summaryrefslogtreecommitdiff
path: root/checkpoint_gc/checkpoint_gc.sh
blob: 10514b5ffe4f4b71a9267fa9024ff53180e1bf01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/system/bin/sh

#
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# This script will run as an pre-checkpointing cleanup for mounting f2fs
# with checkpoint=disable, so that the first mount after the reboot will
# be faster. It is unnecessary to run if the device does not use userdata
# checkpointing on F2FS.

# TARGET_SLOT="${1}"
STATUS_FD="${2}"

SLEEP=5
TIME=0
MAX_TIME=1200

# GC_URGENT_MID, will fall back to GC_URGENT_HIGH if unsupported
GC_TYPE=3

# If we fall back, start off with less impactful GC
# To avoid long wait time, ramp up over time
GC_SLEEP_MAX=150
GC_SLEEP_MIN=50
GC_SLEEP_STEP=5

# We only need to run this if we're using f2fs
if [ ! -f /dev/sys/fs/by-name/userdata/gc_urgent ]; then
  exit 0
fi

# Ideally we want to track unusable, as it directly measures what we
# care about. If it's not present, dirty_segments is the best proxy.
if [ -f /dev/sys/fs/by-name/userdata/unusable ]; then
  UNUSABLE=1
  METRIC="unusable blocks"
  THRESHOLD=25000
  read START < /dev/sys/fs/by-name/userdata/unusable
else
  METRIC="dirty segments"
  THRESHOLD=200
  read START < /dev/sys/fs/by-name/userdata/dirty_segments
fi

log -pi -t checkpoint_gc Turning on GC for userdata

read OLD_SLEEP < /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time || \
  { log -pw -t checkpoint_gc Cannot read gc_urgent_sleep_time; exit 1; }
GC_SLEEP=${GC_SLEEP_MAX}
echo ${GC_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time || \
  { log -pw -t checkpoint_gc Cannot set gc_urgent_sleep_time; exit 1; }


echo ${GC_TYPE} > /dev/sys/fs/by-name/userdata/gc_urgent \
  || { GC_TYPE=1; log -pi -t checkpoint_gc GC_URGENT_MID not supported, using GC_URGENT_HIGH; }

if [ ${GC_TYPE} -eq 1 ]; then
  echo ${GC_TYPE} > /dev/sys/fs/by-name/userdata/gc_urgent || \
    { echo ${OLD_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time; \
    log -pw -t checkpoint_gc Failed to set gc_urgent; exit 1; }
else
  # GC MID will wait for background I/O, so no need to start small
  GC_SLEEP=${GC_SLEEP_MIN}
fi


CURRENT=${START}
TODO=$((${START}-${THRESHOLD}))
while [ ${CURRENT} -gt ${THRESHOLD} ]; do
  log -pi -t checkpoint_gc ${METRIC}:${CURRENT} \(threshold:${THRESHOLD}\) mode:${GC_TYPE} GC_SLEEP:${GC_SLEEP}
  PROGRESS=`echo "(${START}-${CURRENT})/${TODO}"|bc -l`
  if [[ $PROGRESS == -* ]]; then
      PROGRESS=0
  fi
  print -u${STATUS_FD} "global_progress ${PROGRESS}"
  if [ ${UNUSABLE} -eq 1 ]; then
    read CURRENT < /dev/sys/fs/by-name/userdata/unusable
  else
    read CURRENT < /dev/sys/fs/by-name/userdata/dirty_segments
  fi
  sleep ${SLEEP}
  TIME=$((${TIME}+${SLEEP}))
  if [ ${TIME} -gt ${MAX_TIME} ]; then
    log -pw -t checkpoint_gc Timed out with gc threshold not met.
    break
  fi
  if [ ${GC_SLEEP} -gt ${GC_SLEEP_MIN} ]; then
    GC_SLEEP=$((${GC_SLEEP}-${GC_SLEEP_STEP}))
  fi
  # In case someone turns it off behind our back
  echo ${GC_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time
  echo ${GC_TYPE} > /dev/sys/fs/by-name/userdata/gc_urgent
done

# It could be a while before the system reboots for the update...
# Leaving on low level GC can help ensure the boot for ota is faster
# If powerhints decides to turn it off, we'll just rely on normal GC
log -pi -t checkpoint_gc Leaving on GC_URGENT_LOW for userdata
echo ${OLD_SLEEP} > /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time
echo 2 > /dev/sys/fs/by-name/userdata/gc_urgent
sync

print -u${STATUS_FD} "global_progress 1.0"
exit 0