-/* $OpenBSD: art.c,v 1.19 2016/06/14 04:42:02 jmatthew Exp $ */
+/* $OpenBSD: art.c,v 1.20 2016/06/22 06:32:32 dlg Exp $ */
/*
* Copyright (c) 2015 Martin Pieuchot
int, struct art_node *);
struct art_node *art_table_delete(struct art_root *, struct art_table *,
int, struct art_node *);
-void art_table_ref(struct art_root *, struct art_table *);
+struct art_table *art_table_ref(struct art_root *, struct art_table *);
int art_table_free(struct art_root *, struct art_table *);
int art_table_walk(struct art_root *, struct art_table *,
int (*f)(struct art_node *, void *), void *);
+int art_walk_apply(struct art_root *,
+ struct art_node *, struct art_node *,
+ int (*f)(struct art_node *, void *), void *);
void art_table_gc(void *);
void art_gc(void *);
return (an);
}
-void
+struct art_table *
art_table_ref(struct art_root *ar, struct art_table *at)
{
at->at_refcnt++;
+ return (at);
}
static inline int
int
art_walk(struct art_root *ar, int (*f)(struct art_node *, void *), void *arg)
{
+ struct srp_ref sr;
struct art_table *at;
struct art_node *node;
- int error;
-
- KERNEL_ASSERT_LOCKED();
+ int error = 0;
+ KERNEL_LOCK();
at = srp_get_locked(&ar->ar_root);
- if (at == NULL)
- return (0);
+ if (at != NULL) {
+ art_table_ref(ar, at);
- /*
- * The default route should be processed here because the root
- * table does not have a parent.
- */
- node = srp_get_locked(&at->at_default);
- if (node != NULL) {
- error = (*f)(node, arg);
- if (error)
- return (error);
+ /*
+ * The default route should be processed here because the root
+ * table does not have a parent.
+ */
+ node = srp_enter(&sr, &at->at_default);
+ error = art_walk_apply(ar, node, NULL, f, arg);
+ srp_leave(&sr);
+
+ if (error == 0)
+ error = art_table_walk(ar, at, f, arg);
+
+ art_table_free(ar, at);
}
+ KERNEL_UNLOCK();
- return (art_table_walk(ar, at, f, arg));
+ return (error);
}
int
art_table_walk(struct art_root *ar, struct art_table *at,
int (*f)(struct art_node *, void *), void *arg)
{
- struct art_node *next, *an = NULL;
- struct art_node *node;
+ struct srp_ref sr;
+ struct art_node *node, *next;
+ struct art_table *nat;
int i, j, error = 0;
uint32_t maxfringe = (at->at_minfringe << 1);
- /* Prevent this table to be freed while we're manipulating it. */
- art_table_ref(ar, at);
-
/*
* Iterate non-fringe nodes in ``natural'' order.
*/
*/
for (i = max(j, 2); i < at->at_minfringe; i <<= 1) {
next = srp_get_locked(&at->at_heap[i >> 1].node);
- an = srp_get_locked(&at->at_heap[i].node);
- if ((an != NULL) && (an != next)) {
- error = (*f)(an, arg);
- if (error)
- goto out;
- }
+
+ node = srp_enter(&sr, &at->at_heap[i].node);
+ error = art_walk_apply(ar, node, next, f, arg);
+ srp_leave(&sr);
+
+ if (error != 0)
+ return (error);
}
}
*/
for (i = at->at_minfringe; i < maxfringe; i++) {
next = srp_get_locked(&at->at_heap[i >> 1].node);
- node = srp_get_locked(&at->at_heap[i].node);
- if (!ISLEAF(node))
- an = srp_get_locked(&SUBTABLE(node)->at_default);
- else
- an = node;
- if ((an != NULL) && (an != next)) {
- error = (*f)(an, arg);
- if (error)
- goto out;
+ node = srp_enter(&sr, &at->at_heap[i].node);
+ if (!ISLEAF(node)) {
+ nat = art_table_ref(ar, SUBTABLE(node));
+ node = srp_follow(&sr, &nat->at_default);
+ } else
+ nat = NULL;
+
+ error = art_walk_apply(ar, node, next, f, arg);
+ srp_leave(&sr);
+
+ if (error != 0) {
+ art_table_free(ar, nat);
+ return (error);
}
- if (ISLEAF(node))
- continue;
+ if (nat != NULL) {
+ error = art_table_walk(ar, nat, f, arg);
+ art_table_free(ar, nat);
+ if (error != 0)
+ return (error);
+ }
+ }
- error = art_table_walk(ar, SUBTABLE(node), f, arg);
- if (error)
- break;
+ return (0);
+}
+
+int
+art_walk_apply(struct art_root *ar,
+ struct art_node *an, struct art_node *next,
+ int (*f)(struct art_node *, void *), void *arg)
+{
+ int error = 0;
+
+ if ((an != NULL) && (an != next)) {
+ /* this assumes an->an_dst is not used by f */
+ KERNEL_UNLOCK();
+ error = (*f)(an, arg);
+ KERNEL_LOCK();
}
-out:
- art_table_free(ar, at);
return (error);
}