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>
This commit is contained in:
parent
c802673249
commit
70e42fd02c
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue