blob: 40003a13367b18a9b4d337fd95dd1c7fb0b8bae6 [file] [log] [blame]
Sarthak Kukreti6cd83222020-09-28 05:23:39 -07001#!/bin/sh
2# Copyright 2020 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# This script contains common helper functions to use with LVM-based stateful
7# partitions. These helpers are useful for both install and startup
8# scripts.
9
10# Fetches the volume group name on the device. Empty if the device is not a
11# valid physical volume or if it doesn't have a volume group set up on it.
12get_volume_group() {
13 local physical_volume="$1"
14
15 pvdisplay -C --quiet --noheadings --separator '|' \
16 -o vg_name "${physical_volume}" | tr -d '[:space:]'
17}
18
19# Generate a random label, used for volume group name generation.
20generate_random_label() {
21 local n
22 for n in $(od -A none -tu1 -N16 /dev/urandom); do
23 # 36 doesn't evenly divide 256 so there's slight bias here.
24 n=$(( n % 36 ))
25 if [ "${n}" -lt "10" ]; then
26 # shellcheck disable=SC2059
27 printf "${n}"
28 else
29 # shellcheck disable=SC2059
30 printf "\\$(printf '%03o' $((n - 10 + 0x41)))"
31 fi
32 done
33}
34
35# Try to validate the volume group name: if another volume group exists with the
36# same name, regenerate the volume group name. Bail out after 5 tries.
37generate_random_vg_name() {
38 local vg_name
39 local _
40
41 for _ in 1 2 3 4 5; do
42 vg_name="$(generate_random_label)"
43 # If there is no volume group on the device with the generated vg name
44 # return.
45 if ! sudo vgdisplay "${vg_name}" >/dev/null; then
46 # shellcheck disable=SC2059
47 printf "${vg_name}"
48 return
49 fi
50 done
51}
52
53# Gets device size in bytes.
54get_device_size() {
55 local device="$1"
56 blockdev --getsize64 "${device}"
57}
58
59# With multiple logical volumes per user, we need more than 1 physical extent to
60# store the physical volume metadata. Therefore, there may not be enough space
61# to store the data for O(100) logical volumes. We set aside 4 physical extents
62# (the default PE size is 4MB). Additionally, we need to set aside some space
63# the thinpool's metadata. thin_metadata_size estimates the metadata size for
64# storing a maximum of 200 logical volumes as <2% of the size of the thinpool.
65get_thinpool_size() {
66 local physical_volume="$1"
67 echo $(( $(get_device_size "${physical_volume}") * 98 / (100 * 1024 * 1024) ))
68}
69
70# Thin provisioning tools uses a util to calculate what the metadata size should
71# for give a device and maximum number of thinpools associated with the device.
72get_thinpool_metadata_size() {
73 local thinpool_size="$1"
74
75 thin_metadata_size --block-size 4k --pool-size "${thinpool_size}M" \
76 --max-thins 200 --numeric-only -u M
77}
78
79# By default, create thin logical volumes at 95% of the size of the thinpool.
80get_logical_volume_size() {
81 local physical_volume="$1"
82 local thinpool_size
83
84 thinpool_size="$(get_thinpool_size "${physical_volume}")"
85 echo $(( thinpool_size * 95 / 100 ))
86}