diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-04 14:28:10 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 09:15:25 -0400 |
commit | 4455ca6223cc59cbc0a75f4be8bce9e84cc0d6b8 (patch) | |
tree | 5fb5966330b9dff9a364da07e85c224b89ca9dd2 /fs/namei.c | |
parent | 9856fa1b281eccdc9f8d94d716e96818c675e78e (diff) |
clear RCU on all failure exits from link_path_walk()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/fs/namei.c b/fs/namei.c index d29f91e8ff3d..f09887a45831 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1405,8 +1405,9 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1405 | * parent relationships. | 1405 | * parent relationships. |
1406 | */ | 1406 | */ |
1407 | if (unlikely(type != LAST_NORM)) { | 1407 | if (unlikely(type != LAST_NORM)) { |
1408 | if (handle_dots(nd, type)) | 1408 | err = handle_dots(nd, type); |
1409 | return -ECHILD; | 1409 | if (err) |
1410 | goto return_err; | ||
1410 | continue; | 1411 | continue; |
1411 | } | 1412 | } |
1412 | 1413 | ||
@@ -1441,8 +1442,9 @@ last_component: | |||
1441 | if (lookup_flags & LOOKUP_PARENT) | 1442 | if (lookup_flags & LOOKUP_PARENT) |
1442 | goto lookup_parent; | 1443 | goto lookup_parent; |
1443 | if (unlikely(type != LAST_NORM)) { | 1444 | if (unlikely(type != LAST_NORM)) { |
1444 | if (handle_dots(nd, type)) | 1445 | err = handle_dots(nd, type); |
1445 | return -ECHILD; | 1446 | if (err) |
1447 | goto return_err; | ||
1446 | return 0; | 1448 | return 0; |
1447 | } | 1449 | } |
1448 | err = do_lookup(nd, &this, &next, &inode); | 1450 | err = do_lookup(nd, &this, &next, &inode); |
@@ -1475,6 +1477,12 @@ lookup_parent: | |||
1475 | if (!(nd->flags & LOOKUP_RCU)) | 1477 | if (!(nd->flags & LOOKUP_RCU)) |
1476 | path_put(&nd->path); | 1478 | path_put(&nd->path); |
1477 | return_err: | 1479 | return_err: |
1480 | if (nd->flags & LOOKUP_RCU) { | ||
1481 | nd->flags &= ~LOOKUP_RCU; | ||
1482 | nd->root.mnt = NULL; | ||
1483 | rcu_read_unlock(); | ||
1484 | br_read_unlock(vfsmount_lock); | ||
1485 | } | ||
1478 | return err; | 1486 | return err; |
1479 | } | 1487 | } |
1480 | 1488 | ||
@@ -1585,16 +1593,10 @@ static int path_lookupat(int dfd, const char *name, | |||
1585 | retval = link_path_walk(name, nd); | 1593 | retval = link_path_walk(name, nd); |
1586 | 1594 | ||
1587 | if (nd->flags & LOOKUP_RCU) { | 1595 | if (nd->flags & LOOKUP_RCU) { |
1588 | /* RCU dangling. Cancel it. */ | 1596 | /* went all way through without dropping RCU */ |
1589 | if (!retval) { | 1597 | BUG_ON(retval); |
1590 | if (nameidata_drop_rcu_last(nd)) | 1598 | if (nameidata_drop_rcu_last(nd)) |
1591 | retval = -ECHILD; | 1599 | retval = -ECHILD; |
1592 | } else { | ||
1593 | nd->flags &= ~LOOKUP_RCU; | ||
1594 | nd->root.mnt = NULL; | ||
1595 | rcu_read_unlock(); | ||
1596 | br_read_unlock(vfsmount_lock); | ||
1597 | } | ||
1598 | } | 1600 | } |
1599 | 1601 | ||
1600 | if (!retval) | 1602 | if (!retval) |