summaryrefslogtreecommitdiffstats
path: root/fs_mgr/liblp
diff options
context:
space:
mode:
authorDavid Anderson <dvander@google.com>2018-11-06 19:06:41 -0800
committerDavid Anderson <dvander@google.com>2018-11-08 09:51:03 -0800
commit76cde4173ab752ff7e3f0ccd7fcf08187ad016bb (patch)
tree1d2c6000d041c684671eb9728eb72d29bb632ddf /fs_mgr/liblp
parent71c29a9ce0df115860f2167ec2f2fa1dbbaa4202 (diff)
downloadsystem_core-76cde4173ab752ff7e3f0ccd7fcf08187ad016bb.tar.gz
system_core-76cde4173ab752ff7e3f0ccd7fcf08187ad016bb.tar.bz2
system_core-76cde4173ab752ff7e3f0ccd7fcf08187ad016bb.zip
liblp: Allow automatic slot suffixing of partition names.
On retrofit devices, an OTA package or super_empty.img won't know which slot it applies to. This is not an issue on devices shipping with dynamic partitions, since they ship on the "a" slot. To work around this, partitions and block devices can be flagged as "auto-slot-suffixed". This indicates that ReadMetadata should automatically append a slot suffix before returning the metadata. This flag is added by MetadataBuilder when requested, and will be enabled via lpmake separately. After ReadMetadata has applied slot suffixes, it takes care to remove the slot-suffix flag. This prevents the suffix from being applied twice, if for example the metadata is then imported into a MetadataBuilder. Bug: 116802789 Test: liblp_test gtest retrofit device boots Change-Id: Ic7de06d31253a8d5b8d15c0d936175ca2939f857
Diffstat (limited to 'fs_mgr/liblp')
-rw-r--r--fs_mgr/liblp/builder.cpp16
-rw-r--r--fs_mgr/liblp/include/liblp/builder.h4
-rw-r--r--fs_mgr/liblp/include/liblp/liblp.h1
-rw-r--r--fs_mgr/liblp/include/liblp/metadata_format.h28
-rw-r--r--fs_mgr/liblp/io_test.cpp26
-rw-r--r--fs_mgr/liblp/reader.cpp58
-rw-r--r--fs_mgr/liblp/reader.h4
-rw-r--r--fs_mgr/liblp/utility.cpp5
-rw-r--r--fs_mgr/liblp/utility_test.cpp5
-rw-r--r--fs_mgr/liblp/writer.cpp26
10 files changed, 155 insertions, 18 deletions
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4007ad9f7..1e031ad81 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -150,7 +150,7 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata
return builder;
}
-MetadataBuilder::MetadataBuilder() {
+MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
memset(&geometry_, 0, sizeof(geometry_));
geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
geometry_.struct_size = sizeof(geometry_);
@@ -564,7 +564,12 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
metadata->geometry = geometry_;
// Assign this early so the extent table can read it.
- metadata->block_devices = block_devices_;
+ for (const auto& block_device : block_devices_) {
+ metadata->block_devices.emplace_back(block_device);
+ if (auto_slot_suffixing_) {
+ metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+ }
+ }
std::map<std::string, size_t> group_indices;
for (const auto& group : groups_) {
@@ -600,6 +605,9 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
part.num_extents = static_cast<uint32_t>(partition->extents().size());
part.attributes = partition->attributes();
+ if (auto_slot_suffixing_) {
+ part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
+ }
auto iter = group_indices.find(partition->group_name());
if (iter == group_indices.end()) {
@@ -836,5 +844,9 @@ bool MetadataBuilder::ImportPartition(const LpMetadata& metadata,
return true;
}
+void MetadataBuilder::SetAutoSlotSuffixing() {
+ auto_slot_suffixing_ = true;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index d5e3fed61..47ebf6d3e 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -223,6 +223,9 @@ class MetadataBuilder {
// Remove all partitions belonging to a group, then remove the group.
void RemoveGroupAndPartitions(const std::string& group_name);
+ // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag.
+ void SetAutoSlotSuffixing();
+
bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
@@ -275,6 +278,7 @@ class MetadataBuilder {
std::vector<std::unique_ptr<Partition>> partitions_;
std::vector<std::unique_ptr<PartitionGroup>> groups_;
std::vector<LpMetadataBlockDevice> block_devices_;
+ bool auto_slot_suffixing_;
};
// Read BlockDeviceInfo for a given block device. This always returns false
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 8723a7fe6..56332ab9b 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -95,6 +95,7 @@ std::vector<std::string> GetBlockDevicePartitionNames(const LpMetadata& metadata
// Slot suffix helpers.
uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+std::string SlotSuffixForSlotNumber(uint32_t slot_number);
std::string GetPartitionSlotSuffix(const std::string& partition_name);
} // namespace fs_mgr
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 1e40df3cf..c2e25fbfb 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@ extern "C" {
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 8
+#define LP_METADATA_MAJOR_VERSION 9
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -47,10 +47,19 @@ extern "C" {
* device mapper, the block device will be created as read-only.
*/
#define LP_PARTITION_ATTR_NONE 0x0
-#define LP_PARTITION_ATTR_READONLY 0x1
+#define LP_PARTITION_ATTR_READONLY (1 << 0)
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the partition name needs a slot suffix applied. The slot suffix is
+ * determined by the metadata slot number (0 = _a, 1 = _b).
+ */
+#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
/* Mask that defines all valid attributes. */
-#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY)
+#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
/* Default name of the physical partition that holds logical partition entries.
* The layout of this partition will look like:
@@ -302,8 +311,21 @@ typedef struct LpMetadataBlockDevice {
/* 24: Partition name in the GPT. Any unused characters must be 0. */
char partition_name[36];
+
+ /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
+ uint32_t flags;
} LpMetadataBlockDevice;
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the block device needs a slot suffix applied before being used with
+ * IPartitionOpener. The slot suffix is determined by the metadata slot number
+ * (0 = _a, 1 = _b).
+ */
+#define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 603e5c046..459cf828a 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -88,11 +88,14 @@ static bool AddDefaultPartitions(MetadataBuilder* builder) {
}
// Create a temporary disk and flash it with the default partition setup.
-static unique_fd CreateFlashedDisk() {
+static unique_fd CreateFlashedDisk(bool auto_slot_suffix = false) {
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
if (!builder || !AddDefaultPartitions(builder.get())) {
return {};
}
+ if (auto_slot_suffix) {
+ builder->SetAutoSlotSuffixing();
+ }
unique_fd fd = CreateFakeDisk();
if (fd < 0) {
return {};
@@ -608,3 +611,24 @@ TEST(liblp, FlashSparseImage) {
ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
}
+
+TEST(liblp, AutoSlotSuffixing) {
+ auto fd = CreateFlashedDisk(true);
+ ASSERT_GE(fd, 0);
+
+ TestPartitionOpener opener({{"super", fd}});
+
+ auto metadata = ReadMetadata(opener, "super", 1);
+ ASSERT_NE(metadata, nullptr);
+ ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+ EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_b");
+ ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
+ EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_b");
+
+ metadata = ReadMetadata(opener, "super", 0);
+ ASSERT_NE(metadata, nullptr);
+ ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+ EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_a");
+ ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
+ EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index a02e746aa..3319956dd 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -348,6 +348,40 @@ std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry&
return ParseMetadata(geometry, fd);
}
+namespace {
+
+bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) {
+ std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+ for (auto& partition : metadata->partitions) {
+ if (!(partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED)) {
+ continue;
+ }
+ std::string partition_name = GetPartitionName(partition) + slot_suffix;
+ if (partition_name.size() > sizeof(partition.name)) {
+ LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+ return false;
+ }
+ strncpy(partition.name, partition_name.c_str(), sizeof(partition.name));
+ partition.attributes &= ~LP_PARTITION_ATTR_SLOT_SUFFIXED;
+ }
+ for (auto& block_device : metadata->block_devices) {
+ if (!(block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED)) {
+ continue;
+ }
+ std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix;
+ if (partition_name.size() > sizeof(block_device.partition_name)) {
+ LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+ return false;
+ }
+ strncpy(block_device.partition_name, partition_name.c_str(),
+ sizeof(block_device.partition_name));
+ block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+ }
+ return true;
+}
+
+} // namespace
+
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);
@@ -360,18 +394,30 @@ std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
return nullptr;
}
-
if (slot_number >= geometry.metadata_slot_count) {
LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
return nullptr;
}
- // Read the primary copy, and if that fails, try the backup.
- std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
- if (metadata) {
- return metadata;
+ std::vector<int64_t> offsets = {
+ GetPrimaryMetadataOffset(geometry, slot_number),
+ GetBackupMetadataOffset(geometry, slot_number),
+ };
+ std::unique_ptr<LpMetadata> metadata;
+
+ for (const auto& offset : offsets) {
+ if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed, offset " << offset;
+ continue;
+ }
+ if ((metadata = ParseMetadata(geometry, fd)) != nullptr) {
+ break;
+ }
}
- return ReadBackupMetadata(fd, geometry, slot_number);
+ if (!metadata || !AdjustMetadataForSlot(metadata.get(), slot_number)) {
+ return nullptr;
+ }
+ return metadata;
}
std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) {
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index d5d518888..7a2490b9b 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -38,7 +38,9 @@ bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry);
bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry);
-// These functions assume a valid geometry and slot number.
+// These functions assume a valid geometry and slot number, and do not obey
+// auto-slot-suffixing. They are used for tests and for checking whether
+// the metadata is coherent across primary and backup copies.
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
uint32_t slot_number);
std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index cce90a308..2d34ce50d 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -132,5 +132,10 @@ std::string GetPartitionSlotSuffix(const std::string& partition_name) {
return (suffix == "_a" || suffix == "_b") ? suffix : "";
}
+std::string SlotSuffixForSlotNumber(uint32_t slot_number) {
+ CHECK(slot_number == 0 || slot_number == 1);
+ return (slot_number == 0) ? "_a" : "_b";
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 0fa4590ee..15f7fff4e 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -32,6 +32,11 @@ TEST(liblp, SlotNumberForSlotSuffix) {
EXPECT_EQ(SlotNumberForSlotSuffix("_d"), 0);
}
+TEST(liblp, SlotSuffixForSlotNumber) {
+ EXPECT_EQ(SlotSuffixForSlotNumber(0), "_a");
+ EXPECT_EQ(SlotSuffixForSlotNumber(1), "_b");
+}
+
TEST(liblp, GetMetadataOffset) {
LpMetadataGeometry geometry = {LP_METADATA_GEOMETRY_MAGIC,
sizeof(geometry),
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index f4c9b991a..e72cdfa16 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -83,7 +83,7 @@ std::string SerializeMetadata(const LpMetadata& input) {
// Perform sanity checks so we don't accidentally overwrite valid metadata
// with potentially invalid metadata, or random partition data with metadata.
static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
- std::string* blob) {
+ const std::string& slot_suffix, std::string* blob) {
const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
@@ -114,6 +114,15 @@ static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const L
}
for (const auto& block_device : metadata.block_devices) {
std::string partition_name = GetBlockDevicePartitionName(block_device);
+ if (block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) {
+ if (slot_suffix.empty()) {
+ LERROR << "Block device " << partition_name << " requires a slot suffix,"
+ << " which could not be derived from the super partition name.";
+ return false;
+ }
+ partition_name += slot_suffix;
+ }
+
if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
LERROR << "Block device " << partition_name << " has invalid first sector "
<< block_device.first_logical_sector << " for size " << block_device.size;
@@ -234,11 +243,16 @@ bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& supe
return false;
}
+ // This is only used in update_engine and fastbootd, where the super
+ // partition should be specified as a name (or by-name link), and
+ // therefore, we should be able to extract a slot suffix.
+ std::string slot_suffix = GetPartitionSlotSuffix(super_partition);
+
// 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.
std::string metadata_blob;
- if (!ValidateAndSerializeMetadata(opener, metadata, &metadata_blob)) {
+ if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &metadata_blob)) {
return false;
}
@@ -299,11 +313,13 @@ bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& sup
return false;
}
+ std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+
// 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.
std::string blob;
- if (!ValidateAndSerializeMetadata(opener, metadata, &blob)) {
+ if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &blob)) {
return false;
}
@@ -335,7 +351,7 @@ bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& sup
// synchronize the backup copy. This guarantees that a partial write
// still leaves one copy intact.
std::string old_blob;
- if (!ValidateAndSerializeMetadata(opener, *primary.get(), &old_blob)) {
+ if (!ValidateAndSerializeMetadata(opener, *primary.get(), slot_suffix, &old_blob)) {
LERROR << "Error serializing primary metadata to repair corrupted backup";
return false;
}
@@ -347,7 +363,7 @@ bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& sup
// The backup copy is coherent, and the primary is not. Sync it for
// safety.
std::string old_blob;
- if (!ValidateAndSerializeMetadata(opener, *backup.get(), &old_blob)) {
+ if (!ValidateAndSerializeMetadata(opener, *backup.get(), slot_suffix, &old_blob)) {
LERROR << "Error serializing primary metadata to repair corrupted backup";
return false;
}