uvol: some improvements
authorDaniel Golle <redacted>
Sun, 11 Apr 2021 00:41:05 +0000 (01:41 +0100)
committerDaniel Golle <redacted>
Sun, 11 Apr 2021 00:42:58 +0000 (01:42 +0100)
 * use lvm --reportformat json
 * add 'list' and 'align' commands
 * add help output

Signed-off-by: Daniel Golle <redacted>
utils/uvol/files/lvm.sh
utils/uvol/files/ubi.sh
utils/uvol/files/uvol

index 540fe39e92e5ef1b4130335a70069b88a58167f8..35c2ae17e4714e931b5f9ceea1037761b5ae6a8b 100644 (file)
@@ -1,15 +1,23 @@
 #!/bin/sh
 
-command -v lvm || return 1
+cmd="$1"
+shift
+
+if [ "$cmd" = "name" ]; then
+       echo "LVM"
+       return 0
+fi
+
+command -v lvm >/dev/null || return 1
 
 . /lib/functions.sh
 . /lib/upgrade/common.sh
+. /usr/share/libubox/jshn.sh
 
 export_bootdevice
 [ "$BOOTDEV_MAJOR" ] || return 1
 export_partdevice rootdev 0
 [ "$rootdev" ] || return 1
-LVM_SUPPRESS_FD_WARNINGS=1
 
 case "$rootdev" in
        mtd*|\
@@ -18,93 +26,157 @@ case "$rootdev" in
                return 1
 esac
 
-lvs() {
+lvm_cmd() {
        local cmd="$1"
-       local cb="$2"
-       local param="${3:+-S vg_name=${vgname} -S lv_name=~^r[ow]_$3\$}"
-       local oIFS="$IFS"
-       IFS=" "
-       set -- $(LVM_SUPPRESS_FD_WARNINGS=1 $cmd -c $param)
-       [ "$1" ] || {
-               IFS="$oIFS"
-               return 1
-       }
-       IFS=":"
-       set -- $1
-       IFS="$oIFS"
-       $cb "$@"
-}
-
-pvvars() {
-       case "${1:5}" in
-               "$rootdev"*)
-                       partdev="$1"
-                       vgname="$2"
-                       ;;
-       esac
+       shift
+       LVM_SUPPRESS_FD_WARNINGS=1 lvm "$cmd" "$@"
+}
+
+pvs() {
+       lvm_cmd pvs --reportformat json --units b "$@"
 }
 
