Merge "Add //visibility:any_system_partition" into main
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
index 2021348..4456b26 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
@@ -209,6 +209,48 @@
ASSERT_EQ(sink, data);
}
+TEST_F(CowTestV3, BigReplaceOp) {
+ CowOptions options;
+ options.op_count_max = 10000;
+ options.batch_write = true;
+ options.cluster_ops = 2048;
+
+ auto writer = CreateCowWriter(3, options, GetCowFd());
+ std::string data = "This is some data, believe it";
+ data.resize(options.block_size * 4096, '\0');
+ for (int i = 0; i < data.size(); i++) {
+ data[i] = static_cast<char>('A' + i / options.block_size);
+ }
+ ASSERT_TRUE(writer->AddRawBlocks(5, data.data(), data.size()));
+ ASSERT_TRUE(writer->Finalize());
+
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ const auto& header = reader.header_v3();
+ ASSERT_EQ(header.op_count, 4096);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->AtEnd());
+
+ size_t i = 0;
+
+ while (!iter->AtEnd()) {
+ auto op = iter->Get();
+ std::string sink(options.block_size, '\0');
+ ASSERT_EQ(op->type(), kCowReplaceOp);
+ ASSERT_EQ(op->data_length, options.block_size);
+ ASSERT_EQ(op->new_block, 5 + i);
+ ASSERT_TRUE(ReadData(reader, op, sink.data(), options.block_size));
+ ASSERT_EQ(std::string_view(sink),
+ std::string_view(data).substr(i * options.block_size, options.block_size))
+ << " readback data for " << i << "th block does not match";
+ iter->Next();
+ i++;
+ }
+}
+
TEST_F(CowTestV3, ConsecutiveReplaceOp) {
CowOptions options;
options.op_count_max = 20;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index ea1da4b..8cc9964 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -717,13 +717,27 @@
return false;
}
if (!data.empty()) {
- const auto ret = pwritev(fd_, data.data(), data.size(), next_data_pos_);
- if (ret != total_data_size) {
+ int total_written = 0;
+ int i = 0;
+ while (i < data.size()) {
+ int chunk = std::min(static_cast<int>(data.size() - i), IOV_MAX);
+
+ const auto ret = pwritev(fd_, data.data() + i, chunk, next_data_pos_ + total_written);
+ if (ret < 0) {
+ PLOG(ERROR) << "write failed chunk size of: " << chunk
+ << " at offset: " << next_data_pos_ + total_written << " " << errno;
+ return false;
+ }
+ total_written += ret;
+ i += chunk;
+ }
+ if (total_written != total_data_size) {
PLOG(ERROR) << "write failed for data of size: " << data.size()
- << " at offset: " << next_data_pos_ << " " << ret;
+ << " at offset: " << next_data_pos_ << " " << errno;
return false;
}
}
+
header_.op_count += ops.size();
next_data_pos_ += total_data_size;