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.
Change-Id: Ie9d93a2193394ab12550da6141d8b08b9e519ef0
Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Reviewed-on: https://review.whamcloud.com/35763
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Andreas Dilger <adilger@whamcloud.com>
ext2_ino_t free_inodes;
int mount_flags;
int openfs_flags;
+ io_manager io_manager;
blkid_cache blkid; /* blkid cache */
#ifdef HAVE_SETJMP_H
jmp_buf abort_loc;
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;
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;
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) {
if (retval)
return retval;
}
- dest->icache = icache;
if (src->icache) {
ext2fs_free_inode_cache(src->icache);
src->badblocks = NULL;
}
+ io_channel_close(src->io);
return retval;
}
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;
}
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) &&
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,
#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 */
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
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;
+ 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.
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;
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;
- 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;
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)
{
.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,
}
/*
- * 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;
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)
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)
{
.discard = unix_discard,
.cache_readahead = unix_cache_readahead,
.zeroout = unix_zeroout,
+ .flush_cleanup = unix_flush_cleanup,
};
io_manager unix_io_manager = &struct_unix_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;