xfs_ioctl.c revision 170124
1/* 2 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18#include "xfs.h" 19#include "xfs_fs.h" 20#include "xfs_bit.h" 21#include "xfs_log.h" 22#include "xfs_inum.h" 23#include "xfs_trans.h" 24#include "xfs_sb.h" 25#include "xfs_ag.h" 26#include "xfs_dir.h" 27#include "xfs_dir2.h" 28#include "xfs_alloc.h" 29#include "xfs_dmapi.h" 30#include "xfs_mount.h" 31#include "xfs_bmap_btree.h" 32#include "xfs_alloc_btree.h" 33#include "xfs_ialloc_btree.h" 34#include "xfs_dir_sf.h" 35#include "xfs_attr_sf.h" 36#include "xfs_dir2_sf.h" 37#include "xfs_dinode.h" 38#include "xfs_inode.h" 39#include "xfs_btree.h" 40#include "xfs_ialloc.h" 41#include "xfs_rtalloc.h" 42#include "xfs_itable.h" 43#include "xfs_error.h" 44#include "xfs_rw.h" 45#include "xfs_acl.h" 46#include "xfs_cap.h" 47#include "xfs_mac.h" 48#include "xfs_attr.h" 49#include "xfs_bmap.h" 50#include "xfs_buf_item.h" 51#include "xfs_utils.h" 52#include "xfs_dfrag.h" 53#include "xfs_fsops.h" 54 55 56#include <sys/file.h> 57#if 1 58/* 59 * ioctl commands that are used by Linux filesystems 60 */ 61#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) 62#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) 63#define XFS_IOC_GETVERSION _IOR('v', 1, long) 64 65#undef copy_to_user 66static __inline__ int 67copy_to_user(void *dst, void *src, int len) { 68 memcpy(dst,src,len); 69 return 0; 70} 71#undef copy_from_user 72static __inline__ int 73copy_from_user(void *dst, void *src, int len) { 74 memcpy(dst,src,len); 75 return 0; 76} 77 78/* 79 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to 80 * a file or fs handle. 81 * 82 * XFS_IOC_PATH_TO_FSHANDLE 83 * returns fs handle for a mount point or path within that mount point 84 * XFS_IOC_FD_TO_HANDLE 85 * returns full handle for a FD opened in user space 86 * XFS_IOC_PATH_TO_HANDLE 87 * returns full handle for a path 88 */ 89STATIC int 90xfs_find_handle( 91 unsigned int cmd, 92 void __user *arg) 93{ 94#ifdef RMC 95 int hsize; 96#endif 97 xfs_handle_t handle; 98 xfs_fsop_handlereq_t hreq; 99#ifdef RMC 100 struct inode *inode; 101 xfs_vnode_t *vp; 102#endif 103 104 if (copy_from_user(&hreq, arg, sizeof(hreq))) 105 return -XFS_ERROR(EFAULT); 106 107 memset((char *)&handle, 0, sizeof(handle)); 108 109 switch (cmd) { 110#if 0 111 case XFS_IOC_PATH_TO_FSHANDLE: 112 case XFS_IOC_PATH_TO_HANDLE: { 113 struct nameidata nd; 114 int error; 115 116 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, 117 UIO_USERSPACE, hreq.path, td); 118 error = namei(&nd); 119 if (error) 120 return error; 121 NDFREE(&nd, NDF_ONLY_PNBUF); 122 break; 123 } 124 125 case XFS_IOC_FD_TO_HANDLE: { 126 struct file *file; 127 int error; 128 129 error = getvnode(td->td_proc->p_fd, hreq.fd, &file); 130 if (error) 131 return error; 132 133 error = vget(vp, LK_EXCLUSIVE, td); 134 if (error) { 135 fdrop(file); 136 return error; 137 } 138 fdrop(file); 139 break; 140 } 141#endif 142 143 default: 144 ASSERT(0); 145 return XFS_ERROR(EINVAL); 146 } 147 148#ifdef RMC 149 if (inode->i_sb->s_magic != XFS_SB_MAGIC) { 150 /* we're not in XFS anymore, Toto */ 151 iput(inode); 152 return XFS_ERROR(EINVAL); 153 } 154 155 switch (inode->i_mode & S_IFMT) { 156 case S_IFREG: 157 case S_IFDIR: 158 case S_IFLNK: 159 break; 160 default: 161 iput(inode); 162 return XFS_ERROR(EBADF); 163 } 164 /* we need the vnode */ 165 vp = vn_from_inode(inode); 166 167 /* now we can grab the fsid */ 168 memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t)); 169 hsize = sizeof(xfs_fsid_t); 170 171 if (cmd != XFS_IOC_PATH_TO_FSHANDLE) { 172 xfs_inode_t *ip; 173 int lock_mode; 174 175 /* need to get access to the xfs_inode to read the generation */ 176 ip = xfs_vtoi(vp); 177 ASSERT(ip); 178 lock_mode = xfs_ilock_map_shared(ip); 179 180 /* fill in fid section of handle from inode */ 181 handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) - 182 sizeof(handle.ha_fid.xfs_fid_len); 183 handle.ha_fid.xfs_fid_pad = 0; 184 handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen; 185 handle.ha_fid.xfs_fid_ino = ip->i_ino; 186 187 xfs_iunlock_map_shared(ip, lock_mode); 188 189 hsize = XFS_HSIZE(handle); 190 } 191 192 /* now copy our handle into the user buffer & write out the size */ 193 if (copy_to_user(hreq.ohandle, &handle, hsize) || 194 copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) { 195 iput(inode); 196 return XFS_ERROR(EFAULT); 197 } 198 199 iput(inode); 200#endif 201 return 0; 202} 203 204 205/* 206 * Convert userspace handle data into vnode (and inode). 207 * We [ab]use the fact that all the fsop_handlereq ioctl calls 208 * have a data structure argument whose first component is always 209 * a xfs_fsop_handlereq_t, so we can cast to and from this type. 210 * This allows us to optimise the copy_from_user calls and gives 211 * a handy, shared routine. 212 * 213 * If no error, caller must always VN_RELE the returned vp. 214 */ 215STATIC int 216xfs_vget_fsop_handlereq( 217 xfs_mount_t *mp, 218 struct inode *parinode, /* parent inode pointer */ 219 xfs_fsop_handlereq_t *hreq, 220 xfs_vnode_t **vp, 221 struct inode **inode) 222{ 223#if 0 224 void __user *hanp; 225 size_t hlen; 226 xfs_fid_t *xfid; 227 xfs_handle_t *handlep; 228 xfs_handle_t handle; 229 xfs_inode_t *ip; 230 struct inode *inodep; 231 xfs_vnode_t *vpp; 232 xfs_ino_t ino; 233 __u32 igen; 234 int error; 235 236 /* 237 * Only allow handle opens under a directory. 238 */ 239 if (!S_ISDIR(parinode->i_mode)) 240 return XFS_ERROR(ENOTDIR); 241 242 hanp = hreq->ihandle; 243 hlen = hreq->ihandlen; 244 handlep = &handle; 245 246 if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) 247 return XFS_ERROR(EINVAL); 248 if (copy_from_user(handlep, hanp, hlen)) 249 return XFS_ERROR(EFAULT); 250 if (hlen < sizeof(*handlep)) 251 memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen); 252 if (hlen > sizeof(handlep->ha_fsid)) { 253 if (handlep->ha_fid.xfs_fid_len != 254 (hlen - sizeof(handlep->ha_fsid) 255 - sizeof(handlep->ha_fid.xfs_fid_len)) 256 || handlep->ha_fid.xfs_fid_pad) 257 return XFS_ERROR(EINVAL); 258 } 259 260 /* 261 * Crack the handle, obtain the inode # & generation # 262 */ 263 xfid = (struct xfs_fid *)&handlep->ha_fid; 264 if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { 265 ino = xfid->xfs_fid_ino; 266 igen = xfid->xfs_fid_gen; 267 } else { 268 return XFS_ERROR(EINVAL); 269 } 270 271 /* 272 * Get the XFS inode, building a vnode to go with it. 273 */ 274 error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); 275 if (error) 276 return error; 277 if (ip == NULL) 278 return XFS_ERROR(EIO); 279 if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { 280 xfs_iput_new(ip, XFS_ILOCK_SHARED); 281 return XFS_ERROR(ENOENT); 282 } 283 284 vpp = XFS_ITOV(ip); 285 inodep = vn_to_inode(vpp); 286 xfs_iunlock(ip, XFS_ILOCK_SHARED); 287 288 *vp = vpp; 289 *inode = inodep; 290#endif 291 return 0; 292} 293 294STATIC int 295xfs_open_by_handle( 296 xfs_mount_t *mp, 297 void __user *arg, 298 struct file *parfilp, 299 struct inode *parinode) 300{ 301 int new_fd = 0; 302#if 0 303 int error; 304 int permflag; 305 struct file *filp; 306 struct inode *inode; 307 struct dentry *dentry; 308 xfs_vnode_t *vp; 309 xfs_fsop_handlereq_t hreq; 310 311 if (!capable(CAP_SYS_ADMIN)) 312 return -XFS_ERROR(EPERM); 313 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) 314 return XFS_ERROR(EFAULT); 315 316 error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode); 317 if (error) 318 return error; 319 320 /* Restrict xfs_open_by_handle to directories & regular files. */ 321 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { 322 iput(inode); 323 return XFS_ERROR(EINVAL); 324 } 325 326#if BITS_PER_LONG != 32 327 hreq.oflags |= O_LARGEFILE; 328#endif 329 /* Put open permission in namei format. */ 330 permflag = hreq.oflags; 331 if ((permflag+1) & O_ACCMODE) 332 permflag++; 333 if (permflag & O_TRUNC) 334 permflag |= 2; 335 336 if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && 337 (permflag & FMODE_WRITE) && IS_APPEND(inode)) { 338 iput(inode); 339 return XFS_ERROR(EPERM); 340 } 341 342 if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) { 343 iput(inode); 344 return XFS_ERROR(EACCES); 345 } 346 347 /* Can't write directories. */ 348 if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { 349 iput(inode); 350 return XFS_ERROR(EISDIR); 351 } 352 353 if ((new_fd = get_unused_fd()) < 0) { 354 iput(inode); 355 return new_fd; 356 } 357 358 dentry = d_alloc_anon(inode); 359 if (dentry == NULL) { 360 iput(inode); 361 put_unused_fd(new_fd); 362 return XFS_ERROR(ENOMEM); 363 } 364 365 /* Ensure umount returns EBUSY on umounts while this file is open. */ 366 mntget(parfilp->f_vfsmnt); 367 368 /* Create file pointer. */ 369 filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags); 370 if (IS_ERR(filp)) { 371 put_unused_fd(new_fd); 372 return -XFS_ERROR(-PTR_ERR(filp)); 373 } 374 if (inode->i_mode & S_IFREG) 375 filp->f_op = &xfs_invis_file_operations; 376 377 fd_install(new_fd, filp); 378#endif 379 return new_fd; 380} 381 382STATIC int 383xfs_readlink_by_handle( 384 xfs_mount_t *mp, 385 void __user *arg, 386 struct file *parfilp, 387 struct inode *parinode) 388{ 389 int error; 390 struct iovec aiov; 391 struct uio auio; 392 struct inode *inode; 393 xfs_fsop_handlereq_t hreq; 394 xfs_vnode_t *vp = NULL; 395 __u32 olen; 396 397 if (!capable(CAP_SYS_ADMIN)) 398 return -XFS_ERROR(EPERM); 399 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) 400 return -XFS_ERROR(EFAULT); 401 402 error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode); 403 if (error) 404 return -error; 405 406#if 0 407 /* Restrict this handle operation to symlinks only. */ 408 if (vp->v_type != VLNK) { 409 VN_RELE(vp); 410 return -XFS_ERROR(EINVAL); 411 } 412#endif 413 414 if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) { 415 VN_RELE(vp); 416 return -XFS_ERROR(EFAULT); 417 } 418 aiov.iov_len = olen; 419 aiov.iov_base = hreq.ohandle; 420 421 auio.uio_iov = &aiov; 422 auio.uio_iovcnt = 1; 423 auio.uio_offset = 0; 424 auio.uio_segflg = UIO_USERSPACE; 425 auio.uio_resid = olen; 426 427 XVOP_READLINK(vp, &auio, IO_INVIS, NULL, error); 428 429 VN_RELE(vp); 430 return (olen - auio.uio_resid); 431} 432 433STATIC int 434xfs_fssetdm_by_handle( 435 xfs_mount_t *mp, 436 void __user *arg, 437 struct file *parfilp, 438 struct inode *parinode) 439{ 440 int error = 0; 441#if 0 442 struct fsdmidata fsd; 443 xfs_fsop_setdm_handlereq_t dmhreq; 444 struct inode *inode; 445 bhv_desc_t *bdp; 446 xfs_vnode_t *vp; 447 448 if (!capable(CAP_MKNOD)) 449 return XFS_ERROR(EPERM); 450 if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) 451 return XFS_ERROR(EFAULT); 452 453 error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode); 454 if (error) 455 return error; 456 457 if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { 458 VN_RELE(vp); 459 return XFS_ERROR(EPERM); 460 } 461 462 if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { 463 VN_RELE(vp); 464 return XFS_ERROR(EFAULT); 465 } 466 467 bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); 468 error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL); 469 470 VN_RELE(vp); 471 if (error) 472 return error; 473#endif 474 return error; 475} 476 477STATIC int 478xfs_attrlist_by_handle( 479 xfs_mount_t *mp, 480 void __user *arg, 481 struct file *parfilp, 482 struct inode *parinode) 483{ 484 int error = 0; 485#if 0 486 attrlist_cursor_kern_t *cursor; 487 xfs_fsop_attrlist_handlereq_t al_hreq; 488 struct inode *inode; 489 xfs_vnode_t *vp; 490 char *kbuf; 491 492 if (!capable(CAP_SYS_ADMIN)) 493 return -XFS_ERROR(EPERM); 494 if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t))) 495 return -XFS_ERROR(EFAULT); 496 if (al_hreq.buflen > XATTR_LIST_MAX) 497 return -XFS_ERROR(EINVAL); 498 499 error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, 500 &vp, &inode); 501 if (error) 502 goto out; 503 504 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); 505 if (!kbuf) 506 goto out_vn_rele; 507 508 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; 509 XVOP_ATTR_LIST(vp, kbuf, al_hreq.buflen, al_hreq.flags, 510 cursor, NULL, error); 511 if (error) 512 goto out_kfree; 513 514 if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen)) 515 error = -EFAULT; 516 517 out_kfree: 518 kfree(kbuf); 519 out_vn_rele: 520 VN_RELE(vp); 521 out: 522#endif 523 return error; 524} 525 526#if 0 527STATIC int 528xfs_attrmulti_attr_get( 529 xfs_vnode_t *vp, 530 char *name, 531 char __user *ubuf, 532 __uint32_t *len, 533 __uint32_t flags) 534{ 535 int error = EFAULT; 536 char *kbuf; 537 538 if (*len > XATTR_SIZE_MAX) 539 return EINVAL; 540 kbuf = kmalloc(*len, GFP_KERNEL); 541 if (!kbuf) 542 return ENOMEM; 543 544 XVOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error); 545 if (error) 546 goto out_kfree; 547 548 if (copy_to_user(ubuf, kbuf, *len)) 549 error = EFAULT; 550 551 out_kfree: 552 kfree(kbuf); 553 return error; 554} 555#endif 556 557#if 0 558STATIC int 559xfs_attrmulti_attr_set( 560 xfs_vnode_t *vp, 561 char *name, 562 const char __user *ubuf, 563 __uint32_t len, 564 __uint32_t flags) 565{ 566 int error = EFAULT; 567 char *kbuf; 568 569 if (IS_RDONLY(&vp->v_inode)) 570 return -EROFS; 571 if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) 572 return EPERM; 573 if (len > XATTR_SIZE_MAX) 574 return EINVAL; 575 576 kbuf = kmalloc(len, GFP_KERNEL); 577 if (!kbuf) 578 return ENOMEM; 579 580 if (copy_from_user(kbuf, ubuf, len)) 581 goto out_kfree; 582 583 XVOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error); 584 585 out_kfree: 586 kfree(kbuf); 587 return error; 588} 589#endif 590 591#if 0 592STATIC int 593xfs_attrmulti_attr_remove( 594 xfs_vnode_t *vp, 595 char *name, 596 __uint32_t flags) 597{ 598 int error; 599 600 if (IS_RDONLY(&vp->v_inode)) 601 return -EROFS; 602 if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) 603 return EPERM; 604 605 XVOP_ATTR_REMOVE(vp, name, flags, NULL, error); 606 return error; 607} 608#endif 609 610STATIC int 611xfs_attrmulti_by_handle( 612 xfs_mount_t *mp, 613 void __user *arg, 614 struct file *parfilp, 615 struct inode *parinode) 616{ 617 int error = 0; 618#if 0 619 xfs_attr_multiop_t *ops; 620 xfs_fsop_attrmulti_handlereq_t am_hreq; 621 struct inode *inode; 622 xfs_vnode_t *vp; 623 unsigned int i, size; 624 char *attr_name; 625 626 if (!capable(CAP_SYS_ADMIN)) 627 return -XFS_ERROR(EPERM); 628 if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) 629 return -XFS_ERROR(EFAULT); 630 631 error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &vp, &inode); 632 if (error) 633 goto out; 634 635 error = E2BIG; 636 size = am_hreq.opcount * sizeof(attr_multiop_t); 637 if (!size || size > 16 * PAGE_SIZE) 638 goto out_vn_rele; 639 640 error = ENOMEM; 641 ops = kmalloc(size, GFP_KERNEL); 642 if (!ops) 643 goto out_vn_rele; 644 645 error = EFAULT; 646 if (copy_from_user(ops, am_hreq.ops, size)) 647 goto out_kfree_ops; 648 649 attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL); 650 if (!attr_name) 651 goto out_kfree_ops; 652 653 654 error = 0; 655 for (i = 0; i < am_hreq.opcount; i++) { 656 ops[i].am_error = strncpy_from_user(attr_name, 657 ops[i].am_attrname, MAXNAMELEN); 658 if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) 659 error = -ERANGE; 660 if (ops[i].am_error < 0) 661 break; 662 663 switch (ops[i].am_opcode) { 664 case ATTR_OP_GET: 665 ops[i].am_error = xfs_attrmulti_attr_get(vp, 666 attr_name, ops[i].am_attrvalue, 667 &ops[i].am_length, ops[i].am_flags); 668 break; 669 case ATTR_OP_SET: 670 ops[i].am_error = xfs_attrmulti_attr_set(vp, 671 attr_name, ops[i].am_attrvalue, 672 ops[i].am_length, ops[i].am_flags); 673 break; 674 case ATTR_OP_REMOVE: 675 ops[i].am_error = xfs_attrmulti_attr_remove(vp, 676 attr_name, ops[i].am_flags); 677 break; 678 default: 679 ops[i].am_error = EINVAL; 680 } 681 } 682 683 if (copy_to_user(am_hreq.ops, ops, size)) 684 error = XFS_ERROR(EFAULT); 685 686 kfree(attr_name); 687 out_kfree_ops: 688 kfree(ops); 689 out_vn_rele: 690 VN_RELE(vp); 691 out: 692#endif 693 return error; 694} 695 696/* prototypes for a few of the stack-hungry cases that have 697 * their own functions. Functions are defined after their use 698 * so gcc doesn't get fancy and inline them with -03 */ 699 700STATIC int 701xfs_ioc_space( 702 bhv_desc_t *bdp, 703 xfs_vnode_t *vp, 704 struct file *filp, 705 int flags, 706 unsigned int cmd, 707 void __user *arg); 708 709STATIC int 710xfs_ioc_bulkstat( 711 xfs_mount_t *mp, 712 unsigned int cmd, 713 void __user *arg); 714 715STATIC int 716xfs_ioc_fsgeometry_v1( 717 xfs_mount_t *mp, 718 void __user *arg); 719 720STATIC int 721xfs_ioc_fsgeometry( 722 xfs_mount_t *mp, 723 void __user *arg); 724 725STATIC int 726xfs_ioc_xattr( 727 xfs_vnode_t *vp, 728 xfs_inode_t *ip, 729 struct file *filp, 730 unsigned int cmd, 731 void __user *arg); 732 733STATIC int 734xfs_ioc_getbmap( 735 bhv_desc_t *bdp, 736 struct file *filp, 737 int flags, 738 unsigned int cmd, 739 void __user *arg); 740 741STATIC int 742xfs_ioc_getbmapx( 743 bhv_desc_t *bdp, 744 void __user *arg); 745 746int 747xfs_ioctl( 748 bhv_desc_t *bdp, 749 struct inode *inode, 750 struct file *filp, 751 int ioflags, 752 unsigned int cmd, 753 void *arg) 754{ 755 int error; 756 xfs_vnode_t *vp; 757 xfs_inode_t *ip; 758 xfs_mount_t *mp; 759 760// vp = vn_from_inode(inode); 761 vp = BHV_TO_VNODE(bdp); 762 763 printf("xfs_ioctl: bdp %p flags 0x%x cmd 0x%x basecmd 0x%x arg %p\n", 764 bdp, ioflags, cmd, 765 IOCBASECMD(cmd), 766 arg); 767 768 769 vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address); 770 771 ip = XFS_BHVTOI(bdp); 772 mp = ip->i_mount; 773 774 775#if 0 776 if ((cmd << 24 >> 24) == (XFS_IOC_GETBMAPX << 24 >> 24)) { 777 cmd = XFS_IOC_GETBMAPX; 778 } 779#endif 780 781 782 783 switch (cmd) { 784 785 case XFS_IOC_ALLOCSP: 786 case XFS_IOC_FREESP: 787 case XFS_IOC_RESVSP: 788 case XFS_IOC_UNRESVSP: 789 case XFS_IOC_ALLOCSP64: 790 case XFS_IOC_FREESP64: 791 case XFS_IOC_RESVSP64: 792 case XFS_IOC_UNRESVSP64: 793 /* 794 * Only allow the sys admin to reserve space unless 795 * unwritten extents are enabled. 796 */ 797 if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) && 798 !capable(CAP_SYS_ADMIN)) 799 return -EPERM; 800 801 return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg); 802 803 case XFS_IOC_DIOINFO: { 804 struct dioattr da; 805 xfs_buftarg_t *target = 806 (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? 807 mp->m_rtdev_targp : mp->m_ddev_targp; 808 809 da.d_mem = da.d_miniosz = 1 << target->bt_sshift; 810 da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1); 811 812 if (copy_to_user(arg, &da, sizeof(da))) 813 return XFS_ERROR(EFAULT); 814 return 0; 815 } 816 817 case XFS_IOC_FSBULKSTAT_SINGLE: 818 case XFS_IOC_FSBULKSTAT: 819 case XFS_IOC_FSINUMBERS: 820 return xfs_ioc_bulkstat(mp, cmd, arg); 821 822 case XFS_IOC_FSGEOMETRY_V1: 823 return xfs_ioc_fsgeometry_v1(mp, arg); 824 825 case XFS_IOC_FSGEOMETRY: 826 return xfs_ioc_fsgeometry(mp, arg); 827 828 case XFS_IOC_GETVERSION: 829 case XFS_IOC_GETXFLAGS: 830 case XFS_IOC_SETXFLAGS: 831 case XFS_IOC_FSGETXATTR: 832 case XFS_IOC_FSSETXATTR: 833 case XFS_IOC_FSGETXATTRA: 834 return xfs_ioc_xattr(vp, ip, filp, cmd, arg); 835 836 case XFS_IOC_FSSETDM: { 837 struct fsdmidata dmi; 838 839 if (copy_from_user(&dmi, arg, sizeof(dmi))) 840 return XFS_ERROR(EFAULT); 841 842 error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate, 843 NULL); 844 return error; 845 } 846 847 case XFS_IOC_GETBMAP: 848 case XFS_IOC_GETBMAPA: 849 return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg); 850 851 case XFS_IOC_GETBMAPX: 852 return xfs_ioc_getbmapx(bdp, arg); 853 854 case XFS_IOC_FD_TO_HANDLE: 855 case XFS_IOC_PATH_TO_HANDLE: 856 case XFS_IOC_PATH_TO_FSHANDLE: 857 return xfs_find_handle(cmd, arg); 858 859 case XFS_IOC_OPEN_BY_HANDLE: 860 return xfs_open_by_handle(mp, arg, filp, inode); 861 862 case XFS_IOC_FSSETDM_BY_HANDLE: 863 return xfs_fssetdm_by_handle(mp, arg, filp, inode); 864 865 case XFS_IOC_READLINK_BY_HANDLE: 866 return xfs_readlink_by_handle(mp, arg, filp, inode); 867 868 case XFS_IOC_ATTRLIST_BY_HANDLE: 869 return xfs_attrlist_by_handle(mp, arg, filp, inode); 870 871 case XFS_IOC_ATTRMULTI_BY_HANDLE: 872 return xfs_attrmulti_by_handle(mp, arg, filp, inode); 873 874 case XFS_IOC_SWAPEXT: { 875 error = xfs_swapext((struct xfs_swapext __user *)arg); 876 return error; 877 } 878 879 case XFS_IOC_FSCOUNTS: { 880 xfs_fsop_counts_t out; 881 882 error = xfs_fs_counts(mp, &out); 883 if (error) 884 return error; 885 886 if (copy_to_user(arg, &out, sizeof(out))) 887 return XFS_ERROR(EFAULT); 888 return 0; 889 } 890 891 case XFS_IOC_SET_RESBLKS: { 892 xfs_fsop_resblks_t inout; 893 __uint64_t in; 894 895 if (!capable(CAP_SYS_ADMIN)) 896 return EPERM; 897 898 if (copy_from_user(&inout, arg, sizeof(inout))) 899 return XFS_ERROR(EFAULT); 900 901 /* input parameter is passed in resblks field of structure */ 902 in = inout.resblks; 903 error = xfs_reserve_blocks(mp, &in, &inout); 904 if (error) 905 return error; 906 907 if (copy_to_user(arg, &inout, sizeof(inout))) 908 return XFS_ERROR(EFAULT); 909 return 0; 910 } 911 912 case XFS_IOC_GET_RESBLKS: { 913 xfs_fsop_resblks_t out; 914 915 if (!capable(CAP_SYS_ADMIN)) 916 return EPERM; 917 918 error = xfs_reserve_blocks(mp, NULL, &out); 919 if (error) 920 return error; 921 922 if (copy_to_user(arg, &out, sizeof(out))) 923 return XFS_ERROR(EFAULT); 924 925 return 0; 926 } 927 928 case XFS_IOC_FSGROWFSDATA: { 929 xfs_growfs_data_t in; 930 931 if (!capable(CAP_SYS_ADMIN)) 932 return EPERM; 933 934 if (copy_from_user(&in, arg, sizeof(in))) 935 return XFS_ERROR(EFAULT); 936 937 error = xfs_growfs_data(mp, &in); 938 return error; 939 } 940 941 case XFS_IOC_FSGROWFSLOG: { 942 xfs_growfs_log_t in; 943 944 if (!capable(CAP_SYS_ADMIN)) 945 return EPERM; 946 947 if (copy_from_user(&in, arg, sizeof(in))) 948 return XFS_ERROR(EFAULT); 949 950 error = xfs_growfs_log(mp, &in); 951 return error; 952 } 953 954 case XFS_IOC_FSGROWFSRT: { 955 xfs_growfs_rt_t in; 956 957 if (!capable(CAP_SYS_ADMIN)) 958 return EPERM; 959 960 if (copy_from_user(&in, arg, sizeof(in))) 961 return XFS_ERROR(EFAULT); 962 963 error = xfs_growfs_rt(mp, &in); 964 return error; 965 } 966#if 0 967 case XFS_IOC_FREEZE: 968 if (!capable(CAP_SYS_ADMIN)) 969 return -EPERM; 970 xfs_fs_freeze(mp); 971 return 0; 972 973 case XFS_IOC_THAW: 974 if (!capable(CAP_SYS_ADMIN)) 975 return -EPERM; 976 xfs_fs_thaw(mp); 977 return 0; 978#endif 979 980 case XFS_IOC_GOINGDOWN: { 981 __uint32_t in; 982 983 if (!capable(CAP_SYS_ADMIN)) 984 return EPERM; 985 986 if (copy_from_user(&in, arg, sizeof(__uint32_t))) 987 return XFS_ERROR(EFAULT); 988 989 error = xfs_fs_goingdown(mp, in); 990 return error; 991 } 992 993 case XFS_IOC_ERROR_INJECTION: { 994 xfs_error_injection_t in; 995 996 if (!capable(CAP_SYS_ADMIN)) 997 return EPERM; 998 999 if (copy_from_user(&in, arg, sizeof(in))) 1000 return XFS_ERROR(EFAULT); 1001 1002 error = xfs_errortag_add(in.errtag, mp); 1003 return error; 1004 } 1005 1006 case XFS_IOC_ERROR_CLEARALL: 1007 if (!capable(CAP_SYS_ADMIN)) 1008 return EPERM; 1009 1010 error = xfs_errortag_clearall(mp); 1011 return error; 1012 1013 default: 1014 return ENOTTY; 1015 } 1016} 1017 1018STATIC int 1019xfs_ioc_space( 1020 bhv_desc_t *bdp, 1021 xfs_vnode_t *vp, 1022 struct file *filp, 1023 int ioflags, 1024 unsigned int cmd, 1025 void __user *arg) 1026{ 1027 xfs_flock64_t bf; 1028 int attr_flags = 0; 1029 int error; 1030 1031#if 0 1032 if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) 1033 return -XFS_ERROR(EPERM); 1034 1035 if (!(filp->f_mode & FMODE_WRITE)) 1036 return -XFS_ERROR(EBADF); 1037#endif 1038 1039 if (!VN_ISREG(vp)) 1040 return -XFS_ERROR(EINVAL); 1041 1042 if (copy_from_user(&bf, arg, sizeof(bf))) 1043 return -XFS_ERROR(EFAULT); 1044 1045#if 0 1046 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1047 attr_flags |= ATTR_NONBLOCK; 1048#endif 1049 if (ioflags & IO_INVIS) 1050 attr_flags |= ATTR_DMI; 1051 1052 error = xfs_change_file_space(bdp, cmd, 1053 &bf, filp->f_offset, 1054 NULL, attr_flags); 1055 return -error; 1056} 1057 1058STATIC int 1059xfs_ioc_bulkstat( 1060 xfs_mount_t *mp, 1061 unsigned int cmd, 1062 void __user *arg) 1063{ 1064 xfs_fsop_bulkreq_t bulkreq; 1065 int count; /* # of records returned */ 1066 xfs_ino_t inlast; /* last inode number */ 1067 int done; 1068 int error; 1069 1070 /* done = 1 if there are more stats to get and if bulkstat */ 1071 /* should be called again (unused here, but used in dmapi) */ 1072 1073#if 0 1074 if (!capable(CAP_SYS_ADMIN)) 1075 return -EPERM; 1076#endif 1077 1078 if (XFS_FORCED_SHUTDOWN(mp)) 1079 return -XFS_ERROR(EIO); 1080 1081 if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) 1082 return -XFS_ERROR(EFAULT); 1083 1084 if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) 1085 return -XFS_ERROR(EFAULT); 1086 1087 if ((count = bulkreq.icount) <= 0) 1088 return -XFS_ERROR(EINVAL); 1089 1090 if (cmd == XFS_IOC_FSINUMBERS) 1091 error = xfs_inumbers(mp, &inlast, &count, 1092 bulkreq.ubuffer); 1093 else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) 1094 error = xfs_bulkstat_single(mp, &inlast, 1095 bulkreq.ubuffer, &done); 1096 else { /* XFS_IOC_FSBULKSTAT */ 1097 if (count == 1 && inlast != 0) { 1098 inlast++; 1099 error = xfs_bulkstat_single(mp, &inlast, 1100 bulkreq.ubuffer, &done); 1101 } else { 1102 error = xfs_bulkstat(mp, &inlast, &count, 1103 (bulkstat_one_pf)xfs_bulkstat_one, NULL, 1104 sizeof(xfs_bstat_t), bulkreq.ubuffer, 1105 BULKSTAT_FG_QUICK, &done); 1106 } 1107 } 1108 1109 if (error) 1110 return -error; 1111 1112 if (bulkreq.ocount != NULL) { 1113 if (copy_to_user(bulkreq.lastip, &inlast, 1114 sizeof(xfs_ino_t))) 1115 return -XFS_ERROR(EFAULT); 1116 1117 if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) 1118 return -XFS_ERROR(EFAULT); 1119 } 1120 1121 return 0; 1122} 1123 1124STATIC int 1125xfs_ioc_fsgeometry_v1( 1126 xfs_mount_t *mp, 1127 void __user *arg) 1128{ 1129 xfs_fsop_geom_v1_t fsgeo; 1130 int error; 1131 1132 error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3); 1133 if (error) 1134 return -error; 1135 1136 if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) 1137 return -XFS_ERROR(EFAULT); 1138 return 0; 1139} 1140 1141STATIC int 1142xfs_ioc_fsgeometry( 1143 xfs_mount_t *mp, 1144 void __user *arg) 1145{ 1146 xfs_fsop_geom_t fsgeo; 1147 int error; 1148 1149 error = xfs_fs_geometry(mp, &fsgeo, 4); 1150 if (error) 1151 goto error; 1152 1153 printf ("xfs_ioc_fsgeometry: error? %d arg %p\n",error,arg); 1154 1155#if 0 1156 if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) 1157 return XFS_ERROR(EFAULT); 1158#endif 1159 memcpy(arg, &fsgeo, sizeof(fsgeo)); 1160 1161 printf ("xfs_ioc_fsgeometry: error? %d arg %p\n",error,arg); 1162error: 1163 return error; 1164} 1165 1166/* 1167 * Linux extended inode flags interface. 1168 */ 1169#define LINUX_XFLAG_SYNC 0x00000008 /* Synchronous updates */ 1170#define LINUX_XFLAG_IMMUTABLE 0x00000010 /* Immutable file */ 1171#define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */ 1172#define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */ 1173#define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */ 1174 1175STATIC unsigned int 1176xfs_merge_ioc_xflags( 1177 unsigned int flags, 1178 unsigned int start) 1179{ 1180 unsigned int xflags = start; 1181 1182 if (flags & LINUX_XFLAG_IMMUTABLE) 1183 xflags |= XFS_XFLAG_IMMUTABLE; 1184 else 1185 xflags &= ~XFS_XFLAG_IMMUTABLE; 1186 if (flags & LINUX_XFLAG_APPEND) 1187 xflags |= XFS_XFLAG_APPEND; 1188 else 1189 xflags &= ~XFS_XFLAG_APPEND; 1190 if (flags & LINUX_XFLAG_SYNC) 1191 xflags |= XFS_XFLAG_SYNC; 1192 else 1193 xflags &= ~XFS_XFLAG_SYNC; 1194 if (flags & LINUX_XFLAG_NOATIME) 1195 xflags |= XFS_XFLAG_NOATIME; 1196 else 1197 xflags &= ~XFS_XFLAG_NOATIME; 1198 if (flags & LINUX_XFLAG_NODUMP) 1199 xflags |= XFS_XFLAG_NODUMP; 1200 else 1201 xflags &= ~XFS_XFLAG_NODUMP; 1202 1203 return xflags; 1204} 1205 1206STATIC unsigned int 1207xfs_di2lxflags( 1208 __uint16_t di_flags) 1209{ 1210 unsigned int flags = 0; 1211 1212 if (di_flags & XFS_DIFLAG_IMMUTABLE) 1213 flags |= LINUX_XFLAG_IMMUTABLE; 1214 if (di_flags & XFS_DIFLAG_APPEND) 1215 flags |= LINUX_XFLAG_APPEND; 1216 if (di_flags & XFS_DIFLAG_SYNC) 1217 flags |= LINUX_XFLAG_SYNC; 1218 if (di_flags & XFS_DIFLAG_NOATIME) 1219 flags |= LINUX_XFLAG_NOATIME; 1220 if (di_flags & XFS_DIFLAG_NODUMP) 1221 flags |= LINUX_XFLAG_NODUMP; 1222 return flags; 1223} 1224 1225STATIC int 1226xfs_ioc_xattr( 1227 xfs_vnode_t *vp, 1228 xfs_inode_t *ip, 1229 struct file *filp, 1230 unsigned int cmd, 1231 void __user *arg) 1232{ 1233 struct fsxattr fa; 1234 struct xfs_vattr *vattr; 1235 int error; 1236 int attr_flags; 1237 unsigned int flags; 1238 1239 error = 0; 1240 attr_flags = 0; 1241 1242 vattr = kmem_alloc(sizeof(struct xfs_vattr), KM_SLEEP); 1243 if (unlikely(!vattr)) 1244 return ENOMEM; 1245 1246 switch (cmd) { 1247 case XFS_IOC_FSGETXATTR: { 1248 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ 1249 XFS_AT_NEXTENTS | XFS_AT_PROJID; 1250 XVOP_GETATTR(vp, vattr, 0, NULL, error); 1251 if (unlikely(error)) { 1252 error = error; 1253 break; 1254 } 1255 1256 fa.fsx_xflags = vattr->va_xflags; 1257 fa.fsx_extsize = vattr->va_extsize; 1258 fa.fsx_nextents = vattr->va_nextents; 1259 fa.fsx_projid = vattr->va_projid; 1260 1261 if (copy_to_user(arg, &fa, sizeof(fa))) { 1262 error = EFAULT; 1263 break; 1264 } 1265 break; 1266 } 1267 1268 case XFS_IOC_FSSETXATTR: { 1269 if (copy_from_user(&fa, arg, sizeof(fa))) { 1270 error = EFAULT; 1271 break; 1272 } 1273 1274 attr_flags = 0; 1275#if 0 1276 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1277 attr_flags |= ATTR_NONBLOCK; 1278#endif 1279 1280 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; 1281 vattr->va_xflags = fa.fsx_xflags; 1282 vattr->va_extsize = fa.fsx_extsize; 1283 vattr->va_projid = fa.fsx_projid; 1284 1285 XVOP_SETATTR(vp, vattr, attr_flags, NULL, error); 1286#if 0 1287 if (likely(!error)) 1288 __vn_revalidate(vp, vattr); /* update flags */ 1289#endif 1290 error = error; 1291 break; 1292 } 1293 1294 case XFS_IOC_FSGETXATTRA: { 1295 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ 1296 XFS_AT_ANEXTENTS | XFS_AT_PROJID; 1297 XVOP_GETATTR(vp, vattr, 0, NULL, error); 1298 if (unlikely(error)) { 1299 error = error; 1300 break; 1301 } 1302 1303 fa.fsx_xflags = vattr->va_xflags; 1304 fa.fsx_extsize = vattr->va_extsize; 1305 fa.fsx_nextents = vattr->va_anextents; 1306 fa.fsx_projid = vattr->va_projid; 1307 1308 if (copy_to_user(arg, &fa, sizeof(fa))) { 1309 error = EFAULT; 1310 break; 1311 } 1312 break; 1313 } 1314 1315 case XFS_IOC_GETXFLAGS: { 1316 flags = xfs_di2lxflags(ip->i_d.di_flags); 1317 if (copy_to_user(arg, &flags, sizeof(flags))) 1318 error = EFAULT; 1319 break; 1320 } 1321 1322 case XFS_IOC_SETXFLAGS: { 1323 if (copy_from_user(&flags, arg, sizeof(flags))) { 1324 error = EFAULT; 1325 break; 1326 } 1327 1328 if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ 1329 LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ 1330 LINUX_XFLAG_SYNC)) { 1331 error = EOPNOTSUPP; 1332 break; 1333 } 1334 1335#if 0 1336 attr_flags = 0; 1337 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1338 attr_flags |= ATTR_NONBLOCK; 1339#endif 1340 1341 vattr->va_mask = XFS_AT_XFLAGS; 1342 vattr->va_xflags = xfs_merge_ioc_xflags(flags, 1343 xfs_ip2xflags(ip)); 1344 1345 XVOP_SETATTR(vp, vattr, attr_flags, NULL, error); 1346#if 0 1347 if (likely(!error)) 1348 __vn_revalidate(vp, vattr); /* update flags */ 1349#endif 1350 error = error; 1351 break; 1352 } 1353 1354#if 0 1355 case XFS_IOC_GETVERSION: { 1356 flags = vn_to_inode(vp)->i_generation; 1357 if (copy_to_user(arg, &flags, sizeof(flags))) 1358 error = EFAULT; 1359 break; 1360 } 1361#endif 1362 1363 default: 1364 error = ENOTTY; 1365 break; 1366 } 1367 1368 kmem_free(vattr,sizeof(struct xfs_vattr)); 1369 return error; 1370} 1371 1372STATIC int 1373xfs_ioc_getbmap( 1374 bhv_desc_t *bdp, 1375 struct file *filp, 1376 int ioflags, 1377 unsigned int cmd, 1378 void __user *arg) 1379{ 1380 struct getbmap bm; 1381 int iflags; 1382 int error; 1383 1384 if (copy_from_user(&bm, arg, sizeof(bm))) 1385 return -XFS_ERROR(EFAULT); 1386 1387 if (bm.bmv_count < 2) 1388 return -XFS_ERROR(EINVAL); 1389 1390 iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); 1391 if (ioflags & IO_INVIS) 1392 iflags |= BMV_IF_NO_DMAPI_READ; 1393 1394 error = xfs_getbmap(bdp, &bm, (struct getbmap __user *)arg+1, iflags); 1395 if (error) 1396 return -error; 1397 1398 if (copy_to_user(arg, &bm, sizeof(bm))) 1399 return -XFS_ERROR(EFAULT); 1400 return 0; 1401} 1402 1403STATIC int 1404xfs_ioc_getbmapx( 1405 bhv_desc_t *bdp, 1406 void __user *arg) 1407{ 1408 struct getbmapx bmx; 1409 struct getbmap bm; 1410 int iflags; 1411 int error; 1412 1413 printf("%s:%d\n",__FILE__,__LINE__); 1414 if (copy_from_user(&bmx, arg, sizeof(bmx))) 1415 return XFS_ERROR(EFAULT); 1416 1417 printf("%s:%d\n",__FILE__,__LINE__); 1418 if (bmx.bmv_count < 2) 1419 return XFS_ERROR(EINVAL); 1420 1421 /* 1422 * Map input getbmapx structure to a getbmap 1423 * structure for xfs_getbmap. 1424 */ 1425 GETBMAP_CONVERT(bmx, bm); 1426 1427 iflags = bmx.bmv_iflags; 1428 1429 if (iflags & (~BMV_IF_VALID)) 1430 return XFS_ERROR(EINVAL); 1431 1432 iflags |= BMV_IF_EXTENDED; 1433 1434 printf("%s:%d arg+1 %p arg %p\n",__FILE__,__LINE__,(struct getbmapx __user *)arg+1,arg); 1435 error = xfs_getbmap(bdp, &bm, (struct getbmapx __user *)arg+1, iflags); 1436 if (error) 1437 return error; 1438 1439 printf("%s:%d\n",__FILE__,__LINE__); 1440 GETBMAP_CONVERT(bm, bmx); 1441 1442 printf("%s:%d\n",__FILE__,__LINE__); 1443 if (copy_to_user(arg, &bmx, sizeof(bmx))) 1444 return XFS_ERROR(EFAULT); 1445 1446 printf("%s:%d\n",__FILE__,__LINE__); 1447 return 0; 1448} 1449 1450#else 1451 1452int 1453xfs_ioctl( 1454 bhv_desc_t *bdp, 1455 struct inode *inode, 1456 struct file *filp, 1457 int ioflags, 1458 unsigned int cmd, 1459 unsigned long arg) 1460{ 1461 return EINVAL; 1462} 1463 1464#endif 1465