uvol: some improvements

* use lvm --reportformat json
 * add 'list' and 'align' commands
 * add help output

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2021-04-11 01:41:05 +01:00
parent 231d40053b
commit a4b034cf68
No known key found for this signature in database
GPG Key ID: 5A8F39C31C3217CA
3 changed files with 250 additions and 73 deletions

View File

@ -1,15 +1,23 @@
#!/bin/sh #!/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/functions.sh
. /lib/upgrade/common.sh . /lib/upgrade/common.sh
. /usr/share/libubox/jshn.sh
export_bootdevice export_bootdevice
[ "$BOOTDEV_MAJOR" ] || return 1 [ "$BOOTDEV_MAJOR" ] || return 1
export_partdevice rootdev 0 export_partdevice rootdev 0
[ "$rootdev" ] || return 1 [ "$rootdev" ] || return 1
LVM_SUPPRESS_FD_WARNINGS=1
case "$rootdev" in case "$rootdev" in
mtd*|\ mtd*|\
@ -18,93 +26,157 @@ case "$rootdev" in
return 1 return 1
esac esac
lvs() { lvm_cmd() {
local cmd="$1" local cmd="$1"
local cb="$2" shift
local param="${3:+-S vg_name=${vgname} -S lv_name=~^r[ow]_$3\$}" LVM_SUPPRESS_FD_WARNINGS=1 lvm "$cmd" "$@"
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() { pvs() {
case "${1:5}" in lvm_cmd pvs --reportformat json --units b "$@"
"$rootdev"*)
partdev="$1"
vgname="$2"
;;
esac
} }
vgvars() { vgs() {
[ "$1" = "$vgname" ] || return lvm_cmd vgs --reportformat json --units b "$@"
vgbs="${13}"
vgts="${14}"
vgus="${15}"
vgfs="${16}"
} }
lvvars() { lvs() {
lvpath="$1" lvm_cmd vgs --reportformat json --units b "$@"
lvsize=$(( 512 * $7 ))
} }
freebytes() { freebytes() {
echo $((vgfs * vgbs * 1024)) echo $(($vg_free_count * $vg_extent_size * 1024))
} }
totalbytes() { totalbytes() {
echo $((vgts * vgbs * 1024)) echo $(($vg_extent_count * $vg_extent_size * 1024))
} }
existvol() { existvol() {
[ "$1" ] || return 1 [ "$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 $? return $?
} }
getlvname() { vg_name=
lvs lvdisplay lvvars "$1" 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() { getdev() {
existvol "$1" || return 1 existvol "$1" || return 1
readlink /dev/$(getlvname "$1") exportlv "$1"
echo $lv_dm_path
} }
getsize() { getsize() {
lvs lvdisplay lvvars "$1" exportlv "$1"
[ "$lvsize" ] && echo $lvsize [ "$lv_size" ] && echo $lv_size
} }
activatevol() { activatevol() {
LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y "$(getlvname "$1")" exportlv "$1"
lvm_cmd lvchange -a y "$lv_full_name"
} }
disactivatevol() { disactivatevol() {
existvol "$1" || return 1 exportlv "$1"
LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a n "$(getlvname "$1")" lvm_cmd lvchange -a n "$lv_full_name"
} }
getstatus() { getstatus() {
lvs lvdisplay lvvars "$1" exportlv "$1"
[ "$lvsize" ] || return 2 [ "$lv_full_name" ] || return 2
existvol "$1" || return 1 existvol "$1" || return 1
return 0 return 0
} }
createvol() { 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 case "$3" in
ro) ro)
mode=r mode=r
@ -117,53 +189,82 @@ createvol() {
;; ;;
esac 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=$? ret=$?
if [ ! $ret -eq 0 ] || [ "$mode" = "r" ]; then if [ ! $ret -eq 0 ] || [ "$mode" = "r" ]; then
return $ret return $ret
fi fi
lvs lvdisplay lvvars "$1" exportlv "$1"
[ "$lvpath" ] || return 22 [ "$lv_full_name" ] || return 22
lvname=${lvpath:5} lvm_cmd lvchange -a y "$lv_full_name" || return 1
LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y /dev/$lvname || return 1 if [ $lv_size -gt $(( 100 * 1024 * 1024 )) ]; then
if [ $lvsize -gt $(( 100 * 1024 * 1024 )) ]; then mkfs.f2fs -f -l "$1" "$lv_path" || return 1
mkfs.f2fs -f -l "$1" $lvpath || return 1
else else
mke2fs -F -L "$1" $lvpath || return 1 mke2fs -F -L "$1" "$lv_path" || return 1
fi fi
return 0 return 0
} }
removevol() { removevol() {
local lvname="$(getlvname "$1")" exportlv "$1"
[ "$lvname" ] || return 2 [ "$lv_full_name" ] || return 2
LVM_SUPPRESS_FD_WARNINGS=1 lvremove -y "$(getlvname "$1")" lvm_cmd lvremove -y "$lv_full_name"
} }
updatevol() { updatevol() {
lvs lvdisplay lvvars "$1" exportlv "$1"
[ "$lvpath" ] || return 2 [ "$lv_full_name" ] || return 2
[ $lvsize -ge $2 ] || return 27 [ $lv_size -ge $2 ] || return 27
LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y -p rw ${lvpath:5} lvm_cmd lvchange -a y -p rw "$lv_full_name"
dd of=$lvpath dd of=$lv_path
case "$lvpath" in case "$lv_path" in
/dev/*/ro_*) /dev/*/ro_*)
LVM_SUPPRESS_FD_WARNINGS=1 lvchange -p r ${lvpath:5} lvm_cmd lvchange -p r "$lv_full_name"
;; ;;
esac esac
} }
lvs pvdisplay pvvars listvols() {
lvs vgdisplay vgvars local reports rep lv lvs lv_name lv_size lv_mode volname
cmd="$1" volname=${1:-.*}
shift 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 case "$cmd" in
align)
echo "$vg_extent_size"
;;
free) free)
freebytes freebytes
;; ;;
total) total)
totalbytes totalbytes
;; ;;
list)
listvols "$@"
;;
create) create)
createvol "$@" createvol "$@"
;; ;;

