diff options
Diffstat (limited to 'drivers/staging/smbfs')
-rw-r--r-- | drivers/staging/smbfs/cache.c | 16 | ||||
-rw-r--r-- | drivers/staging/smbfs/dir.c | 55 | ||||
-rw-r--r-- | drivers/staging/smbfs/file.c | 5 | ||||
-rw-r--r-- | drivers/staging/smbfs/inode.c | 13 | ||||
-rw-r--r-- | drivers/staging/smbfs/proto.h | 2 |
5 files changed, 55 insertions, 36 deletions
diff --git a/drivers/staging/smbfs/cache.c b/drivers/staging/smbfs/cache.c index dbb9865..f2a1323 100644 --- a/drivers/staging/smbfs/cache.c +++ b/drivers/staging/smbfs/cache.c @@ -62,7 +62,7 @@ smb_invalidate_dircache_entries(struct dentry *parent) struct list_head *next; struct dentry *dentry; - spin_lock(&dcache_lock); + spin_lock(&parent->d_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dentry = list_entry(next, struct dentry, d_u.d_child); @@ -70,7 +70,7 @@ smb_invalidate_dircache_entries(struct dentry *parent) smb_age_dentry(server, dentry); next = next->next; } - spin_unlock(&dcache_lock); + spin_unlock(&parent->d_lock); } /* @@ -96,13 +96,13 @@ smb_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; goto out_unlock; @@ -111,7 +111,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) } dent = NULL; out_unlock: - spin_unlock(&dcache_lock); + spin_unlock(&parent->d_lock); return dent; } @@ -134,7 +134,7 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 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) + if (dentry->d_op->d_hash(dentry, inode, qname) != 0) goto end_advance; newdent = d_lookup(dentry, qname); @@ -145,8 +145,8 @@ smb_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); + /* dir i_mutex is locked because we're in readdir */ + dentry_update_name_case(newdent, qname); } if (!newdent->d_inode) { diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c index f088ea2..87a3a9b 100644 --- a/drivers/staging/smbfs/dir.c +++ b/drivers/staging/smbfs/dir.c @@ -14,6 +14,7 @@ #include <linux/ctype.h> #include <linux/net.h> #include <linux/sched.h> +#include <linux/namei.h> #include "smb_fs.h" #include "smb_mount.h" @@ -274,9 +275,13 @@ smb_dir_open(struct inode *dir, struct file *file) * Dentry operations routines */ static int smb_lookup_validate(struct dentry *, struct nameidata *); -static int smb_hash_dentry(struct dentry *, struct qstr *); -static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *); -static int smb_delete_dentry(struct dentry *); +static int smb_hash_dentry(const struct dentry *, const struct inode *, + struct qstr *); +static int smb_compare_dentry(const struct dentry *, + const struct inode *, + const struct dentry *, const struct inode *, + unsigned int, const char *, const struct qstr *); +static int smb_delete_dentry(const struct dentry *); static const struct dentry_operations smbfs_dentry_operations = { @@ -297,13 +302,20 @@ static const struct dentry_operations smbfs_dentry_operations_case = * This is the callback when the dcache has a lookup hit. */ static int -smb_lookup_validate(struct dentry * dentry, struct nameidata *nd) +smb_lookup_validate(struct dentry *dentry, struct nameidata *nd) { - struct smb_sb_info *server = server_from_dentry(dentry); - struct inode * inode = dentry->d_inode; - unsigned long age = jiffies - dentry->d_time; + struct smb_sb_info *server; + struct inode *inode; + unsigned long age; int valid; + if (nd->flags & LOOKUP_RCU) + return -ECHILD; + + server = server_from_dentry(dentry); + inode = dentry->d_inode; + age = jiffies - dentry->d_time; + /* * The default validation is based on dentry age: * we believe in dentries for a few seconds. (But each @@ -333,7 +345,8 @@ smb_lookup_validate(struct dentry * dentry, struct nameidata *nd) } static int -smb_hash_dentry(struct dentry *dir, struct qstr *this) +smb_hash_dentry(const struct dentry *dir, const struct inode *inode, + struct qstr *this) { unsigned long hash; int i; @@ -347,14 +360,17 @@ smb_hash_dentry(struct dentry *dir, struct qstr *this) } static int -smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b) +smb_compare_dentry(const struct dentry *parent, + const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) { int i, result = 1; - if (a->len != b->len) + if (len != name->len) goto out; - for (i=0; i < a->len; i++) { - if (tolower(a->name[i]) != tolower(b->name[i])) + for (i=0; i < len; i++) { + if (tolower(str[i]) != tolower(name->name[i])) goto out; } result = 0; @@ -367,7 +383,7 @@ out: * We use this to unhash dentries with bad inodes. */ static int -smb_delete_dentry(struct dentry * dentry) +smb_delete_dentry(const struct dentry *dentry) { if (dentry->d_inode) { if (is_bad_inode(dentry->d_inode)) { @@ -387,12 +403,6 @@ smb_delete_dentry(struct dentry * dentry) void smb_new_dentry(struct dentry *dentry) { - struct smb_sb_info *server = server_from_dentry(dentry); - - if (server->mnt->flags & SMB_MOUNT_CASE) - dentry->d_op = &smbfs_dentry_operations_case; - else - dentry->d_op = &smbfs_dentry_operations; dentry->d_time = jiffies; } @@ -424,7 +434,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct smb_fattr finfo; struct inode *inode; int error; - struct smb_sb_info *server; error = -ENAMETOOLONG; if (dentry->d_name.len > SMB_MAXNAMELEN) @@ -452,12 +461,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) inode = smb_iget(dir->i_sb, &finfo); if (inode) { add_entry: - server = server_from_dentry(dentry); - if (server->mnt->flags & SMB_MOUNT_CASE) - dentry->d_op = &smbfs_dentry_operations_case; - else - dentry->d_op = &smbfs_dentry_operations; - d_add(dentry, inode); smb_renew_times(dentry); error = 0; diff --git a/drivers/staging/smbfs/file.c b/drivers/staging/smbfs/file.c index 5dcd19c..31372e7 100644 --- a/drivers/staging/smbfs/file.c +++ b/drivers/staging/smbfs/file.c @@ -407,11 +407,14 @@ smb_file_release(struct inode *inode, struct file * file) * privileges, so we need our own check for this. */ static int -smb_file_permission(struct inode *inode, int mask) +smb_file_permission(struct inode *inode, int mask, unsigned int flags) { int mode = inode->i_mode; int error = 0; + if (flags & IPERM_FLAG_RCU) + return -ECHILD; + VERBOSE("mode=%x, mask=%x\n", mode, mask); /* Look at user permissions */ diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c index 540a984..0778589 100644 --- a/drivers/staging/smbfs/inode.c +++ b/drivers/staging/smbfs/inode.c @@ -62,11 +62,18 @@ static struct inode *smb_alloc_inode(struct super_block *sb) return &ei->vfs_inode; } -static void smb_destroy_inode(struct inode *inode) +static void smb_i_callback(struct rcu_head *head) { + struct inode *inode = container_of(head, struct inode, i_rcu); + INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(smb_inode_cachep, SMB_I(inode)); } +static void smb_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, smb_i_callback); +} + static void init_once(void *foo) { struct smb_inode_info *ei = (struct smb_inode_info *) foo; @@ -607,6 +614,10 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) printk(KERN_ERR "smbfs: failed to start smbiod\n"); goto out_no_smbiod; } + if (server->mnt->flags & SMB_MOUNT_CASE) + sb->s_d_op = &smbfs_dentry_operations_case; + else + sb->s_d_op = &smbfs_dentry_operations; /* * Keep the super block locked while we get the root inode. diff --git a/drivers/staging/smbfs/proto.h b/drivers/staging/smbfs/proto.h index 05939a6..3883cb1 100644 --- a/drivers/staging/smbfs/proto.h +++ b/drivers/staging/smbfs/proto.h @@ -38,6 +38,8 @@ extern void smb_install_null_ops(struct smb_ops *ops); extern const struct file_operations smb_dir_operations; extern const struct inode_operations smb_dir_inode_operations; extern const struct inode_operations smb_dir_inode_operations_unix; +extern const struct dentry_operations smbfs_dentry_operations_case; +extern const struct dentry_operations smbfs_dentry_operations; extern void smb_new_dentry(struct dentry *dentry); extern void smb_renew_times(struct dentry *dentry); /* cache.c */ |