Merge tag 'for-4.19-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - fix for improper fsync after hardlink - fix for a corruption during file deduplication - use after free fixes - RCU warning fix - fix for buffered write to nodatacow file * tag 'for-4.19-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: Fix suspicious RCU usage warning in btrfs_debug_in_rcu btrfs: use after free in btrfs_quota_enable btrfs: btrfs_shrink_device should call commit transaction at the end btrfs: fix qgroup_free wrong num_bytes in btrfs_subvolume_reserve_metadata Btrfs: fix data corruption when deduplicating between different files Btrfs: sync log after logging new name Btrfs: fix unexpected failure of nocow buffered writes after snapshotting when low on space
This commit is contained in:
117
fs/btrfs/inode.c
117
fs/btrfs/inode.c
@@ -1271,7 +1271,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||
u64 disk_num_bytes;
|
||||
u64 ram_bytes;
|
||||
int extent_type;
|
||||
int ret, err;
|
||||
int ret;
|
||||
int type;
|
||||
int nocow;
|
||||
int check_prev = 1;
|
||||
@@ -1403,11 +1403,8 @@ next_slot:
|
||||
* if there are pending snapshots for this root,
|
||||
* we fall into common COW way.
|
||||
*/
|
||||
if (!nolock) {
|
||||
err = btrfs_start_write_no_snapshotting(root);
|
||||
if (!err)
|
||||
goto out_check;
|
||||
}
|
||||
if (!nolock && atomic_read(&root->snapshot_force_cow))
|
||||
goto out_check;
|
||||
/*
|
||||
* force cow if csum exists in the range.
|
||||
* this ensure that csum for a given extent are
|
||||
@@ -1416,9 +1413,6 @@ next_slot:
|
||||
ret = csum_exist_in_range(fs_info, disk_bytenr,
|
||||
num_bytes);
|
||||
if (ret) {
|
||||
if (!nolock)
|
||||
btrfs_end_write_no_snapshotting(root);
|
||||
|
||||
/*
|
||||
* ret could be -EIO if the above fails to read
|
||||
* metadata.
|
||||
@@ -1431,11 +1425,8 @@ next_slot:
|
||||
WARN_ON_ONCE(nolock);
|
||||
goto out_check;
|
||||
}
|
||||
if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
|
||||
if (!nolock)
|
||||
btrfs_end_write_no_snapshotting(root);
|
||||
if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr))
|
||||
goto out_check;
|
||||
}
|
||||
nocow = 1;
|
||||
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
|
||||
extent_end = found_key.offset +
|
||||
@@ -1448,8 +1439,6 @@ next_slot:
|
||||
out_check:
|
||||
if (extent_end <= start) {
|
||||
path->slots[0]++;
|
||||
if (!nolock && nocow)
|
||||
btrfs_end_write_no_snapshotting(root);
|
||||
if (nocow)
|
||||
btrfs_dec_nocow_writers(fs_info, disk_bytenr);
|
||||
goto next_slot;
|
||||
@@ -1471,8 +1460,6 @@ out_check:
|
||||
end, page_started, nr_written, 1,
|
||||
NULL);
|
||||
if (ret) {
|
||||
if (!nolock && nocow)
|
||||
btrfs_end_write_no_snapshotting(root);
|
||||
if (nocow)
|
||||
btrfs_dec_nocow_writers(fs_info,
|
||||
disk_bytenr);
|
||||
@@ -1492,8 +1479,6 @@ out_check:
|
||||
ram_bytes, BTRFS_COMPRESS_NONE,
|
||||
BTRFS_ORDERED_PREALLOC);
|
||||
if (IS_ERR(em)) {
|
||||
if (!nolock && nocow)
|
||||
btrfs_end_write_no_snapshotting(root);
|
||||
if (nocow)
|
||||
btrfs_dec_nocow_writers(fs_info,
|
||||
disk_bytenr);
|
||||
@@ -1532,8 +1517,6 @@ out_check:
|
||||
EXTENT_CLEAR_DATA_RESV,
|
||||
PAGE_UNLOCK | PAGE_SET_PRIVATE2);
|
||||
|
||||
if (!nolock && nocow)
|
||||
btrfs_end_write_no_snapshotting(root);
|
||||
cur_offset = extent_end;
|
||||
|
||||
/*
|
||||
@@ -6639,6 +6622,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
drop_inode = 1;
|
||||
} else {
|
||||
struct dentry *parent = dentry->d_parent;
|
||||
int ret;
|
||||
|
||||
err = btrfs_update_inode(trans, root, inode);
|
||||
if (err)
|
||||
goto fail;
|
||||
@@ -6652,7 +6637,12 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
goto fail;
|
||||
}
|
||||
d_instantiate(dentry, inode);
|
||||
btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent);
|
||||
ret = btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent,
|
||||
true, NULL);
|
||||
if (ret == BTRFS_NEED_TRANS_COMMIT) {
|
||||
err = btrfs_commit_transaction(trans);
|
||||
trans = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
@@ -9388,14 +9378,21 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
||||
u64 new_idx = 0;
|
||||
u64 root_objectid;
|
||||
int ret;
|
||||
int ret2;
|
||||
bool root_log_pinned = false;
|
||||
bool dest_log_pinned = false;
|
||||
struct btrfs_log_ctx ctx_root;
|
||||
struct btrfs_log_ctx ctx_dest;
|
||||
bool sync_log_root = false;
|
||||
bool sync_log_dest = false;
|
||||
bool commit_transaction = false;
|
||||
|
||||
/* we only allow rename subvolume link between subvolumes */
|
||||
if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
|
||||
return -EXDEV;
|
||||
|
||||
btrfs_init_log_ctx(&ctx_root, old_inode);
|
||||
btrfs_init_log_ctx(&ctx_dest, new_inode);
|
||||
|
||||
/* close the race window with snapshot create/destroy ioctl */
|
||||
if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
down_read(&fs_info->subvol_sem);
|
||||
@@ -9542,15 +9539,29 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
||||
|
||||
if (root_log_pinned) {
|
||||
parent = new_dentry->d_parent;
|
||||
btrfs_log_new_name(trans, BTRFS_I(old_inode), BTRFS_I(old_dir),
|
||||
parent);
|
||||
ret = btrfs_log_new_name(trans, BTRFS_I(old_inode),
|
||||
BTRFS_I(old_dir), parent,
|
||||
false, &ctx_root);
|
||||
if (ret == BTRFS_NEED_LOG_SYNC)
|
||||
sync_log_root = true;
|
||||
else if (ret == BTRFS_NEED_TRANS_COMMIT)
|
||||
commit_transaction = true;
|
||||
ret = 0;
|
||||
btrfs_end_log_trans(root);
|
||||
root_log_pinned = false;
|
||||
}
|
||||
if (dest_log_pinned) {
|
||||
parent = old_dentry->d_parent;
|
||||
btrfs_log_new_name(trans, BTRFS_I(new_inode), BTRFS_I(new_dir),
|
||||
parent);
|
||||
if (!commit_transaction) {
|
||||
parent = old_dentry->d_parent;
|
||||
ret = btrfs_log_new_name(trans, BTRFS_I(new_inode),
|
||||
BTRFS_I(new_dir), parent,
|
||||
false, &ctx_dest);
|
||||
if (ret == BTRFS_NEED_LOG_SYNC)
|
||||
sync_log_dest = true;
|
||||
else if (ret == BTRFS_NEED_TRANS_COMMIT)
|
||||
commit_transaction = true;
|
||||
ret = 0;
|
||||
}
|
||||
btrfs_end_log_trans(dest);
|
||||
dest_log_pinned = false;
|
||||
}
|
||||
@@ -9583,8 +9594,26 @@ out_fail:
|
||||
dest_log_pinned = false;
|
||||
}
|
||||
}
|
||||
ret2 = btrfs_end_transaction(trans);
|
||||
ret = ret ? ret : ret2;
|
||||
if (!ret && sync_log_root && !commit_transaction) {
|
||||
ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root,
|
||||
&ctx_root);
|
||||
if (ret)
|
||||
commit_transaction = true;
|
||||
}
|
||||
if (!ret && sync_log_dest && !commit_transaction) {
|
||||
ret = btrfs_sync_log(trans, BTRFS_I(new_inode)->root,
|
||||
&ctx_dest);
|
||||
if (ret)
|
||||
commit_transaction = true;
|
||||
}
|
||||
if (commit_transaction) {
|
||||
ret = btrfs_commit_transaction(trans);
|
||||
} else {
|
||||
int ret2;
|
||||
|
||||
ret2 = btrfs_end_transaction(trans);
|
||||
ret = ret ? ret : ret2;
|
||||
}
|
||||
out_notrans:
|
||||
if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
up_read(&fs_info->subvol_sem);
|
||||
@@ -9661,6 +9690,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
int ret;
|
||||
u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
|
||||
bool log_pinned = false;
|
||||
struct btrfs_log_ctx ctx;
|
||||
bool sync_log = false;
|
||||
bool commit_transaction = false;
|
||||
|
||||
if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
|
||||
return -EPERM;
|
||||
@@ -9818,8 +9850,15 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
if (log_pinned) {
|
||||
struct dentry *parent = new_dentry->d_parent;
|
||||
|
||||
btrfs_log_new_name(trans, BTRFS_I(old_inode), BTRFS_I(old_dir),
|
||||
parent);
|
||||
btrfs_init_log_ctx(&ctx, old_inode);
|
||||
ret = btrfs_log_new_name(trans, BTRFS_I(old_inode),
|
||||
BTRFS_I(old_dir), parent,
|
||||
false, &ctx);
|
||||
if (ret == BTRFS_NEED_LOG_SYNC)
|
||||
sync_log = true;
|
||||
else if (ret == BTRFS_NEED_TRANS_COMMIT)
|
||||
commit_transaction = true;
|
||||
ret = 0;
|
||||
btrfs_end_log_trans(root);
|
||||
log_pinned = false;
|
||||
}
|
||||
@@ -9856,7 +9895,19 @@ out_fail:
|
||||
btrfs_end_log_trans(root);
|
||||
log_pinned = false;
|
||||
}
|
||||
btrfs_end_transaction(trans);
|
||||
if (!ret && sync_log) {
|
||||
ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root, &ctx);
|
||||
if (ret)
|
||||
commit_transaction = true;
|
||||
}
|
||||
if (commit_transaction) {
|
||||
ret = btrfs_commit_transaction(trans);
|
||||
} else {
|
||||
int ret2;
|
||||
|
||||
ret2 = btrfs_end_transaction(trans);
|
||||
ret = ret ? ret : ret2;
|
||||
}
|
||||
out_notrans:
|
||||
if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
up_read(&fs_info->subvol_sem);
|
||||
|
Reference in New Issue
Block a user