On 23/10/20(Fri) 10:31, Martin Pieuchot wrote:
> More refactoring.  This time let's introduce a helper to manipulate
> references.  The goal is to reduce the upcoming diff adding locking.
> 
> This is extracted from a bigger diff from guenther@ as well as some
> bits from NetBSD.

Now with the correct diff, ok?

Index: uvm/uvm_amap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_amap.c,v
retrieving revision 1.85
diff -u -p -r1.85 uvm_amap.c
--- uvm/uvm_amap.c      12 Oct 2020 08:44:45 -0000      1.85
+++ uvm/uvm_amap.c      23 Oct 2020 08:23:59 -0000
@@ -68,7 +68,23 @@ static inline void amap_list_remove(stru
 
 struct vm_amap_chunk *amap_chunk_get(struct vm_amap *, int, int, int);
 void amap_chunk_free(struct vm_amap *, struct vm_amap_chunk *);
-void amap_wiperange_chunk(struct vm_amap *, struct vm_amap_chunk *, int, int);
+
+/*
+ * if we enable PPREF, then we have a couple of extra functions that
+ * we need to prototype here...
+ */
+
+#ifdef UVM_AMAP_PPREF
+
+#define PPREF_NONE ((int *) -1)        /* not using ppref */
+
+void   amap_pp_adjref(struct vm_amap *, int, vsize_t, int);
+void   amap_pp_establish(struct vm_amap *);
+void   amap_wiperange_chunk(struct vm_amap *, struct vm_amap_chunk *, int,
+           int);
+void   amap_wiperange(struct vm_amap *, int, int);
+
+#endif /* UVM_AMAP_PPREF */
 
 static inline void
 amap_list_insert(struct vm_amap *amap)
@@ -1153,6 +1169,32 @@ amap_unadd(struct vm_aref *aref, vaddr_t
 }
 
 /*
+ * amap_adjref_anons: adjust the reference count(s) on amap and its anons.
+ */
+static void
+amap_adjref_anons(struct vm_amap *amap, vaddr_t offset, vsize_t len,
+    int refv, boolean_t all)
+{
+#ifdef UVM_AMAP_PPREF
+       if (amap->am_ppref == NULL && !all && len != amap->am_nslot) {
+               amap_pp_establish(amap);
+       }
+#endif
+
+       amap->am_ref += refv;
+
+#ifdef UVM_AMAP_PPREF
+       if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
+               if (all) {
+                       amap_pp_adjref(amap, 0, amap->am_nslot, refv);
+               } else {
+                       amap_pp_adjref(amap, offset, len, refv);
+               }
+       }
+#endif
+}
+
+/*
  * amap_ref: gain a reference to an amap
  *
  * => "offset" and "len" are in units of pages
@@ -1162,51 +1204,36 @@ void
 amap_ref(struct vm_amap *amap, vaddr_t offset, vsize_t len, int flags)
 {
 
-       amap->am_ref++;
        if (flags & AMAP_SHARED)
                amap->am_flags |= AMAP_SHARED;
-#ifdef UVM_AMAP_PPREF
-       if (amap->am_ppref == NULL && (flags & AMAP_REFALL) == 0 &&
-           len != amap->am_nslot)
-               amap_pp_establish(amap);
-       if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
-               if (flags & AMAP_REFALL)
-                       amap_pp_adjref(amap, 0, amap->am_nslot, 1);
-               else
-                       amap_pp_adjref(amap, offset, len, 1);
-       }
-#endif
+       amap_adjref_anons(amap, offset, len, 1, (flags & AMAP_REFALL) != 0);
 }
 
 /*
  * amap_unref: remove a reference to an amap
  *
- * => caller must remove all pmap-level references to this amap before
- *     dropping the reference
- * => called from uvm_unmap_detach [only]  ... note that entry is no
- *     longer part of a map
+ * => All pmap-level references to this amap must be already removed.
+ * => Called from uvm_unmap_detach(); entry is already removed from the map.
  */
 void
 amap_unref(struct vm_amap *amap, vaddr_t offset, vsize_t len, boolean_t all)
 {
+       KASSERT(amap->am_ref > 0);
 
-       /* if we are the last reference, free the amap and return. */
-       if (amap->am_ref-- == 1) {
-               amap_wipeout(amap);     /* drops final ref and frees */
+       if (amap->am_ref == 1) {
+               /*
+                * If the last reference - wipeout and destroy the amap.
+                */
+               amap->am_ref--;
+               amap_wipeout(amap);
                return;
        }
 
-       /* otherwise just drop the reference count(s) */
-       if (amap->am_ref == 1 && (amap->am_flags & AMAP_SHARED) != 0)
-               amap->am_flags &= ~AMAP_SHARED; /* clear shared flag */
-#ifdef UVM_AMAP_PPREF
-       if (amap->am_ppref == NULL && all == 0 && len != amap->am_nslot)
-               amap_pp_establish(amap);
-       if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
-               if (all)
-                       amap_pp_adjref(amap, 0, amap->am_nslot, -1);
-               else
-                       amap_pp_adjref(amap, offset, len, -1);
+       /*
+        * Otherwise, drop the reference count(s) on anons.
+        */
+       if (amap->am_ref == 2 && (amap->am_flags & AMAP_SHARED) != 0) {
+               amap->am_flags &= ~AMAP_SHARED;
        }
-#endif
+       amap_adjref_anons(amap, offset, len, -1, all);
 }
Index: uvm/uvm_amap.h
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_amap.h,v
retrieving revision 1.31
diff -u -p -r1.31 uvm_amap.h
--- uvm/uvm_amap.h      15 May 2019 06:12:19 -0000      1.31
+++ uvm/uvm_amap.h      23 Oct 2020 08:19:43 -0000
@@ -261,23 +261,6 @@ struct vm_amap {
 #define amap_flags(AMAP)       ((AMAP)->am_flags)
 #define amap_refs(AMAP)                ((AMAP)->am_ref)
 
-/*
- * if we enable PPREF, then we have a couple of extra functions that
- * we need to prototype here...
- */
-
-#ifdef UVM_AMAP_PPREF
-
-#define PPREF_NONE ((int *) -1)        /* not using ppref */
-
-                                       /* adjust references */
-void           amap_pp_adjref(struct vm_amap *, int, vsize_t, int);
-                                       /* establish ppref */
-void           amap_pp_establish(struct vm_amap *);
-                                       /* wipe part of an amap */
-void           amap_wiperange(struct vm_amap *, int, int);
-#endif /* UVM_AMAP_PPREF */
-
 #endif /* _KERNEL */
 
 #endif /* _UVM_UVM_AMAP_H_ */

Reply via email to