Commit 9dbca160 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'block-5.5-2020-01-26' of git://git.kernel.dk/linux-block

Pull block fix from Jens Axboe:
 "Unfortunately this weekend we had a few last minute reports, one was
  for block.

  The partition disable for zoned devices was overly restrictive, it can
  work (and be supported) just fine for host-aware variants.

  Here's a fix ensuring that's the case so we don't break existing users
  of that"

* tag 'block-5.5-2020-01-26' of git://git.kernel.dk/linux-block:
  block: allow partitions on host aware zone devices
parents 54343d95 b7205307
...@@ -321,6 +321,24 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, ...@@ -321,6 +321,24 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
const char *dname; const char *dname;
int err; int err;
/*
* Partitions are not supported on zoned block devices that are used as
* such.
*/
switch (disk->queue->limits.zoned) {
case BLK_ZONED_HM:
pr_warn("%s: partitions not supported on host managed zoned block device\n",
disk->disk_name);
return ERR_PTR(-ENXIO);
case BLK_ZONED_HA:
pr_info("%s: disabling host aware zoned block device support due to partitions\n",
disk->disk_name);
disk->queue->limits.zoned = BLK_ZONED_NONE;
break;
case BLK_ZONED_NONE:
break;
}
err = disk_expand_part_tbl(disk, partno); err = disk_expand_part_tbl(disk, partno);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
...@@ -501,7 +519,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, ...@@ -501,7 +519,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
part = add_partition(disk, p, from, size, state->parts[p].flags, part = add_partition(disk, p, from, size, state->parts[p].flags,
&state->parts[p].info); &state->parts[p].info);
if (IS_ERR(part)) { if (IS_ERR(part) && PTR_ERR(part) != -ENXIO) {
printk(KERN_ERR " %s: p%d could not be added: %ld\n", printk(KERN_ERR " %s: p%d could not be added: %ld\n",
disk->disk_name, p, -PTR_ERR(part)); disk->disk_name, p, -PTR_ERR(part));
return true; return true;
...@@ -540,10 +558,10 @@ int blk_add_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -540,10 +558,10 @@ int blk_add_partitions(struct gendisk *disk, struct block_device *bdev)
} }
/* /*
* Partitions are not supported on zoned block devices. * Partitions are not supported on host managed zoned block devices.
*/ */
if (bdev_is_zoned(bdev)) { if (disk->queue->limits.zoned == BLK_ZONED_HM) {
pr_warn("%s: ignoring partition table on zoned block device\n", pr_warn("%s: ignoring partition table on host managed zoned block device\n",
disk->disk_name); disk->disk_name);
ret = 0; ret = 0;
goto out_free_state; goto out_free_state;
......
...@@ -2958,15 +2958,16 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) ...@@ -2958,15 +2958,16 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
q->limits.zoned = BLK_ZONED_HM; q->limits.zoned = BLK_ZONED_HM;
} else { } else {
sdkp->zoned = (buffer[8] >> 4) & 3; sdkp->zoned = (buffer[8] >> 4) & 3;
if (sdkp->zoned == 1) if (sdkp->zoned == 1 && !disk_has_partitions(sdkp->disk)) {
/* Host-aware */ /* Host-aware */
q->limits.zoned = BLK_ZONED_HA; q->limits.zoned = BLK_ZONED_HA;
else } else {
/* /*
* Treat drive-managed devices as * Treat drive-managed devices and host-aware devices
* regular block devices. * with partitions as regular block devices.
*/ */
q->limits.zoned = BLK_ZONED_NONE; q->limits.zoned = BLK_ZONED_NONE;
}
} }
if (blk_queue_is_zoned(q) && sdkp->first_scan) if (blk_queue_is_zoned(q) && sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n", sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n",
......
...@@ -245,6 +245,18 @@ static inline bool disk_part_scan_enabled(struct gendisk *disk) ...@@ -245,6 +245,18 @@ static inline bool disk_part_scan_enabled(struct gendisk *disk)
!(disk->flags & GENHD_FL_NO_PART_SCAN); !(disk->flags & GENHD_FL_NO_PART_SCAN);
} }
static inline bool disk_has_partitions(struct gendisk *disk)
{
bool ret = false;
rcu_read_lock();
if (rcu_dereference(disk->part_tbl)->len > 1)
ret = true;
rcu_read_unlock();
return ret;
}
static inline dev_t disk_devt(struct gendisk *disk) static inline dev_t disk_devt(struct gendisk *disk)
{ {
return MKDEV(disk->major, disk->first_minor); return MKDEV(disk->major, disk->first_minor);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment