diff mbox

[5/5] sd_zbc: Fix handling of ZBC read after write pointer

Message ID 1468934710-93876-6-git-send-email-hare@suse.de (mailing list archive)
State RFC
Headers show

Commit Message

Hannes Reinecke July 19, 2016, 1:25 p.m. UTC
From: Damien Le Moal <damien.lemoal@hgst.com>

For read requests beyond a sequential write required
zone write pointer, zero-out the request buffer and
directly complete the command. For read requests
straddling the write pointer position, limit the
request size to the number of valid sectors. The
remaining will be processed as a second request
and the buffer zeroed out.

Signed-off-by: Damien Le Moal <damien.lemoal@hgst.com>
---
 drivers/scsi/sd.c     |  4 ++--
 drivers/scsi/sd.h     |  4 ++--
 drivers/scsi/sd_zbc.c | 33 +++++++++++++++++++++++++++------
 3 files changed, 31 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3a9d96e..4b704b0 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -881,7 +881,7 @@  static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
 
 	if (sdkp->zoned == 1 || sdp->type == TYPE_ZBC) {
 		/* sd_zbc_setup_read_write uses block layer sector units */
-		ret = sd_zbc_setup_read_write(sdkp, rq, sector, nr_sectors);
+		ret = sd_zbc_setup_read_write(sdkp, rq, sector, &nr_sectors);
 		if (ret != BLKPREP_OK)
 			return ret;
 	}
@@ -1007,7 +1007,7 @@  static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
 
 	if (sdkp->zoned == 1 || sdp->type == TYPE_ZBC) {
 		/* sd_zbc_setup_read_write uses block layer sector units */
-		ret = sd_zbc_setup_read_write(sdkp, rq, block, this_count);
+		ret = sd_zbc_setup_read_write(sdkp, rq, block, &this_count);
 		if (ret != BLKPREP_OK)
 			goto out;
 	}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 5827b62..47f922f 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -293,7 +293,7 @@  extern void sd_zbc_reset_zones(struct scsi_disk *);
 extern int sd_zbc_setup_discard(struct scsi_disk *, struct request *,
 				sector_t, unsigned int);
 extern int sd_zbc_setup_read_write(struct scsi_disk *, struct request *,
-				   sector_t, unsigned int);
+				   sector_t, unsigned int *);
 extern void sd_zbc_update_zones(struct scsi_disk *, sector_t, int, bool);
 extern void sd_zbc_refresh_zone_work(struct work_struct *);
 
@@ -323,7 +323,7 @@  static inline int sd_zbc_setup_discard(struct scsi_disk *sdkp,
 
 static inline int sd_zbc_setup_read_write(struct scsi_disk *sdkp,
 					  struct request *rq, sector_t sector,
-					  unsigned int num_sectors)
+					  unsigned int *num_sectors)
 {
 	return BLKPREP_OK;
 }
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 75cef62..0485c61 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -426,9 +426,10 @@  out:
 }
 
 int sd_zbc_setup_read_write(struct scsi_disk *sdkp, struct request *rq,
-			    sector_t sector, unsigned int num_sectors)
+			    sector_t sector, unsigned int *num_sectors)
 {
 	struct blk_zone *zone;
+	unsigned int sectors = *num_sectors;
 	int ret = BLKPREP_OK;
 	unsigned long flags;
 
@@ -478,12 +479,32 @@  int sd_zbc_setup_read_write(struct scsi_disk *sdkp, struct request *rq,
 			ret = BLKPREP_KILL;
 			goto out;
 		}
-		zone->wp += num_sectors;
-	} else if (blk_zone_is_smr(zone) && (zone->wp <= sector)) {
+		zone->wp += sectors;
+	} else if (zone->type == BLK_ZONE_TYPE_SEQWRITE_REQ &&
+		   zone->wp <= sector + sectors) {
+		if (zone->wp <= sector) {
+			/* Read beyond WP: clear request buffer */
+			struct req_iterator iter;
+			struct bio_vec bvec;
+			void *buf;
+			sd_zbc_debug(sdkp,
+				     "Read beyond wp %zu+%u/%zu\n",
+				     sector, sectors, zone->wp);
+			rq_for_each_segment(bvec, rq, iter) {
+				buf = bvec_kmap_irq(&bvec, &flags);
+				memset(buf, 0, bvec.bv_len);
+				flush_dcache_page(bvec.bv_page);
+				bvec_kunmap_irq(buf, &flags);
+			}
+			ret = BLKPREP_DONE;
+			goto out;
+		}
+		/* Read straddle WP position: limit request size */
+		*num_sectors = zone->wp - sector;
 		sd_zbc_debug(sdkp,
-			     "Read beyond wp %zu/%zu\n",
-			     sector, zone->wp);
-		ret = BLKPREP_DONE;
+			     "Read straddle wp %zu+%u/%zu => %zu+%u\n",
+			     sector, sectors, zone->wp,
+			     sector, *num_sectors);
 	}
 
 out: