Devices might report a really large REPORT LUN buffer, which will cause kmalloc to bail if it can't allocate enough continuguous pages. However, at that time we already have received a perfectly good response, so we should continue using that buffer to allow us to register at least the LUNs from the 'good' response. Signed-off-by: Hannes Reinecke <hare@xxxxxxx> --- drivers/scsi/scsi_scan.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 82a00d7751b3..0a344653487d 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1290,7 +1290,8 @@ static int scsi_report_lun_scan(struct scsi_target *starget, blist_flags_t bflag struct scsi_sense_hdr sshdr; struct scsi_device *sdev; struct Scsi_Host *shost = dev_to_shost(&starget->dev); - int ret = 0; + int ret = 0, alloc_flags = + shost->unchecked_isa_dma ? __GFP_DMA : 0; /* * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. @@ -1327,14 +1328,13 @@ static int scsi_report_lun_scan(struct scsi_target *starget, blist_flags_t bflag * value of the now removed max_report_luns parameter. */ length = (511 + 1) * sizeof(struct scsi_lun); -retry: - lun_data = kmalloc(length, GFP_KERNEL | - (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); + lun_data = kmalloc(length, GFP_KERNEL | alloc_flags); if (!lun_data) { printk(ALLOC_FAILURE_MSG, __func__); goto out; } +retry: scsi_cmd[0] = REPORT_LUNS; /* @@ -1395,12 +1395,21 @@ static int scsi_report_lun_scan(struct scsi_target *starget, blist_flags_t bflag */ if (get_unaligned_be32(lun_data->scsi_lun) + sizeof(struct scsi_lun) > length) { - length = get_unaligned_be32(lun_data->scsi_lun) + + unsigned int resp_length; + void *resp_data; + + resp_length = get_unaligned_be32(lun_data->scsi_lun) + sizeof(struct scsi_lun); - kfree(lun_data); - goto retry; - } - length = get_unaligned_be32(lun_data->scsi_lun); + resp_data = kmalloc(resp_length, GFP_KERNEL | alloc_flags); + if (resp_data) { + kfree(lun_data); + lun_data = resp_data; + length = resp_length; + goto retry; + } + printk(ALLOC_FAILURE_MSG, __func__); + } else + length = get_unaligned_be32(lun_data->scsi_lun); num_luns = (length / sizeof(struct scsi_lun)); -- 2.16.4