Re: Threads race for VM

From: Andy Valencia <vandys_at_nospam.org>
Date: Tue Nov 30 1999 - 16:27:32 PST

[Eric_Jacobs@fc.mcps.k12.md.us (Eric Jacobs) writes:]

>I just finished unconvering a nasty race for virtual memory that
>sometimes occurs in multi-threaded processes. The most likely to
>be affected are processes that call static-linked functions for the
>first time in two or more threads at the same time.
>...

Attached below is a proposed patch to fix this problem. It seems to fix the
kernel crach for me... care to look it over and also give it a spin? If it
all looks OK, I'll put it in for 1.6.3.

Thanks,
Andy

*** 1.8 1997/09/28 12:15:24
--- include/sys/pview.h 1999/11/09 15:51:44
***************
*** 18,25 ****
--- 18,27 ----
          struct pview /* For listing under vas */
                  *p_next;
          uchar p_prot; /* Protections on view */
          struct hatpview p_hat; /* HAT contribution */
+ uchar *p_valid; /* If attached to a VAS, flags which */
+ /* virtual slots have mappings */
  };
  
  /*
   * Bits for protection
*** 1.8 1997/12/22 17:32:31
--- include/sys/malloc.h 1999/11/09 16:01:32
***************
*** 43,52 ****
  #define MT_PGRP (21) /* Process grouping */
  #define MT_ATL (22) /* Attach lists */
  #define MT_FPU (23) /* FPU save state */
  #define MT_OPENPORT (24) /* FOD pset data structure */
  
! #define MALLOCTYPES (25) /* UPDATE when you add values above */
                                  /* ALSO check n_allocname[] */
  
  /*
   * Our per-storage-size information
--- 43,53 ----
  #define MT_PGRP (21) /* Process grouping */
  #define MT_ATL (22) /* Attach lists */
  #define MT_FPU (23) /* FPU save state */
  #define MT_OPENPORT (24) /* FOD pset data structure */
+ #define MT_PVIEW_VALID (25) /* pview valid page map */
  
! #define MALLOCTYPES (26) /* UPDATE when you add values above */
                                  /* ALSO check n_allocname[] */
  
  /*
   * Our per-storage-size information
*** 1.15 1997/09/28 12:18:26
--- src/os/dbg/dump.c 1999/11/19 14:48:40
***************
*** 296,305 ****
  do_dump_pview(struct pview *pv)
  {
          printf(" pview @ 0x%x vaddr 0x%x len 0x%x off 0x%x hat 0x%x\n",
                  pv, pv->p_vaddr, pv->p_len, pv->p_off, &pv->p_hat);
! printf(" vas 0x%x next 0x%x prot 0x%x pset 0x%x\n",
! pv->p_vas, pv->p_next, pv->p_prot, pv->p_set);
  }
  
  /*
   * dump_pview()
--- 296,305 ----
  do_dump_pview(struct pview *pv)
  {
          printf(" pview @ 0x%x vaddr 0x%x len 0x%x off 0x%x hat 0x%x\n",
                  pv, pv->p_vaddr, pv->p_len, pv->p_off, &pv->p_hat);
! printf(" vas 0x%x next 0x%x prot 0x%x pset 0x%x valid 0x%x\n",
! pv->p_vas, pv->p_next, pv->p_prot, pv->p_set, pv->p_valid);
  }
  
  /*
   * dump_pview()
*** 1.15 1995/10/27 05:43:05
--- src/os/kern/malloc.c 1999/11/09 16:02:46
***************
*** 28,60 ****
   * Value to name mapping, to help the kernel debugger print
   * things out nicely
   */
  char *n_allocname[MALLOCTYPES] = {
! "MT_RMAP",
! "MT_EVENT",
! "MT_EXITGRP",
! "MT_EXITST",
! "MT_MSG",
! "MT_SYSMSG",
! "MT_PORT",
! "MT_PORTREF",
! "MT_PVIEW",
! "MT_PSET",
! "MT_PROC",
! "MT_THREAD",
! "MT_KSTACK",
! "MT_VAS",
! "MT_PERPAGE",
! "MT_QIO",
! "MT_SCHED",
! "MT_SEG",
! "MT_EVENTQ",
! "MT_L1PT",
! "MT_L2PT",
! "MT_PGRP",
! "MT_ATL",
! "MT_FPU",
! "MT_OPENPORT",
  };
  #endif /* DEBUG */
  
  /*
--- 28,41 ----
   * Value to name mapping, to help the kernel debugger print
   * things out nicely
   */
  char *n_allocname[MALLOCTYPES] = {
! "MT_RMAP", "MT_EVENT", "MT_EXITGRP", "MT_EXITST", "MT_MSG",
! "MT_SYSMSG", "MT_PORT", "MT_PORTREF", "MT_PVIEW", "MT_PSET",
! "MT_PROC", "MT_THREAD", "MT_KSTACK", "MT_VAS", "MT_PERPAGE",
! "MT_QIO", "MT_SCHED", "MT_SEG", "MT_EVENTQ", "MT_L1PT",
! "MT_L2PT", "MT_PGRP", "MT_ATL", "MT_FPU", "MT_OPENPORT",
! "MT_PVIEW_VALID",
  };
  #endif /* DEBUG */
  
  /*
*** 1.8 1996/04/18 08:13:40
--- src/os/kern/pview.c 1999/11/09 16:10:30
***************
*** 35,42 ****
--- 35,43 ----
  void
  free_pview(struct pview *pv)
  {
          deref_pset(pv->p_set);
+ ASSERT_DEBUG(pv->p_valid == 0, "free_pview: p_valid not cleared");
          FREE(pv, MT_PVIEW);
  }
  
  /*
***************
*** 52,59 ****
--- 53,61 ----
          bcopy(opv, pv, sizeof(*pv));
          ref_pset(pv->p_set);
          pv->p_next = 0;
          pv->p_vas = 0;
+ pv->p_valid = 0;
          return(pv);
  }
  
  /*
***************
*** 86,95 ****
          struct pview *pv;
          extern struct pview *detach_pview();
  
          pv = detach_pview(vas, vaddr);
! deref_pset(pv->p_set);
! FREE(pv, MT_PVIEW);
  }
  
  /*
   * attach_valid_slots()
--- 88,96 ----
          struct pview *pv;
          extern struct pview *detach_pview();
  
          pv = detach_pview(vas, vaddr);
! free_pview(pv);
  }
  
  /*
   * attach_valid_slots()
***************
*** 111,117 ****
--- 112,119 ----
                          hat_addtrans(pv, (char *)pv->p_vaddr + ptob(x),
                                  pp->pp_pfn, pv->p_prot |
                                  ((pp->pp_flags & PP_COW) ? PROT_RO : 0));
                          ref_slot(ps, pp, idx);
+ pv->p_valid[x] = 1;
                  }
          }
  }
*** 1.57 1997/12/07 23:10:29
--- src/os/kern/proc.c 1999/11/18 16:19:30
***************
*** 44,54 ****
  
          ps = physmem_pset(pfn, pages);
          pv = alloc_pview(ps);
          pv->p_vaddr = vaddr;
! pv->p_vas = vas;
! pv->p_next = vas->v_views;
! vas->v_views = pv;
          return(pv);
  }
  
  /*
--- 44,52 ----
  
          ps = physmem_pset(pfn, pages);
          pv = alloc_pview(ps);
          pv->p_vaddr = vaddr;
! ASSERT(attach_pview(vas, pv), "mkview: attach failed");
          return(pv);
  }
  
  /*
*** 1.19 1998/12/13 22:19:14
--- src/os/kern/vm_steal.c 1999/11/09 16:14:58
***************
*** 139,146 ****
--- 139,151 ----
                          hat_deletetrans(pv, (char *)pv->p_vaddr +
                                  ptob(a->a_idx), pp->pp_pfn);
                          flags |= hat_getbits(pv,
                                  (char *)pv->p_vaddr + ptob(a->a_idx));
+
+ /*
+ * Virtual map under this pview not valid any more
+ */
+ pv->p_valid[a->a_idx] = 0;
                  }
  
                  /*
                   * Free attach list element, update ref count
*** 1.8 1996/04/18 08:13:40
--- src/os/kern/vm_fault.c 1999/11/30 16:37:12
***************
*** 66,74 ****
  {
          struct pview *pv;
          struct pset *ps;
          struct perpage *pp;
! uint idx;
          int error = 0;
          int wasvalid;
  
          /*
--- 66,74 ----
  {
          struct pview *pv;
          struct pset *ps;
          struct perpage *pp;
! uint idx, pvidx;
          int error = 0;
          int wasvalid;
  
          /*
***************
*** 76,83 ****
--- 76,84 ----
           */
          if ((pv = find_pview(vas, vaddr)) == 0) {
                  return(1);
          }
