diff options
Diffstat (limited to 'drivers/infiniband/core/umem.c')
| -rw-r--r-- | drivers/infiniband/core/umem.c | 62 | 
1 files changed, 31 insertions, 31 deletions
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 54ab6335c48d..a41792dbae1f 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -84,7 +84,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  	struct ib_umem *umem;  	struct page **page_list;  	struct vm_area_struct **vma_list; -	unsigned long locked;  	unsigned long lock_limit;  	unsigned long cur_base;  	unsigned long npages; @@ -92,7 +91,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  	int i;  	unsigned long dma_attrs = 0;  	struct scatterlist *sg, *sg_list_start; -	int need_release = 0;  	unsigned int gup_flags = FOLL_WRITE;  	if (dmasync) @@ -121,10 +119,8 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  	if (access & IB_ACCESS_ON_DEMAND) {  		ret = ib_umem_odp_get(context, umem, access); -		if (ret) { -			kfree(umem); -			return ERR_PTR(ret); -		} +		if (ret) +			goto umem_kfree;  		return umem;  	} @@ -135,8 +131,8 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  	page_list = (struct page **) __get_free_page(GFP_KERNEL);  	if (!page_list) { -		kfree(umem); -		return ERR_PTR(-ENOMEM); +		ret = -ENOMEM; +		goto umem_kfree;  	}  	/* @@ -149,41 +145,43 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  	npages = ib_umem_num_pages(umem); -	down_write(¤t->mm->mmap_sem); - -	locked     = npages + current->mm->pinned_vm;  	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; -	if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { +	down_write(¤t->mm->mmap_sem); +	current->mm->pinned_vm += npages; +	if ((current->mm->pinned_vm > lock_limit) && !capable(CAP_IPC_LOCK)) { +		up_write(¤t->mm->mmap_sem);  		ret = -ENOMEM; -		goto out; +		goto vma;  	} +	up_write(¤t->mm->mmap_sem);  	cur_base = addr & PAGE_MASK;  	if (npages == 0 || npages > UINT_MAX) {  		ret = -EINVAL; -		goto out; +		goto vma;  	}  	ret = sg_alloc_table(&umem->sg_head, npages, GFP_KERNEL);  	if (ret) -		goto out; +		goto vma;  	if (!umem->writable)  		gup_flags |= FOLL_FORCE; -	need_release = 1;  	sg_list_start = umem->sg_head.sgl; +	down_read(¤t->mm->mmap_sem);  	while (npages) {  		ret = get_user_pages_longterm(cur_base,  				     min_t(unsigned long, npages,  					   PAGE_SIZE / sizeof (struct page *)),  				     gup_flags, page_list, vma_list); - -		if (ret < 0) -			goto out; +		if (ret < 0) { +			up_read(¤t->mm->mmap_sem); +			goto umem_release; +		}  		umem->npages += ret;  		cur_base += ret * PAGE_SIZE; @@ -199,6 +197,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  		/* preparing for next loop */  		sg_list_start = sg;  	} +	up_read(¤t->mm->mmap_sem);  	umem->nmap = ib_dma_map_sg_attrs(context->device,  				  umem->sg_head.sgl, @@ -206,27 +205,28 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,  				  DMA_BIDIRECTIONAL,  				  dma_attrs); -	if (umem->nmap <= 0) { +	if (!umem->nmap) {  		ret = -ENOMEM; -		goto out; +		goto umem_release;  	}  	ret = 0; +	goto out; -out: -	if (ret < 0) { -		if (need_release) -			__ib_umem_release(context->device, umem, 0); -		kfree(umem); -	} else -		current->mm->pinned_vm = locked; - +umem_release: +	__ib_umem_release(context->device, umem, 0); +vma: +	down_write(¤t->mm->mmap_sem); +	current->mm->pinned_vm -= ib_umem_num_pages(umem);  	up_write(¤t->mm->mmap_sem); +out:  	if (vma_list)  		free_page((unsigned long) vma_list);  	free_page((unsigned long) page_list); - -	return ret < 0 ? ERR_PTR(ret) : umem; +umem_kfree: +	if (ret) +		kfree(umem); +	return ret ? ERR_PTR(ret) : umem;  }  EXPORT_SYMBOL(ib_umem_get);  |