1153323Srodrigc/*
2159451Srodrigc * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3159451Srodrigc * All Rights Reserved.
4153323Srodrigc *
5159451Srodrigc * This program is free software; you can redistribute it and/or
6159451Srodrigc * modify it under the terms of the GNU General Public License as
7153323Srodrigc * published by the Free Software Foundation.
8153323Srodrigc *
9159451Srodrigc * This program is distributed in the hope that it would be useful,
10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of
11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12159451Srodrigc * GNU General Public License for more details.
13153323Srodrigc *
14159451Srodrigc * You should have received a copy of the GNU General Public License
15159451Srodrigc * along with this program; if not, write the Free Software Foundation,
16159451Srodrigc * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17153323Srodrigc */
18153323Srodrigc#include "xfs.h"
19153323Srodrigc#include "xfs_fs.h"
20159451Srodrigc#include "xfs_bit.h"
21159451Srodrigc#include "xfs_log.h"
22153323Srodrigc#include "xfs_inum.h"
23153323Srodrigc#include "xfs_trans.h"
24153323Srodrigc#include "xfs_sb.h"
25159451Srodrigc#include "xfs_ag.h"
26153323Srodrigc#include "xfs_dir.h"
27153323Srodrigc#include "xfs_dir2.h"
28153323Srodrigc#include "xfs_alloc.h"
29153323Srodrigc#include "xfs_dmapi.h"
30153323Srodrigc#include "xfs_mount.h"
31159451Srodrigc#include "xfs_bmap_btree.h"
32153323Srodrigc#include "xfs_alloc_btree.h"
33153323Srodrigc#include "xfs_ialloc_btree.h"
34159451Srodrigc#include "xfs_dir_sf.h"
35153323Srodrigc#include "xfs_attr_sf.h"
36153323Srodrigc#include "xfs_dir2_sf.h"
37153323Srodrigc#include "xfs_dinode.h"
38153323Srodrigc#include "xfs_inode.h"
39159451Srodrigc#include "xfs_btree.h"
40159451Srodrigc#include "xfs_ialloc.h"
41153323Srodrigc#include "xfs_rtalloc.h"
42159451Srodrigc#include "xfs_itable.h"
43153323Srodrigc#include "xfs_error.h"
44153323Srodrigc#include "xfs_rw.h"
45153323Srodrigc#include "xfs_acl.h"
46153323Srodrigc#include "xfs_cap.h"
47153323Srodrigc#include "xfs_mac.h"
48153323Srodrigc#include "xfs_attr.h"
49159451Srodrigc#include "xfs_bmap.h"
50153323Srodrigc#include "xfs_buf_item.h"
51153323Srodrigc#include "xfs_utils.h"
52153323Srodrigc#include "xfs_dfrag.h"
53153323Srodrigc#include "xfs_fsops.h"
54153323Srodrigc
55153323Srodrigc
56159451Srodrigc#include <sys/file.h>
57159451Srodrigc#if 1
58153323Srodrigc/*
59153323Srodrigc * ioctl commands that are used by Linux filesystems
60153323Srodrigc */
61153323Srodrigc#define XFS_IOC_GETXFLAGS	_IOR('f', 1, long)
62153323Srodrigc#define XFS_IOC_SETXFLAGS	_IOW('f', 2, long)
63153323Srodrigc#define XFS_IOC_GETVERSION	_IOR('v', 1, long)
64153323Srodrigc
65159451Srodrigc#undef copy_to_user
66159451Srodrigcstatic __inline__ int
67159451Srodrigccopy_to_user(void *dst, void *src, int len) {
68159451Srodrigc	memcpy(dst,src,len);
69159451Srodrigc	return 0;
70159451Srodrigc}
71159451Srodrigc#undef copy_from_user
72159451Srodrigcstatic __inline__ int
73159451Srodrigccopy_from_user(void *dst, void *src, int len) {
74159451Srodrigc	memcpy(dst,src,len);
75159451Srodrigc	return 0;
76159451Srodrigc}
77153323Srodrigc
78153323Srodrigc/*
79153323Srodrigc * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
80153323Srodrigc * a file or fs handle.
81153323Srodrigc *
82153323Srodrigc * XFS_IOC_PATH_TO_FSHANDLE
83153323Srodrigc *    returns fs handle for a mount point or path within that mount point
84153323Srodrigc * XFS_IOC_FD_TO_HANDLE
85153323Srodrigc *    returns full handle for a FD opened in user space
86153323Srodrigc * XFS_IOC_PATH_TO_HANDLE
87153323Srodrigc *    returns full handle for a path
88153323Srodrigc */
89153323SrodrigcSTATIC int
90153323Srodrigcxfs_find_handle(
91153323Srodrigc	unsigned int		cmd,
92159451Srodrigc	void			__user *arg)
93153323Srodrigc{
94159451Srodrigc#ifdef RMC
95153323Srodrigc	int			hsize;
96159451Srodrigc#endif
97153323Srodrigc	xfs_handle_t		handle;
98153323Srodrigc	xfs_fsop_handlereq_t	hreq;
99159451Srodrigc#ifdef RMC
100159451Srodrigc	struct inode		*inode;
101159451Srodrigc	xfs_vnode_t		*vp;
102159451Srodrigc#endif
103153323Srodrigc
104159451Srodrigc	if (copy_from_user(&hreq, arg, sizeof(hreq)))
105159451Srodrigc		return -XFS_ERROR(EFAULT);
106153323Srodrigc
107153323Srodrigc	memset((char *)&handle, 0, sizeof(handle));
108153323Srodrigc
109153323Srodrigc	switch (cmd) {
110159451Srodrigc#if 0
111153323Srodrigc	case XFS_IOC_PATH_TO_FSHANDLE:
112153323Srodrigc	case XFS_IOC_PATH_TO_HANDLE: {
113153323Srodrigc		struct nameidata	nd;
114153323Srodrigc		int			error;
115153323Srodrigc
116159451Srodrigc		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF,
117153323Srodrigc		    UIO_USERSPACE, hreq.path, td);
118153323Srodrigc		error = namei(&nd);
119153323Srodrigc		if (error)
120153323Srodrigc			return error;
121153323Srodrigc		NDFREE(&nd, NDF_ONLY_PNBUF);
122153323Srodrigc		break;
123153323Srodrigc	}
124153323Srodrigc
125153323Srodrigc	case XFS_IOC_FD_TO_HANDLE: {
126153323Srodrigc		struct file	*file;
127159451Srodrigc		int		error;
128153323Srodrigc
129153323Srodrigc		error = getvnode(td->td_proc->p_fd, hreq.fd, &file);
130153323Srodrigc		if (error)
131153323Srodrigc		    return error;
132153323Srodrigc
133153323Srodrigc		error = vget(vp, LK_EXCLUSIVE, td);
134153323Srodrigc		if (error) {
135153323Srodrigc		    fdrop(file);
136153323Srodrigc		    return error;
137153323Srodrigc		}
138153323Srodrigc		fdrop(file);
139153323Srodrigc		break;
140153323Srodrigc	}
141159451Srodrigc#endif
142153323Srodrigc
143153323Srodrigc	default:
144153323Srodrigc		ASSERT(0);
145153323Srodrigc		return XFS_ERROR(EINVAL);
146153323Srodrigc	}
147153323Srodrigc
148159451Srodrigc#ifdef RMC
149153323Srodrigc	if (inode->i_sb->s_magic != XFS_SB_MAGIC) {
150153323Srodrigc		/* we're not in XFS anymore, Toto */
151153323Srodrigc		iput(inode);
152153323Srodrigc		return XFS_ERROR(EINVAL);
153153323Srodrigc	}
154153323Srodrigc
155159451Srodrigc	switch (inode->i_mode & S_IFMT) {
156159451Srodrigc	case S_IFREG:
157159451Srodrigc	case S_IFDIR:
158159451Srodrigc	case S_IFLNK:
159159451Srodrigc		break;
160159451Srodrigc	default:
161153323Srodrigc		iput(inode);
162153323Srodrigc		return XFS_ERROR(EBADF);
163153323Srodrigc	}
164159451Srodrigc	/* we need the vnode */
165159451Srodrigc	vp = vn_from_inode(inode);
166153323Srodrigc
167153323Srodrigc	/* now we can grab the fsid */
168153323Srodrigc	memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));
169153323Srodrigc	hsize = sizeof(xfs_fsid_t);
170153323Srodrigc
171153323Srodrigc	if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {
172153323Srodrigc		xfs_inode_t	*ip;
173153323Srodrigc		int		lock_mode;
174153323Srodrigc
175153323Srodrigc		/* need to get access to the xfs_inode to read the generation */
176159451Srodrigc		ip = xfs_vtoi(vp);
177153323Srodrigc		ASSERT(ip);
178153323Srodrigc		lock_mode = xfs_ilock_map_shared(ip);
179153323Srodrigc
180153323Srodrigc		/* fill in fid section of handle from inode */
181153323Srodrigc		handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) -
182153323Srodrigc					    sizeof(handle.ha_fid.xfs_fid_len);
183153323Srodrigc		handle.ha_fid.xfs_fid_pad = 0;
184153323Srodrigc		handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen;
185153323Srodrigc		handle.ha_fid.xfs_fid_ino = ip->i_ino;
186153323Srodrigc
187153323Srodrigc		xfs_iunlock_map_shared(ip, lock_mode);
188153323Srodrigc
189153323Srodrigc		hsize = XFS_HSIZE(handle);
190153323Srodrigc	}
191153323Srodrigc
192153323Srodrigc	/* now copy our handle into the user buffer & write out the size */
193159451Srodrigc	if (copy_to_user(hreq.ohandle, &handle, hsize) ||
194153323Srodrigc	    copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {
195153323Srodrigc		iput(inode);
196159451Srodrigc		return XFS_ERROR(EFAULT);
197153323Srodrigc	}
198153323Srodrigc
199153323Srodrigc	iput(inode);
200159451Srodrigc#endif
201153323Srodrigc	return 0;
202153323Srodrigc}
203153323Srodrigc
204153323Srodrigc
205153323Srodrigc/*
206153323Srodrigc * Convert userspace handle data into vnode (and inode).
207153323Srodrigc * We [ab]use the fact that all the fsop_handlereq ioctl calls
208153323Srodrigc * have a data structure argument whose first component is always
209153323Srodrigc * a xfs_fsop_handlereq_t, so we can cast to and from this type.
210153323Srodrigc * This allows us to optimise the copy_from_user calls and gives
211153323Srodrigc * a handy, shared routine.
212153323Srodrigc *
213153323Srodrigc * If no error, caller must always VN_RELE the returned vp.
214153323Srodrigc */
215153323SrodrigcSTATIC int
216153323Srodrigcxfs_vget_fsop_handlereq(
217153323Srodrigc	xfs_mount_t		*mp,
218153323Srodrigc	struct inode		*parinode,	/* parent inode pointer    */
219153323Srodrigc	xfs_fsop_handlereq_t	*hreq,
220159451Srodrigc	xfs_vnode_t		**vp,
221153323Srodrigc	struct inode		**inode)
222153323Srodrigc{
223159451Srodrigc#if 0
224159451Srodrigc	void			__user *hanp;
225153323Srodrigc	size_t			hlen;
226153323Srodrigc	xfs_fid_t		*xfid;
227153323Srodrigc	xfs_handle_t		*handlep;
228153323Srodrigc	xfs_handle_t		handle;
229153323Srodrigc	xfs_inode_t		*ip;
230153323Srodrigc	struct inode		*inodep;
231159451Srodrigc	xfs_vnode_t		*vpp;
232153323Srodrigc	xfs_ino_t		ino;
233153323Srodrigc	__u32			igen;
234153323Srodrigc	int			error;
235153323Srodrigc
236153323Srodrigc	/*
237153323Srodrigc	 * Only allow handle opens under a directory.
238153323Srodrigc	 */
239153323Srodrigc	if (!S_ISDIR(parinode->i_mode))
240153323Srodrigc		return XFS_ERROR(ENOTDIR);
241153323Srodrigc
242153323Srodrigc	hanp = hreq->ihandle;
243153323Srodrigc	hlen = hreq->ihandlen;
244153323Srodrigc	handlep = &handle;
245153323Srodrigc
246153323Srodrigc	if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
247153323Srodrigc		return XFS_ERROR(EINVAL);
248153323Srodrigc	if (copy_from_user(handlep, hanp, hlen))
249153323Srodrigc		return XFS_ERROR(EFAULT);
250153323Srodrigc	if (hlen < sizeof(*handlep))
251153323Srodrigc		memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
252153323Srodrigc	if (hlen > sizeof(handlep->ha_fsid)) {
253153323Srodrigc		if (handlep->ha_fid.xfs_fid_len !=
254153323Srodrigc				(hlen - sizeof(handlep->ha_fsid)
255153323Srodrigc					- sizeof(handlep->ha_fid.xfs_fid_len))
256153323Srodrigc		    || handlep->ha_fid.xfs_fid_pad)
257153323Srodrigc			return XFS_ERROR(EINVAL);
258153323Srodrigc	}
259153323Srodrigc
260153323Srodrigc	/*
261153323Srodrigc	 * Crack the handle, obtain the inode # & generation #
262153323Srodrigc	 */
263153323Srodrigc	xfid = (struct xfs_fid *)&handlep->ha_fid;
264153323Srodrigc	if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
265153323Srodrigc		ino  = xfid->xfs_fid_ino;
266153323Srodrigc		igen = xfid->xfs_fid_gen;
267153323Srodrigc	} else {
268153323Srodrigc		return XFS_ERROR(EINVAL);
269153323Srodrigc	}
270153323Srodrigc
271153323Srodrigc	/*
272153323Srodrigc	 * Get the XFS inode, building a vnode to go with it.
273153323Srodrigc	 */
274159451Srodrigc	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
275153323Srodrigc	if (error)
276153323Srodrigc		return error;
277153323Srodrigc	if (ip == NULL)
278153323Srodrigc		return XFS_ERROR(EIO);
279153323Srodrigc	if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {
280153323Srodrigc		xfs_iput_new(ip, XFS_ILOCK_SHARED);
281153323Srodrigc		return XFS_ERROR(ENOENT);
282153323Srodrigc	}
283153323Srodrigc
284153323Srodrigc	vpp = XFS_ITOV(ip);
285159451Srodrigc	inodep = vn_to_inode(vpp);
286153323Srodrigc	xfs_iunlock(ip, XFS_ILOCK_SHARED);
287153323Srodrigc
288153323Srodrigc	*vp = vpp;
289153323Srodrigc	*inode = inodep;
290159451Srodrigc#endif
291153323Srodrigc	return 0;
292153323Srodrigc}
293153323Srodrigc
294153323SrodrigcSTATIC int
295153323Srodrigcxfs_open_by_handle(
296153323Srodrigc	xfs_mount_t		*mp,
297159451Srodrigc	void			__user *arg,
298153323Srodrigc	struct file		*parfilp,
299153323Srodrigc	struct inode		*parinode)
300153323Srodrigc{
301159451Srodrigc	int			new_fd = 0;
302159451Srodrigc#if 0
303153323Srodrigc	int			error;
304153323Srodrigc	int			permflag;
305153323Srodrigc	struct file		*filp;
306153323Srodrigc	struct inode		*inode;
307153323Srodrigc	struct dentry		*dentry;
308159451Srodrigc	xfs_vnode_t		*vp;
309153323Srodrigc	xfs_fsop_handlereq_t	hreq;
310153323Srodrigc
311159451Srodrigc	if (!capable(CAP_SYS_ADMIN))
312159451Srodrigc		return -XFS_ERROR(EPERM);
313159451Srodrigc	if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
314159451Srodrigc		return XFS_ERROR(EFAULT);
315159451Srodrigc
316159451Srodrigc	error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);
317153323Srodrigc	if (error)
318159451Srodrigc		return error;
319153323Srodrigc
320153323Srodrigc	/* Restrict xfs_open_by_handle to directories & regular files. */
321153323Srodrigc	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
322153323Srodrigc		iput(inode);
323159451Srodrigc		return XFS_ERROR(EINVAL);
324153323Srodrigc	}
325153323Srodrigc
326153323Srodrigc#if BITS_PER_LONG != 32
327153323Srodrigc	hreq.oflags |= O_LARGEFILE;
328153323Srodrigc#endif
329153323Srodrigc	/* Put open permission in namei format. */
330153323Srodrigc	permflag = hreq.oflags;
331153323Srodrigc	if ((permflag+1) & O_ACCMODE)
332153323Srodrigc		permflag++;
333153323Srodrigc	if (permflag & O_TRUNC)
334153323Srodrigc		permflag |= 2;
335153323Srodrigc
336153323Srodrigc	if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
337153323Srodrigc	    (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
338153323Srodrigc		iput(inode);
339159451Srodrigc		return XFS_ERROR(EPERM);
340153323Srodrigc	}
341153323Srodrigc
342153323Srodrigc	if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
343153323Srodrigc		iput(inode);
344159451Srodrigc		return XFS_ERROR(EACCES);
345153323Srodrigc	}
346153323Srodrigc
347153323Srodrigc	/* Can't write directories. */
348153323Srodrigc	if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
349153323Srodrigc		iput(inode);
350159451Srodrigc		return XFS_ERROR(EISDIR);
351153323Srodrigc	}
352153323Srodrigc
353153323Srodrigc	if ((new_fd = get_unused_fd()) < 0) {
354153323Srodrigc		iput(inode);
355153323Srodrigc		return new_fd;
356153323Srodrigc	}
357153323Srodrigc
358153323Srodrigc	dentry = d_alloc_anon(inode);
359153323Srodrigc	if (dentry == NULL) {
360153323Srodrigc		iput(inode);
361153323Srodrigc		put_unused_fd(new_fd);
362159451Srodrigc		return XFS_ERROR(ENOMEM);
363153323Srodrigc	}
364153323Srodrigc
365153323Srodrigc	/* Ensure umount returns EBUSY on umounts while this file is open. */
366153323Srodrigc	mntget(parfilp->f_vfsmnt);
367153323Srodrigc
368153323Srodrigc	/* Create file pointer. */
369153323Srodrigc	filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
370153323Srodrigc	if (IS_ERR(filp)) {
371153323Srodrigc		put_unused_fd(new_fd);
372153323Srodrigc		return -XFS_ERROR(-PTR_ERR(filp));
373153323Srodrigc	}
374153323Srodrigc	if (inode->i_mode & S_IFREG)
375159451Srodrigc		filp->f_op = &xfs_invis_file_operations;
376153323Srodrigc
377153323Srodrigc	fd_install(new_fd, filp);
378159451Srodrigc#endif
379153323Srodrigc	return new_fd;
380153323Srodrigc}
381153323Srodrigc
382153323SrodrigcSTATIC int
383153323Srodrigcxfs_readlink_by_handle(
384153323Srodrigc	xfs_mount_t		*mp,
385159451Srodrigc	void			__user *arg,
386153323Srodrigc	struct file		*parfilp,
387153323Srodrigc	struct inode		*parinode)
388153323Srodrigc{
389153323Srodrigc	int			error;
390153323Srodrigc	struct iovec		aiov;
391153323Srodrigc	struct uio		auio;
392153323Srodrigc	struct inode		*inode;
393153323Srodrigc	xfs_fsop_handlereq_t	hreq;
394170124Skan	xfs_vnode_t		*vp = NULL;
395153323Srodrigc	__u32			olen;
396153323Srodrigc
397159451Srodrigc	if (!capable(CAP_SYS_ADMIN))
398159451Srodrigc		return -XFS_ERROR(EPERM);
399159451Srodrigc	if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
400159451Srodrigc		return -XFS_ERROR(EFAULT);
401159451Srodrigc
402159451Srodrigc	error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);
403153323Srodrigc	if (error)
404153323Srodrigc		return -error;
405153323Srodrigc
406159451Srodrigc#if 0
407153323Srodrigc	/* Restrict this handle operation to symlinks only. */
408153323Srodrigc	if (vp->v_type != VLNK) {
409153323Srodrigc		VN_RELE(vp);
410153323Srodrigc		return -XFS_ERROR(EINVAL);
411153323Srodrigc	}
412159451Srodrigc#endif
413153323Srodrigc
414153323Srodrigc	if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
415153323Srodrigc		VN_RELE(vp);
416153323Srodrigc		return -XFS_ERROR(EFAULT);
417153323Srodrigc	}
418153323Srodrigc	aiov.iov_len	= olen;
419153323Srodrigc	aiov.iov_base	= hreq.ohandle;
420153323Srodrigc
421153323Srodrigc	auio.uio_iov	= &aiov;
422153323Srodrigc	auio.uio_iovcnt	= 1;
423153323Srodrigc	auio.uio_offset	= 0;
424153323Srodrigc	auio.uio_segflg	= UIO_USERSPACE;
425153323Srodrigc	auio.uio_resid	= olen;
426153323Srodrigc
427159451Srodrigc	XVOP_READLINK(vp, &auio, IO_INVIS, NULL, error);
428153323Srodrigc
429153323Srodrigc	VN_RELE(vp);
430153323Srodrigc	return (olen - auio.uio_resid);
431153323Srodrigc}
432153323Srodrigc
433153323SrodrigcSTATIC int
434153323Srodrigcxfs_fssetdm_by_handle(
435153323Srodrigc	xfs_mount_t		*mp,
436159451Srodrigc	void			__user *arg,
437153323Srodrigc	struct file		*parfilp,
438153323Srodrigc	struct inode		*parinode)
439153323Srodrigc{
440159451Srodrigc	int			error = 0;
441159451Srodrigc#if 0
442153323Srodrigc	struct fsdmidata	fsd;
443153323Srodrigc	xfs_fsop_setdm_handlereq_t dmhreq;
444153323Srodrigc	struct inode		*inode;
445153323Srodrigc	bhv_desc_t		*bdp;
446159451Srodrigc	xfs_vnode_t		*vp;
447153323Srodrigc
448159451Srodrigc	if (!capable(CAP_MKNOD))
449159451Srodrigc		return XFS_ERROR(EPERM);
450159451Srodrigc	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
451159451Srodrigc		return XFS_ERROR(EFAULT);
452159451Srodrigc
453159451Srodrigc	error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode);
454153323Srodrigc	if (error)
455159451Srodrigc		return error;
456153323Srodrigc
457153323Srodrigc	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
458153323Srodrigc		VN_RELE(vp);
459159451Srodrigc		return XFS_ERROR(EPERM);
460153323Srodrigc	}
461153323Srodrigc
462153323Srodrigc	if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {
463153323Srodrigc		VN_RELE(vp);
464159451Srodrigc		return XFS_ERROR(EFAULT);
465153323Srodrigc	}
466153323Srodrigc
467153323Srodrigc	bdp = bhv_base_unlocked(VN_BHV_HEAD(vp));
468153323Srodrigc	error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL);
469153323Srodrigc
470153323Srodrigc	VN_RELE(vp);
471153323Srodrigc	if (error)
472159451Srodrigc		return error;
473159451Srodrigc#endif
474159451Srodrigc	return error;
475153323Srodrigc}
476153323Srodrigc
477153323SrodrigcSTATIC int
478153323Srodrigcxfs_attrlist_by_handle(
479153323Srodrigc	xfs_mount_t		*mp,
480159451Srodrigc	void			__user *arg,
481153323Srodrigc	struct file		*parfilp,
482153323Srodrigc	struct inode		*parinode)
483153323Srodrigc{
484159451Srodrigc	int			error = 0;
485159451Srodrigc#if 0
486153323Srodrigc	attrlist_cursor_kern_t	*cursor;
487153323Srodrigc	xfs_fsop_attrlist_handlereq_t al_hreq;
488153323Srodrigc	struct inode		*inode;
489159451Srodrigc	xfs_vnode_t		*vp;
490159451Srodrigc	char			*kbuf;
491153323Srodrigc
492159451Srodrigc	if (!capable(CAP_SYS_ADMIN))
493159451Srodrigc		return -XFS_ERROR(EPERM);
494159451Srodrigc	if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
495159451Srodrigc		return -XFS_ERROR(EFAULT);
496159451Srodrigc	if (al_hreq.buflen > XATTR_LIST_MAX)
497159451Srodrigc		return -XFS_ERROR(EINVAL);
498159451Srodrigc
499159451Srodrigc	error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq,
500159451Srodrigc			&vp, &inode);
501153323Srodrigc	if (error)
502159451Srodrigc		goto out;
503153323Srodrigc
504159451Srodrigc	kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
505159451Srodrigc	if (!kbuf)
506159451Srodrigc		goto out_vn_rele;
507159451Srodrigc
508153323Srodrigc	cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
509159451Srodrigc	XVOP_ATTR_LIST(vp, kbuf, al_hreq.buflen, al_hreq.flags,
510153323Srodrigc			cursor, NULL, error);
511159451Srodrigc	if (error)
512159451Srodrigc		goto out_kfree;
513159451Srodrigc
514159451Srodrigc	if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
515159451Srodrigc		error = -EFAULT;
516159451Srodrigc
517159451Srodrigc out_kfree:
518159451Srodrigc	kfree(kbuf);
519159451Srodrigc out_vn_rele:
520153323Srodrigc	VN_RELE(vp);
521159451Srodrigc out:
522159451Srodrigc#endif
523159451Srodrigc	return error;
524159451Srodrigc}
525159451Srodrigc
526159451Srodrigc#if 0
527159451SrodrigcSTATIC int
528159451Srodrigcxfs_attrmulti_attr_get(
529159451Srodrigc	xfs_vnode_t		*vp,
530159451Srodrigc	char			*name,
531159451Srodrigc	char			__user *ubuf,
532159451Srodrigc	__uint32_t		*len,
533159451Srodrigc	__uint32_t		flags)
534159451Srodrigc{
535159451Srodrigc	int			error = EFAULT;
536159451Srodrigc	char			*kbuf;
537159451Srodrigc
538159451Srodrigc	if (*len > XATTR_SIZE_MAX)
539159451Srodrigc		return EINVAL;
540159451Srodrigc	kbuf = kmalloc(*len, GFP_KERNEL);
541159451Srodrigc	if (!kbuf)
542159451Srodrigc		return ENOMEM;
543159451Srodrigc
544159451Srodrigc	XVOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error);
545153323Srodrigc	if (error)
546159451Srodrigc		goto out_kfree;
547159451Srodrigc
548159451Srodrigc	if (copy_to_user(ubuf, kbuf, *len))
549159451Srodrigc		error = EFAULT;
550159451Srodrigc
551159451Srodrigc out_kfree:
552159451Srodrigc	kfree(kbuf);
553159451Srodrigc	return error;
554153323Srodrigc}
555159451Srodrigc#endif
556153323Srodrigc
557159451Srodrigc#if 0
558153323SrodrigcSTATIC int
559159451Srodrigcxfs_attrmulti_attr_set(
560159451Srodrigc	xfs_vnode_t		*vp,
561159451Srodrigc	char			*name,
562159451Srodrigc	const char		__user *ubuf,
563159451Srodrigc	__uint32_t		len,
564159451Srodrigc	__uint32_t		flags)
565159451Srodrigc{
566159451Srodrigc	int			error = EFAULT;
567159451Srodrigc	char			*kbuf;
568159451Srodrigc
569159451Srodrigc	if (IS_RDONLY(&vp->v_inode))
570159451Srodrigc		return -EROFS;
571159451Srodrigc	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
572159451Srodrigc		return EPERM;
573159451Srodrigc	if (len > XATTR_SIZE_MAX)
574159451Srodrigc		return EINVAL;
575159451Srodrigc
576159451Srodrigc	kbuf = kmalloc(len, GFP_KERNEL);
577159451Srodrigc	if (!kbuf)
578159451Srodrigc		return ENOMEM;
579159451Srodrigc
580159451Srodrigc	if (copy_from_user(kbuf, ubuf, len))
581159451Srodrigc		goto out_kfree;
582159451Srodrigc
583159451Srodrigc	XVOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error);
584159451Srodrigc
585159451Srodrigc out_kfree:
586159451Srodrigc	kfree(kbuf);
587159451Srodrigc	return error;
588159451Srodrigc}
589159451Srodrigc#endif
590159451Srodrigc
591159451Srodrigc#if 0
592159451SrodrigcSTATIC int
593159451Srodrigcxfs_attrmulti_attr_remove(
594159451Srodrigc	xfs_vnode_t		*vp,
595159451Srodrigc	char			*name,
596159451Srodrigc	__uint32_t		flags)
597159451Srodrigc{
598159451Srodrigc	int			error;
599159451Srodrigc
600159451Srodrigc	if (IS_RDONLY(&vp->v_inode))
601159451Srodrigc		return -EROFS;
602159451Srodrigc	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
603159451Srodrigc		return EPERM;
604159451Srodrigc
605159451Srodrigc	XVOP_ATTR_REMOVE(vp, name, flags, NULL, error);
606159451Srodrigc	return error;
607159451Srodrigc}
608159451Srodrigc#endif
609159451Srodrigc
610159451SrodrigcSTATIC int
611153323Srodrigcxfs_attrmulti_by_handle(
612153323Srodrigc	xfs_mount_t		*mp,
613159451Srodrigc	void			__user *arg,
614153323Srodrigc	struct file		*parfilp,
615153323Srodrigc	struct inode		*parinode)
616153323Srodrigc{
617159451Srodrigc	int			error = 0;
618159451Srodrigc#if 0
619153323Srodrigc	xfs_attr_multiop_t	*ops;
620153323Srodrigc	xfs_fsop_attrmulti_handlereq_t am_hreq;
621153323Srodrigc	struct inode		*inode;
622159451Srodrigc	xfs_vnode_t		*vp;
623159451Srodrigc	unsigned int		i, size;
624159451Srodrigc	char			*attr_name;
625153323Srodrigc
626159451Srodrigc	if (!capable(CAP_SYS_ADMIN))
627159451Srodrigc		return -XFS_ERROR(EPERM);
628159451Srodrigc	if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
629159451Srodrigc		return -XFS_ERROR(EFAULT);
630159451Srodrigc
631159451Srodrigc	error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &vp, &inode);
632153323Srodrigc	if (error)
633159451Srodrigc		goto out;
634153323Srodrigc
635159451Srodrigc	error = E2BIG;
636153323Srodrigc	size = am_hreq.opcount * sizeof(attr_multiop_t);
637159451Srodrigc	if (!size || size > 16 * PAGE_SIZE)
638159451Srodrigc		goto out_vn_rele;
639153323Srodrigc
640159451Srodrigc	error = ENOMEM;
641159451Srodrigc	ops = kmalloc(size, GFP_KERNEL);
642159451Srodrigc	if (!ops)
643159451Srodrigc		goto out_vn_rele;
644153323Srodrigc
645159451Srodrigc	error = EFAULT;
646159451Srodrigc	if (copy_from_user(ops, am_hreq.ops, size))
647159451Srodrigc		goto out_kfree_ops;
648159451Srodrigc
649159451Srodrigc	attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
650159451Srodrigc	if (!attr_name)
651159451Srodrigc		goto out_kfree_ops;
652159451Srodrigc
653159451Srodrigc
654159451Srodrigc	error = 0;
655153323Srodrigc	for (i = 0; i < am_hreq.opcount; i++) {
656159451Srodrigc		ops[i].am_error = strncpy_from_user(attr_name,
657159451Srodrigc				ops[i].am_attrname, MAXNAMELEN);
658159451Srodrigc		if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
659159451Srodrigc			error = -ERANGE;
660159451Srodrigc		if (ops[i].am_error < 0)
661159451Srodrigc			break;
662159451Srodrigc
663159451Srodrigc		switch (ops[i].am_opcode) {
664153323Srodrigc		case ATTR_OP_GET:
665159451Srodrigc			ops[i].am_error = xfs_attrmulti_attr_get(vp,
666159451Srodrigc					attr_name, ops[i].am_attrvalue,
667159451Srodrigc					&ops[i].am_length, ops[i].am_flags);
668153323Srodrigc			break;
669153323Srodrigc		case ATTR_OP_SET:
670159451Srodrigc			ops[i].am_error = xfs_attrmulti_attr_set(vp,
671159451Srodrigc					attr_name, ops[i].am_attrvalue,
672159451Srodrigc					ops[i].am_length, ops[i].am_flags);
673153323Srodrigc			break;
674153323Srodrigc		case ATTR_OP_REMOVE:
675159451Srodrigc			ops[i].am_error = xfs_attrmulti_attr_remove(vp,
676159451Srodrigc					attr_name, ops[i].am_flags);
677153323Srodrigc			break;
678153323Srodrigc		default:
679153323Srodrigc			ops[i].am_error = EINVAL;
680153323Srodrigc		}
681153323Srodrigc	}
682153323Srodrigc
683153323Srodrigc	if (copy_to_user(am_hreq.ops, ops, size))
684159451Srodrigc		error = XFS_ERROR(EFAULT);
685153323Srodrigc
686159451Srodrigc	kfree(attr_name);
687159451Srodrigc out_kfree_ops:
688153323Srodrigc	kfree(ops);
689159451Srodrigc out_vn_rele:
690153323Srodrigc	VN_RELE(vp);
691159451Srodrigc out:
692159451Srodrigc#endif
693153323Srodrigc	return error;
694153323Srodrigc}
695153323Srodrigc
696153323Srodrigc/* prototypes for a few of the stack-hungry cases that have
697153323Srodrigc * their own functions.  Functions are defined after their use
698153323Srodrigc * so gcc doesn't get fancy and inline them with -03 */
699153323Srodrigc
700153323SrodrigcSTATIC int
701153323Srodrigcxfs_ioc_space(
702153323Srodrigc	bhv_desc_t		*bdp,
703159451Srodrigc	xfs_vnode_t		*vp,
704153323Srodrigc	struct file		*filp,
705153323Srodrigc	int			flags,
706194944Srdivacky	u_long			cmd,
707159451Srodrigc	void			__user *arg);
708153323Srodrigc
709153323SrodrigcSTATIC int
710153323Srodrigcxfs_ioc_bulkstat(
711153323Srodrigc	xfs_mount_t		*mp,
712153323Srodrigc	unsigned int		cmd,
713159451Srodrigc	void			__user *arg);
714153323Srodrigc
715153323SrodrigcSTATIC int
716153323Srodrigcxfs_ioc_fsgeometry_v1(
717153323Srodrigc	xfs_mount_t		*mp,
718159451Srodrigc	void			__user *arg);
719153323Srodrigc
720153323SrodrigcSTATIC int
721153323Srodrigcxfs_ioc_fsgeometry(
722153323Srodrigc	xfs_mount_t		*mp,
723159451Srodrigc	void			__user *arg);
724153323Srodrigc
725153323SrodrigcSTATIC int
726153323Srodrigcxfs_ioc_xattr(
727159451Srodrigc	xfs_vnode_t		*vp,
728153323Srodrigc	xfs_inode_t		*ip,
729153323Srodrigc	struct file		*filp,
730153323Srodrigc	unsigned int		cmd,
731159451Srodrigc	void			__user *arg);
732153323Srodrigc
733153323SrodrigcSTATIC int
734153323Srodrigcxfs_ioc_getbmap(
735153323Srodrigc	bhv_desc_t		*bdp,
736153323Srodrigc	struct file		*filp,
737153323Srodrigc	int			flags,
738153323Srodrigc	unsigned int		cmd,
739159451Srodrigc	void			__user *arg);
740153323Srodrigc
741153323SrodrigcSTATIC int
742153323Srodrigcxfs_ioc_getbmapx(
743153323Srodrigc	bhv_desc_t		*bdp,
744159451Srodrigc	void			__user *arg);
745153323Srodrigc
746153323Srodrigcint
747153323Srodrigcxfs_ioctl(
748153323Srodrigc	bhv_desc_t		*bdp,
749153323Srodrigc	struct inode		*inode,
750153323Srodrigc	struct file		*filp,
751153323Srodrigc	int			ioflags,
752194944Srdivacky	u_long			cmd,
753159451Srodrigc	void			*arg)
754153323Srodrigc{
755153323Srodrigc	int			error;
756159451Srodrigc	xfs_vnode_t		*vp;
757153323Srodrigc	xfs_inode_t		*ip;
758153323Srodrigc	xfs_mount_t		*mp;
759153323Srodrigc
760159451Srodrigc//	vp = vn_from_inode(inode);
761159451Srodrigc	vp = BHV_TO_VNODE(bdp);
762153323Srodrigc
763194974Srdivacky	printf("xfs_ioctl: bdp %p flags 0x%x cmd 0x%lx basecmd 0x%lx arg %p\n",
764159451Srodrigc	       bdp, ioflags, cmd,
765159451Srodrigc	       IOCBASECMD(cmd),
766159451Srodrigc	       arg);
767159451Srodrigc
768159451Srodrigc
769153323Srodrigc	vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address);
770153323Srodrigc
771153323Srodrigc	ip = XFS_BHVTOI(bdp);
772153323Srodrigc	mp = ip->i_mount;
773153323Srodrigc
774159451Srodrigc
775159451Srodrigc#if 0
776159451Srodrigc	if ((cmd << 24 >> 24) ==  (XFS_IOC_GETBMAPX << 24 >> 24)) {
777159451Srodrigc		cmd = XFS_IOC_GETBMAPX;
778159451Srodrigc	}
779159451Srodrigc#endif
780159451Srodrigc
781159451Srodrigc
782159451Srodrigc
783153323Srodrigc	switch (cmd) {
784153323Srodrigc
785153323Srodrigc	case XFS_IOC_ALLOCSP:
786153323Srodrigc	case XFS_IOC_FREESP:
787153323Srodrigc	case XFS_IOC_RESVSP:
788153323Srodrigc	case XFS_IOC_UNRESVSP:
789153323Srodrigc	case XFS_IOC_ALLOCSP64:
790153323Srodrigc	case XFS_IOC_FREESP64:
791153323Srodrigc	case XFS_IOC_RESVSP64:
792153323Srodrigc	case XFS_IOC_UNRESVSP64:
793153323Srodrigc		/*
794153323Srodrigc		 * Only allow the sys admin to reserve space unless
795153323Srodrigc		 * unwritten extents are enabled.
796153323Srodrigc		 */
797153323Srodrigc		if (!XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) &&
798153323Srodrigc		    !capable(CAP_SYS_ADMIN))
799153323Srodrigc			return -EPERM;
800153323Srodrigc
801153323Srodrigc		return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
802153323Srodrigc
803153323Srodrigc	case XFS_IOC_DIOINFO: {
804153323Srodrigc		struct dioattr	da;
805159451Srodrigc		xfs_buftarg_t	*target =
806159451Srodrigc			(ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
807159451Srodrigc			mp->m_rtdev_targp : mp->m_ddev_targp;
808153323Srodrigc
809159451Srodrigc		da.d_mem = da.d_miniosz = 1 << target->bt_sshift;
810159451Srodrigc		da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
811153323Srodrigc
812159451Srodrigc		if (copy_to_user(arg, &da, sizeof(da)))
813159451Srodrigc			return XFS_ERROR(EFAULT);
814153323Srodrigc		return 0;
815153323Srodrigc	}
816153323Srodrigc
817153323Srodrigc	case XFS_IOC_FSBULKSTAT_SINGLE:
818153323Srodrigc	case XFS_IOC_FSBULKSTAT:
819153323Srodrigc	case XFS_IOC_FSINUMBERS:
820153323Srodrigc		return xfs_ioc_bulkstat(mp, cmd, arg);
821153323Srodrigc
822153323Srodrigc	case XFS_IOC_FSGEOMETRY_V1:
823153323Srodrigc		return xfs_ioc_fsgeometry_v1(mp, arg);
824153323Srodrigc
825153323Srodrigc	case XFS_IOC_FSGEOMETRY:
826153323Srodrigc		return xfs_ioc_fsgeometry(mp, arg);
827153323Srodrigc
828153323Srodrigc	case XFS_IOC_GETVERSION:
829153323Srodrigc	case XFS_IOC_GETXFLAGS:
830153323Srodrigc	case XFS_IOC_SETXFLAGS:
831153323Srodrigc	case XFS_IOC_FSGETXATTR:
832153323Srodrigc	case XFS_IOC_FSSETXATTR:
833153323Srodrigc	case XFS_IOC_FSGETXATTRA:
834153323Srodrigc		return xfs_ioc_xattr(vp, ip, filp, cmd, arg);
835153323Srodrigc
836153323Srodrigc	case XFS_IOC_FSSETDM: {
837153323Srodrigc		struct fsdmidata	dmi;
838153323Srodrigc
839159451Srodrigc		if (copy_from_user(&dmi, arg, sizeof(dmi)))
840159451Srodrigc			return XFS_ERROR(EFAULT);
841153323Srodrigc
842153323Srodrigc		error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate,
843153323Srodrigc							NULL);
844159451Srodrigc		return error;
845153323Srodrigc	}
846153323Srodrigc
847153323Srodrigc	case XFS_IOC_GETBMAP:
848153323Srodrigc	case XFS_IOC_GETBMAPA:
849153323Srodrigc		return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg);
850153323Srodrigc
851153323Srodrigc	case XFS_IOC_GETBMAPX:
852153323Srodrigc		return xfs_ioc_getbmapx(bdp, arg);
853153323Srodrigc
854153323Srodrigc	case XFS_IOC_FD_TO_HANDLE:
855153323Srodrigc	case XFS_IOC_PATH_TO_HANDLE:
856153323Srodrigc	case XFS_IOC_PATH_TO_FSHANDLE:
857153323Srodrigc		return xfs_find_handle(cmd, arg);
858153323Srodrigc
859153323Srodrigc	case XFS_IOC_OPEN_BY_HANDLE:
860153323Srodrigc		return xfs_open_by_handle(mp, arg, filp, inode);
861153323Srodrigc
862153323Srodrigc	case XFS_IOC_FSSETDM_BY_HANDLE:
863153323Srodrigc		return xfs_fssetdm_by_handle(mp, arg, filp, inode);
864153323Srodrigc
865153323Srodrigc	case XFS_IOC_READLINK_BY_HANDLE:
866153323Srodrigc		return xfs_readlink_by_handle(mp, arg, filp, inode);
867153323Srodrigc
868153323Srodrigc	case XFS_IOC_ATTRLIST_BY_HANDLE:
869153323Srodrigc		return xfs_attrlist_by_handle(mp, arg, filp, inode);
870153323Srodrigc
871153323Srodrigc	case XFS_IOC_ATTRMULTI_BY_HANDLE:
872153323Srodrigc		return xfs_attrmulti_by_handle(mp, arg, filp, inode);
873153323Srodrigc
874153323Srodrigc	case XFS_IOC_SWAPEXT: {
875159451Srodrigc		error = xfs_swapext((struct xfs_swapext __user *)arg);
876159451Srodrigc		return error;
877153323Srodrigc	}
878153323Srodrigc
879153323Srodrigc	case XFS_IOC_FSCOUNTS: {
880153323Srodrigc		xfs_fsop_counts_t out;
881153323Srodrigc
882153323Srodrigc		error = xfs_fs_counts(mp, &out);
883153323Srodrigc		if (error)
884159451Srodrigc			return error;
885153323Srodrigc
886159451Srodrigc		if (copy_to_user(arg, &out, sizeof(out)))
887159451Srodrigc			return XFS_ERROR(EFAULT);
888153323Srodrigc		return 0;
889153323Srodrigc	}
890153323Srodrigc
891153323Srodrigc	case XFS_IOC_SET_RESBLKS: {
892153323Srodrigc		xfs_fsop_resblks_t inout;
893153323Srodrigc		__uint64_t	   in;
894153323Srodrigc
895153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
896159451Srodrigc			return EPERM;
897153323Srodrigc
898159451Srodrigc		if (copy_from_user(&inout, arg, sizeof(inout)))
899159451Srodrigc			return XFS_ERROR(EFAULT);
900153323Srodrigc
901153323Srodrigc		/* input parameter is passed in resblks field of structure */
902153323Srodrigc		in = inout.resblks;
903153323Srodrigc		error = xfs_reserve_blocks(mp, &in, &inout);
904153323Srodrigc		if (error)
905159451Srodrigc			return error;
906153323Srodrigc
907159451Srodrigc		if (copy_to_user(arg, &inout, sizeof(inout)))
908159451Srodrigc			return XFS_ERROR(EFAULT);
909153323Srodrigc		return 0;
910153323Srodrigc	}
911153323Srodrigc
912153323Srodrigc	case XFS_IOC_GET_RESBLKS: {
913153323Srodrigc		xfs_fsop_resblks_t out;
914153323Srodrigc
915153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
916159451Srodrigc			return EPERM;
917153323Srodrigc
918153323Srodrigc		error = xfs_reserve_blocks(mp, NULL, &out);
919153323Srodrigc		if (error)
920159451Srodrigc			return error;
921153323Srodrigc
922159451Srodrigc		if (copy_to_user(arg, &out, sizeof(out)))
923159451Srodrigc			return XFS_ERROR(EFAULT);
924153323Srodrigc
925153323Srodrigc		return 0;
926153323Srodrigc	}
927153323Srodrigc
928153323Srodrigc	case XFS_IOC_FSGROWFSDATA: {
929153323Srodrigc		xfs_growfs_data_t in;
930153323Srodrigc
931153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
932159451Srodrigc			return EPERM;
933153323Srodrigc
934159451Srodrigc		if (copy_from_user(&in, arg, sizeof(in)))
935159451Srodrigc			return XFS_ERROR(EFAULT);
936153323Srodrigc
937153323Srodrigc		error = xfs_growfs_data(mp, &in);
938159451Srodrigc		return error;
939153323Srodrigc	}
940153323Srodrigc
941153323Srodrigc	case XFS_IOC_FSGROWFSLOG: {
942153323Srodrigc		xfs_growfs_log_t in;
943153323Srodrigc
944153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
945159451Srodrigc			return EPERM;
946153323Srodrigc
947159451Srodrigc		if (copy_from_user(&in, arg, sizeof(in)))
948159451Srodrigc			return XFS_ERROR(EFAULT);
949153323Srodrigc
950153323Srodrigc		error = xfs_growfs_log(mp, &in);
951159451Srodrigc		return error;
952153323Srodrigc	}
953153323Srodrigc
954153323Srodrigc	case XFS_IOC_FSGROWFSRT: {
955153323Srodrigc		xfs_growfs_rt_t in;
956153323Srodrigc
957153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
958159451Srodrigc			return EPERM;
959153323Srodrigc
960159451Srodrigc		if (copy_from_user(&in, arg, sizeof(in)))
961159451Srodrigc			return XFS_ERROR(EFAULT);
962153323Srodrigc
963153323Srodrigc		error = xfs_growfs_rt(mp, &in);
964159451Srodrigc		return error;
965153323Srodrigc	}
966159451Srodrigc#if 0
967153323Srodrigc	case XFS_IOC_FREEZE:
968153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
969153323Srodrigc			return -EPERM;
970153323Srodrigc		xfs_fs_freeze(mp);
971153323Srodrigc		return 0;
972153323Srodrigc
973153323Srodrigc	case XFS_IOC_THAW:
974153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
975153323Srodrigc			return -EPERM;
976153323Srodrigc		xfs_fs_thaw(mp);
977153323Srodrigc		return 0;
978159451Srodrigc#endif
979153323Srodrigc
980153323Srodrigc	case XFS_IOC_GOINGDOWN: {
981153323Srodrigc		__uint32_t in;
982153323Srodrigc
983153323Srodrigc		if (!capable(CAP_SYS_ADMIN))
984159451Srodrigc			return EPERM;
985153323Srodrigc
986159451Srodrigc		if (copy_from_user(&in, arg, sizeof(__uint32_t)))
987159451Srodrigc			return XFS_ERROR(EFAULT);
988153323Srodrigc
989153323Srodrigc		error = xfs_fs_goingdown(mp, in);
990159451Srodrigc		return error;
991153323Srodrigc	}
992153323Srodrigc
993153323Srodrigc	case XFS_IOC_ERROR_INJECTION: {
994153323Srodrigc		xfs_error_injection_t in;
995153323Srodrigc
996159451Srodrigc		if (!capable(CAP_SYS_ADMIN))
997159451Srodrigc			return EPERM;
998153323Srodrigc
999159451Srodrigc		if (copy_from_user(&in, arg, sizeof(in)))
1000159451Srodrigc			return XFS_ERROR(EFAULT);
1001159451Srodrigc
1002153323Srodrigc		error = xfs_errortag_add(in.errtag, mp);
1003159451Srodrigc		return error;
1004153323Srodrigc	}
1005153323Srodrigc
1006153323Srodrigc	case XFS_IOC_ERROR_CLEARALL:
1007159451Srodrigc		if (!capable(CAP_SYS_ADMIN))
1008159451Srodrigc			return EPERM;
1009159451Srodrigc
1010153323Srodrigc		error = xfs_errortag_clearall(mp);
1011159451Srodrigc		return error;
1012153323Srodrigc
1013153323Srodrigc	default:
1014159451Srodrigc		return ENOTTY;
1015153323Srodrigc	}
1016153323Srodrigc}
1017153323Srodrigc
1018153323SrodrigcSTATIC int
1019153323Srodrigcxfs_ioc_space(
1020153323Srodrigc	bhv_desc_t		*bdp,
1021159451Srodrigc	xfs_vnode_t		*vp,
1022153323Srodrigc	struct file		*filp,
1023153323Srodrigc	int			ioflags,
1024194944Srdivacky	u_long			cmd,
1025159451Srodrigc	void			__user *arg)
1026153323Srodrigc{
1027153323Srodrigc	xfs_flock64_t		bf;
1028153323Srodrigc	int			attr_flags = 0;
1029153323Srodrigc	int			error;
1030153323Srodrigc
1031159451Srodrigc#if 0
1032153323Srodrigc	if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
1033153323Srodrigc		return -XFS_ERROR(EPERM);
1034153323Srodrigc
1035159451Srodrigc	if (!(filp->f_mode & FMODE_WRITE))
1036153323Srodrigc		return -XFS_ERROR(EBADF);
1037159451Srodrigc#endif
1038153323Srodrigc
1039159451Srodrigc	if (!VN_ISREG(vp))
1040153323Srodrigc		return -XFS_ERROR(EINVAL);
1041153323Srodrigc
1042159451Srodrigc	if (copy_from_user(&bf, arg, sizeof(bf)))
1043153323Srodrigc		return -XFS_ERROR(EFAULT);
1044153323Srodrigc
1045159451Srodrigc#if 0
1046153323Srodrigc	if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1047153323Srodrigc		attr_flags |= ATTR_NONBLOCK;
1048159451Srodrigc#endif
1049153323Srodrigc	if (ioflags & IO_INVIS)
1050153323Srodrigc		attr_flags |= ATTR_DMI;
1051153323Srodrigc
1052159451Srodrigc	error = xfs_change_file_space(bdp, cmd,
1053159451Srodrigc				      &bf, filp->f_offset,
1054159451Srodrigc				      NULL, attr_flags);
1055153323Srodrigc	return -error;
1056153323Srodrigc}
1057153323Srodrigc
1058153323SrodrigcSTATIC int
1059153323Srodrigcxfs_ioc_bulkstat(
1060153323Srodrigc	xfs_mount_t		*mp,
1061153323Srodrigc	unsigned int		cmd,
1062159451Srodrigc	void			__user *arg)
1063153323Srodrigc{
1064153323Srodrigc	xfs_fsop_bulkreq_t	bulkreq;
1065153323Srodrigc	int			count;	/* # of records returned */
1066153323Srodrigc	xfs_ino_t		inlast;	/* last inode number */
1067153323Srodrigc	int			done;
1068153323Srodrigc	int			error;
1069153323Srodrigc
1070153323Srodrigc	/* done = 1 if there are more stats to get and if bulkstat */
1071153323Srodrigc	/* should be called again (unused here, but used in dmapi) */
1072153323Srodrigc
1073159451Srodrigc#if 0
1074153323Srodrigc	if (!capable(CAP_SYS_ADMIN))
1075153323Srodrigc		return -EPERM;
1076159451Srodrigc#endif
1077153323Srodrigc
1078153323Srodrigc	if (XFS_FORCED_SHUTDOWN(mp))
1079153323Srodrigc		return -XFS_ERROR(EIO);
1080153323Srodrigc
1081159451Srodrigc	if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
1082153323Srodrigc		return -XFS_ERROR(EFAULT);
1083153323Srodrigc
1084159451Srodrigc	if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
1085153323Srodrigc		return -XFS_ERROR(EFAULT);
1086153323Srodrigc
1087153323Srodrigc	if ((count = bulkreq.icount) <= 0)
1088153323Srodrigc		return -XFS_ERROR(EINVAL);
1089153323Srodrigc
1090153323Srodrigc	if (cmd == XFS_IOC_FSINUMBERS)
1091159451Srodrigc		error = xfs_inumbers(mp, &inlast, &count,
1092153323Srodrigc						bulkreq.ubuffer);
1093153323Srodrigc	else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
1094153323Srodrigc		error = xfs_bulkstat_single(mp, &inlast,
1095153323Srodrigc						bulkreq.ubuffer, &done);
1096153323Srodrigc	else {	/* XFS_IOC_FSBULKSTAT */
1097153323Srodrigc		if (count == 1 && inlast != 0) {
1098153323Srodrigc			inlast++;
1099153323Srodrigc			error = xfs_bulkstat_single(mp, &inlast,
1100153323Srodrigc					bulkreq.ubuffer, &done);
1101153323Srodrigc		} else {
1102159451Srodrigc			error = xfs_bulkstat(mp, &inlast, &count,
1103153323Srodrigc				(bulkstat_one_pf)xfs_bulkstat_one, NULL,
1104153323Srodrigc				sizeof(xfs_bstat_t), bulkreq.ubuffer,
1105153323Srodrigc				BULKSTAT_FG_QUICK, &done);
1106153323Srodrigc		}
1107153323Srodrigc	}
1108153323Srodrigc
1109153323Srodrigc	if (error)
1110153323Srodrigc		return -error;
1111153323Srodrigc
1112153323Srodrigc	if (bulkreq.ocount != NULL) {
1113159451Srodrigc		if (copy_to_user(bulkreq.lastip, &inlast,
1114153323Srodrigc						sizeof(xfs_ino_t)))
1115153323Srodrigc			return -XFS_ERROR(EFAULT);
1116153323Srodrigc
1117159451Srodrigc		if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
1118153323Srodrigc			return -XFS_ERROR(EFAULT);
1119153323Srodrigc	}
1120153323Srodrigc
1121153323Srodrigc	return 0;
1122153323Srodrigc}
1123153323Srodrigc
1124153323SrodrigcSTATIC int
1125153323Srodrigcxfs_ioc_fsgeometry_v1(
1126153323Srodrigc	xfs_mount_t		*mp,
1127159451Srodrigc	void			__user *arg)
1128153323Srodrigc{
1129153323Srodrigc	xfs_fsop_geom_v1_t	fsgeo;
1130153323Srodrigc	int			error;
1131153323Srodrigc
1132153323Srodrigc	error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
1133153323Srodrigc	if (error)
1134153323Srodrigc		return -error;
1135153323Srodrigc
1136159451Srodrigc	if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
1137153323Srodrigc		return -XFS_ERROR(EFAULT);
1138153323Srodrigc	return 0;
1139153323Srodrigc}
1140153323Srodrigc
1141153323SrodrigcSTATIC int
1142153323Srodrigcxfs_ioc_fsgeometry(
1143153323Srodrigc	xfs_mount_t		*mp,
1144159451Srodrigc	void			__user *arg)
1145153323Srodrigc{
1146153323Srodrigc	xfs_fsop_geom_t		fsgeo;
1147153323Srodrigc	int			error;
1148153323Srodrigc
1149153323Srodrigc	error = xfs_fs_geometry(mp, &fsgeo, 4);
1150153323Srodrigc	if (error)
1151159451Srodrigc		goto error;
1152153323Srodrigc
1153159451Srodrigc	printf ("xfs_ioc_fsgeometry: error? %d arg %p\n",error,arg);
1154159451Srodrigc
1155159451Srodrigc#if 0
1156159451Srodrigc	if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
1157159451Srodrigc		return XFS_ERROR(EFAULT);
1158159451Srodrigc#endif
1159159451Srodrigc	memcpy(arg, &fsgeo, sizeof(fsgeo));
1160159451Srodrigc
1161159451Srodrigc	printf ("xfs_ioc_fsgeometry: error? %d arg %p\n",error,arg);
1162159451Srodrigcerror:
1163159451Srodrigc	return error;
1164153323Srodrigc}
1165153323Srodrigc
1166153323Srodrigc/*
1167153323Srodrigc * Linux extended inode flags interface.
1168153323Srodrigc */
1169153323Srodrigc#define LINUX_XFLAG_SYNC	0x00000008 /* Synchronous updates */
1170153323Srodrigc#define LINUX_XFLAG_IMMUTABLE	0x00000010 /* Immutable file */
1171153323Srodrigc#define LINUX_XFLAG_APPEND	0x00000020 /* writes to file may only append */
1172153323Srodrigc#define LINUX_XFLAG_NODUMP	0x00000040 /* do not dump file */
1173153323Srodrigc#define LINUX_XFLAG_NOATIME	0x00000080 /* do not update atime */
1174153323Srodrigc
1175153323SrodrigcSTATIC unsigned int
1176153323Srodrigcxfs_merge_ioc_xflags(
1177153323Srodrigc	unsigned int	flags,
1178153323Srodrigc	unsigned int	start)
1179153323Srodrigc{
1180153323Srodrigc	unsigned int	xflags = start;
1181153323Srodrigc
1182153323Srodrigc	if (flags & LINUX_XFLAG_IMMUTABLE)
1183153323Srodrigc		xflags |= XFS_XFLAG_IMMUTABLE;
1184153323Srodrigc	else
1185153323Srodrigc		xflags &= ~XFS_XFLAG_IMMUTABLE;
1186153323Srodrigc	if (flags & LINUX_XFLAG_APPEND)
1187153323Srodrigc		xflags |= XFS_XFLAG_APPEND;
1188153323Srodrigc	else
1189153323Srodrigc		xflags &= ~XFS_XFLAG_APPEND;
1190153323Srodrigc	if (flags & LINUX_XFLAG_SYNC)
1191153323Srodrigc		xflags |= XFS_XFLAG_SYNC;
1192153323Srodrigc	else
1193153323Srodrigc		xflags &= ~XFS_XFLAG_SYNC;
1194153323Srodrigc	if (flags & LINUX_XFLAG_NOATIME)
1195153323Srodrigc		xflags |= XFS_XFLAG_NOATIME;
1196153323Srodrigc	else
1197153323Srodrigc		xflags &= ~XFS_XFLAG_NOATIME;
1198153323Srodrigc	if (flags & LINUX_XFLAG_NODUMP)
1199153323Srodrigc		xflags |= XFS_XFLAG_NODUMP;
1200153323Srodrigc	else
1201153323Srodrigc		xflags &= ~XFS_XFLAG_NODUMP;
1202153323Srodrigc
1203153323Srodrigc	return xflags;
1204153323Srodrigc}
1205153323Srodrigc
1206159451SrodrigcSTATIC unsigned int
1207159451Srodrigcxfs_di2lxflags(
1208159451Srodrigc	__uint16_t	di_flags)
1209159451Srodrigc{
1210159451Srodrigc	unsigned int	flags = 0;
1211159451Srodrigc
1212159451Srodrigc	if (di_flags & XFS_DIFLAG_IMMUTABLE)
1213159451Srodrigc		flags |= LINUX_XFLAG_IMMUTABLE;
1214159451Srodrigc	if (di_flags & XFS_DIFLAG_APPEND)
1215159451Srodrigc		flags |= LINUX_XFLAG_APPEND;
1216159451Srodrigc	if (di_flags & XFS_DIFLAG_SYNC)
1217159451Srodrigc		flags |= LINUX_XFLAG_SYNC;
1218159451Srodrigc	if (di_flags & XFS_DIFLAG_NOATIME)
1219159451Srodrigc		flags |= LINUX_XFLAG_NOATIME;
1220159451Srodrigc	if (di_flags & XFS_DIFLAG_NODUMP)
1221159451Srodrigc		flags |= LINUX_XFLAG_NODUMP;
1222159451Srodrigc	return flags;
1223159451Srodrigc}
1224159451Srodrigc
1225153323SrodrigcSTATIC int
1226153323Srodrigcxfs_ioc_xattr(
1227159451Srodrigc	xfs_vnode_t		*vp,
1228153323Srodrigc	xfs_inode_t		*ip,
1229153323Srodrigc	struct file		*filp,
1230153323Srodrigc	unsigned int		cmd,
1231159451Srodrigc	void			__user *arg)
1232153323Srodrigc{
1233153323Srodrigc	struct fsxattr		fa;
1234159451Srodrigc	struct xfs_vattr	*vattr;
1235153323Srodrigc	int			error;
1236153323Srodrigc	int			attr_flags;
1237153323Srodrigc	unsigned int		flags;
1238153323Srodrigc
1239159451Srodrigc	error = 0;
1240159451Srodrigc	attr_flags = 0;
1241159451Srodrigc
1242159451Srodrigc	vattr = kmem_alloc(sizeof(struct xfs_vattr), KM_SLEEP);
1243159451Srodrigc	if (unlikely(!vattr))
1244159451Srodrigc		return ENOMEM;
1245159451Srodrigc
1246153323Srodrigc	switch (cmd) {
1247153323Srodrigc	case XFS_IOC_FSGETXATTR: {
1248159451Srodrigc		vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
1249159451Srodrigc				 XFS_AT_NEXTENTS | XFS_AT_PROJID;
1250159451Srodrigc		XVOP_GETATTR(vp, vattr, 0, NULL, error);
1251159451Srodrigc		if (unlikely(error)) {
1252159451Srodrigc			break;
1253159451Srodrigc		}
1254153323Srodrigc
1255159451Srodrigc		fa.fsx_xflags	= vattr->va_xflags;
1256159451Srodrigc		fa.fsx_extsize	= vattr->va_extsize;
1257159451Srodrigc		fa.fsx_nextents = vattr->va_nextents;
1258159451Srodrigc		fa.fsx_projid	= vattr->va_projid;
1259153323Srodrigc
1260159451Srodrigc		if (copy_to_user(arg, &fa, sizeof(fa))) {
1261159451Srodrigc			error = EFAULT;
1262159451Srodrigc			break;
1263159451Srodrigc		}
1264159451Srodrigc		break;
1265153323Srodrigc	}
1266153323Srodrigc
1267153323Srodrigc	case XFS_IOC_FSSETXATTR: {
1268159451Srodrigc		if (copy_from_user(&fa, arg, sizeof(fa))) {
1269159451Srodrigc			error = EFAULT;
1270159451Srodrigc			break;
1271159451Srodrigc		}
1272153323Srodrigc
1273153323Srodrigc		attr_flags = 0;
1274159451Srodrigc#if 0
1275153323Srodrigc		if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1276153323Srodrigc			attr_flags |= ATTR_NONBLOCK;
1277159451Srodrigc#endif
1278153323Srodrigc
1279159451Srodrigc		vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
1280159451Srodrigc		vattr->va_xflags  = fa.fsx_xflags;
1281159451Srodrigc		vattr->va_extsize = fa.fsx_extsize;
1282159451Srodrigc		vattr->va_projid  = fa.fsx_projid;
1283153323Srodrigc
1284159451Srodrigc		XVOP_SETATTR(vp, vattr, attr_flags, NULL, error);
1285159451Srodrigc#if 0
1286159451Srodrigc		if (likely(!error))
1287159451Srodrigc			__vn_revalidate(vp, vattr);	/* update flags */
1288159451Srodrigc#endif
1289159451Srodrigc		break;
1290153323Srodrigc	}
1291153323Srodrigc
1292153323Srodrigc	case XFS_IOC_FSGETXATTRA: {
1293159451Srodrigc		vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
1294159451Srodrigc				 XFS_AT_ANEXTENTS | XFS_AT_PROJID;
1295159451Srodrigc		XVOP_GETATTR(vp, vattr, 0, NULL, error);
1296159451Srodrigc		if (unlikely(error)) {
1297159451Srodrigc			break;
1298159451Srodrigc		}
1299153323Srodrigc
1300159451Srodrigc		fa.fsx_xflags	= vattr->va_xflags;
1301159451Srodrigc		fa.fsx_extsize	= vattr->va_extsize;
1302159451Srodrigc		fa.fsx_nextents = vattr->va_anextents;
1303159451Srodrigc		fa.fsx_projid	= vattr->va_projid;
1304153323Srodrigc
1305159451Srodrigc		if (copy_to_user(arg, &fa, sizeof(fa))) {
1306159451Srodrigc			error = EFAULT;
1307159451Srodrigc			break;
1308159451Srodrigc		}
1309159451Srodrigc		break;
1310153323Srodrigc	}
1311153323Srodrigc
1312153323Srodrigc	case XFS_IOC_GETXFLAGS: {
1313159451Srodrigc		flags = xfs_di2lxflags(ip->i_d.di_flags);
1314159451Srodrigc		if (copy_to_user(arg, &flags, sizeof(flags)))
1315159451Srodrigc			error = EFAULT;
1316159451Srodrigc		break;
1317153323Srodrigc	}
1318153323Srodrigc
1319153323Srodrigc	case XFS_IOC_SETXFLAGS: {
1320159451Srodrigc		if (copy_from_user(&flags, arg, sizeof(flags))) {
1321159451Srodrigc			error = EFAULT;
1322159451Srodrigc			break;
1323159451Srodrigc		}
1324153323Srodrigc
1325153323Srodrigc		if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \
1326153323Srodrigc			      LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \
1327159451Srodrigc			      LINUX_XFLAG_SYNC)) {
1328159451Srodrigc			error = EOPNOTSUPP;
1329159451Srodrigc			break;
1330159451Srodrigc		}
1331153323Srodrigc
1332159451Srodrigc#if 0
1333153323Srodrigc		attr_flags = 0;
1334153323Srodrigc		if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
1335153323Srodrigc			attr_flags |= ATTR_NONBLOCK;
1336159451Srodrigc#endif
1337153323Srodrigc
1338159451Srodrigc		vattr->va_mask = XFS_AT_XFLAGS;
1339159451Srodrigc		vattr->va_xflags = xfs_merge_ioc_xflags(flags,
1340159451Srodrigc							xfs_ip2xflags(ip));
1341153323Srodrigc
1342159451Srodrigc		XVOP_SETATTR(vp, vattr, attr_flags, NULL, error);
1343159451Srodrigc#if 0
1344159451Srodrigc		if (likely(!error))
1345159451Srodrigc			__vn_revalidate(vp, vattr);	/* update flags */
1346159451Srodrigc#endif
1347159451Srodrigc		break;
1348153323Srodrigc	}
1349153323Srodrigc
1350159451Srodrigc#if 0
1351153323Srodrigc	case XFS_IOC_GETVERSION: {
1352159451Srodrigc		flags = vn_to_inode(vp)->i_generation;
1353159451Srodrigc		if (copy_to_user(arg, &flags, sizeof(flags)))
1354159451Srodrigc			error = EFAULT;
1355159451Srodrigc		break;
1356153323Srodrigc	}
1357159451Srodrigc#endif
1358153323Srodrigc
1359153323Srodrigc	default:
1360159451Srodrigc		error = ENOTTY;
1361159451Srodrigc		break;
1362153323Srodrigc	}
1363159451Srodrigc
1364159451Srodrigc	kmem_free(vattr,sizeof(struct xfs_vattr));
1365159451Srodrigc	return error;
1366153323Srodrigc}
1367153323Srodrigc
1368153323SrodrigcSTATIC int
1369153323Srodrigcxfs_ioc_getbmap(
1370153323Srodrigc	bhv_desc_t		*bdp,
1371153323Srodrigc	struct file		*filp,
1372153323Srodrigc	int			ioflags,
1373153323Srodrigc	unsigned int		cmd,
1374159451Srodrigc	void			__user *arg)
1375153323Srodrigc{
1376153323Srodrigc	struct getbmap		bm;
1377153323Srodrigc	int			iflags;
1378153323Srodrigc	int			error;
1379153323Srodrigc
1380159451Srodrigc	if (copy_from_user(&bm, arg, sizeof(bm)))
1381153323Srodrigc		return -XFS_ERROR(EFAULT);
1382153323Srodrigc
1383153323Srodrigc	if (bm.bmv_count < 2)
1384153323Srodrigc		return -XFS_ERROR(EINVAL);
1385153323Srodrigc
1386153323Srodrigc	iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
1387153323Srodrigc	if (ioflags & IO_INVIS)
1388153323Srodrigc		iflags |= BMV_IF_NO_DMAPI_READ;
1389153323Srodrigc
1390159451Srodrigc	error = xfs_getbmap(bdp, &bm, (struct getbmap __user *)arg+1, iflags);
1391153323Srodrigc	if (error)
1392153323Srodrigc		return -error;
1393153323Srodrigc
1394159451Srodrigc	if (copy_to_user(arg, &bm, sizeof(bm)))
1395153323Srodrigc		return -XFS_ERROR(EFAULT);
1396153323Srodrigc	return 0;
1397153323Srodrigc}
1398153323Srodrigc
1399153323SrodrigcSTATIC int
1400153323Srodrigcxfs_ioc_getbmapx(
1401153323Srodrigc	bhv_desc_t		*bdp,
1402159451Srodrigc	void			__user *arg)
1403153323Srodrigc{
1404153323Srodrigc	struct getbmapx		bmx;
1405153323Srodrigc	struct getbmap		bm;
1406153323Srodrigc	int			iflags;
1407153323Srodrigc	int			error;
1408153323Srodrigc
1409159451Srodrigc	printf("%s:%d\n",__FILE__,__LINE__);
1410159451Srodrigc	if (copy_from_user(&bmx, arg, sizeof(bmx)))
1411159451Srodrigc		return XFS_ERROR(EFAULT);
1412153323Srodrigc
1413159451Srodrigc	printf("%s:%d\n",__FILE__,__LINE__);
1414153323Srodrigc	if (bmx.bmv_count < 2)
1415159451Srodrigc		return XFS_ERROR(EINVAL);
1416153323Srodrigc
1417153323Srodrigc	/*
1418153323Srodrigc	 * Map input getbmapx structure to a getbmap
1419153323Srodrigc	 * structure for xfs_getbmap.
1420153323Srodrigc	 */
1421153323Srodrigc	GETBMAP_CONVERT(bmx, bm);
1422153323Srodrigc
1423153323Srodrigc	iflags = bmx.bmv_iflags;
1424153323Srodrigc
1425153323Srodrigc	if (iflags & (~BMV_IF_VALID))
1426159451Srodrigc		return XFS_ERROR(EINVAL);
1427153323Srodrigc
1428153323Srodrigc	iflags |= BMV_IF_EXTENDED;
1429153323Srodrigc
1430159451Srodrigc	printf("%s:%d arg+1 %p arg %p\n",__FILE__,__LINE__,(struct getbmapx __user *)arg+1,arg);
1431159451Srodrigc	error = xfs_getbmap(bdp, &bm, (struct getbmapx __user *)arg+1, iflags);
1432153323Srodrigc	if (error)
1433159451Srodrigc		return error;
1434153323Srodrigc
1435159451Srodrigc	printf("%s:%d\n",__FILE__,__LINE__);
1436153323Srodrigc	GETBMAP_CONVERT(bm, bmx);
1437153323Srodrigc
1438159451Srodrigc	printf("%s:%d\n",__FILE__,__LINE__);
1439159451Srodrigc	if (copy_to_user(arg, &bmx, sizeof(bmx)))
1440159451Srodrigc		return XFS_ERROR(EFAULT);
1441153323Srodrigc
1442159451Srodrigc	printf("%s:%d\n",__FILE__,__LINE__);
1443153323Srodrigc	return 0;
1444153323Srodrigc}
1445153323Srodrigc
1446159451Srodrigc#else
1447153323Srodrigc
1448153323Srodrigcint
1449153323Srodrigcxfs_ioctl(
1450153323Srodrigc	bhv_desc_t		*bdp,
1451153323Srodrigc	struct inode		*inode,
1452153323Srodrigc	struct file		*filp,
1453153323Srodrigc	int			ioflags,
1454194944Srdivacky	u_long			cmd,
1455153323Srodrigc	unsigned long		arg)
1456153323Srodrigc{
1457153323Srodrigc	return EINVAL;
1458153323Srodrigc}
1459159451Srodrigc
1460159451Srodrigc#endif
1461