From: ext2 conversion (helper functions for that one will be actually used a lot by other filesystems, so to fs/namei.c they go) --- 25-akpm/fs/ext2/symlink.c | 17 +++++---------- 25-akpm/fs/namei.c | 49 +++++++++++++++++++++++++++++++++++++++++++-- 25-akpm/include/linux/fs.h | 3 ++ 3 files changed, 56 insertions(+), 13 deletions(-) diff -puN fs/ext2/symlink.c~SL1-ext2-RC6-bk5 fs/ext2/symlink.c --- 25/fs/ext2/symlink.c~SL1-ext2-RC6-bk5 2004-05-19 20:49:57.991492856 -0700 +++ 25-akpm/fs/ext2/symlink.c 2004-05-19 20:49:57.997491944 -0700 @@ -20,22 +20,17 @@ #include "ext2.h" #include "xattr.h" -static int -ext2_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); - return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data); -} - static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); - return vfs_follow_link(nd, (char *)ei->i_data); + nd_set_link(nd, (char *)ei->i_data); + return 0; } struct inode_operations ext2_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, .setxattr = ext2_setxattr, .getxattr = ext2_getxattr, .listxattr = ext2_listxattr, @@ -43,7 +38,7 @@ struct inode_operations ext2_symlink_ino }; struct inode_operations ext2_fast_symlink_inode_operations = { - .readlink = ext2_readlink, + .readlink = generic_readlink, .follow_link = ext2_follow_link, .setxattr = ext2_setxattr, .getxattr = ext2_getxattr, diff -puN fs/namei.c~SL1-ext2-RC6-bk5 fs/namei.c --- 25/fs/namei.c~SL1-ext2-RC6-bk5 2004-05-19 20:49:57.993492552 -0700 +++ 25-akpm/fs/namei.c 2004-05-19 20:49:57.999491640 -0700 @@ -2192,6 +2192,23 @@ out: return len; } +/* + * A helper for ->readlink(). This should be used *ONLY* for symlinks that + * have ->follow_link() touching nd only in nd_set_link(). Using (or not + * using) it for any given inode is up to filesystem. + */ +int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) +{ + struct nameidata nd; + int res = dentry->d_inode->i_op->follow_link(dentry, &nd); + if (!res) { + res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); + if (dentry->d_inode->i_op->put_link) + dentry->d_inode->i_op->put_link(dentry, &nd); + } + return res; +} + static inline int __vfs_follow_link(struct nameidata *nd, const char *link) { @@ -2268,6 +2285,30 @@ int page_readlink(struct dentry *dentry, return res; } +int page_follow_link_light(struct dentry *dentry, struct nameidata *nd) +{ + struct page *page; + char *s = page_getlink(dentry, &page); + if (!IS_ERR(s)) { + nd_set_link(nd, s); + s = NULL; + } + return PTR_ERR(s); +} + +void page_put_link(struct dentry *dentry, struct nameidata *nd) +{ + if (!IS_ERR(nd_get_link(nd))) { + struct page *page; + page = find_get_page(dentry->d_inode->i_mapping, 0); + if (!page) + BUG(); + kunmap(page); + page_cache_release(page); + page_cache_release(page); + } +} + int page_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page = NULL; @@ -2322,8 +2363,9 @@ fail: } struct inode_operations page_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, }; EXPORT_SYMBOL(__user_walk); @@ -2336,6 +2378,8 @@ EXPORT_SYMBOL(lookup_create); EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link); +EXPORT_SYMBOL(page_follow_link_light); +EXPORT_SYMBOL(page_put_link); EXPORT_SYMBOL(page_readlink); EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); @@ -2355,3 +2399,4 @@ EXPORT_SYMBOL(vfs_rename); EXPORT_SYMBOL(vfs_rmdir); EXPORT_SYMBOL(vfs_symlink); EXPORT_SYMBOL(vfs_unlink); +EXPORT_SYMBOL(generic_readlink); diff -puN include/linux/fs.h~SL1-ext2-RC6-bk5 include/linux/fs.h --- 25/include/linux/fs.h~SL1-ext2-RC6-bk5 2004-05-19 20:49:57.995492248 -0700 +++ 25-akpm/include/linux/fs.h 2004-05-19 20:49:58.010489968 -0700 @@ -1468,8 +1468,11 @@ extern int vfs_readlink(struct dentry *, extern int vfs_follow_link(struct nameidata *, const char *); extern int page_readlink(struct dentry *, char __user *, int); extern int page_follow_link(struct dentry *, struct nameidata *); +extern int page_follow_link_light(struct dentry *, struct nameidata *); +extern void page_put_link(struct dentry *, struct nameidata *); extern int page_symlink(struct inode *inode, const char *symname, int len); extern struct inode_operations page_symlink_inode_operations; +extern int generic_readlink(struct dentry *, char __user *, int); extern void generic_fillattr(struct inode *, struct kstat *); extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); void inode_add_bytes(struct inode *inode, loff_t bytes); _