openwrt-packages/utils/uvol/files/lvm.sh

455 lines
8.5 KiB
Bash

#!/bin/sh
cmd="$1"
shift
if [ "$cmd" = "name" ]; then
echo "LVM"
return 0
fi
command -v lvm >/dev/null || return 1
. /lib/functions.sh
. /lib/functions/uvol.sh
. /lib/upgrade/common.sh
. /usr/share/libubox/jshn.sh
export_bootdevice
[ "$BOOTDEV_MAJOR" ] || return 1
export_partdevice rootdev 0
[ "$rootdev" ] || return 1
case "$rootdev" in
mtd*|\
ram*|\
ubi*)
return 1
esac
lvm_cmd() {
local cmd="$1"
shift
LVM_SUPPRESS_FD_WARNINGS=1 lvm "$cmd" "$@"
return $?
}
pvs() {
lvm_cmd pvs --reportformat json --units b "$@"
}
vgs() {
lvm_cmd vgs --reportformat json --units b "$@"
}
lvs() {
lvm_cmd lvs --reportformat json --units b "$@"
}
freebytes() {
echo $((vg_free_count * vg_extent_size))
}
totalbytes() {
echo $((vg_extent_count * vg_extent_size))
}
existvol() {
[ "$1" ] || return 1
test -e "/dev/$vg_name/ro_$1" || test -e "/dev/$vg_name/rw_$1"
return $?
}
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
}
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_active=
lv_name=
lv_full_name=
lv_path=
lv_dm_path=
lv_size=
exportlv() {
local reports rep lv lvs
lv_active=
lv_name=
lv_full_name=
lv_path=
lv_dm_path=
lv_size=
json_init
json_load "$(lvs -o lv_active,lv_name,lv_full_name,lv_size,lv_path,lv_dm_path -S "lv_name=~^[rw][owp]_$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_active lv_name lv_full_name lv_size lv_path lv_dm_path
lv_size=${lv_size%B}
json_select ..
break
done
json_select ..
break
done
}
getdev() {
local dms dm_name
for dms in /sys/devices/virtual/block/dm-* ; do
[ "$dms" = "/sys/devices/virtual/block/dm-*" ] && break
read -r dm_name < "$dms/dm/name"
[ $(basename "$lv_dm_path") = "$dm_name" ] && echo "$(basename "$dms")"
done
}
getuserdev() {
local dms dm_name
existvol "$1" || return 1
exportlv "$1"
getdev "$@"
}
getsize() {
exportlv "$1"
[ "$lv_size" ] && echo "$lv_size"
}
activatevol() {
exportlv "$1"
[ "$lv_path" ] || return 2
case "$lv_path" in
/dev/*/wo_*|\
/dev/*/wp_*)
return 22
;;
*)
uvol_uci_commit "$1"
[ "$lv_active" = "active" ] && return 0
lvm_cmd lvchange -k n "$lv_full_name" || return $?
lvm_cmd lvchange -a y "$lv_full_name" || return $?
return 0
;;
esac
}
disactivatevol() {
exportlv "$1"
local devname
[ "$lv_path" ] || return 2
case "$lv_path" in
/dev/*/wo_*|\
/dev/*/wp_*)
return 22
;;
*)
[ "$lv_active" = "active" ] || return 0
devname="$(getdev "$1")"
[ "$devname" ] && /sbin/block umount "$devname"
lvm_cmd lvchange -a n "$lv_full_name"
lvm_cmd lvchange -k y "$lv_full_name" || return $?
return 0
;;
esac
}
getstatus() {
exportlv "$1"
[ "$lv_full_name" ] || return 2
existvol "$1" || return 1
return 0
}
createvol() {
local mode lvmode 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|wo)
lvmode=r
mode=wo
;;
rw)
lvmode=rw
mode=wp
;;
*)
return 22
;;
esac
lvm_cmd lvcreate -p "$lvmode" -a n -y -W n -Z n -n "${mode}_$1" -l "$size_ext" "$vg_name" || return $?
ret=$?
if [ ! $ret -eq 0 ] || [ "$lvmode" = "r" ]; then
return $ret
fi
exportlv "$1"
[ "$lv_full_name" ] || return 22
lvm_cmd lvchange -a y "$lv_full_name" || return $?
if [ "$lv_size" -gt $(( 100 * 1024 * 1024 )) ]; then
mkfs.f2fs -f -l "$1" "$lv_path"
ret=$?
[ $ret != 0 ] && [ $ret != 134 ] && {
lvm_cmd lvchange -a n "$lv_full_name" || return $?
return $ret
}
else
mke2fs -F -L "$1" "$lv_path" || {
ret=$?
lvm_cmd lvchange -a n "$lv_full_name" || return $?
return $ret
}
fi
uvol_uci_add "$1" "/dev/$(getdev "$1")" "rw"
lvm_cmd lvchange -a n "$lv_full_name" || return $?
lvm_cmd lvrename "$vg_name" "wp_$1" "rw_$1" || return $?
return 0
}
removevol() {
exportlv "$1"
[ "$lv_full_name" ] || return 2
[ "$lv_active" = "active" ] && return 16
lvm_cmd lvremove -y "$lv_full_name" || return $?
uvol_uci_remove "$1"
uvol_uci_commit "$1"
}
updatevol() {
exportlv "$1"
[ "$lv_full_name" ] || return 2
[ "$lv_size" -ge "$2" ] || return 27
case "$lv_path" in
/dev/*/wo_*)
lvm_cmd lvchange -p rw "$lv_full_name" || return $?
lvm_cmd lvchange -a y "$lv_full_name" || return $?
dd of="$lv_path"
uvol_uci_add "$1" "/dev/$(getdev "$1")" "ro"
lvm_cmd lvchange -a n "$lv_full_name" || return $?
lvm_cmd lvchange -p r "$lv_full_name" || return $?
lvm_cmd lvrename "$lv_full_name" "${lv_full_name%%/*}/ro_$1" || return $?
return 0
;;
default)
return 22
;;
esac
}
listvols() {
local reports rep lv lvs lv_name lv_size lv_mode volname json_output json_notfirst
if [ "$1" = "-j" ]; then
json_output=1
echo "["
shift
fi
volname=${1:-.*}
json_init
json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^[rw][owp]_$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}
if [ "$json_output" = "1" ]; then
[ "$json_notfirst" = "1" ] && echo ","
echo -e "\t{"
echo -e "\t\t\"name\": \"$lv_name\","
echo -e "\t\t\"mode\": \"$lv_mode\","
echo -e "\t\t\"size\": $lv_size"
echo -n -e "\t}"
json_notfirst=1
else
echo "$lv_name $lv_mode $lv_size"
fi
json_select ..
done
json_select ..
break
done
if [ "$json_output" = "1" ]; then
[ "$json_notfirst" = "1" ] && echo
echo "]"
fi
}
detect() {
local reports rep lv lvs lv_name lv_full_name lv_mode volname devname lv_skip_activation
local temp_up=""
json_init
json_load "$(lvs -o lv_full_name -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name && lv_skip_activation!=0")"
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
echo "lvchange -a y $lv_full_name"
lvm_cmd lvchange -k n "$lv_full_name"
lvm_cmd lvchange -a y "$lv_full_name"
temp_up="$temp_up $lv_full_name"
json_select ..
done
json_select ..
break
done
sleep 1
uvol_uci_init
json_init
json_load "$(lvs -o lv_name,lv_dm_path -S "lv_name=~^[rw][owp]_.*\$ && 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_dm_path
lv_mode="${lv_name:0:2}"
lv_name="${lv_name:3}"
echo uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
json_select ..
done
json_select ..
break
done
uvol_uci_commit
for lv_full_name in $temp_up; do
echo "lvchange -a n $lv_full_name"
lvm_cmd lvchange -a n "$lv_full_name"
lvm_cmd lvchange -k y "$lv_full_name"
done
}
boot() {
true ; # nothing to do, lvm does it all for us
}
exportpv
exportvg
case "$cmd" in
align)
echo "$vg_extent_size"
;;
free)
freebytes
;;
total)
totalbytes
;;
detect)
detect
;;
boot)
boot
;;
list)
listvols "$@"
;;
create)
createvol "$@"
;;
remove)
removevol "$@"
;;
device)
getuserdev "$@"
;;
size)
getsize "$@"
;;
up)
activatevol "$@"
;;
down)
disactivatevol "$@"
;;
status)
getstatus "$@"
;;
write)
updatevol "$@"
;;
*)
echo "unknown command"
return 1
;;
esac