mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
f2fs: Fix zoned block device support
The introduction of the multi-device feature partially broke the support
for zoned block devices. In the function f2fs_scan_devices, sbi->devs
allocation and initialization is skipped in the case of a single device
mount. This result in no device information structure being allocated
for the device. This is fine if the device is a regular device, but in
the case of a zoned block device, the device zone type array is not
initialized, which causes the function __f2fs_issue_discard_zone to fail
as get_blkz_type is unable to determine the zone type of a section.
Fix this by always allocating and initializing the sbi->devs device
information array even in the case of a single device if that device is
zoned. For this particular case, make sure to obtain a reference on the
single device so that the call to blkdev_put() in destroy_device_list
operates as expected.
Fixes: 3c62be17d4
("f2fs: support multiple devices")
Cc: <stable@vger.kernel.org> # v4.10
Signed-off-by: Masato Suzuki <masato.suzuki@wdc.com>
Acked-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
4fcf589ad4
commit
7bb3a371d1
@ -1743,36 +1743,55 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
|
||||
static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
|
||||
unsigned int max_devices = MAX_DEVICES;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DEVICES; i++) {
|
||||
if (!RDEV(i).path[0])
|
||||
/* Initialize single device information */
|
||||
if (!RDEV(0).path[0]) {
|
||||
if (!bdev_is_zoned(sbi->sb->s_bdev))
|
||||
return 0;
|
||||
max_devices = 1;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
sbi->devs = kzalloc(sizeof(struct f2fs_dev_info) *
|
||||
MAX_DEVICES, GFP_KERNEL);
|
||||
if (!sbi->devs)
|
||||
return -ENOMEM;
|
||||
}
|
||||
/*
|
||||
* Initialize multiple devices information, or single
|
||||
* zoned block device information.
|
||||
*/
|
||||
sbi->devs = kcalloc(max_devices, sizeof(struct f2fs_dev_info),
|
||||
GFP_KERNEL);
|
||||
if (!sbi->devs)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN);
|
||||
FDEV(i).total_segments = le32_to_cpu(RDEV(i).total_segments);
|
||||
if (i == 0) {
|
||||
FDEV(i).start_blk = 0;
|
||||
FDEV(i).end_blk = 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 = FDEV(i - 1).end_blk + 1;
|
||||
FDEV(i).end_blk = FDEV(i).start_blk +
|
||||
(FDEV(i).total_segments <<
|
||||
sbi->log_blocks_per_seg) - 1;
|
||||
}
|
||||
for (i = 0; i < max_devices; i++) {
|
||||
|
||||
FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path,
|
||||
if (i > 0 && !RDEV(i).path[0])
|
||||
break;
|
||||
|
||||
if (max_devices == 1) {
|
||||
/* Single zoned block device mount */
|
||||
FDEV(0).bdev =
|
||||
blkdev_get_by_dev(sbi->sb->s_bdev->bd_dev,
|
||||
sbi->sb->s_mode, sbi->sb->s_type);
|
||||
} else {
|
||||
/* Multi-device mount */
|
||||
memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN);
|
||||
FDEV(i).total_segments =
|
||||
le32_to_cpu(RDEV(i).total_segments);
|
||||
if (i == 0) {
|
||||
FDEV(i).start_blk = 0;
|
||||
FDEV(i).end_blk = 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 = FDEV(i - 1).end_blk + 1;
|
||||
FDEV(i).end_blk = FDEV(i).start_blk +
|
||||
(FDEV(i).total_segments <<
|
||||
sbi->log_blocks_per_seg) - 1;
|
||||
}
|
||||
FDEV(i).bdev = 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);
|
||||
|
||||
@ -1792,6 +1811,8 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
|
||||
"Failed to initialize F2FS blkzone information");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (max_devices == 1)
|
||||
break;
|
||||
f2fs_msg(sbi->sb, KERN_INFO,
|
||||
"Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)",
|
||||
i, FDEV(i).path,
|
||||
|
Loading…
Reference in New Issue
Block a user