svn commit: r344846 - in stable/12/sys: conf kern sys
Konstantin Belousov
kib at FreeBSD.org
Wed Mar 6 17:25:13 UTC 2019
Author: kib
Date: Wed Mar 6 17:25:11 2019
New Revision: 344846
URL: https://svnweb.freebsd.org/changeset/base/344846
Log:
MFC r344351:
Implement rangesets.
Added:
stable/12/sys/kern/subr_rangeset.c
- copied unchanged from r344351, head/sys/kern/subr_rangeset.c
stable/12/sys/sys/_rangeset.h
- copied unchanged from r344351, head/sys/sys/_rangeset.h
stable/12/sys/sys/rangeset.h
- copied unchanged from r344351, head/sys/sys/rangeset.h
Modified:
stable/12/sys/conf/files
Directory Properties:
stable/12/ (props changed)
Modified: stable/12/sys/conf/files
==============================================================================
--- stable/12/sys/conf/files Wed Mar 6 16:50:14 2019 (r344845)
+++ stable/12/sys/conf/files Wed Mar 6 17:25:11 2019 (r344846)
@@ -3919,6 +3919,7 @@ kern/subr_pidctrl.c standard
kern/subr_power.c standard
kern/subr_prf.c standard
kern/subr_prof.c standard
+kern/subr_rangeset.c standard
kern/subr_rman.c standard
kern/subr_rtc.c standard
kern/subr_sbuf.c standard
Copied: stable/12/sys/kern/subr_rangeset.c (from r344351, head/sys/kern/subr_rangeset.c)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/12/sys/kern/subr_rangeset.c Wed Mar 6 17:25:11 2019 (r344846, copy of r344351, head/sys/kern/subr_rangeset.c)
@@ -0,0 +1,365 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/pctrie.h>
+#include <sys/rangeset.h>
+#include <vm/uma.h>
+
+#ifdef DIAGNOSTIC
+static void rangeset_check(struct rangeset *rs);
+#else
+#define rangeset_check(rs)
+#endif
+
+static uma_zone_t rs_node_zone;
+
+static void
+rs_rangeset_init(void *arg __unused)
+{
+
+ rs_node_zone = uma_zcreate("rangeset pctrie nodes",
+ pctrie_node_size(), NULL, NULL, pctrie_zone_init, NULL,
+ UMA_ALIGN_PTR, 0);
+}
+SYSINIT(rs, SI_SUB_LOCK, SI_ORDER_ANY, rs_rangeset_init, NULL);
+
+static void *
+rs_node_alloc(struct pctrie *ptree)
+{
+ struct rangeset *rs;
+
+ rs = __containerof(ptree, struct rangeset, rs_trie);
+ return (uma_zalloc(rs_node_zone, rs->rs_alloc_flags));
+}
+
+static void
+rs_node_free(struct pctrie *ptree __unused, void *node)
+{
+
+ uma_zfree(rs_node_zone, node);
+}
+
+void
+rangeset_init(struct rangeset *rs, rs_dup_data_t dup_data,
+ rs_free_data_t free_data, void *data_ctx, u_int alloc_flags)
+{
+
+ pctrie_init(&rs->rs_trie);
+ rs->rs_dup_data = dup_data;
+ rs->rs_free_data = free_data;
+ rs->rs_data_ctx = data_ctx;
+ rs->rs_alloc_flags = alloc_flags;
+}
+
+void
+rangeset_fini(struct rangeset *rs)
+{
+
+ rangeset_check(rs);
+ rangeset_remove_all(rs);
+}
+
+bool
+rangeset_check_empty(struct rangeset *rs, uint64_t start, uint64_t end)
+{
+ struct rs_el *r;
+ uint64_t *r1;
+
+ rangeset_check(rs);
+ r1 = pctrie_lookup_le(&rs->rs_trie, end);
+ if (r1 != NULL) {
+ r = __containerof(r1, struct rs_el, re_start);
+ if (r->re_end > start)
+ return (false);
+ }
+ return (true);
+}
+
+int
+rangeset_insert(struct rangeset *rs, uint64_t start, uint64_t end,
+ void *data)
+{
+ struct rs_el *r;
+ int error;
+
+ rangeset_check(rs);
+ error = rangeset_remove(rs, start, end);
+ if (error != 0)
+ return (error);
+ r = data;
+ r->re_start = start;
+ r->re_end = end;
+ error = pctrie_insert(&rs->rs_trie, &r->re_start, rs_node_alloc);
+ rangeset_check(rs);
+ return (error);
+}
+
+int
+rangeset_remove_pred(struct rangeset *rs, uint64_t start, uint64_t end,
+ rs_pred_t pred)
+{
+ struct rs_el *r, *rn;
+ uint64_t *r1;
+ int error;
+
+ rangeset_check(rs);
+ error = 0;
+ for (; end > 0 && start < end;) {
+ r1 = pctrie_lookup_le(&rs->rs_trie, end - 1);
+ if (r1 == NULL)
+ break;
+ r = __containerof(r1, struct rs_el, re_start);
+
+ /*
+ * ------============================--|-------|----
+ * rs re s e
+ */
+ if (r->re_end <= start)
+ break;
+
+ if (r->re_end <= end) {
+ if (r->re_start < start) {
+ /*
+ * ------========|==============-------|----
+ * rs s re e
+ */
+ if (pred(rs->rs_data_ctx, r))
+ r->re_end = start;
+ break;
+ }
+
+ /*
+ * ------|--------===================----------|----
+ * s rs re e
+ */
+ end = r->re_start;
+ if (pred(rs->rs_data_ctx, r)) {
+ pctrie_remove(&rs->rs_trie, r->re_start,
+ rs_node_free);
+ rs->rs_free_data(rs->rs_data_ctx, r);
+ }
+ continue;
+ }
+
+ /*
+ * ------|--------====================|==========----
+ * s rs e re
+ */
+ if (r->re_start >= start) {
+ if (pred(rs->rs_data_ctx, r)) {
+ pctrie_remove(&rs->rs_trie, r->re_start,
+ rs_node_free);
+ r->re_start = end;
+ error = pctrie_insert(&rs->rs_trie,
+ &r->re_start, rs_node_alloc);
+ /*
+ * The insert above must succeed
+ * because rs_node zone is marked
+ * nofree and we freed one element
+ * just before.
+ */
+ MPASS(error == 0);
+ } else {
+ end = r->re_start;
+ }
+ continue;
+ }
+
+ /*
+ * ------=========|===================|==========----
+ * rs s e re
+ */
+ if (pred(rs->rs_data_ctx, r)) {
+ /*
+ * Split. Can only happen once, and then if
+ * any allocation fails, the rangeset is kept
+ * intact.
+ */
+ rn = rs->rs_dup_data(rs->rs_data_ctx, r);
+ if (rn == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ rn->re_start = end;
+ rn->re_end = r->re_end;
+ error = pctrie_insert(&rs->rs_trie, &rn->re_start,
+ rs_node_alloc);
+ if (error != 0) {
+ rs->rs_free_data(rs->rs_data_ctx, rn);
+ break;
+ }
+ r->re_end = start;
+ }
+ break;
+ }
+ rangeset_check(rs);
+ return (error);
+}
+
+static bool
+rangeset_true_pred(void *ctx __unused, void *r __unused)
+{
+
+ return (true);
+}
+
+int
+rangeset_remove(struct rangeset *rs, uint64_t start, uint64_t end)
+{
+
+ return (rangeset_remove_pred(rs, start, end, rangeset_true_pred));
+}
+
+void
+rangeset_remove_all(struct rangeset *rs)
+{
+ struct rs_el *r;
+ uint64_t *r1;
+
+ for (;;) {
+ r1 = pctrie_lookup_ge(&rs->rs_trie, 0);
+ if (r1 == NULL)
+ break;
+ r = __containerof(r1, struct rs_el, re_start);
+ pctrie_remove(&rs->rs_trie, r->re_start, rs_node_free);
+ rs->rs_free_data(rs->rs_data_ctx, r);
+ }
+}
+
+void *
+rangeset_lookup(struct rangeset *rs, uint64_t place)
+{
+ struct rs_el *r;
+ uint64_t *r1;
+
+ rangeset_check(rs);
+ r1 = pctrie_lookup_le(&rs->rs_trie, place);
+ if (r1 == NULL)
+ return (NULL);
+ r = __containerof(r1, struct rs_el, re_start);
+ if (r->re_end <= place)
+ return (NULL);
+ return (r);
+}
+
+int
+rangeset_copy(struct rangeset *dst_rs, struct rangeset *src_rs)
+{
+ struct rs_el *src_r, *dst_r;
+ uint64_t cursor, *r1;
+ int error;
+
+ MPASS(pctrie_is_empty(&dst_rs->rs_trie));
+ rangeset_check(src_rs);
+ MPASS(dst_rs->rs_dup_data == src_rs->rs_dup_data);
+
+ error = 0;
+ for (cursor = 0;; cursor = src_r->re_start + 1) {
+ r1 = pctrie_lookup_ge(&src_rs->rs_trie, cursor);
+ if (r1 == NULL)
+ break;
+ src_r = __containerof(r1, struct rs_el, re_start);
+ dst_r = dst_rs->rs_dup_data(dst_rs->rs_data_ctx, src_r);
+ if (dst_r == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ error = pctrie_insert(&dst_rs->rs_trie, &dst_r->re_start,
+ rs_node_alloc);
+ if (error != 0)
+ break;
+ }
+ if (error != 0)
+ rangeset_remove_all(dst_rs);
+ return (error);
+}
+
+#ifdef DIAGNOSTIC
+static void
+rangeset_check(struct rangeset *rs)
+{
+ struct rs_el *r, *rp;
+ uint64_t cursor, *r1;
+
+ for (cursor = 0, rp = NULL;; cursor = r->re_start + 1, rp = r) {
+ r1 = pctrie_lookup_ge(&rs->rs_trie, cursor);
+ if (r1 == NULL)
+ break;
+ r = __containerof(r1, struct rs_el, re_start);
+ KASSERT(r->re_start < r->re_end,
+ ("invalid interval rs %p elem %p (%#jx, %#jx)",
+ rs, r, (uintmax_t)r->re_start, (uintmax_t)r->re_end));
+ if (rp != NULL) {
+ KASSERT(rp->re_end <= r->re_start,
+ ("non-ascending neighbors rs %p "
+ "prev elem %p (%#jx, %#jx) elem %p (%#jx, %#jx)",
+ rs, rp, (uintmax_t)rp->re_start,
+ (uintmax_t)rp->re_end, r, (uintmax_t)r->re_start,
+ (uintmax_t)r->re_end));
+ }
+ }
+}
+#endif
+
+#include "opt_ddb.h"
+#ifdef DDB
+#include <sys/kernel.h>
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(rangeset, rangeset_show_fn)
+{
+ struct rangeset *rs;
+ struct rs_el *r;
+ uint64_t cursor, *r1;
+
+ if (!have_addr) {
+ db_printf("show rangeset addr\n");
+ return;
+ }
+
+ rs = (struct rangeset *)addr;
+ db_printf("rangeset %p\n", rs);
+ for (cursor = 0;; cursor = r->re_start + 1) {
+ r1 = pctrie_lookup_ge(&rs->rs_trie, cursor);
+ if (r1 == NULL)
+ break;
+ r = __containerof(r1, struct rs_el, re_start);
+ db_printf(" el %p start %#jx end %#jx\n",
+ r, r->re_start, r->re_end);
+ }
+}
+#endif
Copied: stable/12/sys/sys/_rangeset.h (from r344351, head/sys/sys/_rangeset.h)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/12/sys/sys/_rangeset.h Wed Mar 6 17:25:11 2019 (r344846, copy of r344351, head/sys/sys/_rangeset.h)
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS__RANGESET_H
+#define _SYS__RANGESET_H
+
+#include <sys/_pctrie.h>
+
+typedef void *(*rs_dup_data_t)(void *ctx, void *data);
+typedef void (*rs_free_data_t)(void *ctx, void *data);
+
+struct rangeset {
+ struct pctrie rs_trie;
+ rs_dup_data_t rs_dup_data;
+ rs_free_data_t rs_free_data;
+ void *rs_data_ctx;
+ u_int rs_alloc_flags;
+};
+
+#endif
+
Copied: stable/12/sys/sys/rangeset.h (from r344351, head/sys/sys/rangeset.h)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/12/sys/sys/rangeset.h Wed Mar 6 17:25:11 2019 (r344846, copy of r344351, head/sys/sys/rangeset.h)
@@ -0,0 +1,88 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_RANGESET_H
+#define _SYS_RANGESET_H
+
+#ifdef _KERNEL
+
+#include <sys/_rangeset.h>
+
+typedef bool (*rs_pred_t)(void *ctx, void *r);
+
+/*
+ * This structure must be embedded at the start of the rangeset element.
+ */
+struct rs_el {
+ uint64_t re_start; /* pctrie key */
+ uint64_t re_end;
+};
+
+void rangeset_init(struct rangeset *rs, rs_dup_data_t dup_data,
+ rs_free_data_t free_data, void *rs_data_ctx, u_int alloc_flags);
+void rangeset_fini(struct rangeset *rs);
+
+bool rangeset_check_empty(struct rangeset *rs, uint64_t start,
+ uint64_t end);
+
+/*
+ * r point to the app data with struct rs_el at the beginning.
+ */
+int rangeset_insert(struct rangeset *rs, uint64_t start, uint64_t end,
+ void *r);
+
+/*
+ * Guarantees that on error the rangeset is not modified. Remove
+ * might need to split element if its start/end completely cover the
+ * removed range, in which case ENOMEM might be returned.
+ */
+void rangeset_remove_all(struct rangeset *rs);
+int rangeset_remove(struct rangeset *rs, uint64_t start, uint64_t end);
+int rangeset_remove_pred(struct rangeset *rs, uint64_t start,
+ uint64_t end, rs_pred_t pred);
+
+/*
+ * Really returns the pointer to the data with struct rs_el embedded
+ * at the beginning.
+ */
+void *rangeset_lookup(struct rangeset *rs, uint64_t place);
+
+/*
+ * Copies src_rs entries into dst_rs. dst_rs must be empty.
+ * Leaves dst_rs empty on failure.
+ */
+int rangeset_copy(struct rangeset *dst_rs, struct rangeset *src_rs);
+
+#endif
+
+#endif
More information about the svn-src-all
mailing list