[XFS] do not have XFSMNT_IDELETE as default when mounted with XFSMNT_DMAPI
[linux-block.git] / fs / xfs / linux-2.6 / xfs_ioctl.c
CommitLineData
1da177e4 1/*
7b718769
NS
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
1da177e4 4 *
7b718769
NS
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
1da177e4
LT
7 * published by the Free Software Foundation.
8 *
7b718769
NS
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.
1da177e4 13 *
7b718769
NS
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
1da177e4 17 */
1da177e4 18#include "xfs.h"
1da177e4 19#include "xfs_fs.h"
a844f451 20#include "xfs_bit.h"
1da177e4 21#include "xfs_log.h"
a844f451 22#include "xfs_inum.h"
1da177e4
LT
23#include "xfs_trans.h"
24#include "xfs_sb.h"
a844f451 25#include "xfs_ag.h"
1da177e4
LT
26#include "xfs_dir2.h"
27#include "xfs_alloc.h"
28#include "xfs_dmapi.h"
29#include "xfs_mount.h"
1da177e4 30#include "xfs_bmap_btree.h"
a844f451 31#include "xfs_alloc_btree.h"
1da177e4 32#include "xfs_ialloc_btree.h"
a844f451 33#include "xfs_attr_sf.h"
1da177e4
LT
34#include "xfs_dir2_sf.h"
35#include "xfs_dinode.h"
36#include "xfs_inode.h"
a844f451
NS
37#include "xfs_btree.h"
38#include "xfs_ialloc.h"
1da177e4 39#include "xfs_rtalloc.h"
1da177e4 40#include "xfs_itable.h"
a844f451 41#include "xfs_error.h"
1da177e4
LT
42#include "xfs_rw.h"
43#include "xfs_acl.h"
1da177e4 44#include "xfs_attr.h"
a844f451 45#include "xfs_bmap.h"
1da177e4
LT
46#include "xfs_buf_item.h"
47#include "xfs_utils.h"
48#include "xfs_dfrag.h"
49#include "xfs_fsops.h"
50
16f7e0fe 51#include <linux/capability.h>
1da177e4
LT
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 */
68STATIC int
69xfs_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;
67fcaa73 77 bhv_vnode_t *vp;
1da177e4
LT
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
e678fb0d
JJS
108 ASSERT(file->f_path.dentry);
109 ASSERT(file->f_path.dentry->d_inode);
110 inode = igrab(file->f_path.dentry->d_inode);
1da177e4
LT
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
0432dab2
CH
126 switch (inode->i_mode & S_IFMT) {
127 case S_IFREG:
128 case S_IFDIR:
129 case S_IFLNK:
130 break;
131 default:
1da177e4
LT
132 iput(inode);
133 return -XFS_ERROR(EBADF);
134 }
135
0432dab2 136 /* we need the vnode */
ec86dc02 137 vp = vn_from_inode(inode);
0432dab2 138
1da177e4
LT
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;
1da177e4
LT
145 int lock_mode;
146
147 /* need to get access to the xfs_inode to read the generation */
75e17b3c 148 ip = xfs_vtoi(vp);
1da177e4
LT
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 */
186STATIC int
187xfs_vget_fsop_handlereq(
188 xfs_mount_t *mp,
189 struct inode *parinode, /* parent inode pointer */
190 xfs_fsop_handlereq_t *hreq,
67fcaa73 191 bhv_vnode_t **vp,
1da177e4
LT
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;
67fcaa73 201 bhv_vnode_t *vpp;
1da177e4
LT
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);
ec86dc02 255 inodep = vn_to_inode(vpp);
1da177e4
LT
256 xfs_iunlock(ip, XFS_ILOCK_SHARED);
257
258 *vp = vpp;
259 *inode = inodep;
260 return 0;
261}
262
263STATIC int
264xfs_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;
67fcaa73 276 bhv_vnode_t *vp;
1da177e4
LT
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. */
e678fb0d 334 mntget(parfilp->f_path.mnt);
1da177e4
LT
335
336 /* Create file pointer. */
e678fb0d 337 filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags);
1da177e4
LT
338 if (IS_ERR(filp)) {
339 put_unused_fd(new_fd);
340 return -XFS_ERROR(-PTR_ERR(filp));
341 }
2e2e7bb1
VA
342 if (inode->i_mode & S_IFREG) {
343 /* invisible operation should not change atime */
344 filp->f_flags |= O_NOATIME;
3562fd45 345 filp->f_op = &xfs_invis_file_operations;
2e2e7bb1 346 }
1da177e4
LT
347
348 fd_install(new_fd, filp);
349 return new_fd;
350}
351
804c83c3
CH
352/*
353 * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's
354 * unused first argument.
355 */
356STATIC int
357do_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
1da177e4
LT
378STATIC int
379xfs_readlink_by_handle(
380 xfs_mount_t *mp,
381 void __user *arg,
1da177e4
LT
382 struct inode *parinode)
383{
1da177e4
LT
384 struct inode *inode;
385 xfs_fsop_handlereq_t hreq;
67fcaa73 386 bhv_vnode_t *vp;
1da177e4 387 __u32 olen;
804c83c3
CH
388 void *link;
389 int error;
1da177e4
LT
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. */
0432dab2 401 if (!S_ISLNK(inode->i_mode)) {
804c83c3
CH
402 error = -XFS_ERROR(EINVAL);
403 goto out_iput;
1da177e4
LT
404 }
405
406 if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
804c83c3
CH
407 error = -XFS_ERROR(EFAULT);
408 goto out_iput;
1da177e4 409 }
1da177e4 410
804c83c3
CH
411 link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
412 if (!link)
413 goto out_iput;
1da177e4 414
804c83c3 415 error = -bhv_vop_readlink(vp, link);
67fcaa73 416 if (error)
804c83c3
CH
417 goto out_kfree;
418 error = do_readlink(hreq.ohandle, olen, link);
419 if (error)
420 goto out_kfree;
67fcaa73 421
804c83c3
CH
422 out_kfree:
423 kfree(link);
424 out_iput:
425 iput(inode);
426 return error;
1da177e4
LT
427}
428
429STATIC int
430xfs_fssetdm_by_handle(
431 xfs_mount_t *mp,
432 void __user *arg,
1da177e4
LT
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;
67fcaa73 440 bhv_vnode_t *vp;
1da177e4
LT
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
470STATIC int
471xfs_attrlist_by_handle(
472 xfs_mount_t *mp,
473 void __user *arg,
1da177e4
LT
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;
67fcaa73 480 bhv_vnode_t *vp;
1da177e4
LT
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;
67fcaa73
NS
500 error = bhv_vop_attr_list(vp, kbuf, al_hreq.buflen, al_hreq.flags,
501 cursor, NULL);
1da177e4
LT
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
516STATIC int
517xfs_attrmulti_attr_get(
67fcaa73 518 bhv_vnode_t *vp,
1da177e4
LT
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
67fcaa73 533 error = bhv_vop_attr_get(vp, name, kbuf, len, flags, NULL);
1da177e4
LT
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
545STATIC int
546xfs_attrmulti_attr_set(
67fcaa73 547 bhv_vnode_t *vp,
1da177e4
LT
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
3542c6e1
CH
556 if (IS_RDONLY(&vp->v_inode))
557 return -EROFS;
1da177e4
LT
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
67fcaa73 570 error = bhv_vop_attr_set(vp, name, kbuf, len, flags, NULL);
1da177e4
LT
571
572 out_kfree:
573 kfree(kbuf);
574 return error;
575}
576
577STATIC int
578xfs_attrmulti_attr_remove(
67fcaa73 579 bhv_vnode_t *vp,
1da177e4
LT
580 char *name,
581 __uint32_t flags)
582{
3542c6e1
CH
583 if (IS_RDONLY(&vp->v_inode))
584 return -EROFS;
1da177e4
LT
585 if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
586 return EPERM;
67fcaa73 587 return bhv_vop_attr_remove(vp, name, flags, NULL);
1da177e4
LT
588}
589
590STATIC int
591xfs_attrmulti_by_handle(
592 xfs_mount_t *mp,
593 void __user *arg,
1da177e4
LT
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;
67fcaa73 600 bhv_vnode_t *vp;
1da177e4
LT
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
677STATIC int
678xfs_ioc_space(
679 bhv_desc_t *bdp,
f37ea149 680 struct inode *inode,
1da177e4
LT
681 struct file *filp,
682 int flags,
683 unsigned int cmd,
684 void __user *arg);
685
686STATIC int
687xfs_ioc_bulkstat(
688 xfs_mount_t *mp,
689 unsigned int cmd,
690 void __user *arg);
691
692STATIC int
693xfs_ioc_fsgeometry_v1(
694 xfs_mount_t *mp,
695 void __user *arg);
696
697STATIC int
698xfs_ioc_fsgeometry(
699 xfs_mount_t *mp,
700 void __user *arg);
701
702STATIC int
703xfs_ioc_xattr(
67fcaa73 704 bhv_vnode_t *vp,
1da177e4
LT
705 xfs_inode_t *ip,
706 struct file *filp,
707 unsigned int cmd,
708 void __user *arg);
709
710STATIC int
711xfs_ioc_getbmap(
712 bhv_desc_t *bdp,
1da177e4
LT
713 int flags,
714 unsigned int cmd,
715 void __user *arg);
716
717STATIC int
718xfs_ioc_getbmapx(
719 bhv_desc_t *bdp,
720 void __user *arg);
721
722int
723xfs_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;
67fcaa73 732 bhv_vnode_t *vp;
1da177e4
LT
733 xfs_inode_t *ip;
734 xfs_mount_t *mp;
735
ec86dc02 736 vp = vn_from_inode(inode);
1da177e4
LT
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
f37ea149 761 return xfs_ioc_space(bdp, inode, filp, ioflags, cmd, arg);
1da177e4
LT
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
ce8e922c 769 da.d_mem = da.d_miniosz = 1 << target->bt_sshift;
0d14824c 770 da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
1da177e4
LT
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:
87395deb
AD
789 return put_user(inode->i_generation, (int __user *)arg);
790
1da177e4
LT
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:
5180602e 811 return xfs_ioc_getbmap(bdp, ioflags, cmd, arg);
1da177e4
LT
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:
5180602e 825 return xfs_fssetdm_by_handle(mp, arg, inode);
1da177e4
LT
826
827 case XFS_IOC_READLINK_BY_HANDLE:
5180602e 828 return xfs_readlink_by_handle(mp, arg, inode);
1da177e4
LT
829
830 case XFS_IOC_ATTRLIST_BY_HANDLE:
5180602e 831 return xfs_attrlist_by_handle(mp, arg, inode);
1da177e4
LT
832
833 case XFS_IOC_ATTRMULTI_BY_HANDLE:
5180602e 834 return xfs_attrmulti_by_handle(mp, arg, inode);
1da177e4
LT
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
982STATIC int
983xfs_ioc_space(
984 bhv_desc_t *bdp,
f37ea149 985 struct inode *inode,
1da177e4
LT
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
f37ea149 995 if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
1da177e4
LT
996 return -XFS_ERROR(EPERM);
997
ad4a8ac4 998 if (!(filp->f_mode & FMODE_WRITE))
1da177e4
LT
999 return -XFS_ERROR(EBADF);
1000
f37ea149 1001 if (!S_ISREG(inode->i_mode))
1da177e4
LT
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
1017STATIC int
1018xfs_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,
faa63e95 1049 bulkreq.ubuffer, xfs_inumbers_fmt);
1da177e4
LT
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
1081STATIC int
1082xfs_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
1098STATIC int
1099xfs_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 */
1da177e4
LT
1118
1119STATIC unsigned int
1120xfs_merge_ioc_xflags(
1121 unsigned int flags,
1122 unsigned int start)
1123{
1124 unsigned int xflags = start;
1125
39058a0e 1126 if (flags & FS_IMMUTABLE_FL)
1da177e4
LT
1127 xflags |= XFS_XFLAG_IMMUTABLE;
1128 else
1129 xflags &= ~XFS_XFLAG_IMMUTABLE;
39058a0e 1130 if (flags & FS_APPEND_FL)
1da177e4
LT
1131 xflags |= XFS_XFLAG_APPEND;
1132 else
1133 xflags &= ~XFS_XFLAG_APPEND;
39058a0e 1134 if (flags & FS_SYNC_FL)
1da177e4
LT
1135 xflags |= XFS_XFLAG_SYNC;
1136 else
1137 xflags &= ~XFS_XFLAG_SYNC;
39058a0e 1138 if (flags & FS_NOATIME_FL)
1da177e4
LT
1139 xflags |= XFS_XFLAG_NOATIME;
1140 else
1141 xflags &= ~XFS_XFLAG_NOATIME;
39058a0e 1142 if (flags & FS_NODUMP_FL)
1da177e4
LT
1143 xflags |= XFS_XFLAG_NODUMP;
1144 else
1145 xflags &= ~XFS_XFLAG_NODUMP;
1146
1147 return xflags;
1148}
1149
1150STATIC unsigned int
1151xfs_di2lxflags(
1152 __uint16_t di_flags)
1153{
1154 unsigned int flags = 0;
1155
1156 if (di_flags & XFS_DIFLAG_IMMUTABLE)
39058a0e 1157 flags |= FS_IMMUTABLE_FL;
1da177e4 1158 if (di_flags & XFS_DIFLAG_APPEND)
39058a0e 1159 flags |= FS_APPEND_FL;
1da177e4 1160 if (di_flags & XFS_DIFLAG_SYNC)
39058a0e 1161 flags |= FS_SYNC_FL;
1da177e4 1162 if (di_flags & XFS_DIFLAG_NOATIME)
39058a0e 1163 flags |= FS_NOATIME_FL;
1da177e4 1164 if (di_flags & XFS_DIFLAG_NODUMP)
39058a0e 1165 flags |= FS_NODUMP_FL;
1da177e4
LT
1166 return flags;
1167}
1168
1169STATIC int
1170xfs_ioc_xattr(
67fcaa73 1171 bhv_vnode_t *vp,
1da177e4
LT
1172 xfs_inode_t *ip,
1173 struct file *filp,
1174 unsigned int cmd,
1175 void __user *arg)
1176{
1177 struct fsxattr fa;
8285fb58 1178 struct bhv_vattr *vattr;
220b5284 1179 int error = 0;
1da177e4
LT
1180 int attr_flags;
1181 unsigned int flags;
1182
220b5284
NS
1183 vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
1184 if (unlikely(!vattr))
1185 return -ENOMEM;
1186
1da177e4
LT
1187 switch (cmd) {
1188 case XFS_IOC_FSGETXATTR: {
220b5284
NS
1189 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
1190 XFS_AT_NEXTENTS | XFS_AT_PROJID;
67fcaa73 1191 error = bhv_vop_getattr(vp, vattr, 0, NULL);
220b5284
NS
1192 if (unlikely(error)) {
1193 error = -error;
1194 break;
1195 }
1da177e4 1196
220b5284
NS
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;
1da177e4 1201
220b5284
NS
1202 if (copy_to_user(arg, &fa, sizeof(fa))) {
1203 error = -EFAULT;
1204 break;
1205 }
1206 break;
1da177e4
LT
1207 }
1208
1209 case XFS_IOC_FSSETXATTR: {
220b5284
NS
1210 if (copy_from_user(&fa, arg, sizeof(fa))) {
1211 error = -EFAULT;
1212 break;
1213 }
1da177e4
LT
1214
1215 attr_flags = 0;
1216 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1217 attr_flags |= ATTR_NONBLOCK;
1218
220b5284
NS
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;
1da177e4 1223
67fcaa73 1224 error = bhv_vop_setattr(vp, vattr, attr_flags, NULL);
220b5284
NS
1225 if (likely(!error))
1226 __vn_revalidate(vp, vattr); /* update flags */
1227 error = -error;
1228 break;
1da177e4
LT
1229 }
1230
1231 case XFS_IOC_FSGETXATTRA: {
220b5284
NS
1232 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
1233 XFS_AT_ANEXTENTS | XFS_AT_PROJID;
67fcaa73 1234 error = bhv_vop_getattr(vp, vattr, 0, NULL);
220b5284
NS
1235 if (unlikely(error)) {
1236 error = -error;
1237 break;
1238 }
1da177e4 1239
220b5284
NS
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;
1da177e4 1244
220b5284
NS
1245 if (copy_to_user(arg, &fa, sizeof(fa))) {
1246 error = -EFAULT;
1247 break;
1248 }
1249 break;
1da177e4
LT
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)))
220b5284
NS
1255 error = -EFAULT;
1256 break;
1da177e4
LT
1257 }
1258
1259 case XFS_IOC_SETXFLAGS: {
220b5284
NS
1260 if (copy_from_user(&flags, arg, sizeof(flags))) {
1261 error = -EFAULT;
1262 break;
1263 }
1da177e4 1264
39058a0e
ES
1265 if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
1266 FS_NOATIME_FL | FS_NODUMP_FL | \
1267 FS_SYNC_FL)) {
220b5284
NS
1268 error = -EOPNOTSUPP;
1269 break;
1270 }
1da177e4
LT
1271
1272 attr_flags = 0;
1273 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1274 attr_flags |= ATTR_NONBLOCK;
1275
220b5284
NS
1276 vattr->va_mask = XFS_AT_XFLAGS;
1277 vattr->va_xflags = xfs_merge_ioc_xflags(flags,
1278 xfs_ip2xflags(ip));
1da177e4 1279
67fcaa73 1280 error = bhv_vop_setattr(vp, vattr, attr_flags, NULL);
220b5284
NS
1281 if (likely(!error))
1282 __vn_revalidate(vp, vattr); /* update flags */
1283 error = -error;
1284 break;
1da177e4
LT
1285 }
1286
1da177e4 1287 default:
220b5284
NS
1288 error = -ENOTTY;
1289 break;
1da177e4 1290 }
220b5284
NS
1291
1292 kfree(vattr);
1293 return error;
1da177e4
LT
1294}
1295
1296STATIC int
1297xfs_ioc_getbmap(
1298 bhv_desc_t *bdp,
1da177e4
LT
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
1326STATIC int
1327xfs_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}