From 29e4402a82dfaa62d64848b66b7c97d5e14b0000 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 2 Jul 2025 10:10:40 +0200 Subject: [PATCH] lklfuse: add lock parameter to avoid duplicate mounts This lock-while-mounted behaviour is similar to what QEMU does, and can help avoid duplicate mounts. Allowing for an explicit lock path that differs from the filesystem image / block device path was intentional, to ensure non-flock supporting filesystems can still be used. Also, there are cases where a block device and partition (e.g. sda and sda1) can both provide access to the same filesystem image, in which case an FS-ID based lock would make sense. Signed-off-by: David Disseldorp --- Documentation/lkl/lklfuse.rst | 4 +++- tools/lkl/lklfuse.c | 27 ++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Documentation/lkl/lklfuse.rst b/Documentation/lkl/lklfuse.rst index f3ac736473de..a519644c9089 100644 --- a/Documentation/lkl/lklfuse.rst +++ b/Documentation/lkl/lklfuse.rst @@ -39,7 +39,9 @@ OPTIONS -o part=parition mount . --o ro open file read-only. +-o ro open block-device read-only. + +-o lock= only mount after taking an exclusive lock on . -o opts=options Linux kernel mount (use \\ to escape , and =). diff --git a/tools/lkl/lklfuse.c b/tools/lkl/lklfuse.c index cde7f4351f97..ac40f16b2fc3 100644 --- a/tools/lkl/lklfuse.c +++ b/tools/lkl/lklfuse.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ struct lklfuse { const char *log; const char *type; const char *opts; + const char *lock; struct lkl_disk disk; int disk_id; int part; @@ -46,6 +48,7 @@ static struct fuse_opt lklfuse_opts[] = { LKLFUSE_OPT("mb=%d", mb, 0), LKLFUSE_OPT("opts=%s", opts, 0), LKLFUSE_OPT("part=%d", part, 0), + LKLFUSE_OPT("lock=%s", lock, 0), FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), FUSE_OPT_KEY("-V", KEY_VERSION), @@ -58,7 +61,7 @@ static struct fuse_opt lklfuse_opts[] = { static void usage(void) { printf( -"usage: lklfuse file mountpoint [options]\n" +"usage: lklfuse block-device mountpoint [options]\n" "\n" "general options:\n" " -o opt,[opt...] mount options\n" @@ -70,7 +73,8 @@ static void usage(void) " -o type=fstype filesystem type\n" " -o mb=memory amount of memory to allocate in MB (default: 64)\n" " -o part=parition partition to mount\n" -" -o ro open file read-only\n" +" -o ro open block-device read-only\n" +" -o lock=FILE only mount after taking an exclusive lock on FILE\n" " -o opts=options mount options (use \\ to escape , and =)\n" ); } @@ -791,7 +795,7 @@ int main(int argc, char **argv) struct fuse_cmdline_opts cli_opts; struct fuse *fuse; struct stat st; - int ret; + int ret, lockfd = -1; if (fuse_opt_parse(&args, &lklfuse, lklfuse_opts, lklfuse_opt_proc)) return 1; @@ -801,6 +805,23 @@ int main(int argc, char **argv) return 1; } + if (lklfuse.lock) { + lockfd = open(lklfuse.lock, O_RDWR | O_CREAT, 0644); + if (lockfd < 0) { + fprintf(stderr, "failed to open %s: %s\n", + lklfuse.lock, strerror(errno)); + return 1; + } + + ret = flock(lockfd, LOCK_EX | LOCK_NB); + if (ret < 0) { + fprintf(stderr, "unable to exclusively lock %s: %s\n", + lklfuse.lock, strerror(errno)); + return 2; + } + /* lock dropped when lockfd is closed on program exit */ + } + if (fuse_parse_cmdline(&args, &cli_opts)) return 1;