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