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