1 diff -ruN linux-2.6.22/Documentation/kernel-parameters.txt suspend2-2.2.10-for-2.6.22/Documentation/kernel-parameters.txt
2 --- linux-2.6.22/Documentation/kernel-parameters.txt 2007-07-11 22:18:38.000000000 +1000
3 +++ suspend2-2.2.10-for-2.6.22/Documentation/kernel-parameters.txt 2007-07-11 22:25:42.000000000 +1000
5 SH SuperH architecture is enabled.
6 SMP The kernel is an SMP kernel.
7 SPARC Sparc architecture is enabled.
8 + SUSPEND2 Suspend2 is enabled.
9 SWSUSP Software suspend is enabled.
10 TS Appropriate touchscreen support is enabled.
11 USB USB support is enabled.
13 noresume [SWSUSP] Disables resume and restores original swap
16 + noresume2 [SUSPEND2] Disables resuming and restores original swap signature.
18 no-scroll [VGA] Disables scrollback.
19 This is required for the Braillex ib80-piezo Braille
20 reader made by F.H. Papenmeier (Germany).
21 @@ -1519,6 +1522,11 @@
23 retain_initrd [RAM] Keep initrd memory after extraction
25 + resume2= [SUSPEND2] Specify the storage device for Suspend2.
26 + Format: <writer>:<writer-parameters>.
27 + See Documentation/power/suspend2.txt for details of the
28 + formats for available image writers.
30 rhash_entries= [KNL,NET]
31 Set number of hash buckets for route cache
33 diff -ruN linux-2.6.22/Documentation/power/suspend2-internals.txt suspend2-2.2.10-for-2.6.22/Documentation/power/suspend2-internals.txt
34 --- linux-2.6.22/Documentation/power/suspend2-internals.txt 1970-01-01 10:00:00.000000000 +1000
35 +++ suspend2-2.2.10-for-2.6.22/Documentation/power/suspend2-internals.txt 2007-07-11 22:25:42.000000000 +1000
37 + Software Suspend 2.2 Internal Documentation.
42 + Software Suspend 2.2 is an addition to the Linux Kernel, designed to
43 + allow the user to quickly shutdown and quickly boot a computer, without
44 + needing to close documents or programs. It is equivalent to the
45 + hibernate facility in some laptops. This implementation, however,
46 + requires no special BIOS or hardware support.
48 + The code in these files is based upon the original implementation
49 + prepared by Gabor Kuti and additional work by Pavel Machek and a
50 + host of others. This code has been substantially reworked by Nigel
51 + Cunningham, again with the help and testing of many others, not the
52 + least of whom is Michael Frank. At its heart, however, the operation is
53 + essentially the same as Gabor's version.
55 +2. Overview of operation.
57 + The basic sequence of operations is as follows:
59 + a. Quiesce all other activity.
60 + b. Ensure enough memory and storage space are available, and attempt
61 + to free memory/storage if necessary.
62 + c. Allocate the required memory and storage space.
66 + There are a number of complicating factors which mean that things are
67 + not as simple as the above would imply, however...
69 + o The activity of each process must be stopped at a point where it will
70 + not be holding locks necessary for saving the image, or unexpectedly
71 + restart operations due to something like a timeout and thereby make
72 + our image inconsistent.
74 + o It is desirous that we sync outstanding I/O to disk before calculating
75 + image statistics. This reduces corruption if one should suspend but
76 + then not resume, and also makes later parts of the operation safer (see
79 + o We need to get as close as we can to an atomic copy of the data.
80 + Inconsistencies in the image will result in inconsistent memory contents at
81 + resume time, and thus in instability of the system and/or file system
82 + corruption. This would appear to imply a maximum image size of one half of
83 + the amount of RAM, but we have a solution... (again, below).
85 + o In 2.6, we choose to play nicely with the other suspend-to-disk
88 +3. Detailed description of internals.
90 + a. Quiescing activity.
92 + Safely quiescing the system is achieved using two methods.
94 + First, we note that the vast majority of processes don't need to run during
95 + suspend. They can be 'frozen'. We therefore implement a refrigerator
96 + routine, which processes enter and in which they remain until the cycle is
97 + complete. Processes enter the refrigerator via try_to_freeze() invocations
98 + at appropriate places. A process cannot be frozen in any old place. It
99 + must not be holding locks that will be needed for writing the image or
100 + freezing other processes. For this reason, userspace processes generally
101 + enter the refrigerator via the signal handling code, and kernel threads at
102 + the place in their event loops where they drop locks and yield to other
103 + processes or sleep.
105 + The second part of our method for quisescing the system involves freezing
106 + the filesystems. We use the standard freeze_bdev and thaw_bdev functions to
107 + ensure that all of the user's data is synced to disk before we begin to
108 + write the image. This is particularly important with XFS, where without
109 + bdev freezing, activity may still occur after we begin to write the image
110 + (potentially causing in-memory and on-disk corruption later).
112 + Quiescing the system works most quickly and reliably when we add one more
113 + element to the algorithm: separating the freezing of userspace processes
114 + from the freezing of kernel space processes, and doing the filesystem freeze
115 + in between. The filesystem freeze needs to be done while kernel threads such
116 + as kjournald can still run. At the same time, though, everything will be
117 + less racy and run more quickly if we stop userspace submitting more I/O work
118 + while we're trying to quiesce.
120 + Quiescing the system is therefore done in three steps:
122 + - Freeze filesystems
123 + - Freeze kernel threads
125 + If we need to free memory, we thaw kernel threads and filesystems, but not
126 + userspace. We can then free caches without worrying about deadlocks due to
127 + swap files being on frozen filesystems or such like.
129 + One limitation of this is that FUSE filesystems are incompatible with
130 + suspending to disk. They need to be unmounted prior to suspending, to avoid
131 + potential deadlocks.
133 + b. Ensure enough memory & storage are available.
135 + We have a number of constraints to meet in order to be able to successfully
136 + suspend and resume.
138 + First, the image will be written in two parts, described below. One of these
139 + parts needs to have an atomic copy made, which of course implies a maximum
140 + size of one half of the amount of system memory. The other part ('pageset')
141 + is not atomically copied, and can therefore be as large or small as desired.
143 + Second, we have constraints on the amount of storage available. In these
144 + calculations, we may also consider any compression that will be done. The
145 + cryptoapi module allows the user to configure an expected compression ratio.
147 + Third, the user can specify an arbitrary limit on the image size, in
148 + megabytes. This limit is treated as a soft limit, so that we don't fail the
149 + attempt to suspend if we cannot meet this constraint.
151 + c. Allocate the required memory and storage space.
153 + Having done the initial freeze, we determine whether the above constraints
154 + are met, and seek to allocate the metadata for the image. If the constraints
155 + are not met, or we fail to allocate the required space for the metadata, we
156 + seek to free the amount of memory that we calculate is needed and try again.
157 + We allow up to four iterations of this loop before aborting the cycle. If we
158 + do fail, it should only be because of a bug in Suspend's calculations.
160 + These steps are merged together in the prepare_image function, found in
161 + prepare_image.c. The functions are merged because of the cyclical nature
162 + of the problem of calculating how much memory and storage is needed. Since
163 + the data structures containing the information about the image must
164 + themselves take memory and use storage, the amount of memory and storage
165 + required changes as we prepare the image. Since the changes are not large,
166 + only one or two iterations will be required to achieve a solution.
168 + The recursive nature of the algorithm is miminised by keeping user space
169 + frozen while preparing the image, and by the fact that our records of which
170 + pages are to be saved and which pageset they are saved in use bitmaps (so
171 + that changes in number or fragmentation of the pages to be saved don't
172 + feedback via changes in the amount of memory needed for metadata). The
173 + recursiveness is thus limited to any extra slab pages allocated to store the
174 + extents that record storage used, and he effects of seeking to free memory.
176 + d. Write the image.
178 + We previously mentioned the need to create an atomic copy of the data, and
179 + the half-of-memory limitation that is implied in this. This limitation is
180 + circumvented by dividing the memory to be saved into two parts, called
183 + Pageset2 contains the page cache - the pages on the active and inactive
184 + lists. These pages aren't needed or modifed while Suspend2 is running, so
185 + they can be safely written without an atomic copy. They are therefore
186 + saved first and reloaded last. While saving these pages, Suspend2 carefully
187 + ensures that the work of writing the pages doesn't make the image
190 + Once pageset2 has been saved, we prepare to do the atomic copy of remaining
191 + memory. As part of the preparation, we power down drivers, thereby providing
192 + them with the opportunity to have their state recorded in the image. The
193 + amount of memory allocated by drivers for this is usually negligible, but if
194 + DRI is in use, video drivers may require significants amounts. Ideally we
195 + would be able to query drivers while preparing the image as to the amount of
196 + memory they will need. Unfortunately no such mechanism exists at the time of
197 + writing. For this reason, Suspend2 allows the user to set an
198 + 'extra_pages_allowance', which is used to seek to ensure sufficient memory
199 + is available for drivers at this point. Suspend2 also lets the user set this
200 + value to 0. In this case, a test driver suspend is done while preparing the
201 + image, and the difference (plus a margin) used instead.
203 + Having suspended the drivers, we save the CPU context before making an
204 + atomic copy of pageset1, resuming the drivers and saving the atomic copy.
205 + After saving the two pagesets, we just need to save our metadata before
208 + As we mentioned earlier, the contents of pageset2 pages aren't needed once
209 + they've been saved. We therefore use them as the destination of our atomic
210 + copy. In the unlikely event that pageset1 is larger, extra pages are
211 + allocated while the image is being prepared. This is normally only a real
212 + possibility when the system has just been booted and the page cache is
215 + This is where we need to be careful about syncing, however. Pageset2 will
216 + probably contain filesystem meta data. If this is overwritten with pageset1
217 + and then a sync occurs, the filesystem will be corrupted - at least until
218 + resume time and another sync of the restored data. Since there is a
219 + possibility that the user might not resume or (may it never be!) that
220 + suspend might oops, we do our utmost to avoid syncing filesystems after
225 + Powering down uses standard kernel routines. Suspend2 supports powering down
226 + using the ACPI S3, S4 and S5 methods or the kernel's non-ACPI power-off.
227 + Supporting suspend to ram (S3) as a power off option might sound strange,
228 + but it allows the user to quickly get their system up and running again if
229 + the battery doesn't run out (we just need to re-read the overwritten pages)
230 + and if the battery does run out (or the user removes power), they can still
235 + Suspend2 uses three main structures to store its metadata and configuration
238 + a) Pageflags bitmaps.
240 + Suspend records which pages will be in pageset1, pageset2, the destination
241 + of the atomic copy and the source of the atomically restored image using
242 + bitmaps. These bitmaps are created from order zero allocations to maximise
243 + reliability. The individual pages are combined together with pointers to
244 + form per-zone bitmaps, which are in turn combined with another layer of
245 + pointers to construct the overall bitmap.
247 + The pageset1 bitmap is thus easily stored in the image header for use at
250 + As mentioned above, using bitmaps also means that the amount of memory and
251 + storage required for recording the above information is constant. This
252 + greatly simplifies the work of preparing the image. In earlier versions of
253 + Suspend2, extents were used to record which pages would be stored. In that
254 + case, however, eating memory could result in greater fragmentation of the
255 + lists of pages, which in turn required more memory to store the extents and
256 + more storage in the image header. These could in turn require further
257 + freeing of memory, and another iteration. All of this complexity is removed
260 + Bitmaps also make a lot of sense because Suspend2 only ever iterates
261 + through the lists. There is therefore no cost to not being able to find the
262 + nth page in order 0 time. We only need to worry about the cost of finding
263 + the n+1th page, given the location of the nth page. Bitwise optimisations
266 + The data structure is: unsigned long ***.
268 + b) Extents for block data.
270 + Suspend2 supports writing the image to multiple block devices. In the case
271 + of swap, multiple partitions and/or files may be in use, and we happily use
272 + them all. This is accomplished as follows:
274 + Whatever the actual source of the allocated storage, the destination of the
275 + image can be viewed in terms of one or more block devices, and on each
276 + device, a list of sectors. To simplify matters, we only use contiguous,
277 + PAGE_SIZE aligned sectors, like the swap code does.
279 + Since sector numbers on each bdev may well not start at 0, it makes much
280 + more sense to use extents here. Contiguous ranges of pages can thus be
281 + represented in the extents by contiguous values.
283 + Variations in block size are taken account of in transforming this data
284 + into the parameters for bio submission.
286 + We can thus implement a layer of abstraction wherein the core of Suspend2
287 + doesn't have to worry about which device we're currently writing to or
288 + where in the device we are. It simply requests that the next page in the
289 + pageset or header be written, leaving the details to this lower layer.
290 + The lower layer remembers where in the sequence of devices and blocks each
291 + pageset starts. The header always starts at the beginning of the allocated
297 + unsigned long minimum, maximum;
298 + struct extent *next;
301 + These are combined into chains of extents for a device:
303 + struct extent_chain {
304 + int size; /* size of the extent ie sum (max-min+1) */
307 + struct extent *first, *last_touched;
310 + For each bdev, we need to store a little more info:
312 + struct suspend_bdev_info {
313 + struct block_device *bdev;
316 + int blocks_per_page;
319 + The dev_t is used to identify the device in the stored image. As a result,
320 + we expect devices at resume time to have the same major and minor numbers
321 + as they had while suspending. This is primarily a concern where the user
322 + utilises LVM for storage, as they will need to dmsetup their partitions in
323 + such a way as to maintain this consistency at resume time.
325 + bmap_shift and blocks_per_page record apply the effects of variations in
326 + blocks per page settings for the filesystem and underlying bdev. For most
327 + filesystems, these are the same, but for xfs, they can have independant
330 + Combining these two structures together, we have everything we need to
331 + record what devices and what blocks on each device are being used to
332 + store the image, and to submit i/o using bio_submit.
334 + The last elements in the picture are a means of recording how the storage
337 + We do this first and foremost by implementing a layer of abstraction on
338 + top of the devices and extent chains which allows us to view however many
339 + devices there might be as one long storage tape, with a single 'head' that
340 + tracks a 'current position' on the tape:
342 + struct extent_iterate_state {
343 + struct extent_chain *chains;
346 + struct extent *current_extent;
347 + unsigned long current_offset;
350 + That is, *chains points to an array of size num_chains of extent chains.
351 + For the filewriter, this is always a single chain. For the swapwriter, the
352 + array is of size MAX_SWAPFILES.
354 + current_chain, current_extent and current_offset thus point to the current
355 + index in the chains array (and into a matching array of struct
356 + suspend_bdev_info), the current extent in that chain (to optimise access),
357 + and the current value in the offset.
359 + The image is divided into three parts:
364 + The header always starts at the first device and first block. We know its
365 + size before we begin to save the image because we carefully account for
366 + everything that will be stored in it.
368 + The second pageset (LRU) is stored first. It begins on the next page after
369 + the end of the header.
371 + The first pageset is stored second. It's start location is only known once
372 + pageset2 has been saved, since pageset2 may be compressed as it is written.
373 + This location is thus recorded at the end of saving pageset2. It is page
376 + Since this information is needed at resume time, and the location of extents
377 + in memory will differ at resume time, this needs to be stored in a portable
380 + struct extent_iterate_saved_state {
383 + unsigned long offset;
386 + We can thus implement a layer of abstraction wherein the core of Suspend2
387 + doesn't have to worry about which device we're currently writing to or
388 + where in the device we are. It simply requests that the next page in the
389 + pageset or header be written, leaving the details to this layer, and
390 + invokes the routines to remember and restore the position, without having
391 + to worry about the details of how the data is arranged on disk or such like.
395 + One aim in designing Suspend2 was to make it flexible. We wanted to allow
396 + for the implementation of different methods of transforming a page to be
397 + written to disk and different methods of getting the pages stored.
399 + In early versions (the betas and perhaps Suspend1), compression support was
400 + inlined in the image writing code, and the data structures and code for
401 + managing swap were intertwined with the rest of the code. A number of people
402 + had expressed interest in implementing image encryption, and alternative
403 + methods of storing the image.
405 + In order to achieve this, Suspend2 was given a modular design.
407 + A module is a single file which encapsulates the functionality needed
408 + to transform a pageset of data (encryption or compression, for example),
409 + or to write the pageset to a device. The former type of module is called
410 + a 'page-transformer', the later a 'writer'.
412 + Modules are linked together in pipeline fashion. There may be zero or more
413 + page transformers in a pipeline, and there is always exactly one writer.
414 + The pipeline follows this pattern:
416 + ---------------------------------
418 + ---------------------------------
421 + ---------------------------------
422 + | Page transformer 1 |
423 + ---------------------------------
426 + ---------------------------------
427 + | Page transformer 2 |
428 + ---------------------------------
431 + ---------------------------------
433 + ---------------------------------
435 + During the writing of an image, the core code feeds pages one at a time
436 + to the first module. This module performs whatever transformations it
437 + implements on the incoming data, completely consuming the incoming data and
438 + feeding output in a similar manner to the next module. A module may buffer
441 + During reading, the pipeline works in the reverse direction. The core code
442 + calls the first module with the address of a buffer which should be filled.
443 + (Note that the buffer size is always PAGE_SIZE at this time). This module
444 + will in turn request data from the next module and so on down until the
445 + writer is made to read from the stored image.
447 + Part of definition of the structure of a module thus looks like this:
449 + int (*rw_init) (int rw, int stream_number);
450 + int (*rw_cleanup) (int rw);
451 + int (*write_chunk) (struct page *buffer_page);
452 + int (*read_chunk) (struct page *buffer_page, int sync);
454 + It should be noted that the _cleanup routine may be called before the
455 + full stream of data has been read or written. While writing the image,
456 + the user may (depending upon settings) choose to abort suspending, and
457 + if we are in the midst of writing the last portion of the image, a portion
458 + of the second pageset may be reread. This may also happen if an error
459 + occurs and we seek to abort the process of writing the image.
461 + The modular design is also useful in a number of other ways. It provides
462 + a means where by we can add support for:
464 + - providing overall initialisation and cleanup routines;
465 + - serialising configuration information in the image header;
466 + - providing debugging information to the user;
467 + - determining memory and image storage requirements;
468 + - dis/enabling components at run-time;
469 + - configuring the module (see below);
471 + ...and routines for writers specific to their work:
472 + - Parsing a resume2= location;
473 + - Determining whether an image exists;
474 + - Marking a resume as having been attempted;
475 + - Invalidating an image;
477 + Since some parts of the core - the user interface and storage manager
478 + support - have use for some of these functions, they are registered as
479 + 'miscellaneous' modules as well.
481 + d) Sysfs data structures.
483 + This brings us naturally to support for configuring Suspend2. We desired to
484 + provide a way to make Suspend2 as flexible and configurable as possible.
485 + The user shouldn't have to reboot just because they want to now suspend to
486 + a file instead of a partition, for example.
488 + To accomplish this, Suspend2 implements a very generic means whereby the
489 + core and modules can register new sysfs entries. All Suspend2 entries use
490 + a single _store and _show routine, both of which are found in sysfs.c in
491 + the kernel/power directory. These routines handle the most common operations
492 + - getting and setting the values of bits, integers, longs, unsigned longs
493 + and strings in one place, and allow overrides for customised get and set
494 + options as well as side-effect routines for all reads and writes.
496 + When combined with some simple macros, a new sysfs entry can then be defined
497 + in just a couple of lines:
499 + { SUSPEND2_ATTR("progress_granularity", SYSFS_RW),
500 + SYSFS_INT(&progress_granularity, 1, 2048)
503 + This defines a sysfs entry named "progress_granularity" which is rw and
504 + allows the user to access an integer stored at &progress_granularity, giving
505 + it a value between 1 and 2048 inclusive.
507 + Sysfs entries are registered under /sys/power/suspend2, and entries for
508 + modules are located in a subdirectory named after the module.
510 diff -ruN linux-2.6.22/Documentation/power/suspend2.txt suspend2-2.2.10-for-2.6.22/Documentation/power/suspend2.txt
511 --- linux-2.6.22/Documentation/power/suspend2.txt 1970-01-01 10:00:00.000000000 +1000
512 +++ suspend2-2.2.10-for-2.6.22/Documentation/power/suspend2.txt 2007-07-11 22:25:42.000000000 +1000
514 + --- Suspend2, version 2.2 ---
517 +2. Why would you want it?
518 +3. What do you need to use it?
519 +4. Why not just use the version already in the kernel?
520 +5. How do you use it?
521 +6. What do all those entries in /sys/power/suspend2 do?
522 +7. How do you get support?
523 +8. I think I've found a bug. What should I do?
524 +9. When will XXX be supported?
525 +10 How does it work?
526 +11. Who wrote Suspend2?
530 + Imagine you're sitting at your computer, working away. For some reason, you
531 + need to turn off your computer for a while - perhaps it's time to go home
532 + for the day. When you come back to your computer next, you're going to want
533 + to carry on where you left off. Now imagine that you could push a button and
534 + have your computer store the contents of its memory to disk and power down.
535 + Then, when you next start up your computer, it loads that image back into
536 + memory and you can carry on from where you were, just as if you'd never
537 + turned the computer off. Far less time to start up, no reopening
538 + applications and finding what directory you put that file in yesterday.
539 + That's what Suspend2 does.
541 + Suspend2 has a long heritage. It began life as work by Gabor Kuti, who,
542 + with some help from Pavel Machek, got an early version going in 1999. The
543 + project was then taken over by Florent Chabaud while still in alpha version
544 + numbers. Nigel Cunningham came on the scene when Florent was unable to
545 + continue, moving the project into betas, then 1.0, 2.0 and so on up to
546 + the present 2.2 series. Pavel Machek's swsusp code, which was merged around
547 + 2.5.17 retains the original name, and was essentially a fork of the beta
548 + code until Rafael Wysocki came on the scene in 2005 and began to improve it
551 +2. Why would you want it?
553 + Why wouldn't you want it?
555 + Being able to save the state of your system and quickly restore it improves
556 + your productivity - you get a useful system in far less time than through
557 + the normal boot process.
559 +3. What do you need to use it?
563 + i) The Suspend2 patch.
565 + Suspend2 is part of the Linux Kernel. This version is not part of Linus's
566 + 2.6 tree at the moment, so you will need to download the kernel source and
567 + apply the latest patch. Having done that, enable the appropriate options in
568 + make [menu|x]config (under Power Management Options), compile and install your
569 + kernel. Suspend2 works with SMP, Highmem, preemption, x86-32, PPC and x86_64.
571 + Suspend2 patches are available from http://suspend2.net.
573 + ii) Compression and encryption support.
575 + Compression and encryption support are implemented via the
576 + cryptoapi. You will therefore want to select any Cryptoapi transforms that
577 + you want to use on your image from the Cryptoapi menu while configuring
580 + You can also tell Suspend to write it's image to an encrypted and/or
581 + compressed filesystem/swap partition. In that case, you don't need to do
582 + anything special for Suspend2 when it comes to kernel configuration.
584 + iii) Configuring other options.
586 + While you're configuring your kernel, try to configure as much as possible
587 + to build as modules. We recommend this because there are a number of drivers
588 + that are still in the process of implementing proper power management
589 + support. In those cases, the best way to work around their current lack is
590 + to build them as modules and remove the modules while suspending. You might
591 + also bug the driver authors to get their support up to speed, or even help!
597 + Suspend2 can store the suspend image in your swap partition, a swap file or
598 + a combination thereof. Whichever combination you choose, you will probably
599 + want to create enough swap space to store the largest image you could have,
600 + plus the space you'd normally use for swap. A good rule of thumb would be
601 + to calculate the amount of swap you'd want without using Suspend2, and then
602 + add the amount of memory you have. This swapspace can be arranged in any way
603 + you'd like. It can be in one partition or file, or spread over a number. The
604 + only requirement is that they be active when you start a suspend cycle.
606 + There is one exception to this requirement. Suspend2 has the ability to turn
607 + on one swap file or partition at the start of suspending and turn it back off
608 + at the end. If you want to ensure you have enough memory to store a image
609 + when your memory is fully used, you might want to make one swap partition or
610 + file for 'normal' use, and another for Suspend2 to activate & deactivate
611 + automatically. (Further details below).
615 + Suspend2 includes a 'filewriter'. The filewriter can store your image in a
616 + simple file. Since Linux has the idea of everything being a file, this is
617 + more powerful than it initially sounds. If, for example, you were to set up
618 + a network block device file, you could suspend to a network server. This has
619 + been tested and works to a point, but nbd itself isn't stateless enough for
622 + Take extra care when setting up the filewriter. If you just type commands
623 + without thinking and then try to suspend, you could cause irreversible
624 + corruption on your filesystems! Make sure you have backups.
626 + Most people will only want to suspend to a local file. To achieve that, do
627 + something along the lines of:
629 + echo "Suspend2" > /suspend-file
630 + dd if=/dev/zero bs=1M count=512 >> suspend-file
632 + This will create a 512MB file called /suspend-file. To get Suspend2 to use
635 + echo /suspend-file > /sys/power/suspend2/filewriter/filewriter_target
639 + cat /sys/power/suspend2/resume2
641 + Put the results of this into your bootloader's configuration (see also step
644 + ---EXAMPLE-ONLY-DON'T-COPY-AND-PASTE---
645 + # cat /sys/power/suspend2/resume2
646 + file:/dev/hda2:0x1e001
648 + In this example, we would edit the append= line of our lilo.conf|menu.lst
649 + so that it included:
651 + resume2=file:/dev/hda2:0x1e001
652 + ---EXAMPLE-ONLY-DON'T-COPY-AND-PASTE---
654 + For those who are thinking 'Could I make the file sparse?', the answer is
655 + 'No!'. At the moment, there is no way for Suspend2 to fill in the holes in
656 + a sparse file while suspending. In the longer term (post merge!), I'd like
657 + to change things so that the file could be dynamically resized as needed.
658 + Right now, however, that's not possible and not a priority.
660 + c. Bootloader configuration.
662 + Using Suspend2 also requires that you add an extra parameter to
663 + your lilo.conf or equivalent. Here's an example for a swap partition:
665 + append="resume2=swap:/dev/hda1"
667 + This would tell Suspend2 that /dev/hda1 is a swap partition you
668 + have. Suspend2 will use the swap signature of this partition as a
669 + pointer to your data when you suspend. This means that (in this example)
670 + /dev/hda1 doesn't need to be _the_ swap partition where all of your data
671 + is actually stored. It just needs to be a swap partition that has a
674 + You don't need to have a swap partition for this purpose. Suspend2
675 + can also use a swap file, but usage is a little more complex. Having made
676 + your swap file, turn it on and do
678 + cat /sys/power/suspend2/swapwriter/headerlocations
680 + (this assumes you've already compiled your kernel with Suspend2
681 + support and booted it). The results of the cat command will tell you
682 + what you need to put in lilo.conf:
684 + For swap partitions like /dev/hda1, simply use resume2=/dev/hda1.
685 + For swapfile `swapfile`, use resume2=swap:/dev/hda2:0x242d.
687 + If the swapfile changes for any reason (it is moved to a different
688 + location, it is deleted and recreated, or the filesystem is
689 + defragmented) then you will have to check
690 + /sys/power/suspend2/swapwriter/headerlocations for a new resume_block value.
692 + Once you've compiled and installed the kernel and adjusted your bootloader
693 + configuration, you should only need to reboot for the most basic part
694 + of Suspend2 to be ready.
696 + If you only compile in the swapwriter, or only compile in the filewriter,
697 + you don't need to add the "swap:" part of the resume2= parameters above.
698 + resume2=/dev/hda2:0x242d will work just as well.
700 + d. The hibernate script.
702 + Since the driver model in 2.6 kernels is still being developed, you may need
703 + to do more, however. Users of Suspend2 usually start the process via a script
704 + which prepares for the suspend, tells the kernel to do its stuff and then
705 + restore things afterwards. This script might involve:
707 + - Switching to a text console and back if X doesn't like the video card
709 + - Un/reloading PCMCIA support since it doesn't play well with suspend.
711 + Note that you might not be able to unload some drivers if there are
712 + processes using them. You might have to kill off processes that hold
713 + devices open. Hint: if your X server accesses an USB mouse, doing a
714 + 'chvt' to a text console releases the device and you can unload the
717 + Check out the latest script (available on suspend2.net).
719 +4. Why not just use the version already in the kernel?
721 + The version in the vanilla kernel has a number of drawbacks. Among these:
722 + - it has a maximum image size of 1/2 total memory.
723 + - it doesn't allocate storage until after it has snapshotted memory.
724 + This means that you can't be sure suspending will work until you
725 + see it start to write the image.
726 + - it performs all of it's I/O synchronously.
727 + - it does not allow you to press escape to cancel a cycle
728 + - it does not allow you to automatically swapon a file when
730 + - it does not allow you to use multiple swap partitions.
731 + - it does not allow you to use swapfiles.
732 + - it does not allow you to use ordinary files.
733 + - it just invalidates an image and continues to boot if you
734 + accidentally boot the wrong kernel after suspending.
735 + - it doesn't support any sort of nice display while suspending
736 + - it is moving toward requiring that you have an initrd/initramfs
737 + to ever have a hope of resuming (uswsusp). While uswsusp will
738 + address some of the concerns above, it won't address all, and
739 + will be more complicated to get set up.
741 +5. How do you use it?
743 + A suspend cycle can be started directly by doing:
745 + echo > /sys/power/suspend2/do_resume
747 + In practice, though, you'll probably want to use the hibernate script
748 + to unload modules, configure the kernel the way you like it and so on.
749 + In that case, you'd do (as root):
753 + See the hibernate script's man page for more details on the options it
756 + If you're using the text or splash user interface modules, one neat feature
757 + of Suspend2 that you might find useful is that you can press Escape at any
758 + time during suspending, and the process will be aborted.
760 + Due to the way suspend works, this means you'll have your system back and
761 + perfectly usable almost instantly. The only exception is when it's at the
762 + very end of writing the image. Then it will need to reload a small (
763 + usually 4-50MBs, depending upon the image characteristics) portion first.
765 + If you run into problems with resuming, adding the "noresume2" option to
766 + the kernel command line will let you skip the resume step and recover your
769 +6. What do all those entries in /sys/power/suspend2 do?
771 + /sys/power/suspend2 is the directory which contains files you can use to
772 + tune and configure Suspend2 to your liking. The exact contents of
773 + the directory will depend upon the version of Suspend2 you're
774 + running and the options you selected at compile time. In the following
775 + descriptions, names in brackets refer to compile time options.
776 + (Note that they're all dependant upon you having selected CONFIG_SUSPEND2
777 + in the first place!).
779 + Since the values of these settings can open potential security risks, they
780 + are usually accessible only to the root user. You can, however, enable a
781 + compile time option which makes all of these files world-accessible. This
782 + should only be done if you trust everyone with shell access to this
787 + Use cryptoapi hashing routines to verify that Pageset2 pages don't change
788 + while we're saving the first part of the image, and to get any pages that
789 + do change resaved in the atomic copy. This should normally not be needed,
790 + but if you're seeing issues, please enable this. If your issues stop you
791 + being able to resume, enable this option, suspend and cancel the cycle
792 + after the atomic copy is done. If the debugging info shows a non-zero
793 + number of pages resaved, please report this to Nigel.
795 + - compression/algorithm
797 + Set the cryptoapi algorithm used for compressing the image.
799 + - compression/expected_compression
801 + These values allow you to set an expected compression ratio, which Software
802 + Suspend will use in calculating whether it meets constraints on the image
803 + size. If this expected compression ratio is not attained, the suspend will
804 + abort, so it is wise to allow some spare. You can see what compression
805 + ratio is achieved in the logs after suspending.
809 + This file returns information about your configuration that may be helpful
810 + in diagnosing problems with suspending.
814 + When anything is written to this file suspend will attempt to read and
815 + restore an image. If there is no image, it will return almost immediately.
816 + If an image exists, the echo > will never return. Instead, the original
817 + kernel context will be restored and the original echo > do_suspend will
822 + When anything is written to this file, the kernel side of Suspend2 will
823 + begin to attempt to write an image to disk and power down. You'll normally
824 + want to run the hibernate script instead, to get modules unloaded first.
826 + - driver_model_beeping
828 + Enable beeping when suspending and resuming the drivers. Might help with
829 + determining where a problem in resuming occurs.
833 + These option can be used to temporarily disable various parts of suspend.
837 + The iv, key, save_key_and_iv, mode and algorithm values allow you to
838 + select a cryptoapi encryption algoritm, set the iv and key and whether
839 + they are saved in the image header. Saving the iv and key in the image
840 + header is of course less secure than having them on some external device,
841 + such as a USB key. If you want to use a USB key, you'll need to write
842 + some scripting in your initrd/ramfs to retrieve the key & iv from your
843 + USB key and put them into the entries again prior to doing the echo to
846 + - extra_pages_allowance
848 + When Suspend2 does its atomic copy, it calls the driver model suspend
849 + and resume methods. If you have DRI enabled with a driver such as fglrx,
850 + this can result in the driver allocating a substantial amount of memory
851 + for storing its state. Extra_pages_allowance tells suspend2 how much
852 + extra memory it should ensure is available for those allocations. If
853 + your attempts at suspending end with a message in dmesg indicating that
854 + insufficient extra pages were allowed, you need to increase this value.
856 + - filewriter/target:
858 + Read this value to get the current setting. Write to it to point Suspend
859 + at a new storage location for the filewriter. See above for details of how
860 + to set up the filewriter.
864 + This entry can be used to get Suspend2 to just test the freezer without
865 + actually doing a suspend cycle. It is useful for diagnosing freezing
870 + Can be used in a script to determine whether a valid image exists at the
871 + location currently pointed to by resume2=. Returns up to three lines.
872 + The first is whether an image exists (-1 for unsure, otherwise 0 or 1).
873 + If an image eixsts, additional lines will return the machine and version.
874 + Echoing anything to this entry removes any current image.
876 + - image_size_limit:
878 + The maximum size of suspend image written to disk, measured in megabytes
881 + - interface_version:
883 + The value returned by this file can be used by scripts and configuration
884 + tools to determine what entries should be looked for. The value is
885 + incremented whenever an entry in /sys/power/suspend2 is obsoleted or
890 + The result of the last suspend, as defined in
891 + include/linux/suspend-debug.h with the values SUSPEND_ABORTED to
892 + SUSPEND_KEPT_IMAGE. This is a bitmask.
894 + - log_everything (CONFIG_PM_DEBUG):
896 + Setting this option results in all messages printed being logged. Normally,
897 + only a subset are logged, so as to not slow the process and not clutter the
898 + logs. Useful for debugging. It can be toggled during a cycle by pressing
901 + - pause_between_steps (CONFIG_PM_DEBUG):
903 + This option is used during debugging, to make Suspend2 pause between
904 + each step of the process. It is ignored when the nice display is on.
906 + - powerdown_method:
908 + Used to select a method by which Suspend2 should powerdown after writing the
911 + 0: Don't use ACPI to power off.
912 + 3: Attempt to enter Suspend-to-ram.
913 + 4: Attempt to enter ACPI S4 mode.
914 + 5: Attempt to power down via ACPI S5 mode.
916 + Note that these options are highly dependant upon your hardware & software:
918 + 3: When succesful, your machine suspends-to-ram instead of powering off.
919 + The advantage of using this mode is that it doesn't matter whether your
920 + battery has enough charge to make it through to your next resume. If it
921 + lasts, you will simply resume from suspend to ram (and the image on disk
922 + will be discarded). If the battery runs out, you will resume from disk
923 + instead. The disadvantage is that it takes longer than a normal
924 + suspend-to-ram to enter the state, since the suspend-to-disk image needs
925 + to be written first.
926 + 4/5: When successful, your machine will be off and comsume (almost) no power.
927 + But it might still react to some external events like opening the lid or
928 + trafic on a network or usb device. For the bios, resume is then the same
929 + as warm boot, similar to a situation where you used the command `reboot'
930 + to reboot your machine. If your machine has problems on warm boot or if
931 + you want to protect your machine with the bios password, this is probably
932 + not the right choice. Mode 4 may be necessary on some machines where ACPI
933 + wake up methods need to be run to properly reinitialise hardware after a
934 + suspend-to-disk cycle.
935 + 0: Switch the machine completely off. The only possible wakeup is the power
936 + button. For the bios, resume is then the same as a cold boot, in
937 + particular you would have to provide your bios boot password if your
938 + machine uses that feature for booting.
940 + - progressbar_granularity_limit:
942 + This option can be used to limit the granularity of the progress bar
943 + displayed with a bootsplash screen. The value is the maximum number of
944 + steps. That is, 10 will make the progress bar jump in 10% increments.
948 + This option causes Suspend2 to reboot rather than powering down
949 + at the end of saving an image. It can be toggled during a cycle by pressing
952 + - resume_commandline:
954 + This entry can be read after resuming to see the commandline that was used
955 + when resuming began. You might use this to set up two bootloader entries
956 + that are the same apart from the fact that one includes a extra append=
957 + argument "at_work=1". You could then grep resume_commandline in your
958 + post-resume scripts and configure networking (for example) differently
959 + depending upon whether you're at home or work. resume_commandline can be
960 + set to arbitrary text if you wish to remove sensitive contents.
962 + - swapwriter/swapfilename:
964 + This entry is used to specify the swapfile or partition that
965 + Suspend2 will attempt to swapon/swapoff automatically. Thus, if
966 + I normally use /dev/hda1 for swap, and want to use /dev/hda2 for specifically
967 + for my suspend image, I would
969 + echo /dev/hda2 > /sys/power/suspend2/swapwriter/swapfile
971 + /dev/hda2 would then be automatically swapon'd and swapoff'd. Note that the
972 + swapon and swapoff occur while other processes are frozen (including kswapd)
973 + so this swap file will not be used up when attempting to free memory. The
974 + parition/file is also given the highest priority, so other swapfiles/partitions
975 + will only be used to save the image when this one is filled.
977 + The value of this file is used by headerlocations along with any currently
978 + activated swapfiles/partitions.
980 + - swapwriter/headerlocations:
982 + This option tells you the resume2= options to use for swap devices you
983 + currently have activated. It is particularly useful when you only want to
984 + use a swap file to store your image. See above for further details.
986 + - toggle_process_nofreeze
988 + This entry can be used to toggle the NOFREEZE flag on a process, to allow it
989 + to run during Suspending. It should be used with extreme caution. There are
990 + strict limitations on what a process running during suspend can do. This is
991 + really only intended for use by Suspend's helpers (userui in particular).
995 + This entry is used to tell Suspend what userspace program to use for
996 + providing a user interface while suspending. The program uses a netlink
997 + socket to pass messages back and forward to the kernel, allowing all of the
998 + functions formerly implemented in the kernel user interface components.
1000 + - user_interface/debug_sections (CONFIG_PM_DEBUG):
1002 + This value, together with the console log level, controls what debugging
1003 + information is displayed. The console log level determines the level of
1004 + detail, and this value determines what detail is displayed. This value is
1005 + a bit vector, and the meaning of the bits can be found in the kernel tree
1006 + in include/linux/suspend2.h. It can be overridden using the kernel's
1007 + command line option suspend_dbg.
1009 + - user_interface/default_console_level (CONFIG_PM_DEBUG):
1011 + This determines the value of the console log level at the start of a
1012 + suspend cycle. If debugging is compiled in, the console log level can be
1013 + changed during a cycle by pressing the digit keys. Meanings are:
1016 + 1: Nice display plus numerical progress.
1018 + 3: Low level debugging info.
1019 + 4: Medium level debugging info.
1020 + 5: High level debugging info.
1021 + 6: Verbose debugging info.
1023 + - user_interface/enable_escape:
1025 + Setting this to "1" will enable you abort a suspend by
1026 + pressing escape, "0" (default) disables this feature. Note that enabling
1027 + this option means that you cannot initiate a suspend and then walk away
1028 + from your computer, expecting it to be secure. With feature disabled,
1029 + you can validly have this expectation once Suspend begins to write the
1030 + image to disk. (Prior to this point, it is possible that Suspend might
1031 + about because of failure to freeze all processes or because constraints
1032 + on its ability to save the image are not met).
1036 + The version of suspend you have compiled into the currently running kernel.
1038 +7. How do you get support?
1040 + Glad you asked. Suspend2 is being actively maintained and supported
1041 + by Nigel (the guy doing most of the kernel coding at the moment), Bernard
1042 + (who maintains the hibernate script and userspace user interface components)
1045 + Resources availble include HowTos, FAQs and a Wiki, all available via
1046 + suspend2.net. You can find the mailing lists there.
1048 +8. I think I've found a bug. What should I do?
1050 + By far and a way, the most common problems people have with suspend2
1051 + related to drivers not having adequate power management support. In this
1052 + case, it is not a bug with suspend2, but we can still help you. As we
1053 + mentioned above, such issues can usually be worked around by building the
1054 + functionality as modules and unloading them while suspending. Please visit
1055 + the Wiki for up-to-date lists of known issues and work arounds.
1057 + If this information doesn't help, try running:
1059 + hibernate --bug-report
1061 + ..and sending the output to the users mailing list.
1063 + Good information on how to provide us with useful information from an
1064 + oops is found in the file REPORTING-BUGS, in the top level directory
1065 + of the kernel tree. If you get an oops, please especially note the
1066 + information about running what is printed on the screen through ksymoops.
1067 + The raw information is useless.
1069 +9. When will XXX be supported?
1071 + If there's a feature missing from Suspend2 that you'd like, feel free to
1072 + ask. We try to be obliging, within reason.
1074 + Patches are welcome. Please send to the list.
1076 +10. How does it work?
1078 + Suspend2 does its work in a number of steps.
1080 + a. Freezing system activity.
1082 + The first main stage in suspending is to stop all other activity. This is
1083 + achieved in stages. Processes are considered in fours groups, which we will
1084 + describe in reverse order for clarity's sake: Threads with the PF_NOFREEZE
1085 + flag, kernel threads without this flag, userspace processes with the
1086 + PF_SYNCTHREAD flag and all other processes. The first set (PF_NOFREEZE) are
1087 + untouched by the refrigerator code. They are allowed to run during suspending
1088 + and resuming, and are used to support user interaction, storage access or the
1089 + like. Other kernel threads (those unneeded while suspending) are frozen last.
1090 + This leaves us with userspace processes that need to be frozen. When a
1091 + process enters one of the *_sync system calls, we set a PF_SYNCTHREAD flag on
1092 + that process for the duration of that call. Processes that have this flag are
1093 + frozen after processes without it, so that we can seek to ensure that dirty
1094 + data is synced to disk as quickly as possible in a situation where other
1095 + processes may be submitting writes at the same time. Freezing the processes
1096 + that are submitting data stops new I/O from being submitted. Syncthreads can
1097 + then cleanly finish their work. So the order is:
1099 + - Userspace processes without PF_SYNCTHREAD or PF_NOFREEZE;
1100 + - Userspace processes with PF_SYNCTHREAD (they won't have NOFREEZE);
1101 + - Kernel processes without PF_NOFREEZE.
1105 + For a successful suspend, you need to have enough disk space to store the
1106 + image and enough memory for the various limitations of Suspend2's
1107 + algorithm. You can also specify a maximum image size. In order to attain
1108 + to those constraints, Suspend2 may 'eat' memory. If, after freezing
1109 + processes, the constraints aren't met, Suspend2 will thaw all the
1110 + other processes and begin to eat memory until its calculations indicate
1111 + the constraints are met. It will then freeze processes again and recheck
1114 + c. Allocation of storage.
1116 + Next, Suspend2 allocates the storage that will be used to save
1119 + The core of Suspend2 knows nothing about how or where pages are stored. We
1120 + therefore request the active writer (remember you might have compiled in
1121 + more than one!) to allocate enough storage for our expect image size. If
1122 + this request cannot be fulfilled, we eat more memory and try again. If it
1123 + is fulfiled, we seek to allocate additional storage, just in case our
1124 + expected compression ratio (if any) isn't achieved. This time, however, we
1125 + just continue if we can't allocate enough storage.
1127 + If these calls to our writer change the characteristics of the image such
1128 + that we haven't allocated enough memory, we also loop. (The writer may well
1129 + need to allocate space for its storage information).
1131 + d. Write the first part of the image.
1133 + Suspend2 stores the image in two sets of pages called 'pagesets'.
1134 + Pageset 2 contains pages on the active and inactive lists; essentially
1135 + the page cache. Pageset 1 contains all other pages, including the kernel.
1136 + We use two pagesets for one important reason: We need to make an atomic copy
1137 + of the kernel to ensure consistency of the image. Without a second pageset,
1138 + that would limit us to an image that was at most half the amount of memory
1139 + available. Using two pagesets allows us to store a full image. Since pageset
1140 + 2 pages won't be needed in saving pageset 1, we first save pageset 2 pages.
1141 + We can then make our atomic copy of the remaining pages using both pageset 2
1142 + pages and any other pages that are free. While saving both pagesets, we are
1143 + careful not to corrupt the image. Among other things, we use lowlevel block
1144 + I/O routines that don't change the pagecache contents.
1146 + The next step, then, is writing pageset 2.
1148 + e. Suspending drivers and storing processor context.
1150 + Having written pageset2, Suspend2 calls the power management functions to
1151 + notify drivers of the suspend, and saves the processor state in preparation
1152 + for the atomic copy of memory we are about to make.
1156 + At this stage, everything else but the Suspend2 code is halted. Processes
1157 + are frozen or idling, drivers are quiesced and have stored (ideally and where
1158 + necessary) their configuration in memory we are about to atomically copy.
1159 + In our lowlevel architecture specific code, we have saved the CPU state.
1160 + We can therefore now do our atomic copy before resuming drivers etc.
1162 + g. Save the atomic copy (pageset 1).
1164 + Suspend can then write the atomic copy of the remaining pages. Since we
1165 + have copied the pages into other locations, we can continue to use the
1166 + normal block I/O routines without fear of corruption our image.
1168 + f. Save the suspend header.
1170 + Nearly there! We save our settings and other parameters needed for
1171 + reloading pageset 1 in a 'suspend header'. We also tell our writer to
1172 + serialise its data at this stage, so that it can reread the image at resume
1173 + time. Note that the writer can write this data in any format - in the case
1174 + of the swapwriter, for example, it splits header pages in 4092 byte blocks,
1175 + using the last four bytes to link pages of data together. This is completely
1176 + transparent to the core.
1178 + g. Set the image header.
1180 + Finally, we edit the header at our resume2= location. The signature is
1181 + changed by the writer to reflect the fact that an image exists, and to point
1182 + to the start of that data if necessary (swapwriter).
1186 + Or reboot if we're debugging and the appropriate option is selected.
1190 + Reloading the image.
1191 + --------------------
1193 + Reloading the image is essentially the reverse of all the above. We load
1194 + our copy of pageset 1, being careful to choose locations that aren't going
1195 + to be overwritten as we copy it back (We start very early in the boot
1196 + process, so there are no other processes to quiesce here). We then copy
1197 + pageset 1 back to its original location in memory and restore the process
1198 + context. We are now running with the original kernel. Next, we reload the
1199 + pageset 2 pages, free the memory and swap used by Suspend2, restore
1200 + the pageset header and restart processes. Sounds easy in comparison to
1201 + suspending, doesn't it!
1203 + There is of course more to Suspend2 than this, but this explanation
1204 + should be a good start. If there's interest, I'll write further
1205 + documentation on range pages and the low level I/O.
1207 +11. Who wrote Suspend2?
1209 + (Answer based on the writings of Florent Chabaud, credits in files and
1210 + Nigel's limited knowledge; apologies to anyone missed out!)
1212 + The main developers of Suspend2 have been...
1220 + They have been aided in their efforts by a host of hundreds, if not thousands
1221 + of testers and people who have submitted bug fixes & suggestions. Of special
1222 + note are the efforts of Michael Frank, who had his computers repetitively
1223 + suspend and resume for literally tens of thousands of cycles and developed
1224 + scripts to stress the system and test Suspend2 far beyond the point
1225 + most of us (Nigel included!) would consider testing. His efforts have
1226 + contributed as much to Suspend2 as any of the names above.
1227 diff -ruN linux-2.6.22/MAINTAINERS suspend2-2.2.10-for-2.6.22/MAINTAINERS
1228 --- linux-2.6.22/MAINTAINERS 2007-07-11 22:18:39.000000000 +1000
1229 +++ suspend2-2.2.10-for-2.6.22/MAINTAINERS 2007-07-11 22:25:42.000000000 +1000
1230 @@ -3440,6 +3440,13 @@
1231 W: http://sammy.net/sun3/
1235 +P: Nigel Cunningham
1236 +M: nigel@suspend2.net
1237 +L: suspend2-devel@suspend2.net
1238 +W: http://suspend2.net
1244 diff -ruN linux-2.6.22/arch/i386/mm/fault.c suspend2-2.2.10-for-2.6.22/arch/i386/mm/fault.c
1245 --- linux-2.6.22/arch/i386/mm/fault.c 2007-07-11 22:18:41.000000000 +1000
1246 +++ suspend2-2.2.10-for-2.6.22/arch/i386/mm/fault.c 2007-07-11 22:25:42.000000000 +1000
1248 #include <linux/kprobes.h>
1249 #include <linux/uaccess.h>
1250 #include <linux/kdebug.h>
1251 +#include <linux/suspend.h>
1253 #include <asm/system.h>
1254 #include <asm/desc.h>
1257 static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
1259 +int suspend2_faulted = 0;
1260 +EXPORT_SYMBOL(suspend2_faulted);
1262 int register_page_fault_notifier(struct notifier_block *nb)
1265 @@ -311,6 +315,20 @@
1267 si_code = SEGV_MAPERR;
1269 + /* During a Suspend2 atomic copy, with DEBUG_SLAB, we will
1270 + * get page faults where slab has been unmapped. Map them
1271 + * temporarily and set the variable that tells Suspend2 to
1272 + * unmap afterwards.
1275 + if (unlikely(suspend2_running && !suspend2_faulted)) {
1276 + struct page *page = NULL;
1277 + suspend2_faulted = 1;
1278 + page = virt_to_page(address);
1279 + kernel_map_pages(page, 1, 1);
1284 * We fault-in kernel-space virtual memory on-demand. The
1285 * 'reference' page table is init_mm.pgd.
1286 diff -ruN linux-2.6.22/arch/i386/mm/init.c suspend2-2.2.10-for-2.6.22/arch/i386/mm/init.c
1287 --- linux-2.6.22/arch/i386/mm/init.c 2007-07-11 22:18:41.000000000 +1000
1288 +++ suspend2-2.2.10-for-2.6.22/arch/i386/mm/init.c 2007-07-11 22:25:42.000000000 +1000
1290 paravirt_pagetable_setup_done(pgd_base);
1293 -#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
1294 +#if defined(CONFIG_SUSPEND_SHARED) || defined(CONFIG_ACPI_SLEEP)
1296 * Swap suspend & friends need this for resume because things like the intel-agp
1297 * driver might have split up a kernel 4MB mapping.
1298 @@ -832,13 +832,13 @@
1301 for (addr = begin; addr < end; addr += PAGE_SIZE) {
1302 - ClearPageReserved(virt_to_page(addr));
1303 - init_page_count(virt_to_page(addr));
1304 + //ClearPageReserved(virt_to_page(addr));
1305 + //init_page_count(virt_to_page(addr));
1306 memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
1309 + //free_page(addr);
1310 + //totalram_pages++;
1312 - printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
1313 + //printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
1316 void free_initmem(void)
1317 diff -ruN linux-2.6.22/arch/i386/mm/pageattr.c suspend2-2.2.10-for-2.6.22/arch/i386/mm/pageattr.c
1318 --- linux-2.6.22/arch/i386/mm/pageattr.c 2007-07-11 22:18:41.000000000 +1000
1319 +++ suspend2-2.2.10-for-2.6.22/arch/i386/mm/pageattr.c 2007-07-11 22:25:42.000000000 +1000
1320 @@ -258,7 +258,27 @@
1324 +EXPORT_SYMBOL(kernel_map_pages);
1327 +int page_is_mapped(struct page *page)
1330 + unsigned long address;
1331 + struct page *kpte_page;
1333 + if(PageHighMem(page))
1336 + address = (unsigned long)page_address(page);
1338 + kpte = lookup_address(address);
1341 + kpte_page = virt_to_page(kpte);
1343 + return (pte_val(*kpte) & (__PAGE_KERNEL_EXEC | __PAGE_KERNEL)) ? 1:0;
1345 EXPORT_SYMBOL(change_page_attr);
1346 EXPORT_SYMBOL(global_flush_tlb);
1347 +EXPORT_SYMBOL(page_is_mapped);
1348 diff -ruN linux-2.6.22/arch/i386/power/Makefile suspend2-2.2.10-for-2.6.22/arch/i386/power/Makefile
1349 --- linux-2.6.22/arch/i386/power/Makefile 2007-07-11 22:18:41.000000000 +1000
1350 +++ suspend2-2.2.10-for-2.6.22/arch/i386/power/Makefile 2007-07-11 22:25:42.000000000 +1000
1352 obj-$(CONFIG_PM) += cpu.o
1353 -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o suspend.o
1354 +obj-$(CONFIG_SUSPEND_SHARED) += swsusp.o suspend.o
1355 diff -ruN linux-2.6.22/arch/powerpc/kernel/Makefile suspend2-2.2.10-for-2.6.22/arch/powerpc/kernel/Makefile
1356 --- linux-2.6.22/arch/powerpc/kernel/Makefile 2007-07-11 22:18:44.000000000 +1000
1357 +++ suspend2-2.2.10-for-2.6.22/arch/powerpc/kernel/Makefile 2007-07-11 22:25:42.000000000 +1000
1359 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
1360 obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
1361 obj-$(CONFIG_TAU) += tau_6xx.o
1362 -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o suspend.o
1363 -obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
1364 -obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
1365 +obj-$(CONFIG_SUSPEND_SHARED) += swsusp.o suspend.o
1366 +obj32-$(CONFIG_SUSPEND_SHARED) += swsusp_32.o
1367 +obj64-$(CONFIG_SUSPEND_SHARED) += swsusp_64.o swsusp_asm64.o
1368 obj32-$(CONFIG_MODULES) += module_32.o
1370 ifeq ($(CONFIG_PPC_MERGE),y)
1371 diff -ruN linux-2.6.22/arch/x86_64/kernel/Makefile suspend2-2.2.10-for-2.6.22/arch/x86_64/kernel/Makefile
1372 --- linux-2.6.22/arch/x86_64/kernel/Makefile 2007-07-11 22:18:48.000000000 +1000
1373 +++ suspend2-2.2.10-for-2.6.22/arch/x86_64/kernel/Makefile 2007-07-11 22:25:42.000000000 +1000
1375 obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
1376 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
1377 obj-$(CONFIG_PM) += suspend.o
1378 -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
1379 +obj-$(CONFIG_SUSPEND_SHARED) += suspend_asm.o
1380 obj-$(CONFIG_CPU_FREQ) += cpufreq/
1381 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
1382 obj-$(CONFIG_IOMMU) += pci-gart.o aperture.o
1383 diff -ruN linux-2.6.22/arch/x86_64/kernel/suspend.c suspend2-2.2.10-for-2.6.22/arch/x86_64/kernel/suspend.c
1384 --- linux-2.6.22/arch/x86_64/kernel/suspend.c 2007-07-11 22:18:48.000000000 +1000
1385 +++ suspend2-2.2.10-for-2.6.22/arch/x86_64/kernel/suspend.c 2007-07-11 22:25:42.000000000 +1000
1390 -#ifdef CONFIG_SOFTWARE_SUSPEND
1391 +#ifdef CONFIG_SUSPEND_SHARED
1392 /* Defined in arch/x86_64/kernel/suspend_asm.S */
1393 extern int restore_image(void);
1396 unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
1397 return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
1399 -#endif /* CONFIG_SOFTWARE_SUSPEND */
1400 +#endif /* CONFIG_SUSPEND_SHARED */
1401 diff -ruN linux-2.6.22/crypto/Kconfig suspend2-2.2.10-for-2.6.22/crypto/Kconfig
1402 --- linux-2.6.22/crypto/Kconfig 2007-07-11 22:18:48.000000000 +1000
1403 +++ suspend2-2.2.10-for-2.6.22/crypto/Kconfig 2007-07-11 22:25:42.000000000 +1000
1404 @@ -419,6 +419,14 @@
1406 You will most probably want this if using IPSec.
1409 + tristate "LZF compression algorithm"
1411 + select CRYPTO_ALGAPI
1413 + This is the LZF algorithm. It is especially useful for Suspend2,
1414 + because it achieves good compression quickly.
1416 config CRYPTO_MICHAEL_MIC
1417 tristate "Michael MIC keyed digest algorithm"
1418 select CRYPTO_ALGAPI
1419 diff -ruN linux-2.6.22/crypto/Makefile suspend2-2.2.10-for-2.6.22/crypto/Makefile
1420 --- linux-2.6.22/crypto/Makefile 2007-07-11 22:18:48.000000000 +1000
1421 +++ suspend2-2.2.10-for-2.6.22/crypto/Makefile 2007-07-11 22:25:42.000000000 +1000
1423 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
1424 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
1425 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
1426 +obj-$(CONFIG_CRYPTO_LZF) += lzf.o
1428 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
1429 diff -ruN linux-2.6.22/crypto/lzf.c suspend2-2.2.10-for-2.6.22/crypto/lzf.c
1430 --- linux-2.6.22/crypto/lzf.c 1970-01-01 10:00:00.000000000 +1000
1431 +++ suspend2-2.2.10-for-2.6.22/crypto/lzf.c 2007-07-11 22:25:42.000000000 +1000
1434 + * Cryptoapi LZF compression module.
1436 + * Copyright (c) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
1438 + * based on the deflate.c file:
1440 + * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
1442 + * and upon the LZF compression module donated to the Suspend2 project with
1443 + * the following copyright:
1445 + * This program is free software; you can redistribute it and/or modify it
1446 + * under the terms of the GNU General Public License as published by the Free
1447 + * Software Foundation; either version 2 of the License, or (at your option)
1448 + * any later version.
1449 + * Copyright (c) 2000-2003 Marc Alexander Lehmann <pcg@goof.com>
1451 + * Redistribution and use in source and binary forms, with or without modifica-
1452 + * tion, are permitted provided that the following conditions are met:
1454 + * 1. Redistributions of source code must retain the above copyright notice,
1455 + * this list of conditions and the following disclaimer.
1457 + * 2. Redistributions in binary form must reproduce the above copyright
1458 + * notice, this list of conditions and the following disclaimer in the
1459 + * documentation and/or other materials provided with the distribution.
1461 + * 3. The name of the author may not be used to endorse or promote products
1462 + * derived from this software without specific prior written permission.
1464 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
1465 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
1466 + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
1467 + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
1468 + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1469 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
1470 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1471 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
1472 + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1473 + * OF THE POSSIBILITY OF SUCH DAMAGE.
1475 + * Alternatively, the contents of this file may be used under the terms of
1476 + * the GNU General Public License version 2 (the "GPL"), in which case the
1477 + * provisions of the GPL are applicable instead of the above. If you wish to
1478 + * allow the use of your version of this file only under the terms of the
1479 + * GPL and not to allow others to use your version of this file under the
1480 + * BSD license, indicate your decision by deleting the provisions above and
1481 + * replace them with the notice and other provisions required by the GPL. If
1482 + * you do not delete the provisions above, a recipient may use your version
1483 + * of this file under either the BSD or the GPL.
1486 +#include <linux/kernel.h>
1487 +#include <linux/module.h>
1488 +#include <linux/init.h>
1489 +#include <linux/module.h>
1490 +#include <linux/crypto.h>
1491 +#include <linux/err.h>
1492 +#include <linux/vmalloc.h>
1493 +#include <asm/string.h>
1497 + unsigned int bufofs;
1501 + * size of hashtable is (1 << hlog) * sizeof (char *)
1502 + * decompression is independent of the hash table size
1503 + * the difference between 15 and 14 is very small
1504 + * for small blocks (and 14 is also faster).
1505 + * For a low-memory configuration, use hlog == 13;
1506 + * For best compression, use 15 or 16.
1508 +static const int hlog = 14;
1511 + * don't play with this unless you benchmark!
1512 + * decompression is not dependent on the hash function
1513 + * the hashing function might seem strange, just believe me
1516 +static inline u16 first(const u8 *p)
1518 + return ((p[0]) << 8) + p[1];
1521 +static inline u16 next(u8 v, const u8 *p)
1523 + return ((v) << 8) + p[2];
1526 +static inline u32 idx(unsigned int h)
1528 + return (((h ^ (h << 5)) >> (3*8 - hlog)) + h*3) & ((1 << hlog) - 1);
1532 + * IDX works because it is very similar to a multiplicative hash, e.g.
1533 + * (h * 57321 >> (3*8 - hlog))
1534 + * the next one is also quite good, albeit slow ;)
1535 + * (int)(cos(h & 0xffffff) * 1e6)
1538 +static const int max_lit = (1 << 5);
1539 +static const int max_off = (1 << 13);
1540 +static const int max_ref = ((1 << 8) + (1 << 3));
1543 + * compressed format
1545 + * 000LLLLL <L+1> ; literal
1546 + * LLLOOOOO oooooooo ; backref L
1547 + * 111OOOOO LLLLLLLL oooooooo ; backref L+7
1551 +static void lzf_compress_exit(struct crypto_tfm *tfm)
1553 + struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1562 +static int lzf_compress_init(struct crypto_tfm *tfm)
1564 + struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1566 + /* Get LZF ready to go */
1567 + ctx->hbuf = vmalloc_32((1 << hlog) * sizeof(char *));
1571 + printk(KERN_WARNING "Failed to allocate %ld bytes for lzf workspace\n",
1572 + (long) ((1 << hlog) * sizeof(char *)));
1576 +static int lzf_compress(struct crypto_tfm *tfm, const u8 *in_data,
1577 + unsigned int in_len, u8 *out_data, unsigned int *out_len)
1579 + struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1580 + const u8 **htab = ctx->hbuf;
1582 + const u8 *ip = in_data;
1583 + u8 *op = out_data;
1584 + const u8 *in_end = ip + in_len;
1585 + u8 *out_end = op + *out_len - 3;
1588 + unsigned int hval = first(ip);
1589 + unsigned long off;
1592 + memset(htab, 0, sizeof(htab));
1595 + if (ip < in_end - 2) {
1596 + hval = next(hval, ip);
1597 + hslot = htab + idx(hval);
1601 + if ((off = ip - ref - 1) < max_off
1602 + && ip + 4 < in_end && ref > in_data
1603 + && *(u16 *) ref == *(u16 *) ip && ref[2] == ip[2]
1605 + /* match found at *ref++ */
1606 + unsigned int len = 2;
1607 + unsigned int maxlen = in_end - ip - len;
1608 + maxlen = maxlen > max_ref ? max_ref : maxlen;
1612 + while (len < maxlen && ref[len] == ip[len]);
1614 + if (op + lit + 1 + 3 >= out_end) {
1615 + *out_len = PAGE_SIZE;
1631 + *op++ = (off >> 8) + (len << 5);
1633 + *op++ = (off >> 8) + (7 << 5);
1641 + hval = next(hval, ip);
1642 + htab[idx(hval)] = ip;
1646 + } else if (ip == in_end)
1649 + /* one more literal byte we must copy */
1653 + if (lit == max_lit) {
1654 + if (op + 1 + max_lit >= out_end) {
1655 + *out_len = PAGE_SIZE;
1659 + *op++ = max_lit - 1;
1660 + memcpy(op, ip - max_lit, max_lit);
1667 + if (op + lit + 1 >= out_end) {
1668 + *out_len = PAGE_SIZE;
1679 + *out_len = op - out_data;
1683 +static int lzf_decompress(struct crypto_tfm *tfm, const u8 *src,
1684 + unsigned int slen, u8 *dst, unsigned int *dlen)
1686 + u8 const *ip = src;
1688 + u8 const *const in_end = ip + slen;
1689 + u8 *const out_end = op + *dlen;
1691 + *dlen = PAGE_SIZE;
1693 + unsigned int ctrl = *ip++;
1695 + if (ctrl < (1 << 5)) { /* literal run */
1698 + if (op + ctrl > out_end)
1700 + memcpy(op, ip, ctrl);
1703 + } else { /* back reference */
1705 + unsigned int len = ctrl >> 5;
1707 + u8 *ref = op - ((ctrl & 0x1f) << 8) - 1;
1715 + if (op + len > out_end || ref < (u8 *) dst)
1723 + while (op < out_end && ip < in_end);
1725 + *dlen = op - (u8 *) dst;
1729 +static struct crypto_alg alg = {
1730 + .cra_name = "lzf",
1731 + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
1733 + .cra_module = THIS_MODULE,
1734 + .cra_list = LIST_HEAD_INIT(alg.cra_list),
1735 + .cra_init = lzf_compress_init,
1736 + .cra_exit = lzf_compress_exit,
1737 + .cra_u = { .compress = {
1738 + .coa_compress = lzf_compress,
1739 + .coa_decompress = lzf_decompress } }
1742 +static int __init init(void)
1744 + return crypto_register_alg(&alg);
1747 +static void __exit fini(void)
1749 + crypto_unregister_alg(&alg);
1755 +MODULE_LICENSE("GPL");
1756 +MODULE_DESCRIPTION("LZF Compression Algorithm");
1757 +MODULE_AUTHOR("Marc Alexander Lehmann & Nigel Cunningham");
1758 diff -ruN linux-2.6.22/drivers/acpi/sleep/main.c suspend2-2.2.10-for-2.6.22/drivers/acpi/sleep/main.c
1759 --- linux-2.6.22/drivers/acpi/sleep/main.c 2007-07-11 22:18:49.000000000 +1000
1760 +++ suspend2-2.2.10-for-2.6.22/drivers/acpi/sleep/main.c 2007-07-11 22:25:42.000000000 +1000
1762 .finish = acpi_pm_finish,
1765 -#ifdef CONFIG_SOFTWARE_SUSPEND
1766 +#ifdef CONFIG_SUSPEND_SHARED
1767 static int acpi_hibernation_prepare(void)
1769 return acpi_sleep_prepare(ACPI_STATE_S4);
1771 .enter = acpi_hibernation_enter,
1772 .finish = acpi_hibernation_finish,
1774 -#endif /* CONFIG_SOFTWARE_SUSPEND */
1775 +#endif /* CONFIG_SUSPEND_SHARED */
1778 * Toshiba fails to preserve interrupts over S1, reinitialization
1781 pm_set_ops(&acpi_pm_ops);
1783 -#ifdef CONFIG_SOFTWARE_SUSPEND
1784 +#ifdef CONFIG_SUSPEND_SHARED
1785 if (sleep_states[ACPI_STATE_S4])
1786 hibernation_set_ops(&acpi_hibernation_ops);
1788 diff -ruN linux-2.6.22/drivers/acpi/sleep/proc.c suspend2-2.2.10-for-2.6.22/drivers/acpi/sleep/proc.c
1789 --- linux-2.6.22/drivers/acpi/sleep/proc.c 2007-07-11 22:18:49.000000000 +1000
1790 +++ suspend2-2.2.10-for-2.6.22/drivers/acpi/sleep/proc.c 2007-07-11 22:25:42.000000000 +1000
1794 state = simple_strtoul(str, NULL, 0);
1795 -#ifdef CONFIG_SOFTWARE_SUSPEND
1796 +#ifdef CONFIG_SUSPEND_SHARED
1798 error = hibernate();
1800 diff -ruN linux-2.6.22/drivers/base/core.c suspend2-2.2.10-for-2.6.22/drivers/base/core.c
1801 --- linux-2.6.22/drivers/base/core.c 2007-07-11 22:18:49.000000000 +1000
1802 +++ suspend2-2.2.10-for-2.6.22/drivers/base/core.c 2007-07-11 22:25:42.000000000 +1000
1804 int (*platform_notify)(struct device * dev) = NULL;
1805 int (*platform_notify_remove)(struct device * dev) = NULL;
1807 +static int do_dump_stack;
1810 * sysfs bindings for devices.
1812 @@ -755,6 +757,18 @@
1813 class_intf->add_dev(dev, class_intf);
1814 up(&dev->class->sem);
1818 + if (!((dev->class && dev->class->resume) ||
1819 + (dev->bus && (dev->bus->resume || dev->bus->resume_early))) &&
1821 + printk("Device driver %s lacks bus and class support for "
1822 + "being resumed.\n", kobject_name(&dev->kobj));
1823 + if (do_dump_stack)
1831 @@ -1103,6 +1117,7 @@
1833 dev->parent = parent;
1834 dev->release = device_create_release;
1837 va_start(args, fmt);
1838 vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
1839 @@ -1311,3 +1326,11 @@
1842 EXPORT_SYMBOL_GPL(device_move);
1844 +static int __init pm_debug_dump_stack(char *str)
1846 + do_dump_stack = 1;
1850 +__setup("pm_debug_dump_stack", pm_debug_dump_stack);
1851 diff -ruN linux-2.6.22/drivers/macintosh/via-pmu.c suspend2-2.2.10-for-2.6.22/drivers/macintosh/via-pmu.c
1852 --- linux-2.6.22/drivers/macintosh/via-pmu.c 2007-07-11 22:19:03.000000000 +1000
1853 +++ suspend2-2.2.10-for-2.6.22/drivers/macintosh/via-pmu.c 2007-07-11 22:25:42.000000000 +1000
1855 #include <linux/interrupt.h>
1856 #include <linux/device.h>
1857 #include <linux/sysdev.h>
1858 -#include <linux/freezer.h>
1859 #include <linux/syscalls.h>
1860 #include <linux/suspend.h>
1861 #include <linux/cpu.h>
1862 diff -ruN linux-2.6.22/drivers/md/md.c suspend2-2.2.10-for-2.6.22/drivers/md/md.c
1863 --- linux-2.6.22/drivers/md/md.c 2007-07-11 22:19:04.000000000 +1000
1864 +++ suspend2-2.2.10-for-2.6.22/drivers/md/md.c 2007-07-11 22:25:42.000000000 +1000
1865 @@ -5401,6 +5401,8 @@
1869 + while(freezer_is_on())
1872 if (kthread_should_stop()) {
1874 diff -ruN linux-2.6.22/drivers/pci/pci-driver.c suspend2-2.2.10-for-2.6.22/drivers/pci/pci-driver.c
1875 --- linux-2.6.22/drivers/pci/pci-driver.c 2007-07-11 22:19:27.000000000 +1000
1876 +++ suspend2-2.2.10-for-2.6.22/drivers/pci/pci-driver.c 2007-07-11 22:25:42.000000000 +1000
1877 @@ -432,6 +432,10 @@
1879 driver_unregister(&drv->driver);
1882 + printk("PCI driver %s lacks driver specific resume support.\n",
1888 diff -ruN linux-2.6.22/drivers/usb/core/driver.c suspend2-2.2.10-for-2.6.22/drivers/usb/core/driver.c
1889 --- linux-2.6.22/drivers/usb/core/driver.c 2007-07-11 22:19:28.000000000 +1000
1890 +++ suspend2-2.2.10-for-2.6.22/drivers/usb/core/driver.c 2007-07-11 22:25:42.000000000 +1000
1892 usbcore_name, new_driver->name);
1893 usbfs_update_special();
1894 usb_create_newid_file(new_driver);
1895 + if (!new_driver->resume)
1896 + printk("USB driver %s lacks resume support.\n",
1897 + new_driver->name);
1899 printk(KERN_ERR "%s: error %d registering interface "
1901 diff -ruN linux-2.6.22/include/asm-i386/cacheflush.h suspend2-2.2.10-for-2.6.22/include/asm-i386/cacheflush.h
1902 --- linux-2.6.22/include/asm-i386/cacheflush.h 2007-07-11 22:19:34.000000000 +1000
1903 +++ suspend2-2.2.10-for-2.6.22/include/asm-i386/cacheflush.h 2007-07-11 22:25:42.000000000 +1000
1905 void mark_rodata_ro(void);
1908 +extern int page_is_mapped(struct page *page);
1910 #endif /* _I386_CACHEFLUSH_H */
1911 diff -ruN linux-2.6.22/include/asm-i386/suspend.h suspend2-2.2.10-for-2.6.22/include/asm-i386/suspend.h
1912 --- linux-2.6.22/include/asm-i386/suspend.h 2007-07-11 22:19:34.000000000 +1000
1913 +++ suspend2-2.2.10-for-2.6.22/include/asm-i386/suspend.h 2007-07-11 22:25:42.000000000 +1000
1916 static inline int arch_prepare_suspend(void) { return 0; }
1918 +extern int suspend2_faulted;
1919 +#define clear_suspend2_fault() do { suspend2_faulted = 0; } while(0)
1921 /* image of the saved processor state */
1922 struct saved_context {
1924 diff -ruN linux-2.6.22/include/asm-ppc/suspend.h suspend2-2.2.10-for-2.6.22/include/asm-ppc/suspend.h
1925 --- linux-2.6.22/include/asm-ppc/suspend.h 2007-07-11 22:19:36.000000000 +1000
1926 +++ suspend2-2.2.10-for-2.6.22/include/asm-ppc/suspend.h 2007-07-11 22:25:42.000000000 +1000
1928 static inline void restore_processor_state(void)
1932 +#define suspend2_faulted (0)
1933 +#define clear_suspend2_fault() do { } while(0)
1934 diff -ruN linux-2.6.22/include/asm-x86_64/cacheflush.h suspend2-2.2.10-for-2.6.22/include/asm-x86_64/cacheflush.h
1935 --- linux-2.6.22/include/asm-x86_64/cacheflush.h 2007-07-11 22:19:38.000000000 +1000
1936 +++ suspend2-2.2.10-for-2.6.22/include/asm-x86_64/cacheflush.h 2007-07-11 22:25:42.000000000 +1000
1938 void mark_rodata_ro(void);
1941 +static inline int page_is_mapped(struct page *page)
1946 #endif /* _X8664_CACHEFLUSH_H */
1947 diff -ruN linux-2.6.22/include/asm-x86_64/suspend.h suspend2-2.2.10-for-2.6.22/include/asm-x86_64/suspend.h
1948 --- linux-2.6.22/include/asm-x86_64/suspend.h 2007-07-11 22:19:38.000000000 +1000
1949 +++ suspend2-2.2.10-for-2.6.22/include/asm-x86_64/suspend.h 2007-07-11 22:25:42.000000000 +1000
1954 +#define suspend2_faulted (0)
1955 +#define clear_suspend2_fault() do { } while(0)
1957 /* Image of the saved processor state. If you touch this, fix acpi_wakeup.S. */
1958 struct saved_context {
1959 u16 ds, es, fs, gs, ss;
1960 diff -ruN linux-2.6.22/include/linux/device.h suspend2-2.2.10-for-2.6.22/include/linux/device.h
1961 --- linux-2.6.22/include/linux/device.h 2007-07-11 22:19:38.000000000 +1000
1962 +++ suspend2-2.2.10-for-2.6.22/include/linux/device.h 2007-07-11 22:25:42.000000000 +1000
1964 char bus_id[BUS_ID_SIZE]; /* position on parent bus */
1965 struct device_type *type;
1966 unsigned is_registered:1;
1967 + unsigned pm_safe:1; /* No resume fn is ok? */
1968 unsigned uevent_suppress:1;
1969 struct device_attribute uevent_attr;
1970 struct device_attribute *devt_attr;
1971 diff -ruN linux-2.6.22/include/linux/dyn_pageflags.h suspend2-2.2.10-for-2.6.22/include/linux/dyn_pageflags.h
1972 --- linux-2.6.22/include/linux/dyn_pageflags.h 1970-01-01 10:00:00.000000000 +1000
1973 +++ suspend2-2.2.10-for-2.6.22/include/linux/dyn_pageflags.h 2007-07-11 22:25:42.000000000 +1000
1976 + * include/linux/dyn_pageflags.h
1978 + * Copyright (C) 2004-2006 Nigel Cunningham <nigel@suspend2.net>
1980 + * This file is released under the GPLv2.
1982 + * It implements support for dynamically allocated bitmaps that are
1983 + * used for temporary or infrequently used pageflags, in lieu of
1984 + * bits in the struct page flags entry.
1987 +#ifndef DYN_PAGEFLAGS_H
1988 +#define DYN_PAGEFLAGS_H
1990 +#include <linux/mm.h>
1992 +/* [pg_dat][zone][page_num] */
1993 +typedef unsigned long **** dyn_pageflags_t;
1995 +#if BITS_PER_LONG == 32
1998 +#if BITS_PER_LONG == 64
2001 +#error Bits per long not 32 or 64?
2005 +#define BIT_NUM_MASK (sizeof(unsigned long) * 8 - 1)
2006 +#define PAGE_NUM_MASK (~((1 << (PAGE_SHIFT + 3)) - 1))
2007 +#define UL_NUM_MASK (~(BIT_NUM_MASK | PAGE_NUM_MASK))
2010 + * PAGENUMBER gives the index of the page within the zone.
2011 + * PAGEINDEX gives the index of the unsigned long within that page.
2012 + * PAGEBIT gives the index of the bit within the unsigned long.
2014 +#define BITS_PER_PAGE (PAGE_SIZE << 3)
2015 +#define PAGENUMBER(zone_offset) ((int) (zone_offset >> (PAGE_SHIFT + 3)))
2016 +#define PAGEINDEX(zone_offset) ((int) ((zone_offset & UL_NUM_MASK) >> UL_SHIFT))
2017 +#define PAGEBIT(zone_offset) ((int) (zone_offset & BIT_NUM_MASK))
2019 +#define PAGE_UL_PTR(bitmap, node, zone_num, zone_pfn) \
2020 + ((bitmap[node][zone_num][PAGENUMBER(zone_pfn)])+PAGEINDEX(zone_pfn))
2022 +#define BITMAP_FOR_EACH_SET(bitmap, counter) \
2023 + for (counter = get_next_bit_on(bitmap, max_pfn + 1); counter <= max_pfn; \
2024 + counter = get_next_bit_on(bitmap, counter))
2026 +extern void clear_dyn_pageflags(dyn_pageflags_t pagemap);
2027 +extern int allocate_dyn_pageflags(dyn_pageflags_t *pagemap);
2028 +extern void free_dyn_pageflags(dyn_pageflags_t *pagemap);
2029 +extern unsigned long get_next_bit_on(dyn_pageflags_t bitmap, unsigned long counter);
2031 +extern int test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page);
2032 +extern void set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page);
2033 +extern void clear_dynpageflag(dyn_pageflags_t *bitmap, struct page *page);
2037 + * With the above macros defined, you can do...
2038 + * #define PagePageset1(page) (test_dynpageflag(&pageset1_map, page))
2039 + * #define SetPagePageset1(page) (set_dynpageflag(&pageset1_map, page))
2040 + * #define ClearPagePageset1(page) (clear_dynpageflag(&pageset1_map, page))
2043 diff -ruN linux-2.6.22/include/linux/freezer.h suspend2-2.2.10-for-2.6.22/include/linux/freezer.h
2044 --- linux-2.6.22/include/linux/freezer.h 2007-07-11 22:19:38.000000000 +1000
2045 +++ suspend2-2.2.10-for-2.6.22/include/linux/freezer.h 2007-07-11 22:25:42.000000000 +1000
2047 /* Freezer declarations */
2048 +#ifndef LINUX_FREEZER_H
2049 +#define LINUX_FREEZER_H
2051 #include <linux/sched.h>
2053 @@ -115,6 +117,18 @@
2054 return !!(p->flags & PF_FREEZER_SKIP);
2057 +extern int freezer_state;
2058 +#define FREEZER_OFF 0
2059 +#define FREEZER_USERSPACE_FROZEN 1
2060 +#define FREEZER_FULLY_ON 2
2062 +static inline int freezer_is_on(void)
2064 + return (freezer_state == FREEZER_FULLY_ON);
2067 +extern void thaw_kernel_threads(void);
2070 static inline int frozen(struct task_struct *p) { return 0; }
2071 static inline int freezing(struct task_struct *p) { return 0; }
2072 @@ -126,8 +140,11 @@
2073 static inline void thaw_processes(void) {}
2075 static inline int try_to_freeze(void) { return 0; }
2076 +static inline int freezer_is_on(void) { return 0; }
2077 +static inline void thaw_kernel_threads(void) { }
2079 static inline void freezer_do_not_count(void) {}
2080 static inline void freezer_count(void) {}
2081 static inline int freezer_should_skip(struct task_struct *p) { return 0; }
2084 diff -ruN linux-2.6.22/include/linux/kernel.h suspend2-2.2.10-for-2.6.22/include/linux/kernel.h
2085 --- linux-2.6.22/include/linux/kernel.h 2007-07-11 22:19:39.000000000 +1000
2086 +++ suspend2-2.2.10-for-2.6.22/include/linux/kernel.h 2007-07-11 22:25:42.000000000 +1000
2088 __attribute__ ((format (printf, 2, 0)));
2089 extern int snprintf(char * buf, size_t size, const char * fmt, ...)
2090 __attribute__ ((format (printf, 3, 4)));
2091 +extern int snprintf_used(char *buffer, int buffer_size,
2092 + const char *fmt, ...);
2093 extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
2094 __attribute__ ((format (printf, 3, 0)));
2095 extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
2096 diff -ruN linux-2.6.22/include/linux/netlink.h suspend2-2.2.10-for-2.6.22/include/linux/netlink.h
2097 --- linux-2.6.22/include/linux/netlink.h 2007-07-11 22:19:39.000000000 +1000
2098 +++ suspend2-2.2.10-for-2.6.22/include/linux/netlink.h 2007-07-11 22:25:42.000000000 +1000
2100 /* leave room for NETLINK_DM (DM Events) */
2101 #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
2102 #define NETLINK_ECRYPTFS 19
2103 +#define NETLINK_SUSPEND2_USERUI 20 /* For suspend2's userui */
2104 +#define NETLINK_SUSPEND2_USM 21 /* For suspend2's userspace storage manager */
2106 #define MAX_LINKS 32
2108 diff -ruN linux-2.6.22/include/linux/suspend.h suspend2-2.2.10-for-2.6.22/include/linux/suspend.h
2109 --- linux-2.6.22/include/linux/suspend.h 2007-07-11 22:19:39.000000000 +1000
2110 +++ suspend2-2.2.10-for-2.6.22/include/linux/suspend.h 2007-07-11 22:25:42.000000000 +1000
2112 void (*finish)(void);
2115 -#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
2116 +#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND_SHARED)
2117 /* kernel/power/snapshot.c */
2118 extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
2119 static inline void register_nosave_region(unsigned long b, unsigned long e)
2121 void __save_processor_state(struct saved_context *ctxt);
2122 void __restore_processor_state(struct saved_context *ctxt);
2125 + SUSPEND_CAN_SUSPEND,
2126 + SUSPEND_CAN_RESUME,
2128 + SUSPEND_RESUME_DEVICE_OK,
2129 + SUSPEND_NORESUME_SPECIFIED,
2130 + SUSPEND_SANITY_CHECK_PROMPT,
2131 + SUSPEND_PAGESET2_NOT_LOADED,
2132 + SUSPEND_CONTINUE_REQ,
2133 + SUSPEND_RESUMED_BEFORE,
2134 + SUSPEND_RESUME_NOT_DONE,
2135 + SUSPEND_BOOT_TIME,
2136 + SUSPEND_NOW_RESUMING,
2137 + SUSPEND_IGNORE_LOGLEVEL,
2138 + SUSPEND_TRYING_TO_RESUME,
2139 + SUSPEND_TRY_RESUME_RD,
2140 + SUSPEND_LOADING_ALT_IMAGE,
2141 + SUSPEND_STOP_RESUME,
2142 + SUSPEND_IO_STOPPED,
2145 +#ifdef CONFIG_SUSPEND2
2147 +/* Used in init dir files */
2148 +extern unsigned long suspend_state;
2149 +#define set_suspend_state(bit) (set_bit(bit, &suspend_state))
2150 +#define clear_suspend_state(bit) (clear_bit(bit, &suspend_state))
2151 +#define test_suspend_state(bit) (test_bit(bit, &suspend_state))
2152 +extern int suspend2_running;
2154 +#else /* !CONFIG_SUSPEND2 */
2156 +#define suspend_state (0)
2157 +#define set_suspend_state(bit) do { } while(0)
2158 +#define clear_suspend_state(bit) do { } while (0)
2159 +#define test_suspend_state(bit) (0)
2160 +#define suspend2_running (0)
2161 +#endif /* CONFIG_SUSPEND2 */
2163 +#ifdef CONFIG_SUSPEND_SHARED
2164 +#ifdef CONFIG_SUSPEND2
2165 +extern void suspend2_try_resume(void);
2167 +#define suspend2_try_resume() do { } while(0)
2170 +extern int resume_attempted;
2172 +#ifdef CONFIG_SOFTWARE_SUSPEND
2173 +extern int software_resume(void);
2175 +static inline int software_resume(void)
2177 + resume_attempted = 1;
2178 + suspend2_try_resume();
2183 +static inline void check_resume_attempted(void)
2185 + if (resume_attempted)
2188 + software_resume();
2191 +#define check_resume_attempted() do { } while(0)
2192 +#define resume_attempted (0)
2195 +#ifdef CONFIG_PRINTK_NOSAVE
2196 +#define POSS_NOSAVE __nosavedata
2198 +#define POSS_NOSAVE
2201 #endif /* _LINUX_SWSUSP_H */
2202 diff -ruN linux-2.6.22/include/linux/swap.h suspend2-2.2.10-for-2.6.22/include/linux/swap.h
2203 --- linux-2.6.22/include/linux/swap.h 2007-07-11 22:19:39.000000000 +1000
2204 +++ suspend2-2.2.10-for-2.6.22/include/linux/swap.h 2007-07-11 22:25:42.000000000 +1000
2206 /* linux/mm/vmscan.c */
2207 extern unsigned long try_to_free_pages(struct zone **, gfp_t);
2208 extern unsigned long shrink_all_memory(unsigned long nr_pages);
2209 +extern void shrink_one_zone(struct zone *zone, int desired_size);
2210 extern int vm_swappiness;
2211 extern int remove_mapping(struct address_space *mapping, struct page *page);
2212 extern long vm_total_pages;
2213 @@ -368,5 +369,10 @@
2214 #define disable_swap_token() do { } while(0)
2216 #endif /* CONFIG_SWAP */
2218 +/* For Suspend2 - unlink LRU pages while saving separately */
2219 +void unlink_lru_lists(void);
2220 +void relink_lru_lists(void);
2222 #endif /* __KERNEL__*/
2223 #endif /* _LINUX_SWAP_H */
2224 diff -ruN linux-2.6.22/include/linux/time.h suspend2-2.2.10-for-2.6.22/include/linux/time.h
2225 --- linux-2.6.22/include/linux/time.h 2007-07-11 22:19:40.000000000 +1000
2226 +++ suspend2-2.2.10-for-2.6.22/include/linux/time.h 2007-07-11 22:25:42.000000000 +1000
2229 #define TIMER_ABSTIME 0x01
2231 +extern void save_avenrun(void);
2232 +extern void restore_avenrun(void);
2235 diff -ruN linux-2.6.22/init/do_mounts.c suspend2-2.2.10-for-2.6.22/init/do_mounts.c
2236 --- linux-2.6.22/init/do_mounts.c 2007-07-11 22:19:40.000000000 +1000
2237 +++ suspend2-2.2.10-for-2.6.22/init/do_mounts.c 2007-07-11 22:25:42.000000000 +1000
2238 @@ -141,11 +141,16 @@
2243 + int part, mount_result;
2246 int mkdir_err = sys_mkdir("/sys", 0700);
2247 - if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
2249 + * When changing resume2 parameter for Software Suspend, sysfs may
2250 + * already be mounted.
2252 + mount_result = sys_mount("sysfs", "/sys", "sysfs", 0, NULL);
2253 + if (mount_result < 0 && mount_result != -EBUSY)
2258 res = try_name(s, part);
2261 - sys_umount("/sys", 0);
2262 + if (mount_result >= 0)
2263 + sys_umount("/sys", 0);
2267 @@ -440,12 +446,27 @@
2269 is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
2272 + * By this point, suspend_early_init has been called to initialise our
2273 + * sysfs interface. If modules are built in, they have registered (all
2274 + * of the above via initcalls).
2276 + * We have not yet looked to see if an image exists, however. If we
2277 + * have an initrd, it is expected that the user will have set it up
2278 + * to echo > /sys/power/suspend2/do_resume and thus initiate any
2279 + * resume. If they don't do that, we do it immediately after the initrd
2280 + * is finished (major issues if they mount filesystems rw from the
2281 + * initrd! - they are warned. If there's no usable initrd, we do our
2287 if (is_floppy && rd_doload && rd_load_disk(0))
2288 ROOT_DEV = Root_RAM0;
2290 + check_resume_attempted();
2294 sys_mount(".", "/", NULL, MS_MOVE, NULL);
2295 diff -ruN linux-2.6.22/init/do_mounts_initrd.c suspend2-2.2.10-for-2.6.22/init/do_mounts_initrd.c
2296 --- linux-2.6.22/init/do_mounts_initrd.c 2007-07-11 22:19:40.000000000 +1000
2297 +++ suspend2-2.2.10-for-2.6.22/init/do_mounts_initrd.c 2007-07-11 22:25:42.000000000 +1000
2299 #include <linux/romfs_fs.h>
2300 #include <linux/initrd.h>
2301 #include <linux/sched.h>
2302 +#include <linux/suspend.h>
2303 #include <linux/freezer.h>
2305 #include "do_mounts.h"
2310 + if (!resume_attempted)
2311 + printk(KERN_ERR "Suspend2: No attempt was made to resume from "
2312 + "any image that might exist.\n");
2313 + clear_suspend_state(SUSPEND_BOOT_TIME);
2315 /* move initrd to rootfs' /old */
2317 sys_mount("/", ".", NULL, MS_MOVE, NULL);
2318 diff -ruN linux-2.6.22/init/main.c suspend2-2.2.10-for-2.6.22/init/main.c
2319 --- linux-2.6.22/init/main.c 2007-07-11 22:19:40.000000000 +1000
2320 +++ suspend2-2.2.10-for-2.6.22/init/main.c 2007-07-11 22:25:42.000000000 +1000
2322 #include <linux/pid_namespace.h>
2323 #include <linux/device.h>
2324 #include <linux/kthread.h>
2325 +#include <linux/suspend.h>
2328 #include <asm/bugs.h>
2332 * check if there is an early userspace init. If yes, let it do all
2334 + * the work. For suspend2, we assume that it will do the right thing
2335 + * with regard to trying to resume at the right place. When that
2336 + * happens, the BOOT_TIME flag will be cleared.
2339 if (!ramdisk_execute_command)
2340 diff -ruN linux-2.6.22/kernel/kmod.c suspend2-2.2.10-for-2.6.22/kernel/kmod.c
2341 --- linux-2.6.22/kernel/kmod.c 2007-07-11 22:19:41.000000000 +1000
2342 +++ suspend2-2.2.10-for-2.6.22/kernel/kmod.c 2007-07-11 22:25:42.000000000 +1000
2344 #include <linux/kernel.h>
2345 #include <linux/init.h>
2346 #include <linux/resource.h>
2347 +#include <linux/freezer.h>
2348 #include <asm/uaccess.h>
2350 extern int max_threads;
2351 @@ -337,6 +338,11 @@
2355 + if (freezer_is_on()) {
2356 + printk(KERN_WARNING "Freezer is on. Refusing to start %s.\n", path);
2360 queue_work(khelper_wq, &sub_info.work);
2361 wait_for_completion(&done);
2362 return sub_info.retval;
2363 diff -ruN linux-2.6.22/kernel/power/Kconfig suspend2-2.2.10-for-2.6.22/kernel/power/Kconfig
2364 --- linux-2.6.22/kernel/power/Kconfig 2007-07-11 22:19:41.000000000 +1000
2365 +++ suspend2-2.2.10-for-2.6.22/kernel/power/Kconfig 2007-07-11 22:25:42.000000000 +1000
2367 suspend/resume routines, but may itself lead to problems, for example
2368 if netconsole is used.
2370 +config PRINTK_NOSAVE
2371 + depends on PM && PM_DEBUG
2372 + bool "Preserve printk data from boot kernel when resuming."
2375 + This option gives printk data and the associated variables the
2376 + attribute __nosave, which means that they will not be saved as
2377 + part of the image. The net effect is that after resuming, your
2378 + dmesg will show the messages from prior to the atomic restore,
2379 + instead of the messages from the resumed kernel. This may be
2380 + useful for debugging hibernation.
2383 bool "Suspend/resume event tracing"
2384 depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
2385 @@ -167,3 +179,174 @@
2386 random kernel OOPSes or reboots that don't seem to be related to
2387 anything, try disabling/enabling this option (or disabling/enabling
2390 +menuconfig SUSPEND2_CORE
2391 + tristate "Suspend2"
2393 + select DYN_PAGEFLAGS
2394 + select HOTPLUG_CPU if SMP
2397 + Suspend2 is the 'new and improved' suspend support.
2399 + See the Suspend2 home page (suspend2.net)
2400 + for FAQs, HOWTOs and other documentation.
2402 + comment "Image Storage (you need at least one allocator)"
2403 + depends on SUSPEND2_CORE
2405 + config SUSPEND2_FILE
2406 + tristate "File Allocator"
2407 + depends on SUSPEND2_CORE
2410 + This option enables support for storing an image in a
2411 + simple file. This should be possible, but we're still
2414 + config SUSPEND2_SWAP
2415 + tristate "Swap Allocator"
2416 + depends on SUSPEND2_CORE
2420 + This option enables support for storing an image in your
2423 + comment "General Options"
2424 + depends on SUSPEND2_CORE
2426 + config SUSPEND2_CRYPTO
2427 + tristate "Compression support"
2428 + depends on SUSPEND2_CORE && CRYPTO
2431 + This option adds support for using cryptoapi compression
2432 + algorithms. Compression is particularly useful as
2433 + the LZF support that comes with the Suspend2 patch can double
2434 + your suspend and resume speed.
2436 + You probably want this, so say Y here.
2438 + comment "No compression support available without Cryptoapi support."
2439 + depends on SUSPEND2_CORE && !CRYPTO
2441 + config SUSPEND2_USERUI
2442 + tristate "Userspace User Interface support"
2443 + depends on SUSPEND2_CORE && NET
2446 + This option enabled support for a userspace based user interface
2447 + to Suspend2, which allows you to have a nice display while suspending
2448 + and resuming, and also enables features such as pressing escape to
2449 + cancel a cycle or interactive debugging.
2451 + config SUSPEND2_DEFAULT_RESUME2
2452 + string "Default resume device name"
2453 + depends on SUSPEND2_CORE
2455 + You normally need to add a resume2= parameter to your lilo.conf or
2456 + equivalent. With this option properly set, the kernel has a value
2457 + to default. No damage will be done if the value is invalid.
2459 + config SUSPEND2_KEEP_IMAGE
2460 + bool "Allow Keep Image Mode"
2461 + depends on SUSPEND2_CORE
2463 + This option allows you to keep and image and reuse it. It is intended
2464 + __ONLY__ for use with systems where all filesystems are mounted read-
2465 + only (kiosks, for example). To use it, compile this option in and boot
2466 + normally. Set the KEEP_IMAGE flag in /sys/power/suspend2 and suspend.
2467 + When you resume, the image will not be removed. You will be unable to turn
2468 + off swap partitions (assuming you are using the swap allocator), but future
2469 + suspends simply do a power-down. The image can be updated using the
2470 + kernel command line parameter suspend_act= to turn off the keep image
2471 + bit. Keep image mode is a little less user friendly on purpose - it
2472 + should not be used without thought!
2474 + config SUSPEND2_REPLACE_SWSUSP
2475 + bool "Replace swsusp by default"
2477 + depends on SUSPEND2_CORE
2479 + Suspend2 can replace swsusp. This option makes that the default state,
2480 + requiring you to echo 0 > /sys/power/suspend2/replace_swsusp if you want
2481 + to use the vanilla kernel functionality. Note that your initrd/ramfs will
2482 + need to do this before trying to resume, too.
2483 + With overriding swsusp enabled, Suspend2 will use both the resume= and
2484 + noresume commandline options _and_ the resume2= and noresume2 ones (for
2485 + compatibility). resume= takes precedence over resume2=. Echoing disk
2486 + to /sys/power/state will start a Suspend2 cycle. If resume= doesn't
2487 + specify an allocator and both the swap and file allocators are compiled in,
2488 + the swap allocator will be used by default.
2490 + config SUSPEND2_CLUSTER
2491 + tristate "Cluster support"
2493 + depends on SUSPEND2_CORE && NET && BROKEN
2495 + Support for linking multiple machines in a cluster so that they suspend
2496 + and resume together.
2498 + config SUSPEND2_DEFAULT_CLUSTER_MASTER
2499 + string "Default cluster master address/port"
2500 + depends on SUSPEND2_CLUSTER
2502 + If this machine will be the master, simply enter a port on which to
2503 + listen for slaves.
2504 + If this machine will be a slave, enter the ip address and port on
2505 + which the master listens with a colon separating them.
2506 + If no value is set here, cluster support will be disabled by default.
2508 + config SUSPEND2_CHECKSUM
2509 + bool "Checksum pageset2"
2510 + depends on SUSPEND2_CORE
2512 + select CRYPTO_ALGAPI
2515 + Adds support for checksumming pageset2 pages, to ensure you really get an
2516 + atomic copy. Should not normally be needed, but here for verification and
2517 + diagnostic purposes.
2519 +config SUSPEND_SHARED
2521 + depends on SUSPEND2_CORE || SOFTWARE_SUSPEND
2524 +config SUSPEND2_USERUI_EXPORTS
2526 + depends on SUSPEND2_USERUI=m
2529 +config SUSPEND2_SWAP_EXPORTS
2531 + depends on SUSPEND2_SWAP=m
2534 +config SUSPEND2_FILE_EXPORTS
2536 + depends on SUSPEND2_FILE=m
2539 +config SUSPEND2_CRYPTO_EXPORTS
2541 + depends on SUSPEND2_CRYPTO=m
2544 +config SUSPEND2_CORE_EXPORTS
2546 + depends on SUSPEND2_CORE=m
2549 +config SUSPEND2_EXPORTS
2551 + depends on SUSPEND2_SWAP_EXPORTS || SUSPEND2_FILE_EXPORTS || \
2552 + SUSPEND2_CRYPTO_EXPORTS || SUSPEND2_CLUSTER=m || \
2553 + SUSPEND2_USERUI_EXPORTS
2558 + depends on SUSPEND2_CORE!=n
2560 diff -ruN linux-2.6.22/kernel/power/Makefile suspend2-2.2.10-for-2.6.22/kernel/power/Makefile
2561 --- linux-2.6.22/kernel/power/Makefile 2007-07-11 22:19:41.000000000 +1000
2562 +++ suspend2-2.2.10-for-2.6.22/kernel/power/Makefile 2007-07-11 22:25:42.000000000 +1000
2565 obj-y := main.o process.o console.o
2566 obj-$(CONFIG_PM_LEGACY) += pm.o
2567 -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o snapshot.o swap.o user.o
2568 +obj-$(CONFIG_SUSPEND_SHARED) += snapshot.o
2570 +suspend_core-objs := modules.o sysfs.o suspend.o \
2571 + io.o pagedir.o prepare_image.o \
2572 + extent.o pageflags.o ui.o \
2573 + power_off.o atomic_copy.o
2575 +obj-$(CONFIG_SUSPEND2) += suspend2_builtin.o
2577 +ifdef CONFIG_SUSPEND2_CHECKSUM
2578 +suspend_core-objs += checksum.o
2582 +suspend_core-objs += storage.o netlink.o
2585 +obj-$(CONFIG_SUSPEND2_CORE) += suspend_core.o
2586 +obj-$(CONFIG_SUSPEND2_CRYPTO) += suspend_compress.o
2588 +obj-$(CONFIG_SUSPEND2_SWAP) += suspend_block_io.o suspend_swap.o
2589 +obj-$(CONFIG_SUSPEND2_FILE) += suspend_block_io.o suspend_file.o
2590 +obj-$(CONFIG_SUSPEND2_CLUSTER) += cluster.o
2592 +obj-$(CONFIG_SUSPEND2_USERUI) += suspend_userui.o
2594 +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o swap.o user.o
2596 obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
2597 diff -ruN linux-2.6.22/kernel/power/atomic_copy.c suspend2-2.2.10-for-2.6.22/kernel/power/atomic_copy.c
2598 --- linux-2.6.22/kernel/power/atomic_copy.c 1970-01-01 10:00:00.000000000 +1000
2599 +++ suspend2-2.2.10-for-2.6.22/kernel/power/atomic_copy.c 2007-07-11 22:25:42.000000000 +1000
2602 + * kernel/power/atomic_copy.c
2604 + * Copyright 2004-2007 Nigel Cunningham (nigel at suspend2 net)
2605 + * Copyright (C) 2006 Red Hat, inc.
2607 + * Distributed under GPLv2.
2609 + * Routines for doing the atomic save/restore.
2612 +#include <linux/suspend.h>
2613 +#include <linux/highmem.h>
2614 +#include <linux/cpu.h>
2615 +#include <linux/freezer.h>
2616 +#include <linux/console.h>
2617 +#include "suspend.h"
2618 +#include "storage.h"
2619 +#include "power_off.h"
2623 +#include "prepare_image.h"
2624 +#include "pageflags.h"
2625 +#include "checksum.h"
2626 +#include "suspend2_builtin.h"
2628 +int extra_pd1_pages_used;
2631 + * Highmem related functions (x86 only).
2634 +#ifdef CONFIG_HIGHMEM
2637 + * copyback_high: Restore highmem pages.
2639 + * Highmem data and pbe lists are/can be stored in highmem.
2640 + * The format is slightly different to the lowmem pbe lists
2641 + * used for the assembly code: the last pbe in each page is
2642 + * a struct page * instead of struct pbe *, pointing to the
2643 + * next page where pbes are stored (or NULL if happens to be
2644 + * the end of the list). Since we don't want to generate
2645 + * unnecessary deltas against swsusp code, we use a cast
2646 + * instead of a union.
2649 +static void copyback_high(void)
2651 + struct page * pbe_page = (struct page *) restore_highmem_pblist;
2652 + struct pbe *this_pbe, *first_pbe;
2653 + unsigned long *origpage, *copypage;
2654 + int pbe_index = 1;
2659 + this_pbe = (struct pbe *) kmap_atomic(pbe_page, KM_BOUNCE_READ);
2660 + first_pbe = this_pbe;
2662 + while (this_pbe) {
2663 + int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
2665 + origpage = kmap_atomic((struct page *) this_pbe->orig_address,
2667 + copypage = kmap_atomic((struct page *) this_pbe->address,
2670 + while (loop >= 0) {
2671 + *(origpage + loop) = *(copypage + loop);
2675 + kunmap_atomic(origpage, KM_BIO_DST_IRQ);
2676 + kunmap_atomic(copypage, KM_BIO_SRC_IRQ);
2678 + if (!this_pbe->next)
2681 + if (pbe_index < PBES_PER_PAGE) {
2685 + pbe_page = (struct page *) this_pbe->next;
2686 + kunmap_atomic(first_pbe, KM_BOUNCE_READ);
2689 + this_pbe = (struct pbe *) kmap_atomic(pbe_page,
2691 + first_pbe = this_pbe;
2695 + kunmap_atomic(first_pbe, KM_BOUNCE_READ);
2698 +#else /* CONFIG_HIGHMEM */
2699 +void copyback_high(void) { }
2703 + * free_pbe_list: Free page backup entries used by the atomic copy code.
2705 + * Normally, this function isn't used. If, however, we need to abort before
2706 + * doing the atomic copy, we use this to free the pbes previously allocated.
2708 +static void free_pbe_list(struct pbe **list, int highmem)
2712 + struct pbe *free_pbe, *next_page = NULL;
2713 + struct page *page;
2716 + page = (struct page *) *list;
2717 + free_pbe = (struct pbe *) kmap(page);
2719 + page = virt_to_page(*list);
2723 + for (i = 0; i < PBES_PER_PAGE; i++) {
2727 + __free_page(free_pbe->address);
2729 + free_page((unsigned long) free_pbe->address);
2730 + free_pbe = free_pbe->next;
2735 + next_page = free_pbe;
2739 + next_page = free_pbe;
2742 + __free_page(page);
2743 + *list = (struct pbe *) next_page;
2748 + * copyback_post: Post atomic-restore actions.
2750 + * After doing the atomic restore, we have a few more things to do:
2751 + * 1) We want to retain some values across the restore, so we now copy
2752 + * these from the nosave variables to the normal ones.
2753 + * 2) Set the status flags.
2754 + * 3) Resume devices.
2755 + * 4) Tell userui so it can redraw & restore settings.
2756 + * 5) Reread the page cache.
2759 +void copyback_post(void)
2763 + suspend_action = suspend2_nosave_state1;
2764 + suspend_debug_state = suspend2_nosave_state2;
2765 + console_loglevel = suspend2_nosave_state3;
2767 + for (loop = 0; loop < 4; loop++)
2768 + suspend_io_time[loop/2][loop%2] =
2769 + suspend2_nosave_io_speed[loop/2][loop%2];
2771 + set_suspend_state(SUSPEND_NOW_RESUMING);
2772 + set_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
2774 + if (suspend_activate_storage(1))
2775 + panic("Failed to reactivate our storage.");
2777 + suspend_ui_post_atomic_restore();
2779 + suspend_cond_pause(1, "About to reload secondary pagedir.");
2781 + if (read_pageset2(0))
2782 + panic("Unable to successfully reread the page cache.");
2784 + clear_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
2788 + * suspend_copy_pageset1: Do the atomic copy of pageset1.
2790 + * Make the atomic copy of pageset1. We can't use copy_page (as we once did)
2791 + * because we can't be sure what side effects it has. On my old Duron, with
2792 + * 3DNOW, kernel_fpu_begin increments preempt count, making our preempt
2793 + * count at resume time 4 instead of 3.
2795 + * We don't want to call kmap_atomic unconditionally because it has the side
2796 + * effect of incrementing the preempt count, which will leave it one too high
2797 + * post resume (the page containing the preempt count will be copied after
2798 + * its incremented. This is essentially the same problem.
2801 +void suspend_copy_pageset1(void)
2804 + unsigned long source_index, dest_index;
2806 + source_index = get_next_bit_on(pageset1_map, max_pfn + 1);
2807 + dest_index = get_next_bit_on(pageset1_copy_map, max_pfn + 1);
2809 + for (i = 0; i < pagedir1.size; i++) {
2810 + unsigned long *origvirt, *copyvirt;
2811 + struct page *origpage, *copypage;
2812 + int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
2814 + origpage = pfn_to_page(source_index);
2815 + copypage = pfn_to_page(dest_index);
2817 + origvirt = PageHighMem(origpage) ?
2818 + kmap_atomic(origpage, KM_USER0) :
2819 + page_address(origpage);
2821 + copyvirt = PageHighMem(copypage) ?
2822 + kmap_atomic(copypage, KM_USER1) :
2823 + page_address(copypage);
2825 + while (loop >= 0) {
2826 + *(copyvirt + loop) = *(origvirt + loop);
2830 + if (PageHighMem(origpage))
2831 + kunmap_atomic(origvirt, KM_USER0);
2832 + else if (suspend2_faulted) {
2833 + printk("%p (%lu) being unmapped after faulting during atomic copy.\n", origpage, source_index);
2834 + kernel_map_pages(origpage, 1, 0);
2835 + clear_suspend2_fault();
2838 + if (PageHighMem(copypage))
2839 + kunmap_atomic(copyvirt, KM_USER1);
2841 + source_index = get_next_bit_on(pageset1_map, source_index);
2842 + dest_index = get_next_bit_on(pageset1_copy_map, dest_index);
2847 + * __suspend_post_context_save: Steps after saving the cpu context.
2849 + * Steps taken after saving the CPU state to make the actual
2852 + * Called from swsusp_save in snapshot.c via suspend_post_context_save.
2855 +int __suspend_post_context_save(void)
2857 + int old_ps1_size = pagedir1.size;
2859 + calculate_check_checksums(1);
2861 + free_checksum_pages();
2863 + suspend_recalculate_image_contents(1);
2865 + extra_pd1_pages_used = pagedir1.size - old_ps1_size;
2867 + if (extra_pd1_pages_used > extra_pd1_pages_allowance) {
2868 + printk("Pageset1 has grown by %d pages. "
2869 + "extra_pages_allowance is currently only %d.\n",
2870 + pagedir1.size - old_ps1_size,
2871 + extra_pd1_pages_allowance);
2872 + set_result_state(SUSPEND_ABORTED);
2873 + set_result_state(SUSPEND_EXTRA_PAGES_ALLOW_TOO_SMALL);
2877 + if (!test_action_state(SUSPEND_TEST_FILTER_SPEED) &&
2878 + !test_action_state(SUSPEND_TEST_BIO))
2879 + suspend_copy_pageset1();
2885 + * suspend2_suspend: High level code for doing the atomic copy.
2887 + * High-level code which prepares to do the atomic copy. Loosely based
2888 + * on the swsusp version, but with the following twists:
2889 + * - We set suspend2_running so the swsusp code uses our code paths.
2890 + * - We give better feedback regarding what goes wrong if there is a problem.
2891 + * - We use an extra function to call the assembly, just in case this code
2892 + * is in a module (return address).
2895 +int suspend2_suspend(void)
2899 + suspend2_running = 1; /* For the swsusp code we use :< */
2901 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2902 + pm_prepare_console();
2904 + if ((error = arch_prepare_suspend()))
2907 + local_irq_disable();
2909 + /* At this point, device_suspend() has been called, but *not*
2910 + * device_power_down(). We *must* device_power_down() now.
2911 + * Otherwise, drivers for some devices (e.g. interrupt controllers)
2912 + * become desynchronized with the actual state of the hardware
2913 + * at resume time, and evil weirdness ensues.
2916 + if ((error = device_power_down(PMSG_FREEZE))) {
2917 + set_result_state(SUSPEND_DEVICE_REFUSED);
2918 + set_result_state(SUSPEND_ABORTED);
2919 + printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
2923 + error = suspend2_lowlevel_builtin();
2925 + if (!suspend2_in_suspend)
2928 + device_power_up();
2930 + local_irq_enable();
2931 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2932 + pm_restore_console();
2934 + suspend2_running = 0;
2939 + * suspend_atomic_restore: Prepare to do the atomic restore.
2941 + * Get ready to do the atomic restore. This part gets us into the same
2942 + * state we are in prior to do calling do_suspend2_lowlevel while
2943 + * suspending: hot-unplugging secondary cpus and freeze processes,
2944 + * before starting the thread that will do the restore.
2947 +int suspend_atomic_restore(void)
2951 + suspend2_running = 1;
2953 + suspend_prepare_status(DONT_CLEAR_BAR, "Prepare console");
2955 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2956 + pm_prepare_console();
2958 + suspend_prepare_status(DONT_CLEAR_BAR, "Device suspend.");
2960 + suspend_console();
2961 + if ((error = device_suspend(PMSG_PRETHAW))) {
2962 + printk("Some devices failed to suspend\n");
2963 + goto device_resume;
2966 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG)) {
2967 + suspend_prepare_status(DONT_CLEAR_BAR, "Disable nonboot cpus.");
2968 + if (disable_nonboot_cpus()) {
2969 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
2970 + set_result_state(SUSPEND_ABORTED);
2971 + goto device_resume;
2975 + suspend_prepare_status(DONT_CLEAR_BAR, "Atomic restore preparation");
2977 + suspend2_nosave_state1 = suspend_action;
2978 + suspend2_nosave_state2 = suspend_debug_state;
2979 + suspend2_nosave_state3 = console_loglevel;
2981 + for (loop = 0; loop < 4; loop++)
2982 + suspend2_nosave_io_speed[loop/2][loop%2] =
2983 + suspend_io_time[loop/2][loop%2];
2984 + memcpy(suspend2_nosave_commandline, saved_command_line, COMMAND_LINE_SIZE);
2988 + local_irq_disable();
2990 + if (device_power_down(PMSG_FREEZE)) {
2991 + printk(KERN_ERR "Some devices failed to power down. Very bad.\n");
2992 + goto device_power_up;
2995 + /* We'll ignore saved state, but this gets preempt count (etc) right */
2996 + save_processor_state();
2998 + error = swsusp_arch_resume();
3000 + * Code below is only ever reached in case of failure. Otherwise
3001 + * execution continues at place where swsusp_arch_suspend was called.
3003 + * We don't know whether it's safe to continue (this shouldn't happen),
3004 + * so lets err on the side of caution.
3009 + device_power_up();
3010 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
3011 + enable_nonboot_cpus();
3015 + free_pbe_list(&restore_pblist, 0);
3016 +#ifdef CONFIG_HIGHMEM
3017 + free_pbe_list(&restore_highmem_pblist, 1);
3019 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
3020 + pm_restore_console();
3021 + suspend2_running = 0;
3024 diff -ruN linux-2.6.22/kernel/power/block_io.h suspend2-2.2.10-for-2.6.22/kernel/power/block_io.h
3025 --- linux-2.6.22/kernel/power/block_io.h 1970-01-01 10:00:00.000000000 +1000
3026 +++ suspend2-2.2.10-for-2.6.22/kernel/power/block_io.h 2007-07-11 22:25:42.000000000 +1000
3029 + * kernel/power/block_io.h
3031 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
3032 + * Copyright (C) 2006 Red Hat, inc.
3034 + * Distributed under GPLv2.
3036 + * This file contains declarations for functions exported from
3037 + * block_io.c, which contains low level io functions.
3040 +#include <linux/buffer_head.h>
3041 +#include "extent.h"
3043 +struct suspend_bdev_info {
3044 + struct block_device *bdev;
3047 + int blocks_per_page;
3051 + * Our exported interface so the swapwriter and filewriter don't
3052 + * need these functions duplicated.
3054 +struct suspend_bio_ops {
3055 + int (*bdev_page_io) (int rw, struct block_device *bdev, long pos,
3056 + struct page *page);
3057 + void (*check_io_stats) (void);
3058 + void (*reset_io_stats) (void);
3059 + void (*finish_all_io) (void);
3060 + int (*forward_one_page) (void);
3061 + void (*set_extra_page_forward) (void);
3062 + void (*set_devinfo) (struct suspend_bdev_info *info);
3063 + int (*read_chunk) (unsigned long *index, struct page *buffer_page,
3064 + unsigned int *buf_size, int sync);
3065 + int (*write_chunk) (unsigned long index, struct page *buffer_page,
3066 + unsigned int buf_size);
3067 + void (*read_header_init) (void);
3068 + int (*rw_header_chunk) (int rw, struct suspend_module_ops *owner,
3069 + char *buffer, int buffer_size);
3070 + int (*write_header_chunk_finish) (void);
3071 + int (*rw_init) (int rw, int stream_number);
3072 + int (*rw_cleanup) (int rw);
3075 +extern struct suspend_bio_ops suspend_bio_ops;
3077 +extern char *suspend_writer_buffer;
3078 +extern int suspend_writer_buffer_posn;
3079 +extern int suspend_read_fd;
3080 +extern struct extent_iterate_saved_state suspend_writer_posn_save[3];
3081 +extern struct extent_iterate_state suspend_writer_posn;
3082 +extern int suspend_header_bytes_used;
3083 diff -ruN linux-2.6.22/kernel/power/checksum.c suspend2-2.2.10-for-2.6.22/kernel/power/checksum.c
3084 --- linux-2.6.22/kernel/power/checksum.c 1970-01-01 10:00:00.000000000 +1000
3085 +++ suspend2-2.2.10-for-2.6.22/kernel/power/checksum.c 2007-07-11 22:25:42.000000000 +1000
3088 + * kernel/power/checksum.c
3090 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3091 + * Copyright (C) 2006 Red Hat, inc.
3093 + * This file is released under the GPLv2.
3095 + * This file contains data checksum routines for suspend2,
3096 + * using cryptoapi. They are used to locate any modifications
3097 + * made to pageset 2 while we're saving it.
3100 +#include <linux/suspend.h>
3101 +#include <linux/module.h>
3102 +#include <linux/highmem.h>
3103 +#include <linux/vmalloc.h>
3104 +#include <linux/crypto.h>
3105 +#include <linux/scatterlist.h>
3107 +#include "suspend.h"
3108 +#include "modules.h"
3111 +#include "pageflags.h"
3112 +#include "checksum.h"
3113 +#include "pagedir.h"
3115 +static struct suspend_module_ops suspend_checksum_ops;
3117 +/* Constant at the mo, but I might allow tuning later */
3118 +static char suspend_checksum_name[32] = "md5";
3119 +/* Bytes per checksum */
3120 +#define CHECKSUM_SIZE (128 / 8)
3122 +#define CHECKSUMS_PER_PAGE ((PAGE_SIZE - sizeof(void *)) / CHECKSUM_SIZE)
3124 +static struct crypto_hash *suspend_checksum_transform;
3125 +static struct hash_desc desc;
3126 +static int pages_allocated;
3127 +static unsigned long page_list;
3129 +static int suspend_num_resaved = 0;
3132 +#define PRINTK(a, b...) do { } while(0)
3134 +#define PRINTK(a, b...) do { printk(a, ##b); } while(0)
3137 +/* ---- Local buffer management ---- */
3140 + * suspend_checksum_cleanup
3142 + * Frees memory allocated for our labours.
3144 +static void suspend_checksum_cleanup(int ending_cycle)
3146 + if (ending_cycle && suspend_checksum_transform) {
3147 + crypto_free_hash(suspend_checksum_transform);
3148 + suspend_checksum_transform = NULL;
3154 + * suspend_crypto_prepare
3156 + * Prepare to do some work by allocating buffers and transforms.
3157 + * Returns: Int: Zero. Even if we can't set up checksum, we still
3158 + * seek to suspend.
3160 +static int suspend_checksum_prepare(int starting_cycle)
3162 + if (!starting_cycle || !suspend_checksum_ops.enabled)
3165 + if (!*suspend_checksum_name) {
3166 + printk("Suspend2: No checksum algorithm name set.\n");
3170 + suspend_checksum_transform = crypto_alloc_hash(suspend_checksum_name, 0, 0);
3171 + if (IS_ERR(suspend_checksum_transform)) {
3172 + printk("Suspend2: Failed to initialise the %s checksum algorithm: %ld.\n",
3173 + suspend_checksum_name,
3174 + (long) suspend_checksum_transform);
3175 + suspend_checksum_transform = NULL;
3179 + desc.tfm = suspend_checksum_transform;
3185 +static int suspend_print_task_if_using_page(struct task_struct *t, struct page *seeking)
3187 + struct vm_area_struct *vma;
3188 + struct mm_struct *mm;
3191 + mm = t->active_mm;
3193 + if (!mm || !mm->mmap) return 0;
3195 + /* Don't try to take the sem when processes are frozen,
3196 + * drivers are suspended and irqs are disabled. We're
3197 + * not racing with anything anyway. */
3198 + if (!irqs_disabled())
3199 + down_read(&mm->mmap_sem);
3201 + for (vma = mm->mmap; vma; vma = vma->vm_next) {
3202 + if (vma->vm_flags & VM_PFNMAP)
3204 + if (vma->vm_start) {
3205 + unsigned long posn;
3206 + for (posn = vma->vm_start; posn < vma->vm_end;
3207 + posn += PAGE_SIZE) {
3208 + struct page *page =
3209 + follow_page(vma, posn, 0);
3210 + if (page == seeking) {
3211 + printk("%s(%d)", t->comm, t->pid);
3220 + if (!irqs_disabled())
3221 + up_read(&mm->mmap_sem);
3226 +static void print_tasks_using_page(struct page *seeking)
3228 + struct task_struct *p;
3230 + read_lock(&tasklist_lock);
3231 + for_each_process(p) {
3232 + if (suspend_print_task_if_using_page(p, seeking))
3235 + read_unlock(&tasklist_lock);
3239 + * suspend_checksum_print_debug_stats
3240 + * @buffer: Pointer to a buffer into which the debug info will be printed.
3241 + * @size: Size of the buffer.
3243 + * Print information to be recorded for debugging purposes into a buffer.
3244 + * Returns: Number of characters written to the buffer.
3247 +static int suspend_checksum_print_debug_stats(char *buffer, int size)
3251 + if (!suspend_checksum_ops.enabled)
3252 + return snprintf_used(buffer, size,
3253 + "- Checksumming disabled.\n");
3255 + len = snprintf_used(buffer, size, "- Checksum method is '%s'.\n",
3256 + suspend_checksum_name);
3257 + len+= snprintf_used(buffer + len, size - len,
3258 + " %d pages resaved in atomic copy.\n", suspend_num_resaved);
3262 +static int suspend_checksum_storage_needed(void)
3264 + if (suspend_checksum_ops.enabled)
3265 + return strlen(suspend_checksum_name) + sizeof(int) + 1;
3271 + * suspend_checksum_save_config_info
3272 + * @buffer: Pointer to a buffer of size PAGE_SIZE.
3274 + * Save informaton needed when reloading the image at resume time.
3275 + * Returns: Number of bytes used for saving our data.
3277 +static int suspend_checksum_save_config_info(char *buffer)
3279 + int namelen = strlen(suspend_checksum_name) + 1;
3282 + *((unsigned int *) buffer) = namelen;
3283 + strncpy(buffer + sizeof(unsigned int), suspend_checksum_name,
3285 + total_len = sizeof(unsigned int) + namelen;
3289 +/* suspend_checksum_load_config_info
3290 + * @buffer: Pointer to the start of the data.
3291 + * @size: Number of bytes that were saved.
3293 + * Description: Reload information needed for dechecksuming the image at
3296 +static void suspend_checksum_load_config_info(char *buffer, int size)
3300 + namelen = *((unsigned int *) (buffer));
3301 + strncpy(suspend_checksum_name, buffer + sizeof(unsigned int),
3307 + * Free Checksum Memory
3310 +void free_checksum_pages(void)
3312 + PRINTK("Freeing %d checksum pages.\n", pages_allocated);
3313 + while (pages_allocated) {
3314 + unsigned long next = *((unsigned long *) page_list);
3315 + PRINTK("Page %3d is at %lx and points to %lx.\n", pages_allocated, page_list, next);
3316 + ClearPageNosave(virt_to_page(page_list));
3317 + free_page((unsigned long) page_list);
3319 + pages_allocated--;
3324 + * Allocate Checksum Memory
3327 +int allocate_checksum_pages(void)
3329 + int pages_needed = DIV_ROUND_UP(pagedir2.size, CHECKSUMS_PER_PAGE);
3331 + if (!suspend_checksum_ops.enabled)
3334 + PRINTK("Need %d checksum pages for %ld pageset2 pages.\n", pages_needed, pagedir2.size);
3335 + while (pages_allocated < pages_needed) {
3336 + unsigned long *new_page =
3337 + (unsigned long *) get_zeroed_page(GFP_ATOMIC);
3340 + SetPageNosave(virt_to_page(new_page));
3341 + (*new_page) = page_list;
3342 + page_list = (unsigned long) new_page;
3343 + pages_allocated++;
3344 + PRINTK("Page %3d is at %lx and points to %lx.\n", pages_allocated, page_list, *((unsigned long *) page_list));
3351 +static void print_checksum(char *buf, int size)
3355 + for (index = 0; index < size; index++)
3356 + printk("%x ", buf[index]);
3363 + * Calculate checksums
3366 +void calculate_check_checksums(int check)
3368 + int pfn, index = 0;
3369 + unsigned long next_page, this_checksum = 0;
3370 + struct scatterlist sg[2];
3371 + char current_checksum[CHECKSUM_SIZE];
3373 + if (!suspend_checksum_ops.enabled)
3376 + next_page = (unsigned long) page_list;
3379 + suspend_num_resaved = 0;
3381 + BITMAP_FOR_EACH_SET(pageset2_map, pfn) {
3383 + if (index % CHECKSUMS_PER_PAGE) {
3384 + this_checksum += CHECKSUM_SIZE;
3386 + this_checksum = next_page + sizeof(void *);
3387 + next_page = *((unsigned long *) next_page);
3389 + PRINTK("Put checksum for page %3d %p in %lx.\n", index, page_address(pfn_to_page(pfn)), this_checksum);
3390 + sg_set_buf(&sg[0], page_address(pfn_to_page(pfn)), PAGE_SIZE);
3392 + ret = crypto_hash_digest(&desc, sg,
3393 + PAGE_SIZE, current_checksum);
3394 + if (memcmp(current_checksum, (char *) this_checksum, CHECKSUM_SIZE)) {
3395 + SetPageResave(pfn_to_page(pfn));
3396 + printk("Page %d changed. Saving in atomic copy."
3397 + "Processes using it:", pfn);
3398 + print_tasks_using_page(pfn_to_page(pfn));
3400 + suspend_num_resaved++;
3401 + if (test_action_state(SUSPEND_ABORT_ON_RESAVE_NEEDED))
3402 + set_result_state(SUSPEND_ABORTED);
3405 + ret = crypto_hash_digest(&desc, sg,
3406 + PAGE_SIZE, (char *) this_checksum);
3408 + printk("Digest failed. Returned %d.\n", ret);
3415 +static struct suspend_sysfs_data sysfs_params[] = {
3416 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
3417 + SYSFS_INT(&suspend_checksum_ops.enabled, 0, 1, 0)
3420 + { SUSPEND2_ATTR("abort_if_resave_needed", SYSFS_RW),
3421 + SYSFS_BIT(&suspend_action, SUSPEND_ABORT_ON_RESAVE_NEEDED, 0)
3428 +static struct suspend_module_ops suspend_checksum_ops = {
3429 + .type = MISC_MODULE,
3430 + .name = "Checksumming",
3431 + .directory = "checksum",
3432 + .module = THIS_MODULE,
3433 + .initialise = suspend_checksum_prepare,
3434 + .cleanup = suspend_checksum_cleanup,
3435 + .print_debug_info = suspend_checksum_print_debug_stats,
3436 + .save_config_info = suspend_checksum_save_config_info,
3437 + .load_config_info = suspend_checksum_load_config_info,
3438 + .storage_needed = suspend_checksum_storage_needed,
3440 + .sysfs_data = sysfs_params,
3441 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
3444 +/* ---- Registration ---- */
3445 +int s2_checksum_init(void)
3447 + int result = suspend_register_module(&suspend_checksum_ops);
3449 + /* Disabled by default */
3450 + suspend_checksum_ops.enabled = 0;
3454 +void s2_checksum_exit(void)
3456 + suspend_unregister_module(&suspend_checksum_ops);
3458 diff -ruN linux-2.6.22/kernel/power/checksum.h suspend2-2.2.10-for-2.6.22/kernel/power/checksum.h
3459 --- linux-2.6.22/kernel/power/checksum.h 1970-01-01 10:00:00.000000000 +1000
3460 +++ suspend2-2.2.10-for-2.6.22/kernel/power/checksum.h 2007-07-11 22:25:42.000000000 +1000
3463 + * kernel/power/checksum.h
3465 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3466 + * Copyright (C) 2006 Red Hat, inc.
3468 + * This file is released under the GPLv2.
3470 + * This file contains data checksum routines for suspend2,
3471 + * using cryptoapi. They are used to locate any modifications
3472 + * made to pageset 2 while we're saving it.
3475 +#if defined(CONFIG_SUSPEND2_CHECKSUM)
3476 +extern int s2_checksum_init(void);
3477 +extern void s2_checksum_exit(void);
3478 +void calculate_check_checksums(int check);
3479 +int allocate_checksum_pages(void);
3480 +void free_checksum_pages(void);
3482 +static inline int s2_checksum_init(void) { return 0; }
3483 +static inline void s2_checksum_exit(void) { }
3484 +static inline void calculate_check_checksums(int check) { };
3485 +static inline int allocate_checksum_pages(void) { return 0; };
3486 +static inline void free_checksum_pages(void) { };
3489 diff -ruN linux-2.6.22/kernel/power/cluster.c suspend2-2.2.10-for-2.6.22/kernel/power/cluster.c
3490 --- linux-2.6.22/kernel/power/cluster.c 1970-01-01 10:00:00.000000000 +1000
3491 +++ suspend2-2.2.10-for-2.6.22/kernel/power/cluster.c 2007-07-11 22:25:42.000000000 +1000
3494 + * kernel/power/cluster.c
3496 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3498 + * This file is released under the GPLv2.
3500 + * This file contains routines for cluster hibernation support.
3504 +#include <linux/suspend.h>
3505 +#include <linux/module.h>
3507 +#include "suspend.h"
3508 +#include "modules.h"
3512 +static char suspend_cluster_master[63] = CONFIG_SUSPEND2_DEFAULT_CLUSTER_MASTER;
3514 +static struct suspend_module_ops suspend_cluster_ops;
3516 +/* suspend_cluster_print_debug_stats
3518 + * Description: Print information to be recorded for debugging purposes into a
3520 + * Arguments: buffer: Pointer to a buffer into which the debug info will be
3522 + * size: Size of the buffer.
3523 + * Returns: Number of characters written to the buffer.
3525 +static int suspend_cluster_print_debug_stats(char *buffer, int size)
3529 + if (strlen(suspend_cluster_master))
3530 + len = snprintf_used(buffer, size, "- Cluster master is '%s'.\n",
3531 + suspend_cluster_master);
3533 + len = snprintf_used(buffer, size, "- Cluster support is disabled.\n");
3537 +/* cluster_memory_needed
3539 + * Description: Tell the caller how much memory we need to operate during
3541 + * Returns: Unsigned long. Maximum number of bytes of memory required for
3544 +static int suspend_cluster_memory_needed(void)
3549 +static int suspend_cluster_storage_needed(void)
3551 + return 1 + strlen(suspend_cluster_master);
3554 +/* suspend_cluster_save_config_info
3556 + * Description: Save informaton needed when reloading the image at resume time.
3557 + * Arguments: Buffer: Pointer to a buffer of size PAGE_SIZE.
3558 + * Returns: Number of bytes used for saving our data.
3560 +static int suspend_cluster_save_config_info(char *buffer)
3562 + strcpy(buffer, suspend_cluster_master);
3563 + return strlen(suspend_cluster_master + 1);
3566 +/* suspend_cluster_load_config_info
3568 + * Description: Reload information needed for declustering the image at
3570 + * Arguments: Buffer: Pointer to the start of the data.
3571 + * Size: Number of bytes that were saved.
3573 +static void suspend_cluster_load_config_info(char *buffer, int size)
3575 + strncpy(suspend_cluster_master, buffer, size);
3580 + * data for our sysfs entries.
3582 +static struct suspend_sysfs_data sysfs_params[] = {
3584 + SUSPEND2_ATTR("master", SYSFS_RW),
3585 + SYSFS_STRING(suspend_cluster_master, 63, SYSFS_SM_NOT_NEEDED)
3589 + SUSPEND2_ATTR("enabled", SYSFS_RW),
3590 + SYSFS_INT(&suspend_cluster_ops.enabled, 0, 1)
3598 +static struct suspend_module_ops suspend_cluster_ops = {
3599 + .type = FILTER_MODULE,
3600 + .name = "Cluster",
3601 + .directory = "cluster",
3602 + .module = THIS_MODULE,
3603 + .memory_needed = suspend_cluster_memory_needed,
3604 + .print_debug_info = suspend_cluster_print_debug_stats,
3605 + .save_config_info = suspend_cluster_save_config_info,
3606 + .load_config_info = suspend_cluster_load_config_info,
3607 + .storage_needed = suspend_cluster_storage_needed,
3609 + .sysfs_data = sysfs_params,
3610 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
3613 +/* ---- Registration ---- */
3616 +#warning Module set.
3617 +#define INIT static __init
3618 +#define EXIT static __exit
3624 +INIT int s2_cluster_init(void)
3626 + int temp = suspend_register_module(&suspend_cluster_ops);
3628 + if (!strlen(suspend_cluster_master))
3629 + suspend_cluster_ops.enabled = 0;
3633 +EXIT void s2_cluster_exit(void)
3635 + suspend_unregister_module(&suspend_cluster_ops);
3639 +MODULE_LICENSE("GPL");
3640 +module_init(s2_cluster_init);
3641 +module_exit(s2_cluster_exit);
3642 +MODULE_AUTHOR("Nigel Cunningham");
3643 +MODULE_DESCRIPTION("Cluster Support for Suspend2");
3645 diff -ruN linux-2.6.22/kernel/power/cluster.h suspend2-2.2.10-for-2.6.22/kernel/power/cluster.h
3646 --- linux-2.6.22/kernel/power/cluster.h 1970-01-01 10:00:00.000000000 +1000
3647 +++ suspend2-2.2.10-for-2.6.22/kernel/power/cluster.h 2007-07-11 22:25:42.000000000 +1000
3650 + * kernel/power/cluster.h
3652 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3653 + * Copyright (C) 2006 Red Hat, inc.
3655 + * This file is released under the GPLv2.
3658 +#ifdef CONFIG_SUSPEND2_CLUSTER
3659 +extern int s2_cluster_init(void);
3660 +extern void s2_cluster_exit(void);
3662 +static inline int s2_cluster_init(void) { return 0; }
3663 +static inline void s2_cluster_exit(void) { }
3666 diff -ruN linux-2.6.22/kernel/power/disk.c suspend2-2.2.10-for-2.6.22/kernel/power/disk.c
3667 --- linux-2.6.22/kernel/power/disk.c 2007-07-11 22:19:41.000000000 +1000
3668 +++ suspend2-2.2.10-for-2.6.22/kernel/power/disk.c 2007-07-11 22:25:42.000000000 +1000
3673 +#include "suspend.h"
3674 +#include "suspend2_builtin.h"
3676 static int noresume = 0;
3677 char resume_file[256] = CONFIG_PM_STD_PARTITION;
3678 @@ -152,6 +154,11 @@
3682 +#ifdef CONFIG_SUSPEND2
3683 + if (test_action_state(SUSPEND_REPLACE_SWSUSP))
3684 + return suspend2_try_suspend(1);
3687 /* The snapshot device should not be opened while we're running */
3688 if (!atomic_add_unless(&snapshot_device_available, -1, 0))
3690 @@ -250,10 +257,22 @@
3694 -static int software_resume(void)
3695 +int software_resume(void)
3699 + resume_attempted = 1;
3701 +#ifdef CONFIG_SUSPEND2
3703 + * We can't know (until an image header - if any - is loaded), whether
3704 + * we did override swsusp. We therefore ensure that both are tried.
3706 + if (test_action_state(SUSPEND_REPLACE_SWSUSP))
3707 + printk("Replacing swsusp.\n");
3708 + suspend2_try_resume();
3711 mutex_lock(&pm_mutex);
3712 if (!swsusp_resume_device) {
3713 if (!strlen(resume_file)) {
3718 -late_initcall(software_resume);
3721 static const char * const hibernation_modes[] = {
3722 [HIBERNATION_PLATFORM] = "platform",
3723 [HIBERNATION_SHUTDOWN] = "shutdown",
3725 static int __init noresume_setup(char *str)
3728 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
3732 diff -ruN linux-2.6.22/kernel/power/extent.c suspend2-2.2.10-for-2.6.22/kernel/power/extent.c
3733 --- linux-2.6.22/kernel/power/extent.c 1970-01-01 10:00:00.000000000 +1000
3734 +++ suspend2-2.2.10-for-2.6.22/kernel/power/extent.c 2007-07-11 22:25:42.000000000 +1000
3737 + * kernel/power/extent.c
3739 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
3741 + * Distributed under GPLv2.
3743 + * These functions encapsulate the manipulation of storage metadata. For
3744 + * pageflags, we use dynamically allocated bitmaps.
3747 +#include <linux/module.h>
3748 +#include <linux/suspend.h>
3749 +#include "modules.h"
3750 +#include "extent.h"
3752 +#include "suspend.h"
3754 +/* suspend_get_extent
3756 + * Returns a free extent. May fail, returning NULL instead.
3758 +static struct extent *suspend_get_extent(void)
3760 + struct extent *result;
3762 + if (!(result = kmalloc(sizeof(struct extent), GFP_ATOMIC)))
3765 + result->minimum = result->maximum = 0;
3766 + result->next = NULL;
3771 +/* suspend_put_extent_chain.
3773 + * Frees a whole chain of extents.
3775 +void suspend_put_extent_chain(struct extent_chain *chain)
3777 + struct extent *this;
3779 + this = chain->first;
3782 + struct extent *next = this->next;
3784 + chain->num_extents--;
3788 + chain->first = chain->last_touched = NULL;
3793 + * suspend_add_to_extent_chain
3795 + * Add an extent to an existing chain.
3797 +int suspend_add_to_extent_chain(struct extent_chain *chain,
3798 + unsigned long minimum, unsigned long maximum)
3800 + struct extent *new_extent = NULL, *start_at;
3802 + /* Find the right place in the chain */
3803 + start_at = (chain->last_touched &&
3804 + (chain->last_touched->minimum < minimum)) ?
3805 + chain->last_touched : NULL;
3807 + if (!start_at && chain->first && chain->first->minimum < minimum)
3808 + start_at = chain->first;
3810 + while (start_at && start_at->next && start_at->next->minimum < minimum)
3811 + start_at = start_at->next;
3813 + if (start_at && start_at->maximum == (minimum - 1)) {
3814 + start_at->maximum = maximum;
3816 + /* Merge with the following one? */
3817 + if (start_at->next &&
3818 + start_at->maximum + 1 == start_at->next->minimum) {
3819 + struct extent *to_free = start_at->next;
3820 + start_at->maximum = start_at->next->maximum;
3821 + start_at->next = start_at->next->next;
3822 + chain->num_extents--;
3826 + chain->last_touched = start_at;
3827 + chain->size+= (maximum - minimum + 1);
3832 + new_extent = suspend_get_extent();
3833 + if (!new_extent) {
3834 + printk("Error unable to append a new extent to the chain.\n");
3838 + chain->num_extents++;
3839 + chain->size+= (maximum - minimum + 1);
3840 + new_extent->minimum = minimum;
3841 + new_extent->maximum = maximum;
3842 + new_extent->next = NULL;
3844 + chain->last_touched = new_extent;
3847 + struct extent *next = start_at->next;
3848 + start_at->next = new_extent;
3849 + new_extent->next = next;
3852 + new_extent->next = chain->first;
3853 + chain->first = new_extent;
3859 +/* suspend_serialise_extent_chain
3861 + * Write a chain in the image.
3863 +int suspend_serialise_extent_chain(struct suspend_module_ops *owner,
3864 + struct extent_chain *chain)
3866 + struct extent *this;
3869 + if ((ret = suspendActiveAllocator->rw_header_chunk(WRITE, owner,
3871 + 2 * sizeof(int))))
3874 + this = chain->first;
3876 + if ((ret = suspendActiveAllocator->rw_header_chunk(WRITE, owner,
3878 + 2 * sizeof(unsigned long))))
3880 + this = this->next;
3884 + if (i != chain->num_extents) {
3885 + printk(KERN_EMERG "Saved %d extents but chain metadata says there "
3886 + "should be %d.\n", i, chain->num_extents);
3893 +/* suspend_load_extent_chain
3895 + * Read back a chain saved in the image.
3897 +int suspend_load_extent_chain(struct extent_chain *chain)
3899 + struct extent *this, *last = NULL;
3902 + if ((ret = suspendActiveAllocator->rw_header_chunk(READ, NULL,
3903 + (char *) chain, 2 * sizeof(int)))) {
3904 + printk("Failed to read size of extent chain.\n");
3908 + for (i = 0; i < chain->num_extents; i++) {
3909 + this = kmalloc(sizeof(struct extent), GFP_ATOMIC);
3911 + printk("Failed to allocate a new extent.\n");
3914 + this->next = NULL;
3915 + if ((ret = suspendActiveAllocator->rw_header_chunk(READ, NULL,
3916 + (char *) this, 2 * sizeof(unsigned long)))) {
3917 + printk("Failed to an extent.\n");
3921 + last->next = this;
3923 + chain->first = this;
3929 +/* suspend_extent_state_next
3931 + * Given a state, progress to the next valid entry. We may begin in an
3932 + * invalid state, as we do when invoked after extent_state_goto_start below.
3934 + * When using compression and expected_compression > 0, we let the image size
3935 + * be larger than storage, so we can validly run out of data to return.
3937 +unsigned long suspend_extent_state_next(struct extent_iterate_state *state)
3939 + if (state->current_chain == state->num_chains)
3942 + if (state->current_extent) {
3943 + if (state->current_offset == state->current_extent->maximum) {
3944 + if (state->current_extent->next) {
3945 + state->current_extent = state->current_extent->next;
3946 + state->current_offset = state->current_extent->minimum;
3948 + state->current_extent = NULL;
3949 + state->current_offset = 0;
3952 + state->current_offset++;
3955 + while(!state->current_extent) {
3956 + int chain_num = ++(state->current_chain);
3958 + if (chain_num == state->num_chains)
3961 + state->current_extent = (state->chains + chain_num)->first;
3963 + if (!state->current_extent)
3966 + state->current_offset = state->current_extent->minimum;
3969 + return state->current_offset;
3972 +/* suspend_extent_state_goto_start
3974 + * Find the first valid value in a group of chains.
3976 +void suspend_extent_state_goto_start(struct extent_iterate_state *state)
3978 + state->current_chain = -1;
3979 + state->current_extent = NULL;
3980 + state->current_offset = 0;
3983 +/* suspend_extent_start_save
3985 + * Given a state and a struct extent_state_store, save the current
3986 + * position in a format that can be used with relocated chains (at
3989 +void suspend_extent_state_save(struct extent_iterate_state *state,
3990 + struct extent_iterate_saved_state *saved_state)
3992 + struct extent *extent;
3994 + saved_state->chain_num = state->current_chain;
3995 + saved_state->extent_num = 0;
3996 + saved_state->offset = state->current_offset;
3998 + if (saved_state->chain_num == -1)
4001 + extent = (state->chains + state->current_chain)->first;
4003 + while (extent != state->current_extent) {
4004 + saved_state->extent_num++;
4005 + extent = extent->next;
4009 +/* suspend_extent_start_restore
4011 + * Restore the position saved by extent_state_save.
4013 +void suspend_extent_state_restore(struct extent_iterate_state *state,
4014 + struct extent_iterate_saved_state *saved_state)
4016 + int posn = saved_state->extent_num;
4018 + if (saved_state->chain_num == -1) {
4019 + suspend_extent_state_goto_start(state);
4023 + state->current_chain = saved_state->chain_num;
4024 + state->current_extent = (state->chains + state->current_chain)->first;
4025 + state->current_offset = saved_state->offset;
4028 + state->current_extent = state->current_extent->next;
4031 +#ifdef CONFIG_SUSPEND2_EXPORTS
4032 +EXPORT_SYMBOL_GPL(suspend_add_to_extent_chain);
4033 +EXPORT_SYMBOL_GPL(suspend_put_extent_chain);
4034 +EXPORT_SYMBOL_GPL(suspend_load_extent_chain);
4035 +EXPORT_SYMBOL_GPL(suspend_serialise_extent_chain);
4036 +EXPORT_SYMBOL_GPL(suspend_extent_state_save);
4037 +EXPORT_SYMBOL_GPL(suspend_extent_state_restore);
4038 +EXPORT_SYMBOL_GPL(suspend_extent_state_goto_start);
4039 +EXPORT_SYMBOL_GPL(suspend_extent_state_next);
4041 diff -ruN linux-2.6.22/kernel/power/extent.h suspend2-2.2.10-for-2.6.22/kernel/power/extent.h
4042 --- linux-2.6.22/kernel/power/extent.h 1970-01-01 10:00:00.000000000 +1000
4043 +++ suspend2-2.2.10-for-2.6.22/kernel/power/extent.h 2007-07-11 22:25:42.000000000 +1000
4046 + * kernel/power/extent.h
4048 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
4050 + * This file is released under the GPLv2.
4052 + * It contains declarations related to extents. Extents are
4053 + * suspend's method of storing some of the metadata for the image.
4054 + * See extent.c for more info.
4058 +#include "modules.h"
4064 + unsigned long minimum, maximum;
4065 + struct extent *next;
4068 +struct extent_chain {
4069 + int size; /* size of the chain ie sum (max-min+1) */
4071 + struct extent *first, *last_touched;
4074 +struct extent_iterate_state {
4075 + struct extent_chain *chains;
4077 + int current_chain;
4078 + struct extent *current_extent;
4079 + unsigned long current_offset;
4082 +struct extent_iterate_saved_state {
4085 + unsigned long offset;
4088 +#define suspend_extent_state_eof(state) ((state)->num_chains == (state)->current_chain)
4090 +/* Simplify iterating through all the values in an extent chain */
4091 +#define suspend_extent_for_each(extent_chain, extentpointer, value) \
4092 +if ((extent_chain)->first) \
4093 + for ((extentpointer) = (extent_chain)->first, (value) = \
4094 + (extentpointer)->minimum; \
4095 + ((extentpointer) && ((extentpointer)->next || (value) <= \
4096 + (extentpointer)->maximum)); \
4097 + (((value) == (extentpointer)->maximum) ? \
4098 + ((extentpointer) = (extentpointer)->next, (value) = \
4099 + ((extentpointer) ? (extentpointer)->minimum : 0)) : \
4102 +void suspend_put_extent_chain(struct extent_chain *chain);
4103 +int suspend_add_to_extent_chain(struct extent_chain *chain,
4104 + unsigned long minimum, unsigned long maximum);
4105 +int suspend_serialise_extent_chain(struct suspend_module_ops *owner,
4106 + struct extent_chain *chain);
4107 +int suspend_load_extent_chain(struct extent_chain *chain);
4109 +/* swap_entry_to_extent_val & extent_val_to_swap_entry:
4110 + * We are putting offset in the low bits so consecutive swap entries
4111 + * make consecutive extent values */
4112 +#define swap_entry_to_extent_val(swp_entry) (swp_entry.val)
4113 +#define extent_val_to_swap_entry(val) (swp_entry_t) { (val) }
4115 +void suspend_extent_state_save(struct extent_iterate_state *state,
4116 + struct extent_iterate_saved_state *saved_state);
4117 +void suspend_extent_state_restore(struct extent_iterate_state *state,
4118 + struct extent_iterate_saved_state *saved_state);
4119 +void suspend_extent_state_goto_start(struct extent_iterate_state *state);
4120 +unsigned long suspend_extent_state_next(struct extent_iterate_state *state);
4122 diff -ruN linux-2.6.22/kernel/power/io.c suspend2-2.2.10-for-2.6.22/kernel/power/io.c
4123 --- linux-2.6.22/kernel/power/io.c 1970-01-01 10:00:00.000000000 +1000
4124 +++ suspend2-2.2.10-for-2.6.22/kernel/power/io.c 2007-07-11 22:25:42.000000000 +1000
4127 + * kernel/power/io.c
4129 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
4130 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
4131 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
4132 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
4134 + * This file is released under the GPLv2.
4136 + * It contains high level IO routines for suspending.
4140 +#include <linux/suspend.h>
4141 +#include <linux/version.h>
4142 +#include <linux/utsname.h>
4143 +#include <linux/mount.h>
4144 +#include <linux/highmem.h>
4145 +#include <linux/module.h>
4146 +#include <linux/kthread.h>
4147 +#include <asm/tlbflush.h>
4149 +#include "suspend.h"
4150 +#include "modules.h"
4151 +#include "pageflags.h"
4154 +#include "storage.h"
4155 +#include "prepare_image.h"
4156 +#include "extent.h"
4158 +#include "suspend2_builtin.h"
4160 +char poweroff_resume2[256];
4162 +/* Variables shared between threads and updated under the mutex */
4163 +static int io_write, io_finish_at, io_base, io_barmax, io_pageset, io_result;
4164 +static int io_index, io_nextupdate, io_pc, io_pc_step;
4165 +static unsigned long pfn, other_pfn;
4166 +static DEFINE_MUTEX(io_mutex);
4167 +static DEFINE_PER_CPU(struct page *, last_sought);
4168 +static DEFINE_PER_CPU(struct page *, last_high_page);
4169 +static DEFINE_PER_CPU(struct pbe *, last_low_page);
4170 +static atomic_t worker_thread_count;
4171 +static atomic_t io_count;
4173 +/* suspend_attempt_to_parse_resume_device
4175 + * Can we suspend, using the current resume2= parameter?
4177 +int suspend_attempt_to_parse_resume_device(int quiet)
4179 + struct list_head *Allocator;
4180 + struct suspend_module_ops *thisAllocator;
4181 + int result, returning = 0;
4183 + if (suspend_activate_storage(0))
4186 + suspendActiveAllocator = NULL;
4187 + clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
4188 + clear_suspend_state(SUSPEND_CAN_RESUME);
4189 + clear_result_state(SUSPEND_ABORTED);
4191 + if (!suspendNumAllocators) {
4193 + printk("Suspend2: No storage allocators have been "
4194 + "registered. Suspending will be disabled.\n");
4198 + if (!resume2_file[0]) {
4200 + printk("Suspend2: Resume2 parameter is empty."
4201 + " Suspending will be disabled.\n");
4205 + list_for_each(Allocator, &suspendAllocators) {
4206 + thisAllocator = list_entry(Allocator, struct suspend_module_ops,
4210 + * Not sure why you'd want to disable an allocator, but
4211 + * we should honour the flag if we're providing it
4213 + if (!thisAllocator->enabled)
4216 + result = thisAllocator->parse_sig_location(
4217 + resume2_file, (suspendNumAllocators == 1),
4222 + /* For this allocator, but not a valid
4223 + * configuration. Error already printed. */
4227 + /* For this allocator and valid. */
4228 + suspendActiveAllocator = thisAllocator;
4230 + set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
4231 + set_suspend_state(SUSPEND_CAN_RESUME);
4233 + printk("Suspend2: Resuming enabled.\n");
4240 + printk("Suspend2: No matching enabled allocator found. "
4241 + "Resuming disabled.\n");
4243 + suspend_deactivate_storage(0);
4247 +void attempt_to_parse_resume_device2(void)
4249 + suspend_prepare_usm();
4250 + suspend_attempt_to_parse_resume_device(0);
4251 + suspend_cleanup_usm();
4254 +void save_restore_resume2(int replace, int quiet)
4256 + static char resume2_save[255];
4257 + static unsigned long suspend_state_save;
4260 + suspend_state_save = suspend_state;
4261 + strcpy(resume2_save, resume2_file);
4262 + strcpy(resume2_file, poweroff_resume2);
4264 + strcpy(resume2_file, resume2_save);
4265 + suspend_state = suspend_state_save;
4267 + suspend_attempt_to_parse_resume_device(quiet);
4270 +void attempt_to_parse_po_resume_device2(void)
4274 + /* Temporarily set resume2 to the poweroff value */
4275 + if (!strlen(poweroff_resume2))
4278 + printk("=== Trying Poweroff Resume2 ===\n");
4279 + save_restore_resume2(SAVE, NOQUIET);
4280 + if (test_suspend_state(SUSPEND_CAN_RESUME))
4283 + printk("=== Done ===\n");
4284 + save_restore_resume2(RESTORE, QUIET);
4286 + /* If not ok, clear the string */
4290 + printk("Can't resume from that location; clearing poweroff_resume2.\n");
4291 + poweroff_resume2[0] = '\0';
4294 +/* noresume_reset_modules
4296 + * Description: When we read the start of an image, modules (and especially the
4297 + * active allocator) might need to reset data structures if we
4298 + * decide to invalidate the image rather than resuming from it.
4301 +static void noresume_reset_modules(void)
4303 + struct suspend_module_ops *this_filter;
4305 + list_for_each_entry(this_filter, &suspend_filters, type_list)
4306 + if (this_filter->noresume_reset)
4307 + this_filter->noresume_reset();
4309 + if (suspendActiveAllocator && suspendActiveAllocator->noresume_reset)
4310 + suspendActiveAllocator->noresume_reset();
4313 +/* fill_suspend_header()
4315 + * Description: Fill the suspend header structure.
4316 + * Arguments: struct suspend_header: Header data structure to be filled.
4319 +static void fill_suspend_header(struct suspend_header *sh)
4323 + memset((char *)sh, 0, sizeof(*sh));
4325 + sh->version_code = LINUX_VERSION_CODE;
4326 + sh->num_physpages = num_physpages;
4327 + memcpy(&sh->uts, init_utsname(), sizeof(struct new_utsname));
4328 + sh->page_size = PAGE_SIZE;
4329 + sh->pagedir = pagedir1;
4330 + sh->pageset_2_size = pagedir2.size;
4331 + sh->param0 = suspend_result;
4332 + sh->param1 = suspend_action;
4333 + sh->param2 = suspend_debug_state;
4334 + sh->param3 = console_loglevel;
4335 + sh->root_fs = current->fs->rootmnt->mnt_sb->s_dev;
4336 + for (i = 0; i < 4; i++)
4337 + sh->io_time[i/2][i%2] = suspend_io_time[i/2][i%2];
4343 + * Iterate over modules, preparing the ones that will be used to read or write
4346 +static int rw_init_modules(int rw, int which)
4348 + struct suspend_module_ops *this_module;
4349 + /* Initialise page transformers */
4350 + list_for_each_entry(this_module, &suspend_filters, type_list) {
4351 + if (!this_module->enabled)
4353 + if (this_module->rw_init && this_module->rw_init(rw, which)) {
4354 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4355 + "Failed to initialise the %s filter.",
4356 + this_module->name);
4361 + /* Initialise allocator */
4362 + if (suspendActiveAllocator->rw_init(rw, which)) {
4363 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4364 + "Failed to initialise the allocator.");
4366 + suspendActiveAllocator->invalidate_image();
4370 + /* Initialise other modules */
4371 + list_for_each_entry(this_module, &suspend_modules, module_list) {
4372 + if (!this_module->enabled ||
4373 + this_module->type == FILTER_MODULE ||
4374 + this_module->type == WRITER_MODULE)
4376 + if (this_module->rw_init && this_module->rw_init(rw, which)) {
4377 + set_result_state(SUSPEND_ABORTED);
4378 + printk("Setting aborted flag due to module init failure.\n");
4387 + * rw_cleanup_modules
4389 + * Cleanup components after reading or writing a set of pages.
4390 + * Only the allocator may fail.
4392 +static int rw_cleanup_modules(int rw)
4394 + struct suspend_module_ops *this_module;
4397 + /* Cleanup other modules */
4398 + list_for_each_entry(this_module, &suspend_modules, module_list) {
4399 + if (!this_module->enabled ||
4400 + this_module->type == FILTER_MODULE ||
4401 + this_module->type == WRITER_MODULE)
4403 + if (this_module->rw_cleanup)
4404 + result |= this_module->rw_cleanup(rw);
4407 + /* Flush data and cleanup */
4408 + list_for_each_entry(this_module, &suspend_filters, type_list) {
4409 + if (!this_module->enabled)
4411 + if (this_module->rw_cleanup)
4412 + result |= this_module->rw_cleanup(rw);
4415 + result |= suspendActiveAllocator->rw_cleanup(rw);
4420 +static struct page *copy_page_from_orig_page(struct page *orig_page)
4422 + int is_high = PageHighMem(orig_page), index, min, max;
4423 + struct page *high_page = NULL,
4424 + **my_last_high_page = &__get_cpu_var(last_high_page),
4425 + **my_last_sought = &__get_cpu_var(last_sought);
4426 + struct pbe *this, **my_last_low_page = &__get_cpu_var(last_low_page);
4430 + if (*my_last_sought && *my_last_high_page && *my_last_sought < orig_page)
4431 + high_page = *my_last_high_page;
4433 + high_page = (struct page *) restore_highmem_pblist;
4434 + this = (struct pbe *) kmap(high_page);
4435 + compare = orig_page;
4437 + if (*my_last_sought && *my_last_low_page && *my_last_sought < orig_page)
4438 + this = *my_last_low_page;
4440 + this = restore_pblist;
4441 + compare = page_address(orig_page);
4444 + *my_last_sought = orig_page;
4446 + /* Locate page containing pbe */
4447 + while ( this[PBES_PER_PAGE - 1].next &&
4448 + this[PBES_PER_PAGE - 1].orig_address < compare) {
4450 + struct page *next_high_page = (struct page *)
4451 + this[PBES_PER_PAGE - 1].next;
4452 + kunmap(high_page);
4453 + this = kmap(next_high_page);
4454 + high_page = next_high_page;
4456 + this = this[PBES_PER_PAGE - 1].next;
4459 + /* Do a binary search within the page */
4461 + max = PBES_PER_PAGE;
4462 + index = PBES_PER_PAGE / 2;
4463 + while (max - min) {
4464 + if (!this[index].orig_address ||
4465 + this[index].orig_address > compare)
4467 + else if (this[index].orig_address == compare) {
4469 + struct page *page = this[index].address;
4470 + *my_last_high_page = high_page;
4471 + kunmap(high_page);
4474 + *my_last_low_page = this;
4475 + return virt_to_page(this[index].address);
4478 + index = ((max + min) / 2);
4482 + kunmap(high_page);
4484 + abort_suspend(SUSPEND_FAILED_IO, "Failed to get destination page for"
4485 + " orig page %p. This[min].orig_address=%p.\n", orig_page,
4486 + this[index].orig_address);
4493 + * The main I/O loop for reading or writing pages.
4495 +static int worker_rw_loop(void *data)
4497 + unsigned long orig_pfn, write_pfn;
4498 + int result, my_io_index = 0;
4499 + struct suspend_module_ops *first_filter = suspend_get_next_filter(NULL);
4500 + struct page *buffer = alloc_page(GFP_ATOMIC);
4502 + atomic_inc(&worker_thread_count);
4504 + mutex_lock(&io_mutex);
4510 + * What page to use? If reading, don't know yet which page's
4511 + * data will be read, so always use the buffer. If writing,
4512 + * use the copy (Pageset1) or original page (Pageset2), but
4513 + * always write the pfn of the original page.
4516 + struct page *page;
4518 + pfn = get_next_bit_on(io_map, pfn);
4520 + /* Another thread could have beaten us to it. */
4521 + if (pfn == max_pfn + 1) {
4522 + if (atomic_read(&io_count)) {
4523 + printk("Ran out of pfns but io_count is still %d.\n", atomic_read(&io_count));
4529 + atomic_dec(&io_count);
4535 + * Other_pfn is updated by all threads, so we're not
4536 + * writing the same page multiple times.
4538 + clear_dynpageflag(&io_map, pfn_to_page(pfn));
4539 + if (io_pageset == 1) {
4540 + other_pfn = get_next_bit_on(pageset1_map, other_pfn);
4541 + write_pfn = other_pfn;
4543 + page = pfn_to_page(pfn);
4545 + my_io_index = io_finish_at - atomic_read(&io_count);
4547 + mutex_unlock(&io_mutex);
4549 + result = first_filter->write_chunk(write_pfn, page,
4552 + atomic_dec(&io_count);
4553 + mutex_unlock(&io_mutex);
4556 + * Are we aborting? If so, don't submit any more I/O as
4557 + * resetting the resume_attempted flag (from ui.c) will
4558 + * clear the bdev flags, making this thread oops.
4560 + if (unlikely(test_suspend_state(SUSPEND_STOP_RESUME))) {
4561 + atomic_dec(&worker_thread_count);
4562 + if (!atomic_read(&worker_thread_count))
4563 + set_suspend_state(SUSPEND_IO_STOPPED);
4568 + result = first_filter->read_chunk(&write_pfn, buffer,
4569 + &buf_size, SUSPEND_ASYNC);
4570 + if (buf_size != PAGE_SIZE) {
4571 + abort_suspend(SUSPEND_FAILED_IO,
4572 + "I/O pipeline returned %d bytes instead "
4573 + "of %d.\n", buf_size, PAGE_SIZE);
4574 + mutex_lock(&io_mutex);
4580 + io_result = result;
4582 + printk("Write chunk returned %d.\n", result);
4583 + abort_suspend(SUSPEND_FAILED_IO,
4584 + "Failed to write a chunk of the "
4586 + mutex_lock(&io_mutex);
4589 + panic("Read chunk returned (%d)", result);
4593 + * Discard reads of resaved pages while reading ps2
4594 + * and unwanted pages while rereading ps2 when aborting.
4596 + if (!io_write && !PageResave(pfn_to_page(write_pfn))) {
4597 + struct page *final_page = pfn_to_page(write_pfn),
4598 + *copy_page = final_page;
4599 + char *virt, *buffer_virt;
4601 + if (io_pageset == 1 && !load_direct(final_page)) {
4602 + copy_page = copy_page_from_orig_page(final_page);
4603 + BUG_ON(!copy_page);
4606 + if (test_dynpageflag(&io_map, final_page)) {
4607 + virt = kmap(copy_page);
4608 + buffer_virt = kmap(buffer);
4609 + memcpy(virt, buffer_virt, PAGE_SIZE);
4610 + kunmap(copy_page);
4612 + clear_dynpageflag(&io_map, final_page);
4613 + mutex_lock(&io_mutex);
4614 + my_io_index = io_finish_at - atomic_read(&io_count);
4615 + mutex_unlock(&io_mutex);
4617 + mutex_lock(&io_mutex);
4618 + atomic_inc(&io_count);
4619 + mutex_unlock(&io_mutex);
4623 + /* Strictly speaking, this is racy - another thread could
4624 + * output the next the next percentage before we've done
4625 + * ours. 1/5th of the pageset would have to be done first,
4626 + * though, so I'm not worried. In addition, the only impact
4627 + * would be messed up output, not image corruption. Doing
4628 + * this under the mutex seems an unnecessary slowdown.
4630 + if ((my_io_index + io_base) >= io_nextupdate)
4631 + io_nextupdate = suspend_update_status(my_io_index +
4632 + io_base, io_barmax, " %d/%d MB ",
4633 + MB(io_base+my_io_index+1), MB(io_barmax));
4635 + if ((my_io_index + 1) == io_pc) {
4636 + printk("%d%%...", 20 * io_pc_step);
4638 + io_pc = io_finish_at * io_pc_step / 5;
4641 + suspend_cond_pause(0, NULL);
4644 + * Subtle: If there's less I/O still to be done than threads
4645 + * running, quit. This stops us doing I/O beyond the end of
4646 + * the image when reading.
4648 + * Possible race condition. Two threads could do the test at
4649 + * the same time; one should exit and one should continue.
4650 + * Therefore we take the mutex before comparing and exiting.
4653 + mutex_lock(&io_mutex);
4655 + } while(atomic_read(&io_count) >= atomic_read(&worker_thread_count) &&
4656 + !(io_write && test_result_state(SUSPEND_ABORTED)));
4658 + atomic_dec(&worker_thread_count);
4659 + mutex_unlock(&io_mutex);
4661 + __free_pages(buffer, 0);
4666 +void start_other_threads(void)
4669 + struct task_struct *p;
4671 + for_each_online_cpu(cpu) {
4672 + if (cpu == smp_processor_id())
4675 + p = kthread_create(worker_rw_loop, NULL, "ks2io/%d", cpu);
4677 + printk("ks2io for %i failed\n", cpu);
4680 + kthread_bind(p, cpu);
4681 + wake_up_process(p);
4688 + * The main I/O loop for reading or writing pages.
4690 +static int do_rw_loop(int write, int finish_at, dyn_pageflags_t *pageflags,
4691 + int base, int barmax, int pageset)
4693 + int index = 0, cpu;
4699 + io_finish_at = finish_at;
4701 + io_barmax = barmax;
4702 + io_pageset = pageset;
4704 + io_pc = io_finish_at / 5;
4707 + io_nextupdate = 0;
4709 + for_each_online_cpu(cpu) {
4710 + per_cpu(last_sought, cpu) = NULL;
4711 + per_cpu(last_low_page, cpu) = NULL;
4712 + per_cpu(last_high_page, cpu) = NULL;
4715 + /* Ensure all bits clear */
4716 + pfn = get_next_bit_on(io_map, max_pfn + 1);
4718 + while (pfn < max_pfn + 1) {
4719 + clear_dynpageflag(&io_map, pfn_to_page(pfn));
4720 + pfn = get_next_bit_on(io_map, pfn);
4723 + /* Set the bits for the pages to write */
4724 + pfn = get_next_bit_on(*pageflags, max_pfn + 1);
4726 + while (pfn < max_pfn + 1 && index < finish_at) {
4727 + set_dynpageflag(&io_map, pfn_to_page(pfn));
4728 + pfn = get_next_bit_on(*pageflags, pfn);
4732 + BUG_ON(index < finish_at);
4734 + atomic_set(&io_count, finish_at);
4736 + pfn = max_pfn + 1;
4739 + clear_suspend_state(SUSPEND_IO_STOPPED);
4741 + if (!test_action_state(SUSPEND_NO_MULTITHREADED_IO))
4742 + start_other_threads();
4743 + worker_rw_loop(NULL);
4745 + while (atomic_read(&worker_thread_count))
4748 + set_suspend_state(SUSPEND_IO_STOPPED);
4749 + if (unlikely(test_suspend_state(SUSPEND_STOP_RESUME))) {
4755 + printk("done.\n");
4757 + suspend_update_status(io_base + io_finish_at, io_barmax, " %d/%d MB ",
4758 + MB(io_base + io_finish_at), MB(io_barmax));
4761 + if (io_write && test_result_state(SUSPEND_ABORTED))
4763 + else /* All I/O done? */
4764 + BUG_ON(get_next_bit_on(io_map, max_pfn + 1) != max_pfn + 1);
4771 + * Description: Write a pageset to disk.
4772 + * Arguments: pagedir: Which pagedir to write..
4773 + * Returns: Zero on success or -1 on failure.
4776 +int write_pageset(struct pagedir *pagedir)
4778 + int finish_at, base = 0, start_time, end_time;
4779 + int barmax = pagedir1.size + pagedir2.size;
4781 + dyn_pageflags_t *pageflags;
4784 + * Even if there is nothing to read or write, the allocator
4785 + * may need the init/cleanup for it's housekeeping. (eg:
4786 + * Pageset1 may start where pageset2 ends when writing).
4788 + finish_at = pagedir->size;
4790 + if (pagedir->id == 1) {
4791 + suspend_prepare_status(DONT_CLEAR_BAR,
4792 + "Writing kernel & process data...");
4793 + base = pagedir2.size;
4794 + if (test_action_state(SUSPEND_TEST_FILTER_SPEED) ||
4795 + test_action_state(SUSPEND_TEST_BIO))
4796 + pageflags = &pageset1_map;
4798 + pageflags = &pageset1_copy_map;
4800 + suspend_prepare_status(CLEAR_BAR, "Writing caches...");
4801 + pageflags = &pageset2_map;
4804 + start_time = jiffies;
4806 + if (rw_init_modules(1, pagedir->id)) {
4807 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4808 + "Failed to initialise modules for writing.");
4813 + error = do_rw_loop(1, finish_at, pageflags, base, barmax,
4816 + if (rw_cleanup_modules(WRITE) && !error) {
4817 + abort_suspend(SUSPEND_FAILED_MODULE_CLEANUP,
4818 + "Failed to cleanup after writing.");
4822 + end_time = jiffies;
4824 + if ((end_time - start_time) && (!test_result_state(SUSPEND_ABORTED))) {
4825 + suspend_io_time[0][0] += finish_at,
4826 + suspend_io_time[0][1] += (end_time - start_time);
4834 + * Description: Read a pageset from disk.
4835 + * Arguments: whichtowrite: Controls what debugging output is printed.
4836 + * overwrittenpagesonly: Whether to read the whole pageset or
4838 + * Returns: Zero on success or -1 on failure.
4841 +static int read_pageset(struct pagedir *pagedir, int overwrittenpagesonly)
4843 + int result = 0, base = 0, start_time, end_time;
4844 + int finish_at = pagedir->size;
4845 + int barmax = pagedir1.size + pagedir2.size;
4846 + dyn_pageflags_t *pageflags;
4848 + if (pagedir->id == 1) {
4849 + suspend_prepare_status(CLEAR_BAR,
4850 + "Reading kernel & process data...");
4851 + pageflags = &pageset1_map;
4853 + suspend_prepare_status(DONT_CLEAR_BAR, "Reading caches...");
4854 + if (overwrittenpagesonly)
4855 + barmax = finish_at = min(pagedir1.size,
4858 + base = pagedir1.size;
4860 + pageflags = &pageset2_map;
4863 + start_time = jiffies;
4865 + if (rw_init_modules(0, pagedir->id)) {
4866 + suspendActiveAllocator->invalidate_image();
4869 + result = do_rw_loop(0, finish_at, pageflags, base, barmax,
4872 + if (rw_cleanup_modules(READ) && !result) {
4873 + abort_suspend(SUSPEND_FAILED_MODULE_CLEANUP,
4874 + "Failed to cleanup after reading.");
4881 + if ((end_time - start_time) && (!test_result_state(SUSPEND_ABORTED))) {
4882 + suspend_io_time[1][0] += finish_at,
4883 + suspend_io_time[1][1] += (end_time - start_time);
4889 +/* write_module_configs()
4891 + * Description: Store the configuration for each module in the image header.
4892 + * Returns: Int: Zero on success, Error value otherwise.
4894 +static int write_module_configs(void)
4896 + struct suspend_module_ops *this_module;
4897 + char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
4898 + int len, index = 1;
4899 + struct suspend_module_header suspend_module_header;
4902 + printk("Failed to allocate a buffer for saving "
4903 + "module configuration info.\n");
4908 + * We have to know which data goes with which module, so we at
4909 + * least write a length of zero for a module. Note that we are
4910 + * also assuming every module's config data takes <= PAGE_SIZE.
4913 + /* For each module (in registration order) */
4914 + list_for_each_entry(this_module, &suspend_modules, module_list) {
4915 + if (!this_module->enabled || !this_module->storage_needed ||
4916 + (this_module->type == WRITER_MODULE &&
4917 + suspendActiveAllocator != this_module))
4920 + /* Get the data from the module */
4922 + if (this_module->save_config_info)
4923 + len = this_module->save_config_info(buffer);
4925 + /* Save the details of the module */
4926 + suspend_module_header.enabled = this_module->enabled;
4927 + suspend_module_header.type = this_module->type;
4928 + suspend_module_header.index = index++;
4929 + strncpy(suspend_module_header.name, this_module->name,
4930 + sizeof(suspend_module_header.name));
4931 + suspendActiveAllocator->rw_header_chunk(WRITE,
4933 + (char *) &suspend_module_header,
4934 + sizeof(suspend_module_header));
4936 + /* Save the size of the data and any data returned */
4937 + suspendActiveAllocator->rw_header_chunk(WRITE,
4939 + (char *) &len, sizeof(int));
4941 + suspendActiveAllocator->rw_header_chunk(
4942 + WRITE, this_module, buffer, len);
4945 + /* Write a blank header to terminate the list */
4946 + suspend_module_header.name[0] = '\0';
4947 + suspendActiveAllocator->rw_header_chunk(WRITE,
4949 + (char *) &suspend_module_header,
4950 + sizeof(suspend_module_header));
4952 + free_page((unsigned long) buffer);
4956 +/* read_module_configs()
4958 + * Description: Reload module configurations from the image header.
4959 + * Returns: Int. Zero on success, error value otherwise.
4962 +static int read_module_configs(void)
4964 + struct suspend_module_ops *this_module;
4965 + char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
4966 + int len, result = 0;
4967 + struct suspend_module_header suspend_module_header;
4970 + printk("Failed to allocate a buffer for reloading module "
4971 + "configuration info.\n");
4975 + /* All modules are initially disabled. That way, if we have a module
4976 + * loaded now that wasn't loaded when we suspended, it won't be used
4977 + * in trying to read the data.
4979 + list_for_each_entry(this_module, &suspend_modules, module_list)
4980 + this_module->enabled = 0;
4982 + /* Get the first module header */
4983 + result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
4984 + (char *) &suspend_module_header,
4985 + sizeof(suspend_module_header));
4987 + printk("Failed to read the next module header.\n");
4988 + free_page((unsigned long) buffer);
4992 + /* For each module (in registration order) */
4993 + while (suspend_module_header.name[0]) {
4995 + /* Find the module */
4996 + this_module = suspend_find_module_given_name(suspend_module_header.name);
4998 + if (!this_module) {
5000 + * Is it used? Only need to worry about filters. The active
5001 + * allocator must be loaded!
5003 + if (suspend_module_header.enabled) {
5004 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
5005 + "It looks like we need module %s for "
5006 + "reading the image but it hasn't been "
5008 + suspend_module_header.name);
5009 + if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
5010 + suspendActiveAllocator->invalidate_image();
5011 + free_page((unsigned long) buffer);
5015 + printk("Module %s configuration data found, but"
5016 + " the module hasn't registered. Looks "
5017 + "like it was disabled, so we're "
5018 + "ignoring it's data.",
5019 + suspend_module_header.name);
5022 + /* Get the length of the data (if any) */
5023 + result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5024 + (char *) &len, sizeof(int));
5026 + printk("Failed to read the length of the module %s's"
5027 + " configuration data.\n",
5028 + suspend_module_header.name);
5029 + free_page((unsigned long) buffer);
5033 + /* Read any data and pass to the module (if we found one) */
5035 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
5037 + if (this_module) {
5038 + if (!this_module->save_config_info) {
5039 + printk("Huh? Module %s appears to have "
5040 + "a save_config_info, but not a "
5041 + "load_config_info function!\n",
5042 + this_module->name);
5044 + this_module->load_config_info(buffer, len);
5048 + if (this_module) {
5049 + /* Now move this module to the tail of its lists. This
5050 + * will put it in order. Any new modules will end up at
5051 + * the top of the lists. They should have been set to
5052 + * disabled when loaded (people will normally not edit
5053 + * an initrd to load a new module and then suspend
5054 + * without using it!).
5057 + suspend_move_module_tail(this_module);
5060 + * We apply the disabled state; modules don't need to
5061 + * save whether they were disabled and if they do, we
5062 + * override them anyway.
5064 + this_module->enabled = suspend_module_header.enabled;
5067 + /* Get the next module header */
5068 + result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5069 + (char *) &suspend_module_header,
5070 + sizeof(suspend_module_header));
5073 + printk("Failed to read the next module header.\n");
5074 + free_page((unsigned long) buffer);
5080 + free_page((unsigned long) buffer);
5084 +/* write_image_header()
5086 + * Description: Write the image header after write the image proper.
5087 + * Returns: Int. Zero on success or -1 on failure.
5090 +int write_image_header(void)
5093 + int total = pagedir1.size + pagedir2.size+2;
5094 + char *header_buffer = NULL;
5096 + /* Now prepare to write the header */
5097 + if ((ret = suspendActiveAllocator->write_header_init())) {
5098 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
5099 + "Active allocator's write_header_init"
5100 + " function failed.");
5101 + goto write_image_header_abort;
5104 + /* Get a buffer */
5105 + header_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
5106 + if (!header_buffer) {
5107 + abort_suspend(SUSPEND_OUT_OF_MEMORY,
5108 + "Out of memory when trying to get page for header!");
5109 + goto write_image_header_abort;
5112 + /* Write suspend header */
5113 + fill_suspend_header((struct suspend_header *) header_buffer);
5114 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
5115 + header_buffer, sizeof(struct suspend_header));
5117 + free_page((unsigned long) header_buffer);
5119 + /* Write module configurations */
5120 + if ((ret = write_module_configs())) {
5121 + abort_suspend(SUSPEND_FAILED_IO,
5122 + "Failed to write module configs.");
5123 + goto write_image_header_abort;
5126 + save_dyn_pageflags(pageset1_map);
5128 + /* Flush data and let allocator cleanup */
5129 + if (suspendActiveAllocator->write_header_cleanup()) {
5130 + abort_suspend(SUSPEND_FAILED_IO,
5131 + "Failed to cleanup writing header.");
5132 + goto write_image_header_abort_no_cleanup;
5135 + if (test_result_state(SUSPEND_ABORTED))
5136 + goto write_image_header_abort_no_cleanup;
5138 + suspend_message(SUSPEND_IO, SUSPEND_VERBOSE, 1, "|\n");
5139 + suspend_update_status(total, total, NULL);
5143 +write_image_header_abort:
5144 + suspendActiveAllocator->write_header_cleanup();
5145 +write_image_header_abort_no_cleanup:
5151 + * Description: Perform a few checks, seeking to ensure that the kernel being
5152 + * booted matches the one suspended. They need to match so we can
5153 + * be _sure_ things will work. It is not absolutely impossible for
5154 + * resuming from a different kernel to work, just not assured.
5155 + * Arguments: Struct suspend_header. The header which was saved at suspend
5158 +static char *sanity_check(struct suspend_header *sh)
5160 + if (sh->version_code != LINUX_VERSION_CODE)
5161 + return "Incorrect kernel version.";
5163 + if (sh->num_physpages != num_physpages)
5164 + return "Incorrect memory size.";
5166 + if (strncmp(sh->uts.sysname, init_utsname()->sysname, 65))
5167 + return "Incorrect system type.";
5169 + if (strncmp(sh->uts.release, init_utsname()->release, 65))
5170 + return "Incorrect release.";
5172 + if (strncmp(sh->uts.version, init_utsname()->version, 65))
5173 + return "Right kernel version but wrong build number.";
5175 + if (strncmp(sh->uts.machine, init_utsname()->machine, 65))
5176 + return "Incorrect machine type.";
5178 + if (sh->page_size != PAGE_SIZE)
5179 + return "Incorrect PAGE_SIZE.";
5181 + if (!test_action_state(SUSPEND_IGNORE_ROOTFS)) {
5182 + const struct super_block *sb;
5183 + list_for_each_entry(sb, &super_blocks, s_list) {
5184 + if ((!(sb->s_flags & MS_RDONLY)) &&
5185 + (sb->s_type->fs_flags & FS_REQUIRES_DEV))
5186 + return "Device backed fs has been mounted "
5187 + "rw prior to resume or initrd/ramfs "
5197 + * Description: Test for the existence of an image and attempt to load it.
5198 + * Returns: Int. Zero if image found and pageset1 successfully loaded.
5199 + * Error if no image found or loaded.
5201 +static int __read_pageset1(void)
5203 + int i, result = 0;
5204 + char *header_buffer = (char *) get_zeroed_page(GFP_ATOMIC),
5205 + *sanity_error = NULL;
5206 + struct suspend_header *suspend_header;
5208 + if (!header_buffer) {
5209 + printk("Unable to allocate a page for reading the signature.\n");
5213 + /* Check for an image */
5214 + if (!(result = suspendActiveAllocator->image_exists())) {
5215 + result = -ENODATA;
5216 + noresume_reset_modules();
5217 + printk("Suspend2: No image found.\n");
5221 + /* Check for noresume command line option */
5222 + if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
5223 + printk("Suspend2: Noresume: Invalidated image.\n");
5224 + goto out_invalidate_image;
5227 + /* Check whether we've resumed before */
5228 + if (test_suspend_state(SUSPEND_RESUMED_BEFORE)) {
5229 + int resumed_before_default = 0;
5230 + if (test_suspend_state(SUSPEND_RETRY_RESUME))
5231 + resumed_before_default = SUSPEND_CONTINUE_REQ;
5233 + suspend_early_boot_message(1, resumed_before_default, NULL);
5234 + clear_suspend_state(SUSPEND_RETRY_RESUME);
5235 + if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
5236 + printk("Suspend2: Tried to resume before: "
5237 + "Invalidated image.\n");
5238 + goto out_invalidate_image;
5242 + clear_suspend_state(SUSPEND_CONTINUE_REQ);
5245 + * Prepare the active allocator for reading the image header. The
5246 + * activate allocator might read its own configuration.
5248 + * NB: This call may never return because there might be a signature
5249 + * for a different image such that we warn the user and they choose
5250 + * to reboot. (If the device ids look erroneous (2.4 vs 2.6) or the
5251 + * location of the image might be unavailable if it was stored on a
5252 + * network connection.
5255 + if ((result = suspendActiveAllocator->read_header_init())) {
5256 + printk("Suspend2: Failed to initialise, reading the image "
5258 + goto out_invalidate_image;
5261 + /* Read suspend header */
5262 + if ((result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5263 + header_buffer, sizeof(struct suspend_header))) < 0) {
5264 + printk("Suspend2: Failed to read the image signature.\n");
5265 + goto out_invalidate_image;
5268 + suspend_header = (struct suspend_header *) header_buffer;
5271 + * NB: This call may also result in a reboot rather than returning.
5274 + if ((sanity_error = sanity_check(suspend_header)) &&
5275 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ, sanity_error)) {
5276 + printk("Suspend2: Sanity check failed.\n");
5277 + goto out_invalidate_image;
5281 + * We have an image and it looks like it will load okay.
5283 + * Get metadata from header. Don't override commandline parameters.
5285 + * We don't need to save the image size limit because it's not used
5286 + * during resume and will be restored with the image anyway.
5289 + memcpy((char *) &pagedir1,
5290 + (char *) &suspend_header->pagedir, sizeof(pagedir1));
5291 + suspend_result = suspend_header->param0;
5292 + suspend_action = suspend_header->param1;
5293 + suspend_debug_state = suspend_header->param2;
5294 + console_loglevel = suspend_header->param3;
5295 + clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
5296 + pagedir2.size = suspend_header->pageset_2_size;
5297 + for (i = 0; i < 4; i++)
5298 + suspend_io_time[i/2][i%2] =
5299 + suspend_header->io_time[i/2][i%2];
5301 + /* Read module configurations */
5302 + if ((result = read_module_configs())) {
5303 + pagedir1.size = pagedir2.size = 0;
5304 + printk("Suspend2: Failed to read Suspend module "
5305 + "configurations.\n");
5306 + clear_action_state(SUSPEND_KEEP_IMAGE);
5307 + goto out_invalidate_image;
5310 + suspend_prepare_console();
5312 + set_suspend_state(SUSPEND_NOW_RESUMING);
5314 + if (pre_resume_freeze())
5315 + goto out_reset_console;
5317 + suspend_cond_pause(1, "About to read original pageset1 locations.");
5320 + * Read original pageset1 locations. These are the addresses we can't
5321 + * use for the data to be restored.
5324 + if (allocate_dyn_pageflags(&pageset1_map) ||
5325 + allocate_dyn_pageflags(&pageset1_copy_map) ||
5326 + allocate_dyn_pageflags(&io_map))
5327 + goto out_reset_console;
5329 + if (load_dyn_pageflags(pageset1_map))
5330 + goto out_reset_console;
5332 + /* Clean up after reading the header */
5333 + if ((result = suspendActiveAllocator->read_header_cleanup())) {
5334 + printk("Suspend2: Failed to cleanup after reading the image "
5336 + goto out_reset_console;
5339 + suspend_cond_pause(1, "About to read pagedir.");
5342 + * Get the addresses of pages into which we will load the kernel to
5345 + if (suspend_get_pageset1_load_addresses()) {
5346 + printk("Suspend2: Failed to get load addresses for pageset1.\n");
5347 + goto out_reset_console;
5350 + /* Read the original kernel back */
5351 + suspend_cond_pause(1, "About to read pageset 1.");
5353 + if (read_pageset(&pagedir1, 0)) {
5354 + suspend_prepare_status(CLEAR_BAR, "Failed to read pageset 1.");
5356 + printk("Suspend2: Failed to get load pageset1.\n");
5357 + goto out_reset_console;
5360 + suspend_cond_pause(1, "About to restore original kernel.");
5363 + if (!test_action_state(SUSPEND_KEEP_IMAGE) &&
5364 + suspendActiveAllocator->mark_resume_attempted)
5365 + suspendActiveAllocator->mark_resume_attempted(1);
5368 + free_page((unsigned long) header_buffer);
5372 + suspend_cleanup_console();
5374 +out_invalidate_image:
5375 + free_dyn_pageflags(&pageset1_map);
5376 + free_dyn_pageflags(&pageset1_copy_map);
5377 + free_dyn_pageflags(&io_map);
5379 + if (!test_action_state(SUSPEND_KEEP_IMAGE))
5380 + suspendActiveAllocator->invalidate_image();
5381 + suspendActiveAllocator->read_header_cleanup();
5382 + noresume_reset_modules();
5388 + * Description: Attempt to read the header and pageset1 of a suspend image.
5389 + * Handle the outcome, complaining where appropriate.
5392 +int read_pageset1(void)
5396 + error = __read_pageset1();
5401 + case -EINVAL: /* non fatal error */
5404 + if (test_result_state(SUSPEND_ABORTED))
5407 + abort_suspend(SUSPEND_IMAGE_ERROR,
5408 + "Suspend2: Error %d resuming\n",
5415 + * get_have_image_data()
5417 +static char *get_have_image_data(void)
5419 + char *output_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
5420 + struct suspend_header *suspend_header;
5422 + if (!output_buffer) {
5423 + printk("Output buffer null.\n");
5427 + /* Check for an image */
5428 + if (!suspendActiveAllocator->image_exists() ||
5429 + suspendActiveAllocator->read_header_init() ||
5430 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
5431 + output_buffer, sizeof(struct suspend_header))) {
5432 + sprintf(output_buffer, "0\n");
5436 + suspend_header = (struct suspend_header *) output_buffer;
5438 + sprintf(output_buffer, "1\n%s\n%s\n",
5439 + suspend_header->uts.machine,
5440 + suspend_header->uts.version);
5442 + /* Check whether we've resumed before */
5443 + if (test_suspend_state(SUSPEND_RESUMED_BEFORE))
5444 + strcat(output_buffer, "Resumed before.\n");
5447 + noresume_reset_modules();
5448 + return output_buffer;
5453 + * Description: Read in part or all of pageset2 of an image, depending upon
5454 + * whether we are suspending and have only overwritten a portion
5455 + * with pageset1 pages, or are resuming and need to read them
5457 + * Arguments: Int. Boolean. Read only pages which would have been
5458 + * overwritten by pageset1?
5459 + * Returns: Int. Zero if no error, otherwise the error value.
5461 +int read_pageset2(int overwrittenpagesonly)
5465 + if (!pagedir2.size)
5468 + result = read_pageset(&pagedir2, overwrittenpagesonly);
5470 + suspend_update_status(100, 100, NULL);
5471 + suspend_cond_pause(1, "Pagedir 2 read.");
5476 +/* image_exists_read
5478 + * Return 0 or 1, depending on whether an image is found.
5479 + * Incoming buffer is PAGE_SIZE and result is guaranteed
5480 + * to be far less than that, so we don't worry about
5483 +int image_exists_read(const char *page, int count)
5488 + if (suspend_activate_storage(0))
5491 + if (!test_suspend_state(SUSPEND_RESUME_DEVICE_OK))
5492 + suspend_attempt_to_parse_resume_device(0);
5494 + if (!suspendActiveAllocator) {
5495 + len = sprintf((char *) page, "-1\n");
5497 + result = get_have_image_data();
5499 + len = sprintf((char *) page, "%s", result);
5500 + free_page((unsigned long) result);
5504 + suspend_deactivate_storage(0);
5509 +/* image_exists_write
5511 + * Invalidate an image if one exists.
5513 +int image_exists_write(const char *buffer, int count)
5515 + if (suspend_activate_storage(0))
5518 + if (suspendActiveAllocator && suspendActiveAllocator->image_exists())
5519 + suspendActiveAllocator->invalidate_image();
5521 + suspend_deactivate_storage(0);
5523 + clear_result_state(SUSPEND_KEPT_IMAGE);
5528 +#ifdef CONFIG_SUSPEND2_EXPORTS
5529 +EXPORT_SYMBOL_GPL(suspend_attempt_to_parse_resume_device);
5530 +EXPORT_SYMBOL_GPL(attempt_to_parse_resume_device2);
5533 diff -ruN linux-2.6.22/kernel/power/io.h suspend2-2.2.10-for-2.6.22/kernel/power/io.h
5534 --- linux-2.6.22/kernel/power/io.h 1970-01-01 10:00:00.000000000 +1000
5535 +++ suspend2-2.2.10-for-2.6.22/kernel/power/io.h 2007-07-11 22:25:42.000000000 +1000
5538 + * kernel/power/io.h
5540 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
5542 + * This file is released under the GPLv2.
5544 + * It contains high level IO routines for suspending.
5548 +#include <linux/utsname.h>
5549 +#include "pagedir.h"
5551 +/* Non-module data saved in our image header */
5552 +struct suspend_header {
5554 + unsigned long num_physpages;
5555 + unsigned long orig_mem_free;
5556 + struct new_utsname uts;
5559 + int pageset_2_size;
5568 + int io_time[2][2];
5569 + struct pagedir pagedir;
5573 +extern int write_pageset(struct pagedir *pagedir);
5574 +extern int write_image_header(void);
5575 +extern int read_pageset1(void);
5576 +extern int read_pageset2(int overwrittenpagesonly);
5578 +extern int suspend_attempt_to_parse_resume_device(int quiet);
5579 +extern void attempt_to_parse_resume_device2(void);
5580 +extern void attempt_to_parse_po_resume_device2(void);
5581 +int image_exists_read(const char *page, int count);
5582 +int image_exists_write(const char *buffer, int count);
5583 +extern void save_restore_resume2(int replace, int quiet);
5585 +/* Args to save_restore_resume2 */
5592 +extern dev_t name_to_dev_t(char *line);
5593 diff -ruN linux-2.6.22/kernel/power/main.c suspend2-2.2.10-for-2.6.22/kernel/power/main.c
5594 --- linux-2.6.22/kernel/power/main.c 2007-07-11 22:19:41.000000000 +1000
5595 +++ suspend2-2.2.10-for-2.6.22/kernel/power/main.c 2007-07-11 22:25:42.000000000 +1000
5597 if (pm_states[i] && valid_state(i))
5598 s += sprintf(s,"%s ", pm_states[i]);
5600 -#ifdef CONFIG_SOFTWARE_SUSPEND
5601 +#ifdef CONFIG_SUSPEND_SHARED
5602 s += sprintf(s, "%s\n", "disk");
5605 diff -ruN linux-2.6.22/kernel/power/modules.c suspend2-2.2.10-for-2.6.22/kernel/power/modules.c
5606 --- linux-2.6.22/kernel/power/modules.c 1970-01-01 10:00:00.000000000 +1000
5607 +++ suspend2-2.2.10-for-2.6.22/kernel/power/modules.c 2007-07-11 22:25:42.000000000 +1000
5610 + * kernel/power/modules.c
5612 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
5616 +#include <linux/suspend.h>
5617 +#include <linux/module.h>
5618 +#include "suspend.h"
5619 +#include "modules.h"
5623 +struct list_head suspend_filters, suspendAllocators, suspend_modules;
5624 +struct suspend_module_ops *suspendActiveAllocator;
5625 +int suspend_num_filters;
5626 +int suspendNumAllocators, suspend_num_modules;
5629 +static inline void suspend_initialise_module_lists(void) {
5630 + INIT_LIST_HEAD(&suspend_filters);
5631 + INIT_LIST_HEAD(&suspendAllocators);
5632 + INIT_LIST_HEAD(&suspend_modules);
5636 + * suspend_header_storage_for_modules
5638 + * Returns the amount of space needed to store configuration
5639 + * data needed by the modules prior to copying back the original
5640 + * kernel. We can exclude data for pageset2 because it will be
5641 + * available anyway once the kernel is copied back.
5643 +int suspend_header_storage_for_modules(void)
5645 + struct suspend_module_ops *this_module;
5648 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5649 + if (!this_module->enabled ||
5650 + (this_module->type == WRITER_MODULE &&
5651 + suspendActiveAllocator != this_module))
5653 + if (this_module->storage_needed) {
5654 + int this = this_module->storage_needed() +
5655 + sizeof(struct suspend_module_header) +
5657 + this_module->header_requested = this;
5662 + /* One more for the empty terminator */
5663 + return bytes + sizeof(struct suspend_module_header);
5667 + * suspend_memory_for_modules
5669 + * Returns the amount of memory requested by modules for
5670 + * doing their work during the cycle.
5673 +int suspend_memory_for_modules(void)
5676 + struct suspend_module_ops *this_module;
5678 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5679 + if (!this_module->enabled)
5681 + if (this_module->memory_needed)
5682 + bytes += this_module->memory_needed();
5685 + return ((bytes + PAGE_SIZE - 1) >> PAGE_SHIFT);
5689 + * suspend_expected_compression_ratio
5691 + * Returns the compression ratio expected when saving the image.
5694 +int suspend_expected_compression_ratio(void)
5697 + struct suspend_module_ops *this_module;
5699 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5700 + if (!this_module->enabled)
5702 + if (this_module->expected_compression)
5703 + ratio = ratio * this_module->expected_compression() / 100;
5709 +/* suspend_find_module_given_name
5710 + * Functionality : Return a module (if found), given a pointer
5714 +struct suspend_module_ops *suspend_find_module_given_name(char *name)
5716 + struct suspend_module_ops *this_module, *found_module = NULL;
5718 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5719 + if (!strcmp(name, this_module->name)) {
5720 + found_module = this_module;
5725 + return found_module;
5729 + * suspend_print_module_debug_info
5730 + * Functionality : Get debugging info from modules into a buffer.
5732 +int suspend_print_module_debug_info(char *buffer, int buffer_size)
5734 + struct suspend_module_ops *this_module;
5737 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5738 + if (!this_module->enabled)
5740 + if (this_module->print_debug_info) {
5742 + result = this_module->print_debug_info(buffer + len,
5743 + buffer_size - len);
5748 + /* Ensure null terminated */
5749 + buffer[buffer_size] = 0;
5755 + * suspend_register_module
5757 + * Register a module.
5759 +int suspend_register_module(struct suspend_module_ops *module)
5762 + struct kobject *kobj;
5764 + if (!initialised) {
5765 + suspend_initialise_module_lists();
5769 + module->enabled = 1;
5771 + if (suspend_find_module_given_name(module->name)) {
5772 + printk("Suspend2: Trying to load module %s,"
5773 + " which is already registered.\n",
5778 + switch (module->type) {
5779 + case FILTER_MODULE:
5780 + list_add_tail(&module->type_list,
5781 + &suspend_filters);
5782 + suspend_num_filters++;
5785 + case WRITER_MODULE:
5786 + list_add_tail(&module->type_list,
5787 + &suspendAllocators);
5788 + suspendNumAllocators++;
5795 + printk("Hmmm. Module '%s' has an invalid type."
5796 + " It has been ignored.\n", module->name);
5799 + list_add_tail(&module->module_list, &suspend_modules);
5800 + suspend_num_modules++;
5802 + if (module->directory || module->shared_directory) {
5804 + * Modules may share a directory, but those with shared_dir
5805 + * set must be loaded (via symbol dependencies) after parents
5806 + * and unloaded beforehand.
5808 + if (module->shared_directory) {
5809 + struct suspend_module_ops *shared =
5810 + suspend_find_module_given_name(module->shared_directory);
5812 + printk("Suspend2: Module %s wants to share %s's directory but %s isn't loaded.\n",
5814 + module->shared_directory,
5815 + module->shared_directory);
5816 + suspend_unregister_module(module);
5819 + kobj = shared->dir_kobj;
5821 + kobj = make_suspend2_sysdir(module->directory);
5822 + module->dir_kobj = kobj;
5823 + for (i=0; i < module->num_sysfs_entries; i++) {
5824 + int result = suspend_register_sysfs_file(kobj, &module->sysfs_data[i]);
5830 + printk("Suspend2 %s support registered.\n", module->name);
5835 + * suspend_unregister_module
5837 + * Remove a module.
5839 +void suspend_unregister_module(struct suspend_module_ops *module)
5843 + if (module->dir_kobj)
5844 + for (i=0; i < module->num_sysfs_entries; i++)
5845 + suspend_unregister_sysfs_file(module->dir_kobj, &module->sysfs_data[i]);
5847 + if (!module->shared_directory && module->directory)
5848 + remove_suspend2_sysdir(module->dir_kobj);
5850 + switch (module->type) {
5851 + case FILTER_MODULE:
5852 + list_del(&module->type_list);
5853 + suspend_num_filters--;
5856 + case WRITER_MODULE:
5857 + list_del(&module->type_list);
5858 + suspendNumAllocators--;
5859 + if (suspendActiveAllocator == module) {
5860 + suspendActiveAllocator = NULL;
5861 + clear_suspend_state(SUSPEND_CAN_RESUME);
5862 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
5870 + printk("Hmmm. Module '%s' has an invalid type."
5871 + " It has been ignored.\n", module->name);
5874 + list_del(&module->module_list);
5875 + suspend_num_modules--;
5876 + printk("Suspend2 %s module unloaded.\n", module->name);
5880 + * suspend_move_module_tail
5882 + * Rearrange modules when reloading the config.
5884 +void suspend_move_module_tail(struct suspend_module_ops *module)
5886 + switch (module->type) {
5887 + case FILTER_MODULE:
5888 + if (suspend_num_filters > 1)
5889 + list_move_tail(&module->type_list,
5890 + &suspend_filters);
5893 + case WRITER_MODULE:
5894 + if (suspendNumAllocators > 1)
5895 + list_move_tail(&module->type_list,
5896 + &suspendAllocators);
5902 + printk("Hmmm. Module '%s' has an invalid type."
5903 + " It has been ignored.\n", module->name);
5906 + if ((suspend_num_filters + suspendNumAllocators) > 1)
5907 + list_move_tail(&module->module_list, &suspend_modules);
5911 + * suspend_initialise_modules
5913 + * Get ready to do some work!
5915 +int suspend_initialise_modules(int starting_cycle)
5917 + struct suspend_module_ops *this_module;
5920 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5921 + this_module->header_requested = 0;
5922 + this_module->header_used = 0;
5923 + if (!this_module->enabled)
5925 + if (this_module->initialise) {
5926 + suspend_message(SUSPEND_MEMORY, SUSPEND_MEDIUM, 1,
5927 + "Initialising module %s.\n",
5928 + this_module->name);
5929 + if ((result = this_module->initialise(starting_cycle))) {
5930 + printk("%s didn't initialise okay.\n",
5931 + this_module->name);
5941 + * suspend_cleanup_modules
5943 + * Tell modules the work is done.
5945 +void suspend_cleanup_modules(int finishing_cycle)
5947 + struct suspend_module_ops *this_module;
5949 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5950 + if (!this_module->enabled)
5952 + if (this_module->cleanup) {
5953 + suspend_message(SUSPEND_MEMORY, SUSPEND_MEDIUM, 1,
5954 + "Cleaning up module %s.\n",
5955 + this_module->name);
5956 + this_module->cleanup(finishing_cycle);
5962 + * suspend_get_next_filter
5964 + * Get the next filter in the pipeline.
5966 +struct suspend_module_ops *suspend_get_next_filter(struct suspend_module_ops *filter_sought)
5968 + struct suspend_module_ops *last_filter = NULL, *this_filter = NULL;
5970 + list_for_each_entry(this_filter, &suspend_filters, type_list) {
5971 + if (!this_filter->enabled)
5973 + if ((last_filter == filter_sought) || (!filter_sought))
5974 + return this_filter;
5975 + last_filter = this_filter;
5978 + return suspendActiveAllocator;
5981 +/* suspend_get_modules
5983 + * Take a reference to modules so they can't go away under us.
5986 +int suspend_get_modules(void)
5988 + struct suspend_module_ops *this_module;
5990 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5991 + if (!try_module_get(this_module->module)) {
5992 + /* Failed! Reverse gets and return error */
5993 + struct suspend_module_ops *this_module2;
5994 + list_for_each_entry(this_module2, &suspend_modules, module_list) {
5995 + if (this_module == this_module2)
5997 + module_put(this_module2->module);
6005 +/* suspend_put_modules
6007 + * Release our references to modules we used.
6010 +void suspend_put_modules(void)
6012 + struct suspend_module_ops *this_module;
6014 + list_for_each_entry(this_module, &suspend_modules, module_list)
6015 + module_put(this_module->module);
6018 +#ifdef CONFIG_SUSPEND2_EXPORTS
6019 +EXPORT_SYMBOL_GPL(suspend_register_module);
6020 +EXPORT_SYMBOL_GPL(suspend_unregister_module);
6021 +EXPORT_SYMBOL_GPL(suspend_get_next_filter);
6022 +EXPORT_SYMBOL_GPL(suspendActiveAllocator);
6024 diff -ruN linux-2.6.22/kernel/power/modules.h suspend2-2.2.10-for-2.6.22/kernel/power/modules.h
6025 --- linux-2.6.22/kernel/power/modules.h 1970-01-01 10:00:00.000000000 +1000
6026 +++ suspend2-2.2.10-for-2.6.22/kernel/power/modules.h 2007-07-11 22:25:42.000000000 +1000
6029 + * kernel/power/modules.h
6031 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6033 + * This file is released under the GPLv2.
6035 + * It contains declarations for modules. Modules are additions to
6036 + * suspend2 that provide facilities such as image compression or
6037 + * encryption, backends for storage of the image and user interfaces.
6041 +#ifndef SUSPEND_MODULES_H
6042 +#define SUSPEND_MODULES_H
6044 +/* This is the maximum size we store in the image header for a module name */
6045 +#define SUSPEND_MAX_MODULE_NAME_LENGTH 30
6047 +/* Per-module metadata */
6048 +struct suspend_module_header {
6049 + char name[SUSPEND_MAX_MODULE_NAME_LENGTH];
6054 + unsigned long signature;
6060 + MISC_MODULE /* Block writer, eg. */
6068 +struct suspend_module_ops {
6069 + /* Functions common to all modules */
6073 + char *shared_directory;
6074 + struct kobject *dir_kobj;
6075 + struct module *module;
6077 + struct list_head module_list;
6079 + /* List of filters or allocators */
6080 + struct list_head list, type_list;
6083 + * Requirements for memory and storage in
6084 + * the image header..
6086 + int (*memory_needed) (void);
6087 + int (*storage_needed) (void);
6089 + int header_requested, header_used;
6091 + int (*expected_compression) (void);
6096 + int (*print_debug_info) (char *buffer, int size);
6097 + int (*save_config_info) (char *buffer);
6098 + void (*load_config_info) (char *buffer, int len);
6101 + * Initialise & cleanup - general routines called
6102 + * at the start and end of a cycle.
6104 + int (*initialise) (int starting_cycle);
6105 + void (*cleanup) (int finishing_cycle);
6108 + * Calls for allocating storage (allocators only).
6110 + * Header space is allocated separately. Note that allocation
6111 + * of space for the header might result in allocated space
6112 + * being stolen from the main pool if there is no unallocated
6113 + * space. We have to be able to allocate enough space for
6114 + * the header. We can eat memory to ensure there is enough
6115 + * for the main pool.
6118 + int (*storage_available) (void);
6119 + int (*allocate_header_space) (int space_requested);
6120 + int (*allocate_storage) (int space_requested);
6121 + int (*storage_allocated) (void);
6122 + int (*release_storage) (void);
6125 + * Routines used in image I/O.
6127 + int (*rw_init) (int rw, int stream_number);
6128 + int (*rw_cleanup) (int rw);
6129 + int (*write_chunk) (unsigned long index, struct page *buffer_page,
6130 + unsigned int buf_size);
6131 + int (*read_chunk) (unsigned long *index, struct page *buffer_page,
6132 + unsigned int *buf_size, int sync);
6134 + /* Reset module if image exists but reading aborted */
6135 + void (*noresume_reset) (void);
6137 + /* Read and write the metadata */
6138 + int (*write_header_init) (void);
6139 + int (*write_header_cleanup) (void);
6141 + int (*read_header_init) (void);
6142 + int (*read_header_cleanup) (void);
6144 + int (*rw_header_chunk) (int rw, struct suspend_module_ops *owner,
6145 + char *buffer_start, int buffer_size);
6147 + /* Attempt to parse an image location */
6148 + int (*parse_sig_location) (char *buffer, int only_writer, int quiet);
6150 + /* Determine whether image exists that we can restore */
6151 + int (*image_exists) (void);
6153 + /* Mark the image as having tried to resume */
6154 + void (*mark_resume_attempted) (int);
6156 + /* Destroy image if one exists */
6157 + int (*invalidate_image) (void);
6160 + struct suspend_sysfs_data *sysfs_data;
6161 + int num_sysfs_entries;
6164 +extern int suspend_num_modules, suspendNumAllocators;
6166 +extern struct suspend_module_ops *suspendActiveAllocator;
6167 +extern struct list_head suspend_filters, suspendAllocators, suspend_modules;
6169 +extern void suspend_prepare_console_modules(void);
6170 +extern void suspend_cleanup_console_modules(void);
6172 +extern struct suspend_module_ops *suspend_find_module_given_name(char *name);
6173 +extern struct suspend_module_ops *suspend_get_next_filter(struct suspend_module_ops *);
6175 +extern int suspend_register_module(struct suspend_module_ops *module);
6176 +extern void suspend_move_module_tail(struct suspend_module_ops *module);
6178 +extern int suspend_header_storage_for_modules(void);
6179 +extern int suspend_memory_for_modules(void);
6180 +extern int suspend_expected_compression_ratio(void);
6182 +extern int suspend_print_module_debug_info(char *buffer, int buffer_size);
6183 +extern int suspend_register_module(struct suspend_module_ops *module);
6184 +extern void suspend_unregister_module(struct suspend_module_ops *module);
6186 +extern int suspend_initialise_modules(int starting_cycle);
6187 +extern void suspend_cleanup_modules(int finishing_cycle);
6189 +int suspend_get_modules(void);
6190 +void suspend_put_modules(void);
6192 diff -ruN linux-2.6.22/kernel/power/netlink.c suspend2-2.2.10-for-2.6.22/kernel/power/netlink.c
6193 --- linux-2.6.22/kernel/power/netlink.c 1970-01-01 10:00:00.000000000 +1000
6194 +++ suspend2-2.2.10-for-2.6.22/kernel/power/netlink.c 2007-07-11 22:25:42.000000000 +1000
6197 + * kernel/power/netlink.c
6199 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6201 + * This file is released under the GPLv2.
6203 + * Functions for communicating with a userspace helper via netlink.
6207 +#include <linux/suspend.h>
6208 +#include "netlink.h"
6209 +#include "suspend.h"
6210 +#include "modules.h"
6212 +struct user_helper_data *uhd_list = NULL;
6215 + * Refill our pool of SKBs for use in emergencies (eg, when eating memory and none
6216 + * can be allocated).
6218 +static void suspend_fill_skb_pool(struct user_helper_data *uhd)
6220 + while (uhd->pool_level < uhd->pool_limit) {
6221 + struct sk_buff *new_skb =
6222 + alloc_skb(NLMSG_SPACE(uhd->skb_size), GFP_ATOMIC);
6227 + new_skb->next = uhd->emerg_skbs;
6228 + uhd->emerg_skbs = new_skb;
6229 + uhd->pool_level++;
6234 + * Try to allocate a single skb. If we can't get one, try to use one from
6237 +static struct sk_buff *suspend_get_skb(struct user_helper_data *uhd)
6239 + struct sk_buff *skb =
6240 + alloc_skb(NLMSG_SPACE(uhd->skb_size), GFP_ATOMIC);
6245 + skb = uhd->emerg_skbs;
6247 + uhd->pool_level--;
6248 + uhd->emerg_skbs = skb->next;
6255 +static void put_skb(struct user_helper_data *uhd, struct sk_buff *skb)
6257 + if (uhd->pool_level < uhd->pool_limit) {
6258 + skb->next = uhd->emerg_skbs;
6259 + uhd->emerg_skbs = skb;
6264 +void suspend_send_netlink_message(struct user_helper_data *uhd,
6265 + int type, void* params, size_t len)
6267 + struct sk_buff *skb;
6268 + struct nlmsghdr *nlh;
6270 + struct task_struct *t;
6272 + if (uhd->pid == -1)
6275 + skb = suspend_get_skb(uhd);
6277 + printk("suspend_netlink: Can't allocate skb!\n");
6281 + /* NLMSG_PUT contains a hidden goto nlmsg_failure */
6282 + nlh = NLMSG_PUT(skb, 0, uhd->sock_seq, type, len);
6285 + dest = NLMSG_DATA(nlh);
6286 + if (params && len > 0)
6287 + memcpy(dest, params, len);
6289 + netlink_unicast(uhd->nl, skb, uhd->pid, 0);
6291 + read_lock(&tasklist_lock);
6292 + if ((t = find_task_by_pid(uhd->pid)) == NULL) {
6293 + read_unlock(&tasklist_lock);
6294 + if (uhd->pid > -1)
6295 + printk("Hmm. Can't find the userspace task %d.\n", uhd->pid);
6298 + wake_up_process(t);
6299 + read_unlock(&tasklist_lock);
6307 + put_skb(uhd, skb);
6310 +static void send_whether_debugging(struct user_helper_data *uhd)
6312 + static int is_debugging = 1;
6314 + suspend_send_netlink_message(uhd, NETLINK_MSG_IS_DEBUGGING,
6315 + &is_debugging, sizeof(int));
6319 + * Set the PF_NOFREEZE flag on the given process to ensure it can run whilst we
6322 +static int nl_set_nofreeze(struct user_helper_data *uhd, int pid)
6324 + struct task_struct *t;
6326 + read_lock(&tasklist_lock);
6327 + if ((t = find_task_by_pid(pid)) == NULL) {
6328 + read_unlock(&tasklist_lock);
6329 + printk("Strange. Can't find the userspace task %d.\n", pid);
6333 + t->flags |= PF_NOFREEZE;
6335 + read_unlock(&tasklist_lock);
6338 + suspend_send_netlink_message(uhd, NETLINK_MSG_NOFREEZE_ACK, NULL, 0);
6344 + * Called when the userspace process has informed us that it's ready to roll.
6346 +static int nl_ready(struct user_helper_data *uhd, int version)
6348 + if (version != uhd->interface_version) {
6349 + printk("%s userspace process using invalid interface version."
6350 + " Trying to continue without it.\n",
6352 + if (uhd->not_ready)
6357 + complete(&uhd->wait_for_process);
6362 +void suspend_netlink_close_complete(struct user_helper_data *uhd)
6365 + sock_release(uhd->nl->sk_socket);
6369 + while (uhd->emerg_skbs) {
6370 + struct sk_buff *next = uhd->emerg_skbs->next;
6371 + kfree_skb(uhd->emerg_skbs);
6372 + uhd->emerg_skbs = next;
6377 + suspend_put_modules();
6380 +static int suspend_nl_gen_rcv_msg(struct user_helper_data *uhd,
6381 + struct sk_buff *skb, struct nlmsghdr *nlh)
6387 + /* Let the more specific handler go first. It returns
6388 + * 1 for valid messages that it doesn't know. */
6389 + if ((err = uhd->rcv_msg(skb, nlh)) != 1)
6392 + type = nlh->nlmsg_type;
6394 + /* Only allow one task to receive NOFREEZE privileges */
6395 + if (type == NETLINK_MSG_NOFREEZE_ME && uhd->pid != -1) {
6396 + printk("Received extra nofreeze me requests.\n");
6400 + data = (int*)NLMSG_DATA(nlh);
6403 + case NETLINK_MSG_NOFREEZE_ME:
6404 + if ((err = nl_set_nofreeze(uhd, nlh->nlmsg_pid)) != 0)
6407 + case NETLINK_MSG_GET_DEBUGGING:
6408 + send_whether_debugging(uhd);
6410 + case NETLINK_MSG_READY:
6411 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
6412 + printk("Invalid ready mesage.\n");
6415 + if ((err = nl_ready(uhd, *data)) != 0)
6418 + case NETLINK_MSG_CLEANUP:
6419 + suspend_netlink_close_complete(uhd);
6426 +static void suspend_user_rcv_skb(struct user_helper_data *uhd,
6427 + struct sk_buff *skb)
6430 + struct nlmsghdr *nlh;
6432 + while (skb->len >= NLMSG_SPACE(0)) {
6435 + nlh = (struct nlmsghdr *) skb->data;
6436 + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
6439 + rlen = NLMSG_ALIGN(nlh->nlmsg_len);
6440 + if (rlen > skb->len)
6443 + if ((err = suspend_nl_gen_rcv_msg(uhd, skb, nlh)) != 0)
6444 + netlink_ack(skb, nlh, err);
6445 + else if (nlh->nlmsg_flags & NLM_F_ACK)
6446 + netlink_ack(skb, nlh, 0);
6447 + skb_pull(skb, rlen);
6451 +static void suspend_netlink_input(struct sock *sk, int len)
6453 + struct user_helper_data *uhd = uhd_list;
6455 + while (uhd && uhd->netlink_id != sk->sk_protocol)
6459 + struct sk_buff *skb;
6460 + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
6461 + suspend_user_rcv_skb(uhd, skb);
6462 + put_skb(uhd, skb);
6464 + } while (uhd->nl && uhd->nl->sk_receive_queue.qlen);
6467 +static int netlink_prepare(struct user_helper_data *uhd)
6469 + suspend_get_modules();
6471 + uhd->next = uhd_list;
6474 + uhd->sock_seq = 0x42c0ffee;
6475 + uhd->nl = netlink_kernel_create(uhd->netlink_id, 0,
6476 + suspend_netlink_input, NULL, THIS_MODULE);
6478 + printk("Failed to allocate netlink socket for %s.\n",
6483 + suspend_fill_skb_pool(uhd);
6488 +void suspend_netlink_close(struct user_helper_data *uhd)
6490 + struct task_struct *t;
6492 + read_lock(&tasklist_lock);
6493 + if ((t = find_task_by_pid(uhd->pid)))
6494 + t->flags &= ~PF_NOFREEZE;
6495 + read_unlock(&tasklist_lock);
6497 + suspend_send_netlink_message(uhd, NETLINK_MSG_CLEANUP, NULL, 0);
6500 +static int suspend2_launch_userspace_program(char *command, int channel_no)
6503 + static char *envp[] = {
6506 + "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
6508 + static char *argv[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
6509 + char *channel = kmalloc(6, GFP_KERNEL);
6510 + int arg = 0, size;
6511 + char test_read[255];
6512 + char *orig_posn = command;
6514 + if (!strlen(orig_posn))
6517 + /* Up to 7 args supported */
6519 + sscanf(orig_posn, "%s", test_read);
6520 + size = strlen(test_read);
6523 + argv[arg] = kmalloc(size + 1, GFP_ATOMIC);
6524 + strcpy(argv[arg], test_read);
6525 + orig_posn += size + 1;
6531 + sprintf(channel, "-c%d", channel_no);
6532 + argv[arg] = channel;
6536 + retval = call_usermodehelper(argv[0], argv, envp, 0);
6539 + printk("Failed to launch userspace program '%s': Error %d\n",
6544 + for (i = 0; i < arg; i++)
6545 + if (argv[i] && argv[i] != channel)
6554 +int suspend_netlink_setup(struct user_helper_data *uhd)
6556 + if (netlink_prepare(uhd) < 0) {
6557 + printk("Netlink prepare failed.\n");
6561 + if (suspend2_launch_userspace_program(uhd->program, uhd->netlink_id) < 0) {
6562 + printk("Launch userspace program failed.\n");
6563 + suspend_netlink_close_complete(uhd);
6567 + /* Wait 2 seconds for the userspace process to make contact */
6568 + wait_for_completion_timeout(&uhd->wait_for_process, 2*HZ);
6570 + if (uhd->pid == -1) {
6571 + printk("%s: Failed to contact userspace process.\n",
6573 + suspend_netlink_close_complete(uhd);
6580 +EXPORT_SYMBOL_GPL(suspend_netlink_setup);
6581 +EXPORT_SYMBOL_GPL(suspend_netlink_close);
6582 +EXPORT_SYMBOL_GPL(suspend_send_netlink_message);
6583 diff -ruN linux-2.6.22/kernel/power/netlink.h suspend2-2.2.10-for-2.6.22/kernel/power/netlink.h
6584 --- linux-2.6.22/kernel/power/netlink.h 1970-01-01 10:00:00.000000000 +1000
6585 +++ suspend2-2.2.10-for-2.6.22/kernel/power/netlink.h 2007-07-11 22:25:42.000000000 +1000
6588 + * kernel/power/netlink.h
6590 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6592 + * This file is released under the GPLv2.
6594 + * Declarations for functions for communicating with a userspace helper
6598 +#include <linux/netlink.h>
6599 +#include <net/sock.h>
6601 +#define NETLINK_MSG_BASE 0x10
6603 +#define NETLINK_MSG_READY 0x10
6604 +#define NETLINK_MSG_NOFREEZE_ME 0x16
6605 +#define NETLINK_MSG_GET_DEBUGGING 0x19
6606 +#define NETLINK_MSG_CLEANUP 0x24
6607 +#define NETLINK_MSG_NOFREEZE_ACK 0x27
6608 +#define NETLINK_MSG_IS_DEBUGGING 0x28
6610 +struct user_helper_data {
6611 + int (*rcv_msg) (struct sk_buff *skb, struct nlmsghdr *nlh);
6612 + void (* not_ready) (void);
6617 + char program[256];
6620 + struct sk_buff *emerg_skbs;
6624 + struct user_helper_data *next;
6625 + struct completion wait_for_process;
6626 + int interface_version;
6631 +int suspend_netlink_setup(struct user_helper_data *uhd);
6632 +void suspend_netlink_close(struct user_helper_data *uhd);
6633 +void suspend_send_netlink_message(struct user_helper_data *uhd,
6634 + int type, void* params, size_t len);
6636 +static inline int suspend_netlink_setup(struct user_helper_data *uhd)
6641 +static inline void suspend_netlink_close(struct user_helper_data *uhd) { };
6642 +static inline void suspend_send_netlink_message(struct user_helper_data *uhd,
6643 + int type, void* params, size_t len) { };
6645 diff -ruN linux-2.6.22/kernel/power/pagedir.c suspend2-2.2.10-for-2.6.22/kernel/power/pagedir.c
6646 --- linux-2.6.22/kernel/power/pagedir.c 1970-01-01 10:00:00.000000000 +1000
6647 +++ suspend2-2.2.10-for-2.6.22/kernel/power/pagedir.c 2007-07-11 22:25:42.000000000 +1000
6650 + * kernel/power/pagedir.c
6652 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
6653 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
6654 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
6655 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
6657 + * This file is released under the GPLv2.
6659 + * Routines for handling pagesets.
6660 + * Note that pbes aren't actually stored as such. They're stored as
6661 + * bitmaps and extents.
6664 +#include <linux/suspend.h>
6665 +#include <linux/highmem.h>
6666 +#include <linux/bootmem.h>
6667 +#include <linux/hardirq.h>
6668 +#include <linux/sched.h>
6669 +#include <asm/tlbflush.h>
6671 +#include "pageflags.h"
6673 +#include "pagedir.h"
6674 +#include "prepare_image.h"
6675 +#include "suspend.h"
6677 +#include "suspend2_builtin.h"
6682 +static int ps2_pfn;
6685 + * suspend_mark_task_as_pageset
6686 + * Functionality : Marks all the saveable pages belonging to a given process
6687 + * as belonging to a particular pageset.
6690 +static void suspend_mark_task_as_pageset(struct task_struct *t, int pageset2)
6692 + struct vm_area_struct *vma;
6693 + struct mm_struct *mm;
6695 + mm = t->active_mm;
6697 + if (!mm || !mm->mmap) return;
6699 + if (!irqs_disabled())
6700 + down_read(&mm->mmap_sem);
6702 + for (vma = mm->mmap; vma; vma = vma->vm_next) {
6703 + unsigned long posn;
6705 + if (vma->vm_flags & (VM_PFNMAP | VM_IO | VM_RESERVED)) {
6706 + printk("Skipping vma %p in process %d (%s) which has "
6707 + "VM_PFNMAP | VM_IO | VM_RESERVED (%lx).\n", vma,
6708 + t->pid, t->comm, vma->vm_flags);
6712 + if (!vma->vm_start)
6715 + for (posn = vma->vm_start; posn < vma->vm_end;
6716 + posn += PAGE_SIZE) {
6717 + struct page *page = follow_page(vma, posn, 0);
6722 + SetPagePageset2(page);
6724 + ClearPagePageset2(page);
6725 + SetPagePageset1(page);
6730 + if (!irqs_disabled())
6731 + up_read(&mm->mmap_sem);
6734 +static void pageset2_full(void)
6736 + struct zone *zone;
6737 + unsigned long flags;
6739 + for_each_zone(zone) {
6740 + spin_lock_irqsave(&zone->lru_lock, flags);
6741 + if (zone_page_state(zone, NR_INACTIVE)) {
6742 + struct page *page;
6743 + list_for_each_entry(page, &zone->inactive_list, lru)
6744 + SetPagePageset2(page);
6746 + if (zone_page_state(zone, NR_ACTIVE)) {
6747 + struct page *page;
6748 + list_for_each_entry(page, &zone->active_list, lru)
6749 + SetPagePageset2(page);
6751 + spin_unlock_irqrestore(&zone->lru_lock, flags);
6755 +/* mark_pages_for_pageset2
6757 + * Description: Mark unshared pages in processes not needed for suspend as
6758 + * being able to be written out in a separate pagedir.
6759 + * HighMem pages are simply marked as pageset2. They won't be
6760 + * needed during suspend.
6763 +struct attention_list {
6764 + struct task_struct *task;
6765 + struct attention_list *next;
6768 +void suspend_mark_pages_for_pageset2(void)
6770 + struct task_struct *p;
6771 + struct attention_list *attention_list = NULL, *last = NULL, *next;
6772 + int i, task_count = 0;
6774 + if (test_action_state(SUSPEND_NO_PAGESET2))
6777 + clear_dyn_pageflags(pageset2_map);
6779 + if (test_action_state(SUSPEND_PAGESET2_FULL))
6782 + read_lock(&tasklist_lock);
6783 + for_each_process(p) {
6784 + if (!p->mm || (p->flags & PF_BORROWED_MM))
6787 + suspend_mark_task_as_pageset(p, PAGESET2);
6789 + read_unlock(&tasklist_lock);
6793 + * Now we count all userspace process (with task->mm) marked PF_NOFREEZE.
6795 + read_lock(&tasklist_lock);
6796 + for_each_process(p)
6797 + if ((p->flags & PF_NOFREEZE) || p == current)
6799 + read_unlock(&tasklist_lock);
6802 + * Allocate attention list structs.
6804 + for (i = 0; i < task_count; i++) {
6805 + struct attention_list *this =
6806 + kmalloc(sizeof(struct attention_list), GFP_ATOMIC);
6808 + printk("Failed to allocate slab for attention list.\n");
6809 + set_result_state(SUSPEND_ABORTED);
6810 + goto free_attention_list;
6812 + this->next = NULL;
6813 + if (attention_list) {
6814 + last->next = this;
6817 + attention_list = last = this;
6820 + next = attention_list;
6821 + read_lock(&tasklist_lock);
6822 + for_each_process(p)
6823 + if ((p->flags & PF_NOFREEZE) || p == current) {
6825 + next = next->next;
6827 + read_unlock(&tasklist_lock);
6830 + * Because the tasks in attention_list are ones related to suspending,
6831 + * we know that they won't go away under us.
6834 +free_attention_list:
6835 + while (attention_list) {
6836 + if (!test_result_state(SUSPEND_ABORTED))
6837 + suspend_mark_task_as_pageset(attention_list->task, PAGESET1);
6838 + last = attention_list;
6839 + attention_list = attention_list->next;
6844 +void suspend_reset_alt_image_pageset2_pfn(void)
6846 + ps2_pfn = max_pfn + 1;
6849 +static struct page *first_conflicting_page;
6852 + * free_conflicting_pages
6855 +void free_conflicting_pages(void)
6857 + while (first_conflicting_page) {
6858 + struct page *next = *((struct page **) kmap(first_conflicting_page));
6859 + kunmap(first_conflicting_page);
6860 + __free_page(first_conflicting_page);
6861 + first_conflicting_page = next;
6865 +/* __suspend_get_nonconflicting_page
6867 + * Description: Gets order zero pages that won't be overwritten
6868 + * while copying the original pages.
6871 +struct page * ___suspend_get_nonconflicting_page(int can_be_highmem)
6873 + struct page *page;
6874 + int flags = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
6875 + if (can_be_highmem)
6876 + flags |= __GFP_HIGHMEM;
6879 + if (test_suspend_state(SUSPEND_LOADING_ALT_IMAGE) && pageset2_map &&
6880 + (ps2_pfn < (max_pfn + 2))) {
6882 + * ps2_pfn = max_pfn + 1 when yet to find first ps2 pfn that can
6884 + * = 0..max_pfn when going through list.
6885 + * = max_pfn + 2 when gone through whole list.
6888 + ps2_pfn = get_next_bit_on(pageset2_map, ps2_pfn);
6889 + if (ps2_pfn <= max_pfn) {
6890 + page = pfn_to_page(ps2_pfn);
6891 + if (!PagePageset1(page) &&
6892 + (can_be_highmem || !PageHighMem(page)))
6896 + } while (ps2_pfn < max_pfn);
6900 + page = alloc_pages(flags, 0);
6902 + printk("Failed to get nonconflicting page.\n");
6905 + if (PagePageset1(page)) {
6906 + struct page **next = (struct page **) kmap(page);
6907 + *next = first_conflicting_page;
6908 + first_conflicting_page = page;
6911 + } while(PagePageset1(page));
6916 +unsigned long __suspend_get_nonconflicting_page(void)
6918 + struct page *page = ___suspend_get_nonconflicting_page(0);
6919 + return page ? (unsigned long) page_address(page) : 0;
6922 +struct pbe *get_next_pbe(struct page **page_ptr, struct pbe *this_pbe, int highmem)
6924 + if (((((unsigned long) this_pbe) & (PAGE_SIZE - 1))
6925 + + 2 * sizeof(struct pbe)) > PAGE_SIZE) {
6926 + struct page *new_page =
6927 + ___suspend_get_nonconflicting_page(highmem);
6929 + return ERR_PTR(-ENOMEM);
6930 + this_pbe = (struct pbe *) kmap(new_page);
6931 + memset(this_pbe, 0, PAGE_SIZE);
6932 + *page_ptr = new_page;
6939 +/* get_pageset1_load_addresses
6941 + * Description: We check here that pagedir & pages it points to won't collide
6942 + * with pages where we're going to restore from the loaded pages
6944 + * Returns: Zero on success, one if couldn't find enough pages (shouldn't
6948 +int suspend_get_pageset1_load_addresses(void)
6950 + int pfn, highallocd = 0, lowallocd = 0;
6951 + int low_needed = pagedir1.size - get_highmem_size(pagedir1);
6952 + int high_needed = get_highmem_size(pagedir1);
6953 + int low_pages_for_highmem = 0;
6954 + unsigned long flags = GFP_ATOMIC | __GFP_NOWARN | __GFP_HIGHMEM;
6955 + struct page *page, *high_pbe_page = NULL, *last_high_pbe_page = NULL,
6957 + struct pbe **last_low_pbe_ptr = &restore_pblist,
6958 + **last_high_pbe_ptr = &restore_highmem_pblist,
6959 + *this_low_pbe = NULL, *this_high_pbe = NULL;
6960 + int orig_low_pfn = max_pfn + 1, orig_high_pfn = max_pfn + 1;
6961 + int high_pbes_done=0, low_pbes_done=0;
6962 + int low_direct = 0, high_direct = 0;
6963 + int high_to_free, low_to_free;
6965 + /* First, allocate pages for the start of our pbe lists. */
6966 + if (high_needed) {
6967 + high_pbe_page = ___suspend_get_nonconflicting_page(1);
6968 + if (!high_pbe_page)
6970 + this_high_pbe = (struct pbe *) kmap(high_pbe_page);
6971 + memset(this_high_pbe, 0, PAGE_SIZE);
6974 + low_pbe_page = ___suspend_get_nonconflicting_page(0);
6975 + if (!low_pbe_page)
6977 + this_low_pbe = (struct pbe *) page_address(low_pbe_page);
6980 + * Next, allocate all possible memory to find where we can
6981 + * load data directly into destination pages. I'd like to do
6982 + * this in bigger chunks, but then we can't free pages
6983 + * individually later.
6987 + page = alloc_pages(flags, 0);
6989 + SetPagePageset1Copy(page);
6993 + * Find out how many high- and lowmem pages we allocated above,
6994 + * and how many pages we can reload directly to their original
6997 + BITMAP_FOR_EACH_SET(pageset1_copy_map, pfn) {
6999 + page = pfn_to_page(pfn);
7000 + is_high = PageHighMem(page);
7002 + if (PagePageset1(page)) {
7003 + if (test_action_state(SUSPEND_NO_DIRECT_LOAD)) {
7004 + ClearPagePageset1Copy(page);
7005 + __free_page(page);
7021 + high_needed-= high_direct;
7022 + low_needed-= low_direct;
7025 + * Do we need to use some lowmem pages for the copies of highmem
7028 + if (high_needed > highallocd) {
7029 + low_pages_for_highmem = high_needed - highallocd;
7030 + high_needed -= low_pages_for_highmem;
7031 + low_needed += low_pages_for_highmem;
7034 + high_to_free = highallocd - high_needed;
7035 + low_to_free = lowallocd - low_needed;
7038 + * Now generate our pbes (which will be used for the atomic restore,
7039 + * and free unneeded pages.
7041 + BITMAP_FOR_EACH_SET(pageset1_copy_map, pfn) {
7043 + page = pfn_to_page(pfn);
7044 + is_high = PageHighMem(page);
7046 + if (PagePageset1(page))
7049 + /* Free the page? */
7050 + if ((is_high && high_to_free) ||
7051 + (!is_high && low_to_free)) {
7052 + ClearPagePageset1Copy(page);
7053 + __free_page(page);
7061 + /* Nope. We're going to use this page. Add a pbe. */
7062 + if (is_high || low_pages_for_highmem) {
7063 + struct page *orig_page;
7066 + low_pages_for_highmem--;
7068 + orig_high_pfn = get_next_bit_on(pageset1_map,
7070 + BUG_ON(orig_high_pfn > max_pfn);
7071 + orig_page = pfn_to_page(orig_high_pfn);
7072 + } while(!PageHighMem(orig_page) || load_direct(orig_page));
7074 + this_high_pbe->orig_address = orig_page;
7075 + this_high_pbe->address = page;
7076 + this_high_pbe->next = NULL;
7077 + if (last_high_pbe_page != high_pbe_page) {
7078 + *last_high_pbe_ptr = (struct pbe *) high_pbe_page;
7079 + if (!last_high_pbe_page)
7080 + last_high_pbe_page = high_pbe_page;
7082 + *last_high_pbe_ptr = this_high_pbe;
7083 + last_high_pbe_ptr = &this_high_pbe->next;
7084 + if (last_high_pbe_page != high_pbe_page) {
7085 + kunmap(last_high_pbe_page);
7086 + last_high_pbe_page = high_pbe_page;
7088 + this_high_pbe = get_next_pbe(&high_pbe_page, this_high_pbe, 1);
7089 + if (IS_ERR(this_high_pbe)) {
7090 + printk("This high pbe is an error.\n");
7094 + struct page *orig_page;
7097 + orig_low_pfn = get_next_bit_on(pageset1_map,
7099 + BUG_ON(orig_low_pfn > max_pfn);
7100 + orig_page = pfn_to_page(orig_low_pfn);
7101 + } while(PageHighMem(orig_page) || load_direct(orig_page));
7103 + this_low_pbe->orig_address = page_address(orig_page);
7104 + this_low_pbe->address = page_address(page);
7105 + this_low_pbe->next = NULL;
7106 + *last_low_pbe_ptr = this_low_pbe;
7107 + last_low_pbe_ptr = &this_low_pbe->next;
7108 + this_low_pbe = get_next_pbe(&low_pbe_page, this_low_pbe, 0);
7109 + if (IS_ERR(this_low_pbe)) {
7110 + printk("this_low_pbe is an error.\n");
7116 + if (high_pbe_page)
7117 + kunmap(high_pbe_page);
7119 + if (last_high_pbe_page != high_pbe_page) {
7120 + if (last_high_pbe_page)
7121 + kunmap(last_high_pbe_page);
7122 + __free_page(high_pbe_page);
7125 + free_conflicting_pages();
7129 diff -ruN linux-2.6.22/kernel/power/pagedir.h suspend2-2.2.10-for-2.6.22/kernel/power/pagedir.h
7130 --- linux-2.6.22/kernel/power/pagedir.h 1970-01-01 10:00:00.000000000 +1000
7131 +++ suspend2-2.2.10-for-2.6.22/kernel/power/pagedir.h 2007-07-11 22:25:42.000000000 +1000
7134 + * kernel/power/pagedir.h
7136 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7138 + * This file is released under the GPLv2.
7140 + * Declarations for routines for handling pagesets.
7143 +#ifndef KERNEL_POWER_PAGEDIR_H
7144 +#define KERNEL_POWER_PAGEDIR_H
7148 + * Contains the metadata for a set of pages saved in the image.
7154 +#ifdef CONFIG_HIGHMEM
7159 +#ifdef CONFIG_HIGHMEM
7160 +#define get_highmem_size(pagedir) (pagedir.size_high)
7161 +#define set_highmem_size(pagedir, sz) do { pagedir.size_high = sz; } while(0)
7162 +#define inc_highmem_size(pagedir) do { pagedir.size_high++; } while(0)
7163 +#define get_lowmem_size(pagedir) (pagedir.size - pagedir.size_high)
7165 +#define get_highmem_size(pagedir) (0)
7166 +#define set_highmem_size(pagedir, sz) do { } while(0)
7167 +#define inc_highmem_size(pagedir) do { } while(0)
7168 +#define get_lowmem_size(pagedir) (pagedir.size)
7171 +extern struct pagedir pagedir1, pagedir2;
7173 +extern void suspend_copy_pageset1(void);
7175 +extern void suspend_mark_pages_for_pageset2(void);
7177 +extern int suspend_get_pageset1_load_addresses(void);
7179 +extern unsigned long __suspend_get_nonconflicting_page(void);
7180 +struct page * ___suspend_get_nonconflicting_page(int can_be_highmem);
7182 +extern void suspend_reset_alt_image_pageset2_pfn(void);
7184 diff -ruN linux-2.6.22/kernel/power/pageflags.c suspend2-2.2.10-for-2.6.22/kernel/power/pageflags.c
7185 --- linux-2.6.22/kernel/power/pageflags.c 1970-01-01 10:00:00.000000000 +1000
7186 +++ suspend2-2.2.10-for-2.6.22/kernel/power/pageflags.c 2007-07-11 22:25:42.000000000 +1000
7189 + * kernel/power/pageflags.c
7191 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7193 + * This file is released under the GPLv2.
7195 + * Routines for serialising and relocating pageflags in which we
7196 + * store our image metadata.
7199 +#include <linux/kernel.h>
7200 +#include <linux/mm.h>
7201 +#include <linux/module.h>
7202 +#include <linux/bitops.h>
7203 +#include <linux/list.h>
7204 +#include <linux/suspend.h>
7205 +#include "pageflags.h"
7206 +#include "modules.h"
7207 +#include "pagedir.h"
7208 +#include "suspend.h"
7210 +dyn_pageflags_t pageset2_map;
7211 +dyn_pageflags_t page_resave_map;
7212 +dyn_pageflags_t io_map;
7213 +dyn_pageflags_t nosave_map;
7214 +dyn_pageflags_t free_map;
7216 +static int pages_for_zone(struct zone *zone)
7218 + return DIV_ROUND_UP(zone->spanned_pages, (PAGE_SIZE << 3));
7221 +int suspend_pageflags_space_needed(void)
7224 + struct zone *zone;
7226 + for_each_zone(zone)
7227 + if (populated_zone(zone))
7228 + total += sizeof(int) * 3 + pages_for_zone(zone) * PAGE_SIZE;
7230 + total += sizeof(int);
7235 +/* save_dyn_pageflags
7237 + * Description: Save a set of pageflags.
7238 + * Arguments: dyn_pageflags_t *: Pointer to the bitmap being saved.
7241 +void save_dyn_pageflags(dyn_pageflags_t pagemap)
7243 + int i, zone_idx, size, node = 0;
7244 + struct zone *zone;
7245 + struct pglist_data *pgdat;
7250 + for_each_online_pgdat(pgdat) {
7251 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
7252 + zone = &pgdat->node_zones[zone_idx];
7254 + if (!populated_zone(zone))
7257 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7258 + (char *) &node, sizeof(int));
7259 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7260 + (char *) &zone_idx, sizeof(int));
7261 + size = pages_for_zone(zone);
7262 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7263 + (char *) &size, sizeof(int));
7265 + for (i = 0; i < size; i++)
7266 + suspendActiveAllocator->rw_header_chunk(WRITE,
7267 + NULL, (char *) pagemap[node][zone_idx][i],
7273 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7274 + (char *) &node, sizeof(int));
7277 +/* load_dyn_pageflags
7279 + * Description: Load a set of pageflags.
7280 + * Arguments: dyn_pageflags_t *: Pointer to the bitmap being loaded.
7281 + * (It must be allocated before calling this routine).
7284 +int load_dyn_pageflags(dyn_pageflags_t pagemap)
7286 + int i, zone_idx, zone_check = 0, size, node = 0;
7287 + struct zone *zone;
7288 + struct pglist_data *pgdat;
7293 + for_each_online_pgdat(pgdat) {
7294 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
7295 + zone = &pgdat->node_zones[zone_idx];
7297 + if (!populated_zone(zone))
7301 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7302 + (char *) &zone_check, sizeof(int));
7303 + if (zone_check != node) {
7304 + printk("Node read (%d) != node (%d).\n",
7305 + zone_check, node);
7310 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7311 + (char *) &zone_check, sizeof(int));
7312 + if (zone_check != zone_idx) {
7313 + printk("Zone read (%d) != node (%d).\n",
7314 + zone_check, zone_idx);
7319 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7320 + (char *) &size, sizeof(int));
7322 + for (i = 0; i < size; i++)
7323 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7324 + (char *) pagemap[node][zone_idx][i],
7329 + suspendActiveAllocator->rw_header_chunk(READ, NULL, (char *) &zone_check,
7331 + if (zone_check != -1) {
7332 + printk("Didn't read end of dyn pageflag data marker.(%x)\n",
7339 diff -ruN linux-2.6.22/kernel/power/pageflags.h suspend2-2.2.10-for-2.6.22/kernel/power/pageflags.h
7340 --- linux-2.6.22/kernel/power/pageflags.h 1970-01-01 10:00:00.000000000 +1000
7341 +++ suspend2-2.2.10-for-2.6.22/kernel/power/pageflags.h 2007-07-11 22:25:42.000000000 +1000
7344 + * kernel/power/pageflags.h
7346 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7348 + * This file is released under the GPLv2.
7350 + * Suspend2 needs a few pageflags while working that aren't otherwise
7351 + * used. To save the struct page pageflags, we dynamically allocate
7352 + * a bitmap and use that. These are the only non order-0 allocations
7356 + * We assume that PAGE_SIZE - sizeof(void *) is a multiple of
7357 + * sizeof(unsigned long). Is this ever false?
7360 +#include <linux/dyn_pageflags.h>
7361 +#include <linux/suspend.h>
7363 +extern dyn_pageflags_t pageset1_map;
7364 +extern dyn_pageflags_t pageset1_copy_map;
7365 +extern dyn_pageflags_t pageset2_map;
7366 +extern dyn_pageflags_t page_resave_map;
7367 +extern dyn_pageflags_t io_map;
7368 +extern dyn_pageflags_t nosave_map;
7369 +extern dyn_pageflags_t free_map;
7371 +#define PagePageset1(page) (test_dynpageflag(&pageset1_map, page))
7372 +#define SetPagePageset1(page) (set_dynpageflag(&pageset1_map, page))
7373 +#define ClearPagePageset1(page) (clear_dynpageflag(&pageset1_map, page))
7375 +#define PagePageset1Copy(page) (test_dynpageflag(&pageset1_copy_map, page))
7376 +#define SetPagePageset1Copy(page) (set_dynpageflag(&pageset1_copy_map, page))
7377 +#define ClearPagePageset1Copy(page) (clear_dynpageflag(&pageset1_copy_map, page))
7379 +#define PagePageset2(page) (test_dynpageflag(&pageset2_map, page))
7380 +#define SetPagePageset2(page) (set_dynpageflag(&pageset2_map, page))
7381 +#define ClearPagePageset2(page) (clear_dynpageflag(&pageset2_map, page))
7383 +#define PageWasRW(page) (test_dynpageflag(&pageset2_map, page))
7384 +#define SetPageWasRW(page) (set_dynpageflag(&pageset2_map, page))
7385 +#define ClearPageWasRW(page) (clear_dynpageflag(&pageset2_map, page))
7387 +#define PageResave(page) (page_resave_map ? test_dynpageflag(&page_resave_map, page) : 0)
7388 +#define SetPageResave(page) (set_dynpageflag(&page_resave_map, page))
7389 +#define ClearPageResave(page) (clear_dynpageflag(&page_resave_map, page))
7391 +#define PageNosave(page) (nosave_map ? test_dynpageflag(&nosave_map, page) : 0)
7392 +#define SetPageNosave(page) (set_dynpageflag(&nosave_map, page))
7393 +#define ClearPageNosave(page) (clear_dynpageflag(&nosave_map, page))
7395 +#define PageNosaveFree(page) (free_map ? test_dynpageflag(&free_map, page) : 0)
7396 +#define SetPageNosaveFree(page) (set_dynpageflag(&free_map, page))
7397 +#define ClearPageNosaveFree(page) (clear_dynpageflag(&free_map, page))
7399 +extern void save_dyn_pageflags(dyn_pageflags_t pagemap);
7400 +extern int load_dyn_pageflags(dyn_pageflags_t pagemap);
7401 +extern int suspend_pageflags_space_needed(void);
7402 diff -ruN linux-2.6.22/kernel/power/power.h suspend2-2.2.10-for-2.6.22/kernel/power/power.h
7403 --- linux-2.6.22/kernel/power/power.h 2007-07-11 22:19:41.000000000 +1000
7404 +++ suspend2-2.2.10-for-2.6.22/kernel/power/power.h 2007-07-11 22:25:42.000000000 +1000
7407 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7410 #include <linux/suspend.h>
7411 #include <linux/utsname.h>
7412 +#include "suspend.h"
7413 +#include "suspend2_builtin.h"
7415 struct swsusp_info {
7416 struct new_utsname uts;
7421 -#ifdef CONFIG_SOFTWARE_SUSPEND
7422 +#ifdef CONFIG_SUSPEND_SHARED
7424 +extern char resume_file[256];
7427 * Keep some memory free so that I/O operations can succeed without paging
7428 * [Might this be more than 4 MB?]
7431 extern struct kset power_subsys;
7433 +extern struct pbe *restore_pblist;
7435 /* Preferred image size in bytes (default 500 MB) */
7436 extern unsigned long image_size;
7437 extern int in_suspend;
7438 @@ -165,3 +176,11 @@
7440 extern void swsusp_show_speed(struct timeval *, struct timeval *,
7441 unsigned int, char *);
7442 +extern struct page *saveable_page(unsigned long pfn);
7443 +#ifdef CONFIG_HIGHMEM
7444 +extern struct page *saveable_highmem_page(unsigned long pfn);
7446 +static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
7449 +#define PBES_PER_PAGE (PAGE_SIZE / sizeof(struct pbe))
7450 diff -ruN linux-2.6.22/kernel/power/power_off.c suspend2-2.2.10-for-2.6.22/kernel/power/power_off.c
7451 --- linux-2.6.22/kernel/power/power_off.c 1970-01-01 10:00:00.000000000 +1000
7452 +++ suspend2-2.2.10-for-2.6.22/kernel/power/power_off.c 2007-07-11 22:25:42.000000000 +1000
7455 + * kernel/power/power_off.c
7457 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7459 + * This file is released under the GPLv2.
7461 + * Support for powering down.
7464 +#include <linux/device.h>
7465 +#include <linux/suspend.h>
7466 +#include <linux/mm.h>
7467 +#include <linux/pm.h>
7468 +#include <linux/reboot.h>
7469 +#include <linux/cpu.h>
7470 +#include <linux/console.h>
7471 +#include "suspend.h"
7473 +#include "power_off.h"
7476 +unsigned long suspend2_poweroff_method = 0; /* 0 - Kernel power off */
7478 +extern struct hibernation_ops *hibernation_ops;
7480 +int suspend2_platform_prepare(void)
7482 + if (suspend2_poweroff_method == 4 && hibernation_ops)
7483 + return hibernation_ops->prepare();
7489 + * suspend2_power_down
7490 + * Functionality : Powers down or reboots the computer once the image
7491 + * has been written to disk.
7492 + * Key Assumptions : Able to reboot/power down via code called or that
7493 + * the warning emitted if the calls fail will be visible
7494 + * to the user (ie printk resumes devices).
7495 + * Called From : do_suspend2_suspend_2
7498 +void suspend2_power_down(void)
7502 + if (test_action_state(SUSPEND_REBOOT)) {
7503 + suspend_prepare_status(DONT_CLEAR_BAR, "Ready to reboot.");
7504 + kernel_restart(NULL);
7507 + suspend_prepare_status(DONT_CLEAR_BAR, "Powering down.");
7509 + switch (suspend2_poweroff_method) {
7513 + suspend_console();
7515 + if (device_suspend(PMSG_SUSPEND)) {
7516 + suspend_prepare_status(DONT_CLEAR_BAR, "Device "
7517 + "suspend failure.");
7518 + goto ResumeConsole;
7522 + (pm_ops->prepare && pm_ops->prepare(PM_SUSPEND_MEM)))
7523 + goto DeviceResume;
7525 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) &&
7526 + disable_nonboot_cpus())
7529 + if (!suspend_enter(PM_SUSPEND_MEM))
7532 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
7533 + enable_nonboot_cpus();
7536 + if (pm_ops->finish)
7537 + pm_ops->finish(PM_SUSPEND_MEM);
7545 + /* If suspended to ram and later woke. */
7550 + kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
7551 + hibernation_ops->enter();
7555 + (pm_ops->prepare && pm_ops->prepare(PM_SUSPEND_MAX)))
7558 + kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
7559 + suspend_enter(suspend2_poweroff_method);
7561 + /* Failed. Fall back to kernel_power_off etc. */
7562 + if (pm_ops->finish)
7563 + pm_ops->finish(PM_SUSPEND_MAX);
7566 + suspend_prepare_status(DONT_CLEAR_BAR, "Falling back to alternate power off method.");
7567 + kernel_power_off();
7569 + suspend_prepare_status(DONT_CLEAR_BAR, "Powerdown failed.");
7574 +void suspend2_platform_finish(void)
7576 + if (suspend2_poweroff_method == 4 && hibernation_ops)
7577 + hibernation_ops->finish();
7580 +EXPORT_SYMBOL_GPL(suspend2_poweroff_method);
7581 +EXPORT_SYMBOL_GPL(suspend2_power_down);
7582 diff -ruN linux-2.6.22/kernel/power/power_off.h suspend2-2.2.10-for-2.6.22/kernel/power/power_off.h
7583 --- linux-2.6.22/kernel/power/power_off.h 1970-01-01 10:00:00.000000000 +1000
7584 +++ suspend2-2.2.10-for-2.6.22/kernel/power/power_off.h 2007-07-11 22:25:42.000000000 +1000
7587 + * kernel/power/power_off.h
7589 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7591 + * This file is released under the GPLv2.
7593 + * Support for the powering down.
7596 +int suspend_pm_state_finish(void);
7597 +void suspend2_power_down(void);
7598 +extern unsigned long suspend2_poweroff_method;
7599 +extern int suspend2_platform_prepare(void);
7600 +extern void suspend2_platform_finish(void);
7601 diff -ruN linux-2.6.22/kernel/power/prepare_image.c suspend2-2.2.10-for-2.6.22/kernel/power/prepare_image.c
7602 --- linux-2.6.22/kernel/power/prepare_image.c 1970-01-01 10:00:00.000000000 +1000
7603 +++ suspend2-2.2.10-for-2.6.22/kernel/power/prepare_image.c 2007-07-11 22:25:42.000000000 +1000
7606 + * kernel/power/prepare_image.c
7608 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
7610 + * This file is released under the GPLv2.
7612 + * We need to eat memory until we can:
7613 + * 1. Perform the save without changing anything (RAM_NEEDED < #pages)
7614 + * 2. Fit it all in available space (suspendActiveAllocator->available_space() >=
7615 + * main_storage_needed())
7616 + * 3. Reload the pagedir and pageset1 to places that don't collide with their
7617 + * final destinations, not knowing to what extent the resumed kernel will
7618 + * overlap with the one loaded at boot time. I think the resumed kernel
7619 + * should overlap completely, but I don't want to rely on this as it is
7620 + * an unproven assumption. We therefore assume there will be no overlap at
7621 + * all (worse case).
7622 + * 4. Meet the user's requested limit (if any) on the size of the image.
7623 + * The limit is in MB, so pages/256 (assuming 4K pages).
7627 +#include <linux/module.h>
7628 +#include <linux/highmem.h>
7629 +#include <linux/freezer.h>
7630 +#include <linux/hardirq.h>
7631 +#include <linux/mmzone.h>
7632 +#include <linux/console.h>
7634 +#include "pageflags.h"
7635 +#include "modules.h"
7638 +#include "extent.h"
7639 +#include "prepare_image.h"
7640 +#include "block_io.h"
7641 +#include "suspend.h"
7642 +#include "checksum.h"
7645 +static int num_nosave = 0;
7646 +static int header_space_allocated = 0;
7647 +static int main_storage_allocated = 0;
7648 +static int storage_available = 0;
7649 +int extra_pd1_pages_allowance = MIN_EXTRA_PAGES_ALLOWANCE;
7650 +int image_size_limit = 0;
7653 + * The atomic copy of pageset1 is stored in pageset2 pages.
7654 + * But if pageset1 is larger (normally only just after boot),
7655 + * we need to allocate extra pages to store the atomic copy.
7656 + * The following data struct and functions are used to handle
7657 + * the allocation and freeing of that memory.
7660 +static int extra_pages_allocated;
7663 + struct page *page;
7665 + struct extras *next;
7668 +static struct extras *extras_list;
7670 +/* suspend_free_extra_pagedir_memory
7672 + * Description: Free previously allocated extra pagedir memory.
7674 +void suspend_free_extra_pagedir_memory(void)
7676 + /* Free allocated pages */
7677 + while (extras_list) {
7678 + struct extras *this = extras_list;
7681 + extras_list = this->next;
7683 + for (i = 0; i < (1 << this->order); i++)
7684 + ClearPageNosave(this->page + i);
7686 + __free_pages(this->page, this->order);
7690 + extra_pages_allocated = 0;
7693 +/* suspend_allocate_extra_pagedir_memory
7695 + * Description: Allocate memory for making the atomic copy of pagedir1 in the
7696 + * case where it is bigger than pagedir2.
7697 + * Arguments: int num_to_alloc: Number of extra pages needed.
7698 + * Result: int. Number of extra pages we now have allocated.
7700 +static int suspend_allocate_extra_pagedir_memory(int extra_pages_needed)
7702 + int j, order, num_to_alloc = extra_pages_needed - extra_pages_allocated;
7703 + unsigned long flags = GFP_ATOMIC | __GFP_NOWARN;
7705 + if (num_to_alloc < 1)
7708 + order = fls(num_to_alloc);
7709 + if (order >= MAX_ORDER)
7710 + order = MAX_ORDER - 1;
7712 + while (num_to_alloc) {
7713 + struct page *newpage;
7714 + unsigned long virt;
7715 + struct extras *extras_entry;
7717 + while ((1 << order) > num_to_alloc)
7720 + extras_entry = (struct extras *) kmalloc(sizeof(struct extras),
7723 + if (!extras_entry)
7724 + return extra_pages_allocated;
7726 + virt = __get_free_pages(flags, order);
7727 + while (!virt && order) {
7729 + virt = __get_free_pages(flags, order);
7733 + kfree(extras_entry);
7734 + return extra_pages_allocated;
7737 + newpage = virt_to_page(virt);
7739 + extras_entry->page = newpage;
7740 + extras_entry->order = order;
7741 + extras_entry->next = NULL;
7744 + extras_entry->next = extras_list;
7746 + extras_list = extras_entry;
7748 + for (j = 0; j < (1 << order); j++) {
7749 + SetPageNosave(newpage + j);
7750 + SetPagePageset1Copy(newpage + j);
7753 + extra_pages_allocated += (1 << order);
7754 + num_to_alloc -= (1 << order);
7757 + return extra_pages_allocated;
7761 + * real_nr_free_pages: Count pcp pages for a zone type or all zones
7762 + * (-1 for all, otherwise zone_idx() result desired).
7764 +int real_nr_free_pages(unsigned long zone_idx_mask)
7766 + struct zone *zone;
7767 + int result = 0, i = 0, cpu;
7770 + for_each_zone(zone) {
7771 + if (!populated_zone(zone))
7774 + if (!(zone_idx_mask & (1 << zone_idx(zone))))
7777 + for_each_online_cpu(cpu) {
7778 + struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
7780 + for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
7781 + struct per_cpu_pages *pcp;
7783 + pcp = &pset->pcp[i];
7784 + result += pcp->count;
7788 + result += zone_page_state(zone, NR_FREE_PAGES);
7794 + * Discover how much extra memory will be required by the drivers
7795 + * when they're asked to suspend. We can then ensure that amount
7796 + * of memory is available when we really want it.
7798 +static void get_extra_pd1_allowance(void)
7800 + int orig_num_free = real_nr_free_pages(all_zones_mask), final;
7802 + suspend_prepare_status(CLEAR_BAR, "Finding allowance for drivers.");
7804 + suspend_console();
7805 + device_suspend(PMSG_FREEZE);
7806 + local_irq_disable(); /* irqs might have been re-enabled on us */
7807 + device_power_down(PMSG_FREEZE);
7809 + final = real_nr_free_pages(all_zones_mask);
7811 + device_power_up();
7812 + local_irq_enable();
7816 + extra_pd1_pages_allowance = max(
7817 + orig_num_free - final + MIN_EXTRA_PAGES_ALLOWANCE,
7818 + MIN_EXTRA_PAGES_ALLOWANCE);
7822 + * Amount of storage needed, possibly taking into account the
7823 + * expected compression ratio and possibly also ignoring our
7824 + * allowance for extra pages.
7826 +static int main_storage_needed(int use_ecr,
7827 + int ignore_extra_pd1_allow)
7829 + return ((pagedir1.size + pagedir2.size +
7830 + (ignore_extra_pd1_allow ? 0 : extra_pd1_pages_allowance)) *
7831 + (use_ecr ? suspend_expected_compression_ratio() : 100) / 100);
7835 + * Storage needed for the image header, in bytes until the return.
7837 +static int header_storage_needed(void)
7839 + int bytes = (int) sizeof(struct suspend_header) +
7840 + suspend_header_storage_for_modules() +
7841 + suspend_pageflags_space_needed();
7843 + return DIV_ROUND_UP(bytes, PAGE_SIZE);
7847 + * When freeing memory, pages from either pageset might be freed.
7849 + * When seeking to free memory to be able to suspend, for every ps1 page freed,
7850 + * we need 2 less pages for the atomic copy because there is one less page to
7851 + * copy and one more page into which data can be copied.
7853 + * Freeing ps2 pages saves us nothing directly. No more memory is available
7854 + * for the atomic copy. Indirectly, a ps1 page might be freed (slab?), but
7855 + * that's too much work to figure out.
7857 + * => ps1_to_free functions
7859 + * Of course if we just want to reduce the image size, because of storage
7860 + * limitations or an image size limit either ps will do.
7862 + * => any_to_free function
7865 +static int highpages_ps1_to_free(void)
7867 + return max_t(int, 0, DIV_ROUND_UP(get_highmem_size(pagedir1) -
7868 + get_highmem_size(pagedir2), 2) - real_nr_free_high_pages());
7871 +static int lowpages_ps1_to_free(void)
7873 + return max_t(int, 0, DIV_ROUND_UP(get_lowmem_size(pagedir1) +
7874 + extra_pd1_pages_allowance + MIN_FREE_RAM +
7875 + suspend_memory_for_modules() - get_lowmem_size(pagedir2) -
7876 + real_nr_free_low_pages() - extra_pages_allocated, 2));
7879 +static int current_image_size(void)
7881 + return pagedir1.size + pagedir2.size + header_space_allocated;
7884 +static int any_to_free(int use_image_size_limit)
7886 + int user_limit = (use_image_size_limit && image_size_limit > 0) ?
7887 + max_t(int, 0, current_image_size() - (image_size_limit << 8))
7890 + int storage_limit = max_t(int, 0,
7891 + main_storage_needed(1, 1) - storage_available);
7893 + return max(user_limit, storage_limit);
7898 + * Calculates the amount by which the image size needs to be reduced to meet
7899 + * our constraints.
7901 +static int amount_needed(int use_image_size_limit)
7903 + return max(highpages_ps1_to_free() + lowpages_ps1_to_free(),
7904 + any_to_free(use_image_size_limit));
7907 +static int image_not_ready(int use_image_size_limit)
7909 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
7910 + "Amount still needed (%d) > 0:%d. Header: %d < %d: %d,"
7911 + " Storage allocd: %d < %d: %d.\n",
7912 + amount_needed(use_image_size_limit),
7913 + (amount_needed(use_image_size_limit) > 0),
7914 + header_space_allocated, header_storage_needed(),
7915 + header_space_allocated < header_storage_needed(),
7916 + main_storage_allocated,
7917 + main_storage_needed(1, 1),
7918 + main_storage_allocated < main_storage_needed(1, 1));
7920 + suspend_cond_pause(0, NULL);
7922 + return ((amount_needed(use_image_size_limit) > 0) ||
7923 + header_space_allocated < header_storage_needed() ||
7924 + main_storage_allocated < main_storage_needed(1, 1));
7927 +static void display_stats(int always, int sub_extra_pd1_allow)
7930 + snprintf(buffer, 254,
7931 + "Free:%d(%d). Sets:%d(%d),%d(%d). Header:%d/%d. Nosave:%d-%d"
7932 + "=%d. Storage:%u/%u(%u=>%u). Needed:%d,%d,%d(%d,%d,%d,%d)\n",
7935 + real_nr_free_pages(all_zones_mask),
7936 + real_nr_free_low_pages(),
7939 + pagedir1.size, pagedir1.size - get_highmem_size(pagedir1),
7940 + pagedir2.size, pagedir2.size - get_highmem_size(pagedir2),
7943 + header_space_allocated, header_storage_needed(),
7946 + num_nosave, extra_pages_allocated,
7947 + num_nosave - extra_pages_allocated,
7950 + main_storage_allocated,
7951 + storage_available,
7952 + main_storage_needed(1, sub_extra_pd1_allow),
7953 + main_storage_needed(1, 1),
7956 + lowpages_ps1_to_free(), highpages_ps1_to_free(),
7958 + MIN_FREE_RAM, suspend_memory_for_modules(),
7959 + extra_pd1_pages_allowance, image_size_limit << 8);
7964 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1, buffer);
7967 +/* generate_free_page_map
7969 + * Description: This routine generates a bitmap of free pages from the
7970 + * lists used by the memory manager. We then use the bitmap
7971 + * to quickly calculate which pages to save and in which
7974 +static void generate_free_page_map(void)
7976 + int order, loop, cpu;
7977 + struct page *page;
7978 + unsigned long flags, i;
7979 + struct zone *zone;
7981 + for_each_zone(zone) {
7982 + if (!populated_zone(zone))
7985 + spin_lock_irqsave(&zone->lock, flags);
7987 + for(i=0; i < zone->spanned_pages; i++)
7988 + ClearPageNosaveFree(pfn_to_page(
7989 + zone->zone_start_pfn + i));
7991 + for (order = MAX_ORDER - 1; order >= 0; --order)
7992 + list_for_each_entry(page,
7993 + &zone->free_area[order].free_list, lru)
7994 + for(loop=0; loop < (1 << order); loop++)
7995 + SetPageNosaveFree(page+loop);
7998 + for_each_online_cpu(cpu) {
7999 + struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
8001 + for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
8002 + struct per_cpu_pages *pcp;
8003 + struct page *page;
8005 + pcp = &pset->pcp[i];
8006 + list_for_each_entry(page, &pcp->list, lru)
8007 + SetPageNosaveFree(page);
8011 + spin_unlock_irqrestore(&zone->lock, flags);
8015 +/* size_of_free_region
8017 + * Description: Return the number of pages that are free, beginning with and
8018 + * including this one.
8020 +static int size_of_free_region(struct page *page)
8022 + struct zone *zone = page_zone(page);
8023 + struct page *posn = page, *last_in_zone =
8024 + pfn_to_page(zone->zone_start_pfn) + zone->spanned_pages - 1;
8026 + while (posn <= last_in_zone && PageNosaveFree(posn))
8028 + return (posn - page);
8031 +/* flag_image_pages
8033 + * This routine generates our lists of pages to be stored in each
8034 + * pageset. Since we store the data using extents, and adding new
8035 + * extents might allocate a new extent page, this routine may well
8036 + * be called more than once.
8038 +static void flag_image_pages(int atomic_copy)
8041 + unsigned long loop;
8042 + struct zone *zone;
8044 + pagedir1.size = 0;
8045 + pagedir2.size = 0;
8047 + set_highmem_size(pagedir1, 0);
8048 + set_highmem_size(pagedir2, 0);
8052 + clear_dyn_pageflags(pageset1_map);
8054 + generate_free_page_map();
8057 + * Pages not to be saved are marked Nosave irrespective of being reserved
8059 + for_each_zone(zone) {
8060 + int highmem = is_highmem(zone);
8062 + if (!populated_zone(zone))
8065 + for (loop = 0; loop < zone->spanned_pages; loop++) {
8066 + unsigned long pfn = zone->zone_start_pfn + loop;
8067 + struct page *page;
8070 + if (!pfn_valid(pfn))
8073 + page = pfn_to_page(pfn);
8075 + chunk_size = size_of_free_region(page);
8077 + num_free += chunk_size;
8078 + loop += chunk_size - 1;
8083 + page = saveable_highmem_page(pfn);
8085 + page = saveable_page(pfn);
8087 + if (!page || PageNosave(page)) {
8092 + if (PagePageset2(page)) {
8094 + if (PageHighMem(page))
8095 + inc_highmem_size(pagedir2);
8097 + SetPagePageset1Copy(page);
8098 + if (PageResave(page)) {
8099 + SetPagePageset1(page);
8100 + ClearPagePageset1Copy(page);
8102 + if (PageHighMem(page))
8103 + inc_highmem_size(pagedir1);
8107 + SetPagePageset1(page);
8108 + if (PageHighMem(page))
8109 + inc_highmem_size(pagedir1);
8117 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 0,
8118 + "Count data pages: Set1 (%d) + Set2 (%d) + Nosave (%d) + "
8119 + "NumFree (%d) = %d.\n",
8120 + pagedir1.size, pagedir2.size, num_nosave, num_free,
8121 + pagedir1.size + pagedir2.size + num_nosave + num_free);
8124 +void suspend_recalculate_image_contents(int atomic_copy)
8126 + clear_dyn_pageflags(pageset1_map);
8127 + if (!atomic_copy) {
8129 + BITMAP_FOR_EACH_SET(pageset2_map, pfn)
8130 + ClearPagePageset1Copy(pfn_to_page(pfn));
8131 + /* Need to call this before getting pageset1_size! */
8132 + suspend_mark_pages_for_pageset2();
8134 + flag_image_pages(atomic_copy);
8136 + if (!atomic_copy) {
8137 + storage_available = suspendActiveAllocator->storage_available();
8138 + display_stats(0, 0);
8144 + * Allocate [more] memory and storage for the image.
8146 +static void update_image(void)
8148 + int result, param_used, wanted, got;
8150 + suspend_recalculate_image_contents(0);
8152 + /* Include allowance for growth in pagedir1 while writing pagedir 2 */
8153 + wanted = pagedir1.size + extra_pd1_pages_allowance -
8154 + get_lowmem_size(pagedir2);
8155 + if (wanted > extra_pages_allocated) {
8156 + got = suspend_allocate_extra_pagedir_memory(wanted);
8157 + if (wanted < got) {
8158 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
8159 + "Want %d extra pages for pageset1, got %d.\n",
8165 + thaw_kernel_threads();
8168 + * Allocate remaining storage space, if possible, up to the
8169 + * maximum we know we'll need. It's okay to allocate the
8170 + * maximum if the writer is the swapwriter, but
8171 + * we don't want to grab all available space on an NFS share.
8172 + * We therefore ignore the expected compression ratio here,
8173 + * thereby trying to allocate the maximum image size we could
8174 + * need (assuming compression doesn't expand the image), but
8175 + * don't complain if we can't get the full amount we're after.
8178 + suspendActiveAllocator->allocate_storage(
8179 + min(storage_available, main_storage_needed(0, 0)));
8181 + main_storage_allocated = suspendActiveAllocator->storage_allocated();
8183 + param_used = header_storage_needed();
8185 + result = suspendActiveAllocator->allocate_header_space(param_used);
8188 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
8189 + "Still need to get more storage space for header.\n");
8191 + header_space_allocated = param_used;
8193 + if (freeze_processes()) {
8194 + set_result_state(SUSPEND_FREEZING_FAILED);
8195 + set_result_state(SUSPEND_ABORTED);
8198 + allocate_checksum_pages();
8200 + suspend_recalculate_image_contents(0);
8203 +/* attempt_to_freeze
8205 + * Try to freeze processes.
8208 +static int attempt_to_freeze(void)
8212 + /* Stop processes before checking again */
8214 + suspend_prepare_status(CLEAR_BAR, "Freezing processes & syncing filesystems.");
8215 + result = freeze_processes();
8218 + set_result_state(SUSPEND_ABORTED);
8219 + set_result_state(SUSPEND_FREEZING_FAILED);
8227 + * Try to free some memory, either to meet hard or soft constraints on the image
8228 + * characteristics.
8230 + * Hard constraints:
8231 + * - Pageset1 must be < half of memory;
8232 + * - We must have enough memory free at resume time to have pageset1
8233 + * be able to be loaded in pages that don't conflict with where it has to
8235 + * Soft constraints
8236 + * - User specificied image size limit.
8238 +static void eat_memory(void)
8240 + int amount_wanted = 0;
8241 + int free_flags = 0, did_eat_memory = 0;
8244 + * Note that if we have enough storage space and enough free memory, we
8245 + * may exit without eating anything. We give up when the last 10
8246 + * iterations ate no extra pages because we're not going to get much
8247 + * more anyway, but the few pages we get will take a lot of time.
8249 + * We freeze processes before beginning, and then unfreeze them if we
8250 + * need to eat memory until we think we have enough. If our attempts
8251 + * to freeze fail, we give up and abort.
8254 + suspend_recalculate_image_contents(0);
8255 + amount_wanted = amount_needed(1);
8257 + switch (image_size_limit) {
8258 + case -1: /* Don't eat any memory */
8259 + if (amount_wanted > 0) {
8260 + set_result_state(SUSPEND_ABORTED);
8261 + set_result_state(SUSPEND_WOULD_EAT_MEMORY);
8265 + case -2: /* Free caches only */
8267 + suspend_recalculate_image_contents(0);
8268 + amount_wanted = amount_needed(1);
8269 + did_eat_memory = 1;
8272 + free_flags = GFP_ATOMIC | __GFP_HIGHMEM;
8275 + if (amount_wanted > 0 && !test_result_state(SUSPEND_ABORTED) &&
8276 + image_size_limit != -1) {
8277 + struct zone *zone;
8280 + suspend_prepare_status(CLEAR_BAR, "Seeking to free %dMB of memory.", MB(amount_wanted));
8282 + thaw_kernel_threads();
8284 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
8285 + int zone_type_free = max_t(int, (zone_idx == ZONE_HIGHMEM) ?
8286 + highpages_ps1_to_free() :
8287 + lowpages_ps1_to_free(), amount_wanted);
8289 + if (zone_type_free < 0)
8292 + for_each_zone(zone) {
8293 + if (zone_idx(zone) != zone_idx)
8296 + shrink_one_zone(zone, zone_type_free);
8298 + did_eat_memory = 1;
8300 + suspend_recalculate_image_contents(0);
8302 + amount_wanted = amount_needed(1);
8303 + zone_type_free = max_t(int, (zone_idx == ZONE_HIGHMEM) ?
8304 + highpages_ps1_to_free() :
8305 + lowpages_ps1_to_free(), amount_wanted);
8307 + if (zone_type_free < 0)
8312 + suspend_cond_pause(0, NULL);
8314 + if (freeze_processes()) {
8315 + set_result_state(SUSPEND_FREEZING_FAILED);
8316 + set_result_state(SUSPEND_ABORTED);
8320 + if (did_eat_memory) {
8321 + unsigned long orig_state = get_suspend_state();
8322 + /* Freeze_processes will call sys_sync too */
8323 + restore_suspend_state(orig_state);
8324 + suspend_recalculate_image_contents(0);
8327 + /* Blank out image size display */
8328 + suspend_update_status(100, 100, NULL);
8331 +/* suspend_prepare_image
8333 + * Entry point to the whole image preparation section.
8335 + * We do four things:
8336 + * - Freeze processes;
8337 + * - Ensure image size constraints are met;
8338 + * - Complete all the preparation for saving the image,
8339 + * including allocation of storage. The only memory
8340 + * that should be needed when we're finished is that
8341 + * for actually storing the image (and we know how
8342 + * much is needed for that because the modules tell
8344 + * - Make sure that all dirty buffers are written out.
8346 +#define MAX_TRIES 2
8347 +int suspend_prepare_image(void)
8349 + int result = 1, tries = 1;
8351 + header_space_allocated = 0;
8352 + main_storage_allocated = 0;
8354 + if (attempt_to_freeze())
8357 + if (!extra_pd1_pages_allowance)
8358 + get_extra_pd1_allowance();
8360 + storage_available = suspendActiveAllocator->storage_available();
8362 + if (!storage_available) {
8363 + printk(KERN_ERR "You need some storage available to be able to suspend.\n");
8364 + set_result_state(SUSPEND_ABORTED);
8365 + set_result_state(SUSPEND_NOSTORAGE_AVAILABLE);
8370 + suspend_prepare_status(CLEAR_BAR, "Preparing Image. Try %d.", tries);
8374 + if (test_result_state(SUSPEND_ABORTED))
8381 + } while (image_not_ready(1) && tries <= MAX_TRIES &&
8382 + !test_result_state(SUSPEND_ABORTED));
8384 + result = image_not_ready(0);
8386 + if (!test_result_state(SUSPEND_ABORTED)) {
8388 + display_stats(1, 0);
8389 + abort_suspend(SUSPEND_UNABLE_TO_PREPARE_IMAGE,
8390 + "Unable to successfully prepare the image.\n");
8392 + unlink_lru_lists();
8393 + suspend_cond_pause(1, "Image preparation complete.");
8400 +#ifdef CONFIG_SUSPEND2_EXPORTS
8401 +EXPORT_SYMBOL_GPL(real_nr_free_pages);
8403 diff -ruN linux-2.6.22/kernel/power/prepare_image.h suspend2-2.2.10-for-2.6.22/kernel/power/prepare_image.h
8404 --- linux-2.6.22/kernel/power/prepare_image.h 1970-01-01 10:00:00.000000000 +1000
8405 +++ suspend2-2.2.10-for-2.6.22/kernel/power/prepare_image.h 2007-07-11 22:25:42.000000000 +1000
8408 + * kernel/power/prepare_image.h
8410 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
8412 + * This file is released under the GPLv2.
8416 +#include <asm/sections.h>
8418 +extern int suspend_prepare_image(void);
8419 +extern void suspend_recalculate_image_contents(int storage_available);
8420 +extern int real_nr_free_pages(unsigned long zone_idx_mask);
8421 +extern int image_size_limit;
8422 +extern void suspend_free_extra_pagedir_memory(void);
8423 +extern int extra_pd1_pages_allowance;
8425 +#define MIN_FREE_RAM 100
8426 +#define MIN_EXTRA_PAGES_ALLOWANCE 500
8428 +#define all_zones_mask ((unsigned long) ((1 << MAX_NR_ZONES) - 1))
8429 +#ifdef CONFIG_HIGHMEM
8430 +#define real_nr_free_high_pages() (real_nr_free_pages(1 << ZONE_HIGHMEM))
8431 +#define real_nr_free_low_pages() (real_nr_free_pages(all_zones_mask - \
8432 + (1 << ZONE_HIGHMEM)))
8434 +#define real_nr_free_high_pages() (0)
8435 +#define real_nr_free_low_pages() (real_nr_free_pages(all_zones_mask))
8437 +/* For eat_memory function */
8438 +#define ZONE_HIGHMEM (MAX_NR_ZONES + 1)
8441 diff -ruN linux-2.6.22/kernel/power/process.c suspend2-2.2.10-for-2.6.22/kernel/power/process.c
8442 --- linux-2.6.22/kernel/power/process.c 2007-07-11 22:19:41.000000000 +1000
8443 +++ suspend2-2.2.10-for-2.6.22/kernel/power/process.c 2007-07-11 22:25:42.000000000 +1000
8445 #include <linux/syscalls.h>
8446 #include <linux/freezer.h>
8448 +int freezer_state = 0;
8451 * Timeout for stopping processes
8453 @@ -192,10 +194,11 @@
8457 + freezer_state = FREEZER_USERSPACE_FROZEN;
8458 nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
8462 + freezer_state = FREEZER_FULLY_ON;
8464 BUG_ON(in_atomic());
8466 @@ -220,11 +223,31 @@
8468 void thaw_processes(void)
8470 + int old_state = freezer_state;
8472 + if (old_state == FREEZER_OFF)
8476 + * Change state beforehand because thawed tasks might submit I/O
8479 + freezer_state = FREEZER_OFF;
8481 printk("Restarting tasks ... ");
8482 - thaw_tasks(FREEZER_KERNEL_THREADS);
8484 + if (old_state == FREEZER_FULLY_ON)
8485 + thaw_tasks(FREEZER_KERNEL_THREADS);
8486 thaw_tasks(FREEZER_USER_SPACE);
8491 +void thaw_kernel_threads(void)
8493 + freezer_state = FREEZER_USERSPACE_FROZEN;
8494 + thaw_tasks(FREEZER_KERNEL_THREADS);
8497 EXPORT_SYMBOL(refrigerator);
8498 +EXPORT_SYMBOL(freezer_state);
8499 diff -ruN linux-2.6.22/kernel/power/snapshot.c suspend2-2.2.10-for-2.6.22/kernel/power/snapshot.c
8500 --- linux-2.6.22/kernel/power/snapshot.c 2007-07-11 22:19:41.000000000 +1000
8501 +++ suspend2-2.2.10-for-2.6.22/kernel/power/snapshot.c 2007-07-11 22:25:42.000000000 +1000
8506 +#include "suspend2_builtin.h"
8508 static int swsusp_page_is_free(struct page *);
8509 static void swsusp_set_page_forbidden(struct page *);
8511 * directly to their "original" page frames.
8513 struct pbe *restore_pblist;
8514 +int resume_attempted;
8515 +EXPORT_SYMBOL_GPL(resume_attempted);
8517 +#ifdef CONFIG_SUSPEND2
8518 +#include "pagedir.h"
8519 +int suspend_post_context_save(void);
8522 /* Pointer to an auxiliary buffer (1 page) */
8523 static void *buffer;
8526 unsigned long get_safe_page(gfp_t gfp_mask)
8528 +#ifdef CONFIG_SUSPEND2
8529 + if (suspend2_running)
8530 + return suspend_get_nonconflicting_page();
8533 return (unsigned long)get_image_page(gfp_mask, PG_SAFE);
8537 unsigned long end_pfn;
8540 -static LIST_HEAD(nosave_regions);
8541 +LIST_HEAD(nosave_regions);
8543 +EXPORT_SYMBOL_GPL(nosave_regions);
8546 * register_nosave_region - register a range of page frames the contents
8548 * and it isn't a part of a free chunk of pages.
8551 -static struct page *saveable_highmem_page(unsigned long pfn)
8552 +struct page *saveable_highmem_page(unsigned long pfn)
8560 -static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
8561 static inline unsigned int count_highmem_pages(void) { return 0; }
8562 #endif /* CONFIG_HIGHMEM */
8565 * a free chunk of pages.
8568 -static struct page *saveable_page(unsigned long pfn)
8569 +struct page *saveable_page(unsigned long pfn)
8573 @@ -1200,6 +1214,11 @@
8575 unsigned int nr_pages, nr_highmem;
8577 +#ifdef CONFIG_SUSPEND2
8578 + if (suspend2_running)
8579 + return suspend_post_context_save();
8582 printk("swsusp: critical section: \n");
8584 drain_local_pages();
8585 diff -ruN linux-2.6.22/kernel/power/storage.c suspend2-2.2.10-for-2.6.22/kernel/power/storage.c
8586 --- linux-2.6.22/kernel/power/storage.c 1970-01-01 10:00:00.000000000 +1000
8587 +++ suspend2-2.2.10-for-2.6.22/kernel/power/storage.c 2007-07-11 22:25:42.000000000 +1000
8590 + * kernel/power/storage.c
8592 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
8594 + * This file is released under the GPLv2.
8596 + * Routines for talking to a userspace program that manages storage.
8598 + * The kernel side:
8599 + * - starts the userspace program;
8600 + * - sends messages telling it when to open and close the connection;
8601 + * - tells it when to quit;
8603 + * The user space side:
8604 + * - passes messages regarding status;
8608 +#include <linux/suspend.h>
8609 +#include <linux/freezer.h>
8612 +#include "modules.h"
8613 +#include "netlink.h"
8614 +#include "storage.h"
8617 +static struct user_helper_data usm_helper_data;
8618 +static struct suspend_module_ops usm_ops;
8619 +static int message_received = 0;
8620 +static int usm_prepare_count = 0;
8621 +static int storage_manager_last_action = 0;
8622 +static int storage_manager_action = 0;
8624 +static int usm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
8629 + type = nlh->nlmsg_type;
8631 + /* A control message: ignore them */
8632 + if (type < NETLINK_MSG_BASE)
8635 + /* Unknown message: reply with EINVAL */
8636 + if (type >= USM_MSG_MAX)
8639 + /* All operations require privileges, even GET */
8640 + if (security_netlink_recv(skb, CAP_NET_ADMIN))
8643 + /* Only allow one task to receive NOFREEZE privileges */
8644 + if (type == NETLINK_MSG_NOFREEZE_ME && usm_helper_data.pid != -1)
8647 + data = (int*)NLMSG_DATA(nlh);
8650 + case USM_MSG_SUCCESS:
8651 + case USM_MSG_FAILED:
8652 + message_received = type;
8653 + complete(&usm_helper_data.wait_for_process);
8656 + printk("Storage manager doesn't recognise message %d.\n", type);
8663 +static int activations = 0;
8665 +int suspend_activate_storage(int force)
8669 + if (usm_helper_data.pid == -1 || !usm_ops.enabled)
8672 + message_received = 0;
8675 + if (activations > 1 && !force)
8678 + while ((!message_received || message_received == USM_MSG_FAILED) && tries < 2) {
8679 + suspend_prepare_status(DONT_CLEAR_BAR, "Activate storage attempt %d.\n", tries);
8681 + init_completion(&usm_helper_data.wait_for_process);
8683 + suspend_send_netlink_message(&usm_helper_data,
8687 + /* Wait 2 seconds for the userspace process to make contact */
8688 + wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2*HZ);
8696 +int suspend_deactivate_storage(int force)
8698 + if (usm_helper_data.pid == -1 || !usm_ops.enabled)
8701 + message_received = 0;
8704 + if (activations && !force)
8707 + init_completion(&usm_helper_data.wait_for_process);
8709 + suspend_send_netlink_message(&usm_helper_data,
8710 + USM_MSG_DISCONNECT,
8713 + wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2*HZ);
8715 + if (!message_received || message_received == USM_MSG_FAILED) {
8716 + printk("Returning failure disconnecting storage.\n");
8724 +static void storage_manager_simulate(void)
8726 + printk("--- Storage manager simulate ---\n");
8727 + suspend_prepare_usm();
8729 + printk("--- Activate storage 1 ---\n");
8730 + suspend_activate_storage(1);
8732 + printk("--- Deactivate storage 1 ---\n");
8733 + suspend_deactivate_storage(1);
8735 + printk("--- Cleanup usm ---\n");
8736 + suspend_cleanup_usm();
8738 + printk("--- Storage manager simulate ends ---\n");
8741 +static int usm_storage_needed(void)
8743 + return strlen(usm_helper_data.program);
8746 +static int usm_save_config_info(char *buf)
8748 + int len = strlen(usm_helper_data.program);
8749 + memcpy(buf, usm_helper_data.program, len);
8753 +static void usm_load_config_info(char *buf, int size)
8755 + /* Don't load the saved path if one has already been set */
8756 + if (usm_helper_data.program[0])
8759 + memcpy(usm_helper_data.program, buf, size);
8762 +static int usm_memory_needed(void)
8764 + /* ball park figure of 32 pages */
8765 + return (32 * PAGE_SIZE);
8768 +/* suspend_prepare_usm
8770 +int suspend_prepare_usm(void)
8772 + usm_prepare_count++;
8774 + if (usm_prepare_count > 1 || !usm_ops.enabled)
8777 + usm_helper_data.pid = -1;
8779 + if (!*usm_helper_data.program)
8782 + suspend_netlink_setup(&usm_helper_data);
8784 + if (usm_helper_data.pid == -1)
8785 + printk("Suspend2 Storage Manager wanted, but couldn't start it.\n");
8787 + suspend_activate_storage(0);
8789 + return (usm_helper_data.pid != -1);
8792 +void suspend_cleanup_usm(void)
8794 + usm_prepare_count--;
8796 + if (usm_helper_data.pid > -1 && !usm_prepare_count) {
8797 + suspend_deactivate_storage(0);
8798 + suspend_netlink_close(&usm_helper_data);
8802 +static void storage_manager_activate(void)
8804 + if (storage_manager_action == storage_manager_last_action)
8807 + if (storage_manager_action)
8808 + suspend_prepare_usm();
8810 + suspend_cleanup_usm();
8812 + storage_manager_last_action = storage_manager_action;
8816 + * User interface specific /sys/power/suspend2 entries.
8819 +static struct suspend_sysfs_data sysfs_params[] = {
8820 + { SUSPEND2_ATTR("simulate_atomic_copy", SYSFS_RW),
8821 + .type = SUSPEND_SYSFS_DATA_NONE,
8822 + .write_side_effect = storage_manager_simulate,
8825 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
8826 + SYSFS_INT(&usm_ops.enabled, 0, 1, 0)
8829 + { SUSPEND2_ATTR("program", SYSFS_RW),
8830 + SYSFS_STRING(usm_helper_data.program, 254, 0)
8833 + { SUSPEND2_ATTR("activate_storage", SYSFS_RW),
8834 + SYSFS_INT(&storage_manager_action, 0, 1, 0),
8835 + .write_side_effect = storage_manager_activate,
8839 +static struct suspend_module_ops usm_ops = {
8840 + .type = MISC_MODULE,
8841 + .name = "Userspace Storage Manager",
8842 + .directory = "storage_manager",
8843 + .module = THIS_MODULE,
8844 + .storage_needed = usm_storage_needed,
8845 + .save_config_info = usm_save_config_info,
8846 + .load_config_info = usm_load_config_info,
8847 + .memory_needed = usm_memory_needed,
8849 + .sysfs_data = sysfs_params,
8850 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
8853 +/* suspend_usm_sysfs_init
8854 + * Description: Boot time initialisation for user interface.
8856 +int s2_usm_init(void)
8858 + usm_helper_data.nl = NULL;
8859 + usm_helper_data.program[0] = '\0';
8860 + usm_helper_data.pid = -1;
8861 + usm_helper_data.skb_size = 0;
8862 + usm_helper_data.pool_limit = 6;
8863 + usm_helper_data.netlink_id = NETLINK_SUSPEND2_USM;
8864 + usm_helper_data.name = "userspace storage manager";
8865 + usm_helper_data.rcv_msg = usm_user_rcv_msg;
8866 + usm_helper_data.interface_version = 1;
8867 + usm_helper_data.must_init = 0;
8868 + init_completion(&usm_helper_data.wait_for_process);
8870 + return suspend_register_module(&usm_ops);
8873 +void s2_usm_exit(void)
8875 + suspend_unregister_module(&usm_ops);
8877 diff -ruN linux-2.6.22/kernel/power/storage.h suspend2-2.2.10-for-2.6.22/kernel/power/storage.h
8878 --- linux-2.6.22/kernel/power/storage.h 1970-01-01 10:00:00.000000000 +1000
8879 +++ suspend2-2.2.10-for-2.6.22/kernel/power/storage.h 2007-07-11 22:25:42.000000000 +1000
8882 + * kernel/power/storage.h
8884 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
8886 + * This file is released under the GPLv2.
8890 +int suspend_prepare_usm(void);
8891 +void suspend_cleanup_usm(void);
8893 +int suspend_activate_storage(int force);
8894 +int suspend_deactivate_storage(int force);
8895 +extern int s2_usm_init(void);
8896 +extern void s2_usm_exit(void);
8898 +static inline int s2_usm_init(void) { return 0; }
8899 +static inline void s2_usm_exit(void) { }
8901 +static inline int suspend_activate_storage(int force)
8906 +static inline int suspend_deactivate_storage(int force)
8911 +static inline int suspend_prepare_usm(void) { return 0; }
8912 +static inline void suspend_cleanup_usm(void) { }
8916 + USM_MSG_BASE = 0x10,
8918 + /* Kernel -> Userspace */
8919 + USM_MSG_CONNECT = 0x30,
8920 + USM_MSG_DISCONNECT = 0x31,
8921 + USM_MSG_SUCCESS = 0x40,
8922 + USM_MSG_FAILED = 0x41,
8928 +extern __init int suspend_usm_init(void);
8929 +extern __exit void suspend_usm_cleanup(void);
8931 +#define suspend_usm_init() do { } while(0)
8932 +#define suspend_usb_cleanup() do { } while(0)
8934 diff -ruN linux-2.6.22/kernel/power/suspend.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend.c
8935 --- linux-2.6.22/kernel/power/suspend.c 1970-01-01 10:00:00.000000000 +1000
8936 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend.c 2007-07-11 22:25:42.000000000 +1000
8939 + * kernel/power/suspend.c
8941 +/** \mainpage Suspend2.
8943 + * Suspend2 provides support for saving and restoring an image of
8944 + * system memory to an arbitrary storage device, either on the local computer,
8945 + * or across some network. The support is entirely OS based, so Suspend2
8946 + * works without requiring BIOS, APM or ACPI support. The vast majority of the
8947 + * code is also architecture independant, so it should be very easy to port
8948 + * the code to new architectures. Suspend includes support for SMP, 4G HighMem
8949 + * and preemption. Initramfses and initrds are also supported.
8951 + * Suspend2 uses a modular design, in which the method of storing the image is
8952 + * completely abstracted from the core code, as are transformations on the data
8953 + * such as compression and/or encryption (multiple 'modules' can be used to
8954 + * provide arbitrary combinations of functionality). The user interface is also
8955 + * modular, so that arbitrarily simple or complex interfaces can be used to
8956 + * provide anything from debugging information through to eye candy.
8958 + * \section Copyright
8960 + * Suspend2 is released under the GPLv2.
8962 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu><BR>
8963 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz><BR>
8964 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr><BR>
8965 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)<BR>
8967 + * \section Credits
8969 + * Nigel would like to thank the following people for their work:
8971 + * Bernard Blackham <bernard@blackham.com.au><BR>
8972 + * Web page & Wiki administration, some coding. A person without whom
8973 + * Suspend would not be where it is.
8975 + * Michael Frank <mhf@linuxmail.org><BR>
8976 + * Extensive testing and help with improving stability. I was constantly
8977 + * amazed by the quality and quantity of Michael's help.
8979 + * Pavel Machek <pavel@ucw.cz><BR>
8980 + * Modifications, defectiveness pointing, being with Gabor at the very beginning,
8981 + * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. Even
8982 + * though Pavel and I disagree on the direction suspend to disk should take, I
8983 + * appreciate the valuable work he did in helping Gabor get the concept working.
8985 + * ..and of course the myriads of Suspend2 users who have helped diagnose
8986 + * and fix bugs, made suggestions on how to improve the code, proofread
8987 + * documentation, and donated time and money.
8989 + * Thanks also to corporate sponsors:
8991 + * <B>Redhat.</B>Sometime employer from May 2006 (my fault, not Redhat's!).
8993 + * <B>Cyclades.com.</B> Nigel's employers from Dec 2004 until May 2006, who
8994 + * allowed him to work on Suspend and PM related issues on company time.
8996 + * <B>LinuxFund.org.</B> Sponsored Nigel's work on Suspend for four months Oct 2003
8999 + * <B>LAC Linux.</B> Donated P4 hardware that enabled development and ongoing
9000 + * maintenance of SMP and Highmem support.
9002 + * <B>OSDL.</B> Provided access to various hardware configurations, make occasional
9003 + * small donations to the project.
9006 +#include <linux/suspend.h>
9007 +#include <linux/module.h>
9008 +#include <linux/freezer.h>
9009 +#include <linux/utsrelease.h>
9010 +#include <linux/cpu.h>
9011 +#include <linux/console.h>
9012 +#include <asm/uaccess.h>
9014 +#include "modules.h"
9016 +#include "prepare_image.h"
9019 +#include "power_off.h"
9020 +#include "storage.h"
9021 +#include "checksum.h"
9022 +#include "cluster.h"
9023 +#include "suspend2_builtin.h"
9025 +/*! Pageset metadata. */
9026 +struct pagedir pagedir2 = {2};
9028 +static int get_pmsem = 0, got_pmsem;
9029 +static mm_segment_t oldfs;
9030 +static atomic_t actions_running;
9031 +static int block_dump_save;
9032 +extern int block_dump;
9034 +int do_suspend2_step(int step);
9037 + * Basic clean-up routine.
9039 +void suspend_finish_anything(int suspend_or_resume)
9041 + if (!atomic_dec_and_test(&actions_running))
9044 + suspend_cleanup_modules(suspend_or_resume);
9045 + suspend_put_modules();
9046 + clear_suspend_state(SUSPEND_RUNNING);
9048 + if (suspend_or_resume) {
9049 + block_dump = block_dump_save;
9050 + set_cpus_allowed(current, CPU_MASK_ALL);
9055 + * Basic set-up routine.
9057 +int suspend_start_anything(int suspend_or_resume)
9059 + if (atomic_add_return(1, &actions_running) != 1) {
9060 + if (suspend_or_resume) {
9061 + printk("Can't start a cycle when actions are "
9062 + "already running.\n");
9063 + atomic_dec(&actions_running);
9070 + set_fs(KERNEL_DS);
9072 + if (!suspendActiveAllocator) {
9073 + /* Be quiet if we're not trying to suspend or resume */
9074 + if (suspend_or_resume)
9075 + printk("No storage allocator is currently active. "
9076 + "Rechecking whether we can use one.\n");
9077 + suspend_attempt_to_parse_resume_device(!suspend_or_resume);
9080 + set_suspend_state(SUSPEND_RUNNING);
9082 + if (suspend_get_modules()) {
9083 + printk("Suspend2: Get modules failed!\n");
9087 + if (suspend_initialise_modules(suspend_or_resume)) {
9088 + printk("Suspend2: Initialise modules failed!\n");
9092 + if (suspend_or_resume) {
9093 + block_dump_save = block_dump;
9095 + set_cpus_allowed(current, CPU_MASK_CPU0);
9101 + if (suspend_or_resume)
9102 + block_dump_save = block_dump;
9103 + suspend_finish_anything(suspend_or_resume);
9108 + * Nosave page tracking.
9110 + * Here rather than in prepare_image because we want to do it once only at the
9111 + * start of a cycle.
9113 +extern struct list_head nosave_regions;
9115 +struct nosave_region {
9116 + struct list_head list;
9117 + unsigned long start_pfn;
9118 + unsigned long end_pfn;
9121 +static void mark_nosave_pages(void)
9123 + struct nosave_region *region;
9125 + list_for_each_entry(region, &nosave_regions, list) {
9126 + unsigned long pfn;
9128 + for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
9129 + SetPageNosave(pfn_to_page(pfn));
9134 + * Allocate & free bitmaps.
9136 +static int allocate_bitmaps(void)
9138 + if (allocate_dyn_pageflags(&pageset1_map) ||
9139 + allocate_dyn_pageflags(&pageset1_copy_map) ||
9140 + allocate_dyn_pageflags(&pageset2_map) ||
9141 + allocate_dyn_pageflags(&io_map) ||
9142 + allocate_dyn_pageflags(&nosave_map) ||
9143 + allocate_dyn_pageflags(&free_map) ||
9144 + allocate_dyn_pageflags(&page_resave_map))
9150 +static void free_bitmaps(void)
9152 + free_dyn_pageflags(&pageset1_map);
9153 + free_dyn_pageflags(&pageset1_copy_map);
9154 + free_dyn_pageflags(&pageset2_map);
9155 + free_dyn_pageflags(&io_map);
9156 + free_dyn_pageflags(&nosave_map);
9157 + free_dyn_pageflags(&free_map);
9158 + free_dyn_pageflags(&page_resave_map);
9161 +static int io_MB_per_second(int read_write)
9163 + return (suspend_io_time[read_write][1]) ?
9164 + MB((unsigned long) suspend_io_time[read_write][0]) * HZ /
9165 + suspend_io_time[read_write][1] : 0;
9169 + * Functionality: Store debug info in a buffer.
9171 +#define SNPRINTF(a...) len += snprintf_used(((char *)buffer) + len, \
9172 + count - len - 1, ## a)
9173 +static int get_suspend_debug_info(const char *buffer, int count)
9177 + SNPRINTF("Suspend2 debugging info:\n");
9178 + SNPRINTF("- Suspend core : %s\n", SUSPEND_CORE_VERSION);
9179 + SNPRINTF("- Kernel Version : %s\n", UTS_RELEASE);
9180 + SNPRINTF("- Compiler vers. : %d.%d\n", __GNUC__, __GNUC_MINOR__);
9181 + SNPRINTF("- Attempt number : %d\n", nr_suspends);
9182 + SNPRINTF("- Parameters : %ld %ld %ld %d %d %ld\n",
9185 + suspend_debug_state,
9186 + suspend_default_console_level,
9188 + suspend2_poweroff_method);
9189 + SNPRINTF("- Overall expected compression percentage: %d.\n",
9190 + 100 - suspend_expected_compression_ratio());
9191 + len+= suspend_print_module_debug_info(((char *) buffer) + len,
9193 + if (suspend_io_time[0][1]) {
9194 + if ((io_MB_per_second(0) < 5) || (io_MB_per_second(1) < 5)) {
9195 + SNPRINTF("- I/O speed: Write %d KB/s",
9196 + (KB((unsigned long) suspend_io_time[0][0]) * HZ /
9197 + suspend_io_time[0][1]));
9198 + if (suspend_io_time[1][1])
9199 + SNPRINTF(", Read %d KB/s",
9200 + (KB((unsigned long) suspend_io_time[1][0]) * HZ /
9201 + suspend_io_time[1][1]));
9203 + SNPRINTF("- I/O speed: Write %d MB/s",
9204 + (MB((unsigned long) suspend_io_time[0][0]) * HZ /
9205 + suspend_io_time[0][1]));
9206 + if (suspend_io_time[1][1])
9207 + SNPRINTF(", Read %d MB/s",
9208 + (MB((unsigned long) suspend_io_time[1][0]) * HZ /
9209 + suspend_io_time[1][1]));
9214 + SNPRINTF("- No I/O speed stats available.\n");
9215 + SNPRINTF("- Extra pages : %d used/%d.\n",
9216 + extra_pd1_pages_used, extra_pd1_pages_allowance);
9225 +static void do_cleanup(int get_debug_info)
9228 + char *buffer = NULL;
9230 + if (get_debug_info)
9231 + suspend_prepare_status(DONT_CLEAR_BAR, "Cleaning up...");
9232 + relink_lru_lists();
9234 + free_checksum_pages();
9236 + if (get_debug_info)
9237 + buffer = (char *) get_zeroed_page(GFP_ATOMIC);
9240 + i = get_suspend_debug_info(buffer, PAGE_SIZE);
9242 + suspend_free_extra_pagedir_memory();
9244 + pagedir1.size = pagedir2.size = 0;
9245 + set_highmem_size(pagedir1, 0);
9246 + set_highmem_size(pagedir2, 0);
9248 + restore_avenrun();
9252 +#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
9253 + if (test_action_state(SUSPEND_KEEP_IMAGE) &&
9254 + !test_result_state(SUSPEND_ABORTED)) {
9255 + suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9256 + "Suspend2: Not invalidating the image due "
9257 + "to Keep Image being enabled.\n");
9258 + set_result_state(SUSPEND_KEPT_IMAGE);
9261 + if (suspendActiveAllocator)
9262 + suspendActiveAllocator->invalidate_image();
9266 + if (buffer && i) {
9267 + /* Printk can only handle 1023 bytes, including
9268 + * its level mangling. */
9269 + for (i = 0; i < 3; i++)
9270 + printk("%s", buffer + (1023 * i));
9271 + free_page((unsigned long) buffer);
9274 + if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9275 + enable_nonboot_cpus();
9276 + suspend_cleanup_console();
9278 + suspend_deactivate_storage(0);
9280 + clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
9281 + clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
9282 + clear_suspend_state(SUSPEND_NOW_RESUMING);
9285 + mutex_unlock(&pm_mutex);
9290 +static int check_still_keeping_image(void)
9292 + if (test_action_state(SUSPEND_KEEP_IMAGE)) {
9293 + printk("Image already stored: powering down immediately.");
9294 + do_suspend2_step(STEP_SUSPEND_POWERDOWN);
9295 + return 1; /* Just in case we're using S3 */
9298 + printk("Invalidating previous image.\n");
9299 + suspendActiveAllocator->invalidate_image();
9304 +static int suspend_init(void)
9306 + suspend_result = 0;
9308 + printk(KERN_INFO "Suspend2: Initiating a software suspend cycle.\n");
9314 + suspend_io_time[0][0] = suspend_io_time[0][1] =
9315 + suspend_io_time[1][0] = suspend_io_time[1][1] = 0;
9317 + if (!test_suspend_state(SUSPEND_CAN_SUSPEND) ||
9318 + allocate_bitmaps())
9321 + mark_nosave_pages();
9323 + suspend_prepare_console();
9324 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) ||
9325 + !disable_nonboot_cpus())
9328 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9329 + set_result_state(SUSPEND_ABORTED);
9333 +static int can_suspend(void)
9336 + if (!mutex_trylock(&pm_mutex)) {
9337 + printk("Suspend2: Failed to obtain pm_mutex.\n");
9339 + set_result_state(SUSPEND_ABORTED);
9340 + set_result_state(SUSPEND_PM_SEM);
9346 + if (!test_suspend_state(SUSPEND_CAN_SUSPEND))
9347 + suspend_attempt_to_parse_resume_device(0);
9349 + if (!test_suspend_state(SUSPEND_CAN_SUSPEND)) {
9350 + printk("Suspend2: Software suspend is disabled.\n"
9351 + "This may be because you haven't put something along "
9352 + "the lines of\n\nresume2=swap:/dev/hda1\n\n"
9353 + "in lilo.conf or equivalent. (Where /dev/hda1 is your "
9354 + "swap partition).\n");
9355 + set_result_state(SUSPEND_ABORTED);
9357 + mutex_unlock(&pm_mutex);
9366 +static int do_power_down(void)
9368 + /* If switching images fails, do normal powerdown */
9369 + if (poweroff_resume2[0])
9370 + do_suspend2_step(STEP_RESUME_ALT_IMAGE);
9372 + suspend_cond_pause(1, "About to power down or reboot.");
9373 + suspend2_power_down();
9375 + /* If we return, it's because we suspended to ram */
9376 + if (read_pageset2(1))
9377 + panic("Attempt to reload pagedir 2 failed. Try rebooting.");
9387 + * Functionality : High level routine which performs the steps necessary
9388 + * to save the image after preparatory steps have been taken.
9389 + * Key Assumptions : Processes frozen, sufficient memory available, drivers
9392 +static int __save_image(void)
9396 + suspend_prepare_status(DONT_CLEAR_BAR, "Starting to save the image..");
9398 + suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9399 + " - Final values: %d and %d.\n",
9400 + pagedir1.size, pagedir2.size);
9402 + suspend_cond_pause(1, "About to write pagedir2.");
9404 + calculate_check_checksums(0);
9406 + temp_result = write_pageset(&pagedir2);
9408 + if (temp_result == -1 || test_result_state(SUSPEND_ABORTED))
9411 + suspend_cond_pause(1, "About to copy pageset 1.");
9413 + if (test_result_state(SUSPEND_ABORTED))
9416 + suspend_deactivate_storage(1);
9418 + suspend_prepare_status(DONT_CLEAR_BAR, "Doing atomic copy.");
9420 + suspend2_in_suspend = 1;
9422 + if (suspend2_platform_prepare()) {
9423 + set_result_state(SUSPEND_PLATFORM_PREP_FAILED);
9424 + set_result_state(SUSPEND_ABORTED);
9428 + suspend_console();
9429 + if (device_suspend(PMSG_FREEZE)) {
9430 + set_result_state(SUSPEND_DEVICE_REFUSED);
9431 + set_result_state(SUSPEND_ABORTED);
9432 + goto ResumeConsole;
9435 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) &&
9436 + disable_nonboot_cpus()) {
9437 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9438 + set_result_state(SUSPEND_ABORTED);
9440 + temp_result = suspend2_suspend();
9442 + /* We return here at resume time too! */
9443 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9444 + enable_nonboot_cpus();
9451 + suspend2_platform_finish();
9453 + if (suspend_activate_storage(1))
9454 + panic("Failed to reactivate our storage.");
9456 + if (temp_result || test_result_state(SUSPEND_ABORTED))
9459 + /* Resume time? */
9460 + if (!suspend2_in_suspend) {
9465 + /* Nope. Suspending. So, see if we can save the image... */
9467 + suspend_update_status(pagedir2.size,
9468 + pagedir1.size + pagedir2.size,
9471 + if (test_result_state(SUSPEND_ABORTED))
9472 + goto abort_reloading_pagedir_two;
9474 + suspend_cond_pause(1, "About to write pageset1.");
9476 + suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9477 + "-- Writing pageset1\n");
9479 + temp_result = write_pageset(&pagedir1);
9481 + /* We didn't overwrite any memory, so no reread needs to be done. */
9482 + if (test_action_state(SUSPEND_TEST_FILTER_SPEED))
9485 + if (temp_result == 1 || test_result_state(SUSPEND_ABORTED))
9486 + goto abort_reloading_pagedir_two;
9488 + suspend_cond_pause(1, "About to write header.");
9490 + if (test_result_state(SUSPEND_ABORTED))
9491 + goto abort_reloading_pagedir_two;
9493 + temp_result = write_image_header();
9495 + if (test_action_state(SUSPEND_TEST_BIO))
9498 + if (!temp_result && !test_result_state(SUSPEND_ABORTED))
9501 +abort_reloading_pagedir_two:
9502 + temp_result = read_pageset2(1);
9504 + /* If that failed, we're sunk. Panic! */
9506 + panic("Attempt to reload pagedir 2 while aborting "
9507 + "a suspend failed.");
9515 + * Save the prepared image.
9518 +static int do_save_image(void)
9520 + int result = __save_image();
9521 + if (!suspend2_in_suspend || result)
9527 +/* do_prepare_image
9529 + * Seek to initialise and prepare an image to be saved. On failure,
9533 +static int do_prepare_image(void)
9535 + if (suspend_activate_storage(0))
9539 + * If kept image and still keeping image and suspending to RAM, we will
9540 + * return 1 after suspending and resuming (provided the power doesn't
9544 + if (!can_suspend() ||
9545 + (test_result_state(SUSPEND_KEPT_IMAGE) &&
9546 + check_still_keeping_image()))
9549 + if (suspend_init() && !suspend_prepare_image() &&
9550 + !test_result_state(SUSPEND_ABORTED))
9558 +static int do_check_can_resume(void)
9560 + char *buf = (char *) get_zeroed_page(GFP_KERNEL);
9566 + /* Only interested in first byte, so throw away return code. */
9567 + image_exists_read(buf, PAGE_SIZE);
9569 + if (buf[0] == '1')
9572 + free_page((unsigned long) buf);
9577 + * We check if we have an image and if so we try to resume.
9579 +static int do_load_atomic_copy(void)
9581 + int read_image_result = 0;
9583 + if (sizeof(swp_entry_t) != sizeof(long)) {
9584 + printk(KERN_WARNING "Suspend2: The size of swp_entry_t != size"
9585 + " of long. Please report this!\n");
9589 + if (!resume2_file[0])
9590 + printk(KERN_WARNING "Suspend2: "
9591 + "You need to use a resume2= command line parameter to "
9592 + "tell Suspend2 where to look for an image.\n");
9594 + suspend_activate_storage(0);
9596 + if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK)) &&
9597 + !suspend_attempt_to_parse_resume_device(0)) {
9599 + * Without a usable storage device we can do nothing -
9600 + * even if noresume is given
9603 + if (!suspendNumAllocators)
9604 + printk(KERN_ALERT "Suspend2: "
9605 + "No storage allocators have been registered.\n");
9607 + printk(KERN_ALERT "Suspend2: "
9608 + "Missing or invalid storage location "
9609 + "(resume2= parameter). Please correct and "
9610 + "rerun lilo (or equivalent) before "
9612 + suspend_deactivate_storage(0);
9616 + read_image_result = read_pageset1(); /* non fatal error ignored */
9618 + if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
9619 + printk(KERN_WARNING "Suspend2: Resuming disabled as requested.\n");
9620 + clear_suspend_state(SUSPEND_NORESUME_SPECIFIED);
9623 + suspend_deactivate_storage(0);
9625 + if (read_image_result)
9631 +static void prepare_restore_load_alt_image(int prepare)
9633 + static dyn_pageflags_t pageset1_map_save, pageset1_copy_map_save;
9636 + pageset1_map_save = pageset1_map;
9637 + pageset1_map = NULL;
9638 + pageset1_copy_map_save = pageset1_copy_map;
9639 + pageset1_copy_map = NULL;
9640 + set_suspend_state(SUSPEND_LOADING_ALT_IMAGE);
9641 + suspend_reset_alt_image_pageset2_pfn();
9644 + free_dyn_pageflags(&pageset1_map);
9645 + pageset1_map = pageset1_map_save;
9646 + if (pageset1_copy_map)
9647 + free_dyn_pageflags(&pageset1_copy_map);
9648 + pageset1_copy_map = pageset1_copy_map_save;
9649 + clear_suspend_state(SUSPEND_NOW_RESUMING);
9650 + clear_suspend_state(SUSPEND_LOADING_ALT_IMAGE);
9654 +int pre_resume_freeze(void)
9656 + if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG)) {
9657 + suspend_prepare_status(DONT_CLEAR_BAR, "Disable nonboot cpus.");
9658 + if (disable_nonboot_cpus()) {
9659 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9660 + set_result_state(SUSPEND_ABORTED);
9665 + suspend_prepare_status(DONT_CLEAR_BAR, "Freeze processes.");
9667 + if (freeze_processes()) {
9668 + printk("Some processes failed to suspend\n");
9675 +void post_resume_thaw(void)
9678 + if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9679 + enable_nonboot_cpus();
9682 +int do_suspend2_step(int step)
9687 + case STEP_SUSPEND_PREPARE_IMAGE:
9688 + return do_prepare_image();
9689 + case STEP_SUSPEND_SAVE_IMAGE:
9690 + return do_save_image();
9691 + case STEP_SUSPEND_POWERDOWN:
9692 + return do_power_down();
9693 + case STEP_RESUME_CAN_RESUME:
9694 + return do_check_can_resume();
9695 + case STEP_RESUME_LOAD_PS1:
9696 + return do_load_atomic_copy();
9697 + case STEP_RESUME_DO_RESTORE:
9699 + * If we succeed, this doesn't return.
9700 + * Instead, we return from do_save_image() in the
9701 + * suspended kernel.
9703 + result = suspend_atomic_restore();
9705 + post_resume_thaw();
9707 + case STEP_RESUME_ALT_IMAGE:
9708 + printk("Trying to resume alternate image.\n");
9709 + suspend2_in_suspend = 0;
9710 + save_restore_resume2(SAVE, NOQUIET);
9711 + prepare_restore_load_alt_image(1);
9712 + if (!do_check_can_resume()) {
9713 + printk("Nothing to resume from.\n");
9716 + if (!do_load_atomic_copy()) {
9717 + printk("Failed to load image.\n");
9718 + suspend_atomic_restore();
9721 + prepare_restore_load_alt_image(0);
9722 + save_restore_resume2(RESTORE, NOQUIET);
9729 +/* -- Functions for kickstarting a suspend or resume --- */
9732 + * Check if we have an image and if so try to resume.
9734 +void __suspend2_try_resume(void)
9736 + set_suspend_state(SUSPEND_TRYING_TO_RESUME);
9737 + resume_attempted = 1;
9739 + if (do_suspend2_step(STEP_RESUME_CAN_RESUME) &&
9740 + !do_suspend2_step(STEP_RESUME_LOAD_PS1))
9741 + do_suspend2_step(STEP_RESUME_DO_RESTORE);
9745 + clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
9746 + clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
9747 + clear_suspend_state(SUSPEND_NOW_RESUMING);
9750 +/* Wrapper for when called from init/do_mounts.c */
9751 +void _suspend2_try_resume(void)
9753 + resume_attempted = 1;
9755 + if (suspend_start_anything(SYSFS_RESUMING))
9758 + /* Unlock will be done in do_cleanup */
9759 + mutex_lock(&pm_mutex);
9762 + __suspend2_try_resume();
9765 + * For initramfs, we have to clear the boot time
9766 + * flag after trying to resume
9768 + clear_suspend_state(SUSPEND_BOOT_TIME);
9769 + suspend_finish_anything(SYSFS_RESUMING);
9773 + * _suspend2_try_suspend
9775 + * Called From : drivers/acpi/sleep/main.c
9778 +int _suspend2_try_suspend(int have_pmsem)
9780 + int result = 0, sys_power_disk = 0;
9782 + if (!atomic_read(&actions_running)) {
9783 + /* Came in via /sys/power/disk */
9784 + if (suspend_start_anything(SYSFS_SUSPENDING))
9786 + sys_power_disk = 1;
9789 + get_pmsem = !have_pmsem;
9791 + if (strlen(poweroff_resume2)) {
9792 + attempt_to_parse_po_resume_device2();
9794 + if (!strlen(poweroff_resume2)) {
9795 + printk("Poweroff resume2 now invalid. Aborting.\n");
9800 + if ((result = do_suspend2_step(STEP_SUSPEND_PREPARE_IMAGE)))
9803 + if (test_action_state(SUSPEND_FREEZER_TEST)) {
9808 + if ((result = do_suspend2_step(STEP_SUSPEND_SAVE_IMAGE)))
9811 + /* This code runs at resume time too! */
9812 + if (suspend2_in_suspend)
9813 + result = do_suspend2_step(STEP_SUSPEND_POWERDOWN);
9815 + if (sys_power_disk)
9816 + suspend_finish_anything(SYSFS_SUSPENDING);
9821 + * This array contains entries that are automatically registered at
9822 + * boot. Modules and the console code register their own entries separately.
9824 +static struct suspend_sysfs_data sysfs_params[] = {
9825 + { SUSPEND2_ATTR("extra_pages_allowance", SYSFS_RW),
9826 + SYSFS_INT(&extra_pd1_pages_allowance, 0, INT_MAX, 0)
9829 + { SUSPEND2_ATTR("image_exists", SYSFS_RW),
9830 + SYSFS_CUSTOM(image_exists_read, image_exists_write,
9831 + SYSFS_NEEDS_SM_FOR_BOTH)
9834 + { SUSPEND2_ATTR("resume2", SYSFS_RW),
9835 + SYSFS_STRING(resume2_file, 255, SYSFS_NEEDS_SM_FOR_WRITE),
9836 + .write_side_effect = attempt_to_parse_resume_device2,
9839 + { SUSPEND2_ATTR("poweroff_resume2", SYSFS_RW),
9840 + SYSFS_STRING(poweroff_resume2, 255, SYSFS_NEEDS_SM_FOR_WRITE),
9841 + .write_side_effect = attempt_to_parse_po_resume_device2,
9843 + { SUSPEND2_ATTR("debug_info", SYSFS_READONLY),
9844 + SYSFS_CUSTOM(get_suspend_debug_info, NULL, 0)
9847 + { SUSPEND2_ATTR("ignore_rootfs", SYSFS_RW),
9848 + SYSFS_BIT(&suspend_action, SUSPEND_IGNORE_ROOTFS, 0)
9851 + { SUSPEND2_ATTR("image_size_limit", SYSFS_RW),
9852 + SYSFS_INT(&image_size_limit, -2, INT_MAX, 0)
9855 + { SUSPEND2_ATTR("last_result", SYSFS_RW),
9856 + SYSFS_UL(&suspend_result, 0, 0, 0)
9859 + { SUSPEND2_ATTR("no_multithreaded_io", SYSFS_RW),
9860 + SYSFS_BIT(&suspend_action, SUSPEND_NO_MULTITHREADED_IO, 0)
9863 + { SUSPEND2_ATTR("full_pageset2", SYSFS_RW),
9864 + SYSFS_BIT(&suspend_action, SUSPEND_PAGESET2_FULL, 0)
9867 + { SUSPEND2_ATTR("reboot", SYSFS_RW),
9868 + SYSFS_BIT(&suspend_action, SUSPEND_REBOOT, 0)
9871 +#ifdef CONFIG_SOFTWARE_SUSPEND
9872 + { SUSPEND2_ATTR("replace_swsusp", SYSFS_RW),
9873 + SYSFS_BIT(&suspend_action, SUSPEND_REPLACE_SWSUSP, 0)
9877 + { SUSPEND2_ATTR("resume_commandline", SYSFS_RW),
9878 + SYSFS_STRING(suspend2_nosave_commandline, COMMAND_LINE_SIZE, 0)
9881 + { SUSPEND2_ATTR("version", SYSFS_READONLY),
9882 + SYSFS_STRING(SUSPEND_CORE_VERSION, 0, 0)
9885 + { SUSPEND2_ATTR("no_load_direct", SYSFS_RW),
9886 + SYSFS_BIT(&suspend_action, SUSPEND_NO_DIRECT_LOAD, 0)
9889 + { SUSPEND2_ATTR("freezer_test", SYSFS_RW),
9890 + SYSFS_BIT(&suspend_action, SUSPEND_FREEZER_TEST, 0)
9893 + { SUSPEND2_ATTR("test_bio", SYSFS_RW),
9894 + SYSFS_BIT(&suspend_action, SUSPEND_TEST_BIO, 0)
9897 + { SUSPEND2_ATTR("test_filter_speed", SYSFS_RW),
9898 + SYSFS_BIT(&suspend_action, SUSPEND_TEST_FILTER_SPEED, 0)
9901 + { SUSPEND2_ATTR("slow", SYSFS_RW),
9902 + SYSFS_BIT(&suspend_action, SUSPEND_SLOW, 0)
9905 + { SUSPEND2_ATTR("no_pageset2", SYSFS_RW),
9906 + SYSFS_BIT(&suspend_action, SUSPEND_NO_PAGESET2, 0)
9909 + { SUSPEND2_ATTR("late_cpu_hotplug", SYSFS_RW),
9910 + SYSFS_BIT(&suspend_action, SUSPEND_LATE_CPU_HOTPLUG, 0)
9913 +#if defined(CONFIG_ACPI)
9914 + { SUSPEND2_ATTR("powerdown_method", SYSFS_RW),
9915 + SYSFS_UL(&suspend2_poweroff_method, 0, 5, 0)
9919 +#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
9920 + { SUSPEND2_ATTR("keep_image", SYSFS_RW),
9921 + SYSFS_BIT(&suspend_action, SUSPEND_KEEP_IMAGE, 0)
9926 +struct suspend2_core_fns my_fns = {
9927 + .get_nonconflicting_page = __suspend_get_nonconflicting_page,
9928 + .post_context_save = __suspend_post_context_save,
9929 + .try_suspend = _suspend2_try_suspend,
9930 + .try_resume = _suspend2_try_resume,
9933 +static __init int core_load(void)
9936 + numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
9938 + printk("Suspend v" SUSPEND_CORE_VERSION "\n");
9940 + if (s2_sysfs_init())
9943 + for (i=0; i< numfiles; i++)
9944 + suspend_register_sysfs_file(&suspend2_subsys.kobj,
9945 + &sysfs_params[i]);
9947 + s2_core_fns = &my_fns;
9949 + if (s2_checksum_init())
9951 + if (s2_cluster_init())
9953 + if (s2_usm_init())
9958 +#ifdef CONFIG_SOFTWARE_SUSPEND
9959 + /* Overriding resume2= with resume=? */
9960 + if (test_action_state(SUSPEND_REPLACE_SWSUSP) && resume_file[0])
9961 + strncpy(resume2_file, resume_file, 256);
9968 +static __exit void core_unload(void)
9971 + numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
9974 + s2_checksum_exit();
9975 + s2_cluster_exit();
9978 + for (i=0; i< numfiles; i++)
9979 + suspend_unregister_sysfs_file(&suspend2_subsys.kobj,
9980 + &sysfs_params[i]);
9982 + s2_core_fns = NULL;
9986 +MODULE_LICENSE("GPL");
9987 +module_init(core_load);
9988 +module_exit(core_unload);
9990 +late_initcall(core_load);
9993 +#ifdef CONFIG_SUSPEND2_EXPORTS
9994 +EXPORT_SYMBOL_GPL(pagedir2);
9996 diff -ruN linux-2.6.22/kernel/power/suspend.h suspend2-2.2.10-for-2.6.22/kernel/power/suspend.h
9997 --- linux-2.6.22/kernel/power/suspend.h 1970-01-01 10:00:00.000000000 +1000
9998 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend.h 2007-07-11 22:25:42.000000000 +1000
10001 + * kernel/power/suspend.h
10003 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10005 + * This file is released under the GPLv2.
10007 + * It contains declarations used throughout swsusp.
10011 +#ifndef KERNEL_POWER_SUSPEND_H
10012 +#define KERNEL_POWER_SUSPEND_H
10014 +#include <linux/delay.h>
10015 +#include <linux/bootmem.h>
10016 +#include <linux/suspend.h>
10017 +#include <linux/dyn_pageflags.h>
10018 +#include <asm/setup.h>
10019 +#include "pageflags.h"
10021 +#define SUSPEND_CORE_VERSION "2.2.10"
10023 +/* == Action states == */
10030 + SUSPEND_CAN_CANCEL,
10031 + SUSPEND_KEEP_IMAGE,
10032 + SUSPEND_FREEZER_TEST,
10033 + SUSPEND_SINGLESTEP,
10034 + SUSPEND_PAUSE_NEAR_PAGESET_END,
10035 + SUSPEND_TEST_FILTER_SPEED,
10036 + SUSPEND_TEST_BIO,
10037 + SUSPEND_NO_PAGESET2,
10038 + SUSPEND_PM_PREPARE_CONSOLE,
10039 + SUSPEND_IGNORE_ROOTFS,
10040 + SUSPEND_REPLACE_SWSUSP,
10041 + SUSPEND_RETRY_RESUME,
10042 + SUSPEND_PAGESET2_FULL,
10043 + SUSPEND_ABORT_ON_RESAVE_NEEDED,
10044 + SUSPEND_NO_MULTITHREADED_IO,
10045 + SUSPEND_NO_DIRECT_LOAD,
10046 + SUSPEND_LATE_CPU_HOTPLUG,
10049 +extern unsigned long suspend_action;
10051 +#define clear_action_state(bit) (test_and_clear_bit(bit, &suspend_action))
10052 +#define test_action_state(bit) (test_bit(bit, &suspend_action))
10054 +/* == Result states == */
10058 + SUSPEND_ABORT_REQUESTED,
10059 + SUSPEND_NOSTORAGE_AVAILABLE,
10060 + SUSPEND_INSUFFICIENT_STORAGE,
10061 + SUSPEND_FREEZING_FAILED,
10062 + SUSPEND_UNEXPECTED_ALLOC,
10063 + SUSPEND_KEPT_IMAGE,
10064 + SUSPEND_WOULD_EAT_MEMORY,
10065 + SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY,
10066 + SUSPEND_ENCRYPTION_SETUP_FAILED,
10068 + SUSPEND_DEVICE_REFUSED,
10069 + SUSPEND_EXTRA_PAGES_ALLOW_TOO_SMALL,
10070 + SUSPEND_UNABLE_TO_PREPARE_IMAGE,
10071 + SUSPEND_FAILED_MODULE_INIT,
10072 + SUSPEND_FAILED_MODULE_CLEANUP,
10073 + SUSPEND_FAILED_IO,
10074 + SUSPEND_OUT_OF_MEMORY,
10075 + SUSPEND_IMAGE_ERROR,
10076 + SUSPEND_PLATFORM_PREP_FAILED,
10077 + SUSPEND_CPU_HOTPLUG_FAILED,
10080 +extern unsigned long suspend_result;
10082 +#define set_result_state(bit) (test_and_set_bit(bit, &suspend_result))
10083 +#define clear_result_state(bit) (test_and_clear_bit(bit, &suspend_result))
10084 +#define test_result_state(bit) (test_bit(bit, &suspend_result))
10086 +/* == Debug sections and levels == */
10088 +/* debugging levels. */
10090 + SUSPEND_STATUS = 0,
10091 + SUSPEND_ERROR = 2,
10099 + SUSPEND_ANY_SECTION,
10100 + SUSPEND_EAT_MEMORY,
10107 +extern unsigned long suspend_debug_state;
10109 +#define set_debug_state(bit) (test_and_set_bit(bit, &suspend_debug_state))
10110 +#define clear_debug_state(bit) (test_and_clear_bit(bit, &suspend_debug_state))
10111 +#define test_debug_state(bit) (test_bit(bit, &suspend_debug_state))
10113 +/* == Steps in suspending == */
10116 + STEP_SUSPEND_PREPARE_IMAGE,
10117 + STEP_SUSPEND_SAVE_IMAGE,
10118 + STEP_SUSPEND_POWERDOWN,
10119 + STEP_RESUME_CAN_RESUME,
10120 + STEP_RESUME_LOAD_PS1,
10121 + STEP_RESUME_DO_RESTORE,
10122 + STEP_RESUME_READ_PS2,
10124 + STEP_RESUME_ALT_IMAGE,
10127 +/* == Suspend states ==
10128 + (see also include/linux/suspend.h) */
10130 +#define get_suspend_state() (suspend_state)
10131 +#define restore_suspend_state(saved_state) \
10132 + do { suspend_state = saved_state; } while(0)
10134 +/* == Module support == */
10136 +struct suspend2_core_fns {
10137 + int (*post_context_save)(void);
10138 + unsigned long (*get_nonconflicting_page)(void);
10139 + int (*try_suspend)(int have_pmsem);
10140 + void (*try_resume)(void);
10143 +extern struct suspend2_core_fns *s2_core_fns;
10145 +/* == All else == */
10146 +#define KB(x) ((x) << (PAGE_SHIFT - 10))
10147 +#define MB(x) ((x) >> (20 - PAGE_SHIFT))
10149 +extern int suspend_start_anything(int suspend_or_resume);
10150 +extern void suspend_finish_anything(int suspend_or_resume);
10152 +extern int save_image_part1(void);
10153 +extern int suspend_atomic_restore(void);
10155 +extern int _suspend2_try_suspend(int have_pmsem);
10156 +extern void __suspend2_try_resume(void);
10158 +extern int __suspend_post_context_save(void);
10160 +extern unsigned int nr_suspends;
10161 +extern char resume2_file[256];
10162 +extern char poweroff_resume2[256];
10164 +extern void copyback_post(void);
10165 +extern int suspend2_suspend(void);
10166 +extern int extra_pd1_pages_used;
10168 +extern int suspend_io_time[2][2];
10170 +#define SECTOR_SIZE 512
10172 +extern int suspend_early_boot_message
10173 + (int can_erase_image, int default_answer, char *warning_reason, ...);
10175 +static inline int load_direct(struct page *page)
10177 + return test_action_state(SUSPEND_NO_DIRECT_LOAD) ? 0 : PagePageset1Copy(page);
10180 +extern int pre_resume_freeze(void);
10182 diff -ruN linux-2.6.22/kernel/power/suspend2_builtin.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend2_builtin.c
10183 --- linux-2.6.22/kernel/power/suspend2_builtin.c 1970-01-01 10:00:00.000000000 +1000
10184 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend2_builtin.c 2007-07-11 22:25:42.000000000 +1000
10187 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10189 + * This file is released under the GPLv2.
10191 +#include <linux/module.h>
10192 +#include <linux/resume-trace.h>
10193 +#include <linux/syscalls.h>
10194 +#include <linux/kernel.h>
10195 +#include <linux/swap.h>
10196 +#include <linux/syscalls.h>
10197 +#include <linux/bio.h>
10198 +#include <linux/root_dev.h>
10199 +#include <linux/freezer.h>
10200 +#include <linux/reboot.h>
10201 +#include <linux/writeback.h>
10202 +#include <linux/tty.h>
10203 +#include <linux/crypto.h>
10204 +#include <linux/cpu.h>
10205 +#include <linux/dyn_pageflags.h>
10207 +#include "suspend.h"
10208 +#include "extent.h"
10209 +#include "block_io.h"
10210 +#include "netlink.h"
10211 +#include "prepare_image.h"
10213 +#include "sysfs.h"
10214 +#include "pagedir.h"
10215 +#include "modules.h"
10216 +#include "suspend2_builtin.h"
10218 +#ifndef CONFIG_SOFTWARE_SUSPEND
10219 +struct hibernation_ops *hibernation_ops;
10222 + * hibernation_set_ops - set the global hibernate operations
10223 + * @ops: the hibernation operations to use in subsequent hibernation transitions
10226 +void hibernation_set_ops(struct hibernation_ops *ops)
10228 + if (ops && !(ops->prepare && ops->enter && ops->finish)) {
10232 + mutex_lock(&pm_mutex);
10233 + hibernation_ops = ops;
10234 + mutex_unlock(&pm_mutex);
10236 +EXPORT_SYMBOL_GPL(hibernation_set_ops);
10239 +EXPORT_SYMBOL_GPL(hibernation_ops);
10241 +#ifdef CONFIG_SUSPEND2_CORE_EXPORTS
10242 +#ifdef CONFIG_SOFTWARE_SUSPEND
10243 +EXPORT_SYMBOL_GPL(resume_file);
10246 +EXPORT_SYMBOL_GPL(max_pfn);
10247 +EXPORT_SYMBOL_GPL(free_dyn_pageflags);
10248 +EXPORT_SYMBOL_GPL(clear_dynpageflag);
10249 +EXPORT_SYMBOL_GPL(test_dynpageflag);
10250 +EXPORT_SYMBOL_GPL(set_dynpageflag);
10251 +EXPORT_SYMBOL_GPL(get_next_bit_on);
10252 +EXPORT_SYMBOL_GPL(allocate_dyn_pageflags);
10253 +EXPORT_SYMBOL_GPL(clear_dyn_pageflags);
10255 +#ifdef CONFIG_X86_64
10256 +EXPORT_SYMBOL_GPL(restore_processor_state);
10257 +EXPORT_SYMBOL_GPL(save_processor_state);
10260 +EXPORT_SYMBOL_GPL(kernel_shutdown_prepare);
10261 +EXPORT_SYMBOL_GPL(drop_pagecache);
10262 +EXPORT_SYMBOL_GPL(restore_pblist);
10263 +EXPORT_SYMBOL_GPL(pm_mutex);
10264 +EXPORT_SYMBOL_GPL(pm_restore_console);
10265 +EXPORT_SYMBOL_GPL(super_blocks);
10266 +EXPORT_SYMBOL_GPL(next_zone);
10268 +EXPORT_SYMBOL_GPL(freeze_processes);
10269 +EXPORT_SYMBOL_GPL(thaw_processes);
10270 +EXPORT_SYMBOL_GPL(thaw_kernel_threads);
10271 +EXPORT_SYMBOL_GPL(shrink_all_memory);
10272 +EXPORT_SYMBOL_GPL(shrink_one_zone);
10273 +EXPORT_SYMBOL_GPL(saveable_page);
10274 +EXPORT_SYMBOL_GPL(swsusp_arch_suspend);
10275 +EXPORT_SYMBOL_GPL(swsusp_arch_resume);
10276 +EXPORT_SYMBOL_GPL(pm_ops);
10277 +EXPORT_SYMBOL_GPL(pm_prepare_console);
10278 +EXPORT_SYMBOL_GPL(follow_page);
10279 +EXPORT_SYMBOL_GPL(machine_halt);
10280 +EXPORT_SYMBOL_GPL(block_dump);
10281 +EXPORT_SYMBOL_GPL(unlink_lru_lists);
10282 +EXPORT_SYMBOL_GPL(relink_lru_lists);
10283 +EXPORT_SYMBOL_GPL(power_subsys);
10284 +EXPORT_SYMBOL_GPL(machine_power_off);
10285 +EXPORT_SYMBOL_GPL(suspend_enter);
10286 +EXPORT_SYMBOL_GPL(first_online_pgdat);
10287 +EXPORT_SYMBOL_GPL(next_online_pgdat);
10288 +EXPORT_SYMBOL_GPL(machine_restart);
10289 +EXPORT_SYMBOL_GPL(saved_command_line);
10290 +EXPORT_SYMBOL_GPL(tasklist_lock);
10291 +#ifdef CONFIG_SUSPEND_SMP
10292 +EXPORT_SYMBOL_GPL(disable_nonboot_cpus);
10293 +EXPORT_SYMBOL_GPL(enable_nonboot_cpus);
10297 +#ifdef CONFIG_SUSPEND2_USERUI_EXPORTS
10298 +EXPORT_SYMBOL_GPL(kmsg_redirect);
10299 +#ifndef CONFIG_COMPAT
10300 +EXPORT_SYMBOL_GPL(sys_ioctl);
10304 +#if defined(CONFIG_SUSPEND2_USERUI_EXPORTS) || defined(CONFIG_SUSPEND2_CORE_EXPORTS)
10305 +EXPORT_SYMBOL_GPL(console_printk);
10307 +#ifdef CONFIG_SUSPEND2_SWAP_EXPORTS /* Suspend swap specific */
10308 +EXPORT_SYMBOL_GPL(sys_swapon);
10309 +EXPORT_SYMBOL_GPL(sys_swapoff);
10310 +EXPORT_SYMBOL_GPL(si_swapinfo);
10311 +EXPORT_SYMBOL_GPL(map_swap_page);
10312 +EXPORT_SYMBOL_GPL(get_swap_page);
10313 +EXPORT_SYMBOL_GPL(swap_free);
10314 +EXPORT_SYMBOL_GPL(get_swap_info_struct);
10317 +#ifdef CONFIG_SUSPEND2_FILE_EXPORTS
10318 +/* Suspend_file specific */
10319 +extern char * __initdata root_device_name;
10321 +EXPORT_SYMBOL_GPL(ROOT_DEV);
10322 +EXPORT_SYMBOL_GPL(root_device_name);
10323 +EXPORT_SYMBOL_GPL(sys_unlink);
10324 +EXPORT_SYMBOL_GPL(sys_mknod);
10327 +/* Swap or file */
10328 +#if defined(CONFIG_SUSPEND2_FILE_EXPORTS) || defined(CONFIG_SUSPEND2_SWAP_EXPORTS)
10329 +EXPORT_SYMBOL_GPL(bio_set_pages_dirty);
10330 +EXPORT_SYMBOL_GPL(name_to_dev_t);
10333 +#if defined(CONFIG_SUSPEND2_EXPORTS) || defined(CONFIG_SUSPEND2_CORE_EXPORTS)
10334 +EXPORT_SYMBOL_GPL(snprintf_used);
10336 +struct suspend2_core_fns *s2_core_fns;
10337 +EXPORT_SYMBOL_GPL(s2_core_fns);
10339 +dyn_pageflags_t pageset1_map;
10340 +dyn_pageflags_t pageset1_copy_map;
10341 +EXPORT_SYMBOL_GPL(pageset1_map);
10342 +EXPORT_SYMBOL_GPL(pageset1_copy_map);
10344 +unsigned long suspend_result = 0;
10345 +unsigned long suspend_debug_state = 0;
10346 +int suspend_io_time[2][2];
10347 +struct pagedir pagedir1 = {1};
10349 +EXPORT_SYMBOL_GPL(suspend_io_time);
10350 +EXPORT_SYMBOL_GPL(suspend_debug_state);
10351 +EXPORT_SYMBOL_GPL(suspend_result);
10352 +EXPORT_SYMBOL_GPL(pagedir1);
10354 +unsigned long suspend_get_nonconflicting_page(void)
10356 + return s2_core_fns->get_nonconflicting_page();
10359 +int suspend_post_context_save(void)
10361 + return s2_core_fns->post_context_save();
10364 +int suspend2_try_suspend(int have_pmsem)
10366 + if (!s2_core_fns)
10369 + return s2_core_fns->try_suspend(have_pmsem);
10372 +void suspend2_try_resume(void)
10375 + s2_core_fns->try_resume();
10378 +int suspend2_lowlevel_builtin(void)
10382 + save_processor_state();
10383 + if ((error = swsusp_arch_suspend()))
10384 + printk(KERN_ERR "Error %d suspending\n", error);
10385 + /* Restore control flow appears here */
10386 + restore_processor_state();
10391 +#ifndef CONFIG_SOFTWARE_SUSPEND
10392 +int hibernate(void)
10394 + return suspend2_try_suspend(0);
10398 +EXPORT_SYMBOL_GPL(suspend2_lowlevel_builtin);
10400 +unsigned long suspend_compress_bytes_in, suspend_compress_bytes_out;
10401 +EXPORT_SYMBOL_GPL(suspend_compress_bytes_in);
10402 +EXPORT_SYMBOL_GPL(suspend_compress_bytes_out);
10404 +#ifdef CONFIG_SUSPEND2_REPLACE_SWSUSP
10405 +unsigned long suspend_action = (1 << SUSPEND_REPLACE_SWSUSP) | (1 << SUSPEND_PAGESET2_FULL);
10407 +unsigned long suspend_action = 1 << SUSPEND_PAGESET2_FULL;
10409 +EXPORT_SYMBOL_GPL(suspend_action);
10411 +unsigned long suspend_state = ((1 << SUSPEND_BOOT_TIME) |
10412 + (1 << SUSPEND_IGNORE_LOGLEVEL) |
10413 + (1 << SUSPEND_IO_STOPPED));
10414 +EXPORT_SYMBOL_GPL(suspend_state);
10416 +/* The number of suspends we have started (some may have been cancelled) */
10417 +unsigned int nr_suspends;
10418 +EXPORT_SYMBOL_GPL(nr_suspends);
10420 +char resume2_file[256] = CONFIG_SUSPEND2_DEFAULT_RESUME2;
10421 +EXPORT_SYMBOL_GPL(resume2_file);
10423 +int suspend2_running = 0;
10424 +EXPORT_SYMBOL_GPL(suspend2_running);
10426 +int suspend2_in_suspend __nosavedata;
10427 +EXPORT_SYMBOL_GPL(suspend2_in_suspend);
10429 +unsigned long suspend2_nosave_state1 __nosavedata = 0;
10430 +unsigned long suspend2_nosave_state2 __nosavedata = 0;
10431 +int suspend2_nosave_state3 __nosavedata = 0;
10432 +int suspend2_nosave_io_speed[2][2] __nosavedata;
10433 +__nosavedata char suspend2_nosave_commandline[COMMAND_LINE_SIZE];
10435 +__nosavedata struct pbe *restore_highmem_pblist;
10437 +#ifdef CONFIG_SUSPEND2_CORE_EXPORTS
10438 +#ifdef CONFIG_HIGHMEM
10439 +EXPORT_SYMBOL_GPL(nr_free_highpages);
10440 +EXPORT_SYMBOL_GPL(saveable_highmem_page);
10441 +EXPORT_SYMBOL_GPL(restore_highmem_pblist);
10444 +EXPORT_SYMBOL_GPL(suspend2_nosave_state1);
10445 +EXPORT_SYMBOL_GPL(suspend2_nosave_state2);
10446 +EXPORT_SYMBOL_GPL(suspend2_nosave_state3);
10447 +EXPORT_SYMBOL_GPL(suspend2_nosave_io_speed);
10448 +EXPORT_SYMBOL_GPL(suspend2_nosave_commandline);
10451 +/* -- Commandline Parameter Handling ---
10453 + * Resume setup: obtain the storage device.
10455 +static int __init resume2_setup(char *str)
10460 + strncpy(resume2_file, str, 255);
10465 + * Allow the user to specify that we should ignore any image found and
10466 + * invalidate the image if necesssary. This is equivalent to running
10467 + * the task queue and a sync and then turning off the power. The same
10468 + * precautions should be taken: fsck if you're not journalled.
10470 +static int __init noresume2_setup(char *str)
10472 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
10476 +static int __init suspend_retry_resume_setup(char *str)
10478 + set_suspend_state(SUSPEND_RETRY_RESUME);
10482 +#ifndef CONFIG_SOFTWARE_SUSPEND
10483 +static int __init resume_setup(char *str)
10488 + strncpy(resume2_file, str, 255);
10492 +static int __init noresume_setup(char *str)
10494 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
10497 +__setup("noresume", noresume_setup);
10498 +__setup("resume=", resume_setup);
10501 +__setup("noresume2", noresume2_setup);
10502 +__setup("resume2=", resume2_setup);
10503 +__setup("suspend_retry_resume", suspend_retry_resume_setup);
10505 diff -ruN linux-2.6.22/kernel/power/suspend2_builtin.h suspend2-2.2.10-for-2.6.22/kernel/power/suspend2_builtin.h
10506 --- linux-2.6.22/kernel/power/suspend2_builtin.h 1970-01-01 10:00:00.000000000 +1000
10507 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend2_builtin.h 2007-07-11 22:25:42.000000000 +1000
10510 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10512 + * This file is released under the GPLv2.
10514 +#include <linux/dyn_pageflags.h>
10515 +#include <asm/setup.h>
10517 +extern struct suspend2_core_fns *s2_core_fns;
10518 +extern unsigned long suspend_compress_bytes_in, suspend_compress_bytes_out;
10519 +extern unsigned long suspend_action;
10520 +extern unsigned int nr_suspends;
10521 +extern char resume2_file[256];
10522 +extern int suspend2_in_suspend;
10524 +extern unsigned long suspend2_nosave_state1 __nosavedata;
10525 +extern unsigned long suspend2_nosave_state2 __nosavedata;
10526 +extern int suspend2_nosave_state3 __nosavedata;
10527 +extern int suspend2_nosave_io_speed[2][2] __nosavedata;
10528 +extern __nosavedata char suspend2_nosave_commandline[COMMAND_LINE_SIZE];
10529 +extern __nosavedata struct pbe *restore_highmem_pblist;
10531 +int suspend2_lowlevel_builtin(void);
10533 +extern dyn_pageflags_t __nosavedata suspend2_nosave_origmap;
10534 +extern dyn_pageflags_t __nosavedata suspend2_nosave_copymap;
10536 +#ifdef CONFIG_HIGHMEM
10537 +extern __nosavedata struct zone_data *suspend2_nosave_zone_list;
10538 +extern __nosavedata unsigned long suspend2_nosave_max_pfn;
10541 +extern unsigned long suspend_get_nonconflicting_page(void);
10542 +extern int suspend_post_context_save(void);
10543 +extern int suspend2_try_suspend(int have_pmsem);
10544 diff -ruN linux-2.6.22/kernel/power/suspend_block_io.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend_block_io.c
10545 --- linux-2.6.22/kernel/power/suspend_block_io.c 1970-01-01 10:00:00.000000000 +1000
10546 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend_block_io.c 2007-07-11 22:25:42.000000000 +1000
10549 + * kernel/power/suspend_block_io.c
10551 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10553 + * Distributed under GPLv2.
10555 + * This file contains block io functions for suspend2. These are
10556 + * used by the swapwriter and it is planned that they will also
10557 + * be used by the NFSwriter.
10561 +#include <linux/blkdev.h>
10562 +#include <linux/syscalls.h>
10563 +#include <linux/suspend.h>
10565 +#include "suspend.h"
10566 +#include "sysfs.h"
10567 +#include "modules.h"
10568 +#include "prepare_image.h"
10569 +#include "block_io.h"
10572 +static int pr_index;
10575 +#define PR_DEBUG(a, b...) do { if (pr_index < 20) printk(a, ##b); } while(0)
10577 +#define PR_DEBUG(a, b...) do { } while(0)
10580 +#define MAX_OUTSTANDING_IO 2048
10581 +#define SUBMIT_BATCH_SIZE 128
10583 +static int max_outstanding_io = MAX_OUTSTANDING_IO;
10584 +static int submit_batch_size = SUBMIT_BATCH_SIZE;
10587 + struct bio *sys_struct;
10588 + sector_t first_block;
10589 + struct page *bio_page, *dest_page;
10590 + int writing, readahead_index;
10591 + struct block_device *dev;
10592 + struct list_head list;
10595 +static LIST_HEAD(ioinfo_ready_for_cleanup);
10596 +static DEFINE_SPINLOCK(ioinfo_ready_lock);
10598 +static LIST_HEAD(ioinfo_submit_batch);
10599 +static DEFINE_SPINLOCK(ioinfo_submit_lock);
10601 +static LIST_HEAD(ioinfo_busy);
10602 +static DEFINE_SPINLOCK(ioinfo_busy_lock);
10604 +static struct io_info *waiting_on;
10606 +static atomic_t submit_batch;
10607 +static int submit_batched(void);
10609 +/* [Max] number of I/O operations pending */
10610 +static atomic_t outstanding_io;
10612 +static int extra_page_forward = 0;
10614 +static volatile unsigned long suspend_readahead_flags[
10615 + DIV_ROUND_UP(MAX_OUTSTANDING_IO, BITS_PER_LONG)];
10616 +static spinlock_t suspend_readahead_flags_lock = SPIN_LOCK_UNLOCKED;
10617 +static struct page *suspend_readahead_pages[MAX_OUTSTANDING_IO];
10618 +static int readahead_index, readahead_submit_index;
10620 +static int current_stream;
10621 +/* 0 = Header, 1 = Pageset1, 2 = Pageset2 */
10622 +struct extent_iterate_saved_state suspend_writer_posn_save[3];
10624 +/* Pointer to current entry being loaded/saved. */
10625 +struct extent_iterate_state suspend_writer_posn;
10627 +/* Not static, so that the allocators can setup and complete
10628 + * writing the header */
10629 +char *suspend_writer_buffer;
10630 +int suspend_writer_buffer_posn;
10632 +int suspend_read_fd;
10634 +static struct suspend_bdev_info *suspend_devinfo;
10636 +int suspend_header_bytes_used = 0;
10638 +DEFINE_MUTEX(suspend_bio_mutex);
10641 + * __suspend_bio_cleanup_one
10643 + * Description: Clean up after completing I/O on a page.
10644 + * Arguments: struct io_info: Data for I/O to be completed.
10646 +static void __suspend_bio_cleanup_one(struct io_info *io_info)
10648 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
10649 + "Cleanup IO: [%p]\n", io_info);
10651 + if (!io_info->writing && io_info->readahead_index == -1) {
10654 + * Copy the page we read into the buffer our caller provided.
10656 + to = (char *) kmap(io_info->dest_page);
10657 + from = (char *) kmap(io_info->bio_page);
10658 + memcpy(to, from, PAGE_SIZE);
10659 + kunmap(io_info->dest_page);
10660 + kunmap(io_info->bio_page);
10663 + if (io_info->writing || io_info->readahead_index == -1) {
10664 + /* Sanity check */
10665 + if (page_count(io_info->bio_page) != 2)
10666 + printk(KERN_EMERG "Cleanup IO: Page count on page %p"
10667 + " is %d. Not good!\n",
10668 + io_info->bio_page,
10669 + page_count(io_info->bio_page));
10670 + put_page(io_info->bio_page);
10671 + __free_page(io_info->bio_page);
10673 + put_page(io_info->bio_page);
10675 + bio_put(io_info->sys_struct);
10676 + io_info->sys_struct = NULL;
10679 +/* __suspend_io_cleanup
10682 +static void suspend_bio_cleanup_one(void *data)
10684 + struct io_info *io_info = (struct io_info *) data;
10685 + int readahead_index;
10686 + unsigned long flags;
10688 + readahead_index = io_info->readahead_index;
10689 + list_del_init(&io_info->list);
10690 + __suspend_bio_cleanup_one(io_info);
10692 + if (readahead_index > -1) {
10693 + int index = readahead_index/BITS_PER_LONG;
10694 + int bit = readahead_index - (index * BITS_PER_LONG);
10695 + spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
10696 + set_bit(bit, &suspend_readahead_flags[index]);
10697 + spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
10700 + if (waiting_on == io_info)
10701 + waiting_on = NULL;
10703 + atomic_dec(&outstanding_io);
10706 +/* suspend_cleanup_some_completed_io
10708 + * NB: This is designed so that multiple callers can be in here simultaneously.
10711 +static void suspend_cleanup_some_completed_io(void)
10713 + int num_cleaned = 0;
10714 + struct io_info *first;
10715 + unsigned long flags;
10717 + spin_lock_irqsave(&ioinfo_ready_lock, flags);
10718 + while(!list_empty(&ioinfo_ready_for_cleanup)) {
10719 + first = list_entry(ioinfo_ready_for_cleanup.next,
10720 + struct io_info, list);
10722 + list_del_init(&first->list);
10724 + spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10725 + suspend_bio_cleanup_one((void *) first);
10726 + spin_lock_irqsave(&ioinfo_ready_lock, flags);
10729 + if (num_cleaned == submit_batch_size)
10732 + spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10737 + * Actions taken when we want some I/O to get run.
10739 + * Submit any I/O that's batched up (if we're not already doing
10740 + * that, unplug queues, schedule and clean up whatever we can.
10742 +static void do_bio_wait(void)
10744 + int num_submitted = 0;
10746 + /* Don't want to wait on I/O we haven't submitted! */
10747 + num_submitted = submit_batched();
10751 + suspend_cleanup_some_completed_io();
10755 + * suspend_finish_all_io
10757 + * Description: Finishes all IO and frees all IO info struct pages.
10759 +static void suspend_finish_all_io(void)
10761 + /* Wait for all I/O to complete. */
10762 + while (atomic_read(&outstanding_io))
10767 + * wait_on_readahead
10769 + * Wait until a particular readahead is ready.
10771 +static void suspend_wait_on_readahead(int readahead_index)
10773 + int index = readahead_index / BITS_PER_LONG;
10774 + int bit = readahead_index - index * BITS_PER_LONG;
10776 + /* read_ahead_index is the one we want to return */
10777 + while (!test_bit(bit, &suspend_readahead_flags[index]))
10784 + * Returns whether the readahead requested is ready.
10787 +static int suspend_readahead_ready(int readahead_index)
10789 + int index = readahead_index / BITS_PER_LONG;
10790 + int bit = readahead_index - (index * BITS_PER_LONG);
10792 + return test_bit(bit, &suspend_readahead_flags[index]);
10795 +/* suspend_readahead_prepare
10796 + * Set up for doing readahead on an image */
10797 +static int suspend_prepare_readahead(int index)
10799 + unsigned long new_page = get_zeroed_page(GFP_ATOMIC | __GFP_NOWARN);
10804 + suspend_readahead_pages[index] = virt_to_page(new_page);
10808 +/* suspend_readahead_cleanup
10809 + * Clean up structures used for readahead */
10810 +static void suspend_cleanup_readahead(int page)
10812 + __free_page(suspend_readahead_pages[page]);
10813 + suspend_readahead_pages[page] = 0;
10818 + * suspend_end_bio
10820 + * Description: Function called by block driver from interrupt context when I/O
10821 + * is completed. This is the reason we use spinlocks in
10822 + * manipulating the io_info lists.
10823 + * Nearly the fs/buffer.c version, but we want to mark the page as
10824 + * done in our own structures too.
10827 +static int suspend_end_bio(struct bio *bio, unsigned int num, int err)
10829 + struct io_info *io_info = bio->bi_private;
10830 + unsigned long flags;
10832 + spin_lock_irqsave(&ioinfo_busy_lock, flags);
10833 + list_del_init(&io_info->list);
10834 + spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
10836 + spin_lock_irqsave(&ioinfo_ready_lock, flags);
10837 + list_add_tail(&io_info->list, &ioinfo_ready_for_cleanup);
10838 + spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10843 + * submit - submit BIO request.
10844 + * @writing: READ or WRITE.
10845 + * @io_info: IO info structure.
10847 + * Based on Patrick's pmdisk code from long ago:
10848 + * "Straight from the textbook - allocate and initialize the bio.
10849 + * If we're writing, make sure the page is marked as dirty.
10850 + * Then submit it and carry on."
10852 + * With a twist, though - we handle block_size != PAGE_SIZE.
10853 + * Caller has already checked that our page is not fragmented.
10856 +static int submit(struct io_info *io_info)
10858 + struct bio *bio = NULL;
10859 + unsigned long flags;
10862 + bio = bio_alloc(GFP_ATOMIC,1);
10867 + bio->bi_bdev = io_info->dev;
10868 + bio->bi_sector = io_info->first_block;
10869 + bio->bi_private = io_info;
10870 + bio->bi_end_io = suspend_end_bio;
10871 + io_info->sys_struct = bio;
10873 + if (bio_add_page(bio, io_info->bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
10874 + printk("ERROR: adding page to bio at %lld\n",
10875 + (unsigned long long) io_info->first_block);
10880 + if (io_info->writing)
10881 + bio_set_pages_dirty(bio);
10883 + spin_lock_irqsave(&ioinfo_busy_lock, flags);
10884 + list_add_tail(&io_info->list, &ioinfo_busy);
10885 + spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
10887 + submit_bio(io_info->writing, bio);
10893 + * submit a batch. The submit function can wait on I/O, so we have
10894 + * simple locking to avoid infinite recursion.
10896 +static int submit_batched(void)
10898 + static int running_already = 0;
10899 + struct io_info *first;
10900 + unsigned long flags;
10901 + int num_submitted = 0;
10903 + if (running_already)
10906 + running_already = 1;
10907 + spin_lock_irqsave(&ioinfo_submit_lock, flags);
10908 + while(!list_empty(&ioinfo_submit_batch)) {
10909 + first = list_entry(ioinfo_submit_batch.next, struct io_info,
10911 + list_del_init(&first->list);
10912 + atomic_dec(&submit_batch);
10913 + spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10915 + spin_lock_irqsave(&ioinfo_submit_lock, flags);
10917 + if (num_submitted == submit_batch_size)
10920 + spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10921 + running_already = 0;
10923 + return num_submitted;
10926 +static void add_to_batch(struct io_info *io_info)
10928 + unsigned long flags;
10931 + /* Put our prepared I/O struct on the batch list. */
10932 + spin_lock_irqsave(&ioinfo_submit_lock, flags);
10933 + list_add_tail(&io_info->list, &ioinfo_submit_batch);
10934 + waiting = atomic_add_return(1, &submit_batch);
10935 + spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10937 + if (waiting >= submit_batch_size)
10938 + submit_batched();
10942 + * get_io_info_struct
10944 + * Description: Get an I/O struct.
10945 + * Returns: Pointer to the struct prepared for use.
10947 +static struct io_info *get_io_info_struct(void)
10949 + struct io_info *this = NULL;
10952 + while (atomic_read(&outstanding_io) >= max_outstanding_io)
10955 + this = kmalloc(sizeof(struct io_info), GFP_ATOMIC);
10958 + INIT_LIST_HEAD(&this->list);
10965 + * Description: Prepare and start a read or write operation.
10966 + * Note that we use our own buffer for reading or writing.
10967 + * This simplifies doing readahead and asynchronous writing.
10968 + * We can begin a read without knowing the location into which
10969 + * the data will eventually be placed, and the buffer passed
10970 + * for a write can be reused immediately (essential for the
10971 + * modules system).
10972 + * Failure? What's that?
10973 + * Returns: The io_info struct created.
10975 +static int suspend_do_io(int writing, struct block_device *bdev, long block0,
10976 + struct page *page, int readahead_index, int syncio)
10978 + struct io_info *io_info;
10979 + unsigned long buffer_virt = 0;
10982 + io_info = get_io_info_struct();
10984 + /* Done before submitting to avoid races. */
10986 + waiting_on = io_info;
10988 + /* Get our local buffer */
10989 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
10990 + "Start_IO: [%p]", io_info);
10992 + /* Copy settings to the io_info struct */
10993 + io_info->writing = writing;
10994 + io_info->dev = bdev;
10995 + io_info->first_block = block0;
10996 + io_info->dest_page = page;
10997 + io_info->readahead_index = readahead_index;
10999 + if (io_info->readahead_index == -1) {
11000 + while (!(buffer_virt = get_zeroed_page(GFP_ATOMIC | __GFP_NOWARN)))
11003 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
11004 + "[ALLOC BUFFER]->%d",
11005 + real_nr_free_pages(all_zones_mask));
11006 + io_info->bio_page = virt_to_page(buffer_virt);
11008 + unsigned long flags;
11009 + int index = io_info->readahead_index / BITS_PER_LONG;
11010 + int bit = io_info->readahead_index - index * BITS_PER_LONG;
11012 + spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
11013 + clear_bit(bit, &suspend_readahead_flags[index]);
11014 + spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
11016 + io_info->bio_page = page;
11019 + /* If writing, copy our data. The data is probably in
11020 + * lowmem, but we cannot be certain. If there is no
11021 + * compression/encryption, we might be passed the
11022 + * actual source page's address. */
11024 + to = (char *) buffer_virt;
11025 + from = kmap_atomic(page, KM_USER1);
11026 + memcpy(to, from, PAGE_SIZE);
11027 + kunmap_atomic(from, KM_USER1);
11030 + /* Submit the page */
11031 + get_page(io_info->bio_page);
11033 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
11034 + "-> (PRE BRW) %d\n", real_nr_free_pages(all_zones_mask));
11039 + add_to_batch(io_info);
11041 + atomic_inc(&outstanding_io);
11044 + do { do_bio_wait(); } while (waiting_on);
11049 +/* We used to use bread here, but it doesn't correctly handle
11050 + * blocksize != PAGE_SIZE. Now we create a submit_info to get the data we
11051 + * want and use our normal routines (synchronously).
11054 +static int suspend_bdev_page_io(int writing, struct block_device *bdev,
11055 + long pos, struct page *page)
11057 + return suspend_do_io(writing, bdev, pos, page, -1, 1);
11060 +static int suspend_bio_memory_needed(void)
11062 + /* We want to have at least enough memory so as to have
11063 + * max_outstanding_io transactions on the fly at once. If we
11064 + * can do more, fine. */
11065 + return (max_outstanding_io * (PAGE_SIZE + sizeof(struct request) +
11066 + sizeof(struct bio) + sizeof(struct io_info)));
11069 +static void suspend_set_devinfo(struct suspend_bdev_info *info)
11071 + suspend_devinfo = info;
11074 +static void dump_block_chains(void)
11078 + for (i = 0; i < suspend_writer_posn.num_chains; i++) {
11079 + struct extent *this;
11081 + printk("Chain %d:", i);
11083 + this = (suspend_writer_posn.chains + i)->first;
11086 + printk(" (Empty)");
11089 + printk(" [%lu-%lu]%s", this->minimum, this->maximum,
11090 + this->next ? "," : "");
11091 + this = this->next;
11097 + for (i = 0; i < 3; i++)
11098 + printk("Posn %d: Chain %d, extent %d, offset %lu.\n", i,
11099 + suspend_writer_posn_save[i].chain_num,
11100 + suspend_writer_posn_save[i].extent_num,
11101 + suspend_writer_posn_save[i].offset);
11103 +static int forward_extra_blocks(void)
11107 + for (i = 1; i < suspend_devinfo[suspend_writer_posn.current_chain].
11108 + blocks_per_page; i++)
11109 + suspend_extent_state_next(&suspend_writer_posn);
11111 + if (suspend_extent_state_eof(&suspend_writer_posn)) {
11112 + printk("Extent state eof.\n");
11113 + dump_block_chains();
11120 +static int forward_one_page(void)
11122 + int at_start = (suspend_writer_posn.current_chain == -1);
11124 + /* Have to go forward one to ensure we're on the right chain,
11125 + * before we can know how many more blocks to skip.*/
11126 + suspend_extent_state_next(&suspend_writer_posn);
11128 + if (!at_start && forward_extra_blocks())
11131 + if (extra_page_forward) {
11132 + extra_page_forward = 0;
11133 + return forward_one_page();
11139 +/* Used in reading header, to jump to 2nd page after getting 1st page
11140 + * direct from image header. */
11141 +static void set_extra_page_forward(void)
11143 + extra_page_forward = 1;
11146 +static int suspend_bio_rw_page(int writing, struct page *page,
11147 + int readahead_index, int sync)
11149 + struct suspend_bdev_info *dev_info;
11151 + if (test_action_state(SUSPEND_TEST_FILTER_SPEED))
11154 + if (forward_one_page()) {
11155 + printk("Failed to advance a page in the extent data.\n");
11159 + if (current_stream == 0 && writing &&
11160 + suspend_writer_posn.current_chain == suspend_writer_posn_save[2].chain_num &&
11161 + suspend_writer_posn.current_offset == suspend_writer_posn_save[2].offset) {
11162 + dump_block_chains();
11166 + dev_info = &suspend_devinfo[suspend_writer_posn.current_chain];
11168 + return suspend_do_io(writing, dev_info->bdev,
11169 + suspend_writer_posn.current_offset <<
11170 + dev_info->bmap_shift,
11171 + page, readahead_index, sync);
11174 +static int suspend_rw_init(int writing, int stream_number)
11176 + suspend_header_bytes_used = 0;
11178 + suspend_extent_state_restore(&suspend_writer_posn,
11179 + &suspend_writer_posn_save[stream_number]);
11181 + suspend_writer_buffer_posn = writing ? 0 : PAGE_SIZE;
11183 + current_stream = stream_number;
11185 + readahead_index = readahead_submit_index = -1;
11192 +static void suspend_read_header_init(void)
11194 + readahead_index = readahead_submit_index = -1;
11197 +static int suspend_rw_cleanup(int writing)
11199 + if (writing && suspend_bio_rw_page(WRITE,
11200 + virt_to_page(suspend_writer_buffer), -1, 0))
11203 + if (writing && current_stream == 2)
11204 + suspend_extent_state_save(&suspend_writer_posn,
11205 + &suspend_writer_posn_save[1]);
11207 + suspend_finish_all_io();
11210 + while (readahead_index != readahead_submit_index) {
11211 + suspend_cleanup_readahead(readahead_index);
11212 + readahead_index++;
11213 + if (readahead_index == max_outstanding_io)
11214 + readahead_index = 0;
11217 + current_stream = 0;
11222 +static int suspend_bio_read_page_with_readahead(void)
11224 + static int last_result;
11225 + unsigned long *virt;
11227 + if (readahead_index == -1) {
11229 + readahead_index = readahead_submit_index = 0;
11232 + /* Start a new readahead? */
11233 + if (last_result) {
11234 + /* We failed to submit a read, and have cleaned up
11235 + * all the readahead previously submitted */
11236 + if (readahead_submit_index == readahead_index) {
11237 + abort_suspend(SUSPEND_FAILED_IO, "Failed to submit"
11238 + " a read and no readahead left.\n");
11245 + if (suspend_prepare_readahead(readahead_submit_index))
11248 + last_result = suspend_bio_rw_page(READ,
11249 + suspend_readahead_pages[readahead_submit_index],
11250 + readahead_submit_index, SUSPEND_ASYNC);
11251 + if (last_result) {
11252 + printk("Begin read chunk for page %d returned %d.\n",
11253 + readahead_submit_index, last_result);
11254 + suspend_cleanup_readahead(readahead_submit_index);
11258 + readahead_submit_index++;
11260 + if (readahead_submit_index == max_outstanding_io)
11261 + readahead_submit_index = 0;
11263 + } while((!last_result) && (readahead_submit_index != readahead_index) &&
11264 + (!suspend_readahead_ready(readahead_index)));
11267 + suspend_wait_on_readahead(readahead_index);
11269 + virt = kmap_atomic(suspend_readahead_pages[readahead_index], KM_USER1);
11270 + memcpy(suspend_writer_buffer, virt, PAGE_SIZE);
11271 + kunmap_atomic(virt, KM_USER1);
11273 + suspend_cleanup_readahead(readahead_index);
11275 + readahead_index++;
11276 + if (readahead_index == max_outstanding_io)
11277 + readahead_index = 0;
11286 +static int suspend_rw_buffer(int writing, char *buffer, int buffer_size)
11288 + int bytes_left = buffer_size;
11290 + /* Read/write a chunk of the header */
11291 + while (bytes_left) {
11292 + char *source_start = buffer + buffer_size - bytes_left;
11293 + char *dest_start = suspend_writer_buffer + suspend_writer_buffer_posn;
11294 + int capacity = PAGE_SIZE - suspend_writer_buffer_posn;
11295 + char *to = writing ? dest_start : source_start;
11296 + char *from = writing ? source_start : dest_start;
11298 + if (bytes_left <= capacity) {
11299 + if (test_debug_state(SUSPEND_HEADER))
11300 + printk("Copy %d bytes %d-%d from %p to %p.\n",
11302 + suspend_header_bytes_used,
11303 + suspend_header_bytes_used + bytes_left,
11305 + memcpy(to, from, bytes_left);
11306 + suspend_writer_buffer_posn += bytes_left;
11307 + suspend_header_bytes_used += bytes_left;
11311 + /* Complete this page and start a new one */
11312 + if (test_debug_state(SUSPEND_HEADER))
11313 + printk("Copy %d bytes (%d-%d) from %p to %p.\n",
11315 + suspend_header_bytes_used,
11316 + suspend_header_bytes_used + capacity,
11318 + memcpy(to, from, capacity);
11319 + bytes_left -= capacity;
11320 + suspend_header_bytes_used += capacity;
11323 + if (test_suspend_state(SUSPEND_TRY_RESUME_RD))
11324 + sys_read(suspend_read_fd,
11325 + suspend_writer_buffer, BLOCK_SIZE);
11327 + if (suspend_bio_read_page_with_readahead())
11329 + } else if (suspend_bio_rw_page(WRITE,
11330 + virt_to_page(suspend_writer_buffer),
11331 + -1, SUSPEND_ASYNC))
11334 + suspend_writer_buffer_posn = 0;
11335 + suspend_cond_pause(0, NULL);
11342 + * suspend_bio_read_chunk
11344 + * Read a (possibly compressed and/or encrypted) page from the image,
11345 + * into buffer_page, returning it's index and the buffer size.
11347 + * If asynchronous I/O is requested, use readahead.
11350 +static int suspend_bio_read_chunk(unsigned long *index, struct page *buffer_page,
11351 + unsigned int *buf_size, int sync)
11354 + char *buffer_virt = kmap(buffer_page);
11358 + while (!mutex_trylock(&suspend_bio_mutex))
11361 + if ((result = suspend_rw_buffer(READ, (char *) index,
11362 + sizeof(unsigned long)))) {
11363 + abort_suspend(SUSPEND_FAILED_IO,
11364 + "Read of index returned %d.\n", result);
11368 + if ((result = suspend_rw_buffer(READ, (char *) buf_size, sizeof(int)))) {
11369 + abort_suspend(SUSPEND_FAILED_IO,
11370 + "Read of buffer size is %d.\n", result);
11374 + result = suspend_rw_buffer(READ, buffer_virt, *buf_size);
11376 + abort_suspend(SUSPEND_FAILED_IO,
11377 + "Read of data returned %d.\n", result);
11379 + PR_DEBUG("%d: Index %ld, %d bytes.\n", pr_index, *index, *buf_size);
11381 + mutex_unlock(&suspend_bio_mutex);
11382 + kunmap(buffer_page);
11384 + abort_suspend(SUSPEND_FAILED_IO,
11385 + "Returning %d from suspend_bio_read_chunk.\n", result);
11390 + * suspend_bio_write_chunk
11392 + * Write a (possibly compressed and/or encrypted) page to the image from
11393 + * the buffer, together with it's index and buffer size.
11396 +static int suspend_bio_write_chunk(unsigned long index, struct page *buffer_page,
11397 + unsigned int buf_size)
11400 + char *buffer_virt = kmap(buffer_page);
11404 + while (!mutex_trylock(&suspend_bio_mutex))
11407 + if ((result = suspend_rw_buffer(WRITE, (char *) &index,
11408 + sizeof(unsigned long))))
11411 + if ((result = suspend_rw_buffer(WRITE, (char *) &buf_size, sizeof(int))))
11414 + result = suspend_rw_buffer(WRITE, buffer_virt, buf_size);
11416 + PR_DEBUG("%d: Index %ld, %d bytes.\n", pr_index, index, buf_size);
11418 + mutex_unlock(&suspend_bio_mutex);
11419 + kunmap(buffer_page);
11424 + * suspend_rw_header_chunk
11426 + * Read or write a portion of the header.
11429 +static int suspend_rw_header_chunk(int writing,
11430 + struct suspend_module_ops *owner,
11431 + char *buffer, int buffer_size)
11434 + owner->header_used += buffer_size;
11435 + if (owner->header_used > owner->header_requested) {
11436 + printk(KERN_EMERG "Suspend2 module %s is using more"
11437 + "header space (%u) than it requested (%u).\n",
11439 + owner->header_used,
11440 + owner->header_requested);
11441 + return buffer_size;
11445 + return suspend_rw_buffer(writing, buffer, buffer_size);
11449 + * write_header_chunk_finish
11451 + * Flush any buffered writes in the section of the image.
11453 +static int write_header_chunk_finish(void)
11455 + return suspend_bio_rw_page(WRITE, virt_to_page(suspend_writer_buffer),
11456 + -1, 0) ? -EIO : 0;
11459 +static int suspend_bio_storage_needed(void)
11461 + return 2 * sizeof(int);
11464 +static int suspend_bio_save_config_info(char *buf)
11466 + int *ints = (int *) buf;
11467 + ints[0] = max_outstanding_io;
11468 + ints[1] = submit_batch_size;
11469 + return 2 * sizeof(int);
11472 +static void suspend_bio_load_config_info(char *buf, int size)
11474 + int *ints = (int *) buf;
11475 + max_outstanding_io = ints[0];
11476 + submit_batch_size = ints[1];
11479 +static int suspend_bio_initialise(int starting_cycle)
11481 + suspend_writer_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
11483 + return suspend_writer_buffer ? 0 : -ENOMEM;
11486 +static void suspend_bio_cleanup(int finishing_cycle)
11488 + if (suspend_writer_buffer) {
11489 + free_page((unsigned long) suspend_writer_buffer);
11490 + suspend_writer_buffer = NULL;
11494 +struct suspend_bio_ops suspend_bio_ops = {
11495 + .bdev_page_io = suspend_bdev_page_io,
11496 + .finish_all_io = suspend_finish_all_io,
11497 + .forward_one_page = forward_one_page,
11498 + .set_extra_page_forward = set_extra_page_forward,
11499 + .set_devinfo = suspend_set_devinfo,
11500 + .read_chunk = suspend_bio_read_chunk,
11501 + .write_chunk = suspend_bio_write_chunk,
11502 + .rw_init = suspend_rw_init,
11503 + .rw_cleanup = suspend_rw_cleanup,
11504 + .read_header_init = suspend_read_header_init,
11505 + .rw_header_chunk = suspend_rw_header_chunk,
11506 + .write_header_chunk_finish = write_header_chunk_finish,
11509 +static struct suspend_sysfs_data sysfs_params[] = {
11510 + { SUSPEND2_ATTR("max_outstanding_io", SYSFS_RW),
11511 + SYSFS_INT(&max_outstanding_io, 16, MAX_OUTSTANDING_IO, 0),
11514 + { SUSPEND2_ATTR("submit_batch_size", SYSFS_RW),
11515 + SYSFS_INT(&submit_batch_size, 16, SUBMIT_BATCH_SIZE, 0),
11519 +static struct suspend_module_ops suspend_blockwriter_ops =
11521 + .name = "Block I/O",
11522 + .type = MISC_MODULE,
11523 + .directory = "block_io",
11524 + .module = THIS_MODULE,
11525 + .memory_needed = suspend_bio_memory_needed,
11526 + .storage_needed = suspend_bio_storage_needed,
11527 + .save_config_info = suspend_bio_save_config_info,
11528 + .load_config_info = suspend_bio_load_config_info,
11529 + .initialise = suspend_bio_initialise,
11530 + .cleanup = suspend_bio_cleanup,
11532 + .sysfs_data = sysfs_params,
11533 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
11536 +static __init int suspend_block_io_load(void)
11538 + return suspend_register_module(&suspend_blockwriter_ops);
11541 +#ifdef CONFIG_SUSPEND2_FILE_EXPORTS
11542 +EXPORT_SYMBOL_GPL(suspend_read_fd);
11544 +#if defined(CONFIG_SUSPEND2_FILE_EXPORTS) || defined(CONFIG_SUSPEND2_SWAP_EXPORTS)
11545 +EXPORT_SYMBOL_GPL(suspend_writer_posn);
11546 +EXPORT_SYMBOL_GPL(suspend_writer_posn_save);
11547 +EXPORT_SYMBOL_GPL(suspend_writer_buffer);
11548 +EXPORT_SYMBOL_GPL(suspend_writer_buffer_posn);
11549 +EXPORT_SYMBOL_GPL(suspend_header_bytes_used);
11550 +EXPORT_SYMBOL_GPL(suspend_bio_ops);
11553 +static __exit void suspend_block_io_unload(void)
11555 + suspend_unregister_module(&suspend_blockwriter_ops);
11558 +module_init(suspend_block_io_load);
11559 +module_exit(suspend_block_io_unload);
11560 +MODULE_LICENSE("GPL");
11561 +MODULE_AUTHOR("Nigel Cunningham");
11562 +MODULE_DESCRIPTION("Suspend2 block io functions");
11564 +late_initcall(suspend_block_io_load);
11566 diff -ruN linux-2.6.22/kernel/power/suspend_compress.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend_compress.c
11567 --- linux-2.6.22/kernel/power/suspend_compress.c 1970-01-01 10:00:00.000000000 +1000
11568 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend_compress.c 2007-07-11 22:25:42.000000000 +1000
11571 + * kernel/power/compression.c
11573 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
11575 + * This file is released under the GPLv2.
11577 + * This file contains data compression routines for suspend,
11578 + * using cryptoapi.
11581 +#include <linux/module.h>
11582 +#include <linux/suspend.h>
11583 +#include <linux/highmem.h>
11584 +#include <linux/vmalloc.h>
11585 +#include <linux/crypto.h>
11587 +#include "suspend2_builtin.h"
11588 +#include "suspend.h"
11589 +#include "modules.h"
11590 +#include "sysfs.h"
11594 +static int suspend_expected_compression = 0;
11596 +static struct suspend_module_ops suspend_compression_ops;
11597 +static struct suspend_module_ops *next_driver;
11599 +static char suspend_compressor_name[32] = "lzf";
11601 +static DEFINE_MUTEX(stats_lock);
11603 +struct cpu_context {
11604 + u8 * page_buffer;
11605 + struct crypto_comp *transform;
11606 + unsigned int len;
11607 + char *buffer_start;
11610 +static DEFINE_PER_CPU(struct cpu_context, contexts);
11612 +static int suspend_compress_prepare_result;
11615 + * suspend_compress_cleanup
11617 + * Frees memory allocated for our labours.
11619 +static void suspend_compress_cleanup(int suspend_or_resume)
11623 + if (!suspend_or_resume)
11626 + for_each_online_cpu(cpu) {
11627 + struct cpu_context *this = &per_cpu(contexts, cpu);
11628 + if (this->transform) {
11629 + crypto_free_comp(this->transform);
11630 + this->transform = NULL;
11633 + if (this->page_buffer)
11634 + free_page((unsigned long) this->page_buffer);
11636 + this->page_buffer = NULL;
11641 + * suspend_crypto_prepare
11643 + * Prepare to do some work by allocating buffers and transforms.
11645 +static int suspend_compress_crypto_prepare(void)
11649 + if (!*suspend_compressor_name) {
11650 + printk("Suspend2: Compression enabled but no compressor name set.\n");
11654 + for_each_online_cpu(cpu) {
11655 + struct cpu_context *this = &per_cpu(contexts, cpu);
11656 + this->transform = crypto_alloc_comp(suspend_compressor_name,
11658 + if (IS_ERR(this->transform)) {
11659 + printk("Suspend2: Failed to initialise the %s "
11660 + "compression transform.\n",
11661 + suspend_compressor_name);
11662 + this->transform = NULL;
11666 + this->page_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
11668 + if (!this->page_buffer) {
11670 + "Failed to allocate a page buffer for suspend2 "
11671 + "encryption driver.\n");
11680 + * suspend_compress_init
11683 +static int suspend_compress_init(int suspend_or_resume)
11685 + if (!suspend_or_resume)
11688 + suspend_compress_bytes_in = suspend_compress_bytes_out = 0;
11690 + next_driver = suspend_get_next_filter(&suspend_compression_ops);
11692 + if (!next_driver) {
11693 + printk("Compression Driver: Argh! Nothing follows me in"
11694 + " the pipeline!\n");
11698 + suspend_compress_prepare_result = suspend_compress_crypto_prepare();
11704 + * suspend_compress_rw_init()
11707 +int suspend_compress_rw_init(int rw, int stream_number)
11709 + if (suspend_compress_prepare_result) {
11710 + printk("Failed to initialise compression algorithm.\n");
11714 + suspend_compression_ops.enabled = 0;
11721 + * suspend_compress_write_chunk()
11723 + * Compress a page of data, buffering output and passing on filled
11724 + * pages to the next module in the pipeline.
11726 + * Buffer_page: Pointer to a buffer of size PAGE_SIZE, containing
11727 + * data to be compressed.
11729 + * Returns: 0 on success. Otherwise the error is that returned by later
11730 + * modules, -ECHILD if we have a broken pipeline or -EIO if
11733 +static int suspend_compress_write_chunk(unsigned long index,
11734 + struct page *buffer_page, unsigned int buf_size)
11736 + int ret, cpu = smp_processor_id();
11737 + struct cpu_context *ctx = &per_cpu(contexts, cpu);
11739 + if (!ctx->transform)
11740 + return next_driver->write_chunk(index, buffer_page, buf_size);
11742 + ctx->buffer_start = kmap(buffer_page);
11744 + ctx->len = buf_size;
11746 + ret = crypto_comp_compress(ctx->transform,
11747 + ctx->buffer_start, buf_size,
11748 + ctx->page_buffer, &ctx->len);
11750 + kunmap(buffer_page);
11753 + printk("Compression failed.\n");
11757 + mutex_lock(&stats_lock);
11758 + suspend_compress_bytes_in += buf_size;
11759 + suspend_compress_bytes_out += ctx->len;
11760 + mutex_unlock(&stats_lock);
11762 + if (ctx->len < buf_size) /* some compression */
11763 + ret = next_driver->write_chunk(index,
11764 + virt_to_page(ctx->page_buffer),
11767 + ret = next_driver->write_chunk(index, buffer_page, buf_size);
11774 + * suspend_compress_read_chunk()
11775 + * @buffer_page: struct page *. Pointer to a buffer of size PAGE_SIZE.
11776 + * @sync: int. Whether the previous module (or core) wants its data
11779 + * Retrieve data from later modules and decompress it until the input buffer
11781 + * Zero if successful. Error condition from me or from downstream on failure.
11783 +static int suspend_compress_read_chunk(unsigned long *index,
11784 + struct page *buffer_page, unsigned int *buf_size, int sync)
11786 + int ret, cpu = smp_processor_id();
11787 + unsigned int len;
11788 + unsigned int outlen = PAGE_SIZE;
11789 + char *buffer_start;
11790 + struct cpu_context *ctx = &per_cpu(contexts, cpu);
11792 + if (!ctx->transform)
11793 + return next_driver->read_chunk(index, buffer_page, buf_size,
11797 + * All our reads must be synchronous - we can't decompress
11798 + * data that hasn't been read yet.
11801 + *buf_size = PAGE_SIZE;
11803 + ret = next_driver->read_chunk(index, buffer_page, &len, SUSPEND_SYNC);
11805 + /* Error or uncompressed data */
11806 + if (ret || len == PAGE_SIZE)
11809 + buffer_start = kmap(buffer_page);
11810 + memcpy(ctx->page_buffer, buffer_start, len);
11811 + ret = crypto_comp_decompress(
11813 + ctx->page_buffer,
11814 + len, buffer_start, &outlen);
11816 + abort_suspend(SUSPEND_FAILED_IO,
11817 + "Compress_read returned %d.\n", ret);
11818 + else if (outlen != PAGE_SIZE) {
11819 + abort_suspend(SUSPEND_FAILED_IO,
11820 + "Decompression yielded %d bytes instead of %ld.\n",
11821 + outlen, PAGE_SIZE);
11823 + *buf_size = outlen;
11825 + kunmap(buffer_page);
11830 + * suspend_compress_print_debug_stats
11831 + * @buffer: Pointer to a buffer into which the debug info will be printed.
11832 + * @size: Size of the buffer.
11834 + * Print information to be recorded for debugging purposes into a buffer.
11835 + * Returns: Number of characters written to the buffer.
11838 +static int suspend_compress_print_debug_stats(char *buffer, int size)
11840 + int pages_in = suspend_compress_bytes_in >> PAGE_SHIFT,
11841 + pages_out = suspend_compress_bytes_out >> PAGE_SHIFT;
11844 + /* Output the compression ratio achieved. */
11845 + if (*suspend_compressor_name)
11846 + len = snprintf_used(buffer, size, "- Compressor is '%s'.\n",
11847 + suspend_compressor_name);
11849 + len = snprintf_used(buffer, size, "- Compressor is not set.\n");
11852 + len+= snprintf_used(buffer+len, size - len,
11853 + " Compressed %ld bytes into %ld (%d percent compression).\n",
11854 + suspend_compress_bytes_in,
11855 + suspend_compress_bytes_out,
11856 + (pages_in - pages_out) * 100 / pages_in);
11861 + * suspend_compress_compression_memory_needed
11863 + * Tell the caller how much memory we need to operate during suspend/resume.
11864 + * Returns: Unsigned long. Maximum number of bytes of memory required for
11867 +static int suspend_compress_memory_needed(void)
11869 + return 2 * PAGE_SIZE;
11872 +static int suspend_compress_storage_needed(void)
11874 + return 4 * sizeof(unsigned long) + strlen(suspend_compressor_name) + 1;
11878 + * suspend_compress_save_config_info
11879 + * @buffer: Pointer to a buffer of size PAGE_SIZE.
11881 + * Save informaton needed when reloading the image at resume time.
11882 + * Returns: Number of bytes used for saving our data.
11884 +static int suspend_compress_save_config_info(char *buffer)
11886 + int namelen = strlen(suspend_compressor_name) + 1;
11889 + *((unsigned long *) buffer) = suspend_compress_bytes_in;
11890 + *((unsigned long *) (buffer + 1 * sizeof(unsigned long))) =
11891 + suspend_compress_bytes_out;
11892 + *((unsigned long *) (buffer + 2 * sizeof(unsigned long))) =
11893 + suspend_expected_compression;
11894 + *((unsigned long *) (buffer + 3 * sizeof(unsigned long))) = namelen;
11895 + strncpy(buffer + 4 * sizeof(unsigned long), suspend_compressor_name,
11897 + total_len = 4 * sizeof(unsigned long) + namelen;
11898 + return total_len;
11901 +/* suspend_compress_load_config_info
11902 + * @buffer: Pointer to the start of the data.
11903 + * @size: Number of bytes that were saved.
11905 + * Description: Reload information needed for decompressing the image at
11908 +static void suspend_compress_load_config_info(char *buffer, int size)
11912 + suspend_compress_bytes_in = *((unsigned long *) buffer);
11913 + suspend_compress_bytes_out = *((unsigned long *) (buffer + 1 * sizeof(unsigned long)));
11914 + suspend_expected_compression = *((unsigned long *) (buffer + 2 *
11915 + sizeof(unsigned long)));
11916 + namelen = *((unsigned long *) (buffer + 3 * sizeof(unsigned long)));
11917 + strncpy(suspend_compressor_name, buffer + 4 * sizeof(unsigned long),
11923 + * suspend_expected_compression_ratio
11925 + * Description: Returns the expected ratio between data passed into this module
11926 + * and the amount of data output when writing.
11927 + * Returns: 100 if the module is disabled. Otherwise the value set by the
11928 + * user via our sysfs entry.
11931 +static int suspend_compress_expected_ratio(void)
11933 + if (!suspend_compression_ops.enabled)
11936 + return 100 - suspend_expected_compression;
11940 + * data for our sysfs entries.
11942 +static struct suspend_sysfs_data sysfs_params[] = {
11944 + SUSPEND2_ATTR("expected_compression", SYSFS_RW),
11945 + SYSFS_INT(&suspend_expected_compression, 0, 99, 0)
11949 + SUSPEND2_ATTR("enabled", SYSFS_RW),
11950 + SYSFS_INT(&suspend_compression_ops.enabled, 0, 1, 0)
11954 + SUSPEND2_ATTR("algorithm", SYSFS_RW),
11955 + SYSFS_STRING(suspend_compressor_name, 31, 0)
11962 +static struct suspend_module_ops suspend_compression_ops = {
11963 + .type = FILTER_MODULE,
11964 + .name = "Compressor",
11965 + .directory = "compression",
11966 + .module = THIS_MODULE,
11967 + .initialise = suspend_compress_init,
11968 + .cleanup = suspend_compress_cleanup,
11969 + .memory_needed = suspend_compress_memory_needed,
11970 + .print_debug_info = suspend_compress_print_debug_stats,
11971 + .save_config_info = suspend_compress_save_config_info,
11972 + .load_config_info = suspend_compress_load_config_info,
11973 + .storage_needed = suspend_compress_storage_needed,
11974 + .expected_compression = suspend_compress_expected_ratio,
11976 + .rw_init = suspend_compress_rw_init,
11978 + .write_chunk = suspend_compress_write_chunk,
11979 + .read_chunk = suspend_compress_read_chunk,
11981 + .sysfs_data = sysfs_params,
11982 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
11985 +/* ---- Registration ---- */
11987 +static __init int suspend_compress_load(void)
11989 + return suspend_register_module(&suspend_compression_ops);
11993 +static __exit void suspend_compress_unload(void)
11995 + suspend_unregister_module(&suspend_compression_ops);
11998 +module_init(suspend_compress_load);
11999 +module_exit(suspend_compress_unload);
12000 +MODULE_LICENSE("GPL");
12001 +MODULE_AUTHOR("Nigel Cunningham");
12002 +MODULE_DESCRIPTION("Compression Support for Suspend2");
12004 +late_initcall(suspend_compress_load);
12006 diff -ruN linux-2.6.22/kernel/power/suspend_file.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend_file.c
12007 --- linux-2.6.22/kernel/power/suspend_file.c 1970-01-01 10:00:00.000000000 +1000
12008 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend_file.c 2007-07-11 22:25:42.000000000 +1000
12011 + * kernel/power/suspend_file.c
12013 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
12015 + * Distributed under GPLv2.
12017 + * This file encapsulates functions for usage of a simple file as a
12018 + * backing store. It is based upon the swapallocator, and shares the
12019 + * same basic working. Here, though, we have nothing to do with
12020 + * swapspace, and only one device to worry about.
12022 + * The user can just
12024 + * echo Suspend2 > /path/to/my_file
12028 + * echo /path/to/my_file > /sys/power/suspend2/suspend_file/target
12030 + * then put what they find in /sys/power/suspend2/resume2
12031 + * as their resume2= parameter in lilo.conf (and rerun lilo if using it).
12033 + * Having done this, they're ready to suspend and resume.
12036 + * - File resizing.
12039 +#include <linux/suspend.h>
12040 +#include <linux/module.h>
12041 +#include <linux/blkdev.h>
12042 +#include <linux/file.h>
12043 +#include <linux/stat.h>
12044 +#include <linux/mount.h>
12045 +#include <linux/statfs.h>
12046 +#include <linux/syscalls.h>
12047 +#include <linux/namei.h>
12048 +#include <linux/fs.h>
12049 +#include <linux/root_dev.h>
12051 +#include "suspend.h"
12052 +#include "sysfs.h"
12053 +#include "modules.h"
12055 +#include "extent.h"
12057 +#include "storage.h"
12058 +#include "block_io.h"
12060 +static struct suspend_module_ops suspend_fileops;
12062 +/* Details of our target. */
12064 +char suspend_file_target[256];
12065 +static struct inode *target_inode;
12066 +static struct file *target_file;
12067 +static struct block_device *suspend_file_target_bdev;
12068 +static dev_t resume_file_dev_t;
12069 +static int used_devt = 0;
12070 +static int setting_suspend_file_target = 0;
12071 +static sector_t target_firstblock = 0, target_header_start = 0;
12072 +static int target_storage_available = 0;
12073 +static int target_claim = 0;
12075 +static char HaveImage[] = "HaveImage\n";
12076 +static char NoImage[] = "Suspend2\n";
12077 +#define sig_size (sizeof(HaveImage) + 1)
12079 +struct suspend_file_header {
12080 + char sig[sig_size];
12081 + int resumed_before;
12082 + unsigned long first_header_block;
12085 +extern char *__initdata root_device_name;
12087 +/* Header Page Information */
12088 +static int header_pages_allocated;
12090 +/* Main Storage Pages */
12091 +static int main_pages_allocated, main_pages_requested;
12093 +#define target_is_normal_file() (S_ISREG(target_inode->i_mode))
12095 +static struct suspend_bdev_info devinfo;
12097 +/* Extent chain for blocks */
12098 +static struct extent_chain block_chain;
12100 +/* Signature operations */
12102 + GET_IMAGE_EXISTS,
12104 + MARK_RESUME_ATTEMPTED,
12105 + UNMARK_RESUME_ATTEMPTED,
12108 +static void set_devinfo(struct block_device *bdev, int target_blkbits)
12110 + devinfo.bdev = bdev;
12111 + if (!target_blkbits) {
12112 + devinfo.bmap_shift = devinfo.blocks_per_page = 0;
12114 + devinfo.bmap_shift = target_blkbits - 9;
12115 + devinfo.blocks_per_page = (1 << (PAGE_SHIFT - target_blkbits));
12119 +static int adjust_for_extra_pages(int unadjusted)
12121 + return (unadjusted << PAGE_SHIFT) / (PAGE_SIZE + sizeof(unsigned long)
12125 +static int suspend_file_storage_available(void)
12128 + struct block_device *bdev=suspend_file_target_bdev;
12130 + if (!target_inode)
12133 + switch (target_inode->i_mode & S_IFMT) {
12136 + case S_IFIFO: /* Socket, Char, Fifo */
12138 + case S_IFREG: /* Regular file: current size - holes + free
12140 + result = target_storage_available;
12142 + case S_IFBLK: /* Block device */
12143 + if (!bdev->bd_disk) {
12144 + printk("bdev->bd_disk null.\n");
12148 + result = (bdev->bd_part ?
12149 + bdev->bd_part->nr_sects :
12150 + bdev->bd_disk->capacity) >> (PAGE_SHIFT - 9);
12153 + return adjust_for_extra_pages(result);
12156 +static int has_contiguous_blocks(int page_num)
12159 + sector_t last = 0;
12161 + for (j = 0; j < devinfo.blocks_per_page; j++) {
12162 + sector_t this = bmap(target_inode,
12163 + page_num * devinfo.blocks_per_page + j);
12165 + if (!this || (last && (last + 1) != this))
12171 + return (j == devinfo.blocks_per_page);
12174 +static int size_ignoring_ignored_pages(void)
12176 + int mappable = 0, i;
12178 + if (!target_is_normal_file())
12179 + return suspend_file_storage_available();
12181 + for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT) ; i++)
12182 + if (has_contiguous_blocks(i))
12188 +static void __populate_block_list(int min, int max)
12190 + if (test_action_state(SUSPEND_TEST_BIO))
12191 + printk("Adding extent %d-%d.\n", min << devinfo.bmap_shift,
12192 + ((max + 1) << devinfo.bmap_shift) - 1);
12194 + suspend_add_to_extent_chain(&block_chain, min, max);
12197 +static void populate_block_list(void)
12200 + int extent_min = -1, extent_max = -1, got_header = 0;
12202 + if (block_chain.first)
12203 + suspend_put_extent_chain(&block_chain);
12205 + if (!target_is_normal_file()) {
12206 + if (target_storage_available > 0)
12207 + __populate_block_list(devinfo.blocks_per_page,
12208 + (target_storage_available + 1) *
12209 + devinfo.blocks_per_page - 1);
12213 + for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT); i++) {
12214 + sector_t new_sector;
12216 + if (!has_contiguous_blocks(i))
12219 + new_sector = bmap(target_inode,
12220 + (i * devinfo.blocks_per_page));
12223 + * Ignore the first block in the file.
12224 + * It gets the header.
12226 + if (new_sector == target_firstblock >> devinfo.bmap_shift) {
12232 + * I'd love to be able to fill in holes and resize
12233 + * files, but not yet...
12236 + if (new_sector == extent_max + 1)
12237 + extent_max+= devinfo.blocks_per_page;
12239 + if (extent_min > -1)
12240 + __populate_block_list(extent_min,
12243 + extent_min = new_sector;
12244 + extent_max = extent_min +
12245 + devinfo.blocks_per_page - 1;
12249 + if (extent_min > -1)
12250 + __populate_block_list(extent_min, extent_max);
12253 +static void suspend_file_cleanup(int finishing_cycle)
12255 + if (suspend_file_target_bdev) {
12256 + if (target_claim) {
12257 + bd_release(suspend_file_target_bdev);
12258 + target_claim = 0;
12262 + blkdev_put(suspend_file_target_bdev);
12265 + suspend_file_target_bdev = NULL;
12266 + target_inode = NULL;
12267 + set_devinfo(NULL, 0);
12268 + target_storage_available = 0;
12271 + if (target_file > 0) {
12272 + filp_close(target_file, NULL);
12273 + target_file = NULL;
12278 + * reopen_resume_devt
12280 + * Having opened resume2= once, we remember the major and
12281 + * minor nodes and use them to reopen the bdev for checking
12282 + * whether an image exists (possibly when starting a resume).
12284 +static void reopen_resume_devt(void)
12286 + suspend_file_target_bdev = open_by_devnum(resume_file_dev_t, FMODE_READ);
12287 + if (IS_ERR(suspend_file_target_bdev)) {
12288 + printk("Got a dev_num (%lx) but failed to open it.\n",
12289 + (unsigned long) resume_file_dev_t);
12292 + target_inode = suspend_file_target_bdev->bd_inode;
12293 + set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12296 +static void suspend_file_get_target_info(char *target, int get_size,
12300 + suspend_file_cleanup(0);
12302 + if (!target || !strlen(target))
12305 + target_file = filp_open(target, O_RDWR, 0);
12307 + if (IS_ERR(target_file) || !target_file) {
12310 + printk("Open file %s returned %p.\n",
12311 + target, target_file);
12312 + target_file = NULL;
12316 + target_file = NULL;
12317 + resume_file_dev_t = name_to_dev_t(target);
12318 + if (!resume_file_dev_t) {
12319 + struct kstat stat;
12320 + int error = vfs_stat(target, &stat);
12321 + printk("Open file %s returned %p and name_to_devt "
12322 + "failed.\n", target, target_file);
12324 + printk("Stating the file also failed."
12325 + " Nothing more we can do.\n");
12327 + resume_file_dev_t = stat.rdev;
12331 + suspend_file_target_bdev = open_by_devnum(resume_file_dev_t,
12333 + if (IS_ERR(suspend_file_target_bdev)) {
12334 + printk("Got a dev_num (%lx) but failed to open it.\n",
12335 + (unsigned long) resume_file_dev_t);
12339 + target_inode = suspend_file_target_bdev->bd_inode;
12341 + target_inode = target_file->f_mapping->host;
12343 + if (S_ISLNK(target_inode->i_mode) || S_ISDIR(target_inode->i_mode) ||
12344 + S_ISSOCK(target_inode->i_mode) || S_ISFIFO(target_inode->i_mode)) {
12345 + printk("File support works with regular files, character "
12346 + "files and block devices.\n");
12350 + if (!used_devt) {
12351 + if (S_ISBLK(target_inode->i_mode)) {
12352 + suspend_file_target_bdev = I_BDEV(target_inode);
12353 + if (!bd_claim(suspend_file_target_bdev, &suspend_fileops))
12354 + target_claim = 1;
12356 + suspend_file_target_bdev = target_inode->i_sb->s_bdev;
12357 + resume_file_dev_t = suspend_file_target_bdev->bd_dev;
12360 + set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12363 + target_storage_available = size_ignoring_ignored_pages();
12366 + target_firstblock = bmap(target_inode, 0) << devinfo.bmap_shift;
12370 + target_inode = NULL;
12371 + if (target_file) {
12372 + filp_close(target_file, NULL);
12373 + target_file = NULL;
12375 + set_devinfo(NULL, 0);
12376 + target_storage_available = 0;
12379 +static int parse_signature(struct suspend_file_header *header)
12381 + int have_image = !memcmp(HaveImage, header->sig, sizeof(HaveImage) - 1);
12382 + int no_image_header = !memcmp(NoImage, header->sig, sizeof(NoImage) - 1);
12384 + if (no_image_header)
12390 + if (header->resumed_before)
12391 + set_suspend_state(SUSPEND_RESUMED_BEFORE);
12393 + clear_suspend_state(SUSPEND_RESUMED_BEFORE);
12395 + target_header_start = header->first_header_block;
12399 +/* prepare_signature */
12401 +static int prepare_signature(struct suspend_file_header *current_header,
12402 + unsigned long first_header_block)
12404 + strncpy(current_header->sig, HaveImage, sizeof(HaveImage));
12405 + current_header->resumed_before = 0;
12406 + current_header->first_header_block = first_header_block;
12410 +static int suspend_file_storage_allocated(void)
12412 + if (!target_inode)
12415 + if (target_is_normal_file())
12416 + return (int) target_storage_available;
12418 + return header_pages_allocated + main_pages_requested;
12421 +static int suspend_file_release_storage(void)
12423 + if (test_action_state(SUSPEND_KEEP_IMAGE) &&
12424 + test_suspend_state(SUSPEND_NOW_RESUMING))
12427 + suspend_put_extent_chain(&block_chain);
12429 + header_pages_allocated = 0;
12430 + main_pages_allocated = 0;
12431 + main_pages_requested = 0;
12435 +static int __suspend_file_allocate_storage(int main_storage_requested,
12436 + int header_storage);
12438 +static int suspend_file_allocate_header_space(int space_requested)
12442 + if (!block_chain.first && __suspend_file_allocate_storage(
12443 + main_pages_requested, space_requested)) {
12444 + printk("Failed to allocate space for the header.\n");
12448 + suspend_extent_state_goto_start(&suspend_writer_posn);
12449 + suspend_bio_ops.forward_one_page(); /* To first page */
12451 + for (i = 0; i < space_requested; i++) {
12452 + if (suspend_bio_ops.forward_one_page()) {
12453 + printk("Out of space while seeking to allocate "
12454 + "header pages,\n");
12455 + header_pages_allocated = i;
12460 + header_pages_allocated = space_requested;
12462 + /* The end of header pages will be the start of pageset 2 */
12463 + suspend_extent_state_save(&suspend_writer_posn,
12464 + &suspend_writer_posn_save[2]);
12468 +static int suspend_file_allocate_storage(int space_requested)
12470 + if (__suspend_file_allocate_storage(space_requested,
12471 + header_pages_allocated))
12474 + main_pages_requested = space_requested;
12478 +static int __suspend_file_allocate_storage(int main_space_requested,
12479 + int header_space_requested)
12483 + int extra_pages = DIV_ROUND_UP(main_space_requested *
12484 + (sizeof(unsigned long) + sizeof(int)), PAGE_SIZE);
12485 + int pages_to_get = main_space_requested + extra_pages +
12486 + header_space_requested;
12487 + int blocks_to_get = pages_to_get - block_chain.size;
12489 + /* Only release_storage reduces the size */
12490 + if (blocks_to_get < 1)
12493 + populate_block_list();
12495 + suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
12496 + "Finished with block_chain.size == %d.\n",
12497 + block_chain.size);
12499 + if (block_chain.size < pages_to_get) {
12500 + printk("Block chain size (%d) < header pages (%d) + extra pages (%d) + main pages (%d) (=%d pages).\n",
12501 + block_chain.size, header_pages_allocated, extra_pages,
12502 + main_space_requested, pages_to_get);
12503 + result = -ENOSPC;
12506 + main_pages_requested = main_space_requested;
12507 + main_pages_allocated = main_space_requested + extra_pages;
12509 + suspend_file_allocate_header_space(header_pages_allocated);
12513 +static int suspend_file_write_header_init(void)
12515 + suspend_extent_state_goto_start(&suspend_writer_posn);
12517 + suspend_writer_buffer_posn = suspend_header_bytes_used = 0;
12519 + /* Info needed to bootstrap goes at the start of the header.
12520 + * First we save the basic info needed for reading, including the number
12521 + * of header pages. Then we save the structs containing data needed
12522 + * for reading the header pages back.
12523 + * Note that even if header pages take more than one page, when we
12524 + * read back the info, we will have restored the location of the
12525 + * next header page by the time we go to use it.
12528 + suspend_bio_ops.rw_header_chunk(WRITE, &suspend_fileops,
12529 + (char *) &suspend_writer_posn_save,
12530 + sizeof(suspend_writer_posn_save));
12532 + suspend_bio_ops.rw_header_chunk(WRITE, &suspend_fileops,
12533 + (char *) &devinfo, sizeof(devinfo));
12535 + suspend_serialise_extent_chain(&suspend_fileops, &block_chain);
12540 +static int suspend_file_write_header_cleanup(void)
12542 + struct suspend_file_header *header;
12544 + /* Write any unsaved data */
12545 + if (suspend_writer_buffer_posn)
12546 + suspend_bio_ops.write_header_chunk_finish();
12548 + suspend_bio_ops.finish_all_io();
12550 + suspend_extent_state_goto_start(&suspend_writer_posn);
12551 + suspend_bio_ops.forward_one_page();
12553 + /* Adjust image header */
12554 + suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12555 + target_firstblock,
12556 + virt_to_page(suspend_writer_buffer));
12558 + header = (struct suspend_file_header *) suspend_writer_buffer;
12560 + prepare_signature(header,
12561 + suspend_writer_posn.current_offset <<
12562 + devinfo.bmap_shift);
12564 + suspend_bio_ops.bdev_page_io(WRITE, suspend_file_target_bdev,
12565 + target_firstblock,
12566 + virt_to_page(suspend_writer_buffer));
12568 + suspend_bio_ops.finish_all_io();
12573 +/* HEADER READING */
12575 +#ifdef CONFIG_DEVFS_FS
12576 +int create_dev(char *name, dev_t dev, char *devfs_name);
12578 +static int create_dev(char *name, dev_t dev, char *devfs_name)
12580 + sys_unlink(name);
12581 + return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
12585 +static int rd_init(void)
12587 + suspend_writer_buffer_posn = 0;
12589 + create_dev("/dev/root", ROOT_DEV, root_device_name);
12590 + create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
12592 + suspend_read_fd = sys_open("/dev/root", O_RDONLY, 0);
12593 + if (suspend_read_fd < 0)
12596 + sys_read(suspend_read_fd, suspend_writer_buffer, BLOCK_SIZE);
12598 + memcpy(&suspend_writer_posn_save,
12599 + suspend_writer_buffer + suspend_writer_buffer_posn,
12600 + sizeof(suspend_writer_posn_save));
12602 + suspend_writer_buffer_posn += sizeof(suspend_writer_posn_save);
12606 + sys_unlink("/dev/ram");
12607 + sys_unlink("/dev/root");
12611 +static int file_init(void)
12613 + suspend_writer_buffer_posn = 0;
12615 + /* Read suspend_file configuration */
12616 + suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12617 + target_header_start,
12618 + virt_to_page((unsigned long) suspend_writer_buffer));
12624 + * read_header_init()
12626 + * Ramdisk support based heavily on init/do_mounts_rd.c
12629 + * 1. Attempt to read the device specified with resume2=.
12630 + * 2. Check the contents of the header for our signature.
12631 + * 3. Warn, ignore, reset and/or continue as appropriate.
12632 + * 4. If continuing, read the suspend_file configuration section
12633 + * of the header and set up block device info so we can read
12634 + * the rest of the header & image.
12637 + * May not return if user choose to reboot at a warning.
12638 + * -EINVAL if cannot resume at this time. Booting should continue
12642 +static int suspend_file_read_header_init(void)
12645 + struct block_device *tmp;
12647 + if (test_suspend_state(SUSPEND_TRY_RESUME_RD))
12648 + result = rd_init();
12650 + result = file_init();
12653 + printk("FileAllocator read header init: Failed to initialise "
12654 + "reading the first page of data.\n");
12658 + memcpy(&suspend_writer_posn_save,
12659 + suspend_writer_buffer + suspend_writer_buffer_posn,
12660 + sizeof(suspend_writer_posn_save));
12662 + suspend_writer_buffer_posn += sizeof(suspend_writer_posn_save);
12664 + tmp = devinfo.bdev;
12667 + suspend_writer_buffer + suspend_writer_buffer_posn,
12668 + sizeof(devinfo));
12670 + devinfo.bdev = tmp;
12671 + suspend_writer_buffer_posn += sizeof(devinfo);
12673 + suspend_bio_ops.read_header_init();
12674 + suspend_extent_state_goto_start(&suspend_writer_posn);
12675 + suspend_bio_ops.set_extra_page_forward();
12677 + suspend_header_bytes_used = suspend_writer_buffer_posn;
12679 + return suspend_load_extent_chain(&block_chain);
12682 +static int suspend_file_read_header_cleanup(void)
12684 + suspend_bio_ops.rw_cleanup(READ);
12688 +static int suspend_file_signature_op(int op)
12691 + int result = 0, changed = 0;
12692 + struct suspend_file_header *header;
12694 + if(suspend_file_target_bdev <= 0)
12697 + cur = (char *) get_zeroed_page(GFP_ATOMIC);
12699 + printk("Unable to allocate a page for reading the image "
12704 + suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12705 + target_firstblock,
12706 + virt_to_page(cur));
12708 + header = (struct suspend_file_header *) cur;
12709 + result = parse_signature(header);
12713 + if (result == -1)
12716 + strcpy(header->sig, NoImage);
12717 + header->resumed_before = 0;
12718 + result = changed = 1;
12720 + case MARK_RESUME_ATTEMPTED:
12721 + if (result == 1) {
12722 + header->resumed_before = 1;
12726 + case UNMARK_RESUME_ATTEMPTED:
12727 + if (result == 1) {
12728 + header->resumed_before = 0;
12735 + suspend_bio_ops.bdev_page_io(WRITE, suspend_file_target_bdev,
12736 + target_firstblock,
12737 + virt_to_page(cur));
12740 + suspend_bio_ops.finish_all_io();
12741 + free_page((unsigned long) cur);
12745 +/* Print debug info
12750 +static int suspend_file_print_debug_stats(char *buffer, int size)
12754 + if (suspendActiveAllocator != &suspend_fileops) {
12755 + len = snprintf_used(buffer, size, "- FileAllocator inactive.\n");
12759 + len = snprintf_used(buffer, size, "- FileAllocator active.\n");
12761 + len+= snprintf_used(buffer+len, size-len, " Storage available for image: "
12763 + suspend_file_storage_allocated());
12771 + * Returns amount of space in the image header required
12772 + * for the suspend_file's data.
12774 + * We ensure the space is allocated, but actually save the
12775 + * data from write_header_init and therefore don't also define a
12776 + * save_config_info routine.
12778 +static int suspend_file_storage_needed(void)
12780 + return sig_size + strlen(suspend_file_target) + 1 +
12781 + 3 * sizeof(struct extent_iterate_saved_state) +
12782 + sizeof(devinfo) +
12783 + sizeof(struct extent_chain) - 2 * sizeof(void *) +
12784 + (2 * sizeof(unsigned long) * block_chain.num_extents);
12788 + * suspend_file_invalidate_image
12791 +static int suspend_file_invalidate_image(void)
12795 + suspend_file_release_storage();
12797 + result = suspend_file_signature_op(INVALIDATE);
12798 + if (result == 1 && !nr_suspends)
12799 + printk(KERN_WARNING "Suspend2: Image invalidated.\n");
12809 +static int suspend_file_image_exists(void)
12811 + if (!suspend_file_target_bdev)
12812 + reopen_resume_devt();
12814 + return suspend_file_signature_op(GET_IMAGE_EXISTS);
12818 + * Mark resume attempted.
12820 + * Record that we tried to resume from this image.
12823 +static void suspend_file_mark_resume_attempted(int mark)
12825 + suspend_file_signature_op(mark ? MARK_RESUME_ATTEMPTED:
12826 + UNMARK_RESUME_ATTEMPTED);
12829 +static void suspend_file_set_resume2(void)
12831 + char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
12832 + char *buffer2 = (char *) get_zeroed_page(GFP_ATOMIC);
12833 + unsigned long sector = bmap(target_inode, 0);
12836 + if (suspend_file_target_bdev) {
12837 + set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12839 + bdevname(suspend_file_target_bdev, buffer2);
12840 + offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12841 + "/dev/%s", buffer2);
12844 + offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12845 + ":0x%lx", sector << devinfo.bmap_shift);
12847 + offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12848 + "%s is not a valid target.", suspend_file_target);
12850 + sprintf(resume2_file, "file:%s", buffer);
12852 + free_page((unsigned long) buffer);
12853 + free_page((unsigned long) buffer2);
12855 + suspend_attempt_to_parse_resume_device(1);
12858 +static int __test_suspend_file_target(char *target, int resume_time, int quiet)
12860 + suspend_file_get_target_info(target, 0, resume_time);
12861 + if (suspend_file_signature_op(GET_IMAGE_EXISTS) > -1) {
12863 + printk("Suspend2: FileAllocator: File signature found.\n");
12864 + if (!resume_time)
12865 + suspend_file_set_resume2();
12867 + suspend_bio_ops.set_devinfo(&devinfo);
12868 + suspend_writer_posn.chains = &block_chain;
12869 + suspend_writer_posn.num_chains = 1;
12871 + if (!resume_time)
12872 + set_suspend_state(SUSPEND_CAN_SUSPEND);
12876 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
12882 + printk("Suspend2: FileAllocator: Sorry. No signature found at"
12883 + " %s.\n", target);
12885 + if (!resume_time)
12886 + printk("Suspend2: FileAllocator: Sorry. Target is not"
12887 + " set for suspending.\n");
12892 +static void test_suspend_file_target(void)
12894 + setting_suspend_file_target = 1;
12896 + printk("Suspend2: Suspending %sabled.\n",
12897 + __test_suspend_file_target(suspend_file_target, 0, 1) ?
12900 + setting_suspend_file_target = 0;
12904 + * Parse Image Location
12906 + * Attempt to parse a resume2= parameter.
12907 + * Swap Writer accepts:
12908 + * resume2=file:DEVNAME[:FIRSTBLOCK]
12911 + * DEVNAME is convertable to a dev_t by name_to_dev_t
12912 + * FIRSTBLOCK is the location of the first block in the file.
12913 + * BLOCKSIZE is the logical blocksize >= SECTOR_SIZE & <= PAGE_SIZE,
12914 + * mod SECTOR_SIZE == 0 of the device.
12915 + * Data is validated by attempting to read a header from the
12916 + * location given. Failure will result in suspend_file refusing to
12917 + * save an image, and a reboot with correct parameters will be
12921 +static int suspend_file_parse_sig_location(char *commandline,
12922 + int only_writer, int quiet)
12924 + char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
12925 + int result = -EINVAL, target_blocksize = 0;
12927 + if (strncmp(commandline, "file:", 5)) {
12928 + if (!only_writer)
12931 + commandline += 5;
12934 + * Don't check signature again if we're beginning a cycle. If we already
12935 + * did the initialisation successfully, assume we'll be okay when it comes
12938 + if (suspend_file_target_bdev)
12941 + devstart = thischar = commandline;
12942 + while ((*thischar != ':') && (*thischar != '@') &&
12943 + ((thischar - commandline) < 250) && (*thischar))
12946 + if (*thischar == ':') {
12947 + colon = thischar;
12952 + while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
12955 + if (*thischar == '@') {
12956 + at_symbol = thischar;
12961 + * For the suspend_file, you can be able to resume, but not suspend,
12962 + * because the resume2= is set correctly, but the suspend_file_target
12965 + * We may have come here as a result of setting resume2 or
12966 + * suspend_file_target. We only test the suspend_file target in the
12967 + * former case (it's already done in the later), and we do it before
12968 + * setting the block number ourselves. It will overwrite the values
12969 + * given on the command line if we don't.
12972 + if (!setting_suspend_file_target)
12973 + __test_suspend_file_target(suspend_file_target, 1, 0);
12976 + target_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
12978 + target_firstblock = 0;
12981 + target_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
12982 + if (target_blocksize & (SECTOR_SIZE - 1)) {
12983 + printk("FileAllocator: Blocksizes are multiples of %d.\n", SECTOR_SIZE);
12984 + result = -EINVAL;
12990 + printk("Suspend2 FileAllocator: Testing whether you can resume:\n");
12992 + suspend_file_get_target_info(commandline, 0, 1);
12994 + if (!suspend_file_target_bdev || IS_ERR(suspend_file_target_bdev)) {
12995 + suspend_file_target_bdev = NULL;
13000 + if (target_blocksize)
13001 + set_devinfo(suspend_file_target_bdev, ffs(target_blocksize));
13003 + result = __test_suspend_file_target(commandline, 1, 0);
13007 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
13010 + printk("Resuming %sabled.\n", result ? "dis" : "en");
13015 + *at_symbol = '@';
13020 +/* suspend_file_save_config_info
13022 + * Description: Save the target's name, not for resume time, but for all_settings.
13023 + * Arguments: Buffer: Pointer to a buffer of size PAGE_SIZE.
13024 + * Returns: Number of bytes used for saving our data.
13027 +static int suspend_file_save_config_info(char *buffer)
13029 + strcpy(buffer, suspend_file_target);
13030 + return strlen(suspend_file_target) + 1;
13033 +/* suspend_file_load_config_info
13035 + * Description: Reload target's name.
13036 + * Arguments: Buffer: Pointer to the start of the data.
13037 + * Size: Number of bytes that were saved.
13040 +static void suspend_file_load_config_info(char *buffer, int size)
13042 + strcpy(suspend_file_target, buffer);
13045 +static int suspend_file_initialise(int starting_cycle)
13047 + if (starting_cycle) {
13048 + if (suspendActiveAllocator != &suspend_fileops)
13051 + if (starting_cycle & SYSFS_SUSPEND && !*suspend_file_target) {
13052 + printk("FileAllocator is the active writer, "
13053 + "but no filename has been set.\n");
13058 + if (suspend_file_target)
13059 + suspend_file_get_target_info(suspend_file_target, starting_cycle, 0);
13061 + if (starting_cycle && (suspend_file_image_exists() == -1)) {
13062 + printk("%s is does not have a valid signature for suspending.\n",
13063 + suspend_file_target);
13070 +static struct suspend_sysfs_data sysfs_params[] = {
13073 + SUSPEND2_ATTR("target", SYSFS_RW),
13074 + SYSFS_STRING(suspend_file_target, 256, SYSFS_NEEDS_SM_FOR_WRITE),
13075 + .write_side_effect = test_suspend_file_target,
13079 + SUSPEND2_ATTR("enabled", SYSFS_RW),
13080 + SYSFS_INT(&suspend_fileops.enabled, 0, 1, 0),
13081 + .write_side_effect = attempt_to_parse_resume_device2,
13085 +static struct suspend_module_ops suspend_fileops = {
13086 + .type = WRITER_MODULE,
13087 + .name = "File Allocator",
13088 + .directory = "file",
13089 + .module = THIS_MODULE,
13090 + .print_debug_info = suspend_file_print_debug_stats,
13091 + .save_config_info = suspend_file_save_config_info,
13092 + .load_config_info = suspend_file_load_config_info,
13093 + .storage_needed = suspend_file_storage_needed,
13094 + .initialise = suspend_file_initialise,
13095 + .cleanup = suspend_file_cleanup,
13097 + .storage_available = suspend_file_storage_available,
13098 + .storage_allocated = suspend_file_storage_allocated,
13099 + .release_storage = suspend_file_release_storage,
13100 + .allocate_header_space = suspend_file_allocate_header_space,
13101 + .allocate_storage = suspend_file_allocate_storage,
13102 + .image_exists = suspend_file_image_exists,
13103 + .mark_resume_attempted = suspend_file_mark_resume_attempted,
13104 + .write_header_init = suspend_file_write_header_init,
13105 + .write_header_cleanup = suspend_file_write_header_cleanup,
13106 + .read_header_init = suspend_file_read_header_init,
13107 + .read_header_cleanup = suspend_file_read_header_cleanup,
13108 + .invalidate_image = suspend_file_invalidate_image,
13109 + .parse_sig_location = suspend_file_parse_sig_location,
13111 + .sysfs_data = sysfs_params,
13112 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
13115 +/* ---- Registration ---- */
13116 +static __init int suspend_file_load(void)
13118 + suspend_fileops.rw_init = suspend_bio_ops.rw_init;
13119 + suspend_fileops.rw_cleanup = suspend_bio_ops.rw_cleanup;
13120 + suspend_fileops.read_chunk = suspend_bio_ops.read_chunk;
13121 + suspend_fileops.write_chunk = suspend_bio_ops.write_chunk;
13122 + suspend_fileops.rw_header_chunk = suspend_bio_ops.rw_header_chunk;
13124 + return suspend_register_module(&suspend_fileops);
13128 +static __exit void suspend_file_unload(void)
13130 + suspend_unregister_module(&suspend_fileops);
13133 +module_init(suspend_file_load);
13134 +module_exit(suspend_file_unload);
13135 +MODULE_LICENSE("GPL");
13136 +MODULE_AUTHOR("Nigel Cunningham");
13137 +MODULE_DESCRIPTION("Suspend2 FileAllocator");
13139 +late_initcall(suspend_file_load);
13141 diff -ruN linux-2.6.22/kernel/power/suspend_swap.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend_swap.c
13142 --- linux-2.6.22/kernel/power/suspend_swap.c 1970-01-01 10:00:00.000000000 +1000
13143 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend_swap.c 2007-07-11 22:25:42.000000000 +1000
13146 + * kernel/power/suspend_swap.c
13148 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
13150 + * Distributed under GPLv2.
13152 + * This file encapsulates functions for usage of swap space as a
13156 +#include <linux/suspend.h>
13157 +#include <linux/module.h>
13158 +#include <linux/blkdev.h>
13159 +#include <linux/swapops.h>
13160 +#include <linux/swap.h>
13161 +#include <linux/syscalls.h>
13163 +#include "suspend.h"
13164 +#include "sysfs.h"
13165 +#include "modules.h"
13168 +#include "extent.h"
13169 +#include "block_io.h"
13171 +static struct suspend_module_ops suspend_swapops;
13173 +#define SIGNATURE_VER 6
13175 +/* --- Struct of pages stored on disk */
13178 + union swap_header swh; /* swh.magic is the only member used */
13181 +union p_diskpage {
13182 + union diskpage *pointer;
13184 + unsigned long address;
13187 +/* Devices used for swap */
13188 +static struct suspend_bdev_info devinfo[MAX_SWAPFILES];
13190 +/* Extent chains for swap & blocks */
13191 +struct extent_chain swapextents;
13192 +struct extent_chain block_chain[MAX_SWAPFILES];
13194 +static dev_t header_dev_t;
13195 +static struct block_device *header_block_device;
13196 +static unsigned long headerblock;
13198 +/* For swapfile automatically swapon/off'd. */
13199 +static char swapfilename[32] = "";
13200 +static int suspend_swapon_status;
13202 +/* Header Page Information */
13203 +static int header_pages_allocated;
13206 +static int main_pages_allocated, main_pages_requested;
13208 +/* User Specified Parameters. */
13210 +static unsigned long resume_firstblock;
13211 +static int resume_blocksize;
13212 +static dev_t resume_swap_dev_t;
13213 +static struct block_device *resume_block_device;
13215 +struct sysinfo swapinfo;
13216 +static int suspend_swap_invalidate_image(void);
13218 +/* Block devices open. */
13219 +struct bdev_opened
13222 + struct block_device *bdev;
13227 + * Entry MAX_SWAPFILES is the resume block device, which may
13228 + * not be a swap device enabled when we suspend.
13229 + * Entry MAX_SWAPFILES + 1 is the header block device, which
13230 + * is needed before we find out which slot it occupies.
13232 +static struct bdev_opened *bdev_info_list[MAX_SWAPFILES + 2];
13234 +static void close_bdev(int i)
13236 + struct bdev_opened *this = bdev_info_list[i];
13238 + if (this->claimed)
13239 + bd_release(this->bdev);
13241 + /* Release our reference. */
13242 + blkdev_put(this->bdev);
13244 + /* Free our info. */
13247 + bdev_info_list[i] = NULL;
13250 +static void close_bdevs(void)
13254 + for (i = 0; i < MAX_SWAPFILES; i++)
13255 + if (bdev_info_list[i])
13258 + resume_block_device = header_block_device = NULL;
13261 +static struct block_device *open_bdev(int index, dev_t device, int display_errs)
13263 + struct bdev_opened *this;
13264 + struct block_device *bdev;
13266 + if (bdev_info_list[index] && (bdev_info_list[index]->device == device)){
13267 + bdev = bdev_info_list[index]->bdev;
13271 + if (bdev_info_list[index] && bdev_info_list[index]->device != device)
13272 + close_bdev(index);
13274 + bdev = open_by_devnum(device, FMODE_READ);
13276 + if (IS_ERR(bdev) || !bdev) {
13277 + if (display_errs)
13278 + suspend_early_boot_message(1,SUSPEND_CONTINUE_REQ,
13279 + "Failed to get access to block device "
13280 + "\"%x\" (error %d).\n Maybe you need "
13281 + "to run mknod and/or lvmsetup in an "
13282 + "initrd/ramfs?", device, bdev);
13283 + return ERR_PTR(-EINVAL);
13286 + this = kmalloc(sizeof(struct bdev_opened), GFP_KERNEL);
13288 + printk(KERN_WARNING "Suspend2: Failed to allocate memory for "
13289 + "opening a bdev.");
13290 + return ERR_PTR(-ENOMEM);
13293 + bdev_info_list[index] = this;
13294 + this->device = device;
13295 + this->bdev = bdev;
13297 + if (index < MAX_SWAPFILES)
13298 + devinfo[index].bdev = bdev;
13303 +/* Must be silent - might be called from cat /sys/power/suspend2/debug_info
13304 + * Returns 0 if was off, -EBUSY if was on, error value otherwise.
13306 +static int enable_swapfile(void)
13308 + int activateswapresult = -EINVAL;
13310 + if (suspend_swapon_status)
13313 + if (swapfilename[0]) {
13314 + /* Attempt to swap on with maximum priority */
13315 + activateswapresult = sys_swapon(swapfilename, 0xFFFF);
13316 + if ((activateswapresult) && (activateswapresult != -EBUSY))
13317 + printk("Suspend2: The swapfile/partition specified by "
13318 + "/sys/power/suspend2/suspend_swap/swapfile "
13319 + "(%s) could not be turned on (error %d). "
13320 + "Attempting to continue.\n",
13321 + swapfilename, activateswapresult);
13322 + if (!activateswapresult)
13323 + suspend_swapon_status = 1;
13325 + return activateswapresult;
13328 +/* Returns 0 if was on, -EINVAL if was off, error value otherwise */
13329 +static int disable_swapfile(void)
13331 + int result = -EINVAL;
13333 + if (!suspend_swapon_status)
13336 + if (swapfilename[0]) {
13337 + result = sys_swapoff(swapfilename);
13338 + if (result == -EINVAL)
13339 + return 0; /* Wasn't on */
13341 + suspend_swapon_status = 0;
13347 +static int try_to_parse_resume_device(char *commandline, int quiet)
13349 + struct kstat stat;
13352 + resume_swap_dev_t = name_to_dev_t(commandline);
13354 + if (!resume_swap_dev_t) {
13355 + struct file *file = filp_open(commandline, O_RDONLY, 0);
13357 + if (!IS_ERR(file) && file) {
13358 + vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
13359 + filp_close(file, NULL);
13361 + error = vfs_stat(commandline, &stat);
13363 + resume_swap_dev_t = stat.rdev;
13366 + if (!resume_swap_dev_t) {
13370 + if (test_suspend_state(SUSPEND_TRYING_TO_RESUME))
13371 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
13372 + "Failed to translate \"%s\" into a device id.\n",
13375 + printk("Suspend2: Can't translate \"%s\" into a device "
13376 + "id yet.\n", commandline);
13380 + resume_block_device = open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 0);
13381 + if (IS_ERR(resume_block_device)) {
13383 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
13384 + "Failed to get access to \"%s\", where"
13385 + " the swap header should be found.",
13394 + * If we have read part of the image, we might have filled memory with
13395 + * data that should be zeroed out.
13397 +static void suspend_swap_noresume_reset(void)
13399 + memset((char *) &devinfo, 0, sizeof(devinfo));
13402 +static int parse_signature(char *header, int restore)
13406 + if (!memcmp("SWAP-SPACE",header,10))
13408 + else if (!memcmp("SWAPSPACE2",header,10))
13411 + else if (!memcmp("S1SUSP",header,6))
13413 + else if (!memcmp("S2SUSP",header,6))
13415 + else if (!memcmp("S1SUSPEND",header,9))
13418 + else if (!memcmp("z",header,1))
13420 + else if (!memcmp("Z",header,1))
13424 + * Put bdev of suspend header in last byte of swap header
13425 + * (unsigned short)
13428 + dev_t *header_ptr = (dev_t *) &header[1];
13429 + unsigned char *headerblocksize_ptr =
13430 + (unsigned char *) &header[5];
13431 + u32 *headerblock_ptr = (u32 *) &header[6];
13432 + header_dev_t = *header_ptr;
13434 + * We are now using the highest bit of the char to indicate
13435 + * whether we have attempted to resume from this image before.
13437 + clear_suspend_state(SUSPEND_RESUMED_BEFORE);
13438 + if (((int) *headerblocksize_ptr) & 0x80)
13439 + set_suspend_state(SUSPEND_RESUMED_BEFORE);
13440 + headerblock = (unsigned long) *headerblock_ptr;
13443 + if ((restore) && (type > 5)) {
13444 + /* We only reset our own signatures */
13446 + memcpy(header,"SWAPSPACE2",10);
13448 + memcpy(header,"SWAP-SPACE",10);
13455 + * prepare_signature
13457 +static int prepare_signature(dev_t bdev, unsigned long block,
13458 + char *current_header)
13460 + int current_type = parse_signature(current_header, 0);
13461 + dev_t *header_ptr = (dev_t *) (¤t_header[1]);
13462 + unsigned long *headerblock_ptr =
13463 + (unsigned long *) (¤t_header[6]);
13465 + if ((current_type > 1) && (current_type < 6))
13468 + /* At the moment, I don't have a way to handle the block being
13469 + * > 32 bits. Not enough room in the signature and no way to
13470 + * safely put the data elsewhere. */
13472 + if (BITS_PER_LONG == 64 && ffs(block) > 31) {
13473 + suspend_prepare_status(DONT_CLEAR_BAR,
13474 + "Header sector requires 33+ bits. "
13475 + "Would not be able to resume.");
13479 + if (current_type & 1)
13480 + current_header[0] = 'Z';
13482 + current_header[0] = 'z';
13483 + *header_ptr = bdev;
13484 + /* prev is the first/last swap page of the resume area */
13485 + *headerblock_ptr = (unsigned long) block;
13489 +static int __suspend_swap_allocate_storage(int main_storage_requested,
13490 + int header_storage);
13492 +static int suspend_swap_allocate_header_space(int space_requested)
13496 + if (!swapextents.size && __suspend_swap_allocate_storage(
13497 + main_pages_requested, space_requested)) {
13498 + printk("Failed to allocate space for the header.\n");
13502 + suspend_extent_state_goto_start(&suspend_writer_posn);
13503 + suspend_bio_ops.forward_one_page(); /* To first page */
13505 + for (i = 0; i < space_requested; i++) {
13506 + if (suspend_bio_ops.forward_one_page()) {
13507 + printk("Out of space while seeking to allocate "
13508 + "header pages,\n");
13509 + header_pages_allocated = i;
13515 + header_pages_allocated = space_requested;
13517 + /* The end of header pages will be the start of pageset 2;
13518 + * we are now sitting on the first pageset2 page. */
13519 + suspend_extent_state_save(&suspend_writer_posn,
13520 + &suspend_writer_posn_save[2]);
13524 +static void get_main_pool_phys_params(void)
13526 + struct extent *extentpointer = NULL;
13527 + unsigned long address;
13528 + int i, extent_min = -1, extent_max = -1, last_chain = -1;
13530 + for (i = 0; i < MAX_SWAPFILES; i++)
13531 + if (block_chain[i].first)
13532 + suspend_put_extent_chain(&block_chain[i]);
13534 + suspend_extent_for_each(&swapextents, extentpointer, address) {
13535 + swp_entry_t swap_address = extent_val_to_swap_entry(address);
13536 + pgoff_t offset = swp_offset(swap_address);
13537 + unsigned swapfilenum = swp_type(swap_address);
13538 + struct swap_info_struct *sis = get_swap_info_struct(swapfilenum);
13539 + sector_t new_sector = map_swap_page(sis, offset);
13541 + if ((new_sector == extent_max + 1) &&
13542 + (last_chain == swapfilenum))
13545 + if (extent_min > -1) {
13546 + if (test_action_state(SUSPEND_TEST_BIO))
13547 + printk("Adding extent chain %d %d-%d.\n",
13550 + devinfo[last_chain].bmap_shift,
13552 + devinfo[last_chain].bmap_shift);
13554 + suspend_add_to_extent_chain(
13555 + &block_chain[last_chain],
13556 + extent_min, extent_max);
13558 + extent_min = extent_max = new_sector;
13559 + last_chain = swapfilenum;
13563 + if (extent_min > -1) {
13564 + if (test_action_state(SUSPEND_TEST_BIO))
13565 + printk("Adding extent chain %d %d-%d.\n",
13568 + devinfo[last_chain].bmap_shift,
13570 + devinfo[last_chain].bmap_shift);
13571 + suspend_add_to_extent_chain(
13572 + &block_chain[last_chain],
13573 + extent_min, extent_max);
13576 + suspend_swap_allocate_header_space(header_pages_allocated);
13579 +static int suspend_swap_storage_allocated(void)
13581 + return main_pages_requested + header_pages_allocated;
13584 +static int suspend_swap_storage_available(void)
13586 + si_swapinfo(&swapinfo);
13587 + return (((int) swapinfo.freeswap + main_pages_allocated) * PAGE_SIZE /
13588 + (PAGE_SIZE + sizeof(unsigned long) + sizeof(int)));
13591 +static int suspend_swap_initialise(int starting_cycle)
13593 + if (!starting_cycle)
13596 + enable_swapfile();
13598 + if (resume_swap_dev_t && !resume_block_device &&
13599 + IS_ERR(resume_block_device =
13600 + open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 1)))
13606 +static void suspend_swap_cleanup(int ending_cycle)
13608 + if (ending_cycle)
13609 + disable_swapfile();
13614 +static int suspend_swap_release_storage(void)
13618 + if (test_action_state(SUSPEND_KEEP_IMAGE) &&
13619 + test_suspend_state(SUSPEND_NOW_RESUMING))
13622 + header_pages_allocated = 0;
13623 + main_pages_allocated = 0;
13625 + if (swapextents.first) {
13626 + /* Free swap entries */
13627 + struct extent *extentpointer;
13628 + unsigned long extentvalue;
13629 + suspend_extent_for_each(&swapextents, extentpointer,
13631 + swap_free(extent_val_to_swap_entry(extentvalue));
13633 + suspend_put_extent_chain(&swapextents);
13635 + for (i = 0; i < MAX_SWAPFILES; i++)
13636 + if (block_chain[i].first)
13637 + suspend_put_extent_chain(&block_chain[i]);
13643 +static int suspend_swap_allocate_storage(int space_requested)
13645 + if (!__suspend_swap_allocate_storage(space_requested,
13646 + header_pages_allocated)) {
13647 + main_pages_requested = space_requested;
13654 +static void free_swap_range(unsigned long min, unsigned long max)
13658 + for (j = min; j < max; j++)
13659 + swap_free(extent_val_to_swap_entry(j));
13663 + * Round robin allocation (where swap storage has the same priority).
13664 + * could make this very inefficient, so we track extents allocated on
13665 + * a per-swapfiles basis.
13667 +static int __suspend_swap_allocate_storage(int main_space_requested,
13668 + int header_space_requested)
13670 + int i, result = 0, first[MAX_SWAPFILES], pages_to_get, extra_pages, gotten = 0;
13671 + unsigned long extent_min[MAX_SWAPFILES], extent_max[MAX_SWAPFILES];
13673 + extra_pages = DIV_ROUND_UP(main_space_requested * (sizeof(unsigned long)
13674 + + sizeof(int)), PAGE_SIZE);
13675 + pages_to_get = main_space_requested + extra_pages +
13676 + header_space_requested - swapextents.size;
13678 + if (pages_to_get < 1)
13681 + for (i=0; i < MAX_SWAPFILES; i++) {
13682 + struct swap_info_struct *si = get_swap_info_struct(i);
13683 + if ((devinfo[i].bdev = si->bdev))
13684 + devinfo[i].dev_t = si->bdev->bd_dev;
13685 + devinfo[i].bmap_shift = 3;
13686 + devinfo[i].blocks_per_page = 1;
13690 + for(i=0; i < pages_to_get; i++) {
13691 + swp_entry_t entry;
13692 + unsigned long new_value;
13693 + unsigned swapfilenum;
13695 + entry = get_swap_page();
13699 + swapfilenum = swp_type(entry);
13700 + new_value = swap_entry_to_extent_val(entry);
13702 + if (first[swapfilenum]) {
13703 + first[swapfilenum] = 0;
13704 + extent_min[swapfilenum] = new_value;
13705 + extent_max[swapfilenum] = new_value;
13710 + if (new_value == extent_max[swapfilenum] + 1) {
13711 + extent_max[swapfilenum]++;
13716 + if (suspend_add_to_extent_chain(&swapextents,
13717 + extent_min[swapfilenum],
13718 + extent_max[swapfilenum])) {
13719 + free_swap_range(extent_min[swapfilenum],
13720 + extent_max[swapfilenum]);
13721 + swap_free(entry);
13722 + gotten -= (extent_max[swapfilenum] -
13723 + extent_min[swapfilenum]);
13726 + extent_min[swapfilenum] = new_value;
13727 + extent_max[swapfilenum] = new_value;
13732 + for (i = 0; i < MAX_SWAPFILES; i++)
13733 + if (!first[i] && suspend_add_to_extent_chain(&swapextents,
13734 + extent_min[i], extent_max[i])) {
13735 + free_swap_range(extent_min[i], extent_max[i]);
13736 + gotten -= (extent_max[i] - extent_min[i]);
13739 + if (gotten < pages_to_get)
13740 + result = -ENOSPC;
13742 + main_pages_allocated += gotten;
13743 + get_main_pool_phys_params();
13747 +static int suspend_swap_write_header_init(void)
13750 + struct swap_info_struct *si;
13752 + suspend_extent_state_goto_start(&suspend_writer_posn);
13754 + suspend_writer_buffer_posn = suspend_header_bytes_used = 0;
13756 + /* Info needed to bootstrap goes at the start of the header.
13757 + * First we save the positions and devinfo, including the number
13758 + * of header pages. Then we save the structs containing data needed
13759 + * for reading the header pages back.
13760 + * Note that even if header pages take more than one page, when we
13761 + * read back the info, we will have restored the location of the
13762 + * next header page by the time we go to use it.
13765 + /* Forward one page will be done prior to the read */
13766 + for (i = 0; i < MAX_SWAPFILES; i++) {
13767 + si = get_swap_info_struct(i);
13768 + if (si->swap_file)
13769 + devinfo[i].dev_t = si->bdev->bd_dev;
13771 + devinfo[i].dev_t = (dev_t) 0;
13774 + if ((result = suspend_bio_ops.rw_header_chunk(WRITE,
13775 + &suspend_swapops,
13776 + (char *) &suspend_writer_posn_save,
13777 + sizeof(suspend_writer_posn_save))))
13780 + if ((result = suspend_bio_ops.rw_header_chunk(WRITE,
13781 + &suspend_swapops,
13782 + (char *) &devinfo, sizeof(devinfo))))
13785 + for (i=0; i < MAX_SWAPFILES; i++)
13786 + suspend_serialise_extent_chain(&suspend_swapops, &block_chain[i]);
13791 +static int suspend_swap_write_header_cleanup(void)
13794 + struct swap_info_struct *si;
13796 + /* Write any unsaved data */
13797 + if (suspend_writer_buffer_posn)
13798 + suspend_bio_ops.write_header_chunk_finish();
13800 + suspend_bio_ops.finish_all_io();
13802 + suspend_extent_state_goto_start(&suspend_writer_posn);
13803 + suspend_bio_ops.forward_one_page();
13805 + /* Adjust swap header */
13806 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
13807 + resume_firstblock,
13808 + virt_to_page(suspend_writer_buffer));
13810 + si = get_swap_info_struct(suspend_writer_posn.current_chain);
13811 + result = prepare_signature(si->bdev->bd_dev,
13812 + suspend_writer_posn.current_offset,
13813 + ((union swap_header *) suspend_writer_buffer)->magic.magic);
13816 + suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
13817 + resume_firstblock,
13818 + virt_to_page(suspend_writer_buffer));
13820 + suspend_bio_ops.finish_all_io();
13825 +/* ------------------------- HEADER READING ------------------------- */
13828 + * read_header_init()
13831 + * 1. Attempt to read the device specified with resume2=.
13832 + * 2. Check the contents of the swap header for our signature.
13833 + * 3. Warn, ignore, reset and/or continue as appropriate.
13834 + * 4. If continuing, read the suspend_swap configuration section
13835 + * of the header and set up block device info so we can read
13836 + * the rest of the header & image.
13839 + * May not return if user choose to reboot at a warning.
13840 + * -EINVAL if cannot resume at this time. Booting should continue
13844 +static int suspend_swap_read_header_init(void)
13846 + int i, result = 0;
13848 + suspend_header_bytes_used = 0;
13850 + if (!header_dev_t) {
13851 + printk("read_header_init called when we haven't "
13852 + "verified there is an image!\n");
13857 + * If the header is not on the resume_swap_dev_t, get the resume device first.
13859 + if (header_dev_t != resume_swap_dev_t) {
13860 + header_block_device = open_bdev(MAX_SWAPFILES + 1,
13861 + header_dev_t, 1);
13863 + if (IS_ERR(header_block_device))
13864 + return PTR_ERR(header_block_device);
13866 + header_block_device = resume_block_device;
13869 + * Read suspend_swap configuration.
13870 + * Headerblock size taken into account already.
13872 + suspend_bio_ops.bdev_page_io(READ, header_block_device,
13873 + headerblock << 3,
13874 + virt_to_page((unsigned long) suspend_writer_buffer));
13876 + memcpy(&suspend_writer_posn_save, suspend_writer_buffer, 3 * sizeof(struct extent_iterate_saved_state));
13878 + suspend_writer_buffer_posn = 3 * sizeof(struct extent_iterate_saved_state);
13879 + suspend_header_bytes_used += 3 * sizeof(struct extent_iterate_saved_state);
13881 + memcpy(&devinfo, suspend_writer_buffer + suspend_writer_buffer_posn, sizeof(devinfo));
13883 + suspend_writer_buffer_posn += sizeof(devinfo);
13884 + suspend_header_bytes_used += sizeof(devinfo);
13886 + /* Restore device info */
13887 + for (i = 0; i < MAX_SWAPFILES; i++) {
13888 + dev_t thisdevice = devinfo[i].dev_t;
13889 + struct block_device *result;
13891 + devinfo[i].bdev = NULL;
13896 + if (thisdevice == resume_swap_dev_t) {
13897 + devinfo[i].bdev = resume_block_device;
13898 + bdev_info_list[i] = bdev_info_list[MAX_SWAPFILES];
13899 + bdev_info_list[MAX_SWAPFILES] = NULL;
13903 + if (thisdevice == header_dev_t) {
13904 + devinfo[i].bdev = header_block_device;
13905 + bdev_info_list[i] = bdev_info_list[MAX_SWAPFILES + 1];
13906 + bdev_info_list[MAX_SWAPFILES + 1] = NULL;
13910 + result = open_bdev(i, thisdevice, 1);
13911 + if (IS_ERR(result))
13912 + return PTR_ERR(result);
13915 + suspend_bio_ops.read_header_init();
13916 + suspend_extent_state_goto_start(&suspend_writer_posn);
13917 + suspend_bio_ops.set_extra_page_forward();
13919 + for (i = 0; i < MAX_SWAPFILES && !result; i++)
13920 + result = suspend_load_extent_chain(&block_chain[i]);
13925 +static int suspend_swap_read_header_cleanup(void)
13927 + suspend_bio_ops.rw_cleanup(READ);
13931 +/* suspend_swap_invalidate_image
13934 +static int suspend_swap_invalidate_image(void)
13936 + union p_diskpage cur;
13940 + cur.address = get_zeroed_page(GFP_ATOMIC);
13941 + if (!cur.address) {
13942 + printk("Unable to allocate a page for restoring the swap signature.\n");
13947 + * If nr_suspends == 0, we must be booting, so no swap pages
13948 + * will be recorded as used yet.
13951 + if (nr_suspends > 0)
13952 + suspend_swap_release_storage();
13955 + * We don't do a sanity check here: we want to restore the swap
13956 + * whatever version of kernel made the suspend image.
13958 + * We need to write swap, but swap may not be enabled so
13959 + * we write the device directly
13962 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
13963 + resume_firstblock,
13964 + virt_to_page(cur.pointer));
13966 + result = parse_signature(cur.pointer->swh.magic.magic, 1);
13971 + strncpy(newsig, cur.pointer->swh.magic.magic, 10);
13974 + suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
13975 + resume_firstblock,
13976 + virt_to_page(cur.pointer));
13978 + if (!nr_suspends)
13979 + printk(KERN_WARNING "Suspend2: Image invalidated.\n");
13981 + suspend_bio_ops.finish_all_io();
13982 + free_page(cur.address);
13990 + * Returns the number of bytes of RAM needed for this
13991 + * code to do its work. (Used when calculating whether
13992 + * we have enough memory to be able to suspend & resume).
13995 +static int suspend_swap_memory_needed(void)
14001 + * Print debug info
14005 +static int suspend_swap_print_debug_stats(char *buffer, int size)
14008 + struct sysinfo sysinfo;
14010 + if (suspendActiveAllocator != &suspend_swapops) {
14011 + len = snprintf_used(buffer, size, "- SwapAllocator inactive.\n");
14015 + len = snprintf_used(buffer, size, "- SwapAllocator active.\n");
14016 + if (swapfilename[0])
14017 + len+= snprintf_used(buffer+len, size-len,
14018 + " Attempting to automatically swapon: %s.\n", swapfilename);
14020 + si_swapinfo(&sysinfo);
14022 + len+= snprintf_used(buffer+len, size-len, " Swap available for image: %ld pages.\n",
14023 + (int) sysinfo.freeswap + suspend_swap_storage_allocated());
14031 + * Returns amount of space in the swap header required
14032 + * for the suspend_swap's data. This ignores the links between
14033 + * pages, which we factor in when allocating the space.
14035 + * We ensure the space is allocated, but actually save the
14036 + * data from write_header_init and therefore don't also define a
14037 + * save_config_info routine.
14039 +static int suspend_swap_storage_needed(void)
14042 + result = sizeof(suspend_writer_posn_save) + sizeof(devinfo);
14044 + for (i = 0; i < MAX_SWAPFILES; i++) {
14045 + result += 3 * sizeof(int);
14046 + result += (2 * sizeof(unsigned long) *
14047 + block_chain[i].num_extents);
14056 +static int suspend_swap_image_exists(void)
14058 + int signature_found;
14059 + union p_diskpage diskpage;
14061 + if (!resume_swap_dev_t) {
14062 + printk("Not even trying to read header "
14063 + "because resume_swap_dev_t is not set.\n");
14067 + if (!resume_block_device &&
14068 + IS_ERR(resume_block_device =
14069 + open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 1))) {
14070 + printk("Failed to open resume dev_t (%x).\n", resume_swap_dev_t);
14074 + diskpage.address = get_zeroed_page(GFP_ATOMIC);
14076 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
14077 + resume_firstblock,
14078 + virt_to_page(diskpage.ptr));
14079 + suspend_bio_ops.finish_all_io();
14081 + signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14082 + free_page(diskpage.address);
14084 + if (signature_found < 2) {
14085 + printk("Suspend2: Normal swapspace found.\n");
14086 + return 0; /* Normal swap space */
14087 + } else if (signature_found == -1) {
14088 + printk(KERN_ERR "Suspend2: Unable to find a signature. Could "
14089 + "you have moved a swap file?\n");
14091 + } else if (signature_found < 6) {
14092 + printk("Suspend2: Detected another implementation's signature.\n");
14094 + } else if ((signature_found >> 1) != SIGNATURE_VER) {
14095 + if ((!(test_suspend_state(SUSPEND_NORESUME_SPECIFIED))) &&
14096 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
14097 + "Found a different style suspend image signature.")) {
14098 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
14099 + printk("Suspend2: Dectected another implementation's signature.\n");
14107 + * Mark resume attempted.
14109 + * Record that we tried to resume from this image.
14111 +static void suspend_swap_mark_resume_attempted(int mark)
14113 + union p_diskpage diskpage;
14114 + int signature_found;
14116 + if (!resume_swap_dev_t) {
14117 + printk("Not even trying to record attempt at resuming"
14118 + " because resume_swap_dev_t is not set.\n");
14122 + diskpage.address = get_zeroed_page(GFP_ATOMIC);
14124 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
14125 + resume_firstblock,
14126 + virt_to_page(diskpage.ptr));
14127 + signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14129 + switch (signature_found) {
14132 + diskpage.pointer->swh.magic.magic[5] &= ~0x80;
14134 + diskpage.pointer->swh.magic.magic[5] |= 0x80;
14138 + suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
14139 + resume_firstblock,
14140 + virt_to_page(diskpage.ptr));
14141 + suspend_bio_ops.finish_all_io();
14142 + free_page(diskpage.address);
14147 + * Parse Image Location
14149 + * Attempt to parse a resume2= parameter.
14150 + * Swap Writer accepts:
14151 + * resume2=swap:DEVNAME[:FIRSTBLOCK][@BLOCKSIZE]
14154 + * DEVNAME is convertable to a dev_t by name_to_dev_t
14155 + * FIRSTBLOCK is the location of the first block in the swap file
14156 + * (specifying for a swap partition is nonsensical but not prohibited).
14157 + * Data is validated by attempting to read a swap header from the
14158 + * location given. Failure will result in suspend_swap refusing to
14159 + * save an image, and a reboot with correct parameters will be
14162 +static int suspend_swap_parse_sig_location(char *commandline,
14163 + int only_allocator, int quiet)
14165 + char *thischar, *devstart, *colon = NULL, *at_symbol = NULL;
14166 + union p_diskpage diskpage;
14167 + int signature_found, result = -EINVAL, temp_result;
14169 + if (strncmp(commandline, "swap:", 5)) {
14171 + * Failing swap:, we'll take a simple
14172 + * resume2=/dev/hda2, but fall through to
14173 + * other allocators if /dev/ isn't matched.
14175 + if (strncmp(commandline, "/dev/", 5))
14178 + commandline += 5;
14180 + devstart = thischar = commandline;
14181 + while ((*thischar != ':') && (*thischar != '@') &&
14182 + ((thischar - commandline) < 250) && (*thischar))
14185 + if (*thischar == ':') {
14186 + colon = thischar;
14191 + while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
14194 + if (*thischar == '@') {
14195 + at_symbol = thischar;
14200 + resume_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
14202 + resume_firstblock = 0;
14204 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
14205 + clear_suspend_state(SUSPEND_CAN_RESUME);
14209 + resume_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
14210 + if (resume_blocksize & (SECTOR_SIZE - 1)) {
14212 + printk("SwapAllocator: Blocksizes are multiples"
14213 + "of %d!\n", SECTOR_SIZE);
14216 + resume_firstblock = resume_firstblock *
14217 + (resume_blocksize / SECTOR_SIZE);
14220 + temp_result = try_to_parse_resume_device(devstart, quiet);
14225 + *at_symbol = '@';
14230 + diskpage.address = get_zeroed_page(GFP_ATOMIC);
14231 + if (!diskpage.address) {
14232 + printk(KERN_ERR "Suspend2: SwapAllocator: Failed to allocate "
14233 + "a diskpage for I/O.\n");
14237 + temp_result = suspend_bio_ops.bdev_page_io(READ,
14238 + resume_block_device,
14239 + resume_firstblock,
14240 + virt_to_page(diskpage.ptr));
14242 + suspend_bio_ops.finish_all_io();
14244 + if (temp_result) {
14245 + printk(KERN_ERR "Suspend2: SwapAllocator: Failed to submit "
14250 + signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14252 + if (signature_found != -1) {
14254 + printk("Suspend2: SwapAllocator: Signature found.\n");
14257 + suspend_bio_ops.set_devinfo(devinfo);
14258 + suspend_writer_posn.chains = &block_chain[0];
14259 + suspend_writer_posn.num_chains = MAX_SWAPFILES;
14260 + set_suspend_state(SUSPEND_CAN_SUSPEND);
14261 + set_suspend_state(SUSPEND_CAN_RESUME);
14264 + printk(KERN_ERR "Suspend2: SwapAllocator: No swap "
14265 + "signature found at specified location.\n");
14267 + free_page((unsigned long) diskpage.address);
14272 +static int header_locations_read_sysfs(const char *page, int count)
14274 + int i, printedpartitionsmessage = 0, len = 0, haveswap = 0;
14275 + struct inode *swapf = 0;
14277 + char *path_page = (char *) __get_free_page(GFP_KERNEL);
14278 + char *path, *output = (char *) page;
14284 + for (i = 0; i < MAX_SWAPFILES; i++) {
14285 + struct swap_info_struct *si = get_swap_info_struct(i);
14287 + if (!si->swap_file)
14290 + if (S_ISBLK(si->swap_file->f_mapping->host->i_mode)) {
14292 + if (!printedpartitionsmessage) {
14293 + len += sprintf(output + len,
14294 + "For swap partitions, simply use the "
14295 + "format: resume2=swap:/dev/hda1.\n");
14296 + printedpartitionsmessage = 1;
14301 + path = d_path(si->swap_file->f_dentry,
14302 + si->swap_file->f_vfsmnt,
14305 + path_len = snprintf(path_page, 31, "%s", path);
14308 + swapf = si->swap_file->f_mapping->host;
14309 + if (!(zone = bmap(swapf,0))) {
14310 + len+= sprintf(output + len,
14311 + "Swapfile %s has been corrupted. Reuse"
14312 + " mkswap on it and try again.\n",
14315 + char name_buffer[255];
14316 + len+= sprintf(output + len, "For swapfile `%s`,"
14317 + " use resume2=swap:/dev/%s:0x%x.\n",
14319 + bdevname(si->bdev, name_buffer),
14320 + zone << (swapf->i_blkbits - 9));
14327 + len = sprintf(output, "You need to turn on swap partitions "
14328 + "before examining this file.\n");
14330 + free_page((unsigned long) path_page);
14334 +static struct suspend_sysfs_data sysfs_params[] = {
14336 + SUSPEND2_ATTR("swapfilename", SYSFS_RW),
14337 + SYSFS_STRING(swapfilename, 255, 0)
14341 + SUSPEND2_ATTR("headerlocations", SYSFS_READONLY),
14342 + SYSFS_CUSTOM(header_locations_read_sysfs, NULL, 0)
14345 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
14346 + SYSFS_INT(&suspend_swapops.enabled, 0, 1, 0),
14347 + .write_side_effect = attempt_to_parse_resume_device2,
14351 +static struct suspend_module_ops suspend_swapops = {
14352 + .type = WRITER_MODULE,
14353 + .name = "Swap Allocator",
14354 + .directory = "swap",
14355 + .module = THIS_MODULE,
14356 + .memory_needed = suspend_swap_memory_needed,
14357 + .print_debug_info = suspend_swap_print_debug_stats,
14358 + .storage_needed = suspend_swap_storage_needed,
14359 + .initialise = suspend_swap_initialise,
14360 + .cleanup = suspend_swap_cleanup,
14362 + .noresume_reset = suspend_swap_noresume_reset,
14363 + .storage_available = suspend_swap_storage_available,
14364 + .storage_allocated = suspend_swap_storage_allocated,
14365 + .release_storage = suspend_swap_release_storage,
14366 + .allocate_header_space = suspend_swap_allocate_header_space,
14367 + .allocate_storage = suspend_swap_allocate_storage,
14368 + .image_exists = suspend_swap_image_exists,
14369 + .mark_resume_attempted = suspend_swap_mark_resume_attempted,
14370 + .write_header_init = suspend_swap_write_header_init,
14371 + .write_header_cleanup = suspend_swap_write_header_cleanup,
14372 + .read_header_init = suspend_swap_read_header_init,
14373 + .read_header_cleanup = suspend_swap_read_header_cleanup,
14374 + .invalidate_image = suspend_swap_invalidate_image,
14375 + .parse_sig_location = suspend_swap_parse_sig_location,
14377 + .sysfs_data = sysfs_params,
14378 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
14381 +/* ---- Registration ---- */
14382 +static __init int suspend_swap_load(void)
14384 + suspend_swapops.rw_init = suspend_bio_ops.rw_init;
14385 + suspend_swapops.rw_cleanup = suspend_bio_ops.rw_cleanup;
14386 + suspend_swapops.read_chunk = suspend_bio_ops.read_chunk;
14387 + suspend_swapops.write_chunk = suspend_bio_ops.write_chunk;
14388 + suspend_swapops.rw_header_chunk = suspend_bio_ops.rw_header_chunk;
14390 + return suspend_register_module(&suspend_swapops);
14394 +static __exit void suspend_swap_unload(void)
14396 + suspend_unregister_module(&suspend_swapops);
14399 +module_init(suspend_swap_load);
14400 +module_exit(suspend_swap_unload);
14401 +MODULE_LICENSE("GPL");
14402 +MODULE_AUTHOR("Nigel Cunningham");
14403 +MODULE_DESCRIPTION("Suspend2 SwapAllocator");
14405 +late_initcall(suspend_swap_load);
14407 diff -ruN linux-2.6.22/kernel/power/suspend_userui.c suspend2-2.2.10-for-2.6.22/kernel/power/suspend_userui.c
14408 --- linux-2.6.22/kernel/power/suspend_userui.c 1970-01-01 10:00:00.000000000 +1000
14409 +++ suspend2-2.2.10-for-2.6.22/kernel/power/suspend_userui.c 2007-07-11 22:25:42.000000000 +1000
14412 + * kernel/power/user_ui.c
14414 + * Copyright (C) 2005-2007 Bernard Blackham
14415 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
14417 + * This file is released under the GPLv2.
14419 + * Routines for Suspend2's user interface.
14421 + * The user interface code talks to a userspace program via a
14422 + * netlink socket.
14424 + * The kernel side:
14425 + * - starts the userui program;
14426 + * - sends text messages and progress bar status;
14428 + * The user space side:
14429 + * - passes messages regarding user requests (abort, toggle reboot etc)
14433 +#define __KERNEL_SYSCALLS__
14435 +#include <linux/suspend.h>
14436 +#include <linux/freezer.h>
14437 +#include <linux/console.h>
14438 +#include <linux/ctype.h>
14439 +#include <linux/tty.h>
14440 +#include <linux/vt_kern.h>
14441 +#include <linux/module.h>
14442 +#include <linux/reboot.h>
14443 +#include <linux/kmod.h>
14444 +#include <linux/security.h>
14445 +#include <linux/syscalls.h>
14447 +#include "sysfs.h"
14448 +#include "modules.h"
14449 +#include "suspend.h"
14451 +#include "netlink.h"
14452 +#include "power_off.h"
14454 +static char local_printf_buf[1024]; /* Same as printk - should be safe */
14456 +static struct user_helper_data ui_helper_data;
14457 +static struct suspend_module_ops userui_ops;
14458 +static int orig_kmsg;
14460 +static char lastheader[512];
14461 +static int lastheader_message_len;
14462 +static int ui_helper_changed; /* Used at resume-time so don't overwrite value
14463 + set from initrd/ramfs. */
14465 +/* Number of distinct progress amounts that userspace can display */
14466 +static int progress_granularity = 30;
14468 +DECLARE_WAIT_QUEUE_HEAD(userui_wait_for_key);
14470 +static void ui_nl_set_state(int n)
14472 + /* Only let them change certain settings */
14473 + static const int suspend_action_mask =
14474 + (1 << SUSPEND_REBOOT) | (1 << SUSPEND_PAUSE) | (1 << SUSPEND_SLOW) |
14475 + (1 << SUSPEND_LOGALL) | (1 << SUSPEND_SINGLESTEP) |
14476 + (1 << SUSPEND_PAUSE_NEAR_PAGESET_END);
14478 + suspend_action = (suspend_action & (~suspend_action_mask)) |
14479 + (n & suspend_action_mask);
14481 + if (!test_action_state(SUSPEND_PAUSE) &&
14482 + !test_action_state(SUSPEND_SINGLESTEP))
14483 + wake_up_interruptible(&userui_wait_for_key);
14486 +static void userui_post_atomic_restore(void)
14488 + suspend_send_netlink_message(&ui_helper_data,
14489 + USERUI_MSG_POST_ATOMIC_RESTORE, NULL, 0);
14492 +static int userui_storage_needed(void)
14494 + return sizeof(ui_helper_data.program) + 1 + sizeof(int);
14497 +static int userui_save_config_info(char *buf)
14499 + *((int *) buf) = progress_granularity;
14500 + memcpy(buf + sizeof(int), ui_helper_data.program, sizeof(ui_helper_data.program));
14501 + return sizeof(ui_helper_data.program) + sizeof(int) + 1;
14504 +static void userui_load_config_info(char *buf, int size)
14506 + progress_granularity = *((int *) buf);
14507 + size -= sizeof(int);
14509 + /* Don't load the saved path if one has already been set */
14510 + if (ui_helper_changed)
14513 + if (size > sizeof(ui_helper_data.program))
14514 + size = sizeof(ui_helper_data.program);
14516 + memcpy(ui_helper_data.program, buf + sizeof(int), size);
14517 + ui_helper_data.program[sizeof(ui_helper_data.program)-1] = '\0';
14520 +static void set_ui_program_set(void)
14522 + ui_helper_changed = 1;
14525 +static int userui_memory_needed(void)
14527 + /* ball park figure of 128 pages */
14528 + return (128 * PAGE_SIZE);
14531 +/* suspend_update_status
14533 + * Description: Update the progress bar and (if on) in-bar message.
14534 + * Arguments: UL value, maximum: Current progress percentage (value/max).
14535 + * const char *fmt, ...: Message to be displayed in the middle
14536 + * of the progress bar.
14537 + * Note that a NULL message does not mean that any previous
14538 + * message is erased! For that, you need suspend_prepare_status with
14540 + * Returns: Unsigned long: The next value where status needs to be updated.
14541 + * This is to reduce unnecessary calls to update_status.
14543 +static unsigned long userui_update_status(unsigned long value,
14544 + unsigned long maximum, const char *fmt, ...)
14546 + static int last_step = -1;
14547 + struct userui_msg_params msg;
14550 + unsigned long next_update;
14552 + if (ui_helper_data.pid == -1)
14555 + if ((!maximum) || (!progress_granularity))
14561 + if (value > maximum)
14564 + /* Try to avoid math problems - we can't do 64 bit math here
14565 + * (and shouldn't need it - anyone got screen resolution
14566 + * of 65536 pixels or more?) */
14567 + bitshift = fls(maximum) - 16;
14568 + if (bitshift > 0) {
14569 + unsigned long temp_maximum = maximum >> bitshift;
14570 + unsigned long temp_value = value >> bitshift;
14571 + this_step = (int)
14572 + (temp_value * progress_granularity / temp_maximum);
14573 + next_update = (((this_step + 1) * temp_maximum /
14574 + progress_granularity) + 1) << bitshift;
14576 + this_step = (int) (value * progress_granularity / maximum);
14577 + next_update = ((this_step + 1) * maximum /
14578 + progress_granularity) + 1;
14581 + if (this_step == last_step)
14582 + return next_update;
14584 + memset(&msg, 0, sizeof(msg));
14586 + msg.a = this_step;
14587 + msg.b = progress_granularity;
14591 + va_start(args, fmt);
14592 + vsnprintf(msg.text, sizeof(msg.text), fmt, args);
14594 + msg.text[sizeof(msg.text)-1] = '\0';
14597 + suspend_send_netlink_message(&ui_helper_data, USERUI_MSG_PROGRESS,
14598 + &msg, sizeof(msg));
14599 + last_step = this_step;
14601 + return next_update;
14604 +/* userui_message.
14606 + * Description: This function is intended to do the same job as printk, but
14607 + * without normally logging what is printed. The point is to be
14608 + * able to get debugging info on screen without filling the logs
14609 + * with "1/534. ^M 2/534^M. 3/534^M"
14611 + * It may be called from an interrupt context - can't sleep!
14613 + * Arguments: int mask: The debugging section(s) this message belongs to.
14614 + * int level: The level of verbosity of this message.
14615 + * int restartline: Whether to output a \r or \n with this line
14616 + * (\n if we're logging all output).
14617 + * const char *fmt, ...: Message to be displayed a la printk.
14619 +static void userui_message(unsigned long section, unsigned long level,
14620 + int normally_logged, const char *fmt, ...)
14622 + struct userui_msg_params msg;
14624 + if ((level) && (level > console_loglevel))
14627 + memset(&msg, 0, sizeof(msg));
14631 + msg.c = normally_logged;
14635 + va_start(args, fmt);
14636 + vsnprintf(msg.text, sizeof(msg.text), fmt, args);
14638 + msg.text[sizeof(msg.text)-1] = '\0';
14641 + if (test_action_state(SUSPEND_LOGALL))
14642 + printk("%s\n", msg.text);
14644 + suspend_send_netlink_message(&ui_helper_data, USERUI_MSG_MESSAGE,
14645 + &msg, sizeof(msg));
14648 +static void wait_for_key_via_userui(void)
14650 + DECLARE_WAITQUEUE(wait, current);
14652 + add_wait_queue(&userui_wait_for_key, &wait);
14653 + set_current_state(TASK_INTERRUPTIBLE);
14655 + interruptible_sleep_on(&userui_wait_for_key);
14657 + set_current_state(TASK_RUNNING);
14658 + remove_wait_queue(&userui_wait_for_key, &wait);
14661 +static char userui_wait_for_keypress(int timeout)
14665 + struct termios t, t_backup;
14667 + if (ui_helper_data.pid != -1) {
14668 + wait_for_key_via_userui();
14673 + /* We should be guaranteed /dev/console exists after populate_rootfs() in
14676 + if ((fd = sys_open("/dev/console", O_RDONLY, 0)) < 0) {
14677 + printk("Couldn't open /dev/console.\n");
14681 + if (sys_ioctl(fd, TCGETS, (long)&t) < 0)
14684 + memcpy(&t_backup, &t, sizeof(t));
14686 + t.c_lflag &= ~(ISIG|ICANON|ECHO);
14687 + t.c_cc[VMIN] = 0;
14689 + t.c_cc[VTIME] = timeout*10;
14691 + if (sys_ioctl(fd, TCSETS, (long)&t) < 0)
14692 + goto out_restore;
14695 + if (sys_read(fd, &key, 1) <= 0) {
14699 + key = tolower(key);
14700 + if (test_suspend_state(SUSPEND_SANITY_CHECK_PROMPT)) {
14701 + if (key == 'c') {
14702 + set_suspend_state(SUSPEND_CONTINUE_REQ);
14704 + } else if (key == ' ')
14711 + sys_ioctl(fd, TCSETS, (long)&t_backup);
14718 +/* suspend_prepare_status
14719 + * Description: Prepare the 'nice display', drawing the header and version,
14720 + * along with the current action and perhaps also resetting the
14723 + * int clearbar: Whether to reset the progress bar.
14724 + * const char *fmt, ...: The action to be displayed.
14726 +static void userui_prepare_status(int clearbar, const char *fmt, ...)
14731 + va_start(args, fmt);
14732 + lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
14737 + suspend_update_status(0, 1, NULL);
14739 + suspend_message(0, SUSPEND_STATUS, 1, lastheader, NULL);
14741 + if (ui_helper_data.pid == -1)
14742 + printk(KERN_EMERG "%s\n", lastheader);
14747 + * Description: Begin to abort a cycle. If this wasn't at the user's request
14748 + * (and we're displaying output), tell the user why and wait for
14749 + * them to acknowledge the message.
14750 + * Arguments: A parameterised string (imagine this is printk) to display,
14751 + * telling the user why we're aborting.
14754 +static void userui_abort_suspend(int result_code, const char *fmt, ...)
14757 + int printed_len = 0;
14759 + set_result_state(result_code);
14760 + if (!test_result_state(SUSPEND_ABORTED)) {
14761 + if (!test_result_state(SUSPEND_ABORT_REQUESTED)) {
14762 + va_start(args, fmt);
14763 + printed_len = vsnprintf(local_printf_buf,
14764 + sizeof(local_printf_buf), fmt, args);
14766 + if (ui_helper_data.pid != -1)
14767 + printed_len = sprintf(local_printf_buf + printed_len,
14768 + " (Press SPACE to continue)");
14769 + suspend_prepare_status(CLEAR_BAR, local_printf_buf);
14771 + if (ui_helper_data.pid != -1)
14772 + suspend_wait_for_keypress(0);
14774 + /* Turn on aborting flag */
14775 + set_result_state(SUSPEND_ABORTED);
14779 +/* request_abort_suspend
14781 + * Description: Handle the user requesting the cancellation of a suspend by
14782 + * pressing escape.
14783 + * Callers: Invoked from a netlink packet from userspace when the user presses
14786 +static void request_abort_suspend(void)
14788 + if (test_result_state(SUSPEND_ABORT_REQUESTED))
14791 + if (test_suspend_state(SUSPEND_NOW_RESUMING)) {
14792 + suspend_prepare_status(CLEAR_BAR, "Escape pressed. "
14793 + "Powering down again.");
14794 + set_suspend_state(SUSPEND_STOP_RESUME);
14795 + while (!test_suspend_state(SUSPEND_IO_STOPPED))
14797 + if (suspendActiveAllocator->mark_resume_attempted)
14798 + suspendActiveAllocator->mark_resume_attempted(0);
14799 + suspend2_power_down();
14801 + suspend_prepare_status(CLEAR_BAR, "--- ESCAPE PRESSED :"
14802 + " ABORTING SUSPEND ---");
14803 + set_result_state(SUSPEND_ABORTED);
14804 + set_result_state(SUSPEND_ABORT_REQUESTED);
14806 + wake_up_interruptible(&userui_wait_for_key);
14810 +static int userui_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
14815 + type = nlh->nlmsg_type;
14817 + /* A control message: ignore them */
14818 + if (type < NETLINK_MSG_BASE)
14821 + /* Unknown message: reply with EINVAL */
14822 + if (type >= USERUI_MSG_MAX)
14825 + /* All operations require privileges, even GET */
14826 + if (security_netlink_recv(skb, CAP_NET_ADMIN))
14829 + /* Only allow one task to receive NOFREEZE privileges */
14830 + if (type == NETLINK_MSG_NOFREEZE_ME && ui_helper_data.pid != -1) {
14831 + printk("Got NOFREEZE_ME request when ui_helper_data.pid is %d.\n", ui_helper_data.pid);
14835 + data = (int*)NLMSG_DATA(nlh);
14838 + case USERUI_MSG_ABORT:
14839 + request_abort_suspend();
14841 + case USERUI_MSG_GET_STATE:
14842 + suspend_send_netlink_message(&ui_helper_data,
14843 + USERUI_MSG_GET_STATE, &suspend_action,
14844 + sizeof(suspend_action));
14846 + case USERUI_MSG_GET_DEBUG_STATE:
14847 + suspend_send_netlink_message(&ui_helper_data,
14848 + USERUI_MSG_GET_DEBUG_STATE,
14849 + &suspend_debug_state,
14850 + sizeof(suspend_debug_state));
14852 + case USERUI_MSG_SET_STATE:
14853 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14855 + ui_nl_set_state(*data);
14857 + case USERUI_MSG_SET_DEBUG_STATE:
14858 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14860 + suspend_debug_state = (*data);
14862 + case USERUI_MSG_SPACE:
14863 + wake_up_interruptible(&userui_wait_for_key);
14865 + case USERUI_MSG_GET_POWERDOWN_METHOD:
14866 + suspend_send_netlink_message(&ui_helper_data,
14867 + USERUI_MSG_GET_POWERDOWN_METHOD,
14868 + &suspend2_poweroff_method,
14869 + sizeof(suspend2_poweroff_method));
14871 + case USERUI_MSG_SET_POWERDOWN_METHOD:
14872 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14874 + suspend2_poweroff_method = (*data);
14876 + case USERUI_MSG_GET_LOGLEVEL:
14877 + suspend_send_netlink_message(&ui_helper_data,
14878 + USERUI_MSG_GET_LOGLEVEL,
14879 + &suspend_default_console_level,
14880 + sizeof(suspend_default_console_level));
14882 + case USERUI_MSG_SET_LOGLEVEL:
14883 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14885 + suspend_default_console_level = (*data);
14892 +/* userui_cond_pause
14894 + * Description: Potentially pause and wait for the user to tell us to continue.
14895 + * We normally only pause when @pause is set.
14896 + * Arguments: int pause: Whether we normally pause.
14897 + * char *message: The message to display. Not parameterised
14898 + * because it's normally a constant.
14901 +static void userui_cond_pause(int pause, char *message)
14903 + int displayed_message = 0, last_key = 0;
14905 + while (last_key != 32 &&
14906 + ui_helper_data.pid != -1 &&
14907 + (!test_result_state(SUSPEND_ABORTED)) &&
14908 + ((test_action_state(SUSPEND_PAUSE) && pause) ||
14909 + (test_action_state(SUSPEND_SINGLESTEP)))) {
14910 + if (!displayed_message) {
14911 + suspend_prepare_status(DONT_CLEAR_BAR,
14912 + "%s Press SPACE to continue.%s",
14913 + message ? message : "",
14914 + (test_action_state(SUSPEND_SINGLESTEP)) ?
14915 + " Single step on." : "");
14916 + displayed_message = 1;
14918 + last_key = suspend_wait_for_keypress(0);
14923 +/* userui_prepare_console
14925 + * Description: Prepare a console for use, save current settings.
14926 + * Returns: Boolean: Whether an error occured. Errors aren't
14927 + * treated as fatal, but a warning is printed.
14929 +static void userui_prepare_console(void)
14931 + orig_kmsg = kmsg_redirect;
14932 + kmsg_redirect = fg_console + 1;
14934 + ui_helper_data.pid = -1;
14936 + if (!userui_ops.enabled)
14939 + if (!*ui_helper_data.program) {
14940 + printk("suspend_userui: program not configured. suspend_userui disabled.\n");
14944 + suspend_netlink_setup(&ui_helper_data);
14949 +/* userui_cleanup_console
14951 + * Description: Restore the settings we saved above.
14954 +static void userui_cleanup_console(void)
14956 + if (ui_helper_data.pid > -1)
14957 + suspend_netlink_close(&ui_helper_data);
14959 + kmsg_redirect = orig_kmsg;
14963 + * User interface specific /sys/power/suspend2 entries.
14966 +static struct suspend_sysfs_data sysfs_params[] = {
14967 +#if defined(CONFIG_NET) && defined(CONFIG_SYSFS)
14968 + { SUSPEND2_ATTR("enable_escape", SYSFS_RW),
14969 + SYSFS_BIT(&suspend_action, SUSPEND_CAN_CANCEL, 0)
14972 + { SUSPEND2_ATTR("pause_between_steps", SYSFS_RW),
14973 + SYSFS_BIT(&suspend_action, SUSPEND_PAUSE, 0)
14976 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
14977 + SYSFS_INT(&userui_ops.enabled, 0, 1, 0)
14980 + { SUSPEND2_ATTR("progress_granularity", SYSFS_RW),
14981 + SYSFS_INT(&progress_granularity, 1, 2048, 0)
14984 + { SUSPEND2_ATTR("program", SYSFS_RW),
14985 + SYSFS_STRING(ui_helper_data.program, 255, 0),
14986 + .write_side_effect = set_ui_program_set,
14991 +static struct suspend_module_ops userui_ops = {
14992 + .type = MISC_MODULE,
14993 + .name = "Userspace UI",
14994 + .shared_directory = "Basic User Interface",
14995 + .module = THIS_MODULE,
14996 + .storage_needed = userui_storage_needed,
14997 + .save_config_info = userui_save_config_info,
14998 + .load_config_info = userui_load_config_info,
14999 + .memory_needed = userui_memory_needed,
15000 + .sysfs_data = sysfs_params,
15001 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
15004 +static struct ui_ops my_ui_ops = {
15005 + .post_atomic_restore = userui_post_atomic_restore,
15006 + .update_status = userui_update_status,
15007 + .message = userui_message,
15008 + .prepare_status = userui_prepare_status,
15009 + .abort = userui_abort_suspend,
15010 + .cond_pause = userui_cond_pause,
15011 + .prepare = userui_prepare_console,
15012 + .cleanup = userui_cleanup_console,
15013 + .wait_for_key = userui_wait_for_keypress,
15016 +/* suspend_console_sysfs_init
15017 + * Description: Boot time initialisation for user interface.
15020 +static __init int s2_user_ui_init(void)
15024 + ui_helper_data.nl = NULL;
15025 + ui_helper_data.program[0] = '\0';
15026 + ui_helper_data.pid = -1;
15027 + ui_helper_data.skb_size = sizeof(struct userui_msg_params);
15028 + ui_helper_data.pool_limit = 6;
15029 + ui_helper_data.netlink_id = NETLINK_SUSPEND2_USERUI;
15030 + ui_helper_data.name = "userspace ui";
15031 + ui_helper_data.rcv_msg = userui_user_rcv_msg;
15032 + ui_helper_data.interface_version = 7;
15033 + ui_helper_data.must_init = 0;
15034 + ui_helper_data.not_ready = userui_cleanup_console;
15035 + init_completion(&ui_helper_data.wait_for_process);
15036 + result = suspend_register_module(&userui_ops);
15038 + result = s2_register_ui_ops(&my_ui_ops);
15040 + suspend_unregister_module(&userui_ops);
15046 +static __exit void s2_user_ui_exit(void)
15048 + s2_remove_ui_ops(&my_ui_ops);
15049 + suspend_unregister_module(&userui_ops);
15052 +module_init(s2_user_ui_init);
15053 +module_exit(s2_user_ui_exit);
15054 +MODULE_AUTHOR("Nigel Cunningham");
15055 +MODULE_DESCRIPTION("Suspend2 Userui Support");
15056 +MODULE_LICENSE("GPL");
15058 +late_initcall(s2_user_ui_init);
15060 diff -ruN linux-2.6.22/kernel/power/sysfs.c suspend2-2.2.10-for-2.6.22/kernel/power/sysfs.c
15061 --- linux-2.6.22/kernel/power/sysfs.c 1970-01-01 10:00:00.000000000 +1000
15062 +++ suspend2-2.2.10-for-2.6.22/kernel/power/sysfs.c 2007-07-11 22:25:42.000000000 +1000
15065 + * kernel/power/sysfs.c
15067 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
15069 + * This file is released under the GPLv2.
15071 + * This file contains support for sysfs entries for tuning Suspend2.
15073 + * We have a generic handler that deals with the most common cases, and
15074 + * hooks for special handlers to use.
15077 +#include <linux/suspend.h>
15078 +#include <linux/module.h>
15079 +#include <asm/uaccess.h>
15081 +#include "sysfs.h"
15082 +#include "suspend.h"
15083 +#include "storage.h"
15085 +static int suspend_sysfs_initialised = 0;
15087 +static void suspend_initialise_sysfs(void);
15089 +static struct suspend_sysfs_data sysfs_params[];
15091 +#define to_sysfs_data(_attr) container_of(_attr, struct suspend_sysfs_data, attr)
15093 +static void suspend2_main_wrapper(void)
15095 + _suspend2_try_suspend(0);
15098 +static ssize_t suspend2_attr_show(struct kobject *kobj, struct attribute *attr,
15101 + struct suspend_sysfs_data *sysfs_data = to_sysfs_data(attr);
15104 + if (suspend_start_anything(0))
15107 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_READ)
15108 + suspend_prepare_usm();
15110 + switch (sysfs_data->type) {
15111 + case SUSPEND_SYSFS_DATA_CUSTOM:
15112 + len = (sysfs_data->data.special.read_sysfs) ?
15113 + (sysfs_data->data.special.read_sysfs)(page, PAGE_SIZE)
15116 + case SUSPEND_SYSFS_DATA_BIT:
15117 + len = sprintf(page, "%d\n",
15118 + -test_bit(sysfs_data->data.bit.bit,
15119 + sysfs_data->data.bit.bit_vector));
15121 + case SUSPEND_SYSFS_DATA_INTEGER:
15122 + len = sprintf(page, "%d\n",
15123 + *(sysfs_data->data.integer.variable));
15125 + case SUSPEND_SYSFS_DATA_LONG:
15126 + len = sprintf(page, "%ld\n",
15127 + *(sysfs_data->data.a_long.variable));
15129 + case SUSPEND_SYSFS_DATA_UL:
15130 + len = sprintf(page, "%lu\n",
15131 + *(sysfs_data->data.ul.variable));
15133 + case SUSPEND_SYSFS_DATA_STRING:
15134 + len = sprintf(page, "%s\n",
15135 + sysfs_data->data.string.variable);
15138 + /* Side effect routine? */
15139 + if (sysfs_data->read_side_effect)
15140 + sysfs_data->read_side_effect();
15142 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_READ)
15143 + suspend_cleanup_usm();
15145 + suspend_finish_anything(0);
15150 +#define BOUND(_variable, _type) \
15151 + if (*_variable < sysfs_data->data._type.minimum) \
15152 + *_variable = sysfs_data->data._type.minimum; \
15153 + else if (*_variable > sysfs_data->data._type.maximum) \
15154 + *_variable = sysfs_data->data._type.maximum;
15156 +static ssize_t suspend2_attr_store(struct kobject *kobj, struct attribute *attr,
15157 + const char *my_buf, size_t count)
15159 + int assigned_temp_buffer = 0, result = count;
15160 + struct suspend_sysfs_data *sysfs_data = to_sysfs_data(attr);
15162 + if (suspend_start_anything((sysfs_data->flags & SYSFS_SUSPEND_OR_RESUME)))
15165 + ((char *) my_buf)[count] = 0;
15167 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_WRITE)
15168 + suspend_prepare_usm();
15170 + switch (sysfs_data->type) {
15171 + case SUSPEND_SYSFS_DATA_CUSTOM:
15172 + if (sysfs_data->data.special.write_sysfs)
15173 + result = (sysfs_data->data.special.write_sysfs)
15176 + case SUSPEND_SYSFS_DATA_BIT:
15178 + int value = simple_strtoul(my_buf, NULL, 0);
15180 + set_bit(sysfs_data->data.bit.bit,
15181 + (sysfs_data->data.bit.bit_vector));
15183 + clear_bit(sysfs_data->data.bit.bit,
15184 + (sysfs_data->data.bit.bit_vector));
15187 + case SUSPEND_SYSFS_DATA_INTEGER:
15189 + int *variable = sysfs_data->data.integer.variable;
15190 + *variable = simple_strtol(my_buf, NULL, 0);
15191 + BOUND(variable, integer);
15194 + case SUSPEND_SYSFS_DATA_LONG:
15196 + long *variable = sysfs_data->data.a_long.variable;
15197 + *variable = simple_strtol(my_buf, NULL, 0);
15198 + BOUND(variable, a_long);
15201 + case SUSPEND_SYSFS_DATA_UL:
15203 + unsigned long *variable = sysfs_data->data.ul.variable;
15204 + *variable = simple_strtoul(my_buf, NULL, 0);
15205 + BOUND(variable, ul);
15209 + case SUSPEND_SYSFS_DATA_STRING:
15211 + int copy_len = count;
15213 + sysfs_data->data.string.variable;
15215 + if (sysfs_data->data.string.max_length &&
15216 + (copy_len > sysfs_data->data.string.max_length))
15217 + copy_len = sysfs_data->data.string.max_length;
15220 + sysfs_data->data.string.variable =
15221 + variable = (char *) get_zeroed_page(GFP_ATOMIC);
15222 + assigned_temp_buffer = 1;
15224 + strncpy(variable, my_buf, copy_len);
15225 + if ((copy_len) &&
15226 + (my_buf[copy_len - 1] == '\n'))
15227 + variable[count - 1] = 0;
15228 + variable[count] = 0;
15233 + /* Side effect routine? */
15234 + if (sysfs_data->write_side_effect)
15235 + sysfs_data->write_side_effect();
15237 + /* Free temporary buffers */
15238 + if (assigned_temp_buffer) {
15239 + free_page((unsigned long) sysfs_data->data.string.variable);
15240 + sysfs_data->data.string.variable = NULL;
15243 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_WRITE)
15244 + suspend_cleanup_usm();
15246 + suspend_finish_anything(sysfs_data->flags & SYSFS_SUSPEND_OR_RESUME);
15251 +static struct sysfs_ops suspend2_sysfs_ops = {
15252 + .show = &suspend2_attr_show,
15253 + .store = &suspend2_attr_store,
15256 +static struct kobj_type suspend2_ktype = {
15257 + .sysfs_ops = &suspend2_sysfs_ops,
15260 +decl_subsys(suspend2, &suspend2_ktype, NULL);
15262 +/* Non-module sysfs entries.
15264 + * This array contains entries that are automatically registered at
15265 + * boot. Modules and the console code register their own entries separately.
15267 + * NB: If you move do_suspend, change suspend_write_sysfs's test so that
15268 + * suspend_start_anything still gets a 1 when the user echos > do_suspend!
15271 +static struct suspend_sysfs_data sysfs_params[] = {
15272 + { SUSPEND2_ATTR("do_suspend", SYSFS_WRITEONLY),
15273 + SYSFS_CUSTOM(NULL, NULL, SYSFS_SUSPENDING),
15274 + .write_side_effect = suspend2_main_wrapper
15277 + { SUSPEND2_ATTR("do_resume", SYSFS_WRITEONLY),
15278 + SYSFS_CUSTOM(NULL, NULL, SYSFS_RESUMING),
15279 + .write_side_effect = __suspend2_try_resume
15284 +void remove_suspend2_sysdir(struct kobject *kobj)
15289 + kobject_unregister(kobj);
15294 +struct kobject *make_suspend2_sysdir(char *name)
15296 + struct kobject *kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
15300 + printk("Suspend2: Can't allocate kobject for sysfs dir!\n");
15304 + err = kobject_set_name(kobj, "%s", name);
15311 + kobj->kset = &suspend2_subsys;
15313 + err = kobject_register(kobj);
15318 + return err ? NULL : kobj;
15321 +/* suspend_register_sysfs_file
15323 + * Helper for registering a new /sysfs/suspend2 entry.
15326 +int suspend_register_sysfs_file(
15327 + struct kobject *kobj,
15328 + struct suspend_sysfs_data *suspend_sysfs_data)
15332 + if (!suspend_sysfs_initialised)
15333 + suspend_initialise_sysfs();
15335 + if ((result = sysfs_create_file(kobj, &suspend_sysfs_data->attr)))
15336 + printk("Suspend2: sysfs_create_file for %s returned %d.\n",
15337 + suspend_sysfs_data->attr.name, result);
15342 +/* suspend_unregister_sysfs_file
15344 + * Helper for removing unwanted /sys/power/suspend2 entries.
15347 +void suspend_unregister_sysfs_file(struct kobject *kobj,
15348 + struct suspend_sysfs_data *suspend_sysfs_data)
15350 + sysfs_remove_file(kobj, &suspend_sysfs_data->attr);
15353 +void suspend_cleanup_sysfs(void)
15356 + numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
15358 + if (!suspend_sysfs_initialised)
15361 + for (i=0; i< numfiles; i++)
15362 + suspend_unregister_sysfs_file(&suspend2_subsys.kobj,
15363 + &sysfs_params[i]);
15365 + kobj_set_kset_s(&suspend2_subsys, power_subsys);
15366 + subsystem_unregister(&suspend2_subsys);
15368 + suspend_sysfs_initialised = 0;
15371 +/* suspend_initialise_sysfs
15373 + * Initialise the /sysfs/suspend2 directory.
15376 +static void suspend_initialise_sysfs(void)
15379 + int numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
15381 + if (suspend_sysfs_initialised)
15384 + /* Make our suspend2 directory a child of /sys/power */
15385 + kobj_set_kset_s(&suspend2_subsys, power_subsys);
15386 + error = subsystem_register(&suspend2_subsys);
15391 + /* Make it use the .store and .show routines above */
15392 + kobj_set_kset_s(&suspend2_subsys, suspend2_subsys);
15394 + suspend_sysfs_initialised = 1;
15396 + for (i=0; i< numfiles; i++)
15397 + suspend_register_sysfs_file(&suspend2_subsys.kobj,
15398 + &sysfs_params[i]);
15401 +int s2_sysfs_init(void)
15403 + suspend_initialise_sysfs();
15407 +void s2_sysfs_exit(void)
15409 + suspend_cleanup_sysfs();
15411 diff -ruN linux-2.6.22/kernel/power/sysfs.h suspend2-2.2.10-for-2.6.22/kernel/power/sysfs.h
15412 --- linux-2.6.22/kernel/power/sysfs.h 1970-01-01 10:00:00.000000000 +1000
15413 +++ suspend2-2.2.10-for-2.6.22/kernel/power/sysfs.h 2007-07-11 22:25:42.000000000 +1000
15416 + * kernel/power/sysfs.h
15418 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
15420 + * This file is released under the GPLv2.
15422 + * It provides declarations for suspend to use in managing
15423 + * /sysfs/suspend2. When we switch to kobjects,
15424 + * this will become redundant.
15428 +#include <linux/sysfs.h>
15429 +#include "power.h"
15431 +struct suspend_sysfs_data {
15432 + struct attribute attr;
15437 + unsigned long *bit_vector;
15451 + unsigned long *variable;
15452 + unsigned long minimum;
15453 + unsigned long maximum;
15460 + int (*read_sysfs) (const char *buffer, int count);
15461 + int (*write_sysfs) (const char *buffer, int count);
15466 + /* Side effects routines. Used, eg, for reparsing the
15467 + * resume2 entry when it changes */
15468 + void (*read_side_effect) (void);
15469 + void (*write_side_effect) (void);
15470 + struct list_head sysfs_data_list;
15474 + SUSPEND_SYSFS_DATA_NONE = 1,
15475 + SUSPEND_SYSFS_DATA_CUSTOM,
15476 + SUSPEND_SYSFS_DATA_BIT,
15477 + SUSPEND_SYSFS_DATA_INTEGER,
15478 + SUSPEND_SYSFS_DATA_UL,
15479 + SUSPEND_SYSFS_DATA_LONG,
15480 + SUSPEND_SYSFS_DATA_STRING
15483 +#define SUSPEND2_ATTR(_name, _mode) \
15484 + .attr = {.name = _name , .mode = _mode }
15486 +#define SYSFS_BIT(_ul, _bit, _flags) \
15487 + .type = SUSPEND_SYSFS_DATA_BIT, \
15488 + .flags = _flags, \
15489 + .data = { .bit = { .bit_vector = _ul, .bit = _bit } }
15491 +#define SYSFS_INT(_int, _min, _max, _flags) \
15492 + .type = SUSPEND_SYSFS_DATA_INTEGER, \
15493 + .flags = _flags, \
15494 + .data = { .integer = { .variable = _int, .minimum = _min, \
15495 + .maximum = _max } }
15497 +#define SYSFS_UL(_ul, _min, _max, _flags) \
15498 + .type = SUSPEND_SYSFS_DATA_UL, \
15499 + .flags = _flags, \
15500 + .data = { .ul = { .variable = _ul, .minimum = _min, \
15501 + .maximum = _max } }
15503 +#define SYSFS_LONG(_long, _min, _max, _flags) \
15504 + .type = SUSPEND_SYSFS_DATA_LONG, \
15505 + .flags = _flags, \
15506 + .data = { .a_long = { .variable = _long, .minimum = _min, \
15507 + .maximum = _max } }
15509 +#define SYSFS_STRING(_string, _max_len, _flags) \
15510 + .type = SUSPEND_SYSFS_DATA_STRING, \
15511 + .flags = _flags, \
15512 + .data = { .string = { .variable = _string, .max_length = _max_len } }
15514 +#define SYSFS_CUSTOM(_read, _write, _flags) \
15515 + .type = SUSPEND_SYSFS_DATA_CUSTOM, \
15516 + .flags = _flags, \
15517 + .data = { .special = { .read_sysfs = _read, .write_sysfs = _write } }
15519 +#define SYSFS_WRITEONLY 0200
15520 +#define SYSFS_READONLY 0444
15521 +#define SYSFS_RW 0644
15524 +#define SYSFS_NEEDS_SM_FOR_READ 1
15525 +#define SYSFS_NEEDS_SM_FOR_WRITE 2
15526 +#define SYSFS_SUSPEND 4
15527 +#define SYSFS_RESUME 8
15528 +#define SYSFS_SUSPEND_OR_RESUME (SYSFS_SUSPEND | SYSFS_RESUME)
15529 +#define SYSFS_SUSPENDING (SYSFS_SUSPEND | SYSFS_NEEDS_SM_FOR_WRITE)
15530 +#define SYSFS_RESUMING (SYSFS_RESUME | SYSFS_NEEDS_SM_FOR_WRITE)
15531 +#define SYSFS_NEEDS_SM_FOR_BOTH \
15532 + (SYSFS_NEEDS_SM_FOR_READ | SYSFS_NEEDS_SM_FOR_WRITE)
15534 +int suspend_register_sysfs_file(struct kobject *kobj,
15535 + struct suspend_sysfs_data *suspend_sysfs_data);
15536 +void suspend_unregister_sysfs_file(struct kobject *kobj,
15537 + struct suspend_sysfs_data *suspend_sysfs_data);
15539 +extern struct kset suspend2_subsys;
15541 +struct kobject *make_suspend2_sysdir(char *name);
15542 +void remove_suspend2_sysdir(struct kobject *obj);
15543 +extern void suspend_cleanup_sysfs(void);
15545 +extern int s2_sysfs_init(void);
15546 +extern void s2_sysfs_exit(void);
15547 diff -ruN linux-2.6.22/kernel/power/ui.c suspend2-2.2.10-for-2.6.22/kernel/power/ui.c
15548 --- linux-2.6.22/kernel/power/ui.c 1970-01-01 10:00:00.000000000 +1000
15549 +++ suspend2-2.2.10-for-2.6.22/kernel/power/ui.c 2007-07-11 22:25:42.000000000 +1000
15552 + * kernel/power/ui.c
15554 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
15555 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
15556 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
15557 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
15559 + * This file is released under the GPLv2.
15561 + * Routines for Suspend2's user interface.
15563 + * The user interface code talks to a userspace program via a
15564 + * netlink socket.
15566 + * The kernel side:
15567 + * - starts the userui program;
15568 + * - sends text messages and progress bar status;
15570 + * The user space side:
15571 + * - passes messages regarding user requests (abort, toggle reboot etc)
15575 +#define __KERNEL_SYSCALLS__
15577 +#include <linux/suspend.h>
15578 +#include <linux/freezer.h>
15579 +#include <linux/console.h>
15580 +#include <linux/ctype.h>
15581 +#include <linux/tty.h>
15582 +#include <linux/vt_kern.h>
15583 +#include <linux/module.h>
15584 +#include <linux/reboot.h>
15585 +#include <linux/kmod.h>
15586 +#include <linux/security.h>
15587 +#include <linux/syscalls.h>
15589 +#include "sysfs.h"
15590 +#include "modules.h"
15591 +#include "suspend.h"
15593 +#include "netlink.h"
15594 +#include "power_off.h"
15596 +static char local_printf_buf[1024]; /* Same as printk - should be safe */
15597 +struct ui_ops *s2_current_ui;
15599 +/*! The console log level we default to. */
15600 +int suspend_default_console_level = 0;
15602 +/* suspend_early_boot_message()
15603 + * Description: Handle errors early in the process of booting.
15604 + * The user may press C to continue booting, perhaps
15605 + * invalidating the image, or space to reboot.
15606 + * This works from either the serial console or normally
15607 + * attached keyboard.
15609 + * Note that we come in here from init, while the kernel is
15610 + * locked. If we want to get events from the serial console,
15611 + * we need to temporarily unlock the kernel.
15613 + * suspend_early_boot_message may also be called post-boot.
15614 + * In this case, it simply printks the message and returns.
15616 + * Arguments: int Whether we are able to erase the image.
15617 + * int default_answer. What to do when we timeout. This
15618 + * will normally be continue, but the user might
15619 + * provide command line options (__setup) to override
15620 + * particular cases.
15621 + * Char *. Pointer to a string explaining why we're moaning.
15624 +#define say(message, a...) printk(KERN_EMERG message, ##a)
15625 +#define message_timeout 25 /* message_timeout * 10 must fit in 8 bits */
15627 +int suspend_early_boot_message(int message_detail, int default_answer, char *warning_reason, ...)
15629 + unsigned long orig_state = get_suspend_state(), continue_req = 0;
15630 + unsigned long orig_loglevel = console_loglevel;
15634 + if (warning_reason) {
15635 + va_start(args, warning_reason);
15636 + printed_len = vsnprintf(local_printf_buf,
15637 + sizeof(local_printf_buf),
15643 + if (!test_suspend_state(SUSPEND_BOOT_TIME)) {
15644 + printk("Suspend2: %s\n", local_printf_buf);
15645 + return default_answer;
15648 + /* We might be called directly from do_mounts_initrd if the
15649 + * user fails to set up their initrd properly. We need to
15650 + * enable the keyboard handler by setting the running flag */
15651 + set_suspend_state(SUSPEND_RUNNING);
15653 +#if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE)
15654 + console_loglevel = 7;
15656 + say("=== Suspend2 ===\n\n");
15657 + if (warning_reason) {
15658 + say("BIG FAT WARNING!! %s\n\n", local_printf_buf);
15659 + switch (message_detail) {
15661 + say("If you continue booting, note that any image WILL NOT BE REMOVED.\n");
15662 + say("Suspend is unable to do so because the appropriate modules aren't\n");
15663 + say("loaded. You should manually remove the image to avoid any\n");
15664 + say("possibility of corrupting your filesystem(s) later.\n");
15667 + say("If you want to use the current suspend image, reboot and try\n");
15668 + say("again with the same kernel that you suspended from. If you want\n");
15669 + say("to forget that image, continue and the image will be erased.\n");
15672 + say("Press SPACE to reboot or C to continue booting with this kernel\n\n");
15673 + say("Default action if you don't select one in %d seconds is: %s.\n",
15675 + default_answer == SUSPEND_CONTINUE_REQ ?
15676 + "continue booting" : "reboot");
15678 + say("BIG FAT WARNING!!\n\n");
15679 + say("You have tried to resume from this image before.\n");
15680 + say("If it failed once, it may well fail again.\n");
15681 + say("Would you like to remove the image and boot normally?\n");
15682 + say("This will be equivalent to entering noresume2 on the\n");
15683 + say("kernel command line.\n\n");
15684 + say("Press SPACE to remove the image or C to continue resuming.\n\n");
15685 + say("Default action if you don't select one in %d seconds is: %s.\n",
15687 + !!default_answer ?
15688 + "continue resuming" : "remove the image");
15690 + console_loglevel = orig_loglevel;
15692 + set_suspend_state(SUSPEND_SANITY_CHECK_PROMPT);
15693 + clear_suspend_state(SUSPEND_CONTINUE_REQ);
15695 + if (suspend_wait_for_keypress(message_timeout) == 0) /* We timed out */
15696 + continue_req = !!default_answer;
15698 + continue_req = test_suspend_state(SUSPEND_CONTINUE_REQ);
15700 + if ((warning_reason) && (!continue_req))
15701 + machine_restart(NULL);
15703 + restore_suspend_state(orig_state);
15704 + if (continue_req)
15705 + set_suspend_state(SUSPEND_CONTINUE_REQ);
15707 +#endif /* CONFIG_VT or CONFIG_SERIAL_CONSOLE */
15713 + * User interface specific /sys/power/suspend2 entries.
15716 +static struct suspend_sysfs_data sysfs_params[] = {
15717 +#if defined(CONFIG_NET) && defined(CONFIG_SYSFS)
15718 + { SUSPEND2_ATTR("default_console_level", SYSFS_RW),
15719 + SYSFS_INT(&suspend_default_console_level, 0, 7, 0)
15722 + { SUSPEND2_ATTR("debug_sections", SYSFS_RW),
15723 + SYSFS_UL(&suspend_debug_state, 0, 1 << 30, 0)
15726 + { SUSPEND2_ATTR("log_everything", SYSFS_RW),
15727 + SYSFS_BIT(&suspend_action, SUSPEND_LOGALL, 0)
15730 + { SUSPEND2_ATTR("pm_prepare_console", SYSFS_RW),
15731 + SYSFS_BIT(&suspend_action, SUSPEND_PM_PREPARE_CONSOLE, 0)
15735 +static struct suspend_module_ops userui_ops = {
15736 + .type = MISC_MODULE,
15737 + .name = "Basic User Interface",
15738 + .directory = "user_interface",
15739 + .module = THIS_MODULE,
15740 + .sysfs_data = sysfs_params,
15741 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
15744 +int s2_register_ui_ops(struct ui_ops *this_ui)
15746 + if (s2_current_ui) {
15747 + printk("Only one Suspend2 user interface module can be loaded"
15752 + s2_current_ui = this_ui;
15757 +void s2_remove_ui_ops(struct ui_ops *this_ui)
15759 + if (s2_current_ui != this_ui)
15762 + s2_current_ui = NULL;
15765 +/* suspend_console_sysfs_init
15766 + * Description: Boot time initialisation for user interface.
15769 +int s2_ui_init(void)
15771 + return suspend_register_module(&userui_ops);
15774 +void s2_ui_exit(void)
15776 + suspend_unregister_module(&userui_ops);
15779 +#ifdef CONFIG_SUSPEND2_EXPORTS
15780 +EXPORT_SYMBOL_GPL(s2_current_ui);
15781 +EXPORT_SYMBOL_GPL(suspend_early_boot_message);
15782 +EXPORT_SYMBOL_GPL(s2_register_ui_ops);
15783 +EXPORT_SYMBOL_GPL(s2_remove_ui_ops);
15784 +EXPORT_SYMBOL_GPL(suspend_default_console_level);
15786 diff -ruN linux-2.6.22/kernel/power/ui.h suspend2-2.2.10-for-2.6.22/kernel/power/ui.h
15787 --- linux-2.6.22/kernel/power/ui.h 1970-01-01 10:00:00.000000000 +1000
15788 +++ suspend2-2.2.10-for-2.6.22/kernel/power/ui.h 2007-07-11 22:25:42.000000000 +1000
15791 + * kernel/power/ui.h
15793 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
15802 + /* Userspace -> Kernel */
15803 + USERUI_MSG_ABORT = 0x11,
15804 + USERUI_MSG_SET_STATE = 0x12,
15805 + USERUI_MSG_GET_STATE = 0x13,
15806 + USERUI_MSG_GET_DEBUG_STATE = 0x14,
15807 + USERUI_MSG_SET_DEBUG_STATE = 0x15,
15808 + USERUI_MSG_SPACE = 0x18,
15809 + USERUI_MSG_GET_POWERDOWN_METHOD = 0x1A,
15810 + USERUI_MSG_SET_POWERDOWN_METHOD = 0x1B,
15811 + USERUI_MSG_GET_LOGLEVEL = 0x1C,
15812 + USERUI_MSG_SET_LOGLEVEL = 0x1D,
15814 + /* Kernel -> Userspace */
15815 + USERUI_MSG_MESSAGE = 0x21,
15816 + USERUI_MSG_PROGRESS = 0x22,
15817 + USERUI_MSG_POST_ATOMIC_RESTORE = 0x25,
15822 +struct userui_msg_params {
15823 + unsigned long a, b, c, d;
15828 + char (*wait_for_key) (int timeout);
15829 + unsigned long (*update_status) (unsigned long value,
15830 + unsigned long maximum, const char *fmt, ...);
15831 + void (*prepare_status) (int clearbar, const char *fmt, ...);
15832 + void (*cond_pause) (int pause, char *message);
15833 + void (*abort)(int result_code, const char *fmt, ...);
15834 + void (*prepare)(void);
15835 + void (*cleanup)(void);
15836 + void (*post_atomic_restore)(void);
15837 + void (*message)(unsigned long section, unsigned long level,
15838 + int normally_logged, const char *fmt, ...);
15841 +extern struct ui_ops *s2_current_ui;
15843 +#define suspend_update_status(val, max, fmt, args...) \
15844 + (s2_current_ui ? (s2_current_ui->update_status) (val, max, fmt, ##args) : max)
15846 +#define suspend_wait_for_keypress(timeout) \
15847 + (s2_current_ui ? (s2_current_ui->wait_for_key) (timeout) : 0)
15849 +#define suspend_ui_post_atomic_restore(void) \
15850 + do { if (s2_current_ui) \
15851 + (s2_current_ui->post_atomic_restore)(); \
15854 +#define suspend_prepare_console(void) \
15855 + do { if (s2_current_ui) \
15856 + (s2_current_ui->prepare)(); \
15859 +#define suspend_cleanup_console(void) \
15860 + do { if (s2_current_ui) \
15861 + (s2_current_ui->cleanup)(); \
15864 +#define abort_suspend(result, fmt, args...) \
15865 + do { if (s2_current_ui) \
15866 + (s2_current_ui->abort)(result, fmt, ##args); \
15868 + set_result_state(SUSPEND_ABORTED); \
15869 + set_result_state(result); \
15873 +#define suspend_cond_pause(pause, message) \
15874 + do { if (s2_current_ui) \
15875 + (s2_current_ui->cond_pause)(pause, message); \
15878 +#define suspend_prepare_status(clear, fmt, args...) \
15879 + do { if (s2_current_ui) \
15880 + (s2_current_ui->prepare_status)(clear, fmt, ##args); \
15882 + printk(fmt, ##args); \
15885 +extern int suspend_default_console_level;
15887 +#define suspend_message(sn, lev, log, fmt, a...) \
15889 + if (s2_current_ui && (!sn || test_debug_state(sn))) \
15890 + s2_current_ui->message(sn, lev, log, fmt, ##a); \
15893 +__exit void suspend_ui_cleanup(void);
15894 +extern int s2_ui_init(void);
15895 +extern void s2_ui_exit(void);
15896 +extern int s2_register_ui_ops(struct ui_ops *this_ui);
15897 +extern void s2_remove_ui_ops(struct ui_ops *this_ui);
15898 diff -ruN linux-2.6.22/kernel/printk.c suspend2-2.2.10-for-2.6.22/kernel/printk.c
15899 --- linux-2.6.22/kernel/printk.c 2007-07-11 22:19:41.000000000 +1000
15900 +++ suspend2-2.2.10-for-2.6.22/kernel/printk.c 2007-07-11 22:25:42.000000000 +1000
15902 #include <linux/bootmem.h>
15903 #include <linux/syscalls.h>
15904 #include <linux/jiffies.h>
15905 +#include <linux/suspend.h>
15907 #include <asm/uaccess.h>
15910 * The indices into log_buf are not constrained to log_buf_len - they
15911 * must be masked before subscripting
15913 -static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */
15914 -static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */
15915 -static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */
15916 +static unsigned long POSS_NOSAVE log_start; /* Index into log_buf: next char to be read by syslog() */
15917 +static unsigned long POSS_NOSAVE con_start; /* Index into log_buf: next char to be sent to consoles */
15918 +static unsigned long POSS_NOSAVE log_end; /* Index into log_buf: most-recently-written-char + 1 */
15921 * Array of consoles built from command line options (console=)
15922 @@ -116,10 +117,10 @@
15924 #ifdef CONFIG_PRINTK
15926 -static char __log_buf[__LOG_BUF_LEN];
15927 -static char *log_buf = __log_buf;
15928 -static int log_buf_len = __LOG_BUF_LEN;
15929 -static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
15930 +static char POSS_NOSAVE __log_buf[__LOG_BUF_LEN];
15931 +static char POSS_NOSAVE *log_buf = __log_buf;
15932 +static int POSS_NOSAVE log_buf_len = __LOG_BUF_LEN;
15933 +static unsigned long POSS_NOSAVE logged_chars; /* Number of chars produced since last read+clear operation */
15935 static int __init log_buf_len_setup(char *str)
15937 @@ -738,12 +739,14 @@
15938 acquire_console_sem();
15939 console_suspended = 1;
15941 +EXPORT_SYMBOL(suspend_console);
15943 void resume_console(void)
15945 console_suspended = 0;
15946 release_console_sem();
15948 +EXPORT_SYMBOL(resume_console);
15949 #endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
15952 diff -ruN linux-2.6.22/kernel/timer.c suspend2-2.2.10-for-2.6.22/kernel/timer.c
15953 --- linux-2.6.22/kernel/timer.c 2007-07-11 22:19:41.000000000 +1000
15954 +++ suspend2-2.2.10-for-2.6.22/kernel/timer.c 2007-07-11 22:25:42.000000000 +1000
15955 @@ -843,6 +843,38 @@
15957 EXPORT_SYMBOL(avenrun);
15959 +static unsigned long avenrun_save[3];
15961 + * save_avenrun - Record the values prior to starting a hibernation cycle.
15962 + * We do this to make the work done in hibernation invisible to userspace
15963 + * post-suspend. Some programs, including some MTAs, watch the load average
15964 + * and stop work until it lowers. Without this, they would stop working for
15965 + * a while post-resume, unnecessarily.
15968 +void save_avenrun(void)
15970 + avenrun_save[0] = avenrun[0];
15971 + avenrun_save[1] = avenrun[1];
15972 + avenrun_save[2] = avenrun[2];
15975 +EXPORT_SYMBOL_GPL(save_avenrun);
15977 +void restore_avenrun(void)
15979 + if (!avenrun_save[0])
15982 + avenrun[0] = avenrun_save[0];
15983 + avenrun[1] = avenrun_save[1];
15984 + avenrun[2] = avenrun_save[2];
15986 + avenrun_save[0] = 0;
15989 +EXPORT_SYMBOL_GPL(restore_avenrun);
15992 * calc_load - given tick count, update the avenrun load estimates.
15993 * This is called while holding a write_lock on xtime_lock.
15994 diff -ruN linux-2.6.22/lib/Kconfig suspend2-2.2.10-for-2.6.22/lib/Kconfig
15995 --- linux-2.6.22/lib/Kconfig 2007-07-11 22:19:41.000000000 +1000
15996 +++ suspend2-2.2.10-for-2.6.22/lib/Kconfig 2007-07-11 22:25:42.000000000 +1000
15998 depends on AUDIT && !AUDIT_ARCH
16001 +config DYN_PAGEFLAGS
16005 # compression support is select'ed if needed
16007 diff -ruN linux-2.6.22/lib/Makefile suspend2-2.2.10-for-2.6.22/lib/Makefile
16008 --- linux-2.6.22/lib/Makefile 2007-07-11 22:19:41.000000000 +1000
16009 +++ suspend2-2.2.10-for-2.6.22/lib/Makefile 2007-07-11 22:25:42.000000000 +1000
16013 obj-$(CONFIG_BITREVERSE) += bitrev.o
16015 +obj-$(CONFIG_DYN_PAGEFLAGS) += dyn_pageflags.o
16017 obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
16018 obj-$(CONFIG_CRC16) += crc16.o
16019 obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o
16020 diff -ruN linux-2.6.22/lib/dyn_pageflags.c suspend2-2.2.10-for-2.6.22/lib/dyn_pageflags.c
16021 --- linux-2.6.22/lib/dyn_pageflags.c 1970-01-01 10:00:00.000000000 +1000
16022 +++ suspend2-2.2.10-for-2.6.22/lib/dyn_pageflags.c 2007-07-11 22:25:42.000000000 +1000
16025 + * lib/dyn_pageflags.c
16027 + * Copyright (C) 2004-2006 Nigel Cunningham <nigel@suspend2.net>
16029 + * This file is released under the GPLv2.
16031 + * Routines for dynamically allocating and releasing bitmaps
16032 + * used as pseudo-pageflags.
16035 +#include <linux/module.h>
16036 +#include <linux/dyn_pageflags.h>
16037 +#include <linux/bootmem.h>
16038 +#include <linux/mm.h>
16041 +#define PR_DEBUG(a, b...) do { printk(a, ##b); } while(0)
16043 +#define PR_DEBUG(a, b...) do { } while(0)
16046 +#define pages_for_zone(zone) \
16047 + (DIV_ROUND_UP((zone)->spanned_pages, (PAGE_SIZE << 3)))
16050 + * clear_dyn_pageflags(dyn_pageflags_t pagemap)
16052 + * Clear an array used to store local page flags.
16056 +void clear_dyn_pageflags(dyn_pageflags_t pagemap)
16058 + int i = 0, zone_idx, node_id = 0;
16059 + struct zone *zone;
16060 + struct pglist_data *pgdat;
16062 + BUG_ON(!pagemap);
16064 + for_each_online_pgdat(pgdat) {
16065 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
16066 + zone = &pgdat->node_zones[zone_idx];
16068 + if (!populated_zone(zone))
16071 + for (i = 0; i < pages_for_zone(zone); i++)
16072 + memset((pagemap[node_id][zone_idx][i]), 0,
16080 + * free_dyn_pageflags(dyn_pageflags_t pagemap)
16082 + * Free a dynamically allocated pageflags bitmap. For Suspend2 usage, we
16083 + * support data being relocated from slab to pages that don't conflict
16084 + * with the image that will be copied back. This is the reason for the
16085 + * PageSlab tests below.
16088 +void free_dyn_pageflags(dyn_pageflags_t *pagemap)
16090 + int i = 0, zone_pages, node_id = -1, zone_idx;
16091 + struct zone *zone;
16092 + struct pglist_data *pgdat;
16097 + PR_DEBUG("Seeking to free dyn_pageflags %p.\n", pagemap);
16099 + for_each_online_pgdat(pgdat) {
16102 + PR_DEBUG("Node id %d.\n", node_id);
16104 + if (!(*pagemap)[node_id]) {
16105 + PR_DEBUG("Node %d unallocated.\n", node_id);
16109 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
16110 + zone = &pgdat->node_zones[zone_idx];
16111 + if (!populated_zone(zone)) {
16112 + PR_DEBUG("Node %d zone %d unpopulated.\n", node_id, zone_idx);
16116 + if (!(*pagemap)[node_id][zone_idx]) {
16117 + PR_DEBUG("Node %d zone %d unallocated.\n", node_id, zone_idx);
16121 + PR_DEBUG("Node id %d. Zone %d.\n", node_id, zone_idx);
16123 + zone_pages = pages_for_zone(zone);
16125 + for (i = 0; i < zone_pages; i++) {
16126 + PR_DEBUG("Node id %d. Zone %d. Page %d.\n", node_id, zone_idx, i);
16127 + free_page((unsigned long)(*pagemap)[node_id][zone_idx][i]);
16130 + kfree((*pagemap)[node_id][zone_idx]);
16132 + PR_DEBUG("Free node %d (%p).\n", node_id, pagemap[node_id]);
16133 + kfree((*pagemap)[node_id]);
16136 + PR_DEBUG("Free map pgdat list at %p.\n", pagemap);
16140 + PR_DEBUG("Done.\n");
16144 +static int try_alloc_dyn_pageflag_part(int nr_ptrs, void **ptr)
16146 + *ptr = kzalloc(sizeof(void *) * nr_ptrs, GFP_ATOMIC);
16147 + PR_DEBUG("Got %p. Putting it in %p.\n", *ptr, ptr);
16152 + printk("Error. Unable to allocate memory for dynamic pageflags.");
16157 + * allocate_dyn_pageflags
16159 + * Allocate a bitmap for dynamic page flags.
16162 +int allocate_dyn_pageflags(dyn_pageflags_t *pagemap)
16164 + int i, zone_idx, zone_pages, node_id = 0;
16165 + struct zone *zone;
16166 + struct pglist_data *pgdat;
16169 + PR_DEBUG("Pagemap %p already allocated.\n", pagemap);
16173 + PR_DEBUG("Seeking to allocate dyn_pageflags %p.\n", pagemap);
16175 + for_each_online_pgdat(pgdat)
16178 + if (try_alloc_dyn_pageflag_part(node_id, (void **) pagemap))
16183 + for_each_online_pgdat(pgdat) {
16184 + PR_DEBUG("Node %d.\n", node_id);
16186 + if (try_alloc_dyn_pageflag_part(MAX_NR_ZONES,
16187 + (void **) &(*pagemap)[node_id]))
16190 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
16191 + PR_DEBUG("Zone %d of %d.\n", zone_idx, MAX_NR_ZONES);
16193 + zone = &pgdat->node_zones[zone_idx];
16195 + if (!populated_zone(zone)) {
16196 + PR_DEBUG("Node %d zone %d unpopulated - won't allocate.\n", node_id, zone_idx);
16200 + zone_pages = pages_for_zone(zone);
16202 + PR_DEBUG("Node %d zone %d (needs %d pages).\n", node_id, zone_idx, zone_pages);
16204 + if (try_alloc_dyn_pageflag_part(zone_pages,
16205 + (void **) &(*pagemap)[node_id][zone_idx]))
16208 + for (i = 0; i < zone_pages; i++) {
16209 + unsigned long address = get_zeroed_page(GFP_ATOMIC);
16211 + PR_DEBUG("Error. Unable to allocate memory for "
16212 + "dynamic pageflags.");
16213 + free_dyn_pageflags(pagemap);
16216 + PR_DEBUG("Node %d zone %d. Page %d.\n", node_id, zone_idx, i);
16217 + (*pagemap)[node_id][zone_idx][i] =
16218 + (unsigned long *) address;
16224 + PR_DEBUG("Done.\n");
16228 +#define GET_BIT_AND_UL(bitmap, page) \
16229 + struct zone *zone = page_zone(page); \
16230 + unsigned long zone_pfn = page_to_pfn(page) - zone->zone_start_pfn; \
16231 + int node = page_to_nid(page); \
16232 + int zone_num = zone_idx(zone); \
16233 + int pagenum = PAGENUMBER(zone_pfn); \
16234 + int page_offset = PAGEINDEX(zone_pfn); \
16235 + unsigned long *ul = ((*bitmap)[node][zone_num][pagenum]) + page_offset; \
16236 + int bit = PAGEBIT(zone_pfn);
16239 + * test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16241 + * Is the page flagged in the given bitmap?
16245 +int test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16247 + GET_BIT_AND_UL(bitmap, page);
16248 + return test_bit(bit, ul);
16252 + * set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16254 + * Set the flag for the page in the given bitmap.
16258 +void set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16260 + GET_BIT_AND_UL(bitmap, page);
16261 + set_bit(bit, ul);
16265 + * clear_dynpageflags(dyn_pageflags_t *bitmap, struct page *page)
16267 + * Clear the flag for the page in the given bitmap.
16271 +void clear_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16273 + GET_BIT_AND_UL(bitmap, page);
16274 + clear_bit(bit, ul);
16278 + * get_next_bit_on(dyn_pageflags_t bitmap, int counter)
16280 + * Given a pfn (possibly -1), find the next pfn in the bitmap that
16281 + * is set. If there are no more flags set, return -1.
16285 +unsigned long get_next_bit_on(dyn_pageflags_t bitmap, unsigned long counter)
16287 + struct page *page;
16288 + struct zone *zone;
16289 + unsigned long *ul = NULL;
16290 + unsigned long zone_offset;
16291 + int pagebit, zone_num, first = (counter == (max_pfn + 1)), node;
16294 + counter = first_online_pgdat()->node_zones->zone_start_pfn;
16296 + page = pfn_to_page(counter);
16297 + zone = page_zone(page);
16298 + node = zone->zone_pgdat->node_id;
16299 + zone_num = zone_idx(zone);
16300 + zone_offset = counter - zone->zone_start_pfn;
16308 + if (zone_offset >= zone->spanned_pages) {
16310 + zone = next_zone(zone);
16312 + return max_pfn + 1;
16313 + } while(!zone->spanned_pages);
16315 + zone_num = zone_idx(zone);
16316 + node = zone->zone_pgdat->node_id;
16320 + pagebit = PAGEBIT(zone_offset);
16322 + if (!pagebit || !ul)
16323 + ul = (bitmap[node][zone_num][PAGENUMBER(zone_offset)])
16324 + + PAGEINDEX(zone_offset);
16326 + if (!(*ul & ~((1 << pagebit) - 1))) {
16327 + zone_offset += BITS_PER_LONG - pagebit - 1;
16331 + } while(!test_bit(pagebit, ul));
16333 + return zone->zone_start_pfn + zone_offset;
16336 diff -ruN linux-2.6.22/lib/vsprintf.c suspend2-2.2.10-for-2.6.22/lib/vsprintf.c
16337 --- linux-2.6.22/lib/vsprintf.c 2007-07-11 22:19:42.000000000 +1000
16338 +++ suspend2-2.2.10-for-2.6.22/lib/vsprintf.c 2007-07-11 22:25:42.000000000 +1000
16339 @@ -236,6 +236,29 @@
16346 + * Functionality : Print a string with parameters to a buffer of a
16347 + * limited size. Unlike vsnprintf, we return the number
16348 + * of bytes actually put in the buffer, not the number
16349 + * that would have been put in if it was big enough.
16351 +int snprintf_used(char *buffer, int buffer_size, const char *fmt, ...)
16356 + if (!buffer_size)
16359 + va_start(args, fmt);
16360 + result = vsnprintf(buffer, buffer_size, fmt, args);
16363 + return result > buffer_size ? buffer_size : result;
16367 * vsnprintf - Format a string and place it in a buffer
16368 * @buf: The buffer to place the result into
16369 diff -ruN linux-2.6.22/mm/vmscan.c suspend2-2.2.10-for-2.6.22/mm/vmscan.c
16370 --- linux-2.6.22/mm/vmscan.c 2007-07-11 22:19:42.000000000 +1000
16371 +++ suspend2-2.2.10-for-2.6.22/mm/vmscan.c 2007-07-11 22:25:42.000000000 +1000
16372 @@ -650,6 +650,28 @@
16376 +/* return_lru_pages puts a list of pages back on a zone's lru lists. */
16378 +static void return_lru_pages(struct list_head *page_list, struct zone *zone,
16379 + struct pagevec *pvec)
16381 + while (!list_empty(page_list)) {
16382 + struct page *page = lru_to_page(page_list);
16383 + VM_BUG_ON(PageLRU(page));
16384 + SetPageLRU(page);
16385 + list_del(&page->lru);
16386 + if (PageActive(page))
16387 + add_page_to_active_list(zone, page);
16389 + add_page_to_inactive_list(zone, page);
16390 + if (!pagevec_add(pvec, page)) {
16391 + spin_unlock_irq(&zone->lru_lock);
16392 + __pagevec_release(pvec);
16393 + spin_lock_irq(&zone->lru_lock);
16399 * shrink_inactive_list() is a helper for shrink_zone(). It returns the number
16400 * of reclaimed pages
16401 @@ -667,7 +689,6 @@
16403 spin_lock_irq(&zone->lru_lock);
16405 - struct page *page;
16406 unsigned long nr_taken;
16407 unsigned long nr_scan;
16408 unsigned long nr_freed;
16409 @@ -697,21 +718,7 @@
16411 * Put back any unfreeable pages.
16413 - while (!list_empty(&page_list)) {
16414 - page = lru_to_page(&page_list);
16415 - VM_BUG_ON(PageLRU(page));
16416 - SetPageLRU(page);
16417 - list_del(&page->lru);
16418 - if (PageActive(page))
16419 - add_page_to_active_list(zone, page);
16421 - add_page_to_inactive_list(zone, page);
16422 - if (!pagevec_add(&pvec, page)) {
16423 - spin_unlock_irq(&zone->lru_lock);
16424 - __pagevec_release(&pvec);
16425 - spin_lock_irq(&zone->lru_lock);
16428 + return_lru_pages(&page_list, zone, &pvec);
16429 } while (nr_scanned < max_scan);
16430 spin_unlock(&zone->lru_lock);
16432 @@ -1272,6 +1279,72 @@
16433 return nr_reclaimed;
16437 + struct zone *zone;
16438 + struct list_head active_list;
16439 + struct list_head inactive_list;
16440 + struct lru_save *next;
16443 +struct lru_save *lru_save_list;
16445 +void unlink_lru_lists(void)
16447 + struct zone *zone;
16449 + for_each_zone(zone) {
16450 + struct lru_save *this;
16451 + unsigned long moved, scanned;
16453 + if (!zone->spanned_pages)
16456 + this = (struct lru_save *)
16457 + kzalloc(sizeof(struct lru_save), GFP_ATOMIC);
16461 + this->next = lru_save_list;
16462 + lru_save_list = this;
16464 + this->zone = zone;
16466 + spin_lock_irq(&zone->lru_lock);
16467 + INIT_LIST_HEAD(&this->active_list);
16468 + INIT_LIST_HEAD(&this->inactive_list);
16469 + moved = isolate_lru_pages(zone_page_state(zone, NR_ACTIVE),
16470 + &zone->active_list, &this->active_list,
16472 + __mod_zone_page_state(zone, NR_ACTIVE, -moved);
16473 + moved = isolate_lru_pages(zone_page_state(zone, NR_INACTIVE),
16474 + &zone->inactive_list, &this->inactive_list,
16476 + __mod_zone_page_state(zone, NR_INACTIVE, -moved);
16477 + spin_unlock_irq(&zone->lru_lock);
16481 +void relink_lru_lists(void)
16483 + while(lru_save_list) {
16484 + struct lru_save *this = lru_save_list;
16485 + struct zone *zone = this->zone;
16486 + struct pagevec pvec;
16488 + pagevec_init(&pvec, 1);
16490 + lru_save_list = this->next;
16492 + spin_lock_irq(&zone->lru_lock);
16493 + return_lru_pages(&this->active_list, zone, &pvec);
16494 + return_lru_pages(&this->inactive_list, zone, &pvec);
16495 + spin_unlock_irq(&zone->lru_lock);
16496 + pagevec_release(&pvec);
16503 * The background pageout daemon, started as a kernel thread
16504 * from the init process.
16505 @@ -1356,6 +1429,9 @@
16506 if (!populated_zone(zone))
16509 + if (freezer_is_on())
16512 pgdat = zone->zone_pgdat;
16513 if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0))
16515 @@ -1369,6 +1445,91 @@
16519 +void shrink_one_zone(struct zone *zone, int total_to_free)
16522 + unsigned long still_to_free = total_to_free;
16523 + struct scan_control sc = {
16524 + .gfp_mask = GFP_KERNEL,
16526 + .may_writepage = 1,
16527 + .swappiness = vm_swappiness,
16530 + if (!populated_zone(zone) || zone->all_unreclaimable)
16533 + if (still_to_free <= 0)
16536 + if (is_highmem(zone))
16537 + sc.gfp_mask |= __GFP_HIGHMEM;
16539 + for (prio = DEF_PRIORITY; prio >= 0; prio--) {
16540 + unsigned long to_free, just_freed, orig_size;
16541 + unsigned long old_nr_active;
16543 + to_free = min(zone_page_state(zone, NR_ACTIVE) +
16544 + zone_page_state(zone, NR_INACTIVE),
16547 + if (to_free <= 0)
16550 + sc.swap_cluster_max = to_free -
16551 + zone_page_state(zone, NR_INACTIVE);
16554 + old_nr_active = zone_page_state(zone, NR_ACTIVE);
16555 + zone->nr_scan_active = sc.swap_cluster_max - 1;
16556 + shrink_active_list(sc.swap_cluster_max, zone, &sc,
16558 + zone->nr_scan_active = 0;
16560 + sc.swap_cluster_max = to_free - zone_page_state(zone,
16563 + } while (sc.swap_cluster_max > 0 &&
16564 + zone_page_state(zone, NR_ACTIVE) > old_nr_active);
16566 + to_free = min(zone_page_state(zone, NR_ACTIVE) +
16567 + zone_page_state(zone, NR_INACTIVE),
16571 + orig_size = zone_page_state(zone, NR_ACTIVE) +
16572 + zone_page_state(zone, NR_INACTIVE);
16573 + zone->nr_scan_inactive = to_free;
16574 + sc.swap_cluster_max = to_free;
16575 + shrink_inactive_list(to_free, zone, &sc);
16576 + just_freed = (orig_size -
16577 + (zone_page_state(zone, NR_ACTIVE) +
16578 + zone_page_state(zone, NR_INACTIVE)));
16579 + zone->nr_scan_inactive = 0;
16580 + still_to_free -= just_freed;
16581 + to_free -= just_freed;
16582 + } while (just_freed > 0 && still_to_free > 0);
16585 + while (still_to_free > 0) {
16586 + unsigned long nr_slab = global_page_state(NR_SLAB_RECLAIMABLE);
16587 + struct reclaim_state reclaim_state;
16589 + if (nr_slab > still_to_free)
16590 + nr_slab = still_to_free;
16592 + reclaim_state.reclaimed_slab = 0;
16593 + shrink_slab(nr_slab, sc.gfp_mask, nr_slab);
16594 + if (!reclaim_state.reclaimed_slab)
16597 + still_to_free -= reclaim_state.reclaimed_slab;
16605 * Helper function for shrink_all_memory(). Tries to reclaim 'nr_pages' pages
16606 * from LRU lists system-wide, for given pass and priority, and returns the