Btrfs: Give each subvol and snapshot their own anonymous devid
authorChris Mason <chris.mason@oracle.com>
Tue, 18 Nov 2008 01:42:26 +0000 (20:42 -0500)
committerChris Mason <chris.mason@oracle.com>
Tue, 18 Nov 2008 01:42:26 +0000 (20:42 -0500)
Each subvolume has its own private inode number space, and so we need
to fill in different device numbers for each subvolume to avoid confusing
applications.

This commit puts a struct super_block into struct btrfs_root so it can
call set_anon_super() and get a different device number generated for
each root.

btrfs_rename is changed to prevent renames across subvols.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/transaction.c

index 5611f8e035a41f08a1a74e816cde2be05453ee9a..b3bc65b08c6a0373e91645e139162d2cd36438ee 100644 (file)
@@ -799,6 +799,12 @@ struct btrfs_root {
        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;
 };
 
 /*
index 0a5350573f61a26da93dc0835ffdee364cee1942..8d7866b733d63105f32c44df3cb922f54b9eef6f 100644 (file)
@@ -877,6 +877,12 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        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;
 }
 
@@ -1083,6 +1089,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
        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);
@@ -1950,6 +1959,10 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *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)
index e163b1b747079c7ce24fd1d800c7aa98c612f766..7ef79ce86e2514d5b4c496c9cff1628911edfa07 100644 (file)
@@ -2212,7 +2212,12 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        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;
        }
 
@@ -4410,7 +4415,6 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry,
        if (error)
                return error;
 
-       atomic_inc(&inode->i_count);
        d_instantiate(dentry, inode);
        return 0;
 }
@@ -4548,6 +4552,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
 {
        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;
@@ -4565,6 +4570,11 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
        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;
@@ -4920,6 +4930,7 @@ static int btrfs_permission(struct inode *inode, int mask)
 }
 
 static struct inode_operations btrfs_dir_inode_operations = {
+       .getattr        = btrfs_getattr,
        .lookup         = btrfs_lookup,
        .create         = btrfs_create,
        .unlink         = btrfs_unlink,
index ec45b30861369083c7b52b20973e611b41be09d4..773db07b5f726a81d099897927ca8b5155940591 100644 (file)
@@ -127,7 +127,6 @@ static noinline int create_subvol(struct btrfs_root *root,
        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)
@@ -175,7 +174,6 @@ fail:
                ret = err;
 fail_commit:
        btrfs_btree_balance_dirty(root, nr);
-printk("all done ret %d\n", ret);
        return ret;
 }
 
index eec8b24650396ccb09bfedc7db707136da2203d6..93f23a456a361ca0370aa1c44c68c3cfa6686f90 100644 (file)
@@ -832,13 +832,13 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
        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,