mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
scsi: lpfc: Fix invalid sleeping context in lpfc_sli4_nvmet_alloc()
commit62e3a931dbupstream. The following calltrace was seen: BUG: sleeping function called from invalid context at mm/slab.h:494 ... Call Trace: dump_stack+0x9a/0xf0 ___might_sleep.cold.63+0x13d/0x178 slab_pre_alloc_hook+0x6a/0x90 kmem_cache_alloc_trace+0x3a/0x2d0 lpfc_sli4_nvmet_alloc+0x4c/0x280 [lpfc] lpfc_post_rq_buffer+0x2e7/0xa60 [lpfc] lpfc_sli4_hba_setup+0x6b4c/0xa4b0 [lpfc] lpfc_pci_probe_one_s4.isra.15+0x14f8/0x2280 [lpfc] lpfc_pci_probe_one+0x260/0x2880 [lpfc] local_pci_probe+0xd4/0x180 work_for_cpu_fn+0x51/0xa0 process_one_work+0x8f0/0x17b0 worker_thread+0x536/0xb50 kthread+0x30c/0x3d0 ret_from_fork+0x3a/0x50 A prior patch introduced a spin_lock_irqsave(hbalock) in the lpfc_post_rq_buffer() routine. Call trace is seen as the hbalock is held with interrupts disabled during a GFP_KERNEL allocation in lpfc_sli4_nvmet_alloc(). Fix by reordering locking so that hbalock not held when calling sli4_nvmet_alloc() (aka rqb_buf_list()). Link: https://lore.kernel.org/r/20201020202719.54726-2-james.smart@broadcom.com Fixes:411de511c6("scsi: lpfc: Fix RQ empty firmware trap") Cc: <stable@vger.kernel.org> # v4.17+ Co-developed-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: James Smart <james.smart@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
6a6754485b
commit
0af3d9342c
@@ -588,8 +588,6 @@ lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab)
|
|||||||
* Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI
|
* Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI
|
||||||
* pool along a non-DMA-mapped container for it.
|
* pool along a non-DMA-mapped container for it.
|
||||||
*
|
*
|
||||||
* Notes: Not interrupt-safe. Must be called with no locks held.
|
|
||||||
*
|
|
||||||
* Returns:
|
* Returns:
|
||||||
* pointer to HBQ on success
|
* pointer to HBQ on success
|
||||||
* NULL on failure
|
* NULL on failure
|
||||||
@@ -599,7 +597,7 @@ lpfc_sli4_nvmet_alloc(struct lpfc_hba *phba)
|
|||||||
{
|
{
|
||||||
struct rqb_dmabuf *dma_buf;
|
struct rqb_dmabuf *dma_buf;
|
||||||
|
|
||||||
dma_buf = kzalloc(sizeof(struct rqb_dmabuf), GFP_KERNEL);
|
dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL);
|
||||||
if (!dma_buf)
|
if (!dma_buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -7248,12 +7248,16 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
|
|||||||
struct rqb_dmabuf *rqb_buffer;
|
struct rqb_dmabuf *rqb_buffer;
|
||||||
LIST_HEAD(rqb_buf_list);
|
LIST_HEAD(rqb_buf_list);
|
||||||
|
|
||||||
spin_lock_irqsave(&phba->hbalock, flags);
|
|
||||||
rqbp = hrq->rqbp;
|
rqbp = hrq->rqbp;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
|
spin_lock_irqsave(&phba->hbalock, flags);
|
||||||
/* IF RQ is already full, don't bother */
|
/* IF RQ is already full, don't bother */
|
||||||
if (rqbp->buffer_count + i >= rqbp->entry_count - 1)
|
if (rqbp->buffer_count + i >= rqbp->entry_count - 1) {
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||||
|
|
||||||
rqb_buffer = rqbp->rqb_alloc_buffer(phba);
|
rqb_buffer = rqbp->rqb_alloc_buffer(phba);
|
||||||
if (!rqb_buffer)
|
if (!rqb_buffer)
|
||||||
break;
|
break;
|
||||||
@@ -7262,6 +7266,8 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
|
|||||||
rqb_buffer->idx = idx;
|
rqb_buffer->idx = idx;
|
||||||
list_add_tail(&rqb_buffer->hbuf.list, &rqb_buf_list);
|
list_add_tail(&rqb_buffer->hbuf.list, &rqb_buf_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&phba->hbalock, flags);
|
||||||
while (!list_empty(&rqb_buf_list)) {
|
while (!list_empty(&rqb_buf_list)) {
|
||||||
list_remove_head(&rqb_buf_list, rqb_buffer, struct rqb_dmabuf,
|
list_remove_head(&rqb_buf_list, rqb_buffer, struct rqb_dmabuf,
|
||||||
hbuf.list);
|
hbuf.list);
|
||||||
|
|||||||
Reference in New Issue
Block a user