gtfs: Use a kernel message to destroy the gtfs
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 27 Jun 2018 17:55:12 +0000 (13:55 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 27 Jun 2018 18:10:36 +0000 (14:10 -0400)
You can't use blocking RCU primitives, such as rcu_barrier(), from within
an RCU callback.  Release methods, such as gtfs_release(), are often called
from a lot of contexts - anywhere you might decref - including RCU
callbacks.

As they say, all problems in CS can be solved with a level of indirection.
Using a kernel message decouples the work we want to do from the current
thread context, which is unable to use RCU barrier et. al.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/gtfs.c

index 5962975..6a596ea 100644 (file)
@@ -187,9 +187,9 @@ static void purge_cb(struct tree_file *tf)
        poperror();
 }
 
-static void gtfs_release(struct kref *kref)
+static void __gtfs_destroy(uint32_t srcid, long a0, long a1, long a2)
 {
-       struct gtfs *gtfs = container_of(kref, struct gtfs, users);
+       struct gtfs *gtfs = (struct gtfs*)a0;
 
        tfs_frontend_purge(&gtfs->tfs, purge_cb);
        /* this is the ref from attach */
@@ -201,6 +201,18 @@ static void gtfs_release(struct kref *kref)
        kfree(gtfs);
 }
 
+static void gtfs_release(struct kref *kref)
+{
+       struct gtfs *gtfs = container_of(kref, struct gtfs, users);
+
+       /* We can't use RCU within an RCU callback, and release methods are often
+        * called from within callbacks.  We can use a kernel message, which can
+        * block and do whatever else it wants.  In essence, we break the connection
+        * to our current context (the rcu_mgmt_ktask) by using a kmsg. */
+       send_kernel_message(core_id(), __gtfs_destroy, (long)gtfs, 0, 0,
+                           KMSG_ROUTINE);
+}
+
 static struct gtfs *chan_to_gtfs(struct chan *c)
 {
        struct tree_file *tf = chan_to_tree_file(c);