Btrfs: Give each subvol and snapshot their own anonymous devid
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>
This commit is contained in:
parent
3de4586c52
commit
3394e1607e
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue