1 /* 2 * Copyright (c) 2004-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 <linux/compat.h> 19 #include <linux/ioctl.h> 20 #include <linux/mount.h> 21 #include <linux/slab.h> 22 #include <asm/uaccess.h> 23 #include "xfs.h" 24 #include "xfs_fs.h" 25 #include "xfs_bit.h" 26 #include "xfs_log.h" 27 #include "xfs_inum.h" 28 #include "xfs_trans.h" 29 #include "xfs_sb.h" 30 #include "xfs_ag.h" 31 #include "xfs_mount.h" 32 #include "xfs_bmap_btree.h" 33 #include "xfs_vnode.h" 34 #include "xfs_dinode.h" 35 #include "xfs_inode.h" 36 #include "xfs_itable.h" 37 #include "xfs_error.h" 38 #include "xfs_dfrag.h" 39 #include "xfs_vnodeops.h" 40 #include "xfs_fsops.h" 41 #include "xfs_alloc.h" 42 #include "xfs_rtalloc.h" 43 #include "xfs_attr.h" 44 #include "xfs_ioctl.h" 45 #include "xfs_ioctl32.h" 46 #include "xfs_trace.h" 47 48 #define _NATIVE_IOC(cmd, type) \ 49 _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) 50 51 #ifdef BROKEN_X86_ALIGNMENT 52 STATIC int 53 xfs_compat_flock64_copyin( 54 xfs_flock64_t *bf, 55 compat_xfs_flock64_t __user *arg32) 56 { 57 if (get_user(bf->l_type, &arg32->l_type) || 58 get_user(bf->l_whence, &arg32->l_whence) || 59 get_user(bf->l_start, &arg32->l_start) || 60 get_user(bf->l_len, &arg32->l_len) || 61 get_user(bf->l_sysid, &arg32->l_sysid) || 62 get_user(bf->l_pid, &arg32->l_pid) || 63 copy_from_user(bf->l_pad, &arg32->l_pad, 4*sizeof(u32))) 64 return -XFS_ERROR(EFAULT); 65 return 0; 66 } 67 68 STATIC int 69 xfs_compat_ioc_fsgeometry_v1( 70 struct xfs_mount *mp, 71 compat_xfs_fsop_geom_v1_t __user *arg32) 72 { 73 xfs_fsop_geom_t fsgeo; 74 int error; 75 76 error = xfs_fs_geometry(mp, &fsgeo, 3); 77 if (error) 78 return -error; 79 /* The 32-bit variant simply has some padding at the end */ 80 if (copy_to_user(arg32, &fsgeo, sizeof(struct compat_xfs_fsop_geom_v1))) 81 return -XFS_ERROR(EFAULT); 82 return 0; 83 } 84 85 STATIC int 86 xfs_compat_growfs_data_copyin( 87 struct xfs_growfs_data *in, 88 compat_xfs_growfs_data_t __user *arg32) 89 { 90 if (get_user(in->newblocks, &arg32->newblocks) || 91 get_user(in->imaxpct, &arg32->imaxpct)) 92 return -XFS_ERROR(EFAULT); 93 return 0; 94 } 95 96 STATIC int 97 xfs_compat_growfs_rt_copyin( 98 struct xfs_growfs_rt *in, 99 compat_xfs_growfs_rt_t __user *arg32) 100 { 101 if (get_user(in->newblocks, &arg32->newblocks) || 102 get_user(in->extsize, &arg32->extsize)) 103 return -XFS_ERROR(EFAULT); 104 return 0; 105 } 106 107 STATIC int 108 xfs_inumbers_fmt_compat( 109 void __user *ubuffer, 110 const xfs_inogrp_t *buffer, 111 long count, 112 long *written) 113 { 114 compat_xfs_inogrp_t __user *p32 = ubuffer; 115 long i; 116 117 for (i = 0; i < count; i++) { 118 if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || 119 put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || 120 put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) 121 return -XFS_ERROR(EFAULT); 122 } 123 *written = count * sizeof(*p32); 124 return 0; 125 } 126 127 #else 128 #define xfs_inumbers_fmt_compat xfs_inumbers_fmt 129 #endif /* BROKEN_X86_ALIGNMENT */ 130 131 STATIC int 132 xfs_ioctl32_bstime_copyin( 133 xfs_bstime_t *bstime, 134 compat_xfs_bstime_t __user *bstime32) 135 { 136 compat_time_t sec32; /* tv_sec differs on 64 vs. 32 */ 137 138 if (get_user(sec32, &bstime32->tv_sec) || 139 get_user(bstime->tv_nsec, &bstime32->tv_nsec)) 140 return -XFS_ERROR(EFAULT); 141 bstime->tv_sec = sec32; 142 return 0; 143 } 144 145 /* xfs_bstat_t has differing alignment on intel, & bstime_t sizes everywhere */ 146 STATIC int 147 xfs_ioctl32_bstat_copyin( 148 xfs_bstat_t *bstat, 149 compat_xfs_bstat_t __user *bstat32) 150 { 151 if (get_user(bstat->bs_ino, &bstat32->bs_ino) || 152 get_user(bstat->bs_mode, &bstat32->bs_mode) || 153 get_user(bstat->bs_nlink, &bstat32->bs_nlink) || 154 get_user(bstat->bs_uid, &bstat32->bs_uid) || 155 get_user(bstat->bs_gid, &bstat32->bs_gid) || 156 get_user(bstat->bs_rdev, &bstat32->bs_rdev) || 157 get_user(bstat->bs_blksize, &bstat32->bs_blksize) || 158 get_user(bstat->bs_size, &bstat32->bs_size) || 159 xfs_ioctl32_bstime_copyin(&bstat->bs_atime, &bstat32->bs_atime) || 160 xfs_ioctl32_bstime_copyin(&bstat->bs_mtime, &bstat32->bs_mtime) || 161 xfs_ioctl32_bstime_copyin(&bstat->bs_ctime, &bstat32->bs_ctime) || 162 get_user(bstat->bs_blocks, &bstat32->bs_size) || 163 get_user(bstat->bs_xflags, &bstat32->bs_size) || 164 get_user(bstat->bs_extsize, &bstat32->bs_extsize) || 165 get_user(bstat->bs_extents, &bstat32->bs_extents) || 166 get_user(bstat->bs_gen, &bstat32->bs_gen) || 167 get_user(bstat->bs_projid_lo, &bstat32->bs_projid_lo) || 168 get_user(bstat->bs_projid_hi, &bstat32->bs_projid_hi) || 169 get_user(bstat->bs_dmevmask, &bstat32->bs_dmevmask) || 170 get_user(bstat->bs_dmstate, &bstat32->bs_dmstate) || 171 get_user(bstat->bs_aextents, &bstat32->bs_aextents)) 172 return -XFS_ERROR(EFAULT); 173 return 0; 174 } 175 176 /* XFS_IOC_FSBULKSTAT and friends */ 177 178 STATIC int 179 xfs_bstime_store_compat( 180 compat_xfs_bstime_t __user *p32, 181 const xfs_bstime_t *p) 182 { 183 __s32 sec32; 184 185 sec32 = p->tv_sec; 186 if (put_user(sec32, &p32->tv_sec) || 187 put_user(p->tv_nsec, &p32->tv_nsec)) 188 return -XFS_ERROR(EFAULT); 189 return 0; 190 } 191 192 /* Return 0 on success or positive error (to xfs_bulkstat()) */ 193 STATIC int 194 xfs_bulkstat_one_fmt_compat( 195 void __user *ubuffer, 196 int ubsize, 197 int *ubused, 198 const xfs_bstat_t *buffer) 199 { 200 compat_xfs_bstat_t __user *p32 = ubuffer; 201 202 if (ubsize < sizeof(*p32)) 203 return XFS_ERROR(ENOMEM); 204 205 if (put_user(buffer->bs_ino, &p32->bs_ino) || 206 put_user(buffer->bs_mode, &p32->bs_mode) || 207 put_user(buffer->bs_nlink, &p32->bs_nlink) || 208 put_user(buffer->bs_uid, &p32->bs_uid) || 209 put_user(buffer->bs_gid, &p32->bs_gid) || 210 put_user(buffer->bs_rdev, &p32->bs_rdev) || 211 put_user(buffer->bs_blksize, &p32->bs_blksize) || 212 put_user(buffer->bs_size, &p32->bs_size) || 213 xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) || 214 xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) || 215 xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) || 216 put_user(buffer->bs_blocks, &p32->bs_blocks) || 217 put_user(buffer->bs_xflags, &p32->bs_xflags) || 218 put_user(buffer->bs_extsize, &p32->bs_extsize) || 219 put_user(buffer->bs_extents, &p32->bs_extents) || 220 put_user(buffer->bs_gen, &p32->bs_gen) || 221 put_user(buffer->bs_projid, &p32->bs_projid) || 222 put_user(buffer->bs_projid_hi, &p32->bs_projid_hi) || 223 put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) || 224 put_user(buffer->bs_dmstate, &p32->bs_dmstate) || 225 put_user(buffer->bs_aextents, &p32->bs_aextents)) 226 return XFS_ERROR(EFAULT); 227 if (ubused) 228 *ubused = sizeof(*p32); 229 return 0; 230 } 231 232 STATIC int 233 xfs_bulkstat_one_compat( 234 xfs_mount_t *mp, /* mount point for filesystem */ 235 xfs_ino_t ino, /* inode number to get data for */ 236 void __user *buffer, /* buffer to place output in */ 237 int ubsize, /* size of buffer */ 238 int *ubused, /* bytes used by me */ 239 int *stat) /* BULKSTAT_RV_... */ 240 { 241 return xfs_bulkstat_one_int(mp, ino, buffer, ubsize, 242 xfs_bulkstat_one_fmt_compat, 243 ubused, stat); 244 } 245 246 /* copied from xfs_ioctl.c */ 247 STATIC int 248 xfs_compat_ioc_bulkstat( 249 xfs_mount_t *mp, 250 unsigned int cmd, 251 compat_xfs_fsop_bulkreq_t __user *p32) 252 { 253 u32 addr; 254 xfs_fsop_bulkreq_t bulkreq; 255 int count; /* # of records returned */ 256 xfs_ino_t inlast; /* last inode number */ 257 int done; 258 int error; 259 260 /* done = 1 if there are more stats to get and if bulkstat */ 261 /* should be called again (unused here, but used in dmapi) */ 262 263 if (!capable(CAP_SYS_ADMIN)) 264 return -XFS_ERROR(EPERM); 265 266 if (XFS_FORCED_SHUTDOWN(mp)) 267 return -XFS_ERROR(EIO); 268 269 if (get_user(addr, &p32->lastip)) 270 return -XFS_ERROR(EFAULT); 271 bulkreq.lastip = compat_ptr(addr); 272 if (get_user(bulkreq.icount, &p32->icount) || 273 get_user(addr, &p32->ubuffer)) 274 return -XFS_ERROR(EFAULT); 275 bulkreq.ubuffer = compat_ptr(addr); 276 if (get_user(addr, &p32->ocount)) 277 return -XFS_ERROR(EFAULT); 278 bulkreq.ocount = compat_ptr(addr); 279 280 if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) 281 return -XFS_ERROR(EFAULT); 282 283 if ((count = bulkreq.icount) <= 0) 284 return -XFS_ERROR(EINVAL); 285 286 if (bulkreq.ubuffer == NULL) 287 return -XFS_ERROR(EINVAL); 288 289 if (cmd == XFS_IOC_FSINUMBERS_32) { 290 error = xfs_inumbers(mp, &inlast, &count, 291 bulkreq.ubuffer, xfs_inumbers_fmt_compat); 292 } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) { 293 int res; 294 295 error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer, 296 sizeof(compat_xfs_bstat_t), NULL, &res); 297 } else if (cmd == XFS_IOC_FSBULKSTAT_32) { 298 error = xfs_bulkstat(mp, &inlast, &count, 299 xfs_bulkstat_one_compat, sizeof(compat_xfs_bstat_t), 300 bulkreq.ubuffer, &done); 301 } else 302 error = XFS_ERROR(EINVAL); 303 if (error) 304 return -error; 305 306 if (bulkreq.ocount != NULL) { 307 if (copy_to_user(bulkreq.lastip, &inlast, 308 sizeof(xfs_ino_t))) 309 return -XFS_ERROR(EFAULT); 310 311 if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) 312 return -XFS_ERROR(EFAULT); 313 } 314 315 return 0; 316 } 317 318 STATIC int 319 xfs_compat_handlereq_copyin( 320 xfs_fsop_handlereq_t *hreq, 321 compat_xfs_fsop_handlereq_t __user *arg32) 322 { 323 compat_xfs_fsop_handlereq_t hreq32; 324 325 if (copy_from_user(&hreq32, arg32, sizeof(compat_xfs_fsop_handlereq_t))) 326 return -XFS_ERROR(EFAULT); 327 328 hreq->fd = hreq32.fd; 329 hreq->path = compat_ptr(hreq32.path); 330 hreq->oflags = hreq32.oflags; 331 hreq->ihandle = compat_ptr(hreq32.ihandle); 332 hreq->ihandlen = hreq32.ihandlen; 333 hreq->ohandle = compat_ptr(hreq32.ohandle); 334 hreq->ohandlen = compat_ptr(hreq32.ohandlen); 335 336 return 0; 337 } 338 339 STATIC struct dentry * 340 xfs_compat_handlereq_to_dentry( 341 struct file *parfilp, 342 compat_xfs_fsop_handlereq_t *hreq) 343 { 344 return xfs_handle_to_dentry(parfilp, 345 compat_ptr(hreq->ihandle), hreq->ihandlen); 346 } 347 348 STATIC int 349 xfs_compat_attrlist_by_handle( 350 struct file *parfilp, 351 void __user *arg) 352 { 353 int error; 354 attrlist_cursor_kern_t *cursor; 355 compat_xfs_fsop_attrlist_handlereq_t al_hreq; 356 struct dentry *dentry; 357 char *kbuf; 358 359 if (!capable(CAP_SYS_ADMIN)) 360 return -XFS_ERROR(EPERM); 361 if (copy_from_user(&al_hreq, arg, 362 sizeof(compat_xfs_fsop_attrlist_handlereq_t))) 363 return -XFS_ERROR(EFAULT); 364 if (al_hreq.buflen > XATTR_LIST_MAX) 365 return -XFS_ERROR(EINVAL); 366 367 /* 368 * Reject flags, only allow namespaces. 369 */ 370 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) 371 return -XFS_ERROR(EINVAL); 372 373 dentry = xfs_compat_handlereq_to_dentry(parfilp, &al_hreq.hreq); 374 if (IS_ERR(dentry)) 375 return PTR_ERR(dentry); 376 377 error = -ENOMEM; 378 kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); 379 if (!kbuf) 380 goto out_dput; 381 382 cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; 383 error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, 384 al_hreq.flags, cursor); 385 if (error) 386 goto out_kfree; 387 388 if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen)) 389 error = -EFAULT; 390 391 out_kfree: 392 kfree(kbuf); 393 out_dput: 394 dput(dentry); 395 return error; 396 } 397 398 STATIC int 399 xfs_compat_attrmulti_by_handle( 400 struct file *parfilp, 401 void __user *arg) 402 { 403 int error; 404 compat_xfs_attr_multiop_t *ops; 405 compat_xfs_fsop_attrmulti_handlereq_t am_hreq; 406 struct dentry *dentry; 407 unsigned int i, size; 408 unsigned char *attr_name; 409 410 if (!capable(CAP_SYS_ADMIN)) 411 return -XFS_ERROR(EPERM); 412 if (copy_from_user(&am_hreq, arg, 413 sizeof(compat_xfs_fsop_attrmulti_handlereq_t))) 414 return -XFS_ERROR(EFAULT); 415 416 /* overflow check */ 417 if (am_hreq.opcount >= INT_MAX / sizeof(compat_xfs_attr_multiop_t)) 418 return -E2BIG; 419 420 dentry = xfs_compat_handlereq_to_dentry(parfilp, &am_hreq.hreq); 421 if (IS_ERR(dentry)) 422 return PTR_ERR(dentry); 423 424 error = E2BIG; 425 size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t); 426 if (!size || size > 16 * PAGE_SIZE) 427 goto out_dput; 428 429 ops = memdup_user(compat_ptr(am_hreq.ops), size); 430 if (IS_ERR(ops)) { 431 error = PTR_ERR(ops); 432 goto out_dput; 433 } 434 435 attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL); 436 if (!attr_name) 437 goto out_kfree_ops; 438 439 error = 0; 440 for (i = 0; i < am_hreq.opcount; i++) { 441 ops[i].am_error = strncpy_from_user((char *)attr_name, 442 compat_ptr(ops[i].am_attrname), 443 MAXNAMELEN); 444 if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) 445 error = -ERANGE; 446 if (ops[i].am_error < 0) 447 break; 448 449 switch (ops[i].am_opcode) { 450 case ATTR_OP_GET: 451 ops[i].am_error = xfs_attrmulti_attr_get( 452 dentry->d_inode, attr_name, 453 compat_ptr(ops[i].am_attrvalue), 454 &ops[i].am_length, ops[i].am_flags); 455 break; 456 case ATTR_OP_SET: 457 ops[i].am_error = mnt_want_write_file(parfilp); 458 if (ops[i].am_error) 459 break; 460 ops[i].am_error = xfs_attrmulti_attr_set( 461 dentry->d_inode, attr_name, 462 compat_ptr(ops[i].am_attrvalue), 463 ops[i].am_length, ops[i].am_flags); 464 mnt_drop_write_file(parfilp); 465 break; 466 case ATTR_OP_REMOVE: 467 ops[i].am_error = mnt_want_write_file(parfilp); 468 if (ops[i].am_error) 469 break; 470 ops[i].am_error = xfs_attrmulti_attr_remove( 471 dentry->d_inode, attr_name, 472 ops[i].am_flags); 473 mnt_drop_write_file(parfilp); 474 break; 475 default: 476 ops[i].am_error = EINVAL; 477 } 478 } 479 480 if (copy_to_user(compat_ptr(am_hreq.ops), ops, size)) 481 error = XFS_ERROR(EFAULT); 482 483 kfree(attr_name); 484 out_kfree_ops: 485 kfree(ops); 486 out_dput: 487 dput(dentry); 488 return -error; 489 } 490 491 STATIC int 492 xfs_compat_fssetdm_by_handle( 493 struct file *parfilp, 494 void __user *arg) 495 { 496 int error; 497 struct fsdmidata fsd; 498 compat_xfs_fsop_setdm_handlereq_t dmhreq; 499 struct dentry *dentry; 500 501 if (!capable(CAP_MKNOD)) 502 return -XFS_ERROR(EPERM); 503 if (copy_from_user(&dmhreq, arg, 504 sizeof(compat_xfs_fsop_setdm_handlereq_t))) 505 return -XFS_ERROR(EFAULT); 506 507 dentry = xfs_compat_handlereq_to_dentry(parfilp, &dmhreq.hreq); 508 if (IS_ERR(dentry)) 509 return PTR_ERR(dentry); 510 511 if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { 512 error = -XFS_ERROR(EPERM); 513 goto out; 514 } 515 516 if (copy_from_user(&fsd, compat_ptr(dmhreq.data), sizeof(fsd))) { 517 error = -XFS_ERROR(EFAULT); 518 goto out; 519 } 520 521 error = -xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask, 522 fsd.fsd_dmstate); 523 524 out: 525 dput(dentry); 526 return error; 527 } 528 529 long 530 xfs_file_compat_ioctl( 531 struct file *filp, 532 unsigned cmd, 533 unsigned long p) 534 { 535 struct inode *inode = filp->f_path.dentry->d_inode; 536 struct xfs_inode *ip = XFS_I(inode); 537 struct xfs_mount *mp = ip->i_mount; 538 void __user *arg = (void __user *)p; 539 int ioflags = 0; 540 int error; 541 542 if (filp->f_mode & FMODE_NOCMTIME) 543 ioflags |= IO_INVIS; 544 545 trace_xfs_file_compat_ioctl(ip); 546 547 switch (cmd) { 548 /* No size or alignment issues on any arch */ 549 case XFS_IOC_DIOINFO: 550 case XFS_IOC_FSGEOMETRY: 551 case XFS_IOC_FSGETXATTR: 552 case XFS_IOC_FSSETXATTR: 553 case XFS_IOC_FSGETXATTRA: 554 case XFS_IOC_FSSETDM: 555 case XFS_IOC_GETBMAP: 556 case XFS_IOC_GETBMAPA: 557 case XFS_IOC_GETBMAPX: 558 case XFS_IOC_FSCOUNTS: 559 case XFS_IOC_SET_RESBLKS: 560 case XFS_IOC_GET_RESBLKS: 561 case XFS_IOC_FSGROWFSLOG: 562 case XFS_IOC_GOINGDOWN: 563 case XFS_IOC_ERROR_INJECTION: 564 case XFS_IOC_ERROR_CLEARALL: 565 return xfs_file_ioctl(filp, cmd, p); 566 #ifndef BROKEN_X86_ALIGNMENT 567 /* These are handled fine if no alignment issues */ 568 case XFS_IOC_ALLOCSP: 569 case XFS_IOC_FREESP: 570 case XFS_IOC_RESVSP: 571 case XFS_IOC_UNRESVSP: 572 case XFS_IOC_ALLOCSP64: 573 case XFS_IOC_FREESP64: 574 case XFS_IOC_RESVSP64: 575 case XFS_IOC_UNRESVSP64: 576 case XFS_IOC_FSGEOMETRY_V1: 577 case XFS_IOC_FSGROWFSDATA: 578 case XFS_IOC_FSGROWFSRT: 579 case XFS_IOC_ZERO_RANGE: 580 return xfs_file_ioctl(filp, cmd, p); 581 #else 582 case XFS_IOC_ALLOCSP_32: 583 case XFS_IOC_FREESP_32: 584 case XFS_IOC_ALLOCSP64_32: 585 case XFS_IOC_FREESP64_32: 586 case XFS_IOC_RESVSP_32: 587 case XFS_IOC_UNRESVSP_32: 588 case XFS_IOC_RESVSP64_32: 589 case XFS_IOC_UNRESVSP64_32: 590 case XFS_IOC_ZERO_RANGE_32: { 591 struct xfs_flock64 bf; 592 593 if (xfs_compat_flock64_copyin(&bf, arg)) 594 return -XFS_ERROR(EFAULT); 595 cmd = _NATIVE_IOC(cmd, struct xfs_flock64); 596 return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf); 597 } 598 case XFS_IOC_FSGEOMETRY_V1_32: 599 return xfs_compat_ioc_fsgeometry_v1(mp, arg); 600 case XFS_IOC_FSGROWFSDATA_32: { 601 struct xfs_growfs_data in; 602 603 if (xfs_compat_growfs_data_copyin(&in, arg)) 604 return -XFS_ERROR(EFAULT); 605 error = xfs_growfs_data(mp, &in); 606 return -error; 607 } 608 case XFS_IOC_FSGROWFSRT_32: { 609 struct xfs_growfs_rt in; 610 611 if (xfs_compat_growfs_rt_copyin(&in, arg)) 612 return -XFS_ERROR(EFAULT); 613 error = xfs_growfs_rt(mp, &in); 614 return -error; 615 } 616 #endif 617 /* long changes size, but xfs only copiese out 32 bits */ 618 case XFS_IOC_GETXFLAGS_32: 619 case XFS_IOC_SETXFLAGS_32: 620 case XFS_IOC_GETVERSION_32: 621 cmd = _NATIVE_IOC(cmd, long); 622 return xfs_file_ioctl(filp, cmd, p); 623 case XFS_IOC_SWAPEXT_32: { 624 struct xfs_swapext sxp; 625 struct compat_xfs_swapext __user *sxu = arg; 626 627 /* Bulk copy in up to the sx_stat field, then copy bstat */ 628 if (copy_from_user(&sxp, sxu, 629 offsetof(struct xfs_swapext, sx_stat)) || 630 xfs_ioctl32_bstat_copyin(&sxp.sx_stat, &sxu->sx_stat)) 631 return -XFS_ERROR(EFAULT); 632 error = xfs_swapext(&sxp); 633 return -error; 634 } 635 case XFS_IOC_FSBULKSTAT_32: 636 case XFS_IOC_FSBULKSTAT_SINGLE_32: 637 case XFS_IOC_FSINUMBERS_32: 638 return xfs_compat_ioc_bulkstat(mp, cmd, arg); 639 case XFS_IOC_FD_TO_HANDLE_32: 640 case XFS_IOC_PATH_TO_HANDLE_32: 641 case XFS_IOC_PATH_TO_FSHANDLE_32: { 642 struct xfs_fsop_handlereq hreq; 643 644 if (xfs_compat_handlereq_copyin(&hreq, arg)) 645 return -XFS_ERROR(EFAULT); 646 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq); 647 return xfs_find_handle(cmd, &hreq); 648 } 649 case XFS_IOC_OPEN_BY_HANDLE_32: { 650 struct xfs_fsop_handlereq hreq; 651 652 if (xfs_compat_handlereq_copyin(&hreq, arg)) 653 return -XFS_ERROR(EFAULT); 654 return xfs_open_by_handle(filp, &hreq); 655 } 656 case XFS_IOC_READLINK_BY_HANDLE_32: { 657 struct xfs_fsop_handlereq hreq; 658 659 if (xfs_compat_handlereq_copyin(&hreq, arg)) 660 return -XFS_ERROR(EFAULT); 661 return xfs_readlink_by_handle(filp, &hreq); 662 } 663 case XFS_IOC_ATTRLIST_BY_HANDLE_32: 664 return xfs_compat_attrlist_by_handle(filp, arg); 665 case XFS_IOC_ATTRMULTI_BY_HANDLE_32: 666 return xfs_compat_attrmulti_by_handle(filp, arg); 667 case XFS_IOC_FSSETDM_BY_HANDLE_32: 668 return xfs_compat_fssetdm_by_handle(filp, arg); 669 default: 670 return -XFS_ERROR(ENOIOCTLCMD); 671 } 672 } 673