[openib-general] [PATCH] process locked in D state.

Gleb Natapov glebn at voltaire.com
Tue Jun 28 00:04:41 PDT 2005


On Mon, Jun 27, 2005 at 04:59:54PM -0700, Roland Dreier wrote:
> Something like this should work...

Yes, but don't forget the first part of my patch (for libibverbs/src/device.c)
I think it should be applied to.

[snip]
>  
> -void ib_umem_release(struct ib_device *dev, struct ib_umem *umem)
> +static void ib_umem_account(void *work_ptr)
>  {
> -	struct mm_struct *mm;
> +	struct ib_umem_account_work *work = work_ptr;
>  
> -	mm = get_task_mm(current);
Are you sure that ib_umem_account will run on behalf the process that schedules it?
Anyway you are correctly using work->mm in the rest of the function so
this line should be dropped I think.

> +	down_write(&work->mm->mmap_sem);
> +	work->mm->locked_vm -= work->diff;
> +	up_write(&work->mm->mmap_sem);
> +	mmput(work->mm);
> +	kfree(work);
> +}
>  
> -	if (mm) {
> -		down_write(&mm->mmap_sem);
> -		mm->locked_vm -= PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
> -	}
> +void ib_umem_release(struct ib_device *dev, struct ib_umem *umem)
> +{
> +	struct mm_struct *mm;
>  
>  	__ib_umem_release(dev, umem, 1);
>  
> +	mm = get_task_mm(current);
>  	if (mm) {
> -		up_write(&mm->mmap_sem);
> -		mmput(mm);
> +		/*
> +		 * We may be called with the mm's mmap_sem already
> +		 * held.  This can happen when a userspace munmap() is
> +		 * the call that drops the last reference to our file
> +		 * and calls our release method.  If there are memory
> +		 * regions to destroy, we'll end up here and not be
> +		 * able to take the mmap_sem.
> +		 *
> +		 * To handle this, we try to grab the mmap_sem, and if
> +		 * we can't get it immediately, we defer the
> +		 * accounting to the system workqueue.
> +		 */
> +		if (down_write_trylock(&mm->mmap_sem)) {
> +			mm->locked_vm -= PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
> +			up_write(&mm->mmap_sem);
> +			mmput(mm);
> +		} else {
> +			struct ib_umem_account_work *work;
> +
> +			work = kmalloc(sizeof *work, GFP_KERNEL);
> +			if (!work)
> +				return;
> +
> +			INIT_WORK(&work->work, ib_umem_account, work);
> +			work->mm   = mm;
> +			work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
> +
> +			schedule_work(&work->work);
> +		}
>  	}
>  }

--
			Gleb.



More information about the general mailing list