writeback fixes
Subsystems (5)
Linus,
Please pull 4 writeback fixes for
- 1 divide error
- 3 NULL dereference bugs in writeback tracing, when SD card is removed w/o umount
Thanks,
Fengguang
The following changes since commit 62aa2b537c6f5957afd98e29f96897419ed5ebab:
Linux 3.3-rc2 (2012-01-31 13:31:54 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/wfg/linux.git writeback-fixes
Rabin Vincent (1):
backing-dev: fix wakeup timer races with bdi_unregister()
Wu Fengguang (3):
writeback: fix NULL bdi->dev in trace writeback_single_inode
lib: proportion: lower PROP_MAX_SHIFT to 32 on 64-bit kernel
writeback: fix dereferencing NULL bdi->dev on trace_writeback_queuefs/fs-writeback.c | 16 ++++++++-------- include/linux/proportions.h | 4 ++++ include/trace/events/writeback.h | 7 +++++-- mm/backing-dev.c | 23 ++++++++++++++++++----- 4 files changed, 35 insertions(+), 15 deletions(-)
fs/fs-writeback.c +8 -8
@@ -53,14 +53,6 @@ struct wb_writeback_work { };/* -* Include the creation of the trace points after defining the -* wb_writeback_work structure so that the definition remains local to this -* file. -*/ -#define CREATE_TRACE_POINTS -#include <trace/events/writeback.h> - -/* * We don't actually have pdflush, but this one is exported though /proc... */ int nr_pdflush_threads;
@@ -92,6 +84,14 @@ static inline struct inode *wb_inode(struct list_head *head) return list_entry(head, struct inode, i_wb_list); } +/* +* Include the creation of the trace points after defining the +* wb_writeback_work structure and inline functions so that the definition +* remains local to this file. +*/ +#define CREATE_TRACE_POINTS +#include <trace/events/writeback.h> +/* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */ static void bdi_wakeup_flusher (struct backing_dev_info *bdi) {
include/linux/proportions.h +4 -0
@@ -81,7 +81,11 @@ void prop_inc_percpu(struct prop_descriptor *pd, struct prop_local_percpu *pl)* Limit the time part in order to ensure there are some bits left for the * cycle counter and fraction multiply. */ +#if BITS_PER_LONG ==32 #define PROP_MAX_SHIFT (3*BITS_PER_LONG/4) +#else +#define PROP_MAX_SHIFT (BITS_PER_LONG/2) +#endif #define PROP_FRAC_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1)#define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT)
include/trace/events/writeback.h +5 -2
@@ -47,7 +47,10 @@ DECLARE_EVENT_CLASS(writeback_work_class,__field (int, reason) ),TP_fast_assign ( - strncpy(__entry->name, dev_name(bdi->dev), 32); + struct device *dev = bdi->dev; +if (!dev) + dev = default_backing_dev_info.dev; +strncpy (__entry->name,dev_name (dev),32 ); __entry->nr_pages = work->nr_pages; __entry->sb_dev = work->sb ? work->sb->s_dev :0 ; __entry->sync_mode = work->sync_mode;
@@ -426,7 +429,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,TP_fast_assign (strncpy (__entry->name, - dev_name(inode->i_mapping->backing_dev_info->dev), 32); + dev_name(inode_to_bdi(inode)->dev), 32); __entry->ino = inode->i_ino; __entry->state = inode->i_state; __entry->dirtied_when = inode->dirtied_when;
mm/backing-dev.c +18 -5
@@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned long data)if (bdi->wb.task) {trace_writeback_wake_thread (bdi);wake_up_process (bdi->wb.task); - }else { + }else if (bdi->dev) {/* * When bdi tasks are inactive for long time, they are killed. * In this case we have to wake-up the forker thread which
@@ -584,6 +584,8 @@ EXPORT_SYMBOL(bdi_register_dev);*/ static void bdi_wb_shutdown (struct backing_dev_info *bdi) { +struct task_struct *task; +if (!bdi_cap_writeback_dirty (bdi))return ;
@@ -602,8 +604,13 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)* Finally, kill the kernel thread. We don't need to be RCU * safe anymore, since the bdi is gone from visibility. */ -if (bdi->wb.task) -kthread_stop (bdi->wb.task); +spin_lock_bh (&bdi->wb_lock); + task = bdi->wb.task; + bdi->wb.task =NULL ; +spin_unlock_bh (&bdi->wb_lock); + +if (task) +kthread_stop (task); }/*
@@ -623,7 +630,9 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)void bdi_unregister (struct backing_dev_info *bdi) { -if (bdi->dev) { +struct device *dev = bdi->dev; + +if (dev) {bdi_set_min_ratio (bdi,0 );trace_writeback_bdi_unregister (bdi);bdi_prune_sb (bdi);
@@ -632,8 +641,12 @@ void bdi_unregister(struct backing_dev_info *bdi)if (!bdi_cap_flush_forker (bdi))bdi_wb_shutdown (bdi);bdi_debug_unregister (bdi); -device_unregister (bdi->dev); + +spin_lock_bh (&bdi->wb_lock); bdi->dev =NULL ; +spin_unlock_bh (&bdi->wb_lock); + +device_unregister (dev); } }EXPORT_SYMBOL (bdi_unregister);