diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto index d04c9c19d..2e948dda7 100644 --- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto +++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto @@ -124,8 +124,7 @@ message SnapshotStatus { // Default value is 32, can be set lower for low mem devices uint32 read_ahead_size = 17; - // Enable direct reads on source device - bool o_direct = 18; + reserved 18; // Blocks size to be verified at once uint64 verify_block_size = 19; @@ -227,6 +226,9 @@ message SnapshotUpdateStatus { // legacy dm-snapshot based snapuserd bool legacy_snapuserd = 11; + + // Enable direct reads from source device + bool o_direct = 12; } // Next: 10 diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 3ccc3dbf4..6d422c614 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -410,6 +410,7 @@ class SnapshotManager final : public ISnapshotManager { FRIEND_TEST(SnapshotTest, CreateSnapshot); FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback); FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge); + FRIEND_TEST(SnapshotTest, FlagCheck); FRIEND_TEST(SnapshotTest, FlashSuperDuringMerge); FRIEND_TEST(SnapshotTest, FlashSuperDuringUpdate); FRIEND_TEST(SnapshotTest, MapPartialSnapshot); @@ -425,6 +426,7 @@ class SnapshotManager final : public ISnapshotManager { FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback); FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery); FRIEND_TEST(SnapshotUpdateTest, DataWipeWithStaleSnapshots); + FRIEND_TEST(SnapshotUpdateTest, FlagCheck); FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow); FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow); FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery); @@ -822,6 +824,9 @@ class SnapshotManager final : public ISnapshotManager { // Check if io_uring API's need to be used bool UpdateUsesIouring(LockedFile* lock); + // Check if direct reads are enabled for the source image + bool UpdateUsesODirect(LockedFile* lock); + // Wrapper around libdm, with diagnostics. bool DeleteDeviceIfExists(const std::string& name, const std::chrono::milliseconds& timeout_ms = {}); diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h index a75d993c7..1adbba2c8 100644 --- a/fs_mgr/libsnapshot/partition_cow_creator.h +++ b/fs_mgr/libsnapshot/partition_cow_creator.h @@ -62,6 +62,9 @@ struct PartitionCowCreator { uint64_t compression_factor; uint32_t read_ahead_size; + // Enable direct reads on source device + bool o_direct; + // True if multi-threaded compression should be enabled bool enable_threading; diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 8620620e4..c01360e0b 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -1697,6 +1697,9 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition, if (UpdateUsesIouring(lock.get())) { snapuserd_argv->emplace_back("-io_uring"); } + if (UpdateUsesODirect(lock.get())) { + snapuserd_argv->emplace_back("-o_direct"); + } } size_t num_cows = 0; @@ -2114,6 +2117,11 @@ bool SnapshotManager::UpdateUsesIouring(LockedFile* lock) { return update_status.io_uring_enabled(); } +bool SnapshotManager::UpdateUsesODirect(LockedFile* lock) { + SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock); + return update_status.o_direct(); +} + /* * Please see b/304829384 for more details. * @@ -3016,6 +3024,7 @@ bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state, status.set_userspace_snapshots(old_status.userspace_snapshots()); status.set_io_uring_enabled(old_status.io_uring_enabled()); status.set_legacy_snapuserd(old_status.legacy_snapuserd()); + status.set_o_direct(old_status.o_direct()); } return WriteSnapshotUpdateStatus(lock, status); } @@ -3310,17 +3319,19 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife } auto read_ahead_size = android::base::GetUintProperty("ro.virtual_ab.read_ahead_size", kReadAheadSizeKb); - PartitionCowCreator cow_creator{.target_metadata = target_metadata.get(), - .target_suffix = target_suffix, - .target_partition = nullptr, - .current_metadata = current_metadata.get(), - .current_suffix = current_suffix, - .update = nullptr, - .extra_extents = {}, - .using_snapuserd = using_snapuserd, - .compression_algorithm = compression_algorithm, - .compression_factor = compression_factor, - .read_ahead_size = read_ahead_size}; + PartitionCowCreator cow_creator{ + .target_metadata = target_metadata.get(), + .target_suffix = target_suffix, + .target_partition = nullptr, + .current_metadata = current_metadata.get(), + .current_suffix = current_suffix, + .update = nullptr, + .extra_extents = {}, + .using_snapuserd = using_snapuserd, + .compression_algorithm = compression_algorithm, + .compression_factor = compression_factor, + .read_ahead_size = read_ahead_size, + }; if (dap_metadata.vabc_feature_set().has_threaded()) { cow_creator.enable_threading = dap_metadata.vabc_feature_set().threaded(); @@ -3388,10 +3399,13 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife status.set_io_uring_enabled(true); LOG(INFO) << "io_uring for snapshots enabled"; } - + if (GetODirectEnabledProperty()) { + status.set_o_direct(true); + LOG(INFO) << "o_direct for source image enabled"; + } if (is_legacy_snapuserd) { - LOG(INFO) << "Setting legacy_snapuserd to true"; status.set_legacy_snapuserd(true); + LOG(INFO) << "Setting legacy_snapuserd to true"; } } else if (legacy_compression) { LOG(INFO) << "Virtual A/B using legacy snapuserd"; @@ -3827,6 +3841,7 @@ bool SnapshotManager::Dump(std::ostream& os) { ss << "Using snapuserd: " << update_status.using_snapuserd() << std::endl; ss << "Using userspace snapshots: " << update_status.userspace_snapshots() << std::endl; ss << "Using io_uring: " << update_status.io_uring_enabled() << std::endl; + ss << "Using o_direct: " << update_status.o_direct() << std::endl; ss << "Using XOR compression: " << GetXorCompressionEnabledProperty() << std::endl; ss << "Current slot: " << device_->GetSlotSuffix() << std::endl; ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl; diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 80dad17cc..3299ec5c9 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2647,6 +2647,41 @@ TEST_F(SnapshotUpdateTest, BadCowVersion) { ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); } +TEST_F(SnapshotTest, FlagCheck) { + if (!snapuserd_required_) { + GTEST_SKIP() << "Skipping snapuserd test"; + } + ASSERT_TRUE(AcquireLock()); + + SnapshotUpdateStatus status = sm->ReadSnapshotUpdateStatus(lock_.get()); + + // Set flags in proto + status.set_o_direct(true); + status.set_io_uring_enabled(true); + status.set_userspace_snapshots(true); + + sm->WriteSnapshotUpdateStatus(lock_.get(), status); + // Ensure a connection to the second-stage daemon, but use the first-stage + // code paths thereafter. + ASSERT_TRUE(sm->EnsureSnapuserdConnected()); + sm->set_use_first_stage_snapuserd(true); + + auto init = NewManagerForFirstStageMount("_b"); + ASSERT_NE(init, nullptr); + + lock_ = nullptr; + + std::vector snapuserd_argv; + ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SELINUX_DETACH, + &snapuserd_argv)); + ASSERT_TRUE(std::find(snapuserd_argv.begin(), snapuserd_argv.end(), "-o_direct") != + snapuserd_argv.end()); + ASSERT_TRUE(std::find(snapuserd_argv.begin(), snapuserd_argv.end(), "-io_uring") != + snapuserd_argv.end()); + ASSERT_TRUE(std::find(snapuserd_argv.begin(), snapuserd_argv.end(), "-user_snapshot") != + snapuserd_argv.end()); +} + class FlashAfterUpdateTest : public SnapshotUpdateTest, public WithParamInterface> { public: diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index 0ebe543df..67e9e52ea 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -29,6 +29,7 @@ DEFINE_bool(socket_handoff, false, "If true, perform a socket hand-off with an existing snapuserd instance, then exit."); DEFINE_bool(user_snapshot, false, "If true, user-space snapshots are used"); DEFINE_bool(io_uring, false, "If true, io_uring feature is enabled"); +DEFINE_bool(o_direct, false, "If true, enable direct reads on source device"); namespace android { namespace snapshot { @@ -67,7 +68,6 @@ bool Daemon::StartDaemon(int argc, char** argv) { if (!user_snapshots) { user_snapshots = IsUserspaceSnapshotsEnabled(); } - if (user_snapshots) { LOG(INFO) << "Starting daemon for user-space snapshots....."; return StartServerForUserspaceSnapshots(arg_start, argc, argv); @@ -109,11 +109,13 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar for (int i = arg_start; i < argc; i++) { auto parts = android::base::Split(argv[i], ","); + if (parts.size() != 4) { - LOG(ERROR) << "Malformed message, expected four sub-arguments."; + LOG(ERROR) << "Malformed message, expected at least four sub-arguments."; return false; } - auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3]); + auto handler = + user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3], FLAGS_o_direct); if (!handler || !user_server_.StartHandler(parts[0])) { return false; } diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp index fe2d95c64..7eaaca95b 100644 --- a/fs_mgr/libsnapshot/utility.cpp +++ b/fs_mgr/libsnapshot/utility.cpp @@ -199,7 +199,7 @@ bool WriteStringToFileAtomic(const std::string& content, const std::string& path } std::ostream& operator<<(std::ostream& os, const Now&) { - struct tm now {}; + struct tm now{}; time_t t = time(nullptr); localtime_r(&t, &now); return os << std::put_time(&now, "%Y%m%d-%H%M%S"); @@ -272,6 +272,11 @@ bool GetXorCompressionEnabledProperty() { return fetcher->GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false); } +bool GetODirectEnabledProperty() { + auto fetcher = IPropertyFetcher::GetInstance(); + return fetcher->GetBoolProperty("ro.virtual_ab.o_direct.enabled", false); +} + std::string GetOtherPartitionName(const std::string& name) { auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name); CHECK(suffix == "_a" || suffix == "_b"); diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h index f956a0544..7dae942b3 100644 --- a/fs_mgr/libsnapshot/utility.h +++ b/fs_mgr/libsnapshot/utility.h @@ -133,6 +133,7 @@ bool GetLegacyCompressionEnabledProperty(); bool GetUserspaceSnapshotsEnabledProperty(); bool GetIouringEnabledProperty(); bool GetXorCompressionEnabledProperty(); +bool GetODirectEnabledProperty(); bool CanUseUserspaceSnapshots(); bool IsDmSnapshotTestingEnabled();