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