forked from Minki/linux
scsi: core: Reallocate device's budget map on queue depth change
We currently use ->cmd_per_lun as initial queue depth for setting up the budget_map. Martin Wilck reported that it is common for the queue_depth to be subsequently updated in slave_configure() based on detected hardware characteristics. As a result, for some drivers, the static host template settings for cmd_per_lun and can_queue won't actually get used in practice. And if the default values are used to allocate the budget_map, memory may be consumed unnecessarily. Fix the issue by reallocating the budget_map after ->slave_configure() returns. At that time the device queue_depth should accurately reflect what the hardware needs. Link: https://lore.kernel.org/r/20220127153733.409132-1-ming.lei@redhat.com Cc: Bart Van Assche <bvanassche@acm.org> Reported-by: Martin Wilck <martin.wilck@suse.com> Suggested-by: Martin Wilck <martin.wilck@suse.com> Tested-by: Martin Wilck <mwilck@suse.com> Reviewed-by: Martin Wilck <mwilck@suse.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
936bd03405
commit
edb854a368
@ -214,6 +214,48 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
|
|||||||
SCSI_TIMEOUT, 3, NULL);
|
SCSI_TIMEOUT, 3, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
|
||||||
|
unsigned int depth)
|
||||||
|
{
|
||||||
|
int new_shift = sbitmap_calculate_shift(depth);
|
||||||
|
bool need_alloc = !sdev->budget_map.map;
|
||||||
|
bool need_free = false;
|
||||||
|
int ret;
|
||||||
|
struct sbitmap sb_backup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* realloc if new shift is calculated, which is caused by setting
|
||||||
|
* up one new default queue depth after calling ->slave_configure
|
||||||
|
*/
|
||||||
|
if (!need_alloc && new_shift != sdev->budget_map.shift)
|
||||||
|
need_alloc = need_free = true;
|
||||||
|
|
||||||
|
if (!need_alloc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request queue has to be frozen for reallocating budget map,
|
||||||
|
* and here disk isn't added yet, so freezing is pretty fast
|
||||||
|
*/
|
||||||
|
if (need_free) {
|
||||||
|
blk_mq_freeze_queue(sdev->request_queue);
|
||||||
|
sb_backup = sdev->budget_map;
|
||||||
|
}
|
||||||
|
ret = sbitmap_init_node(&sdev->budget_map,
|
||||||
|
scsi_device_max_queue_depth(sdev),
|
||||||
|
new_shift, GFP_KERNEL,
|
||||||
|
sdev->request_queue->node, false, true);
|
||||||
|
if (need_free) {
|
||||||
|
if (ret)
|
||||||
|
sdev->budget_map = sb_backup;
|
||||||
|
else
|
||||||
|
sbitmap_free(&sb_backup);
|
||||||
|
ret = 0;
|
||||||
|
blk_mq_unfreeze_queue(sdev->request_queue);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scsi_alloc_sdev - allocate and setup a scsi_Device
|
* scsi_alloc_sdev - allocate and setup a scsi_Device
|
||||||
* @starget: which target to allocate a &scsi_device for
|
* @starget: which target to allocate a &scsi_device for
|
||||||
@ -306,11 +348,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
|
|||||||
* default device queue depth to figure out sbitmap shift
|
* default device queue depth to figure out sbitmap shift
|
||||||
* since we use this queue depth most of times.
|
* since we use this queue depth most of times.
|
||||||
*/
|
*/
|
||||||
if (sbitmap_init_node(&sdev->budget_map,
|
if (scsi_realloc_sdev_budget_map(sdev, depth)) {
|
||||||
scsi_device_max_queue_depth(sdev),
|
|
||||||
sbitmap_calculate_shift(depth),
|
|
||||||
GFP_KERNEL, sdev->request_queue->node,
|
|
||||||
false, true)) {
|
|
||||||
put_device(&starget->dev);
|
put_device(&starget->dev);
|
||||||
kfree(sdev);
|
kfree(sdev);
|
||||||
goto out;
|
goto out;
|
||||||
@ -1017,6 +1055,13 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
|
|||||||
}
|
}
|
||||||
return SCSI_SCAN_NO_RESPONSE;
|
return SCSI_SCAN_NO_RESPONSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The queue_depth is often changed in ->slave_configure.
|
||||||
|
* Set up budget map again since memory consumption of
|
||||||
|
* the map depends on actual queue depth.
|
||||||
|
*/
|
||||||
|
scsi_realloc_sdev_budget_map(sdev, sdev->queue_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdev->scsi_level >= SCSI_3)
|
if (sdev->scsi_level >= SCSI_3)
|
||||||
|
Loading…
Reference in New Issue
Block a user