replace some function names
[linux-2.6/zen-sources.git] / kernel / power / tuxonice_compress.c
blob3e6ce42c3cf154ea81689297608a34ccb99d93a3
1 /*
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,
9 * using cryptoapi.
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"
19 #include "tuxonice.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);
35 struct cpu_context {
36 u8 *page_buffer;
37 struct crypto_comp *transform;
38 unsigned int len;
39 char *buffer_start;
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)
53 int cpu;
55 if (!toi_or_resume)
56 return;
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;
73 * toi_crypto_prepare
75 * Prepare to do some work by allocating buffers and transforms.
77 static int toi_compress_crypto_prepare(void)
79 int cpu;
81 if (!*toi_compressor_name) {
82 printk(KERN_INFO "TuxOnIce: Compression enabled but no "
83 "compressor name set.\n");
84 return 1;
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",
93 toi_compressor_name);
94 this->transform = NULL;
95 return 1;
98 this->page_buffer =
99 (char *) toi_get_zeroed_page(16, TOI_ATOMIC_GFP);
101 if (!this->page_buffer) {
102 printk(KERN_ERR
103 "Failed to allocate a page buffer for TuxOnIce "
104 "encryption driver.\n");
105 return -ENOMEM;
109 return 0;
113 * toi_compress_init
116 static int toi_compress_init(int toi_or_resume)
118 if (!toi_or_resume)
119 return 0;
121 toi_compress_bytes_in = toi_compress_bytes_out = 0;
123 next_driver = toi_get_next_filter(&toi_compression_ops);
125 if (!next_driver)
126 return -ECHILD;
128 toi_compress_prepare_result = toi_compress_crypto_prepare();
130 return 0;
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");
141 if (rw == READ)
142 return -ENODEV;
143 else
144 toi_compression_ops.enabled = 0;
147 return 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
161 * zlib errs.
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);
169 if (!ctx->transform)
170 return next_driver->write_page(index, buffer_page, buf_size);
172 ctx->buffer_start = kmap(buffer_page);
174 ctx->len = buf_size;
176 ret = crypto_comp_compress(ctx->transform,
177 ctx->buffer_start, buf_size,
178 ctx->page_buffer, &ctx->len);
180 kunmap(buffer_page);
182 if (ret) {
183 printk(KERN_INFO "Compression failed.\n");
184 goto failure;
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),
195 ctx->len);
196 else
197 ret = next_driver->write_page(index, buffer_page, buf_size);
199 failure:
200 return ret;
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
208 * is filled.
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();
215 unsigned int len;
216 unsigned int outlen = PAGE_SIZE;
217 char *buffer_start;
218 struct cpu_context *ctx = &per_cpu(contexts, cpu);
220 if (!ctx->transform)
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)
234 return ret;
236 buffer_start = kmap(buffer_page);
237 memcpy(ctx->page_buffer, buffer_start, len);
238 ret = crypto_comp_decompress(
239 ctx->transform,
240 ctx->page_buffer,
241 len, buffer_start, &outlen);
242 if (ret)
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",
248 outlen, PAGE_SIZE);
249 printk(KERN_ERR "Decompression yielded %d bytes instead of "
250 "%ld.\n", outlen, PAGE_SIZE);
251 ret = -EIO;
252 *buf_size = outlen;
254 kunmap(buffer_page);
255 return ret;
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;
271 int len;
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);
277 else
278 len = snprintf_used(buffer, size, "- Compressor is not set.\n");
280 if (pages_in)
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);
286 return len;
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
294 * operation.
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;
316 int total_len;
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,
325 namelen);
326 total_len = 4 * sizeof(unsigned long) + namelen;
327 return total_len;
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
335 * resume time.
337 static void toi_compress_load_config_info(char *buffer, int size)
339 int namelen;
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),
348 namelen)) {
349 toi_compress_cleanup(1);
350 strncpy(toi_compressor_name, buffer + 4 * sizeof(unsigned long),
351 namelen);
352 toi_compress_crypto_prepare();
354 return;
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)
369 return 100;
370 else
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,
379 0, 99, 0, NULL),
380 SYSFS_INT("enabled", SYSFS_RW, &toi_compression_ops.enabled, 0, 1, 0,
381 NULL),
382 SYSFS_STRING("algorithm", SYSFS_RW, toi_compressor_name, 31, 0, NULL),
386 * Ops structure.
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);
419 #ifdef MODULE
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");
430 #else
431 late_initcall(toi_compress_load);
432 #endif