From: Darrick J. Wong <djwong@xxxxxxxxxx> As an optimization, only fsync the block device fd if we tried to write to the io channel. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- lib/ext2fs/unix_io.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c index 7c5cb075d6b6b6..0fc83e471ca0fe 100644 --- a/lib/ext2fs/unix_io.c +++ b/lib/ext2fs/unix_io.c @@ -129,10 +129,13 @@ struct unix_cache { #define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ #define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ +#define UNIX_STATE_DIRTY (1U << 0) /* device needs fsyncing */ + struct unix_private_data { int magic; int dev; int flags; + unsigned int state; /* UNIX_STATE_* */ int align; int access_time; ext2_loff_t offset; @@ -1121,10 +1124,37 @@ static errcode_t unix_open(const char *name, int flags, return unix_open_channel(name, fd, flags, channel, unix_io_manager); } +static void mark_dirty(io_channel channel) +{ + struct unix_private_data *data = + (struct unix_private_data *) channel->private_data; + + mutex_lock(data, CACHE_MTX); + data->state |= UNIX_STATE_DIRTY; + mutex_unlock(data, CACHE_MTX); +} + +static errcode_t maybe_fsync(io_channel channel) +{ + struct unix_private_data *data = + (struct unix_private_data *) channel->private_data; + int was_dirty; + + mutex_lock(data, CACHE_MTX); + was_dirty = data->state & UNIX_STATE_DIRTY; + data->state &= ~UNIX_STATE_DIRTY; + mutex_unlock(data, CACHE_MTX); + + if (was_dirty && fsync(data->dev) != 0) + return errno; + + return 0; +} + static errcode_t unix_close(io_channel channel) { struct unix_private_data *data; - errcode_t retval = 0; + errcode_t retval = 0, retval2; EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); data = (struct unix_private_data *) channel->private_data; @@ -1137,8 +1167,9 @@ static errcode_t unix_close(io_channel channel) retval = flush_cached_blocks(channel, data, 0); #endif /* always fsync the device, even if flushing our own cache failed */ - if (fsync(data->dev) != 0 && !retval) - retval = errno; + retval2 = maybe_fsync(channel); + if (retval2 && !retval) + retval = retval2; if (close(data->dev) < 0 && !retval) retval = errno; @@ -1306,6 +1337,8 @@ static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, data = (struct unix_private_data *) channel->private_data; EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + mark_dirty(channel); + #ifdef NO_IO_CACHE return raw_write_blk(channel, data, block, count, buf, 0); #else @@ -1430,6 +1463,8 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset, if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) return errno; + mark_dirty(channel); + actual = write(data->dev, buf, size); if (actual < 0) return errno; @@ -1445,7 +1480,7 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset, static errcode_t unix_flush(io_channel channel) { struct unix_private_data *data; - errcode_t retval = 0; + errcode_t retval = 0, retval2; EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); data = (struct unix_private_data *) channel->private_data; @@ -1456,8 +1491,9 @@ static errcode_t unix_flush(io_channel channel) #endif #ifdef HAVE_FSYNC /* always fsync the device, even if flushing our own cache failed */ - if (fsync(data->dev) != 0 && !retval) - return errno; + retval2 = maybe_fsync(channel); + if (retval2 && !retval) + retval = retval2; #endif return retval; }