diff options
-rw-r--r-- | include/linux/writeback.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace.c | 38 | ||||
-rw-r--r-- | mm/page-writeback.c | 10 |
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; | |||
105 | extern int block_dump; | 105 | extern int block_dump; |
106 | extern int laptop_mode; | 106 | extern int laptop_mode; |
107 | 107 | ||
108 | extern unsigned long determine_dirtyable_memory(void); | ||
109 | |||
108 | extern int dirty_ratio_handler(struct ctl_table *table, int write, | 110 | extern 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 | ||
52 | static int tracing_disabled = 1; | 53 | static int tracing_disabled = 1; |
53 | 54 | ||
55 | static unsigned long tracing_pages_allocated; | ||
56 | |||
54 | long | 57 | long |
55 | ns2usecs(cycle_t nsec) | 58 | ns2usecs(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); | |||
126 | static struct prop_descriptor vm_completions; | 126 | static struct prop_descriptor vm_completions; |
127 | static struct prop_descriptor vm_dirties; | 127 | static struct prop_descriptor vm_dirties; |
128 | 128 | ||
129 | static 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 | ||
350 | static 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 | */ | ||
354 | unsigned long determine_dirtyable_memory(void) | ||
351 | { | 355 | { |
352 | unsigned long x; | 356 | unsigned long x; |
353 | 357 | ||