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