From: Eric Biggers <ebiggers@kernel.org>
To: Chao Yu <chao@kernel.org>
Cc: Dan Carpenter <dan.carpenter@oracle.com>,
linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [bug report] f2fs: use rb_*_cached friends
Date: Thu, 10 Jan 2019 14:51:21 -0800 [thread overview]
Message-ID: <20190110225119.GE149637@gmail.com> (raw)
In-Reply-To: <de7d9aa6-b828-f2d9-4568-bfc758fad9d0@kernel.org>
Hi Chao,
On Fri, Oct 12, 2018 at 10:00:20PM +0800, Chao Yu wrote:
> Hi Dan,
>
> Firstly, thanks for the report. :)
>
> On 2018-10-11 20:23, Dan Carpenter wrote:
> > Hello Chao Yu,
> >
> > The patch df634f444ee9: "f2fs: use rb_*_cached friends" from Oct 4,
> > 2018, leads to the following static checker warning:
> >
> > fs/f2fs/extent_cache.c:606 f2fs_update_extent_tree_range()
> > error: uninitialized symbol 'leftmost'.
> >
> > fs/f2fs/extent_cache.c
> > 497 static void f2fs_update_extent_tree_range(struct inode *inode,
> > 498 pgoff_t fofs, block_t blkaddr, unsigned int len)
> > 499 {
> > 500 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> > 501 struct extent_tree *et = F2FS_I(inode)->extent_tree;
> > 502 struct extent_node *en = NULL, *en1 = NULL;
> > 503 struct extent_node *prev_en = NULL, *next_en = NULL;
> > 504 struct extent_info ei, dei, prev;
> > 505 struct rb_node **insert_p = NULL, *insert_parent = NULL;
> > 506 unsigned int end = fofs + len;
> > 507 unsigned int pos = (unsigned int)fofs;
> > 508 bool updated = false;
> > 509 bool leftmost;
> > 510
> > 511 if (!et)
> > 512 return;
> > 513
> > 514 trace_f2fs_update_extent_tree_range(inode, fofs, blkaddr, len);
> > 515
> > 516 write_lock(&et->lock);
> > 517
> > 518 if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
> > 519 write_unlock(&et->lock);
> > 520 return;
> > 521 }
> > 522
> > 523 prev = et->largest;
> > 524 dei.len = 0;
> > 525
> > 526 /*
> > 527 * drop largest extent before lookup, in case it's already
> > 528 * been shrunk from extent tree
> > 529 */
> > 530 __drop_largest_extent(et, fofs, len);
> > 531
> > 532 /* 1. lookup first extent node in range [fofs, fofs + len - 1] */
> > 533 en = (struct extent_node *)f2fs_lookup_rb_tree_ret(&et->root,
> > 534 (struct rb_entry *)et->cached_en, fofs,
> > 535 (struct rb_entry **)&prev_en,
> > 536 (struct rb_entry **)&next_en,
> > 537 &insert_p, &insert_parent, false,
> > 538 &leftmost);
> > ^^^^^^^^
> > Not always initialized in there.
>
> I think the behavior should be acting as designed.
>
> f2fs_lookup_rb_tree_ret()
> {
> ...
> *insert_p = NULL;
> *insert_parent = NULL;
> *prev_entry = NULL;
> *next_entry = NULL;
>
> if (RB_EMPTY_ROOT(&root->rb_root))
> return NULL;
>
> if (re) {
> if (re->ofs <= ofs && re->ofs + re->len > ofs)
> goto lookup_neighbors;
> }
>
> Until here, @leftmost has not been initialized, but both *insert_p and
> *insert_parent are NULL,
>
> if (leftmost)
> *leftmost = true;
> ...
> }
>
> Later in __insert_extent_tree()
>
> we will not hit below condition because insert_p & insert_parent are not valid:
> if (insert_p && insert_parent) {
> parent = insert_parent;
> p = insert_p;
> goto do_insert;
> }
>
> leftmost = true;
>
> So finally, we will initialize leftmost's value here, anyway, I think there is
> such place we use an uninitialized variable.
>
> BTW, do we have any chance to detect such case in smatch?
>
> Thanks,
>
> >
> > 539 if (!en)
> > 540 en = next_en;
> > 541
> > 542 /* 2. invlidate all extent nodes in range [fofs, fofs + len - 1] */
> > 543 while (en && en->ei.fofs < end) {
> > 544 unsigned int org_end;
> > 545 int parts = 0; /* # of parts current extent split into */
> > 546
> > 547 next_en = en1 = NULL;
> > 548
> > 549 dei = en->ei;
> > 550 org_end = dei.fofs + dei.len;
> > 551 f2fs_bug_on(sbi, pos >= org_end);
> > 552
> > 553 if (pos > dei.fofs && pos - dei.fofs >= F2FS_MIN_EXTENT_LEN) {
> > 554 en->ei.len = pos - en->ei.fofs;
> > 555 prev_en = en;
> > 556 parts = 1;
> > 557 }
> > 558
> > 559 if (end < org_end && org_end - end >= F2FS_MIN_EXTENT_LEN) {
> > 560 if (parts) {
> > 561 set_extent_info(&ei, end,
> > 562 end - dei.fofs + dei.blk,
> > 563 org_end - end);
> > 564 en1 = __insert_extent_tree(sbi, et, &ei,
> > 565 NULL, NULL, true);
> > 566 next_en = en1;
> > 567 } else {
> > 568 en->ei.fofs = end;
> > 569 en->ei.blk += end - dei.fofs;
> > 570 en->ei.len -= end - dei.fofs;
> > 571 next_en = en;
> > 572 }
> > 573 parts++;
> > 574 }
> > 575
> > 576 if (!next_en) {
> > 577 struct rb_node *node = rb_next(&en->rb_node);
> > 578
> > 579 next_en = rb_entry_safe(node, struct extent_node,
> > 580 rb_node);
> > 581 }
> > 582
> > 583 if (parts)
> > 584 __try_update_largest_extent(et, en);
> > 585 else
> > 586 __release_extent_node(sbi, et, en);
> > 587
> > 588 /*
> > 589 * if original extent is split into zero or two parts, extent
> > 590 * tree has been altered by deletion or insertion, therefore
> > 591 * invalidate pointers regard to tree.
> > 592 */
> > 593 if (parts != 1) {
> > 594 insert_p = NULL;
> > 595 insert_parent = NULL;
> > 596 }
> > 597 en = next_en;
> > 598 }
> > 599
> > 600 /* 3. update extent in extent cache */
> > 601 if (blkaddr) {
> > 602
> > 603 set_extent_info(&ei, fofs, blkaddr, len);
> > 604 if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
> > 605 __insert_extent_tree(sbi, et, &ei,
> > 606 insert_p, insert_parent, leftmost);
> > ^^^^^^^^
> > Smatch complains, but I'm to stupid to know if it's valid.
> >
> > 607
> > 608 /* give up extent_cache, if split and small updates happen */
> > 609 if (dei.len >= 1 &&
> > 610 prev.len < F2FS_MIN_EXTENT_LEN &&
> > 611 et->largest.len < F2FS_MIN_EXTENT_LEN) {
> > 612 et->largest.len = 0;
> > 613 et->largest_updated = true;
> > 614 set_inode_flag(inode, FI_NO_EXTENT);
> > 615 }
> > 616 }
> >
> > regards,
> > dan carpenter
> >
I get an UBSAN warning on this same line, so this seems to be a real bug.
It goes away if I initialize 'leftmost'.
To reproduce, build a kernel with CONFIG_F2FS_FS=y CONFIG_F2FS_FS_ENCRYPTION=y
CONFIG_UBSAN=y CONFIG_KASAN=y and run 'kvm-xfstests -c f2fs generic/397'.
(There's probably a better reproducer, but that's how I saw it.)
This is on latest mainline.
================================================================================
UBSAN: Undefined behaviour in fs/f2fs/extent_cache.c:605:4
load of value 255 is not a valid value for type '_Bool'
CPU: 0 PID: 94 Comm: kworker/u4:2 Not tainted 5.0.0-rc1-00043-g1bdbe22749207 #14
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
Workqueue: writeback wb_workfn (flush-254:32)
Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0x70/0xa5 lib/dump_stack.c:113
ubsan_epilogue+0xd/0x40 lib/ubsan.c:159
__ubsan_handle_load_invalid_value+0x8e/0xa0 lib/ubsan.c:457
f2fs_update_extent_tree_range+0x6e9/0x760 fs/f2fs/extent_cache.c:605
f2fs_update_extent_cache+0xce/0xf0 fs/f2fs/extent_cache.c:804
f2fs_update_data_blkaddr+0x18/0x20 fs/f2fs/data.c:639
f2fs_outplace_write_data+0x63/0x130 fs/f2fs/segment.c:3147
f2fs_do_write_data_page+0x3ae/0x7e0 fs/f2fs/data.c:1892
__write_data_page+0x734/0xd00 fs/f2fs/data.c:1993
f2fs_write_cache_pages+0x1fb/0x610 fs/f2fs/data.c:2160
__f2fs_write_data_pages fs/f2fs/data.c:2273 [inline]
f2fs_write_data_pages+0x3dc/0x450 fs/f2fs/data.c:2300
do_writepages+0x43/0xf0 mm/page-writeback.c:2335
__writeback_single_inode+0x56/0x660 fs/fs-writeback.c:1316
writeback_sb_inodes+0x20b/0x6b0 fs/fs-writeback.c:1580
wb_writeback+0x10f/0x510 fs/fs-writeback.c:1756
wb_do_writeback fs/fs-writeback.c:1901 [inline]
wb_workfn+0xa7/0x670 fs/fs-writeback.c:1942
process_one_work+0x25d/0x670 kernel/workqueue.c:2153
worker_thread+0x3e/0x3d0 kernel/workqueue.c:2296
kthread+0x124/0x140 kernel/kthread.c:246
ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352
================================================================================
next prev parent reply other threads:[~2019-01-10 22:51 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-11 12:23 [bug report] f2fs: use rb_*_cached friends Dan Carpenter
2018-10-12 14:00 ` Chao Yu
2018-10-12 14:18 ` Dan Carpenter
2018-10-12 14:31 ` Chao Yu
2019-01-10 22:51 ` Eric Biggers [this message]
2019-01-11 2:00 ` Chao Yu
2019-01-11 6:55 ` Dan Carpenter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190110225119.GE149637@gmail.com \
--to=ebiggers@kernel.org \
--cc=chao@kernel.org \
--cc=dan.carpenter@oracle.com \
--cc=linux-f2fs-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.