uvol: make volume creation atomic
authorDaniel Golle <redacted>
Thu, 15 Apr 2021 01:51:11 +0000 (02:51 +0100)
committerDaniel Golle <redacted>
Thu, 15 Apr 2021 01:55:10 +0000 (02:55 +0100)
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 <redacted>
utils/uvol/files/lvm.sh
utils/uvol/files/ubi.sh
utils/uvol/files/uvol

index 35c2ae17e4714e931b5f9ceea1037761b5ae6a8b..158ab1c83deac14807dc87e562f641bc705d0bf3 100644 (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
index 28841ca0474ff94a959809fd52cc95efa74a3c48..7851a98df486d7ecde93fa4d76aecde80db53fb3 100644 (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() {
index 58d08f07e10f9a0455afe0ebecaee276d5dd36e3..0fea88f38ce7d4fde7f78dbb77916b3be90422f3 100644 (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
 
git clone https://git.99rst.org/PROJECT