2 * kernel/power/tuxonice_modules.c
4 * Copyright (C) 2004-2010 Nigel Cunningham (nigel at tuxonice net)
8 #include <linux/suspend.h>
10 #include "tuxonice_modules.h"
11 #include "tuxonice_sysfs.h"
12 #include "tuxonice_ui.h"
14 LIST_HEAD(toi_filters
);
15 LIST_HEAD(toiAllocators
);
17 LIST_HEAD(toi_modules
);
18 EXPORT_SYMBOL_GPL(toi_modules
);
20 struct toi_module_ops
*toiActiveAllocator
;
21 EXPORT_SYMBOL_GPL(toiActiveAllocator
);
23 static int toi_num_filters
;
24 int toiNumAllocators
, toi_num_modules
;
27 * toi_header_storage_for_modules
29 * Returns the amount of space needed to store configuration
30 * data needed by the modules prior to copying back the original
31 * kernel. We can exclude data for pageset2 because it will be
32 * available anyway once the kernel is copied back.
34 long toi_header_storage_for_modules(void)
36 struct toi_module_ops
*this_module
;
39 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
40 if (!this_module
->enabled
||
41 (this_module
->type
== WRITER_MODULE
&& toiActiveAllocator
!= this_module
))
43 if (this_module
->storage_needed
) {
44 int this = this_module
->storage_needed() +
45 sizeof(struct toi_module_header
) + sizeof(int);
46 this_module
->header_requested
= this;
51 /* One more for the empty terminator */
52 return bytes
+ sizeof(struct toi_module_header
);
55 void print_toi_header_storage_for_modules(void)
57 struct toi_module_ops
*this_module
;
60 printk(KERN_DEBUG
"Header storage:\n");
61 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
62 if (!this_module
->enabled
||
63 (this_module
->type
== WRITER_MODULE
&& toiActiveAllocator
!= this_module
))
65 if (this_module
->storage_needed
) {
66 int this = this_module
->storage_needed() +
67 sizeof(struct toi_module_header
) + sizeof(int);
68 this_module
->header_requested
= this;
70 printk(KERN_DEBUG
"+ %16s : %-4d/%d.\n",
71 this_module
->name
, this_module
->header_used
, this);
75 printk(KERN_DEBUG
"+ empty terminator : %zu.\n", sizeof(struct toi_module_header
));
76 printk(KERN_DEBUG
" ====\n");
77 printk(KERN_DEBUG
" %zu\n", bytes
+ sizeof(struct toi_module_header
));
79 EXPORT_SYMBOL_GPL(print_toi_header_storage_for_modules
);
82 * toi_memory_for_modules
84 * Returns the amount of memory requested by modules for
85 * doing their work during the cycle.
88 long toi_memory_for_modules(int print_parts
)
90 long bytes
= 0, result
;
91 struct toi_module_ops
*this_module
;
94 printk(KERN_INFO
"Memory for modules:\n===================\n");
95 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
97 if (!this_module
->enabled
)
99 if (this_module
->memory_needed
) {
100 this = this_module
->memory_needed();
102 printk(KERN_INFO
"%10d bytes (%5ld pages) for "
103 "module '%s'.\n", this,
104 DIV_ROUND_UP(this, PAGE_SIZE
), this_module
->name
);
109 result
= DIV_ROUND_UP(bytes
, PAGE_SIZE
);
111 printk(KERN_INFO
" => %ld bytes, %ld pages.\n", bytes
, result
);
117 * toi_expected_compression_ratio
119 * Returns the compression ratio expected when saving the image.
122 int toi_expected_compression_ratio(void)
125 struct toi_module_ops
*this_module
;
127 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
128 if (!this_module
->enabled
)
130 if (this_module
->expected_compression
)
131 ratio
= ratio
* this_module
->expected_compression()
138 #ifdef CONFIG_TOI_ENHANCE
140 * toi_actual_compression_ratio
142 * Returns the actual compression ratio when saving the image.
144 int toi_actual_compression_ratio(void)
147 struct toi_module_ops
*this_module
;
149 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
150 if (!this_module
->enabled
)
152 if (this_module
->actual_compression
)
153 ratio
= this_module
->actual_compression();
158 #endif /* CONFIG_TOI_ENHANCE */
161 /* toi_find_module_given_dir
162 * Functionality : Return a module (if found), given a pointer
163 * to its directory name
166 static struct toi_module_ops
*toi_find_module_given_dir(char *name
)
168 struct toi_module_ops
*this_module
, *found_module
= NULL
;
170 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
171 if (!strcmp(name
, this_module
->directory
)) {
172 found_module
= this_module
;
180 /* toi_find_module_given_name
181 * Functionality : Return a module (if found), given a pointer
185 struct toi_module_ops
*toi_find_module_given_name(char *name
)
187 struct toi_module_ops
*this_module
, *found_module
= NULL
;
189 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
190 if (!strcmp(name
, this_module
->name
)) {
191 found_module
= this_module
;
200 * toi_print_module_debug_info
201 * Functionality : Get debugging info from modules into a buffer.
203 int toi_print_module_debug_info(char *buffer
, int buffer_size
)
205 struct toi_module_ops
*this_module
;
208 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
209 if (!this_module
->enabled
)
211 if (this_module
->print_debug_info
) {
213 result
= this_module
->print_debug_info(buffer
+ len
, buffer_size
- len
);
218 /* Ensure null terminated */
219 buffer
[buffer_size
] = 0;
225 * toi_register_module
229 int toi_register_module(struct toi_module_ops
*module
)
232 struct kobject
*kobj
;
236 if (toi_find_module_given_name(module
->name
)) {
237 printk(KERN_INFO
"TuxOnIce: Trying to load module %s,"
238 " which is already registered.\n", module
->name
);
242 switch (module
->type
) {
244 list_add_tail(&module
->type_list
, &toi_filters
);
248 list_add_tail(&module
->type_list
, &toiAllocators
);
252 case MISC_HIDDEN_MODULE
:
253 case BIO_ALLOCATOR_MODULE
:
256 printk(KERN_ERR
"Hmmm. Module '%s' has an invalid type."
257 " It has been ignored.\n", module
->name
);
260 list_add_tail(&module
->module_list
, &toi_modules
);
263 if ((!module
->directory
&& !module
->shared_directory
) ||
264 !module
->sysfs_data
|| !module
->num_sysfs_entries
)
268 * Modules may share a directory, but those with shared_dir
269 * set must be loaded (via symbol dependencies) after parents
270 * and unloaded beforehand.
272 if (module
->shared_directory
) {
273 struct toi_module_ops
*shared
= toi_find_module_given_dir(module
->shared_directory
);
275 printk(KERN_ERR
"TuxOnIce: Module %s wants to share "
276 "%s's directory but %s isn't loaded.\n",
277 module
->name
, module
->shared_directory
, module
->shared_directory
);
278 toi_unregister_module(module
);
281 kobj
= shared
->dir_kobj
;
283 if (!strncmp(module
->directory
, "[ROOT]", 6))
284 kobj
= tuxonice_kobj
;
286 kobj
= make_toi_sysdir(module
->directory
);
288 module
->dir_kobj
= kobj
;
289 for (i
= 0; i
< module
->num_sysfs_entries
; i
++) {
290 int result
= toi_register_sysfs_file(kobj
,
291 &module
->sysfs_data
[i
]);
297 EXPORT_SYMBOL_GPL(toi_register_module
);
300 * toi_unregister_module
304 void toi_unregister_module(struct toi_module_ops
*module
)
308 if (module
->dir_kobj
)
309 for (i
= 0; i
< module
->num_sysfs_entries
; i
++)
310 toi_unregister_sysfs_file(module
->dir_kobj
, &module
->sysfs_data
[i
]);
312 if (!module
->shared_directory
&& module
->directory
&&
313 strncmp(module
->directory
, "[ROOT]", 6))
314 remove_toi_sysdir(module
->dir_kobj
);
316 switch (module
->type
) {
318 list_del(&module
->type_list
);
322 list_del(&module
->type_list
);
324 if (toiActiveAllocator
== module
) {
325 toiActiveAllocator
= NULL
;
326 clear_toi_state(TOI_CAN_RESUME
);
327 clear_toi_state(TOI_CAN_HIBERNATE
);
331 case MISC_HIDDEN_MODULE
:
332 case BIO_ALLOCATOR_MODULE
:
335 printk(KERN_ERR
"Module '%s' has an invalid type."
336 " It has been ignored.\n", module
->name
);
339 list_del(&module
->module_list
);
342 EXPORT_SYMBOL_GPL(toi_unregister_module
);
345 * toi_move_module_tail
347 * Rearrange modules when reloading the config.
349 void toi_move_module_tail(struct toi_module_ops
*module
)
351 switch (module
->type
) {
353 if (toi_num_filters
> 1)
354 list_move_tail(&module
->type_list
, &toi_filters
);
357 if (toiNumAllocators
> 1)
358 list_move_tail(&module
->type_list
, &toiAllocators
);
361 case MISC_HIDDEN_MODULE
:
362 case BIO_ALLOCATOR_MODULE
:
365 printk(KERN_ERR
"Module '%s' has an invalid type."
366 " It has been ignored.\n", module
->name
);
369 if ((toi_num_filters
+ toiNumAllocators
) > 1)
370 list_move_tail(&module
->module_list
, &toi_modules
);
374 * toi_initialise_modules
376 * Get ready to do some work!
378 int toi_initialise_modules(int starting_cycle
, int early
)
380 struct toi_module_ops
*this_module
;
383 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
384 this_module
->header_requested
= 0;
385 this_module
->header_used
= 0;
386 if (!this_module
->enabled
)
388 if (this_module
->early
!= early
)
390 if (this_module
->initialise
) {
391 result
= this_module
->initialise(starting_cycle
);
393 toi_cleanup_modules(starting_cycle
);
396 this_module
->initialised
= 1;
404 * toi_cleanup_modules
406 * Tell modules the work is done.
408 void toi_cleanup_modules(int finishing_cycle
)
410 struct toi_module_ops
*this_module
;
412 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
413 if (!this_module
->enabled
|| !this_module
->initialised
)
415 if (this_module
->cleanup
)
416 this_module
->cleanup(finishing_cycle
);
417 this_module
->initialised
= 0;
422 * toi_pre_atomic_restore_modules
424 * Get ready to do some work!
426 void toi_pre_atomic_restore_modules(struct toi_boot_kernel_data
*bkd
)
428 struct toi_module_ops
*this_module
;
430 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
431 if (this_module
->enabled
&& this_module
->pre_atomic_restore
)
432 this_module
->pre_atomic_restore(bkd
);
437 * toi_post_atomic_restore_modules
439 * Get ready to do some work!
441 void toi_post_atomic_restore_modules(struct toi_boot_kernel_data
*bkd
)
443 struct toi_module_ops
*this_module
;
445 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
446 if (this_module
->enabled
&& this_module
->post_atomic_restore
)
447 this_module
->post_atomic_restore(bkd
);
452 * toi_get_next_filter
454 * Get the next filter in the pipeline.
456 struct toi_module_ops
*toi_get_next_filter(struct toi_module_ops
*filter_sought
)
458 struct toi_module_ops
*last_filter
= NULL
, *this_filter
= NULL
;
460 list_for_each_entry(this_filter
, &toi_filters
, type_list
) {
461 if (!this_filter
->enabled
)
463 if ((last_filter
== filter_sought
) || (!filter_sought
))
465 last_filter
= this_filter
;
468 return toiActiveAllocator
;
470 EXPORT_SYMBOL_GPL(toi_get_next_filter
);
473 * toi_show_modules: Printk what support is loaded.
475 void toi_print_modules(void)
477 struct toi_module_ops
*this_module
;
480 printk(KERN_INFO
"TuxOnIce " TOI_CORE_VERSION
", with support for");
482 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
483 if (this_module
->type
== MISC_HIDDEN_MODULE
)
485 printk("%s %s%s%s", prev
? "," : "",
486 this_module
->enabled
? "" : "[",
487 this_module
->name
, this_module
->enabled
? "" : "]");
496 * Take a reference to modules so they can't go away under us.
499 int toi_get_modules(void)
501 struct toi_module_ops
*this_module
;
503 list_for_each_entry(this_module
, &toi_modules
, module_list
) {
504 struct toi_module_ops
*this_module2
;
506 if (try_module_get(this_module
->module
))
509 /* Failed! Reverse gets and return error */
510 list_for_each_entry(this_module2
, &toi_modules
, module_list
) {
511 if (this_module
== this_module2
)
513 module_put(this_module2
->module
);
521 * Release our references to modules we used.
524 void toi_put_modules(void)
526 struct toi_module_ops
*this_module
;
528 list_for_each_entry(this_module
, &toi_modules
, module_list
)
529 module_put(this_module
->module
);