fastbootd: Wait for /dev/block paths when opening logical partitions.

Note that in addition to waiting for the path to appear, we must also
wait for it to be unlinked. Otherwise, we could accidentally access an
older device when opening and closing the same partition twice in a row.

Bug: 114198005
Test: fastboot flashall works
Change-Id: Iddffc34e1ac8aa066c28e7b1a92b09b6dfd7945c
This commit is contained in:
David Anderson 2018-09-06 17:25:03 -07:00
parent 0a8f61530b
commit c8ac4e7644
5 changed files with 44 additions and 15 deletions

View File

@ -28,6 +28,7 @@
#include "fastboot_device.h"
using namespace android::fs_mgr;
using namespace std::chrono_literals;
using android::base::unique_fd;
using android::hardware::boot::V1_0::Slot;
@ -48,11 +49,11 @@ static bool OpenLogicalPartition(const std::string& name, const std::string& slo
}
uint32_t slot_number = SlotNumberForSlotSuffix(slot);
std::string dm_path;
if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, &dm_path)) {
if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, 5s, &dm_path)) {
LOG(ERROR) << "Could not map partition: " << name;
return false;
}
auto closer = [name]() -> void { DestroyLogicalPartition(name); };
auto closer = [name]() -> void { DestroyLogicalPartition(name, 5s); };
*handle = PartitionHandle(dm_path, std::move(closer));
return true;
}

View File

@ -102,12 +102,16 @@ enum FsStatFlags {
// TODO: switch to inotify()
bool fs_mgr_wait_for_file(const std::string& filename,
const std::chrono::milliseconds relative_timeout) {
const std::chrono::milliseconds relative_timeout,
FileWaitMode file_wait_mode) {
auto start_time = std::chrono::steady_clock::now();
while (true) {
if (!access(filename.c_str(), F_OK) || errno != ENOENT) {
return true;
int rv = access(filename.c_str(), F_OK);
if (file_wait_mode == FileWaitMode::Exists) {
if (!rv || errno != ENOENT) return true;
} else if (file_wait_mode == FileWaitMode::DoesNotExist) {
if (rv && errno == ENOENT) return true;
}
std::this_thread::sleep_for(50ms);

View File

@ -81,7 +81,7 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met
static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
const LpMetadataPartition& partition, bool force_writable,
std::string* path) {
const std::chrono::milliseconds& timeout_ms, std::string* path) {
DeviceMapper& dm = DeviceMapper::Instance();
DmTable table;
@ -98,6 +98,13 @@ static bool CreateLogicalPartition(const std::string& block_device, const LpMeta
if (!dm.GetDmDevicePathByName(name, path)) {
return false;
}
if (timeout_ms > std::chrono::milliseconds::zero()) {
if (!fs_mgr_wait_for_file(*path, timeout_ms, FileWaitMode::Exists)) {
DestroyLogicalPartition(name, {});
LERROR << "Timed out waiting for device path: " << *path;
return false;
}
}
LINFO << "Created logical partition " << name << " on device " << *path;
return true;
}
@ -115,7 +122,7 @@ bool CreateLogicalPartitions(const std::string& block_device) {
continue;
}
std::string path;
if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, &path)) {
if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, {}, &path)) {
LERROR << "Could not create logical partition: " << GetPartitionName(partition);
return false;
}
@ -125,7 +132,7 @@ bool CreateLogicalPartitions(const std::string& block_device) {
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
const std::string& partition_name, bool force_writable,
std::string* path) {
const std::chrono::milliseconds& timeout_ms, std::string* path) {
auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
if (!metadata) {
LOG(ERROR) << "Could not read partition table.";
@ -134,18 +141,26 @@ bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_s
for (const auto& partition : metadata->partitions) {
if (GetPartitionName(partition) == partition_name) {
return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable,
path);
timeout_ms, path);
}
}
LERROR << "Could not find any partition with name: " << partition_name;
return false;
}
bool DestroyLogicalPartition(const std::string& name) {
bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
DeviceMapper& dm = DeviceMapper::Instance();
std::string path;
if (timeout_ms > std::chrono::milliseconds::zero()) {
dm.GetDmDevicePathByName(name, &path);
}
if (!dm.DeleteDevice(name)) {
return false;
}
if (!path.empty() && !fs_mgr_wait_for_file(path, timeout_ms, FileWaitMode::DoesNotExist)) {
LERROR << "Timed out waiting for device path to unlink: " << path;
return false;
}
LINFO << "Unmapped logical partition " << name;
return true;
}

View File

@ -119,9 +119,13 @@
using namespace std::chrono_literals;
int fs_mgr_set_blk_ro(const char *blockdev);
enum class FileWaitMode { Exists, DoesNotExist };
bool fs_mgr_wait_for_file(const std::string& filename,
const std::chrono::milliseconds relative_timeout);
const std::chrono::milliseconds relative_timeout,
FileWaitMode wait_mode = FileWaitMode::Exists);
int fs_mgr_set_blk_ro(const char* blockdev);
bool fs_mgr_update_for_slotselect(struct fstab *fstab);
bool fs_mgr_is_device_unlocked();
const std::string& get_android_dt_dir();

View File

@ -27,6 +27,7 @@
#include <stdint.h>
#include <chrono>
#include <memory>
#include <string>
#include <vector>
@ -43,12 +44,16 @@ bool CreateLogicalPartitions(const std::string& block_device);
// the partition name. On success, a path to the partition's block device is
// returned. If |force_writable| is true, the "readonly" flag will be ignored
// so the partition can be flashed.
//
// If |timeout_ms| is non-zero, then CreateLogicalPartition will block for the
// given amount of time until the path returned in |path| is available.
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
const std::string& partition_name, bool force_writable,
std::string* path);
const std::chrono::milliseconds& timeout_ms, std::string* path);
// Destroy the block device for a logical partition, by name.
bool DestroyLogicalPartition(const std::string& name);
// Destroy the block device for a logical partition, by name. If |timeout_ms|
// is non-zero, then this will block until the device path has been unlinked.
bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms);
} // namespace fs_mgr
} // namespace android