Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp274164ybp; Thu, 3 Oct 2019 13:23:43 -0700 (PDT) X-Google-Smtp-Source: APXvYqyqrnEOvyxIY4Jl3JZctZlA7eRUHconr8/HBJ3C++TSshrPFdgaxFL2a0C1tr05rAhhdMQM X-Received: by 2002:a50:9625:: with SMTP id y34mr11380677eda.72.1570134222905; Thu, 03 Oct 2019 13:23:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1570134222; cv=none; d=google.com; s=arc-20160816; b=FKBBrlFe7pxGCXiZduN3+qWhuf1HeOOMIT1iOdqei72c5DnLmCsI3CPuXbZGZ8mzjP 7Qeh3Q4vNWojIez9E5foLrp0B0M8Rqp7pB5Y1FwOhPrZp1Wu2Ppbzx+9AMlZSnbHb9GZ Ulyy041c74o47EDufihVVKzv91jLatSBXsi92UCBMl54MB40F8zNQELXLYalfEMrKllA 4/ncA6zKxbNqaIUDKGiGk0dqs5exyhJT4rVbufY6OKUv+SWKwMPN/XQ2xCplUFQHWlzr sqYo3UQ+6xu0hwCnMobMzLpab9sU35BEQ1759ionXDH1gGRP75pcUxmSNo8FJEj+bP2x TOwg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=poyNwJSq8jC1oSwRgEf9oT2/lxxYJiqxRXcV5ZsTOmU=; b=h0Z2dLLbj1kZFQxQvB0c4+k//ntMSHdNtUF9UtOsjVyjS88oSg+qC/2JS6UN+ODOS1 xNcZgE1eNyLk/1E872qDvBl7HicPyeXFsOIPR1BJgey4yorQFyelfvNz8YYTgwR1yk4v Xln3J1NkxAxosCRK4F8+Ipb5FMACWVXjpHkGDnjF3JYpF5AAtHKw61tvMWM/1Sw4VjWV XlcwmW387Mn2RdjkHy2fJJVclwC0oJs3dmQB0krbmaljysiBZmnvHuV0Q5c0uRlFpTJv 9b0lLzfq80Kr7tHEWzas75vg8u+vZ35+Ccn2fgFR1YRgo4cA9XIbNLeE9dKo3ZKf9V4U E47Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g37si2275515edg.59.2019.10.03.13.23.18; Thu, 03 Oct 2019 13:23:42 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729278AbfJCUUS (ORCPT + 99 others); Thu, 3 Oct 2019 16:20:18 -0400 Received: from mx2.suse.de ([195.135.220.15]:46416 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1733146AbfJCUUP (ORCPT ); Thu, 3 Oct 2019 16:20:15 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id D3484B052; Thu, 3 Oct 2019 20:20:12 +0000 (UTC) From: Davidlohr Bueso To: akpm@linux-foundation.org Cc: walken@google.com, peterz@infradead.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, dri-devel@lists.freedesktop.org, linux-rdma@vger.kernel.org, dave@stgolabs.net, Davidlohr Bueso Subject: [PATCH 02/11] lib/interval-tree: add an equivalent tree with [a,b) intervals Date: Thu, 3 Oct 2019 13:18:49 -0700 Message-Id: <20191003201858.11666-3-dave@stgolabs.net> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20191003201858.11666-1-dave@stgolabs.net> References: <20191003201858.11666-1-dave@stgolabs.net> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org While the kernel's interval tree implementation uses closed intervals, all users (with the exception of query stabbing) really want half closed intervals, specifically [a, b), and will explicitly correct this before calling the tree api. This patch simply duplicates the include/linuxinterval_tree_generic.h header into a interval_tree_gen.h (gen as in 'generic' and 'generate' :-) with two differences: - The 'last' endpoint is renamed 'end'; this is something lib/interval_tree.c will also need to update, but that is later in the series. - The lookup calls have been adapted accordingly, such that users need not need to do the subtraction by one fixup. No users are ported over in this patch. Signed-off-by: Davidlohr Bueso --- include/linux/interval_tree_gen.h | 179 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 include/linux/interval_tree_gen.h diff --git a/include/linux/interval_tree_gen.h b/include/linux/interval_tree_gen.h new file mode 100644 index 000000000000..5d446c0bd89a --- /dev/null +++ b/include/linux/interval_tree_gen.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + Interval Trees + (C) 2012 Michel Lespinasse +*/ + +#include + +/* + * Template for implementing interval trees + * + * ITSTRUCT: struct type of the interval tree nodes + * ITRB: name of struct rb_node field within ITSTRUCT + * ITTYPE: type of the interval endpoints + * ITSUBTREE: name of ITTYPE field within ITSTRUCT holding end-in-subtree + * ITSTART(n): start endpoint of ITSTRUCT node n + * ITEND(n): end/last endpoint of ITSTRUCT node n + * ITSTATIC: 'static' or empty + * ITPREFIX: prefix to use for the inline tree definitions + * + * Note - before using this, please consider if generic version + * (interval_tree.h) would work for you... + */ + +#define INTERVAL_TREE_DEFINE(ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, \ + ITSTART, ITEND, ITSTATIC, ITPREFIX) \ + \ +/* Callbacks for augmented rbtree insert and remove */ \ + \ +RB_DECLARE_CALLBACKS_MAX(static, ITPREFIX ## _augment, \ + ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, ITEND) \ + \ +/* Insert / remove interval nodes from the tree */ \ + \ +ITSTATIC void ITPREFIX ## _insert(ITSTRUCT *node, \ + struct rb_root_cached *root) \ +{ \ + struct rb_node **link = &root->rb_root.rb_node, *rb_parent = NULL; \ + ITTYPE start = ITSTART(node), end = ITEND(node); \ + ITSTRUCT *parent; \ + bool leftmost = true; \ + \ + while (*link) { \ + rb_parent = *link; \ + parent = rb_entry(rb_parent, ITSTRUCT, ITRB); \ + if (parent->ITSUBTREE < end) \ + parent->ITSUBTREE = end; \ + if (start < ITSTART(parent)) \ + link = &parent->ITRB.rb_left; \ + else { \ + link = &parent->ITRB.rb_right; \ + leftmost = false; \ + } \ + } \ + \ + node->ITSUBTREE = end; \ + rb_link_node(&node->ITRB, rb_parent, link); \ + rb_insert_augmented_cached(&node->ITRB, root, \ + leftmost, &ITPREFIX ## _augment); \ +} \ + \ +ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \ + struct rb_root_cached *root) \ +{ \ + rb_erase_augmented_cached(&node->ITRB, root, &ITPREFIX ## _augment); \ +} \ + \ +/* \ + * Iterate over intervals intersecting [start;end) \ + * \ + * Note that a node's interval intersects [start;end) iff: \ + * Cond1: ITSTART(node) < end \ + * and \ + * Cond2: start < ITEND(node) \ + */ \ + \ +static ITSTRUCT * \ +ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE end) \ +{ \ + while (true) { \ + /* \ + * Loop invariant: start <= node->ITSUBTREE \ + * (Cond2 is satisfied by one of the subtree nodes) \ + */ \ + if (node->ITRB.rb_left) { \ + ITSTRUCT *left = rb_entry(node->ITRB.rb_left, \ + ITSTRUCT, ITRB); \ + if (start < left->ITSUBTREE) { \ + /* \ + * Some nodes in left subtree satisfy Cond2. \ + * Iterate to find the leftmost such node N. \ + * If it also satisfies Cond1, that's the \ + * match we are looking for. Otherwise, there \ + * is no matching interval as nodes to the \ + * right of N can't satisfy Cond1 either. \ + */ \ + node = left; \ + continue; \ + } \ + } \ + if (ITSTART(node) < end) { /* Cond1 */ \ + if (start < ITEND(node)) /* Cond2 */ \ + return node; /* node is leftmost match */ \ + if (node->ITRB.rb_right) { \ + node = rb_entry(node->ITRB.rb_right, \ + ITSTRUCT, ITRB); \ + if (start <= node->ITSUBTREE) \ + continue; \ + } \ + } \ + return NULL; /* No match */ \ + } \ +} \ + \ +ITSTATIC ITSTRUCT * \ +ITPREFIX ## _iter_first(struct rb_root_cached *root, \ + ITTYPE start, ITTYPE end) \ +{ \ + ITSTRUCT *node, *leftmost; \ + \ + if (!root->rb_root.rb_node) \ + return NULL; \ + \ + /* \ + * Fastpath range intersection/overlap where we compare the \ + * smallest 'start' and largest 'end' in the tree. For the latter, \ + * we rely on the root node, which by augmented interval tree \ + * property, holds the largest value in its end-in-subtree. \ + * This allows mitigating some of the tree walk overhead for \ + * for non-intersecting ranges, maintained and consulted in O(1). \ + */ \ + node = rb_entry(root->rb_root.rb_node, ITSTRUCT, ITRB); \ + if (node->ITSUBTREE <= start) /* !Cond2 */ \ + return NULL; \ + \ + leftmost = rb_entry(root->rb_leftmost, ITSTRUCT, ITRB); \ + if (ITSTART(leftmost) >= end) /* !Cond1 */ \ + return NULL; \ + \ + return ITPREFIX ## _subtree_search(node, start, end); \ +} \ + \ +ITSTATIC ITSTRUCT * \ +ITPREFIX ## _iter_next(ITSTRUCT *node, ITTYPE start, ITTYPE end) \ +{ \ + struct rb_node *rb = node->ITRB.rb_right, *prev; \ + \ + while (true) { \ + /* \ + * Loop invariants: \ + * Cond1: ITSTART(node) < end \ + * rb == node->ITRB.rb_right \ + * \ + * First, search right subtree if suitable \ + */ \ + if (rb) { \ + ITSTRUCT *right = rb_entry(rb, ITSTRUCT, ITRB); \ + if (start < right->ITSUBTREE) \ + return ITPREFIX ## _subtree_search(right, \ + start, end); \ + } \ + \ + /* Move up the tree until we come from a node's left child */ \ + do { \ + rb = rb_parent(&node->ITRB); \ + if (!rb) \ + return NULL; \ + prev = &node->ITRB; \ + node = rb_entry(rb, ITSTRUCT, ITRB); \ + rb = node->ITRB.rb_right; \ + } while (prev == rb); \ + \ + /* Check if the node intersects [start;end) */ \ + if (end <= ITSTART(node)) /* !Cond1 */ \ + return NULL; \ + else if (start < ITEND(node)) /* Cond2 */ \ + return node; \ + } \ +} -- 2.16.4