aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c136
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.h12
2 files changed, 147 insertions, 1 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index cc1fe96efab5..e7eb0d7e0d56 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -46,6 +46,7 @@
46#include "xfs_fsops.h" 46#include "xfs_fsops.h"
47#include "xfs_alloc.h" 47#include "xfs_alloc.h"
48#include "xfs_rtalloc.h" 48#include "xfs_rtalloc.h"
49#include "xfs_attr.h"
49#include "xfs_ioctl.h" 50#include "xfs_ioctl.h"
50#include "xfs_ioctl32.h" 51#include "xfs_ioctl32.h"
51 52
@@ -343,6 +344,138 @@ xfs_compat_handlereq_copyin(
343 return 0; 344 return 0;
344} 345}
345 346
347/*
348 * Convert userspace handle data into inode.
349 *
350 * We use the fact that all the fsop_handlereq ioctl calls have a data
351 * structure argument whose first component is always a xfs_fsop_handlereq_t,
352 * so we can pass that sub structure into this handy, shared routine.
353 *
354 * If no error, caller must always iput the returned inode.
355 */
356STATIC int
357xfs_vget_fsop_handlereq_compat(
358 xfs_mount_t *mp,
359 struct inode *parinode, /* parent inode pointer */
360 compat_xfs_fsop_handlereq_t *hreq,
361 struct inode **inode)
362{
363 void __user *hanp;
364 size_t hlen;
365 xfs_fid_t *xfid;
366 xfs_handle_t *handlep;
367 xfs_handle_t handle;
368 xfs_inode_t *ip;
369 xfs_ino_t ino;
370 __u32 igen;
371 int error;
372
373 /*
374 * Only allow handle opens under a directory.
375 */
376 if (!S_ISDIR(parinode->i_mode))
377 return XFS_ERROR(ENOTDIR);
378
379 hanp = compat_ptr(hreq->ihandle);
380 hlen = hreq->ihandlen;
381 handlep = &handle;
382
383 if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
384 return XFS_ERROR(EINVAL);
385 if (copy_from_user(handlep, hanp, hlen))
386 return XFS_ERROR(EFAULT);
387 if (hlen < sizeof(*handlep))
388 memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
389 if (hlen > sizeof(handlep->ha_fsid)) {
390 if (handlep->ha_fid.fid_len !=
391 (hlen - sizeof(handlep->ha_fsid) -
392 sizeof(handlep->ha_fid.fid_len)) ||
393 handlep->ha_fid.fid_pad)
394 return XFS_ERROR(EINVAL);
395 }
396
397 /*
398 * Crack the handle, obtain the inode # & generation #
399 */
400 xfid = (struct xfs_fid *)&handlep->ha_fid;
401 if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) {
402 ino = xfid->fid_ino;
403 igen = xfid->fid_gen;
404 } else {
405 return XFS_ERROR(EINVAL);
406 }
407
408 /*
409 * Get the XFS inode, building a Linux inode to go with it.
410 */
411 error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
412 if (error)
413 return error;
414 if (ip == NULL)
415 return XFS_ERROR(EIO);
416 if (ip->i_d.di_gen != igen) {
417 xfs_iput_new(ip, XFS_ILOCK_SHARED);
418 return XFS_ERROR(ENOENT);
419 }
420
421 xfs_iunlock(ip, XFS_ILOCK_SHARED);
422
423 *inode = VFS_I(ip);
424 return 0;
425}
426
427STATIC int
428xfs_compat_attrlist_by_handle(
429 xfs_mount_t *mp,
430 void __user *arg,
431 struct inode *parinode)
432{
433 int error;
434 attrlist_cursor_kern_t *cursor;
435 compat_xfs_fsop_attrlist_handlereq_t al_hreq;
436 struct inode *inode;
437 char *kbuf;
438
439 if (!capable(CAP_SYS_ADMIN))
440 return -XFS_ERROR(EPERM);
441 if (copy_from_user(&al_hreq, arg,
442 sizeof(compat_xfs_fsop_attrlist_handlereq_t)))
443 return -XFS_ERROR(EFAULT);
444 if (al_hreq.buflen > XATTR_LIST_MAX)
445 return -XFS_ERROR(EINVAL);
446
447 /*
448 * Reject flags, only allow namespaces.
449 */
450 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
451 return -XFS_ERROR(EINVAL);
452
453 error = xfs_vget_fsop_handlereq_compat(mp, parinode, &al_hreq.hreq,
454 &inode);
455 if (error)
456 goto out;
457
458 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
459 if (!kbuf)
460 goto out_vn_rele;
461
462 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
463 error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen,
464 al_hreq.flags, cursor);
465 if (error)
466 goto out_kfree;
467
468 if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen))
469 error = -EFAULT;
470
471 out_kfree:
472 kfree(kbuf);
473 out_vn_rele:
474 iput(inode);
475 out:
476 return -error;
477}
478
346STATIC long 479STATIC long
347xfs_compat_ioctl( 480xfs_compat_ioctl(
348 xfs_inode_t *ip, 481 xfs_inode_t *ip,
@@ -368,7 +501,6 @@ xfs_compat_ioctl(
368 case XFS_IOC_GETBMAPX: 501 case XFS_IOC_GETBMAPX:
369/* not handled 502/* not handled
370 case XFS_IOC_FSSETDM_BY_HANDLE: 503 case XFS_IOC_FSSETDM_BY_HANDLE:
371 case XFS_IOC_ATTRLIST_BY_HANDLE:
372 case XFS_IOC_ATTRMULTI_BY_HANDLE: 504 case XFS_IOC_ATTRMULTI_BY_HANDLE:
373*/ 505*/
374 case XFS_IOC_FSCOUNTS: 506 case XFS_IOC_FSCOUNTS:
@@ -476,6 +608,8 @@ xfs_compat_ioctl(
476 return -XFS_ERROR(EFAULT); 608 return -XFS_ERROR(EFAULT);
477 return xfs_readlink_by_handle(mp, &hreq, inode); 609 return xfs_readlink_by_handle(mp, &hreq, inode);
478 } 610 }
611 case XFS_IOC_ATTRLIST_BY_HANDLE_32:
612 return xfs_compat_attrlist_by_handle(mp, arg, inode);
479 default: 613 default:
480 return -XFS_ERROR(ENOIOCTLCMD); 614 return -XFS_ERROR(ENOIOCTLCMD);
481 } 615 }
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/linux-2.6/xfs_ioctl32.h
index 8b2a12a8e96f..bbf3a2cd8a7d 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.h
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.h
@@ -123,6 +123,18 @@ typedef struct compat_xfs_swapext {
123 123
124#define XFS_IOC_SWAPEXT_32 _IOWR('X', 109, struct compat_xfs_swapext) 124#define XFS_IOC_SWAPEXT_32 _IOWR('X', 109, struct compat_xfs_swapext)
125 125
126typedef struct compat_xfs_fsop_attrlist_handlereq {
127 struct compat_xfs_fsop_handlereq hreq; /* handle interface structure */
128 struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
129 __u32 flags; /* which namespace to use */
130 __u32 buflen; /* length of buffer supplied */
131 compat_uptr_t buffer; /* returned names */
132} __compat_packed compat_xfs_fsop_attrlist_handlereq_t;
133
134/* Note: actually this is read/write */
135#define XFS_IOC_ATTRLIST_BY_HANDLE_32 \
136 _IOW('X', 122, struct compat_xfs_fsop_attrlist_handlereq)
137
126#ifdef BROKEN_X86_ALIGNMENT 138#ifdef BROKEN_X86_ALIGNMENT
127/* on ia32 l_start is on a 32-bit boundary */ 139/* on ia32 l_start is on a 32-bit boundary */
128typedef struct compat_xfs_flock64 { 140typedef struct compat_xfs_flock64 {