aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Le Moal <damien.lemoal@wdc.com>2017-08-08 23:00:22 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2017-08-16 20:01:31 -0400
commit70e42fd02c46e2aa9ab07b766d418637e3a51de7 (patch)
tree2f59f796eb5a19d660f3277869042a9bf144d52a
parentc80267324938a5517fd31fa4bbd2d63c564401f9 (diff)
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>
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/sd_zbc.c9
-rw-r--r--include/scsi/scsi_cmnd.h1
3 files changed, 9 insertions, 4 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index bea36adeee17..e2647f2d4430 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1277,6 +1277,9 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
1277{ 1277{
1278 struct request *rq = SCpnt->request; 1278 struct request *rq = SCpnt->request;
1279 1279
1280 if (SCpnt->flags & SCMD_ZONE_WRITE_LOCK)
1281 sd_zbc_write_unlock_zone(SCpnt);
1282
1280 if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) 1283 if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
1281 __free_page(rq->special_vec.bv_page); 1284 __free_page(rq->special_vec.bv_page);
1282 1285
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 96855df9f49d..8aa54779aac1 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -294,6 +294,9 @@ int sd_zbc_write_lock_zone(struct scsi_cmnd *cmd)
294 test_and_set_bit(zno, sdkp->zones_wlock)) 294 test_and_set_bit(zno, sdkp->zones_wlock))
295 return BLKPREP_DEFER; 295 return BLKPREP_DEFER;
296 296
297 WARN_ON_ONCE(cmd->flags & SCMD_ZONE_WRITE_LOCK);
298 cmd->flags |= SCMD_ZONE_WRITE_LOCK;
299
297 return BLKPREP_OK; 300 return BLKPREP_OK;
298} 301}
299 302
@@ -302,9 +305,10 @@ void sd_zbc_write_unlock_zone(struct scsi_cmnd *cmd)
302 struct request *rq = cmd->request; 305 struct request *rq = cmd->request;
303 struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); 306 struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
304 307
305 if (sdkp->zones_wlock) { 308 if (sdkp->zones_wlock && cmd->flags & SCMD_ZONE_WRITE_LOCK) {
306 unsigned int zno = sd_zbc_zone_no(sdkp, blk_rq_pos(rq)); 309 unsigned int zno = sd_zbc_zone_no(sdkp, blk_rq_pos(rq));
307 WARN_ON_ONCE(!test_bit(zno, sdkp->zones_wlock)); 310 WARN_ON_ONCE(!test_bit(zno, sdkp->zones_wlock));
311 cmd->flags &= ~SCMD_ZONE_WRITE_LOCK;
308 clear_bit_unlock(zno, sdkp->zones_wlock); 312 clear_bit_unlock(zno, sdkp->zones_wlock);
309 smp_mb__after_atomic(); 313 smp_mb__after_atomic();
310 } 314 }
@@ -335,9 +339,6 @@ void sd_zbc_complete(struct scsi_cmnd *cmd,
335 case REQ_OP_WRITE_ZEROES: 339 case REQ_OP_WRITE_ZEROES:
336 case REQ_OP_WRITE_SAME: 340 case REQ_OP_WRITE_SAME:
337 341
338 /* Unlock the zone */
339 sd_zbc_write_unlock_zone(cmd);
340
341 if (result && 342 if (result &&
342 sshdr->sense_key == ILLEGAL_REQUEST && 343 sshdr->sense_key == ILLEGAL_REQUEST &&
343 sshdr->asc == 0x21) 344 sshdr->asc == 0x21)
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index a1266d318c85..6af198d8120b 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -57,6 +57,7 @@ struct scsi_pointer {
57/* for scmd->flags */ 57/* for scmd->flags */
58#define SCMD_TAGGED (1 << 0) 58#define SCMD_TAGGED (1 << 0)
59#define SCMD_UNCHECKED_ISA_DMA (1 << 1) 59#define SCMD_UNCHECKED_ISA_DMA (1 << 1)
60#define SCMD_ZONE_WRITE_LOCK (1 << 2)
60 61
61struct scsi_cmnd { 62struct scsi_cmnd {
62 struct scsi_request req; 63 struct scsi_request req;