Hello, This is the second patch of the series, implementing the userspace support for physical write barriers.
libstore, rumpdisk: Add write barrier support This patch introduces a sync method to the store interface, allowing users to request a physical write barrier from the underlying storage. It implements this method for the device class by sending the new DEV_FLUSH_CACHE status code, and adds the corresponding handler in rumpdisk to trigger a physical cache flush via the NetBSD DIOCCACHESYNC ioctl. Note: This patch requires the corresponding gnumach patch 'device: Define DEV_FLUSH_CACHE status flavor' to build cleanly. Verification: I verified this using a crash-test methodology: 1. Instrumented ext2fs/pager.c to explicitly call store_sync() for a specific inode immediately after writing. 2. Wrote to that inode inside the VM. 3. Immediately killed the QEMU process from the host (simulating power loss). 4. Inspected the disk image from the host; verified that the new content persisted, confirming the barrier successfully forced a physical flush. Regards, Milos
From 4c06d8b59d1e7a9284367123b5c67ca613517f8f Mon Sep 17 00:00:00 2001 From: Milos Nikic <[email protected]> Date: Fri, 23 Jan 2026 14:37:01 -0800 Subject: [PATCH] libstore, rumpdisk: Add write barrier support This patch introduces a sync method to the store interface, allowing users to request a physical write barrier from the underlying storage. It implements this method for the device class by sending the new DEV_FLUSH_CACHE status code, and adds the corresponding handler in rumpdisk to trigger a physical cache flush via the NetBSD DIOCCACHESYNC ioctl. Note: This patch requires the corresponding gnumach patch 'device: Define DEV_FLUSH_CACHE status flavor' to build cleanly. * libstore/store.h (struct store_class): Add `sync` member. (store_sync): Add prototype. * libstore/rdwr.c (store_sync): New function. * libstore/device.c (dev_sync): New static function. (store_device_class): Add `dev_sync` to the class vector. * rumpdisk/block-rump.c (DIOCCACHESYNC): Define fallback if missing. (rumpdisk_device_set_status): Handle DEV_FLUSH_CACHE flavor. --- libstore/device.c | 8 +++++++- libstore/rdwr.c | 9 +++++++++ libstore/store.h | 5 +++++ rumpdisk/block-rump.c | 24 ++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/libstore/device.c b/libstore/device.c index c7b9d756..dc0f7650 100644 --- a/libstore/device.c +++ b/libstore/device.c @@ -87,6 +87,12 @@ dev_write (struct store *store, store_offset_t addr, return err; } +static error_t +dev_sync (struct store *store) +{ + return device_set_status (store->port, DEV_FLUSH_CACHE, NULL, 0); +} + static error_t dev_set_size (struct store *store, size_t newsize) { @@ -318,7 +324,7 @@ store_device_class = { STORAGE_DEVICE, "device", dev_read, dev_write, dev_set_size, store_std_leaf_allocate_encoding, store_std_leaf_encode, dev_decode, - dev_set_flags, dev_clear_flags, 0, 0, 0, dev_open, 0, dev_map + dev_set_flags, dev_clear_flags, 0, 0, 0, dev_open, 0, dev_map, dev_sync }; STORE_STD_CLASS (device); diff --git a/libstore/rdwr.c b/libstore/rdwr.c index f443ad9f..e5e853cf 100644 --- a/libstore/rdwr.c +++ b/libstore/rdwr.c @@ -296,3 +296,12 @@ store_set_size (struct store *store, size_t newsize) return err; } + +/* Ensure all writes to STORE are on permanent storage. */ +error_t +store_sync (struct store *store) +{ + if (store->class->sync) + return (*store->class->sync) (store); + return EOPNOTSUPP; +} diff --git a/libstore/store.h b/libstore/store.h index f4697460..0404d798 100644 --- a/libstore/store.h +++ b/libstore/store.h @@ -207,6 +207,8 @@ struct store_class /* Return a memory object paging on STORE. */ error_t (*map) (const struct store *store, vm_prot_t prot, mach_port_t *memobj); + /* Sync any cached writes to permanent storage. */ + error_t (*sync) (struct store *store); }; /* Return a new store in STORE, which refers to the storage underlying @@ -319,6 +321,9 @@ error_t store_read (struct store *store, /* Set STORE's size to NEWSIZE (in bytes). */ error_t store_set_size (struct store *store, size_t newsize); +/* Ensure all writes to STORE are on permanent storage. */ +error_t store_sync (struct store *store); + /* If STORE was created using store_create, remove the reference to the source from which it was created. */ void store_close_source (struct store *store); diff --git a/rumpdisk/block-rump.c b/rumpdisk/block-rump.c index aa8afb4f..7ef1795b 100644 --- a/rumpdisk/block-rump.c +++ b/rumpdisk/block-rump.c @@ -55,6 +55,15 @@ #define RUMP_TYPE_STRING "rump USB" #endif +#ifndef DIOCCACHESYNC + #ifdef _IOW + #define DIOCCACHESYNC _IOW('d', 118, int) + #else + /* Fallback if _IOW macro isn't visible, though ioccom-rump.h should have it */ + #define DIOCCACHESYNC (0x80000000 | (sizeof(int) << 16) | ('d' << 8) | 118) + #endif +#endif + static bool disabled; static mach_port_t master_host; @@ -535,12 +544,27 @@ static io_return_t rumpdisk_device_set_status (void *d, dev_flavor_t flavor, dev_status_t status, mach_msg_type_number_t status_count) { + struct block_data *bd = d; + int ret; + int force = 1; switch (flavor) { case BLKRRPART: /* Partitions are not implemented here, but in the parted-based * translators. */ return D_SUCCESS; + case DEV_FLUSH_CACHE: + /* * Rump/NetBSD expects an integer argument for DIOCCACHESYNC. + * 1 = Force flush + */ + ret = rump_sys_ioctl (bd->rump_fd, DIOCCACHESYNC, &force); + + if (ret < 0) + { + /* rump_errno2host handles the translation */ + return rump_errno2host (errno); + } + return D_SUCCESS; default: return D_INVALID_OPERATION; } -- 2.52.0
