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