Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754718AbcKIW6E (ORCPT ); Wed, 9 Nov 2016 17:58:04 -0500 Received: from mail-it0-f65.google.com ([209.85.214.65]:33236 "EHLO mail-it0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754633AbcKIW6B (ORCPT ); Wed, 9 Nov 2016 17:58:01 -0500 Subject: Re: [PATCH] f2fs: support multiple devices Mime-Version: 1.0 (Mac OS X Mail 9.3 \(3124\)) Content-Type: multipart/signed; boundary="Apple-Mail=_BA06BDC1-F1E9-47DD-A826-6669C35625EE"; protocol="application/pgp-signature"; micalg=pgp-sha256 X-Pgp-Agent: GPGMail From: Andreas Dilger In-Reply-To: <20161109205653.70061-1-jaegeuk@kernel.org> Date: Wed, 9 Nov 2016 15:57:53 -0700 Cc: LKML , Lustre Development , linux-fsdevel , linux-f2fs-devel@lists.sourceforge.net, linux-btrfs Message-Id: <0D1876A8-BB77-4C1A-BE4F-B4A0E81DD4EA@dilger.ca> References: <20161109205653.70061-1-jaegeuk@kernel.org> To: Jaegeuk Kim X-Mailer: Apple Mail (2.3124) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 24365 Lines: 811 --Apple-Mail=_BA06BDC1-F1E9-47DD-A826-6669C35625EE Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii On Nov 9, 2016, at 1:56 PM, Jaegeuk Kim wrote: >=20 > This patch implements multiple devices support for f2fs. > Given multiple devices by mkfs.f2fs, f2fs shows them entirely as one = big > volume under one f2fs instance. >=20 > Internal block management is very simple, but we will modify block > allocation and background GC policy to boost IO speed by exploiting = them > accoording to each device speed. How will you integrate this into FIEMAP, since it is now possible if a file is split across multiple devices then it will return ambiguous = block numbers for a file. I've been meaning to merge the FIEMAP handling in Lustre to support multiple devices in a single filesystem, so that this can be detected in userspace. struct ll_fiemap_extent { __u64 fe_logical; /* logical offset in bytes for the start of * the extent from the beginning of the file */ __u64 fe_physical; /* physical offset in bytes for the start * of the extent from the beginning of the = disk */ __u64 fe_length; /* length in bytes for this extent */ __u64 fe_reserved64[2]; __u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */ __u32 fe_device; /* device number for this extent */ __u32 fe_reserved[2]; }; This adds the 32-bit "fe_device" field, which would optionally be filled in by the filesystem (zero otherwise). It would return the kernel = device number (i.e. st_dev), or for network filesystem (with FIEMAP_EXTENT_NET set) this could just return an integer device number since the device number is meaningless (and may conflict) on a remote system. Since AFAIK Btrfs also has multiple device support there are an = increasing number of places where this would be useful. Cheers, Andreas >=20 > Signed-off-by: Jaegeuk Kim > --- > fs/f2fs/data.c | 55 ++++++++++++++++--- > fs/f2fs/f2fs.h | 29 ++++++++-- > fs/f2fs/segment.c | 119 = +++++++++++++++++++++++++++++------------ > fs/f2fs/super.c | 138 = ++++++++++++++++++++++++++++++++++++++---------- > include/linux/f2fs_fs.h | 10 +++- > 5 files changed, 277 insertions(+), 74 deletions(-) >=20 > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c > index 47ded0c..e2be24e 100644 > --- a/fs/f2fs/data.c > +++ b/fs/f2fs/data.c > @@ -88,6 +88,46 @@ static void f2fs_write_end_io(struct bio *bio) > } >=20 > /* > + * Return true, if pre_bio's bdev is same as its target device. > + */ > +struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi, > + block_t blk_addr, struct bio *bio) > +{ > + struct block_device *bdev =3D sbi->sb->s_bdev; > + int i; > + > + for (i =3D 0; i < sbi->s_ndevs; i++) { > + if (FDEV(i).start_blk <=3D blk_addr && > + FDEV(i).end_blk >=3D blk_addr) { > + blk_addr -=3D FDEV(i).start_blk; > + bdev =3D FDEV(i).bdev; > + break; > + } > + } > + if (bio) { > + bio->bi_bdev =3D bdev; > + bio->bi_iter.bi_sector =3D SECTOR_FROM_BLOCK(blk_addr); > + } > + return bdev; > +} > + > +int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t = blkaddr) > +{ > + int i; > + > + for (i =3D 0; i < sbi->s_ndevs; i++) > + if (FDEV(i).start_blk <=3D blkaddr && FDEV(i).end_blk >=3D= blkaddr) > + return i; > + return 0; > +} > + > +static bool __same_bdev(struct f2fs_sb_info *sbi, > + block_t blk_addr, struct bio *bio) > +{ > + return f2fs_target_device(sbi, blk_addr, NULL) =3D=3D = bio->bi_bdev; > +} > + > +/* > * Low-level block read/write IO operations. > */ > static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t = blk_addr, > @@ -97,8 +137,7 @@ static struct bio *__bio_alloc(struct f2fs_sb_info = *sbi, block_t blk_addr, >=20 > bio =3D f2fs_bio_alloc(npages); >=20 > - bio->bi_bdev =3D sbi->sb->s_bdev; > - bio->bi_iter.bi_sector =3D SECTOR_FROM_BLOCK(blk_addr); > + f2fs_target_device(sbi, blk_addr, bio); > bio->bi_end_io =3D is_read ? f2fs_read_end_io : = f2fs_write_end_io; > bio->bi_private =3D is_read ? NULL : sbi; >=20 > @@ -273,7 +312,8 @@ void f2fs_submit_page_mbio(struct f2fs_io_info = *fio) > down_write(&io->io_rwsem); >=20 > if (io->bio && (io->last_block_in_bio !=3D fio->new_blkaddr - 1 = || > - (io->fio.op !=3D fio->op || io->fio.op_flags !=3D = fio->op_flags))) > + (io->fio.op !=3D fio->op || io->fio.op_flags !=3D = fio->op_flags) || > + !__same_bdev(sbi, fio->new_blkaddr, io->bio))) > __submit_merged_bio(io); > alloc_new: > if (io->bio =3D=3D NULL) { > @@ -965,7 +1005,6 @@ static struct bio *f2fs_grab_bio(struct inode = *inode, block_t blkaddr, > { > struct f2fs_sb_info *sbi =3D F2FS_I_SB(inode); > struct fscrypt_ctx *ctx =3D NULL; > - struct block_device *bdev =3D sbi->sb->s_bdev; > struct bio *bio; >=20 > if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { > @@ -983,8 +1022,7 @@ static struct bio *f2fs_grab_bio(struct inode = *inode, block_t blkaddr, > fscrypt_release_ctx(ctx); > return ERR_PTR(-ENOMEM); > } > - bio->bi_bdev =3D bdev; > - bio->bi_iter.bi_sector =3D SECTOR_FROM_BLOCK(blkaddr); > + f2fs_target_device(sbi, blkaddr, bio); > bio->bi_end_io =3D f2fs_read_end_io; > bio->bi_private =3D ctx; >=20 > @@ -1079,7 +1117,8 @@ static int f2fs_mpage_readpages(struct = address_space *mapping, > * This page will go to BIO. Do we need to send this > * BIO off first? > */ > - if (bio && (last_block_in_bio !=3D block_nr - 1)) { > + if (bio && (last_block_in_bio !=3D block_nr - 1 || > + !__same_bdev(F2FS_I_SB(inode), block_nr, bio))) = { > submit_and_realloc: > __submit_bio(F2FS_I_SB(inode), bio, DATA); > bio =3D NULL; > @@ -1738,6 +1777,8 @@ static ssize_t f2fs_direct_IO(struct kiocb = *iocb, struct iov_iter *iter) > return 0; > if (test_opt(F2FS_I_SB(inode), LFS)) > return 0; > + if (F2FS_I_SB(inode)->s_ndevs) > + return 0; >=20 > trace_f2fs_direct_IO_enter(inode, offset, count, rw); >=20 > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index 9650514..1737c45 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -730,6 +730,20 @@ struct f2fs_bio_info { > struct rw_semaphore io_rwsem; /* blocking op for bio */ > }; >=20 > +#define FDEV(i) (sbi->devs[i]) > +#define RDEV(i) (raw_super->devs[i]) > +struct f2fs_dev_info { > + struct block_device *bdev; > + char path[MAX_PATH_LEN]; > + unsigned int total_segments; > + block_t start_blk; > + block_t end_blk; > +#ifdef CONFIG_BLK_DEV_ZONED > + unsigned int nr_blkz; /* Total number of zones = */ > + u8 *blkz_type; /* Array of zones type = */ > +#endif > +}; > + > enum inode_type { > DIR_INODE, /* for dirty dir inode */ > FILE_INODE, /* for dirty regular/symlink = inode */ > @@ -778,10 +792,8 @@ struct f2fs_sb_info { > #endif >=20 > #ifdef CONFIG_BLK_DEV_ZONED > - unsigned int nr_blkz; /* Total number of zones = */ > unsigned int blocks_per_blkz; /* F2FS blocks per zone = */ > unsigned int log_blocks_per_blkz; /* log2 F2FS blocks per = zone */ > - u8 *blkz_type; /* Array of zones type = */ > #endif >=20 > /* for node-related operations */ > @@ -897,6 +909,8 @@ struct f2fs_sb_info { >=20 > /* For shrinker support */ > struct list_head s_list; > + int s_ndevs; /* number of devices */ > + struct f2fs_dev_info *devs; /* for device list */ > struct mutex umount_mutex; > unsigned int shrinker_run_no; >=20 > @@ -2159,6 +2173,9 @@ void f2fs_submit_merged_bio_cond(struct = f2fs_sb_info *, struct inode *, > void f2fs_flush_merged_bios(struct f2fs_sb_info *); > int f2fs_submit_page_bio(struct f2fs_io_info *); > void f2fs_submit_page_mbio(struct f2fs_io_info *); > +struct block_device *f2fs_target_device(struct f2fs_sb_info *, > + block_t, struct bio *); > +int f2fs_target_device_index(struct f2fs_sb_info *, block_t); > void set_data_blkaddr(struct dnode_of_data *); > void f2fs_update_data_blkaddr(struct dnode_of_data *, block_t); > int reserve_new_blocks(struct dnode_of_data *, blkcnt_t); > @@ -2446,11 +2463,15 @@ static inline int = f2fs_sb_mounted_blkzoned(struct super_block *sb) >=20 > #ifdef CONFIG_BLK_DEV_ZONED > static inline int get_blkz_type(struct f2fs_sb_info *sbi, > - block_t blkaddr) > + struct block_device *bdev, block_t blkaddr) > { > unsigned int zno =3D blkaddr >> sbi->log_blocks_per_blkz; > + int i; >=20 > - return sbi->blkz_type[zno]; > + for (i =3D 0; i < sbi->s_ndevs; i++) > + if (FDEV(i).bdev =3D=3D bdev) > + return FDEV(i).blkz_type[zno]; > + return -EINVAL; > } > #endif >=20 > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index 7fb7dd3..ef727d1 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -403,6 +403,33 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) > } > } >=20 > +static int __submit_flush_wait(struct block_device *bdev) > +{ > + struct bio *bio =3D f2fs_bio_alloc(0); > + int ret; > + > + bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); > + bio->bi_bdev =3D bdev; > + ret =3D submit_bio_wait(bio); > + bio_put(bio); > + return ret; > +} > + > +static int submit_flush_wait(struct f2fs_sb_info *sbi) > +{ > + int ret =3D __submit_flush_wait(sbi->sb->s_bdev); > + int i; > + > + if (sbi->s_ndevs && !ret) { > + for (i =3D 1; i < sbi->s_ndevs; i++) { > + ret =3D __submit_flush_wait(FDEV(i).bdev); > + if (ret) > + break; > + } > + } > + return ret; > +} > + > static int issue_flush_thread(void *data) > { > struct f2fs_sb_info *sbi =3D data; > @@ -413,25 +440,18 @@ static int issue_flush_thread(void *data) > return 0; >=20 > if (!llist_empty(&fcc->issue_list)) { > - struct bio *bio; > struct flush_cmd *cmd, *next; > int ret; >=20 > - bio =3D f2fs_bio_alloc(0); > - > fcc->dispatch_list =3D llist_del_all(&fcc->issue_list); > fcc->dispatch_list =3D = llist_reverse_order(fcc->dispatch_list); >=20 > - bio->bi_bdev =3D sbi->sb->s_bdev; > - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); > - ret =3D submit_bio_wait(bio); > - > + ret =3D submit_flush_wait(sbi); > llist_for_each_entry_safe(cmd, next, > fcc->dispatch_list, llnode) { > cmd->ret =3D ret; > complete(&cmd->wait); > } > - bio_put(bio); > fcc->dispatch_list =3D NULL; > } >=20 > @@ -452,15 +472,11 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi) > return 0; >=20 > if (!test_opt(sbi, FLUSH_MERGE) || = !atomic_read(&fcc->submit_flush)) { > - struct bio *bio =3D f2fs_bio_alloc(0); > int ret; >=20 > atomic_inc(&fcc->submit_flush); > - bio->bi_bdev =3D sbi->sb->s_bdev; > - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); > - ret =3D submit_bio_wait(bio); > + ret =3D submit_flush_wait(sbi); > atomic_dec(&fcc->submit_flush); > - bio_put(bio); > return ret; > } >=20 > @@ -637,14 +653,18 @@ static void f2fs_submit_bio_wait_endio(struct = bio *bio) >=20 > /* this function is copied from blkdev_issue_discard from = block/blk-lib.c */ > static int __f2fs_issue_discard_async(struct f2fs_sb_info *sbi, > - block_t blkstart, block_t blklen) > + struct block_device *bdev, block_t blkstart, block_t = blklen) > { > - struct block_device *bdev =3D sbi->sb->s_bdev; > struct bio *bio =3D NULL; > int err; >=20 > trace_f2fs_issue_discard(sbi->sb, blkstart, blklen); >=20 > + if (sbi->s_ndevs) { > + int devi =3D f2fs_target_device_index(sbi, blkstart); > + > + blkstart -=3D FDEV(devi).start_blk; > + } > err =3D __blkdev_issue_discard(bdev, > SECTOR_FROM_BLOCK(blkstart), > SECTOR_FROM_BLOCK(blklen), > @@ -662,18 +682,24 @@ static int __f2fs_issue_discard_async(struct = f2fs_sb_info *sbi, > } >=20 > #ifdef CONFIG_BLK_DEV_ZONED > -static int f2fs_issue_discard_zone(struct f2fs_sb_info *sbi, > - block_t blkstart, block_t = blklen) > +static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi, > + struct block_device *bdev, block_t blkstart, block_t = blklen) > { > - sector_t sector =3D SECTOR_FROM_BLOCK(blkstart); > sector_t nr_sects =3D SECTOR_FROM_BLOCK(blklen); > - struct block_device *bdev =3D sbi->sb->s_bdev; > + sector_t sector; > + int devi =3D 0; >=20 > - if (nr_sects !=3D bdev_zone_size(bdev)) { > + if (sbi->s_ndevs) { > + devi =3D f2fs_target_device_index(sbi, blkstart); > + blkstart -=3D FDEV(devi).start_blk; > + } > + sector =3D SECTOR_FROM_BLOCK(blkstart); > + > + if (sector % bdev_zone_size(bdev) || nr_sects !=3D = bdev_zone_size(bdev)) { > f2fs_msg(sbi->sb, KERN_INFO, > - "Unaligned discard attempted (sector %llu + = %llu)", > - (unsigned long long)sector, > - (unsigned long long)nr_sects); > + "(%d) %s: Unaligned discard attempted (block %x = + %x)", > + devi, sbi->s_ndevs ? FDEV(devi).path: "", > + blkstart, blklen); > return -EIO; > } >=20 > @@ -682,14 +708,12 @@ static int f2fs_issue_discard_zone(struct = f2fs_sb_info *sbi, > * use regular discard if the drive supports it. For sequential > * zones, reset the zone write pointer. > */ > - switch (get_blkz_type(sbi, blkstart)) { > + switch (get_blkz_type(sbi, bdev, blkstart)) { >=20 > case BLK_ZONE_TYPE_CONVENTIONAL: > if (!blk_queue_discard(bdev_get_queue(bdev))) > return 0; > - return __f2fs_issue_discard_async(sbi, blkstart, > - blklen); > - > + return __f2fs_issue_discard_async(sbi, bdev, blkstart, = blklen); > case BLK_ZONE_TYPE_SEQWRITE_REQ: > case BLK_ZONE_TYPE_SEQWRITE_PREF: > trace_f2fs_issue_reset_zone(sbi->sb, blkstart); > @@ -702,14 +726,45 @@ static int f2fs_issue_discard_zone(struct = f2fs_sb_info *sbi, > } > #endif >=20 > +static int __issue_discard_async(struct f2fs_sb_info *sbi, > + struct block_device *bdev, block_t blkstart, block_t = blklen) > +{ > +#ifdef CONFIG_BLK_DEV_ZONED > + if (f2fs_sb_mounted_blkzoned(sbi->sb) && > + bdev_zoned_model(bdev) !=3D = BLK_ZONED_NONE) > + return __f2fs_issue_discard_zone(sbi, bdev, blkstart, = blklen); > +#endif > + return __f2fs_issue_discard_async(sbi, bdev, blkstart, blklen); > +} > + > static int f2fs_issue_discard(struct f2fs_sb_info *sbi, > block_t blkstart, block_t blklen) > { > + sector_t start =3D blkstart, len =3D 0; > + struct block_device *bdev; > struct seg_entry *se; > unsigned int offset; > block_t i; > + int err =3D 0; > + > + bdev =3D f2fs_target_device(sbi, blkstart, NULL); > + > + for (i =3D blkstart; i < blkstart + blklen; i++, len++) { > + if (i !=3D start) { > + struct block_device *bdev2 =3D > + f2fs_target_device(sbi, i, NULL); > + > + if (bdev2 !=3D bdev) { > + err =3D __issue_discard_async(sbi, bdev, > + start, len); > + if (err) > + return err; > + bdev =3D bdev2; > + start =3D i; > + len =3D 0; > + } > + } >=20 > - for (i =3D blkstart; i < blkstart + blklen; i++) { > se =3D get_seg_entry(sbi, GET_SEGNO(sbi, i)); > offset =3D GET_BLKOFF_FROM_SEG0(sbi, i); >=20 > @@ -717,11 +772,9 @@ static int f2fs_issue_discard(struct f2fs_sb_info = *sbi, > sbi->discard_blks--; > } >=20 > -#ifdef CONFIG_BLK_DEV_ZONED > - if (f2fs_sb_mounted_blkzoned(sbi->sb)) > - return f2fs_issue_discard_zone(sbi, blkstart, blklen); > -#endif > - return __f2fs_issue_discard_async(sbi, blkstart, blklen); > + if (len) > + err =3D __issue_discard_async(sbi, bdev, start, len); > + return err; > } >=20 > static void __add_discard_entry(struct f2fs_sb_info *sbi, > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c > index eca9aea..4ccbb86 100644 > --- a/fs/f2fs/super.c > +++ b/fs/f2fs/super.c > @@ -713,6 +713,19 @@ static void destroy_percpu_info(struct = f2fs_sb_info *sbi) > percpu_counter_destroy(&sbi->total_valid_inode_count); > } >=20 > +static void destroy_device_list(struct f2fs_sb_info *sbi) > +{ > + int i; > + > + for (i =3D 0; i < sbi->s_ndevs; i++) { > + blkdev_put(FDEV(i).bdev, FMODE_EXCL); > +#ifdef CONFIG_BLK_DEV_ZONED > + kfree(FDEV(i).blkz_type); > +#endif > + } > + kfree(sbi->devs); > +} > + > static void f2fs_put_super(struct super_block *sb) > { > struct f2fs_sb_info *sbi =3D F2FS_SB(sb); > @@ -773,6 +786,8 @@ static void f2fs_put_super(struct super_block *sb) > crypto_free_shash(sbi->s_chksum_driver); > kfree(sbi->raw_super); >=20 > + destroy_device_list(sbi); > + > destroy_percpu_info(sbi); > kfree(sbi); > } > @@ -1516,9 +1531,9 @@ static int init_percpu_info(struct f2fs_sb_info = *sbi) > } >=20 > #ifdef CONFIG_BLK_DEV_ZONED > -static int init_blkz_info(struct f2fs_sb_info *sbi) > +static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) > { > - struct block_device *bdev =3D sbi->sb->s_bdev; > + struct block_device *bdev =3D FDEV(devi).bdev; > sector_t nr_sectors =3D bdev->bd_part->nr_sects; > sector_t sector =3D 0; > struct blk_zone *zones; > @@ -1529,15 +1544,21 @@ static int init_blkz_info(struct f2fs_sb_info = *sbi) > if (!f2fs_sb_mounted_blkzoned(sbi->sb)) > return 0; >=20 > + if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=3D > + SECTOR_TO_BLOCK(bdev_zone_size(bdev))) > + return -EINVAL; > sbi->blocks_per_blkz =3D SECTOR_TO_BLOCK(bdev_zone_size(bdev)); > + if (sbi->log_blocks_per_blkz && sbi->log_blocks_per_blkz !=3D > + __ilog2_u32(sbi->blocks_per_blkz)) > + return -EINVAL; > sbi->log_blocks_per_blkz =3D __ilog2_u32(sbi->blocks_per_blkz); > - sbi->nr_blkz =3D SECTOR_TO_BLOCK(nr_sectors) >> > - sbi->log_blocks_per_blkz; > + FDEV(devi).nr_blkz =3D SECTOR_TO_BLOCK(nr_sectors) >> > + sbi->log_blocks_per_blkz; > if (nr_sectors & (bdev_zone_size(bdev) - 1)) > - sbi->nr_blkz++; > + FDEV(devi).nr_blkz++; >=20 > - sbi->blkz_type =3D kmalloc(sbi->nr_blkz, GFP_KERNEL); > - if (!sbi->blkz_type) > + FDEV(devi).blkz_type =3D kmalloc(FDEV(devi).nr_blkz, = GFP_KERNEL); > + if (!FDEV(devi).blkz_type) > return -ENOMEM; >=20 > #define F2FS_REPORT_NR_ZONES 4096 > @@ -1562,7 +1583,7 @@ static int init_blkz_info(struct f2fs_sb_info = *sbi) > } >=20 > for (i =3D 0; i < nr_zones; i++) { > - sbi->blkz_type[n] =3D zones[i].type; > + FDEV(devi).blkz_type[n] =3D zones[i].type; > sector +=3D zones[i].len; > n++; > } > @@ -1666,6 +1687,77 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, = bool recover) > return err; > } >=20 > +static int f2fs_scan_devices(struct f2fs_sb_info *sbi) > +{ > + struct f2fs_super_block *raw_super =3D F2FS_RAW_SUPER(sbi); > + int i; > + > + for (i =3D 0; i < MAX_DEVICES; i++) { > + if (!RDEV(i).path[0]) > + return 0; > + > + if (i =3D=3D 0) { > + sbi->devs =3D kzalloc(sizeof(struct = f2fs_dev_info) * > + MAX_DEVICES, = GFP_KERNEL); > + if (!sbi->devs) > + return -ENOMEM; > + } > + > + memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN); > + FDEV(i).total_segments =3D = le32_to_cpu(RDEV(i).total_segments); > + if (i =3D=3D 0) { > + FDEV(i).start_blk =3D 0; > + FDEV(i).end_blk =3D FDEV(i).start_blk + > + (FDEV(i).total_segments << > + sbi->log_blocks_per_seg) - 1 + > + = le32_to_cpu(raw_super->segment0_blkaddr); > + } else { > + FDEV(i).start_blk =3D FDEV(i - 1).end_blk + 1; > + FDEV(i).end_blk =3D FDEV(i).start_blk + > + (FDEV(i).total_segments << > + sbi->log_blocks_per_seg) - 1; > + } > + > + FDEV(i).bdev =3D blkdev_get_by_path(FDEV(i).path, > + sbi->sb->s_mode, = sbi->sb->s_type); > + if (IS_ERR(FDEV(i).bdev)) > + return PTR_ERR(FDEV(i).bdev); > + > + /* to release errored devices */ > + sbi->s_ndevs =3D i + 1; > + > +#ifdef CONFIG_BLK_DEV_ZONED > + if (bdev_zoned_model(FDEV(i).bdev) =3D=3D BLK_ZONED_HM = && > + !f2fs_sb_mounted_blkzoned(sbi->sb)) { > + f2fs_msg(sbi->sb, KERN_ERR, > + "Zoned block device feature not = enabled\n"); > + return -EINVAL; > + } > + if (bdev_zoned_model(FDEV(i).bdev) !=3D BLK_ZONED_NONE) = { > + if (init_blkz_info(sbi, i)) { > + f2fs_msg(sbi->sb, KERN_ERR, > + "Failed to initialize F2FS = blkzone information"); > + return -EINVAL; > + } > + f2fs_msg(sbi->sb, KERN_INFO, > + "Mount Device [%2d]: %20s, %8u, %8x - = %8x (zone: %s)", > + i, FDEV(i).path, > + FDEV(i).total_segments, > + FDEV(i).start_blk, FDEV(i).end_blk, > + bdev_zoned_model(FDEV(i).bdev) =3D=3D = BLK_ZONED_HA ? > + "Host-aware" : "Host-managed"); > + continue; > + } > +#endif > + f2fs_msg(sbi->sb, KERN_INFO, > + "Mount Device [%2d]: %20s, %8u, %8x - %8x", > + i, FDEV(i).path, > + FDEV(i).total_segments, > + FDEV(i).start_blk, FDEV(i).end_blk); > + } > + return 0; > +} > + > static int f2fs_fill_super(struct super_block *sb, void *data, int = silent) > { > struct f2fs_sb_info *sbi; > @@ -1724,15 +1816,7 @@ static int f2fs_fill_super(struct super_block = *sb, void *data, int silent) > "Zoned block device support is not enabled\n"); > goto free_sb_buf; > } > -#else > - if (bdev_zoned_model(sb->s_bdev) =3D=3D BLK_ZONED_HM && > - !f2fs_sb_mounted_blkzoned(sb)) { > - f2fs_msg(sb, KERN_ERR, > - "Zoned block device feature not enabled\n"); > - goto free_sb_buf; > - } > #endif > - > default_options(sbi); > /* parse mount options */ > options =3D kstrdup((const char *)data, GFP_KERNEL); > @@ -1802,6 +1886,13 @@ static int f2fs_fill_super(struct super_block = *sb, void *data, int silent) > goto free_meta_inode; > } >=20 > + /* Initialize device list */ > + err =3D f2fs_scan_devices(sbi); > + if (err) { > + f2fs_msg(sb, KERN_ERR, "Failed to find devices"); > + goto free_devices; > + } > + > sbi->total_valid_node_count =3D > = le32_to_cpu(sbi->ckpt->valid_node_count); > percpu_counter_set(&sbi->total_valid_inode_count, > @@ -1820,15 +1911,6 @@ static int f2fs_fill_super(struct super_block = *sb, void *data, int silent) >=20 > init_ino_entry_info(sbi); >=20 > -#ifdef CONFIG_BLK_DEV_ZONED > - err =3D init_blkz_info(sbi); > - if (err) { > - f2fs_msg(sb, KERN_ERR, > - "Failed to initialize F2FS blkzone = information"); > - goto free_blkz; > - } > -#endif > - > /* setup f2fs internal modules */ > err =3D build_segment_manager(sbi); > if (err) { > @@ -2007,10 +2089,8 @@ static int f2fs_fill_super(struct super_block = *sb, void *data, int silent) > destroy_node_manager(sbi); > free_sm: > destroy_segment_manager(sbi); > -#ifdef CONFIG_BLK_DEV_ZONED > -free_blkz: > - kfree(sbi->blkz_type); > -#endif > +free_devices: > + destroy_device_list(sbi); > kfree(sbi->ckpt); > free_meta_inode: > make_bad_inode(sbi->meta_inode); > diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h > index 422630b..cea41a1 100644 > --- a/include/linux/f2fs_fs.h > +++ b/include/linux/f2fs_fs.h > @@ -52,10 +52,17 @@ >=20 > #define VERSION_LEN 256 > #define MAX_VOLUME_NAME 512 > +#define MAX_PATH_LEN 64 > +#define MAX_DEVICES 8 >=20 > /* > * For superblock > */ > +struct f2fs_device { > + __u8 path[MAX_PATH_LEN]; > + __le32 total_segments; > +} __packed; > + > struct f2fs_super_block { > __le32 magic; /* Magic Number */ > __le16 major_ver; /* Major Version */ > @@ -94,7 +101,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 */ > } __packed; >=20 > /* > -- > 2.8.3 Cheers, Andreas --Apple-Mail=_BA06BDC1-F1E9-47DD-A826-6669C35625EE Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=signature.asc Content-Type: application/pgp-signature; name=signature.asc Content-Description: Message signed with OpenPGP using GPGMail -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org iQIVAwUBWCOp8nKl2rkXzB/gAQhk0g/7BhOJ930i/wnB/3lZfaANTj27ZxH4kZF9 psQQwoJu8uZRLUhWKAqHh1jDMEUnPpsbdZLzhWG+0jYxc2WhEerrvmaZoN741UOm +tpR3ecfmhlUSajDerlttcUHvhwdA6G3J0PGO67E5XbF4yM/MGbCLvHs3pdUKFi+ naM+C1HGGZBr5u8tdEsjsKZYE8UaSu0g0MpbZuwyYqwxb5vO+6JSSockAFazTbLz QSTLgHgcVHBanc21v4G9RlOxDyAjGLHhs0qIcd9kz/AkBvn8SyiRmpbLFU/k/IG5 6EdfrwHweBKnX7OKTmINmvBZDGld/AlB1DkQ/y0BLt6h9mBxcdRtzHUG9T7FL04K 3WMxL30IT4g1qxY69IKNQpPyqBaFtYAVpEEopMjla6B8SMJE7PCxRLdMu2RBbFpT EHnNDp7MyraG3piOQGoMySD4MnkyJJnD8KF3PRghxS9ZcNPv7JPCQb3K0IQuLXPf U4SyfcNYv8PBQNGmQnHmXyDBJdaep4zArnyf24i1JI+hT8WvXclQ26yRfo3Zq1cg pGO42oSn/3n0i2ww8MskRo1aHF7GQbcuZLVYy5YiYexdt6f43hcRHGeS4yTC0lzI WOhJ2F33q1JcDLiVOI05ygVlhF0cyHCfX5I04PKvk8WViOYakYHXrOVuleopmGxZ 8AiHA24QuOg= =6Yjv -----END PGP SIGNATURE----- --Apple-Mail=_BA06BDC1-F1E9-47DD-A826-6669C35625EE--