Commit af5feae3 authored by Linus Torvalds's avatar Linus Torvalds

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()
parents ce2814f2 977b7e3a
...@@ -52,14 +52,6 @@ struct wb_writeback_work { ...@@ -52,14 +52,6 @@ struct wb_writeback_work {
struct completion *done; /* set if the caller waits */ struct completion *done; /* set if the caller waits */
}; };
/*
* 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... * We don't actually have pdflush, but this one is exported though /proc...
*/ */
...@@ -92,6 +84,14 @@ static inline struct inode *wb_inode(struct list_head *head) ...@@ -92,6 +84,14 @@ static inline struct inode *wb_inode(struct list_head *head)
return list_entry(head, struct inode, i_wb_list); 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. */ /* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */
static void bdi_wakeup_flusher(struct backing_dev_info *bdi) static void bdi_wakeup_flusher(struct backing_dev_info *bdi)
{ {
......
...@@ -81,7 +81,11 @@ void prop_inc_percpu(struct prop_descriptor *pd, struct prop_local_percpu *pl) ...@@ -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 * Limit the time part in order to ensure there are some bits left for the
* cycle counter and fraction multiply. * cycle counter and fraction multiply.
*/ */
#if BITS_PER_LONG == 32
#define PROP_MAX_SHIFT (3*BITS_PER_LONG/4) #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_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1)
#define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT) #define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT)
......
...@@ -47,7 +47,10 @@ DECLARE_EVENT_CLASS(writeback_work_class, ...@@ -47,7 +47,10 @@ DECLARE_EVENT_CLASS(writeback_work_class,
__field(int, reason) __field(int, reason)
), ),
TP_fast_assign( 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->nr_pages = work->nr_pages;
__entry->sb_dev = work->sb ? work->sb->s_dev : 0; __entry->sb_dev = work->sb ? work->sb->s_dev : 0;
__entry->sync_mode = work->sync_mode; __entry->sync_mode = work->sync_mode;
...@@ -426,7 +429,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template, ...@@ -426,7 +429,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,
TP_fast_assign( TP_fast_assign(
strncpy(__entry->name, 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->ino = inode->i_ino;
__entry->state = inode->i_state; __entry->state = inode->i_state;
__entry->dirtied_when = inode->dirtied_when; __entry->dirtied_when = inode->dirtied_when;
......
...@@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned long data) ...@@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned long data)
if (bdi->wb.task) { if (bdi->wb.task) {
trace_writeback_wake_thread(bdi); trace_writeback_wake_thread(bdi);
wake_up_process(bdi->wb.task); wake_up_process(bdi->wb.task);
} else { } else if (bdi->dev) {
/* /*
* When bdi tasks are inactive for long time, they are killed. * When bdi tasks are inactive for long time, they are killed.
* In this case we have to wake-up the forker thread which * In this case we have to wake-up the forker thread which
...@@ -584,6 +584,8 @@ EXPORT_SYMBOL(bdi_register_dev); ...@@ -584,6 +584,8 @@ EXPORT_SYMBOL(bdi_register_dev);
*/ */
static void bdi_wb_shutdown(struct backing_dev_info *bdi) static void bdi_wb_shutdown(struct backing_dev_info *bdi)
{ {
struct task_struct *task;
if (!bdi_cap_writeback_dirty(bdi)) if (!bdi_cap_writeback_dirty(bdi))
return; return;
...@@ -602,8 +604,13 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi) ...@@ -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 * Finally, kill the kernel thread. We don't need to be RCU
* safe anymore, since the bdi is gone from visibility. * safe anymore, since the bdi is gone from visibility.
*/ */
if (bdi->wb.task) spin_lock_bh(&bdi->wb_lock);
kthread_stop(bdi->wb.task); 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) ...@@ -623,7 +630,9 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)
void bdi_unregister(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); bdi_set_min_ratio(bdi, 0);
trace_writeback_bdi_unregister(bdi); trace_writeback_bdi_unregister(bdi);
bdi_prune_sb(bdi); bdi_prune_sb(bdi);
...@@ -632,8 +641,12 @@ void bdi_unregister(struct backing_dev_info *bdi) ...@@ -632,8 +641,12 @@ void bdi_unregister(struct backing_dev_info *bdi)
if (!bdi_cap_flush_forker(bdi)) if (!bdi_cap_flush_forker(bdi))
bdi_wb_shutdown(bdi); bdi_wb_shutdown(bdi);
bdi_debug_unregister(bdi); bdi_debug_unregister(bdi);
device_unregister(bdi->dev);
spin_lock_bh(&bdi->wb_lock);
bdi->dev = NULL; bdi->dev = NULL;
spin_unlock_bh(&bdi->wb_lock);
device_unregister(dev);
} }
} }
EXPORT_SYMBOL(bdi_unregister); EXPORT_SYMBOL(bdi_unregister);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment