diff options
author | Tadeusz Struk <tadeusz.struk@intel.com> | 2016-10-25 11:57:55 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2016-11-15 16:16:41 -0500 |
commit | acd7c8fe14938a315f0ac1b92a92375f7226c2fd (patch) | |
tree | a7c672b8310d578ed82ea0f9f353ee8826abcfd9 /drivers/infiniband/hw/hfi1/file_ops.c | |
parent | d9ac4555fb2bcd6b794aaa0b39acad81111d9f42 (diff) |
IB/hfi1: Fix an Oops on pci device force remove
This patch fixes an Oops on device unbind, when the device is used
by a PSM user process. PSM processes access device resources which
are freed on device removal. Similar protection exists in uverbs
in ib_core for Verbs clients, but PSM doesn't use ib_uverbs hence
a separate protection is required for PSM clients.
Cc: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Dean Luick <dean.luick@intel.com>
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
Diffstat (limited to 'drivers/infiniband/hw/hfi1/file_ops.c')
-rw-r--r-- | drivers/infiniband/hw/hfi1/file_ops.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 677efa0e8cd6..bd786b7bd30b 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c | |||
@@ -172,6 +172,9 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) | |||
172 | struct hfi1_devdata, | 172 | struct hfi1_devdata, |
173 | user_cdev); | 173 | user_cdev); |
174 | 174 | ||
175 | if (!atomic_inc_not_zero(&dd->user_refcount)) | ||
176 | return -ENXIO; | ||
177 | |||
175 | /* Just take a ref now. Not all opens result in a context assign */ | 178 | /* Just take a ref now. Not all opens result in a context assign */ |
176 | kobject_get(&dd->kobj); | 179 | kobject_get(&dd->kobj); |
177 | 180 | ||
@@ -183,11 +186,17 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) | |||
183 | fd->rec_cpu_num = -1; /* no cpu affinity by default */ | 186 | fd->rec_cpu_num = -1; /* no cpu affinity by default */ |
184 | fd->mm = current->mm; | 187 | fd->mm = current->mm; |
185 | atomic_inc(&fd->mm->mm_count); | 188 | atomic_inc(&fd->mm->mm_count); |
186 | } | 189 | fp->private_data = fd; |
190 | } else { | ||
191 | fp->private_data = NULL; | ||
192 | |||
193 | if (atomic_dec_and_test(&dd->user_refcount)) | ||
194 | complete(&dd->user_comp); | ||
187 | 195 | ||
188 | fp->private_data = fd; | 196 | return -ENOMEM; |
197 | } | ||
189 | 198 | ||
190 | return fd ? 0 : -ENOMEM; | 199 | return 0; |
191 | } | 200 | } |
192 | 201 | ||
193 | static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, | 202 | static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, |
@@ -798,6 +807,10 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) | |||
798 | done: | 807 | done: |
799 | mmdrop(fdata->mm); | 808 | mmdrop(fdata->mm); |
800 | kobject_put(&dd->kobj); | 809 | kobject_put(&dd->kobj); |
810 | |||
811 | if (atomic_dec_and_test(&dd->user_refcount)) | ||
812 | complete(&dd->user_comp); | ||
813 | |||
801 | kfree(fdata); | 814 | kfree(fdata); |
802 | return 0; | 815 | return 0; |
803 | } | 816 | } |