summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2007-08-28 13:59:03 +1000
committerTim Shimmin <tes@chook.melbourne.sgi.com>2007-10-15 16:50:13 +1000
commit804c83c37607efe415774c3a170ad72a789e5992 (patch)
treef53df9e59968cf16904e7652bca7e2a7cd3da57b /fs/xfs
parent051e7cd44ab8f0f7c2958371485b4a1ff64a8d1b (diff)
downloadlinux-804c83c37607efe415774c3a170ad72a789e5992.tar.bz2
[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: Christoph Hellwig <hch@infradead.org> Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Tim Shimmin <tes@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c63
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c50
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h8
-rw-r--r--fs/xfs/xfs_vnodeops.c132
4 files changed, 121 insertions, 132 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 5917808abbd6..47cfde6cfae2 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -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
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 0b5fa124bef2..ef941f99b2bc 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -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
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 146c84ba6941..bddbdb904234 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -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))
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 36318c66a7bf..bde4a1ad90f2 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -951,6 +951,53 @@ 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
*
@@ -958,29 +1005,14 @@ xfs_access(
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);
@@ -988,68 +1020,24 @@ xfs_readlink(
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
*