History

block: allow partitions on host aware zone devices

Host-aware SMR drives can be used with the commands to explicitly manage zone state, but they can also be used as normal disks. In the former case it makes perfect sense to allow partitions on them, in the latter it does not, just like for host managed devices. Add a check to add_partition to allow partitions on host aware devices, but give up any zone management capabilities in that case, which also catches the previously missed case of adding a partition vs just scanning it. Because sd can rescan the attribute at runtime it needs to check if a disk has partitions, for which a new helper is added to genhd.h.

Christoph Hellwig committed 6 years ago

Commit b7205301 parent ad6bf883 files · +39 −8Browse files

Unified · Split

3 files
  1. block/partition-generic.c +22 −4
  2. drivers/scsi/sd.c +5 −4
  3. include/linux/genhd.h +12 −0
block/partition-generic.c+22−4
@@ -321,6 +321,24 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, · 320 unmodified lines
321321 const char *dname;
322322 int err;
323323
324+ /*
325+ * Partitions are not supported on zoned block devices that are used as
326+ * such.
327+ */
328+ switch (disk->queue->limits.zoned) {
329+ case BLK_ZONED_HM:
330+ pr_warn("%s: partitions not supported on host managed zoned block device\n",
331+ disk->disk_name);
332+ return ERR_PTR(-ENXIO);
333+ case BLK_ZONED_HA:
334+ pr_info("%s: disabling host aware zoned block device support due to partitions\n",
335+ disk->disk_name);
336+ disk->queue->limits.zoned = BLK_ZONED_NONE;
337+ break;
338+ case BLK_ZONED_NONE:
339+ break;
340+ }
341+
324342 err = disk_expand_part_tbl(disk, partno);
325343 if (err)
326344 return ERR_PTR(err);
@@ -501,7 +519,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, · 174 unmodified lines
501519
502520 part = add_partition(disk, p, from, size, state->parts[p].flags,
503521 &state->parts[p].info);
504− if (IS_ERR(part)) {
522+ if (IS_ERR(part) && PTR_ERR(part) != -ENXIO) {
505523 printk(KERN_ERR " %s: p%d could not be added: %ld\n",
506524 disk->disk_name, p, -PTR_ERR(part));
507525 return true;
@@ -540,10 +558,10 @@ int blk_add_partitions(struct gendisk *disk, struct block_device *bdev) · 32 unmodified lines
540558 }
541559
542560 /*
543− * Partitions are not supported on zoned block devices.
561+ * Partitions are not supported on host managed zoned block devices.
544562 */
545− if (bdev_is_zoned(bdev)) {
546− pr_warn("%s: ignoring partition table on zoned block device\n",
563+ if (disk->queue->limits.zoned == BLK_ZONED_HM) {
564+ pr_warn("%s: ignoring partition table on host managed zoned block device\n",
547565 disk->disk_name);
548566 ret = 0;
549567 goto out_free_state;
drivers/scsi/sd.c+5−4
@@ -2956,15 +2956,16 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) · 2955 unmodified lines
29562956 q->limits.zoned = BLK_ZONED_HM;
29572957 } else {
29582958 sdkp->zoned = (buffer[8] >> 4) & 3;
2959− if (sdkp->zoned == 1)
2959+ if (sdkp->zoned == 1 && !disk_has_partitions(sdkp->disk)) {
29602960 /* Host-aware */
29612961 q->limits.zoned = BLK_ZONED_HA;
2962− else
2962+ } else {
29632963 /*
2964− * Treat drive-managed devices as
2965− * regular block devices.
2964+ * Treat drive-managed devices and host-aware devices
2965+ * with partitions as regular block devices.
29662966 */
29672967 q->limits.zoned = BLK_ZONED_NONE;
2968+ }
29682969 }
29692970 if (blk_queue_is_zoned(q) && sdkp->first_scan)
29702971 sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n",
include/linux/genhd.h+12−0
@@ -245,6 +245,18 @@ static inline bool disk_part_scan_enabled(struct gendisk *disk) · 244 unmodified lines
245245 !(disk->flags & GENHD_FL_NO_PART_SCAN);
246246 }
247247
248+static inline bool disk_has_partitions(struct gendisk *disk)
249+{
250+ bool ret = false;
251+
252+ rcu_read_lock();
253+ if (rcu_dereference(disk->part_tbl)->len > 1)
254+ ret = true;
255+ rcu_read_unlock();
256+
257+ return ret;
258+}
259+
248260 static inline dev_t disk_devt(struct gendisk *disk)
249261 {
250262 return MKDEV(disk->major, disk->first_minor);