Skip to content

Commit

Permalink
scsi: sd_zbc: Write unlock zone from sd_uninit_cmnd()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Damien Le Moal authored and Martin K. Petersen committed Aug 17, 2017
1 parent c802673 commit 70e42fd
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 4 deletions.
3 changes: 3 additions & 0 deletions drivers/scsi/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,9 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
{
struct request *rq = SCpnt->request;

if (SCpnt->flags & SCMD_ZONE_WRITE_LOCK)
sd_zbc_write_unlock_zone(SCpnt);

if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
__free_page(rq->special_vec.bv_page);

Expand Down
9 changes: 5 additions & 4 deletions drivers/scsi/sd_zbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd)
test_and_set_bit(zno, sdkp->zones_wlock))
return BLKPREP_DEFER;

WARN_ON_ONCE(cmd->flags & SCMD_ZONE_WRITE_LOCK);
cmd->flags |= SCMD_ZONE_WRITE_LOCK;

return BLKPREP_OK;
}

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

if (sdkp->zones_wlock) {
if (sdkp->zones_wlock && cmd->flags & SCMD_ZONE_WRITE_LOCK) {
unsigned int zno = sd_zbc_zone_no(sdkp, blk_rq_pos(rq));
WARN_ON_ONCE(!test_bit(zno, sdkp->zones_wlock));
cmd->flags &= ~SCMD_ZONE_WRITE_LOCK;
clear_bit_unlock(zno, sdkp->zones_wlock);
smp_mb__after_atomic();
}
Expand Down Expand Up @@ -335,9 +339,6 @@ void sd_zbc_complete(struct scsi_cmnd *cmd,
case REQ_OP_WRITE_ZEROES:
case REQ_OP_WRITE_SAME:

/* Unlock the zone */
sd_zbc_write_unlock_zone(cmd);

if (result &&
sshdr->sense_key == ILLEGAL_REQUEST &&
sshdr->asc == 0x21)
Expand Down
1 change: 1 addition & 0 deletions include/scsi/scsi_cmnd.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct scsi_pointer {
/* for scmd->flags */
#define SCMD_TAGGED (1 << 0)
#define SCMD_UNCHECKED_ISA_DMA (1 << 1)
#define SCMD_ZONE_WRITE_LOCK (1 << 2)

struct scsi_cmnd {
struct scsi_request req;
Expand Down

0 comments on commit 70e42fd

Please sign in to comment.