Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <dirent.h> |
| 18 | #include <errno.h> |
Mark Salyzyn | 3ff87d8 | 2018-07-02 10:45:25 -0700 | [diff] [blame] | 19 | #include <fcntl.h> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 20 | #include <linux/fs.h> |
| 21 | #include <selinux/selinux.h> |
| 22 | #include <stdio.h> |
Mark Salyzyn | 2fde1ec | 2018-11-01 15:05:44 -0700 | [diff] [blame] | 23 | #include <stdlib.h> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 24 | #include <string.h> |
| 25 | #include <sys/mount.h> |
| 26 | #include <sys/param.h> |
| 27 | #include <sys/stat.h> |
Mark Salyzyn | 53c96da | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 28 | #include <sys/statvfs.h> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 29 | #include <sys/types.h> |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 30 | #include <sys/utsname.h> |
Mark Salyzyn | 3ff87d8 | 2018-07-02 10:45:25 -0700 | [diff] [blame] | 31 | #include <sys/vfs.h> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 32 | #include <unistd.h> |
| 33 | |
Mark Salyzyn | 54e4790 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 34 | #include <algorithm> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 35 | #include <memory> |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 36 | #include <optional> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 37 | #include <string> |
| 38 | #include <vector> |
| 39 | |
| 40 | #include <android-base/file.h> |
| 41 | #include <android-base/macros.h> |
| 42 | #include <android-base/properties.h> |
| 43 | #include <android-base/strings.h> |
Mark Salyzyn | 3ff87d8 | 2018-07-02 10:45:25 -0700 | [diff] [blame] | 44 | #include <android-base/unique_fd.h> |
| 45 | #include <ext4_utils/ext4_utils.h> |
Mark Salyzyn | 1b066c3 | 2018-10-25 09:02:08 -0700 | [diff] [blame] | 46 | #include <fs_mgr.h> |
David Anderson | 5c475c7 | 2019-06-11 17:40:49 -0700 | [diff] [blame] | 47 | #include <fs_mgr/file_wait.h> |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 48 | #include <fs_mgr_dm_linear.h> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 49 | #include <fs_mgr_overlayfs.h> |
| 50 | #include <fstab/fstab.h> |
Mark Salyzyn | 54e4790 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 51 | #include <libdm/dm.h> |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 52 | #include <libfiemap/image_manager.h> |
David Anderson | 0e330f1 | 2019-01-03 18:16:56 -0800 | [diff] [blame] | 53 | #include <libgsi/libgsi.h> |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 54 | #include <liblp/builder.h> |
| 55 | #include <liblp/liblp.h> |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 56 | #include <storage_literals/storage_literals.h> |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 57 | |
| 58 | #include "fs_mgr_priv.h" |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 59 | #include "libfiemap/utility.h" |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 60 | |
| 61 | using namespace std::literals; |
Mark Salyzyn | 54e4790 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 62 | using namespace android::dm; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 63 | using namespace android::fs_mgr; |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 64 | using namespace android::storage_literals; |
| 65 | using android::fiemap::FilesystemHasReliablePinning; |
| 66 | using android::fiemap::IImageManager; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 67 | |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 68 | namespace { |
| 69 | |
| 70 | bool fs_mgr_access(const std::string& path) { |
Justin Yun | 818ff63 | 2018-11-01 17:25:39 +0900 | [diff] [blame] | 71 | auto save_errno = errno; |
| 72 | auto ret = access(path.c_str(), F_OK) == 0; |
| 73 | errno = save_errno; |
| 74 | return ret; |
| 75 | } |
| 76 | |
Mark Salyzyn | 6d109ec | 2019-01-30 10:19:15 -0800 | [diff] [blame] | 77 | // determine if a filesystem is available |
| 78 | bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) { |
| 79 | std::string filesystems; |
| 80 | if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false; |
| 81 | return filesystems.find("\t" + filesystem + "\n") != std::string::npos; |
| 82 | } |
| 83 | |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 84 | } // namespace |
| 85 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 86 | #if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs |
| 87 | |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 88 | Fstab fs_mgr_overlayfs_candidate_list(const Fstab&) { |
| 89 | return {}; |
| 90 | } |
| 91 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 92 | bool fs_mgr_overlayfs_mount_all(Fstab*) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 93 | return false; |
| 94 | } |
| 95 | |
Mark Salyzyn | e0c581f | 2019-05-29 14:01:56 -0700 | [diff] [blame] | 96 | bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change, bool) { |
Greg Kaiser | b4bf8c6 | 2018-08-10 05:24:25 -0700 | [diff] [blame] | 97 | if (change) *change = false; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 98 | return false; |
| 99 | } |
| 100 | |
| 101 | bool fs_mgr_overlayfs_teardown(const char*, bool* change) { |
Greg Kaiser | b4bf8c6 | 2018-08-10 05:24:25 -0700 | [diff] [blame] | 102 | if (change) *change = false; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 103 | return false; |
| 104 | } |
| 105 | |
Mark Salyzyn | dd748aa | 2018-12-03 13:42:22 -0800 | [diff] [blame] | 106 | bool fs_mgr_overlayfs_is_setup() { |
| 107 | return false; |
| 108 | } |
| 109 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 110 | namespace android { |
| 111 | namespace fs_mgr { |
| 112 | |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 113 | void MapScratchPartitionIfNeeded(Fstab*, const std::function<bool(const std::set<std::string>&)>&) { |
| 114 | } |
| 115 | |
Jintao Zhu | 84822c8 | 2021-04-21 14:31:22 +0800 | [diff] [blame] | 116 | void CleanupOldScratchFiles() {} |
| 117 | |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 118 | void TeardownAllOverlayForMountPoint(const std::string&) {} |
| 119 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 120 | } // namespace fs_mgr |
| 121 | } // namespace android |
| 122 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 123 | #else // ALLOW_ADBD_DISABLE_VERITY == 0 |
| 124 | |
| 125 | namespace { |
| 126 | |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 127 | bool fs_mgr_in_recovery() { |
| 128 | // Check the existence of recovery binary instead of using the compile time |
Yi-Yo Chiang | 8f73f02e | 2022-02-23 16:20:09 +0800 | [diff] [blame] | 129 | // __ANDROID_RECOVERY__ macro. |
| 130 | // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot |
| 131 | // mode would use the same init binary, which would mean during normal boot |
| 132 | // the '/init' binary is actually a symlink pointing to |
| 133 | // init_second_stage.recovery, which would be compiled with |
| 134 | // __ANDROID_RECOVERY__ defined. |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 135 | return fs_mgr_access("/system/bin/recovery"); |
| 136 | } |
| 137 | |
| 138 | bool fs_mgr_is_dsu_running() { |
| 139 | // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is |
| 140 | // never called in recovery, the return value of android::gsi::IsGsiRunning() |
| 141 | // is not well-defined. In this case, just return false as being in recovery |
| 142 | // implies not running a DSU system. |
| 143 | if (fs_mgr_in_recovery()) return false; |
| 144 | auto saved_errno = errno; |
| 145 | auto ret = android::gsi::IsGsiRunning(); |
| 146 | errno = saved_errno; |
| 147 | return ret; |
| 148 | } |
| 149 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 150 | // list of acceptable overlayfs backing storage |
| 151 | const auto kScratchMountPoint = "/mnt/scratch"s; |
| 152 | const auto kCacheMountPoint = "/cache"s; |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 153 | |
| 154 | std::vector<const std::string> OverlayMountPoints() { |
| 155 | // Never fallback to legacy cache mount point if within a DSU system, |
| 156 | // because running a DSU system implies the device supports dynamic |
| 157 | // partitions, which means legacy cache mustn't be used. |
| 158 | if (fs_mgr_is_dsu_running()) { |
| 159 | return {kScratchMountPoint}; |
| 160 | } |
| 161 | return {kScratchMountPoint, kCacheMountPoint}; |
| 162 | } |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 163 | |
Mark Salyzyn | 5f6b069 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 164 | // Return true if everything is mounted, but before adb is started. Right |
| 165 | // after 'trigger load_persist_props_action' is done. |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 166 | bool fs_mgr_boot_completed() { |
Mark Salyzyn | 5f6b069 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 167 | return android::base::GetBoolProperty("ro.persistent_properties.ready", false); |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | bool fs_mgr_is_dir(const std::string& path) { |
| 171 | struct stat st; |
| 172 | return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode); |
| 173 | } |
| 174 | |
| 175 | // Similar test as overlayfs workdir= validation in the kernel for read-write |
| 176 | // validation, except we use fs_mgr_work. Covers space and storage issues. |
| 177 | bool fs_mgr_dir_is_writable(const std::string& path) { |
| 178 | auto test_directory = path + "/fs_mgr_work"; |
| 179 | rmdir(test_directory.c_str()); |
| 180 | auto ret = !mkdir(test_directory.c_str(), 0700); |
| 181 | return ret | !rmdir(test_directory.c_str()); |
| 182 | } |
| 183 | |
Mark Salyzyn | 1808541 | 2019-08-15 08:34:27 -0700 | [diff] [blame] | 184 | // At less than 1% or 8MB of free space return value of false, |
Mark Salyzyn | 53c96da | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 185 | // means we will try to wrap with overlayfs. |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 186 | bool fs_mgr_filesystem_has_space(const std::string& mount_point) { |
Mark Salyzyn | 53c96da | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 187 | // If we have access issues to find out space remaining, return true |
| 188 | // to prevent us trying to override with overlayfs. |
| 189 | struct statvfs vst; |
Mark Salyzyn | 98a0128 | 2019-05-13 09:14:55 -0700 | [diff] [blame] | 190 | auto save_errno = errno; |
| 191 | if (statvfs(mount_point.c_str(), &vst)) { |
| 192 | errno = save_errno; |
| 193 | return true; |
| 194 | } |
Mark Salyzyn | 53c96da | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 195 | |
Mark Salyzyn | 1808541 | 2019-08-15 08:34:27 -0700 | [diff] [blame] | 196 | static constexpr int kPercentThreshold = 1; // 1% |
| 197 | static constexpr unsigned long kSizeThreshold = 8 * 1024 * 1024; // 8MB |
Mark Salyzyn | 53c96da | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 198 | |
Mark Salyzyn | 1808541 | 2019-08-15 08:34:27 -0700 | [diff] [blame] | 199 | return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100)) && |
Yi-Yo Chiang | 67e3bbc | 2021-02-12 15:55:50 +0800 | [diff] [blame] | 200 | (static_cast<uint64_t>(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold; |
Mark Salyzyn | 53c96da | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 201 | } |
| 202 | |
Mark Salyzyn | 31c14e1 | 2019-07-31 08:33:53 -0700 | [diff] [blame] | 203 | const auto kPhysicalDevice = "/dev/block/by-name/"s; |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 204 | constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata"; |
| 205 | |
| 206 | // Note: this is meant only for recovery/first-stage init. |
| 207 | bool ScratchIsOnData() { |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 208 | // The scratch partition of DSU is managed by gsid. |
| 209 | if (fs_mgr_is_dsu_running()) { |
| 210 | return false; |
| 211 | } |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 212 | return fs_mgr_access(kScratchImageMetadata); |
| 213 | } |
Mark Salyzyn | 31c14e1 | 2019-07-31 08:33:53 -0700 | [diff] [blame] | 214 | |
| 215 | bool fs_mgr_update_blk_device(FstabEntry* entry) { |
| 216 | if (entry->fs_mgr_flags.logical) { |
| 217 | fs_mgr_update_logical_partition(entry); |
| 218 | } |
| 219 | if (fs_mgr_access(entry->blk_device)) { |
| 220 | return true; |
| 221 | } |
| 222 | if (entry->blk_device != "/dev/root") { |
| 223 | return false; |
| 224 | } |
| 225 | |
| 226 | // special case for system-as-root (taimen and others) |
| 227 | auto blk_device = kPhysicalDevice + "system"; |
| 228 | if (!fs_mgr_access(blk_device)) { |
| 229 | blk_device += fs_mgr_get_slot_suffix(); |
| 230 | if (!fs_mgr_access(blk_device)) { |
| 231 | return false; |
| 232 | } |
| 233 | } |
| 234 | entry->blk_device = blk_device; |
| 235 | return true; |
| 236 | } |
| 237 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 238 | bool fs_mgr_overlayfs_enabled(FstabEntry* entry) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 239 | // readonly filesystem, can not be mount -o remount,rw |
Mark Salyzyn | c11f8e5 | 2019-01-22 08:54:56 -0800 | [diff] [blame] | 240 | // for squashfs, erofs or if free space is (near) zero making such a remount |
Mark Salyzyn | 3ff87d8 | 2018-07-02 10:45:25 -0700 | [diff] [blame] | 241 | // virtually useless, or if there are shared blocks that prevent remount,rw |
Mark Salyzyn | c11f8e5 | 2019-01-22 08:54:56 -0800 | [diff] [blame] | 242 | if (!fs_mgr_filesystem_has_space(entry->mount_point)) { |
Mark Salyzyn | 1b066c3 | 2018-10-25 09:02:08 -0700 | [diff] [blame] | 243 | return true; |
| 244 | } |
Mark Salyzyn | 31c14e1 | 2019-07-31 08:33:53 -0700 | [diff] [blame] | 245 | |
| 246 | // blk_device needs to be setup so we can check superblock. |
| 247 | // If we fail here, because during init first stage and have doubts. |
| 248 | if (!fs_mgr_update_blk_device(entry)) { |
| 249 | return true; |
Mark Salyzyn | 1b066c3 | 2018-10-25 09:02:08 -0700 | [diff] [blame] | 250 | } |
Mark Salyzyn | 31c14e1 | 2019-07-31 08:33:53 -0700 | [diff] [blame] | 251 | |
| 252 | // check if ext4 de-dupe |
Mark Salyzyn | d202c55 | 2018-12-12 10:36:32 -0800 | [diff] [blame] | 253 | auto save_errno = errno; |
| 254 | auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device); |
Mark Salyzyn | d6ef9d2 | 2019-04-11 12:58:19 -0700 | [diff] [blame] | 255 | if (!has_shared_blocks && (entry->mount_point == "/system")) { |
| 256 | has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device); |
| 257 | } |
Mark Salyzyn | d202c55 | 2018-12-12 10:36:32 -0800 | [diff] [blame] | 258 | errno = save_errno; |
| 259 | return has_shared_blocks; |
Mark Salyzyn | 1b066c3 | 2018-10-25 09:02:08 -0700 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) { |
| 263 | auto save_errno = errno; |
| 264 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir); |
| 265 | if (!dir) { |
| 266 | if (errno == ENOENT) { |
| 267 | errno = save_errno; |
| 268 | return true; |
| 269 | } |
| 270 | PERROR << "opendir " << path << " depth=" << level; |
| 271 | if ((errno == EPERM) && (level != 0)) { |
| 272 | errno = save_errno; |
| 273 | return true; |
| 274 | } |
| 275 | return false; |
| 276 | } |
| 277 | dirent* entry; |
| 278 | auto ret = true; |
| 279 | while ((entry = readdir(dir.get()))) { |
| 280 | if (("."s == entry->d_name) || (".."s == entry->d_name)) continue; |
| 281 | auto file = path + "/" + entry->d_name; |
| 282 | if (entry->d_type == DT_UNKNOWN) { |
| 283 | struct stat st; |
| 284 | save_errno = errno; |
| 285 | if (!lstat(file.c_str(), &st) && (st.st_mode & S_IFDIR)) entry->d_type = DT_DIR; |
| 286 | errno = save_errno; |
| 287 | } |
| 288 | if (entry->d_type == DT_DIR) { |
| 289 | ret &= fs_mgr_rm_all(file, change, level + 1); |
| 290 | if (!rmdir(file.c_str())) { |
| 291 | if (change) *change = true; |
| 292 | } else { |
| 293 | if (errno != ENOENT) ret = false; |
| 294 | PERROR << "rmdir " << file << " depth=" << level; |
| 295 | } |
| 296 | continue; |
| 297 | } |
| 298 | if (!unlink(file.c_str())) { |
| 299 | if (change) *change = true; |
| 300 | } else { |
| 301 | if (errno != ENOENT) ret = false; |
| 302 | PERROR << "rm " << file << " depth=" << level; |
| 303 | } |
| 304 | } |
| 305 | return ret; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 306 | } |
| 307 | |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 308 | const auto kUpperName = "upper"s; |
| 309 | const auto kWorkName = "work"s; |
| 310 | const auto kOverlayTopDir = "/overlay"s; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 311 | |
| 312 | std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) { |
| 313 | if (!fs_mgr_is_dir(mount_point)) return ""; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 314 | const auto base = android::base::Basename(mount_point) + "/"; |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 315 | for (const auto& overlay_mount_point : OverlayMountPoints()) { |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 316 | auto dir = overlay_mount_point + kOverlayTopDir + "/" + base; |
| 317 | auto upper = dir + kUpperName; |
| 318 | if (!fs_mgr_is_dir(upper)) continue; |
| 319 | auto work = dir + kWorkName; |
| 320 | if (!fs_mgr_is_dir(work)) continue; |
| 321 | if (!fs_mgr_dir_is_writable(work)) continue; |
| 322 | return dir; |
| 323 | } |
| 324 | return ""; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 325 | } |
| 326 | |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 327 | const auto kLowerdirOption = "lowerdir="s; |
| 328 | const auto kUpperdirOption = "upperdir="s; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 329 | |
David Anderson | 70d0574 | 2021-11-19 16:00:27 -0800 | [diff] [blame] | 330 | static inline bool KernelSupportsUserXattrs() { |
| 331 | struct utsname uts; |
| 332 | uname(&uts); |
| 333 | |
| 334 | int major, minor; |
| 335 | if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { |
| 336 | return false; |
| 337 | } |
| 338 | return major > 5 || (major == 5 && minor >= 15); |
| 339 | } |
| 340 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 341 | // default options for mount_point, returns empty string for none available. |
Mark Salyzyn | d3dc3c8 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 342 | std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) { |
| 343 | auto candidate = fs_mgr_get_overlayfs_candidate(mount_point); |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 344 | if (candidate.empty()) return ""; |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 345 | auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName + |
| 346 | ",workdir=" + candidate + kWorkName; |
| 347 | if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) { |
| 348 | ret += ",override_creds=off"; |
| 349 | } |
David Anderson | 70d0574 | 2021-11-19 16:00:27 -0800 | [diff] [blame] | 350 | if (KernelSupportsUserXattrs()) { |
| 351 | ret += ",userxattr"; |
| 352 | } |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 353 | return ret; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 354 | } |
| 355 | |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 356 | const std::string fs_mgr_mount_point(const std::string& mount_point) { |
Mark Salyzyn | d3dc3c8 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 357 | if ("/"s != mount_point) return mount_point; |
Mark Salyzyn | d3dc3c8 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 358 | return "/system"; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 359 | } |
| 360 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 361 | bool fs_mgr_rw_access(const std::string& path) { |
| 362 | if (path.empty()) return false; |
| 363 | auto save_errno = errno; |
| 364 | auto ret = access(path.c_str(), R_OK | W_OK) == 0; |
| 365 | errno = save_errno; |
| 366 | return ret; |
| 367 | } |
| 368 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 369 | bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) { |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 370 | Fstab fstab; |
Mark Salyzyn | 98a0128 | 2019-05-13 09:14:55 -0700 | [diff] [blame] | 371 | auto save_errno = errno; |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 372 | if (!ReadFstabFromFile("/proc/mounts", &fstab)) { |
| 373 | return false; |
| 374 | } |
Mark Salyzyn | 98a0128 | 2019-05-13 09:14:55 -0700 | [diff] [blame] | 375 | errno = save_errno; |
Mark Salyzyn | a526bbe | 2018-09-20 15:23:00 -0700 | [diff] [blame] | 376 | const auto lowerdir = kLowerdirOption + mount_point; |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 377 | for (const auto& entry : fstab) { |
| 378 | if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue; |
| 379 | if (mount_point != entry.mount_point) continue; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 380 | if (!overlay_only) return true; |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 381 | const auto options = android::base::Split(entry.fs_options, ","); |
Mark Salyzyn | a526bbe | 2018-09-20 15:23:00 -0700 | [diff] [blame] | 382 | for (const auto& opt : options) { |
| 383 | if (opt == lowerdir) { |
| 384 | return true; |
| 385 | } |
| 386 | } |
| 387 | } |
| 388 | return false; |
| 389 | } |
| 390 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 391 | bool fs_mgr_wants_overlayfs(FstabEntry* entry) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 392 | // Don't check entries that are managed by vold. |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 393 | if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 394 | |
Yifan Hong | acf859a | 2019-01-09 11:13:09 -0800 | [diff] [blame] | 395 | // *_other doesn't want overlayfs. |
| 396 | if (entry->fs_mgr_flags.slot_select_other) return false; |
| 397 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 398 | // Only concerned with readonly partitions. |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 399 | if (!(entry->flags & MS_RDONLY)) return false; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 400 | |
| 401 | // If unbindable, do not allow overlayfs as this could expose us to |
| 402 | // security issues. On Android, this could also be used to turn off |
| 403 | // the ability to overlay an otherwise acceptable filesystem since |
| 404 | // /system and /vendor are never bound(sic) to. |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 405 | if (entry->flags & MS_UNBINDABLE) return false; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 406 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 407 | if (!fs_mgr_overlayfs_enabled(entry)) return false; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 408 | |
Mark Salyzyn | 54e4790 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 409 | return true; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 410 | } |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 411 | constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0"; |
Mark Salyzyn | 40b45b8 | 2018-08-27 12:41:50 -0700 | [diff] [blame] | 412 | |
Mark Salyzyn | 780db02 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 413 | bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) { |
| 414 | auto ret = true; |
| 415 | auto top = dir + kOverlayTopDir; |
| 416 | if (setfscreatecon(kOverlayfsFileContext)) { |
| 417 | ret = false; |
| 418 | PERROR << "setfscreatecon " << kOverlayfsFileContext; |
| 419 | } |
| 420 | auto save_errno = errno; |
| 421 | if (!mkdir(top.c_str(), 0755)) { |
| 422 | if (change) *change = true; |
| 423 | } else if (errno != EEXIST) { |
| 424 | ret = false; |
| 425 | PERROR << "mkdir " << top; |
| 426 | } else { |
| 427 | errno = save_errno; |
| 428 | } |
| 429 | setfscreatecon(nullptr); |
| 430 | |
| 431 | if (overlay) *overlay = std::move(top); |
| 432 | return ret; |
| 433 | } |
| 434 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 435 | bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point, |
| 436 | bool* change) { |
| 437 | auto ret = true; |
Mark Salyzyn | fab9f08 | 2019-02-04 14:59:16 -0800 | [diff] [blame] | 438 | if (fs_mgr_overlayfs_already_mounted(mount_point)) return ret; |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 439 | auto fsrec_mount_point = overlay + "/" + android::base::Basename(mount_point) + "/"; |
Mark Salyzyn | 40b45b8 | 2018-08-27 12:41:50 -0700 | [diff] [blame] | 440 | |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 441 | if (setfscreatecon(kOverlayfsFileContext)) { |
Mark Salyzyn | 40b45b8 | 2018-08-27 12:41:50 -0700 | [diff] [blame] | 442 | ret = false; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 443 | PERROR << "setfscreatecon " << kOverlayfsFileContext; |
Mark Salyzyn | 40b45b8 | 2018-08-27 12:41:50 -0700 | [diff] [blame] | 444 | } |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 445 | auto save_errno = errno; |
| 446 | if (!mkdir(fsrec_mount_point.c_str(), 0755)) { |
| 447 | if (change) *change = true; |
| 448 | } else if (errno != EEXIST) { |
| 449 | ret = false; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 450 | PERROR << "mkdir " << fsrec_mount_point; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 451 | } else { |
| 452 | errno = save_errno; |
| 453 | } |
| 454 | |
| 455 | save_errno = errno; |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 456 | if (!mkdir((fsrec_mount_point + kWorkName).c_str(), 0755)) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 457 | if (change) *change = true; |
| 458 | } else if (errno != EEXIST) { |
| 459 | ret = false; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 460 | PERROR << "mkdir " << fsrec_mount_point << kWorkName; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 461 | } else { |
| 462 | errno = save_errno; |
| 463 | } |
Mark Salyzyn | 40b45b8 | 2018-08-27 12:41:50 -0700 | [diff] [blame] | 464 | setfscreatecon(nullptr); |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 465 | |
| 466 | auto new_context = fs_mgr_get_context(mount_point); |
| 467 | if (!new_context.empty() && setfscreatecon(new_context.c_str())) { |
| 468 | ret = false; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 469 | PERROR << "setfscreatecon " << new_context; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 470 | } |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 471 | auto upper = fsrec_mount_point + kUpperName; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 472 | save_errno = errno; |
| 473 | if (!mkdir(upper.c_str(), 0755)) { |
| 474 | if (change) *change = true; |
| 475 | } else if (errno != EEXIST) { |
| 476 | ret = false; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 477 | PERROR << "mkdir " << upper; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 478 | } else { |
| 479 | errno = save_errno; |
| 480 | } |
| 481 | if (!new_context.empty()) setfscreatecon(nullptr); |
| 482 | |
| 483 | return ret; |
| 484 | } |
| 485 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 486 | uint32_t fs_mgr_overlayfs_slot_number() { |
| 487 | return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); |
| 488 | } |
| 489 | |
| 490 | std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { |
Mark Salyzyn | f269312 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 491 | return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number); |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 492 | } |
| 493 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 494 | bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) { |
| 495 | for (const auto& entry : fstab) { |
| 496 | if (entry.fs_mgr_flags.logical) { |
| 497 | return true; |
| 498 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 499 | } |
| 500 | return false; |
| 501 | } |
| 502 | |
Mark Salyzyn | c0966c9 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 503 | void fs_mgr_overlayfs_umount_scratch() { |
| 504 | // Lazy umount will allow us to move on and possibly later |
| 505 | // establish a new fresh mount without requiring a reboot should |
| 506 | // the developer wish to restart. Old references should melt |
| 507 | // away or have no data. Main goal is to shut the door on the |
| 508 | // current overrides with an expectation of a subsequent reboot, |
| 509 | // thus any errors here are ignored. |
| 510 | umount2(kScratchMountPoint.c_str(), MNT_DETACH); |
| 511 | LINFO << "umount(" << kScratchMountPoint << ")"; |
| 512 | rmdir(kScratchMountPoint.c_str()); |
| 513 | } |
| 514 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 515 | bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) { |
| 516 | // umount and delete kScratchMountPoint storage if we have logical partitions |
| 517 | if (overlay != kScratchMountPoint) return true; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 518 | |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 519 | // Validation check. |
| 520 | if (fs_mgr_is_dsu_running()) { |
| 521 | LERROR << "Destroying DSU scratch is not allowed."; |
| 522 | return false; |
| 523 | } |
| 524 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 525 | auto save_errno = errno; |
| 526 | if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) { |
Mark Salyzyn | c0966c9 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 527 | fs_mgr_overlayfs_umount_scratch(); |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 528 | } |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 529 | |
| 530 | const auto partition_name = android::base::Basename(kScratchMountPoint); |
| 531 | |
| 532 | auto images = IImageManager::Open("remount", 10s); |
| 533 | if (images && images->BackingImageExists(partition_name)) { |
| 534 | #if defined __ANDROID_RECOVERY__ |
| 535 | if (!images->DisableImage(partition_name)) { |
| 536 | return false; |
| 537 | } |
| 538 | #else |
| 539 | if (!images->UnmapImageIfExists(partition_name) || |
| 540 | !images->DeleteBackingImage(partition_name)) { |
| 541 | return false; |
| 542 | } |
| 543 | #endif |
| 544 | } |
| 545 | |
| 546 | auto slot_number = fs_mgr_overlayfs_slot_number(); |
| 547 | auto super_device = fs_mgr_overlayfs_super_device(slot_number); |
| 548 | if (!fs_mgr_rw_access(super_device)) return true; |
| 549 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 550 | auto builder = MetadataBuilder::New(super_device, slot_number); |
| 551 | if (!builder) { |
| 552 | errno = save_errno; |
| 553 | return true; |
| 554 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 555 | if (builder->FindPartition(partition_name) == nullptr) { |
| 556 | errno = save_errno; |
| 557 | return true; |
| 558 | } |
| 559 | builder->RemovePartition(partition_name); |
| 560 | auto metadata = builder->Export(); |
| 561 | if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { |
| 562 | if (change) *change = true; |
David Anderson | 470fe2b | 2019-07-10 18:09:50 -0700 | [diff] [blame] | 563 | if (!DestroyLogicalPartition(partition_name)) return false; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 564 | } else { |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 565 | LERROR << "delete partition " << overlay; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 566 | return false; |
| 567 | } |
| 568 | errno = save_errno; |
| 569 | return true; |
| 570 | } |
| 571 | |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 572 | bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point, |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 573 | bool* change, bool* should_destroy_scratch = nullptr) { |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 574 | const auto top = overlay + kOverlayTopDir; |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 575 | |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 576 | if (!fs_mgr_access(top)) { |
| 577 | if (should_destroy_scratch) *should_destroy_scratch = true; |
| 578 | return true; |
| 579 | } |
Mark Salyzyn | aace486 | 2018-03-16 11:00:26 -0700 | [diff] [blame] | 580 | |
| 581 | auto cleanup_all = mount_point.empty(); |
Mark Salyzyn | 9b44e80 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 582 | const auto partition_name = android::base::Basename(mount_point); |
| 583 | const auto oldpath = top + (cleanup_all ? "" : ("/" + partition_name)); |
| 584 | const auto newpath = cleanup_all ? overlay + "/." + kOverlayTopDir.substr(1) + ".teardown" |
| 585 | : top + "/." + partition_name + ".teardown"; |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 586 | auto ret = fs_mgr_rm_all(newpath); |
Mark Salyzyn | aace486 | 2018-03-16 11:00:26 -0700 | [diff] [blame] | 587 | auto save_errno = errno; |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 588 | if (!rename(oldpath.c_str(), newpath.c_str())) { |
| 589 | if (change) *change = true; |
| 590 | } else if (errno != ENOENT) { |
| 591 | ret = false; |
| 592 | PERROR << "mv " << oldpath << " " << newpath; |
| 593 | } else { |
| 594 | errno = save_errno; |
| 595 | } |
| 596 | ret &= fs_mgr_rm_all(newpath, change); |
| 597 | save_errno = errno; |
| 598 | if (!rmdir(newpath.c_str())) { |
| 599 | if (change) *change = true; |
| 600 | } else if (errno != ENOENT) { |
| 601 | ret = false; |
| 602 | PERROR << "rmdir " << newpath; |
| 603 | } else { |
| 604 | errno = save_errno; |
| 605 | } |
Mark Salyzyn | aace486 | 2018-03-16 11:00:26 -0700 | [diff] [blame] | 606 | if (!cleanup_all) { |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 607 | save_errno = errno; |
| 608 | if (!rmdir(top.c_str())) { |
| 609 | if (change) *change = true; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 610 | cleanup_all = true; |
Mark Salyzyn | 9b44e80 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 611 | } else if (errno == ENOTEMPTY) { |
| 612 | cleanup_all = true; |
| 613 | // cleanup all if the content is all hidden (leading .) |
| 614 | std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(top.c_str()), closedir); |
| 615 | if (!dir) { |
| 616 | PERROR << "opendir " << top; |
| 617 | } else { |
| 618 | dirent* entry; |
| 619 | while ((entry = readdir(dir.get()))) { |
| 620 | if (entry->d_name[0] != '.') { |
| 621 | cleanup_all = false; |
| 622 | break; |
| 623 | } |
| 624 | } |
| 625 | } |
| 626 | errno = save_errno; |
| 627 | } else if (errno == ENOENT) { |
| 628 | cleanup_all = true; |
| 629 | errno = save_errno; |
| 630 | } else { |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 631 | ret = false; |
| 632 | PERROR << "rmdir " << top; |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 633 | } |
| 634 | } |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 635 | if (should_destroy_scratch) *should_destroy_scratch = cleanup_all; |
Mark Salyzyn | 336f759 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 636 | return ret; |
| 637 | } |
| 638 | |
Mark Salyzyn | 8cf2103 | 2019-05-29 08:49:11 -0700 | [diff] [blame] | 639 | bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) { |
| 640 | auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE, |
| 641 | nullptr); |
| 642 | if (ret) { |
| 643 | PERROR << "__mount(target=" << mount_point |
| 644 | << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret; |
| 645 | return false; |
| 646 | } |
| 647 | return true; |
| 648 | } |
| 649 | |
| 650 | bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) { |
| 651 | auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr); |
| 652 | if (ret) { |
| 653 | PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret; |
| 654 | return false; |
| 655 | } |
| 656 | return true; |
| 657 | } |
| 658 | |
| 659 | struct mount_info { |
| 660 | std::string mount_point; |
| 661 | bool shared_flag; |
| 662 | }; |
| 663 | |
| 664 | std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) { |
| 665 | std::vector<mount_info> info; |
| 666 | |
| 667 | auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose}; |
| 668 | if (!file) { |
| 669 | PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'"; |
| 670 | return info; |
| 671 | } |
| 672 | |
| 673 | ssize_t len; |
| 674 | size_t alloc_len = 0; |
| 675 | char* line = nullptr; |
| 676 | while ((len = getline(&line, &alloc_len, file.get())) != -1) { |
| 677 | /* if the last character is a newline, shorten the string by 1 byte */ |
| 678 | if (line[len - 1] == '\n') { |
| 679 | line[len - 1] = '\0'; |
| 680 | } |
| 681 | |
| 682 | static constexpr char delim[] = " \t"; |
| 683 | char* save_ptr; |
| 684 | if (!strtok_r(line, delim, &save_ptr)) { |
| 685 | LERROR << "Error parsing mount ID"; |
| 686 | break; |
| 687 | } |
| 688 | if (!strtok_r(nullptr, delim, &save_ptr)) { |
| 689 | LERROR << "Error parsing parent ID"; |
| 690 | break; |
| 691 | } |
| 692 | if (!strtok_r(nullptr, delim, &save_ptr)) { |
| 693 | LERROR << "Error parsing mount source"; |
| 694 | break; |
| 695 | } |
| 696 | if (!strtok_r(nullptr, delim, &save_ptr)) { |
| 697 | LERROR << "Error parsing root"; |
| 698 | break; |
| 699 | } |
| 700 | |
| 701 | char* p; |
| 702 | if (!(p = strtok_r(nullptr, delim, &save_ptr))) { |
| 703 | LERROR << "Error parsing mount_point"; |
| 704 | break; |
| 705 | } |
| 706 | mount_info entry = {p, false}; |
| 707 | |
| 708 | if (!strtok_r(nullptr, delim, &save_ptr)) { |
| 709 | LERROR << "Error parsing mount_flags"; |
| 710 | break; |
| 711 | } |
| 712 | |
| 713 | while ((p = strtok_r(nullptr, delim, &save_ptr))) { |
| 714 | if ((p[0] == '-') && (p[1] == '\0')) break; |
| 715 | if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true; |
| 716 | } |
| 717 | if (!p) { |
| 718 | LERROR << "Error parsing fields"; |
| 719 | break; |
| 720 | } |
| 721 | info.emplace_back(std::move(entry)); |
| 722 | } |
| 723 | |
| 724 | free(line); |
| 725 | if (info.empty()) { |
| 726 | LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'"; |
| 727 | } |
| 728 | return info; |
| 729 | } |
| 730 | |
Mark Salyzyn | d3dc3c8 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 731 | bool fs_mgr_overlayfs_mount(const std::string& mount_point) { |
| 732 | auto options = fs_mgr_get_overlayfs_options(mount_point); |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 733 | if (options.empty()) return false; |
| 734 | |
Mark Salyzyn | 8cf2103 | 2019-05-29 08:49:11 -0700 | [diff] [blame] | 735 | auto retval = true; |
| 736 | auto save_errno = errno; |
| 737 | |
| 738 | struct move_entry { |
| 739 | std::string mount_point; |
| 740 | std::string dir; |
| 741 | bool shared_flag; |
| 742 | }; |
| 743 | std::vector<move_entry> move; |
| 744 | auto parent_private = false; |
| 745 | auto parent_made_private = false; |
| 746 | auto dev_private = false; |
| 747 | auto dev_made_private = false; |
| 748 | for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) { |
| 749 | if ((entry.mount_point == mount_point) && !entry.shared_flag) { |
| 750 | parent_private = true; |
| 751 | } |
| 752 | if ((entry.mount_point == "/dev") && !entry.shared_flag) { |
| 753 | dev_private = true; |
| 754 | } |
| 755 | |
| 756 | if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) { |
| 757 | continue; |
| 758 | } |
| 759 | if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) { |
| 760 | return android::base::StartsWith(entry.mount_point, it.mount_point + "/"); |
| 761 | }) != move.end()) { |
| 762 | continue; |
| 763 | } |
| 764 | |
| 765 | // use as the bound directory in /dev. |
| 766 | auto new_context = fs_mgr_get_context(entry.mount_point); |
| 767 | if (!new_context.empty() && setfscreatecon(new_context.c_str())) { |
| 768 | PERROR << "setfscreatecon " << new_context; |
| 769 | } |
| 770 | move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX", |
| 771 | entry.shared_flag}; |
| 772 | const auto target = mkdtemp(new_entry.dir.data()); |
| 773 | if (!target) { |
| 774 | retval = false; |
| 775 | save_errno = errno; |
| 776 | PERROR << "temporary directory for MS_BIND"; |
| 777 | setfscreatecon(nullptr); |
| 778 | continue; |
| 779 | } |
| 780 | setfscreatecon(nullptr); |
| 781 | |
| 782 | if (!parent_private && !parent_made_private) { |
| 783 | parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false); |
| 784 | } |
| 785 | if (new_entry.shared_flag) { |
| 786 | new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false); |
| 787 | } |
| 788 | if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) { |
| 789 | retval = false; |
| 790 | save_errno = errno; |
| 791 | if (new_entry.shared_flag) { |
| 792 | fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true); |
| 793 | } |
| 794 | continue; |
| 795 | } |
| 796 | move.emplace_back(std::move(new_entry)); |
| 797 | } |
| 798 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 799 | // hijack __mount() report format to help triage |
Mark Salyzyn | d3dc3c8 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 800 | auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay"; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 801 | const auto opt_list = android::base::Split(options, ","); |
Chih-Hung Hsieh | 1b7b797 | 2018-12-11 10:34:33 -0800 | [diff] [blame] | 802 | for (const auto& opt : opt_list) { |
Mark Salyzyn | e5ecbb5 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 803 | if (android::base::StartsWith(opt, kUpperdirOption)) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 804 | report = report + "," + opt; |
| 805 | break; |
| 806 | } |
| 807 | } |
| 808 | report = report + ")="; |
| 809 | |
Mark Salyzyn | 808763e | 2019-08-28 12:53:26 -0700 | [diff] [blame] | 810 | auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 811 | options.c_str()); |
| 812 | if (ret) { |
Mark Salyzyn | 8cf2103 | 2019-05-29 08:49:11 -0700 | [diff] [blame] | 813 | retval = false; |
| 814 | save_errno = errno; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 815 | PERROR << report << ret; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 816 | } else { |
| 817 | LINFO << report << ret; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 818 | } |
Mark Salyzyn | 8cf2103 | 2019-05-29 08:49:11 -0700 | [diff] [blame] | 819 | |
| 820 | // Move submounts back. |
| 821 | for (const auto& entry : move) { |
| 822 | if (!dev_private && !dev_made_private) { |
| 823 | dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false); |
| 824 | } |
| 825 | |
| 826 | if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) { |
| 827 | retval = false; |
| 828 | save_errno = errno; |
| 829 | } else if (entry.shared_flag && |
| 830 | !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) { |
| 831 | retval = false; |
| 832 | save_errno = errno; |
| 833 | } |
| 834 | rmdir(entry.dir.c_str()); |
| 835 | } |
| 836 | if (dev_made_private) { |
| 837 | fs_mgr_overlayfs_set_shared_mount("/dev", true); |
| 838 | } |
| 839 | if (parent_made_private) { |
| 840 | fs_mgr_overlayfs_set_shared_mount(mount_point, true); |
| 841 | } |
| 842 | |
| 843 | errno = save_errno; |
| 844 | return retval; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 845 | } |
| 846 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 847 | // Mount kScratchMountPoint |
Yifan Hong | 3be2c7a | 2019-01-08 13:33:52 -0800 | [diff] [blame] | 848 | bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type, |
| 849 | bool readonly = false) { |
| 850 | if (readonly) { |
| 851 | if (!fs_mgr_access(device_path)) return false; |
| 852 | } else { |
| 853 | if (!fs_mgr_rw_access(device_path)) return false; |
| 854 | } |
| 855 | |
Mark Salyzyn | 60a76f3 | 2019-03-14 15:34:35 -0700 | [diff] [blame] | 856 | auto f2fs = fs_mgr_is_f2fs(device_path); |
| 857 | auto ext4 = fs_mgr_is_ext4(device_path); |
| 858 | if (!f2fs && !ext4) return false; |
| 859 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 860 | if (setfscreatecon(kOverlayfsFileContext)) { |
| 861 | PERROR << "setfscreatecon " << kOverlayfsFileContext; |
| 862 | } |
| 863 | if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) { |
| 864 | PERROR << "create " << kScratchMountPoint; |
| 865 | } |
| 866 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 867 | FstabEntry entry; |
| 868 | entry.blk_device = device_path; |
| 869 | entry.mount_point = kScratchMountPoint; |
| 870 | entry.fs_type = mnt_type; |
Mark Salyzyn | 60a76f3 | 2019-03-14 15:34:35 -0700 | [diff] [blame] | 871 | if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4"; |
| 872 | if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs"; |
Mark Salyzyn | 93ce58d | 2020-02-12 11:43:13 -0800 | [diff] [blame] | 873 | entry.flags = MS_NOATIME | MS_RDONLY; |
| 874 | auto mounted = true; |
| 875 | if (!readonly) { |
| 876 | if (entry.fs_type == "ext4") { |
| 877 | // check if ext4 de-dupe |
| 878 | entry.flags |= MS_RDONLY; |
| 879 | auto save_errno = errno; |
| 880 | mounted = fs_mgr_do_mount_one(entry) == 0; |
| 881 | if (mounted) { |
| 882 | mounted = !fs_mgr_has_shared_blocks(entry.mount_point, entry.blk_device); |
| 883 | fs_mgr_overlayfs_umount_scratch(); |
| 884 | } |
| 885 | errno = save_errno; |
| 886 | } |
| 887 | entry.flags &= ~MS_RDONLY; |
Jaegeuk Kim | bbad87a | 2021-12-29 13:17:15 -0800 | [diff] [blame] | 888 | entry.flags |= MS_SYNCHRONOUS; |
| 889 | entry.fs_options = "nodiscard"; |
Yifan Hong | ccdba57 | 2019-01-08 13:33:52 -0800 | [diff] [blame] | 890 | fs_mgr_set_blk_ro(device_path, false); |
| 891 | } |
Jaegeuk Kim | 06db803 | 2022-01-06 17:28:41 -0800 | [diff] [blame] | 892 | // check_fs requires apex runtime library |
| 893 | if (fs_mgr_overlayfs_already_mounted("/data", false)) { |
| 894 | entry.fs_mgr_flags.check = true; |
| 895 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 896 | auto save_errno = errno; |
Mark Salyzyn | 93ce58d | 2020-02-12 11:43:13 -0800 | [diff] [blame] | 897 | if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0; |
Mark Salyzyn | 6b313de | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 898 | if (!mounted) { |
Mark Salyzyn | 60a76f3 | 2019-03-14 15:34:35 -0700 | [diff] [blame] | 899 | if ((entry.fs_type == "f2fs") && ext4) { |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 900 | entry.fs_type = "ext4"; |
Mark Salyzyn | 60a76f3 | 2019-03-14 15:34:35 -0700 | [diff] [blame] | 901 | mounted = fs_mgr_do_mount_one(entry) == 0; |
| 902 | } else if ((entry.fs_type == "ext4") && f2fs) { |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 903 | entry.fs_type = "f2fs"; |
Mark Salyzyn | 60a76f3 | 2019-03-14 15:34:35 -0700 | [diff] [blame] | 904 | mounted = fs_mgr_do_mount_one(entry) == 0; |
Mark Salyzyn | 6b313de | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 905 | } |
Mark Salyzyn | 6b313de | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 906 | if (!mounted) save_errno = errno; |
| 907 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 908 | setfscreatecon(nullptr); |
| 909 | if (!mounted) rmdir(kScratchMountPoint.c_str()); |
| 910 | errno = save_errno; |
| 911 | return mounted; |
| 912 | } |
| 913 | |
| 914 | const std::string kMkF2fs("/system/bin/make_f2fs"); |
| 915 | const std::string kMkExt4("/system/bin/mke2fs"); |
| 916 | |
Mark Salyzyn | 6b313de | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 917 | // Only a suggestion for _first_ try during mounting |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 918 | std::string fs_mgr_overlayfs_scratch_mount_type() { |
Mark Salyzyn | 6d109ec | 2019-01-30 10:19:15 -0800 | [diff] [blame] | 919 | if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) { |
| 920 | return "f2fs"; |
| 921 | } |
| 922 | if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) { |
| 923 | return "ext4"; |
| 924 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 925 | return "auto"; |
| 926 | } |
| 927 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 928 | // Note: we do not check access() here except for the super partition, since |
| 929 | // in first-stage init we wouldn't have registed by-name symlinks for "other" |
| 930 | // partitions that won't be mounted. |
| 931 | static std::string GetPhysicalScratchDevice() { |
Mark Salyzyn | f269312 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 932 | auto slot_number = fs_mgr_overlayfs_slot_number(); |
| 933 | auto super_device = fs_mgr_overlayfs_super_device(slot_number); |
| 934 | auto path = fs_mgr_overlayfs_super_device(slot_number == 0); |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 935 | if (super_device != path) { |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 936 | return path; |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 937 | } |
| 938 | if (fs_mgr_access(super_device)) { |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 939 | // Do not try to use system_other on a DAP device. |
| 940 | return ""; |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 941 | } |
| 942 | |
| 943 | auto other_slot = fs_mgr_get_other_slot_suffix(); |
| 944 | if (!other_slot.empty()) { |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 945 | return kPhysicalDevice + "system" + other_slot; |
Mark Salyzyn | f269312 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 946 | } |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 947 | return ""; |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 948 | } |
| 949 | |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 950 | // Note: The scratch partition of DSU is managed by gsid, and should be initialized during |
| 951 | // first-stage-mount. Just check if the DM device for DSU scratch partition is created or not. |
| 952 | static std::string GetDsuScratchDevice() { |
| 953 | auto& dm = DeviceMapper::Instance(); |
| 954 | std::string device; |
| 955 | if (dm.GetState(android::gsi::kDsuScratch) != DmDeviceState::INVALID && |
| 956 | dm.GetDmDevicePathByName(android::gsi::kDsuScratch, &device)) { |
| 957 | return device; |
| 958 | } |
| 959 | return ""; |
| 960 | } |
| 961 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 962 | // This returns the scratch device that was detected during early boot (first- |
| 963 | // stage init). If the device was created later, for example during setup for |
| 964 | // the adb remount command, it can return an empty string since it does not |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 965 | // query ImageManager. (Note that ImageManager in first-stage init will always |
| 966 | // use device-mapper, since /data is not available to use loop devices.) |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 967 | static std::string GetBootScratchDevice() { |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 968 | // Note: fs_mgr_is_dsu_running() always returns false in recovery or fastbootd. |
| 969 | if (fs_mgr_is_dsu_running()) { |
| 970 | return GetDsuScratchDevice(); |
| 971 | } |
| 972 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 973 | auto& dm = DeviceMapper::Instance(); |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 974 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 975 | // If there is a scratch partition allocated in /data or on super, we |
| 976 | // automatically prioritize that over super_other or system_other. |
| 977 | // Some devices, for example, have a write-protected eMMC and the |
| 978 | // super partition cannot be used even if it exists. |
| 979 | std::string device; |
| 980 | auto partition_name = android::base::Basename(kScratchMountPoint); |
| 981 | if (dm.GetState(partition_name) != DmDeviceState::INVALID && |
| 982 | dm.GetDmDevicePathByName(partition_name, &device)) { |
| 983 | return device; |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 984 | } |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 985 | |
| 986 | // There is no dynamic scratch, so try and find a physical one. |
| 987 | return GetPhysicalScratchDevice(); |
David Anderson | 864021f | 2019-12-10 21:07:51 -0800 | [diff] [blame] | 988 | } |
| 989 | |
Mark Salyzyn | d14eb57 | 2018-12-05 10:19:48 -0800 | [diff] [blame] | 990 | bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) { |
| 991 | // Force mkfs by design for overlay support of adb remount, simplify and |
| 992 | // thus do not rely on fsck to correct problems that could creep in. |
| 993 | auto command = ""s; |
| 994 | if (mnt_type == "f2fs") { |
| 995 | command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); |
| 996 | } else if (mnt_type == "ext4") { |
Mark Salyzyn | 6d109ec | 2019-01-30 10:19:15 -0800 | [diff] [blame] | 997 | command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; |
Mark Salyzyn | d14eb57 | 2018-12-05 10:19:48 -0800 | [diff] [blame] | 998 | } else { |
| 999 | errno = ESRCH; |
| 1000 | LERROR << mnt_type << " has no mkfs cookbook"; |
| 1001 | return false; |
| 1002 | } |
Mark Salyzyn | 4560714 | 2019-04-17 11:21:12 -0700 | [diff] [blame] | 1003 | command += " " + scratch_device + " >/dev/null 2>/dev/null </dev/null"; |
Yifan Hong | ccdba57 | 2019-01-08 13:33:52 -0800 | [diff] [blame] | 1004 | fs_mgr_set_blk_ro(scratch_device, false); |
Mark Salyzyn | d14eb57 | 2018-12-05 10:19:48 -0800 | [diff] [blame] | 1005 | auto ret = system(command.c_str()); |
| 1006 | if (ret) { |
| 1007 | LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret; |
| 1008 | return false; |
| 1009 | } |
| 1010 | return true; |
| 1011 | } |
| 1012 | |
Mark Salyzyn | c3fc2aa | 2019-04-30 13:21:04 -0700 | [diff] [blame] | 1013 | static void TruncatePartitionsWithSuffix(MetadataBuilder* builder, const std::string& suffix) { |
| 1014 | auto& dm = DeviceMapper::Instance(); |
| 1015 | |
| 1016 | // Remove <other> partitions |
| 1017 | for (const auto& group : builder->ListGroups()) { |
| 1018 | for (const auto& part : builder->ListPartitionsInGroup(group)) { |
| 1019 | const auto& name = part->name(); |
| 1020 | if (!android::base::EndsWith(name, suffix)) { |
| 1021 | continue; |
| 1022 | } |
David Anderson | 470fe2b | 2019-07-10 18:09:50 -0700 | [diff] [blame] | 1023 | if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name)) { |
Mark Salyzyn | c3fc2aa | 2019-04-30 13:21:04 -0700 | [diff] [blame] | 1024 | continue; |
| 1025 | } |
| 1026 | builder->ResizePartition(builder->FindPartition(name), 0); |
| 1027 | } |
| 1028 | } |
| 1029 | } |
| 1030 | |
David Anderson | a3bf847 | 2019-12-10 20:43:40 -0800 | [diff] [blame] | 1031 | // Create or update a scratch partition within super. |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1032 | static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_exists, |
| 1033 | bool* change) { |
David Anderson | a3bf847 | 2019-12-10 20:43:40 -0800 | [diff] [blame] | 1034 | const auto partition_name = android::base::Basename(kScratchMountPoint); |
| 1035 | |
| 1036 | auto& dm = DeviceMapper::Instance(); |
| 1037 | *partition_exists = dm.GetState(partition_name) != DmDeviceState::INVALID; |
| 1038 | |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1039 | auto partition_create = !*partition_exists; |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1040 | auto slot_number = fs_mgr_overlayfs_slot_number(); |
| 1041 | auto super_device = fs_mgr_overlayfs_super_device(slot_number); |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1042 | auto builder = MetadataBuilder::New(super_device, slot_number); |
| 1043 | if (!builder) { |
| 1044 | LERROR << "open " << super_device << " metadata"; |
| 1045 | return false; |
| 1046 | } |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1047 | auto partition = builder->FindPartition(partition_name); |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1048 | *partition_exists = partition != nullptr; |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1049 | auto changed = false; |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1050 | if (!*partition_exists) { |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1051 | partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); |
| 1052 | if (!partition) { |
| 1053 | LERROR << "create " << partition_name; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1054 | return false; |
| 1055 | } |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1056 | changed = true; |
| 1057 | } |
Mark Salyzyn | 756eebe | 2018-11-27 16:14:35 -0800 | [diff] [blame] | 1058 | // Take half of free space, minimum 512MB or maximum free - margin. |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1059 | static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024); |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1060 | if (partition->size() < kMinimumSize) { |
| 1061 | auto partition_size = |
| 1062 | builder->AllocatableSpace() - builder->UsedSpace() + partition->size(); |
| 1063 | if ((partition_size > kMinimumSize) || !partition->size()) { |
Mark Salyzyn | 756eebe | 2018-11-27 16:14:35 -0800 | [diff] [blame] | 1064 | // Leave some space for free space jitter of a few erase |
| 1065 | // blocks, in case they are needed for any individual updates |
| 1066 | // to any other partition that needs to be flashed while |
| 1067 | // overlayfs is in force. Of course if margin_size is not |
| 1068 | // enough could normally get a flash failure, so |
| 1069 | // ResizePartition() will delete the scratch partition in |
| 1070 | // order to fulfill. Deleting scratch will destroy all of |
| 1071 | // the adb remount overrides :-( . |
| 1072 | auto margin_size = uint64_t(3 * 256 * 1024); |
| 1073 | BlockDeviceInfo info; |
Mark Salyzyn | c3fc2aa | 2019-04-30 13:21:04 -0700 | [diff] [blame] | 1074 | if (builder->GetBlockDeviceInfo(fs_mgr_get_super_partition_name(slot_number), &info)) { |
Mark Salyzyn | 756eebe | 2018-11-27 16:14:35 -0800 | [diff] [blame] | 1075 | margin_size = 3 * info.logical_block_size; |
| 1076 | } |
| 1077 | partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size), |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1078 | partition_size / 2); |
| 1079 | if (partition_size > partition->size()) { |
| 1080 | if (!builder->ResizePartition(partition, partition_size)) { |
Mark Salyzyn | c3fc2aa | 2019-04-30 13:21:04 -0700 | [diff] [blame] | 1081 | // Try to free up space by deallocating partitions in the other slot. |
| 1082 | TruncatePartitionsWithSuffix(builder.get(), fs_mgr_get_other_slot_suffix()); |
| 1083 | |
| 1084 | partition_size = |
| 1085 | builder->AllocatableSpace() - builder->UsedSpace() + partition->size(); |
| 1086 | partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size), |
| 1087 | partition_size / 2); |
| 1088 | if (!builder->ResizePartition(partition, partition_size)) { |
| 1089 | LERROR << "resize " << partition_name; |
| 1090 | return false; |
| 1091 | } |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1092 | } |
David Anderson | 470fe2b | 2019-07-10 18:09:50 -0700 | [diff] [blame] | 1093 | if (!partition_create) DestroyLogicalPartition(partition_name); |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1094 | changed = true; |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1095 | *partition_exists = false; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1096 | } |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1097 | } |
| 1098 | } |
| 1099 | // land the update back on to the partition |
| 1100 | if (changed) { |
| 1101 | auto metadata = builder->Export(); |
| 1102 | if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { |
| 1103 | LERROR << "add partition " << partition_name; |
| 1104 | return false; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1105 | } |
| 1106 | |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1107 | if (change) *change = true; |
| 1108 | } |
| 1109 | |
| 1110 | if (changed || partition_create) { |
David Anderson | 15aa954 | 2019-08-12 17:07:50 -0700 | [diff] [blame] | 1111 | CreateLogicalPartitionParams params = { |
| 1112 | .block_device = super_device, |
| 1113 | .metadata_slot = slot_number, |
| 1114 | .partition_name = partition_name, |
| 1115 | .force_writable = true, |
| 1116 | .timeout_ms = 10s, |
| 1117 | }; |
| 1118 | if (!CreateLogicalPartition(params, scratch_device)) { |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1119 | return false; |
David Anderson | 15aa954 | 2019-08-12 17:07:50 -0700 | [diff] [blame] | 1120 | } |
Mark Salyzyn | cb2f6b6 | 2018-11-20 12:59:21 -0800 | [diff] [blame] | 1121 | |
| 1122 | if (change) *change = true; |
Mark Salyzyn | 5ced760 | 2020-02-11 07:52:18 -0800 | [diff] [blame] | 1123 | } else if (scratch_device->empty()) { |
| 1124 | *scratch_device = GetBootScratchDevice(); |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1125 | } |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1126 | return true; |
| 1127 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1128 | |
David Anderson | c1c05da | 2022-02-16 18:57:41 -0800 | [diff] [blame] | 1129 | static inline uint64_t GetIdealDataScratchSize() { |
| 1130 | BlockDeviceInfo super_info; |
| 1131 | PartitionOpener opener; |
| 1132 | if (!opener.GetInfo(fs_mgr_get_super_partition_name(), &super_info)) { |
| 1133 | LERROR << "could not get block device info for super"; |
| 1134 | return 0; |
| 1135 | } |
| 1136 | |
| 1137 | struct statvfs s; |
| 1138 | if (statvfs("/data", &s) < 0) { |
| 1139 | PERROR << "could not statfs /data"; |
| 1140 | return 0; |
| 1141 | } |
| 1142 | |
| 1143 | return std::min(super_info.size, (uint64_t(s.f_frsize) * s.f_bfree) / 2); |
| 1144 | } |
| 1145 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1146 | static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exists, bool* change) { |
| 1147 | *partition_exists = false; |
George Burgess IV | 1c8d814 | 2020-11-09 22:15:16 -0800 | [diff] [blame] | 1148 | if (change) *change = false; |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1149 | |
| 1150 | auto images = IImageManager::Open("remount", 10s); |
| 1151 | if (!images) { |
| 1152 | return false; |
| 1153 | } |
| 1154 | |
| 1155 | auto partition_name = android::base::Basename(kScratchMountPoint); |
| 1156 | if (images->GetMappedImageDevice(partition_name, scratch_device)) { |
| 1157 | *partition_exists = true; |
| 1158 | return true; |
| 1159 | } |
| 1160 | |
George Burgess IV | 1c8d814 | 2020-11-09 22:15:16 -0800 | [diff] [blame] | 1161 | if (change) *change = true; |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1162 | |
| 1163 | // Note: calling RemoveDisabledImages here ensures that we do not race with |
| 1164 | // clean_scratch_files and accidentally try to map an image that will be |
| 1165 | // deleted. |
| 1166 | if (!images->RemoveDisabledImages()) { |
| 1167 | return false; |
| 1168 | } |
| 1169 | if (!images->BackingImageExists(partition_name)) { |
David Anderson | c1c05da | 2022-02-16 18:57:41 -0800 | [diff] [blame] | 1170 | uint64_t size = GetIdealDataScratchSize(); |
| 1171 | if (!size) { |
| 1172 | size = 2_GiB; |
| 1173 | } |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1174 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1175 | auto flags = IImageManager::CREATE_IMAGE_DEFAULT; |
| 1176 | |
| 1177 | if (!images->CreateBackingImage(partition_name, size, flags)) { |
| 1178 | LERROR << "could not create scratch image of " << size << " bytes"; |
| 1179 | return false; |
| 1180 | } |
| 1181 | } |
| 1182 | if (!images->MapImageDevice(partition_name, 10s, scratch_device)) { |
| 1183 | LERROR << "could not map scratch image"; |
| 1184 | return false; |
| 1185 | } |
| 1186 | return true; |
| 1187 | } |
| 1188 | |
| 1189 | static bool CanUseSuperPartition(const Fstab& fstab, bool* is_virtual_ab) { |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1190 | auto slot_number = fs_mgr_overlayfs_slot_number(); |
| 1191 | auto super_device = fs_mgr_overlayfs_super_device(slot_number); |
| 1192 | if (!fs_mgr_rw_access(super_device) || !fs_mgr_overlayfs_has_logical(fstab)) { |
David Anderson | a3bf847 | 2019-12-10 20:43:40 -0800 | [diff] [blame] | 1193 | return false; |
| 1194 | } |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1195 | auto metadata = ReadMetadata(super_device, slot_number); |
| 1196 | if (!metadata) { |
| 1197 | return false; |
| 1198 | } |
| 1199 | *is_virtual_ab = !!(metadata->header.flags & LP_HEADER_FLAG_VIRTUAL_AB_DEVICE); |
David Anderson | a3bf847 | 2019-12-10 20:43:40 -0800 | [diff] [blame] | 1200 | return true; |
| 1201 | } |
| 1202 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1203 | bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device, |
| 1204 | bool* partition_exists, bool* change) { |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1205 | // Use the DSU scratch device managed by gsid if within a DSU system. |
| 1206 | if (fs_mgr_is_dsu_running()) { |
| 1207 | *scratch_device = GetDsuScratchDevice(); |
| 1208 | *partition_exists = !scratch_device->empty(); |
| 1209 | *change = false; |
| 1210 | return *partition_exists; |
| 1211 | } |
| 1212 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1213 | // Try a physical partition first. |
| 1214 | *scratch_device = GetPhysicalScratchDevice(); |
| 1215 | if (!scratch_device->empty() && fs_mgr_rw_access(*scratch_device)) { |
| 1216 | *partition_exists = true; |
| 1217 | return true; |
| 1218 | } |
| 1219 | |
| 1220 | // If that fails, see if we can land on super. |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1221 | bool is_virtual_ab; |
| 1222 | if (CanUseSuperPartition(fstab, &is_virtual_ab)) { |
| 1223 | bool can_use_data = false; |
| 1224 | if (is_virtual_ab && FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) { |
| 1225 | return CreateScratchOnData(scratch_device, partition_exists, change); |
| 1226 | } |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1227 | return CreateDynamicScratch(scratch_device, partition_exists, change); |
| 1228 | } |
| 1229 | |
| 1230 | errno = ENXIO; |
| 1231 | return false; |
| 1232 | } |
| 1233 | |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1234 | // Create and mount kScratchMountPoint storage if we have logical partitions |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1235 | bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab, bool* change) { |
Mark Salyzyn | 13a6605 | 2018-12-05 10:45:06 -0800 | [diff] [blame] | 1236 | if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; |
| 1237 | |
| 1238 | std::string scratch_device; |
| 1239 | bool partition_exists; |
| 1240 | if (!fs_mgr_overlayfs_create_scratch(fstab, &scratch_device, &partition_exists, change)) { |
| 1241 | return false; |
| 1242 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1243 | |
Mark Salyzyn | d14eb57 | 2018-12-05 10:19:48 -0800 | [diff] [blame] | 1244 | // If the partition exists, assume first that it can be mounted. |
| 1245 | auto mnt_type = fs_mgr_overlayfs_scratch_mount_type(); |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1246 | if (partition_exists) { |
| 1247 | if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) { |
Mark Salyzyn | df8cf18 | 2019-01-04 14:43:27 -0800 | [diff] [blame] | 1248 | if (!fs_mgr_access(kScratchMountPoint + kOverlayTopDir) && |
| 1249 | !fs_mgr_filesystem_has_space(kScratchMountPoint)) { |
| 1250 | // declare it useless, no overrides and no free space |
| 1251 | fs_mgr_overlayfs_umount_scratch(); |
| 1252 | } else { |
| 1253 | if (change) *change = true; |
| 1254 | return true; |
| 1255 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1256 | } |
Mark Salyzyn | d14eb57 | 2018-12-05 10:19:48 -0800 | [diff] [blame] | 1257 | // partition existed, but was not initialized; fall through to make it. |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1258 | errno = 0; |
| 1259 | } |
| 1260 | |
Mark Salyzyn | d14eb57 | 2018-12-05 10:19:48 -0800 | [diff] [blame] | 1261 | if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) return false; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1262 | |
| 1263 | if (change) *change = true; |
| 1264 | |
| 1265 | return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type); |
| 1266 | } |
| 1267 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1268 | bool fs_mgr_overlayfs_invalid() { |
Mark Salyzyn | 9040aa5 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 1269 | if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true; |
| 1270 | |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1271 | // in recovery or fastbootd, not allowed! |
| 1272 | return fs_mgr_in_recovery(); |
Mark Salyzyn | 9040aa5 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 1273 | } |
| 1274 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1275 | } // namespace |
| 1276 | |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1277 | Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) { |
| 1278 | Fstab candidates; |
| 1279 | for (const auto& entry : fstab) { |
| 1280 | FstabEntry new_entry = entry; |
Ryan Savitski | 814cbfa | 2019-07-30 12:01:46 +0000 | [diff] [blame] | 1281 | if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) && |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1282 | !fs_mgr_wants_overlayfs(&new_entry)) { |
| 1283 | continue; |
| 1284 | } |
| 1285 | auto new_mount_point = fs_mgr_mount_point(entry.mount_point); |
| 1286 | auto duplicate_or_more_specific = false; |
| 1287 | for (auto it = candidates.begin(); it != candidates.end();) { |
| 1288 | auto it_mount_point = fs_mgr_mount_point(it->mount_point); |
| 1289 | if ((it_mount_point == new_mount_point) || |
| 1290 | (android::base::StartsWith(new_mount_point, it_mount_point + "/"))) { |
| 1291 | duplicate_or_more_specific = true; |
| 1292 | break; |
| 1293 | } |
| 1294 | if (android::base::StartsWith(it_mount_point, new_mount_point + "/")) { |
| 1295 | it = candidates.erase(it); |
| 1296 | } else { |
| 1297 | ++it; |
| 1298 | } |
| 1299 | } |
| 1300 | if (!duplicate_or_more_specific) candidates.emplace_back(std::move(new_entry)); |
| 1301 | } |
| 1302 | return candidates; |
| 1303 | } |
| 1304 | |
David Anderson | cd720dc | 2019-12-10 21:08:08 -0800 | [diff] [blame] | 1305 | static void TryMountScratch() { |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1306 | // Note we get the boot scratch device here, which means if scratch was |
| 1307 | // just created through ImageManager, this could fail. In practice this |
| 1308 | // should not happen because "remount" detects this scenario (by checking |
| 1309 | // if verity is still disabled, i.e. no reboot occurred), and skips calling |
| 1310 | // fs_mgr_overlayfs_mount_all(). |
| 1311 | auto scratch_device = GetBootScratchDevice(); |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1312 | if (!fs_mgr_rw_access(scratch_device)) { |
David Anderson | cd720dc | 2019-12-10 21:08:08 -0800 | [diff] [blame] | 1313 | return; |
| 1314 | } |
| 1315 | if (!WaitForFile(scratch_device, 10s)) { |
| 1316 | return; |
| 1317 | } |
| 1318 | const auto mount_type = fs_mgr_overlayfs_scratch_mount_type(); |
| 1319 | if (!fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type, true /* readonly */)) { |
| 1320 | return; |
| 1321 | } |
| 1322 | auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir); |
| 1323 | fs_mgr_overlayfs_umount_scratch(); |
| 1324 | if (has_overlayfs_dir) { |
| 1325 | fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type); |
| 1326 | } |
| 1327 | } |
| 1328 | |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1329 | bool fs_mgr_overlayfs_mount_all(Fstab* fstab) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1330 | auto ret = false; |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1331 | if (fs_mgr_overlayfs_invalid()) return ret; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1332 | |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1333 | auto scratch_can_be_mounted = true; |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1334 | for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) { |
| 1335 | if (fs_mgr_is_verity_enabled(entry)) continue; |
| 1336 | auto mount_point = fs_mgr_mount_point(entry.mount_point); |
Mark Salyzyn | fab9f08 | 2019-02-04 14:59:16 -0800 | [diff] [blame] | 1337 | if (fs_mgr_overlayfs_already_mounted(mount_point)) { |
| 1338 | ret = true; |
| 1339 | continue; |
| 1340 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1341 | if (scratch_can_be_mounted) { |
| 1342 | scratch_can_be_mounted = false; |
David Anderson | cd720dc | 2019-12-10 21:08:08 -0800 | [diff] [blame] | 1343 | TryMountScratch(); |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1344 | } |
Mark Salyzyn | d3dc3c8 | 2018-06-13 09:33:28 -0700 | [diff] [blame] | 1345 | if (fs_mgr_overlayfs_mount(mount_point)) ret = true; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1346 | } |
| 1347 | return ret; |
| 1348 | } |
| 1349 | |
| 1350 | // Returns false if setup not permitted, errno set to last error. |
| 1351 | // If something is altered, set *change. |
Ed Chen | 1981401 | 2019-12-17 08:53:13 +0000 | [diff] [blame] | 1352 | bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change, |
| 1353 | bool force) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1354 | if (change) *change = false; |
| 1355 | auto ret = false; |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 1356 | if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1357 | if (!fs_mgr_boot_completed()) { |
| 1358 | errno = EBUSY; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 1359 | PERROR << "setup"; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1360 | return ret; |
| 1361 | } |
| 1362 | |
Mark Salyzyn | d202c55 | 2018-12-12 10:36:32 -0800 | [diff] [blame] | 1363 | auto save_errno = errno; |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1364 | Fstab fstab; |
| 1365 | if (!ReadDefaultFstab(&fstab)) { |
| 1366 | return false; |
| 1367 | } |
Mark Salyzyn | d202c55 | 2018-12-12 10:36:32 -0800 | [diff] [blame] | 1368 | errno = save_errno; |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1369 | auto candidates = fs_mgr_overlayfs_candidate_list(fstab); |
| 1370 | for (auto it = candidates.begin(); it != candidates.end();) { |
| 1371 | if (mount_point && |
| 1372 | (fs_mgr_mount_point(it->mount_point) != fs_mgr_mount_point(mount_point))) { |
| 1373 | it = candidates.erase(it); |
| 1374 | continue; |
| 1375 | } |
| 1376 | save_errno = errno; |
Mark Salyzyn | e0c581f | 2019-05-29 14:01:56 -0700 | [diff] [blame] | 1377 | auto verity_enabled = !force && fs_mgr_is_verity_enabled(*it); |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1378 | if (errno == ENOENT || errno == ENXIO) errno = save_errno; |
| 1379 | if (verity_enabled) { |
| 1380 | it = candidates.erase(it); |
| 1381 | continue; |
| 1382 | } |
| 1383 | ++it; |
| 1384 | } |
| 1385 | |
| 1386 | if (candidates.empty()) return ret; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1387 | |
| 1388 | std::string dir; |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 1389 | for (const auto& overlay_mount_point : OverlayMountPoints()) { |
Ed Chen | 1981401 | 2019-12-17 08:53:13 +0000 | [diff] [blame] | 1390 | if (backing && backing[0] && (overlay_mount_point != backing)) continue; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1391 | if (overlay_mount_point == kScratchMountPoint) { |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1392 | if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1393 | } else { |
Tom Cherry | 2e545f8 | 2019-01-29 08:49:57 -0800 | [diff] [blame] | 1394 | if (GetEntryForMountPoint(&fstab, overlay_mount_point) == nullptr) { |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1395 | continue; |
| 1396 | } |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1397 | } |
| 1398 | dir = overlay_mount_point; |
| 1399 | break; |
| 1400 | } |
| 1401 | if (dir.empty()) { |
Mark Salyzyn | d202c55 | 2018-12-12 10:36:32 -0800 | [diff] [blame] | 1402 | if (change && *change) errno = ESRCH; |
| 1403 | if (errno == EPERM) errno = save_errno; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1404 | return ret; |
| 1405 | } |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1406 | |
Mark Salyzyn | 780db02 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1407 | std::string overlay; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1408 | ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change); |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1409 | for (const auto& entry : candidates) { |
| 1410 | ret |= fs_mgr_overlayfs_setup_one(overlay, fs_mgr_mount_point(entry.mount_point), change); |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1411 | } |
| 1412 | return ret; |
| 1413 | } |
| 1414 | |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1415 | struct MapInfo { |
| 1416 | // If set, partition is owned by ImageManager. |
| 1417 | std::unique_ptr<IImageManager> images; |
| 1418 | // If set, and images is null, this is a DAP partition. |
| 1419 | std::string name; |
| 1420 | // If set, and images and name are empty, this is a non-dynamic partition. |
| 1421 | std::string device; |
| 1422 | |
| 1423 | MapInfo() = default; |
| 1424 | MapInfo(MapInfo&&) = default; |
| 1425 | ~MapInfo() { |
| 1426 | if (images) { |
| 1427 | images->UnmapImageDevice(name); |
| 1428 | } else if (!name.empty()) { |
| 1429 | DestroyLogicalPartition(name); |
| 1430 | } |
| 1431 | } |
| 1432 | }; |
| 1433 | |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1434 | // Note: This function never returns the DSU scratch device in recovery or fastbootd, |
| 1435 | // because the DSU scratch is created in the first-stage-mount, which is not run in recovery. |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1436 | static std::optional<MapInfo> EnsureScratchMapped() { |
| 1437 | MapInfo info; |
| 1438 | info.device = GetBootScratchDevice(); |
| 1439 | if (!info.device.empty()) { |
| 1440 | return {std::move(info)}; |
David Anderson | 43d9f18 | 2019-12-10 21:18:28 -0800 | [diff] [blame] | 1441 | } |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1442 | if (!fs_mgr_in_recovery()) { |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1443 | return {}; |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1444 | } |
| 1445 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1446 | auto partition_name = android::base::Basename(kScratchMountPoint); |
| 1447 | |
| 1448 | // Check for scratch on /data first, before looking for a modified super |
| 1449 | // partition. We should only reach this code in recovery, because scratch |
| 1450 | // would otherwise always be mapped. |
| 1451 | auto images = IImageManager::Open("remount", 10s); |
| 1452 | if (images && images->BackingImageExists(partition_name)) { |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1453 | if (images->IsImageDisabled(partition_name)) { |
| 1454 | return {}; |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1455 | } |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1456 | if (!images->MapImageDevice(partition_name, 10s, &info.device)) { |
| 1457 | return {}; |
| 1458 | } |
| 1459 | info.name = partition_name; |
| 1460 | info.images = std::move(images); |
| 1461 | return {std::move(info)}; |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1462 | } |
| 1463 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1464 | // Avoid uart spam by first checking for a scratch partition. |
| 1465 | auto metadata_slot = fs_mgr_overlayfs_slot_number(); |
| 1466 | auto super_device = fs_mgr_overlayfs_super_device(metadata_slot); |
| 1467 | auto metadata = ReadCurrentMetadata(super_device); |
| 1468 | if (!metadata) { |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1469 | return {}; |
David Anderson | 43d9f18 | 2019-12-10 21:18:28 -0800 | [diff] [blame] | 1470 | } |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1471 | |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1472 | auto partition = FindPartition(*metadata.get(), partition_name); |
| 1473 | if (!partition) { |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1474 | return {}; |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1475 | } |
| 1476 | |
| 1477 | CreateLogicalPartitionParams params = { |
| 1478 | .block_device = super_device, |
| 1479 | .metadata = metadata.get(), |
| 1480 | .partition = partition, |
| 1481 | .force_writable = true, |
| 1482 | .timeout_ms = 10s, |
| 1483 | }; |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1484 | if (!CreateLogicalPartition(params, &info.device)) { |
| 1485 | return {}; |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1486 | } |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1487 | info.name = partition_name; |
| 1488 | return {std::move(info)}; |
David Anderson | 43d9f18 | 2019-12-10 21:18:28 -0800 | [diff] [blame] | 1489 | } |
| 1490 | |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1491 | // This should only be reachable in recovery, where DSU scratch is not |
| 1492 | // automatically mapped. |
| 1493 | static bool MapDsuScratchDevice(std::string* device) { |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1494 | std::string dsu_slot; |
| 1495 | if (!android::gsi::IsGsiInstalled() || !android::gsi::GetActiveDsu(&dsu_slot) || |
| 1496 | dsu_slot.empty()) { |
| 1497 | // Nothing to do if no DSU installation present. |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1498 | return false; |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1499 | } |
| 1500 | |
| 1501 | auto images = IImageManager::Open("dsu/" + dsu_slot, 10s); |
| 1502 | if (!images || !images->BackingImageExists(android::gsi::kDsuScratch)) { |
| 1503 | // Nothing to do if DSU scratch device doesn't exist. |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1504 | return false; |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1505 | } |
| 1506 | |
| 1507 | images->UnmapImageDevice(android::gsi::kDsuScratch); |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1508 | if (!images->MapImageDevice(android::gsi::kDsuScratch, 10s, device)) { |
| 1509 | return false; |
| 1510 | } |
| 1511 | return true; |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1512 | } |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1513 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1514 | // Returns false if teardown not permitted, errno set to last error. |
| 1515 | // If something is altered, set *change. |
| 1516 | bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) { |
| 1517 | if (change) *change = false; |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1518 | auto ret = true; |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1519 | |
Mark Salyzyn | 7f47e4b | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 1520 | // If scratch exists, but is not mounted, lets gain access to clean |
| 1521 | // specific override entries. |
Mark Salyzyn | c0966c9 | 2018-11-26 09:57:17 -0800 | [diff] [blame] | 1522 | auto mount_scratch = false; |
Mark Salyzyn | 7f47e4b | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 1523 | if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) { |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1524 | std::string scratch_device = GetBootScratchDevice(); |
| 1525 | if (!scratch_device.empty()) { |
David Anderson | 43d9f18 | 2019-12-10 21:18:28 -0800 | [diff] [blame] | 1526 | mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device, |
| 1527 | fs_mgr_overlayfs_scratch_mount_type()); |
Mark Salyzyn | 7f47e4b | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 1528 | } |
Mark Salyzyn | 7f47e4b | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 1529 | } |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1530 | bool should_destroy_scratch = false; |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 1531 | for (const auto& overlay_mount_point : OverlayMountPoints()) { |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1532 | ret &= fs_mgr_overlayfs_teardown_one( |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1533 | overlay_mount_point, mount_point ? fs_mgr_mount_point(mount_point) : "", change, |
| 1534 | overlay_mount_point == kScratchMountPoint ? &should_destroy_scratch : nullptr); |
| 1535 | } |
| 1536 | // Do not attempt to destroy DSU scratch if within a DSU system, |
| 1537 | // because DSU scratch partition is managed by gsid. |
| 1538 | if (should_destroy_scratch && !fs_mgr_is_dsu_running()) { |
Yo Chiang | 0267bf0 | 2020-10-21 22:25:21 +0800 | [diff] [blame] | 1539 | ret &= fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, change); |
Mark Salyzyn | 69ebd44 | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1540 | } |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 1541 | if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1542 | // After obligatory teardown to make sure everything is clean, but if |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1543 | // we didn't want overlayfs in the first place, we do not want to |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1544 | // waste time on a reboot (or reboot request message). |
| 1545 | if (change) *change = false; |
| 1546 | } |
| 1547 | // And now that we did what we could, lets inform |
| 1548 | // caller that there may still be more to do. |
| 1549 | if (!fs_mgr_boot_completed()) { |
| 1550 | errno = EBUSY; |
Mark Salyzyn | 03df423 | 2018-08-29 10:44:33 -0700 | [diff] [blame] | 1551 | PERROR << "teardown"; |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1552 | ret = false; |
| 1553 | } |
David Anderson | 69def12 | 2019-12-15 22:51:33 -0800 | [diff] [blame] | 1554 | if (mount_scratch) { |
| 1555 | fs_mgr_overlayfs_umount_scratch(); |
| 1556 | } |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1557 | return ret; |
| 1558 | } |
| 1559 | |
Mark Salyzyn | dd748aa | 2018-12-03 13:42:22 -0800 | [diff] [blame] | 1560 | bool fs_mgr_overlayfs_is_setup() { |
| 1561 | if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; |
Tom Cherry | 23319eb | 2018-11-30 16:16:05 -0800 | [diff] [blame] | 1562 | Fstab fstab; |
| 1563 | if (!ReadDefaultFstab(&fstab)) { |
| 1564 | return false; |
| 1565 | } |
| 1566 | if (fs_mgr_overlayfs_invalid()) return false; |
Mark Salyzyn | dffdb43 | 2019-01-24 11:08:10 -0800 | [diff] [blame] | 1567 | for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) { |
| 1568 | if (fs_mgr_is_verity_enabled(entry)) continue; |
| 1569 | if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true; |
Mark Salyzyn | dd748aa | 2018-12-03 13:42:22 -0800 | [diff] [blame] | 1570 | } |
| 1571 | return false; |
| 1572 | } |
| 1573 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1574 | namespace android { |
| 1575 | namespace fs_mgr { |
| 1576 | |
| 1577 | void MapScratchPartitionIfNeeded(Fstab* fstab, |
| 1578 | const std::function<bool(const std::set<std::string>&)>& init) { |
| 1579 | if (fs_mgr_overlayfs_invalid()) { |
| 1580 | return; |
| 1581 | } |
| 1582 | if (GetEntryForMountPoint(fstab, kScratchMountPoint) != nullptr) { |
| 1583 | return; |
| 1584 | } |
| 1585 | |
| 1586 | bool want_scratch = false; |
| 1587 | for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) { |
| 1588 | if (fs_mgr_is_verity_enabled(entry)) { |
| 1589 | continue; |
| 1590 | } |
| 1591 | if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) { |
| 1592 | continue; |
| 1593 | } |
| 1594 | want_scratch = true; |
| 1595 | break; |
| 1596 | } |
| 1597 | if (!want_scratch) { |
| 1598 | return; |
| 1599 | } |
| 1600 | |
| 1601 | if (ScratchIsOnData()) { |
| 1602 | if (auto images = IImageManager::Open("remount", 0ms)) { |
| 1603 | images->MapAllImages(init); |
| 1604 | } |
| 1605 | } |
| 1606 | |
| 1607 | // Physical or logical partitions will have already been mapped here, |
| 1608 | // so just ensure /dev/block symlinks exist. |
| 1609 | auto device = GetBootScratchDevice(); |
| 1610 | if (!device.empty()) { |
| 1611 | init({android::base::Basename(device)}); |
| 1612 | } |
| 1613 | } |
| 1614 | |
| 1615 | void CleanupOldScratchFiles() { |
| 1616 | if (!ScratchIsOnData()) { |
| 1617 | return; |
| 1618 | } |
| 1619 | if (auto images = IImageManager::Open("remount", 0ms)) { |
| 1620 | images->RemoveDisabledImages(); |
| 1621 | } |
| 1622 | } |
| 1623 | |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1624 | void TeardownAllOverlayForMountPoint(const std::string& mount_point) { |
| 1625 | if (!fs_mgr_in_recovery()) { |
| 1626 | LERROR << __FUNCTION__ << "(): must be called within recovery."; |
| 1627 | return; |
| 1628 | } |
| 1629 | |
| 1630 | // Empty string means teardown everything. |
| 1631 | const std::string teardown_dir = mount_point.empty() ? "" : fs_mgr_mount_point(mount_point); |
| 1632 | constexpr bool* ignore_change = nullptr; |
| 1633 | |
| 1634 | // Teardown legacy overlay mount points that's not backed by a scratch device. |
Yi-Yo Chiang | d1ff1bc | 2021-02-11 22:59:11 +0800 | [diff] [blame] | 1635 | for (const auto& overlay_mount_point : OverlayMountPoints()) { |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1636 | if (overlay_mount_point == kScratchMountPoint) { |
| 1637 | continue; |
| 1638 | } |
| 1639 | fs_mgr_overlayfs_teardown_one(overlay_mount_point, teardown_dir, ignore_change); |
| 1640 | } |
| 1641 | |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1642 | if (mount_point.empty()) { |
| 1643 | // Throw away the entire partition. |
| 1644 | auto partition_name = android::base::Basename(kScratchMountPoint); |
| 1645 | auto images = IImageManager::Open("remount", 10s); |
| 1646 | if (images && images->BackingImageExists(partition_name)) { |
| 1647 | if (images->DisableImage(partition_name)) { |
| 1648 | LOG(INFO) << "Disabled scratch partition for: " << kScratchMountPoint; |
| 1649 | } else { |
| 1650 | LOG(ERROR) << "Unable to disable scratch partition for " << kScratchMountPoint; |
| 1651 | } |
| 1652 | } |
| 1653 | } |
| 1654 | |
| 1655 | if (auto info = EnsureScratchMapped(); info.has_value()) { |
| 1656 | // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint. |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1657 | fs_mgr_overlayfs_umount_scratch(); |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1658 | if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) { |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1659 | bool should_destroy_scratch = false; |
| 1660 | fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change, |
| 1661 | &should_destroy_scratch); |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1662 | fs_mgr_overlayfs_umount_scratch(); |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1663 | if (should_destroy_scratch) { |
| 1664 | fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr); |
| 1665 | } |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1666 | } |
| 1667 | } |
| 1668 | |
| 1669 | // Teardown DSU overlay if present. |
David Anderson | 982c341 | 2022-02-08 22:06:44 -0800 | [diff] [blame] | 1670 | std::string scratch_device; |
Yo Chiang | 66d0d96 | 2020-10-27 19:07:37 +0800 | [diff] [blame] | 1671 | if (MapDsuScratchDevice(&scratch_device)) { |
| 1672 | fs_mgr_overlayfs_umount_scratch(); |
| 1673 | if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) { |
| 1674 | fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change); |
| 1675 | fs_mgr_overlayfs_umount_scratch(); |
| 1676 | } |
| 1677 | DestroyLogicalPartition(android::gsi::kDsuScratch); |
| 1678 | } |
| 1679 | } |
| 1680 | |
David Anderson | c13586f | 2019-12-17 21:06:15 -0800 | [diff] [blame] | 1681 | } // namespace fs_mgr |
| 1682 | } // namespace android |
| 1683 | |
Mark Salyzyn | b28389f | 2018-06-06 13:10:40 -0700 | [diff] [blame] | 1684 | #endif // ALLOW_ADBD_DISABLE_VERITY != 0 |
Mark Salyzyn | 3ff87d8 | 2018-07-02 10:45:25 -0700 | [diff] [blame] | 1685 | |
| 1686 | bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) { |
| 1687 | struct statfs fs; |
| 1688 | if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) || |
| 1689 | (fs.f_type != EXT4_SUPER_MAGIC)) { |
| 1690 | return false; |
| 1691 | } |
| 1692 | |
| 1693 | android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC)); |
| 1694 | if (fd < 0) return false; |
| 1695 | |
| 1696 | struct ext4_super_block sb; |
| 1697 | if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) || |
| 1698 | (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) { |
| 1699 | return false; |
| 1700 | } |
| 1701 | |
| 1702 | struct fs_info info; |
| 1703 | if (ext4_parse_sb(&sb, &info) < 0) return false; |
| 1704 | |
| 1705 | return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0; |
| 1706 | } |
Justin Yun | 6bab0a9 | 2018-10-29 18:31:48 +0900 | [diff] [blame] | 1707 | |
| 1708 | std::string fs_mgr_get_context(const std::string& mount_point) { |
| 1709 | char* ctx = nullptr; |
| 1710 | if (getfilecon(mount_point.c_str(), &ctx) == -1) { |
| 1711 | return ""; |
| 1712 | } |
| 1713 | |
| 1714 | std::string context(ctx); |
| 1715 | free(ctx); |
| 1716 | return context; |
| 1717 | } |
| 1718 | |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 1719 | OverlayfsValidResult fs_mgr_overlayfs_valid() { |
Justin Yun | 6bab0a9 | 2018-10-29 18:31:48 +0900 | [diff] [blame] | 1720 | // Overlayfs available in the kernel, and patched for override_creds? |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 1721 | if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) { |
| 1722 | return OverlayfsValidResult::kOverrideCredsRequired; |
| 1723 | } |
Mark Salyzyn | 6d109ec | 2019-01-30 10:19:15 -0800 | [diff] [blame] | 1724 | if (!fs_mgr_overlayfs_filesystem_available("overlay")) { |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 1725 | return OverlayfsValidResult::kNotSupported; |
| 1726 | } |
| 1727 | struct utsname uts; |
| 1728 | if (uname(&uts) == -1) { |
| 1729 | return OverlayfsValidResult::kNotSupported; |
| 1730 | } |
| 1731 | int major, minor; |
| 1732 | if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { |
| 1733 | return OverlayfsValidResult::kNotSupported; |
| 1734 | } |
| 1735 | if (major < 4) { |
| 1736 | return OverlayfsValidResult::kOk; |
| 1737 | } |
| 1738 | if (major > 4) { |
| 1739 | return OverlayfsValidResult::kNotSupported; |
| 1740 | } |
Mark Salyzyn | a9451a5 | 2019-02-26 08:39:40 -0800 | [diff] [blame] | 1741 | if (minor > 3) { |
Mark Salyzyn | 6a11694 | 2018-11-05 08:53:30 -0800 | [diff] [blame] | 1742 | return OverlayfsValidResult::kNotSupported; |
| 1743 | } |
| 1744 | return OverlayfsValidResult::kOk; |
Justin Yun | 6bab0a9 | 2018-10-29 18:31:48 +0900 | [diff] [blame] | 1745 | } |