Commit 149487bd authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: Add separate helper for putting borrowed reference to kvm

Add a new helper, kvm_put_kvm_no_destroy(), to handle putting a borrowed
reference[*] to the VM when installing a new file descriptor fails.  KVM
expects the refcount to remain valid in this case, as the in-progress
ioctl() has an explicit reference to the VM.  The primary motiviation
for the helper is to document that the 'kvm' pointer is still valid
after putting the borrowed reference, e.g. to document that doing
mutex(&kvm->lock) immediately after putting a ref to kvm isn't broken.

[*] When exposing a new object to userspace via a file descriptor, e.g.
    a new vcpu, KVM grabs a reference to itself (the VM) prior to making
    the object visible to userspace to avoid prematurely freeing the VM
    in the scenario where userspace immediately closes file descriptor.
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent c90992bf
...@@ -2000,7 +2000,7 @@ int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *ghf) ...@@ -2000,7 +2000,7 @@ int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *ghf)
ret = anon_inode_getfd("kvm-htab", &kvm_htab_fops, ctx, rwflag | O_CLOEXEC); ret = anon_inode_getfd("kvm-htab", &kvm_htab_fops, ctx, rwflag | O_CLOEXEC);
if (ret < 0) { if (ret < 0) {
kfree(ctx); kfree(ctx);
kvm_put_kvm(kvm); kvm_put_kvm_no_destroy(kvm);
return ret; return ret;
} }
......
...@@ -317,7 +317,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, ...@@ -317,7 +317,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
if (ret >= 0) if (ret >= 0)
list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables); list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
else else
kvm_put_kvm(kvm); kvm_put_kvm_no_destroy(kvm);
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
......
...@@ -621,6 +621,7 @@ void kvm_exit(void); ...@@ -621,6 +621,7 @@ void kvm_exit(void);
void kvm_get_kvm(struct kvm *kvm); void kvm_get_kvm(struct kvm *kvm);
void kvm_put_kvm(struct kvm *kvm); void kvm_put_kvm(struct kvm *kvm);
void kvm_put_kvm_no_destroy(struct kvm *kvm);
static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id) static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
{ {
......
...@@ -772,6 +772,18 @@ void kvm_put_kvm(struct kvm *kvm) ...@@ -772,6 +772,18 @@ void kvm_put_kvm(struct kvm *kvm)
} }
EXPORT_SYMBOL_GPL(kvm_put_kvm); EXPORT_SYMBOL_GPL(kvm_put_kvm);
/*
* Used to put a reference that was taken on behalf of an object associated
* with a user-visible file descriptor, e.g. a vcpu or device, if installation
* of the new file descriptor fails and the reference cannot be transferred to
* its final owner. In such cases, the caller is still actively using @kvm and
* will fail miserably if the refcount unexpectedly hits zero.
*/
void kvm_put_kvm_no_destroy(struct kvm *kvm)
{
WARN_ON(refcount_dec_and_test(&kvm->users_count));
}
EXPORT_SYMBOL_GPL(kvm_put_kvm_no_destroy);
static int kvm_vm_release(struct inode *inode, struct file *filp) static int kvm_vm_release(struct inode *inode, struct file *filp)
{ {
...@@ -2679,7 +2691,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) ...@@ -2679,7 +2691,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
kvm_get_kvm(kvm); kvm_get_kvm(kvm);
r = create_vcpu_fd(vcpu); r = create_vcpu_fd(vcpu);
if (r < 0) { if (r < 0) {
kvm_put_kvm(kvm); kvm_put_kvm_no_destroy(kvm);
goto unlock_vcpu_destroy; goto unlock_vcpu_destroy;
} }
...@@ -3117,7 +3129,7 @@ static int kvm_ioctl_create_device(struct kvm *kvm, ...@@ -3117,7 +3129,7 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
kvm_get_kvm(kvm); kvm_get_kvm(kvm);
ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC); ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
if (ret < 0) { if (ret < 0) {
kvm_put_kvm(kvm); kvm_put_kvm_no_destroy(kvm);
mutex_lock(&kvm->lock); mutex_lock(&kvm->lock);
list_del(&dev->vm_node); list_del(&dev->vm_node);
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment