diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-10 12:05:52 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-10 12:05:52 -0500 |
| commit | af5feae3d7e821d8c4d38103a7f53146f2590892 (patch) | |
| tree | 9017bb0661fb617177534f0617c3771d89e31afc | |
| parent | ce2814f227d3adae8456f7cbd0bd5f922fd284f0 (diff) | |
| parent | 977b7e3a52a7421ad33a393a38ece59f3d41c2fa (diff) | |
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()
| -rw-r--r-- | fs/fs-writeback.c | 16 | ||||
| -rw-r--r-- | include/linux/proportions.h | 4 | ||||
| -rw-r--r-- | include/trace/events/writeback.h | 7 | ||||
| -rw-r--r-- | mm/backing-dev.c | 23 |
4 files changed, 35 insertions, 15 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index f855916657ba..5b4a9362d5aa 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -53,14 +53,6 @@ struct wb_writeback_work { | |||
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | /* | 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 | |||
| 63 | /* | ||
| 64 | * We don't actually have pdflush, but this one is exported though /proc... | 56 | * We don't actually have pdflush, but this one is exported though /proc... |
| 65 | */ | 57 | */ |
| 66 | int nr_pdflush_threads; | 58 | int nr_pdflush_threads; |
| @@ -92,6 +84,14 @@ static inline struct inode *wb_inode(struct list_head *head) | |||
| 92 | return list_entry(head, struct inode, i_wb_list); | 84 | return list_entry(head, struct inode, i_wb_list); |
| 93 | } | 85 | } |
| 94 | 86 | ||
| 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 | |||
| 95 | /* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */ | 95 | /* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */ |
| 96 | static void bdi_wakeup_flusher(struct backing_dev_info *bdi) | 96 | static void bdi_wakeup_flusher(struct backing_dev_info *bdi) |
| 97 | { | 97 | { |
diff --git a/include/linux/proportions.h b/include/linux/proportions.h index ef35bb73f69b..26a8a4ed9b07 100644 --- a/include/linux/proportions.h +++ b/include/linux/proportions.h | |||
| @@ -81,7 +81,11 @@ void prop_inc_percpu(struct prop_descriptor *pd, struct prop_local_percpu *pl) | |||
| 81 | * Limit the time part in order to ensure there are some bits left for the | 81 | * Limit the time part in order to ensure there are some bits left for the |
| 82 | * cycle counter and fraction multiply. | 82 | * cycle counter and fraction multiply. |
| 83 | */ | 83 | */ |
| 84 | #if BITS_PER_LONG == 32 | ||
| 84 | #define PROP_MAX_SHIFT (3*BITS_PER_LONG/4) | 85 | #define PROP_MAX_SHIFT (3*BITS_PER_LONG/4) |
| 86 | #else | ||
| 87 | #define PROP_MAX_SHIFT (BITS_PER_LONG/2) | ||
| 88 | #endif | ||
| 85 | 89 | ||
| 86 | #define PROP_FRAC_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1) | 90 | #define PROP_FRAC_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1) |
| 87 | #define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT) | 91 | #define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT) |
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index 8588a8918023..5973410e8f8c 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h | |||
| @@ -47,7 +47,10 @@ DECLARE_EVENT_CLASS(writeback_work_class, | |||
| 47 | __field(int, reason) | 47 | __field(int, reason) |
| 48 | ), | 48 | ), |
| 49 | TP_fast_assign( | 49 | 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); | ||
| 51 | __entry->nr_pages = work->nr_pages; | 54 | __entry->nr_pages = work->nr_pages; |
| 52 | __entry->sb_dev = work->sb ? work->sb->s_dev : 0; | 55 | __entry->sb_dev = work->sb ? work->sb->s_dev : 0; |
| 53 | __entry->sync_mode = work->sync_mode; | 56 | __entry->sync_mode = work->sync_mode; |
| @@ -426,7 +429,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template, | |||
| 426 | 429 | ||
| 427 | TP_fast_assign( | 430 | TP_fast_assign( |
| 428 | strncpy(__entry->name, | 431 | strncpy(__entry->name, |
| 429 | dev_name(inode->i_mapping->backing_dev_info->dev), 32); | 432 | dev_name(inode_to_bdi(inode)->dev), 32); |
| 430 | __entry->ino = inode->i_ino; | 433 | __entry->ino = inode->i_ino; |
| 431 | __entry->state = inode->i_state; | 434 | __entry->state = inode->i_state; |
| 432 | __entry->dirtied_when = inode->dirtied_when; | 435 | __entry->dirtied_when = inode->dirtied_when; |
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 7ba8feae11b8..dd8e2aafb07e 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
| @@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned long data) | |||
| 318 | if (bdi->wb.task) { | 318 | if (bdi->wb.task) { |
| 319 | trace_writeback_wake_thread(bdi); | 319 | trace_writeback_wake_thread(bdi); |
| 320 | wake_up_process(bdi->wb.task); | 320 | wake_up_process(bdi->wb.task); |
| 321 | } else { | 321 | } else if (bdi->dev) { |
| 322 | /* | 322 | /* |
| 323 | * When bdi tasks are inactive for long time, they are killed. | 323 | * When bdi tasks are inactive for long time, they are killed. |
| 324 | * In this case we have to wake-up the forker thread which | 324 | * In this case we have to wake-up the forker thread which |
| @@ -584,6 +584,8 @@ EXPORT_SYMBOL(bdi_register_dev); | |||
| 584 | */ | 584 | */ |
| 585 | static void bdi_wb_shutdown(struct backing_dev_info *bdi) | 585 | static void bdi_wb_shutdown(struct backing_dev_info *bdi) |
| 586 | { | 586 | { |
| 587 | struct task_struct *task; | ||
| 588 | |||
| 587 | if (!bdi_cap_writeback_dirty(bdi)) | 589 | if (!bdi_cap_writeback_dirty(bdi)) |
| 588 | return; | 590 | return; |
| 589 | 591 | ||
| @@ -602,8 +604,13 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi) | |||
| 602 | * Finally, kill the kernel thread. We don't need to be RCU | 604 | * Finally, kill the kernel thread. We don't need to be RCU |
| 603 | * safe anymore, since the bdi is gone from visibility. | 605 | * safe anymore, since the bdi is gone from visibility. |
| 604 | */ | 606 | */ |
| 605 | if (bdi->wb.task) | 607 | spin_lock_bh(&bdi->wb_lock); |
| 606 | kthread_stop(bdi->wb.task); | 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); | ||
| 607 | } | 614 | } |
| 608 | 615 | ||
| 609 | /* | 616 | /* |
| @@ -623,7 +630,9 @@ static void bdi_prune_sb(struct backing_dev_info *bdi) | |||
| 623 | 630 | ||
| 624 | void bdi_unregister(struct backing_dev_info *bdi) | 631 | void bdi_unregister(struct backing_dev_info *bdi) |
| 625 | { | 632 | { |
| 626 | if (bdi->dev) { | 633 | struct device *dev = bdi->dev; |
| 634 | |||
| 635 | if (dev) { | ||
| 627 | bdi_set_min_ratio(bdi, 0); | 636 | bdi_set_min_ratio(bdi, 0); |
| 628 | trace_writeback_bdi_unregister(bdi); | 637 | trace_writeback_bdi_unregister(bdi); |
| 629 | bdi_prune_sb(bdi); | 638 | bdi_prune_sb(bdi); |
| @@ -632,8 +641,12 @@ void bdi_unregister(struct backing_dev_info *bdi) | |||
| 632 | if (!bdi_cap_flush_forker(bdi)) | 641 | if (!bdi_cap_flush_forker(bdi)) |
| 633 | bdi_wb_shutdown(bdi); | 642 | bdi_wb_shutdown(bdi); |
| 634 | bdi_debug_unregister(bdi); | 643 | bdi_debug_unregister(bdi); |
| 635 | device_unregister(bdi->dev); | 644 | |
| 645 | spin_lock_bh(&bdi->wb_lock); | ||
| 636 | bdi->dev = NULL; | 646 | bdi->dev = NULL; |
| 647 | spin_unlock_bh(&bdi->wb_lock); | ||
| 648 | |||
| 649 | device_unregister(dev); | ||
| 637 | } | 650 | } |
| 638 | } | 651 | } |
| 639 | EXPORT_SYMBOL(bdi_unregister); | 652 | EXPORT_SYMBOL(bdi_unregister); |
