f2fs-tools: support multiple devices

This patch adds an option to specify multiple devices for an f2fs instance.

Up to 7 devices in addition to the default device can be added.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Jaegeuk Kim 2016-11-01 17:23:40 -07:00
parent ea1bd1ce31
commit de7e07e011
11 changed files with 388 additions and 146 deletions

View File

@ -301,7 +301,7 @@ void f2fs_parse_options(int argc, char *argv[])
else if (c.func == SLOAD)
sload_usage();
}
c.device_name = argv[optind];
c.devices[0].path = strdup(argv[optind]);
}
static void do_fsck(struct f2fs_sb_info *sbi)
@ -474,7 +474,7 @@ int main(int argc, char **argv)
f2fs_parse_options(argc, argv);
if (f2fs_dev_is_umounted() < 0) {
if (f2fs_devs_are_umounted() < 0) {
if (!c.ro || c.func == DEFRAG) {
MSG(0, "\tError: Not available on mounted device!\n");
return -1;

View File

@ -400,7 +400,7 @@ int sanity_check_raw_super(struct f2fs_super_block *sb, u64 offset)
return -1;
/* Check zoned block device feature */
if (c.zoned_model == F2FS_ZONED_HM &&
if (c.devices[0].zoned_model == F2FS_ZONED_HM &&
!(sb->feature & cpu_to_le32(F2FS_FEATURE_BLKZONED))) {
MSG(0, "\tMissing zoned block device feature\n");
return -1;
@ -470,6 +470,7 @@ int init_sb_info(struct f2fs_sb_info *sbi)
{
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
u64 total_sectors;
int i;
sbi->log_sectors_per_block = get_sb(log_sectors_per_block);
sbi->log_blocksize = get_sb(log_blocksize);
@ -486,6 +487,37 @@ int init_sb_info(struct f2fs_sb_info *sbi)
sbi->meta_ino_num = get_sb(meta_ino);
sbi->cur_victim_sec = NULL_SEGNO;
for (i = 0; i < MAX_DEVICES; i++) {
if (!sb->devs[i].path[0])
break;
if (i) {
c.devices[i].path = strdup((char *)sb->devs[i].path);
if (get_device_info(i))
ASSERT(0);
} else {
ASSERT(!strcmp((char *)sb->devs[i].path,
(char *)c.devices[i].path));
}
c.devices[i].total_segments =
le32_to_cpu(sb->devs[i].total_segments);
if (i)
c.devices[i].start_blkaddr =
c.devices[i - 1].end_blkaddr + 1;
c.devices[i].end_blkaddr = c.devices[i].start_blkaddr +
c.devices[i].total_segments *
c.blks_per_seg - 1;
if (i == 0)
c.devices[i].end_blkaddr += get_sb(segment0_blkaddr);
c.ndevs = i + 1;
MSG(0, "Info: Device[%d] : %s blkaddr = %"PRIx64"--%"PRIx64"\n",
i, c.devices[i].path,
c.devices[i].start_blkaddr,
c.devices[i].end_blkaddr);
}
total_sectors = get_sb(block_count) << sbi->log_sectors_per_block;
MSG(0, "Info: total FS sectors = %"PRIu64" (%"PRIu64" MB)\n",
total_sectors, total_sectors >>

View File

@ -212,6 +212,8 @@ static inline uint64_t bswap_64(uint64_t val)
#define BITS_PER_BYTE 8
#define F2FS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */
#define CHECKSUM_OFFSET 4092
#define MAX_PATH_LEN 64
#define MAX_DEVICES 8
#define F2FS_BYTES_TO_BLK(bytes) ((bytes) >> F2FS_BLKSIZE_BITS)
#define F2FS_BLKSIZE_BITS 12
@ -233,10 +235,28 @@ enum f2fs_config_func {
SLOAD,
};
struct f2fs_configuration {
struct device_info {
char *path;
int32_t fd;
u_int32_t sector_size;
u_int64_t total_sectors; /* got by get_device_info */
u_int64_t start_blkaddr;
u_int64_t end_blkaddr;
u_int32_t total_segments;
/* to handle zone block devices */
int zoned_model;
u_int32_t nr_zones;
u_int32_t nr_rnd_zones;
size_t zone_blocks;
};
struct f2fs_configuration {
u_int32_t reserved_segments;
u_int32_t new_reserved_segments;
int zoned_mode;
int zoned_model;
size_t zone_blocks;
double overprovision;
double new_overprovision;
u_int32_t cur_seg[6];
@ -244,7 +264,10 @@ struct f2fs_configuration {
u_int32_t secs_per_zone;
u_int32_t segs_per_zone;
u_int32_t start_sector;
u_int32_t total_segments;
u_int32_t sector_size;
u_int64_t total_sectors;
u_int64_t wanted_total_sectors;
u_int64_t target_sectors;
u_int32_t sectors_per_blk;
u_int32_t blks_per_seg;
@ -253,9 +276,10 @@ struct f2fs_configuration {
__u8 version[VERSION_LEN + 1];
char *vol_label;
int heap;
int32_t fd, kd;
int32_t kd;
int32_t dump_fd;
char *device_name;
struct device_info devices[MAX_DEVICES];
int ndevs;
char *extension_list;
const char *rootdev_name;
int dbg_lv;
@ -278,13 +302,6 @@ struct f2fs_configuration {
/* sload parameters */
char *from_dir;
char *mount_point;
/* to handle zone block devices */
int zoned_mode;
int zoned_model;
u_int32_t nr_zones;
u_int32_t nr_rnd_zones;
size_t zone_blocks;
} __attribute__((packed));
#ifdef CONFIG_64BIT
@ -443,6 +460,11 @@ enum {
/*
* For superblock
*/
struct f2fs_device {
__u8 path[MAX_PATH_LEN];
__le32 total_segments;
} __attribute__((packed));
struct f2fs_super_block {
__le32 magic; /* Magic Number */
__le16 major_ver; /* Major Version */
@ -481,7 +503,8 @@ struct f2fs_super_block {
__le32 feature; /* defined features */
__u8 encryption_level; /* versioning level for encryption */
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
__u8 reserved[871]; /* valid reserved region */
struct f2fs_device devs[MAX_DEVICES]; /* device list */
__u8 reserved[327]; /* valid reserved region */
} __attribute__((packed));
/*
@ -933,8 +956,10 @@ extern u_int32_t f2fs_cal_crc32(u_int32_t, void *, int);
extern int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len);
extern void f2fs_init_configuration(void);
extern int f2fs_dev_is_umounted(void);
extern int f2fs_devs_are_umounted(void);
extern int f2fs_dev_is_umounted(char *);
extern int f2fs_get_device_info(void);
extern int get_device_info(int);
extern void f2fs_finalize_device(void);
extern int dev_read(void *, __u64, size_t);
@ -1014,10 +1039,10 @@ blk_zone_cond_str(struct blk_zone *blkz)
#endif
extern void f2fs_get_zoned_model();
extern int f2fs_get_zone_blocks();
extern int f2fs_check_zones();
extern int f2fs_reset_zones();
extern void f2fs_get_zoned_model(int);
extern int f2fs_get_zone_blocks(int);
extern int f2fs_check_zones(int);
extern int f2fs_reset_zones(int);
extern struct f2fs_configuration c;

View File

@ -541,13 +541,25 @@ const char *get_rootdev()
*/
void f2fs_init_configuration(void)
{
int i;
c.ndevs = 1;
c.total_sectors = 0;
c.sector_size = DEFAULT_SECTOR_SIZE;
c.sector_size = 0;
c.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
c.blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
c.rootdev_name = get_rootdev();
c.wanted_total_sectors = -1;
c.zoned_mode = 0;
c.zoned_model = F2FS_ZONED_NONE;
c.zoned_model = 0;
c.zone_blocks = 0;
for (i = 0; i < MAX_DEVICES; i++) {
memset(&c.devices[i], 0, sizeof(struct device_info));
c.devices[i].sector_size = DEFAULT_SECTOR_SIZE;
c.devices[i].end_blkaddr = -1;
c.devices[i].zoned_model = F2FS_ZONED_NONE;
}
/* calculated by overprovision ratio */
c.reserved_segments = 0;
@ -557,9 +569,9 @@ void f2fs_init_configuration(void)
c.segs_per_zone = 1;
c.heap = 1;
c.vol_label = "";
c.device_name = NULL;
c.trim = 1;
c.ro = 0;
c.kd = -1;
}
static int is_mounted(const char *mpt, const char *device)
@ -584,26 +596,26 @@ static int is_mounted(const char *mpt, const char *device)
return mnt ? 1 : 0;
}
int f2fs_dev_is_umounted(void)
int f2fs_dev_is_umounted(char *path)
{
struct stat st_buf;
int is_rootdev = 0;
int ret = 0;
if (c.rootdev_name && !strcmp(c.device_name, c.rootdev_name))
if (c.rootdev_name && !strcmp(path, c.rootdev_name))
is_rootdev = 1;
/*
* try with /proc/mounts fist to detect RDONLY.
* f2fs_stop_checkpoint makes RO in /proc/mounts while RW in /etc/mtab.
*/
ret = is_mounted("/proc/mounts", c.device_name);
ret = is_mounted("/proc/mounts", path);
if (ret) {
MSG(0, "Info: Mounted device!\n");
return -1;
}
ret = is_mounted(MOUNTED, c.device_name);
ret = is_mounted(MOUNTED, path);
if (ret) {
MSG(0, "Info: Mounted device!\n");
return -1;
@ -626,8 +638,8 @@ int f2fs_dev_is_umounted(void)
* If f2fs is umounted with -l, the process can still use
* the file system. In this case, we should not format.
*/
if (stat(c.device_name, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
int fd = open(c.device_name, O_RDONLY | O_EXCL);
if (stat(path, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
int fd = open(path, O_RDONLY | O_EXCL);
if (fd >= 0) {
close(fd);
@ -639,6 +651,16 @@ int f2fs_dev_is_umounted(void)
return 0;
}
int f2fs_devs_are_umounted(void)
{
int i;
for (i = 0; i < c.ndevs; i++)
if (f2fs_dev_is_umounted((char *)c.devices[i].path))
return -1;
return 0;
}
void get_kernel_version(__u8 *version)
{
int i;
@ -649,7 +671,7 @@ void get_kernel_version(__u8 *version)
memset(version + i, 0, VERSION_LEN + 1 - i);
}
int f2fs_get_device_info(void)
int get_device_info(int i)
{
int32_t fd = 0;
uint32_t sector_size;
@ -663,18 +685,23 @@ int f2fs_get_device_info(void)
unsigned char reply_buffer[96] = {0};
unsigned char model_inq[6] = {MODELINQUIRY};
#endif
u_int64_t wanted_total_sectors = c.total_sectors;
struct device_info *dev = c.devices + i;
fd = open(c.device_name, O_RDWR);
fd = open((char *)dev->path, O_RDWR);
if (fd < 0) {
MSG(0, "\tError: Failed to open the device!\n");
return -1;
}
c.fd = fd;
c.kd = open("/proc/version", O_RDONLY);
if (c.kd < 0)
MSG(0, "\tInfo: No support kernel version!\n");
dev->fd = fd;
if (c.kd == -1) {
c.kd = open("/proc/version", O_RDONLY);
if (c.kd < 0) {
MSG(0, "\tInfo: No support kernel version!\n");
c.kd = -2;
}
}
if (fstat(fd, &stat_buf) < 0 ) {
MSG(0, "\tError: Failed to get the device stat!\n");
@ -682,31 +709,26 @@ int f2fs_get_device_info(void)
}
if (S_ISREG(stat_buf.st_mode)) {
c.total_sectors = stat_buf.st_size / c.sector_size;
dev->total_sectors = stat_buf.st_size / dev->sector_size;
} else if (S_ISBLK(stat_buf.st_mode)) {
if (ioctl(fd, BLKSSZGET, &sector_size) < 0) {
if (ioctl(fd, BLKSSZGET, &sector_size) < 0)
MSG(0, "\tError: Using the default sector size\n");
} else {
if (c.sector_size < sector_size) {
c.sector_size = sector_size;
c.sectors_per_blk = PAGE_SIZE / sector_size;
}
}
else if (dev->sector_size < sector_size)
dev->sector_size = sector_size;
#ifdef BLKGETSIZE64
if (ioctl(fd, BLKGETSIZE64, &c.total_sectors) < 0) {
if (ioctl(fd, BLKGETSIZE64, &dev->total_sectors) < 0) {
MSG(0, "\tError: Cannot get the device size\n");
return -1;
}
c.total_sectors /= c.sector_size;
#else
if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
MSG(0, "\tError: Cannot get the device size\n");
return -1;
}
total_sectors /= c.sector_size;
c.total_sectors = total_sectors;
dev->total_sectors = total_sectors;
#endif
dev->total_sectors /= dev->sector_size;
if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
c.start_sector = 0;
else
@ -723,10 +745,11 @@ int f2fs_get_device_info(void)
io_hdr.cmdp = model_inq;
io_hdr.timeout = 1000;
if (!ioctl(fd,SG_IO,&io_hdr)) {
if (!ioctl(fd, SG_IO, &io_hdr)) {
int i = 16;
MSG(0, "Info: Disk Model: ");
MSG(0, "Info: [%s] Disk Model: ",
dev->path);
while (reply_buffer[i] != '`' && i < 80)
printf("%c", reply_buffer[i++]);
printf("\n");
@ -736,10 +759,58 @@ int f2fs_get_device_info(void)
MSG(0, "\tError: Volume type is not supported!!!\n");
return -1;
}
if (wanted_total_sectors && wanted_total_sectors < c.total_sectors) {
if (!c.sector_size) {
c.sector_size = dev->sector_size;
c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size;
} else if (c.sector_size != c.devices[i].sector_size) {
MSG(0, "\tError: Different sector sizes!!!\n");
return -1;
}
#ifndef WITH_ANDROID
if (S_ISBLK(stat_buf.st_mode))
f2fs_get_zoned_model(i);
if (dev->zoned_model != F2FS_ZONED_NONE) {
if (dev->zoned_model == F2FS_ZONED_HM)
c.zoned_model = F2FS_ZONED_HM;
if (f2fs_get_zone_blocks(i)) {
MSG(0, "\tError: Failed to get number of blocks per zone\n");
return -1;
}
if (f2fs_check_zones(i)) {
MSG(0, "\tError: Failed to check zone configuration\n");
return -1;
}
MSG(0, "Info: Host-%s zoned block device:\n",
(dev->zoned_model == F2FS_ZONED_HA) ?
"aware" : "managed");
MSG(0, " %u zones, %u randomly writeable zones\n",
dev->nr_zones, dev->nr_rnd_zones);
MSG(0, " %lu blocks per zone\n",
dev->zone_blocks);
}
#endif
c.total_sectors += dev->total_sectors;
return 0;
}
int f2fs_get_device_info(void)
{
int i;
for (i = 0; i < c.ndevs; i++)
if (get_device_info(i))
return -1;
if (c.wanted_total_sectors < c.total_sectors) {
MSG(0, "Info: total device sectors = %"PRIu64" (in %u bytes)\n",
c.total_sectors, c.sector_size);
c.total_sectors = wanted_total_sectors;
c.total_sectors, c.sector_size);
c.total_sectors = c.wanted_total_sectors;
c.devices[0].total_sectors = c.total_sectors;
}
if (c.total_sectors * c.sector_size >
(u_int64_t)F2FS_MAX_SEGMENT * 2 * 1024 * 1024) {
@ -747,36 +818,28 @@ int f2fs_get_device_info(void)
return -1;
}
#ifndef WITH_ANDROID
if (S_ISBLK(stat_buf.st_mode))
f2fs_get_zoned_model();
if (c.zoned_model == F2FS_ZONED_NONE) {
c.zoned_mode = 0;
} else {
if (f2fs_get_zone_blocks()) {
MSG(0, "\tError: Failed to get number of blocks per zone\n");
return -1;
for (i = 0; i < c.ndevs; i++) {
if (c.devices[i].zoned_model != F2FS_ZONED_NONE) {
if (c.zone_blocks &&
c.zone_blocks != c.devices[i].zone_blocks) {
MSG(0, "\tError: not support different zone sizes!!!\n");
return -1;
}
c.zone_blocks = c.devices[i].zone_blocks;
}
}
if (f2fs_check_zones()) {
MSG(0, "\tError: Failed to check zone configuration\n");
return -1;
}
MSG(0, "Info: Host-%s zoned block device:\n",
(c.zoned_model == F2FS_ZONED_HA) ?
"aware" : "managed");
MSG(0, " %u zones, %u randomly writeable zones\n",
c.nr_zones, c.nr_rnd_zones);
MSG(0, " %lu blocks per zone\n",
c.zone_blocks);
/*
* Align sections to the device zone size
* and align F2FS zones to the device zones.
*/
/*
* Align sections to the device zone size
* and align F2FS zones to the device zones.
*/
if (c.zone_blocks) {
c.segs_per_sec = c.zone_blocks / DEFAULT_BLOCKS_PER_SEGMENT;
c.secs_per_zone = 1;
} else {
c.zoned_mode = 0;
}
#endif
c.segs_per_zone = c.segs_per_sec * c.secs_per_zone;
MSG(0, "Info: Segments per section = %d\n", c.segs_per_sec);
@ -787,4 +850,3 @@ int f2fs_get_device_info(void)
(c.sector_size >> 9)) >> 11);
return 0;
}

View File

@ -25,6 +25,22 @@
struct f2fs_configuration c;
static int __get_device_fd(__u64 *offset)
{
__u64 blk_addr = *offset >> F2FS_BLKSIZE_BITS;
int i;
for (i = 0; i < c.ndevs; i++) {
if (c.devices[i].start_blkaddr <= blk_addr &&
c.devices[i].end_blkaddr >= blk_addr) {
*offset -=
c.devices[i].start_blkaddr << F2FS_BLKSIZE_BITS;
return c.devices[i].fd;
}
}
return -1;
}
/*
* IO interfaces
*/
@ -39,17 +55,26 @@ int dev_read_version(void *buf, __u64 offset, size_t len)
int dev_read(void *buf, __u64 offset, size_t len)
{
if (lseek64(c.fd, (off64_t)offset, SEEK_SET) < 0)
int fd = __get_device_fd(&offset);
if (fd < 0)
return fd;
if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
return -1;
if (read(c.fd, buf, len) < 0)
if (read(fd, buf, len) < 0)
return -1;
return 0;
}
int dev_readahead(__u64 offset, size_t len)
{
int fd = __get_device_fd(&offset);
if (fd < 0)
return fd;
#ifdef POSIX_FADV_WILLNEED
return posix_fadvise(c.fd, offset, len, POSIX_FADV_WILLNEED);
return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
#else
return 0;
#endif
@ -57,9 +82,14 @@ int dev_readahead(__u64 offset, size_t len)
int dev_write(void *buf, __u64 offset, size_t len)
{
if (lseek64(c.fd, (off64_t)offset, SEEK_SET) < 0)
int fd = __get_device_fd(&offset);
if (fd < 0)
return fd;
if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
return -1;
if (write(c.fd, buf, len) < 0)
if (write(fd, buf, len) < 0)
return -1;
return 0;
}
@ -80,12 +110,17 @@ int dev_write_dump(void *buf, __u64 offset, size_t len)
int dev_fill(void *buf, __u64 offset, size_t len)
{
int fd = __get_device_fd(&offset);
if (fd < 0)
return fd;
/* Only allow fill to zero */
if (*((__u8*)buf))
return -1;
if (lseek64(c.fd, (off64_t)offset, SEEK_SET) < 0)
if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
return -1;
if (write(c.fd, buf, len) < 0)
if (write(fd, buf, len) < 0)
return -1;
return 0;
}
@ -107,15 +142,18 @@ int dev_reada_block(__u64 blk_addr)
void f2fs_finalize_device(void)
{
int i;
/*
* We should call fsync() to flush out all the dirty pages
* in the block device page cache.
*/
if (fsync(c.fd) < 0)
MSG(0, "\tError: Could not conduct fsync!!!\n");
if (close(c.fd) < 0)
MSG(0, "\tError: Failed to close device file!!!\n");
for (i = 0; i < c.ndevs; i++) {
if (fsync(c.devices[i].fd) < 0)
MSG(0, "\tError: Could not conduct fsync!!!\n");
if (close(c.devices[i].fd) < 0)
MSG(0, "\tError: Failed to close device file!!!\n");
}
close(c.kd);
}

View File

@ -22,8 +22,9 @@
#ifdef HAVE_LINUX_BLKZONED_H
void f2fs_get_zoned_model()
void f2fs_get_zoned_model(int i)
{
struct device_info *dev = c.devices + i;
char str[128];
FILE *file;
int res;
@ -31,7 +32,7 @@ void f2fs_get_zoned_model()
/* Check that this is a zoned block device */
snprintf(str, sizeof(str),
"/sys/block/%s/queue/zoned",
basename(c.device_name));
basename(dev->path));
file = fopen(str, "r");
if (!file)
goto not_zoned;
@ -44,31 +45,32 @@ void f2fs_get_zoned_model()
goto not_zoned;
if (strcmp(str, "host-aware") == 0) {
c.zoned_model = F2FS_ZONED_HA;
dev->zoned_model = F2FS_ZONED_HA;
return;
}
if (strcmp(str, "host-managed") == 0) {
c.zoned_model = F2FS_ZONED_HM;
dev->zoned_model = F2FS_ZONED_HM;
return;
}
not_zoned:
c.zoned_model = F2FS_ZONED_NONE;
dev->zoned_model = F2FS_ZONED_NONE;
}
int f2fs_get_zone_blocks()
int f2fs_get_zone_blocks(int i)
{
struct device_info *dev = c.devices + i;
uint64_t sectors;
char str[128];
FILE *file;
int res;
/* Get zone size */
c.zone_blocks = 0;
dev->zone_blocks = 0;
snprintf(str, sizeof(str),
"/sys/block/%s/queue/chunk_sectors",
basename(c.device_name));
basename(dev->path));
file = fopen(str, "r");
if (!file)
return -1;
@ -84,24 +86,25 @@ int f2fs_get_zone_blocks()
if (!sectors)
return -1;
c.zone_blocks = sectors >> (F2FS_BLKSIZE_BITS - 9);
dev->zone_blocks = sectors >> (F2FS_BLKSIZE_BITS - 9);
sectors = (sectors << 9) / c.sector_size;
/*
* Total number of zones: there may
* be a last smaller runt zone.
*/
c.nr_zones = c.total_sectors / sectors;
if (c.total_sectors % sectors)
c.nr_zones++;
dev->nr_zones = dev->total_sectors / sectors;
if (dev->total_sectors % sectors)
dev->nr_zones++;
return 0;
}
#define F2FS_REPORT_ZONES_BUFSZ 524288
int f2fs_check_zones()
int f2fs_check_zones(int j)
{
struct device_info *dev = c.devices + j;
struct blk_zone_report *rep;
struct blk_zone *blkz;
unsigned int i, n = 0;
@ -116,9 +119,9 @@ int f2fs_check_zones()
return -ENOMEM;
}
c.nr_rnd_zones = 0;
dev->nr_rnd_zones = 0;
sector = 0;
total_sectors = (c.total_sectors * c.sector_size) >> 9;
total_sectors = (dev->total_sectors * c.sector_size) >> 9;
while (sector < total_sectors) {
@ -128,7 +131,7 @@ int f2fs_check_zones()
rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report))
/ sizeof(struct blk_zone);
ret = ioctl(c.fd, BLKREPORTZONE, rep);
ret = ioctl(dev->fd, BLKREPORTZONE, rep);
if (ret != 0) {
ret = -errno;
ERR_MSG("ioctl BLKREPORTZONE failed\n");
@ -147,7 +150,7 @@ int f2fs_check_zones()
if (blk_zone_conv(blkz) ||
blk_zone_seq_pref(blkz)) {
if (last_is_conv)
c.nr_rnd_zones++;
dev->nr_rnd_zones++;
} else {
last_is_conv = 0;
}
@ -180,26 +183,25 @@ int f2fs_check_zones()
n++;
blkz++;
}
}
if (sector != total_sectors) {
ERR_MSG("Invalid zones: last sector reported is %llu, expected %llu\n",
(unsigned long long)(sector << 9) / c.sector_size,
(unsigned long long)c.total_sectors);
(unsigned long long)dev->total_sectors);
ret = -1;
goto out;
}
if (n != c.nr_zones) {
if (n != dev->nr_zones) {
ERR_MSG("Inconsistent number of zones: expected %u zones, got %u\n",
c.nr_zones, n);
dev->nr_zones, n);
ret = -1;
goto out;
}
if (c.zoned_model == F2FS_ZONED_HM &&
!c.nr_rnd_zones) {
if (dev->zoned_model == F2FS_ZONED_HM &&
!dev->nr_rnd_zones) {
ERR_MSG("No conventional zone for super block\n");
ret = -1;
}
@ -208,8 +210,9 @@ out:
return ret;
}
int f2fs_reset_zones()
int f2fs_reset_zones(int j)
{
struct device_info *dev = c.devices + j;
struct blk_zone_report *rep;
struct blk_zone *blkz;
struct blk_zone_range range;
@ -225,7 +228,7 @@ int f2fs_reset_zones()
}
sector = 0;
total_sectors = (c.total_sectors * c.sector_size) >> 9;
total_sectors = (dev->total_sectors * c.sector_size) >> 9;
while (sector < total_sectors) {
/* Get zone info */
@ -234,7 +237,7 @@ int f2fs_reset_zones()
rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report))
/ sizeof(struct blk_zone);
ret = ioctl(c.fd, BLKREPORTZONE, rep);
ret = ioctl(dev->fd, BLKREPORTZONE, rep);
if (ret != 0) {
ret = -errno;
ERR_MSG("ioctl BLKREPORTZONES failed\n");
@ -251,8 +254,9 @@ int f2fs_reset_zones()
/* Non empty sequential zone: reset */
range.sector = blk_zone_sector(blkz);
range.nr_sectors = blk_zone_length(blkz);
ret = ioctl(c.fd, BLKRESETZONE, &range);
ret = ioctl(dev->fd, BLKRESETZONE, &range);
if (ret != 0) {
ret = -errno;
ERR_MSG("ioctl BLKRESETZONE failed\n");
goto out;
}
@ -260,39 +264,43 @@ int f2fs_reset_zones()
sector = blk_zone_sector(blkz) + blk_zone_length(blkz);
blkz++;
}
}
out:
free(rep);
return 0;
if (!ret)
MSG(0, "Info: Discarded %"PRIu64" MB\n", (sector << 9) >> 20);
return ret;
}
#else
void f2fs_get_zoned_model()
void f2fs_get_zoned_model(int i)
{
struct device_info *dev = c.devices + i;
c.zoned_mode = 0;
c.zoned_model = F2FS_ZONED_NONE;
dev->zoned_model = F2FS_ZONED_NONE;
}
int f2fs_get_zone_blocks()
int f2fs_get_zone_blocks(int i)
{
struct device_info *dev = c.devices + i;
c.zoned_mode = 0;
c.nr_zones = 0;
c.zone_blocks = 0;
c.zoned_model = F2FS_ZONED_NONE;
dev->nr_zones = 0;
dev->zone_blocks = 0;
dev->zoned_model = F2FS_ZONED_NONE;
return 0;
}
int f2fs_check_zones()
int f2fs_check_zones(int i)
{
ERR_MSG("Zoned block devices are not supported\n");
return -1;
}
int f2fs_reset_zones()
int f2fs_reset_zones(int i)
{
ERR_MSG("Zoned block devices are not supported\n");
return -1;

View File

@ -12,6 +12,10 @@ mkfs.f2fs \- create an F2FS file system
.I heap-based-allocation
]
[
.B \-c
.I device
]
[
.B \-l
.I volume-label
]
@ -55,6 +59,10 @@ If the value is equal to 1, each of active log areas are initially
assigned separately according to the whole volume size.
The default value is 1.
.TP
.BI \-c " device"
Build f2fs with this device additionally, so that user can see all
the devices as one big volume.
.TP
.BI \-l " volume-label"
Specify the volume label to the partition mounted as F2FS.
.TP

View File

@ -131,6 +131,7 @@ static int f2fs_prepare_super_block(void)
u_int32_t sit_bitmap_size, max_sit_bitmap_size;
u_int32_t max_nat_bitmap_size, max_nat_segments;
u_int32_t total_zones;
int i;
set_sb(magic, F2FS_SUPER_MAGIC);
set_sb(major_ver, F2FS_MAJOR_VERSION);
@ -167,29 +168,59 @@ static int f2fs_prepare_super_block(void)
c.start_sector * c.sector_size;
if (c.start_sector % c.sectors_per_blk) {
MSG(1, "\tWARN: Align start sector number to the page unit\n");
MSG(1, "\t%s: Align start sector number to the page unit\n",
c.zoned_mode ? "FAIL" : "WARN");
MSG(1, "\ti.e., start sector: %d, ofs:%d (sects/page: %d)\n",
c.start_sector,
c.start_sector % c.sectors_per_blk,
c.sectors_per_blk);
if (c.zoned_mode)
return -1;
}
set_sb(segment_count, (c.total_sectors * c.sector_size -
zone_align_start_offset) / segment_size_bytes /
c.segs_per_zone * c.segs_per_zone);
set_sb(segment0_blkaddr, zone_align_start_offset / blk_size_bytes);
sb->cp_blkaddr = sb->segment0_blkaddr;
MSG(0, "Info: zone aligned segment0 blkaddr: %u\n",
get_sb(segment0_blkaddr));
if (c.zoned_mode && get_sb(segment0_blkaddr) % c.zone_blocks) {
if (c.zoned_mode && (get_sb(segment0_blkaddr) + c.start_sector /
c.sectors_per_blk) % c.zone_blocks) {
MSG(1, "\tError: Unaligned segment0 block address %u\n",
get_sb(segment0_blkaddr));
return -1;
}
for (i = 0; i < c.ndevs; i++) {
if (i == 0) {
c.devices[i].total_segments =
(c.devices[i].total_sectors *
c.sector_size - zone_align_start_offset) /
segment_size_bytes;
c.devices[i].start_blkaddr = 0;
c.devices[i].end_blkaddr = c.devices[i].total_segments *
c.blks_per_seg - 1 +
sb->segment0_blkaddr;
} else {
c.devices[i].total_segments =
c.devices[i].total_sectors /
(c.sectors_per_blk * c.blks_per_seg);
c.devices[i].start_blkaddr =
c.devices[i - 1].end_blkaddr + 1;
c.devices[i].end_blkaddr = c.devices[i].start_blkaddr +
c.devices[i].total_segments *
c.blks_per_seg - 1;
}
if (c.ndevs > 1) {
memcpy(sb->devs[i].path, c.devices[i].path, MAX_PATH_LEN);
sb->devs[i].total_segments =
cpu_to_le32(c.devices[i].total_segments);
}
c.total_segments += c.devices[i].total_segments;
}
set_sb(segment_count, (c.total_segments / c.segs_per_zone *
c.segs_per_zone));
set_sb(segment_count_ckpt, F2FS_NUMBER_OF_CHECKPOINT_PACK);
set_sb(sit_blkaddr, get_sb(segment0_blkaddr) +
@ -286,9 +317,10 @@ static int f2fs_prepare_super_block(void)
*/
unsigned long main_blkzone = get_sb(main_blkaddr) / c.zone_blocks;
if (c.nr_rnd_zones < main_blkzone) {
MSG(1, "\tError: Device does not have enough random "
"write zones for F2FS volume (%lu needed)",
if (c.devices[0].zoned_model == F2FS_ZONED_HM &&
c.devices[0].nr_rnd_zones < main_blkzone) {
MSG(0, "\tError: Device does not have enough random "
"write zones for F2FS volume (%lu needed)\n",
main_blkzone);
return -1;
}
@ -969,7 +1001,7 @@ int f2fs_format_device(void)
}
if (c.trim) {
err = f2fs_trim_device(c.fd, c.total_sectors * c.sector_size);
err = f2fs_trim_devices();
if (err < 0) {
MSG(0, "\tError: Failed to trim whole device!!!\n");
goto exit;

View File

@ -28,6 +28,7 @@ static void mkfs_usage()
MSG(0, "\nUsage: mkfs.f2fs [options] device [sectors]\n");
MSG(0, "[options]:\n");
MSG(0, " -a heap-based allocation [default:1]\n");
MSG(0, " -c [device path]\n");
MSG(0, " -d debug level [default:0]\n");
MSG(0, " -e [extension list] e.g. \"mp3,gif,mov\"\n");
MSG(0, " -l label\n");
@ -71,7 +72,7 @@ static void parse_feature(const char *features)
static void f2fs_parse_options(int argc, char *argv[])
{
static const char *option_string = "qa:d:e:l:mo:O:s:z:t:";
static const char *option_string = "qa:c:d:e:l:mo:O:s:z:t:";
int32_t option=0;
while ((option = getopt(argc,argv,option_string)) != EOF) {
@ -82,6 +83,14 @@ static void f2fs_parse_options(int argc, char *argv[])
case 'a':
c.heap = atoi(optarg);
break;
case 'c':
if (strlen(optarg) > MAX_PATH_LEN) {
MSG(0, "Error: device path should be less than "
"%d characters\n", MAX_PATH_LEN);
mkfs_usage();
}
c.devices[c.ndevs++].path = strdup(optarg);
break;
case 'd':
c.dbg_lv = atoi(optarg);
break;
@ -125,7 +134,21 @@ static void f2fs_parse_options(int argc, char *argv[])
MSG(0, "\tError: Device not specified\n");
mkfs_usage();
}
c.device_name = argv[optind];
/* [0] : META, [1 to MAX_DEVICES + 1] : NODE/DATA */
c.devices[0].path = strdup(argv[optind]);
if (c.ndevs > MAX_DEVICES) {
MSG(0, "\tError: Too many devices\n");
mkfs_usage();
}
if ((optind + 1) < argc) {
if (c.ndevs > 1) {
MSG(0, "\tError: Not support custom size on multi-devs.\n");
mkfs_usage();
}
c.wanted_total_sectors = atoll(argv[optind+1]);
}
if ((optind + 1) < argc)
c.total_sectors = atoll(argv[optind+1]);
@ -142,7 +165,7 @@ int main(int argc, char *argv[])
f2fs_show_info();
if (f2fs_dev_is_umounted() < 0) {
if (f2fs_devs_are_umounted() < 0) {
MSG(0, "\tError: Not available on mounted device!\n");
return -1;
}

View File

@ -34,10 +34,13 @@
#define BLKSECDISCARD _IO(0x12,125)
#endif
int f2fs_trim_device(int fd, u_int64_t bytes)
static int trim_device(int i)
{
unsigned long long range[2];
struct stat stat_buf;
struct device_info *dev = c.devices + i;
u_int64_t bytes = dev->total_sectors * dev->sector_size;
int fd = dev->fd;
if (fstat(fd, &stat_buf) < 0 ) {
MSG(1, "\tError: Failed to get the device stat!!!\n");
@ -48,7 +51,7 @@ int f2fs_trim_device(int fd, u_int64_t bytes)
range[1] = bytes;
#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD)
MSG(0, "Info: Discarding device\n");
MSG(0, "Info: [%s] Discarding device\n", dev->path);
if (S_ISREG(stat_buf.st_mode)) {
#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
@ -58,8 +61,8 @@ int f2fs_trim_device(int fd, u_int64_t bytes)
#endif
return 0;
} else if (S_ISBLK(stat_buf.st_mode)) {
if (c.zoned_mode)
return f2fs_reset_zones();
if (dev->zoned_model != F2FS_ZONED_NONE)
return f2fs_reset_zones(i);
#ifdef BLKSECDISCARD
if (ioctl(fd, BLKSECDISCARD, &range) < 0) {
MSG(0, "Info: This device doesn't support BLKSECDISCARD\n");
@ -79,3 +82,13 @@ int f2fs_trim_device(int fd, u_int64_t bytes)
#endif
return 0;
}
int f2fs_trim_devices(void)
{
int i;
for (i = 0; i < c.ndevs; i++)
if (trim_device(i))
return -1;
return 0;
}

View File

@ -13,4 +13,5 @@
extern struct f2fs_configuration c;
int f2fs_trim_device(int, u_int64_t);
int f2fs_trim_devices(void);
int f2fs_format_device(void);