Skip to content

Commit 54f4030

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge "liblp: Allow specifying a custom block size when building sparse images."
2 parents bd13056 + ce483b6 commit 54f4030

File tree

3 files changed

+63
-38
lines changed

3 files changed

+63
-38
lines changed

fs_mgr/liblp/images.cpp

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,9 @@ std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
5757

5858
bool WriteToImageFile(int fd, const LpMetadata& input) {
5959
std::string geometry = SerializeGeometry(input.geometry);
60-
std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
6160
std::string metadata = SerializeMetadata(input);
6261

63-
std::string everything = geometry + padding + metadata;
62+
std::string everything = geometry + metadata;
6463

6564
if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
6665
PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
@@ -83,26 +82,29 @@ bool WriteToImageFile(const char* file, const LpMetadata& input) {
8382
// to do this when the data pointers are all in one place.
8483
class SparseBuilder {
8584
public:
86-
explicit SparseBuilder(const LpMetadata& metadata);
85+
SparseBuilder(const LpMetadata& metadata, uint32_t block_size);
8786

8887
bool Build();
8988
bool Export(const char* file);
9089
bool IsValid() const { return file_ != nullptr; }
9190

9291
private:
93-
bool AddData(const std::string& blob, uint32_t block);
92+
bool AddData(const std::string& blob, uint64_t sector);
93+
bool SectorToBlock(uint64_t sector, uint32_t* block);
9494

9595
const LpMetadata& metadata_;
9696
const LpMetadataGeometry& geometry_;
97+
uint32_t block_size_;
9798
std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
98-
std::string geometry_blob_;
99-
std::string metadata_blob_;
99+
std::string primary_blob_;
100+
std::string backup_blob_;
100101
};
101102

102-
SparseBuilder::SparseBuilder(const LpMetadata& metadata)
103+
SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size)
103104
: metadata_(metadata),
104105
geometry_(metadata.geometry),
105-
file_(sparse_file_new(LP_SECTOR_SIZE, geometry_.block_device_size), sparse_file_destroy) {}
106+
block_size_(block_size),
107+
file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy) {}
106108

