Skip to content

Commit 5b7acfc

Browse files
authored
Merge pull request #611 from ddiss/lklfuse_flock
lklfuse: support exclusive locks to avoid duplicate mounts
2 parents 46f599b + 656eccf commit 5b7acfc

File tree

5 files changed

+56
-14
lines changed

5 files changed

+56
-14
lines changed

Documentation/lkl/lklfuse.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ OPTIONS
3939

4040
-o part=parition mount <partition>.
4141

42-
-o ro open file read-only.
42+
-o ro open block-device read-only.
43+
44+
-o lock=<file> only mount after taking an exclusive lock on <file>.
4345

4446
-o opts=options Linux kernel mount <options> (use \\ to escape , and =).
4547

tools/lkl/lklfuse.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <stdio.h>
77
#include <string.h>
88
#include <stdlib.h>
9+
#include <sys/file.h>
910
#include <sys/stat.h>
1011
#include <string.h>
1112
#include <errno.h>
@@ -24,6 +25,7 @@ struct lklfuse {
2425
const char *log;
2526
const char *type;
2627
const char *opts;
28+
const char *lock;
2729
struct lkl_disk disk;
2830
int disk_id;
2931
int part;
@@ -46,6 +48,7 @@ static struct fuse_opt lklfuse_opts[] = {
4648
LKLFUSE_OPT("mb=%d", mb, 0),
4749
LKLFUSE_OPT("opts=%s", opts, 0),
4850
LKLFUSE_OPT("part=%d", part, 0),
51+
LKLFUSE_OPT("lock=%s", lock, 0),
4952
FUSE_OPT_KEY("-h", KEY_HELP),
5053
FUSE_OPT_KEY("--help", KEY_HELP),
5154
FUSE_OPT_KEY("-V", KEY_VERSION),
@@ -58,7 +61,7 @@ static struct fuse_opt lklfuse_opts[] = {
5861
static void usage(void)
5962
{
6063
printf(
61-
"usage: lklfuse file mountpoint [options]\n"
64+
"usage: lklfuse block-device mountpoint [options]\n"
6265
"\n"
6366
"general options:\n"
6467
" -o opt,[opt...] mount options\n"
@@ -70,7 +73,8 @@ static void usage(void)
7073
" -o type=fstype filesystem type\n"
7174
" -o mb=memory amount of memory to allocate in MB (default: 64)\n"
7275
" -o part=parition partition to mount\n"
73-
" -o ro open file read-only\n"
76+
" -o ro open block-device read-only\n"
77+
" -o lock=FILE only mount after taking an exclusive lock on FILE\n"
7478
" -o opts=options mount options (use \\ to escape , and =)\n"
7579
);
7680
}
@@ -791,7 +795,7 @@ int main(int argc, char **argv)
791795
struct fuse_cmdline_opts cli_opts;
792796
struct fuse *fuse;
793797
struct stat st;
794-
int ret;
798+
int ret, lockfd = -1;
795799

796800
if (fuse_opt_parse(&args, &lklfuse, lklfuse_opts, lklfuse_opt_proc))
797801
return 1;
@@ -801,6 +805,23 @@ int main(int argc, char **argv)
801805
return 1;
802806
}
803807

808+
if (lklfuse.lock) {
809+
lockfd = open(lklfuse.lock, O_RDWR | O_CREAT, 0644);
810+
if (lockfd < 0) {
811+
fprintf(stderr, "failed to open %s: %s\n",
812+
lklfuse.lock, strerror(errno));
813+
return 1;
814+
}
815+
816+
ret = flock(lockfd, LOCK_EX | LOCK_NB);
817+
if (ret < 0) {
818+
fprintf(stderr, "unable to exclusively lock %s: %s\n",
819+
lklfuse.lock, strerror(errno));
820+
return 2;
821+
}
822+
/* lock dropped when lockfd is closed on program exit */
823+
}
824+
804825
if (fuse_parse_cmdline(&args, &cli_opts))
805826
return 1;
806827

tools/lkl/systemd/[email protected]

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ [email protected]
66

77
[Service]
88
RuntimeDirectory=lklfuse-%i
9+
StateDirectory=lklfuse/fsid-mutex
910
# The "allow_other" mount option permits fuse mount access by users other than
1011
# the lklfuse user, and requires a "user_allow_other" setting in fuse3.conf
1112
Environment=LKLFUSE_ARGS="-s -oallow_other"
@@ -18,8 +19,11 @@ EnvironmentFile=-/etc/lklfuse.conf
1819
# run as unprivileged user
1920
User=lklfuse
2021
Group=lklfuse
21-
ExecCondition=/bin/bash -c "udevadm info -q env -x --property=ID_FS_TYPE -n \"%I\" > ${RUNTIME_DIRECTORY}/udev.env"
22-
ExecStart=/bin/bash -c ". ${RUNTIME_DIRECTORY}/udev.env; rm ${RUNTIME_DIRECTORY}/udev.env; /usr/bin/lklfuse -f -ofsname=\"/dev/%I\",subtype=\"lkl.$ID_FS_TYPE\",type=\"$ID_FS_TYPE\" $LKLFUSE_ARGS \"/dev/%I\" $RUNTIME_DIRECTORY"
22+
ExecCondition=/bin/bash -xc "udevadm info -q env -x --property=ID_FS_TYPE,ID_FS_UUID -n \"%I\" > ${RUNTIME_DIRECTORY}/udev.env"
23+
# Use an ID_FS_UUID based lock file to avoid duplicate mounts.
24+
# If udev doesn't provide an id then use a static noid path, ensuring lock
25+
# conflict with any other id-less mount.
26+
ExecStart=/bin/bash -xc ". ${RUNTIME_DIRECTORY}/udev.env; rm ${RUNTIME_DIRECTORY}/udev.env; /usr/bin/lklfuse -f -ofsname=\"/dev/%I\",subtype=\"lkl.$ID_FS_TYPE\",type=\"$ID_FS_TYPE\",lock=\"${STATE_DIRECTORY}/${ID_FS_UUID:-noid}\" $LKLFUSE_ARGS \"/dev/%I\" ${RUNTIME_DIRECTORY}"
2327

2428
[Install]
2529
WantedBy=default.target

tools/lkl/tests/lklfuse.sh

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ cleanup()
88
{
99
set -e
1010

11-
sleep 1
1211
if type -P fusermount3 > /dev/null; then
1312
fusermount3 -u $dir
1413
else
@@ -18,7 +17,6 @@ cleanup()
1817
rmdir $dir
1918
}
2019

21-
2220
# $1 - disk image
2321
# $2 - fstype
2422
function prepfs()
@@ -33,9 +31,10 @@ function prepfs()
3331
# $1 - disk image
3432
# $2 - mount point
3533
# $3 - filesystem type
34+
# $4 - lock file
3635
lklfuse_mount()
3736
{
38-
${script_dir}/../lklfuse $1 $2 -o type=$3
37+
${script_dir}/../lklfuse $1 $2 -o type=$3,lock=$4
3938
}
4039

4140
# $1 - mount point
@@ -74,6 +73,21 @@ lklfuse_stressng()
7473
--sync-file-bytes 10m
7574
}
7675

76+
# $1 - disk image
77+
# $2 - filesystem type
78+
# $3 - lock file
79+
lklfuse_lock_conflict()
80+
{
81+
local ret=$TEST_FAILURE unused_mnt=`mktemp -d`
82+
83+
set +e
84+
# assume lklfuse already running with same lock file, causing lock conflict
85+
${script_dir}/../lklfuse -f $1 $unused_mnt -o type=$2,lock=$3
86+
[ $? -eq 2 ] && ret=$TEST_SUCCESS
87+
rmdir "$unused_mnt"
88+
return $ret
89+
}
90+
7791
if [ "$1" = "-t" ]; then
7892
shift
7993
fstype=$1
@@ -102,18 +116,19 @@ if [ -z $(which mkfs.$fstype) ]; then
102116
exit 0
103117
fi
104118

105-
106119
file=`mktemp`
107120
dir=`mktemp -d`
121+
lock_file="$file"
108122

109123
trap cleanup EXIT
110124

111-
lkl_test_plan 4 "lklfuse $fstype"
125+
lkl_test_plan 5 "lklfuse $fstype"
112126

113127
lkl_test_run 1 prepfs $file $fstype
114-
lkl_test_run 2 lklfuse_mount $file $dir $fstype
128+
lkl_test_run 2 lklfuse_mount $file $dir $fstype $lock_file
115129
lkl_test_run 3 lklfuse_basic $dir
116130
# stress-ng returns 2 with no apparent failures so skip it for now
117131
#lkl_test_run 4 lklfuse_stressng $dir $fstype
132+
lkl_test_run 4 lklfuse_lock_conflict $file $fstype $lock_file
118133
trap : EXIT
119-
lkl_test_run 4 cleanup
134+
lkl_test_run 5 cleanup

tools/lkl/tests/net.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ setup_backend()
127127
;;
128128
*)
129129
echo "don't know how to setup backend $1"
130-
return $TEST_FAILED
130+
return $TEST_FAILURE
131131
;;
132132
esac
133133
}

0 commit comments

Comments
 (0)