Index: sys/pool.h =================================================================== RCS file: /cvs/src/sys/sys/pool.h,v retrieving revision 1.78 diff -u -p -r1.78 pool.h --- sys/pool.h 2 Jan 2021 03:23:59 -0000 1.78 +++ sys/pool.h 5 Jan 2023 03:09:54 -0000 @@ -284,6 +284,15 @@ void pool_printit(struct pool *, const int (*)(const char *, ...)); void pool_walk(struct pool *, int, int (*)(const char *, ...), void (*)(void *, int, int (*)(const char *, ...))); + +int pool_inspect(struct pool *, void *); + +/* pool_inspect return values */ +#define POOL_ITEM_NULL 0x0 /* item is NULL */ +#define POOL_ITEM_INUSE 0x1 +#define POOL_ITEM_FREE 0x2 +#define POOL_ITEM_UNALIGNED 0x3 /* item is on a page, but misaligned */ +#define POOL_ITEM_INVALID 0x4 /* item is not on a page */ #endif /* the allocator for dma-able memory is a thin layer on top of pool */ Index: kern/subr_pool.c =================================================================== RCS file: /cvs/src/sys/kern/subr_pool.c,v retrieving revision 1.236 diff -u -p -r1.236 subr_pool.c --- kern/subr_pool.c 14 Aug 2022 01:58:28 -0000 1.236 +++ kern/subr_pool.c 5 Jan 2023 03:09:55 -0000 @@ -1023,8 +1023,7 @@ pool_p_insert(struct pool *pp, struct po pp->pr_curpage = ph; TAILQ_INSERT_TAIL(&pp->pr_emptypages, ph, ph_entry); - if (!POOL_INPGHDR(pp)) - RBT_INSERT(phtree, &pp->pr_phtree, ph); + RBT_INSERT(phtree, &pp->pr_phtree, ph); pp->pr_nitems += pp->pr_itemsperpage; pp->pr_nidle++; @@ -1044,8 +1043,7 @@ pool_p_remove(struct pool *pp, struct po pp->pr_nidle--; pp->pr_nitems -= pp->pr_itemsperpage; - if (!POOL_INPGHDR(pp)) - RBT_REMOVE(phtree, &pp->pr_phtree, ph); + RBT_REMOVE(phtree, &pp->pr_phtree, ph); TAILQ_REMOVE(&pp->pr_emptypages, ph, ph_entry); pool_update_curpage(pp); @@ -1453,6 +1451,49 @@ pool_walk(struct pool *pp, int full, cp += pp->pr_size; } while (n > 0); } +} + +int +pool_inspect(struct pool *pp, void *v) +{ + struct pool_page_header *ph, key; + struct pool_item *pi; + caddr_t addr; + size_t diff; + + if (v == NULL) + return (POOL_ITEM_NULL); + + addr = (caddr_t)v; + + /* we can't trust v, so always look in the tree */ + key.ph_page = v; + ph = RBT_NFIND(phtree, &pp->pr_phtree, &key); + if (ph == NULL) + return (POOL_ITEM_INVALID); + + /* item is off the end of the page? */ + if (ph->ph_page + pp->pr_pgsize <= addr) + return (POOL_ITEM_INVALID); + + diff = addr - ph->ph_colored; + /* item is on the page but unaligned? */ + if (diff % pp->pr_size) + return (POOL_ITEM_UNALIGNED); + + /* item is off the data portion of the page */ + diff /= pp->pr_size; + if (diff >= pp->pr_itemsperpage) + return (POOL_ITEM_INVALID); + + XSIMPLEQ_FOREACH(pi, &ph->ph_items, pi_list) { + if ((caddr_t)pi == addr) { + /* check the magic? */ + return (POOL_ITEM_FREE); + } + } + + return (POOL_ITEM_INUSE); } #endif Index: ddb/db_command.c =================================================================== RCS file: /cvs/src/sys/ddb/db_command.c,v retrieving revision 1.97 diff -u -p -r1.97 db_command.c --- ddb/db_command.c 5 Nov 2022 19:29:45 -0000 1.97 +++ ddb/db_command.c 5 Jan 2023 03:09:55 -0000 @@ -983,3 +983,82 @@ db_write_cmd(db_expr_t address, int have db_skip_to_eol(); } + +#include + +/* + * go over an RBT populated with pool entries, and inspect their validity + * + * awk ' + * BEGIN { print "digraph {" } + * END { print "}" } + * ($3 != "NULL") { print "n" $1 " -> n" $3 " [label=\"" $2 "\"]" } + * ' | dot + */ + +static const char *db_pool_inspect_names[] = { + [POOL_ITEM_NULL] = "null", + [POOL_ITEM_INUSE] = "in use", + [POOL_ITEM_FREE] = "free", + [POOL_ITEM_UNALIGNED] = "unaligned", + [POOL_ITEM_INVALID] = "invalid", +}; + +static void +db_rbe_x_pool(struct pool *pp, int verbose, const struct rb_type *rbt, + void *parent, void *rbe, const char *label) +{ + void *rbe_p, *rbe_l, *rbe_r; + int rv; + + if (rbe == NULL) { + if (verbose) + db_printf("%p %s NULL\n", parent, label); + return; + } + + if (verbose) + db_printf("%p %s %p\n", parent, label, rbe); + + rv = pool_inspect(pp, rbe); + if (rv != POOL_ITEM_INUSE) { + db_printf("! %p %s %p: %s\n", parent, label, rbe, + db_pool_inspect_names[rv]); + return; + } + + rbe_p = _rb_parent(rbt, rbe); + if (rbe_p != parent) { + db_printf("# %p %s %p: parent %p mismatch\n", + parent, label, rbe, rbe_p); + } + + rbe_l = _rb_left(rbt, rbe); + db_rbe_x_pool(pp, verbose, rbt, rbe, rbe_l, "left"); + if (rbe_l != NULL && rbt->t_compare(rbe_l, rbe) >= 0) { + db_printf("! %p left %p: unexpected compare result\n", + rbe, rbe_l); + } + + rbe_r = _rb_right(rbt, rbe); + db_rbe_x_pool(pp, verbose, rbt, rbe, rbe_r, "right"); + if (rbe_r != NULL && rbt->t_compare(rbe, rbe_r) >= 0) { + db_printf("! %p right %p: unexpected compare result\n", + rbe, rbe_r); + } + + if (rbe_l != NULL && rbe_r != NULL && + rbt->t_compare(rbe_l, rbe_r) >= 0) { + db_printf("! %p sibling %p: unexpected compare result\n", + rbe_l, rbe_r); + } +} + +void +db_rbt_x_pool(struct pool *pp, int verbose, const struct rb_type *rbt, + struct rb_tree *tree) +{ + void *rbe = _rb_root(rbt, tree); + + db_rbe_x_pool(pp, verbose, rbt, NULL, rbe, "root"); +}