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