diff options
author | Tadeusz Struk <tadeusz.struk@intel.com> | 2016-07-06 17:14:47 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2016-07-12 10:46:24 -0400 |
commit | 98f179a5eaf77eaac49df3d0c217c6eaaba8c0db (patch) | |
tree | 4b15d13bca8be3cb662896164d3bf04bac91ede9 | |
parent | 896ce45da2c2f4abc508d443fdecde7de0b3fa7e (diff) |
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 <dennis.dalessandro@intel.com>
Reviewed-by: Sebastian Sanchez <sebastian.sanchez@intel.com>
Reviewed-by: Dean Luick <dean.luick@intel.com>
Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/hw/hfi1/chip.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index f5de85178055..dad4d0ebbdff 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) | |||
14113 | { | 14113 | { |
14114 | unsigned long flags; | 14114 | unsigned long flags; |
14115 | struct hfi1_devdata *tmp, *peer = NULL; | 14115 | struct hfi1_devdata *tmp, *peer = NULL; |
14116 | struct hfi1_asic_data *asic_data; | ||
14116 | int ret = 0; | 14117 | int ret = 0; |
14117 | 14118 | ||
14119 | /* pre-allocate the asic structure in case we are the first device */ | ||
14120 | asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL); | ||
14121 | if (!asic_data) | ||
14122 | return -ENOMEM; | ||
14123 | |||
14118 | spin_lock_irqsave(&hfi1_devs_lock, flags); | 14124 | spin_lock_irqsave(&hfi1_devs_lock, flags); |
14119 | /* Find our peer device */ | 14125 | /* Find our peer device */ |
14120 | list_for_each_entry(tmp, &hfi1_dev_list, list) { | 14126 | list_for_each_entry(tmp, &hfi1_dev_list, list) { |
@@ -14126,18 +14132,14 @@ static int init_asic_data(struct hfi1_devdata *dd) | |||
14126 | } | 14132 | } |
14127 | 14133 | ||
14128 | if (peer) { | 14134 | if (peer) { |
14135 | /* use already allocated structure */ | ||
14129 | dd->asic_data = peer->asic_data; | 14136 | dd->asic_data = peer->asic_data; |
14137 | kfree(asic_data); | ||
14130 | } else { | 14138 | } else { |
14131 | dd->asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL); | 14139 | dd->asic_data = asic_data; |
14132 | if (!dd->asic_data) { | ||
14133 | ret = -ENOMEM; | ||
14134 | goto done; | ||
14135 | } | ||
14136 | mutex_init(&dd->asic_data->asic_resource_mutex); | 14140 | mutex_init(&dd->asic_data->asic_resource_mutex); |
14137 | } | 14141 | } |
14138 | dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */ | 14142 | dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */ |
14139 | |||
14140 | done: | ||
14141 | spin_unlock_irqrestore(&hfi1_devs_lock, flags); | 14143 | spin_unlock_irqrestore(&hfi1_devs_lock, flags); |
14142 | return ret; | 14144 | return ret; |
14143 | } | 14145 | } |