Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2/linux Implement kfree_rcu.



details:   https://anonhg.NetBSD.org/src/rev/929df777c036
branches:  trunk
changeset: 1027951:929df777c036
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Dec 19 01:20:45 2021 +0000

description:
Implement kfree_rcu.

diffstat:

 sys/external/bsd/drm2/include/linux/rcupdate.h |   13 +-
 sys/external/bsd/drm2/linux/linux_rcu.c        |  147 ++++++++++++++++--------
 2 files changed, 110 insertions(+), 50 deletions(-)

diffs (269 lines):

diff -r 61362445f46f -r 929df777c036 sys/external/bsd/drm2/include/linux/rcupdate.h
--- a/sys/external/bsd/drm2/include/linux/rcupdate.h    Sun Dec 19 01:20:38 2021 +0000
+++ b/sys/external/bsd/drm2/include/linux/rcupdate.h    Sun Dec 19 01:20:45 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rcupdate.h,v 1.11 2021/12/19 01:19:45 riastradh Exp $  */
+/*     $NetBSD: rcupdate.h,v 1.12 2021/12/19 01:20:45 riastradh Exp $  */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -67,10 +67,14 @@
 #define        rcu_pointer_handoff(P)  (P)
 
 struct rcu_head {
-       void            (*rcuh_callback)(struct rcu_head *);
+       union {
+               void            (*callback)(struct rcu_head *);
+               void            *obj;
+       }               rcuh_u;
        struct rcu_head *rcuh_next;
 };
 
+#define        _kfree_rcu              linux__kfree_rcu
 #define        call_rcu                linux_call_rcu
 #define        rcu_barrier             linux_rcu_barrier
 #define        synchronize_rcu         linux_synchronize_rcu
@@ -82,6 +86,8 @@
 void   rcu_barrier(void);
 void   synchronize_rcu(void);
 
+void   _kfree_rcu(struct rcu_head *, void *);
+
 static inline void
 rcu_read_lock(void)
 {
@@ -98,4 +104,7 @@
        kpreempt_enable();
 }
 
+#define        kfree_rcu(P, F)                                                       \
+       _kfree_rcu(&(P)->F, (P))
+
 #endif  /* _LINUX_RCUPDATE_H_ */
diff -r 61362445f46f -r 929df777c036 sys/external/bsd/drm2/linux/linux_rcu.c
--- a/sys/external/bsd/drm2/linux/linux_rcu.c   Sun Dec 19 01:20:38 2021 +0000
+++ b/sys/external/bsd/drm2/linux/linux_rcu.c   Sun Dec 19 01:20:45 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_rcu.c,v 1.7 2021/12/19 01:19:52 riastradh Exp $  */
+/*     $NetBSD: linux_rcu.c,v 1.8 2021/12/19 01:20:45 riastradh Exp $  */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,v 1.7 2021/12/19 01:19:52 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,v 1.8 2021/12/19 01:20:45 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -42,6 +42,7 @@
 #include <sys/xcall.h>
 
 #include <linux/rcupdate.h>
+#include <linux/slab.h>
 
 SDT_PROBE_DEFINE0(sdt, linux, rcu, synchronize__start);
 SDT_PROBE_DEFINE1(sdt, linux, rcu, synchronize__cpu, "unsigned"/*cpu*/);
@@ -54,11 +55,18 @@
     "struct rcu_head *"/*head*/, "void (*)(struct rcu_head *)"/*callback*/);
 SDT_PROBE_DEFINE2(sdt, linux, rcu, call__done,
     "struct rcu_head *"/*head*/, "void (*)(struct rcu_head *)"/*callback*/);
