浏览代码

xfs: Introduce XFS_IOC_ZERO_RANGE

XFS_IOC_ZERO_RANGE is the equivalent of an atomic XFS_IOC_UNRESVSP/
XFS_IOC_RESVSP call pair. It enabled ranges of written data to be
turned into zeroes without requiring IO or having to free and
reallocate the extents in the range given as would occur if we had
to punch and then preallocate them separately.  This enables
applications to zero parts of files very quickly without changing
the layout of the files in any way.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Dave Chinner 14 年之前
父节点
当前提交
4472235205
共有 6 个文件被更改,包括 27 次插入9 次删除
  1. 2 1
      fs/xfs/linux-2.6/xfs_ioctl.c
  2. 1 0
      fs/xfs/linux-2.6/xfs_ioctl32.c
  3. 9 3
      fs/xfs/xfs_bmap.c
  4. 6 3
      fs/xfs/xfs_bmap.h
  5. 1 0
      fs/xfs/xfs_fs.h
  6. 8 2
      fs/xfs/xfs_vnodeops.c

+ 2 - 1
fs/xfs/linux-2.6/xfs_ioctl.c

@@ -1301,7 +1301,8 @@ xfs_file_ioctl(
 	case XFS_IOC_ALLOCSP64:
 	case XFS_IOC_ALLOCSP64:
 	case XFS_IOC_FREESP64:
 	case XFS_IOC_FREESP64:
 	case XFS_IOC_RESVSP64:
 	case XFS_IOC_RESVSP64:
-	case XFS_IOC_UNRESVSP64: {
+	case XFS_IOC_UNRESVSP64:
+	case XFS_IOC_ZERO_RANGE: {
 		xfs_flock64_t		bf;
 		xfs_flock64_t		bf;
 
 
 		if (copy_from_user(&bf, arg, sizeof(bf)))
 		if (copy_from_user(&bf, arg, sizeof(bf)))

+ 1 - 0
fs/xfs/linux-2.6/xfs_ioctl32.c

@@ -574,6 +574,7 @@ xfs_file_compat_ioctl(
 	case XFS_IOC_FSGEOMETRY_V1:
 	case XFS_IOC_FSGEOMETRY_V1:
 	case XFS_IOC_FSGROWFSDATA:
 	case XFS_IOC_FSGROWFSDATA:
 	case XFS_IOC_FSGROWFSRT:
 	case XFS_IOC_FSGROWFSRT:
+	case XFS_IOC_ZERO_RANGE:
 		return xfs_file_ioctl(filp, cmd, p);
 		return xfs_file_ioctl(filp, cmd, p);
 #else
 #else
 	case XFS_IOC_ALLOCSP_32:
 	case XFS_IOC_ALLOCSP_32:

+ 9 - 3
fs/xfs/xfs_bmap.c

@@ -4744,8 +4744,12 @@ xfs_bmapi(
 		 * Check if writing previously allocated but
 		 * Check if writing previously allocated but
 		 * unwritten extents.
 		 * unwritten extents.
 		 */
 		 */
-		if (wr && mval->br_state == XFS_EXT_UNWRITTEN &&
-		    ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) {
+		if (wr &&
+		    ((mval->br_state == XFS_EXT_UNWRITTEN &&
+		      ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) ||
+		     (mval->br_state == XFS_EXT_NORM &&
+		      ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT)) ==
+				(XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT))))) {
 			/*
 			/*
 			 * Modify (by adding) the state flag, if writing.
 			 * Modify (by adding) the state flag, if writing.
 			 */
 			 */
@@ -4757,7 +4761,9 @@ xfs_bmapi(
 					*firstblock;
 					*firstblock;
 				cur->bc_private.b.flist = flist;
 				cur->bc_private.b.flist = flist;
 			}
 			}
-			mval->br_state = XFS_EXT_NORM;
+			mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
+						? XFS_EXT_NORM
+						: XFS_EXT_UNWRITTEN;
 			error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
 			error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
 				firstblock, flist, &tmp_logflags,
 				firstblock, flist, &tmp_logflags,
 				whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
 				whichfork, (flags & XFS_BMAPI_RSVBLOCKS));

+ 6 - 3
fs/xfs/xfs_bmap.h

@@ -74,9 +74,12 @@ typedef	struct xfs_bmap_free
 #define	XFS_BMAPI_IGSTATE	0x080	/* Ignore state - */
 #define	XFS_BMAPI_IGSTATE	0x080	/* Ignore state - */
 					/* combine contig. space */
 					/* combine contig. space */
 #define	XFS_BMAPI_CONTIG	0x100	/* must allocate only one extent */
 #define	XFS_BMAPI_CONTIG	0x100	/* must allocate only one extent */
-#define XFS_BMAPI_CONVERT	0x200	/* unwritten extent conversion - */
-					/* need write cache flushing and no */
-					/* additional allocation alignments */
+/*
+ * unwritten extent conversion - this needs write cache flushing and no additional
+ * allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts
+ * from written to unwritten, otherwise convert from unwritten to written.
+ */
+#define XFS_BMAPI_CONVERT	0x200
 
 
 #define XFS_BMAPI_FLAGS \
 #define XFS_BMAPI_FLAGS \
 	{ XFS_BMAPI_WRITE,	"WRITE" }, \
 	{ XFS_BMAPI_WRITE,	"WRITE" }, \

+ 1 - 0
fs/xfs/xfs_fs.h

@@ -448,6 +448,7 @@ typedef struct xfs_handle {
 /*	XFS_IOC_SETBIOSIZE ---- deprecated 46	   */
 /*	XFS_IOC_SETBIOSIZE ---- deprecated 46	   */
 /*	XFS_IOC_GETBIOSIZE ---- deprecated 47	   */
 /*	XFS_IOC_GETBIOSIZE ---- deprecated 47	   */
 #define XFS_IOC_GETBMAPX	_IOWR('X', 56, struct getbmap)
 #define XFS_IOC_GETBMAPX	_IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
 
 
 /*
 /*
  * ioctl commands that replace IRIX syssgi()'s
  * ioctl commands that replace IRIX syssgi()'s

+ 8 - 2
fs/xfs/xfs_vnodeops.c

@@ -2272,7 +2272,7 @@ xfs_alloc_file_space(
 	count = len;
 	count = len;
 	imapp = &imaps[0];
 	imapp = &imaps[0];
 	nimaps = 1;
 	nimaps = 1;
-	bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
+	bmapi_flag = XFS_BMAPI_WRITE | alloc_type;
 	startoffset_fsb	= XFS_B_TO_FSBT(mp, offset);
 	startoffset_fsb	= XFS_B_TO_FSBT(mp, offset);
 	allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 	allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 
 
@@ -2711,6 +2711,7 @@ xfs_change_file_space(
 	xfs_off_t	llen;
 	xfs_off_t	llen;
 	xfs_trans_t	*tp;
 	xfs_trans_t	*tp;
 	struct iattr	iattr;
 	struct iattr	iattr;
+	int		prealloc_type;
 
 
 	if (!S_ISREG(ip->i_d.di_mode))
 	if (!S_ISREG(ip->i_d.di_mode))
 		return XFS_ERROR(EINVAL);
 		return XFS_ERROR(EINVAL);
@@ -2753,12 +2754,17 @@ xfs_change_file_space(
 	 * size to be changed.
 	 * size to be changed.
 	 */
 	 */
 	setprealloc = clrprealloc = 0;
 	setprealloc = clrprealloc = 0;
+	prealloc_type = XFS_BMAPI_PREALLOC;
 
 
 	switch (cmd) {
 	switch (cmd) {
+	case XFS_IOC_ZERO_RANGE:
+		prealloc_type |= XFS_BMAPI_CONVERT;
+		xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0);
+		/* FALLTHRU */
 	case XFS_IOC_RESVSP:
 	case XFS_IOC_RESVSP:
 	case XFS_IOC_RESVSP64:
 	case XFS_IOC_RESVSP64:
 		error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
 		error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
-								1, attr_flags);
+						prealloc_type, attr_flags);
 		if (error)
 		if (error)
 			return error;
 			return error;
 		setprealloc = 1;
 		setprealloc = 1;