--- linux.orig/fs/fs-writeback.c 2009-09-21 20:09:22.000000000 +0800 +++ linux/fs/fs-writeback.c 2009-09-21 21:00:56.000000000 +0800 @@ -68,6 +68,30 @@ enum { #define WS_USED (1 << WS_USED_B) #define WS_ONSTACK (1 << WS_ONSTACK_B) +void print_writeback_control(struct writeback_control *wbc) +{ + printk(KERN_DEBUG + "global dirty=%lu writeback=%lu nfs=%lu " + "flags=%c%c towrite=%ld skipped=%ld\n", + global_page_state(NR_FILE_DIRTY), + global_page_state(NR_WRITEBACK), + global_page_state(NR_UNSTABLE_NFS), + wbc->encountered_congestion ? 'C':'_', + wbc->more_io ? 'M':'_', + wbc->nr_to_write, + wbc->pages_skipped); +} + +void __writeback_debug_report(long n, struct writeback_control *wbc, + const char *file, int line, const char *func) +{ + printk(KERN_DEBUG "%s +%d %s(): comm=%s pid=%d n=%ld\n", + file, line, func, + current->comm, current->pid, + n); + print_writeback_control(wbc); +} + static inline bool bdi_work_on_stack(struct bdi_work *work) { return test_bit(WS_ONSTACK_B, &work->state); @@ -81,6 +105,9 @@ static inline void bdi_work_init(struct work->state = WS_USED; } +int sysctl_dirty_debug __read_mostly; + + /** * writeback_in_progress - determine whether there is writeback in progress * @bdi: the device's backing_dev_info structure. @@ -260,6 +287,21 @@ void bdi_start_writeback(struct backing_ bdi_alloc_queue_work(bdi, &args); } +#define redirty_tail(inode) \ + do { \ + __redirty_tail(inode, __LINE__); \ + } while (0) + +#define requeue_io(inode) \ + do { \ + __requeue_io(inode, __LINE__); \ + } while (0) + +#define requeue_partial_io(wbc, inode) \ + do { \ + __requeue_partial_io(wbc, inode, __LINE__); \ + } while (0) + /* * Redirty an inode: set its when-it-was dirtied timestamp and move it to the * furthest end of its superblock's dirty-inode list. @@ -269,7 +311,7 @@ void bdi_start_writeback(struct backing_ * the case then the inode must have been redirtied while it was being written * out and we don't reset its dirtied_when. */ -static void redirty_tail(struct inode *inode) +static void __redirty_tail(struct inode *inode, int line) { struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; @@ -281,16 +323,26 @@ static void redirty_tail(struct inode *i inode->dirtied_when = jiffies; } list_move(&inode->i_list, &wb->b_dirty); + + if (sysctl_dirty_debug) { + printk(KERN_DEBUG "redirty_tail() +%d: inode=%lu\n", + line, inode->i_ino); + } } /* * requeue inode for re-scanning after bdi->b_io list is exhausted. */ -static void requeue_io(struct inode *inode) +static void __requeue_io(struct inode *inode, int line) { struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; list_move(&inode->i_list, &wb->b_more_io); + + if (sysctl_dirty_debug) { + printk(KERN_DEBUG "requeue_io() +%d: inode=%lu\n", + line, inode->i_ino); + } } static void inode_sync_complete(struct inode *inode) @@ -743,6 +795,7 @@ static long wb_writeback(struct bdi_writ args->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; + writeback_debug_report(wrote, &wbc); /* * If we ran out of stuff to write, bail unless more_io got set */ --- linux.orig/include/linux/writeback.h 2009-09-21 20:09:21.000000000 +0800 +++ linux/include/linux/writeback.h 2009-09-21 20:09:37.000000000 +0800 @@ -156,5 +156,15 @@ void writeback_set_ratelimit(void); extern int nr_pdflush_threads; /* Global so it can be exported to sysctl read-only. */ +extern int sysctl_dirty_debug; + +#define writeback_debug_report(n, wbc) do { \ + if(sysctl_dirty_debug) \ + __writeback_debug_report(n, wbc, \ + __FILE__, __LINE__, __FUNCTION__); \ +} while (0) +void __writeback_debug_report(long n, struct writeback_control *wbc, + const char *file, int line, const char *func); + #endif /* WRITEBACK_H */ --- linux.orig/kernel/sysctl.c 2009-09-21 20:07:08.000000000 +0800 +++ linux/kernel/sysctl.c 2009-09-21 20:09:24.000000000 +0800 @@ -1531,6 +1531,14 @@ static struct ctl_table fs_table[] = { .extra1 = &zero, .extra2 = &two, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "dirty_debug", + .data = &sysctl_dirty_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) { .ctl_name = CTL_UNNUMBERED, --- linux.orig/mm/page-writeback.c 2009-09-21 20:09:29.000000000 +0800 +++ linux/mm/page-writeback.c 2009-09-21 20:54:15.000000000 +0800 @@ -536,6 +536,7 @@ static void balance_dirty_pages(struct a pages_written += write_chunk - wbc.nr_to_write; get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi); + writeback_debug_report(pages_written, &wbc); } /* @@ -561,7 +562,7 @@ static void balance_dirty_pages(struct a if (pages_written >= write_chunk) break; /* We've done our duty */ - schedule_timeout(1); + schedule_timeout(HZ/10); } if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh &&