| 
									
										
										
										
											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"
 | 
					
						
							| 
									
										
										
										
											2013-10-23 10:36:05 +11:00
										 |  |  | #include "xfs_shared.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-23 10:50:10 +11:00
										 |  |  | #include "xfs_format.h"
 | 
					
						
							|  |  |  | #include "xfs_log_format.h"
 | 
					
						
							|  |  |  | #include "xfs_trans_resv.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #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_mount.h"
 | 
					
						
							|  |  |  | #include "xfs_inode.h"
 | 
					
						
							| 
									
										
										
										
											2009-03-05 15:20:25 +01:00
										 |  |  | #include "xfs_ioctl.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-23 10:51:50 +11:00
										 |  |  | #include "xfs_alloc.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"
 | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:42 +10:00
										 |  |  | #include "xfs_bmap_util.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include "xfs_fsops.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"
 | 
					
						
							| 
									
										
										
										
											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"
 | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:45 +10:00
										 |  |  | #include "xfs_symlink.h"
 | 
					
						
							| 
									
										
										
										
											2013-10-23 10:51:50 +11:00
										 |  |  | #include "xfs_dinode.h"
 | 
					
						
							|  |  |  | #include "xfs_trans.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; | 
					
						
							| 
									
										
										
										
											2013-09-02 20:49:36 +10:00
										 |  |  | 	struct fd		f = {NULL}; | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | 		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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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))) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -EPERM; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		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)) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -EPERM; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		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)) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -EACCES; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		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)) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -EISDIR; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-02 18:39:34 +02:00
										 |  |  | 	fd = get_unused_fd_flags(0); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		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))) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		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) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -ENOMEM; | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 		goto out_dput; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10: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; | 
					
						
							| 
									
										
										
										
											2014-03-14 13:42:45 -04:00
										 |  |  | 	error = readlink_copy(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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:45 +10:00
										 |  |  | int | 
					
						
							|  |  |  | xfs_set_dmattrs( | 
					
						
							|  |  |  | 	xfs_inode_t     *ip, | 
					
						
							|  |  |  | 	u_int		evmask, | 
					
						
							|  |  |  | 	u_int16_t	state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	xfs_mount_t	*mp = ip->i_mount; | 
					
						
							|  |  |  | 	xfs_trans_t	*tp; | 
					
						
							|  |  |  | 	int		error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!capable(CAP_SYS_ADMIN)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (XFS_FORCED_SHUTDOWN(mp)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EIO; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:59 +10:00
										 |  |  | 	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:45 +10:00
										 |  |  | 	if (error) { | 
					
						
							|  |  |  | 		xfs_trans_cancel(tp, 0); | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	xfs_ilock(ip, XFS_ILOCK_EXCL); | 
					
						
							|  |  |  | 	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ip->i_d.di_dmevmask = evmask; | 
					
						
							|  |  |  | 	ip->i_d.di_dmstate  = state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 
					
						
							|  |  |  | 	error = xfs_trans_commit(tp, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -EPERM; | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		error = -EFAULT; | 
					
						
							| 
									
										
										
										
											2007-10-11 18:09:50 +10:00
										 |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10: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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2013-10-31 21:00:10 +03:00
										 |  |  | 	if (al_hreq.buflen < sizeof(struct attrlist) || | 
					
						
							|  |  |  | 	    al_hreq.buflen > XATTR_LIST_MAX) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-27 13:32:19 +10:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Reject flags, only allow namespaces. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2008-06-27 13:32:19 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-02 20:53:00 +10:00
										 |  |  | 	kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP); | 
					
						
							|  |  |  | 	if (!kbuf) | 
					
						
							|  |  |  | 		goto out_dput; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10: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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-02 20:53:00 +10:00
										 |  |  | out_kfree: | 
					
						
							|  |  |  | 	kmem_free(kbuf); | 
					
						
							|  |  |  | out_dput: | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10: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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-09-02 20:53:00 +10:00
										 |  |  | 	kbuf = kmem_zalloc_large(*len, KM_SLEEP); | 
					
						
							|  |  |  | 	if (!kbuf) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		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)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-02 20:53:00 +10:00
										 |  |  | out_kfree: | 
					
						
							|  |  |  | 	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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-29 10:58:01 +10:00
										 |  |  | 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (len > XATTR_SIZE_MAX) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 	return xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); | 
					
						
							| 
									
										
										
										
											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_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)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10: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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10: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)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 	error = -ENOMEM; | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			error = -ERANGE; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		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: | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			ops[i].am_error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(am_hreq.ops, ops, size)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	kfree(attr_name); | 
					
						
							|  |  |  |  out_kfree_ops: | 
					
						
							|  |  |  | 	kfree(ops); | 
					
						
							| 
									
										
										
										
											2009-01-19 02:02:57 +01:00
										 |  |  |  out_dput: | 
					
						
							|  |  |  | 	dput(dentry); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											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_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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 	struct xfs_mount	*mp = ip->i_mount; | 
					
						
							|  |  |  | 	struct xfs_trans	*tp; | 
					
						
							|  |  |  | 	struct iattr		iattr; | 
					
						
							|  |  |  | 	bool			setprealloc = false; | 
					
						
							|  |  |  | 	bool			clrprealloc = false; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-28 10:52:04 +10:00
										 |  |  | 	if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EPERM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-02 16:41:16 +10:00
										 |  |  | 	if (!(filp->f_mode & FMODE_WRITE)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EBADF; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-28 10:52:04 +10:00
										 |  |  | 	if (!S_ISREG(inode->i_mode)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:06 -07:00
										 |  |  | 	xfs_ilock(ip, XFS_IOLOCK_EXCL); | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (bf->l_whence) { | 
					
						
							|  |  |  | 	case 0: /*SEEK_SET*/ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 1: /*SEEK_CUR*/ | 
					
						
							|  |  |  | 		bf->l_start += filp->f_pos; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 2: /*SEEK_END*/ | 
					
						
							|  |  |  | 		bf->l_start += XFS_ISIZE(ip); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 		goto out_unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * length of <= 0 for resv/unresv/zero is invalid.  length for | 
					
						
							|  |  |  | 	 * alloc/free is ignored completely and we have no idea what userspace | 
					
						
							|  |  |  | 	 * might have set it to, so set it to zero to allow range | 
					
						
							|  |  |  | 	 * checks to pass. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case XFS_IOC_ZERO_RANGE: | 
					
						
							|  |  |  | 	case XFS_IOC_RESVSP: | 
					
						
							|  |  |  | 	case XFS_IOC_RESVSP64: | 
					
						
							|  |  |  | 	case XFS_IOC_UNRESVSP: | 
					
						
							|  |  |  | 	case XFS_IOC_UNRESVSP64: | 
					
						
							|  |  |  | 		if (bf->l_len <= 0) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 			goto out_unlock; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		bf->l_len = 0; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bf->l_start < 0 || | 
					
						
							|  |  |  | 	    bf->l_start > mp->m_super->s_maxbytes || | 
					
						
							|  |  |  | 	    bf->l_start + bf->l_len < 0 || | 
					
						
							|  |  |  | 	    bf->l_start + bf->l_len >= mp->m_super->s_maxbytes) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 		goto out_unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case XFS_IOC_ZERO_RANGE: | 
					
						
							|  |  |  | 		error = xfs_zero_file_space(ip, bf->l_start, bf->l_len); | 
					
						
							|  |  |  | 		if (!error) | 
					
						
							|  |  |  | 			setprealloc = true; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case XFS_IOC_RESVSP: | 
					
						
							|  |  |  | 	case XFS_IOC_RESVSP64: | 
					
						
							|  |  |  | 		error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len, | 
					
						
							|  |  |  | 						XFS_BMAPI_PREALLOC); | 
					
						
							|  |  |  | 		if (!error) | 
					
						
							|  |  |  | 			setprealloc = true; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case XFS_IOC_UNRESVSP: | 
					
						
							|  |  |  | 	case XFS_IOC_UNRESVSP64: | 
					
						
							|  |  |  | 		error = xfs_free_file_space(ip, bf->l_start, bf->l_len); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case XFS_IOC_ALLOCSP: | 
					
						
							|  |  |  | 	case XFS_IOC_ALLOCSP64: | 
					
						
							|  |  |  | 	case XFS_IOC_FREESP: | 
					
						
							|  |  |  | 	case XFS_IOC_FREESP64: | 
					
						
							|  |  |  | 		if (bf->l_start > XFS_ISIZE(ip)) { | 
					
						
							|  |  |  | 			error = xfs_alloc_file_space(ip, XFS_ISIZE(ip), | 
					
						
							|  |  |  | 					bf->l_start - XFS_ISIZE(ip), 0); | 
					
						
							|  |  |  | 			if (error) | 
					
						
							|  |  |  | 				goto out_unlock; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		iattr.ia_valid = ATTR_SIZE; | 
					
						
							|  |  |  | 		iattr.ia_size = bf->l_start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_setattr_size(ip, &iattr); | 
					
						
							|  |  |  | 		if (!error) | 
					
						
							|  |  |  | 			clrprealloc = true; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		ASSERT(0); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto out_unlock; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); | 
					
						
							|  |  |  | 	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_writeid, 0, 0); | 
					
						
							|  |  |  | 	if (error) { | 
					
						
							|  |  |  | 		xfs_trans_cancel(tp, 0); | 
					
						
							|  |  |  | 		goto out_unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xfs_ilock(ip, XFS_ILOCK_EXCL); | 
					
						
							|  |  |  | 	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-04 13:28:20 +10:00
										 |  |  | 	if (!(ioflags & XFS_IO_INVIS)) { | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:08 -07:00
										 |  |  | 		ip->i_d.di_mode &= ~S_ISUID; | 
					
						
							|  |  |  | 		if (ip->i_d.di_mode & S_IXGRP) | 
					
						
							|  |  |  | 			ip->i_d.di_mode &= ~S_ISGID; | 
					
						
							|  |  |  | 		xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (setprealloc) | 
					
						
							|  |  |  | 		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | 
					
						
							|  |  |  | 	else if (clrprealloc) | 
					
						
							|  |  |  | 		ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 
					
						
							|  |  |  | 	if (filp->f_flags & O_DSYNC) | 
					
						
							|  |  |  | 		xfs_trans_set_sync(tp); | 
					
						
							|  |  |  | 	error = xfs_trans_commit(tp, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out_unlock: | 
					
						
							| 
									
										
										
										
											2013-10-12 00:55:06 -07:00
										 |  |  | 	xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 	mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ((count = bulkreq.icount) <= 0) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-23 16:30:32 +11:00
										 |  |  | 	if (bulkreq.ubuffer == NULL) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2007-11-23 16:30:32 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2014-07-24 12:07:15 +10:00
										 |  |  | 		error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer, | 
					
						
							|  |  |  | 					sizeof(xfs_bstat_t), NULL, &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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (bulkreq.ocount != NULL) { | 
					
						
							|  |  |  | 		if (copy_to_user(bulkreq.lastip, &inlast, | 
					
						
							|  |  |  | 						sizeof(xfs_ino_t))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	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_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; | 
					
						
							| 
									
										
										
										
											2014-10-02 09:18:40 +10:00
										 |  |  | 		if (xflags & XFS_XFLAG_PROJINHERIT) | 
					
						
							|  |  |  | 			di_flags |= XFS_DIFLAG_PROJINHERIT; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2013-07-11 00:00:40 -05:00
										 |  |  | 	struct xfs_dquot	*pdqp = 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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EROFS; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	if (XFS_FORCED_SHUTDOWN(mp)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EIO; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2010-08-26 10:19:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							| 
									
										
										
										
											2013-07-11 00:00:40 -05:00
										 |  |  | 					 XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:59 +10:00
										 |  |  | 	code = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	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. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:00 -04:00
										 |  |  | 	if (!inode_owner_or_capable(VFS_I(ip))) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		code = -EPERM; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		goto error_return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Do a quota reservation only if projid is actually going to change. | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:00 -04:00
										 |  |  | 	 * Only allow changing of projid from init_user_ns since it is a | 
					
						
							|  |  |  | 	 * non user namespace aware identifier. | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mask & FSX_PROJID) { | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:00 -04:00
										 |  |  | 		if (current_user_ns() != &init_user_ns) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			code = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:00 -04:00
										 |  |  | 			goto error_return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2013-07-11 00:00:40 -05:00
										 |  |  | 			code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, | 
					
						
							|  |  |  | 						pdqp, capable(CAP_FOWNER) ? | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 						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)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			code = -EINVAL;	/* EFBIG? */ | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			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) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 				code = -EINVAL; | 
					
						
							| 
									
										
										
										
											2011-01-27 12:18:18 +11:00
										 |  |  | 				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) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 					code = -EINVAL; | 
					
						
							| 
									
										
										
										
											2011-01-27 12:18:18 +11:00
										 |  |  | 					goto error_return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (fa->fsx_extsize % size) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 				code = -EINVAL; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 				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)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			code = -EINVAL;	/* EFBIG? */ | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			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)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 				code = -EINVAL; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 				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)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			code = -EPERM; | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			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)) && | 
					
						
							| 
									
										
										
										
											2014-06-10 12:45:42 -07:00
										 |  |  | 		    !capable_wrt_inode_uidgid(VFS_I(ip), CAP_FSETID)) | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			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, | 
					
						
							| 
									
										
										
										
											2013-07-11 00:00:40 -05:00
										 |  |  | 							&ip->i_pdquot, pdqp); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-05-20 07:46:40 +10:00
										 |  |  | 			ASSERT(ip->i_d.di_version > 1); | 
					
						
							| 
									
										
										
										
											2010-09-26 06:10:18 +00:00
										 |  |  | 			xfs_set_projid(ip, fa->fsx_projid); | 
					
						
							| 
									
										
										
										
											2008-07-18 17:13:20 +10:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-02 09:20:30 +10:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Only set the extent size hint if we've already determined that the | 
					
						
							|  |  |  | 	 * extent size hint should be set on the inode. If no extent size flags | 
					
						
							|  |  |  | 	 * are set on the inode then unconditionally clear the extent size hint. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mask & FSX_EXTSIZE) { | 
					
						
							|  |  |  | 		int	extsize = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ip->i_d.di_flags & | 
					
						
							|  |  |  | 				(XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT)) | 
					
						
							|  |  |  | 			extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; | 
					
						
							|  |  |  | 		ip->i_d.di_extsize = extsize; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2013-07-11 00:00:40 -05:00
										 |  |  | 	xfs_qm_dqrele(pdqp); | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2013-07-11 00:00:40 -05:00
										 |  |  | 	xfs_qm_dqrele(pdqp); | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 	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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-29 10:46:22 +10:00
										 |  |  | 	struct getbmap __user	*base = (struct getbmap __user *)*ap; | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* copy only getbmap portion (not getbmapx) */ | 
					
						
							|  |  |  | 	if (copy_to_user(base, bmv, sizeof(struct getbmap))) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	*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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	if (bmx.bmv_count < 2) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); | 
					
						
							| 
									
										
										
										
											2014-08-04 13:28:20 +10:00
										 |  |  | 	if (ioflags & XFS_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, | 
					
						
							| 
									
										
										
										
											2014-09-29 10:46:22 +10:00
										 |  |  | 			    (__force struct getbmap *)arg+1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	/* copy back header - only size of getbmap */ | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &bmx, sizeof(struct getbmap))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | STATIC int | 
					
						
							|  |  |  | xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-09-29 10:46:22 +10:00
										 |  |  | 	struct getbmapx __user	*base = (struct getbmapx __user *)*ap; | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (copy_to_user(base, bmv, sizeof(struct getbmapx))) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	*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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (bmx.bmv_count < 2) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	if (bmx.bmv_iflags & (~BMV_IF_VALID)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format, | 
					
						
							| 
									
										
										
										
											2014-09-29 10:46:22 +10:00
										 |  |  | 			    (__force struct getbmapx *)arg+1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (error) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-28 14:23:35 +11:00
										 |  |  | 	/* copy back header */ | 
					
						
							|  |  |  | 	if (copy_to_user(arg, &bmx, sizeof(struct getbmapx))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 		return -EFAULT; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | int | 
					
						
							|  |  |  | xfs_ioc_swapext( | 
					
						
							|  |  |  | 	xfs_swapext_t	*sxp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	xfs_inode_t     *ip, *tip; | 
					
						
							|  |  |  | 	struct fd	f, tmp; | 
					
						
							|  |  |  | 	int		error = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Pull information for the target fd */ | 
					
						
							|  |  |  | 	f = fdget((int)sxp->sx_fdtarget); | 
					
						
							|  |  |  | 	if (!f.file) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(f.file->f_mode & FMODE_WRITE) || | 
					
						
							|  |  |  | 	    !(f.file->f_mode & FMODE_READ) || | 
					
						
							|  |  |  | 	    (f.file->f_flags & O_APPEND)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EBADF; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp = fdget((int)sxp->sx_fdtmp); | 
					
						
							|  |  |  | 	if (!tmp.file) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(tmp.file->f_mode & FMODE_WRITE) || | 
					
						
							|  |  |  | 	    !(tmp.file->f_mode & FMODE_READ) || | 
					
						
							|  |  |  | 	    (tmp.file->f_flags & O_APPEND)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EBADF; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_tmp_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (IS_SWAPFILE(file_inode(f.file)) || | 
					
						
							|  |  |  | 	    IS_SWAPFILE(file_inode(tmp.file))) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_tmp_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ip = XFS_I(file_inode(f.file)); | 
					
						
							|  |  |  | 	tip = XFS_I(file_inode(tmp.file)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ip->i_mount != tip->i_mount) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_tmp_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ip->i_ino == tip->i_ino) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_tmp_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		error = -EIO; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		goto out_put_tmp_file; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = xfs_swap_extents(ip, tip, sxp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out_put_tmp_file: | 
					
						
							|  |  |  | 	fdput(tmp); | 
					
						
							|  |  |  |  out_put_file: | 
					
						
							|  |  |  | 	fdput(f); | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2014-08-04 13:28:20 +10:00
										 |  |  | 		ioflags |= XFS_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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												xfs: allow logical-sector sized O_DIRECT
Some time ago, mkfs.xfs started picking the storage physical
sector size as the default filesystem "sector size" in order
to avoid RMW costs incurred by doing IOs at logical sector
size alignments.
However, this means that for a filesystem made with i.e.
a 4k sector size on an "advanced format" 4k/512 disk,
512-byte direct IOs are no longer allowed.  This means
that XFS has essentially turned this AF drive into a hard
4K device, from the filesystem on up.
XFS's mkfs-specified "sector size" is really just controlling
the minimum size & alignment of filesystem metadata.
There is no real need to tightly couple XFS's minimal
metadata size to the minimum allowed direct IO size;
XFS can continue doing metadata in optimal sizes, but
still allow smaller DIOs for apps which issue them,
for whatever reason.
This patch adds a new field to the xfs_buftarg, so that
we now track 2 sizes:
 1) The metadata sector size, which is the minimum unit and
    alignment of IO which will be performed by metadata operations.
 2) The device logical sector size
The first is used internally by the file system for metadata
alignment and IOs.
The second is used for the minimum allowed direct IO alignment.
This has passed xfstests on filesystems made with 4k sectors,
including when run under the patch I sent to ignore
XFS_IOC_DIOINFO, and issue 512 DIOs anyway.  I also directly
tested end of block behavior on preallocated, sparse, and
existing files when we do a 512 IO into a 4k file on a 
4k-sector filesystem, to be sure there were no unexpected
behaviors.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
											
										 
											2014-01-21 16:46:23 -06:00
										 |  |  | 		da.d_mem =  da.d_miniosz = target->bt_logical_sectorsize; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &da, sizeof(da))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-11-25 21:20:06 -06:00
										 |  |  | 		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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		error = mnt_want_write_file(filp); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2013-08-12 20:49:48 +10:00
										 |  |  | 		error = xfs_ioc_swapext(&sxp); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:20:39 +02:00
										 |  |  | 		mnt_drop_write_file(filp); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSCOUNTS: { | 
					
						
							|  |  |  | 		xfs_fsop_counts_t out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		error = xfs_fs_counts(mp, &out); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &out, sizeof(out))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EROFS; | 
					
						
							| 
									
										
										
										
											2010-02-05 22:59:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		if (copy_from_user(&inout, arg, sizeof(inout))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &inout, sizeof(inout))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_to_user(arg, &out, sizeof(out))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGROWFSDATA: { | 
					
						
							|  |  |  | 		xfs_growfs_data_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGROWFSLOG: { | 
					
						
							|  |  |  | 		xfs_growfs_log_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_FSGROWFSRT: { | 
					
						
							|  |  |  | 		xfs_growfs_rt_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (copy_from_user(&in, arg, sizeof(in))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_GOINGDOWN: { | 
					
						
							|  |  |  | 		__uint32_t in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (get_user(in, (__uint32_t __user *)arg)) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return xfs_fs_goingdown(mp, in); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return xfs_errortag_add(in.errtag, mp); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case XFS_IOC_ERROR_CLEARALL: | 
					
						
							|  |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return xfs_errortag_clearall(mp, 1); | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 	case XFS_IOC_FREE_EOFBLOCKS: { | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:02 -04:00
										 |  |  | 		struct xfs_fs_eofblocks eofb; | 
					
						
							|  |  |  | 		struct xfs_eofblocks keofb; | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:03 -04:00
										 |  |  | 		if (!capable(CAP_SYS_ADMIN)) | 
					
						
							|  |  |  | 			return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (mp->m_flags & XFS_MOUNT_RDONLY) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EROFS; | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:03 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 		if (copy_from_user(&eofb, arg, sizeof(eofb))) | 
					
						
							| 
									
										
										
										
											2014-06-22 15:04:54 +10:00
										 |  |  | 			return -EFAULT; | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-15 14:08:02 -04:00
										 |  |  | 		error = xfs_fs_eofblocks_from_user(&eofb, &keofb); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 			return error; | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 14:58:08 +10:00
										 |  |  | 		return xfs_icache_free_eofblocks(mp, &keofb); | 
					
						
							| 
									
										
										
										
											2012-11-07 12:21:12 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-18 11:44:03 +10:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return -ENOTTY; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |