aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/writeback.h2
-rw-r--r--kernel/trace/trace.c38
-rw-r--r--mm/page-writeback.c10
3 files changed, 47 insertions, 3 deletions
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index f462439cc288..bd91987c065f 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -105,6 +105,8 @@ extern int vm_highmem_is_dirtyable;
105extern int block_dump; 105extern int block_dump;
106extern int laptop_mode; 106extern int laptop_mode;
107 107
108extern unsigned long determine_dirtyable_memory(void);
109
108extern int dirty_ratio_handler(struct ctl_table *table, int write, 110extern int dirty_ratio_handler(struct ctl_table *table, int write,
109 struct file *filp, void __user *buffer, size_t *lenp, 111 struct file *filp, void __user *buffer, size_t *lenp,
110 loff_t *ppos); 112 loff_t *ppos);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 82ced406aacf..2824cf48cdca 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -27,6 +27,7 @@
27#include <linux/poll.h> 27#include <linux/poll.h>
28#include <linux/gfp.h> 28#include <linux/gfp.h>
29#include <linux/fs.h> 29#include <linux/fs.h>
30#include <linux/writeback.h>
30 31
31#include <linux/stacktrace.h> 32#include <linux/stacktrace.h>
32 33
@@ -51,6 +52,8 @@ static int trace_free_page(void);
51 52
52static int tracing_disabled = 1; 53static int tracing_disabled = 1;
53 54
55static unsigned long tracing_pages_allocated;
56
54long 57long
55ns2usecs(cycle_t nsec) 58ns2usecs(cycle_t nsec)
56{ 59{
@@ -2591,12 +2594,41 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
2591 } 2594 }
2592 2595
2593 if (val > global_trace.entries) { 2596 if (val > global_trace.entries) {
2597 long pages_requested;
2598 unsigned long freeable_pages;
2599
2600 /* make sure we have enough memory before mapping */
2601 pages_requested =
2602 (val + (ENTRIES_PER_PAGE-1)) / ENTRIES_PER_PAGE;
2603
2604 /* account for each buffer (and max_tr) */
2605 pages_requested *= tracing_nr_buffers * 2;
2606
2607 /* Check for overflow */
2608 if (pages_requested < 0) {
2609 cnt = -ENOMEM;
2610 goto out;
2611 }
2612
2613 freeable_pages = determine_dirtyable_memory();
2614
2615 /* we only allow to request 1/4 of useable memory */
2616 if (pages_requested >
2617 ((freeable_pages + tracing_pages_allocated) / 4)) {
2618 cnt = -ENOMEM;
2619 goto out;
2620 }
2621
2594 while (global_trace.entries < val) { 2622 while (global_trace.entries < val) {
2595 if (trace_alloc_page()) { 2623 if (trace_alloc_page()) {
2596 cnt = -ENOMEM; 2624 cnt = -ENOMEM;
2597 goto out; 2625 goto out;
2598 } 2626 }
2627 /* double check that we don't go over the known pages */
2628 if (tracing_pages_allocated > pages_requested)
2629 break;
2599 } 2630 }
2631
2600 } else { 2632 } else {
2601 /* include the number of entries in val (inc of page entries) */ 2633 /* include the number of entries in val (inc of page entries) */
2602 while (global_trace.entries > val + (ENTRIES_PER_PAGE - 1)) 2634 while (global_trace.entries > val + (ENTRIES_PER_PAGE - 1))
@@ -2776,6 +2808,7 @@ static int trace_alloc_page(void)
2776 struct page *page, *tmp; 2808 struct page *page, *tmp;
2777 LIST_HEAD(pages); 2809 LIST_HEAD(pages);
2778 void *array; 2810 void *array;
2811 unsigned pages_allocated = 0;
2779 int i; 2812 int i;
2780 2813
2781 /* first allocate a page for each CPU */ 2814 /* first allocate a page for each CPU */
@@ -2787,6 +2820,7 @@ static int trace_alloc_page(void)
2787 goto free_pages; 2820 goto free_pages;
2788 } 2821 }
2789 2822
2823 pages_allocated++;
2790 page = virt_to_page(array); 2824 page = virt_to_page(array);
2791 list_add(&page->lru, &pages); 2825 list_add(&page->lru, &pages);
2792 2826
@@ -2798,6 +2832,7 @@ static int trace_alloc_page(void)
2798 "for trace buffer!\n"); 2832 "for trace buffer!\n");
2799 goto free_pages; 2833 goto free_pages;
2800 } 2834 }
2835 pages_allocated++;
2801 page = virt_to_page(array); 2836 page = virt_to_page(array);
2802 list_add(&page->lru, &pages); 2837 list_add(&page->lru, &pages);
2803#endif 2838#endif
@@ -2819,6 +2854,7 @@ static int trace_alloc_page(void)
2819 SetPageLRU(page); 2854 SetPageLRU(page);
2820#endif 2855#endif
2821 } 2856 }
2857 tracing_pages_allocated += pages_allocated;
2822 global_trace.entries += ENTRIES_PER_PAGE; 2858 global_trace.entries += ENTRIES_PER_PAGE;
2823 2859
2824 return 0; 2860 return 0;
@@ -2853,6 +2889,8 @@ static int trace_free_page(void)
2853 page = list_entry(p, struct page, lru); 2889 page = list_entry(p, struct page, lru);
2854 ClearPageLRU(page); 2890 ClearPageLRU(page);
2855 list_del(&page->lru); 2891 list_del(&page->lru);
2892 tracing_pages_allocated--;
2893 tracing_pages_allocated--;
2856 __free_page(page); 2894 __free_page(page);
2857 2895
2858 tracing_reset(data); 2896 tracing_reset(data);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 789b6adbef37..b38f700825fc 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -126,8 +126,6 @@ static void background_writeout(unsigned long _min_pages);
126static struct prop_descriptor vm_completions; 126static struct prop_descriptor vm_completions;
127static struct prop_descriptor vm_dirties; 127static struct prop_descriptor vm_dirties;
128 128
129static unsigned long determine_dirtyable_memory(void);
130
131/* 129/*
132 * couple the period to the dirty_ratio: 130 * couple the period to the dirty_ratio:
133 * 131 *
@@ -347,7 +345,13 @@ static unsigned long highmem_dirtyable_memory(unsigned long total)
347#endif 345#endif
348} 346}
349 347
350static unsigned long determine_dirtyable_memory(void) 348/**
349 * determine_dirtyable_memory - amount of memory that may be used
350 *
351 * Returns the numebr of pages that can currently be freed and used
352 * by the kernel for direct mappings.
353 */
354unsigned long determine_dirtyable_memory(void)
351{ 355{
352 unsigned long x; 356 unsigned long x;
353 357