Merge "Move ENOSPC tests to libfiemap."
This commit is contained in:
commit
3a079130de
4 changed files with 87 additions and 126 deletions
|
@ -93,6 +93,9 @@ cc_test {
|
|||
test_options: {
|
||||
min_shipping_api_level: 29,
|
||||
},
|
||||
header_libs: [
|
||||
"libstorage_literals_headers",
|
||||
],
|
||||
require_root: true,
|
||||
}
|
||||
|
||||
|
|
|
@ -22,21 +22,25 @@
|
|||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <fstab/fstab.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <libdm/loop_control.h>
|
||||
#include <libfiemap/fiemap_writer.h>
|
||||
#include <libfiemap/split_fiemap_writer.h>
|
||||
#include <libgsi/libgsi.h>
|
||||
#include <storage_literals/storage_literals.h>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
|
@ -46,6 +50,7 @@ namespace fiemap {
|
|||
using namespace std;
|
||||
using namespace std::string_literals;
|
||||
using namespace android::fiemap;
|
||||
using namespace android::storage_literals;
|
||||
using unique_fd = android::base::unique_fd;
|
||||
using LoopDevice = android::dm::LoopDevice;
|
||||
|
||||
|
@ -427,90 +432,123 @@ TEST_F(SplitFiemapTest, WritePastEnd) {
|
|||
ASSERT_FALSE(ptr->Write(buffer.get(), kSize));
|
||||
}
|
||||
|
||||
class VerifyBlockWritesExt4 : public ::testing::Test {
|
||||
// Get max file size and free space.
|
||||
std::pair<uint64_t, uint64_t> GetBigFileLimit(const std::string& mount_point) {
|
||||
struct statvfs fs;
|
||||
if (statvfs(mount_point.c_str(), &fs) < 0) {
|
||||
PLOG(ERROR) << "statfs failed";
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
auto fs_limit = static_cast<uint64_t>(fs.f_blocks) * (fs.f_bsize - 1);
|
||||
auto fs_free = static_cast<uint64_t>(fs.f_bfree) * fs.f_bsize;
|
||||
|
||||
LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free;
|
||||
|
||||
return {fs_limit, fs_free};
|
||||
}
|
||||
|
||||
class FsTest : public ::testing::Test {
|
||||
protected:
|
||||
// 2GB Filesystem and 4k block size by default
|
||||
static constexpr uint64_t block_size = 4096;
|
||||
static constexpr uint64_t fs_size = 2147483648;
|
||||
static constexpr uint64_t fs_size = 64 * 1024 * 1024;
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
fs_path = std::string(getenv("TMPDIR")) + "/ext4_2G.img";
|
||||
void SetUp() {
|
||||
android::fs_mgr::Fstab fstab;
|
||||
ASSERT_TRUE(android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab));
|
||||
|
||||
ASSERT_EQ(access(tmpdir_.path, F_OK), 0);
|
||||
fs_path_ = tmpdir_.path + "/fs_image"s;
|
||||
mntpoint_ = tmpdir_.path + "/mnt_point"s;
|
||||
|
||||
auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data");
|
||||
ASSERT_NE(entry, nullptr);
|
||||
if (entry->fs_type == "ext4") {
|
||||
SetUpExt4();
|
||||
} else if (entry->fs_type == "f2fs") {
|
||||
SetUpF2fs();
|
||||
} else {
|
||||
FAIL() << "Unrecognized fs_type: " << entry->fs_type;
|
||||
}
|
||||
}
|
||||
|
||||
void SetUpExt4() {
|
||||
uint64_t count = fs_size / block_size;
|
||||
std::string dd_cmd =
|
||||
::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64
|
||||
" count=%" PRIu64 " > /dev/null 2>&1",
|
||||
fs_path.c_str(), block_size, count);
|
||||
fs_path_.c_str(), block_size, count);
|
||||
std::string mkfs_cmd =
|
||||
::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path.c_str());
|
||||
::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path_.c_str());
|
||||
// create mount point
|
||||
mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt";
|
||||
ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0);
|
||||
ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0);
|
||||
// create file for the file system
|
||||
int ret = system(dd_cmd.c_str());
|
||||
ASSERT_EQ(ret, 0);
|
||||
// Get and attach a loop device to the filesystem we created
|
||||
LoopDevice loop_dev(fs_path, 10s);
|
||||
LoopDevice loop_dev(fs_path_, 10s);
|
||||
ASSERT_TRUE(loop_dev.valid());
|
||||
// create file system
|
||||
ret = system(mkfs_cmd.c_str());
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
// mount the file system
|
||||
ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "ext4", 0, nullptr), 0);
|
||||
ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "ext4", 0, nullptr), 0);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
umount(mntpoint.c_str());
|
||||
rmdir(mntpoint.c_str());
|
||||
unlink(fs_path.c_str());
|
||||
}
|
||||
|
||||
std::string mntpoint;
|
||||
std::string fs_path;
|
||||
};
|
||||
|
||||
class VerifyBlockWritesF2fs : public ::testing::Test {
|
||||
// 2GB Filesystem and 4k block size by default
|
||||
static constexpr uint64_t block_size = 4096;
|
||||
static constexpr uint64_t fs_size = 2147483648;
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
fs_path = std::string(getenv("TMPDIR")) + "/f2fs_2G.img";
|
||||
void SetUpF2fs() {
|
||||
uint64_t count = fs_size / block_size;
|
||||
std::string dd_cmd =
|
||||
::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64
|
||||
" count=%" PRIu64 " > /dev/null 2>&1",
|
||||
fs_path.c_str(), block_size, count);
|
||||
fs_path_.c_str(), block_size, count);
|
||||
std::string mkfs_cmd =
|
||||
::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path.c_str());
|
||||
::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path_.c_str());
|
||||
// create mount point
|
||||
mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt";
|
||||
ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0);
|
||||
ASSERT_EQ(mkdir(mntpoint_.c_str(), S_IRWXU), 0);
|
||||
// create file for the file system
|
||||
int ret = system(dd_cmd.c_str());
|
||||
ASSERT_EQ(ret, 0);
|
||||
// Get and attach a loop device to the filesystem we created
|
||||
LoopDevice loop_dev(fs_path, 10s);
|
||||
LoopDevice loop_dev(fs_path_, 10s);
|
||||
ASSERT_TRUE(loop_dev.valid());
|
||||
// create file system
|
||||
ret = system(mkfs_cmd.c_str());
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
// mount the file system
|
||||
ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "f2fs", 0, nullptr), 0);
|
||||
ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
umount(mntpoint.c_str());
|
||||
rmdir(mntpoint.c_str());
|
||||
unlink(fs_path.c_str());
|
||||
umount(mntpoint_.c_str());
|
||||
rmdir(mntpoint_.c_str());
|
||||
unlink(fs_path_.c_str());
|
||||
}
|
||||
|
||||
std::string mntpoint;
|
||||
std::string fs_path;
|
||||
TemporaryDir tmpdir_;
|
||||
std::string mntpoint_;
|
||||
std::string fs_path_;
|
||||
};
|
||||
|
||||
TEST_F(FsTest, LowSpaceError) {
|
||||
auto limits = GetBigFileLimit(mntpoint_);
|
||||
ASSERT_GE(limits.first, 0);
|
||||
|
||||
FiemapUniquePtr ptr;
|
||||
|
||||
auto test_file = mntpoint_ + "/big_file";
|
||||
auto status = FiemapWriter::Open(test_file, limits.first, &ptr);
|
||||
ASSERT_FALSE(status.is_ok());
|
||||
ASSERT_EQ(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE);
|
||||
|
||||
// Also test for EFBIG.
|
||||
status = FiemapWriter::Open(test_file, 16_TiB, &ptr);
|
||||
ASSERT_FALSE(status.is_ok());
|
||||
ASSERT_NE(status.error_code(), FiemapStatus::ErrorCode::NO_SPACE);
|
||||
}
|
||||
|
||||
bool DetermineBlockSize() {
|
||||
struct statfs s;
|
||||
if (statfs(gTestDir.c_str(), &s)) {
|
||||
|
|
|
@ -2372,60 +2372,6 @@ TEST_F(SnapshotUpdateTest, Overflow) {
|
|||
<< "FinishedSnapshotWrites should detect overflow of CoW device.";
|
||||
}
|
||||
|
||||
// Get max file size and free space.
|
||||
std::pair<uint64_t, uint64_t> GetBigFileLimit() {
|
||||
struct statvfs fs;
|
||||
if (statvfs("/data", &fs) < 0) {
|
||||
PLOG(ERROR) << "statfs failed";
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
auto fs_limit = static_cast<uint64_t>(fs.f_blocks) * (fs.f_bsize - 1);
|
||||
auto fs_free = static_cast<uint64_t>(fs.f_bfree) * fs.f_bsize;
|
||||
|
||||
LOG(INFO) << "Big file limit: " << fs_limit << ", free space: " << fs_free;
|
||||
|
||||
return {fs_limit, fs_free};
|
||||
}
|
||||
|
||||
TEST_F(SnapshotUpdateTest, LowSpace) {
|
||||
// To make the low space test more reliable, we force a large cow estimate.
|
||||
// However legacy VAB ignores the COW estimate and uses InstallOperations
|
||||
// to compute the exact size required for dm-snapshot. It's difficult to
|
||||
// make this work reliably (we'd need to somehow fake an extremely large
|
||||
// super partition, and we don't have that level of dependency injection).
|
||||
//
|
||||
// For now, just skip this test on legacy VAB.
|
||||
if (!snapuserd_required_) {
|
||||
GTEST_SKIP() << "Skipping test on legacy VAB";
|
||||
}
|
||||
|
||||
auto fs = GetBigFileLimit();
|
||||
ASSERT_NE(fs.first, 0);
|
||||
|
||||
constexpr uint64_t partition_size = 10_MiB;
|
||||
SetSize(sys_, partition_size);
|
||||
SetSize(vnd_, partition_size);
|
||||
SetSize(prd_, partition_size);
|
||||
sys_->set_estimate_cow_size(fs.first);
|
||||
vnd_->set_estimate_cow_size(fs.first);
|
||||
prd_->set_estimate_cow_size(fs.first);
|
||||
|
||||
AddOperationForPartitions();
|
||||
|
||||
// Execute the update.
|
||||
ASSERT_TRUE(sm->BeginUpdate());
|
||||
auto res = sm->CreateUpdateSnapshots(manifest_);
|
||||
ASSERT_FALSE(res);
|
||||
ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code());
|
||||
|
||||
// It's hard to predict exactly how much free space is needed, since /data
|
||||
// is writable and the test is not the only process running. Divide by two
|
||||
// as a rough lower bound, and adjust this in the future as necessary.
|
||||
auto expected_delta = fs.first - fs.second;
|
||||
ASSERT_GE(res.required_size(), expected_delta / 2);
|
||||
}
|
||||
|
||||
TEST_F(SnapshotUpdateTest, AddPartition) {
|
||||
group_->add_partition_names("dlkm");
|
||||
|
||||
|
@ -2796,38 +2742,6 @@ INSTANTIATE_TEST_SUITE_P(Snapshot, FlashAfterUpdateTest, Combine(Values(0, 1), B
|
|||
"Merge"s;
|
||||
});
|
||||
|
||||
class ImageManagerTest : public SnapshotTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
SKIP_IF_NON_VIRTUAL_AB();
|
||||
SnapshotTest::SetUp();
|
||||
}
|
||||
void TearDown() override {
|
||||
RETURN_IF_NON_VIRTUAL_AB();
|
||||
CleanUp();
|
||||
SnapshotTest::TearDown();
|
||||
}
|
||||
void CleanUp() {
|
||||
if (!image_manager_) {
|
||||
return;
|
||||
}
|
||||
EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
|
||||
image_manager_->DeleteBackingImage(kImageName));
|
||||
}
|
||||
|
||||
static constexpr const char* kImageName = "my_image";
|
||||
};
|
||||
|
||||
TEST_F(ImageManagerTest, CreateImageNoSpace) {
|
||||
auto fs = GetBigFileLimit();
|
||||
ASSERT_NE(fs.first, 0);
|
||||
|
||||
auto res = image_manager_->CreateBackingImage(kImageName, fs.first,
|
||||
IImageManager::CREATE_IMAGE_DEFAULT);
|
||||
ASSERT_FALSE(res);
|
||||
ASSERT_EQ(res.error_code(), FiemapStatus::ErrorCode::NO_SPACE) << res.string();
|
||||
}
|
||||
|
||||
bool Mkdir(const std::string& path) {
|
||||
if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
|
||||
std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
|
||||
|
|
|
@ -37,6 +37,7 @@ using B = Size<0>;
|
|||
using KiB = Size<10>;
|
||||
using MiB = Size<20>;
|
||||
using GiB = Size<30>;
|
||||
using TiB = Size<40>;
|
||||
|
||||
constexpr B operator""_B(unsigned long long v) { // NOLINT
|
||||
return B{v};
|
||||
|
@ -54,6 +55,10 @@ constexpr GiB operator""_GiB(unsigned long long v) { // NOLINT
|
|||
return GiB{v};
|
||||
}
|
||||
|
||||
constexpr TiB operator""_TiB(unsigned long long v) { // NOLINT
|
||||
return TiB{v};
|
||||
}
|
||||
|
||||
template <typename Dest, typename Src>
|
||||
constexpr Dest size_cast(Src src) {
|
||||
if (Src::power < Dest::power) {
|
||||
|
@ -69,6 +74,7 @@ static_assert(1_B == 1);
|
|||
static_assert(1_KiB == 1 << 10);
|
||||
static_assert(1_MiB == 1 << 20);
|
||||
static_assert(1_GiB == 1 << 30);
|
||||
static_assert(1_TiB == 1ULL << 40);
|
||||
static_assert(size_cast<KiB>(1_B).count() == 0);
|
||||
static_assert(size_cast<KiB>(1024_B).count() == 1);
|
||||
static_assert(size_cast<KiB>(1_MiB).count() == 1024);
|
||||
|
|
Loading…
Reference in a new issue