| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-11-02 14:58:39 +11:00
										 |  |  |  * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 
					
						
							|  |  |  |  * All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-11-02 14:58:39 +11:00
										 |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License as | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-11-02 14:58:39 +11:00
										 |  |  |  * This program is distributed in the hope that it would be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-11-02 14:58:39 +11:00
										 |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | #include "xfs.h"
 | 
					
						
							|  |  |  | #include "xfs_fs.h"
 | 
					
						
							|  |  |  | #include "xfs_log.h"
 | 
					
						
							|  |  |  | #include "xfs_trans.h"
 | 
					
						
							|  |  |  | #include "xfs_sb.h"
 | 
					
						
							| 
									
										
										
										
											2005-11-02 14:38:42 +11:00
										 |  |  | #include "xfs_ag.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include "xfs_alloc.h"
 | 
					
						
							|  |  |  | #include "xfs_mount.h"
 | 
					
						
							|  |  |  | #include "xfs_bmap_btree.h"
 | 
					
						
							|  |  |  | #include "xfs_dinode.h"
 | 
					
						
							|  |  |  | #include "xfs_inode.h"
 | 
					
						
							| 
									
										
										
										
											2009-03-05 15:20:25 +01:00
										 |  |  | #include "xfs_ioctl.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include "xfs_rtalloc.h"
 | 
					
						
							|  |  |  | #include "xfs_itable.h"
 | 
					
						
							| 
									
										
										
										
											2005-11-02 14:38:42 +11:00
										 |  |  | #include "xfs_error.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include "xfs_attr.h"
 | 
					
						
							| 
									
										
										
										
											2005-11-02 14:38:42 +11:00
										 |  |  | #include "xfs_bmap.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include "xfs_buf_item.h"
 | 
					
						
							|  |  |  | #include "xfs_utils.h"
 | 
					
						
							|  |  |  | #include "xfs_dfrag.h"
 | 
					
						
							|  |  |  | #include "xfs_fsops.h"
 | 
					
						
							| 
									
										
										
										
											2007-08-28 16:12:30 +10:00
										 |  |  | #include "xfs_vnodeops.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 13:02:04 +00:00
										 |  |  | #include "xfs_discard.h"
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | #include "xfs_quota.h"
 | 
					
						
							|  |  |  | #include "xfs_inode_item.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | #include "xfs_export.h"
 | 
					
						
							| 
									
										
										
										
											2009-12-14 23:14:59 +00:00
										 |  |  | #include "xfs_trace.h"
 | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | #include "xfs_icache.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-11 12:17:46 -08:00
										 |  |  | #include <linux/capability.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/dcache.h>
 | 
					
						
							|  |  |  | #include <linux/mount.h>
 | 
					
						
							|  |  |  | #include <linux/namei.h>
 | 
					
						
							|  |  |  | #include <linux/pagemap.h>
 | 
					
						
							| 
									
										
											  
											
												include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
  http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.
2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).
   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
											
										 
											2010-03-24 17:04:11 +09:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | #include <linux/exportfs.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to | 
					
						
							|  |  |  |  * a file or fs handle. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * XFS_IOC_PATH_TO_FSHANDLE | 
					
						
							|  |  |  |  *    returns fs handle for a mount point or path within that mount point | 
					
						
							|  |  |  |  * XFS_IOC_FD_TO_HANDLE | 
					
						
							|  |  |  |  *    returns full handle for a FD opened in user space | 
					
						
							|  |  |  |  * XFS_IOC_PATH_TO_HANDLE | 
					
						
							|  |  |  |  *    returns full handle for a path | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:08 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_find_handle( | 
					
						
							|  |  |  | 	unsigned int		cmd, | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	xfs_fsop_handlereq_t	*hreq) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int			hsize; | 
					
						
							|  |  |  | 	xfs_handle_t		handle; | 
					
						
							|  |  |  | 	struct inode		*inode; | 
					
						
							| 
									
										
										
										
											2012-10-25 17:22:30 +11:00
										 |  |  | 	struct fd		f = {0}; | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	struct path		path; | 
					
						
							| 
									
										
										
										
											2012-08-28 12:52:22 -04:00
										 |  |  | 	int			error; | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	struct xfs_inode	*ip; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	if (cmd == XFS_IOC_FD_TO_HANDLE) { | 
					
						
							| 
									
										
										
										
											2012-08-28 12:52:22 -04:00
										 |  |  | 		f = fdget(hreq->fd); | 
					
						
							|  |  |  | 		if (!f.file) | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 			return -EBADF; | 
					
						
							| 
									
										
										
										
											2013-01-23 17:07:38 -05:00
										 |  |  | 		inode = file_inode(f.file); | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		error = user_lpath((const char __user *)hreq->path, &path); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							|  |  |  | 		inode = path.dentry->d_inode; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	ip = XFS_I(inode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * We can only generate handles for inodes residing on a XFS filesystem, | 
					
						
							|  |  |  | 	 * and only for regular files, directories or symbolic links. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	error = -EINVAL; | 
					
						
							|  |  |  | 	if (inode->i_sb->s_magic != XFS_SB_MAGIC) | 
					
						
							|  |  |  | 		goto out_put; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = -EBADF; | 
					
						
							|  |  |  | 	if (!S_ISREG(inode->i_mode) && | 
					
						
							|  |  |  | 	    !S_ISDIR(inode->i_mode) && | 
					
						
							|  |  |  | 	    !S_ISLNK(inode->i_mode)) | 
					
						
							|  |  |  | 		goto out_put; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cmd == XFS_IOC_PATH_TO_FSHANDLE) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * This handle only contains an fsid, zero the rest. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		memset(&handle.ha_fid, 0, sizeof(handle.ha_fid)); | 
					
						
							|  |  |  | 		hsize = sizeof(xfs_fsid_t); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		int		lock_mode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		lock_mode = xfs_ilock_map_shared(ip); | 
					
						
							| 
									
										
										
										
											2007-09-14 15:22:37 +10:00
										 |  |  | 		handle.ha_fid.fid_len = sizeof(xfs_fid_t) - | 
					
						
							|  |  |  | 					sizeof(handle.ha_fid.fid_len); | 
					
						
							|  |  |  | 		handle.ha_fid.fid_pad = 0; | 
					
						
							|  |  |  | 		handle.ha_fid.fid_gen = ip->i_d.di_gen; | 
					
						
							|  |  |  | 		handle.ha_fid.fid_ino = ip->i_ino; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		xfs_iunlock_map_shared(ip, lock_mode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hsize = XFS_HSIZE(handle); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	error = -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	if (copy_to_user(hreq->ohandle, &handle, hsize) || | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	    copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) | 
					
						
							|  |  |  | 		goto out_put; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	error = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out_put: | 
					
						
							|  |  |  | 	if (cmd == XFS_IOC_FD_TO_HANDLE) | 
					
						
							| 
									
										
										
										
											2012-08-28 12:52:22 -04:00
										 |  |  | 		fdput(f); | 
					
						
							| 
									
										
										
										
											2009-02-08 21:51:14 +01:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		path_put(&path); | 
					
						
							|  |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  |  * No need to do permission checks on the various pathname components | 
					
						
							|  |  |  |  * as the handle operations are privileged. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | STATIC int | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | xfs_handle_acceptable( | 
					
						
							|  |  |  | 	void			*context, | 
					
						
							|  |  |  | 	struct dentry		*dentry) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Convert userspace handle data into a dentry. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct dentry * | 
					
						
							|  |  |  | xfs_handle_to_dentry( | 
					
						
							|  |  |  | 	struct file		*parfilp, | 
					
						
							|  |  |  | 	void __user		*uhandle, | 
					
						
							|  |  |  | 	u32			hlen) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	xfs_handle_t		handle; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct xfs_fid64	fid; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Only allow handle opens under a directory. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-01-23 17:07:38 -05:00
										 |  |  | 	if (!S_ISDIR(file_inode(parfilp)->i_mode)) | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return ERR_PTR(-ENOTDIR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (hlen != sizeof(xfs_handle_t)) | 
					
						
							|  |  |  | 		return ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 	if (copy_from_user(&handle, uhandle, hlen)) | 
					
						
							|  |  |  | 		return ERR_PTR(-EFAULT); | 
					
						
							|  |  |  | 	if (handle.ha_fid.fid_len != | 
					
						
							|  |  |  | 	    sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len)) | 
					
						
							|  |  |  | 		return ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&fid, 0, sizeof(struct fid)); | 
					
						
							|  |  |  | 	fid.ino = handle.ha_fid.fid_ino; | 
					
						
							|  |  |  | 	fid.gen = handle.ha_fid.fid_gen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3, | 
					
						
							|  |  |  | 			FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, | 
					
						
							|  |  |  | 			xfs_handle_acceptable, NULL); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | STATIC struct dentry * | 
					
						
							|  |  |  | xfs_handlereq_to_dentry( | 
					
						
							|  |  |  | 	struct file		*parfilp, | 
					
						
							|  |  |  | 	xfs_fsop_handlereq_t	*hreq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:08 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_open_by_handle( | 
					
						
							|  |  |  | 	struct file		*parfilp, | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	xfs_fsop_handlereq_t	*hreq) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-11-14 10:39:22 +11:00
										 |  |  | 	const struct cred	*cred = current_cred(); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			error; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	int			fd; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			permflag; | 
					
						
							|  |  |  | 	struct file		*filp; | 
					
						
							|  |  |  | 	struct inode		*inode; | 
					
						
							|  |  |  | 	struct dentry		*dentry; | 
					
						
							| 
									
										
										
										
											2012-03-22 05:15:06 +00:00
										 |  |  | 	fmode_t			fmode; | 
					
						
							| 
									
										
										
										
											2012-06-26 21:58:53 +04:00
										 |  |  | 	struct path		path; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	dentry = xfs_handlereq_to_dentry(parfilp, hreq); | 
					
						
							|  |  |  | 	if (IS_ERR(dentry)) | 
					
						
							|  |  |  | 		return PTR_ERR(dentry); | 
					
						
							|  |  |  | 	inode = dentry->d_inode; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Restrict xfs_open_by_handle to directories & regular files. */ | 
					
						
							|  |  |  | 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		error = -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if BITS_PER_LONG != 32
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	hreq->oflags |= O_LARGEFILE; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	permflag = hreq->oflags; | 
					
						
							| 
									
										
										
										
											2012-03-22 05:15:06 +00:00
										 |  |  | 	fmode = OPEN_FMODE(permflag); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && | 
					
						
							| 
									
										
										
										
											2012-03-22 05:15:06 +00:00
										 |  |  | 	    (fmode & FMODE_WRITE) && IS_APPEND(inode)) { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		error = -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-22 05:15:06 +00:00
										 |  |  | 	if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		error = -XFS_ERROR(EACCES); | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Can't write directories. */ | 
					
						
							| 
									
										
										
										
											2012-03-22 05:15:06 +00:00
										 |  |  | 	if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		error = -XFS_ERROR(EISDIR); | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	fd = get_unused_fd(); | 
					
						
							|  |  |  | 	if (fd < 0) { | 
					
						
							|  |  |  | 		error = fd; | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-26 21:58:53 +04:00
										 |  |  | 	path.mnt = parfilp->f_path.mnt; | 
					
						
							|  |  |  | 	path.dentry = dentry; | 
					
						
							|  |  |  | 	filp = dentry_open(&path, hreq->oflags, cred); | 
					
						
							|  |  |  | 	dput(dentry); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (IS_ERR(filp)) { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		put_unused_fd(fd); | 
					
						
							|  |  |  | 		return PTR_ERR(filp); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-25 20:54:24 -04:00
										 |  |  | 	if (S_ISREG(inode->i_mode)) { | 
					
						
							| 
									
										
										
										
											2006-11-11 18:04:47 +11:00
										 |  |  | 		filp->f_flags |= O_NOATIME; | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | 		filp->f_mode |= FMODE_NOCMTIME; | 
					
						
							| 
									
										
										
										
											2006-11-11 18:04:47 +11:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	fd_install(fd, filp); | 
					
						
							|  |  |  | 	return fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out_dput: | 
					
						
							|  |  |  | 	dput(dentry); | 
					
						
							|  |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's | 
					
						
							|  |  |  |  * unused first argument. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | do_readlink( | 
					
						
							|  |  |  | 	char __user		*buffer, | 
					
						
							|  |  |  | 	int			buflen, | 
					
						
							|  |  |  | 	const char		*link) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |         int len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	len = PTR_ERR(link); | 
					
						
							|  |  |  | 	if (IS_ERR(link)) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	len = strlen(link); | 
					
						
							|  |  |  | 	if (len > (unsigned) buflen) | 
					
						
							|  |  |  | 		len = buflen; | 
					
						
							|  |  |  | 	if (copy_to_user(buffer, link, len)) | 
					
						
							|  |  |  | 		len = -EFAULT; | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	return len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:08 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_readlink_by_handle( | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct file		*parfilp, | 
					
						
							|  |  |  | 	xfs_fsop_handlereq_t	*hreq) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct dentry		*dentry; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	__u32			olen; | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 	void			*link; | 
					
						
							|  |  |  | 	int			error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	dentry = xfs_handlereq_to_dentry(parfilp, hreq); | 
					
						
							|  |  |  | 	if (IS_ERR(dentry)) | 
					
						
							|  |  |  | 		return PTR_ERR(dentry); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Restrict this handle operation to symlinks only. */ | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	if (!S_ISLNK(dentry->d_inode->i_mode)) { | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 		error = -XFS_ERROR(EINVAL); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) { | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 		error = -XFS_ERROR(EFAULT); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 	link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	if (!link) { | 
					
						
							|  |  |  | 		error = -XFS_ERROR(ENOMEM); | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	error = -xfs_readlink(XFS_I(dentry->d_inode), link); | 
					
						
							| 
									
										
										
										
											2006-06-09 17:00:52 +10:00
										 |  |  | 	if (error) | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 		goto out_kfree; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	error = do_readlink(hreq->ohandle, olen, link); | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto out_kfree; | 
					
						
							| 
									
										
										
										
											2006-06-09 17:00:52 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  |  out_kfree: | 
					
						
							|  |  |  | 	kfree(link); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  |  out_dput: | 
					
						
							|  |  |  | 	dput(dentry); | 
					
						
							| 
									
										
										
										
											2007-08-28 13:59:03 +10:00
										 |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_fssetdm_by_handle( | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct file		*parfilp, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int			error; | 
					
						
							|  |  |  | 	struct fsdmidata	fsd; | 
					
						
							|  |  |  | 	xfs_fsop_setdm_handlereq_t dmhreq; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct dentry		*dentry; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_MKNOD)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	error = mnt_want_write_file(parfilp); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	if (IS_ERR(dentry)) { | 
					
						
							|  |  |  | 		mnt_drop_write_file(parfilp); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return PTR_ERR(dentry); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  | 		error = -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  | 		error = -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	error = -xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask, | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  | 				 fsd.fsd_dmstate); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  |  out: | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	mnt_drop_write_file(parfilp); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	dput(dentry); | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_attrlist_by_handle( | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct file		*parfilp, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	int			error = -ENOMEM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	attrlist_cursor_kern_t	*cursor; | 
					
						
							|  |  |  | 	xfs_fsop_attrlist_handlereq_t al_hreq; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct dentry		*dentry; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	char			*kbuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 	if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 	if (al_hreq.buflen > XATTR_LIST_MAX) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-27 13:32:19 +10:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Reject flags, only allow namespaces. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq); | 
					
						
							|  |  |  | 	if (IS_ERR(dentry)) | 
					
						
							|  |  |  | 		return PTR_ERR(dentry); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-30 14:26:17 +00:00
										 |  |  | 	kbuf = kzalloc(al_hreq.buflen, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (!kbuf) | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 					al_hreq.flags, cursor); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto out_kfree; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen)) | 
					
						
							|  |  |  | 		error = -EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out_kfree: | 
					
						
							|  |  |  | 	kfree(kbuf); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  |  out_dput: | 
					
						
							|  |  |  | 	dput(dentry); | 
					
						
							|  |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:15 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_attrmulti_attr_get( | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	struct inode		*inode, | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 	unsigned char		*name, | 
					
						
							|  |  |  | 	unsigned char		__user *ubuf, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	__uint32_t		*len, | 
					
						
							|  |  |  | 	__uint32_t		flags) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 	unsigned char		*kbuf; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			error = EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-22 17:34:31 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (*len > XATTR_SIZE_MAX) | 
					
						
							|  |  |  | 		return EINVAL; | 
					
						
							| 
									
										
										
										
											2012-03-07 04:50:21 +00:00
										 |  |  | 	kbuf = kmem_zalloc(*len, KM_SLEEP | KM_MAYFAIL); | 
					
						
							|  |  |  | 	if (!kbuf) { | 
					
						
							|  |  |  | 		kbuf = kmem_zalloc_large(*len); | 
					
						
							|  |  |  | 		if (!kbuf) | 
					
						
							|  |  |  | 			return ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 17:34:31 +10:00
										 |  |  | 	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto out_kfree; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(ubuf, kbuf, *len)) | 
					
						
							|  |  |  | 		error = EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out_kfree: | 
					
						
							| 
									
										
										
										
											2012-03-07 04:50:21 +00:00
										 |  |  | 	if (is_vmalloc_addr(kbuf)) | 
					
						
							|  |  |  | 		kmem_free_large(kbuf); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		kmem_free(kbuf); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:15 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_attrmulti_attr_set( | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	struct inode		*inode, | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 	unsigned char		*name, | 
					
						
							|  |  |  | 	const unsigned char	__user *ubuf, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	__uint32_t		len, | 
					
						
							|  |  |  | 	__uint32_t		flags) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 	unsigned char		*kbuf; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			error = EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return EPERM; | 
					
						
							|  |  |  | 	if (len > XATTR_SIZE_MAX) | 
					
						
							|  |  |  | 		return EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-08 15:08:04 +08:00
										 |  |  | 	kbuf = memdup_user(ubuf, len); | 
					
						
							|  |  |  | 	if (IS_ERR(kbuf)) | 
					
						
							|  |  |  | 		return PTR_ERR(kbuf); | 
					
						
							| 
									
										
										
										
											2008-04-22 17:34:31 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:15 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_attrmulti_attr_remove( | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	struct inode		*inode, | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 	unsigned char		*name, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	__uint32_t		flags) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return EPERM; | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	return xfs_attr_remove(XFS_I(inode), name, flags); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_attrmulti_by_handle( | 
					
						
							| 
									
										
										
										
											2008-02-15 14:37:46 -08:00
										 |  |  | 	struct file		*parfilp, | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	void			__user *arg) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int			error; | 
					
						
							|  |  |  | 	xfs_attr_multiop_t	*ops; | 
					
						
							|  |  |  | 	xfs_fsop_attrmulti_handlereq_t am_hreq; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	struct dentry		*dentry; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	unsigned int		i, size; | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 	unsigned char		*attr_name; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 	if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-23 09:51:22 +11:00
										 |  |  | 	/* overflow check */ | 
					
						
							|  |  |  | 	if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t)) | 
					
						
							|  |  |  | 		return -E2BIG; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq); | 
					
						
							|  |  |  | 	if (IS_ERR(dentry)) | 
					
						
							|  |  |  | 		return PTR_ERR(dentry); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	error = E2BIG; | 
					
						
							| 
									
										
										
										
											2008-06-27 13:32:31 +10:00
										 |  |  | 	size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (!size || size > 16 * PAGE_SIZE) | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-08 15:08:04 +08:00
										 |  |  | 	ops = memdup_user(am_hreq.ops, size); | 
					
						
							|  |  |  | 	if (IS_ERR(ops)) { | 
					
						
							|  |  |  | 		error = PTR_ERR(ops); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2009-04-08 15:08:04 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!attr_name) | 
					
						
							|  |  |  | 		goto out_kfree_ops; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = 0; | 
					
						
							|  |  |  | 	for (i = 0; i < am_hreq.opcount; i++) { | 
					
						
							| 
									
										
										
										
											2010-01-20 10:47:48 +11:00
										 |  |  | 		ops[i].am_error = strncpy_from_user((char *)attr_name, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				ops[i].am_attrname, MAXNAMELEN); | 
					
						
							|  |  |  | 		if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) | 
					
						
							|  |  |  | 			error = -ERANGE; | 
					
						
							|  |  |  | 		if (ops[i].am_error < 0) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (ops[i].am_opcode) { | 
					
						
							|  |  |  | 		case ATTR_OP_GET: | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 			ops[i].am_error = xfs_attrmulti_attr_get( | 
					
						
							|  |  |  | 					dentry->d_inode, attr_name, | 
					
						
							|  |  |  | 					ops[i].am_attrvalue, &ops[i].am_length, | 
					
						
							|  |  |  | 					ops[i].am_flags); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case ATTR_OP_SET: | 
					
						
							| 
									
										
										
										
											2011-11-23 11:57:51 -05:00
										 |  |  | 			ops[i].am_error = mnt_want_write_file(parfilp); | 
					
						
							| 
									
										
										
										
											2008-02-15 14:37:46 -08:00
										 |  |  | 			if (ops[i].am_error) | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 			ops[i].am_error = xfs_attrmulti_attr_set( | 
					
						
							|  |  |  | 					dentry->d_inode, attr_name, | 
					
						
							|  |  |  | 					ops[i].am_attrvalue, ops[i].am_length, | 
					
						
							|  |  |  | 					ops[i].am_flags); | 
					
						
							| 
									
										
										
										
											2011-12-09 08:06:57 -05:00
										 |  |  | 			mnt_drop_write_file(parfilp); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case ATTR_OP_REMOVE: | 
					
						
							| 
									
										
										
										
											2011-11-23 11:57:51 -05:00
										 |  |  | 			ops[i].am_error = mnt_want_write_file(parfilp); | 
					
						
							| 
									
										
										
										
											2008-02-15 14:37:46 -08:00
										 |  |  | 			if (ops[i].am_error) | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 			ops[i].am_error = xfs_attrmulti_attr_remove( | 
					
						
							|  |  |  | 					dentry->d_inode, attr_name, | 
					
						
							|  |  |  | 					ops[i].am_flags); | 
					
						
							| 
									
										
										
										
											2011-12-09 08:06:57 -05:00
										 |  |  | 			mnt_drop_write_file(parfilp); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			ops[i].am_error = EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(am_hreq.ops, ops, size)) | 
					
						
							|  |  |  | 		error = XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(attr_name); | 
					
						
							|  |  |  |  out_kfree_ops: | 
					
						
							|  |  |  | 	kfree(ops); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  |  out_dput: | 
					
						
							|  |  |  | 	dput(dentry); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return -error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:08 -06:00
										 |  |  | int | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | xfs_ioc_space( | 
					
						
							| 
									
										
										
										
											2007-08-28 16:12:30 +10:00
										 |  |  | 	struct xfs_inode	*ip, | 
					
						
							| 
									
										
										
										
											2006-09-28 10:52:04 +10:00
										 |  |  | 	struct inode		*inode, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	struct file		*filp, | 
					
						
							|  |  |  | 	int			ioflags, | 
					
						
							|  |  |  | 	unsigned int		cmd, | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	xfs_flock64_t		*bf) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int			attr_flags = 0; | 
					
						
							|  |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Only allow the sys admin to reserve space unless | 
					
						
							|  |  |  | 	 * unwritten extents are enabled. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) && | 
					
						
							|  |  |  | 	    !capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-28 10:52:04 +10:00
										 |  |  | 	if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-02 16:41:16 +10:00
										 |  |  | 	if (!(filp->f_mode & FMODE_WRITE)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EBADF); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-28 10:52:04 +10:00
										 |  |  | 	if (!S_ISREG(inode->i_mode)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:28 +10:00
										 |  |  | 		attr_flags |= XFS_ATTR_NONBLOCK; | 
					
						
							| 
									
										
										
										
											2011-03-26 09:13:08 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (filp->f_flags & O_DSYNC) | 
					
						
							|  |  |  | 		attr_flags |= XFS_ATTR_SYNC; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (ioflags & IO_INVIS) | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:28 +10:00
										 |  |  | 		attr_flags |= XFS_ATTR_DMI; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return -error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_bulkstat( | 
					
						
							|  |  |  | 	xfs_mount_t		*mp, | 
					
						
							|  |  |  | 	unsigned int		cmd, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	xfs_fsop_bulkreq_t	bulkreq; | 
					
						
							|  |  |  | 	int			count;	/* # of records returned */ | 
					
						
							|  |  |  | 	xfs_ino_t		inlast;	/* last inode number */ | 
					
						
							|  |  |  | 	int			done; | 
					
						
							|  |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* done = 1 if there are more stats to get and if bulkstat */ | 
					
						
							|  |  |  | 	/* should be called again (unused here, but used in dmapi) */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 		return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (XFS_FORCED_SHUTDOWN(mp)) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EIO); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((count = bulkreq.icount) <= 0) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-23 16:30:32 +11:00
										 |  |  | 	if (bulkreq.ubuffer == NULL) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (cmd == XFS_IOC_FSINUMBERS) | 
					
						
							|  |  |  | 		error = xfs_inumbers(mp, &inlast, &count, | 
					
						
							| 
									
										
										
										
											2007-07-11 11:10:19 +10:00
										 |  |  | 					bulkreq.ubuffer, xfs_inumbers_fmt); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) | 
					
						
							|  |  |  | 		error = xfs_bulkstat_single(mp, &inlast, | 
					
						
							|  |  |  | 						bulkreq.ubuffer, &done); | 
					
						
							| 
									
										
										
										
											2007-11-23 16:30:32 +11:00
										 |  |  | 	else	/* XFS_IOC_FSBULKSTAT */ | 
					
						
							| 
									
										
										
										
											2010-06-23 18:11:11 +10:00
										 |  |  | 		error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, | 
					
						
							|  |  |  | 				     sizeof(xfs_bstat_t), bulkreq.ubuffer, | 
					
						
							|  |  |  | 				     &done); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bulkreq.ocount != NULL) { | 
					
						
							|  |  |  | 		if (copy_to_user(bulkreq.lastip, &inlast, | 
					
						
							|  |  |  | 						sizeof(xfs_ino_t))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_fsgeometry_v1( | 
					
						
							|  |  |  | 	xfs_mount_t		*mp, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-01 17:50:00 +00:00
										 |  |  | 	xfs_fsop_geom_t         fsgeo; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-01 17:50:00 +00:00
										 |  |  | 	error = xfs_fs_geometry(mp, &fsgeo, 3); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-01 17:50:00 +00:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Caller should have passed an argument of type | 
					
						
							|  |  |  | 	 * xfs_fsop_geom_v1_t.  This is a proper subset of the | 
					
						
							|  |  |  | 	 * xfs_fsop_geom_t that xfs_fs_geometry() fills in. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &fsgeo, sizeof(xfs_fsop_geom_v1_t))) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_fsgeometry( | 
					
						
							|  |  |  | 	xfs_mount_t		*mp, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	xfs_fsop_geom_t		fsgeo; | 
					
						
							|  |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = xfs_fs_geometry(mp, &fsgeo, 4); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Linux extended inode flags interface. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC unsigned int | 
					
						
							|  |  |  | xfs_merge_ioc_xflags( | 
					
						
							|  |  |  | 	unsigned int	flags, | 
					
						
							|  |  |  | 	unsigned int	start) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int	xflags = start; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 	if (flags & FS_IMMUTABLE_FL) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		xflags |= XFS_XFLAG_IMMUTABLE; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		xflags &= ~XFS_XFLAG_IMMUTABLE; | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 	if (flags & FS_APPEND_FL) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		xflags |= XFS_XFLAG_APPEND; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		xflags &= ~XFS_XFLAG_APPEND; | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 	if (flags & FS_SYNC_FL) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		xflags |= XFS_XFLAG_SYNC; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		xflags &= ~XFS_XFLAG_SYNC; | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 	if (flags & FS_NOATIME_FL) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		xflags |= XFS_XFLAG_NOATIME; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		xflags &= ~XFS_XFLAG_NOATIME; | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 	if (flags & FS_NODUMP_FL) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		xflags |= XFS_XFLAG_NODUMP; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		xflags &= ~XFS_XFLAG_NODUMP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return xflags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC unsigned int | 
					
						
							|  |  |  | xfs_di2lxflags( | 
					
						
							|  |  |  | 	__uint16_t	di_flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int	flags = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (di_flags & XFS_DIFLAG_IMMUTABLE) | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 		flags |= FS_IMMUTABLE_FL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (di_flags & XFS_DIFLAG_APPEND) | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 		flags |= FS_APPEND_FL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (di_flags & XFS_DIFLAG_SYNC) | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 		flags |= FS_SYNC_FL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (di_flags & XFS_DIFLAG_NOATIME) | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 		flags |= FS_NOATIME_FL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (di_flags & XFS_DIFLAG_NODUMP) | 
					
						
							| 
									
										
										
										
											2007-02-10 18:37:10 +11:00
										 |  |  | 		flags |= FS_NODUMP_FL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return flags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-11 17:47:00 +10:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_fsgetxattr( | 
					
						
							|  |  |  | 	xfs_inode_t		*ip, | 
					
						
							|  |  |  | 	int			attr, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fsxattr		fa; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-06 18:24:57 -04:00
										 |  |  | 	memset(&fa, 0, sizeof(struct fsxattr)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-11 17:47:00 +10:00
										 |  |  | 	xfs_ilock(ip, XFS_ILOCK_SHARED); | 
					
						
							|  |  |  | 	fa.fsx_xflags = xfs_ip2xflags(ip); | 
					
						
							|  |  |  | 	fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 	fa.fsx_projid = xfs_get_projid(ip); | 
					
						
							| 
									
										
										
										
											2007-10-11 17:47:00 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (attr) { | 
					
						
							|  |  |  | 		if (ip->i_afp) { | 
					
						
							|  |  |  | 			if (ip->i_afp->if_flags & XFS_IFEXTENTS) | 
					
						
							|  |  |  | 				fa.fsx_nextents = ip->i_afp->if_bytes / | 
					
						
							|  |  |  | 							sizeof(xfs_bmbt_rec_t); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				fa.fsx_nextents = ip->i_d.di_anextents; | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			fa.fsx_nextents = 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (ip->i_df.if_flags & XFS_IFEXTENTS) | 
					
						
							|  |  |  | 			fa.fsx_nextents = ip->i_df.if_bytes / | 
					
						
							|  |  |  | 						sizeof(xfs_bmbt_rec_t); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			fa.fsx_nextents = ip->i_d.di_nextents; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	xfs_iunlock(ip, XFS_ILOCK_SHARED); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &fa, sizeof(fa))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | STATIC void | 
					
						
							|  |  |  | xfs_set_diflags( | 
					
						
							|  |  |  | 	struct xfs_inode	*ip, | 
					
						
							|  |  |  | 	unsigned int		xflags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int		di_flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* can't set PREALLOC this way, just preserve it */ | 
					
						
							|  |  |  | 	di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_IMMUTABLE) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_IMMUTABLE; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_APPEND) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_APPEND; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_SYNC) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_SYNC; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_NOATIME) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_NOATIME; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_NODUMP) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_NODUMP; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_PROJINHERIT) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_PROJINHERIT; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_NODEFRAG) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_NODEFRAG; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_FILESTREAM) | 
					
						
							|  |  |  | 		di_flags |= XFS_DIFLAG_FILESTREAM; | 
					
						
							| 
									
										
										
										
											2011-07-26 02:31:30 -04:00
										 |  |  | 	if (S_ISDIR(ip->i_d.di_mode)) { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		if (xflags & XFS_XFLAG_RTINHERIT) | 
					
						
							|  |  |  | 			di_flags |= XFS_DIFLAG_RTINHERIT; | 
					
						
							|  |  |  | 		if (xflags & XFS_XFLAG_NOSYMLINKS) | 
					
						
							|  |  |  | 			di_flags |= XFS_DIFLAG_NOSYMLINKS; | 
					
						
							|  |  |  | 		if (xflags & XFS_XFLAG_EXTSZINHERIT) | 
					
						
							|  |  |  | 			di_flags |= XFS_DIFLAG_EXTSZINHERIT; | 
					
						
							| 
									
										
										
										
											2011-07-26 02:31:30 -04:00
										 |  |  | 	} else if (S_ISREG(ip->i_d.di_mode)) { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		if (xflags & XFS_XFLAG_REALTIME) | 
					
						
							|  |  |  | 			di_flags |= XFS_DIFLAG_REALTIME; | 
					
						
							|  |  |  | 		if (xflags & XFS_XFLAG_EXTSIZE) | 
					
						
							|  |  |  | 			di_flags |= XFS_DIFLAG_EXTSIZE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ip->i_d.di_flags = di_flags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-21 16:16:15 +10:00
										 |  |  | STATIC void | 
					
						
							|  |  |  | xfs_diflags_to_linux( | 
					
						
							|  |  |  | 	struct xfs_inode	*ip) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-08-13 16:00:45 +10:00
										 |  |  | 	struct inode		*inode = VFS_I(ip); | 
					
						
							| 
									
										
										
										
											2008-07-21 16:16:15 +10:00
										 |  |  | 	unsigned int		xflags = xfs_ip2xflags(ip); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_IMMUTABLE) | 
					
						
							|  |  |  | 		inode->i_flags |= S_IMMUTABLE; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		inode->i_flags &= ~S_IMMUTABLE; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_APPEND) | 
					
						
							|  |  |  | 		inode->i_flags |= S_APPEND; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		inode->i_flags &= ~S_APPEND; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_SYNC) | 
					
						
							|  |  |  | 		inode->i_flags |= S_SYNC; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		inode->i_flags &= ~S_SYNC; | 
					
						
							|  |  |  | 	if (xflags & XFS_XFLAG_NOATIME) | 
					
						
							|  |  |  | 		inode->i_flags |= S_NOATIME; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		inode->i_flags &= ~S_NOATIME; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define FSX_PROJID	1
 | 
					
						
							|  |  |  | #define FSX_EXTSIZE	2
 | 
					
						
							|  |  |  | #define FSX_XFLAGS	4
 | 
					
						
							|  |  |  | #define FSX_NONBLOCK	8
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioctl_setattr( | 
					
						
							|  |  |  | 	xfs_inode_t		*ip, | 
					
						
							|  |  |  | 	struct fsxattr		*fa, | 
					
						
							|  |  |  | 	int			mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct xfs_mount	*mp = ip->i_mount; | 
					
						
							|  |  |  | 	struct xfs_trans	*tp; | 
					
						
							|  |  |  | 	unsigned int		lock_flags = 0; | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 	struct xfs_dquot	*udqp = NULL; | 
					
						
							|  |  |  | 	struct xfs_dquot	*gdqp = NULL; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	struct xfs_dquot	*olddquot = NULL; | 
					
						
							|  |  |  | 	int			code; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-24 11:57:09 +10:00
										 |  |  | 	trace_xfs_ioctl_setattr(ip); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (mp->m_flags & XFS_MOUNT_RDONLY) | 
					
						
							|  |  |  | 		return XFS_ERROR(EROFS); | 
					
						
							|  |  |  | 	if (XFS_FORCED_SHUTDOWN(mp)) | 
					
						
							|  |  |  | 		return XFS_ERROR(EIO); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-26 10:19:43 +00:00
										 |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 	 * Disallow 32bit project ids when projid32bit feature is not enabled. | 
					
						
							| 
									
										
										
										
											2010-08-26 10:19:43 +00:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 	if ((mask & FSX_PROJID) && (fa->fsx_projid > (__uint16_t)-1) && | 
					
						
							|  |  |  | 			!xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb)) | 
					
						
							| 
									
										
										
										
											2010-08-26 10:19:43 +00:00
										 |  |  | 		return XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If disk quotas is on, we make sure that the dquots do exist on disk, | 
					
						
							|  |  |  | 	 * before we start any other transactions. Trying to do this later | 
					
						
							|  |  |  | 	 * is messy. We don't care to take a readlock to look at the ids | 
					
						
							|  |  |  | 	 * in inode here, because we can't hold it across the trans_reserve. | 
					
						
							|  |  |  | 	 * If the IDs do change before we take the ilock, we're covered | 
					
						
							|  |  |  | 	 * because the i_*dquot fields will get updated anyway. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) { | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 		code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid, | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 					 ip->i_d.di_gid, fa->fsx_projid, | 
					
						
							|  |  |  | 					 XFS_QMOPT_PQUOTA, &udqp, &gdqp); | 
					
						
							|  |  |  | 		if (code) | 
					
						
							|  |  |  | 			return code; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * For the other attributes, we acquire the inode lock and | 
					
						
							|  |  |  | 	 * first do an error checking pass. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | 
					
						
							|  |  |  | 	code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); | 
					
						
							|  |  |  | 	if (code) | 
					
						
							|  |  |  | 		goto error_return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lock_flags = XFS_ILOCK_EXCL; | 
					
						
							|  |  |  | 	xfs_ilock(ip, lock_flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * CAP_FOWNER overrides the following restrictions: | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * The user ID of the calling process must be equal | 
					
						
							|  |  |  | 	 * to the file owner ID, except in cases where the | 
					
						
							|  |  |  | 	 * CAP_FSETID capability is applicable. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2008-10-31 15:50:04 +11:00
										 |  |  | 	if (current_fsuid() != ip->i_d.di_uid && !capable(CAP_FOWNER)) { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		code = XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 		goto error_return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Do a quota reservation only if projid is actually going to change. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mask & FSX_PROJID) { | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 		if (XFS_IS_QUOTA_RUNNING(mp) && | 
					
						
							|  |  |  | 		    XFS_IS_PQUOTA_ON(mp) && | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 		    xfs_get_projid(ip) != fa->fsx_projid) { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			ASSERT(tp); | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 						capable(CAP_FOWNER) ? | 
					
						
							|  |  |  | 						XFS_QMOPT_FORCE_RES : 0); | 
					
						
							|  |  |  | 			if (code)	/* out of quota */ | 
					
						
							|  |  |  | 				goto error_return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mask & FSX_EXTSIZE) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Can't change extent size if any extents are allocated. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (ip->i_d.di_nextents && | 
					
						
							|  |  |  | 		    ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != | 
					
						
							|  |  |  | 		     fa->fsx_extsize)) { | 
					
						
							|  |  |  | 			code = XFS_ERROR(EINVAL);	/* EFBIG? */ | 
					
						
							|  |  |  | 			goto error_return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Extent size must be a multiple of the appropriate block | 
					
						
							| 
									
										
										
										
											2011-01-27 12:18:18 +11:00
										 |  |  | 		 * size, if set at all. It must also be smaller than the | 
					
						
							|  |  |  | 		 * maximum extent size supported by the filesystem. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * Also, for non-realtime files, limit the extent size hint to | 
					
						
							|  |  |  | 		 * half the size of the AGs in the filesystem so alignment | 
					
						
							|  |  |  | 		 * doesn't result in extents larger than an AG. | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		 */ | 
					
						
							|  |  |  | 		if (fa->fsx_extsize != 0) { | 
					
						
							| 
									
										
										
										
											2011-01-27 12:18:18 +11:00
										 |  |  | 			xfs_extlen_t    size; | 
					
						
							|  |  |  | 			xfs_fsblock_t   extsize_fsb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize); | 
					
						
							|  |  |  | 			if (extsize_fsb > MAXEXTLEN) { | 
					
						
							|  |  |  | 				code = XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 				goto error_return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (XFS_IS_REALTIME_INODE(ip) || | 
					
						
							|  |  |  | 			    ((mask & FSX_XFLAGS) && | 
					
						
							|  |  |  | 			    (fa->fsx_xflags & XFS_XFLAG_REALTIME))) { | 
					
						
							|  |  |  | 				size = mp->m_sb.sb_rextsize << | 
					
						
							|  |  |  | 				       mp->m_sb.sb_blocklog; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				size = mp->m_sb.sb_blocksize; | 
					
						
							| 
									
										
										
										
											2011-01-27 12:18:18 +11:00
										 |  |  | 				if (extsize_fsb > mp->m_sb.sb_agblocks / 2) { | 
					
						
							|  |  |  | 					code = XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 					goto error_return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (fa->fsx_extsize % size) { | 
					
						
							|  |  |  | 				code = XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 				goto error_return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mask & FSX_XFLAGS) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Can't change realtime flag if any extents are allocated. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if ((ip->i_d.di_nextents || ip->i_delayed_blks) && | 
					
						
							|  |  |  | 		    (XFS_IS_REALTIME_INODE(ip)) != | 
					
						
							|  |  |  | 		    (fa->fsx_xflags & XFS_XFLAG_REALTIME)) { | 
					
						
							|  |  |  | 			code = XFS_ERROR(EINVAL);	/* EFBIG? */ | 
					
						
							|  |  |  | 			goto error_return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * If realtime flag is set then must have realtime data. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) { | 
					
						
							|  |  |  | 			if ((mp->m_sb.sb_rblocks == 0) || | 
					
						
							|  |  |  | 			    (mp->m_sb.sb_rextsize == 0) || | 
					
						
							|  |  |  | 			    (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { | 
					
						
							|  |  |  | 				code = XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 				goto error_return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Can't modify an immutable/append-only file unless | 
					
						
							|  |  |  | 		 * we have appropriate permission. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if ((ip->i_d.di_flags & | 
					
						
							|  |  |  | 				(XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) || | 
					
						
							|  |  |  | 		     (fa->fsx_xflags & | 
					
						
							|  |  |  | 				(XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) && | 
					
						
							|  |  |  | 		    !capable(CAP_LINUX_IMMUTABLE)) { | 
					
						
							|  |  |  | 			code = XFS_ERROR(EPERM); | 
					
						
							|  |  |  | 			goto error_return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-19 15:00:54 +00:00
										 |  |  | 	xfs_trans_ijoin(tp, ip, 0); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Change file ownership.  Must be the owner or privileged. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mask & FSX_PROJID) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * CAP_FSETID overrides the following restrictions: | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * The set-user-ID and set-group-ID bits of a file will be | 
					
						
							|  |  |  | 		 * cleared upon successful return from chown() | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) && | 
					
						
							|  |  |  | 		    !capable(CAP_FSETID)) | 
					
						
							|  |  |  | 			ip->i_d.di_mode &= ~(S_ISUID|S_ISGID); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Change the ownerships and register quota modifications | 
					
						
							|  |  |  | 		 * in the transaction. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 		if (xfs_get_projid(ip) != fa->fsx_projid) { | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 			if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) { | 
					
						
							|  |  |  | 				olddquot = xfs_qm_vop_chown(tp, ip, | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 							&ip->i_gdquot, gdqp); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 			xfs_set_projid(ip, fa->fsx_projid); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * We may have to rev the inode as well as | 
					
						
							|  |  |  | 			 * the superblock version number since projids didn't | 
					
						
							|  |  |  | 			 * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:39 +11:00
										 |  |  | 			if (ip->i_d.di_version == 1) | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 				xfs_bump_ino_vers2(tp, ip); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mask & FSX_EXTSIZE) | 
					
						
							|  |  |  | 		ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; | 
					
						
							| 
									
										
										
										
											2008-07-21 16:16:15 +10:00
										 |  |  | 	if (mask & FSX_XFLAGS) { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		xfs_set_diflags(ip, fa->fsx_xflags); | 
					
						
							| 
									
										
										
										
											2008-07-21 16:16:15 +10:00
										 |  |  | 		xfs_diflags_to_linux(ip); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-28 12:27:25 +10:00
										 |  |  | 	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	XFS_STATS_INC(xs_ig_attrchg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If this is a synchronous mount, make sure that the | 
					
						
							|  |  |  | 	 * transaction goes to disk before returning to the user. | 
					
						
							|  |  |  | 	 * This is slightly sub-optimal in that truncates require | 
					
						
							|  |  |  | 	 * two sync transactions instead of one for wsync filesystems. | 
					
						
							|  |  |  | 	 * One for the truncate and one for the timestamps since we | 
					
						
							|  |  |  | 	 * don't want to change the timestamps unless we're sure the | 
					
						
							|  |  |  | 	 * truncate worked.  Truncates are less than 1% of the laddis | 
					
						
							|  |  |  | 	 * mix so this probably isn't worth the trouble to optimize. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mp->m_flags & XFS_MOUNT_WSYNC) | 
					
						
							|  |  |  | 		xfs_trans_set_sync(tp); | 
					
						
							|  |  |  | 	code = xfs_trans_commit(tp, 0); | 
					
						
							|  |  |  | 	xfs_iunlock(ip, lock_flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Release any dquot(s) the inode had kept before chown. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 	xfs_qm_dqrele(olddquot); | 
					
						
							|  |  |  | 	xfs_qm_dqrele(udqp); | 
					
						
							|  |  |  | 	xfs_qm_dqrele(gdqp); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-23 18:11:15 +10:00
										 |  |  | 	return code; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |  error_return: | 
					
						
							| 
									
										
										
										
											2009-06-08 15:33:32 +02:00
										 |  |  | 	xfs_qm_dqrele(udqp); | 
					
						
							|  |  |  | 	xfs_qm_dqrele(gdqp); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	xfs_trans_cancel(tp, 0); | 
					
						
							|  |  |  | 	if (lock_flags) | 
					
						
							|  |  |  | 		xfs_iunlock(ip, lock_flags); | 
					
						
							|  |  |  | 	return code; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | STATIC int | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | xfs_ioc_fssetxattr( | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	xfs_inode_t		*ip, | 
					
						
							|  |  |  | 	struct file		*filp, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fsxattr		fa; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	unsigned int		mask; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	int error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&fa, arg, sizeof(fa))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		mask |= FSX_NONBLOCK; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 	error = xfs_ioctl_setattr(ip, &fa, mask); | 
					
						
							|  |  |  | 	mnt_drop_write_file(filp); | 
					
						
							|  |  |  | 	return -error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_getxflags( | 
					
						
							|  |  |  | 	xfs_inode_t		*ip, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int		flags; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	flags = xfs_di2lxflags(ip->i_d.di_flags); | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &flags, sizeof(flags))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_setxflags( | 
					
						
							|  |  |  | 	xfs_inode_t		*ip, | 
					
						
							|  |  |  | 	struct file		*filp, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	struct fsxattr		fa; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	unsigned int		flags; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	unsigned int		mask; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	int error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	if (copy_from_user(&flags, arg, sizeof(flags))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ | 
					
						
							|  |  |  | 		      FS_NOATIME_FL | FS_NODUMP_FL | \ | 
					
						
							|  |  |  | 		      FS_SYNC_FL)) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	mask = FSX_XFLAGS; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		mask |= FSX_NONBLOCK; | 
					
						
							|  |  |  | 	fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 	error = xfs_ioctl_setattr(ip, &fa, mask); | 
					
						
							|  |  |  | 	mnt_drop_write_file(filp); | 
					
						
							|  |  |  | 	return -error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct getbmap __user	*base = *ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* copy only getbmap portion (not getbmapx) */ | 
					
						
							|  |  |  | 	if (copy_to_user(base, bmv, sizeof(struct getbmap))) | 
					
						
							|  |  |  | 		return XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*ap += sizeof(struct getbmap); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_getbmap( | 
					
						
							| 
									
										
										
										
											2007-08-28 16:12:30 +10:00
										 |  |  | 	struct xfs_inode	*ip, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			ioflags, | 
					
						
							|  |  |  | 	unsigned int		cmd, | 
					
						
							|  |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	struct getbmapx		bmx; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	if (copy_from_user(&bmx, arg, sizeof(struct getbmapx))) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	if (bmx.bmv_count < 2) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (ioflags & IO_INVIS) | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 		bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	error = xfs_getbmap(ip, &bmx, xfs_getbmap_format, | 
					
						
							|  |  |  | 			    (struct getbmap *)arg+1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	/* copy back header - only size of getbmap */ | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &bmx, sizeof(struct getbmap))) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct getbmapx __user	*base = *ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(base, bmv, sizeof(struct getbmapx))) | 
					
						
							|  |  |  | 		return XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*ap += sizeof(struct getbmapx); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_ioc_getbmapx( | 
					
						
							| 
									
										
										
										
											2007-08-28 16:12:30 +10:00
										 |  |  | 	struct xfs_inode	*ip, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	void			__user *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct getbmapx		bmx; | 
					
						
							|  |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&bmx, arg, sizeof(bmx))) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bmx.bmv_count < 2) | 
					
						
							|  |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	if (bmx.bmv_iflags & (~BMV_IF_VALID)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format, | 
					
						
							|  |  |  | 			    (struct getbmapx *)arg+1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	/* copy back header */ | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &bmx, sizeof(struct getbmapx))) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Note: some of the ioctl's return positive numbers as a | 
					
						
							|  |  |  |  * byte count indicating success, such as readlink_by_handle. | 
					
						
							|  |  |  |  * So we don't "sign flip" like most other routines.  This means | 
					
						
							|  |  |  |  * true errors need to be returned as a negative value. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | long | 
					
						
							|  |  |  | xfs_file_ioctl( | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	struct file		*filp, | 
					
						
							|  |  |  | 	unsigned int		cmd, | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | 	unsigned long		p) | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-01-23 17:07:38 -05:00
										 |  |  | 	struct inode		*inode = file_inode(filp); | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | 	struct xfs_inode	*ip = XFS_I(inode); | 
					
						
							|  |  |  | 	struct xfs_mount	*mp = ip->i_mount; | 
					
						
							|  |  |  | 	void			__user *arg = (void __user *)p; | 
					
						
							|  |  |  | 	int			ioflags = 0; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	int			error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | 	if (filp->f_mode & FMODE_NOCMTIME) | 
					
						
							|  |  |  | 		ioflags |= IO_INVIS; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-24 11:57:09 +10:00
										 |  |  | 	trace_xfs_file_ioctl(ip); | 
					
						
							| 
									
										
										
										
											2008-12-09 04:47:33 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							| 
									
										
										
										
											2011-01-07 13:02:04 +00:00
										 |  |  | 	case FITRIM: | 
					
						
							|  |  |  | 		return xfs_ioc_trim(mp, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	case XFS_IOC_ALLOCSP: | 
					
						
							|  |  |  | 	case XFS_IOC_FREESP: | 
					
						
							|  |  |  | 	case XFS_IOC_RESVSP: | 
					
						
							|  |  |  | 	case XFS_IOC_UNRESVSP: | 
					
						
							|  |  |  | 	case XFS_IOC_ALLOCSP64: | 
					
						
							|  |  |  | 	case XFS_IOC_FREESP64: | 
					
						
							|  |  |  | 	case XFS_IOC_RESVSP64: | 
					
						
							| 
									
										
										
										
											2010-08-24 12:02:11 +10:00
										 |  |  | 	case XFS_IOC_UNRESVSP64: | 
					
						
							|  |  |  | 	case XFS_IOC_ZERO_RANGE: { | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		xfs_flock64_t		bf; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		if (copy_from_user(&bf, arg, sizeof(bf))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 		return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	case XFS_IOC_DIOINFO: { | 
					
						
							|  |  |  | 		struct dioattr	da; | 
					
						
							|  |  |  | 		xfs_buftarg_t	*target = | 
					
						
							|  |  |  | 			XFS_IS_REALTIME_INODE(ip) ? | 
					
						
							|  |  |  | 			mp->m_rtdev_targp : mp->m_ddev_targp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		da.d_mem = da.d_miniosz = 1 << target->bt_sshift; | 
					
						
							|  |  |  | 		da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &da, sizeof(da))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSBULKSTAT_SINGLE: | 
					
						
							|  |  |  | 	case XFS_IOC_FSBULKSTAT: | 
					
						
							|  |  |  | 	case XFS_IOC_FSINUMBERS: | 
					
						
							|  |  |  | 		return xfs_ioc_bulkstat(mp, cmd, arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGEOMETRY_V1: | 
					
						
							|  |  |  | 		return xfs_ioc_fsgeometry_v1(mp, arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGEOMETRY: | 
					
						
							|  |  |  | 		return xfs_ioc_fsgeometry(mp, arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_GETVERSION: | 
					
						
							|  |  |  | 		return put_user(inode->i_generation, (int __user *)arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGETXATTR: | 
					
						
							|  |  |  | 		return xfs_ioc_fsgetxattr(ip, 0, arg); | 
					
						
							|  |  |  | 	case XFS_IOC_FSGETXATTRA: | 
					
						
							|  |  |  | 		return xfs_ioc_fsgetxattr(ip, 1, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 12:59:45 +10:00
										 |  |  | 	case XFS_IOC_FSSETXATTR: | 
					
						
							|  |  |  | 		return xfs_ioc_fssetxattr(ip, filp, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	case XFS_IOC_GETXFLAGS: | 
					
						
							| 
									
										
										
										
											2008-04-18 12:59:45 +10:00
										 |  |  | 		return xfs_ioc_getxflags(ip, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	case XFS_IOC_SETXFLAGS: | 
					
						
							| 
									
										
										
										
											2008-04-18 12:59:45 +10:00
										 |  |  | 		return xfs_ioc_setxflags(ip, filp, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSSETDM: { | 
					
						
							|  |  |  | 		struct fsdmidata	dmi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&dmi, arg, sizeof(dmi))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask, | 
					
						
							|  |  |  | 				dmi.fsd_dmstate); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_GETBMAP: | 
					
						
							|  |  |  | 	case XFS_IOC_GETBMAPA: | 
					
						
							|  |  |  | 		return xfs_ioc_getbmap(ip, ioflags, cmd, arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_GETBMAPX: | 
					
						
							|  |  |  | 		return xfs_ioc_getbmapx(ip, arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FD_TO_HANDLE: | 
					
						
							|  |  |  | 	case XFS_IOC_PATH_TO_HANDLE: | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	case XFS_IOC_PATH_TO_FSHANDLE: { | 
					
						
							|  |  |  | 		xfs_fsop_handlereq_t	hreq; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		if (copy_from_user(&hreq, arg, sizeof(hreq))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 		return xfs_find_handle(cmd, &hreq); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case XFS_IOC_OPEN_BY_HANDLE: { | 
					
						
							|  |  |  | 		xfs_fsop_handlereq_t	hreq; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return xfs_open_by_handle(filp, &hreq); | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	case XFS_IOC_FSSETDM_BY_HANDLE: | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return xfs_fssetdm_by_handle(filp, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	case XFS_IOC_READLINK_BY_HANDLE: { | 
					
						
							|  |  |  | 		xfs_fsop_handlereq_t	hreq; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return xfs_readlink_by_handle(filp, &hreq); | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	case XFS_IOC_ATTRLIST_BY_HANDLE: | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return xfs_attrlist_by_handle(filp, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_ATTRMULTI_BY_HANDLE: | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		return xfs_attrmulti_by_handle(filp, arg); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_SWAPEXT: { | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		struct xfs_swapext	sxp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		error = xfs_swapext(&sxp); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSCOUNTS: { | 
					
						
							|  |  |  | 		xfs_fsop_counts_t out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_fs_counts(mp, &out); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &out, sizeof(out))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_SET_RESBLKS: { | 
					
						
							|  |  |  | 		xfs_fsop_resblks_t inout; | 
					
						
							|  |  |  | 		__uint64_t	   in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 22:59:53 +00:00
										 |  |  | 		if (mp->m_flags & XFS_MOUNT_RDONLY) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EROFS); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		if (copy_from_user(&inout, arg, sizeof(inout))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		/* input parameter is passed in resblks field of structure */ | 
					
						
							|  |  |  | 		in = inout.resblks; | 
					
						
							|  |  |  | 		error = xfs_reserve_blocks(mp, &in, &inout); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		if (error) | 
					
						
							|  |  |  | 			return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &inout, sizeof(inout))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_GET_RESBLKS: { | 
					
						
							|  |  |  | 		xfs_fsop_resblks_t out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_reserve_blocks(mp, NULL, &out); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &out, sizeof(out))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGROWFSDATA: { | 
					
						
							|  |  |  | 		xfs_growfs_data_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		error = xfs_growfs_data(mp, &in); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGROWFSLOG: { | 
					
						
							|  |  |  | 		xfs_growfs_log_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		error = xfs_growfs_log(mp, &in); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGROWFSRT: { | 
					
						
							|  |  |  | 		xfs_growfs_rt_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		error = xfs_growfs_rt(mp, &in); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_GOINGDOWN: { | 
					
						
							|  |  |  | 		__uint32_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (get_user(in, (__uint32_t __user *)arg)) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_fs_goingdown(mp, in); | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_ERROR_INJECTION: { | 
					
						
							|  |  |  | 		xfs_error_injection_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_errortag_add(in.errtag, mp); | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_ERROR_CLEARALL: | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_errortag_clearall(mp, 1); | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 	case XFS_IOC_FREE_EOFBLOCKS: { | 
					
						
							|  |  |  | 		struct xfs_eofblocks eofb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&eofb, arg, sizeof(eofb))) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EFAULT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (eofb.eof_version != XFS_EOFBLOCKS_VERSION) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (eofb.eof_flags & ~XFS_EOF_FLAGS_VALID) | 
					
						
							|  |  |  | 			return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:13 -05:00
										 |  |  | 		if (memchr_inv(&eofb.pad32, 0, sizeof(eofb.pad32)) || | 
					
						
							|  |  |  | 		    memchr_inv(eofb.pad64, 0, sizeof(eofb.pad64))) | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 			return -XFS_ERROR(EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_icache_free_eofblocks(mp, &eofb); | 
					
						
							|  |  |  | 		return -error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return -ENOTTY; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |