Hi Chengyu,
On 2026/6/19 12:19, Chengyu wrote:
From: Chengyu Zhu <[email protected]>
Enable ublk user recovery so erofsmount can reattach a daemon to a
recoverable ublk device after the previous userspace server exits.
Store the recovery source information in a ublk-specific runtime record,
create ublk devices with user recovery enabled, and add the mount-side
reattach path for existing recoverable ublk devices.
Also encode ublk IO uring command opcodes explicitly for non-legacy kernels,
and initialize the control ring before querying whether a ublk device is
recoverable.
Signed-off-by: Chengyu Zhu <[email protected]>
---
lib/backends/ublk.c | 23 ++++++---
mount/main.c | 115 ++++++++++++++++++++++++++++++++++++++++----
2 files changed, 122 insertions(+), 16 deletions(-)
diff --git a/lib/backends/ublk.c b/lib/backends/ublk.c
index a8ecad9..49191de 100644
--- a/lib/backends/ublk.c
+++ b/lib/backends/ublk.c
@@ -258,7 +258,16 @@ static unsigned int erofsublk_formalize_cmd_op(unsigned
int op)
DBG_BUGON(_IOC_DIR(op) != 0);
DBG_BUGON(_IOC_SIZE(op) != 0);
- if (op < ARRAY_SIZE(ctrl_cmd_op) && !erofs_ublk_use_legacy_cmds)
+ if (erofs_ublk_use_legacy_cmds)
+ return op;
+
+ /* IO opcodes live above the ctrl table and need explicit encoding */
+ if (op == UBLK_IO_FETCH_REQ)
+ return UBLK_U_IO_FETCH_REQ;
+ if (op == UBLK_IO_COMMIT_AND_FETCH_REQ)
+ return UBLK_U_IO_COMMIT_AND_FETCH_REQ;
+
+ if (op < ARRAY_SIZE(ctrl_cmd_op))
return ctrl_cmd_op[op];
return op;
if (!erofs_ublk_use_legacy_cmds) {
if (op == UBLK_IO_FETCH_REQ)
return UBLK_U_IO_FETCH_REQ;
if (op == UBLK_IO_COMMIT_AND_FETCH_REQ)
return UBLK_U_IO_COMMIT_AND_FETCH_REQ;
if (op < ARRAY_SIZE(ctrl_cmd_op))
return ctrl_cmd_op[op];
}
return op;
?
}
@@ -528,11 +537,6 @@ static inline unsigned int user_data_to_tag(u64 user_data)
return user_data & 0xffff;
}
..
+static int ublk_dev_id_from_path(const char *path);
Can we avoid forward declaration?
+
+static int erofsmount_ublk_reattach(int dev_id)
+{
+ struct erofsmount_nbd_ctx ctx = { .vd = &ctx._vd };
+ char *recp;
+ FILE *f;
+ int err;
+
+ if (!erofs_ublk_is_recoverable(dev_id))
+ return -EINVAL;
+
+ if (asprintf(&recp, EROFSMOUNT_UBLK_REC_FMT, dev_id) <= 0)
+ return -ENOMEM;
+
+ f = fopen(recp, "r");
+ if (!f) {
+ err = -errno;
+ free(recp);
+ return err;
+ }
+
+ err = erofsmount_open_recovery_source(&ctx, f);
+ if (err) {
+ free(recp);
+ return err;
+ }
+
+ if (fork() == 0) {
+ err = erofs_ublk_recover_dev(dev_id, erofsmount_ublk_handler,
+ ctx.vd);
+ if (err) {
+ erofs_err("ublk recover dev %d failed: %s",
+ dev_id, strerror(-err));
+ erofs_io_close(ctx.vd);
+ exit(EXIT_FAILURE);
+ }
+ err = erofs_ublk_start(dev_id, -1);
+ erofs_ublk_destroy(dev_id);
+ erofs_io_close(ctx.vd);
+ (void)unlink(recp);
+ exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+
+ erofs_io_close(ctx.vd);
+ free(recp);
+ return 0;
+}
+
static int erofsmount_reattach(const char *target)
{
struct erofsmount_nbd_ctx ctx = { .vd = &ctx._vd };
@@ -1450,6 +1528,10 @@ static int erofsmount_reattach(const char *target)
if (err < 0)
return -errno;
+ nbdnum = ublk_dev_id_from_path(target);
+ if (S_ISBLK(st.st_mode) && nbdnum >= 0)
+ return erofsmount_ublk_reattach(nbdnum);
+
if (!S_ISBLK(st.st_mode) || major(st.st_rdev) != EROFS_NBD_MAJOR)
return -ENOTBLK;
if (!S_ISBLK(st.st_mode))
return -ENOTBLK;
nbdnum = ublk_dev_id_from_path(target);
if (nbdnum >= 0)
return erofsmount_ublk_reattach(nbdnum);
if (major(st.st_rdev) != EROFS_NBD_MAJOR)
return -ENOTBLK;
?
Thanks,
Gao Xiang