Skip to content

Commit af5feae

Browse files
committed
Merge tag 'writeback-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/wfg/linux
fix 1 mysterious divide error fix 3 NULL dereference bugs in writeback tracing, on SD card removal w/o umount * tag 'writeback-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/wfg/linux: writeback: fix dereferencing NULL bdi->dev on trace_writeback_queue lib: proportion: lower PROP_MAX_SHIFT to 32 on 64-bit kernel writeback: fix NULL bdi->dev in trace writeback_single_inode backing-dev: fix wakeup timer races with bdi_unregister()
2 parents ce2814f + 977b7e3 commit af5feae

File tree

4 files changed

+35
-15
lines changed

4 files changed

+35
-15
lines changed

fs/fs-writeback.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,6 @@ struct wb_writeback_work {
5252
struct completion *done; /* set if the caller waits */
5353
};
5454

55-
/*
56-
* Include the creation of the trace points after defining the
57-
* wb_writeback_work structure so that the definition remains local to this
58-
* file.
59-
*/
60-
#define CREATE_TRACE_POINTS
61-
#include <trace/events/writeback.h>
62-
6355
/*
6456
* We don't actually have pdflush, but this one is exported though /proc...
6557
*/
@@ -92,6 +84,14 @@ static inline struct inode *wb_inode(struct list_head *head)
9284
return list_entry(head, struct inode, i_wb_list);
9385
}
9486

87+
/*
88+
* Include the creation of the trace points after defining the
89+
* wb_writeback_work structure and inline functions so that the definition
90+
* remains local to this file.
91+
*/
92+
#define CREATE_TRACE_POINTS
93+
#include <trace/events/writeback.h>
94+
9595
/* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */
9696
static void bdi_wakeup_flusher(struct backing_dev_info *bdi)
9797
{

include/linux/proportions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ void prop_inc_percpu(struct prop_descriptor *pd, struct prop_local_percpu *pl)
8181
* Limit the time part in order to ensure there are some bits left for the
8282
* cycle counter and fraction multiply.
8383
*/
84+
#if BITS_PER_LONG == 32
8485
#define PROP_MAX_SHIFT (3*BITS_PER_LONG/4)
86+
#else
87+
#define PROP_MAX_SHIFT (BITS_PER_LONG/2)
88+
#endif
8589

8690
#define PROP_FRAC_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1)
8791
#define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT)

include/trace/events/writeback.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ DECLARE_EVENT_CLASS(writeback_work_class,
4747
__field(int, reason)
4848
),
4949
TP_fast_assign(
50-
strncpy(__entry->name, dev_name(bdi->dev), 32);
50+
struct device *dev = bdi->dev;
51+
if (!dev)
52+
dev = default_backing_dev_info.dev;
53+
strncpy(__entry->name, dev_name(dev), 32);
5154
__entry->nr_pages = work->nr_pages;
5255
__entry->sb_dev = work->sb ? work->sb->s_dev : 0;
5356
__entry->sync_mode = work->sync_mode;
@@ -426,7 +429,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,
426429

427430
TP_fast_assign(
428431
strncpy(__entry->name,
429-
dev_name(inode->i_mapping->backing_dev_info->dev), 32);
432+
dev_name(inode_to_bdi(inode)->dev), 32);
430433
__entry->ino = inode->i_ino;
431434
__entry->state = inode->i_state;
432435
__entry->dirtied_when = inode->dirtied_when;

mm/backing-dev.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned long data)
318318
if (bdi->wb.task) {
319319
trace_writeback_wake_thread(bdi);
320320
wake_up_process(bdi->wb.task);
321-
} else {
321+
} else if (bdi->dev) {
322322
/*
323323
* When bdi tasks are inactive for long time, they are killed.
324324
* In this case we have to wake-up the forker thread which
@@ -584,6 +584,8 @@ EXPORT_SYMBOL(bdi_register_dev);
584584
*/
585585
static void bdi_wb_shutdown(struct backing_dev_info *bdi)
586586
{
587+
struct task_struct *task;
588+
587589
if (!bdi_cap_writeback_dirty(bdi))
588590
return;
589591

@@ -602,8 +604,13 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
602604
* Finally, kill the kernel thread. We don't need to be RCU
603605
* safe anymore, since the bdi is gone from visibility.
604606
*/
605-
if (bdi->wb.task)
606-
kthread_stop(bdi->wb.task);
607+
spin_lock_bh(&bdi->wb_lock);
608+
task = bdi->wb.task;
609+
bdi->wb.task = NULL;
610+
spin_unlock_bh(&bdi->wb_lock);
611+
612+
if (task)
613+
kthread_stop(task);
607614
}
608615

609616
/*
@@ -623,7 +630,9 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)
623630

624631
void bdi_unregister(struct backing_dev_info *bdi)
625632
{
626-
if (bdi->dev) {
633+
struct device *dev = bdi->dev;
634+
635+
if (dev) {
627636
bdi_set_min_ratio(bdi, 0);
628637
trace_writeback_bdi_unregister(bdi);
629638
bdi_prune_sb(bdi);
@@ -632,8 +641,12 @@ void bdi_unregister(struct backing_dev_info *bdi)
632641
if (!bdi_cap_flush_forker(bdi))
633642
bdi_wb_shutdown(bdi);
634643
bdi_debug_unregister(bdi);
635-
device_unregister(bdi->dev);
644+
645+
spin_lock_bh(&bdi->wb_lock);
636646
bdi->dev = NULL;
647+
spin_unlock_bh(&bdi->wb_lock);
648+
649+
device_unregister(dev);
637650
}
638651
}
639652
EXPORT_SYMBOL(bdi_unregister);

0 commit comments

Comments
 (0)