2 * kernel/power/compression.c
4 * Copyright (C) 2003-2008 Nigel Cunningham (nigel at tuxonice net)
6 * This file is released under the GPLv2.
8 * This file contains data compression routines for TuxOnIce,
12 #include <linux/module.h>
13 #include <linux/suspend.h>
14 #include <linux/highmem.h>
15 #include <linux/vmalloc.h>
16 #include <linux/crypto.h>
18 #include "tuxonice_builtin.h"
20 #include "tuxonice_modules.h"
21 #include "tuxonice_sysfs.h"
22 #include "tuxonice_io.h"
23 #include "tuxonice_ui.h"
24 #include "tuxonice_alloc.h"
26 static int toi_expected_compression
;
28 static struct toi_module_ops toi_compression_ops
;
29 static struct toi_module_ops
*next_driver
;
31 static char toi_compressor_name
[32] = "lzf";
33 static DEFINE_MUTEX(stats_lock
);
37 struct crypto_comp
*transform
;
42 static DEFINE_PER_CPU(struct cpu_context
, contexts
);
44 static int toi_compress_prepare_result
;
47 * toi_compress_cleanup
49 * Frees memory allocated for our labours.
51 static void toi_compress_cleanup(int toi_or_resume
)
58 for_each_online_cpu(cpu
) {
59 struct cpu_context
*this = &per_cpu(contexts
, cpu
);
60 if (this->transform
) {
61 crypto_free_comp(this->transform
);
62 this->transform
= NULL
;
65 if (this->page_buffer
)
66 toi_free_page(16, (unsigned long) this->page_buffer
);
68 this->page_buffer
= NULL
;
75 * Prepare to do some work by allocating buffers and transforms.
77 static int toi_compress_crypto_prepare(void)
81 if (!*toi_compressor_name
) {
82 printk(KERN_INFO
"TuxOnIce: Compression enabled but no "
83 "compressor name set.\n");
87 for_each_online_cpu(cpu
) {
88 struct cpu_context
*this = &per_cpu(contexts
, cpu
);
89 this->transform
= crypto_alloc_comp(toi_compressor_name
, 0, 0);
90 if (IS_ERR(this->transform
)) {
91 printk(KERN_INFO
"TuxOnIce: Failed to initialise the "
92 "%s compression transform.\n",
94 this->transform
= NULL
;
99 (char *) toi_get_zeroed_page(16, TOI_ATOMIC_GFP
);
101 if (!this->page_buffer
) {
103 "Failed to allocate a page buffer for TuxOnIce "
104 "encryption driver.\n");
116 static int toi_compress_init(int toi_or_resume
)
121 toi_compress_bytes_in
= toi_compress_bytes_out
= 0;
123 next_driver
= toi_get_next_filter(&toi_compression_ops
);
128 toi_compress_prepare_result
= toi_compress_crypto_prepare();
134 * toi_compress_rw_init()
137 int toi_compress_rw_init(int rw
, int stream_number
)
139 if (toi_compress_prepare_result
) {
140 printk("Failed to initialise compression algorithm.\n");
144 toi_compression_ops
.enabled
= 0;
151 * toi_compress_write_page()
153 * Compress a page of data, buffering output and passing on filled
154 * pages to the next module in the pipeline.
156 * Buffer_page: Pointer to a buffer of size PAGE_SIZE, containing
157 * data to be compressed.
159 * Returns: 0 on success. Otherwise the error is that returned by later
160 * modules, -ECHILD if we have a broken pipeline or -EIO if
163 static int toi_compress_write_page(unsigned long index
,
164 struct page
*buffer_page
, unsigned int buf_size
)
166 int ret
, cpu
= smp_processor_id();
167 struct cpu_context
*ctx
= &per_cpu(contexts
, cpu
);
170 return next_driver
->write_page(index
, buffer_page
, buf_size
);
172 ctx
->buffer_start
= kmap(buffer_page
);
176 ret
= crypto_comp_compress(ctx
->transform
,
177 ctx
->buffer_start
, buf_size
,
178 ctx
->page_buffer
, &ctx
->len
);
183 printk(KERN_INFO
"Compression failed.\n");
187 mutex_lock(&stats_lock
);
188 toi_compress_bytes_in
+= buf_size
;
189 toi_compress_bytes_out
+= ctx
->len
;
190 mutex_unlock(&stats_lock
);
192 if (ctx
->len
< buf_size
) /* some compression */
193 ret
= next_driver
->write_page(index
,
194 virt_to_page(ctx
->page_buffer
),
197 ret
= next_driver
->write_page(index
, buffer_page
, buf_size
);
204 * toi_compress_read_page()
205 * @buffer_page: struct page *. Pointer to a buffer of size PAGE_SIZE.
207 * Retrieve data from later modules and decompress it until the input buffer
209 * Zero if successful. Error condition from me or from downstream on failure.
211 static int toi_compress_read_page(unsigned long *index
,
212 struct page
*buffer_page
, unsigned int *buf_size
)
214 int ret
, cpu
= smp_processor_id();
216 unsigned int outlen
= PAGE_SIZE
;
218 struct cpu_context
*ctx
= &per_cpu(contexts
, cpu
);
221 return next_driver
->read_page(index
, buffer_page
, buf_size
);
224 * All our reads must be synchronous - we can't decompress
225 * data that hasn't been read yet.
228 *buf_size
= PAGE_SIZE
;
230 ret
= next_driver
->read_page(index
, buffer_page
, &len
);
232 /* Error or uncompressed data */
233 if (ret
|| len
== PAGE_SIZE
)
236 buffer_start
= kmap(buffer_page
);
237 memcpy(ctx
->page_buffer
, buffer_start
, len
);
238 ret
= crypto_comp_decompress(
241 len
, buffer_start
, &outlen
);
243 abort_hibernate(TOI_FAILED_IO
,
244 "Compress_read returned %d.\n", ret
);
245 else if (outlen
!= PAGE_SIZE
) {
246 abort_hibernate(TOI_FAILED_IO
,
247 "Decompression yielded %d bytes instead of %ld.\n",
249 printk(KERN_ERR
"Decompression yielded %d bytes instead of "
250 "%ld.\n", outlen
, PAGE_SIZE
);
259 * toi_compress_print_debug_stats
260 * @buffer: Pointer to a buffer into which the debug info will be printed.
261 * @size: Size of the buffer.
263 * Print information to be recorded for debugging purposes into a buffer.
264 * Returns: Number of characters written to the buffer.
267 static int toi_compress_print_debug_stats(char *buffer
, int size
)
269 unsigned long pages_in
= toi_compress_bytes_in
>> PAGE_SHIFT
,
270 pages_out
= toi_compress_bytes_out
>> PAGE_SHIFT
;
273 /* Output the compression ratio achieved. */
274 if (*toi_compressor_name
)
275 len
= snprintf_used(buffer
, size
, "- Compressor is '%s'.\n",
276 toi_compressor_name
);
278 len
= snprintf_used(buffer
, size
, "- Compressor is not set.\n");
281 len
+= snprintf_used(buffer
+len
, size
- len
,
282 " Compressed %lu bytes into %lu (%d percent compression).\n",
283 toi_compress_bytes_in
,
284 toi_compress_bytes_out
,
285 (pages_in
- pages_out
) * 100 / pages_in
);
290 * toi_compress_compression_memory_needed
292 * Tell the caller how much memory we need to operate during hibernate/resume.
293 * Returns: Unsigned long. Maximum number of bytes of memory required for
296 static int toi_compress_memory_needed(void)
298 return 2 * PAGE_SIZE
;
301 static int toi_compress_storage_needed(void)
303 return 4 * sizeof(unsigned long) + strlen(toi_compressor_name
) + 1;
307 * toi_compress_save_config_info
308 * @buffer: Pointer to a buffer of size PAGE_SIZE.
310 * Save informaton needed when reloading the image at resume time.
311 * Returns: Number of bytes used for saving our data.
313 static int toi_compress_save_config_info(char *buffer
)
315 int namelen
= strlen(toi_compressor_name
) + 1;
318 *((unsigned long *) buffer
) = toi_compress_bytes_in
;
319 *((unsigned long *) (buffer
+ 1 * sizeof(unsigned long))) =
320 toi_compress_bytes_out
;
321 *((unsigned long *) (buffer
+ 2 * sizeof(unsigned long))) =
322 toi_expected_compression
;
323 *((unsigned long *) (buffer
+ 3 * sizeof(unsigned long))) = namelen
;
324 strncpy(buffer
+ 4 * sizeof(unsigned long), toi_compressor_name
,
326 total_len
= 4 * sizeof(unsigned long) + namelen
;
330 /* toi_compress_load_config_info
331 * @buffer: Pointer to the start of the data.
332 * @size: Number of bytes that were saved.
334 * Description: Reload information needed for decompressing the image at
337 static void toi_compress_load_config_info(char *buffer
, int size
)
341 toi_compress_bytes_in
= *((unsigned long *) buffer
);
342 toi_compress_bytes_out
= *((unsigned long *) (buffer
+ 1 *
343 sizeof(unsigned long)));
344 toi_expected_compression
= *((unsigned long *) (buffer
+ 2 *
345 sizeof(unsigned long)));
346 namelen
= *((unsigned long *) (buffer
+ 3 * sizeof(unsigned long)));
347 if (strncmp(toi_compressor_name
, buffer
+ 4 * sizeof(unsigned long),
349 toi_compress_cleanup(1);
350 strncpy(toi_compressor_name
, buffer
+ 4 * sizeof(unsigned long),
352 toi_compress_crypto_prepare();
358 * toi_expected_compression_ratio
360 * Description: Returns the expected ratio between data passed into this module
361 * and the amount of data output when writing.
362 * Returns: 100 if the module is disabled. Otherwise the value set by the
363 * user via our sysfs entry.
366 static int toi_compress_expected_ratio(void)
368 if (!toi_compression_ops
.enabled
)
371 return 100 - toi_expected_compression
;
375 * data for our sysfs entries.
377 static struct toi_sysfs_data sysfs_params
[] = {
378 SYSFS_INT("expected_compression", SYSFS_RW
, &toi_expected_compression
,
380 SYSFS_INT("enabled", SYSFS_RW
, &toi_compression_ops
.enabled
, 0, 1, 0,
382 SYSFS_STRING("algorithm", SYSFS_RW
, toi_compressor_name
, 31, 0, NULL
),
388 static struct toi_module_ops toi_compression_ops
= {
389 .type
= FILTER_MODULE
,
390 .name
= "compression",
391 .directory
= "compression",
392 .module
= THIS_MODULE
,
393 .initialise
= toi_compress_init
,
394 .cleanup
= toi_compress_cleanup
,
395 .memory_needed
= toi_compress_memory_needed
,
396 .print_debug_info
= toi_compress_print_debug_stats
,
397 .save_config_info
= toi_compress_save_config_info
,
398 .load_config_info
= toi_compress_load_config_info
,
399 .storage_needed
= toi_compress_storage_needed
,
400 .expected_compression
= toi_compress_expected_ratio
,
402 .rw_init
= toi_compress_rw_init
,
404 .write_page
= toi_compress_write_page
,
405 .read_page
= toi_compress_read_page
,
407 .sysfs_data
= sysfs_params
,
408 .num_sysfs_entries
= sizeof(sysfs_params
) /
409 sizeof(struct toi_sysfs_data
),
412 /* ---- Registration ---- */
414 static __init
int toi_compress_load(void)
416 return toi_register_module(&toi_compression_ops
);
420 static __exit
void toi_compress_unload(void)
422 toi_unregister_module(&toi_compression_ops
);
425 module_init(toi_compress_load
);
426 module_exit(toi_compress_unload
);
427 MODULE_LICENSE("GPL");
428 MODULE_AUTHOR("Nigel Cunningham");
429 MODULE_DESCRIPTION("Compression Support for TuxOnIce");
431 late_initcall(toi_compress_load
);