Re: git: 4a30d7bb373c - main - growfs script: add swap partition as well as growing root
Date: Sun, 11 Dec 2022 18:52:08 UTC
Hi Mike
On Sun, Dec 11, 2022 at 07:26:46AM -0600, Mike Karels wrote:
> On 11 Dec 2022, at 4:09, Gordon Bergling wrote:
> > 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
a MFC to stable/13 would be very welcomed. Once I find the time I test
this on -CURRENT.
--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
> >>
> >
> > --
--