]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
libext2fs: zero blocks via FALLOC_FL_ZERO_RANGE in ext2fs_zero_blocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Sun, 29 Mar 2015 03:01:08 +0000 (23:01 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 29 Mar 2015 03:08:25 +0000 (23:08 -0400)
Plumb a new call into the IO manager to support translating
ext2fs_zero_blocks calls into the equivalent FALLOC_FL_ZERO_RANGE
fallocate flag primitive when possible.  This patch provides _only_
support for file-based images.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/ext2_io.h
lib/ext2fs/io_manager.c
lib/ext2fs/mkjournal.c
lib/ext2fs/test_io.c
lib/ext2fs/unix_io.c

index 4c5a5c5eac570839132d32221662855d90f06d1d..1faa720aa4f43e7f01ddd9d679739ec78b4f6405 100644 (file)
@@ -93,7 +93,9 @@ struct struct_io_manager {
        errcode_t (*cache_readahead)(io_channel channel,
                                     unsigned long long block,
                                     unsigned long long count);
-       long    reserved[15];
+       errcode_t (*zeroout)(io_channel channel, unsigned long long block,
+                            unsigned long long count);
+       long    reserved[14];
 };
 
 #define IO_FLAG_RW             0x0001
@@ -125,6 +127,9 @@ extern errcode_t io_channel_write_blk64(io_channel channel,
 extern errcode_t io_channel_discard(io_channel channel,
                                    unsigned long long block,
                                    unsigned long long count);
+extern errcode_t io_channel_zeroout(io_channel channel,
+                                   unsigned long long block,
+                                   unsigned long long count);
 extern errcode_t io_channel_alloc_buf(io_channel channel,
                                      int count, void *ptr);
 extern errcode_t io_channel_cache_readahead(io_channel io,
index dc5888dba5172ed3ffd35a5a125f88b3f40d5bf1..c395d615fa7d0a3ff254cfbd47c89d9b7a0792c5 100644 (file)
@@ -112,6 +112,17 @@ errcode_t io_channel_discard(io_channel channel, unsigned long long block,
        return EXT2_ET_UNIMPLEMENTED;
 }
 
+errcode_t io_channel_zeroout(io_channel channel, unsigned long long block,
+                            unsigned long long count)
+{
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+       if (channel->manager->zeroout)
+               return (channel->manager->zeroout)(channel, block, count);
+
+       return EXT2_ET_UNIMPLEMENTED;
+}
+
 errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr)
 {
        size_t  size;
index fcc6741ff12e0ea41ff9c3fe250a7cc2893b6f72..c42cb98d37701ce89bfb5a77c5a50fb0b6d9809e 100644 (file)
@@ -170,6 +170,11 @@ errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
        if (num <= 0)
                return 0;
 
+       /* Try a zero out command, if supported */
+       retval = io_channel_zeroout(fs->io, blk, num);
+       if (retval == 0)
+               return 0;
+
        /* Allocate the zeroizing buffer if necessary */
        if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) {
                void *p;
index b03a9395b5cfd2df8304cb19de637258d8a123c4..f7c50d1be5a88e6e6d68bb0bae12e7f689439e50 100644 (file)
@@ -86,6 +86,7 @@ void (*test_io_cb_write_byte)
 #define TEST_FLAG_SET_OPTION           0x20
 #define TEST_FLAG_DISCARD              0x40
 #define TEST_FLAG_READAHEAD            0x80
+#define TEST_FLAG_ZEROOUT              0x100
 
 static void test_dump_block(io_channel channel,
                            struct test_private_data *data,
@@ -507,6 +508,25 @@ static errcode_t test_cache_readahead(io_channel channel,
        return retval;
 }
 
+static errcode_t test_zeroout(io_channel channel, unsigned long long block,
+                             unsigned long long count)
+{
+       struct test_private_data *data;
+       errcode_t       retval = 0;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+       data = (struct test_private_data *) channel->private_data;
+       EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+       if (data->real)
+               retval = io_channel_zeroout(data->real, block, count);
+       if (data->flags & TEST_FLAG_ZEROOUT)
+               fprintf(data->outfile,
+                       "Test_io: zeroout(%llu, %llu) returned %s\n",
+                       block, count, retval ? error_message(retval) : "OK");
+       return retval;
+}
+
 static struct struct_io_manager struct_test_manager = {
        .magic          = EXT2_ET_MAGIC_IO_MANAGER,
        .name           = "Test I/O Manager",
@@ -523,6 +543,7 @@ static struct struct_io_manager struct_test_manager = {
        .write_blk64    = test_write_blk64,
        .discard        = test_discard,
        .cache_readahead        = test_cache_readahead,
+       .zeroout        = test_zeroout,
 };
 
 io_manager test_io_manager = &struct_test_manager;
index c3a8ea5f9f9ca5281b58b92593bc33bb3699174f..3fce5c0142c27ad3ab1dc5abfb50b069cdf59e64 100644 (file)
@@ -987,6 +987,72 @@ unimplemented:
        return EXT2_ET_UNIMPLEMENTED;
 }
 
+static errcode_t unix_zeroout(io_channel channel, unsigned long long block,
+                             unsigned long long count)
+{
+       struct unix_private_data *data;
+       int             ret;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+       data = (struct unix_private_data *) channel->private_data;
+       EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+       if (getenv("UNIX_IO_NOZEROOUT"))
+               goto unimplemented;
+
+       if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
+               /* Not implemented until the BLKZEROOUT mess is fixed */
+               goto unimplemented;
+       } else {
+               /* Regular file, try to use truncate/punch/zero. */
+#if defined(HAVE_FALLOCATE) && (defined(FALLOC_FL_ZERO_RANGE) || \
+       (defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)))
+               struct stat statbuf;
+
+               if (count == 0)
+                       return 0;
+               /*
+                * If we're trying to zero a range past the end of the file,
+                * extend the file size, then punch (or zero_range) everything.
+                */
+               ret = fstat(data->dev, &statbuf);
+               if (ret)
+                       goto err;
+               if (statbuf.st_size < (block + count) * channel->block_size) {
+                       ret = ftruncate(data->dev,
+                                       (block + count) * channel->block_size);
+                       if (ret)
+                               goto err;
+               }
+#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
+               ret = fallocate(data->dev,
+                               FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+                               (off_t)(block) * channel->block_size,
+                               (off_t)(count) * channel->block_size);
+               if (ret == 0)
+                       goto err;
+#endif
+#ifdef FALLOC_FL_ZERO_RANGE
+               ret = fallocate(data->dev,
+                               FALLOC_FL_ZERO_RANGE,
+                               (off_t)(block) * channel->block_size,
+                               (off_t)(count) * channel->block_size);
+#endif
+#else
+               goto unimplemented;
+#endif /* HAVE_FALLOCATE && (ZERO_RANGE || (PUNCH_HOLE && KEEP_SIZE)) */
+       }
+err:
+       if (ret < 0) {
+               if (errno == EOPNOTSUPP)
+                       goto unimplemented;
+               return errno;
+       }
+       return 0;
+unimplemented:
+       return EXT2_ET_UNIMPLEMENTED;
+}
+
 static struct struct_io_manager struct_unix_manager = {
        .magic          = EXT2_ET_MAGIC_IO_MANAGER,
        .name           = "Unix I/O Manager",
@@ -1003,6 +1069,7 @@ static struct struct_io_manager struct_unix_manager = {
        .write_blk64    = unix_write_blk64,
        .discard        = unix_discard,
        .cache_readahead        = unix_cache_readahead,
+       .zeroout        = unix_zeroout,
 };
 
 io_manager unix_io_manager = &struct_unix_manager;