From: "Darrick J. Wong" <djwong@kernel.org>
To: tytso@mit.edu
Cc: linux-ext4@vger.kernel.org
Subject: [PATCH 3/3] libext2fs: only fsync the unix fd if we wrote to the device
Date: Wed, 22 Apr 2026 16:23:31 -0700 [thread overview]
Message-ID: <177689989365.3821152.8925862475853227905.stgit@frogsfrogsfrogs> (raw)
In-Reply-To: <177689989303.3821152.12873703999139555043.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
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@kernel.org>
---
lib/ext2fs/unix_io.c | 86 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 67 insertions(+), 19 deletions(-)
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 15d6d55ff7fdd4..f4307db0fb2b05 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -132,10 +132,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;
int unix_flock_flags;
@@ -1198,10 +1201,65 @@ static errcode_t unix_open(const char *name, int flags,
return unix_open_channel(name, fd, flags, channel, unix_io_manager);
}
+#ifdef HAVE_FSYNC
+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, int force_fsync)
+{
+ struct unix_private_data *data =
+ (struct unix_private_data *) channel->private_data;
+ int need_fsync;
+ errcode_t retval = 0;
+
+#ifndef NO_IO_CACHE
+ retval = flush_cached_blocks(channel, data, 0);
+#endif
+
+ mutex_lock(data, CACHE_MTX);
+ need_fsync = force_fsync || (data->state & UNIX_STATE_DIRTY);
+ data->state &= ~UNIX_STATE_DIRTY;
+ mutex_unlock(data, CACHE_MTX);
+
+ if (need_fsync && fsync(data->dev) != 0) {
+ if (!retval)
+ retval = errno;
+ }
+ if (retval) {
+ /* redirty because writeback failed */
+ mark_dirty(channel);
+ return retval;
+ }
+
+ return 0;
+}
+#else
+# define mark_dirty(...) ((void)0)
+
+static errcode_t maybe_fsync(io_channel channel, int force_fsync)
+{
+ struct unix_private_data *data =
+ (struct unix_private_data *) channel->private_data;
+ errcode_t retval = 0;
+
+#ifndef NO_IO_CACHE
+ retval = flush_cached_blocks(channel, data, 0);
+#endif
+ return retval;
+}
+#endif
+
static errcode_t unix_close(io_channel channel)
{
struct unix_private_data *data;
- errcode_t retval = 0;
+ errcode_t retval;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
@@ -1210,14 +1268,7 @@ static errcode_t unix_close(io_channel channel)
if (--channel->refcount > 0)
return 0;
-#ifndef NO_IO_CACHE
- retval = flush_cached_blocks(channel, data, 0);
-#endif
-#ifdef HAVE_FSYNC
- /* always fsync the device, even if flushing our own cache failed */
- if (fsync(data->dev) != 0 && !retval)
- retval = errno;
-#endif
+ retval = maybe_fsync(channel, 1);
unix_funlock(channel);
@@ -1388,6 +1439,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
@@ -1512,6 +1565,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;
@@ -1527,21 +1582,12 @@ 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;
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);
-#ifndef NO_IO_CACHE
- retval = flush_cached_blocks(channel, data, 0);
-#endif
-#ifdef HAVE_FSYNC
- /* always fsync the device, even if flushing our own cache failed */
- if (fsync(data->dev) != 0 && !retval)
- return errno;
-#endif
- return retval;
+ return maybe_fsync(channel, 0);
}
static errcode_t unix_set_option(io_channel channel, const char *option,
@@ -1653,6 +1699,7 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block,
}
return errno;
}
+ mark_dirty(channel);
return 0;
unimplemented:
return EXT2_ET_UNIMPLEMENTED;
@@ -1734,6 +1781,7 @@ static errcode_t unix_zeroout(io_channel channel, unsigned long long block,
}
return errno;
}
+ mark_dirty(channel);
return 0;
unimplemented:
return EXT2_ET_UNIMPLEMENTED;
next prev parent reply other threads:[~2026-04-22 23:23 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-22 23:15 [PATCHBOMB v5] fuse/libfuse/e2fsprogs/etc: containerize ext4 for safer operation Darrick J. Wong
2026-04-22 23:19 ` [PATCHSET 1/2] libext2fs: fix some missed fsync calls Darrick J. Wong
2026-04-22 23:23 ` [PATCH 1/3] libext2fs: always fsync the device when flushing the cache Darrick J. Wong
2026-04-22 23:23 ` [PATCH 2/3] libext2fs: always fsync the device when closing the unix IO manager Darrick J. Wong
2026-04-22 23:23 ` Darrick J. Wong [this message]
2026-04-22 23:19 ` [PATCHSET v5 2/2] fuse4fs: run servers as a contained service Darrick J. Wong
2026-04-22 23:23 ` [PATCH 01/10] libext2fs: make it possible to extract the fd from an IO manager Darrick J. Wong
2026-04-22 23:24 ` [PATCH 02/10] libext2fs: fix checking for valid fds in mmp.c Darrick J. Wong
2026-04-22 23:24 ` [PATCH 03/10] unix_io: allow passing /dev/fd/XXX paths to the unixfd IO manager Darrick J. Wong
2026-04-22 23:24 ` [PATCH 04/10] libext2fs: fix MMP code to work with " Darrick J. Wong
2026-04-22 23:24 ` [PATCH 05/10] libext2fs: bump libfuse API version to 3.19 Darrick J. Wong
2026-04-22 23:25 ` [PATCH 06/10] fuse4fs: hoist some code out of fuse4fs_main Darrick J. Wong
2026-04-22 23:25 ` [PATCH 07/10] fuse4fs: enable safe service mode Darrick J. Wong
2026-04-22 23:25 ` [PATCH 08/10] fuse4fs: set proc title when in fuse " Darrick J. Wong
2026-04-22 23:25 ` [PATCH 09/10] fuse4fs: make MMP work correctly in safe " Darrick J. Wong
2026-04-22 23:26 ` [PATCH 10/10] debian: update packaging for fuse4fs service Darrick J. Wong
2026-04-22 23:29 ` [RFC PATCH 1/4] fusefatfs: enable fuse systemd service mode Darrick J. Wong
2026-04-22 23:30 ` [RFC PATCH 2/4] exfat: " Darrick J. Wong
2026-04-22 23:32 ` [RFC PATCH 3/4] fuseiso: enable " Darrick J. Wong
2026-04-22 23:32 ` [RFC PATCH 4/4] httpdirfs: enable fuse " Darrick J. Wong
2026-04-23 8:44 ` [PATCHBOMB v5] fuse/libfuse/e2fsprogs/etc: containerize ext4 for safer operation Amir Goldstein
2026-04-23 14:50 ` Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=177689989365.3821152.8925862475853227905.stgit@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox