diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-04 01:23:02 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-04 01:23:03 +0400 |
commit | 56a79b7b021bf1b08334e63c2c14b280e2dbf47a (patch) | |
tree | 0419233e6194f4f12073c9284852885aa8984bec /fs/9p | |
parent | 1c82315a12144cde732636e259d39e3ee81b3c5b (diff) | |
parent | dcf787f39162ce32ca325b3e784aba2d2444619a (diff) | |
download | linux-56a79b7b021bf1b08334e63c2c14b280e2dbf47a.tar.xz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more VFS bits from Al Viro:
"Unfortunately, it looks like xattr series will have to wait until the
next cycle ;-/
This pile contains 9p cleanups and fixes (races in v9fs_fid_add()
etc), fixup for nommu breakage in shmem.c, several cleanups and a bit
more file_inode() work"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
constify path_get/path_put and fs_struct.c stuff
fix nommu breakage in shmem.c
cache the value of file_inode() in struct file
9p: if v9fs_fid_lookup() gets to asking server, it'd better have hashed dentry
9p: make sure ->lookup() adds fid to the right dentry
9p: untangle ->lookup() a bit
9p: double iput() in ->lookup() if d_materialise_unique() fails
9p: v9fs_fid_add() can't fail now
v9fs: get rid of v9fs_dentry
9p: turn fid->dlist into hlist
9p: don't bother with private lock in ->d_fsdata; dentry->d_lock will do just fine
more file_inode() open-coded instances
selinux: opened file can't have NULL or negative ->f_path.dentry
(In the meantime, the hlist traversal macros have changed, so this
required a semantic conflict fixup for the newly hlistified fid->dlist)
Diffstat (limited to 'fs/9p')
-rw-r--r-- | fs/9p/fid.c | 54 | ||||
-rw-r--r-- | fs/9p/fid.h | 22 | ||||
-rw-r--r-- | fs/9p/vfs_dentry.c | 17 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 40 | ||||
-rw-r--r-- | fs/9p/vfs_inode_dotl.c | 19 |
5 files changed, 51 insertions, 101 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index afd4724b2d92..d51ec9fafcc8 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -41,29 +41,16 @@ * */ -int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) +static inline void __add_fid(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; - - spin_lock_init(&dent->lock); - INIT_LIST_HEAD(&dent->fidlist); - dentry->d_fsdata = dent; - } - - spin_lock(&dent->lock); - list_add(&fid->dlist, &dent->fidlist); - spin_unlock(&dent->lock); + hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata); +} - return 0; +void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) +{ + spin_lock(&dentry->d_lock); + __add_fid(dentry, fid); + spin_unlock(&dentry->d_lock); } /** @@ -76,23 +63,23 @@ 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) { - spin_lock(&dent->lock); - list_for_each_entry(fid, &dent->fidlist, dlist) { + /* 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; + spin_lock(&dentry->d_lock); + hlist_for_each_entry(fid, h, dlist) { if (any || uid_eq(fid->uid, uid)) { ret = fid; break; } } - spin_unlock(&dent->lock); + spin_unlock(&dentry->d_lock); } return ret; @@ -215,8 +202,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; diff --git a/fs/9p/fid.h b/fs/9p/fid.h index bb0b6e7f58fc..2b6787fcb626 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -23,28 +23,8 @@ #define FS_9P_FID_H #include <linux/list.h> -/** - * 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 - * 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. - * - * 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; -}; - 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_dentry.c b/fs/9p/vfs_dentry.c index 9ad68628522c..f039b104a98e 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -83,21 +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 p9_fid *temp, *current_fid; - + 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) { - list_for_each_entry_safe(current_fid, temp, &dent->fidlist, - dlist) { - p9_client_clunk(current_fid); - } - - 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) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index b5340c829de1..d86edc8d3fd0 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; @@ -790,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); @@ -808,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 @@ -826,14 +821,9 @@ 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); } - result = v9fs_fid_add(dentry, fid); - if (result < 0) - goto error_iput; -inst_out: /* * If we had a rename on the server and a parallel lookup * for the new name, then make sure we instantiate with @@ -842,15 +832,13 @@ inst_out: * k/b. */ res = d_materialise_unique(dentry, inode); - if (!IS_ERR(res)) - return res; - result = PTR_ERR(res); -error_iput: - iput(inode); -error: - p9_client_clunk(fid); - - return ERR_PTR(result); + if (!res) + v9fs_fid_add(dentry, fid); + else if (!IS_ERR(res)) + v9fs_fid_add(res, fid); + else + p9_client_clunk(fid); + return res; } static int diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 61e4fa70a6fa..53687bbf2296 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. |