]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rc/rc.d/growfs
MFV: less v632.
[FreeBSD/FreeBSD.git] / libexec / rc / rc.d / growfs
1 #!/bin/sh
2 #
3 # Copyright 2022 Michael J. Karels
4 # Copyright 2014 John-Mark Gurney
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 #    notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 #    notice, this list of conditions and the following disclaimer in the
14 #    documentation and/or other materials provided with the distribution.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 # SUCH DAMAGE.
27 #
28 # $FreeBSD$
29 #
30
31 # PROVIDE: growfs
32 # REQUIRE: fsck
33 # BEFORE: root
34 # KEYWORD: firstboot
35
36 # Grow root partition to fill available space, optionally adding a swap
37 # partition at the end.  This allows us to distribute an image and
38 # have it work on essentially any size drive.
39
40 # Note that this uses awk(1), and thus will not work if /usr is on a separate
41 # filesystem.  We need to run early, because there might be not enough free
42 # space on rootfs for the boot to succeed, and on images we ship - which are
43 # the primary purpose of this script - there is no separate /usr anyway.
44
45 . /etc/rc.subr
46
47 name="growfs"
48 desc="Grow root partition to fill device"
49 start_cmd="growfs_start"
50 stop_cmd=":"
51 rcvar="growfs_enable"
52
53 growfs_get_diskdev()
54 {
55         local _search=${1}
56         sysctl -b kern.geom.conftxt |
57         while read x1 _type _dev line
58         do
59                 if [ "${_type}" = "DISK" -a -n "$(echo ${_search} | grep ${_dev})" ]; then
60                         echo -n ${_dev}
61                         break
62                 fi
63         done
64 }
65
66 # Compute upper bound on swap partition size (if added), based on physmem
67 # and vm.swap_maxpages / 2 (the limit that elicits a warning).
68 # Rule for swap size based on memory size:
69 #       up to 4 GB      twice memory size
70 #       4 GB - 8 GB     8 GB
71 #       over 8 GB       memory size
72 growfs_swap_max()
73 {
74         memsize=$(sysctl -n hw.physmem)
75         memsizeMB=$(($memsize / (1024 * 1024)))
76
77         if  [ $memsizeMB -lt 4096 ]
78         then
79                 swapmax=$(($memsize * 2))
80         elif  [ $memsizeMB -lt 8192 ]
81         then
82                 swapmax=$((8192 * 1024 * 1024))
83         else
84                 swapmax=$memsize
85         fi
86
87         pagesize=$(sysctl -n hw.pagesize)
88         vm_swap_max=$(($(sysctl -n vm.swap_maxpages) / 2 * $pagesize))
89
90         if [ $swapmax -gt $vm_swap_max ]
91         then
92                 swapmax=$vm_swap_max
93         fi
94         echo -n "$swapmax"
95 }
96
97 # Find newly-added swap partition on parent device ($1).
98 growfs_last_swap()
99 {
100         swapdev=$(gpart list $1 | awk '
101                 $2 == "Name:" { dev = $3 }
102                 $1 == "type:" && $2 == "freebsd-swap" { swapdev = dev }
103                 END { print swapdev }
104             ')
105         echo -n $swapdev
106 }
107
108 growfs_start()
109 {
110         verbose=0
111         echo "Growing root partition to fill device"
112         FSTYPE=$(mount -p | awk '{ if ( $2 == "/") { print $3 }}')
113         FSDEV=$(mount -p | awk '{ if ( $2 == "/") { print $1 }}')
114         case "$FSTYPE" in
115         ufs)
116                 rootdev=${FSDEV#/dev/}
117                 ;;
118         zfs)
119                 pool=${FSDEV%%/*}
120                 rootdev=$(zpool list -v $pool | awk 'END { print $1 }')
121                 ;;
122         *)
123                 echo "Don't know how to grow root filesystem type: $FSTYPE"
124                 return
125         esac
126         if [ x"$rootdev" = x"${rootdev%/*}" ]; then
127                 # raw device
128                 rawdev="$rootdev"
129         else
130                 rawdev=$(glabel status | awk -v rootdev=$rootdev 'index(rootdev, $1) { print $3; }')
131                 if [ x"$rawdev" = x"" ]; then
132                         echo "Can't figure out device for: $rootdev"
133                         return
134                 fi
135         fi
136
137         if [ x"diskid" = x"${rootdev%/*}" ]; then
138                 search=$rootdev
139         else
140                 search=$rawdev
141         fi
142
143         diskdev=$(growfs_get_diskdev ${search})
144         if [ -z "${diskdev}" ]; then
145                 diskdev=${rootdev}
146         fi
147
148         # Check kenv for growfs_swap_size; if not present,
149         # check $growfs_swap_size from /etc/rc.conf.
150         # A value of 0 suppresses swap addition,
151         # "" (or unset) specifies the default;
152         # other values indicate the size in bytes.
153         # If default, check whether swap is already in fstab;
154         # if so, don't add another.
155         addswap=1
156         swapsize="$(kenv -q growfs_swap_size 2>/dev/null)"
157         case "$swapsize" in
158         "0")    addswap=0
159                 ;;
160         "")     case "$growfs_swap_size" in
161                 "0")    addswap=0
162                         ;;
163                 "")
164                         if ! awk '
165                                 /^#/ { next }
166                                 $3 == "swap" { exit 1 }
167                             ' < /etc/fstab
168                         then
169                                 addswap=0
170                         fi
171                         ;;
172                 *)      swapsize="$growfs_swap_size"
173                         ;;
174                 esac
175                 ;;
176         *)      ;;
177         esac
178
179         swaplim=$(growfs_swap_max)
180
181         [ $verbose -eq 1 ] && {
182                 echo "diskdev is $diskdev"
183                 echo "search is $search"
184                 echo "swapsize is $swapsize"
185                 echo "swaplim is $swaplim"
186         }
187
188         sysctl -b kern.geom.conftxt | awk '
189 {
190         verbose = 0
191         lvl=$1
192         device[lvl] = $3
193         type[lvl] = $2
194         idx[lvl] = $7
195         offset[lvl] = $9
196         parttype[lvl] = $13
197         size[lvl] = $4
198         if (verbose) print lvl, type[lvl], $3
199         if (type[lvl] == "DISK") {
200                 disksize = size[lvl]
201                 if (verbose)
202                         print "disksize ", disksize
203                 # Do not add swap on disks under 15 GB (decimal) by default.
204                 if (addswap == 1 && (size[lvl] > 15000000000 || swapsize > 0))
205                         doing_swap = 1
206                 else
207                         doing_swap = 0
208         } else if (type[lvl] == "PART" && $11 == "freebsd-swap" && \
209             int(swapsize) == 0) {
210                 # This finds swap only if it precedes root, e.g. preceding disk.
211                 addswap = 0
212                 doing_swap = 0
213                 print "swap device exists, not adding swap"
214         }
215         if (dev == $3) {
216                 for (i = 1; i <= lvl; i++) {
217                         # resize
218                         if (type[i] == "PART") {
219                                 pdev = device[i - 1]
220                                 if (verbose)
221                                         print i, pdev, addswap, disksize, \
222                                             doing_swap
223                                 swapcmd = ""
224                                 # Allow swap if current root is < 40% of disk.
225                                 if (parttype[i] != "MBR" && doing_swap == 1 && \
226                                     (size[i] / disksize < 0.4 || \
227                                     swapsize > 0)) {
228                                         print "Adding swap partition"
229                                         if (int(swapsize) == 0) {
230                                                 swapsize = int(disksize / 10)
231                                                 if (swapsize > swaplim)
232                                                         swapsize = swaplim
233                                         }
234                                         sector = $5
235                                         swapsize /= sector
236                                         if (verbose)
237                                                 print "swapsize sectors",
238                                                     swapsize
239                                         align = 4 * 1024 * 1024 / sector
240
241                                         # Estimate offset for swap; let
242                                         # gpart compute actual start and size.
243                                         # Assume expansion all goes into this
244                                         # partition for MBR case.
245                                         if (parttype[i - 1] == "MBR") {
246                                             if (verbose)
247                                                 print "sz ", size[i - 1], \
248                                                     " off ", offset[i - 1]
249                                             expand = size[0] - \
250                                                 (size[i - 1] + offset[i - 1])
251                                         } else {
252                                             if (verbose)
253                                                 print "sz ", size[i], \
254                                                     " off ", offset[i]
255                                             expand = size[0] - \
256                                                 (size[i] + offset[i])
257                                         }
258                                         if (verbose)
259                                             print "expand ", expand, \
260                                                 " sz ", size[i]
261                                         swapbase = (expand + size[i]) / sector
262                                         swapbase -= swapsize + align
263                                         swapcmd = "gpart add -t freebsd-swap -a " align " -b " int(swapbase) " " pdev " && kenv growfs_swap_pdev=" pdev " >/dev/null; "
264                                         if (verbose)
265                                                 swapcmd = "set -x; gpart show; " swapcmd
266                                 }
267                                 cmd[i] = swapcmd "gpart resize -i " idx[i] " " pdev
268                                 if (parttype[i] == "GPT")
269                                         cmd[i] = "gpart recover " pdev " ; " cmd[i]
270                         } else if (type[i] == "LABEL") {
271                                 continue
272                         } else {
273                                 print "unhandled type: " type[i]
274                                 exit 1
275                         }
276                 }
277                 for (i = 1; i <= lvl; i++) {
278                         if (cmd[i])
279                                 system(cmd[i])
280                 }
281                 exit 0
282         }
283 }' dev="$search" addswap="$addswap" swapsize="$swapsize" swaplim="$swaplim"
284         gpart commit "$diskdev" 2> /dev/null
285         case "$FSTYPE" in
286         ufs)
287                 growfs -y /dev/"$rootdev"
288                 ;;
289         zfs)
290                 zpool online -e $pool $rootdev
291                 ;;
292         esac
293
294         # Get parent device of swap partition if one was added;
295         # if so, find swap device and label it.
296         pdev=$(kenv -q growfs_swap_pdev)
297         if [ -n "$pdev" ]
298         then
299                 dev=$(growfs_last_swap "$pdev")
300                 if [ -z "$dev" ]
301                 then
302                         echo "Swap partition not found on $pdev"
303                         exit 0
304                 fi
305                 glabel label -v growfs_swap $dev
306         fi
307 }
308
309 load_rc_config $name
310 run_rc_command "$1"