xfs: Introduce XFS_IOC_ZERO_RANGE
authorDave Chinner <dchinner@redhat.com>
Tue, 24 Aug 2010 02:02:11 +0000 (12:02 +1000)
committerAlex Elder <aelder@sgi.com>
Mon, 18 Oct 2010 20:07:25 +0000 (15:07 -0500)
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>
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_ioctl32.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_fs.h
fs/xfs/xfs_vnodeops.c

index 3b9e626f7cd1562877cc340d0c43c5a776dd2e35..03aa908a9cb9eeed8241c5e30f5182b3284616c0 100644 (file)
@@ -1301,7 +1301,8 @@ xfs_file_ioctl(
        case XFS_IOC_ALLOCSP64:
        case XFS_IOC_FREESP64:
        case XFS_IOC_RESVSP64:
-       case XFS_IOC_UNRESVSP64: {
+       case XFS_IOC_UNRESVSP64:
+       case XFS_IOC_ZERO_RANGE: {
                xfs_flock64_t           bf;
 
                if (copy_from_user(&bf, arg, sizeof(bf)))
index 6c83f7f62dc99ca29d5597aad61c97b432ec19ed..464bcc76e980c24290b2b361189be17cadcd8dae 100644 (file)
@@ -574,6 +574,7 @@ xfs_file_compat_ioctl(
        case XFS_IOC_FSGEOMETRY_V1:
        case XFS_IOC_FSGROWFSDATA:
        case XFS_IOC_FSGROWFSRT:
+       case XFS_IOC_ZERO_RANGE:
                return xfs_file_ioctl(filp, cmd, p);
 #else
        case XFS_IOC_ALLOCSP_32:
index f90dadd5a96877ff9975ecaaf2fb260863f7d089..5e33b7862d419989e3997433e2070d8ef6db8d86 100644 (file)
@@ -4744,8 +4744,12 @@ xfs_bmapi(
                 * Check if writing previously allocated but
                 * 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.
                         */
@@ -4757,7 +4761,9 @@ xfs_bmapi(
                                        *firstblock;
                                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,
                                firstblock, flist, &tmp_logflags,
                                whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
index b13569a6179b7235f315fe87f624e42336310c9e..71ec9b6ecdfcbb15e65d7857681cd3f9126cc9b1 100644 (file)
@@ -74,9 +74,12 @@ typedef      struct xfs_bmap_free
 #define        XFS_BMAPI_IGSTATE       0x080   /* Ignore state - */
                                        /* combine contig. space */
 #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 \
        { XFS_BMAPI_WRITE,      "WRITE" }, \
index 87c2e9d02288d6ff0eba2949d379e1d02546eb11..10f6093671b04cf78e009f0915f12bbccac90c7e 100644 (file)
@@ -448,6 +448,7 @@ typedef struct xfs_handle {
 /*     XFS_IOC_SETBIOSIZE ---- deprecated 46      */
 /*     XFS_IOC_GETBIOSIZE ---- deprecated 47      */
 #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
index 4c7c7bfb2b2fc0aa8cc3cb3c98334392eb902c00..dc6e4fb8bbc9a7902b4a38097bfc6dde17d098dc 100644 (file)
@@ -2272,7 +2272,7 @@ xfs_alloc_file_space(
        count = len;
        imapp = &imaps[0];
        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);
        allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 
@@ -2711,6 +2711,7 @@ xfs_change_file_space(
        xfs_off_t       llen;
        xfs_trans_t     *tp;
        struct iattr    iattr;
+       int             prealloc_type;
 
        if (!S_ISREG(ip->i_d.di_mode))
                return XFS_ERROR(EINVAL);
@@ -2753,12 +2754,17 @@ xfs_change_file_space(
         * size to be changed.
         */
        setprealloc = clrprealloc = 0;
+       prealloc_type = XFS_BMAPI_PREALLOC;
 
        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_RESVSP64:
                error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
-                                                               1, attr_flags);
+                                               prealloc_type, attr_flags);
                if (error)
                        return error;
                setprealloc = 1;