Loading fs/btrfs/TODO +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ * Check compat and incompat flags on the inode * Add virtual filesystems, mountable snapshots * Get rid of struct ctree_path, limiting tree levels held at one time * EEXIST for dirs instead of hash overflow * Release * Do real tree locking * Add extent mirroring (backup copies of blocks) Loading fs/btrfs/disk-io.c +24 −14 Original line number Diff line number Diff line Loading @@ -301,6 +301,12 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, int ret = 0; printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags); root = radix_tree_lookup(&fs_info->fs_roots_radix, (unsigned long)location->objectid); if (root) { printk("found %p in cache\n", root); return root; } root = kmalloc(sizeof(*root), GFP_NOFS); if (!root) { printk("failed1\n"); Loading Loading @@ -349,7 +355,8 @@ printk("internal search_slot gives us %d\n", ret); insert: printk("inserting %p\n", root); root->ref_cows = 1; ret = radix_tree_insert(&fs_info->fs_roots_radix, (unsigned long)root, ret = radix_tree_insert(&fs_info->fs_roots_radix, (unsigned long)root->root_key.objectid, root); if (ret) { printk("radix_tree_insert gives us %d\n", ret); Loading Loading @@ -460,6 +467,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root return 0; } static int 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->inode) iput(root->inode); if (root->node) brelse(root->node); if (root->commit_root) brelse(root->commit_root); kfree(root); return 0; } int del_fs_roots(struct btrfs_fs_info *fs_info) { int ret; Loading @@ -472,19 +493,8 @@ int del_fs_roots(struct btrfs_fs_info *fs_info) ARRAY_SIZE(gang)); if (!ret) break; for (i = 0; i < ret; i++) { radix_tree_delete(&fs_info->fs_roots_radix, (unsigned long)gang[i]); if (gang[i]->inode) iput(gang[i]->inode); else printk("no inode for root %p\n", gang[i]); if (gang[i]->node) brelse(gang[i]->node); if (gang[i]->commit_root) brelse(gang[i]->commit_root); kfree(gang[i]); } for (i = 0; i < ret; i++) free_fs_root(fs_info, gang[i]); } return 0; } Loading fs/btrfs/super.c +152 −26 Original line number Diff line number Diff line Loading @@ -495,10 +495,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(-EACCES); if (inode->i_state & I_NEW) { if (sub_root != root) { ret = radix_tree_insert( &root->fs_info->fs_roots_radix, (unsigned long)sub_root, sub_root); printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root); igrab(inode); sub_root->inode = inode; Loading Loading @@ -723,22 +719,19 @@ static int btrfs_write_inode(struct inode *inode, int wait) } static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, struct inode *dir, int mode) struct btrfs_root *root, u64 objectid, int mode) { struct inode *inode; struct btrfs_inode_item inode_item; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_key *location; int ret; u64 objectid; inode = new_inode(dir->i_sb); inode = new_inode(root->fs_info->sb); if (!inode) return ERR_PTR(-ENOMEM); BTRFS_I(inode)->root = BTRFS_I(dir)->root; ret = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); BUG_ON(ret); BTRFS_I(inode)->root = root; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; Loading Loading @@ -804,10 +797,18 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, struct inode *inode; int err; int drop_inode = 0; u64 objectid; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); inode = btrfs_new_inode(trans, dir, mode); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); if (err) { err = -ENOSPC; goto out_unlock; } inode = btrfs_new_inode(trans, root, objectid, mode); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_unlock; Loading @@ -833,9 +834,9 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, } static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) struct btrfs_root *root, u64 objectid, u64 dirid) { struct btrfs_root *root = BTRFS_I(dir)->root; int ret; char buf[2]; struct btrfs_key key; Loading @@ -843,22 +844,20 @@ static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, buf[0] = '.'; buf[1] = '.'; key.objectid = inode->i_ino; key.objectid = objectid; key.offset = 0; key.flags = 0; btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); ret = btrfs_insert_dir_item(trans, root, buf, 1, inode->i_ino, ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid, &key, 1); if (ret) goto error; key.objectid = dir->i_ino; ret = btrfs_insert_dir_item(trans, root, buf, 2, inode->i_ino, key.objectid = dirid; ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid, &key, 1); if (ret) goto error; inode->i_size = 6; ret = btrfs_update_inode(trans, root, inode); error: return ret; } Loading @@ -870,6 +869,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) struct btrfs_root *root = BTRFS_I(dir)->root; int err = 0; int drop_on_err = 0; u64 objectid; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); Loading @@ -877,7 +877,14 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) err = PTR_ERR(trans); goto out_unlock; } inode = btrfs_new_inode(trans, dir, S_IFDIR | mode); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); if (err) { err = -ENOSPC; goto out_unlock; } inode = btrfs_new_inode(trans, root, objectid, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_fail; Loading @@ -886,7 +893,12 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; err = btrfs_make_empty_dir(trans, inode, dir); err = btrfs_make_empty_dir(trans, root, inode->i_ino, dir->i_ino); if (err) goto out_fail; inode->i_size = 6; err = btrfs_update_inode(trans, root, inode); if (err) goto out_fail; err = btrfs_add_link(trans, dentry, inode); Loading Loading @@ -1666,6 +1678,102 @@ static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, return retval; } static int create_subvol(struct btrfs_root *root, char *name, int namelen) { struct btrfs_trans_handle *trans; struct btrfs_key key; struct btrfs_root_item root_item; struct btrfs_inode_item *inode_item; struct buffer_head *subvol; struct btrfs_leaf *leaf; struct btrfs_root *new_root; struct inode *inode; int ret; u64 objectid; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); subvol = btrfs_alloc_free_block(trans, root); leaf = btrfs_buffer_leaf(subvol); btrfs_set_header_nritems(&leaf->header, 0); btrfs_set_header_level(&leaf->header, 0); btrfs_set_header_blocknr(&leaf->header, subvol->b_blocknr); btrfs_set_header_generation(&leaf->header, trans->transid); memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, sizeof(leaf->header.fsid)); inode_item = &root_item.inode; memset(inode_item, 0, sizeof(*inode_item)); btrfs_set_inode_generation(inode_item, 1); btrfs_set_inode_size(inode_item, 3); btrfs_set_inode_nlink(inode_item, 1); btrfs_set_inode_nblocks(inode_item, 1); btrfs_set_inode_mode(inode_item, S_IFDIR | 0755); btrfs_set_root_blocknr(&root_item, subvol->b_blocknr); btrfs_set_root_refs(&root_item, 1); mark_buffer_dirty(subvol); brelse(subvol); subvol = NULL; ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root, 0, &objectid); BUG_ON(ret); btrfs_set_root_dirid(&root_item, new_dirid); key.objectid = objectid; key.offset = 1; key.flags = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, &root_item); BUG_ON(ret); /* * insert the directory item */ key.offset = (u64)-1; ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, name, namelen, root->fs_info->sb->s_root->d_inode->i_ino, &key, 0); BUG_ON(ret); ret = btrfs_commit_transaction(trans, root); BUG_ON(ret); new_root = btrfs_read_fs_root(root->fs_info, &key); BUG_ON(!new_root); trans = btrfs_start_transaction(new_root, 1); BUG_ON(!trans); inode = btrfs_new_inode(trans, new_root, new_dirid, S_IFDIR | 0700); inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; ret = btrfs_make_empty_dir(trans, new_root, new_dirid, new_dirid); BUG_ON(ret); inode->i_nlink = 1; inode->i_size = 6; ret = btrfs_update_inode(trans, new_root, inode); BUG_ON(ret); ret = btrfs_commit_transaction(trans, new_root); BUG_ON(ret); iput(inode); mutex_unlock(&root->fs_info->fs_mutex); return 0; } static int create_snapshot(struct btrfs_root *root, char *name, int namelen) { struct btrfs_trans_handle *trans; Loading @@ -1674,6 +1782,9 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) int ret; u64 objectid; if (!root->ref_cows) return -EINVAL; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); Loading @@ -1685,7 +1796,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) 0, &objectid); BUG_ON(ret); memset(&new_root_item, 0, sizeof(new_root_item)); memcpy(&new_root_item, &root->root_item, sizeof(new_root_item)); Loading Loading @@ -1728,9 +1838,9 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int struct btrfs_ioctl_vol_args vol_args; int ret; int namelen; struct btrfs_path *path; u64 root_dirid; if (!root->ref_cows) return -EINVAL; switch (cmd) { case BTRFS_IOC_SNAP_CREATE: if (copy_from_user(&vol_args, Loading @@ -1740,6 +1850,22 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int namelen = strlen(vol_args.name); if (namelen > BTRFS_VOL_NAME_MAX) return -EINVAL; path = btrfs_alloc_path(); if (!path) return -ENOMEM; root_dirid = btrfs_root_dirid( &root->fs_info->tree_root->root_item); mutex_lock(&root->fs_info->fs_mutex); ret = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, path, root_dirid, vol_args.name, namelen, 0); mutex_unlock(&root->fs_info->fs_mutex); if (ret == 0) return -EEXIST; if (root == root->fs_info->tree_root) ret = create_subvol(root, vol_args.name, namelen); else ret = create_snapshot(root, vol_args.name, namelen); WARN_ON(ret); break; Loading fs/btrfs/transaction.c +5 −3 Original line number Diff line number Diff line Loading @@ -64,7 +64,8 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, if (root != root->fs_info->tree_root && root->last_trans < running_trans_id) { radix_tree_tag_set(&root->fs_info->fs_roots_radix, (unsigned long)root, BTRFS_ROOT_TRANS_TAG); (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); root->commit_root = root->node; get_bh(root->node); } Loading Loading @@ -171,7 +172,8 @@ int add_dirty_roots(struct btrfs_trans_handle *trans, break; for (i = 0; i < ret; i++) { root = gang[i]; radix_tree_tag_clear(radix, (unsigned long)root, radix_tree_tag_clear(radix, (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); if (root->commit_root == root->node) { WARN_ON(root->node->b_blocknr != Loading Loading
fs/btrfs/TODO +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ * Check compat and incompat flags on the inode * Add virtual filesystems, mountable snapshots * Get rid of struct ctree_path, limiting tree levels held at one time * EEXIST for dirs instead of hash overflow * Release * Do real tree locking * Add extent mirroring (backup copies of blocks) Loading
fs/btrfs/disk-io.c +24 −14 Original line number Diff line number Diff line Loading @@ -301,6 +301,12 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, int ret = 0; printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags); root = radix_tree_lookup(&fs_info->fs_roots_radix, (unsigned long)location->objectid); if (root) { printk("found %p in cache\n", root); return root; } root = kmalloc(sizeof(*root), GFP_NOFS); if (!root) { printk("failed1\n"); Loading Loading @@ -349,7 +355,8 @@ printk("internal search_slot gives us %d\n", ret); insert: printk("inserting %p\n", root); root->ref_cows = 1; ret = radix_tree_insert(&fs_info->fs_roots_radix, (unsigned long)root, ret = radix_tree_insert(&fs_info->fs_roots_radix, (unsigned long)root->root_key.objectid, root); if (ret) { printk("radix_tree_insert gives us %d\n", ret); Loading Loading @@ -460,6 +467,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root return 0; } static int 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->inode) iput(root->inode); if (root->node) brelse(root->node); if (root->commit_root) brelse(root->commit_root); kfree(root); return 0; } int del_fs_roots(struct btrfs_fs_info *fs_info) { int ret; Loading @@ -472,19 +493,8 @@ int del_fs_roots(struct btrfs_fs_info *fs_info) ARRAY_SIZE(gang)); if (!ret) break; for (i = 0; i < ret; i++) { radix_tree_delete(&fs_info->fs_roots_radix, (unsigned long)gang[i]); if (gang[i]->inode) iput(gang[i]->inode); else printk("no inode for root %p\n", gang[i]); if (gang[i]->node) brelse(gang[i]->node); if (gang[i]->commit_root) brelse(gang[i]->commit_root); kfree(gang[i]); } for (i = 0; i < ret; i++) free_fs_root(fs_info, gang[i]); } return 0; } Loading
fs/btrfs/super.c +152 −26 Original line number Diff line number Diff line Loading @@ -495,10 +495,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(-EACCES); if (inode->i_state & I_NEW) { if (sub_root != root) { ret = radix_tree_insert( &root->fs_info->fs_roots_radix, (unsigned long)sub_root, sub_root); printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root); igrab(inode); sub_root->inode = inode; Loading Loading @@ -723,22 +719,19 @@ static int btrfs_write_inode(struct inode *inode, int wait) } static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, struct inode *dir, int mode) struct btrfs_root *root, u64 objectid, int mode) { struct inode *inode; struct btrfs_inode_item inode_item; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_key *location; int ret; u64 objectid; inode = new_inode(dir->i_sb); inode = new_inode(root->fs_info->sb); if (!inode) return ERR_PTR(-ENOMEM); BTRFS_I(inode)->root = BTRFS_I(dir)->root; ret = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); BUG_ON(ret); BTRFS_I(inode)->root = root; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; Loading Loading @@ -804,10 +797,18 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, struct inode *inode; int err; int drop_inode = 0; u64 objectid; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); inode = btrfs_new_inode(trans, dir, mode); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); if (err) { err = -ENOSPC; goto out_unlock; } inode = btrfs_new_inode(trans, root, objectid, mode); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_unlock; Loading @@ -833,9 +834,9 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, } static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, struct inode *inode, struct inode *dir) struct btrfs_root *root, u64 objectid, u64 dirid) { struct btrfs_root *root = BTRFS_I(dir)->root; int ret; char buf[2]; struct btrfs_key key; Loading @@ -843,22 +844,20 @@ static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, buf[0] = '.'; buf[1] = '.'; key.objectid = inode->i_ino; key.objectid = objectid; key.offset = 0; key.flags = 0; btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); ret = btrfs_insert_dir_item(trans, root, buf, 1, inode->i_ino, ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid, &key, 1); if (ret) goto error; key.objectid = dir->i_ino; ret = btrfs_insert_dir_item(trans, root, buf, 2, inode->i_ino, key.objectid = dirid; ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid, &key, 1); if (ret) goto error; inode->i_size = 6; ret = btrfs_update_inode(trans, root, inode); error: return ret; } Loading @@ -870,6 +869,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) struct btrfs_root *root = BTRFS_I(dir)->root; int err = 0; int drop_on_err = 0; u64 objectid; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); Loading @@ -877,7 +877,14 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) err = PTR_ERR(trans); goto out_unlock; } inode = btrfs_new_inode(trans, dir, S_IFDIR | mode); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); if (err) { err = -ENOSPC; goto out_unlock; } inode = btrfs_new_inode(trans, root, objectid, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_fail; Loading @@ -886,7 +893,12 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; err = btrfs_make_empty_dir(trans, inode, dir); err = btrfs_make_empty_dir(trans, root, inode->i_ino, dir->i_ino); if (err) goto out_fail; inode->i_size = 6; err = btrfs_update_inode(trans, root, inode); if (err) goto out_fail; err = btrfs_add_link(trans, dentry, inode); Loading Loading @@ -1666,6 +1678,102 @@ static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, return retval; } static int create_subvol(struct btrfs_root *root, char *name, int namelen) { struct btrfs_trans_handle *trans; struct btrfs_key key; struct btrfs_root_item root_item; struct btrfs_inode_item *inode_item; struct buffer_head *subvol; struct btrfs_leaf *leaf; struct btrfs_root *new_root; struct inode *inode; int ret; u64 objectid; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); subvol = btrfs_alloc_free_block(trans, root); leaf = btrfs_buffer_leaf(subvol); btrfs_set_header_nritems(&leaf->header, 0); btrfs_set_header_level(&leaf->header, 0); btrfs_set_header_blocknr(&leaf->header, subvol->b_blocknr); btrfs_set_header_generation(&leaf->header, trans->transid); memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, sizeof(leaf->header.fsid)); inode_item = &root_item.inode; memset(inode_item, 0, sizeof(*inode_item)); btrfs_set_inode_generation(inode_item, 1); btrfs_set_inode_size(inode_item, 3); btrfs_set_inode_nlink(inode_item, 1); btrfs_set_inode_nblocks(inode_item, 1); btrfs_set_inode_mode(inode_item, S_IFDIR | 0755); btrfs_set_root_blocknr(&root_item, subvol->b_blocknr); btrfs_set_root_refs(&root_item, 1); mark_buffer_dirty(subvol); brelse(subvol); subvol = NULL; ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root, 0, &objectid); BUG_ON(ret); btrfs_set_root_dirid(&root_item, new_dirid); key.objectid = objectid; key.offset = 1; key.flags = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, &root_item); BUG_ON(ret); /* * insert the directory item */ key.offset = (u64)-1; ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, name, namelen, root->fs_info->sb->s_root->d_inode->i_ino, &key, 0); BUG_ON(ret); ret = btrfs_commit_transaction(trans, root); BUG_ON(ret); new_root = btrfs_read_fs_root(root->fs_info, &key); BUG_ON(!new_root); trans = btrfs_start_transaction(new_root, 1); BUG_ON(!trans); inode = btrfs_new_inode(trans, new_root, new_dirid, S_IFDIR | 0700); inode->i_op = &btrfs_dir_inode_operations; inode->i_fop = &btrfs_dir_file_operations; ret = btrfs_make_empty_dir(trans, new_root, new_dirid, new_dirid); BUG_ON(ret); inode->i_nlink = 1; inode->i_size = 6; ret = btrfs_update_inode(trans, new_root, inode); BUG_ON(ret); ret = btrfs_commit_transaction(trans, new_root); BUG_ON(ret); iput(inode); mutex_unlock(&root->fs_info->fs_mutex); return 0; } static int create_snapshot(struct btrfs_root *root, char *name, int namelen) { struct btrfs_trans_handle *trans; Loading @@ -1674,6 +1782,9 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) int ret; u64 objectid; if (!root->ref_cows) return -EINVAL; mutex_lock(&root->fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); Loading @@ -1685,7 +1796,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) 0, &objectid); BUG_ON(ret); memset(&new_root_item, 0, sizeof(new_root_item)); memcpy(&new_root_item, &root->root_item, sizeof(new_root_item)); Loading Loading @@ -1728,9 +1838,9 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int struct btrfs_ioctl_vol_args vol_args; int ret; int namelen; struct btrfs_path *path; u64 root_dirid; if (!root->ref_cows) return -EINVAL; switch (cmd) { case BTRFS_IOC_SNAP_CREATE: if (copy_from_user(&vol_args, Loading @@ -1740,6 +1850,22 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int namelen = strlen(vol_args.name); if (namelen > BTRFS_VOL_NAME_MAX) return -EINVAL; path = btrfs_alloc_path(); if (!path) return -ENOMEM; root_dirid = btrfs_root_dirid( &root->fs_info->tree_root->root_item); mutex_lock(&root->fs_info->fs_mutex); ret = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, path, root_dirid, vol_args.name, namelen, 0); mutex_unlock(&root->fs_info->fs_mutex); if (ret == 0) return -EEXIST; if (root == root->fs_info->tree_root) ret = create_subvol(root, vol_args.name, namelen); else ret = create_snapshot(root, vol_args.name, namelen); WARN_ON(ret); break; Loading
fs/btrfs/transaction.c +5 −3 Original line number Diff line number Diff line Loading @@ -64,7 +64,8 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, if (root != root->fs_info->tree_root && root->last_trans < running_trans_id) { radix_tree_tag_set(&root->fs_info->fs_roots_radix, (unsigned long)root, BTRFS_ROOT_TRANS_TAG); (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); root->commit_root = root->node; get_bh(root->node); } Loading Loading @@ -171,7 +172,8 @@ int add_dirty_roots(struct btrfs_trans_handle *trans, break; for (i = 0; i < ret; i++) { root = gang[i]; radix_tree_tag_clear(radix, (unsigned long)root, radix_tree_tag_clear(radix, (unsigned long)root->root_key.objectid, BTRFS_ROOT_TRANS_TAG); if (root->commit_root == root->node) { WARN_ON(root->node->b_blocknr != Loading