Branch 'uidmap' - scripts/cfs_start_volume.py xlators/features

Kaleb KEITHLEY kkeithle at fedoraproject.org
Wed Jun 1 18:38:36 UTC 2011


 scripts/cfs_start_volume.py             |   18 
 xlators/features/uidmap/src/Makefile.am |    8 
 xlators/features/uidmap/src/rb.c        |  929 ++++++++++++++++++++++++++++++++
 xlators/features/uidmap/src/rb.h        |  122 ++++
 xlators/features/uidmap/src/rbmap.c     |  453 +++++++++++++++
 xlators/features/uidmap/src/uidmap.c    |   18 
 xlators/features/uidmap/src/uidmap.h    |    4 
 7 files changed, 1534 insertions(+), 18 deletions(-)

New commits:
commit 1e82abcb19581d28414bb1b5a54cc59db6d7170a
Author: Kaleb S. KEITHLEY <kkeithle at cloudfs-node01.kkeithle.redhat.com>
Date:   Wed Jun 1 14:19:58 2011 -0400

    Use non-default RBtree maps of client-side uid, gid to server-side uid,
    gid To simplify building, the RBtree implementation itself is a copy of
    gluster's implementation in contrib. It doesn't appear to be in any of
    the gluster shared libs that we install.
    
    The shared lib containing the RBtree implemenation and rbmap wrappers
    for consumption by the uidmap xlator is installed in the glusterfs xlator
    dir in /usr/lib64/glusterfs/<version>/xlator/features/... It is loaded
    at run-time by specifying the fully qualified path and name of the shared
    lib as an option to the uidmap xlator. Thus, with this commit, the default
    map used by the uidmap xlator is the RBtree.
    
    In addition, cfs_start_volume:check_volume_directory() is modified to try
    harder to ensure that .idle_ports (and .used_ports) are populated.  I
    noticed that after a reboot the files did not exist, even though the
    directories still existed. Apparently some /etc/{init.d,rc?.d} script
    cleans /var/run during boot (or shutdown). As a result, if the files don't
    exist, attempts to start a volume will fail, and with very little in the
    way of logging or error reporting that indicates why.

diff --git a/scripts/cfs_start_volume.py b/scripts/cfs_start_volume.py
index 87793b9..b51b653 100755
--- a/scripts/cfs_start_volume.py
+++ b/scripts/cfs_start_volume.py
@@ -25,11 +25,18 @@ def check_volume_directory(vol_name):
 		os.mkdir(cfs_paths.pid_dir,0700)
 	if not os.path.exists(cfs_paths.idle_subdir):
 		os.mkdir(cfs_paths.idle_subdir,0700)
+	if not os.path.exists(cfs_paths.used_subdir):
+		os.mkdir(cfs_paths.used_subdir,0700)
+	idle = glob.glob("%s/*" % cfs_paths.idle_subdir)
+	used = glob.glob("%s/*" % cfs_paths.used_subdir)
+	if len(idle) + len(used) == 0:
+		# idle and used dirs are both empty, probably after a reboot
+		# when /var/run is cleaned of files and symlinks
+		# creating idle ports
 		for i in range(24010, 24030):
+			print "creating %s/%d" % (cfs_paths.idle_subdir, i)
 			fp = open("%s/%d" % (cfs_paths.idle_subdir, i), "w")
 			fp.close()
-	if not os.path.exists(cfs_paths.used_subdir):
-		os.mkdir(cfs_paths.used_subdir,0700)
 
 	vol_dir = "%s/%s" % (cfs_paths.info_dir, vol_name)
 	if not os.path.exists(vol_dir):
@@ -113,9 +120,10 @@ def cloudify_server (input, output, users, port):
 		del last.opts[opt]
 
 	default_uidmap_opts = dict()
-	default_uidmap_opts["uid-range"] = "10000-19999";
-	default_uidmap_opts["gid-range"] = "10000-19999";
-	default_uidmap_opts["tenant"] = "ChangeMe";
+	default_uidmap_opts["uid-range"] = "10000-19999"
+	default_uidmap_opts["gid-range"] = "10000-19999"
+	default_uidmap_opts["tenant"] = "ChangeMe"
+	default_uidmap_opts["plugin"] = "/usr/lib64/glusterfs/3.1.3git/xlator/features/libmaprbtree.so"
 
 	last.subvols = []
 	for user, pw in users:
diff --git a/xlators/features/uidmap/src/Makefile.am b/xlators/features/uidmap/src/Makefile.am
index f603b77..d0da92c 100644
--- a/xlators/features/uidmap/src/Makefile.am
+++ b/xlators/features/uidmap/src/Makefile.am
@@ -1,12 +1,16 @@
 
-xlator_LTLIBRARIES = uidmap.la
+xlator_LTLIBRARIES = uidmap.la libmaprbtree.la
 xlatordir = $(libdir)/glusterfs/$(GLUSTER_VERSION)/xlator/features
 
 uidmap_la_LDFLAGS = -module -avoidversion -lglusterfs
 
 uidmap_la_SOURCES = uidmap.c
 
-noinst_HEADERS = uidmap.h
+libmaprbtree_la_LDFLAGS = -module -avoidversion -lglusterfs
+
+libmaprbtree_la_SOURCES = rb.c rbmap.c
+
+noinst_HEADERS = uidmap.h rb.h
 
 GLUSTERDIR=$(includedir)/glusterfs
 
