1
0
Fork 0

for-4.19-rc2-tag

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAluRLa8ACgkQxWXV+ddt
 WDvc+BAAqxTMVngZ60WfktXzsS56OB6fu/R3DORgYcSZ0BCD4zTwoDlCjLhrCK6E
 cmC+BMj+AspDQYiYESwGyFcN10sK0X7w7fa3wypTc4GNWxpkRm0Z6zT/kCvLUhdI
 NlkMqAfsZ9N6iIXcR0qOxI7G55e3mpXPZGdFTk5rmDTv/9TqU0TMp9s8Zw5scn6R
 ctdE+iE0lpRfNjF8ZDH1BtYIV4g2X81sZF/fkGz621HQfMTCjjPHFdlz+jlirBaf
 BrYR4w4zjVuMKd3ZC5FHffVchbkvt29h6fAr4sEpJTwFJwd8pjI7GuPYWDQ918NB
 TGX6EUP6usQqDK2zD405jCS6MbMshJm3uh5kmEpeNgK/tKJTln8Sbef/Xs93yIn2
 +k9BMKOIcUHHBiv6PgCaZomcWCpii2S2u6vncqCnNuI4wK1RN3gHJc5YPhJArlrB
 NUFJiTCQE6LWYOP2Hw+rggcrtBxli0bX7Mqp5FYFVdh5KBvolJE1o3B/JS8qpqRF
 u0dPwbLHtTpTpXM5EfmM8a45S+DxuxTDBh3vdoAOM9LN/ivpeqqnFbHrIGmrTMjo
 pQJ8aTrCwYMEMNu6oCV1cniFrOYRZ439hYjg524MjVXYCRyxhzAdVmVTEBaLjWCW
 9GlGqEC7YZY2wLi5lPEGqxsIaVVELpettJB9KbBKmYB47VFWEf0=
 =fu93
 -----END PGP SIGNATURE-----

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
hifive-unleashed-5.1
Linus Torvalds 2018-09-06 09:04:45 -07:00
commit 5404525b98
9 changed files with 197 additions and 55 deletions

View File

@ -1280,6 +1280,7 @@ struct btrfs_root {
int send_in_progress;
struct btrfs_subvolume_writers *subv_writers;
atomic_t will_be_snapshotted;
atomic_t snapshot_force_cow;
/* For qgroup metadata reserved space */
spinlock_t qgroup_meta_rsv_lock;
@ -3390,9 +3391,9 @@ do { \
#define btrfs_debug(fs_info, fmt, args...) \
btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
#define btrfs_debug_in_rcu(fs_info, fmt, args...) \
btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \
btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args)
#define btrfs_debug_rl(fs_info, fmt, args...) \
btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args)
#endif
@ -3404,6 +3405,13 @@ do { \
rcu_read_unlock(); \
} while (0)
#define btrfs_no_printk_in_rcu(fs_info, fmt, args...) \
do { \
rcu_read_lock(); \
btrfs_no_printk(fs_info, fmt, ##args); \
rcu_read_unlock(); \
} while (0)
#define btrfs_printk_ratelimited(fs_info, fmt, args...) \
do { \
static DEFINE_RATELIMIT_STATE(_rs, \

View File

@ -1187,6 +1187,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
atomic_set(&root->log_batch, 0);
refcount_set(&root->refs, 1);
atomic_set(&root->will_be_snapshotted, 0);
atomic_set(&root->snapshot_force_cow, 0);
root->log_transid = 0;
root->log_transid_committed = -1;
root->last_log_commit = 0;

View File

@ -5800,7 +5800,7 @@ void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans)
* root: the root of the parent directory
* rsv: block reservation
* items: the number of items that we need do reservation
* qgroup_reserved: used to return the reserved size in qgroup
* use_global_rsv: allow fallback to the global block reservation
*
* This function is used to reserve the space for snapshot/subvolume
* creation and deletion. Those operations are different with the
@ -5810,10 +5810,10 @@ void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans)
* the space reservation mechanism in start_transaction().
*/
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
struct btrfs_block_rsv *rsv,
int items,
struct btrfs_block_rsv *rsv, int items,
bool use_global_rsv)
{
u64 qgroup_num_bytes = 0;
u64 num_bytes;
int ret;
struct btrfs_fs_info *fs_info = root->fs_info;
@ -5821,12 +5821,11 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
/* One for parent inode, two for dir entries */
num_bytes = 3 * fs_info->nodesize;
ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
qgroup_num_bytes = 3 * fs_info->nodesize;
ret = btrfs_qgroup_reserve_meta_prealloc(root,
qgroup_num_bytes, true);
if (ret)
return ret;
} else {
num_bytes = 0;
}
num_bytes = btrfs_calc_trans_metadata_size(fs_info, items);
@ -5838,8 +5837,8 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
if (ret == -ENOSPC && use_global_rsv)
ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1);
if (ret && num_bytes)
btrfs_qgroup_free_meta_prealloc(root, num_bytes);
if (ret && qgroup_num_bytes)
btrfs_qgroup_free_meta_prealloc(root, qgroup_num_bytes);
return ret;
}

View File

@ -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);

View File

