diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 13:34:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 13:34:35 -0400 |
commit | 1193755ac6328ad240ba987e6ec41d5e8baf0680 (patch) | |
tree | 40bf847d7e3ebaa57b107151d14e6cd1d280cc6d /fs/namei.c | |
parent | 4edebed86690eb8db9af3ab85baf4a34e73266cc (diff) | |
parent | 0ef97dcfce4179a2eba046b855ee2f91d6f1b414 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs changes from Al Viro.
"A lot of misc stuff. The obvious groups:
* Miklos' atomic_open series; kills the damn abuse of
->d_revalidate() by NFS, which was the major stumbling block for
all work in that area.
* ripping security_file_mmap() and dealing with deadlocks in the
area; sanitizing the neighborhood of vm_mmap()/vm_munmap() in
general.
* ->encode_fh() switched to saner API; insane fake dentry in
mm/cleancache.c gone.
* assorted annotations in fs (endianness, __user)
* parts of Artem's ->s_dirty work (jff2 and reiserfs parts)
* ->update_time() work from Josef.
* other bits and pieces all over the place.
Normally it would've been in two or three pull requests, but
signal.git stuff had eaten a lot of time during this cycle ;-/"
Fix up trivial conflicts in Documentation/filesystems/vfs.txt (the
'truncate_range' inode method was removed by the VM changes, the VFS
update adds an 'update_time()' method), and in fs/btrfs/ulist.[ch] (due
to sparse fix added twice, with other changes nearby).
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (95 commits)
nfs: don't open in ->d_revalidate
vfs: retry last component if opening stale dentry
vfs: nameidata_to_filp(): don't throw away file on error
vfs: nameidata_to_filp(): inline __dentry_open()
vfs: do_dentry_open(): don't put filp
vfs: split __dentry_open()
vfs: do_last() common post lookup
vfs: do_last(): add audit_inode before open
vfs: do_last(): only return EISDIR for O_CREAT
vfs: do_last(): check LOOKUP_DIRECTORY
vfs: do_last(): make ENOENT exit RCU safe
vfs: make follow_link check RCU safe
vfs: do_last(): use inode variable
vfs: do_last(): inline walk_component()
vfs: do_last(): make exit RCU safe
vfs: split do_lookup()
Btrfs: move over to use ->update_time
fs: introduce inode operation ->update_time
reiserfs: get rid of resierfs_sync_super
reiserfs: mark the superblock as dirty a bit later
...
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 177 |
1 files changed, 127 insertions, 50 deletions
diff --git a/fs/namei.c b/fs/namei.c index c651f02c9fec..7d694194024a 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -449,7 +449,7 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry) | |||
449 | mntget(nd->path.mnt); | 449 | mntget(nd->path.mnt); |
450 | 450 | ||
451 | rcu_read_unlock(); | 451 | rcu_read_unlock(); |
452 | br_read_unlock(vfsmount_lock); | 452 | br_read_unlock(&vfsmount_lock); |
453 | nd->flags &= ~LOOKUP_RCU; | 453 | nd->flags &= ~LOOKUP_RCU; |
454 | return 0; | 454 | return 0; |
455 | 455 | ||
@@ -507,14 +507,14 @@ static int complete_walk(struct nameidata *nd) | |||
507 | if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) { | 507 | if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) { |
508 | spin_unlock(&dentry->d_lock); | 508 | spin_unlock(&dentry->d_lock); |
509 | rcu_read_unlock(); | 509 | rcu_read_unlock(); |
510 | br_read_unlock(vfsmount_lock); | 510 | br_read_unlock(&vfsmount_lock); |
511 | return -ECHILD; | 511 | return -ECHILD; |
512 | } | 512 | } |
513 | BUG_ON(nd->inode != dentry->d_inode); | 513 | BUG_ON(nd->inode != dentry->d_inode); |
514 | spin_unlock(&dentry->d_lock); | 514 | spin_unlock(&dentry->d_lock); |
515 | mntget(nd->path.mnt); | 515 | mntget(nd->path.mnt); |
516 | rcu_read_unlock(); | 516 | rcu_read_unlock(); |
517 | br_read_unlock(vfsmount_lock); | 517 | br_read_unlock(&vfsmount_lock); |
518 | } | 518 | } |
519 | 519 | ||
520 | if (likely(!(nd->flags & LOOKUP_JUMPED))) | 520 | if (likely(!(nd->flags & LOOKUP_JUMPED))) |
@@ -681,15 +681,15 @@ int follow_up(struct path *path) | |||
681 | struct mount *parent; | 681 | struct mount *parent; |
682 | struct dentry *mountpoint; | 682 | struct dentry *mountpoint; |
683 | 683 | ||
684 | br_read_lock(vfsmount_lock); | 684 | br_read_lock(&vfsmount_lock); |
685 | parent = mnt->mnt_parent; | 685 | parent = mnt->mnt_parent; |
686 | if (&parent->mnt == path->mnt) { | 686 | if (&parent->mnt == path->mnt) { |
687 | br_read_unlock(vfsmount_lock); | 687 | br_read_unlock(&vfsmount_lock); |
688 | return 0; | 688 | return 0; |
689 | } | 689 | } |
690 | mntget(&parent->mnt); | 690 | mntget(&parent->mnt); |
691 | mountpoint = dget(mnt->mnt_mountpoint); | 691 | mountpoint = dget(mnt->mnt_mountpoint); |
692 | br_read_unlock(vfsmount_lock); | 692 | br_read_unlock(&vfsmount_lock); |
693 | dput(path->dentry); | 693 | dput(path->dentry); |
694 | path->dentry = mountpoint; | 694 | path->dentry = mountpoint; |
695 | mntput(path->mnt); | 695 | mntput(path->mnt); |
@@ -947,7 +947,7 @@ failed: | |||
947 | if (!(nd->flags & LOOKUP_ROOT)) | 947 | if (!(nd->flags & LOOKUP_ROOT)) |
948 | nd->root.mnt = NULL; | 948 | nd->root.mnt = NULL; |
949 | rcu_read_unlock(); | 949 | rcu_read_unlock(); |
950 | br_read_unlock(vfsmount_lock); | 950 | br_read_unlock(&vfsmount_lock); |
951 | return -ECHILD; | 951 | return -ECHILD; |
952 | } | 952 | } |
953 | 953 | ||
@@ -1125,8 +1125,8 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
1125 | * small and for now I'd prefer to have fast path as straight as possible. | 1125 | * small and for now I'd prefer to have fast path as straight as possible. |
1126 | * It _is_ time-critical. | 1126 | * It _is_ time-critical. |
1127 | */ | 1127 | */ |
1128 | static int do_lookup(struct nameidata *nd, struct qstr *name, | 1128 | static int lookup_fast(struct nameidata *nd, struct qstr *name, |
1129 | struct path *path, struct inode **inode) | 1129 | struct path *path, struct inode **inode) |
1130 | { | 1130 | { |
1131 | struct vfsmount *mnt = nd->path.mnt; | 1131 | struct vfsmount *mnt = nd->path.mnt; |
1132 | struct dentry *dentry, *parent = nd->path.dentry; | 1132 | struct dentry *dentry, *parent = nd->path.dentry; |
@@ -1208,7 +1208,7 @@ unlazy: | |||
1208 | goto need_lookup; | 1208 | goto need_lookup; |
1209 | } | 1209 | } |
1210 | } | 1210 | } |
1211 | done: | 1211 | |
1212 | path->mnt = mnt; | 1212 | path->mnt = mnt; |
1213 | path->dentry = dentry; | 1213 | path->dentry = dentry; |
1214 | err = follow_managed(path, nd->flags); | 1214 | err = follow_managed(path, nd->flags); |
@@ -1222,6 +1222,17 @@ done: | |||
1222 | return 0; | 1222 | return 0; |
1223 | 1223 | ||
1224 | need_lookup: | 1224 | need_lookup: |
1225 | return 1; | ||
1226 | } | ||
1227 | |||
1228 | /* Fast lookup failed, do it the slow way */ | ||
1229 | static int lookup_slow(struct nameidata *nd, struct qstr *name, | ||
1230 | struct path *path) | ||
1231 | { | ||
1232 | struct dentry *dentry, *parent; | ||
1233 | int err; | ||
1234 | |||
1235 | parent = nd->path.dentry; | ||
1225 | BUG_ON(nd->inode != parent->d_inode); | 1236 | BUG_ON(nd->inode != parent->d_inode); |
1226 | 1237 | ||
1227 | mutex_lock(&parent->d_inode->i_mutex); | 1238 | mutex_lock(&parent->d_inode->i_mutex); |
@@ -1229,7 +1240,16 @@ need_lookup: | |||
1229 | mutex_unlock(&parent->d_inode->i_mutex); | 1240 | mutex_unlock(&parent->d_inode->i_mutex); |
1230 | if (IS_ERR(dentry)) | 1241 | if (IS_ERR(dentry)) |
1231 | return PTR_ERR(dentry); | 1242 | return PTR_ERR(dentry); |
1232 | goto done; | 1243 | path->mnt = nd->path.mnt; |
1244 | path->dentry = dentry; | ||
1245 | err = follow_managed(path, nd->flags); | ||
1246 | if (unlikely(err < 0)) { | ||
1247 | path_put_conditional(path, nd); | ||
1248 | return err; | ||
1249 | } | ||
1250 | if (err) | ||
1251 | nd->flags |= LOOKUP_JUMPED; | ||
1252 | return 0; | ||
1233 | } | 1253 | } |
1234 | 1254 | ||
1235 | static inline int may_lookup(struct nameidata *nd) | 1255 | static inline int may_lookup(struct nameidata *nd) |
@@ -1265,7 +1285,7 @@ static void terminate_walk(struct nameidata *nd) | |||
1265 | if (!(nd->flags & LOOKUP_ROOT)) | 1285 | if (!(nd->flags & LOOKUP_ROOT)) |
1266 | nd->root.mnt = NULL; | 1286 | nd->root.mnt = NULL; |
1267 | rcu_read_unlock(); | 1287 | rcu_read_unlock(); |
1268 | br_read_unlock(vfsmount_lock); | 1288 | br_read_unlock(&vfsmount_lock); |
1269 | } | 1289 | } |
1270 | } | 1290 | } |
1271 | 1291 | ||
@@ -1301,21 +1321,26 @@ static inline int walk_component(struct nameidata *nd, struct path *path, | |||
1301 | */ | 1321 | */ |
1302 | if (unlikely(type != LAST_NORM)) | 1322 | if (unlikely(type != LAST_NORM)) |
1303 | return handle_dots(nd, type); | 1323 | return handle_dots(nd, type); |
1304 | err = do_lookup(nd, name, path, &inode); | 1324 | err = lookup_fast(nd, name, path, &inode); |
1305 | if (unlikely(err)) { | 1325 | if (unlikely(err)) { |
1306 | terminate_walk(nd); | 1326 | if (err < 0) |
1307 | return err; | 1327 | goto out_err; |
1308 | } | 1328 | |
1309 | if (!inode) { | 1329 | err = lookup_slow(nd, name, path); |
1310 | path_to_nameidata(path, nd); | 1330 | if (err < 0) |
1311 | terminate_walk(nd); | 1331 | goto out_err; |
1312 | return -ENOENT; | 1332 | |
1333 | inode = path->dentry->d_inode; | ||
1313 | } | 1334 | } |
1335 | err = -ENOENT; | ||
1336 | if (!inode) | ||
1337 | goto out_path_put; | ||
1338 | |||
1314 | if (should_follow_link(inode, follow)) { | 1339 | if (should_follow_link(inode, follow)) { |
1315 | if (nd->flags & LOOKUP_RCU) { | 1340 | if (nd->flags & LOOKUP_RCU) { |
1316 | if (unlikely(unlazy_walk(nd, path->dentry))) { | 1341 | if (unlikely(unlazy_walk(nd, path->dentry))) { |
1317 | terminate_walk(nd); | 1342 | err = -ECHILD; |
1318 | return -ECHILD; | 1343 | goto out_err; |
1319 | } | 1344 | } |
1320 | } | 1345 | } |
1321 | BUG_ON(inode != path->dentry->d_inode); | 1346 | BUG_ON(inode != path->dentry->d_inode); |
@@ -1324,6 +1349,12 @@ static inline int walk_component(struct nameidata *nd, struct path *path, | |||
1324 | path_to_nameidata(path, nd); | 1349 | path_to_nameidata(path, nd); |
1325 | nd->inode = inode; | 1350 | nd->inode = inode; |
1326 | return 0; | 1351 | return 0; |
1352 | |||
1353 | out_path_put: | ||
1354 | path_to_nameidata(path, nd); | ||
1355 | out_err: | ||
1356 | terminate_walk(nd); | ||
1357 | return err; | ||
1327 | } | 1358 | } |
1328 | 1359 | ||
1329 | /* | 1360 | /* |
@@ -1620,7 +1651,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1620 | nd->path = nd->root; | 1651 | nd->path = nd->root; |
1621 | nd->inode = inode; | 1652 | nd->inode = inode; |
1622 | if (flags & LOOKUP_RCU) { | 1653 | if (flags & LOOKUP_RCU) { |
1623 | br_read_lock(vfsmount_lock); | 1654 | br_read_lock(&vfsmount_lock); |
1624 | rcu_read_lock(); | 1655 | rcu_read_lock(); |
1625 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | 1656 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); |
1626 | } else { | 1657 | } else { |
@@ -1633,7 +1664,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1633 | 1664 | ||
1634 | if (*name=='/') { | 1665 | if (*name=='/') { |
1635 | if (flags & LOOKUP_RCU) { | 1666 | if (flags & LOOKUP_RCU) { |
1636 | br_read_lock(vfsmount_lock); | 1667 | br_read_lock(&vfsmount_lock); |
1637 | rcu_read_lock(); | 1668 | rcu_read_lock(); |
1638 | set_root_rcu(nd); | 1669 | set_root_rcu(nd); |
1639 | } else { | 1670 | } else { |
@@ -1646,7 +1677,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1646 | struct fs_struct *fs = current->fs; | 1677 | struct fs_struct *fs = current->fs; |
1647 | unsigned seq; | 1678 | unsigned seq; |
1648 | 1679 | ||
1649 | br_read_lock(vfsmount_lock); | 1680 | br_read_lock(&vfsmount_lock); |
1650 | rcu_read_lock(); | 1681 | rcu_read_lock(); |
1651 | 1682 | ||
1652 | do { | 1683 | do { |
@@ -1682,7 +1713,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1682 | if (fput_needed) | 1713 | if (fput_needed) |
1683 | *fp = file; | 1714 | *fp = file; |
1684 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | 1715 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); |
1685 | br_read_lock(vfsmount_lock); | 1716 | br_read_lock(&vfsmount_lock); |
1686 | rcu_read_lock(); | 1717 | rcu_read_lock(); |
1687 | } else { | 1718 | } else { |
1688 | path_get(&file->f_path); | 1719 | path_get(&file->f_path); |
@@ -2169,6 +2200,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2169 | int want_write = 0; | 2200 | int want_write = 0; |
2170 | int acc_mode = op->acc_mode; | 2201 | int acc_mode = op->acc_mode; |
2171 | struct file *filp; | 2202 | struct file *filp; |
2203 | struct inode *inode; | ||
2204 | int symlink_ok = 0; | ||
2205 | struct path save_parent = { .dentry = NULL, .mnt = NULL }; | ||
2206 | bool retried = false; | ||
2172 | int error; | 2207 | int error; |
2173 | 2208 | ||
2174 | nd->flags &= ~LOOKUP_PARENT; | 2209 | nd->flags &= ~LOOKUP_PARENT; |
@@ -2200,30 +2235,23 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2200 | } | 2235 | } |
2201 | 2236 | ||
2202 | if (!(open_flag & O_CREAT)) { | 2237 | if (!(open_flag & O_CREAT)) { |
2203 | int symlink_ok = 0; | ||
2204 | if (nd->last.name[nd->last.len]) | 2238 | if (nd->last.name[nd->last.len]) |
2205 | nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | 2239 | nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; |
2206 | if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW)) | 2240 | if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW)) |
2207 | symlink_ok = 1; | 2241 | symlink_ok = 1; |
2208 | /* we _can_ be in RCU mode here */ | 2242 | /* we _can_ be in RCU mode here */ |
2209 | error = walk_component(nd, path, &nd->last, LAST_NORM, | 2243 | error = lookup_fast(nd, &nd->last, path, &inode); |
2210 | !symlink_ok); | 2244 | if (unlikely(error)) { |
2211 | if (error < 0) | 2245 | if (error < 0) |
2212 | return ERR_PTR(error); | 2246 | goto exit; |
2213 | if (error) /* symlink */ | ||
2214 | return NULL; | ||
2215 | /* sayonara */ | ||
2216 | error = complete_walk(nd); | ||
2217 | if (error) | ||
2218 | return ERR_PTR(error); | ||
2219 | 2247 | ||
2220 | error = -ENOTDIR; | 2248 | error = lookup_slow(nd, &nd->last, path); |
2221 | if (nd->flags & LOOKUP_DIRECTORY) { | 2249 | if (error < 0) |
2222 | if (!nd->inode->i_op->lookup) | ||
2223 | goto exit; | 2250 | goto exit; |
2251 | |||
2252 | inode = path->dentry->d_inode; | ||
2224 | } | 2253 | } |
2225 | audit_inode(pathname, nd->path.dentry); | 2254 | goto finish_lookup; |
2226 | goto ok; | ||
2227 | } | 2255 | } |
2228 | 2256 | ||
2229 | /* create side of things */ | 2257 | /* create side of things */ |
@@ -2241,6 +2269,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2241 | if (nd->last.name[nd->last.len]) | 2269 | if (nd->last.name[nd->last.len]) |
2242 | goto exit; | 2270 | goto exit; |
2243 | 2271 | ||
2272 | retry_lookup: | ||
2244 | mutex_lock(&dir->d_inode->i_mutex); | 2273 | mutex_lock(&dir->d_inode->i_mutex); |
2245 | 2274 | ||
2246 | dentry = lookup_hash(nd); | 2275 | dentry = lookup_hash(nd); |
@@ -2302,22 +2331,49 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2302 | if (error) | 2331 | if (error) |
2303 | nd->flags |= LOOKUP_JUMPED; | 2332 | nd->flags |= LOOKUP_JUMPED; |
2304 | 2333 | ||
2334 | BUG_ON(nd->flags & LOOKUP_RCU); | ||
2335 | inode = path->dentry->d_inode; | ||
2336 | finish_lookup: | ||
2337 | /* we _can_ be in RCU mode here */ | ||
2305 | error = -ENOENT; | 2338 | error = -ENOENT; |
2306 | if (!path->dentry->d_inode) | 2339 | if (!inode) { |
2307 | goto exit_dput; | 2340 | path_to_nameidata(path, nd); |
2341 | goto exit; | ||
2342 | } | ||
2308 | 2343 | ||
2309 | if (path->dentry->d_inode->i_op->follow_link) | 2344 | if (should_follow_link(inode, !symlink_ok)) { |
2345 | if (nd->flags & LOOKUP_RCU) { | ||
2346 | if (unlikely(unlazy_walk(nd, path->dentry))) { | ||
2347 | error = -ECHILD; | ||
2348 | goto exit; | ||
2349 | } | ||
2350 | } | ||
2351 | BUG_ON(inode != path->dentry->d_inode); | ||
2310 | return NULL; | 2352 | return NULL; |
2353 | } | ||
2311 | 2354 | ||
2312 | path_to_nameidata(path, nd); | 2355 | if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) { |
2313 | nd->inode = path->dentry->d_inode; | 2356 | path_to_nameidata(path, nd); |
2357 | } else { | ||
2358 | save_parent.dentry = nd->path.dentry; | ||
2359 | save_parent.mnt = mntget(path->mnt); | ||
2360 | nd->path.dentry = path->dentry; | ||
2361 | |||
2362 | } | ||
2363 | nd->inode = inode; | ||
2314 | /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ | 2364 | /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ |
2315 | error = complete_walk(nd); | 2365 | error = complete_walk(nd); |
2316 | if (error) | 2366 | if (error) { |
2367 | path_put(&save_parent); | ||
2317 | return ERR_PTR(error); | 2368 | return ERR_PTR(error); |
2369 | } | ||
2318 | error = -EISDIR; | 2370 | error = -EISDIR; |
2319 | if (S_ISDIR(nd->inode->i_mode)) | 2371 | if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode)) |
2372 | goto exit; | ||
2373 | error = -ENOTDIR; | ||
2374 | if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup) | ||
2320 | goto exit; | 2375 | goto exit; |
2376 | audit_inode(pathname, nd->path.dentry); | ||
2321 | ok: | 2377 | ok: |
2322 | if (!S_ISREG(nd->inode->i_mode)) | 2378 | if (!S_ISREG(nd->inode->i_mode)) |
2323 | will_truncate = 0; | 2379 | will_truncate = 0; |
@@ -2333,6 +2389,20 @@ common: | |||
2333 | if (error) | 2389 | if (error) |
2334 | goto exit; | 2390 | goto exit; |
2335 | filp = nameidata_to_filp(nd); | 2391 | filp = nameidata_to_filp(nd); |
2392 | if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) { | ||
2393 | BUG_ON(save_parent.dentry != dir); | ||
2394 | path_put(&nd->path); | ||
2395 | nd->path = save_parent; | ||
2396 | nd->inode = dir->d_inode; | ||
2397 | save_parent.mnt = NULL; | ||
2398 | save_parent.dentry = NULL; | ||
2399 | if (want_write) { | ||
2400 | mnt_drop_write(nd->path.mnt); | ||
2401 | want_write = 0; | ||
2402 | } | ||
2403 | retried = true; | ||
2404 | goto retry_lookup; | ||
2405 | } | ||
2336 | if (!IS_ERR(filp)) { | 2406 | if (!IS_ERR(filp)) { |
2337 | error = ima_file_check(filp, op->acc_mode); | 2407 | error = ima_file_check(filp, op->acc_mode); |
2338 | if (error) { | 2408 | if (error) { |
@@ -2352,7 +2422,8 @@ common: | |||
2352 | out: | 2422 | out: |
2353 | if (want_write) | 2423 | if (want_write) |
2354 | mnt_drop_write(nd->path.mnt); | 2424 | mnt_drop_write(nd->path.mnt); |
2355 | path_put(&nd->path); | 2425 | path_put(&save_parent); |
2426 | terminate_walk(nd); | ||
2356 | return filp; | 2427 | return filp; |
2357 | 2428 | ||
2358 | exit_mutex_unlock: | 2429 | exit_mutex_unlock: |
@@ -2415,6 +2486,12 @@ out: | |||
2415 | if (base) | 2486 | if (base) |
2416 | fput(base); | 2487 | fput(base); |
2417 | release_open_intent(nd); | 2488 | release_open_intent(nd); |
2489 | if (filp == ERR_PTR(-EOPENSTALE)) { | ||
2490 | if (flags & LOOKUP_RCU) | ||
2491 | filp = ERR_PTR(-ECHILD); | ||
2492 | else | ||
2493 | filp = ERR_PTR(-ESTALE); | ||
2494 | } | ||
2418 | return filp; | 2495 | return filp; |
2419 | 2496 | ||
2420 | out_filp: | 2497 | out_filp: |