diff options
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 136 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.h | 12 |
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 | */ | ||
356 | STATIC int | ||
357 | xfs_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 | |||
427 | STATIC int | ||
428 | xfs_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 | |||
346 | STATIC long | 479 | STATIC long |
347 | xfs_compat_ioctl( | 480 | xfs_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 | ||
126 | typedef 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 */ |
128 | typedef struct compat_xfs_flock64 { | 140 | typedef struct compat_xfs_flock64 { |