Skip to content

Commit 70e42fd

Browse files
damien-lemoalmartinkpetersen
authored andcommitted
scsi: sd_zbc: Write unlock zone from sd_uninit_cmnd()
Releasing a zone write lock only when the write commnand that acquired the lock completes can cause deadlocks due to potential command reordering if the lock owning request is requeued and not executed. This problem exists only with the scsi-mq path as, unlike the legacy path, requests are moved out of the dispatch queue before being prepared and so before locking a zone for a write command. Since sd_uninit_cmnd() is now always called when a request is requeued, call sd_zbc_write_unlock_zone() from that function for write requests that acquired a zone lock instead of from sd_done(). Acquisition of a zone lock by a write command is indicated using the new command flag SCMD_ZONE_WRITE_LOCK. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Bart Van Assche <Bart.VanAssche@wdc.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent c802673 commit 70e42fd

File tree

3 files changed

+9
-4
lines changed

3 files changed

+9
-4
lines changed

drivers/scsi/sd.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,9 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
12771277
{
12781278
struct request *rq = SCpnt->request;
12791279

1280+
if (SCpnt->flags & SCMD_ZONE_WRITE_LOCK)
1281+
sd_zbc_write_unlock_zone(SCpnt);
1282+
12801283
if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
12811284
__free_page(rq->special_vec.bv_page);
12821285

drivers/scsi/sd_zbc.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd)
294294
test_and_set_bit(zno, sdkp->zones_wlock))
295295
return BLKPREP_DEFER;
296296

297+
WARN_ON_ONCE(cmd->flags & SCMD_ZONE_WRITE_LOCK);
298+
cmd->flags |= SCMD_ZONE_WRITE_LOCK;
299+
297300
return BLKPREP_OK;
298301
}
299302

@@ -302,9 +305,10 @@ void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd)
302305
struct request *rq = cmd->request;
303306
struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
304307

305-
if (sdkp->zones_wlock) {
308+
if (sdkp->zones_wlock && cmd->flags & SCMD_ZONE_WRITE_LOCK) {
306309
unsigned int zno = sd_zbc_zone_no(sdkp, blk_rq_pos(rq));
307310
WARN_ON_ONCE(!test_bit(zno, sdkp->zones_wlock));
311+
cmd->flags &= ~SCMD_ZONE_WRITE_LOCK;
308312
clear_bit_unlock(zno, sdkp->zones_wlock);
309313
smp_mb__after_atomic();
310314
}
@@ -335,9 +339,6 @@ void sd_zbc_complete(struct scsi_cmnd *cmd,
335339
case REQ_OP_WRITE_ZEROES:
336340
case REQ_OP_WRITE_SAME:
337341

338-
/* Unlock the zone */
339-
sd_zbc_write_unlock_zone(cmd);
340-
341342
if (result &&
342343
sshdr->sense_key == ILLEGAL_REQUEST &&
343344
sshdr->asc == 0x21)

include/scsi/scsi_cmnd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct scsi_pointer {
5757
/* for scmd->flags */
5858
#define SCMD_TAGGED (1 << 0)
5959
#define SCMD_UNCHECKED_ISA_DMA (1 << 1)
60+
#define SCMD_ZONE_WRITE_LOCK (1 << 2)
6061

6162
struct scsi_cmnd {
6263
struct scsi_request req;

0 commit comments

Comments
 (0)