+ ASSERT_DEBUG(pv->p_valid, "vas_fault: pview !p_valid");
          ps = pv->p_set;
  
          /*
           * Next easiest--trying to write to read-only view
***************
*** 89,97 ****
  
          /*
           * Transfer from pset lock to page slot lock
           */
! idx = btop(((char *)vaddr - (char *)pv->p_vaddr)) + pv->p_off;
          pp = find_pp(ps, idx);
          lock_slot(ps, pp);
  
          /*
--- 90,99 ----
  
          /*
           * Transfer from pset lock to page slot lock
           */
! pvidx = btop((char *)vaddr - (char *)pv->p_vaddr);
! idx = pvidx + pv->p_off;
          pp = find_pp(ps, idx);
          lock_slot(ps, pp);
  
          /*
***************
*** 121,151 ****
          /*
           * Break COW association when we write it
           */
          if ((pp->pp_flags & PP_COW) && write) {
                  if (wasvalid) {
! uint pvidx;
!
! /*
! * May or may not be there. If it is, remove
! * its reference from the per-page struct.
! */
! pvidx = btop((ulong)vaddr - (ulong)pv->p_vaddr);
! if (delete_atl(pp, pv, pvidx) == 0) {
! deref_slot(ps, pp, idx);
                          }
                  }
                  cow_write(ps, pp, idx);
                  ASSERT(pp->pp_flags & PP_V, "vm_fault: lost the page 2");
          }
  
          /*
           * With a valid slot, add a hat translation and tabulate
           * the entry with an atl.
           */
! add_atl(pp, pv, btop((ulong)vaddr - (ulong)(pv->p_vaddr)), 0);
          hat_addtrans(pv, vaddr, pp->pp_pfn, pv->p_prot |
                  ((pp->pp_flags & PP_COW) ? PROT_RO : 0));
  
          /*
           * Free the various things we hold and return
           */
--- 123,164 ----
          /*
           * Break COW association when we write it
           */
          if ((pp->pp_flags & PP_COW) && write) {
+ /*
+ * May or may not be there. If it is, remove
+ * its reference from the per-page struct.
+ */
                  if (wasvalid) {
! if (pv->p_valid[pvidx]) {
! ASSERT(delete_atl(pp, pv, pvidx) == 0,
! "vas_fault: p_valid no atl");
! pv->p_valid[pvidx] = 0;
                          }
+ deref_slot(ps, pp, idx);
                  }
                  cow_write(ps, pp, idx);
                  ASSERT(pp->pp_flags & PP_V, "vm_fault: lost the page 2");
+
+ /*
+ * If not writing to a COW association, then inhibit adding
+ * the translation if it's already present (another thread
+ * ran and brought it in for us, probably)
+ */
+ } else if (pv->p_valid[pvidx]) {
+ deref_slot(ps, pp, idx);
+ goto out;
          }
  
          /*
           * With a valid slot, add a hat translation and tabulate
           * the entry with an atl.
           */
! add_atl(pp, pv, pvidx, 0);
          hat_addtrans(pv, vaddr, pp->pp_pfn, pv->p_prot |
                  ((pp->pp_flags & PP_COW) ? PROT_RO : 0));
+ ASSERT_DEBUG(pv->p_valid[pvidx] == 0, "vas_fault: p_valid went on");
+ pv->p_valid[pvidx] = 1;
  
          /*
           * Free the various things we hold and return
           */
