Skip to content

Commit 3977372

Browse files
sd: Make discard granularity match logical block size when LBPRZ=1
A device may report an OPTIMAL UNMAP GRANULARITY and UNMAP GRANULARITY ALIGNMENT in the Block Limits VPD. These parameters describe the device's internal provisioning allocation units. By default the block layer will round and align any discard requests based on these limits. If a device reports LBPRZ=1 to guarantee zeroes after discard, however, it is imperative that the block layer does not leave out any parts of the requested block range. Otherwise the device can not do the required zeroing of any partial allocation units and this can lead to data corruption. Since the dm thinp personality relies on the block layer's current behavior and is unable to deal with partial discard blocks we work around the problem by setting the granularity to match the logical block size when LBPRZ is enabled. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 653cfb8 commit 3977372

1 file changed

Lines changed: 18 additions & 5 deletions

File tree

drivers/scsi/sd.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -637,11 +637,24 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
637637
unsigned int max_blocks = 0;
638638

639639
q->limits.discard_zeroes_data = 0;
640-
q->limits.discard_alignment = sdkp->unmap_alignment *
641-
logical_block_size;
642-
q->limits.discard_granularity =
643-
max(sdkp->physical_block_size,
644-
sdkp->unmap_granularity * logical_block_size);
640+
641+
/*
642+
* When LBPRZ is reported, discard alignment and granularity
643+
* must be fixed to the logical block size. Otherwise the block
644+
* layer will drop misaligned portions of the request which can
645+
* lead to data corruption. If LBPRZ is not set, we honor the
646+
* device preference.
647+
*/
648+
if (sdkp->lbprz) {
649+
q->limits.discard_alignment = 0;
650+
q->limits.discard_granularity = 1;
651+
} else {
652+
q->limits.discard_alignment = sdkp->unmap_alignment *
653+
logical_block_size;
654+
q->limits.discard_granularity =
655+
max(sdkp->physical_block_size,
656+
sdkp->unmap_granularity * logical_block_size);
657+
}
645658

646659
sdkp->provisioning_mode = mode;
647660

0 commit comments

Comments
 (0)