Skip to content

Commit 3457c04

Browse files
Alex Williamsongregkh
authored andcommitted
vfio: New external user group/file match
commit 5d6dee80a1e94cc284d03e06d930e60e8d3ecf7d upstream. At the point where the kvm-vfio pseudo device wants to release its vfio group reference, we can't always acquire a new reference to make that happen. The group can be in a state where we wouldn't allow a new reference to be added. This new helper function allows a caller to match a file to a group to facilitate this. Given a file and group, report if they match. Thus the caller needs to already have a group reference to match to the file. This allows the deletion of a group without acquiring a new reference. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent db42944 commit 3457c04

3 files changed

Lines changed: 30 additions & 8 deletions

File tree

drivers/vfio/vfio.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,15 @@ void vfio_group_put_external_user(struct vfio_group *group)
15871587
}
15881588
EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
15891589

1590+
bool vfio_external_group_match_file(struct vfio_group *test_group,
1591+
struct file *filep)
1592+
{
1593+
struct vfio_group *group = filep->private_data;
1594+
1595+
return (filep->f_op == &vfio_group_fops) && (group == test_group);
1596+
}
1597+
EXPORT_SYMBOL_GPL(vfio_external_group_match_file);
1598+
15901599
int vfio_external_user_iommu_id(struct vfio_group *group)
15911600
{
15921601
return iommu_group_id(group->iommu_group);

include/linux/vfio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ extern void vfio_unregister_iommu_driver(
8585
*/
8686
extern struct vfio_group *vfio_group_get_external_user(struct file *filep);
8787
extern void vfio_group_put_external_user(struct vfio_group *group);
88+
extern bool vfio_external_group_match_file(struct vfio_group *group,
89+
struct file *filep);
8890
extern int vfio_external_user_iommu_id(struct vfio_group *group);
8991
extern long vfio_external_check_extension(struct vfio_group *group,
9092
unsigned long arg);

virt/kvm/vfio.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ static struct vfio_group *kvm_vfio_group_get_external_user(struct file *filep)
4747
return vfio_group;
4848
}
4949

50+
static bool kvm_vfio_external_group_match_file(struct vfio_group *group,
51+
struct file *filep)
52+
{
53+
bool ret, (*fn)(struct vfio_group *, struct file *);
54+
55+
fn = symbol_get(vfio_external_group_match_file);
56+
if (!fn)
57+
return false;
58+
59+
ret = fn(group, filep);
60+
61+
symbol_put(vfio_external_group_match_file);
62+
63+
return ret;
64+
}
65+
5066
static void kvm_vfio_group_put_external_user(struct vfio_group *vfio_group)
5167
{
5268
void (*fn)(struct vfio_group *);
@@ -171,18 +187,13 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
171187
if (!f.file)
172188
return -EBADF;
173189

174-
vfio_group = kvm_vfio_group_get_external_user(f.file);
175-
fdput(f);
176-
177-
if (IS_ERR(vfio_group))
178-
return PTR_ERR(vfio_group);
179-
180190
ret = -ENOENT;
181191

182192
mutex_lock(&kv->lock);
183193

184194
list_for_each_entry(kvg, &kv->group_list, node) {
185-
if (kvg->vfio_group != vfio_group)
195+
if (!kvm_vfio_external_group_match_file(kvg->vfio_group,
196+
f.file))
186197
continue;
187198

188199
list_del(&kvg->node);
@@ -196,7 +207,7 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
196207

197208
mutex_unlock(&kv->lock);
198209

199-
kvm_vfio_group_put_external_user(vfio_group);
210+
fdput(f);
200211

201212
kvm_vfio_update_coherency(dev);
202213

0 commit comments

Comments
 (0)