Complete the renaming to TuxOnIce with function names, vars etc.
[linux-2.6/suspend2-head.git] / kernel / power / tuxonice_file.c
blob6f04ea1446a806a00cf82a4baa4239f39e0988f9
1 /*
2 * kernel/power/tuxonice_file.c
4 * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
6 * Distributed under GPLv2.
7 *
8 * This file encapsulates functions for usage of a simple file as a
9 * backing store. It is based upon the swapallocator, and shares the
10 * same basic working. Here, though, we have nothing to do with
11 * swapspace, and only one device to worry about.
13 * The user can just
15 * echo TuxOnIce > /path/to/my_file
17 * dd if=/dev/zero bs=1M count=<file_size_desired> >> /path/to/my_file
19 * and
21 * echo /path/to/my_file > /sys/power/suspend2/file/target
23 * then put what they find in /sys/power/suspend2/resume
24 * as their resume= parameter in lilo.conf (and rerun lilo if using it).
26 * Having done this, they're ready to hibernate and resume.
28 * TODO:
29 * - File resizing.
32 #include <linux/suspend.h>
33 #include <linux/module.h>
34 #include <linux/blkdev.h>
35 #include <linux/file.h>
36 #include <linux/stat.h>
37 #include <linux/mount.h>
38 #include <linux/statfs.h>
39 #include <linux/syscalls.h>
40 #include <linux/namei.h>
41 #include <linux/fs.h>
42 #include <linux/root_dev.h>
44 #include "tuxonice.h"
45 #include "tuxonice_sysfs.h"
46 #include "tuxonice_modules.h"
47 #include "tuxonice_ui.h"
48 #include "tuxonice_extent.h"
49 #include "tuxonice_io.h"
50 #include "tuxonice_storage.h"
51 #include "tuxonice_block_io.h"
53 static struct toi_module_ops toi_fileops;
55 /* Details of our target. */
57 char toi_file_target[256];
58 static struct inode *target_inode;
59 static struct file *target_file;
60 static struct block_device *toi_file_target_bdev;
61 static dev_t resume_file_dev_t;
62 static int used_devt = 0;
63 static int setting_toi_file_target = 0;
64 static sector_t target_firstblock = 0, target_header_start = 0;
65 static int target_storage_available = 0;
66 static int target_claim = 0;
68 static char HaveImage[] = "HaveImage\n";
69 static char NoImage[] = "TuxOnIce\n";
70 #define sig_size (sizeof(HaveImage) + 1)
72 struct toi_file_header {
73 char sig[sig_size];
74 int resumed_before;
75 unsigned long first_header_block;
78 extern char *__initdata root_device_name;
80 /* Header Page Information */
81 static int header_pages_allocated;
83 /* Main Storage Pages */
84 static int main_pages_allocated, main_pages_requested;
86 #define target_is_normal_file() (S_ISREG(target_inode->i_mode))
88 static struct toi_bdev_info devinfo;
90 /* Extent chain for blocks */
91 static struct extent_chain block_chain;
93 /* Signature operations */
94 enum {
95 GET_IMAGE_EXISTS,
96 INVALIDATE,
97 MARK_RESUME_ATTEMPTED,
98 UNMARK_RESUME_ATTEMPTED,
101 static void set_devinfo(struct block_device *bdev, int target_blkbits)
103 devinfo.bdev = bdev;
104 if (!target_blkbits) {
105 devinfo.bmap_shift = devinfo.blocks_per_page = 0;
106 } else {
107 devinfo.bmap_shift = target_blkbits - 9;
108 devinfo.blocks_per_page = (1 << (PAGE_SHIFT - target_blkbits));
112 static int adjust_for_extra_pages(int unadjusted)
114 return (unadjusted << PAGE_SHIFT) / (PAGE_SIZE + sizeof(unsigned long)
115 + sizeof(int));
118 static int toi_file_storage_available(void)
120 int result = 0;
121 struct block_device *bdev=toi_file_target_bdev;
123 if (!target_inode)
124 return 0;
126 switch (target_inode->i_mode & S_IFMT) {
127 case S_IFSOCK:
128 case S_IFCHR:
129 case S_IFIFO: /* Socket, Char, Fifo */
130 return -1;
131 case S_IFREG: /* Regular file: current size - holes + free
132 space on part */
133 result = target_storage_available;
134 break;
135 case S_IFBLK: /* Block device */
136 if (!bdev->bd_disk) {
137 printk("bdev->bd_disk null.\n");
138 return 0;
141 result = (bdev->bd_part ?
142 bdev->bd_part->nr_sects :
143 bdev->bd_disk->capacity) >> (PAGE_SHIFT - 9);
146 return adjust_for_extra_pages(result);
149 static int has_contiguous_blocks(int page_num)
151 int j;
152 sector_t last = 0;
154 for (j = 0; j < devinfo.blocks_per_page; j++) {
155 sector_t this = bmap(target_inode,
156 page_num * devinfo.blocks_per_page + j);
158 if (!this || (last && (last + 1) != this))
159 break;
161 last = this;
164 return (j == devinfo.blocks_per_page);
167 static int size_ignoring_ignored_pages(void)
169 int mappable = 0, i;
171 if (!target_is_normal_file())
172 return toi_file_storage_available();
174 for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT) ; i++)
175 if (has_contiguous_blocks(i))
176 mappable++;
178 return mappable;
181 static void __populate_block_list(int min, int max)
183 if (test_action_state(TOI_TEST_BIO))
184 printk("Adding extent %d-%d.\n", min << devinfo.bmap_shift,
185 ((max + 1) << devinfo.bmap_shift) - 1);
187 toi_add_to_extent_chain(&block_chain, min, max);
190 static void populate_block_list(void)
192 int i;
193 int extent_min = -1, extent_max = -1, got_header = 0;
195 if (block_chain.first)
196 toi_put_extent_chain(&block_chain);
198 if (!target_is_normal_file()) {
199 if (target_storage_available > 0)
200 __populate_block_list(devinfo.blocks_per_page,
201 (target_storage_available + 1) *
202 devinfo.blocks_per_page - 1);
203 return;
206 for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT); i++) {
207 sector_t new_sector;
209 if (!has_contiguous_blocks(i))
210 continue;
212 new_sector = bmap(target_inode,
213 (i * devinfo.blocks_per_page));
216 * Ignore the first block in the file.
217 * It gets the header.
219 if (new_sector == target_firstblock >> devinfo.bmap_shift) {
220 got_header = 1;
221 continue;
225 * I'd love to be able to fill in holes and resize
226 * files, but not yet...
229 if (new_sector == extent_max + 1)
230 extent_max+= devinfo.blocks_per_page;
231 else {
232 if (extent_min > -1)
233 __populate_block_list(extent_min,
234 extent_max);
236 extent_min = new_sector;
237 extent_max = extent_min +
238 devinfo.blocks_per_page - 1;
242 if (extent_min > -1)
243 __populate_block_list(extent_min, extent_max);
246 static void toi_file_cleanup(int finishing_cycle)
248 if (toi_file_target_bdev) {
249 if (target_claim) {
250 bd_release(toi_file_target_bdev);
251 target_claim = 0;
254 if (used_devt) {
255 blkdev_put(toi_file_target_bdev);
256 used_devt = 0;
258 toi_file_target_bdev = NULL;
259 target_inode = NULL;
260 set_devinfo(NULL, 0);
261 target_storage_available = 0;
264 if (target_file > 0) {
265 filp_close(target_file, NULL);
266 target_file = NULL;
271 * reopen_resume_devt
273 * Having opened resume= once, we remember the major and
274 * minor nodes and use them to reopen the bdev for checking
275 * whether an image exists (possibly when starting a resume).
277 static void reopen_resume_devt(void)
279 toi_file_target_bdev = open_by_devnum(resume_file_dev_t, FMODE_READ);
280 if (IS_ERR(toi_file_target_bdev)) {
281 printk("Got a dev_num (%lx) but failed to open it.\n",
282 (unsigned long) resume_file_dev_t);
283 return;
285 target_inode = toi_file_target_bdev->bd_inode;
286 set_devinfo(toi_file_target_bdev, target_inode->i_blkbits);
289 static void toi_file_get_target_info(char *target, int get_size,
290 int resume_param)
292 if (target_file)
293 toi_file_cleanup(0);
295 if (!target || !strlen(target))
296 return;
298 target_file = filp_open(target, O_RDWR|O_LARGEFILE, 0);
300 if (IS_ERR(target_file) || !target_file) {
302 if (!resume_param) {
303 printk("Open file %s returned %p.\n",
304 target, target_file);
305 target_file = NULL;
306 return;
309 target_file = NULL;
310 resume_file_dev_t = name_to_dev_t(target);
311 if (!resume_file_dev_t) {
312 struct kstat stat;
313 int error = vfs_stat(target, &stat);
314 printk("Open file %s returned %p and name_to_devt "
315 "failed.\n", target, target_file);
316 if (error)
317 printk("Stating the file also failed."
318 " Nothing more we can do.\n");
319 else
320 resume_file_dev_t = stat.rdev;
321 return;
324 toi_file_target_bdev = open_by_devnum(resume_file_dev_t,
325 FMODE_READ);
326 if (IS_ERR(toi_file_target_bdev)) {
327 printk("Got a dev_num (%lx) but failed to open it.\n",
328 (unsigned long) resume_file_dev_t);
329 return;
331 used_devt = 1;
332 target_inode = toi_file_target_bdev->bd_inode;
333 } else
334 target_inode = target_file->f_mapping->host;
336 if (S_ISLNK(target_inode->i_mode) || S_ISDIR(target_inode->i_mode) ||
337 S_ISSOCK(target_inode->i_mode) || S_ISFIFO(target_inode->i_mode)) {
338 printk("File support works with regular files, character "
339 "files and block devices.\n");
340 goto cleanup;
343 if (!used_devt) {
344 if (S_ISBLK(target_inode->i_mode)) {
345 toi_file_target_bdev = I_BDEV(target_inode);
346 if (!bd_claim(toi_file_target_bdev, &toi_fileops))
347 target_claim = 1;
348 } else
349 toi_file_target_bdev = target_inode->i_sb->s_bdev;
350 resume_file_dev_t = toi_file_target_bdev->bd_dev;
353 set_devinfo(toi_file_target_bdev, target_inode->i_blkbits);
355 if (get_size)
356 target_storage_available = size_ignoring_ignored_pages();
358 if (!resume_param)
359 target_firstblock = bmap(target_inode, 0) << devinfo.bmap_shift;
361 return;
362 cleanup:
363 target_inode = NULL;
364 if (target_file) {
365 filp_close(target_file, NULL);
366 target_file = NULL;
368 set_devinfo(NULL, 0);
369 target_storage_available = 0;
372 static int parse_signature(struct toi_file_header *header)
374 int have_image = !memcmp(HaveImage, header->sig, sizeof(HaveImage) - 1);
375 int no_image_header = !memcmp(NoImage, header->sig, sizeof(NoImage) - 1);
377 if (no_image_header)
378 return 0;
380 if (!have_image)
381 return -1;
383 if (header->resumed_before)
384 set_toi_state(TOI_RESUMED_BEFORE);
385 else
386 clear_toi_state(TOI_RESUMED_BEFORE);
388 target_header_start = header->first_header_block;
389 return 1;
392 /* prepare_signature */
394 static int prepare_signature(struct toi_file_header *current_header,
395 unsigned long first_header_block)
397 strncpy(current_header->sig, HaveImage, sizeof(HaveImage));
398 current_header->resumed_before = 0;
399 current_header->first_header_block = first_header_block;
400 return 0;
403 static int toi_file_storage_allocated(void)
405 if (!target_inode)
406 return 0;
408 if (target_is_normal_file())
409 return (int) target_storage_available;
410 else
411 return header_pages_allocated + main_pages_requested;
414 static int toi_file_release_storage(void)
416 if (test_action_state(TOI_KEEP_IMAGE) &&
417 test_toi_state(TOI_NOW_RESUMING))
418 return 0;
420 toi_put_extent_chain(&block_chain);
422 header_pages_allocated = 0;
423 main_pages_allocated = 0;
424 main_pages_requested = 0;
425 return 0;
428 static int __toi_file_allocate_storage(int main_storage_requested,
429 int header_storage);
431 static int toi_file_allocate_header_space(int space_requested)
433 int i;
435 if (!block_chain.first && __toi_file_allocate_storage(
436 main_pages_requested, space_requested)) {
437 printk("Failed to allocate space for the header.\n");
438 return -ENOSPC;
441 toi_extent_state_goto_start(&toi_writer_posn);
442 toi_bio_ops.forward_one_page(); /* To first page */
444 for (i = 0; i < space_requested; i++) {
445 if (toi_bio_ops.forward_one_page()) {
446 printk("Out of space while seeking to allocate "
447 "header pages,\n");
448 header_pages_allocated = i;
449 return -ENOSPC;
453 header_pages_allocated = space_requested;
455 /* The end of header pages will be the start of pageset 2 */
456 toi_extent_state_save(&toi_writer_posn,
457 &toi_writer_posn_save[2]);
458 return 0;
461 static int toi_file_allocate_storage(int space_requested)
463 if (__toi_file_allocate_storage(space_requested,
464 header_pages_allocated))
465 return -ENOSPC;
467 main_pages_requested = space_requested;
468 return -ENOSPC;
471 static int __toi_file_allocate_storage(int main_space_requested,
472 int header_space_requested)
474 int result = 0;
476 int extra_pages = DIV_ROUND_UP(main_space_requested *
477 (sizeof(unsigned long) + sizeof(int)), PAGE_SIZE);
478 int pages_to_get = main_space_requested + extra_pages +
479 header_space_requested;
480 int blocks_to_get = pages_to_get - block_chain.size;
482 /* Only release_storage reduces the size */
483 if (blocks_to_get < 1)
484 return 0;
486 populate_block_list();
488 toi_message(TOI_WRITER, TOI_MEDIUM, 0,
489 "Finished with block_chain.size == %d.\n",
490 block_chain.size);
492 if (block_chain.size < pages_to_get) {
493 printk("Block chain size (%d) < header pages (%d) + extra pages (%d) + main pages (%d) (=%d pages).\n",
494 block_chain.size, header_pages_allocated, extra_pages,
495 main_space_requested, pages_to_get);
496 result = -ENOSPC;
499 main_pages_requested = main_space_requested;
500 main_pages_allocated = main_space_requested + extra_pages;
502 toi_file_allocate_header_space(header_pages_allocated);
503 return result;
506 static int toi_file_write_header_init(void)
508 toi_extent_state_goto_start(&toi_writer_posn);
510 toi_writer_buffer_posn = toi_header_bytes_used = 0;
512 /* Info needed to bootstrap goes at the start of the header.
513 * First we save the basic info needed for reading, including the number
514 * of header pages. Then we save the structs containing data needed
515 * for reading the header pages back.
516 * Note that even if header pages take more than one page, when we
517 * read back the info, we will have restored the location of the
518 * next header page by the time we go to use it.
521 toi_bio_ops.rw_header_chunk(WRITE, &toi_fileops,
522 (char *) &toi_writer_posn_save,
523 sizeof(toi_writer_posn_save));
525 toi_bio_ops.rw_header_chunk(WRITE, &toi_fileops,
526 (char *) &devinfo, sizeof(devinfo));
528 toi_serialise_extent_chain(&toi_fileops, &block_chain);
530 return 0;
533 static int toi_file_write_header_cleanup(void)
535 struct toi_file_header *header;
537 /* Write any unsaved data */
538 if (toi_writer_buffer_posn)
539 toi_bio_ops.write_header_chunk_finish();
541 toi_bio_ops.finish_all_io();
543 toi_extent_state_goto_start(&toi_writer_posn);
544 toi_bio_ops.forward_one_page();
546 /* Adjust image header */
547 toi_bio_ops.bdev_page_io(READ, toi_file_target_bdev,
548 target_firstblock,
549 virt_to_page(toi_writer_buffer));
551 header = (struct toi_file_header *) toi_writer_buffer;
553 prepare_signature(header,
554 toi_writer_posn.current_offset <<
555 devinfo.bmap_shift);
557 toi_bio_ops.bdev_page_io(WRITE, toi_file_target_bdev,
558 target_firstblock,
559 virt_to_page(toi_writer_buffer));
561 toi_bio_ops.finish_all_io();
563 return 0;
566 /* HEADER READING */
568 #ifdef CONFIG_DEVFS_FS
569 int create_dev(char *name, dev_t dev, char *devfs_name);
570 #else
571 static int create_dev(char *name, dev_t dev, char *devfs_name)
573 sys_unlink(name);
574 return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
576 #endif
578 static int rd_init(void)
580 toi_writer_buffer_posn = 0;
582 create_dev("/dev/root", ROOT_DEV, root_device_name);
583 create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
585 toi_read_fd = sys_open("/dev/root", O_RDONLY, 0);
586 if (toi_read_fd < 0)
587 goto out;
589 sys_read(toi_read_fd, toi_writer_buffer, BLOCK_SIZE);
591 memcpy(&toi_writer_posn_save,
592 toi_writer_buffer + toi_writer_buffer_posn,
593 sizeof(toi_writer_posn_save));
595 toi_writer_buffer_posn += sizeof(toi_writer_posn_save);
597 return 0;
598 out:
599 sys_unlink("/dev/ram");
600 sys_unlink("/dev/root");
601 return -EIO;
604 static int file_init(void)
606 toi_writer_buffer_posn = 0;
608 /* Read toi_file configuration */
609 toi_bio_ops.bdev_page_io(READ, toi_file_target_bdev,
610 target_header_start,
611 virt_to_page((unsigned long) toi_writer_buffer));
613 return 0;
617 * read_header_init()
619 * Ramdisk support based heavily on init/do_mounts_rd.c
621 * Description:
622 * 1. Attempt to read the device specified with resume=.
623 * 2. Check the contents of the header for our signature.
624 * 3. Warn, ignore, reset and/or continue as appropriate.
625 * 4. If continuing, read the toi_file configuration section
626 * of the header and set up block device info so we can read
627 * the rest of the header & image.
629 * Returns:
630 * May not return if user choose to reboot at a warning.
631 * -EINVAL if cannot resume at this time. Booting should continue
632 * normally.
635 static int toi_file_read_header_init(void)
637 int result;
638 struct block_device *tmp;
640 if (test_toi_state(TOI_TRY_RESUME_RD))
641 result = rd_init();
642 else
643 result = file_init();
645 if (result) {
646 printk("FileAllocator read header init: Failed to initialise "
647 "reading the first page of data.\n");
648 return result;
651 memcpy(&toi_writer_posn_save,
652 toi_writer_buffer + toi_writer_buffer_posn,
653 sizeof(toi_writer_posn_save));
655 toi_writer_buffer_posn += sizeof(toi_writer_posn_save);
657 tmp = devinfo.bdev;
659 memcpy(&devinfo,
660 toi_writer_buffer + toi_writer_buffer_posn,
661 sizeof(devinfo));
663 devinfo.bdev = tmp;
664 toi_writer_buffer_posn += sizeof(devinfo);
666 toi_bio_ops.read_header_init();
667 toi_extent_state_goto_start(&toi_writer_posn);
668 toi_bio_ops.set_extra_page_forward();
670 toi_header_bytes_used = toi_writer_buffer_posn;
672 return toi_load_extent_chain(&block_chain);
675 static int toi_file_read_header_cleanup(void)
677 toi_bio_ops.rw_cleanup(READ);
678 return 0;
681 static int toi_file_signature_op(int op)
683 char *cur;
684 int result = 0, changed = 0;
685 struct toi_file_header *header;
687 if(toi_file_target_bdev <= 0)
688 return -1;
690 cur = (char *) get_zeroed_page(TOI_ATOMIC_GFP);
691 if (!cur) {
692 printk("Unable to allocate a page for reading the image "
693 "signature.\n");
694 return -ENOMEM;
697 toi_bio_ops.bdev_page_io(READ, toi_file_target_bdev,
698 target_firstblock,
699 virt_to_page(cur));
701 header = (struct toi_file_header *) cur;
702 result = parse_signature(header);
704 switch (op) {
705 case INVALIDATE:
706 if (result == -1)
707 goto out;
709 strcpy(header->sig, NoImage);
710 header->resumed_before = 0;
711 result = changed = 1;
712 break;
713 case MARK_RESUME_ATTEMPTED:
714 if (result == 1) {
715 header->resumed_before = 1;
716 changed = 1;
718 break;
719 case UNMARK_RESUME_ATTEMPTED:
720 if (result == 1) {
721 header->resumed_before = 0;
722 changed = 1;
724 break;
727 if (changed)
728 toi_bio_ops.bdev_page_io(WRITE, toi_file_target_bdev,
729 target_firstblock,
730 virt_to_page(cur));
732 out:
733 toi_bio_ops.finish_all_io();
734 free_page((unsigned long) cur);
735 return result;
738 /* Print debug info
740 * Description:
743 static int toi_file_print_debug_stats(char *buffer, int size)
745 int len = 0;
747 if (toiActiveAllocator != &toi_fileops) {
748 len = snprintf_used(buffer, size, "- FileAllocator inactive.\n");
749 return len;
752 len = snprintf_used(buffer, size, "- FileAllocator active.\n");
754 len+= snprintf_used(buffer+len, size-len, " Storage available for image: "
755 "%ld pages.\n",
756 toi_file_storage_allocated());
758 return len;
762 * Storage needed
764 * Returns amount of space in the image header required
765 * for the toi_file's data.
767 * We ensure the space is allocated, but actually save the
768 * data from write_header_init and therefore don't also define a
769 * save_config_info routine.
771 static int toi_file_storage_needed(void)
773 return sig_size + strlen(toi_file_target) + 1 +
774 3 * sizeof(struct extent_iterate_saved_state) +
775 sizeof(devinfo) +
776 sizeof(struct extent_chain) - 2 * sizeof(void *) +
777 (2 * sizeof(unsigned long) * block_chain.num_extents);
781 * toi_file_remove_image
784 static int toi_file_remove_image(void)
786 toi_file_release_storage();
787 return toi_file_signature_op(INVALIDATE);
791 * Image_exists
795 static int toi_file_image_exists(void)
797 if (!toi_file_target_bdev)
798 reopen_resume_devt();
800 return toi_file_signature_op(GET_IMAGE_EXISTS);
804 * Mark resume attempted.
806 * Record that we tried to resume from this image.
809 static void toi_file_mark_resume_attempted(int mark)
811 toi_file_signature_op(mark ? MARK_RESUME_ATTEMPTED:
812 UNMARK_RESUME_ATTEMPTED);
815 static void toi_file_set_resume_param(void)
817 char *buffer = (char *) get_zeroed_page(TOI_ATOMIC_GFP);
818 char *buffer2 = (char *) get_zeroed_page(TOI_ATOMIC_GFP);
819 unsigned long sector = bmap(target_inode, 0);
820 int offset = 0;
822 if (toi_file_target_bdev) {
823 set_devinfo(toi_file_target_bdev, target_inode->i_blkbits);
825 bdevname(toi_file_target_bdev, buffer2);
826 offset += snprintf(buffer + offset, PAGE_SIZE - offset,
827 "/dev/%s", buffer2);
829 if (sector)
830 offset += snprintf(buffer + offset, PAGE_SIZE - offset,
831 ":0x%lx", sector << devinfo.bmap_shift);
832 } else
833 offset += snprintf(buffer + offset, PAGE_SIZE - offset,
834 "%s is not a valid target.", toi_file_target);
836 sprintf(resume_file, "file:%s", buffer);
838 free_page((unsigned long) buffer);
839 free_page((unsigned long) buffer2);
841 toi_attempt_to_parse_resume_device(1);
844 static int __test_toi_file_target(char *target, int resume_time, int quiet)
846 toi_file_get_target_info(target, 0, resume_time);
847 if (toi_file_signature_op(GET_IMAGE_EXISTS) > -1) {
848 if (!quiet)
849 printk("TuxOnIce: FileAllocator: File signature found.\n");
850 if (!resume_time)
851 toi_file_set_resume_param();
853 toi_bio_ops.set_devinfo(&devinfo);
854 toi_writer_posn.chains = &block_chain;
855 toi_writer_posn.num_chains = 1;
857 if (!resume_time)
858 set_toi_state(TOI_CAN_HIBERNATE);
859 return 0;
862 clear_toi_state(TOI_CAN_HIBERNATE);
864 if (quiet)
865 return 1;
867 if (*target)
868 printk("TuxOnIce: FileAllocator: Sorry. No signature found at"
869 " %s.\n", target);
870 else
871 if (!resume_time)
872 printk("TuxOnIce: FileAllocator: Sorry. Target is not"
873 " set for hibernating.\n");
875 return 1;
878 static void test_toi_file_target(void)
880 setting_toi_file_target = 1;
882 printk("TuxOnIce: Hibernating %sabled.\n",
883 __test_toi_file_target(toi_file_target, 0, 1) ?
884 "dis" : "en");
886 setting_toi_file_target = 0;
890 * Parse Image Location
892 * Attempt to parse a resume= parameter.
893 * File Allocator accepts:
894 * resume=file:DEVNAME[:FIRSTBLOCK]
896 * Where:
897 * DEVNAME is convertable to a dev_t by name_to_dev_t
898 * FIRSTBLOCK is the location of the first block in the file.
899 * BLOCKSIZE is the logical blocksize >= SECTOR_SIZE & <= PAGE_SIZE,
900 * mod SECTOR_SIZE == 0 of the device.
901 * Data is validated by attempting to read a header from the
902 * location given. Failure will result in toi_file refusing to
903 * save an image, and a reboot with correct parameters will be
904 * necessary.
907 static int toi_file_parse_sig_location(char *commandline,
908 int only_writer, int quiet)
910 char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
911 int result = -EINVAL, target_blocksize = 0;
913 if (strncmp(commandline, "file:", 5)) {
914 if (!only_writer)
915 return 1;
916 } else
917 commandline += 5;
920 * Don't check signature again if we're beginning a cycle. If we already
921 * did the initialisation successfully, assume we'll be okay when it comes
922 * to resuming.
924 if (toi_file_target_bdev)
925 return 0;
927 devstart = thischar = commandline;
928 while ((*thischar != ':') && (*thischar != '@') &&
929 ((thischar - commandline) < 250) && (*thischar))
930 thischar++;
932 if (*thischar == ':') {
933 colon = thischar;
934 *colon = 0;
935 thischar++;
938 while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
939 thischar++;
941 if (*thischar == '@') {
942 at_symbol = thischar;
943 *at_symbol = 0;
947 * For the toi_file, you can be able to resume, but not hibernate,
948 * because the resume= is set correctly, but the toi_file_target
949 * isn't.
951 * We may have come here as a result of setting resume or
952 * toi_file_target. We only test the toi_file target in the
953 * former case (it's already done in the later), and we do it before
954 * setting the block number ourselves. It will overwrite the values
955 * given on the command line if we don't.
958 if (!setting_toi_file_target)
959 __test_toi_file_target(toi_file_target, 1, 0);
961 if (colon)
962 target_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
963 else
964 target_firstblock = 0;
966 if (at_symbol) {
967 target_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
968 if (target_blocksize & (SECTOR_SIZE - 1)) {
969 printk("FileAllocator: Blocksizes are multiples of %d.\n", SECTOR_SIZE);
970 result = -EINVAL;
971 goto out;
975 if (!quiet)
976 printk("TuxOnIce FileAllocator: Testing whether you can resume:\n");
978 toi_file_get_target_info(commandline, 0, 1);
980 if (!toi_file_target_bdev || IS_ERR(toi_file_target_bdev)) {
981 toi_file_target_bdev = NULL;
982 result = -1;
983 goto out;
986 if (target_blocksize)
987 set_devinfo(toi_file_target_bdev, ffs(target_blocksize));
989 result = __test_toi_file_target(commandline, 1, 0);
991 out:
992 if (result)
993 clear_toi_state(TOI_CAN_HIBERNATE);
995 if (!quiet)
996 printk("Resuming %sabled.\n", result ? "dis" : "en");
998 if (colon)
999 *colon = ':';
1000 if (at_symbol)
1001 *at_symbol = '@';
1003 return result;
1006 /* toi_file_save_config_info
1008 * Description: Save the target's name, not for resume time, but for all_settings.
1009 * Arguments: Buffer: Pointer to a buffer of size PAGE_SIZE.
1010 * Returns: Number of bytes used for saving our data.
1013 static int toi_file_save_config_info(char *buffer)
1015 strcpy(buffer, toi_file_target);
1016 return strlen(toi_file_target) + 1;
1019 /* toi_file_load_config_info
1021 * Description: Reload target's name.
1022 * Arguments: Buffer: Pointer to the start of the data.
1023 * Size: Number of bytes that were saved.
1026 static void toi_file_load_config_info(char *buffer, int size)
1028 strcpy(toi_file_target, buffer);
1031 static int toi_file_initialise(int starting_cycle)
1033 if (starting_cycle) {
1034 if (toiActiveAllocator != &toi_fileops)
1035 return 0;
1037 if (starting_cycle & SYSFS_HIBERNATE && !*toi_file_target) {
1038 printk("FileAllocator is the active writer, "
1039 "but no filename has been set.\n");
1040 return 1;
1044 if (toi_file_target)
1045 toi_file_get_target_info(toi_file_target, starting_cycle, 0);
1047 if (starting_cycle && (toi_file_image_exists() == -1)) {
1048 printk("%s is does not have a valid signature for hibernating.\n",
1049 toi_file_target);
1050 return 1;
1053 return 0;
1056 static struct toi_sysfs_data sysfs_params[] = {
1059 TOI_ATTR("target", SYSFS_RW),
1060 SYSFS_STRING(toi_file_target, 256, SYSFS_NEEDS_SM_FOR_WRITE),
1061 .write_side_effect = test_toi_file_target,
1065 TOI_ATTR("enabled", SYSFS_RW),
1066 SYSFS_INT(&toi_fileops.enabled, 0, 1, 0),
1067 .write_side_effect = attempt_to_parse_resume_device2,
1071 static struct toi_module_ops toi_fileops = {
1072 .type = WRITER_MODULE,
1073 .name = "file storage",
1074 .directory = "file",
1075 .module = THIS_MODULE,
1076 .print_debug_info = toi_file_print_debug_stats,
1077 .save_config_info = toi_file_save_config_info,
1078 .load_config_info = toi_file_load_config_info,
1079 .storage_needed = toi_file_storage_needed,
1080 .initialise = toi_file_initialise,
1081 .cleanup = toi_file_cleanup,
1083 .storage_available = toi_file_storage_available,
1084 .storage_allocated = toi_file_storage_allocated,
1085 .release_storage = toi_file_release_storage,
1086 .allocate_header_space = toi_file_allocate_header_space,
1087 .allocate_storage = toi_file_allocate_storage,
1088 .image_exists = toi_file_image_exists,
1089 .mark_resume_attempted = toi_file_mark_resume_attempted,
1090 .write_header_init = toi_file_write_header_init,
1091 .write_header_cleanup = toi_file_write_header_cleanup,
1092 .read_header_init = toi_file_read_header_init,
1093 .read_header_cleanup = toi_file_read_header_cleanup,
1094 .remove_image = toi_file_remove_image,
1095 .parse_sig_location = toi_file_parse_sig_location,
1097 .sysfs_data = sysfs_params,
1098 .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data),
1101 /* ---- Registration ---- */
1102 static __init int toi_file_load(void)
1104 toi_fileops.rw_init = toi_bio_ops.rw_init;
1105 toi_fileops.rw_cleanup = toi_bio_ops.rw_cleanup;
1106 toi_fileops.read_page = toi_bio_ops.read_page;
1107 toi_fileops.write_page = toi_bio_ops.write_page;
1108 toi_fileops.rw_header_chunk = toi_bio_ops.rw_header_chunk;
1110 return toi_register_module(&toi_fileops);
1113 #ifdef MODULE
1114 static __exit void toi_file_unload(void)
1116 toi_unregister_module(&toi_fileops);
1119 module_init(toi_file_load);
1120 module_exit(toi_file_unload);
1121 MODULE_LICENSE("GPL");
1122 MODULE_AUTHOR("Nigel Cunningham");
1123 MODULE_DESCRIPTION("TuxOnIce FileAllocator");
1124 #else
1125 late_initcall(toi_file_load);
1126 #endif