diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 22:20:34 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-15 17:16:25 -0400 |
| commit | 574197e0de46a8a4db5c54ef7b65e43ffa8873a7 (patch) | |
| tree | c7669dd50705785f4632ff9b054bcd2e4614ea46 | |
| parent | b356379a020bb7197603118bb1cbc903963aa198 (diff) | |
tidy the trailing symlinks traversal up
* pull the handling of current->total_link_count into
__do_follow_link()
* put the common "do ->put_link() if needed and path_put() the link"
stuff into a helper (put_link(nd, link, cookie))
* rename __do_follow_link() to follow_link(), while we are at it
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/namei.c | 71 |
1 files changed, 26 insertions, 45 deletions
diff --git a/fs/namei.c b/fs/namei.c index 017c3fa3a08..0a601cae23d 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -737,14 +737,31 @@ static inline void path_to_nameidata(const struct path *path, | |||
| 737 | nd->path.dentry = path->dentry; | 737 | nd->path.dentry = path->dentry; |
| 738 | } | 738 | } |
| 739 | 739 | ||
| 740 | static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) | ||
| 741 | { | ||
| 742 | struct inode *inode = link->dentry->d_inode; | ||
| 743 | if (!IS_ERR(cookie) && inode->i_op->put_link) | ||
| 744 | inode->i_op->put_link(link->dentry, nd, cookie); | ||
| 745 | path_put(link); | ||
| 746 | } | ||
| 747 | |||
| 740 | static __always_inline int | 748 | static __always_inline int |
| 741 | __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | 749 | follow_link(struct path *link, struct nameidata *nd, void **p) |
| 742 | { | 750 | { |
| 743 | int error; | 751 | int error; |
| 744 | struct dentry *dentry = link->dentry; | 752 | struct dentry *dentry = link->dentry; |
| 745 | 753 | ||
| 746 | BUG_ON(nd->flags & LOOKUP_RCU); | 754 | BUG_ON(nd->flags & LOOKUP_RCU); |
| 747 | 755 | ||
| 756 | if (unlikely(current->total_link_count >= 40)) { | ||
| 757 | *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */ | ||
| 758 | path_put_conditional(link, nd); | ||
| 759 | path_put(&nd->path); | ||
| 760 | return -ELOOP; | ||
| 761 | } | ||
| 762 | cond_resched(); | ||
| 763 | current->total_link_count++; | ||
| 764 | |||
| 748 | touch_atime(link->mnt, dentry); | 765 | touch_atime(link->mnt, dentry); |
| 749 | nd_set_link(nd, NULL); | 766 | nd_set_link(nd, NULL); |
| 750 | 767 | ||
| @@ -1356,21 +1373,12 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd) | |||
| 1356 | do { | 1373 | do { |
| 1357 | struct path link = *path; | 1374 | struct path link = *path; |
| 1358 | void *cookie; | 1375 | void *cookie; |
| 1359 | if (unlikely(current->total_link_count >= 40)) { | 1376 | |
| 1360 | path_put_conditional(path, nd); | 1377 | res = follow_link(&link, nd, &cookie); |
| 1361 | path_put(&nd->path); | ||
| 1362 | res = -ELOOP; | ||
| 1363 | break; | ||
| 1364 | } | ||
| 1365 | cond_resched(); | ||
| 1366 | current->total_link_count++; | ||
| 1367 | res = __do_follow_link(&link, nd, &cookie); | ||
| 1368 | if (!res) | 1378 | if (!res) |
| 1369 | res = walk_component(nd, path, &nd->last, | 1379 | res = walk_component(nd, path, &nd->last, |
| 1370 | nd->last_type, LOOKUP_FOLLOW); | 1380 | nd->last_type, LOOKUP_FOLLOW); |
| 1371 | if (!IS_ERR(cookie) && link.dentry->d_inode->i_op->put_link) | 1381 | put_link(nd, &link, cookie); |
| 1372 | link.dentry->d_inode->i_op->put_link(link.dentry, nd, cookie); | ||
| 1373 | path_put(&link); | ||
| 1374 | } while (res > 0); | 1382 | } while (res > 0); |
| 1375 | 1383 | ||
| 1376 | current->link_count--; | 1384 | current->link_count--; |
| @@ -1619,27 +1627,15 @@ static int path_lookupat(int dfd, const char *name, | |||
| 1619 | err = link_path_walk(name, nd); | 1627 | err = link_path_walk(name, nd); |
| 1620 | 1628 | ||
| 1621 | if (!err && !(flags & LOOKUP_PARENT)) { | 1629 | if (!err && !(flags & LOOKUP_PARENT)) { |
| 1622 | int count = 0; | ||
| 1623 | err = lookup_last(nd, &path); | 1630 | err = lookup_last(nd, &path); |
| 1624 | while (err > 0) { | 1631 | while (err > 0) { |
| 1625 | void *cookie; | 1632 | void *cookie; |
| 1626 | struct path link = path; | 1633 | struct path link = path; |
| 1627 | struct inode *inode = link.dentry->d_inode; | ||
| 1628 | |||
| 1629 | if (count++ > 32) { | ||
| 1630 | path_put_conditional(&path, nd); | ||
| 1631 | path_put(&nd->path); | ||
| 1632 | err = -ELOOP; | ||
| 1633 | break; | ||
| 1634 | } | ||
| 1635 | cond_resched(); | ||
| 1636 | nd->flags |= LOOKUP_PARENT; | 1634 | nd->flags |= LOOKUP_PARENT; |
| 1637 | err = __do_follow_link(&link, nd, &cookie); | 1635 | err = follow_link(&link, nd, &cookie); |
| 1638 | if (!err) | 1636 | if (!err) |
| 1639 | err = lookup_last(nd, &path); | 1637 | err = lookup_last(nd, &path); |
| 1640 | if (!IS_ERR(cookie) && inode->i_op->put_link) | 1638 | put_link(nd, &link, cookie); |
| 1641 | inode->i_op->put_link(link.dentry, nd, cookie); | ||
| 1642 | path_put(&link); | ||
| 1643 | } | 1639 | } |
| 1644 | } | 1640 | } |
| 1645 | 1641 | ||
| @@ -2298,7 +2294,6 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
| 2298 | struct file *base = NULL; | 2294 | struct file *base = NULL; |
| 2299 | struct file *filp; | 2295 | struct file *filp; |
| 2300 | struct path path; | 2296 | struct path path; |
| 2301 | int count = 0; | ||
| 2302 | int error; | 2297 | int error; |
| 2303 | 2298 | ||
| 2304 | filp = get_empty_filp(); | 2299 | filp = get_empty_filp(); |
| @@ -2322,35 +2317,21 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
| 2322 | filp = do_last(nd, &path, op, pathname); | 2317 | filp = do_last(nd, &path, op, pathname); |
| 2323 | while (unlikely(!filp)) { /* trailing symlink */ | 2318 | while (unlikely(!filp)) { /* trailing symlink */ |
| 2324 | struct path link = path; | 2319 | struct path link = path; |
| 2325 | struct inode *linki = link.dentry->d_inode; | ||
| 2326 | void *cookie; | 2320 | void *cookie; |
| 2327 | if (!(nd->flags & LOOKUP_FOLLOW) || count++ == 32) { | 2321 | if (!(nd->flags & LOOKUP_FOLLOW)) { |
| 2328 | path_put_conditional(&path, nd); | 2322 | path_put_conditional(&path, nd); |
| 2329 | path_put(&nd->path); | 2323 | path_put(&nd->path); |
| 2330 | filp = ERR_PTR(-ELOOP); | 2324 | filp = ERR_PTR(-ELOOP); |
| 2331 | break; | 2325 | break; |
| 2332 | } | 2326 | } |
| 2333 | /* | ||
| 2334 | * This is subtle. Instead of calling do_follow_link() we do | ||
| 2335 | * the thing by hands. The reason is that this way we have zero | ||
| 2336 | * link_count and path_walk() (called from ->follow_link) | ||
| 2337 | * honoring LOOKUP_PARENT. After that we have the parent and | ||
| 2338 | * last component, i.e. we are in the same situation as after | ||
| 2339 | * the first path_walk(). Well, almost - if the last component | ||
| 2340 | * is normal we get its copy stored in nd->last.name and we will | ||
| 2341 | * have to putname() it when we are done. Procfs-like symlinks | ||
| 2342 | * just set LAST_BIND. | ||
| 2343 | */ | ||
| 2344 | nd->flags |= LOOKUP_PARENT; | 2327 | nd->flags |= LOOKUP_PARENT; |
| 2345 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | 2328 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); |
| 2346 | error = __do_follow_link(&link, nd, &cookie); | 2329 | error = follow_link(&link, nd, &cookie); |
| 2347 | if (unlikely(error)) | 2330 | if (unlikely(error)) |
| 2348 | filp = ERR_PTR(error); | 2331 | filp = ERR_PTR(error); |
| 2349 | else | 2332 | else |
| 2350 | filp = do_last(nd, &path, op, pathname); | 2333 | filp = do_last(nd, &path, op, pathname); |
| 2351 | if (!IS_ERR(cookie) && linki->i_op->put_link) | 2334 | put_link(nd, &link, cookie); |
| 2352 | linki->i_op->put_link(link.dentry, nd, cookie); | ||
| 2353 | path_put(&link); | ||
| 2354 | } | 2335 | } |
| 2355 | out: | 2336 | out: |
| 2356 | if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) | 2337 | if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) |
