From: John Stultz <john.stultz@linaro.org>
To: linux-kernel@vger.kernel.org
Cc: John Stultz <john.stultz@linaro.org>,
Andrew Morton <akpm@linux-foundation.org>,
Android Kernel Team <kernel-team@android.com>,
Robert Love <rlove@google.com>, Mel Gorman <mel@csn.ul.ie>,
Hugh Dickins <hughd@google.com>,
Dave Hansen <dave@linux.vnet.ibm.com>,
Rik van Riel <riel@redhat.com>,
Dmitry Adamushko <dmitry.adamushko@gmail.com>,
Dave Chinner <david@fromorbit.com>, Neil Brown <neilb@suse.de>,
Andrea Righi <andrea@betterlinux.com>,
"Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Subject: [PATCH 1/2] [RFC] Range tree implementation
Date: Fri, 16 Mar 2012 15:51:06 -0700 [thread overview]
Message-ID: <1331938267-13583-2-git-send-email-john.stultz@linaro.org> (raw)
In-Reply-To: <1331938267-13583-1-git-send-email-john.stultz@linaro.org>
After Andrew suggested something like his mumbletree idea
to better store a list of ranges, I worked on a few different
approaches, and this is what I've finally managed to get working.
I suspect range-tree isn't a totally accurate name, but I
couldn't quite make out the difference between range trees
and interval trees, so I just picked one to call it. Do
let me know if you have a better name.
The idea of storing ranges in a tree is nice, but has a number
of complications. When adding a range, its possible that a
large range will consume and merge a number of smaller ranges.
When removing a range, its possible you may end up splitting an
existing range, causing one range to become two. This makes it
very difficult to provide generic list_head like behavior, as
the parent structures would need to be duplicated and removed,
and that has lots of memory ownership issues.
So, this is a much simplified and more list_head like
implementation. You can add a node to a tree, or remove a node
to a tree, but the generic implementation doesn't do the
merging or splitting for you. But it does provide helpers to
find overlapping and adjacent ranges.
Andrew also really wanted this range-tree implementation to be
resuable so we don't duplicate the file locking logic. I'm not
totally convinced that the requirements between the volatile
ranges and file locking are really equivelent, but this reduced
impelementation may make it possible.
Do let me know what you think or if you have other ideas for
better ways to do the same.
Changelog:
v2:
* Reworked code to use an rbtree instead of splaying
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Android Kernel Team <kernel-team@android.com>
CC: Robert Love <rlove@google.com>
CC: Mel Gorman <mel@csn.ul.ie>
CC: Hugh Dickins <hughd@google.com>
CC: Dave Hansen <dave@linux.vnet.ibm.com>
CC: Rik van Riel <riel@redhat.com>
CC: Dmitry Adamushko <dmitry.adamushko@gmail.com>
CC: Dave Chinner <david@fromorbit.com>
CC: Neil Brown <neilb@suse.de>
CC: Andrea Righi <andrea@betterlinux.com>
CC: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
include/linux/rangetree.h | 53 +++++++++++++++++++++++
lib/Makefile | 2 +-
lib/rangetree.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 159 insertions(+), 1 deletions(-)
create mode 100644 include/linux/rangetree.h
create mode 100644 lib/rangetree.c
diff --git a/include/linux/rangetree.h b/include/linux/rangetree.h
new file mode 100644
index 0000000..ca03821
--- /dev/null
+++ b/include/linux/rangetree.h
@@ -0,0 +1,53 @@
+#ifndef _LINUX_RANGETREE_H
+#define _LINUX_RANGETREE_H
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+
+struct range_tree_node {
+ struct rb_node rb;
+ u64 start;
+ u64 end;
+};
+
+struct range_tree_root {
+ struct rb_root head;
+};
+
+static inline void range_tree_init(struct range_tree_root *root)
+{
+ root->head = RB_ROOT;
+}
+
+static inline void range_tree_node_init(struct range_tree_node *node)
+{
+ rb_init_node(&node->rb);
+ node->start = 0;
+ node->end = 0;
+}
+
+static inline int range_tree_empty(struct range_tree_root *root)
+{
+ return RB_EMPTY_ROOT(&root->head);
+}
+
+static inline
+struct range_tree_node *range_tree_root_node(struct range_tree_root *root)
+{
+ struct range_tree_node *ret;
+ ret = container_of(root->head.rb_node, struct range_tree_node, rb);
+ return ret;
+}
+
+extern struct range_tree_node *range_tree_in_range(struct range_tree_root *root,
+ u64 start, u64 end);
+extern struct range_tree_node *range_tree_in_range_adjacent(
+ struct range_tree_root *root,
+ u64 start, u64 end);
+extern void range_tree_add(struct range_tree_root *root,
+ struct range_tree_node *node);
+extern void range_tree_remove(struct range_tree_root *root,
+ struct range_tree_node *node);
+#endif
+
+
diff --git a/lib/Makefile b/lib/Makefile
index 18515f0..f43ef0d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o prio_heap.o ratelimit.o show_mem.o \
- is_single_threaded.o plist.o decompress.o
+ is_single_threaded.o plist.o decompress.o rangetree.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/rangetree.c b/lib/rangetree.c
new file mode 100644
index 0000000..0f6208a
--- /dev/null
+++ b/lib/rangetree.c
@@ -0,0 +1,105 @@
+#include <linux/rangetree.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+
+/**
+ * range_tree_in_range - Returns the first node that overlaps with the
+ * given range
+ * @root: range_tree root
+ * @start: range start
+ * @end: range end
+ *
+ */
+struct range_tree_node *range_tree_in_range(struct range_tree_root *root,
+ u64 start, u64 end)
+{
+ struct rb_node **p = &root->head.rb_node;
+ struct range_tree_node *candidate;
+
+ while (*p) {
+ candidate = rb_entry(*p, struct range_tree_node, rb);
+ if (end < candidate->start)
+ p = &(*p)->rb_left;
+ else if (start > candidate->end)
+ p = &(*p)->rb_right;
+ else
+ return candidate;
+ }
+
+ return 0;
+}
+
+
+/**
+ * range_tree_in_range - Returns the first node that overlaps or is adjacent
+ * with the given range
+ * @root: range_tree root
+ * @start: range start
+ * @end: range end
+ *
+ */
+struct range_tree_node *range_tree_in_range_adjacent(
+ struct range_tree_root *root,
+ u64 start, u64 end)
+{
+ struct rb_node **p = &root->head.rb_node;
+ struct range_tree_node *candidate;
+
+ while (*p) {
+ candidate = rb_entry(*p, struct range_tree_node, rb);
+ if (end+1 < candidate->start)
+ p = &(*p)->rb_left;
+ else if (start > candidate->end + 1)
+ p = &(*p)->rb_right;
+ else
+ return candidate;
+ }
+ return 0;
+}
+
+/**
+ * range_tree_add - Add a node to a range tree
+ * @root: range tree to be added to
+ * @node: range_tree_node to be added
+ *
+ * Adds a node to the range tree.
+ */
+void range_tree_add(struct range_tree_root *root,
+ struct range_tree_node *node)
+{
+ struct rb_node **p = &root->head.rb_node;
+ struct rb_node *parent = NULL;
+ struct range_tree_node *ptr;
+
+ WARN_ON_ONCE(!RB_EMPTY_NODE(&node->rb));
+
+ while (*p) {
+ parent = *p;
+ ptr = rb_entry(parent, struct range_tree_node, rb);
+ if (node->start < ptr->start)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ rb_link_node(&node->rb, parent, p);
+ rb_insert_color(&node->rb, &root->head);
+
+}
+
+
+/**
+ * range_tree_remove: Removes a given node from the tree
+ * @root: root of tree
+ * @node: Node to be removed
+ *
+ * Removes a node and splays the tree
+ */
+void range_tree_remove(struct range_tree_root *root,
+ struct range_tree_node *node)
+{
+ WARN_ON_ONCE(RB_EMPTY_NODE(&node->rb));
+
+ rb_erase(&node->rb, &root->head);
+ RB_CLEAR_NODE(&node->rb);
+}
--
1.7.3.2.146.gca209
next prev parent reply other threads:[~2012-03-16 22:51 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-16 22:51 [PATCH 0/2] [RFC] Volatile ranges (v4) John Stultz
2012-03-16 22:51 ` John Stultz [this message]
2012-03-20 10:00 ` [PATCH 1/2] [RFC] Range tree implementation Dmitry Adamushko
2012-03-20 18:04 ` John Stultz
2012-03-20 16:44 ` Aneesh Kumar K.V
2012-03-16 22:51 ` [PATCH 2/2] [RFC] fadvise: Add _VOLATILE,_ISVOLATILE, and _NONVOLATILE flags John Stultz
2012-03-17 0:47 ` [PATCH] fadvise volatile fixes from Dmitry John Stultz
2012-03-17 16:21 ` [PATCH 2/2] [RFC] fadvise: Add _VOLATILE,_ISVOLATILE, and _NONVOLATILE flags Dmitry Adamushko
2012-03-18 9:13 ` Dmitry Adamushko
2012-03-20 0:18 ` John Stultz
2012-07-19 10:13 ` [PATCH 0/2] [RFC] Volatile ranges (v4) Dmitry Vyukov
[not found] ` <CAO6Zf6BSpq53UqYjCkq0b3pTPW=WDTnCorQ59tONnV7U-U6EOg@mail.gmail.com>
[not found] ` <CACT4Y+ZgBo9=HX5MHhmWBiQcdiGMss9RSS_reF4gJimivJx7sQ@mail.gmail.com>
2012-07-21 11:17 ` Dmitry Adamushko
-- strict thread matches above, loose matches on Subject: below --
2012-04-14 1:07 [PATCH 0/2][RFC] Volatile Ranges (v7) John Stultz
2012-04-14 1:08 ` [PATCH 1/2] [RFC] Range tree implementation John Stultz
2012-04-07 0:08 [PATCH 0/2] [RFC] Volatile Ranges (v6) John Stultz
2012-04-07 0:08 ` [PATCH 1/2] [RFC] Range tree implementation John Stultz
2012-04-07 17:36 ` Sasha Levin
2012-04-09 18:04 ` John Stultz
2012-04-09 18:44 ` Sasha Levin
2012-03-21 4:15 [PATCH 0/2] [RFC] fadivse volatile & range tree (v5) John Stultz
2012-03-21 4:15 ` [PATCH 1/2] [RFC] Range tree implementation John Stultz
2012-02-10 0:16 John Stultz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1331938267-13583-2-git-send-email-john.stultz@linaro.org \
--to=john.stultz@linaro.org \
--cc=akpm@linux-foundation.org \
--cc=andrea@betterlinux.com \
--cc=aneesh.kumar@linux.vnet.ibm.com \
--cc=dave@linux.vnet.ibm.com \
--cc=david@fromorbit.com \
--cc=dmitry.adamushko@gmail.com \
--cc=hughd@google.com \
--cc=kernel-team@android.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mel@csn.ul.ie \
--cc=neilb@suse.de \
--cc=riel@redhat.com \
--cc=rlove@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).