diff --git a/xlators/features/uidmap/src/rb.c b/xlators/features/uidmap/src/rb.c
new file mode 100644
index 0000000..d1339b9
--- /dev/null
+++ b/xlators/features/uidmap/src/rb.c
@@ -0,0 +1,929 @@
+/* Produced by texiweb from libavl.w. */
+
+/* libavl - library for manipulation of binary trees.
+   Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The author may be contacted at <blp at gnu.org> on the Internet, or
+   write to Ben Pfaff, Stanford University, Computer Science Dept., 353
+   Serra Mall, Stanford CA 94305, USA.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rb.h"
+
+/* Creates and returns a new table
+   with comparison function |compare| using parameter |param|
+   and memory allocator |allocator|.
+   Returns |NULL| if memory allocation failed. */
+struct rb_table *
+rb_create (rb_comparison_func *compare, void *param,
+            struct libavl_allocator *allocator)
+{
+  struct rb_table *tree;
+
+  assert (compare != NULL);
+
+  if (allocator == NULL)
+    allocator = &rb_allocator_default;
+
+  tree = allocator->libavl_malloc (allocator, sizeof *tree);
+  if (tree == NULL)
+    return NULL;
+
+  tree->rb_root = NULL;
+  tree->rb_compare = compare;
+  tree->rb_param = param;
+  tree->rb_alloc = allocator;
+  tree->rb_count = 0;
+  tree->rb_generation = 0;
+
+  return tree;
+}
+
+/* Search |tree| for an item matching |item|, and return it if found.
+   Otherwise return |NULL|. */
+void *
+rb_find (const struct rb_table *tree, const void *item)
+{
+  const struct rb_node *p;
+
+  assert (tree != NULL && item != NULL);
+  for (p = tree->rb_root; p != NULL; )
+    {
+      int cmp = tree->rb_compare (item, p->rb_data, tree->rb_param);
+
+      if (cmp < 0)
+        p = p->rb_link[0];
+      else if (cmp > 0)
+        p = p->rb_link[1];
+      else /* |cmp == 0| */
+        return p->rb_data;
+    }
+
+  return NULL;
+}
+
+/* Inserts |item| into |tree| and returns a pointer to |item|'s address.
+   If a duplicate item is found in the tree,
+   returns a pointer to the duplicate without inserting |item|.
+   Returns |NULL| in case of memory allocation failure. */
+void **
+rb_probe (struct rb_table *tree, void *item)
+{
+  struct rb_node *pa[RB_MAX_HEIGHT]; /* Nodes on stack. */
+  unsigned char da[RB_MAX_HEIGHT];   /* Directions moved from stack nodes. */
+  int k;                             /* Stack height. */
+
+  struct rb_node *p; /* Traverses tree looking for insertion point. */
+  struct rb_node *n; /* Newly inserted node. */
+
+  assert (tree != NULL && item != NULL);
+
+  pa[0] = (struct rb_node *) &tree->rb_root;
+  da[0] = 0;
+  k = 1;
+  for (p = tree->rb_root; p != NULL; p = p->rb_link[da[k - 1]])
+    {
+      int cmp = tree->rb_compare (item, p->rb_data, tree->rb_param);
+      if (cmp == 0)
+        return &p->rb_data;
+
+      pa[k] = p;
+      da[k++] = cmp > 0;
+    }
+
+  n = pa[k - 1]->rb_link[da[k - 1]] =
+    tree->rb_alloc->libavl_malloc (tree->rb_alloc, sizeof *n);
+  if (n == NULL)
+    return NULL;
+
+  n->rb_data = item;
+  n->rb_link[0] = n->rb_link[1] = NULL;
+  n->rb_color = RB_RED;
+  tree->rb_count++;
+  tree->rb_generation++;
+
+  while (k >= 3 && pa[k - 1]->rb_color == RB_RED)
+    {
+      if (da[k - 2] == 0)
+        {
+          struct rb_node *y = pa[k - 2]->rb_link[1];
+          if (y != NULL && y->rb_color == RB_RED)
+            {
+              pa[k - 1]->rb_color = y->rb_color = RB_BLACK;
+              pa[k - 2]->rb_color = RB_RED;
+              k -= 2;
+            }
+          else
+            {
+              struct rb_node *x;
+
+              if (da[k - 1] == 0)
+                y = pa[k - 1];
+              else
+                {
+                  x = pa[k - 1];
+                  y = x->rb_link[1];
+                  x->rb_link[1] = y->rb_link[0];
+                  y->rb_link[0] = x;
+                  pa[k - 2]->rb_link[0] = y;
+                }
+
+              x = pa[k - 2];
+              x->rb_color = RB_RED;
+              y->rb_color = RB_BLACK;
+
+              x->rb_link[0] = y->rb_link[1];
+              y->rb_link[1] = x;
+              pa[k - 3]->rb_link[da[k - 3]] = y;
+              break;
+            }
+        }
+      else
+        {
+          struct rb_node *y = pa[k - 2]->rb_link[0];
+          if (y != NULL && y->rb_color == RB_RED)
+            {
+              pa[k - 1]->rb_color = y->rb_color = RB_BLACK;
+              pa[k - 2]->rb_color = RB_RED;
+              k -= 2;
+            }
+          else
+            {
+              struct rb_node *x;
+
+              if (da[k - 1] == 1)
+                y = pa[k - 1];
+              else
+                {
+                  x = pa[k - 1];
+                  y = x->rb_link[0];
+                  x->rb_link[0] = y->rb_link[1];
+                  y->rb_link[1] = x;
+                  pa[k - 2]->rb_link[1] = y;
+                }
+
+              x = pa[k - 2];
+              x->rb_color = RB_RED;
+              y->rb_color = RB_BLACK;
+
+              x->rb_link[1] = y->rb_link[0];
+              y->rb_link[0] = x;
+              pa[k - 3]->rb_link[da[k - 3]] = y;
+              break;
+            }
+        }
+    }
+  tree->rb_root->rb_color = RB_BLACK;
+
+
+  return &n->rb_data;
+}
+
+/* Inserts |item| into |table|.
+   Returns |NULL| if |item| was successfully inserted
+   or if a memory allocation error occurred.
+   Otherwise, returns the duplicate item. */
+void *
+rb_insert (struct rb_table *table, void *item)
+{
+  void **p = rb_probe (table, item);
+  return p == NULL || *p == item ? NULL : *p;
+}
+
+/* Inserts |item| into |table|, replacing any duplicate item.
+   Returns |NULL| if |item| was inserted without replacing a duplicate,
+   or if a memory allocation error occurred.
+   Otherwise, returns the item that was replaced. */
+void *
+rb_replace (struct rb_table *table, void *item)
+{
+  void **p = rb_probe (table, item);
+  if (p == NULL || *p == item)
+    return NULL;
+  else
+    {
+      void *r = *p;
+      *p = item;
+      return r;
+    }
+}
+
+/* Deletes from |tree| and returns an item matching |item|.
+   Returns a null pointer if no matching item found. */
+void *
+rb_delete (struct rb_table *tree, const void *item)
+{
+  struct rb_node *pa[RB_MAX_HEIGHT]; /* Nodes on stack. */
+  unsigned char da[RB_MAX_HEIGHT];   /* Directions moved from stack nodes. */
+  int k;                             /* Stack height. */
+
+  struct rb_node *p;    /* The node to delete, or a node part way to it. */
+  int cmp;              /* Result of comparison between |item| and |p|. */
+
+  assert (tree != NULL && item != NULL);
+
+  k = 0;
+  p = (struct rb_node *) &tree->rb_root;
+  for (cmp = -1; cmp != 0;
+       cmp = tree->rb_compare (item, p->rb_data, tree->rb_param))
+    {
+      int dir = cmp > 0;
+
+      pa[k] = p;
+      da[k++] = dir;
+
+      p = p->rb_link[dir];
+      if (p == NULL)
+        return NULL;
+    }
+  item = p->rb_data;
+
+  if (p->rb_link[1] == NULL)
+    pa[k - 1]->rb_link[da[k - 1]] = p->rb_link[0];
+  else
+    {
+      enum rb_color t;
+      struct rb_node *r = p->rb_link[1];
+
+      if (r->rb_link[0] == NULL)
+        {
+          r->rb_link[0] = p->rb_link[0];
+          t = r->rb_color;
+          r->rb_color = p->rb_color;
+          p->rb_color = t;
+          pa[k - 1]->rb_link[da[k - 1]] = r;
+          da[k] = 1;
+          pa[k++] = r;
+        }
+      else
+        {
+          struct rb_node *s;
+          int j = k++;
+
+          for (;;)
+            {
+              da[k] = 0;
+              pa[k++] = r;
+              s = r->rb_link[0];
+              if (s->rb_link[0] == NULL)
+                break;
+
+              r = s;
+            }
+
+          da[j] = 1;
+          pa[j] = s;
+          pa[j - 1]->rb_link[da[j - 1]] = s;
+
+          s->rb_link[0] = p->rb_link[0];
+          r->rb_link[0] = s->rb_link[1];
+          s->rb_link[1] = p->rb_link[1];
+
+          t = s->rb_color;
+          s->rb_color = p->rb_color;
+          p->rb_color = t;
+        }
+    }
+
+  if (p->rb_color == RB_BLACK)
+    {
+      for (;;)
+        {
+          struct rb_node *x = pa[k - 1]->rb_link[da[k - 1]];
+          if (x != NULL && x->rb_color == RB_RED)
+            {
+              x->rb_color = RB_BLACK;
+              break;
+            }
+          if (k < 2)
+            break;
+
+          if (da[k - 1] == 0)
+            {
+              struct rb_node *w = pa[k - 1]->rb_link[1];
+
+              if (w->rb_color == RB_RED)
+                {
+                  w->rb_color = RB_BLACK;
+                  pa[k - 1]->rb_color = RB_RED;
+
+                  pa[k - 1]->rb_link[1] = w->rb_link[0];
+                  w->rb_link[0] = pa[k - 1];
+                  pa[k - 2]->rb_link[da[k - 2]] = w;
+
+                  pa[k] = pa[k - 1];
+                  da[k] = 0;
+                  pa[k - 1] = w;
+                  k++;
+
+                  w = pa[k - 1]->rb_link[1];
+                }
+
+              if ((w->rb_link[0] == NULL
+                   || w->rb_link[0]->rb_color == RB_BLACK)
+                  && (w->rb_link[1] == NULL
+                      || w->rb_link[1]->rb_color == RB_BLACK))
+                w->rb_color = RB_RED;
+              else
+                {
+                  if (w->rb_link[1] == NULL
+                      || w->rb_link[1]->rb_color == RB_BLACK)
+                    {
+                      struct rb_node *y = w->rb_link[0];
+                      y->rb_color = RB_BLACK;
+                      w->rb_color = RB_RED;
+                      w->rb_link[0] = y->rb_link[1];
+                      y->rb_link[1] = w;
+                      w = pa[k - 1]->rb_link[1] = y;
+                    }
+
+                  w->rb_color = pa[k - 1]->rb_color;
+                  pa[k - 1]->rb_color = RB_BLACK;
+                  w->rb_link[1]->rb_color = RB_BLACK;
+
+                  pa[k - 1]->rb_link[1] = w->rb_link[0];
+                  w->rb_link[0] = pa[k - 1];
+                  pa[k - 2]->rb_link[da[k - 2]] = w;
+                  break;
+                }
+            }
+          else
+            {
+              struct rb_node *w = pa[k - 1]->rb_link[0];
+
+              if (w->rb_color == RB_RED)
+                {
+                  w->rb_color = RB_BLACK;
+                  pa[k - 1]->rb_color = RB_RED;
+
+                  pa[k - 1]->rb_link[0] = w->rb_link[1];
+                  w->rb_link[1] = pa[k - 1];
+                  pa[k - 2]->rb_link[da[k - 2]] = w;
+
+                  pa[k] = pa[k - 1];
+                  da[k] = 1;
+                  pa[k - 1] = w;
+                  k++;
+
+                  w = pa[k - 1]->rb_link[0];
+                }
+
+              if ((w->rb_link[0] == NULL
+                   || w->rb_link[0]->rb_color == RB_BLACK)
+                  && (w->rb_link[1] == NULL
+                      || w->rb_link[1]->rb_color == RB_BLACK))
+                w->rb_color = RB_RED;
+              else
+                {
+                  if (w->rb_link[0] == NULL
+                      || w->rb_link[0]->rb_color == RB_BLACK)
+                    {
+                      struct rb_node *y = w->rb_link[1];
+                      y->rb_color = RB_BLACK;
+                      w->rb_color = RB_RED;
+                      w->rb_link[1] = y->rb_link[0];
+                      y->rb_link[0] = w;
+                      w = pa[k - 1]->rb_link[0] = y;
+                    }
+
+                  w->rb_color = pa[k - 1]->rb_color;
+                  pa[k - 1]->rb_color = RB_BLACK;
+                  w->rb_link[0]->rb_color = RB_BLACK;
+
+                  pa[k - 1]->rb_link[0] = w->rb_link[1];
+                  w->rb_link[1] = pa[k - 1];
+                  pa[k - 2]->rb_link[da[k - 2]] = w;
+                  break;
+                }
+            }
+
+          k--;
+        }
+
+    }
+
+  tree->rb_alloc->libavl_free (tree->rb_alloc, p);
+  tree->rb_count--;
+  tree->rb_generation++;
+  return (void *) item;
+}
+
+/* Refreshes the stack of parent pointers in |trav|
+   and updates its generation number. */
+static void
+trav_refresh (struct rb_traverser *trav)
+{
+  assert (trav != NULL);
+
+  trav->rb_generation = trav->rb_table->rb_generation;
+
+  if (trav->rb_node != NULL)
+    {
+      rb_comparison_func *cmp = trav->rb_table->rb_compare;
+      void *param = trav->rb_table->rb_param;
+      struct rb_node *node = trav->rb_node;
+      struct rb_node *i;
+
+      trav->rb_height = 0;
+      for (i = trav->rb_table->rb_root; i != node; )
+        {
+          assert (trav->rb_height < RB_MAX_HEIGHT);
+          assert (i != NULL);
+
+          trav->rb_stack[trav->rb_height++] = i;
+          i = i->rb_link[cmp (node->rb_data, i->rb_data, param) > 0];
+        }
+    }
+}
+
+/* Initializes |trav| for use with |tree|
+   and selects the null node. */
+void
+rb_t_init (struct rb_traverser *trav, struct rb_table *tree)
+{
+  trav->rb_table = tree;
+  trav->rb_node = NULL;
+  trav->rb_height = 0;
+  trav->rb_generation = tree->rb_generation;
+}
+
+/* Initializes |trav| for |tree|
+   and selects and returns a pointer to its least-valued item.
+   Returns |NULL| if |tree| contains no nodes. */
+void *
+rb_t_first (struct rb_traverser *trav, struct rb_table *tree)
+{
+  struct rb_node *x;
+
+  assert (tree != NULL && trav != NULL);
+
+  trav->rb_table = tree;
+  trav->rb_height = 0;
+  trav->rb_generation = tree->rb_generation;
+
+  x = tree->rb_root;
+  if (x != NULL)
+    while (x->rb_link[0] != NULL)
+      {
+        assert (trav->rb_height < RB_MAX_HEIGHT);
+        trav->rb_stack[trav->rb_height++] = x;
+        x = x->rb_link[0];
+      }
+  trav->rb_node = x;
+
+  return x != NULL ? x->rb_data : NULL;
+}
+
+/* Initializes |trav| for |tree|
+   and selects and returns a pointer to its greatest-valued item.
+   Returns |NULL| if |tree| contains no nodes. */
+void *
+rb_t_last (struct rb_traverser *trav, struct rb_table *tree)
+{
+  struct rb_node *x;
+
+  assert (tree != NULL && trav != NULL);
+
+  trav->rb_table = tree;
+  trav->rb_height = 0;
+  trav->rb_generation = tree->rb_generation;
+
+  x = tree->rb_root;
+  if (x != NULL)
+    while (x->rb_link[1] != NULL)
+      {
+        assert (trav->rb_height < RB_MAX_HEIGHT);
+        trav->rb_stack[trav->rb_height++] = x;
+        x = x->rb_link[1];
+      }
+  trav->rb_node = x;
+
+  return x != NULL ? x->rb_data : NULL;
+}
+
+/* Searches for |item| in |tree|.
+   If found, initializes |trav| to the item found and returns the item
+   as well.
+   If there is no matching item, initializes |trav| to the null item
+   and returns |NULL|. */
+void *
+rb_t_find (struct rb_traverser *trav, struct rb_table *tree, void *item)
+{
+  struct rb_node *p, *q;
+
+  assert (trav != NULL && tree != NULL && item != NULL);
+  trav->rb_table = tree;
+  trav->rb_height = 0;
+  trav->rb_generation = tree->rb_generation;
+  for (p = tree->rb_root; p != NULL; p = q)
+    {
+      int cmp = tree->rb_compare (item, p->rb_data, tree->rb_param);
+
+      if (cmp < 0)
+        q = p->rb_link[0];
+      else if (cmp > 0)
+        q = p->rb_link[1];
+      else /* |cmp == 0| */
+        {
+          trav->rb_node = p;
+          return p->rb_data;
+        }
+
+      assert (trav->rb_height < RB_MAX_HEIGHT);
+      trav->rb_stack[trav->rb_height++] = p;
+    }
+
+  trav->rb_height = 0;
+  trav->rb_node = NULL;
+  return NULL;
+}
+
+/* Attempts to insert |item| into |tree|.
+   If |item| is inserted successfully, it is returned and |trav| is
+   initialized to its location.
+   If a duplicate is found, it is returned and |trav| is initialized to
+   its location.  No replacement of the item occurs.
+   If a memory allocation failure occurs, |NULL| is returned and |trav|
+   is initialized to the null item. */
+void *
+rb_t_insert (struct rb_traverser *trav, struct rb_table *tree, void *item)
+{
+  void **p;
+
+  assert (trav != NULL && tree != NULL && item != NULL);
+
+  p = rb_probe (tree, item);
+  if (p != NULL)
+    {
+      trav->rb_table = tree;
+      trav->rb_node =
+        ((struct rb_node *)
+         ((char *) p - offsetof (struct rb_node, rb_data)));
+      trav->rb_generation = tree->rb_generation - 1;
+      return *p;
+    }
+  else
+    {
+      rb_t_init (trav, tree);
+      return NULL;
+    }
+}
+
+/* Initializes |trav| to have the same current node as |src|. */
+void *
+rb_t_copy (struct rb_traverser *trav, const struct rb_traverser *src)
+{
+  assert (trav != NULL && src != NULL);
+
+  if (trav != src)
+    {
+      trav->rb_table = src->rb_table;
+      trav->rb_node = src->rb_node;
+      trav->rb_generation = src->rb_generation;
+      if (trav->rb_generation == trav->rb_table->rb_generation)
+        {
+          trav->rb_height = src->rb_height;
+          memcpy (trav->rb_stack, (const void *) src->rb_stack,
+                  sizeof *trav->rb_stack * trav->rb_height);
+        }
+    }
+
+  return trav->rb_node != NULL ? trav->rb_node->rb_data : NULL;
+}
+
+/* Returns the next data item in inorder
+   within the tree being traversed with |trav|,
+   or if there are no more data items returns |NULL|. */
+void *
+rb_t_next (struct rb_traverser *trav)
+{
+  struct rb_node *x;
+
+  assert (trav != NULL);
+
+  if (trav->rb_generation != trav->rb_table->rb_generation)
+    trav_refresh (trav);
+
+  x = trav->rb_node;
+  if (x == NULL)
+    {
+      return rb_t_first (trav, trav->rb_table);
+    }
+  else if (x->rb_link[1] != NULL)
+    {
+      assert (trav->rb_height < RB_MAX_HEIGHT);
+      trav->rb_stack[trav->rb_height++] = x;
+      x = x->rb_link[1];
+
+      while (x->rb_link[0] != NULL)
+        {
+          assert (trav->rb_height < RB_MAX_HEIGHT);
+          trav->rb_stack[trav->rb_height++] = x;
+          x = x->rb_link[0];
+        }
+    }
+  else
+    {
+      struct rb_node *y;
+
+      do
+        {
+          if (trav->rb_height == 0)
+            {
+              trav->rb_node = NULL;
+              return NULL;
+            }
+
+          y = x;
+          x = trav->rb_stack[--trav->rb_height];
+        }
+      while (y == x->rb_link[1]);
+    }
+  trav->rb_node = x;
+
+  return x->rb_data;
+}
+
+/* Returns the previous data item in inorder
+   within the tree being traversed with |trav|,
+   or if there are no more data items returns |NULL|. */
+void *
+rb_t_prev (struct rb_traverser *trav)
+{
+  struct rb_node *x;
+
+  assert (trav != NULL);
+
+  if (trav->rb_generation != trav->rb_table->rb_generation)
+    trav_refresh (trav);
+
+  x = trav->rb_node;
+  if (x == NULL)
+    {
+      return rb_t_last (trav, trav->rb_table);
+    }
+  else if (x->rb_link[0] != NULL)
+    {
+      assert (trav->rb_height < RB_MAX_HEIGHT);
+      trav->rb_stack[trav->rb_height++] = x;
+      x = x->rb_link[0];
+
+      while (x->rb_link[1] != NULL)
+        {
+          assert (trav->rb_height < RB_MAX_HEIGHT);
+          trav->rb_stack[trav->rb_height++] = x;
+          x = x->rb_link[1];
+        }
+    }
+  else
+    {
+      struct rb_node *y;
+
+      do
+        {
+          if (trav->rb_height == 0)
+            {
+              trav->rb_node = NULL;
+              return NULL;
+            }
+
+          y = x;
+          x = trav->rb_stack[--trav->rb_height];
+        }
+      while (y == x->rb_link[0]);
+    }
+  trav->rb_node = x;
+
+  return x->rb_data;
+}
+
+/* Returns |trav|'s current item. */
+void *
+rb_t_cur (struct rb_traverser *trav)
+{
+  assert (trav != NULL);
+
+  return trav->rb_node != NULL ? trav->rb_node->rb_data : NULL;
+}
+
+/* Replaces the current item in |trav| by |new| and returns the item replaced.
+   |trav| must not have the null item selected.
+   The new item must not upset the ordering of the tree. */
+void *
+rb_t_replace (struct rb_traverser *trav, void *new)
+{
+  void *old;
+
+  assert (trav != NULL && trav->rb_node != NULL && new != NULL);
+  old = trav->rb_node->rb_data;
+  trav->rb_node->rb_data = new;
+  return old;
+}
+
+/* Destroys |new| with |rb_destroy (new, destroy)|,
+   first setting right links of nodes in |stack| within |new|
+   to null pointers to avoid touching uninitialized data. */
+static void
+copy_error_recovery (struct rb_node **stack, int height,
+                     struct rb_table *new, rb_item_func *destroy)
+{
+  assert (stack != NULL && height >= 0 && new != NULL);
+
+  for (; height > 2; height -= 2)
+    stack[height - 1]->rb_link[1] = NULL;
+  rb_destroy (new, destroy);
+}
+
+/* Copies |org| to a newly created tree, which is returned.
+   If |copy != NULL|, each data item in |org| is first passed to |copy|,
+   and the return values are inserted into the tree,
+   with |NULL| return values taken as indications of failure.
+   On failure, destroys the partially created new tree,
+   applying |destroy|, if non-null, to each item in the new tree so far,
+   and returns |NULL|.
+   If |allocator != NULL|, it is used for allocation in the new tree.
+   Otherwise, the same allocator used for |org| is used. */
+struct rb_table *
+rb_copy (const struct rb_table *org, rb_copy_func *copy,
+          rb_item_func *destroy, struct libavl_allocator *allocator)
+{
+  struct rb_node *stack[2 * (RB_MAX_HEIGHT + 1)];
+  int height = 0;
+
+  struct rb_table *new;
+  const struct rb_node *x;
+  struct rb_node *y;
+
+  assert (org != NULL);
+  new = rb_create (org->rb_compare, org->rb_param,
+                    allocator != NULL ? allocator : org->rb_alloc);
+  if (new == NULL)
+    return NULL;
+  new->rb_count = org->rb_count;
+  if (new->rb_count == 0)
+    return new;
+
+  x = (const struct rb_node *) &org->rb_root;
+  y = (struct rb_node *) &new->rb_root;
+  for (;;)
+    {
+      while (x->rb_link[0] != NULL)
+        {
+          assert (height < 2 * (RB_MAX_HEIGHT + 1));
+
+          y->rb_link[0] =
+            new->rb_alloc->libavl_malloc (new->rb_alloc,
+                                           sizeof *y->rb_link[0]);
+          if (y->rb_link[0] == NULL)
+            {
+              if (y != (struct rb_node *) &new->rb_root)
+                {
+                  y->rb_data = NULL;
+                  y->rb_link[1] = NULL;
+                }
+
+              copy_error_recovery (stack, height, new, destroy);
+              return NULL;
+            }
+
+          stack[height++] = (struct rb_node *) x;
+          stack[height++] = y;
+          x = x->rb_link[0];
+          y = y->rb_link[0];
+        }
+      y->rb_link[0] = NULL;
+
+      for (;;)
+        {
+          y->rb_color = x->rb_color;
+          if (copy == NULL)
+            y->rb_data = x->rb_data;
+          else
+            {
+              y->rb_data = copy (x->rb_data, org->rb_param);
+              if (y->rb_data == NULL)
+                {
+                  y->rb_link[1] = NULL;
+                  copy_error_recovery (stack, height, new, destroy);
+                  return NULL;
+                }
+            }
+
+          if (x->rb_link[1] != NULL)
+            {
+              y->rb_link[1] =
+                new->rb_alloc->libavl_malloc (new->rb_alloc,
+                                               sizeof *y->rb_link[1]);
+              if (y->rb_link[1] == NULL)
+                {
+                  copy_error_recovery (stack, height, new, destroy);
+                  return NULL;
+                }
+
+              x = x->rb_link[1];
+              y = y->rb_link[1];
+              break;
+            }
+          else
+            y->rb_link[1] = NULL;
+
+          if (height <= 2)
+            return new;
+
+          y = stack[--height];
+          x = stack[--height];
+        }
+    }
+}
+
+/* Frees storage allocated for |tree|.
+   If |destroy != NULL|, applies it to each data item in inorder. */
+void
+rb_destroy (struct rb_table *tree, rb_item_func *destroy)
+{
+  struct rb_node *p, *q;
+
+  assert (tree != NULL);
+
+  for (p = tree->rb_root; p != NULL; p = q)
+    if (p->rb_link[0] == NULL)
+      {
+        q = p->rb_link[1];
+        if (destroy != NULL && p->rb_data != NULL)
+          destroy (p->rb_data, tree->rb_param);
+        tree->rb_alloc->libavl_free (tree->rb_alloc, p);
+      }
+    else
+      {
+        q = p->rb_link[0];
+        p->rb_link[0] = q->rb_link[1];
+        q->rb_link[1] = p;
+      }
+
+  tree->rb_alloc->libavl_free (tree->rb_alloc, tree);
+}
+
+/* Allocates |size| bytes of space using |malloc()|.
+   Returns a null pointer if allocation fails. */
+void *
+rb_malloc (struct libavl_allocator *allocator, size_t size)
+{
+  assert (allocator != NULL && size > 0);
+  return malloc (size);
+}
+
+/* Frees |block|. */
+void
+rb_free (struct libavl_allocator *allocator, void *block)
+{
+  assert (allocator != NULL && block != NULL);
+  free (block);
+}
+
+/* Default memory allocator that uses |malloc()| and |free()|. */
+struct libavl_allocator rb_allocator_default =
+  {
+    rb_malloc,
+    rb_free
+  };
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Asserts that |rb_insert()| succeeds at inserting |item| into |table|. */
+void
+(rb_assert_insert) (struct rb_table *table, void *item)
+{
+  void **p = rb_probe (table, item);
+  assert (p != NULL && *p == item);
+}
+
+/* Asserts that |rb_delete()| really removes |item| from |table|,
+   and returns the removed item. */
+void *
+(rb_assert_delete) (struct rb_table *table, void *item)
+{
+  void *p = rb_delete (table, item);
+  assert (p != NULL);
+  return p;
+}
+
diff --git a/xlators/features/uidmap/src/rb.h b/xlators/features/uidmap/src/rb.h
new file mode 100644
index 0000000..c8858b5
--- /dev/null
+++ b/xlators/features/uidmap/src/rb.h
@@ -0,0 +1,122 @@
+/* Produced by texiweb from libavl.w. */
+
+/* libavl - library for manipulation of binary trees.
+   Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The author may be contacted at <blp at gnu.org> on the Internet, or
+   write to Ben Pfaff, Stanford University, Computer Science Dept., 353
+   Serra Mall, Stanford CA 94305, USA.
+*/
+
+#ifndef RB_H
+#define RB_H 1
+
+#include <stddef.h>
+
+/* Function types. */
+typedef int rb_comparison_func (const void *rb_a, const void *rb_b,
+                                 void *rb_param);
+typedef void rb_item_func (void *rb_item, void *rb_param);
+typedef void *rb_copy_func (void *rb_item, void *rb_param);
+
+#ifndef LIBAVL_ALLOCATOR
+#define LIBAVL_ALLOCATOR
+/* Memory allocator. */
+struct libavl_allocator
+  {
+    void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
+    void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
+  };
+#endif
+
+/* Default memory allocator. */
+extern struct libavl_allocator rb_allocator_default;
+void *rb_malloc (struct libavl_allocator *, size_t);
+void rb_free (struct libavl_allocator *, void *);
+
+/* Maximum RB height. */
+#ifndef RB_MAX_HEIGHT
+#define RB_MAX_HEIGHT 48
+#endif
+
+/* Tree data structure. */
+struct rb_table
+  {
+    struct rb_node *rb_root;          /* Tree's root. */
+    rb_comparison_func *rb_compare;   /* Comparison function. */
+    void *rb_param;                    /* Extra argument to |rb_compare|. */
+    struct libavl_allocator *rb_alloc; /* Memory allocator. */
+    size_t rb_count;                   /* Number of items in tree. */
+    unsigned long rb_generation;       /* Generation number. */
+  };
+
+/* Color of a red-black node. */
+enum rb_color
+  {
+    RB_BLACK,   /* Black. */
+    RB_RED      /* Red. */
+  };
+
+/* A red-black tree node. */
+struct rb_node
+  {
+    struct rb_node *rb_link[2];   /* Subtrees. */
+    void *rb_data;                /* Pointer to data. */
+    unsigned char rb_color;       /* Color. */
+  };
+
+/* RB traverser structure. */
+struct rb_traverser
+  {
+    struct rb_table *rb_table;        /* Tree being traversed. */
+    struct rb_node *rb_node;          /* Current node in tree. */
+    struct rb_node *rb_stack[RB_MAX_HEIGHT];
+                                        /* All the nodes above |rb_node|. */
+    size_t rb_height;                  /* Number of nodes in |rb_parent|. */
+    unsigned long rb_generation;       /* Generation number. */
+  };
+
+/* Table functions. */
+struct rb_table *rb_create (rb_comparison_func *, void *,
+                              struct libavl_allocator *);
+struct rb_table *rb_copy (const struct rb_table *, rb_copy_func *,
+                            rb_item_func *, struct libavl_allocator *);
+void rb_destroy (struct rb_table *, rb_item_func *);
+void **rb_probe (struct rb_table *, void *);
+void *rb_insert (struct rb_table *, void *);
+void *rb_replace (struct rb_table *, void *);
+void *rb_delete (struct rb_table *, const void *);
+void *rb_find (const struct rb_table *, const void *);
+void rb_assert_insert (struct rb_table *, void *);
+void *rb_assert_delete (struct rb_table *, void *);
+
+#define rb_count(table) ((size_t) (table)->rb_count)
+
+/* Table traverser functions. */
+void rb_t_init (struct rb_traverser *, struct rb_table *);
+void *rb_t_first (struct rb_traverser *, struct rb_table *);
+void *rb_t_last (struct rb_traverser *, struct rb_table *);
+void *rb_t_find (struct rb_traverser *, struct rb_table *, void *);
+void *rb_t_insert (struct rb_traverser *, struct rb_table *, void *);
+void *rb_t_copy (struct rb_traverser *, const struct rb_traverser *);
+void *rb_t_next (struct rb_traverser *);
+void *rb_t_prev (struct rb_traverser *);
+void *rb_t_cur (struct rb_traverser *);
+void *rb_t_replace (struct rb_traverser *, void *);
+
+#endif /* rb.h */
diff --git a/xlators/features/uidmap/src/rbmap.c b/xlators/features/uidmap/src/rbmap.c
new file mode 100644
index 0000000..59a227a
--- /dev/null
+++ b/xlators/features/uidmap/src/rbmap.c
@@ -0,0 +1,453 @@
+/* 
+   Copyright © 2011, Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation, version 2 of the
+   License.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+*/
+
+#include <sys/file.h>
+#include <stdio.h>
+#include "glusterfs.h"
+#include "xlator.h"
+#include "uidmap.h"
+#include "rb.h"
+
+static struct {
+        uid_t uid_low;
+        uid_t uid_high;
+        uid_t uid_next;
+        gid_t gid_low;
+        gid_t gid_high;
+        uid_t gid_next;
+        struct rb_table *uid_map;
+        struct rb_table *uid_revmap;
+        struct rb_table *gid_map;
+        struct rb_table *gid_revmap;
+        char* tenant;
+        int root_squash;
+        pthread_mutex_t mtx;
+} rbmap;
+
+union tuple {
+        struct {
+                uid_t u1;
+                uid_t u2;
+        };
+        struct {
+                gid_t g1;
+                gid_t g2;
+        };
+};
+
+#define RBMAP_SIGNATURE         "cloudfs map: rbmap\n"
+#define RBMAP_UID_MAP_ENTRY     "uid_map_entry:"
+#define RBMAP_UID_MAP_ENTRY_LEN 13
+#define RBMAP_UID_LOW           "uid_low:"
+#define RBMAP_UID_LOW_LEN       8
+#define RBMAP_UID_HIGH          "uid_high:"
+#define RBMAP_UID_HIGH_LEN      9
+#define RBMAP_UID_NEXT          "uid_next:"
+#define RBMAP_UID_NEXT_LEN      9
+#define RBMAP_GID_MAP_ENTRY     "gid_map_entry:"
+#define RBMAP_GID_MAP_ENTRY_LEN 13
+#define RBMAP_GID_LOW           "gid_low:"
+#define RBMAP_GID_LOW_LEN       8
+#define RBMAP_GID_HIGH          "gid_high:"
+#define RBMAP_GID_HIGH_LEN      9
+#define RBMAP_GID_NEXT          "gid_next:"
+#define RBMAP_GID_NEXT_LEN      9
+
+#define RBMAP_LOG_LEVEL GF_LOG_DEBUG
+
+/* serialize and persist */
+static void
+rbmap_serialize(char *tenant)
+{
+        char fname[128], lkname[128];
+        FILE *file = NULL;
+        int lockfd = -1;
+        (void) snprintf(lkname, sizeof lkname, UIDMAP_MAP_LOCK_FILE, tenant);
+        (void) snprintf(fname, sizeof fname, UIDMAP_MAP_FILE, tenant);
+
+        do {
+                int status;
+                struct rb_traverser trav;
+                union tuple *data;
+                lockfd = open(lkname, O_CREAT|O_WRONLY, 0644);
+                if (lockfd == -1) {
+                        gf_log("serialize", GF_LOG_CRITICAL, "open %s: %s", lkname, strerror(errno));
+                        break;
+                }
+                status = flock(lockfd, LOCK_EX);
+                if (status == -1) {
+                        gf_log("serialize", GF_LOG_CRITICAL, "flock failed %s", strerror(errno));
+                        break;
+                }
+                file = fopen(fname, "w");
+                if (file == NULL) {
+                        (void) flock(lockfd, LOCK_UN);
+                        gf_log("serialize", GF_LOG_CRITICAL, "fopen failed %s", strerror(errno));
+                        break;
+                }
+                (void) fprintf(file, RBMAP_SIGNATURE);
+                data = (union tuple *) rb_t_first(&trav, rbmap.uid_map);
+                while (data != NULL) {
+                        (void) fprintf(file, "%s %u %u\n",
+                                       RBMAP_UID_MAP_ENTRY,
+                                       data->u1, data->u2);
+                        data = (union tuple *) rb_t_next(&trav);
+                }
+                (void) fprintf(file, "%s %u\n", RBMAP_UID_LOW, rbmap.uid_low);
+                (void) fprintf(file, "%s %u\n", RBMAP_UID_HIGH, rbmap.uid_high);
+                (void) fprintf(file, "%s %u\n", RBMAP_UID_NEXT, rbmap.uid_next);
+                data = (union tuple *) rb_t_first(&trav, rbmap.gid_map);
+                while (data != NULL) {
+                        (void) fprintf(file, "%s %u %u\n",
+                                       RBMAP_GID_MAP_ENTRY,
+                                       data->g1, data->g2);
+                        data = (union tuple *) rb_t_next(&trav);
+                }
+                (void) fprintf(file, "%s %u\n", RBMAP_GID_LOW, rbmap.gid_low);
+                (void) fprintf(file, "%s %u\n", RBMAP_GID_HIGH, rbmap.gid_high);
+                (void) fprintf(file, "%s %u\n", RBMAP_GID_NEXT, rbmap.gid_next);
+        } while (0);
+        if (file != NULL) {
+                (void) fclose(file);
+        }
+        if (lockfd != -1) {
+                (void) flock(lockfd, LOCK_UN);
+                (void) close(lockfd);
+        }
+}
+
+static int
+rbmap_deserialize(char *tenant)
+{
+        char fname[128], lkname[128];
+        FILE* file = NULL;
+        int lockfd = -1;
+        (void) snprintf(lkname, sizeof lkname, UIDMAP_MAP_LOCK_FILE, tenant);
+        (void) snprintf(fname, sizeof fname, UIDMAP_MAP_FILE, tenant);
+
+        do {
+                char scratch[128];
+                char* sts;
+                int status;
+                lockfd = open(lkname, O_CREAT|O_RDONLY, 0644);
+                if (lockfd == -1) {
+                        gf_log("deserialize", GF_LOG_CRITICAL, "open %s: %s", lkname, strerror(errno));
+                        break;
+                }
+                status = flock(lockfd, LOCK_EX);
+                if (status == -1) {
+                        gf_log("deserialize", GF_LOG_CRITICAL, "flock: %s", strerror(errno));
+                        break;
+                }
+                file = fopen(fname, "r");
+                if (file == NULL) {
+                        gf_log("deserialize", GF_LOG_CRITICAL, "fopen failed: %s", strerror(errno));
+                        break;
+                }
+                /* read the first line (signature) of the file) */
+                if ((sts = fgets(scratch, sizeof scratch, file)) == (char *) EOF || sts == NULL) {
+                        gf_log("deserialize", GF_LOG_CRITICAL, "fgets signature failed: %s", strerror(errno));
+                        break;
+                }
+                if (strcmp(RBMAP_SIGNATURE, scratch) != 0) {
+                        gf_log("deserialize", GF_LOG_CRITICAL, " signature mismatch: %s", scratch);
+                        break;
+                }
+                while ((sts = fgets(scratch, sizeof scratch, file)) != (char *) EOF && sts != NULL) {
+                        if (strncmp(scratch, RBMAP_UID_MAP_ENTRY, RBMAP_UID_MAP_ENTRY_LEN) == 0) {
+                                union tuple *map_data;
+                                union tuple *revmap_data = (union tuple *) malloc(sizeof(union tuple));
+                                if (revmap_data != NULL) {
+                                        map_data = (union tuple *) malloc(sizeof(union tuple));
+                                } else {
+                                        return -1;
+                                }
+                                if (map_data != NULL) {
+                                        int num = sscanf(&scratch[RBMAP_UID_MAP_ENTRY_LEN+1], " %u %u", &map_data->u1, &map_data->u2);
+                                        if (num == 2) {
+                                                rb_insert(rbmap.uid_map, map_data);
+                                                revmap_data->u1 = map_data->u2;
+                                                revmap_data->u2 = map_data->u1;
+                                                rb_insert(rbmap.uid_revmap, revmap_data);
+                                        } else {
+                                                (void) free(map_data);
+                                                (void) free(revmap_data);
+                                                return -1;
+                                        }
+                                } else {
+                                        (void) free(revmap_data);
+                                        return -1;
+                                }
+                        } else if (strncmp(scratch, RBMAP_UID_LOW, RBMAP_UID_LOW_LEN) == 0) {
+                                rbmap.uid_low = (uid_t) strtoul(&scratch[RBMAP_UID_LOW_LEN+1], NULL, 10);
+                        } else if (strncmp(scratch, RBMAP_UID_HIGH, RBMAP_UID_HIGH_LEN) == 0) {
+                                rbmap.uid_high = (uid_t) strtoul(&scratch[RBMAP_UID_HIGH_LEN+1], NULL, 10);
+                        } else if (strncmp(scratch, RBMAP_UID_NEXT, RBMAP_UID_NEXT_LEN) == 0) {
+                                rbmap.uid_next = (uid_t) strtoul(&scratch[RBMAP_UID_NEXT_LEN+1], NULL, 10);
+                        } else if (strncmp(scratch, RBMAP_GID_MAP_ENTRY, RBMAP_GID_MAP_ENTRY_LEN) == 0) {
+                                union tuple *map_data;
+                                union tuple *revmap_data = (union tuple *) malloc(sizeof(union tuple));
+                                if (revmap_data != NULL) {
+                                        map_data = (union tuple *) malloc(sizeof(union tuple));
+                                } else {
+                                        return -1;
+                                }
+                                if (map_data != NULL) {
+                                        int num = sscanf(&scratch[RBMAP_GID_MAP_ENTRY_LEN+1], " %u %u", &map_data->g1, &map_data->g2);
+                                        if (num == 2) {
+                                                rb_insert(rbmap.gid_map, map_data);
+                                                revmap_data->g1 = map_data->g2;
+                                                revmap_data->g2 = map_data->g1;
+                                                rb_insert(rbmap.gid_revmap, revmap_data);
+                                        } else {
+                                                (void) free(map_data);
+                                                (void) free(revmap_data);
+                                                return -1;
+                                        }
+                                } else {
+                                        (void) free(revmap_data);
+                                        return -1;
+                                }
+                        } else if (strncmp(scratch, RBMAP_GID_LOW, RBMAP_GID_LOW_LEN) == 0) {
+                                rbmap.gid_low = (uid_t) strtoul(&scratch[RBMAP_GID_LOW_LEN+1], NULL, 10);
+                        } else if (strncmp(scratch, RBMAP_GID_HIGH, RBMAP_GID_HIGH_LEN) == 0) {
+                                rbmap.gid_high = (uid_t) strtoul(&scratch[RBMAP_GID_HIGH_LEN+1], NULL, 10);
+                        } else if (strncmp(scratch, RBMAP_GID_NEXT, RBMAP_GID_NEXT_LEN) == 0) {
+                                rbmap.gid_next = (uid_t) strtoul(&scratch[RBMAP_GID_NEXT_LEN+1], NULL, 10);
+                        }
+                }
+        } while (0);
+        if (file != NULL) {
+                (void) fclose(file);
+        }
+        if (lockfd != -1) {
+                (void) flock(lockfd, LOCK_UN);
+                (void) close(lockfd);
+        }
+        return 0;
+}
+
+
+int
+map(struct _call_stack_t *stack, struct _xlator *xlator)
+{
+        char *tenant = rbmap.tenant ? rbmap.tenant : "unknown";
+        int do_persist = 0;
+        if (stack->uid == 0 && rbmap.root_squash) {
+                stack->uid = stack->gid = CLOUDFS_NOBODY;
+                return 0;
+        }
+        pthread_mutex_lock(&rbmap.mtx);
+        do {
+                if (stack->uid != 0) {
+                        /* look for an existing match */
+                        union tuple *new_map, needle;
+                        needle.u1 = stack->uid;
+                        new_map = (union tuple *) rb_find(rbmap.uid_map, &needle);
+                        if (new_map == NULL) {
+                                union tuple *new_revmap = NULL;
+                                /* couldn't find one, make a new one */
+                                if (rbmap.uid_next > rbmap.uid_high) {
+                                        gf_log("map uid", GF_LOG_CRITICAL,
+                                               "exhausted uids in range %u-%u",
+                                               rbmap.uid_low, rbmap.uid_high);
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        return -1;
+                                }
+                                new_map = (union tuple *) malloc(sizeof(union tuple));
+                                new_revmap = (union tuple *) malloc(sizeof(union tuple));
+                                if (new_map == NULL || new_revmap == NULL) {
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        if (new_map != NULL) (void) free(new_map);
+                                        if (new_revmap != NULL) (void) free(new_revmap);
+                                        return -1;
+                                }
+                                do_persist = 1;
+                                new_map->u1 = stack->uid;
+                                new_map->u2 = rbmap.uid_next++;
+                                new_revmap->u1 = new_map->u2;
+                                new_revmap->u2 = new_map->u1;
+                                if (rb_probe(rbmap.uid_map, new_map) == NULL) {
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        (void) free(new_map);
+                                        (void) free(new_revmap);
+                                        return -1;
+                                }
+                                if (rb_probe(rbmap.uid_revmap, new_revmap) == NULL) {
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        (void) rb_delete(rbmap.uid_map, new_map);
+                                        (void) free(new_map);
+                                        (void) free(new_revmap);
+                                        return -1;
+                                }
+                                gf_log("map uid", GF_LOG_TRACE,
+                                       "added new uid mapping for %s %u -> %u",
+                                       tenant, stack->uid, new_map->u2);
+                        }
+                        stack->uid = new_map->u2;
+                }
+                if (stack->gid != 0) {
+                        /* look for an existing match */
+                        union tuple *new_map, needle;
+                        needle.g1 = stack->gid;
+                        new_map = (union tuple *) rb_find(rbmap.gid_map, &needle);
+                        if (new_map == NULL) {
+                                union tuple *new_revmap = NULL;
+                                /* couldn't find one, make a new one */
+                                if (rbmap.gid_next > rbmap.gid_high) {
+                                        gf_log("map gid", GF_LOG_CRITICAL,
+                                               "exhausted gids in range %u-%u",
+                                               rbmap.gid_low, rbmap.gid_high);
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        return -1;
+                                }
+                                new_map = (union tuple *) malloc(sizeof(union tuple));
+                                new_revmap = (union tuple *) malloc(sizeof(union tuple));
+                                if (new_map == NULL || new_revmap == NULL) {
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        if (new_map != NULL) (void) free(new_map);
+                                        if (new_revmap != NULL) (void) free(new_revmap);
+                                        return -1;
+                                }
+                                do_persist = 1;
+                                new_map->g1 = stack->gid;
+                                new_map->g2 = rbmap.gid_next++;
+                                new_revmap->g1 = new_map->g2;
+                                new_revmap->g2 = new_map->g1;
+                                if (rb_probe(rbmap.gid_map, new_map) == NULL) {
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        (void) free(new_map);
+                                        (void) free(new_revmap);
+                                        return -1;
+                                }
+                                if (rb_probe(rbmap.gid_revmap, new_revmap) == NULL) {
+                                        pthread_mutex_unlock(&rbmap.mtx);
+                                        (void) rb_delete(rbmap.gid_map, new_map);
+                                        (void) free(new_map);
+                                        (void) free(new_revmap);
+                                        return -1;
+                                }
+                                gf_log("map gid", GF_LOG_TRACE,
+                                       "added new gid mapping for %s %u -> %u",
+                                       tenant, stack->gid, new_map->g2);
+                        }
+                        stack->gid = new_map->g2;
+                }
+        } while (0);
+        if (do_persist > 0)
+                rbmap_serialize(tenant);
+        pthread_mutex_unlock(&rbmap.mtx);
+
+        return 0;
+}
+
+
+void
+revmap(uid_t *uid, gid_t *gid)
+{
+        union tuple *found, needle;
+        switch (*uid) {
+        case 0:
+                /* break; */
+        case CLOUDFS_NOBODY:
+                *uid = 0;
+                break;
+        default:
+                needle.u1 = *uid;
+                found = (union tuple *) rb_find(rbmap.uid_revmap, &needle);
+                if (found != NULL) {
+                        *uid = found->u2;
+                }
+                break;
+        }
+        switch (*gid) {
+        case 0:
+                /* break; */
+        case CLOUDFS_NOBODY:
+                *uid = 0;
+                break;
+        default:
+                needle.g1 = *gid;
+                found = (union tuple *) rb_find(rbmap.gid_revmap, &needle);
+                if (found != NULL) {
+                        *gid = found->g2;
+                }
+                break;
+        }
+}
+
+
+static int
+rbmap_compare_uid(const void *rb_a, const void *rb_b, void *rb_param)
+{
+        union tuple *a = (union tuple *)rb_a;
+        union tuple *b = (union tuple *)rb_b;
+        int ret = 0;
+        if (a->u1 < b->u1)
+                ret--;
+        else if (a->u1 > b->u1)
+                ret++;
+        return ret;
+}
+
+
+static int
+rbmap_compare_gid(const void *rb_a, const void *rb_b, void *rb_param)
+{
+        union tuple *a = (union tuple *)rb_a;
+        union tuple *b = (union tuple *)rb_b;
+        int ret = 0;
+        if (a->g1 < b->g1)
+                ret--;
+        else if (a->g1 > b->g1)
+                ret++;
+        return ret;
+}
+
+
+int32_t
+init(struct _xlator *xlator, char *tenant, uid_t uid_low, uid_t uid_hi, gid_t gid_low, gid_t gid_hi, int root_squash)
+{
+        pthread_mutex_init(&rbmap.mtx, NULL);
+        rbmap.tenant      = strdup(tenant);
+        rbmap.root_squash = root_squash;
+        rbmap.uid_low     = rbmap.uid_next = uid_low;
+        rbmap.uid_high    = uid_hi;
+        rbmap.gid_low     = rbmap.gid_next = gid_low;
+        rbmap.gid_high    = gid_hi;
+        rbmap.uid_map     = rb_create(rbmap_compare_uid, NULL, NULL);
+        rbmap.uid_revmap  = rb_create(rbmap_compare_uid, NULL, NULL);
+        rbmap.gid_map     = rb_create(rbmap_compare_gid, NULL, NULL);
+        rbmap.gid_revmap  = rb_create(rbmap_compare_gid, NULL, NULL);
+
+        return rbmap_deserialize(tenant);
+}
+
+void
+fini(struct _xlator *xlator)
+{
+
+}
+
+/* convenience symbols for debugging. */
+/* Why weak? Dunno, just because I guess; I don't think it matters  */
+extern int _rb_map(struct _call_stack_t *, struct _xlator *) __attribute__ ((weak, alias ("map")));
+extern void _rb_revmap(uid_t *, gid_t *) __attribute__ ((weak, alias ("revmap")));
+extern int32_t _rb_init(struct _xlator *, char *, uid_t, uid_t, gid_t, gid_t) __attribute__ ((weak, alias ("init")));
+extern void _rb_fini(struct _xlator *) __attribute__ ((weak, alias ("fini")));
diff --git a/xlators/features/uidmap/src/uidmap.c b/xlators/features/uidmap/src/uidmap.c
index c9fd893..4000d8b 100644
--- a/xlators/features/uidmap/src/uidmap.c
+++ b/xlators/features/uidmap/src/uidmap.c
@@ -26,7 +26,6 @@
  * xlators/cluster/uidmap :
  */
 
