1#!/bin/sh 2 3# PROVIDE: ec2_ephemeralswap 4# REQUIRE: NETWORKING 5# BEFORE: savecore 6 7# Define ec2_ephemeralswap_enable=YES in /etc/rc.conf to enable slicing 8# of the ephemeral disks to create swap space when the system next boots. 9# 10# Define ec2_ephemeralswap_size=N in /etc/rc.conf to use N MB of swap space 11# instead of auto-sizing based on the amount of RAM. 12# 13: ${ec2_ephemeralswap_enable=NO} 14: ${ec2_ephemeralswap_size=AUTO} 15 16. /etc/rc.subr 17 18name="ec2_ephemeralswap" 19rcvar=ec2_ephemeralswap_enable 20start_cmd="ec2_ephemeralswap_run" 21stop_cmd=":" 22 23ec2_ephemeralswap_run() 24{ 25 local RAM RAMMB SWAPMB SWZONESTRUCTS SWZONEMAXMB 26 local EC2DISKS EC2DISK BLKDEV SWAPDISKS NSWAPDISKS 27 local SWAPPERDISK SWAPDISK 28 29 # Compute "ideal" swap size: 30 # 2*RAM if RAM <= 4 GB 31 # 8 GB if 4 GB <= RAM <= 8 GB 32 # RAM if 8 GB <= RAM 33 RAM=`sysctl -n hw.physmem` 34 RAMMB=`expr $RAM / 1048576` 35 if [ $RAMMB -lt 4096 ]; then 36 SWAPMB=`expr $RAMMB \* 2` 37 elif [ $RAMMB -lt 8192 ]; then 38 SWAPMB=8192 39 else 40 SWAPMB=$RAMMB 41 fi 42 43 # If a swap size was specified, use that instead of our "ideal" value. 44 case ${ec2_ephemeralswap_size} in 45 [Aa][Uu][Tt][Oo]) 46 ;; 47 *) 48 SWAPMB=${ec2_ephemeralswap_size} 49 ;; 50 esac 51 52 # Reduce this size if the kernel hasn't reserved enough space to 53 # keep track of that much swap. 54 SWZONESTRUCTS=`vmstat -z | tr -d , | awk '/^SWAPMETA/ { print $3 }'` 55 SWZONEMAXMB=`expr $SWZONESTRUCTS / 16` 56 if [ $SWZONEMAXMB -lt $SWAPMB ]; then 57 echo -n "Reducing ephemeral swap target from $SWAPMB MB to" 58 echo -n " $SWZONEMAXMB MB since kernel SWAPMETA zone is" 59 echo " too small." 60 SWAPMB=$SWZONEMAXMB 61 fi 62 63 # Fetch a list of EC2 disks 64 EC2DISKS=`fetch -qo - http://169.254.169.254/latest/meta-data/block-device-mapping/ | grep -E '^ephemeral[0-9]+$'` 65 debug "EC2 ephemeral disks are $EC2DISKS" 66 67 # Figure out where they're mapped to 68 SWAPDISKS="" 69 NSWAPDISKS=0 70 for EC2DISK in $EC2DISKS; do 71 BLKDEV=`fetch -qo - http://169.254.169.254/latest/meta-data/block-device-mapping/$EC2DISK | sed 's|/dev/||'` 72 case "$BLKDEV" in 73 sd[a-j]) 74 SWAPDISK="/dev/xbd`echo $BLKDEV | cut -c 3 | tr 'a-j' '0-9'`" 75 ;; 76 xvd[a-z]) 77 SWAPDISK="/dev/xbd`echo $BLKDEV | cut -c 4 | tr 'a-j' '0-9'`" 78 ;; 79 *) 80 echo "Can't translate $EC2DISK to a FreeBSD device name" 81 continue 82 ;; 83 esac 84 if [ -c $SWAPDISK ]; then 85 SWAPDISKS="$SWAPDISKS $SWAPDISK" 86 NSWAPDISKS=$(($NSWAPDISKS + 1)) 87 else 88 debug "Ephemeral swap disk $SWAPDISK doesn't exist" 89 fi 90 done 91 92 # If we have no ephemeral disks, give up. 93 if [ $NSWAPDISKS -eq 0 ]; then 94 echo -n "No ephemeral disks are available," 95 echo " so no swap space is being created." 96 return 0; 97 fi 98 99 # How much swap space do we want per disk? 100 SWAPPERDISK=`expr $SWAPMB / $NSWAPDISKS` 101 if [ $SWAPPERDISK -gt 32768 ]; then 102 # FreeBSD swap_pager code can't use more than 32 GB per device 103 SWAPPERDISK=32768 104 fi 105 106 debug "Want $SWAPPERDISK MB swap on each of $NSWAPDISKS disks: $SWAPDISKS" 107 108 # Slice and partition disks 109 for SWAPDISK in $SWAPDISKS; do 110 if [ `ls $SWAPDISK[a-z.]* 2>/dev/null | wc -l` -gt 1 ]; then 111 debug "Ephemeral swap disk $SWAPDISK already in use" 112 continue; 113 fi 114 115 # Figure out how large the disk is. Subtract off 16 MB for 116 # losses to "cylinder" alignment etc. 117 DISKSZ=`diskinfo $SWAPDISK | awk '{ print $3 }'` 118 DISKSZM=`expr $DISKSZ / 1048576 - 16` 119 120 # Use the size we want or the size we've got, whichever is less 121 if [ $DISKSZM -lt $SWAPPERDISK ]; then 122 SWAPSZ=$DISKSZM; 123 else 124 SWAPSZ=$SWAPPERDISK; 125 fi 126 127 # Try to create a $SWAPSZ MB slice on this disk. 128 echo -n "Attempting to create a $SWAPSZ MB swap area on $SWAPDISK..." 129 ( echo "p 1 0xa5 64 ${SWAPSZ}M"; echo "p 2 0xa5 * *" ) | 130 fdisk -i -f /dev/stdin $SWAPDISK >/dev/null 2>/dev/null 131 132 # Attempt to create a swap partition on the new slice. 133 ( echo "b: * 0 swap"; echo "c: * 0 unused" ) | 134 bsdlabel -R ${SWAPDISK}s1 /dev/stdin 135 136 # Did we succeed? 137 if [ -c ${SWAPDISK}s1b ]; then 138 echo " done." 139 else 140 echo " failed." 141 fi 142 done 143 144 # Turn on swap 145 for SWAPDISK in $SWAPDISKS; do 146 # If there isn't an s1b partition, this isn't one of ours. 147 if ! [ -c "${SWAPDISK}s1b" ]; then 148 continue; 149 fi 150 151 # Make sure that s1b is a swap partition. 152 if ! bsdlabel ${SWAPDISK}s1 | grep b: | grep -q swap; then 153 continue; 154 fi 155 156 # Enable swap on this disk 157 echo "Enabling swapping to ${SWAPDISK}s1b" 158 swapon ${SWAPDISK}s1b 159 done 160 161 # Turn on dumping, if ${dumpdev} is AUTO (the dumpon rc.d script runs 162 # early in the boot process, but we can't run until the network has 163 # been brought up -- so we duplicate here some of the work which that 164 # script does. 165 case ${dumpdev} in 166 [Aa][Uu][Tt][Oo]) 167 for SWAPDISK in $SWAPDISKS; do 168 # Skip if this is not a disk we're swapping to. 169 if ! swapinfo | grep -Eq "^${SWAPDISK}s1b"; then 170 continue; 171 fi 172 173 # If we don't have a dump disk yet, use this one. 174 if ! [ -e /dev/dumpdev ]; then 175 echo "Enabling crash dumps to ${SWAPDISK}s1b" 176 dumpon ${SWAPDISK}s1b 177 ln -sf ${SWAPDISK}s1b /dev/dumpdev 178 fi 179 done 180 ;; 181 esac 182} 183 184load_rc_config $name 185run_rc_command "$1" 186