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 <jaeg...@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
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to