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