diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_ioctl32.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 184 |
1 files changed, 58 insertions, 126 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 50903ad3182e..c70c4e3db790 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | #include <linux/compat.h> | 18 | #include <linux/compat.h> |
19 | #include <linux/ioctl.h> | 19 | #include <linux/ioctl.h> |
20 | #include <linux/mount.h> | ||
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | #include "xfs.h" | 22 | #include "xfs.h" |
22 | #include "xfs_fs.h" | 23 | #include "xfs_fs.h" |
@@ -340,96 +341,24 @@ xfs_compat_handlereq_copyin( | |||
340 | return 0; | 341 | return 0; |
341 | } | 342 | } |
342 | 343 | ||
343 | /* | 344 | STATIC struct dentry * |
344 | * Convert userspace handle data into inode. | 345 | xfs_compat_handlereq_to_dentry( |
345 | * | 346 | struct file *parfilp, |
346 | * We use the fact that all the fsop_handlereq ioctl calls have a data | 347 | compat_xfs_fsop_handlereq_t *hreq) |
347 | * structure argument whose first component is always a xfs_fsop_handlereq_t, | ||
348 | * so we can pass that sub structure into this handy, shared routine. | ||
349 | * | ||
350 | * If no error, caller must always iput the returned inode. | ||
351 | */ | ||
352 | STATIC int | ||
353 | xfs_vget_fsop_handlereq_compat( | ||
354 | xfs_mount_t *mp, | ||
355 | struct inode *parinode, /* parent inode pointer */ | ||
356 | compat_xfs_fsop_handlereq_t *hreq, | ||
357 | struct inode **inode) | ||
358 | { | 348 | { |
359 | void __user *hanp; | 349 | return xfs_handle_to_dentry(parfilp, |
360 | size_t hlen; | 350 | compat_ptr(hreq->ihandle), hreq->ihandlen); |
361 | xfs_fid_t *xfid; | ||
362 | xfs_handle_t *handlep; | ||
363 | xfs_handle_t handle; | ||
364 | xfs_inode_t *ip; | ||
365 | xfs_ino_t ino; | ||
366 | __u32 igen; | ||
367 | int error; | ||
368 | |||
369 | /* | ||
370 | * Only allow handle opens under a directory. | ||
371 | */ | ||
372 | if (!S_ISDIR(parinode->i_mode)) | ||
373 | return XFS_ERROR(ENOTDIR); | ||
374 | |||
375 | hanp = compat_ptr(hreq->ihandle); | ||
376 | hlen = hreq->ihandlen; | ||
377 | handlep = &handle; | ||
378 | |||
379 | if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) | ||
380 | return XFS_ERROR(EINVAL); | ||
381 | if (copy_from_user(handlep, hanp, hlen)) | ||
382 | return XFS_ERROR(EFAULT); | ||
383 | if (hlen < sizeof(*handlep)) | ||
384 | memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen); | ||
385 | if (hlen > sizeof(handlep->ha_fsid)) { | ||
386 | if (handlep->ha_fid.fid_len != | ||
387 | (hlen - sizeof(handlep->ha_fsid) - | ||
388 | sizeof(handlep->ha_fid.fid_len)) || | ||
389 | handlep->ha_fid.fid_pad) | ||
390 | return XFS_ERROR(EINVAL); | ||
391 | } | ||
392 | |||
393 | /* | ||
394 | * Crack the handle, obtain the inode # & generation # | ||
395 | */ | ||
396 | xfid = (struct xfs_fid *)&handlep->ha_fid; | ||
397 | if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) { | ||
398 | ino = xfid->fid_ino; | ||
399 | igen = xfid->fid_gen; | ||
400 | } else { | ||
401 | return XFS_ERROR(EINVAL); | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Get the XFS inode, building a Linux inode to go with it. | ||
406 | */ | ||
407 | error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); | ||
408 | if (error) | ||
409 | return error; | ||
410 | if (ip == NULL) | ||
411 | return XFS_ERROR(EIO); | ||
412 | if (ip->i_d.di_gen != igen) { | ||
413 | xfs_iput_new(ip, XFS_ILOCK_SHARED); | ||
414 | return XFS_ERROR(ENOENT); | ||
415 | } | ||
416 | |||
417 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
418 | |||
419 | *inode = VFS_I(ip); | ||
420 | return 0; | ||
421 | } | 351 | } |
422 | 352 | ||
423 | STATIC int | 353 | STATIC int |
424 | xfs_compat_attrlist_by_handle( | 354 | xfs_compat_attrlist_by_handle( |
425 | xfs_mount_t *mp, | 355 | struct file *parfilp, |
426 | void __user *arg, | 356 | void __user *arg) |
427 | struct inode *parinode) | ||
428 | { | 357 | { |
429 | int error; | 358 | int error; |
430 | attrlist_cursor_kern_t *cursor; | 359 | attrlist_cursor_kern_t *cursor; |
431 | compat_xfs_fsop_attrlist_handlereq_t al_hreq; | 360 | compat_xfs_fsop_attrlist_handlereq_t al_hreq; |
432 | struct inode *inode; | 361 | struct dentry *dentry; |
433 | char *kbuf; | 362 | char *kbuf; |
434 | 363 | ||
435 | if (!capable(CAP_SYS_ADMIN)) | 364 | if (!capable(CAP_SYS_ADMIN)) |
@@ -446,17 +375,17 @@ xfs_compat_attrlist_by_handle( | |||
446 | if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) | 375 | if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) |
447 | return -XFS_ERROR(EINVAL); | 376 | return -XFS_ERROR(EINVAL); |
448 | 377 | ||
449 | error = xfs_vget_fsop_handlereq_compat(mp, parinode, &al_hreq.hreq, | 378 | dentry = xfs_compat_handlereq_to_dentry(parfilp, &al_hreq.hreq); |
450 | &inode); | 379 | if (IS_ERR(dentry)) |
451 | if (error) | 380 | return PTR_ERR(dentry); |
452 | goto out; | ||
453 | 381 | ||
382 | error = -ENOMEM; | ||
454 | kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); | 383 | kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); |
455 | if (!kbuf) | 384 | if (!kbuf) |
456 | goto out_vn_rele; | 385 | goto out_dput; |
457 | 386 | ||
458 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 387 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; |
459 | error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen, | 388 | error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, |
460 | al_hreq.flags, cursor); | 389 | al_hreq.flags, cursor); |
461 | if (error) | 390 | if (error) |
462 | goto out_kfree; | 391 | goto out_kfree; |
@@ -466,22 +395,20 @@ xfs_compat_attrlist_by_handle( | |||
466 | 395 | ||
467 | out_kfree: | 396 | out_kfree: |
468 | kfree(kbuf); | 397 | kfree(kbuf); |
469 | out_vn_rele: | 398 | out_dput: |
470 | iput(inode); | 399 | dput(dentry); |
471 | out: | 400 | return error; |
472 | return -error; | ||
473 | } | 401 | } |
474 | 402 | ||
475 | STATIC int | 403 | STATIC int |
476 | xfs_compat_attrmulti_by_handle( | 404 | xfs_compat_attrmulti_by_handle( |
477 | xfs_mount_t *mp, | 405 | struct file *parfilp, |
478 | void __user *arg, | 406 | void __user *arg) |
479 | struct inode *parinode) | ||
480 | { | 407 | { |
481 | int error; | 408 | int error; |
482 | compat_xfs_attr_multiop_t *ops; | 409 | compat_xfs_attr_multiop_t *ops; |
483 | compat_xfs_fsop_attrmulti_handlereq_t am_hreq; | 410 | compat_xfs_fsop_attrmulti_handlereq_t am_hreq; |
484 | struct inode *inode; | 411 | struct dentry *dentry; |
485 | unsigned int i, size; | 412 | unsigned int i, size; |
486 | char *attr_name; | 413 | char *attr_name; |
487 | 414 | ||
@@ -491,20 +418,19 @@ xfs_compat_attrmulti_by_handle( | |||
491 | sizeof(compat_xfs_fsop_attrmulti_handlereq_t))) | 418 | sizeof(compat_xfs_fsop_attrmulti_handlereq_t))) |
492 | return -XFS_ERROR(EFAULT); | 419 | return -XFS_ERROR(EFAULT); |
493 | 420 | ||
494 | error = xfs_vget_fsop_handlereq_compat(mp, parinode, &am_hreq.hreq, | 421 | dentry = xfs_compat_handlereq_to_dentry(parfilp, &am_hreq.hreq); |
495 | &inode); | 422 | if (IS_ERR(dentry)) |
496 | if (error) | 423 | return PTR_ERR(dentry); |
497 | goto out; | ||
498 | 424 | ||
499 | error = E2BIG; | 425 | error = E2BIG; |
500 | size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t); | 426 | size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t); |
501 | if (!size || size > 16 * PAGE_SIZE) | 427 | if (!size || size > 16 * PAGE_SIZE) |
502 | goto out_vn_rele; | 428 | goto out_dput; |
503 | 429 | ||
504 | error = ENOMEM; | 430 | error = ENOMEM; |
505 | ops = kmalloc(size, GFP_KERNEL); | 431 | ops = kmalloc(size, GFP_KERNEL); |
506 | if (!ops) | 432 | if (!ops) |
507 | goto out_vn_rele; | 433 | goto out_dput; |
508 | 434 | ||
509 | error = EFAULT; | 435 | error = EFAULT; |
510 | if (copy_from_user(ops, compat_ptr(am_hreq.ops), size)) | 436 | if (copy_from_user(ops, compat_ptr(am_hreq.ops), size)) |
@@ -527,20 +453,29 @@ xfs_compat_attrmulti_by_handle( | |||
527 | 453 | ||
528 | switch (ops[i].am_opcode) { | 454 | switch (ops[i].am_opcode) { |
529 | case ATTR_OP_GET: | 455 | case ATTR_OP_GET: |
530 | ops[i].am_error = xfs_attrmulti_attr_get(inode, | 456 | ops[i].am_error = xfs_attrmulti_attr_get( |
531 | attr_name, | 457 | dentry->d_inode, attr_name, |
532 | compat_ptr(ops[i].am_attrvalue), | 458 | compat_ptr(ops[i].am_attrvalue), |
533 | &ops[i].am_length, ops[i].am_flags); | 459 | &ops[i].am_length, ops[i].am_flags); |
534 | break; | 460 | break; |
535 | case ATTR_OP_SET: | 461 | case ATTR_OP_SET: |
536 | ops[i].am_error = xfs_attrmulti_attr_set(inode, | 462 | ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); |
537 | attr_name, | 463 | if (ops[i].am_error) |
464 | break; | ||
465 | ops[i].am_error = xfs_attrmulti_attr_set( | ||
466 | dentry->d_inode, attr_name, | ||
538 | compat_ptr(ops[i].am_attrvalue), | 467 | compat_ptr(ops[i].am_attrvalue), |
539 | ops[i].am_length, ops[i].am_flags); | 468 | ops[i].am_length, ops[i].am_flags); |
469 | mnt_drop_write(parfilp->f_path.mnt); | ||
540 | break; | 470 | break; |
541 | case ATTR_OP_REMOVE: | 471 | case ATTR_OP_REMOVE: |
542 | ops[i].am_error = xfs_attrmulti_attr_remove(inode, | 472 | ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); |
543 | attr_name, ops[i].am_flags); | 473 | if (ops[i].am_error) |
474 | break; | ||
475 | ops[i].am_error = xfs_attrmulti_attr_remove( | ||
476 | dentry->d_inode, attr_name, | ||
477 | ops[i].am_flags); | ||
478 | mnt_drop_write(parfilp->f_path.mnt); | ||
544 | break; | 479 | break; |
545 | default: | 480 | default: |
546 | ops[i].am_error = EINVAL; | 481 | ops[i].am_error = EINVAL; |
@@ -553,22 +488,20 @@ xfs_compat_attrmulti_by_handle( | |||
553 | kfree(attr_name); | 488 | kfree(attr_name); |
554 | out_kfree_ops: | 489 | out_kfree_ops: |
555 | kfree(ops); | 490 | kfree(ops); |
556 | out_vn_rele: | 491 | out_dput: |
557 | iput(inode); | 492 | dput(dentry); |
558 | out: | ||
559 | return -error; | 493 | return -error; |
560 | } | 494 | } |
561 | 495 | ||
562 | STATIC int | 496 | STATIC int |
563 | xfs_compat_fssetdm_by_handle( | 497 | xfs_compat_fssetdm_by_handle( |
564 | xfs_mount_t *mp, | 498 | struct file *parfilp, |
565 | void __user *arg, | 499 | void __user *arg) |
566 | struct inode *parinode) | ||
567 | { | 500 | { |
568 | int error; | 501 | int error; |
569 | struct fsdmidata fsd; | 502 | struct fsdmidata fsd; |
570 | compat_xfs_fsop_setdm_handlereq_t dmhreq; | 503 | compat_xfs_fsop_setdm_handlereq_t dmhreq; |
571 | struct inode *inode; | 504 | struct dentry *dentry; |
572 | 505 | ||
573 | if (!capable(CAP_MKNOD)) | 506 | if (!capable(CAP_MKNOD)) |
574 | return -XFS_ERROR(EPERM); | 507 | return -XFS_ERROR(EPERM); |
@@ -576,12 +509,11 @@ xfs_compat_fssetdm_by_handle( | |||
576 | sizeof(compat_xfs_fsop_setdm_handlereq_t))) | 509 | sizeof(compat_xfs_fsop_setdm_handlereq_t))) |
577 | return -XFS_ERROR(EFAULT); | 510 | return -XFS_ERROR(EFAULT); |
578 | 511 | ||
579 | error = xfs_vget_fsop_handlereq_compat(mp, parinode, &dmhreq.hreq, | 512 | dentry = xfs_compat_handlereq_to_dentry(parfilp, &dmhreq.hreq); |
580 | &inode); | 513 | if (IS_ERR(dentry)) |
581 | if (error) | 514 | return PTR_ERR(dentry); |
582 | return -error; | ||
583 | 515 | ||
584 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { | 516 | if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { |
585 | error = -XFS_ERROR(EPERM); | 517 | error = -XFS_ERROR(EPERM); |
586 | goto out; | 518 | goto out; |
587 | } | 519 | } |
@@ -591,11 +523,11 @@ xfs_compat_fssetdm_by_handle( | |||
591 | goto out; | 523 | goto out; |
592 | } | 524 | } |
593 | 525 | ||
594 | error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask, | 526 | error = -xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask, |
595 | fsd.fsd_dmstate); | 527 | fsd.fsd_dmstate); |
596 | 528 | ||
597 | out: | 529 | out: |
598 | iput(inode); | 530 | dput(dentry); |
599 | return error; | 531 | return error; |
600 | } | 532 | } |
601 | 533 | ||
@@ -722,21 +654,21 @@ xfs_file_compat_ioctl( | |||
722 | 654 | ||
723 | if (xfs_compat_handlereq_copyin(&hreq, arg)) | 655 | if (xfs_compat_handlereq_copyin(&hreq, arg)) |
724 | return -XFS_ERROR(EFAULT); | 656 | return -XFS_ERROR(EFAULT); |
725 | return xfs_open_by_handle(mp, &hreq, filp, inode); | 657 | return xfs_open_by_handle(filp, &hreq); |
726 | } | 658 | } |
727 | case XFS_IOC_READLINK_BY_HANDLE_32: { | 659 | case XFS_IOC_READLINK_BY_HANDLE_32: { |
728 | struct xfs_fsop_handlereq hreq; | 660 | struct xfs_fsop_handlereq hreq; |
729 | 661 | ||
730 | if (xfs_compat_handlereq_copyin(&hreq, arg)) | 662 | if (xfs_compat_handlereq_copyin(&hreq, arg)) |
731 | return -XFS_ERROR(EFAULT); | 663 | return -XFS_ERROR(EFAULT); |
732 | return xfs_readlink_by_handle(mp, &hreq, inode); | 664 | return xfs_readlink_by_handle(filp, &hreq); |
733 | } | 665 | } |
734 | case XFS_IOC_ATTRLIST_BY_HANDLE_32: | 666 | case XFS_IOC_ATTRLIST_BY_HANDLE_32: |
735 | return xfs_compat_attrlist_by_handle(mp, arg, inode); | 667 | return xfs_compat_attrlist_by_handle(filp, arg); |
736 | case XFS_IOC_ATTRMULTI_BY_HANDLE_32: | 668 | case XFS_IOC_ATTRMULTI_BY_HANDLE_32: |
737 | return xfs_compat_attrmulti_by_handle(mp, arg, inode); | 669 | return xfs_compat_attrmulti_by_handle(filp, arg); |
738 | case XFS_IOC_FSSETDM_BY_HANDLE_32: | 670 | case XFS_IOC_FSSETDM_BY_HANDLE_32: |
739 | return xfs_compat_fssetdm_by_handle(mp, arg, inode); | 671 | return xfs_compat_fssetdm_by_handle(filp, arg); |
740 | default: | 672 | default: |
741 | return -XFS_ERROR(ENOIOCTLCMD); | 673 | return -XFS_ERROR(ENOIOCTLCMD); |
742 | } | 674 | } |