Merge "liblp: Allow automatic slot suffixing of partition names." am: 9e04f62895
am: e655a67b08
Change-Id: I437754b4deea7483251a6a5d944669aef148166d
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4007ad9..1e031ad 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -150,7 +150,7 @@
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 @@
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 @@
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 @@
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 d5e3fed..47ebf6d 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -223,6 +223,9 @@
// 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 @@
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 8723a7f..56332ab 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -95,6 +95,7 @@
// 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 1e40df3..c2e25fb 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#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 @@
* 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 @@
/* 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 603e5c0..459cf82 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -88,11 +88,14 @@
}
// 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 @@
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 a02e746..3319956 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -348,6 +348,40 @@
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 @@
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 d5d5188..7a2490b 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -38,7 +38,9 @@
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 cce90a3..2d34ce5 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -132,5 +132,10 @@
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 0fa4590..15f7fff 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -32,6 +32,11 @@
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 f4c9b99..e72cdfa 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -83,7 +83,7 @@
// 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 @@
}
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 @@
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 @@
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 @@
// 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 @@
// 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;
}