From: Marco Stornelli <marco.stornelli@gmail.com>
To: Linux Kernel <linux-kernel@vger.kernel.org>
Cc: Linux Embedded <linux-embedded@vger.kernel.org>,
Linux FS Devel <linux-fsdevel@vger.kernel.org>,
Tim Bird <tim.bird@am.sony.com>,
Andrew Morton <akpm@linux-foundation.org>
Subject: [PATCH 13/16 v5] pramfs: extended attributes block descriptors tree
Date: Thu, 16 Dec 2010 19:02:10 +0100 [thread overview]
Message-ID: <4D0A5422.7040005@gmail.com> (raw)
From: Marco Stornelli <marco.stornelli@gmail.com>
Extended attributes block descriptors tree.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/desctree.c linux-2.6.36/fs/pramfs/desctree.c
--- linux-2.6.36-orig/fs/pramfs/desctree.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.36/fs/pramfs/desctree.c 2010-11-27 11:12:04.000000000 +0100
@@ -0,0 +1,181 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Extended attributes block descriptors tree.
+ *
+ * Copyright 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/spinlock.h>
+#include "desctree.h"
+#include "pram.h"
+
+/* xblock_desc_init_always()
+ *
+ * These are initializations that need to be done on every
+ * descriptor allocation as the fields are not initialised
+ * by slab allocation.
+ */
+void xblock_desc_init_always(struct pram_xblock_desc *desc)
+{
+ atomic_set(&desc->refcount, 0);
+ desc->blocknr = 0;
+ desc->flags = 0;
+}
+
+/* xblock_desc_init_once()
+ *
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the descriptor, so let the slab aware of that.
+ */
+void xblock_desc_init_once(struct pram_xblock_desc *desc)
+{
+ mutex_init(&desc->lock);
+}
+
+/* __insert_xblock_desc()
+ *
+ * Insert a new descriptor in the tree.
+ */
+static void __insert_xblock_desc(struct pram_sb_info *sbi,
+ unsigned long blocknr, struct rb_node *node)
+{
+ struct rb_node **p = &(sbi->desc_tree.rb_node);
+ struct rb_node *parent = NULL;
+ struct pram_xblock_desc *desc;
+
+ while (*p) {
+ parent = *p;
+ desc = rb_entry(parent, struct pram_xblock_desc, node);
+
+ if (blocknr < desc->blocknr)
+ p = &(*p)->rb_left;
+ else if (blocknr > desc->blocknr)
+ p = &(*p)->rb_right;
+ else
+ /* Oops...an other descriptor for the same block ? */
+ BUG();
+ }
+
+ rb_link_node(node, parent, p);
+ rb_insert_color(node, &sbi->desc_tree);
+}
+
+void insert_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc)
+{
+ spin_lock(&sbi->desc_tree_lock);
+ __insert_xblock_desc(sbi, desc->blocknr, &desc->node);
+ spin_unlock(&sbi->desc_tree_lock);
+};
+
+/* __lookup_xblock_desc()
+ *
+ * Search an extended attribute descriptor in the tree via the
+ * block number. It returns the descriptor if it's found or
+ * NULL. If not found it creates a new descriptor if create is not 0.
+ */
+static struct pram_xblock_desc *__lookup_xblock_desc(struct pram_sb_info *sbi,
+ unsigned long blocknr,
+ struct kmem_cache *cache,
+ int create)
+{
+ struct rb_node *n = sbi->desc_tree.rb_node;
+ struct pram_xblock_desc *desc = NULL;
+
+ while (n) {
+ desc = rb_entry(n, struct pram_xblock_desc, node);
+
+ if (blocknr < desc->blocknr)
+ n = n->rb_left;
+ else if (blocknr > desc->blocknr)
+ n = n->rb_right;
+ else {
+ atomic_inc(&desc->refcount);
+ goto out;
+ }
+ }
+
+ /* not found */
+ if (create) {
+ desc = kmem_cache_alloc(cache, GFP_NOFS);
+ if (!desc)
+ return ERR_PTR(-ENOMEM);
+ xblock_desc_init_always(desc);
+ atomic_set(&desc->refcount, 1);
+ desc->blocknr = blocknr;
+ __insert_xblock_desc(sbi, desc->blocknr, &desc->node);
+ }
+out:
+ return desc;
+}
+
+struct pram_xblock_desc *lookup_xblock_desc(struct pram_sb_info *sbi,
+ unsigned long blocknr,
+ struct kmem_cache *cache,
+ int create)
+{
+ struct pram_xblock_desc *desc = NULL;
+
+ spin_lock(&sbi->desc_tree_lock);
+ desc = __lookup_xblock_desc(sbi, blocknr, cache, create);
+ spin_unlock(&sbi->desc_tree_lock);
+ return desc;
+}
+
+/* put_xblock_desc()
+ *
+ * Decrement the reference count and if it reaches zero and the
+ * desciptor has been marked to be free, then we free it.
+ * It returns 0 if the descriptor has been deleted and 1 otherwise.
+ */
+int put_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc)
+{
+ int ret = 1;
+ if (!desc)
+ return ret;
+
+ if (atomic_dec_and_lock(&desc->refcount, &sbi->desc_tree_lock)) {
+ if (test_bit(FREEING, &desc->flags)) {
+ rb_erase(&desc->node, &sbi->desc_tree);
+ pram_dbg("erasing desc for block %lu\n", desc->blocknr);
+ ret = 0;
+ }
+ spin_unlock(&sbi->desc_tree_lock);
+ }
+ return ret;
+};
+
+/* mark_free_desc()
+ *
+ * Mark free a descriptor. The descriptor will be deleted later in the
+ * put_xblock_desc().
+ */
+void mark_free_desc(struct pram_xblock_desc *desc)
+{
+ set_bit(FREEING, &desc->flags);
+}
+
+/* erase_tree()
+ *
+ * Free all objects in the tree.
+ */
+void erase_tree(struct pram_sb_info *sbi, struct kmem_cache *cachep)
+{
+ struct rb_node *n;
+ struct pram_xblock_desc *desc;
+
+ spin_lock(&sbi->desc_tree_lock);
+ n = rb_first(&sbi->desc_tree);
+ while (n) {
+ desc = rb_entry(n, struct pram_xblock_desc, node);
+ rb_erase(n, &sbi->desc_tree);
+ kmem_cache_free(cachep, desc);
+ n = rb_next(n);
+ }
+ spin_unlock(&sbi->desc_tree_lock);
+}
diff -Nurp linux-2.6.36-orig/fs/pramfs/desctree.h linux-2.6.36/fs/pramfs/desctree.h
--- linux-2.6.36-orig/fs/pramfs/desctree.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.36/fs/pramfs/desctree.h 2010-11-27 11:12:10.000000000 +0100
@@ -0,0 +1,44 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Extended attributes block descriptors tree.
+ *
+ * Copyright 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <asm/atomic.h>
+#include <linux/slab.h>
+#include "pram.h"
+
+struct pram_xblock_desc {
+#define FREEING (1UL << 1)
+ unsigned long flags; /* descriptor flags */
+ atomic_t refcount; /* users count of this descriptor */
+ unsigned long blocknr; /* absolute block number */
+ struct mutex lock; /* block lock */
+ struct rb_node node; /* node in the rb tree */
+};
+
+extern struct pram_xblock_desc *lookup_xblock_desc(struct pram_sb_info *sbi,
+ unsigned long blocknr,
+ struct kmem_cache *, int);
+extern void insert_xblock_desc(struct pram_sb_info *sbi,
+ struct pram_xblock_desc *desc);
+extern void mark_free_desc(struct pram_xblock_desc *desc);
+extern int put_xblock_desc(struct pram_sb_info *sbi,
+ struct pram_xblock_desc *desc);
+extern void xblock_desc_init_always(struct pram_xblock_desc *desc);
+extern void xblock_desc_init_once(struct pram_xblock_desc *desc);
+extern void erase_tree(struct pram_sb_info *sbi,
+ struct kmem_cache *);
+
+static inline void xblock_desc_init(struct pram_xblock_desc *desc)
+{
+ xblock_desc_init_always(desc);
+ xblock_desc_init_once(desc);
+};
+
reply other threads:[~2010-12-16 18:02 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=4D0A5422.7040005@gmail.com \
--to=marco.stornelli@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=linux-embedded@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tim.bird@am.sony.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.