2 * kernel/power/tuxonice_file.c
4 * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
6 * Distributed under GPLv2.
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.
15 * echo TuxOnIce > /path/to/my_file
17 * dd if=/dev/zero bs=1M count=<file_size_desired> >> /path/to/my_file
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.
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>
42 #include <linux/root_dev.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
{
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 */
97 MARK_RESUME_ATTEMPTED
,
98 UNMARK_RESUME_ATTEMPTED
,
101 static void set_devinfo(struct block_device
*bdev
, int target_blkbits
)
104 if (!target_blkbits
) {
105 devinfo
.bmap_shift
= devinfo
.blocks_per_page
= 0;
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)
118 static int toi_file_storage_available(void)
121 struct block_device
*bdev
=toi_file_target_bdev
;
126 switch (target_inode
->i_mode
& S_IFMT
) {
129 case S_IFIFO
: /* Socket, Char, Fifo */
131 case S_IFREG
: /* Regular file: current size - holes + free
133 result
= target_storage_available
;
135 case S_IFBLK
: /* Block device */
136 if (!bdev
->bd_disk
) {
137 printk("bdev->bd_disk null.\n");
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
)
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))
164 return (j
== devinfo
.blocks_per_page
);
167 static int size_ignoring_ignored_pages(void)
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
))
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)
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);
206 for (i
= 0; i
< (target_inode
->i_size
>> PAGE_SHIFT
); i
++) {
209 if (!has_contiguous_blocks(i
))
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
) {
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
;
233 __populate_block_list(extent_min
,
236 extent_min
= new_sector
;
237 extent_max
= extent_min
+
238 devinfo
.blocks_per_page
- 1;
243 __populate_block_list(extent_min
, extent_max
);
246 static void toi_file_cleanup(int finishing_cycle
)
248 if (toi_file_target_bdev
) {
250 bd_release(toi_file_target_bdev
);
255 blkdev_put(toi_file_target_bdev
);
258 toi_file_target_bdev
= NULL
;
260 set_devinfo(NULL
, 0);
261 target_storage_available
= 0;
264 if (target_file
> 0) {
265 filp_close(target_file
, NULL
);
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
);
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
,
295 if (!target
|| !strlen(target
))
298 target_file
= filp_open(target
, O_RDWR
|O_LARGEFILE
, 0);
300 if (IS_ERR(target_file
) || !target_file
) {
303 printk("Open file %s returned %p.\n",
304 target
, target_file
);
310 resume_file_dev_t
= name_to_dev_t(target
);
311 if (!resume_file_dev_t
) {
313 int error
= vfs_stat(target
, &stat
);
314 printk("Open file %s returned %p and name_to_devt "
315 "failed.\n", target
, target_file
);
317 printk("Stating the file also failed."
318 " Nothing more we can do.\n");
320 resume_file_dev_t
= stat
.rdev
;
324 toi_file_target_bdev
= open_by_devnum(resume_file_dev_t
,
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
);
332 target_inode
= toi_file_target_bdev
->bd_inode
;
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");
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
))
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
);
356 target_storage_available
= size_ignoring_ignored_pages();
359 target_firstblock
= bmap(target_inode
, 0) << devinfo
.bmap_shift
;
365 filp_close(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);
383 if (header
->resumed_before
)
384 set_toi_state(TOI_RESUMED_BEFORE
);
386 clear_toi_state(TOI_RESUMED_BEFORE
);
388 target_header_start
= header
->first_header_block
;
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
;
403 static int toi_file_storage_allocated(void)
408 if (target_is_normal_file())
409 return (int) target_storage_available
;
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
))
420 toi_put_extent_chain(&block_chain
);
422 header_pages_allocated
= 0;
423 main_pages_allocated
= 0;
424 main_pages_requested
= 0;
428 static int __toi_file_allocate_storage(int main_storage_requested
,
431 static int toi_file_allocate_header_space(int space_requested
)
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");
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 "
448 header_pages_allocated
= i
;
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]);
461 static int toi_file_allocate_storage(int space_requested
)
463 if (__toi_file_allocate_storage(space_requested
,
464 header_pages_allocated
))
467 main_pages_requested
= space_requested
;
471 static int __toi_file_allocate_storage(int main_space_requested
,
472 int header_space_requested
)
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)
486 populate_block_list();
488 toi_message(TOI_WRITER
, TOI_MEDIUM
, 0,
489 "Finished with block_chain.size == %d.\n",
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
);
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
);
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
);
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
,
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
<<
557 toi_bio_ops
.bdev_page_io(WRITE
, toi_file_target_bdev
,
559 virt_to_page(toi_writer_buffer
));
561 toi_bio_ops
.finish_all_io();
568 #ifdef CONFIG_DEVFS_FS
569 int create_dev(char *name
, dev_t dev
, char *devfs_name
);
571 static int create_dev(char *name
, dev_t dev
, char *devfs_name
)
574 return sys_mknod(name
, S_IFBLK
|0600, new_encode_dev(dev
));
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);
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
);
599 sys_unlink("/dev/ram");
600 sys_unlink("/dev/root");
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
,
611 virt_to_page((unsigned long) toi_writer_buffer
));
619 * Ramdisk support based heavily on init/do_mounts_rd.c
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.
630 * May not return if user choose to reboot at a warning.
631 * -EINVAL if cannot resume at this time. Booting should continue
635 static int toi_file_read_header_init(void)
638 struct block_device
*tmp
;
640 if (test_toi_state(TOI_TRY_RESUME_RD
))
643 result
= file_init();
646 printk("FileAllocator read header init: Failed to initialise "
647 "reading the first page of data.\n");
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
);
660 toi_writer_buffer
+ toi_writer_buffer_posn
,
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
);
681 static int toi_file_signature_op(int op
)
684 int result
= 0, changed
= 0;
685 struct toi_file_header
*header
;
687 if(toi_file_target_bdev
<= 0)
690 cur
= (char *) get_zeroed_page(TOI_ATOMIC_GFP
);
692 printk("Unable to allocate a page for reading the image "
697 toi_bio_ops
.bdev_page_io(READ
, toi_file_target_bdev
,
701 header
= (struct toi_file_header
*) cur
;
702 result
= parse_signature(header
);
709 strcpy(header
->sig
, NoImage
);
710 header
->resumed_before
= 0;
711 result
= changed
= 1;
713 case MARK_RESUME_ATTEMPTED
:
715 header
->resumed_before
= 1;
719 case UNMARK_RESUME_ATTEMPTED
:
721 header
->resumed_before
= 0;
728 toi_bio_ops
.bdev_page_io(WRITE
, toi_file_target_bdev
,
733 toi_bio_ops
.finish_all_io();
734 free_page((unsigned long) cur
);
743 static int toi_file_print_debug_stats(char *buffer
, int size
)
747 if (toiActiveAllocator
!= &toi_fileops
) {
748 len
= snprintf_used(buffer
, size
, "- FileAllocator inactive.\n");
752 len
= snprintf_used(buffer
, size
, "- FileAllocator active.\n");
754 len
+= snprintf_used(buffer
+len
, size
-len
, " Storage available for image: "
756 toi_file_storage_allocated());
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
) +
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
);
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);
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
,
830 offset
+= snprintf(buffer
+ offset
, PAGE_SIZE
- offset
,
831 ":0x%lx", sector
<< devinfo
.bmap_shift
);
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) {
849 printk("TuxOnIce: FileAllocator: File signature found.\n");
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;
858 set_toi_state(TOI_CAN_HIBERNATE
);
862 clear_toi_state(TOI_CAN_HIBERNATE
);
868 printk("TuxOnIce: FileAllocator: Sorry. No signature found at"
872 printk("TuxOnIce: FileAllocator: Sorry. Target is not"
873 " set for hibernating.\n");
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) ?
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]
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
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)) {
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
924 if (toi_file_target_bdev
)
927 devstart
= thischar
= commandline
;
928 while ((*thischar
!= ':') && (*thischar
!= '@') &&
929 ((thischar
- commandline
) < 250) && (*thischar
))
932 if (*thischar
== ':') {
938 while ((*thischar
!= '@') && ((thischar
- commandline
) < 250) && (*thischar
))
941 if (*thischar
== '@') {
942 at_symbol
= thischar
;
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
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);
962 target_firstblock
= (int) simple_strtoul(colon
+ 1, NULL
, 0);
964 target_firstblock
= 0;
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
);
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
;
986 if (target_blocksize
)
987 set_devinfo(toi_file_target_bdev
, ffs(target_blocksize
));
989 result
= __test_toi_file_target(commandline
, 1, 0);
993 clear_toi_state(TOI_CAN_HIBERNATE
);
996 printk("Resuming %sabled.\n", result
? "dis" : "en");
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
)
1037 if (starting_cycle
& SYSFS_HIBERNATE
&& !*toi_file_target
) {
1038 printk("FileAllocator is the active writer, "
1039 "but no filename has been set.\n");
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",
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
);
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");
1125 late_initcall(toi_file_load
);