[XFS] Clean up some existing compat ioctl calls
[pandora-kernel.git] / fs / xfs / linux-2.6 / xfs_ioctl.c
1 /*
2  * Copyright (c) 2000-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 "xfs.h"
19 #include "xfs_fs.h"
20 #include "xfs_bit.h"
21 #include "xfs_log.h"
22 #include "xfs_inum.h"
23 #include "xfs_trans.h"
24 #include "xfs_sb.h"
25 #include "xfs_ag.h"
26 #include "xfs_dir2.h"
27 #include "xfs_alloc.h"
28 #include "xfs_dmapi.h"
29 #include "xfs_mount.h"
30 #include "xfs_bmap_btree.h"
31 #include "xfs_alloc_btree.h"
32 #include "xfs_ialloc_btree.h"
33 #include "xfs_attr_sf.h"
34 #include "xfs_dir2_sf.h"
35 #include "xfs_dinode.h"
36 #include "xfs_inode.h"
37 #include "xfs_btree.h"
38 #include "xfs_ialloc.h"
39 #include "xfs_rtalloc.h"
40 #include "xfs_itable.h"
41 #include "xfs_error.h"
42 #include "xfs_rw.h"
43 #include "xfs_acl.h"
44 #include "xfs_attr.h"
45 #include "xfs_bmap.h"
46 #include "xfs_buf_item.h"
47 #include "xfs_utils.h"
48 #include "xfs_dfrag.h"
49 #include "xfs_fsops.h"
50 #include "xfs_vnodeops.h"
51 #include "xfs_quota.h"
52 #include "xfs_inode_item.h"
53
54 #include <linux/capability.h>
55 #include <linux/dcache.h>
56 #include <linux/mount.h>
57 #include <linux/namei.h>
58 #include <linux/pagemap.h>
59
60 /*
61  * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
62  * a file or fs handle.
63  *
64  * XFS_IOC_PATH_TO_FSHANDLE
65  *    returns fs handle for a mount point or path within that mount point
66  * XFS_IOC_FD_TO_HANDLE
67  *    returns full handle for a FD opened in user space
68  * XFS_IOC_PATH_TO_HANDLE
69  *    returns full handle for a path
70  */
71 int
72 xfs_find_handle(
73         unsigned int            cmd,
74         xfs_fsop_handlereq_t    *hreq)
75 {
76         int                     hsize;
77         xfs_handle_t            handle;
78         struct inode            *inode;
79
80         memset((char *)&handle, 0, sizeof(handle));
81
82         switch (cmd) {
83         case XFS_IOC_PATH_TO_FSHANDLE:
84         case XFS_IOC_PATH_TO_HANDLE: {
85                 struct path path;
86                 int error = user_lpath((const char __user *)hreq->path, &path);
87                 if (error)
88                         return error;
89
90                 ASSERT(path.dentry);
91                 ASSERT(path.dentry->d_inode);
92                 inode = igrab(path.dentry->d_inode);
93                 path_put(&path);
94                 break;
95         }
96
97         case XFS_IOC_FD_TO_HANDLE: {
98                 struct file     *file;
99
100                 file = fget(hreq->fd);
101                 if (!file)
102                     return -EBADF;
103
104                 ASSERT(file->f_path.dentry);
105                 ASSERT(file->f_path.dentry->d_inode);
106                 inode = igrab(file->f_path.dentry->d_inode);
107                 fput(file);
108                 break;
109         }
110
111         default:
112                 ASSERT(0);
113                 return -XFS_ERROR(EINVAL);
114         }
115
116         if (inode->i_sb->s_magic != XFS_SB_MAGIC) {
117                 /* we're not in XFS anymore, Toto */
118                 iput(inode);
119                 return -XFS_ERROR(EINVAL);
120         }
121
122         switch (inode->i_mode & S_IFMT) {
123         case S_IFREG:
124         case S_IFDIR:
125         case S_IFLNK:
126                 break;
127         default:
128                 iput(inode);
129                 return -XFS_ERROR(EBADF);
130         }
131
132         /* now we can grab the fsid */
133         memcpy(&handle.ha_fsid, XFS_I(inode)->i_mount->m_fixedfsid,
134                         sizeof(xfs_fsid_t));
135         hsize = sizeof(xfs_fsid_t);
136
137         if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {
138                 xfs_inode_t     *ip = XFS_I(inode);
139                 int             lock_mode;
140
141                 /* need to get access to the xfs_inode to read the generation */
142                 lock_mode = xfs_ilock_map_shared(ip);
143
144                 /* fill in fid section of handle from inode */
145                 handle.ha_fid.fid_len = sizeof(xfs_fid_t) -
146                                         sizeof(handle.ha_fid.fid_len);
147                 handle.ha_fid.fid_pad = 0;
148                 handle.ha_fid.fid_gen = ip->i_d.di_gen;
149                 handle.ha_fid.fid_ino = ip->i_ino;
150
151                 xfs_iunlock_map_shared(ip, lock_mode);
152
153                 hsize = XFS_HSIZE(handle);
154         }
155
156         /* now copy our handle into the user buffer & write out the size */
157         if (copy_to_user(hreq->ohandle, &handle, hsize) ||
158             copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) {
159                 iput(inode);
160                 return -XFS_ERROR(EFAULT);
161         }
162
163         iput(inode);
164         return 0;
165 }
166
167
168 /*
169  * Convert userspace handle data into inode.
170  *
171  * We use the fact that all the fsop_handlereq ioctl calls have a data
172  * structure argument whose first component is always a xfs_fsop_handlereq_t,
173  * so we can pass that sub structure into this handy, shared routine.
174  *
175  * If no error, caller must always iput the returned inode.
176  */
177 STATIC int
178 xfs_vget_fsop_handlereq(
179         xfs_mount_t             *mp,
180         struct inode            *parinode,      /* parent inode pointer    */
181         xfs_fsop_handlereq_t    *hreq,
182         struct inode            **inode)
183 {
184         void                    __user *hanp;
185         size_t                  hlen;
186         xfs_fid_t               *xfid;
187         xfs_handle_t            *handlep;
188         xfs_handle_t            handle;
189         xfs_inode_t             *ip;
190         xfs_ino_t               ino;
191         __u32                   igen;
192         int                     error;
193
194         /*
195          * Only allow handle opens under a directory.
196          */
197         if (!S_ISDIR(parinode->i_mode))
198                 return XFS_ERROR(ENOTDIR);
199
200         hanp = hreq->ihandle;
201         hlen = hreq->ihandlen;
202         handlep = &handle;
203
204         if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
205                 return XFS_ERROR(EINVAL);
206         if (copy_from_user(handlep, hanp, hlen))
207                 return XFS_ERROR(EFAULT);
208         if (hlen < sizeof(*handlep))
209                 memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
210         if (hlen > sizeof(handlep->ha_fsid)) {
211                 if (handlep->ha_fid.fid_len !=
212                     (hlen - sizeof(handlep->ha_fsid) -
213                             sizeof(handlep->ha_fid.fid_len)) ||
214                     handlep->ha_fid.fid_pad)
215                         return XFS_ERROR(EINVAL);
216         }
217
218         /*
219          * Crack the handle, obtain the inode # & generation #
220          */
221         xfid = (struct xfs_fid *)&handlep->ha_fid;
222         if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) {
223                 ino  = xfid->fid_ino;
224                 igen = xfid->fid_gen;
225         } else {
226                 return XFS_ERROR(EINVAL);
227         }
228
229         /*
230          * Get the XFS inode, building a Linux inode to go with it.
231          */
232         error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
233         if (error)
234                 return error;
235         if (ip == NULL)
236                 return XFS_ERROR(EIO);
237         if (ip->i_d.di_gen != igen) {
238                 xfs_iput_new(ip, XFS_ILOCK_SHARED);
239                 return XFS_ERROR(ENOENT);
240         }
241
242         xfs_iunlock(ip, XFS_ILOCK_SHARED);
243
244         *inode = VFS_I(ip);
245         return 0;
246 }
247
248 int
249 xfs_open_by_handle(
250         xfs_mount_t             *mp,
251         xfs_fsop_handlereq_t    *hreq,
252         struct file             *parfilp,
253         struct inode            *parinode)
254 {
255         int                     error;
256         int                     new_fd;
257         int                     permflag;
258         struct file             *filp;
259         struct inode            *inode;
260         struct dentry           *dentry;
261
262         if (!capable(CAP_SYS_ADMIN))
263                 return -XFS_ERROR(EPERM);
264
265         error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode);
266         if (error)
267                 return -error;
268
269         /* Restrict xfs_open_by_handle to directories & regular files. */
270         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
271                 iput(inode);
272                 return -XFS_ERROR(EINVAL);
273         }
274
275 #if BITS_PER_LONG != 32
276         hreq->oflags |= O_LARGEFILE;
277 #endif
278         /* Put open permission in namei format. */
279         permflag = hreq->oflags;
280         if ((permflag+1) & O_ACCMODE)
281                 permflag++;
282         if (permflag & O_TRUNC)
283                 permflag |= 2;
284
285         if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
286             (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
287                 iput(inode);
288                 return -XFS_ERROR(EPERM);
289         }
290
291         if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
292                 iput(inode);
293                 return -XFS_ERROR(EACCES);
294         }
295
296         /* Can't write directories. */
297         if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
298                 iput(inode);
299                 return -XFS_ERROR(EISDIR);
300         }
301
302         if ((new_fd = get_unused_fd()) < 0) {
303                 iput(inode);
304                 return new_fd;
305         }
306
307         dentry = d_obtain_alias(inode);
308         if (IS_ERR(dentry)) {
309                 put_unused_fd(new_fd);
310                 return PTR_ERR(dentry);
311         }
312
313         /* Ensure umount returns EBUSY on umounts while this file is open. */
314         mntget(parfilp->f_path.mnt);
315
316         /* Create file pointer. */
317         filp = dentry_open(dentry, parfilp->f_path.mnt, hreq->oflags);
318         if (IS_ERR(filp)) {
319                 put_unused_fd(new_fd);
320                 return -XFS_ERROR(-PTR_ERR(filp));
321         }
322         if (inode->i_mode & S_IFREG) {
323                 /* invisible operation should not change atime */
324                 filp->f_flags |= O_NOATIME;
325                 filp->f_op = &xfs_invis_file_operations;
326         }
327
328         fd_install(new_fd, filp);
329         return new_fd;
330 }
331
332 /*
333  * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's
334  * unused first argument.
335  */
336 STATIC int
337 do_readlink(
338         char __user             *buffer,
339         int                     buflen,
340         const char              *link)
341 {
342         int len;
343
344         len = PTR_ERR(link);
345         if (IS_ERR(link))
346                 goto out;
347
348         len = strlen(link);
349         if (len > (unsigned) buflen)
350                 len = buflen;
351         if (copy_to_user(buffer, link, len))
352                 len = -EFAULT;
353  out:
354         return len;
355 }
356
357
358 int
359 xfs_readlink_by_handle(
360         xfs_mount_t             *mp,
361         xfs_fsop_handlereq_t    *hreq,
362         struct inode            *parinode)
363 {
364         struct inode            *inode;
365         __u32                   olen;
366         void                    *link;
367         int                     error;
368
369         if (!capable(CAP_SYS_ADMIN))
370                 return -XFS_ERROR(EPERM);
371
372         error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode);
373         if (error)
374                 return -error;
375
376         /* Restrict this handle operation to symlinks only. */
377         if (!S_ISLNK(inode->i_mode)) {
378                 error = -XFS_ERROR(EINVAL);
379                 goto out_iput;
380         }
381
382         if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) {
383                 error = -XFS_ERROR(EFAULT);
384                 goto out_iput;
385         }
386
387         link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
388         if (!link)
389                 goto out_iput;
390
391         error = -xfs_readlink(XFS_I(inode), link);
392         if (error)
393                 goto out_kfree;
394         error = do_readlink(hreq->ohandle, olen, link);
395         if (error)
396                 goto out_kfree;
397
398  out_kfree:
399         kfree(link);
400  out_iput:
401         iput(inode);
402         return error;
403 }
404
405 STATIC int
406 xfs_fssetdm_by_handle(
407         xfs_mount_t             *mp,
408         void                    __user *arg,
409         struct inode            *parinode)
410 {
411         int                     error;
412         struct fsdmidata        fsd;
413         xfs_fsop_setdm_handlereq_t dmhreq;
414         struct inode            *inode;
415
416         if (!capable(CAP_MKNOD))
417                 return -XFS_ERROR(EPERM);
418         if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
419                 return -XFS_ERROR(EFAULT);
420
421         error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &inode);
422         if (error)
423                 return -error;
424
425         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
426                 error = -XFS_ERROR(EPERM);
427                 goto out;
428         }
429
430         if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
431                 error = -XFS_ERROR(EFAULT);
432                 goto out;
433         }
434
435         error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask,
436                                  fsd.fsd_dmstate);
437
438  out:
439         iput(inode);
440         return error;
441 }
442
443 STATIC int
444 xfs_attrlist_by_handle(
445         xfs_mount_t             *mp,
446         void                    __user *arg,
447         struct inode            *parinode)
448 {
449         int                     error;
450         attrlist_cursor_kern_t  *cursor;
451         xfs_fsop_attrlist_handlereq_t al_hreq;
452         struct inode            *inode;
453         char                    *kbuf;
454
455         if (!capable(CAP_SYS_ADMIN))
456                 return -XFS_ERROR(EPERM);
457         if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
458                 return -XFS_ERROR(EFAULT);
459         if (al_hreq.buflen > XATTR_LIST_MAX)
460                 return -XFS_ERROR(EINVAL);
461
462         /*
463          * Reject flags, only allow namespaces.
464          */
465         if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
466                 return -XFS_ERROR(EINVAL);
467
468         error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode);
469         if (error)
470                 goto out;
471
472         kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
473         if (!kbuf)
474                 goto out_vn_rele;
475
476         cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
477         error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen,
478                                         al_hreq.flags, cursor);
479         if (error)
480                 goto out_kfree;
481
482         if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
483                 error = -EFAULT;
484
485  out_kfree:
486         kfree(kbuf);
487  out_vn_rele:
488         iput(inode);
489  out:
490         return -error;
491 }
492
493 STATIC int
494 xfs_attrmulti_attr_get(
495         struct inode            *inode,
496         char                    *name,
497         char                    __user *ubuf,
498         __uint32_t              *len,
499         __uint32_t              flags)
500 {
501         char                    *kbuf;
502         int                     error = EFAULT;
503
504         if (*len > XATTR_SIZE_MAX)
505                 return EINVAL;
506         kbuf = kmalloc(*len, GFP_KERNEL);
507         if (!kbuf)
508                 return ENOMEM;
509
510         error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
511         if (error)
512                 goto out_kfree;
513
514         if (copy_to_user(ubuf, kbuf, *len))
515                 error = EFAULT;
516
517  out_kfree:
518         kfree(kbuf);
519         return error;
520 }
521
522 STATIC int
523 xfs_attrmulti_attr_set(
524         struct inode            *inode,
525         char                    *name,
526         const char              __user *ubuf,
527         __uint32_t              len,
528         __uint32_t              flags)
529 {
530         char                    *kbuf;
531         int                     error = EFAULT;
532
533         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
534                 return EPERM;
535         if (len > XATTR_SIZE_MAX)
536                 return EINVAL;
537
538         kbuf = kmalloc(len, GFP_KERNEL);
539         if (!kbuf)
540                 return ENOMEM;
541
542         if (copy_from_user(kbuf, ubuf, len))
543                 goto out_kfree;
544
545         error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
546
547  out_kfree:
548         kfree(kbuf);
549         return error;
550 }
551
552 STATIC int
553 xfs_attrmulti_attr_remove(
554         struct inode            *inode,
555         char                    *name,
556         __uint32_t              flags)
557 {
558         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
559                 return EPERM;
560         return xfs_attr_remove(XFS_I(inode), name, flags);
561 }
562
563 STATIC int
564 xfs_attrmulti_by_handle(
565         xfs_mount_t             *mp,
566         void                    __user *arg,
567         struct file             *parfilp,
568         struct inode            *parinode)
569 {
570         int                     error;
571         xfs_attr_multiop_t      *ops;
572         xfs_fsop_attrmulti_handlereq_t am_hreq;
573         struct inode            *inode;
574         unsigned int            i, size;
575         char                    *attr_name;
576
577         if (!capable(CAP_SYS_ADMIN))
578                 return -XFS_ERROR(EPERM);
579         if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
580                 return -XFS_ERROR(EFAULT);
581
582         error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &inode);
583         if (error)
584                 goto out;
585
586         error = E2BIG;
587         size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
588         if (!size || size > 16 * PAGE_SIZE)
589                 goto out_vn_rele;
590
591         error = ENOMEM;
592         ops = kmalloc(size, GFP_KERNEL);
593         if (!ops)
594                 goto out_vn_rele;
595
596         error = EFAULT;
597         if (copy_from_user(ops, am_hreq.ops, size))
598                 goto out_kfree_ops;
599
600         attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
601         if (!attr_name)
602                 goto out_kfree_ops;
603
604
605         error = 0;
606         for (i = 0; i < am_hreq.opcount; i++) {
607                 ops[i].am_error = strncpy_from_user(attr_name,
608                                 ops[i].am_attrname, MAXNAMELEN);
609                 if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
610                         error = -ERANGE;
611                 if (ops[i].am_error < 0)
612                         break;
613
614                 switch (ops[i].am_opcode) {
615                 case ATTR_OP_GET:
616                         ops[i].am_error = xfs_attrmulti_attr_get(inode,
617                                         attr_name, ops[i].am_attrvalue,
618                                         &ops[i].am_length, ops[i].am_flags);
619                         break;
620                 case ATTR_OP_SET:
621                         ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
622                         if (ops[i].am_error)
623                                 break;
624                         ops[i].am_error = xfs_attrmulti_attr_set(inode,
625                                         attr_name, ops[i].am_attrvalue,
626                                         ops[i].am_length, ops[i].am_flags);
627                         mnt_drop_write(parfilp->f_path.mnt);
628                         break;
629                 case ATTR_OP_REMOVE:
630                         ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
631                         if (ops[i].am_error)
632                                 break;
633                         ops[i].am_error = xfs_attrmulti_attr_remove(inode,
634                                         attr_name, ops[i].am_flags);
635                         mnt_drop_write(parfilp->f_path.mnt);
636                         break;
637                 default:
638                         ops[i].am_error = EINVAL;
639                 }
640         }
641
642         if (copy_to_user(am_hreq.ops, ops, size))
643                 error = XFS_ERROR(EFAULT);
644
645         kfree(attr_name);
646  out_kfree_ops:
647         kfree(ops);
648  out_vn_rele:
649         iput(inode);
650  out:
651         return -error;
652 }
653
654 int
655 xfs_ioc_space(
656         struct xfs_inode        *ip,
657         struct inode            *inode,
658         struct file             *filp,
659         int                     ioflags,
660         unsigned int            cmd,
661         xfs_flock64_t           *bf)
662 {
663         int                     attr_flags = 0;
664         int                     error;
665
666         /*
667          * Only allow the sys admin to reserve space unless
668          * unwritten extents are enabled.
669          */
670         if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) &&
671             !capable(CAP_SYS_ADMIN))
672                 return -XFS_ERROR(EPERM);
673
674         if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
675                 return -XFS_ERROR(EPERM);
676
677         if (!(filp->f_mode & FMODE_WRITE))
678                 return -XFS_ERROR(EBADF);
679
680         if (!S_ISREG(inode->i_mode))
681                 return -XFS_ERROR(EINVAL);
682
683         if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
684                 attr_flags |= XFS_ATTR_NONBLOCK;
685         if (ioflags & IO_INVIS)
686                 attr_flags |= XFS_ATTR_DMI;
687
688         error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags);
689         return -error;
690 }
691
692 STATIC int
693 xfs_ioc_bulkstat(
694         xfs_mount_t             *mp,
695         unsigned int            cmd,
696         void                    __user *arg)
697 {
698         xfs_fsop_bulkreq_t      bulkreq;
699         int                     count;  /* # of records returned */
700         xfs_ino_t               inlast; /* last inode number */
701         int                     done;
702         int                     error;
703
704         /* done = 1 if there are more stats to get and if bulkstat */
705         /* should be called again (unused here, but used in dmapi) */
706
707         if (!capable(CAP_SYS_ADMIN))
708                 return -EPERM;
709
710         if (XFS_FORCED_SHUTDOWN(mp))
711                 return -XFS_ERROR(EIO);
712
713         if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
714                 return -XFS_ERROR(EFAULT);
715
716         if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
717                 return -XFS_ERROR(EFAULT);
718
719         if ((count = bulkreq.icount) <= 0)
720                 return -XFS_ERROR(EINVAL);
721
722         if (bulkreq.ubuffer == NULL)
723                 return -XFS_ERROR(EINVAL);
724
725         if (cmd == XFS_IOC_FSINUMBERS)
726                 error = xfs_inumbers(mp, &inlast, &count,
727                                         bulkreq.ubuffer, xfs_inumbers_fmt);
728         else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
729                 error = xfs_bulkstat_single(mp, &inlast,
730                                                 bulkreq.ubuffer, &done);
731         else    /* XFS_IOC_FSBULKSTAT */
732                 error = xfs_bulkstat(mp, &inlast, &count,
733                         (bulkstat_one_pf)xfs_bulkstat_one, NULL,
734                         sizeof(xfs_bstat_t), bulkreq.ubuffer,
735                         BULKSTAT_FG_QUICK, &done);
736
737         if (error)
738                 return -error;
739
740         if (bulkreq.ocount != NULL) {
741                 if (copy_to_user(bulkreq.lastip, &inlast,
742                                                 sizeof(xfs_ino_t)))
743                         return -XFS_ERROR(EFAULT);
744
745                 if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
746                         return -XFS_ERROR(EFAULT);
747         }
748
749         return 0;
750 }
751
752 STATIC int
753 xfs_ioc_fsgeometry_v1(
754         xfs_mount_t             *mp,
755         void                    __user *arg)
756 {
757         xfs_fsop_geom_v1_t      fsgeo;
758         int                     error;
759
760         error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
761         if (error)
762                 return -error;
763
764         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
765                 return -XFS_ERROR(EFAULT);
766         return 0;
767 }
768
769 STATIC int
770 xfs_ioc_fsgeometry(
771         xfs_mount_t             *mp,
772         void                    __user *arg)
773 {
774         xfs_fsop_geom_t         fsgeo;
775         int                     error;
776
777         error = xfs_fs_geometry(mp, &fsgeo, 4);
778         if (error)
779                 return -error;
780
781         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
782                 return -XFS_ERROR(EFAULT);
783         return 0;
784 }
785
786 /*
787  * Linux extended inode flags interface.
788  */
789
790 STATIC unsigned int
791 xfs_merge_ioc_xflags(
792         unsigned int    flags,
793         unsigned int    start)
794 {
795         unsigned int    xflags = start;
796
797         if (flags & FS_IMMUTABLE_FL)
798                 xflags |= XFS_XFLAG_IMMUTABLE;
799         else
800                 xflags &= ~XFS_XFLAG_IMMUTABLE;
801         if (flags & FS_APPEND_FL)
802                 xflags |= XFS_XFLAG_APPEND;
803         else
804                 xflags &= ~XFS_XFLAG_APPEND;
805         if (flags & FS_SYNC_FL)
806                 xflags |= XFS_XFLAG_SYNC;
807         else
808                 xflags &= ~XFS_XFLAG_SYNC;
809         if (flags & FS_NOATIME_FL)
810                 xflags |= XFS_XFLAG_NOATIME;
811         else
812                 xflags &= ~XFS_XFLAG_NOATIME;
813         if (flags & FS_NODUMP_FL)
814                 xflags |= XFS_XFLAG_NODUMP;
815         else
816                 xflags &= ~XFS_XFLAG_NODUMP;
817
818         return xflags;
819 }
820
821 STATIC unsigned int
822 xfs_di2lxflags(
823         __uint16_t      di_flags)
824 {
825         unsigned int    flags = 0;
826
827         if (di_flags & XFS_DIFLAG_IMMUTABLE)
828                 flags |= FS_IMMUTABLE_FL;
829         if (di_flags & XFS_DIFLAG_APPEND)
830                 flags |= FS_APPEND_FL;
831         if (di_flags & XFS_DIFLAG_SYNC)
832                 flags |= FS_SYNC_FL;
833         if (di_flags & XFS_DIFLAG_NOATIME)
834                 flags |= FS_NOATIME_FL;
835         if (di_flags & XFS_DIFLAG_NODUMP)
836                 flags |= FS_NODUMP_FL;
837         return flags;
838 }
839
840 STATIC int
841 xfs_ioc_fsgetxattr(
842         xfs_inode_t             *ip,
843         int                     attr,
844         void                    __user *arg)
845 {
846         struct fsxattr          fa;
847
848         xfs_ilock(ip, XFS_ILOCK_SHARED);
849         fa.fsx_xflags = xfs_ip2xflags(ip);
850         fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
851         fa.fsx_projid = ip->i_d.di_projid;
852
853         if (attr) {
854                 if (ip->i_afp) {
855                         if (ip->i_afp->if_flags & XFS_IFEXTENTS)
856                                 fa.fsx_nextents = ip->i_afp->if_bytes /
857                                                         sizeof(xfs_bmbt_rec_t);
858                         else
859                                 fa.fsx_nextents = ip->i_d.di_anextents;
860                 } else
861                         fa.fsx_nextents = 0;
862         } else {
863                 if (ip->i_df.if_flags & XFS_IFEXTENTS)
864                         fa.fsx_nextents = ip->i_df.if_bytes /
865                                                 sizeof(xfs_bmbt_rec_t);
866                 else
867                         fa.fsx_nextents = ip->i_d.di_nextents;
868         }
869         xfs_iunlock(ip, XFS_ILOCK_SHARED);
870
871         if (copy_to_user(arg, &fa, sizeof(fa)))
872                 return -EFAULT;
873         return 0;
874 }
875
876 STATIC void
877 xfs_set_diflags(
878         struct xfs_inode        *ip,
879         unsigned int            xflags)
880 {
881         unsigned int            di_flags;
882
883         /* can't set PREALLOC this way, just preserve it */
884         di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
885         if (xflags & XFS_XFLAG_IMMUTABLE)
886                 di_flags |= XFS_DIFLAG_IMMUTABLE;
887         if (xflags & XFS_XFLAG_APPEND)
888                 di_flags |= XFS_DIFLAG_APPEND;
889         if (xflags & XFS_XFLAG_SYNC)
890                 di_flags |= XFS_DIFLAG_SYNC;
891         if (xflags & XFS_XFLAG_NOATIME)
892                 di_flags |= XFS_DIFLAG_NOATIME;
893         if (xflags & XFS_XFLAG_NODUMP)
894                 di_flags |= XFS_DIFLAG_NODUMP;
895         if (xflags & XFS_XFLAG_PROJINHERIT)
896                 di_flags |= XFS_DIFLAG_PROJINHERIT;
897         if (xflags & XFS_XFLAG_NODEFRAG)
898                 di_flags |= XFS_DIFLAG_NODEFRAG;
899         if (xflags & XFS_XFLAG_FILESTREAM)
900                 di_flags |= XFS_DIFLAG_FILESTREAM;
901         if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
902                 if (xflags & XFS_XFLAG_RTINHERIT)
903                         di_flags |= XFS_DIFLAG_RTINHERIT;
904                 if (xflags & XFS_XFLAG_NOSYMLINKS)
905                         di_flags |= XFS_DIFLAG_NOSYMLINKS;
906                 if (xflags & XFS_XFLAG_EXTSZINHERIT)
907                         di_flags |= XFS_DIFLAG_EXTSZINHERIT;
908         } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
909                 if (xflags & XFS_XFLAG_REALTIME)
910                         di_flags |= XFS_DIFLAG_REALTIME;
911                 if (xflags & XFS_XFLAG_EXTSIZE)
912                         di_flags |= XFS_DIFLAG_EXTSIZE;
913         }
914
915         ip->i_d.di_flags = di_flags;
916 }
917
918 STATIC void
919 xfs_diflags_to_linux(
920         struct xfs_inode        *ip)
921 {
922         struct inode            *inode = VFS_I(ip);
923         unsigned int            xflags = xfs_ip2xflags(ip);
924
925         if (xflags & XFS_XFLAG_IMMUTABLE)
926                 inode->i_flags |= S_IMMUTABLE;
927         else
928                 inode->i_flags &= ~S_IMMUTABLE;
929         if (xflags & XFS_XFLAG_APPEND)
930                 inode->i_flags |= S_APPEND;
931         else
932                 inode->i_flags &= ~S_APPEND;
933         if (xflags & XFS_XFLAG_SYNC)
934                 inode->i_flags |= S_SYNC;
935         else
936                 inode->i_flags &= ~S_SYNC;
937         if (xflags & XFS_XFLAG_NOATIME)
938                 inode->i_flags |= S_NOATIME;
939         else
940                 inode->i_flags &= ~S_NOATIME;
941 }
942
943 #define FSX_PROJID      1
944 #define FSX_EXTSIZE     2
945 #define FSX_XFLAGS      4
946 #define FSX_NONBLOCK    8
947
948 STATIC int
949 xfs_ioctl_setattr(
950         xfs_inode_t             *ip,
951         struct fsxattr          *fa,
952         int                     mask)
953 {
954         struct xfs_mount        *mp = ip->i_mount;
955         struct xfs_trans        *tp;
956         unsigned int            lock_flags = 0;
957         struct xfs_dquot        *udqp = NULL, *gdqp = NULL;
958         struct xfs_dquot        *olddquot = NULL;
959         int                     code;
960
961         xfs_itrace_entry(ip);
962
963         if (mp->m_flags & XFS_MOUNT_RDONLY)
964                 return XFS_ERROR(EROFS);
965         if (XFS_FORCED_SHUTDOWN(mp))
966                 return XFS_ERROR(EIO);
967
968         /*
969          * If disk quotas is on, we make sure that the dquots do exist on disk,
970          * before we start any other transactions. Trying to do this later
971          * is messy. We don't care to take a readlock to look at the ids
972          * in inode here, because we can't hold it across the trans_reserve.
973          * If the IDs do change before we take the ilock, we're covered
974          * because the i_*dquot fields will get updated anyway.
975          */
976         if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
977                 code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
978                                          ip->i_d.di_gid, fa->fsx_projid,
979                                          XFS_QMOPT_PQUOTA, &udqp, &gdqp);
980                 if (code)
981                         return code;
982         }
983
984         /*
985          * For the other attributes, we acquire the inode lock and
986          * first do an error checking pass.
987          */
988         tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
989         code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
990         if (code)
991                 goto error_return;
992
993         lock_flags = XFS_ILOCK_EXCL;
994         xfs_ilock(ip, lock_flags);
995
996         /*
997          * CAP_FOWNER overrides the following restrictions:
998          *
999          * The user ID of the calling process must be equal
1000          * to the file owner ID, except in cases where the
1001          * CAP_FSETID capability is applicable.
1002          */
1003         if (current_fsuid() != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
1004                 code = XFS_ERROR(EPERM);
1005                 goto error_return;
1006         }
1007
1008         /*
1009          * Do a quota reservation only if projid is actually going to change.
1010          */
1011         if (mask & FSX_PROJID) {
1012                 if (XFS_IS_PQUOTA_ON(mp) &&
1013                     ip->i_d.di_projid != fa->fsx_projid) {
1014                         ASSERT(tp);
1015                         code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
1016                                                 capable(CAP_FOWNER) ?
1017                                                 XFS_QMOPT_FORCE_RES : 0);
1018                         if (code)       /* out of quota */
1019                                 goto error_return;
1020                 }
1021         }
1022
1023         if (mask & FSX_EXTSIZE) {
1024                 /*
1025                  * Can't change extent size if any extents are allocated.
1026                  */
1027                 if (ip->i_d.di_nextents &&
1028                     ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
1029                      fa->fsx_extsize)) {
1030                         code = XFS_ERROR(EINVAL);       /* EFBIG? */
1031                         goto error_return;
1032                 }
1033
1034                 /*
1035                  * Extent size must be a multiple of the appropriate block
1036                  * size, if set at all.
1037                  */
1038                 if (fa->fsx_extsize != 0) {
1039                         xfs_extlen_t    size;
1040
1041                         if (XFS_IS_REALTIME_INODE(ip) ||
1042                             ((mask & FSX_XFLAGS) &&
1043                             (fa->fsx_xflags & XFS_XFLAG_REALTIME))) {
1044                                 size = mp->m_sb.sb_rextsize <<
1045                                        mp->m_sb.sb_blocklog;
1046                         } else {
1047                                 size = mp->m_sb.sb_blocksize;
1048                         }
1049
1050                         if (fa->fsx_extsize % size) {
1051                                 code = XFS_ERROR(EINVAL);
1052                                 goto error_return;
1053                         }
1054                 }
1055         }
1056
1057
1058         if (mask & FSX_XFLAGS) {
1059                 /*
1060                  * Can't change realtime flag if any extents are allocated.
1061                  */
1062                 if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
1063                     (XFS_IS_REALTIME_INODE(ip)) !=
1064                     (fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1065                         code = XFS_ERROR(EINVAL);       /* EFBIG? */
1066                         goto error_return;
1067                 }
1068
1069                 /*
1070                  * If realtime flag is set then must have realtime data.
1071                  */
1072                 if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1073                         if ((mp->m_sb.sb_rblocks == 0) ||
1074                             (mp->m_sb.sb_rextsize == 0) ||
1075                             (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
1076                                 code = XFS_ERROR(EINVAL);
1077                                 goto error_return;
1078                         }
1079                 }
1080
1081                 /*
1082                  * Can't modify an immutable/append-only file unless
1083                  * we have appropriate permission.
1084                  */
1085                 if ((ip->i_d.di_flags &
1086                                 (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||
1087                      (fa->fsx_xflags &
1088                                 (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
1089                     !capable(CAP_LINUX_IMMUTABLE)) {
1090                         code = XFS_ERROR(EPERM);
1091                         goto error_return;
1092                 }
1093         }
1094
1095         xfs_trans_ijoin(tp, ip, lock_flags);
1096         xfs_trans_ihold(tp, ip);
1097
1098         /*
1099          * Change file ownership.  Must be the owner or privileged.
1100          */
1101         if (mask & FSX_PROJID) {
1102                 /*
1103                  * CAP_FSETID overrides the following restrictions:
1104                  *
1105                  * The set-user-ID and set-group-ID bits of a file will be
1106                  * cleared upon successful return from chown()
1107                  */
1108                 if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
1109                     !capable(CAP_FSETID))
1110                         ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
1111
1112                 /*
1113                  * Change the ownerships and register quota modifications
1114                  * in the transaction.
1115                  */
1116                 if (ip->i_d.di_projid != fa->fsx_projid) {
1117                         if (XFS_IS_PQUOTA_ON(mp)) {
1118                                 olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
1119                                                         &ip->i_gdquot, gdqp);
1120                         }
1121                         ip->i_d.di_projid = fa->fsx_projid;
1122
1123                         /*
1124                          * We may have to rev the inode as well as
1125                          * the superblock version number since projids didn't
1126                          * exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
1127                          */
1128                         if (ip->i_d.di_version == 1)
1129                                 xfs_bump_ino_vers2(tp, ip);
1130                 }
1131
1132         }
1133
1134         if (mask & FSX_EXTSIZE)
1135                 ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
1136         if (mask & FSX_XFLAGS) {
1137                 xfs_set_diflags(ip, fa->fsx_xflags);
1138                 xfs_diflags_to_linux(ip);
1139         }
1140
1141         xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1142         xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
1143
1144         XFS_STATS_INC(xs_ig_attrchg);
1145
1146         /*
1147          * If this is a synchronous mount, make sure that the
1148          * transaction goes to disk before returning to the user.
1149          * This is slightly sub-optimal in that truncates require
1150          * two sync transactions instead of one for wsync filesystems.
1151          * One for the truncate and one for the timestamps since we
1152          * don't want to change the timestamps unless we're sure the
1153          * truncate worked.  Truncates are less than 1% of the laddis
1154          * mix so this probably isn't worth the trouble to optimize.
1155          */
1156         if (mp->m_flags & XFS_MOUNT_WSYNC)
1157                 xfs_trans_set_sync(tp);
1158         code = xfs_trans_commit(tp, 0);
1159         xfs_iunlock(ip, lock_flags);
1160
1161         /*
1162          * Release any dquot(s) the inode had kept before chown.
1163          */
1164         XFS_QM_DQRELE(mp, olddquot);
1165         XFS_QM_DQRELE(mp, udqp);
1166         XFS_QM_DQRELE(mp, gdqp);
1167
1168         if (code)
1169                 return code;
1170
1171         if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
1172                 XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
1173                                 NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
1174                                 (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
1175         }
1176
1177         return 0;
1178
1179  error_return:
1180         XFS_QM_DQRELE(mp, udqp);
1181         XFS_QM_DQRELE(mp, gdqp);
1182         xfs_trans_cancel(tp, 0);
1183         if (lock_flags)
1184                 xfs_iunlock(ip, lock_flags);
1185         return code;
1186 }
1187
1188 STATIC int
1189 xfs_ioc_fssetxattr(
1190         xfs_inode_t             *ip,
1191         struct file             *filp,
1192         void                    __user *arg)
1193 {
1194         struct fsxattr          fa;
1195         unsigned int            mask;
1196
1197         if (copy_from_user(&fa, arg, sizeof(fa)))
1198                 return -EFAULT;
1199
1200         mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
1201         if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1202                 mask |= FSX_NONBLOCK;
1203
1204         return -xfs_ioctl_setattr(ip, &fa, mask);
1205 }
1206
1207 STATIC int
1208 xfs_ioc_getxflags(
1209         xfs_inode_t             *ip,
1210         void                    __user *arg)
1211 {
1212         unsigned int            flags;
1213
1214         flags = xfs_di2lxflags(ip->i_d.di_flags);
1215         if (copy_to_user(arg, &flags, sizeof(flags)))
1216                 return -EFAULT;
1217         return 0;
1218 }
1219
1220 STATIC int
1221 xfs_ioc_setxflags(
1222         xfs_inode_t             *ip,
1223         struct file             *filp,
1224         void                    __user *arg)
1225 {
1226         struct fsxattr          fa;
1227         unsigned int            flags;
1228         unsigned int            mask;
1229
1230         if (copy_from_user(&flags, arg, sizeof(flags)))
1231                 return -EFAULT;
1232
1233         if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
1234                       FS_NOATIME_FL | FS_NODUMP_FL | \
1235                       FS_SYNC_FL))
1236                 return -EOPNOTSUPP;
1237
1238         mask = FSX_XFLAGS;
1239         if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1240                 mask |= FSX_NONBLOCK;
1241         fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
1242
1243         return -xfs_ioctl_setattr(ip, &fa, mask);
1244 }
1245
1246 STATIC int
1247 xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full)
1248 {
1249         struct getbmap __user   *base = *ap;
1250
1251         /* copy only getbmap portion (not getbmapx) */
1252         if (copy_to_user(base, bmv, sizeof(struct getbmap)))
1253                 return XFS_ERROR(EFAULT);
1254
1255         *ap += sizeof(struct getbmap);
1256         return 0;
1257 }
1258
1259 STATIC int
1260 xfs_ioc_getbmap(
1261         struct xfs_inode        *ip,
1262         int                     ioflags,
1263         unsigned int            cmd,
1264         void                    __user *arg)
1265 {
1266         struct getbmapx         bmx;
1267         int                     error;
1268
1269         if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
1270                 return -XFS_ERROR(EFAULT);
1271
1272         if (bmx.bmv_count < 2)
1273                 return -XFS_ERROR(EINVAL);
1274
1275         bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
1276         if (ioflags & IO_INVIS)
1277                 bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
1278
1279         error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
1280                             (struct getbmap *)arg+1);
1281         if (error)
1282                 return -error;
1283
1284         /* copy back header - only size of getbmap */
1285         if (copy_to_user(arg, &bmx, sizeof(struct getbmap)))
1286                 return -XFS_ERROR(EFAULT);
1287         return 0;
1288 }
1289
1290 STATIC int
1291 xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full)
1292 {
1293         struct getbmapx __user  *base = *ap;
1294
1295         if (copy_to_user(base, bmv, sizeof(struct getbmapx)))
1296                 return XFS_ERROR(EFAULT);
1297
1298         *ap += sizeof(struct getbmapx);
1299         return 0;
1300 }
1301
1302 STATIC int
1303 xfs_ioc_getbmapx(
1304         struct xfs_inode        *ip,
1305         void                    __user *arg)
1306 {
1307         struct getbmapx         bmx;
1308         int                     error;
1309
1310         if (copy_from_user(&bmx, arg, sizeof(bmx)))
1311                 return -XFS_ERROR(EFAULT);
1312
1313         if (bmx.bmv_count < 2)
1314                 return -XFS_ERROR(EINVAL);
1315
1316         if (bmx.bmv_iflags & (~BMV_IF_VALID))
1317                 return -XFS_ERROR(EINVAL);
1318
1319         error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format,
1320                             (struct getbmapx *)arg+1);
1321         if (error)
1322                 return -error;
1323
1324         /* copy back header */
1325         if (copy_to_user(arg, &bmx, sizeof(struct getbmapx)))
1326                 return -XFS_ERROR(EFAULT);
1327
1328         return 0;
1329 }
1330
1331 int
1332 xfs_ioctl(
1333         xfs_inode_t             *ip,
1334         struct file             *filp,
1335         int                     ioflags,
1336         unsigned int            cmd,
1337         void                    __user *arg)
1338 {
1339         struct inode            *inode = filp->f_path.dentry->d_inode;
1340         xfs_mount_t             *mp = ip->i_mount;
1341         int                     error;
1342
1343         xfs_itrace_entry(XFS_I(inode));
1344         switch (cmd) {
1345
1346         case XFS_IOC_ALLOCSP:
1347         case XFS_IOC_FREESP:
1348         case XFS_IOC_RESVSP:
1349         case XFS_IOC_UNRESVSP:
1350         case XFS_IOC_ALLOCSP64:
1351         case XFS_IOC_FREESP64:
1352         case XFS_IOC_RESVSP64:
1353         case XFS_IOC_UNRESVSP64: {
1354                 xfs_flock64_t           bf;
1355
1356                 if (copy_from_user(&bf, arg, sizeof(bf)))
1357                         return -XFS_ERROR(EFAULT);
1358                 return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf);
1359         }
1360         case XFS_IOC_DIOINFO: {
1361                 struct dioattr  da;
1362                 xfs_buftarg_t   *target =
1363                         XFS_IS_REALTIME_INODE(ip) ?
1364                         mp->m_rtdev_targp : mp->m_ddev_targp;
1365
1366                 da.d_mem = da.d_miniosz = 1 << target->bt_sshift;
1367                 da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
1368
1369                 if (copy_to_user(arg, &da, sizeof(da)))
1370                         return -XFS_ERROR(EFAULT);
1371                 return 0;
1372         }
1373
1374         case XFS_IOC_FSBULKSTAT_SINGLE:
1375         case XFS_IOC_FSBULKSTAT:
1376         case XFS_IOC_FSINUMBERS:
1377                 return xfs_ioc_bulkstat(mp, cmd, arg);
1378
1379         case XFS_IOC_FSGEOMETRY_V1:
1380                 return xfs_ioc_fsgeometry_v1(mp, arg);
1381
1382         case XFS_IOC_FSGEOMETRY:
1383                 return xfs_ioc_fsgeometry(mp, arg);
1384
1385         case XFS_IOC_GETVERSION:
1386                 return put_user(inode->i_generation, (int __user *)arg);
1387
1388         case XFS_IOC_FSGETXATTR:
1389                 return xfs_ioc_fsgetxattr(ip, 0, arg);
1390         case XFS_IOC_FSGETXATTRA:
1391                 return xfs_ioc_fsgetxattr(ip, 1, arg);
1392         case XFS_IOC_FSSETXATTR:
1393                 return xfs_ioc_fssetxattr(ip, filp, arg);
1394         case XFS_IOC_GETXFLAGS:
1395                 return xfs_ioc_getxflags(ip, arg);
1396         case XFS_IOC_SETXFLAGS:
1397                 return xfs_ioc_setxflags(ip, filp, arg);
1398
1399         case XFS_IOC_FSSETDM: {
1400                 struct fsdmidata        dmi;
1401
1402                 if (copy_from_user(&dmi, arg, sizeof(dmi)))
1403                         return -XFS_ERROR(EFAULT);
1404
1405                 error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask,
1406                                 dmi.fsd_dmstate);
1407                 return -error;
1408         }
1409
1410         case XFS_IOC_GETBMAP:
1411         case XFS_IOC_GETBMAPA:
1412                 return xfs_ioc_getbmap(ip, ioflags, cmd, arg);
1413
1414         case XFS_IOC_GETBMAPX:
1415                 return xfs_ioc_getbmapx(ip, arg);
1416
1417         case XFS_IOC_FD_TO_HANDLE:
1418         case XFS_IOC_PATH_TO_HANDLE:
1419         case XFS_IOC_PATH_TO_FSHANDLE: {
1420                 xfs_fsop_handlereq_t    hreq;
1421
1422                 if (copy_from_user(&hreq, arg, sizeof(hreq)))
1423                         return -XFS_ERROR(EFAULT);
1424                 return xfs_find_handle(cmd, &hreq);
1425         }
1426         case XFS_IOC_OPEN_BY_HANDLE: {
1427                 xfs_fsop_handlereq_t    hreq;
1428
1429                 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
1430                         return -XFS_ERROR(EFAULT);
1431                 return xfs_open_by_handle(mp, &hreq, filp, inode);
1432         }
1433         case XFS_IOC_FSSETDM_BY_HANDLE:
1434                 return xfs_fssetdm_by_handle(mp, arg, inode);
1435
1436         case XFS_IOC_READLINK_BY_HANDLE: {
1437                 xfs_fsop_handlereq_t    hreq;
1438
1439                 if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
1440                         return -XFS_ERROR(EFAULT);
1441                 return xfs_readlink_by_handle(mp, &hreq, inode);
1442         }
1443         case XFS_IOC_ATTRLIST_BY_HANDLE:
1444                 return xfs_attrlist_by_handle(mp, arg, inode);
1445
1446         case XFS_IOC_ATTRMULTI_BY_HANDLE:
1447                 return xfs_attrmulti_by_handle(mp, arg, filp, inode);
1448
1449         case XFS_IOC_SWAPEXT: {
1450                 struct xfs_swapext      sxp;
1451
1452                 if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t)))
1453                         return -XFS_ERROR(EFAULT);
1454                 error = xfs_swapext(&sxp);
1455                 return -error;
1456         }
1457
1458         case XFS_IOC_FSCOUNTS: {
1459                 xfs_fsop_counts_t out;
1460
1461                 error = xfs_fs_counts(mp, &out);
1462                 if (error)
1463                         return -error;
1464
1465                 if (copy_to_user(arg, &out, sizeof(out)))
1466                         return -XFS_ERROR(EFAULT);
1467                 return 0;
1468         }
1469
1470         case XFS_IOC_SET_RESBLKS: {
1471                 xfs_fsop_resblks_t inout;
1472                 __uint64_t         in;
1473
1474                 if (!capable(CAP_SYS_ADMIN))
1475                         return -EPERM;
1476
1477                 if (copy_from_user(&inout, arg, sizeof(inout)))
1478                         return -XFS_ERROR(EFAULT);
1479
1480                 /* input parameter is passed in resblks field of structure */
1481                 in = inout.resblks;
1482                 error = xfs_reserve_blocks(mp, &in, &inout);
1483                 if (error)
1484                         return -error;
1485
1486                 if (copy_to_user(arg, &inout, sizeof(inout)))
1487                         return -XFS_ERROR(EFAULT);
1488                 return 0;
1489         }
1490
1491         case XFS_IOC_GET_RESBLKS: {
1492                 xfs_fsop_resblks_t out;
1493
1494                 if (!capable(CAP_SYS_ADMIN))
1495                         return -EPERM;
1496
1497                 error = xfs_reserve_blocks(mp, NULL, &out);
1498                 if (error)
1499                         return -error;
1500
1501                 if (copy_to_user(arg, &out, sizeof(out)))
1502                         return -XFS_ERROR(EFAULT);
1503
1504                 return 0;
1505         }
1506
1507         case XFS_IOC_FSGROWFSDATA: {
1508                 xfs_growfs_data_t in;
1509
1510                 if (copy_from_user(&in, arg, sizeof(in)))
1511                         return -XFS_ERROR(EFAULT);
1512
1513                 error = xfs_growfs_data(mp, &in);
1514                 return -error;
1515         }
1516
1517         case XFS_IOC_FSGROWFSLOG: {
1518                 xfs_growfs_log_t in;
1519
1520                 if (copy_from_user(&in, arg, sizeof(in)))
1521                         return -XFS_ERROR(EFAULT);
1522
1523                 error = xfs_growfs_log(mp, &in);
1524                 return -error;
1525         }
1526
1527         case XFS_IOC_FSGROWFSRT: {
1528                 xfs_growfs_rt_t in;
1529
1530                 if (copy_from_user(&in, arg, sizeof(in)))
1531                         return -XFS_ERROR(EFAULT);
1532
1533                 error = xfs_growfs_rt(mp, &in);
1534                 return -error;
1535         }
1536
1537         case XFS_IOC_FREEZE:
1538                 if (!capable(CAP_SYS_ADMIN))
1539                         return -EPERM;
1540
1541                 if (inode->i_sb->s_frozen == SB_UNFROZEN)
1542                         freeze_bdev(inode->i_sb->s_bdev);
1543                 return 0;
1544
1545         case XFS_IOC_THAW:
1546                 if (!capable(CAP_SYS_ADMIN))
1547                         return -EPERM;
1548                 if (inode->i_sb->s_frozen != SB_UNFROZEN)
1549                         thaw_bdev(inode->i_sb->s_bdev, inode->i_sb);
1550                 return 0;
1551
1552         case XFS_IOC_GOINGDOWN: {
1553                 __uint32_t in;
1554
1555                 if (!capable(CAP_SYS_ADMIN))
1556                         return -EPERM;
1557
1558                 if (get_user(in, (__uint32_t __user *)arg))
1559                         return -XFS_ERROR(EFAULT);
1560
1561                 error = xfs_fs_goingdown(mp, in);
1562                 return -error;
1563         }
1564
1565         case XFS_IOC_ERROR_INJECTION: {
1566                 xfs_error_injection_t in;
1567
1568                 if (!capable(CAP_SYS_ADMIN))
1569                         return -EPERM;
1570
1571                 if (copy_from_user(&in, arg, sizeof(in)))
1572                         return -XFS_ERROR(EFAULT);
1573
1574                 error = xfs_errortag_add(in.errtag, mp);
1575                 return -error;
1576         }
1577
1578         case XFS_IOC_ERROR_CLEARALL:
1579                 if (!capable(CAP_SYS_ADMIN))
1580                         return -EPERM;
1581
1582                 error = xfs_errortag_clearall(mp, 1);
1583                 return -error;
1584
1585         default:
1586                 return -ENOTTY;
1587         }
1588 }