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 ec4b2d0190a8..9e701e28a329 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)) |
