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.

454 lines
8.5 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. uvol_uci_commit "$1"
  159. [ "$lv_active" = "active" ] && return 0
  160. lvm_cmd lvchange -k n "$lv_full_name" || return $?
  161. lvm_cmd lvchange -a y "$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 json_output json_notfirst
  269. if [ "$1" = "-j" ]; then
  270. json_output=1
  271. echo "["
  272. shift
  273. fi
  274. volname=${1:-.*}
  275. json_init
  276. json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^[rw][owp]_$volname\$ && vg_name=$vg_name")"
  277. json_select report
  278. json_get_keys reports
  279. for rep in $reports; do
  280. json_select "$rep"
  281. json_select lv
  282. json_get_keys lvs
  283. for lv in $lvs; do
  284. json_select "$lv"
  285. json_get_vars lv_name lv_size
  286. lv_mode="${lv_name:0:2}"
  287. lv_name="${lv_name:3}"
  288. lv_size=${lv_size%B}
  289. if [ "$json_output" = "1" ]; then
  290. [ "$json_notfirst" = "1" ] && echo ","
  291. echo -e "\t{"
  292. echo -e "\t\t\"name\": \"$lv_name\","
  293. echo -e "\t\t\"mode\": \"$lv_mode\","
  294. echo -e "\t\t\"size\": $lv_size"
  295. echo -n -e "\t}"
  296. json_notfirst=1
  297. else
  298. echo "$lv_name $lv_mode $lv_size"
  299. fi
  300. json_select ..
  301. done
  302. json_select ..
  303. break
  304. done
  305. if [ "$json_output" = "1" ]; then
  306. [ "$json_notfirst" = "1" ] && echo
  307. echo "]"
  308. fi
  309. }
  310. detect() {
  311. local reports rep lv lvs lv_name lv_full_name lv_mode volname devname lv_skip_activation
  312. local temp_up=""
  313. json_init
  314. json_load "$(lvs -o lv_full_name -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name && lv_skip_activation!=0")"
  315. json_select report
  316. json_get_keys reports
  317. for rep in $reports; do
  318. json_select "$rep"
  319. json_select lv
  320. json_get_keys lvs
  321. for lv in $lvs; do
  322. json_select "$lv"
  323. json_get_vars lv_full_name
  324. echo "lvchange -a y $lv_full_name"
  325. lvm_cmd lvchange -k n "$lv_full_name"
  326. lvm_cmd lvchange -a y "$lv_full_name"
  327. temp_up="$temp_up $lv_full_name"
  328. json_select ..
  329. done
  330. json_select ..
  331. break
  332. done
  333. sleep 1
  334. uvol_uci_init
  335. json_init
  336. json_load "$(lvs -o lv_name,lv_dm_path -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name")"
  337. json_select report
  338. json_get_keys reports
  339. for rep in $reports; do
  340. json_select "$rep"
  341. json_select lv
  342. json_get_keys lvs
  343. for lv in $lvs; do
  344. json_select "$lv"
  345. json_get_vars lv_name lv_dm_path
  346. lv_mode="${lv_name:0:2}"
  347. lv_name="${lv_name:3}"
  348. echo uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
  349. uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
  350. json_select ..
  351. done
  352. json_select ..
  353. break
  354. done
  355. uvol_uci_commit
  356. for lv_full_name in $temp_up; do
  357. echo "lvchange -a n $lv_full_name"
  358. lvm_cmd lvchange -a n "$lv_full_name"
  359. lvm_cmd lvchange -k y "$lv_full_name"
  360. done
  361. }
  362. boot() {
  363. true ; # nothing to do, lvm does it all for us
  364. }
  365. exportpv
  366. exportvg
  367. case "$cmd" in
  368. align)
  369. echo "$vg_extent_size"
  370. ;;
  371. free)
  372. freebytes
  373. ;;
  374. total)
  375. totalbytes
  376. ;;
  377. detect)
  378. detect
  379. ;;
  380. boot)
  381. boot
  382. ;;
  383. list)
  384. listvols "$@"
  385. ;;
  386. create)
  387. createvol "$@"
  388. ;;
  389. remove)
  390. removevol "$@"
  391. ;;
  392. device)
  393. getuserdev "$@"
  394. ;;
  395. size)
  396. getsize "$@"
  397. ;;
  398. up)
  399. activatevol "$@"
  400. ;;
  401. down)
  402. disactivatevol "$@"
  403. ;;
  404. status)
  405. getstatus "$@"
  406. ;;
  407. write)
  408. updatevol "$@"
  409. ;;
  410. *)
  411. echo "unknown command"
  412. return 1
  413. ;;
  414. esac