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