diff --git a/block/partition-generic.c b/block/partition-generic.c index 1d20c9cf213f..564fae77711d 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -321,6 +321,24 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, const char *dname; 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); if (err) return ERR_PTR(err); @@ -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, &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", disk->disk_name, p, -PTR_ERR(part)); return true; @@ -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)) { - pr_warn("%s: ignoring partition table on zoned block device\n", + if (disk->queue->limits.zoned == BLK_ZONED_HM) { + pr_warn("%s: ignoring partition table on host managed zoned block device\n", disk->disk_name); ret = 0; goto out_free_state; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index cea625906440..122e77855ea0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2956,15 +2956,16 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) q->limits.zoned = BLK_ZONED_HM; } else { sdkp->zoned = (buffer[8] >> 4) & 3; - if (sdkp->zoned == 1) + if (sdkp->zoned == 1 && !disk_has_partitions(sdkp->disk)) { /* Host-aware */ q->limits.zoned = BLK_ZONED_HA; - else + } else { /* - * Treat drive-managed devices as - * regular block devices. + * Treat drive-managed devices and host-aware devices + * with partitions as regular block devices. */ q->limits.zoned = BLK_ZONED_NONE; + } } if (blk_queue_is_zoned(q) && sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n", diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 8bb63027e4d6..ea4c133b4139 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -245,6 +245,18 @@ static inline bool disk_part_scan_enabled(struct gendisk *disk) !(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) { return MKDEV(disk->major, disk->first_minor);