diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fs-writeback.c | 61 |
1 files changed, 46 insertions, 15 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 3d06ccc953aa..3a07f6d8bc0b 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -84,13 +84,9 @@ static inline struct inode *wb_inode(struct list_head *head) | |||
84 | return list_entry(head, struct inode, i_wb_list); | 84 | return list_entry(head, struct inode, i_wb_list); |
85 | } | 85 | } |
86 | 86 | ||
87 | static void bdi_queue_work(struct backing_dev_info *bdi, | 87 | /* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */ |
88 | struct wb_writeback_work *work) | 88 | static void bdi_wakeup_flusher(struct backing_dev_info *bdi) |
89 | { | 89 | { |
90 | trace_writeback_queue(bdi, work); | ||
91 | |||
92 | spin_lock_bh(&bdi->wb_lock); | ||
93 | list_add_tail(&work->list, &bdi->work_list); | ||
94 | if (bdi->wb.task) { | 90 | if (bdi->wb.task) { |
95 | wake_up_process(bdi->wb.task); | 91 | wake_up_process(bdi->wb.task); |
96 | } else { | 92 | } else { |
@@ -98,15 +94,26 @@ static void bdi_queue_work(struct backing_dev_info *bdi, | |||
98 | * The bdi thread isn't there, wake up the forker thread which | 94 | * The bdi thread isn't there, wake up the forker thread which |
99 | * will create and run it. | 95 | * will create and run it. |
100 | */ | 96 | */ |
101 | trace_writeback_nothread(bdi, work); | ||
102 | wake_up_process(default_backing_dev_info.wb.task); | 97 | wake_up_process(default_backing_dev_info.wb.task); |
103 | } | 98 | } |
99 | } | ||
100 | |||
101 | static void bdi_queue_work(struct backing_dev_info *bdi, | ||
102 | struct wb_writeback_work *work) | ||
103 | { | ||
104 | trace_writeback_queue(bdi, work); | ||
105 | |||
106 | spin_lock_bh(&bdi->wb_lock); | ||
107 | list_add_tail(&work->list, &bdi->work_list); | ||
108 | if (!bdi->wb.task) | ||
109 | trace_writeback_nothread(bdi, work); | ||
110 | bdi_wakeup_flusher(bdi); | ||
104 | spin_unlock_bh(&bdi->wb_lock); | 111 | spin_unlock_bh(&bdi->wb_lock); |
105 | } | 112 | } |
106 | 113 | ||
107 | static void | 114 | static void |
108 | __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | 115 | __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, |
109 | bool range_cyclic, bool for_background) | 116 | bool range_cyclic) |
110 | { | 117 | { |
111 | struct wb_writeback_work *work; | 118 | struct wb_writeback_work *work; |
112 | 119 | ||
@@ -126,7 +133,6 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | |||
126 | work->sync_mode = WB_SYNC_NONE; | 133 | work->sync_mode = WB_SYNC_NONE; |
127 | work->nr_pages = nr_pages; | 134 | work->nr_pages = nr_pages; |
128 | work->range_cyclic = range_cyclic; | 135 | work->range_cyclic = range_cyclic; |
129 | work->for_background = for_background; | ||
130 | 136 | ||
131 | bdi_queue_work(bdi, work); | 137 | bdi_queue_work(bdi, work); |
132 | } | 138 | } |
@@ -144,7 +150,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | |||
144 | */ | 150 | */ |
145 | void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages) | 151 | void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages) |
146 | { | 152 | { |
147 | __bdi_start_writeback(bdi, nr_pages, true, false); | 153 | __bdi_start_writeback(bdi, nr_pages, true); |
148 | } | 154 | } |
149 | 155 | ||
150 | /** | 156 | /** |
@@ -152,13 +158,20 @@ void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages) | |||
152 | * @bdi: the backing device to write from | 158 | * @bdi: the backing device to write from |
153 | * | 159 | * |
154 | * Description: | 160 | * Description: |
155 | * This does WB_SYNC_NONE background writeback. The IO is only | 161 | * This makes sure WB_SYNC_NONE background writeback happens. When |
156 | * started when this function returns, we make no guarentees on | 162 | * this function returns, it is only guaranteed that for given BDI |
157 | * completion. Caller need not hold sb s_umount semaphore. | 163 | * some IO is happening if we are over background dirty threshold. |
164 | * Caller need not hold sb s_umount semaphore. | ||
158 | */ | 165 | */ |
159 | void bdi_start_background_writeback(struct backing_dev_info *bdi) | 166 | void bdi_start_background_writeback(struct backing_dev_info *bdi) |
160 | { | 167 | { |
161 | __bdi_start_writeback(bdi, LONG_MAX, true, true); | 168 | /* |
169 | * We just wake up the flusher thread. It will perform background | ||
170 | * writeback as soon as there is no other work to do. | ||
171 | */ | ||
172 | spin_lock_bh(&bdi->wb_lock); | ||
173 | bdi_wakeup_flusher(bdi); | ||
174 | spin_unlock_bh(&bdi->wb_lock); | ||
162 | } | 175 | } |
163 | 176 | ||
164 | /* | 177 | /* |
@@ -718,6 +731,23 @@ static unsigned long get_nr_dirty_pages(void) | |||
718 | get_nr_dirty_inodes(); | 731 | get_nr_dirty_inodes(); |
719 | } | 732 | } |
720 | 733 | ||
734 | static long wb_check_background_flush(struct bdi_writeback *wb) | ||
735 | { | ||
736 | if (over_bground_thresh()) { | ||
737 | |||
738 | struct wb_writeback_work work = { | ||
739 | .nr_pages = LONG_MAX, | ||
740 | .sync_mode = WB_SYNC_NONE, | ||
741 | .for_background = 1, | ||
742 | .range_cyclic = 1, | ||
743 | }; | ||
744 | |||
745 | return wb_writeback(wb, &work); | ||
746 | } | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
721 | static long wb_check_old_data_flush(struct bdi_writeback *wb) | 751 | static long wb_check_old_data_flush(struct bdi_writeback *wb) |
722 | { | 752 | { |
723 | unsigned long expired; | 753 | unsigned long expired; |
@@ -787,6 +817,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
787 | * Check for periodic writeback, kupdated() style | 817 | * Check for periodic writeback, kupdated() style |
788 | */ | 818 | */ |
789 | wrote += wb_check_old_data_flush(wb); | 819 | wrote += wb_check_old_data_flush(wb); |
820 | wrote += wb_check_background_flush(wb); | ||
790 | clear_bit(BDI_writeback_running, &wb->bdi->state); | 821 | clear_bit(BDI_writeback_running, &wb->bdi->state); |
791 | 822 | ||
792 | return wrote; | 823 | return wrote; |
@@ -873,7 +904,7 @@ void wakeup_flusher_threads(long nr_pages) | |||
873 | list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { | 904 | list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { |
874 | if (!bdi_has_dirty_io(bdi)) | 905 | if (!bdi_has_dirty_io(bdi)) |
875 | continue; | 906 | continue; |
876 | __bdi_start_writeback(bdi, nr_pages, false, false); | 907 | __bdi_start_writeback(bdi, nr_pages, false); |
877 | } | 908 | } |
878 | rcu_read_unlock(); | 909 | rcu_read_unlock(); |
879 | } | 910 | } |