]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: open io-channel when copying fs
authorLi Xi <lixi@ddn.com>
Sat, 10 Aug 2019 07:59:09 +0000 (15:59 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 25 Jan 2021 20:16:38 +0000 (15:16 -0500)
This patch also add writethrough flag to the thread io-channel.
When multiple threads write the same disk, we don't want the
data being saved in memory cache. This will be useful in the
future, but even without that flag, the tests can be passed too.

This patch also cleanup the io channel cache of the global
context. Otherwise, after pass1 step, the next steps would use
old data saved in the cache. And the cached data might have
already been overwritten in pass1.

Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Signed-off-by: Saranya Muruganandam <saranyamohan@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/unix.c
lib/ext2fs/ext2_io.h
lib/ext2fs/ext2fs.h
lib/ext2fs/openfs.c
lib/ext2fs/undo_io.c
lib/ext2fs/unix_io.c

index e2784248c67663141469b4a4a1d14817ffd8d34a..1416f15eafcb471478311f5ff50df11147a4236c 100644 (file)
@@ -228,6 +228,8 @@ typedef struct e2fsck_struct *e2fsck_t;
 #define MAX_EXTENT_DEPTH_COUNT 5
 
 struct e2fsck_struct {
+       /* Global context to get the cancel flag */
+       e2fsck_t                global_ctx;
        ext2_filsys fs;
        const char *program_name;
        char *filesystem_name;
@@ -247,6 +249,7 @@ struct e2fsck_struct {
        ext2_ino_t free_inodes;
        int     mount_flags;
        int     openfs_flags;
+       io_manager io_manager;
        blkid_cache blkid;      /* blkid cache */
 
 #ifdef HAVE_SETJMP_H
index 14508dd825da1e67f435438bc388b3445bf90992..10efa0ed6100a5afa03e9dc75556593e3afadcf5 100644 (file)
@@ -2103,7 +2103,9 @@ static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap
        return 0;
 }
 
-static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, ext2_filsys src)
+
+static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
+                                     ext2_filsys src)
 {
        errcode_t       retval;
 
@@ -2129,6 +2131,33 @@ static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, ext2_filsys src)
                        return retval;
        }
 
+       /* disable it for now */
+       src_context->openfs_flags &= ~EXT2_FLAG_EXCLUSIVE;
+       retval = ext2fs_open_channel(dest, src_context->io_options,
+                                    src_context->io_manager,
+                                    src_context->openfs_flags,
+                                    src->io->block_size);
+       if (retval)
+               return retval;
+
+       /* Block size might not be default */
+       io_channel_set_blksize(dest->io, src->io->block_size);
+       ehandler_init(dest->io);
+
+       assert(dest->io->magic == src->io->magic);
+       assert(dest->io->manager == src->io->manager);
+       assert(strcmp(dest->io->name, src->io->name) == 0);
+       assert(dest->io->block_size == src->io->block_size);
+       assert(dest->io->read_error == src->io->read_error);
+       assert(dest->io->write_error == src->io->write_error);
+       assert(dest->io->refcount == src->io->refcount);
+       assert(dest->io->flags == src->io->flags);
+       assert(dest->io->app_data == dest);
+       assert(src->io->app_data == src);
+       assert(dest->io->align == src->io->align);
+
+       /* The data should be written to disk immediately */
+       dest->io->flags |= CHANNEL_FLAGS_WRITETHROUGH;
        /* icache will be rebuilt if needed, so do not copy from @src */
        src->icache = NULL;
        return 0;
@@ -2137,9 +2166,17 @@ static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, ext2_filsys src)
 static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
 {
        struct ext2_inode_cache *icache = dest->icache;
-       errcode_t       retval = 0;
+       errcode_t retval = 0;
+       io_channel dest_io;
+       io_channel dest_image_io;
+
+       dest_io = dest->io;
+       dest_image_io = dest->image_io;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
+       dest->io = dest_io;
+       dest->image_io = dest_image_io;
+       dest->icache = icache;
        if (dest->dblist)
                dest->dblist->fs = dest;
        if (src->inode_map) {
@@ -2154,7 +2191,6 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
                if (retval)
                        return retval;
        }
-       dest->icache = icache;
 
        if (src->icache) {
                ext2fs_free_inode_cache(src->icache);
@@ -2168,6 +2204,7 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
                src->badblocks = NULL;
        }
 
+       io_channel_close(src->io);
        return retval;
 }
 
@@ -2205,7 +2242,8 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre
                goto out_context;
        }
 
