From 3d4d75c519c435337a04eec4cc16ab0296f2c507 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 15 Apr 2021 02:51:11 +0100 Subject: [PATCH] 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 --- utils/uvol/files/lvm.sh | 39 +++++++++++++++++++++++++++------------ utils/uvol/files/ubi.sh | 40 +++++++++++++++++++++------------------- utils/uvol/files/uvol | 2 -- 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/utils/uvol/files/lvm.sh b/utils/uvol/files/lvm.sh index 35c2ae17e4..158ab1c83d 100644 --- a/utils/uvol/files/lvm.sh +++ b/utils/uvol/files/lvm.sh @@ -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 diff --git a/utils/uvol/files/ubi.sh b/utils/uvol/files/ubi.sh index 28841ca047..7851a98df4 100644 --- a/utils/uvol/files/ubi.sh +++ b/utils/uvol/files/ubi.sh @@ -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() { diff --git a/utils/uvol/files/uvol b/utils/uvol/files/uvol index 58d08f07e1..0fea88f38c 100644 --- a/utils/uvol/files/uvol +++ b/utils/uvol/files/uvol @@ -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