-vgvars() {
-       [ "$1" = "$vgname" ] || return
-       vgbs="${13}"
-       vgts="${14}"
-       vgus="${15}"
-       vgfs="${16}"
+vgs() {
+       lvm_cmd vgs --reportformat json --units b "$@"
 }
 
-lvvars() {
-       lvpath="$1"
-       lvsize=$(( 512 * $7 ))
+lvs() {
+       lvm_cmd vgs --reportformat json --units b "$@"
 }
 
 freebytes() {
-       echo $((vgfs * vgbs * 1024))
+       echo $(($vg_free_count * $vg_extent_size * 1024))
 }
 
 totalbytes() {
-       echo $((vgts * vgbs * 1024))
+       echo $(($vg_extent_count * $vg_extent_size * 1024))
 }
 
 existvol() {
        [ "$1" ] || return 1
-       test -e "/dev/$vgname/ro_$1" || test -e "/dev/$vgname/rw_$1"
+       test -e "/dev/$vg_name/ro_$1" || test -e "/dev/$vg_name/rw_$1"
        return $?
 }
 
-getlvname() {
-       lvs lvdisplay lvvars "$1"
+vg_name=
+exportpv() {
+       local reports rep pv pvs
+       vg_name=
+       json_init
+       json_load "$(pvs -o vg_name -S "pv_name=~^/dev/$rootdev.*\$")"
+       json_select report
+       json_get_keys reports
+       for rep in $reports; do
+               json_select "$rep"
+               json_select pv
+               json_get_keys pvs
+               for pv in $pvs; do
+                       json_select "$pv"
+                       json_get_vars vg_name
+                       json_select ..
+                       break
+               done
+               json_select ..
+               break
+       done
+}
 
-       [ "$lvpath" ] && echo ${lvpath:5}
+vg_extent_size=
+vg_extent_count=
+vg_free_count=
+exportvg() {
+       local reports rep vg vgs
+       vg_extent_size=
+       vg_extent_count=
+       vg_free_count=
+       json_init
+       json_load "$(vgs -o vg_extent_size,vg_extent_count,vg_free_count -S "vg_name=$vg_name")"
+       json_select report
+       json_get_keys reports
+       for rep in $reports; do
+               json_select "$rep"
+               json_select vg
+               json_get_keys vgs
+               for vg in $vgs; do
+                       json_select "$vg"
+                       json_get_vars vg_extent_size vg_extent_count vg_free_count
+                       vg_extent_size=${vg_extent_size%B}
+                       json_select ..
+                       break
+               done
+               json_select ..
+               break
+       done
+}
+
+lv_full_name=
+lv_path=
+lv_dm_path=
+lv_size=
+exportlv() {
+       local reports rep lv lvs
+       lv_full_name=
+       lv_path=
+       lv_dm_path=
+       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_select report
+       json_get_keys reports
+       for rep in $reports; do
+               json_select "$rep"
+               json_select lv
+               json_get_keys lvs
+               for lv in $lvs; do
+                       json_select "$lv"
+                       json_get_vars lv_full_name lv_size lv_path lv_dm_path
+                       lv_size=${lv_size%B}
+                       json_select ..
+                       break
+               done
+               json_select ..
+               break
+       done
 }
 
 getdev() {
        existvol "$1" || return 1
-       readlink /dev/$(getlvname "$1")
+       exportlv "$1"
+       echo $lv_dm_path
 }
 
 getsize() {
-       lvs lvdisplay lvvars "$1"
-       [ "$lvsize" ] && echo $lvsize
+       exportlv "$1"
+       [ "$lv_size" ] && echo $lv_size
 }
 
 activatevol() {
-       LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y "$(getlvname "$1")"
+       exportlv "$1"
+       lvm_cmd lvchange -a y "$lv_full_name"
 }
 
 disactivatevol() {
-       existvol "$1" || return 1
-       LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a n "$(getlvname "$1")"
+       exportlv "$1"
+       lvm_cmd lvchange -a n "$lv_full_name"
 }
 
 getstatus() {
-       lvs lvdisplay lvvars "$1"
-       [ "$lvsize" ] || return 2
+       exportlv "$1"
+       [ "$lv_full_name" ] || return 2
        existvol "$1" || return 1
        return 0
 }
 
 createvol() {
-       local mode ret lvname
+       local mode ret
+       local volsize=$(($2))
+       [ "$volsize" ] || return 22
+       exportlv "$1"
+       [ "$lv_size" ] && return 17
+       size_ext=$((volsize / vg_extent_size))
+       [ $((size_ext * vg_extent_size)) -lt $volsize ] && size_ext=$((size_ext + 1))
+
        case "$3" in
                ro)
                        mode=r
@@ -117,53 +189,82 @@ createvol() {
                        ;;
        esac
 
-       LVM_SUPPRESS_FD_WARNINGS=1 lvcreate -p $mode -a n -y -W n -Z n -n "${3}_${1}" -L "$2" $vgname
+       lvm_cmd lvcreate -p $mode -a n -y -W n -Z n -n "${3}_${1}" -l "$size_ext" $vg_name
        ret=$?
        if [ ! $ret -eq 0 ] || [ "$mode" = "r" ]; then
                return $ret
        fi
-       lvs lvdisplay lvvars "$1"
-       [ "$lvpath" ] || return 22
-       lvname=${lvpath:5}
-       LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y /dev/$lvname || return 1
-       if [ $lvsize -gt $(( 100 * 1024 * 1024 )) ]; then
-               mkfs.f2fs -f -l "$1" $lvpath || return 1
+       exportlv "$1"
+       [ "$lv_full_name" ] || return 22
+       lvm_cmd lvchange -a y "$lv_full_name" || return 1
+       if [ $lv_size -gt $(( 100 * 1024 * 1024 )) ]; then
+               mkfs.f2fs -f -l "$1" "$lv_path" || return 1
        else
-               mke2fs -F -L "$1" $lvpath || return 1
+               mke2fs -F -L "$1" "$lv_path" || return 1
        fi
        return 0
 }
 
 removevol() {
-       local lvname="$(getlvname "$1")"
-       [ "$lvname" ] || return 2
-       LVM_SUPPRESS_FD_WARNINGS=1 lvremove -y "$(getlvname "$1")"
+       exportlv "$1"
+       [ "$lv_full_name" ] || return 2
+       lvm_cmd lvremove -y "$lv_full_name"
 }
 
 updatevol() {
-       lvs lvdisplay lvvars "$1"
-       [ "$lvpath" ] || return 2
-       [ $lvsize -ge $2 ] || return 27
-       LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y -p rw ${lvpath:5}
-       dd of=$lvpath
-       case "$lvpath" in
+       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_*)
-                       LVM_SUPPRESS_FD_WARNINGS=1 lvchange -p r ${lvpath:5}
+                       lvm_cmd lvchange -p r "$lv_full_name"
                        ;;
        esac
 }
 
-lvs pvdisplay pvvars
-lvs vgdisplay vgvars
-cmd="$1"
-shift
+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_select report
+       json_get_keys reports
+       for rep in $reports; do
+               json_select "$rep"
+               json_select lv
+               json_get_keys lvs
+               for lv in $lvs; do
+                       json_select "$lv"
+                       json_get_vars lv_name lv_size
+                       lv_mode="${lv_name:0:2}"
+                       lv_name="${lv_name:3}"
+                       lv_size=${lv_size%B}
+                       echo "$lv_name $lv_mode $lv_size"
+                       json_select ..
+               done
+               json_select ..
+               break
+       done
+}
+
+exportpv
+exportvg
+
 case "$cmd" in
+       align)
+               echo "$vg_extent_size"
+               ;;
        free)
                freebytes
                ;;
        total)
                totalbytes
                ;;
