Commit 7ed641be authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull btrfs fixes from Chris Mason:
 "Filipe is doing a careful pass through fsync problems, and these are
  the fixes so far.  I'll have one more for rc6 that we're still
  testing.

  My big commit is fixing up some inode hash races that Al Viro found
  (thanks Al)"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: use insert_inode_locked4 for inode creation
  Btrfs: fix fsync data loss after a ranged fsync
  Btrfs: kfree()ing ERR_PTRs
  Btrfs: fix crash while doing a ranged fsync
  Btrfs: fix corruption after write/fsync failure + fsync + log recovery
  Btrfs: fix autodefrag with compression
parents 9925cc13 b0d5d10f
...@@ -1966,7 +1966,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -1966,7 +1966,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
btrfs_init_log_ctx(&ctx); btrfs_init_log_ctx(&ctx);
ret = btrfs_log_dentry_safe(trans, root, dentry, &ctx); ret = btrfs_log_dentry_safe(trans, root, dentry, start, end, &ctx);
if (ret < 0) { if (ret < 0) {
/* Fallthrough and commit/free transaction. */ /* Fallthrough and commit/free transaction. */
ret = 1; ret = 1;
......
...@@ -778,8 +778,12 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -778,8 +778,12 @@ static noinline int submit_compressed_extents(struct inode *inode,
ins.offset, ins.offset,
BTRFS_ORDERED_COMPRESSED, BTRFS_ORDERED_COMPRESSED,
async_extent->compress_type); async_extent->compress_type);
if (ret) if (ret) {
btrfs_drop_extent_cache(inode, async_extent->start,
async_extent->start +
async_extent->ram_size - 1, 0);
goto out_free_reserve; goto out_free_reserve;
}
/* /*
* clear dirty, set writeback and unlock the pages. * clear dirty, set writeback and unlock the pages.
...@@ -971,14 +975,14 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -971,14 +975,14 @@ static noinline int cow_file_range(struct inode *inode,
ret = btrfs_add_ordered_extent(inode, start, ins.objectid, ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
ram_size, cur_alloc_size, 0); ram_size, cur_alloc_size, 0);
if (ret) if (ret)
goto out_reserve; goto out_drop_extent_cache;
if (root->root_key.objectid == if (root->root_key.objectid ==
BTRFS_DATA_RELOC_TREE_OBJECTID) { BTRFS_DATA_RELOC_TREE_OBJECTID) {
ret = btrfs_reloc_clone_csums(inode, start, ret = btrfs_reloc_clone_csums(inode, start,
cur_alloc_size); cur_alloc_size);
if (ret) if (ret)
goto out_reserve; goto out_drop_extent_cache;
} }
if (disk_num_bytes < cur_alloc_size) if (disk_num_bytes < cur_alloc_size)
...@@ -1006,6 +1010,8 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -1006,6 +1010,8 @@ static noinline int cow_file_range(struct inode *inode,
out: out:
return ret; return ret;
out_drop_extent_cache:
btrfs_drop_extent_cache(inode, start, start + ram_size - 1, 0);
out_reserve: out_reserve:
btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1);
out_unlock: out_unlock:
...@@ -4242,7 +4248,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -4242,7 +4248,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
} }
error: error:
if (last_size != (u64)-1) if (last_size != (u64)-1 &&
root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
btrfs_ordered_update_i_size(inode, last_size, NULL); btrfs_ordered_update_i_size(inode, last_size, NULL);
btrfs_free_path(path); btrfs_free_path(path);
return err; return err;
...@@ -5627,6 +5634,17 @@ int btrfs_set_inode_index(struct inode *dir, u64 *index) ...@@ -5627,6 +5634,17 @@ int btrfs_set_inode_index(struct inode *dir, u64 *index)
return ret; return ret;
} }
static int btrfs_insert_inode_locked(struct inode *inode)
{
struct btrfs_iget_args args;
args.location = &BTRFS_I(inode)->location;
args.root = BTRFS_I(inode)->root;
return insert_inode_locked4(inode,
btrfs_inode_hash(inode->i_ino, BTRFS_I(inode)->root),
btrfs_find_actor, &args);
}
static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *dir, struct inode *dir,
...@@ -5719,10 +5737,19 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5719,10 +5737,19 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
sizes[1] = name_len + sizeof(*ref); sizes[1] = name_len + sizeof(*ref);
} }
location = &BTRFS_I(inode)->location;
location->objectid = objectid;
location->offset = 0;
btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
ret = btrfs_insert_inode_locked(inode);
if (ret < 0)
goto fail;
path->leave_spinning = 1; path->leave_spinning = 1;
ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems); ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems);
if (ret != 0) if (ret != 0)
goto fail; goto fail_unlock;
inode_init_owner(inode, dir, mode); inode_init_owner(inode, dir, mode);
inode_set_bytes(inode, 0); inode_set_bytes(inode, 0);
...@@ -5745,11 +5772,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5745,11 +5772,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path); btrfs_free_path(path);
location = &BTRFS_I(inode)->location;
location->objectid = objectid;
location->offset = 0;
btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
btrfs_inherit_iflags(inode, dir); btrfs_inherit_iflags(inode, dir);
if (S_ISREG(mode)) { if (S_ISREG(mode)) {
...@@ -5760,7 +5782,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5760,7 +5782,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
BTRFS_INODE_NODATASUM; BTRFS_INODE_NODATASUM;
} }
btrfs_insert_inode_hash(inode);
inode_tree_add(inode); inode_tree_add(inode);
trace_btrfs_inode_new(inode); trace_btrfs_inode_new(inode);
...@@ -5775,6 +5796,9 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5775,6 +5796,9 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
btrfs_ino(inode), root->root_key.objectid, ret); btrfs_ino(inode), root->root_key.objectid, ret);
return inode; return inode;
fail_unlock:
unlock_new_inode(inode);
fail: fail:
if (dir && name) if (dir && name)
BTRFS_I(dir)->index_cnt--; BTRFS_I(dir)->index_cnt--;
...@@ -5909,28 +5933,28 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -5909,28 +5933,28 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
goto out_unlock; goto out_unlock;
} }
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) {
drop_inode = 1;
goto out_unlock;
}
/* /*
* If the active LSM wants to access the inode during * If the active LSM wants to access the inode during
* d_instantiate it needs these. Smack checks to see * d_instantiate it needs these. Smack checks to see
* if the filesystem supports xattrs by looking at the * if the filesystem supports xattrs by looking at the
* ops vector. * ops vector.
*/ */
inode->i_op = &btrfs_special_inode_operations; inode->i_op = &btrfs_special_inode_operations;
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); init_special_inode(inode, inode->i_mode, rdev);
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) if (err)
drop_inode = 1; goto out_unlock_inode;
else {
init_special_inode(inode, inode->i_mode, rdev); err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err) {
goto out_unlock_inode;
} else {
btrfs_update_inode(trans, root, inode); btrfs_update_inode(trans, root, inode);
unlock_new_inode(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
} }
out_unlock: out_unlock:
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
btrfs_balance_delayed_items(root); btrfs_balance_delayed_items(root);
...@@ -5940,6 +5964,12 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -5940,6 +5964,12 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
iput(inode); iput(inode);
} }
return err; return err;
out_unlock_inode:
drop_inode = 1;
unlock_new_inode(inode);
goto out_unlock;
} }
static int btrfs_create(struct inode *dir, struct dentry *dentry, static int btrfs_create(struct inode *dir, struct dentry *dentry,
...@@ -5974,15 +6004,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, ...@@ -5974,15 +6004,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
goto out_unlock; goto out_unlock;
} }
drop_inode_on_err = 1; drop_inode_on_err = 1;
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err)
goto out_unlock;
err = btrfs_update_inode(trans, root, inode);
if (err)
goto out_unlock;
/* /*
* If the active LSM wants to access the inode during * If the active LSM wants to access the inode during
* d_instantiate it needs these. Smack checks to see * d_instantiate it needs these. Smack checks to see
...@@ -5991,14 +6012,23 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, ...@@ -5991,14 +6012,23 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
*/ */
inode->i_fop = &btrfs_file_operations; inode->i_fop = &btrfs_file_operations;
inode->i_op = &btrfs_file_inode_operations; inode->i_op = &btrfs_file_inode_operations;
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err)
goto out_unlock_inode;
err = btrfs_update_inode(trans, root, inode);
if (err)
goto out_unlock_inode;
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err) if (err)
goto out_unlock; goto out_unlock_inode;
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
unlock_new_inode(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
out_unlock: out_unlock:
...@@ -6010,6 +6040,11 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, ...@@ -6010,6 +6040,11 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
btrfs_balance_delayed_items(root); btrfs_balance_delayed_items(root);
btrfs_btree_balance_dirty(root); btrfs_btree_balance_dirty(root);
return err; return err;
out_unlock_inode:
unlock_new_inode(inode);
goto out_unlock;
} }
static int btrfs_link(struct dentry *old_dentry, struct inode *dir, static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
...@@ -6117,25 +6152,30 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -6117,25 +6152,30 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
} }
drop_on_err = 1; drop_on_err = 1;
/* these must be set before we unlock the inode */
inode->i_op = &btrfs_dir_inode_operations;
inode->i_fop = &btrfs_dir_file_operations;
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name); err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) if (err)
goto out_fail; goto out_fail_inode;
inode->i_op = &btrfs_dir_inode_operations;
inode->i_fop = &btrfs_dir_file_operations;
btrfs_i_size_write(inode, 0); btrfs_i_size_write(inode, 0);
err = btrfs_update_inode(trans, root, inode); err = btrfs_update_inode(trans, root, inode);
if (err) if (err)
goto out_fail; goto out_fail_inode;
err = btrfs_add_link(trans, dir, inode, dentry->d_name.name, err = btrfs_add_link(trans, dir, inode, dentry->d_name.name,
dentry->d_name.len, 0, index); dentry->d_name.len, 0, index);
if (err) if (err)
goto out_fail; goto out_fail_inode;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
/*
* mkdir is special. We're unlocking after we call d_instantiate
* to avoid a race with nfsd calling d_instantiate.
*/
unlock_new_inode(inode);
drop_on_err = 0; drop_on_err = 0;
out_fail: out_fail:
...@@ -6145,6 +6185,10 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -6145,6 +6185,10 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
btrfs_balance_delayed_items(root); btrfs_balance_delayed_items(root);
btrfs_btree_balance_dirty(root); btrfs_btree_balance_dirty(root);
return err; return err;
out_fail_inode:
unlock_new_inode(inode);
goto out_fail;
} }
/* helper for btfs_get_extent. Given an existing extent in the tree, /* helper for btfs_get_extent. Given an existing extent in the tree,
...@@ -8100,6 +8144,7 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, ...@@ -8100,6 +8144,7 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
set_nlink(inode, 1); set_nlink(inode, 1);
btrfs_i_size_write(inode, 0); btrfs_i_size_write(inode, 0);
unlock_new_inode(inode);
err = btrfs_subvol_inherit_props(trans, new_root, parent_root); err = btrfs_subvol_inherit_props(trans, new_root, parent_root);
if (err) if (err)
...@@ -8760,12 +8805,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -8760,12 +8805,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
goto out_unlock; goto out_unlock;
} }
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err) {
drop_inode = 1;
goto out_unlock;
}
/* /*
* If the active LSM wants to access the inode during * If the active LSM wants to access the inode during
* d_instantiate it needs these. Smack checks to see * d_instantiate it needs these. Smack checks to see
...@@ -8774,23 +8813,22 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -8774,23 +8813,22 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
*/ */
inode->i_fop = &btrfs_file_operations; inode->i_fop = &btrfs_file_operations;
inode->i_op = &btrfs_file_inode_operations; inode->i_op = &btrfs_file_inode_operations;
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
if (err)
goto out_unlock_inode;
err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
if (err) if (err)
drop_inode = 1; goto out_unlock_inode;
else {
inode->i_mapping->a_ops = &btrfs_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
}
if (drop_inode)
goto out_unlock;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) { if (!path) {
err = -ENOMEM; err = -ENOMEM;
drop_inode = 1; goto out_unlock_inode;
goto out_unlock;
} }
key.objectid = btrfs_ino(inode); key.objectid = btrfs_ino(inode);
key.offset = 0; key.offset = 0;
...@@ -8799,9 +8837,8 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -8799,9 +8837,8 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
err = btrfs_insert_empty_item(trans, root, path, &key, err = btrfs_insert_empty_item(trans, root, path, &key,
datasize); datasize);
if (err) { if (err) {
drop_inode = 1;
btrfs_free_path(path); btrfs_free_path(path);
goto out_unlock; goto out_unlock_inode;
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
ei = btrfs_item_ptr(leaf, path->slots[0], ei = btrfs_item_ptr(leaf, path->slots[0],
...@@ -8825,12 +8862,15 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -8825,12 +8862,15 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
inode_set_bytes(inode, name_len); inode_set_bytes(inode, name_len);
btrfs_i_size_write(inode, name_len); btrfs_i_size_write(inode, name_len);
err = btrfs_update_inode(trans, root, inode); err = btrfs_update_inode(trans, root, inode);
if (err) if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock_inode;
}
unlock_new_inode(inode);
d_instantiate(dentry, inode);
out_unlock: out_unlock:
if (!err)
d_instantiate(dentry, inode);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
if (drop_inode) { if (drop_inode) {
inode_dec_link_count(inode); inode_dec_link_count(inode);
...@@ -8838,6 +8878,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -8838,6 +8878,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
} }
btrfs_btree_balance_dirty(root); btrfs_btree_balance_dirty(root);
return err; return err;
out_unlock_inode:
drop_inode = 1;
unlock_new_inode(inode);
goto out_unlock;
} }
static int __btrfs_prealloc_file_range(struct inode *inode, int mode, static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
...@@ -9021,14 +9066,6 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -9021,14 +9066,6 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
goto out; goto out;
} }
ret = btrfs_init_inode_security(trans, inode, dir, NULL);
if (ret)
goto out;
ret = btrfs_update_inode(trans, root, inode);
if (ret)
goto out;
inode->i_fop = &btrfs_file_operations; inode->i_fop = &btrfs_file_operations;
inode->i_op = &btrfs_file_inode_operations; inode->i_op = &btrfs_file_inode_operations;
...@@ -9036,9 +9073,16 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -9036,9 +9073,16 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
inode->i_mapping->backing_dev_info = &root->fs_info->bdi; inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
ret = btrfs_init_inode_security(trans, inode, dir, NULL);
if (ret)
goto out_inode;
ret = btrfs_update_inode(trans, root, inode);
if (ret)
goto out_inode;
ret = btrfs_orphan_add(trans, inode); ret = btrfs_orphan_add(trans, inode);
if (ret) if (ret)
goto out; goto out_inode;
/* /*
* We set number of links to 0 in btrfs_new_inode(), and here we set * We set number of links to 0 in btrfs_new_inode(), and here we set
...@@ -9048,6 +9092,7 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -9048,6 +9092,7 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
* d_tmpfile() -> inode_dec_link_count() -> drop_nlink() * d_tmpfile() -> inode_dec_link_count() -> drop_nlink()
*/ */
set_nlink(inode, 1); set_nlink(inode, 1);
unlock_new_inode(inode);
d_tmpfile(dentry, inode); d_tmpfile(dentry, inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -9057,8 +9102,12 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -9057,8 +9102,12 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
iput(inode); iput(inode);
btrfs_balance_delayed_items(root); btrfs_balance_delayed_items(root);
btrfs_btree_balance_dirty(root); btrfs_btree_balance_dirty(root);
return ret; return ret;
out_inode:
unlock_new_inode(inode);
goto out;
} }
static const struct inode_operations btrfs_dir_inode_operations = { static const struct inode_operations btrfs_dir_inode_operations = {
......
...@@ -1019,8 +1019,10 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) ...@@ -1019,8 +1019,10 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em)
return false; return false;
next = defrag_lookup_extent(inode, em->start + em->len); next = defrag_lookup_extent(inode, em->start + em->len);
if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE || if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE)
(em->block_start + em->block_len == next->block_start)) ret = false;
else if ((em->block_start + em->block_len == next->block_start) &&
(em->block_len > 128 * 1024 && next->block_len > 128 * 1024))
ret = false; ret = false;
free_extent_map(next); free_extent_map(next);
...@@ -1055,7 +1057,6 @@ static int should_defrag_range(struct inode *inode, u64 start, int thresh, ...@@ -1055,7 +1057,6 @@ static int should_defrag_range(struct inode *inode, u64 start, int thresh,
} }
next_mergeable = defrag_check_next_extent(inode, em); next_mergeable = defrag_check_next_extent(inode, em);
/* /*
* we hit a real extent, if it is big or the next extent is not a * we hit a real extent, if it is big or the next extent is not a
* real extent, don't bother defragging it * real extent, don't bother defragging it
...@@ -1702,7 +1703,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, ...@@ -1702,7 +1703,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY |
BTRFS_SUBVOL_QGROUP_INHERIT)) { BTRFS_SUBVOL_QGROUP_INHERIT)) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out; goto free_args;
} }
if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC)
...@@ -1712,27 +1713,31 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, ...@@ -1712,27 +1713,31 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) { if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
if (vol_args->size > PAGE_CACHE_SIZE) { if (vol_args->size > PAGE_CACHE_SIZE) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto free_args;
} }
inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size); inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size);
if (IS_ERR(inherit)) { if (IS_ERR(inherit)) {
ret = PTR_ERR(inherit); ret = PTR_ERR(inherit);
goto out; goto free_args;
} }
} }
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,
vol_args->fd, subvol, ptr, vol_args->fd, subvol, ptr,
readonly, inherit); readonly, inherit);
if (ret)
goto free_inherit;
if (ret == 0 && ptr && if (ptr && copy_to_user(arg +
copy_to_user(arg + offsetof(struct btrfs_ioctl_vol_args_v2,
offsetof(struct btrfs_ioctl_vol_args_v2, transid),
transid), ptr, sizeof(*ptr))) ptr, sizeof(*ptr)))
ret = -EFAULT; ret = -EFAULT;
out:
kfree(vol_args); free_inherit:
kfree(inherit); kfree(inherit);
free_args:
kfree(vol_args);
return ret; return ret;
} }
...@@ -2652,7 +2657,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) ...@@ -2652,7 +2657,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
vol_args = memdup_user(arg, sizeof(*vol_args)); vol_args = memdup_user(arg, sizeof(*vol_args));
if (IS_ERR(vol_args)) { if (IS_ERR(vol_args)) {
ret = PTR_ERR(vol_args); ret = PTR_ERR(vol_args);
goto out; goto err_drop;
} }
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
...@@ -2670,6 +2675,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) ...@@ -2670,6 +2675,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
out: out:
kfree(vol_args); kfree(vol_args);
err_drop:
mnt_drop_write_file(file); mnt_drop_write_file(file);
return ret; return ret;
} }
......
...@@ -94,8 +94,10 @@ ...@@ -94,8 +94,10 @@
#define LOG_WALK_REPLAY_ALL 3 #define LOG_WALK_REPLAY_ALL 3
static int btrfs_log_inode(struct btrfs_trans_handle *trans, static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode, struct btrfs_root *root, struct inode *inode,
int inode_only); int inode_only,
const loff_t start,
const loff_t end);
static int link_to_fixup_dir(struct btrfs_trans_handle *trans, static int link_to_fixup_dir(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, u64 objectid); struct btrfs_path *path, u64 objectid);
...@@ -3858,8 +3860,10 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, ...@@ -3858,8 +3860,10 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
* This handles both files and directories. * This handles both files and directories.
*/ */
static int btrfs_log_inode(struct btrfs_trans_handle *trans, static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode, struct btrfs_root *root, struct inode *inode,
int inode_only) int inode_only,
const loff_t start,
const loff_t end)
{ {
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_path *dst_path; struct btrfs_path *dst_path;
...@@ -3876,6 +3880,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -3876,6 +3880,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
int ins_nr; int ins_nr;
bool fast_search = false; bool fast_search = false;
u64 ino = btrfs_ino(inode); u64 ino = btrfs_ino(inode);
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
...@@ -4049,13 +4054,35 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -4049,13 +4054,35 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
goto out_unlock; goto out_unlock;
} }
} else if (inode_only == LOG_INODE_ALL) { } else if (inode_only == LOG_INODE_ALL) {
struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
struct extent_map *em, *n; struct extent_map *em, *n;
write_lock(&tree->lock); write_lock(&em_tree->lock);
list_for_each_entry_safe(em, n, &tree->modified_extents, list) /*
list_del_init(&em->list); * We can't just remove every em if we're called for a ranged
write_unlock(&tree->lock); * fsync - that is, one that doesn't cover the whole possible
* file range (0 to LLONG_MAX). This is because we can have
* em's that fall outside the range we're logging and therefore
* their ordered operations haven't completed yet
* (btrfs_finish_ordered_io() not invoked yet). This means we
* didn't get their respective file extent item in the fs/subvol
* tree yet, and need to let the next fast fsync (one which
* consults the list of modified extent maps) find the em so
* that it logs a matching file extent item and waits for the
* respective ordered operation to complete (if it's still
* running).
*
* Removing every em outside the range we're logging would make
* the next fast fsync not log their matching file extent items,
* therefore making us lose data after a log replay.
*/
list_for_each_entry_safe(em, n, &em_tree->modified_extents,
list) {
const u64 mod_end = em->mod_start + em->mod_len - 1;
if (em->mod_start >= start && mod_end <= end)
list_del_init(&em->list);
}
write_unlock(&em_tree->lock);
} }
if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
...@@ -4065,8 +4092,19 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -4065,8 +4092,19 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
goto out_unlock; goto out_unlock;
} }
} }
BTRFS_I(inode)->logged_trans = trans->transid;
BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; write_lock(&em_tree->lock);
/*
* If we're doing a ranged fsync and there are still modified extents
* in the list, we must run on the next fsync call as it might cover
* those extents (a full fsync or an fsync for other range).
*/
if (list_empty(&em_tree->modified_extents)) {
BTRFS_I(inode)->logged_trans = trans->transid;
BTRFS_I(inode)->last_log_commit =
BTRFS_I(inode)->last_sub_trans;
}
write_unlock(&em_tree->lock);
out_unlock: out_unlock:
if (unlikely(err)) if (unlikely(err))
btrfs_put_logged_extents(&logged_list); btrfs_put_logged_extents(&logged_list);
...@@ -4161,7 +4199,10 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, ...@@ -4161,7 +4199,10 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
*/ */
static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode, struct btrfs_root *root, struct inode *inode,
struct dentry *parent, int exists_only, struct dentry *parent,
const loff_t start,
const loff_t end,
int exists_only,
struct btrfs_log_ctx *ctx) struct btrfs_log_ctx *ctx)
{ {
int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
...@@ -4207,7 +4248,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -4207,7 +4248,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
if (ret) if (ret)
goto end_no_trans; goto end_no_trans;
ret = btrfs_log_inode(trans, root, inode, inode_only); ret = btrfs_log_inode(trans, root, inode, inode_only, start, end);
if (ret) if (ret)
goto end_trans; goto end_trans;
...@@ -4235,7 +4276,8 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -4235,7 +4276,8 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
if (BTRFS_I(inode)->generation > if (BTRFS_I(inode)->generation >
root->fs_info->last_trans_committed) { root->fs_info->last_trans_committed) {
ret = btrfs_log_inode(trans, root, inode, inode_only); ret = btrfs_log_inode(trans, root, inode, inode_only,
0, LLONG_MAX);
if (ret) if (ret)
goto end_trans; goto end_trans;
} }
...@@ -4269,13 +4311,15 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, ...@@ -4269,13 +4311,15 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
*/ */
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry, struct btrfs_root *root, struct dentry *dentry,
const loff_t start,
const loff_t end,
struct btrfs_log_ctx *ctx) struct btrfs_log_ctx *ctx)
{ {
struct dentry *parent = dget_parent(dentry); struct dentry *parent = dget_parent(dentry);
int ret; int ret;
ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent,
0, ctx); start, end, 0, ctx);
dput(parent); dput(parent);
return ret; return ret;
...@@ -4512,6 +4556,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, ...@@ -4512,6 +4556,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
root->fs_info->last_trans_committed)) root->fs_info->last_trans_committed))
return 0; return 0;
return btrfs_log_inode_parent(trans, root, inode, parent, 1, NULL); return btrfs_log_inode_parent(trans, root, inode, parent, 0,
LLONG_MAX, 1, NULL);
} }
...@@ -59,6 +59,8 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -59,6 +59,8 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
int btrfs_recover_log_trees(struct btrfs_root *tree_root); int btrfs_recover_log_trees(struct btrfs_root *tree_root);
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry, struct btrfs_root *root, struct dentry *dentry,
const loff_t start,
const loff_t end,
struct btrfs_log_ctx *ctx); struct btrfs_log_ctx *ctx);
int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment