Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upsystemd-swap/systemd-swap.sh
Go to file| #!/bin/bash -e | |
| ################################################################################ | |
| # echo wrappers | |
| INFO(){ echo -n "INFO: "; echo "$@" ;} | |
| WARN(){ echo -n "WARN: "; echo "$@" ;} | |
| ERRO(){ echo -n "ERRO: "; echo -n "$@" ; echo " Abort!"; exit 1;} | |
| ################################################################################ | |
| # helper function for see information about writing data | |
| write(){ | |
| [ "$#" == "2" ] || return 0 | |
| val="$1" file="$2" | |
| [ ! -z "$val" ] || return 0 | |
| [ ! -z "$file" ] || return 0 | |
| INFO "$val >> $file" | |
| echo "$val" >> "$file" || \ | |
| WARN "Problem with writing $val >> $file" | |
| } | |
| zram_hot_add(){ | |
| WARN "zramctl can't find free device" | |
| INFO "Use workaround hook for hot add" | |
| if [ -f /sys/class/zram-control/hot_add ]; then | |
| NEW_ZRAM=$(cat /sys/class/zram-control/hot_add) | |
| INFO "Success: new device /dev/zram$NEW_ZRAM" | |
| else | |
| ERRO "This kernel not support hot add zram device, please use 4.2+ kernels or see modinfo zram and make modprobe rule" | |
| fi | |
| } | |
| manage_zram(){ | |
| case $1 in | |
| start) | |
| [ -z "${zram[size]}" ] && return 0 | |
| zram[alg]=${zram[alg]:-lzo} | |
| zram[streams]=${zram[streams]:-${sys[cpu_count]}} | |
| zram[force]=${zram[force]:-true} | |
| # Wrapper, for handling zram initialization problems | |
| for (( i = 0; i < 10; i++ )); do | |
| [ -d /sys/module/zram ] || modprobe zram | |
| done | |
| for (( i = 0; i < 10; i++ )); do | |
| # zramctl is a external program -> return name of first free device | |
| OUTPUT="$(zramctl -f -a ${zram[alg]} -t ${zram[streams]} -s ${zram[size]} 2>&1 || :)" | |
| if echo "$OUTPUT" | grep -q "failed to reset: Device or resource busy"; then | |
| sleep 1 | |
| continue | |
| elif echo "$OUTPUT" | grep -q "zramctl: no free zram device found"; then | |
| zram_hot_add | |
| elif echo "$OUTPUT" | grep -q "/dev/zram"; then | |
| [ -b "$OUTPUT" ] || continue | |
| zram[dev]="$OUTPUT" | |
| break | |
| else | |
| : | |
| fi | |
| done | |
| mkswap "${zram[dev]}" | |
| swapon -p 32767 "${zram[dev]}" | |
| write "zram[dev]=${zram[dev]}" ${lock[zram]} | |
| ;; | |
| stop) | |
| # read info from zram lock file | |
| . "${lock[zram]}" | |
| swapoff "${zram[dev]}" | |
| zramctl -r "${zram[dev]}" | |
| rm "${lock[zram]}" | |
| ;; | |
| esac | |
| } | |
| manage_swapf(){ | |
| case $1 in | |
| start) | |
| [ -z ${swapf[path]} ] && return 0 | |
| [ -z ${swapf[size]} ] && return 0 | |
| # Create sparse file for swap | |
| truncate -s ${swapf[size]} ${swapf[path]} || return 0 | |
| # get first free loop device and | |
| # use swap file through loop, for avoid error: | |
| # skipping - it appears to have holes | |
| swapf[loop]=`losetup -f --show ${swapf[path]}` | |
| # loop use file descriptor, file still exist, but no have path | |
| # When loop deatach file, file will be deleted. | |
| rm ${swapf[path]} | |
| mkswap ${swapf[loop]} | |
| swapon -d ${swapf[loop]} | |
| # set autoclear flag | |
| losetup -d ${swapf[loop]} | |
| write "swapf[loop]=${swapf[loop]}" ${lock[swapf]} | |
| ;; | |
| stop) | |
| . ${lock[swapf]} | |
| if [ ! -z ${swapf[loop]} ]; then | |
| swapoff ${swapf[loop]} | |
| fi | |
| rm ${lock[swapf]} | |
| ;; | |
| esac | |
| } | |
| manage_swapdev(){ | |
| case $1 in | |
| start) | |
| [ -z "${swapd[devs]}" ] && return 0 | |
| for i in `echo ${swapd[devs]}`; do | |
| if swapon -d -p 1 $i; then | |
| write $i ${lock[dev]} | |
| else | |
| : | |
| fi | |
| done | |
| ;; | |
| stop) | |
| for i in `cat ${lock[dev]}`; do | |
| swapoff $i || : | |
| done | |
| rm ${lock[dev]} | |
| ;; | |
| esac | |
| } | |
| manage_zswap(){ | |
| ZSWAP_P=/sys/module/zswap/parameters/ | |
| case $1 in | |
| start) | |
| [ -f "${lock[zswap]}" ] && return 0 | |
| declare -A local | |
| for param in enabled compressor max_pool_percent zpool; do | |
| local["$param"]="$(cat $ZSWAP_P/$param)" | |
| write "zswap[$param]=${local[$param]}" "${lock[zswap]}" | |
| write "${zswap[$param]}" "$ZSWAP_P/$param" | |
| done | |
| ;; | |
| stop) | |
| . "${lock[zswap]}" | |
| for param in enabled compressor max_pool_percent zpool; do | |
| write "${zswap[$param]}" "$ZSWAP_P/$param" | |
| done | |
| rm ${lock[zswap]} | |
| ;; | |
| esac | |
| } | |
| read_line(){ | |
| FILE=$1 NUM=$2 | |
| head -n $NUM $FILE | tail -n 1 | |
| } | |
| gen_vram_bounds(){ | |
| FILE_TMP="$(mktemp)" | |
| lspci | grep VGA > $FILE_TMP | |
| VGA_COUNT="$(cat -n $FILE_TMP | wc -l)" | |
| for a in $(seq 1 $VGA_COUNT); do | |
| PCI_SLOT=$(read_line $FILE_TMP $a| awk '{print $1}') | |
| FILE_REGIONS_TMP="$(mktemp)" | |
| lspci -v -s $PCI_SLOT | grep '(64-bit, prefetchable)' > $FILE_REGIONS_TMP | |
| REGION_COUNT="$(cat -n $FILE_REGIONS_TMP | tail -n 1 | awk '{print $1}')" | |
| for b in $(seq 1 $REGION_COUNT); do | |
| LINE=$(read_line $FILE_REGIONS_TMP $b) | |
| REGION_START=$( echo $LINE | awk '{print $3}' ) | |
| REGION_START_BYTE="$((16#$REGION_START))" | |
| REGION_LENGHT=$( echo $LINE | awk '{print $6}' | cut -d'=' -f2 | tr -d ']' ) | |
| if echo $REGION_LENGHT | grep -q M; then | |
| REGION_LENGHT_MB="$(echo $REGION_LENGHT | tr -d 'M')" | |
| REGION_LENGHT_BYTE=$[$REGION_LENGHT_MB*1024*1024] | |
| REGION_END=$[$REGION_START_BYTE+$REGION_LENGHT_BYTE] | |
| vramswap_regions[${a}_${b}]="$REGION_START_BYTE $REGION_END" | |
| else | |
| ERRO "Can't compute VRAM Region size for $PCI_SLOT!" | |
| fi | |
| done | |
| done | |
| rm $FILE_TMP | |
| } | |
| manage_vramswap(){ | |
| case $1 in | |
| start) | |
| [ -f "${lock[vramswap]}" ] && return 0 | |
| [ -z "${vramswap[region_start]}" ] && return 0 | |
| [ -z "${vramswap[region_size]}" ] && return 0 | |
| if [ -b /dev/mtdblock0 ]; then | |
| ERRO "Can't handle VRAM SWAP if /dev/mtdblock0 exist before first systemd-swap initialization!" | |
| fi | |
| gen_vram_bounds | |
| U_REG_START="${vramswap[region_start]}" | |
| U_REG_START="$((16#$U_REG_START))" | |
| U_REG_END="${vramswap[region_size]}" | |
| U_REG_END="$((16#$U_REG_END))" | |
| U_REG_END="$[$U_REG_START+$U_REG_END]" | |
| MEM_REGION_OKAY=false | |
| for region in "${vramswap_regions[@]}"; do | |
| break | |
| START=$(echo $region | cut -d' ' -f1) | |
| END=$(echo $region | cut -d' ' -f2) | |
| if (( $U_REG_START >= $START )) && (( $U_REG_START < $END )); then | |
| if (( $U_REG_END <= $END )); then | |
| MEM_REGION_OKAY=true | |
| else | |
| continue | |
| fi | |
| else | |
| continue | |
| fi | |
| done | |
| if $MEM_REGION_OKAY; then | |
| modprobe slram map=VRAM,0x${vramswap[region_start]},+0x${vramswap[region_size]} | |
| modprobe mtdblock | |
| if [ -b /dev/mtdblock0 ]; then | |
| mkswap -L VRAM /dev/mtdblock0 | |
| swapon -p 32767 /dev/mtdblock0 | |
| fi | |
| write /dev/mtdblock0 ${lock[vramswap]} | |
| else | |
| ERRO "No one parsed region is acceptable for VRAM!" | |
| fi | |
| ;; | |
| stop) | |
| swapoff "$(cat ${lock[vramswap]})" | |
| rmmod slram mtdblock | |
| ;; | |
| esac | |
| } | |
| ############################################################################### | |
| # Script body | |
| # Create associative arrays | |
| declare -A sys zram lock swapf swapd zswap vramswap vramswap_regions | |
| parse_config(){ | |
| # get cpu count from cpuinfo | |
| sys[cpu_count]=$(nproc) | |
| # get total ram size for meminfo | |
| sys[ram_size]=$(awk '/MemTotal:/ { print $2 }' /proc/meminfo) | |
| # get values from /etc/systemd-swap.conf | |
| . $config | |
| # Parse fstab for swap mounts | |
| [ -z ${swapf[fstab]} ] || \ | |
| if [ ! -z "`grep '^[^#]*swap' /etc/fstab || :`" ]; then | |
| unset swapf | |
| INFO "Swap already specified in fstab, so disable swap file creation" | |
| fi | |
| # Try to auto found swap partitions | |
| if [ ! -z ${swapd[parse]} ]; then | |
| swapd[devs]=" `blkid -t TYPE=swap -o device | grep -vE '(zram|loop)' || :` | |
| ${swapd[devs]}" | |
| [ ! -z ${swapf[Poff]} ] && [ ! -z "${swapd[devs]}" ] && unset swapf || : | |
| fi | |
| } | |
| manage_config(){ | |
| config=/etc/systemd-swap.conf | |
| if [ -f $config ]; then | |
| parse_config | |
| else | |
| ERRO "Config $config deleted, reinstall package" | |
| fi | |
| } | |
| ############################################################################### | |
| lock[zram]=/run/.systemd-swap.zram | |
| lock[dev]=/run/.systemd-swap.dev | |
| lock[swapf]=/run/.systemd-swap.swapf | |
| lock[zswap]=/run/.systemd-swap.zswap | |
| lock[vramswap]=/run/.systemd-swap.vramswap | |
| case $1 in | |
| start) | |
| manage_config | |
| # start several independent threads | |
| [ -f ${lock[zram]} ] || manage_zram $1 & | |
| [ -f ${lock[dev]} ] || manage_swapdev $1 & | |
| [ -f ${lock[swapf]} ] || manage_swapf $1 & | |
| [ -f ${lock[zswap]} ] || manage_zswap $1 & | |
| [ -f ${lock[vramswap]} ] || manage_vramswap $1 & | |
| ;; | |
| stop) | |
| [ -f ${lock[zram]} ] && manage_zram $1 & | |
| [ -f ${lock[dev]} ] && manage_swapdev $1 & | |
| [ -f ${lock[swapf]} ] && manage_swapf $1 & | |
| [ -f ${lock[zswap]} ] && manage_zswap $1 & | |
| [ -f ${lock[vramswap]} ] && manage_vramswap $1 & | |
| ;; | |
| esac | |
| wait |