/* holds quota configuration and tracking */
 #define BTRFS_QUOTA_TREE_OBJECTID 8ULL
 
+/* for storing items that use the BTRFS_UUID_KEY* types */
+#define BTRFS_UUID_TREE_OBJECTID 9ULL
+
 /* for storing balance parameters in the root tree */
 #define BTRFS_BALANCE_OBJECTID -4ULL
 
  */
 #define BTRFS_DEV_REPLACE_KEY  250
 
+/*
+ * Stores items that allow to quickly map UUIDs to something else.
+ * These items are part of the filesystem UUID tree.
+ * The key is built like this:
+ * (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits).
+ */
+#if BTRFS_UUID_SIZE != 16
+#error "UUID items require BTRFS_UUID_SIZE == 16!"
+#endif
+#define BTRFS_UUID_KEY_SUBVOL  251     /* for UUIDs assigned to subvols */
+#define BTRFS_UUID_KEY_RECEIVED_SUBVOL 252     /* for UUIDs assigned to
+                                                * received subvols */
+
 /*
  * string items are for debugging.  They just store a short string of
  * data in the FS
 void btrfs_update_root_times(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root);
 
+/* uuid-tree.c */
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid);
+int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid);
+
 /* dir-item.c */
 int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
                          const char *name, int name_len);
 
--- /dev/null
+/*
+ * Copyright (C) STRATO AG 2013.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * 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 021110-1307, USA.
+ */
+#include <linux/uuid.h>
+#include <asm/unaligned.h>
+#include "ctree.h"
+#include "transaction.h"
+#include "disk-io.h"
+#include "print-tree.h"
+
+
+static void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key)
+{
+       key->type = type;
+       key->objectid = get_unaligned_le64(uuid);
+       key->offset = get_unaligned_le64(uuid + sizeof(u64));
+}
+
+/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
+static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
+                                 u8 type, u64 subid)
+{
+       int ret;
+       struct btrfs_path *path = NULL;
+       struct extent_buffer *eb;
+       int slot;
+       u32 item_size;
+       unsigned long offset;
+       struct btrfs_key key;
+
+       if (WARN_ON_ONCE(!uuid_root)) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       btrfs_uuid_to_key(uuid, type, &key);
+       ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
+       if (ret < 0) {
+               goto out;
+       } else if (ret > 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       eb = path->nodes[0];
+       slot = path->slots[0];
+       item_size = btrfs_item_size_nr(eb, slot);
+       offset = btrfs_item_ptr_offset(eb, slot);
+       ret = -ENOENT;
+
+       if (!IS_ALIGNED(item_size, sizeof(u64))) {
+               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                       (unsigned long)item_size);
+               goto out;
+       }
+       while (item_size) {
+               __le64 data;
+
+               read_extent_buffer(eb, &data, offset, sizeof(data));
+               if (le64_to_cpu(data) == subid) {
+                       ret = 0;
+                       break;
+               }
+               offset += sizeof(data);
+               item_size -= sizeof(data);
+       }
+
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid_cpu)
+{
+       int ret;
+       struct btrfs_path *path = NULL;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       int slot;
+       unsigned long offset;
+       __le64 subid_le;
+
+       ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu);
+       if (ret != -ENOENT)
+               return ret;
+
+       if (WARN_ON_ONCE(!uuid_root)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       btrfs_uuid_to_key(uuid, type, &key);
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
+                                     sizeof(subid_le));
+       if (ret >= 0) {
+               /* Add an item for the type for the first time */
+               eb = path->nodes[0];
+               slot = path->slots[0];
+               offset = btrfs_item_ptr_offset(eb, slot);
+       } else if (ret == -EEXIST) {
+               /*
+                * An item with that type already exists.
+                * Extend the item and store the new subid at the end.
+                */
+               btrfs_extend_item(uuid_root, path, sizeof(subid_le));
+               eb = path->nodes[0];
+               slot = path->slots[0];
+               offset = btrfs_item_ptr_offset(eb, slot);
+               offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le);
+       } else if (ret < 0) {
+               pr_warn("btrfs: insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!\n",
+                       ret, (unsigned long long)key.objectid,
+                       (unsigned long long)key.offset, type);
+               goto out;
+       }
+
+       ret = 0;
+       subid_le = cpu_to_le64(subid_cpu);
+       write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le));
+       btrfs_mark_buffer_dirty(eb);
+
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid)
+{
+       int ret;
+       struct btrfs_path *path = NULL;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       int slot;
+       unsigned long offset;
+       u32 item_size;
+       unsigned long move_dst;
+       unsigned long move_src;
+       unsigned long move_len;
+
+       if (WARN_ON_ONCE(!uuid_root)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       btrfs_uuid_to_key(uuid, type, &key);
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
+       if (ret < 0) {
+               pr_warn("btrfs: error %d while searching for uuid item!\n",
+                       ret);
+               goto out;
+       }
+       if (ret > 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       eb = path->nodes[0];
+       slot = path->slots[0];
+       offset = btrfs_item_ptr_offset(eb, slot);
+       item_size = btrfs_item_size_nr(eb, slot);
+       if (!IS_ALIGNED(item_size, sizeof(u64))) {
+               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                       (unsigned long)item_size);
+               ret = -ENOENT;
+               goto out;
+       }
+       while (item_size) {
+               __le64 read_subid;
+
+               read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
+               if (le64_to_cpu(read_subid) == subid)
+                       break;
+               offset += sizeof(read_subid);
+               item_size -= sizeof(read_subid);
+       }
+
+       if (!item_size) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       item_size = btrfs_item_size_nr(eb, slot);
+       if (item_size == sizeof(subid)) {
+               ret = btrfs_del_item(trans, uuid_root, path);
+               goto out;
+       }
+
+       move_dst = offset;
+       move_src = offset + sizeof(subid);
+       move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
+       memmove_extent_buffer(eb, move_dst, move_src, move_len);
+       btrfs_truncate_item(uuid_root, path, item_size - sizeof(subid), 1);
+
+out:
+       btrfs_free_path(path);
+       return ret;
+}