+       list)
+               listvols "$@"
+               ;;
        create)
                createvol "$@"
                ;;
index f2f2ab2248bf202fcd4e3c039559c3c9a6f232e7..28841ca0474ff94a959809fd52cc95efa74a3c48 100644 (file)
@@ -1,5 +1,13 @@
 #!/bin/sh
 
+cmd="$1"
+shift
+
+if [ "$cmd" = "name" ]; then
+       echo "UBI"
+       return 0
+fi
+
 test -e /sys/class/ubi/version || return 0
 read ubiver < /sys/class/ubi/version
 [ "$ubiver" = "1" ] || return 1
@@ -65,8 +73,8 @@ getuserdev() {
 }
 
 createvol() {
-       local mode
-       local existdev=$(getdev "$1")
+       local mode ret
+       local existdev=$(getdev "$@")
        [ "$existdev" ] && return 17
        case "$3" in
                ro)
@@ -80,6 +88,9 @@ createvol() {
                        ;;
        esac
        ubimkvol /dev/$ubidev -N "uvol-$mode-$1" -s "$2"
+       ret=$?
+       [ $ret -eq 0 ] || return $ret
+       ubiupdatevol -t /dev/$(getdev "$@")
 }
 
 removevol() {
@@ -120,15 +131,37 @@ getstatus() {
        return 0
 }
 
-cmd="$1"
-shift
+listvols() {
+       local volname volmode volsize
+       for voldir in /sys/devices/virtual/ubi/${ubidev}/${ubidev}_*; do
+               read volname < $voldir/name
+               case "$volname" in
+                       uvol-r[wo]*)
+                               read volsize < $voldir/data_bytes
+                               ;;
+                       *)
+                               continue
+                               ;;
+               esac
+               volmode=${volname:5:2}
+               volname=${volname:8}
+               echo "$volname $volmode $volsize"
+       done
+}
+
 case "$cmd" in
+       align)
+               echo "$ebsize"
+               ;;
        free)
                freebytes
                ;;
        total)
                totalbytes
                ;;
+       list)
+               listvols "$@"
+               ;;
        create)
                createvol "$@"
                ;;
index 89c6518c86fd96fe3c307823ef38b6143502ad5e..58d08f07e10f9a0455afe0ebecaee276d5dd36e3 100644 (file)
@@ -1,9 +1,52 @@
 #!/bin/sh
 
+# 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
+
+if [ -z "$1" ]; then cat <<EOF
+uvol storage volume manager
+
+syntax: uvol command ...
+
+commands:
+  free                         show number of bytes available
+  total                                show total number of bytes
+  align                                show sector size in bytes
+  list [volname]               list volumes
+  create volname type size     create new volume
+    type: 'ro' or 'rw'
+    size: in bytes
+  remove volname               delete volume
+  device volname               show block device for mounting
+  size volname                 show size of volume
+  up volname                   get volume ready for mounting
+  down volname                 take volume down after unmounting
+  status volname               return status of volume
+    return code: 0 - volume is ready for use
+                 1 - volume is not ready for use
+                 2 - volume doesn'y exist
+  write volname size           write to volume from stdin, size in bytes
+EOF
+       return 22
+fi
+
 uvol_backend=
+backends_tried=
+
 for backend in /usr/libexec/uvol/*.sh; do
        total=$($backend total)
+       backends_tried="$backends_tried $($backend name)"
        [ "$total" ] && uvol_backend=$backend
 done
 
+if [ -z "$uvol_backend" ]; then
+       echo "No backend available. (tried:$backends_tried)"
+       echo "To setup devices with block storage install 'autopart'."
+       return 2
+fi
+
 flock -x /tmp/run/uvol.lock $uvol_backend "$@"
git clone https://git.99rst.org/PROJECT