aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vfio/vfio.c
diff options
context:
space:
mode:
authorJiang Liu <liuj97@gmail.com>2012-12-07 15:43:50 -0500
committerAlex Williamson <alex.williamson@redhat.com>2012-12-07 15:43:50 -0500
commit9df7b25ab71cee770826d1e7983eb8b6715543d6 (patch)
tree4aaf6a8dd26d823ef587354704f40e76dd3f8211 /drivers/vfio/vfio.c
parent2007722a606bf9f195217f7afd2fbee4bc202c42 (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.c31
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
194static 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
289static void vfio_group_put(struct vfio_group *group) 288static void vfio_group_put(struct vfio_group *group)