Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

Ming Lei and committed by
Martin K. Petersen
edb854a3 936bd034

+50 -5
+50 -5
drivers/scsi/scsi_scan.c
··· 214 214 SCSI_TIMEOUT, 3, NULL); 215 215 } 216 216 217 + static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev, 218 + unsigned int depth) 219 + { 220 + int new_shift = sbitmap_calculate_shift(depth); 221 + bool need_alloc = !sdev->budget_map.map; 222 + bool need_free = false; 223 + int ret; 224 + struct sbitmap sb_backup; 225 + 226 + /* 227 + * realloc if new shift is calculated, which is caused by setting 228 + * up one new default queue depth after calling ->slave_configure 229 + */ 230 + if (!need_alloc && new_shift != sdev->budget_map.shift) 231 + need_alloc = need_free = true; 232 + 233 + if (!need_alloc) 234 + return 0; 235 + 236 + /* 237 + * Request queue has to be frozen for reallocating budget map, 238 + * and here disk isn't added yet, so freezing is pretty fast 239 + */ 240 + if (need_free) { 241 + blk_mq_freeze_queue(sdev->request_queue); 242 + sb_backup = sdev->budget_map; 243 + } 244 + ret = sbitmap_init_node(&sdev->budget_map, 245 + scsi_device_max_queue_depth(sdev), 246 + new_shift, GFP_KERNEL, 247 + sdev->request_queue->node, false, true); 248 + if (need_free) { 249 + if (ret) 250 + sdev->budget_map = sb_backup; 251 + else 252 + sbitmap_free(&sb_backup); 253 + ret = 0; 254 + blk_mq_unfreeze_queue(sdev->request_queue); 255 + } 256 + return ret; 257 + } 258 + 217 259 /** 218 260 * scsi_alloc_sdev - allocate and setup a scsi_Device 219 261 * @starget: which target to allocate a &scsi_device for ··· 348 306 * default device queue depth to figure out sbitmap shift 349 307 * since we use this queue depth most of times. 350 308 */ 351 - if (sbitmap_init_node(&sdev->budget_map, 352 - scsi_device_max_queue_depth(sdev), 353 - sbitmap_calculate_shift(depth), 354 - GFP_KERNEL, sdev->request_queue->node, 355 - false, true)) { 309 + if (scsi_realloc_sdev_budget_map(sdev, depth)) { 356 310 put_device(&starget->dev); 357 311 kfree(sdev); 358 312 goto out; ··· 1055 1017 } 1056 1018 return SCSI_SCAN_NO_RESPONSE; 1057 1019 } 1020 + 1021 + /* 1022 + * The queue_depth is often changed in ->slave_configure. 1023 + * Set up budget map again since memory consumption of 1024 + * the map depends on actual queue depth. 1025 + */ 1026 + scsi_realloc_sdev_budget_map(sdev, sdev->queue_depth); 1058 1027 } 1059 1028 1060 1029 if (sdev->scsi_level >= SCSI_3)