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.

459 lines
8.6 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. vg_name=
  52. config_load fstab
  53. local uvolsect="$(config_foreach echo uvol)"
  54. [ -n "$uvolsect" ] && config_get vg_name "$uvolsect" vg_name
  55. [ -n "$vg_name" ] && return
  56. local reports rep pv pvs
  57. json_init
  58. json_load "$(pvs -o vg_name -S "pv_name=~^/dev/$rootdev.*\$")"
  59. json_select report
  60. json_get_keys reports
  61. for rep in $reports; do
  62. json_select "$rep"
  63. json_select pv
  64. json_get_keys pvs
  65. for pv in $pvs; do
  66. json_select "$pv"
  67. json_get_vars vg_name
  68. json_select ..
  69. break
  70. done
  71. json_select ..
  72. break
  73. done
  74. }
  75. vg_extent_size=
  76. vg_extent_count=
  77. vg_free_count=
  78. exportvg() {
  79. local reports rep vg vgs
  80. vg_extent_size=
  81. vg_extent_count=
  82. vg_free_count=
  83. json_init
  84. json_load "$(vgs -o vg_extent_size,vg_extent_count,vg_free_count -S "vg_name=$vg_name")"
  85. json_select report
  86. json_get_keys reports
  87. for rep in $reports; do
  88. json_select "$rep"
  89. json_select vg
  90. json_get_keys vgs
  91. for vg in $vgs; do
  92. json_select "$vg"
  93. json_get_vars vg_extent_size vg_extent_count vg_free_count
  94. vg_extent_size=${vg_extent_size%B}
  95. json_select ..
  96. break
  97. done
  98. json_select ..
  99. break
  100. done
  101. }
  102. lv_active=
  103. lv_name=
  104. lv_full_name=
  105. lv_path=
  106. lv_dm_path=
  107. lv_size=
  108. exportlv() {
  109. local reports rep lv lvs
  110. lv_active=
  111. lv_name=
  112. lv_full_name=
  113. lv_path=
  114. lv_dm_path=
  115. lv_size=
  116. json_init
  117. 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")"
  118. json_select report
  119. json_get_keys reports
  120. for rep in $reports; do
  121. json_select "$rep"
  122. json_select lv
  123. json_get_keys lvs
  124. for lv in $lvs; do
  125. json_select "$lv"
  126. json_get_vars lv_active lv_name lv_full_name lv_size lv_path lv_dm_path
  127. lv_size=${lv_size%B}
  128. json_select ..
  129. break
  130. done
  131. json_select ..
  132. break
  133. done
  134. }
  135. getdev() {
  136. local dms dm_name
  137. for dms in /sys/devices/virtual/block/dm-* ; do
  138. [ "$dms" = "/sys/devices/virtual/block/dm-*" ] && break
  139. read -r dm_name < "$dms/dm/name"
  140. [ "$(basename "$lv_dm_path")" = "$dm_name" ] && basename "$dms"
  141. done
  142. }
  143. getuserdev() {
  144. local dms dm_name
  145. existvol "$1" || return 1
  146. exportlv "$1"
  147. getdev "$@"
  148. }
  149. getsize() {
  150. exportlv "$1"
  151. [ "$lv_size" ] && echo "$lv_size"
  152. }
  153. activatevol() {
  154. exportlv "$1"
  155. [ "$lv_path" ] || return 2
  156. case "$lv_path" in
  157. /dev/*/wo_*|\
  158. /dev/*/wp_*)
  159. return 22
  160. ;;
  161. *)
  162. uvol_uci_commit "$1"
  163. [ "$lv_active" = "active" ] && return 0
  164. lvm_cmd lvchange -k n "$lv_full_name" || return $?
  165. lvm_cmd lvchange -a y "$lv_full_name" || return $?
  166. return 0
  167. ;;
  168. esac
  169. }
  170. disactivatevol() {
  171. exportlv "$1"
  172. local devname
  173. [ "$lv_path" ] || return 2
  174. case "$lv_path" in
  175. /dev/*/wo_*|\
  176. /dev/*/wp_*)
  177. return 22
  178. ;;
  179. *)
  180. [ "$lv_active" = "active" ] || return 0
  181. devname="$(getdev "$1")"
  182. [ "$devname" ] && umount "/dev/$devname"
  183. lvm_cmd lvchange -a n "$lv_full_name"
  184. lvm_cmd lvchange -k y "$lv_full_name" || return $?
  185. return 0
  186. ;;
  187. esac
  188. }
  189. getstatus() {
  190. exportlv "$1"
  191. [ "$lv_full_name" ] || return 2
  192. existvol "$1" || return 1
  193. return 0
  194. }
  195. createvol() {
  196. local mode lvmode ret
  197. local volsize=$(($2))
  198. [ "$volsize" ] || return 22
  199. exportlv "$1"
  200. [ "$lv_size" ] && return 17
  201. size_ext=$((volsize / vg_extent_size))
  202. [ $((size_ext * vg_extent_size)) -lt $volsize ] && size_ext=$((size_ext + 1))
  203. case "$3" in
  204. ro|wo)
  205. lvmode=r
  206. mode=wo
  207. ;;
  208. rw)
  209. lvmode=rw
  210. mode=wp
  211. ;;
  212. *)
  213. return 22
  214. ;;
  215. esac
  216. lvm_cmd lvcreate -p "$lvmode" -a n -y -W n -Z n -n "${mode}_$1" -l "$size_ext" "$vg_name" || return $?
  217. ret=$?
  218. if [ ! $ret -eq 0 ] || [ "$lvmode" = "r" ]; then
  219. return $ret
  220. fi
  221. exportlv "$1"
  222. [ "$lv_full_name" ] || return 22
  223. lvm_cmd lvchange -a y "$lv_full_name" || return $?
  224. if [ "$lv_size" -gt $(( 100 * 1024 * 1024 )) ]; then
  225. mkfs.f2fs -f -l "$1" "$lv_path"
  226. ret=$?
  227. [ $ret != 0 ] && [ $ret != 134 ] && {
  228. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  229. return $ret
  230. }
  231. else
  232. mke2fs -F -L "$1" "$lv_path" || {
  233. ret=$?
  234. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  235. return $ret
  236. }
  237. fi
  238. uvol_uci_add "$1" "/dev/$(getdev "$1")" "rw"
  239. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  240. lvm_cmd lvrename "$vg_name" "wp_$1" "rw_$1" || return $?
  241. return 0
  242. }
  243. removevol() {
  244. exportlv "$1"
  245. [ "$lv_full_name" ] || return 2
  246. [ "$lv_active" = "active" ] && return 16
  247. lvm_cmd lvremove -y "$lv_full_name" || return $?
  248. uvol_uci_remove "$1"
  249. uvol_uci_commit "$1"
  250. }
  251. updatevol() {
  252. exportlv "$1"
  253. [ "$lv_full_name" ] || return 2
  254. [ "$lv_size" -ge "$2" ] || return 27
  255. case "$lv_path" in
  256. /dev/*/wo_*)
  257. lvm_cmd lvchange -p rw "$lv_full_name" || return $?
  258. lvm_cmd lvchange -a y "$lv_full_name" || return $?
  259. dd of="$lv_path"
  260. uvol_uci_add "$1" "/dev/$(getdev "$1")" "ro"
  261. lvm_cmd lvchange -a n "$lv_full_name" || return $?
  262. lvm_cmd lvchange -p r "$lv_full_name" || return $?
  263. lvm_cmd lvrename "$lv_full_name" "${lv_full_name%%/*}/ro_$1" || return $?
  264. return 0
  265. ;;
  266. default)
  267. return 22
  268. ;;
  269. esac
  270. }
  271. listvols() {
  272. local reports rep lv lvs lv_name lv_size lv_mode volname json_output json_notfirst
  273. if [ "$1" = "-j" ]; then
  274. json_output=1
  275. echo "["
  276. shift
  277. fi
  278. volname=${1:-.*}
  279. json_init
  280. json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^[rw][owp]_$volname\$ && vg_name=$vg_name")"
  281. json_select report
  282. json_get_keys reports
  283. for rep in $reports; do
  284. json_select "$rep"
  285. json_select lv
  286. json_get_keys lvs
  287. for lv in $lvs; do
  288. json_select "$lv"
  289. json_get_vars lv_name lv_size
  290. lv_mode="${lv_name:0:2}"
  291. lv_name="${lv_name:3}"
  292. lv_size=${lv_size%B}
  293. [ "${lv_name:0:1}" = "." ] && continue
  294. if [ "$json_output" = "1" ]; then
  295. [ "$json_notfirst" = "1" ] && echo ","
  296. echo -e "\t{"
  297. echo -e "\t\t\"name\": \"$lv_name\","
  298. echo -e "\t\t\"mode\": \"$lv_mode\","
  299. echo -e "\t\t\"size\": $lv_size"
  300. echo -n -e "\t}"
  301. json_notfirst=1
  302. else
  303. echo "$lv_name $lv_mode $lv_size"
  304. fi
  305. json_select ..
  306. done
  307. json_select ..
  308. break
  309. done
  310. if [ "$json_output" = "1" ]; then
  311. [ "$json_notfirst" = "1" ] && echo
  312. echo "]"
  313. fi
  314. }
  315. detect() {
  316. local reports rep lv lvs lv_name lv_full_name lv_mode volname devname
  317. local temp_up=""
  318. json_init
  319. json_load "$(lvs -o lv_full_name -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name && lv_skip_activation!=0")"
  320. json_select report
  321. json_get_keys reports
  322. for rep in $reports; do
  323. json_select "$rep"
  324. json_select lv
  325. json_get_keys lvs
  326. for lv in $lvs; do
  327. json_select "$lv"
  328. json_get_vars lv_full_name
  329. echo "lvchange -a y $lv_full_name"
  330. lvm_cmd lvchange -k n "$lv_full_name"
  331. lvm_cmd lvchange -a y "$lv_full_name"
  332. temp_up="$temp_up $lv_full_name"
  333. json_select ..
  334. done
  335. json_select ..
  336. break
  337. done
  338. sleep 1
  339. uvol_uci_init
  340. json_init
  341. json_load "$(lvs -o lv_name,lv_dm_path -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name")"
  342. json_select report
  343. json_get_keys reports
  344. for rep in $reports; do
  345. json_select "$rep"
  346. json_select lv
  347. json_get_keys lvs
  348. for lv in $lvs; do
  349. json_select "$lv"
  350. json_get_vars lv_name lv_dm_path
  351. lv_mode="${lv_name:0:2}"
  352. lv_name="${lv_name:3}"
  353. echo uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
  354. uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
  355. json_select ..
  356. done
  357. json_select ..
  358. break
  359. done
  360. uvol_uci_commit
  361. for lv_full_name in $temp_up; do
  362. echo "lvchange -a n $lv_full_name"
  363. lvm_cmd lvchange -a n "$lv_full_name"
  364. lvm_cmd lvchange -k y "$lv_full_name"
  365. done
  366. }
  367. boot() {
  368. true ; # nothing to do, lvm does it all for us
  369. }
  370. exportpv
  371. exportvg
  372. case "$cmd" in
  373. align)
  374. echo "$vg_extent_size"
  375. ;;
  376. free)
  377. freebytes
  378. ;;
  379. total)
  380. totalbytes
  381. ;;
  382. detect)
  383. detect
  384. ;;
  385. boot)
  386. boot
  387. ;;
  388. list)
  389. listvols "$@"
  390. ;;
  391. create)
  392. createvol "$@"
  393. ;;
  394. remove)
  395. removevol "$@"
  396. ;;
  397. device)
  398. getuserdev "$@"
  399. ;;
  400. size)
  401. getsize "$@"
  402. ;;
  403. up)
  404. activatevol "$@"
  405. ;;
  406. down)
  407. disactivatevol "$@"
  408. ;;
  409. status)
  410. getstatus "$@"
  411. ;;
  412. write)
  413. updatevol "$@"
  414. ;;
  415. *)
  416. echo "unknown command"
  417. return 1
  418. ;;
  419. esac