vserver 1.9.5.x5
[linux-2.6.git] / fs / xfs / linux-2.6 / xfs_ioctl.c
1 /*
2  * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32
33 #include "xfs.h"
34
35 #include "xfs_fs.h"
36 #include "xfs_inum.h"
37 #include "xfs_log.h"
38 #include "xfs_trans.h"
39 #include "xfs_sb.h"
40 #include "xfs_dir.h"
41 #include "xfs_dir2.h"
42 #include "xfs_alloc.h"
43 #include "xfs_dmapi.h"
44 #include "xfs_mount.h"
45 #include "xfs_alloc_btree.h"
46 #include "xfs_bmap_btree.h"
47 #include "xfs_ialloc_btree.h"
48 #include "xfs_btree.h"
49 #include "xfs_ialloc.h"
50 #include "xfs_attr_sf.h"
51 #include "xfs_dir_sf.h"
52 #include "xfs_dir2_sf.h"
53 #include "xfs_dinode.h"
54 #include "xfs_inode.h"
55 #include "xfs_bmap.h"
56 #include "xfs_bit.h"
57 #include "xfs_rtalloc.h"
58 #include "xfs_error.h"
59 #include "xfs_itable.h"
60 #include "xfs_rw.h"
61 #include "xfs_acl.h"
62 #include "xfs_cap.h"
63 #include "xfs_mac.h"
64 #include "xfs_attr.h"
65 #include "xfs_buf_item.h"
66 #include "xfs_utils.h"
67 #include "xfs_dfrag.h"
68 #include "xfs_fsops.h"
69
70 #include <linux/dcache.h>
71 #include <linux/mount.h>
72 #include <linux/namei.h>
73 #include <linux/pagemap.h>
74
75 /*
76  * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
77  * a file or fs handle.
78  *
79  * XFS_IOC_PATH_TO_FSHANDLE
80  *    returns fs handle for a mount point or path within that mount point
81  * XFS_IOC_FD_TO_HANDLE
82  *    returns full handle for a FD opened in user space
83  * XFS_IOC_PATH_TO_HANDLE
84  *    returns full handle for a path
85  */
86 STATIC int
87 xfs_find_handle(
88         unsigned int            cmd,
89         void                    __user *arg)
90 {
91         int                     hsize;
92         xfs_handle_t            handle;
93         xfs_fsop_handlereq_t    hreq;
94         struct inode            *inode;
95         struct vnode            *vp;
96
97         if (copy_from_user(&hreq, arg, sizeof(hreq)))
98                 return -XFS_ERROR(EFAULT);
99
100         memset((char *)&handle, 0, sizeof(handle));
101
102         switch (cmd) {
103         case XFS_IOC_PATH_TO_FSHANDLE:
104         case XFS_IOC_PATH_TO_HANDLE: {
105                 struct nameidata        nd;
106                 int                     error;
107
108                 error = user_path_walk_link((const char __user *)hreq.path, &nd);
109                 if (error)
110                         return error;
111
112                 ASSERT(nd.dentry);
113                 ASSERT(nd.dentry->d_inode);
114                 inode = igrab(nd.dentry->d_inode);
115                 path_release(&nd);
116                 break;
117         }
118
119         case XFS_IOC_FD_TO_HANDLE: {
120                 struct file     *file;
121
122                 file = fget(hreq.fd);
123                 if (!file)
124                     return -EBADF;
125
126                 ASSERT(file->f_dentry);
127                 ASSERT(file->f_dentry->d_inode);
128                 inode = igrab(file->f_dentry->d_inode);
129                 fput(file);
130                 break;
131         }
132
133         default:
134                 ASSERT(0);
135                 return -XFS_ERROR(EINVAL);
136         }
137
138         if (inode->i_sb->s_magic != XFS_SB_MAGIC) {
139                 /* we're not in XFS anymore, Toto */
140                 iput(inode);
141                 return -XFS_ERROR(EINVAL);
142         }
143
144         /* we need the vnode */
145         vp = LINVFS_GET_VP(inode);
146         if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
147                 iput(inode);
148                 return -XFS_ERROR(EBADF);
149         }
150
151         /* now we can grab the fsid */
152         memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));
153         hsize = sizeof(xfs_fsid_t);
154
155         if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {
156                 xfs_inode_t     *ip;
157                 bhv_desc_t      *bhv;
158                 int             lock_mode;
159
160                 /* need to get access to the xfs_inode to read the generation */
161                 bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);
162                 ASSERT(bhv);
163                 ip = XFS_BHVTOI(bhv);
164                 ASSERT(ip);
165                 lock_mode = xfs_ilock_map_shared(ip);
166
167                 /* fill in fid section of handle from inode */
168                 handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) -
169                                             sizeof(handle.ha_fid.xfs_fid_len);
170                 handle.ha_fid.xfs_fid_pad = 0;
171                 handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen;
172                 handle.ha_fid.xfs_fid_ino = ip->i_ino;
173
174                 xfs_iunlock_map_shared(ip, lock_mode);
175
176                 hsize = XFS_HSIZE(handle);
177         }
178
179         /* now copy our handle into the user buffer & write out the size */
180         if (copy_to_user(hreq.ohandle, &handle, hsize) ||
181             copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {
182                 iput(inode);
183                 return -XFS_ERROR(EFAULT);
184         }
185
186         iput(inode);
187         return 0;
188 }
189
190
191 /*
192  * Convert userspace handle data into vnode (and inode).
193  * We [ab]use the fact that all the fsop_handlereq ioctl calls
194  * have a data structure argument whose first component is always
195  * a xfs_fsop_handlereq_t, so we can cast to and from this type.
196  * This allows us to optimise the copy_from_user calls and gives
197  * a handy, shared routine.
198  *
199  * If no error, caller must always VN_RELE the returned vp.
200  */
201 STATIC int
202 xfs_vget_fsop_handlereq(
203         xfs_mount_t             *mp,
204         struct inode            *parinode,      /* parent inode pointer    */
205         int                     cap,            /* capability level for op */
206         void                    __user *arg,    /* userspace data pointer  */
207         unsigned long           size,           /* size of expected struct */
208         /* output arguments */
209         xfs_fsop_handlereq_t    *hreq,
210         vnode_t                 **vp,
211         struct inode            **inode)
212 {
213         void                    __user *hanp;
214         size_t                  hlen;
215         xfs_fid_t               *xfid;
216         xfs_handle_t            *handlep;
217         xfs_handle_t            handle;
218         xfs_inode_t             *ip;
219         struct inode            *inodep;
220         vnode_t                 *vpp;
221         xfs_ino_t               ino;
222         __u32                   igen;
223         int                     error;
224
225         if (!capable(cap))
226                 return XFS_ERROR(EPERM);
227
228         /*
229          * Only allow handle opens under a directory.
230          */
231         if (!S_ISDIR(parinode->i_mode))
232                 return XFS_ERROR(ENOTDIR);
233
234         /*
235          * Copy the handle down from the user and validate
236          * that it looks to be in the correct format.
237          */
238         if (copy_from_user(hreq, arg, size))
239                 return XFS_ERROR(EFAULT);
240
241         hanp = hreq->ihandle;
242         hlen = hreq->ihandlen;
243         handlep = &handle;
244
245         if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
246                 return XFS_ERROR(EINVAL);
247         if (copy_from_user(handlep, hanp, hlen))
248                 return XFS_ERROR(EFAULT);
249         if (hlen < sizeof(*handlep))
250                 memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
251         if (hlen > sizeof(handlep->ha_fsid)) {
252                 if (handlep->ha_fid.xfs_fid_len !=
253                                 (hlen - sizeof(handlep->ha_fsid)
254                                         - sizeof(handlep->ha_fid.xfs_fid_len))
255                     || handlep->ha_fid.xfs_fid_pad)
256                         return XFS_ERROR(EINVAL);
257         }
258
259         /*
260          * Crack the handle, obtain the inode # & generation #
261          */
262         xfid = (struct xfs_fid *)&handlep->ha_fid;
263         if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
264                 ino  = xfid->xfs_fid_ino;
265                 igen = xfid->xfs_fid_gen;
266         } else {
267                 return XFS_ERROR(EINVAL);
268         }
269
270         /*
271          * Get the XFS inode, building a vnode to go with it.
272          */
273         error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
274         if (error)
275                 return error;
276         if (ip == NULL)
277                 return XFS_ERROR(EIO);
278         if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {
279                 xfs_iput_new(ip, XFS_ILOCK_SHARED);
280                 return XFS_ERROR(ENOENT);
281         }
282
283         vpp = XFS_ITOV(ip);
284         inodep = LINVFS_GET_IP(vpp);
285         xfs_iunlock(ip, XFS_ILOCK_SHARED);
286
287         *vp = vpp;
288         *inode = inodep;
289         return 0;
290 }
291
292 STATIC int
293 xfs_open_by_handle(
294         xfs_mount_t             *mp,
295         void                    __user *arg,
296         struct file             *parfilp,
297         struct inode            *parinode)
298 {
299         int                     error;
300         int                     new_fd;
301         int                     permflag;
302         struct file             *filp;
303         struct inode            *inode;
304         struct dentry           *dentry;
305         vnode_t                 *vp;
306         xfs_fsop_handlereq_t    hreq;
307
308         error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
309                                         sizeof(xfs_fsop_handlereq_t),
310                                         &hreq, &vp, &inode);
311         if (error)
312                 return -error;
313
314         /* Restrict xfs_open_by_handle to directories & regular files. */
315         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
316                 iput(inode);
317                 return -XFS_ERROR(EINVAL);
318         }
319
320 #if BITS_PER_LONG != 32
321         hreq.oflags |= O_LARGEFILE;
322 #endif
323         /* Put open permission in namei format. */
324         permflag = hreq.oflags;
325         if ((permflag+1) & O_ACCMODE)
326                 permflag++;
327         if (permflag & O_TRUNC)
328                 permflag |= 2;
329
330         if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
331             (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
332                 iput(inode);
333                 return -XFS_ERROR(EPERM);
334         }
335
336         if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
337                 iput(inode);
338                 return -XFS_ERROR(EACCES);
339         }
340
341         /* Can't write directories. */
342         if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
343                 iput(inode);
344                 return -XFS_ERROR(EISDIR);
345         }
346
347         if ((new_fd = get_unused_fd()) < 0) {
348                 iput(inode);
349                 return new_fd;
350         }
351
352         dentry = d_alloc_anon(inode);
353         if (dentry == NULL) {
354                 iput(inode);
355                 put_unused_fd(new_fd);
356                 return -XFS_ERROR(ENOMEM);
357         }
358
359         /* Ensure umount returns EBUSY on umounts while this file is open. */
360         mntget(parfilp->f_vfsmnt);
361
362         /* Create file pointer. */
363         filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
364         if (IS_ERR(filp)) {
365                 put_unused_fd(new_fd);
366                 return -XFS_ERROR(-PTR_ERR(filp));
367         }
368         if (inode->i_mode & S_IFREG)
369                 filp->f_op = &linvfs_invis_file_operations;
370
371         fd_install(new_fd, filp);
372         return new_fd;
373 }
374
375 STATIC int
376 xfs_readlink_by_handle(
377         xfs_mount_t             *mp,
378         void                    __user *arg,
379         struct file             *parfilp,
380         struct inode            *parinode)
381 {
382         int                     error;
383         struct iovec            aiov;
384         struct uio              auio;
385         struct inode            *inode;
386         xfs_fsop_handlereq_t    hreq;
387         vnode_t                 *vp;
388         __u32                   olen;
389
390         error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
391                                         sizeof(xfs_fsop_handlereq_t),
392                                         &hreq, &vp, &inode);
393         if (error)
394                 return -error;
395
396         /* Restrict this handle operation to symlinks only. */
397         if (vp->v_type != VLNK) {
398                 VN_RELE(vp);
399                 return -XFS_ERROR(EINVAL);
400         }
401
402         if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
403                 VN_RELE(vp);
404                 return -XFS_ERROR(EFAULT);
405         }
406         aiov.iov_len    = olen;
407         aiov.iov_base   = hreq.ohandle;
408
409         auio.uio_iov    = &aiov;
410         auio.uio_iovcnt = 1;
411         auio.uio_offset = 0;
412         auio.uio_segflg = UIO_USERSPACE;
413         auio.uio_resid  = olen;
414
415         VOP_READLINK(vp, &auio, IO_INVIS, NULL, error);
416
417         VN_RELE(vp);
418         return (olen - auio.uio_resid);
419 }
420
421 STATIC int
422 xfs_fssetdm_by_handle(
423         xfs_mount_t             *mp,
424         void                    __user *arg,
425         struct file             *parfilp,
426         struct inode            *parinode)
427 {
428         int                     error;
429         struct fsdmidata        fsd;
430         xfs_fsop_setdm_handlereq_t dmhreq;
431         struct inode            *inode;
432         bhv_desc_t              *bdp;
433         vnode_t                 *vp;
434
435         error = xfs_vget_fsop_handlereq(mp, parinode, CAP_MKNOD, arg,
436                                         sizeof(xfs_fsop_setdm_handlereq_t),
437                                         (xfs_fsop_handlereq_t *)&dmhreq,
438                                         &vp, &inode);
439         if (error)
440                 return -error;
441
442         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
443                 VN_RELE(vp);
444                 return -XFS_ERROR(EPERM);
445         }
446
447         if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
448                 VN_RELE(vp);
449                 return -XFS_ERROR(EFAULT);
450         }
451
452         bdp = bhv_base_unlocked(VN_BHV_HEAD(vp));
453         error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL);
454
455         VN_RELE(vp);
456         if (error)
457                 return -error;
458         return 0;
459 }
460
461 STATIC int
462 xfs_attrlist_by_handle(
463         xfs_mount_t             *mp,
464         void                    __user *arg,
465         struct file             *parfilp,
466         struct inode            *parinode)
467 {
468         int                     error;
469         attrlist_cursor_kern_t  *cursor;
470         xfs_fsop_attrlist_handlereq_t al_hreq;
471         struct inode            *inode;
472         vnode_t                 *vp;
473
474         error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
475                                         sizeof(xfs_fsop_attrlist_handlereq_t),
476                                         (xfs_fsop_handlereq_t *)&al_hreq,
477                                         &vp, &inode);
478         if (error)
479                 return -error;
480
481         cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
482         VOP_ATTR_LIST(vp, al_hreq.buffer, al_hreq.buflen, al_hreq.flags,
483                         cursor, NULL, error);
484         VN_RELE(vp);
485         if (error)
486                 return -error;
487         return 0;
488 }
489
490 STATIC int
491 xfs_attrmulti_by_handle(
492         xfs_mount_t             *mp,
493         void                    __user *arg,
494         struct file             *parfilp,
495         struct inode            *parinode)
496 {
497         int                     error;
498         xfs_attr_multiop_t      *ops;
499         xfs_fsop_attrmulti_handlereq_t am_hreq;
500         struct inode            *inode;
501         vnode_t                 *vp;
502         unsigned int            i, size;
503
504         error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg,
505                                         sizeof(xfs_fsop_attrmulti_handlereq_t),
506                                         (xfs_fsop_handlereq_t *)&am_hreq,
507                                         &vp, &inode);
508         if (error)
509                 return -error;
510
511         size = am_hreq.opcount * sizeof(attr_multiop_t);
512         if (!size || size > 16 * PAGE_SIZE) {
513                 VN_RELE(vp);
514                 return -XFS_ERROR(E2BIG);
515         }
516
517         ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL);
518         if (!ops) {
519                 VN_RELE(vp);
520                 return -XFS_ERROR(ENOMEM);
521         }
522
523         if (copy_from_user(ops, am_hreq.ops, size)) {
524                 kfree(ops);
525                 VN_RELE(vp);
526                 return -XFS_ERROR(EFAULT);
527         }
528
529         for (i = 0; i < am_hreq.opcount; i++) {
530                 switch(ops[i].am_opcode) {
531                 case ATTR_OP_GET:
532                         VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
533                                         &ops[i].am_length, ops[i].am_flags,
534                                         NULL, ops[i].am_error);
535                         break;
536                 case ATTR_OP_SET:
537                         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
538                                 ops[i].am_error = EPERM;
539                                 break;
540                         }
541                         VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
542                                         ops[i].am_length, ops[i].am_flags,
543                                         NULL, ops[i].am_error);
544                         break;
545                 case ATTR_OP_REMOVE:
546                         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
547                                 ops[i].am_error = EPERM;
548                                 break;
549                         }
550                         VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
551                                         NULL, ops[i].am_error);
552                         break;
553                 default:
554                         ops[i].am_error = EINVAL;
555                 }
556         }
557
558         if (copy_to_user(am_hreq.ops, ops, size))
559                 error = -XFS_ERROR(EFAULT);
560
561         kfree(ops);
562         VN_RELE(vp);
563         return error;
564 }
565
566 /* prototypes for a few of the stack-hungry cases that have
567  * their own functions.  Functions are defined after their use
568  * so gcc doesn't get fancy and inline them with -03 */
569
570 STATIC int
571 xfs_ioc_space(
572         bhv_desc_t              *bdp,
573         vnode_t                 *vp,
574         struct file             *filp,
575         int                     flags,
576         unsigned int            cmd,
577         void                    __user *arg);
578
579 STATIC int
580 xfs_ioc_bulkstat(
581         xfs_mount_t             *mp,
582         unsigned int            cmd,
583         void                    __user *arg);
584
585 STATIC int
586 xfs_ioc_fsgeometry_v1(
587         xfs_mount_t             *mp,
588         void                    __user *arg);
589
590 STATIC int
591 xfs_ioc_fsgeometry(
592         xfs_mount_t             *mp,
593         void                    __user *arg);
594
595 STATIC int
596 xfs_ioc_xattr(
597         vnode_t                 *vp,
598         xfs_inode_t             *ip,
599         struct file             *filp,
600         unsigned int            cmd,
601         void                    __user *arg);
602
603 STATIC int
604 xfs_ioc_getbmap(
605         bhv_desc_t              *bdp,
606         struct file             *filp,
607         int                     flags,
608         unsigned int            cmd,
609         void                    __user *arg);
610
611 STATIC int
612 xfs_ioc_getbmapx(
613         bhv_desc_t              *bdp,
614         void                    __user *arg);
615
616 int
617 xfs_ioctl(
618         bhv_desc_t              *bdp,
619         struct inode            *inode,
620         struct file             *filp,
621         int                     ioflags,
622         unsigned int            cmd,
623         void                    __user *arg)
624 {
625         int                     error;
626         vnode_t                 *vp;
627         xfs_inode_t             *ip;
628         xfs_mount_t             *mp;
629
630         vp = LINVFS_GET_VP(inode);
631
632         vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address);
633
634         ip = XFS_BHVTOI(bdp);
635         mp = ip->i_mount;
636
637         switch (cmd) {
638
639         case XFS_IOC_ALLOCSP:
640         case XFS_IOC_FREESP:
641         case XFS_IOC_RESVSP:
642         case XFS_IOC_UNRESVSP:
643         case XFS_IOC_ALLOCSP64:
644         case XFS_IOC_FREESP64:
645         case XFS_IOC_RESVSP64:
646         case XFS_IOC_UNRESVSP64:
647                 /*
648                  * Only allow the sys admin to reserve space unless
649                  * unwritten extents are enabled.
650                  */
651                 if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) &&
652                     !capable(CAP_SYS_ADMIN))
653                         return -EPERM;
654
655                 return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
656
657         case XFS_IOC_DIOINFO: {
658                 struct dioattr  da;
659                 xfs_buftarg_t   *target =
660                         (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
661                         mp->m_rtdev_targp : mp->m_ddev_targp;
662
663                 da.d_mem = da.d_miniosz = 1 << target->pbr_sshift;
664                 /* The size dio will do in one go */
665                 da.d_maxiosz = 64 * PAGE_CACHE_SIZE;
666
667                 if (copy_to_user(arg, &da, sizeof(da)))
668                         return -XFS_ERROR(EFAULT);
669                 return 0;
670         }
671
672         case XFS_IOC_FSBULKSTAT_SINGLE:
673         case XFS_IOC_FSBULKSTAT:
674         case XFS_IOC_FSINUMBERS:
675                 return xfs_ioc_bulkstat(mp, cmd, arg);
676
677         case XFS_IOC_FSGEOMETRY_V1:
678                 return xfs_ioc_fsgeometry_v1(mp, arg);
679
680         case XFS_IOC_FSGEOMETRY:
681                 return xfs_ioc_fsgeometry(mp, arg);
682
683         case XFS_IOC_GETVERSION:
684         case XFS_IOC_GETXFLAGS:
685         case XFS_IOC_SETXFLAGS:
686         case XFS_IOC_FSGETXATTR:
687         case XFS_IOC_FSSETXATTR:
688         case XFS_IOC_FSGETXATTRA:
689                 return xfs_ioc_xattr(vp, ip, filp, cmd, arg);
690
691         case XFS_IOC_FSSETDM: {
692                 struct fsdmidata        dmi;
693
694                 if (copy_from_user(&dmi, arg, sizeof(dmi)))
695                         return -XFS_ERROR(EFAULT);
696
697                 error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate,
698                                                         NULL);
699                 return -error;
700         }
701
702         case XFS_IOC_GETBMAP:
703         case XFS_IOC_GETBMAPA:
704                 return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg);
705
706         case XFS_IOC_GETBMAPX:
707                 return xfs_ioc_getbmapx(bdp, arg);
708
709         case XFS_IOC_FD_TO_HANDLE:
710         case XFS_IOC_PATH_TO_HANDLE:
711         case XFS_IOC_PATH_TO_FSHANDLE:
712                 return xfs_find_handle(cmd, arg);
713
714         case XFS_IOC_OPEN_BY_HANDLE:
715                 return xfs_open_by_handle(mp, arg, filp, inode);
716
717         case XFS_IOC_FSSETDM_BY_HANDLE:
718                 return xfs_fssetdm_by_handle(mp, arg, filp, inode);
719
720         case XFS_IOC_READLINK_BY_HANDLE:
721                 return xfs_readlink_by_handle(mp, arg, filp, inode);
722
723         case XFS_IOC_ATTRLIST_BY_HANDLE:
724                 return xfs_attrlist_by_handle(mp, arg, filp, inode);
725
726         case XFS_IOC_ATTRMULTI_BY_HANDLE:
727                 return xfs_attrmulti_by_handle(mp, arg, filp, inode);
728
729         case XFS_IOC_SWAPEXT: {
730                 error = xfs_swapext((struct xfs_swapext __user *)arg);
731                 return -error;
732         }
733
734         case XFS_IOC_FSCOUNTS: {
735                 xfs_fsop_counts_t out;
736
737                 error = xfs_fs_counts(mp, &out);
738                 if (error)
739                         return -error;
740
741                 if (copy_to_user(arg, &out, sizeof(out)))
742                         return -XFS_ERROR(EFAULT);
743                 return 0;
744         }
745
746         case XFS_IOC_SET_RESBLKS: {
747                 xfs_fsop_resblks_t inout;
748                 __uint64_t         in;
749
750                 if (!capable(CAP_SYS_ADMIN))
751                         return -EPERM;
752
753                 if (copy_from_user(&inout, arg, sizeof(inout)))
754                         return -XFS_ERROR(EFAULT);
755
756                 /* input parameter is passed in resblks field of structure */
757                 in = inout.resblks;
758                 error = xfs_reserve_blocks(mp, &in, &inout);
759                 if (error)
760                         return -error;
761
762                 if (copy_to_user(arg, &inout, sizeof(inout)))
763                         return -XFS_ERROR(EFAULT);
764                 return 0;
765         }
766
767         case XFS_IOC_GET_RESBLKS: {
768                 xfs_fsop_resblks_t out;
769
770                 if (!capable(CAP_SYS_ADMIN))
771                         return -EPERM;
772
773                 error = xfs_reserve_blocks(mp, NULL, &out);
774                 if (error)
775                         return -error;
776
777                 if (copy_to_user(arg, &out, sizeof(out)))
778                         return -XFS_ERROR(EFAULT);
779
780                 return 0;
781         }
782
783         case XFS_IOC_FSGROWFSDATA: {
784                 xfs_growfs_data_t in;
785
786                 if (!capable(CAP_SYS_ADMIN))
787                         return -EPERM;
788
789                 if (copy_from_user(&in, arg, sizeof(in)))
790                         return -XFS_ERROR(EFAULT);
791
792                 error = xfs_growfs_data(mp, &in);
793                 return -error;
794         }
795
796         case XFS_IOC_FSGROWFSLOG: {
797                 xfs_growfs_log_t in;
798
799                 if (!capable(CAP_SYS_ADMIN))
800                         return -EPERM;
801
802                 if (copy_from_user(&in, arg, sizeof(in)))
803                         return -XFS_ERROR(EFAULT);
804
805                 error = xfs_growfs_log(mp, &in);
806                 return -error;
807         }
808
809         case XFS_IOC_FSGROWFSRT: {
810                 xfs_growfs_rt_t in;
811
812                 if (!capable(CAP_SYS_ADMIN))
813                         return -EPERM;
814
815                 if (copy_from_user(&in, arg, sizeof(in)))
816                         return -XFS_ERROR(EFAULT);
817
818                 error = xfs_growfs_rt(mp, &in);
819                 return -error;
820         }
821
822         case XFS_IOC_FREEZE:
823                 if (!capable(CAP_SYS_ADMIN))
824                         return -EPERM;
825
826                 if (inode->i_sb->s_frozen == SB_UNFROZEN)
827                         freeze_bdev(inode->i_sb->s_bdev);
828                 return 0;
829
830         case XFS_IOC_THAW:
831                 if (!capable(CAP_SYS_ADMIN))
832                         return -EPERM;
833                 if (inode->i_sb->s_frozen != SB_UNFROZEN)
834                         thaw_bdev(inode->i_sb->s_bdev, inode->i_sb);
835                 return 0;
836
837         case XFS_IOC_GOINGDOWN: {
838                 __uint32_t in;
839
840                 if (!capable(CAP_SYS_ADMIN))
841                         return -EPERM;
842
843                 if (get_user(in, (__uint32_t __user *)arg))
844                         return -XFS_ERROR(EFAULT);
845
846                 error = xfs_fs_goingdown(mp, in);
847                 return -error;
848         }
849
850         case XFS_IOC_ERROR_INJECTION: {
851                 xfs_error_injection_t in;
852
853                 if (!capable(CAP_SYS_ADMIN))
854                         return -EPERM;
855
856                 if (copy_from_user(&in, arg, sizeof(in)))
857                         return -XFS_ERROR(EFAULT);
858
859                 error = xfs_errortag_add(in.errtag, mp);
860                 return -error;
861         }
862
863         case XFS_IOC_ERROR_CLEARALL:
864                 if (!capable(CAP_SYS_ADMIN))
865                         return -EPERM;
866
867                 error = xfs_errortag_clearall(mp);
868                 return -error;
869
870         default:
871                 return -ENOTTY;
872         }
873 }
874
875 STATIC int
876 xfs_ioc_space(
877         bhv_desc_t              *bdp,
878         vnode_t                 *vp,
879         struct file             *filp,
880         int                     ioflags,
881         unsigned int            cmd,
882         void                    __user *arg)
883 {
884         xfs_flock64_t           bf;
885         int                     attr_flags = 0;
886         int                     error;
887
888         if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
889                 return -XFS_ERROR(EPERM);
890
891         if (!(filp->f_flags & FMODE_WRITE))
892                 return -XFS_ERROR(EBADF);
893
894         if (vp->v_type != VREG)
895                 return -XFS_ERROR(EINVAL);
896
897         if (copy_from_user(&bf, arg, sizeof(bf)))
898                 return -XFS_ERROR(EFAULT);
899
900         if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
901                 attr_flags |= ATTR_NONBLOCK;
902         if (ioflags & IO_INVIS)
903                 attr_flags |= ATTR_DMI;
904
905         error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos,
906                                               NULL, attr_flags);
907         return -error;
908 }
909
910 STATIC int
911 xfs_ioc_bulkstat(
912         xfs_mount_t             *mp,
913         unsigned int            cmd,
914         void                    __user *arg)
915 {
916         xfs_fsop_bulkreq_t      bulkreq;
917         int                     count;  /* # of records returned */
918         xfs_ino_t               inlast; /* last inode number */
919         int                     done;
920         int                     error;
921
922         /* done = 1 if there are more stats to get and if bulkstat */
923         /* should be called again (unused here, but used in dmapi) */
924
925         if (!capable(CAP_SYS_ADMIN))
926                 return -EPERM;
927
928         if (XFS_FORCED_SHUTDOWN(mp))
929                 return -XFS_ERROR(EIO);
930
931         if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
932                 return -XFS_ERROR(EFAULT);
933
934         if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
935                 return -XFS_ERROR(EFAULT);
936
937         if ((count = bulkreq.icount) <= 0)
938                 return -XFS_ERROR(EINVAL);
939
940         if (cmd == XFS_IOC_FSINUMBERS)
941                 error = xfs_inumbers(mp, &inlast, &count,
942                                                 bulkreq.ubuffer);
943         else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
944                 error = xfs_bulkstat_single(mp, &inlast,
945                                                 bulkreq.ubuffer, &done);
946         else {  /* XFS_IOC_FSBULKSTAT */
947                 if (count == 1 && inlast != 0) {
948                         inlast++;
949                         error = xfs_bulkstat_single(mp, &inlast,
950                                         bulkreq.ubuffer, &done);
951                 } else {
952                         error = xfs_bulkstat(mp, &inlast, &count,
953                                 (bulkstat_one_pf)xfs_bulkstat_one, NULL,
954                                 sizeof(xfs_bstat_t), bulkreq.ubuffer,
955                                 BULKSTAT_FG_QUICK, &done);
956                 }
957         }
958
959         if (error)
960                 return -error;
961
962         if (bulkreq.ocount != NULL) {
963                 if (copy_to_user(bulkreq.lastip, &inlast,
964                                                 sizeof(xfs_ino_t)))
965                         return -XFS_ERROR(EFAULT);
966
967                 if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
968                         return -XFS_ERROR(EFAULT);
969         }
970
971         return 0;
972 }
973
974 STATIC int
975 xfs_ioc_fsgeometry_v1(
976         xfs_mount_t             *mp,
977         void                    __user *arg)
978 {
979         xfs_fsop_geom_v1_t      fsgeo;
980         int                     error;
981
982         error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
983         if (error)
984                 return -error;
985
986         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
987                 return -XFS_ERROR(EFAULT);
988         return 0;
989 }
990
991 STATIC int
992 xfs_ioc_fsgeometry(
993         xfs_mount_t             *mp,
994         void                    __user *arg)
995 {
996         xfs_fsop_geom_t         fsgeo;
997         int                     error;
998
999         error = xfs_fs_geometry(mp, &fsgeo, 4);
1000         if (error)
1001                 return -error;
1002
1003         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
1004                 return -XFS_ERROR(EFAULT);
1005         return 0;
1006 }
1007
1008 /*
1009  * Linux extended inode flags interface.
1010  */
1011 #define LINUX_XFLAG_SYNC        0x00000008 /* Synchronous updates */
1012 #define LINUX_XFLAG_IMMUTABLE   0x00000010 /* Immutable file */
1013 #define LINUX_XFLAG_APPEND      0x00000020 /* writes to file may only append */
1014 #define LINUX_XFLAG_NODUMP      0x00000040 /* do not dump file */
1015 #define LINUX_XFLAG_NOATIME     0x00000080 /* do not update atime */
1016 #define LINUX_XFLAG_BARRIER     0x00004000 /* chroot() barrier */
1017 #define LINUX_XFLAG_IUNLINK     0x00008000 /* immutable unlink */
1018
1019 STATIC unsigned int
1020 xfs_merge_ioc_xflags(
1021         unsigned int    flags,
1022         unsigned int    start)
1023 {
1024         unsigned int    xflags = start;
1025
1026         if (flags & LINUX_XFLAG_IMMUTABLE)
1027                 xflags |= XFS_XFLAG_IMMUTABLE;
1028         else
1029                 xflags &= ~XFS_XFLAG_IMMUTABLE;
1030         if (flags & LINUX_XFLAG_APPEND)
1031                 xflags |= XFS_XFLAG_APPEND;
1032         else
1033                 xflags &= ~XFS_XFLAG_APPEND;
1034         if (flags & LINUX_XFLAG_SYNC)
1035                 xflags |= XFS_XFLAG_SYNC;
1036         else
1037                 xflags &= ~XFS_XFLAG_SYNC;
1038         if (flags & LINUX_XFLAG_NOATIME)
1039                 xflags |= XFS_XFLAG_NOATIME;
1040         else
1041                 xflags &= ~XFS_XFLAG_NOATIME;
1042         if (flags & LINUX_XFLAG_NODUMP)
1043                 xflags |= XFS_XFLAG_NODUMP;
1044         else
1045                 xflags &= ~XFS_XFLAG_NODUMP;
1046
1047         return xflags;
1048 }
1049
1050 STATIC unsigned int
1051 xfs_di2lxflags(
1052         __uint16_t      di_flags)
1053 {
1054         unsigned int    flags = 0;
1055
1056         if (di_flags & XFS_DIFLAG_IMMUTABLE)
1057                 flags |= LINUX_XFLAG_IMMUTABLE;
1058         if (di_flags & XFS_DIFLAG_IUNLINK)
1059                 flags |= LINUX_XFLAG_IUNLINK;
1060         if (di_flags & XFS_DIFLAG_BARRIER)
1061                 flags |= LINUX_XFLAG_BARRIER;
1062         if (di_flags & XFS_DIFLAG_APPEND)
1063                 flags |= LINUX_XFLAG_APPEND;
1064         if (di_flags & XFS_DIFLAG_SYNC)
1065                 flags |= LINUX_XFLAG_SYNC;
1066         if (di_flags & XFS_DIFLAG_NOATIME)
1067                 flags |= LINUX_XFLAG_NOATIME;
1068         if (di_flags & XFS_DIFLAG_NODUMP)
1069                 flags |= LINUX_XFLAG_NODUMP;
1070         return flags;
1071 }
1072
1073 STATIC int
1074 xfs_ioc_xattr(
1075         vnode_t                 *vp,
1076         xfs_inode_t             *ip,
1077         struct file             *filp,
1078         unsigned int            cmd,
1079         void                    __user *arg)
1080 {
1081         struct fsxattr          fa;
1082         vattr_t                 va;
1083         int                     error;
1084         int                     attr_flags;
1085         unsigned int            flags;
1086
1087         switch (cmd) {
1088         case XFS_IOC_FSGETXATTR: {
1089                 va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS;
1090                 VOP_GETATTR(vp, &va, 0, NULL, error);
1091                 if (error)
1092                         return -error;
1093
1094                 fa.fsx_xflags   = va.va_xflags;
1095                 fa.fsx_extsize  = va.va_extsize;
1096                 fa.fsx_nextents = va.va_nextents;
1097
1098                 if (copy_to_user(arg, &fa, sizeof(fa)))
1099                         return -XFS_ERROR(EFAULT);
1100                 return 0;
1101         }
1102
1103         case XFS_IOC_FSSETXATTR: {
1104                 if (copy_from_user(&fa, arg, sizeof(fa)))
1105                         return -XFS_ERROR(EFAULT);
1106
1107                 attr_flags = 0;
1108                 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1109                         attr_flags |= ATTR_NONBLOCK;
1110
1111                 va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
1112                 va.va_xflags  = fa.fsx_xflags;
1113                 va.va_extsize = fa.fsx_extsize;
1114
1115                 VOP_SETATTR(vp, &va, attr_flags, NULL, error);
1116                 if (!error)
1117                         vn_revalidate(vp);      /* update Linux inode flags */
1118                 return -error;
1119         }
1120
1121         case XFS_IOC_FSGETXATTRA: {
1122                 va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS;
1123                 VOP_GETATTR(vp, &va, 0, NULL, error);
1124                 if (error)
1125                         return -error;
1126
1127                 fa.fsx_xflags   = va.va_xflags;
1128                 fa.fsx_extsize  = va.va_extsize;
1129                 fa.fsx_nextents = va.va_anextents;
1130
1131                 if (copy_to_user(arg, &fa, sizeof(fa)))
1132                         return -XFS_ERROR(EFAULT);
1133                 return 0;
1134         }
1135
1136         case XFS_IOC_GETXFLAGS: {
1137                 flags = xfs_di2lxflags(ip->i_d.di_flags);
1138                 if (copy_to_user(arg, &flags, sizeof(flags)))
1139                         return -XFS_ERROR(EFAULT);
1140                 return 0;
1141         }
1142
1143         case XFS_IOC_SETXFLAGS: {
1144                 if (copy_from_user(&flags, arg, sizeof(flags)))
1145                         return -XFS_ERROR(EFAULT);
1146
1147                 if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \
1148                               LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \
1149                               LINUX_XFLAG_SYNC))
1150                         return -XFS_ERROR(EOPNOTSUPP);
1151
1152                 attr_flags = 0;
1153                 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1154                         attr_flags |= ATTR_NONBLOCK;
1155
1156                 va.va_mask = XFS_AT_XFLAGS;
1157                 va.va_xflags = xfs_merge_ioc_xflags(flags,
1158                                 xfs_dic2xflags(&ip->i_d, ARCH_NOCONVERT));
1159
1160                 VOP_SETATTR(vp, &va, attr_flags, NULL, error);
1161                 if (!error)
1162                         vn_revalidate(vp);      /* update Linux inode flags */
1163                 return -error;
1164         }
1165
1166         case XFS_IOC_GETVERSION: {
1167                 flags = LINVFS_GET_IP(vp)->i_generation;
1168                 if (copy_to_user(arg, &flags, sizeof(flags)))
1169                         return -XFS_ERROR(EFAULT);
1170                 return 0;
1171         }
1172
1173         default:
1174                 return -ENOTTY;
1175         }
1176 }
1177
1178 STATIC int
1179 xfs_ioc_getbmap(
1180         bhv_desc_t              *bdp,
1181         struct file             *filp,
1182         int                     ioflags,
1183         unsigned int            cmd,
1184         void                    __user *arg)
1185 {
1186         struct getbmap          bm;
1187         int                     iflags;
1188         int                     error;
1189
1190         if (copy_from_user(&bm, arg, sizeof(bm)))
1191                 return -XFS_ERROR(EFAULT);
1192
1193         if (bm.bmv_count < 2)
1194                 return -XFS_ERROR(EINVAL);
1195
1196         iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
1197         if (ioflags & IO_INVIS)
1198                 iflags |= BMV_IF_NO_DMAPI_READ;
1199
1200         error = xfs_getbmap(bdp, &bm, (struct getbmap __user *)arg+1, iflags);
1201         if (error)
1202                 return -error;
1203
1204         if (copy_to_user(arg, &bm, sizeof(bm)))
1205                 return -XFS_ERROR(EFAULT);
1206         return 0;
1207 }
1208
1209 STATIC int
1210 xfs_ioc_getbmapx(
1211         bhv_desc_t              *bdp,
1212         void                    __user *arg)
1213 {
1214         struct getbmapx         bmx;
1215         struct getbmap          bm;
1216         int                     iflags;
1217         int                     error;
1218
1219         if (copy_from_user(&bmx, arg, sizeof(bmx)))
1220                 return -XFS_ERROR(EFAULT);
1221
1222         if (bmx.bmv_count < 2)
1223                 return -XFS_ERROR(EINVAL);
1224
1225         /*
1226          * Map input getbmapx structure to a getbmap
1227          * structure for xfs_getbmap.
1228          */
1229         GETBMAP_CONVERT(bmx, bm);
1230
1231         iflags = bmx.bmv_iflags;
1232
1233         if (iflags & (~BMV_IF_VALID))
1234                 return -XFS_ERROR(EINVAL);
1235
1236         iflags |= BMV_IF_EXTENDED;
1237
1238         error = xfs_getbmap(bdp, &bm, (struct getbmapx __user *)arg+1, iflags);
1239         if (error)
1240                 return -error;
1241
1242         GETBMAP_CONVERT(bm, bmx);
1243
1244         if (copy_to_user(arg, &bmx, sizeof(bmx)))
1245                 return -XFS_ERROR(EFAULT);
1246
1247         return 0;
1248 }