diff options
Diffstat (limited to 'fs/ncpfs')
-rw-r--r-- | fs/ncpfs/dir.c | 221 | ||||
-rw-r--r-- | fs/ncpfs/file.c | 25 | ||||
-rw-r--r-- | fs/ncpfs/inode.c | 55 | ||||
-rw-r--r-- | fs/ncpfs/ioctl.c | 470 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.c | 101 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 15 | ||||
-rw-r--r-- | fs/ncpfs/ncpsign_kernel.c | 10 | ||||
-rw-r--r-- | fs/ncpfs/sock.c | 1 |
8 files changed, 493 insertions, 405 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 9578cbe0cd5..aac8832e919 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -95,6 +95,34 @@ const struct dentry_operations ncp_root_dentry_operations = }; +#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber]) + +static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) +{ +#ifdef CONFIG_NCPFS_SMALLDOS + int ns = ncp_namespace(i); + + if ((ns == NW_NS_DOS) +#ifdef CONFIG_NCPFS_OS2_NS + || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS)) +#endif /* CONFIG_NCPFS_OS2_NS */ + ) + return 0; +#endif /* CONFIG_NCPFS_SMALLDOS */ + return 1; +} + +#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS) + +static inline int ncp_case_sensitive(struct dentry *dentry) +{ +#ifdef CONFIG_NCPFS_NFS_NS + return ncp_namespace(dentry->d_inode) == NW_NS_NFS; +#else + return 0; +#endif /* CONFIG_NCPFS_NFS_NS */ +} + /* * Note: leave the hash unchanged if the directory * is case-sensitive. @@ -102,13 +130,12 @@ const struct dentry_operations ncp_root_dentry_operations = static int ncp_hash_dentry(struct dentry *dentry, struct qstr *this) { - struct nls_table *t; - unsigned long hash; - int i; - - t = NCP_IO_TABLE(dentry); + if (!ncp_case_sensitive(dentry)) { + struct nls_table *t; + unsigned long hash; + int i; - if (!ncp_case_sensitive(dentry->d_inode)) { + t = NCP_IO_TABLE(dentry); hash = init_name_hash(); for (i=0; i<this->len ; i++) hash = partial_name_hash(ncp_tolower(t, this->name[i]), @@ -124,7 +151,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) if (a->len != b->len) return 1; - if (ncp_case_sensitive(dentry->d_inode)) + if (ncp_case_sensitive(dentry)) return strncmp(a->name, b->name, a->len); return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); @@ -266,7 +293,7 @@ leave_me:; static int -__ncp_lookup_validate(struct dentry *dentry) +ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd) { struct ncp_server *server; struct dentry *parent; @@ -283,9 +310,6 @@ __ncp_lookup_validate(struct dentry *dentry) server = NCP_SERVER(dir); - if (!ncp_conn_valid(server)) - goto finished; - /* * Inspired by smbfs: * The default validation is based on dentry age: @@ -304,8 +328,11 @@ __ncp_lookup_validate(struct dentry *dentry) if (ncp_is_server_root(dir)) { res = ncp_io2vol(server, __name, &len, dentry->d_name.name, dentry->d_name.len, 1); - if (!res) + if (!res) { res = ncp_lookup_volume(server, __name, &(finfo.i)); + if (!res) + ncp_update_known_namespace(server, finfo.i.volNumber, NULL); + } } else { res = ncp_io2vol(server, __name, &len, dentry->d_name.name, dentry->d_name.len, !ncp_preserve_case(dir)); @@ -320,13 +347,17 @@ __ncp_lookup_validate(struct dentry *dentry) * what we remember, it's not valid any more. */ if (!res) { - if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) { + struct inode *inode = dentry->d_inode; + + mutex_lock(&inode->i_mutex); + if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) { ncp_new_dentry(dentry); val=1; } else DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); - ncp_update_inode2(dentry->d_inode, &finfo); + ncp_update_inode2(inode, &finfo); + mutex_unlock(&inode->i_mutex); } finished: @@ -335,16 +366,6 @@ finished: return val; } -static int -ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) -{ - int res; - lock_kernel(); - res = __ncp_lookup_validate(dentry); - unlock_kernel(); - return res; -} - static struct dentry * ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) { @@ -411,8 +432,6 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) int result, mtime_valid = 0; time_t mtime = 0; - lock_kernel(); - ctl.page = NULL; ctl.cache = NULL; @@ -421,6 +440,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) (int) filp->f_pos); result = -EIO; + /* Do not generate '.' and '..' when server is dead. */ if (!ncp_conn_valid(server)) goto out; @@ -532,6 +552,12 @@ read_really: ctl.head.end = ctl.fpos - 1; ctl.head.eof = ctl.valid; finished: + if (ctl.page) { + kunmap(ctl.page); + SetPageUptodate(ctl.page); + unlock_page(ctl.page); + page_cache_release(ctl.page); + } if (page) { cache->head = ctl.head; kunmap(page); @@ -539,23 +565,17 @@ finished: unlock_page(page); page_cache_release(page); } - if (ctl.page) { - kunmap(ctl.page); - SetPageUptodate(ctl.page); - unlock_page(ctl.page); - page_cache_release(ctl.page); - } out: - unlock_kernel(); return result; } static int ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, - struct ncp_cache_control *ctrl, struct ncp_entry_info *entry) + struct ncp_cache_control *ctrl, struct ncp_entry_info *entry, + int inval_childs) { struct dentry *newdent, *dentry = filp->f_path.dentry; - struct inode *newino, *inode = dentry->d_inode; + struct inode *dir = dentry->d_inode; struct ncp_cache_control ctl = *ctrl; struct qstr qname; int valid = 0; @@ -564,9 +584,9 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, __u8 __name[NCP_MAXPATHLEN + 1]; qname.len = sizeof(__name); - if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len, + if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len, entry->i.entryName, entry->i.nameLen, - !ncp_preserve_entry_case(inode, entry->i.NSCreator))) + !ncp_preserve_entry_case(dir, entry->i.NSCreator))) return 1; /* I'm not sure */ qname.name = __name; @@ -584,22 +604,64 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, goto end_advance; } else { hashed = 1; - memcpy((char *) newdent->d_name.name, qname.name, - newdent->d_name.len); + + /* If case sensitivity changed for this volume, all entries below this one + should be thrown away. This entry itself is not affected, as its case + sensitivity is controlled by its own parent. */ + if (inval_childs) + shrink_dcache_parent(newdent); + + /* + * It is not as dangerous as it looks. NetWare's OS2 namespace is + * case preserving yet case insensitive. So we update dentry's name + * as received from server. We found dentry via d_lookup with our + * hash, so we know that hash does not change, and so replacing name + * should be reasonably safe. + */ + if (qname.len == newdent->d_name.len && + memcmp(newdent->d_name.name, qname.name, newdent->d_name.len)) { + struct inode *inode = newdent->d_inode; + + /* + * Inside ncpfs all uses of d_name are either for debugging, + * or on functions which acquire inode mutex (mknod, creat, + * lookup). So grab i_mutex here, to be sure. d_path + * uses dcache_lock when generating path, so we should too. + * And finally d_compare is protected by dentry's d_lock, so + * here we go. + */ + if (inode) + mutex_lock(&inode->i_mutex); + spin_lock(&dcache_lock); + spin_lock(&newdent->d_lock); + memcpy((char *) newdent->d_name.name, qname.name, + newdent->d_name.len); + spin_unlock(&newdent->d_lock); + spin_unlock(&dcache_lock); + if (inode) + mutex_unlock(&inode->i_mutex); + } } if (!newdent->d_inode) { + struct inode *inode; + entry->opened = 0; - entry->ino = iunique(inode->i_sb, 2); - newino = ncp_iget(inode->i_sb, entry); - if (newino) { + entry->ino = iunique(dir->i_sb, 2); + inode = ncp_iget(dir->i_sb, entry); + if (inode) { newdent->d_op = &ncp_dentry_operations; - d_instantiate(newdent, newino); + d_instantiate(newdent, inode); if (!hashed) d_rehash(newdent); } - } else - ncp_update_inode2(newdent->d_inode, entry); + } else { + struct inode *inode = newdent->d_inode; + + mutex_lock(&inode->i_mutex); + ncp_update_inode2(inode, entry); + mutex_unlock(&inode->i_mutex); + } if (newdent->d_inode) { ino = newdent->d_inode->i_ino; @@ -617,7 +679,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, ctl.cache = NULL; ctl.idx -= NCP_DIRCACHE_SIZE; ctl.ofs += 1; - ctl.page = grab_cache_page(&inode->i_data, ctl.ofs); + ctl.page = grab_cache_page(&dir->i_data, ctl.ofs); if (ctl.page) ctl.cache = kmap(ctl.page); } @@ -633,7 +695,7 @@ end_advance: if (!ino) ino = find_inode_number(dentry, &qname); if (!ino) - ino = iunique(inode->i_sb, 2); + ino = iunique(dir->i_sb, 2); ctl.filled = filldir(dirent, qname.name, qname.len, filp->f_pos, ino, DT_UNKNOWN); if (!ctl.filled) @@ -660,6 +722,7 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, (unsigned long) filp->f_pos); for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { + int inval_dentry; if (ncp_get_volume_info_with_number(server, i, &info) != 0) return; @@ -675,8 +738,9 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, info.volume_name); continue; } + inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL); entry.volume = entry.i.volNumber; - if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) + if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, inval_dentry)) return; } } @@ -739,7 +803,7 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, rpl += onerpl; rpls -= onerpl; entry.volume = entry.i.volNumber; - if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) + if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, 0)) break; } } while (more); @@ -775,17 +839,19 @@ int ncp_conn_logged_in(struct super_block *sb) if (dent) { struct inode* ino = dent->d_inode; if (ino) { + ncp_update_known_namespace(server, volNumber, NULL); NCP_FINFO(ino)->volNumber = volNumber; NCP_FINFO(ino)->dirEntNum = dirEntNum; NCP_FINFO(ino)->DosDirNum = DosDirNum; + result = 0; } else { DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); } } else { DPRINTK("ncpfs: sb->s_root == NULL!\n"); } - } - result = 0; + } else + result = 0; out: return result; @@ -799,7 +865,6 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc int error, res, len; __u8 __name[NCP_MAXPATHLEN + 1]; - lock_kernel(); error = -EIO; if (!ncp_conn_valid(server)) goto finished; @@ -813,6 +878,8 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc dentry->d_name.len, 1); if (!res) res = ncp_lookup_volume(server, __name, &(finfo.i)); + if (!res) + ncp_update_known_namespace(server, finfo.i.volNumber, NULL); } else { res = ncp_io2vol(server, __name, &len, dentry->d_name.name, dentry->d_name.len, !ncp_preserve_case(dir)); @@ -846,7 +913,6 @@ add_entry: finished: PPRINTK("ncp_lookup: result=%d\n", error); - unlock_kernel(); return ERR_PTR(error); } @@ -887,11 +953,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n", dentry->d_parent->d_name.name, dentry->d_name.name, mode); - error = -EIO; - lock_kernel(); - if (!ncp_conn_valid(server)) - goto out; - ncp_age_dentry(server, dentry); len = sizeof(__name); error = ncp_io2vol(server, __name, &len, dentry->d_name.name, @@ -917,6 +978,8 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, if (result) { if (result == 0x87) error = -ENAMETOOLONG; + else if (result < 0) + error = result; DPRINTK("ncp_create: %s/%s failed\n", dentry->d_parent->d_name.name, dentry->d_name.name); goto out; @@ -935,7 +998,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, error = ncp_instantiate(dir, dentry, &finfo); out: - unlock_kernel(); return error; } @@ -955,11 +1017,6 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) DPRINTK("ncp_mkdir: making %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - error = -EIO; - lock_kernel(); - if (!ncp_conn_valid(server)) - goto out; - ncp_age_dentry(server, dentry); len = sizeof(__name); error = ncp_io2vol(server, __name, &len, dentry->d_name.name, @@ -967,12 +1024,11 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (error) goto out; - error = -EACCES; - if (ncp_open_create_file_or_subdir(server, dir, __name, + error = ncp_open_create_file_or_subdir(server, dir, __name, OC_MODE_CREATE, aDIR, cpu_to_le16(0xffff), - &finfo) == 0) - { + &finfo); + if (error == 0) { if (ncp_is_nfs_extras(server, finfo.volume)) { mode |= S_IFDIR; finfo.i.nfs.mode = mode; @@ -983,9 +1039,10 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) goto out; } error = ncp_instantiate(dir, dentry, &finfo); + } else if (error > 0) { + error = -EACCES; } out: - unlock_kernel(); return error; } @@ -998,11 +1055,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) DPRINTK("ncp_rmdir: removing %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - error = -EIO; - lock_kernel(); - if (!ncp_conn_valid(server)) - goto out; - error = -EBUSY; if (!d_unhashed(dentry)) goto out; @@ -1036,11 +1088,10 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) error = -ENOENT; break; default: - error = -EACCES; + error = result < 0 ? result : -EACCES; break; } out: - unlock_kernel(); return error; } @@ -1050,15 +1101,10 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) struct ncp_server *server; int error; - lock_kernel(); server = NCP_SERVER(dir); DPRINTK("ncp_unlink: unlinking %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - error = -EIO; - if (!ncp_conn_valid(server)) - goto out; - /* * Check whether to close the file ... */ @@ -1097,12 +1143,9 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) error = -ENOENT; break; default: - error = -EACCES; + error = error < 0 ? error : -EACCES; break; } - -out: - unlock_kernel(); return error; } @@ -1118,11 +1161,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name); - error = -EIO; - lock_kernel(); - if (!ncp_conn_valid(server)) - goto out; - ncp_age_dentry(server, old_dentry); ncp_age_dentry(server, new_dentry); @@ -1161,11 +1199,10 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, error = -ENOENT; break; default: - error = -EACCES; + error = error < 0 ? error : -EACCES; break; } out: - unlock_kernel(); return error; } diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 3639cc5cbda..6c754f70c52 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -113,9 +113,6 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) DPRINTK("ncp_file_read: enter %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - if (!ncp_conn_valid(NCP_SERVER(inode))) - return -EIO; - pos = *ppos; if ((ssize_t) count < 0) { @@ -192,13 +189,11 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t * DPRINTK("ncp_file_write: enter %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - if (!ncp_conn_valid(NCP_SERVER(inode))) - return -EIO; if ((ssize_t) count < 0) return -EINVAL; pos = *ppos; if (file->f_flags & O_APPEND) { - pos = inode->i_size; + pos = i_size_read(inode); } if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { @@ -264,8 +259,11 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t * *ppos = pos; - if (pos > inode->i_size) { - inode->i_size = pos; + if (pos > i_size_read(inode)) { + mutex_lock(&inode->i_mutex); + if (pos > i_size_read(inode)) + i_size_write(inode, pos); + mutex_unlock(&inode->i_mutex); } DPRINTK("ncp_file_write: exit %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); @@ -281,18 +279,9 @@ static int ncp_release(struct inode *inode, struct file *file) { return 0; } -static loff_t ncp_remote_llseek(struct file *file, loff_t offset, int origin) -{ - loff_t ret; - lock_kernel(); - ret = generic_file_llseek_unlocked(file, offset, origin); - unlock_kernel(); - return ret; -} - const struct file_operations ncp_file_operations = { - .llseek = ncp_remote_llseek, + .llseek = generic_file_llseek, .read = ncp_file_read, .write = ncp_file_write, .unlocked_ioctl = ncp_ioctl, diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index b4de38cf49f..985fabb26ac 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -139,7 +139,7 @@ static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi) inode->i_mode = nwi->nfs.mode; } - inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; + inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate); inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate); @@ -158,18 +158,21 @@ static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo) inode->i_mode = server->m.dir_mode; /* for directories dataStreamSize seems to be some Object ID ??? */ - inode->i_size = NCP_BLOCK_SIZE; + i_size_write(inode, NCP_BLOCK_SIZE); } else { + u32 size; + inode->i_mode = server->m.file_mode; - inode->i_size = le32_to_cpu(nwi->dataStreamSize); + size = le32_to_cpu(nwi->dataStreamSize); + i_size_write(inode, size); #ifdef CONFIG_NCPFS_EXTRAS if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) && (nwi->attributes & aSHARED)) { switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { case aHIDDEN: if (server->m.flags & NCP_MOUNT_SYMLINKS) { - if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE) - && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { + if (/* (size >= NCP_MIN_SYMLINK_SIZE) + && */ (size <= NCP_MAX_SYMLINK_SIZE)) { inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK; break; @@ -208,7 +211,7 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) } /* - * Fill in the inode based on the ncp_entry_info structure. + * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes. */ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) { @@ -254,6 +257,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info) if (inode) { atomic_set(&NCP_FINFO(inode)->opened, info->opened); + inode->i_mapping->backing_dev_info = sb->s_bdi; inode->i_ino = info->ino; ncp_set_attr(inode, info); if (S_ISREG(inode->i_mode)) { @@ -299,10 +303,12 @@ ncp_evict_inode(struct inode *inode) static void ncp_stop_tasks(struct ncp_server *server) { struct sock* sk = server->ncp_sock->sk; - + + lock_sock(sk); sk->sk_error_report = server->error_report; sk->sk_data_ready = server->data_ready; sk->sk_write_space = server->write_space; + release_sock(sk); del_timer_sync(&server->timeout_tm); flush_scheduled_work(); } @@ -565,10 +571,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) /* server->conn_status = 0; */ /* server->root_dentry = NULL; */ /* server->root_setuped = 0; */ + mutex_init(&server->root_setup_lock); #ifdef CONFIG_NCPFS_PACKET_SIGNING /* server->sign_wanted = 0; */ /* server->sign_active = 0; */ #endif + init_rwsem(&server->auth_rwsem); server->auth.auth_type = NCP_AUTH_NONE; /* server->auth.object_name_len = 0; */ /* server->auth.object_name = NULL; */ @@ -593,16 +601,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) server->nls_io = load_nls_default(); #endif /* CONFIG_NCPFS_NLS */ - server->dentry_ttl = 0; /* no caching */ + atomic_set(&server->dentry_ttl, 0); /* no caching */ INIT_LIST_HEAD(&server->tx.requests); mutex_init(&server->rcv.creq_mutex); server->tx.creq = NULL; server->rcv.creq = NULL; - server->data_ready = sock->sk->sk_data_ready; - server->write_space = sock->sk->sk_write_space; - server->error_report = sock->sk->sk_error_report; - sock->sk->sk_user_data = server; init_timer(&server->timeout_tm); #undef NCP_PACKET_SIZE @@ -619,6 +623,11 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) if (server->rxbuf == NULL) goto out_txbuf; + lock_sock(sock->sk); + server->data_ready = sock->sk->sk_data_ready; + server->write_space = sock->sk->sk_write_space; + server->error_report = sock->sk->sk_error_report; + sock->sk->sk_user_data = server; sock->sk->sk_data_ready = ncp_tcp_data_ready; sock->sk->sk_error_report = ncp_tcp_error_report; if (sock->type == SOCK_STREAM) { @@ -634,6 +643,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) server->timeout_tm.data = (unsigned long)server; server->timeout_tm.function = ncpdgram_timeout_call; } + release_sock(sock->sk); ncp_lock_server(server); error = ncp_connect(server); @@ -658,8 +668,10 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) goto out_disconnect; } } + ncp_lock_server(server); if (options & 2) server->sign_wanted = 1; + ncp_unlock_server(server); } else #endif /* CONFIG_NCPFS_PACKET_SIGNING */ @@ -720,6 +732,9 @@ out_nls: unload_nls(server->nls_io); unload_nls(server->nls_vol); #endif + mutex_destroy(&server->rcv.creq_mutex); + mutex_destroy(&server->root_setup_lock); + mutex_destroy(&server->mutex); out_fput2: if (server->info_filp) fput(server->info_filp); @@ -743,8 +758,6 @@ static void ncp_put_super(struct super_block *sb) { struct ncp_server *server = NCP_SBP(sb); - lock_kernel(); - ncp_lock_server(server); ncp_disconnect(server); ncp_unlock_server(server); @@ -756,6 +769,9 @@ static void ncp_put_super(struct super_block *sb) unload_nls(server->nls_vol); unload_nls(server->nls_io); #endif /* CONFIG_NCPFS_NLS */ + mutex_destroy(&server->rcv.creq_mutex); + mutex_destroy(&server->root_setup_lock); + mutex_destroy(&server->mutex); if (server->info_filp) fput(server->info_filp); @@ -771,8 +787,6 @@ static void ncp_put_super(struct super_block *sb) vfree(server->packet); sb->s_fs_info = NULL; kfree(server); - - unlock_kernel(); } static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) @@ -851,10 +865,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) result = -EIO; - lock_kernel(); - server = NCP_SERVER(inode); - if ((!server) || !ncp_conn_valid(server)) + if (!server) /* How this could happen? */ goto out; /* ageing the dentry to force validation */ @@ -981,8 +993,6 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode), inode, info_mask, &info); if (result != 0) { - result = -EACCES; - if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) { /* NetWare seems not to allow this. I do not know why. So, just tell the @@ -1005,7 +1015,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) mark_inode_dirty(inode); out: - unlock_kernel(); + if (result > 0) + result = -EACCES; return result; } diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 84a8cfc4e38..c2a1f9a155c 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -35,16 +35,11 @@ #define NCP_PACKET_SIZE_INTERNAL 65536 static int -ncp_get_fs_info(struct ncp_server * server, struct file *file, +ncp_get_fs_info(struct ncp_server * server, struct inode *inode, struct ncp_fs_info __user *arg) { - struct inode *inode = file->f_path.dentry->d_inode; struct ncp_fs_info info; - if (file_permission(file, MAY_WRITE) != 0 - && current_uid() != server->m.mounted_uid) - return -EACCES; - if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; @@ -65,16 +60,11 @@ ncp_get_fs_info(struct ncp_server * server, struct file *file, } static int -ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, +ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode, struct ncp_fs_info_v2 __user * arg) { - struct inode *inode = file->f_path.dentry->d_inode; struct ncp_fs_info_v2 info2; - if (file_permission(file, MAY_WRITE) != 0 - && current_uid() != server->m.mounted_uid) - return -EACCES; - if (copy_from_user(&info2, arg, sizeof(info2))) return -EFAULT; @@ -136,16 +126,11 @@ struct compat_ncp_privatedata_ioctl #define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) static int -ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, +ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode, struct compat_ncp_fs_info_v2 __user * arg) { - struct inode *inode = file->f_path.dentry->d_inode; struct compat_ncp_fs_info_v2 info2; - if (file_permission(file, MAY_WRITE) != 0 - && current_uid() != server->m.mounted_uid) - return -EACCES; - if (copy_from_user(&info2, arg, sizeof(info2))) return -EFAULT; @@ -182,11 +167,8 @@ ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) struct nls_table *iocharset; struct nls_table *oldset_io; struct nls_table *oldset_cp; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (server->root_setuped) - return -EBUSY; + int utf8; + int err; if (copy_from_user(&user, arg, sizeof(user))) return -EFAULT; @@ -206,28 +188,40 @@ ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) user.iocharset[NCP_IOCSNAME_LEN] = 0; if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { iocharset = load_nls_default(); - NCP_CLR_FLAG(server, NCP_FLAG_UTF8); + utf8 = 0; } else if (!strcmp(user.iocharset, "utf8")) { iocharset = load_nls_default(); - NCP_SET_FLAG(server, NCP_FLAG_UTF8); + utf8 = 1; } else { iocharset = load_nls(user.iocharset); if (!iocharset) { unload_nls(codepage); return -EBADRQC; } - NCP_CLR_FLAG(server, NCP_FLAG_UTF8); + utf8 = 0; } - oldset_cp = server->nls_vol; - server->nls_vol = codepage; - oldset_io = server->nls_io; - server->nls_io = iocharset; - + mutex_lock(&server->root_setup_lock); + if (server->root_setuped) { + oldset_cp = codepage; + oldset_io = iocharset; + err = -EBUSY; + } else { + if (utf8) + NCP_SET_FLAG(server, NCP_FLAG_UTF8); + else + NCP_CLR_FLAG(server, NCP_FLAG_UTF8); + oldset_cp = server->nls_vol; + server->nls_vol = codepage; + oldset_io = server->nls_io; + server->nls_io = iocharset; + err = 0; + } + mutex_unlock(&server->root_setup_lock); unload_nls(oldset_cp); unload_nls(oldset_io); - return 0; + return err; } static int @@ -237,6 +231,7 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) int len; memset(&user, 0, sizeof(user)); + mutex_lock(&server->root_setup_lock); if (server->nls_vol && server->nls_vol->charset) { len = strlen(server->nls_vol->charset); if (len > NCP_IOCSNAME_LEN) @@ -254,6 +249,7 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) strncpy(user.iocharset, server->nls_io->charset, len); user.iocharset[len] = 0; } + mutex_unlock(&server->root_setup_lock); if (copy_to_user(arg, &user, sizeof(user))) return -EFAULT; @@ -261,25 +257,19 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) } #endif /* CONFIG_NCPFS_NLS */ -static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg) { - struct inode *inode = filp->f_dentry->d_inode; struct ncp_server *server = NCP_SERVER(inode); int result; struct ncp_ioctl_request request; char* bouncebuffer; void __user *argp = (void __user *)arg; - uid_t uid = current_uid(); switch (cmd) { #ifdef CONFIG_COMPAT case NCP_IOC_NCPREQUEST_32: #endif case NCP_IOC_NCPREQUEST: - if (file_permission(filp, MAY_WRITE) != 0 - && uid != server->m.mounted_uid) - return -EACCES; - #ifdef CONFIG_COMPAT if (cmd == NCP_IOC_NCPREQUEST_32) { struct compat_ncp_ioctl_request request32; @@ -314,7 +304,7 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) server->current_size = request.size; memcpy(server->packet, bouncebuffer, request.size); - result = ncp_request2(server, request.function, + result = ncp_request2(server, request.function, bouncebuffer, NCP_PACKET_SIZE_INTERNAL); if (result < 0) result = -EIO; @@ -331,69 +321,69 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case NCP_IOC_CONN_LOGGED_IN: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE)) return -EINVAL; + mutex_lock(&server->root_setup_lock); if (server->root_setuped) - return -EBUSY; - server->root_setuped = 1; - return ncp_conn_logged_in(inode->i_sb); + result = -EBUSY; + else { + result = ncp_conn_logged_in(inode->i_sb); + if (result == 0) + server->root_setuped = 1; + } + mutex_unlock(&server->root_setup_lock); + return result; case NCP_IOC_GET_FS_INFO: - return ncp_get_fs_info(server, filp, argp); + return ncp_get_fs_info(server, inode, argp); case NCP_IOC_GET_FS_INFO_V2: - return ncp_get_fs_info_v2(server, filp, argp); + return ncp_get_fs_info_v2(server, inode, argp); #ifdef CONFIG_COMPAT case NCP_IOC_GET_FS_INFO_V2_32: - return ncp_get_compat_fs_info_v2(server, filp, argp); + return ncp_get_compat_fs_info_v2(server, inode, argp); #endif /* we have too many combinations of CONFIG_COMPAT, * CONFIG_64BIT and CONFIG_UID16, so just handle * any of the possible ioctls */ case NCP_IOC_GETMOUNTUID16: - case NCP_IOC_GETMOUNTUID32: - case NCP_IOC_GETMOUNTUID64: - if (file_permission(filp, MAY_READ) != 0 - && uid != server->m.mounted_uid) - return -EACCES; - - if (cmd == NCP_IOC_GETMOUNTUID16) { + { u16 uid; + SET_UID(uid, server->m.mounted_uid); if (put_user(uid, (u16 __user *)argp)) return -EFAULT; - } else if (cmd == NCP_IOC_GETMOUNTUID32) { - if (put_user(server->m.mounted_uid, - (u32 __user *)argp)) - return -EFAULT; - } else { - if (put_user(server->m.mounted_uid, - (u64 __user *)argp)) - return -EFAULT; + return 0; } + case NCP_IOC_GETMOUNTUID32: + if (put_user(server->m.mounted_uid, + (u32 __user *)argp)) + return -EFAULT; + return 0; + case NCP_IOC_GETMOUNTUID64: + if (put_user(server->m.mounted_uid, + (u64 __user *)argp)) + return -EFAULT; return 0; case NCP_IOC_GETROOT: { struct ncp_setroot_ioctl sr; - if (file_permission(filp, MAY_READ) != 0 - && uid != server->m.mounted_uid) - return -EACCES; - + result = -EACCES; + mutex_lock(&server->root_setup_lock); if (server->m.mounted_vol[0]) { struct dentry* dentry = inode->i_sb->s_root; if (dentry) { struct inode* s_inode = dentry->d_inode; - + if (s_inode) { sr.volNumber = NCP_FINFO(s_inode)->volNumber; sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum; sr.namespace = server->name_space[sr.volNumber]; + result = 0; } else DPRINTK("ncpfs: s_root->d_inode==NULL\n"); } else @@ -402,10 +392,12 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) sr.volNumber = -1; sr.namespace = 0; sr.dirEntNum = 0; + result = 0; } - if (copy_to_user(argp, &sr, sizeof(sr))) - return -EFAULT; - return 0; + mutex_unlock(&server->root_setup_lock); + if (!result && copy_to_user(argp, &sr, sizeof(sr))) |