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