Loading fs/gfs2/ops_inode.c +27 −86 Original line number Diff line number Diff line Loading @@ -976,122 +976,62 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, } /** * gfs2_readlinki - return the contents of a symlink * @ip: the symlink's inode * @buf: a pointer to the buffer to be filled * @len: a pointer to the length of @buf * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link * @nd: Data that we pass to vfs_follow_link() * * If @buf is too small, a piece of memory is kmalloc()ed and needs * to be freed by the caller. * This can handle symlinks of any size. * * Returns: errno * Returns: 0 on success or error code */ static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder i_gh; struct buffer_head *dibh; unsigned int x; char *buf; int error; gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); error = gfs2_glock_nq(&i_gh); if (error) { gfs2_holder_uninit(&i_gh); return error; nd_set_link(nd, ERR_PTR(error)); return NULL; } if (!ip->i_disksize) { gfs2_consist_inode(ip); error = -EIO; buf = ERR_PTR(-EIO); goto out; } error = gfs2_meta_inode_buffer(ip, &dibh); if (error) if (error) { buf = ERR_PTR(error); goto out; x = ip->i_disksize + 1; if (x > *len) { *buf = kmalloc(x, GFP_NOFS); if (!*buf) { error = -ENOMEM; goto out_brelse; } } memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); *len = x; out_brelse: x = ip->i_disksize + 1; buf = kmalloc(x, GFP_NOFS); if (!buf) buf = ERR_PTR(-ENOMEM); else memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); brelse(dibh); out: gfs2_glock_dq_uninit(&i_gh); return error; } /** * gfs2_readlink - Read the value of a symlink * @dentry: the symlink * @buf: the buffer to read the symlink data into * @size: the size of the buffer * * Returns: errno */ static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, int user_size) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (error) return error; if (user_size > len - 1) user_size = len - 1; if (copy_to_user(user_buf, buf, user_size)) error = -EFAULT; else error = user_size; if (buf != array) kfree(buf); return error; nd_set_link(nd, buf); return NULL; } /** * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link * @nd: Data that we pass to vfs_follow_link() * * This can handle symlinks of any size. It is optimised for symlinks * under GFS2_FAST_NAME_SIZE. * * Returns: 0 on success or error code */ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (!error) { error = vfs_follow_link(nd, buf); if (buf != array) kfree(buf); } else path_put(&nd->path); return ERR_PTR(error); char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); } /** Loading Loading @@ -1426,8 +1366,9 @@ const struct inode_operations gfs2_dir_iops = { }; const struct inode_operations gfs2_symlink_iops = { .readlink = gfs2_readlink, .readlink = generic_readlink, .follow_link = gfs2_follow_link, .put_link = gfs2_put_link, .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, Loading Loading
fs/gfs2/ops_inode.c +27 −86 Original line number Diff line number Diff line Loading @@ -976,122 +976,62 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, } /** * gfs2_readlinki - return the contents of a symlink * @ip: the symlink's inode * @buf: a pointer to the buffer to be filled * @len: a pointer to the length of @buf * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link * @nd: Data that we pass to vfs_follow_link() * * If @buf is too small, a piece of memory is kmalloc()ed and needs * to be freed by the caller. * This can handle symlinks of any size. * * Returns: errno * Returns: 0 on success or error code */ static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder i_gh; struct buffer_head *dibh; unsigned int x; char *buf; int error; gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); error = gfs2_glock_nq(&i_gh); if (error) { gfs2_holder_uninit(&i_gh); return error; nd_set_link(nd, ERR_PTR(error)); return NULL; } if (!ip->i_disksize) { gfs2_consist_inode(ip); error = -EIO; buf = ERR_PTR(-EIO); goto out; } error = gfs2_meta_inode_buffer(ip, &dibh); if (error) if (error) { buf = ERR_PTR(error); goto out; x = ip->i_disksize + 1; if (x > *len) { *buf = kmalloc(x, GFP_NOFS); if (!*buf) { error = -ENOMEM; goto out_brelse; } } memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); *len = x; out_brelse: x = ip->i_disksize + 1; buf = kmalloc(x, GFP_NOFS); if (!buf) buf = ERR_PTR(-ENOMEM); else memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); brelse(dibh); out: gfs2_glock_dq_uninit(&i_gh); return error; } /** * gfs2_readlink - Read the value of a symlink * @dentry: the symlink * @buf: the buffer to read the symlink data into * @size: the size of the buffer * * Returns: errno */ static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, int user_size) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (error) return error; if (user_size > len - 1) user_size = len - 1; if (copy_to_user(user_buf, buf, user_size)) error = -EFAULT; else error = user_size; if (buf != array) kfree(buf); return error; nd_set_link(nd, buf); return NULL; } /** * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link * @nd: Data that we pass to vfs_follow_link() * * This can handle symlinks of any size. It is optimised for symlinks * under GFS2_FAST_NAME_SIZE. * * Returns: 0 on success or error code */ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (!error) { error = vfs_follow_link(nd, buf); if (buf != array) kfree(buf); } else path_put(&nd->path); return ERR_PTR(error); char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); } /** Loading Loading @@ -1426,8 +1366,9 @@ const struct inode_operations gfs2_dir_iops = { }; const struct inode_operations gfs2_symlink_iops = { .readlink = gfs2_readlink, .readlink = generic_readlink, .follow_link = gfs2_follow_link, .put_link = gfs2_put_link, .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, Loading