diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/fs/namei.c b/fs/namei.c index 2808958e6c67..1da3064311e2 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -842,7 +842,7 @@ static inline void path_to_nameidata(const struct path *path, | |||
842 | } | 842 | } |
843 | 843 | ||
844 | /* | 844 | /* |
845 | * Helper to directly jump to a known parsed path from ->follow_link, | 845 | * Helper to directly jump to a known parsed path from ->get_link, |
846 | * caller must have taken a reference to path beforehand. | 846 | * caller must have taken a reference to path beforehand. |
847 | */ | 847 | */ |
848 | void nd_jump_link(struct path *path) | 848 | void nd_jump_link(struct path *path) |
@@ -1005,10 +1005,18 @@ const char *get_link(struct nameidata *nd) | |||
1005 | res = inode->i_link; | 1005 | res = inode->i_link; |
1006 | if (!res) { | 1006 | if (!res) { |
1007 | if (nd->flags & LOOKUP_RCU) { | 1007 | if (nd->flags & LOOKUP_RCU) { |
1008 | if (unlikely(unlazy_walk(nd, NULL, 0))) | 1008 | res = inode->i_op->get_link(NULL, inode, |
1009 | return ERR_PTR(-ECHILD); | 1009 | &last->cookie); |
1010 | if (res == ERR_PTR(-ECHILD)) { | ||
1011 | if (unlikely(unlazy_walk(nd, NULL, 0))) | ||
1012 | return ERR_PTR(-ECHILD); | ||
1013 | res = inode->i_op->get_link(dentry, inode, | ||
1014 | &last->cookie); | ||
1015 | } | ||
1016 | } else { | ||
1017 | res = inode->i_op->get_link(dentry, inode, | ||
1018 | &last->cookie); | ||
1010 | } | 1019 | } |
1011 | res = inode->i_op->follow_link(dentry, &last->cookie); | ||
1012 | if (IS_ERR_OR_NULL(res)) { | 1020 | if (IS_ERR_OR_NULL(res)) { |
1013 | last->cookie = NULL; | 1021 | last->cookie = NULL; |
1014 | return res; | 1022 | return res; |
@@ -4495,8 +4503,8 @@ EXPORT_SYMBOL(readlink_copy); | |||
4495 | 4503 | ||
4496 | /* | 4504 | /* |
4497 | * A helper for ->readlink(). This should be used *ONLY* for symlinks that | 4505 | * A helper for ->readlink(). This should be used *ONLY* for symlinks that |
4498 | * have ->follow_link() touching nd only in nd_set_link(). Using (or not | 4506 | * have ->get_link() not calling nd_jump_link(). Using (or not using) it |
4499 | * using) it for any given inode is up to filesystem. | 4507 | * for any given inode is up to filesystem. |
4500 | */ | 4508 | */ |
4501 | int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) | 4509 | int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) |
4502 | { | 4510 | { |
@@ -4506,7 +4514,7 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) | |||
4506 | int res; | 4514 | int res; |
4507 | 4515 | ||
4508 | if (!link) { | 4516 | if (!link) { |
4509 | link = inode->i_op->follow_link(dentry, &cookie); | 4517 | link = inode->i_op->get_link(dentry, inode, &cookie); |
4510 | if (IS_ERR(link)) | 4518 | if (IS_ERR(link)) |
4511 | return PTR_ERR(link); | 4519 | return PTR_ERR(link); |
4512 | } | 4520 | } |
@@ -4518,26 +4526,27 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) | |||
4518 | EXPORT_SYMBOL(generic_readlink); | 4526 | EXPORT_SYMBOL(generic_readlink); |
4519 | 4527 | ||
4520 | /* get the link contents into pagecache */ | 4528 | /* get the link contents into pagecache */ |
4521 | static const char *page_getlink(struct dentry * dentry, void **cookie) | 4529 | const char *page_get_link(struct dentry *dentry, struct inode *inode, |
4530 | void **cookie) | ||
4522 | { | 4531 | { |
4523 | char *kaddr; | 4532 | char *kaddr; |
4524 | struct page *page; | 4533 | struct page *page; |
4525 | struct address_space *mapping = dentry->d_inode->i_mapping; | 4534 | struct address_space *mapping = inode->i_mapping; |
4535 | |||
4536 | if (!dentry) | ||
4537 | return ERR_PTR(-ECHILD); | ||
4538 | |||
4526 | page = read_mapping_page(mapping, 0, NULL); | 4539 | page = read_mapping_page(mapping, 0, NULL); |
4527 | if (IS_ERR(page)) | 4540 | if (IS_ERR(page)) |
4528 | return (char*)page; | 4541 | return (char*)page; |
4529 | *cookie = page; | 4542 | *cookie = page; |
4530 | BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); | 4543 | BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); |
4531 | kaddr = page_address(page); | 4544 | kaddr = page_address(page); |
4532 | nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1); | 4545 | nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1); |
4533 | return kaddr; | 4546 | return kaddr; |
4534 | } | 4547 | } |
4535 | 4548 | ||
4536 | const char *page_follow_link_light(struct dentry *dentry, void **cookie) | 4549 | EXPORT_SYMBOL(page_get_link); |
4537 | { | ||
4538 | return page_getlink(dentry, cookie); | ||
4539 | } | ||
4540 | EXPORT_SYMBOL(page_follow_link_light); | ||
4541 | 4550 | ||
4542 | void page_put_link(struct inode *unused, void *cookie) | 4551 | void page_put_link(struct inode *unused, void *cookie) |
4543 | { | 4552 | { |
@@ -4549,7 +4558,9 @@ EXPORT_SYMBOL(page_put_link); | |||
4549 | int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) | 4558 | int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) |
4550 | { | 4559 | { |
4551 | void *cookie = NULL; | 4560 | void *cookie = NULL; |
4552 | int res = readlink_copy(buffer, buflen, page_getlink(dentry, &cookie)); | 4561 | int res = readlink_copy(buffer, buflen, |
4562 | page_get_link(dentry, d_inode(dentry), | ||
4563 | &cookie)); | ||
4553 | if (cookie) | 4564 | if (cookie) |
4554 | page_put_link(NULL, cookie); | 4565 | page_put_link(NULL, cookie); |
4555 | return res; | 4566 | return res; |
@@ -4600,7 +4611,7 @@ EXPORT_SYMBOL(page_symlink); | |||
4600 | 4611 | ||
4601 | const struct inode_operations page_symlink_inode_operations = { | 4612 | const struct inode_operations page_symlink_inode_operations = { |
4602 | .readlink = generic_readlink, | 4613 | .readlink = generic_readlink, |
4603 | .follow_link = page_follow_link_light, | 4614 | .get_link = page_get_link, |
4604 | .put_link = page_put_link, | 4615 | .put_link = page_put_link, |
4605 | }; | 4616 | }; |
4606 | EXPORT_SYMBOL(page_symlink_inode_operations); | 4617 | EXPORT_SYMBOL(page_symlink_inode_operations); |