* [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup
@ 2015-09-25 2:37 Qu Wenruo
2015-09-25 2:38 ` [PATCH 1/2] btrfs: Add support to do stack item key operation Qu Wenruo
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Qu Wenruo @ 2015-09-25 2:37 UTC (permalink / raw)
To: linux-btrfs, stephane_btrfs
Stephane Lesimple reported an qgroup rescan bug:
[92098.841309] general protection fault: 0000 [#1] SMP
[92098.841338] Modules linked in: ...
[92098.841814] CPU: 1 PID: 24655 Comm: kworker/u4:12 Not tainted
4.3.0-rc1 #1
[92098.841868] Workqueue: btrfs-qgroup-rescan btrfs_qgroup_rescan_helper
[btrfs]
[92098.842261] Call Trace:
[92098.842277] [<ffffffffc035a5d8>] ? read_extent_buffer+0xb8/0x110
[btrfs]
[92098.842304] [<ffffffffc0396d00>] ? btrfs_find_all_roots+0x60/0x70
[btrfs]
[92098.842329] [<ffffffffc039af3d>]
btrfs_qgroup_rescan_worker+0x28d/0x5a0 [btrfs]
...
The triggering function btrfs_disk_key_to_cpu(), which should never
fail.
But it turned out that the extent_buffere being called on is memcpied
from an existing one.
Such behavior to copy a structure with page pointers and locks in it is
never a sane thing.
Fix it by do it in memory other than extent_buffer.
Qu Wenruo (2):
btrfs: Add support to do stack item key operation
btrfs: qgroup: Don't copy extent buffer to do qgroup rescan
fs/btrfs/ctree.h | 20 ++++++++++++++++++++
fs/btrfs/qgroup.c | 22 ++++++++++++----------
2 files changed, 32 insertions(+), 10 deletions(-)
--
2.5.3
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 1/2] btrfs: Add support to do stack item key operation 2015-09-25 2:37 [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Qu Wenruo @ 2015-09-25 2:38 ` Qu Wenruo 2015-10-01 16:46 ` David Sterba 2015-09-25 2:38 ` [PATCH 2/2] btrfs: qgroup: Don't copy extent buffer to do qgroup rescan Qu Wenruo 2015-09-25 22:35 ` [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Stéphane Lesimple 2 siblings, 1 reply; 6+ messages in thread From: Qu Wenruo @ 2015-09-25 2:38 UTC (permalink / raw) To: linux-btrfs, stephane_btrfs Normal btrfs_item_key_to_cpu() will need extent buffer to do it, and there is not stack version to handle in memory leaf. Add btrfs_stack_item_key_to_cpu() function for such operation, which will provide the basis for later qgroup fix. Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> --- fs/btrfs/ctree.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 938efe3..33e9d04 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2683,6 +2683,17 @@ static inline void btrfs_item_key(struct extent_buffer *eb, read_eb_member(eb, item, struct btrfs_item, key, disk_key); } +static inline void btrfs_stack_item_key(char *stack_leaf, + struct btrfs_disk_key *disk_key, + int nr) +{ + unsigned long item_offset = btrfs_item_nr_offset(nr); + struct btrfs_item *item; + + item = (struct btrfs_item *)(stack_leaf + item_offset); + memcpy(disk_key, &item->key, sizeof(*disk_key)); +} + static inline void btrfs_set_item_key(struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { @@ -2785,6 +2796,15 @@ static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb, btrfs_disk_key_to_cpu(key, &disk_key); } +static inline void btrfs_stack_item_key_to_cpu(char *stack_leaf, + struct btrfs_key *key, + int nr) +{ + struct btrfs_disk_key disk_key; + btrfs_stack_item_key(stack_leaf, &disk_key, nr); + btrfs_disk_key_to_cpu(key, &disk_key); +} + static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb, struct btrfs_dir_item *item, struct btrfs_key *key) -- 2.5.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] btrfs: Add support to do stack item key operation 2015-09-25 2:38 ` [PATCH 1/2] btrfs: Add support to do stack item key operation Qu Wenruo @ 2015-10-01 16:46 ` David Sterba 2015-10-02 1:08 ` Qu Wenruo 0 siblings, 1 reply; 6+ messages in thread From: David Sterba @ 2015-10-01 16:46 UTC (permalink / raw) To: Qu Wenruo; +Cc: linux-btrfs, stephane_btrfs On Fri, Sep 25, 2015 at 10:38:00AM +0800, Qu Wenruo wrote: > +static inline void btrfs_stack_item_key(char *stack_leaf, > + struct btrfs_disk_key *disk_key, > + int nr) > +static inline void btrfs_stack_item_key_to_cpu(char *stack_leaf, > + struct btrfs_key *key, > + int nr) The functions do not follow the pattern of btrfs_stack_* , also passing 'char *' is not right, it should be 'struct extent_buffer *'. IOW the manually created structure accessors must match the prototypes that would result from BTRFS_STACK_FUNCS and BTRFS_SETGET_STACK_FUNCS. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] btrfs: Add support to do stack item key operation 2015-10-01 16:46 ` David Sterba @ 2015-10-02 1:08 ` Qu Wenruo 0 siblings, 0 replies; 6+ messages in thread From: Qu Wenruo @ 2015-10-02 1:08 UTC (permalink / raw) To: dsterba, Qu Wenruo, linux-btrfs, stephane_btrfs 在 2015年10月02日 00:46, David Sterba 写道: > On Fri, Sep 25, 2015 at 10:38:00AM +0800, Qu Wenruo wrote: >> +static inline void btrfs_stack_item_key(char *stack_leaf, >> + struct btrfs_disk_key *disk_key, >> + int nr) > >> +static inline void btrfs_stack_item_key_to_cpu(char *stack_leaf, >> + struct btrfs_key *key, >> + int nr) > > The functions do not follow the pattern of btrfs_stack_*, The extent buffer version is btrfs_item_key() and btrfs_item_key_to_cpu() So I don't see the problem with the naming. Would you please pointing out what's wrong with the naming? > also passing > 'char *' is not right, it should be 'struct extent_buffer *'. The problem is, extent_buffer is not some thing we can operate directly in memory. It uses page pointer to do read/write. So we read out the real extent buffer content and do operation. I can change the struct name to btrfs_header, but not extent_buffer. > > IOW the manually created structure accessors must match the prototypes > that would result from BTRFS_STACK_FUNCS and BTRFS_SETGET_STACK_FUNCS. Unfortunately, the original btrfs_item_key() and its variants are not from BTRFS_STACK_FCUNS. Thanks, Qu > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] btrfs: qgroup: Don't copy extent buffer to do qgroup rescan 2015-09-25 2:37 [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Qu Wenruo 2015-09-25 2:38 ` [PATCH 1/2] btrfs: Add support to do stack item key operation Qu Wenruo @ 2015-09-25 2:38 ` Qu Wenruo 2015-09-25 22:35 ` [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Stéphane Lesimple 2 siblings, 0 replies; 6+ messages in thread From: Qu Wenruo @ 2015-09-25 2:38 UTC (permalink / raw) To: linux-btrfs, stephane_btrfs Ancient qgroup code call memcpy() on a extent buffer and use it for leaf iteration. As extent buffer contains lock, pointers to pages, it's never sane to do such copy. The following bug may be caused by this insane operation: [92098.841309] general protection fault: 0000 [#1] SMP [92098.841338] Modules linked in: ... [92098.841814] CPU: 1 PID: 24655 Comm: kworker/u4:12 Not tainted 4.3.0-rc1 #1 [92098.841868] Workqueue: btrfs-qgroup-rescan btrfs_qgroup_rescan_helper [btrfs] [92098.842261] Call Trace: [92098.842277] [<ffffffffc035a5d8>] ? read_extent_buffer+0xb8/0x110 [btrfs] [92098.842304] [<ffffffffc0396d00>] ? btrfs_find_all_roots+0x60/0x70 [btrfs] [92098.842329] [<ffffffffc039af3d>] btrfs_qgroup_rescan_worker+0x28d/0x5a0 [btrfs] Where btrfs_qgroup_rescan_worker+0x28d is btrfs_disk_key_to_cpu(), called in reading key from the memcpied extent_buffer. This patch will read the whole leaf into memory, and use newly introduced stack function to do qgroup rescan. Reported-by: Stephane Lesimple <stephane_btrfs@lesimple.fr> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> --- fs/btrfs/qgroup.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e9ace09..3b9221f 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2183,11 +2183,11 @@ void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) */ static int qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - struct btrfs_trans_handle *trans, - struct extent_buffer *scratch_leaf) + struct btrfs_trans_handle *trans, char *stack_leaf) { struct btrfs_key found; struct ulist *roots = NULL; + struct btrfs_header *header; struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); u64 num_bytes; int slot; @@ -2224,13 +2224,15 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, fs_info->qgroup_rescan_progress.objectid = found.objectid + 1; btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); - memcpy(scratch_leaf, path->nodes[0], sizeof(*scratch_leaf)); + read_extent_buffer(path->nodes[0], stack_leaf, 0, + fs_info->extent_root->nodesize); + header = (struct btrfs_header *)stack_leaf; slot = path->slots[0]; btrfs_release_path(path); mutex_unlock(&fs_info->qgroup_rescan_lock); - for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) { - btrfs_item_key_to_cpu(scratch_leaf, &found, slot); + for (; slot < btrfs_stack_header_nritems(header); ++slot) { + btrfs_stack_item_key_to_cpu(stack_leaf, &found, slot); if (found.type != BTRFS_EXTENT_ITEM_KEY && found.type != BTRFS_METADATA_ITEM_KEY) continue; @@ -2261,15 +2263,15 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) qgroup_rescan_work); struct btrfs_path *path; struct btrfs_trans_handle *trans = NULL; - struct extent_buffer *scratch_leaf = NULL; + char *stack_leaf = NULL; int err = -ENOMEM; int ret = 0; path = btrfs_alloc_path(); if (!path) goto out; - scratch_leaf = kmalloc(sizeof(*scratch_leaf), GFP_NOFS); - if (!scratch_leaf) + stack_leaf = kmalloc(fs_info->extent_root->nodesize, GFP_NOFS); + if (!stack_leaf) goto out; err = 0; @@ -2283,7 +2285,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) err = -EINTR; } else { err = qgroup_rescan_leaf(fs_info, path, trans, - scratch_leaf); + stack_leaf); } if (err > 0) btrfs_commit_transaction(trans, fs_info->fs_root); @@ -2292,7 +2294,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) } out: - kfree(scratch_leaf); + kfree(stack_leaf); btrfs_free_path(path); mutex_lock(&fs_info->qgroup_rescan_lock); -- 2.5.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup 2015-09-25 2:37 [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Qu Wenruo 2015-09-25 2:38 ` [PATCH 1/2] btrfs: Add support to do stack item key operation Qu Wenruo 2015-09-25 2:38 ` [PATCH 2/2] btrfs: qgroup: Don't copy extent buffer to do qgroup rescan Qu Wenruo @ 2015-09-25 22:35 ` Stéphane Lesimple 2 siblings, 0 replies; 6+ messages in thread From: Stéphane Lesimple @ 2015-09-25 22:35 UTC (permalink / raw) To: Qu Wenruo; +Cc: linux-btrfs Le 2015-09-25 04:37, Qu Wenruo a écrit : > Stephane Lesimple reported an qgroup rescan bug: > > [92098.841309] general protection fault: 0000 [#1] SMP > [92098.841338] Modules linked in: ... > [92098.841814] CPU: 1 PID: 24655 Comm: kworker/u4:12 Not tainted > 4.3.0-rc1 #1 > [92098.841868] Workqueue: btrfs-qgroup-rescan > btrfs_qgroup_rescan_helper > [btrfs] > [92098.842261] Call Trace: > [92098.842277] [<ffffffffc035a5d8>] ? read_extent_buffer+0xb8/0x110 > [btrfs] > [92098.842304] [<ffffffffc0396d00>] ? btrfs_find_all_roots+0x60/0x70 > [btrfs] > [92098.842329] [<ffffffffc039af3d>] > btrfs_qgroup_rescan_worker+0x28d/0x5a0 [btrfs] > ... > > The triggering function btrfs_disk_key_to_cpu(), which should never > fail. > But it turned out that the extent_buffere being called on is memcpied > from an existing one. > > Such behavior to copy a structure with page pointers and locks in it is > never a sane thing. > > Fix it by do it in memory other than extent_buffer. > > Qu Wenruo (2): > btrfs: Add support to do stack item key operation > btrfs: qgroup: Don't copy extent buffer to do qgroup rescan > > fs/btrfs/ctree.h | 20 ++++++++++++++++++++ > fs/btrfs/qgroup.c | 22 ++++++++++++---------- > 2 files changed, 32 insertions(+), 10 deletions(-) I applied this patch and ran 100+ rescans on my filesystem for several hours. No crash happened, where only a few rescans were enough to trigger the bug previously. I'm confident this patch fixes the GPF, thanks Qu ! -- Stéphane. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-10-02 1:08 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-09-25 2:37 [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Qu Wenruo 2015-09-25 2:38 ` [PATCH 1/2] btrfs: Add support to do stack item key operation Qu Wenruo 2015-10-01 16:46 ` David Sterba 2015-10-02 1:08 ` Qu Wenruo 2015-09-25 2:38 ` [PATCH 2/2] btrfs: qgroup: Don't copy extent buffer to do qgroup rescan Qu Wenruo 2015-09-25 22:35 ` [PATCH 0/2] Btrfs: Fix a insane extent_buffer copy behavior for qgroup Stéphane Lesimple
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).