aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page-writeback.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/page-writeback.c')
-rw-r--r--mm/page-writeback.c77
1 files changed, 71 insertions, 6 deletions
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 5e00f1772c20..789b6adbef37 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -164,9 +164,20 @@ int dirty_ratio_handler(struct ctl_table *table, int write,
164 */ 164 */
165static inline void __bdi_writeout_inc(struct backing_dev_info *bdi) 165static inline void __bdi_writeout_inc(struct backing_dev_info *bdi)
166{ 166{
167 __prop_inc_percpu(&vm_completions, &bdi->completions); 167 __prop_inc_percpu_max(&vm_completions, &bdi->completions,
168 bdi->max_prop_frac);
168} 169}
169 170
171void bdi_writeout_inc(struct backing_dev_info *bdi)
172{
173 unsigned long flags;
174
175 local_irq_save(flags);
176 __bdi_writeout_inc(bdi);
177 local_irq_restore(flags);
178}
179EXPORT_SYMBOL_GPL(bdi_writeout_inc);
180
170static inline void task_dirty_inc(struct task_struct *tsk) 181static inline void task_dirty_inc(struct task_struct *tsk)
171{ 182{
172 prop_inc_single(&vm_dirties, &tsk->dirties); 183 prop_inc_single(&vm_dirties, &tsk->dirties);
@@ -200,7 +211,8 @@ clip_bdi_dirty_limit(struct backing_dev_info *bdi, long dirty, long *pbdi_dirty)
200 avail_dirty = dirty - 211 avail_dirty = dirty -
201 (global_page_state(NR_FILE_DIRTY) + 212 (global_page_state(NR_FILE_DIRTY) +
202 global_page_state(NR_WRITEBACK) + 213 global_page_state(NR_WRITEBACK) +
203 global_page_state(NR_UNSTABLE_NFS)); 214 global_page_state(NR_UNSTABLE_NFS) +
215 global_page_state(NR_WRITEBACK_TEMP));
204 216
205 if (avail_dirty < 0) 217 if (avail_dirty < 0)
206 avail_dirty = 0; 218 avail_dirty = 0;
@@ -243,6 +255,55 @@ static void task_dirty_limit(struct task_struct *tsk, long *pdirty)
243} 255}
244 256
245/* 257/*
258 *
259 */
260static DEFINE_SPINLOCK(bdi_lock);
261static unsigned int bdi_min_ratio;
262
263int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio)
264{
265 int ret = 0;
266 unsigned long flags;
267
268 spin_lock_irqsave(&bdi_lock, flags);
269 if (min_ratio > bdi->max_ratio) {
270 ret = -EINVAL;
271 } else {
272 min_ratio -= bdi->min_ratio;
273 if (bdi_min_ratio + min_ratio < 100) {
274 bdi_min_ratio += min_ratio;
275 bdi->min_ratio += min_ratio;
276 } else {
277 ret = -EINVAL;
278 }
279 }
280 spin_unlock_irqrestore(&bdi_lock, flags);
281
282 return ret;
283}
284
285int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
286{
287 unsigned long flags;
288 int ret = 0;
289
290 if (max_ratio > 100)
291 return -EINVAL;
292
293 spin_lock_irqsave(&bdi_lock, flags);
294 if (bdi->min_ratio > max_ratio) {
295 ret = -EINVAL;
296 } else {
297 bdi->max_ratio = max_ratio;
298 bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100;
299 }
300 spin_unlock_irqrestore(&bdi_lock, flags);
301
302 return ret;
303}
304EXPORT_SYMBOL(bdi_set_max_ratio);
305
306/*
246 * Work out the current dirty-memory clamping and background writeout 307 * Work out the current dirty-memory clamping and background writeout
247 * thresholds. 308 * thresholds.
248 * 309 *
@@ -300,7 +361,7 @@ static unsigned long determine_dirtyable_memory(void)
300 return x + 1; /* Ensure that we never return 0 */ 361 return x + 1; /* Ensure that we never return 0 */
301} 362}
302 363
303static void 364void
304get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty, 365get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty,
305 struct backing_dev_info *bdi) 366 struct backing_dev_info *bdi)
306{ 367{
@@ -330,7 +391,7 @@ get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty,
330 *pdirty = dirty; 391 *pdirty = dirty;
331 392
332 if (bdi) { 393 if (bdi) {
333 u64 bdi_dirty = dirty; 394 u64 bdi_dirty;
334 long numerator, denominator; 395 long numerator, denominator;
335 396
336 /* 397 /*
@@ -338,8 +399,12 @@ get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty,
338 */ 399 */
339 bdi_writeout_fraction(bdi, &numerator, &denominator); 400 bdi_writeout_fraction(bdi, &numerator, &denominator);
340 401
402 bdi_dirty = (dirty * (100 - bdi_min_ratio)) / 100;
341 bdi_dirty *= numerator; 403 bdi_dirty *= numerator;
342 do_div(bdi_dirty, denominator); 404 do_div(bdi_dirty, denominator);
405 bdi_dirty += (dirty * bdi->min_ratio) / 100;
406 if (bdi_dirty > (dirty * bdi->max_ratio) / 100)
407 bdi_dirty = dirty * bdi->max_ratio / 100;
343 408
344 *pbdi_dirty = bdi_dirty; 409 *pbdi_dirty = bdi_dirty;
345 clip_bdi_dirty_limit(bdi, dirty, pbdi_dirty); 410 clip_bdi_dirty_limit(bdi, dirty, pbdi_dirty);
@@ -1192,7 +1257,7 @@ int test_clear_page_writeback(struct page *page)
1192 radix_tree_tag_clear(&mapping->page_tree, 1257 radix_tree_tag_clear(&mapping->page_tree,
1193 page_index(page), 1258 page_index(page),
1194 PAGECACHE_TAG_WRITEBACK); 1259 PAGECACHE_TAG_WRITEBACK);
1195 if (bdi_cap_writeback_dirty(bdi)) { 1260 if (bdi_cap_account_writeback(bdi)) {
1196 __dec_bdi_stat(bdi, BDI_WRITEBACK); 1261 __dec_bdi_stat(bdi, BDI_WRITEBACK);
1197 __bdi_writeout_inc(bdi); 1262 __bdi_writeout_inc(bdi);
1198 } 1263 }
@@ -1221,7 +1286,7 @@ int test_set_page_writeback(struct page *page)
1221 radix_tree_tag_set(&mapping->page_tree, 1286 radix_tree_tag_set(&mapping->page_tree,
1222 page_index(page), 1287 page_index(page),
1223 PAGECACHE_TAG_WRITEBACK); 1288 PAGECACHE_TAG_WRITEBACK);
1224 if (bdi_cap_writeback_dirty(bdi)) 1289 if (bdi_cap_account_writeback(bdi))
1225 __inc_bdi_stat(bdi, BDI_WRITEBACK); 1290 __inc_bdi_stat(bdi, BDI_WRITEBACK);
1226 } 1291 }
1227 if (!PageDirty(page)) 1292 if (!PageDirty(page))