|
@@ -294,32 +294,26 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
|
|
|
struct kvm_create_spapr_tce_64 *args)
|
|
|
{
|
|
|
struct kvmppc_spapr_tce_table *stt = NULL;
|
|
|
+ struct kvmppc_spapr_tce_table *siter;
|
|
|
unsigned long npages, size;
|
|
|
int ret = -ENOMEM;
|
|
|
int i;
|
|
|
+ int fd = -1;
|
|
|
|
|
|
if (!args->size)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- /* Check this LIOBN hasn't been previously allocated */
|
|
|
- list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
|
|
|
- if (stt->liobn == args->liobn)
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
size = _ALIGN_UP(args->size, PAGE_SIZE >> 3);
|
|
|
npages = kvmppc_tce_pages(size);
|
|
|
ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
|
|
|
- if (ret) {
|
|
|
- stt = NULL;
|
|
|
- goto fail;
|
|
|
- }
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
ret = -ENOMEM;
|
|
|
stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
|
|
|
GFP_KERNEL);
|
|
|
if (!stt)
|
|
|
- goto fail;
|
|
|
+ goto fail_acct;
|
|
|
|
|
|
stt->liobn = args->liobn;
|
|
|
stt->page_shift = args->page_shift;
|
|
@@ -334,24 +328,42 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
- kvm_get_kvm(kvm);
|
|
|
+ ret = fd = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
|
|
|
+ stt, O_RDWR | O_CLOEXEC);
|
|
|
+ if (ret < 0)
|
|
|
+ goto fail;
|
|
|
|
|
|
mutex_lock(&kvm->lock);
|
|
|
- list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
|
|
|
+
|
|
|
+ /* Check this LIOBN hasn't been previously allocated */
|
|
|
+ ret = 0;
|
|
|
+ list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
|
|
|
+ if (siter->liobn == args->liobn) {
|
|
|
+ ret = -EBUSY;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ret) {
|
|
|
+ list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
|
|
|
+ kvm_get_kvm(kvm);
|
|
|
+ }
|
|
|
|
|
|
mutex_unlock(&kvm->lock);
|
|
|
|
|
|
- return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
|
|
|
- stt, O_RDWR | O_CLOEXEC);
|
|
|
+ if (!ret)
|
|
|
+ return fd;
|
|
|
|
|
|
-fail:
|
|
|
- if (stt) {
|
|
|
- for (i = 0; i < npages; i++)
|
|
|
- if (stt->pages[i])
|
|
|
- __free_page(stt->pages[i]);
|
|
|
+ put_unused_fd(fd);
|
|
|
|
|
|
- kfree(stt);
|
|
|
- }
|
|
|
+ fail:
|
|
|
+ for (i = 0; i < npages; i++)
|
|
|
+ if (stt->pages[i])
|
|
|
+ __free_page(stt->pages[i]);
|
|
|
+
|
|
|
+ kfree(stt);
|
|
|
+ fail_acct:
|
|
|
+ kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
|
|
|
return ret;
|
|
|
}
|
|
|
|