View File

@ -1,5 +1,13 @@
#!/bin/sh #!/bin/sh
cmd="$1"
shift
if [ "$cmd" = "name" ]; then
echo "UBI"
return 0
fi
test -e /sys/class/ubi/version || return 0 test -e /sys/class/ubi/version || return 0
read ubiver < /sys/class/ubi/version read ubiver < /sys/class/ubi/version
[ "$ubiver" = "1" ] || return 1 [ "$ubiver" = "1" ] || return 1
@ -65,8 +73,8 @@ getuserdev() {
} }
createvol() { createvol() {
local mode local mode ret
local existdev=$(getdev "$1") local existdev=$(getdev "$@")
[ "$existdev" ] && return 17 [ "$existdev" ] && return 17
case "$3" in case "$3" in
ro) ro)
@ -80,6 +88,9 @@ createvol() {
;; ;;
esac esac
ubimkvol /dev/$ubidev -N "uvol-$mode-$1" -s "$2" ubimkvol /dev/$ubidev -N "uvol-$mode-$1" -s "$2"
ret=$?
[ $ret -eq 0 ] || return $ret
ubiupdatevol -t /dev/$(getdev "$@")
} }
removevol() { removevol() {
@ -120,15 +131,37 @@ getstatus() {
return 0 return 0
} }
cmd="$1" listvols() {
shift 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 case "$cmd" in
align)
echo "$ebsize"
;;
free) free)
freebytes freebytes
;; ;;
total) total)
totalbytes totalbytes
;; ;;
list)
listvols "$@"
;;
create) create)
createvol "$@" createvol "$@"
;; ;;

View File

@ -1,9 +1,52 @@
#!/bin/sh #!/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= uvol_backend=
backends_tried=
for backend in /usr/libexec/uvol/*.sh; do for backend in /usr/libexec/uvol/*.sh; do
total=$($backend total) total=$($backend total)
backends_tried="$backends_tried $($backend name)"
[ "$total" ] && uvol_backend=$backend [ "$total" ] && uvol_backend=$backend
done 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 "$@" flock -x /tmp/run/uvol.lock $uvol_backend "$@"