Skip to content

Commit

Permalink
[XFS] stop using uio in the readlink code
Browse files Browse the repository at this point in the history
Simplify the readlink code to get rid of the last user of uio.

SGI-PV: 968563
SGI-Modid: xfs-linux-melb:xfs-kern:29479a

Signed-off-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
  • Loading branch information
Christoph Hellwig authored and Tim Shimmin committed Oct 15, 2007
1 parent 051e7cd commit 804c83c
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 132 deletions.
63 changes: 45 additions & 18 deletions fs/xfs/linux-2.6/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,19 +349,44 @@ xfs_open_by_handle(
return new_fd;
}

/*
* This is a copy from fs/namei.c:vfs_readlink(), except for removing it's
* unused first argument.
*/
STATIC int
do_readlink(
char __user *buffer,
int buflen,
const char *link)
{
int len;

len = PTR_ERR(link);
if (IS_ERR(link))
goto out;

len = strlen(link);
if (len > (unsigned) buflen)
len = buflen;
if (copy_to_user(buffer, link, len))
len = -EFAULT;
out:
return len;
}


STATIC int
xfs_readlink_by_handle(
xfs_mount_t *mp,
void __user *arg,
struct inode *parinode)
{
int error;
struct iovec aiov;
struct uio auio;
struct inode *inode;
xfs_fsop_handlereq_t hreq;
bhv_vnode_t *vp;
__u32 olen;
void *link;
int error;

if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
Expand All @@ -374,29 +399,31 @@ xfs_readlink_by_handle(

/* Restrict this handle operation to symlinks only. */
if (!S_ISLNK(inode->i_mode)) {
VN_RELE(vp);
return -XFS_ERROR(EINVAL);
error = -XFS_ERROR(EINVAL);
goto out_iput;
}

if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
VN_RELE(vp);
return -XFS_ERROR(EFAULT);
error = -XFS_ERROR(EFAULT);
goto out_iput;
}
aiov.iov_len = olen;
aiov.iov_base = hreq.ohandle;

auio.uio_iov = (struct kvec *)&aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_resid = olen;
link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
if (!link)
goto out_iput;

error = bhv_vop_readlink(vp, &auio, IO_INVIS, NULL);
VN_RELE(vp);
error = -bhv_vop_readlink(vp, link);
if (error)
return -error;
goto out_kfree;
error = do_readlink(hreq.ohandle, olen, link);
if (error)
goto out_kfree;

return (olen - auio.uio_resid);
out_kfree:
kfree(link);
out_iput:
iput(inode);
return error;
}

STATIC int
Expand Down
50 changes: 13 additions & 37 deletions fs/xfs/linux-2.6/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,50 +542,26 @@ xfs_vn_follow_link(
struct dentry *dentry,
struct nameidata *nd)
{
bhv_vnode_t *vp;
uio_t *uio;
iovec_t iov;
int error;
bhv_vnode_t *vp = vn_from_inode(dentry->d_inode);
char *link;

ASSERT(dentry);
ASSERT(nd);
int error = -ENOMEM;

link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
if (!link) {
nd_set_link(nd, ERR_PTR(-ENOMEM));
return NULL;
}

uio = kmalloc(sizeof(uio_t), GFP_KERNEL);
if (!uio) {
kfree(link);
nd_set_link(nd, ERR_PTR(-ENOMEM));
return NULL;
}

vp = vn_from_inode(dentry->d_inode);
if (!link)
goto out_err;

iov.iov_base = link;
iov.iov_len = MAXPATHLEN;

uio->uio_iov = &iov;
uio->uio_offset = 0;
uio->uio_segflg = UIO_SYSSPACE;
uio->uio_resid = MAXPATHLEN;
uio->uio_iovcnt = 1;

error = bhv_vop_readlink(vp, uio, 0, NULL);
if (unlikely(error)) {
kfree(link);
link = ERR_PTR(-error);
} else {
link[MAXPATHLEN - uio->uio_resid] = '\0';
}
kfree(uio);
error = -bhv_vop_readlink(vp, link);
if (unlikely(error))
goto out_kfree;

nd_set_link(nd, link);
return NULL;

out_kfree:
kfree(link);
out_err:
nd_set_link(nd, ERR_PTR(error));
return NULL;
}

STATIC void
Expand Down
8 changes: 3 additions & 5 deletions fs/xfs/linux-2.6/xfs_vnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#ifndef __XFS_VNODE_H__
#define __XFS_VNODE_H__

