linux-f2fs-devel.lists.sourceforge.net archive mirror
 help / color / mirror / Atom feed
* [PATCH] f2fs-tools: support multiple devices
@ 2016-11-09 20:56 Jaegeuk Kim
  0 siblings, 0 replies; only message in thread
From: Jaegeuk Kim @ 2016-11-09 20:56 UTC (permalink / raw)
  To: linux-f2fs-devel; +Cc: Jaegeuk Kim

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>
---
 fsck/main.c              |   4 +-
 fsck/mount.c             |  34 +++++++++-
 include/f2fs_fs.h        |  57 +++++++++++-----
 lib/libf2fs.c            | 170 ++++++++++++++++++++++++++++++++---------------
 lib/libf2fs_io.c         |  62 +++++++++++++----
 lib/libf2fs_zoned.c      |  84 ++++++++++++-----------
 man/mkfs.f2fs.8          |   8 +++
 mkfs/f2fs_format.c       |  52 ++++++++++++---
 mkfs/f2fs_format_main.c  |  29 +++++++-
 mkfs/f2fs_format_utils.c |  21 ++++--
 mkfs/f2fs_format_utils.h |   1 +
 11 files changed, 382 insertions(+), 140 deletions(-)

diff --git a/fsck/main.c b/fsck/main.c
index 64537cc..39ef8d3 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -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;
diff --git a/fsck/mount.c b/fsck/mount.c
index 9fcb008..6c29a1a 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -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 >>
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 78ea939..6233452 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -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;
 
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 0485448..74d4d82 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -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,47 +759,87 @@ 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) {
-		MSG(0, "Info: total device sectors = %"PRIu64" (in %u bytes)\n",
-					c.total_sectors, c.sector_size);
-		c.total_sectors = wanted_total_sectors;
-	}
-	if (c.total_sectors * c.sector_size >
-		(u_int64_t)F2FS_MAX_SEGMENT * 2 * 1024 * 1024) {
-		MSG(0, "\tError: F2FS can support 16TB at most!!!\n");
+
+	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();
-	if (c.zoned_model == F2FS_ZONED_NONE) {
-		c.zoned_mode = 0;
-	} else {
-		if (f2fs_get_zone_blocks()) {
+		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()) {
+		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",
-				(c.zoned_model == F2FS_ZONED_HA) ?
+				(dev->zoned_model == F2FS_ZONED_HA) ?
 					"aware" : "managed");
 		MSG(0, "      %u zones, %u randomly writeable zones\n",
-				c.nr_zones, c.nr_rnd_zones);
+				dev->nr_zones, dev->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.
-		 */
+				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 = 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) {
+		MSG(0, "\tError: F2FS can support 16TB at most!!!\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;
+		}
+	}
+
+	/*
+	 * 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;
 }
-
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 1817c15..c09db36 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -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);
 }
diff --git a/lib/libf2fs_zoned.c b/lib/libf2fs_zoned.c
index 93b48f1..3c2186a 100644
--- a/lib/libf2fs_zoned.c
+++ b/lib/libf2fs_zoned.c
@@ -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;
diff --git a/man/mkfs.f2fs.8 b/man/mkfs.f2fs.8
index 0e54fe8..bdb9755 100644
--- a/man/mkfs.f2fs.8
+++ b/man/mkfs.f2fs.8
@@ -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
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index 3385a91..9a536f0 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -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;
diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c
index 6fd2f2a..70ed77a 100644
--- a/mkfs/f2fs_format_main.c
+++ b/mkfs/f2fs_format_main.c
@@ -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;
 	}
diff --git a/mkfs/f2fs_format_utils.c b/mkfs/f2fs_format_utils.c
index d204bd4..fc80ec6 100644
--- a/mkfs/f2fs_format_utils.c
+++ b/mkfs/f2fs_format_utils.c
@@ -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;
+}
diff --git a/mkfs/f2fs_format_utils.h b/mkfs/f2fs_format_utils.h
index ed28c58..274db7b 100644
--- a/mkfs/f2fs_format_utils.h
+++ b/mkfs/f2fs_format_utils.h
@@ -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);
-- 
2.8.3


------------------------------------------------------------------------------
Developer Access Program for Intel Xeon Phi Processors
Access to Intel Xeon Phi processor-based developer platforms.
With one year of Intel Parallel Studio XE.
Training and support from Colfax.
Order your platform today. http://sdm.link/xeonphi

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2016-11-09 20:56 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-09 20:56 [PATCH] f2fs-tools: support multiple devices Jaegeuk Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).