]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-tuxonice.patch
- windows mobile 5 support
[packages/kernel.git] / kernel-tuxonice.patch
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
4 @@ -83,6 +83,7 @@
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.
12 @@ -1214,6 +1215,8 @@
13         noresume        [SWSUSP] Disables resume and restores original swap
14                         space.
15  
16 +       noresume2       [SUSPEND2] Disables resuming and restores original swap signature.
17
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 @@
22  
23         retain_initrd   [RAM] Keep initrd memory after extraction
24  
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.
29 +
30         rhash_entries=  [KNL,NET]
31                         Set number of hash buckets for route cache
32  
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
36 @@ -0,0 +1,473 @@
37 +               Software Suspend 2.2 Internal Documentation.
38 +                               Version 1
39 +
40 +1.  Introduction.
41 +
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.
47 +
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.
54 +
55 +2.  Overview of operation.
56 +
57 +    The basic sequence of operations is as follows:
58 +
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.
63 +       d. Write the image.
64 +       e. Power down.
65 +
66 +    There are a number of complicating factors which mean that things are
67 +    not as simple as the above would imply, however...
68 +
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.
73 +
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
77 +    below).
78 +
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).
84 +
85 +    o In 2.6, we choose to play nicely with the other suspend-to-disk
86 +    implementations.
87 +
88 +3.  Detailed description of internals.
89 +
90 +    a. Quiescing activity.
91 +
92 +    Safely quiescing the system is achieved using two methods.
93 +
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.
104 +
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).
111 +
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.
119 +
120 +    Quiescing the system is therefore done in three steps:
121 +       - Freeze userspace
122 +       - Freeze filesystems
123 +       - Freeze kernel threads
124 +
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.
128 +
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.
132 +
133 +    b. Ensure enough memory & storage are available.
134 +
135 +    We have a number of constraints to meet in order to be able to successfully
136 +    suspend and resume.
137 +
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.
142 +
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.
146 +   
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.
150 +
151 +    c. Allocate the required memory and storage space.
152 +
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.
159 +    
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.
167 +
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.
175 +
176 +    d. Write the image.
177 +
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
181 +    pagesets.
182 +
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
188 +    inconsistent.
189 +
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.
202 +
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
206 +    powering down.
207 +
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
213 +    small.
214 +
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
221 +    copying pageset1.
222 +
223 +    e. Power down.
224 +
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
231 +    resume.
232 +
233 +4.  Data Structures.
234 +
235 +    Suspend2 uses three main structures to store its metadata and configuration
236 +    information:
237 +
238 +    a) Pageflags bitmaps.
239 +
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.
246 +
247 +    The pageset1 bitmap is thus easily stored in the image header for use at
248 +    resume time.
249 +
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
258 +    by having bitmaps.
259 +
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
264 +    help here.
265 +
266 +    The data structure is: unsigned long ***.
267 +
268 +    b) Extents for block data.
269 +
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:
273 +
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.
278 +
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.
282 +
283 +    Variations in block size are taken account of in transforming this data
284 +    into the parameters for bio submission.
285 +
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
292 +    storage.
293 +
294 +    So extents are:
295 +
296 +    struct extent {
297 +      unsigned long minimum, maximum;
298 +      struct extent *next;
299 +    }
300 +
301 +    These are combined into chains of extents for a device:
302 +
303 +    struct extent_chain {
304 +      int size; /* size of the extent ie sum (max-min+1) */
305 +      int allocs, frees;
306 +      char *name;
307 +      struct extent *first, *last_touched;
308 +    };
309 +
310 +    For each bdev, we need to store a little more info:
311 +
312 +    struct suspend_bdev_info {
313 +       struct block_device *bdev;
314 +       dev_t dev_t;
315 +       int bmap_shift;
316 +       int blocks_per_page;
317 +    };
318 +
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.
324 +
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
328 +    values.
329 +
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.
333 +
334 +    The last elements in the picture are a means of recording how the storage
335 +    is being used.
336 +
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:
341 +
342 +    struct extent_iterate_state {
343 +      struct extent_chain *chains;
344 +      int num_chains;
345 +      int current_chain;
346 +      struct extent *current_extent;
347 +      unsigned long current_offset;
348 +    };
349 +
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.
353 +
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.
358 +
359 +    The image is divided into three parts:
360 +    - The header
361 +    - Pageset 1
362 +    - Pageset 2
363 +
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.
367 +
368 +    The second pageset (LRU) is stored first. It begins on the next page after
369 +    the end of the header.
370 +
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
374 +    aligned also.
375 +
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
378 +    way:
379 +
380 +    struct extent_iterate_saved_state {
381 +        int chain_num;
382 +        int extent_num;
383 +        unsigned long offset;
384 +    };
385 +
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.
392 +
393 +    c) Modules
394 +
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.
398 +
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.
404 +
405 +    In order to achieve this, Suspend2 was given a modular design.
406 +
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'.
411 +
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:
415 +
416 +               ---------------------------------
417 +               |          Suspend2 Core        |
418 +               ---------------------------------
419 +                               |
420 +                               |
421 +               ---------------------------------
422 +               |       Page transformer 1      |
423 +               ---------------------------------
424 +                               |
425 +                               |
426 +               ---------------------------------
427 +               |       Page transformer 2      |
428 +               ---------------------------------
429 +                               |
430 +                               |
431 +               ---------------------------------
432 +               |            Writer             |
433 +               ---------------------------------
434 +
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
439 +    its output.
440 +
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.
446 +
447 +    Part of definition of the structure of a module thus looks like this:
448 +
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);
453 +
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.
460 +
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:
463 +
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);
470 +
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;
476 +
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.
480 +
481 +    d) Sysfs data structures.
482 +
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.
487 +
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.
495 +
496 +    When combined with some simple macros, a new sysfs entry can then be defined
497 +    in just a couple of lines:
498 +
499 +    { SUSPEND2_ATTR("progress_granularity", SYSFS_RW),
500 +      SYSFS_INT(&progress_granularity, 1, 2048)
501 +    },
502 +
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.
506 +
507 +    Sysfs entries are registered under /sys/power/suspend2, and entries for
508 +    modules are located in a subdirectory named after the module.
509 +
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
513 @@ -0,0 +1,713 @@
514 +       --- Suspend2, version 2.2 ---
515 +
516 +1.  What is it?
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?
527 +
528 +1. What is it?
529 +
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.
540 +
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
549 +   further.
550 +
551 +2. Why would you want it?
552 +
553 +   Why wouldn't you want it?
554 +   
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.
558 +   
559 +3. What do you need to use it?
560 +
561 +   a. Kernel Support.
562 +
563 +   i) The Suspend2 patch.
564 +   
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.
570 +
571 +   Suspend2 patches are available from http://suspend2.net.
572 +
573 +   ii) Compression and encryption support.
574 +
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
578 +   your kernel.
579 +
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.
583 +
584 +   iii) Configuring other options.
585 +
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!
592 +
593 +   b. Storage.
594 +
595 +   i) Swap.
596 +
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.
605 +   
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).
612 +
613 +   ii) Normal files.
614 +
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
620 +   our purposes.
621 +
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.
625 +
626 +   Most people will only want to suspend to a local file. To achieve that, do
627 +   something along the lines of:
628 +
629 +   echo "Suspend2" > /suspend-file
630 +   dd if=/dev/zero bs=1M count=512 >> suspend-file
631 +
632 +   This will create a 512MB file called /suspend-file. To get Suspend2 to use
633 +   it:
634 +
635 +   echo /suspend-file > /sys/power/suspend2/filewriter/filewriter_target
636 +
637 +   Then
638 +
639 +   cat /sys/power/suspend2/resume2
640 +
641 +   Put the results of this into your bootloader's configuration (see also step
642 +   C, below:
643 +
644 +   ---EXAMPLE-ONLY-DON'T-COPY-AND-PASTE---
645 +   # cat /sys/power/suspend2/resume2
646 +   file:/dev/hda2:0x1e001
647 +   
648 +   In this example, we would edit the append= line of our lilo.conf|menu.lst
649 +   so that it included:
650 +
651 +   resume2=file:/dev/hda2:0x1e001
652 +   ---EXAMPLE-ONLY-DON'T-COPY-AND-PASTE---
653
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.
659 +
660 +   c. Bootloader configuration.
661 +   
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:
664 +
665 +   append="resume2=swap:/dev/hda1"
666 +
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
672 +   valid signature.
673 +
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 
677 +
678 +   cat /sys/power/suspend2/swapwriter/headerlocations
679 +
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:
683 +
684 +   For swap partitions like /dev/hda1, simply use resume2=/dev/hda1.
685 +   For swapfile `swapfile`, use resume2=swap:/dev/hda2:0x242d.
686 +
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.
691 +
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.
695 +
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.
699 +
700 +   d. The hibernate script.
701 +
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:
706 +
707 +   - Switching to a text console and back if X doesn't like the video card
708 +     status on resume.
709 +   - Un/reloading PCMCIA support since it doesn't play well with suspend.
710 +  
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
715 +   module.
716 +
717 +   Check out the latest script (available on suspend2.net).
718 +   
719 +4. Why not just use the version already in the kernel?
720 +
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
729 +         starting a cycle.
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.
740 +
741 +5. How do you use it?
742 +
743 +   A suspend cycle can be started directly by doing:
744 +
745 +       echo > /sys/power/suspend2/do_resume
746 +
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):
750 +
751 +       hibernate
752 +
753 +   See the hibernate script's man page for more details on the options it
754 +   takes.
755 +
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.
759 +   
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.
764 +
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
767 +   system.
768 +
769 +6. What do all those entries in /sys/power/suspend2 do?
770 +
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!).
778 +
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
783 +   computer!
784
785 +   - checksum/enabled
786 +
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.
794
795 +   - compression/algorithm
796 +
797 +   Set the cryptoapi algorithm used for compressing the image.
798 +
799 +   - compression/expected_compression
800 +
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.
806 +
807 +   - debug_info:
808 +  
809 +   This file returns information about your configuration that may be helpful
810 +   in diagnosing problems with suspending.
811 +
812 +   - do_resume:
813 +
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
818 +   return.
819 +
820 +   - do_suspend:
821 +
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.
825 +
826 +   - driver_model_beeping
827 +
828 +   Enable beeping when suspending and resuming the drivers. Might help with
829 +   determining where a problem in resuming occurs.
830 +
831 +   - */enabled
832 +
833 +   These option can be used to temporarily disable various parts of suspend.
834 +
835 +   - encryption/*
836 +
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
844 +   do_resume.
845 +
846 +   - extra_pages_allowance
847 +
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.
855 +
856 +   - filewriter/target:
857 +
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.
861 +
862 +   - freezer_test
863 +
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
866 +   issues.
867 +
868 +   - image_exists:
869 +
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.
875 +
876 +   - image_size_limit:
877 +
878 +   The maximum size of suspend image written to disk, measured in megabytes
879 +   (1024*1024).
880 +
881 +   - interface_version:
882 +
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 
886 +   added.
887 +
888 +   - last_result:
889 +
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.
893 +
894 +   - log_everything (CONFIG_PM_DEBUG):
895 +
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
899 +   'L'.
900 +
901 +   - pause_between_steps (CONFIG_PM_DEBUG):
902 +
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.
905 +
906 +   - powerdown_method:
907 +
908 +   Used to select a method by which Suspend2 should powerdown after writing the
909 +   image. Currently:
910 +
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.
915 +
916 +   Note that these options are highly dependant upon your hardware & software:
917 +
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.
939 +
940 +   - progressbar_granularity_limit:
941 +
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.
945 +
946 +   - reboot:
947 +
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
950 +   'R'.
951 +
952 +   - resume_commandline:
953 +
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.
961 +
962 +   - swapwriter/swapfilename:
963 +
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
968 +  
969 +   echo /dev/hda2 > /sys/power/suspend2/swapwriter/swapfile
970 +
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.
976 +
977 +   The value of this file is used by headerlocations along with any currently
978 +   activated swapfiles/partitions.
979 +
980 +   - swapwriter/headerlocations:
981 +
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.
985 +
986 +   - toggle_process_nofreeze
987 +
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).
992 +
993 +   - userui_program
994 +
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.
999 +
1000 +   - user_interface/debug_sections (CONFIG_PM_DEBUG):
1001 +
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.
1008 +
1009 +   - user_interface/default_console_level (CONFIG_PM_DEBUG):
1010 +
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:
1014 +
1015 +   0: Nice display.
1016 +   1: Nice display plus numerical progress.
1017 +   2: Errors only.
1018 +   3: Low level debugging info.
1019 +   4: Medium level debugging info.
1020 +   5: High level debugging info.
1021 +   6: Verbose debugging info.
1022 +
1023 +   - user_interface/enable_escape:
1024 +
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).
1033 +
1034 +   - version:
1035 +  
1036 +   The version of suspend you have compiled into the currently running kernel.
1037 +
1038 +7. How do you get support?
1039 +
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)
1043 +   and its users.
1044 +
1045 +   Resources availble include HowTos, FAQs and a Wiki, all available via
1046 +   suspend2.net.  You can find the mailing lists there.
1047 +
1048 +8. I think I've found a bug. What should I do?
1049 +
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.
1056 +
1057 +   If this information doesn't help, try running:
1058 +
1059 +   hibernate --bug-report
1060 +
1061 +   ..and sending the output to the users mailing list.
1062 +
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.
1068 +
1069 +9. When will XXX be supported?
1070 +
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.
1073 +
1074 +   Patches are welcome. Please send to the list.
1075 +
1076 +10. How does it work?
1077 +
1078 +   Suspend2 does its work in a number of steps.
1079 +
1080 +   a. Freezing system activity.
1081 +
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:
1098 +
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.
1102 +
1103 +   b. Eating memory.
1104 +
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
1112 +   its calculations.
1113 +
1114 +   c. Allocation of storage.
1115 +
1116 +   Next, Suspend2 allocates the storage that will be used to save
1117 +   the image.
1118 +
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.
1126 +
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).
1130 +
1131 +   d. Write the first part of the image.
1132 +
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.
1145 +
1146 +   The next step, then, is writing pageset 2.
1147 +
1148 +   e. Suspending drivers and storing processor context.
1149 +
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.
1153 +
1154 +   f. Atomic copy.
1155 +
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.
1161 +
1162 +   g. Save the atomic copy (pageset 1).
1163 +
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.
1167 +
1168 +   f. Save the suspend header.
1169 +
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.
1177 +
1178 +   g. Set the image header.
1179 +
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).
1183 +
1184 +   h. Power down.
1185 +
1186 +   Or reboot if we're debugging and the appropriate option is selected.
1187 +
1188 +   Whew!
1189 +
1190 +   Reloading the image.
1191 +   --------------------
1192 +
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!
1202 +
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.
1206 +
1207 +11. Who wrote Suspend2?
1208 +
1209 +   (Answer based on the writings of Florent Chabaud, credits in files and
1210 +   Nigel's limited knowledge; apologies to anyone missed out!)
1211 +
1212 +   The main developers of Suspend2 have been...
1213 +
1214 +   Gabor Kuti
1215 +   Pavel Machek
1216 +   Florent Chabaud
1217 +   Bernard Blackham
1218 +   Nigel Cunningham
1219 +
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/
1232  S:     Maintained
1233  
1234 +SUSPEND2
1235 +P:     Nigel Cunningham
1236 +M:     nigel@suspend2.net
1237 +L:     suspend2-devel@suspend2.net
1238 +W:     http://suspend2.net
1239 +S:     Maintained
1240 +
1241  SVGA HANDLING
1242  P:     Martin Mares
1243  M:     mj@ucw.cz
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
1247 @@ -25,6 +25,7 @@
1248  #include <linux/kprobes.h>
1249  #include <linux/uaccess.h>
1250  #include <linux/kdebug.h>
1251 +#include <linux/suspend.h>
1252  
1253  #include <asm/system.h>
1254  #include <asm/desc.h>
1255 @@ -34,6 +35,9 @@
1256  
1257  static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
1258  
1259 +int suspend2_faulted = 0;
1260 +EXPORT_SYMBOL(suspend2_faulted);
1261 +
1262  int register_page_fault_notifier(struct notifier_block *nb)
1263  {
1264         vmalloc_sync_all();
1265 @@ -311,6 +315,20 @@
1266  
1267         si_code = SEGV_MAPERR;
1268  
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.
1273 +        */
1274 +
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);
1280 +               return;
1281 +       }
1282 +
1283         /*
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
1289 @@ -432,7 +432,7 @@
1290         paravirt_pagetable_setup_done(pgd_base);
1291  }
1292  
1293 -#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
1294 +#if defined(CONFIG_SUSPEND_SHARED) || defined(CONFIG_ACPI_SLEEP)
1295  /*
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 @@
1299         unsigned long addr;
1300  
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);
1307 -               free_page(addr);
1308 -               totalram_pages++;
1309 +               //free_page(addr);
1310 +               //totalram_pages++;
1311         }
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);
1314  }
1315  
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 @@
1321          */
1322         __flush_tlb_all();
1323  }
1324 +EXPORT_SYMBOL(kernel_map_pages);
1325  #endif
1326  
1327 +int page_is_mapped(struct page *page)
1328 +{
1329 +       pte_t *kpte; 
1330 +       unsigned long address;
1331 +       struct page *kpte_page;
1332 +
1333 +       if(PageHighMem(page))
1334 +               return 0;
1335 +
1336 +       address = (unsigned long)page_address(page);
1337 +
1338 +       kpte = lookup_address(address);
1339 +       if (!kpte)
1340 +               return -EINVAL;
1341 +       kpte_page = virt_to_page(kpte);
1342 +
1343 +       return (pte_val(*kpte) & (__PAGE_KERNEL_EXEC | __PAGE_KERNEL)) ? 1:0;
1344 +}
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
1351 @@ -1,2 +1,2 @@
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
1358 @@ -36,9 +36,9 @@
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
1369  
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
1374 @@ -26,7 +26,7 @@
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
1386 @@ -146,7 +146,7 @@
1387  
1388  }
1389  
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);
1394  
1395 @@ -236,4 +236,4 @@
1396         unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
1397         return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
1398  }
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 @@
1405           
1406           You will most probably want this if using IPSec.
1407  
1408 +config CRYPTO_LZF
1409 +       tristate "LZF compression algorithm"
1410 +       default y
1411 +       select CRYPTO_ALGAPI
1412 +       help
1413 +         This is the LZF algorithm. It is especially useful for Suspend2,
1414 +         because it achieves good compression quickly.
1415 +
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
1422 @@ -48,5 +48,6 @@
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
1427  
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
1432 @@ -0,0 +1,325 @@
1433 +/* 
1434 + * Cryptoapi LZF compression module.
1435 + *
1436 + * Copyright (c) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
1437 + *
1438 + * based on the deflate.c file:
1439 + * 
1440 + * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
1441 + * 
1442 + * and upon the LZF compression module donated to the Suspend2 project with
1443 + * the following copyright:
1444 + *
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>
1450 + * 
1451 + * Redistribution and use in source and binary forms, with or without modifica-
1452 + * tion, are permitted provided that the following conditions are met:
1453 + * 
1454 + *   1.  Redistributions of source code must retain the above copyright notice,
1455 + *       this list of conditions and the following disclaimer.
1456 + * 
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.
1460 + * 
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.
1463 + * 
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.
1474 + *
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.
1484 + */
1485 +
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>
1494 +
1495 +struct lzf_ctx {
1496 +       void *hbuf;
1497 +       unsigned int bufofs;
1498 +};
1499 +
1500 +/*
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.
1507 + */
1508 +static const int hlog = 14;
1509 +
1510 +/*
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
1514 + * it works ;)
1515 + */
1516 +static inline u16 first(const u8 *p)
1517 +{
1518 +       return ((p[0]) << 8) + p[1];
1519 +}
1520 +
1521 +static inline u16 next(u8 v, const u8 *p)
1522 +{
1523 +       return ((v) << 8) + p[2];
1524 +}
1525 +
1526 +static inline u32 idx(unsigned int h)
1527 +{
1528 +       return (((h ^ (h << 5)) >> (3*8 - hlog)) + h*3) & ((1 << hlog) - 1);
1529 +}
1530 +
1531 +/*
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)
1536 + */
1537 +
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));
1541 +
1542 +/*
1543 + * compressed format
1544 + *
1545 + * 000LLLLL <L+1>    ; literal
1546 + * LLLOOOOO oooooooo ; backref L
1547 + * 111OOOOO LLLLLLLL oooooooo ; backref L+7
1548 + *
1549 + */
1550 +
1551 +static void lzf_compress_exit(struct crypto_tfm *tfm)
1552 +{
1553 +       struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1554 +
1555 +       if (!ctx->hbuf)
1556 +               return;
1557 +
1558 +       vfree(ctx->hbuf);
1559 +       ctx->hbuf = NULL;
1560 +}
1561 +
1562 +static int lzf_compress_init(struct crypto_tfm *tfm)
1563 +{
1564 +       struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1565 +
1566 +       /* Get LZF ready to go */
1567 +       ctx->hbuf = vmalloc_32((1 << hlog) * sizeof(char *));
1568 +       if (ctx->hbuf)
1569 +               return 0;
1570 +
1571 +       printk(KERN_WARNING "Failed to allocate %ld bytes for lzf workspace\n",
1572 +                       (long) ((1 << hlog) * sizeof(char *)));
1573 +       return -ENOMEM;
1574 +}
1575 +
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)
1578 +{
1579 +       struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1580 +       const u8 **htab = ctx->hbuf;
1581 +       const u8 **hslot;
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;
1586 +       const u8 *ref;
1587 +
1588 +       unsigned int hval = first(ip);
1589 +       unsigned long off;
1590 +       int lit = 0;
1591 +
1592 +       memset(htab, 0, sizeof(htab));
1593 +
1594 +       for (;;) {
1595 +               if (ip < in_end - 2) {
1596 +                       hval = next(hval, ip);
1597 +                       hslot = htab + idx(hval);
1598 +                       ref = *hslot;
1599 +                       *hslot = ip;
1600 +
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]
1604 +                           ) {
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;
1609 +
1610 +                               do
1611 +                                       len++;
1612 +                               while (len < maxlen && ref[len] == ip[len]);
1613 +
1614 +                               if (op + lit + 1 + 3 >= out_end) {
1615 +                                       *out_len = PAGE_SIZE;
1616 +                                       return 0;
1617 +                               }
1618 +
1619 +                               if (lit) {
1620 +                                       *op++ = lit - 1;
1621 +                                       lit = -lit;
1622 +                                       do
1623 +                                               *op++ = ip[lit];
1624 +                                       while (++lit);
1625 +                               }
1626 +
1627 +                               len -= 2;
1628 +                               ip++;
1629 +
1630 +                               if (len < 7) {
1631 +                                       *op++ = (off >> 8) + (len << 5);
1632 +                               } else {
1633 +                                       *op++ = (off >> 8) + (7 << 5);
1634 +                                       *op++ = len - 7;
1635 +                               }
1636 +
1637 +                               *op++ = off;
1638 +
1639 +                               ip += len;
1640 +                               hval = first(ip);
1641 +                               hval = next(hval, ip);
1642 +                               htab[idx(hval)] = ip;
1643 +                               ip++;
1644 +                               continue;
1645 +                       }
1646 +               } else if (ip == in_end)
1647 +                       break;
1648 +
1649 +               /* one more literal byte we must copy */
1650 +               lit++;
1651 +               ip++;
1652 +
1653 +               if (lit == max_lit) {
1654 +                       if (op + 1 + max_lit >= out_end) {
1655 +                               *out_len = PAGE_SIZE;
1656 +                               return 0;
1657 +                       }
1658 +
1659 +                       *op++ = max_lit - 1;
1660 +                       memcpy(op, ip - max_lit, max_lit);
1661 +                       op += max_lit;
1662 +                       lit = 0;
1663 +               }
1664 +       }
1665 +
1666 +       if (lit) {
1667 +               if (op + lit + 1 >= out_end) {
1668 +                       *out_len = PAGE_SIZE;
1669 +                       return 0;
1670 +               }
1671 +
1672 +               *op++ = lit - 1;
1673 +               lit = -lit;
1674 +               do
1675 +                       *op++ = ip[lit];
1676 +               while (++lit);
1677 +       }
1678 +
1679 +       *out_len = op - out_data;
1680 +       return 0;
1681 +}
1682 +
1683 +static int lzf_decompress(struct crypto_tfm *tfm, const u8 *src,
1684 +               unsigned int slen, u8 *dst, unsigned int *dlen)
1685 +{
1686 +       u8 const *ip = src;
1687 +       u8 *op = dst;
1688 +       u8 const *const in_end = ip + slen;
1689 +       u8 *const out_end = op + *dlen;
1690 +
1691 +       *dlen = PAGE_SIZE;
1692 +       do {
1693 +               unsigned int ctrl = *ip++;
1694 +
1695 +               if (ctrl < (1 << 5)) {  /* literal run */
1696 +                       ctrl++;
1697 +
1698 +                       if (op + ctrl > out_end)
1699 +                               return 0;
1700 +                       memcpy(op, ip, ctrl);
1701 +                       op += ctrl;
1702 +                       ip += ctrl;
1703 +               } else {        /* back reference */
1704 +
1705 +                       unsigned int len = ctrl >> 5;
1706 +
1707 +                       u8 *ref = op - ((ctrl & 0x1f) << 8) - 1;
1708 +
1709 +                       if (len == 7)
1710 +                               len += *ip++;
1711 +
1712 +                       ref -= *ip++;
1713 +                       len += 2;
1714 +
1715 +                       if (op + len > out_end || ref < (u8 *) dst)
1716 +                               return 0;
1717 +
1718 +                       do
1719 +                               *op++ = *ref++;
1720 +                       while (--len);
1721 +               }
1722 +       }
1723 +       while (op < out_end && ip < in_end);
1724 +
1725 +       *dlen = op - (u8 *) dst;
1726 +       return 0;
1727 +}
1728 +
1729 +static struct crypto_alg alg = {
1730 +       .cra_name = "lzf",
1731 +       .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
1732 +       .cra_ctxsize = 0,
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 } }
1740 +};
1741 +
1742 +static int __init init(void)
1743 +{
1744 +       return crypto_register_alg(&alg);
1745 +}
1746 +
1747 +static void __exit fini(void)
1748 +{
1749 +       crypto_unregister_alg(&alg);
1750 +}
1751 +
1752 +module_init(init);
1753 +module_exit(fini);
1754 +
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
1761 @@ -181,7 +181,7 @@
1762         .finish = acpi_pm_finish,
1763  };
1764  
1765 -#ifdef CONFIG_SOFTWARE_SUSPEND
1766 +#ifdef CONFIG_SUSPEND_SHARED
1767  static int acpi_hibernation_prepare(void)
1768  {
1769         return acpi_sleep_prepare(ACPI_STATE_S4);
1770 @@ -222,7 +222,7 @@
1771         .enter = acpi_hibernation_enter,
1772         .finish = acpi_hibernation_finish,
1773  };
1774 -#endif                         /* CONFIG_SOFTWARE_SUSPEND */
1775 +#endif                         /* CONFIG_SUSPEND_SHARED */
1776  
1777  /*
1778   * Toshiba fails to preserve interrupts over S1, reinitialization
1779 @@ -267,7 +267,7 @@
1780  
1781         pm_set_ops(&acpi_pm_ops);
1782  
1783 -#ifdef CONFIG_SOFTWARE_SUSPEND
1784 +#ifdef CONFIG_SUSPEND_SHARED
1785         if (sleep_states[ACPI_STATE_S4])
1786                 hibernation_set_ops(&acpi_hibernation_ops);
1787  #else
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
1791 @@ -58,7 +58,7 @@
1792                 goto Done;
1793         }
1794         state = simple_strtoul(str, NULL, 0);
1795 -#ifdef CONFIG_SOFTWARE_SUSPEND
1796 +#ifdef CONFIG_SUSPEND_SHARED
1797         if (state == 4) {
1798                 error = hibernate();
1799                 goto Done;
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
1803 @@ -27,6 +27,8 @@
1804  int (*platform_notify)(struct device * dev) = NULL;
1805  int (*platform_notify_remove)(struct device * dev) = NULL;
1806  
1807 +static int do_dump_stack;
1808 +
1809  /*
1810   * sysfs bindings for devices.
1811   */
1812 @@ -755,6 +757,18 @@
1813                                 class_intf->add_dev(dev, class_intf);
1814                 up(&dev->class->sem);
1815         }
1816 +
1817 +#ifdef CONFIG_PM
1818 +       if (!((dev->class && dev->class->resume) ||
1819 +             (dev->bus && (dev->bus->resume || dev->bus->resume_early))) &&
1820 +           !dev->pm_safe) {
1821 +               printk("Device driver %s lacks bus and class support for "
1822 +                               "being resumed.\n", kobject_name(&dev->kobj));
1823 +               if (do_dump_stack)
1824 +                       dump_stack();
1825 +       }
1826 +#endif
1827 +
1828   Done:
1829         kfree(class_name);
1830         put_device(dev);
1831 @@ -1103,6 +1117,7 @@
1832         dev->class = class;
1833         dev->parent = parent;
1834         dev->release = device_create_release;
1835 +       dev->pm_safe = 1;
1836  
1837         va_start(args, fmt);
1838         vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
1839 @@ -1311,3 +1326,11 @@
1840  }
1841  
1842  EXPORT_SYMBOL_GPL(device_move);
1843 +
1844 +static int __init pm_debug_dump_stack(char *str)
1845 +{
1846 +       do_dump_stack = 1;
1847 +       return 1;
1848 +}
1849 +
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
1854 @@ -42,7 +42,6 @@
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 @@
1866                         last_mark = next;
1867                 }
1868  
1869 +               while(freezer_is_on())
1870 +                       yield();
1871  
1872                 if (kthread_should_stop()) {
1873                         /*
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 @@
1878         if (error)
1879                 driver_unregister(&drv->driver);
1880  
1881 +       if (!drv->resume)
1882 +               printk("PCI driver %s lacks driver specific resume support.\n",
1883 +                               drv->name);
1884 +
1885         return error;
1886  }
1887  
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
1891 @@ -756,6 +756,9 @@
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);
1898         } else {
1899                 printk(KERN_ERR "%s: error %d registering interface "
1900                         "       driver %s\n",
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
1904 @@ -36,4 +36,6 @@
1905  void mark_rodata_ro(void);
1906  #endif
1907  
1908 +extern int page_is_mapped(struct page *page);
1909 +
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
1914 @@ -8,6 +8,9 @@
1915  
1916  static inline int arch_prepare_suspend(void) { return 0; }
1917  
1918 +extern int suspend2_faulted;
1919 +#define clear_suspend2_fault() do { suspend2_faulted = 0; } while(0)
1920 +
1921  /* image of the saved processor state */
1922  struct saved_context {
1923         u16 es, fs, gs, ss;
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
1927 @@ -10,3 +10,6 @@
1928  static inline void restore_processor_state(void)
1929  {
1930  }
1931 +
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
1937 @@ -32,4 +32,9 @@
1938  void mark_rodata_ro(void);
1939  #endif
1940  
1941 +static inline int page_is_mapped(struct page *page)
1942 +{
1943 +       return 1;
1944 +}
1945 +
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
1950 @@ -12,6 +12,9 @@
1951         return 0;
1952  }
1953  
1954 +#define suspend2_faulted (0)
1955 +#define clear_suspend2_fault() do { } while(0)
1956 +
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
1963 @@ -418,6 +418,7 @@
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
1974 @@ -0,0 +1,68 @@
1975 +/*
1976 + * include/linux/dyn_pageflags.h
1977 + *
1978 + * Copyright (C) 2004-2006 Nigel Cunningham <nigel@suspend2.net>
1979 + *
1980 + * This file is released under the GPLv2.
1981 + *
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.
1985 + */
1986 +
1987 +#ifndef DYN_PAGEFLAGS_H
1988 +#define DYN_PAGEFLAGS_H
1989 +
1990 +#include <linux/mm.h>
1991 +
1992 +/* [pg_dat][zone][page_num] */
1993 +typedef unsigned long **** dyn_pageflags_t;
1994 +
1995 +#if BITS_PER_LONG == 32
1996 +#define UL_SHIFT 5
1997 +#else 
1998 +#if BITS_PER_LONG == 64
1999 +#define UL_SHIFT 6
2000 +#else
2001 +#error Bits per long not 32 or 64?
2002 +#endif
2003 +#endif
2004 +
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))
2008 +
2009 +/*
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.
2013 + */
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))
2018 +
2019 +#define PAGE_UL_PTR(bitmap, node, zone_num, zone_pfn) \
2020 +       ((bitmap[node][zone_num][PAGENUMBER(zone_pfn)])+PAGEINDEX(zone_pfn))
2021 +
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))
2025 +
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);
2030 +
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);
2034 +#endif
2035 +
2036 +/* 
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))
2041 + */
2042 +
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
2046 @@ -1,4 +1,6 @@
2047  /* Freezer declarations */
2048 +#ifndef LINUX_FREEZER_H
2049 +#define LINUX_FREEZER_H
2050  
2051  #include <linux/sched.h>
2052  
2053 @@ -115,6 +117,18 @@
2054         return !!(p->flags & PF_FREEZER_SKIP);
2055  }
2056  
2057 +extern int freezer_state;
2058 +#define FREEZER_OFF 0
2059 +#define FREEZER_USERSPACE_FROZEN 1
2060 +#define FREEZER_FULLY_ON 2
2061 +
2062 +static inline int freezer_is_on(void)
2063 +{
2064 +       return (freezer_state == FREEZER_FULLY_ON);
2065 +}
2066 +
2067 +extern void thaw_kernel_threads(void);
2068 +
2069  #else
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) {}
2074  
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) { }
2078  
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; }
2082  #endif
2083 +#endif
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
2087 @@ -124,6 +124,8 @@
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
2099 @@ -24,6 +24,8 @@
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 */
2105  
2106  #define MAX_LINKS 32           
2107  
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
2111 @@ -50,7 +50,7 @@
2112         void (*finish)(void);
2113  };
2114  
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)
2120 @@ -85,4 +85,81 @@
2121  void __save_processor_state(struct saved_context *ctxt);
2122  void __restore_processor_state(struct saved_context *ctxt);
2123  
2124 +enum {
2125 +       SUSPEND_CAN_SUSPEND,
2126 +       SUSPEND_CAN_RESUME,
2127 +       SUSPEND_RUNNING,
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,
2143 +};
2144 +
2145 +#ifdef CONFIG_SUSPEND2
2146 +
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;
2153 +
2154 +#else /* !CONFIG_SUSPEND2 */
2155 +
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 */
2162 +
2163 +#ifdef CONFIG_SUSPEND_SHARED
2164 +#ifdef CONFIG_SUSPEND2
2165 +extern void suspend2_try_resume(void);
2166 +#else
2167 +#define suspend2_try_resume() do { } while(0)
2168 +#endif
2169 +
2170 +extern int resume_attempted;
2171 +
2172 +#ifdef CONFIG_SOFTWARE_SUSPEND
2173 +extern int software_resume(void);
2174 +#else
2175 +static inline int software_resume(void)
2176 +{
2177 +       resume_attempted = 1;
2178 +       suspend2_try_resume();
2179 +       return 0;
2180 +}
2181 +#endif
2182 +
2183 +static inline void check_resume_attempted(void)
2184 +{
2185 +       if (resume_attempted)
2186 +               return;
2187 +
2188 +       software_resume();
2189 +}
2190 +#else
2191 +#define check_resume_attempted() do { } while(0)
2192 +#define resume_attempted (0)
2193 +#endif
2194 +
2195 +#ifdef CONFIG_PRINTK_NOSAVE
2196 +#define POSS_NOSAVE __nosavedata
2197 +#else
2198 +#define POSS_NOSAVE
2199 +#endif
2200 +
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
2205 @@ -190,6 +190,7 @@
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)
2215  
2216  #endif /* CONFIG_SWAP */
2217 +
2218 +/* For Suspend2 - unlink LRU pages while saving separately */
2219 +void unlink_lru_lists(void);
2220 +void relink_lru_lists(void);
2221 +
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
2227 @@ -225,4 +225,7 @@
2228   */
2229  #define TIMER_ABSTIME                  0x01
2230  
2231 +extern void save_avenrun(void);
2232 +extern void restore_avenrun(void);
2233 +
2234  #endif
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 @@
2239         char s[32];
2240         char *p;
2241         dev_t res = 0;
2242 -       int part;
2243 +       int part, mount_result;
2244  
2245  #ifdef CONFIG_SYSFS
2246         int mkdir_err = sys_mkdir("/sys", 0700);
2247 -       if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
2248 +       /* 
2249 +        * When changing resume2 parameter for Software Suspend, sysfs may
2250 +        * already be mounted. 
2251 +        */
2252 +       mount_result = sys_mount("sysfs", "/sys", "sysfs", 0, NULL);
2253 +       if (mount_result < 0 && mount_result != -EBUSY)
2254                 goto out;
2255  #endif
2256  
2257 @@ -197,7 +202,8 @@
2258         res = try_name(s, part);
2259  done:
2260  #ifdef CONFIG_SYSFS
2261 -       sys_umount("/sys", 0);
2262 +       if (mount_result >= 0)
2263 +               sys_umount("/sys", 0);
2264  out:
2265         if (!mkdir_err)
2266                 sys_rmdir("/sys");
2267 @@ -440,12 +446,27 @@
2268  
2269         is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
2270  
2271 +       /* Suspend2:
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).
2275 +        * 
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
2282 +        * check next.
2283 +        */
2284         if (initrd_load())
2285                 goto out;
2286  
2287         if (is_floppy && rd_doload && rd_load_disk(0))
2288                 ROOT_DEV = Root_RAM0;
2289  
2290 +       check_resume_attempted();
2291 +
2292         mount_root();
2293  out:
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
2298 @@ -6,6 +6,7 @@
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>
2304  
2305  #include "do_mounts.h"
2306 @@ -63,6 +64,11 @@
2307                 }
2308         }
2309  
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);
2314 +
2315         /* move initrd to rootfs' /old */
2316         sys_fchdir(old_fd);
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
2321 @@ -55,6 +55,7 @@
2322  #include <linux/pid_namespace.h>
2323  #include <linux/device.h>
2324  #include <linux/kthread.h>
2325 +#include <linux/suspend.h>
2326  
2327  #include <asm/io.h>
2328  #include <asm/bugs.h>
2329 @@ -817,7 +818,9 @@
2330  
2331         /*
2332          * check if there is an early userspace init.  If yes, let it do all
2333 -        * the work
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.
2337          */
2338  
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
2343 @@ -33,6 +33,7 @@
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>
2349  
2350  extern int max_threads;
2351 @@ -337,6 +338,11 @@
2352         }
2353         sub_info.stdin = f;
2354  
2355 +       if (freezer_is_on()) {
2356 +               printk(KERN_WARNING "Freezer is on. Refusing to start %s.\n", path);
2357 +               return -EBUSY;
2358 +       }
2359 +
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
2366 @@ -48,6 +48,18 @@
2367         suspend/resume routines, but may itself lead to problems, for example
2368         if netconsole is used.
2369  
2370 +config PRINTK_NOSAVE
2371 +       depends on PM && PM_DEBUG
2372 +       bool "Preserve printk data from boot kernel when resuming."
2373 +       default n
2374 +       ---help---
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.
2381 +
2382  config PM_TRACE
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
2388           APM in your BIOS).
2389 +
2390 +menuconfig SUSPEND2_CORE
2391 +       tristate "Suspend2"
2392 +       depends on PM
2393 +       select DYN_PAGEFLAGS
2394 +       select HOTPLUG_CPU if SMP
2395 +       default y
2396 +       ---help---
2397 +         Suspend2 is the 'new and improved' suspend support.
2398 +         
2399 +         See the Suspend2 home page (suspend2.net)
2400 +         for FAQs, HOWTOs and other documentation.
2401 +
2402 +       comment "Image Storage (you need at least one allocator)"
2403 +               depends on SUSPEND2_CORE
2404 +       
2405 +       config SUSPEND2_FILE
2406 +               tristate "File Allocator"
2407 +               depends on SUSPEND2_CORE
2408 +               default y
2409 +               ---help---
2410 +                 This option enables support for storing an image in a
2411 +                 simple file. This should be possible, but we're still
2412 +                 testing it.
2413 +
2414 +       config SUSPEND2_SWAP
2415 +               tristate "Swap Allocator"
2416 +               depends on SUSPEND2_CORE
2417 +               default y
2418 +               select SWAP
2419 +               ---help---
2420 +                 This option enables support for storing an image in your
2421 +                 swap space.
2422 +
2423 +       comment "General Options"
2424 +               depends on SUSPEND2_CORE
2425 +
2426 +       config SUSPEND2_CRYPTO
2427 +               tristate "Compression support"
2428 +               depends on SUSPEND2_CORE && CRYPTO
2429 +               default y
2430 +               ---help---
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.
2435 +
2436 +                 You probably want this, so say Y here.
2437 +
2438 +       comment "No compression support available without Cryptoapi support."
2439 +               depends on SUSPEND2_CORE && !CRYPTO
2440 +
2441 +       config SUSPEND2_USERUI
2442 +               tristate "Userspace User Interface support"
2443 +               depends on SUSPEND2_CORE && NET
2444 +               default y
2445 +               ---help---
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.
2450 +
2451 +       config SUSPEND2_DEFAULT_RESUME2
2452 +               string "Default resume device name"
2453 +               depends on SUSPEND2_CORE
2454 +               ---help---
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.
2458 +
2459 +       config SUSPEND2_KEEP_IMAGE
2460 +               bool "Allow Keep Image Mode"
2461 +               depends on SUSPEND2_CORE
2462 +               ---help---
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!
2473 +
2474 +       config SUSPEND2_REPLACE_SWSUSP
2475 +               bool "Replace swsusp by default"
2476 +               default y
2477 +               depends on SUSPEND2_CORE
2478 +               ---help---
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.
2489 +
2490 +       config SUSPEND2_CLUSTER
2491 +               tristate "Cluster support"
2492 +               default n
2493 +               depends on SUSPEND2_CORE && NET && BROKEN
2494 +               ---help---
2495 +                 Support for linking multiple machines in a cluster so that they suspend
2496 +                 and resume together.
2497 +
2498 +       config SUSPEND2_DEFAULT_CLUSTER_MASTER
2499 +               string "Default cluster master address/port"
2500 +               depends on SUSPEND2_CLUSTER
2501 +               ---help---
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.
2507 +
2508 +       config SUSPEND2_CHECKSUM
2509 +               bool "Checksum pageset2"
2510 +               depends on SUSPEND2_CORE
2511 +               select CRYPTO
2512 +               select CRYPTO_ALGAPI
2513 +               select CRYPTO_MD5
2514 +               ---help---
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.
2518 +
2519 +config SUSPEND_SHARED
2520 +       bool
2521 +       depends on SUSPEND2_CORE || SOFTWARE_SUSPEND
2522 +       default y
2523 +
2524 +config SUSPEND2_USERUI_EXPORTS
2525 +       bool
2526 +       depends on SUSPEND2_USERUI=m
2527 +       default y
2528 +
2529 +config SUSPEND2_SWAP_EXPORTS
2530 +       bool
2531 +       depends on SUSPEND2_SWAP=m
2532 +       default y
2533 +
2534 +config SUSPEND2_FILE_EXPORTS
2535 +       bool
2536 +       depends on SUSPEND2_FILE=m
2537 +       default y
2538 +
2539 +config SUSPEND2_CRYPTO_EXPORTS
2540 +       bool
2541 +       depends on SUSPEND2_CRYPTO=m
2542 +       default y
2543 +
2544 +config SUSPEND2_CORE_EXPORTS
2545 +       bool
2546 +       depends on SUSPEND2_CORE=m
2547 +       default y
2548 +
2549 +config SUSPEND2_EXPORTS
2550 +       bool
2551 +       depends on SUSPEND2_SWAP_EXPORTS || SUSPEND2_FILE_EXPORTS || \
2552 +               SUSPEND2_CRYPTO_EXPORTS || SUSPEND2_CLUSTER=m || \
2553 +               SUSPEND2_USERUI_EXPORTS
2554 +       default y
2555 +
2556 +config SUSPEND2
2557 +       bool
2558 +       depends on SUSPEND2_CORE!=n
2559 +       default y
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
2563 @@ -5,6 +5,32 @@
2564  
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
2569 +
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
2574 +
2575 +obj-$(CONFIG_SUSPEND2)         += suspend2_builtin.o
2576 +
2577 +ifdef CONFIG_SUSPEND2_CHECKSUM
2578 +suspend_core-objs      += checksum.o
2579 +endif
2580 +
2581 +ifdef CONFIG_NET
2582 +suspend_core-objs      += storage.o netlink.o
2583 +endif
2584 +
2585 +obj-$(CONFIG_SUSPEND2_CORE)    += suspend_core.o
2586 +obj-$(CONFIG_SUSPEND2_CRYPTO)  += suspend_compress.o
2587 +
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
2591 +
2592 +obj-$(CONFIG_SUSPEND2_USERUI)  += suspend_userui.o
2593 +
2594 +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o swap.o user.o
2595  
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
2600 @@ -0,0 +1,423 @@
2601 +/*
2602 + * kernel/power/atomic_copy.c
2603 + *
2604 + * Copyright 2004-2007 Nigel Cunningham (nigel at suspend2 net)
2605 + * Copyright (C) 2006 Red Hat, inc.
2606 + *
2607 + * Distributed under GPLv2.
2608 + *
2609 + * Routines for doing the atomic save/restore.
2610 + */
2611 +
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"
2620 +#include "ui.h"
2621 +#include "power.h"
2622 +#include "io.h"
2623 +#include "prepare_image.h"
2624 +#include "pageflags.h"
2625 +#include "checksum.h"
2626 +#include "suspend2_builtin.h"
2627 +
2628 +int extra_pd1_pages_used;
2629 +
2630 +/*
2631 + * Highmem related functions (x86 only).
2632 + */
2633 +
2634 +#ifdef CONFIG_HIGHMEM
2635 +
2636 +/**
2637 + * copyback_high: Restore highmem pages.
2638 + *
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.
2647 + **/
2648 +
2649 +static void copyback_high(void)
2650 +{
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;
2655 +
2656 +       if (!pbe_page)
2657 +               return;
2658 +
2659 +       this_pbe = (struct pbe *) kmap_atomic(pbe_page, KM_BOUNCE_READ);
2660 +       first_pbe = this_pbe;
2661 +
2662 +       while (this_pbe) {
2663 +               int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
2664 +
2665 +               origpage = kmap_atomic((struct page *) this_pbe->orig_address,
2666 +                       KM_BIO_DST_IRQ);
2667 +               copypage = kmap_atomic((struct page *) this_pbe->address,
2668 +                       KM_BIO_SRC_IRQ);
2669 +
2670 +               while (loop >= 0) {
2671 +                       *(origpage + loop) = *(copypage + loop);
2672 +                       loop--;
2673 +               }
2674 +
2675 +               kunmap_atomic(origpage, KM_BIO_DST_IRQ);
2676 +               kunmap_atomic(copypage, KM_BIO_SRC_IRQ);
2677 +
2678 +               if (!this_pbe->next)
2679 +                       break;
2680 +
2681 +               if (pbe_index < PBES_PER_PAGE) {
2682 +                       this_pbe++;
2683 +                       pbe_index++;
2684 +               } else {
2685 +                       pbe_page = (struct page *) this_pbe->next;
2686 +                       kunmap_atomic(first_pbe, KM_BOUNCE_READ);
2687 +                       if (!pbe_page)
2688 +                               return;
2689 +                       this_pbe = (struct pbe *) kmap_atomic(pbe_page,
2690 +                                       KM_BOUNCE_READ);
2691 +                       first_pbe = this_pbe;
2692 +                       pbe_index = 1;
2693 +               }
2694 +       }
2695 +       kunmap_atomic(first_pbe, KM_BOUNCE_READ);
2696 +}
2697 +
2698 +#else /* CONFIG_HIGHMEM */
2699 +void copyback_high(void) { }
2700 +#endif
2701 +
2702 +/**
2703 + * free_pbe_list: Free page backup entries used by the atomic copy code.
2704 + *
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.
2707 + **/
2708 +static void free_pbe_list(struct pbe **list, int highmem)
2709 +{
2710 +       while(*list) {
2711 +               int i;
2712 +               struct pbe *free_pbe, *next_page = NULL;
2713 +               struct page *page;
2714 +
2715 +               if (highmem) {
2716 +                       page = (struct page *) *list;
2717 +                       free_pbe = (struct pbe *) kmap(page);
2718 +               } else {
2719 +                       page = virt_to_page(*list);
2720 +                       free_pbe = *list;
2721 +               }
2722 +
2723 +               for (i = 0; i < PBES_PER_PAGE; i++) {
2724 +                       if (!free_pbe)
2725 +                               break;
2726 +                       if (highmem)
2727 +                               __free_page(free_pbe->address);
2728 +                       else
2729 +                               free_page((unsigned long) free_pbe->address);
2730 +                       free_pbe = free_pbe->next;
2731 +               }
2732 +
2733 +               if (highmem) {
2734 +                       if (free_pbe)
2735 +                               next_page = free_pbe;
2736 +                       kunmap(page);
2737 +               } else {
2738 +                       if (free_pbe)
2739 +                               next_page = free_pbe;
2740 +               }
2741 +
2742 +               __free_page(page);
2743 +               *list = (struct pbe *) next_page;
2744 +       };
2745 +}
2746 +
2747 +/**
2748 + * copyback_post: Post atomic-restore actions.
2749 + *
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.
2757 + **/
2758 +
2759 +void copyback_post(void)
2760 +{
2761 +       int loop;
2762 +
2763 +       suspend_action = suspend2_nosave_state1;
2764 +       suspend_debug_state = suspend2_nosave_state2;
2765 +       console_loglevel = suspend2_nosave_state3;
2766 +
2767 +       for (loop = 0; loop < 4; loop++)
2768 +               suspend_io_time[loop/2][loop%2] =
2769 +                       suspend2_nosave_io_speed[loop/2][loop%2];
2770 +
2771 +       set_suspend_state(SUSPEND_NOW_RESUMING);
2772 +       set_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
2773 +
2774 +       if (suspend_activate_storage(1))
2775 +               panic("Failed to reactivate our storage.");
2776 +
2777 +       suspend_ui_post_atomic_restore();
2778 +
2779 +       suspend_cond_pause(1, "About to reload secondary pagedir.");
2780 +
2781 +       if (read_pageset2(0))
2782 +               panic("Unable to successfully reread the page cache.");
2783 +
2784 +       clear_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
2785 +}
2786 +
2787 +/**
2788 + * suspend_copy_pageset1: Do the atomic copy of pageset1.
2789 + *
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.
2794 + * 
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.
2799 + **/
2800 +
2801 +void suspend_copy_pageset1(void)
2802 +{
2803 +       int i;
2804 +       unsigned long source_index, dest_index;
2805 +
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);
2808 +
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;
2813 +
2814 +               origpage = pfn_to_page(source_index);
2815 +               copypage = pfn_to_page(dest_index);
2816 +               
2817 +               origvirt = PageHighMem(origpage) ?
2818 +                       kmap_atomic(origpage, KM_USER0) :
2819 +                       page_address(origpage);
2820 +
2821 +               copyvirt = PageHighMem(copypage) ?
2822 +                       kmap_atomic(copypage, KM_USER1) :
2823 +                       page_address(copypage);
2824 +
2825 +               while (loop >= 0) {
2826 +                       *(copyvirt + loop) = *(origvirt + loop);
2827 +                       loop--;
2828 +               }
2829 +               
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();
2836 +               }
2837 +
2838 +               if (PageHighMem(copypage))
2839 +                       kunmap_atomic(copyvirt, KM_USER1);
2840 +               
2841 +               source_index = get_next_bit_on(pageset1_map, source_index);
2842 +               dest_index = get_next_bit_on(pageset1_copy_map, dest_index);
2843 +       }
2844 +}
2845 +
2846 +/**
2847 + * __suspend_post_context_save: Steps after saving the cpu context.
2848 + *
2849 + * Steps taken after saving the CPU state to make the actual
2850 + * atomic copy.
2851 + *
2852 + * Called from swsusp_save in snapshot.c via suspend_post_context_save.
2853 + **/
2854 +
2855 +int __suspend_post_context_save(void)
2856 +{
2857 +       int old_ps1_size = pagedir1.size;
2858 +       
2859 +       calculate_check_checksums(1);
2860 +
2861 +       free_checksum_pages();
2862 +
2863 +       suspend_recalculate_image_contents(1);
2864 +
2865 +       extra_pd1_pages_used = pagedir1.size - old_ps1_size;
2866 +
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);
2874 +               return -1;
2875 +       }
2876 +
2877 +       if (!test_action_state(SUSPEND_TEST_FILTER_SPEED) &&
2878 +           !test_action_state(SUSPEND_TEST_BIO))
2879 +               suspend_copy_pageset1();
2880 +
2881 +       return 0;
2882 +}
2883 +
2884 +/**
2885 + * suspend2_suspend: High level code for doing the atomic copy.
2886 + *
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).
2893 + **/
2894 +
2895 +int suspend2_suspend(void)
2896 +{
2897 +       int error;
2898 +
2899 +       suspend2_running = 1; /* For the swsusp code we use :< */
2900 +
2901 +       if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2902 +               pm_prepare_console();
2903 +
2904 +       if ((error = arch_prepare_suspend()))
2905 +               goto err_out;
2906 +
2907 +       local_irq_disable();
2908 +
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.
2914 +        */
2915 +
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");
2920 +               goto enable_irqs;
2921 +       }
2922 +
2923 +       error = suspend2_lowlevel_builtin();
2924 +
2925 +       if (!suspend2_in_suspend)
2926 +               copyback_high();
2927 +
2928 +       device_power_up();
2929 +enable_irqs:
2930 +       local_irq_enable();
2931 +       if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2932 +               pm_restore_console();
2933 +err_out:
2934 +       suspend2_running = 0;
2935 +       return error;
2936 +}
2937 +
2938 +/**
2939 + * suspend_atomic_restore: Prepare to do the atomic restore.
2940 + *
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.
2945 + **/
2946 +
2947 +int suspend_atomic_restore(void)
2948 +{
2949 +       int error, loop;
2950 +
2951 +       suspend2_running = 1;
2952 +
2953 +       suspend_prepare_status(DONT_CLEAR_BAR,  "Prepare console");
2954 +
2955 +       if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2956 +               pm_prepare_console();
2957 +
2958 +       suspend_prepare_status(DONT_CLEAR_BAR,  "Device suspend.");
2959 +
2960 +       suspend_console();
2961 +       if ((error = device_suspend(PMSG_PRETHAW))) {
2962 +               printk("Some devices failed to suspend\n");
2963 +               goto device_resume;
2964 +       }
2965 +
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;
2972 +               }
2973 +       }
2974 +
2975 +       suspend_prepare_status(DONT_CLEAR_BAR,  "Atomic restore preparation");
2976 +
2977 +       suspend2_nosave_state1 = suspend_action;
2978 +       suspend2_nosave_state2 = suspend_debug_state;
2979 +       suspend2_nosave_state3 = console_loglevel;
2980 +       
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);
2985 +
2986 +       mb();
2987 +
2988 +       local_irq_disable();
2989 +
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;
2993 +       }
2994 +
2995 +       /* We'll ignore saved state, but this gets preempt count (etc) right */
2996 +       save_processor_state();
2997 +
2998 +       error = swsusp_arch_resume();
2999 +       /* 
3000 +        * Code below is only ever reached in case of failure. Otherwise
3001 +        * execution continues at place where swsusp_arch_suspend was called.
3002 +        *
3003 +        * We don't know whether it's safe to continue (this shouldn't happen),
3004 +        * so lets err on the side of caution.
3005 +         */
3006 +       BUG();
3007 +
3008 +device_power_up:
3009 +       device_power_up();
3010 +       if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
3011 +               enable_nonboot_cpus();
3012 +device_resume:
3013 +       device_resume();
3014 +       resume_console();
3015 +       free_pbe_list(&restore_pblist, 0);
3016 +#ifdef CONFIG_HIGHMEM
3017 +       free_pbe_list(&restore_highmem_pblist, 1);
3018 +#endif
3019 +       if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
3020 +               pm_restore_console();
3021 +       suspend2_running = 0;
3022 +       return 1;
3023 +}
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
3027 @@ -0,0 +1,55 @@
3028 +/*
3029 + * kernel/power/block_io.h
3030 + *
3031 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
3032 + * Copyright (C) 2006 Red Hat, inc.
3033 + *
3034 + * Distributed under GPLv2.
3035 + *
3036 + * This file contains declarations for functions exported from
3037 + * block_io.c, which contains low level io functions.
3038 + */
3039 +
3040 +#include <linux/buffer_head.h>
3041 +#include "extent.h"
3042 +
3043 +struct suspend_bdev_info {
3044 +       struct block_device *bdev;
3045 +       dev_t dev_t;
3046 +       int bmap_shift;
3047 +       int blocks_per_page;
3048 +};
3049 +
3050 +/* 
3051 + * Our exported interface so the swapwriter and filewriter don't
3052 + * need these functions duplicated.
3053 + */
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);
3073 +};
3074 +
3075 +extern struct suspend_bio_ops suspend_bio_ops;
3076 +
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
3086 @@ -0,0 +1,371 @@
3087 +/*
3088 + * kernel/power/checksum.c
3089 + *
3090 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3091 + * Copyright (C) 2006 Red Hat, inc.
3092 + *
3093 + * This file is released under the GPLv2.
3094 + *
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.
3098 + */
3099 +
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>
3106 +
3107 +#include "suspend.h"
3108 +#include "modules.h"
3109 +#include "sysfs.h"
3110 +#include "io.h"
3111 +#include "pageflags.h"
3112 +#include "checksum.h"
3113 +#include "pagedir.h"
3114 +
3115 +static struct suspend_module_ops suspend_checksum_ops;
3116 +
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)
3121 +
3122 +#define CHECKSUMS_PER_PAGE ((PAGE_SIZE - sizeof(void *)) / CHECKSUM_SIZE)
3123 +
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;
3128 +
3129 +static int suspend_num_resaved = 0;
3130 +
3131 +#if 1
3132 +#define PRINTK(a, b...) do { } while(0)
3133 +#else
3134 +#define PRINTK(a, b...) do { printk(a, ##b); } while(0)
3135 +#endif
3136 +
3137 +/* ---- Local buffer management ---- */
3138 +
3139 +/* 
3140 + * suspend_checksum_cleanup
3141 + *
3142 + * Frees memory allocated for our labours.
3143 + */
3144 +static void suspend_checksum_cleanup(int ending_cycle)
3145 +{
3146 +       if (ending_cycle && suspend_checksum_transform) {
3147 +               crypto_free_hash(suspend_checksum_transform);
3148 +               suspend_checksum_transform = NULL;
3149 +               desc.tfm = NULL;
3150 +       }
3151 +}
3152 +
3153 +/* 
3154 + * suspend_crypto_prepare
3155 + *
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.
3159 + */
3160 +static int suspend_checksum_prepare(int starting_cycle)
3161 +{
3162 +       if (!starting_cycle || !suspend_checksum_ops.enabled)
3163 +               return 0;
3164 +
3165 +       if (!*suspend_checksum_name) {
3166 +               printk("Suspend2: No checksum algorithm name set.\n");
3167 +               return 1;
3168 +       }
3169 +
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;
3176 +               return 1;
3177 +       }
3178 +
3179 +       desc.tfm = suspend_checksum_transform;
3180 +       desc.flags = 0;
3181 +
3182 +       return 0;
3183 +}
3184 +
3185 +static int suspend_print_task_if_using_page(struct task_struct *t, struct page *seeking)
3186 +{
3187 +       struct vm_area_struct *vma;
3188 +       struct mm_struct *mm;
3189 +       int result = 0;
3190 +
3191 +       mm = t->active_mm;
3192 +
3193 +       if (!mm || !mm->mmap) return 0;
3194 +
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);
3200 +       
3201 +       for (vma = mm->mmap; vma; vma = vma->vm_next) {
3202 +               if (vma->vm_flags & VM_PFNMAP)
3203 +                       continue;
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);
3212 +                                       result = 1;
3213 +                                       goto out;
3214 +                               }
3215 +                       }
3216 +               }
3217 +       }
3218 +
3219 +out:
3220 +       if (!irqs_disabled())
3221 +               up_read(&mm->mmap_sem);
3222 +
3223 +       return result;
3224 +}
3225 +
3226 +static void print_tasks_using_page(struct page *seeking)
3227 +{
3228 +       struct task_struct *p;
3229 +
3230 +       read_lock(&tasklist_lock);
3231 +       for_each_process(p) {
3232 +               if (suspend_print_task_if_using_page(p, seeking))
3233 +                       printk(" ");
3234 +       }
3235 +       read_unlock(&tasklist_lock);
3236 +}
3237 +
3238 +/* 
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.
3242 + *
3243 + * Print information to be recorded for debugging purposes into a buffer.
3244 + * Returns: Number of characters written to the buffer.
3245 + */
3246 +
3247 +static int suspend_checksum_print_debug_stats(char *buffer, int size)
3248 +{
3249 +       int len;
3250 +
3251 +       if (!suspend_checksum_ops.enabled)
3252 +               return snprintf_used(buffer, size,
3253 +                       "- Checksumming disabled.\n");
3254 +       
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);
3259 +       return len;
3260 +}
3261 +
3262 +static int suspend_checksum_storage_needed(void)
3263 +{
3264 +       if (suspend_checksum_ops.enabled)
3265 +               return strlen(suspend_checksum_name) + sizeof(int) + 1;
3266 +       else
3267 +               return 0;
3268 +}
3269 +
3270 +/* 
3271 + * suspend_checksum_save_config_info
3272 + * @buffer: Pointer to a buffer of size PAGE_SIZE.
3273 + *
3274 + * Save informaton needed when reloading the image at resume time.
3275 + * Returns: Number of bytes used for saving our data.
3276 + */
3277 +static int suspend_checksum_save_config_info(char *buffer)
3278 +{
3279 +       int namelen = strlen(suspend_checksum_name) + 1;
3280 +       int total_len;
3281 +       
3282 +       *((unsigned int *) buffer) = namelen;
3283 +       strncpy(buffer + sizeof(unsigned int), suspend_checksum_name, 
3284 +                                                               namelen);
3285 +       total_len = sizeof(unsigned int) + namelen;
3286 +       return total_len;
3287 +}
3288 +
3289 +/* suspend_checksum_load_config_info
3290 + * @buffer: Pointer to the start of the data.
3291 + * @size: Number of bytes that were saved.
3292 + *
3293 + * Description:        Reload information needed for dechecksuming the image at
3294 + * resume time.
3295 + */
3296 +static void suspend_checksum_load_config_info(char *buffer, int size)
3297 +{
3298 +       int namelen;
3299 +
3300 +       namelen = *((unsigned int *) (buffer));
3301 +       strncpy(suspend_checksum_name, buffer + sizeof(unsigned int),
3302 +                       namelen);
3303 +       return;
3304 +}
3305 +
3306 +/*
3307 + * Free Checksum Memory
3308 + */
3309 +
3310 +void free_checksum_pages(void)
3311 +{
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);
3318 +               page_list = next;
3319 +               pages_allocated--;
3320 +       }
3321 +}
3322 +
3323 +/*
3324 + * Allocate Checksum Memory
3325 + */
3326 +
3327 +int allocate_checksum_pages(void)
3328 +{
3329 +       int pages_needed = DIV_ROUND_UP(pagedir2.size, CHECKSUMS_PER_PAGE);
3330 +
3331 +       if (!suspend_checksum_ops.enabled)
3332 +               return 0;
3333 +
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);
3338 +               if (!new_page)
3339 +                       return -ENOMEM;
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));
3345 +       }
3346 +
3347 +       return 0;
3348 +}
3349 +
3350 +#if 0
3351 +static void print_checksum(char *buf, int size)
3352 +{
3353 +       int index;
3354 +
3355 +       for (index = 0; index < size; index++)
3356 +               printk("%x ", buf[index]);
3357 +
3358 +       printk("\n");
3359 +}
3360 +#endif
3361 +
3362 +/*
3363 + * Calculate checksums
3364 + */
3365 +
3366 +void calculate_check_checksums(int check)
3367 +{
3368 +       int pfn, index = 0;
3369 +       unsigned long next_page, this_checksum = 0;
3370 +       struct scatterlist sg[2];
3371 +       char current_checksum[CHECKSUM_SIZE];
3372 +
3373 +       if (!suspend_checksum_ops.enabled)
3374 +               return;
3375 +
3376 +       next_page = (unsigned long) page_list;
3377 +
3378 +       if (check)
3379 +               suspend_num_resaved = 0;
3380 +
3381 +       BITMAP_FOR_EACH_SET(pageset2_map, pfn) {
3382 +               int ret;
3383 +               if (index % CHECKSUMS_PER_PAGE) {
3384 +                       this_checksum += CHECKSUM_SIZE;
3385 +               } else {
3386 +                       this_checksum = next_page + sizeof(void *);
3387 +                       next_page = *((unsigned long *) next_page);
3388 +               }
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);
3391 +               if (check) {
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));
3399 +                               printk("\n");
3400 +                               suspend_num_resaved++;
3401 +                               if (test_action_state(SUSPEND_ABORT_ON_RESAVE_NEEDED))
3402 +                                       set_result_state(SUSPEND_ABORTED);
3403 +                       }
3404 +               } else
3405 +                       ret = crypto_hash_digest(&desc, sg, 
3406 +                                       PAGE_SIZE, (char *) this_checksum);
3407 +               if (ret) {
3408 +                       printk("Digest failed. Returned %d.\n", ret);
3409 +                       return;
3410 +               }
3411 +               index++;
3412 +       }
3413 +}
3414 +
3415 +static struct suspend_sysfs_data sysfs_params[] = {
3416 +       { SUSPEND2_ATTR("enabled", SYSFS_RW),
3417 +         SYSFS_INT(&suspend_checksum_ops.enabled, 0, 1, 0)
3418 +       },
3419 +
3420 +       { SUSPEND2_ATTR("abort_if_resave_needed", SYSFS_RW),
3421 +         SYSFS_BIT(&suspend_action, SUSPEND_ABORT_ON_RESAVE_NEEDED, 0)
3422 +       }
3423 +};
3424 +
3425 +/*
3426 + * Ops structure.
3427 + */
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,
3439 +
3440 +       .sysfs_data             = sysfs_params,
3441 +       .num_sysfs_entries      = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
3442 +};
3443 +
3444 +/* ---- Registration ---- */
3445 +int s2_checksum_init(void)
3446 +{
3447 +       int result = suspend_register_module(&suspend_checksum_ops);
3448 +
3449 +       /* Disabled by default */
3450 +       suspend_checksum_ops.enabled = 0;
3451 +       return result;
3452 +}
3453 +
3454 +void s2_checksum_exit(void)
3455 +{
3456 +       suspend_unregister_module(&suspend_checksum_ops);
3457 +}
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
3461 @@ -0,0 +1,27 @@
3462 +/*
3463 + * kernel/power/checksum.h
3464 + *
3465 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3466 + * Copyright (C) 2006 Red Hat, inc.
3467 + *
3468 + * This file is released under the GPLv2.
3469 + *
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.
3473 + */
3474 +
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);
3481 +#else
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) { };
3487 +#endif
3488 +
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
3492 @@ -0,0 +1,152 @@
3493 +/*
3494 + * kernel/power/cluster.c
3495 + *
3496 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3497 + *
3498 + * This file is released under the GPLv2.
3499 + *
3500 + * This file contains routines for cluster hibernation support.
3501 + *
3502 + */
3503 +
3504 +#include <linux/suspend.h>
3505 +#include <linux/module.h>
3506 +
3507 +#include "suspend.h"
3508 +#include "modules.h"
3509 +#include "sysfs.h"
3510 +#include "io.h"
3511 +
3512 +static char suspend_cluster_master[63] = CONFIG_SUSPEND2_DEFAULT_CLUSTER_MASTER;
3513 +
3514 +static struct suspend_module_ops suspend_cluster_ops;
3515 +
3516 +/* suspend_cluster_print_debug_stats
3517 + *
3518 + * Description:        Print information to be recorded for debugging purposes into a
3519 + *             buffer.
3520 + * Arguments:  buffer: Pointer to a buffer into which the debug info will be
3521 + *                     printed.
3522 + *             size:   Size of the buffer.
3523 + * Returns:    Number of characters written to the buffer.
3524 + */
3525 +static int suspend_cluster_print_debug_stats(char *buffer, int size)
3526 +{
3527 +       int len;
3528 +       
3529 +       if (strlen(suspend_cluster_master))
3530 +               len = snprintf_used(buffer, size, "- Cluster master is '%s'.\n",
3531 +                               suspend_cluster_master);
3532 +       else
3533 +               len = snprintf_used(buffer, size, "- Cluster support is disabled.\n");
3534 +       return len;
3535 +}
3536 +
3537 +/* cluster_memory_needed
3538 + *
3539 + * Description:        Tell the caller how much memory we need to operate during
3540 + *             suspend/resume.
3541 + * Returns:    Unsigned long. Maximum number of bytes of memory required for
3542 + *             operation.
3543 + */
3544 +static int suspend_cluster_memory_needed(void)
3545 +{
3546 +       return 0;
3547 +}
3548 +
3549 +static int suspend_cluster_storage_needed(void)
3550 +{
3551 +       return 1 + strlen(suspend_cluster_master);
3552 +}
3553 +       
3554 +/* suspend_cluster_save_config_info
3555 + *
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.
3559 + */
3560 +static int suspend_cluster_save_config_info(char *buffer)
3561 +{
3562 +       strcpy(buffer, suspend_cluster_master);
3563 +       return strlen(suspend_cluster_master + 1);
3564 +}
3565 +
3566 +/* suspend_cluster_load_config_info
3567 + *
3568 + * Description:        Reload information needed for declustering the image at 
3569 + *             resume time.
3570 + * Arguments:  Buffer:         Pointer to the start of the data.
3571 + *             Size:           Number of bytes that were saved.
3572 + */
3573 +static void suspend_cluster_load_config_info(char *buffer, int size)
3574 +{
3575 +       strncpy(suspend_cluster_master, buffer, size);
3576 +       return;
3577 +}
3578 +
3579 +/*
3580 + * data for our sysfs entries.
3581 + */
3582 +static struct suspend_sysfs_data sysfs_params[] = {
3583 +       {
3584 +               SUSPEND2_ATTR("master", SYSFS_RW),
3585 +               SYSFS_STRING(suspend_cluster_master, 63, SYSFS_SM_NOT_NEEDED)
3586 +       },
3587 +
3588 +       {
3589 +               SUSPEND2_ATTR("enabled", SYSFS_RW),
3590 +               SYSFS_INT(&suspend_cluster_ops.enabled, 0, 1)
3591 +       }
3592 +};
3593 +
3594 +/*
3595 + * Ops structure.
3596 + */
3597 +
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,
3608 +       
3609 +       .sysfs_data             = sysfs_params,
3610 +       .num_sysfs_entries      = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
3611 +};
3612 +
3613 +/* ---- Registration ---- */
3614 +
3615 +#ifdef MODULE
3616 +#warning Module set.
3617 +#define INIT static __init
3618 +#define EXIT static __exit
3619 +#else
3620 +#define INIT
3621 +#define EXIT
3622 +#endif
3623 +
3624 +INIT int s2_cluster_init(void)
3625 +{
3626 +       int temp = suspend_register_module(&suspend_cluster_ops);
3627 +
3628 +       if (!strlen(suspend_cluster_master))
3629 +               suspend_cluster_ops.enabled = 0;
3630 +       return temp;    
3631 +}
3632 +
3633 +EXIT void s2_cluster_exit(void)
3634 +{
3635 +       suspend_unregister_module(&suspend_cluster_ops);
3636 +}
3637 +
3638 +#ifdef MODULE
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");
3644 +#endif
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
3648 @@ -0,0 +1,17 @@
3649 +/*
3650 + * kernel/power/cluster.h
3651 + *
3652 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3653 + * Copyright (C) 2006 Red Hat, inc.
3654 + *
3655 + * This file is released under the GPLv2.
3656 + */
3657 +
3658 +#ifdef CONFIG_SUSPEND2_CLUSTER
3659 +extern int s2_cluster_init(void);
3660 +extern void s2_cluster_exit(void);
3661 +#else
3662 +static inline int s2_cluster_init(void) { return 0; }
3663 +static inline void s2_cluster_exit(void) { }
3664 +#endif
3665 +
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
3669 @@ -24,6 +24,8 @@
3670  
3671  #include "power.h"
3672  
3673 +#include "suspend.h"
3674 +#include "suspend2_builtin.h"
3675  
3676  static int noresume = 0;
3677  char resume_file[256] = CONFIG_PM_STD_PARTITION;
3678 @@ -152,6 +154,11 @@
3679  {
3680         int error;
3681  
3682 +#ifdef CONFIG_SUSPEND2
3683 +       if (test_action_state(SUSPEND_REPLACE_SWSUSP))
3684 +               return suspend2_try_suspend(1);
3685 +#endif
3686 +
3687         /* The snapshot device should not be opened while we're running */
3688         if (!atomic_add_unless(&snapshot_device_available, -1, 0))
3689                 return -EBUSY;
3690 @@ -250,10 +257,22 @@
3691   *
3692   */
3693  
3694 -static int software_resume(void)
3695 +int software_resume(void)
3696  {
3697         int error;
3698  
3699 +       resume_attempted = 1;
3700 +
3701 +#ifdef CONFIG_SUSPEND2
3702 +       /* 
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.
3705 +        */
3706 +       if (test_action_state(SUSPEND_REPLACE_SWSUSP))
3707 +               printk("Replacing swsusp.\n");
3708 +               suspend2_try_resume();
3709 +#endif
3710 +
3711         mutex_lock(&pm_mutex);
3712         if (!swsusp_resume_device) {
3713                 if (!strlen(resume_file)) {
3714 @@ -336,9 +355,6 @@
3715         return 0;
3716  }
3717  
3718 -late_initcall(software_resume);
3719 -
3720 -
3721  static const char * const hibernation_modes[] = {
3722         [HIBERNATION_PLATFORM]  = "platform",
3723         [HIBERNATION_SHUTDOWN]  = "shutdown",
3724 @@ -545,6 +561,7 @@
3725  static int __init noresume_setup(char *str)
3726  {
3727         noresume = 1;
3728 +       set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
3729         return 1;
3730  }
3731  
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
3735 @@ -0,0 +1,305 @@
3736 +/* 
3737 + * kernel/power/extent.c
3738 + * 
3739 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
3740 + *
3741 + * Distributed under GPLv2.
3742 + * 
3743 + * These functions encapsulate the manipulation of storage metadata. For
3744 + * pageflags, we use dynamically allocated bitmaps.
3745 + */
3746 +
3747 +#include <linux/module.h>
3748 +#include <linux/suspend.h>
3749 +#include "modules.h"
3750 +#include "extent.h"
3751 +#include "ui.h"
3752 +#include "suspend.h"
3753 +
3754 +/* suspend_get_extent
3755 + *
3756 + * Returns a free extent. May fail, returning NULL instead.
3757 + */
3758 +static struct extent *suspend_get_extent(void)
3759 +{
3760 +       struct extent *result;
3761 +       
3762 +       if (!(result = kmalloc(sizeof(struct extent), GFP_ATOMIC)))
3763 +               return NULL;
3764 +
3765 +       result->minimum = result->maximum = 0;
3766 +       result->next = NULL;
3767 +
3768 +       return result;
3769 +}
3770 +
3771 +/* suspend_put_extent_chain.
3772 + *
3773 + * Frees a whole chain of extents.
3774 + */
3775 +void suspend_put_extent_chain(struct extent_chain *chain)
3776 +{
3777 +       struct extent *this;
3778 +
3779 +       this = chain->first;
3780 +
3781 +       while(this) {
3782 +               struct extent *next = this->next;
3783 +               kfree(this);
3784 +               chain->num_extents--;
3785 +               this = next;
3786 +       }
3787 +       
3788 +       chain->first = chain->last_touched = NULL;
3789 +       chain->size = 0;
3790 +}
3791 +
3792 +/* 
3793 + * suspend_add_to_extent_chain
3794 + *
3795 + * Add an extent to an existing chain.
3796 + */
3797 +int suspend_add_to_extent_chain(struct extent_chain *chain, 
3798 +               unsigned long minimum, unsigned long maximum)
3799 +{
3800 +       struct extent *new_extent = NULL, *start_at;
3801 +
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;
3806 +
3807 +       if (!start_at && chain->first && chain->first->minimum < minimum)
3808 +               start_at = chain->first;
3809 +
3810 +       while (start_at && start_at->next && start_at->next->minimum < minimum)
3811 +               start_at = start_at->next;
3812 +
3813 +       if (start_at && start_at->maximum == (minimum - 1)) {
3814 +               start_at->maximum = maximum;
3815 +
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--;
3823 +                       kfree(to_free);
3824 +               }
3825 +
3826 +               chain->last_touched = start_at;
3827 +               chain->size+= (maximum - minimum + 1);
3828 +
3829 +               return 0;
3830 +       }
3831 +
3832 +       new_extent = suspend_get_extent();
3833 +       if (!new_extent) {
3834 +               printk("Error unable to append a new extent to the chain.\n");
3835 +               return 2;
3836 +       }
3837 +
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;
3843 +
3844 +       chain->last_touched = new_extent;
3845 +
3846 +       if (start_at) {
3847 +               struct extent *next = start_at->next;
3848 +               start_at->next = new_extent;
3849 +               new_extent->next = next;
3850 +       } else {
3851 +               if (chain->first)
3852 +                       new_extent->next = chain->first;
3853 +               chain->first = new_extent;
3854 +       }
3855 +
3856 +       return 0;
3857 +}
3858 +
3859 +/* suspend_serialise_extent_chain
3860 + *
3861 + * Write a chain in the image.
3862 + */
3863 +int suspend_serialise_extent_chain(struct suspend_module_ops *owner,
3864 +               struct extent_chain *chain)
3865 +{
3866 +       struct extent *this;
3867 +       int ret, i = 0;
3868 +       
3869 +       if ((ret = suspendActiveAllocator->rw_header_chunk(WRITE, owner,
3870 +               (char *) chain,
3871 +               2 * sizeof(int))))
3872 +               return ret;
3873 +
3874 +       this = chain->first;
3875 +       while (this) {
3876 +               if ((ret = suspendActiveAllocator->rw_header_chunk(WRITE, owner,
3877 +                               (char *) this,
3878 +                               2 * sizeof(unsigned long))))
3879 +                       return ret;
3880 +               this = this->next;
3881 +               i++;
3882 +       }
3883 +
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);
3887 +               return 1;
3888 +       }
3889 +
3890 +       return ret;
3891 +}
3892 +
3893 +/* suspend_load_extent_chain
3894 + *
3895 + * Read back a chain saved in the image.
3896 + */
3897 +int suspend_load_extent_chain(struct extent_chain *chain)
3898 +{
3899 +       struct extent *this, *last = NULL;
3900 +       int i, ret;
3901 +
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");
3905 +               return 1;
3906 +       }
3907 +
3908 +       for (i = 0; i < chain->num_extents; i++) {
3909 +               this = kmalloc(sizeof(struct extent), GFP_ATOMIC);
3910 +               if (!this) {
3911 +                       printk("Failed to allocate a new extent.\n");
3912 +                       return -ENOMEM;
3913 +               }
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");
3918 +                       return 1;
3919 +               }
3920 +               if (last)
3921 +                       last->next = this;
3922 +               else
3923 +                       chain->first = this;
3924 +               last = this;
3925 +       }
3926 +       return 0;
3927 +}
3928 +
3929 +/* suspend_extent_state_next
3930 + *
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.
3933 + *
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.
3936 + */
3937 +unsigned long suspend_extent_state_next(struct extent_iterate_state *state)
3938 +{
3939 +       if (state->current_chain == state->num_chains)
3940 +               return 0;
3941 +
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;
3947 +                       } else {
3948 +                               state->current_extent = NULL;
3949 +                               state->current_offset = 0;
3950 +                       }
3951 +               } else
3952 +                       state->current_offset++;
3953 +       }
3954 +
3955 +       while(!state->current_extent) {
3956 +               int chain_num = ++(state->current_chain);
3957 +
3958 +               if (chain_num == state->num_chains)
3959 +                       return 0;
3960 +
3961 +               state->current_extent = (state->chains + chain_num)->first;
3962 +
3963 +               if (!state->current_extent)
3964 +                       continue;
3965 +
3966 +               state->current_offset = state->current_extent->minimum;
3967 +       }
3968 +
3969 +       return state->current_offset;
3970 +}
3971 +
3972 +/* suspend_extent_state_goto_start
3973 + *
3974 + * Find the first valid value in a group of chains.
3975 + */
3976 +void suspend_extent_state_goto_start(struct extent_iterate_state *state)
3977 +{
3978 +       state->current_chain = -1;
3979 +       state->current_extent = NULL;
3980 +       state->current_offset = 0;
3981 +}
3982 +
3983 +/* suspend_extent_start_save
3984 + *
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
3987 + * resume time).
3988 + */
3989 +void suspend_extent_state_save(struct extent_iterate_state *state,
3990 +               struct extent_iterate_saved_state *saved_state)
3991 +{
3992 +       struct extent *extent;
3993 +
3994 +       saved_state->chain_num = state->current_chain;
3995 +       saved_state->extent_num = 0;
3996 +       saved_state->offset = state->current_offset;
3997 +
3998 +       if (saved_state->chain_num == -1)
3999 +               return;
4000 +       
4001 +       extent = (state->chains + state->current_chain)->first;
4002 +
4003 +       while (extent != state->current_extent) {
4004 +               saved_state->extent_num++;
4005 +               extent = extent->next;
4006 +       }
4007 +}
4008 +
4009 +/* suspend_extent_start_restore
4010 + *
4011 + * Restore the position saved by extent_state_save.
4012 + */
4013 +void suspend_extent_state_restore(struct extent_iterate_state *state,
4014 +               struct extent_iterate_saved_state *saved_state)
4015 +{
4016 +       int posn = saved_state->extent_num;
4017 +
4018 +       if (saved_state->chain_num == -1) {
4019 +               suspend_extent_state_goto_start(state);
4020 +               return;
4021 +       }
4022 +
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;
4026 +
4027 +       while (posn--)
4028 +               state->current_extent = state->current_extent->next;
4029 +}
4030 +
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);
4040 +#endif
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
4044 @@ -0,0 +1,77 @@
4045 +/*
4046 + * kernel/power/extent.h
4047 + *
4048 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
4049 + *
4050 + * This file is released under the GPLv2.
4051 + *
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.
4055 + *
4056 + */
4057 +
4058 +#include "modules.h"
4059 +
4060 +#ifndef EXTENT_H
4061 +#define EXTENT_H
4062 +
4063 +struct extent {
4064 +       unsigned long minimum, maximum;
4065 +       struct extent *next;
4066 +};
4067 +
4068 +struct extent_chain {
4069 +       int size; /* size of the chain ie sum (max-min+1) */
4070 +       int num_extents;
4071 +       struct extent *first, *last_touched;
4072 +};
4073 +
4074 +struct extent_iterate_state {
4075 +       struct extent_chain *chains;
4076 +       int num_chains;
4077 +       int current_chain;
4078 +       struct extent *current_extent;
4079 +       unsigned long current_offset;
4080 +};
4081 +
4082 +struct extent_iterate_saved_state {
4083 +       int chain_num;
4084 +       int extent_num;
4085 +       unsigned long offset;
4086 +};
4087 +
4088 +#define suspend_extent_state_eof(state) ((state)->num_chains == (state)->current_chain)
4089 +
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)) : \
4100 +                       (value)++))
4101 +
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);
4108 +
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) }
4114 +
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);
4121 +#endif
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
4125 @@ -0,0 +1,1407 @@
4126 +/*
4127 + * kernel/power/io.c
4128 + *
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)
4133 + *
4134 + * This file is released under the GPLv2.
4135 + *
4136 + * It contains high level IO routines for suspending.
4137 + *
4138 + */
4139 +
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>
4148 +
4149 +#include "suspend.h"
4150 +#include "modules.h"
4151 +#include "pageflags.h"
4152 +#include "io.h"
4153 +#include "ui.h"
4154 +#include "storage.h"
4155 +#include "prepare_image.h"
4156 +#include "extent.h"
4157 +#include "sysfs.h"
4158 +#include "suspend2_builtin.h"
4159 +
4160 +char poweroff_resume2[256];
4161 +
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;
4172 +
4173 +/* suspend_attempt_to_parse_resume_device
4174 + *
4175 + * Can we suspend, using the current resume2= parameter?
4176 + */
4177 +int suspend_attempt_to_parse_resume_device(int quiet)
4178 +{
4179 +       struct list_head *Allocator;
4180 +       struct suspend_module_ops *thisAllocator;
4181 +       int result, returning = 0;
4182 +
4183 +       if (suspend_activate_storage(0))
4184 +               return 0;
4185 +
4186 +       suspendActiveAllocator = NULL;
4187 +       clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
4188 +       clear_suspend_state(SUSPEND_CAN_RESUME);
4189 +       clear_result_state(SUSPEND_ABORTED);
4190 +
4191 +       if (!suspendNumAllocators) {
4192 +               if (!quiet)
4193 +                       printk("Suspend2: No storage allocators have been "
4194 +                               "registered. Suspending will be disabled.\n");
4195 +               goto cleanup;
4196 +       }
4197 +       
4198 +       if (!resume2_file[0]) {
4199 +               if (!quiet)
4200 +                       printk("Suspend2: Resume2 parameter is empty."
4201 +                               " Suspending will be disabled.\n");
4202 +               goto cleanup;
4203 +       }
4204 +
4205 +       list_for_each(Allocator, &suspendAllocators) {
4206 +               thisAllocator = list_entry(Allocator, struct suspend_module_ops,
4207 +                                                               type_list);
4208 +
4209 +               /* 
4210 +                * Not sure why you'd want to disable an allocator, but
4211 +                * we should honour the flag if we're providing it
4212 +                */
4213 +               if (!thisAllocator->enabled)
4214 +                       continue;
4215 +
4216 +               result = thisAllocator->parse_sig_location(
4217 +                               resume2_file, (suspendNumAllocators == 1),
4218 +                               quiet);
4219 +
4220 +               switch (result) {
4221 +                       case -EINVAL:
4222 +                               /* For this allocator, but not a valid 
4223 +                                * configuration. Error already printed. */
4224 +                               goto cleanup;
4225 +
4226 +                       case 0:
4227 +                               /* For this allocator and valid. */
4228 +                               suspendActiveAllocator = thisAllocator;
4229 +
4230 +                               set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
4231 +                               set_suspend_state(SUSPEND_CAN_RESUME);
4232 +                               if (!quiet)
4233 +                                       printk("Suspend2: Resuming enabled.\n");
4234 +
4235 +                               returning = 1;
4236 +                               goto cleanup;
4237 +               }
4238 +       }
4239 +       if (!quiet)
4240 +               printk("Suspend2: No matching enabled allocator found. "
4241 +                               "Resuming disabled.\n");
4242 +cleanup:
4243 +       suspend_deactivate_storage(0);
4244 +       return returning;
4245 +}
4246 +
4247 +void attempt_to_parse_resume_device2(void)
4248 +{
4249 +       suspend_prepare_usm();
4250 +       suspend_attempt_to_parse_resume_device(0);
4251 +       suspend_cleanup_usm();
4252 +}
4253 +
4254 +void save_restore_resume2(int replace, int quiet)
4255 +{
4256 +       static char resume2_save[255];
4257 +       static unsigned long suspend_state_save;
4258 +
4259 +       if (replace) {
4260 +               suspend_state_save = suspend_state;
4261 +               strcpy(resume2_save, resume2_file);
4262 +               strcpy(resume2_file, poweroff_resume2); 
4263 +       } else {
4264 +               strcpy(resume2_file, resume2_save);
4265 +               suspend_state = suspend_state_save;
4266 +       }
4267 +       suspend_attempt_to_parse_resume_device(quiet);
4268 +}
4269 +
4270 +void attempt_to_parse_po_resume_device2(void)
4271 +{
4272 +       int ok = 0;
4273 +
4274 +       /* Temporarily set resume2 to the poweroff value */
4275 +       if (!strlen(poweroff_resume2))
4276 +               return;
4277 +
4278 +       printk("=== Trying Poweroff Resume2 ===\n");
4279 +       save_restore_resume2(SAVE, NOQUIET);
4280 +       if (test_suspend_state(SUSPEND_CAN_RESUME))
4281 +               ok = 1;
4282 +       
4283 +       printk("=== Done ===\n");
4284 +       save_restore_resume2(RESTORE, QUIET);
4285 +       
4286 +       /* If not ok, clear the string */
4287 +       if (ok)
4288 +               return;
4289 +
4290 +       printk("Can't resume from that location; clearing poweroff_resume2.\n");
4291 +       poweroff_resume2[0] = '\0';
4292 +}
4293 +
4294 +/* noresume_reset_modules
4295 + *
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.
4299 + */
4300 +
4301 +static void noresume_reset_modules(void)
4302 +{
4303 +       struct suspend_module_ops *this_filter;
4304 +       
4305 +       list_for_each_entry(this_filter, &suspend_filters, type_list)
4306 +               if (this_filter->noresume_reset)
4307 +                       this_filter->noresume_reset();
4308 +
4309 +       if (suspendActiveAllocator && suspendActiveAllocator->noresume_reset)
4310 +               suspendActiveAllocator->noresume_reset();
4311 +}
4312 +
4313 +/* fill_suspend_header()
4314 + * 
4315 + * Description:        Fill the suspend header structure.
4316 + * Arguments:  struct suspend_header: Header data structure to be filled.
4317 + */
4318 +
4319 +static void fill_suspend_header(struct suspend_header *sh)
4320 +{
4321 +       int i;
4322 +       
4323 +       memset((char *)sh, 0, sizeof(*sh));
4324 +
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];
4338 +}
4339 +
4340 +/*
4341 + * rw_init_modules
4342 + *
4343 + * Iterate over modules, preparing the ones that will be used to read or write
4344 + * data.
4345 + */
4346 +static int rw_init_modules(int rw, int which)
4347 +{
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)
4352 +                       continue;
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);
4357 +                       return 1;
4358 +               }
4359 +       }
4360 +
4361 +       /* Initialise allocator */
4362 +       if (suspendActiveAllocator->rw_init(rw, which)) {
4363 +               abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4364 +                               "Failed to initialise the allocator."); 
4365 +               if (!rw)
4366 +                       suspendActiveAllocator->invalidate_image();
4367 +               return 1;
4368 +       }
4369 +
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)
4375 +                       continue;
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");
4379 +                       return 1;
4380 +               }
4381 +       }
4382 +
4383 +       return 0;
4384 +}
4385 +
4386 +/*
4387 + * rw_cleanup_modules
4388 + *
4389 + * Cleanup components after reading or writing a set of pages.
4390 + * Only the allocator may fail.
4391 + */
4392 +static int rw_cleanup_modules(int rw)
4393 +{
4394 +       struct suspend_module_ops *this_module;
4395 +       int result = 0;
4396 +
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)
4402 +                       continue;
4403 +               if (this_module->rw_cleanup)
4404 +                       result |= this_module->rw_cleanup(rw);
4405 +       }
4406 +
4407 +       /* Flush data and cleanup */
4408 +       list_for_each_entry(this_module, &suspend_filters, type_list) {
4409 +               if (!this_module->enabled)
4410 +                       continue;
4411 +               if (this_module->rw_cleanup)
4412 +                       result |= this_module->rw_cleanup(rw);
4413 +       }
4414 +
4415 +       result |= suspendActiveAllocator->rw_cleanup(rw);
4416 +
4417 +       return result;
4418 +}
4419 +
4420 +static struct page *copy_page_from_orig_page(struct page *orig_page)
4421 +{
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);
4427 +       void *compare;
4428 +
4429 +       if (is_high) {
4430 +               if (*my_last_sought && *my_last_high_page && *my_last_sought < orig_page)
4431 +                       high_page = *my_last_high_page;
4432 +               else
4433 +                       high_page = (struct page *) restore_highmem_pblist;
4434 +               this = (struct pbe *) kmap(high_page);
4435 +               compare = orig_page;
4436 +       } else {
4437 +               if (*my_last_sought && *my_last_low_page && *my_last_sought < orig_page)
4438 +                       this = *my_last_low_page;
4439 +               else
4440 +                       this = restore_pblist;
4441 +               compare = page_address(orig_page);
4442 +       }
4443 +
4444 +       *my_last_sought = orig_page;
4445 +
4446 +       /* Locate page containing pbe */
4447 +       while ( this[PBES_PER_PAGE - 1].next &&
4448 +               this[PBES_PER_PAGE - 1].orig_address < compare) {
4449 +               if (is_high) {
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;
4455 +               } else
4456 +                       this = this[PBES_PER_PAGE - 1].next;
4457 +       }
4458 +
4459 +       /* Do a binary search within the page */
4460 +       min = 0;
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)
4466 +                       max = index;
4467 +               else if (this[index].orig_address == compare) {
4468 +                       if (is_high) {
4469 +                               struct page *page = this[index].address;
4470 +                               *my_last_high_page = high_page;
4471 +                               kunmap(high_page);
4472 +                               return page;
4473 +                       }
4474 +                       *my_last_low_page = this;
4475 +                       return virt_to_page(this[index].address);
4476 +               } else
4477 +                       min = index;
4478 +               index = ((max + min) / 2);
4479 +       };
4480 +
4481 +       if (is_high)
4482 +               kunmap(high_page);
4483 +
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);
4487 +       return NULL;
4488 +}
4489 +
4490 +/*
4491 + * do_rw_loop
4492 + *
4493 + * The main I/O loop for reading or writing pages.
4494 + */
4495 +static int worker_rw_loop(void *data)
4496 +{
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);
4501 +
4502 +       atomic_inc(&worker_thread_count);
4503 +
4504 +       mutex_lock(&io_mutex);
4505 +
4506 +       do {
4507 +               int buf_size;
4508 +
4509 +               /*
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.
4514 +                */
4515 +               if (io_write) {
4516 +                       struct page *page;
4517 +
4518 +                       pfn = get_next_bit_on(io_map, pfn);
4519 +
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));
4524 +                                       BUG();
4525 +                               }
4526 +                               break;
4527 +                       }
4528 +
4529 +                       atomic_dec(&io_count);
4530 +
4531 +                       orig_pfn = pfn;
4532 +                       write_pfn = pfn;
4533 +
4534 +                       /* 
4535 +                        * Other_pfn is updated by all threads, so we're not
4536 +                        * writing the same page multiple times.
4537 +                        */
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;
4542 +                       }
4543 +                       page = pfn_to_page(pfn);
4544 +
4545 +                       my_io_index = io_finish_at - atomic_read(&io_count);
4546 +
4547 +                       mutex_unlock(&io_mutex);
4548 +
4549 +                       result = first_filter->write_chunk(write_pfn, page,
4550 +                                       PAGE_SIZE);
4551 +               } else {
4552 +                       atomic_dec(&io_count);
4553 +                       mutex_unlock(&io_mutex);
4554 +
4555 +                       /* 
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.
4559 +                        */
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);
4564 +                               while (1)
4565 +                                       schedule();
4566 +                       }
4567 +
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);
4575 +                               break;
4576 +                       }
4577 +               }
4578 +
4579 +               if (result) {
4580 +                       io_result = result;
4581 +                       if (io_write) {
4582 +                               printk("Write chunk returned %d.\n", result);
4583 +                               abort_suspend(SUSPEND_FAILED_IO,
4584 +                                       "Failed to write a chunk of the "
4585 +                                       "image.");
4586 +                               mutex_lock(&io_mutex);
4587 +                               break;
4588 +                       }
4589 +                       panic("Read chunk returned (%d)", result);
4590 +               }
4591 +
4592 +               /* 
4593 +                * Discard reads of resaved pages while reading ps2
4594 +                * and unwanted pages while rereading ps2 when aborting.
4595 +                */
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;
4600 +
4601 +                       if (io_pageset == 1 && !load_direct(final_page)) {
4602 +                               copy_page = copy_page_from_orig_page(final_page);
4603 +                               BUG_ON(!copy_page);
4604 +                       }
4605 +
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);
4611 +                               kunmap(buffer);
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);
4616 +                       } else {
4617 +                               mutex_lock(&io_mutex);
4618 +                               atomic_inc(&io_count);
4619 +                               mutex_unlock(&io_mutex);
4620 +                       }
4621 +               }
4622 +
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.
4629 +                */
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));
4634 +
4635 +               if ((my_io_index + 1) == io_pc) {
4636 +                       printk("%d%%...", 20 * io_pc_step);
4637 +                       io_pc_step++;
4638 +                       io_pc = io_finish_at * io_pc_step / 5;
4639 +               }
4640 +               
4641 +               suspend_cond_pause(0, NULL);
4642 +
4643 +               /* 
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.
4647 +                *
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.
4651 +                */
4652 +
4653 +               mutex_lock(&io_mutex);
4654 +
4655 +       } while(atomic_read(&io_count) >= atomic_read(&worker_thread_count) &&
4656 +               !(io_write && test_result_state(SUSPEND_ABORTED)));
4657 +
4658 +       atomic_dec(&worker_thread_count);
4659 +       mutex_unlock(&io_mutex);
4660 +
4661 +       __free_pages(buffer, 0);
4662 +
4663 +       return 0;
4664 +}
4665 +
4666 +void start_other_threads(void)
4667 +{
4668 +       int cpu;
4669 +       struct task_struct *p;
4670 +
4671 +       for_each_online_cpu(cpu) {
4672 +               if (cpu == smp_processor_id())
4673 +                       continue;
4674 +
4675 +               p = kthread_create(worker_rw_loop, NULL, "ks2io/%d", cpu);
4676 +               if (IS_ERR(p)) {
4677 +                       printk("ks2io for %i failed\n", cpu);
4678 +                       continue;
4679 +               }
4680 +               kthread_bind(p, cpu);
4681 +               wake_up_process(p);
4682 +       }
4683 +}
4684 +
4685 +/*
4686 + * do_rw_loop
4687 + *
4688 + * The main I/O loop for reading or writing pages.
4689 + */
4690 +static int do_rw_loop(int write, int finish_at, dyn_pageflags_t *pageflags,
4691 +               int base, int barmax, int pageset)
4692 +{
4693 +       int index = 0, cpu;
4694 +
4695 +       if (!finish_at)
4696 +               return 0;
4697 +
4698 +       io_write = write;
4699 +       io_finish_at = finish_at;
4700 +       io_base = base;
4701 +       io_barmax = barmax;
4702 +       io_pageset = pageset;
4703 +       io_index = 0;
4704 +       io_pc = io_finish_at / 5;
4705 +       io_pc_step = 1;
4706 +       io_result = 0;
4707 +       io_nextupdate = 0;
4708 +
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;
4713 +       }
4714 +
4715 +       /* Ensure all bits clear */
4716 +       pfn = get_next_bit_on(io_map, max_pfn + 1);
4717 +
4718 +       while (pfn < max_pfn + 1) {
4719 +               clear_dynpageflag(&io_map, pfn_to_page(pfn));
4720 +               pfn = get_next_bit_on(io_map, pfn);
4721 +       }
4722 +
4723 +       /* Set the bits for the pages to write */
4724 +       pfn = get_next_bit_on(*pageflags, max_pfn + 1);
4725 +
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);
4729 +               index++;
4730 +       }
4731 +
4732 +       BUG_ON(index < finish_at);
4733 +
4734 +       atomic_set(&io_count, finish_at);
4735 +
4736 +       pfn = max_pfn + 1;
4737 +       other_pfn = pfn;
4738 +
4739 +       clear_suspend_state(SUSPEND_IO_STOPPED);
4740 +
4741 +       if (!test_action_state(SUSPEND_NO_MULTITHREADED_IO))
4742 +               start_other_threads();
4743 +       worker_rw_loop(NULL);
4744 +
4745 +       while (atomic_read(&worker_thread_count))
4746 +               schedule();
4747 +
4748 +       set_suspend_state(SUSPEND_IO_STOPPED);
4749 +       if (unlikely(test_suspend_state(SUSPEND_STOP_RESUME))) {
4750 +               while (1)
4751 +                       schedule();
4752 +       }
4753 +
4754 +       if (!io_result) {
4755 +               printk("done.\n");
4756 +
4757 +               suspend_update_status(io_base + io_finish_at, io_barmax, " %d/%d MB ",
4758 +                               MB(io_base + io_finish_at), MB(io_barmax));
4759 +       }
4760 +
4761 +       if (io_write && test_result_state(SUSPEND_ABORTED))
4762 +               io_result = 1;
4763 +       else /* All I/O done? */
4764 +               BUG_ON(get_next_bit_on(io_map, max_pfn + 1) != max_pfn + 1);
4765 +
4766 +       return io_result;
4767 +}
4768 +
4769 +/* write_pageset()
4770 + *
4771 + * Description:        Write a pageset to disk.
4772 + * Arguments:  pagedir:        Which pagedir to write..
4773 + * Returns:    Zero on success or -1 on failure.
4774 + */
4775 +
4776 +int write_pageset(struct pagedir *pagedir)
4777 +{
4778 +       int finish_at, base = 0, start_time, end_time;
4779 +       int barmax = pagedir1.size + pagedir2.size;
4780 +       long error = 0;
4781 +       dyn_pageflags_t *pageflags;
4782 +
4783 +       /* 
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).
4787 +        */
4788 +       finish_at = pagedir->size;
4789 +
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;
4797 +               else
4798 +                       pageflags = &pageset1_copy_map;
4799 +       } else {
4800 +               suspend_prepare_status(CLEAR_BAR, "Writing caches...");
4801 +               pageflags = &pageset2_map;
4802 +       }       
4803 +       
4804 +       start_time = jiffies;
4805 +
4806 +       if (rw_init_modules(1, pagedir->id)) {
4807 +               abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4808 +                               "Failed to initialise modules for writing.");
4809 +               error = 1;
4810 +       }
4811 +
4812 +       if (!error)
4813 +               error = do_rw_loop(1, finish_at, pageflags, base, barmax,
4814 +                               pagedir->id);
4815 +
4816 +       if (rw_cleanup_modules(WRITE) && !error) {
4817 +               abort_suspend(SUSPEND_FAILED_MODULE_CLEANUP,
4818 +                               "Failed to cleanup after writing.");
4819 +               error = 1;
4820 +       }
4821 +
4822 +       end_time = jiffies;
4823 +       
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);
4827 +       }
4828 +
4829 +       return error;
4830 +}
4831 +
4832 +/* read_pageset()
4833 + *
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
4837 + *             only part.
4838 + * Returns:    Zero on success or -1 on failure.
4839 + */
4840 +
4841 +static int read_pageset(struct pagedir *pagedir, int overwrittenpagesonly)
4842 +{
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;
4847 +
4848 +       if (pagedir->id == 1) {
4849 +               suspend_prepare_status(CLEAR_BAR,
4850 +                               "Reading kernel & process data...");
4851 +               pageflags = &pageset1_map;
4852 +       } else {
4853 +               suspend_prepare_status(DONT_CLEAR_BAR, "Reading caches...");
4854 +               if (overwrittenpagesonly)
4855 +                       barmax = finish_at = min(pagedir1.size, 
4856 +                                                pagedir2.size);
4857 +               else {
4858 +                       base = pagedir1.size;
4859 +               }
4860 +               pageflags = &pageset2_map;
4861 +       }       
4862 +       
4863 +       start_time = jiffies;
4864 +
4865 +       if (rw_init_modules(0, pagedir->id)) {
4866 +               suspendActiveAllocator->invalidate_image();
4867 +               result = 1;
4868 +       } else
4869 +               result = do_rw_loop(0, finish_at, pageflags, base, barmax,
4870 +                               pagedir->id);
4871 +
4872 +       if (rw_cleanup_modules(READ) && !result) {
4873 +               abort_suspend(SUSPEND_FAILED_MODULE_CLEANUP,
4874 +                               "Failed to cleanup after reading.");
4875 +               result = 1;
4876 +       }
4877 +
4878 +       /* Statistics */
4879 +       end_time=jiffies;
4880 +
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);
4884 +       }
4885 +
4886 +       return result;
4887 +}
4888 +
4889 +/* write_module_configs()
4890 + *
4891 + * Description:        Store the configuration for each module in the image header.
4892 + * Returns:    Int: Zero on success, Error value otherwise.
4893 + */
4894 +static int write_module_configs(void)
4895 +{
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;
4900 +
4901 +       if (!buffer) {
4902 +               printk("Failed to allocate a buffer for saving "
4903 +                               "module configuration info.\n");
4904 +               return -ENOMEM;
4905 +       }
4906 +               
4907 +       /* 
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.
4911 +        */
4912 +
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))
4918 +                       continue;
4919 +
4920 +               /* Get the data from the module */
4921 +               len = 0;
4922 +               if (this_module->save_config_info)
4923 +                       len = this_module->save_config_info(buffer);
4924 +
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,
4932 +                               this_module,
4933 +                               (char *) &suspend_module_header,
4934 +                               sizeof(suspend_module_header));
4935 +
4936 +               /* Save the size of the data and any data returned */
4937 +               suspendActiveAllocator->rw_header_chunk(WRITE,
4938 +                               this_module,
4939 +                               (char *) &len, sizeof(int));
4940 +               if (len)
4941 +                       suspendActiveAllocator->rw_header_chunk(
4942 +                               WRITE, this_module, buffer, len);
4943 +       }
4944 +
4945 +       /* Write a blank header to terminate the list */
4946 +       suspend_module_header.name[0] = '\0';
4947 +       suspendActiveAllocator->rw_header_chunk(WRITE, 
4948 +                       NULL,
4949 +                       (char *) &suspend_module_header,
4950 +                       sizeof(suspend_module_header));
4951 +
4952 +       free_page((unsigned long) buffer);
4953 +       return 0;
4954 +}
4955 +
4956 +/* read_module_configs()
4957 + *
4958 + * Description:        Reload module configurations from the image header.
4959 + * Returns:    Int. Zero on success, error value otherwise.
4960 + */
4961 +
4962 +static int read_module_configs(void)
4963 +{
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;
4968 +
4969 +       if (!buffer) {
4970 +               printk("Failed to allocate a buffer for reloading module "
4971 +                               "configuration info.\n");
4972 +               return -ENOMEM;
4973 +       }
4974 +               
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.
4978 +        */
4979 +       list_for_each_entry(this_module, &suspend_modules, module_list)
4980 +               this_module->enabled = 0;
4981 +       
4982 +       /* Get the first module header */
4983 +       result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
4984 +                       (char *) &suspend_module_header,
4985 +                       sizeof(suspend_module_header));
4986 +       if (result) {
4987 +               printk("Failed to read the next module header.\n");
4988 +               free_page((unsigned long) buffer);
4989 +               return -EINVAL;
4990 +       }
4991 +
4992 +       /* For each module (in registration order) */
4993 +       while (suspend_module_header.name[0]) {
4994 +
4995 +               /* Find the module */
4996 +               this_module = suspend_find_module_given_name(suspend_module_header.name);
4997 +
4998 +               if (!this_module) {
4999 +                       /* 
5000 +                        * Is it used? Only need to worry about filters. The active
5001 +                        * allocator must be loaded!
5002 +                        */
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 "
5007 +                                       "registered.\n",
5008 +                                       suspend_module_header.name);
5009 +                               if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
5010 +                                       suspendActiveAllocator->invalidate_image();
5011 +                                       free_page((unsigned long) buffer);
5012 +                                       return -EINVAL;
5013 +                               }
5014 +                       } else
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);
5020 +               }
5021 +               
5022 +               /* Get the length of the data (if any) */
5023 +               result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5024 +                               (char *) &len, sizeof(int));
5025 +               if (result) {
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);
5030 +                       return -EINVAL;
5031 +               }
5032 +
5033 +               /* Read any data and pass to the module (if we found one) */
5034 +               if (len) {
5035 +                       suspendActiveAllocator->rw_header_chunk(READ, NULL,
5036 +                                       buffer, len);
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);
5043 +                               } else
5044 +                                       this_module->load_config_info(buffer, len);
5045 +                       }
5046 +               }
5047 +
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!).
5055 +                        */
5056 +
5057 +                       suspend_move_module_tail(this_module);
5058 +
5059 +                       /* 
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.
5063 +                        */
5064 +                       this_module->enabled = suspend_module_header.enabled;
5065 +               }
5066 +
5067 +               /* Get the next module header */
5068 +               result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5069 +                               (char *) &suspend_module_header,
5070 +                               sizeof(suspend_module_header));
5071 +
5072 +               if (result) {
5073 +                       printk("Failed to read the next module header.\n");
5074 +                       free_page((unsigned long) buffer);
5075 +                       return -EINVAL;
5076 +               }
5077 +
5078 +       }
5079 +
5080 +       free_page((unsigned long) buffer);
5081 +       return 0;
5082 +}
5083 +
5084 +/* write_image_header()
5085 + *
5086 + * Description:        Write the image header after write the image proper.
5087 + * Returns:    Int. Zero on success or -1 on failure.
5088 + */
5089 +
5090 +int write_image_header(void)
5091 +{
5092 +       int ret;
5093 +       int total = pagedir1.size + pagedir2.size+2;
5094 +       char *header_buffer = NULL;
5095 +
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;
5102 +       }
5103 +
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;
5110 +       }
5111 +
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));
5116 +
5117 +       free_page((unsigned long) header_buffer);
5118 +
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;
5124 +       }
5125 +
5126 +       save_dyn_pageflags(pageset1_map);
5127 +
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;
5133 +       }
5134 +
5135 +       if (test_result_state(SUSPEND_ABORTED))
5136 +               goto write_image_header_abort_no_cleanup;
5137 +
5138 +       suspend_message(SUSPEND_IO, SUSPEND_VERBOSE, 1, "|\n");
5139 +       suspend_update_status(total, total, NULL);
5140 +
5141 +       return 0;
5142 +
5143 +write_image_header_abort:
5144 +       suspendActiveAllocator->write_header_cleanup();
5145 +write_image_header_abort_no_cleanup:
5146 +       return -1;
5147 +}
5148 +
5149 +/* sanity_check()
5150 + *
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
5156 + *             time.
5157 + */
5158 +static char *sanity_check(struct suspend_header *sh)
5159 +{
5160 +       if (sh->version_code != LINUX_VERSION_CODE)
5161 +               return "Incorrect kernel version.";
5162 +       
5163 +       if (sh->num_physpages != num_physpages)
5164 +               return "Incorrect memory size.";
5165 +
5166 +       if (strncmp(sh->uts.sysname, init_utsname()->sysname, 65))
5167 +               return "Incorrect system type.";
5168 +
5169 +       if (strncmp(sh->uts.release, init_utsname()->release, 65))
5170 +               return "Incorrect release.";
5171 +
5172 +       if (strncmp(sh->uts.version, init_utsname()->version, 65))
5173 +               return "Right kernel version but wrong build number.";
5174 +
5175 +       if (strncmp(sh->uts.machine, init_utsname()->machine, 65))
5176 +               return "Incorrect machine type.";
5177 +
5178 +       if (sh->page_size != PAGE_SIZE)
5179 +               return "Incorrect PAGE_SIZE.";
5180 +
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 "
5188 +                                       "is mounted rw.";
5189 +               }
5190 +       }
5191 +
5192 +       return 0;
5193 +}
5194 +
5195 +/* __read_pageset1
5196 + *
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.
5200 + */
5201 +static int __read_pageset1(void)
5202 +{                      
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;
5207 +
5208 +       if (!header_buffer) {
5209 +               printk("Unable to allocate a page for reading the signature.\n");
5210 +               return -ENOMEM;
5211 +       }
5212 +       
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");
5218 +               goto out;
5219 +       }
5220 +
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;
5225 +       }
5226 +
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;
5232 +
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;
5239 +               }
5240 +       }
5241 +
5242 +       clear_suspend_state(SUSPEND_CONTINUE_REQ);
5243 +
5244 +       /* 
5245 +        * Prepare the active allocator for reading the image header. The
5246 +        * activate allocator might read its own configuration.
5247 +        * 
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.
5253 +        */
5254 +
5255 +       if ((result = suspendActiveAllocator->read_header_init())) {
5256 +               printk("Suspend2: Failed to initialise, reading the image "
5257 +                               "header.\n");
5258 +               goto out_invalidate_image;
5259 +       }
5260 +       
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;
5266 +       }
5267 +       
5268 +       suspend_header = (struct suspend_header *) header_buffer;
5269 +
5270 +       /*
5271 +        * NB: This call may also result in a reboot rather than returning.
5272 +        */
5273 +
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;
5278 +       }
5279 +
5280 +       /*
5281 +        * We have an image and it looks like it will load okay.
5282 +        *
5283 +        * Get metadata from header. Don't override commandline parameters.
5284 +        *
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.
5287 +        */
5288 +       
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];
5300 +
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;
5308 +       }
5309 +
5310 +       suspend_prepare_console();
5311 +
5312 +       set_suspend_state(SUSPEND_NOW_RESUMING);
5313 +
5314 +       if (pre_resume_freeze())
5315 +               goto out_reset_console;
5316 +
5317 +       suspend_cond_pause(1, "About to read original pageset1 locations.");
5318 +
5319 +       /*
5320 +        * Read original pageset1 locations. These are the addresses we can't
5321 +        * use for the data to be restored.
5322 +        */
5323 +
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;
5328 +
5329 +       if (load_dyn_pageflags(pageset1_map))
5330 +               goto out_reset_console;
5331 +
5332 +       /* Clean up after reading the header */
5333 +       if ((result = suspendActiveAllocator->read_header_cleanup())) {
5334 +               printk("Suspend2: Failed to cleanup after reading the image "
5335 +                               "header.\n");
5336 +               goto out_reset_console;
5337 +       }
5338 +
5339 +       suspend_cond_pause(1, "About to read pagedir.");
5340 +
5341 +       /* 
5342 +        * Get the addresses of pages into which we will load the kernel to
5343 +        * be copied back
5344 +        */
5345 +       if (suspend_get_pageset1_load_addresses()) {
5346 +               printk("Suspend2: Failed to get load addresses for pageset1.\n");
5347 +               goto out_reset_console;
5348 +       }
5349 +
5350 +       /* Read the original kernel back */
5351 +       suspend_cond_pause(1, "About to read pageset 1.");
5352 +
5353 +       if (read_pageset(&pagedir1, 0)) {
5354 +               suspend_prepare_status(CLEAR_BAR, "Failed to read pageset 1.");
5355 +               result = -EIO;
5356 +               printk("Suspend2: Failed to get load pageset1.\n");
5357 +               goto out_reset_console;
5358 +       }
5359 +
5360 +       suspend_cond_pause(1, "About to restore original kernel.");
5361 +       result = 0;
5362 +
5363 +       if (!test_action_state(SUSPEND_KEEP_IMAGE) &&
5364 +           suspendActiveAllocator->mark_resume_attempted)
5365 +               suspendActiveAllocator->mark_resume_attempted(1);
5366 +
5367 +out:
5368 +       free_page((unsigned long) header_buffer);
5369 +       return result;
5370 +
5371 +out_reset_console:
5372 +       suspend_cleanup_console();
5373 +
5374 +out_invalidate_image:
5375 +       free_dyn_pageflags(&pageset1_map);
5376 +       free_dyn_pageflags(&pageset1_copy_map);
5377 +       free_dyn_pageflags(&io_map);
5378 +       result = -EINVAL;
5379 +       if (!test_action_state(SUSPEND_KEEP_IMAGE))
5380 +               suspendActiveAllocator->invalidate_image();
5381 +       suspendActiveAllocator->read_header_cleanup();
5382 +       noresume_reset_modules();
5383 +       goto out;
5384 +}
5385 +
5386 +/* read_pageset1()
5387 + *
5388 + * Description:        Attempt to read the header and pageset1 of a suspend image.
5389 + *             Handle the outcome, complaining where appropriate.
5390 + */
5391 +
5392 +int read_pageset1(void)
5393 +{
5394 +       int error;
5395 +
5396 +       error = __read_pageset1();
5397 +
5398 +       switch (error) {
5399 +               case 0:
5400 +               case -ENODATA:
5401 +               case -EINVAL:   /* non fatal error */
5402 +                       break;
5403 +               default:
5404 +                       if (test_result_state(SUSPEND_ABORTED))
5405 +                               break;
5406 +
5407 +                       abort_suspend(SUSPEND_IMAGE_ERROR,
5408 +                                       "Suspend2: Error %d resuming\n",
5409 +                                       error);
5410 +       }
5411 +       return error;
5412 +}
5413 +
5414 +/*
5415 + * get_have_image_data()
5416 + */
5417 +static char *get_have_image_data(void)
5418 +{
5419 +       char *output_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
5420 +       struct suspend_header *suspend_header;
5421 +
5422 +       if (!output_buffer) {
5423 +               printk("Output buffer null.\n");
5424 +               return NULL;
5425 +       }
5426 +
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");
5433 +               goto out;
5434 +       }
5435 +
5436 +       suspend_header = (struct suspend_header *) output_buffer;
5437 +
5438 +       sprintf(output_buffer, "1\n%s\n%s\n",
5439 +                       suspend_header->uts.machine,
5440 +                       suspend_header->uts.version);
5441 +
5442 +       /* Check whether we've resumed before */
5443 +       if (test_suspend_state(SUSPEND_RESUMED_BEFORE))
5444 +               strcat(output_buffer, "Resumed before.\n");
5445 +
5446 +out:
5447 +       noresume_reset_modules();
5448 +       return output_buffer;
5449 +}
5450 +
5451 +/* read_pageset2()
5452 + *
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 
5456 + *             all.
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.
5460 + */
5461 +int read_pageset2(int overwrittenpagesonly)
5462 +{
5463 +       int result = 0;
5464 +
5465 +       if (!pagedir2.size)
5466 +               return 0;
5467 +
5468 +       result = read_pageset(&pagedir2, overwrittenpagesonly);
5469 +
5470 +       suspend_update_status(100, 100, NULL);
5471 +       suspend_cond_pause(1, "Pagedir 2 read.");
5472 +
5473 +       return result;
5474 +}
5475 +
5476 +/* image_exists_read
5477 + * 
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
5481 + * overflow.
5482 + */
5483 +int image_exists_read(const char *page, int count)
5484 +{
5485 +       int len = 0;
5486 +       char *result;
5487 +       
5488 +       if (suspend_activate_storage(0))
5489 +               return count;
5490 +
5491 +       if (!test_suspend_state(SUSPEND_RESUME_DEVICE_OK))
5492 +               suspend_attempt_to_parse_resume_device(0);
5493 +
5494 +       if (!suspendActiveAllocator) {
5495 +               len = sprintf((char *) page, "-1\n");
5496 +       } else {
5497 +               result = get_have_image_data();
5498 +               if (result) {
5499 +                       len = sprintf((char *) page, "%s",  result);
5500 +                       free_page((unsigned long) result);
5501 +               }
5502 +       }
5503 +
5504 +       suspend_deactivate_storage(0);
5505 +
5506 +       return len;
5507 +}
5508 +
5509 +/* image_exists_write
5510 + * 
5511 + * Invalidate an image if one exists.
5512 + */
5513 +int image_exists_write(const char *buffer, int count)
5514 +{
5515 +       if (suspend_activate_storage(0))
5516 +               return count;
5517 +
5518 +       if (suspendActiveAllocator && suspendActiveAllocator->image_exists())
5519 +               suspendActiveAllocator->invalidate_image();
5520 +
5521 +       suspend_deactivate_storage(0);
5522 +
5523 +       clear_result_state(SUSPEND_KEPT_IMAGE);
5524 +
5525 +       return count;
5526 +}
5527 +
5528 +#ifdef CONFIG_SUSPEND2_EXPORTS
5529 +EXPORT_SYMBOL_GPL(suspend_attempt_to_parse_resume_device);
5530 +EXPORT_SYMBOL_GPL(attempt_to_parse_resume_device2);
5531 +#endif
5532 +
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
5536 @@ -0,0 +1,56 @@
5537 +/*
5538 + * kernel/power/io.h
5539 + *
5540 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
5541 + *
5542 + * This file is released under the GPLv2.
5543 + *
5544 + * It contains high level IO routines for suspending.
5545 + *
5546 + */
5547 +
5548 +#include <linux/utsname.h>
5549 +#include "pagedir.h"
5550 +
5551 +/* Non-module data saved in our image header */
5552 +struct suspend_header {
5553 +       u32 version_code;
5554 +       unsigned long num_physpages;
5555 +       unsigned long orig_mem_free;
5556 +       struct new_utsname uts;
5557 +       int num_cpus;
5558 +       int page_size;
5559 +       int pageset_2_size;
5560 +       int param0;
5561 +       int param1;
5562 +       int param2;
5563 +       int param3;
5564 +       int progress0;
5565 +       int progress1;
5566 +       int progress2;
5567 +       int progress3;
5568 +       int io_time[2][2];
5569 +       struct pagedir pagedir;
5570 +       dev_t root_fs;
5571 +};
5572 +
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);
5577 +
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);
5584 +
5585 +/* Args to save_restore_resume2 */
5586 +#define RESTORE 0
5587 +#define SAVE 1
5588 +
5589 +#define NOQUIET 0
5590 +#define QUIET 1
5591 +
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
5596 @@ -272,7 +272,7 @@
5597                 if (pm_states[i] && valid_state(i))
5598                         s += sprintf(s,"%s ", pm_states[i]);
5599         }
5600 -#ifdef CONFIG_SOFTWARE_SUSPEND
5601 +#ifdef CONFIG_SUSPEND_SHARED
5602         s += sprintf(s, "%s\n", "disk");
5603  #else
5604         if (s != buf)
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
5608 @@ -0,0 +1,415 @@
5609 +/*
5610 + * kernel/power/modules.c
5611 + *
5612 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
5613 + *
5614 + */
5615 +
5616 +#include <linux/suspend.h>
5617 +#include <linux/module.h>
5618 +#include "suspend.h"
5619 +#include "modules.h"
5620 +#include "sysfs.h"
5621 +#include "ui.h"
5622 +
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;
5627 +int initialised;
5628 +       
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);
5633 +}
5634 +
5635 +/*
5636 + * suspend_header_storage_for_modules
5637 + *
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.
5642 + */
5643 +int suspend_header_storage_for_modules(void)
5644 +{
5645 +       struct suspend_module_ops *this_module;
5646 +       int bytes = 0;
5647 +       
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))
5652 +                       continue;
5653 +               if (this_module->storage_needed) {
5654 +                       int this = this_module->storage_needed() +
5655 +                               sizeof(struct suspend_module_header) +
5656 +                               sizeof(int);
5657 +                       this_module->header_requested = this;
5658 +                       bytes += this;
5659 +               }
5660 +       }
5661 +
5662 +       /* One more for the empty terminator */
5663 +       return bytes + sizeof(struct suspend_module_header);
5664 +}
5665 +
5666 +/*
5667 + * suspend_memory_for_modules
5668 + *
5669 + * Returns the amount of memory requested by modules for
5670 + * doing their work during the cycle.
5671 + */
5672 +
5673 +int suspend_memory_for_modules(void)
5674 +{
5675 +       int bytes = 0;
5676 +       struct suspend_module_ops *this_module;
5677 +
5678 +       list_for_each_entry(this_module, &suspend_modules, module_list) {
5679 +               if (!this_module->enabled)
5680 +                       continue;
5681 +               if (this_module->memory_needed)
5682 +                       bytes += this_module->memory_needed();
5683 +       }
5684 +
5685 +       return ((bytes + PAGE_SIZE - 1) >> PAGE_SHIFT);
5686 +}
5687 +
5688 +/*
5689 + * suspend_expected_compression_ratio
5690 + *
5691 + * Returns the compression ratio expected when saving the image.
5692 + */
5693 +
5694 +int suspend_expected_compression_ratio(void)
5695 +{
5696 +       int ratio = 100;
5697 +       struct suspend_module_ops *this_module;
5698 +
5699 +       list_for_each_entry(this_module, &suspend_modules, module_list) {
5700 +               if (!this_module->enabled)
5701 +                       continue;
5702 +               if (this_module->expected_compression)
5703 +                       ratio = ratio * this_module->expected_compression() / 100;
5704 +       }
5705 +
5706 +       return ratio;
5707 +}
5708 +
5709 +/* suspend_find_module_given_name
5710 + * Functionality :     Return a module (if found), given a pointer
5711 + *                     to its name
5712 + */
5713 +
5714 +struct suspend_module_ops *suspend_find_module_given_name(char *name)
5715 +{
5716 +       struct suspend_module_ops *this_module, *found_module = NULL;
5717 +       
5718 +       list_for_each_entry(this_module, &suspend_modules, module_list) {
5719 +               if (!strcmp(name, this_module->name)) {
5720 +                       found_module = this_module;
5721 +                       break;
5722 +               }                       
5723 +       }
5724 +
5725 +       return found_module;
5726 +}
5727 +
5728 +/*
5729 + * suspend_print_module_debug_info
5730 + * Functionality   : Get debugging info from modules into a buffer.
5731 + */
5732 +int suspend_print_module_debug_info(char *buffer, int buffer_size)
5733 +{
5734 +       struct suspend_module_ops *this_module;
5735 +       int len = 0;
5736 +
5737 +       list_for_each_entry(this_module, &suspend_modules, module_list) {
5738 +               if (!this_module->enabled)
5739 +                       continue;
5740 +               if (this_module->print_debug_info) {
5741 +                       int result;
5742 +                       result = this_module->print_debug_info(buffer + len, 
5743 +                                       buffer_size - len);
5744 +                       len += result;
5745 +               }
5746 +       }
5747 +
5748 +       /* Ensure null terminated */
5749 +       buffer[buffer_size] = 0;
5750 +
5751 +       return len;
5752 +}
5753 +
5754 +/*
5755 + * suspend_register_module
5756 + *
5757 + * Register a module.
5758 + */
5759 +int suspend_register_module(struct suspend_module_ops *module)
5760 +{
5761 +       int i;
5762 +       struct kobject *kobj;
5763 +
5764 +       if (!initialised) {
5765 +               suspend_initialise_module_lists();
5766 +               initialised = 1;
5767 +       }
5768 +
5769 +       module->enabled = 1;
5770 +       
5771 +       if (suspend_find_module_given_name(module->name)) {
5772 +               printk("Suspend2: Trying to load module %s,"
5773 +                               " which is already registered.\n",
5774 +                               module->name);
5775 +               return -EBUSY;
5776 +       }
5777 +
5778 +       switch (module->type) {
5779 +               case FILTER_MODULE:
5780 +                       list_add_tail(&module->type_list,
5781 +                                       &suspend_filters);
5782 +                       suspend_num_filters++;
5783 +                       break;
5784 +
5785 +               case WRITER_MODULE:
5786 +                       list_add_tail(&module->type_list,
5787 +                                       &suspendAllocators);
5788 +                       suspendNumAllocators++;
5789 +                       break;
5790 +
5791 +               case MISC_MODULE:
5792 +                       break;
5793 +
5794 +               default:
5795 +                       printk("Hmmm. Module '%s' has an invalid type."
5796 +                               " It has been ignored.\n", module->name);
5797 +                       return -EINVAL;
5798 +       }
5799 +       list_add_tail(&module->module_list, &suspend_modules);
5800 +       suspend_num_modules++;
5801 +
5802 +       if (module->directory || module->shared_directory) {
5803 +               /* 
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.
5807 +                */
5808 +               if (module->shared_directory) {
5809 +                       struct suspend_module_ops *shared =
5810 +                               suspend_find_module_given_name(module->shared_directory);
5811 +                       if (!shared) {
5812 +                               printk("Suspend2: Module %s wants to share %s's directory but %s isn't loaded.\n",
5813 +                                               module->name,
5814 +                                               module->shared_directory,
5815 +                                               module->shared_directory);
5816 +                               suspend_unregister_module(module);
5817 +                               return -ENODEV;
5818 +                       }
5819 +                       kobj = shared->dir_kobj;
5820 +               } else
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]);
5825 +                       if (result)
5826 +                               return result;
5827 +               }
5828 +       }
5829 +
5830 +       printk("Suspend2 %s support registered.\n", module->name);
5831 +       return 0;
5832 +}
5833 +
5834 +/*
5835 + * suspend_unregister_module
5836 + *
5837 + * Remove a module.
5838 + */
5839 +void suspend_unregister_module(struct suspend_module_ops *module)
5840 +{
5841 +       int i;
5842 +
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]);
5846 +
5847 +       if (!module->shared_directory && module->directory)
5848 +               remove_suspend2_sysdir(module->dir_kobj);
5849 +
5850 +       switch (module->type) {
5851 +               case FILTER_MODULE:
5852 +                       list_del(&module->type_list);
5853 +                       suspend_num_filters--;
5854 +                       break;
5855 +
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);
5863 +                       }
5864 +                       break;
5865 +               
5866 +               case MISC_MODULE:
5867 +                       break;
5868 +
5869 +               default:
5870 +                       printk("Hmmm. Module '%s' has an invalid type."
5871 +                               " It has been ignored.\n", module->name);
5872 +                       return;
5873 +       }
5874 +       list_del(&module->module_list);
5875 +       suspend_num_modules--;
5876 +       printk("Suspend2 %s module unloaded.\n", module->name);
5877 +}
5878 +
5879 +/*
5880 + * suspend_move_module_tail
5881 + *
5882 + * Rearrange modules when reloading the config.
5883 + */
5884 +void suspend_move_module_tail(struct suspend_module_ops *module)
5885 +{
5886 +       switch (module->type) {
5887 +               case FILTER_MODULE:
5888 +                       if (suspend_num_filters > 1)
5889 +                               list_move_tail(&module->type_list,
5890 +                                               &suspend_filters);
5891 +                       break;
5892 +
5893 +               case WRITER_MODULE:
5894 +                       if (suspendNumAllocators > 1)
5895 +                               list_move_tail(&module->type_list,
5896 +                                               &suspendAllocators);
5897 +                       break;
5898 +               
5899 +               case MISC_MODULE:
5900 +                       break;
5901 +               default:
5902 +                       printk("Hmmm. Module '%s' has an invalid type."
5903 +                               " It has been ignored.\n", module->name);
5904 +                       return;
5905 +       }
5906 +       if ((suspend_num_filters + suspendNumAllocators) > 1)
5907 +               list_move_tail(&module->module_list, &suspend_modules);
5908 +}
5909 +
5910 +/*
5911 + * suspend_initialise_modules
5912 + *
5913 + * Get ready to do some work!
5914 + */
5915 +int suspend_initialise_modules(int starting_cycle)
5916 +{
5917 +       struct suspend_module_ops *this_module;
5918 +       int result;
5919 +       
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)
5924 +                       continue;
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);
5932 +                               return result;
5933 +                       }
5934 +               }
5935 +       }
5936 +
5937 +       return 0;
5938 +}
5939 +
5940 +/* 
5941 + * suspend_cleanup_modules
5942 + *
5943 + * Tell modules the work is done.
5944 + */
5945 +void suspend_cleanup_modules(int finishing_cycle)
5946 +{
5947 +       struct suspend_module_ops *this_module;
5948 +       
5949 +       list_for_each_entry(this_module, &suspend_modules, module_list) {
5950 +               if (!this_module->enabled)
5951 +                       continue;
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);
5957 +               }
5958 +       }
5959 +}
5960 +
5961 +/*
5962 + * suspend_get_next_filter
5963 + *
5964 + * Get the next filter in the pipeline.
5965 + */
5966 +struct suspend_module_ops *suspend_get_next_filter(struct suspend_module_ops *filter_sought)
5967 +{
5968 +       struct suspend_module_ops *last_filter = NULL, *this_filter = NULL;
5969 +
5970 +       list_for_each_entry(this_filter, &suspend_filters, type_list) {
5971 +               if (!this_filter->enabled)
5972 +                       continue;
5973 +               if ((last_filter == filter_sought) || (!filter_sought))
5974 +                       return this_filter;
5975 +               last_filter = this_filter;
5976 +       }
5977 +
5978 +       return suspendActiveAllocator;
5979 +}
5980 +
5981 +/* suspend_get_modules
5982 + * 
5983 + * Take a reference to modules so they can't go away under us.
5984 + */
5985 +
5986 +int suspend_get_modules(void)
5987 +{
5988 +       struct suspend_module_ops *this_module;
5989 +       
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)
5996 +                                       return -EINVAL;
5997 +                               module_put(this_module2->module);
5998 +                       }
5999 +               }
6000 +       }
6001 +
6002 +       return 0;
6003 +}
6004 +
6005 +/* suspend_put_modules
6006 + *
6007 + * Release our references to modules we used.
6008 + */
6009 +
6010 +void suspend_put_modules(void)
6011 +{
6012 +       struct suspend_module_ops *this_module;
6013 +       
6014 +       list_for_each_entry(this_module, &suspend_modules, module_list)
6015 +               module_put(this_module->module);
6016 +}
6017 +
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);
6023 +#endif
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
6027 @@ -0,0 +1,164 @@
6028 +/*
6029 + * kernel/power/modules.h
6030 + *
6031 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6032 + *
6033 + * This file is released under the GPLv2.
6034 + *
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.
6038 + *
6039 + */
6040 +
6041 +#ifndef SUSPEND_MODULES_H
6042 +#define SUSPEND_MODULES_H
6043 +
6044 +/* This is the maximum size we store in the image header for a module name */
6045 +#define SUSPEND_MAX_MODULE_NAME_LENGTH 30
6046 +
6047 +/* Per-module metadata */
6048 +struct suspend_module_header {
6049 +       char name[SUSPEND_MAX_MODULE_NAME_LENGTH];
6050 +       int enabled;
6051 +       int type;
6052 +       int index;
6053 +       int data_length;
6054 +       unsigned long signature;
6055 +};
6056 +
6057 +enum {
6058 +       FILTER_MODULE,
6059 +       WRITER_MODULE,
6060 +       MISC_MODULE /* Block writer, eg. */
6061 +};
6062 +
6063 +enum {
6064 +       SUSPEND_ASYNC,
6065 +       SUSPEND_SYNC
6066 +};
6067 +
6068 +struct suspend_module_ops {
6069 +       /* Functions common to all modules */
6070 +       int type;
6071 +       char *name;
6072 +       char *directory;
6073 +       char *shared_directory;
6074 +       struct kobject *dir_kobj;
6075 +       struct module *module;
6076 +       int enabled;
6077 +       struct list_head module_list;
6078 +
6079 +       /* List of filters or allocators */
6080 +       struct list_head list, type_list;
6081 +
6082 +       /*
6083 +        * Requirements for memory and storage in
6084 +        * the image header..
6085 +        */
6086 +       int (*memory_needed) (void);
6087 +       int (*storage_needed) (void);
6088 +
6089 +       int header_requested, header_used;
6090 +
6091 +       int (*expected_compression) (void);
6092 +       
6093 +       /* 
6094 +        * Debug info
6095 +        */
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);
6099 +
6100 +       /* 
6101 +        * Initialise & cleanup - general routines called
6102 +        * at the start and end of a cycle.
6103 +        */
6104 +       int (*initialise) (int starting_cycle);
6105 +       void (*cleanup) (int finishing_cycle);
6106 +
6107 +       /* 
6108 +        * Calls for allocating storage (allocators only).
6109 +        *
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.
6116 +        */
6117 +
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);
6123 +       
6124 +       /*
6125 +        * Routines used in image I/O.
6126 +        */
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);
6133 +
6134 +       /* Reset module if image exists but reading aborted */
6135 +       void (*noresume_reset) (void);
6136 +
6137 +       /* Read and write the metadata */       
6138 +       int (*write_header_init) (void);
6139 +       int (*write_header_cleanup) (void);
6140 +
6141 +       int (*read_header_init) (void);
6142 +       int (*read_header_cleanup) (void);
6143 +
6144 +       int (*rw_header_chunk) (int rw, struct suspend_module_ops *owner,
6145 +                       char *buffer_start, int buffer_size);
6146 +       
6147 +       /* Attempt to parse an image location */
6148 +       int (*parse_sig_location) (char *buffer, int only_writer, int quiet);
6149 +
6150 +       /* Determine whether image exists that we can restore */
6151 +       int (*image_exists) (void);
6152 +       
6153 +       /* Mark the image as having tried to resume */
6154 +       void (*mark_resume_attempted) (int);
6155 +
6156 +       /* Destroy image if one exists */
6157 +       int (*invalidate_image) (void);
6158 +       
6159 +       /* Sysfs Data */
6160 +       struct suspend_sysfs_data *sysfs_data;
6161 +       int num_sysfs_entries;
6162 +};
6163 +
6164 +extern int suspend_num_modules, suspendNumAllocators;
6165 +
6166 +extern struct suspend_module_ops *suspendActiveAllocator;
6167 +extern struct list_head suspend_filters, suspendAllocators, suspend_modules;
6168 +
6169 +extern void suspend_prepare_console_modules(void);
6170 +extern void suspend_cleanup_console_modules(void);
6171 +
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 *);
6174 +
6175 +extern int suspend_register_module(struct suspend_module_ops *module);
6176 +extern void suspend_move_module_tail(struct suspend_module_ops *module);
6177 +
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);
6181 +
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);
6185 +
6186 +extern int suspend_initialise_modules(int starting_cycle);
6187 +extern void suspend_cleanup_modules(int finishing_cycle);
6188 +
6189 +int suspend_get_modules(void);
6190 +void suspend_put_modules(void);
6191 +#endif
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
6195 @@ -0,0 +1,387 @@
6196 +/*
6197 + * kernel/power/netlink.c
6198 + *
6199 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6200 + *
6201 + * This file is released under the GPLv2.
6202 + *
6203 + * Functions for communicating with a userspace helper via netlink.
6204 + */
6205 +
6206 +
6207 +#include <linux/suspend.h>
6208 +#include "netlink.h"
6209 +#include "suspend.h"
6210 +#include "modules.h"
6211 +
6212 +struct user_helper_data *uhd_list = NULL;
6213 +
6214 +/* 
6215 + * Refill our pool of SKBs for use in emergencies (eg, when eating memory and none
6216 + * can be allocated).
6217 + */
6218 +static void suspend_fill_skb_pool(struct user_helper_data *uhd)
6219 +{
6220 +       while (uhd->pool_level < uhd->pool_limit) {
6221 +               struct sk_buff *new_skb =
6222 +                       alloc_skb(NLMSG_SPACE(uhd->skb_size), GFP_ATOMIC);
6223 +
6224 +               if (!new_skb)
6225 +                       break;
6226 +
6227 +               new_skb->next = uhd->emerg_skbs;
6228 +               uhd->emerg_skbs = new_skb;
6229 +               uhd->pool_level++;
6230 +       }
6231 +}
6232 +
6233 +/* 
6234 + * Try to allocate a single skb. If we can't get one, try to use one from
6235 + * our pool.
6236 + */
6237 +static struct sk_buff *suspend_get_skb(struct user_helper_data *uhd)
6238 +{
6239 +       struct sk_buff *skb =
6240 +               alloc_skb(NLMSG_SPACE(uhd->skb_size), GFP_ATOMIC);
6241 +
6242 +       if (skb)
6243 +               return skb;
6244 +
6245 +       skb = uhd->emerg_skbs;
6246 +       if (skb) {
6247 +               uhd->pool_level--;
6248 +               uhd->emerg_skbs = skb->next;
6249 +               skb->next = NULL;
6250 +       }
6251 +
6252 +       return skb;
6253 +}
6254 +
6255 +static void put_skb(struct user_helper_data *uhd, struct sk_buff *skb)
6256 +{
6257 +       if (uhd->pool_level < uhd->pool_limit) {
6258 +               skb->next = uhd->emerg_skbs;
6259 +               uhd->emerg_skbs = skb;
6260 +       } else
6261 +               kfree_skb(skb);
6262 +}
6263 +
6264 +void suspend_send_netlink_message(struct user_helper_data *uhd,
6265 +               int type, void* params, size_t len)
6266 +{
6267 +       struct sk_buff *skb;
6268 +       struct nlmsghdr *nlh;
6269 +       void *dest;
6270 +       struct task_struct *t;
6271 +
6272 +       if (uhd->pid == -1)
6273 +               return;
6274 +
6275 +       skb = suspend_get_skb(uhd);
6276 +       if (!skb) {
6277 +               printk("suspend_netlink: Can't allocate skb!\n");
6278 +               return;
6279 +       }
6280 +
6281 +       /* NLMSG_PUT contains a hidden goto nlmsg_failure */
6282 +       nlh = NLMSG_PUT(skb, 0, uhd->sock_seq, type, len);
6283 +       uhd->sock_seq++;
6284 +
6285 +       dest = NLMSG_DATA(nlh);
6286 +       if (params && len > 0)
6287 +               memcpy(dest, params, len);
6288 +
6289 +       netlink_unicast(uhd->nl, skb, uhd->pid, 0);
6290 +
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);
6296 +               return;
6297 +       }
6298 +       wake_up_process(t);
6299 +       read_unlock(&tasklist_lock);
6300 +
6301 +       yield();
6302 +
6303 +       return;
6304 +
6305 +nlmsg_failure:
6306 +       if (skb)
6307 +               put_skb(uhd, skb);
6308 +}
6309 +
6310 +static void send_whether_debugging(struct user_helper_data *uhd)
6311 +{
6312 +       static int is_debugging = 1;
6313 +
6314 +       suspend_send_netlink_message(uhd, NETLINK_MSG_IS_DEBUGGING,
6315 +                       &is_debugging, sizeof(int));
6316 +}
6317 +
6318 +/*
6319 + * Set the PF_NOFREEZE flag on the given process to ensure it can run whilst we
6320 + * are suspending.
6321 + */
6322 +static int nl_set_nofreeze(struct user_helper_data *uhd, int pid)
6323 +{
6324 +       struct task_struct *t;
6325 +
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);
6330 +               return -EINVAL;
6331 +       }
6332 +
6333 +       t->flags |= PF_NOFREEZE;
6334 +
6335 +       read_unlock(&tasklist_lock);
6336 +       uhd->pid = pid;
6337 +
6338 +       suspend_send_netlink_message(uhd, NETLINK_MSG_NOFREEZE_ACK, NULL, 0);
6339 +
6340 +       return 0;
6341 +}
6342 +
6343 +/*
6344 + * Called when the userspace process has informed us that it's ready to roll.
6345 + */
6346 +static int nl_ready(struct user_helper_data *uhd, int version)
6347 +{
6348 +       if (version != uhd->interface_version) {
6349 +               printk("%s userspace process using invalid interface version."
6350 +                               " Trying to continue without it.\n",
6351 +                               uhd->name);
6352 +               if (uhd->not_ready)
6353 +                       uhd->not_ready();
6354 +               return 1;
6355 +       }
6356 +
6357 +       complete(&uhd->wait_for_process);
6358 +
6359 +       return 0;
6360 +}
6361 +
6362 +void suspend_netlink_close_complete(struct user_helper_data *uhd)
6363 +{
6364 +       if (uhd->nl) {
6365 +               sock_release(uhd->nl->sk_socket);
6366 +               uhd->nl = NULL;
6367 +       }
6368 +
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;
6373 +       }
6374 +
6375 +       uhd->pid = -1;
6376 +
6377 +       suspend_put_modules();
6378 +}
6379 +
6380 +static int suspend_nl_gen_rcv_msg(struct user_helper_data *uhd,
6381 +               struct sk_buff *skb, struct nlmsghdr *nlh)
6382 +{
6383 +       int type;
6384 +       int *data;
6385 +       int err;
6386 +
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)
6390 +               return err;
6391 +       
6392 +       type = nlh->nlmsg_type;
6393 +
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");
6397 +               return -EBUSY;
6398 +       }
6399 +
6400 +       data = (int*)NLMSG_DATA(nlh);
6401 +
6402 +       switch (type) {
6403 +               case NETLINK_MSG_NOFREEZE_ME:
6404 +                       if ((err = nl_set_nofreeze(uhd, nlh->nlmsg_pid)) != 0)
6405 +                               return err;
6406 +                       break;
6407 +               case NETLINK_MSG_GET_DEBUGGING:
6408 +                       send_whether_debugging(uhd);
6409 +                       break;
6410 +               case NETLINK_MSG_READY:
6411 +                       if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
6412 +                               printk("Invalid ready mesage.\n");
6413 +                               return -EINVAL;
6414 +                       }
6415 +                       if ((err = nl_ready(uhd, *data)) != 0)
6416 +                               return err;
6417 +                       break;
6418 +               case NETLINK_MSG_CLEANUP:
6419 +                       suspend_netlink_close_complete(uhd);
6420 +                       break;
6421 +       }
6422 +
6423 +       return 0;
6424 +}
6425 +
6426 +static void suspend_user_rcv_skb(struct user_helper_data *uhd,
6427 +                                 struct sk_buff *skb)
6428 +{
6429 +       int err;
6430 +       struct nlmsghdr *nlh;
6431 +
6432 +       while (skb->len >= NLMSG_SPACE(0)) {
6433 +               u32 rlen;
6434 +
6435 +               nlh = (struct nlmsghdr *) skb->data;
6436 +               if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
6437 +                       return;
6438 +
6439 +               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
6440 +               if (rlen > skb->len)
6441 +                       rlen = skb->len;
6442 +
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);
6448 +       }
6449 +}
6450 +
6451 +static void suspend_netlink_input(struct sock *sk, int len)
6452 +{
6453 +       struct user_helper_data *uhd = uhd_list;
6454 +
6455 +       while (uhd && uhd->netlink_id != sk->sk_protocol)
6456 +               uhd= uhd->next;
6457 +
6458 +       do {
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);
6463 +               }
6464 +       } while (uhd->nl && uhd->nl->sk_receive_queue.qlen);
6465 +}
6466 +
6467 +static int netlink_prepare(struct user_helper_data *uhd)
6468 +{
6469 +       suspend_get_modules();
6470 +
6471 +       uhd->next = uhd_list;
6472 +       uhd_list = uhd;
6473 +
6474 +       uhd->sock_seq = 0x42c0ffee;
6475 +       uhd->nl = netlink_kernel_create(uhd->netlink_id, 0,
6476 +                       suspend_netlink_input, NULL, THIS_MODULE);
6477 +       if (!uhd->nl) {
6478 +               printk("Failed to allocate netlink socket for %s.\n",
6479 +                               uhd->name);
6480 +               return -ENOMEM;
6481 +       }
6482 +
6483 +       suspend_fill_skb_pool(uhd);
6484 +
6485 +       return 0;
6486 +}
6487 +
6488 +void suspend_netlink_close(struct user_helper_data *uhd)
6489 +{
6490 +       struct task_struct *t;
6491 +
6492 +       read_lock(&tasklist_lock);
6493 +       if ((t = find_task_by_pid(uhd->pid)))
6494 +               t->flags &= ~PF_NOFREEZE;
6495 +       read_unlock(&tasklist_lock);
6496 +
6497 +       suspend_send_netlink_message(uhd, NETLINK_MSG_CLEANUP, NULL, 0);
6498 +}
6499 +
6500 +static int suspend2_launch_userspace_program(char *command, int channel_no)
6501 +{
6502 +       int retval;
6503 +       static char *envp[] = {
6504 +                       "HOME=/",
6505 +                       "TERM=linux",
6506 +                       "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
6507 +                       NULL };
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;
6513 +
6514 +       if (!strlen(orig_posn))
6515 +               return 1;
6516 +
6517 +       /* Up to 7 args supported */
6518 +       while (arg < 7) {
6519 +               sscanf(orig_posn, "%s", test_read);
6520 +               size = strlen(test_read);
6521 +               if (!(size))
6522 +                       break;
6523 +               argv[arg] = kmalloc(size + 1, GFP_ATOMIC);
6524 +               strcpy(argv[arg], test_read);
6525 +               orig_posn += size + 1;
6526 +               *test_read = 0;
6527 +               arg++;
6528 +       }
6529 +       
6530 +       if (channel_no) {
6531 +               sprintf(channel, "-c%d", channel_no);
6532 +               argv[arg] = channel;
6533 +       } else
6534 +               arg--;
6535 +
6536 +       retval = call_usermodehelper(argv[0], argv, envp, 0);
6537 +
6538 +       if (retval)
6539 +               printk("Failed to launch userspace program '%s': Error %d\n",
6540 +                               command, retval);
6541 +
6542 +       {
6543 +               int i;
6544 +               for (i = 0; i < arg; i++)
6545 +                       if (argv[i] && argv[i] != channel)
6546 +                               kfree(argv[i]);
6547 +       }
6548 +
6549 +       kfree(channel);
6550 +
6551 +       return retval;
6552 +}
6553 +
6554 +int suspend_netlink_setup(struct user_helper_data *uhd)
6555 +{
6556 +       if (netlink_prepare(uhd) < 0) {
6557 +               printk("Netlink prepare failed.\n");
6558 +               return 1;
6559 +       }
6560 +
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);
6564 +               return 1;
6565 +       }
6566 +
6567 +       /* Wait 2 seconds for the userspace process to make contact */
6568 +       wait_for_completion_timeout(&uhd->wait_for_process, 2*HZ);
6569 +
6570 +       if (uhd->pid == -1) {
6571 +               printk("%s: Failed to contact userspace process.\n",
6572 +                               uhd->name);
6573 +               suspend_netlink_close_complete(uhd);
6574 +               return 1;
6575 +       }
6576 +
6577 +       return 0;
6578 +}
6579 +
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
6586 @@ -0,0 +1,58 @@
6587 +/*
6588 + * kernel/power/netlink.h
6589 + *
6590 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6591 + *
6592 + * This file is released under the GPLv2.
6593 + *
6594 + * Declarations for functions for communicating with a userspace helper
6595 + * via netlink.
6596 + */
6597 +
6598 +#include <linux/netlink.h>
6599 +#include <net/sock.h>
6600 +
6601 +#define NETLINK_MSG_BASE 0x10
6602 +
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
6609 +
6610 +struct user_helper_data {
6611 +       int (*rcv_msg) (struct sk_buff *skb, struct nlmsghdr *nlh);
6612 +       void (* not_ready) (void);
6613 +       struct sock *nl;
6614 +       u32 sock_seq;
6615 +       pid_t pid;
6616 +       char *comm;
6617 +       char program[256];
6618 +       int pool_level;
6619 +       int pool_limit;
6620 +       struct sk_buff *emerg_skbs;
6621 +       int skb_size;
6622 +       int netlink_id; 
6623 +       char *name;
6624 +       struct user_helper_data *next;
6625 +       struct completion wait_for_process;
6626 +       int interface_version;
6627 +       int must_init;
6628 +};
6629 +
6630 +#ifdef CONFIG_NET
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);
6635 +#else
6636 +static inline int suspend_netlink_setup(struct user_helper_data *uhd)
6637 +{
6638 +       return 0;
6639 +}
6640 +
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) { };
6644 +#endif
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
6648 @@ -0,0 +1,480 @@
6649 +/*
6650 + * kernel/power/pagedir.c
6651 + *
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)
6656 + *
6657 + * This file is released under the GPLv2.
6658 + *
6659 + * Routines for handling pagesets.
6660 + * Note that pbes aren't actually stored as such. They're stored as
6661 + * bitmaps and extents.
6662 + */
6663 +
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>
6670 +
6671 +#include "pageflags.h"
6672 +#include "ui.h"
6673 +#include "pagedir.h"
6674 +#include "prepare_image.h"
6675 +#include "suspend.h"
6676 +#include "power.h"
6677 +#include "suspend2_builtin.h"
6678 +
6679 +#define PAGESET1 0
6680 +#define PAGESET2 1
6681 +
6682 +static int ps2_pfn;
6683 +
6684 +/*
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.
6688 + */
6689 +
6690 +static void suspend_mark_task_as_pageset(struct task_struct *t, int pageset2)
6691 +{
6692 +       struct vm_area_struct *vma;
6693 +       struct mm_struct *mm;
6694 +
6695 +       mm = t->active_mm;
6696 +
6697 +       if (!mm || !mm->mmap) return;
6698 +
6699 +       if (!irqs_disabled())
6700 +               down_read(&mm->mmap_sem);
6701 +       
6702 +       for (vma = mm->mmap; vma; vma = vma->vm_next) {
6703 +               unsigned long posn;
6704 +
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);
6709 +                       continue;
6710 +               }
6711 +
6712 +               if (!vma->vm_start)
6713 +                       continue;
6714 +
6715 +               for (posn = vma->vm_start; posn < vma->vm_end;
6716 +                               posn += PAGE_SIZE) {
6717 +                       struct page *page = follow_page(vma, posn, 0);
6718 +                       if (!page)
6719 +                               continue;
6720 +
6721 +                       if (pageset2)
6722 +                               SetPagePageset2(page);
6723 +                       else {
6724 +                               ClearPagePageset2(page);
6725 +                               SetPagePageset1(page);
6726 +                       }
6727 +               }
6728 +       }
6729 +
6730 +       if (!irqs_disabled())
6731 +               up_read(&mm->mmap_sem);
6732 +}
6733 +
6734 +static void pageset2_full(void)
6735 +{
6736 +       struct zone *zone;
6737 +       unsigned long flags;
6738 +
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);
6745 +               }
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);
6750 +               }
6751 +               spin_unlock_irqrestore(&zone->lru_lock, flags);
6752 +       }
6753 +}
6754 +
6755 +/* mark_pages_for_pageset2
6756 + *
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.
6761 + */
6762 +
6763 +struct attention_list {
6764 +       struct task_struct *task;
6765 +       struct attention_list *next;
6766 +};
6767 +
6768 +void suspend_mark_pages_for_pageset2(void)
6769 +{
6770 +       struct task_struct *p;
6771 +       struct attention_list *attention_list = NULL, *last = NULL, *next;
6772 +       int i, task_count = 0;
6773 +
6774 +       if (test_action_state(SUSPEND_NO_PAGESET2))
6775 +               return;
6776 +
6777 +       clear_dyn_pageflags(pageset2_map);
6778 +       
6779 +       if (test_action_state(SUSPEND_PAGESET2_FULL))
6780 +               pageset2_full();
6781 +       else {
6782 +               read_lock(&tasklist_lock);
6783 +               for_each_process(p) {
6784 +                       if (!p->mm || (p->flags & PF_BORROWED_MM))
6785 +                               continue;
6786 +
6787 +                       suspend_mark_task_as_pageset(p, PAGESET2);
6788 +               }
6789 +               read_unlock(&tasklist_lock);
6790 +       }
6791 +
6792 +       /* 
6793 +        * Now we count all userspace process (with task->mm) marked PF_NOFREEZE.
6794 +        */
6795 +       read_lock(&tasklist_lock);
6796 +       for_each_process(p)
6797 +               if ((p->flags & PF_NOFREEZE) || p == current)
6798 +                       task_count++;
6799 +       read_unlock(&tasklist_lock);
6800 +
6801 +       /* 
6802 +        * Allocate attention list structs.
6803 +        */
6804 +       for (i = 0; i < task_count; i++) {
6805 +               struct attention_list *this =
6806 +                       kmalloc(sizeof(struct attention_list), GFP_ATOMIC);
6807 +               if (!this) {
6808 +                       printk("Failed to allocate slab for attention list.\n");
6809 +                       set_result_state(SUSPEND_ABORTED);
6810 +                       goto free_attention_list;
6811 +               }
6812 +               this->next = NULL;
6813 +               if (attention_list) {
6814 +                       last->next = this;
6815 +                       last = this;
6816 +               } else
6817 +                       attention_list = last = this;
6818 +       }
6819 +
6820 +       next = attention_list;
6821 +       read_lock(&tasklist_lock);
6822 +       for_each_process(p)
6823 +               if ((p->flags & PF_NOFREEZE) || p == current) {
6824 +                       next->task = p;
6825 +                       next = next->next;
6826 +               }
6827 +       read_unlock(&tasklist_lock);
6828 +
6829 +       /* 
6830 +        * Because the tasks in attention_list are ones related to suspending,
6831 +        * we know that they won't go away under us.
6832 +        */
6833 +
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;
6840 +               kfree(last);
6841 +       }
6842 +}
6843 +
6844 +void suspend_reset_alt_image_pageset2_pfn(void)
6845 +{
6846 +       ps2_pfn = max_pfn + 1;
6847 +}
6848 +
6849 +static struct page *first_conflicting_page;
6850 +
6851 +/*
6852 + * free_conflicting_pages
6853 + */
6854 +
6855 +void free_conflicting_pages(void)
6856 +{
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;
6862 +       }
6863 +}
6864 +
6865 +/* __suspend_get_nonconflicting_page
6866 + *
6867 + * Description: Gets order zero pages that won't be overwritten
6868 + *             while copying the original pages.
6869 + */
6870 +
6871 +struct page * ___suspend_get_nonconflicting_page(int can_be_highmem)
6872 +{
6873 +       struct page *page;
6874 +       int flags = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
6875 +       if (can_be_highmem)
6876 +               flags |= __GFP_HIGHMEM;
6877 +
6878 +
6879 +       if (test_suspend_state(SUSPEND_LOADING_ALT_IMAGE) && pageset2_map &&
6880 +                               (ps2_pfn < (max_pfn + 2))) {
6881 +               /*
6882 +                * ps2_pfn = max_pfn + 1 when yet to find first ps2 pfn that can
6883 +                *              be used.
6884 +                *         = 0..max_pfn when going through list.
6885 +                *         = max_pfn + 2 when gone through whole list.
6886 +                */
6887 +               do {
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)))
6893 +                                       return page;
6894 +                       } else
6895 +                               ps2_pfn++;
6896 +               } while (ps2_pfn < max_pfn);
6897 +       }
6898 +
6899 +       do {
6900 +               page = alloc_pages(flags, 0);
6901 +               if (!page) {
6902 +                       printk("Failed to get nonconflicting page.\n");
6903 +                       return 0;
6904 +               }
6905 +               if (PagePageset1(page)) {
6906 +                       struct page **next = (struct page **) kmap(page);
6907 +                       *next = first_conflicting_page;
6908 +                       first_conflicting_page = page;
6909 +                       kunmap(page);
6910 +               }
6911 +       } while(PagePageset1(page));
6912 +
6913 +       return page;
6914 +}
6915 +
6916 +unsigned long __suspend_get_nonconflicting_page(void)
6917 +{
6918 +       struct page *page = ___suspend_get_nonconflicting_page(0);
6919 +       return page ? (unsigned long) page_address(page) : 0;
6920 +}
6921 +
6922 +struct pbe *get_next_pbe(struct page **page_ptr, struct pbe *this_pbe, int highmem)
6923 +{
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);
6928 +               if (!new_page)
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;
6933 +       } else
6934 +               this_pbe++;
6935 +
6936 +       return this_pbe;
6937 +}
6938 +
6939 +/* get_pageset1_load_addresses
6940 + * 
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
6943 + *             later.
6944 + * Returns:    Zero on success, one if couldn't find enough pages (shouldn't
6945 + *             happen).
6946 + */
6947 +
6948 +int suspend_get_pageset1_load_addresses(void)
6949 +{
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,
6956 +                   *low_pbe_page;
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;
6964 +
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)
6969 +                       return 1;
6970 +               this_high_pbe = (struct pbe *) kmap(high_pbe_page);
6971 +               memset(this_high_pbe, 0, PAGE_SIZE);
6972 +       }
6973 +
6974 +       low_pbe_page = ___suspend_get_nonconflicting_page(0);
6975 +       if (!low_pbe_page)
6976 +               return 1;
6977 +       this_low_pbe = (struct pbe *) page_address(low_pbe_page);
6978 +
6979 +       /* 
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.
6984 +        */
6985 +
6986 +       do {
6987 +               page = alloc_pages(flags, 0);
6988 +               if (page)
6989 +                       SetPagePageset1Copy(page);
6990 +       } while (page);
6991 +
6992 +       /* 
6993 +        * Find out how many high- and lowmem pages we allocated above,
6994 +        * and how many pages we can reload directly to their original
6995 +        * location.
6996 +        */
6997 +       BITMAP_FOR_EACH_SET(pageset1_copy_map, pfn) {
6998 +               int is_high;
6999 +               page = pfn_to_page(pfn);
7000 +               is_high = PageHighMem(page);
7001 +
7002 +               if (PagePageset1(page)) {
7003 +                       if (test_action_state(SUSPEND_NO_DIRECT_LOAD)) {
7004 +                               ClearPagePageset1Copy(page);
7005 +                               __free_page(page);
7006 +                               continue;
7007 +                       } else {
7008 +                               if (is_high)
7009 +                                       high_direct++;
7010 +                               else
7011 +                                       low_direct++;
7012 +                       }
7013 +               } else {
7014 +                       if (is_high)
7015 +                               highallocd++;
7016 +                       else
7017 +                               lowallocd++;
7018 +               }
7019 +       }
7020 +
7021 +       high_needed-= high_direct;
7022 +       low_needed-= low_direct;
7023 +
7024 +       /*
7025 +        * Do we need to use some lowmem pages for the copies of highmem
7026 +        * pages?
7027 +        */
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;
7032 +       }
7033 +       
7034 +       high_to_free = highallocd - high_needed;
7035 +       low_to_free = lowallocd - low_needed;
7036 +
7037 +       /*
7038 +        * Now generate our pbes (which will be used for the atomic restore,
7039 +        * and free unneeded pages.
7040 +        */
7041 +       BITMAP_FOR_EACH_SET(pageset1_copy_map, pfn) {
7042 +               int is_high;
7043 +               page = pfn_to_page(pfn);
7044 +               is_high = PageHighMem(page);
7045 +
7046 +               if (PagePageset1(page))
7047 +                       continue;
7048 +
7049 +               /* Free the page? */
7050 +               if ((is_high && high_to_free) ||
7051 +                   (!is_high && low_to_free)) {
7052 +                       ClearPagePageset1Copy(page);
7053 +                       __free_page(page);
7054 +                       if (is_high)
7055 +                               high_to_free--;
7056 +                       else
7057 +                               low_to_free--;
7058 +                       continue;
7059 +               }
7060 +
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;
7064 +                       high_pbes_done++;
7065 +                       if (!is_high)
7066 +                               low_pages_for_highmem--;
7067 +                       do {
7068 +                               orig_high_pfn = get_next_bit_on(pageset1_map,
7069 +                                               orig_high_pfn);
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));
7073 +
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;
7081 +                       } else
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;
7087 +                       }
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");
7091 +                               return -ENOMEM;
7092 +                       }
7093 +               } else {
7094 +                       struct page *orig_page;
7095 +                       low_pbes_done++;
7096 +                       do {
7097 +                               orig_low_pfn = get_next_bit_on(pageset1_map,
7098 +                                               orig_low_pfn);
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));
7102 +
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");
7111 +                               return -ENOMEM;
7112 +                       }
7113 +               }
7114 +       }
7115 +
7116 +       if (high_pbe_page)
7117 +               kunmap(high_pbe_page);
7118 +
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);
7123 +       }
7124 +
7125 +       free_conflicting_pages();
7126 +
7127 +       return 0;
7128 +}
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
7132 @@ -0,0 +1,51 @@
7133 +/*
7134 + * kernel/power/pagedir.h
7135 + *
7136 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7137 + *
7138 + * This file is released under the GPLv2.
7139 + *
7140 + * Declarations for routines for handling pagesets.
7141 + */
7142 +
7143 +#ifndef KERNEL_POWER_PAGEDIR_H
7144 +#define KERNEL_POWER_PAGEDIR_H
7145 +
7146 +/* Pagedir
7147 + *
7148 + * Contains the metadata for a set of pages saved in the image.
7149 + */
7150 +
7151 +struct pagedir {
7152 +       int id;
7153 +       int size;
7154 +#ifdef CONFIG_HIGHMEM
7155 +       int size_high;
7156 +#endif
7157 +};
7158 +
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)
7164 +#else
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)
7169 +#endif
7170 +
7171 +extern struct pagedir pagedir1, pagedir2;
7172 +
7173 +extern void suspend_copy_pageset1(void);
7174 +
7175 +extern void suspend_mark_pages_for_pageset2(void);
7176 +
7177 +extern int suspend_get_pageset1_load_addresses(void);
7178 +
7179 +extern unsigned long __suspend_get_nonconflicting_page(void);
7180 +struct page * ___suspend_get_nonconflicting_page(int can_be_highmem);
7181 +
7182 +extern void suspend_reset_alt_image_pageset2_pfn(void);
7183 +#endif
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
7187 @@ -0,0 +1,151 @@
7188 +/*
7189 + * kernel/power/pageflags.c
7190 + *
7191 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7192 + * 
7193 + * This file is released under the GPLv2.
7194 + *
7195 + * Routines for serialising and relocating pageflags in which we
7196 + * store our image metadata.
7197 + */
7198 +
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"
7209 +
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;
7215 +
7216 +static int pages_for_zone(struct zone *zone)
7217 +{
7218 +       return DIV_ROUND_UP(zone->spanned_pages, (PAGE_SIZE << 3));
7219 +}
7220 +
7221 +int suspend_pageflags_space_needed(void)
7222 +{
7223 +       int total = 0;
7224 +       struct zone *zone;
7225 +
7226 +       for_each_zone(zone)
7227 +               if (populated_zone(zone))
7228 +                       total += sizeof(int) * 3 + pages_for_zone(zone) * PAGE_SIZE;
7229 +
7230 +       total += sizeof(int);
7231 +
7232 +       return total;
7233 +}
7234 +
7235 +/* save_dyn_pageflags
7236 + *
7237 + * Description: Save a set of pageflags.
7238 + * Arguments:   dyn_pageflags_t *: Pointer to the bitmap being saved.
7239 + */
7240 +
7241 +void save_dyn_pageflags(dyn_pageflags_t pagemap)
7242 +{
7243 +       int i, zone_idx, size, node = 0;
7244 +       struct zone *zone;
7245 +       struct pglist_data *pgdat;
7246 +
7247 +       if (!*pagemap)
7248 +               return;
7249 +
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];
7253 +
7254 +                       if (!populated_zone(zone))
7255 +                               continue;
7256 +
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));
7264 +
7265 +                       for (i = 0; i < size; i++)
7266 +                               suspendActiveAllocator->rw_header_chunk(WRITE,
7267 +                                       NULL, (char *) pagemap[node][zone_idx][i],
7268 +                                       PAGE_SIZE);
7269 +               }
7270 +               node++;
7271 +       }
7272 +       node = -1;
7273 +       suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7274 +                       (char *) &node, sizeof(int));
7275 +}
7276 +
7277 +/* load_dyn_pageflags
7278 + *
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).
7282 + */
7283 +
7284 +int load_dyn_pageflags(dyn_pageflags_t pagemap)
7285 +{
7286 +       int i, zone_idx, zone_check = 0, size, node = 0;
7287 +       struct zone *zone;
7288 +       struct pglist_data *pgdat;
7289 +
7290 +       if (!pagemap)
7291 +               return 1;
7292 +
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];
7296 +
7297 +                       if (!populated_zone(zone))
7298 +                               continue;
7299 +
7300 +                       /* Same node? */
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);
7306 +                               return 1;
7307 +                       }
7308 +
7309 +                       /* Same zone? */
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);
7315 +                               return 1;
7316 +                       }
7317 +
7318 +
7319 +                       suspendActiveAllocator->rw_header_chunk(READ, NULL,
7320 +                               (char *) &size, sizeof(int));
7321 +
7322 +                       for (i = 0; i < size; i++)
7323 +                               suspendActiveAllocator->rw_header_chunk(READ, NULL,
7324 +                                       (char *) pagemap[node][zone_idx][i],
7325 +                                       PAGE_SIZE);
7326 +               }
7327 +               node++;
7328 +       }
7329 +       suspendActiveAllocator->rw_header_chunk(READ, NULL, (char *) &zone_check,
7330 +                       sizeof(int));
7331 +       if (zone_check != -1) {
7332 +               printk("Didn't read end of dyn pageflag data marker.(%x)\n",
7333 +                               zone_check);
7334 +               return 1;
7335 +       }
7336 +
7337 +       return 0;
7338 +}
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
7342 @@ -0,0 +1,59 @@
7343 +/*
7344 + * kernel/power/pageflags.h
7345 + *
7346 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7347 + *
7348 + * This file is released under the GPLv2.
7349 + *
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
7353 + * we do.
7354 + *
7355 + * NOTE!!!
7356 + * We assume that PAGE_SIZE - sizeof(void *) is a multiple of
7357 + * sizeof(unsigned long). Is this ever false?
7358 + */
7359 +
7360 +#include <linux/dyn_pageflags.h>
7361 +#include <linux/suspend.h>
7362 +
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;
7370 +
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))
7374 +
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))
7378 +
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))
7382 +
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))
7386 +
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))
7390 +
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))
7394 +
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))
7398 +
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
7405 @@ -1,5 +1,11 @@
7406 +/*
7407 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7408 + */
7409 +
7410  #include <linux/suspend.h>
7411  #include <linux/utsname.h>
7412 +#include "suspend.h"
7413 +#include "suspend2_builtin.h"
7414  
7415  struct swsusp_info {
7416         struct new_utsname      uts;
7417 @@ -13,7 +19,10 @@
7418  
7419  
7420  
7421 -#ifdef CONFIG_SOFTWARE_SUSPEND
7422 +#ifdef CONFIG_SUSPEND_SHARED
7423 +
7424 +extern char resume_file[256];
7425 +
7426  /*
7427   * Keep some memory free so that I/O operations can succeed without paging
7428   * [Might this be more than 4 MB?]
7429 @@ -44,6 +53,8 @@
7430  
7431  extern struct kset power_subsys;
7432  
7433 +extern struct pbe *restore_pblist;
7434 +
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 @@
7439  struct timeval;
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);
7445 +#else
7446 +static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
7447 +#endif
7448 +
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
7453 @@ -0,0 +1,128 @@
7454 +/*
7455 + * kernel/power/power_off.c
7456 + *
7457 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7458 + *
7459 + * This file is released under the GPLv2.
7460 + *
7461 + * Support for powering down.
7462 + */
7463 +
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"
7472 +#include "ui.h"
7473 +#include "power_off.h"
7474 +#include "power.h"
7475 +
7476 +unsigned long suspend2_poweroff_method = 0; /* 0 - Kernel power off */
7477 +
7478 +extern struct hibernation_ops *hibernation_ops;
7479 +
7480 +int suspend2_platform_prepare(void)
7481 +{
7482 +       if (suspend2_poweroff_method == 4 && hibernation_ops)
7483 +               return hibernation_ops->prepare();
7484 +
7485 +       return 0;
7486 +}
7487 +
7488 +/*
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
7496 + */
7497 +
7498 +void suspend2_power_down(void)
7499 +{
7500 +       int result = 0;
7501 +
7502 +       if (test_action_state(SUSPEND_REBOOT)) {
7503 +               suspend_prepare_status(DONT_CLEAR_BAR, "Ready to reboot.");
7504 +               kernel_restart(NULL);
7505 +       }
7506 +
7507 +       suspend_prepare_status(DONT_CLEAR_BAR, "Powering down.");
7508 +
7509 +       switch (suspend2_poweroff_method) {
7510 +               case 0:
7511 +                       break;
7512 +               case 3:
7513 +                       suspend_console();
7514 +
7515 +                       if (device_suspend(PMSG_SUSPEND)) {
7516 +                               suspend_prepare_status(DONT_CLEAR_BAR, "Device "
7517 +                                       "suspend failure.");
7518 +                               goto ResumeConsole;
7519 +                       }
7520 +
7521 +                       if (!pm_ops ||
7522 +                           (pm_ops->prepare && pm_ops->prepare(PM_SUSPEND_MEM)))
7523 +                               goto DeviceResume;
7524 +
7525 +                       if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) &&
7526 +                               disable_nonboot_cpus())
7527 +                               goto PmOpsFinish;
7528 +       
7529 +                       if (!suspend_enter(PM_SUSPEND_MEM))
7530 +                               result = 1;
7531 +
7532 +                       if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
7533 +                               enable_nonboot_cpus();
7534 +
7535 +PmOpsFinish:
7536 +                       if (pm_ops->finish)
7537 +                               pm_ops->finish(PM_SUSPEND_MEM);
7538 +
7539 +DeviceResume:
7540 +                       device_resume();
7541 +
7542 +ResumeConsole:
7543 +                       resume_console();
7544 +
7545 +                       /* If suspended to ram and later woke. */
7546 +                       if (result)
7547 +                               return;
7548 +                       break;
7549 +               case 4:
7550 +                       kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
7551 +                       hibernation_ops->enter();
7552 +                       break;
7553 +               case 5:
7554 +                       if (!pm_ops ||
7555 +                           (pm_ops->prepare && pm_ops->prepare(PM_SUSPEND_MAX)))
7556 +                               break;
7557 +
7558 +                       kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
7559 +                       suspend_enter(suspend2_poweroff_method);
7560 +
7561 +                       /* Failed. Fall back to kernel_power_off etc. */
7562 +                       if (pm_ops->finish)
7563 +                               pm_ops->finish(PM_SUSPEND_MAX);
7564 +       }
7565 +
7566 +       suspend_prepare_status(DONT_CLEAR_BAR, "Falling back to alternate power off method.");
7567 +       kernel_power_off();
7568 +       kernel_halt();
7569 +       suspend_prepare_status(DONT_CLEAR_BAR, "Powerdown failed.");
7570 +       while (1)
7571 +               cpu_relax();
7572 +}
7573 +
7574 +void suspend2_platform_finish(void)
7575 +{
7576 +       if (suspend2_poweroff_method == 4 && hibernation_ops)
7577 +               hibernation_ops->finish();
7578 +}
7579 +
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
7585 @@ -0,0 +1,15 @@
7586 +/*
7587 + * kernel/power/power_off.h
7588 + *
7589 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7590 + *
7591 + * This file is released under the GPLv2.
7592 + *
7593 + * Support for the powering down.
7594 + */
7595 +
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
7604 @@ -0,0 +1,798 @@
7605 +/*
7606 + * kernel/power/prepare_image.c
7607 + *
7608 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
7609 + *
7610 + * This file is released under the GPLv2.
7611 + *
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).
7624 + *
7625 + */
7626 +
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>
7633 +
7634 +#include "pageflags.h"
7635 +#include "modules.h"
7636 +#include "io.h"
7637 +#include "ui.h"
7638 +#include "extent.h"
7639 +#include "prepare_image.h"
7640 +#include "block_io.h"
7641 +#include "suspend.h"
7642 +#include "checksum.h"
7643 +#include "sysfs.h"
7644 +
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;
7651 +
7652 +/*
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.
7658 + */
7659 +
7660 +static int extra_pages_allocated;
7661 +
7662 +struct extras {
7663 +       struct page *page;
7664 +       int order;
7665 +       struct extras *next;
7666 +};
7667 +
7668 +static struct extras *extras_list;
7669 +
7670 +/* suspend_free_extra_pagedir_memory
7671 + *
7672 + * Description:        Free previously allocated extra pagedir memory.
7673 + */
7674 +void suspend_free_extra_pagedir_memory(void)
7675 +{
7676 +       /* Free allocated pages */
7677 +       while (extras_list) {
7678 +               struct extras *this = extras_list;
7679 +               int i;
7680 +
7681 +               extras_list = this->next;
7682 +
7683 +               for (i = 0; i < (1 << this->order); i++)
7684 +                       ClearPageNosave(this->page + i);
7685 +
7686 +               __free_pages(this->page, this->order);
7687 +               kfree(this);
7688 +       }
7689 +
7690 +       extra_pages_allocated = 0;
7691 +}
7692 +
7693 +/* suspend_allocate_extra_pagedir_memory
7694 + *
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.
7699 + */
7700 +static int suspend_allocate_extra_pagedir_memory(int extra_pages_needed)
7701 +{
7702 +       int j, order, num_to_alloc = extra_pages_needed - extra_pages_allocated;
7703 +       unsigned long flags = GFP_ATOMIC | __GFP_NOWARN;
7704 +
7705 +       if (num_to_alloc < 1)
7706 +               return 0;
7707 +
7708 +       order = fls(num_to_alloc);
7709 +       if (order >= MAX_ORDER)
7710 +               order = MAX_ORDER - 1;
7711 +
7712 +       while (num_to_alloc) {
7713 +               struct page *newpage;
7714 +               unsigned long virt;
7715 +               struct extras *extras_entry;
7716 +                       
7717 +               while ((1 << order) > num_to_alloc)
7718 +                       order--;
7719 +
7720 +               extras_entry = (struct extras *) kmalloc(sizeof(struct extras),
7721 +                       GFP_ATOMIC);
7722 +
7723 +               if (!extras_entry)
7724 +                       return extra_pages_allocated;
7725 +
7726 +               virt = __get_free_pages(flags, order);
7727 +               while (!virt && order) {
7728 +                       order--;
7729 +                       virt = __get_free_pages(flags, order);
7730 +               }
7731 +
7732 +               if (!virt) {
7733 +                       kfree(extras_entry);
7734 +                       return extra_pages_allocated;
7735 +               }
7736 +
7737 +               newpage = virt_to_page(virt);
7738 +
7739 +               extras_entry->page = newpage;
7740 +               extras_entry->order = order;
7741 +               extras_entry->next = NULL;
7742 +
7743 +               if (extras_list)
7744 +                       extras_entry->next = extras_list;
7745 +
7746 +               extras_list = extras_entry;
7747 +
7748 +               for (j = 0; j < (1 << order); j++) {
7749 +                       SetPageNosave(newpage + j);
7750 +                       SetPagePageset1Copy(newpage + j);
7751 +               }
7752 +
7753 +               extra_pages_allocated += (1 << order);
7754 +               num_to_alloc -= (1 << order);
7755 +       }
7756 +
7757 +       return extra_pages_allocated;
7758 +}
7759 +
7760 +/*
7761 + * real_nr_free_pages: Count pcp pages for a zone type or all zones
7762 + * (-1 for all, otherwise zone_idx() result desired).
7763 + */
7764 +int real_nr_free_pages(unsigned long zone_idx_mask)
7765 +{
7766 +       struct zone *zone;
7767 +       int result = 0, i = 0, cpu;
7768 +
7769 +       /* PCP lists */
7770 +       for_each_zone(zone) {
7771 +               if (!populated_zone(zone))
7772 +                       continue;
7773 +               
7774 +               if (!(zone_idx_mask & (1 << zone_idx(zone))))
7775 +                       continue;
7776 +
7777 +               for_each_online_cpu(cpu) {
7778 +                       struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
7779 +
7780 +                       for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
7781 +                               struct per_cpu_pages *pcp;
7782 +
7783 +                               pcp = &pset->pcp[i];
7784 +                               result += pcp->count;
7785 +                       }
7786 +               }
7787 +
7788 +               result += zone_page_state(zone, NR_FREE_PAGES);
7789 +       }
7790 +       return result;
7791 +}
7792 +
7793 +/*
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.
7797 + */
7798 +static void get_extra_pd1_allowance(void)
7799 +{
7800 +       int orig_num_free = real_nr_free_pages(all_zones_mask), final;
7801 +       
7802 +       suspend_prepare_status(CLEAR_BAR, "Finding allowance for drivers.");
7803 +
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);
7808 +       
7809 +       final = real_nr_free_pages(all_zones_mask);
7810 +
7811 +       device_power_up();
7812 +       local_irq_enable();
7813 +       device_resume();
7814 +       resume_console();
7815 +
7816 +       extra_pd1_pages_allowance = max(
7817 +               orig_num_free - final + MIN_EXTRA_PAGES_ALLOWANCE,
7818 +               MIN_EXTRA_PAGES_ALLOWANCE);
7819 +}
7820 +
7821 +/*
7822 + * Amount of storage needed, possibly taking into account the
7823 + * expected compression ratio and possibly also ignoring our
7824 + * allowance for extra pages.
7825 + */
7826 +static int main_storage_needed(int use_ecr,
7827 +               int ignore_extra_pd1_allow)
7828 +{
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);
7832 +}
7833 +
7834 +/*
7835 + * Storage needed for the image header, in bytes until the return.
7836 + */
7837 +static int header_storage_needed(void)
7838 +{
7839 +       int bytes = (int) sizeof(struct suspend_header) +
7840 +                       suspend_header_storage_for_modules() +
7841 +                       suspend_pageflags_space_needed();
7842 +
7843 +       return DIV_ROUND_UP(bytes, PAGE_SIZE);
7844 +}
7845 +
7846 +/*
7847 + * When freeing memory, pages from either pageset might be freed.
7848 + *
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.
7852 + *
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.
7856 + *
7857 + * => ps1_to_free functions
7858 + *
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.
7861 + *
7862 + * => any_to_free function
7863 + */
7864 +
7865 +static int highpages_ps1_to_free(void)
7866 +{
7867 +       return max_t(int, 0, DIV_ROUND_UP(get_highmem_size(pagedir1) -
7868 +               get_highmem_size(pagedir2), 2) - real_nr_free_high_pages());
7869 +}
7870 +
7871 +static int lowpages_ps1_to_free(void)
7872 +{
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));
7877 +}
7878 +
7879 +static int current_image_size(void)
7880 +{
7881 +       return pagedir1.size + pagedir2.size + header_space_allocated;
7882 +}
7883 +
7884 +static int any_to_free(int use_image_size_limit)
7885 +{
7886 +       int user_limit = (use_image_size_limit && image_size_limit > 0) ?
7887 +               max_t(int, 0, current_image_size() - (image_size_limit << 8))
7888 +               : 0;
7889 +
7890 +       int storage_limit = max_t(int, 0,
7891 +                       main_storage_needed(1, 1) - storage_available);
7892 +
7893 +       return max(user_limit, storage_limit);
7894 +}
7895 +
7896 +/* amount_needed
7897 + *
7898 + * Calculates the amount by which the image size needs to be reduced to meet
7899 + * our constraints.
7900 + */
7901 +static int amount_needed(int use_image_size_limit)
7902 +{
7903 +       return max(highpages_ps1_to_free() + lowpages_ps1_to_free(),
7904 +                       any_to_free(use_image_size_limit));
7905 +}
7906 +
7907 +static int image_not_ready(int use_image_size_limit)
7908 +{
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));
7919 +
7920 +       suspend_cond_pause(0, NULL);
7921 +
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));
7925 +}
7926 +
7927 +static void display_stats(int always, int sub_extra_pd1_allow)
7928 +{ 
7929 +       char buffer[255];
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",
7933 +               
7934 +               /* Free */
7935 +               real_nr_free_pages(all_zones_mask),
7936 +               real_nr_free_low_pages(),
7937 +               
7938 +               /* Sets */
7939 +               pagedir1.size, pagedir1.size - get_highmem_size(pagedir1),
7940 +               pagedir2.size, pagedir2.size - get_highmem_size(pagedir2),
7941 +
7942 +               /* Header */
7943 +               header_space_allocated, header_storage_needed(),
7944 +
7945 +               /* Nosave */
7946 +               num_nosave, extra_pages_allocated,
7947 +               num_nosave - extra_pages_allocated,
7948 +
7949 +               /* Storage */
7950 +               main_storage_allocated,
7951 +               storage_available,
7952 +               main_storage_needed(1, sub_extra_pd1_allow),
7953 +               main_storage_needed(1, 1),
7954 +
7955 +               /* Needed */
7956 +               lowpages_ps1_to_free(), highpages_ps1_to_free(),
7957 +               any_to_free(1),
7958 +               MIN_FREE_RAM, suspend_memory_for_modules(),
7959 +               extra_pd1_pages_allowance, image_size_limit << 8);
7960 +
7961 +       if (always)
7962 +               printk(buffer);
7963 +       else
7964 +               suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1, buffer);
7965 +}
7966 +
7967 +/* generate_free_page_map
7968 + *
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
7972 + *             pagesets.
7973 + */
7974 +static void generate_free_page_map(void) 
7975 +{
7976 +       int order, loop, cpu;
7977 +       struct page *page;
7978 +       unsigned long flags, i;
7979 +       struct zone *zone;
7980 +
7981 +       for_each_zone(zone) {
7982 +               if (!populated_zone(zone))
7983 +                       continue;
7984 +               
7985 +               spin_lock_irqsave(&zone->lock, flags);
7986 +
7987 +               for(i=0; i < zone->spanned_pages; i++)
7988 +                       ClearPageNosaveFree(pfn_to_page(
7989 +                                               zone->zone_start_pfn + i));
7990 +       
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);
7996 +
7997 +               
7998 +               for_each_online_cpu(cpu) {
7999 +                       struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
8000 +
8001 +                       for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
8002 +                               struct per_cpu_pages *pcp;
8003 +                               struct page *page;
8004 +
8005 +                               pcp = &pset->pcp[i];
8006 +                               list_for_each_entry(page, &pcp->list, lru)
8007 +                                       SetPageNosaveFree(page);
8008 +                       }
8009 +               }
8010 +               
8011 +               spin_unlock_irqrestore(&zone->lock, flags);
8012 +       }
8013 +}
8014 +
8015 +/* size_of_free_region
8016 + * 
8017 + * Description:        Return the number of pages that are free, beginning with and 
8018 + *             including this one.
8019 + */
8020 +static int size_of_free_region(struct page *page)
8021 +{
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;
8025 +
8026 +       while (posn <= last_in_zone && PageNosaveFree(posn))
8027 +               posn++;
8028 +       return (posn - page);
8029 +}
8030 +
8031 +/* flag_image_pages
8032 + *
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.
8037 + */
8038 +static void flag_image_pages(int atomic_copy)
8039 +{
8040 +       int num_free = 0;
8041 +       unsigned long loop;
8042 +       struct zone *zone;
8043 +
8044 +       pagedir1.size = 0;
8045 +       pagedir2.size = 0;
8046 +
8047 +       set_highmem_size(pagedir1, 0);
8048 +       set_highmem_size(pagedir2, 0);
8049 +
8050 +       num_nosave = 0;
8051 +
8052 +       clear_dyn_pageflags(pageset1_map);
8053 +
8054 +       generate_free_page_map();
8055 +
8056 +       /*
8057 +        * Pages not to be saved are marked Nosave irrespective of being reserved
8058 +        */
8059 +       for_each_zone(zone) {
8060 +               int highmem = is_highmem(zone);
8061 +
8062 +               if (!populated_zone(zone))
8063 +                       continue;
8064 +
8065 +               for (loop = 0; loop < zone->spanned_pages; loop++) {
8066 +                       unsigned long pfn = zone->zone_start_pfn + loop;
8067 +                       struct page *page;
8068 +                       int chunk_size;
8069 +
8070 +                       if (!pfn_valid(pfn))
8071 +                               continue;
8072 +
8073 +                       page = pfn_to_page(pfn);
8074 +
8075 +                       chunk_size = size_of_free_region(page);
8076 +                       if (chunk_size) {
8077 +                               num_free += chunk_size;
8078 +                               loop += chunk_size - 1;
8079 +                               continue;
8080 +                       }
8081 +
8082 +                       if (highmem)
8083 +                               page = saveable_highmem_page(pfn);
8084 +                       else
8085 +                               page = saveable_page(pfn);
8086 +
8087 +                       if (!page || PageNosave(page)) {
8088 +                               num_nosave++;
8089 +                               continue;
8090 +                       }
8091 +
8092 +                       if (PagePageset2(page)) {
8093 +                               pagedir2.size++;
8094 +                               if (PageHighMem(page))
8095 +                                       inc_highmem_size(pagedir2);
8096 +                               else
8097 +                                       SetPagePageset1Copy(page);
8098 +                               if (PageResave(page)) {
8099 +                                       SetPagePageset1(page);
8100 +                                       ClearPagePageset1Copy(page);
8101 +                                       pagedir1.size++;
8102 +                                       if (PageHighMem(page))
8103 +                                               inc_highmem_size(pagedir1);
8104 +                               }
8105 +                       } else {
8106 +                               pagedir1.size++;
8107 +                               SetPagePageset1(page);
8108 +                               if (PageHighMem(page))
8109 +                                       inc_highmem_size(pagedir1);
8110 +                       }
8111 +               }
8112 +       }
8113 +
8114 +       if (atomic_copy)
8115 +               return;
8116 +
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);
8122 +}
8123 +
8124 +void suspend_recalculate_image_contents(int atomic_copy) 
8125 +{
8126 +       clear_dyn_pageflags(pageset1_map);
8127 +       if (!atomic_copy) {
8128 +               int pfn;
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();
8133 +       }
8134 +       flag_image_pages(atomic_copy);
8135 +
8136 +       if (!atomic_copy) {
8137 +               storage_available = suspendActiveAllocator->storage_available();
8138 +               display_stats(0, 0);
8139 +       }
8140 +}
8141 +
8142 +/* update_image
8143 + *
8144 + * Allocate [more] memory and storage for the image.
8145 + */
8146 +static void update_image(void) 
8147 +{ 
8148 +       int result, param_used, wanted, got;
8149 +
8150 +       suspend_recalculate_image_contents(0);
8151 +
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",
8160 +                               wanted, got);
8161 +                       return;
8162 +               }
8163 +       }
8164 +
8165 +       thaw_kernel_threads();
8166 +
8167 +       /* 
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.
8176 +        */
8177 +
8178 +       suspendActiveAllocator->allocate_storage(
8179 +               min(storage_available, main_storage_needed(0, 0)));
8180 +
8181 +       main_storage_allocated = suspendActiveAllocator->storage_allocated();
8182 +
8183 +       param_used = header_storage_needed();
8184 +
8185 +       result = suspendActiveAllocator->allocate_header_space(param_used);
8186 +
8187 +       if (result)
8188 +               suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
8189 +                       "Still need to get more storage space for header.\n");
8190 +       else
8191 +               header_space_allocated = param_used;
8192 +
8193 +       if (freeze_processes()) {
8194 +               set_result_state(SUSPEND_FREEZING_FAILED);
8195 +               set_result_state(SUSPEND_ABORTED);
8196 +       }
8197 +
8198 +       allocate_checksum_pages();
8199 +
8200 +       suspend_recalculate_image_contents(0);
8201 +}
8202 +
8203 +/* attempt_to_freeze
8204 + * 
8205 + * Try to freeze processes.
8206 + */
8207 +
8208 +static int attempt_to_freeze(void)
8209 +{
8210 +       int result;
8211 +       
8212 +       /* Stop processes before checking again */
8213 +       thaw_processes();
8214 +       suspend_prepare_status(CLEAR_BAR, "Freezing processes & syncing filesystems.");
8215 +       result = freeze_processes();
8216 +
8217 +       if (result) {
8218 +               set_result_state(SUSPEND_ABORTED);
8219 +               set_result_state(SUSPEND_FREEZING_FAILED);
8220 +       }
8221 +
8222 +       return result;
8223 +}
8224 +
8225 +/* eat_memory
8226 + *
8227 + * Try to free some memory, either to meet hard or soft constraints on the image
8228 + * characteristics.
8229 + * 
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
8234 + *   be restored.
8235 + * Soft constraints
8236 + * - User specificied image size limit.
8237 + */
8238 +static void eat_memory(void)
8239 +{
8240 +       int amount_wanted = 0;
8241 +       int free_flags = 0, did_eat_memory = 0;
8242 +       
8243 +       /*
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.
8248 +        *
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.
8252 +        */
8253 +
8254 +       suspend_recalculate_image_contents(0);
8255 +       amount_wanted = amount_needed(1);
8256 +
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);
8262 +                               return;
8263 +                       }
8264 +                       break;
8265 +               case -2:  /* Free caches only */
8266 +                       drop_pagecache();
8267 +                       suspend_recalculate_image_contents(0);
8268 +                       amount_wanted = amount_needed(1);
8269 +                       did_eat_memory = 1;
8270 +                       break;
8271 +               default:
8272 +                       free_flags = GFP_ATOMIC | __GFP_HIGHMEM;
8273 +       }
8274 +
8275 +       if (amount_wanted > 0 && !test_result_state(SUSPEND_ABORTED) &&
8276 +                       image_size_limit != -1) {
8277 +               struct zone *zone;
8278 +               int zone_idx;
8279 +
8280 +               suspend_prepare_status(CLEAR_BAR, "Seeking to free %dMB of memory.", MB(amount_wanted));
8281 +
8282 +               thaw_kernel_threads();
8283 +
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);
8288 +
8289 +                       if (zone_type_free < 0)
8290 +                               break;
8291 +
8292 +                       for_each_zone(zone) {
8293 +                               if (zone_idx(zone) != zone_idx)
8294 +                                       continue;
8295 +
8296 +                               shrink_one_zone(zone, zone_type_free);
8297 +
8298 +                               did_eat_memory = 1;
8299 +
8300 +                               suspend_recalculate_image_contents(0);
8301 +
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);
8306 +
8307 +                               if (zone_type_free < 0)
8308 +                                       break;
8309 +                       }
8310 +               }
8311 +
8312 +               suspend_cond_pause(0, NULL);
8313 +
8314 +               if (freeze_processes()) {
8315 +                       set_result_state(SUSPEND_FREEZING_FAILED);
8316 +                       set_result_state(SUSPEND_ABORTED);
8317 +               }
8318 +       }
8319 +       
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);
8325 +       }
8326 +
8327 +       /* Blank out image size display */
8328 +       suspend_update_status(100, 100, NULL);
8329 +}
8330 +
8331 +/* suspend_prepare_image
8332 + *
8333 + * Entry point to the whole image preparation section.
8334 + *
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
8343 + *   us).
8344 + * - Make sure that all dirty buffers are written out.
8345 + */
8346 +#define MAX_TRIES 2
8347 +int suspend_prepare_image(void)
8348 +{
8349 +       int result = 1, tries = 1;
8350 +
8351 +       header_space_allocated = 0;
8352 +       main_storage_allocated = 0;
8353 +
8354 +       if (attempt_to_freeze())
8355 +               return 1;
8356 +
8357 +       if (!extra_pd1_pages_allowance)
8358 +               get_extra_pd1_allowance();
8359 +
8360 +       storage_available = suspendActiveAllocator->storage_available();
8361 +
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);
8366 +               return 1;
8367 +       }
8368 +
8369 +       do {
8370 +               suspend_prepare_status(CLEAR_BAR, "Preparing Image. Try %d.", tries);
8371 +       
8372 +               eat_memory();
8373 +
8374 +               if (test_result_state(SUSPEND_ABORTED))
8375 +                       break;
8376 +
8377 +               update_image();
8378 +
8379 +               tries++;
8380 +
8381 +       } while (image_not_ready(1) && tries <= MAX_TRIES &&
8382 +                       !test_result_state(SUSPEND_ABORTED));
8383 +
8384 +       result = image_not_ready(0);
8385 +
8386 +       if (!test_result_state(SUSPEND_ABORTED)) {
8387 +               if (result) {
8388 +                       display_stats(1, 0);
8389 +                       abort_suspend(SUSPEND_UNABLE_TO_PREPARE_IMAGE,
8390 +                               "Unable to successfully prepare the image.\n");
8391 +               } else {
8392 +                       unlink_lru_lists();
8393 +                       suspend_cond_pause(1, "Image preparation complete.");
8394 +               }
8395 +       }
8396 +
8397 +       return result;
8398 +}
8399 +
8400 +#ifdef CONFIG_SUSPEND2_EXPORTS
8401 +EXPORT_SYMBOL_GPL(real_nr_free_pages);
8402 +#endif
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
8406 @@ -0,0 +1,34 @@
8407 +/*
8408 + * kernel/power/prepare_image.h
8409 + *
8410 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
8411 + *
8412 + * This file is released under the GPLv2.
8413 + *
8414 + */
8415 +
8416 +#include <asm/sections.h>
8417 +
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;
8424 +
8425 +#define MIN_FREE_RAM 100
8426 +#define MIN_EXTRA_PAGES_ALLOWANCE 500
8427 +
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)))
8433 +#else
8434 +#define real_nr_free_high_pages() (0)
8435 +#define real_nr_free_low_pages() (real_nr_free_pages(all_zones_mask))
8436 +
8437 +/* For eat_memory function */
8438 +#define ZONE_HIGHMEM (MAX_NR_ZONES + 1)
8439 +#endif
8440 +
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
8444 @@ -14,6 +14,8 @@
8445  #include <linux/syscalls.h>
8446  #include <linux/freezer.h>
8447  
8448 +int freezer_state = 0;
8449 +
8450  /* 
8451   * Timeout for stopping processes
8452   */
8453 @@ -192,10 +194,11 @@
8454                 return nr_unfrozen;
8455  
8456         sys_sync();
8457 +       freezer_state = FREEZER_USERSPACE_FROZEN;
8458         nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
8459         if (nr_unfrozen)
8460                 return nr_unfrozen;
8461 -
8462 +       freezer_state = FREEZER_FULLY_ON;
8463         printk("done.\n");
8464         BUG_ON(in_atomic());
8465         return 0;
8466 @@ -220,11 +223,31 @@
8467  
8468  void thaw_processes(void)
8469  {
8470 +       int old_state = freezer_state;
8471 +
8472 +       if (old_state == FREEZER_OFF)
8473 +               return;
8474 +
8475 +       /* 
8476 +        * Change state beforehand because thawed tasks might submit I/O
8477 +        * immediately.
8478 +        */
8479 +       freezer_state = FREEZER_OFF;
8480 +
8481         printk("Restarting tasks ... ");
8482 -       thaw_tasks(FREEZER_KERNEL_THREADS);
8483 +
8484 +       if (old_state == FREEZER_FULLY_ON)
8485 +               thaw_tasks(FREEZER_KERNEL_THREADS);
8486         thaw_tasks(FREEZER_USER_SPACE);
8487         schedule();
8488         printk("done.\n");
8489  }
8490  
8491 +void thaw_kernel_threads(void)
8492 +{
8493 +       freezer_state = FREEZER_USERSPACE_FROZEN;
8494 +       thaw_tasks(FREEZER_KERNEL_THREADS);
8495 +}
8496 +
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
8502 @@ -33,6 +33,7 @@
8503  #include <asm/io.h>
8504  
8505  #include "power.h"
8506 +#include "suspend2_builtin.h"
8507  
8508  static int swsusp_page_is_free(struct page *);
8509  static void swsusp_set_page_forbidden(struct page *);
8510 @@ -44,6 +45,13 @@
8511   * directly to their "original" page frames.
8512   */
8513  struct pbe *restore_pblist;
8514 +int resume_attempted;
8515 +EXPORT_SYMBOL_GPL(resume_attempted);
8516 +
8517 +#ifdef CONFIG_SUSPEND2
8518 +#include "pagedir.h"
8519 +int suspend_post_context_save(void);
8520 +#endif
8521  
8522  /* Pointer to an auxiliary buffer (1 page) */
8523  static void *buffer;
8524 @@ -86,6 +94,11 @@
8525  
8526  unsigned long get_safe_page(gfp_t gfp_mask)
8527  {
8528 +#ifdef CONFIG_SUSPEND2
8529 +       if (suspend2_running)
8530 +               return suspend_get_nonconflicting_page();
8531 +#endif
8532 +
8533         return (unsigned long)get_image_page(gfp_mask, PG_SAFE);
8534  }
8535  
8536 @@ -598,7 +611,9 @@
8537         unsigned long end_pfn;
8538  };
8539  
8540 -static LIST_HEAD(nosave_regions);
8541 +LIST_HEAD(nosave_regions);
8542 +
8543 +EXPORT_SYMBOL_GPL(nosave_regions);
8544  
8545  /**
8546   *     register_nosave_region - register a range of page frames the contents
8547 @@ -827,7 +842,7 @@
8548   *     and it isn't a part of a free chunk of pages.
8549   */
8550  
8551 -static struct page *saveable_highmem_page(unsigned long pfn)
8552 +struct page *saveable_highmem_page(unsigned long pfn)
8553  {
8554         struct page *page;
8555  
8556 @@ -870,7 +885,6 @@
8557         return n;
8558  }
8559  #else
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 */
8563  
8564 @@ -883,7 +897,7 @@
8565   *     a free chunk of pages.
8566   */
8567  
8568 -static struct page *saveable_page(unsigned long pfn)
8569 +struct page *saveable_page(unsigned long pfn)
8570  {
8571         struct page *page;
8572  
8573 @@ -1200,6 +1214,11 @@
8574  {
8575         unsigned int nr_pages, nr_highmem;
8576  
8577 +#ifdef CONFIG_SUSPEND2
8578 +       if (suspend2_running)
8579 +               return suspend_post_context_save();
8580 +#endif
8581 +
8582         printk("swsusp: critical section: \n");
8583  
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
8588 @@ -0,0 +1,288 @@
8589 +/*
8590 + * kernel/power/storage.c
8591 + *
8592 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
8593 + *
8594 + * This file is released under the GPLv2.
8595 + *
8596 + * Routines for talking to a userspace program that manages storage.
8597 + *
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;
8602 + *
8603 + * The user space side:
8604 + * - passes messages regarding status;
8605 + *
8606 + */
8607 +
8608 +#include <linux/suspend.h>
8609 +#include <linux/freezer.h>
8610
8611 +#include "sysfs.h"
8612 +#include "modules.h"
8613 +#include "netlink.h"
8614 +#include "storage.h"
8615 +#include "ui.h"
8616 +
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;
8623 +       
8624 +static int usm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
8625 +{
8626 +       int type;
8627 +       int *data;
8628 +
8629 +       type = nlh->nlmsg_type;
8630 +
8631 +       /* A control message: ignore them */
8632 +       if (type < NETLINK_MSG_BASE)
8633 +               return 0;
8634 +
8635 +       /* Unknown message: reply with EINVAL */
8636 +       if (type >= USM_MSG_MAX)
8637 +               return -EINVAL;
8638 +
8639 +       /* All operations require privileges, even GET */
8640 +       if (security_netlink_recv(skb, CAP_NET_ADMIN))
8641 +               return -EPERM;
8642 +
8643 +       /* Only allow one task to receive NOFREEZE privileges */
8644 +       if (type == NETLINK_MSG_NOFREEZE_ME && usm_helper_data.pid != -1)
8645 +               return -EBUSY;
8646 +
8647 +       data = (int*)NLMSG_DATA(nlh);
8648 +
8649 +       switch (type) {
8650 +               case USM_MSG_SUCCESS:
8651 +               case USM_MSG_FAILED:
8652 +                       message_received = type;
8653 +                       complete(&usm_helper_data.wait_for_process);
8654 +                       break;
8655 +               default:
8656 +                       printk("Storage manager doesn't recognise message %d.\n", type);
8657 +       }
8658 +
8659 +       return 1;
8660 +}
8661 +
8662 +#ifdef CONFIG_NET
8663 +static int activations = 0;
8664 +
8665 +int suspend_activate_storage(int force)
8666 +{
8667 +       int tries = 1;
8668 +
8669 +       if (usm_helper_data.pid == -1 || !usm_ops.enabled)
8670 +               return 0;
8671 +
8672 +       message_received = 0;
8673 +       activations++;
8674 +
8675 +       if (activations > 1 && !force)
8676 +               return 0;
8677 +
8678 +       while ((!message_received || message_received == USM_MSG_FAILED) && tries < 2) {
8679 +               suspend_prepare_status(DONT_CLEAR_BAR, "Activate storage attempt %d.\n", tries);
8680 +
8681 +               init_completion(&usm_helper_data.wait_for_process);
8682 +
8683 +               suspend_send_netlink_message(&usm_helper_data,
8684 +                       USM_MSG_CONNECT,
8685 +                       NULL, 0);
8686 +
8687 +               /* Wait 2 seconds for the userspace process to make contact */
8688 +               wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2*HZ);
8689 +
8690 +               tries++;
8691 +       }
8692 +
8693 +       return 0;
8694 +}
8695 +
8696 +int suspend_deactivate_storage(int force)
8697 +{
8698 +       if (usm_helper_data.pid == -1 || !usm_ops.enabled)
8699 +               return 0;
8700 +       
8701 +       message_received = 0;
8702 +       activations--;
8703 +
8704 +       if (activations && !force)
8705 +               return 0;
8706 +
8707 +       init_completion(&usm_helper_data.wait_for_process);
8708 +
8709 +       suspend_send_netlink_message(&usm_helper_data,
8710 +                       USM_MSG_DISCONNECT,
8711 +                       NULL, 0);
8712 +
8713 +       wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2*HZ);
8714 +
8715 +       if (!message_received || message_received == USM_MSG_FAILED) {
8716 +               printk("Returning failure disconnecting storage.\n");
8717 +               return 1;
8718 +       }
8719 +
8720 +       return 0;
8721 +}
8722 +#endif
8723 +
8724 +static void storage_manager_simulate(void)
8725 +{
8726 +       printk("--- Storage manager simulate ---\n");
8727 +       suspend_prepare_usm();
8728 +       schedule();
8729 +       printk("--- Activate storage 1 ---\n");
8730 +       suspend_activate_storage(1);
8731 +       schedule();
8732 +       printk("--- Deactivate storage 1 ---\n");
8733 +       suspend_deactivate_storage(1);
8734 +       schedule();
8735 +       printk("--- Cleanup usm ---\n");
8736 +       suspend_cleanup_usm();
8737 +       schedule();
8738 +       printk("--- Storage manager simulate ends ---\n");
8739 +}
8740 +
8741 +static int usm_storage_needed(void)
8742 +{
8743 +       return strlen(usm_helper_data.program);
8744 +}
8745 +
8746 +static int usm_save_config_info(char *buf)
8747 +{
8748 +       int len = strlen(usm_helper_data.program);
8749 +       memcpy(buf, usm_helper_data.program, len);
8750 +       return len;
8751 +}
8752 +
8753 +static void usm_load_config_info(char *buf, int size)
8754 +{
8755 +       /* Don't load the saved path if one has already been set */
8756 +       if (usm_helper_data.program[0])
8757 +               return;
8758 +
8759 +       memcpy(usm_helper_data.program, buf, size);
8760 +}
8761 +
8762 +static int usm_memory_needed(void)
8763 +{
8764 +       /* ball park figure of 32 pages */
8765 +       return (32 * PAGE_SIZE);
8766 +}
8767 +
8768 +/* suspend_prepare_usm
8769 + */
8770 +int suspend_prepare_usm(void)
8771 +{
8772 +       usm_prepare_count++;
8773 +
8774 +       if (usm_prepare_count > 1 || !usm_ops.enabled)
8775 +               return 0;
8776 +       
8777 +       usm_helper_data.pid = -1;
8778 +
8779 +       if (!*usm_helper_data.program)
8780 +               return 0;
8781 +
8782 +       suspend_netlink_setup(&usm_helper_data);
8783 +
8784 +       if (usm_helper_data.pid == -1)
8785 +               printk("Suspend2 Storage Manager wanted, but couldn't start it.\n");
8786 +
8787 +       suspend_activate_storage(0);
8788 +
8789 +       return (usm_helper_data.pid != -1);
8790 +}
8791 +
8792 +void suspend_cleanup_usm(void)
8793 +{
8794 +       usm_prepare_count--;
8795 +
8796 +       if (usm_helper_data.pid > -1 && !usm_prepare_count) {
8797 +               suspend_deactivate_storage(0);
8798 +               suspend_netlink_close(&usm_helper_data);
8799 +       }
8800 +}
8801 +
8802 +static void storage_manager_activate(void)
8803 +{
8804 +       if (storage_manager_action == storage_manager_last_action)
8805 +               return;
8806 +
8807 +       if (storage_manager_action)
8808 +               suspend_prepare_usm();
8809 +       else
8810 +               suspend_cleanup_usm();
8811 +
8812 +       storage_manager_last_action = storage_manager_action;
8813 +}
8814 +
8815 +/*
8816 + * User interface specific /sys/power/suspend2 entries.
8817 + */
8818 +
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,
8823 +       },
8824 +
8825 +       { SUSPEND2_ATTR("enabled", SYSFS_RW),
8826 +         SYSFS_INT(&usm_ops.enabled, 0, 1, 0)
8827 +       },
8828 +
8829 +       { SUSPEND2_ATTR("program", SYSFS_RW),
8830 +         SYSFS_STRING(usm_helper_data.program, 254, 0)
8831 +       },
8832 +
8833 +       { SUSPEND2_ATTR("activate_storage", SYSFS_RW),
8834 +         SYSFS_INT(&storage_manager_action, 0, 1, 0),
8835 +         .write_side_effect            = storage_manager_activate,
8836 +       }
8837 +};
8838 +
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,
8848 +
8849 +       .sysfs_data                     = sysfs_params,
8850 +       .num_sysfs_entries              = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
8851 +};
8852 +
8853 +/* suspend_usm_sysfs_init
8854 + * Description: Boot time initialisation for user interface.
8855 + */
8856 +int s2_usm_init(void)
8857 +{
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);
8869 +
8870 +       return suspend_register_module(&usm_ops);
8871 +}
8872 +
8873 +void s2_usm_exit(void)
8874 +{
8875 +       suspend_unregister_module(&usm_ops);
8876 +}
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
8880 @@ -0,0 +1,53 @@
8881 +/*
8882 + * kernel/power/storage.h
8883 + *
8884 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
8885 + *
8886 + * This file is released under the GPLv2.
8887 + */
8888 +
8889 +#ifdef CONFIG_NET
8890 +int suspend_prepare_usm(void);
8891 +void suspend_cleanup_usm(void);
8892 +
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);
8897 +#else
8898 +static inline int s2_usm_init(void) { return 0; }
8899 +static inline void s2_usm_exit(void) { }
8900 +
8901 +static inline int suspend_activate_storage(int force)
8902 +{
8903 +       return 0;
8904 +}
8905 +
8906 +static inline int suspend_deactivate_storage(int force)
8907 +{
8908 +       return 0;
8909 +}
8910 +
8911 +static inline int suspend_prepare_usm(void) { return 0; }
8912 +static inline void suspend_cleanup_usm(void) { }
8913 +#endif
8914 +
8915 +enum {
8916 +       USM_MSG_BASE = 0x10,
8917 +
8918 +       /* Kernel -> Userspace */
8919 +       USM_MSG_CONNECT = 0x30,
8920 +       USM_MSG_DISCONNECT = 0x31,
8921 +       USM_MSG_SUCCESS = 0x40,
8922 +       USM_MSG_FAILED = 0x41,
8923 +
8924 +       USM_MSG_MAX,
8925 +};
8926 +
8927 +#ifdef CONFIG_NET
8928 +extern __init int suspend_usm_init(void);
8929 +extern __exit void suspend_usm_cleanup(void);
8930 +#else
8931 +#define suspend_usm_init() do { } while(0)
8932 +#define suspend_usb_cleanup() do { } while(0)
8933 +#endif
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
8937 @@ -0,0 +1,1058 @@
8938 +/*
8939 + * kernel/power/suspend.c
8940 + */
8941 +/** \mainpage Suspend2.
8942 + *
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.
8950 + *
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.
8957 + * 
8958 + * \section Copyright
8959 + *
8960 + * Suspend2 is released under the GPLv2.
8961 + *
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>
8966 + *
8967 + * \section Credits
8968 + * 
8969 + * Nigel would like to thank the following people for their work:
8970 + * 
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.
8974 + *
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.
8978 + *
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.
8984 + *
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.
8988 + *
8989 + * Thanks also to corporate sponsors:
8990 + *
8991 + * <B>Redhat.</B>Sometime employer from May 2006 (my fault, not Redhat's!).
8992 + *
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.
8995 + * 
8996 + * <B>LinuxFund.org.</B> Sponsored Nigel's work on Suspend for four months Oct 2003
8997 + * to Jan 2004.
8998 + *
8999 + * <B>LAC Linux.</B> Donated P4 hardware that enabled development and ongoing
9000 + * maintenance of SMP and Highmem support.
9001 + *
9002 + * <B>OSDL.</B> Provided access to various hardware configurations, make occasional
9003 + * small donations to the project.
9004 + */
9005 +
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>
9013 +
9014 +#include "modules.h"
9015 +#include "sysfs.h"
9016 +#include "prepare_image.h"
9017 +#include "io.h"
9018 +#include "ui.h"
9019 +#include "power_off.h"
9020 +#include "storage.h"
9021 +#include "checksum.h"
9022 +#include "cluster.h"
9023 +#include "suspend2_builtin.h"
9024 +
9025 +/*! Pageset metadata. */
9026 +struct pagedir pagedir2 = {2}; 
9027 +
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;
9033 +
9034 +int do_suspend2_step(int step);
9035 +
9036 +/*
9037 + * Basic clean-up routine.
9038 + */
9039 +void suspend_finish_anything(int suspend_or_resume)
9040 +{
9041 +       if (!atomic_dec_and_test(&actions_running))
9042 +               return;
9043 +
9044 +       suspend_cleanup_modules(suspend_or_resume);
9045 +       suspend_put_modules();
9046 +       clear_suspend_state(SUSPEND_RUNNING);
9047 +       set_fs(oldfs);
9048 +       if (suspend_or_resume) {
9049 +               block_dump = block_dump_save;
9050 +               set_cpus_allowed(current, CPU_MASK_ALL);
9051 +       }
9052 +}
9053 +
9054 +/*
9055 + * Basic set-up routine.
9056 + */
9057 +int suspend_start_anything(int suspend_or_resume)
9058 +{
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);
9064 +                       return -EBUSY;
9065 +               } else
9066 +                       return 0;
9067 +       }
9068 +
9069 +       oldfs = get_fs();
9070 +       set_fs(KERNEL_DS);
9071 +
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);
9078 +       }
9079 +
9080 +       set_suspend_state(SUSPEND_RUNNING);
9081 +
9082 +       if (suspend_get_modules()) {
9083 +               printk("Suspend2: Get modules failed!\n");
9084 +               goto out_err;
9085 +       }
9086 +
9087 +       if (suspend_initialise_modules(suspend_or_resume)) {
9088 +               printk("Suspend2: Initialise modules failed!\n");
9089 +               goto out_err;
9090 +       }
9091 +
9092 +       if (suspend_or_resume) {
9093 +               block_dump_save = block_dump;
9094 +               block_dump = 0;
9095 +               set_cpus_allowed(current, CPU_MASK_CPU0);
9096 +       }
9097 +
9098 +       return 0;
9099 +
9100 +out_err:
9101 +       if (suspend_or_resume)
9102 +               block_dump_save = block_dump;
9103 +       suspend_finish_anything(suspend_or_resume);
9104 +       return -EBUSY;
9105 +}
9106 +
9107 +/*
9108 + * Nosave page tracking.
9109 + *
9110 + * Here rather than in prepare_image because we want to do it once only at the
9111 + * start of a cycle.
9112 + */
9113 +extern struct list_head nosave_regions;
9114 +
9115 +struct nosave_region {
9116 +       struct list_head list;
9117 +       unsigned long start_pfn;
9118 +       unsigned long end_pfn;
9119 +};
9120 +
9121 +static void mark_nosave_pages(void)
9122 +{
9123 +       struct nosave_region *region;
9124 +
9125 +       list_for_each_entry(region, &nosave_regions, list) {
9126 +               unsigned long pfn;
9127 +
9128 +               for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
9129 +                       SetPageNosave(pfn_to_page(pfn));
9130 +       }
9131 +}
9132 +
9133 +/*
9134 + * Allocate & free bitmaps.
9135 + */
9136 +static int allocate_bitmaps(void)
9137 +{
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))
9145 +               return 1;
9146 +
9147 +       return 0;
9148 +}
9149 +
9150 +static void free_bitmaps(void)
9151 +{
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);
9159 +}
9160 +
9161 +static int io_MB_per_second(int read_write)
9162 +{
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;
9166 +}
9167 +
9168 +/* get_debug_info
9169 + * Functionality:      Store debug info in a buffer.
9170 + */
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)
9174 +{
9175 +       int len = 0;
9176 +
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",
9183 +                       suspend_result,
9184 +                       suspend_action,
9185 +                       suspend_debug_state,
9186 +                       suspend_default_console_level,
9187 +                       image_size_limit,
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, 
9192 +                       count - len - 1);
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]));
9202 +               } else {
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]));
9210 +               }
9211 +               SNPRINTF(".\n");
9212 +       }
9213 +       else
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);
9217 +
9218 +       return len;
9219 +}
9220 +
9221 +/*
9222 + * do_cleanup
9223 + */
9224 +
9225 +static void do_cleanup(int get_debug_info)
9226 +{
9227 +       int i = 0;
9228 +       char *buffer = NULL;
9229 +
9230 +       if (get_debug_info)
9231 +               suspend_prepare_status(DONT_CLEAR_BAR, "Cleaning up...");
9232 +       relink_lru_lists();
9233 +
9234 +       free_checksum_pages();
9235 +
9236 +       if (get_debug_info)
9237 +               buffer = (char *) get_zeroed_page(GFP_ATOMIC);
9238 +
9239 +       if (buffer)
9240 +               i = get_suspend_debug_info(buffer, PAGE_SIZE);
9241 +
9242 +       suspend_free_extra_pagedir_memory();
9243 +       
9244 +       pagedir1.size = pagedir2.size = 0;
9245 +       set_highmem_size(pagedir1, 0);
9246 +       set_highmem_size(pagedir2, 0);
9247 +
9248 +       restore_avenrun();
9249 +
9250 +       thaw_processes();
9251 +
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);
9259 +       } else
9260 +#endif
9261 +               if (suspendActiveAllocator)
9262 +                       suspendActiveAllocator->invalidate_image();
9263 +
9264 +       free_bitmaps();
9265 +
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);
9272 +       }
9273 +
9274 +       if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9275 +               enable_nonboot_cpus();
9276 +       suspend_cleanup_console();
9277 +
9278 +       suspend_deactivate_storage(0);
9279 +
9280 +       clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
9281 +       clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
9282 +       clear_suspend_state(SUSPEND_NOW_RESUMING);
9283 +
9284 +       if (got_pmsem) {
9285 +               mutex_unlock(&pm_mutex);
9286 +               got_pmsem = 0;
9287 +       }
9288 +}
9289 +
9290 +static int check_still_keeping_image(void)
9291 +{
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 */
9296 +       }
9297 +
9298 +       printk("Invalidating previous image.\n");
9299 +       suspendActiveAllocator->invalidate_image();
9300 +
9301 +       return 0;
9302 +}
9303 +
9304 +static int suspend_init(void)
9305 +{
9306 +       suspend_result = 0;
9307 +
9308 +       printk(KERN_INFO "Suspend2: Initiating a software suspend cycle.\n");
9309 +
9310 +       nr_suspends++;
9311 +       
9312 +       save_avenrun();
9313 +
9314 +       suspend_io_time[0][0] = suspend_io_time[0][1] = 
9315 +               suspend_io_time[1][0] = suspend_io_time[1][1] = 0;
9316 +
9317 +       if (!test_suspend_state(SUSPEND_CAN_SUSPEND) ||
9318 +           allocate_bitmaps())
9319 +               return 0;
9320 +       
9321 +       mark_nosave_pages();
9322 +
9323 +       suspend_prepare_console();
9324 +       if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) ||
9325 +                       !disable_nonboot_cpus())
9326 +               return 1;
9327 +
9328 +       set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9329 +       set_result_state(SUSPEND_ABORTED);
9330 +       return 0;
9331 +}
9332 +
9333 +static int can_suspend(void)
9334 +{
9335 +       if (get_pmsem) {
9336 +               if (!mutex_trylock(&pm_mutex)) {
9337 +                       printk("Suspend2: Failed to obtain pm_mutex.\n");
9338 +                       dump_stack();
9339 +                       set_result_state(SUSPEND_ABORTED);
9340 +                       set_result_state(SUSPEND_PM_SEM);
9341 +                       return 0;
9342 +               }
9343 +               got_pmsem = 1;
9344 +       }
9345 +
9346 +       if (!test_suspend_state(SUSPEND_CAN_SUSPEND))
9347 +               suspend_attempt_to_parse_resume_device(0);
9348 +
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);
9356 +               if (!got_pmsem) {
9357 +                       mutex_unlock(&pm_mutex);
9358 +                       got_pmsem = 0;
9359 +               }
9360 +               return 0;
9361 +       }
9362 +       
9363 +       return 1;
9364 +}
9365 +
9366 +static int do_power_down(void)
9367 +{
9368 +       /* If switching images fails, do normal powerdown */
9369 +       if (poweroff_resume2[0])
9370 +               do_suspend2_step(STEP_RESUME_ALT_IMAGE);
9371 +
9372 +       suspend_cond_pause(1, "About to power down or reboot.");
9373 +       suspend2_power_down();
9374 +
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.");
9378 +
9379 +       barrier();
9380 +       mb();
9381 +       do_cleanup(1);
9382 +       return 0;
9383 +}
9384 +
9385 +/*
9386 + * __save_image
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
9390 + *                    suspended.
9391 + */
9392 +static int __save_image(void)
9393 +{
9394 +       int temp_result;
9395 +
9396 +       suspend_prepare_status(DONT_CLEAR_BAR, "Starting to save the image..");
9397 +
9398 +       suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9399 +               " - Final values: %d and %d.\n",
9400 +               pagedir1.size, pagedir2.size);
9401 +
9402 +       suspend_cond_pause(1, "About to write pagedir2.");
9403 +
9404 +       calculate_check_checksums(0);
9405 +
9406 +       temp_result = write_pageset(&pagedir2);
9407 +       
9408 +       if (temp_result == -1 || test_result_state(SUSPEND_ABORTED))
9409 +               return 1;
9410 +
9411 +       suspend_cond_pause(1, "About to copy pageset 1.");
9412 +
9413 +       if (test_result_state(SUSPEND_ABORTED))
9414 +               return 1;
9415 +
9416 +       suspend_deactivate_storage(1);
9417 +
9418 +       suspend_prepare_status(DONT_CLEAR_BAR, "Doing atomic copy.");
9419 +       
9420 +       suspend2_in_suspend = 1;
9421 +       
9422 +       if (suspend2_platform_prepare()) {
9423 +               set_result_state(SUSPEND_PLATFORM_PREP_FAILED);
9424 +               set_result_state(SUSPEND_ABORTED);
9425 +               return 1;
9426 +       }
9427 +
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;
9433 +       }
9434 +       
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);
9439 +       } else
9440 +               temp_result = suspend2_suspend();
9441 +
9442 +       /* We return here at resume time too! */
9443 +       if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9444 +               enable_nonboot_cpus();
9445 +
9446 +       device_resume();
9447 +
9448 +ResumeConsole:
9449 +       resume_console();
9450 +
9451 +       suspend2_platform_finish();
9452 +
9453 +       if (suspend_activate_storage(1))
9454 +               panic("Failed to reactivate our storage.");
9455 +       
9456 +       if (temp_result || test_result_state(SUSPEND_ABORTED))
9457 +               return 1;
9458 +       
9459 +       /* Resume time? */
9460 +       if (!suspend2_in_suspend) {
9461 +               copyback_post();
9462 +               return 0;
9463 +       }
9464 +
9465 +       /* Nope. Suspending. So, see if we can save the image... */
9466 +
9467 +       suspend_update_status(pagedir2.size,
9468 +                       pagedir1.size + pagedir2.size,
9469 +                       NULL);
9470 +       
9471 +       if (test_result_state(SUSPEND_ABORTED))
9472 +               goto abort_reloading_pagedir_two;
9473 +
9474 +       suspend_cond_pause(1, "About to write pageset1.");
9475 +
9476 +       suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9477 +                       "-- Writing pageset1\n");
9478 +
9479 +       temp_result = write_pageset(&pagedir1);
9480 +
9481 +       /* We didn't overwrite any memory, so no reread needs to be done. */
9482 +       if (test_action_state(SUSPEND_TEST_FILTER_SPEED))
9483 +               return 1;
9484 +
9485 +       if (temp_result == 1 || test_result_state(SUSPEND_ABORTED))
9486 +               goto abort_reloading_pagedir_two;
9487 +
9488 +       suspend_cond_pause(1, "About to write header.");
9489 +
9490 +       if (test_result_state(SUSPEND_ABORTED))
9491 +               goto abort_reloading_pagedir_two;
9492 +
9493 +       temp_result = write_image_header();
9494 +
9495 +       if (test_action_state(SUSPEND_TEST_BIO))
9496 +               return 1;
9497 +
9498 +       if (!temp_result && !test_result_state(SUSPEND_ABORTED))
9499 +               return 0;
9500 +
9501 +abort_reloading_pagedir_two:
9502 +       temp_result = read_pageset2(1);
9503 +
9504 +       /* If that failed, we're sunk. Panic! */
9505 +       if (temp_result)
9506 +               panic("Attempt to reload pagedir 2 while aborting "
9507 +                               "a suspend failed.");
9508 +
9509 +       return 1;
9510 +}
9511 +
9512 +/* 
9513 + * do_save_image
9514 + *
9515 + * Save the prepared image.
9516 + */
9517 +
9518 +static int do_save_image(void)
9519 +{
9520 +       int result = __save_image();
9521 +       if (!suspend2_in_suspend || result)
9522 +               do_cleanup(1);
9523 +       return result;
9524 +}
9525 +
9526 +
9527 +/* do_prepare_image
9528 + *
9529 + * Seek to initialise and prepare an image to be saved. On failure,
9530 + * cleanup.
9531 + */
9532 +
9533 +static int do_prepare_image(void)
9534 +{
9535 +       if (suspend_activate_storage(0))
9536 +               return 1;
9537 +
9538 +       /*
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
9541 +        * run out.
9542 +        */
9543 +
9544 +       if (!can_suspend() ||
9545 +           (test_result_state(SUSPEND_KEPT_IMAGE) &&
9546 +            check_still_keeping_image()))
9547 +               goto cleanup;
9548 +
9549 +       if (suspend_init() && !suspend_prepare_image() &&
9550 +                       !test_result_state(SUSPEND_ABORTED))
9551 +               return 0;
9552 +
9553 +cleanup:
9554 +       do_cleanup(0);
9555 +       return 1;
9556 +}
9557 +
9558 +static int do_check_can_resume(void)
9559 +{
9560 +       char *buf = (char *) get_zeroed_page(GFP_KERNEL);
9561 +       int result = 0;
9562 +
9563 +       if (!buf)
9564 +               return 0;
9565 +
9566 +       /* Only interested in first byte, so throw away return code. */
9567 +       image_exists_read(buf, PAGE_SIZE);
9568 +
9569 +       if (buf[0] == '1')
9570 +               result = 1;
9571 +
9572 +       free_page((unsigned long) buf);
9573 +       return result;
9574 +}
9575 +
9576 +/*
9577 + * We check if we have an image and if so we try to resume.
9578 + */
9579 +static int do_load_atomic_copy(void)
9580 +{
9581 +       int read_image_result = 0;
9582 +
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");
9586 +               return 1;
9587 +       }
9588 +       
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");
9593 +
9594 +       suspend_activate_storage(0);
9595 +
9596 +       if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK)) &&
9597 +               !suspend_attempt_to_parse_resume_device(0)) {
9598 +               /* 
9599 +                * Without a usable storage device we can do nothing - 
9600 +                * even if noresume is given
9601 +                */
9602 +
9603 +               if (!suspendNumAllocators)
9604 +                       printk(KERN_ALERT "Suspend2: "
9605 +                         "No storage allocators have been registered.\n");
9606 +               else
9607 +                       printk(KERN_ALERT "Suspend2: "
9608 +                               "Missing or invalid storage location "
9609 +                               "(resume2= parameter). Please correct and "
9610 +                               "rerun lilo (or equivalent) before "
9611 +                               "suspending.\n");
9612 +               suspend_deactivate_storage(0);
9613 +               return 1;
9614 +       }
9615 +
9616 +       read_image_result = read_pageset1(); /* non fatal error ignored */
9617 +
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);
9621 +       }
9622 +
9623 +       suspend_deactivate_storage(0);
9624 +       
9625 +       if (read_image_result)
9626 +               return 1;
9627 +
9628 +       return 0;
9629 +}
9630 +
9631 +static void prepare_restore_load_alt_image(int prepare)
9632 +{
9633 +       static dyn_pageflags_t pageset1_map_save, pageset1_copy_map_save;
9634 +
9635 +       if (prepare) {
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();
9642 +       } else {
9643 +               if (pageset1_map)
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);
9651 +       }
9652 +}
9653 +
9654 +int pre_resume_freeze(void)
9655 +{
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);
9661 +                       return 1;
9662 +               }
9663 +       }
9664 +
9665 +       suspend_prepare_status(DONT_CLEAR_BAR,  "Freeze processes.");
9666 +
9667 +       if (freeze_processes()) {
9668 +               printk("Some processes failed to suspend\n");
9669 +               return 1;
9670 +       }
9671 +
9672 +       return 0;
9673 +}
9674 +
9675 +void post_resume_thaw(void)
9676 +{
9677 +       thaw_processes();
9678 +       if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9679 +               enable_nonboot_cpus();
9680 +}
9681 +
9682 +int do_suspend2_step(int step)
9683 +{
9684 +       int result;
9685 +
9686 +       switch (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:
9698 +                       /* 
9699 +                        * If we succeed, this doesn't return.
9700 +                        * Instead, we return from do_save_image() in the
9701 +                        * suspended kernel.
9702 +                        */
9703 +                       result = suspend_atomic_restore();
9704 +                       if (result)
9705 +                               post_resume_thaw();
9706 +                       return result;
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");
9714 +                               goto out;
9715 +                       }
9716 +                       if (!do_load_atomic_copy()) {
9717 +                               printk("Failed to load image.\n");
9718 +                               suspend_atomic_restore();
9719 +                       }
9720 +out:
9721 +                       prepare_restore_load_alt_image(0);
9722 +                       save_restore_resume2(RESTORE, NOQUIET);
9723 +                       break;
9724 +       }
9725 +
9726 +       return 0;
9727 +}
9728 +
9729 +/* -- Functions for kickstarting a suspend or resume --- */
9730 +
9731 +/*
9732 + * Check if we have an image and if so try to resume.
9733 + */
9734 +void __suspend2_try_resume(void)
9735 +{
9736 +       set_suspend_state(SUSPEND_TRYING_TO_RESUME);
9737 +       resume_attempted = 1;
9738 +
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);
9742 +
9743 +       do_cleanup(0);
9744 +
9745 +       clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
9746 +       clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
9747 +       clear_suspend_state(SUSPEND_NOW_RESUMING);
9748 +}
9749 +
9750 +/* Wrapper for when called from init/do_mounts.c */
9751 +void _suspend2_try_resume(void)
9752 +{
9753 +       resume_attempted = 1;
9754 +
9755 +       if (suspend_start_anything(SYSFS_RESUMING))
9756 +               return;
9757 +
9758 +       /* Unlock will be done in do_cleanup */
9759 +       mutex_lock(&pm_mutex);
9760 +       got_pmsem = 1;
9761 +
9762 +       __suspend2_try_resume();
9763 +
9764 +       /* 
9765 +        * For initramfs, we have to clear the boot time
9766 +        * flag after trying to resume
9767 +        */
9768 +       clear_suspend_state(SUSPEND_BOOT_TIME);
9769 +       suspend_finish_anything(SYSFS_RESUMING);
9770 +}
9771 +
9772 +/*
9773 + * _suspend2_try_suspend
9774 + * Functionality   : 
9775 + * Called From     : drivers/acpi/sleep/main.c
9776 + *                   kernel/reboot.c
9777 + */
9778 +int _suspend2_try_suspend(int have_pmsem)
9779 +{
9780 +       int result = 0, sys_power_disk = 0;
9781 +
9782 +       if (!atomic_read(&actions_running)) {
9783 +               /* Came in via /sys/power/disk */
9784 +               if (suspend_start_anything(SYSFS_SUSPENDING))
9785 +                       return -EBUSY;
9786 +               sys_power_disk = 1;
9787 +       }
9788 +
9789 +       get_pmsem = !have_pmsem;
9790 +
9791 +       if (strlen(poweroff_resume2)) {
9792 +               attempt_to_parse_po_resume_device2();
9793 +
9794 +               if (!strlen(poweroff_resume2)) {
9795 +                       printk("Poweroff resume2 now invalid. Aborting.\n");
9796 +                       goto out;
9797 +               }
9798 +       }
9799 +
9800 +       if ((result = do_suspend2_step(STEP_SUSPEND_PREPARE_IMAGE)))
9801 +               goto out;
9802 +
9803 +       if (test_action_state(SUSPEND_FREEZER_TEST)) {
9804 +               do_cleanup(0);
9805 +               goto out;
9806 +       }
9807 +
9808 +       if ((result = do_suspend2_step(STEP_SUSPEND_SAVE_IMAGE)))
9809 +               goto out;
9810 +
9811 +       /* This code runs at resume time too! */
9812 +       if (suspend2_in_suspend)
9813 +               result = do_suspend2_step(STEP_SUSPEND_POWERDOWN);
9814 +out:
9815 +       if (sys_power_disk)
9816 +               suspend_finish_anything(SYSFS_SUSPENDING);
9817 +       return result;
9818 +}
9819 +
9820 +/*
9821 + * This array contains entries that are automatically registered at
9822 + * boot. Modules and the console code register their own entries separately.
9823 + */
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)
9827 +       },
9828 +
9829 +       { SUSPEND2_ATTR("image_exists", SYSFS_RW),
9830 +         SYSFS_CUSTOM(image_exists_read, image_exists_write,
9831 +                         SYSFS_NEEDS_SM_FOR_BOTH)
9832 +       },
9833 +
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,
9837 +       },
9838 +
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,
9842 +       },
9843 +       { SUSPEND2_ATTR("debug_info", SYSFS_READONLY),
9844 +         SYSFS_CUSTOM(get_suspend_debug_info, NULL, 0)
9845 +       },
9846 +       
9847 +       { SUSPEND2_ATTR("ignore_rootfs", SYSFS_RW),
9848 +         SYSFS_BIT(&suspend_action, SUSPEND_IGNORE_ROOTFS, 0)
9849 +       },
9850 +       
9851 +       { SUSPEND2_ATTR("image_size_limit", SYSFS_RW),
9852 +         SYSFS_INT(&image_size_limit, -2, INT_MAX, 0)
9853 +       },
9854 +
9855 +       { SUSPEND2_ATTR("last_result", SYSFS_RW),
9856 +         SYSFS_UL(&suspend_result, 0, 0, 0)
9857 +       },
9858 +       
9859 +       { SUSPEND2_ATTR("no_multithreaded_io", SYSFS_RW),
9860 +         SYSFS_BIT(&suspend_action, SUSPEND_NO_MULTITHREADED_IO, 0)
9861 +       },
9862 +
9863 +       { SUSPEND2_ATTR("full_pageset2", SYSFS_RW),
9864 +         SYSFS_BIT(&suspend_action, SUSPEND_PAGESET2_FULL, 0)
9865 +       },
9866 +
9867 +       { SUSPEND2_ATTR("reboot", SYSFS_RW),
9868 +         SYSFS_BIT(&suspend_action, SUSPEND_REBOOT, 0)
9869 +       },
9870 +
9871 +#ifdef CONFIG_SOFTWARE_SUSPEND
9872 +       { SUSPEND2_ATTR("replace_swsusp", SYSFS_RW),
9873 +         SYSFS_BIT(&suspend_action, SUSPEND_REPLACE_SWSUSP, 0)
9874 +       },
9875 +#endif
9876 +
9877 +       { SUSPEND2_ATTR("resume_commandline", SYSFS_RW),
9878 +         SYSFS_STRING(suspend2_nosave_commandline, COMMAND_LINE_SIZE, 0)
9879 +       },
9880 +
9881 +       { SUSPEND2_ATTR("version", SYSFS_READONLY),
9882 +         SYSFS_STRING(SUSPEND_CORE_VERSION, 0, 0)
9883 +       },
9884 +
9885 +       { SUSPEND2_ATTR("no_load_direct", SYSFS_RW),
9886 +         SYSFS_BIT(&suspend_action, SUSPEND_NO_DIRECT_LOAD, 0)
9887 +       },
9888 +
9889 +       { SUSPEND2_ATTR("freezer_test", SYSFS_RW),
9890 +         SYSFS_BIT(&suspend_action, SUSPEND_FREEZER_TEST, 0)
9891 +       },
9892 +
9893 +       { SUSPEND2_ATTR("test_bio", SYSFS_RW),
9894 +         SYSFS_BIT(&suspend_action, SUSPEND_TEST_BIO, 0)
9895 +       },
9896 +
9897 +       { SUSPEND2_ATTR("test_filter_speed", SYSFS_RW),
9898 +         SYSFS_BIT(&suspend_action, SUSPEND_TEST_FILTER_SPEED, 0)
9899 +       },
9900 +
9901 +       { SUSPEND2_ATTR("slow", SYSFS_RW),
9902 +         SYSFS_BIT(&suspend_action, SUSPEND_SLOW, 0)
9903 +       },
9904 +
9905 +       { SUSPEND2_ATTR("no_pageset2", SYSFS_RW),
9906 +         SYSFS_BIT(&suspend_action, SUSPEND_NO_PAGESET2, 0)
9907 +       },
9908 +         
9909 +       { SUSPEND2_ATTR("late_cpu_hotplug", SYSFS_RW),
9910 +         SYSFS_BIT(&suspend_action, SUSPEND_LATE_CPU_HOTPLUG, 0)
9911 +       },
9912 +         
9913 +#if defined(CONFIG_ACPI)
9914 +       { SUSPEND2_ATTR("powerdown_method", SYSFS_RW),
9915 +         SYSFS_UL(&suspend2_poweroff_method, 0, 5, 0)
9916 +       },
9917 +#endif
9918 +
9919 +#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
9920 +       { SUSPEND2_ATTR("keep_image", SYSFS_RW),
9921 +         SYSFS_BIT(&suspend_action, SUSPEND_KEEP_IMAGE, 0)
9922 +       },
9923 +#endif
9924 +};
9925 +
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,
9931 +};
9932
9933 +static __init int core_load(void)
9934 +{
9935 +       int i,
9936 +           numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
9937 +
9938 +       printk("Suspend v" SUSPEND_CORE_VERSION "\n");
9939 +
9940 +       if (s2_sysfs_init())
9941 +               return 1;
9942 +
9943 +       for (i=0; i< numfiles; i++)
9944 +               suspend_register_sysfs_file(&suspend2_subsys.kobj,
9945 +                               &sysfs_params[i]);
9946 +
9947 +       s2_core_fns = &my_fns;
9948 +
9949 +       if (s2_checksum_init())
9950 +               return 1;
9951 +       if (s2_cluster_init())
9952 +               return 1;
9953 +       if (s2_usm_init())
9954 +               return 1;
9955 +       if (s2_ui_init())
9956 +               return 1;
9957 +
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);
9962 +#endif
9963 +
9964 +       return 0;
9965 +}
9966 +
9967 +#ifdef MODULE
9968 +static __exit void core_unload(void)
9969 +{
9970 +       int i,
9971 +           numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
9972 +
9973 +       s2_ui_exit();
9974 +       s2_checksum_exit();
9975 +       s2_cluster_exit();
9976 +       s2_usm_exit();
9977 +
9978 +       for (i=0; i< numfiles; i++)
9979 +               suspend_unregister_sysfs_file(&suspend2_subsys.kobj,
9980 +                               &sysfs_params[i]);
9981 +
9982 +       s2_core_fns = NULL;
9983 +
9984 +       s2_sysfs_exit();
9985 +}
9986 +MODULE_LICENSE("GPL");
9987 +module_init(core_load);
9988 +module_exit(core_unload);
9989 +#else
9990 +late_initcall(core_load);
9991 +#endif
9992 +
9993 +#ifdef CONFIG_SUSPEND2_EXPORTS
9994 +EXPORT_SYMBOL_GPL(pagedir2);
9995 +#endif
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
9999 @@ -0,0 +1,182 @@
10000 +/*
10001 + * kernel/power/suspend.h
10002 + *
10003 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10004 + *
10005 + * This file is released under the GPLv2.
10006 + *
10007 + * It contains declarations used throughout swsusp.
10008 + *
10009 + */
10010 +
10011 +#ifndef KERNEL_POWER_SUSPEND_H
10012 +#define KERNEL_POWER_SUSPEND_H
10013 +
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"
10020 +
10021 +#define SUSPEND_CORE_VERSION "2.2.10"
10022 +
10023 +/*              == Action states ==            */
10024 +
10025 +enum {
10026 +       SUSPEND_REBOOT,
10027 +       SUSPEND_PAUSE,
10028 +       SUSPEND_SLOW,
10029 +       SUSPEND_LOGALL,
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,
10047 +};
10048 +
10049 +extern unsigned long suspend_action;
10050 +
10051 +#define clear_action_state(bit) (test_and_clear_bit(bit, &suspend_action))
10052 +#define test_action_state(bit) (test_bit(bit, &suspend_action))
10053 +
10054 +/*              == Result states ==            */
10055 +
10056 +enum {
10057 +       SUSPEND_ABORTED,
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,
10067 +       SUSPEND_PM_SEM,
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,
10078 +};
10079 +
10080 +extern unsigned long suspend_result;
10081 +
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))
10085 +
10086 +/*      == Debug sections and levels ==        */
10087 +
10088 +/* debugging levels. */
10089 +enum {
10090 +       SUSPEND_STATUS = 0,
10091 +       SUSPEND_ERROR = 2,
10092 +       SUSPEND_LOW,
10093 +       SUSPEND_MEDIUM,
10094 +       SUSPEND_HIGH,
10095 +       SUSPEND_VERBOSE,
10096 +};
10097 +
10098 +enum {
10099 +       SUSPEND_ANY_SECTION,
10100 +       SUSPEND_EAT_MEMORY,
10101 +       SUSPEND_IO,
10102 +       SUSPEND_HEADER,
10103 +       SUSPEND_WRITER,
10104 +       SUSPEND_MEMORY,
10105 +};
10106 +
10107 +extern unsigned long suspend_debug_state;
10108 +
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))
10112 +
10113 +/*             == Steps in suspending ==       */
10114 +
10115 +enum {
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,
10123 +       STEP_RESUME_GO,
10124 +       STEP_RESUME_ALT_IMAGE,
10125 +};
10126 +
10127 +/*             == Suspend states ==
10128 +       (see also include/linux/suspend.h)      */
10129 +
10130 +#define get_suspend_state()  (suspend_state)
10131 +#define restore_suspend_state(saved_state) \
10132 +       do { suspend_state = saved_state; } while(0)
10133 +
10134 +/*             == Module support ==            */
10135 +
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);
10141 +};
10142 +
10143 +extern struct suspend2_core_fns *s2_core_fns;
10144 +
10145 +/*             == All else ==                  */
10146 +#define KB(x) ((x) << (PAGE_SHIFT - 10))
10147 +#define MB(x) ((x) >> (20 - PAGE_SHIFT))
10148 +
10149 +extern int suspend_start_anything(int suspend_or_resume);
10150 +extern void suspend_finish_anything(int suspend_or_resume);
10151 +
10152 +extern int save_image_part1(void);
10153 +extern int suspend_atomic_restore(void);
10154 +
10155 +extern int _suspend2_try_suspend(int have_pmsem);
10156 +extern void __suspend2_try_resume(void);
10157 +
10158 +extern int __suspend_post_context_save(void);
10159 +
10160 +extern unsigned int nr_suspends;
10161 +extern char resume2_file[256];
10162 +extern char poweroff_resume2[256];
10163 +
10164 +extern void copyback_post(void);
10165 +extern int suspend2_suspend(void);
10166 +extern int extra_pd1_pages_used;
10167 +
10168 +extern int suspend_io_time[2][2];
10169 +
10170 +#define SECTOR_SIZE 512
10171 +
10172 +extern int suspend_early_boot_message 
10173 +       (int can_erase_image, int default_answer, char *warning_reason, ...);
10174 +
10175 +static inline int load_direct(struct page *page)
10176 +{
10177 +       return test_action_state(SUSPEND_NO_DIRECT_LOAD) ? 0 : PagePageset1Copy(page);
10178 +}
10179 +
10180 +extern int pre_resume_freeze(void);
10181 +#endif
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
10185 @@ -0,0 +1,319 @@
10186 +/*
10187 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10188 + *
10189 + * This file is released under the GPLv2.
10190 + */
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>
10206 +#include "io.h"
10207 +#include "suspend.h"
10208 +#include "extent.h"
10209 +#include "block_io.h"
10210 +#include "netlink.h"
10211 +#include "prepare_image.h"
10212 +#include "ui.h"
10213 +#include "sysfs.h"
10214 +#include "pagedir.h"
10215 +#include "modules.h"
10216 +#include "suspend2_builtin.h"
10217 +
10218 +#ifndef CONFIG_SOFTWARE_SUSPEND
10219 +struct hibernation_ops *hibernation_ops;
10220 +
10221 +/**
10222 + * hibernation_set_ops - set the global hibernate operations
10223 + * @ops: the hibernation operations to use in subsequent hibernation transitions
10224 + */
10225 +
10226 +void hibernation_set_ops(struct hibernation_ops *ops)
10227 +{
10228 +       if (ops && !(ops->prepare && ops->enter && ops->finish)) {
10229 +               WARN_ON(1);
10230 +               return;
10231 +       }
10232 +       mutex_lock(&pm_mutex);
10233 +       hibernation_ops = ops;
10234 +       mutex_unlock(&pm_mutex);
10235 +}
10236 +EXPORT_SYMBOL_GPL(hibernation_set_ops);
10237 +#endif
10238 +
10239 +EXPORT_SYMBOL_GPL(hibernation_ops);
10240 +
10241 +#ifdef CONFIG_SUSPEND2_CORE_EXPORTS
10242 +#ifdef CONFIG_SOFTWARE_SUSPEND
10243 +EXPORT_SYMBOL_GPL(resume_file);
10244 +#endif
10245 +
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);
10254 +
10255 +#ifdef CONFIG_X86_64
10256 +EXPORT_SYMBOL_GPL(restore_processor_state);
10257 +EXPORT_SYMBOL_GPL(save_processor_state);
10258 +#endif
10259 +
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);
10267 +
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);
10294 +#endif
10295 +#endif
10296 +
10297 +#ifdef CONFIG_SUSPEND2_USERUI_EXPORTS
10298 +EXPORT_SYMBOL_GPL(kmsg_redirect);
10299 +#ifndef CONFIG_COMPAT
10300 +EXPORT_SYMBOL_GPL(sys_ioctl);
10301 +#endif
10302 +#endif
10303 +
10304 +#if defined(CONFIG_SUSPEND2_USERUI_EXPORTS) || defined(CONFIG_SUSPEND2_CORE_EXPORTS)
10305 +EXPORT_SYMBOL_GPL(console_printk);
10306 +#endif
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);
10315 +#endif
10316 +
10317 +#ifdef CONFIG_SUSPEND2_FILE_EXPORTS
10318 +/* Suspend_file specific */
10319 +extern char * __initdata root_device_name;
10320 +
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);
10325 +#endif
10326 +
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);
10331 +#endif
10332 +
10333 +#if defined(CONFIG_SUSPEND2_EXPORTS) || defined(CONFIG_SUSPEND2_CORE_EXPORTS)
10334 +EXPORT_SYMBOL_GPL(snprintf_used);
10335 +#endif
10336 +struct suspend2_core_fns *s2_core_fns;
10337 +EXPORT_SYMBOL_GPL(s2_core_fns);
10338 +
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);
10343 +
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};
10348 +
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);
10353 +
10354 +unsigned long suspend_get_nonconflicting_page(void)
10355 +{
10356 +       return s2_core_fns->get_nonconflicting_page();
10357 +}
10358 +
10359 +int suspend_post_context_save(void)
10360 +{
10361 +       return s2_core_fns->post_context_save();
10362 +}
10363 +
10364 +int suspend2_try_suspend(int have_pmsem)
10365 +{
10366 +       if (!s2_core_fns)
10367 +               return -ENODEV;
10368 +
10369 +       return s2_core_fns->try_suspend(have_pmsem);
10370 +}
10371 +
10372 +void suspend2_try_resume(void)
10373 +{
10374 +       if (s2_core_fns)
10375 +               s2_core_fns->try_resume();
10376 +}
10377 +
10378 +int suspend2_lowlevel_builtin(void)
10379 +{
10380 +       int error = 0;
10381 +
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();
10387 +
10388 +       return error;
10389 +}
10390 +
10391 +#ifndef CONFIG_SOFTWARE_SUSPEND
10392 +int hibernate(void)
10393 +{
10394 +       return suspend2_try_suspend(0);
10395 +}
10396 +#endif
10397 +
10398 +EXPORT_SYMBOL_GPL(suspend2_lowlevel_builtin);
10399 +
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);
10403 +
10404 +#ifdef CONFIG_SUSPEND2_REPLACE_SWSUSP
10405 +unsigned long suspend_action = (1 << SUSPEND_REPLACE_SWSUSP) | (1 << SUSPEND_PAGESET2_FULL);
10406 +#else
10407 +unsigned long suspend_action = 1 << SUSPEND_PAGESET2_FULL;
10408 +#endif
10409 +EXPORT_SYMBOL_GPL(suspend_action);
10410 +
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);
10415 +
10416 +/* The number of suspends we have started (some may have been cancelled) */
10417 +unsigned int nr_suspends;
10418 +EXPORT_SYMBOL_GPL(nr_suspends);
10419 +
10420 +char resume2_file[256] = CONFIG_SUSPEND2_DEFAULT_RESUME2;
10421 +EXPORT_SYMBOL_GPL(resume2_file);
10422 +
10423 +int suspend2_running = 0;
10424 +EXPORT_SYMBOL_GPL(suspend2_running);
10425 +
10426 +int suspend2_in_suspend __nosavedata;
10427 +EXPORT_SYMBOL_GPL(suspend2_in_suspend);
10428 +
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];
10434 +
10435 +__nosavedata struct pbe *restore_highmem_pblist;
10436 +
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);
10442 +#endif
10443 +
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);
10449 +#endif
10450 +
10451 +/* --  Commandline Parameter Handling ---
10452 + *
10453 + * Resume setup: obtain the storage device.
10454 + */
10455 +static int __init resume2_setup(char *str)
10456 +{
10457 +       if (!*str)
10458 +               return 0;
10459 +       
10460 +       strncpy(resume2_file, str, 255);
10461 +       return 0;
10462 +}
10463 +
10464 +/*
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.
10469 + */
10470 +static int __init noresume2_setup(char *str)
10471 +{
10472 +       set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
10473 +       return 0;
10474 +}
10475 +
10476 +static int __init suspend_retry_resume_setup(char *str)
10477 +{
10478 +       set_suspend_state(SUSPEND_RETRY_RESUME);
10479 +       return 0;
10480 +}
10481 +
10482 +#ifndef CONFIG_SOFTWARE_SUSPEND
10483 +static int __init resume_setup(char *str)
10484 +{
10485 +       if (!*str)
10486 +               return 0;
10487 +       
10488 +       strncpy(resume2_file, str, 255);
10489 +       return 0;
10490 +}
10491 +
10492 +static int __init noresume_setup(char *str)
10493 +{
10494 +       set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
10495 +       return 0;
10496 +}
10497 +__setup("noresume", noresume_setup);
10498 +__setup("resume=", resume_setup);
10499 +#endif
10500 +
10501 +__setup("noresume2", noresume2_setup);
10502 +__setup("resume2=", resume2_setup);
10503 +__setup("suspend_retry_resume", suspend_retry_resume_setup);
10504 +
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
10508 @@ -0,0 +1,35 @@
10509 +/*
10510 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10511 + *
10512 + * This file is released under the GPLv2.
10513 + */
10514 +#include <linux/dyn_pageflags.h>
10515 +#include <asm/setup.h>
10516 +
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;
10523 +
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;
10530 +
10531 +int suspend2_lowlevel_builtin(void);
10532 +
10533 +extern dyn_pageflags_t __nosavedata suspend2_nosave_origmap;
10534 +extern dyn_pageflags_t __nosavedata suspend2_nosave_copymap;
10535 +
10536 +#ifdef CONFIG_HIGHMEM
10537 +extern __nosavedata struct zone_data *suspend2_nosave_zone_list;
10538 +extern __nosavedata unsigned long suspend2_nosave_max_pfn;
10539 +#endif
10540 +
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
10547 @@ -0,0 +1,1018 @@
10548 +/*
10549 + * kernel/power/suspend_block_io.c
10550 + *
10551 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10552 + *
10553 + * Distributed under GPLv2.
10554 + * 
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.
10558 + *
10559 + */
10560 +
10561 +#include <linux/blkdev.h>
10562 +#include <linux/syscalls.h>
10563 +#include <linux/suspend.h>
10564 +
10565 +#include "suspend.h"
10566 +#include "sysfs.h"
10567 +#include "modules.h"
10568 +#include "prepare_image.h"
10569 +#include "block_io.h"
10570 +#include "ui.h"
10571 +
10572 +static int pr_index;
10573 +
10574 +#if 0
10575 +#define PR_DEBUG(a, b...) do { if (pr_index < 20) printk(a, ##b); } while(0)
10576 +#else
10577 +#define PR_DEBUG(a, b...) do { } while(0)
10578 +#endif
10579 +
10580 +#define MAX_OUTSTANDING_IO 2048
10581 +#define SUBMIT_BATCH_SIZE 128
10582 +
10583 +static int max_outstanding_io = MAX_OUTSTANDING_IO;
10584 +static int submit_batch_size = SUBMIT_BATCH_SIZE;
10585 +
10586 +struct io_info {
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;
10593 +};
10594 +
10595 +static LIST_HEAD(ioinfo_ready_for_cleanup);
10596 +static DEFINE_SPINLOCK(ioinfo_ready_lock);
10597 +
10598 +static LIST_HEAD(ioinfo_submit_batch);
10599 +static DEFINE_SPINLOCK(ioinfo_submit_lock);
10600 +
10601 +static LIST_HEAD(ioinfo_busy);
10602 +static DEFINE_SPINLOCK(ioinfo_busy_lock);
10603 +
10604 +static struct io_info *waiting_on;
10605 +
10606 +static atomic_t submit_batch;
10607 +static int submit_batched(void);
10608 +
10609 +/* [Max] number of I/O operations pending */
10610 +static atomic_t outstanding_io;
10611 +
10612 +static int extra_page_forward = 0;
10613 +
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;
10619 +
10620 +static int current_stream;
10621 +/* 0 = Header, 1 = Pageset1, 2 = Pageset2 */
10622 +struct extent_iterate_saved_state suspend_writer_posn_save[3];
10623 +
10624 +/* Pointer to current entry being loaded/saved. */
10625 +struct extent_iterate_state suspend_writer_posn;
10626 +
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;
10631 +
10632 +int suspend_read_fd;
10633 +
10634 +static struct suspend_bdev_info *suspend_devinfo;
10635 +
10636 +int suspend_header_bytes_used = 0;
10637 +
10638 +DEFINE_MUTEX(suspend_bio_mutex);
10639 +
10640 +/*
10641 + * __suspend_bio_cleanup_one
10642 + * 
10643 + * Description: Clean up after completing I/O on a page.
10644 + * Arguments:  struct io_info: Data for I/O to be completed.
10645 + */
10646 +static void __suspend_bio_cleanup_one(struct io_info *io_info)
10647 +{
10648 +       suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
10649 +               "Cleanup IO: [%p]\n", io_info);
10650 +
10651 +       if (!io_info->writing && io_info->readahead_index == -1) {
10652 +               char *from, *to;
10653 +               /*
10654 +                * Copy the page we read into the buffer our caller provided.
10655 +                */
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);
10661 +       }
10662 +
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);
10672 +       } else
10673 +               put_page(io_info->bio_page);
10674 +       
10675 +       bio_put(io_info->sys_struct);
10676 +       io_info->sys_struct = NULL;
10677 +}
10678 +
10679 +/* __suspend_io_cleanup
10680 + */
10681 +
10682 +static void suspend_bio_cleanup_one(void *data)
10683 +{
10684 +       struct io_info *io_info = (struct io_info *) data;
10685 +       int readahead_index;
10686 +       unsigned long flags;
10687 +
10688 +       readahead_index = io_info->readahead_index;
10689 +       list_del_init(&io_info->list);
10690 +       __suspend_bio_cleanup_one(io_info);
10691 +
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);
10698 +       }
10699 +
10700 +       if (waiting_on == io_info)
10701 +               waiting_on = NULL;
10702 +       kfree(io_info);
10703 +       atomic_dec(&outstanding_io);
10704 +}
10705 +
10706 +/* suspend_cleanup_some_completed_io
10707 + *
10708 + * NB: This is designed so that multiple callers can be in here simultaneously.
10709 + */
10710 +
10711 +static void suspend_cleanup_some_completed_io(void)
10712 +{
10713 +       int num_cleaned = 0;
10714 +       struct io_info *first;
10715 +       unsigned long flags;
10716 +
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);
10721 +
10722 +               list_del_init(&first->list);
10723 +
10724 +               spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10725 +               suspend_bio_cleanup_one((void *) first);
10726 +               spin_lock_irqsave(&ioinfo_ready_lock, flags);
10727 +
10728 +               num_cleaned++;
10729 +               if (num_cleaned == submit_batch_size)
10730 +                       break;
10731 +       }
10732 +       spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10733 +}
10734 +
10735 +/* do_bio_wait
10736 + *
10737 + * Actions taken when we want some I/O to get run.
10738 + * 
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.
10741 + */
10742 +static void do_bio_wait(void)
10743 +{
10744 +       int num_submitted = 0;
10745 +
10746 +       /* Don't want to wait on I/O we haven't submitted! */
10747 +       num_submitted = submit_batched();
10748 +       
10749 +       io_schedule();
10750 +
10751 +       suspend_cleanup_some_completed_io();
10752 +}
10753 +
10754 +/*
10755 + * suspend_finish_all_io
10756 + *
10757 + * Description:        Finishes all IO and frees all IO info struct pages.
10758 + */
10759 +static void suspend_finish_all_io(void)
10760 +{
10761 +       /* Wait for all I/O to complete. */
10762 +       while (atomic_read(&outstanding_io))
10763 +               do_bio_wait();
10764 +}
10765 +
10766 +/*
10767 + * wait_on_readahead
10768 + *
10769 + * Wait until a particular readahead is ready.
10770 + */
10771 +static void suspend_wait_on_readahead(int readahead_index)
10772 +{
10773 +       int index = readahead_index / BITS_PER_LONG;
10774 +       int bit = readahead_index - index * BITS_PER_LONG;
10775 +
10776 +       /* read_ahead_index is the one we want to return */
10777 +       while (!test_bit(bit, &suspend_readahead_flags[index]))
10778 +               do_bio_wait();
10779 +}
10780 +
10781 +/*
10782 + * readahead_done
10783 + *
10784 + * Returns whether the readahead requested is ready.
10785 + */
10786 +
10787 +static int suspend_readahead_ready(int readahead_index)
10788 +{
10789 +       int index = readahead_index / BITS_PER_LONG;
10790 +       int bit = readahead_index - (index * BITS_PER_LONG);
10791 +
10792 +       return test_bit(bit, &suspend_readahead_flags[index]);
10793 +}
10794 +
10795 +/* suspend_readahead_prepare
10796 + * Set up for doing readahead on an image */
10797 +static int suspend_prepare_readahead(int index)
10798 +{
10799 +       unsigned long new_page = get_zeroed_page(GFP_ATOMIC | __GFP_NOWARN);
10800 +
10801 +       if(!new_page)
10802 +               return -ENOMEM;
10803 +
10804 +       suspend_readahead_pages[index] = virt_to_page(new_page);
10805 +       return 0;
10806 +}
10807 +
10808 +/* suspend_readahead_cleanup
10809 + * Clean up structures used for readahead */
10810 +static void suspend_cleanup_readahead(int page)
10811 +{
10812 +       __free_page(suspend_readahead_pages[page]);
10813 +       suspend_readahead_pages[page] = 0;
10814 +       return;
10815 +}
10816 +
10817 +/*
10818 + * suspend_end_bio
10819 + *
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.
10825 + */
10826 +
10827 +static int suspend_end_bio(struct bio *bio, unsigned int num, int err)
10828 +{
10829 +       struct io_info *io_info = bio->bi_private;
10830 +       unsigned long flags;
10831 +
10832 +       spin_lock_irqsave(&ioinfo_busy_lock, flags);
10833 +       list_del_init(&io_info->list);
10834 +       spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
10835 +
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);
10839 +       return 0;
10840 +}
10841 +
10842 +/**
10843 + *     submit - submit BIO request.
10844 + *     @writing: READ or WRITE.
10845 + *     @io_info: IO info structure.
10846 + *
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."
10851 + *
10852 + *     With a twist, though - we handle block_size != PAGE_SIZE.
10853 + *     Caller has already checked that our page is not fragmented.
10854 + */
10855 +
10856 +static int submit(struct io_info *io_info)
10857 +{
10858 +       struct bio *bio = NULL;
10859 +       unsigned long flags;
10860 +
10861 +       while (!bio) {
10862 +               bio = bio_alloc(GFP_ATOMIC,1);
10863 +               if (!bio)
10864 +                       do_bio_wait();
10865 +       }
10866 +
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;
10872 +
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);
10876 +               bio_put(bio);
10877 +               return -EFAULT;
10878 +       }
10879 +
10880 +       if (io_info->writing)
10881 +               bio_set_pages_dirty(bio);
10882 +
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);
10886 +       
10887 +       submit_bio(io_info->writing, bio);
10888 +
10889 +       return 0;
10890 +}
10891 +
10892 +/* 
10893 + * submit a batch. The submit function can wait on I/O, so we have
10894 + * simple locking to avoid infinite recursion.
10895 + */
10896 +static int submit_batched(void)
10897 +{
10898 +       static int running_already = 0;
10899 +       struct io_info *first;
10900 +       unsigned long flags;
10901 +       int num_submitted = 0;
10902 +
10903 +       if (running_already)
10904 +               return 0;
10905 +
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,
10910 +                               list);
10911 +               list_del_init(&first->list);
10912 +               atomic_dec(&submit_batch);
10913 +               spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10914 +               submit(first);
10915 +               spin_lock_irqsave(&ioinfo_submit_lock, flags);
10916 +               num_submitted++;
10917 +               if (num_submitted == submit_batch_size)
10918 +                       break;
10919 +       }
10920 +       spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10921 +       running_already = 0;
10922 +
10923 +       return num_submitted;
10924 +}
10925 +
10926 +static void add_to_batch(struct io_info *io_info)
10927 +{
10928 +       unsigned long flags;
10929 +       int waiting;
10930 +
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);
10936 +
10937 +       if (waiting >= submit_batch_size)
10938 +               submit_batched();
10939 +}
10940 +
10941 +/*
10942 + * get_io_info_struct
10943 + *
10944 + * Description:        Get an I/O struct.
10945 + * Returns:    Pointer to the struct prepared for use.
10946 + */
10947 +static struct io_info *get_io_info_struct(void)
10948 +{
10949 +       struct io_info *this = NULL;
10950 +
10951 +       do {
10952 +               while (atomic_read(&outstanding_io) >= max_outstanding_io)
10953 +                       do_bio_wait();
10954 +
10955 +               this = kmalloc(sizeof(struct io_info), GFP_ATOMIC);
10956 +       } while (!this);
10957 +
10958 +       INIT_LIST_HEAD(&this->list);
10959 +       return this;
10960 +}
10961 +
10962 +/*
10963 + * suspend_do_io
10964 + *
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.
10974 + */
10975 +static int suspend_do_io(int writing, struct block_device *bdev, long block0,
10976 +       struct page *page, int readahead_index, int syncio)
10977 +{
10978 +       struct io_info *io_info;
10979 +       unsigned long buffer_virt = 0;
10980 +       char *to, *from;
10981 +
10982 +       io_info = get_io_info_struct();
10983 +
10984 +       /* Done before submitting to avoid races. */
10985 +       if (syncio)
10986 +               waiting_on = io_info;
10987 +
10988 +       /* Get our local buffer */
10989 +       suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
10990 +                       "Start_IO: [%p]", io_info);
10991 +       
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;
10998 +
10999 +       if (io_info->readahead_index == -1) {
11000 +               while (!(buffer_virt = get_zeroed_page(GFP_ATOMIC | __GFP_NOWARN)))
11001 +                       do_bio_wait();
11002 +
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);
11007 +       } else {
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;
11011 +
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);
11015 +
11016 +               io_info->bio_page = page;
11017 +       }
11018 +
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. */
11023 +       if (writing) {
11024 +               to = (char *) buffer_virt;
11025 +               from = kmap_atomic(page, KM_USER1);
11026 +               memcpy(to, from, PAGE_SIZE);
11027 +               kunmap_atomic(from, KM_USER1);
11028 +       }
11029 +
11030 +       /* Submit the page */
11031 +       get_page(io_info->bio_page);
11032 +       
11033 +       suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
11034 +               "-> (PRE BRW) %d\n", real_nr_free_pages(all_zones_mask));
11035 +
11036 +       if (syncio)
11037 +               submit(io_info);
11038 +       else
11039 +               add_to_batch(io_info);
11040 +       
11041 +       atomic_inc(&outstanding_io);
11042 +       
11043 +       if (syncio)
11044 +               do { do_bio_wait(); } while (waiting_on);
11045 +
11046 +       return 0;
11047 +}
11048 +
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).
11052 + */
11053 +
11054 +static int suspend_bdev_page_io(int writing, struct block_device *bdev,
11055 +               long pos, struct page *page)
11056 +{
11057 +       return suspend_do_io(writing, bdev, pos, page, -1, 1);
11058 +}
11059 +
11060 +static int suspend_bio_memory_needed(void)
11061 +{
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)));
11067 +}
11068 +
11069 +static void suspend_set_devinfo(struct suspend_bdev_info *info)
11070 +{
11071 +       suspend_devinfo = info;
11072 +}
11073 +
11074 +static void dump_block_chains(void)
11075 +{
11076 +       int i;
11077 +
11078 +       for (i = 0; i < suspend_writer_posn.num_chains; i++) {
11079 +               struct extent *this;
11080 +
11081 +               printk("Chain %d:", i);
11082 +
11083 +               this = (suspend_writer_posn.chains + i)->first;
11084 +
11085 +               if (!this)
11086 +                       printk(" (Empty)");
11087 +
11088 +               while (this) {
11089 +                       printk(" [%lu-%lu]%s", this->minimum, this->maximum,
11090 +                                       this->next ? "," : "");
11091 +                       this = this->next;
11092 +               }
11093 +
11094 +               printk("\n");
11095 +       }
11096 +
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);
11102 +}
11103 +static int forward_extra_blocks(void)
11104 +{
11105 +       int i;
11106 +
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);
11110 +
11111 +       if (suspend_extent_state_eof(&suspend_writer_posn)) {
11112 +               printk("Extent state eof.\n");
11113 +               dump_block_chains();
11114 +               return -ENODATA;
11115 +       }
11116 +
11117 +       return 0;
11118 +}
11119 +
11120 +static int forward_one_page(void)
11121 +{
11122 +       int at_start = (suspend_writer_posn.current_chain == -1);
11123 +
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);
11127 +
11128 +       if (!at_start && forward_extra_blocks())
11129 +               return -ENODATA;
11130 +
11131 +       if (extra_page_forward) {
11132 +               extra_page_forward = 0;
11133 +               return forward_one_page();
11134 +       }
11135 +
11136 +       return 0;
11137 +}
11138 +
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)
11142 +{
11143 +       extra_page_forward = 1;
11144 +}
11145 +
11146 +static int suspend_bio_rw_page(int writing, struct page *page,
11147 +               int readahead_index, int sync)
11148 +{
11149 +       struct suspend_bdev_info *dev_info;
11150 +
11151 +       if (test_action_state(SUSPEND_TEST_FILTER_SPEED))
11152 +               return 0;
11153 +               
11154 +       if (forward_one_page()) {
11155 +               printk("Failed to advance a page in the extent data.\n");
11156 +               return -ENODATA;
11157 +       }
11158 +
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();
11163 +               BUG();
11164 +       }
11165 +
11166 +       dev_info = &suspend_devinfo[suspend_writer_posn.current_chain];
11167 +
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);
11172 +}
11173 +
11174 +static int suspend_rw_init(int writing, int stream_number)
11175 +{
11176 +       suspend_header_bytes_used = 0;
11177 +
11178 +       suspend_extent_state_restore(&suspend_writer_posn,
11179 +                       &suspend_writer_posn_save[stream_number]);
11180 +
11181 +       suspend_writer_buffer_posn = writing ? 0 : PAGE_SIZE;
11182 +
11183 +       current_stream = stream_number;
11184 +
11185 +       readahead_index = readahead_submit_index = -1;
11186 +
11187 +       pr_index = 0;
11188 +
11189 +       return 0;
11190 +}
11191 +
11192 +static void suspend_read_header_init(void)
11193 +{
11194 +       readahead_index = readahead_submit_index = -1;
11195 +}
11196 +
11197 +static int suspend_rw_cleanup(int writing)
11198 +{
11199 +       if (writing && suspend_bio_rw_page(WRITE,
11200 +                       virt_to_page(suspend_writer_buffer), -1, 0))
11201 +               return -EIO;
11202 +
11203 +       if (writing && current_stream == 2)
11204 +               suspend_extent_state_save(&suspend_writer_posn,
11205 +                               &suspend_writer_posn_save[1]);
11206 +       
11207 +       suspend_finish_all_io();
11208 +       
11209 +       if (!writing)
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;
11215 +               }
11216 +
11217 +       current_stream = 0;
11218 +
11219 +       return 0;
11220 +}
11221 +
11222 +static int suspend_bio_read_page_with_readahead(void)
11223 +{
11224 +       static int last_result;
11225 +       unsigned long *virt;
11226 +
11227 +       if (readahead_index == -1) {
11228 +               last_result = 0;
11229 +               readahead_index = readahead_submit_index = 0;
11230 +       }
11231 +
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");
11239 +                       return -EIO;
11240 +               }
11241 +               goto wait;
11242 +       }
11243 +       
11244 +       do {
11245 +               if (suspend_prepare_readahead(readahead_submit_index))
11246 +                       break;
11247 +
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);
11255 +                       break;
11256 +               }
11257 +
11258 +               readahead_submit_index++;
11259 +
11260 +               if (readahead_submit_index == max_outstanding_io)
11261 +                       readahead_submit_index = 0;
11262 +
11263 +       } while((!last_result) && (readahead_submit_index != readahead_index) &&
11264 +                       (!suspend_readahead_ready(readahead_index)));
11265 +
11266 +wait:
11267 +       suspend_wait_on_readahead(readahead_index);
11268 +
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);
11272 +
11273 +       suspend_cleanup_readahead(readahead_index);
11274 +
11275 +       readahead_index++;
11276 +       if (readahead_index == max_outstanding_io)
11277 +               readahead_index = 0;
11278 +
11279 +       return 0;
11280 +}
11281 +
11282 +/*
11283 + *
11284 + */
11285 +
11286 +static int suspend_rw_buffer(int writing, char *buffer, int buffer_size)
11287 +{
11288 +       int bytes_left = buffer_size;
11289 +
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;
11297 +
11298 +               if (bytes_left <= capacity) {
11299 +                       if (test_debug_state(SUSPEND_HEADER))
11300 +                               printk("Copy %d bytes %d-%d from %p to %p.\n",
11301 +                                               bytes_left,
11302 +                                               suspend_header_bytes_used,
11303 +                                               suspend_header_bytes_used + bytes_left,
11304 +                                               from, to);
11305 +                       memcpy(to, from, bytes_left);
11306 +                       suspend_writer_buffer_posn += bytes_left;
11307 +                       suspend_header_bytes_used += bytes_left;
11308 +                       return 0;
11309 +               }
11310 +
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",
11314 +                                       capacity,
11315 +                                       suspend_header_bytes_used,
11316 +                                       suspend_header_bytes_used + capacity,
11317 +                                       from, to);
11318 +               memcpy(to, from, capacity);
11319 +               bytes_left -= capacity;
11320 +               suspend_header_bytes_used += capacity;
11321 +
11322 +               if (!writing) {
11323 +                       if (test_suspend_state(SUSPEND_TRY_RESUME_RD))
11324 +                               sys_read(suspend_read_fd,
11325 +                                       suspend_writer_buffer, BLOCK_SIZE);
11326 +                       else
11327 +                               if (suspend_bio_read_page_with_readahead())
11328 +                                       return -EIO;
11329 +               } else if (suspend_bio_rw_page(WRITE,
11330 +                                       virt_to_page(suspend_writer_buffer),
11331 +                                       -1, SUSPEND_ASYNC))
11332 +                               return -EIO;
11333 +
11334 +               suspend_writer_buffer_posn = 0;
11335 +               suspend_cond_pause(0, NULL);
11336 +       }
11337 +
11338 +       return 0;
11339 +}
11340 +
11341 +/*
11342 + * suspend_bio_read_chunk
11343 + *
11344 + * Read a (possibly compressed and/or encrypted) page from the image,
11345 + * into buffer_page, returning it's index and the buffer size.
11346 + *
11347 + * If asynchronous I/O is requested, use readahead.
11348 + */
11349 +
11350 +static int suspend_bio_read_chunk(unsigned long *index, struct page *buffer_page,
11351 +               unsigned int *buf_size, int sync)
11352 +{
11353 +       int result;
11354 +       char *buffer_virt = kmap(buffer_page);
11355 +
11356 +       pr_index++;
11357 +
11358 +       while (!mutex_trylock(&suspend_bio_mutex))
11359 +               do_bio_wait();
11360 +       
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);
11365 +               goto out;
11366 +       }
11367 +
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);
11371 +               goto out;
11372 +       }
11373 +
11374 +       result = suspend_rw_buffer(READ, buffer_virt, *buf_size);
11375 +       if (result)
11376 +               abort_suspend(SUSPEND_FAILED_IO,
11377 +                               "Read of data returned %d.\n", result);
11378 +
11379 +       PR_DEBUG("%d: Index %ld, %d bytes.\n", pr_index, *index, *buf_size);
11380 +out:
11381 +       mutex_unlock(&suspend_bio_mutex);
11382 +       kunmap(buffer_page);
11383 +       if (result)
11384 +               abort_suspend(SUSPEND_FAILED_IO,
11385 +                       "Returning %d from suspend_bio_read_chunk.\n", result);
11386 +       return result;
11387 +}
11388 +
11389 +/*
11390 + * suspend_bio_write_chunk
11391 + *
11392 + * Write a (possibly compressed and/or encrypted) page to the image from
11393 + * the buffer, together with it's index and buffer size.
11394 + */
11395 +
11396 +static int suspend_bio_write_chunk(unsigned long index, struct page *buffer_page,
11397 +               unsigned int buf_size)
11398 +{
11399 +       int result;
11400 +       char *buffer_virt = kmap(buffer_page);
11401 +
11402 +       pr_index++;
11403 +
11404 +       while (!mutex_trylock(&suspend_bio_mutex))
11405 +               do_bio_wait();
11406 +       
11407 +       if ((result = suspend_rw_buffer(WRITE, (char *) &index,
11408 +                                       sizeof(unsigned long))))
11409 +               goto out;
11410 +
11411 +       if ((result = suspend_rw_buffer(WRITE, (char *) &buf_size, sizeof(int))))
11412 +               goto out;
11413 +
11414 +       result = suspend_rw_buffer(WRITE, buffer_virt, buf_size);
11415 +
11416 +       PR_DEBUG("%d: Index %ld, %d bytes.\n", pr_index, index, buf_size);
11417 +out:
11418 +       mutex_unlock(&suspend_bio_mutex);
11419 +       kunmap(buffer_page);
11420 +       return result;
11421 +}
11422 +
11423 +/*
11424 + * suspend_rw_header_chunk
11425 + *
11426 + * Read or write a portion of the header.
11427 + */
11428 +
11429 +static int suspend_rw_header_chunk(int writing,
11430 +               struct suspend_module_ops *owner,
11431 +               char *buffer, int buffer_size)
11432 +{
11433 +       if (owner) {
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",
11438 +                               owner->name,
11439 +                               owner->header_used,
11440 +                               owner->header_requested);
11441 +                       return buffer_size;
11442 +               }
11443 +       }
11444 +
11445 +       return suspend_rw_buffer(writing, buffer, buffer_size);
11446 +}
11447 +
11448 +/*
11449 + * write_header_chunk_finish
11450 + *
11451 + * Flush any buffered writes in the section of the image.
11452 + */
11453 +static int write_header_chunk_finish(void)
11454 +{
11455 +       return suspend_bio_rw_page(WRITE, virt_to_page(suspend_writer_buffer),
11456 +               -1, 0) ? -EIO : 0;
11457 +}
11458 +
11459 +static int suspend_bio_storage_needed(void)
11460 +{
11461 +       return 2 * sizeof(int);
11462 +}
11463 +
11464 +static int suspend_bio_save_config_info(char *buf)
11465 +{
11466 +       int *ints = (int *) buf;
11467 +       ints[0] = max_outstanding_io;
11468 +       ints[1] = submit_batch_size;
11469 +       return 2 * sizeof(int);
11470 +}
11471 +
11472 +static void suspend_bio_load_config_info(char *buf, int size)
11473 +{
11474 +       int *ints = (int *) buf;
11475 +       max_outstanding_io  = ints[0];
11476 +       submit_batch_size = ints[1];
11477 +}
11478 +
11479 +static int suspend_bio_initialise(int starting_cycle)
11480 +{
11481 +       suspend_writer_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
11482 +
11483 +       return suspend_writer_buffer ? 0 : -ENOMEM;
11484 +}
11485 +
11486 +static void suspend_bio_cleanup(int finishing_cycle)
11487 +{
11488 +       if (suspend_writer_buffer) {
11489 +               free_page((unsigned long) suspend_writer_buffer);
11490 +               suspend_writer_buffer = NULL;
11491 +       }
11492 +}
11493 +
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,
11507 +};
11508 +
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),
11512 +       },
11513 +
11514 +       { SUSPEND2_ATTR("submit_batch_size", SYSFS_RW),
11515 +         SYSFS_INT(&submit_batch_size, 16, SUBMIT_BATCH_SIZE, 0),
11516 +       }
11517 +};
11518 +
11519 +static struct suspend_module_ops suspend_blockwriter_ops = 
11520 +{
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,
11531 +
11532 +       .sysfs_data             = sysfs_params,
11533 +       .num_sysfs_entries      = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
11534 +};
11535 +
11536 +static __init int suspend_block_io_load(void)
11537 +{
11538 +       return suspend_register_module(&suspend_blockwriter_ops);
11539 +}
11540 +
11541 +#ifdef CONFIG_SUSPEND2_FILE_EXPORTS
11542 +EXPORT_SYMBOL_GPL(suspend_read_fd);
11543 +#endif
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);
11551 +#endif
11552 +#ifdef MODULE
11553 +static __exit void suspend_block_io_unload(void)
11554 +{
11555 +       suspend_unregister_module(&suspend_blockwriter_ops);
11556 +}
11557 +
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");
11563 +#else
11564 +late_initcall(suspend_block_io_load);
11565 +#endif
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
11569 @@ -0,0 +1,436 @@
11570 +/*
11571 + * kernel/power/compression.c
11572 + *
11573 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
11574 + *
11575 + * This file is released under the GPLv2.
11576 + *
11577 + * This file contains data compression routines for suspend,
11578 + * using cryptoapi.
11579 + */
11580 +
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>
11586 +
11587 +#include "suspend2_builtin.h"
11588 +#include "suspend.h"
11589 +#include "modules.h"
11590 +#include "sysfs.h"
11591 +#include "io.h"
11592 +#include "ui.h"
11593 +
11594 +static int suspend_expected_compression = 0;
11595 +
11596 +static struct suspend_module_ops suspend_compression_ops;
11597 +static struct suspend_module_ops *next_driver;
11598 +
11599 +static char suspend_compressor_name[32] = "lzf";
11600 +
11601 +static DEFINE_MUTEX(stats_lock);
11602 +
11603 +struct cpu_context {
11604 +       u8 * page_buffer;
11605 +       struct crypto_comp *transform;
11606 +       unsigned int len;
11607 +       char *buffer_start;
11608 +};
11609 +
11610 +static DEFINE_PER_CPU(struct cpu_context, contexts);
11611 +
11612 +static int suspend_compress_prepare_result;
11613 +
11614 +/* 
11615 + * suspend_compress_cleanup
11616 + *
11617 + * Frees memory allocated for our labours.
11618 + */
11619 +static void suspend_compress_cleanup(int suspend_or_resume)
11620 +{
11621 +       int cpu;
11622 +
11623 +       if (!suspend_or_resume)
11624 +               return;
11625 +
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;
11631 +               }
11632 +
11633 +               if (this->page_buffer)
11634 +                       free_page((unsigned long) this->page_buffer);
11635 +
11636 +               this->page_buffer = NULL;
11637 +       }
11638 +}
11639 +
11640 +/* 
11641 + * suspend_crypto_prepare
11642 + *
11643 + * Prepare to do some work by allocating buffers and transforms.
11644 + */
11645 +static int suspend_compress_crypto_prepare(void)
11646 +{
11647 +       int cpu;
11648 +
11649 +       if (!*suspend_compressor_name) {
11650 +               printk("Suspend2: Compression enabled but no compressor name set.\n");
11651 +               return 1;
11652 +       }
11653 +
11654 +       for_each_online_cpu(cpu) {
11655 +               struct cpu_context *this = &per_cpu(contexts, cpu);
11656 +               this->transform = crypto_alloc_comp(suspend_compressor_name,
11657 +                               0, 0);
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;
11663 +                       return 1;
11664 +               }
11665 +
11666 +               this->page_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
11667 +       
11668 +               if (!this->page_buffer) {
11669 +                       printk(KERN_ERR
11670 +                         "Failed to allocate a page buffer for suspend2 "
11671 +                         "encryption driver.\n");
11672 +                       return -ENOMEM;
11673 +               }
11674 +       }
11675 +
11676 +       return 0;
11677 +}
11678 +
11679 +/*
11680 + * suspend_compress_init
11681 + */
11682 +
11683 +static int suspend_compress_init(int suspend_or_resume)
11684 +{
11685 +       if (!suspend_or_resume)
11686 +               return 0;
11687 +
11688 +       suspend_compress_bytes_in = suspend_compress_bytes_out = 0;
11689 +
11690 +       next_driver = suspend_get_next_filter(&suspend_compression_ops);
11691 +
11692 +       if (!next_driver) {
11693 +               printk("Compression Driver: Argh! Nothing follows me in"
11694 +                               " the pipeline!\n");
11695 +               return -ECHILD;
11696 +       }
11697 +
11698 +       suspend_compress_prepare_result = suspend_compress_crypto_prepare();
11699 +
11700 +       return 0;
11701 +}
11702 +
11703 +/*
11704 + * suspend_compress_rw_init()
11705 + */
11706 +
11707 +int suspend_compress_rw_init(int rw, int stream_number)
11708 +{
11709 +       if (suspend_compress_prepare_result) {
11710 +               printk("Failed to initialise compression algorithm.\n");
11711 +               if (rw == READ)
11712 +                       return -ENODEV;
11713 +               else
11714 +                       suspend_compression_ops.enabled = 0;
11715 +       }
11716 +
11717 +       return 0;
11718 +}
11719 +
11720 +/* 
11721 + * suspend_compress_write_chunk()
11722 + *
11723 + * Compress a page of data, buffering output and passing on filled
11724 + * pages to the next module in the pipeline.
11725 + * 
11726 + * Buffer_page:        Pointer to a buffer of size PAGE_SIZE, containing
11727 + * data to be compressed.
11728 + *
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
11731 + *             zlib errs.
11732 + */
11733 +static int suspend_compress_write_chunk(unsigned long index,
11734 +               struct page *buffer_page, unsigned int buf_size)
11735 +{
11736 +       int ret, cpu = smp_processor_id();
11737 +       struct cpu_context *ctx = &per_cpu(contexts, cpu);
11738 +       
11739 +       if (!ctx->transform)
11740 +               return next_driver->write_chunk(index, buffer_page, buf_size);
11741 +
11742 +       ctx->buffer_start = kmap(buffer_page);
11743 +
11744 +       ctx->len = buf_size;
11745 +
11746 +       ret = crypto_comp_compress(ctx->transform,
11747 +                       ctx->buffer_start, buf_size,
11748 +                       ctx->page_buffer, &ctx->len);
11749 +       
11750 +       kunmap(buffer_page);
11751 +
11752 +       if (ret) {
11753 +               printk("Compression failed.\n");
11754 +               goto failure;
11755 +       }
11756 +       
11757 +       mutex_lock(&stats_lock);
11758 +       suspend_compress_bytes_in += buf_size;
11759 +       suspend_compress_bytes_out += ctx->len;
11760 +       mutex_unlock(&stats_lock);
11761 +
11762 +       if (ctx->len < buf_size) /* some compression */
11763 +               ret = next_driver->write_chunk(index,
11764 +                               virt_to_page(ctx->page_buffer),
11765 +                               ctx->len);
11766 +       else
11767 +               ret = next_driver->write_chunk(index, buffer_page, buf_size);
11768 +
11769 +failure:
11770 +       return ret;
11771 +}
11772 +
11773 +/* 
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
11777 + *             synchronously.
11778 + *
11779 + * Retrieve data from later modules and decompress it until the input buffer
11780 + * is filled.
11781 + * Zero if successful. Error condition from me or from downstream on failure.
11782 + */
11783 +static int suspend_compress_read_chunk(unsigned long *index,
11784 +               struct page *buffer_page, unsigned int *buf_size, int sync)
11785 +{
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);
11791 +
11792 +       if (!ctx->transform)
11793 +               return next_driver->read_chunk(index, buffer_page, buf_size,
11794 +                               sync);
11795 +
11796 +       /* 
11797 +        * All our reads must be synchronous - we can't decompress
11798 +        * data that hasn't been read yet.
11799 +        */
11800 +
11801 +       *buf_size = PAGE_SIZE;
11802 +
11803 +       ret = next_driver->read_chunk(index, buffer_page, &len, SUSPEND_SYNC);
11804 +
11805 +       /* Error or uncompressed data */
11806 +       if (ret || len == PAGE_SIZE)
11807 +               return ret;
11808 +
11809 +       buffer_start = kmap(buffer_page);
11810 +       memcpy(ctx->page_buffer, buffer_start, len);
11811 +       ret = crypto_comp_decompress(
11812 +                       ctx->transform,
11813 +                       ctx->page_buffer,
11814 +                       len, buffer_start, &outlen);
11815 +       if (ret)
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);
11822 +               ret = -EIO;
11823 +               *buf_size = outlen;
11824 +       }
11825 +       kunmap(buffer_page);
11826 +       return ret;
11827 +}
11828 +
11829 +/* 
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.
11833 + *
11834 + * Print information to be recorded for debugging purposes into a buffer.
11835 + * Returns: Number of characters written to the buffer.
11836 + */
11837 +
11838 +static int suspend_compress_print_debug_stats(char *buffer, int size)
11839 +{
11840 +       int pages_in = suspend_compress_bytes_in >> PAGE_SHIFT, 
11841 +           pages_out = suspend_compress_bytes_out >> PAGE_SHIFT;
11842 +       int len;
11843 +       
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);
11848 +       else
11849 +               len = snprintf_used(buffer, size, "- Compressor is not set.\n");
11850 +
11851 +       if (pages_in)
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);
11857 +       return len;
11858 +}
11859 +
11860 +/* 
11861 + * suspend_compress_compression_memory_needed
11862 + *
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
11865 + * operation.
11866 + */
11867 +static int suspend_compress_memory_needed(void)
11868 +{
11869 +       return 2 * PAGE_SIZE;
11870 +}
11871 +
11872 +static int suspend_compress_storage_needed(void)
11873 +{
11874 +       return 4 * sizeof(unsigned long) + strlen(suspend_compressor_name) + 1;
11875 +}
11876 +
11877 +/* 
11878 + * suspend_compress_save_config_info
11879 + * @buffer: Pointer to a buffer of size PAGE_SIZE.
11880 + *
11881 + * Save informaton needed when reloading the image at resume time.
11882 + * Returns: Number of bytes used for saving our data.
11883 + */
11884 +static int suspend_compress_save_config_info(char *buffer)
11885 +{
11886 +       int namelen = strlen(suspend_compressor_name) + 1;
11887 +       int total_len;
11888 +       
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, 
11896 +                                                               namelen);
11897 +       total_len = 4 * sizeof(unsigned long) + namelen;
11898 +       return total_len;
11899 +}
11900 +
11901 +/* suspend_compress_load_config_info
11902 + * @buffer: Pointer to the start of the data.
11903 + * @size: Number of bytes that were saved.
11904 + *
11905 + * Description:        Reload information needed for decompressing the image at
11906 + * resume time.
11907 + */
11908 +static void suspend_compress_load_config_info(char *buffer, int size)
11909 +{
11910 +       int namelen;
11911 +       
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),
11918 +                       namelen);
11919 +       return;
11920 +}
11921 +
11922 +/* 
11923 + * suspend_expected_compression_ratio
11924 + * 
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.
11929 + */
11930 +
11931 +static int suspend_compress_expected_ratio(void)
11932 +{
11933 +       if (!suspend_compression_ops.enabled)
11934 +               return 100;
11935 +       else
11936 +               return 100 - suspend_expected_compression;
11937 +}
11938 +
11939 +/*
11940 + * data for our sysfs entries.
11941 + */
11942 +static struct suspend_sysfs_data sysfs_params[] = {
11943 +       {
11944 +               SUSPEND2_ATTR("expected_compression", SYSFS_RW),
11945 +               SYSFS_INT(&suspend_expected_compression, 0, 99, 0)
11946 +       },
11947 +
11948 +       {
11949 +               SUSPEND2_ATTR("enabled", SYSFS_RW),
11950 +               SYSFS_INT(&suspend_compression_ops.enabled, 0, 1, 0)
11951 +       },
11952 +
11953 +       {
11954 +               SUSPEND2_ATTR("algorithm", SYSFS_RW),
11955 +               SYSFS_STRING(suspend_compressor_name, 31, 0)
11956 +       }
11957 +};
11958 +
11959 +/*
11960 + * Ops structure.
11961 + */
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,
11975 +       
11976 +       .rw_init                = suspend_compress_rw_init,
11977 +
11978 +       .write_chunk            = suspend_compress_write_chunk,
11979 +       .read_chunk             = suspend_compress_read_chunk,
11980 +
11981 +       .sysfs_data             = sysfs_params,
11982 +       .num_sysfs_entries      = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
11983 +};
11984 +
11985 +/* ---- Registration ---- */
11986 +
11987 +static __init int suspend_compress_load(void)
11988 +{
11989 +       return suspend_register_module(&suspend_compression_ops);
11990 +}
11991 +
11992 +#ifdef MODULE
11993 +static __exit void suspend_compress_unload(void)
11994 +{
11995 +       suspend_unregister_module(&suspend_compression_ops);
11996 +}
11997 +
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");
12003 +#else
12004 +late_initcall(suspend_compress_load);
12005 +#endif
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
12009 @@ -0,0 +1,1131 @@
12010 +/*
12011 + * kernel/power/suspend_file.c
12012 + *
12013 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
12014 + *
12015 + * Distributed under GPLv2.
12016 + * 
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.
12021 + *
12022 + * The user can just
12023 + *
12024 + * echo Suspend2 > /path/to/my_file
12025 + *
12026 + * and
12027 + *
12028 + * echo /path/to/my_file > /sys/power/suspend2/suspend_file/target
12029 + *
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).
12032 + *
12033 + * Having done this, they're ready to suspend and resume.
12034 + *
12035 + * TODO:
12036 + * - File resizing.
12037 + */
12038 +
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>
12050 +
12051 +#include "suspend.h"
12052 +#include "sysfs.h"
12053 +#include "modules.h"
12054 +#include "ui.h"
12055 +#include "extent.h"
12056 +#include "io.h"
12057 +#include "storage.h"
12058 +#include "block_io.h"
12059 +
12060 +static struct suspend_module_ops suspend_fileops;
12061 +
12062 +/* Details of our target.  */
12063 +
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;
12074 +
12075 +static char HaveImage[] = "HaveImage\n";
12076 +static char NoImage[] =   "Suspend2\n";
12077 +#define sig_size (sizeof(HaveImage) + 1)
12078 +
12079 +struct suspend_file_header {
12080 +       char sig[sig_size];
12081 +       int resumed_before;
12082 +       unsigned long first_header_block;
12083 +};
12084 +
12085 +extern char *__initdata root_device_name;
12086 +
12087 +/* Header Page Information */
12088 +static int header_pages_allocated;
12089 +
12090 +/* Main Storage Pages */
12091 +static int main_pages_allocated, main_pages_requested;
12092 +
12093 +#define target_is_normal_file() (S_ISREG(target_inode->i_mode))
12094 +
12095 +static struct suspend_bdev_info devinfo;
12096 +
12097 +/* Extent chain for blocks */
12098 +static struct extent_chain block_chain;
12099 +
12100 +/* Signature operations */
12101 +enum {
12102 +       GET_IMAGE_EXISTS,
12103 +       INVALIDATE,
12104 +       MARK_RESUME_ATTEMPTED,
12105 +       UNMARK_RESUME_ATTEMPTED,
12106 +};
12107 +
12108 +static void set_devinfo(struct block_device *bdev, int target_blkbits)
12109 +{
12110 +       devinfo.bdev = bdev;
12111 +       if (!target_blkbits) {
12112 +               devinfo.bmap_shift = devinfo.blocks_per_page = 0;
12113 +       } else {
12114 +               devinfo.bmap_shift = target_blkbits - 9;
12115 +               devinfo.blocks_per_page = (1 << (PAGE_SHIFT - target_blkbits));
12116 +       }
12117 +}
12118 +
12119 +static int adjust_for_extra_pages(int unadjusted)
12120 +{
12121 +       return (unadjusted << PAGE_SHIFT) / (PAGE_SIZE + sizeof(unsigned long)
12122 +                       + sizeof(int));
12123 +}
12124 +
12125 +static int suspend_file_storage_available(void)
12126 +{
12127 +       int result = 0;
12128 +       struct block_device *bdev=suspend_file_target_bdev;
12129 +
12130 +       if (!target_inode)
12131 +               return 0;
12132 +
12133 +       switch (target_inode->i_mode & S_IFMT) {
12134 +               case S_IFSOCK:
12135 +               case S_IFCHR:
12136 +               case S_IFIFO: /* Socket, Char, Fifo */
12137 +                       return -1;
12138 +               case S_IFREG: /* Regular file: current size - holes + free
12139 +                                space on part */
12140 +                       result = target_storage_available;
12141 +                       break;
12142 +               case S_IFBLK: /* Block device */
12143 +                       if (!bdev->bd_disk) {
12144 +                               printk("bdev->bd_disk null.\n");
12145 +                               return 0;
12146 +                       }
12147 +
12148 +                       result = (bdev->bd_part ?
12149 +                               bdev->bd_part->nr_sects :
12150 +                               bdev->bd_disk->capacity) >> (PAGE_SHIFT - 9);
12151 +       }
12152 +
12153 +       return adjust_for_extra_pages(result);
12154 +}
12155 +
12156 +static int has_contiguous_blocks(int page_num)
12157 +{
12158 +       int j;
12159 +       sector_t last = 0;
12160 +
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);
12164 +
12165 +               if (!this || (last && (last + 1) != this))
12166 +                       break;
12167 +
12168 +               last = this;
12169 +       }
12170 +                       
12171 +       return (j == devinfo.blocks_per_page);
12172 +}
12173 +
12174 +static int size_ignoring_ignored_pages(void)
12175 +{
12176 +       int mappable = 0, i;
12177 +       
12178 +       if (!target_is_normal_file())
12179 +               return suspend_file_storage_available();
12180 +
12181 +       for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT) ; i++)
12182 +               if (has_contiguous_blocks(i))
12183 +                       mappable++;
12184 +       
12185 +       return mappable;
12186 +}
12187 +
12188 +static void __populate_block_list(int min, int max)
12189 +{
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);
12193 +
12194 +       suspend_add_to_extent_chain(&block_chain, min, max);
12195 +}
12196 +
12197 +static void populate_block_list(void)
12198 +{
12199 +       int i;
12200 +       int extent_min = -1, extent_max = -1, got_header = 0;
12201 +       
12202 +       if (block_chain.first)
12203 +               suspend_put_extent_chain(&block_chain);
12204 +
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);
12210 +               return;
12211 +       }
12212 +
12213 +       for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT); i++) {
12214 +               sector_t new_sector;
12215 +
12216 +               if (!has_contiguous_blocks(i))
12217 +                       continue;
12218 +
12219 +               new_sector = bmap(target_inode,
12220 +               (i * devinfo.blocks_per_page));
12221 +
12222 +               /* 
12223 +                * Ignore the first block in the file.
12224 +                * It gets the header.
12225 +                */
12226 +               if (new_sector == target_firstblock >> devinfo.bmap_shift) {
12227 +                       got_header = 1;
12228 +                       continue;
12229 +               }
12230 +
12231 +               /* 
12232 +                * I'd love to be able to fill in holes and resize 
12233 +                * files, but not yet...
12234 +                */
12235 +
12236 +               if (new_sector == extent_max + 1)
12237 +                       extent_max+= devinfo.blocks_per_page;
12238 +               else {
12239 +                       if (extent_min > -1)
12240 +                               __populate_block_list(extent_min,
12241 +                                               extent_max);
12242 +
12243 +                       extent_min = new_sector;
12244 +                       extent_max = extent_min +
12245 +                               devinfo.blocks_per_page - 1;
12246 +               }
12247 +       }
12248 +
12249 +       if (extent_min > -1)
12250 +               __populate_block_list(extent_min, extent_max);
12251 +}
12252 +
12253 +static void suspend_file_cleanup(int finishing_cycle)
12254 +{
12255 +       if (suspend_file_target_bdev) {
12256 +               if (target_claim) {
12257 +                       bd_release(suspend_file_target_bdev);
12258 +                       target_claim = 0;
12259 +               }
12260 +
12261 +               if (used_devt) {
12262 +                       blkdev_put(suspend_file_target_bdev);
12263 +                       used_devt = 0;
12264 +               }
12265 +               suspend_file_target_bdev = NULL;
12266 +               target_inode = NULL;
12267 +               set_devinfo(NULL, 0);
12268 +               target_storage_available = 0;
12269 +       }
12270 +
12271 +       if (target_file > 0) {
12272 +               filp_close(target_file, NULL);
12273 +               target_file = NULL;
12274 +       }
12275 +}
12276 +
12277 +/* 
12278 + * reopen_resume_devt
12279 + *
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).
12283 + */
12284 +static void reopen_resume_devt(void)
12285 +{
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);
12290 +               return;
12291 +       }
12292 +       target_inode = suspend_file_target_bdev->bd_inode;
12293 +       set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12294 +}
12295 +
12296 +static void suspend_file_get_target_info(char *target, int get_size,
12297 +               int resume2)
12298 +{
12299 +       if (target_file)
12300 +               suspend_file_cleanup(0);
12301 +
12302 +       if (!target || !strlen(target))
12303 +               return;
12304 +
12305 +       target_file = filp_open(target, O_RDWR, 0);
12306 +
12307 +       if (IS_ERR(target_file) || !target_file) {
12308 +
12309 +               if (!resume2) {
12310 +                       printk("Open file %s returned %p.\n",
12311 +                                       target, target_file);
12312 +                       target_file = NULL;
12313 +                       return;
12314 +               }
12315 +
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);
12323 +                       if (error)
12324 +                               printk("Stating the file also failed."
12325 +                                       " Nothing more we can do.\n");
12326 +                       else
12327 +                               resume_file_dev_t = stat.rdev;
12328 +                       return;
12329 +               }
12330 +
12331 +               suspend_file_target_bdev = open_by_devnum(resume_file_dev_t,
12332 +                               FMODE_READ);
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);
12336 +                       return;
12337 +               }
12338 +               used_devt = 1;
12339 +               target_inode = suspend_file_target_bdev->bd_inode;
12340 +       } else
12341 +               target_inode = target_file->f_mapping->host;
12342 +
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");
12347 +               goto cleanup;
12348 +       }
12349 +
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;
12355 +               } else
12356 +                       suspend_file_target_bdev = target_inode->i_sb->s_bdev;
12357 +               resume_file_dev_t = suspend_file_target_bdev->bd_dev;
12358 +       }
12359 +
12360 +       set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12361 +
12362 +       if (get_size)
12363 +               target_storage_available = size_ignoring_ignored_pages();
12364 +
12365 +       if (!resume2)
12366 +               target_firstblock = bmap(target_inode, 0) << devinfo.bmap_shift;
12367 +       
12368 +       return;
12369 +cleanup:
12370 +       target_inode = NULL;
12371 +       if (target_file) {
12372 +               filp_close(target_file, NULL);
12373 +               target_file = NULL;
12374 +       }
12375 +       set_devinfo(NULL, 0);
12376 +       target_storage_available = 0;
12377 +}
12378 +
12379 +static int parse_signature(struct suspend_file_header *header)
12380 +{
12381 +       int have_image = !memcmp(HaveImage, header->sig, sizeof(HaveImage) - 1);
12382 +       int no_image_header = !memcmp(NoImage, header->sig, sizeof(NoImage) - 1);
12383 +
12384 +       if (no_image_header)
12385 +               return 0;
12386 +
12387 +       if (!have_image)
12388 +               return -1;
12389 +
12390 +       if (header->resumed_before)
12391 +               set_suspend_state(SUSPEND_RESUMED_BEFORE);
12392 +       else
12393 +               clear_suspend_state(SUSPEND_RESUMED_BEFORE);
12394 +
12395 +       target_header_start = header->first_header_block;
12396 +       return 1;
12397 +}
12398 +
12399 +/* prepare_signature */
12400 +
12401 +static int prepare_signature(struct suspend_file_header *current_header,
12402 +               unsigned long first_header_block)
12403 +{
12404 +       strncpy(current_header->sig, HaveImage, sizeof(HaveImage));
12405 +       current_header->resumed_before = 0;
12406 +       current_header->first_header_block = first_header_block;
12407 +       return 0;
12408 +}
12409 +
12410 +static int suspend_file_storage_allocated(void)
12411 +{
12412 +       if (!target_inode)
12413 +               return 0;
12414 +
12415 +       if (target_is_normal_file())
12416 +               return (int) target_storage_available;
12417 +       else
12418 +               return header_pages_allocated + main_pages_requested;
12419 +}
12420 +
12421 +static int suspend_file_release_storage(void)
12422 +{
12423 +       if (test_action_state(SUSPEND_KEEP_IMAGE) &&
12424 +           test_suspend_state(SUSPEND_NOW_RESUMING))
12425 +               return 0;
12426 +
12427 +       suspend_put_extent_chain(&block_chain);
12428 +
12429 +       header_pages_allocated = 0;
12430 +       main_pages_allocated = 0;
12431 +       main_pages_requested = 0;
12432 +       return 0;
12433 +}
12434 +
12435 +static int __suspend_file_allocate_storage(int main_storage_requested,
12436 +               int header_storage);
12437 +
12438 +static int suspend_file_allocate_header_space(int space_requested)
12439 +{
12440 +       int i;
12441 +
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");
12445 +               return -ENOSPC;
12446 +       }
12447 +
12448 +       suspend_extent_state_goto_start(&suspend_writer_posn);
12449 +       suspend_bio_ops.forward_one_page(); /* To first page */
12450 +
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;
12456 +                       return -ENOSPC;
12457 +               }
12458 +       }
12459 +
12460 +       header_pages_allocated = space_requested;
12461 +
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]);
12465 +       return 0;
12466 +}
12467 +
12468 +static int suspend_file_allocate_storage(int space_requested)
12469 +{
12470 +       if (__suspend_file_allocate_storage(space_requested,
12471 +                               header_pages_allocated))
12472 +               return -ENOSPC;
12473 +
12474 +       main_pages_requested = space_requested;
12475 +       return -ENOSPC;
12476 +}
12477 +
12478 +static int __suspend_file_allocate_storage(int main_space_requested,
12479 +               int header_space_requested)
12480 +{
12481 +       int result = 0;
12482 +
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;
12488 +       
12489 +       /* Only release_storage reduces the size */
12490 +       if (blocks_to_get < 1)
12491 +               return 0;
12492 +
12493 +       populate_block_list();
12494 +
12495 +       suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
12496 +               "Finished with block_chain.size == %d.\n",
12497 +               block_chain.size);
12498 +
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;
12504 +       }
12505 +
12506 +       main_pages_requested = main_space_requested;
12507 +       main_pages_allocated = main_space_requested + extra_pages;
12508 +
12509 +       suspend_file_allocate_header_space(header_pages_allocated);
12510 +       return result;
12511 +}
12512 +
12513 +static int suspend_file_write_header_init(void)
12514 +{
12515 +       suspend_extent_state_goto_start(&suspend_writer_posn);
12516 +
12517 +       suspend_writer_buffer_posn = suspend_header_bytes_used = 0;
12518 +
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.
12526 +        */
12527 +
12528 +       suspend_bio_ops.rw_header_chunk(WRITE, &suspend_fileops,
12529 +                       (char *) &suspend_writer_posn_save, 
12530 +                       sizeof(suspend_writer_posn_save));
12531 +
12532 +       suspend_bio_ops.rw_header_chunk(WRITE, &suspend_fileops,
12533 +                       (char *) &devinfo, sizeof(devinfo));
12534 +
12535 +       suspend_serialise_extent_chain(&suspend_fileops, &block_chain);
12536 +       
12537 +       return 0;
12538 +}
12539 +
12540 +static int suspend_file_write_header_cleanup(void)
12541 +{
12542 +       struct suspend_file_header *header;
12543 +
12544 +       /* Write any unsaved data */
12545 +       if (suspend_writer_buffer_posn)
12546 +               suspend_bio_ops.write_header_chunk_finish();
12547 +
12548 +       suspend_bio_ops.finish_all_io();
12549 +
12550 +       suspend_extent_state_goto_start(&suspend_writer_posn);
12551 +       suspend_bio_ops.forward_one_page();
12552 +
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));
12557 +
12558 +       header = (struct suspend_file_header *) suspend_writer_buffer;
12559 +
12560 +       prepare_signature(header,
12561 +                       suspend_writer_posn.current_offset <<
12562 +                       devinfo.bmap_shift);
12563 +               
12564 +       suspend_bio_ops.bdev_page_io(WRITE, suspend_file_target_bdev,
12565 +                       target_firstblock,
12566 +                       virt_to_page(suspend_writer_buffer));
12567 +
12568 +       suspend_bio_ops.finish_all_io();
12569 +
12570 +       return 0;
12571 +}
12572 +
12573 +/* HEADER READING */
12574 +
12575 +#ifdef CONFIG_DEVFS_FS
12576 +int  create_dev(char *name, dev_t dev, char *devfs_name);
12577 +#else
12578 +static int create_dev(char *name, dev_t dev, char *devfs_name)
12579 +{
12580 +       sys_unlink(name);
12581 +       return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
12582 +}
12583 +#endif
12584 +
12585 +static int rd_init(void)
12586 +{
12587 +       suspend_writer_buffer_posn = 0;
12588 +
12589 +       create_dev("/dev/root", ROOT_DEV, root_device_name);
12590 +       create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
12591 +
12592 +       suspend_read_fd = sys_open("/dev/root", O_RDONLY, 0);
12593 +       if (suspend_read_fd < 0)
12594 +               goto out;
12595 +       
12596 +       sys_read(suspend_read_fd, suspend_writer_buffer, BLOCK_SIZE);
12597 +
12598 +       memcpy(&suspend_writer_posn_save,
12599 +               suspend_writer_buffer + suspend_writer_buffer_posn,
12600 +               sizeof(suspend_writer_posn_save));
12601 +       
12602 +       suspend_writer_buffer_posn += sizeof(suspend_writer_posn_save);
12603 +
12604 +       return 0;
12605 +out:
12606 +       sys_unlink("/dev/ram");
12607 +       sys_unlink("/dev/root");
12608 +       return -EIO;
12609 +}
12610 +
12611 +static int file_init(void)
12612 +{
12613 +       suspend_writer_buffer_posn = 0;
12614 +
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));
12619 +       
12620 +       return 0;
12621 +}
12622 +
12623 +/*
12624 + * read_header_init()
12625 + * 
12626 + * Ramdisk support based heavily on init/do_mounts_rd.c
12627 + *
12628 + * Description:
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.
12635 + *
12636 + * Returns:
12637 + * May not return if user choose to reboot at a warning.
12638 + * -EINVAL if cannot resume at this time. Booting should continue
12639 + * normally.
12640 + */
12641 +
12642 +static int suspend_file_read_header_init(void)
12643 +{
12644 +       int result;
12645 +       struct block_device *tmp;
12646 +
12647 +       if (test_suspend_state(SUSPEND_TRY_RESUME_RD))
12648 +               result = rd_init();
12649 +       else
12650 +               result = file_init();
12651 +       
12652 +       if (result) {
12653 +               printk("FileAllocator read header init: Failed to initialise "
12654 +                               "reading the first page of data.\n");
12655 +               return result;
12656 +       }
12657 +
12658 +       memcpy(&suspend_writer_posn_save,
12659 +              suspend_writer_buffer + suspend_writer_buffer_posn,
12660 +              sizeof(suspend_writer_posn_save));
12661 +       
12662 +       suspend_writer_buffer_posn += sizeof(suspend_writer_posn_save);
12663 +
12664 +       tmp = devinfo.bdev;
12665 +
12666 +       memcpy(&devinfo,
12667 +              suspend_writer_buffer + suspend_writer_buffer_posn,
12668 +              sizeof(devinfo));
12669 +
12670 +       devinfo.bdev = tmp;
12671 +       suspend_writer_buffer_posn += sizeof(devinfo);
12672 +
12673 +       suspend_bio_ops.read_header_init();
12674 +       suspend_extent_state_goto_start(&suspend_writer_posn);
12675 +       suspend_bio_ops.set_extra_page_forward();
12676 +
12677 +       suspend_header_bytes_used = suspend_writer_buffer_posn;
12678 +
12679 +       return suspend_load_extent_chain(&block_chain);
12680 +}
12681 +
12682 +static int suspend_file_read_header_cleanup(void)
12683 +{
12684 +       suspend_bio_ops.rw_cleanup(READ);
12685 +       return 0;
12686 +}
12687 +
12688 +static int suspend_file_signature_op(int op)
12689 +{
12690 +       char *cur;
12691 +       int result = 0, changed = 0;
12692 +       struct suspend_file_header *header;
12693 +       
12694 +       if(suspend_file_target_bdev <= 0)
12695 +               return -1;
12696 +
12697 +       cur = (char *) get_zeroed_page(GFP_ATOMIC);
12698 +       if (!cur) {
12699 +               printk("Unable to allocate a page for reading the image "
12700 +                               "signature.\n");
12701 +               return -ENOMEM;
12702 +       }
12703 +
12704 +       suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12705 +                       target_firstblock,
12706 +                       virt_to_page(cur));
12707 +
12708 +       header = (struct suspend_file_header *) cur;
12709 +       result = parse_signature(header);
12710 +               
12711 +       switch (op) {
12712 +               case INVALIDATE:
12713 +                       if (result == -1)
12714 +                               goto out;
12715 +
12716 +                       strcpy(header->sig, NoImage);
12717 +                       header->resumed_before = 0;
12718 +                       result = changed = 1;
12719 +                       break;
12720 +               case MARK_RESUME_ATTEMPTED:
12721 +                       if (result == 1) {
12722 +                               header->resumed_before = 1;
12723 +                               changed = 1;
12724 +                       }
12725 +                       break;
12726 +               case UNMARK_RESUME_ATTEMPTED:
12727 +                       if (result == 1) {
12728 +                               header->resumed_before = 0;
12729 +                               changed = 1;
12730 +                       }
12731 +                       break;
12732 +       }
12733 +
12734 +       if (changed)
12735 +               suspend_bio_ops.bdev_page_io(WRITE, suspend_file_target_bdev,
12736 +                               target_firstblock,
12737 +                               virt_to_page(cur));
12738 +
12739 +out:
12740 +       suspend_bio_ops.finish_all_io();
12741 +       free_page((unsigned long) cur);
12742 +       return result;
12743 +}
12744 +
12745 +/* Print debug info
12746 + *
12747 + * Description:
12748 + */
12749 +
12750 +static int suspend_file_print_debug_stats(char *buffer, int size)
12751 +{
12752 +       int len = 0;
12753 +       
12754 +       if (suspendActiveAllocator != &suspend_fileops) {
12755 +               len = snprintf_used(buffer, size, "- FileAllocator inactive.\n");
12756 +               return len;
12757 +       }
12758 +
12759 +       len = snprintf_used(buffer, size, "- FileAllocator active.\n");
12760 +
12761 +       len+= snprintf_used(buffer+len, size-len, "  Storage available for image: "
12762 +                       "%ld pages.\n",
12763 +                       suspend_file_storage_allocated());
12764 +
12765 +       return len;
12766 +}
12767 +
12768 +/*
12769 + * Storage needed
12770 + *
12771 + * Returns amount of space in the image header required
12772 + * for the suspend_file's data.
12773 + *
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.
12777 + */
12778 +static int suspend_file_storage_needed(void)
12779 +{
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);
12785 +}
12786 +
12787 +/* 
12788 + * suspend_file_invalidate_image
12789 + * 
12790 + */
12791 +static int suspend_file_invalidate_image(void)
12792 +{
12793 +       int result;
12794 +
12795 +       suspend_file_release_storage();
12796 +
12797 +       result = suspend_file_signature_op(INVALIDATE);
12798 +       if (result == 1 && !nr_suspends)
12799 +               printk(KERN_WARNING "Suspend2: Image invalidated.\n");
12800 +
12801 +       return result;
12802 +}
12803 +
12804 +/*
12805 + * Image_exists
12806 + *
12807 + */
12808 +
12809 +static int suspend_file_image_exists(void)
12810 +{
12811 +       if (!suspend_file_target_bdev)
12812 +               reopen_resume_devt();
12813 +
12814 +       return suspend_file_signature_op(GET_IMAGE_EXISTS);
12815 +}
12816 +
12817 +/*
12818 + * Mark resume attempted.
12819 + *
12820 + * Record that we tried to resume from this image.
12821 + */
12822 +
12823 +static void suspend_file_mark_resume_attempted(int mark)
12824 +{
12825 +       suspend_file_signature_op(mark ? MARK_RESUME_ATTEMPTED:
12826 +               UNMARK_RESUME_ATTEMPTED);
12827 +}
12828 +
12829 +static void suspend_file_set_resume2(void)
12830 +{
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);
12834 +       int offset = 0;
12835 +
12836 +       if (suspend_file_target_bdev) {
12837 +               set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12838 +
12839 +               bdevname(suspend_file_target_bdev, buffer2);
12840 +               offset += snprintf(buffer + offset, PAGE_SIZE - offset, 
12841 +                               "/dev/%s", buffer2);
12842 +               
12843 +               if (sector)
12844 +                       offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12845 +                               ":0x%lx", sector << devinfo.bmap_shift);
12846 +       } else
12847 +               offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12848 +                               "%s is not a valid target.", suspend_file_target);
12849 +                       
12850 +       sprintf(resume2_file, "file:%s", buffer);
12851 +
12852 +       free_page((unsigned long) buffer);
12853 +       free_page((unsigned long) buffer2);
12854 +
12855 +       suspend_attempt_to_parse_resume_device(1);
12856 +}
12857 +
12858 +static int __test_suspend_file_target(char *target, int resume_time, int quiet)
12859 +{
12860 +       suspend_file_get_target_info(target, 0, resume_time);
12861 +       if (suspend_file_signature_op(GET_IMAGE_EXISTS) > -1) {
12862 +               if (!quiet)
12863 +                       printk("Suspend2: FileAllocator: File signature found.\n");
12864 +               if (!resume_time)
12865 +                       suspend_file_set_resume2();
12866 +               
12867 +               suspend_bio_ops.set_devinfo(&devinfo);
12868 +               suspend_writer_posn.chains = &block_chain;
12869 +               suspend_writer_posn.num_chains = 1;
12870 +
12871 +               if (!resume_time)
12872 +                       set_suspend_state(SUSPEND_CAN_SUSPEND);
12873 +               return 0;
12874 +       }
12875 +
12876 +       clear_suspend_state(SUSPEND_CAN_SUSPEND);
12877 +
12878 +       if (quiet)
12879 +               return 1;
12880 +
12881 +       if (*target)
12882 +               printk("Suspend2: FileAllocator: Sorry. No signature found at"
12883 +                                       " %s.\n", target);
12884 +       else
12885 +               if (!resume_time)
12886 +                       printk("Suspend2: FileAllocator: Sorry. Target is not"
12887 +                                               " set for suspending.\n");
12888 +
12889 +       return 1;
12890 +}
12891 +
12892 +static void test_suspend_file_target(void)
12893 +{
12894 +       setting_suspend_file_target = 1;
12895 +               
12896 +       printk("Suspend2: Suspending %sabled.\n",
12897 +                       __test_suspend_file_target(suspend_file_target, 0, 1) ?
12898 +                       "dis" : "en");
12899 +       
12900 +       setting_suspend_file_target = 0;
12901 +}
12902 +
12903 +/*
12904 + * Parse Image Location
12905 + *
12906 + * Attempt to parse a resume2= parameter.
12907 + * Swap Writer accepts:
12908 + * resume2=file:DEVNAME[:FIRSTBLOCK]
12909 + *
12910 + * Where:
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
12918 + * necessary.
12919 + */
12920 +
12921 +static int suspend_file_parse_sig_location(char *commandline,
12922 +               int only_writer, int quiet)
12923 +{
12924 +       char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
12925 +       int result = -EINVAL, target_blocksize = 0;
12926 +
12927 +       if (strncmp(commandline, "file:", 5)) {
12928 +               if (!only_writer)
12929 +                       return 1;
12930 +       } else
12931 +               commandline += 5;
12932 +
12933 +       /* 
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
12936 +        * to resuming.
12937 +        */
12938 +       if (suspend_file_target_bdev)
12939 +               return 0;
12940 +       
12941 +       devstart = thischar = commandline;
12942 +       while ((*thischar != ':') && (*thischar != '@') &&
12943 +               ((thischar - commandline) < 250) && (*thischar))
12944 +               thischar++;
12945 +
12946 +       if (*thischar == ':') {
12947 +               colon = thischar;
12948 +               *colon = 0;
12949 +               thischar++;
12950 +       }
12951 +
12952 +       while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
12953 +               thischar++;
12954 +
12955 +       if (*thischar == '@') {
12956 +               at_symbol = thischar;
12957 +               *at_symbol = 0;
12958 +       }
12959 +       
12960 +       /* 
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
12963 +        * isn't. 
12964 +        *
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.
12970 +        */
12971 +
12972 +       if (!setting_suspend_file_target)
12973 +               __test_suspend_file_target(suspend_file_target, 1, 0);
12974 +
12975 +       if (colon)
12976 +               target_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
12977 +       else
12978 +               target_firstblock = 0;
12979 +
12980 +       if (at_symbol) {
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;
12985 +                       goto out;
12986 +               }
12987 +       }
12988 +       
12989 +       if (!quiet)
12990 +               printk("Suspend2 FileAllocator: Testing whether you can resume:\n");
12991 +
12992 +       suspend_file_get_target_info(commandline, 0, 1);
12993 +
12994 +       if (!suspend_file_target_bdev || IS_ERR(suspend_file_target_bdev)) {
12995 +               suspend_file_target_bdev = NULL;
12996 +               result = -1;
12997 +               goto out;
12998 +       }
12999 +
13000 +       if (target_blocksize)
13001 +               set_devinfo(suspend_file_target_bdev, ffs(target_blocksize));
13002 +
13003 +       result = __test_suspend_file_target(commandline, 1, 0);
13004 +
13005 +out:
13006 +       if (result)
13007 +               clear_suspend_state(SUSPEND_CAN_SUSPEND);
13008 +
13009 +       if (!quiet)
13010 +               printk("Resuming %sabled.\n",  result ? "dis" : "en");
13011 +
13012 +       if (colon)
13013 +               *colon = ':';
13014 +       if (at_symbol)
13015 +               *at_symbol = '@';
13016 +
13017 +       return result;
13018 +}
13019 +
13020 +/* suspend_file_save_config_info
13021 + *
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.
13025 + */
13026 +
13027 +static int suspend_file_save_config_info(char *buffer)
13028 +{
13029 +       strcpy(buffer, suspend_file_target);
13030 +       return strlen(suspend_file_target) + 1;
13031 +}
13032 +
13033 +/* suspend_file_load_config_info
13034 + *
13035 + * Description:        Reload target's name.
13036 + * Arguments:  Buffer:         Pointer to the start of the data.
13037 + *             Size:           Number of bytes that were saved.
13038 + */
13039 +
13040 +static void suspend_file_load_config_info(char *buffer, int size)
13041 +{
13042 +       strcpy(suspend_file_target, buffer);
13043 +}
13044 +
13045 +static int suspend_file_initialise(int starting_cycle)
13046 +{
13047 +       if (starting_cycle) {
13048 +               if (suspendActiveAllocator != &suspend_fileops)
13049 +                       return 0;
13050 +
13051 +               if (starting_cycle & SYSFS_SUSPEND && !*suspend_file_target) {
13052 +                       printk("FileAllocator is the active writer,  "
13053 +                                       "but no filename has been set.\n");
13054 +                       return 1;
13055 +               }
13056 +       }
13057 +
13058 +       if (suspend_file_target)
13059 +               suspend_file_get_target_info(suspend_file_target, starting_cycle, 0);
13060 +
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);
13064 +               return 1;
13065 +       }
13066 +
13067 +       return 0;
13068 +}
13069 +
13070 +static struct suspend_sysfs_data sysfs_params[] = {
13071 +
13072 +       {
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,
13076 +       },
13077 +
13078 +       {
13079 +         SUSPEND2_ATTR("enabled", SYSFS_RW),
13080 +         SYSFS_INT(&suspend_fileops.enabled, 0, 1, 0),
13081 +         .write_side_effect            = attempt_to_parse_resume_device2,
13082 +       }
13083 +};
13084 +
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,
13096 +
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,
13110 +
13111 +       .sysfs_data             = sysfs_params,
13112 +       .num_sysfs_entries      = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
13113 +};
13114 +
13115 +/* ---- Registration ---- */
13116 +static __init int suspend_file_load(void)
13117 +{
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;
13123 +
13124 +       return suspend_register_module(&suspend_fileops);
13125 +}
13126 +
13127 +#ifdef MODULE
13128 +static __exit void suspend_file_unload(void)
13129 +{
13130 +       suspend_unregister_module(&suspend_fileops);
13131 +}
13132 +
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");
13138 +#else
13139 +late_initcall(suspend_file_load);
13140 +#endif
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
13144 @@ -0,0 +1,1262 @@
13145 +/*
13146 + * kernel/power/suspend_swap.c
13147 + *
13148 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
13149 + *
13150 + * Distributed under GPLv2.
13151 + * 
13152 + * This file encapsulates functions for usage of swap space as a
13153 + * backing store.
13154 + */
13155 +
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>
13162 +
13163 +#include "suspend.h"
13164 +#include "sysfs.h"
13165 +#include "modules.h"
13166 +#include "io.h"
13167 +#include "ui.h"
13168 +#include "extent.h"
13169 +#include "block_io.h"
13170 +
13171 +static struct suspend_module_ops suspend_swapops;
13172 +
13173 +#define SIGNATURE_VER 6
13174 +
13175 +/* --- Struct of pages stored on disk */
13176 +
13177 +union diskpage {
13178 +       union swap_header swh;  /* swh.magic is the only member used */
13179 +};
13180 +
13181 +union p_diskpage {
13182 +       union diskpage *pointer;
13183 +       char *ptr;
13184 +        unsigned long address;
13185 +};
13186 +
13187 +/* Devices used for swap */
13188 +static struct suspend_bdev_info devinfo[MAX_SWAPFILES];
13189 +
13190 +/* Extent chains for swap & blocks */
13191 +struct extent_chain swapextents;
13192 +struct extent_chain block_chain[MAX_SWAPFILES];
13193 +
13194 +static dev_t header_dev_t;
13195 +static struct block_device *header_block_device;
13196 +static unsigned long headerblock;
13197 +
13198 +/* For swapfile automatically swapon/off'd. */
13199 +static char swapfilename[32] = "";
13200 +static int suspend_swapon_status;
13201 +
13202 +/* Header Page Information */
13203 +static int header_pages_allocated;
13204 +
13205 +/* Swap Pages */
13206 +static int main_pages_allocated, main_pages_requested;
13207 +
13208 +/* User Specified Parameters. */
13209 +
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;
13214 +
13215 +struct sysinfo swapinfo;
13216 +static int suspend_swap_invalidate_image(void);
13217 +
13218 +/* Block devices open. */
13219 +struct bdev_opened
13220 +{
13221 +       dev_t device;
13222 +       struct block_device *bdev;
13223 +       int claimed;
13224 +};
13225 +
13226 +/* 
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.
13231 + */
13232 +static struct bdev_opened *bdev_info_list[MAX_SWAPFILES + 2];
13233 +       
13234 +static void close_bdev(int i)
13235 +{
13236 +       struct bdev_opened *this = bdev_info_list[i];
13237 +
13238 +       if (this->claimed)
13239 +               bd_release(this->bdev);
13240 +
13241 +       /* Release our reference. */
13242 +       blkdev_put(this->bdev);
13243 +
13244 +       /* Free our info. */
13245 +       kfree(this);
13246 +
13247 +       bdev_info_list[i] = NULL;
13248 +}
13249 +
13250 +static void close_bdevs(void)
13251 +{
13252 +       int i;
13253 +
13254 +       for (i = 0; i < MAX_SWAPFILES; i++)
13255 +               if (bdev_info_list[i])
13256 +                       close_bdev(i);
13257 +
13258 +       resume_block_device = header_block_device = NULL;
13259 +}
13260 +
13261 +static struct block_device *open_bdev(int index, dev_t device, int display_errs)
13262 +{
13263 +       struct bdev_opened *this;
13264 +       struct block_device *bdev;
13265 +
13266 +       if (bdev_info_list[index] && (bdev_info_list[index]->device == device)){
13267 +               bdev = bdev_info_list[index]->bdev;
13268 +               return bdev;
13269 +       }
13270 +       
13271 +       if (bdev_info_list[index] && bdev_info_list[index]->device != device)
13272 +               close_bdev(index);
13273 +
13274 +       bdev = open_by_devnum(device, FMODE_READ);
13275 +
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);
13284 +       }
13285 +
13286 +       this = kmalloc(sizeof(struct bdev_opened), GFP_KERNEL);
13287 +       if (!this) {
13288 +               printk(KERN_WARNING "Suspend2: Failed to allocate memory for "
13289 +                               "opening a bdev.");
13290 +               return ERR_PTR(-ENOMEM);
13291 +       }
13292 +
13293 +       bdev_info_list[index] = this;
13294 +       this->device = device;
13295 +       this->bdev = bdev;
13296 +
13297 +       if (index < MAX_SWAPFILES)
13298 +               devinfo[index].bdev = bdev;
13299 +
13300 +       return bdev;
13301 +}
13302 +
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.
13305 + */
13306 +static int enable_swapfile(void)
13307 +{
13308 +       int activateswapresult = -EINVAL;
13309 +
13310 +       if (suspend_swapon_status)
13311 +               return 0;
13312 +
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;
13324 +       }
13325 +       return activateswapresult;
13326 +}
13327 +
13328 +/* Returns 0 if was on, -EINVAL if was off, error value otherwise */
13329 +static int disable_swapfile(void)
13330 +{
13331 +       int result = -EINVAL;
13332 +       
13333 +       if (!suspend_swapon_status)
13334 +               return 0;
13335 +
13336 +       if (swapfilename[0]) {
13337 +               result = sys_swapoff(swapfilename);
13338 +               if (result == -EINVAL)
13339 +                       return 0;       /* Wasn't on */
13340 +               if (!result)
13341 +                       suspend_swapon_status = 0;
13342 +       }
13343 +
13344 +       return result;
13345 +}
13346 +
13347 +static int try_to_parse_resume_device(char *commandline, int quiet)
13348 +{
13349 +       struct kstat stat;
13350 +       int error = 0;
13351 +
13352 +       resume_swap_dev_t = name_to_dev_t(commandline);
13353 +
13354 +       if (!resume_swap_dev_t) {
13355 +               struct file *file = filp_open(commandline, O_RDONLY, 0);
13356 +
13357 +               if (!IS_ERR(file) && file) {
13358 +                       vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
13359 +                       filp_close(file, NULL);
13360 +               } else
13361 +                       error = vfs_stat(commandline, &stat);
13362 +               if (!error)
13363 +                       resume_swap_dev_t = stat.rdev;
13364 +       }
13365 +
13366 +       if (!resume_swap_dev_t) {
13367 +               if (quiet)
13368 +                       return 1;
13369 +
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",
13373 +                         commandline);
13374 +               else
13375 +                       printk("Suspend2: Can't translate \"%s\" into a device "
13376 +                                       "id yet.\n", commandline);
13377 +               return 1;
13378 +       }
13379 +
13380 +       resume_block_device = open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 0);
13381 +       if (IS_ERR(resume_block_device)) {
13382 +               if (!quiet)
13383 +                       suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
13384 +                               "Failed to get access to \"%s\", where"
13385 +                               " the swap header should be found.",
13386 +                               commandline);
13387 +               return 1;
13388 +       }
13389 +       
13390 +       return 0;
13391 +}
13392 +
13393 +/* 
13394 + * If we have read part of the image, we might have filled  memory with
13395 + * data that should be zeroed out.
13396 + */
13397 +static void suspend_swap_noresume_reset(void)
13398 +{
13399 +       memset((char *) &devinfo, 0, sizeof(devinfo));
13400 +}
13401 +
13402 +static int parse_signature(char *header, int restore)
13403 +{
13404 +       int type = -1;
13405 +
13406 +       if (!memcmp("SWAP-SPACE",header,10))
13407 +               return 0;
13408 +       else if (!memcmp("SWAPSPACE2",header,10))
13409 +               return 1;
13410 +
13411 +       else if (!memcmp("S1SUSP",header,6))
13412 +               type = 2;
13413 +       else if (!memcmp("S2SUSP",header,6))
13414 +               type = 3;
13415 +       else if (!memcmp("S1SUSPEND",header,9))
13416 +               type = 4;
13417 +       
13418 +       else if (!memcmp("z",header,1))
13419 +               type = 12;
13420 +       else if (!memcmp("Z",header,1))
13421 +               type = 13;
13422 +       
13423 +       /* 
13424 +        * Put bdev of suspend header in last byte of swap header
13425 +        * (unsigned short)
13426 +        */
13427 +       if (type > 11) {
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;
13433 +               /* 
13434 +                * We are now using the highest bit of the char to indicate
13435 +                * whether we have attempted to resume from this image before.
13436 +                */
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;
13441 +       }
13442 +
13443 +       if ((restore) && (type > 5)) {
13444 +               /* We only reset our own signatures */
13445 +               if (type & 1)
13446 +                       memcpy(header,"SWAPSPACE2",10);
13447 +               else
13448 +                       memcpy(header,"SWAP-SPACE",10);
13449 +       }
13450 +
13451 +       return type;
13452 +}
13453 +
13454 +/*
13455 + * prepare_signature
13456 + */
13457 +static int prepare_signature(dev_t bdev, unsigned long block,
13458 +               char *current_header)
13459 +{
13460 +       int current_type = parse_signature(current_header, 0);
13461 +       dev_t *header_ptr = (dev_t *) (&current_header[1]);
13462 +       unsigned long *headerblock_ptr =
13463 +               (unsigned long *) (&current_header[6]);
13464 +
13465 +       if ((current_type > 1) && (current_type < 6))
13466 +               return 1;
13467 +
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. */
13471 +
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.");
13476 +               return 1;
13477 +       }
13478 +
13479 +       if (current_type & 1)
13480 +               current_header[0] = 'Z';
13481 +       else
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; 
13486 +       return 0;
13487 +}
13488 +
13489 +static int __suspend_swap_allocate_storage(int main_storage_requested,
13490 +               int header_storage);
13491 +
13492 +static int suspend_swap_allocate_header_space(int space_requested)
13493 +{
13494 +       int i;
13495 +
13496 +       if (!swapextents.size && __suspend_swap_allocate_storage(
13497 +                               main_pages_requested, space_requested)) {
13498 +               printk("Failed to allocate space for the header.\n");
13499 +               return -ENOSPC;
13500 +       }
13501 +
13502 +       suspend_extent_state_goto_start(&suspend_writer_posn);
13503 +       suspend_bio_ops.forward_one_page(); /* To first page */
13504 +       
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;
13510 +                       return -ENOSPC;
13511 +               }
13512 +
13513 +       }
13514 +
13515 +       header_pages_allocated = space_requested;
13516 +
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]);
13521 +       return 0;
13522 +}
13523 +
13524 +static void get_main_pool_phys_params(void)
13525 +{
13526 +       struct extent *extentpointer = NULL;
13527 +       unsigned long address;
13528 +       int i, extent_min = -1, extent_max = -1, last_chain = -1;
13529 +
13530 +       for (i = 0; i < MAX_SWAPFILES; i++)
13531 +               if (block_chain[i].first)
13532 +                       suspend_put_extent_chain(&block_chain[i]);
13533 +
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);
13540 +
13541 +               if ((new_sector == extent_max + 1) &&
13542 +                   (last_chain == swapfilenum))
13543 +                       extent_max++;
13544 +               else {
13545 +                       if (extent_min > -1) {
13546 +                               if (test_action_state(SUSPEND_TEST_BIO))
13547 +                                       printk("Adding extent chain %d %d-%d.\n",
13548 +                                               swapfilenum,
13549 +                                               extent_min <<
13550 +                                                devinfo[last_chain].bmap_shift,
13551 +                                               extent_max <<
13552 +                                                devinfo[last_chain].bmap_shift);
13553 +                                               
13554 +                               suspend_add_to_extent_chain(
13555 +                                       &block_chain[last_chain],
13556 +                                       extent_min, extent_max);
13557 +                       }
13558 +                       extent_min = extent_max = new_sector;
13559 +                       last_chain = swapfilenum;
13560 +               }
13561 +       }
13562 +
13563 +       if (extent_min > -1) {
13564 +               if (test_action_state(SUSPEND_TEST_BIO))
13565 +                       printk("Adding extent chain %d %d-%d.\n",
13566 +                               last_chain,
13567 +                               extent_min <<
13568 +                                       devinfo[last_chain].bmap_shift,
13569 +                               extent_max <<
13570 +                                       devinfo[last_chain].bmap_shift);
13571 +               suspend_add_to_extent_chain(
13572 +                       &block_chain[last_chain],
13573 +                       extent_min, extent_max);
13574 +       }
13575 +
13576 +       suspend_swap_allocate_header_space(header_pages_allocated);
13577 +}
13578 +
13579 +static int suspend_swap_storage_allocated(void)
13580 +{
13581 +       return main_pages_requested + header_pages_allocated;
13582 +}
13583 +
13584 +static int suspend_swap_storage_available(void)
13585 +{
13586 +       si_swapinfo(&swapinfo);
13587 +       return (((int) swapinfo.freeswap + main_pages_allocated) * PAGE_SIZE /
13588 +               (PAGE_SIZE + sizeof(unsigned long) + sizeof(int)));
13589 +}
13590 +
13591 +static int suspend_swap_initialise(int starting_cycle)
13592 +{
13593 +       if (!starting_cycle)
13594 +               return 0;
13595 +
13596 +       enable_swapfile();
13597 +
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)))
13601 +               return 1;
13602 +
13603 +       return 0;
13604 +}
13605 +
13606 +static void suspend_swap_cleanup(int ending_cycle)
13607 +{
13608 +       if (ending_cycle)
13609 +               disable_swapfile();
13610 +       
13611 +       close_bdevs();
13612 +}
13613 +
13614 +static int suspend_swap_release_storage(void)
13615 +{
13616 +       int i = 0;
13617 +
13618 +       if (test_action_state(SUSPEND_KEEP_IMAGE) &&
13619 +           test_suspend_state(SUSPEND_NOW_RESUMING))
13620 +               return 0;
13621 +
13622 +       header_pages_allocated = 0;
13623 +       main_pages_allocated = 0;
13624 +
13625 +       if (swapextents.first) {
13626 +               /* Free swap entries */
13627 +               struct extent *extentpointer;
13628 +               unsigned long extentvalue;
13629 +               suspend_extent_for_each(&swapextents, extentpointer, 
13630 +                               extentvalue)
13631 +                       swap_free(extent_val_to_swap_entry(extentvalue));
13632 +
13633 +               suspend_put_extent_chain(&swapextents);
13634 +
13635 +               for (i = 0; i < MAX_SWAPFILES; i++)
13636 +                       if (block_chain[i].first)
13637 +                               suspend_put_extent_chain(&block_chain[i]);
13638 +       }
13639 +
13640 +       return 0;
13641 +}
13642 +
13643 +static int suspend_swap_allocate_storage(int space_requested)
13644 +{
13645 +       if (!__suspend_swap_allocate_storage(space_requested,
13646 +                               header_pages_allocated)) {
13647 +               main_pages_requested = space_requested;
13648 +               return 0;
13649 +       }
13650 +
13651 +       return -ENOSPC;
13652 +}
13653 +
13654 +static void free_swap_range(unsigned long min, unsigned long max)
13655 +{
13656 +       int j;
13657 +
13658 +       for (j = min; j < max; j++)
13659 +               swap_free(extent_val_to_swap_entry(j));
13660 +}
13661 +
13662 +/* 
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.
13666 + */
13667 +static int __suspend_swap_allocate_storage(int main_space_requested,
13668 +               int header_space_requested)
13669 +{
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];
13672 +
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;
13677 +
13678 +       if (pages_to_get < 1)
13679 +               return 0;
13680 +
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;
13687 +               first[i] = 1;
13688 +       }
13689 +
13690 +       for(i=0; i < pages_to_get; i++) {
13691 +               swp_entry_t entry;
13692 +               unsigned long new_value;
13693 +               unsigned swapfilenum;
13694 +
13695 +               entry = get_swap_page();
13696 +               if (!entry.val)
13697 +                       break;
13698 +
13699 +               swapfilenum = swp_type(entry);
13700 +               new_value = swap_entry_to_extent_val(entry);
13701 +
13702 +               if (first[swapfilenum]) {
13703 +                       first[swapfilenum] = 0;
13704 +                       extent_min[swapfilenum] = new_value;
13705 +                       extent_max[swapfilenum] = new_value;
13706 +                       gotten++;
13707 +                       continue;
13708 +               }
13709 +
13710 +               if (new_value == extent_max[swapfilenum] + 1) {
13711 +                       extent_max[swapfilenum]++;
13712 +                       gotten++;
13713 +                       continue;
13714 +               }
13715 +
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]);
13724 +                       break;
13725 +               } else {
13726 +                       extent_min[swapfilenum] = new_value;
13727 +                       extent_max[swapfilenum] = new_value;
13728 +                       gotten++;
13729 +               }
13730 +       }
13731 +
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]);
13737 +               }
13738 +
13739 +       if (gotten < pages_to_get)
13740 +               result = -ENOSPC;
13741 +
13742 +       main_pages_allocated += gotten;
13743 +       get_main_pool_phys_params();
13744 +       return result;
13745 +}
13746 +
13747 +static int suspend_swap_write_header_init(void)
13748 +{
13749 +       int i, result;
13750 +       struct swap_info_struct *si;
13751 +
13752 +       suspend_extent_state_goto_start(&suspend_writer_posn);
13753 +
13754 +       suspend_writer_buffer_posn = suspend_header_bytes_used = 0;
13755 +
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.
13763 +        */
13764 +
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;
13770 +               else
13771 +                       devinfo[i].dev_t = (dev_t) 0;
13772 +       }
13773 +
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))))
13778 +               return result;
13779 +
13780 +       if ((result = suspend_bio_ops.rw_header_chunk(WRITE,
13781 +                       &suspend_swapops,
13782 +                       (char *) &devinfo, sizeof(devinfo))))
13783 +               return result;
13784 +
13785 +       for (i=0; i < MAX_SWAPFILES; i++)
13786 +               suspend_serialise_extent_chain(&suspend_swapops, &block_chain[i]);
13787 +
13788 +       return 0;
13789 +}
13790 +
13791 +static int suspend_swap_write_header_cleanup(void)
13792 +{
13793 +       int result;
13794 +       struct swap_info_struct *si;
13795 +
13796 +       /* Write any unsaved data */
13797 +       if (suspend_writer_buffer_posn)
13798 +               suspend_bio_ops.write_header_chunk_finish();
13799 +
13800 +       suspend_bio_ops.finish_all_io();
13801 +
13802 +       suspend_extent_state_goto_start(&suspend_writer_posn);
13803 +       suspend_bio_ops.forward_one_page();
13804 +
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));
13809 +
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);
13814 +               
13815 +       if (!result)
13816 +               suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
13817 +                       resume_firstblock,
13818 +                       virt_to_page(suspend_writer_buffer));
13819 +
13820 +       suspend_bio_ops.finish_all_io();
13821 +
13822 +       return result;
13823 +}
13824 +
13825 +/* ------------------------- HEADER READING ------------------------- */
13826 +
13827 +/*
13828 + * read_header_init()
13829 + * 
13830 + * Description:
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.
13837 + *
13838 + * Returns:
13839 + * May not return if user choose to reboot at a warning.
13840 + * -EINVAL if cannot resume at this time. Booting should continue
13841 + * normally.
13842 + */
13843 +
13844 +static int suspend_swap_read_header_init(void)
13845 +{
13846 +       int i, result = 0;
13847 +
13848 +       suspend_header_bytes_used = 0;
13849 +
13850 +       if (!header_dev_t) {
13851 +               printk("read_header_init called when we haven't "
13852 +                               "verified there is an image!\n");
13853 +               return -EINVAL;
13854 +       }
13855 +
13856 +       /* 
13857 +        * If the header is not on the resume_swap_dev_t, get the resume device first.
13858 +        */
13859 +       if (header_dev_t != resume_swap_dev_t) {
13860 +               header_block_device = open_bdev(MAX_SWAPFILES + 1,
13861 +                               header_dev_t, 1);
13862 +
13863 +               if (IS_ERR(header_block_device))
13864 +                       return PTR_ERR(header_block_device);
13865 +       } else
13866 +               header_block_device = resume_block_device;
13867 +
13868 +       /* 
13869 +        * Read suspend_swap configuration.
13870 +        * Headerblock size taken into account already.
13871 +        */
13872 +       suspend_bio_ops.bdev_page_io(READ, header_block_device,
13873 +                       headerblock << 3,
13874 +                       virt_to_page((unsigned long) suspend_writer_buffer));
13875 +
13876 +       memcpy(&suspend_writer_posn_save, suspend_writer_buffer, 3 * sizeof(struct extent_iterate_saved_state));
13877 +
13878 +       suspend_writer_buffer_posn = 3 * sizeof(struct extent_iterate_saved_state);
13879 +       suspend_header_bytes_used += 3 * sizeof(struct extent_iterate_saved_state);
13880 +
13881 +       memcpy(&devinfo, suspend_writer_buffer + suspend_writer_buffer_posn, sizeof(devinfo));
13882 +
13883 +       suspend_writer_buffer_posn += sizeof(devinfo);
13884 +       suspend_header_bytes_used += sizeof(devinfo);
13885 +
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;
13890 +
13891 +               devinfo[i].bdev = NULL;
13892 +
13893 +               if (!thisdevice)
13894 +                       continue;
13895 +
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;
13900 +                       continue;
13901 +               }
13902 +
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;
13907 +                       continue;
13908 +               }
13909 +
13910 +               result = open_bdev(i, thisdevice, 1);
13911 +               if (IS_ERR(result))
13912 +                       return PTR_ERR(result);
13913 +       }
13914 +
13915 +       suspend_bio_ops.read_header_init();
13916 +       suspend_extent_state_goto_start(&suspend_writer_posn);
13917 +       suspend_bio_ops.set_extra_page_forward();
13918 +
13919 +       for (i = 0; i < MAX_SWAPFILES && !result; i++)
13920 +               result = suspend_load_extent_chain(&block_chain[i]);
13921 +
13922 +       return result;
13923 +}
13924 +
13925 +static int suspend_swap_read_header_cleanup(void)
13926 +{
13927 +       suspend_bio_ops.rw_cleanup(READ);
13928 +       return 0;
13929 +}
13930 +
13931 +/* suspend_swap_invalidate_image
13932 + * 
13933 + */
13934 +static int suspend_swap_invalidate_image(void)
13935 +{
13936 +       union p_diskpage cur;
13937 +       int result = 0;
13938 +       char newsig[11];
13939 +       
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");
13943 +               return -ENOMEM;
13944 +       }
13945 +
13946 +       /*
13947 +        * If nr_suspends == 0, we must be booting, so no swap pages
13948 +        * will be recorded as used yet.
13949 +        */
13950 +
13951 +       if (nr_suspends > 0)
13952 +               suspend_swap_release_storage();
13953 +
13954 +       /* 
13955 +        * We don't do a sanity check here: we want to restore the swap 
13956 +        * whatever version of kernel made the suspend image.
13957 +        * 
13958 +        * We need to write swap, but swap may not be enabled so
13959 +        * we write the device directly
13960 +        */
13961 +       
13962 +       suspend_bio_ops.bdev_page_io(READ, resume_block_device,
13963 +                       resume_firstblock,
13964 +                       virt_to_page(cur.pointer));
13965 +
13966 +       result = parse_signature(cur.pointer->swh.magic.magic, 1);
13967 +               
13968 +       if (result < 5)
13969 +               goto out;
13970 +
13971 +       strncpy(newsig, cur.pointer->swh.magic.magic, 10);
13972 +       newsig[10] = 0;
13973 +
13974 +       suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
13975 +                       resume_firstblock,
13976 +                       virt_to_page(cur.pointer));
13977 +
13978 +       if (!nr_suspends)
13979 +               printk(KERN_WARNING "Suspend2: Image invalidated.\n");
13980 +out:
13981 +       suspend_bio_ops.finish_all_io();
13982 +       free_page(cur.address);
13983 +       return 0;
13984 +}
13985 +
13986 +/*
13987 + * workspace_size
13988 + *
13989 + * Description:
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).
13993 + *
13994 + */
13995 +static int suspend_swap_memory_needed(void)
13996 +{
13997 +       return 1;
13998 +}
13999 +
14000 +/*
14001 + * Print debug info
14002 + *
14003 + * Description:
14004 + */
14005 +static int suspend_swap_print_debug_stats(char *buffer, int size)
14006 +{
14007 +       int len = 0;
14008 +       struct sysinfo sysinfo;
14009 +       
14010 +       if (suspendActiveAllocator != &suspend_swapops) {
14011 +               len = snprintf_used(buffer, size, "- SwapAllocator inactive.\n");
14012 +               return len;
14013 +       }
14014 +
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);
14019 +
14020 +       si_swapinfo(&sysinfo);
14021 +       
14022 +       len+= snprintf_used(buffer+len, size-len, "  Swap available for image: %ld pages.\n",
14023 +                       (int) sysinfo.freeswap + suspend_swap_storage_allocated());
14024 +
14025 +       return len;
14026 +}
14027 +
14028 +/*
14029 + * Storage needed
14030 + *
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.
14034 + *
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.
14038 + */
14039 +static int suspend_swap_storage_needed(void)
14040 +{
14041 +       int i, result;
14042 +       result = sizeof(suspend_writer_posn_save) + sizeof(devinfo);
14043 +
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);
14048 +       }
14049 +
14050 +       return result;
14051 +}
14052 +
14053 +/*
14054 + * Image_exists
14055 + */
14056 +static int suspend_swap_image_exists(void)
14057 +{
14058 +       int signature_found;
14059 +       union p_diskpage diskpage;
14060 +       
14061 +       if (!resume_swap_dev_t) {
14062 +               printk("Not even trying to read header "
14063 +                               "because resume_swap_dev_t is not set.\n");
14064 +               return 0;
14065 +       }
14066 +       
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);
14071 +               return 0;
14072 +       }
14073 +
14074 +       diskpage.address = get_zeroed_page(GFP_ATOMIC);
14075 +
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();
14080 +
14081 +       signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14082 +       free_page(diskpage.address);
14083 +
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");
14090 +               return 0;
14091 +       } else if (signature_found < 6) {
14092 +               printk("Suspend2: Detected another implementation's signature.\n");
14093 +               return 0;
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");
14100 +               }
14101 +       }
14102 +
14103 +       return 1;
14104 +}
14105 +
14106 +/*
14107 + * Mark resume attempted.
14108 + *
14109 + * Record that we tried to resume from this image.
14110 + */
14111 +static void suspend_swap_mark_resume_attempted(int mark)
14112 +{
14113 +       union p_diskpage diskpage;
14114 +       int signature_found;
14115 +       
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");
14119 +               return;
14120 +       }
14121 +       
14122 +       diskpage.address = get_zeroed_page(GFP_ATOMIC);
14123 +
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);
14128 +
14129 +       switch (signature_found) {
14130 +               case 12:
14131 +               case 13:
14132 +                       diskpage.pointer->swh.magic.magic[5] &= ~0x80;
14133 +                       if (mark)
14134 +                               diskpage.pointer->swh.magic.magic[5] |= 0x80;
14135 +                       break;
14136 +       }
14137 +       
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);
14143 +       return;
14144 +}
14145 +
14146 +/*
14147 + * Parse Image Location
14148 + *
14149 + * Attempt to parse a resume2= parameter.
14150 + * Swap Writer accepts:
14151 + * resume2=swap:DEVNAME[:FIRSTBLOCK][@BLOCKSIZE]
14152 + *
14153 + * Where:
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
14160 + * necessary.
14161 + */
14162 +static int suspend_swap_parse_sig_location(char *commandline,
14163 +               int only_allocator, int quiet)
14164 +{
14165 +       char *thischar, *devstart, *colon = NULL, *at_symbol = NULL;
14166 +       union p_diskpage diskpage;
14167 +       int signature_found, result = -EINVAL, temp_result;
14168 +
14169 +       if (strncmp(commandline, "swap:", 5)) {
14170 +               /* 
14171 +                * Failing swap:, we'll take a simple
14172 +                * resume2=/dev/hda2, but fall through to
14173 +                * other allocators if /dev/ isn't matched.
14174 +                */
14175 +               if (strncmp(commandline, "/dev/", 5))
14176 +                       return 1;
14177 +       } else
14178 +               commandline += 5;
14179 +
14180 +       devstart = thischar = commandline;
14181 +       while ((*thischar != ':') && (*thischar != '@') &&
14182 +               ((thischar - commandline) < 250) && (*thischar))
14183 +               thischar++;
14184 +
14185 +       if (*thischar == ':') {
14186 +               colon = thischar;
14187 +               *colon = 0;
14188 +               thischar++;
14189 +       }
14190 +
14191 +       while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
14192 +               thischar++;
14193 +
14194 +       if (*thischar == '@') {
14195 +               at_symbol = thischar;
14196 +               *at_symbol = 0;
14197 +       }
14198 +       
14199 +       if (colon)
14200 +               resume_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
14201 +       else
14202 +               resume_firstblock = 0;
14203 +
14204 +       clear_suspend_state(SUSPEND_CAN_SUSPEND);
14205 +       clear_suspend_state(SUSPEND_CAN_RESUME);
14206 +       
14207 +       /* Legacy */
14208 +       if (at_symbol) {
14209 +               resume_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
14210 +               if (resume_blocksize & (SECTOR_SIZE - 1)) {
14211 +                       if (!quiet)
14212 +                               printk("SwapAllocator: Blocksizes are multiples"
14213 +                                               "of %d!\n", SECTOR_SIZE);
14214 +                       return -EINVAL;
14215 +               }
14216 +               resume_firstblock = resume_firstblock *
14217 +                       (resume_blocksize / SECTOR_SIZE);
14218 +       }
14219 +       
14220 +       temp_result = try_to_parse_resume_device(devstart, quiet);
14221 +
14222 +       if (colon)
14223 +               *colon = ':';
14224 +       if (at_symbol)
14225 +               *at_symbol = '@';
14226 +
14227 +       if (temp_result)
14228 +               return -EINVAL;
14229 +
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");
14234 +               return -ENOMEM;
14235 +       }
14236 +
14237 +       temp_result = suspend_bio_ops.bdev_page_io(READ,
14238 +                       resume_block_device,
14239 +                       resume_firstblock,
14240 +                       virt_to_page(diskpage.ptr));
14241 +
14242 +       suspend_bio_ops.finish_all_io();
14243 +       
14244 +       if (temp_result) {
14245 +               printk(KERN_ERR "Suspend2: SwapAllocator: Failed to submit "
14246 +                                       "I/O.\n");
14247 +               goto invalid;
14248 +       }
14249 +       
14250 +       signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14251 +
14252 +       if (signature_found != -1) {
14253 +               if (!quiet)
14254 +                       printk("Suspend2: SwapAllocator: Signature found.\n");
14255 +               result = 0;
14256 +
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);
14262 +       } else
14263 +               if (!quiet)
14264 +                       printk(KERN_ERR "Suspend2: SwapAllocator: No swap "
14265 +                               "signature found at specified location.\n");
14266 +invalid:
14267 +       free_page((unsigned long) diskpage.address);
14268 +       return result;
14269 +
14270 +}
14271 +
14272 +static int header_locations_read_sysfs(const char *page, int count)
14273 +{
14274 +       int i, printedpartitionsmessage = 0, len = 0, haveswap = 0;
14275 +       struct inode *swapf = 0;
14276 +       int zone;
14277 +       char *path_page = (char *) __get_free_page(GFP_KERNEL);
14278 +       char *path, *output = (char *) page;
14279 +       int path_len;
14280 +       
14281 +       if (!page)
14282 +               return 0;
14283 +
14284 +       for (i = 0; i < MAX_SWAPFILES; i++) {
14285 +               struct swap_info_struct *si =  get_swap_info_struct(i);
14286 +
14287 +               if (!si->swap_file)
14288 +                       continue;
14289 +               
14290 +               if (S_ISBLK(si->swap_file->f_mapping->host->i_mode)) {
14291 +                       haveswap = 1;
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;
14297 +                       }
14298 +               } else {
14299 +                       path_len = 0;
14300 +                       
14301 +                       path = d_path(si->swap_file->f_dentry,
14302 +                               si->swap_file->f_vfsmnt,
14303 +                               path_page,
14304 +                               PAGE_SIZE);
14305 +                       path_len = snprintf(path_page, 31, "%s", path);
14306 +                       
14307 +                       haveswap = 1;
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",
14313 +                                       path_page);
14314 +                       } else {
14315 +                               char name_buffer[255];
14316 +                               len+= sprintf(output + len, "For swapfile `%s`,"
14317 +                                       " use resume2=swap:/dev/%s:0x%x.\n",
14318 +                                       path_page,
14319 +                                       bdevname(si->bdev, name_buffer),
14320 +                                       zone << (swapf->i_blkbits - 9));
14321 +                       }
14322 +
14323 +               }
14324 +       }
14325 +       
14326 +       if (!haveswap)
14327 +               len = sprintf(output, "You need to turn on swap partitions "
14328 +                               "before examining this file.\n");
14329 +
14330 +       free_page((unsigned long) path_page);
14331 +       return len;
14332 +}
14333 +
14334 +static struct suspend_sysfs_data sysfs_params[] = {
14335 +       {
14336 +        SUSPEND2_ATTR("swapfilename", SYSFS_RW),
14337 +        SYSFS_STRING(swapfilename, 255, 0)
14338 +       },
14339 +
14340 +       {
14341 +        SUSPEND2_ATTR("headerlocations", SYSFS_READONLY),
14342 +        SYSFS_CUSTOM(header_locations_read_sysfs, NULL, 0)
14343 +       },
14344 +
14345 +       { SUSPEND2_ATTR("enabled", SYSFS_RW),
14346 +         SYSFS_INT(&suspend_swapops.enabled, 0, 1, 0),
14347 +         .write_side_effect            = attempt_to_parse_resume_device2,
14348 +       }
14349 +};
14350 +
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,
14361 +
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,
14376 +
14377 +       .sysfs_data             = sysfs_params,
14378 +       .num_sysfs_entries      = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
14379 +};
14380 +
14381 +/* ---- Registration ---- */
14382 +static __init int suspend_swap_load(void)
14383 +{
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;
14389 +
14390 +       return suspend_register_module(&suspend_swapops);
14391 +}
14392 +
14393 +#ifdef MODULE
14394 +static __exit void suspend_swap_unload(void)
14395 +{
14396 +       suspend_unregister_module(&suspend_swapops);
14397 +}
14398 +
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");
14404 +#else
14405 +late_initcall(suspend_swap_load);
14406 +#endif
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
14410 @@ -0,0 +1,649 @@
14411 +/*
14412 + * kernel/power/user_ui.c
14413 + *
14414 + * Copyright (C) 2005-2007 Bernard Blackham
14415 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
14416 + *
14417 + * This file is released under the GPLv2.
14418 + *
14419 + * Routines for Suspend2's user interface.
14420 + *
14421 + * The user interface code talks to a userspace program via a
14422 + * netlink socket.
14423 + *
14424 + * The kernel side:
14425 + * - starts the userui program;
14426 + * - sends text messages and progress bar status;
14427 + *
14428 + * The user space side:
14429 + * - passes messages regarding user requests (abort, toggle reboot etc)
14430 + *
14431 + */
14432 +
14433 +#define __KERNEL_SYSCALLS__
14434 +
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>
14446
14447 +#include "sysfs.h"
14448 +#include "modules.h"
14449 +#include "suspend.h"
14450 +#include "ui.h"
14451 +#include "netlink.h"
14452 +#include "power_off.h"
14453 +
14454 +static char local_printf_buf[1024];    /* Same as printk - should be safe */
14455 +
14456 +static struct user_helper_data ui_helper_data;
14457 +static struct suspend_module_ops userui_ops;
14458 +static int orig_kmsg;
14459 +
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. */
14464 +
14465 +/* Number of distinct progress amounts that userspace can display */
14466 +static int progress_granularity = 30;
14467 +
14468 +DECLARE_WAIT_QUEUE_HEAD(userui_wait_for_key);
14469 +
14470 +static void ui_nl_set_state(int n)
14471 +{
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);
14477 +
14478 +       suspend_action = (suspend_action & (~suspend_action_mask)) |
14479 +               (n & suspend_action_mask);
14480 +
14481 +       if (!test_action_state(SUSPEND_PAUSE) &&
14482 +                       !test_action_state(SUSPEND_SINGLESTEP))
14483 +               wake_up_interruptible(&userui_wait_for_key);
14484 +}
14485 +
14486 +static void userui_post_atomic_restore(void)
14487 +{
14488 +       suspend_send_netlink_message(&ui_helper_data,
14489 +                       USERUI_MSG_POST_ATOMIC_RESTORE, NULL, 0);
14490 +}
14491 +
14492 +static int userui_storage_needed(void)
14493 +{
14494 +       return sizeof(ui_helper_data.program) + 1 + sizeof(int);
14495 +}
14496 +
14497 +static int userui_save_config_info(char *buf)
14498 +{
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;
14502 +}
14503 +
14504 +static void userui_load_config_info(char *buf, int size)
14505 +{
14506 +       progress_granularity = *((int *) buf);
14507 +       size -= sizeof(int);
14508 +
14509 +       /* Don't load the saved path if one has already been set */
14510 +       if (ui_helper_changed)
14511 +               return;
14512 +
14513 +       if (size > sizeof(ui_helper_data.program))
14514 +               size = sizeof(ui_helper_data.program);
14515 +
14516 +       memcpy(ui_helper_data.program, buf + sizeof(int), size);
14517 +       ui_helper_data.program[sizeof(ui_helper_data.program)-1] = '\0';
14518 +}
14519 +
14520 +static void set_ui_program_set(void)
14521 +{
14522 +       ui_helper_changed = 1;
14523 +}
14524 +
14525 +static int userui_memory_needed(void)
14526 +{
14527 +       /* ball park figure of 128 pages */
14528 +       return (128 * PAGE_SIZE);
14529 +}
14530 +
14531 +/* suspend_update_status
14532 + *
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
14539 + *             clearbar on.
14540 + * Returns:    Unsigned long: The next value where status needs to be updated.
14541 + *             This is to reduce unnecessary calls to update_status.
14542 + */
14543 +static unsigned long userui_update_status(unsigned long value,
14544 +               unsigned long maximum, const char *fmt, ...)
14545 +{
14546 +       static int last_step = -1;
14547 +       struct userui_msg_params msg;
14548 +       int bitshift;
14549 +       int this_step;
14550 +       unsigned long next_update;
14551 +
14552 +       if (ui_helper_data.pid == -1)
14553 +               return 0;
14554 +
14555 +       if ((!maximum) || (!progress_granularity))
14556 +               return maximum;
14557 +
14558 +       if (value < 0)
14559 +               value = 0;
14560 +
14561 +       if (value > maximum)
14562 +               value = maximum;
14563 +
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;
14575 +       } else {
14576 +               this_step = (int) (value * progress_granularity / maximum);
14577 +               next_update = ((this_step + 1) * maximum /
14578 +                               progress_granularity) + 1;
14579 +       }
14580 +
14581 +       if (this_step == last_step)
14582 +               return next_update;
14583 +
14584 +       memset(&msg, 0, sizeof(msg));
14585 +
14586 +       msg.a = this_step;
14587 +       msg.b = progress_granularity;
14588 +
14589 +       if (fmt) {
14590 +               va_list args;
14591 +               va_start(args, fmt);
14592 +               vsnprintf(msg.text, sizeof(msg.text), fmt, args);
14593 +               va_end(args);
14594 +               msg.text[sizeof(msg.text)-1] = '\0';
14595 +       }
14596 +
14597 +       suspend_send_netlink_message(&ui_helper_data, USERUI_MSG_PROGRESS,
14598 +                       &msg, sizeof(msg));
14599 +       last_step = this_step;
14600 +
14601 +       return next_update;
14602 +}
14603 +
14604 +/* userui_message.
14605 + *
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"
14610 + *
14611 + *             It may be called from an interrupt context - can't sleep!
14612 + *
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.
14618 + */
14619 +static void userui_message(unsigned long section, unsigned long level,
14620 +               int normally_logged, const char *fmt, ...)
14621 +{
14622 +       struct userui_msg_params msg;
14623 +
14624 +       if ((level) && (level > console_loglevel))
14625 +               return;
14626 +
14627 +       memset(&msg, 0, sizeof(msg));
14628 +
14629 +       msg.a = section;
14630 +       msg.b = level;
14631 +       msg.c = normally_logged;
14632 +
14633 +       if (fmt) {
14634 +               va_list args;
14635 +               va_start(args, fmt);
14636 +               vsnprintf(msg.text, sizeof(msg.text), fmt, args);
14637 +               va_end(args);
14638 +               msg.text[sizeof(msg.text)-1] = '\0';
14639 +       }
14640 +
14641 +       if (test_action_state(SUSPEND_LOGALL))
14642 +               printk("%s\n", msg.text);
14643 +
14644 +       suspend_send_netlink_message(&ui_helper_data, USERUI_MSG_MESSAGE,
14645 +                       &msg, sizeof(msg));
14646 +}
14647 +
14648 +static void wait_for_key_via_userui(void)
14649 +{
14650 +       DECLARE_WAITQUEUE(wait, current);
14651 +
14652 +       add_wait_queue(&userui_wait_for_key, &wait);
14653 +       set_current_state(TASK_INTERRUPTIBLE);
14654 +
14655 +       interruptible_sleep_on(&userui_wait_for_key);
14656 +
14657 +       set_current_state(TASK_RUNNING);
14658 +       remove_wait_queue(&userui_wait_for_key, &wait);
14659 +}
14660 +
14661 +static char userui_wait_for_keypress(int timeout)
14662 +{
14663 +       int fd;
14664 +       char key = '\0';
14665 +       struct termios t, t_backup;
14666 +
14667 +       if (ui_helper_data.pid != -1) {
14668 +               wait_for_key_via_userui();
14669 +               key = ' ';
14670 +               goto out;
14671 +       }
14672 +       
14673 +       /* We should be guaranteed /dev/console exists after populate_rootfs() in
14674 +        * init/main.c
14675 +        */
14676 +       if ((fd = sys_open("/dev/console", O_RDONLY, 0)) < 0) {
14677 +               printk("Couldn't open /dev/console.\n");
14678 +               goto out;
14679 +       }
14680 +
14681 +       if (sys_ioctl(fd, TCGETS, (long)&t) < 0)
14682 +               goto out_close;
14683 +
14684 +       memcpy(&t_backup, &t, sizeof(t));
14685 +
14686 +       t.c_lflag &= ~(ISIG|ICANON|ECHO);
14687 +       t.c_cc[VMIN] = 0;
14688 +       if (timeout)
14689 +               t.c_cc[VTIME] = timeout*10;
14690 +
14691 +       if (sys_ioctl(fd, TCSETS, (long)&t) < 0)
14692 +               goto out_restore;
14693 +
14694 +       while (1) {
14695 +               if (sys_read(fd, &key, 1) <= 0) {
14696 +                       key = '\0';
14697 +                       break;
14698 +               }
14699 +               key = tolower(key);
14700 +               if (test_suspend_state(SUSPEND_SANITY_CHECK_PROMPT)) {
14701 +                       if (key == 'c') {
14702 +                               set_suspend_state(SUSPEND_CONTINUE_REQ);
14703 +                               break;
14704 +                       } else if (key == ' ')
14705 +                               break;
14706 +               } else
14707 +                       break;
14708 +       }
14709 +
14710 +out_restore:
14711 +       sys_ioctl(fd, TCSETS, (long)&t_backup);
14712 +out_close:
14713 +       sys_close(fd);
14714 +out:
14715 +       return key;
14716 +}
14717 +
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
14721 + *             progress bar.
14722 + * Arguments:  
14723 + *             int clearbar: Whether to reset the progress bar.
14724 + *             const char *fmt, ...: The action to be displayed.
14725 + */
14726 +static void userui_prepare_status(int clearbar, const char *fmt, ...)
14727 +{
14728 +       va_list args;
14729 +
14730 +       if (fmt) {
14731 +               va_start(args, fmt);
14732 +               lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
14733 +               va_end(args);
14734 +       }
14735 +
14736 +       if (clearbar)
14737 +               suspend_update_status(0, 1, NULL);
14738 +
14739 +       suspend_message(0, SUSPEND_STATUS, 1, lastheader, NULL);
14740 +
14741 +       if (ui_helper_data.pid == -1)
14742 +               printk(KERN_EMERG "%s\n", lastheader);
14743 +}
14744 +
14745 +/* abort_suspend
14746 + *
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.
14752 + */
14753 +
14754 +static void userui_abort_suspend(int result_code, const char *fmt, ...)
14755 +{
14756 +       va_list args;
14757 +       int printed_len = 0;
14758 +
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);
14765 +                       va_end(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);
14770 +
14771 +                       if (ui_helper_data.pid != -1)
14772 +                               suspend_wait_for_keypress(0);
14773 +               }
14774 +               /* Turn on aborting flag */
14775 +               set_result_state(SUSPEND_ABORTED);
14776 +       }
14777 +}
14778 +
14779 +/* request_abort_suspend
14780 + *
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
14784 + *             escape.
14785 + */
14786 +static void request_abort_suspend(void)
14787 +{
14788 +       if (test_result_state(SUSPEND_ABORT_REQUESTED))
14789 +               return;
14790 +
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))
14796 +                       schedule();
14797 +               if (suspendActiveAllocator->mark_resume_attempted)
14798 +                       suspendActiveAllocator->mark_resume_attempted(0);
14799 +               suspend2_power_down();
14800 +       } else {
14801 +               suspend_prepare_status(CLEAR_BAR, "--- ESCAPE PRESSED :"
14802 +                                       " ABORTING SUSPEND ---");
14803 +               set_result_state(SUSPEND_ABORTED);
14804 +               set_result_state(SUSPEND_ABORT_REQUESTED);
14805 +       
14806 +               wake_up_interruptible(&userui_wait_for_key);
14807 +       }
14808 +}
14809 +
14810 +static int userui_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
14811 +{
14812 +       int type;
14813 +       int *data;
14814 +
14815 +       type = nlh->nlmsg_type;
14816 +
14817 +       /* A control message: ignore them */
14818 +       if (type < NETLINK_MSG_BASE)
14819 +               return 0;
14820 +
14821 +       /* Unknown message: reply with EINVAL */
14822 +       if (type >= USERUI_MSG_MAX)
14823 +               return -EINVAL;
14824 +
14825 +       /* All operations require privileges, even GET */
14826 +       if (security_netlink_recv(skb, CAP_NET_ADMIN))
14827 +               return -EPERM;
14828 +
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);
14832 +               return -EBUSY;
14833 +       }
14834 +
14835 +       data = (int*)NLMSG_DATA(nlh);
14836 +
14837 +       switch (type) {
14838 +               case USERUI_MSG_ABORT:
14839 +                       request_abort_suspend();
14840 +                       break;
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));
14845 +                       break;
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));
14851 +                       break;
14852 +               case USERUI_MSG_SET_STATE:
14853 +                       if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14854 +                               return -EINVAL;
14855 +                       ui_nl_set_state(*data);
14856 +                       break;
14857 +               case USERUI_MSG_SET_DEBUG_STATE:
14858 +                       if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14859 +                               return -EINVAL;
14860 +                       suspend_debug_state = (*data);
14861 +                       break;
14862 +               case USERUI_MSG_SPACE:
14863 +                       wake_up_interruptible(&userui_wait_for_key);
14864 +                       break;
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));
14870 +                       break;
14871 +               case USERUI_MSG_SET_POWERDOWN_METHOD:
14872 +                       if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14873 +                               return -EINVAL;
14874 +                       suspend2_poweroff_method = (*data);
14875 +                       break;
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));
14881 +                       break;
14882 +               case USERUI_MSG_SET_LOGLEVEL:
14883 +                       if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14884 +                               return -EINVAL;
14885 +                       suspend_default_console_level = (*data);
14886 +                       break;
14887 +       }
14888 +
14889 +       return 1;
14890 +}
14891 +
14892 +/* userui_cond_pause
14893 + * 
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.
14899 + */
14900 +
14901 +static void userui_cond_pause(int pause, char *message)
14902 +{
14903 +       int displayed_message = 0, last_key = 0;
14904 +       
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;
14917 +               }
14918 +               last_key = suspend_wait_for_keypress(0);
14919 +       }
14920 +       schedule();
14921 +}
14922 +
14923 +/* userui_prepare_console
14924 + *
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.
14928 + */
14929 +static void userui_prepare_console(void)
14930 +{
14931 +       orig_kmsg = kmsg_redirect;
14932 +       kmsg_redirect = fg_console + 1;
14933 +
14934 +       ui_helper_data.pid = -1;
14935 +
14936 +       if (!userui_ops.enabled)
14937 +               return;
14938 +
14939 +       if (!*ui_helper_data.program) {
14940 +               printk("suspend_userui: program not configured. suspend_userui disabled.\n");
14941 +               return;
14942 +       }
14943 +
14944 +       suspend_netlink_setup(&ui_helper_data);
14945 +
14946 +       return;
14947 +}
14948 +
14949 +/* userui_cleanup_console
14950 + *
14951 + * Description: Restore the settings we saved above.
14952 + */
14953 +
14954 +static void userui_cleanup_console(void)
14955 +{
14956 +       if (ui_helper_data.pid > -1)
14957 +               suspend_netlink_close(&ui_helper_data);
14958 +
14959 +       kmsg_redirect = orig_kmsg;
14960 +}
14961 +
14962 +/*
14963 + * User interface specific /sys/power/suspend2 entries.
14964 + */
14965 +
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)
14970 +       },
14971 +
14972 +       { SUSPEND2_ATTR("pause_between_steps", SYSFS_RW),
14973 +         SYSFS_BIT(&suspend_action, SUSPEND_PAUSE, 0)
14974 +       },
14975 +
14976 +       { SUSPEND2_ATTR("enabled", SYSFS_RW),
14977 +         SYSFS_INT(&userui_ops.enabled, 0, 1, 0)
14978 +       },
14979 +
14980 +       { SUSPEND2_ATTR("progress_granularity", SYSFS_RW),
14981 +         SYSFS_INT(&progress_granularity, 1, 2048, 0)
14982 +       },
14983 +
14984 +       { SUSPEND2_ATTR("program", SYSFS_RW),
14985 +         SYSFS_STRING(ui_helper_data.program, 255, 0),
14986 +         .write_side_effect = set_ui_program_set,
14987 +       },
14988 +#endif
14989 +};
14990 +
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),
15002 +};
15003 +
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,
15014 +};
15015 +
15016 +/* suspend_console_sysfs_init
15017 + * Description: Boot time initialisation for user interface.
15018 + */
15019 +
15020 +static __init int s2_user_ui_init(void)
15021 +{
15022 +       int result;
15023 +
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);
15037 +       if (!result)
15038 +               result = s2_register_ui_ops(&my_ui_ops);
15039 +       if (result)
15040 +               suspend_unregister_module(&userui_ops);
15041 +
15042 +       return result;
15043 +}
15044 +
15045 +#ifdef MODULE
15046 +static __exit void s2_user_ui_exit(void)
15047 +{
15048 +       s2_remove_ui_ops(&my_ui_ops);
15049 +       suspend_unregister_module(&userui_ops);
15050 +}
15051 +
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");
15057 +#else
15058 +late_initcall(s2_user_ui_init);
15059 +#endif
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
15063 @@ -0,0 +1,347 @@
15064 +/*
15065 + * kernel/power/sysfs.c
15066 + *
15067 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
15068 + *
15069 + * This file is released under the GPLv2.
15070 + *
15071 + * This file contains support for sysfs entries for tuning Suspend2.
15072 + *
15073 + * We have a generic handler that deals with the most common cases, and
15074 + * hooks for special handlers to use.
15075 + */
15076 +
15077 +#include <linux/suspend.h>
15078 +#include <linux/module.h>
15079 +#include <asm/uaccess.h>
15080 +
15081 +#include "sysfs.h"
15082 +#include "suspend.h"
15083 +#include "storage.h"
15084 +
15085 +static int suspend_sysfs_initialised = 0;
15086 +
15087 +static void suspend_initialise_sysfs(void);
15088 +
15089 +static struct suspend_sysfs_data sysfs_params[];
15090 +
15091 +#define to_sysfs_data(_attr) container_of(_attr, struct suspend_sysfs_data, attr)
15092 +
15093 +static void suspend2_main_wrapper(void)
15094 +{
15095 +       _suspend2_try_suspend(0);
15096 +}
15097 +
15098 +static ssize_t suspend2_attr_show(struct kobject *kobj, struct attribute *attr,
15099 +                             char *page)
15100 +{
15101 +       struct suspend_sysfs_data *sysfs_data = to_sysfs_data(attr);
15102 +       int len = 0;
15103 +
15104 +       if (suspend_start_anything(0))
15105 +               return -EBUSY;
15106 +
15107 +       if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_READ)
15108 +               suspend_prepare_usm();
15109 +       
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)
15114 +                               : 0;
15115 +                       break;
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));
15120 +                       break;
15121 +               case SUSPEND_SYSFS_DATA_INTEGER:
15122 +                       len = sprintf(page, "%d\n",
15123 +                               *(sysfs_data->data.integer.variable));
15124 +                       break;
15125 +               case SUSPEND_SYSFS_DATA_LONG:
15126 +                       len = sprintf(page, "%ld\n",
15127 +                               *(sysfs_data->data.a_long.variable));
15128 +                       break;
15129 +               case SUSPEND_SYSFS_DATA_UL:
15130 +                       len = sprintf(page, "%lu\n",
15131 +                               *(sysfs_data->data.ul.variable));
15132 +                       break;
15133 +               case SUSPEND_SYSFS_DATA_STRING:
15134 +                       len = sprintf(page, "%s\n",
15135 +                               sysfs_data->data.string.variable);
15136 +                       break;
15137 +       }
15138 +       /* Side effect routine? */
15139 +       if (sysfs_data->read_side_effect)
15140 +               sysfs_data->read_side_effect();
15141 +
15142 +       if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_READ)
15143 +               suspend_cleanup_usm();
15144 +
15145 +       suspend_finish_anything(0);
15146 +
15147 +       return len;
15148 +}
15149 +
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;
15155 +
15156 +static ssize_t suspend2_attr_store(struct kobject *kobj, struct attribute *attr,
15157 +               const char *my_buf, size_t count)
15158 +{
15159 +       int assigned_temp_buffer = 0, result = count;
15160 +       struct suspend_sysfs_data *sysfs_data = to_sysfs_data(attr);
15161 +
15162 +       if (suspend_start_anything((sysfs_data->flags & SYSFS_SUSPEND_OR_RESUME)))
15163 +               return -EBUSY;
15164 +
15165 +       ((char *) my_buf)[count] = 0;
15166 +
15167 +       if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_WRITE)
15168 +               suspend_prepare_usm();
15169 +
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)
15174 +                                       (my_buf, count);
15175 +                       break;
15176 +               case SUSPEND_SYSFS_DATA_BIT:
15177 +                       {
15178 +                       int value = simple_strtoul(my_buf, NULL, 0);
15179 +                       if (value)
15180 +                               set_bit(sysfs_data->data.bit.bit, 
15181 +                                       (sysfs_data->data.bit.bit_vector));
15182 +                       else
15183 +                               clear_bit(sysfs_data->data.bit.bit,
15184 +                                       (sysfs_data->data.bit.bit_vector));
15185 +                       }
15186 +                       break;
15187 +               case SUSPEND_SYSFS_DATA_INTEGER:
15188 +                       {
15189 +                               int *variable = sysfs_data->data.integer.variable;
15190 +                               *variable = simple_strtol(my_buf, NULL, 0);
15191 +                               BOUND(variable, integer);
15192 +                               break;
15193 +                       }
15194 +               case SUSPEND_SYSFS_DATA_LONG:
15195 +                       {
15196 +                               long *variable = sysfs_data->data.a_long.variable;
15197 +                               *variable = simple_strtol(my_buf, NULL, 0);
15198 +                               BOUND(variable, a_long);
15199 +                               break;
15200 +                       }
15201 +               case SUSPEND_SYSFS_DATA_UL:
15202 +                       {
15203 +                               unsigned long *variable = sysfs_data->data.ul.variable;
15204 +                               *variable = simple_strtoul(my_buf, NULL, 0);
15205 +                               BOUND(variable, ul);
15206 +                               break;
15207 +                       }
15208 +                       break;
15209 +               case SUSPEND_SYSFS_DATA_STRING:
15210 +                       {
15211 +                               int copy_len = count;
15212 +                               char *variable =
15213 +                                       sysfs_data->data.string.variable;
15214 +
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;
15218 +
15219 +                               if (!variable) {
15220 +                                       sysfs_data->data.string.variable =
15221 +                                               variable = (char *) get_zeroed_page(GFP_ATOMIC);
15222 +                                       assigned_temp_buffer = 1;
15223 +                               }
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;
15229 +                       }
15230 +                       break;
15231 +       }
15232 +
15233 +       /* Side effect routine? */
15234 +       if (sysfs_data->write_side_effect)
15235 +               sysfs_data->write_side_effect();
15236 +
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;
15241 +       }
15242 +
15243 +       if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_WRITE)
15244 +               suspend_cleanup_usm();
15245 +
15246 +       suspend_finish_anything(sysfs_data->flags & SYSFS_SUSPEND_OR_RESUME);
15247 +
15248 +       return result;
15249 +}
15250 +
15251 +static struct sysfs_ops suspend2_sysfs_ops = {
15252 +       .show   = &suspend2_attr_show,
15253 +       .store  = &suspend2_attr_store,
15254 +};
15255 +
15256 +static struct kobj_type suspend2_ktype = {
15257 +       .sysfs_ops      = &suspend2_sysfs_ops,
15258 +};
15259 +
15260 +decl_subsys(suspend2, &suspend2_ktype, NULL);
15261 +
15262 +/* Non-module sysfs entries.
15263 + *
15264 + * This array contains entries that are automatically registered at
15265 + * boot. Modules and the console code register their own entries separately.
15266 + *
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!
15269 + */
15270 +
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
15275 +       },
15276 +
15277 +       { SUSPEND2_ATTR("do_resume", SYSFS_WRITEONLY),
15278 +         SYSFS_CUSTOM(NULL, NULL, SYSFS_RESUMING),
15279 +         .write_side_effect = __suspend2_try_resume
15280 +       },
15281 +
15282 +};
15283 +
15284 +void remove_suspend2_sysdir(struct kobject *kobj)
15285 +{
15286 +       if (!kobj)
15287 +               return;
15288 +
15289 +       kobject_unregister(kobj);
15290 +
15291 +       kfree(kobj);
15292 +}
15293 +
15294 +struct kobject *make_suspend2_sysdir(char *name)
15295 +{
15296 +       struct kobject *kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
15297 +       int err;
15298 +
15299 +       if(!kobj) {
15300 +               printk("Suspend2: Can't allocate kobject for sysfs dir!\n");
15301 +               return NULL;
15302 +       }
15303 +
15304 +       err = kobject_set_name(kobj, "%s", name);
15305 +
15306 +       if (err) {
15307 +               kfree(kobj);
15308 +               return NULL;
15309 +       }
15310 +
15311 +       kobj->kset = &suspend2_subsys;
15312 +
15313 +       err = kobject_register(kobj);
15314 +
15315 +       if (err)
15316 +               kfree(kobj);
15317 +
15318 +       return err ? NULL : kobj;
15319 +}
15320 +
15321 +/* suspend_register_sysfs_file
15322 + *
15323 + * Helper for registering a new /sysfs/suspend2 entry.
15324 + */
15325 +
15326 +int suspend_register_sysfs_file(
15327 +               struct kobject *kobj,
15328 +               struct suspend_sysfs_data *suspend_sysfs_data)
15329 +{
15330 +       int result;
15331 +
15332 +       if (!suspend_sysfs_initialised)
15333 +               suspend_initialise_sysfs();
15334 +
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);
15338 +
15339 +       return result;
15340 +}
15341 +
15342 +/* suspend_unregister_sysfs_file
15343 + *
15344 + * Helper for removing unwanted /sys/power/suspend2 entries.
15345 + *
15346 + */
15347 +void suspend_unregister_sysfs_file(struct kobject *kobj,
15348 +               struct suspend_sysfs_data *suspend_sysfs_data)
15349 +{
15350 +       sysfs_remove_file(kobj, &suspend_sysfs_data->attr);
15351 +}
15352 +
15353 +void suspend_cleanup_sysfs(void)
15354 +{
15355 +       int i,
15356 +           numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
15357 +
15358 +       if (!suspend_sysfs_initialised)
15359 +               return;
15360 +
15361 +       for (i=0; i< numfiles; i++)
15362 +               suspend_unregister_sysfs_file(&suspend2_subsys.kobj,
15363 +                               &sysfs_params[i]);
15364 +
15365 +       kobj_set_kset_s(&suspend2_subsys, power_subsys);
15366 +       subsystem_unregister(&suspend2_subsys);
15367 +
15368 +       suspend_sysfs_initialised = 0;
15369 +}
15370 +
15371 +/* suspend_initialise_sysfs
15372 + *
15373 + * Initialise the /sysfs/suspend2 directory.
15374 + */
15375 +
15376 +static void suspend_initialise_sysfs(void)
15377 +{
15378 +       int i, error;
15379 +       int numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
15380 +       
15381 +       if (suspend_sysfs_initialised)
15382 +               return;
15383 +
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);
15387 +
15388 +       if (error)
15389 +               return;
15390 +
15391 +       /* Make it use the .store and .show routines above */
15392 +       kobj_set_kset_s(&suspend2_subsys, suspend2_subsys);
15393 +
15394 +       suspend_sysfs_initialised = 1;
15395 +
15396 +       for (i=0; i< numfiles; i++)
15397 +               suspend_register_sysfs_file(&suspend2_subsys.kobj,
15398 +                               &sysfs_params[i]);
15399 +}
15400 +
15401 +int s2_sysfs_init(void)
15402 +{
15403 +       suspend_initialise_sysfs();
15404 +       return 0;
15405 +}
15406 +
15407 +void s2_sysfs_exit(void)
15408 +{
15409 +       suspend_cleanup_sysfs();
15410 +}
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
15414 @@ -0,0 +1,132 @@
15415 +/*
15416 + * kernel/power/sysfs.h
15417 + *
15418 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
15419 + *
15420 + * This file is released under the GPLv2.
15421 + *
15422 + * It provides declarations for suspend to use in managing
15423 + * /sysfs/suspend2. When we switch to kobjects,
15424 + * this will become redundant.
15425 + *
15426 + */
15427 +
15428 +#include <linux/sysfs.h>
15429 +#include "power.h"
15430 +
15431 +struct suspend_sysfs_data {
15432 +       struct attribute attr;
15433 +       int type;
15434 +       int flags;
15435 +       union {
15436 +               struct {
15437 +                       unsigned long *bit_vector;
15438 +                       int bit;
15439 +               } bit;
15440 +               struct {
15441 +                       int *variable;
15442 +                       int minimum;
15443 +                       int maximum;
15444 +               } integer;
15445 +               struct {
15446 +                       long *variable;
15447 +                       long minimum;
15448 +                       long maximum;
15449 +               } a_long;
15450 +               struct {
15451 +                       unsigned long *variable;
15452 +                       unsigned long minimum;
15453 +                       unsigned long maximum;
15454 +               } ul;
15455 +               struct {
15456 +                       char *variable;
15457 +                       int max_length;
15458 +               } string;
15459 +               struct {
15460 +                       int (*read_sysfs) (const char *buffer, int count);
15461 +                       int (*write_sysfs) (const char *buffer, int count);
15462 +                       void *data;
15463 +               } special;
15464 +       } data;
15465 +       
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;
15471 +};
15472 +
15473 +enum {
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
15481 +};
15482 +
15483 +#define SUSPEND2_ATTR(_name, _mode)      \
15484 +        .attr = {.name  = _name , .mode   = _mode }
15485 +
15486 +#define SYSFS_BIT(_ul, _bit, _flags) \
15487 +       .type = SUSPEND_SYSFS_DATA_BIT, \
15488 +       .flags = _flags, \
15489 +       .data = { .bit = { .bit_vector = _ul, .bit = _bit } }
15490 +
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 } }
15496 +
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 } }
15502 +
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 } }
15508 +
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 } }
15513 +
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 } }
15518 +
15519 +#define SYSFS_WRITEONLY 0200
15520 +#define SYSFS_READONLY 0444
15521 +#define SYSFS_RW 0644
15522 +
15523 +/* Flags */
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)
15533 +
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);
15538 +
15539 +extern struct kset suspend2_subsys;
15540 +
15541 +struct kobject *make_suspend2_sysdir(char *name);
15542 +void remove_suspend2_sysdir(struct kobject *obj);
15543 +extern void suspend_cleanup_sysfs(void);
15544 +
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
15550 @@ -0,0 +1,235 @@
15551 +/*
15552 + * kernel/power/ui.c
15553 + *
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)
15558 + *
15559 + * This file is released under the GPLv2.
15560 + *
15561 + * Routines for Suspend2's user interface.
15562 + *
15563 + * The user interface code talks to a userspace program via a
15564 + * netlink socket.
15565 + *
15566 + * The kernel side:
15567 + * - starts the userui program;
15568 + * - sends text messages and progress bar status;
15569 + *
15570 + * The user space side:
15571 + * - passes messages regarding user requests (abort, toggle reboot etc)
15572 + *
15573 + */
15574 +
15575 +#define __KERNEL_SYSCALLS__
15576 +
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>
15588
15589 +#include "sysfs.h"
15590 +#include "modules.h"
15591 +#include "suspend.h"
15592 +#include "ui.h"
15593 +#include "netlink.h"
15594 +#include "power_off.h"
15595 +
15596 +static char local_printf_buf[1024];    /* Same as printk - should be safe */
15597 +struct ui_ops *s2_current_ui;
15598 +
15599 +/*! The console log level we default to. */
15600 +int suspend_default_console_level = 0;
15601 +
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.
15608 + *
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.
15612 + *
15613 + *             suspend_early_boot_message may also be called post-boot.
15614 + *             In this case, it simply printks the message and returns.
15615 + *
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.
15622 + */
15623 +
15624 +#define say(message, a...) printk(KERN_EMERG message, ##a)
15625 +#define message_timeout 25 /* message_timeout * 10 must fit in 8 bits */
15626 +
15627 +int suspend_early_boot_message(int message_detail, int default_answer, char *warning_reason, ...)
15628 +{
15629 +       unsigned long orig_state = get_suspend_state(), continue_req = 0;
15630 +       unsigned long orig_loglevel = console_loglevel;
15631 +       va_list args;
15632 +       int printed_len;
15633 +
15634 +       if (warning_reason) {
15635 +               va_start(args, warning_reason);
15636 +               printed_len = vsnprintf(local_printf_buf, 
15637 +                               sizeof(local_printf_buf), 
15638 +                               warning_reason,
15639 +                               args);
15640 +               va_end(args);
15641 +       }
15642 +
15643 +       if (!test_suspend_state(SUSPEND_BOOT_TIME)) {
15644 +               printk("Suspend2: %s\n", local_printf_buf);
15645 +               return default_answer;
15646 +       }
15647 +
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);
15652 +
15653 +#if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE)
15654 +       console_loglevel = 7;
15655 +
15656 +       say("=== Suspend2 ===\n\n");
15657 +       if (warning_reason) {
15658 +               say("BIG FAT WARNING!! %s\n\n", local_printf_buf);
15659 +               switch (message_detail) {
15660 +                case 0:
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");
15665 +                       break;
15666 +                case 1:
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");
15670 +                       break;
15671 +               }
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",
15674 +                       message_timeout,
15675 +                       default_answer == SUSPEND_CONTINUE_REQ ?
15676 +                       "continue booting" : "reboot");
15677 +       } else {
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",
15686 +                       message_timeout,
15687 +                       !!default_answer ?
15688 +                       "continue resuming" : "remove the image");
15689 +       }
15690 +       console_loglevel = orig_loglevel;
15691 +       
15692 +       set_suspend_state(SUSPEND_SANITY_CHECK_PROMPT);
15693 +       clear_suspend_state(SUSPEND_CONTINUE_REQ);
15694 +
15695 +       if (suspend_wait_for_keypress(message_timeout) == 0) /* We timed out */
15696 +               continue_req = !!default_answer;
15697 +       else
15698 +               continue_req = test_suspend_state(SUSPEND_CONTINUE_REQ);
15699 +
15700 +       if ((warning_reason) && (!continue_req))
15701 +               machine_restart(NULL);
15702 +       
15703 +       restore_suspend_state(orig_state);
15704 +       if (continue_req)
15705 +               set_suspend_state(SUSPEND_CONTINUE_REQ);
15706 +
15707 +#endif /* CONFIG_VT or CONFIG_SERIAL_CONSOLE */
15708 +       return -EIO;
15709 +}
15710 +#undef say
15711 +
15712 +/*
15713 + * User interface specific /sys/power/suspend2 entries.
15714 + */
15715 +
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)
15720 +       },
15721 +
15722 +       { SUSPEND2_ATTR("debug_sections", SYSFS_RW),
15723 +         SYSFS_UL(&suspend_debug_state, 0, 1 << 30, 0)
15724 +       },
15725 +
15726 +       { SUSPEND2_ATTR("log_everything", SYSFS_RW),
15727 +         SYSFS_BIT(&suspend_action, SUSPEND_LOGALL, 0)
15728 +       },
15729 +#endif
15730 +       { SUSPEND2_ATTR("pm_prepare_console", SYSFS_RW),
15731 +         SYSFS_BIT(&suspend_action, SUSPEND_PM_PREPARE_CONSOLE, 0)
15732 +       }
15733 +};
15734 +
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),
15742 +};
15743 +
15744 +int s2_register_ui_ops(struct ui_ops *this_ui)
15745 +{
15746 +       if (s2_current_ui) {
15747 +               printk("Only one Suspend2 user interface module can be loaded"
15748 +                       " at a time.");
15749 +               return -EBUSY;
15750 +       }
15751 +
15752 +       s2_current_ui = this_ui;
15753 +
15754 +       return 0;
15755 +}
15756 +
15757 +void s2_remove_ui_ops(struct ui_ops *this_ui)
15758 +{
15759 +       if (s2_current_ui != this_ui)
15760 +               return;
15761 +
15762 +       s2_current_ui = NULL;
15763 +}
15764 +
15765 +/* suspend_console_sysfs_init
15766 + * Description: Boot time initialisation for user interface.
15767 + */
15768 +
15769 +int s2_ui_init(void)
15770 +{
15771 +       return suspend_register_module(&userui_ops);
15772 +}
15773 +
15774 +void s2_ui_exit(void)
15775 +{
15776 +       suspend_unregister_module(&userui_ops);
15777 +}
15778 +
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);
15785 +#endif
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
15789 @@ -0,0 +1,108 @@
15790 +/*
15791 + * kernel/power/ui.h
15792 + *
15793 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
15794 + */
15795 +
15796 +enum {
15797 +       DONT_CLEAR_BAR,
15798 +       CLEAR_BAR
15799 +};
15800 +
15801 +enum {
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,
15813 +
15814 +       /* Kernel -> Userspace */
15815 +       USERUI_MSG_MESSAGE = 0x21,
15816 +       USERUI_MSG_PROGRESS = 0x22,
15817 +       USERUI_MSG_POST_ATOMIC_RESTORE = 0x25,
15818 +
15819 +       USERUI_MSG_MAX,
15820 +};
15821 +
15822 +struct userui_msg_params {
15823 +       unsigned long a, b, c, d;
15824 +       char text[255];
15825 +};
15826 +
15827 +struct ui_ops {
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, ...);
15839 +};
15840 +
15841 +extern struct ui_ops *s2_current_ui;
15842 +
15843 +#define suspend_update_status(val, max, fmt, args...) \
15844 + (s2_current_ui ? (s2_current_ui->update_status) (val, max, fmt, ##args) : max)
15845 +
15846 +#define suspend_wait_for_keypress(timeout) \
15847 + (s2_current_ui ? (s2_current_ui->wait_for_key) (timeout) : 0)
15848 +
15849 +#define suspend_ui_post_atomic_restore(void) \
15850 +       do { if (s2_current_ui) \
15851 +               (s2_current_ui->post_atomic_restore)(); \
15852 +       } while(0)
15853 +
15854 +#define suspend_prepare_console(void) \
15855 +       do { if (s2_current_ui) \
15856 +               (s2_current_ui->prepare)(); \
15857 +       } while(0)
15858 +
15859 +#define suspend_cleanup_console(void) \
15860 +       do { if (s2_current_ui) \
15861 +               (s2_current_ui->cleanup)(); \
15862 +       } while(0)
15863 +
15864 +#define abort_suspend(result, fmt, args...) \
15865 +       do { if (s2_current_ui) \
15866 +               (s2_current_ui->abort)(result, fmt, ##args); \
15867 +            else { \
15868 +               set_result_state(SUSPEND_ABORTED); \
15869 +               set_result_state(result); \
15870 +            } \
15871 +       } while(0)
15872 +
15873 +#define suspend_cond_pause(pause, message) \
15874 +       do { if (s2_current_ui) \
15875 +               (s2_current_ui->cond_pause)(pause, message); \
15876 +       } while(0)
15877 +
15878 +#define suspend_prepare_status(clear, fmt, args...) \
15879 +       do { if (s2_current_ui) \
15880 +               (s2_current_ui->prepare_status)(clear, fmt, ##args); \
15881 +            else \
15882 +               printk(fmt, ##args); \
15883 +       } while(0)
15884 +
15885 +extern int suspend_default_console_level;
15886 +
15887 +#define suspend_message(sn, lev, log, fmt, a...) \
15888 +do { \
15889 +       if (s2_current_ui && (!sn || test_debug_state(sn))) \
15890 +               s2_current_ui->message(sn, lev, log, fmt, ##a); \
15891 +} while(0)
15892 +
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
15901 @@ -31,6 +31,7 @@
15902  #include <linux/bootmem.h>
15903  #include <linux/syscalls.h>
15904  #include <linux/jiffies.h>
15905 +#include <linux/suspend.h>
15906  
15907  #include <asm/uaccess.h>
15908  
15909 @@ -91,9 +92,9 @@
15910   * The indices into log_buf are not constrained to log_buf_len - they
15911   * must be masked before subscripting
15912   */
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 */
15919  
15920  /*
15921   *     Array of consoles built from command line options (console=)
15922 @@ -116,10 +117,10 @@
15923  
15924  #ifdef CONFIG_PRINTK
15925  
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 */
15934  
15935  static int __init log_buf_len_setup(char *str)
15936  {
15937 @@ -738,12 +739,14 @@
15938         acquire_console_sem();
15939         console_suspended = 1;
15940  }
15941 +EXPORT_SYMBOL(suspend_console);
15942  
15943  void resume_console(void)
15944  {
15945         console_suspended = 0;
15946         release_console_sem();
15947  }
15948 +EXPORT_SYMBOL(resume_console);
15949  #endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
15950  
15951  /**
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 @@
15956  
15957  EXPORT_SYMBOL(avenrun);
15958  
15959 +static unsigned long avenrun_save[3];
15960 +/*
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.
15966 + */
15967 +
15968 +void save_avenrun(void)
15969 +{
15970 +       avenrun_save[0] = avenrun[0];
15971 +       avenrun_save[1] = avenrun[1];
15972 +       avenrun_save[2] = avenrun[2];
15973 +}
15974 +
15975 +EXPORT_SYMBOL_GPL(save_avenrun);
15976 +
15977 +void restore_avenrun(void)
15978 +{
15979 +       if (!avenrun_save[0])
15980 +               return;
15981 +
15982 +       avenrun[0] = avenrun_save[0];
15983 +       avenrun[1] = avenrun_save[1];
15984 +       avenrun[2] = avenrun_save[2];
15985 +
15986 +       avenrun_save[0] = 0;
15987 +}
15988 +
15989 +EXPORT_SYMBOL_GPL(restore_avenrun);
15990 +
15991  /*
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
15997 @@ -55,6 +55,9 @@
15998         depends on AUDIT && !AUDIT_ARCH
15999         default y
16000  
16001 +config DYN_PAGEFLAGS
16002 +       bool
16003 +
16004  #
16005  # compression support is select'ed if needed
16006  #
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
16010 @@ -39,6 +39,9 @@
16011  endif
16012  
16013  obj-$(CONFIG_BITREVERSE) += bitrev.o
16014 +
16015 +obj-$(CONFIG_DYN_PAGEFLAGS) += dyn_pageflags.o
16016 +
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
16023 @@ -0,0 +1,312 @@
16024 +/*
16025 + * lib/dyn_pageflags.c
16026 + *
16027 + * Copyright (C) 2004-2006 Nigel Cunningham <nigel@suspend2.net>
16028 + * 
16029 + * This file is released under the GPLv2.
16030 + *
16031 + * Routines for dynamically allocating and releasing bitmaps
16032 + * used as pseudo-pageflags.
16033 + */
16034 +
16035 +#include <linux/module.h>
16036 +#include <linux/dyn_pageflags.h>
16037 +#include <linux/bootmem.h>
16038 +#include <linux/mm.h>
16039 +
16040 +#if 0
16041 +#define PR_DEBUG(a, b...) do { printk(a, ##b); } while(0)
16042 +#else
16043 +#define PR_DEBUG(a, b...) do { } while(0)
16044 +#endif
16045 +
16046 +#define pages_for_zone(zone) \
16047 +       (DIV_ROUND_UP((zone)->spanned_pages, (PAGE_SIZE << 3)))
16048 +
16049 +/* 
16050 + * clear_dyn_pageflags(dyn_pageflags_t pagemap)
16051 + *
16052 + * Clear an array used to store local page flags.
16053 + *
16054 + */
16055 +
16056 +void clear_dyn_pageflags(dyn_pageflags_t pagemap)
16057 +{
16058 +       int i = 0, zone_idx, node_id = 0;
16059 +       struct zone *zone;
16060 +       struct pglist_data *pgdat;
16061 +       
16062 +       BUG_ON(!pagemap);
16063 +
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];
16067 +
16068 +                       if (!populated_zone(zone))
16069 +                               continue;
16070 +
16071 +                       for (i = 0; i < pages_for_zone(zone); i++)
16072 +                               memset((pagemap[node_id][zone_idx][i]), 0,
16073 +                                               PAGE_SIZE);
16074 +               }
16075 +               node_id++;
16076 +       }
16077 +}
16078 +
16079 +/* 
16080 + * free_dyn_pageflags(dyn_pageflags_t pagemap)
16081 + *
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.
16086 + *
16087 + */
16088 +void free_dyn_pageflags(dyn_pageflags_t *pagemap)
16089 +{
16090 +       int i = 0, zone_pages, node_id = -1, zone_idx;
16091 +       struct zone *zone;
16092 +       struct pglist_data *pgdat;
16093 +
16094 +       if (!*pagemap)
16095 +               return;
16096 +       
16097 +       PR_DEBUG("Seeking to free dyn_pageflags %p.\n", pagemap);
16098 +
16099 +       for_each_online_pgdat(pgdat) {
16100 +               node_id++;
16101 +
16102 +               PR_DEBUG("Node id %d.\n", node_id);
16103 +
16104 +               if (!(*pagemap)[node_id]) {
16105 +                       PR_DEBUG("Node %d unallocated.\n", node_id);
16106 +                       continue;
16107 +               }
16108 +               
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);
16113 +                               continue;
16114 +                       }
16115 +
16116 +                       if (!(*pagemap)[node_id][zone_idx]) {
16117 +                               PR_DEBUG("Node %d zone %d unallocated.\n", node_id, zone_idx);
16118 +                               continue;
16119 +                       }
16120 +
16121 +                       PR_DEBUG("Node id %d. Zone %d.\n", node_id, zone_idx);
16122 +
16123 +                       zone_pages = pages_for_zone(zone);
16124 +
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]);
16128 +                       }
16129 +
16130 +                       kfree((*pagemap)[node_id][zone_idx]);
16131 +               }
16132 +               PR_DEBUG("Free node %d (%p).\n", node_id, pagemap[node_id]);
16133 +               kfree((*pagemap)[node_id]);
16134 +       }
16135 +
16136 +       PR_DEBUG("Free map pgdat list at %p.\n", pagemap);
16137 +       kfree(*pagemap);
16138 +
16139 +       *pagemap = NULL;
16140 +       PR_DEBUG("Done.\n");
16141 +       return;
16142 +}
16143 +
16144 +static int try_alloc_dyn_pageflag_part(int nr_ptrs, void **ptr)
16145 +{
16146 +       *ptr = kzalloc(sizeof(void *) * nr_ptrs, GFP_ATOMIC);
16147 +       PR_DEBUG("Got %p. Putting it in %p.\n", *ptr, ptr);
16148 +
16149 +       if (*ptr)
16150 +               return 0;
16151 +
16152 +       printk("Error. Unable to allocate memory for dynamic pageflags.");
16153 +       return -ENOMEM;
16154 +}
16155 +
16156 +/* 
16157 + * allocate_dyn_pageflags
16158 + *
16159 + * Allocate a bitmap for dynamic page flags.
16160 + *
16161 + */
16162 +int allocate_dyn_pageflags(dyn_pageflags_t *pagemap)
16163 +{
16164 +       int i, zone_idx, zone_pages, node_id = 0;
16165 +       struct zone *zone;
16166 +       struct pglist_data *pgdat;
16167 +
16168 +       if (*pagemap) {
16169 +               PR_DEBUG("Pagemap %p already allocated.\n", pagemap);
16170 +               return 0;
16171 +       }
16172 +
16173 +       PR_DEBUG("Seeking to allocate dyn_pageflags %p.\n", pagemap);
16174 +
16175 +       for_each_online_pgdat(pgdat)
16176 +               node_id++;
16177 +
16178 +       if (try_alloc_dyn_pageflag_part(node_id, (void **) pagemap))
16179 +               return -ENOMEM;
16180 +
16181 +       node_id = 0;
16182 +
16183 +       for_each_online_pgdat(pgdat) {
16184 +               PR_DEBUG("Node %d.\n", node_id);
16185 +
16186 +               if (try_alloc_dyn_pageflag_part(MAX_NR_ZONES,
16187 +                                       (void **) &(*pagemap)[node_id]))
16188 +                               return -ENOMEM;
16189 +
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);
16192 +
16193 +                       zone = &pgdat->node_zones[zone_idx];
16194 +
16195 +                       if (!populated_zone(zone)) {
16196 +                               PR_DEBUG("Node %d zone %d unpopulated - won't allocate.\n", node_id, zone_idx);
16197 +                               continue;
16198 +                       }
16199 +
16200 +                       zone_pages = pages_for_zone(zone);
16201 +
16202 +                       PR_DEBUG("Node %d zone %d (needs %d pages).\n", node_id, zone_idx, zone_pages);
16203 +
16204 +                       if (try_alloc_dyn_pageflag_part(zone_pages,
16205 +                               (void **) &(*pagemap)[node_id][zone_idx]))
16206 +                               return -ENOMEM;
16207 +
16208 +                       for (i = 0; i < zone_pages; i++) {
16209 +                               unsigned long address = get_zeroed_page(GFP_ATOMIC);
16210 +                               if (!address) {
16211 +                                       PR_DEBUG("Error. Unable to allocate memory for "
16212 +                                               "dynamic pageflags.");
16213 +                                       free_dyn_pageflags(pagemap);
16214 +                                       return -ENOMEM;
16215 +                               }
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;
16219 +                       }
16220 +               }
16221 +               node_id++;
16222 +       }
16223 +
16224 +       PR_DEBUG("Done.\n");
16225 +       return 0;
16226 +}
16227 +
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);
16237 +
16238 +/*
16239 + * test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16240 + *
16241 + * Is the page flagged in the given bitmap?
16242 + *
16243 + */
16244 +
16245 +int test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16246 +{
16247 +       GET_BIT_AND_UL(bitmap, page);
16248 +       return test_bit(bit, ul);
16249 +}
16250 +
16251 +/*
16252 + * set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16253 + *
16254 + * Set the flag for the page in the given bitmap.
16255 + *
16256 + */
16257 +
16258 +void set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16259 +{
16260 +       GET_BIT_AND_UL(bitmap, page);
16261 +       set_bit(bit, ul);
16262 +}
16263 +
16264 +/*
16265 + * clear_dynpageflags(dyn_pageflags_t *bitmap, struct page *page)
16266 + *
16267 + * Clear the flag for the page in the given bitmap.
16268 + *
16269 + */
16270 +
16271 +void clear_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16272 +{
16273 +       GET_BIT_AND_UL(bitmap, page);
16274 +       clear_bit(bit, ul);
16275 +}
16276 +
16277 +/*
16278 + * get_next_bit_on(dyn_pageflags_t bitmap, int counter)
16279 + *
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.
16282 + *
16283 + */
16284 +
16285 +unsigned long get_next_bit_on(dyn_pageflags_t bitmap, unsigned long counter)
16286 +{
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;
16292 +
16293 +       if (first)
16294 +               counter = first_online_pgdat()->node_zones->zone_start_pfn;
16295 +
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;
16301 +
16302 +       if (first)
16303 +               goto test;
16304 +
16305 +       do {
16306 +               zone_offset++;
16307 +       
16308 +               if (zone_offset >= zone->spanned_pages) {
16309 +                       do {
16310 +                               zone = next_zone(zone);
16311 +                               if (!zone)
16312 +                                       return max_pfn + 1;
16313 +                       } while(!zone->spanned_pages);
16314 +                       
16315 +                       zone_num = zone_idx(zone);
16316 +                       node = zone->zone_pgdat->node_id;
16317 +                       zone_offset = 0;
16318 +               }
16319 +test:
16320 +               pagebit = PAGEBIT(zone_offset);
16321 +
16322 +               if (!pagebit || !ul)
16323 +                       ul = (bitmap[node][zone_num][PAGENUMBER(zone_offset)])
16324 +                               + PAGEINDEX(zone_offset);
16325 +
16326 +               if (!(*ul & ~((1 << pagebit) - 1))) {
16327 +                       zone_offset += BITS_PER_LONG - pagebit - 1;
16328 +                       continue;
16329 +               }
16330 +
16331 +       } while(!test_bit(pagebit, ul));
16332 +
16333 +       return zone->zone_start_pfn + zone_offset;
16334 +}
16335 +
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 @@
16340         return buf;
16341  }
16342  
16343 +/*
16344 + * vsnprintf_used
16345 + *
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.
16350 + */
16351 +int snprintf_used(char *buffer, int buffer_size, const char *fmt, ...)
16352 +{
16353 +       int result;
16354 +       va_list args;
16355 +
16356 +       if (!buffer_size)
16357 +               return 0;
16358 +
16359 +       va_start(args, fmt);
16360 +       result = vsnprintf(buffer, buffer_size, fmt, args);
16361 +       va_end(args);
16362 +
16363 +       return result > buffer_size ? buffer_size : result;
16364 +}
16365 +
16366  /**
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 @@
16373         return nr_taken;
16374  }
16375  
16376 +/* return_lru_pages puts a list of pages back on a zone's lru lists. */
16377 +
16378 +static void return_lru_pages(struct list_head *page_list, struct zone *zone,
16379 +               struct pagevec *pvec)
16380 +{
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);
16388 +               else
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);
16394 +               }
16395 +       }
16396 +}
16397 +
16398  /*
16399   * shrink_inactive_list() is a helper for shrink_zone().  It returns the number
16400   * of reclaimed pages
16401 @@ -667,7 +689,6 @@
16402         lru_add_drain();
16403         spin_lock_irq(&zone->lru_lock);
16404         do {
16405 -               struct page *page;
16406                 unsigned long nr_taken;
16407                 unsigned long nr_scan;
16408                 unsigned long nr_freed;
16409 @@ -697,21 +718,7 @@
16410                 /*
16411                  * Put back any unfreeable pages.
16412                  */
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);
16420 -                       else
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);
16426 -                       }
16427 -               }
16428 +               return_lru_pages(&page_list, zone, &pvec);
16429         } while (nr_scanned < max_scan);
16430         spin_unlock(&zone->lru_lock);
16431  done:
16432 @@ -1272,6 +1279,72 @@
16433         return nr_reclaimed;
16434  }
16435  
16436 +struct lru_save {
16437 +       struct zone             *zone;
16438 +       struct list_head        active_list;
16439 +       struct list_head        inactive_list;
16440 +       struct lru_save         *next;
16441 +};
16442 +
16443 +struct lru_save *lru_save_list;
16444 +
16445 +void unlink_lru_lists(void)
16446 +{
16447 +       struct zone *zone;
16448 +
16449 +       for_each_zone(zone) {
16450 +               struct lru_save *this;
16451 +               unsigned long moved, scanned;
16452 +
16453 +               if (!zone->spanned_pages)
16454 +                       continue;
16455 +
16456 +               this = (struct lru_save *)
16457 +                       kzalloc(sizeof(struct lru_save), GFP_ATOMIC);
16458 +
16459 +               BUG_ON(!this);
16460 +
16461 +               this->next = lru_save_list;
16462 +               lru_save_list = this;
16463 +               
16464 +               this->zone = zone;
16465 +
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,
16471 +                               &scanned);
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,
16475 +                               &scanned);
16476 +               __mod_zone_page_state(zone, NR_INACTIVE, -moved);
16477 +               spin_unlock_irq(&zone->lru_lock);
16478 +       }
16479 +}
16480 +
16481 +void relink_lru_lists(void)
16482 +{
16483 +       while(lru_save_list) {
16484 +               struct lru_save *this = lru_save_list;
16485 +               struct zone *zone = this->zone;
16486 +               struct pagevec pvec;
16487 +
16488 +               pagevec_init(&pvec, 1);
16489 +
16490 +               lru_save_list = this->next;
16491 +
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);
16497 +
16498 +               kfree(this);
16499 +       }
16500 +}
16501 +
16502  /*
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))
16507                 return;
16508  
16509 +       if (freezer_is_on())
16510 +               return;
16511 +
16512         pgdat = zone->zone_pgdat;
16513         if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0))
16514                 return;
16515 @@ -1369,6 +1445,91 @@
16516  }
16517  
16518  #ifdef CONFIG_PM
16519 +void shrink_one_zone(struct zone *zone, int total_to_free)
16520 +{
16521 +       int prio;
16522 +       unsigned long still_to_free = total_to_free;
16523 +       struct scan_control sc = {
16524 +               .gfp_mask = GFP_KERNEL,
16525 +               .may_swap = 0,
16526 +               .may_writepage = 1,
16527 +               .swappiness = vm_swappiness,
16528 +       };
16529 +
16530 +       if (!populated_zone(zone) || zone->all_unreclaimable)
16531 +               return;
16532 +
16533 +       if (still_to_free <= 0)
16534 +               return;
16535 +
16536 +       if (is_highmem(zone))
16537 +               sc.gfp_mask |= __GFP_HIGHMEM;
16538 +
16539 +       for (prio = DEF_PRIORITY; prio >= 0; prio--) {
16540 +               unsigned long to_free, just_freed, orig_size;
16541 +               unsigned long old_nr_active;
16542 +
16543 +               to_free = min(zone_page_state(zone, NR_ACTIVE) +
16544 +                               zone_page_state(zone, NR_INACTIVE),
16545 +                               still_to_free);
16546 +
16547 +               if (to_free <= 0)
16548 +                       return;
16549 +
16550 +               sc.swap_cluster_max = to_free -
16551 +                       zone_page_state(zone, NR_INACTIVE);
16552 +
16553 +               do {
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,
16557 +                                       prio);
16558 +                       zone->nr_scan_active = 0;
16559 +
16560 +                       sc.swap_cluster_max = to_free - zone_page_state(zone,
16561 +                                       NR_INACTIVE);
16562 +
16563 +               } while (sc.swap_cluster_max > 0 &&
16564 +                        zone_page_state(zone, NR_ACTIVE) > old_nr_active);
16565 +
16566 +               to_free = min(zone_page_state(zone, NR_ACTIVE) +
16567 +                               zone_page_state(zone, NR_INACTIVE),
16568 +                               still_to_free);
16569 +               
16570 +               do {
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);
16583 +       };
16584 +
16585 +       while (still_to_free > 0) {
16586 +               unsigned long nr_slab = global_page_state(NR_SLAB_RECLAIMABLE);
16587 +               struct reclaim_state reclaim_state;
16588 +
16589 +               if (nr_slab > still_to_free)
16590 +                       nr_slab = still_to_free;
16591 +
16592 +               reclaim_state.reclaimed_slab = 0;
16593 +               shrink_slab(nr_slab, sc.gfp_mask, nr_slab);
16594 +               if (!reclaim_state.reclaimed_slab)
16595 +                       break;
16596 +
16597 +               still_to_free -= reclaim_state.reclaimed_slab;
16598 +       }
16599 +
16600 +       return;
16601 +}
16602 +
16603 +
16604  /*
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
This page took 1.22797 seconds and 3 git commands to generate.