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