@@ -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;
}
@@ -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;
}
@@ -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: