[2/4] fs: add generic UNRESVSP and ZERO_RANGE ioctl handlers
diff mbox series

Message ID 20191025023609.22295-3-hch@lst.de
State New
Headers show
Series
  • [1/4] xfs: don't implement XFS_IOC_RESVSP / XFS_IOC_RESVSP64 directly
Related show

Commit Message

Christoph Hellwig Oct. 25, 2019, 2:36 a.m. UTC
These use the same scheme as the pre-existing mapping of the XFS
RESVP ioctls to ->falloc, so just extend it and remove the XFS
implementation.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/compat_ioctl.c      | 32 ++++++++++++++++---
 fs/ioctl.c             | 12 +++++--
 fs/xfs/xfs_ioctl.c     | 72 +++++++-----------------------------------
 fs/xfs/xfs_ioctl.h     |  1 -
 fs/xfs/xfs_ioctl32.c   |  7 ++--
 include/linux/falloc.h |  3 ++
 include/linux/fs.h     |  2 +-
 7 files changed, 54 insertions(+), 75 deletions(-)

Comments

Darrick J. Wong Oct. 25, 2019, 5:44 a.m. UTC | #1
On Fri, Oct 25, 2019 at 11:36:07AM +0900, Christoph Hellwig wrote:
> These use the same scheme as the pre-existing mapping of the XFS
> RESVP ioctls to ->falloc, so just extend it and remove the XFS
> implementation.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  fs/compat_ioctl.c      | 32 ++++++++++++++++---
>  fs/ioctl.c             | 12 +++++--
>  fs/xfs/xfs_ioctl.c     | 72 +++++++-----------------------------------
>  fs/xfs/xfs_ioctl.h     |  1 -
>  fs/xfs/xfs_ioctl32.c   |  7 ++--
>  include/linux/falloc.h |  3 ++
>  include/linux/fs.h     |  2 +-
>  7 files changed, 54 insertions(+), 75 deletions(-)
> 
> diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
> index a7ec2d3dff92..7d920dda2811 100644
> --- a/fs/compat_ioctl.c
> +++ b/fs/compat_ioctl.c
> @@ -480,11 +480,14 @@ struct space_resv_32 {
>  	__s32		l_pad[4];	/* reserve area */
>  };
>  
> -#define FS_IOC_RESVSP_32		_IOW ('X', 40, struct space_resv_32)
> +#define FS_IOC_RESVSP_32	_IOW ('X', 40, struct space_resv_32)
> +#define FS_IOC_UNRESVSP_32	_IOW ('X', 41, struct space_resv_32)
>  #define FS_IOC_RESVSP64_32	_IOW ('X', 42, struct space_resv_32)
> +#define FS_IOC_UNRESVSP64_32	_IOW ('X', 43, struct space_resv_32)
> +#define FS_IOC_ZERO_RANGE_32	_IOW ('X', 57, struct space_resv_32)
>  
>  /* just account for different alignment */
> -static int compat_ioctl_preallocate(struct file *file,
> +static int compat_ioctl_preallocate(struct file *file, int mode,
>  			struct space_resv_32    __user *p32)
>  {
>  	struct space_resv	__user *p = compat_alloc_user_space(sizeof(*p));
> @@ -498,7 +501,7 @@ static int compat_ioctl_preallocate(struct file *file,
>  	    copy_in_user(&p->l_pad,	&p32->l_pad,	4*sizeof(u32)))
>  		return -EFAULT;
>  
> -	return ioctl_preallocate(file, p);
> +	return ioctl_preallocate(file, mode, p);
>  }
>  #endif
>  
> @@ -1022,13 +1025,32 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
>  #if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
>  	case FS_IOC_RESVSP_32:
>  	case FS_IOC_RESVSP64_32:
> -		error = compat_ioctl_preallocate(f.file, compat_ptr(arg));
> +		error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
> +		goto out_fput;
> +	case FS_IOC_UNRESVSP_32:
> +	case FS_IOC_UNRESVSP64_32:
> +		error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
> +				compat_ptr(arg));
> +		goto out_fput;
> +	case FS_IOC_ZERO_RANGE_32:
> +		error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
> +				compat_ptr(arg));
>  		goto out_fput;
>  #else
>  	case FS_IOC_RESVSP:
>  	case FS_IOC_RESVSP64:
> -		error = ioctl_preallocate(f.file, compat_ptr(arg));
> +		error = ioctl_preallocate(f.file, 0, compat_ptr(arg));
> +		goto out_fput;
> +	case FS_IOC_UNRESVSP:
> +	case FS_IOC_UNRESVSP64:
> +		error = ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
> +				compat_ptr(arg));
>  		goto out_fput;
> +	case FS_IOC_ZERO_RANGE:
> +		error = ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
> +				compat_ptr(arg));
> +		goto out_fput;
> +	}
>  #endif
>  
>  	case FICLONE:
> diff --git a/fs/ioctl.c b/fs/ioctl.c
> index fef3a6bf7c78..55c7cfb0e599 100644
> --- a/fs/ioctl.c
> +++ b/fs/ioctl.c
> @@ -466,7 +466,7 @@ EXPORT_SYMBOL(generic_block_fiemap);
>   * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
>   * are used here, rest are ignored.
>   */
> -int ioctl_preallocate(struct file *filp, void __user *argp)
> +int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
>  {
>  	struct inode *inode = file_inode(filp);
>  	struct space_resv sr;
> @@ -487,7 +487,8 @@ int ioctl_preallocate(struct file *filp, void __user *argp)
>  		return -EINVAL;
>  	}
>  
> -	return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
> +	return vfs_fallocate(filp, mode | FALLOC_FL_KEEP_SIZE, sr.l_start,
> +			sr.l_len);
>  }
>  
>  static int file_ioctl(struct file *filp, unsigned int cmd,
> @@ -503,7 +504,12 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
>  		return put_user(i_size_read(inode) - filp->f_pos, p);
>  	case FS_IOC_RESVSP:
>  	case FS_IOC_RESVSP64:
> -		return ioctl_preallocate(filp, p);
> +		return ioctl_preallocate(filp, 0, p);
> +	case FS_IOC_UNRESVSP:
> +	case FS_IOC_UNRESVSP64:
> +		return ioctl_preallocate(filp, FALLOC_FL_PUNCH_HOLE, p);
> +	case FS_IOC_ZERO_RANGE:
> +		return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
>  	}
>  
>  	return vfs_ioctl(filp, cmd, arg);
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index da4aaa75cfd3..3fe1543f9f02 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -588,13 +588,12 @@ xfs_attrmulti_by_handle(
>  int
>  xfs_ioc_space(
>  	struct file		*filp,
> -	unsigned int		cmd,
>  	xfs_flock64_t		*bf)
>  {
>  	struct inode		*inode = file_inode(filp);
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	struct iattr		iattr;
> -	enum xfs_prealloc_flags	flags = 0;
> +	enum xfs_prealloc_flags	flags = XFS_PREALLOC_CLEAR;
>  	uint			iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
>  	int			error;
>  
> @@ -635,65 +634,21 @@ xfs_ioc_space(
>  		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_UNRESVSP:
> -	case XFS_IOC_UNRESVSP64:
> -		if (bf->l_len <= 0) {
> -			error = -EINVAL;
> -			goto out_unlock;
> -		}
> -		break;
> -	default:
> -		bf->l_len = 0;
> -		break;
> -	}
> -
> -	if (bf->l_start < 0 ||
> -	    bf->l_start > inode->i_sb->s_maxbytes ||
> -	    bf->l_start + bf->l_len < 0 ||
> -	    bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) {
> +	if (bf->l_start < 0 || bf->l_start > inode->i_sb->s_maxbytes) {
>  		error = -EINVAL;
>  		goto out_unlock;
>  	}
>  
> -	switch (cmd) {
> -	case XFS_IOC_ZERO_RANGE:
> -		flags |= XFS_PREALLOC_SET;
> -		error = xfs_zero_file_space(ip, bf->l_start, bf->l_len);
> -		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:
> -		flags |= XFS_PREALLOC_CLEAR;
> -		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_vn_setattr_size(file_dentry(filp), &iattr);
> -		break;
> -	default:
> -		ASSERT(0);
> -		error = -EINVAL;
> +	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_vn_setattr_size(file_dentry(filp), &iattr);
>  	if (error)
>  		goto out_unlock;
>  
> @@ -2113,16 +2068,13 @@ xfs_file_ioctl(
>  		return xfs_ioc_setlabel(filp, mp, arg);
>  	case XFS_IOC_ALLOCSP:
>  	case XFS_IOC_FREESP:
> -	case XFS_IOC_UNRESVSP:
>  	case XFS_IOC_ALLOCSP64:
> -	case XFS_IOC_FREESP64:
> -	case XFS_IOC_UNRESVSP64:
> -	case XFS_IOC_ZERO_RANGE: {
> +	case XFS_IOC_FREESP64: {

Ok, so this hoists everything to the vfs except for ALLOCSP and FREESP,
which seems to be ... "set new size; allocate between old and new EOF if
appropriate"?

I'm asking because I was never really clear on what those things are
supposed to do. :)

--D

>  		xfs_flock64_t		bf;
>  
>  		if (copy_from_user(&bf, arg, sizeof(bf)))
>  			return -EFAULT;
> -		return xfs_ioc_space(filp, cmd, &bf);
> +		return xfs_ioc_space(filp, &bf);
>  	}
>  	case XFS_IOC_DIOINFO: {
>  		struct dioattr		da;
> diff --git a/fs/xfs/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h
> index 654c0bb1bcf8..25ef178cbb74 100644
> --- a/fs/xfs/xfs_ioctl.h
> +++ b/fs/xfs/xfs_ioctl.h
> @@ -9,7 +9,6 @@
>  extern int
>  xfs_ioc_space(
>  	struct file		*filp,
> -	unsigned int		cmd,
>  	xfs_flock64_t		*bf);
>  
>  int
> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
> index 257b7caf7fed..3c0d518e1039 100644
> --- a/fs/xfs/xfs_ioctl32.c
> +++ b/fs/xfs/xfs_ioctl32.c
> @@ -557,16 +557,13 @@ xfs_file_compat_ioctl(
>  	case XFS_IOC_ALLOCSP_32:
>  	case XFS_IOC_FREESP_32:
>  	case XFS_IOC_ALLOCSP64_32:
> -	case XFS_IOC_FREESP64_32:
> -	case XFS_IOC_RESVSP64_32:
> -	case XFS_IOC_UNRESVSP64_32:
> -	case XFS_IOC_ZERO_RANGE_32: {
> +	case XFS_IOC_FREESP64_32: {
>  		struct xfs_flock64	bf;
>  
>  		if (xfs_compat_flock64_copyin(&bf, arg))
>  			return -EFAULT;
>  		cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
> -		return xfs_ioc_space(filp, cmd, &bf);
> +		return xfs_ioc_space(filp, &bf);
>  	}
>  	case XFS_IOC_FSGEOMETRY_V1_32:
>  		return xfs_compat_ioc_fsgeometry_v1(mp, arg);
> diff --git a/include/linux/falloc.h b/include/linux/falloc.h
> index 674d59f4d6ce..f5c73f0ec22d 100644
> --- a/include/linux/falloc.h
> +++ b/include/linux/falloc.h
> @@ -20,7 +20,10 @@ struct space_resv {
>  };
>  
>  #define FS_IOC_RESVSP		_IOW('X', 40, struct space_resv)
> +#define FS_IOC_UNRESVSP		_IOW('X', 41, struct space_resv)
>  #define FS_IOC_RESVSP64		_IOW('X', 42, struct space_resv)
> +#define FS_IOC_UNRESVSP64	_IOW('X', 43, struct space_resv)
> +#define FS_IOC_ZERO_RANGE	_IOW('X', 57, struct space_resv)
>  
>  #define	FALLOC_FL_SUPPORTED_MASK	(FALLOC_FL_KEEP_SIZE |		\
>  					 FALLOC_FL_PUNCH_HOLE |		\
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index e0d909d35763..2b5692207c1d 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2547,7 +2547,7 @@ extern int finish_no_open(struct file *file, struct dentry *dentry);
>  
>  /* fs/ioctl.c */
>  
> -extern int ioctl_preallocate(struct file *filp, void __user *argp);
> +extern int ioctl_preallocate(struct file *filp, int mode, void __user *argp);
>  
>  /* fs/dcache.c */
>  extern void __init vfs_caches_init_early(void);
> -- 
> 2.20.1
>
Christoph Hellwig Oct. 25, 2019, 9:50 a.m. UTC | #2
On Thu, Oct 24, 2019 at 10:44:52PM -0700, Darrick J. Wong wrote:
> >  	case XFS_IOC_FREESP:
> > -	case XFS_IOC_UNRESVSP:
> >  	case XFS_IOC_ALLOCSP64:
> > -	case XFS_IOC_FREESP64:
> > -	case XFS_IOC_UNRESVSP64:
> > -	case XFS_IOC_ZERO_RANGE: {
> > +	case XFS_IOC_FREESP64: {
> 
> Ok, so this hoists everything to the vfs except for ALLOCSP and FREESP,
> which seems to be ... "set new size; allocate between old and new EOF if
> appropriate"?
> 
> I'm asking because I was never really clear on what those things are
> supposed to do. :)

Yes. ALLOCSP/FREESP have so weird semantics that we never added the
equivalent functionality to fallocate.
Dave Chinner Oct. 26, 2019, 8:56 p.m. UTC | #3
On Fri, Oct 25, 2019 at 11:50:05AM +0200, Christoph Hellwig wrote:
> On Thu, Oct 24, 2019 at 10:44:52PM -0700, Darrick J. Wong wrote:
> > >  	case XFS_IOC_FREESP:
> > > -	case XFS_IOC_UNRESVSP:
> > >  	case XFS_IOC_ALLOCSP64:
> > > -	case XFS_IOC_FREESP64:
> > > -	case XFS_IOC_UNRESVSP64:
> > > -	case XFS_IOC_ZERO_RANGE: {
> > > +	case XFS_IOC_FREESP64: {
> > 
> > Ok, so this hoists everything to the vfs except for ALLOCSP and FREESP,
> > which seems to be ... "set new size; allocate between old and new EOF if
> > appropriate"?
> > 
> > I'm asking because I was never really clear on what those things are
> > supposed to do. :)
> 
> Yes. ALLOCSP/FREESP have so weird semantics that we never added the
> equivalent functionality to fallocate.

We should plan to deprecate and remove ALLOCSP/FREESP - they just
aren't useful APIs anymore, and nobody has used them in preference
to the RESVSP/UNRESVSP ioctls since they were introduced in ~1998
with unwritten extents. We probably should have deprecated then 10
years ago....

Cheers,

Dave.
Christoph Hellwig Oct. 27, 2019, 3:19 p.m. UTC | #4
On Sun, Oct 27, 2019 at 07:56:09AM +1100, Dave Chinner wrote:
> We should plan to deprecate and remove ALLOCSP/FREESP - they just
> aren't useful APIs anymore, and nobody has used them in preference
> to the RESVSP/UNRESVSP ioctls since they were introduced in ~1998
> with unwritten extents. We probably should have deprecated then 10
> years ago....

I vaguely remember an actually reported bug beeing fixed in the code
just a few years ago, which suggests actual users.  That being said
I'm all for throwing in a deprecation warnings and then see if anyone
screams.  With this series the code becomes more self-contained, and
I have another patch that moves the IOC_RESVP / fallocate implementation
over to use iomap, at which point it is entirely standalone.

Patch
diff mbox series

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a7ec2d3dff92..7d920dda2811 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -480,11 +480,14 @@  struct space_resv_32 {
 	__s32		l_pad[4];	/* reserve area */
 };
 
-#define FS_IOC_RESVSP_32		_IOW ('X', 40, struct space_resv_32)
+#define FS_IOC_RESVSP_32	_IOW ('X', 40, struct space_resv_32)
+#define FS_IOC_UNRESVSP_32	_IOW ('X', 41, struct space_resv_32)
 #define FS_IOC_RESVSP64_32	_IOW ('X', 42, struct space_resv_32)
+#define FS_IOC_UNRESVSP64_32	_IOW ('X', 43, struct space_resv_32)
+#define FS_IOC_ZERO_RANGE_32	_IOW ('X', 57, struct space_resv_32)
 
 /* just account for different alignment */
-static int compat_ioctl_preallocate(struct file *file,
+static int compat_ioctl_preallocate(struct file *file, int mode,
 			struct space_resv_32    __user *p32)
 {
 	struct space_resv	__user *p = compat_alloc_user_space(sizeof(*p));
@@ -498,7 +501,7 @@  static int compat_ioctl_preallocate(struct file *file,
 	    copy_in_user(&p->l_pad,	&p32->l_pad,	4*sizeof(u32)))
 		return -EFAULT;
 
-	return ioctl_preallocate(file, p);
+	return ioctl_preallocate(file, mode, p);
 }
 #endif
 
@@ -1022,13 +1025,32 @@  COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
 #if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
 	case FS_IOC_RESVSP_32:
 	case FS_IOC_RESVSP64_32:
-		error = compat_ioctl_preallocate(f.file, compat_ptr(arg));
+		error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
+		goto out_fput;
+	case FS_IOC_UNRESVSP_32:
+	case FS_IOC_UNRESVSP64_32:
+		error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
+				compat_ptr(arg));
+		goto out_fput;
+	case FS_IOC_ZERO_RANGE_32:
+		error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
+				compat_ptr(arg));
 		goto out_fput;
 #else
 	case FS_IOC_RESVSP:
 	case FS_IOC_RESVSP64:
-		error = ioctl_preallocate(f.file, compat_ptr(arg));
+		error = ioctl_preallocate(f.file, 0, compat_ptr(arg));
+		goto out_fput;
+	case FS_IOC_UNRESVSP:
+	case FS_IOC_UNRESVSP64:
+		error = ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
+				compat_ptr(arg));
 		goto out_fput;
+	case FS_IOC_ZERO_RANGE:
+		error = ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
+				compat_ptr(arg));
+		goto out_fput;
+	}
 #endif
 
 	case FICLONE:
diff --git a/fs/ioctl.c b/fs/ioctl.c
index fef3a6bf7c78..55c7cfb0e599 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -466,7 +466,7 @@  EXPORT_SYMBOL(generic_block_fiemap);
  * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
  * are used here, rest are ignored.
  */
-int ioctl_preallocate(struct file *filp, void __user *argp)
+int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
 {
 	struct inode *inode = file_inode(filp);
 	struct space_resv sr;
@@ -487,7 +487,8 @@  int ioctl_preallocate(struct file *filp, void __user *argp)
 		return -EINVAL;
 	}
 
-	return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+	return vfs_fallocate(filp, mode | FALLOC_FL_KEEP_SIZE, sr.l_start,
+			sr.l_len);
 }
 
 static int file_ioctl(struct file *filp, unsigned int cmd,
@@ -503,7 +504,12 @@  static int file_ioctl(struct file *filp, unsigned int cmd,
 		return put_user(i_size_read(inode) - filp->f_pos, p);
 	case FS_IOC_RESVSP:
 	case FS_IOC_RESVSP64:
-		return ioctl_preallocate(filp, p);
+		return ioctl_preallocate(filp, 0, p);
+	case FS_IOC_UNRESVSP:
+	case FS_IOC_UNRESVSP64:
+		return ioctl_preallocate(filp, FALLOC_FL_PUNCH_HOLE, p);
+	case FS_IOC_ZERO_RANGE:
+		return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
 	}
 
 	return vfs_ioctl(filp, cmd, arg);
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index da4aaa75cfd3..3fe1543f9f02 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -588,13 +588,12 @@  xfs_attrmulti_by_handle(
 int
 xfs_ioc_space(
 	struct file		*filp,
-	unsigned int		cmd,
 	xfs_flock64_t		*bf)
 {
 	struct inode		*inode = file_inode(filp);
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct iattr		iattr;
-	enum xfs_prealloc_flags	flags = 0;
+	enum xfs_prealloc_flags	flags = XFS_PREALLOC_CLEAR;
 	uint			iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
 	int			error;
 
@@ -635,65 +634,21 @@  xfs_ioc_space(
 		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_UNRESVSP:
-	case XFS_IOC_UNRESVSP64:
-		if (bf->l_len <= 0) {
-			error = -EINVAL;
-			goto out_unlock;
-		}
-		break;
-	default:
-		bf->l_len = 0;
-		break;
-	}
-
-	if (bf->l_start < 0 ||
-	    bf->l_start > inode->i_sb->s_maxbytes ||
-	    bf->l_start + bf->l_len < 0 ||
-	    bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) {
+	if (bf->l_start < 0 || bf->l_start > inode->i_sb->s_maxbytes) {
 		error = -EINVAL;
 		goto out_unlock;
 	}
 
-	switch (cmd) {
-	case XFS_IOC_ZERO_RANGE:
-		flags |= XFS_PREALLOC_SET;
-		error = xfs_zero_file_space(ip, bf->l_start, bf->l_len);
-		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:
-		flags |= XFS_PREALLOC_CLEAR;
-		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_vn_setattr_size(file_dentry(filp), &iattr);
-		break;
-	default:
-		ASSERT(0);
-		error = -EINVAL;
+	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_vn_setattr_size(file_dentry(filp), &iattr);
 	if (error)
 		goto out_unlock;
 
@@ -2113,16 +2068,13 @@  xfs_file_ioctl(
 		return xfs_ioc_setlabel(filp, mp, arg);
 	case XFS_IOC_ALLOCSP:
 	case XFS_IOC_FREESP:
-	case XFS_IOC_UNRESVSP:
 	case XFS_IOC_ALLOCSP64:
-	case XFS_IOC_FREESP64:
-	case XFS_IOC_UNRESVSP64:
-	case XFS_IOC_ZERO_RANGE: {
+	case XFS_IOC_FREESP64: {
 		xfs_flock64_t		bf;
 
 		if (copy_from_user(&bf, arg, sizeof(bf)))
 			return -EFAULT;
-		return xfs_ioc_space(filp, cmd, &bf);
+		return xfs_ioc_space(filp, &bf);
 	}
 	case XFS_IOC_DIOINFO: {
 		struct dioattr		da;
diff --git a/fs/xfs/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h
index 654c0bb1bcf8..25ef178cbb74 100644
--- a/fs/xfs/xfs_ioctl.h
+++ b/fs/xfs/xfs_ioctl.h
@@ -9,7 +9,6 @@ 
 extern int
 xfs_ioc_space(
 	struct file		*filp,
-	unsigned int		cmd,
 	xfs_flock64_t		*bf);
 
 int
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index 257b7caf7fed..3c0d518e1039 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -557,16 +557,13 @@  xfs_file_compat_ioctl(
 	case XFS_IOC_ALLOCSP_32:
 	case XFS_IOC_FREESP_32:
 	case XFS_IOC_ALLOCSP64_32:
-	case XFS_IOC_FREESP64_32:
-	case XFS_IOC_RESVSP64_32:
-	case XFS_IOC_UNRESVSP64_32:
-	case XFS_IOC_ZERO_RANGE_32: {
+	case XFS_IOC_FREESP64_32: {
 		struct xfs_flock64	bf;
 
 		if (xfs_compat_flock64_copyin(&bf, arg))
 			return -EFAULT;
 		cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
-		return xfs_ioc_space(filp, cmd, &bf);
+		return xfs_ioc_space(filp, &bf);
 	}
 	case XFS_IOC_FSGEOMETRY_V1_32:
 		return xfs_compat_ioc_fsgeometry_v1(mp, arg);
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
index 674d59f4d6ce..f5c73f0ec22d 100644
--- a/include/linux/falloc.h
+++ b/include/linux/falloc.h
@@ -20,7 +20,10 @@  struct space_resv {
 };
 
 #define FS_IOC_RESVSP		_IOW('X', 40, struct space_resv)
+#define FS_IOC_UNRESVSP		_IOW('X', 41, struct space_resv)
 #define FS_IOC_RESVSP64		_IOW('X', 42, struct space_resv)
+#define FS_IOC_UNRESVSP64	_IOW('X', 43, struct space_resv)
+#define FS_IOC_ZERO_RANGE	_IOW('X', 57, struct space_resv)
 
 #define	FALLOC_FL_SUPPORTED_MASK	(FALLOC_FL_KEEP_SIZE |		\
 					 FALLOC_FL_PUNCH_HOLE |		\
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e0d909d35763..2b5692207c1d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2547,7 +2547,7 @@  extern int finish_no_open(struct file *file, struct dentry *dentry);
 
 /* fs/ioctl.c */
 
-extern int ioctl_preallocate(struct file *filp, void __user *argp);
+extern int ioctl_preallocate(struct file *filp, int mode, void __user *argp);
 
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);