upgrade to linux 2.6.10-1.12_FC2
[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         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         if(am_hreq.opcount > 1024) {
512                 VN_RELE(vp);
513                 return -XFS_ERROR(ENOMEM);
514         }
515         size = am_hreq.opcount * sizeof(attr_multiop_t);
516         ops = (xfs_attr_multiop_t *)kmalloc(size, GFP_KERNEL);
517         if (!ops) {
518                 VN_RELE(vp);
519                 return -XFS_ERROR(ENOMEM);
520         }
521
522         if (copy_from_user(ops, am_hreq.ops, size)) {
523                 kfree(ops);
524                 VN_RELE(vp);
525                 return -XFS_ERROR(EFAULT);
526         }
527
528         for (i = 0; i < am_hreq.opcount; i++) {
529                 switch(ops[i].am_opcode) {
530                 case ATTR_OP_GET:
531                         VOP_ATTR_GET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
532                                         &ops[i].am_length, ops[i].am_flags,
533                                         NULL, ops[i].am_error);
534                         break;
535                 case ATTR_OP_SET:
536                         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
537                                 ops[i].am_error = EPERM;
538                                 break;
539                         }
540                         VOP_ATTR_SET(vp,ops[i].am_attrname, ops[i].am_attrvalue,
541                                         ops[i].am_length, ops[i].am_flags,
542                                         NULL, ops[i].am_error);
543                         break;
544                 case ATTR_OP_REMOVE:
545                         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
546                                 ops[i].am_error = EPERM;
547                                 break;
548                         }
549                         VOP_ATTR_REMOVE(vp, ops[i].am_attrname, ops[i].am_flags,
550                                         NULL, ops[i].am_error);
551                         break;
552                 default:
553                         ops[i].am_error = EINVAL;
554                 }
555         }
556
557         if (copy_to_user(am_hreq.ops, ops, size))
558                 error = -XFS_ERROR(EFAULT);
559
560         kfree(ops);
561         VN_RELE(vp);
562         return error;
563 }
564
565 /* prototypes for a few of the stack-hungry cases that have
566  * their own functions.  Functions are defined after their use
567  * so gcc doesn't get fancy and inline them with -03 */
568
569 STATIC int
570 xfs_ioc_space(
571         bhv_desc_t              *bdp,
572         vnode_t                 *vp,
573         struct file             *filp,
574         int                     flags,
575         unsigned int            cmd,
576         void                    __user *arg);
577
578 STATIC int
579 xfs_ioc_bulkstat(
580         xfs_mount_t             *mp,
581         unsigned int            cmd,
582         void                    __user *arg);
583
584 STATIC int
585 xfs_ioc_fsgeometry_v1(
586         xfs_mount_t             *mp,
587         void                    __user *arg);
588
589 STATIC int
590 xfs_ioc_fsgeometry(
591         xfs_mount_t             *mp,
592         void                    __user *arg);
593
594 STATIC int
595 xfs_ioc_xattr(
596         vnode_t                 *vp,
597         xfs_inode_t             *ip,
598         struct file             *filp,
599         unsigned int            cmd,
600         void                    __user *arg);
601
602 STATIC int
603 xfs_ioc_getbmap(
604         bhv_desc_t              *bdp,
605         struct file             *filp,
606         int                     flags,
607         unsigned int            cmd,
608         void                    __user *arg);
609
610 STATIC int
611 xfs_ioc_getbmapx(
612         bhv_desc_t              *bdp,
613         void                    __user *arg);
614
615 int
616 xfs_ioctl(
617         bhv_desc_t              *bdp,
618         struct inode            *inode,
619         struct file             *filp,
620         int                     ioflags,
621         unsigned int            cmd,
622         void                    __user *arg)
623 {
624         int                     error;
625         vnode_t                 *vp;
626         xfs_inode_t             *ip;
627         xfs_mount_t             *mp;
628
629         vp = LINVFS_GET_VP(inode);
630
631         vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address);
632
633         ip = XFS_BHVTOI(bdp);
634         mp = ip->i_mount;
635
636         switch (cmd) {
637
638         case XFS_IOC_ALLOCSP:
639         case XFS_IOC_FREESP:
640         case XFS_IOC_RESVSP:
641         case XFS_IOC_UNRESVSP:
642         case XFS_IOC_ALLOCSP64:
643         case XFS_IOC_FREESP64:
644         case XFS_IOC_RESVSP64:
645         case XFS_IOC_UNRESVSP64:
646                 /*
647                  * Only allow the sys admin to reserve space unless
648                  * unwritten extents are enabled.
649                  */
650                 if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) &&
651                     !capable(CAP_SYS_ADMIN))
652                         return -EPERM;
653
654                 return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
655
656         case XFS_IOC_DIOINFO: {
657                 struct dioattr  da;
658                 xfs_buftarg_t   *target =
659                         (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
660                         mp->m_rtdev_targp : mp->m_ddev_targp;
661
662                 da.d_mem = da.d_miniosz = 1 << target->pbr_sshift;
663                 /* The size dio will do in one go */
664                 da.d_maxiosz = 64 * PAGE_CACHE_SIZE;
665
666                 if (copy_to_user(arg, &da, sizeof(da)))
667                         return -XFS_ERROR(EFAULT);
668                 return 0;
669         }
670
671         case XFS_IOC_FSBULKSTAT_SINGLE:
672         case XFS_IOC_FSBULKSTAT:
673         case XFS_IOC_FSINUMBERS:
674                 return xfs_ioc_bulkstat(mp, cmd, arg);
675
676         case XFS_IOC_FSGEOMETRY_V1:
677                 return xfs_ioc_fsgeometry_v1(mp, arg);
678
679         case XFS_IOC_FSGEOMETRY:
680                 return xfs_ioc_fsgeometry(mp, arg);
681
682         case XFS_IOC_GETVERSION:
683         case XFS_IOC_GETXFLAGS:
684         case XFS_IOC_SETXFLAGS:
685         case XFS_IOC_FSGETXATTR:
686         case XFS_IOC_FSSETXATTR:
687         case XFS_IOC_FSGETXATTRA:
688                 return xfs_ioc_xattr(vp, ip, filp, cmd, arg);
689
690         case XFS_IOC_FSSETDM: {
691                 struct fsdmidata        dmi;
692
693                 if (copy_from_user(&dmi, arg, sizeof(dmi)))
694                         return -XFS_ERROR(EFAULT);
695
696                 error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate,
697                                                         NULL);
698                 return -error;
699         }
700
701         case XFS_IOC_GETBMAP:
702         case XFS_IOC_GETBMAPA:
703                 return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg);
704
705         case XFS_IOC_GETBMAPX:
706                 return xfs_ioc_getbmapx(bdp, arg);
707
708         case XFS_IOC_FD_TO_HANDLE:
709         case XFS_IOC_PATH_TO_HANDLE:
710         case XFS_IOC_PATH_TO_FSHANDLE:
711                 return xfs_find_handle(cmd, arg);
712
713         case XFS_IOC_OPEN_BY_HANDLE:
714                 return xfs_open_by_handle(mp, arg, filp, inode);
715
716         case XFS_IOC_FSSETDM_BY_HANDLE:
717                 return xfs_fssetdm_by_handle(mp, arg, filp, inode);
718
719         case XFS_IOC_READLINK_BY_HANDLE:
720                 return xfs_readlink_by_handle(mp, arg, filp, inode);
721
722         case XFS_IOC_ATTRLIST_BY_HANDLE:
723                 return xfs_attrlist_by_handle(mp, arg, filp, inode);
724
725         case XFS_IOC_ATTRMULTI_BY_HANDLE:
726                 return xfs_attrmulti_by_handle(mp, arg, filp, inode);
727
728         case XFS_IOC_SWAPEXT: {
729                 error = xfs_swapext((struct xfs_swapext __user *)arg);
730                 return -error;
731         }
732
733         case XFS_IOC_FSCOUNTS: {
734                 xfs_fsop_counts_t out;
735
736                 error = xfs_fs_counts(mp, &out);
737                 if (error)
738                         return -error;
739
740                 if (copy_to_user(arg, &out, sizeof(out)))
741                         return -XFS_ERROR(EFAULT);
742                 return 0;
743         }
744
745         case XFS_IOC_SET_RESBLKS: {
746                 xfs_fsop_resblks_t inout;
747                 __uint64_t         in;
748
749                 if (!capable(CAP_SYS_ADMIN))
750                         return -EPERM;
751
752                 if (copy_from_user(&inout, arg, sizeof(inout)))
753                         return -XFS_ERROR(EFAULT);
754
755                 /* input parameter is passed in resblks field of structure */
756                 in = inout.resblks;
757                 error = xfs_reserve_blocks(mp, &in, &inout);
758                 if (error)
759                         return -error;
760
761                 if (copy_to_user(arg, &inout, sizeof(inout)))
762                         return -XFS_ERROR(EFAULT);
763                 return 0;
764         }
765
766         case XFS_IOC_GET_RESBLKS: {
767                 xfs_fsop_resblks_t out;
768
769                 if (!capable(CAP_SYS_ADMIN))
770                         return -EPERM;
771
772                 error = xfs_reserve_blocks(mp, NULL, &out);
773                 if (error)
774                         return -error;
775
776                 if (copy_to_user(arg, &out, sizeof(out)))
777                         return -XFS_ERROR(EFAULT);
778
779                 return 0;
780         }
781
782         case XFS_IOC_FSGROWFSDATA: {
783                 xfs_growfs_data_t in;
784
785                 if (!capable(CAP_SYS_ADMIN))
786                         return -EPERM;
787
788                 if (copy_from_user(&in, arg, sizeof(in)))
789                         return -XFS_ERROR(EFAULT);
790
791                 error = xfs_growfs_data(mp, &in);
792                 return -error;
793         }
794
795         case XFS_IOC_FSGROWFSLOG: {
796                 xfs_growfs_log_t in;
797
798                 if (!capable(CAP_SYS_ADMIN))
799                         return -EPERM;
800
801                 if (copy_from_user(&in, arg, sizeof(in)))
802                         return -XFS_ERROR(EFAULT);
803
804                 error = xfs_growfs_log(mp, &in);
805                 return -error;
806         }
807
808         case XFS_IOC_FSGROWFSRT: {
809                 xfs_growfs_rt_t in;
810
811                 if (!capable(CAP_SYS_ADMIN))
812                         return -EPERM;
813
814                 if (copy_from_user(&in, arg, sizeof(in)))
815                         return -XFS_ERROR(EFAULT);
816
817                 error = xfs_growfs_rt(mp, &in);
818                 return -error;
819         }
820
821         case XFS_IOC_FREEZE:
822                 if (!capable(CAP_SYS_ADMIN))
823                         return -EPERM;
824
825                 if (inode->i_sb->s_frozen == SB_UNFROZEN)
826                         freeze_bdev(inode->i_sb->s_bdev);
827                 return 0;
828
829         case XFS_IOC_THAW:
830                 if (!capable(CAP_SYS_ADMIN))
831                         return -EPERM;
832                 if (inode->i_sb->s_frozen != SB_UNFROZEN)
833                         thaw_bdev(inode->i_sb->s_bdev, inode->i_sb);
834                 return 0;
835
836         case XFS_IOC_GOINGDOWN: {
837                 __uint32_t in;
838
839                 if (!capable(CAP_SYS_ADMIN))
840                         return -EPERM;
841
842                 if (get_user(in, (__uint32_t __user *)arg))
843                         return -XFS_ERROR(EFAULT);
844
845                 error = xfs_fs_goingdown(mp, in);
846                 return -error;
847         }
848
849         case XFS_IOC_ERROR_INJECTION: {
850                 xfs_error_injection_t in;
851
852                 if (!capable(CAP_SYS_ADMIN))
853                         return -EPERM;
854
855                 if (copy_from_user(&in, arg, sizeof(in)))
856                         return -XFS_ERROR(EFAULT);
857
858                 error = xfs_errortag_add(in.errtag, mp);
859                 return -error;
860         }
861
862         case XFS_IOC_ERROR_CLEARALL:
863                 if (!capable(CAP_SYS_ADMIN))
864                         return -EPERM;
865
866                 error = xfs_errortag_clearall(mp);
867                 return -error;
868
869         default:
870                 return -ENOTTY;
871         }
872 }
873
874 STATIC int
875 xfs_ioc_space(
876         bhv_desc_t              *bdp,
877         vnode_t                 *vp,
878         struct file             *filp,
879         int                     ioflags,
880         unsigned int            cmd,
881         void                    __user *arg)
882 {
883         xfs_flock64_t           bf;
884         int                     attr_flags = 0;
885         int                     error;
886
887         if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
888                 return -XFS_ERROR(EPERM);
889
890         if (!(filp->f_flags & FMODE_WRITE))
891                 return -XFS_ERROR(EBADF);
892
893         if (vp->v_type != VREG)
894                 return -XFS_ERROR(EINVAL);
895
896         if (copy_from_user(&bf, arg, sizeof(bf)))
897                 return -XFS_ERROR(EFAULT);
898
899         if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
900                 attr_flags |= ATTR_NONBLOCK;
901         if (ioflags & IO_INVIS)
902                 attr_flags |= ATTR_DMI;
903
904         error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos,
905                                               NULL, attr_flags);
906         return -error;
907 }
908
909 STATIC int
910 xfs_ioc_bulkstat(
911         xfs_mount_t             *mp,
912         unsigned int            cmd,
913         void                    __user *arg)
914 {
915         xfs_fsop_bulkreq_t      bulkreq;
916         int                     count;  /* # of records returned */
917         xfs_ino_t               inlast; /* last inode number */
918         int                     done;
919         int                     error;
920
921         /* done = 1 if there are more stats to get and if bulkstat */
922         /* should be called again (unused here, but used in dmapi) */
923
924         if (!capable(CAP_SYS_ADMIN))
925                 return -EPERM;
926
927         if (XFS_FORCED_SHUTDOWN(mp))
928                 return -XFS_ERROR(EIO);
929
930         if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
931                 return -XFS_ERROR(EFAULT);
932
933         if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
934                 return -XFS_ERROR(EFAULT);
935
936         if ((count = bulkreq.icount) <= 0)
937                 return -XFS_ERROR(EINVAL);
938
939         if (cmd == XFS_IOC_FSINUMBERS)
940                 error = xfs_inumbers(mp, &inlast, &count,
941                                                 bulkreq.ubuffer);
942         else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
943                 error = xfs_bulkstat_single(mp, &inlast,
944                                                 bulkreq.ubuffer, &done);
945         else {  /* XFS_IOC_FSBULKSTAT */
946                 if (count == 1 && inlast != 0) {
947                         inlast++;
948                         error = xfs_bulkstat_single(mp, &inlast,
949                                         bulkreq.ubuffer, &done);
950                 } else {
951                         error = xfs_bulkstat(mp, &inlast, &count,
952                                 (bulkstat_one_pf)xfs_bulkstat_one, NULL,
953                                 sizeof(xfs_bstat_t), bulkreq.ubuffer,
954                                 BULKSTAT_FG_QUICK, &done);
955                 }
956         }
957
958         if (error)
959                 return -error;
960
961         if (bulkreq.ocount != NULL) {
962                 if (copy_to_user(bulkreq.lastip, &inlast,
963                                                 sizeof(xfs_ino_t)))
964                         return -XFS_ERROR(EFAULT);
965
966                 if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
967                         return -XFS_ERROR(EFAULT);
968         }
969
970         return 0;
971 }
972
973 STATIC int
974 xfs_ioc_fsgeometry_v1(
975         xfs_mount_t             *mp,
976         void                    __user *arg)
977 {
978         xfs_fsop_geom_v1_t      fsgeo;
979         int                     error;
980
981         error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
982         if (error)
983                 return -error;
984
985         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
986                 return -XFS_ERROR(EFAULT);
987         return 0;
988 }
989
990 STATIC int
991 xfs_ioc_fsgeometry(
992         xfs_mount_t             *mp,
993         void                    __user *arg)
994 {
995         xfs_fsop_geom_t         fsgeo;
996         int                     error;
997
998         error = xfs_fs_geometry(mp, &fsgeo, 4);
999         if (error)
1000                 return -error;
1001
1002         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
1003                 return -XFS_ERROR(EFAULT);
1004         return 0;
1005 }
1006
1007 /*
1008  * Linux extended inode flags interface.
1009  */
1010 #define LINUX_XFLAG_SYNC        0x00000008 /* Synchronous updates */
1011 #define LINUX_XFLAG_IMMUTABLE   0x00000010 /* Immutable file */
1012 #define LINUX_XFLAG_APPEND      0x00000020 /* writes to file may only append */
1013 #define LINUX_XFLAG_NODUMP      0x00000040 /* do not dump file */
1014 #define LINUX_XFLAG_NOATIME     0x00000080 /* do not update atime */
1015 #define LINUX_XFLAG_BARRIER     0x00004000 /* chroot() barrier */
1016 #define LINUX_XFLAG_IUNLINK     0x00008000 /* Immutable unlink */
1017
1018 STATIC unsigned int
1019 xfs_merge_ioc_xflags(
1020         unsigned int    flags,
1021         unsigned int    start)
1022 {
1023         unsigned int    xflags = start;
1024
1025         if (flags & LINUX_XFLAG_IMMUTABLE)
1026                 xflags |= XFS_XFLAG_IMMUTABLE;
1027         else
1028                 xflags &= ~XFS_XFLAG_IMMUTABLE;
1029         if (flags & LINUX_XFLAG_APPEND)
1030                 xflags |= XFS_XFLAG_APPEND;
1031         else
1032                 xflags &= ~XFS_XFLAG_APPEND;
1033         if (flags & LINUX_XFLAG_SYNC)
1034                 xflags |= XFS_XFLAG_SYNC;
1035         else
1036                 xflags &= ~XFS_XFLAG_SYNC;
1037         if (flags & LINUX_XFLAG_NOATIME)
1038                 xflags |= XFS_XFLAG_NOATIME;
1039         else
1040                 xflags &= ~XFS_XFLAG_NOATIME;
1041         if (flags & LINUX_XFLAG_NODUMP)
1042                 xflags |= XFS_XFLAG_NODUMP;
1043         else
1044                 xflags &= ~XFS_XFLAG_NODUMP;
1045
1046         return xflags;
1047 }
1048
1049 STATIC unsigned int
1050 xfs_di2lxflags(
1051         __uint16_t      di_flags)
1052 {
1053         unsigned int    flags = 0;
1054
1055         if (di_flags & XFS_DIFLAG_IMMUTABLE)
1056                 flags |= LINUX_XFLAG_IMMUTABLE;
1057         if (di_flags & XFS_DIFLAG_IUNLINK)
1058                 flags |= LINUX_XFLAG_IUNLINK;
1059         if (di_flags & XFS_DIFLAG_APPEND)
1060                 flags |= LINUX_XFLAG_APPEND;
1061         if (di_flags & XFS_DIFLAG_SYNC)
1062                 flags |= LINUX_XFLAG_SYNC;
1063         if (di_flags & XFS_DIFLAG_NOATIME)
1064                 flags |= LINUX_XFLAG_NOATIME;
1065         if (di_flags & XFS_DIFLAG_NODUMP)
1066                 flags |= LINUX_XFLAG_NODUMP;
1067         return flags;
1068 }
1069
1070 STATIC int
1071 xfs_ioc_xattr(
1072         vnode_t                 *vp,
1073         xfs_inode_t             *ip,
1074         struct file             *filp,
1075         unsigned int            cmd,
1076         void                    __user *arg)
1077 {
1078         struct fsxattr          fa;
1079         vattr_t                 va;
1080         int                     error;
1081         int                     attr_flags;
1082         unsigned int            flags;
1083
1084         switch (cmd) {
1085         case XFS_IOC_FSGETXATTR: {
1086                 va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS;
1087                 VOP_GETATTR(vp, &va, 0, NULL, error);
1088                 if (error)
1089                         return -error;
1090
1091                 fa.fsx_xflags   = va.va_xflags;
1092                 fa.fsx_extsize  = va.va_extsize;
1093                 fa.fsx_nextents = va.va_nextents;
1094
1095                 if (copy_to_user(arg, &fa, sizeof(fa)))
1096                         return -XFS_ERROR(EFAULT);
1097                 return 0;
1098         }
1099
1100         case XFS_IOC_FSSETXATTR: {
1101                 if (copy_from_user(&fa, arg, sizeof(fa)))
1102                         return -XFS_ERROR(EFAULT);
1103
1104                 attr_flags = 0;
1105                 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1106                         attr_flags |= ATTR_NONBLOCK;
1107                 
1108                 va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
1109                 va.va_xflags  = fa.fsx_xflags;
1110                 va.va_extsize = fa.fsx_extsize;
1111
1112                 VOP_SETATTR(vp, &va, attr_flags, NULL, error);
1113                 if (!error)
1114                         vn_revalidate(vp);      /* update Linux inode flags */
1115                 return -error;
1116         }
1117
1118         case XFS_IOC_FSGETXATTRA: {
1119                 va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS;
1120                 VOP_GETATTR(vp, &va, 0, NULL, error);
1121                 if (error)
1122                         return -error;
1123
1124                 fa.fsx_xflags   = va.va_xflags;
1125                 fa.fsx_extsize  = va.va_extsize;
1126                 fa.fsx_nextents = va.va_anextents;
1127
1128                 if (copy_to_user(arg, &fa, sizeof(fa)))
1129                         return -XFS_ERROR(EFAULT);
1130                 return 0;
1131         }
1132
1133         case XFS_IOC_GETXFLAGS: {
1134                 flags = xfs_di2lxflags(ip->i_d.di_flags);
1135                 if (copy_to_user(arg, &flags, sizeof(flags)))
1136                         return -XFS_ERROR(EFAULT);
1137                 return 0;
1138         }
1139
1140         case XFS_IOC_SETXFLAGS: {
1141                 if (copy_from_user(&flags, arg, sizeof(flags)))
1142                         return -XFS_ERROR(EFAULT);
1143
1144                 if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \
1145                               LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \
1146                               LINUX_XFLAG_SYNC))
1147                         return -XFS_ERROR(EOPNOTSUPP);
1148
1149                 attr_flags = 0;
1150                 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1151                         attr_flags |= ATTR_NONBLOCK;
1152
1153                 va.va_mask = XFS_AT_XFLAGS;
1154                 va.va_xflags = xfs_merge_ioc_xflags(flags,
1155                                 xfs_dic2xflags(&ip->i_d, ARCH_NOCONVERT));
1156
1157                 VOP_SETATTR(vp, &va, attr_flags, NULL, error);
1158                 if (!error)
1159                         vn_revalidate(vp);      /* update Linux inode flags */
1160                 return -error;
1161         }
1162
1163         case XFS_IOC_GETVERSION: {
1164                 flags = LINVFS_GET_IP(vp)->i_generation;
1165                 if (copy_to_user(arg, &flags, sizeof(flags)))
1166                         return -XFS_ERROR(EFAULT);
1167                 return 0;
1168         }
1169
1170         default:
1171                 return -ENOTTY;
1172         }
1173 }
1174
1175 STATIC int
1176 xfs_ioc_getbmap(
1177         bhv_desc_t              *bdp,
1178         struct file             *filp,
1179         int                     ioflags,
1180         unsigned int            cmd,
1181         void                    __user *arg)
1182 {
1183         struct getbmap          bm;
1184         int                     iflags;
1185         int                     error;
1186
1187         if (copy_from_user(&bm, arg, sizeof(bm)))
1188                 return -XFS_ERROR(EFAULT);
1189
1190         if (bm.bmv_count < 2)
1191                 return -XFS_ERROR(EINVAL);
1192
1193         iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
1194         if (ioflags & IO_INVIS)
1195                 iflags |= BMV_IF_NO_DMAPI_READ;
1196
1197         error = xfs_getbmap(bdp, &bm, (struct getbmap __user *)arg+1, iflags);
1198         if (error)
1199                 return -error;
1200
1201         if (copy_to_user(arg, &bm, sizeof(bm)))
1202                 return -XFS_ERROR(EFAULT);
1203         return 0;
1204 }
1205
1206 STATIC int
1207 xfs_ioc_getbmapx(
1208         bhv_desc_t              *bdp,
1209         void                    __user *arg)
1210 {
1211         struct getbmapx         bmx;
1212         struct getbmap          bm;
1213         int                     iflags;
1214         int                     error;
1215
1216         if (copy_from_user(&bmx, arg, sizeof(bmx)))
1217                 return -XFS_ERROR(EFAULT);
1218
1219         if (bmx.bmv_count < 2)
1220                 return -XFS_ERROR(EINVAL);
1221
1222         /*
1223          * Map input getbmapx structure to a getbmap
1224          * structure for xfs_getbmap.
1225          */
1226         GETBMAP_CONVERT(bmx, bm);
1227
1228         iflags = bmx.bmv_iflags;
1229
1230         if (iflags & (~BMV_IF_VALID))
1231                 return -XFS_ERROR(EINVAL);
1232
1233         iflags |= BMV_IF_EXTENDED;
1234
1235         error = xfs_getbmap(bdp, &bm, (struct getbmapx __user *)arg+1, iflags);
1236         if (error)
1237                 return -error;
1238
1239         GETBMAP_CONVERT(bm, bmx);
1240
1241         if (copy_to_user(arg, &bmx, sizeof(bmx)))
1242                 return -XFS_ERROR(EFAULT);
1243
1244         return 0;
1245 }