diff options
Diffstat (limited to 'drivers/infiniband/core/device.c')
| -rw-r--r-- | drivers/infiniband/core/device.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 8872453e26c0..238ec42778ef 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c | |||
| @@ -156,19 +156,26 @@ struct ib_device *ib_device_get_by_index(u32 index) | |||
| 156 | down_read(&lists_rwsem); | 156 | down_read(&lists_rwsem); |
| 157 | device = __ib_device_get_by_index(index); | 157 | device = __ib_device_get_by_index(index); |
| 158 | if (device) { | 158 | if (device) { |
| 159 | /* Do not return a device if unregistration has started. */ | 159 | if (!ib_device_try_get(device)) |
| 160 | if (!refcount_inc_not_zero(&device->refcount)) | ||
| 161 | device = NULL; | 160 | device = NULL; |
| 162 | } | 161 | } |
| 163 | up_read(&lists_rwsem); | 162 | up_read(&lists_rwsem); |
| 164 | return device; | 163 | return device; |
| 165 | } | 164 | } |
| 166 | 165 | ||
| 166 | /** | ||
| 167 | * ib_device_put - Release IB device reference | ||
| 168 | * @device: device whose reference to be released | ||
| 169 | * | ||
| 170 | * ib_device_put() releases reference to the IB device to allow it to be | ||
| 171 | * unregistered and eventually free. | ||
| 172 | */ | ||
| 167 | void ib_device_put(struct ib_device *device) | 173 | void ib_device_put(struct ib_device *device) |
| 168 | { | 174 | { |
| 169 | if (refcount_dec_and_test(&device->refcount)) | 175 | if (refcount_dec_and_test(&device->refcount)) |
| 170 | complete(&device->unreg_completion); | 176 | complete(&device->unreg_completion); |
| 171 | } | 177 | } |
| 178 | EXPORT_SYMBOL(ib_device_put); | ||
| 172 | 179 | ||
| 173 | static struct ib_device *__ib_device_get_by_name(const char *name) | 180 | static struct ib_device *__ib_device_get_by_name(const char *name) |
| 174 | { | 181 | { |
| @@ -303,7 +310,6 @@ struct ib_device *ib_alloc_device(size_t size) | |||
| 303 | rwlock_init(&device->client_data_lock); | 310 | rwlock_init(&device->client_data_lock); |
| 304 | INIT_LIST_HEAD(&device->client_data_list); | 311 | INIT_LIST_HEAD(&device->client_data_list); |
| 305 | INIT_LIST_HEAD(&device->port_list); | 312 | INIT_LIST_HEAD(&device->port_list); |
| 306 | refcount_set(&device->refcount, 1); | ||
| 307 | init_completion(&device->unreg_completion); | 313 | init_completion(&device->unreg_completion); |
| 308 | 314 | ||
| 309 | return device; | 315 | return device; |
| @@ -620,6 +626,7 @@ int ib_register_device(struct ib_device *device, const char *name, | |||
| 620 | goto cg_cleanup; | 626 | goto cg_cleanup; |
| 621 | } | 627 | } |
| 622 | 628 | ||
| 629 | refcount_set(&device->refcount, 1); | ||
| 623 | device->reg_state = IB_DEV_REGISTERED; | 630 | device->reg_state = IB_DEV_REGISTERED; |
| 624 | 631 | ||
| 625 | list_for_each_entry(client, &client_list, list) | 632 | list_for_each_entry(client, &client_list, list) |