+SDT_PROBE_DEFINE2(sdt, linux, rcu, kfree__queue,
+    "struct rcu_head *"/*head*/, "void *"/*obj*/);
+SDT_PROBE_DEFINE2(sdt, linux, rcu, kfree__free,
+    "struct rcu_head *"/*head*/, "void *"/*obj*/);
+SDT_PROBE_DEFINE2(sdt, linux, rcu, kfree__done,
+    "struct rcu_head *"/*head*/, "void *"/*obj*/);
 
 static struct {
        kmutex_t        lock;
        kcondvar_t      cv;
-       struct rcu_head *first;
+       struct rcu_head *first_callback;
+       struct rcu_head *first_kfree;
        struct lwp      *lwp;
        uint64_t        gen;
        bool            dying;
@@ -101,7 +109,7 @@
 
        SDT_PROBE0(sdt, linux, rcu, barrier__start);
        mutex_enter(&gc.lock);
-       if (gc.first != NULL) {
+       if (gc.first_callback != NULL || gc.first_kfree != NULL) {
                gen = gc.gen;
                do {
                        cv_wait(&gc.cv, &gc.lock);
@@ -121,68 +129,109 @@
 call_rcu(struct rcu_head *head, void (*callback)(struct rcu_head *))
 {
 
-       head->rcuh_callback = callback;
+       head->rcuh_u.callback = callback;
 
        mutex_enter(&gc.lock);
-       head->rcuh_next = gc.first;
-       gc.first = head;
+       head->rcuh_next = gc.first_callback;
+       gc.first_callback = head;
        cv_broadcast(&gc.cv);
        SDT_PROBE2(sdt, linux, rcu, call__queue,  head, callback);
        mutex_exit(&gc.lock);
 }
 
+/*
+ * _kfree_rcu(head, obj)
+ *
+ *     kfree_rcu helper: schedule kfree(obj) using head for storage.
+ */
+void
+_kfree_rcu(struct rcu_head *head, void *obj)
+{
+
+       head->rcuh_u.obj = obj;
+
+       mutex_enter(&gc.lock);
+       head->rcuh_next = gc.first_kfree;
+       gc.first_kfree = head;
+       cv_broadcast(&gc.cv);
+       SDT_PROBE2(sdt, linux, rcu, kfree__queue,  head, obj);
+       mutex_exit(&gc.lock);
+}
+
 static void
 gc_thread(void *cookie)
 {
-       struct rcu_head *head, *next;
-       void (*callback)(struct rcu_head *);
+       struct rcu_head *head_callback, *head_kfree, *head, *next;
 
        mutex_enter(&gc.lock);
        for (;;) {
-               /* Wait for a task or death notice.  */
-               while ((head = gc.first) == NULL && !gc.dying)
-                       cv_wait(&gc.cv, &gc.lock);
+               /* Start with no work.  */
+               bool work = false;
 
-               /* If we got a list of callbacks, run them.  */
-               if (head != NULL) {
-                       gc.first = NULL;        /* mine */
-                       mutex_exit(&gc.lock);
-
-                       /* Wait for activity on all CPUs.  */
-                       synchronize_rcu();
+               /* Grab the list of callbacks.  */
+               if ((head_callback = gc.first_callback) != NULL) {
+                       gc.first_callback = NULL;
+                       work = true;
+               }
 
-                       /* It is now safe to call the callbacks.  */
-                       for (; head != NULL; head = next) {
-                               next = head->rcuh_next;
-                               callback = head->rcuh_callback;
-                               SDT_PROBE2(sdt, linux, rcu, call__run,
-                                   head, callback);
-                               (*callback)(head);
-                               /*
-                                * Can't dereference head or invoke
-                                * callback after this point.
-                                */
-                               SDT_PROBE2(sdt, linux, rcu, call__done,
-                                   head, callback);
-                       }
+               /* Grab the list of objects to kfree.  */
+               if ((head_kfree = gc.first_kfree) != NULL) {
+                       gc.first_kfree = NULL;
+                       work = true;
+               }
 
-                       mutex_enter(&gc.lock);
-                       gc.gen++;               /* done running */
-                       cv_broadcast(&gc.cv);   /* notify rcu_barrier */
-
-                       /*
-                        * Go back to the top and get more work before
-                        * deciding whether to stop so that we
-                        * guarantee to run all callbacks.
-                        */
+               /*
+                * If no work, then either stop, if we're dying, or
+                * wait for work, if not.
+                */
+               if (!work) {
+                       if (gc.dying)
+                               break;
+                       cv_wait(&gc.cv, &gc.lock);
                        continue;
                }
 
-               /* If we're asked to close shop, do so.  */
-               if (gc.dying)
-                       break;
+               /* We have work to do.  Drop the lock to do it.  */
+               mutex_exit(&gc.lock);
+
+               /* Wait for activity on all CPUs.  */
+               synchronize_rcu();
+
+               /* Call the callbacks.  */
+               for (head = head_callback; head != NULL; head = next) {
+                       void (*callback)(struct rcu_head *) =
+                           head->rcuh_u.callback;
+                       next = head->rcuh_next;
+                       SDT_PROBE2(sdt, linux, rcu, call__run,
+                           head, callback);
+                       (*callback)(head);
+                       /*
+                        * Can't dereference head or invoke
+                        * callback after this point.
+                        */
+                       SDT_PROBE2(sdt, linux, rcu, call__done,
+                           head, callback);
+               }
+
+               /* Free the objects to kfree.  */
+               for (head = head_kfree; head != NULL; head = next) {
+                       void *obj = head->rcuh_u.obj;
+                       next = head->rcuh_next;
+                       SDT_PROBE2(sdt, linux, rcu, kfree__free,  head, obj);
+                       kfree(obj);
+                       /* Can't dereference head or obj after this point.  */
+                       SDT_PROBE2(sdt, linux, rcu, kfree__done,  head, obj);
+               }
+
+               /* Return to the lock.  */
+               mutex_enter(&gc.lock);
+
+               /* Finished a batch of work.  Notify rcu_barrier.  */
+               gc.gen++;
+               cv_broadcast(&gc.cv);
        }
-       KASSERT(gc.first == NULL);
+       KASSERT(gc.first_callback == NULL);
+       KASSERT(gc.first_kfree == NULL);
        mutex_exit(&gc.lock);
 
        kthread_exit(0);
@@ -195,7 +244,8 @@
 
        mutex_init(&gc.lock, MUTEX_DEFAULT, IPL_VM);
        cv_init(&gc.cv, "lnxrcugc");
-       gc.first = NULL;
+       gc.first_callback = NULL;
+       gc.first_kfree = NULL;
        gc.gen = 0;
        gc.dying = false;
 
@@ -224,7 +274,8 @@
 
        kthread_join(gc.lwp);
        gc.lwp = NULL;
-       KASSERT(gc.first == NULL);
+       KASSERT(gc.first_callback == NULL);
+       KASSERT(gc.first_kfree == NULL);
        cv_destroy(&gc.cv);
        mutex_destroy(&gc.lock);
 }



Home | Main Index | Thread Index | Old Index