*** 1.13 1996/01/04 22:48:17
--- src/os/kern/vas.c 1999/11/18 16:23:00
***************
*** 59,66 ****
--- 59,67 ----
          struct pset *ps;
          struct perpage *pp;
          int x;
          struct pview *pv, **pvp;
+ char *va;
  
          /*
           * Remove our pview from the vas. It's singly linked, so we
           * have to search from the front.
***************
*** 76,83 ****
--- 77,85 ----
                  pvp = &pv->p_next;
          }
          ASSERT(pv, "detach_pview: lost a pview");
          v_lock(&vas->v_lock, SPL0_SAME);
+ ASSERT_DEBUG(pv->p_valid, "detach_pview: !p_valid");
          ps = pv->p_set;
  
          /*
           * Walk each valid slot, and tear down any HAT translation.
***************
*** 85,125 ****
          p_lock_void(&ps->p_lock, SPL0_SAME);
          for (x = 0; x < pv->p_len; ++x) {
                  uint pfn, idx;
  
- idx = pv->p_off + x;
- pp = find_pp(ps, idx);
-
                  /*
! * Can't be a translation if not a valid page
                   */
! if (!(pp->pp_flags & PP_V)) {
                          continue;
                  }
                  pfn = pp->pp_pfn;
  
                  /*
                   * Lock the slot. Lock the underlying page. Delete
                   * translation, and deref our use of the slot.
                   */
                  lock_slot(ps, pp);
! if (delete_atl(pp, pv, x) == 0) {
! char *va;
  
! /*
! * Valid in our view; delete HAT translation. Record
! * ref/mod bits for final time.
! */
! va = pv->p_vaddr;
! va += ptob(x);
! hat_deletetrans(pv, va, pfn);
! pp->pp_flags |= hat_getbits(pv, va);
!
! /*
! * Release our reference to the slot
! */
! deref_slot(ps, pp, idx);
! }
                  unlock_slot(ps, pp);
  
                  /*
                   * Reacquire pset lock
--- 87,131 ----
          p_lock_void(&ps->p_lock, SPL0_SAME);
          for (x = 0; x < pv->p_len; ++x) {
                  uint pfn, idx;
  
                  /*
! * Skip all but those with active mappings
                   */
! if (!pv->p_valid[x]) {
                          continue;
                  }
+
+ /*
+ * Point to the mapping
+ */
+ idx = pv->p_off + x;
+ pp = find_pp(ps, idx);
+ ASSERT_DEBUG(pp->pp_flags & PP_V,
+ "detach_pview: p_valid !PP_V");
                  pfn = pp->pp_pfn;
  
                  /*
                   * Lock the slot. Lock the underlying page. Delete
                   * translation, and deref our use of the slot.
                   */
                  lock_slot(ps, pp);
! ASSERT(delete_atl(pp, pv, x) == 0,
! "detach_pview: p_valid but not ATL");
  
! /*
! * Valid in our view; delete HAT translation. Record
! * ref/mod bits for final time.
! */
! va = pv->p_vaddr;
! va += ptob(x);
! hat_deletetrans(pv, va, pfn);
! pp->pp_flags |= hat_getbits(pv, va);
!
! /*
! * Release our reference to the slot
! */
! deref_slot(ps, pp, idx);
                  unlock_slot(ps, pp);
  
                  /*
                   * Reacquire pset lock
***************
*** 136,143 ****
--- 142,155 ----
           * Let hat hear about detach
           */
          hat_detach(pv);
  
+ /*
+ * Free valid map memory
+ */
+ FREE(pv->p_valid, MT_PVIEW_VALID);
+ pv->p_valid = 0;
+
          return(pv);
  }
  
  /*
***************
*** 174,181 ****
--- 186,199 ----
                  pv->p_vas = 0;
                  return(0);
          }
          vaddr = pv->p_vaddr;
+
+ /*
+ * Get the memory for the valid map
+ */
+ pv->p_valid = MALLOC(pv->p_len, MT_PVIEW_VALID);
+ bzero(pv->p_valid, pv->p_len);
  
          /*
           * Now that we're committed, link it onto the vas
           */
Received on Tue Nov 30 17:27:59 1999

This archive was generated by hypermail 2.1.8 : Thu Sep 22 2005 - 15:12:56 PDT