Merge "fs_mgr: Create a C++ Fstab struct"
diff --git a/adb/NOTICE b/adb/NOTICE
index ff47c95..9ffcc08 100644
--- a/adb/NOTICE
+++ b/adb/NOTICE
@@ -189,63 +189,3 @@
END OF TERMS AND CONDITIONS
-------------------------------------------------------------
-libwinpthread license:
-------------------------------------------------------------
-Copyright (c) 2011 mingw-w64 project
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-
-/*
- * Parts of this library are derived by:
- *
- * Posix Threads library for Microsoft Windows
- *
- * Use at own risk, there is no implied warranty to this code.
- * It uses undocumented features of Microsoft Windows that can change
- * at any time in the future.
- *
- * (C) 2010 Lockless Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * * Neither the name of Lockless Inc. nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 4e3879b..4e6c879 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -16,6 +16,7 @@
#pragma once
+#include <dirent.h>
#include <fcntl.h>
#if !defined(_WIN32)
@@ -231,3 +232,13 @@
template <typename T>
int close(const android::base::unique_fd_impl<T>&)
__attribute__((__unavailable__("close called on unique_fd")));
+
+template <typename T>
+FILE* fdopen(const android::base::unique_fd_impl<T>&, const char* mode)
+ __attribute__((__unavailable__("fdopen takes ownership of the fd passed in; either dup the "
+ "unique_fd, or use android::base::Fdopen to pass ownership")));
+
+template <typename T>
+DIR* fdopendir(const android::base::unique_fd_impl<T>&) __attribute__((
+ __unavailable__("fdopendir takes ownership of the fd passed in; either dup the "
+ "unique_fd, or use android::base::Fdopendir to pass ownership")));
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 7b99884..fbba631 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -153,6 +153,7 @@
if (!FlashPartitionTable(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to flash new partition table");
}
+ fs_mgr_overlayfs_teardown();
return device->WriteOkay("Successfully flashed partition table");
}
@@ -186,5 +187,6 @@
if (!UpdateAllPartitionMetadata(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to write new partition table");
}
+ fs_mgr_overlayfs_teardown();
return device->WriteOkay("Successfully updated partition table");
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 820ff31..6f863ad 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -82,6 +82,7 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+using android::base::Realpath;
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
using android::fs_mgr::AvbHandle;
@@ -100,7 +101,7 @@
FS_STAT_FULL_MOUNT_FAILED = 0x0100,
FS_STAT_E2FSCK_FAILED = 0x0200,
FS_STAT_E2FSCK_FS_FIXED = 0x0400,
- FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
+ FS_STAT_INVALID_MAGIC = 0x0800,
FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
@@ -143,6 +144,18 @@
return fs_type == "ext4" || fs_type == "ext3" || fs_type == "ext2";
}
+static bool is_f2fs(const std::string& fs_type) {
+ return fs_type == "f2fs";
+}
+
+static std::string realpath(const char* blk_device) {
+ std::string real_path;
+ if (!Realpath(blk_device, &real_path)) {
+ real_path = blk_device;
+ }
+ return real_path;
+}
+
static bool should_force_check(int fs_stat) {
return fs_stat &
(FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
@@ -160,11 +173,12 @@
const char* e2fsck_argv[] = {E2FSCK_BIN, "-y", blk_device};
const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};
+ if (*fs_stat & FS_STAT_INVALID_MAGIC) { // will fail, so do not try
+ return;
+ }
+
/* Check for the types of filesystems we know how to check */
if (is_extfs(fs_type)) {
- if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) { // will fail, so do not try
- return;
- }
/*
* First try to mount and unmount the filesystem. We do this because
* the kernel is more efficient than e2fsck in running the journal and
@@ -214,10 +228,10 @@
* (e.g. recent SDK system images). Detect these and skip the check.
*/
if (access(E2FSCK_BIN, X_OK)) {
- LINFO << "Not running " << E2FSCK_BIN << " on " << blk_device
+ LINFO << "Not running " << E2FSCK_BIN << " on " << realpath(blk_device)
<< " (executable not in system image)";
} else {
- LINFO << "Running " << E2FSCK_BIN << " on " << blk_device;
+ LINFO << "Running " << E2FSCK_BIN << " on " << realpath(blk_device);
if (should_force_check(*fs_stat)) {
ret = android_fork_execvp_ext(
ARRAY_SIZE(e2fsck_forced_argv), const_cast<char**>(e2fsck_forced_argv), &status,
@@ -237,13 +251,9 @@
*fs_stat |= FS_STAT_E2FSCK_FS_FIXED;
}
}
- } else if (!strcmp(fs_type, "f2fs")) {
- const char *f2fs_fsck_argv[] = {
- F2FS_FSCK_BIN,
- "-a",
- blk_device
- };
- LINFO << "Running " << F2FS_FSCK_BIN << " -a " << blk_device;
+ } else if (is_f2fs(fs_type)) {
+ const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", blk_device};
+ LINFO << "Running " << F2FS_FSCK_BIN << " -a " << realpath(blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv),
const_cast<char **>(f2fs_fsck_argv),
@@ -277,7 +287,7 @@
}
// Read the primary superblock from an ext4 filesystem. On failure return
-// false. If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
+// false. If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC.
static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
@@ -294,7 +304,7 @@
if (!is_ext4_superblock_valid(sb)) {
LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
// not a valid fs, tune2fs, fsck, and mount will all fail.
- *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
+ *fs_stat |= FS_STAT_INVALID_MAGIC;
return false;
}
*fs_stat |= FS_STAT_IS_EXT4;
@@ -422,6 +432,36 @@
}
}
+// Read the primary superblock from an f2fs filesystem. On failure return
+// false. If it's not an f2fs filesystem, also set FS_STAT_INVALID_MAGIC.
+#define F2FS_BLKSIZE 4096
+#define F2FS_SUPER_OFFSET 1024
+static bool read_f2fs_superblock(const char* blk_device, int* fs_stat) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
+ __le32 sb1, sb2;
+
+ if (fd < 0) {
+ PERROR << "Failed to open '" << blk_device << "'";
+ return false;
+ }
+
+ if (pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET) != sizeof(sb1)) {
+ PERROR << "Can't read '" << blk_device << "' superblock1";
+ return false;
+ }
+ if (pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET) != sizeof(sb2)) {
+ PERROR << "Can't read '" << blk_device << "' superblock2";
+ return false;
+ }
+
+ if (sb1 != cpu_to_le32(F2FS_SUPER_MAGIC) && sb2 != cpu_to_le32(F2FS_SUPER_MAGIC)) {
+ LINFO << "Invalid f2fs superblock on '" << blk_device << "'";
+ *fs_stat |= FS_STAT_INVALID_MAGIC;
+ return false;
+ }
+ return true;
+}
+
//
// Prepare the filesystem on the given block device to be mounted.
//
@@ -451,6 +491,10 @@
} else {
return fs_stat;
}
+ } else if (is_f2fs(rec->fs_type)) {
+ if (!read_f2fs_superblock(blk_device, &fs_stat)) {
+ return fs_stat;
+ }
}
if ((rec->fs_mgr_flags & MF_CHECK) ||
@@ -617,9 +661,10 @@
}
int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]);
- if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {
- LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint="
- << fstab->recs[i].mount_point << " rec[" << i
+ if (fs_stat & FS_STAT_INVALID_MAGIC) {
+ LERROR << __FUNCTION__ << "(): skipping mount due to invalid magic, mountpoint="
+ << fstab->recs[i].mount_point
+ << " blk_dev=" << realpath(fstab->recs[i].blk_device) << " rec[" << i
<< "].fs_type=" << fstab->recs[i].fs_type;
mount_errno = EINVAL; // continue bootup for FDE
continue;
@@ -911,7 +956,7 @@
private:
bool UpdateCheckpointPartition(struct fstab_rec* rec) {
if (fs_mgr_is_checkpoint_fs(rec)) {
- if (!strcmp(rec->fs_type, "f2fs")) {
+ if (is_f2fs(rec->fs_type)) {
std::string opts(rec->fs_options);
opts += ",checkpoint=disable";
@@ -1002,7 +1047,7 @@
/* Skip mounting the root partition, as it will already have been mounted */
if (!strcmp(fstab->recs[i].mount_point, "/") ||
!strcmp(fstab->recs[i].mount_point, "/system")) {
- if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) {
+ if ((fstab->recs[i].flags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
}
continue;
@@ -1104,10 +1149,9 @@
* at two different lines in the fstab. Use the top one for formatting
* as that is the preferred one.
*/
- LERROR << __FUNCTION__ << "(): " << fstab->recs[top_idx].blk_device
- << " is wiped and " << fstab->recs[top_idx].mount_point
- << " " << fstab->recs[top_idx].fs_type
- << " is formattable. Format it.";
+ LERROR << __FUNCTION__ << "(): " << realpath(fstab->recs[top_idx].blk_device)
+ << " is wiped and " << fstab->recs[top_idx].mount_point << " "
+ << fstab->recs[top_idx].fs_type << " is formattable. Format it.";
checkpoint_manager.Revert(&fstab->recs[top_idx]);
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index bef46e1..20652ad 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -395,6 +395,18 @@
return false;
}
+void fs_mgr_overlayfs_umount_scratch() {
+ // Lazy umount will allow us to move on and possibly later
+ // establish a new fresh mount without requiring a reboot should
+ // the developer wish to restart. Old references should melt
+ // away or have no data. Main goal is to shut the door on the
+ // current overrides with an expectation of a subsequent reboot,
+ // thus any errors here are ignored.
+ umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+ LINFO << "umount(" << kScratchMountPoint << ")";
+ rmdir(kScratchMountPoint.c_str());
+}
+
// reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise
std::string scratch_device_cache;
@@ -408,13 +420,7 @@
auto save_errno = errno;
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
- // Lazy umount will allow us to move on and possibly later
- // establish a new fresh mount without requiring a reboot should
- // the developer wish to restart. Old references should melt
- // away or have no data. Main goal is to shut the door on the
- // current overrides with an expectation of a subsequent reboot,
- // thus any errors here are ignored.
- umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+ fs_mgr_overlayfs_umount_scratch();
}
auto builder = MetadataBuilder::New(super_device, slot_number);
if (!builder) {
@@ -753,14 +759,20 @@
return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
}
+bool fs_mgr_overlayfs_invalid(const fstab* fstab) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true;
+
+ // in recovery or fastbootd mode, not allowed!
+ if (fs_mgr_access("/system/bin/recovery")) return true;
+
+ return !fstab;
+}
+
} // namespace
bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
auto ret = false;
-
- if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
-
- if (!fstab) return ret;
+ if (fs_mgr_overlayfs_invalid(fstab)) return ret;
auto scratch_can_be_mounted = true;
for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
@@ -773,8 +785,7 @@
fs_mgr_overlayfs_mount_scratch(scratch_device,
fs_mgr_overlayfs_scratch_mount_type()) &&
!fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
- umount2(kScratchMountPoint.c_str(), MNT_DETACH);
- rmdir(kScratchMountPoint.c_str());
+ fs_mgr_overlayfs_umount_scratch();
}
}
if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
@@ -790,9 +801,9 @@
}
std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
- if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return {};
+ if (fs_mgr_overlayfs_invalid(fstab)) return {};
- if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
+ if (fs_mgr_get_entry_for_mount_point(fstab, kScratchMountPoint)) {
return {};
}
@@ -867,6 +878,7 @@
auto ret = true;
// If scratch exists, but is not mounted, lets gain access to clean
// specific override entries.
+ auto mount_scratch = false;
if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
auto scratch_device = fs_mgr_overlayfs_scratch_device();
if (scratch_device.empty()) {
@@ -876,7 +888,8 @@
CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
&scratch_device);
}
- fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type());
+ mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
+ fs_mgr_overlayfs_scratch_mount_type());
}
for (const auto& overlay_mount_point : kOverlayMountPoints) {
ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
@@ -894,6 +907,8 @@
PERROR << "teardown";
ret = false;
}
+ if (mount_scratch) fs_mgr_overlayfs_umount_scratch();
+
return ret;
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 8644dae..d35329e 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -413,7 +413,14 @@
// heads up for instantiating required device(s) for overlayfs logic
const auto devices = fs_mgr_overlayfs_required_devices(device_tree_fstab_.get());
for (auto const& device : devices) {
- InitMappedDevice(device);
+ if (android::base::StartsWith(device, "/dev/block/by-name/")) {
+ required_devices_partition_names_.emplace(basename(device.c_str()));
+ auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
+ uevent_listener_.RegenerateUevents(uevent_callback);
+ uevent_listener_.Poll(uevent_callback, 10s);
+ } else {
+ InitMappedDevice(device);
+ }
}
fs_mgr_overlayfs_mount_all(device_tree_fstab_.get());
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 8cf2128..d6765b7 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -87,8 +87,8 @@
}
UeventListener::UeventListener() {
- // is 2MB enough? udev uses 128MB!
- device_fd_.reset(uevent_open_socket(2 * 1024 * 1024, true));
+ // is 16MB enough? udev uses 128MB!
+ device_fd_.reset(uevent_open_socket(16 * 1024 * 1024, true));
if (device_fd_ == -1) {
LOG(FATAL) << "Could not open uevent socket";
}
diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp
index 2dfceed..721de7c 100644
--- a/libcutils/uevent.cpp
+++ b/libcutils/uevent.cpp
@@ -95,6 +95,8 @@
int uevent_open_socket(int buf_sz, bool passcred) {
struct sockaddr_nl addr;
int on = passcred;
+ int buf_sz_readback = 0;
+ socklen_t optlen = sizeof(buf_sz_readback);
int s;
memset(&addr, 0, sizeof(addr));
@@ -105,11 +107,21 @@
s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if (s < 0) return -1;
- /* buf_sz should be less than net.core.rmem_max for this to succeed */
- if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) {
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0 ||
+ getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz_readback, &optlen) < 0) {
close(s);
return -1;
}
+ /* Only if SO_RCVBUF was not effective, try SO_RCVBUFFORCE. Generally, we
+ * want to avoid SO_RCVBUFFORCE, because it generates SELinux denials in
+ * case we don't have CAP_NET_ADMIN. This is the case, for example, for
+ * healthd. */
+ if (buf_sz_readback < 2 * buf_sz) {
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz)) < 0) {
+ close(s);
+ return -1;
+ }
+ }
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));