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.
Unified · Split
| @@ -321,6 +321,24 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, · 320 unmodified lines | |||
| 321 | const char *dname; | 321 | const char *dname; |
| 322 | int err; | 322 | int err; |
| 323 | 323 | ||
| 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 | |||
| 324 | err = disk_expand_part_tbl(disk, partno); | 342 | err = disk_expand_part_tbl(disk, partno); |
| 325 | if (err) | 343 | if (err) |
| 326 | return ERR_PTR(err); | 344 | return ERR_PTR(err); |
| @@ -501,7 +519,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, · 174 unmodified lines | |||
| 501 | 519 | ||
| 502 | part = add_partition(disk, p, from, size, state->parts[p].flags, | 520 | part = add_partition(disk, p, from, size, state->parts[p].flags, |
| 503 | &state->parts[p].info); | 521 | &state->parts[p].info); |
| 504 | if (IS_ERR(part)) { | 522 | if (IS_ERR(part) && PTR_ERR(part) != -ENXIO) { |
| 505 | printk(KERN_ERR " %s: p%d could not be added: %ld\n", | 523 | printk(KERN_ERR " %s: p%d could not be added: %ld\n", |
| 506 | disk->disk_name, p, -PTR_ERR(part)); | 524 | disk->disk_name, p, -PTR_ERR(part)); |
| 507 | return true; | 525 | return true; |
| @@ -540,10 +558,10 @@ int blk_add_partitions(struct gendisk *disk, struct block_device *bdev) · 32 unmodified lines | |||
| 540 | } | 558 | } |
| 541 | 559 | ||
| 542 | /* | 560 | /* |
| 543 | * Partitions are not supported on zoned block devices. | 561 | * Partitions are not supported on host managed zoned block devices. |
| 544 | */ | 562 | */ |
| 545 | if (bdev_is_zoned(bdev)) { | 563 | if (disk->queue->limits.zoned == BLK_ZONED_HM) { |
| 546 | pr_warn("%s: ignoring partition table on zoned block device\n", | 564 | pr_warn("%s: ignoring partition table on host managed zoned block device\n", |
| 547 | disk->disk_name); | 565 | disk->disk_name); |
| 548 | ret = 0; | 566 | ret = 0; |
| 549 | goto out_free_state; | 567 | goto out_free_state; |
| @@ -2956,15 +2956,16 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) · 2955 unmodified lines | |||
| 2956 | q->limits.zoned = BLK_ZONED_HM; | 2956 | q->limits.zoned = BLK_ZONED_HM; |
| 2957 | } else { | 2957 | } else { |
| 2958 | sdkp->zoned = (buffer[8] >> 4) & 3; | 2958 | sdkp->zoned = (buffer[8] >> 4) & 3; |
| 2959 | if (sdkp->zoned == 1) | 2959 | if (sdkp->zoned == 1 && !disk_has_partitions(sdkp->disk)) { |
| 2960 | /* Host-aware */ | 2960 | /* Host-aware */ |
| 2961 | q->limits.zoned = BLK_ZONED_HA; | 2961 | q->limits.zoned = BLK_ZONED_HA; |
| 2962 | else | 2962 | } else { |
| 2963 | /* | 2963 | /* |
| 2964 | * Treat drive-managed devices as | 2964 | * Treat drive-managed devices and host-aware devices |
| 2965 | * regular block devices. | 2965 | * with partitions as regular block devices. |
| 2966 | */ | 2966 | */ |
| 2967 | q->limits.zoned = BLK_ZONED_NONE; | 2967 | q->limits.zoned = BLK_ZONED_NONE; |
| 2968 | } | ||
| 2968 | } | 2969 | } |
| 2969 | if (blk_queue_is_zoned(q) && sdkp->first_scan) | 2970 | if (blk_queue_is_zoned(q) && sdkp->first_scan) |
| 2970 | sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n", | 2971 | 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) · 244 unmodified lines | |||
| 245 | !(disk->flags & GENHD_FL_NO_PART_SCAN); | 245 | !(disk->flags & GENHD_FL_NO_PART_SCAN); |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 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 | |||
| 248 | static inline dev_t disk_devt(struct gendisk *disk) | 260 | static inline dev_t disk_devt(struct gendisk *disk) |
| 249 | { | 261 | { |
| 250 | return MKDEV(disk->major, disk->first_minor); | 262 | return MKDEV(disk->major, disk->first_minor); |