Skip to content

Commit

Permalink
sd: Limit transfer length
Browse files Browse the repository at this point in the history
Until now the per-command transfer length has exclusively been gated by
the max_sectors parameter in the scsi_host template. Given that the size
of this parameter has been bumped to an unsigned int we have to be
careful not to exceed the target device's capabilities.

If the if the device specifies a Maximum Transfer Length in the Block
Limits VPD we'll use that value. Otherwise we'll use 0xffffffff for
devices that have use_16_for_rw set and 0xffff for the rest. We then
combine the chosen disk limit with max_sectors in the host template. The
smaller of the two will be used to set the max_hw_sectors queue limit.

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Ewan D. Milne <emilne@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
  • Loading branch information
Martin K. Petersen authored and Christoph Hellwig committed Jul 17, 2014
1 parent 8d96447 commit bcdb247
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 1 deletion.
16 changes: 15 additions & 1 deletion drivers/scsi/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2236,7 +2236,11 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
}
}

sdp->use_16_for_rw = (sdkp->capacity > 0xffffffff);
if (sdkp->capacity > 0xffffffff) {
sdp->use_16_for_rw = 1;
sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS;
} else
sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS;

/* Rescale capacity to 512-byte units */
if (sector_size == 4096)
Expand Down Expand Up @@ -2551,13 +2555,18 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
{
unsigned int sector_sz = sdkp->device->sector_size;
const int vpd_len = 64;
u32 max_xfer_length;
unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);

if (!buffer ||
/* Block Limits VPD */
scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
goto out;

max_xfer_length = get_unaligned_be32(&buffer[8]);
if (max_xfer_length)
sdkp->max_xfer_blocks = max_xfer_length;

blk_queue_io_min(sdkp->disk->queue,
get_unaligned_be16(&buffer[6]) * sector_sz);
blk_queue_io_opt(sdkp->disk->queue,
Expand Down Expand Up @@ -2712,6 +2721,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
unsigned char *buffer;
unsigned int max_xfer;

SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
"sd_revalidate_disk\n"));
Expand Down Expand Up @@ -2759,6 +2769,10 @@ static int sd_revalidate_disk(struct gendisk *disk)
*/
sd_set_flush_flag(sdkp);

max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue),
sdkp->max_xfer_blocks);
max_xfer <<= ilog2(sdp->sector_size) - 9;
blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer);
set_capacity(disk, sdkp->capacity);
sd_config_write_same(sdkp);
kfree(buffer);
Expand Down
3 changes: 3 additions & 0 deletions drivers/scsi/sd.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ enum {
};

enum {
SD_DEF_XFER_BLOCKS = 0xffff,
SD_MAX_XFER_BLOCKS = 0xffffffff,
SD_MAX_WS10_BLOCKS = 0xffff,
SD_MAX_WS16_BLOCKS = 0x7fffff,
};
Expand All @@ -64,6 +66,7 @@ struct scsi_disk {
struct gendisk *disk;
atomic_t openers;
sector_t capacity; /* size in 512-byte sectors */
u32 max_xfer_blocks;
u32 max_ws_blocks;
u32 max_unmap_blocks;
u32 unmap_granularity;
Expand Down

0 comments on commit bcdb247

Please sign in to comment.