Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scsi: sd: Use the block layer zone append emulation

Set the request queue of a TYPE_ZBC device as needing zone append
emulation by setting the device queue max_zone_append_sectors limit to
0. This enables the block layer generic implementation provided by zone
write plugging. With this, the sd driver will never see a
REQ_OP_ZONE_APPEND request and the zone append emulation code
implemented in sd_zbc.c can be removed.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Tested-by: Hans Holmberg <hans.holmberg@wdc.com>
Tested-by: Dennis Maisenbacher <dennis.maisenbacher@wdc.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Link: https://lore.kernel.org/r/20240408014128.205141-14-dlemoal@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Damien Le Moal and committed by
Jens Axboe
1846f308 f211268e

+10 -352
-8
drivers/scsi/sd.c
··· 1260 1260 } 1261 1261 } 1262 1262 1263 - if (req_op(rq) == REQ_OP_ZONE_APPEND) { 1264 - ret = sd_zbc_prepare_zone_append(cmd, &lba, nr_blocks); 1265 - if (ret) 1266 - goto fail; 1267 - } 1268 - 1269 1263 fua = rq->cmd_flags & REQ_FUA ? 0x8 : 0; 1270 1264 dix = scsi_prot_sg_count(cmd); 1271 1265 dif = scsi_host_dif_capable(cmd->device->host, sdkp->protection_type); ··· 1342 1348 return sd_setup_flush_cmnd(cmd); 1343 1349 case REQ_OP_READ: 1344 1350 case REQ_OP_WRITE: 1345 - case REQ_OP_ZONE_APPEND: 1346 1351 return sd_setup_read_write_cmnd(cmd); 1347 1352 case REQ_OP_ZONE_RESET: 1348 1353 return sd_zbc_setup_zone_mgmt_cmnd(cmd, ZO_RESET_WRITE_POINTER, ··· 3972 3979 struct scsi_disk *sdkp = to_scsi_disk(dev); 3973 3980 3974 3981 ida_free(&sd_index_ida, sdkp->index); 3975 - sd_zbc_free_zone_info(sdkp); 3976 3982 put_device(&sdkp->device->sdev_gendev); 3977 3983 free_opal_dev(sdkp->opal_dev); 3978 3984
-19
drivers/scsi/sd.h
··· 104 104 * between zone starting LBAs is constant. 105 105 */ 106 106 u32 zone_starting_lba_gran; 107 - u32 *zones_wp_offset; 108 - spinlock_t zones_wp_offset_lock; 109 - u32 *rev_wp_offset; 110 - struct mutex rev_mutex; 111 - struct work_struct zone_wp_offset_work; 112 - char *zone_wp_update_buf; 113 107 #endif 114 108 atomic_t openers; 115 109 sector_t capacity; /* size in logical blocks */ ··· 239 245 240 246 #ifdef CONFIG_BLK_DEV_ZONED 241 247 242 - void sd_zbc_free_zone_info(struct scsi_disk *sdkp); 243 248 int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE]); 244 249 int sd_zbc_revalidate_zones(struct scsi_disk *sdkp); 245 250 blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, ··· 248 255 int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, 249 256 unsigned int nr_zones, report_zones_cb cb, void *data); 250 257 251 - blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba, 252 - unsigned int nr_blocks); 253 - 254 258 #else /* CONFIG_BLK_DEV_ZONED */ 255 - 256 - static inline void sd_zbc_free_zone_info(struct scsi_disk *sdkp) {} 257 259 258 260 static inline int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE]) 259 261 { ··· 271 283 unsigned int good_bytes, struct scsi_sense_hdr *sshdr) 272 284 { 273 285 return good_bytes; 274 - } 275 - 276 - static inline blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, 277 - sector_t *lba, 278 - unsigned int nr_blocks) 279 - { 280 - return BLK_STS_TARGET; 281 286 } 282 287 283 288 #define sd_zbc_report_zones NULL
+10 -325
drivers/scsi/sd_zbc.c
··· 23 23 #define CREATE_TRACE_POINTS 24 24 #include "sd_trace.h" 25 25 26 - /** 27 - * sd_zbc_get_zone_wp_offset - Get zone write pointer offset. 28 - * @zone: Zone for which to return the write pointer offset. 29 - * 30 - * Return: offset of the write pointer from the start of the zone. 31 - */ 32 - static unsigned int sd_zbc_get_zone_wp_offset(struct blk_zone *zone) 33 - { 34 - if (zone->type == ZBC_ZONE_TYPE_CONV) 35 - return 0; 36 - 37 - switch (zone->cond) { 38 - case BLK_ZONE_COND_IMP_OPEN: 39 - case BLK_ZONE_COND_EXP_OPEN: 40 - case BLK_ZONE_COND_CLOSED: 41 - return zone->wp - zone->start; 42 - case BLK_ZONE_COND_FULL: 43 - return zone->len; 44 - case BLK_ZONE_COND_EMPTY: 45 - case BLK_ZONE_COND_OFFLINE: 46 - case BLK_ZONE_COND_READONLY: 47 - default: 48 - /* 49 - * Offline and read-only zones do not have a valid 50 - * write pointer. Use 0 as for an empty zone. 51 - */ 52 - return 0; 53 - } 54 - } 55 - 56 26 /* Whether or not a SCSI zone descriptor describes a gap zone. */ 57 27 static bool sd_zbc_is_gap_zone(const u8 buf[64]) 58 28 { ··· 90 120 ret = cb(&zone, idx, data); 91 121 if (ret) 92 122 return ret; 93 - 94 - if (sdkp->rev_wp_offset) 95 - sdkp->rev_wp_offset[idx] = sd_zbc_get_zone_wp_offset(&zone); 96 123 97 124 return 0; 98 125 } ··· 314 347 return BLK_STS_OK; 315 348 } 316 349 317 - #define SD_ZBC_INVALID_WP_OFST (~0u) 318 - #define SD_ZBC_UPDATING_WP_OFST (SD_ZBC_INVALID_WP_OFST - 1) 319 - 320 - static int sd_zbc_update_wp_offset_cb(struct blk_zone *zone, unsigned int idx, 321 - void *data) 322 - { 323 - struct scsi_disk *sdkp = data; 324 - 325 - lockdep_assert_held(&sdkp->zones_wp_offset_lock); 326 - 327 - sdkp->zones_wp_offset[idx] = sd_zbc_get_zone_wp_offset(zone); 328 - 329 - return 0; 330 - } 331 - 332 - /* 333 - * An attempt to append a zone triggered an invalid write pointer error. 334 - * Reread the write pointer of the zone(s) in which the append failed. 335 - */ 336 - static void sd_zbc_update_wp_offset_workfn(struct work_struct *work) 337 - { 338 - struct scsi_disk *sdkp; 339 - unsigned long flags; 340 - sector_t zno; 341 - int ret; 342 - 343 - sdkp = container_of(work, struct scsi_disk, zone_wp_offset_work); 344 - 345 - spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags); 346 - for (zno = 0; zno < sdkp->zone_info.nr_zones; zno++) { 347 - if (sdkp->zones_wp_offset[zno] != SD_ZBC_UPDATING_WP_OFST) 348 - continue; 349 - 350 - spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags); 351 - ret = sd_zbc_do_report_zones(sdkp, sdkp->zone_wp_update_buf, 352 - SD_BUF_SIZE, 353 - zno * sdkp->zone_info.zone_blocks, true); 354 - spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags); 355 - if (!ret) 356 - sd_zbc_parse_report(sdkp, sdkp->zone_wp_update_buf + 64, 357 - zno, sd_zbc_update_wp_offset_cb, 358 - sdkp); 359 - } 360 - spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags); 361 - 362 - scsi_device_put(sdkp->device); 363 - } 364 - 365 - /** 366 - * sd_zbc_prepare_zone_append() - Prepare an emulated ZONE_APPEND command. 367 - * @cmd: the command to setup 368 - * @lba: the LBA to patch 369 - * @nr_blocks: the number of LBAs to be written 370 - * 371 - * Called from sd_setup_read_write_cmnd() for REQ_OP_ZONE_APPEND. 372 - * @sd_zbc_prepare_zone_append() handles the necessary zone wrote locking and 373 - * patching of the lba for an emulated ZONE_APPEND command. 374 - * 375 - * In case the cached write pointer offset is %SD_ZBC_INVALID_WP_OFST it will 376 - * schedule a REPORT ZONES command and return BLK_STS_IOERR. 377 - */ 378 - blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba, 379 - unsigned int nr_blocks) 380 - { 381 - struct request *rq = scsi_cmd_to_rq(cmd); 382 - struct scsi_disk *sdkp = scsi_disk(rq->q->disk); 383 - unsigned int wp_offset, zno = blk_rq_zone_no(rq); 384 - unsigned long flags; 385 - blk_status_t ret; 386 - 387 - ret = sd_zbc_cmnd_checks(cmd); 388 - if (ret != BLK_STS_OK) 389 - return ret; 390 - 391 - if (!blk_rq_zone_is_seq(rq)) 392 - return BLK_STS_IOERR; 393 - 394 - /* Unlock of the write lock will happen in sd_zbc_complete() */ 395 - if (!blk_req_zone_write_trylock(rq)) 396 - return BLK_STS_ZONE_RESOURCE; 397 - 398 - spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags); 399 - wp_offset = sdkp->zones_wp_offset[zno]; 400 - switch (wp_offset) { 401 - case SD_ZBC_INVALID_WP_OFST: 402 - /* 403 - * We are about to schedule work to update a zone write pointer 404 - * offset, which will cause the zone append command to be 405 - * requeued. So make sure that the scsi device does not go away 406 - * while the work is being processed. 407 - */ 408 - if (scsi_device_get(sdkp->device)) { 409 - ret = BLK_STS_IOERR; 410 - break; 411 - } 412 - sdkp->zones_wp_offset[zno] = SD_ZBC_UPDATING_WP_OFST; 413 - schedule_work(&sdkp->zone_wp_offset_work); 414 - fallthrough; 415 - case SD_ZBC_UPDATING_WP_OFST: 416 - ret = BLK_STS_DEV_RESOURCE; 417 - break; 418 - default: 419 - wp_offset = sectors_to_logical(sdkp->device, wp_offset); 420 - if (wp_offset + nr_blocks > sdkp->zone_info.zone_blocks) { 421 - ret = BLK_STS_IOERR; 422 - break; 423 - } 424 - 425 - trace_scsi_prepare_zone_append(cmd, *lba, wp_offset); 426 - *lba += wp_offset; 427 - } 428 - spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags); 429 - if (ret) 430 - blk_req_zone_write_unlock(rq); 431 - return ret; 432 - } 433 - 434 350 /** 435 351 * sd_zbc_setup_zone_mgmt_cmnd - Prepare a zone ZBC_OUT command. The operations 436 352 * can be RESET WRITE POINTER, OPEN, CLOSE or FINISH. ··· 354 504 return BLK_STS_OK; 355 505 } 356 506 357 - static bool sd_zbc_need_zone_wp_update(struct request *rq) 358 - { 359 - switch (req_op(rq)) { 360 - case REQ_OP_ZONE_APPEND: 361 - case REQ_OP_ZONE_FINISH: 362 - case REQ_OP_ZONE_RESET: 363 - case REQ_OP_ZONE_RESET_ALL: 364 - return true; 365 - case REQ_OP_WRITE: 366 - case REQ_OP_WRITE_ZEROES: 367 - return blk_rq_zone_is_seq(rq); 368 - default: 369 - return false; 370 - } 371 - } 372 - 373 - /** 374 - * sd_zbc_zone_wp_update - Update cached zone write pointer upon cmd completion 375 - * @cmd: Completed command 376 - * @good_bytes: Command reply bytes 377 - * 378 - * Called from sd_zbc_complete() to handle the update of the cached zone write 379 - * pointer value in case an update is needed. 380 - */ 381 - static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd, 382 - unsigned int good_bytes) 383 - { 384 - int result = cmd->result; 385 - struct request *rq = scsi_cmd_to_rq(cmd); 386 - struct scsi_disk *sdkp = scsi_disk(rq->q->disk); 387 - unsigned int zno = blk_rq_zone_no(rq); 388 - enum req_op op = req_op(rq); 389 - unsigned long flags; 390 - 391 - /* 392 - * If we got an error for a command that needs updating the write 393 - * pointer offset cache, we must mark the zone wp offset entry as 394 - * invalid to force an update from disk the next time a zone append 395 - * command is issued. 396 - */ 397 - spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags); 398 - 399 - if (result && op != REQ_OP_ZONE_RESET_ALL) { 400 - if (op == REQ_OP_ZONE_APPEND) { 401 - /* Force complete completion (no retry) */ 402 - good_bytes = 0; 403 - scsi_set_resid(cmd, blk_rq_bytes(rq)); 404 - } 405 - 406 - /* 407 - * Force an update of the zone write pointer offset on 408 - * the next zone append access. 409 - */ 410 - if (sdkp->zones_wp_offset[zno] != SD_ZBC_UPDATING_WP_OFST) 411 - sdkp->zones_wp_offset[zno] = SD_ZBC_INVALID_WP_OFST; 412 - goto unlock_wp_offset; 413 - } 414 - 415 - switch (op) { 416 - case REQ_OP_ZONE_APPEND: 417 - trace_scsi_zone_wp_update(cmd, rq->__sector, 418 - sdkp->zones_wp_offset[zno], good_bytes); 419 - rq->__sector += sdkp->zones_wp_offset[zno]; 420 - fallthrough; 421 - case REQ_OP_WRITE_ZEROES: 422 - case REQ_OP_WRITE: 423 - if (sdkp->zones_wp_offset[zno] < sd_zbc_zone_sectors(sdkp)) 424 - sdkp->zones_wp_offset[zno] += 425 - good_bytes >> SECTOR_SHIFT; 426 - break; 427 - case REQ_OP_ZONE_RESET: 428 - sdkp->zones_wp_offset[zno] = 0; 429 - break; 430 - case REQ_OP_ZONE_FINISH: 431 - sdkp->zones_wp_offset[zno] = sd_zbc_zone_sectors(sdkp); 432 - break; 433 - case REQ_OP_ZONE_RESET_ALL: 434 - memset(sdkp->zones_wp_offset, 0, 435 - sdkp->zone_info.nr_zones * sizeof(unsigned int)); 436 - break; 437 - default: 438 - break; 439 - } 440 - 441 - unlock_wp_offset: 442 - spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags); 443 - 444 - return good_bytes; 445 - } 446 - 447 507 /** 448 508 * sd_zbc_complete - ZBC command post processing. 449 509 * @cmd: Completed command ··· 379 619 * so be quiet about the error. 380 620 */ 381 621 rq->rq_flags |= RQF_QUIET; 382 - } else if (sd_zbc_need_zone_wp_update(rq)) 383 - good_bytes = sd_zbc_zone_wp_update(cmd, good_bytes); 384 - 385 - if (req_op(rq) == REQ_OP_ZONE_APPEND) 386 - blk_req_zone_write_unlock(rq); 622 + } 387 623 388 624 return good_bytes; 389 625 } ··· 536 780 sdkp->zone_info.zone_blocks); 537 781 } 538 782 539 - static int sd_zbc_init_disk(struct scsi_disk *sdkp) 540 - { 541 - sdkp->zones_wp_offset = NULL; 542 - spin_lock_init(&sdkp->zones_wp_offset_lock); 543 - sdkp->rev_wp_offset = NULL; 544 - mutex_init(&sdkp->rev_mutex); 545 - INIT_WORK(&sdkp->zone_wp_offset_work, sd_zbc_update_wp_offset_workfn); 546 - sdkp->zone_wp_update_buf = kzalloc(SD_BUF_SIZE, GFP_KERNEL); 547 - if (!sdkp->zone_wp_update_buf) 548 - return -ENOMEM; 549 - 550 - return 0; 551 - } 552 - 553 - void sd_zbc_free_zone_info(struct scsi_disk *sdkp) 554 - { 555 - if (!sdkp->zone_wp_update_buf) 556 - return; 557 - 558 - /* Serialize against revalidate zones */ 559 - mutex_lock(&sdkp->rev_mutex); 560 - 561 - kvfree(sdkp->zones_wp_offset); 562 - sdkp->zones_wp_offset = NULL; 563 - kfree(sdkp->zone_wp_update_buf); 564 - sdkp->zone_wp_update_buf = NULL; 565 - 566 - sdkp->early_zone_info = (struct zoned_disk_info){ }; 567 - sdkp->zone_info = (struct zoned_disk_info){ }; 568 - 569 - mutex_unlock(&sdkp->rev_mutex); 570 - } 571 - 572 - static void sd_zbc_revalidate_zones_cb(struct gendisk *disk) 573 - { 574 - struct scsi_disk *sdkp = scsi_disk(disk); 575 - 576 - swap(sdkp->zones_wp_offset, sdkp->rev_wp_offset); 577 - } 578 - 579 783 /* 580 784 * Call blk_revalidate_disk_zones() if any of the zoned disk properties have 581 785 * changed that make it necessary to call that function. Called by ··· 547 831 struct request_queue *q = disk->queue; 548 832 u32 zone_blocks = sdkp->early_zone_info.zone_blocks; 549 833 unsigned int nr_zones = sdkp->early_zone_info.nr_zones; 550 - int ret = 0; 551 834 unsigned int flags; 552 - 553 - /* 554 - * For all zoned disks, initialize zone append emulation data if not 555 - * already done. 556 - */ 557 - if (sd_is_zoned(sdkp) && !sdkp->zone_wp_update_buf) { 558 - ret = sd_zbc_init_disk(sdkp); 559 - if (ret) 560 - return ret; 561 - } 835 + int ret; 562 836 563 837 /* 564 838 * There is nothing to do for regular disks, including host-aware disks ··· 557 851 if (!blk_queue_is_zoned(q)) 558 852 return 0; 559 853 560 - /* 561 - * Make sure revalidate zones are serialized to ensure exclusive 562 - * updates of the scsi disk data. 563 - */ 564 - mutex_lock(&sdkp->rev_mutex); 565 - 566 854 if (sdkp->zone_info.zone_blocks == zone_blocks && 567 855 sdkp->zone_info.nr_zones == nr_zones && 568 856 disk->nr_zones == nr_zones) 569 - goto unlock; 857 + return 0; 570 858 571 - flags = memalloc_noio_save(); 572 859 sdkp->zone_info.zone_blocks = zone_blocks; 573 860 sdkp->zone_info.nr_zones = nr_zones; 574 - sdkp->rev_wp_offset = kvcalloc(nr_zones, sizeof(u32), GFP_KERNEL); 575 - if (!sdkp->rev_wp_offset) { 576 - ret = -ENOMEM; 577 - memalloc_noio_restore(flags); 578 - goto unlock; 579 - } 580 861 581 862 blk_queue_chunk_sectors(q, 582 863 logical_to_sectors(sdkp->device, zone_blocks)); 583 - blk_queue_max_zone_append_sectors(q, 584 - q->limits.max_segments << PAGE_SECTORS_SHIFT); 585 864 586 - ret = blk_revalidate_disk_zones(disk, sd_zbc_revalidate_zones_cb); 865 + /* Enable block layer zone append emulation */ 866 + blk_queue_max_zone_append_sectors(q, 0); 587 867 868 + flags = memalloc_noio_save(); 869 + ret = blk_revalidate_disk_zones(disk, NULL); 588 870 memalloc_noio_restore(flags); 589 - kvfree(sdkp->rev_wp_offset); 590 - sdkp->rev_wp_offset = NULL; 591 - 592 871 if (ret) { 593 872 sdkp->zone_info = (struct zoned_disk_info){ }; 594 873 sdkp->capacity = 0; 595 - goto unlock; 874 + return ret; 596 875 } 597 876 598 877 sd_zbc_print_zones(sdkp); 599 878 600 - unlock: 601 - mutex_unlock(&sdkp->rev_mutex); 602 - 603 - return ret; 879 + return 0; 604 880 } 605 881 606 882 /** ··· 605 917 if (!sd_is_zoned(sdkp)) { 606 918 /* 607 919 * Device managed or normal SCSI disk, no special handling 608 - * required. Nevertheless, free the disk zone information in 609 - * case the device type changed. 920 + * required. 610 921 */ 611 - sd_zbc_free_zone_info(sdkp); 612 922 return 0; 613 923 } 614 924 ··· 627 941 628 942 /* The drive satisfies the kernel restrictions: set it up */ 629 943 blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q); 630 - blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE); 631 944 if (sdkp->zones_max_open == U32_MAX) 632 945 disk_set_max_open_zones(disk, 0); 633 946 else