diff options
Diffstat (limited to 'fs/ncpfs/dir.c')
| -rw-r--r-- | fs/ncpfs/dir.c | 457 |
1 files changed, 225 insertions, 232 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index b8b5b30d53f..08b8ea8c353 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -15,33 +15,30 @@ #include <linux/errno.h> #include <linux/stat.h> #include <linux/kernel.h> -#include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/mm.h> +#include <linux/namei.h> #include <asm/uaccess.h> #include <asm/byteorder.h> -#include <linux/smp_lock.h> -#include <linux/ncp_fs.h> +#include "ncp_fs.h" -#include "ncplib_kernel.h" - -static void ncp_read_volume_list(struct file *, void *, filldir_t, +static void ncp_read_volume_list(struct file *, struct dir_context *, struct ncp_cache_control *); -static void ncp_do_readdir(struct file *, void *, filldir_t, +static void ncp_do_readdir(struct file *, struct dir_context *, struct ncp_cache_control *); -static int ncp_readdir(struct file *, void *, filldir_t); +static int ncp_readdir(struct file *, struct dir_context *); -static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *); -static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *); +static int ncp_create(struct inode *, struct dentry *, umode_t, bool); +static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int); static int ncp_unlink(struct inode *, struct dentry *); -static int ncp_mkdir(struct inode *, struct dentry *, int); +static int ncp_mkdir(struct inode *, struct dentry *, umode_t); static int ncp_rmdir(struct inode *, struct dentry *); static int ncp_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); static int ncp_mknod(struct inode * dir, struct dentry *dentry, - int mode, dev_t rdev); + umode_t mode, dev_t rdev); #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) extern int ncp_symlink(struct inode *, struct dentry *, const char *); #else @@ -50,9 +47,10 @@ extern int ncp_symlink(struct inode *, struct dentry *, const char *); const struct file_operations ncp_dir_operations = { + .llseek = generic_file_llseek, .read = generic_read_dir, - .readdir = ncp_readdir, - .ioctl = ncp_ioctl, + .iterate = ncp_readdir, + .unlocked_ioctl = ncp_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ncp_compat_ioctl, #endif @@ -74,12 +72,13 @@ const struct inode_operations ncp_dir_inode_operations = /* * Dentry operations routines */ -static int ncp_lookup_validate(struct dentry *, struct nameidata *); -static int ncp_hash_dentry(struct dentry *, struct qstr *); -static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); -static int ncp_delete_dentry(struct dentry *); +static int ncp_lookup_validate(struct dentry *, unsigned int); +static int ncp_hash_dentry(const struct dentry *, struct qstr *); +static int ncp_compare_dentry(const struct dentry *, const struct dentry *, + unsigned int, const char *, const struct qstr *); +static int ncp_delete_dentry(const struct dentry *); -static const struct dentry_operations ncp_dentry_operations = +const struct dentry_operations ncp_dentry_operations = { .d_revalidate = ncp_lookup_validate, .d_hash = ncp_hash_dentry, @@ -87,28 +86,57 @@ static const struct dentry_operations ncp_dentry_operations = .d_delete = ncp_delete_dentry, }; -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) { - .d_hash = ncp_hash_dentry, - .d_compare = ncp_compare_dentry, - .d_delete = ncp_delete_dentry, -}; +#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(const struct inode *i) +{ +#ifdef CONFIG_NCPFS_NFS_NS + return ncp_namespace(i) == NW_NS_NFS; +#else + return 0; +#endif /* CONFIG_NCPFS_NFS_NS */ +} /* * Note: leave the hash unchanged if the directory * is case-sensitive. + * + * Accessing the parent inode can be racy under RCU pathwalking. + * Use ACCESS_ONCE() to make sure we use _one_ particular inode, + * the callers will handle races. */ static int -ncp_hash_dentry(struct dentry *dentry, struct qstr *this) +ncp_hash_dentry(const struct dentry *dentry, struct qstr *this) { - struct nls_table *t; - unsigned long hash; - int i; + struct inode *inode = ACCESS_ONCE(dentry->d_inode); + + if (!inode) + return 0; - t = NCP_IO_TABLE(dentry); + if (!ncp_case_sensitive(inode)) { + struct super_block *sb = dentry->d_sb; + struct nls_table *t; + unsigned long hash; + int i; - if (!ncp_case_sensitive(dentry->d_inode)) { + t = NCP_IO_TABLE(sb); hash = init_name_hash(); for (i=0; i<this->len ; i++) hash = partial_name_hash(ncp_tolower(t, this->name[i]), @@ -118,16 +146,28 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this) return 0; } +/* + * Accessing the parent inode can be racy under RCU pathwalking. + * Use ACCESS_ONCE() to make sure we use _one_ particular inode, + * the callers will handle races. + */ static int -ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) +ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) { - if (a->len != b->len) + struct inode *pinode; + + if (len != name->len) + return 1; + + pinode = ACCESS_ONCE(parent->d_inode); + if (!pinode) return 1; - if (ncp_case_sensitive(dentry->d_inode)) - return strncmp(a->name, b->name, a->len); + if (ncp_case_sensitive(pinode)) + return strncmp(str, name->name, len); - return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); + return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len); } /* @@ -136,7 +176,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) * Closing files can be safely postponed until iput() - it's done there anyway. */ static int -ncp_delete_dentry(struct dentry * dentry) +ncp_delete_dentry(const struct dentry * dentry) { struct inode *inode = dentry->d_inode; @@ -266,7 +306,7 @@ leave_me:; static int -__ncp_lookup_validate(struct dentry *dentry) +ncp_lookup_validate(struct dentry *dentry, unsigned int flags) { struct ncp_server *server; struct dentry *parent; @@ -275,6 +315,12 @@ __ncp_lookup_validate(struct dentry *dentry) int res, val = 0, len; __u8 __name[NCP_MAXPATHLEN + 1]; + if (dentry == dentry->d_sb->s_root) + return 1; + + if (flags & LOOKUP_RCU) + return -ECHILD; + parent = dget_parent(dentry); dir = parent->d_inode; @@ -283,9 +329,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: @@ -296,16 +339,18 @@ __ncp_lookup_validate(struct dentry *dentry) if (val) goto finished; - DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - NCP_GET_AGE(dentry)); + ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n", + dentry, NCP_GET_AGE(dentry)); len = sizeof(__name); 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)); @@ -313,38 +358,32 @@ __ncp_lookup_validate(struct dentry *dentry) res = ncp_obtain_info(server, dir, __name, &(finfo.i)); } finfo.volume = finfo.i.volNumber; - DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n", - dentry->d_parent->d_name.name, __name, res); + ncp_dbg(2, "looked for %pd/%s, res=%d\n", + dentry->d_parent, __name, res); /* * If we didn't find it, or if it has a different dirEntNum to * 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_dbg(2, "found, but dirEntNum changed\n"); - ncp_update_inode2(dentry->d_inode, &finfo); + ncp_update_inode2(inode, &finfo); + mutex_unlock(&inode->i_mutex); } finished: - DDPRINTK("ncp_lookup_validate: result=%d\n", val); + ncp_dbg(2, "result=%d\n", val); dput(parent); 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) { @@ -364,21 +403,21 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) } /* If a pointer is invalid, we search the dentry. */ - spin_lock(&dcache_lock); + spin_lock(&parent->d_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dent = list_entry(next, struct dentry, d_u.d_child); if ((unsigned long)dent->d_fsdata == fpos) { if (dent->d_inode) - dget_locked(dent); + dget(dent); else dent = NULL; - spin_unlock(&dcache_lock); + spin_unlock(&parent->d_lock); goto out; } next = next->next; } - spin_unlock(&dcache_lock); + spin_unlock(&parent->d_lock); return NULL; out: @@ -400,9 +439,9 @@ static time_t ncp_obtain_mtime(struct dentry *dentry) return ncp_date_dos2unix(i.modifyTime, i.modifyDate); } -static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) +static int ncp_readdir(struct file *file, struct dir_context *ctx) { - struct dentry *dentry = filp->f_path.dentry; + struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; struct page *page = NULL; struct ncp_server *server = NCP_SERVER(inode); @@ -411,30 +450,19 @@ 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; - DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - (int) filp->f_pos); + ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos); result = -EIO; + /* Do not generate '.' and '..' when server is dead. */ if (!ncp_conn_valid(server)) goto out; result = 0; - if (filp->f_pos == 0) { - if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) - goto out; - filp->f_pos = 1; - } - if (filp->f_pos == 1) { - if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR)) - goto out; - filp->f_pos = 2; - } + if (!dir_emit_dots(file, ctx)) + goto out; page = grab_cache_page(&inode->i_data, 0); if (!page) @@ -446,7 +474,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) if (!PageUptodate(page) || !ctl.head.eof) goto init_cache; - if (filp->f_pos == 2) { + if (ctx->pos == 2) { if (jiffies - ctl.head.time >= NCP_MAX_AGE(server)) goto init_cache; @@ -456,10 +484,10 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) goto init_cache; } - if (filp->f_pos > ctl.head.end) + if (ctx->pos > ctl.head.end) goto finished; - ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2); + ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2); ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE; ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE; @@ -474,21 +502,21 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) } while (ctl.idx < NCP_DIRCACHE_SIZE) { struct dentry *dent; - int res; + bool over; dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], - dentry, filp->f_pos); + dentry, ctx->pos); if (!dent) goto invalid_cache; - res = filldir(dirent, dent->d_name.name, - dent->d_name.len, filp->f_pos, + over = !dir_emit(ctx, dent->d_name.name, + dent->d_name.len, dent->d_inode->i_ino, DT_UNKNOWN); dput(dent); - if (res) + if (over) goto finished; - filp->f_pos += 1; + ctx->pos += 1; ctl.idx += 1; - if (filp->f_pos > ctl.head.end) + if (ctx->pos > ctl.head.end) goto finished; } if (ctl.page) { @@ -525,13 +553,19 @@ init_cache: ctl.valid = 1; read_really: if (ncp_is_server_root(inode)) { - ncp_read_volume_list(filp, dirent, filldir, &ctl); + ncp_read_volume_list(file, ctx, &ctl); } else { - ncp_do_readdir(filp, dirent, filldir, &ctl); + ncp_do_readdir(file, ctx, &ctl); } 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 +573,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) +ncp_fill_cache(struct file *file, struct dir_context *ctx, + 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 dentry *newdent, *dentry = file->f_path.dentry; + struct inode *dir = dentry->d_inode; struct ncp_cache_control ctl = *ctrl; struct qstr qname; int valid = 0; @@ -564,42 +592,56 @@ 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; - qname.hash = full_name_hash(qname.name, qname.len); - - if (dentry->d_op && dentry->d_op->d_hash) - if (dentry->d_op->d_hash(dentry, &qname) != 0) - goto end_advance; - - newdent = d_lookup(dentry, &qname); + newdent = d_hash_and_lookup(dentry, &qname); + if (unlikely(IS_ERR(newdent))) + goto end_advance; if (!newdent) { newdent = d_alloc(dentry, &qname); if (!newdent) 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); + + /* + * NetWare's OS2 namespace is case preserving yet case + * insensitive. So we update dentry's name as received from + * server. Parent dir's i_mutex is locked because we're in + * readdir. + */ + dentry_update_name_case(newdent, &qname); } 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) { - newdent->d_op = &ncp_dentry_operations; - d_instantiate(newdent, newino); + entry->ino = iunique(dir->i_sb, 2); + inode = ncp_iget(dir->i_sb, entry); + if (inode) { + 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_nested(&inode->i_mutex, I_MUTEX_CHILD); + ncp_update_inode2(inode, entry); + mutex_unlock(&inode->i_mutex); + } if (newdent->d_inode) { ino = newdent->d_inode->i_ino; @@ -617,7 +659,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); } @@ -629,15 +671,13 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, end_advance: if (!valid) ctl.valid = 0; - if (!ctl.filled && (ctl.fpos == filp->f_pos)) { + if (!ctl.filled && (ctl.fpos == ctx->pos)) { if (!ino) - ino = find_inode_number(dentry, &qname); - if (!ino) - ino = iunique(inode->i_sb, 2); - ctl.filled = filldir(dirent, qname.name, qname.len, - filp->f_pos, ino, DT_UNKNOWN); + ino = iunique(dir->i_sb, 2); + ctl.filled = !dir_emit(ctx, qname.name, qname.len, + ino, DT_UNKNOWN); if (!ctl.filled) - filp->f_pos += 1; + ctx->pos += 1; } ctl.fpos += 1; ctl.idx += 1; @@ -646,46 +686,46 @@ end_advance: } static void -ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, +ncp_read_volume_list(struct file *file, struct dir_context *ctx, struct ncp_cache_control *ctl) { - struct dentry *dentry = filp->f_path.dentry; + struct dentry *dentry = file->f_path.dentry; struct inode *inode = dentry->d_inode; struct ncp_server *server = NCP_SERVER(inode); struct ncp_volume_info info; struct ncp_entry_info entry; int i; - DPRINTK("ncp_read_volume_list: pos=%ld\n", - (unsigned long) filp->f_pos); + ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->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; if (!strlen(info.volume_name)) continue; - DPRINTK("ncp_read_volume_list: found vol: %s\n", - info.volume_name); + ncp_dbg(1, "found vol: %s\n", info.volume_name); if (ncp_lookup_volume(server, info.volume_name, &entry.i)) { - DPRINTK("ncpfs: could not lookup vol %s\n", + ncp_dbg(1, "could not lookup vol %s\n", 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(file, ctx, ctl, &entry, inval_dentry)) return; } } static void -ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, +ncp_do_readdir(struct file *file, struct dir_context *ctx, struct ncp_cache_control *ctl) { - struct dentry *dentry = filp->f_path.dentry; + struct dentry *dentry = file->f_path.dentry; struct inode *dir = dentry->d_inode; struct ncp_server *server = NCP_SERVER(dir); struct nw_search_sequence seq; @@ -695,16 +735,13 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, int more; size_t bufsize; - DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - (unsigned long) filp->f_pos); - PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n", - dentry->d_name.name, NCP_FINFO(dir)->volNumber, - NCP_FINFO(dir)->dirEntNum); + ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos); + ncp_vdbg("init %pD, volnum=%d, dirent=%u\n", + file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum); err = ncp_initialize_search(server, dir, &seq); if (err) { - DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); + ncp_dbg(1, "init failed, err=%d\n", err); return; } /* We MUST NOT use server->buffer_size handshaked with server if we are @@ -739,7 +776,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(file, ctx, ctl, &entry, 0)) break; } } while (more); @@ -767,31 +804,32 @@ int ncp_conn_logged_in(struct super_block *sb) goto out; result = -ENOENT; if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) { - PPRINTK("ncp_conn_logged_in: %s not found\n", - server->m.mounted_vol); + ncp_vdbg("%s not found\n", server->m.mounted_vol); goto out; } dent = sb->s_root; 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"); + ncp_dbg(1, "sb->s_root->d_inode == NULL!\n"); } } else { - DPRINTK("ncpfs: sb->s_root == NULL!\n"); + ncp_dbg(1, "sb->s_root == NULL!\n"); } - } - result = 0; + } else + result = 0; out: return result; } -static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) +static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct ncp_server *server = NCP_SERVER(dir); struct inode *inode = NULL; @@ -799,13 +837,11 @@ 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; - PPRINTK("ncp_lookup: server lookup for %s/%s\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + ncp_vdbg("server lookup for %pd2\n", dentry); len = sizeof(__name); if (ncp_is_server_root(dir)) { @@ -813,14 +849,15 @@ 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)); if (!res) res = ncp_obtain_info(server, dir, __name, &(finfo.i)); } - PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n", - dentry->d_parent->d_name.name, __name, res); + ncp_vdbg("looked for %pd2, res=%d\n", dentry, res); /* * If we didn't find an entry, make a negative dentry. */ @@ -839,14 +876,12 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc if (inode) { ncp_new_dentry(dentry); add_entry: - dentry->d_op = &ncp_dentry_operations; d_add(dentry, inode); error = 0; } finished: - PPRINTK("ncp_lookup: result=%d\n", error); - unlock_kernel(); + ncp_vdbg("result=%d\n", error); return ERR_PTR(error); } @@ -869,13 +904,12 @@ out: return error; out_close: - PPRINTK("ncp_instantiate: %s/%s failed, closing file\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + ncp_vdbg("%pd2 failed, closing file\n", dentry); ncp_close_file(NCP_SERVER(dir), finfo->file_handle); goto out; } -int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, +int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev, __le32 attributes) { struct ncp_server *server = NCP_SERVER(dir); @@ -884,13 +918,7 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, int opmode; __u8 __name[NCP_MAXPATHLEN + 1]; - 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_vdbg("creating %pd2, mode=%hx\n", dentry, mode); ncp_age_dentry(server, dentry); len = sizeof(__name); @@ -917,8 +945,9 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, if (result) { if (result == 0x87) error = -ENAMETOOLONG; - DPRINTK("ncp_create: %s/%s failed\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + else if (result < 0) + error = result; + ncp_dbg(1, "%pd2 failed\n", dentry); goto out; } opmode = O_WRONLY; @@ -935,30 +964,23 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, error = ncp_instantiate(dir, dentry, &finfo); out: - unlock_kernel(); return error; } -static int ncp_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) +static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) { return ncp_create_new(dir, dentry, mode, 0, 0); } -static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct ncp_entry_info finfo; struct ncp_server *server = NCP_SERVER(dir); int error, len; __u8 __name[NCP_MAXPATHLEN + 1]; - 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_dbg(1, "making %pd2\n", dentry); ncp_age_dentry(server, dentry); len = sizeof(__name); @@ -967,12 +989,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 +1004,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; } @@ -995,17 +1017,7 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) int error, result, len; __u8 __name[NCP_MAXPATHLEN + 1]; - 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; + ncp_dbg(1, "removing %pd2\n", dentry); len = sizeof(__name); error = ncp_io2vol(server, __name, &len, dentry->d_name.name, @@ -1036,11 +1048,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,20 +1061,14 @@ 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); + ncp_dbg(1, "unlinking %pd2\n", dentry); - error = -EIO; - if (!ncp_conn_valid(server)) - goto out; - /* * Check whether to close the file ... */ if (inode) { - PPRINTK("ncp_unlink: closing file\n"); + ncp_vdbg("closing file\n"); ncp_make_closed(inode); } @@ -1077,8 +1082,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) #endif switch (error) { case 0x00: - DPRINTK("ncp: removed %s/%s\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + ncp_dbg(1, "removed %pd2\n", dentry); break; case 0x85: case 0x8A: @@ -1097,12 +1101,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; } @@ -1114,14 +1115,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, int old_len, new_len; __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1]; - DPRINTK("ncp_rename: %s/%s to %s/%s\n", - 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_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry); ncp_age_dentry(server, old_dentry); ncp_age_dentry(server, new_dentry); @@ -1151,8 +1145,8 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, #endif switch (error) { case 0x00: - DPRINTK("ncp renamed %s -> %s.\n", - old_dentry->d_name.name,new_dentry->d_name.name); + ncp_dbg(1, "renamed %pd -> %pd\n", + old_dentry, new_dentry); break; case 0x9E: error = -ENAMETOOLONG; @@ -1161,21 +1155,20 @@ 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; } static int ncp_mknod(struct inode * dir, struct dentry *dentry, - int mode, dev_t rdev) + umode_t mode, dev_t rdev) { if (!new_valid_dev(rdev)) return -EINVAL; if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) { - DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode); + ncp_dbg(1, "mode = 0%ho\n", mode); return ncp_create_new(dir, dentry, mode, rdev, 0); } return -EPERM; /* Strange, but true */ |
