diff options
author | Jiang Liu <liuj97@gmail.com> | 2012-12-07 15:43:50 -0500 |
---|---|---|
committer | Alex Williamson <alex.williamson@redhat.com> | 2012-12-07 15:43:50 -0500 |
commit | 9df7b25ab71cee770826d1e7983eb8b6715543d6 (patch) | |
tree | 4aaf6a8dd26d823ef587354704f40e76dd3f8211 /drivers/vfio/vfio.c | |
parent | 2007722a606bf9f195217f7afd2fbee4bc202c42 (diff) |
VFIO: unregister IOMMU notifier on error recovery path
On error recovery path in function vfio_create_group(), it should
unregister the IOMMU notifier for the new VFIO group. Otherwise it may
cause invalid memory access later when handling bus notifications.
Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'drivers/vfio/vfio.c')
-rw-r--r-- | drivers/vfio/vfio.c | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 56097c6d072d..3b7fa7967221 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -191,6 +191,17 @@ static void vfio_container_put(struct vfio_container *container) | |||
191 | kref_put(&container->kref, vfio_container_release); | 191 | kref_put(&container->kref, vfio_container_release); |
192 | } | 192 | } |
193 | 193 | ||
194 | static void vfio_group_unlock_and_free(struct vfio_group *group) | ||
195 | { | ||
196 | mutex_unlock(&vfio.group_lock); | ||
197 | /* | ||
198 | * Unregister outside of lock. A spurious callback is harmless now | ||
199 | * that the group is no longer in vfio.group_list. | ||
200 | */ | ||
201 | iommu_group_unregister_notifier(group->iommu_group, &group->nb); | ||
202 | kfree(group); | ||
203 | } | ||
204 | |||
194 | /** | 205 | /** |
195 | * Group objects - create, release, get, put, search | 206 | * Group objects - create, release, get, put, search |
196 | */ | 207 | */ |
@@ -229,8 +240,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |||
229 | 240 | ||
230 | minor = vfio_alloc_group_minor(group); | 241 | minor = vfio_alloc_group_minor(group); |
231 | if (minor < 0) { | 242 | if (minor < 0) { |
232 | mutex_unlock(&vfio.group_lock); | 243 | vfio_group_unlock_and_free(group); |
233 | kfree(group); | ||
234 | return ERR_PTR(minor); | 244 | return ERR_PTR(minor); |
235 | } | 245 | } |
236 | 246 | ||
@@ -239,8 +249,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |||
239 | if (tmp->iommu_group == iommu_group) { | 249 | if (tmp->iommu_group == iommu_group) { |
240 | vfio_group_get(tmp); | 250 | vfio_group_get(tmp); |
241 | vfio_free_group_minor(minor); | 251 | vfio_free_group_minor(minor); |
242 | mutex_unlock(&vfio.group_lock); | 252 | vfio_group_unlock_and_free(group); |
243 | kfree(group); | ||
244 | return tmp; | 253 | return tmp; |
245 | } | 254 | } |
246 | } | 255 | } |
@@ -249,8 +258,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |||
249 | group, "%d", iommu_group_id(iommu_group)); | 258 | group, "%d", iommu_group_id(iommu_group)); |
250 | if (IS_ERR(dev)) { | 259 | if (IS_ERR(dev)) { |
251 | vfio_free_group_minor(minor); | 260 | vfio_free_group_minor(minor); |
252 | mutex_unlock(&vfio.group_lock); | 261 | vfio_group_unlock_and_free(group); |
253 | kfree(group); | ||
254 | return (struct vfio_group *)dev; /* ERR_PTR */ | 262 | return (struct vfio_group *)dev; /* ERR_PTR */ |
255 | } | 263 | } |
256 | 264 | ||
@@ -274,16 +282,7 @@ static void vfio_group_release(struct kref *kref) | |||
274 | device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor)); | 282 | device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor)); |
275 | list_del(&group->vfio_next); | 283 | list_del(&group->vfio_next); |
276 | vfio_free_group_minor(group->minor); | 284 | vfio_free_group_minor(group->minor); |
277 | 285 | vfio_group_unlock_and_free(group); | |
278 | mutex_unlock(&vfio.group_lock); | ||
279 | |||
280 | /* | ||
281 | * Unregister outside of lock. A spurious callback is harmless now | ||
282 | * that the group is no longer in vfio.group_list. | ||
283 | */ | ||
284 | iommu_group_unregister_notifier(group->iommu_group, &group->nb); | ||
285 | |||
286 | kfree(group); | ||
287 | } | 286 | } |
288 | 287 | ||
289 | static void vfio_group_put(struct vfio_group *group) | 288 | static void vfio_group_put(struct vfio_group *group) |