Commit 804c83c3 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Tim Shimmin
Browse files

[XFS] stop using uio in the readlink code



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: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
parent 051e7cd4
Loading
Loading
Loading
Loading
+45 −18
Original line number Diff line number Diff line
@@ -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);
@@ -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
+13 −37
Original line number Diff line number Diff line
@@ -542,49 +542,25 @@ 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;
	error = -bhv_vop_readlink(vp, link);
	if (unlikely(error))
		goto out_kfree;

	uio->uio_iov = &iov;
	uio->uio_offset = 0;
	uio->uio_segflg = UIO_SYSSPACE;
	uio->uio_resid = MAXPATHLEN;
	uio->uio_iovcnt = 1;
	nd_set_link(nd, link);
	return NULL;

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

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

+3 −5
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@
#ifndef __XFS_VNODE_H__
#define __XFS_VNODE_H__

struct uio;
struct file;
struct bhv_vfs;
struct bhv_vattr;
@@ -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 *);
@@ -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))
+60 −72
Original line number Diff line number Diff line
@@ -951,105 +951,93 @@ xfs_access(
 */
#define SYMLINK_MAPS 2

/*
 * xfs_readlink
 *
 */
STATIC int
xfs_readlink(
	bhv_desc_t	*bdp,
	uio_t		*uiop,
	int		ioflags,
	cred_t		*credp)
xfs_readlink_bmap(
	xfs_inode_t	*ip,
	char		*link)
{
	xfs_inode_t     *ip;
	int		count;
	xfs_off_t	offset;
	int		pathlen;
	bhv_vnode_t	*vp;
	int		error = 0;
	xfs_mount_t	*mp;
	int             nmaps;
	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;

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

	ip = XFS_BHVTOI(bdp);
	mp = ip->i_mount;

	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);

	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;

	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;
		}
	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);

		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;
			goto out;
		}
		if (pathlen < byte_cnt)
			byte_cnt = pathlen;
		pathlen -= byte_cnt;

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

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

 out:
	return error;
}

error_return:
/*
 * xfs_readlink
 *
 */
STATIC int
xfs_readlink(
	bhv_desc_t	*bdp,
	char		*link)
{
	xfs_inode_t     *ip = XFS_BHVTOI(bdp);
	xfs_mount_t	*mp = ip->i_mount;
	int		pathlen;
	int		error = 0;

	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);

	pathlen = ip->i_d.di_size;
	if (!pathlen)
		goto out;

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

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


/*
 * xfs_fsync
 *