struct uio;
struct file;
struct bhv_vfs;
struct bhv_vattr;
Expand Down Expand Up @@ -165,8 +164,7 @@ typedef int (*vop_readdir_t)(bhv_desc_t *, void *dirent, size_t bufsize,
xfs_off_t *offset, filldir_t filldir);
typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*,
char *, bhv_vnode_t **, struct cred *);
typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int,
struct cred *);
typedef int (*vop_readlink_t)(bhv_desc_t *, char *);
typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *,
xfs_off_t, xfs_off_t);
typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *);
Expand Down Expand Up @@ -271,8 +269,8 @@ typedef struct bhv_vnodeops {
VOP(vop_readdir, vp)(VNHEAD(vp),dirent,bufsize,offset,filldir)
#define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \
VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr)
#define bhv_vop_readlink(vp,uiop,fl,cr) \
VOP(vop_readlink, vp)(VNHEAD(vp),uiop,fl,cr)
#define bhv_vop_readlink(vp,link) \
VOP(vop_readlink, vp)(VNHEAD(vp), link)
#define bhv_vop_fsync(vp,f,cr,b,e) VOP(vop_fsync, vp)(VNHEAD(vp),f,cr,b,e)
#define bhv_vop_inactive(vp,cr) VOP(vop_inactive, vp)(VNHEAD(vp),cr)
#define bhv_vop_release(vp) VOP(vop_release, vp)(VNHEAD(vp))
Expand Down
132 changes: 60 additions & 72 deletions fs/xfs/xfs_vnodeops.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,105 +951,93 @@ xfs_access(
*/
#define SYMLINK_MAPS 2

STATIC int
xfs_readlink_bmap(
xfs_inode_t *ip,
char *link)
{
xfs_mount_t *mp = ip->i_mount;
int pathlen = ip->i_d.di_size;
int nmaps = SYMLINK_MAPS;
xfs_bmbt_irec_t mval[SYMLINK_MAPS];
xfs_daddr_t d;
int byte_cnt;
int n;
xfs_buf_t *bp;
int error = 0;

error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
mval, &nmaps, NULL, NULL);
if (error)
goto out;

for (n = 0; n < nmaps; n++) {
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);

bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0);
error = XFS_BUF_GETERROR(bp);
if (error) {
xfs_ioerror_alert("xfs_readlink",
ip->i_mount, bp, XFS_BUF_ADDR(bp));
xfs_buf_relse(bp);
goto out;
}
if (pathlen < byte_cnt)
byte_cnt = pathlen;
pathlen -= byte_cnt;

memcpy(link, XFS_BUF_PTR(bp), byte_cnt);
xfs_buf_relse(bp);
}

link[ip->i_d.di_size] = '\0';
error = 0;

out:
return error;
}

/*
* xfs_readlink
*
*/
STATIC int
xfs_readlink(
bhv_desc_t *bdp,
uio_t *uiop,
int ioflags,
cred_t *credp)
char *link)
{
xfs_inode_t *ip;
int count;
xfs_off_t offset;
xfs_inode_t *ip = XFS_BHVTOI(bdp);
xfs_mount_t *mp = ip->i_mount;
int pathlen;
bhv_vnode_t *vp;
int error = 0;
xfs_mount_t *mp;
int nmaps;
xfs_bmbt_irec_t mval[SYMLINK_MAPS];
xfs_daddr_t d;
int byte_cnt;
int n;
xfs_buf_t *bp;

vp = BHV_TO_VNODE(bdp);
vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);

ip = XFS_BHVTOI(bdp);
mp = ip->i_mount;
vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);

if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);

xfs_ilock(ip, XFS_ILOCK_SHARED);

ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
ASSERT(ip->i_d.di_size <= MAXPATHLEN);

offset = uiop->uio_offset;
count = uiop->uio_resid;

if (offset < 0) {
error = XFS_ERROR(EINVAL);
goto error_return;
}
if (count <= 0) {
error = 0;
goto error_return;
}

/*
* See if the symlink is stored inline.
*/
pathlen = (int)ip->i_d.di_size;
pathlen = ip->i_d.di_size;
if (!pathlen)
goto out;

if (ip->i_df.if_flags & XFS_IFINLINE) {
error = xfs_uio_read(ip->i_df.if_u1.if_data, pathlen, uiop);
}
else {
/*
* Symlink not inline. Call bmap to get it in.
*/
nmaps = SYMLINK_MAPS;

error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen),
0, NULL, 0, mval, &nmaps, NULL, NULL);

if (error) {
goto error_return;
}

for (n = 0; n < nmaps; n++) {
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
bp = xfs_buf_read(mp->m_ddev_targp, d,
BTOBB(byte_cnt), 0);
error = XFS_BUF_GETERROR(bp);
if (error) {
xfs_ioerror_alert("xfs_readlink",
ip->i_mount, bp, XFS_BUF_ADDR(bp));
xfs_buf_relse(bp);
goto error_return;
}
if (pathlen < byte_cnt)
byte_cnt = pathlen;
pathlen -= byte_cnt;

error = xfs_uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop);
xfs_buf_relse (bp);
}

memcpy(link, ip->i_df.if_u1.if_data, pathlen);
link[pathlen] = '\0';
} else {
error = xfs_readlink_bmap(ip, link);
}

error_return:
out:
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return error;
}


/*
* xfs_fsync
*
Expand Down

0 comments on commit 804c83c

Please sign in to comment.