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