uvol: make volume creation atomic

Make sure filesystem is ready when volume becomes available.
Use 'write-once' as initial state for read-only volumes, only allow
writing to volumes in that state and transision to 'read-only' once
write has completed.
Also fix a typo which prevented 'list' command from working with LVM.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2021-04-15 02:51:11 +01:00
parent ee1a3654dc
commit 3d4d75c519
No known key found for this signature in database
GPG Key ID: 5A8F39C31C3217CA
3 changed files with 48 additions and 33 deletions

View File

@ -41,7 +41,7 @@ vgs() {
}
lvs() {
lvm_cmd vgs --reportformat json --units b "$@"
lvm_cmd lvs --reportformat json --units b "$@"
}
freebytes() {
@ -121,7 +121,7 @@ exportlv() {
lv_size=
json_init
json_load "$(lvs -o lv_full_name,lv_size,lv_path,lv_dm_path -S "lv_name=~^r[ow]_$1\$ && vg_name=$vg_name")"
json_load "$(lvs -o lv_full_name,lv_size,lv_path,lv_dm_path -S "lv_name=~^[rw][ow]_$1\$ && vg_name=$vg_name")"
json_select report
json_get_keys reports
for rep in $reports; do
@ -153,7 +153,15 @@ getsize() {
activatevol() {
exportlv "$1"
lvm_cmd lvchange -a y "$lv_full_name"
case "$lv_path" in
/dev/*/wo_*)
return 22
;;
*)
lvm_cmd lvchange -a y "$lv_full_name"
return 0
;;
esac
}
disactivatevol() {
@ -169,7 +177,7 @@ getstatus() {
}
createvol() {
local mode ret
local mode lvmode ret
local volsize=$(($2))
[ "$volsize" ] || return 22
exportlv "$1"
@ -178,10 +186,12 @@ createvol() {
[ $((size_ext * vg_extent_size)) -lt $volsize ] && size_ext=$((size_ext + 1))
case "$3" in
ro)
mode=r
ro|wo)
lvmode=r
mode=wo
;;
rw)
lvmode=rw
mode=rw
;;
*)
@ -189,9 +199,9 @@ createvol() {
;;
esac
lvm_cmd lvcreate -p $mode -a n -y -W n -Z n -n "${3}_${1}" -l "$size_ext" $vg_name
lvm_cmd lvcreate -p $lvmode -a n -y -W n -Z n -n "${mode}_${1}" -l "$size_ext" $vg_name
ret=$?
if [ ! $ret -eq 0 ] || [ "$mode" = "r" ]; then
if [ ! $ret -eq 0 ] || [ "$lvmode" = "r" ]; then
return $ret
fi
exportlv "$1"
@ -215,11 +225,16 @@ updatevol() {
exportlv "$1"
[ "$lv_full_name" ] || return 2
[ $lv_size -ge $2 ] || return 27
lvm_cmd lvchange -a y -p rw "$lv_full_name"
dd of=$lv_path
case "$lv_path" in
/dev/*/ro_*)
/dev/*/wo_*)
lvm_cmd lvchange -a y -p rw "$lv_full_name"
dd of=$lv_path
lvm_cmd lvchange -p r "$lv_full_name"
lvm_cmd lvrename "$lv_full_name" "${lv_full_name%%/*}/ro_$1"
return 0
;;
default)
return 22
;;
esac
}
@ -228,7 +243,7 @@ listvols() {
local reports rep lv lvs lv_name lv_size lv_mode volname
volname=${1:-.*}
json_init
json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^r[ow]_$volname\$ && vg_name=$vg_name")"
json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^[rw][ow]_$volname\$ && vg_name=$vg_name")"
json_select report
json_get_keys reports
for rep in $reports; do

View File

@ -31,17 +31,17 @@ getdev() {
local voldir volname devname
for voldir in /sys/devices/virtual/ubi/${ubidev}/${ubidev}_*; do
read volname < "${voldir}/name"
[ "$volname" = "uvol-ro-$1" ] || [ "$volname" = "uvol-rw-$1" ] || continue
[ "$volname" = "uvol-ro-$1" ] || [ "$volname" = "uvol-wp-$1" ] || [ "$volname" = "uvol-rw-$1" ] || [ "$volname" = "uvol-wo-$1" ] || continue
basename "$voldir"
done
}
needs_ubiblock() {
vol_is_mode() {
local voldev="$1"
local volname
read volname < "/sys/devices/virtual/ubi/${ubidev}/${voldev}/name"
case "$volname" in
uvol-ro-*)
uvol-$2-*)
return 0
;;
esac
@ -51,7 +51,8 @@ needs_ubiblock() {
getstatus() {
local voldev=$(getdev "$@")
[ "$voldev" ] || return 2
needs_ubiblock $voldev && [ ! -e "/dev/ubiblock${voldev:3}" ] && return 1
vol_is_mode $voldev wo && return 1
vol_is_mode $voldev ro && [ ! -e "/dev/ubiblock${voldev:3}" ] && return 1
return 0
}
@ -65,9 +66,9 @@ getsize() {
getuserdev() {
local voldev=$(getdev "$@")
[ "$voldev" ] || return 2
if needs_ubiblock $voldev ; then
if vol_is_mode $voldev ro ; then
echo "/dev/ubiblock${voldev:3}"
else
elif vol_is_mode $voldev rw ; then
echo "/dev/$voldev"
fi
}
@ -77,11 +78,11 @@ createvol() {
local existdev=$(getdev "$@")
[ "$existdev" ] && return 17
case "$3" in
ro)
mode=ro
ro|wo)
mode=wo
;;
rw)
mode=rw
mode=wp
;;
*)
return 22
@ -91,6 +92,12 @@ createvol() {
ret=$?
[ $ret -eq 0 ] || return $ret
ubiupdatevol -t /dev/$(getdev "$@")
[ "$mode" = "wp" ] || return 0
local tmp_mp=$(mktemp -d)
mount -t ubifs /dev/$(getdev "$@") $tmp_mp
umount $tmp_mp
rmdir $tmp_mp
ubirename /dev/$ubidev uvol-wp-$1 uvol-rw-$1
}
removevol() {
@ -103,7 +110,8 @@ removevol() {
activatevol() {
local voldev=$(getdev "$@")
[ "$voldev" ] || return 2
needs_ubiblock $voldev || return 0
vol_is_mode $voldev wo || return 1
vol_is_mode $voldev ro || return 0
[ -e "/dev/ubiblock${voldev:3}" ] && return 0
ubiblock --create /dev/$voldev
}
@ -111,7 +119,7 @@ activatevol() {
disactivatevol() {
local voldev=$(getdev "$@")
[ "$voldev" ] || return 2
needs_ubiblock $voldev || return 0
vol_is_mode $voldev ro || return 0
[ -e "/dev/ubiblock${voldev:3}" ] || return 0
ubiblock --remove /dev/$voldev
}
@ -120,15 +128,9 @@ updatevol() {
local voldev=$(getdev "$@")
[ "$voldev" ] || return 2
[ "$2" ] || return 22
needs_ubiblock $voldev || return 22
vol_is_mode $voldev wo || return 22
ubiupdatevol -s $2 /dev/$voldev -
}
getstatus() {
local voldev=$(getdev "$@")
[ "$voldev" ] || return 2
needs_ubiblock $voldev && [ ! -e "/dev/ubiblock${voldev:3}" ] && return 1
return 0
ubirename /dev/$ubidev uvol-wo-$1 uvol-ro-$1
}
listvols() {

View File

@ -2,8 +2,6 @@
# uvol prototype
# future development roadmap (aka. to-do):
# * atomic create using temp volnames
# * create read-only volumes as 'write-once', introduce 'pending' state until written
# * re-implement in C (use libubox, execve lvm/ubi*)
# * add atomic batch processing for use by container/package manager