summaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c45
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 */
848void nd_jump_link(struct path *path) 848void 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 */
4501int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) 4509int 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)
4518EXPORT_SYMBOL(generic_readlink); 4526EXPORT_SYMBOL(generic_readlink);
4519 4527
4520/* get the link contents into pagecache */ 4528/* get the link contents into pagecache */
4521static const char *page_getlink(struct dentry * dentry, void **cookie) 4529const 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
4536const char *page_follow_link_light(struct dentry *dentry, void **cookie) 4549EXPORT_SYMBOL(page_get_link);
4537{
4538 return page_getlink(dentry, cookie);
4539}
4540EXPORT_SYMBOL(page_follow_link_light);
4541 4550
4542void page_put_link(struct inode *unused, void *cookie) 4551void page_put_link(struct inode *unused, void *cookie)
4543{ 4552{
@@ -4549,7 +4558,9 @@ EXPORT_SYMBOL(page_put_link);
4549int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) 4558int 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
4601const struct inode_operations page_symlink_inode_operations = { 4612const 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};
4606EXPORT_SYMBOL(page_symlink_inode_operations); 4617EXPORT_SYMBOL(page_symlink_inode_operations);