]> err.no Git - linux-2.6/blob - fs/xfs/linux-2.6/xfs_ioctl.c
[XFS] stop using uio in the readlink code
[linux-2.6] / 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 /*
353  * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's
354  * unused first argument.
355  */
356 STATIC int
357 do_readlink(
358         char __user             *buffer,
359         int                     buflen,
360         const char              *link)
361 {
362         int len;
363
364         len = PTR_ERR(link);
365         if (IS_ERR(link))
366                 goto out;
367
368         len = strlen(link);
369         if (len > (unsigned) buflen)
370                 len = buflen;
371         if (copy_to_user(buffer, link, len))
372                 len = -EFAULT;
373  out:
374         return len;
375 }
376
377
378 STATIC int
379 xfs_readlink_by_handle(
380         xfs_mount_t             *mp,
381         void                    __user *arg,
382         struct inode            *parinode)
383 {
384         struct inode            *inode;
385         xfs_fsop_handlereq_t    hreq;
386         bhv_vnode_t             *vp;
387         __u32                   olen;
388         void                    *link;
389         int                     error;
390
391         if (!capable(CAP_SYS_ADMIN))
392                 return -XFS_ERROR(EPERM);
393         if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
394                 return -XFS_ERROR(EFAULT);
395
396         error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);
397         if (error)
398                 return -error;
399
400         /* Restrict this handle operation to symlinks only. */
401         if (!S_ISLNK(inode->i_mode)) {
402                 error = -XFS_ERROR(EINVAL);
403                 goto out_iput;
404         }
405
406         if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
407                 error = -XFS_ERROR(EFAULT);
408                 goto out_iput;
409         }
410
411         link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
412         if (!link)
413                 goto out_iput;
414
415         error = -bhv_vop_readlink(vp, link);
416         if (error)
417                 goto out_kfree;
418         error = do_readlink(hreq.ohandle, olen, link);
419         if (error)
420                 goto out_kfree;
421
422  out_kfree:
423         kfree(link);
424  out_iput:
425         iput(inode);
426         return error;
427 }
428
429 STATIC int
430 xfs_fssetdm_by_handle(
431         xfs_mount_t             *mp,
432         void                    __user *arg,
433         struct inode            *parinode)
434 {
435         int                     error;
436         struct fsdmidata        fsd;
437         xfs_fsop_setdm_handlereq_t dmhreq;
438         struct inode            *inode;
439         bhv_desc_t              *bdp;
440         bhv_vnode_t             *vp;
441
442         if (!capable(CAP_MKNOD))
443                 return -XFS_ERROR(EPERM);
444         if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
445                 return -XFS_ERROR(EFAULT);
446
447         error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode);
448         if (error)
449                 return -error;
450
451         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
452                 VN_RELE(vp);
453                 return -XFS_ERROR(EPERM);
454         }
455
456         if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
457                 VN_RELE(vp);
458                 return -XFS_ERROR(EFAULT);
459         }
460
461         bdp = bhv_base_unlocked(VN_BHV_HEAD(vp));
462         error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL);
463
464         VN_RELE(vp);
465         if (error)
466                 return -error;
467         return 0;
468 }
469
470 STATIC int
471 xfs_attrlist_by_handle(
472         xfs_mount_t             *mp,
473         void                    __user *arg,
474         struct inode            *parinode)
475 {
476         int                     error;
477         attrlist_cursor_kern_t  *cursor;
478         xfs_fsop_attrlist_handlereq_t al_hreq;
479         struct inode            *inode;
480         bhv_vnode_t             *vp;
481         char                    *kbuf;
482
483         if (!capable(CAP_SYS_ADMIN))
484                 return -XFS_ERROR(EPERM);
485         if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
486                 return -XFS_ERROR(EFAULT);
487         if (al_hreq.buflen > XATTR_LIST_MAX)
488                 return -XFS_ERROR(EINVAL);
489
490         error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq,
491                         &vp, &inode);
492         if (error)
493                 goto out;
494
495         kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
496         if (!kbuf)
497                 goto out_vn_rele;
498
499         cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
500         error = bhv_vop_attr_list(vp, kbuf, al_hreq.buflen, al_hreq.flags,
501                                         cursor, NULL);
502         if (error)
503                 goto out_kfree;
504
505         if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
506                 error = -EFAULT;
507
508  out_kfree:
509         kfree(kbuf);
510  out_vn_rele:
511         VN_RELE(vp);
512  out:
513         return -error;
514 }
515
516 STATIC int
517 xfs_attrmulti_attr_get(
518         bhv_vnode_t             *vp,
519         char                    *name,
520         char                    __user *ubuf,
521         __uint32_t              *len,
522         __uint32_t              flags)
523 {
524         char                    *kbuf;
525         int                     error = EFAULT;
526         
527         if (*len > XATTR_SIZE_MAX)
528                 return EINVAL;
529         kbuf = kmalloc(*len, GFP_KERNEL);
530         if (!kbuf)
531                 return ENOMEM;
532
533         error = bhv_vop_attr_get(vp, name, kbuf, len, flags, NULL);
534         if (error)
535                 goto out_kfree;
536
537         if (copy_to_user(ubuf, kbuf, *len))
538                 error = EFAULT;
539
540  out_kfree:
541         kfree(kbuf);
542         return error;
543 }
544
545 STATIC int
546 xfs_attrmulti_attr_set(
547         bhv_vnode_t             *vp,
548         char                    *name,
549         const char              __user *ubuf,
550         __uint32_t              len,
551         __uint32_t              flags)
552 {
553         char                    *kbuf;
554         int                     error = EFAULT;
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         if (len > XATTR_SIZE_MAX)
561                 return EINVAL;
562
563         kbuf = kmalloc(len, GFP_KERNEL);
564         if (!kbuf)
565                 return ENOMEM;
566
567         if (copy_from_user(kbuf, ubuf, len))
568                 goto out_kfree;
569                         
570         error = bhv_vop_attr_set(vp, name, kbuf, len, flags, NULL);
571
572  out_kfree:
573         kfree(kbuf);
574         return error;
575 }
576
577 STATIC int
578 xfs_attrmulti_attr_remove(
579         bhv_vnode_t             *vp,
580         char                    *name,
581         __uint32_t              flags)
582 {
583         if (IS_RDONLY(&vp->v_inode))
584                 return -EROFS;
585         if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
586                 return EPERM;
587         return bhv_vop_attr_remove(vp, name, flags, NULL);
588 }
589
590 STATIC int
591 xfs_attrmulti_by_handle(
592         xfs_mount_t             *mp,
593         void                    __user *arg,
594         struct inode            *parinode)
595 {
596         int                     error;
597         xfs_attr_multiop_t      *ops;
598         xfs_fsop_attrmulti_handlereq_t am_hreq;
599         struct inode            *inode;
600         bhv_vnode_t             *vp;
601         unsigned int            i, size;
602         char                    *attr_name;
603
604         if (!capable(CAP_SYS_ADMIN))
605                 return -XFS_ERROR(EPERM);
606         if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
607                 return -XFS_ERROR(EFAULT);
608
609         error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &vp, &inode);
610         if (error)
611                 goto out;
612
613         error = E2BIG;
614         size = am_hreq.opcount * sizeof(attr_multiop_t);
615         if (!size || size > 16 * PAGE_SIZE)
616                 goto out_vn_rele;
617
618         error = ENOMEM;
619         ops = kmalloc(size, GFP_KERNEL);
620         if (!ops)
621                 goto out_vn_rele;
622
623         error = EFAULT;
624         if (copy_from_user(ops, am_hreq.ops, size))
625                 goto out_kfree_ops;
626
627         attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
628         if (!attr_name)
629                 goto out_kfree_ops;
630
631
632         error = 0;
633         for (i = 0; i < am_hreq.opcount; i++) {
634                 ops[i].am_error = strncpy_from_user(attr_name,
635                                 ops[i].am_attrname, MAXNAMELEN);
636                 if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
637                         error = -ERANGE;
638                 if (ops[i].am_error < 0)
639                         break;
640
641                 switch (ops[i].am_opcode) {
642                 case ATTR_OP_GET:
643                         ops[i].am_error = xfs_attrmulti_attr_get(vp,
644                                         attr_name, ops[i].am_attrvalue,
645                                         &ops[i].am_length, ops[i].am_flags);
646                         break;
647                 case ATTR_OP_SET:
648                         ops[i].am_error = xfs_attrmulti_attr_set(vp,
649                                         attr_name, ops[i].am_attrvalue,
650                                         ops[i].am_length, ops[i].am_flags);
651                         break;
652                 case ATTR_OP_REMOVE:
653                         ops[i].am_error = xfs_attrmulti_attr_remove(vp,
654                                         attr_name, ops[i].am_flags);
655                         break;
656                 default:
657                         ops[i].am_error = EINVAL;
658                 }
659         }
660
661         if (copy_to_user(am_hreq.ops, ops, size))
662                 error = XFS_ERROR(EFAULT);
663
664         kfree(attr_name);
665  out_kfree_ops:
666         kfree(ops);
667  out_vn_rele:
668         VN_RELE(vp);
669  out:
670         return -error;
671 }
672
673 /* prototypes for a few of the stack-hungry cases that have
674  * their own functions.  Functions are defined after their use
675  * so gcc doesn't get fancy and inline them with -03 */
676
677 STATIC int
678 xfs_ioc_space(
679         bhv_desc_t              *bdp,
680         struct inode            *inode,
681         struct file             *filp,
682         int                     flags,
683         unsigned int            cmd,
684         void                    __user *arg);
685
686 STATIC int
687 xfs_ioc_bulkstat(
688         xfs_mount_t             *mp,
689         unsigned int            cmd,
690         void                    __user *arg);
691
692 STATIC int
693 xfs_ioc_fsgeometry_v1(
694         xfs_mount_t             *mp,
695         void                    __user *arg);
696
697 STATIC int
698 xfs_ioc_fsgeometry(
699         xfs_mount_t             *mp,
700         void                    __user *arg);
701
702 STATIC int
703 xfs_ioc_xattr(
704         bhv_vnode_t             *vp,
705         xfs_inode_t             *ip,
706         struct file             *filp,
707         unsigned int            cmd,
708         void                    __user *arg);
709
710 STATIC int
711 xfs_ioc_getbmap(
712         bhv_desc_t              *bdp,
713         int                     flags,
714         unsigned int            cmd,
715         void                    __user *arg);
716
717 STATIC int
718 xfs_ioc_getbmapx(
719         bhv_desc_t              *bdp,
720         void                    __user *arg);
721
722 int
723 xfs_ioctl(
724         bhv_desc_t              *bdp,
725         struct inode            *inode,
726         struct file             *filp,
727         int                     ioflags,
728         unsigned int            cmd,
729         void                    __user *arg)
730 {
731         int                     error;
732         bhv_vnode_t             *vp;
733         xfs_inode_t             *ip;
734         xfs_mount_t             *mp;
735
736         vp = vn_from_inode(inode);
737
738         vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address);
739
740         ip = XFS_BHVTOI(bdp);
741         mp = ip->i_mount;
742
743         switch (cmd) {
744
745         case XFS_IOC_ALLOCSP:
746         case XFS_IOC_FREESP:
747         case XFS_IOC_RESVSP:
748         case XFS_IOC_UNRESVSP:
749         case XFS_IOC_ALLOCSP64:
750         case XFS_IOC_FREESP64:
751         case XFS_IOC_RESVSP64:
752         case XFS_IOC_UNRESVSP64:
753                 /*
754                  * Only allow the sys admin to reserve space unless
755                  * unwritten extents are enabled.
756                  */
757                 if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) &&
758                     !capable(CAP_SYS_ADMIN))
759                         return -EPERM;
760
761                 return xfs_ioc_space(bdp, inode, filp, ioflags, cmd, arg);
762
763         case XFS_IOC_DIOINFO: {
764                 struct dioattr  da;
765                 xfs_buftarg_t   *target =
766                         (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
767                         mp->m_rtdev_targp : mp->m_ddev_targp;
768
769                 da.d_mem = da.d_miniosz = 1 << target->bt_sshift;
770                 da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
771
772                 if (copy_to_user(arg, &da, sizeof(da)))
773                         return -XFS_ERROR(EFAULT);
774                 return 0;
775         }
776
777         case XFS_IOC_FSBULKSTAT_SINGLE:
778         case XFS_IOC_FSBULKSTAT:
779         case XFS_IOC_FSINUMBERS:
780                 return xfs_ioc_bulkstat(mp, cmd, arg);
781
782         case XFS_IOC_FSGEOMETRY_V1:
783                 return xfs_ioc_fsgeometry_v1(mp, arg);
784
785         case XFS_IOC_FSGEOMETRY:
786                 return xfs_ioc_fsgeometry(mp, arg);
787
788         case XFS_IOC_GETVERSION:
789                 return put_user(inode->i_generation, (int __user *)arg);
790
791         case XFS_IOC_GETXFLAGS:
792         case XFS_IOC_SETXFLAGS:
793         case XFS_IOC_FSGETXATTR:
794         case XFS_IOC_FSSETXATTR:
795         case XFS_IOC_FSGETXATTRA:
796                 return xfs_ioc_xattr(vp, ip, filp, cmd, arg);
797
798         case XFS_IOC_FSSETDM: {
799                 struct fsdmidata        dmi;
800
801                 if (copy_from_user(&dmi, arg, sizeof(dmi)))
802                         return -XFS_ERROR(EFAULT);
803
804                 error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate,
805                                                         NULL);
806                 return -error;
807         }
808
809         case XFS_IOC_GETBMAP:
810         case XFS_IOC_GETBMAPA:
811                 return xfs_ioc_getbmap(bdp, ioflags, cmd, arg);
812
813         case XFS_IOC_GETBMAPX:
814                 return xfs_ioc_getbmapx(bdp, arg);
815
816         case XFS_IOC_FD_TO_HANDLE:
817         case XFS_IOC_PATH_TO_HANDLE:
818         case XFS_IOC_PATH_TO_FSHANDLE:
819                 return xfs_find_handle(cmd, arg);
820
821         case XFS_IOC_OPEN_BY_HANDLE:
822                 return xfs_open_by_handle(mp, arg, filp, inode);
823
824         case XFS_IOC_FSSETDM_BY_HANDLE:
825                 return xfs_fssetdm_by_handle(mp, arg, inode);
826
827         case XFS_IOC_READLINK_BY_HANDLE:
828                 return xfs_readlink_by_handle(mp, arg, inode);
829
830         case XFS_IOC_ATTRLIST_BY_HANDLE:
831                 return xfs_attrlist_by_handle(mp, arg, inode);
832
833         case XFS_IOC_ATTRMULTI_BY_HANDLE:
834                 return xfs_attrmulti_by_handle(mp, arg, inode);
835
836         case XFS_IOC_SWAPEXT: {
837                 error = xfs_swapext((struct xfs_swapext __user *)arg);
838                 return -error;
839         }
840
841         case XFS_IOC_FSCOUNTS: {
842                 xfs_fsop_counts_t out;
843
844                 error = xfs_fs_counts(mp, &out);
845                 if (error)
846                         return -error;
847
848                 if (copy_to_user(arg, &out, sizeof(out)))
849                         return -XFS_ERROR(EFAULT);
850                 return 0;
851         }
852
853         case XFS_IOC_SET_RESBLKS: {
854                 xfs_fsop_resblks_t inout;
855                 __uint64_t         in;
856
857                 if (!capable(CAP_SYS_ADMIN))
858                         return -EPERM;
859
860                 if (copy_from_user(&inout, arg, sizeof(inout)))
861                         return -XFS_ERROR(EFAULT);
862
863                 /* input parameter is passed in resblks field of structure */
864                 in = inout.resblks;
865                 error = xfs_reserve_blocks(mp, &in, &inout);
866                 if (error)
867                         return -error;
868
869                 if (copy_to_user(arg, &inout, sizeof(inout)))
870                         return -XFS_ERROR(EFAULT);
871                 return 0;
872         }
873
874         case XFS_IOC_GET_RESBLKS: {
875                 xfs_fsop_resblks_t out;
876
877                 if (!capable(CAP_SYS_ADMIN))
878                         return -EPERM;
879
880                 error = xfs_reserve_blocks(mp, NULL, &out);
881                 if (error)
882                         return -error;
883
884                 if (copy_to_user(arg, &out, sizeof(out)))
885                         return -XFS_ERROR(EFAULT);
886
887                 return 0;
888         }
889
890         case XFS_IOC_FSGROWFSDATA: {
891                 xfs_growfs_data_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_data(mp, &in);
900                 return -error;
901         }
902
903         case XFS_IOC_FSGROWFSLOG: {
904                 xfs_growfs_log_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_log(mp, &in);
913                 return -error;
914         }
915
916         case XFS_IOC_FSGROWFSRT: {
917                 xfs_growfs_rt_t in;
918
919                 if (!capable(CAP_SYS_ADMIN))
920                         return -EPERM;
921
922                 if (copy_from_user(&in, arg, sizeof(in)))
923                         return -XFS_ERROR(EFAULT);
924
925                 error = xfs_growfs_rt(mp, &in);
926                 return -error;
927         }
928
929         case XFS_IOC_FREEZE:
930                 if (!capable(CAP_SYS_ADMIN))
931                         return -EPERM;
932
933                 if (inode->i_sb->s_frozen == SB_UNFROZEN)
934                         freeze_bdev(inode->i_sb->s_bdev);
935                 return 0;
936
937         case XFS_IOC_THAW:
938                 if (!capable(CAP_SYS_ADMIN))
939                         return -EPERM;
940                 if (inode->i_sb->s_frozen != SB_UNFROZEN)
941                         thaw_bdev(inode->i_sb->s_bdev, inode->i_sb);
942                 return 0;
943
944         case XFS_IOC_GOINGDOWN: {
945                 __uint32_t in;
946
947                 if (!capable(CAP_SYS_ADMIN))
948                         return -EPERM;
949
950                 if (get_user(in, (__uint32_t __user *)arg))
951                         return -XFS_ERROR(EFAULT);
952
953                 error = xfs_fs_goingdown(mp, in);
954                 return -error;
955         }
956
957         case XFS_IOC_ERROR_INJECTION: {
958                 xfs_error_injection_t in;
959
960                 if (!capable(CAP_SYS_ADMIN))
961                         return -EPERM;
962
963                 if (copy_from_user(&in, arg, sizeof(in)))
964                         return -XFS_ERROR(EFAULT);
965
966                 error = xfs_errortag_add(in.errtag, mp);
967                 return -error;
968         }
969
970         case XFS_IOC_ERROR_CLEARALL:
971                 if (!capable(CAP_SYS_ADMIN))
972                         return -EPERM;
973
974                 error = xfs_errortag_clearall(mp);
975                 return -error;
976
977         default:
978                 return -ENOTTY;
979         }
980 }
981
982 STATIC int
983 xfs_ioc_space(
984         bhv_desc_t              *bdp,
985         struct inode            *inode,
986         struct file             *filp,
987         int                     ioflags,
988         unsigned int            cmd,
989         void                    __user *arg)
990 {
991         xfs_flock64_t           bf;
992         int                     attr_flags = 0;
993         int                     error;
994
995         if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
996                 return -XFS_ERROR(EPERM);
997
998         if (!(filp->f_mode & FMODE_WRITE))
999                 return -XFS_ERROR(EBADF);
1000
1001         if (!S_ISREG(inode->i_mode))
1002                 return -XFS_ERROR(EINVAL);
1003
1004         if (copy_from_user(&bf, arg, sizeof(bf)))
1005                 return -XFS_ERROR(EFAULT);
1006
1007         if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1008                 attr_flags |= ATTR_NONBLOCK;
1009         if (ioflags & IO_INVIS)
1010                 attr_flags |= ATTR_DMI;
1011
1012         error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos,
1013                                               NULL, attr_flags);
1014         return -error;
1015 }
1016
1017 STATIC int
1018 xfs_ioc_bulkstat(
1019         xfs_mount_t             *mp,
1020         unsigned int            cmd,
1021         void                    __user *arg)
1022 {
1023         xfs_fsop_bulkreq_t      bulkreq;
1024         int                     count;  /* # of records returned */
1025         xfs_ino_t               inlast; /* last inode number */
1026         int                     done;
1027         int                     error;
1028
1029         /* done = 1 if there are more stats to get and if bulkstat */
1030         /* should be called again (unused here, but used in dmapi) */
1031
1032         if (!capable(CAP_SYS_ADMIN))
1033                 return -EPERM;
1034
1035         if (XFS_FORCED_SHUTDOWN(mp))
1036                 return -XFS_ERROR(EIO);
1037
1038         if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
1039                 return -XFS_ERROR(EFAULT);
1040
1041         if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
1042                 return -XFS_ERROR(EFAULT);
1043
1044         if ((count = bulkreq.icount) <= 0)
1045                 return -XFS_ERROR(EINVAL);
1046
1047         if (cmd == XFS_IOC_FSINUMBERS)
1048                 error = xfs_inumbers(mp, &inlast, &count,
1049                                         bulkreq.ubuffer, xfs_inumbers_fmt);
1050         else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
1051                 error = xfs_bulkstat_single(mp, &inlast,
1052                                                 bulkreq.ubuffer, &done);
1053         else {  /* XFS_IOC_FSBULKSTAT */
1054                 if (count == 1 && inlast != 0) {
1055                         inlast++;
1056                         error = xfs_bulkstat_single(mp, &inlast,
1057                                         bulkreq.ubuffer, &done);
1058                 } else {
1059                         error = xfs_bulkstat(mp, &inlast, &count,
1060                                 (bulkstat_one_pf)xfs_bulkstat_one, NULL,
1061                                 sizeof(xfs_bstat_t), bulkreq.ubuffer,
1062                                 BULKSTAT_FG_QUICK, &done);
1063                 }
1064         }
1065
1066         if (error)
1067                 return -error;
1068
1069         if (bulkreq.ocount != NULL) {
1070                 if (copy_to_user(bulkreq.lastip, &inlast,
1071                                                 sizeof(xfs_ino_t)))
1072                         return -XFS_ERROR(EFAULT);
1073
1074                 if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
1075                         return -XFS_ERROR(EFAULT);
1076         }
1077
1078         return 0;
1079 }
1080
1081 STATIC int
1082 xfs_ioc_fsgeometry_v1(
1083         xfs_mount_t             *mp,
1084         void                    __user *arg)
1085 {
1086         xfs_fsop_geom_v1_t      fsgeo;
1087         int                     error;
1088
1089         error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
1090         if (error)
1091                 return -error;
1092
1093         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
1094                 return -XFS_ERROR(EFAULT);
1095         return 0;
1096 }
1097
1098 STATIC int
1099 xfs_ioc_fsgeometry(
1100         xfs_mount_t             *mp,
1101         void                    __user *arg)
1102 {
1103         xfs_fsop_geom_t         fsgeo;
1104         int                     error;
1105
1106         error = xfs_fs_geometry(mp, &fsgeo, 4);
1107         if (error)
1108                 return -error;
1109
1110         if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
1111                 return -XFS_ERROR(EFAULT);
1112         return 0;
1113 }
1114
1115 /*
1116  * Linux extended inode flags interface.
1117  */
1118
1119 STATIC unsigned int
1120 xfs_merge_ioc_xflags(
1121         unsigned int    flags,
1122         unsigned int    start)
1123 {
1124         unsigned int    xflags = start;
1125
1126         if (flags & FS_IMMUTABLE_FL)
1127                 xflags |= XFS_XFLAG_IMMUTABLE;
1128         else
1129                 xflags &= ~XFS_XFLAG_IMMUTABLE;
1130         if (flags & FS_APPEND_FL)
1131                 xflags |= XFS_XFLAG_APPEND;
1132         else
1133                 xflags &= ~XFS_XFLAG_APPEND;
1134         if (flags & FS_SYNC_FL)
1135                 xflags |= XFS_XFLAG_SYNC;
1136         else
1137                 xflags &= ~XFS_XFLAG_SYNC;
1138         if (flags & FS_NOATIME_FL)
1139                 xflags |= XFS_XFLAG_NOATIME;
1140         else
1141                 xflags &= ~XFS_XFLAG_NOATIME;
1142         if (flags & FS_NODUMP_FL)
1143                 xflags |= XFS_XFLAG_NODUMP;
1144         else
1145                 xflags &= ~XFS_XFLAG_NODUMP;
1146
1147         return xflags;
1148 }
1149
1150 STATIC unsigned int
1151 xfs_di2lxflags(
1152         __uint16_t      di_flags)
1153 {
1154         unsigned int    flags = 0;
1155
1156         if (di_flags & XFS_DIFLAG_IMMUTABLE)
1157                 flags |= FS_IMMUTABLE_FL;
1158         if (di_flags & XFS_DIFLAG_APPEND)
1159                 flags |= FS_APPEND_FL;
1160         if (di_flags & XFS_DIFLAG_SYNC)
1161                 flags |= FS_SYNC_FL;
1162         if (di_flags & XFS_DIFLAG_NOATIME)
1163                 flags |= FS_NOATIME_FL;
1164         if (di_flags & XFS_DIFLAG_NODUMP)
1165                 flags |= FS_NODUMP_FL;
1166         return flags;
1167 }
1168
1169 STATIC int
1170 xfs_ioc_xattr(
1171         bhv_vnode_t             *vp,
1172         xfs_inode_t             *ip,
1173         struct file             *filp,
1174         unsigned int            cmd,
1175         void                    __user *arg)
1176 {
1177         struct fsxattr          fa;
1178         struct bhv_vattr        *vattr;
1179         int                     error = 0;
1180         int                     attr_flags;
1181         unsigned int            flags;
1182
1183         vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
1184         if (unlikely(!vattr))
1185                 return -ENOMEM;
1186
1187         switch (cmd) {
1188         case XFS_IOC_FSGETXATTR: {
1189                 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
1190                                  XFS_AT_NEXTENTS | XFS_AT_PROJID;
1191                 error = bhv_vop_getattr(vp, vattr, 0, NULL);
1192                 if (unlikely(error)) {
1193                         error = -error;
1194                         break;
1195                 }
1196
1197                 fa.fsx_xflags   = vattr->va_xflags;
1198                 fa.fsx_extsize  = vattr->va_extsize;
1199                 fa.fsx_nextents = vattr->va_nextents;
1200                 fa.fsx_projid   = vattr->va_projid;
1201
1202                 if (copy_to_user(arg, &fa, sizeof(fa))) {
1203                         error = -EFAULT;
1204                         break;
1205                 }
1206                 break;
1207         }
1208
1209         case XFS_IOC_FSSETXATTR: {
1210                 if (copy_from_user(&fa, arg, sizeof(fa))) {
1211                         error = -EFAULT;
1212                         break;
1213                 }
1214
1215                 attr_flags = 0;
1216                 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1217                         attr_flags |= ATTR_NONBLOCK;
1218
1219                 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
1220                 vattr->va_xflags  = fa.fsx_xflags;
1221                 vattr->va_extsize = fa.fsx_extsize;
1222                 vattr->va_projid  = fa.fsx_projid;
1223
1224                 error = bhv_vop_setattr(vp, vattr, attr_flags, NULL);
1225                 if (likely(!error))
1226                         __vn_revalidate(vp, vattr);     /* update flags */
1227                 error = -error;
1228                 break;
1229         }
1230
1231         case XFS_IOC_FSGETXATTRA: {
1232                 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
1233                                  XFS_AT_ANEXTENTS | XFS_AT_PROJID;
1234                 error = bhv_vop_getattr(vp, vattr, 0, NULL);
1235                 if (unlikely(error)) {
1236                         error = -error;
1237                         break;
1238                 }
1239
1240                 fa.fsx_xflags   = vattr->va_xflags;
1241                 fa.fsx_extsize  = vattr->va_extsize;
1242                 fa.fsx_nextents = vattr->va_anextents;
1243                 fa.fsx_projid   = vattr->va_projid;
1244
1245                 if (copy_to_user(arg, &fa, sizeof(fa))) {
1246                         error = -EFAULT;
1247                         break;
1248                 }
1249                 break;
1250         }
1251
1252         case XFS_IOC_GETXFLAGS: {
1253                 flags = xfs_di2lxflags(ip->i_d.di_flags);
1254                 if (copy_to_user(arg, &flags, sizeof(flags)))
1255                         error = -EFAULT;
1256                 break;
1257         }
1258
1259         case XFS_IOC_SETXFLAGS: {
1260                 if (copy_from_user(&flags, arg, sizeof(flags))) {
1261                         error = -EFAULT;
1262                         break;
1263                 }
1264
1265                 if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
1266                               FS_NOATIME_FL | FS_NODUMP_FL | \
1267                               FS_SYNC_FL)) {
1268                         error = -EOPNOTSUPP;
1269                         break;
1270                 }
1271
1272                 attr_flags = 0;
1273                 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1274                         attr_flags |= ATTR_NONBLOCK;
1275
1276                 vattr->va_mask = XFS_AT_XFLAGS;
1277                 vattr->va_xflags = xfs_merge_ioc_xflags(flags,
1278                                                         xfs_ip2xflags(ip));
1279
1280                 error = bhv_vop_setattr(vp, vattr, attr_flags, NULL);
1281                 if (likely(!error))
1282                         __vn_revalidate(vp, vattr);     /* update flags */
1283                 error = -error;
1284                 break;
1285         }
1286
1287         default:
1288                 error = -ENOTTY;
1289                 break;
1290         }
1291
1292         kfree(vattr);
1293         return error;
1294 }
1295
1296 STATIC int
1297 xfs_ioc_getbmap(
1298         bhv_desc_t              *bdp,
1299         int                     ioflags,
1300         unsigned int            cmd,
1301         void                    __user *arg)
1302 {
1303         struct getbmap          bm;
1304         int                     iflags;
1305         int                     error;
1306
1307         if (copy_from_user(&bm, arg, sizeof(bm)))
1308                 return -XFS_ERROR(EFAULT);
1309
1310         if (bm.bmv_count < 2)
1311                 return -XFS_ERROR(EINVAL);
1312
1313         iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
1314         if (ioflags & IO_INVIS)
1315                 iflags |= BMV_IF_NO_DMAPI_READ;
1316
1317         error = xfs_getbmap(bdp, &bm, (struct getbmap __user *)arg+1, iflags);
1318         if (error)
1319                 return -error;
1320
1321         if (copy_to_user(arg, &bm, sizeof(bm)))
1322                 return -XFS_ERROR(EFAULT);
1323         return 0;
1324 }
1325
1326 STATIC int
1327 xfs_ioc_getbmapx(
1328         bhv_desc_t              *bdp,
1329         void                    __user *arg)
1330 {
1331         struct getbmapx         bmx;
1332         struct getbmap          bm;
1333         int                     iflags;
1334         int                     error;
1335
1336         if (copy_from_user(&bmx, arg, sizeof(bmx)))
1337                 return -XFS_ERROR(EFAULT);
1338
1339         if (bmx.bmv_count < 2)
1340                 return -XFS_ERROR(EINVAL);
1341
1342         /*
1343          * Map input getbmapx structure to a getbmap
1344          * structure for xfs_getbmap.
1345          */
1346         GETBMAP_CONVERT(bmx, bm);
1347
1348         iflags = bmx.bmv_iflags;
1349
1350         if (iflags & (~BMV_IF_VALID))
1351                 return -XFS_ERROR(EINVAL);
1352
1353         iflags |= BMV_IF_EXTENDED;
1354
1355         error = xfs_getbmap(bdp, &bm, (struct getbmapx __user *)arg+1, iflags);
1356         if (error)
1357                 return -error;
1358
1359         GETBMAP_CONVERT(bm, bmx);
1360
1361         if (copy_to_user(arg, &bmx, sizeof(bmx)))
1362                 return -XFS_ERROR(EFAULT);
1363
1364         return 0;
1365 }