diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 15:44:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 15:44:24 -0400 |
commit | b05430fc9341fea7a6228a3611c850a476809596 (patch) | |
tree | 91bd662d269a3478db78d6a04a34901f0cfe521b /fs | |
parent | d0d272771035a36a7839bb70ab6ebae3f4f4960b (diff) | |
parent | 48f5ec21d9c67e881ff35343988e290ef5cf933f (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs pile 3 (of many) from Al Viro:
"Waiman's conversion of d_path() and bits related to it,
kern_path_mountpoint(), several cleanups and fixes (exportfs
one is -stable fodder, IMO).
There definitely will be more... ;-/"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
split read_seqretry_or_unlock(), convert d_walk() to resulting primitives
dcache: Translating dentry into pathname without taking rename_lock
autofs4 - fix device ioctl mount lookup
introduce kern_path_mountpoint()
rename user_path_umountat() to user_path_mountpoint_at()
take unlazy_walk() into umount_lookup_last()
Kill indirect include of file.h from eventfd.h, use fdget() in cgroup.c
prune_super(): sb->s_op is never NULL
exportfs: don't assume that ->iterate() won't feed us too long entries
afs: get rid of redundant ->d_name.len checks
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/dir.c | 24 | ||||
-rw-r--r-- | fs/autofs4/dev-ioctl.c | 23 | ||||
-rw-r--r-- | fs/dcache.c | 220 | ||||
-rw-r--r-- | fs/exportfs/expfs.c | 2 | ||||
-rw-r--r-- | fs/internal.h | 3 | ||||
-rw-r--r-- | fs/namei.c | 112 | ||||
-rw-r--r-- | fs/namespace.c | 2 | ||||
-rw-r--r-- | fs/super.c | 2 |
8 files changed, 221 insertions, 167 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 0b74d3176ab7..646337dc5201 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -751,10 +751,6 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
751 | _enter("{%x:%u},{%s},%ho", | 751 | _enter("{%x:%u},{%s},%ho", |
752 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 752 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
753 | 753 | ||
754 | ret = -ENAMETOOLONG; | ||
755 | if (dentry->d_name.len >= AFSNAMEMAX) | ||
756 | goto error; | ||
757 | |||
758 | key = afs_request_key(dvnode->volume->cell); | 754 | key = afs_request_key(dvnode->volume->cell); |
759 | if (IS_ERR(key)) { | 755 | if (IS_ERR(key)) { |
760 | ret = PTR_ERR(key); | 756 | ret = PTR_ERR(key); |
@@ -816,10 +812,6 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
816 | _enter("{%x:%u},{%s}", | 812 | _enter("{%x:%u},{%s}", |
817 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 813 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
818 | 814 | ||
819 | ret = -ENAMETOOLONG; | ||
820 | if (dentry->d_name.len >= AFSNAMEMAX) | ||
821 | goto error; | ||
822 | |||
823 | key = afs_request_key(dvnode->volume->cell); | 815 | key = afs_request_key(dvnode->volume->cell); |
824 | if (IS_ERR(key)) { | 816 | if (IS_ERR(key)) { |
825 | ret = PTR_ERR(key); | 817 | ret = PTR_ERR(key); |
@@ -936,10 +928,6 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
936 | _enter("{%x:%u},{%s},%ho,", | 928 | _enter("{%x:%u},{%s},%ho,", |
937 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 929 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
938 | 930 | ||
939 | ret = -ENAMETOOLONG; | ||
940 | if (dentry->d_name.len >= AFSNAMEMAX) | ||
941 | goto error; | ||
942 | |||
943 | key = afs_request_key(dvnode->volume->cell); | 931 | key = afs_request_key(dvnode->volume->cell); |
944 | if (IS_ERR(key)) { | 932 | if (IS_ERR(key)) { |
945 | ret = PTR_ERR(key); | 933 | ret = PTR_ERR(key); |
@@ -1005,10 +993,6 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
1005 | dvnode->fid.vid, dvnode->fid.vnode, | 993 | dvnode->fid.vid, dvnode->fid.vnode, |
1006 | dentry->d_name.name); | 994 | dentry->d_name.name); |
1007 | 995 | ||
1008 | ret = -ENAMETOOLONG; | ||
1009 | if (dentry->d_name.len >= AFSNAMEMAX) | ||
1010 | goto error; | ||
1011 | |||
1012 | key = afs_request_key(dvnode->volume->cell); | 996 | key = afs_request_key(dvnode->volume->cell); |
1013 | if (IS_ERR(key)) { | 997 | if (IS_ERR(key)) { |
1014 | ret = PTR_ERR(key); | 998 | ret = PTR_ERR(key); |
@@ -1053,10 +1037,6 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1053 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, | 1037 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, |
1054 | content); | 1038 | content); |
1055 | 1039 | ||
1056 | ret = -ENAMETOOLONG; | ||
1057 | if (dentry->d_name.len >= AFSNAMEMAX) | ||
1058 | goto error; | ||
1059 | |||
1060 | ret = -EINVAL; | 1040 | ret = -EINVAL; |
1061 | if (strlen(content) >= AFSPATHMAX) | 1041 | if (strlen(content) >= AFSPATHMAX) |
1062 | goto error; | 1042 | goto error; |
@@ -1127,10 +1107,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1127 | new_dvnode->fid.vid, new_dvnode->fid.vnode, | 1107 | new_dvnode->fid.vid, new_dvnode->fid.vnode, |
1128 | new_dentry->d_name.name); | 1108 | new_dentry->d_name.name); |
1129 | 1109 | ||
1130 | ret = -ENAMETOOLONG; | ||
1131 | if (new_dentry->d_name.len >= AFSNAMEMAX) | ||
1132 | goto error; | ||
1133 | |||
1134 | key = afs_request_key(orig_dvnode->volume->cell); | 1110 | key = afs_request_key(orig_dvnode->volume->cell); |
1135 | if (IS_ERR(key)) { | 1111 | if (IS_ERR(key)) { |
1136 | ret = PTR_ERR(key); | 1112 | ret = PTR_ERR(key); |
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 743c7c2c949d..0f00da329e71 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c | |||
@@ -183,13 +183,14 @@ static int autofs_dev_ioctl_protosubver(struct file *fp, | |||
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
185 | 185 | ||
186 | /* Find the topmost mount satisfying test() */ | ||
186 | static int find_autofs_mount(const char *pathname, | 187 | static int find_autofs_mount(const char *pathname, |
187 | struct path *res, | 188 | struct path *res, |
188 | int test(struct path *path, void *data), | 189 | int test(struct path *path, void *data), |
189 | void *data) | 190 | void *data) |
190 | { | 191 | { |
191 | struct path path; | 192 | struct path path; |
192 | int err = kern_path(pathname, 0, &path); | 193 | int err = kern_path_mountpoint(AT_FDCWD, pathname, &path, 0); |
193 | if (err) | 194 | if (err) |
194 | return err; | 195 | return err; |
195 | err = -ENOENT; | 196 | err = -ENOENT; |
@@ -197,10 +198,9 @@ static int find_autofs_mount(const char *pathname, | |||
197 | if (path.dentry->d_sb->s_magic == AUTOFS_SUPER_MAGIC) { | 198 | if (path.dentry->d_sb->s_magic == AUTOFS_SUPER_MAGIC) { |
198 | if (test(&path, data)) { | 199 | if (test(&path, data)) { |
199 | path_get(&path); | 200 | path_get(&path); |
200 | if (!err) /* already found some */ | ||
201 | path_put(res); | ||
202 | *res = path; | 201 | *res = path; |
203 | err = 0; | 202 | err = 0; |
203 | break; | ||
204 | } | 204 | } |
205 | } | 205 | } |
206 | if (!follow_up(&path)) | 206 | if (!follow_up(&path)) |
@@ -486,12 +486,11 @@ static int autofs_dev_ioctl_askumount(struct file *fp, | |||
486 | * mount if there is one or 0 if it isn't a mountpoint. | 486 | * mount if there is one or 0 if it isn't a mountpoint. |
487 | * | 487 | * |
488 | * If we aren't supplied with a file descriptor then we | 488 | * If we aren't supplied with a file descriptor then we |
489 | * lookup the nameidata of the path and check if it is the | 489 | * lookup the path and check if it is the root of a mount. |
490 | * root of a mount. If a type is given we are looking for | 490 | * If a type is given we are looking for a particular autofs |
491 | * a particular autofs mount and if we don't find a match | 491 | * mount and if we don't find a match we return fail. If the |
492 | * we return fail. If the located nameidata path is the | 492 | * located path is the root of a mount we return 1 along with |
493 | * root of a mount we return 1 along with the super magic | 493 | * the super magic of the mount or 0 otherwise. |
494 | * of the mount or 0 otherwise. | ||
495 | * | 494 | * |
496 | * In both cases the the device number (as returned by | 495 | * In both cases the the device number (as returned by |
497 | * new_encode_dev()) is also returned. | 496 | * new_encode_dev()) is also returned. |
@@ -519,9 +518,11 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, | |||
519 | 518 | ||
520 | if (!fp || param->ioctlfd == -1) { | 519 | if (!fp || param->ioctlfd == -1) { |
521 | if (autofs_type_any(type)) | 520 | if (autofs_type_any(type)) |
522 | err = kern_path(name, LOOKUP_FOLLOW, &path); | 521 | err = kern_path_mountpoint(AT_FDCWD, |
522 | name, &path, LOOKUP_FOLLOW); | ||
523 | else | 523 | else |
524 | err = find_autofs_mount(name, &path, test_by_type, &type); | 524 | err = find_autofs_mount(name, &path, |
525 | test_by_type, &type); | ||
525 | if (err) | 526 | if (err) |
526 | goto out; | 527 | goto out; |
527 | devid = new_encode_dev(path.dentry->d_sb->s_dev); | 528 | devid = new_encode_dev(path.dentry->d_sb->s_dev); |
diff --git a/fs/dcache.c b/fs/dcache.c index ca8e9cd60f87..4d9df3c940e6 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -88,6 +88,35 @@ EXPORT_SYMBOL(rename_lock); | |||
88 | 88 | ||
89 | static struct kmem_cache *dentry_cache __read_mostly; | 89 | static struct kmem_cache *dentry_cache __read_mostly; |
90 | 90 | ||
91 | /** | ||
92 | * read_seqbegin_or_lock - begin a sequence number check or locking block | ||
93 | * lock: sequence lock | ||
94 | * seq : sequence number to be checked | ||
95 | * | ||
96 | * First try it once optimistically without taking the lock. If that fails, | ||
97 | * take the lock. The sequence number is also used as a marker for deciding | ||
98 | * whether to be a reader (even) or writer (odd). | ||
99 | * N.B. seq must be initialized to an even number to begin with. | ||
100 | */ | ||
101 | static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) | ||
102 | { | ||
103 | if (!(*seq & 1)) /* Even */ | ||
104 | *seq = read_seqbegin(lock); | ||
105 | else /* Odd */ | ||
106 | write_seqlock(lock); | ||
107 | } | ||
108 | |||
109 | static inline int need_seqretry(seqlock_t *lock, int seq) | ||
110 | { | ||
111 | return !(seq & 1) && read_seqretry(lock, seq); | ||
112 | } | ||
113 | |||
114 | static inline void done_seqretry(seqlock_t *lock, int seq) | ||
115 | { | ||
116 | if (seq & 1) | ||
117 | write_sequnlock(lock); | ||
118 | } | ||
119 | |||
91 | /* | 120 | /* |
92 | * This is the single most critical data structure when it comes | 121 | * This is the single most critical data structure when it comes |
93 | * to the dcache: the hashtable for lookups. Somebody should try | 122 | * to the dcache: the hashtable for lookups. Somebody should try |
@@ -1012,7 +1041,7 @@ void shrink_dcache_for_umount(struct super_block *sb) | |||
1012 | * the parenthood after dropping the lock and check | 1041 | * the parenthood after dropping the lock and check |
1013 | * that the sequence number still matches. | 1042 | * that the sequence number still matches. |
1014 | */ | 1043 | */ |
1015 | static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq) | 1044 | static struct dentry *try_to_ascend(struct dentry *old, unsigned seq) |
1016 | { | 1045 | { |
1017 | struct dentry *new = old->d_parent; | 1046 | struct dentry *new = old->d_parent; |
1018 | 1047 | ||
@@ -1026,7 +1055,7 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq | |||
1026 | */ | 1055 | */ |
1027 | if (new != old->d_parent || | 1056 | if (new != old->d_parent || |
1028 | (old->d_flags & DCACHE_DENTRY_KILLED) || | 1057 | (old->d_flags & DCACHE_DENTRY_KILLED) || |
1029 | (!locked && read_seqretry(&rename_lock, seq))) { | 1058 | need_seqretry(&rename_lock, seq)) { |
1030 | spin_unlock(&new->d_lock); | 1059 | spin_unlock(&new->d_lock); |
1031 | new = NULL; | 1060 | new = NULL; |
1032 | } | 1061 | } |
@@ -1063,13 +1092,12 @@ static void d_walk(struct dentry *parent, void *data, | |||
1063 | { | 1092 | { |
1064 | struct dentry *this_parent; | 1093 | struct dentry *this_parent; |
1065 | struct list_head *next; | 1094 | struct list_head *next; |
1066 | unsigned seq; | 1095 | unsigned seq = 0; |
1067 | int locked = 0; | ||
1068 | enum d_walk_ret ret; | 1096 | enum d_walk_ret ret; |
1069 | bool retry = true; | 1097 | bool retry = true; |
1070 | 1098 | ||
1071 | seq = read_seqbegin(&rename_lock); | ||
1072 | again: | 1099 | again: |
1100 | read_seqbegin_or_lock(&rename_lock, &seq); | ||
1073 | this_parent = parent; | 1101 | this_parent = parent; |
1074 | spin_lock(&this_parent->d_lock); | 1102 | spin_lock(&this_parent->d_lock); |
1075 | 1103 | ||
@@ -1123,13 +1151,13 @@ resume: | |||
1123 | */ | 1151 | */ |
1124 | if (this_parent != parent) { | 1152 | if (this_parent != parent) { |
1125 | struct dentry *child = this_parent; | 1153 | struct dentry *child = this_parent; |
1126 | this_parent = try_to_ascend(this_parent, locked, seq); | 1154 | this_parent = try_to_ascend(this_parent, seq); |
1127 | if (!this_parent) | 1155 | if (!this_parent) |
1128 | goto rename_retry; | 1156 | goto rename_retry; |
1129 | next = child->d_u.d_child.next; | 1157 | next = child->d_u.d_child.next; |
1130 | goto resume; | 1158 | goto resume; |
1131 | } | 1159 | } |
1132 | if (!locked && read_seqretry(&rename_lock, seq)) { | 1160 | if (need_seqretry(&rename_lock, seq)) { |
1133 | spin_unlock(&this_parent->d_lock); | 1161 | spin_unlock(&this_parent->d_lock); |
1134 | goto rename_retry; | 1162 | goto rename_retry; |
1135 | } | 1163 | } |
@@ -1138,17 +1166,13 @@ resume: | |||
1138 | 1166 | ||
1139 | out_unlock: | 1167 | out_unlock: |
1140 | spin_unlock(&this_parent->d_lock); | 1168 | spin_unlock(&this_parent->d_lock); |
1141 | if (locked) | 1169 | done_seqretry(&rename_lock, seq); |
1142 | write_sequnlock(&rename_lock); | ||
1143 | return; | 1170 | return; |
1144 | 1171 | ||
1145 | rename_retry: | 1172 | rename_retry: |
1146 | if (!retry) | 1173 | if (!retry) |
1147 | return; | 1174 | return; |
1148 | if (locked) | 1175 | seq = 1; |
1149 | goto again; | ||
1150 | locked = 1; | ||
1151 | write_seqlock(&rename_lock); | ||
1152 | goto again; | 1176 | goto again; |
1153 | } | 1177 | } |
1154 | 1178 | ||
@@ -2647,9 +2671,39 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen) | |||
2647 | return 0; | 2671 | return 0; |
2648 | } | 2672 | } |
2649 | 2673 | ||
2674 | /** | ||
2675 | * prepend_name - prepend a pathname in front of current buffer pointer | ||
2676 | * buffer: buffer pointer | ||
2677 | * buflen: allocated length of the buffer | ||
2678 | * name: name string and length qstr structure | ||
2679 | * | ||
2680 | * With RCU path tracing, it may race with d_move(). Use ACCESS_ONCE() to | ||
2681 | * make sure that either the old or the new name pointer and length are | ||
2682 | * fetched. However, there may be mismatch between length and pointer. | ||
2683 | * The length cannot be trusted, we need to copy it byte-by-byte until | ||
2684 | * the length is reached or a null byte is found. It also prepends "/" at | ||
2685 | * the beginning of the name. The sequence number check at the caller will | ||
2686 | * retry it again when a d_move() does happen. So any garbage in the buffer | ||
2687 | * due to mismatched pointer and length will be discarded. | ||
2688 | */ | ||
2650 | static int prepend_name(char **buffer, int *buflen, struct qstr *name) | 2689 | static int prepend_name(char **buffer, int *buflen, struct qstr *name) |
2651 | { | 2690 | { |
2652 | return prepend(buffer, buflen, name->name, name->len); | 2691 | const char *dname = ACCESS_ONCE(name->name); |
2692 | u32 dlen = ACCESS_ONCE(name->len); | ||
2693 | char *p; | ||
2694 | |||
2695 | if (*buflen < dlen + 1) | ||
2696 | return -ENAMETOOLONG; | ||
2697 | *buflen -= dlen + 1; | ||
2698 | p = *buffer -= dlen + 1; | ||
2699 | *p++ = '/'; | ||
2700 | while (dlen--) { | ||
2701 | char c = *dname++; | ||
2702 | if (!c) | ||
2703 | break; | ||
2704 | *p++ = c; | ||
2705 | } | ||
2706 | return 0; | ||
2653 | } | 2707 | } |
2654 | 2708 | ||
2655 | /** | 2709 | /** |
@@ -2659,7 +2713,14 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) | |||
2659 | * @buffer: pointer to the end of the buffer | 2713 | * @buffer: pointer to the end of the buffer |
2660 | * @buflen: pointer to buffer length | 2714 | * @buflen: pointer to buffer length |
2661 | * | 2715 | * |
2662 | * Caller holds the rename_lock. | 2716 | * The function tries to write out the pathname without taking any lock other |
2717 | * than the RCU read lock to make sure that dentries won't go away. It only | ||
2718 | * checks the sequence number of the global rename_lock as any change in the | ||
2719 | * dentry's d_seq will be preceded by changes in the rename_lock sequence | ||
2720 | * number. If the sequence number had been change, it will restart the whole | ||
2721 | * pathname back-tracing sequence again. It performs a total of 3 trials of | ||
2722 | * lockless back-tracing sequences before falling back to take the | ||
2723 | * rename_lock. | ||
2663 | */ | 2724 | */ |
2664 | static int prepend_path(const struct path *path, | 2725 | static int prepend_path(const struct path *path, |
2665 | const struct path *root, | 2726 | const struct path *root, |
@@ -2668,54 +2729,66 @@ static int prepend_path(const struct path *path, | |||
2668 | struct dentry *dentry = path->dentry; | 2729 | struct dentry *dentry = path->dentry; |
2669 | struct vfsmount *vfsmnt = path->mnt; | 2730 | struct vfsmount *vfsmnt = path->mnt; |
2670 | struct mount *mnt = real_mount(vfsmnt); | 2731 | struct mount *mnt = real_mount(vfsmnt); |
2671 | bool slash = false; | ||
2672 | int error = 0; | 2732 | int error = 0; |
2733 | unsigned seq = 0; | ||
2734 | char *bptr; | ||
2735 | int blen; | ||
2673 | 2736 | ||
2737 | rcu_read_lock(); | ||
2738 | restart: | ||
2739 | bptr = *buffer; | ||
2740 | blen = *buflen; | ||
2741 | read_seqbegin_or_lock(&rename_lock, &seq); | ||
2674 | while (dentry != root->dentry || vfsmnt != root->mnt) { | 2742 | while (dentry != root->dentry || vfsmnt != root->mnt) { |
2675 | struct dentry * parent; | 2743 | struct dentry * parent; |
2676 | 2744 | ||
2677 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 2745 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
2678 | /* Global root? */ | 2746 | /* Global root? */ |
2679 | if (!mnt_has_parent(mnt)) | 2747 | if (mnt_has_parent(mnt)) { |
2680 | goto global_root; | 2748 | dentry = mnt->mnt_mountpoint; |
2681 | dentry = mnt->mnt_mountpoint; | 2749 | mnt = mnt->mnt_parent; |
2682 | mnt = mnt->mnt_parent; | 2750 | vfsmnt = &mnt->mnt; |
2683 | vfsmnt = &mnt->mnt; | 2751 | continue; |
2684 | continue; | 2752 | } |
2753 | /* | ||
2754 | * Filesystems needing to implement special "root names" | ||
2755 | * should do so with ->d_dname() | ||
2756 | */ | ||
2757 | if (IS_ROOT(dentry) && | ||
2758 | (dentry->d_name.len != 1 || | ||
2759 | dentry->d_name.name[0] != '/')) { | ||
2760 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
2761 | (int) dentry->d_name.len, | ||
2762 | dentry->d_name.name); | ||
2763 | } | ||
2764 | if (!error) | ||
2765 | error = is_mounted(vfsmnt) ? 1 : 2; | ||
2766 | break; | ||
2685 | } | 2767 | } |
2686 | parent = dentry->d_parent; | 2768 | parent = dentry->d_parent; |
2687 | prefetch(parent); | 2769 | prefetch(parent); |
2688 | spin_lock(&dentry->d_lock); | 2770 | error = prepend_name(&bptr, &blen, &dentry->d_name); |
2689 | error = prepend_name(buffer, buflen, &dentry->d_name); | ||
2690 | spin_unlock(&dentry->d_lock); | ||
2691 | if (!error) | ||
2692 | error = prepend(buffer, buflen, "/", 1); | ||
2693 | if (error) | 2771 | if (error) |
2694 | break; | 2772 | break; |
2695 | 2773 | ||
2696 | slash = true; | ||
2697 | dentry = parent; | 2774 | dentry = parent; |
2698 | } | 2775 | } |
2776 | if (!(seq & 1)) | ||
2777 | rcu_read_unlock(); | ||
2778 | if (need_seqretry(&rename_lock, seq)) { | ||
2779 | seq = 1; | ||
2780 | goto restart; | ||
2781 | } | ||
2782 | done_seqretry(&rename_lock, seq); | ||
2699 | 2783 | ||
2700 | if (!error && !slash) | 2784 | if (error >= 0 && bptr == *buffer) { |
2701 | error = prepend(buffer, buflen, "/", 1); | 2785 | if (--blen < 0) |
2702 | 2786 | error = -ENAMETOOLONG; | |
2703 | return error; | 2787 | else |
2704 | 2788 | *--bptr = '/'; | |
2705 | global_root: | 2789 | } |
2706 | /* | 2790 | *buffer = bptr; |
2707 | * Filesystems needing to implement special "root names" | 2791 | *buflen = blen; |
2708 | * should do so with ->d_dname() | ||
2709 | */ | ||
2710 | if (IS_ROOT(dentry) && | ||
2711 | (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { | ||
2712 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
2713 | (int) dentry->d_name.len, dentry->d_name.name); | ||
2714 | } | ||
2715 | if (!slash) | ||
2716 | error = prepend(buffer, buflen, "/", 1); | ||
2717 | if (!error) | ||
2718 | error = is_mounted(vfsmnt) ? 1 : 2; | ||
2719 | return error; | 2792 | return error; |
2720 | } | 2793 | } |
2721 | 2794 | ||
@@ -2744,9 +2817,7 @@ char *__d_path(const struct path *path, | |||
2744 | 2817 | ||
2745 | prepend(&res, &buflen, "\0", 1); | 2818 | prepend(&res, &buflen, "\0", 1); |
2746 | br_read_lock(&vfsmount_lock); | 2819 | br_read_lock(&vfsmount_lock); |
2747 | write_seqlock(&rename_lock); | ||
2748 | error = prepend_path(path, root, &res, &buflen); | 2820 | error = prepend_path(path, root, &res, &buflen); |
2749 | write_sequnlock(&rename_lock); | ||
2750 | br_read_unlock(&vfsmount_lock); | 2821 | br_read_unlock(&vfsmount_lock); |
2751 | 2822 | ||
2752 | if (error < 0) | 2823 | if (error < 0) |
@@ -2765,9 +2836,7 @@ char *d_absolute_path(const struct path *path, | |||
2765 | 2836 | ||
2766 | prepend(&res, &buflen, "\0", 1); | 2837 | prepend(&res, &buflen, "\0", 1); |
2767 | br_read_lock(&vfsmount_lock); | 2838 | br_read_lock(&vfsmount_lock); |
2768 | write_seqlock(&rename_lock); | ||
2769 | error = prepend_path(path, &root, &res, &buflen); | 2839 | error = prepend_path(path, &root, &res, &buflen); |
2770 | write_sequnlock(&rename_lock); | ||
2771 | br_read_unlock(&vfsmount_lock); | 2840 | br_read_unlock(&vfsmount_lock); |
2772 | 2841 | ||
2773 | if (error > 1) | 2842 | if (error > 1) |
@@ -2833,9 +2902,7 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
2833 | 2902 | ||
2834 | get_fs_root(current->fs, &root); | 2903 | get_fs_root(current->fs, &root); |
2835 | br_read_lock(&vfsmount_lock); | 2904 | br_read_lock(&vfsmount_lock); |
2836 | write_seqlock(&rename_lock); | ||
2837 | error = path_with_deleted(path, &root, &res, &buflen); | 2905 | error = path_with_deleted(path, &root, &res, &buflen); |
2838 | write_sequnlock(&rename_lock); | ||
2839 | br_read_unlock(&vfsmount_lock); | 2906 | br_read_unlock(&vfsmount_lock); |
2840 | if (error < 0) | 2907 | if (error < 0) |
2841 | res = ERR_PTR(error); | 2908 | res = ERR_PTR(error); |
@@ -2870,10 +2937,10 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) | |||
2870 | char *end = buffer + buflen; | 2937 | char *end = buffer + buflen; |
2871 | /* these dentries are never renamed, so d_lock is not needed */ | 2938 | /* these dentries are never renamed, so d_lock is not needed */ |
2872 | if (prepend(&end, &buflen, " (deleted)", 11) || | 2939 | if (prepend(&end, &buflen, " (deleted)", 11) || |
2873 | prepend_name(&end, &buflen, &dentry->d_name) || | 2940 | prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) || |
2874 | prepend(&end, &buflen, "/", 1)) | 2941 | prepend(&end, &buflen, "/", 1)) |
2875 | end = ERR_PTR(-ENAMETOOLONG); | 2942 | end = ERR_PTR(-ENAMETOOLONG); |
2876 | return end; | 2943 | return end; |
2877 | } | 2944 | } |
2878 | 2945 | ||
2879 | /* | 2946 | /* |
@@ -2881,30 +2948,42 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) | |||
2881 | */ | 2948 | */ |
2882 | static char *__dentry_path(struct dentry *dentry, char *buf, int buflen) | 2949 | static char *__dentry_path(struct dentry *dentry, char *buf, int buflen) |
2883 | { | 2950 | { |
2884 | char *end = buf + buflen; | 2951 | char *end, *retval; |
2885 | char *retval; | 2952 | int len, seq = 0; |
2953 | int error = 0; | ||
2886 | 2954 | ||
2887 | prepend(&end, &buflen, "\0", 1); | 2955 | rcu_read_lock(); |
2956 | restart: | ||
2957 | end = buf + buflen; | ||
2958 | len = buflen; | ||
2959 | prepend(&end, &len, "\0", 1); | ||
2888 | if (buflen < 1) | 2960 | if (buflen < 1) |
2889 | goto Elong; | 2961 | goto Elong; |
2890 | /* Get '/' right */ | 2962 | /* Get '/' right */ |
2891 | retval = end-1; | 2963 | retval = end-1; |
2892 | *retval = '/'; | 2964 | *retval = '/'; |
2893 | 2965 | read_seqbegin_or_lock(&rename_lock, &seq); | |
2894 | while (!IS_ROOT(dentry)) { | 2966 | while (!IS_ROOT(dentry)) { |
2895 | struct dentry *parent = dentry->d_parent; | 2967 | struct dentry *parent = dentry->d_parent; |
2896 | int error; | 2968 | int error; |
2897 | 2969 | ||
2898 | prefetch(parent); | 2970 | prefetch(parent); |
2899 | spin_lock(&dentry->d_lock); | 2971 | error = prepend_name(&end, &len, &dentry->d_name); |
2900 | error = prepend_name(&end, &buflen, &dentry->d_name); | 2972 | if (error) |
2901 | spin_unlock(&dentry->d_lock); | 2973 | break; |
2902 | if (error != 0 || prepend(&end, &buflen, "/", 1) != 0) | ||
2903 | goto Elong; | ||
2904 | 2974 | ||
2905 | retval = end; | 2975 | retval = end; |
2906 | dentry = parent; | 2976 | dentry = parent; |
2907 | } | 2977 | } |
2978 | if (!(seq & 1)) | ||
2979 | rcu_read_unlock(); | ||
2980 | if (need_seqretry(&rename_lock, seq)) { | ||
2981 | seq = 1; | ||
2982 | goto restart; | ||
2983 | } | ||
2984 | done_seqretry(&rename_lock, seq); | ||
2985 | if (error) | ||
2986 | goto Elong; | ||
2908 | return retval; | 2987 | return retval; |
2909 | Elong: | 2988 | Elong: |
2910 | return ERR_PTR(-ENAMETOOLONG); | 2989 | return ERR_PTR(-ENAMETOOLONG); |
@@ -2912,13 +2991,7 @@ Elong: | |||
2912 | 2991 | ||
2913 | char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen) | 2992 | char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen) |
2914 | { | 2993 | { |
2915 | char *retval; | 2994 | return __dentry_path(dentry, buf, buflen); |
2916 | |||
2917 | write_seqlock(&rename_lock); | ||
2918 | retval = __dentry_path(dentry, buf, buflen); | ||
2919 | write_sequnlock(&rename_lock); | ||
2920 | |||
2921 | return retval; | ||
2922 | } | 2995 | } |
2923 | EXPORT_SYMBOL(dentry_path_raw); | 2996 | EXPORT_SYMBOL(dentry_path_raw); |
2924 | 2997 | ||
@@ -2927,7 +3000,6 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
2927 | char *p = NULL; | 3000 | char *p = NULL; |
2928 | char *retval; | 3001 | char *retval; |
2929 | 3002 | ||
2930 | write_seqlock(&rename_lock); | ||
2931 | if (d_unlinked(dentry)) { | 3003 | if (d_unlinked(dentry)) { |
2932 | p = buf + buflen; | 3004 | p = buf + buflen; |
2933 | if (prepend(&p, &buflen, "//deleted", 10) != 0) | 3005 | if (prepend(&p, &buflen, "//deleted", 10) != 0) |
@@ -2935,7 +3007,6 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
2935 | buflen++; | 3007 | buflen++; |
2936 | } | 3008 | } |
2937 | retval = __dentry_path(dentry, buf, buflen); | 3009 | retval = __dentry_path(dentry, buf, buflen); |
2938 | write_sequnlock(&rename_lock); | ||
2939 | if (!IS_ERR(retval) && p) | 3010 | if (!IS_ERR(retval) && p) |
2940 | *p = '/'; /* restore '/' overriden with '\0' */ | 3011 | *p = '/'; /* restore '/' overriden with '\0' */ |
2941 | return retval; | 3012 | return retval; |
@@ -2974,7 +3045,6 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
2974 | 3045 | ||
2975 | error = -ENOENT; | 3046 | error = -ENOENT; |
2976 | br_read_lock(&vfsmount_lock); | 3047 | br_read_lock(&vfsmount_lock); |
2977 | write_seqlock(&rename_lock); | ||
2978 | if (!d_unlinked(pwd.dentry)) { | 3048 | if (!d_unlinked(pwd.dentry)) { |
2979 | unsigned long len; | 3049 | unsigned long len; |
2980 | char *cwd = page + PAGE_SIZE; | 3050 | char *cwd = page + PAGE_SIZE; |
@@ -2982,7 +3052,6 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
2982 | 3052 | ||
2983 | prepend(&cwd, &buflen, "\0", 1); | 3053 | prepend(&cwd, &buflen, "\0", 1); |
2984 | error = prepend_path(&pwd, &root, &cwd, &buflen); | 3054 | error = prepend_path(&pwd, &root, &cwd, &buflen); |
2985 | write_sequnlock(&rename_lock); | ||
2986 | br_read_unlock(&vfsmount_lock); | 3055 | br_read_unlock(&vfsmount_lock); |
2987 | 3056 | ||
2988 | if (error < 0) | 3057 | if (error < 0) |
@@ -3003,7 +3072,6 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
3003 | error = -EFAULT; | 3072 | error = -EFAULT; |
3004 | } | 3073 | } |
3005 | } else { | 3074 | } else { |
3006 | write_sequnlock(&rename_lock); | ||
3007 | br_read_unlock(&vfsmount_lock); | 3075 | br_read_unlock(&vfsmount_lock); |
3008 | } | 3076 | } |
3009 | 3077 | ||
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 293bc2e47a73..a235f0016889 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -231,7 +231,7 @@ static int filldir_one(void * __buf, const char * name, int len, | |||
231 | int result = 0; | 231 | int result = 0; |
232 | 232 | ||
233 | buf->sequence++; | 233 | buf->sequence++; |
234 | if (buf->ino == ino) { | 234 | if (buf->ino == ino && len <= NAME_MAX) { |
235 | memcpy(buf->name, name, len); | 235 | memcpy(buf->name, name, len); |
236 | buf->name[len] = '\0'; | 236 | buf->name[len] = '\0'; |
237 | buf->found = 1; | 237 | buf->found = 1; |
diff --git a/fs/internal.h b/fs/internal.h index d20893795526..2be46ea5dd0b 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -45,6 +45,9 @@ extern void __init chrdev_init(void); | |||
45 | * namei.c | 45 | * namei.c |
46 | */ | 46 | */ |
47 | extern int __inode_permission(struct inode *, int); | 47 | extern int __inode_permission(struct inode *, int); |
48 | extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *); | ||
49 | extern int vfs_path_lookup(struct dentry *, struct vfsmount *, | ||
50 | const char *, unsigned int, struct path *); | ||
48 | 51 | ||
49 | /* | 52 | /* |
50 | * namespace.c | 53 | * namespace.c |
diff --git a/fs/namei.c b/fs/namei.c index 5e6aaadc1dcd..409a441ba2ae 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2209,7 +2209,7 @@ user_path_parent(int dfd, const char __user *path, struct nameidata *nd, | |||
2209 | } | 2209 | } |
2210 | 2210 | ||
2211 | /** | 2211 | /** |
2212 | * umount_lookup_last - look up last component for umount | 2212 | * mountpoint_last - look up last component for umount |
2213 | * @nd: pathwalk nameidata - currently pointing at parent directory of "last" | 2213 | * @nd: pathwalk nameidata - currently pointing at parent directory of "last" |
2214 | * @path: pointer to container for result | 2214 | * @path: pointer to container for result |
2215 | * | 2215 | * |
@@ -2236,25 +2236,28 @@ user_path_parent(int dfd, const char __user *path, struct nameidata *nd, | |||
2236 | * to the link, and nd->path will *not* be put. | 2236 | * to the link, and nd->path will *not* be put. |
2237 | */ | 2237 | */ |
2238 | static int | 2238 | static int |
2239 | umount_lookup_last(struct nameidata *nd, struct path *path) | 2239 | mountpoint_last(struct nameidata *nd, struct path *path) |
2240 | { | 2240 | { |
2241 | int error = 0; | 2241 | int error = 0; |
2242 | struct dentry *dentry; | 2242 | struct dentry *dentry; |
2243 | struct dentry *dir = nd->path.dentry; | 2243 | struct dentry *dir = nd->path.dentry; |
2244 | 2244 | ||
2245 | if (unlikely(nd->flags & LOOKUP_RCU)) { | 2245 | /* If we're in rcuwalk, drop out of it to handle last component */ |
2246 | WARN_ON_ONCE(1); | 2246 | if (nd->flags & LOOKUP_RCU) { |
2247 | error = -ECHILD; | 2247 | if (unlazy_walk(nd, NULL)) { |
2248 | goto error_check; | 2248 | error = -ECHILD; |
2249 | goto out; | ||
2250 | } | ||
2249 | } | 2251 | } |
2250 | 2252 | ||
2251 | nd->flags &= ~LOOKUP_PARENT; | 2253 | nd->flags &= ~LOOKUP_PARENT; |
2252 | 2254 | ||
2253 | if (unlikely(nd->last_type != LAST_NORM)) { | 2255 | if (unlikely(nd->last_type != LAST_NORM)) { |
2254 | error = handle_dots(nd, nd->last_type); | 2256 | error = handle_dots(nd, nd->last_type); |
2255 | if (!error) | 2257 | if (error) |
2256 | dentry = dget(nd->path.dentry); | 2258 | goto out; |
2257 | goto error_check; | 2259 | dentry = dget(nd->path.dentry); |
2260 | goto done; | ||
2258 | } | 2261 | } |
2259 | 2262 | ||
2260 | mutex_lock(&dir->d_inode->i_mutex); | 2263 | mutex_lock(&dir->d_inode->i_mutex); |
@@ -2268,44 +2271,43 @@ umount_lookup_last(struct nameidata *nd, struct path *path) | |||
2268 | dentry = d_alloc(dir, &nd->last); | 2271 | dentry = d_alloc(dir, &nd->last); |
2269 | if (!dentry) { | 2272 | if (!dentry) { |
2270 | error = -ENOMEM; | 2273 | error = -ENOMEM; |
2271 | } else { | 2274 | goto out; |
2272 | dentry = lookup_real(dir->d_inode, dentry, nd->flags); | ||
2273 | if (IS_ERR(dentry)) | ||
2274 | error = PTR_ERR(dentry); | ||
2275 | } | 2275 | } |
2276 | dentry = lookup_real(dir->d_inode, dentry, nd->flags); | ||
2277 | error = PTR_ERR(dentry); | ||
2278 | if (IS_ERR(dentry)) | ||
2279 | goto out; | ||
2276 | } | 2280 | } |
2277 | mutex_unlock(&dir->d_inode->i_mutex); | 2281 | mutex_unlock(&dir->d_inode->i_mutex); |
2278 | 2282 | ||
2279 | error_check: | 2283 | done: |
2280 | if (!error) { | 2284 | if (!dentry->d_inode) { |
2281 | if (!dentry->d_inode) { | 2285 | error = -ENOENT; |
2282 | error = -ENOENT; | 2286 | dput(dentry); |
2283 | dput(dentry); | 2287 | goto out; |
2284 | } else { | ||
2285 | path->dentry = dentry; | ||
2286 | path->mnt = mntget(nd->path.mnt); | ||
2287 | if (should_follow_link(dentry->d_inode, | ||
2288 | nd->flags & LOOKUP_FOLLOW)) | ||
2289 | return 1; | ||
2290 | follow_mount(path); | ||
2291 | } | ||
2292 | } | 2288 | } |
2289 | path->dentry = dentry; | ||
2290 | path->mnt = mntget(nd->path.mnt); | ||
2291 | if (should_follow_link(dentry->d_inode, nd->flags & LOOKUP_FOLLOW)) | ||
2292 | return 1; | ||
2293 | follow_mount(path); | ||
2294 | error = 0; | ||
2295 | out: | ||
2293 | terminate_walk(nd); | 2296 | terminate_walk(nd); |
2294 | return error; | 2297 | return error; |
2295 | } | 2298 | } |
2296 | 2299 | ||
2297 | /** | 2300 | /** |
2298 | * path_umountat - look up a path to be umounted | 2301 | * path_mountpoint - look up a path to be umounted |
2299 | * @dfd: directory file descriptor to start walk from | 2302 | * @dfd: directory file descriptor to start walk from |
2300 | * @name: full pathname to walk | 2303 | * @name: full pathname to walk |
2301 | * @flags: lookup flags | 2304 | * @flags: lookup flags |
2302 | * @nd: pathwalk nameidata | ||
2303 | * | 2305 | * |
2304 | * Look up the given name, but don't attempt to revalidate the last component. | 2306 | * Look up the given name, but don't attempt to revalidate the last component. |
2305 | * Returns 0 and "path" will be valid on success; Retuns error otherwise. | 2307 | * Returns 0 and "path" will be valid on success; Retuns error otherwise. |
2306 | */ | 2308 | */ |
2307 | static int | 2309 | static int |
2308 | path_umountat(int dfd, const char *name, struct path *path, unsigned int flags) | 2310 | path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags) |
2309 | { | 2311 | { |
2310 | struct file *base = NULL; | 2312 | struct file *base = NULL; |
2311 | struct nameidata nd; | 2313 | struct nameidata nd; |
@@ -2320,16 +2322,7 @@ path_umountat(int dfd, const char *name, struct path *path, unsigned int flags) | |||
2320 | if (err) | 2322 | if (err) |
2321 | goto out; | 2323 | goto out; |
2322 | 2324 | ||
2323 | /* If we're in rcuwalk, drop out of it to handle last component */ | 2325 | err = mountpoint_last(&nd, path); |
2324 | if (nd.flags & LOOKUP_RCU) { | ||
2325 | err = unlazy_walk(&nd, NULL); | ||
2326 | if (err) { | ||
2327 | terminate_walk(&nd); | ||
2328 | goto out; | ||
2329 | } | ||
2330 | } | ||
2331 | |||
2332 | err = umount_lookup_last(&nd, path); | ||
2333 | while (err > 0) { | 2326 | while (err > 0) { |
2334 | void *cookie; | 2327 | void *cookie; |
2335 | struct path link = *path; | 2328 | struct path link = *path; |
@@ -2340,7 +2333,7 @@ path_umountat(int dfd, const char *name, struct path *path, unsigned int flags) | |||
2340 | err = follow_link(&link, &nd, &cookie); | 2333 | err = follow_link(&link, &nd, &cookie); |
2341 | if (err) | 2334 | if (err) |
2342 | break; | 2335 | break; |
2343 | err = umount_lookup_last(&nd, path); | 2336 | err = mountpoint_last(&nd, path); |
2344 | put_link(&nd, &link, cookie); | 2337 | put_link(&nd, &link, cookie); |
2345 | } | 2338 | } |
2346 | out: | 2339 | out: |
@@ -2353,8 +2346,22 @@ out: | |||
2353 | return err; | 2346 | return err; |
2354 | } | 2347 | } |
2355 | 2348 | ||
2349 | static int | ||
2350 | filename_mountpoint(int dfd, struct filename *s, struct path *path, | ||
2351 | unsigned int flags) | ||
2352 | { | ||
2353 | int error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU); | ||
2354 | if (unlikely(error == -ECHILD)) | ||
2355 | error = path_mountpoint(dfd, s->name, path, flags); | ||
2356 | if (unlikely(error == -ESTALE)) | ||
2357 | error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL); | ||
2358 | if (likely(!error)) | ||
2359 | audit_inode(s, path->dentry, 0); | ||
2360 | return error; | ||
2361 | } | ||
2362 | |||
2356 | /** | 2363 | /** |
2357 | * user_path_umountat - lookup a path from userland in order to umount it | 2364 | * user_path_mountpoint_at - lookup a path from userland in order to umount it |
2358 | * @dfd: directory file descriptor | 2365 | * @dfd: directory file descriptor |
2359 | * @name: pathname from userland | 2366 | * @name: pathname from userland |
2360 | * @flags: lookup flags | 2367 | * @flags: lookup flags |
@@ -2368,28 +2375,27 @@ out: | |||
2368 | * Returns 0 and populates "path" on success. | 2375 | * Returns 0 and populates "path" on success. |
2369 | */ | 2376 | */ |
2370 | int | 2377 | int |
2371 | user_path_umountat(int dfd, const char __user *name, unsigned int flags, | 2378 | user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags, |
2372 | struct path *path) | 2379 | struct path *path) |
2373 | { | 2380 | { |
2374 | struct filename *s = getname(name); | 2381 | struct filename *s = getname(name); |
2375 | int error; | 2382 | int error; |
2376 | |||
2377 | if (IS_ERR(s)) | 2383 | if (IS_ERR(s)) |
2378 | return PTR_ERR(s); | 2384 | return PTR_ERR(s); |
2379 | 2385 | error = filename_mountpoint(dfd, s, path, flags); | |
2380 | error = path_umountat(dfd, s->name, path, flags | LOOKUP_RCU); | ||
2381 | if (unlikely(error == -ECHILD)) | ||
2382 | error = path_umountat(dfd, s->name, path, flags); | ||
2383 | if (unlikely(error == -ESTALE)) | ||
2384 | error = path_umountat(dfd, s->name, path, flags | LOOKUP_REVAL); | ||
2385 | |||
2386 | if (likely(!error)) | ||
2387 | audit_inode(s, path->dentry, 0); | ||
2388 | |||
2389 | putname(s); | 2386 | putname(s); |
2390 | return error; | 2387 | return error; |
2391 | } | 2388 | } |
2392 | 2389 | ||
2390 | int | ||
2391 | kern_path_mountpoint(int dfd, const char *name, struct path *path, | ||
2392 | unsigned int flags) | ||
2393 | { | ||
2394 | struct filename s = {.name = name}; | ||
2395 | return filename_mountpoint(dfd, &s, path, flags); | ||
2396 | } | ||
2397 | EXPORT_SYMBOL(kern_path_mountpoint); | ||
2398 | |||
2393 | /* | 2399 | /* |
2394 | * It's inline, so penalty for filesystems that don't use sticky bit is | 2400 | * It's inline, so penalty for filesystems that don't use sticky bit is |
2395 | * minimal. | 2401 | * minimal. |
diff --git a/fs/namespace.c b/fs/namespace.c index fc2b5226278d..25845d1b300b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1321,7 +1321,7 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) | |||
1321 | if (!(flags & UMOUNT_NOFOLLOW)) | 1321 | if (!(flags & UMOUNT_NOFOLLOW)) |
1322 | lookup_flags |= LOOKUP_FOLLOW; | 1322 | lookup_flags |= LOOKUP_FOLLOW; |
1323 | 1323 | ||
1324 | retval = user_path_umountat(AT_FDCWD, name, lookup_flags, &path); | 1324 | retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path); |
1325 | if (retval) | 1325 | if (retval) |
1326 | goto out; | 1326 | goto out; |
1327 | mnt = real_mount(path.mnt); | 1327 | mnt = real_mount(path.mnt); |
diff --git a/fs/super.c b/fs/super.c index 5536a95186e2..f6961ea84c56 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -71,7 +71,7 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) | |||
71 | if (!grab_super_passive(sb)) | 71 | if (!grab_super_passive(sb)) |
72 | return -1; | 72 | return -1; |
73 | 73 | ||
74 | if (sb->s_op && sb->s_op->nr_cached_objects) | 74 | if (sb->s_op->nr_cached_objects) |
75 | fs_objects = sb->s_op->nr_cached_objects(sb); | 75 | fs_objects = sb->s_op->nr_cached_objects(sb); |
76 | 76 | ||
77 | total_objects = sb->s_nr_dentry_unused + | 77 | total_objects = sb->s_nr_dentry_unused + |