2 * kernel/power/tuxonice_alloc.c
4 * Copyright (C) 2008-2010 Nigel Cunningham (nigel at tuxonice net)
6 * This file is released under the GPLv2.
10 #ifdef CONFIG_PM_DEBUG
11 #include <linux/export.h>
12 #include <linux/slab.h>
13 #include "tuxonice_modules.h"
14 #include "tuxonice_alloc.h"
15 #include "tuxonice_sysfs.h"
18 #define TOI_ALLOC_PATHS 40
20 static DEFINE_MUTEX(toi_alloc_mutex
);
22 static struct toi_module_ops toi_alloc_ops
;
24 static int toi_fail_num
;
26 static atomic_t toi_alloc_count
[TOI_ALLOC_PATHS
],
27 toi_free_count
[TOI_ALLOC_PATHS
],
28 toi_test_count
[TOI_ALLOC_PATHS
], toi_fail_count
[TOI_ALLOC_PATHS
];
29 static int toi_cur_allocd
[TOI_ALLOC_PATHS
], toi_max_allocd
[TOI_ALLOC_PATHS
];
30 static int cur_allocd
, max_allocd
;
32 static char *toi_alloc_desc
[TOI_ALLOC_PATHS
] = {
36 "extent (loading chain)",
39 "attention list metadata",
40 "extra pagedir memory metadata",
42 "extra pagedir memory",
43 "header_locations_read", /* 10 */
47 "writer buffer in bio_init",
48 "checksum buffer", /* 15 */
50 "filewriter signature op",
51 "set resume param alloc1",
52 "set resume param alloc2",
53 "debugging info buffer", /* 20 */
54 "check can resume buffer",
55 "write module config buffer",
56 "read module config buffer",
57 "write image header buffer",
58 "read pageset1 buffer", /* 25 */
59 "get_have_image_data buffer",
62 "get nonconflicting page",
63 "ps1 load addresses", /* 30 */
66 "swap parse sig location",
68 "swap mark resume attempted buffer", /* 35 */
70 "boot kernel data buffer",
71 "setting swap signature",
72 "block i/o bdev struct"
75 #define MIGHT_FAIL(FAIL_NUM, FAIL_VAL) \
77 BUG_ON(FAIL_NUM >= TOI_ALLOC_PATHS); \
79 if (FAIL_NUM == toi_fail_num) { \
80 atomic_inc(&toi_test_count[FAIL_NUM]); \
86 static void alloc_update_stats(int fail_num
, void *result
, int size
)
89 atomic_inc(&toi_fail_count
[fail_num
]);
93 atomic_inc(&toi_alloc_count
[fail_num
]);
94 if (unlikely(test_action_state(TOI_GET_MAX_MEM_ALLOCD
))) {
95 mutex_lock(&toi_alloc_mutex
);
96 toi_cur_allocd
[fail_num
]++;
98 if (unlikely(cur_allocd
> max_allocd
)) {
101 for (i
= 0; i
< TOI_ALLOC_PATHS
; i
++)
102 toi_max_allocd
[i
] = toi_cur_allocd
[i
];
103 max_allocd
= cur_allocd
;
105 mutex_unlock(&toi_alloc_mutex
);
109 static void free_update_stats(int fail_num
, int size
)
111 BUG_ON(fail_num
>= TOI_ALLOC_PATHS
);
112 atomic_inc(&toi_free_count
[fail_num
]);
113 if (unlikely(atomic_read(&toi_free_count
[fail_num
]) >
114 atomic_read(&toi_alloc_count
[fail_num
])))
116 if (unlikely(test_action_state(TOI_GET_MAX_MEM_ALLOCD
))) {
117 mutex_lock(&toi_alloc_mutex
);
119 toi_cur_allocd
[fail_num
]--;
120 mutex_unlock(&toi_alloc_mutex
);
124 void *toi_kzalloc(int fail_num
, size_t size
, gfp_t flags
)
128 if (toi_alloc_ops
.enabled
)
129 MIGHT_FAIL(fail_num
, NULL
);
130 result
= kzalloc(size
, flags
);
131 if (toi_alloc_ops
.enabled
)
132 alloc_update_stats(fail_num
, result
, size
);
133 if (fail_num
== toi_trace_allocs
)
137 EXPORT_SYMBOL_GPL(toi_kzalloc
);
139 unsigned long toi_get_free_pages(int fail_num
, gfp_t mask
, unsigned int order
)
141 unsigned long result
;
143 if (toi_alloc_ops
.enabled
)
144 MIGHT_FAIL(fail_num
, 0);
145 result
= __get_free_pages(mask
, order
);
146 if (toi_alloc_ops
.enabled
)
147 alloc_update_stats(fail_num
, (void *)result
, PAGE_SIZE
<< order
);
148 if (fail_num
== toi_trace_allocs
)
152 EXPORT_SYMBOL_GPL(toi_get_free_pages
);
154 struct page
*toi_alloc_page(int fail_num
, gfp_t mask
)
158 if (toi_alloc_ops
.enabled
)
159 MIGHT_FAIL(fail_num
, NULL
);
160 result
= alloc_page(mask
);
161 if (toi_alloc_ops
.enabled
)
162 alloc_update_stats(fail_num
, (void *)result
, PAGE_SIZE
);
163 if (fail_num
== toi_trace_allocs
)
167 EXPORT_SYMBOL_GPL(toi_alloc_page
);
169 unsigned long toi_get_zeroed_page(int fail_num
, gfp_t mask
)
171 unsigned long result
;
173 if (toi_alloc_ops
.enabled
)
174 MIGHT_FAIL(fail_num
, 0);
175 result
= get_zeroed_page(mask
);
176 if (toi_alloc_ops
.enabled
)
177 alloc_update_stats(fail_num
, (void *)result
, PAGE_SIZE
);
178 if (fail_num
== toi_trace_allocs
)
182 EXPORT_SYMBOL_GPL(toi_get_zeroed_page
);
184 void toi_kfree(int fail_num
, const void *arg
, int size
)
186 if (arg
&& toi_alloc_ops
.enabled
)
187 free_update_stats(fail_num
, size
);
189 if (fail_num
== toi_trace_allocs
)
193 EXPORT_SYMBOL_GPL(toi_kfree
);
195 void toi_free_page(int fail_num
, unsigned long virt
)
197 if (virt
&& toi_alloc_ops
.enabled
)
198 free_update_stats(fail_num
, PAGE_SIZE
);
200 if (fail_num
== toi_trace_allocs
)
204 EXPORT_SYMBOL_GPL(toi_free_page
);
206 void toi__free_page(int fail_num
, struct page
*page
)
208 if (page
&& toi_alloc_ops
.enabled
)
209 free_update_stats(fail_num
, PAGE_SIZE
);
211 if (fail_num
== toi_trace_allocs
)
215 EXPORT_SYMBOL_GPL(toi__free_page
);
217 void toi_free_pages(int fail_num
, struct page
*page
, int order
)
219 if (page
&& toi_alloc_ops
.enabled
)
220 free_update_stats(fail_num
, PAGE_SIZE
<< order
);
222 if (fail_num
== toi_trace_allocs
)
224 __free_pages(page
, order
);
227 void toi_alloc_print_debug_stats(void)
229 int i
, header_done
= 0;
231 if (!toi_alloc_ops
.enabled
)
234 for (i
= 0; i
< TOI_ALLOC_PATHS
; i
++)
235 if (atomic_read(&toi_alloc_count
[i
]) != atomic_read(&toi_free_count
[i
])) {
237 printk(KERN_INFO
"Idx Allocs Frees Tests "
238 " Fails Max Description\n");
242 printk(KERN_INFO
"%3d %7d %7d %7d %7d %7d %s\n", i
,
243 atomic_read(&toi_alloc_count
[i
]),
244 atomic_read(&toi_free_count
[i
]),
245 atomic_read(&toi_test_count
[i
]),
246 atomic_read(&toi_fail_count
[i
]),
247 toi_max_allocd
[i
], toi_alloc_desc
[i
]);
250 EXPORT_SYMBOL_GPL(toi_alloc_print_debug_stats
);
252 static int toi_alloc_initialise(int starting_cycle
)
259 if (toi_trace_allocs
)
262 for (i
= 0; i
< TOI_ALLOC_PATHS
; i
++) {
263 atomic_set(&toi_alloc_count
[i
], 0);
264 atomic_set(&toi_free_count
[i
], 0);
265 atomic_set(&toi_test_count
[i
], 0);
266 atomic_set(&toi_fail_count
[i
], 0);
267 toi_cur_allocd
[i
] = 0;
268 toi_max_allocd
[i
] = 0;
276 static struct toi_sysfs_data sysfs_params
[] = {
277 SYSFS_INT("failure_test", SYSFS_RW
, &toi_fail_num
, 0, 99, 0, NULL
),
278 SYSFS_INT("trace", SYSFS_RW
, &toi_trace_allocs
, 0, TOI_ALLOC_PATHS
, 0,
280 SYSFS_BIT("find_max_mem_allocated", SYSFS_RW
, &toi_bkd
.toi_action
,
281 TOI_GET_MAX_MEM_ALLOCD
, 0),
282 SYSFS_INT("enabled", SYSFS_RW
, &toi_alloc_ops
.enabled
, 0, 1, 0,
286 static struct toi_module_ops toi_alloc_ops
= {
287 .type
= MISC_HIDDEN_MODULE
,
288 .name
= "allocation debugging",
289 .directory
= "alloc",
290 .module
= THIS_MODULE
,
292 .initialise
= toi_alloc_initialise
,
294 .sysfs_data
= sysfs_params
,
295 .num_sysfs_entries
= sizeof(sysfs_params
) / sizeof(struct toi_sysfs_data
),
298 int toi_alloc_init(void)
300 int result
= toi_register_module(&toi_alloc_ops
);
304 void toi_alloc_exit(void)
306 toi_unregister_module(&toi_alloc_ops
);