diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_ioctl32.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 175 |
1 files changed, 49 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..fd4362063f25 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c | |||
@@ -340,96 +340,24 @@ xfs_compat_handlereq_copyin( | |||
340 | return 0; | 340 | return 0; |
341 | } | 341 | } |
342 | 342 | ||
343 | /* | 343 | STATIC struct dentry * |
344 | * Convert userspace handle data into inode. | 344 | xfs_compat_handlereq_to_dentry( |
345 | * | 345 | struct file *parfilp, |
346 | * We use the fact that all the fsop_handlereq ioctl calls have a data | 346 | 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 | { | 347 | { |
359 | void __user *hanp; | 348 | return xfs_handle_to_dentry(parfilp, |
360 | size_t hlen; | 349 | 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 | } | 350 | } |
422 | 351 | ||
423 | STATIC int | 352 | STATIC int |
424 | xfs_compat_attrlist_by_handle( | 353 | xfs_compat_attrlist_by_handle( |
425 | xfs_mount_t *mp, | 354 | struct file *parfilp, |
426 | void __user *arg, | 355 | void __user *arg) |
427 | struct inode *parinode) | ||
428 | { | 356 | { |
429 | int error; | 357 | int error; |
430 | attrlist_cursor_kern_t *cursor; | 358 | attrlist_cursor_kern_t *cursor; |
431 | compat_xfs_fsop_attrlist_handlereq_t al_hreq; | 359 | compat_xfs_fsop_attrlist_handlereq_t al_hreq; |
432 | struct inode *inode; | 360 | struct dentry *dentry; |
433 | char *kbuf; | 361 | char *kbuf; |
434 | 362 | ||
435 | if (!capable(CAP_SYS_ADMIN)) | 363 | if (!capable(CAP_SYS_ADMIN)) |
@@ -446,17 +374,17 @@ xfs_compat_attrlist_by_handle( | |||
446 | if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) | 374 | if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) |
447 | return -XFS_ERROR(EINVAL); | 375 | return -XFS_ERROR(EINVAL); |
448 | 376 | ||
449 | error = xfs_vget_fsop_handlereq_compat(mp, parinode, &al_hreq.hreq, | 377 | dentry = xfs_compat_handlereq_to_dentry(parfilp, &al_hreq.hreq); |
450 | &inode); | 378 | if (IS_ERR(dentry)) |
451 | if (error) | 379 | return PTR_ERR(dentry); |
452 | goto out; | ||
453 | 380 | ||
381 | error = -ENOMEM; | ||
454 | kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); | 382 | kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); |
455 | if (!kbuf) | 383 | if (!kbuf) |
456 | goto out_vn_rele; | 384 | goto out_dput; |
457 | 385 | ||
458 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 386 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; |
459 | error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen, | 387 | error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, |
460 | al_hreq.flags, cursor); | 388 | al_hreq.flags, cursor); |
461 | if (error) | 389 | if (error) |
462 | goto out_kfree; | 390 | goto out_kfree; |
@@ -466,22 +394,20 @@ xfs_compat_attrlist_by_handle( | |||
466 | 394 | ||
467 | out_kfree: | 395 | out_kfree: |
468 | kfree(kbuf); | 396 | kfree(kbuf); |
469 | out_vn_rele: | 397 | out_dput: |
470 | iput(inode); | 398 | dput(dentry); |
471 | out: | 399 | return error; |
472 | return -error; | ||
473 | } | 400 | } |
474 | 401 | ||
475 | STATIC int | 402 | STATIC int |
476 | xfs_compat_attrmulti_by_handle( | 403 | xfs_compat_attrmulti_by_handle( |
477 | xfs_mount_t *mp, | 404 | struct file *parfilp, |
478 | void __user *arg, | 405 | void __user *arg) |
479 | struct inode *parinode) | ||
480 | { | 406 | { |
481 | int error; | 407 | int error; |
482 | compat_xfs_attr_multiop_t *ops; | 408 | compat_xfs_attr_multiop_t *ops; |
483 | compat_xfs_fsop_attrmulti_handlereq_t am_hreq; | 409 | compat_xfs_fsop_attrmulti_handlereq_t am_hreq; |
484 | struct inode *inode; | 410 | struct dentry *dentry; |
485 | unsigned int i, size; | 411 | unsigned int i, size; |
486 | char *attr_name; | 412 | char *attr_name; |
487 | 413 | ||
@@ -491,20 +417,19 @@ xfs_compat_attrmulti_by_handle( | |||
491 | sizeof(compat_xfs_fsop_attrmulti_handlereq_t))) | 417 | sizeof(compat_xfs_fsop_attrmulti_handlereq_t))) |
492 | return -XFS_ERROR(EFAULT); | 418 | return -XFS_ERROR(EFAULT); |
493 | 419 | ||
494 | error = xfs_vget_fsop_handlereq_compat(mp, parinode, &am_hreq.hreq, | 420 | dentry = xfs_compat_handlereq_to_dentry(parfilp, &am_hreq.hreq); |
495 | &inode); | 421 | if (IS_ERR(dentry)) |
496 | if (error) | 422 | return PTR_ERR(dentry); |
497 | goto out; | ||
498 | 423 | ||
499 | error = E2BIG; | 424 | error = E2BIG; |
500 | size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t); | 425 | size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t); |
501 | if (!size || size > 16 * PAGE_SIZE) | 426 | if (!size || size > 16 * PAGE_SIZE) |
502 | goto out_vn_rele; | 427 | goto out_dput; |
503 | 428 | ||
504 | error = ENOMEM; | 429 | error = ENOMEM; |
505 | ops = kmalloc(size, GFP_KERNEL); | 430 | ops = kmalloc(size, GFP_KERNEL); |
506 | if (!ops) | 431 | if (!ops) |
507 | goto out_vn_rele; | 432 | goto out_dput; |
508 | 433 | ||
509 | error = EFAULT; | 434 | error = EFAULT; |
510 | if (copy_from_user(ops, compat_ptr(am_hreq.ops), size)) | 435 | if (copy_from_user(ops, compat_ptr(am_hreq.ops), size)) |
@@ -527,20 +452,21 @@ xfs_compat_attrmulti_by_handle( | |||
527 | 452 | ||
528 | switch (ops[i].am_opcode) { | 453 | switch (ops[i].am_opcode) { |
529 | case ATTR_OP_GET: | 454 | case ATTR_OP_GET: |
530 | ops[i].am_error = xfs_attrmulti_attr_get(inode, | 455 | ops[i].am_error = xfs_attrmulti_attr_get( |
531 | attr_name, | 456 | dentry->d_inode, attr_name, |
532 | compat_ptr(ops[i].am_attrvalue), | 457 | compat_ptr(ops[i].am_attrvalue), |
533 | &ops[i].am_length, ops[i].am_flags); | 458 | &ops[i].am_length, ops[i].am_flags); |
534 | break; | 459 | break; |
535 | case ATTR_OP_SET: | 460 | case ATTR_OP_SET: |
536 | ops[i].am_error = xfs_attrmulti_attr_set(inode, | 461 | ops[i].am_error = xfs_attrmulti_attr_set( |
537 | attr_name, | 462 | dentry->d_inode, attr_name, |
538 | compat_ptr(ops[i].am_attrvalue), | 463 | compat_ptr(ops[i].am_attrvalue), |
539 | ops[i].am_length, ops[i].am_flags); | 464 | ops[i].am_length, ops[i].am_flags); |
540 | break; | 465 | break; |
541 | case ATTR_OP_REMOVE: | 466 | case ATTR_OP_REMOVE: |
542 | ops[i].am_error = xfs_attrmulti_attr_remove(inode, | 467 | ops[i].am_error = xfs_attrmulti_attr_remove( |
543 | attr_name, ops[i].am_flags); | 468 | dentry->d_inode, attr_name, |
469 | ops[i].am_flags); | ||
544 | break; | 470 | break; |
545 | default: | 471 | default: |
546 | ops[i].am_error = EINVAL; | 472 | ops[i].am_error = EINVAL; |
@@ -553,22 +479,20 @@ xfs_compat_attrmulti_by_handle( | |||
553 | kfree(attr_name); | 479 | kfree(attr_name); |
554 | out_kfree_ops: | 480 | out_kfree_ops: |
555 | kfree(ops); | 481 | kfree(ops); |
556 | out_vn_rele: | 482 | out_dput: |
557 | iput(inode); | 483 | dput(dentry); |
558 | out: | ||
559 | return -error; | 484 | return -error; |
560 | } | 485 | } |
561 | 486 | ||
562 | STATIC int | 487 | STATIC int |
563 | xfs_compat_fssetdm_by_handle( | 488 | xfs_compat_fssetdm_by_handle( |
564 | xfs_mount_t *mp, | 489 | struct file *parfilp, |
565 | void __user *arg, | 490 | void __user *arg) |
566 | struct inode *parinode) | ||
567 | { | 491 | { |
568 | int error; | 492 | int error; |
569 | struct fsdmidata fsd; | 493 | struct fsdmidata fsd; |
570 | compat_xfs_fsop_setdm_handlereq_t dmhreq; | 494 | compat_xfs_fsop_setdm_handlereq_t dmhreq; |
571 | struct inode *inode; | 495 | struct dentry *dentry; |
572 | 496 | ||
573 | if (!capable(CAP_MKNOD)) | 497 | if (!capable(CAP_MKNOD)) |
574 | return -XFS_ERROR(EPERM); | 498 | return -XFS_ERROR(EPERM); |
@@ -576,12 +500,11 @@ xfs_compat_fssetdm_by_handle( | |||
576 | sizeof(compat_xfs_fsop_setdm_handlereq_t))) | 500 | sizeof(compat_xfs_fsop_setdm_handlereq_t))) |
577 | return -XFS_ERROR(EFAULT); | 501 | return -XFS_ERROR(EFAULT); |
578 | 502 | ||
579 | error = xfs_vget_fsop_handlereq_compat(mp, parinode, &dmhreq.hreq, | 503 | dentry = xfs_compat_handlereq_to_dentry(parfilp, &dmhreq.hreq); |
580 | &inode); | 504 | if (IS_ERR(dentry)) |
581 | if (error) | 505 | return PTR_ERR(dentry); |
582 | return -error; | ||
583 | 506 | ||
584 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { | 507 | if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { |
585 | error = -XFS_ERROR(EPERM); | 508 | error = -XFS_ERROR(EPERM); |
586 | goto out; | 509 | goto out; |
587 | } | 510 | } |
@@ -591,11 +514,11 @@ xfs_compat_fssetdm_by_handle( | |||
591 | goto out; | 514 | goto out; |
592 | } | 515 | } |
593 | 516 | ||
594 | error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask, | 517 | error = -xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask, |
595 | fsd.fsd_dmstate); | 518 | fsd.fsd_dmstate); |
596 | 519 | ||
597 | out: | 520 | out: |
598 | iput(inode); | 521 | dput(dentry); |
599 | return error; | 522 | return error; |
600 | } | 523 | } |
601 | 524 | ||
@@ -722,21 +645,21 @@ xfs_file_compat_ioctl( | |||
722 | 645 | ||
723 | if (xfs_compat_handlereq_copyin(&hreq, arg)) | 646 | if (xfs_compat_handlereq_copyin(&hreq, arg)) |
724 | return -XFS_ERROR(EFAULT); | 647 | return -XFS_ERROR(EFAULT); |
725 | return xfs_open_by_handle(mp, &hreq, filp, inode); | 648 | return xfs_open_by_handle(filp, &hreq); |
726 | } | 649 | } |
727 | case XFS_IOC_READLINK_BY_HANDLE_32: { | 650 | case XFS_IOC_READLINK_BY_HANDLE_32: { |
728 | struct xfs_fsop_handlereq hreq; | 651 | struct xfs_fsop_handlereq hreq; |
729 | 652 | ||
730 | if (xfs_compat_handlereq_copyin(&hreq, arg)) | 653 | if (xfs_compat_handlereq_copyin(&hreq, arg)) |
731 | return -XFS_ERROR(EFAULT); | 654 | return -XFS_ERROR(EFAULT); |
732 | return xfs_readlink_by_handle(mp, &hreq, inode); | 655 | return xfs_readlink_by_handle(filp, &hreq); |
733 | } | 656 | } |
734 | case XFS_IOC_ATTRLIST_BY_HANDLE_32: | 657 | case XFS_IOC_ATTRLIST_BY_HANDLE_32: |
735 | return xfs_compat_attrlist_by_handle(mp, arg, inode); | 658 | return xfs_compat_attrlist_by_handle(filp, arg); |
736 | case XFS_IOC_ATTRMULTI_BY_HANDLE_32: | 659 | case XFS_IOC_ATTRMULTI_BY_HANDLE_32: |
737 | return xfs_compat_attrmulti_by_handle(mp, arg, inode); | 660 | return xfs_compat_attrmulti_by_handle(filp, arg); |
738 | case XFS_IOC_FSSETDM_BY_HANDLE_32: | 661 | case XFS_IOC_FSSETDM_BY_HANDLE_32: |
739 | return xfs_compat_fssetdm_by_handle(mp, arg, inode); | 662 | return xfs_compat_fssetdm_by_handle(filp, arg); |
740 | default: | 663 | default: |
741 | return -XFS_ERROR(ENOIOCTLCMD); | 664 | return -XFS_ERROR(ENOIOCTLCMD); |
742 | } | 665 | } |