Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 70832
b: refs/heads/master
c: 804c83c
h: refs/heads/master
v: v3
  • Loading branch information
Christoph Hellwig authored and Tim Shimmin committed Oct 15, 2007
1 parent a3c3f66 commit 763a8bc
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 133 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 051e7cd44ab8f0f7c2958371485b4a1ff64a8d1b
refs/heads/master: 804c83c37607efe415774c3a170ad72a789e5992
63 changes: 45 additions & 18 deletions trunk/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 trunk/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 trunk/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 trunk/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 763a8bc

Please sign in to comment.