u8 level;
 } __attribute__ ((__packed__));
 
+/*
+ * this is used for both forward and backward root refs
+ */
+struct btrfs_root_ref {
+       __le64 dirid;
+       __le64 sequence;
+       __le16 name_len;
+} __attribute__ ((__packed__));
+
 #define BTRFS_FILE_EXTENT_INLINE 0
 #define BTRFS_FILE_EXTENT_REG 1
 #define BTRFS_FILE_EXTENT_PREALLOC 2
  * the FS
  */
 #define BTRFS_INODE_ITEM_KEY           1
-#define BTRFS_INODE_REF_KEY            2
-#define BTRFS_XATTR_ITEM_KEY           8
-#define BTRFS_ORPHAN_ITEM_KEY          9
+#define BTRFS_INODE_REF_KEY            12
+#define BTRFS_XATTR_ITEM_KEY           24
+#define BTRFS_ORPHAN_ITEM_KEY          48
 /* reserve 2-15 close to the inode for later flexibility */
 
 /*
  * dir items are the name -> inode pointers in a directory.  There is one
  * for every name in a directory.
  */
-#define BTRFS_DIR_LOG_ITEM_KEY  14
-#define BTRFS_DIR_LOG_INDEX_KEY 15
-#define BTRFS_DIR_ITEM_KEY     16
-#define BTRFS_DIR_INDEX_KEY    17
+#define BTRFS_DIR_LOG_ITEM_KEY  60
+#define BTRFS_DIR_LOG_INDEX_KEY 72
+#define BTRFS_DIR_ITEM_KEY     84
+#define BTRFS_DIR_INDEX_KEY    96
 /*
  * extent data is for file data
  */
-#define BTRFS_EXTENT_DATA_KEY  18
+#define BTRFS_EXTENT_DATA_KEY  108
 /*
  * csum items have the checksums for data in the extents
  */
-#define BTRFS_CSUM_ITEM_KEY    19
+#define BTRFS_CSUM_ITEM_KEY    120
 
 
 /* reserve 21-31 for other file/dir stuff */
  * root items point to tree roots.  There are typically in the root
  * tree used by the super block to find all the other trees
  */
-#define BTRFS_ROOT_ITEM_KEY    32
+#define BTRFS_ROOT_ITEM_KEY    132
+
+/*
+ * root backrefs tie subvols and snapshots to the directory entries that
+ * reference them
+ */
+#define BTRFS_ROOT_BACKREF_KEY 144
+
+/*
+ * root refs make a fast index for listing all of the snapshots and
+ * subvolumes referenced by a given root.  They point directly to the
+ * directory item in the root that references the subvol
+ */
+#define BTRFS_ROOT_REF_KEY     156
+
 /*
  * extent items are in the extent map tree.  These record which blocks
  * are used, and how many references there are to each block
  */
-#define BTRFS_EXTENT_ITEM_KEY  33
-#define BTRFS_EXTENT_REF_KEY   34
+#define BTRFS_EXTENT_ITEM_KEY  168
+#define BTRFS_EXTENT_REF_KEY   180
 
 /*
  * block groups give us hints into the extent allocation trees.  Which
  * blocks are free etc etc
  */
-#define BTRFS_BLOCK_GROUP_ITEM_KEY 50
+#define BTRFS_BLOCK_GROUP_ITEM_KEY 192
 
-#define BTRFS_DEV_EXTENT_KEY   75
-#define BTRFS_DEV_ITEM_KEY     76
-#define BTRFS_CHUNK_ITEM_KEY   77
+#define BTRFS_DEV_EXTENT_KEY   204
+#define BTRFS_DEV_ITEM_KEY     216
+#define BTRFS_CHUNK_ITEM_KEY   228
 
 /*
  * string items are for debugging.  They just store a short string of
 
 BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64);
 
+/*
+ * struct btrfs_root_ref
+ */
+BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);
+BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);
+BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
+
 /* struct btrfs_dir_item */
 BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
 BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
                        struct extent_buffer *node,
                        struct extent_buffer *parent);
 /* root-item.c */
+int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *tree_root,
+                      u64 root_id, u8 type, u64 ref_id,
+                      u64 dirid, u64 sequence,
+                      const char *name, int name_len);
 int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                   struct btrfs_key *key);
 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
 
                return -ENOTEMPTY;
        }
 
+       /* to rename a snapshot or subvolume, we need to juggle the
+        * backrefs.  This isn't coded yet
+        */
+       if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
+               return -EXDEV;
+
        ret = btrfs_check_free_space(root, 1, 0);
        if (ret)
                goto out_unlock;
 
                                    BTRFS_FT_DIR, index);
        if (ret)
                goto fail;
