From: Sasha Levin Date: Sun, 23 Aug 2020 01:16:35 +0000 (-0400) Subject: Fixes for 5.4 X-Git-Tag: v4.4.234~61 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f4d7b8a2162c2866a638bd1641d03e2ebf6a9585;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.4 Signed-off-by: Sasha Levin --- diff --git a/queue-5.4/bcache-avoid-nr_stripes-overflow-in-bcache_device_in.patch b/queue-5.4/bcache-avoid-nr_stripes-overflow-in-bcache_device_in.patch new file mode 100644 index 00000000000..36f5dbb93c3 --- /dev/null +++ b/queue-5.4/bcache-avoid-nr_stripes-overflow-in-bcache_device_in.patch @@ -0,0 +1,62 @@ +From ab86df06e46c37649929e12630ce1bb0354e789f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Jul 2020 20:00:21 +0800 +Subject: bcache: avoid nr_stripes overflow in bcache_device_init() + +From: Coly Li + +[ Upstream commit 65f0f017e7be8c70330372df23bcb2a407ecf02d ] + +For some block devices which large capacity (e.g. 8TB) but small io_opt +size (e.g. 8 sectors), in bcache_device_init() the stripes number calcu- +lated by, + DIV_ROUND_UP_ULL(sectors, d->stripe_size); +might be overflow to the unsigned int bcache_device->nr_stripes. + +This patch uses the uint64_t variable to store DIV_ROUND_UP_ULL() +and after the value is checked to be available in unsigned int range, +sets it to bache_device->nr_stripes. Then the overflow is avoided. + +Reported-and-tested-by: Ken Raeburn +Signed-off-by: Coly Li +Cc: stable@vger.kernel.org +Link: https://bugzilla.redhat.com/show_bug.cgi?id=1783075 +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/md/bcache/super.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 25ad64a3919f6..2cbfcd99b7ee7 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -816,19 +816,19 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size, + struct request_queue *q; + const size_t max_stripes = min_t(size_t, INT_MAX, + SIZE_MAX / sizeof(atomic_t)); +- size_t n; ++ uint64_t n; + int idx; + + if (!d->stripe_size) + d->stripe_size = 1 << 31; + +- d->nr_stripes = DIV_ROUND_UP_ULL(sectors, d->stripe_size); +- +- if (!d->nr_stripes || d->nr_stripes > max_stripes) { +- pr_err("nr_stripes too large or invalid: %u (start sector beyond end of disk?)", +- (unsigned int)d->nr_stripes); ++ n = DIV_ROUND_UP_ULL(sectors, d->stripe_size); ++ if (!n || n > max_stripes) { ++ pr_err("nr_stripes too large or invalid: %llu (start sector beyond end of disk?)\n", ++ n); + return -ENOMEM; + } ++ d->nr_stripes = n; + + n = d->nr_stripes * sizeof(atomic_t); + d->stripe_sectors_dirty = kvzalloc(n, GFP_KERNEL); +-- +2.25.1 + diff --git a/queue-5.4/btrfs-add-wrapper-for-transaction-abort-predicate.patch b/queue-5.4/btrfs-add-wrapper-for-transaction-abort-predicate.patch new file mode 100644 index 00000000000..8644aaeac9d --- /dev/null +++ b/queue-5.4/btrfs-add-wrapper-for-transaction-abort-predicate.patch @@ -0,0 +1,252 @@ +From f044d112a36247e0dd7eee2c5feb5e0cb6980f9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2020 17:34:34 +0100 +Subject: btrfs: add wrapper for transaction abort predicate + +From: David Sterba + +[ Upstream commit bf31f87f71cc7a89871ab0a451c047a0c0144bf1 ] + +The status of aborted transaction can change between calls and it needs +to be accessed by READ_ONCE. Add a helper that also wraps the unlikely +hint. + +Reviewed-by: Josef Bacik +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 2 +- + fs/btrfs/delayed-inode.c | 2 +- + fs/btrfs/extent-tree.c | 10 +++++----- + fs/btrfs/super.c | 2 +- + fs/btrfs/transaction.c | 25 +++++++++++++------------ + fs/btrfs/transaction.h | 12 ++++++++++++ + 6 files changed, 33 insertions(+), 20 deletions(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 42d69e77f89d9..b167649f5f5de 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -2168,7 +2168,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, + return 0; + } + +- if (trans->aborted) ++ if (TRANS_ABORTED(trans)) + return 0; + again: + inode = lookup_free_space_inode(block_group, path); +diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c +index 5bcccfbcc7c15..a34ee9c2f3151 100644 +--- a/fs/btrfs/delayed-inode.c ++++ b/fs/btrfs/delayed-inode.c +@@ -1151,7 +1151,7 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr) + int ret = 0; + bool count = (nr > 0); + +- if (trans->aborted) ++ if (TRANS_ABORTED(trans)) + return -EIO; + + path = btrfs_alloc_path(); +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index 739332b462059..a36bd4507bacd 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -1561,7 +1561,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans, + int err = 0; + int metadata = !extent_op->is_data; + +- if (trans->aborted) ++ if (TRANS_ABORTED(trans)) + return 0; + + if (metadata && !btrfs_fs_incompat(fs_info, SKINNY_METADATA)) +@@ -1681,7 +1681,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, + { + int ret = 0; + +- if (trans->aborted) { ++ if (TRANS_ABORTED(trans)) { + if (insert_reserved) + btrfs_pin_extent(trans->fs_info, node->bytenr, + node->num_bytes, 1); +@@ -2169,7 +2169,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, + int run_all = count == (unsigned long)-1; + + /* We'll clean this up in btrfs_cleanup_transaction */ +- if (trans->aborted) ++ if (TRANS_ABORTED(trans)) + return 0; + + if (test_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags)) +@@ -2892,7 +2892,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) + else + unpin = &fs_info->freed_extents[0]; + +- while (!trans->aborted) { ++ while (!TRANS_ABORTED(trans)) { + struct extent_state *cached_state = NULL; + + mutex_lock(&fs_info->unused_bg_unpin_mutex); +@@ -2924,7 +2924,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) + u64 trimmed = 0; + + ret = -EROFS; +- if (!trans->aborted) ++ if (!TRANS_ABORTED(trans)) + ret = btrfs_discard_extent(fs_info, + block_group->key.objectid, + block_group->key.offset, +diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c +index e21cae80c6d58..a1498df419b4f 100644 +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -241,7 +241,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans, + { + struct btrfs_fs_info *fs_info = trans->fs_info; + +- trans->aborted = errno; ++ WRITE_ONCE(trans->aborted, errno); + /* Nothing used. The other threads that have joined this + * transaction may be able to continue. */ + if (!trans->dirty && list_empty(&trans->new_bgs)) { +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index 465ddb297c381..c346ee7ec18d4 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -174,7 +174,7 @@ loop: + + cur_trans = fs_info->running_transaction; + if (cur_trans) { +- if (cur_trans->aborted) { ++ if (TRANS_ABORTED(cur_trans)) { + spin_unlock(&fs_info->trans_lock); + return cur_trans->aborted; + } +@@ -390,7 +390,7 @@ static inline int is_transaction_blocked(struct btrfs_transaction *trans) + { + return (trans->state >= TRANS_STATE_BLOCKED && + trans->state < TRANS_STATE_UNBLOCKED && +- !trans->aborted); ++ !TRANS_ABORTED(trans)); + } + + /* wait for commit against the current transaction to become unblocked +@@ -409,7 +409,7 @@ static void wait_current_trans(struct btrfs_fs_info *fs_info) + + wait_event(fs_info->transaction_wait, + cur_trans->state >= TRANS_STATE_UNBLOCKED || +- cur_trans->aborted); ++ TRANS_ABORTED(cur_trans)); + btrfs_put_transaction(cur_trans); + } else { + spin_unlock(&fs_info->trans_lock); +@@ -870,7 +870,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, + if (throttle) + btrfs_run_delayed_iputs(info); + +- if (trans->aborted || ++ if (TRANS_ABORTED(trans) || + test_bit(BTRFS_FS_STATE_ERROR, &info->fs_state)) { + wake_up_process(info->transaction_kthread); + if (TRANS_ABORTED(trans)) +@@ -1730,7 +1730,8 @@ static void wait_current_trans_commit_start(struct btrfs_fs_info *fs_info, + struct btrfs_transaction *trans) + { + wait_event(fs_info->transaction_blocked_wait, +- trans->state >= TRANS_STATE_COMMIT_START || trans->aborted); ++ trans->state >= TRANS_STATE_COMMIT_START || ++ TRANS_ABORTED(trans)); + } + + /* +@@ -1742,7 +1743,8 @@ static void wait_current_trans_commit_start_and_unblock( + struct btrfs_transaction *trans) + { + wait_event(fs_info->transaction_wait, +- trans->state >= TRANS_STATE_UNBLOCKED || trans->aborted); ++ trans->state >= TRANS_STATE_UNBLOCKED || ++ TRANS_ABORTED(trans)); + } + + /* +@@ -1960,7 +1962,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + trans->dirty = true; + + /* Stop the commit early if ->aborted is set */ +- if (unlikely(READ_ONCE(cur_trans->aborted))) { ++ if (TRANS_ABORTED(cur_trans)) { + ret = cur_trans->aborted; + btrfs_end_transaction(trans); + return ret; +@@ -2034,7 +2036,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + + wait_for_commit(cur_trans); + +- if (unlikely(cur_trans->aborted)) ++ if (TRANS_ABORTED(cur_trans)) + ret = cur_trans->aborted; + + btrfs_put_transaction(cur_trans); +@@ -2053,7 +2055,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + spin_unlock(&fs_info->trans_lock); + + wait_for_commit(prev_trans); +- ret = prev_trans->aborted; ++ ret = READ_ONCE(prev_trans->aborted); + + btrfs_put_transaction(prev_trans); + if (ret) +@@ -2107,8 +2109,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + wait_event(cur_trans->writer_wait, + atomic_read(&cur_trans->num_writers) == 1); + +- /* ->aborted might be set after the previous check, so check it */ +- if (unlikely(READ_ONCE(cur_trans->aborted))) { ++ if (TRANS_ABORTED(cur_trans)) { + ret = cur_trans->aborted; + goto scrub_continue; + } +@@ -2226,7 +2227,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) + * The tasks which save the space cache and inode cache may also + * update ->aborted, check it. + */ +- if (unlikely(READ_ONCE(cur_trans->aborted))) { ++ if (TRANS_ABORTED(cur_trans)) { + ret = cur_trans->aborted; + mutex_unlock(&fs_info->tree_log_mutex); + mutex_unlock(&fs_info->reloc_mutex); +diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h +index b15c31d231488..7291a2a930751 100644 +--- a/fs/btrfs/transaction.h ++++ b/fs/btrfs/transaction.h +@@ -116,6 +116,10 @@ struct btrfs_trans_handle { + struct btrfs_block_rsv *orig_rsv; + refcount_t use_count; + unsigned int type; ++ /* ++ * Error code of transaction abort, set outside of locks and must use ++ * the READ_ONCE/WRITE_ONCE access ++ */ + short aborted; + bool adding_csums; + bool allocating_chunk; +@@ -127,6 +131,14 @@ struct btrfs_trans_handle { + struct list_head new_bgs; + }; + ++/* ++ * The abort status can be changed between calls and is not protected by locks. ++ * This accepts btrfs_transaction and btrfs_trans_handle as types. Once it's ++ * set to a non-zero value it does not change, so the macro should be in checks ++ * but is not necessary for further reads of the value. ++ */ ++#define TRANS_ABORTED(trans) (unlikely(READ_ONCE((trans)->aborted))) ++ + struct btrfs_pending_snapshot { + struct dentry *dentry; + struct inode *dir; +-- +2.25.1 + diff --git a/queue-5.4/btrfs-don-t-show-full-path-of-bind-mounts-in-subvol.patch b/queue-5.4/btrfs-don-t-show-full-path-of-bind-mounts-in-subvol.patch new file mode 100644 index 00000000000..a1bcb1f5a18 --- /dev/null +++ b/queue-5.4/btrfs-don-t-show-full-path-of-bind-mounts-in-subvol.patch @@ -0,0 +1,67 @@ +From e52292f89964b8c709f8441efd880ad404b09094 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2020 11:12:46 -0400 +Subject: btrfs: don't show full path of bind mounts in subvol= + +From: Josef Bacik + +[ Upstream commit 3ef3959b29c4a5bd65526ab310a1a18ae533172a ] + +Chris Murphy reported a problem where rpm ostree will bind mount a bunch +of things for whatever voodoo it's doing. But when it does this +/proc/mounts shows something like + + /dev/sda /mnt/test btrfs rw,relatime,subvolid=256,subvol=/foo 0 0 + /dev/sda /mnt/test/baz btrfs rw,relatime,subvolid=256,subvol=/foo/bar 0 0 + +Despite subvolid=256 being subvol=/foo. This is because we're just +spitting out the dentry of the mount point, which in the case of bind +mounts is the source path for the mountpoint. Instead we should spit +out the path to the actual subvol. Fix this by looking up the name for +the subvolid we have mounted. With this fix the same test looks like +this + + /dev/sda /mnt/test btrfs rw,relatime,subvolid=256,subvol=/foo 0 0 + /dev/sda /mnt/test/baz btrfs rw,relatime,subvolid=256,subvol=/foo 0 0 + +Reported-by: Chris Murphy +CC: stable@vger.kernel.org # 4.4+ +Signed-off-by: Josef Bacik +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/super.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c +index 32c36821cc7b4..e21cae80c6d58 100644 +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -1291,6 +1291,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) + { + struct btrfs_fs_info *info = btrfs_sb(dentry->d_sb); + const char *compress_type; ++ const char *subvol_name; + + if (btrfs_test_opt(info, DEGRADED)) + seq_puts(seq, ",degraded"); +@@ -1375,8 +1376,13 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) + seq_puts(seq, ",ref_verify"); + seq_printf(seq, ",subvolid=%llu", + BTRFS_I(d_inode(dentry))->root->root_key.objectid); +- seq_puts(seq, ",subvol="); +- seq_dentry(seq, dentry, " \t\n\\"); ++ subvol_name = btrfs_get_subvol_name_from_objectid(info, ++ BTRFS_I(d_inode(dentry))->root->root_key.objectid); ++ if (!IS_ERR(subvol_name)) { ++ seq_puts(seq, ",subvol="); ++ seq_escape(seq, subvol_name, " \t\n\\"); ++ kfree(subvol_name); ++ } + return 0; + } + +-- +2.25.1 + diff --git a/queue-5.4/btrfs-export-helpers-for-subvolume-name-id-resolutio.patch b/queue-5.4/btrfs-export-helpers-for-subvolume-name-id-resolutio.patch new file mode 100644 index 00000000000..cc2d593ef36 --- /dev/null +++ b/queue-5.4/btrfs-export-helpers-for-subvolume-name-id-resolutio.patch @@ -0,0 +1,107 @@ +From 7832dc6dfcd889648c15f43081c14ada3a7b13be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Feb 2020 14:56:12 +0100 +Subject: btrfs: export helpers for subvolume name/id resolution + +From: Marcos Paulo de Souza + +[ Upstream commit c0c907a47dccf2cf26251a8fb4a8e7a3bf79ce84 ] + +The functions will be used outside of export.c and super.c to allow +resolving subvolume name from a given id, eg. for subvolume deletion by +id ioctl. + +Signed-off-by: Marcos Paulo de Souza +Reviewed-by: David Sterba +[ split from the next patch ] +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ctree.h | 2 ++ + fs/btrfs/export.c | 8 ++++---- + fs/btrfs/export.h | 5 +++++ + fs/btrfs/super.c | 8 ++++---- + 4 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index 2374f3f6f3b70..18357b054a91e 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -2965,6 +2965,8 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, + int btrfs_parse_options(struct btrfs_fs_info *info, char *options, + unsigned long new_flags); + int btrfs_sync_fs(struct super_block *sb, int wait); ++char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info, ++ u64 subvol_objectid); + + static inline __printf(2, 3) __cold + void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) +diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c +index ddf28ecf17f93..93cceeba484cc 100644 +--- a/fs/btrfs/export.c ++++ b/fs/btrfs/export.c +@@ -57,9 +57,9 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, + return type; + } + +-static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, +- u64 root_objectid, u32 generation, +- int check_generation) ++struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, ++ u64 root_objectid, u32 generation, ++ int check_generation) + { + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_root *root; +@@ -152,7 +152,7 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, + return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1); + } + +-static struct dentry *btrfs_get_parent(struct dentry *child) ++struct dentry *btrfs_get_parent(struct dentry *child) + { + struct inode *dir = d_inode(child); + struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); +diff --git a/fs/btrfs/export.h b/fs/btrfs/export.h +index 57488ecd7d4ef..f32f4113c976a 100644 +--- a/fs/btrfs/export.h ++++ b/fs/btrfs/export.h +@@ -18,4 +18,9 @@ struct btrfs_fid { + u64 parent_root_objectid; + } __attribute__ ((packed)); + ++struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, ++ u64 root_objectid, u32 generation, ++ int check_generation); ++struct dentry *btrfs_get_parent(struct dentry *child); ++ + #endif +diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c +index 4b0ee34aa65d5..32c36821cc7b4 100644 +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -1009,8 +1009,8 @@ out: + return error; + } + +-static char *get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info, +- u64 subvol_objectid) ++char *btrfs_get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info, ++ u64 subvol_objectid) + { + struct btrfs_root *root = fs_info->tree_root; + struct btrfs_root *fs_root; +@@ -1421,8 +1421,8 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid, + goto out; + } + } +- subvol_name = get_subvol_name_from_objectid(btrfs_sb(mnt->mnt_sb), +- subvol_objectid); ++ subvol_name = btrfs_get_subvol_name_from_objectid( ++ btrfs_sb(mnt->mnt_sb), subvol_objectid); + if (IS_ERR(subvol_name)) { + root = ERR_CAST(subvol_name); + subvol_name = NULL; +-- +2.25.1 + diff --git a/queue-5.4/btrfs-return-erofs-for-btrfs_fs_state_error-cases.patch b/queue-5.4/btrfs-return-erofs-for-btrfs_fs_state_error-cases.patch new file mode 100644 index 00000000000..e0c340270ce --- /dev/null +++ b/queue-5.4/btrfs-return-erofs-for-btrfs_fs_state_error-cases.patch @@ -0,0 +1,157 @@ +From 1c53e6f5d30a6ac96087ab28523115bdae03921f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Jul 2020 10:38:37 -0400 +Subject: btrfs: return EROFS for BTRFS_FS_STATE_ERROR cases + +From: Josef Bacik + +Eric reported seeing this message while running generic/475 + + BTRFS: error (device dm-3) in btrfs_sync_log:3084: errno=-117 Filesystem corrupted + +Full stack trace: + + BTRFS: error (device dm-0) in btrfs_commit_transaction:2323: errno=-5 IO failure (Error while writing out transaction) + BTRFS info (device dm-0): forced readonly + BTRFS warning (device dm-0): Skipping commit of aborted transaction. + ------------[ cut here ]------------ + BTRFS: error (device dm-0) in cleanup_transaction:1894: errno=-5 IO failure + BTRFS: Transaction aborted (error -117) + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6480 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6488 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6490 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c6498 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64a0 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64a8 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64b0 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64b8 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3555 rw 0,0 sector 0x1c64c0 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3572 rw 0,0 sector 0x1b85e8 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3572 rw 0,0 sector 0x1b85f0 len 4096 err no 10 + WARNING: CPU: 3 PID: 23985 at fs/btrfs/tree-log.c:3084 btrfs_sync_log+0xbc8/0xd60 [btrfs] + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d4288 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d4290 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d4298 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42a0 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42a8 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42b0 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42b8 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42c0 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42c8 len 4096 err no 10 + BTRFS warning (device dm-0): direct IO failed ino 3548 rw 0,0 sector 0x1d42d0 len 4096 err no 10 + CPU: 3 PID: 23985 Comm: fsstress Tainted: G W L 5.8.0-rc4-default+ #1181 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014 + RIP: 0010:btrfs_sync_log+0xbc8/0xd60 [btrfs] + RSP: 0018:ffff909a44d17bd0 EFLAGS: 00010286 + RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000001 + RDX: ffff8f3be41cb940 RSI: ffffffffb0108d2b RDI: ffffffffb0108ff7 + RBP: ffff909a44d17e70 R08: 0000000000000000 R09: 0000000000000000 + R10: 0000000000000000 R11: 0000000000037988 R12: ffff8f3bd20e4000 + R13: ffff8f3bd20e4428 R14: 00000000ffffff8b R15: ffff909a44d17c70 + FS: 00007f6a6ed3fb80(0000) GS:ffff8f3c3dc00000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007f6a6ed3e000 CR3: 00000000525c0003 CR4: 0000000000160ee0 + Call Trace: + ? finish_wait+0x90/0x90 + ? __mutex_unlock_slowpath+0x45/0x2a0 + ? lock_acquire+0xa3/0x440 + ? lockref_put_or_lock+0x9/0x30 + ? dput+0x20/0x4a0 + ? dput+0x20/0x4a0 + ? do_raw_spin_unlock+0x4b/0xc0 + ? _raw_spin_unlock+0x1f/0x30 + btrfs_sync_file+0x335/0x490 [btrfs] + do_fsync+0x38/0x70 + __x64_sys_fsync+0x10/0x20 + do_syscall_64+0x50/0xe0 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 + RIP: 0033:0x7f6a6ef1b6e3 + Code: Bad RIP value. + RSP: 002b:00007ffd01e20038 EFLAGS: 00000246 ORIG_RAX: 000000000000004a + RAX: ffffffffffffffda RBX: 000000000007a120 RCX: 00007f6a6ef1b6e3 + RDX: 00007ffd01e1ffa0 RSI: 00007ffd01e1ffa0 RDI: 0000000000000003 + RBP: 0000000000000003 R08: 0000000000000001 R09: 00007ffd01e2004c + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000009f + R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 + irq event stamp: 0 + hardirqs last enabled at (0): [<0000000000000000>] 0x0 + hardirqs last disabled at (0): [] copy_process+0x67b/0x1b00 + softirqs last enabled at (0): [] copy_process+0x67b/0x1b00 + softirqs last disabled at (0): [<0000000000000000>] 0x0 + ---[ end trace af146e0e38433456 ]--- + BTRFS: error (device dm-0) in btrfs_sync_log:3084: errno=-117 Filesystem corrupted + +This ret came from btrfs_write_marked_extents(). If we get an aborted +transaction via EIO before, we'll see it in btree_write_cache_pages() +and return EUCLEAN, which gets printed as "Filesystem corrupted". + +Except we shouldn't be returning EUCLEAN here, we need to be returning +EROFS because EUCLEAN is reserved for actual corruption, not IO errors. + +We are inconsistent about our handling of BTRFS_FS_STATE_ERROR +elsewhere, but we want to use EROFS for this particular case. The +original transaction abort has the real error code for why we ended up +with an aborted transaction, all subsequent actions just need to return +EROFS because they may not have a trans handle and have no idea about +the original cause of the abort. + +After patch "btrfs: don't WARN if we abort a transaction with EROFS" the +stacktrace will not be dumped either. + +Reported-by: Eric Sandeen +CC: stable@vger.kernel.org # 5.4+ +Signed-off-by: Josef Bacik +Reviewed-by: David Sterba +[ add full test stacktrace ] +Signed-off-by: David Sterba +--- + fs/btrfs/extent_io.c | 2 +- + fs/btrfs/scrub.c | 2 +- + fs/btrfs/transaction.c | 5 ++++- + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 035ea5bc692ad..5707bf0575d43 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -4073,7 +4073,7 @@ retry: + if (!test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { + ret = flush_write_bio(&epd); + } else { +- ret = -EUCLEAN; ++ ret = -EROFS; + end_write_bio(&epd, ret); + } + return ret; +diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c +index a7b043fd7a572..498b824148187 100644 +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -3717,7 +3717,7 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, + struct btrfs_fs_info *fs_info = sctx->fs_info; + + if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) +- return -EIO; ++ return -EROFS; + + /* Seed devices of a new filesystem has their own generation. */ + if (scrub_dev->fs_devices != fs_info->fs_devices) +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index 54589e940f9af..465ddb297c381 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -873,7 +873,10 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, + if (trans->aborted || + test_bit(BTRFS_FS_STATE_ERROR, &info->fs_state)) { + wake_up_process(info->transaction_kthread); +- err = -EIO; ++ if (TRANS_ABORTED(trans)) ++ err = trans->aborted; ++ else ++ err = -EROFS; + } + + kmem_cache_free(btrfs_trans_handle_cachep, trans); +-- +2.25.1 + diff --git a/queue-5.4/drm-vgem-replace-opencoded-version-of-drm_gem_dumb_m.patch b/queue-5.4/drm-vgem-replace-opencoded-version-of-drm_gem_dumb_m.patch new file mode 100644 index 00000000000..0e678a8655c --- /dev/null +++ b/queue-5.4/drm-vgem-replace-opencoded-version-of-drm_gem_dumb_m.patch @@ -0,0 +1,83 @@ +From fbc3cd1cc3189cedb14d7a87eb2b4df940250814 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Jul 2020 16:49:11 +0100 +Subject: drm/vgem: Replace opencoded version of drm_gem_dumb_map_offset() + +From: Chris Wilson + +[ Upstream commit 119c53d2d4044c59c450c4f5a568d80b9d861856 ] + +drm_gem_dumb_map_offset() now exists and does everything +vgem_gem_dump_map does and *ought* to do. + +In particular, vgem_gem_dumb_map() was trying to reject mmapping an +imported dmabuf by checking the existence of obj->filp. Unfortunately, +we always allocated an obj->filp, even if unused for an imported dmabuf. +Instead, the drm_gem_dumb_map_offset(), since commit 90378e589192 +("drm/gem: drm_gem_dumb_map_offset(): reject dma-buf"), uses the +obj->import_attach to reject such invalid mmaps. + +This prevents vgem from allowing userspace mmapping the dumb handle and +attempting to incorrectly fault in remote pages belonging to another +device, where there may not even be a struct page. + +v2: Use the default drm_gem_dumb_map_offset() callback + +Fixes: af33a9190d02 ("drm/vgem: Enable dmabuf import interfaces") +Signed-off-by: Chris Wilson +Reviewed-by: Daniel Vetter +Cc: # v4.13+ +Link: https://patchwork.freedesktop.org/patch/msgid/20200708154911.21236-1-chris@chris-wilson.co.uk +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/vgem/vgem_drv.c | 27 --------------------------- + 1 file changed, 27 deletions(-) + +diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c +index 909eba43664a2..204d1df5a21d1 100644 +--- a/drivers/gpu/drm/vgem/vgem_drv.c ++++ b/drivers/gpu/drm/vgem/vgem_drv.c +@@ -229,32 +229,6 @@ static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + return 0; + } + +-static int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev, +- uint32_t handle, uint64_t *offset) +-{ +- struct drm_gem_object *obj; +- int ret; +- +- obj = drm_gem_object_lookup(file, handle); +- if (!obj) +- return -ENOENT; +- +- if (!obj->filp) { +- ret = -EINVAL; +- goto unref; +- } +- +- ret = drm_gem_create_mmap_offset(obj); +- if (ret) +- goto unref; +- +- *offset = drm_vma_node_offset_addr(&obj->vma_node); +-unref: +- drm_gem_object_put_unlocked(obj); +- +- return ret; +-} +- + static struct drm_ioctl_desc vgem_ioctls[] = { + DRM_IOCTL_DEF_DRV(VGEM_FENCE_ATTACH, vgem_fence_attach_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VGEM_FENCE_SIGNAL, vgem_fence_signal_ioctl, DRM_RENDER_ALLOW), +@@ -448,7 +422,6 @@ static struct drm_driver vgem_driver = { + .fops = &vgem_driver_fops, + + .dumb_create = vgem_gem_dumb_create, +- .dumb_map_offset = vgem_gem_dumb_map, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, +-- +2.25.1 + diff --git a/queue-5.4/gfs2-improve-mmap-write-vs.-punch_hole-consistency.patch b/queue-5.4/gfs2-improve-mmap-write-vs.-punch_hole-consistency.patch new file mode 100644 index 00000000000..64cd51d5664 --- /dev/null +++ b/queue-5.4/gfs2-improve-mmap-write-vs.-punch_hole-consistency.patch @@ -0,0 +1,62 @@ +From 0c722adcc833760197b3e4e59d0b73f012a22bac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Sep 2019 14:51:38 +0100 +Subject: gfs2: Improve mmap write vs. punch_hole consistency + +From: Andreas Gruenbacher + +[ Upstream commit 39c3a948ecf6e7b8f55f0e91a5febc924fede4d7 ] + +When punching a hole in a file, use filemap_write_and_wait_range to +write back any dirty pages in the range of the hole. As a side effect, +if the hole isn't page aligned, this marks unaligned pages at the +beginning and the end of the hole read-only. This is required when the +block size is smaller than the page size: when those pages are written +to again after the hole punching, we must make sure that page_mkwrite is +called for those pages so that the page will be fully allocated and any +blocks turned into holes from the hole punching will be reallocated. +(If a page is writably mapped, page_mkwrite won't be called.) + +Fixes xfstest generic/567. + +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index adbb8fef22162..4846e0c47e6af 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -2442,8 +2442,16 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) + struct inode *inode = file_inode(file); + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); ++ unsigned int blocksize = i_blocksize(inode); ++ loff_t start, end; + int error; + ++ start = round_down(offset, blocksize); ++ end = round_up(offset + length, blocksize) - 1; ++ error = filemap_write_and_wait_range(inode->i_mapping, start, end); ++ if (error) ++ return error; ++ + if (gfs2_is_jdata(ip)) + error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, + GFS2_JTRUNC_REVOKES); +@@ -2457,9 +2465,8 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) + if (error) + goto out; + } else { +- unsigned int start_off, end_len, blocksize; ++ unsigned int start_off, end_len; + +- blocksize = i_blocksize(inode); + start_off = offset & (blocksize - 1); + end_len = (offset + length) & (blocksize - 1); + if (start_off) { +-- +2.25.1 + diff --git a/queue-5.4/gfs2-never-call-gfs2_block_zero_range-with-an-open-t.patch b/queue-5.4/gfs2-never-call-gfs2_block_zero_range-with-an-open-t.patch new file mode 100644 index 00000000000..1caa908b52e --- /dev/null +++ b/queue-5.4/gfs2-never-call-gfs2_block_zero_range-with-an-open-t.patch @@ -0,0 +1,158 @@ +From ce47414b53a0142cdfa2429fbf82c112266cecc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2020 12:06:31 -0500 +Subject: gfs2: Never call gfs2_block_zero_range with an open transaction + +From: Bob Peterson + +[ Upstream commit 70499cdfeb3625c87eebe4f7a7ea06fa7447e5df ] + +Before this patch, some functions started transactions then they called +gfs2_block_zero_range. However, gfs2_block_zero_range, like writes, can +start transactions, which results in a recursive transaction error. +For example: + +do_shrink + trunc_start + gfs2_trans_begin <------------------------------------------------ + gfs2_block_zero_range + iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops); + iomap_apply ... iomap_zero_range_actor + iomap_begin + gfs2_iomap_begin + gfs2_iomap_begin_write + actor (iomap_zero_range_actor) + iomap_zero + iomap_write_begin + gfs2_iomap_page_prepare + gfs2_trans_begin <------------------------ + +This patch reorders the callers of gfs2_block_zero_range so that they +only start their transactions after the call. It also adds a BUG_ON to +ensure this doesn't happen again. + +Fixes: 2257e468a63b ("gfs2: implement gfs2_block_zero_range using iomap_zero_range") +Cc: stable@vger.kernel.org # v5.5+ +Signed-off-by: Bob Peterson +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/bmap.c | 69 ++++++++++++++++++++++++++++---------------------- + 1 file changed, 39 insertions(+), 30 deletions(-) + +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 4846e0c47e6af..50fa3e08c02f3 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -1350,9 +1350,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi + return ret; + } + ++/* ++ * NOTE: Never call gfs2_block_zero_range with an open transaction because it ++ * uses iomap write to perform its actions, which begin their own transactions ++ * (iomap_begin, page_prepare, etc.) ++ */ + static int gfs2_block_zero_range(struct inode *inode, loff_t from, + unsigned int length) + { ++ BUG_ON(current->journal_info); + return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops); + } + +@@ -1413,6 +1419,16 @@ static int trunc_start(struct inode *inode, u64 newsize) + u64 oldsize = inode->i_size; + int error; + ++ if (!gfs2_is_stuffed(ip)) { ++ unsigned int blocksize = i_blocksize(inode); ++ unsigned int offs = newsize & (blocksize - 1); ++ if (offs) { ++ error = gfs2_block_zero_range(inode, newsize, ++ blocksize - offs); ++ if (error) ++ return error; ++ } ++ } + if (journaled) + error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES); + else +@@ -1426,19 +1442,10 @@ static int trunc_start(struct inode *inode, u64 newsize) + + gfs2_trans_add_meta(ip->i_gl, dibh); + +- if (gfs2_is_stuffed(ip)) { ++ if (gfs2_is_stuffed(ip)) + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize); +- } else { +- unsigned int blocksize = i_blocksize(inode); +- unsigned int offs = newsize & (blocksize - 1); +- if (offs) { +- error = gfs2_block_zero_range(inode, newsize, +- blocksize - offs); +- if (error) +- goto out; +- } ++ else + ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; +- } + + i_size_write(inode, newsize); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode); +@@ -2446,25 +2453,7 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) + loff_t start, end; + int error; + +- start = round_down(offset, blocksize); +- end = round_up(offset + length, blocksize) - 1; +- error = filemap_write_and_wait_range(inode->i_mapping, start, end); +- if (error) +- return error; +- +- if (gfs2_is_jdata(ip)) +- error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, +- GFS2_JTRUNC_REVOKES); +- else +- error = gfs2_trans_begin(sdp, RES_DINODE, 0); +- if (error) +- return error; +- +- if (gfs2_is_stuffed(ip)) { +- error = stuffed_zero_range(inode, offset, length); +- if (error) +- goto out; +- } else { ++ if (!gfs2_is_stuffed(ip)) { + unsigned int start_off, end_len; + + start_off = offset & (blocksize - 1); +@@ -2487,6 +2476,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length) + } + } + ++ start = round_down(offset, blocksize); ++ end = round_up(offset + length, blocksize) - 1; ++ error = filemap_write_and_wait_range(inode->i_mapping, start, end); ++ if (error) ++ return error; ++ ++ if (gfs2_is_jdata(ip)) ++ error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, ++ GFS2_JTRUNC_REVOKES); ++ else ++ error = gfs2_trans_begin(sdp, RES_DINODE, 0); ++ if (error) ++ return error; ++ ++ if (gfs2_is_stuffed(ip)) { ++ error = stuffed_zero_range(inode, offset, length); ++ if (error) ++ goto out; ++ } ++ + if (gfs2_is_jdata(ip)) { + BUG_ON(!current->journal_info); + gfs2_journaled_truncate_range(inode, offset, length); +-- +2.25.1 + diff --git a/queue-5.4/khugepaged-adjust-vm_bug_on_mm-in-__khugepaged_enter.patch b/queue-5.4/khugepaged-adjust-vm_bug_on_mm-in-__khugepaged_enter.patch new file mode 100644 index 00000000000..cbc08cd5449 --- /dev/null +++ b/queue-5.4/khugepaged-adjust-vm_bug_on_mm-in-__khugepaged_enter.patch @@ -0,0 +1,51 @@ +From 98796d4ed55b4c4f69e4dda3ef9b9409ec8b24b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Aug 2020 17:42:02 -0700 +Subject: khugepaged: adjust VM_BUG_ON_MM() in __khugepaged_enter() + +From: Hugh Dickins + +[ Upstream commit f3f99d63a8156c7a4a6b20aac22b53c5579c7dc1 ] + +syzbot crashes on the VM_BUG_ON_MM(khugepaged_test_exit(mm), mm) in +__khugepaged_enter(): yes, when one thread is about to dump core, has set +core_state, and is waiting for others, another might do something calling +__khugepaged_enter(), which now crashes because I lumped the core_state +test (known as "mmget_still_valid") into khugepaged_test_exit(). I still +think it's best to lump them together, so just in this exceptional case, +check mm->mm_users directly instead of khugepaged_test_exit(). + +Fixes: bbe98f9cadff ("khugepaged: khugepaged_test_exit() check mmget_still_valid()") +Reported-by: syzbot +Signed-off-by: Hugh Dickins +Signed-off-by: Andrew Morton +Acked-by: Yang Shi +Cc: "Kirill A. Shutemov" +Cc: Andrea Arcangeli +Cc: Song Liu +Cc: Mike Kravetz +Cc: Eric Dumazet +Cc: [4.8+] +Link: http://lkml.kernel.org/r/alpine.LSU.2.11.2008141503370.18085@eggly.anvils +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + mm/khugepaged.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/khugepaged.c b/mm/khugepaged.c +index 76e3e90dbc16e..3623d1c5343f2 100644 +--- a/mm/khugepaged.c ++++ b/mm/khugepaged.c +@@ -438,7 +438,7 @@ int __khugepaged_enter(struct mm_struct *mm) + return -ENOMEM; + + /* __khugepaged_exit() must not run from under us */ +- VM_BUG_ON_MM(khugepaged_test_exit(mm), mm); ++ VM_BUG_ON_MM(atomic_read(&mm->mm_users) == 0, mm); + if (unlikely(test_and_set_bit(MMF_VM_HUGEPAGE, &mm->flags))) { + free_mm_slot(mm_slot); + return 0; +-- +2.25.1 + diff --git a/queue-5.4/khugepaged-khugepaged_test_exit-check-mmget_still_va.patch b/queue-5.4/khugepaged-khugepaged_test_exit-check-mmget_still_va.patch new file mode 100644 index 00000000000..ad59e5d7c72 --- /dev/null +++ b/queue-5.4/khugepaged-khugepaged_test_exit-check-mmget_still_va.patch @@ -0,0 +1,60 @@ +From 7ca98fa06d15321ccb25f256a2a90bfbe2b456b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Aug 2020 23:26:25 -0700 +Subject: khugepaged: khugepaged_test_exit() check mmget_still_valid() + +From: Hugh Dickins + +[ Upstream commit bbe98f9cadff58cdd6a4acaeba0efa8565dabe65 ] + +Move collapse_huge_page()'s mmget_still_valid() check into +khugepaged_test_exit() itself. collapse_huge_page() is used for anon THP +only, and earned its mmget_still_valid() check because it inserts a huge +pmd entry in place of the page table's pmd entry; whereas +collapse_file()'s retract_page_tables() or collapse_pte_mapped_thp() +merely clears the page table's pmd entry. But core dumping without mmap +lock must have been as open to mistaking a racily cleared pmd entry for a +page table at physical page 0, as exit_mmap() was. And we certainly have +no interest in mapping as a THP once dumping core. + +Fixes: 59ea6d06cfa9 ("coredump: fix race condition between collapse_huge_page() and core dumping") +Signed-off-by: Hugh Dickins +Signed-off-by: Andrew Morton +Cc: Andrea Arcangeli +Cc: Song Liu +Cc: Mike Kravetz +Cc: Kirill A. Shutemov +Cc: [4.8+] +Link: http://lkml.kernel.org/r/alpine.LSU.2.11.2008021217020.27773@eggly.anvils +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + mm/khugepaged.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/mm/khugepaged.c b/mm/khugepaged.c +index 719f49d1fba2f..76e3e90dbc16e 100644 +--- a/mm/khugepaged.c ++++ b/mm/khugepaged.c +@@ -401,7 +401,7 @@ static void insert_to_mm_slots_hash(struct mm_struct *mm, + + static inline int khugepaged_test_exit(struct mm_struct *mm) + { +- return atomic_read(&mm->mm_users) == 0; ++ return atomic_read(&mm->mm_users) == 0 || !mmget_still_valid(mm); + } + + static bool hugepage_vma_check(struct vm_area_struct *vma, +@@ -1019,9 +1019,6 @@ static void collapse_huge_page(struct mm_struct *mm, + * handled by the anon_vma lock + PG_lock. + */ + down_write(&mm->mmap_sem); +- result = SCAN_ANY_PROCESS; +- if (!mmget_still_valid(mm)) +- goto out; + result = hugepage_vma_revalidate(mm, address, &vma); + if (result) + goto out; +-- +2.25.1 + diff --git a/queue-5.4/perf-probe-fix-memory-leakage-when-the-probe-point-i.patch b/queue-5.4/perf-probe-fix-memory-leakage-when-the-probe-point-i.patch new file mode 100644 index 00000000000..834e0b90ee0 --- /dev/null +++ b/queue-5.4/perf-probe-fix-memory-leakage-when-the-probe-point-i.patch @@ -0,0 +1,52 @@ +From 82731e6b83d69134614ca9e738a1519e3c8ad84d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Jul 2020 22:11:23 +0900 +Subject: perf probe: Fix memory leakage when the probe point is not found + +From: Masami Hiramatsu + +[ Upstream commit 12d572e785b15bc764e956caaa8a4c846fd15694 ] + +Fix the memory leakage in debuginfo__find_trace_events() when the probe +point is not found in the debuginfo. If there is no probe point found in +the debuginfo, debuginfo__find_probes() will NOT return -ENOENT, but 0. + +Thus the caller of debuginfo__find_probes() must check the tf.ntevs and +release the allocated memory for the array of struct probe_trace_event. + +The current code releases the memory only if the debuginfo__find_probes() +hits an error but not checks tf.ntevs. In the result, the memory allocated +on *tevs are not released if tf.ntevs == 0. + +This fixes the memory leakage by checking tf.ntevs == 0 in addition to +ret < 0. + +Fixes: ff741783506c ("perf probe: Introduce debuginfo to encapsulate dwarf information") +Signed-off-by: Masami Hiramatsu +Reviewed-by: Srikar Dronamraju +Cc: Andi Kleen +Cc: Oleg Nesterov +Cc: stable@vger.kernel.org +Link: http://lore.kernel.org/lkml/159438668346.62703.10887420400718492503.stgit@devnote2 +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Sasha Levin +--- + tools/perf/util/probe-finder.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c +index dc9d495e3d6ab..849d8d2e5976b 100644 +--- a/tools/perf/util/probe-finder.c ++++ b/tools/perf/util/probe-finder.c +@@ -1362,7 +1362,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, + tf.ntevs = 0; + + ret = debuginfo__find_probes(dbg, &tf.pf); +- if (ret < 0) { ++ if (ret < 0 || tf.ntevs == 0) { + for (i = 0; i < tf.ntevs; i++) + clear_probe_trace_event(&tf.tevs[i]); + zfree(tevs); +-- +2.25.1 + diff --git a/queue-5.4/series b/queue-5.4/series index 7f777ddb8be..22f4382ae54 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -7,3 +7,14 @@ kbuild-remove-python2-variable.patch kbuild-remove-as-variable.patch kbuild-replace-as-clang-with-llvm_ias-1.patch kbuild-support-llvm-1-to-switch-the-default-tools-to-clang-llvm.patch +drm-vgem-replace-opencoded-version-of-drm_gem_dumb_m.patch +gfs2-improve-mmap-write-vs.-punch_hole-consistency.patch +gfs2-never-call-gfs2_block_zero_range-with-an-open-t.patch +perf-probe-fix-memory-leakage-when-the-probe-point-i.patch +khugepaged-khugepaged_test_exit-check-mmget_still_va.patch +khugepaged-adjust-vm_bug_on_mm-in-__khugepaged_enter.patch +bcache-avoid-nr_stripes-overflow-in-bcache_device_in.patch +btrfs-export-helpers-for-subvolume-name-id-resolutio.patch +btrfs-don-t-show-full-path-of-bind-mounts-in-subvol.patch +btrfs-return-erofs-for-btrfs_fs_state_error-cases.patch +btrfs-add-wrapper-for-transaction-abort-predicate.patch