You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
7.0 KiB

  1. #!/bin/sh
  2. cmd="$1"
  3. shift
  4. if [ "$cmd" = "name" ]; then
  5. echo "LVM"
  6. return 0
  7. fi
  8. command -v lvm >/dev/null || return 1
  9. . /lib/functions.sh
  10. . /lib/functions/uvol.sh
  11. . /lib/upgrade/common.sh
  12. . /usr/share/libubox/jshn.sh
  13. export_bootdevice
  14. [ "$BOOTDEV_MAJOR" ] || return 1
  15. export_partdevice rootdev 0
  16. [ "$rootdev" ] || return 1
  17. case "$rootdev" in
  18. mtd*|\
  19. ram*|\
  20. ubi*)
  21. return 1
  22. esac
  23. lvm_cmd() {
  24. local cmd="$1"
  25. shift
  26. LVM_SUPPRESS_FD_WARNINGS=1 lvm "$cmd" "$@"
  27. return $?
  28. }
  29. pvs() {
  30. lvm_cmd pvs --reportformat json --units b "$@"
  31. }
  32. vgs() {
  33. lvm_cmd vgs --reportformat json --units b "$@"
  34. }
  35. lvs() {
  36. lvm_cmd lvs --reportformat json --units b "$@"
  37. }
  38. freebytes() {
  39. echo $((vg_free_count * vg_extent_size))
  40. }
  41. totalbytes() {
  42. echo $((vg_extent_count * vg_extent_size))
  43. }
  44. existvol() {
  45. [ "$1" ] || return 1
  46. test -e "/dev/$vg_name/ro_$1" || test -e "/dev/$vg_name/rw_$1"
  47. return $?
  48. }
  49. vg_name=
  50. exportpv() {
  51. local reports rep pv pvs
  52. vg_name=
  53. json_init
  54. json_load "$(pvs -o vg_name -S "pv_name=~^/dev/$rootdev.*\$")"
  55. json_select report
  56. json_get_keys reports
  57. for rep in $reports; do
  58. json_select "$rep"
  59. json_select pv
  60. json_get_keys pvs
  61. for pv in $pvs; do
  62. json_select "$pv"
  63. json_get_vars vg_name
  64. json_select ..
  65. break
  66. done
  67. json_select ..
  68. break
  69. done
  70. }
  71. vg_extent_size=
  72. vg_extent_count=
  73. vg_free_count=
  74. exportvg() {
  75. local reports rep vg vgs
  76. vg_extent_size=
  77. vg_extent_count=
  78. vg_free_count=
  79. json_init
  80. json_load "$(vgs -o vg_extent_size,vg_extent_count,vg_free_count -S "vg_name=$vg_name")"
  81. json_select report
  82. json_get_keys reports
  83. for rep in $reports; do
  84. json_select "$rep"
  85. json_select vg
  86. json_get_keys vgs
  87. for vg in $vgs; do
  88. json_select "$vg"
  89. json_get_vars vg_extent_size vg_extent_count vg_free_count
  90. vg_extent_size=${vg_extent_size%B}
  91. json_select ..
  92. break
  93. done
  94. json_select ..
  95. break
  96. done
  97. }
  98. lv_active=
  99. lv_name=
  100. lv_full_name=
  101. lv_path=
  102. lv_dm_path=
  103. lv_size=
  104. exportlv() {
  105. local reports rep lv lvs
  106. lv_active=
  107. lv_name=
  108. lv_full_name=
  109. lv_path=
  110. lv_dm_path=
  111. lv_size=
  112. json_init
  113. 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")"
  114. json_select report
  115. json_get_keys reports
  116. for rep in $reports; do
  117. json_select "$rep"
  118. json_select lv
  119. json_get_keys lvs
  120. for lv in $lvs; do
  121. json_select "$lv"
  122. json_get_vars lv_active lv_name lv_full_name lv_size lv_path lv_dm_path
  123. lv_size=${lv_size%B}
  124. json_select ..
  125. break
  126. done
  127. json_select ..
  128. break
  129. done
  130. }
  131. getdev() {
  132. local dms dm_name
  133. for dms in /sys/devices/virtual/block/dm-* ; do
  134. [ "$dms" = "/sys/devices/virtual/block/dm-*" ] && break
  135. read -r dm_name < "$dms/dm/name"
  136. [ $(basename "$lv_dm_path") = "$dm_name" ] && echo "$(basename "$dms")"
  137. done
  138. }
  139. getuserdev() {
  140. local dms dm_name
  141. existvol "$1" || return 1
  142. exportlv "$1"
  143. getdev "$@"
  144. }
  145. getsize() {
  146. exportlv "$1"
  147. [ "$lv_size" ] && echo "$lv_size"
  148. }
  149. activatevol() {
  150. exportlv "$1"
  151. [ "$lv_path" ] || return 2
  152. case "$lv_path" in
  153. /dev/*/wo_*|\
  154. /dev/*/wp_*)
  155. return 22
  156. ;;
  157. *)
  158. [ "$lv_active" = "active" ] && return 0
  159. uvol_uci_commit "$1"
  160. lvm_cmd lvchange -a y "$lv_full_name" || return $?
  161. lvm_cmd lvchange -k n "$lv_full_name" || return $?
  162. return 0
  163. ;;
  164. esac
  165. }
  166. disactivatevol() {
  167. exportlv "$1"
  168. local devname
  169. [ "$lv_path" ] || return 2
  170. case "$lv_path" in
  171. /dev/*/wo_*|\
  172. /dev/*/wp_*)
  173. return 22
  174. ;;
  175. *)
  176. [ "$lv_active" = "active" ] || return 0
  177. devname="$(getdev "$1")"
  178. [ "$devname" ] && /sbin/block umount "$devname"
  179. lvm_cmd lvchange -a n "$lv_full_name"
  180. lvm_cmd lvchange -k y "$lv_full_name" || return $?
  181. return 0
  182. ;;
  183. esac
  184. }
  185. getstatus() {
  186. exportlv "$1"
  187. [ "$lv_full_name" ] || return 2
  188. existvol "$1" || return 1
  189. return 0
  190. }
  191. createvol() {
  192. local mode lvmode ret
  193. local volsize=$(($2))
  194. [ "$volsize" ] || return 22
  195. exportlv "$1"
  196. [ "$lv_size" ] && return 17
  197. size_ext=$((volsize / vg_extent_size))
  198. [ $((size_ext * vg_extent_size)) -lt $volsize ] && size_ext=$((size_ext + 1))
  199. case "$3" in
  200. ro|wo)
  201. lvmode=r
  202. mode=wo
  203. ;;
  204. rw)
  205. lvmode=rw
  206. mode=wp
  207. ;;
  208. *)
  209. return 22
  210. ;;
  211. esac
  212. lvm_cmd lvcreate -p "$lvmode" -a n -y -W n -Z n -n "${mode}_$1" -l "$size_ext" "$vg_name" || return $?
  213. ret=$?
  214. if [ ! $ret -eq 0 ] || [ "$lvmode" = "r" ]; then
  215. return $ret
  216. fi
  217. exportlv "$1"
  218. [ "$lv_full_name" ] || return 22
  219. lvm_cmd lvchange -a y "$lv_full_name" || return $?
  220. if [ "$lv_size" -gt $(( 100 * 1024 * 1024 )) ]; then
  221. mkfs.f2fs -f -l "$1" "$lv_path"
  222. ret=$?
  223. [ $ret != 0 ] && [ $ret != 134 ] && {
  224. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  225. return $ret
  226. }
  227. else
  228. mke2fs -F -L "$1" "$lv_path" || {
  229. ret=$?
  230. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  231. return $ret
  232. }
  233. fi
  234. uvol_uci_add "$1" "/dev/$(getdev "$1")" "rw"
  235. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  236. lvm_cmd lvrename "$vg_name" "wp_$1" "rw_$1" || return $?
  237. return 0
  238. }
  239. removevol() {
  240. exportlv "$1"
  241. [ "$lv_full_name" ] || return 2
  242. [ "$lv_active" = "active" ] && return 16
  243. lvm_cmd lvremove -y "$lv_full_name" || return $?
  244. uvol_uci_remove "$1"
  245. uvol_uci_commit "$1"
  246. }
  247. updatevol() {
  248. exportlv "$1"
  249. [ "$lv_full_name" ] || return 2
  250. [ "$lv_size" -ge "$2" ] || return 27
  251. case "$lv_path" in
  252. /dev/*/wo_*)
  253. lvm_cmd lvchange -p rw "$lv_full_name" || return $?
  254. lvm_cmd lvchange -a y "$lv_full_name" || return $?
  255. dd of="$lv_path"
  256. uvol_uci_add "$1" "/dev/$(getdev "$1")" "ro"
  257. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  258. lvm_cmd lvchange -p r "$lv_full_name" || return $?
  259. lvm_cmd lvrename "$lv_full_name" "${lv_full_name%%/*}/ro_$1" || return $?
  260. return 0
  261. ;;
  262. default)
  263. return 22
  264. ;;
  265. esac
  266. }
  267. listvols() {
  268. local reports rep lv lvs lv_name lv_size lv_mode volname
  269. volname=${1:-.*}
  270. json_init
  271. json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^[rw][owp]_$volname\$ && vg_name=$vg_name")"
  272. json_select report
  273. json_get_keys reports
  274. for rep in $reports; do
  275. json_select "$rep"
  276. json_select lv
  277. json_get_keys lvs
  278. for lv in $lvs; do
  279. json_select "$lv"
  280. json_get_vars lv_name lv_size
  281. lv_mode="${lv_name:0:2}"
  282. lv_name="${lv_name:3}"
  283. lv_size=${lv_size%B}
  284. echo "$lv_name $lv_mode $lv_size"
  285. json_select ..
  286. done
  287. json_select ..
  288. break
  289. done
  290. }
  291. boot() {
  292. local reports rep lv lvs lv_name lv_dm_path lv_mode volname
  293. json_init
  294. json_load "$(lvs -o lv_name,lv_dm_path -S "lv_name=~^[rw][ow]_.*\$ && vg_name=$vg_name && lv_active=active")"
  295. json_select report
  296. json_get_keys reports
  297. for rep in $reports; do
  298. json_select "$rep"
  299. json_select lv
  300. json_get_keys lvs
  301. for lv in $lvs; do
  302. json_select "$lv"
  303. json_get_vars lv_name lv_dm_path
  304. lv_mode="${lv_name:0:2}"
  305. lv_name="${lv_name:3}"
  306. json_select ..
  307. done
  308. json_select ..
  309. break
  310. done
  311. }
  312. exportpv
  313. exportvg
  314. case "$cmd" in
  315. align)
  316. echo "$vg_extent_size"
  317. ;;
  318. free)
  319. freebytes
  320. ;;
  321. total)
  322. totalbytes
  323. ;;
  324. boot)
  325. boot
  326. ;;
  327. list)
  328. listvols "$@"
  329. ;;
  330. create)
  331. createvol "$@"
  332. ;;
  333. remove)
  334. removevol "$@"
  335. ;;
  336. device)
  337. getuserdev "$@"
  338. ;;
  339. size)
  340. getsize "$@"
  341. ;;
  342. up)
  343. activatevol "$@"
  344. ;;
  345. down)
  346. disactivatevol "$@"
  347. ;;
  348. status)
  349. getstatus "$@"
  350. ;;
  351. write)
  352. updatevol "$@"
  353. ;;
  354. *)
  355. echo "unknown command"
  356. return 1
  357. ;;
  358. esac