-#if 0
-       ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
-                            name, namelen, objectid,
-                            root->fs_info->sb->s_root->d_inode->i_ino, 0);
-       if (ret)
-               goto fail;
-#endif
+
+       /* add the backref first */
+       ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
+                                objectid, BTRFS_ROOT_BACKREF_KEY,
+                                root->root_key.objectid,
+                                dir->i_ino, index, name, namelen);
+
+       BUG_ON(ret);
+
+       /* now add the forward ref */
+       ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
+                                root->root_key.objectid, BTRFS_ROOT_REF_KEY,
+                                objectid,
+                                dir->i_ino, index, name, namelen);
+
+       BUG_ON(ret);
+
        ret = btrfs_commit_transaction(trans, root);
        if (ret)
                goto fail_commit;
 
        int slot;
 
        search_key.objectid = objectid;
-       search_key.type = (u8)-1;
+       search_key.type = BTRFS_ROOT_ITEM_KEY;
        search_key.offset = (u64)-1;
 
        path = btrfs_alloc_path();
        btrfs_free_path(path);
        return ret;
 }
+
+int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *tree_root,
+                      u64 root_id, u8 type, u64 ref_id)
+{
+       struct btrfs_key key;
+       int ret;
+       struct btrfs_path *path;
+
+       path = btrfs_alloc_path();
+
+       key.objectid = root_id;
+       key.type = type;
+       key.offset = ref_id;
+
+       ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
+       BUG_ON(ret);
+
+       ret = btrfs_del_item(trans, tree_root, path);
+       BUG_ON(ret);
+
+       btrfs_free_path(path);
+       return ret;
+}
+
+/*
+ * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
+ * or BTRFS_ROOT_BACKREF_KEY.
+ *
+ * The dirid, sequence, name and name_len refer to the directory entry
+ * that is referencing the root.
+ *
+ * For a forward ref, the root_id is the id of the tree referencing
+ * the root and ref_id is the id of the subvol  or snapshot.
+ *
+ * For a back ref the root_id is the id of the subvol or snapshot and
+ * ref_id is the id of the tree referencing it.
+ */
+int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *tree_root,
+                      u64 root_id, u8 type, u64 ref_id,
+                      u64 dirid, u64 sequence,
+                      const char *name, int name_len)
+{
+       struct btrfs_key key;
+       int ret;
+       struct btrfs_path *path;
+       struct btrfs_root_ref *ref;
+       struct extent_buffer *leaf;
+       unsigned long ptr;
+
+
+       path = btrfs_alloc_path();
+
+       key.objectid = root_id;
+       key.type = type;
+       key.offset = ref_id;
+
+       ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
+                                     sizeof(*ref) + name_len);
+       BUG_ON(ret);
+
+       leaf = path->nodes[0];
+       ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
+       btrfs_set_root_ref_dirid(leaf, ref, dirid);
+       btrfs_set_root_ref_sequence(leaf, ref, sequence);
+       btrfs_set_root_ref_name_len(leaf, ref, name_len);
+       ptr = (unsigned long)(ref + 1);
+       write_extent_buffer(leaf, name, ptr, name_len);
+       btrfs_mark_buffer_dirty(leaf);
+
+       btrfs_free_path(path);
+       return ret;
+}
 
        struct btrfs_trans_handle *trans;
        struct inode *parent_inode;
        struct inode *inode;
+       struct btrfs_root *parent_root;
 
        parent_inode = pending->dentry->d_parent->d_inode;
-       trans = btrfs_start_transaction(BTRFS_I(parent_inode)->root, 1);
+       parent_root = BTRFS_I(parent_inode)->root;
+       trans = btrfs_start_transaction(parent_root, 1);
 
        /*
         * insert the directory item
         */
        namelen = strlen(pending->name);
        ret = btrfs_set_inode_index(parent_inode, &index);
-       ret = btrfs_insert_dir_item(trans,
-                           BTRFS_I(parent_inode)->root,
+       ret = btrfs_insert_dir_item(trans, parent_root,
                            pending->name, namelen,
                            parent_inode->i_ino,
                            &pending->root_key, BTRFS_FT_DIR, index);
 
        if (ret)
                goto fail;
-#if 0
-       ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
-                            pending->name, strlen(pending->name), objectid,
-                            root->fs_info->sb->s_root->d_inode->i_ino, 0);
-#endif
+
+       /* add the backref first */
+       ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root,
+                                pending->root_key.objectid,
+                                BTRFS_ROOT_BACKREF_KEY,
+                                parent_root->root_key.objectid,
+                                parent_inode->i_ino, index, pending->name,
+                                namelen);
+
+       BUG_ON(ret);
+
+       /* now add the forward ref */
+       ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root,
+                                parent_root->root_key.objectid,
+                                BTRFS_ROOT_REF_KEY,
+                                pending->root_key.objectid,
+                                parent_inode->i_ino, index, pending->name,
+                                namelen);
+
        inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
        d_instantiate(pending->dentry, inode);
 fail: