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.

--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 <kar...@freebsd.org>
> AuthorDate: 2022-12-10 19:38:36 +0000
> Commit:     Mike Karels <kar...@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
> 

-- 

Attachment: signature.asc
Description: PGP signature

Reply via email to