spinlock_t list_lock;
        struct list_head dead_list;
        struct list_head orphan_list;
+
+       /*
+        * right now this just gets used so that a root has its own devid
+        * for stat.  It may be used for more later
+        */
+       struct super_block anon_super;
 };
 
 /*
 
        root->defrag_running = 0;
        root->defrag_level = 0;
        root->root_key.objectid = objectid;
+       root->anon_super.s_root = NULL;
+       root->anon_super.s_dev = 0;
+       INIT_LIST_HEAD(&root->anon_super.s_list);
+       INIT_LIST_HEAD(&root->anon_super.s_instances);
+       init_rwsem(&root->anon_super.s_umount);
+
        return 0;
 }
 
        root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location);
        if (IS_ERR(root))
                return root;
+
+       set_anon_super(&root->anon_super, NULL);
+
        ret = radix_tree_insert(&fs_info->fs_roots_radix,
                                (unsigned long)root->root_key.objectid,
                                root);
 {
        radix_tree_delete(&fs_info->fs_roots_radix,
                          (unsigned long)root->root_key.objectid);
+       if (root->anon_super.s_dev) {
+               down_write(&root->anon_super.s_umount);
+               kill_anon_super(&root->anon_super);
+       }
        if (root->in_sysfs)
                btrfs_sysfs_del_root(root);
        if (root->node)
 
        struct btrfs_trans_handle *trans;
        unsigned long nr = 0;
 
-       if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) {
+       /*
+        * the FIRST_FREE_OBJECTID check makes sure we don't try to rmdir
+        * the root of a subvolume or snapshot
+        */
+       if (inode->i_size > BTRFS_EMPTY_DIR_SIZE ||
+           inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
                return -ENOTEMPTY;
        }
 
        if (error)
                return error;
 
-       atomic_inc(&inode->i_count);
        d_instantiate(dentry, inode);
        return 0;
 }
 {
        struct inode *inode = dentry->d_inode;
        generic_fillattr(inode, stat);
+       stat->dev = BTRFS_I(inode)->root->anon_super.s_dev;
        stat->blksize = PAGE_CACHE_SIZE;
        stat->blocks = (inode_get_bytes(inode) +
                        BTRFS_I(inode)->delalloc_bytes) >> 9;
        u64 index = 0;
        int ret;
 
+       /* we're not allowed to rename between subvolumes */
+       if (BTRFS_I(old_inode)->root->root_key.objectid !=
+           BTRFS_I(new_dir)->root->root_key.objectid)
+               return -EXDEV;
+
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
            new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) {
                return -ENOTEMPTY;
 }
 
 static struct inode_operations btrfs_dir_inode_operations = {
+       .getattr        = btrfs_getattr,
        .lookup         = btrfs_lookup,
        .create         = btrfs_create,
        .unlink         = btrfs_unlink,
 
        key.objectid = objectid;
        key.offset = 1;
        btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
-printk("inserting root objectid %Lu\n", objectid);
        ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
                                &root_item);
        if (ret)
                ret = err;
 fail_commit:
        btrfs_btree_balance_dirty(root, nr);
-printk("all done ret %d\n", ret);
        return ret;
 }
 
 
        struct inode *parent_inode;
        struct inode *inode;
 
-       trans = btrfs_start_transaction(fs_info->fs_root, 1);
+       parent_inode = pending->dentry->d_parent->d_inode;
+       trans = btrfs_start_transaction(BTRFS_I(parent_inode)->root, 1);
 
        /*
         * insert the directory item
         */
        namelen = strlen(pending->name);
-       parent_inode = pending->dentry->d_parent->d_inode;
        ret = btrfs_set_inode_index(parent_inode, &index);
        ret = btrfs_insert_dir_item(trans,
                            BTRFS_I(parent_inode)->root,