Skip to content

Commit 231cfc4

Browse files
dvandercorpGerrit Code Review
authored and
Gerrit Code Review
committed
Merge "libsnapshot: Add a helper for waiting for device paths."
2 parents 84cfcc2 + 189e8e3 commit 231cfc4

File tree

2 files changed

+70
-11
lines changed

2 files changed

+70
-11
lines changed

fs_mgr/libsnapshot/include/libsnapshot/snapshot.h

+15
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,14 @@ class SnapshotManager final : public ISnapshotManager {
345345
bool MapAllSnapshots(const std::chrono::milliseconds& timeout_ms = {}) override;
346346
bool UnmapAllSnapshots() override;
347347

348+
// We can't use WaitForFile during first-stage init, because ueventd is not
349+
// running and therefore will not automatically create symlinks. Instead,
350+
// we let init provide us with the correct function to use to ensure
351+
// uevents have been processed and symlink/mknod calls completed.
352+
void SetUeventRegenCallback(std::function<bool(const std::string&)> callback) {
353+
uevent_regen_callback_ = callback;
354+
}
355+
348356
private:
349357
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
350358
FRIEND_TEST(SnapshotTest, CreateSnapshot);
@@ -676,13 +684,20 @@ class SnapshotManager final : public ISnapshotManager {
676684
// Same as above, but for paths only (no major:minor device strings).
677685
bool GetMappedImageDevicePath(const std::string& device_name, std::string* device_path);
678686

687+
// Wait for a device to be created by ueventd (eg, its symlink or node to be populated).
688+
// This is needed for any code that uses device-mapper path in first-stage init. If
689+
// |timeout_ms| is empty or the given device is not a path, WaitForDevice immediately
690+
// returns true.
691+
bool WaitForDevice(const std::string& device, std::chrono::milliseconds timeout_ms);
692+
679693
std::string gsid_dir_;
680694
std::string metadata_dir_;
681695
std::unique_ptr<IDeviceInfo> device_;
682696
std::unique_ptr<IImageManager> images_;
683697
bool has_local_image_manager_ = false;
684698
bool use_first_stage_snapuserd_ = false;
685699
bool in_factory_data_reset_ = false;
700+
std::function<bool(const std::string&)> uevent_regen_callback_;
686701
std::unique_ptr<SnapuserdClient> snapuserd_client_;
687702
};
688703

fs_mgr/libsnapshot/snapshot.cpp

+55-11
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,12 @@ bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name,
409409
if (!dm.CreateDevice(name, table, path, timeout_ms)) {
410410
return false;
411411
}
412+
if (!WaitForDevice(*path, timeout_ms)) {
413+
return false;
414+
}
412415

413416
auto control_device = "/dev/dm-user/" + misc_name;
414-
if (!android::fs_mgr::WaitForFile(control_device, timeout_ms)) {
415-
LOG(ERROR) << "Timed out waiting for dm-user misc device: " << control_device;
417+
if (!WaitForDevice(control_device, timeout_ms)) {
416418
return false;
417419
}
418420

@@ -1340,10 +1342,12 @@ bool SnapshotManager::PerformSecondStageTransition() {
13401342
continue;
13411343
}
13421344

1345+
auto misc_name = user_cow_name;
1346+
13431347
DmTable table;
1344-
table.Emplace<DmTargetUser>(0, target.spec.length, user_cow_name);
1348+
table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
13451349
if (!dm.LoadTableAndActivate(user_cow_name, table)) {
1346-
LOG(ERROR) << "Unable to swap tables for " << user_cow_name;
1350+
LOG(ERROR) << "Unable to swap tables for " << misc_name;
13471351
continue;
13481352
}
13491353

@@ -1369,14 +1373,13 @@ bool SnapshotManager::PerformSecondStageTransition() {
13691373
}
13701374

13711375
// Wait for ueventd to acknowledge and create the control device node.
1372-
std::string control_device = "/dev/dm-user/" + user_cow_name;
1373-
if (!android::fs_mgr::WaitForFile(control_device, 10s)) {
1374-
LOG(ERROR) << "Could not find control device: " << control_device;
1376+
std::string control_device = "/dev/dm-user/" + misc_name;
1377+
if (!WaitForDevice(control_device, 10s)) {
13751378
continue;
13761379
}
13771380

13781381
uint64_t base_sectors =
1379-
snapuserd_client_->InitDmUserCow(user_cow_name, cow_image_device, backing_device);
1382+
snapuserd_client_->InitDmUserCow(misc_name, cow_image_device, backing_device);
13801383
if (base_sectors == 0) {
13811384
// Unrecoverable as metadata reads from cow device failed
13821385
LOG(FATAL) << "Failed to retrieve base_sectors from Snapuserd";
@@ -1385,7 +1388,7 @@ bool SnapshotManager::PerformSecondStageTransition() {
13851388

13861389
CHECK(base_sectors == target.spec.length);
13871390

1388-
if (!snapuserd_client_->AttachDmUser(user_cow_name)) {
1391+
if (!snapuserd_client_->AttachDmUser(misc_name)) {
13891392
// This error is unrecoverable. We cannot proceed because reads to
13901393
// the underlying device will fail.
13911394
LOG(FATAL) << "Could not initialize snapuserd for " << user_cow_name;
@@ -1924,13 +1927,20 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
19241927
if (live_snapshot_status->compression_enabled()) {
19251928
auto name = GetDmUserCowName(params.GetPartitionName());
19261929

1927-
// :TODO: need to force init to process uevents for these in first-stage.
19281930
std::string cow_path;
19291931
if (!GetMappedImageDevicePath(cow_name, &cow_path)) {
19301932
LOG(ERROR) << "Could not determine path for: " << cow_name;
19311933
return false;
19321934
}
19331935

1936+
// Ensure both |base_path| and |cow_path| are created, for snapuserd.
1937+
if (!WaitForDevice(base_path, remaining_time)) {
1938+
return false;
1939+
}
1940+
if (!WaitForDevice(cow_path, remaining_time)) {
1941+
return false;
1942+
}
1943+
19341944
std::string new_cow_device;
19351945
if (!MapDmUserCow(lock, name, cow_path, base_path, remaining_time, &new_cow_device)) {
19361946
LOG(ERROR) << "Could not map dm-user device for partition "
@@ -2070,7 +2080,7 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name)
20702080
if (!EnsureSnapuserdConnected()) {
20712081
return false;
20722082
}
2073-
if (!dm.DeleteDevice(dm_user_name)) {
2083+
if (!dm.DeleteDeviceIfExists(dm_user_name)) {
20742084
LOG(ERROR) << "Cannot unmap " << dm_user_name;
20752085
return false;
20762086
}
@@ -3302,5 +3312,39 @@ bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device
33023312
return true;
33033313
}
33043314

3315+
bool SnapshotManager::WaitForDevice(const std::string& device,
3316+
std::chrono::milliseconds timeout_ms) {
3317+
if (!android::base::StartsWith(device, "/")) {
3318+
return true;
3319+
}
3320+
3321+
// In first-stage init, we rely on init setting a callback which can
3322+
// regenerate uevents and populate /dev for us.
3323+
if (uevent_regen_callback_) {
3324+
if (!uevent_regen_callback_(device)) {
3325+
LOG(ERROR) << "Failed to find device after regenerating uevents: " << device;
3326+
return false;
3327+
}
3328+
return true;
3329+
}
3330+
3331+
// Otherwise, the only kind of device we need to wait for is a dm-user
3332+
// misc device. Normal calls to DeviceMapper::CreateDevice() guarantee
3333+
// the path has been created.
3334+
if (!android::base::StartsWith(device, "/dev/dm-user/")) {
3335+
return true;
3336+
}
3337+
3338+
if (timeout_ms.count() == 0) {
3339+
LOG(ERROR) << "No timeout was specified to wait for device: " << device;
3340+
return false;
3341+
}
3342+
if (!android::fs_mgr::WaitForFile(device, timeout_ms)) {
3343+
LOG(ERROR) << "Timed out waiting for device to appear: " << device;
3344+
return false;
3345+
}
3346+
return true;
3347+
}
3348+
33053349
} // namespace snapshot
33063350
} // namespace android

0 commit comments

Comments
 (0)