Commit 2e54eb96 authored by Petr Vandrovec's avatar Petr Vandrovec Committed by Arnd Bergmann
Browse files

BKL: Remove BKL from ncpfs



Dozen of changes in ncpfs to provide some locking other than BKL.

In readdir cache unlock and mark complete first page as last operation,
so it can be used for synchronization, as code intended.

When updating dentry name on case insensitive filesystems do at least
some basic locking...

Hold i_mutex when updating inode fields.

Push some ncp_conn_is_valid down to ncp_request.  Connection can become
invalid at any moment, and fewer error code paths to test the better.

Use i_size_{read,write} to modify file size.

Set inode's backing_dev_info as ncpfs has its own special bdi.

In ioctl unbreak ioctls invoked on filesystem mounted 'ro' - tests are
for inode writeable or owner match, but were turned to filesystem
writeable and inode writeable or owner match.  Also collect all permission
checks in single place.

Add some locking, and remove comments saying that it would be cool to
add some locks to the code.

Constify some pointers.
Signed-off-by: default avatarPetr Vandrovec <petr@vandrovec.name>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent 60056794
...@@ -95,6 +95,34 @@ const struct dentry_operations ncp_root_dentry_operations = ...@@ -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 * Note: leave the hash unchanged if the directory
* is case-sensitive. * is case-sensitive.
...@@ -102,13 +130,12 @@ const struct dentry_operations ncp_root_dentry_operations = ...@@ -102,13 +130,12 @@ const struct dentry_operations ncp_root_dentry_operations =
static int static int
ncp_hash_dentry(struct dentry *dentry, struct qstr *this) ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
{ {
struct nls_table *t; if (!ncp_case_sensitive(dentry)) {
unsigned long hash; struct nls_table *t;
int i; unsigned long hash;
int i;
t = NCP_IO_TABLE(dentry);
if (!ncp_case_sensitive(dentry->d_inode)) { t = NCP_IO_TABLE(dentry);
hash = init_name_hash(); hash = init_name_hash();
for (i=0; i<this->len ; i++) for (i=0; i<this->len ; i++)
hash = partial_name_hash(ncp_tolower(t, this->name[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) ...@@ -124,7 +151,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
if (a->len != b->len) if (a->len != b->len)
return 1; return 1;
if (ncp_case_sensitive(dentry->d_inode)) if (ncp_case_sensitive(dentry))
return strncmp(a->name, b->name, a->len); return strncmp(a->name, b->name, a->len);
return ncp_strnicmp(NCP_IO_TABLE(dentry), 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:; ...@@ -266,7 +293,7 @@ leave_me:;
static int static int
__ncp_lookup_validate(struct dentry *dentry) ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
{ {
struct ncp_server *server; struct ncp_server *server;
struct dentry *parent; struct dentry *parent;
...@@ -283,9 +310,6 @@ __ncp_lookup_validate(struct dentry *dentry) ...@@ -283,9 +310,6 @@ __ncp_lookup_validate(struct dentry *dentry)
server = NCP_SERVER(dir); server = NCP_SERVER(dir);
if (!ncp_conn_valid(server))
goto finished;
/* /*
* Inspired by smbfs: * Inspired by smbfs:
* The default validation is based on dentry age: * The default validation is based on dentry age:
...@@ -304,8 +328,11 @@ __ncp_lookup_validate(struct dentry *dentry) ...@@ -304,8 +328,11 @@ __ncp_lookup_validate(struct dentry *dentry)
if (ncp_is_server_root(dir)) { if (ncp_is_server_root(dir)) {
res = ncp_io2vol(server, __name, &len, dentry->d_name.name, res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
dentry->d_name.len, 1); dentry->d_name.len, 1);
if (!res) if (!res) {
res = ncp_lookup_volume(server, __name, &(finfo.i)); res = ncp_lookup_volume(server, __name, &(finfo.i));
if (!res)
ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
}
} else { } else {
res = ncp_io2vol(server, __name, &len, dentry->d_name.name, res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
dentry->d_name.len, !ncp_preserve_case(dir)); dentry->d_name.len, !ncp_preserve_case(dir));
...@@ -320,13 +347,17 @@ __ncp_lookup_validate(struct dentry *dentry) ...@@ -320,13 +347,17 @@ __ncp_lookup_validate(struct dentry *dentry)
* what we remember, it's not valid any more. * what we remember, it's not valid any more.
*/ */
if (!res) { 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); ncp_new_dentry(dentry);
val=1; val=1;
} else } else
DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); 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: finished:
...@@ -335,16 +366,6 @@ finished: ...@@ -335,16 +366,6 @@ finished:
return val; 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 * static struct dentry *
ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) 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) ...@@ -411,8 +432,6 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
int result, mtime_valid = 0; int result, mtime_valid = 0;
time_t mtime = 0; time_t mtime = 0;
lock_kernel();
ctl.page = NULL; ctl.page = NULL;
ctl.cache = NULL; ctl.cache = NULL;
...@@ -421,6 +440,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -421,6 +440,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
(int) filp->f_pos); (int) filp->f_pos);
result = -EIO; result = -EIO;
/* Do not generate '.' and '..' when server is dead. */
if (!ncp_conn_valid(server)) if (!ncp_conn_valid(server))
goto out; goto out;
...@@ -532,6 +552,12 @@ read_really: ...@@ -532,6 +552,12 @@ read_really:
ctl.head.end = ctl.fpos - 1; ctl.head.end = ctl.fpos - 1;
ctl.head.eof = ctl.valid; ctl.head.eof = ctl.valid;
finished: finished:
if (ctl.page) {
kunmap(ctl.page);
SetPageUptodate(ctl.page);
unlock_page(ctl.page);
page_cache_release(ctl.page);
}
if (page) { if (page) {
cache->head = ctl.head; cache->head = ctl.head;
kunmap(page); kunmap(page);
...@@ -539,23 +565,17 @@ finished: ...@@ -539,23 +565,17 @@ finished:
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
} }
if (ctl.page) {
kunmap(ctl.page);
SetPageUptodate(ctl.page);
unlock_page(ctl.page);
page_cache_release(ctl.page);
}
out: out:
unlock_kernel();
return result; return result;
} }
static int static int
ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 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 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 ncp_cache_control ctl = *ctrl;
struct qstr qname; struct qstr qname;
int valid = 0; int valid = 0;
...@@ -564,9 +584,9 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, ...@@ -564,9 +584,9 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
__u8 __name[NCP_MAXPATHLEN + 1]; __u8 __name[NCP_MAXPATHLEN + 1];
qname.len = sizeof(__name); 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, 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 */ return 1; /* I'm not sure */
qname.name = __name; qname.name = __name;
...@@ -584,22 +604,64 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, ...@@ -584,22 +604,64 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
goto end_advance; goto end_advance;
} else { } else {
hashed = 1; 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) { if (!newdent->d_inode) {
struct inode *inode;
entry->opened = 0; entry->opened = 0;
entry->ino = iunique(inode->i_sb, 2); entry->ino = iunique(dir->i_sb, 2);
newino = ncp_iget(inode->i_sb, entry); inode = ncp_iget(dir->i_sb, entry);
if (newino) { if (inode) {
newdent->d_op = &ncp_dentry_operations; newdent->d_op = &ncp_dentry_operations;
d_instantiate(newdent, newino); d_instantiate(newdent, inode);
if (!hashed) if (!hashed)
d_rehash(newdent); d_rehash(newdent);
} }
} else } else {
ncp_update_inode2(newdent->d_inode, entry); 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) { if (newdent->d_inode) {
ino = newdent->d_inode->i_ino; ino = newdent->d_inode->i_ino;
...@@ -617,7 +679,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, ...@@ -617,7 +679,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
ctl.cache = NULL; ctl.cache = NULL;
ctl.idx -= NCP_DIRCACHE_SIZE; ctl.idx -= NCP_DIRCACHE_SIZE;
ctl.ofs += 1; 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) if (ctl.page)
ctl.cache = kmap(ctl.page); ctl.cache = kmap(ctl.page);
} }
...@@ -633,7 +695,7 @@ end_advance: ...@@ -633,7 +695,7 @@ end_advance:
if (!ino) if (!ino)
ino = find_inode_number(dentry, &qname); ino = find_inode_number(dentry, &qname);
if (!ino) if (!ino)
ino = iunique(inode->i_sb, 2); ino = iunique(dir->i_sb, 2);
ctl.filled = filldir(dirent, qname.name, qname.len, ctl.filled = filldir(dirent, qname.name, qname.len,
filp->f_pos, ino, DT_UNKNOWN); filp->f_pos, ino, DT_UNKNOWN);
if (!ctl.filled) if (!ctl.filled)
...@@ -660,6 +722,7 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, ...@@ -660,6 +722,7 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
(unsigned long) filp->f_pos); (unsigned long) filp->f_pos);
for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
int inval_dentry;
if (ncp_get_volume_info_with_number(server, i, &info) != 0) if (ncp_get_volume_info_with_number(server, i, &info) != 0)
return; return;
...@@ -675,8 +738,9 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, ...@@ -675,8 +738,9 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
info.volume_name); info.volume_name);
continue; continue;
} }
inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
entry.volume = entry.i.volNumber; 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; return;
} }
} }
...@@ -739,7 +803,7 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, ...@@ -739,7 +803,7 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
rpl += onerpl; rpl += onerpl;
rpls -= onerpl; rpls -= onerpl;
entry.volume = entry.i.volNumber; 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; break;
} }
} while (more); } while (more);
...@@ -775,17 +839,19 @@ int ncp_conn_logged_in(struct super_block *sb) ...@@ -775,17 +839,19 @@ int ncp_conn_logged_in(struct super_block *sb)
if (dent) { if (dent) {
struct inode* ino = dent->d_inode; struct inode* ino = dent->d_inode;
if (ino) { if (ino) {
ncp_update_known_namespace(server, volNumber, NULL);
NCP_FINFO(ino)->volNumber = volNumber; NCP_FINFO(ino)->volNumber = volNumber;
NCP_FINFO(ino)->dirEntNum = dirEntNum; NCP_FINFO(ino)->dirEntNum = dirEntNum;
NCP_FINFO(ino)->DosDirNum = DosDirNum; NCP_FINFO(ino)->DosDirNum = DosDirNum;
result = 0;
} else { } else {
DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
} }
} else { } else {
DPRINTK("ncpfs: sb->s_root == NULL!\n"); DPRINTK("ncpfs: sb->s_root == NULL!\n");
} }
} } else
result = 0; result = 0;
out: out:
return result; return result;
...@@ -799,7 +865,6 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc ...@@ -799,7 +865,6 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc
int error, res, len; int error, res, len;
__u8 __name[NCP_MAXPATHLEN + 1]; __u8 __name[NCP_MAXPATHLEN + 1];
lock_kernel();
error = -EIO; error = -EIO;
if (!ncp_conn_valid(server)) if (!ncp_conn_valid(server))
goto finished; goto finished;
...@@ -813,6 +878,8 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc ...@@ -813,6 +878,8 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc
dentry->d_name.len, 1); dentry->d_name.len, 1);
if (!res) if (!res)
res = ncp_lookup_volume(server, __name, &(finfo.i)); res = ncp_lookup_volume(server, __name, &(finfo.i));
if (!res)
ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
} else { } else {
res = ncp_io2vol(server, __name, &len, dentry->d_name.name, res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
dentry->d_name.len, !ncp_preserve_case(dir)); dentry->d_name.len, !ncp_preserve_case(dir));
...@@ -846,7 +913,6 @@ add_entry: ...@@ -846,7 +913,6 @@ add_entry:
finished: finished:
PPRINTK("ncp_lookup: result=%d\n", error); PPRINTK("ncp_lookup: result=%d\n", error);
unlock_kernel();
return ERR_PTR(error); return ERR_PTR(error);
} }
...@@ -887,11 +953,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, ...@@ -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", PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
dentry->d_parent->d_name.name, dentry->d_name.name, mode); 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); ncp_age_dentry(server, dentry);
len = sizeof(__name); len = sizeof(__name);
error = ncp_io2vol(server, __name, &len, dentry->d_name.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, ...@@ -917,6 +978,8 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
if (result) { if (result) {
if (result == 0x87) if (result == 0x87)
error = -ENAMETOOLONG; error = -ENAMETOOLONG;
else if (result < 0)
error = result;
DPRINTK("ncp_create: %s/%s failed\n", DPRINTK("ncp_create: %s/%s failed\n",
dentry->d_parent->d_name.name, dentry->d_name.name); dentry->d_parent->d_name.name, dentry->d_name.name);
goto out; goto out;
...@@ -935,7 +998,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, ...@@ -935,7 +998,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
error = ncp_instantiate(dir, dentry, &finfo); error = ncp_instantiate(dir, dentry, &finfo);
out: out:
unlock_kernel();
return error; return error;
} }
...@@ -955,11 +1017,6 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -955,11 +1017,6 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
DPRINTK("ncp_mkdir: making %s/%s\n", DPRINTK("ncp_mkdir: making %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name); 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); ncp_age_dentry(server, dentry);
len = sizeof(__name); len = sizeof(__name);
error = ncp_io2vol(server, __name, &len, dentry->d_name.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) ...@@ -967,12 +1024,11 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (error) if (error)
goto out; goto out;
error = -EACCES; error = ncp_open_create_file_or_subdir(server, dir, __name,
if (ncp_open_create_file_or_subdir(server, dir, __name,
OC_MODE_CREATE, aDIR, OC_MODE_CREATE, aDIR,
cpu_to_le16(0xffff), cpu_to_le16(0xffff),
&finfo) == 0) &finfo);
{ if (error == 0) {
if (ncp_is_nfs_extras(server, finfo.volume)) { if (ncp_is_nfs_extras(server, finfo.volume)) {
mode |= S_IFDIR; mode |= S_IFDIR;
finfo.i.nfs.mode = mode; finfo.i.nfs.mode = mode;
...@@ -983,9 +1039,10 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -983,9 +1039,10 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
goto out; goto out;
} }
error = ncp_instantiate(dir, dentry, &finfo); error = ncp_instantiate(dir, dentry, &finfo);
} else if (error > 0) {
error = -EACCES;
} }
out: out:
unlock_kernel();
return error; return error;
} }
...@@ -998,11 +1055,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -998,11 +1055,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
DPRINTK("ncp_rmdir: removing %s/%s\n", DPRINTK("ncp_rmdir: removing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name); dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
lock_kernel();
if (!ncp_conn_valid(server))
goto out;
error = -EBUSY; error = -EBUSY;
if (!d_unhashed(dentry)) if (!d_unhashed(dentry))
goto out; goto out;
...@@ -1036,11 +1088,10 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1036,11 +1088,10 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
error = -ENOENT; error = -ENOENT;
break; break;
default: default:
error = -EACCES; error = result < 0 ? result : -EACCES;
break; break;
} }
out: out:
unlock_kernel();
return error; return error;
} }
...@@ -1050,15 +1101,10 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1050,15 +1101,10 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
struct ncp_server *server; struct ncp_server *server;
int error; int error;
lock_kernel();
server = NCP_SERVER(dir);