107109
bool SparseBuilder::Export(const char* file) {
108110
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
@@ -119,7 +121,11 @@ bool SparseBuilder::Export(const char* file) {
119121
return true;
120122
}
121123

122-
bool SparseBuilder::AddData(const std::string& blob, uint32_t block) {
124+
bool SparseBuilder::AddData(const std::string& blob, uint64_t sector) {
125+
uint32_t block;
126+
if (!SectorToBlock(sector, &block)) {
127+
return false;
128+
}
123129
void* data = const_cast<char*>(blob.data());
124130
int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
125131
if (ret != 0) {
@@ -129,54 +135,70 @@ bool SparseBuilder::AddData(const std::string& blob, uint32_t block) {
129135
return true;
130136
}
131137

132-
bool SparseBuilder::Build() {
133-
geometry_blob_ = SerializeGeometry(geometry_);
134-
geometry_blob_.resize(LP_METADATA_GEOMETRY_SIZE);
135-
if (!AddData(geometry_blob_, 0)) {
138+
bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
139+
// The caller must ensure that the metadata has an alignment that is a
140+
// multiple of the block size. liblp will take care of the rest, ensuring
141+
// that all partitions are on an aligned boundary. Therefore all writes
142+
// should be block-aligned, and if they are not, the table was misconfigured.
143+
// Note that the default alignment is 1MiB, which is a multiple of the
144+
// default block size (4096).
145+
if ((sector * LP_SECTOR_SIZE) % block_size_ != 0) {
146+
LERROR << "sector " << sector << " is not aligned to block size " << block_size_;
136147
return false;
137148
}
149+
*block = (sector * LP_SECTOR_SIZE) / block_size_;
150+
return true;
151+
}
138152

139-
// Metadata immediately follows geometry, and we write the same metadata
140-
// to all slots.
141-
uint32_t metadata_block = LP_METADATA_GEOMETRY_SIZE / LP_SECTOR_SIZE;
142-
metadata_blob_ = SerializeMetadata(metadata_);
153+
bool SparseBuilder::Build() {
154+
std::string geometry_blob = SerializeGeometry(geometry_);
155+
std::string metadata_blob = SerializeMetadata(metadata_);
156+
metadata_blob.resize(geometry_.metadata_max_size);
157+
158+
std::string all_metadata;
143159
for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
144-
if (!AddData(metadata_blob_, metadata_block)) {
145-
return false;
146-
}
147-
metadata_block += geometry_.metadata_max_size / LP_SECTOR_SIZE;
160+
all_metadata += metadata_blob;
161+
}
162+
163+
// Metadata immediately follows geometry, and we write the same metadata
164+
// to all slots. Note that we don't bother trying to write skip chunks
165+
// here since it's a small amount of data.
166+
primary_blob_ = geometry_blob + all_metadata;
167+
if (!AddData(primary_blob_, 0)) {
168+
return false;
148169
}
149170

150171
// The backup area contains all metadata slots, and then geometry. Similar
151172
// to before we write the metadata to every slot.
152173
int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
153174
uint64_t backups_start = geometry_.block_device_size + backup_offset;
154175
uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
155-
for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
156-
if (!AddData(metadata_blob_, backup_sector)) {
157-
return false;
158-
}
159-
backup_sector += geometry_.metadata_max_size / LP_SECTOR_SIZE;
160-
}
161-
if (!AddData(geometry_blob_, backup_sector)) {
176+
177+
backup_blob_ = all_metadata + geometry_blob;
178+
if (!AddData(backup_blob_, backup_sector)) {
162179
return false;
163180
}
164181
return true;
165182
}
166183

167-
bool WriteToSparseFile(const char* file, const LpMetadata& metadata) {
168-
uint64_t num_blocks =
169-
AlignTo(metadata.geometry.block_device_size, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
184+
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size) {
185+
if (block_size % LP_SECTOR_SIZE != 0) {
186+
LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
187+
return false;
188+
}
189+
if (metadata.geometry.block_device_size % block_size != 0) {
190+
LERROR << "Device size must be a multiple of the block size, " << block_size;
191+
return false;
192+
}
193+
uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
170194
if (num_blocks >= UINT_MAX) {
171-
// libsparse counts blocks in unsigned 32-bit integers, but our block
172-
// size is rather low (512 bytes), since we operate in sectors.
173-
// Therefore the maximum block device size we can represent with a
174-
// sparse file is 2TB for now.
195+
// libsparse counts blocks in unsigned 32-bit integers, so we check to
196+
// make sure we're not going to overflow.
175197
LERROR << "Block device is too large to encode with libsparse.";
176198
return false;
177199
}
178200

179-
SparseBuilder builder(metadata);
201+
SparseBuilder builder(metadata, block_size);
180202
if (!builder.IsValid()) {
181203
LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
182204
return false;

fs_mgr/liblp/include/liblp/liblp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot
5959

6060
// Read/Write logical partition metadata to an image file, for diagnostics or
6161
// flashing.
62-
bool WriteToSparseFile(const char* file, const LpMetadata& metadata);
62+
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size);
6363
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
6464
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
6565

fs_mgr/liblp/writer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ std::string SerializeGeometry(const LpMetadataGeometry& input) {
3434
LpMetadataGeometry geometry = input;
3535
memset(geometry.checksum, 0, sizeof(geometry.checksum));
3636
SHA256(&geometry, sizeof(geometry), geometry.checksum);
37-
return std::string(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
37+
38+
std::string blob(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
39+
blob.resize(LP_METADATA_GEOMETRY_SIZE);
40+
return blob;
3841
}
3942

4043
static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {

0 commit comments

Comments
 (0)