1#!/system/bin/sh 2 3# 4# Copyright (C) 2019 The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19# This script will run as an pre-checkpointing cleanup for mounting f2fs 20# with checkpoint=disable, so that the first mount after the reboot will 21# be faster. It is unnecessary to run if the device does not use userdata 22# checkpointing on F2FS. 23 24# TARGET_SLOT="${1}" 25STATUS_FD="${2}" 26 27SLEEP=5 28TIME=0 29MAX_TIME=1200 30 31# GC_URGENT_MID, will fall back to GC_URGENT_HIGH if unsupported 32GC_TYPE=3 33 34# If we fall back, start off with less impactful GC 35# To avoid long wait time, ramp up over time 36GC_SLEEP_MAX=150 37GC_SLEEP_MIN=50 38GC_SLEEP_STEP=5 39 40# We only need to run this if we're using f2fs 41if [ ! -f /dev/sys/fs/by-name/userdata/gc_urgent ]; then 42 exit 0 43fi 44 45# If we have sufficient free segments, it doesn't matter how much extra 46# space is unusable, since we only need to make it to boot complete to 47# get that space back 48MIN_FREE_SEGMENT=500 49 50# Ideally we want to track unusable, as it directly measures what we 51# care about. If it's not present, dirty_segments is the best proxy. 52if [ -f /dev/sys/fs/by-name/userdata/unusable ]; then 53 UNUSABLE=1 54 METRIC="unusable blocks" 55 THRESHOLD=25000 56 MAX_INCREASE=500 57 read START < /dev/sys/fs/by-name/userdata/unusable 58else 59 METRIC="dirty segments" 60 THRESHOLD=200 61 MAX_INCREASE=5 62 read START < /dev/sys/fs/by-name/userdata/dirty_segments 63fi 64 65log -pi -t checkpoint_gc Turning on GC for userdata 66 67read OLD_SLEEP < /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time || \ 68 { log -pw -t checkpoint_gc Cannot read gc_urgent_sleep_time; exit 1; } 69GC_SLEEP=${GC_SLEEP_MAX} 70echo ${GC_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time || \ 71 { log -pw -t checkpoint_gc Cannot set gc_urgent_sleep_time; exit 1; } 72 73 74echo ${GC_TYPE} > /dev/sys/fs/by-name/userdata/gc_urgent \ 75 || { GC_TYPE=1; log -pi -t checkpoint_gc GC_URGENT_MID not supported, using GC_URGENT_HIGH; } 76 77if [ ${GC_TYPE} -eq 1 ]; then 78 echo ${GC_TYPE} > /dev/sys/fs/by-name/userdata/gc_urgent || \ 79 { echo ${OLD_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time; \ 80 log -pw -t checkpoint_gc Failed to set gc_urgent; exit 1; } 81else 82 # GC MID will wait for background I/O, so no need to start small 83 GC_SLEEP=${GC_SLEEP_MIN} 84fi 85 86 87CURRENT=${START} 88TODO=$((${START}-${THRESHOLD})) 89CUTOFF=$((${START} + ${MAX_INCREASE})) 90while [ ${CURRENT} -gt ${THRESHOLD} ]; do 91 log -pi -t checkpoint_gc ${METRIC}:${CURRENT} \(threshold:${THRESHOLD}\) mode:${GC_TYPE} GC_SLEEP:${GC_SLEEP} 92 PROGRESS=`echo "(${START}-${CURRENT})/${TODO}"|bc -l` 93 if [[ $PROGRESS == -* ]]; then 94 PROGRESS=0 95 fi 96 print -u${STATUS_FD} "global_progress ${PROGRESS}" 97 if [ ${UNUSABLE} -eq 1 ]; then 98 read CURRENT < /dev/sys/fs/by-name/userdata/unusable 99 else 100 read CURRENT < /dev/sys/fs/by-name/userdata/dirty_segments 101 fi 102 103 if [ ${CURRENT} -gt ${CUTOFF} ]; then 104 log -pw -t checkpoint_gc Garbage Collection is making no progress. Aborting checkpoint_gc attempt \(initial ${METRIC}: ${START}, now: ${CURRENT}\) 105 break 106 fi 107 108 read CURRENT_FREE_SEGMENTS < /dev/sys/fs/by-name/userdata/free_segments 109 read CURRENT_OVP < /dev/sys/fs/by-name/userdata/ovp_segments 110 CURRENT_FREE_SEG=$((${CURRENT_FREE_SEGMENTS}-${CURRENT_OVP})) 111 if [ ${CURRENT_FREE_SEG} -gt ${MIN_FREE_SEGMENT} ]; then 112 log -pi checkpoint_gc Sufficient free segments. Extra gc not needed. 113 break 114 fi 115 116 sleep ${SLEEP} 117 TIME=$((${TIME}+${SLEEP})) 118 if [ ${TIME} -gt ${MAX_TIME} ]; then 119 log -pw -t checkpoint_gc Timed out with gc threshold not met. 120 break 121 fi 122 if [ ${GC_SLEEP} -gt ${GC_SLEEP_MIN} ]; then 123 GC_SLEEP=$((${GC_SLEEP}-${GC_SLEEP_STEP})) 124 fi 125 # In case someone turns it off behind our back 126 echo ${GC_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time 127 echo ${GC_TYPE} > /dev/sys/fs/by-name/userdata/gc_urgent 128done 129 130# It could be a while before the system reboots for the update... 131# Leaving on low level GC can help ensure the boot for ota is faster 132# If powerhints decides to turn it off, we'll just rely on normal GC 133log -pi -t checkpoint_gc Leaving on GC_URGENT_LOW for userdata 134echo ${OLD_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time 135echo 2 > /dev/sys/fs/by-name/userdata/gc_urgent 136sync 137 138print -u${STATUS_FD} "global_progress 1.0" 139exit 0 140