Whamcloud - gitweb
e2fsprogs: Add discard function into struct_io_manager
authorLukas Czerner <lczerner@redhat.com>
Thu, 18 Nov 2010 03:38:36 +0000 (03:38 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 23 Nov 2010 01:41:00 +0000 (20:41 -0500)
In order to provide generic "discard" function for all e2fsprogs tools
add a discard function prototype into struct_io_manager. Specific
function for specific io managers can be crated that way.

This commit also creates unix_discard function which uses BLKDISCARD
ioctl to discard data blocks on the block device and bind it into
unit_io_manager structure to be available for all e2fsprogs tools.
Note that BLKDISCARD is still Linux specific ioctl, however other
unix systems may provide similar functionality. So far the
unix_discard() remains linux specific hence is embedded in #ifdef
__linux__ macro.

Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/ext2_io.h
lib/ext2fs/io_manager.c
lib/ext2fs/test_io.c
lib/ext2fs/unix_io.c

index ccc9c8b..f26b569 100644 (file)
@@ -83,6 +83,8 @@ struct struct_io_manager {
                                        int count, void *data);
        errcode_t (*write_blk64)(io_channel channel, unsigned long long block,
                                        int count, const void *data);
+       errcode_t (*discard)(io_channel channel, unsigned long long block,
+                            unsigned long long count);
        long    reserved[16];
 };
 
index 6d0e234..80f9dfc 100644 (file)
@@ -99,3 +99,14 @@ errcode_t io_channel_write_blk64(io_channel channel, unsigned long long block,
        return (channel->manager->write_blk)(channel, (unsigned long) block,
                                             count, data);
 }
+
+errcode_t io_channel_discard(io_channel channel, unsigned long long block,
+                            unsigned long long count)
+{
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+       if (channel->manager->discard)
+               return (channel->manager->discard)(channel, block, count);
+
+       return EXT2_ET_UNIMPLEMENTED;
+}
index 8d887a8..242d442 100644 (file)
@@ -73,7 +73,8 @@ static errcode_t test_write_byte(io_channel channel, unsigned long offset,
 static errcode_t test_set_option(io_channel channel, const char *option,
                                 const char *arg);
 static errcode_t test_get_stats(io_channel channel, io_stats *stats);
-
+static errcode_t test_discard(io_channel channel, unsigned long long block,
+                             unsigned long long count);
 
 static struct struct_io_manager struct_test_manager = {
        EXT2_ET_MAGIC_IO_MANAGER,
@@ -89,6 +90,7 @@ static struct struct_io_manager struct_test_manager = {
        test_get_stats,
        test_read_blk64,
        test_write_blk64,
+       test_discard,
 };
 
 io_manager test_io_manager = &struct_test_manager;
@@ -120,6 +122,7 @@ void (*test_io_cb_write_byte)
 #define TEST_FLAG_FLUSH                        0x08
 #define TEST_FLAG_DUMP                 0x10
 #define TEST_FLAG_SET_OPTION           0x20
+#define TEST_FLAG_DISCARD              0x40
 
 static void test_dump_block(io_channel channel,
                            struct test_private_data *data,
@@ -495,3 +498,21 @@ static errcode_t test_get_stats(io_channel channel, io_stats *stats)
        }
        return retval;
 }
+
+static errcode_t test_discard(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);
+
+       retval = io_channel_discard(channel, block, count);
+       if (data->flags & TEST_FLAG_DISCARD)
+               fprintf(data->outfile,
+                       "Test_io: discard(%llu, %llu) returned %s\n",
+                       block, count, retval ? error_message(retval) : "OK");
+       return retval;
+}
index 1df1fdd..2302374 100644 (file)
@@ -115,6 +115,8 @@ static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
                               int count, void *data);
 static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
                                int count, const void *data);
+static errcode_t unix_discard(io_channel channel, unsigned long long block,
+                             unsigned long long count);
 
 static struct struct_io_manager struct_unix_manager = {
        EXT2_ET_MAGIC_IO_MANAGER,
@@ -130,6 +132,7 @@ static struct struct_io_manager struct_unix_manager = {
        unix_get_stats,
        unix_read_blk64,
        unix_write_blk64,
+       unix_discard,
 };
 
 io_manager unix_io_manager = &struct_unix_manager;
@@ -834,3 +837,31 @@ static errcode_t unix_set_option(io_channel channel, const char *option,
        }
        return EXT2_ET_INVALID_ARGUMENT;
 }
+
+#if defined(__linux__) && !defined(BLKDISCARD)
+#define BLKDISCARD     _IO(0x12,119)
+#endif
+
+static errcode_t unix_discard(io_channel channel, unsigned long long block,
+                             unsigned long long count)
+{
+#ifdef BLKDISCARD
+       struct unix_private_data *data;
+       __uint64_t      range[2];
+       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);
+
+       range[0] = (__uint64_t)(block) * channel->block_size;
+       range[1] = (__uint64_t)(count) * channel->block_size;
+
+       ret = ioctl(data->dev, BLKDISCARD, &range);
+       if (ret < 0)
+               return errno;
+       return 0;
+#else
+       return EXT2_ET_UNIMPLEMENTED;
+#endif
+}