@ -747,6 +747,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
struct btrfs_pending_snapshot *pending_snapshot;
struct btrfs_trans_handle *trans;
int ret;
bool snapshot_force_cow = false;
if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
return -EINVAL;
@ -763,6 +764,11 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
goto free_pending;
}
/*
* Force new buffered writes to reserve space even when NOCOW is
* possible. This is to avoid later writeback (running dealloc) to
* fallback to COW mode and unexpectedly fail with ENOSPC.
*/
atomic_inc(&root->will_be_snapshotted);
smp_mb__after_atomic();
/* wait for no snapshot writes */
@ -773,6 +779,14 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
if (ret)
goto dec_and_free;
/*
* All previous writes have started writeback in NOCOW mode, so now
* we force future writes to fallback to COW mode during snapshot
* creation.
*/
atomic_inc(&root->snapshot_force_cow);
snapshot_force_cow = true;
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
btrfs_init_block_rsv(&pending_snapshot->block_rsv,
@ -837,6 +851,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
fail:
btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv);
dec_and_free:
if (snapshot_force_cow)
atomic_dec(&root->snapshot_force_cow);
if (atomic_dec_and_test(&root->will_be_snapshotted))
wake_up_var(&root->will_be_snapshotted);
free_pending:
@ -3453,6 +3469,25 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
same_lock_start = min_t(u64, loff, dst_loff);
same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start;
} else {
/*
* If the source and destination inodes are different, the
* source's range end offset matches the source's i_size, that
* i_size is not a multiple of the sector size, and the
* destination range does not go past the destination's i_size,
* we must round down the length to the nearest sector size
* multiple. If we don't do this adjustment we end replacing
* with zeroes the bytes in the range that starts at the
* deduplication range's end offset and ends at the next sector
* size multiple.
*/
if (loff + olen == i_size_read(src) &&
dst_loff + len < i_size_read(dst)) {
const u64 sz = BTRFS_I(src)->root->fs_info->sectorsize;
len = round_down(i_size_read(src), sz) - loff;
olen = len;
}
}
again:

View File

@ -1019,10 +1019,9 @@ out_add_root:
spin_unlock(&fs_info->qgroup_lock);
ret = btrfs_commit_transaction(trans);
if (ret) {
trans = NULL;
trans = NULL;
if (ret)
goto out_free_path;
}
ret = qgroup_rescan_init(fs_info, 0, 1);
if (!ret) {

View File

@ -6025,14 +6025,25 @@ void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans,
* Call this after adding a new name for a file and it will properly
* update the log to reflect the new name.
*
* It will return zero if all goes well, and it will return 1 if a
* full transaction commit is required.
* @ctx can not be NULL when @sync_log is false, and should be NULL when it's
* true (because it's not used).
*
* Return value depends on whether @sync_log is true or false.
* When true: returns BTRFS_NEED_TRANS_COMMIT if the transaction needs to be
* committed by the caller, and BTRFS_DONT_NEED_TRANS_COMMIT
* otherwise.
* When false: returns BTRFS_DONT_NEED_LOG_SYNC if the caller does not need to
* to sync the log, BTRFS_NEED_LOG_SYNC if it needs to sync the log,
* or BTRFS_NEED_TRANS_COMMIT if the transaction needs to be
* committed (without attempting to sync the log).
*/
int btrfs_log_new_name(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode, struct btrfs_inode *old_dir,
struct dentry *parent)
struct dentry *parent,
bool sync_log, struct btrfs_log_ctx *ctx)
{
struct btrfs_fs_info *fs_info = trans->fs_info;
int ret;
/*
* this will force the logging code to walk the dentry chain
@ -6047,9 +6058,34 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
*/
if (inode->logged_trans <= fs_info->last_trans_committed &&
(!old_dir || old_dir->logged_trans <= fs_info->last_trans_committed))
return 0;
return sync_log ? BTRFS_DONT_NEED_TRANS_COMMIT :
BTRFS_DONT_NEED_LOG_SYNC;
return btrfs_log_inode_parent(trans, inode, parent, 0, LLONG_MAX,
LOG_INODE_EXISTS, NULL);
if (sync_log) {
struct btrfs_log_ctx ctx2;
btrfs_init_log_ctx(&ctx2, &inode->vfs_inode);
ret = btrfs_log_inode_parent(trans, inode, parent, 0, LLONG_MAX,
LOG_INODE_EXISTS, &ctx2);
if (ret == BTRFS_NO_LOG_SYNC)
return BTRFS_DONT_NEED_TRANS_COMMIT;
else if (ret)
return BTRFS_NEED_TRANS_COMMIT;
ret = btrfs_sync_log(trans, inode->root, &ctx2);
if (ret)
return BTRFS_NEED_TRANS_COMMIT;
return BTRFS_DONT_NEED_TRANS_COMMIT;
}
ASSERT(ctx);
ret = btrfs_log_inode_parent(trans, inode, parent, 0, LLONG_MAX,
LOG_INODE_EXISTS, ctx);
if (ret == BTRFS_NO_LOG_SYNC)
return BTRFS_DONT_NEED_LOG_SYNC;
else if (ret)
return BTRFS_NEED_TRANS_COMMIT;
return BTRFS_NEED_LOG_SYNC;
}

View File

@ -71,8 +71,16 @@ void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
int for_rename);
void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir);
/* Return values for btrfs_log_new_name() */
enum {
BTRFS_DONT_NEED_TRANS_COMMIT,
BTRFS_NEED_TRANS_COMMIT,
BTRFS_DONT_NEED_LOG_SYNC,
BTRFS_NEED_LOG_SYNC,
};
int btrfs_log_new_name(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode, struct btrfs_inode *old_dir,
struct dentry *parent);
struct dentry *parent,
bool sync_log, struct btrfs_log_ctx *ctx);
#endif

View File

@ -4491,7 +4491,12 @@ again:
/* Now btrfs_update_device() will change the on-disk size. */
ret = btrfs_update_device(trans, device);
btrfs_end_transaction(trans);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
} else {
ret = btrfs_commit_transaction(trans);
}
done:
btrfs_free_path(path);
if (ret) {