On 16/06/21(Wed) 11:26, Martin Pieuchot wrote:
> Diff below does two things:
>
> - Use atomic operations for incrementing/decrementing references of
> anonymous objects. This allows us to manipulate them without holding
> the KERNEL_LOCK().
>
> - Rewrite the loop from uao_swap_off() to only keep a reference to the
> next item in the list. This is imported from NetBSD and is necessary
> to introduce locking around uao_pagein().
>
> ok?
Anyone?
>
> Index: uvm/uvm_aobj.c
> ===================================================================
> RCS file: /cvs/src/sys/uvm/uvm_aobj.c,v
> retrieving revision 1.98
> diff -u -p -r1.98 uvm_aobj.c
> --- uvm/uvm_aobj.c 16 Jun 2021 09:02:21 -0000 1.98
> +++ uvm/uvm_aobj.c 16 Jun 2021 09:20:26 -0000
> @@ -779,19 +779,11 @@ uao_init(void)
> void
> uao_reference(struct uvm_object *uobj)
> {
> - KERNEL_ASSERT_LOCKED();
> - uao_reference_locked(uobj);
> -}
> -
> -void
> -uao_reference_locked(struct uvm_object *uobj)
> -{
> -
> /* Kernel object is persistent. */
> if (UVM_OBJ_IS_KERN_OBJECT(uobj))
> return;
>
> - uobj->uo_refs++;
> + atomic_inc_int(&uobj->uo_refs);
> }
>
>
> @@ -801,34 +793,19 @@ uao_reference_locked(struct uvm_object *
> void
> uao_detach(struct uvm_object *uobj)
> {
> - KERNEL_ASSERT_LOCKED();
> - uao_detach_locked(uobj);
> -}
> -
> -
> -/*
> - * uao_detach_locked: drop a reference to an aobj
> - *
> - * => aobj may freed upon return.
> - */
> -void
> -uao_detach_locked(struct uvm_object *uobj)
> -{
> struct uvm_aobj *aobj = (struct uvm_aobj *)uobj;
> struct vm_page *pg;
>
> /*
> * Detaching from kernel_object is a NOP.
> */
> - if (UVM_OBJ_IS_KERN_OBJECT(uobj)) {
> + if (UVM_OBJ_IS_KERN_OBJECT(uobj))
> return;
> - }
>
> /*
> * Drop the reference. If it was the last one, destroy the object.
> */
> - uobj->uo_refs--;
> - if (uobj->uo_refs) {
> + if (atomic_dec_int_nv(&uobj->uo_refs) > 0) {
> return;
> }
>
> @@ -1265,68 +1242,54 @@ uao_dropswap(struct uvm_object *uobj, in
> boolean_t
> uao_swap_off(int startslot, int endslot)
> {
> - struct uvm_aobj *aobj, *nextaobj, *prevaobj = NULL;
> + struct uvm_aobj *aobj;
>
> /*
> - * Walk the list of all anonymous UVM objects.
> + * Walk the list of all anonymous UVM objects. Grab the first.
> */
> mtx_enter(&uao_list_lock);
> + if ((aobj = LIST_FIRST(&uao_list)) == NULL) {
> + mtx_leave(&uao_list_lock);
> + return FALSE;
> + }
> + uao_reference(&aobj->u_obj);
>
> - for (aobj = LIST_FIRST(&uao_list);
> - aobj != NULL;
> - aobj = nextaobj) {
> + do {
> + struct uvm_aobj *nextaobj;
> boolean_t rv;
>
> /*
> - * add a ref to the aobj so it doesn't disappear
> - * while we're working.
> - */
> - uao_reference_locked(&aobj->u_obj);
> -
> - /*
> - * now it's safe to unlock the uao list.
> - * note that lock interleaving is alright with IPL_NONE mutexes.
> + * Prefetch the next object and immediately hold a reference
> + * on it, so neither the current nor the next entry could
> + * disappear while we are iterating.
> */
> - mtx_leave(&uao_list_lock);
> -
> - if (prevaobj) {
> - uao_detach_locked(&prevaobj->u_obj);
> - prevaobj = NULL;
> + if ((nextaobj = LIST_NEXT(aobj, u_list)) != NULL) {
> + uao_reference(&nextaobj->u_obj);
> }
> + mtx_leave(&uao_list_lock);
>
> /*
> - * page in any pages in the swslot range.
> - * if there's an error, abort and return the error.
> + * Page in all pages in the swap slot range.
> */
> rv = uao_pagein(aobj, startslot, endslot);
> +
> + /* Drop the reference of the current object. */
> + uao_detach(&aobj->u_obj);
> if (rv) {
> - uao_detach_locked(&aobj->u_obj);
> + if (nextaobj) {
> + uao_detach(&nextaobj->u_obj);
> + }
> return rv;
> }
>
> - /*
> - * we're done with this aobj.
> - * relock the list and drop our ref on the aobj.
> - */
> + aobj = nextaobj;
> mtx_enter(&uao_list_lock);
> - nextaobj = LIST_NEXT(aobj, u_list);
> - /*
> - * prevaobj means that we have an object that we need
> - * to drop a reference for. We can't just drop it now with
> - * the list locked since that could cause lock recursion in
> - * the case where we reduce the refcount to 0. It will be
> - * released the next time we drop the list lock.
> - */
> - prevaobj = aobj;
> - }
> + } while (aobj);
>
> /*
> * done with traversal, unlock the list
> */
> mtx_leave(&uao_list_lock);
> - if (prevaobj) {
> - uao_detach_locked(&prevaobj->u_obj);
> - }
> return FALSE;
> }
>
>