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.
_______________________________________________
openib-general mailing list
openib-general@openib.org
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to