From 98f179a5eaf77eaac49df3d0c217c6eaaba8c0db Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 6 Jul 2016 17:14:47 -0400 Subject: [PATCH] IB/hfi1: Fix sleep inside atomic issue in init_asic_data The critical section should protect only the list traversal and dd->asic_data modification, not the memory allocation. The fix pulls the allocation out of the critical section. Reviewed-by: Dennis Dalessandro Reviewed-by: Sebastian Sanchez Reviewed-by: Dean Luick Signed-off-by: Tadeusz Struk Signed-off-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index f5de851..dad4d0e 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -14113,8 +14113,14 @@ static int init_asic_data(struct hfi1_devdata *dd) { unsigned long flags; struct hfi1_devdata *tmp, *peer = NULL; + struct hfi1_asic_data *asic_data; int ret = 0; + /* pre-allocate the asic structure in case we are the first device */ + asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL); + if (!asic_data) + return -ENOMEM; + spin_lock_irqsave(&hfi1_devs_lock, flags); /* Find our peer device */ list_for_each_entry(tmp, &hfi1_dev_list, list) { @@ -14126,18 +14132,14 @@ static int init_asic_data(struct hfi1_devdata *dd) } if (peer) { + /* use already allocated structure */ dd->asic_data = peer->asic_data; + kfree(asic_data); } else { - dd->asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL); - if (!dd->asic_data) { - ret = -ENOMEM; - goto done; - } + dd->asic_data = asic_data; mutex_init(&dd->asic_data->asic_resource_mutex); } dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */ - -done: spin_unlock_irqrestore(&hfi1_devs_lock, flags); return ret; } -- 2.7.4