Commit 6143b9ad authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] symlink 2/9: ext2 conversion and helper functions

        ext2 conversion (helper functions for that one will be actually
used a lot by other filesystems, so to fs/namei.c they go)
parent e6a9fb1e
...@@ -19,23 +19,19 @@ ...@@ -19,23 +19,19 @@
#include "ext2.h" #include "ext2.h"
#include "xattr.h" #include "xattr.h"
#include <linux/namei.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) static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); 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 = { struct inode_operations ext2_symlink_inode_operations = {
.readlink = page_readlink, .readlink = generic_readlink,
.follow_link = page_follow_link, .follow_link = page_follow_link_light,
.put_link = page_put_link,
.setxattr = ext2_setxattr, .setxattr = ext2_setxattr,
.getxattr = ext2_getxattr, .getxattr = ext2_getxattr,
.listxattr = ext2_listxattr, .listxattr = ext2_listxattr,
...@@ -43,7 +39,7 @@ struct inode_operations ext2_symlink_inode_operations = { ...@@ -43,7 +39,7 @@ struct inode_operations ext2_symlink_inode_operations = {
}; };
struct inode_operations ext2_fast_symlink_inode_operations = { struct inode_operations ext2_fast_symlink_inode_operations = {
.readlink = ext2_readlink, .readlink = generic_readlink,
.follow_link = ext2_follow_link, .follow_link = ext2_follow_link,
.setxattr = ext2_setxattr, .setxattr = ext2_setxattr,
.getxattr = ext2_getxattr, .getxattr = ext2_getxattr,
......
...@@ -2189,6 +2189,23 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const c ...@@ -2189,6 +2189,23 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const c
return len; 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 static inline int
__vfs_follow_link(struct nameidata *nd, const char *link) __vfs_follow_link(struct nameidata *nd, const char *link)
{ {
...@@ -2265,6 +2282,30 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) ...@@ -2265,6 +2282,30 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
return res; 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) int page_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
struct page *page = NULL; struct page *page = NULL;
...@@ -2319,8 +2360,9 @@ int page_symlink(struct inode *inode, const char *symname, int len) ...@@ -2319,8 +2360,9 @@ int page_symlink(struct inode *inode, const char *symname, int len)
} }
struct inode_operations page_symlink_inode_operations = { struct inode_operations page_symlink_inode_operations = {
.readlink = page_readlink, .readlink = generic_readlink,
.follow_link = page_follow_link, .follow_link = page_follow_link_light,
.put_link = page_put_link,
}; };
EXPORT_SYMBOL(__user_walk); EXPORT_SYMBOL(__user_walk);
...@@ -2333,6 +2375,8 @@ EXPORT_SYMBOL(lookup_create); ...@@ -2333,6 +2375,8 @@ EXPORT_SYMBOL(lookup_create);
EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(lookup_hash);
EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(lookup_one_len);
EXPORT_SYMBOL(page_follow_link); EXPORT_SYMBOL(page_follow_link);
EXPORT_SYMBOL(page_follow_link_light);
EXPORT_SYMBOL(page_put_link);
EXPORT_SYMBOL(page_readlink); EXPORT_SYMBOL(page_readlink);
EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink);
EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(page_symlink_inode_operations);
...@@ -2352,3 +2396,4 @@ EXPORT_SYMBOL(vfs_rename); ...@@ -2352,3 +2396,4 @@ EXPORT_SYMBOL(vfs_rename);
EXPORT_SYMBOL(vfs_rmdir); EXPORT_SYMBOL(vfs_rmdir);
EXPORT_SYMBOL(vfs_symlink); EXPORT_SYMBOL(vfs_symlink);
EXPORT_SYMBOL(vfs_unlink); EXPORT_SYMBOL(vfs_unlink);
EXPORT_SYMBOL(generic_readlink);
...@@ -1468,8 +1468,11 @@ extern int vfs_readlink(struct dentry *, char __user *, int, const char *); ...@@ -1468,8 +1468,11 @@ extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
extern int vfs_follow_link(struct nameidata *, const char *); extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char __user *, int); extern int page_readlink(struct dentry *, char __user *, int);
extern int page_follow_link(struct dentry *, struct nameidata *); 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 int page_symlink(struct inode *inode, const char *symname, int len);
extern struct inode_operations page_symlink_inode_operations; 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 void generic_fillattr(struct inode *, struct kstat *);
extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
void inode_add_bytes(struct inode *inode, loff_t bytes); void inode_add_bytes(struct inode *inode, loff_t bytes);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment