aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6/xfs_ioctl32.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_ioctl32.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c175
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/* 343STATIC struct dentry *
344 * Convert userspace handle data into inode. 344xfs_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 */
352STATIC int
353xfs_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
423STATIC int 352STATIC int
424xfs_compat_attrlist_by_handle( 353xfs_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
475STATIC int 402STATIC int
476xfs_compat_attrmulti_by_handle( 403xfs_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
562STATIC int 487STATIC int
563xfs_compat_fssetdm_by_handle( 488xfs_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
597out: 520out:
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 }