Merge "liblp: Add an abstraction layer for opening partitions."
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 4953655..5689bdf 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -25,6 +25,7 @@
srcs: [
"builder.cpp",
"images.cpp",
+ "partition_opener.cpp",
"reader.cpp",
"utility.cpp",
"writer.cpp",
@@ -59,6 +60,7 @@
srcs: [
"builder_test.cpp",
"io_test.cpp",
+ "test_partition_opener.cpp",
"utility_test.cpp",
],
}
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4dd60e9..1b8ed57 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -16,11 +16,7 @@
#include "liblp/builder.h"
-#if defined(__linux__)
-#include <linux/fs.h>
-#endif
#include <string.h>
-#include <sys/ioctl.h>
#include <algorithm>
@@ -33,43 +29,6 @@
namespace android {
namespace fs_mgr {
-bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
-#if defined(__linux__)
- android::base::unique_fd fd(open(block_device.c_str(), O_RDONLY));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
- return false;
- }
- if (!GetDescriptorSize(fd, &device_info->size)) {
- return false;
- }
- if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
- return false;
- }
-
- int alignment_offset;
- if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
- return false;
- }
- int logical_block_size;
- if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
- return false;
- }
-
- device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
- device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
- return true;
-#else
- (void)block_device;
- (void)device_info;
- LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
- return false;
-#endif
-}
-
void LinearExtent::AddTo(LpMetadata* out) const {
out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_});
}
@@ -138,9 +97,10 @@
return sectors * LP_SECTOR_SIZE;
}
-std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& opener,
+ const std::string& super_partition,
uint32_t slot_number) {
- std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
+ std::unique_ptr<LpMetadata> metadata = ReadMetadata(opener, super_partition, slot_number);
if (!metadata) {
return nullptr;
}
@@ -149,12 +109,17 @@
return nullptr;
}
BlockDeviceInfo device_info;
- if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
+ if (opener.GetInfo(super_partition, &device_info)) {
builder->UpdateBlockDeviceInfo(device_info);
}
return builder;
}
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
+ uint32_t slot_number) {
+ return New(PartitionOpener(), super_partition, slot_number);
+}
+
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info,
uint32_t metadata_max_size,
uint32_t metadata_slot_count) {
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index c3a5ffe..c02242a 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -424,13 +424,10 @@
fs_mgr_free_fstab);
ASSERT_NE(fstab, nullptr);
- // This should read from the "super" partition once we have a well-defined
- // way to access it.
- struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), "/data");
- ASSERT_NE(rec, nullptr);
+ PartitionOpener opener;
BlockDeviceInfo device_info;
- ASSERT_TRUE(GetBlockDeviceInfo(rec->blk_device, &device_info));
+ ASSERT_TRUE(opener.GetInfo(fs_mgr_get_super_partition_name(), &device_info));
// Sanity check that the device doesn't give us some weird inefficient
// alignment.
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 6d7324d..a090889 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -24,6 +24,7 @@
#include <memory>
#include "liblp.h"
+#include "partition_opener.h"
namespace android {
namespace fs_mgr {
@@ -34,27 +35,6 @@
static const uint32_t kDefaultPartitionAlignment = 1024 * 1024;
static const uint32_t kDefaultBlockSize = 4096;
-struct BlockDeviceInfo {
- BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
- BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
- uint32_t logical_block_size)
- : size(size),
- alignment(alignment),
- alignment_offset(alignment_offset),
- logical_block_size(logical_block_size) {}
- // Size of the block device, in bytes.
- uint64_t size;
- // Optimal target alignment, in bytes. Partition extents will be aligned to
- // this value by default. This value must be 0 or a multiple of 512.
- uint32_t alignment;
- // Alignment offset to parent device (if any), in bytes. The sector at
- // |alignment_offset| on the target device is correctly aligned on its
- // parent device. This value must be 0 or a multiple of 512.
- uint32_t alignment_offset;
- // Block size, for aligning extent sizes and partition sizes.
- uint32_t logical_block_size;
-};
-
// Abstraction around dm-targets that can be encoded into logical partition tables.
class Extent {
public:
@@ -157,7 +137,12 @@
// Import an existing table for modification. This reads metadata off the
// given block device and imports it. It also adjusts alignment information
// based on run-time values in the operating system.
- static std::unique_ptr<MetadataBuilder> New(const std::string& block_device,
+ static std::unique_ptr<MetadataBuilder> New(const IPartitionOpener& opener,
+ const std::string& super_partition,
+ uint32_t slot_number);
+
+ // Same as above, but use the default PartitionOpener.
+ static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition,
uint32_t slot_number);
// Import an existing table for modification. If the table is not valid, for
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 15fcd43..4669cea 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -24,7 +24,10 @@
#include <memory>
#include <string>
+#include <android-base/unique_fd.h>
+
#include "metadata_format.h"
+#include "partition_opener.h"
namespace android {
namespace fs_mgr {
@@ -44,7 +47,8 @@
// existing geometry, and should not be used for normal partition table
// updates. False can be returned if the geometry is incompatible with the
// block device or an I/O error occurs.
-bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata);
+bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
+ const LpMetadata& metadata);
// Update the partition table for a given metadata slot number. False is
// returned if an error occurs, which can include:
@@ -52,12 +56,19 @@
// - I/O error.
// - Corrupt or missing metadata geometry on disk.
// - Incompatible geometry.
-bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
- uint32_t slot_number);
+bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
+ const LpMetadata& metadata, uint32_t slot_number);
// Read logical partition metadata from its predetermined location on a block
// device. If readback fails, we also attempt to load from a backup copy.
-std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
+std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
+ const std::string& super_partition, uint32_t slot_number);
+
+// Helper functions that use the default PartitionOpener.
+bool FlashPartitionTable(const std::string& super_partition, const LpMetadata& metadata);
+bool UpdatePartitionTable(const std::string& super_partition, const LpMetadata& metadata,
+ uint32_t slot_number);
+std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number);
// Read/Write logical partition metadata to an image file, for diagnostics or
// flashing.
diff --git a/fs_mgr/liblp/include/liblp/partition_opener.h b/fs_mgr/liblp/include/liblp/partition_opener.h
new file mode 100644
index 0000000..fe61b9c
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/partition_opener.h
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <stdint.h>
+
+#include <string>
+
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace fs_mgr {
+
+struct BlockDeviceInfo {
+ BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
+ BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
+ uint32_t logical_block_size)
+ : size(size),
+ alignment(alignment),
+ alignment_offset(alignment_offset),
+ logical_block_size(logical_block_size) {}
+ // Size of the block device, in bytes.
+ uint64_t size;
+ // Optimal target alignment, in bytes. Partition extents will be aligned to
+ // this value by default. This value must be 0 or a multiple of 512.
+ uint32_t alignment;
+ // Alignment offset to parent device (if any), in bytes. The sector at
+ // |alignment_offset| on the target device is correctly aligned on its
+ // parent device. This value must be 0 or a multiple of 512.
+ uint32_t alignment_offset;
+ // Block size, for aligning extent sizes and partition sizes.
+ uint32_t logical_block_size;
+};
+
+// Test-friendly interface for interacting with partitions.
+class IPartitionOpener {
+ public:
+ virtual ~IPartitionOpener() = default;
+
+ // Open the given named physical partition with the provided open() flags.
+ // The name can be an absolute path if the full path is already known.
+ virtual android::base::unique_fd Open(const std::string& partition_name, int flags) const = 0;
+
+ // Return block device information about the given named physical partition.
+ // The name can be an absolute path if the full path is already known.
+ virtual bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const = 0;
+};
+
+// Helper class to implement IPartitionOpener. If |partition_name| is not an
+// absolute path, /dev/block/by-name/ will be prepended.
+class PartitionOpener : public IPartitionOpener {
+ public:
+ virtual android::base::unique_fd Open(const std::string& partition_name,
+ int flags) const override;
+ virtual bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const override;
+};
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 3889e87..9c675fe 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -26,6 +26,7 @@
#include "images.h"
#include "reader.h"
+#include "test_partition_opener.h"
#include "utility.h"
#include "writer.h"
@@ -101,7 +102,9 @@
if (!exported) {
return {};
}
- if (!FlashPartitionTable(fd, *exported.get())) {
+
+ TestPartitionOpener opener({{"super", fd}});
+ if (!FlashPartitionTable(opener, "super", *exported.get())) {
return {};
}
return fd;
@@ -116,8 +119,10 @@
ASSERT_TRUE(GetDescriptorSize(fd, &size));
ASSERT_EQ(size, kDiskSize);
+ TestPartitionOpener opener({{"super", fd}});
+
// Verify that we can't read unwritten metadata.
- ASSERT_EQ(ReadMetadata(fd, 1), nullptr);
+ ASSERT_EQ(ReadMetadata(opener, "super", 1), nullptr);
}
// Flashing metadata should not work if the metadata was created for a larger
@@ -133,7 +138,9 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
- EXPECT_FALSE(FlashPartitionTable(fd, *exported.get()));
+ TestPartitionOpener opener({{"super", fd}});
+
+ EXPECT_FALSE(FlashPartitionTable(opener, "super", *exported.get()));
}
// Test the basics of flashing a partition and reading it back.
@@ -145,16 +152,18 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
// Export and flash.
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
- ASSERT_TRUE(FlashPartitionTable(fd, *exported.get()));
+ ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
// Read back. Note that some fields are only filled in during
// serialization, so exported and imported will not be identical. For
// example, table sizes and checksums are computed in WritePartitionTable.
// Therefore we check on a field-by-field basis.
- unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
// Check geometry and header.
@@ -189,23 +198,25 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
+ unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
// Change the name before writing to the next slot.
strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
- ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
+ ASSERT_TRUE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
// Read back the original slot, make sure it hasn't changed.
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "system");
// Now read back the new slot, and verify that it has a different name.
- imported = ReadMetadata(fd, 1);
+ imported = ReadMetadata(opener, "super", 1);
ASSERT_NE(imported, nullptr);
ASSERT_EQ(imported->partitions.size(), 1);
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
@@ -232,15 +243,17 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
// Make sure all slots are filled.
- unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
ASSERT_NE(metadata, nullptr);
for (uint32_t i = 1; i < kMetadataSlots; i++) {
- ASSERT_TRUE(UpdatePartitionTable(fd, *metadata.get(), i));
+ ASSERT_TRUE(UpdatePartitionTable(opener, "super", *metadata.get(), i));
}
// Verify that we can't read unavailable slots.
- EXPECT_EQ(ReadMetadata(fd, kMetadataSlots), nullptr);
+ EXPECT_EQ(ReadMetadata(opener, "super", kMetadataSlots), nullptr);
}
// Test that updating a metadata slot does not allow it to be computed based
@@ -249,25 +262,27 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
+ unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
- ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
+ ASSERT_TRUE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
imported->geometry.metadata_max_size += LP_SECTOR_SIZE;
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
imported->geometry.metadata_slot_count++;
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
ASSERT_EQ(imported->block_devices.size(), 1);
imported->block_devices[0].first_logical_sector++;
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 1));
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
}
@@ -276,6 +291,8 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
LpMetadataGeometry geometry;
ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
ASSERT_TRUE(android::base::ReadFully(fd, &geometry, sizeof(geometry)));
@@ -284,7 +301,7 @@
bad_geometry.metadata_slot_count++;
ASSERT_TRUE(android::base::WriteFully(fd, &bad_geometry, sizeof(bad_geometry)));
- unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
ASSERT_NE(metadata, nullptr);
EXPECT_EQ(metadata->geometry.metadata_slot_count, 2);
}
@@ -293,25 +310,29 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
char corruption[LP_METADATA_GEOMETRY_SIZE];
memset(corruption, 0xff, sizeof(corruption));
// Corrupt the primary geometry.
ASSERT_GE(lseek(fd, GetPrimaryGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
- EXPECT_NE(ReadMetadata(fd, 0), nullptr);
+ EXPECT_NE(ReadMetadata(opener, "super", 0), nullptr);
// Corrupt the backup geometry.
ASSERT_GE(lseek(fd, GetBackupGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
- EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
+ EXPECT_EQ(ReadMetadata(opener, "super", 0), nullptr);
}
TEST(liblp, ReadBackupMetadata) {
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
+ unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
char corruption[kMetadataSize];
memset(corruption, 0xff, sizeof(corruption));
@@ -320,14 +341,14 @@
ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
- EXPECT_NE(ReadMetadata(fd, 0), nullptr);
+ EXPECT_NE(ReadMetadata(opener, "super", 0), nullptr);
offset = GetBackupMetadataOffset(metadata->geometry, 0);
// Corrupt the backup metadata.
ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
- EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
+ EXPECT_EQ(ReadMetadata(opener, "super", 0), nullptr);
}
// Test that we don't attempt to write metadata if it would overflow its
@@ -357,8 +378,10 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
// Check that we are able to write our table.
- ASSERT_TRUE(FlashPartitionTable(fd, *exported.get()));
+ ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
// Check that adding one more partition overflows the metadata allotment.
partition = builder->AddPartition("final", LP_PARTITION_ATTR_NONE);
@@ -368,7 +391,7 @@
ASSERT_NE(exported, nullptr);
// The new table should be too large to be written.
- ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *exported.get(), 1));
auto super_device = GetMetadataSuperBlockDevice(*exported.get());
ASSERT_NE(super_device, nullptr);
@@ -464,23 +487,25 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
BadWriter writer;
// Read and write it back.
writer.FailOnWrite(1);
- unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
// We should still be able to read the backup copy.
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
// Flash again, this time fail the backup copy. We should still be able
// to read the primary.
writer.FailOnWrite(3);
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
- imported = ReadMetadata(fd, 0);
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
}
@@ -490,23 +515,25 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
BadWriter writer;
// Read and write it back.
writer.FailOnWrite(2);
- unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
// We should still be able to read the primary copy.
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
// Flash again, this time fail the primary copy. We should still be able
// to read the primary.
writer.FailOnWrite(2);
- ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
- imported = ReadMetadata(fd, 0);
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *imported.get(), 0, writer));
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
}
@@ -517,20 +544,22 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
+ TestPartitionOpener opener({{"super", fd}});
+
BadWriter writer;
// Change the name of the existing partition.
- unique_ptr<LpMetadata> new_table = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> new_table = ReadMetadata(opener, "super", 0);
ASSERT_NE(new_table, nullptr);
ASSERT_GE(new_table->partitions.size(), 1);
new_table->partitions[0].name[0]++;
// Flash it, but fail to write the backup copy.
writer.FailAfterWrite(2);
- ASSERT_FALSE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
+ ASSERT_FALSE(UpdatePartitionTable(opener, "super", *new_table.get(), 0, writer));
// When we read back, we should get the updated primary copy.
- unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
ASSERT_GE(new_table->partitions.size(), 1);
ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
@@ -539,9 +568,9 @@
// Note that the sync step should have used the primary to sync, not
// the backup.
writer.Reset();
- ASSERT_TRUE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
+ ASSERT_TRUE(UpdatePartitionTable(opener, "super", *new_table.get(), 0, writer));
- imported = ReadMetadata(fd, 0);
+ imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
ASSERT_GE(new_table->partitions.size(), 1);
ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
new file mode 100644
index 0000000..7381eed
--- /dev/null
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "liblp/partition_opener.h"
+
+#if defined(__linux__)
+#include <linux/fs.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "utility.h"
+
+namespace android {
+namespace fs_mgr {
+
+using android::base::unique_fd;
+
+namespace {
+
+std::string GetPartitionAbsolutePath(const std::string& path) {
+ if (path[0] == '/') {
+ return path;
+ }
+ return "/dev/block/by-name/" + path;
+}
+
+bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
+#if defined(__linux__)
+ unique_fd fd(open(block_device.c_str(), O_RDONLY));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
+ return false;
+ }
+ if (!GetDescriptorSize(fd, &device_info->size)) {
+ return false;
+ }
+ if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+ return false;
+ }
+
+ int alignment_offset;
+ if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+ return false;
+ }
+ int logical_block_size;
+ if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
+ return false;
+ }
+
+ device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
+ device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
+ return true;
+#else
+ (void)block_device;
+ (void)device_info;
+ LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
+ return false;
+#endif
+}
+
+} // namespace
+
+unique_fd PartitionOpener::Open(const std::string& partition_name, int flags) const {
+ std::string path = GetPartitionAbsolutePath(partition_name);
+ return unique_fd{open(path.c_str(), flags)};
+}
+
+bool PartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
+ std::string path = GetPartitionAbsolutePath(partition_name);
+ return GetBlockDeviceInfo(path, info);
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index c34b138..070573c 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -342,7 +342,14 @@
return ParseMetadata(geometry, fd);
}
-std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
+std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
+ const std::string& super_partition, uint32_t slot_number) {
+ android::base::unique_fd fd = opener.Open(super_partition, O_RDONLY);
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
+ return nullptr;
+ }
+
LpMetadataGeometry geometry;
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
return nullptr;
@@ -361,13 +368,8 @@
return ReadBackupMetadata(fd, geometry, slot_number);
}
-std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
- android::base::unique_fd fd(open(block_device, O_RDONLY));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
- return nullptr;
- }
- return ReadMetadata(fd, slot_number);
+std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) {
+ return ReadMetadata(PartitionOpener(), super_partition, slot_number);
}
static std::string NameFromFixedArray(const char* name, size_t buffer_size) {
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index 24b2611..d5d5188 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -31,7 +31,6 @@
bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry);
// Helper functions for manually reading geometry and metadata.
-std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, int fd);
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
size_t size);
diff --git a/fs_mgr/liblp/test_partition_opener.cpp b/fs_mgr/liblp/test_partition_opener.cpp
new file mode 100644
index 0000000..c796f6c
--- /dev/null
+++ b/fs_mgr/liblp/test_partition_opener.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test_partition_opener.h"
+
+#include <errno.h>
+
+namespace android {
+namespace fs_mgr {
+
+using android::base::unique_fd;
+
+TestPartitionOpener::TestPartitionOpener(
+ const std::map<std::string, int>& partition_map,
+ const std::map<std::string, BlockDeviceInfo>& partition_info)
+ : partition_map_(partition_map), partition_info_(partition_info) {}
+
+unique_fd TestPartitionOpener::Open(const std::string& partition_name, int flags) const {
+ auto iter = partition_map_.find(partition_name);
+ if (iter == partition_map_.end()) {
+ errno = ENOENT;
+ return {};
+ }
+ return unique_fd{dup(iter->second)};
+}
+
+bool TestPartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
+ auto iter = partition_info_.find(partition_name);
+ if (iter == partition_info_.end()) {
+ errno = ENOENT;
+ return false;
+ }
+ *info = iter->second;
+ return true;
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/test_partition_opener.h b/fs_mgr/liblp/test_partition_opener.h
new file mode 100644
index 0000000..b90fee7
--- /dev/null
+++ b/fs_mgr/liblp/test_partition_opener.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <android-base/unique_fd.h>
+#include <liblp/partition_opener.h>
+
+namespace android {
+namespace fs_mgr {
+
+class TestPartitionOpener : public PartitionOpener {
+ public:
+ explicit TestPartitionOpener(const std::map<std::string, int>& partition_map,
+ const std::map<std::string, BlockDeviceInfo>& partition_info = {});
+
+ android::base::unique_fd Open(const std::string& partition_name, int flags) const override;
+ bool GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const override;
+
+ private:
+ std::map<std::string, int> partition_map_;
+ std::map<std::string, BlockDeviceInfo> partition_info_;
+};
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 518920d..742ad82 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -16,7 +16,6 @@
#include <fcntl.h>
#include <stdint.h>
-#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index ddae842..c740bd4 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -218,7 +218,14 @@
return android::base::WriteFully(fd, blob.data(), blob.size());
}
-bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
+bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
+ const LpMetadata& metadata) {
+ android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
+ return false;
+ }
+
// Before writing geometry and/or logical partition tables, perform some
// basic checks that the geometry and tables are coherent, and will fit
// on the given block device.
@@ -238,6 +245,8 @@
return false;
}
+ LWARN << "Flashing new logical partition geometry to " << super_partition;
+
// Write geometry to the primary and backup locations.
std::string blob = SerializeGeometry(metadata.geometry);
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
@@ -264,13 +273,24 @@
return ok;
}
+bool FlashPartitionTable(const std::string& super_partition, const LpMetadata& metadata) {
+ return FlashPartitionTable(PartitionOpener(), super_partition, metadata);
+}
+
static bool CompareMetadata(const LpMetadata& a, const LpMetadata& b) {
return !memcmp(a.header.header_checksum, b.header.header_checksum,
sizeof(a.header.header_checksum));
}
-bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
+ const LpMetadata& metadata, uint32_t slot_number,
const std::function<bool(int, const std::string&)>& writer) {
+ android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << super_partition;
+ return false;
+ }
+
// Before writing geometry and/or logical partition tables, perform some
// basic checks that the geometry and tables are coherent, and will fit
// on the given block device.
@@ -330,39 +350,24 @@
}
// Both copies should now be in sync, so we can continue the update.
- return WriteMetadata(fd, metadata, slot_number, blob, writer);
-}
+ if (!WriteMetadata(fd, metadata, slot_number, blob, writer)) {
+ return false;
+ }
-bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) {
- android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
- return false;
- }
- if (!FlashPartitionTable(fd, metadata)) {
- return false;
- }
- LWARN << "Flashed new logical partition geometry to " << block_device;
- return true;
-}
-
-bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
- uint32_t slot_number) {
- android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
- return false;
- }
- if (!UpdatePartitionTable(fd, metadata, slot_number)) {
- return false;
- }
LINFO << "Updated logical partition table at slot " << slot_number << " on device "
- << block_device;
+ << super_partition;
return true;
}
-bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
- return UpdatePartitionTable(fd, metadata, slot_number, DefaultWriter);
+bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
+ const LpMetadata& metadata, uint32_t slot_number) {
+ return UpdatePartitionTable(opener, super_partition, metadata, slot_number, DefaultWriter);
+}
+
+bool UpdatePartitionTable(const std::string& super_partition, const LpMetadata& metadata,
+ uint32_t slot_number) {
+ PartitionOpener opener;
+ return UpdatePartitionTable(opener, super_partition, metadata, slot_number, DefaultWriter);
}
} // namespace fs_mgr
diff --git a/fs_mgr/liblp/writer.h b/fs_mgr/liblp/writer.h
index ab18d45..6f1da0f 100644
--- a/fs_mgr/liblp/writer.h
+++ b/fs_mgr/liblp/writer.h
@@ -30,10 +30,8 @@
// These variants are for testing only. The path-based functions should be used
// for actual operation, so that open() is called with the correct flags.
-bool FlashPartitionTable(int fd, const LpMetadata& metadata);
-bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number);
-
-bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
+ const LpMetadata& metadata, uint32_t slot_number,
const std::function<bool(int, const std::string&)>& writer);
} // namespace fs_mgr