[f2fs] Enable mkfs options for f2fs
This change enables to configure mkfs options as below.
-l label
-a heap-based allocation [default: 1]
-o overprovision ratio [default: 5]
-s # of segments per section [default: 1]
-z # of sections per zone [default: 1]
-e [extension list] e.g. "mp3,gif,mov"
Test: fx test f2fs-unittest fs-tests large-fs-tests
Prerequisite:
FUCHSIA_DIR$ patch -p1 < \
third_party/f2fs/patches/0007-f2fs-Add-filesystem-specific-mkfs-option.patch
Change-Id: Ibd944e9b4638f0ba122572355dd2e5eca3520094
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/f2fs/+/543302
Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/f2fs.cc b/f2fs.cc
index b120c87..40f31df 100644
--- a/f2fs.cc
+++ b/f2fs.cc
@@ -56,12 +56,6 @@
kBlockSize);
}
-zx_status_t Mkfs(const MkfsOptions& options, std::unique_ptr<f2fs::Bcache> bc) {
- F2fsMkfs mkfs(std::move(bc), options);
-
- return mkfs.Mkfs();
-}
-
zx_status_t Fsck(const MountOptions& options, std::unique_ptr<f2fs::Bcache> bc) { return ZX_OK; }
F2fs::F2fs(std::unique_ptr<f2fs::Bcache> bc, SuperBlock* sb, const MountOptions& mount_options)
diff --git a/f2fs.h b/f2fs.h
index c8edf22..fcdf6d2 100644
--- a/f2fs.h
+++ b/f2fs.h
@@ -65,12 +65,12 @@
kExportDirectory
};
-zx_status_t Mkfs(const MkfsOptions &options, std::unique_ptr<f2fs::Bcache> bc);
zx_status_t Fsck(const MountOptions &options, std::unique_ptr<f2fs::Bcache> bc);
zx_status_t Mount(const MountOptions &options, std::unique_ptr<f2fs::Bcache> bc);
zx_status_t CreateBcache(std::unique_ptr<block_client::BlockDevice> device, bool *out_readonly,
std::unique_ptr<f2fs::Bcache> *out);
+zx_status_t LoadSuperblock(f2fs::Bcache *bc, SuperBlock *out_info);
using SyncCallback = fs::Vnode::SyncCallback;
diff --git a/file.cc b/file.cc
index 98029f5..654f3d3 100644
--- a/file.cc
+++ b/file.cc
@@ -399,8 +399,8 @@
// If it fails with any reasons such as no space/memory,
// every data_pages[less than index] is released, and DoWrite() returns with the err code.
for (uint64_t m = 0; m < index; m++) {
- if (data_pages[m] != nullptr)
- F2fsPutPage(data_pages[m], 1);
+ if (data_pages[m] != nullptr)
+ F2fsPutPage(data_pages[m], 1);
}
*out_actual = 0;
diff --git a/mkfs.cc b/mkfs.cc
index 8fcb2b8..8c99f7f 100644
--- a/mkfs.cc
+++ b/mkfs.cc
@@ -2,45 +2,117 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <getopt.h>
+
+#include <cmath>
#include <codecvt>
#include "f2fs.h"
#include "src/lib/uuid/uuid.h"
+#include <lib/syslog/cpp/macros.h>
namespace f2fs {
-const char *kMediaExtList[] = {"jpg", "gif", "png", "avi", "divx", "mp4", "mp3", "3gp",
- "wmv", "wma", "mpeg", "mkv", "mov", "asx", "asf", "wmx",
- "svi", "wvx", "wm", "mpg", "mpe", "rm", "ogg"};
+MkfsWorker::MkfsWorker(Bcache *bc) : bc_(bc) {}
-F2fsMkfs::F2fsMkfs(std::unique_ptr<f2fs::Bcache> bc, const MkfsOptions &mkfs_options)
- : bc_(std::move(bc)), mkfs_options_(mkfs_options) {}
+void MkfsWorker::PrintUsage() {
+ fprintf(stderr, "Usage: mkfs -p \"[OPTIONS]\" devicepath f2fs\n");
+ fprintf(stderr, "[OPTIONS]\n");
+ fprintf(stderr, " -l label\n");
+ fprintf(stderr, " -a heap-based allocation [default: 1]\n");
+ fprintf(stderr, " -o overprovision ratio [default: 5]\n");
+ fprintf(stderr, " -s # of segments per section [default: 1]\n");
+ fprintf(stderr, " -z # of sections per zone [default: 1]\n");
+ fprintf(stderr, " -e [extension list] e.g. \"mp3,gif,mov\"\n");
+ fprintf(stderr, "e.g. mkfs -p \"-l hello -a 1 -o 5 -s 1 -z 1 -e mp3,gif\" devicepath f2fs\n");
+}
-zx_status_t F2fsMkfs::Mkfs() {
- char extension_list[] = "";
+zx_status_t MkfsWorker::ParseOptions(int argc, char **argv) {
+ struct option opts[] = {
+ {"label", required_argument, nullptr, 'l'},
+ {"heap", required_argument, nullptr, 'a'},
+ {"op", required_argument, nullptr, 'o'},
+ {"seg_per_sec", required_argument, nullptr, 's'},
+ {"sec_per_zone", required_argument, nullptr, 'z'},
+ {"ext_list", required_argument, nullptr, 'e'},
+ {nullptr, 0, nullptr, 0},
+ };
+ int opt_index = -1;
+ int c = -1;
+
+ optreset = 1;
+ optind = 1;
+
+ while ((c = getopt_long(argc, argv, "l:a:o:s:z:e:", opts, &opt_index)) >= 0) {
+ switch (c) {
+ case 'l':
+ mkfs_options_.label = optarg;
+ if (strlen(mkfs_options_.label) >= sizeof(params_.vol_label)) {
+ fprintf(stderr, "ERROR: label length should be less than 16.\n");
+ return ZX_ERR_INVALID_ARGS;
+ }
+ break;
+ case 'a':
+ mkfs_options_.heap_based_allocation =
+ (static_cast<uint32_t>(strtoul(optarg, NULL, 0)) != 0);
+ break;
+ case 'o':
+ mkfs_options_.overprovision_ratio = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
+ if (mkfs_options_.overprovision_ratio == 0) {
+ fprintf(stderr, "ERROR: overprovision ratio should be larger than 0.\n");
+ return ZX_ERR_INVALID_ARGS;
+ }
+ break;
+ case 's':
+ mkfs_options_.segs_per_sec = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
+ if (mkfs_options_.segs_per_sec == 0) {
+ fprintf(stderr, "ERROR: # of segments per section should be larger than 0.\n");
+ return ZX_ERR_INVALID_ARGS;
+ }
+ break;
+ case 'z':
+ mkfs_options_.secs_per_zone = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
+ if (mkfs_options_.secs_per_zone == 0) {
+ fprintf(stderr, "ERROR: # of sections per zone should be larger than 0.\n");
+ return ZX_ERR_INVALID_ARGS;
+ }
+ break;
+ case 'e':
+ mkfs_options_.extension_list = optarg;
+ break;
+ default:
+ PrintUsage();
+ return ZX_ERR_INVALID_ARGS;
+ };
+ };
+
+ return ZX_OK;
+}
+
+void MkfsWorker::PrintCurrentOption() {
+ fprintf(stderr, "f2fs mkfs label = %s\n", mkfs_options_.label);
+ fprintf(stderr, "f2fs mkfs heap-based allocation = %d\n", mkfs_options_.heap_based_allocation);
+ fprintf(stderr, "f2fs mkfs overprovision ratio = %u\n", mkfs_options_.overprovision_ratio);
+ fprintf(stderr, "f2fs mkfs segments per sector = %u\n", mkfs_options_.segs_per_sec);
+ fprintf(stderr, "f2fs mkfs sectors per zone = %u\n", mkfs_options_.secs_per_zone);
+ fprintf(stderr, "f2fs mkfs extension list = %s\n", mkfs_options_.extension_list);
+}
+
+zx_status_t MkfsWorker::DoMkfs() {
#ifdef F2FS_BU_DEBUG
- // TODO: lable, extention list
- std::cout << "f2fs mkfs heap-based allocation = " << mkfs_options_.heap_based_allocation
- << std::endl;
- std::cout << "f2fs mkfs overprovision ratio = " << mkfs_options_.overprovision_ratio << std::endl;
- std::cout << "f2fs mkfs # of segments per section = " << mkfs_options_.num_of_seg_per_sec
- << std::endl;
- std::cout << "f2fs mkfs overprovision ratio = " << mkfs_options_.num_of_sec_per_zone << std::endl;
+ PrintCurrentOption();
#endif
- // TODO: parse mkfs options
- params_.extension_list = extension_list;
-
InitGlobalParameters();
- if (GetDeviceInfo() < 0)
- return -1;
+ if (zx_status_t ret = GetDeviceInfo(); ret != ZX_OK)
+ return ret;
- if (FormatDevice() < 0)
- return -1;
+ if (zx_status_t ret = FormatDevice(); ret != ZX_OK)
+ return ret;
- printf("Info: format successful\n");
+ fprintf(stderr, "Info: format successful\n");
return ZX_OK;
}
@@ -48,74 +120,40 @@
/*
* String must be less than 16 characters.
*/
-void F2fsMkfs::AsciiToUnicode(const std::string &in_string, std::u16string *out_string) {
+void AsciiToUnicode(const std::string &in_string, std::u16string *out_string) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> cvt16;
out_string->assign(cvt16.from_bytes(in_string));
}
-void F2fsMkfs::InitGlobalParameters() {
+void MkfsWorker::InitGlobalParameters() {
static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
params_.sector_size = kDefaultSectorSize;
params_.sectors_per_blk = kDefaultSectorsPerBlock;
params_.blks_per_seg = kDefaultBlocksPerSegment;
params_.reserved_segments = 20; /* calculated by overprovision ratio */
- params_.overprovision = 5;
- params_.segs_per_sec = 1;
- params_.secs_per_zone = 1;
- params_.heap = 1;
- memset(params_.vol_label, 0, sizeof(params_.vol_label));
+ params_.overprovision = mkfs_options_.overprovision_ratio;
+ params_.segs_per_sec = mkfs_options_.segs_per_sec;
+ params_.secs_per_zone = mkfs_options_.secs_per_zone;
+ params_.heap = (mkfs_options_.heap_based_allocation ? 1 : 0);
+ if (mkfs_options_.label != nullptr) {
+ memcpy(params_.vol_label, mkfs_options_.label, strlen(mkfs_options_.label) + 1);
+ } else {
+ memset(params_.vol_label, 0, sizeof(params_.vol_label));
- params_.vol_label[0] = 'F';
- params_.vol_label[1] = '2';
- params_.vol_label[2] = 'F';
- params_.vol_label[3] = 'S';
- params_.vol_label[4] = '\0';
+ params_.vol_label[0] = 'F';
+ params_.vol_label[1] = '2';
+ params_.vol_label[2] = 'F';
+ params_.vol_label[3] = 'S';
+ params_.vol_label[4] = '\0';
+ }
params_.device_name = nullptr;
+
+ params_.extension_list = mkfs_options_.extension_list;
}
-inline int F2fsMkfs::F2fsSetBit(uint32_t nr, uint8_t *addr) {
- int mask;
- int ret;
-
- addr += (nr >> 3);
- mask = 1 << (7 - (nr & 0x07));
- ret = mask & *addr;
- *addr |= mask;
- return ret;
-}
-
-int8_t F2fsMkfs::LogBase2(uint32_t num) {
- int8_t ret = 0;
-
- if (num <= 0 || (num & (num - 1)) != 0) {
- return -1;
- }
-
- while (num >>= 1) {
- ret++;
- }
-
- return ret;
-}
-
-#if 0 // porting needed
-void F2fsMkfs::f2fs_usage(void)
-{
- fprintf(stderr, "Usage: f2fs_format [options] device\n");
- fprintf(stderr, "[options]\n");
- fprintf(stderr, "-l label\n");
- fprintf(stderr, "-a heap-based allocation [default:1]\n");
- fprintf(stderr, "-o overprovision ratio [default:5]\n");
- fprintf(stderr, "-s # of segments per section [default:1]\n");
- fprintf(stderr, "-z # of sections per zone [default:1]\n");
- fprintf(stderr, "-e [extension list] e.g. \"mp3,gif,mov\"\n");
- exit(1);
-}
-#endif
-
-zx_status_t F2fsMkfs::GetDeviceInfo() {
+zx_status_t MkfsWorker::GetDeviceInfo() {
fuchsia_hardware_block_BlockInfo info;
bc_->device()->BlockGetInfo(&info);
@@ -128,52 +166,45 @@
params_.start_sector = kSuperblockStart;
if (params_.total_sectors < (kMinVolumeSize / kDefaultSectorSize)) {
- printf("Error: Min volume size supported is %d\n", kMinVolumeSize);
+ fprintf(stderr, "Error: Min volume size supported is %d\n", kMinVolumeSize);
return ZX_ERR_NO_RESOURCES;
}
return ZX_OK;
}
-void F2fsMkfs::ConfigureExtensionList() {
+void MkfsWorker::ConfigureExtensionList() {
char *ext_str = params_.extension_list;
- char *ue;
- int name_len;
- int i = 0;
super_block_.extension_count = 0;
memset(super_block_.extension_list, 0, sizeof(super_block_.extension_list));
+ int name_len;
+ int i = 0;
+
for (const char *ext : kMediaExtList) {
name_len = static_cast<int>(strlen(ext));
memcpy(super_block_.extension_list[i++], ext, name_len);
}
- super_block_.extension_count = i - 1;
+ super_block_.extension_count = i;
if (!ext_str)
return;
/* add user ext list */
- ue = strtok(ext_str, ",");
+ char *ue = strtok(ext_str, ",");
while (ue != nullptr) {
name_len = static_cast<int>(strlen(ue));
memcpy(super_block_.extension_list[i++], ue, name_len);
ue = strtok(nullptr, ",");
- if (i > kMaxExtension)
+ if (i >= kMaxExtension)
break;
}
- super_block_.extension_count = i - 1;
-#if 0 // porting needed
- // TODO: strdup in f2fs_parse_options
- // free(params_.extension_list);
-#endif
+ super_block_.extension_count = i;
}
-zx_status_t F2fsMkfs::WriteToDisk(void *buf, uint64_t offset, size_t length) {
- zx_status_t status = 0;
- uint64_t curr_offset = offset;
-
+zx_status_t MkfsWorker::WriteToDisk(void *buf, uint64_t offset, size_t length) {
#ifdef F2FS_BU_DEBUG
std::cout << std::hex << "writetodeisk: offset= 0x" << offset << " length= 0x" << length
<< std::endl;
@@ -191,6 +222,9 @@
return ZX_ERR_INVALID_ARGS;
}
+ zx_status_t status = ZX_OK;
+ uint64_t curr_offset = offset;
+
for (uint64_t i = 0; i < length / kBlockSize; i++) {
if ((status = bc_->Writeblk((offset / kBlockSize) + i, buf)) != ZX_OK) {
std::cout << "mkfs: Failed to write root directory: " << status << std::endl;
@@ -204,26 +238,17 @@
return status;
}
-zx_status_t F2fsMkfs::PrepareSuperBlock() {
- uint32_t blk_size_bytes;
- uint32_t log_sectorsize, log_sectors_per_block;
- uint32_t log_blocksize, log_blks_per_seg;
- uint32_t segment_size_bytes, zone_size_bytes;
- uint32_t sit_segments;
- uint32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
- uint32_t total_valid_blks_available;
- uint64_t zone_align_start_offset, diff, total_meta_segments;
- uint32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments;
- uint32_t total_zones;
-
+zx_status_t MkfsWorker::PrepareSuperBlock() {
super_block_.magic = CpuToLe(uint32_t{kF2fsSuperMagic});
super_block_.major_ver = CpuToLe(kMajorVersion);
super_block_.minor_ver = CpuToLe(kMinorVersion);
- log_sectorsize = LogBase2(params_.sector_size);
- log_sectors_per_block = LogBase2(params_.sectors_per_blk);
- log_blocksize = log_sectorsize + log_sectors_per_block;
- log_blks_per_seg = LogBase2(params_.blks_per_seg);
+ uint32_t log_sectorsize = static_cast<uint32_t>(log2(static_cast<double>(params_.sector_size)));
+ uint32_t log_sectors_per_block =
+ static_cast<uint32_t>(log2(static_cast<double>(params_.sectors_per_blk)));
+ uint32_t log_blocksize = log_sectorsize + log_sectors_per_block;
+ uint32_t log_blks_per_seg =
+ static_cast<uint32_t>(log2(static_cast<double>(params_.blks_per_seg)));
super_block_.log_sectorsize = CpuToLe(log_sectorsize);
@@ -249,16 +274,16 @@
super_block_.segs_per_sec = CpuToLe(params_.segs_per_sec);
super_block_.secs_per_zone = CpuToLe(params_.secs_per_zone);
- blk_size_bytes = 1 << log_blocksize;
- segment_size_bytes = blk_size_bytes * params_.blks_per_seg;
- zone_size_bytes =
+ uint32_t blk_size_bytes = 1 << log_blocksize;
+ uint32_t segment_size_bytes = blk_size_bytes * params_.blks_per_seg;
+ uint32_t zone_size_bytes =
blk_size_bytes * params_.secs_per_zone * params_.segs_per_sec * params_.blks_per_seg;
super_block_.checksum_offset = 0;
super_block_.block_count = CpuToLe((params_.total_sectors * kDefaultSectorSize) / blk_size_bytes);
- zone_align_start_offset =
+ uint64_t zone_align_start_offset =
(params_.start_sector * kDefaultSectorSize + 2 * kBlkSize + zone_size_bytes - 1) /
zone_size_bytes * zone_size_bytes -
params_.start_sector * kDefaultSectorSize;
@@ -282,10 +307,10 @@
CpuToLe(LeToCpu(super_block_.segment0_blkaddr) +
(LeToCpu(super_block_.segment_count_ckpt) * (1 << log_blks_per_seg)));
- blocks_for_sit =
+ uint32_t blocks_for_sit =
(LeToCpu(super_block_.segment_count) + kSitEntryPerBlock - 1) / kSitEntryPerBlock;
- sit_segments = (blocks_for_sit + params_.blks_per_seg - 1) / params_.blks_per_seg;
+ uint32_t sit_segments = (blocks_for_sit + params_.blks_per_seg - 1) / params_.blks_per_seg;
super_block_.segment_count_sit = CpuToLe(sit_segments * 2);
@@ -293,12 +318,13 @@
CpuToLe(LeToCpu(super_block_.sit_blkaddr) +
(LeToCpu(super_block_.segment_count_sit) * params_.blks_per_seg));
- total_valid_blks_available =
+ uint32_t total_valid_blks_available =
(LeToCpu(super_block_.segment_count) -
(LeToCpu(super_block_.segment_count_ckpt) + LeToCpu(super_block_.segment_count_sit))) *
params_.blks_per_seg;
- blocks_for_nat = (total_valid_blks_available + kNatEntryPerBlock - 1) / kNatEntryPerBlock;
+ uint32_t blocks_for_nat =
+ (total_valid_blks_available + kNatEntryPerBlock - 1) / kNatEntryPerBlock;
super_block_.segment_count_nat =
CpuToLe((blocks_for_nat + params_.blks_per_seg - 1) / params_.blks_per_seg);
@@ -307,9 +333,10 @@
* This number resizes NAT bitmap area in a CP page.
* So the threshold is determined not to overflow one CP page
*/
- sit_bitmap_size = ((LeToCpu(super_block_.segment_count_sit) / 2) << log_blks_per_seg) / 8;
- max_nat_bitmap_size = 4096 - sizeof(Checkpoint) + 1 - sit_bitmap_size;
- max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
+ uint32_t sit_bitmap_size =
+ ((LeToCpu(super_block_.segment_count_sit) / 2) << log_blks_per_seg) / 8;
+ uint32_t max_nat_bitmap_size = 4096 - sizeof(Checkpoint) + 1 - sit_bitmap_size;
+ uint32_t max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
if (LeToCpu(super_block_.segment_count_nat) > max_nat_segments)
super_block_.segment_count_nat = CpuToLe(max_nat_segments);
@@ -326,16 +353,17 @@
LeToCpu(super_block_.segment_count_nat))) *
params_.blks_per_seg;
- blocks_for_ssa = total_valid_blks_available / params_.blks_per_seg + 1;
+ uint32_t blocks_for_ssa = total_valid_blks_available / params_.blks_per_seg + 1;
super_block_.segment_count_ssa =
CpuToLe((blocks_for_ssa + params_.blks_per_seg - 1) / params_.blks_per_seg);
- total_meta_segments =
+ uint64_t total_meta_segments =
LeToCpu(super_block_.segment_count_ckpt) + LeToCpu(super_block_.segment_count_sit) +
LeToCpu(super_block_.segment_count_nat) + LeToCpu(super_block_.segment_count_ssa);
- diff = total_meta_segments % (params_.segs_per_sec * params_.secs_per_zone);
- if (diff)
+
+ if (uint64_t diff = total_meta_segments % (params_.segs_per_sec * params_.secs_per_zone);
+ diff != 0)
super_block_.segment_count_ssa = CpuToLe(LeToCpu(super_block_.segment_count_ssa) +
(params_.segs_per_sec * params_.secs_per_zone - diff));
@@ -374,8 +402,8 @@
super_block_.meta_ino = CpuToLe(uint32_t{2});
super_block_.root_ino = CpuToLe(uint32_t{3});
- total_zones = ((LeToCpu(super_block_.segment_count_main) - 1) / params_.segs_per_sec) /
- params_.secs_per_zone;
+ uint32_t total_zones = ((LeToCpu(super_block_.segment_count_main) - 1) / params_.segs_per_sec) /
+ params_.secs_per_zone;
if (total_zones <= 6) {
printf("\n\tError: %d zones: Need more zones by shrinking zone size\n", total_zones);
return ZX_ERR_NO_SPACE;
@@ -419,31 +447,23 @@
ConfigureExtensionList();
- return 0;
+ return ZX_OK;
}
-zx_status_t F2fsMkfs::InitSitArea() {
- uint32_t blk_size_bytes;
- uint32_t seg_size_bytes;
- uint32_t index = 0;
- uint64_t sit_seg_blk_offset = 0;
- uint8_t *zero_buf = nullptr;
- zx_status_t ret;
+zx_status_t MkfsWorker::InitSitArea() {
+ uint32_t blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
+ uint32_t seg_size_bytes = (1 << LeToCpu(super_block_.log_blocks_per_seg)) * blk_size_bytes;
- blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
- seg_size_bytes = (1 << LeToCpu(super_block_.log_blocks_per_seg)) * blk_size_bytes;
-
- zero_buf = static_cast<uint8_t *>(calloc(sizeof(uint8_t), seg_size_bytes));
+ uint8_t *zero_buf = static_cast<uint8_t *>(calloc(sizeof(uint8_t), seg_size_bytes));
if (zero_buf == nullptr) {
printf("\n\tError: Calloc Failed for sit_zero_buf!!!\n");
return ZX_ERR_NO_MEMORY;
}
- sit_seg_blk_offset = LeToCpu(super_block_.sit_blkaddr) * blk_size_bytes;
+ uint64_t sit_seg_blk_offset = LeToCpu(super_block_.sit_blkaddr) * blk_size_bytes;
- for (index = 0; index < (LeToCpu(super_block_.segment_count_sit) / 2); index++) {
- ret = WriteToDisk(zero_buf, sit_seg_blk_offset, seg_size_bytes);
- if (ret < 0) {
+ for (uint32_t index = 0; index < (LeToCpu(super_block_.segment_count_sit) / 2); index++) {
+ if (zx_status_t ret = WriteToDisk(zero_buf, sit_seg_blk_offset, seg_size_bytes); ret != ZX_OK) {
printf("\n\tError: While zeroing out the sit area on disk!!!\n");
return ret;
}
@@ -454,28 +474,20 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::InitNatArea() {
- uint32_t blk_size_bytes;
- uint32_t seg_size_bytes;
- uint32_t index = 0;
- uint64_t nat_seg_blk_offset = 0;
- uint8_t *nat_buf = nullptr;
- zx_status_t ret;
+zx_status_t MkfsWorker::InitNatArea() {
+ uint32_t blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
+ uint32_t seg_size_bytes = (1 << LeToCpu(super_block_.log_blocks_per_seg)) * blk_size_bytes;
- blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
- seg_size_bytes = (1 << LeToCpu(super_block_.log_blocks_per_seg)) * blk_size_bytes;
-
- nat_buf = static_cast<uint8_t *>(calloc(sizeof(uint8_t), seg_size_bytes));
+ uint8_t *nat_buf = static_cast<uint8_t *>(calloc(sizeof(uint8_t), seg_size_bytes));
if (nat_buf == nullptr) {
printf("\n\tError: Calloc Failed for nat_zero_blk!!!\n");
return ZX_ERR_NO_MEMORY;
}
- nat_seg_blk_offset = LeToCpu(super_block_.nat_blkaddr) * blk_size_bytes;
+ uint64_t nat_seg_blk_offset = LeToCpu(super_block_.nat_blkaddr) * blk_size_bytes;
- for (index = 0; index < (LeToCpu(super_block_.segment_count_nat) / 2); index++) {
- ret = WriteToDisk(nat_buf, nat_seg_blk_offset, seg_size_bytes);
- if (ret < 0) {
+ for (uint32_t index = 0; index < (LeToCpu(super_block_.segment_count_nat) / 2); index++) {
+ if (zx_status_t ret = WriteToDisk(nat_buf, nat_seg_blk_offset, seg_size_bytes); ret != ZX_OK) {
printf("\n\tError: While zeroing out the nat area on disk!!!\n");
return ret;
}
@@ -486,22 +498,14 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::WriteCheckPointPack() {
- Checkpoint *ckp = nullptr;
- SummaryBlock *sum = nullptr;
- uint32_t blk_size_bytes;
- uint64_t cp_seg_blk_offset = 0;
- uint32_t crc = 0;
- zx_status_t ret;
- int i;
-
- ckp = static_cast<Checkpoint *>(calloc(kBlkSize, 1));
+zx_status_t MkfsWorker::WriteCheckPointPack() {
+ Checkpoint *ckp = static_cast<Checkpoint *>(calloc(kBlkSize, 1));
if (ckp == nullptr) {
printf("\n\tError: Calloc Failed for Checkpoint!!!\n");
return ZX_ERR_NO_MEMORY;
}
- sum = static_cast<SummaryBlock *>(calloc(kBlkSize, 1));
+ SummaryBlock *sum = static_cast<SummaryBlock *>(calloc(kBlkSize, 1));
if (sum == nullptr) {
printf("\n\tError: Calloc Failed for summay_node!!!\n");
return ZX_ERR_NO_MEMORY;
@@ -515,7 +519,7 @@
ckp->cur_data_segno[0] = CpuToLe(params_.cur_seg[static_cast<int>(CursegType::kCursegHotData)]);
ckp->cur_data_segno[1] = CpuToLe(params_.cur_seg[static_cast<int>(CursegType::kCursegWarmData)]);
ckp->cur_data_segno[2] = CpuToLe(params_.cur_seg[static_cast<int>(CursegType::kCursegColdData)]);
- for (i = 3; i < kMaxActiveNodeLogs; i++) {
+ for (int i = 3; i < kMaxActiveNodeLogs; i++) {
ckp->cur_node_segno[i] = 0xffffffff;
ckp->cur_data_segno[i] = 0xffffffff;
}
@@ -554,15 +558,14 @@
ckp->checksum_offset = CpuToLe(uint32_t{kChecksumOffset});
- crc = F2fsCalCrc32(kF2fsSuperMagic, ckp, LeToCpu(ckp->checksum_offset));
+ uint32_t crc = F2fsCalCrc32(kF2fsSuperMagic, ckp, LeToCpu(ckp->checksum_offset));
*(reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(ckp) +
LeToCpu(ckp->checksum_offset))) = crc;
- blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
- cp_seg_blk_offset = LeToCpu(super_block_.segment0_blkaddr) * blk_size_bytes;
+ uint32_t blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
+ uint64_t cp_seg_blk_offset = LeToCpu(super_block_.segment0_blkaddr) * blk_size_bytes;
- ret = WriteToDisk(ckp, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(ckp, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the ckp to disk!!!\n");
return ret;
}
@@ -575,8 +578,7 @@
sum->entries[0].ofs_in_node = 0;
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the sum_blk to disk!!!\n");
return ret;
}
@@ -586,8 +588,7 @@
SetSumType((&sum->footer), kSumTypeData);
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the sum_blk to disk!!!\n");
return ret;
}
@@ -601,7 +602,7 @@
sum->sit_j.entries[0].segno = ckp->cur_node_segno[0];
sum->sit_j.entries[0].se.vblocks =
CpuToLe(uint16_t{(static_cast<int>(CursegType::kCursegHotNode) << 10) | 1});
- F2fsSetBit(0, sum->sit_j.entries[0].se.valid_map);
+ f2fs_set_bit(0, reinterpret_cast<char *>(sum->sit_j.entries[0].se.valid_map));
sum->sit_j.entries[1].segno = ckp->cur_node_segno[1];
sum->sit_j.entries[1].se.vblocks =
CpuToLe(uint16_t{(static_cast<int>(CursegType::kCursegWarmNode) << 10)});
@@ -613,7 +614,7 @@
sum->sit_j.entries[3].segno = ckp->cur_data_segno[0];
sum->sit_j.entries[3].se.vblocks =
CpuToLe(uint16_t{(static_cast<uint16_t>(CursegType::kCursegHotData) << 10) | 1});
- F2fsSetBit(0, sum->sit_j.entries[3].se.valid_map);
+ f2fs_set_bit(0, reinterpret_cast<char *>(sum->sit_j.entries[3].se.valid_map));
sum->sit_j.entries[4].segno = ckp->cur_data_segno[1];
sum->sit_j.entries[4].se.vblocks =
CpuToLe(uint16_t{(static_cast<int>(CursegType::kCursegWarmData) << 10)});
@@ -622,8 +623,7 @@
CpuToLe(uint16_t{(static_cast<int>(CursegType::kCursegColdData) << 10)});
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the sum_blk to disk!!!\n");
return ret;
}
@@ -636,8 +636,7 @@
sum->entries[0].ofs_in_node = 0;
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the sum_blk to disk!!!\n");
return ret;
}
@@ -647,8 +646,7 @@
SetSumType((&sum->footer), kSumTypeNode);
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the sum_blk to disk!!!\n");
return ret;
}
@@ -657,16 +655,14 @@
memset(sum, 0, sizeof(SummaryBlock));
SetSumType((&sum->footer), kSumTypeNode);
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(sum, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the sum_blk to disk!!!\n");
return ret;
}
/* 8. cp page2 */
cp_seg_blk_offset += blk_size_bytes;
- ret = WriteToDisk(ckp, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(ckp, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the ckp to disk!!!\n");
return ret;
}
@@ -682,8 +678,7 @@
cp_seg_blk_offset =
(LeToCpu(super_block_.segment0_blkaddr) + params_.blks_per_seg) * blk_size_bytes;
- ret = WriteToDisk(ckp, cp_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(ckp, cp_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the ckp to disk!!!\n");
return ret;
}
@@ -693,18 +688,13 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::WriteSuperBlock() {
- uint32_t index = 0;
- uint8_t *zero_buff;
- zx_status_t ret;
-
- zero_buff = static_cast<uint8_t *>(calloc(kBlkSize, 1));
+zx_status_t MkfsWorker::WriteSuperBlock() {
+ uint8_t *zero_buff = static_cast<uint8_t *>(calloc(kBlkSize, 1));
memcpy(zero_buff + kSuperOffset, &super_block_, sizeof(super_block_));
- for (index = 0; index < 2; index++) {
- ret = WriteToDisk(zero_buff, index * kBlkSize, kBlkSize);
- if (ret < 0) {
+ for (uint32_t index = 0; index < 2; index++) {
+ if (zx_status_t ret = WriteToDisk(zero_buff, index * kBlkSize, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While while writing supe_blk on disk!!! index : %d\n", index);
return ret;
}
@@ -714,14 +704,8 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::WriteRootInode() {
- Node *raw_node = nullptr;
- uint32_t blk_size_bytes;
- uint64_t data_blk_nor;
- uint64_t main_area_node_seg_blk_offset = 0;
- zx_status_t ret;
-
- raw_node = static_cast<Node *>(calloc(kBlkSize, 1));
+zx_status_t MkfsWorker::WriteRootInode() {
+ Node *raw_node = static_cast<Node *>(calloc(kBlkSize, 1));
if (raw_node == nullptr) {
printf("\n\tError: Calloc Failed for raw_node!!!\n");
return ZX_ERR_NO_MEMORY;
@@ -739,7 +723,7 @@
raw_node->i.i_uid = CpuToLe(getuid());
raw_node->i.i_gid = CpuToLe(getgid());
- blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
+ uint32_t blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
raw_node->i.i_size = CpuToLe(1 * blk_size_bytes); /* dentry */
raw_node->i.i_blocks = CpuToLe(uint64_t{2});
@@ -756,7 +740,7 @@
raw_node->i.i_flags = 0;
raw_node->i.i_current_depth = CpuToLe(uint32_t{1});
- data_blk_nor =
+ uint64_t data_blk_nor =
LeToCpu(super_block_.main_blkaddr) +
params_.cur_seg[static_cast<int>(CursegType::kCursegHotData)] * params_.blks_per_seg;
raw_node->i.i_addr[0] = CpuToLe(data_blk_nor);
@@ -765,21 +749,21 @@
raw_node->i.i_ext.blk_addr = CpuToLe(data_blk_nor);
raw_node->i.i_ext.len = CpuToLe(uint32_t{1});
- main_area_node_seg_blk_offset = LeToCpu(super_block_.main_blkaddr);
+ uint64_t main_area_node_seg_blk_offset = LeToCpu(super_block_.main_blkaddr);
main_area_node_seg_blk_offset +=
params_.cur_seg[static_cast<int>(CursegType::kCursegHotNode)] * params_.blks_per_seg;
main_area_node_seg_blk_offset *= blk_size_bytes;
- ret = WriteToDisk(raw_node, main_area_node_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(raw_node, main_area_node_seg_blk_offset, kBlkSize);
+ ret != ZX_OK) {
printf("\n\tError: While writing the raw_node to disk!!!, size = %lu\n", sizeof(Node));
return ret;
}
memset(raw_node, 0xff, sizeof(Node));
- ret = WriteToDisk(raw_node, main_area_node_seg_blk_offset + 4096, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(raw_node, main_area_node_seg_blk_offset + 4096, kBlkSize);
+ ret != ZX_OK) {
printf("\n\tError: While writing the raw_node to disk!!!\n");
return ret;
}
@@ -787,13 +771,8 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::UpdateNatRoot() {
- NatBlock *nat_blk = nullptr;
- uint32_t blk_size_bytes;
- uint64_t nat_seg_blk_offset = 0;
- zx_status_t ret;
-
- nat_blk = static_cast<NatBlock *>(calloc(kBlkSize, 1));
+zx_status_t MkfsWorker::UpdateNatRoot() {
+ NatBlock *nat_blk = static_cast<NatBlock *>(calloc(kBlkSize, 1));
if (nat_blk == nullptr) {
printf("\n\tError: Calloc Failed for nat_blk!!!\n");
return ZX_ERR_NO_MEMORY;
@@ -813,12 +792,11 @@
nat_blk->entries[super_block_.meta_ino].block_addr = CpuToLe(uint32_t{1});
nat_blk->entries[super_block_.meta_ino].ino = super_block_.meta_ino;
- blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
+ uint32_t blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
- nat_seg_blk_offset = LeToCpu(super_block_.nat_blkaddr) * blk_size_bytes;
+ uint64_t nat_seg_blk_offset = LeToCpu(super_block_.nat_blkaddr) * blk_size_bytes;
- ret = WriteToDisk(nat_blk, nat_seg_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(nat_blk, nat_seg_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the nat_blk set0 to disk!!!\n");
return ret;
}
@@ -827,13 +805,8 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::AddDefaultDentryRoot() {
- DentryBlock *dent_blk = nullptr;
- uint32_t blk_size_bytes;
- uint64_t data_blk_offset = 0;
- zx_status_t ret;
-
- dent_blk = static_cast<DentryBlock *>(calloc(kBlkSize, 1));
+zx_status_t MkfsWorker::AddDefaultDentryRoot() {
+ DentryBlock *dent_blk = static_cast<DentryBlock *>(calloc(kBlkSize, 1));
if (dent_blk == nullptr) {
printf("\n\tError: Calloc Failed for dent_blk!!!\n");
return ZX_ERR_NO_MEMORY;
@@ -853,14 +826,13 @@
/* bitmap for . and .. */
dent_blk->dentry_bitmap[0] = (1 << 1) | (1 << 0);
- blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
- data_blk_offset =
+ uint32_t blk_size_bytes = 1 << LeToCpu(super_block_.log_blocksize);
+ uint64_t data_blk_offset =
(LeToCpu(super_block_.main_blkaddr) +
params_.cur_seg[static_cast<int>(CursegType::kCursegHotData)] * params_.blks_per_seg) *
blk_size_bytes;
- ret = WriteToDisk(dent_blk, data_blk_offset, kBlkSize);
- if (ret < 0) {
+ if (zx_status_t ret = WriteToDisk(dent_blk, data_blk_offset, kBlkSize); ret != ZX_OK) {
printf("\n\tError: While writing the dentry_blk to disk!!!\n");
return ret;
}
@@ -869,35 +841,26 @@
return ZX_OK;
}
-zx_status_t F2fsMkfs::CreateRootDir() {
- int8_t err = 0;
-
- err = WriteRootInode();
- if (err < 0) {
- printf("\n\tError: Failed to write root inode!!!\n");
- goto exit;
+zx_status_t MkfsWorker::CreateRootDir() {
+ zx_status_t err = ZX_OK;
+ const char err_msg[] = "Error creating root directry: ";
+ if (err = WriteRootInode(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to write root inode" << err;
+ return err;
}
-
- err = UpdateNatRoot();
- if (err < 0) {
- printf("\n\tError: Failed to update NAT for root!!!\n");
- goto exit;
+ if (err = UpdateNatRoot(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to update NAT for root" << err;
+ return err;
}
-
- err = AddDefaultDentryRoot();
- if (err < 0) {
- printf("\n\tError: Failed to add default dentries for root!!!\n");
- goto exit;
+ if (err = AddDefaultDentryRoot(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to add default dentries for root" << err;
+ return err;
}
-exit:
- if (err)
- printf("\n\tError: Could not create the root directory!!!\n");
-
return err;
}
#if 0 // porting needed
-// int F2fsMkfs::F2fsTrimDevice()
+// int MkfsWorker::F2fsTrimDevice()
// {
// uint64_t range[2];
// stat stat_buf;
@@ -921,53 +884,45 @@
// }
#endif
-zx_status_t F2fsMkfs::FormatDevice() {
- zx_status_t err = 0;
-
- err = PrepareSuperBlock();
- if (err < 0)
- goto exit;
-
+zx_status_t MkfsWorker::FormatDevice() {
+ zx_status_t err = ZX_OK;
+ const char err_msg[] = "Error formatting the device: ";
+ if (err = PrepareSuperBlock(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to prepare superblock information";
+ return err;
+ }
#if 0 // porting needed
- // TRIM is not supported
- // err = f2fs_trim_device();
- // if (err < 0) {
- // printf("\n\tError: Failed to trim whole device!!!\n");
- // goto exit;
- // }
+ // TRIM is not supported
+ // err = f2fs_trim_device();
+ // if (err < 0) {
+ // printf("\n\tError: Failed to trim whole device!!!\n");
+ // break;
+ // }
#endif
- err = InitSitArea();
- if (err < 0) {
- printf("\n\tError: Failed to Initialise the SIT AREA!!!\n");
- goto exit;
+ if (err = InitSitArea(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to Initialise the SIT AREA" << err;
+ return err;
}
- err = InitNatArea();
- if (err < 0) {
- printf("\n\tError: Failed to Initialise the NAT AREA!!!\n");
- goto exit;
+ if (err = InitNatArea(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to Initialise the NAT AREA" << err;
+ return err;
}
- err = CreateRootDir();
- if (err < 0) {
- printf("\n\tError: Failed to create the root directory!!!\n");
- goto exit;
+ if (err = CreateRootDir(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to create the root directory" << err;
+ return err;
}
- err = WriteCheckPointPack();
- if (err < 0) {
- printf("\n\tError: Failed to write the check point pack!!!\n");
- goto exit;
+ if (err = WriteCheckPointPack(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to write the check point pack" << err;
+ return err;
}
- err = WriteSuperBlock();
- if (err < 0) {
- printf("\n\tError: Failed to write the Super Block!!!\n");
- goto exit;
+ if (err = WriteSuperBlock(); err != ZX_OK) {
+ FX_LOGS(ERROR) << err_msg << "Failed to write the Super Block" << err;
+ return err;
}
-exit:
- if (err)
- printf("\n\tError: Could not format the device!!!\n");
/*
* We should call fsync() to flush out all the dirty pages
@@ -978,4 +933,14 @@
return err;
}
+zx_status_t Mkfs(Bcache *bc, int argc, char **argv) {
+ MkfsWorker mkfs(bc);
+
+ if (zx_status_t ret = mkfs.ParseOptions(argc, argv); ret != ZX_OK) {
+ return ret;
+ }
+
+ return mkfs.DoMkfs();
+}
+
} // namespace f2fs
diff --git a/mkfs.h b/mkfs.h
index 22f69eb..f5bc25c 100644
--- a/mkfs.h
+++ b/mkfs.h
@@ -8,38 +8,32 @@
namespace f2fs {
constexpr uint32_t kChecksumOffset = 4092;
-struct MkfsOptions {
- // TODO: Add mkfs options
- /*
- Usage: mkfs.f2fs [options] device [sectors]
- [options]:
- -l label
- -a heap-based allocation [default:0]
- -o overprovision ratio [default:5]
- -s # of segments per section [default:1]
- -z # of sections per zone [default:1]
- -e [extention list] e.g. "mp3,gif,mov"
- */
+static const char* kMediaExtList[] = {"jpg", "gif", "png", "avi", "divx", "mp4", "mp3", "3gp",
+ "wmv", "wma", "mpeg", "mkv", "mov", "asx", "asf", "wmx",
+ "svi", "wvx", "wm", "mpg", "mpe", "rm", "ogg"};
+
+struct MkfsOptions {
char* label = nullptr;
- bool heap_based_allocation = false;
+ bool heap_based_allocation = true;
uint32_t overprovision_ratio = 5;
- uint32_t num_of_seg_per_sec = 1;
- uint32_t num_of_sec_per_zone = 1;
- char* extention_list = nullptr;
+ uint32_t segs_per_sec = 1;
+ uint32_t secs_per_zone = 1;
+ char* extension_list = nullptr;
};
-class F2fsMkfs {
+class MkfsWorker {
public:
- explicit F2fsMkfs(std::unique_ptr<f2fs::Bcache> bc, const MkfsOptions& mkfs_options);
+ explicit MkfsWorker(Bcache* bc);
- ~F2fsMkfs() = default;
+ ~MkfsWorker() = default;
- zx_status_t Mkfs();
+ zx_status_t DoMkfs();
+ zx_status_t ParseOptions(int argc, char** argv);
private:
- std::unique_ptr<f2fs::Bcache> bc_;
- [[maybe_unused]] const MkfsOptions& mkfs_options_;
+ Bcache* bc_;
+ MkfsOptions mkfs_options_;
// F2FS Parameter
GlobalParameters params_;
@@ -49,10 +43,6 @@
zx_status_t GetDeviceInfo();
zx_status_t FormatDevice();
- void AsciiToUnicode(const std::string& in_string, std::u16string* out_string);
-
- inline int F2fsSetBit(uint32_t nr, uint8_t* addr);
- int8_t LogBase2(uint32_t num);
void ConfigureExtensionList();
zx_status_t WriteToDisk(void* buf, uint64_t offset, size_t length);
@@ -68,12 +58,19 @@
zx_status_t AddDefaultDentryRoot();
zx_status_t CreateRootDir();
+ void PrintUsage();
+ void PrintCurrentOption();
+
#if 0 // porting needed
// TODO: Trim support
// int f2fs_trim_device()
#endif
};
+zx_status_t Mkfs(Bcache* bc, int argc, char** argv);
+
+void AsciiToUnicode(const std::string& in_string, std::u16string* out_string);
+
} // namespace f2fs
#endif // THIRD_PARTY_F2FS_MKFS_H_
diff --git a/patches/0007-f2fs-Add-filesystem-specific-mkfs-option.patch b/patches/0007-f2fs-Add-filesystem-specific-mkfs-option.patch
new file mode 100644
index 0000000..6fa9128
--- /dev/null
+++ b/patches/0007-f2fs-Add-filesystem-specific-mkfs-option.patch
@@ -0,0 +1,150 @@
+From 9fca37737ec96fd715ab24ab8199dd5c9a9d53df Mon Sep 17 00:00:00 2001
+From: Dongjin Kim <dongjin_.kim@samsung.com>
+Date: Tue, 8 Jun 2021 19:23:09 +0900
+Subject: [PATCH] [f2fs] Add filesystem specific mkfs option
+
+"-p" option is delivered to filesystem, and filesystem will parse it.
+(currently only for f2fs)
+
+Change-Id: Id10a624c5e1177ca53b3f900fadf5a0646f212c2
+---
+ .../cpp/include/fs-management/admin.h | 2 +
+ src/lib/storage/fs_management/cpp/mkfs.cc | 53 ++++++++++++++++++-
+ src/storage/bin/mkfs/main.cc | 10 +++-
+ 3 files changed, 62 insertions(+), 3 deletions(-)
+
+diff --git a/src/lib/storage/fs_management/cpp/include/fs-management/admin.h b/src/lib/storage/fs_management/cpp/include/fs-management/admin.h
+index 6d5b7476e9c..420d0ea091e 100644
+--- a/src/lib/storage/fs_management/cpp/include/fs-management/admin.h
++++ b/src/lib/storage/fs_management/cpp/include/fs-management/admin.h
+@@ -58,6 +58,8 @@ typedef struct mkfs_options {
+ // The initial number of inodes to allocate space for. If 0, a default is used. Only supported
+ // for blobfs.
+ uint64_t num_inodes;
++ // Filesystem-specific options (currently for f2fs)
++ char* private_options = nullptr;
+ } mkfs_options_t;
+
+ __EXPORT
+diff --git a/src/lib/storage/fs_management/cpp/mkfs.cc b/src/lib/storage/fs_management/cpp/mkfs.cc
+index 506512aaf51..cc6030084a4 100644
+--- a/src/lib/storage/fs_management/cpp/mkfs.cc
++++ b/src/lib/storage/fs_management/cpp/mkfs.cc
+@@ -18,6 +18,7 @@
+
+ #include <iterator>
+ #include <new>
++#include <sstream>
+ #include <vector>
+
+ #include <fbl/algorithm.h>
+@@ -97,6 +98,55 @@ zx_status_t MkfsFat(const char* device_path, LaunchCallback cb, const mkfs_optio
+ return cb(argv.size() - 1, argv.data(), NULL, NULL, 0);
+ }
+
++zx_status_t MkfsF2fs(const char* device_path, LaunchCallback cb, const mkfs_options_t* options) {
++ fbl::unique_fd device_fd;
++ device_fd.reset(open(device_path, O_RDWR));
++ if (!device_fd) {
++ fprintf(stderr, "Failed to open device\n");
++ return ZX_ERR_BAD_STATE;
++ }
++ zx::channel block_device;
++ zx_status_t status =
++ fdio_get_service_handle(device_fd.release(), block_device.reset_and_get_address());
++ if (status != ZX_OK) {
++ return status;
++ }
++
++ const std::string tool_path = fs_management::GetBinaryPath("f2fs");
++ std::vector<const char*> argv = {tool_path.c_str()};
++ argv.push_back("mkfs");
++
++ std::vector<std::string> private_options_buf(10, "");
++
++ if (options->private_options != nullptr) {
++ std::istringstream iss(options->private_options);
++ std::string token;
++ uint32_t idx = 0;
++
++ while (std::getline(iss, token, ' ')) {
++ if (token == "")
++ continue;
++
++ if (idx >= private_options_buf.size()) {
++ private_options_buf.resize(private_options_buf.size() * 2, "");
++ }
++ private_options_buf[idx++] = token;
++ }
++
++ for (uint32_t i = 0; i < idx; i++) {
++ argv.push_back(private_options_buf[i].c_str());
++ }
++ }
++
++ argv.push_back(nullptr);
++
++ zx_handle_t hnd = block_device.release();
++ uint32_t id = FS_HANDLE_BLOCK_DEVICE_ID;
++ status =
++ static_cast<zx_status_t>(cb(static_cast<int>(argv.size() - 1), argv.data(), &hnd, &id, 1));
++ return status;
++}
++
+ } // namespace
+
+ __EXPORT
+@@ -118,8 +168,7 @@ zx_status_t mkfs(const char* device_path, disk_format_t df, LaunchCallback cb,
+ return MkfsNativeFs(fs_management::GetBinaryPath("blobfs").c_str(), device_path, cb, options,
+ true);
+ case DISK_FORMAT_F2FS:
+- return MkfsNativeFs(fs_management::GetBinaryPath("f2fs").c_str(), device_path, cb, options,
+- true);
++ return MkfsF2fs(device_path, cb, options);
+ default:
+ return ZX_ERR_NOT_SUPPORTED;
+ }
+diff --git a/src/storage/bin/mkfs/main.cc b/src/storage/bin/mkfs/main.cc
+index 9d370619483..0124d28f1e8 100644
+--- a/src/storage/bin/mkfs/main.cc
++++ b/src/storage/bin/mkfs/main.cc
+@@ -40,6 +40,10 @@ int usage(void) {
+ " -s|--fvm_data_slices SLICES If block device is on top of a FVM,\n"
+ " the filesystem will have at least SLICES slices\n"
+ " allocated for data.\n");
++ fprintf(stderr, " -p|--private_options OPTIONS Filesystem-specific options, wrapped in \"\".\n");
++ fprintf(stderr,
++ " It is delivered to filesystem without parsing,\n");
++ fprintf(stderr, " and the filesystem will parse it.\n");
+ fprintf(stderr, " values for 'filesystem' include:\n");
+ for (size_t i = 0; i < countof(FILESYSTEMS); i++) {
+ fprintf(stderr, " '%s'\n", FILESYSTEMS[i].name);
+@@ -53,13 +57,14 @@ int parse_args(int argc, char** argv, mkfs_options_t* options, disk_format_t* df
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"fvm_data_slices", required_argument, NULL, 's'},
++ {"private_options", required_argument, NULL, 'p'},
+ {0, 0, 0, 0},
+ };
+
+ int opt_index = -1;
+ int c = -1;
+
+- while ((c = getopt_long(argc, argv, "hvs:", cmds, &opt_index)) >= 0) {
++ while ((c = getopt_long(argc, argv, "hvs:p:", cmds, &opt_index)) >= 0) {
+ switch (c) {
+ case 'v':
+ options->verbose = true;
+@@ -73,6 +78,9 @@ int parse_args(int argc, char** argv, mkfs_options_t* options, disk_format_t* df
+ break;
+ case 'h':
+ return usage();
++ case 'p':
++ options->private_options = optarg;
++ break;
+ default:
+ break;
+ };
+--
+2.25.1
+
diff --git a/test/unit/mkfs.cc b/test/unit/mkfs.cc
index 08669ce..432e7f3 100644
--- a/test/unit/mkfs.cc
+++ b/test/unit/mkfs.cc
@@ -1,3 +1,437 @@
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+
+#include <string.h>
+
+#include <sstream>
+
+#include <block-client/cpp/fake-device.h>
+#include <gtest/gtest.h>
+
+#include "third_party/f2fs/f2fs.h"
+
+namespace f2fs {
+namespace {
+
+using block_client::FakeBlockDevice;
+
+constexpr uint64_t kBlockCount = 819200;
+constexpr uint32_t kBlockSize = 512;
+
+const MkfsOptions default_option;
+
+enum class ArgType {
+ Label,
+ SegsPerSec,
+ SecsPerZone,
+ Extension,
+ Heap,
+ OP,
+};
+
+void AddArg(std::vector<const char *> &argv, ArgType t, const char *val) {
+ switch (t) {
+ case ArgType::Label:
+ argv.push_back("-l");
+ break;
+ case ArgType::SegsPerSec:
+ argv.push_back("-s");
+ break;
+ case ArgType::SecsPerZone:
+ argv.push_back("-z");
+ break;
+ case ArgType::Extension:
+ argv.push_back("-e");
+ break;
+ case ArgType::Heap:
+ argv.push_back("-a");
+ break;
+ case ArgType::OP:
+ argv.push_back("-o");
+ break;
+ }
+ argv.push_back(val);
+}
+
+void PrintArg(std::vector<const char *> &argv) {
+ std::cout << "mkfs arg: ";
+ for (uint32_t i = 0; i < argv.size(); i++)
+ std::cout << (argv.data())[i] << " ";
+ std::cout << std::endl;
+}
+
+void DoMkfs(Bcache *bc, std::vector<const char *> &argv, bool expect_success) {
+ if (expect_success)
+ ASSERT_EQ(Mkfs(bc, static_cast<int>(argv.size()), const_cast<char **>(argv.data())), ZX_OK);
+ else
+ ASSERT_NE(Mkfs(bc, static_cast<int>(argv.size()), const_cast<char **>(argv.data())), ZX_OK);
+}
+
+void ReadSuperblock(Bcache *bc, SuperBlock *sb) { ASSERT_EQ(LoadSuperblock(bc, sb), ZX_OK); }
+
+void ReadCheckpoint(Bcache *bc, SuperBlock &sb, Checkpoint *ckp) {
+ char buf[4096];
+ ASSERT_EQ(bc->Readblk(sb.segment0_blkaddr, buf), ZX_OK);
+ memcpy(ckp, buf, sizeof(Checkpoint));
+}
+
+void VerifyLabel(SuperBlock &sb, const char *label) {
+ std::string vol_label(label);
+ std::u16string volume_name;
+ AsciiToUnicode(vol_label, &volume_name);
+
+ uint16_t volume_name_arr[512];
+ volume_name.copy(reinterpret_cast<char16_t *>(volume_name_arr), vol_label.size());
+ volume_name_arr[vol_label.size()] = '\0';
+ ASSERT_EQ(memcmp(sb.volume_name, volume_name_arr, vol_label.size() + 1), 0);
+}
+
+void VerifySegsPerSec(SuperBlock &sb, uint32_t segs_per_sec) {
+ ASSERT_EQ(sb.segs_per_sec, segs_per_sec);
+}
+
+void VerifySecsPerZone(SuperBlock &sb, uint32_t secs_per_zone) {
+ ASSERT_EQ(sb.secs_per_zone, secs_per_zone);
+}
+
+void VerifyExtensionList(SuperBlock &sb, const char *extensions) {
+ ASSERT_LE(sb.extension_count, static_cast<uint32_t>(kMaxExtension));
+ uint32_t extension_iter = 0;
+ for (const char *ext_item : kMediaExtList) {
+ ASSERT_LT(extension_iter, sb.extension_count);
+ ASSERT_EQ(strcmp(reinterpret_cast<char *>(sb.extension_list[extension_iter++]), ext_item), 0);
+ }
+
+ ASSERT_EQ(extension_iter, sizeof(kMediaExtList) / sizeof(const char *));
+
+ std::istringstream iss(extensions);
+ std::string token;
+
+ while (std::getline(iss, token, ',')) {
+ ASSERT_LE(extension_iter, sb.extension_count);
+ ASSERT_EQ(strcmp(reinterpret_cast<char *>(sb.extension_list[extension_iter++]), token.c_str()),
+ 0);
+ if (extension_iter >= kMaxExtension)
+ break;
+ }
+
+ ASSERT_EQ(extension_iter, sb.extension_count);
+}
+
+void VerifyHeapBasedAllocation(SuperBlock &sb, Checkpoint &ckp, bool is_heap_based) {
+ uint32_t total_zones =
+ ((LeToCpu(sb.segment_count_main) - 1) / sb.segs_per_sec) / sb.secs_per_zone;
+ ASSERT_GT(total_zones, static_cast<uint32_t>(6));
+
+ uint32_t cur_seg[6];
+ if (is_heap_based) {
+ cur_seg[static_cast<int>(CursegType::kCursegHotNode)] =
+ (total_zones - 1) * sb.segs_per_sec * sb.secs_per_zone +
+ ((sb.secs_per_zone - 1) * sb.segs_per_sec);
+ cur_seg[static_cast<int>(CursegType::kCursegWarmNode)] =
+ cur_seg[static_cast<int>(CursegType::kCursegHotNode)] - sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegColdNode)] =
+ cur_seg[static_cast<int>(CursegType::kCursegWarmNode)] - sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegHotData)] =
+ cur_seg[static_cast<int>(CursegType::kCursegColdNode)] - sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegColdData)] = 0;
+ cur_seg[static_cast<int>(CursegType::kCursegWarmData)] =
+ cur_seg[static_cast<int>(CursegType::kCursegColdData)] + sb.segs_per_sec * sb.secs_per_zone;
+ } else {
+ cur_seg[static_cast<int>(CursegType::kCursegHotNode)] = 0;
+ cur_seg[static_cast<int>(CursegType::kCursegWarmNode)] =
+ cur_seg[static_cast<int>(CursegType::kCursegHotNode)] + sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegColdNode)] =
+ cur_seg[static_cast<int>(CursegType::kCursegWarmNode)] + sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegHotData)] =
+ cur_seg[static_cast<int>(CursegType::kCursegColdNode)] + sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegColdData)] =
+ cur_seg[static_cast<int>(CursegType::kCursegHotData)] + sb.segs_per_sec * sb.secs_per_zone;
+ cur_seg[static_cast<int>(CursegType::kCursegWarmData)] =
+ cur_seg[static_cast<int>(CursegType::kCursegColdData)] + sb.segs_per_sec * sb.secs_per_zone;
+ }
+
+ ASSERT_EQ(ckp.cur_node_segno[0], cur_seg[static_cast<int>(CursegType::kCursegHotNode)]);
+ ASSERT_EQ(ckp.cur_node_segno[1], cur_seg[static_cast<int>(CursegType::kCursegWarmNode)]);
+ ASSERT_EQ(ckp.cur_node_segno[2], cur_seg[static_cast<int>(CursegType::kCursegColdNode)]);
+ ASSERT_EQ(ckp.cur_data_segno[0], cur_seg[static_cast<int>(CursegType::kCursegHotData)]);
+ ASSERT_EQ(ckp.cur_data_segno[1], cur_seg[static_cast<int>(CursegType::kCursegWarmData)]);
+ ASSERT_EQ(ckp.cur_data_segno[2], cur_seg[static_cast<int>(CursegType::kCursegColdData)]);
+}
+
+void VerifyOP(SuperBlock &sb, Checkpoint &ckp, uint32_t op_ratio) {
+ uint32_t overprov_segment_count =
+ CpuToLe((LeToCpu(sb.segment_count_main) - LeToCpu(ckp.rsvd_segment_count)) * op_ratio / 100 +
+ LeToCpu(ckp.rsvd_segment_count));
+ ASSERT_EQ(ckp.overprov_segment_count, overprov_segment_count);
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsLabel) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ char label[20];
+ const char *default_label = "F2FS";
+
+ // Check default label is written when there is no arg for label
+ std::vector<const char *> argv = {"mkfs"};
+ DoMkfs(bc.get(), argv, true);
+
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+ VerifyLabel(sb, default_label);
+
+ // Try with max size label (16)
+ argv.clear();
+ argv.push_back("mkfs");
+ memcpy(label, "0123456789abcde", 16);
+ AddArg(argv, ArgType::Label, label);
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ VerifyLabel(sb, label);
+
+ // Check failure with label size larger than max size
+ argv.clear();
+ argv.push_back("mkfs");
+ memcpy(label, "0123456789abcdef", 17);
+ AddArg(argv, ArgType::Label, label);
+ DoMkfs(bc.get(), argv, false);
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsSegsPerSec) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ // Check default value
+ std::vector<const char *> argv = {"mkfs"};
+ DoMkfs(bc.get(), argv, true);
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+ VerifySegsPerSec(sb, default_option.segs_per_sec);
+
+ // Try with various values
+ const uint32_t segs_per_sec_list[] = {1, 2, 4, 8};
+ for (uint32_t segs_per_sec : segs_per_sec_list) {
+ std::cout << "segs_per_sec = " << segs_per_sec << std::endl;
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::SegsPerSec, std::to_string(segs_per_sec).c_str());
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ VerifySegsPerSec(sb, segs_per_sec);
+ }
+
+ // Check failure with zero
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::SegsPerSec, "0");
+ DoMkfs(bc.get(), argv, false);
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsSecsPerZone) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ // Check default value
+ std::vector<const char *> argv = {"mkfs"};
+ DoMkfs(bc.get(), argv, true);
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+ VerifySecsPerZone(sb, default_option.secs_per_zone);
+
+ // Try with various values
+ const uint32_t secs_per_zone_list[] = {1, 2, 4, 8};
+ for (uint32_t secs_per_zone : secs_per_zone_list) {
+ std::cout << "secs_per_zone = " << secs_per_zone << std::endl;
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::SecsPerZone, std::to_string(secs_per_zone).c_str());
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ VerifySecsPerZone(sb, secs_per_zone);
+ }
+
+ // Check failure with zero
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::SecsPerZone, "0");
+ DoMkfs(bc.get(), argv, false);
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsExtensions) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ // Check default
+ std::vector<const char *> argv = {"mkfs"};
+ DoMkfs(bc.get(), argv, true);
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+ VerifyExtensionList(sb, "");
+
+ // Try with max extension counts
+ std::string extensions("");
+ for (uint32_t i = sizeof(kMediaExtList) / sizeof(const char *); i < kMaxExtension; i++) {
+ if (i > sizeof(kMediaExtList) / sizeof(const char *))
+ extensions.append(",");
+ extensions.append(std::to_string(i));
+ }
+ char ext_arg_buf[512];
+ strcpy(ext_arg_buf, extensions.c_str());
+
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::Extension, ext_arg_buf);
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ VerifyExtensionList(sb, extensions.c_str());
+
+ // If exeeding max extension counts, only extensions within max count are valid
+ extensions.append(",foo");
+ strcpy(ext_arg_buf, extensions.c_str());
+
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::Extension, ext_arg_buf);
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ VerifyExtensionList(sb, extensions.c_str());
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsHeapBasedAlloc) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ // Check default
+ std::vector<const char *> argv = {"mkfs"};
+ DoMkfs(bc.get(), argv, true);
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+ Checkpoint ckp = {};
+ ReadCheckpoint(bc.get(), sb, &ckp);
+ VerifyHeapBasedAllocation(sb, ckp, default_option.heap_based_allocation);
+
+ // If arg set to 0, not using heap-based allocation
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::Heap, "0");
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ ReadCheckpoint(bc.get(), sb, &ckp);
+ VerifyHeapBasedAllocation(sb, ckp, false);
+
+ // If arg set to 1, using heap-based allocation
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::Heap, "1");
+ DoMkfs(bc.get(), argv, true);
+ ReadSuperblock(bc.get(), &sb);
+ ReadCheckpoint(bc.get(), sb, &ckp);
+ VerifyHeapBasedAllocation(sb, ckp, true);
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsOverprovision) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ // Check default
+ std::vector<const char *> argv = {"mkfs"};
+ DoMkfs(bc.get(), argv, true);
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+ Checkpoint ckp = {};
+ ReadCheckpoint(bc.get(), sb, &ckp);
+ VerifyOP(sb, ckp, default_option.overprovision_ratio);
+
+ // Try with various values
+ const uint32_t overprovision_ratio_list[] = {1, 3, 5};
+ for (uint32_t overprovision_ratio : overprovision_ratio_list) {
+ std::cout << "overprovision_ratio = " << overprovision_ratio << std::endl;
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::OP, std::to_string(overprovision_ratio).c_str());
+ DoMkfs(bc.get(), argv, true);
+ ReadCheckpoint(bc.get(), sb, &ckp);
+ VerifyOP(sb, ckp, overprovision_ratio);
+ }
+
+ // Check failure with zero
+ argv.clear();
+ argv.push_back("mkfs");
+ AddArg(argv, ArgType::OP, "0");
+ DoMkfs(bc.get(), argv, false);
+}
+
+TEST(FormatFilesystemTest, MkfsOptionsMixed) {
+ auto device = std::make_unique<FakeBlockDevice>(kBlockCount, kBlockSize);
+ std::unique_ptr<Bcache> bc;
+ bool readonly_device = false;
+ ASSERT_EQ(CreateBcache(std::move(device), &readonly_device, &bc), ZX_OK);
+
+ const char *label_list[] = {"aa", "bbbbb"};
+ const uint32_t segs_per_sec_list[] = {2, 4};
+ const uint32_t secs_per_zone_list[] = {2, 4};
+ const char *ext_list[] = {"foo", "foo,bar"};
+ const uint32_t heap_based_list[] = {0};
+ const uint32_t overprovision_list[] = {1, 3};
+
+ for (const char *label : label_list) {
+ for (const uint32_t segs_per_sec : segs_per_sec_list) {
+ for (const uint32_t secs_per_zone : secs_per_zone_list) {
+ for (const char *extensions : ext_list) {
+ for (const uint32_t heap_based : heap_based_list) {
+ for (const uint32_t overprovision : overprovision_list) {
+ std::vector<const char *> argv = {"mkfs"};
+ char ext_arg_buf[512];
+
+ AddArg(argv, ArgType::Label, label);
+ AddArg(argv, ArgType::SegsPerSec, std::to_string(segs_per_sec).c_str());
+ AddArg(argv, ArgType::SecsPerZone, std::to_string(secs_per_zone).c_str());
+
+ // Mkfs will tokenize extension list using strtok().
+ // Since strtok() needs to modify original string, use non-const buffer to deliver
+ // argument
+ strcpy(ext_arg_buf, extensions);
+ AddArg(argv, ArgType::Extension, ext_arg_buf);
+
+ AddArg(argv, ArgType::Heap, std::to_string(heap_based).c_str());
+ AddArg(argv, ArgType::OP, std::to_string(overprovision).c_str());
+
+ PrintArg(argv);
+ DoMkfs(bc.get(), argv, true);
+
+ SuperBlock sb = {};
+ ReadSuperblock(bc.get(), &sb);
+
+ Checkpoint ckp = {};
+ ReadCheckpoint(bc.get(), sb, &ckp);
+
+ VerifyLabel(sb, label);
+ VerifySegsPerSec(sb, segs_per_sec);
+ VerifySecsPerZone(sb, secs_per_zone);
+ VerifyExtensionList(sb, extensions);
+ VerifyHeapBasedAllocation(sb, ckp, (heap_based != 0));
+ VerifyOP(sb, ckp, overprovision);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace
+} // namespace f2fs
diff --git a/tools/main.cc b/tools/main.cc
index 26e1874..b5f22f3 100644
--- a/tools/main.cc
+++ b/tools/main.cc
@@ -25,9 +25,8 @@
#include "third_party/f2fs/f2fs.h"
-int main(int argc, const char** argv) {
+int main(int argc, char** argv) {
f2fs::MountOptions options;
- f2fs::MkfsOptions mkfs_options;
std::cout << "f2fs arg= ";
@@ -82,7 +81,7 @@
// TODO: implement the fsck logic
if (!strcmp(argv[1], "mkfs")) {
- f2fs::Mkfs(mkfs_options, std::move(bc));
+ return f2fs::Mkfs(bc.get(), argc, argv);
} else if (!strcmp(argv[1], "fsck")) {
f2fs::Fsck(options, std::move(bc));
} else if (!strcmp(argv[1], "mount")) {