aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2008-05-12 15:21:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 16:05:14 -0400
commit3eefae994d9224fb7771a3ddb683868363c23510 (patch)
tree0c7fe35765b485ff2a155c4ae1189199476a34b3
parent6c6c27969a4c6024e6c8838829546c02aaddca18 (diff)
ftrace: limit trace entries
Currently there is no protection from the root user to use up all of memory for trace buffers. If the root user allocates too many entries, the OOM killer might start kill off all tasks. This patch adds an algorith to check the following condition: pages_requested > (freeable_memory + current_trace_buffer_pages) / 4 If the above is met then the allocation fails. The above prevents more than 1/4th of freeable memory from being used by trace buffers. To determine the freeable_memory, I made determine_dirtyable_memory in mm/page-writeback.c global. Special thanks goes to Peter Zijlstra for suggesting the above calculation. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-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