-#include <time.h>
 #include <dlfcn.h>
 #include <sys/file.h>
 #include "glusterfs.h"
@@ -43,8 +42,6 @@
 static short uidmap_root_squash = 0;
 static char *uidmap_tenant = NULL;
 
-#define CLOUDFS_NOBODY 65534 /* just like NFS root squash */
-
 typedef struct uid_map_entry {
         uid_t me_client_uid;
         uid_t me_server_uid;
@@ -106,13 +103,13 @@ static id_mapping_t uidmap_mapping = {
 
 /* serialize and persist */
 static void
-uidmap_serialize_default(char *name)
+uidmap_serialize_default(char *tenant)
 {
         char fname[128], lkname[128];
         FILE *file = NULL;
         int lockfd = -1;
-        (void) snprintf(lkname, sizeof lkname, UIDMAP_MAP_LOCK_FILE, name);
-        (void) snprintf(fname, sizeof fname, UIDMAP_MAP_FILE, name);
+        (void) snprintf(lkname, sizeof lkname, UIDMAP_MAP_LOCK_FILE, tenant);
+        (void) snprintf(fname, sizeof fname, UIDMAP_MAP_FILE, tenant);
 
         do {
                 int status;
@@ -133,7 +130,7 @@ uidmap_serialize_default(char *name)
                         gf_log("serialize", GF_LOG_CRITICAL, "fopen failed %s", strerror(errno));
                         break;
                 }
-                (void) fprintf(file, "cloudfs map: default\n");
+                (void) fprintf(file, CFS_SIGNATURE);
                 for (i = 0; i < uidmap_mapping.im_uid_map_len; i++) {
                         (void) fprintf(file, "%s %u %u\n",
                                        CFS_UID_MAP_ENTRY,
@@ -195,7 +192,7 @@ uidmap_deserialize_default(char *tenant)
                         gf_log("deserialize", GF_LOG_CRITICAL, "fgets signature failed: %s", strerror(errno));
                         break;
                 }
-                if (strcmp("cloudfs map: default\n", scratch) != 0) {
+                if (strcmp(CFS_SIGNATURE, scratch) != 0) {
                         gf_log("deserialize", GF_LOG_CRITICAL, " signature mismatch: %s", scratch);
                         break;
                 }
@@ -1846,8 +1843,9 @@ init(xlator_t *this)
                                                "plugin missing init: %s", dlerror());
                                 } else {
                                     if ((*plugin_init)(this, uidmap_tenant,
-                                            uidmap_low_uid, uidmap_hi_uid,
-                                            uidmap_low_gid, uidmap_hi_gid) != 0) {
+                                                       uidmap_low_uid, uidmap_hi_uid,
+                                                       uidmap_low_gid, uidmap_hi_gid,
+                                                       uidmap_root_squash) != 0) {
                                         gf_log(this->name, GF_LOG_CRITICAL,
                                                "plugin init error");
                                     }
diff --git a/xlators/features/uidmap/src/uidmap.h b/xlators/features/uidmap/src/uidmap.h
index f868a99..5de9322 100644
--- a/xlators/features/uidmap/src/uidmap.h
+++ b/xlators/features/uidmap/src/uidmap.h
@@ -24,11 +24,13 @@
 
 typedef int (* map_fn)(struct _call_stack_t *, struct _xlator *);
 typedef void (* revmap_fn)(uid_t *, gid_t *);
-typedef int32_t (* init_fn)(struct _xlator *, char *, uid_t, uid_t, gid_t, gid_t);
+typedef int32_t (* init_fn)(struct _xlator *, char *, uid_t, uid_t, gid_t, gid_t, int);
 typedef void (* fini_fn)(struct _xlator *);
 
 #define UIDMAP_MAP_LOCK_FILE "/var/lib/cloudfs/map_%s.lck"
 #define UIDMAP_MAP_FILE      "/var/lib/cloudfs/map_%s"
 
+#define CLOUDFS_NOBODY 65534 /* just like NFS root squash */
+
 #endif /* __UIDMAP_H__ */
 




More information about the cloudfs-devel mailing list