Merge tag 'block-5.5-2020-01-26' of git://git.kernel.dk/linux-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Jan 2020 20:12:36 +0000 (12:12 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Jan 2020 20:12:36 +0000 (12:12 -0800)
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

block/partition-generic.c
drivers/scsi/sd.c
include/linux/genhd.h

index 1d20c9c..564fae7 100644 (file)
@@ -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;
index 65ce10c..902b649 100644 (file)
@@ -2958,15 +2958,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",
index 8bb6302..ea4c133 100644 (file)
@@ -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);