Module Name: src Committed By: riastradh Date: Sun Dec 19 11:51:51 UTC 2021
Modified Files: src/sys/external/bsd/drm2/include/linux: radix-tree.h src/sys/external/bsd/drm2/linux: linux_radixtree.c Log Message: linux: Kludgily make radix tree safe for RCU Using a lock is completely stupid (gotta be cpu_simple_lock because there's no radix_tree_destroy or anything), and the nonsense to do unvolatile/unconst is garbage, but it will serve to make this safe for RCU until someone makes our radix tree code RCU-safe (which Someone^TM should totally do). To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/sys/external/bsd/drm2/include/linux/radix-tree.h cvs rdiff -u -r1.1 -r1.2 src/sys/external/bsd/drm2/linux/linux_radixtree.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/drm2/include/linux/radix-tree.h diff -u src/sys/external/bsd/drm2/include/linux/radix-tree.h:1.7 src/sys/external/bsd/drm2/include/linux/radix-tree.h:1.8 --- src/sys/external/bsd/drm2/include/linux/radix-tree.h:1.7 Sun Dec 19 11:51:43 2021 +++ src/sys/external/bsd/drm2/include/linux/radix-tree.h Sun Dec 19 11:51:51 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: radix-tree.h,v 1.7 2021/12/19 11:51:43 riastradh Exp $ */ +/* $NetBSD: radix-tree.h,v 1.8 2021/12/19 11:51:51 riastradh Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -30,6 +30,7 @@ #define _LINUX_RADIX_TREE_H_ #include <sys/radixtree.h> +#include <sys/lock.h> #include <linux/gfp.h> @@ -45,12 +46,13 @@ #define radix_tree_next_slot linux_radix_tree_next_slot struct radix_tree_root { - struct radix_tree rtr_tree; + struct radix_tree rtr_tree; + __cpu_simple_lock_t rtr_lock; /* XXX lame-o */ }; struct radix_tree_iter { - unsigned long index; - struct radix_tree *rti_tree; + unsigned long index; + const struct radix_tree_root *rti_tree; }; void INIT_RADIX_TREE(struct radix_tree_root *, gfp_t); Index: src/sys/external/bsd/drm2/linux/linux_radixtree.c diff -u src/sys/external/bsd/drm2/linux/linux_radixtree.c:1.1 src/sys/external/bsd/drm2/linux/linux_radixtree.c:1.2 --- src/sys/external/bsd/drm2/linux/linux_radixtree.c:1.1 Sun Dec 19 11:51:43 2021 +++ src/sys/external/bsd/drm2/linux/linux_radixtree.c Sun Dec 19 11:51:51 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: linux_radixtree.c,v 1.1 2021/12/19 11:51:43 riastradh Exp $ */ +/* $NetBSD: linux_radixtree.c,v 1.2 2021/12/19 11:51:51 riastradh Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -27,16 +27,25 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_radixtree.c,v 1.1 2021/12/19 11:51:43 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_radixtree.c,v 1.2 2021/12/19 11:51:51 riastradh Exp $"); +#include <sys/atomic.h> +#include <sys/kmem.h> +#include <sys/lock.h> #include <sys/radixtree.h> #include <linux/gfp.h> #include <linux/radix-tree.h> +#include <linux/rcupdate.h> +#include <linux/slab.h> + +/* XXX mega-kludgerific */ +#define __UNVOLANST(p) ((void *)(unsigned long)(const volatile void *)(p)) struct kludge { uint64_t k_key; void *k_datum; + struct rcu_head k_rcu; }; void @@ -44,21 +53,30 @@ INIT_RADIX_TREE(struct radix_tree_root * { radix_tree_init_tree(&root->rtr_tree); + __cpu_simple_lock_init(&root->rtr_lock); } int radix_tree_insert(struct radix_tree_root *root, unsigned long key, void *datum) { struct kludge *kludge; + int error; - if ((kludge = kmem_zalloc(sizeof(*kludge), KM_NOSLEEP)) == NULL) + /* XXX No way to know whether the caller can sleep or not... */ + if ((kludge = kzalloc(sizeof(*kludge), GFP_NOWAIT)) == NULL) return -ENOMEM; kludge->k_key = key; kludge->k_datum = datum; + membar_exit(); + + __cpu_simple_lock(&root->rtr_lock); + error = radix_tree_insert_node(&root->rtr_tree, key, kludge); + __cpu_simple_unlock(&root->rtr_lock); + /* XXX errno NetBSD->Linux */ - return -radix_tree_insert_node(&root->rtr_tree, key, kludge); + return -error; } void * @@ -67,12 +85,14 @@ radix_tree_delete(struct radix_tree_root struct kludge *kludge; void *datum = NULL; - if ((kludge = radix_tree_remove_node(&root->rtr_tree, key)) == NULL) + __cpu_simple_lock(&root->rtr_lock); + kludge = radix_tree_remove_node(&root->rtr_tree, key); + __cpu_simple_unlock(&root->rtr_lock); + if (kludge == NULL) return NULL; - /* XXX RCU defer */ datum = kludge->k_datum; - kmem_free(kludge, sizeof(*kludge)); + kfree_rcu(kludge, k_rcu); return datum; } @@ -80,8 +100,13 @@ radix_tree_delete(struct radix_tree_root bool radix_tree_empty(struct radix_tree_root *root) { + bool empty; + + __cpu_simple_lock(&root->rtr_lock); + empty = radix_tree_empty_tree_p(&root->rtr_tree); + __cpu_simple_unlock(&root->rtr_lock); - return radix_tree_empty_tree_p(&root->rtr_tree); + return empty; } void * @@ -89,9 +114,11 @@ radix_tree_lookup(const struct radix_tre { struct kludge *kludge; - kludge = radix_tree_lookup_node(&root->rtr_tree, key); + __cpu_simple_lock(__UNVOLANST(&root->rtr_lock)); + kludge = radix_tree_lookup_node(__UNVOLANST(&root->rtr_tree), key); + __cpu_simple_unlock(__UNVOLANST(&root->rtr_lock)); if (kludge == NULL) - NULL; + return NULL; return kludge->k_datum; } @@ -118,16 +145,21 @@ radix_tree_next_chunk(const struct radix { void *result; struct kludge *kludge; + unsigned nresults; KASSERT(flags == 0); - if (radix_tree_gang_lookup_node(&root->rtr_tree, I->index, - &result, /*maxresults*/1, /*dense*/false) == 0) + __cpu_simple_lock(__UNVOLANST(&root->rtr_lock)); + nresults = radix_tree_gang_lookup_node(__UNVOLANST(&root->rtr_tree), + I->index, &result, /*maxresults*/1, /*dense*/false); + __cpu_simple_unlock(__UNVOLANST(&root->rtr_lock)); + if (nresults == 0) return NULL; + KASSERT(nresults == 1); kludge = result; I->index = kludge->k_key; - I->rti_tree = &root->rtr_tree; + I->rti_tree = root; return &kludge->k_datum; } @@ -136,17 +168,25 @@ radix_tree_next_slot(void **slot, struct { struct kludge *kludge; void *result; + unsigned nresults; KASSERT(flags == 0); + kludge = container_of(slot, struct kludge, k_datum); - if (radix_tree_gang_lookup_node(I->rtr_tree, kludge->k_key, - &result, /*maxresults*/1, /*dense*/true) == 0) + + __cpu_simple_lock(__UNVOLANST(&I->rti_tree->rtr_lock)); + nresults = radix_tree_gang_lookup_node( + __UNVOLANST(&I->rti_tree->rtr_tree), + kludge->k_key, &result, /*maxresults*/1, /*dense*/true); + __cpu_simple_unlock(__UNVOLANST(&I->rti_tree->rtr_lock)); + if (nresults == 0) return NULL; + KASSERT(nresults == 1); kludge = result; I->index = kludge->k_key; - I->rti_tree = &root->rtr_tree; + /* XXX Hope the tree hasn't changed! */ return &kludge->k_datum; } @@ -157,6 +197,9 @@ radix_tree_iter_delete(struct radix_tree struct kludge *kludge = container_of(slot, struct kludge, k_datum); struct kludge *kludge0 __diagused; + __cpu_simple_lock(&root->rtr_lock); kludge0 = radix_tree_remove_node(&root->rtr_tree, kludge->k_key); + __cpu_simple_unlock(&root->rtr_lock); + KASSERT(kludge0 == kludge); }