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/namei.c | |
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/namei.c')
-rw-r--r-- | fs/namei.c | 112 |
1 files changed, 59 insertions, 53 deletions
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. |