I'm testing SD card removal, and with tracing enabled I'm seeing a crash in the writeback:single_inode event sometimes when a umount is done after a card is removed with pending io. When the problem occurs, writeback is begin attempted with the default_backing_dev_info. The block bdi which was handling this device has been unregistered and it's bdi->dev is NULL. However it is still referenced by inode->i_mapping->backing_dev_info, and the trace point does the following, leading to the oops: TP_fast_assign( strncpy(__entry->name, dev_name(inode->i_mapping->backing_dev_info->dev), 32); umount-33 0.... 10973110us : writeback_inodes_sb <-__sync_filesystem umount-33 0.... 10973248us : writeback_inodes_sb_nr <-__sync_filesystem umount-33 0.... 10973289us : bdi_queue_work <-writeback_inodes_sb_nr umount-33 0...1 10973336us : writeback_queue: bdi default: sb_dev 179:0 nr_pages=2153 sync_mode=0 kupdate=0 range_cyclic=0 background=0 reason=sync bdi-defa-14 1.... 10974021us : wb_do_writeback <-bdi_forker_thread bdi-defa-14 1...1 10974041us : writeback_exec: bdi default: sb_dev 179:0 nr_pages=2153 sync_mode=0 kupdate=0 range_cyclic=0 background=0 reason=sync bdi-defa-14 1.... 10974053us : wb_writeback <-wb_do_writeback bdi-defa-14 1...2 10974059us : writeback_start: bdi default: sb_dev 179:0 nr_pages=2153 sync_mode=0 kupdate=0 range_cyclic=0 background=0 reason=sync bdi-defa-14 1...2 10974093us : writeback_queue_io: bdi default: older=4294939114 age=0 enqueue=2 reason=sync bdi-defa-14 1...1 10974101us : writeback_sb_inodes <-wb_writeback bdi-defa-14 1...2 10974166us : writeback_single_inode <-writeback_sb_inodes Unable to handle kernel NULL pointer dereference at virtual address 0000002c pgd = c0004000 [0000002c] *pgd=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP PC is at ftrace_raw_event_writeback_single_inode_template+0x60/0xe4 LR is at ftrace_raw_event_writeback_single_inode_template+0x50/0xe4 The full trace+log is attached. My kernel (current linus) has a delay inserted in __mark_inode_dirty, to easily trigger the condition: diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index f855916..424a655 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1057,6 +1057,7 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode) * page->mapping->host, so the page-dirtying time is recorded in the internal * blockdev inode. */ +#include void __mark_inode_dirty(struct inode *inode, int flags) { struct super_block *sb = inode->i_sb; @@ -1131,6 +1132,8 @@ void __mark_inode_dirty(struct inode *inode, int flags) wakeup_bdi = true; } + trace_printk("bdi %s\n", bdi->name); + spin_unlock(&inode->i_lock); spin_lock(&bdi->wb.list_lock); inode->dirtied_when = jiffies; @@ -1139,6 +1142,14 @@ void __mark_inode_dirty(struct inode *inode, int flags) if (wakeup_bdi) bdi_wakeup_thread_delayed(bdi); + + if (!strcmp(bdi->name, "block")) { + printk("waiting 6s, remove card\n"); + trace_printk("waiting 6s, remove card\n"); + msleep(6000); + printk("done waiting\n"); + trace_printk("done waiting\n"); + } return; } }