diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 151 |
1 files changed, 71 insertions, 80 deletions
diff --git a/fs/namei.c b/fs/namei.c index 7d77f24d32a9..0087cf9c2c6b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -455,14 +455,6 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry | |||
455 | struct fs_struct *fs = current->fs; | 455 | struct fs_struct *fs = current->fs; |
456 | struct dentry *parent = nd->path.dentry; | 456 | struct dentry *parent = nd->path.dentry; |
457 | 457 | ||
458 | /* | ||
459 | * It can be possible to revalidate the dentry that we started | ||
460 | * the path walk with. force_reval_path may also revalidate the | ||
461 | * dentry already committed to the nameidata. | ||
462 | */ | ||
463 | if (unlikely(parent == dentry)) | ||
464 | return nameidata_drop_rcu(nd); | ||
465 | |||
466 | BUG_ON(!(nd->flags & LOOKUP_RCU)); | 458 | BUG_ON(!(nd->flags & LOOKUP_RCU)); |
467 | if (nd->root.mnt) { | 459 | if (nd->root.mnt) { |
468 | spin_lock(&fs->lock); | 460 | spin_lock(&fs->lock); |
@@ -561,39 +553,25 @@ static inline int nameidata_drop_rcu_last_maybe(struct nameidata *nd) | |||
561 | */ | 553 | */ |
562 | void release_open_intent(struct nameidata *nd) | 554 | void release_open_intent(struct nameidata *nd) |
563 | { | 555 | { |
564 | if (nd->intent.open.file->f_path.dentry == NULL) | 556 | struct file *file = nd->intent.open.file; |
565 | put_filp(nd->intent.open.file); | ||
566 | else | ||
567 | fput(nd->intent.open.file); | ||
568 | } | ||
569 | |||
570 | /* | ||
571 | * Call d_revalidate and handle filesystems that request rcu-walk | ||
572 | * to be dropped. This may be called and return in rcu-walk mode, | ||
573 | * regardless of success or error. If -ECHILD is returned, the caller | ||
574 | * must return -ECHILD back up the path walk stack so path walk may | ||
575 | * be restarted in ref-walk mode. | ||
576 | */ | ||
577 | static int d_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
578 | { | ||
579 | int status; | ||
580 | 557 | ||
581 | status = dentry->d_op->d_revalidate(dentry, nd); | 558 | if (file && !IS_ERR(file)) { |
582 | if (status == -ECHILD) { | 559 | if (file->f_path.dentry == NULL) |
583 | if (nameidata_dentry_drop_rcu(nd, dentry)) | 560 | put_filp(file); |
584 | return status; | 561 | else |
585 | status = dentry->d_op->d_revalidate(dentry, nd); | 562 | fput(file); |
586 | } | 563 | } |
564 | } | ||
587 | 565 | ||
588 | return status; | 566 | static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd) |
567 | { | ||
568 | return dentry->d_op->d_revalidate(dentry, nd); | ||
589 | } | 569 | } |
590 | 570 | ||
591 | static inline struct dentry * | 571 | static struct dentry * |
592 | do_revalidate(struct dentry *dentry, struct nameidata *nd) | 572 | do_revalidate(struct dentry *dentry, struct nameidata *nd) |
593 | { | 573 | { |
594 | int status; | 574 | int status = d_revalidate(dentry, nd); |
595 | |||
596 | status = d_revalidate(dentry, nd); | ||
597 | if (unlikely(status <= 0)) { | 575 | if (unlikely(status <= 0)) { |
598 | /* | 576 | /* |
599 | * The dentry failed validation. | 577 | * The dentry failed validation. |
@@ -602,24 +580,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
602 | * to return a fail status. | 580 | * to return a fail status. |
603 | */ | 581 | */ |
604 | if (status < 0) { | 582 | if (status < 0) { |
605 | /* If we're in rcu-walk, we don't have a ref */ | 583 | dput(dentry); |
606 | if (!(nd->flags & LOOKUP_RCU)) | ||
607 | dput(dentry); | ||
608 | dentry = ERR_PTR(status); | 584 | dentry = ERR_PTR(status); |
609 | 585 | } else if (!d_invalidate(dentry)) { | |
610 | } else { | 586 | dput(dentry); |
611 | /* Don't d_invalidate in rcu-walk mode */ | 587 | dentry = NULL; |
612 | if (nameidata_dentry_drop_rcu_maybe(nd, dentry)) | ||
613 | return ERR_PTR(-ECHILD); | ||
614 | if (!d_invalidate(dentry)) { | ||
615 | dput(dentry); | ||
616 | dentry = NULL; | ||
617 | } | ||
618 | } | 588 | } |
619 | } | 589 | } |
620 | return dentry; | 590 | return dentry; |
621 | } | 591 | } |
622 | 592 | ||
593 | static inline struct dentry * | ||
594 | do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd) | ||
595 | { | ||
596 | int status = d_revalidate(dentry, nd); | ||
597 | if (likely(status > 0)) | ||
598 | return dentry; | ||
599 | if (status == -ECHILD) { | ||
600 | if (nameidata_dentry_drop_rcu(nd, dentry)) | ||
601 | return ERR_PTR(-ECHILD); | ||
602 | return do_revalidate(dentry, nd); | ||
603 | } | ||
604 | if (status < 0) | ||
605 | return ERR_PTR(status); | ||
606 | /* Don't d_invalidate in rcu-walk mode */ | ||
607 | if (nameidata_dentry_drop_rcu(nd, dentry)) | ||
608 | return ERR_PTR(-ECHILD); | ||
609 | if (!d_invalidate(dentry)) { | ||
610 | dput(dentry); | ||
611 | dentry = NULL; | ||
612 | } | ||
613 | return dentry; | ||
614 | } | ||
615 | |||
623 | static inline int need_reval_dot(struct dentry *dentry) | 616 | static inline int need_reval_dot(struct dentry *dentry) |
624 | { | 617 | { |
625 | if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) | 618 | if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) |
@@ -664,9 +657,6 @@ force_reval_path(struct path *path, struct nameidata *nd) | |||
664 | return 0; | 657 | return 0; |
665 | 658 | ||
666 | if (!status) { | 659 | if (!status) { |
667 | /* Don't d_invalidate in rcu-walk mode */ | ||
668 | if (nameidata_drop_rcu(nd)) | ||
669 | return -ECHILD; | ||
670 | d_invalidate(dentry); | 660 | d_invalidate(dentry); |
671 | status = -ESTALE; | 661 | status = -ESTALE; |
672 | } | 662 | } |
@@ -773,6 +763,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | |||
773 | int error; | 763 | int error; |
774 | struct dentry *dentry = link->dentry; | 764 | struct dentry *dentry = link->dentry; |
775 | 765 | ||
766 | BUG_ON(nd->flags & LOOKUP_RCU); | ||
767 | |||
776 | touch_atime(link->mnt, dentry); | 768 | touch_atime(link->mnt, dentry); |
777 | nd_set_link(nd, NULL); | 769 | nd_set_link(nd, NULL); |
778 | 770 | ||
@@ -803,10 +795,16 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | |||
803 | * Without that kind of total limit, nasty chains of consecutive | 795 | * Without that kind of total limit, nasty chains of consecutive |
804 | * symlinks can cause almost arbitrarily long lookups. | 796 | * symlinks can cause almost arbitrarily long lookups. |
805 | */ | 797 | */ |
806 | static inline int do_follow_link(struct path *path, struct nameidata *nd) | 798 | static inline int do_follow_link(struct inode *inode, struct path *path, struct nameidata *nd) |
807 | { | 799 | { |
808 | void *cookie; | 800 | void *cookie; |
809 | int err = -ELOOP; | 801 | int err = -ELOOP; |
802 | |||
803 | /* We drop rcu-walk here */ | ||
804 | if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry)) | ||
805 | return -ECHILD; | ||
806 | BUG_ON(inode != path->dentry->d_inode); | ||
807 | |||
810 | if (current->link_count >= MAX_NESTED_LINKS) | 808 | if (current->link_count >= MAX_NESTED_LINKS) |
811 | goto loop; | 809 | goto loop; |
812 | if (current->total_link_count >= 40) | 810 | if (current->total_link_count >= 40) |
@@ -1251,9 +1249,15 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1251 | return -ECHILD; | 1249 | return -ECHILD; |
1252 | 1250 | ||
1253 | nd->seq = seq; | 1251 | nd->seq = seq; |
1254 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | 1252 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1255 | goto need_revalidate; | 1253 | dentry = do_revalidate_rcu(dentry, nd); |
1256 | done2: | 1254 | if (!dentry) |
1255 | goto need_lookup; | ||
1256 | if (IS_ERR(dentry)) | ||
1257 | goto fail; | ||
1258 | if (!(nd->flags & LOOKUP_RCU)) | ||
1259 | goto done; | ||
1260 | } | ||
1257 | path->mnt = mnt; | 1261 | path->mnt = mnt; |
1258 | path->dentry = dentry; | 1262 | path->dentry = dentry; |
1259 | if (likely(__follow_mount_rcu(nd, path, inode, false))) | 1263 | if (likely(__follow_mount_rcu(nd, path, inode, false))) |
@@ -1266,8 +1270,13 @@ done2: | |||
1266 | if (!dentry) | 1270 | if (!dentry) |
1267 | goto need_lookup; | 1271 | goto need_lookup; |
1268 | found: | 1272 | found: |
1269 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | 1273 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1270 | goto need_revalidate; | 1274 | dentry = do_revalidate(dentry, nd); |
1275 | if (!dentry) | ||
1276 | goto need_lookup; | ||
1277 | if (IS_ERR(dentry)) | ||
1278 | goto fail; | ||
1279 | } | ||
1271 | done: | 1280 | done: |
1272 | path->mnt = mnt; | 1281 | path->mnt = mnt; |
1273 | path->dentry = dentry; | 1282 | path->dentry = dentry; |
@@ -1309,16 +1318,6 @@ need_lookup: | |||
1309 | mutex_unlock(&dir->i_mutex); | 1318 | mutex_unlock(&dir->i_mutex); |
1310 | goto found; | 1319 | goto found; |
1311 | 1320 | ||
1312 | need_revalidate: | ||
1313 | dentry = do_revalidate(dentry, nd); | ||
1314 | if (!dentry) | ||
1315 | goto need_lookup; | ||
1316 | if (IS_ERR(dentry)) | ||
1317 | goto fail; | ||
1318 | if (nd->flags & LOOKUP_RCU) | ||
1319 | goto done2; | ||
1320 | goto done; | ||
1321 | |||
1322 | fail: | 1321 | fail: |
1323 | return PTR_ERR(dentry); | 1322 | return PTR_ERR(dentry); |
1324 | } | 1323 | } |
@@ -1415,11 +1414,7 @@ exec_again: | |||
1415 | goto out_dput; | 1414 | goto out_dput; |
1416 | 1415 | ||
1417 | if (inode->i_op->follow_link) { | 1416 | if (inode->i_op->follow_link) { |
1418 | /* We commonly drop rcu-walk here */ | 1417 | err = do_follow_link(inode, &next, nd); |
1419 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | ||
1420 | return -ECHILD; | ||
1421 | BUG_ON(inode != next.dentry->d_inode); | ||
1422 | err = do_follow_link(&next, nd); | ||
1423 | if (err) | 1418 | if (err) |
1424 | goto return_err; | 1419 | goto return_err; |
1425 | nd->inode = nd->path.dentry->d_inode; | 1420 | nd->inode = nd->path.dentry->d_inode; |
@@ -1463,10 +1458,7 @@ last_component: | |||
1463 | break; | 1458 | break; |
1464 | if (inode && unlikely(inode->i_op->follow_link) && | 1459 | if (inode && unlikely(inode->i_op->follow_link) && |
1465 | (lookup_flags & LOOKUP_FOLLOW)) { | 1460 | (lookup_flags & LOOKUP_FOLLOW)) { |
1466 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | 1461 | err = do_follow_link(inode, &next, nd); |
1467 | return -ECHILD; | ||
1468 | BUG_ON(inode != next.dentry->d_inode); | ||
1469 | err = do_follow_link(&next, nd); | ||
1470 | if (err) | 1462 | if (err) |
1471 | goto return_err; | 1463 | goto return_err; |
1472 | nd->inode = nd->path.dentry->d_inode; | 1464 | nd->inode = nd->path.dentry->d_inode; |
@@ -1500,12 +1492,15 @@ return_reval: | |||
1500 | * We may need to check the cached dentry for staleness. | 1492 | * We may need to check the cached dentry for staleness. |
1501 | */ | 1493 | */ |
1502 | if (need_reval_dot(nd->path.dentry)) { | 1494 | if (need_reval_dot(nd->path.dentry)) { |
1495 | if (nameidata_drop_rcu_last_maybe(nd)) | ||
1496 | return -ECHILD; | ||
1503 | /* Note: we do not d_invalidate() */ | 1497 | /* Note: we do not d_invalidate() */ |
1504 | err = d_revalidate(nd->path.dentry, nd); | 1498 | err = d_revalidate(nd->path.dentry, nd); |
1505 | if (!err) | 1499 | if (!err) |
1506 | err = -ESTALE; | 1500 | err = -ESTALE; |
1507 | if (err < 0) | 1501 | if (err < 0) |
1508 | break; | 1502 | break; |
1503 | return 0; | ||
1509 | } | 1504 | } |
1510 | return_base: | 1505 | return_base: |
1511 | if (nameidata_drop_rcu_last_maybe(nd)) | 1506 | if (nameidata_drop_rcu_last_maybe(nd)) |
@@ -2265,8 +2260,6 @@ static struct file *finish_open(struct nameidata *nd, | |||
2265 | return filp; | 2260 | return filp; |
2266 | 2261 | ||
2267 | exit: | 2262 | exit: |
2268 | if (!IS_ERR(nd->intent.open.file)) | ||
2269 | release_open_intent(nd); | ||
2270 | path_put(&nd->path); | 2263 | path_put(&nd->path); |
2271 | return ERR_PTR(error); | 2264 | return ERR_PTR(error); |
2272 | } | 2265 | } |
@@ -2389,8 +2382,6 @@ exit_mutex_unlock: | |||
2389 | exit_dput: | 2382 | exit_dput: |
2390 | path_put_conditional(path, nd); | 2383 | path_put_conditional(path, nd); |
2391 | exit: | 2384 | exit: |
2392 | if (!IS_ERR(nd->intent.open.file)) | ||
2393 | release_open_intent(nd); | ||
2394 | path_put(&nd->path); | 2385 | path_put(&nd->path); |
2395 | return ERR_PTR(error); | 2386 | return ERR_PTR(error); |
2396 | } | 2387 | } |
@@ -2477,6 +2468,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
2477 | } | 2468 | } |
2478 | audit_inode(pathname, nd.path.dentry); | 2469 | audit_inode(pathname, nd.path.dentry); |
2479 | filp = finish_open(&nd, open_flag, acc_mode); | 2470 | filp = finish_open(&nd, open_flag, acc_mode); |
2471 | release_open_intent(&nd); | ||
2480 | return filp; | 2472 | return filp; |
2481 | 2473 | ||
2482 | creat: | 2474 | creat: |
@@ -2553,6 +2545,7 @@ out: | |||
2553 | path_put(&nd.root); | 2545 | path_put(&nd.root); |
2554 | if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL)) | 2546 | if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL)) |
2555 | goto reval; | 2547 | goto reval; |
2548 | release_open_intent(&nd); | ||
2556 | return filp; | 2549 | return filp; |
2557 | 2550 | ||
2558 | exit_dput: | 2551 | exit_dput: |
@@ -2560,8 +2553,6 @@ exit_dput: | |||
2560 | out_path: | 2553 | out_path: |
2561 | path_put(&nd.path); | 2554 | path_put(&nd.path); |
2562 | out_filp: | 2555 | out_filp: |
2563 | if (!IS_ERR(nd.intent.open.file)) | ||
2564 | release_open_intent(&nd); | ||
2565 | filp = ERR_PTR(error); | 2556 | filp = ERR_PTR(error); |
2566 | goto out; | 2557 | goto out; |
2567 | } | 2558 | } |