diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-02-15 11:06:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-02-15 11:06:36 -0500 |
commit | 055d219441cc23f631240335fd369b6b5852681a (patch) | |
tree | 4b9edd925dcda0b72a4ca3ec146f516f52e51bee | |
parent | 007a14af2649c9ac77f38cd23469518ffb8b355a (diff) | |
parent | 4e924a4f53a0e1ea060bd50695a12a238b250322 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
get rid of nameidata_dentry_drop_rcu() calling nameidata_drop_rcu()
drop out of RCU in return_reval
split do_revalidate() into RCU and non-RCU cases
in do_lookup() split RCU and non-RCU cases of need_revalidate
nothing in do_follow_link() is going to see RCU
-rw-r--r-- | fs/namei.c | 122 |
1 files changed, 57 insertions, 65 deletions
diff --git a/fs/namei.c b/fs/namei.c index ec4b2d0190a..9e701e28a32 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); |
@@ -571,33 +563,15 @@ void release_open_intent(struct nameidata *nd) | |||
571 | } | 563 | } |
572 | } | 564 | } |
573 | 565 | ||
574 | /* | 566 | static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd) |
575 | * Call d_revalidate and handle filesystems that request rcu-walk | ||
576 | * to be dropped. This may be called and return in rcu-walk mode, | ||
577 | * regardless of success or error. If -ECHILD is returned, the caller | ||
578 | * must return -ECHILD back up the path walk stack so path walk may | ||
579 | * be restarted in ref-walk mode. | ||
580 | */ | ||
581 | static int d_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
582 | { | 567 | { |
583 | int status; | 568 | return dentry->d_op->d_revalidate(dentry, nd); |
584 | |||
585 | status = dentry->d_op->d_revalidate(dentry, nd); | ||
586 | if (status == -ECHILD) { | ||
587 | if (nameidata_dentry_drop_rcu(nd, dentry)) | ||
588 | return status; | ||
589 | status = dentry->d_op->d_revalidate(dentry, nd); | ||
590 | } | ||
591 | |||
592 | return status; | ||
593 | } | 569 | } |
594 | 570 | ||
595 | static inline struct dentry * | 571 | static struct dentry * |
596 | do_revalidate(struct dentry *dentry, struct nameidata *nd) | 572 | do_revalidate(struct dentry *dentry, struct nameidata *nd) |
597 | { | 573 | { |
598 | int status; | 574 | int status = d_revalidate(dentry, nd); |
599 | |||
600 | status = d_revalidate(dentry, nd); | ||
601 | if (unlikely(status <= 0)) { | 575 | if (unlikely(status <= 0)) { |
602 | /* | 576 | /* |
603 | * The dentry failed validation. | 577 | * The dentry failed validation. |
@@ -606,24 +580,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
606 | * to return a fail status. | 580 | * to return a fail status. |
607 | */ | 581 | */ |
608 | if (status < 0) { | 582 | if (status < 0) { |
609 | /* If we're in rcu-walk, we don't have a ref */ | 583 | dput(dentry); |
610 | if (!(nd->flags & LOOKUP_RCU)) | ||
611 | dput(dentry); | ||
612 | dentry = ERR_PTR(status); | 584 | dentry = ERR_PTR(status); |
613 | 585 | } else if (!d_invalidate(dentry)) { | |
614 | } else { | 586 | dput(dentry); |
615 | /* Don't d_invalidate in rcu-walk mode */ | 587 | dentry = NULL; |
616 | if (nameidata_dentry_drop_rcu_maybe(nd, dentry)) | ||
617 | return ERR_PTR(-ECHILD); | ||
618 | if (!d_invalidate(dentry)) { | ||
619 | dput(dentry); | ||
620 | dentry = NULL; | ||
621 | } | ||
622 | } | 588 | } |
623 | } | 589 | } |
624 | return dentry; | 590 | return dentry; |
625 | } | 591 | } |
626 | 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 | |||
627 | static inline int need_reval_dot(struct dentry *dentry) | 616 | static inline int need_reval_dot(struct dentry *dentry) |
628 | { | 617 | { |
629 | if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) | 618 | if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) |
@@ -668,9 +657,6 @@ force_reval_path(struct path *path, struct nameidata *nd) | |||
668 | return 0; | 657 | return 0; |
669 | 658 | ||
670 | if (!status) { | 659 | if (!status) { |
671 | /* Don't d_invalidate in rcu-walk mode */ | ||
672 | if (nameidata_drop_rcu(nd)) | ||
673 | return -ECHILD; | ||
674 | d_invalidate(dentry); | 660 | d_invalidate(dentry); |
675 | status = -ESTALE; | 661 | status = -ESTALE; |
676 | } | 662 | } |
@@ -777,6 +763,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | |||
777 | int error; | 763 | int error; |
778 | struct dentry *dentry = link->dentry; | 764 | struct dentry *dentry = link->dentry; |
779 | 765 | ||
766 | BUG_ON(nd->flags & LOOKUP_RCU); | ||
767 | |||
780 | touch_atime(link->mnt, dentry); | 768 | touch_atime(link->mnt, dentry); |
781 | nd_set_link(nd, NULL); | 769 | nd_set_link(nd, NULL); |
782 | 770 | ||
@@ -811,6 +799,11 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) | |||
811 | { | 799 | { |
812 | void *cookie; | 800 | void *cookie; |
813 | 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 | |||
814 | if (current->link_count >= MAX_NESTED_LINKS) | 807 | if (current->link_count >= MAX_NESTED_LINKS) |
815 | goto loop; | 808 | goto loop; |
816 | if (current->total_link_count >= 40) | 809 | if (current->total_link_count >= 40) |
@@ -1255,9 +1248,15 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1255 | return -ECHILD; | 1248 | return -ECHILD; |
1256 | 1249 | ||
1257 | nd->seq = seq; | 1250 | nd->seq = seq; |
1258 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | 1251 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1259 | goto need_revalidate; | 1252 | dentry = do_revalidate_rcu(dentry, nd); |
1260 | done2: | 1253 | if (!dentry) |
1254 | goto need_lookup; | ||
1255 | if (IS_ERR(dentry)) | ||
1256 | goto fail; | ||
1257 | if (!(nd->flags & LOOKUP_RCU)) | ||
1258 | goto done; | ||
1259 | } | ||
1261 | path->mnt = mnt; | 1260 | path->mnt = mnt; |
1262 | path->dentry = dentry; | 1261 | path->dentry = dentry; |
1263 | if (likely(__follow_mount_rcu(nd, path, inode, false))) | 1262 | if (likely(__follow_mount_rcu(nd, path, inode, false))) |
@@ -1270,8 +1269,13 @@ done2: | |||
1270 | if (!dentry) | 1269 | if (!dentry) |
1271 | goto need_lookup; | 1270 | goto need_lookup; |
1272 | found: | 1271 | found: |
1273 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | 1272 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1274 | goto need_revalidate; | 1273 | dentry = do_revalidate(dentry, nd); |
1274 | if (!dentry) | ||
1275 | goto need_lookup; | ||
1276 | if (IS_ERR(dentry)) | ||
1277 | goto fail; | ||
1278 | } | ||
1275 | done: | 1279 | done: |
1276 | path->mnt = mnt; | 1280 | path->mnt = mnt; |
1277 | path->dentry = dentry; | 1281 | path->dentry = dentry; |
@@ -1313,16 +1317,6 @@ need_lookup: | |||
1313 | mutex_unlock(&dir->i_mutex); | 1317 | mutex_unlock(&dir->i_mutex); |
1314 | goto found; | 1318 | goto found; |
1315 | 1319 | ||
1316 | need_revalidate: | ||
1317 | dentry = do_revalidate(dentry, nd); | ||
1318 | if (!dentry) | ||
1319 | goto need_lookup; | ||
1320 | if (IS_ERR(dentry)) | ||
1321 | goto fail; | ||
1322 | if (nd->flags & LOOKUP_RCU) | ||
1323 | goto done2; | ||
1324 | goto done; | ||
1325 | |||
1326 | fail: | 1320 | fail: |
1327 | return PTR_ERR(dentry); | 1321 | return PTR_ERR(dentry); |
1328 | } | 1322 | } |
@@ -1419,9 +1413,6 @@ exec_again: | |||
1419 | goto out_dput; | 1413 | goto out_dput; |
1420 | 1414 | ||
1421 | if (inode->i_op->follow_link) { | 1415 | if (inode->i_op->follow_link) { |
1422 | /* We commonly drop rcu-walk here */ | ||
1423 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | ||
1424 | return -ECHILD; | ||
1425 | BUG_ON(inode != next.dentry->d_inode); | 1416 | BUG_ON(inode != next.dentry->d_inode); |
1426 | err = do_follow_link(&next, nd); | 1417 | err = do_follow_link(&next, nd); |
1427 | if (err) | 1418 | if (err) |
@@ -1467,8 +1458,6 @@ last_component: | |||
1467 | break; | 1458 | break; |
1468 | if (inode && unlikely(inode->i_op->follow_link) && | 1459 | if (inode && unlikely(inode->i_op->follow_link) && |
1469 | (lookup_flags & LOOKUP_FOLLOW)) { | 1460 | (lookup_flags & LOOKUP_FOLLOW)) { |
1470 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | ||
1471 | return -ECHILD; | ||
1472 | BUG_ON(inode != next.dentry->d_inode); | 1461 | BUG_ON(inode != next.dentry->d_inode); |
1473 | err = do_follow_link(&next, nd); | 1462 | err = do_follow_link(&next, nd); |
1474 | if (err) | 1463 | if (err) |
@@ -1504,12 +1493,15 @@ return_reval: | |||
1504 | * We may need to check the cached dentry for staleness. | 1493 | * We may need to check the cached dentry for staleness. |
1505 | */ | 1494 | */ |
1506 | if (need_reval_dot(nd->path.dentry)) { | 1495 | if (need_reval_dot(nd->path.dentry)) { |
1496 | if (nameidata_drop_rcu_last_maybe(nd)) | ||
1497 | return -ECHILD; | ||
1507 | /* Note: we do not d_invalidate() */ | 1498 | /* Note: we do not d_invalidate() */ |
1508 | err = d_revalidate(nd->path.dentry, nd); | 1499 | err = d_revalidate(nd->path.dentry, nd); |
1509 | if (!err) | 1500 | if (!err) |
1510 | err = -ESTALE; | 1501 | err = -ESTALE; |
1511 | if (err < 0) | 1502 | if (err < 0) |
1512 | break; | 1503 | break; |
1504 | return 0; | ||
1513 | } | 1505 | } |
1514 | return_base: | 1506 | return_base: |
1515 | if (nameidata_drop_rcu_last_maybe(nd)) | 1507 | if (nameidata_drop_rcu_last_maybe(nd)) |