[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