aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-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(
349 return new_fd; 349 return new_fd;
350} 350}
351 351
352/*
353 * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's
354 * unused first argument.
355 */
356STATIC int
357do_readlink(
358 char __user *buffer,
359 int buflen,
360 const char *link)
361{
362 int len;
363
364 len = PTR_ERR(link);
365 if (IS_ERR(link))
366 goto out;
367
368 len = strlen(link);
369 if (len > (unsigned) buflen)
370 len = buflen;
371 if (copy_to_user(buffer, link, len))
372 len = -EFAULT;
373 out:
374 return len;
375}
376
377
352STATIC int 378STATIC int
353xfs_readlink_by_handle( 379xfs_readlink_by_handle(
354 xfs_mount_t *mp, 380 xfs_mount_t *mp,
355 void __user *arg, 381 void __user *arg,
356 struct inode *parinode) 382 struct inode *parinode)
357{ 383{
358 int error;
359 struct iovec aiov;
360 struct uio auio;
361 struct inode *inode; 384 struct inode *inode;
362 xfs_fsop_handlereq_t hreq; 385 xfs_fsop_handlereq_t hreq;
363 bhv_vnode_t *vp; 386 bhv_vnode_t *vp;
364 __u32 olen; 387 __u32 olen;
388 void *link;
389 int error;
365 390
366 if (!capable(CAP_SYS_ADMIN)) 391 if (!capable(CAP_SYS_ADMIN))
367 return -XFS_ERROR(EPERM); 392 return -XFS_ERROR(EPERM);
@@ -374,29 +399,31 @@ xfs_readlink_by_handle(
374 399
375 /* Restrict this handle operation to symlinks only. */ 400 /* Restrict this handle operation to symlinks only. */
376 if (!S_ISLNK(inode->i_mode)) { 401 if (!S_ISLNK(inode->i_mode)) {
377 VN_RELE(vp); 402 error = -XFS_ERROR(EINVAL);
378 return -XFS_ERROR(EINVAL); 403 goto out_iput;
379 } 404 }
380 405
381 if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) { 406 if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
382 VN_RELE(vp); 407 error = -XFS_ERROR(EFAULT);
383 return -XFS_ERROR(EFAULT); 408 goto out_iput;
384 } 409 }
385 aiov.iov_len = olen;
386 aiov.iov_base = hreq.ohandle;
387 410
388 auio.uio_iov = (struct kvec *)&aiov; 411 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
389 auio.uio_iovcnt = 1; 412 if (!link)
390 auio.uio_offset = 0; 413 goto out_iput;
391 auio.uio_segflg = UIO_USERSPACE;
392 auio.uio_resid = olen;
393 414
394 error = bhv_vop_readlink(vp, &auio, IO_INVIS, NULL); 415 error = -bhv_vop_readlink(vp, link);
395 VN_RELE(vp);
396 if (error) 416 if (error)
397 return -error; 417 goto out_kfree;
418 error = do_readlink(hreq.ohandle, olen, link);
419 if (error)
420 goto out_kfree;
398 421
399 return (olen - auio.uio_resid); 422 out_kfree:
423 kfree(link);
424 out_iput:
425 iput(inode);
426 return error;
400} 427}
401 428
402STATIC int 429STATIC 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(
542 struct dentry *dentry, 542 struct dentry *dentry,
543 struct nameidata *nd) 543 struct nameidata *nd)
544{ 544{
545 bhv_vnode_t *vp; 545 bhv_vnode_t *vp = vn_from_inode(dentry->d_inode);
546 uio_t *uio;
547 iovec_t iov;
548 int error;
549 char *link; 546 char *link;
550 547 int error = -ENOMEM;
551 ASSERT(dentry);
552 ASSERT(nd);
553 548
554 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); 549 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
555 if (!link) { 550 if (!link)
556 nd_set_link(nd, ERR_PTR(-ENOMEM)); 551 goto out_err;
557 return NULL;
558 }
559
560 uio = kmalloc(sizeof(uio_t), GFP_KERNEL);
561 if (!uio) {
562 kfree(link);
563 nd_set_link(nd, ERR_PTR(-ENOMEM));
564 return NULL;
565 }
566
567 vp = vn_from_inode(dentry->d_inode);
568 552
569 iov.iov_base = link; 553 error = -bhv_vop_readlink(vp, link);
570 iov.iov_len = MAXPATHLEN; 554 if (unlikely(error))
571 555 goto out_kfree;
572 uio->uio_iov = &iov;
573 uio->uio_offset = 0;
574 uio->uio_segflg = UIO_SYSSPACE;
575 uio->uio_resid = MAXPATHLEN;
576 uio->uio_iovcnt = 1;
577
578 error = bhv_vop_readlink(vp, uio, 0, NULL);
579 if (unlikely(error)) {
580 kfree(link);
581 link = ERR_PTR(-error);
582 } else {
583 link[MAXPATHLEN - uio->uio_resid] = '\0';
584 }
585 kfree(uio);
586 556
587 nd_set_link(nd, link); 557 nd_set_link(nd, link);
588 return NULL; 558 return NULL;
559
560 out_kfree:
561 kfree(link);
562 out_err:
563 nd_set_link(nd, ERR_PTR(error));
564 return NULL;
589} 565}
590 566
591STATIC void 567STATIC 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 @@
18#ifndef __XFS_VNODE_H__ 18#ifndef __XFS_VNODE_H__
19#define __XFS_VNODE_H__ 19#define __XFS_VNODE_H__
20 20
21struct uio;
22struct file; 21struct file;
23struct bhv_vfs; 22struct bhv_vfs;
24struct bhv_vattr; 23struct bhv_vattr;
@@ -165,8 +164,7 @@ typedef int (*vop_readdir_t)(bhv_desc_t *, void *dirent, size_t bufsize,
165 xfs_off_t *offset, filldir_t filldir); 164 xfs_off_t *offset, filldir_t filldir);
166typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*, 165typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*,
167 char *, bhv_vnode_t **, struct cred *); 166 char *, bhv_vnode_t **, struct cred *);
168typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int, 167typedef int (*vop_readlink_t)(bhv_desc_t *, char *);
169 struct cred *);
170typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, 168typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *,
171 xfs_off_t, xfs_off_t); 169 xfs_off_t, xfs_off_t);
172typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); 170typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *);
@@ -271,8 +269,8 @@ typedef struct bhv_vnodeops {
271 VOP(vop_readdir, vp)(VNHEAD(vp),dirent,bufsize,offset,filldir) 269 VOP(vop_readdir, vp)(VNHEAD(vp),dirent,bufsize,offset,filldir)
272#define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \ 270#define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \
273 VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr) 271 VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr)
274#define bhv_vop_readlink(vp,uiop,fl,cr) \ 272#define bhv_vop_readlink(vp,link) \
275 VOP(vop_readlink, vp)(VNHEAD(vp),uiop,fl,cr) 273 VOP(vop_readlink, vp)(VNHEAD(vp), link)
276#define bhv_vop_fsync(vp,f,cr,b,e) VOP(vop_fsync, vp)(VNHEAD(vp),f,cr,b,e) 274#define bhv_vop_fsync(vp,f,cr,b,e) VOP(vop_fsync, vp)(VNHEAD(vp),f,cr,b,e)
277#define bhv_vop_inactive(vp,cr) VOP(vop_inactive, vp)(VNHEAD(vp),cr) 275#define bhv_vop_inactive(vp,cr) VOP(vop_inactive, vp)(VNHEAD(vp),cr)
278#define bhv_vop_release(vp) VOP(vop_release, vp)(VNHEAD(vp)) 276#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(
951 */ 951 */
952#define SYMLINK_MAPS 2 952#define SYMLINK_MAPS 2
953 953
954STATIC int
955xfs_readlink_bmap(
956 xfs_inode_t *ip,
957 char *link)
958{
959 xfs_mount_t *mp = ip->i_mount;
960 int pathlen = ip->i_d.di_size;
961 int nmaps = SYMLINK_MAPS;
962 xfs_bmbt_irec_t mval[SYMLINK_MAPS];
963 xfs_daddr_t d;
964 int byte_cnt;
965 int n;
966 xfs_buf_t *bp;
967 int error = 0;
968
969 error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
970 mval, &nmaps, NULL, NULL);
971 if (error)
972 goto out;
973
974 for (n = 0; n < nmaps; n++) {
975 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
976 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
977
978 bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0);
979 error = XFS_BUF_GETERROR(bp);
980 if (error) {
981 xfs_ioerror_alert("xfs_readlink",
982 ip->i_mount, bp, XFS_BUF_ADDR(bp));
983 xfs_buf_relse(bp);
984 goto out;
985 }
986 if (pathlen < byte_cnt)
987 byte_cnt = pathlen;
988 pathlen -= byte_cnt;
989
990 memcpy(link, XFS_BUF_PTR(bp), byte_cnt);
991 xfs_buf_relse(bp);
992 }
993
994 link[ip->i_d.di_size] = '\0';
995 error = 0;
996
997 out:
998 return error;
999}
1000
954/* 1001/*
955 * xfs_readlink 1002 * xfs_readlink
956 * 1003 *
@@ -958,29 +1005,14 @@ xfs_access(
958STATIC int 1005STATIC int
959xfs_readlink( 1006xfs_readlink(
960 bhv_desc_t *bdp, 1007 bhv_desc_t *bdp,
961 uio_t *uiop, 1008 char *link)
962 int ioflags,
963 cred_t *credp)
964{ 1009{
965 xfs_inode_t *ip; 1010 xfs_inode_t *ip = XFS_BHVTOI(bdp);
966 int count; 1011 xfs_mount_t *mp = ip->i_mount;
967 xfs_off_t offset;
968 int pathlen; 1012 int pathlen;
969 bhv_vnode_t *vp;
970 int error = 0; 1013 int error = 0;
971 xfs_mount_t *mp;
972 int nmaps;
973 xfs_bmbt_irec_t mval[SYMLINK_MAPS];
974 xfs_daddr_t d;
975 int byte_cnt;
976 int n;
977 xfs_buf_t *bp;
978 1014
979 vp = BHV_TO_VNODE(bdp); 1015 vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
980 vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
981
982 ip = XFS_BHVTOI(bdp);
983 mp = ip->i_mount;
984 1016
985 if (XFS_FORCED_SHUTDOWN(mp)) 1017 if (XFS_FORCED_SHUTDOWN(mp))
986 return XFS_ERROR(EIO); 1018 return XFS_ERROR(EIO);
@@ -988,68 +1020,24 @@ xfs_readlink(
988 xfs_ilock(ip, XFS_ILOCK_SHARED); 1020 xfs_ilock(ip, XFS_ILOCK_SHARED);
989 1021
990 ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); 1022 ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK);
1023 ASSERT(ip->i_d.di_size <= MAXPATHLEN);
991 1024
992 offset = uiop->uio_offset; 1025 pathlen = ip->i_d.di_size;
993 count = uiop->uio_resid; 1026 if (!pathlen)
994 1027 goto out;
995 if (offset < 0) {
996 error = XFS_ERROR(EINVAL);
997 goto error_return;
998 }
999 if (count <= 0) {
1000 error = 0;
1001 goto error_return;
1002 }
1003
1004 /*
1005 * See if the symlink is stored inline.
1006 */
1007 pathlen = (int)ip->i_d.di_size;
1008 1028
1009 if (ip->i_df.if_flags & XFS_IFINLINE) { 1029 if (ip->i_df.if_flags & XFS_IFINLINE) {
1010 error = xfs_uio_read(ip->i_df.if_u1.if_data, pathlen, uiop); 1030 memcpy(link, ip->i_df.if_u1.if_data, pathlen);
1011 } 1031 link[pathlen] = '\0';
1012 else { 1032 } else {
1013 /* 1033 error = xfs_readlink_bmap(ip, link);
1014 * Symlink not inline. Call bmap to get it in.
1015 */
1016 nmaps = SYMLINK_MAPS;
1017
1018 error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen),
1019 0, NULL, 0, mval, &nmaps, NULL, NULL);
1020
1021 if (error) {
1022 goto error_return;
1023 }
1024
1025 for (n = 0; n < nmaps; n++) {
1026 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
1027 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
1028 bp = xfs_buf_read(mp->m_ddev_targp, d,
1029 BTOBB(byte_cnt), 0);
1030 error = XFS_BUF_GETERROR(bp);
1031 if (error) {
1032 xfs_ioerror_alert("xfs_readlink",
1033 ip->i_mount, bp, XFS_BUF_ADDR(bp));
1034 xfs_buf_relse(bp);
1035 goto error_return;
1036 }
1037 if (pathlen < byte_cnt)
1038 byte_cnt = pathlen;
1039 pathlen -= byte_cnt;
1040
1041 error = xfs_uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop);
1042 xfs_buf_relse (bp);
1043 }
1044
1045 } 1034 }
1046 1035
1047error_return: 1036 out:
1048 xfs_iunlock(ip, XFS_ILOCK_SHARED); 1037 xfs_iunlock(ip, XFS_ILOCK_SHARED);
1049 return error; 1038 return error;
1050} 1039}
1051 1040
1052
1053/* 1041/*
1054 * xfs_fsync 1042 * xfs_fsync
1055 * 1043 *