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