Re: git: 4a30d7bb373c - main - growfs script: add swap partition as well as growing root
Date: Sun, 11 Dec 2022 13:26:46 UTC
On 11 Dec 2022, at 4:09, Gordon Bergling wrote:
> Hi Mike,
>
> thanks for implementation. After the MFC and the new -STABLE snapshots
> I am really looking forward to try this out an my RPi4B.
You are welcome, but I hadn’t decided yet whether this should be MFC’d.
That depends in part on how it seems to work out, but I am interested
in opinions on that.
Mike
> --Gordon
>
> On Sat, Dec 10, 2022 at 07:41:13PM +0000, Mike Karels wrote:
>> The branch main has been updated by karels:
>>
>> URL: https://cgit.FreeBSD.org/src/commit/?id=4a30d7bb373c08f42f953b9cd1e793e236b4cd92
>>
>> commit 4a30d7bb373c08f42f953b9cd1e793e236b4cd92
>> Author: Mike Karels <karels@FreeBSD.org>
>> AuthorDate: 2022-12-10 19:38:36 +0000
>> Commit: Mike Karels <karels@FreeBSD.org>
>> CommitDate: 2022-12-10 19:38:36 +0000
>>
>> growfs script: add swap partition as well as growing root
>>
>> Add the ability to create a swap partition in the course of growing
>> the root file system on first boot, enabling by default. The default
>> rules are: add swap if the disk is at least 15 GB (decimal), and the
>> existing root is less than 40% of the disk. The default size is 10%
>> of the disk, but is limited by the memory size. The limit is twice
>> memory size up to 4 GB, 8 GB up to 8 GB memory, and memory size over
>> 8 GB memory. Swap size is clamped at vm.swap_maxpages/2 as well.
>> The new swap partition is labeled as "growfs_swap".
>>
>> The default behavior can be overridden by setting growfs_swap_size in
>> /etc/rc.conf or in the kernel environment, with kenv taking priority.
>> A value of 0 inhibits the addition of swap, an empty value specifies
>> the default, and other values indicate a swap size in bytes.
>>
>> By default, addition of swap is inhibited if a swap partition is found
>> in the output of the sysctl kern.geom.conftxt before the current root
>> partition, usually meaning that there is another disk present.
>> Swap space is not added if one is already present in /etc/fstab.
>>
>> The root partition is read-only when growfs runs, so /etc/fstab can
>> not be modified. That step is handled by a new growfs_fstab script,
>> added in a separate commit. Set the value "growfs_swap_pdev" in kenv
>> to indicate that this should be done, as well as for internal use.
>>
>> There is optional verbose output meant for debugging; it can only be
>> enabled by modifying the script (in two places, for sh and awk).
>> This should be removed before release, after testing on -current.
>>
>> Discussed with: cperciva
>> Reviewed by: imp (previous version)
>> Differential Revision: https://reviews.freebsd.org/D37462
>> ---
>> libexec/rc/rc.d/growfs | 178 +++++++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 172 insertions(+), 6 deletions(-)
>>
>> diff --git a/libexec/rc/rc.d/growfs b/libexec/rc/rc.d/growfs
>> index 5402bd442279..3c48a7dca6b2 100755
>> --- a/libexec/rc/rc.d/growfs
>> +++ b/libexec/rc/rc.d/growfs
>> @@ -1,5 +1,6 @@
>> #!/bin/sh
>> #
>> +# Copyright 2022 Michael J. Karels
>> # Copyright 2014 John-Mark Gurney
>> # All rights reserved.
>> #
>> @@ -32,8 +33,9 @@
>> # BEFORE: root
>> # KEYWORD: firstboot
>>
>> -# This allows us to distribute an image
>> -# and have it work on essentially any size drive.
>> +# Grow root partition to fill available space, optionally adding a swap
>> +# partition at the end. This allows us to distribute an image and
>> +# have it work on essentially any size drive.
>>
>> # Note that this uses awk(1), and thus will not work if /usr is on a separate
>> # filesystem. We need to run early, because there might be not enough free
>> @@ -48,7 +50,7 @@ start_cmd="growfs_start"
>> stop_cmd=":"
>> rcvar="growfs_enable"
>>
>> -growfs_get_diskdev ()
>> +growfs_get_diskdev()
>> {
>> local _search=${1}
>> sysctl -b kern.geom.conftxt |
>> @@ -61,8 +63,51 @@ growfs_get_diskdev ()
>> done
>> }
>>
>> -growfs_start ()
>> +# Compute upper bound on swap partition size (if added), based on physmem
>> +# and vm.swap_maxpages / 2 (the limit that elicits a warning).
>> +# Rule for swap size based on memory size:
>> +# up to 4 GB twice memory size
>> +# 4 GB - 8 GB 8 GB
>> +# over 8 GB memory size
>> +growfs_swap_max()
>> {
>> + memsize=$(sysctl -n hw.physmem)
>> + memsizeMB=$(($memsize / (1024 * 1024)))
>> +
>> + if [ $memsizeMB -lt 4096 ]
>> + then
>> + swapmax=$(($memsize * 2))
>> + elif [ $memsizeMB -lt 8192 ]
>> + then
>> + swapmax=$((8192 * 1024 * 1024))
>> + else
>> + swapmax=$memsize
>> + fi
>> +
>> + pagesize=$(sysctl -n hw.pagesize)
>> + vm_swap_max=$(($(sysctl -n vm.swap_maxpages) / 2 * $pagesize))
>> +
>> + if [ $swapmax -gt $vm_swap_max ]
>> + then
>> + $swapmax=$vm_swap_max
>> + fi
>> + echo -n "$swapmax"
>> +}
>> +
>> +# Find newly-added swap partition on parent device ($1).
>> +growfs_last_swap()
>> +{
>> + swapdev=$(gpart list $1 | awk '
>> + $2 == "Name:" { dev = $3 }
>> + $1 == "type:" && $2 == "freebsd-swap" { swapdev = dev }
>> + END { print swapdev }
>> + ')
>> + echo -n $swapdev
>> +}
>> +
>> +growfs_start()
>> +{
>> + verbose=0
>> echo "Growing root partition to fill device"
>> FSTYPE=$(mount -p | awk '{ if ( $2 == "/") { print $3 }}')
>> FSDEV=$(mount -p | awk '{ if ( $2 == "/") { print $1 }}')
>> @@ -100,19 +145,126 @@ growfs_start ()
>> diskdev=${rootdev}
>> fi
>>
>> + # Check kenv for growfs_swap_size; if not present,
>> + # check $growfs_swap_size from /etc/rc.conf.
>> + # A value of 0 suppresses swap addition,
>> + # "" (or unset) specifies the default;
>> + # other values indicate the size in bytes.
>> + # If default, check whether swap is already in fstab;
>> + # if so, don't add another.
>> + addswap=1
>> + swapsize="$(kenv -q growfs_swap_size 2>/dev/null)"
>> + case "$swapsize" in
>> + "0") addswap=0
>> + ;;
>> + "") case "$growfs_swap_size" in
>> + "0") addswap=0
>> + ;;
>> + "")
>> + if ! awk '
>> + /^#/ { next }
>> + $3 == "swap" { exit 1 }
>> + ' < /etc/fstab
>> + then
>> + addswap=0
>> + fi
>> + ;;
>> + *) swapsize="$growfs_swap_size"
>> + ;;
>> + esac
>> + ;;
>> + *) ;;
>> + esac
>> +
>> + swaplim=$(growfs_swap_max)
>> +
>> + [ $verbose -eq 1 ] && {
>> + echo "diskdev is $diskdev"
>> + echo "search is $search"
>> + echo "swapsize is $swapsize"
>> + echo "swaplim is $swaplim"
>> + }
>> +
>> sysctl -b kern.geom.conftxt | awk '
>> {
>> + verbose = 0
>> lvl=$1
>> device[lvl] = $3
>> type[lvl] = $2
>> idx[lvl] = $7
>> + offset[lvl] = $9
>> parttype[lvl] = $13
>> + size[lvl] = $4
>> + if (verbose) print lvl, type[lvl], $3
>> + if (type[lvl] == "DISK") {
>> + disksize = size[lvl]
>> + if (verbose)
>> + print "disksize ", disksize
>> + # Don't add swap on disks under 15 GB (decimal) by default.
>> + if (addswap == 1 && (size[lvl] > 15000000000 || swapsize > 0))
>> + doing_swap = 1
>> + else
>> + doing_swap = 0
>> + } else if (type[lvl] == "PART" && $11 == "freebsd-swap" && \
>> + int(swapsize) == 0) {
>> + # This finds swap only if it precedes root, e.g. preceding disk.
>> + addswap = 0
>> + doing_swap = 0
>> + print "swap device exists, not adding swap"
>> + }
>> if (dev == $3) {
>> for (i = 1; i <= lvl; i++) {
>> # resize
>> if (type[i] == "PART") {
>> pdev = device[i - 1]
>> - cmd[i] = "gpart resize -i " idx[i] " " pdev
>> + if (verbose)
>> + print i, pdev, addswap, disksize, \
>> + doing_swap
>> + swapcmd = ""
>> + # Allow swap if current root is < 40% of disk.
>> + if (parttype[i] != "MBR" && doing_swap == 1 && \
>> + (size[i] / disksize < 0.4 || \
>> + swapsize > 0)) {
>> + print "Adding swap partition"
>> + if (int(swapsize) == 0) {
>> + swapsize = int(disksize / 10)
>> + if (swapsize > swaplim)
>> + swapsize = swaplim
>> + }
>> + sector = $5
>> + swapsize /= sector
>> + if (verbose)
>> + print "swapsize sectors",
>> + swapsize
>> + align = 4 * 1024 * 1024 / sector
>> +
>> + # Estimate offset for swap; let
>> + # gpart compute actual start and size.
>> + # Assume expansion all goes into this
>> + # partition for MBR case.
>> + if (parttype[i - 1] == "MBR") {
>> + if (verbose)
>> + print "sz ", size[i - 1], \
>> + " off ", offset[i - 1]
>> + expand = size[0] - \
>> + (size[i - 1] + offset[i - 1])
>> + } else {
>> + if (verbose)
>> + print "sz ", size[i], \
>> + " off ", offset[i]
>> + expand = size[0] - \
>> + (size[i] + offset[i])
>> + }
>> + if (verbose)
>> + print "expand ", expand, \
>> + " sz ", size[i]
>> + swapbase = (expand + size[i]) / sector
>> + swapbase -= swapsize + align
>> + swapcmd = "gpart add -t freebsd-swap -a " align " -b " swapbase " " pdev "; kenv growfs_swap_pdev=" pdev " >/dev/null; "
>> + if (verbose)
>> + swapcmd = "set -x; " swapcmd
>> + }
>> + cmd[i] = swapcmd "gpart resize -i " idx[i] " " pdev
>> if (parttype[i] == "GPT")
>> cmd[i] = "gpart recover " pdev " ; " cmd[i]
>> } else if (type[i] == "LABEL") {
>> @@ -128,7 +280,7 @@ growfs_start ()
>> }
>> exit 0
>> }
>> -}' dev="$search"
>> +}' dev="$search" addswap="$addswap" swapsize="$swapsize" swaplim="$swaplim"
>> gpart commit "$diskdev" 2> /dev/null
>> case "$FSTYPE" in
>> ufs)
>> @@ -138,6 +290,20 @@ growfs_start ()
>> zpool online -e $pool $rootdev
>> ;;
>> esac
>> +
>> + # Get parent device of swap partition if one was added;
>> + # if so, find swap device and label it.
>> + pdev=$(kenv -q growfs_swap_pdev)
>> + if [ -n "$pdev" ]
>> + then
>> + dev=$(growfs_last_swap "$pdev")
>> + if [ -z "$dev" ]
>> + then
>> + echo "Swap partition not found on $pdev"
>> + exit 0
>> + fi
>> + glabel label -v growfs_swap $dev
>> + fi
>> }
>>
>> load_rc_config $name
>>
>
> --