diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-03 16:23:02 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-03 16:23:03 -0500 |
| commit | 56a79b7b021bf1b08334e63c2c14b280e2dbf47a (patch) | |
| tree | 0419233e6194f4f12073c9284852885aa8984bec /fs/9p | |
| parent | 1c82315a12144cde732636e259d39e3ee81b3c5b (diff) | |
| parent | dcf787f39162ce32ca325b3e784aba2d2444619a (diff) | |
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 @@ | |||
| 41 | * | 41 | * |
| 42 | */ | 42 | */ |
| 43 | 43 | ||
| 44 | int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) | 44 | static inline void __add_fid(struct dentry *dentry, struct p9_fid *fid) |
| 45 | { | 45 | { |
| 46 | struct v9fs_dentry *dent; | 46 | hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata); |
| 47 | 47 | } | |
| 48 | p9_debug(P9_DEBUG_VFS, "fid %d dentry %s\n", | ||
| 49 | fid->fid, dentry->d_name.name); | ||
| 50 | |||
| 51 | dent = dentry->d_fsdata; | ||
| 52 | if (!dent) { | ||
| 53 | dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL); | ||
| 54 | if (!dent) | ||
| 55 | return -ENOMEM; | ||
| 56 | |||
| 57 | spin_lock_init(&dent->lock); | ||
| 58 | INIT_LIST_HEAD(&dent->fidlist); | ||
| 59 | dentry->d_fsdata = dent; | ||
| 60 | } | ||
| 61 | |||
| 62 | spin_lock(&dent->lock); | ||
| 63 | list_add(&fid->dlist, &dent->fidlist); | ||
| 64 | spin_unlock(&dent->lock); | ||
| 65 | 48 | ||
| 66 | return 0; | 49 | void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) |
| 50 | { | ||
| 51 | spin_lock(&dentry->d_lock); | ||
| 52 | __add_fid(dentry, fid); | ||
| 53 | spin_unlock(&dentry->d_lock); | ||
| 67 | } | 54 | } |
| 68 | 55 | ||
| 69 | /** | 56 | /** |
| @@ -76,23 +63,23 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid) | |||
| 76 | 63 | ||
| 77 | static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) | 64 | static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) |
| 78 | { | 65 | { |
| 79 | struct v9fs_dentry *dent; | ||
| 80 | struct p9_fid *fid, *ret; | 66 | struct p9_fid *fid, *ret; |
| 81 | 67 | ||
| 82 | p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n", | 68 | p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n", |
| 83 | dentry->d_name.name, dentry, from_kuid(&init_user_ns, uid), | 69 | dentry->d_name.name, dentry, from_kuid(&init_user_ns, uid), |
| 84 | any); | 70 | any); |
| 85 | dent = (struct v9fs_dentry *) dentry->d_fsdata; | ||
| 86 | ret = NULL; | 71 | ret = NULL; |
| 87 | if (dent) { | 72 | /* we'll recheck under lock if there's anything to look in */ |
| 88 | spin_lock(&dent->lock); | 73 | if (dentry->d_fsdata) { |
| 89 | list_for_each_entry(fid, &dent->fidlist, dlist) { | 74 | struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata; |
| 75 | spin_lock(&dentry->d_lock); | ||
| 76 | hlist_for_each_entry(fid, h, dlist) { | ||
| 90 | if (any || uid_eq(fid->uid, uid)) { | 77 | if (any || uid_eq(fid->uid, uid)) { |
| 91 | ret = fid; | 78 | ret = fid; |
| 92 | break; | 79 | break; |
| 93 | } | 80 | } |
| 94 | } | 81 | } |
| 95 | spin_unlock(&dent->lock); | 82 | spin_unlock(&dentry->d_lock); |
| 96 | } | 83 | } |
| 97 | 84 | ||
| 98 | return ret; | 85 | return ret; |
| @@ -215,8 +202,17 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, | |||
| 215 | } | 202 | } |
| 216 | kfree(wnames); | 203 | kfree(wnames); |
| 217 | fid_out: | 204 | fid_out: |
| 218 | if (!IS_ERR(fid)) | 205 | if (!IS_ERR(fid)) { |
| 219 | v9fs_fid_add(dentry, fid); | 206 | spin_lock(&dentry->d_lock); |
| 207 | if (d_unhashed(dentry)) { | ||
| 208 | spin_unlock(&dentry->d_lock); | ||
| 209 | p9_client_clunk(fid); | ||
| 210 | fid = ERR_PTR(-ENOENT); | ||
| 211 | } else { | ||
| 212 | __add_fid(dentry, fid); | ||
| 213 | spin_unlock(&dentry->d_lock); | ||
| 214 | } | ||
| 215 | } | ||
| 220 | err_out: | 216 | err_out: |
| 221 | up_read(&v9ses->rename_sem); | 217 | up_read(&v9ses->rename_sem); |
| 222 | return fid; | 218 | 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 @@ | |||
| 23 | #define FS_9P_FID_H | 23 | #define FS_9P_FID_H |
| 24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
| 25 | 25 | ||
| 26 | /** | ||
| 27 | * struct v9fs_dentry - 9p private data stored in dentry d_fsdata | ||
| 28 | * @lock: protects the fidlist | ||
| 29 | * @fidlist: list of FIDs currently associated with this dentry | ||
| 30 | * | ||
| 31 | * This structure defines the 9p private data associated with | ||
| 32 | * a particular dentry. In particular, this private data is used | ||
| 33 | * to lookup which 9P FID handle should be used for a particular VFS | ||
| 34 | * operation. FID handles are associated with dentries instead of | ||
| 35 | * inodes in order to more closely map functionality to the Plan 9 | ||
| 36 | * expected behavior for FID reclaimation and tracking. | ||
| 37 | * | ||
| 38 | * See Also: Mapping FIDs to Linux VFS model in | ||
| 39 | * Design and Implementation of the Linux 9P File System documentation | ||
| 40 | */ | ||
| 41 | struct v9fs_dentry { | ||
| 42 | spinlock_t lock; /* protect fidlist */ | ||
| 43 | struct list_head fidlist; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); | 26 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); |
| 47 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry); | 27 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry); |
| 48 | int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); | 28 | void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); |
| 49 | struct p9_fid *v9fs_writeback_fid(struct dentry *dentry); | 29 | struct p9_fid *v9fs_writeback_fid(struct dentry *dentry); |
| 50 | #endif | 30 | #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) | |||
| 83 | 83 | ||
| 84 | static void v9fs_dentry_release(struct dentry *dentry) | 84 | static void v9fs_dentry_release(struct dentry *dentry) |
| 85 | { | 85 | { |
| 86 | struct v9fs_dentry *dent; | 86 | struct hlist_node *p, *n; |
| 87 | struct p9_fid *temp, *current_fid; | ||
| 88 | |||
| 89 | p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", | 87 | p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", |
| 90 | dentry->d_name.name, dentry); | 88 | dentry->d_name.name, dentry); |
| 91 | dent = dentry->d_fsdata; | 89 | hlist_for_each_safe(p, n, (struct hlist_head *)&dentry->d_fsdata) |
| 92 | if (dent) { | 90 | p9_client_clunk(hlist_entry(p, struct p9_fid, dlist)); |
| 93 | list_for_each_entry_safe(current_fid, temp, &dent->fidlist, | 91 | dentry->d_fsdata = NULL; |
| 94 | dlist) { | ||
| 95 | p9_client_clunk(current_fid); | ||
| 96 | } | ||
| 97 | |||
| 98 | kfree(dent); | ||
| 99 | dentry->d_fsdata = NULL; | ||
| 100 | } | ||
| 101 | } | 92 | } |
| 102 | 93 | ||
| 103 | static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | 94 | 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, | |||
| 692 | "inode creation failed %d\n", err); | 692 | "inode creation failed %d\n", err); |
| 693 | goto error; | 693 | goto error; |
| 694 | } | 694 | } |
| 695 | err = v9fs_fid_add(dentry, fid); | 695 | v9fs_fid_add(dentry, fid); |
| 696 | if (err < 0) | ||
| 697 | goto error; | ||
| 698 | d_instantiate(dentry, inode); | 696 | d_instantiate(dentry, inode); |
| 699 | } | 697 | } |
| 700 | return ofid; | 698 | return ofid; |
| @@ -790,7 +788,6 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 790 | struct p9_fid *dfid, *fid; | 788 | struct p9_fid *dfid, *fid; |
| 791 | struct inode *inode; | 789 | struct inode *inode; |
| 792 | char *name; | 790 | char *name; |
| 793 | int result = 0; | ||
| 794 | 791 | ||
| 795 | p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n", | 792 | p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n", |
| 796 | dir, dentry->d_name.name, dentry, flags); | 793 | dir, dentry->d_name.name, dentry, flags); |
| @@ -808,13 +805,11 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 808 | name = (char *) dentry->d_name.name; | 805 | name = (char *) dentry->d_name.name; |
| 809 | fid = p9_client_walk(dfid, 1, &name, 1); | 806 | fid = p9_client_walk(dfid, 1, &name, 1); |
| 810 | if (IS_ERR(fid)) { | 807 | if (IS_ERR(fid)) { |
| 811 | result = PTR_ERR(fid); | 808 | if (fid == ERR_PTR(-ENOENT)) { |
| 812 | if (result == -ENOENT) { | 809 | d_add(dentry, NULL); |
| 813 | inode = NULL; | 810 | return NULL; |
| 814 | goto inst_out; | ||
| 815 | } | 811 | } |
| 816 | 812 | return ERR_CAST(fid); | |
| 817 | return ERR_PTR(result); | ||
| 818 | } | 813 | } |
| 819 | /* | 814 | /* |
| 820 | * Make sure we don't use a wrong inode due to parallel | 815 | * 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, | |||
| 826 | else | 821 | else |
| 827 | inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); | 822 | inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); |
| 828 | if (IS_ERR(inode)) { | 823 | if (IS_ERR(inode)) { |
| 829 | result = PTR_ERR(inode); | 824 | p9_client_clunk(fid); |
| 830 | inode = NULL; | 825 | return ERR_CAST(inode); |
| 831 | goto error; | ||
| 832 | } | 826 | } |
| 833 | result = v9fs_fid_add(dentry, fid); | ||
| 834 | if (result < 0) | ||
| 835 | goto error_iput; | ||
| 836 | inst_out: | ||
| 837 | /* | 827 | /* |
| 838 | * If we had a rename on the server and a parallel lookup | 828 | * If we had a rename on the server and a parallel lookup |
| 839 | * for the new name, then make sure we instantiate with | 829 | * for the new name, then make sure we instantiate with |
| @@ -842,15 +832,13 @@ inst_out: | |||
| 842 | * k/b. | 832 | * k/b. |
| 843 | */ | 833 | */ |
| 844 | res = d_materialise_unique(dentry, inode); | 834 | res = d_materialise_unique(dentry, inode); |
| 845 | if (!IS_ERR(res)) | 835 | if (!res) |
| 846 | return res; | 836 | v9fs_fid_add(dentry, fid); |
| 847 | result = PTR_ERR(res); | 837 | else if (!IS_ERR(res)) |
| 848 | error_iput: | 838 | v9fs_fid_add(res, fid); |
| 849 | iput(inode); | 839 | else |
| 850 | error: | 840 | p9_client_clunk(fid); |
| 851 | p9_client_clunk(fid); | 841 | return res; |
| 852 | |||
| 853 | return ERR_PTR(result); | ||
| 854 | } | 842 | } |
| 855 | 843 | ||
| 856 | static int | 844 | 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, | |||
| 333 | /* Now set the ACL based on the default value */ | 333 | /* Now set the ACL based on the default value */ |
| 334 | v9fs_set_create_acl(inode, fid, dacl, pacl); | 334 | v9fs_set_create_acl(inode, fid, dacl, pacl); |
| 335 | 335 | ||
| 336 | err = v9fs_fid_add(dentry, fid); | 336 | v9fs_fid_add(dentry, fid); |
| 337 | if (err < 0) | ||
| 338 | goto error; | ||
| 339 | d_instantiate(dentry, inode); | 337 | d_instantiate(dentry, inode); |
| 340 | 338 | ||
| 341 | v9inode = V9FS_I(inode); | 339 | v9inode = V9FS_I(inode); |
| @@ -453,12 +451,11 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, | |||
| 453 | err); | 451 | err); |
| 454 | goto error; | 452 | goto error; |
| 455 | } | 453 | } |
| 456 | err = v9fs_fid_add(dentry, fid); | 454 | v9fs_fid_add(dentry, fid); |
| 457 | if (err < 0) | ||
| 458 | goto error; | ||
| 459 | v9fs_set_create_acl(inode, fid, dacl, pacl); | 455 | v9fs_set_create_acl(inode, fid, dacl, pacl); |
| 460 | d_instantiate(dentry, inode); | 456 | d_instantiate(dentry, inode); |
| 461 | fid = NULL; | 457 | fid = NULL; |
| 458 | err = 0; | ||
| 462 | } else { | 459 | } else { |
| 463 | /* | 460 | /* |
| 464 | * Not in cached mode. No need to populate | 461 | * Not in cached mode. No need to populate |
| @@ -747,11 +744,10 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | |||
| 747 | err); | 744 | err); |
| 748 | goto error; | 745 | goto error; |
| 749 | } | 746 | } |
| 750 | err = v9fs_fid_add(dentry, fid); | 747 | v9fs_fid_add(dentry, fid); |
| 751 | if (err < 0) | ||
| 752 | goto error; | ||
| 753 | d_instantiate(dentry, inode); | 748 | d_instantiate(dentry, inode); |
| 754 | fid = NULL; | 749 | fid = NULL; |
| 750 | err = 0; | ||
| 755 | } else { | 751 | } else { |
| 756 | /* Not in cached mode. No need to populate inode with stat */ | 752 | /* Not in cached mode. No need to populate inode with stat */ |
| 757 | inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0); | 753 | 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, | |||
| 900 | goto error; | 896 | goto error; |
| 901 | } | 897 | } |
| 902 | v9fs_set_create_acl(inode, fid, dacl, pacl); | 898 | v9fs_set_create_acl(inode, fid, dacl, pacl); |
| 903 | err = v9fs_fid_add(dentry, fid); | 899 | v9fs_fid_add(dentry, fid); |
| 904 | if (err < 0) | ||
| 905 | goto error; | ||
| 906 | d_instantiate(dentry, inode); | 900 | d_instantiate(dentry, inode); |
| 907 | fid = NULL; | 901 | fid = NULL; |
| 902 | err = 0; | ||
| 908 | } else { | 903 | } else { |
| 909 | /* | 904 | /* |
| 910 | * Not in cached mode. No need to populate inode with stat. | 905 | * Not in cached mode. No need to populate inode with stat. |