-       retval = e2fsck_pass1_copy_fs(thread_fs, global_fs);
+       io_channel_flush_cleanup(global_fs->io);
+       retval = e2fsck_pass1_copy_fs(thread_fs, global_ctx, global_fs);
        if (retval) {
                com_err(global_ctx->program_name, retval, "while copying fs");
                goto out_fs;
index 4098e26a1e53f66f60783882c2c07e93ec51b748..1d68f3186ce329622ea3a065613cf339ec9c66b1 100644 (file)
@@ -1526,6 +1526,7 @@ restart:
        }
 
        ctx->openfs_flags = flags;
+       ctx->io_manager = io_ptr;
        retval = try_open_fs(ctx, flags, io_ptr, &fs);
 
        if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
index 95c25a7b1cc1ad147e25a7e34d3ab04c77d85d86..a5d82f816e8a0c9542e9f11bc9afe5b5e766c3a4 100644 (file)
@@ -82,6 +82,7 @@ struct struct_io_manager {
        errcode_t (*write_blk)(io_channel channel, unsigned long block,
                               int count, const void *data);
        errcode_t (*flush)(io_channel channel);
+       errcode_t (*flush_cleanup)(io_channel channel);
        errcode_t (*write_byte)(io_channel channel, unsigned long offset,
                                int count, const void *data);
        errcode_t (*set_option)(io_channel channel, const char *option,
@@ -116,6 +117,7 @@ struct struct_io_manager {
 #define io_channel_read_blk(c,b,n,d)   ((c)->manager->read_blk((c),b,n,d))
 #define io_channel_write_blk(c,b,n,d)  ((c)->manager->write_blk((c),b,n,d))
 #define io_channel_flush(c)            ((c)->manager->flush((c)))
+#define io_channel_flush_cleanup(c)    ((c)->manager->flush_cleanup((c)))
 #define io_channel_bumpcount(c)                ((c)->refcount++)
 
 /* io_manager.c */
index 7218fde93ddccbb6df018f9832d4ec009971759f..1f60652f1445bde44e74a10898f0d620ab47df68 100644 (file)
@@ -1671,6 +1671,9 @@ extern errcode_t ext2fs_open2(const char *name, const char *io_options,
                              int flags, int superblock,
                              unsigned int block_size, io_manager manager,
                              ext2_filsys *ret_fs);
+errcode_t ext2fs_open_channel(ext2_filsys fs, const char *io_options,
+                             io_manager manager, int flags,
+                             int blocksize);
 /*
  * The dgrp_t argument to these two functions is not actually a group number
  * but a block number offset within a group table!  Convert with the formula
index 5ec8ed5c1bb10f3443d71b1b4723c16e45c17053..b08eaa3b7f86325cd2124ef12d8fadefeaf73920 100644 (file)
@@ -99,6 +99,40 @@ static void block_sha_map_free_entry(void *data)
        return;
 }
 
+errcode_t ext2fs_open_channel(ext2_filsys fs, const char *io_options,
+                             io_manager manager, int flags,
+                             int blocksize)
+{
+       errcode_t       retval;
+       unsigned int    io_flags = 0;
+
+       if (flags & EXT2_FLAG_RW)
+               io_flags |= IO_FLAG_RW;
+       if (flags & EXT2_FLAG_EXCLUSIVE)
+               io_flags |= IO_FLAG_EXCLUSIVE;
+       if (flags & EXT2_FLAG_DIRECT_IO)
+               io_flags |= IO_FLAG_DIRECT_IO;
+       if (flags & EXT2_FLAG_THREADS)
+               io_flags |= IO_FLAG_THREADS;
+       retval = manager->open(fs->device_name, io_flags, &fs->io);
+       if (retval)
+               return retval;
+
+       if (io_options &&
+           (retval = io_channel_set_options(fs->io, io_options)))
+               goto out_close;
+       fs->image_io = fs->io;
+       fs->io->app_data = fs;
+
+       if (blocksize > 0)
+               io_channel_set_blksize(fs->io, blocksize);
+
+       return 0;
+out_close:
+       io_channel_close(fs->io);
+       return retval;
+}
+
 /*
  *  Note: if superblock is non-zero, block-size must also be non-zero.
  *     Superblock and block_size can be zero to use the default size.
@@ -122,7 +156,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
        errcode_t       retval;
        unsigned long   i, first_meta_bg;
        __u32           features;
-       unsigned int    blocks_per_group, io_flags;
+       unsigned int    blocks_per_group;
        blk64_t         group_block, blk;
        char            *dest, *cp;
        int             group_zero_adjust = 0;
@@ -163,23 +197,9 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                io_options = cp;
        }
 
-       io_flags = 0;
-       if (flags & EXT2_FLAG_RW)
-               io_flags |= IO_FLAG_RW;
-       if (flags & EXT2_FLAG_EXCLUSIVE)
-               io_flags |= IO_FLAG_EXCLUSIVE;
-       if (flags & EXT2_FLAG_DIRECT_IO)
-               io_flags |= IO_FLAG_DIRECT_IO;
-       if (flags & EXT2_FLAG_THREADS)
-               io_flags |= IO_FLAG_THREADS;
-       retval = manager->open(fs->device_name, io_flags, &fs->io);
+       retval = ext2fs_open_channel(fs, io_options, manager, flags, 0);
        if (retval)
                goto cleanup;
-       if (io_options &&
-           (retval = io_channel_set_options(fs->io, io_options)))
-               goto cleanup;
-       fs->image_io = fs->io;
-       fs->io->app_data = fs;
        retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
        if (retval)
                goto cleanup;
index eb56f53d5d3b5680bcc3544be2b7e1a020eaa462..267fa38f36cfd660aa111eee6b0ad6ac6ff53552 100644 (file)
@@ -1022,6 +1022,24 @@ static errcode_t undo_flush(io_channel channel)
        return retval;
 }
 
+/*
+ * Flush data buffers to disk and cleanup the cache.
+ */
+static errcode_t undo_flush_cleanup(io_channel channel)
+{
+       errcode_t       retval = 0;
+       struct undo_private_data *data;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+       data = (struct undo_private_data *) channel->private_data;
+       EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+       if (data->real)
+               retval = io_channel_flush_cleanup(data->real);
+
+       return retval;
+}
+
 static errcode_t undo_set_option(io_channel channel, const char *option,
                                 const char *arg)
 {
@@ -1093,6 +1111,7 @@ static struct struct_io_manager struct_undo_manager = {
        .read_blk       = undo_read_blk,
        .write_blk      = undo_write_blk,
        .flush          = undo_flush,
+       .flush_cleanup  = undo_flush_cleanup,
        .write_byte     = undo_write_byte,
        .set_option     = undo_set_option,
        .get_stats      = undo_get_stats,
index 73f5667ec1f3991968d1cd039c3cbd0f6ecf4bd0..ccb8d77e65361cad81401d80e004f43d2d5fc3fd 100644 (file)
@@ -1139,9 +1139,9 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
 }
 
 /*
- * Flush data buffers to disk.
+ * Flush data buffers to disk and invalidate cache if needed
  */
-static errcode_t unix_flush(io_channel channel)
+static errcode_t _unix_flush(io_channel channel, int invalidate)
 {
        struct unix_private_data *data;
        errcode_t retval = 0;
@@ -1151,7 +1151,7 @@ static errcode_t unix_flush(io_channel channel)
        EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
 
 #ifndef NO_IO_CACHE
-       retval = flush_cached_blocks(channel, data, 0);
+       retval = flush_cached_blocks(channel, data, invalidate);
 #endif
 #ifdef HAVE_FSYNC
        if (!retval && fsync(data->dev) != 0)
@@ -1160,6 +1160,22 @@ static errcode_t unix_flush(io_channel channel)
        return retval;
 }
 
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t unix_flush(io_channel channel)
+{
+       return _unix_flush(channel, 0);
+}
+
+/*
+ * Flush data buffers to disk and invalidate cache.
+ */
+static errcode_t unix_flush_cleanup(io_channel channel)
+{
+       return _unix_flush(channel, 1);
+}
+
 static errcode_t unix_set_option(io_channel channel, const char *option,
                                 const char *arg)
 {
@@ -1349,6 +1365,7 @@ static struct struct_io_manager struct_unix_manager = {
        .discard        = unix_discard,
        .cache_readahead        = unix_cache_readahead,
        .zeroout        = unix_zeroout,
+       .flush_cleanup  = unix_flush_cleanup,
 };
 
 io_manager unix_io_manager = &struct_unix_manager;
@@ -1370,6 +1387,7 @@ static struct struct_io_manager struct_unixfd_manager = {
        .discard        = unix_discard,
        .cache_readahead        = unix_cache_readahead,
        .zeroout        = unix_zeroout,
+       .flush_cleanup  = unix_flush_cleanup,
 };
 
 io_manager unixfd_io_manager = &struct_unixfd_manager;