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