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