From 634095dab2a2001844fc8b26673c0cb14a766cdf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Feb 2013 22:37:21 -0500 Subject: 9p: don't bother with private lock in ->d_fsdata; dentry->d_lock will do just fine Signed-off-by: Al Viro --- fs/9p/fid.c | 9 ++++----- fs/9p/fid.h | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/fid.c b/fs/9p/fid.c index afd4724b2d9..71bc36a03e7 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -54,14 +54,13 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) if (!dent) return -ENOMEM; - spin_lock_init(&dent->lock); INIT_LIST_HEAD(&dent->fidlist); dentry->d_fsdata = dent; } - spin_lock(&dent->lock); + spin_lock(&dentry->d_lock); list_add(&fid->dlist, &dent->fidlist); - spin_unlock(&dent->lock); + spin_unlock(&dentry->d_lock); return 0; } @@ -85,14 +84,14 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) dent = (struct v9fs_dentry *) dentry->d_fsdata; ret = NULL; if (dent) { - spin_lock(&dent->lock); + spin_lock(&dentry->d_lock); list_for_each_entry(fid, &dent->fidlist, dlist) { if (any || uid_eq(fid->uid, uid)) { ret = fid; break; } } - spin_unlock(&dent->lock); + spin_unlock(&dentry->d_lock); } return ret; diff --git a/fs/9p/fid.h b/fs/9p/fid.h index bb0b6e7f58f..469b5d51769 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -25,7 +25,6 @@ /** * struct v9fs_dentry - 9p private data stored in dentry d_fsdata - * @lock: protects the fidlist * @fidlist: list of FIDs currently associated with this dentry * * This structure defines the 9p private data associated with @@ -35,11 +34,12 @@ * inodes in order to more closely map functionality to the Plan 9 * expected behavior for FID reclaimation and tracking. * + * Protected by ->d_lock of dentry it belongs to. + * * See Also: Mapping FIDs to Linux VFS model in * Design and Implementation of the Linux 9P File System documentation */ struct v9fs_dentry { - spinlock_t lock; /* protect fidlist */ struct list_head fidlist; }; -- cgit v1.2.3-70-g09d2 From c4d30967f3020cda9df9ee22af79cd1f2c284244 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Feb 2013 22:51:08 -0500 Subject: 9p: turn fid->dlist into hlist Signed-off-by: Al Viro --- fs/9p/fid.c | 7 ++++--- fs/9p/fid.h | 2 +- fs/9p/vfs_dentry.c | 9 +++------ include/net/9p/client.h | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 71bc36a03e7..49de4264db9 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -54,12 +54,12 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) if (!dent) return -ENOMEM; - INIT_LIST_HEAD(&dent->fidlist); + INIT_HLIST_HEAD(&dent->fidlist); dentry->d_fsdata = dent; } spin_lock(&dentry->d_lock); - list_add(&fid->dlist, &dent->fidlist); + hlist_add_head(&fid->dlist, &dent->fidlist); spin_unlock(&dentry->d_lock); return 0; @@ -84,8 +84,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) dent = (struct v9fs_dentry *) dentry->d_fsdata; ret = NULL; if (dent) { + struct hlist_node *n; spin_lock(&dentry->d_lock); - list_for_each_entry(fid, &dent->fidlist, dlist) { + hlist_for_each_entry(fid, n, &dent->fidlist, dlist) { if (any || uid_eq(fid->uid, uid)) { ret = fid; break; diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 469b5d51769..86eeb34ce46 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -40,7 +40,7 @@ * Design and Implementation of the Linux 9P File System documentation */ struct v9fs_dentry { - struct list_head fidlist; + struct hlist_head fidlist; }; struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 9ad68628522..fcd49833ef8 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -84,16 +84,13 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry) static void v9fs_dentry_release(struct dentry *dentry) { struct v9fs_dentry *dent; - struct p9_fid *temp, *current_fid; - p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, dentry); dent = dentry->d_fsdata; if (dent) { - list_for_each_entry_safe(current_fid, temp, &dent->fidlist, - dlist) { - p9_client_clunk(current_fid); - } + struct hlist_node *p, *n; + hlist_for_each_safe(p, n, &dent->fidlist) + p9_client_clunk(hlist_entry(p, struct p9_fid, dlist)); kfree(dent); dentry->d_fsdata = NULL; diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 5ff70f433e8..4c7c01a7391 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -192,7 +192,7 @@ struct p9_fid { void *rdir; struct list_head flist; - struct list_head dlist; /* list of all fids attached to a dentry */ + struct hlist_node dlist; /* list of all fids attached to a dentry */ }; /** -- cgit v1.2.3-70-g09d2 From aaeb7ecfb48ad4c8942a26874322d8918524a04f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Feb 2013 01:13:19 -0500 Subject: v9fs: get rid of v9fs_dentry ->d_fsdata can act as hlist_head... Signed-off-by: Al Viro --- fs/9p/fid.c | 26 +++++--------------------- fs/9p/fid.h | 20 -------------------- fs/9p/vfs_dentry.c | 14 ++++---------- 3 files changed, 9 insertions(+), 51 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 49de4264db9..ddf618936d8 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -43,25 +43,9 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) { - struct v9fs_dentry *dent; - - p9_debug(P9_DEBUG_VFS, "fid %d dentry %s\n", - fid->fid, dentry->d_name.name); - - dent = dentry->d_fsdata; - if (!dent) { - dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL); - if (!dent) - return -ENOMEM; - - INIT_HLIST_HEAD(&dent->fidlist); - dentry->d_fsdata = dent; - } - spin_lock(&dentry->d_lock); - hlist_add_head(&fid->dlist, &dent->fidlist); + hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata); spin_unlock(&dentry->d_lock); - return 0; } @@ -75,18 +59,18 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) { - struct v9fs_dentry *dent; struct p9_fid *fid, *ret; p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n", dentry->d_name.name, dentry, from_kuid(&init_user_ns, uid), any); - dent = (struct v9fs_dentry *) dentry->d_fsdata; ret = NULL; - if (dent) { + /* we'll recheck under lock if there's anything to look in */ + if (dentry->d_fsdata) { + struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata; struct hlist_node *n; spin_lock(&dentry->d_lock); - hlist_for_each_entry(fid, n, &dent->fidlist, dlist) { + hlist_for_each_entry(fid, n, h, dlist) { if (any || uid_eq(fid->uid, uid)) { ret = fid; break; diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 86eeb34ce46..377eb6f2e7f 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -23,26 +23,6 @@ #define FS_9P_FID_H #include -/** - * struct v9fs_dentry - 9p private data stored in dentry d_fsdata - * @fidlist: list of FIDs currently associated with this dentry - * - * This structure defines the 9p private data associated with - * a particular dentry. In particular, this private data is used - * to lookup which 9P FID handle should be used for a particular VFS - * operation. FID handles are associated with dentries instead of - * inodes in order to more closely map functionality to the Plan 9 - * expected behavior for FID reclaimation and tracking. - * - * Protected by ->d_lock of dentry it belongs to. - * - * See Also: Mapping FIDs to Linux VFS model in - * Design and Implementation of the Linux 9P File System documentation - */ -struct v9fs_dentry { - struct hlist_head fidlist; -}; - struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); struct p9_fid *v9fs_fid_clone(struct dentry *dentry); int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index fcd49833ef8..f039b104a98 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -83,18 +83,12 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry) static void v9fs_dentry_release(struct dentry *dentry) { - struct v9fs_dentry *dent; + struct hlist_node *p, *n; p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, dentry); - dent = dentry->d_fsdata; - if (dent) { - struct hlist_node *p, *n; - hlist_for_each_safe(p, n, &dent->fidlist) - p9_client_clunk(hlist_entry(p, struct p9_fid, dlist)); - - kfree(dent); - dentry->d_fsdata = NULL; - } + hlist_for_each_safe(p, n, (struct hlist_head *)&dentry->d_fsdata) + p9_client_clunk(hlist_entry(p, struct p9_fid, dlist)); + dentry->d_fsdata = NULL; } static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) -- cgit v1.2.3-70-g09d2 From 2ea03e1d62d56c37737e43550c360b43a5e40a32 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Feb 2013 01:18:14 -0500 Subject: 9p: v9fs_fid_add() can't fail now Signed-off-by: Al Viro --- fs/9p/fid.c | 3 +-- fs/9p/fid.h | 2 +- fs/9p/vfs_inode.c | 9 ++------- fs/9p/vfs_inode_dotl.c | 19 +++++++------------ 4 files changed, 11 insertions(+), 22 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/fid.c b/fs/9p/fid.c index ddf618936d8..73ca55042cb 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -41,12 +41,11 @@ * */ -int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) +void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) { spin_lock(&dentry->d_lock); hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata); spin_unlock(&dentry->d_lock); - return 0; } /** diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 377eb6f2e7f..2b6787fcb62 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -25,6 +25,6 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); struct p9_fid *v9fs_fid_clone(struct dentry *dentry); -int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); +void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); struct p9_fid *v9fs_writeback_fid(struct dentry *dentry); #endif diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index b5340c829de..ce601d71a42 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -692,9 +692,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, "inode creation failed %d\n", err); goto error; } - err = v9fs_fid_add(dentry, fid); - if (err < 0) - goto error; + v9fs_fid_add(dentry, fid); d_instantiate(dentry, inode); } return ofid; @@ -830,9 +828,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, inode = NULL; goto error; } - result = v9fs_fid_add(dentry, fid); - if (result < 0) - goto error_iput; + v9fs_fid_add(dentry, fid); inst_out: /* * If we had a rename on the server and a parallel lookup @@ -845,7 +841,6 @@ inst_out: if (!IS_ERR(res)) return res; result = PTR_ERR(res); -error_iput: iput(inode); error: p9_client_clunk(fid); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 61e4fa70a6f..53687bbf229 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -333,9 +333,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, /* Now set the ACL based on the default value */ v9fs_set_create_acl(inode, fid, dacl, pacl); - err = v9fs_fid_add(dentry, fid); - if (err < 0) - goto error; + v9fs_fid_add(dentry, fid); d_instantiate(dentry, inode); v9inode = V9FS_I(inode); @@ -453,12 +451,11 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, err); goto error; } - err = v9fs_fid_add(dentry, fid); - if (err < 0) - goto error; + v9fs_fid_add(dentry, fid); v9fs_set_create_acl(inode, fid, dacl, pacl); d_instantiate(dentry, inode); fid = NULL; + err = 0; } else { /* * Not in cached mode. No need to populate @@ -747,11 +744,10 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, err); goto error; } - err = v9fs_fid_add(dentry, fid); - if (err < 0) - goto error; + v9fs_fid_add(dentry, fid); d_instantiate(dentry, inode); fid = NULL; + err = 0; } else { /* Not in cached mode. No need to populate inode with stat */ inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0); @@ -900,11 +896,10 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode, goto error; } v9fs_set_create_acl(inode, fid, dacl, pacl); - err = v9fs_fid_add(dentry, fid); - if (err < 0) - goto error; + v9fs_fid_add(dentry, fid); d_instantiate(dentry, inode); fid = NULL; + err = 0; } else { /* * Not in cached mode. No need to populate inode with stat. -- cgit v1.2.3-70-g09d2 From 3509b678a6bb93a49d9603c9c8028c8d95019539 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Feb 2013 01:21:38 -0500 Subject: 9p: double iput() in ->lookup() if d_materialise_unique() fails d_materialise_unique() does iput() itself. Signed-off-by: Al Viro --- fs/9p/vfs_inode.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/9p') diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index ce601d71a42..cbee5ec4039 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -841,7 +841,6 @@ inst_out: if (!IS_ERR(res)) return res; result = PTR_ERR(res); - iput(inode); error: p9_client_clunk(fid); -- cgit v1.2.3-70-g09d2 From 7b5be621993567d39f09a5190c4d651241be296f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Feb 2013 01:28:21 -0500 Subject: 9p: untangle ->lookup() a bit Signed-off-by: Al Viro --- fs/9p/vfs_inode.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index cbee5ec4039..80ff01bcae3 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -788,7 +788,6 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, struct p9_fid *dfid, *fid; struct inode *inode; char *name; - int result = 0; p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n", dir, dentry->d_name.name, dentry, flags); @@ -806,13 +805,11 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, name = (char *) dentry->d_name.name; fid = p9_client_walk(dfid, 1, &name, 1); if (IS_ERR(fid)) { - result = PTR_ERR(fid); - if (result == -ENOENT) { - inode = NULL; - goto inst_out; + if (fid == ERR_PTR(-ENOENT)) { + d_add(dentry, NULL); + return NULL; } - - return ERR_PTR(result); + return ERR_CAST(fid); } /* * Make sure we don't use a wrong inode due to parallel @@ -824,12 +821,10 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, else inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { - result = PTR_ERR(inode); - inode = NULL; - goto error; + p9_client_clunk(fid); + return ERR_CAST(inode); } v9fs_fid_add(dentry, fid); -inst_out: /* * If we had a rename on the server and a parallel lookup * for the new name, then make sure we instantiate with @@ -838,13 +833,9 @@ inst_out: * k/b. */ res = d_materialise_unique(dentry, inode); - if (!IS_ERR(res)) - return res; - result = PTR_ERR(res); -error: - p9_client_clunk(fid); - - return ERR_PTR(result); + if (IS_ERR(res)) + p9_client_clunk(fid); + return res; } static int -- cgit v1.2.3-70-g09d2 From a3b2157e72e321fa313389ac744bbf6d6cb6986d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Feb 2013 01:29:48 -0500 Subject: 9p: make sure ->lookup() adds fid to the right dentry Signed-off-by: Al Viro --- fs/9p/vfs_inode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 80ff01bcae3..d86edc8d3fd 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -824,7 +824,6 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, p9_client_clunk(fid); return ERR_CAST(inode); } - v9fs_fid_add(dentry, fid); /* * If we had a rename on the server and a parallel lookup * for the new name, then make sure we instantiate with @@ -833,7 +832,11 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, * k/b. */ res = d_materialise_unique(dentry, inode); - if (IS_ERR(res)) + if (!res) + v9fs_fid_add(dentry, fid); + else if (!IS_ERR(res)) + v9fs_fid_add(res, fid); + else p9_client_clunk(fid); return res; } -- cgit v1.2.3-70-g09d2 From 5e608671dfbfd6a9556c31df65a4f147439eed59 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 28 Feb 2013 01:50:20 -0500 Subject: 9p: if v9fs_fid_lookup() gets to asking server, it'd better have hashed dentry ... otherwise the path we'd built isn't worth much. Don't accept such fids obtained from paths unless dentry is still alived by the end of the work. Signed-off-by: Al Viro --- fs/9p/fid.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 73ca55042cb..616abaf1c6c 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -41,10 +41,15 @@ * */ +static inline void __add_fid(struct dentry *dentry, struct p9_fid *fid) +{ + hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata); +} + void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) { spin_lock(&dentry->d_lock); - hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata); + __add_fid(dentry, fid); spin_unlock(&dentry->d_lock); } @@ -198,8 +203,17 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, } kfree(wnames); fid_out: - if (!IS_ERR(fid)) - v9fs_fid_add(dentry, fid); + if (!IS_ERR(fid)) { + spin_lock(&dentry->d_lock); + if (d_unhashed(dentry)) { + spin_unlock(&dentry->d_lock); + p9_client_clunk(fid); + fid = ERR_PTR(-ENOENT); + } else { + __add_fid(dentry, fid); + spin_unlock(&dentry->d_lock); + } + } err_out: up_read(&v9ses->rename_sem); return fid; -- cgit v1.2.3-70-g09d2