diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2009-12-26 08:37:05 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-05 09:01:40 -0500 |
commit | def4af30cf945a3735ffca865788ea84b30b25d9 (patch) | |
tree | adeac07e1675c51e8d9fa42ccf284b7b893041f1 /fs/namei.c | |
parent | 3866248e5f86d74960a3d1592882490ec3021675 (diff) |
Get rid of symlink body copying
Now that nd->last stays around until ->put_link() is called, we can
just postpone that ->put_link() in do_filp_open() a bit and don't
bother with copying.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 55 |
1 files changed, 24 insertions, 31 deletions
diff --git a/fs/namei.c b/fs/namei.c index adfbaf5c04a7..1f5d86d1fbf5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -498,8 +498,6 @@ static int link_path_walk(const char *, struct nameidata *); | |||
498 | 498 | ||
499 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 499 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
500 | { | 500 | { |
501 | int res = 0; | ||
502 | char *name; | ||
503 | if (IS_ERR(link)) | 501 | if (IS_ERR(link)) |
504 | goto fail; | 502 | goto fail; |
505 | 503 | ||
@@ -510,22 +508,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l | |||
510 | path_get(&nd->root); | 508 | path_get(&nd->root); |
511 | } | 509 | } |
512 | 510 | ||
513 | res = link_path_walk(link, nd); | 511 | return link_path_walk(link, nd); |
514 | if (nd->depth || res || nd->last_type!=LAST_NORM) | ||
515 | return res; | ||
516 | /* | ||
517 | * If it is an iterative symlinks resolution in open_namei() we | ||
518 | * have to copy the last component. And all that crap because of | ||
519 | * bloody create() on broken symlinks. Furrfu... | ||
520 | */ | ||
521 | name = __getname(); | ||
522 | if (unlikely(!name)) { | ||
523 | path_put(&nd->path); | ||
524 | return -ENOMEM; | ||
525 | } | ||
526 | strcpy(name, nd->last.name); | ||
527 | nd->last.name = name; | ||
528 | return 0; | ||
529 | fail: | 512 | fail: |
530 | path_put(&nd->path); | 513 | path_put(&nd->path); |
531 | return PTR_ERR(link); | 514 | return PTR_ERR(link); |
@@ -547,10 +530,10 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd) | |||
547 | nd->path.dentry = path->dentry; | 530 | nd->path.dentry = path->dentry; |
548 | } | 531 | } |
549 | 532 | ||
550 | static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) | 533 | static __always_inline int |
534 | __do_follow_link(struct path *path, struct nameidata *nd, void **p) | ||
551 | { | 535 | { |
552 | int error; | 536 | int error; |
553 | void *cookie; | ||
554 | struct dentry *dentry = path->dentry; | 537 | struct dentry *dentry = path->dentry; |
555 | 538 | ||
556 | touch_atime(path->mnt, dentry); | 539 | touch_atime(path->mnt, dentry); |
@@ -562,9 +545,9 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
562 | } | 545 | } |
563 | mntget(path->mnt); | 546 | mntget(path->mnt); |
564 | nd->last_type = LAST_BIND; | 547 | nd->last_type = LAST_BIND; |
565 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); | 548 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); |
566 | error = PTR_ERR(cookie); | 549 | error = PTR_ERR(*p); |
567 | if (!IS_ERR(cookie)) { | 550 | if (!IS_ERR(*p)) { |
568 | char *s = nd_get_link(nd); | 551 | char *s = nd_get_link(nd); |
569 | error = 0; | 552 | error = 0; |
570 | if (s) | 553 | if (s) |
@@ -574,8 +557,6 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
574 | if (error) | 557 | if (error) |
575 | path_put(&nd->path); | 558 | path_put(&nd->path); |
576 | } | 559 | } |
577 | if (dentry->d_inode->i_op->put_link) | ||
578 | dentry->d_inode->i_op->put_link(dentry, nd, cookie); | ||
579 | } | 560 | } |
580 | return error; | 561 | return error; |
581 | } | 562 | } |
@@ -589,6 +570,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
589 | */ | 570 | */ |
590 | static inline int do_follow_link(struct path *path, struct nameidata *nd) | 571 | static inline int do_follow_link(struct path *path, struct nameidata *nd) |
591 | { | 572 | { |
573 | void *cookie; | ||
592 | int err = -ELOOP; | 574 | int err = -ELOOP; |
593 | if (current->link_count >= MAX_NESTED_LINKS) | 575 | if (current->link_count >= MAX_NESTED_LINKS) |
594 | goto loop; | 576 | goto loop; |
@@ -602,7 +584,9 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) | |||
602 | current->link_count++; | 584 | current->link_count++; |
603 | current->total_link_count++; | 585 | current->total_link_count++; |
604 | nd->depth++; | 586 | nd->depth++; |
605 | err = __do_follow_link(path, nd); | 587 | err = __do_follow_link(path, nd, &cookie); |
588 | if (!IS_ERR(cookie) && path->dentry->d_inode->i_op->put_link) | ||
589 | path->dentry->d_inode->i_op->put_link(path->dentry, nd, cookie); | ||
606 | path_put(path); | 590 | path_put(path); |
607 | current->link_count--; | 591 | current->link_count--; |
608 | nd->depth--; | 592 | nd->depth--; |
@@ -1847,6 +1831,9 @@ reval: | |||
1847 | nd.flags |= LOOKUP_EXCL; | 1831 | nd.flags |= LOOKUP_EXCL; |
1848 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1832 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
1849 | while (unlikely(!filp)) { /* trailing symlink */ | 1833 | while (unlikely(!filp)) { /* trailing symlink */ |
1834 | struct path holder; | ||
1835 | struct inode *inode; | ||
1836 | void *cookie; | ||
1850 | error = -ELOOP; | 1837 | error = -ELOOP; |
1851 | if ((open_flag & O_NOFOLLOW) || count++ == 32) | 1838 | if ((open_flag & O_NOFOLLOW) || count++ == 32) |
1852 | goto exit_dput; | 1839 | goto exit_dput; |
@@ -1865,18 +1852,24 @@ reval: | |||
1865 | error = security_inode_follow_link(path.dentry, &nd); | 1852 | error = security_inode_follow_link(path.dentry, &nd); |
1866 | if (error) | 1853 | if (error) |
1867 | goto exit_dput; | 1854 | goto exit_dput; |
1868 | error = __do_follow_link(&path, &nd); | 1855 | error = __do_follow_link(&path, &nd, &cookie); |
1869 | path_put(&path); | 1856 | if (unlikely(error)) { |
1870 | if (error) { | ||
1871 | /* nd.path had been dropped */ | 1857 | /* nd.path had been dropped */ |
1858 | inode = path.dentry->d_inode; | ||
1859 | if (!IS_ERR(cookie) && inode->i_op->put_link) | ||
1860 | inode->i_op->put_link(path.dentry, &nd, cookie); | ||
1861 | path_put(&path); | ||
1872 | release_open_intent(&nd); | 1862 | release_open_intent(&nd); |
1873 | filp = ERR_PTR(error); | 1863 | filp = ERR_PTR(error); |
1874 | goto out; | 1864 | goto out; |
1875 | } | 1865 | } |
1866 | holder = path; | ||
1876 | nd.flags &= ~LOOKUP_PARENT; | 1867 | nd.flags &= ~LOOKUP_PARENT; |
1877 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1868 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
1878 | if (nd.last_type == LAST_NORM) | 1869 | inode = holder.dentry->d_inode; |
1879 | __putname(nd.last.name); | 1870 | if (inode->i_op->put_link) |
1871 | inode->i_op->put_link(holder.dentry, &nd, cookie); | ||
1872 | path_put(&holder); | ||
1880 | } | 1873 | } |
1881 | out: | 1874 | out: |
1882 | if (nd.root.mnt) | 1875 | if (nd.root.mnt) |