Magellan Linux

Contents of /trunk/kernel26-magellan/patches-2.6.21-r11/0154-2.6.21-suspend2-2.2.10.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 301 - (show annotations) (download)
Fri Aug 17 22:52:50 2007 UTC (16 years, 9 months ago) by niro
File size: 478877 byte(s)
-2.6.21-magellan-r11

1 diff -Naur linux-2.6.21-ck2/Documentation/kernel-parameters.txt linux-2.6.21-magellan-r11/Documentation/kernel-parameters.txt
2 --- linux-2.6.21-ck2/Documentation/kernel-parameters.txt 2007-04-26 05:08:32.000000000 +0200
3 +++ linux-2.6.21-magellan-r11/Documentation/kernel-parameters.txt 2007-08-17 15:57:25.000000000 +0200
4 @@ -82,6 +82,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 @@ -1140,6 +1141,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 @@ -1445,6 +1448,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 -Naur linux-2.6.21-ck2/Documentation/power/suspend2-internals.txt linux-2.6.21-magellan-r11/Documentation/power/suspend2-internals.txt
34 --- linux-2.6.21-ck2/Documentation/power/suspend2-internals.txt 1970-01-01 01:00:00.000000000 +0100
35 +++ linux-2.6.21-magellan-r11/Documentation/power/suspend2-internals.txt 2007-08-17 15:57:25.000000000 +0200
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 -Naur linux-2.6.21-ck2/Documentation/power/suspend2.txt linux-2.6.21-magellan-r11/Documentation/power/suspend2.txt
511 --- linux-2.6.21-ck2/Documentation/power/suspend2.txt 1970-01-01 01:00:00.000000000 +0100
512 +++ linux-2.6.21-magellan-r11/Documentation/power/suspend2.txt 2007-08-17 15:57:25.000000000 +0200
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 -Naur linux-2.6.21-ck2/MAINTAINERS linux-2.6.21-magellan-r11/MAINTAINERS
1228 --- linux-2.6.21-ck2/MAINTAINERS 2007-04-26 05:08:32.000000000 +0200
1229 +++ linux-2.6.21-magellan-r11/MAINTAINERS 2007-08-17 15:57:25.000000000 +0200
1230 @@ -3218,6 +3218,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 -Naur linux-2.6.21-ck2/arch/i386/mm/fault.c linux-2.6.21-magellan-r11/arch/i386/mm/fault.c
1245 --- linux-2.6.21-ck2/arch/i386/mm/fault.c 2007-04-26 05:08:32.000000000 +0200
1246 +++ linux-2.6.21-magellan-r11/arch/i386/mm/fault.c 2007-08-17 15:57:25.000000000 +0200
1247 @@ -23,6 +23,7 @@
1248 #include <linux/module.h>
1249 #include <linux/kprobes.h>
1250 #include <linux/uaccess.h>
1251 +#include <linux/suspend.h>
1252
1253 #include <asm/system.h>
1254 #include <asm/desc.h>
1255 @@ -33,6 +34,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 -Naur linux-2.6.21-ck2/arch/i386/mm/init.c linux-2.6.21-magellan-r11/arch/i386/mm/init.c
1287 --- linux-2.6.21-ck2/arch/i386/mm/init.c 2007-04-26 05:08:32.000000000 +0200
1288 +++ linux-2.6.21-magellan-r11/arch/i386/mm/init.c 2007-08-17 15:57:25.000000000 +0200
1289 @@ -387,7 +387,7 @@
1290 #endif
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 @@ -774,13 +774,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: %ldk freed\n", what, (end - begin) >> 10);
1313 + //printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
1314 }
1315
1316 void free_initmem(void)
1317 diff -Naur linux-2.6.21-ck2/arch/i386/mm/pageattr.c linux-2.6.21-magellan-r11/arch/i386/mm/pageattr.c
1318 --- linux-2.6.21-ck2/arch/i386/mm/pageattr.c 2007-04-26 05:08:32.000000000 +0200
1319 +++ linux-2.6.21-magellan-r11/arch/i386/mm/pageattr.c 2007-08-17 15:57:25.000000000 +0200
1320 @@ -252,7 +252,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 -Naur linux-2.6.21-ck2/arch/i386/power/Makefile linux-2.6.21-magellan-r11/arch/i386/power/Makefile
1349 --- linux-2.6.21-ck2/arch/i386/power/Makefile 2007-04-26 05:08:32.000000000 +0200
1350 +++ linux-2.6.21-magellan-r11/arch/i386/power/Makefile 2007-08-17 15:57:25.000000000 +0200
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 -Naur linux-2.6.21-ck2/arch/powerpc/kernel/Makefile linux-2.6.21-magellan-r11/arch/powerpc/kernel/Makefile
1356 --- linux-2.6.21-ck2/arch/powerpc/kernel/Makefile 2007-04-26 05:08:32.000000000 +0200
1357 +++ linux-2.6.21-magellan-r11/arch/powerpc/kernel/Makefile 2007-08-17 15:57:25.000000000 +0200
1358 @@ -36,7 +36,7 @@
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 -obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
1363 +obj32-$(CONFIG_SUSPEND_SHARED) += swsusp_32.o
1364 obj32-$(CONFIG_MODULES) += module_32.o
1365
1366 ifeq ($(CONFIG_PPC_MERGE),y)
1367 diff -Naur linux-2.6.21-ck2/arch/powerpc/platforms/powermac/setup.c linux-2.6.21-magellan-r11/arch/powerpc/platforms/powermac/setup.c
1368 --- linux-2.6.21-ck2/arch/powerpc/platforms/powermac/setup.c 2007-04-26 05:08:32.000000000 +0200
1369 +++ linux-2.6.21-magellan-r11/arch/powerpc/platforms/powermac/setup.c 2007-08-17 15:57:25.000000000 +0200
1370 @@ -425,7 +425,7 @@
1371 * only
1372 */
1373
1374 -#ifdef CONFIG_SOFTWARE_SUSPEND
1375 +#ifdef CONFIG_SUSPEND_SHARED
1376
1377 static int pmac_pm_prepare(suspend_state_t state)
1378 {
1379 @@ -480,16 +480,16 @@
1380 .valid = pmac_pm_valid,
1381 };
1382
1383 -#endif /* CONFIG_SOFTWARE_SUSPEND */
1384 +#endif /* CONFIG_SUSPEND_SHARED */
1385
1386 static int initializing = 1;
1387
1388 static int pmac_late_init(void)
1389 {
1390 initializing = 0;
1391 -#ifdef CONFIG_SOFTWARE_SUSPEND
1392 +#ifdef CONFIG_SUSPEND_SHARED
1393 pm_set_ops(&pmac_pm_ops);
1394 -#endif /* CONFIG_SOFTWARE_SUSPEND */
1395 +#endif /* CONFIG_SUSPEND_SHARED */
1396 return 0;
1397 }
1398
1399 diff -Naur linux-2.6.21-ck2/arch/x86_64/kernel/Makefile linux-2.6.21-magellan-r11/arch/x86_64/kernel/Makefile
1400 --- linux-2.6.21-ck2/arch/x86_64/kernel/Makefile 2007-04-26 05:08:32.000000000 +0200
1401 +++ linux-2.6.21-magellan-r11/arch/x86_64/kernel/Makefile 2007-08-17 15:57:25.000000000 +0200
1402 @@ -26,7 +26,7 @@
1403 obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
1404 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
1405 obj-$(CONFIG_PM) += suspend.o
1406 -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
1407 +obj-$(CONFIG_SUSPEND_SHARED) += suspend_asm.o
1408 obj-$(CONFIG_CPU_FREQ) += cpufreq/
1409 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
1410 obj-$(CONFIG_IOMMU) += pci-gart.o aperture.o
1411 diff -Naur linux-2.6.21-ck2/arch/x86_64/kernel/suspend.c linux-2.6.21-magellan-r11/arch/x86_64/kernel/suspend.c
1412 --- linux-2.6.21-ck2/arch/x86_64/kernel/suspend.c 2007-04-26 05:08:32.000000000 +0200
1413 +++ linux-2.6.21-magellan-r11/arch/x86_64/kernel/suspend.c 2007-08-17 15:57:25.000000000 +0200
1414 @@ -140,7 +140,7 @@
1415
1416 }
1417
1418 -#ifdef CONFIG_SOFTWARE_SUSPEND
1419 +#ifdef CONFIG_SUSPEND_SHARED
1420 /* Defined in arch/x86_64/kernel/suspend_asm.S */
1421 extern int restore_image(void);
1422
1423 @@ -219,4 +219,4 @@
1424 restore_image();
1425 return 0;
1426 }
1427 -#endif /* CONFIG_SOFTWARE_SUSPEND */
1428 +#endif /* CONFIG_SUSPEND_SHARED */
1429 diff -Naur linux-2.6.21-ck2/crypto/Kconfig linux-2.6.21-magellan-r11/crypto/Kconfig
1430 --- linux-2.6.21-ck2/crypto/Kconfig 2007-04-26 05:08:32.000000000 +0200
1431 +++ linux-2.6.21-magellan-r11/crypto/Kconfig 2007-08-17 15:57:25.000000000 +0200
1432 @@ -406,6 +406,14 @@
1433
1434 You will most probably want this if using IPSec.
1435
1436 +config CRYPTO_LZF
1437 + tristate "LZF compression algorithm"
1438 + default y
1439 + select CRYPTO_ALGAPI
1440 + help
1441 + This is the LZF algorithm. It is especially useful for Suspend2,
1442 + because it achieves good compression quickly.
1443 +
1444 config CRYPTO_MICHAEL_MIC
1445 tristate "Michael MIC keyed digest algorithm"
1446 select CRYPTO_ALGAPI
1447 diff -Naur linux-2.6.21-ck2/crypto/Makefile linux-2.6.21-magellan-r11/crypto/Makefile
1448 --- linux-2.6.21-ck2/crypto/Makefile 2007-04-26 05:08:32.000000000 +0200
1449 +++ linux-2.6.21-magellan-r11/crypto/Makefile 2007-08-17 15:57:25.000000000 +0200
1450 @@ -46,5 +46,6 @@
1451 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
1452 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
1453 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
1454 +obj-$(CONFIG_CRYPTO_LZF) += lzf.o
1455
1456 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
1457 diff -Naur linux-2.6.21-ck2/crypto/lzf.c linux-2.6.21-magellan-r11/crypto/lzf.c
1458 --- linux-2.6.21-ck2/crypto/lzf.c 1970-01-01 01:00:00.000000000 +0100
1459 +++ linux-2.6.21-magellan-r11/crypto/lzf.c 2007-08-17 15:57:25.000000000 +0200
1460 @@ -0,0 +1,325 @@
1461 +/*
1462 + * Cryptoapi LZF compression module.
1463 + *
1464 + * Copyright (c) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
1465 + *
1466 + * based on the deflate.c file:
1467 + *
1468 + * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
1469 + *
1470 + * and upon the LZF compression module donated to the Suspend2 project with
1471 + * the following copyright:
1472 + *
1473 + * This program is free software; you can redistribute it and/or modify it
1474 + * under the terms of the GNU General Public License as published by the Free
1475 + * Software Foundation; either version 2 of the License, or (at your option)
1476 + * any later version.
1477 + * Copyright (c) 2000-2003 Marc Alexander Lehmann <pcg@goof.com>
1478 + *
1479 + * Redistribution and use in source and binary forms, with or without modifica-
1480 + * tion, are permitted provided that the following conditions are met:
1481 + *
1482 + * 1. Redistributions of source code must retain the above copyright notice,
1483 + * this list of conditions and the following disclaimer.
1484 + *
1485 + * 2. Redistributions in binary form must reproduce the above copyright
1486 + * notice, this list of conditions and the following disclaimer in the
1487 + * documentation and/or other materials provided with the distribution.
1488 + *
1489 + * 3. The name of the author may not be used to endorse or promote products
1490 + * derived from this software without specific prior written permission.
1491 + *
1492 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
1493 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
1494 + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
1495 + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
1496 + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1497 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
1498 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1499 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
1500 + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1501 + * OF THE POSSIBILITY OF SUCH DAMAGE.
1502 + *
1503 + * Alternatively, the contents of this file may be used under the terms of
1504 + * the GNU General Public License version 2 (the "GPL"), in which case the
1505 + * provisions of the GPL are applicable instead of the above. If you wish to
1506 + * allow the use of your version of this file only under the terms of the
1507 + * GPL and not to allow others to use your version of this file under the
1508 + * BSD license, indicate your decision by deleting the provisions above and
1509 + * replace them with the notice and other provisions required by the GPL. If
1510 + * you do not delete the provisions above, a recipient may use your version
1511 + * of this file under either the BSD or the GPL.
1512 + */
1513 +
1514 +#include <linux/kernel.h>
1515 +#include <linux/module.h>
1516 +#include <linux/init.h>
1517 +#include <linux/module.h>
1518 +#include <linux/crypto.h>
1519 +#include <linux/err.h>
1520 +#include <linux/vmalloc.h>
1521 +#include <asm/string.h>
1522 +
1523 +struct lzf_ctx {
1524 + void *hbuf;
1525 + unsigned int bufofs;
1526 +};
1527 +
1528 +/*
1529 + * size of hashtable is (1 << hlog) * sizeof (char *)
1530 + * decompression is independent of the hash table size
1531 + * the difference between 15 and 14 is very small
1532 + * for small blocks (and 14 is also faster).
1533 + * For a low-memory configuration, use hlog == 13;
1534 + * For best compression, use 15 or 16.
1535 + */
1536 +static const int hlog = 14;
1537 +
1538 +/*
1539 + * don't play with this unless you benchmark!
1540 + * decompression is not dependent on the hash function
1541 + * the hashing function might seem strange, just believe me
1542 + * it works ;)
1543 + */
1544 +static inline u16 first(const u8 *p)
1545 +{
1546 + return ((p[0]) << 8) + p[1];
1547 +}
1548 +
1549 +static inline u16 next(u8 v, const u8 *p)
1550 +{
1551 + return ((v) << 8) + p[2];
1552 +}
1553 +
1554 +static inline u32 idx(unsigned int h)
1555 +{
1556 + return (((h ^ (h << 5)) >> (3*8 - hlog)) + h*3) & ((1 << hlog) - 1);
1557 +}
1558 +
1559 +/*
1560 + * IDX works because it is very similar to a multiplicative hash, e.g.
1561 + * (h * 57321 >> (3*8 - hlog))
1562 + * the next one is also quite good, albeit slow ;)
1563 + * (int)(cos(h & 0xffffff) * 1e6)
1564 + */
1565 +
1566 +static const int max_lit = (1 << 5);
1567 +static const int max_off = (1 << 13);
1568 +static const int max_ref = ((1 << 8) + (1 << 3));
1569 +
1570 +/*
1571 + * compressed format
1572 + *
1573 + * 000LLLLL <L+1> ; literal
1574 + * LLLOOOOO oooooooo ; backref L
1575 + * 111OOOOO LLLLLLLL oooooooo ; backref L+7
1576 + *
1577 + */
1578 +
1579 +static void lzf_compress_exit(struct crypto_tfm *tfm)
1580 +{
1581 + struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1582 +
1583 + if (!ctx->hbuf)
1584 + return;
1585 +
1586 + vfree(ctx->hbuf);
1587 + ctx->hbuf = NULL;
1588 +}
1589 +
1590 +static int lzf_compress_init(struct crypto_tfm *tfm)
1591 +{
1592 + struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1593 +
1594 + /* Get LZF ready to go */
1595 + ctx->hbuf = vmalloc_32((1 << hlog) * sizeof(char *));
1596 + if (ctx->hbuf)
1597 + return 0;
1598 +
1599 + printk(KERN_WARNING "Failed to allocate %ld bytes for lzf workspace\n",
1600 + (long) ((1 << hlog) * sizeof(char *)));
1601 + return -ENOMEM;
1602 +}
1603 +
1604 +static int lzf_compress(struct crypto_tfm *tfm, const u8 *in_data,
1605 + unsigned int in_len, u8 *out_data, unsigned int *out_len)
1606 +{
1607 + struct lzf_ctx *ctx = crypto_tfm_ctx(tfm);
1608 + const u8 **htab = ctx->hbuf;
1609 + const u8 **hslot;
1610 + const u8 *ip = in_data;
1611 + u8 *op = out_data;
1612 + const u8 *in_end = ip + in_len;
1613 + u8 *out_end = op + *out_len - 3;
1614 + const u8 *ref;
1615 +
1616 + unsigned int hval = first(ip);
1617 + unsigned long off;
1618 + int lit = 0;
1619 +
1620 + memset(htab, 0, sizeof(htab));
1621 +
1622 + for (;;) {
1623 + if (ip < in_end - 2) {
1624 + hval = next(hval, ip);
1625 + hslot = htab + idx(hval);
1626 + ref = *hslot;
1627 + *hslot = ip;
1628 +
1629 + if ((off = ip - ref - 1) < max_off
1630 + && ip + 4 < in_end && ref > in_data
1631 + && *(u16 *) ref == *(u16 *) ip && ref[2] == ip[2]
1632 + ) {
1633 + /* match found at *ref++ */
1634 + unsigned int len = 2;
1635 + unsigned int maxlen = in_end - ip - len;
1636 + maxlen = maxlen > max_ref ? max_ref : maxlen;
1637 +
1638 + do
1639 + len++;
1640 + while (len < maxlen && ref[len] == ip[len]);
1641 +
1642 + if (op + lit + 1 + 3 >= out_end) {
1643 + *out_len = PAGE_SIZE;
1644 + return 0;
1645 + }
1646 +
1647 + if (lit) {
1648 + *op++ = lit - 1;
1649 + lit = -lit;
1650 + do
1651 + *op++ = ip[lit];
1652 + while (++lit);
1653 + }
1654 +
1655 + len -= 2;
1656 + ip++;
1657 +
1658 + if (len < 7) {
1659 + *op++ = (off >> 8) + (len << 5);
1660 + } else {
1661 + *op++ = (off >> 8) + (7 << 5);
1662 + *op++ = len - 7;
1663 + }
1664 +
1665 + *op++ = off;
1666 +
1667 + ip += len;
1668 + hval = first(ip);
1669 + hval = next(hval, ip);
1670 + htab[idx(hval)] = ip;
1671 + ip++;
1672 + continue;
1673 + }
1674 + } else if (ip == in_end)
1675 + break;
1676 +
1677 + /* one more literal byte we must copy */
1678 + lit++;
1679 + ip++;
1680 +
1681 + if (lit == max_lit) {
1682 + if (op + 1 + max_lit >= out_end) {
1683 + *out_len = PAGE_SIZE;
1684 + return 0;
1685 + }
1686 +
1687 + *op++ = max_lit - 1;
1688 + memcpy(op, ip - max_lit, max_lit);
1689 + op += max_lit;
1690 + lit = 0;
1691 + }
1692 + }
1693 +
1694 + if (lit) {
1695 + if (op + lit + 1 >= out_end) {
1696 + *out_len = PAGE_SIZE;
1697 + return 0;
1698 + }
1699 +
1700 + *op++ = lit - 1;
1701 + lit = -lit;
1702 + do
1703 + *op++ = ip[lit];
1704 + while (++lit);
1705 + }
1706 +
1707 + *out_len = op - out_data;
1708 + return 0;
1709 +}
1710 +
1711 +static int lzf_decompress(struct crypto_tfm *tfm, const u8 *src,
1712 + unsigned int slen, u8 *dst, unsigned int *dlen)
1713 +{
1714 + u8 const *ip = src;
1715 + u8 *op = dst;
1716 + u8 const *const in_end = ip + slen;
1717 + u8 *const out_end = op + *dlen;
1718 +
1719 + *dlen = PAGE_SIZE;
1720 + do {
1721 + unsigned int ctrl = *ip++;
1722 +
1723 + if (ctrl < (1 << 5)) { /* literal run */
1724 + ctrl++;
1725 +
1726 + if (op + ctrl > out_end)
1727 + return 0;
1728 + memcpy(op, ip, ctrl);
1729 + op += ctrl;
1730 + ip += ctrl;
1731 + } else { /* back reference */
1732 +
1733 + unsigned int len = ctrl >> 5;
1734 +
1735 + u8 *ref = op - ((ctrl & 0x1f) << 8) - 1;
1736 +
1737 + if (len == 7)
1738 + len += *ip++;
1739 +
1740 + ref -= *ip++;
1741 + len += 2;
1742 +
1743 + if (op + len > out_end || ref < (u8 *) dst)
1744 + return 0;
1745 +
1746 + do
1747 + *op++ = *ref++;
1748 + while (--len);
1749 + }
1750 + }
1751 + while (op < out_end && ip < in_end);
1752 +
1753 + *dlen = op - (u8 *) dst;
1754 + return 0;
1755 +}
1756 +
1757 +static struct crypto_alg alg = {
1758 + .cra_name = "lzf",
1759 + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
1760 + .cra_ctxsize = 0,
1761 + .cra_module = THIS_MODULE,
1762 + .cra_list = LIST_HEAD_INIT(alg.cra_list),
1763 + .cra_init = lzf_compress_init,
1764 + .cra_exit = lzf_compress_exit,
1765 + .cra_u = { .compress = {
1766 + .coa_compress = lzf_compress,
1767 + .coa_decompress = lzf_decompress } }
1768 +};
1769 +
1770 +static int __init init(void)
1771 +{
1772 + return crypto_register_alg(&alg);
1773 +}
1774 +
1775 +static void __exit fini(void)
1776 +{
1777 + crypto_unregister_alg(&alg);
1778 +}
1779 +
1780 +module_init(init);
1781 +module_exit(fini);
1782 +
1783 +MODULE_LICENSE("GPL");
1784 +MODULE_DESCRIPTION("LZF Compression Algorithm");
1785 +MODULE_AUTHOR("Marc Alexander Lehmann & Nigel Cunningham");
1786 diff -Naur linux-2.6.21-ck2/drivers/base/core.c linux-2.6.21-magellan-r11/drivers/base/core.c
1787 --- linux-2.6.21-ck2/drivers/base/core.c 2007-04-26 05:08:32.000000000 +0200
1788 +++ linux-2.6.21-magellan-r11/drivers/base/core.c 2007-08-17 15:57:25.000000000 +0200
1789 @@ -27,6 +27,8 @@
1790 int (*platform_notify)(struct device * dev) = NULL;
1791 int (*platform_notify_remove)(struct device * dev) = NULL;
1792
1793 +static int do_dump_stack;
1794 +
1795 /*
1796 * sysfs bindings for devices.
1797 */
1798 @@ -638,6 +640,18 @@
1799 class_intf->add_dev(dev, class_intf);
1800 up(&dev->class->sem);
1801 }
1802 +
1803 +#ifdef CONFIG_PM
1804 + if (!((dev->class && dev->class->resume) ||
1805 + (dev->bus && (dev->bus->resume || dev->bus->resume_early))) &&
1806 + !dev->pm_safe) {
1807 + printk("Device driver %s lacks bus and class support for "
1808 + "being resumed.\n", kobject_name(&dev->kobj));
1809 + if (do_dump_stack)
1810 + dump_stack();
1811 + }
1812 +#endif
1813 +
1814 Done:
1815 kfree(class_name);
1816 put_device(dev);
1817 @@ -975,6 +989,7 @@
1818 dev->class = class;
1819 dev->parent = parent;
1820 dev->release = device_create_release;
1821 + dev->pm_safe = 1;
1822
1823 va_start(args, fmt);
1824 vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
1825 @@ -1183,3 +1198,11 @@
1826 }
1827
1828 EXPORT_SYMBOL_GPL(device_move);
1829 +
1830 +static int __init pm_debug_dump_stack(char *str)
1831 +{
1832 + do_dump_stack = 1;
1833 + return 1;
1834 +}
1835 +
1836 +__setup("pm_debug_dump_stack", pm_debug_dump_stack);
1837 diff -Naur linux-2.6.21-ck2/drivers/macintosh/via-pmu.c linux-2.6.21-magellan-r11/drivers/macintosh/via-pmu.c
1838 --- linux-2.6.21-ck2/drivers/macintosh/via-pmu.c 2007-04-26 05:08:32.000000000 +0200
1839 +++ linux-2.6.21-magellan-r11/drivers/macintosh/via-pmu.c 2007-08-17 15:57:25.000000000 +0200
1840 @@ -42,7 +42,6 @@
1841 #include <linux/interrupt.h>
1842 #include <linux/device.h>
1843 #include <linux/sysdev.h>
1844 -#include <linux/freezer.h>
1845 #include <linux/syscalls.h>
1846 #include <linux/suspend.h>
1847 #include <linux/cpu.h>
1848 diff -Naur linux-2.6.21-ck2/drivers/md/md.c linux-2.6.21-magellan-r11/drivers/md/md.c
1849 --- linux-2.6.21-ck2/drivers/md/md.c 2007-04-26 05:08:32.000000000 +0200
1850 +++ linux-2.6.21-magellan-r11/drivers/md/md.c 2007-08-17 15:57:25.000000000 +0200
1851 @@ -5309,6 +5309,8 @@
1852 last_mark = next;
1853 }
1854
1855 + while(freezer_is_on())
1856 + yield();
1857
1858 if (kthread_should_stop()) {
1859 /*
1860 diff -Naur linux-2.6.21-ck2/drivers/pci/pci-driver.c linux-2.6.21-magellan-r11/drivers/pci/pci-driver.c
1861 --- linux-2.6.21-ck2/drivers/pci/pci-driver.c 2007-04-26 05:08:32.000000000 +0200
1862 +++ linux-2.6.21-magellan-r11/drivers/pci/pci-driver.c 2007-08-17 15:57:25.000000000 +0200
1863 @@ -451,6 +451,10 @@
1864 if (error)
1865 driver_unregister(&drv->driver);
1866
1867 + if (!drv->resume)
1868 + printk("PCI driver %s lacks driver specific resume support.\n",
1869 + drv->name);
1870 +
1871 return error;
1872 }
1873
1874 diff -Naur linux-2.6.21-ck2/drivers/usb/core/driver.c linux-2.6.21-magellan-r11/drivers/usb/core/driver.c
1875 --- linux-2.6.21-ck2/drivers/usb/core/driver.c 2007-04-26 05:08:32.000000000 +0200
1876 +++ linux-2.6.21-magellan-r11/drivers/usb/core/driver.c 2007-08-17 15:57:25.000000000 +0200
1877 @@ -788,6 +788,9 @@
1878 usbcore_name, new_driver->name);
1879 usbfs_update_special();
1880 usb_create_newid_file(new_driver);
1881 + if (!new_driver->resume)
1882 + printk("USB driver %s lacks resume support.\n",
1883 + new_driver->name);
1884 } else {
1885 printk(KERN_ERR "%s: error %d registering interface "
1886 " driver %s\n",
1887 diff -Naur linux-2.6.21-ck2/include/asm-i386/cacheflush.h linux-2.6.21-magellan-r11/include/asm-i386/cacheflush.h
1888 --- linux-2.6.21-ck2/include/asm-i386/cacheflush.h 2007-04-26 05:08:32.000000000 +0200
1889 +++ linux-2.6.21-magellan-r11/include/asm-i386/cacheflush.h 2007-08-17 15:57:25.000000000 +0200
1890 @@ -36,4 +36,6 @@
1891 void mark_rodata_ro(void);
1892 #endif
1893
1894 +extern int page_is_mapped(struct page *page);
1895 +
1896 #endif /* _I386_CACHEFLUSH_H */
1897 diff -Naur linux-2.6.21-ck2/include/asm-i386/suspend.h linux-2.6.21-magellan-r11/include/asm-i386/suspend.h
1898 --- linux-2.6.21-ck2/include/asm-i386/suspend.h 2007-04-26 05:08:32.000000000 +0200
1899 +++ linux-2.6.21-magellan-r11/include/asm-i386/suspend.h 2007-08-17 15:57:25.000000000 +0200
1900 @@ -8,6 +8,9 @@
1901
1902 static inline int arch_prepare_suspend(void) { return 0; }
1903
1904 +extern int suspend2_faulted;
1905 +#define clear_suspend2_fault() do { suspend2_faulted = 0; } while(0)
1906 +
1907 /* image of the saved processor state */
1908 struct saved_context {
1909 u16 es, fs, gs, ss;
1910 diff -Naur linux-2.6.21-ck2/include/asm-ppc/suspend.h linux-2.6.21-magellan-r11/include/asm-ppc/suspend.h
1911 --- linux-2.6.21-ck2/include/asm-ppc/suspend.h 2007-04-26 05:08:32.000000000 +0200
1912 +++ linux-2.6.21-magellan-r11/include/asm-ppc/suspend.h 2007-08-17 15:57:25.000000000 +0200
1913 @@ -10,3 +10,6 @@
1914 static inline void restore_processor_state(void)
1915 {
1916 }
1917 +
1918 +#define suspend2_faulted (0)
1919 +#define clear_suspend2_fault() do { } while(0)
1920 diff -Naur linux-2.6.21-ck2/include/asm-x86_64/cacheflush.h linux-2.6.21-magellan-r11/include/asm-x86_64/cacheflush.h
1921 --- linux-2.6.21-ck2/include/asm-x86_64/cacheflush.h 2007-04-26 05:08:32.000000000 +0200
1922 +++ linux-2.6.21-magellan-r11/include/asm-x86_64/cacheflush.h 2007-08-17 15:57:25.000000000 +0200
1923 @@ -32,4 +32,9 @@
1924 void mark_rodata_ro(void);
1925 #endif
1926
1927 +static inline int page_is_mapped(struct page *page)
1928 +{
1929 + return 1;
1930 +}
1931 +
1932 #endif /* _X8664_CACHEFLUSH_H */
1933 diff -Naur linux-2.6.21-ck2/include/asm-x86_64/suspend.h linux-2.6.21-magellan-r11/include/asm-x86_64/suspend.h
1934 --- linux-2.6.21-ck2/include/asm-x86_64/suspend.h 2007-04-26 05:08:32.000000000 +0200
1935 +++ linux-2.6.21-magellan-r11/include/asm-x86_64/suspend.h 2007-08-17 15:57:25.000000000 +0200
1936 @@ -12,6 +12,9 @@
1937 return 0;
1938 }
1939
1940 +#define suspend2_faulted (0)
1941 +#define clear_suspend2_fault() do { } while(0)
1942 +
1943 /* Image of the saved processor state. If you touch this, fix acpi_wakeup.S. */
1944 struct saved_context {
1945 u16 ds, es, fs, gs, ss;
1946 diff -Naur linux-2.6.21-ck2/include/linux/device.h linux-2.6.21-magellan-r11/include/linux/device.h
1947 --- linux-2.6.21-ck2/include/linux/device.h 2007-04-26 05:08:32.000000000 +0200
1948 +++ linux-2.6.21-magellan-r11/include/linux/device.h 2007-08-17 15:57:25.000000000 +0200
1949 @@ -402,6 +402,7 @@
1950 char bus_id[BUS_ID_SIZE]; /* position on parent bus */
1951 struct device_type *type;
1952 unsigned is_registered:1;
1953 + unsigned pm_safe:1; /* No resume fn is ok? */
1954 struct device_attribute uevent_attr;
1955 struct device_attribute *devt_attr;
1956
1957 diff -Naur linux-2.6.21-ck2/include/linux/dyn_pageflags.h linux-2.6.21-magellan-r11/include/linux/dyn_pageflags.h
1958 --- linux-2.6.21-ck2/include/linux/dyn_pageflags.h 1970-01-01 01:00:00.000000000 +0100
1959 +++ linux-2.6.21-magellan-r11/include/linux/dyn_pageflags.h 2007-08-17 15:57:25.000000000 +0200
1960 @@ -0,0 +1,68 @@
1961 +/*
1962 + * include/linux/dyn_pageflags.h
1963 + *
1964 + * Copyright (C) 2004-2006 Nigel Cunningham <nigel@suspend2.net>
1965 + *
1966 + * This file is released under the GPLv2.
1967 + *
1968 + * It implements support for dynamically allocated bitmaps that are
1969 + * used for temporary or infrequently used pageflags, in lieu of
1970 + * bits in the struct page flags entry.
1971 + */
1972 +
1973 +#ifndef DYN_PAGEFLAGS_H
1974 +#define DYN_PAGEFLAGS_H
1975 +
1976 +#include <linux/mm.h>
1977 +
1978 +/* [pg_dat][zone][page_num] */
1979 +typedef unsigned long **** dyn_pageflags_t;
1980 +
1981 +#if BITS_PER_LONG == 32
1982 +#define UL_SHIFT 5
1983 +#else
1984 +#if BITS_PER_LONG == 64
1985 +#define UL_SHIFT 6
1986 +#else
1987 +#error Bits per long not 32 or 64?
1988 +#endif
1989 +#endif
1990 +
1991 +#define BIT_NUM_MASK (sizeof(unsigned long) * 8 - 1)
1992 +#define PAGE_NUM_MASK (~((1 << (PAGE_SHIFT + 3)) - 1))
1993 +#define UL_NUM_MASK (~(BIT_NUM_MASK | PAGE_NUM_MASK))
1994 +
1995 +/*
1996 + * PAGENUMBER gives the index of the page within the zone.
1997 + * PAGEINDEX gives the index of the unsigned long within that page.
1998 + * PAGEBIT gives the index of the bit within the unsigned long.
1999 + */
2000 +#define BITS_PER_PAGE (PAGE_SIZE << 3)
2001 +#define PAGENUMBER(zone_offset) ((int) (zone_offset >> (PAGE_SHIFT + 3)))
2002 +#define PAGEINDEX(zone_offset) ((int) ((zone_offset & UL_NUM_MASK) >> UL_SHIFT))
2003 +#define PAGEBIT(zone_offset) ((int) (zone_offset & BIT_NUM_MASK))
2004 +
2005 +#define PAGE_UL_PTR(bitmap, node, zone_num, zone_pfn) \
2006 + ((bitmap[node][zone_num][PAGENUMBER(zone_pfn)])+PAGEINDEX(zone_pfn))
2007 +
2008 +#define BITMAP_FOR_EACH_SET(bitmap, counter) \
2009 + for (counter = get_next_bit_on(bitmap, max_pfn + 1); counter <= max_pfn; \
2010 + counter = get_next_bit_on(bitmap, counter))
2011 +
2012 +extern void clear_dyn_pageflags(dyn_pageflags_t pagemap);
2013 +extern int allocate_dyn_pageflags(dyn_pageflags_t *pagemap);
2014 +extern void free_dyn_pageflags(dyn_pageflags_t *pagemap);
2015 +extern unsigned long get_next_bit_on(dyn_pageflags_t bitmap, unsigned long counter);
2016 +
2017 +extern int test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page);
2018 +extern void set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page);
2019 +extern void clear_dynpageflag(dyn_pageflags_t *bitmap, struct page *page);
2020 +#endif
2021 +
2022 +/*
2023 + * With the above macros defined, you can do...
2024 + * #define PagePageset1(page) (test_dynpageflag(&pageset1_map, page))
2025 + * #define SetPagePageset1(page) (set_dynpageflag(&pageset1_map, page))
2026 + * #define ClearPagePageset1(page) (clear_dynpageflag(&pageset1_map, page))
2027 + */
2028 +
2029 diff -Naur linux-2.6.21-ck2/include/linux/freezer.h linux-2.6.21-magellan-r11/include/linux/freezer.h
2030 --- linux-2.6.21-ck2/include/linux/freezer.h 2007-04-26 05:08:32.000000000 +0200
2031 +++ linux-2.6.21-magellan-r11/include/linux/freezer.h 2007-08-17 15:57:25.000000000 +0200
2032 @@ -1,7 +1,10 @@
2033 -/* Freezer declarations */
2034 +#ifndef LINUX_FREEZER_H
2035 +#define LINUX_FREEZER_H
2036
2037 #include <linux/sched.h>
2038
2039 +/* Freezer declarations */
2040 +
2041 #ifdef CONFIG_PM
2042 /*
2043 * Check if a process has been frozen
2044 @@ -73,6 +76,18 @@
2045
2046 extern void thaw_some_processes(int all);
2047
2048 +extern int freezer_state;
2049 +#define FREEZER_OFF 0
2050 +#define FREEZER_USERSPACE_FROZEN 1
2051 +#define FREEZER_FULLY_ON 2
2052 +
2053 +static inline int freezer_is_on(void)
2054 +{
2055 + return (freezer_state == FREEZER_FULLY_ON);
2056 +}
2057 +
2058 +extern void thaw_kernel_threads(void);
2059 +
2060 #else
2061 static inline int frozen(struct task_struct *p) { return 0; }
2062 static inline int freezing(struct task_struct *p) { return 0; }
2063 @@ -85,6 +100,9 @@
2064 static inline void thaw_processes(void) {}
2065
2066 static inline int try_to_freeze(void) { return 0; }
2067 +static inline int freezer_is_on(void) { return 0; }
2068 +static inline void thaw_kernel_threads(void) { }
2069
2070
2071 #endif
2072 +#endif
2073 diff -Naur linux-2.6.21-ck2/include/linux/kernel.h linux-2.6.21-magellan-r11/include/linux/kernel.h
2074 --- linux-2.6.21-ck2/include/linux/kernel.h 2007-04-26 05:08:32.000000000 +0200
2075 +++ linux-2.6.21-magellan-r11/include/linux/kernel.h 2007-08-17 15:57:25.000000000 +0200
2076 @@ -113,6 +113,8 @@
2077 __attribute__ ((format (printf, 2, 0)));
2078 extern int snprintf(char * buf, size_t size, const char * fmt, ...)
2079 __attribute__ ((format (printf, 3, 4)));
2080 +extern int snprintf_used(char *buffer, int buffer_size,
2081 + const char *fmt, ...);
2082 extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
2083 __attribute__ ((format (printf, 3, 0)));
2084 extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
2085 diff -Naur linux-2.6.21-ck2/include/linux/netlink.h linux-2.6.21-magellan-r11/include/linux/netlink.h
2086 --- linux-2.6.21-ck2/include/linux/netlink.h 2007-04-26 05:08:32.000000000 +0200
2087 +++ linux-2.6.21-magellan-r11/include/linux/netlink.h 2007-08-17 15:57:25.000000000 +0200
2088 @@ -24,6 +24,8 @@
2089 /* leave room for NETLINK_DM (DM Events) */
2090 #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
2091 #define NETLINK_ECRYPTFS 19
2092 +#define NETLINK_SUSPEND2_USERUI 20 /* For suspend2's userui */
2093 +#define NETLINK_SUSPEND2_USM 21 /* For suspend2's userspace storage manager */
2094
2095 #define MAX_LINKS 32
2096
2097 diff -Naur linux-2.6.21-ck2/include/linux/suspend.h linux-2.6.21-magellan-r11/include/linux/suspend.h
2098 --- linux-2.6.21-ck2/include/linux/suspend.h 2007-04-26 05:08:32.000000000 +0200
2099 +++ linux-2.6.21-magellan-r11/include/linux/suspend.h 2007-08-17 15:57:25.000000000 +0200
2100 @@ -27,14 +27,9 @@
2101 /* kernel/power/swsusp.c */
2102 extern int software_suspend(void);
2103
2104 -#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
2105 extern int pm_prepare_console(void);
2106 extern void pm_restore_console(void);
2107 #else
2108 -static inline int pm_prepare_console(void) { return 0; }
2109 -static inline void pm_restore_console(void) {}
2110 -#endif /* defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) */
2111 -#else
2112 static inline int software_suspend(void)
2113 {
2114 printk("Warning: fake suspend called\n");
2115 @@ -45,8 +40,6 @@
2116 void save_processor_state(void);
2117 void restore_processor_state(void);
2118 struct saved_context;
2119 -void __save_processor_state(struct saved_context *ctxt);
2120 -void __restore_processor_state(struct saved_context *ctxt);
2121 unsigned long get_safe_page(gfp_t gfp_mask);
2122
2123 /*
2124 @@ -55,4 +48,81 @@
2125 */
2126 #define PAGES_FOR_IO 1024
2127
2128 +enum {
2129 + SUSPEND_CAN_SUSPEND,
2130 + SUSPEND_CAN_RESUME,
2131 + SUSPEND_RUNNING,
2132 + SUSPEND_RESUME_DEVICE_OK,
2133 + SUSPEND_NORESUME_SPECIFIED,
2134 + SUSPEND_SANITY_CHECK_PROMPT,
2135 + SUSPEND_PAGESET2_NOT_LOADED,
2136 + SUSPEND_CONTINUE_REQ,
2137 + SUSPEND_RESUMED_BEFORE,
2138 + SUSPEND_RESUME_NOT_DONE,
2139 + SUSPEND_BOOT_TIME,
2140 + SUSPEND_NOW_RESUMING,
2141 + SUSPEND_IGNORE_LOGLEVEL,
2142 + SUSPEND_TRYING_TO_RESUME,
2143 + SUSPEND_TRY_RESUME_RD,
2144 + SUSPEND_LOADING_ALT_IMAGE,
2145 + SUSPEND_STOP_RESUME,
2146 + SUSPEND_IO_STOPPED,
2147 +};
2148 +
2149 +#ifdef CONFIG_SUSPEND2
2150 +
2151 +/* Used in init dir files */
2152 +extern unsigned long suspend_state;
2153 +#define set_suspend_state(bit) (set_bit(bit, &suspend_state))
2154 +#define clear_suspend_state(bit) (clear_bit(bit, &suspend_state))
2155 +#define test_suspend_state(bit) (test_bit(bit, &suspend_state))
2156 +extern int suspend2_running;
2157 +
2158 +#else /* !CONFIG_SUSPEND2 */
2159 +
2160 +#define suspend_state (0)
2161 +#define set_suspend_state(bit) do { } while(0)
2162 +#define clear_suspend_state(bit) do { } while (0)
2163 +#define test_suspend_state(bit) (0)
2164 +#define suspend2_running (0)
2165 +#endif /* CONFIG_SUSPEND2 */
2166 +
2167 +#ifdef CONFIG_SUSPEND_SHARED
2168 +#ifdef CONFIG_SUSPEND2
2169 +extern void suspend2_try_resume(void);
2170 +#else
2171 +#define suspend2_try_resume() do { } while(0)
2172 +#endif
2173 +
2174 +extern int resume_attempted;
2175 +
2176 +#ifdef CONFIG_SOFTWARE_SUSPEND
2177 +extern int software_resume(void);
2178 +#else
2179 +static inline int software_resume(void)
2180 +{
2181 + resume_attempted = 1;
2182 + suspend2_try_resume();
2183 + return 0;
2184 +}
2185 +#endif
2186 +
2187 +static inline void check_resume_attempted(void)
2188 +{
2189 + if (resume_attempted)
2190 + return;
2191 +
2192 + software_resume();
2193 +}
2194 +#else
2195 +#define check_resume_attempted() do { } while(0)
2196 +#define resume_attempted (0)
2197 +#endif
2198 +
2199 +#ifdef CONFIG_PRINTK_NOSAVE
2200 +#define POSS_NOSAVE __nosavedata
2201 +#else
2202 +#define POSS_NOSAVE
2203 +#endif
2204 +
2205 #endif /* _LINUX_SWSUSP_H */
2206 diff -Naur linux-2.6.21-ck2/include/linux/swap.h linux-2.6.21-magellan-r11/include/linux/swap.h
2207 --- linux-2.6.21-ck2/include/linux/swap.h 2007-08-17 15:48:42.000000000 +0200
2208 +++ linux-2.6.21-magellan-r11/include/linux/swap.h 2007-08-17 16:00:10.000000000 +0200
2209 @@ -192,6 +192,7 @@
2210 extern unsigned long try_to_free_pages(struct zone **, gfp_t,
2211 struct task_struct *p);
2212 extern unsigned long shrink_all_memory(unsigned long nr_pages);
2213 +extern void shrink_one_zone(struct zone *zone, int desired_size);
2214 extern int vm_mapped;
2215 extern int vm_hardmaplimit;
2216 extern int remove_mapping(struct address_space *mapping, struct page *page);
2217 @@ -372,5 +373,10 @@
2218 #define disable_swap_token() do { } while(0)
2219
2220 #endif /* CONFIG_SWAP */
2221 +
2222 +/* For Suspend2 - unlink LRU pages while saving separately */
2223 +void unlink_lru_lists(void);
2224 +void relink_lru_lists(void);
2225 +
2226 #endif /* __KERNEL__*/
2227 #endif /* _LINUX_SWAP_H */
2228 diff -Naur linux-2.6.21-ck2/include/linux/time.h linux-2.6.21-magellan-r11/include/linux/time.h
2229 --- linux-2.6.21-ck2/include/linux/time.h 2007-04-26 05:08:32.000000000 +0200
2230 +++ linux-2.6.21-magellan-r11/include/linux/time.h 2007-08-17 15:57:25.000000000 +0200
2231 @@ -224,4 +224,7 @@
2232 */
2233 #define TIMER_ABSTIME 0x01
2234
2235 +extern void save_avenrun(void);
2236 +extern void restore_avenrun(void);
2237 +
2238 #endif
2239 diff -Naur linux-2.6.21-ck2/init/do_mounts.c linux-2.6.21-magellan-r11/init/do_mounts.c
2240 --- linux-2.6.21-ck2/init/do_mounts.c 2007-04-26 05:08:32.000000000 +0200
2241 +++ linux-2.6.21-magellan-r11/init/do_mounts.c 2007-08-17 15:57:25.000000000 +0200
2242 @@ -139,11 +139,16 @@
2243 char s[32];
2244 char *p;
2245 dev_t res = 0;
2246 - int part;
2247 + int part, mount_result;
2248
2249 #ifdef CONFIG_SYSFS
2250 int mkdir_err = sys_mkdir("/sys", 0700);
2251 - if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
2252 + /*
2253 + * When changing resume2 parameter for Software Suspend, sysfs may
2254 + * already be mounted.
2255 + */
2256 + mount_result = sys_mount("sysfs", "/sys", "sysfs", 0, NULL);
2257 + if (mount_result < 0 && mount_result != -EBUSY)
2258 goto out;
2259 #endif
2260
2261 @@ -195,7 +200,8 @@
2262 res = try_name(s, part);
2263 done:
2264 #ifdef CONFIG_SYSFS
2265 - sys_umount("/sys", 0);
2266 + if (mount_result >= 0)
2267 + sys_umount("/sys", 0);
2268 out:
2269 if (!mkdir_err)
2270 sys_rmdir("/sys");
2271 @@ -434,12 +440,27 @@
2272
2273 is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
2274
2275 + /* Suspend2:
2276 + * By this point, suspend_early_init has been called to initialise our
2277 + * sysfs interface. If modules are built in, they have registered (all
2278 + * of the above via initcalls).
2279 + *
2280 + * We have not yet looked to see if an image exists, however. If we
2281 + * have an initrd, it is expected that the user will have set it up
2282 + * to echo > /sys/power/suspend2/do_resume and thus initiate any
2283 + * resume. If they don't do that, we do it immediately after the initrd
2284 + * is finished (major issues if they mount filesystems rw from the
2285 + * initrd! - they are warned. If there's no usable initrd, we do our
2286 + * check next.
2287 + */
2288 if (initrd_load())
2289 goto out;
2290
2291 if (is_floppy && rd_doload && rd_load_disk(0))
2292 ROOT_DEV = Root_RAM0;
2293
2294 + check_resume_attempted();
2295 +
2296 mount_root();
2297 out:
2298 sys_mount(".", "/", NULL, MS_MOVE, NULL);
2299 diff -Naur linux-2.6.21-ck2/init/do_mounts_initrd.c linux-2.6.21-magellan-r11/init/do_mounts_initrd.c
2300 --- linux-2.6.21-ck2/init/do_mounts_initrd.c 2007-04-26 05:08:32.000000000 +0200
2301 +++ linux-2.6.21-magellan-r11/init/do_mounts_initrd.c 2007-08-17 15:57:25.000000000 +0200
2302 @@ -6,6 +6,7 @@
2303 #include <linux/romfs_fs.h>
2304 #include <linux/initrd.h>
2305 #include <linux/sched.h>
2306 +#include <linux/suspend.h>
2307 #include <linux/freezer.h>
2308
2309 #include "do_mounts.h"
2310 @@ -58,10 +59,18 @@
2311 current->flags |= PF_NOFREEZE;
2312 pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
2313 if (pid > 0) {
2314 - while (pid != sys_wait4(-1, NULL, 0, NULL))
2315 + while (pid != sys_wait4(-1, NULL, 0, NULL)) {
2316 yield();
2317 + try_to_freeze();
2318 + }
2319 }
2320
2321 + if (!resume_attempted)
2322 + printk(KERN_ERR "Suspend2: No attempt was made to resume from "
2323 + "any image that might exist.\n");
2324 + clear_suspend_state(SUSPEND_BOOT_TIME);
2325 + current->flags &= ~PF_NOFREEZE;
2326 +
2327 /* move initrd to rootfs' /old */
2328 sys_fchdir(old_fd);
2329 sys_mount("/", ".", NULL, MS_MOVE, NULL);
2330 diff -Naur linux-2.6.21-ck2/init/main.c linux-2.6.21-magellan-r11/init/main.c
2331 --- linux-2.6.21-ck2/init/main.c 2007-04-26 05:08:32.000000000 +0200
2332 +++ linux-2.6.21-magellan-r11/init/main.c 2007-08-17 15:57:25.000000000 +0200
2333 @@ -54,6 +54,7 @@
2334 #include <linux/lockdep.h>
2335 #include <linux/pid_namespace.h>
2336 #include <linux/device.h>
2337 +#include <linux/suspend.h>
2338
2339 #include <asm/io.h>
2340 #include <asm/bugs.h>
2341 @@ -804,7 +805,9 @@
2342
2343 /*
2344 * check if there is an early userspace init. If yes, let it do all
2345 - * the work
2346 + * the work. For suspend2, we assume that it will do the right thing
2347 + * with regard to trying to resume at the right place. When that
2348 + * happens, the BOOT_TIME flag will be cleared.
2349 */
2350
2351 if (!ramdisk_execute_command)
2352 diff -Naur linux-2.6.21-ck2/kernel/kmod.c linux-2.6.21-magellan-r11/kernel/kmod.c
2353 --- linux-2.6.21-ck2/kernel/kmod.c 2007-04-26 05:08:32.000000000 +0200
2354 +++ linux-2.6.21-magellan-r11/kernel/kmod.c 2007-08-17 15:57:25.000000000 +0200
2355 @@ -34,6 +34,7 @@
2356 #include <linux/kernel.h>
2357 #include <linux/init.h>
2358 #include <linux/resource.h>
2359 +#include <linux/freezer.h>
2360 #include <asm/uaccess.h>
2361
2362 extern int max_threads;
2363 @@ -338,6 +339,11 @@
2364 }
2365 sub_info.stdin = f;
2366
2367 + if (freezer_is_on()) {
2368 + printk(KERN_WARNING "Freezer is on. Refusing to start %s.\n", path);
2369 + return -EBUSY;
2370 + }
2371 +
2372 queue_work(khelper_wq, &sub_info.work);
2373 wait_for_completion(&done);
2374 return sub_info.retval;
2375 diff -Naur linux-2.6.21-ck2/kernel/power/Kconfig linux-2.6.21-magellan-r11/kernel/power/Kconfig
2376 --- linux-2.6.21-ck2/kernel/power/Kconfig 2007-04-26 05:08:32.000000000 +0200
2377 +++ linux-2.6.21-magellan-r11/kernel/power/Kconfig 2007-08-17 15:57:25.000000000 +0200
2378 @@ -48,6 +48,18 @@
2379 suspend/resume routines, but may itself lead to problems, for example
2380 if netconsole is used.
2381
2382 +config PRINTK_NOSAVE
2383 + depends on PM && PM_DEBUG
2384 + bool "Preserve printk data from boot kernel when resuming."
2385 + default n
2386 + ---help---
2387 + This option gives printk data and the associated variables the
2388 + attribute __nosave, which means that they will not be saved as
2389 + part of the image. The net effect is that after resuming, your
2390 + dmesg will show the messages from prior to the atomic restore,
2391 + instead of the messages from the resumed kernel. This may be
2392 + useful for debugging hibernation.
2393 +
2394 config PM_TRACE
2395 bool "Suspend/resume event tracing"
2396 depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
2397 @@ -162,3 +174,174 @@
2398 random kernel OOPSes or reboots that don't seem to be related to
2399 anything, try disabling/enabling this option (or disabling/enabling
2400 APM in your BIOS).
2401 +
2402 +menuconfig SUSPEND2_CORE
2403 + tristate "Suspend2"
2404 + depends on PM
2405 + select DYN_PAGEFLAGS
2406 + select HOTPLUG_CPU if SMP
2407 + default y
2408 + ---help---
2409 + Suspend2 is the 'new and improved' suspend support.
2410 +
2411 + See the Suspend2 home page (suspend2.net)
2412 + for FAQs, HOWTOs and other documentation.
2413 +
2414 + comment "Image Storage (you need at least one allocator)"
2415 + depends on SUSPEND2_CORE
2416 +
2417 + config SUSPEND2_FILE
2418 + tristate "File Allocator"
2419 + depends on SUSPEND2_CORE
2420 + default y
2421 + ---help---
2422 + This option enables support for storing an image in a
2423 + simple file. This should be possible, but we're still
2424 + testing it.
2425 +
2426 + config SUSPEND2_SWAP
2427 + tristate "Swap Allocator"
2428 + depends on SUSPEND2_CORE
2429 + default y
2430 + select SWAP
2431 + ---help---
2432 + This option enables support for storing an image in your
2433 + swap space.
2434 +
2435 + comment "General Options"
2436 + depends on SUSPEND2_CORE
2437 +
2438 + config SUSPEND2_CRYPTO
2439 + tristate "Compression support"
2440 + depends on SUSPEND2_CORE && CRYPTO
2441 + default y
2442 + ---help---
2443 + This option adds support for using cryptoapi compression
2444 + algorithms. Compression is particularly useful as
2445 + the LZF support that comes with the Suspend2 patch can double
2446 + your suspend and resume speed.
2447 +
2448 + You probably want this, so say Y here.
2449 +
2450 + comment "No compression support available without Cryptoapi support."
2451 + depends on SUSPEND2_CORE && !CRYPTO
2452 +
2453 + config SUSPEND2_USERUI
2454 + tristate "Userspace User Interface support"
2455 + depends on SUSPEND2_CORE && NET
2456 + default y
2457 + ---help---
2458 + This option enabled support for a userspace based user interface
2459 + to Suspend2, which allows you to have a nice display while suspending
2460 + and resuming, and also enables features such as pressing escape to
2461 + cancel a cycle or interactive debugging.
2462 +
2463 + config SUSPEND2_DEFAULT_RESUME2
2464 + string "Default resume device name"
2465 + depends on SUSPEND2_CORE
2466 + ---help---
2467 + You normally need to add a resume2= parameter to your lilo.conf or
2468 + equivalent. With this option properly set, the kernel has a value
2469 + to default. No damage will be done if the value is invalid.
2470 +
2471 + config SUSPEND2_KEEP_IMAGE
2472 + bool "Allow Keep Image Mode"
2473 + depends on SUSPEND2_CORE
2474 + ---help---
2475 + This option allows you to keep and image and reuse it. It is intended
2476 + __ONLY__ for use with systems where all filesystems are mounted read-
2477 + only (kiosks, for example). To use it, compile this option in and boot
2478 + normally. Set the KEEP_IMAGE flag in /sys/power/suspend2 and suspend.
2479 + When you resume, the image will not be removed. You will be unable to turn
2480 + off swap partitions (assuming you are using the swap allocator), but future
2481 + suspends simply do a power-down. The image can be updated using the
2482 + kernel command line parameter suspend_act= to turn off the keep image
2483 + bit. Keep image mode is a little less user friendly on purpose - it
2484 + should not be used without thought!
2485 +
2486 + config SUSPEND2_REPLACE_SWSUSP
2487 + bool "Replace swsusp by default"
2488 + default y
2489 + depends on SUSPEND2_CORE
2490 + ---help---
2491 + Suspend2 can replace swsusp. This option makes that the default state,
2492 + requiring you to echo 0 > /sys/power/suspend2/replace_swsusp if you want
2493 + to use the vanilla kernel functionality. Note that your initrd/ramfs will
2494 + need to do this before trying to resume, too.
2495 + With overriding swsusp enabled, Suspend2 will use both the resume= and
2496 + noresume commandline options _and_ the resume2= and noresume2 ones (for
2497 + compatibility). resume= takes precedence over resume2=. Echoing disk
2498 + to /sys/power/state will start a Suspend2 cycle. If resume= doesn't
2499 + specify an allocator and both the swap and file allocators are compiled in,
2500 + the swap allocator will be used by default.
2501 +
2502 + config SUSPEND2_CLUSTER
2503 + tristate "Cluster support"
2504 + default n
2505 + depends on SUSPEND2_CORE && NET && BROKEN
2506 + ---help---
2507 + Support for linking multiple machines in a cluster so that they suspend
2508 + and resume together.
2509 +
2510 + config SUSPEND2_DEFAULT_CLUSTER_MASTER
2511 + string "Default cluster master address/port"
2512 + depends on SUSPEND2_CLUSTER
2513 + ---help---
2514 + If this machine will be the master, simply enter a port on which to
2515 + listen for slaves.
2516 + If this machine will be a slave, enter the ip address and port on
2517 + which the master listens with a colon separating them.
2518 + If no value is set here, cluster support will be disabled by default.
2519 +
2520 + config SUSPEND2_CHECKSUM
2521 + bool "Checksum pageset2"
2522 + depends on SUSPEND2_CORE
2523 + select CRYPTO
2524 + select CRYPTO_ALGAPI
2525 + select CRYPTO_MD5
2526 + ---help---
2527 + Adds support for checksumming pageset2 pages, to ensure you really get an
2528 + atomic copy. Should not normally be needed, but here for verification and
2529 + diagnostic purposes.
2530 +
2531 +config SUSPEND_SHARED
2532 + bool
2533 + depends on SUSPEND2_CORE || SOFTWARE_SUSPEND
2534 + default y
2535 +
2536 +config SUSPEND2_USERUI_EXPORTS
2537 + bool
2538 + depends on SUSPEND2_USERUI=m
2539 + default y
2540 +
2541 +config SUSPEND2_SWAP_EXPORTS
2542 + bool
2543 + depends on SUSPEND2_SWAP=m
2544 + default y
2545 +
2546 +config SUSPEND2_FILE_EXPORTS
2547 + bool
2548 + depends on SUSPEND2_FILE=m
2549 + default y
2550 +
2551 +config SUSPEND2_CRYPTO_EXPORTS
2552 + bool
2553 + depends on SUSPEND2_CRYPTO=m
2554 + default y
2555 +
2556 +config SUSPEND2_CORE_EXPORTS
2557 + bool
2558 + depends on SUSPEND2_CORE=m
2559 + default y
2560 +
2561 +config SUSPEND2_EXPORTS
2562 + bool
2563 + depends on SUSPEND2_SWAP_EXPORTS || SUSPEND2_FILE_EXPORTS || \
2564 + SUSPEND2_CRYPTO_EXPORTS || SUSPEND2_CLUSTER=m || \
2565 + SUSPEND2_USERUI_EXPORTS
2566 + default y
2567 +
2568 +config SUSPEND2
2569 + bool
2570 + depends on SUSPEND2_CORE!=n
2571 + default y
2572 diff -Naur linux-2.6.21-ck2/kernel/power/Makefile linux-2.6.21-magellan-r11/kernel/power/Makefile
2573 --- linux-2.6.21-ck2/kernel/power/Makefile 2007-04-26 05:08:32.000000000 +0200
2574 +++ linux-2.6.21-magellan-r11/kernel/power/Makefile 2007-08-17 15:57:25.000000000 +0200
2575 @@ -5,6 +5,32 @@
2576
2577 obj-y := main.o process.o console.o
2578 obj-$(CONFIG_PM_LEGACY) += pm.o
2579 -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o snapshot.o swap.o user.o
2580 +obj-$(CONFIG_SUSPEND_SHARED) += snapshot.o
2581 +
2582 +suspend_core-objs := modules.o sysfs.o suspend.o \
2583 + io.o pagedir.o prepare_image.o \
2584 + extent.o pageflags.o ui.o \
2585 + power_off.o atomic_copy.o
2586 +
2587 +obj-$(CONFIG_SUSPEND2) += suspend2_builtin.o
2588 +
2589 +ifdef CONFIG_SUSPEND2_CHECKSUM
2590 +suspend_core-objs += checksum.o
2591 +endif
2592 +
2593 +ifdef CONFIG_NET
2594 +suspend_core-objs += storage.o netlink.o
2595 +endif
2596 +
2597 +obj-$(CONFIG_SUSPEND2_CORE) += suspend_core.o
2598 +obj-$(CONFIG_SUSPEND2_CRYPTO) += suspend_compress.o
2599 +
2600 +obj-$(CONFIG_SUSPEND2_SWAP) += suspend_block_io.o suspend_swap.o
2601 +obj-$(CONFIG_SUSPEND2_FILE) += suspend_block_io.o suspend_file.o
2602 +obj-$(CONFIG_SUSPEND2_CLUSTER) += cluster.o
2603 +
2604 +obj-$(CONFIG_SUSPEND2_USERUI) += suspend_userui.o
2605 +
2606 +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o swap.o user.o
2607
2608 obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
2609 diff -Naur linux-2.6.21-ck2/kernel/power/atomic_copy.c linux-2.6.21-magellan-r11/kernel/power/atomic_copy.c
2610 --- linux-2.6.21-ck2/kernel/power/atomic_copy.c 1970-01-01 01:00:00.000000000 +0100
2611 +++ linux-2.6.21-magellan-r11/kernel/power/atomic_copy.c 2007-08-17 15:57:25.000000000 +0200
2612 @@ -0,0 +1,423 @@
2613 +/*
2614 + * kernel/power/atomic_copy.c
2615 + *
2616 + * Copyright 2004-2007 Nigel Cunningham (nigel at suspend2 net)
2617 + * Copyright (C) 2006 Red Hat, inc.
2618 + *
2619 + * Distributed under GPLv2.
2620 + *
2621 + * Routines for doing the atomic save/restore.
2622 + */
2623 +
2624 +#include <linux/suspend.h>
2625 +#include <linux/highmem.h>
2626 +#include <linux/cpu.h>
2627 +#include <linux/freezer.h>
2628 +#include <linux/console.h>
2629 +#include "suspend.h"
2630 +#include "storage.h"
2631 +#include "power_off.h"
2632 +#include "ui.h"
2633 +#include "power.h"
2634 +#include "io.h"
2635 +#include "prepare_image.h"
2636 +#include "pageflags.h"
2637 +#include "checksum.h"
2638 +#include "suspend2_builtin.h"
2639 +
2640 +int extra_pd1_pages_used;
2641 +
2642 +/*
2643 + * Highmem related functions (x86 only).
2644 + */
2645 +
2646 +#ifdef CONFIG_HIGHMEM
2647 +
2648 +/**
2649 + * copyback_high: Restore highmem pages.
2650 + *
2651 + * Highmem data and pbe lists are/can be stored in highmem.
2652 + * The format is slightly different to the lowmem pbe lists
2653 + * used for the assembly code: the last pbe in each page is
2654 + * a struct page * instead of struct pbe *, pointing to the
2655 + * next page where pbes are stored (or NULL if happens to be
2656 + * the end of the list). Since we don't want to generate
2657 + * unnecessary deltas against swsusp code, we use a cast
2658 + * instead of a union.
2659 + **/
2660 +
2661 +static void copyback_high(void)
2662 +{
2663 + struct page * pbe_page = (struct page *) restore_highmem_pblist;
2664 + struct pbe *this_pbe, *first_pbe;
2665 + unsigned long *origpage, *copypage;
2666 + int pbe_index = 1;
2667 +
2668 + if (!pbe_page)
2669 + return;
2670 +
2671 + this_pbe = (struct pbe *) kmap_atomic(pbe_page, KM_BOUNCE_READ);
2672 + first_pbe = this_pbe;
2673 +
2674 + while (this_pbe) {
2675 + int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
2676 +
2677 + origpage = kmap_atomic((struct page *) this_pbe->orig_address,
2678 + KM_BIO_DST_IRQ);
2679 + copypage = kmap_atomic((struct page *) this_pbe->address,
2680 + KM_BIO_SRC_IRQ);
2681 +
2682 + while (loop >= 0) {
2683 + *(origpage + loop) = *(copypage + loop);
2684 + loop--;
2685 + }
2686 +
2687 + kunmap_atomic(origpage, KM_BIO_DST_IRQ);
2688 + kunmap_atomic(copypage, KM_BIO_SRC_IRQ);
2689 +
2690 + if (!this_pbe->next)
2691 + break;
2692 +
2693 + if (pbe_index < PBES_PER_PAGE) {
2694 + this_pbe++;
2695 + pbe_index++;
2696 + } else {
2697 + pbe_page = (struct page *) this_pbe->next;
2698 + kunmap_atomic(first_pbe, KM_BOUNCE_READ);
2699 + if (!pbe_page)
2700 + return;
2701 + this_pbe = (struct pbe *) kmap_atomic(pbe_page,
2702 + KM_BOUNCE_READ);
2703 + first_pbe = this_pbe;
2704 + pbe_index = 1;
2705 + }
2706 + }
2707 + kunmap_atomic(first_pbe, KM_BOUNCE_READ);
2708 +}
2709 +
2710 +#else /* CONFIG_HIGHMEM */
2711 +void copyback_high(void) { }
2712 +#endif
2713 +
2714 +/**
2715 + * free_pbe_list: Free page backup entries used by the atomic copy code.
2716 + *
2717 + * Normally, this function isn't used. If, however, we need to abort before
2718 + * doing the atomic copy, we use this to free the pbes previously allocated.
2719 + **/
2720 +static void free_pbe_list(struct pbe **list, int highmem)
2721 +{
2722 + while(*list) {
2723 + int i;
2724 + struct pbe *free_pbe, *next_page = NULL;
2725 + struct page *page;
2726 +
2727 + if (highmem) {
2728 + page = (struct page *) *list;
2729 + free_pbe = (struct pbe *) kmap(page);
2730 + } else {
2731 + page = virt_to_page(*list);
2732 + free_pbe = *list;
2733 + }
2734 +
2735 + for (i = 0; i < PBES_PER_PAGE; i++) {
2736 + if (!free_pbe)
2737 + break;
2738 + if (highmem)
2739 + __free_page(free_pbe->address);
2740 + else
2741 + free_page((unsigned long) free_pbe->address);
2742 + free_pbe = free_pbe->next;
2743 + }
2744 +
2745 + if (highmem) {
2746 + if (free_pbe)
2747 + next_page = free_pbe;
2748 + kunmap(page);
2749 + } else {
2750 + if (free_pbe)
2751 + next_page = free_pbe;
2752 + }
2753 +
2754 + __free_page(page);
2755 + *list = (struct pbe *) next_page;
2756 + };
2757 +}
2758 +
2759 +/**
2760 + * copyback_post: Post atomic-restore actions.
2761 + *
2762 + * After doing the atomic restore, we have a few more things to do:
2763 + * 1) We want to retain some values across the restore, so we now copy
2764 + * these from the nosave variables to the normal ones.
2765 + * 2) Set the status flags.
2766 + * 3) Resume devices.
2767 + * 4) Tell userui so it can redraw & restore settings.
2768 + * 5) Reread the page cache.
2769 + **/
2770 +
2771 +void copyback_post(void)
2772 +{
2773 + int loop;
2774 +
2775 + suspend_action = suspend2_nosave_state1;
2776 + suspend_debug_state = suspend2_nosave_state2;
2777 + console_loglevel = suspend2_nosave_state3;
2778 +
2779 + for (loop = 0; loop < 4; loop++)
2780 + suspend_io_time[loop/2][loop%2] =
2781 + suspend2_nosave_io_speed[loop/2][loop%2];
2782 +
2783 + set_suspend_state(SUSPEND_NOW_RESUMING);
2784 + set_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
2785 +
2786 + if (suspend_activate_storage(1))
2787 + panic("Failed to reactivate our storage.");
2788 +
2789 + suspend_ui_post_atomic_restore();
2790 +
2791 + suspend_cond_pause(1, "About to reload secondary pagedir.");
2792 +
2793 + if (read_pageset2(0))
2794 + panic("Unable to successfully reread the page cache.");
2795 +
2796 + clear_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
2797 +}
2798 +
2799 +/**
2800 + * suspend_copy_pageset1: Do the atomic copy of pageset1.
2801 + *
2802 + * Make the atomic copy of pageset1. We can't use copy_page (as we once did)
2803 + * because we can't be sure what side effects it has. On my old Duron, with
2804 + * 3DNOW, kernel_fpu_begin increments preempt count, making our preempt
2805 + * count at resume time 4 instead of 3.
2806 + *
2807 + * We don't want to call kmap_atomic unconditionally because it has the side
2808 + * effect of incrementing the preempt count, which will leave it one too high
2809 + * post resume (the page containing the preempt count will be copied after
2810 + * its incremented. This is essentially the same problem.
2811 + **/
2812 +
2813 +void suspend_copy_pageset1(void)
2814 +{
2815 + int i;
2816 + unsigned long source_index, dest_index;
2817 +
2818 + source_index = get_next_bit_on(pageset1_map, max_pfn + 1);
2819 + dest_index = get_next_bit_on(pageset1_copy_map, max_pfn + 1);
2820 +
2821 + for (i = 0; i < pagedir1.size; i++) {
2822 + unsigned long *origvirt, *copyvirt;
2823 + struct page *origpage, *copypage;
2824 + int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
2825 +
2826 + origpage = pfn_to_page(source_index);
2827 + copypage = pfn_to_page(dest_index);
2828 +
2829 + origvirt = PageHighMem(origpage) ?
2830 + kmap_atomic(origpage, KM_USER0) :
2831 + page_address(origpage);
2832 +
2833 + copyvirt = PageHighMem(copypage) ?
2834 + kmap_atomic(copypage, KM_USER1) :
2835 + page_address(copypage);
2836 +
2837 + while (loop >= 0) {
2838 + *(copyvirt + loop) = *(origvirt + loop);
2839 + loop--;
2840 + }
2841 +
2842 + if (PageHighMem(origpage))
2843 + kunmap_atomic(origvirt, KM_USER0);
2844 + else if (suspend2_faulted) {
2845 + printk("%p (%lu) being unmapped after faulting during atomic copy.\n", origpage, source_index);
2846 + kernel_map_pages(origpage, 1, 0);
2847 + clear_suspend2_fault();
2848 + }
2849 +
2850 + if (PageHighMem(copypage))
2851 + kunmap_atomic(copyvirt, KM_USER1);
2852 +
2853 + source_index = get_next_bit_on(pageset1_map, source_index);
2854 + dest_index = get_next_bit_on(pageset1_copy_map, dest_index);
2855 + }
2856 +}
2857 +
2858 +/**
2859 + * __suspend_post_context_save: Steps after saving the cpu context.
2860 + *
2861 + * Steps taken after saving the CPU state to make the actual
2862 + * atomic copy.
2863 + *
2864 + * Called from swsusp_save in snapshot.c via suspend_post_context_save.
2865 + **/
2866 +
2867 +int __suspend_post_context_save(void)
2868 +{
2869 + int old_ps1_size = pagedir1.size;
2870 +
2871 + calculate_check_checksums(1);
2872 +
2873 + free_checksum_pages();
2874 +
2875 + suspend_recalculate_image_contents(1);
2876 +
2877 + extra_pd1_pages_used = pagedir1.size - old_ps1_size;
2878 +
2879 + if (extra_pd1_pages_used > extra_pd1_pages_allowance) {
2880 + printk("Pageset1 has grown by %d pages. "
2881 + "extra_pages_allowance is currently only %d.\n",
2882 + pagedir1.size - old_ps1_size,
2883 + extra_pd1_pages_allowance);
2884 + set_result_state(SUSPEND_ABORTED);
2885 + set_result_state(SUSPEND_EXTRA_PAGES_ALLOW_TOO_SMALL);
2886 + return -1;
2887 + }
2888 +
2889 + if (!test_action_state(SUSPEND_TEST_FILTER_SPEED) &&
2890 + !test_action_state(SUSPEND_TEST_BIO))
2891 + suspend_copy_pageset1();
2892 +
2893 + return 0;
2894 +}
2895 +
2896 +/**
2897 + * suspend2_suspend: High level code for doing the atomic copy.
2898 + *
2899 + * High-level code which prepares to do the atomic copy. Loosely based
2900 + * on the swsusp version, but with the following twists:
2901 + * - We set suspend2_running so the swsusp code uses our code paths.
2902 + * - We give better feedback regarding what goes wrong if there is a problem.
2903 + * - We use an extra function to call the assembly, just in case this code
2904 + * is in a module (return address).
2905 + **/
2906 +
2907 +int suspend2_suspend(void)
2908 +{
2909 + int error;
2910 +
2911 + suspend2_running = 1; /* For the swsusp code we use :< */
2912 +
2913 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2914 + pm_prepare_console();
2915 +
2916 + if ((error = arch_prepare_suspend()))
2917 + goto err_out;
2918 +
2919 + local_irq_disable();
2920 +
2921 + /* At this point, device_suspend() has been called, but *not*
2922 + * device_power_down(). We *must* device_power_down() now.
2923 + * Otherwise, drivers for some devices (e.g. interrupt controllers)
2924 + * become desynchronized with the actual state of the hardware
2925 + * at resume time, and evil weirdness ensues.
2926 + */
2927 +
2928 + if ((error = device_power_down(PMSG_FREEZE))) {
2929 + set_result_state(SUSPEND_DEVICE_REFUSED);
2930 + set_result_state(SUSPEND_ABORTED);
2931 + printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
2932 + goto enable_irqs;
2933 + }
2934 +
2935 + error = suspend2_lowlevel_builtin();
2936 +
2937 + if (!suspend2_in_suspend)
2938 + copyback_high();
2939 +
2940 + device_power_up();
2941 +enable_irqs:
2942 + local_irq_enable();
2943 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2944 + pm_restore_console();
2945 +err_out:
2946 + suspend2_running = 0;
2947 + return error;
2948 +}
2949 +
2950 +/**
2951 + * suspend_atomic_restore: Prepare to do the atomic restore.
2952 + *
2953 + * Get ready to do the atomic restore. This part gets us into the same
2954 + * state we are in prior to do calling do_suspend2_lowlevel while
2955 + * suspending: hot-unplugging secondary cpus and freeze processes,
2956 + * before starting the thread that will do the restore.
2957 + **/
2958 +
2959 +int suspend_atomic_restore(void)
2960 +{
2961 + int error, loop;
2962 +
2963 + suspend2_running = 1;
2964 +
2965 + suspend_prepare_status(DONT_CLEAR_BAR, "Prepare console");
2966 +
2967 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
2968 + pm_prepare_console();
2969 +
2970 + suspend_prepare_status(DONT_CLEAR_BAR, "Device suspend.");
2971 +
2972 + suspend_console();
2973 + if ((error = device_suspend(PMSG_PRETHAW))) {
2974 + printk("Some devices failed to suspend\n");
2975 + goto device_resume;
2976 + }
2977 +
2978 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG)) {
2979 + suspend_prepare_status(DONT_CLEAR_BAR, "Disable nonboot cpus.");
2980 + if (disable_nonboot_cpus()) {
2981 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
2982 + set_result_state(SUSPEND_ABORTED);
2983 + goto device_resume;
2984 + }
2985 + }
2986 +
2987 + suspend_prepare_status(DONT_CLEAR_BAR, "Atomic restore preparation");
2988 +
2989 + suspend2_nosave_state1 = suspend_action;
2990 + suspend2_nosave_state2 = suspend_debug_state;
2991 + suspend2_nosave_state3 = console_loglevel;
2992 +
2993 + for (loop = 0; loop < 4; loop++)
2994 + suspend2_nosave_io_speed[loop/2][loop%2] =
2995 + suspend_io_time[loop/2][loop%2];
2996 + memcpy(suspend2_nosave_commandline, saved_command_line, COMMAND_LINE_SIZE);
2997 +
2998 + mb();
2999 +
3000 + local_irq_disable();
3001 +
3002 + if (device_power_down(PMSG_FREEZE)) {
3003 + printk(KERN_ERR "Some devices failed to power down. Very bad.\n");
3004 + goto device_power_up;
3005 + }
3006 +
3007 + /* We'll ignore saved state, but this gets preempt count (etc) right */
3008 + save_processor_state();
3009 +
3010 + error = swsusp_arch_resume();
3011 + /*
3012 + * Code below is only ever reached in case of failure. Otherwise
3013 + * execution continues at place where swsusp_arch_suspend was called.
3014 + *
3015 + * We don't know whether it's safe to continue (this shouldn't happen),
3016 + * so lets err on the side of caution.
3017 + */
3018 + BUG();
3019 +
3020 +device_power_up:
3021 + device_power_up();
3022 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
3023 + enable_nonboot_cpus();
3024 +device_resume:
3025 + device_resume();
3026 + resume_console();
3027 + free_pbe_list(&restore_pblist, 0);
3028 +#ifdef CONFIG_HIGHMEM
3029 + free_pbe_list(&restore_highmem_pblist, 1);
3030 +#endif
3031 + if (test_action_state(SUSPEND_PM_PREPARE_CONSOLE))
3032 + pm_restore_console();
3033 + suspend2_running = 0;
3034 + return 1;
3035 +}
3036 diff -Naur linux-2.6.21-ck2/kernel/power/block_io.h linux-2.6.21-magellan-r11/kernel/power/block_io.h
3037 --- linux-2.6.21-ck2/kernel/power/block_io.h 1970-01-01 01:00:00.000000000 +0100
3038 +++ linux-2.6.21-magellan-r11/kernel/power/block_io.h 2007-08-17 15:57:25.000000000 +0200
3039 @@ -0,0 +1,55 @@
3040 +/*
3041 + * kernel/power/block_io.h
3042 + *
3043 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
3044 + * Copyright (C) 2006 Red Hat, inc.
3045 + *
3046 + * Distributed under GPLv2.
3047 + *
3048 + * This file contains declarations for functions exported from
3049 + * block_io.c, which contains low level io functions.
3050 + */
3051 +
3052 +#include <linux/buffer_head.h>
3053 +#include "extent.h"
3054 +
3055 +struct suspend_bdev_info {
3056 + struct block_device *bdev;
3057 + dev_t dev_t;
3058 + int bmap_shift;
3059 + int blocks_per_page;
3060 +};
3061 +
3062 +/*
3063 + * Our exported interface so the swapwriter and filewriter don't
3064 + * need these functions duplicated.
3065 + */
3066 +struct suspend_bio_ops {
3067 + int (*bdev_page_io) (int rw, struct block_device *bdev, long pos,
3068 + struct page *page);
3069 + void (*check_io_stats) (void);
3070 + void (*reset_io_stats) (void);
3071 + void (*finish_all_io) (void);
3072 + int (*forward_one_page) (void);
3073 + void (*set_extra_page_forward) (void);
3074 + void (*set_devinfo) (struct suspend_bdev_info *info);
3075 + int (*read_chunk) (unsigned long *index, struct page *buffer_page,
3076 + unsigned int *buf_size, int sync);
3077 + int (*write_chunk) (unsigned long index, struct page *buffer_page,
3078 + unsigned int buf_size);
3079 + void (*read_header_init) (void);
3080 + int (*rw_header_chunk) (int rw, struct suspend_module_ops *owner,
3081 + char *buffer, int buffer_size);
3082 + int (*write_header_chunk_finish) (void);
3083 + int (*rw_init) (int rw, int stream_number);
3084 + int (*rw_cleanup) (int rw);
3085 +};
3086 +
3087 +extern struct suspend_bio_ops suspend_bio_ops;
3088 +
3089 +extern char *suspend_writer_buffer;
3090 +extern int suspend_writer_buffer_posn;
3091 +extern int suspend_read_fd;
3092 +extern struct extent_iterate_saved_state suspend_writer_posn_save[3];
3093 +extern struct extent_iterate_state suspend_writer_posn;
3094 +extern int suspend_header_bytes_used;
3095 diff -Naur linux-2.6.21-ck2/kernel/power/checksum.c linux-2.6.21-magellan-r11/kernel/power/checksum.c
3096 --- linux-2.6.21-ck2/kernel/power/checksum.c 1970-01-01 01:00:00.000000000 +0100
3097 +++ linux-2.6.21-magellan-r11/kernel/power/checksum.c 2007-08-17 15:57:25.000000000 +0200
3098 @@ -0,0 +1,371 @@
3099 +/*
3100 + * kernel/power/checksum.c
3101 + *
3102 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3103 + * Copyright (C) 2006 Red Hat, inc.
3104 + *
3105 + * This file is released under the GPLv2.
3106 + *
3107 + * This file contains data checksum routines for suspend2,
3108 + * using cryptoapi. They are used to locate any modifications
3109 + * made to pageset 2 while we're saving it.
3110 + */
3111 +
3112 +#include <linux/suspend.h>
3113 +#include <linux/module.h>
3114 +#include <linux/highmem.h>
3115 +#include <linux/vmalloc.h>
3116 +#include <linux/crypto.h>
3117 +#include <linux/scatterlist.h>
3118 +
3119 +#include "suspend.h"
3120 +#include "modules.h"
3121 +#include "sysfs.h"
3122 +#include "io.h"
3123 +#include "pageflags.h"
3124 +#include "checksum.h"
3125 +#include "pagedir.h"
3126 +
3127 +static struct suspend_module_ops suspend_checksum_ops;
3128 +
3129 +/* Constant at the mo, but I might allow tuning later */
3130 +static char suspend_checksum_name[32] = "md5";
3131 +/* Bytes per checksum */
3132 +#define CHECKSUM_SIZE (128 / 8)
3133 +
3134 +#define CHECKSUMS_PER_PAGE ((PAGE_SIZE - sizeof(void *)) / CHECKSUM_SIZE)
3135 +
3136 +static struct crypto_hash *suspend_checksum_transform;
3137 +static struct hash_desc desc;
3138 +static int pages_allocated;
3139 +static unsigned long page_list;
3140 +
3141 +static int suspend_num_resaved = 0;
3142 +
3143 +#if 1
3144 +#define PRINTK(a, b...) do { } while(0)
3145 +#else
3146 +#define PRINTK(a, b...) do { printk(a, ##b); } while(0)
3147 +#endif
3148 +
3149 +/* ---- Local buffer management ---- */
3150 +
3151 +/*
3152 + * suspend_checksum_cleanup
3153 + *
3154 + * Frees memory allocated for our labours.
3155 + */
3156 +static void suspend_checksum_cleanup(int ending_cycle)
3157 +{
3158 + if (ending_cycle && suspend_checksum_transform) {
3159 + crypto_free_hash(suspend_checksum_transform);
3160 + suspend_checksum_transform = NULL;
3161 + desc.tfm = NULL;
3162 + }
3163 +}
3164 +
3165 +/*
3166 + * suspend_crypto_prepare
3167 + *
3168 + * Prepare to do some work by allocating buffers and transforms.
3169 + * Returns: Int: Zero. Even if we can't set up checksum, we still
3170 + * seek to suspend.
3171 + */
3172 +static int suspend_checksum_prepare(int starting_cycle)
3173 +{
3174 + if (!starting_cycle || !suspend_checksum_ops.enabled)
3175 + return 0;
3176 +
3177 + if (!*suspend_checksum_name) {
3178 + printk("Suspend2: No checksum algorithm name set.\n");
3179 + return 1;
3180 + }
3181 +
3182 + suspend_checksum_transform = crypto_alloc_hash(suspend_checksum_name, 0, 0);
3183 + if (IS_ERR(suspend_checksum_transform)) {
3184 + printk("Suspend2: Failed to initialise the %s checksum algorithm: %ld.\n",
3185 + suspend_checksum_name,
3186 + (long) suspend_checksum_transform);
3187 + suspend_checksum_transform = NULL;
3188 + return 1;
3189 + }
3190 +
3191 + desc.tfm = suspend_checksum_transform;
3192 + desc.flags = 0;
3193 +
3194 + return 0;
3195 +}
3196 +
3197 +static int suspend_print_task_if_using_page(struct task_struct *t, struct page *seeking)
3198 +{
3199 + struct vm_area_struct *vma;
3200 + struct mm_struct *mm;
3201 + int result = 0;
3202 +
3203 + mm = t->active_mm;
3204 +
3205 + if (!mm || !mm->mmap) return 0;
3206 +
3207 + /* Don't try to take the sem when processes are frozen,
3208 + * drivers are suspended and irqs are disabled. We're
3209 + * not racing with anything anyway. */
3210 + if (!irqs_disabled())
3211 + down_read(&mm->mmap_sem);
3212 +
3213 + for (vma = mm->mmap; vma; vma = vma->vm_next) {
3214 + if (vma->vm_flags & VM_PFNMAP)
3215 + continue;
3216 + if (vma->vm_start) {
3217 + unsigned long posn;
3218 + for (posn = vma->vm_start; posn < vma->vm_end;
3219 + posn += PAGE_SIZE) {
3220 + struct page *page =
3221 + follow_page(vma, posn, 0);
3222 + if (page == seeking) {
3223 + printk("%s(%d)", t->comm, t->pid);
3224 + result = 1;
3225 + goto out;
3226 + }
3227 + }
3228 + }
3229 + }
3230 +
3231 +out:
3232 + if (!irqs_disabled())
3233 + up_read(&mm->mmap_sem);
3234 +
3235 + return result;
3236 +}
3237 +
3238 +static void print_tasks_using_page(struct page *seeking)
3239 +{
3240 + struct task_struct *p;
3241 +
3242 + read_lock(&tasklist_lock);
3243 + for_each_process(p) {
3244 + if (suspend_print_task_if_using_page(p, seeking))
3245 + printk(" ");
3246 + }
3247 + read_unlock(&tasklist_lock);
3248 +}
3249 +
3250 +/*
3251 + * suspend_checksum_print_debug_stats
3252 + * @buffer: Pointer to a buffer into which the debug info will be printed.
3253 + * @size: Size of the buffer.
3254 + *
3255 + * Print information to be recorded for debugging purposes into a buffer.
3256 + * Returns: Number of characters written to the buffer.
3257 + */
3258 +
3259 +static int suspend_checksum_print_debug_stats(char *buffer, int size)
3260 +{
3261 + int len;
3262 +
3263 + if (!suspend_checksum_ops.enabled)
3264 + return snprintf_used(buffer, size,
3265 + "- Checksumming disabled.\n");
3266 +
3267 + len = snprintf_used(buffer, size, "- Checksum method is '%s'.\n",
3268 + suspend_checksum_name);
3269 + len+= snprintf_used(buffer + len, size - len,
3270 + " %d pages resaved in atomic copy.\n", suspend_num_resaved);
3271 + return len;
3272 +}
3273 +
3274 +static int suspend_checksum_storage_needed(void)
3275 +{
3276 + if (suspend_checksum_ops.enabled)
3277 + return strlen(suspend_checksum_name) + sizeof(int) + 1;
3278 + else
3279 + return 0;
3280 +}
3281 +
3282 +/*
3283 + * suspend_checksum_save_config_info
3284 + * @buffer: Pointer to a buffer of size PAGE_SIZE.
3285 + *
3286 + * Save informaton needed when reloading the image at resume time.
3287 + * Returns: Number of bytes used for saving our data.
3288 + */
3289 +static int suspend_checksum_save_config_info(char *buffer)
3290 +{
3291 + int namelen = strlen(suspend_checksum_name) + 1;
3292 + int total_len;
3293 +
3294 + *((unsigned int *) buffer) = namelen;
3295 + strncpy(buffer + sizeof(unsigned int), suspend_checksum_name,
3296 + namelen);
3297 + total_len = sizeof(unsigned int) + namelen;
3298 + return total_len;
3299 +}
3300 +
3301 +/* suspend_checksum_load_config_info
3302 + * @buffer: Pointer to the start of the data.
3303 + * @size: Number of bytes that were saved.
3304 + *
3305 + * Description: Reload information needed for dechecksuming the image at
3306 + * resume time.
3307 + */
3308 +static void suspend_checksum_load_config_info(char *buffer, int size)
3309 +{
3310 + int namelen;
3311 +
3312 + namelen = *((unsigned int *) (buffer));
3313 + strncpy(suspend_checksum_name, buffer + sizeof(unsigned int),
3314 + namelen);
3315 + return;
3316 +}
3317 +
3318 +/*
3319 + * Free Checksum Memory
3320 + */
3321 +
3322 +void free_checksum_pages(void)
3323 +{
3324 + PRINTK("Freeing %d checksum pages.\n", pages_allocated);
3325 + while (pages_allocated) {
3326 + unsigned long next = *((unsigned long *) page_list);
3327 + PRINTK("Page %3d is at %lx and points to %lx.\n", pages_allocated, page_list, next);
3328 + ClearPageNosave(virt_to_page(page_list));
3329 + free_page((unsigned long) page_list);
3330 + page_list = next;
3331 + pages_allocated--;
3332 + }
3333 +}
3334 +
3335 +/*
3336 + * Allocate Checksum Memory
3337 + */
3338 +
3339 +int allocate_checksum_pages(void)
3340 +{
3341 + int pages_needed = DIV_ROUND_UP(pagedir2.size, CHECKSUMS_PER_PAGE);
3342 +
3343 + if (!suspend_checksum_ops.enabled)
3344 + return 0;
3345 +
3346 + PRINTK("Need %d checksum pages for %ld pageset2 pages.\n", pages_needed, pagedir2.size);
3347 + while (pages_allocated < pages_needed) {
3348 + unsigned long *new_page =
3349 + (unsigned long *) get_zeroed_page(GFP_ATOMIC);
3350 + if (!new_page)
3351 + return -ENOMEM;
3352 + SetPageNosave(virt_to_page(new_page));
3353 + (*new_page) = page_list;
3354 + page_list = (unsigned long) new_page;
3355 + pages_allocated++;
3356 + PRINTK("Page %3d is at %lx and points to %lx.\n", pages_allocated, page_list, *((unsigned long *) page_list));
3357 + }
3358 +
3359 + return 0;
3360 +}
3361 +
3362 +#if 0
3363 +static void print_checksum(char *buf, int size)
3364 +{
3365 + int index;
3366 +
3367 + for (index = 0; index < size; index++)
3368 + printk("%x ", buf[index]);
3369 +
3370 + printk("\n");
3371 +}
3372 +#endif
3373 +
3374 +/*
3375 + * Calculate checksums
3376 + */
3377 +
3378 +void calculate_check_checksums(int check)
3379 +{
3380 + int pfn, index = 0;
3381 + unsigned long next_page, this_checksum = 0;
3382 + struct scatterlist sg[2];
3383 + char current_checksum[CHECKSUM_SIZE];
3384 +
3385 + if (!suspend_checksum_ops.enabled)
3386 + return;
3387 +
3388 + next_page = (unsigned long) page_list;
3389 +
3390 + if (check)
3391 + suspend_num_resaved = 0;
3392 +
3393 + BITMAP_FOR_EACH_SET(pageset2_map, pfn) {
3394 + int ret;
3395 + if (index % CHECKSUMS_PER_PAGE) {
3396 + this_checksum += CHECKSUM_SIZE;
3397 + } else {
3398 + this_checksum = next_page + sizeof(void *);
3399 + next_page = *((unsigned long *) next_page);
3400 + }
3401 + PRINTK("Put checksum for page %3d %p in %lx.\n", index, page_address(pfn_to_page(pfn)), this_checksum);
3402 + sg_set_buf(&sg[0], page_address(pfn_to_page(pfn)), PAGE_SIZE);
3403 + if (check) {
3404 + ret = crypto_hash_digest(&desc, sg,
3405 + PAGE_SIZE, current_checksum);
3406 + if (memcmp(current_checksum, (char *) this_checksum, CHECKSUM_SIZE)) {
3407 + SetPageResave(pfn_to_page(pfn));
3408 + printk("Page %d changed. Saving in atomic copy."
3409 + "Processes using it:", pfn);
3410 + print_tasks_using_page(pfn_to_page(pfn));
3411 + printk("\n");
3412 + suspend_num_resaved++;
3413 + if (test_action_state(SUSPEND_ABORT_ON_RESAVE_NEEDED))
3414 + set_result_state(SUSPEND_ABORTED);
3415 + }
3416 + } else
3417 + ret = crypto_hash_digest(&desc, sg,
3418 + PAGE_SIZE, (char *) this_checksum);
3419 + if (ret) {
3420 + printk("Digest failed. Returned %d.\n", ret);
3421 + return;
3422 + }
3423 + index++;
3424 + }
3425 +}
3426 +
3427 +static struct suspend_sysfs_data sysfs_params[] = {
3428 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
3429 + SYSFS_INT(&suspend_checksum_ops.enabled, 0, 1, 0)
3430 + },
3431 +
3432 + { SUSPEND2_ATTR("abort_if_resave_needed", SYSFS_RW),
3433 + SYSFS_BIT(&suspend_action, SUSPEND_ABORT_ON_RESAVE_NEEDED, 0)
3434 + }
3435 +};
3436 +
3437 +/*
3438 + * Ops structure.
3439 + */
3440 +static struct suspend_module_ops suspend_checksum_ops = {
3441 + .type = MISC_MODULE,
3442 + .name = "Checksumming",
3443 + .directory = "checksum",
3444 + .module = THIS_MODULE,
3445 + .initialise = suspend_checksum_prepare,
3446 + .cleanup = suspend_checksum_cleanup,
3447 + .print_debug_info = suspend_checksum_print_debug_stats,
3448 + .save_config_info = suspend_checksum_save_config_info,
3449 + .load_config_info = suspend_checksum_load_config_info,
3450 + .storage_needed = suspend_checksum_storage_needed,
3451 +
3452 + .sysfs_data = sysfs_params,
3453 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
3454 +};
3455 +
3456 +/* ---- Registration ---- */
3457 +int s2_checksum_init(void)
3458 +{
3459 + int result = suspend_register_module(&suspend_checksum_ops);
3460 +
3461 + /* Disabled by default */
3462 + suspend_checksum_ops.enabled = 0;
3463 + return result;
3464 +}
3465 +
3466 +void s2_checksum_exit(void)
3467 +{
3468 + suspend_unregister_module(&suspend_checksum_ops);
3469 +}
3470 diff -Naur linux-2.6.21-ck2/kernel/power/checksum.h linux-2.6.21-magellan-r11/kernel/power/checksum.h
3471 --- linux-2.6.21-ck2/kernel/power/checksum.h 1970-01-01 01:00:00.000000000 +0100
3472 +++ linux-2.6.21-magellan-r11/kernel/power/checksum.h 2007-08-17 15:57:25.000000000 +0200
3473 @@ -0,0 +1,27 @@
3474 +/*
3475 + * kernel/power/checksum.h
3476 + *
3477 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3478 + * Copyright (C) 2006 Red Hat, inc.
3479 + *
3480 + * This file is released under the GPLv2.
3481 + *
3482 + * This file contains data checksum routines for suspend2,
3483 + * using cryptoapi. They are used to locate any modifications
3484 + * made to pageset 2 while we're saving it.
3485 + */
3486 +
3487 +#if defined(CONFIG_SUSPEND2_CHECKSUM)
3488 +extern int s2_checksum_init(void);
3489 +extern void s2_checksum_exit(void);
3490 +void calculate_check_checksums(int check);
3491 +int allocate_checksum_pages(void);
3492 +void free_checksum_pages(void);
3493 +#else
3494 +static inline int s2_checksum_init(void) { return 0; }
3495 +static inline void s2_checksum_exit(void) { }
3496 +static inline void calculate_check_checksums(int check) { };
3497 +static inline int allocate_checksum_pages(void) { return 0; };
3498 +static inline void free_checksum_pages(void) { };
3499 +#endif
3500 +
3501 diff -Naur linux-2.6.21-ck2/kernel/power/cluster.c linux-2.6.21-magellan-r11/kernel/power/cluster.c
3502 --- linux-2.6.21-ck2/kernel/power/cluster.c 1970-01-01 01:00:00.000000000 +0100
3503 +++ linux-2.6.21-magellan-r11/kernel/power/cluster.c 2007-08-17 15:57:25.000000000 +0200
3504 @@ -0,0 +1,152 @@
3505 +/*
3506 + * kernel/power/cluster.c
3507 + *
3508 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3509 + *
3510 + * This file is released under the GPLv2.
3511 + *
3512 + * This file contains routines for cluster hibernation support.
3513 + *
3514 + */
3515 +
3516 +#include <linux/suspend.h>
3517 +#include <linux/module.h>
3518 +
3519 +#include "suspend.h"
3520 +#include "modules.h"
3521 +#include "sysfs.h"
3522 +#include "io.h"
3523 +
3524 +static char suspend_cluster_master[63] = CONFIG_SUSPEND2_DEFAULT_CLUSTER_MASTER;
3525 +
3526 +static struct suspend_module_ops suspend_cluster_ops;
3527 +
3528 +/* suspend_cluster_print_debug_stats
3529 + *
3530 + * Description: Print information to be recorded for debugging purposes into a
3531 + * buffer.
3532 + * Arguments: buffer: Pointer to a buffer into which the debug info will be
3533 + * printed.
3534 + * size: Size of the buffer.
3535 + * Returns: Number of characters written to the buffer.
3536 + */
3537 +static int suspend_cluster_print_debug_stats(char *buffer, int size)
3538 +{
3539 + int len;
3540 +
3541 + if (strlen(suspend_cluster_master))
3542 + len = snprintf_used(buffer, size, "- Cluster master is '%s'.\n",
3543 + suspend_cluster_master);
3544 + else
3545 + len = snprintf_used(buffer, size, "- Cluster support is disabled.\n");
3546 + return len;
3547 +}
3548 +
3549 +/* cluster_memory_needed
3550 + *
3551 + * Description: Tell the caller how much memory we need to operate during
3552 + * suspend/resume.
3553 + * Returns: Unsigned long. Maximum number of bytes of memory required for
3554 + * operation.
3555 + */
3556 +static int suspend_cluster_memory_needed(void)
3557 +{
3558 + return 0;
3559 +}
3560 +
3561 +static int suspend_cluster_storage_needed(void)
3562 +{
3563 + return 1 + strlen(suspend_cluster_master);
3564 +}
3565 +
3566 +/* suspend_cluster_save_config_info
3567 + *
3568 + * Description: Save informaton needed when reloading the image at resume time.
3569 + * Arguments: Buffer: Pointer to a buffer of size PAGE_SIZE.
3570 + * Returns: Number of bytes used for saving our data.
3571 + */
3572 +static int suspend_cluster_save_config_info(char *buffer)
3573 +{
3574 + strcpy(buffer, suspend_cluster_master);
3575 + return strlen(suspend_cluster_master + 1);
3576 +}
3577 +
3578 +/* suspend_cluster_load_config_info
3579 + *
3580 + * Description: Reload information needed for declustering the image at
3581 + * resume time.
3582 + * Arguments: Buffer: Pointer to the start of the data.
3583 + * Size: Number of bytes that were saved.
3584 + */
3585 +static void suspend_cluster_load_config_info(char *buffer, int size)
3586 +{
3587 + strncpy(suspend_cluster_master, buffer, size);
3588 + return;
3589 +}
3590 +
3591 +/*
3592 + * data for our sysfs entries.
3593 + */
3594 +static struct suspend_sysfs_data sysfs_params[] = {
3595 + {
3596 + SUSPEND2_ATTR("master", SYSFS_RW),
3597 + SYSFS_STRING(suspend_cluster_master, 63, SYSFS_SM_NOT_NEEDED)
3598 + },
3599 +
3600 + {
3601 + SUSPEND2_ATTR("enabled", SYSFS_RW),
3602 + SYSFS_INT(&suspend_cluster_ops.enabled, 0, 1)
3603 + }
3604 +};
3605 +
3606 +/*
3607 + * Ops structure.
3608 + */
3609 +
3610 +static struct suspend_module_ops suspend_cluster_ops = {
3611 + .type = FILTER_MODULE,
3612 + .name = "Cluster",
3613 + .directory = "cluster",
3614 + .module = THIS_MODULE,
3615 + .memory_needed = suspend_cluster_memory_needed,
3616 + .print_debug_info = suspend_cluster_print_debug_stats,
3617 + .save_config_info = suspend_cluster_save_config_info,
3618 + .load_config_info = suspend_cluster_load_config_info,
3619 + .storage_needed = suspend_cluster_storage_needed,
3620 +
3621 + .sysfs_data = sysfs_params,
3622 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
3623 +};
3624 +
3625 +/* ---- Registration ---- */
3626 +
3627 +#ifdef MODULE
3628 +#warning Module set.
3629 +#define INIT static __init
3630 +#define EXIT static __exit
3631 +#else
3632 +#define INIT
3633 +#define EXIT
3634 +#endif
3635 +
3636 +INIT int s2_cluster_init(void)
3637 +{
3638 + int temp = suspend_register_module(&suspend_cluster_ops);
3639 +
3640 + if (!strlen(suspend_cluster_master))
3641 + suspend_cluster_ops.enabled = 0;
3642 + return temp;
3643 +}
3644 +
3645 +EXIT void s2_cluster_exit(void)
3646 +{
3647 + suspend_unregister_module(&suspend_cluster_ops);
3648 +}
3649 +
3650 +#ifdef MODULE
3651 +MODULE_LICENSE("GPL");
3652 +module_init(s2_cluster_init);
3653 +module_exit(s2_cluster_exit);
3654 +MODULE_AUTHOR("Nigel Cunningham");
3655 +MODULE_DESCRIPTION("Cluster Support for Suspend2");
3656 +#endif
3657 diff -Naur linux-2.6.21-ck2/kernel/power/cluster.h linux-2.6.21-magellan-r11/kernel/power/cluster.h
3658 --- linux-2.6.21-ck2/kernel/power/cluster.h 1970-01-01 01:00:00.000000000 +0100
3659 +++ linux-2.6.21-magellan-r11/kernel/power/cluster.h 2007-08-17 15:57:25.000000000 +0200
3660 @@ -0,0 +1,17 @@
3661 +/*
3662 + * kernel/power/cluster.h
3663 + *
3664 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
3665 + * Copyright (C) 2006 Red Hat, inc.
3666 + *
3667 + * This file is released under the GPLv2.
3668 + */
3669 +
3670 +#ifdef CONFIG_SUSPEND2_CLUSTER
3671 +extern int s2_cluster_init(void);
3672 +extern void s2_cluster_exit(void);
3673 +#else
3674 +static inline int s2_cluster_init(void) { return 0; }
3675 +static inline void s2_cluster_exit(void) { }
3676 +#endif
3677 +
3678 diff -Naur linux-2.6.21-ck2/kernel/power/disk.c linux-2.6.21-magellan-r11/kernel/power/disk.c
3679 --- linux-2.6.21-ck2/kernel/power/disk.c 2007-04-26 05:08:32.000000000 +0200
3680 +++ linux-2.6.21-magellan-r11/kernel/power/disk.c 2007-08-17 15:57:25.000000000 +0200
3681 @@ -24,6 +24,8 @@
3682
3683 #include "power.h"
3684
3685 +#include "suspend.h"
3686 +#include "suspend2_builtin.h"
3687
3688 static int noresume = 0;
3689 char resume_file[256] = CONFIG_PM_STD_PARTITION;
3690 @@ -118,6 +120,11 @@
3691 {
3692 int error;
3693
3694 +#ifdef CONFIG_SUSPEND2
3695 + if (test_action_state(SUSPEND_REPLACE_SWSUSP))
3696 + return suspend2_try_suspend(1);
3697 +#endif
3698 +
3699 error = prepare_processes();
3700 if (error)
3701 return error;
3702 @@ -200,10 +207,22 @@
3703 *
3704 */
3705
3706 -static int software_resume(void)
3707 +int software_resume(void)
3708 {
3709 int error;
3710
3711 + resume_attempted = 1;
3712 +
3713 +#ifdef CONFIG_SUSPEND2
3714 + /*
3715 + * We can't know (until an image header - if any - is loaded), whether
3716 + * we did override swsusp. We therefore ensure that both are tried.
3717 + */
3718 + if (test_action_state(SUSPEND_REPLACE_SWSUSP))
3719 + printk("Replacing swsusp.\n");
3720 + suspend2_try_resume();
3721 +#endif
3722 +
3723 mutex_lock(&pm_mutex);
3724 if (!swsusp_resume_device) {
3725 if (!strlen(resume_file)) {
3726 @@ -274,9 +293,6 @@
3727 return 0;
3728 }
3729
3730 -late_initcall(software_resume);
3731 -
3732 -
3733 static const char * const pm_disk_modes[] = {
3734 [PM_DISK_FIRMWARE] = "firmware",
3735 [PM_DISK_PLATFORM] = "platform",
3736 @@ -457,6 +473,7 @@
3737 static int __init noresume_setup(char *str)
3738 {
3739 noresume = 1;
3740 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
3741 return 1;
3742 }
3743
3744 diff -Naur linux-2.6.21-ck2/kernel/power/extent.c linux-2.6.21-magellan-r11/kernel/power/extent.c
3745 --- linux-2.6.21-ck2/kernel/power/extent.c 1970-01-01 01:00:00.000000000 +0100
3746 +++ linux-2.6.21-magellan-r11/kernel/power/extent.c 2007-08-17 15:57:25.000000000 +0200
3747 @@ -0,0 +1,305 @@
3748 +/*
3749 + * kernel/power/extent.c
3750 + *
3751 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
3752 + *
3753 + * Distributed under GPLv2.
3754 + *
3755 + * These functions encapsulate the manipulation of storage metadata. For
3756 + * pageflags, we use dynamically allocated bitmaps.
3757 + */
3758 +
3759 +#include <linux/module.h>
3760 +#include <linux/suspend.h>
3761 +#include "modules.h"
3762 +#include "extent.h"
3763 +#include "ui.h"
3764 +#include "suspend.h"
3765 +
3766 +/* suspend_get_extent
3767 + *
3768 + * Returns a free extent. May fail, returning NULL instead.
3769 + */
3770 +static struct extent *suspend_get_extent(void)
3771 +{
3772 + struct extent *result;
3773 +
3774 + if (!(result = kmalloc(sizeof(struct extent), GFP_ATOMIC)))
3775 + return NULL;
3776 +
3777 + result->minimum = result->maximum = 0;
3778 + result->next = NULL;
3779 +
3780 + return result;
3781 +}
3782 +
3783 +/* suspend_put_extent_chain.
3784 + *
3785 + * Frees a whole chain of extents.
3786 + */
3787 +void suspend_put_extent_chain(struct extent_chain *chain)
3788 +{
3789 + struct extent *this;
3790 +
3791 + this = chain->first;
3792 +
3793 + while(this) {
3794 + struct extent *next = this->next;
3795 + kfree(this);
3796 + chain->num_extents--;
3797 + this = next;
3798 + }
3799 +
3800 + chain->first = chain->last_touched = NULL;
3801 + chain->size = 0;
3802 +}
3803 +
3804 +/*
3805 + * suspend_add_to_extent_chain
3806 + *
3807 + * Add an extent to an existing chain.
3808 + */
3809 +int suspend_add_to_extent_chain(struct extent_chain *chain,
3810 + unsigned long minimum, unsigned long maximum)
3811 +{
3812 + struct extent *new_extent = NULL, *start_at;
3813 +
3814 + /* Find the right place in the chain */
3815 + start_at = (chain->last_touched &&
3816 + (chain->last_touched->minimum < minimum)) ?
3817 + chain->last_touched : NULL;
3818 +
3819 + if (!start_at && chain->first && chain->first->minimum < minimum)
3820 + start_at = chain->first;
3821 +
3822 + while (start_at && start_at->next && start_at->next->minimum < minimum)
3823 + start_at = start_at->next;
3824 +
3825 + if (start_at && start_at->maximum == (minimum - 1)) {
3826 + start_at->maximum = maximum;
3827 +
3828 + /* Merge with the following one? */
3829 + if (start_at->next &&
3830 + start_at->maximum + 1 == start_at->next->minimum) {
3831 + struct extent *to_free = start_at->next;
3832 + start_at->maximum = start_at->next->maximum;
3833 + start_at->next = start_at->next->next;
3834 + chain->num_extents--;
3835 + kfree(to_free);
3836 + }
3837 +
3838 + chain->last_touched = start_at;
3839 + chain->size+= (maximum - minimum + 1);
3840 +
3841 + return 0;
3842 + }
3843 +
3844 + new_extent = suspend_get_extent();
3845 + if (!new_extent) {
3846 + printk("Error unable to append a new extent to the chain.\n");
3847 + return 2;
3848 + }
3849 +
3850 + chain->num_extents++;
3851 + chain->size+= (maximum - minimum + 1);
3852 + new_extent->minimum = minimum;
3853 + new_extent->maximum = maximum;
3854 + new_extent->next = NULL;
3855 +
3856 + chain->last_touched = new_extent;
3857 +
3858 + if (start_at) {
3859 + struct extent *next = start_at->next;
3860 + start_at->next = new_extent;
3861 + new_extent->next = next;
3862 + } else {
3863 + if (chain->first)
3864 + new_extent->next = chain->first;
3865 + chain->first = new_extent;
3866 + }
3867 +
3868 + return 0;
3869 +}
3870 +
3871 +/* suspend_serialise_extent_chain
3872 + *
3873 + * Write a chain in the image.
3874 + */
3875 +int suspend_serialise_extent_chain(struct suspend_module_ops *owner,
3876 + struct extent_chain *chain)
3877 +{
3878 + struct extent *this;
3879 + int ret, i = 0;
3880 +
3881 + if ((ret = suspendActiveAllocator->rw_header_chunk(WRITE, owner,
3882 + (char *) chain,
3883 + 2 * sizeof(int))))
3884 + return ret;
3885 +
3886 + this = chain->first;
3887 + while (this) {
3888 + if ((ret = suspendActiveAllocator->rw_header_chunk(WRITE, owner,
3889 + (char *) this,
3890 + 2 * sizeof(unsigned long))))
3891 + return ret;
3892 + this = this->next;
3893 + i++;
3894 + }
3895 +
3896 + if (i != chain->num_extents) {
3897 + printk(KERN_EMERG "Saved %d extents but chain metadata says there "
3898 + "should be %d.\n", i, chain->num_extents);
3899 + return 1;
3900 + }
3901 +
3902 + return ret;
3903 +}
3904 +
3905 +/* suspend_load_extent_chain
3906 + *
3907 + * Read back a chain saved in the image.
3908 + */
3909 +int suspend_load_extent_chain(struct extent_chain *chain)
3910 +{
3911 + struct extent *this, *last = NULL;
3912 + int i, ret;
3913 +
3914 + if ((ret = suspendActiveAllocator->rw_header_chunk(READ, NULL,
3915 + (char *) chain, 2 * sizeof(int)))) {
3916 + printk("Failed to read size of extent chain.\n");
3917 + return 1;
3918 + }
3919 +
3920 + for (i = 0; i < chain->num_extents; i++) {
3921 + this = kmalloc(sizeof(struct extent), GFP_ATOMIC);
3922 + if (!this) {
3923 + printk("Failed to allocate a new extent.\n");
3924 + return -ENOMEM;
3925 + }
3926 + this->next = NULL;
3927 + if ((ret = suspendActiveAllocator->rw_header_chunk(READ, NULL,
3928 + (char *) this, 2 * sizeof(unsigned long)))) {
3929 + printk("Failed to an extent.\n");
3930 + return 1;
3931 + }
3932 + if (last)
3933 + last->next = this;
3934 + else
3935 + chain->first = this;
3936 + last = this;
3937 + }
3938 + return 0;
3939 +}
3940 +
3941 +/* suspend_extent_state_next
3942 + *
3943 + * Given a state, progress to the next valid entry. We may begin in an
3944 + * invalid state, as we do when invoked after extent_state_goto_start below.
3945 + *
3946 + * When using compression and expected_compression > 0, we let the image size
3947 + * be larger than storage, so we can validly run out of data to return.
3948 + */
3949 +unsigned long suspend_extent_state_next(struct extent_iterate_state *state)
3950 +{
3951 + if (state->current_chain == state->num_chains)
3952 + return 0;
3953 +
3954 + if (state->current_extent) {
3955 + if (state->current_offset == state->current_extent->maximum) {
3956 + if (state->current_extent->next) {
3957 + state->current_extent = state->current_extent->next;
3958 + state->current_offset = state->current_extent->minimum;
3959 + } else {
3960 + state->current_extent = NULL;
3961 + state->current_offset = 0;
3962 + }
3963 + } else
3964 + state->current_offset++;
3965 + }
3966 +
3967 + while(!state->current_extent) {
3968 + int chain_num = ++(state->current_chain);
3969 +
3970 + if (chain_num == state->num_chains)
3971 + return 0;
3972 +
3973 + state->current_extent = (state->chains + chain_num)->first;
3974 +
3975 + if (!state->current_extent)
3976 + continue;
3977 +
3978 + state->current_offset = state->current_extent->minimum;
3979 + }
3980 +
3981 + return state->current_offset;
3982 +}
3983 +
3984 +/* suspend_extent_state_goto_start
3985 + *
3986 + * Find the first valid value in a group of chains.
3987 + */
3988 +void suspend_extent_state_goto_start(struct extent_iterate_state *state)
3989 +{
3990 + state->current_chain = -1;
3991 + state->current_extent = NULL;
3992 + state->current_offset = 0;
3993 +}
3994 +
3995 +/* suspend_extent_start_save
3996 + *
3997 + * Given a state and a struct extent_state_store, save the current
3998 + * position in a format that can be used with relocated chains (at
3999 + * resume time).
4000 + */
4001 +void suspend_extent_state_save(struct extent_iterate_state *state,
4002 + struct extent_iterate_saved_state *saved_state)
4003 +{
4004 + struct extent *extent;
4005 +
4006 + saved_state->chain_num = state->current_chain;
4007 + saved_state->extent_num = 0;
4008 + saved_state->offset = state->current_offset;
4009 +
4010 + if (saved_state->chain_num == -1)
4011 + return;
4012 +
4013 + extent = (state->chains + state->current_chain)->first;
4014 +
4015 + while (extent != state->current_extent) {
4016 + saved_state->extent_num++;
4017 + extent = extent->next;
4018 + }
4019 +}
4020 +
4021 +/* suspend_extent_start_restore
4022 + *
4023 + * Restore the position saved by extent_state_save.
4024 + */
4025 +void suspend_extent_state_restore(struct extent_iterate_state *state,
4026 + struct extent_iterate_saved_state *saved_state)
4027 +{
4028 + int posn = saved_state->extent_num;
4029 +
4030 + if (saved_state->chain_num == -1) {
4031 + suspend_extent_state_goto_start(state);
4032 + return;
4033 + }
4034 +
4035 + state->current_chain = saved_state->chain_num;
4036 + state->current_extent = (state->chains + state->current_chain)->first;
4037 + state->current_offset = saved_state->offset;
4038 +
4039 + while (posn--)
4040 + state->current_extent = state->current_extent->next;
4041 +}
4042 +
4043 +#ifdef CONFIG_SUSPEND2_EXPORTS
4044 +EXPORT_SYMBOL_GPL(suspend_add_to_extent_chain);
4045 +EXPORT_SYMBOL_GPL(suspend_put_extent_chain);
4046 +EXPORT_SYMBOL_GPL(suspend_load_extent_chain);
4047 +EXPORT_SYMBOL_GPL(suspend_serialise_extent_chain);
4048 +EXPORT_SYMBOL_GPL(suspend_extent_state_save);
4049 +EXPORT_SYMBOL_GPL(suspend_extent_state_restore);
4050 +EXPORT_SYMBOL_GPL(suspend_extent_state_goto_start);
4051 +EXPORT_SYMBOL_GPL(suspend_extent_state_next);
4052 +#endif
4053 diff -Naur linux-2.6.21-ck2/kernel/power/extent.h linux-2.6.21-magellan-r11/kernel/power/extent.h
4054 --- linux-2.6.21-ck2/kernel/power/extent.h 1970-01-01 01:00:00.000000000 +0100
4055 +++ linux-2.6.21-magellan-r11/kernel/power/extent.h 2007-08-17 15:57:25.000000000 +0200
4056 @@ -0,0 +1,77 @@
4057 +/*
4058 + * kernel/power/extent.h
4059 + *
4060 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
4061 + *
4062 + * This file is released under the GPLv2.
4063 + *
4064 + * It contains declarations related to extents. Extents are
4065 + * suspend's method of storing some of the metadata for the image.
4066 + * See extent.c for more info.
4067 + *
4068 + */
4069 +
4070 +#include "modules.h"
4071 +
4072 +#ifndef EXTENT_H
4073 +#define EXTENT_H
4074 +
4075 +struct extent {
4076 + unsigned long minimum, maximum;
4077 + struct extent *next;
4078 +};
4079 +
4080 +struct extent_chain {
4081 + int size; /* size of the chain ie sum (max-min+1) */
4082 + int num_extents;
4083 + struct extent *first, *last_touched;
4084 +};
4085 +
4086 +struct extent_iterate_state {
4087 + struct extent_chain *chains;
4088 + int num_chains;
4089 + int current_chain;
4090 + struct extent *current_extent;
4091 + unsigned long current_offset;
4092 +};
4093 +
4094 +struct extent_iterate_saved_state {
4095 + int chain_num;
4096 + int extent_num;
4097 + unsigned long offset;
4098 +};
4099 +
4100 +#define suspend_extent_state_eof(state) ((state)->num_chains == (state)->current_chain)
4101 +
4102 +/* Simplify iterating through all the values in an extent chain */
4103 +#define suspend_extent_for_each(extent_chain, extentpointer, value) \
4104 +if ((extent_chain)->first) \
4105 + for ((extentpointer) = (extent_chain)->first, (value) = \
4106 + (extentpointer)->minimum; \
4107 + ((extentpointer) && ((extentpointer)->next || (value) <= \
4108 + (extentpointer)->maximum)); \
4109 + (((value) == (extentpointer)->maximum) ? \
4110 + ((extentpointer) = (extentpointer)->next, (value) = \
4111 + ((extentpointer) ? (extentpointer)->minimum : 0)) : \
4112 + (value)++))
4113 +
4114 +void suspend_put_extent_chain(struct extent_chain *chain);
4115 +int suspend_add_to_extent_chain(struct extent_chain *chain,
4116 + unsigned long minimum, unsigned long maximum);
4117 +int suspend_serialise_extent_chain(struct suspend_module_ops *owner,
4118 + struct extent_chain *chain);
4119 +int suspend_load_extent_chain(struct extent_chain *chain);
4120 +
4121 +/* swap_entry_to_extent_val & extent_val_to_swap_entry:
4122 + * We are putting offset in the low bits so consecutive swap entries
4123 + * make consecutive extent values */
4124 +#define swap_entry_to_extent_val(swp_entry) (swp_entry.val)
4125 +#define extent_val_to_swap_entry(val) (swp_entry_t) { (val) }
4126 +
4127 +void suspend_extent_state_save(struct extent_iterate_state *state,
4128 + struct extent_iterate_saved_state *saved_state);
4129 +void suspend_extent_state_restore(struct extent_iterate_state *state,
4130 + struct extent_iterate_saved_state *saved_state);
4131 +void suspend_extent_state_goto_start(struct extent_iterate_state *state);
4132 +unsigned long suspend_extent_state_next(struct extent_iterate_state *state);
4133 +#endif
4134 diff -Naur linux-2.6.21-ck2/kernel/power/io.c linux-2.6.21-magellan-r11/kernel/power/io.c
4135 --- linux-2.6.21-ck2/kernel/power/io.c 1970-01-01 01:00:00.000000000 +0100
4136 +++ linux-2.6.21-magellan-r11/kernel/power/io.c 2007-08-17 15:57:25.000000000 +0200
4137 @@ -0,0 +1,1407 @@
4138 +/*
4139 + * kernel/power/io.c
4140 + *
4141 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
4142 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
4143 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
4144 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
4145 + *
4146 + * This file is released under the GPLv2.
4147 + *
4148 + * It contains high level IO routines for suspending.
4149 + *
4150 + */
4151 +
4152 +#include <linux/suspend.h>
4153 +#include <linux/version.h>
4154 +#include <linux/utsname.h>
4155 +#include <linux/mount.h>
4156 +#include <linux/highmem.h>
4157 +#include <linux/module.h>
4158 +#include <linux/kthread.h>
4159 +#include <asm/tlbflush.h>
4160 +
4161 +#include "suspend.h"
4162 +#include "modules.h"
4163 +#include "pageflags.h"
4164 +#include "io.h"
4165 +#include "ui.h"
4166 +#include "storage.h"
4167 +#include "prepare_image.h"
4168 +#include "extent.h"
4169 +#include "sysfs.h"
4170 +#include "suspend2_builtin.h"
4171 +
4172 +char poweroff_resume2[256];
4173 +
4174 +/* Variables shared between threads and updated under the mutex */
4175 +static int io_write, io_finish_at, io_base, io_barmax, io_pageset, io_result;
4176 +static int io_index, io_nextupdate, io_pc, io_pc_step;
4177 +static unsigned long pfn, other_pfn;
4178 +static DEFINE_MUTEX(io_mutex);
4179 +static DEFINE_PER_CPU(struct page *, last_sought);
4180 +static DEFINE_PER_CPU(struct page *, last_high_page);
4181 +static DEFINE_PER_CPU(struct pbe *, last_low_page);
4182 +static atomic_t worker_thread_count;
4183 +static atomic_t io_count;
4184 +
4185 +/* suspend_attempt_to_parse_resume_device
4186 + *
4187 + * Can we suspend, using the current resume2= parameter?
4188 + */
4189 +int suspend_attempt_to_parse_resume_device(int quiet)
4190 +{
4191 + struct list_head *Allocator;
4192 + struct suspend_module_ops *thisAllocator;
4193 + int result, returning = 0;
4194 +
4195 + if (suspend_activate_storage(0))
4196 + return 0;
4197 +
4198 + suspendActiveAllocator = NULL;
4199 + clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
4200 + clear_suspend_state(SUSPEND_CAN_RESUME);
4201 + clear_result_state(SUSPEND_ABORTED);
4202 +
4203 + if (!suspendNumAllocators) {
4204 + if (!quiet)
4205 + printk("Suspend2: No storage allocators have been "
4206 + "registered. Suspending will be disabled.\n");
4207 + goto cleanup;
4208 + }
4209 +
4210 + if (!resume2_file[0]) {
4211 + if (!quiet)
4212 + printk("Suspend2: Resume2 parameter is empty."
4213 + " Suspending will be disabled.\n");
4214 + goto cleanup;
4215 + }
4216 +
4217 + list_for_each(Allocator, &suspendAllocators) {
4218 + thisAllocator = list_entry(Allocator, struct suspend_module_ops,
4219 + type_list);
4220 +
4221 + /*
4222 + * Not sure why you'd want to disable an allocator, but
4223 + * we should honour the flag if we're providing it
4224 + */
4225 + if (!thisAllocator->enabled)
4226 + continue;
4227 +
4228 + result = thisAllocator->parse_sig_location(
4229 + resume2_file, (suspendNumAllocators == 1),
4230 + quiet);
4231 +
4232 + switch (result) {
4233 + case -EINVAL:
4234 + /* For this allocator, but not a valid
4235 + * configuration. Error already printed. */
4236 + goto cleanup;
4237 +
4238 + case 0:
4239 + /* For this allocator and valid. */
4240 + suspendActiveAllocator = thisAllocator;
4241 +
4242 + set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
4243 + set_suspend_state(SUSPEND_CAN_RESUME);
4244 + if (!quiet)
4245 + printk("Suspend2: Resuming enabled.\n");
4246 +
4247 + returning = 1;
4248 + goto cleanup;
4249 + }
4250 + }
4251 + if (!quiet)
4252 + printk("Suspend2: No matching enabled allocator found. "
4253 + "Resuming disabled.\n");
4254 +cleanup:
4255 + suspend_deactivate_storage(0);
4256 + return returning;
4257 +}
4258 +
4259 +void attempt_to_parse_resume_device2(void)
4260 +{
4261 + suspend_prepare_usm();
4262 + suspend_attempt_to_parse_resume_device(0);
4263 + suspend_cleanup_usm();
4264 +}
4265 +
4266 +void save_restore_resume2(int replace, int quiet)
4267 +{
4268 + static char resume2_save[255];
4269 + static unsigned long suspend_state_save;
4270 +
4271 + if (replace) {
4272 + suspend_state_save = suspend_state;
4273 + strcpy(resume2_save, resume2_file);
4274 + strcpy(resume2_file, poweroff_resume2);
4275 + } else {
4276 + strcpy(resume2_file, resume2_save);
4277 + suspend_state = suspend_state_save;
4278 + }
4279 + suspend_attempt_to_parse_resume_device(quiet);
4280 +}
4281 +
4282 +void attempt_to_parse_po_resume_device2(void)
4283 +{
4284 + int ok = 0;
4285 +
4286 + /* Temporarily set resume2 to the poweroff value */
4287 + if (!strlen(poweroff_resume2))
4288 + return;
4289 +
4290 + printk("=== Trying Poweroff Resume2 ===\n");
4291 + save_restore_resume2(SAVE, NOQUIET);
4292 + if (test_suspend_state(SUSPEND_CAN_RESUME))
4293 + ok = 1;
4294 +
4295 + printk("=== Done ===\n");
4296 + save_restore_resume2(RESTORE, QUIET);
4297 +
4298 + /* If not ok, clear the string */
4299 + if (ok)
4300 + return;
4301 +
4302 + printk("Can't resume from that location; clearing poweroff_resume2.\n");
4303 + poweroff_resume2[0] = '\0';
4304 +}
4305 +
4306 +/* noresume_reset_modules
4307 + *
4308 + * Description: When we read the start of an image, modules (and especially the
4309 + * active allocator) might need to reset data structures if we
4310 + * decide to invalidate the image rather than resuming from it.
4311 + */
4312 +
4313 +static void noresume_reset_modules(void)
4314 +{
4315 + struct suspend_module_ops *this_filter;
4316 +
4317 + list_for_each_entry(this_filter, &suspend_filters, type_list)
4318 + if (this_filter->noresume_reset)
4319 + this_filter->noresume_reset();
4320 +
4321 + if (suspendActiveAllocator && suspendActiveAllocator->noresume_reset)
4322 + suspendActiveAllocator->noresume_reset();
4323 +}
4324 +
4325 +/* fill_suspend_header()
4326 + *
4327 + * Description: Fill the suspend header structure.
4328 + * Arguments: struct suspend_header: Header data structure to be filled.
4329 + */
4330 +
4331 +static void fill_suspend_header(struct suspend_header *sh)
4332 +{
4333 + int i;
4334 +
4335 + memset((char *)sh, 0, sizeof(*sh));
4336 +
4337 + sh->version_code = LINUX_VERSION_CODE;
4338 + sh->num_physpages = num_physpages;
4339 + memcpy(&sh->uts, init_utsname(), sizeof(struct new_utsname));
4340 + sh->page_size = PAGE_SIZE;
4341 + sh->pagedir = pagedir1;
4342 + sh->pageset_2_size = pagedir2.size;
4343 + sh->param0 = suspend_result;
4344 + sh->param1 = suspend_action;
4345 + sh->param2 = suspend_debug_state;
4346 + sh->param3 = console_loglevel;
4347 + sh->root_fs = current->fs->rootmnt->mnt_sb->s_dev;
4348 + for (i = 0; i < 4; i++)
4349 + sh->io_time[i/2][i%2] = suspend_io_time[i/2][i%2];
4350 +}
4351 +
4352 +/*
4353 + * rw_init_modules
4354 + *
4355 + * Iterate over modules, preparing the ones that will be used to read or write
4356 + * data.
4357 + */
4358 +static int rw_init_modules(int rw, int which)
4359 +{
4360 + struct suspend_module_ops *this_module;
4361 + /* Initialise page transformers */
4362 + list_for_each_entry(this_module, &suspend_filters, type_list) {
4363 + if (!this_module->enabled)
4364 + continue;
4365 + if (this_module->rw_init && this_module->rw_init(rw, which)) {
4366 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4367 + "Failed to initialise the %s filter.",
4368 + this_module->name);
4369 + return 1;
4370 + }
4371 + }
4372 +
4373 + /* Initialise allocator */
4374 + if (suspendActiveAllocator->rw_init(rw, which)) {
4375 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4376 + "Failed to initialise the allocator.");
4377 + if (!rw)
4378 + suspendActiveAllocator->invalidate_image();
4379 + return 1;
4380 + }
4381 +
4382 + /* Initialise other modules */
4383 + list_for_each_entry(this_module, &suspend_modules, module_list) {
4384 + if (!this_module->enabled ||
4385 + this_module->type == FILTER_MODULE ||
4386 + this_module->type == WRITER_MODULE)
4387 + continue;
4388 + if (this_module->rw_init && this_module->rw_init(rw, which)) {
4389 + set_result_state(SUSPEND_ABORTED);
4390 + printk("Setting aborted flag due to module init failure.\n");
4391 + return 1;
4392 + }
4393 + }
4394 +
4395 + return 0;
4396 +}
4397 +
4398 +/*
4399 + * rw_cleanup_modules
4400 + *
4401 + * Cleanup components after reading or writing a set of pages.
4402 + * Only the allocator may fail.
4403 + */
4404 +static int rw_cleanup_modules(int rw)
4405 +{
4406 + struct suspend_module_ops *this_module;
4407 + int result = 0;
4408 +
4409 + /* Cleanup other modules */
4410 + list_for_each_entry(this_module, &suspend_modules, module_list) {
4411 + if (!this_module->enabled ||
4412 + this_module->type == FILTER_MODULE ||
4413 + this_module->type == WRITER_MODULE)
4414 + continue;
4415 + if (this_module->rw_cleanup)
4416 + result |= this_module->rw_cleanup(rw);
4417 + }
4418 +
4419 + /* Flush data and cleanup */
4420 + list_for_each_entry(this_module, &suspend_filters, type_list) {
4421 + if (!this_module->enabled)
4422 + continue;
4423 + if (this_module->rw_cleanup)
4424 + result |= this_module->rw_cleanup(rw);
4425 + }
4426 +
4427 + result |= suspendActiveAllocator->rw_cleanup(rw);
4428 +
4429 + return result;
4430 +}
4431 +
4432 +static struct page *copy_page_from_orig_page(struct page *orig_page)
4433 +{
4434 + int is_high = PageHighMem(orig_page), index, min, max;
4435 + struct page *high_page = NULL,
4436 + **my_last_high_page = &__get_cpu_var(last_high_page),
4437 + **my_last_sought = &__get_cpu_var(last_sought);
4438 + struct pbe *this, **my_last_low_page = &__get_cpu_var(last_low_page);
4439 + void *compare;
4440 +
4441 + if (is_high) {
4442 + if (*my_last_sought && *my_last_high_page && *my_last_sought < orig_page)
4443 + high_page = *my_last_high_page;
4444 + else
4445 + high_page = (struct page *) restore_highmem_pblist;
4446 + this = (struct pbe *) kmap(high_page);
4447 + compare = orig_page;
4448 + } else {
4449 + if (*my_last_sought && *my_last_low_page && *my_last_sought < orig_page)
4450 + this = *my_last_low_page;
4451 + else
4452 + this = restore_pblist;
4453 + compare = page_address(orig_page);
4454 + }
4455 +
4456 + *my_last_sought = orig_page;
4457 +
4458 + /* Locate page containing pbe */
4459 + while ( this[PBES_PER_PAGE - 1].next &&
4460 + this[PBES_PER_PAGE - 1].orig_address < compare) {
4461 + if (is_high) {
4462 + struct page *next_high_page = (struct page *)
4463 + this[PBES_PER_PAGE - 1].next;
4464 + kunmap(high_page);
4465 + this = kmap(next_high_page);
4466 + high_page = next_high_page;
4467 + } else
4468 + this = this[PBES_PER_PAGE - 1].next;
4469 + }
4470 +
4471 + /* Do a binary search within the page */
4472 + min = 0;
4473 + max = PBES_PER_PAGE;
4474 + index = PBES_PER_PAGE / 2;
4475 + while (max - min) {
4476 + if (!this[index].orig_address ||
4477 + this[index].orig_address > compare)
4478 + max = index;
4479 + else if (this[index].orig_address == compare) {
4480 + if (is_high) {
4481 + struct page *page = this[index].address;
4482 + *my_last_high_page = high_page;
4483 + kunmap(high_page);
4484 + return page;
4485 + }
4486 + *my_last_low_page = this;
4487 + return virt_to_page(this[index].address);
4488 + } else
4489 + min = index;
4490 + index = ((max + min) / 2);
4491 + };
4492 +
4493 + if (is_high)
4494 + kunmap(high_page);
4495 +
4496 + abort_suspend(SUSPEND_FAILED_IO, "Failed to get destination page for"
4497 + " orig page %p. This[min].orig_address=%p.\n", orig_page,
4498 + this[index].orig_address);
4499 + return NULL;
4500 +}
4501 +
4502 +/*
4503 + * do_rw_loop
4504 + *
4505 + * The main I/O loop for reading or writing pages.
4506 + */
4507 +static int worker_rw_loop(void *data)
4508 +{
4509 + unsigned long orig_pfn, write_pfn;
4510 + int result, my_io_index = 0;
4511 + struct suspend_module_ops *first_filter = suspend_get_next_filter(NULL);
4512 + struct page *buffer = alloc_page(GFP_ATOMIC);
4513 +
4514 + atomic_inc(&worker_thread_count);
4515 +
4516 + mutex_lock(&io_mutex);
4517 +
4518 + do {
4519 + int buf_size;
4520 +
4521 + /*
4522 + * What page to use? If reading, don't know yet which page's
4523 + * data will be read, so always use the buffer. If writing,
4524 + * use the copy (Pageset1) or original page (Pageset2), but
4525 + * always write the pfn of the original page.
4526 + */
4527 + if (io_write) {
4528 + struct page *page;
4529 +
4530 + pfn = get_next_bit_on(io_map, pfn);
4531 +
4532 + /* Another thread could have beaten us to it. */
4533 + if (pfn == max_pfn + 1) {
4534 + if (atomic_read(&io_count)) {
4535 + printk("Ran out of pfns but io_count is still %d.\n", atomic_read(&io_count));
4536 + BUG();
4537 + }
4538 + break;
4539 + }
4540 +
4541 + atomic_dec(&io_count);
4542 +
4543 + orig_pfn = pfn;
4544 + write_pfn = pfn;
4545 +
4546 + /*
4547 + * Other_pfn is updated by all threads, so we're not
4548 + * writing the same page multiple times.
4549 + */
4550 + clear_dynpageflag(&io_map, pfn_to_page(pfn));
4551 + if (io_pageset == 1) {
4552 + other_pfn = get_next_bit_on(pageset1_map, other_pfn);
4553 + write_pfn = other_pfn;
4554 + }
4555 + page = pfn_to_page(pfn);
4556 +
4557 + my_io_index = io_finish_at - atomic_read(&io_count);
4558 +
4559 + mutex_unlock(&io_mutex);
4560 +
4561 + result = first_filter->write_chunk(write_pfn, page,
4562 + PAGE_SIZE);
4563 + } else {
4564 + atomic_dec(&io_count);
4565 + mutex_unlock(&io_mutex);
4566 +
4567 + /*
4568 + * Are we aborting? If so, don't submit any more I/O as
4569 + * resetting the resume_attempted flag (from ui.c) will
4570 + * clear the bdev flags, making this thread oops.
4571 + */
4572 + if (unlikely(test_suspend_state(SUSPEND_STOP_RESUME))) {
4573 + atomic_dec(&worker_thread_count);
4574 + if (!atomic_read(&worker_thread_count))
4575 + set_suspend_state(SUSPEND_IO_STOPPED);
4576 + while (1)
4577 + schedule();
4578 + }
4579 +
4580 + result = first_filter->read_chunk(&write_pfn, buffer,
4581 + &buf_size, SUSPEND_ASYNC);
4582 + if (buf_size != PAGE_SIZE) {
4583 + abort_suspend(SUSPEND_FAILED_IO,
4584 + "I/O pipeline returned %d bytes instead "
4585 + "of %d.\n", buf_size, PAGE_SIZE);
4586 + mutex_lock(&io_mutex);
4587 + break;
4588 + }
4589 + }
4590 +
4591 + if (result) {
4592 + io_result = result;
4593 + if (io_write) {
4594 + printk("Write chunk returned %d.\n", result);
4595 + abort_suspend(SUSPEND_FAILED_IO,
4596 + "Failed to write a chunk of the "
4597 + "image.");
4598 + mutex_lock(&io_mutex);
4599 + break;
4600 + }
4601 + panic("Read chunk returned (%d)", result);
4602 + }
4603 +
4604 + /*
4605 + * Discard reads of resaved pages while reading ps2
4606 + * and unwanted pages while rereading ps2 when aborting.
4607 + */
4608 + if (!io_write && !PageResave(pfn_to_page(write_pfn))) {
4609 + struct page *final_page = pfn_to_page(write_pfn),
4610 + *copy_page = final_page;
4611 + char *virt, *buffer_virt;
4612 +
4613 + if (io_pageset == 1 && !load_direct(final_page)) {
4614 + copy_page = copy_page_from_orig_page(final_page);
4615 + BUG_ON(!copy_page);
4616 + }
4617 +
4618 + if (test_dynpageflag(&io_map, final_page)) {
4619 + virt = kmap(copy_page);
4620 + buffer_virt = kmap(buffer);
4621 + memcpy(virt, buffer_virt, PAGE_SIZE);
4622 + kunmap(copy_page);
4623 + kunmap(buffer);
4624 + clear_dynpageflag(&io_map, final_page);
4625 + mutex_lock(&io_mutex);
4626 + my_io_index = io_finish_at - atomic_read(&io_count);
4627 + mutex_unlock(&io_mutex);
4628 + } else {
4629 + mutex_lock(&io_mutex);
4630 + atomic_inc(&io_count);
4631 + mutex_unlock(&io_mutex);
4632 + }
4633 + }
4634 +
4635 + /* Strictly speaking, this is racy - another thread could
4636 + * output the next the next percentage before we've done
4637 + * ours. 1/5th of the pageset would have to be done first,
4638 + * though, so I'm not worried. In addition, the only impact
4639 + * would be messed up output, not image corruption. Doing
4640 + * this under the mutex seems an unnecessary slowdown.
4641 + */
4642 + if ((my_io_index + io_base) >= io_nextupdate)
4643 + io_nextupdate = suspend_update_status(my_io_index +
4644 + io_base, io_barmax, " %d/%d MB ",
4645 + MB(io_base+my_io_index+1), MB(io_barmax));
4646 +
4647 + if ((my_io_index + 1) == io_pc) {
4648 + printk("%d%%...", 20 * io_pc_step);
4649 + io_pc_step++;
4650 + io_pc = io_finish_at * io_pc_step / 5;
4651 + }
4652 +
4653 + suspend_cond_pause(0, NULL);
4654 +
4655 + /*
4656 + * Subtle: If there's less I/O still to be done than threads
4657 + * running, quit. This stops us doing I/O beyond the end of
4658 + * the image when reading.
4659 + *
4660 + * Possible race condition. Two threads could do the test at
4661 + * the same time; one should exit and one should continue.
4662 + * Therefore we take the mutex before comparing and exiting.
4663 + */
4664 +
4665 + mutex_lock(&io_mutex);
4666 +
4667 + } while(atomic_read(&io_count) >= atomic_read(&worker_thread_count) &&
4668 + !(io_write && test_result_state(SUSPEND_ABORTED)));
4669 +
4670 + atomic_dec(&worker_thread_count);
4671 + mutex_unlock(&io_mutex);
4672 +
4673 + __free_pages(buffer, 0);
4674 +
4675 + return 0;
4676 +}
4677 +
4678 +void start_other_threads(void)
4679 +{
4680 + int cpu;
4681 + struct task_struct *p;
4682 +
4683 + for_each_online_cpu(cpu) {
4684 + if (cpu == smp_processor_id())
4685 + continue;
4686 +
4687 + p = kthread_create(worker_rw_loop, NULL, "ks2io/%d", cpu);
4688 + if (IS_ERR(p)) {
4689 + printk("ks2io for %i failed\n", cpu);
4690 + continue;
4691 + }
4692 + kthread_bind(p, cpu);
4693 + wake_up_process(p);
4694 + }
4695 +}
4696 +
4697 +/*
4698 + * do_rw_loop
4699 + *
4700 + * The main I/O loop for reading or writing pages.
4701 + */
4702 +static int do_rw_loop(int write, int finish_at, dyn_pageflags_t *pageflags,
4703 + int base, int barmax, int pageset)
4704 +{
4705 + int index = 0, cpu;
4706 +
4707 + if (!finish_at)
4708 + return 0;
4709 +
4710 + io_write = write;
4711 + io_finish_at = finish_at;
4712 + io_base = base;
4713 + io_barmax = barmax;
4714 + io_pageset = pageset;
4715 + io_index = 0;
4716 + io_pc = io_finish_at / 5;
4717 + io_pc_step = 1;
4718 + io_result = 0;
4719 + io_nextupdate = 0;
4720 +
4721 + for_each_online_cpu(cpu) {
4722 + per_cpu(last_sought, cpu) = NULL;
4723 + per_cpu(last_low_page, cpu) = NULL;
4724 + per_cpu(last_high_page, cpu) = NULL;
4725 + }
4726 +
4727 + /* Ensure all bits clear */
4728 + pfn = get_next_bit_on(io_map, max_pfn + 1);
4729 +
4730 + while (pfn < max_pfn + 1) {
4731 + clear_dynpageflag(&io_map, pfn_to_page(pfn));
4732 + pfn = get_next_bit_on(io_map, pfn);
4733 + }
4734 +
4735 + /* Set the bits for the pages to write */
4736 + pfn = get_next_bit_on(*pageflags, max_pfn + 1);
4737 +
4738 + while (pfn < max_pfn + 1 && index < finish_at) {
4739 + set_dynpageflag(&io_map, pfn_to_page(pfn));
4740 + pfn = get_next_bit_on(*pageflags, pfn);
4741 + index++;
4742 + }
4743 +
4744 + BUG_ON(index < finish_at);
4745 +
4746 + atomic_set(&io_count, finish_at);
4747 +
4748 + pfn = max_pfn + 1;
4749 + other_pfn = pfn;
4750 +
4751 + clear_suspend_state(SUSPEND_IO_STOPPED);
4752 +
4753 + if (!test_action_state(SUSPEND_NO_MULTITHREADED_IO))
4754 + start_other_threads();
4755 + worker_rw_loop(NULL);
4756 +
4757 + while (atomic_read(&worker_thread_count))
4758 + schedule();
4759 +
4760 + set_suspend_state(SUSPEND_IO_STOPPED);
4761 + if (unlikely(test_suspend_state(SUSPEND_STOP_RESUME))) {
4762 + while (1)
4763 + schedule();
4764 + }
4765 +
4766 + if (!io_result) {
4767 + printk("done.\n");
4768 +
4769 + suspend_update_status(io_base + io_finish_at, io_barmax, " %d/%d MB ",
4770 + MB(io_base + io_finish_at), MB(io_barmax));
4771 + }
4772 +
4773 + if (io_write && test_result_state(SUSPEND_ABORTED))
4774 + io_result = 1;
4775 + else /* All I/O done? */
4776 + BUG_ON(get_next_bit_on(io_map, max_pfn + 1) != max_pfn + 1);
4777 +
4778 + return io_result;
4779 +}
4780 +
4781 +/* write_pageset()
4782 + *
4783 + * Description: Write a pageset to disk.
4784 + * Arguments: pagedir: Which pagedir to write..
4785 + * Returns: Zero on success or -1 on failure.
4786 + */
4787 +
4788 +int write_pageset(struct pagedir *pagedir)
4789 +{
4790 + int finish_at, base = 0, start_time, end_time;
4791 + int barmax = pagedir1.size + pagedir2.size;
4792 + long error = 0;
4793 + dyn_pageflags_t *pageflags;
4794 +
4795 + /*
4796 + * Even if there is nothing to read or write, the allocator
4797 + * may need the init/cleanup for it's housekeeping. (eg:
4798 + * Pageset1 may start where pageset2 ends when writing).
4799 + */
4800 + finish_at = pagedir->size;
4801 +
4802 + if (pagedir->id == 1) {
4803 + suspend_prepare_status(DONT_CLEAR_BAR,
4804 + "Writing kernel & process data...");
4805 + base = pagedir2.size;
4806 + if (test_action_state(SUSPEND_TEST_FILTER_SPEED) ||
4807 + test_action_state(SUSPEND_TEST_BIO))
4808 + pageflags = &pageset1_map;
4809 + else
4810 + pageflags = &pageset1_copy_map;
4811 + } else {
4812 + suspend_prepare_status(CLEAR_BAR, "Writing caches...");
4813 + pageflags = &pageset2_map;
4814 + }
4815 +
4816 + start_time = jiffies;
4817 +
4818 + if (rw_init_modules(1, pagedir->id)) {
4819 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
4820 + "Failed to initialise modules for writing.");
4821 + error = 1;
4822 + }
4823 +
4824 + if (!error)
4825 + error = do_rw_loop(1, finish_at, pageflags, base, barmax,
4826 + pagedir->id);
4827 +
4828 + if (rw_cleanup_modules(WRITE) && !error) {
4829 + abort_suspend(SUSPEND_FAILED_MODULE_CLEANUP,
4830 + "Failed to cleanup after writing.");
4831 + error = 1;
4832 + }
4833 +
4834 + end_time = jiffies;
4835 +
4836 + if ((end_time - start_time) && (!test_result_state(SUSPEND_ABORTED))) {
4837 + suspend_io_time[0][0] += finish_at,
4838 + suspend_io_time[0][1] += (end_time - start_time);
4839 + }
4840 +
4841 + return error;
4842 +}
4843 +
4844 +/* read_pageset()
4845 + *
4846 + * Description: Read a pageset from disk.
4847 + * Arguments: whichtowrite: Controls what debugging output is printed.
4848 + * overwrittenpagesonly: Whether to read the whole pageset or
4849 + * only part.
4850 + * Returns: Zero on success or -1 on failure.
4851 + */
4852 +
4853 +static int read_pageset(struct pagedir *pagedir, int overwrittenpagesonly)
4854 +{
4855 + int result = 0, base = 0, start_time, end_time;
4856 + int finish_at = pagedir->size;
4857 + int barmax = pagedir1.size + pagedir2.size;
4858 + dyn_pageflags_t *pageflags;
4859 +
4860 + if (pagedir->id == 1) {
4861 + suspend_prepare_status(CLEAR_BAR,
4862 + "Reading kernel & process data...");
4863 + pageflags = &pageset1_map;
4864 + } else {
4865 + suspend_prepare_status(DONT_CLEAR_BAR, "Reading caches...");
4866 + if (overwrittenpagesonly)
4867 + barmax = finish_at = min(pagedir1.size,
4868 + pagedir2.size);
4869 + else {
4870 + base = pagedir1.size;
4871 + }
4872 + pageflags = &pageset2_map;
4873 + }
4874 +
4875 + start_time = jiffies;
4876 +
4877 + if (rw_init_modules(0, pagedir->id)) {
4878 + suspendActiveAllocator->invalidate_image();
4879 + result = 1;
4880 + } else
4881 + result = do_rw_loop(0, finish_at, pageflags, base, barmax,
4882 + pagedir->id);
4883 +
4884 + if (rw_cleanup_modules(READ) && !result) {
4885 + abort_suspend(SUSPEND_FAILED_MODULE_CLEANUP,
4886 + "Failed to cleanup after reading.");
4887 + result = 1;
4888 + }
4889 +
4890 + /* Statistics */
4891 + end_time=jiffies;
4892 +
4893 + if ((end_time - start_time) && (!test_result_state(SUSPEND_ABORTED))) {
4894 + suspend_io_time[1][0] += finish_at,
4895 + suspend_io_time[1][1] += (end_time - start_time);
4896 + }
4897 +
4898 + return result;
4899 +}
4900 +
4901 +/* write_module_configs()
4902 + *
4903 + * Description: Store the configuration for each module in the image header.
4904 + * Returns: Int: Zero on success, Error value otherwise.
4905 + */
4906 +static int write_module_configs(void)
4907 +{
4908 + struct suspend_module_ops *this_module;
4909 + char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
4910 + int len, index = 1;
4911 + struct suspend_module_header suspend_module_header;
4912 +
4913 + if (!buffer) {
4914 + printk("Failed to allocate a buffer for saving "
4915 + "module configuration info.\n");
4916 + return -ENOMEM;
4917 + }
4918 +
4919 + /*
4920 + * We have to know which data goes with which module, so we at
4921 + * least write a length of zero for a module. Note that we are
4922 + * also assuming every module's config data takes <= PAGE_SIZE.
4923 + */
4924 +
4925 + /* For each module (in registration order) */
4926 + list_for_each_entry(this_module, &suspend_modules, module_list) {
4927 + if (!this_module->enabled || !this_module->storage_needed ||
4928 + (this_module->type == WRITER_MODULE &&
4929 + suspendActiveAllocator != this_module))
4930 + continue;
4931 +
4932 + /* Get the data from the module */
4933 + len = 0;
4934 + if (this_module->save_config_info)
4935 + len = this_module->save_config_info(buffer);
4936 +
4937 + /* Save the details of the module */
4938 + suspend_module_header.enabled = this_module->enabled;
4939 + suspend_module_header.type = this_module->type;
4940 + suspend_module_header.index = index++;
4941 + strncpy(suspend_module_header.name, this_module->name,
4942 + sizeof(suspend_module_header.name));
4943 + suspendActiveAllocator->rw_header_chunk(WRITE,
4944 + this_module,
4945 + (char *) &suspend_module_header,
4946 + sizeof(suspend_module_header));
4947 +
4948 + /* Save the size of the data and any data returned */
4949 + suspendActiveAllocator->rw_header_chunk(WRITE,
4950 + this_module,
4951 + (char *) &len, sizeof(int));
4952 + if (len)
4953 + suspendActiveAllocator->rw_header_chunk(
4954 + WRITE, this_module, buffer, len);
4955 + }
4956 +
4957 + /* Write a blank header to terminate the list */
4958 + suspend_module_header.name[0] = '\0';
4959 + suspendActiveAllocator->rw_header_chunk(WRITE,
4960 + NULL,
4961 + (char *) &suspend_module_header,
4962 + sizeof(suspend_module_header));
4963 +
4964 + free_page((unsigned long) buffer);
4965 + return 0;
4966 +}
4967 +
4968 +/* read_module_configs()
4969 + *
4970 + * Description: Reload module configurations from the image header.
4971 + * Returns: Int. Zero on success, error value otherwise.
4972 + */
4973 +
4974 +static int read_module_configs(void)
4975 +{
4976 + struct suspend_module_ops *this_module;
4977 + char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
4978 + int len, result = 0;
4979 + struct suspend_module_header suspend_module_header;
4980 +
4981 + if (!buffer) {
4982 + printk("Failed to allocate a buffer for reloading module "
4983 + "configuration info.\n");
4984 + return -ENOMEM;
4985 + }
4986 +
4987 + /* All modules are initially disabled. That way, if we have a module
4988 + * loaded now that wasn't loaded when we suspended, it won't be used
4989 + * in trying to read the data.
4990 + */
4991 + list_for_each_entry(this_module, &suspend_modules, module_list)
4992 + this_module->enabled = 0;
4993 +
4994 + /* Get the first module header */
4995 + result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
4996 + (char *) &suspend_module_header,
4997 + sizeof(suspend_module_header));
4998 + if (result) {
4999 + printk("Failed to read the next module header.\n");
5000 + free_page((unsigned long) buffer);
5001 + return -EINVAL;
5002 + }
5003 +
5004 + /* For each module (in registration order) */
5005 + while (suspend_module_header.name[0]) {
5006 +
5007 + /* Find the module */
5008 + this_module = suspend_find_module_given_name(suspend_module_header.name);
5009 +
5010 + if (!this_module) {
5011 + /*
5012 + * Is it used? Only need to worry about filters. The active
5013 + * allocator must be loaded!
5014 + */
5015 + if (suspend_module_header.enabled) {
5016 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
5017 + "It looks like we need module %s for "
5018 + "reading the image but it hasn't been "
5019 + "registered.\n",
5020 + suspend_module_header.name);
5021 + if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
5022 + suspendActiveAllocator->invalidate_image();
5023 + free_page((unsigned long) buffer);
5024 + return -EINVAL;
5025 + }
5026 + } else
5027 + printk("Module %s configuration data found, but"
5028 + " the module hasn't registered. Looks "
5029 + "like it was disabled, so we're "
5030 + "ignoring it's data.",
5031 + suspend_module_header.name);
5032 + }
5033 +
5034 + /* Get the length of the data (if any) */
5035 + result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5036 + (char *) &len, sizeof(int));
5037 + if (result) {
5038 + printk("Failed to read the length of the module %s's"
5039 + " configuration data.\n",
5040 + suspend_module_header.name);
5041 + free_page((unsigned long) buffer);
5042 + return -EINVAL;
5043 + }
5044 +
5045 + /* Read any data and pass to the module (if we found one) */
5046 + if (len) {
5047 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
5048 + buffer, len);
5049 + if (this_module) {
5050 + if (!this_module->save_config_info) {
5051 + printk("Huh? Module %s appears to have "
5052 + "a save_config_info, but not a "
5053 + "load_config_info function!\n",
5054 + this_module->name);
5055 + } else
5056 + this_module->load_config_info(buffer, len);
5057 + }
5058 + }
5059 +
5060 + if (this_module) {
5061 + /* Now move this module to the tail of its lists. This
5062 + * will put it in order. Any new modules will end up at
5063 + * the top of the lists. They should have been set to
5064 + * disabled when loaded (people will normally not edit
5065 + * an initrd to load a new module and then suspend
5066 + * without using it!).
5067 + */
5068 +
5069 + suspend_move_module_tail(this_module);
5070 +
5071 + /*
5072 + * We apply the disabled state; modules don't need to
5073 + * save whether they were disabled and if they do, we
5074 + * override them anyway.
5075 + */
5076 + this_module->enabled = suspend_module_header.enabled;
5077 + }
5078 +
5079 + /* Get the next module header */
5080 + result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5081 + (char *) &suspend_module_header,
5082 + sizeof(suspend_module_header));
5083 +
5084 + if (result) {
5085 + printk("Failed to read the next module header.\n");
5086 + free_page((unsigned long) buffer);
5087 + return -EINVAL;
5088 + }
5089 +
5090 + }
5091 +
5092 + free_page((unsigned long) buffer);
5093 + return 0;
5094 +}
5095 +
5096 +/* write_image_header()
5097 + *
5098 + * Description: Write the image header after write the image proper.
5099 + * Returns: Int. Zero on success or -1 on failure.
5100 + */
5101 +
5102 +int write_image_header(void)
5103 +{
5104 + int ret;
5105 + int total = pagedir1.size + pagedir2.size+2;
5106 + char *header_buffer = NULL;
5107 +
5108 + /* Now prepare to write the header */
5109 + if ((ret = suspendActiveAllocator->write_header_init())) {
5110 + abort_suspend(SUSPEND_FAILED_MODULE_INIT,
5111 + "Active allocator's write_header_init"
5112 + " function failed.");
5113 + goto write_image_header_abort;
5114 + }
5115 +
5116 + /* Get a buffer */
5117 + header_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
5118 + if (!header_buffer) {
5119 + abort_suspend(SUSPEND_OUT_OF_MEMORY,
5120 + "Out of memory when trying to get page for header!");
5121 + goto write_image_header_abort;
5122 + }
5123 +
5124 + /* Write suspend header */
5125 + fill_suspend_header((struct suspend_header *) header_buffer);
5126 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
5127 + header_buffer, sizeof(struct suspend_header));
5128 +
5129 + free_page((unsigned long) header_buffer);
5130 +
5131 + /* Write module configurations */
5132 + if ((ret = write_module_configs())) {
5133 + abort_suspend(SUSPEND_FAILED_IO,
5134 + "Failed to write module configs.");
5135 + goto write_image_header_abort;
5136 + }
5137 +
5138 + save_dyn_pageflags(pageset1_map);
5139 +
5140 + /* Flush data and let allocator cleanup */
5141 + if (suspendActiveAllocator->write_header_cleanup()) {
5142 + abort_suspend(SUSPEND_FAILED_IO,
5143 + "Failed to cleanup writing header.");
5144 + goto write_image_header_abort_no_cleanup;
5145 + }
5146 +
5147 + if (test_result_state(SUSPEND_ABORTED))
5148 + goto write_image_header_abort_no_cleanup;
5149 +
5150 + suspend_message(SUSPEND_IO, SUSPEND_VERBOSE, 1, "|\n");
5151 + suspend_update_status(total, total, NULL);
5152 +
5153 + return 0;
5154 +
5155 +write_image_header_abort:
5156 + suspendActiveAllocator->write_header_cleanup();
5157 +write_image_header_abort_no_cleanup:
5158 + return -1;
5159 +}
5160 +
5161 +/* sanity_check()
5162 + *
5163 + * Description: Perform a few checks, seeking to ensure that the kernel being
5164 + * booted matches the one suspended. They need to match so we can
5165 + * be _sure_ things will work. It is not absolutely impossible for
5166 + * resuming from a different kernel to work, just not assured.
5167 + * Arguments: Struct suspend_header. The header which was saved at suspend
5168 + * time.
5169 + */
5170 +static char *sanity_check(struct suspend_header *sh)
5171 +{
5172 + if (sh->version_code != LINUX_VERSION_CODE)
5173 + return "Incorrect kernel version.";
5174 +
5175 + if (sh->num_physpages != num_physpages)
5176 + return "Incorrect memory size.";
5177 +
5178 + if (strncmp(sh->uts.sysname, init_utsname()->sysname, 65))
5179 + return "Incorrect system type.";
5180 +
5181 + if (strncmp(sh->uts.release, init_utsname()->release, 65))
5182 + return "Incorrect release.";
5183 +
5184 + if (strncmp(sh->uts.version, init_utsname()->version, 65))
5185 + return "Right kernel version but wrong build number.";
5186 +
5187 + if (strncmp(sh->uts.machine, init_utsname()->machine, 65))
5188 + return "Incorrect machine type.";
5189 +
5190 + if (sh->page_size != PAGE_SIZE)
5191 + return "Incorrect PAGE_SIZE.";
5192 +
5193 + if (!test_action_state(SUSPEND_IGNORE_ROOTFS)) {
5194 + const struct super_block *sb;
5195 + list_for_each_entry(sb, &super_blocks, s_list) {
5196 + if ((!(sb->s_flags & MS_RDONLY)) &&
5197 + (sb->s_type->fs_flags & FS_REQUIRES_DEV))
5198 + return "Device backed fs has been mounted "
5199 + "rw prior to resume or initrd/ramfs "
5200 + "is mounted rw.";
5201 + }
5202 + }
5203 +
5204 + return 0;
5205 +}
5206 +
5207 +/* __read_pageset1
5208 + *
5209 + * Description: Test for the existence of an image and attempt to load it.
5210 + * Returns: Int. Zero if image found and pageset1 successfully loaded.
5211 + * Error if no image found or loaded.
5212 + */
5213 +static int __read_pageset1(void)
5214 +{
5215 + int i, result = 0;
5216 + char *header_buffer = (char *) get_zeroed_page(GFP_ATOMIC),
5217 + *sanity_error = NULL;
5218 + struct suspend_header *suspend_header;
5219 +
5220 + if (!header_buffer) {
5221 + printk("Unable to allocate a page for reading the signature.\n");
5222 + return -ENOMEM;
5223 + }
5224 +
5225 + /* Check for an image */
5226 + if (!(result = suspendActiveAllocator->image_exists())) {
5227 + result = -ENODATA;
5228 + noresume_reset_modules();
5229 + printk("Suspend2: No image found.\n");
5230 + goto out;
5231 + }
5232 +
5233 + /* Check for noresume command line option */
5234 + if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
5235 + printk("Suspend2: Noresume: Invalidated image.\n");
5236 + goto out_invalidate_image;
5237 + }
5238 +
5239 + /* Check whether we've resumed before */
5240 + if (test_suspend_state(SUSPEND_RESUMED_BEFORE)) {
5241 + int resumed_before_default = 0;
5242 + if (test_suspend_state(SUSPEND_RETRY_RESUME))
5243 + resumed_before_default = SUSPEND_CONTINUE_REQ;
5244 +
5245 + suspend_early_boot_message(1, resumed_before_default, NULL);
5246 + clear_suspend_state(SUSPEND_RETRY_RESUME);
5247 + if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
5248 + printk("Suspend2: Tried to resume before: "
5249 + "Invalidated image.\n");
5250 + goto out_invalidate_image;
5251 + }
5252 + }
5253 +
5254 + clear_suspend_state(SUSPEND_CONTINUE_REQ);
5255 +
5256 + /*
5257 + * Prepare the active allocator for reading the image header. The
5258 + * activate allocator might read its own configuration.
5259 + *
5260 + * NB: This call may never return because there might be a signature
5261 + * for a different image such that we warn the user and they choose
5262 + * to reboot. (If the device ids look erroneous (2.4 vs 2.6) or the
5263 + * location of the image might be unavailable if it was stored on a
5264 + * network connection.
5265 + */
5266 +
5267 + if ((result = suspendActiveAllocator->read_header_init())) {
5268 + printk("Suspend2: Failed to initialise, reading the image "
5269 + "header.\n");
5270 + goto out_invalidate_image;
5271 + }
5272 +
5273 + /* Read suspend header */
5274 + if ((result = suspendActiveAllocator->rw_header_chunk(READ, NULL,
5275 + header_buffer, sizeof(struct suspend_header))) < 0) {
5276 + printk("Suspend2: Failed to read the image signature.\n");
5277 + goto out_invalidate_image;
5278 + }
5279 +
5280 + suspend_header = (struct suspend_header *) header_buffer;
5281 +
5282 + /*
5283 + * NB: This call may also result in a reboot rather than returning.
5284 + */
5285 +
5286 + if ((sanity_error = sanity_check(suspend_header)) &&
5287 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ, sanity_error)) {
5288 + printk("Suspend2: Sanity check failed.\n");
5289 + goto out_invalidate_image;
5290 + }
5291 +
5292 + /*
5293 + * We have an image and it looks like it will load okay.
5294 + *
5295 + * Get metadata from header. Don't override commandline parameters.
5296 + *
5297 + * We don't need to save the image size limit because it's not used
5298 + * during resume and will be restored with the image anyway.
5299 + */
5300 +
5301 + memcpy((char *) &pagedir1,
5302 + (char *) &suspend_header->pagedir, sizeof(pagedir1));
5303 + suspend_result = suspend_header->param0;
5304 + suspend_action = suspend_header->param1;
5305 + suspend_debug_state = suspend_header->param2;
5306 + console_loglevel = suspend_header->param3;
5307 + clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
5308 + pagedir2.size = suspend_header->pageset_2_size;
5309 + for (i = 0; i < 4; i++)
5310 + suspend_io_time[i/2][i%2] =
5311 + suspend_header->io_time[i/2][i%2];
5312 +
5313 + /* Read module configurations */
5314 + if ((result = read_module_configs())) {
5315 + pagedir1.size = pagedir2.size = 0;
5316 + printk("Suspend2: Failed to read Suspend module "
5317 + "configurations.\n");
5318 + clear_action_state(SUSPEND_KEEP_IMAGE);
5319 + goto out_invalidate_image;
5320 + }
5321 +
5322 + suspend_prepare_console();
5323 +
5324 + set_suspend_state(SUSPEND_NOW_RESUMING);
5325 +
5326 + if (pre_resume_freeze())
5327 + goto out_reset_console;
5328 +
5329 + suspend_cond_pause(1, "About to read original pageset1 locations.");
5330 +
5331 + /*
5332 + * Read original pageset1 locations. These are the addresses we can't
5333 + * use for the data to be restored.
5334 + */
5335 +
5336 + if (allocate_dyn_pageflags(&pageset1_map) ||
5337 + allocate_dyn_pageflags(&pageset1_copy_map) ||
5338 + allocate_dyn_pageflags(&io_map))
5339 + goto out_reset_console;
5340 +
5341 + if (load_dyn_pageflags(pageset1_map))
5342 + goto out_reset_console;
5343 +
5344 + /* Clean up after reading the header */
5345 + if ((result = suspendActiveAllocator->read_header_cleanup())) {
5346 + printk("Suspend2: Failed to cleanup after reading the image "
5347 + "header.\n");
5348 + goto out_reset_console;
5349 + }
5350 +
5351 + suspend_cond_pause(1, "About to read pagedir.");
5352 +
5353 + /*
5354 + * Get the addresses of pages into which we will load the kernel to
5355 + * be copied back
5356 + */
5357 + if (suspend_get_pageset1_load_addresses()) {
5358 + printk("Suspend2: Failed to get load addresses for pageset1.\n");
5359 + goto out_reset_console;
5360 + }
5361 +
5362 + /* Read the original kernel back */
5363 + suspend_cond_pause(1, "About to read pageset 1.");
5364 +
5365 + if (read_pageset(&pagedir1, 0)) {
5366 + suspend_prepare_status(CLEAR_BAR, "Failed to read pageset 1.");
5367 + result = -EIO;
5368 + printk("Suspend2: Failed to get load pageset1.\n");
5369 + goto out_reset_console;
5370 + }
5371 +
5372 + suspend_cond_pause(1, "About to restore original kernel.");
5373 + result = 0;
5374 +
5375 + if (!test_action_state(SUSPEND_KEEP_IMAGE) &&
5376 + suspendActiveAllocator->mark_resume_attempted)
5377 + suspendActiveAllocator->mark_resume_attempted(1);
5378 +
5379 +out:
5380 + free_page((unsigned long) header_buffer);
5381 + return result;
5382 +
5383 +out_reset_console:
5384 + suspend_cleanup_console();
5385 +
5386 +out_invalidate_image:
5387 + free_dyn_pageflags(&pageset1_map);
5388 + free_dyn_pageflags(&pageset1_copy_map);
5389 + free_dyn_pageflags(&io_map);
5390 + result = -EINVAL;
5391 + if (!test_action_state(SUSPEND_KEEP_IMAGE))
5392 + suspendActiveAllocator->invalidate_image();
5393 + suspendActiveAllocator->read_header_cleanup();
5394 + noresume_reset_modules();
5395 + goto out;
5396 +}
5397 +
5398 +/* read_pageset1()
5399 + *
5400 + * Description: Attempt to read the header and pageset1 of a suspend image.
5401 + * Handle the outcome, complaining where appropriate.
5402 + */
5403 +
5404 +int read_pageset1(void)
5405 +{
5406 + int error;
5407 +
5408 + error = __read_pageset1();
5409 +
5410 + switch (error) {
5411 + case 0:
5412 + case -ENODATA:
5413 + case -EINVAL: /* non fatal error */
5414 + break;
5415 + default:
5416 + if (test_result_state(SUSPEND_ABORTED))
5417 + break;
5418 +
5419 + abort_suspend(SUSPEND_IMAGE_ERROR,
5420 + "Suspend2: Error %d resuming\n",
5421 + error);
5422 + }
5423 + return error;
5424 +}
5425 +
5426 +/*
5427 + * get_have_image_data()
5428 + */
5429 +static char *get_have_image_data(void)
5430 +{
5431 + char *output_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
5432 + struct suspend_header *suspend_header;
5433 +
5434 + if (!output_buffer) {
5435 + printk("Output buffer null.\n");
5436 + return NULL;
5437 + }
5438 +
5439 + /* Check for an image */
5440 + if (!suspendActiveAllocator->image_exists() ||
5441 + suspendActiveAllocator->read_header_init() ||
5442 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
5443 + output_buffer, sizeof(struct suspend_header))) {
5444 + sprintf(output_buffer, "0\n");
5445 + goto out;
5446 + }
5447 +
5448 + suspend_header = (struct suspend_header *) output_buffer;
5449 +
5450 + sprintf(output_buffer, "1\n%s\n%s\n",
5451 + suspend_header->uts.machine,
5452 + suspend_header->uts.version);
5453 +
5454 + /* Check whether we've resumed before */
5455 + if (test_suspend_state(SUSPEND_RESUMED_BEFORE))
5456 + strcat(output_buffer, "Resumed before.\n");
5457 +
5458 +out:
5459 + noresume_reset_modules();
5460 + return output_buffer;
5461 +}
5462 +
5463 +/* read_pageset2()
5464 + *
5465 + * Description: Read in part or all of pageset2 of an image, depending upon
5466 + * whether we are suspending and have only overwritten a portion
5467 + * with pageset1 pages, or are resuming and need to read them
5468 + * all.
5469 + * Arguments: Int. Boolean. Read only pages which would have been
5470 + * overwritten by pageset1?
5471 + * Returns: Int. Zero if no error, otherwise the error value.
5472 + */
5473 +int read_pageset2(int overwrittenpagesonly)
5474 +{
5475 + int result = 0;
5476 +
5477 + if (!pagedir2.size)
5478 + return 0;
5479 +
5480 + result = read_pageset(&pagedir2, overwrittenpagesonly);
5481 +
5482 + suspend_update_status(100, 100, NULL);
5483 + suspend_cond_pause(1, "Pagedir 2 read.");
5484 +
5485 + return result;
5486 +}
5487 +
5488 +/* image_exists_read
5489 + *
5490 + * Return 0 or 1, depending on whether an image is found.
5491 + * Incoming buffer is PAGE_SIZE and result is guaranteed
5492 + * to be far less than that, so we don't worry about
5493 + * overflow.
5494 + */
5495 +int image_exists_read(const char *page, int count)
5496 +{
5497 + int len = 0;
5498 + char *result;
5499 +
5500 + if (suspend_activate_storage(0))
5501 + return count;
5502 +
5503 + if (!test_suspend_state(SUSPEND_RESUME_DEVICE_OK))
5504 + suspend_attempt_to_parse_resume_device(0);
5505 +
5506 + if (!suspendActiveAllocator) {
5507 + len = sprintf((char *) page, "-1\n");
5508 + } else {
5509 + result = get_have_image_data();
5510 + if (result) {
5511 + len = sprintf((char *) page, "%s", result);
5512 + free_page((unsigned long) result);
5513 + }
5514 + }
5515 +
5516 + suspend_deactivate_storage(0);
5517 +
5518 + return len;
5519 +}
5520 +
5521 +/* image_exists_write
5522 + *
5523 + * Invalidate an image if one exists.
5524 + */
5525 +int image_exists_write(const char *buffer, int count)
5526 +{
5527 + if (suspend_activate_storage(0))
5528 + return count;
5529 +
5530 + if (suspendActiveAllocator && suspendActiveAllocator->image_exists())
5531 + suspendActiveAllocator->invalidate_image();
5532 +
5533 + suspend_deactivate_storage(0);
5534 +
5535 + clear_result_state(SUSPEND_KEPT_IMAGE);
5536 +
5537 + return count;
5538 +}
5539 +
5540 +#ifdef CONFIG_SUSPEND2_EXPORTS
5541 +EXPORT_SYMBOL_GPL(suspend_attempt_to_parse_resume_device);
5542 +EXPORT_SYMBOL_GPL(attempt_to_parse_resume_device2);
5543 +#endif
5544 +
5545 diff -Naur linux-2.6.21-ck2/kernel/power/io.h linux-2.6.21-magellan-r11/kernel/power/io.h
5546 --- linux-2.6.21-ck2/kernel/power/io.h 1970-01-01 01:00:00.000000000 +0100
5547 +++ linux-2.6.21-magellan-r11/kernel/power/io.h 2007-08-17 15:57:25.000000000 +0200
5548 @@ -0,0 +1,56 @@
5549 +/*
5550 + * kernel/power/io.h
5551 + *
5552 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
5553 + *
5554 + * This file is released under the GPLv2.
5555 + *
5556 + * It contains high level IO routines for suspending.
5557 + *
5558 + */
5559 +
5560 +#include <linux/utsname.h>
5561 +#include "pagedir.h"
5562 +
5563 +/* Non-module data saved in our image header */
5564 +struct suspend_header {
5565 + u32 version_code;
5566 + unsigned long num_physpages;
5567 + unsigned long orig_mem_free;
5568 + struct new_utsname uts;
5569 + int num_cpus;
5570 + int page_size;
5571 + int pageset_2_size;
5572 + int param0;
5573 + int param1;
5574 + int param2;
5575 + int param3;
5576 + int progress0;
5577 + int progress1;
5578 + int progress2;
5579 + int progress3;
5580 + int io_time[2][2];
5581 + struct pagedir pagedir;
5582 + dev_t root_fs;
5583 +};
5584 +
5585 +extern int write_pageset(struct pagedir *pagedir);
5586 +extern int write_image_header(void);
5587 +extern int read_pageset1(void);
5588 +extern int read_pageset2(int overwrittenpagesonly);
5589 +
5590 +extern int suspend_attempt_to_parse_resume_device(int quiet);
5591 +extern void attempt_to_parse_resume_device2(void);
5592 +extern void attempt_to_parse_po_resume_device2(void);
5593 +int image_exists_read(const char *page, int count);
5594 +int image_exists_write(const char *buffer, int count);
5595 +extern void save_restore_resume2(int replace, int quiet);
5596 +
5597 +/* Args to save_restore_resume2 */
5598 +#define RESTORE 0
5599 +#define SAVE 1
5600 +
5601 +#define NOQUIET 0
5602 +#define QUIET 1
5603 +
5604 +extern dev_t name_to_dev_t(char *line);
5605 diff -Naur linux-2.6.21-ck2/kernel/power/main.c linux-2.6.21-magellan-r11/kernel/power/main.c
5606 --- linux-2.6.21-ck2/kernel/power/main.c 2007-04-26 05:08:32.000000000 +0200
5607 +++ linux-2.6.21-magellan-r11/kernel/power/main.c 2007-08-17 15:57:25.000000000 +0200
5608 @@ -155,7 +155,7 @@
5609 static const char * const pm_states[PM_SUSPEND_MAX] = {
5610 [PM_SUSPEND_STANDBY] = "standby",
5611 [PM_SUSPEND_MEM] = "mem",
5612 -#ifdef CONFIG_SOFTWARE_SUSPEND
5613 +#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SUSPEND2)
5614 [PM_SUSPEND_DISK] = "disk",
5615 #endif
5616 };
5617 diff -Naur linux-2.6.21-ck2/kernel/power/modules.c linux-2.6.21-magellan-r11/kernel/power/modules.c
5618 --- linux-2.6.21-ck2/kernel/power/modules.c 1970-01-01 01:00:00.000000000 +0100
5619 +++ linux-2.6.21-magellan-r11/kernel/power/modules.c 2007-08-17 15:57:25.000000000 +0200
5620 @@ -0,0 +1,415 @@
5621 +/*
5622 + * kernel/power/modules.c
5623 + *
5624 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
5625 + *
5626 + */
5627 +
5628 +#include <linux/suspend.h>
5629 +#include <linux/module.h>
5630 +#include "suspend.h"
5631 +#include "modules.h"
5632 +#include "sysfs.h"
5633 +#include "ui.h"
5634 +
5635 +struct list_head suspend_filters, suspendAllocators, suspend_modules;
5636 +struct suspend_module_ops *suspendActiveAllocator;
5637 +int suspend_num_filters;
5638 +int suspendNumAllocators, suspend_num_modules;
5639 +int initialised;
5640 +
5641 +static inline void suspend_initialise_module_lists(void) {
5642 + INIT_LIST_HEAD(&suspend_filters);
5643 + INIT_LIST_HEAD(&suspendAllocators);
5644 + INIT_LIST_HEAD(&suspend_modules);
5645 +}
5646 +
5647 +/*
5648 + * suspend_header_storage_for_modules
5649 + *
5650 + * Returns the amount of space needed to store configuration
5651 + * data needed by the modules prior to copying back the original
5652 + * kernel. We can exclude data for pageset2 because it will be
5653 + * available anyway once the kernel is copied back.
5654 + */
5655 +int suspend_header_storage_for_modules(void)
5656 +{
5657 + struct suspend_module_ops *this_module;
5658 + int bytes = 0;
5659 +
5660 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5661 + if (!this_module->enabled ||
5662 + (this_module->type == WRITER_MODULE &&
5663 + suspendActiveAllocator != this_module))
5664 + continue;
5665 + if (this_module->storage_needed) {
5666 + int this = this_module->storage_needed() +
5667 + sizeof(struct suspend_module_header) +
5668 + sizeof(int);
5669 + this_module->header_requested = this;
5670 + bytes += this;
5671 + }
5672 + }
5673 +
5674 + /* One more for the empty terminator */
5675 + return bytes + sizeof(struct suspend_module_header);
5676 +}
5677 +
5678 +/*
5679 + * suspend_memory_for_modules
5680 + *
5681 + * Returns the amount of memory requested by modules for
5682 + * doing their work during the cycle.
5683 + */
5684 +
5685 +int suspend_memory_for_modules(void)
5686 +{
5687 + int bytes = 0;
5688 + struct suspend_module_ops *this_module;
5689 +
5690 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5691 + if (!this_module->enabled)
5692 + continue;
5693 + if (this_module->memory_needed)
5694 + bytes += this_module->memory_needed();
5695 + }
5696 +
5697 + return ((bytes + PAGE_SIZE - 1) >> PAGE_SHIFT);
5698 +}
5699 +
5700 +/*
5701 + * suspend_expected_compression_ratio
5702 + *
5703 + * Returns the compression ratio expected when saving the image.
5704 + */
5705 +
5706 +int suspend_expected_compression_ratio(void)
5707 +{
5708 + int ratio = 100;
5709 + struct suspend_module_ops *this_module;
5710 +
5711 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5712 + if (!this_module->enabled)
5713 + continue;
5714 + if (this_module->expected_compression)
5715 + ratio = ratio * this_module->expected_compression() / 100;
5716 + }
5717 +
5718 + return ratio;
5719 +}
5720 +
5721 +/* suspend_find_module_given_name
5722 + * Functionality : Return a module (if found), given a pointer
5723 + * to its name
5724 + */
5725 +
5726 +struct suspend_module_ops *suspend_find_module_given_name(char *name)
5727 +{
5728 + struct suspend_module_ops *this_module, *found_module = NULL;
5729 +
5730 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5731 + if (!strcmp(name, this_module->name)) {
5732 + found_module = this_module;
5733 + break;
5734 + }
5735 + }
5736 +
5737 + return found_module;
5738 +}
5739 +
5740 +/*
5741 + * suspend_print_module_debug_info
5742 + * Functionality : Get debugging info from modules into a buffer.
5743 + */
5744 +int suspend_print_module_debug_info(char *buffer, int buffer_size)
5745 +{
5746 + struct suspend_module_ops *this_module;
5747 + int len = 0;
5748 +
5749 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5750 + if (!this_module->enabled)
5751 + continue;
5752 + if (this_module->print_debug_info) {
5753 + int result;
5754 + result = this_module->print_debug_info(buffer + len,
5755 + buffer_size - len);
5756 + len += result;
5757 + }
5758 + }
5759 +
5760 + /* Ensure null terminated */
5761 + buffer[buffer_size] = 0;
5762 +
5763 + return len;
5764 +}
5765 +
5766 +/*
5767 + * suspend_register_module
5768 + *
5769 + * Register a module.
5770 + */
5771 +int suspend_register_module(struct suspend_module_ops *module)
5772 +{
5773 + int i;
5774 + struct kobject *kobj;
5775 +
5776 + if (!initialised) {
5777 + suspend_initialise_module_lists();
5778 + initialised = 1;
5779 + }
5780 +
5781 + module->enabled = 1;
5782 +
5783 + if (suspend_find_module_given_name(module->name)) {
5784 + printk("Suspend2: Trying to load module %s,"
5785 + " which is already registered.\n",
5786 + module->name);
5787 + return -EBUSY;
5788 + }
5789 +
5790 + switch (module->type) {
5791 + case FILTER_MODULE:
5792 + list_add_tail(&module->type_list,
5793 + &suspend_filters);
5794 + suspend_num_filters++;
5795 + break;
5796 +
5797 + case WRITER_MODULE:
5798 + list_add_tail(&module->type_list,
5799 + &suspendAllocators);
5800 + suspendNumAllocators++;
5801 + break;
5802 +
5803 + case MISC_MODULE:
5804 + break;
5805 +
5806 + default:
5807 + printk("Hmmm. Module '%s' has an invalid type."
5808 + " It has been ignored.\n", module->name);
5809 + return -EINVAL;
5810 + }
5811 + list_add_tail(&module->module_list, &suspend_modules);
5812 + suspend_num_modules++;
5813 +
5814 + if (module->directory || module->shared_directory) {
5815 + /*
5816 + * Modules may share a directory, but those with shared_dir
5817 + * set must be loaded (via symbol dependencies) after parents
5818 + * and unloaded beforehand.
5819 + */
5820 + if (module->shared_directory) {
5821 + struct suspend_module_ops *shared =
5822 + suspend_find_module_given_name(module->shared_directory);
5823 + if (!shared) {
5824 + printk("Suspend2: Module %s wants to share %s's directory but %s isn't loaded.\n",
5825 + module->name,
5826 + module->shared_directory,
5827 + module->shared_directory);
5828 + suspend_unregister_module(module);
5829 + return -ENODEV;
5830 + }
5831 + kobj = shared->dir_kobj;
5832 + } else
5833 + kobj = make_suspend2_sysdir(module->directory);
5834 + module->dir_kobj = kobj;
5835 + for (i=0; i < module->num_sysfs_entries; i++) {
5836 + int result = suspend_register_sysfs_file(kobj, &module->sysfs_data[i]);
5837 + if (result)
5838 + return result;
5839 + }
5840 + }
5841 +
5842 + printk("Suspend2 %s support registered.\n", module->name);
5843 + return 0;
5844 +}
5845 +
5846 +/*
5847 + * suspend_unregister_module
5848 + *
5849 + * Remove a module.
5850 + */
5851 +void suspend_unregister_module(struct suspend_module_ops *module)
5852 +{
5853 + int i;
5854 +
5855 + if (module->dir_kobj)
5856 + for (i=0; i < module->num_sysfs_entries; i++)
5857 + suspend_unregister_sysfs_file(module->dir_kobj, &module->sysfs_data[i]);
5858 +
5859 + if (!module->shared_directory && module->directory)
5860 + remove_suspend2_sysdir(module->dir_kobj);
5861 +
5862 + switch (module->type) {
5863 + case FILTER_MODULE:
5864 + list_del(&module->type_list);
5865 + suspend_num_filters--;
5866 + break;
5867 +
5868 + case WRITER_MODULE:
5869 + list_del(&module->type_list);
5870 + suspendNumAllocators--;
5871 + if (suspendActiveAllocator == module) {
5872 + suspendActiveAllocator = NULL;
5873 + clear_suspend_state(SUSPEND_CAN_RESUME);
5874 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
5875 + }
5876 + break;
5877 +
5878 + case MISC_MODULE:
5879 + break;
5880 +
5881 + default:
5882 + printk("Hmmm. Module '%s' has an invalid type."
5883 + " It has been ignored.\n", module->name);
5884 + return;
5885 + }
5886 + list_del(&module->module_list);
5887 + suspend_num_modules--;
5888 + printk("Suspend2 %s module unloaded.\n", module->name);
5889 +}
5890 +
5891 +/*
5892 + * suspend_move_module_tail
5893 + *
5894 + * Rearrange modules when reloading the config.
5895 + */
5896 +void suspend_move_module_tail(struct suspend_module_ops *module)
5897 +{
5898 + switch (module->type) {
5899 + case FILTER_MODULE:
5900 + if (suspend_num_filters > 1)
5901 + list_move_tail(&module->type_list,
5902 + &suspend_filters);
5903 + break;
5904 +
5905 + case WRITER_MODULE:
5906 + if (suspendNumAllocators > 1)
5907 + list_move_tail(&module->type_list,
5908 + &suspendAllocators);
5909 + break;
5910 +
5911 + case MISC_MODULE:
5912 + break;
5913 + default:
5914 + printk("Hmmm. Module '%s' has an invalid type."
5915 + " It has been ignored.\n", module->name);
5916 + return;
5917 + }
5918 + if ((suspend_num_filters + suspendNumAllocators) > 1)
5919 + list_move_tail(&module->module_list, &suspend_modules);
5920 +}
5921 +
5922 +/*
5923 + * suspend_initialise_modules
5924 + *
5925 + * Get ready to do some work!
5926 + */
5927 +int suspend_initialise_modules(int starting_cycle)
5928 +{
5929 + struct suspend_module_ops *this_module;
5930 + int result;
5931 +
5932 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5933 + this_module->header_requested = 0;
5934 + this_module->header_used = 0;
5935 + if (!this_module->enabled)
5936 + continue;
5937 + if (this_module->initialise) {
5938 + suspend_message(SUSPEND_MEMORY, SUSPEND_MEDIUM, 1,
5939 + "Initialising module %s.\n",
5940 + this_module->name);
5941 + if ((result = this_module->initialise(starting_cycle))) {
5942 + printk("%s didn't initialise okay.\n",
5943 + this_module->name);
5944 + return result;
5945 + }
5946 + }
5947 + }
5948 +
5949 + return 0;
5950 +}
5951 +
5952 +/*
5953 + * suspend_cleanup_modules
5954 + *
5955 + * Tell modules the work is done.
5956 + */
5957 +void suspend_cleanup_modules(int finishing_cycle)
5958 +{
5959 + struct suspend_module_ops *this_module;
5960 +
5961 + list_for_each_entry(this_module, &suspend_modules, module_list) {
5962 + if (!this_module->enabled)
5963 + continue;
5964 + if (this_module->cleanup) {
5965 + suspend_message(SUSPEND_MEMORY, SUSPEND_MEDIUM, 1,
5966 + "Cleaning up module %s.\n",
5967 + this_module->name);
5968 + this_module->cleanup(finishing_cycle);
5969 + }
5970 + }
5971 +}
5972 +
5973 +/*
5974 + * suspend_get_next_filter
5975 + *
5976 + * Get the next filter in the pipeline.
5977 + */
5978 +struct suspend_module_ops *suspend_get_next_filter(struct suspend_module_ops *filter_sought)
5979 +{
5980 + struct suspend_module_ops *last_filter = NULL, *this_filter = NULL;
5981 +
5982 + list_for_each_entry(this_filter, &suspend_filters, type_list) {
5983 + if (!this_filter->enabled)
5984 + continue;
5985 + if ((last_filter == filter_sought) || (!filter_sought))
5986 + return this_filter;
5987 + last_filter = this_filter;
5988 + }
5989 +
5990 + return suspendActiveAllocator;
5991 +}
5992 +
5993 +/* suspend_get_modules
5994 + *
5995 + * Take a reference to modules so they can't go away under us.
5996 + */
5997 +
5998 +int suspend_get_modules(void)
5999 +{
6000 + struct suspend_module_ops *this_module;
6001 +
6002 + list_for_each_entry(this_module, &suspend_modules, module_list) {
6003 + if (!try_module_get(this_module->module)) {
6004 + /* Failed! Reverse gets and return error */
6005 + struct suspend_module_ops *this_module2;
6006 + list_for_each_entry(this_module2, &suspend_modules, module_list) {
6007 + if (this_module == this_module2)
6008 + return -EINVAL;
6009 + module_put(this_module2->module);
6010 + }
6011 + }
6012 + }
6013 +
6014 + return 0;
6015 +}
6016 +
6017 +/* suspend_put_modules
6018 + *
6019 + * Release our references to modules we used.
6020 + */
6021 +
6022 +void suspend_put_modules(void)
6023 +{
6024 + struct suspend_module_ops *this_module;
6025 +
6026 + list_for_each_entry(this_module, &suspend_modules, module_list)
6027 + module_put(this_module->module);
6028 +}
6029 +
6030 +#ifdef CONFIG_SUSPEND2_EXPORTS
6031 +EXPORT_SYMBOL_GPL(suspend_register_module);
6032 +EXPORT_SYMBOL_GPL(suspend_unregister_module);
6033 +EXPORT_SYMBOL_GPL(suspend_get_next_filter);
6034 +EXPORT_SYMBOL_GPL(suspendActiveAllocator);
6035 +#endif
6036 diff -Naur linux-2.6.21-ck2/kernel/power/modules.h linux-2.6.21-magellan-r11/kernel/power/modules.h
6037 --- linux-2.6.21-ck2/kernel/power/modules.h 1970-01-01 01:00:00.000000000 +0100
6038 +++ linux-2.6.21-magellan-r11/kernel/power/modules.h 2007-08-17 15:57:25.000000000 +0200
6039 @@ -0,0 +1,164 @@
6040 +/*
6041 + * kernel/power/modules.h
6042 + *
6043 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6044 + *
6045 + * This file is released under the GPLv2.
6046 + *
6047 + * It contains declarations for modules. Modules are additions to
6048 + * suspend2 that provide facilities such as image compression or
6049 + * encryption, backends for storage of the image and user interfaces.
6050 + *
6051 + */
6052 +
6053 +#ifndef SUSPEND_MODULES_H
6054 +#define SUSPEND_MODULES_H
6055 +
6056 +/* This is the maximum size we store in the image header for a module name */
6057 +#define SUSPEND_MAX_MODULE_NAME_LENGTH 30
6058 +
6059 +/* Per-module metadata */
6060 +struct suspend_module_header {
6061 + char name[SUSPEND_MAX_MODULE_NAME_LENGTH];
6062 + int enabled;
6063 + int type;
6064 + int index;
6065 + int data_length;
6066 + unsigned long signature;
6067 +};
6068 +
6069 +enum {
6070 + FILTER_MODULE,
6071 + WRITER_MODULE,
6072 + MISC_MODULE /* Block writer, eg. */
6073 +};
6074 +
6075 +enum {
6076 + SUSPEND_ASYNC,
6077 + SUSPEND_SYNC
6078 +};
6079 +
6080 +struct suspend_module_ops {
6081 + /* Functions common to all modules */
6082 + int type;
6083 + char *name;
6084 + char *directory;
6085 + char *shared_directory;
6086 + struct kobject *dir_kobj;
6087 + struct module *module;
6088 + int enabled;
6089 + struct list_head module_list;
6090 +
6091 + /* List of filters or allocators */
6092 + struct list_head list, type_list;
6093 +
6094 + /*
6095 + * Requirements for memory and storage in
6096 + * the image header..
6097 + */
6098 + int (*memory_needed) (void);
6099 + int (*storage_needed) (void);
6100 +
6101 + int header_requested, header_used;
6102 +
6103 + int (*expected_compression) (void);
6104 +
6105 + /*
6106 + * Debug info
6107 + */
6108 + int (*print_debug_info) (char *buffer, int size);
6109 + int (*save_config_info) (char *buffer);
6110 + void (*load_config_info) (char *buffer, int len);
6111 +
6112 + /*
6113 + * Initialise & cleanup - general routines called
6114 + * at the start and end of a cycle.
6115 + */
6116 + int (*initialise) (int starting_cycle);
6117 + void (*cleanup) (int finishing_cycle);
6118 +
6119 + /*
6120 + * Calls for allocating storage (allocators only).
6121 + *
6122 + * Header space is allocated separately. Note that allocation
6123 + * of space for the header might result in allocated space
6124 + * being stolen from the main pool if there is no unallocated
6125 + * space. We have to be able to allocate enough space for
6126 + * the header. We can eat memory to ensure there is enough
6127 + * for the main pool.
6128 + */
6129 +
6130 + int (*storage_available) (void);
6131 + int (*allocate_header_space) (int space_requested);
6132 + int (*allocate_storage) (int space_requested);
6133 + int (*storage_allocated) (void);
6134 + int (*release_storage) (void);
6135 +
6136 + /*
6137 + * Routines used in image I/O.
6138 + */
6139 + int (*rw_init) (int rw, int stream_number);
6140 + int (*rw_cleanup) (int rw);
6141 + int (*write_chunk) (unsigned long index, struct page *buffer_page,
6142 + unsigned int buf_size);
6143 + int (*read_chunk) (unsigned long *index, struct page *buffer_page,
6144 + unsigned int *buf_size, int sync);
6145 +
6146 + /* Reset module if image exists but reading aborted */
6147 + void (*noresume_reset) (void);
6148 +
6149 + /* Read and write the metadata */
6150 + int (*write_header_init) (void);
6151 + int (*write_header_cleanup) (void);
6152 +
6153 + int (*read_header_init) (void);
6154 + int (*read_header_cleanup) (void);
6155 +
6156 + int (*rw_header_chunk) (int rw, struct suspend_module_ops *owner,
6157 + char *buffer_start, int buffer_size);
6158 +
6159 + /* Attempt to parse an image location */
6160 + int (*parse_sig_location) (char *buffer, int only_writer, int quiet);
6161 +
6162 + /* Determine whether image exists that we can restore */
6163 + int (*image_exists) (void);
6164 +
6165 + /* Mark the image as having tried to resume */
6166 + void (*mark_resume_attempted) (int);
6167 +
6168 + /* Destroy image if one exists */
6169 + int (*invalidate_image) (void);
6170 +
6171 + /* Sysfs Data */
6172 + struct suspend_sysfs_data *sysfs_data;
6173 + int num_sysfs_entries;
6174 +};
6175 +
6176 +extern int suspend_num_modules, suspendNumAllocators;
6177 +
6178 +extern struct suspend_module_ops *suspendActiveAllocator;
6179 +extern struct list_head suspend_filters, suspendAllocators, suspend_modules;
6180 +
6181 +extern void suspend_prepare_console_modules(void);
6182 +extern void suspend_cleanup_console_modules(void);
6183 +
6184 +extern struct suspend_module_ops *suspend_find_module_given_name(char *name);
6185 +extern struct suspend_module_ops *suspend_get_next_filter(struct suspend_module_ops *);
6186 +
6187 +extern int suspend_register_module(struct suspend_module_ops *module);
6188 +extern void suspend_move_module_tail(struct suspend_module_ops *module);
6189 +
6190 +extern int suspend_header_storage_for_modules(void);
6191 +extern int suspend_memory_for_modules(void);
6192 +extern int suspend_expected_compression_ratio(void);
6193 +
6194 +extern int suspend_print_module_debug_info(char *buffer, int buffer_size);
6195 +extern int suspend_register_module(struct suspend_module_ops *module);
6196 +extern void suspend_unregister_module(struct suspend_module_ops *module);
6197 +
6198 +extern int suspend_initialise_modules(int starting_cycle);
6199 +extern void suspend_cleanup_modules(int finishing_cycle);
6200 +
6201 +int suspend_get_modules(void);
6202 +void suspend_put_modules(void);
6203 +#endif
6204 diff -Naur linux-2.6.21-ck2/kernel/power/netlink.c linux-2.6.21-magellan-r11/kernel/power/netlink.c
6205 --- linux-2.6.21-ck2/kernel/power/netlink.c 1970-01-01 01:00:00.000000000 +0100
6206 +++ linux-2.6.21-magellan-r11/kernel/power/netlink.c 2007-08-17 15:57:25.000000000 +0200
6207 @@ -0,0 +1,387 @@
6208 +/*
6209 + * kernel/power/netlink.c
6210 + *
6211 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6212 + *
6213 + * This file is released under the GPLv2.
6214 + *
6215 + * Functions for communicating with a userspace helper via netlink.
6216 + */
6217 +
6218 +
6219 +#include <linux/suspend.h>
6220 +#include "netlink.h"
6221 +#include "suspend.h"
6222 +#include "modules.h"
6223 +
6224 +struct user_helper_data *uhd_list = NULL;
6225 +
6226 +/*
6227 + * Refill our pool of SKBs for use in emergencies (eg, when eating memory and none
6228 + * can be allocated).
6229 + */
6230 +static void suspend_fill_skb_pool(struct user_helper_data *uhd)
6231 +{
6232 + while (uhd->pool_level < uhd->pool_limit) {
6233 + struct sk_buff *new_skb =
6234 + alloc_skb(NLMSG_SPACE(uhd->skb_size), GFP_ATOMIC);
6235 +
6236 + if (!new_skb)
6237 + break;
6238 +
6239 + new_skb->next = uhd->emerg_skbs;
6240 + uhd->emerg_skbs = new_skb;
6241 + uhd->pool_level++;
6242 + }
6243 +}
6244 +
6245 +/*
6246 + * Try to allocate a single skb. If we can't get one, try to use one from
6247 + * our pool.
6248 + */
6249 +static struct sk_buff *suspend_get_skb(struct user_helper_data *uhd)
6250 +{
6251 + struct sk_buff *skb =
6252 + alloc_skb(NLMSG_SPACE(uhd->skb_size), GFP_ATOMIC);
6253 +
6254 + if (skb)
6255 + return skb;
6256 +
6257 + skb = uhd->emerg_skbs;
6258 + if (skb) {
6259 + uhd->pool_level--;
6260 + uhd->emerg_skbs = skb->next;
6261 + skb->next = NULL;
6262 + }
6263 +
6264 + return skb;
6265 +}
6266 +
6267 +static void put_skb(struct user_helper_data *uhd, struct sk_buff *skb)
6268 +{
6269 + if (uhd->pool_level < uhd->pool_limit) {
6270 + skb->next = uhd->emerg_skbs;
6271 + uhd->emerg_skbs = skb;
6272 + } else
6273 + kfree_skb(skb);
6274 +}
6275 +
6276 +void suspend_send_netlink_message(struct user_helper_data *uhd,
6277 + int type, void* params, size_t len)
6278 +{
6279 + struct sk_buff *skb;
6280 + struct nlmsghdr *nlh;
6281 + void *dest;
6282 + struct task_struct *t;
6283 +
6284 + if (uhd->pid == -1)
6285 + return;
6286 +
6287 + skb = suspend_get_skb(uhd);
6288 + if (!skb) {
6289 + printk("suspend_netlink: Can't allocate skb!\n");
6290 + return;
6291 + }
6292 +
6293 + /* NLMSG_PUT contains a hidden goto nlmsg_failure */
6294 + nlh = NLMSG_PUT(skb, 0, uhd->sock_seq, type, len);
6295 + uhd->sock_seq++;
6296 +
6297 + dest = NLMSG_DATA(nlh);
6298 + if (params && len > 0)
6299 + memcpy(dest, params, len);
6300 +
6301 + netlink_unicast(uhd->nl, skb, uhd->pid, 0);
6302 +
6303 + read_lock(&tasklist_lock);
6304 + if ((t = find_task_by_pid(uhd->pid)) == NULL) {
6305 + read_unlock(&tasklist_lock);
6306 + if (uhd->pid > -1)
6307 + printk("Hmm. Can't find the userspace task %d.\n", uhd->pid);
6308 + return;
6309 + }
6310 + wake_up_process(t);
6311 + read_unlock(&tasklist_lock);
6312 +
6313 + yield();
6314 +
6315 + return;
6316 +
6317 +nlmsg_failure:
6318 + if (skb)
6319 + put_skb(uhd, skb);
6320 +}
6321 +
6322 +static void send_whether_debugging(struct user_helper_data *uhd)
6323 +{
6324 + static int is_debugging = 1;
6325 +
6326 + suspend_send_netlink_message(uhd, NETLINK_MSG_IS_DEBUGGING,
6327 + &is_debugging, sizeof(int));
6328 +}
6329 +
6330 +/*
6331 + * Set the PF_NOFREEZE flag on the given process to ensure it can run whilst we
6332 + * are suspending.
6333 + */
6334 +static int nl_set_nofreeze(struct user_helper_data *uhd, int pid)
6335 +{
6336 + struct task_struct *t;
6337 +
6338 + read_lock(&tasklist_lock);
6339 + if ((t = find_task_by_pid(pid)) == NULL) {
6340 + read_unlock(&tasklist_lock);
6341 + printk("Strange. Can't find the userspace task %d.\n", pid);
6342 + return -EINVAL;
6343 + }
6344 +
6345 + t->flags |= PF_NOFREEZE;
6346 +
6347 + read_unlock(&tasklist_lock);
6348 + uhd->pid = pid;
6349 +
6350 + suspend_send_netlink_message(uhd, NETLINK_MSG_NOFREEZE_ACK, NULL, 0);
6351 +
6352 + return 0;
6353 +}
6354 +
6355 +/*
6356 + * Called when the userspace process has informed us that it's ready to roll.
6357 + */
6358 +static int nl_ready(struct user_helper_data *uhd, int version)
6359 +{
6360 + if (version != uhd->interface_version) {
6361 + printk("%s userspace process using invalid interface version."
6362 + " Trying to continue without it.\n",
6363 + uhd->name);
6364 + if (uhd->not_ready)
6365 + uhd->not_ready();
6366 + return 1;
6367 + }
6368 +
6369 + complete(&uhd->wait_for_process);
6370 +
6371 + return 0;
6372 +}
6373 +
6374 +void suspend_netlink_close_complete(struct user_helper_data *uhd)
6375 +{
6376 + if (uhd->nl) {
6377 + sock_release(uhd->nl->sk_socket);
6378 + uhd->nl = NULL;
6379 + }
6380 +
6381 + while (uhd->emerg_skbs) {
6382 + struct sk_buff *next = uhd->emerg_skbs->next;
6383 + kfree_skb(uhd->emerg_skbs);
6384 + uhd->emerg_skbs = next;
6385 + }
6386 +
6387 + uhd->pid = -1;
6388 +
6389 + suspend_put_modules();
6390 +}
6391 +
6392 +static int suspend_nl_gen_rcv_msg(struct user_helper_data *uhd,
6393 + struct sk_buff *skb, struct nlmsghdr *nlh)
6394 +{
6395 + int type;
6396 + int *data;
6397 + int err;
6398 +
6399 + /* Let the more specific handler go first. It returns
6400 + * 1 for valid messages that it doesn't know. */
6401 + if ((err = uhd->rcv_msg(skb, nlh)) != 1)
6402 + return err;
6403 +
6404 + type = nlh->nlmsg_type;
6405 +
6406 + /* Only allow one task to receive NOFREEZE privileges */
6407 + if (type == NETLINK_MSG_NOFREEZE_ME && uhd->pid != -1) {
6408 + printk("Received extra nofreeze me requests.\n");
6409 + return -EBUSY;
6410 + }
6411 +
6412 + data = (int*)NLMSG_DATA(nlh);
6413 +
6414 + switch (type) {
6415 + case NETLINK_MSG_NOFREEZE_ME:
6416 + if ((err = nl_set_nofreeze(uhd, nlh->nlmsg_pid)) != 0)
6417 + return err;
6418 + break;
6419 + case NETLINK_MSG_GET_DEBUGGING:
6420 + send_whether_debugging(uhd);
6421 + break;
6422 + case NETLINK_MSG_READY:
6423 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
6424 + printk("Invalid ready mesage.\n");
6425 + return -EINVAL;
6426 + }
6427 + if ((err = nl_ready(uhd, *data)) != 0)
6428 + return err;
6429 + break;
6430 + case NETLINK_MSG_CLEANUP:
6431 + suspend_netlink_close_complete(uhd);
6432 + break;
6433 + }
6434 +
6435 + return 0;
6436 +}
6437 +
6438 +static void suspend_user_rcv_skb(struct user_helper_data *uhd,
6439 + struct sk_buff *skb)
6440 +{
6441 + int err;
6442 + struct nlmsghdr *nlh;
6443 +
6444 + while (skb->len >= NLMSG_SPACE(0)) {
6445 + u32 rlen;
6446 +
6447 + nlh = (struct nlmsghdr *) skb->data;
6448 + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
6449 + return;
6450 +
6451 + rlen = NLMSG_ALIGN(nlh->nlmsg_len);
6452 + if (rlen > skb->len)
6453 + rlen = skb->len;
6454 +
6455 + if ((err = suspend_nl_gen_rcv_msg(uhd, skb, nlh)) != 0)
6456 + netlink_ack(skb, nlh, err);
6457 + else if (nlh->nlmsg_flags & NLM_F_ACK)
6458 + netlink_ack(skb, nlh, 0);
6459 + skb_pull(skb, rlen);
6460 + }
6461 +}
6462 +
6463 +static void suspend_netlink_input(struct sock *sk, int len)
6464 +{
6465 + struct user_helper_data *uhd = uhd_list;
6466 +
6467 + while (uhd && uhd->netlink_id != sk->sk_protocol)
6468 + uhd= uhd->next;
6469 +
6470 + do {
6471 + struct sk_buff *skb;
6472 + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
6473 + suspend_user_rcv_skb(uhd, skb);
6474 + put_skb(uhd, skb);
6475 + }
6476 + } while (uhd->nl && uhd->nl->sk_receive_queue.qlen);
6477 +}
6478 +
6479 +static int netlink_prepare(struct user_helper_data *uhd)
6480 +{
6481 + suspend_get_modules();
6482 +
6483 + uhd->next = uhd_list;
6484 + uhd_list = uhd;
6485 +
6486 + uhd->sock_seq = 0x42c0ffee;
6487 + uhd->nl = netlink_kernel_create(uhd->netlink_id, 0,
6488 + suspend_netlink_input, THIS_MODULE);
6489 + if (!uhd->nl) {
6490 + printk("Failed to allocate netlink socket for %s.\n",
6491 + uhd->name);
6492 + return -ENOMEM;
6493 + }
6494 +
6495 + suspend_fill_skb_pool(uhd);
6496 +
6497 + return 0;
6498 +}
6499 +
6500 +void suspend_netlink_close(struct user_helper_data *uhd)
6501 +{
6502 + struct task_struct *t;
6503 +
6504 + read_lock(&tasklist_lock);
6505 + if ((t = find_task_by_pid(uhd->pid)))
6506 + t->flags &= ~PF_NOFREEZE;
6507 + read_unlock(&tasklist_lock);
6508 +
6509 + suspend_send_netlink_message(uhd, NETLINK_MSG_CLEANUP, NULL, 0);
6510 +}
6511 +
6512 +static int suspend2_launch_userspace_program(char *command, int channel_no)
6513 +{
6514 + int retval;
6515 + static char *envp[] = {
6516 + "HOME=/",
6517 + "TERM=linux",
6518 + "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
6519 + NULL };
6520 + static char *argv[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
6521 + char *channel = kmalloc(6, GFP_KERNEL);
6522 + int arg = 0, size;
6523 + char test_read[255];
6524 + char *orig_posn = command;
6525 +
6526 + if (!strlen(orig_posn))
6527 + return 1;
6528 +
6529 + /* Up to 7 args supported */
6530 + while (arg < 7) {
6531 + sscanf(orig_posn, "%s", test_read);
6532 + size = strlen(test_read);
6533 + if (!(size))
6534 + break;
6535 + argv[arg] = kmalloc(size + 1, GFP_ATOMIC);
6536 + strcpy(argv[arg], test_read);
6537 + orig_posn += size + 1;
6538 + *test_read = 0;
6539 + arg++;
6540 + }
6541 +
6542 + if (channel_no) {
6543 + sprintf(channel, "-c%d", channel_no);
6544 + argv[arg] = channel;
6545 + } else
6546 + arg--;
6547 +
6548 + retval = call_usermodehelper(argv[0], argv, envp, 0);
6549 +
6550 + if (retval)
6551 + printk("Failed to launch userspace program '%s': Error %d\n",
6552 + command, retval);
6553 +
6554 + {
6555 + int i;
6556 + for (i = 0; i < arg; i++)
6557 + if (argv[i] && argv[i] != channel)
6558 + kfree(argv[i]);
6559 + }
6560 +
6561 + kfree(channel);
6562 +
6563 + return retval;
6564 +}
6565 +
6566 +int suspend_netlink_setup(struct user_helper_data *uhd)
6567 +{
6568 + if (netlink_prepare(uhd) < 0) {
6569 + printk("Netlink prepare failed.\n");
6570 + return 1;
6571 + }
6572 +
6573 + if (suspend2_launch_userspace_program(uhd->program, uhd->netlink_id) < 0) {
6574 + printk("Launch userspace program failed.\n");
6575 + suspend_netlink_close_complete(uhd);
6576 + return 1;
6577 + }
6578 +
6579 + /* Wait 2 seconds for the userspace process to make contact */
6580 + wait_for_completion_timeout(&uhd->wait_for_process, 2*HZ);
6581 +
6582 + if (uhd->pid == -1) {
6583 + printk("%s: Failed to contact userspace process.\n",
6584 + uhd->name);
6585 + suspend_netlink_close_complete(uhd);
6586 + return 1;
6587 + }
6588 +
6589 + return 0;
6590 +}
6591 +
6592 +EXPORT_SYMBOL_GPL(suspend_netlink_setup);
6593 +EXPORT_SYMBOL_GPL(suspend_netlink_close);
6594 +EXPORT_SYMBOL_GPL(suspend_send_netlink_message);
6595 diff -Naur linux-2.6.21-ck2/kernel/power/netlink.h linux-2.6.21-magellan-r11/kernel/power/netlink.h
6596 --- linux-2.6.21-ck2/kernel/power/netlink.h 1970-01-01 01:00:00.000000000 +0100
6597 +++ linux-2.6.21-magellan-r11/kernel/power/netlink.h 2007-08-17 15:57:25.000000000 +0200
6598 @@ -0,0 +1,58 @@
6599 +/*
6600 + * kernel/power/netlink.h
6601 + *
6602 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
6603 + *
6604 + * This file is released under the GPLv2.
6605 + *
6606 + * Declarations for functions for communicating with a userspace helper
6607 + * via netlink.
6608 + */
6609 +
6610 +#include <linux/netlink.h>
6611 +#include <net/sock.h>
6612 +
6613 +#define NETLINK_MSG_BASE 0x10
6614 +
6615 +#define NETLINK_MSG_READY 0x10
6616 +#define NETLINK_MSG_NOFREEZE_ME 0x16
6617 +#define NETLINK_MSG_GET_DEBUGGING 0x19
6618 +#define NETLINK_MSG_CLEANUP 0x24
6619 +#define NETLINK_MSG_NOFREEZE_ACK 0x27
6620 +#define NETLINK_MSG_IS_DEBUGGING 0x28
6621 +
6622 +struct user_helper_data {
6623 + int (*rcv_msg) (struct sk_buff *skb, struct nlmsghdr *nlh);
6624 + void (* not_ready) (void);
6625 + struct sock *nl;
6626 + u32 sock_seq;
6627 + pid_t pid;
6628 + char *comm;
6629 + char program[256];
6630 + int pool_level;
6631 + int pool_limit;
6632 + struct sk_buff *emerg_skbs;
6633 + int skb_size;
6634 + int netlink_id;
6635 + char *name;
6636 + struct user_helper_data *next;
6637 + struct completion wait_for_process;
6638 + int interface_version;
6639 + int must_init;
6640 +};
6641 +
6642 +#ifdef CONFIG_NET
6643 +int suspend_netlink_setup(struct user_helper_data *uhd);
6644 +void suspend_netlink_close(struct user_helper_data *uhd);
6645 +void suspend_send_netlink_message(struct user_helper_data *uhd,
6646 + int type, void* params, size_t len);
6647 +#else
6648 +static inline int suspend_netlink_setup(struct user_helper_data *uhd)
6649 +{
6650 + return 0;
6651 +}
6652 +
6653 +static inline void suspend_netlink_close(struct user_helper_data *uhd) { };
6654 +static inline void suspend_send_netlink_message(struct user_helper_data *uhd,
6655 + int type, void* params, size_t len) { };
6656 +#endif
6657 diff -Naur linux-2.6.21-ck2/kernel/power/pagedir.c linux-2.6.21-magellan-r11/kernel/power/pagedir.c
6658 --- linux-2.6.21-ck2/kernel/power/pagedir.c 1970-01-01 01:00:00.000000000 +0100
6659 +++ linux-2.6.21-magellan-r11/kernel/power/pagedir.c 2007-08-17 15:57:25.000000000 +0200
6660 @@ -0,0 +1,480 @@
6661 +/*
6662 + * kernel/power/pagedir.c
6663 + *
6664 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
6665 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
6666 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
6667 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
6668 + *
6669 + * This file is released under the GPLv2.
6670 + *
6671 + * Routines for handling pagesets.
6672 + * Note that pbes aren't actually stored as such. They're stored as
6673 + * bitmaps and extents.
6674 + */
6675 +
6676 +#include <linux/suspend.h>
6677 +#include <linux/highmem.h>
6678 +#include <linux/bootmem.h>
6679 +#include <linux/hardirq.h>
6680 +#include <linux/sched.h>
6681 +#include <asm/tlbflush.h>
6682 +
6683 +#include "pageflags.h"
6684 +#include "ui.h"
6685 +#include "pagedir.h"
6686 +#include "prepare_image.h"
6687 +#include "suspend.h"
6688 +#include "power.h"
6689 +#include "suspend2_builtin.h"
6690 +
6691 +#define PAGESET1 0
6692 +#define PAGESET2 1
6693 +
6694 +static int ps2_pfn;
6695 +
6696 +/*
6697 + * suspend_mark_task_as_pageset
6698 + * Functionality : Marks all the saveable pages belonging to a given process
6699 + * as belonging to a particular pageset.
6700 + */
6701 +
6702 +static void suspend_mark_task_as_pageset(struct task_struct *t, int pageset2)
6703 +{
6704 + struct vm_area_struct *vma;
6705 + struct mm_struct *mm;
6706 +
6707 + mm = t->active_mm;
6708 +
6709 + if (!mm || !mm->mmap) return;
6710 +
6711 + if (!irqs_disabled())
6712 + down_read(&mm->mmap_sem);
6713 +
6714 + for (vma = mm->mmap; vma; vma = vma->vm_next) {
6715 + unsigned long posn;
6716 +
6717 + if (vma->vm_flags & (VM_PFNMAP | VM_IO | VM_RESERVED)) {
6718 + printk("Skipping vma %p in process %d (%s) which has "
6719 + "VM_PFNMAP | VM_IO | VM_RESERVED (%lx).\n", vma,
6720 + t->pid, t->comm, vma->vm_flags);
6721 + continue;
6722 + }
6723 +
6724 + if (!vma->vm_start)
6725 + continue;
6726 +
6727 + for (posn = vma->vm_start; posn < vma->vm_end;
6728 + posn += PAGE_SIZE) {
6729 + struct page *page = follow_page(vma, posn, 0);
6730 + if (!page)
6731 + continue;
6732 +
6733 + if (pageset2)
6734 + SetPagePageset2(page);
6735 + else {
6736 + ClearPagePageset2(page);
6737 + SetPagePageset1(page);
6738 + }
6739 + }
6740 + }
6741 +
6742 + if (!irqs_disabled())
6743 + up_read(&mm->mmap_sem);
6744 +}
6745 +
6746 +static void pageset2_full(void)
6747 +{
6748 + struct zone *zone;
6749 + unsigned long flags;
6750 +
6751 + for_each_zone(zone) {
6752 + spin_lock_irqsave(&zone->lru_lock, flags);
6753 + if (zone_page_state(zone, NR_INACTIVE)) {
6754 + struct page *page;
6755 + list_for_each_entry(page, &zone->inactive_list, lru)
6756 + SetPagePageset2(page);
6757 + }
6758 + if (zone_page_state(zone, NR_ACTIVE)) {
6759 + struct page *page;
6760 + list_for_each_entry(page, &zone->active_list, lru)
6761 + SetPagePageset2(page);
6762 + }
6763 + spin_unlock_irqrestore(&zone->lru_lock, flags);
6764 + }
6765 +}
6766 +
6767 +/* mark_pages_for_pageset2
6768 + *
6769 + * Description: Mark unshared pages in processes not needed for suspend as
6770 + * being able to be written out in a separate pagedir.
6771 + * HighMem pages are simply marked as pageset2. They won't be
6772 + * needed during suspend.
6773 + */
6774 +
6775 +struct attention_list {
6776 + struct task_struct *task;
6777 + struct attention_list *next;
6778 +};
6779 +
6780 +void suspend_mark_pages_for_pageset2(void)
6781 +{
6782 + struct task_struct *p;
6783 + struct attention_list *attention_list = NULL, *last = NULL, *next;
6784 + int i, task_count = 0;
6785 +
6786 + if (test_action_state(SUSPEND_NO_PAGESET2))
6787 + return;
6788 +
6789 + clear_dyn_pageflags(pageset2_map);
6790 +
6791 + if (test_action_state(SUSPEND_PAGESET2_FULL))
6792 + pageset2_full();
6793 + else {
6794 + read_lock(&tasklist_lock);
6795 + for_each_process(p) {
6796 + if (!p->mm || (p->flags & PF_BORROWED_MM))
6797 + continue;
6798 +
6799 + suspend_mark_task_as_pageset(p, PAGESET2);
6800 + }
6801 + read_unlock(&tasklist_lock);
6802 + }
6803 +
6804 + /*
6805 + * Now we count all userspace process (with task->mm) marked PF_NOFREEZE.
6806 + */
6807 + read_lock(&tasklist_lock);
6808 + for_each_process(p)
6809 + if ((p->flags & PF_NOFREEZE) || p == current)
6810 + task_count++;
6811 + read_unlock(&tasklist_lock);
6812 +
6813 + /*
6814 + * Allocate attention list structs.
6815 + */
6816 + for (i = 0; i < task_count; i++) {
6817 + struct attention_list *this =
6818 + kmalloc(sizeof(struct attention_list), GFP_ATOMIC);
6819 + if (!this) {
6820 + printk("Failed to allocate slab for attention list.\n");
6821 + set_result_state(SUSPEND_ABORTED);
6822 + goto free_attention_list;
6823 + }
6824 + this->next = NULL;
6825 + if (attention_list) {
6826 + last->next = this;
6827 + last = this;
6828 + } else
6829 + attention_list = last = this;
6830 + }
6831 +
6832 + next = attention_list;
6833 + read_lock(&tasklist_lock);
6834 + for_each_process(p)
6835 + if ((p->flags & PF_NOFREEZE) || p == current) {
6836 + next->task = p;
6837 + next = next->next;
6838 + }
6839 + read_unlock(&tasklist_lock);
6840 +
6841 + /*
6842 + * Because the tasks in attention_list are ones related to suspending,
6843 + * we know that they won't go away under us.
6844 + */
6845 +
6846 +free_attention_list:
6847 + while (attention_list) {
6848 + if (!test_result_state(SUSPEND_ABORTED))
6849 + suspend_mark_task_as_pageset(attention_list->task, PAGESET1);
6850 + last = attention_list;
6851 + attention_list = attention_list->next;
6852 + kfree(last);
6853 + }
6854 +}
6855 +
6856 +void suspend_reset_alt_image_pageset2_pfn(void)
6857 +{
6858 + ps2_pfn = max_pfn + 1;
6859 +}
6860 +
6861 +static struct page *first_conflicting_page;
6862 +
6863 +/*
6864 + * free_conflicting_pages
6865 + */
6866 +
6867 +void free_conflicting_pages(void)
6868 +{
6869 + while (first_conflicting_page) {
6870 + struct page *next = *((struct page **) kmap(first_conflicting_page));
6871 + kunmap(first_conflicting_page);
6872 + __free_page(first_conflicting_page);
6873 + first_conflicting_page = next;
6874 + }
6875 +}
6876 +
6877 +/* __suspend_get_nonconflicting_page
6878 + *
6879 + * Description: Gets order zero pages that won't be overwritten
6880 + * while copying the original pages.
6881 + */
6882 +
6883 +struct page * ___suspend_get_nonconflicting_page(int can_be_highmem)
6884 +{
6885 + struct page *page;
6886 + int flags = GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO;
6887 + if (can_be_highmem)
6888 + flags |= __GFP_HIGHMEM;
6889 +
6890 +
6891 + if (test_suspend_state(SUSPEND_LOADING_ALT_IMAGE) && pageset2_map &&
6892 + (ps2_pfn < (max_pfn + 2))) {
6893 + /*
6894 + * ps2_pfn = max_pfn + 1 when yet to find first ps2 pfn that can
6895 + * be used.
6896 + * = 0..max_pfn when going through list.
6897 + * = max_pfn + 2 when gone through whole list.
6898 + */
6899 + do {
6900 + ps2_pfn = get_next_bit_on(pageset2_map, ps2_pfn);
6901 + if (ps2_pfn <= max_pfn) {
6902 + page = pfn_to_page(ps2_pfn);
6903 + if (!PagePageset1(page) &&
6904 + (can_be_highmem || !PageHighMem(page)))
6905 + return page;
6906 + } else
6907 + ps2_pfn++;
6908 + } while (ps2_pfn < max_pfn);
6909 + }
6910 +
6911 + do {
6912 + page = alloc_pages(flags, 0);
6913 + if (!page) {
6914 + printk("Failed to get nonconflicting page.\n");
6915 + return 0;
6916 + }
6917 + if (PagePageset1(page)) {
6918 + struct page **next = (struct page **) kmap(page);
6919 + *next = first_conflicting_page;
6920 + first_conflicting_page = page;
6921 + kunmap(page);
6922 + }
6923 + } while(PagePageset1(page));
6924 +
6925 + return page;
6926 +}
6927 +
6928 +unsigned long __suspend_get_nonconflicting_page(void)
6929 +{
6930 + struct page *page = ___suspend_get_nonconflicting_page(0);
6931 + return page ? (unsigned long) page_address(page) : 0;
6932 +}
6933 +
6934 +struct pbe *get_next_pbe(struct page **page_ptr, struct pbe *this_pbe, int highmem)
6935 +{
6936 + if (((((unsigned long) this_pbe) & (PAGE_SIZE - 1))
6937 + + 2 * sizeof(struct pbe)) > PAGE_SIZE) {
6938 + struct page *new_page =
6939 + ___suspend_get_nonconflicting_page(highmem);
6940 + if (!new_page)
6941 + return ERR_PTR(-ENOMEM);
6942 + this_pbe = (struct pbe *) kmap(new_page);
6943 + memset(this_pbe, 0, PAGE_SIZE);
6944 + *page_ptr = new_page;
6945 + } else
6946 + this_pbe++;
6947 +
6948 + return this_pbe;
6949 +}
6950 +
6951 +/* get_pageset1_load_addresses
6952 + *
6953 + * Description: We check here that pagedir & pages it points to won't collide
6954 + * with pages where we're going to restore from the loaded pages
6955 + * later.
6956 + * Returns: Zero on success, one if couldn't find enough pages (shouldn't
6957 + * happen).
6958 + */
6959 +
6960 +int suspend_get_pageset1_load_addresses(void)
6961 +{
6962 + int pfn, highallocd = 0, lowallocd = 0;
6963 + int low_needed = pagedir1.size - get_highmem_size(pagedir1);
6964 + int high_needed = get_highmem_size(pagedir1);
6965 + int low_pages_for_highmem = 0;
6966 + unsigned long flags = GFP_ATOMIC | __GFP_NOWARN | __GFP_HIGHMEM;
6967 + struct page *page, *high_pbe_page = NULL, *last_high_pbe_page = NULL,
6968 + *low_pbe_page;
6969 + struct pbe **last_low_pbe_ptr = &restore_pblist,
6970 + **last_high_pbe_ptr = &restore_highmem_pblist,
6971 + *this_low_pbe = NULL, *this_high_pbe = NULL;
6972 + int orig_low_pfn = max_pfn + 1, orig_high_pfn = max_pfn + 1;
6973 + int high_pbes_done=0, low_pbes_done=0;
6974 + int low_direct = 0, high_direct = 0;
6975 + int high_to_free, low_to_free;
6976 +
6977 + /* First, allocate pages for the start of our pbe lists. */
6978 + if (high_needed) {
6979 + high_pbe_page = ___suspend_get_nonconflicting_page(1);
6980 + if (!high_pbe_page)
6981 + return 1;
6982 + this_high_pbe = (struct pbe *) kmap(high_pbe_page);
6983 + memset(this_high_pbe, 0, PAGE_SIZE);
6984 + }
6985 +
6986 + low_pbe_page = ___suspend_get_nonconflicting_page(0);
6987 + if (!low_pbe_page)
6988 + return 1;
6989 + this_low_pbe = (struct pbe *) page_address(low_pbe_page);
6990 +
6991 + /*
6992 + * Next, allocate all possible memory to find where we can
6993 + * load data directly into destination pages. I'd like to do
6994 + * this in bigger chunks, but then we can't free pages
6995 + * individually later.
6996 + */
6997 +
6998 + do {
6999 + page = alloc_pages(flags, 0);
7000 + if (page)
7001 + SetPagePageset1Copy(page);
7002 + } while (page);
7003 +
7004 + /*
7005 + * Find out how many high- and lowmem pages we allocated above,
7006 + * and how many pages we can reload directly to their original
7007 + * location.
7008 + */
7009 + BITMAP_FOR_EACH_SET(pageset1_copy_map, pfn) {
7010 + int is_high;
7011 + page = pfn_to_page(pfn);
7012 + is_high = PageHighMem(page);
7013 +
7014 + if (PagePageset1(page)) {
7015 + if (test_action_state(SUSPEND_NO_DIRECT_LOAD)) {
7016 + ClearPagePageset1Copy(page);
7017 + __free_page(page);
7018 + continue;
7019 + } else {
7020 + if (is_high)
7021 + high_direct++;
7022 + else
7023 + low_direct++;
7024 + }
7025 + } else {
7026 + if (is_high)
7027 + highallocd++;
7028 + else
7029 + lowallocd++;
7030 + }
7031 + }
7032 +
7033 + high_needed-= high_direct;
7034 + low_needed-= low_direct;
7035 +
7036 + /*
7037 + * Do we need to use some lowmem pages for the copies of highmem
7038 + * pages?
7039 + */
7040 + if (high_needed > highallocd) {
7041 + low_pages_for_highmem = high_needed - highallocd;
7042 + high_needed -= low_pages_for_highmem;
7043 + low_needed += low_pages_for_highmem;
7044 + }
7045 +
7046 + high_to_free = highallocd - high_needed;
7047 + low_to_free = lowallocd - low_needed;
7048 +
7049 + /*
7050 + * Now generate our pbes (which will be used for the atomic restore,
7051 + * and free unneeded pages.
7052 + */
7053 + BITMAP_FOR_EACH_SET(pageset1_copy_map, pfn) {
7054 + int is_high;
7055 + page = pfn_to_page(pfn);
7056 + is_high = PageHighMem(page);
7057 +
7058 + if (PagePageset1(page))
7059 + continue;
7060 +
7061 + /* Free the page? */
7062 + if ((is_high && high_to_free) ||
7063 + (!is_high && low_to_free)) {
7064 + ClearPagePageset1Copy(page);
7065 + __free_page(page);
7066 + if (is_high)
7067 + high_to_free--;
7068 + else
7069 + low_to_free--;
7070 + continue;
7071 + }
7072 +
7073 + /* Nope. We're going to use this page. Add a pbe. */
7074 + if (is_high || low_pages_for_highmem) {
7075 + struct page *orig_page;
7076 + high_pbes_done++;
7077 + if (!is_high)
7078 + low_pages_for_highmem--;
7079 + do {
7080 + orig_high_pfn = get_next_bit_on(pageset1_map,
7081 + orig_high_pfn);
7082 + BUG_ON(orig_high_pfn > max_pfn);
7083 + orig_page = pfn_to_page(orig_high_pfn);
7084 + } while(!PageHighMem(orig_page) || load_direct(orig_page));
7085 +
7086 + this_high_pbe->orig_address = orig_page;
7087 + this_high_pbe->address = page;
7088 + this_high_pbe->next = NULL;
7089 + if (last_high_pbe_page != high_pbe_page) {
7090 + *last_high_pbe_ptr = (struct pbe *) high_pbe_page;
7091 + if (!last_high_pbe_page)
7092 + last_high_pbe_page = high_pbe_page;
7093 + } else
7094 + *last_high_pbe_ptr = this_high_pbe;
7095 + last_high_pbe_ptr = &this_high_pbe->next;
7096 + if (last_high_pbe_page != high_pbe_page) {
7097 + kunmap(last_high_pbe_page);
7098 + last_high_pbe_page = high_pbe_page;
7099 + }
7100 + this_high_pbe = get_next_pbe(&high_pbe_page, this_high_pbe, 1);
7101 + if (IS_ERR(this_high_pbe)) {
7102 + printk("This high pbe is an error.\n");
7103 + return -ENOMEM;
7104 + }
7105 + } else {
7106 + struct page *orig_page;
7107 + low_pbes_done++;
7108 + do {
7109 + orig_low_pfn = get_next_bit_on(pageset1_map,
7110 + orig_low_pfn);
7111 + BUG_ON(orig_low_pfn > max_pfn);
7112 + orig_page = pfn_to_page(orig_low_pfn);
7113 + } while(PageHighMem(orig_page) || load_direct(orig_page));
7114 +
7115 + this_low_pbe->orig_address = page_address(orig_page);
7116 + this_low_pbe->address = page_address(page);
7117 + this_low_pbe->next = NULL;
7118 + *last_low_pbe_ptr = this_low_pbe;
7119 + last_low_pbe_ptr = &this_low_pbe->next;
7120 + this_low_pbe = get_next_pbe(&low_pbe_page, this_low_pbe, 0);
7121 + if (IS_ERR(this_low_pbe)) {
7122 + printk("this_low_pbe is an error.\n");
7123 + return -ENOMEM;
7124 + }
7125 + }
7126 + }
7127 +
7128 + if (high_pbe_page)
7129 + kunmap(high_pbe_page);
7130 +
7131 + if (last_high_pbe_page != high_pbe_page) {
7132 + if (last_high_pbe_page)
7133 + kunmap(last_high_pbe_page);
7134 + __free_page(high_pbe_page);
7135 + }
7136 +
7137 + free_conflicting_pages();
7138 +
7139 + return 0;
7140 +}
7141 diff -Naur linux-2.6.21-ck2/kernel/power/pagedir.h linux-2.6.21-magellan-r11/kernel/power/pagedir.h
7142 --- linux-2.6.21-ck2/kernel/power/pagedir.h 1970-01-01 01:00:00.000000000 +0100
7143 +++ linux-2.6.21-magellan-r11/kernel/power/pagedir.h 2007-08-17 15:57:25.000000000 +0200
7144 @@ -0,0 +1,51 @@
7145 +/*
7146 + * kernel/power/pagedir.h
7147 + *
7148 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7149 + *
7150 + * This file is released under the GPLv2.
7151 + *
7152 + * Declarations for routines for handling pagesets.
7153 + */
7154 +
7155 +#ifndef KERNEL_POWER_PAGEDIR_H
7156 +#define KERNEL_POWER_PAGEDIR_H
7157 +
7158 +/* Pagedir
7159 + *
7160 + * Contains the metadata for a set of pages saved in the image.
7161 + */
7162 +
7163 +struct pagedir {
7164 + int id;
7165 + int size;
7166 +#ifdef CONFIG_HIGHMEM
7167 + int size_high;
7168 +#endif
7169 +};
7170 +
7171 +#ifdef CONFIG_HIGHMEM
7172 +#define get_highmem_size(pagedir) (pagedir.size_high)
7173 +#define set_highmem_size(pagedir, sz) do { pagedir.size_high = sz; } while(0)
7174 +#define inc_highmem_size(pagedir) do { pagedir.size_high++; } while(0)
7175 +#define get_lowmem_size(pagedir) (pagedir.size - pagedir.size_high)
7176 +#else
7177 +#define get_highmem_size(pagedir) (0)
7178 +#define set_highmem_size(pagedir, sz) do { } while(0)
7179 +#define inc_highmem_size(pagedir) do { } while(0)
7180 +#define get_lowmem_size(pagedir) (pagedir.size)
7181 +#endif
7182 +
7183 +extern struct pagedir pagedir1, pagedir2;
7184 +
7185 +extern void suspend_copy_pageset1(void);
7186 +
7187 +extern void suspend_mark_pages_for_pageset2(void);
7188 +
7189 +extern int suspend_get_pageset1_load_addresses(void);
7190 +
7191 +extern unsigned long __suspend_get_nonconflicting_page(void);
7192 +struct page * ___suspend_get_nonconflicting_page(int can_be_highmem);
7193 +
7194 +extern void suspend_reset_alt_image_pageset2_pfn(void);
7195 +#endif
7196 diff -Naur linux-2.6.21-ck2/kernel/power/pageflags.c linux-2.6.21-magellan-r11/kernel/power/pageflags.c
7197 --- linux-2.6.21-ck2/kernel/power/pageflags.c 1970-01-01 01:00:00.000000000 +0100
7198 +++ linux-2.6.21-magellan-r11/kernel/power/pageflags.c 2007-08-17 15:57:25.000000000 +0200
7199 @@ -0,0 +1,149 @@
7200 +/*
7201 + * kernel/power/pageflags.c
7202 + *
7203 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7204 + *
7205 + * This file is released under the GPLv2.
7206 + *
7207 + * Routines for serialising and relocating pageflags in which we
7208 + * store our image metadata.
7209 + */
7210 +
7211 +#include <linux/kernel.h>
7212 +#include <linux/mm.h>
7213 +#include <linux/module.h>
7214 +#include <linux/bitops.h>
7215 +#include <linux/list.h>
7216 +#include <linux/suspend.h>
7217 +#include "pageflags.h"
7218 +#include "modules.h"
7219 +#include "pagedir.h"
7220 +#include "suspend.h"
7221 +
7222 +dyn_pageflags_t pageset2_map;
7223 +dyn_pageflags_t page_resave_map;
7224 +dyn_pageflags_t io_map;
7225 +
7226 +static int pages_for_zone(struct zone *zone)
7227 +{
7228 + return DIV_ROUND_UP(zone->spanned_pages, (PAGE_SIZE << 3));
7229 +}
7230 +
7231 +int suspend_pageflags_space_needed(void)
7232 +{
7233 + int total = 0;
7234 + struct zone *zone;
7235 +
7236 + for_each_zone(zone)
7237 + if (populated_zone(zone))
7238 + total += sizeof(int) * 3 + pages_for_zone(zone) * PAGE_SIZE;
7239 +
7240 + total += sizeof(int);
7241 +
7242 + return total;
7243 +}
7244 +
7245 +/* save_dyn_pageflags
7246 + *
7247 + * Description: Save a set of pageflags.
7248 + * Arguments: dyn_pageflags_t *: Pointer to the bitmap being saved.
7249 + */
7250 +
7251 +void save_dyn_pageflags(dyn_pageflags_t pagemap)
7252 +{
7253 + int i, zone_idx, size, node = 0;
7254 + struct zone *zone;
7255 + struct pglist_data *pgdat;
7256 +
7257 + if (!*pagemap)
7258 + return;
7259 +
7260 + for_each_online_pgdat(pgdat) {
7261 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
7262 + zone = &pgdat->node_zones[zone_idx];
7263 +
7264 + if (!populated_zone(zone))
7265 + continue;
7266 +
7267 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7268 + (char *) &node, sizeof(int));
7269 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7270 + (char *) &zone_idx, sizeof(int));
7271 + size = pages_for_zone(zone);
7272 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7273 + (char *) &size, sizeof(int));
7274 +
7275 + for (i = 0; i < size; i++)
7276 + suspendActiveAllocator->rw_header_chunk(WRITE,
7277 + NULL, (char *) pagemap[node][zone_idx][i],
7278 + PAGE_SIZE);
7279 + }
7280 + node++;
7281 + }
7282 + node = -1;
7283 + suspendActiveAllocator->rw_header_chunk(WRITE, NULL,
7284 + (char *) &node, sizeof(int));
7285 +}
7286 +
7287 +/* load_dyn_pageflags
7288 + *
7289 + * Description: Load a set of pageflags.
7290 + * Arguments: dyn_pageflags_t *: Pointer to the bitmap being loaded.
7291 + * (It must be allocated before calling this routine).
7292 + */
7293 +
7294 +int load_dyn_pageflags(dyn_pageflags_t pagemap)
7295 +{
7296 + int i, zone_idx, zone_check = 0, size, node = 0;
7297 + struct zone *zone;
7298 + struct pglist_data *pgdat;
7299 +
7300 + if (!pagemap)
7301 + return 1;
7302 +
7303 + for_each_online_pgdat(pgdat) {
7304 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
7305 + zone = &pgdat->node_zones[zone_idx];
7306 +
7307 + if (!populated_zone(zone))
7308 + continue;
7309 +
7310 + /* Same node? */
7311 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7312 + (char *) &zone_check, sizeof(int));
7313 + if (zone_check != node) {
7314 + printk("Node read (%d) != node (%d).\n",
7315 + zone_check, node);
7316 + return 1;
7317 + }
7318 +
7319 + /* Same zone? */
7320 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7321 + (char *) &zone_check, sizeof(int));
7322 + if (zone_check != zone_idx) {
7323 + printk("Zone read (%d) != node (%d).\n",
7324 + zone_check, zone_idx);
7325 + return 1;
7326 + }
7327 +
7328 +
7329 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7330 + (char *) &size, sizeof(int));
7331 +
7332 + for (i = 0; i < size; i++)
7333 + suspendActiveAllocator->rw_header_chunk(READ, NULL,
7334 + (char *) pagemap[node][zone_idx][i],
7335 + PAGE_SIZE);
7336 + }
7337 + node++;
7338 + }
7339 + suspendActiveAllocator->rw_header_chunk(READ, NULL, (char *) &zone_check,
7340 + sizeof(int));
7341 + if (zone_check != -1) {
7342 + printk("Didn't read end of dyn pageflag data marker.(%x)\n",
7343 + zone_check);
7344 + return 1;
7345 + }
7346 +
7347 + return 0;
7348 +}
7349 diff -Naur linux-2.6.21-ck2/kernel/power/pageflags.h linux-2.6.21-magellan-r11/kernel/power/pageflags.h
7350 --- linux-2.6.21-ck2/kernel/power/pageflags.h 1970-01-01 01:00:00.000000000 +0100
7351 +++ linux-2.6.21-magellan-r11/kernel/power/pageflags.h 2007-08-17 15:57:25.000000000 +0200
7352 @@ -0,0 +1,49 @@
7353 +/*
7354 + * kernel/power/pageflags.h
7355 + *
7356 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
7357 + *
7358 + * This file is released under the GPLv2.
7359 + *
7360 + * Suspend2 needs a few pageflags while working that aren't otherwise
7361 + * used. To save the struct page pageflags, we dynamically allocate
7362 + * a bitmap and use that. These are the only non order-0 allocations
7363 + * we do.
7364 + *
7365 + * NOTE!!!
7366 + * We assume that PAGE_SIZE - sizeof(void *) is a multiple of
7367 + * sizeof(unsigned long). Is this ever false?
7368 + */
7369 +
7370 +#include <linux/dyn_pageflags.h>
7371 +#include <linux/suspend.h>
7372 +
7373 +extern dyn_pageflags_t pageset1_map;
7374 +extern dyn_pageflags_t pageset1_copy_map;
7375 +extern dyn_pageflags_t pageset2_map;
7376 +extern dyn_pageflags_t page_resave_map;
7377 +extern dyn_pageflags_t io_map;
7378 +
7379 +#define PagePageset1(page) (test_dynpageflag(&pageset1_map, page))
7380 +#define SetPagePageset1(page) (set_dynpageflag(&pageset1_map, page))
7381 +#define ClearPagePageset1(page) (clear_dynpageflag(&pageset1_map, page))
7382 +
7383 +#define PagePageset1Copy(page) (test_dynpageflag(&pageset1_copy_map, page))
7384 +#define SetPagePageset1Copy(page) (set_dynpageflag(&pageset1_copy_map, page))
7385 +#define ClearPagePageset1Copy(page) (clear_dynpageflag(&pageset1_copy_map, page))
7386 +
7387 +#define PagePageset2(page) (test_dynpageflag(&pageset2_map, page))
7388 +#define SetPagePageset2(page) (set_dynpageflag(&pageset2_map, page))
7389 +#define ClearPagePageset2(page) (clear_dynpageflag(&pageset2_map, page))
7390 +
7391 +#define PageWasRW(page) (test_dynpageflag(&pageset2_map, page))
7392 +#define SetPageWasRW(page) (set_dynpageflag(&pageset2_map, page))
7393 +#define ClearPageWasRW(page) (clear_dynpageflag(&pageset2_map, page))
7394 +
7395 +#define PageResave(page) (page_resave_map ? test_dynpageflag(&page_resave_map, page) : 0)
7396 +#define SetPageResave(page) (set_dynpageflag(&page_resave_map, page))
7397 +#define ClearPageResave(page) (clear_dynpageflag(&page_resave_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 -Naur linux-2.6.21-ck2/kernel/power/power.h linux-2.6.21-magellan-r11/kernel/power/power.h
7403 --- linux-2.6.21-ck2/kernel/power/power.h 2007-04-26 05:08:32.000000000 +0200
7404 +++ linux-2.6.21-magellan-r11/kernel/power/power.h 2007-08-17 15:57:25.000000000 +0200
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 @@ -15,11 +21,15 @@
7418
7419 #ifdef CONFIG_SOFTWARE_SUSPEND
7420 extern int pm_suspend_disk(void);
7421 -
7422 +extern char resume_file[256];
7423 #else
7424 static inline int pm_suspend_disk(void)
7425 {
7426 - return -EPERM;
7427 +#ifdef CONFIG_SUSPEND2
7428 + return suspend2_try_suspend(1);
7429 +#else
7430 + return -ENODEV;
7431 +#endif
7432 }
7433 #endif
7434
7435 @@ -40,6 +50,8 @@
7436 /* References to section boundaries */
7437 extern const void __nosave_begin, __nosave_end;
7438
7439 +extern struct pbe *restore_pblist;
7440 +
7441 /* Preferred image size in bytes (default 500 MB) */
7442 extern unsigned long image_size;
7443 extern int in_suspend;
7444 @@ -177,3 +189,11 @@
7445 struct timeval;
7446 extern void swsusp_show_speed(struct timeval *, struct timeval *,
7447 unsigned int, char *);
7448 +extern struct page *saveable_page(unsigned long pfn);
7449 +#ifdef CONFIG_HIGHMEM
7450 +extern struct page *saveable_highmem_page(unsigned long pfn);
7451 +#else
7452 +static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
7453 +#endif
7454 +
7455 +#define PBES_PER_PAGE (PAGE_SIZE / sizeof(struct pbe))
7456 diff -Naur linux-2.6.21-ck2/kernel/power/power_off.c linux-2.6.21-magellan-r11/kernel/power/power_off.c
7457 --- linux-2.6.21-ck2/kernel/power/power_off.c 1970-01-01 01:00:00.000000000 +0100
7458 +++ linux-2.6.21-magellan-r11/kernel/power/power_off.c 2007-08-17 15:57:25.000000000 +0200
7459 @@ -0,0 +1,109 @@
7460 +/*
7461 + * kernel/power/power_off.c
7462 + *
7463 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7464 + *
7465 + * This file is released under the GPLv2.
7466 + *
7467 + * Support for powering down.
7468 + */
7469 +
7470 +#include <linux/device.h>
7471 +#include <linux/suspend.h>
7472 +#include <linux/mm.h>
7473 +#include <linux/pm.h>
7474 +#include <linux/reboot.h>
7475 +#include <linux/cpu.h>
7476 +#include <linux/console.h>
7477 +#include "suspend.h"
7478 +#include "ui.h"
7479 +#include "power_off.h"
7480 +#include "power.h"
7481 +
7482 +unsigned long suspend2_poweroff_method = 0; /* 0 - Kernel power off */
7483 +
7484 +/*
7485 + * suspend2_power_down
7486 + * Functionality : Powers down or reboots the computer once the image
7487 + * has been written to disk.
7488 + * Key Assumptions : Able to reboot/power down via code called or that
7489 + * the warning emitted if the calls fail will be visible
7490 + * to the user (ie printk resumes devices).
7491 + * Called From : do_suspend2_suspend_2
7492 + */
7493 +
7494 +void suspend2_power_down(void)
7495 +{
7496 + int result = 0;
7497 +
7498 + if (test_action_state(SUSPEND_REBOOT)) {
7499 + suspend_prepare_status(DONT_CLEAR_BAR, "Ready to reboot.");
7500 + kernel_restart(NULL);
7501 + }
7502 +
7503 + suspend_prepare_status(DONT_CLEAR_BAR, "Powering down.");
7504 +
7505 + switch (suspend2_poweroff_method) {
7506 + case 0:
7507 + break;
7508 + case 3:
7509 + suspend_console();
7510 +
7511 + if (device_suspend(PMSG_SUSPEND)) {
7512 + suspend_prepare_status(DONT_CLEAR_BAR, "Device "
7513 + "suspend failure.");
7514 + goto ResumeConsole;
7515 + }
7516 +
7517 + if (!pm_ops ||
7518 + (pm_ops->prepare && pm_ops->prepare(PM_SUSPEND_MEM)))
7519 + goto DeviceResume;
7520 +
7521 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) &&
7522 + disable_nonboot_cpus())
7523 + goto PmOpsFinish;
7524 +
7525 + if (!suspend_enter(PM_SUSPEND_MEM))
7526 + result = 1;
7527 +
7528 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
7529 + enable_nonboot_cpus();
7530 +
7531 +PmOpsFinish:
7532 + if (pm_ops->finish)
7533 + pm_ops->finish(PM_SUSPEND_MEM);
7534 +
7535 +DeviceResume:
7536 + device_resume();
7537 +
7538 +ResumeConsole:
7539 + resume_console();
7540 +
7541 + /* If suspended to ram and later woke. */
7542 + if (result)
7543 + return;
7544 + break;
7545 + case 4:
7546 + case 5:
7547 + if (!pm_ops ||
7548 + (pm_ops->prepare && pm_ops->prepare(PM_SUSPEND_MAX)))
7549 + break;
7550 +
7551 + kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
7552 + suspend_enter(suspend2_poweroff_method);
7553 +
7554 + /* Failed. Fall back to kernel_power_off etc. */
7555 + if (pm_ops->finish)
7556 + pm_ops->finish(PM_SUSPEND_MAX);
7557 + }
7558 +
7559 + suspend_prepare_status(DONT_CLEAR_BAR, "Falling back to alternate power off method.");
7560 + kernel_power_off();
7561 + kernel_halt();
7562 + suspend_prepare_status(DONT_CLEAR_BAR, "Powerdown failed.");
7563 + while (1)
7564 + cpu_relax();
7565 +}
7566 +
7567 +EXPORT_SYMBOL_GPL(suspend2_poweroff_method);
7568 +EXPORT_SYMBOL_GPL(suspend2_power_down);
7569 diff -Naur linux-2.6.21-ck2/kernel/power/power_off.h linux-2.6.21-magellan-r11/kernel/power/power_off.h
7570 --- linux-2.6.21-ck2/kernel/power/power_off.h 1970-01-01 01:00:00.000000000 +0100
7571 +++ linux-2.6.21-magellan-r11/kernel/power/power_off.h 2007-08-17 15:57:25.000000000 +0200
7572 @@ -0,0 +1,13 @@
7573 +/*
7574 + * kernel/power/power_off.h
7575 + *
7576 + * Copyright (C) 2006-2007 Nigel Cunningham (nigel at suspend2 net)
7577 + *
7578 + * This file is released under the GPLv2.
7579 + *
7580 + * Support for the powering down.
7581 + */
7582 +
7583 +int suspend_pm_state_finish(void);
7584 +void suspend2_power_down(void);
7585 +extern unsigned long suspend2_poweroff_method;
7586 diff -Naur linux-2.6.21-ck2/kernel/power/prepare_image.c linux-2.6.21-magellan-r11/kernel/power/prepare_image.c
7587 --- linux-2.6.21-ck2/kernel/power/prepare_image.c 1970-01-01 01:00:00.000000000 +0100
7588 +++ linux-2.6.21-magellan-r11/kernel/power/prepare_image.c 2007-08-17 15:57:25.000000000 +0200
7589 @@ -0,0 +1,798 @@
7590 +/*
7591 + * kernel/power/prepare_image.c
7592 + *
7593 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
7594 + *
7595 + * This file is released under the GPLv2.
7596 + *
7597 + * We need to eat memory until we can:
7598 + * 1. Perform the save without changing anything (RAM_NEEDED < #pages)
7599 + * 2. Fit it all in available space (suspendActiveAllocator->available_space() >=
7600 + * main_storage_needed())
7601 + * 3. Reload the pagedir and pageset1 to places that don't collide with their
7602 + * final destinations, not knowing to what extent the resumed kernel will
7603 + * overlap with the one loaded at boot time. I think the resumed kernel
7604 + * should overlap completely, but I don't want to rely on this as it is
7605 + * an unproven assumption. We therefore assume there will be no overlap at
7606 + * all (worse case).
7607 + * 4. Meet the user's requested limit (if any) on the size of the image.
7608 + * The limit is in MB, so pages/256 (assuming 4K pages).
7609 + *
7610 + */
7611 +
7612 +#include <linux/module.h>
7613 +#include <linux/highmem.h>
7614 +#include <linux/freezer.h>
7615 +#include <linux/hardirq.h>
7616 +#include <linux/mmzone.h>
7617 +#include <linux/console.h>
7618 +
7619 +#include "pageflags.h"
7620 +#include "modules.h"
7621 +#include "io.h"
7622 +#include "ui.h"
7623 +#include "extent.h"
7624 +#include "prepare_image.h"
7625 +#include "block_io.h"
7626 +#include "suspend.h"
7627 +#include "checksum.h"
7628 +#include "sysfs.h"
7629 +
7630 +static int num_nosave = 0;
7631 +static int header_space_allocated = 0;
7632 +static int main_storage_allocated = 0;
7633 +static int storage_available = 0;
7634 +int extra_pd1_pages_allowance = MIN_EXTRA_PAGES_ALLOWANCE;
7635 +int image_size_limit = 0;
7636 +
7637 +/*
7638 + * The atomic copy of pageset1 is stored in pageset2 pages.
7639 + * But if pageset1 is larger (normally only just after boot),
7640 + * we need to allocate extra pages to store the atomic copy.
7641 + * The following data struct and functions are used to handle
7642 + * the allocation and freeing of that memory.
7643 + */
7644 +
7645 +static int extra_pages_allocated;
7646 +
7647 +struct extras {
7648 + struct page *page;
7649 + int order;
7650 + struct extras *next;
7651 +};
7652 +
7653 +static struct extras *extras_list;
7654 +
7655 +/* suspend_free_extra_pagedir_memory
7656 + *
7657 + * Description: Free previously allocated extra pagedir memory.
7658 + */
7659 +void suspend_free_extra_pagedir_memory(void)
7660 +{
7661 + /* Free allocated pages */
7662 + while (extras_list) {
7663 + struct extras *this = extras_list;
7664 + int i;
7665 +
7666 + extras_list = this->next;
7667 +
7668 + for (i = 0; i < (1 << this->order); i++)
7669 + ClearPageNosave(this->page + i);
7670 +
7671 + __free_pages(this->page, this->order);
7672 + kfree(this);
7673 + }
7674 +
7675 + extra_pages_allocated = 0;
7676 +}
7677 +
7678 +/* suspend_allocate_extra_pagedir_memory
7679 + *
7680 + * Description: Allocate memory for making the atomic copy of pagedir1 in the
7681 + * case where it is bigger than pagedir2.
7682 + * Arguments: int num_to_alloc: Number of extra pages needed.
7683 + * Result: int. Number of extra pages we now have allocated.
7684 + */
7685 +static int suspend_allocate_extra_pagedir_memory(int extra_pages_needed)
7686 +{
7687 + int j, order, num_to_alloc = extra_pages_needed - extra_pages_allocated;
7688 + unsigned long flags = GFP_ATOMIC | __GFP_NOWARN;
7689 +
7690 + if (num_to_alloc < 1)
7691 + return 0;
7692 +
7693 + order = fls(num_to_alloc);
7694 + if (order >= MAX_ORDER)
7695 + order = MAX_ORDER - 1;
7696 +
7697 + while (num_to_alloc) {
7698 + struct page *newpage;
7699 + unsigned long virt;
7700 + struct extras *extras_entry;
7701 +
7702 + while ((1 << order) > num_to_alloc)
7703 + order--;
7704 +
7705 + extras_entry = (struct extras *) kmalloc(sizeof(struct extras),
7706 + GFP_ATOMIC);
7707 +
7708 + if (!extras_entry)
7709 + return extra_pages_allocated;
7710 +
7711 + virt = __get_free_pages(flags, order);
7712 + while (!virt && order) {
7713 + order--;
7714 + virt = __get_free_pages(flags, order);
7715 + }
7716 +
7717 + if (!virt) {
7718 + kfree(extras_entry);
7719 + return extra_pages_allocated;
7720 + }
7721 +
7722 + newpage = virt_to_page(virt);
7723 +
7724 + extras_entry->page = newpage;
7725 + extras_entry->order = order;
7726 + extras_entry->next = NULL;
7727 +
7728 + if (extras_list)
7729 + extras_entry->next = extras_list;
7730 +
7731 + extras_list = extras_entry;
7732 +
7733 + for (j = 0; j < (1 << order); j++) {
7734 + SetPageNosave(newpage + j);
7735 + SetPagePageset1Copy(newpage + j);
7736 + }
7737 +
7738 + extra_pages_allocated += (1 << order);
7739 + num_to_alloc -= (1 << order);
7740 + }
7741 +
7742 + return extra_pages_allocated;
7743 +}
7744 +
7745 +/*
7746 + * real_nr_free_pages: Count pcp pages for a zone type or all zones
7747 + * (-1 for all, otherwise zone_idx() result desired).
7748 + */
7749 +int real_nr_free_pages(unsigned long zone_idx_mask)
7750 +{
7751 + struct zone *zone;
7752 + int result = 0, i = 0, cpu;
7753 +
7754 + /* PCP lists */
7755 + for_each_zone(zone) {
7756 + if (!populated_zone(zone))
7757 + continue;
7758 +
7759 + if (!(zone_idx_mask & (1 << zone_idx(zone))))
7760 + continue;
7761 +
7762 + for_each_online_cpu(cpu) {
7763 + struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
7764 +
7765 + for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
7766 + struct per_cpu_pages *pcp;
7767 +
7768 + pcp = &pset->pcp[i];
7769 + result += pcp->count;
7770 + }
7771 + }
7772 +
7773 + result += zone_page_state(zone, NR_FREE_PAGES);
7774 + }
7775 + return result;
7776 +}
7777 +
7778 +/*
7779 + * Discover how much extra memory will be required by the drivers
7780 + * when they're asked to suspend. We can then ensure that amount
7781 + * of memory is available when we really want it.
7782 + */
7783 +static void get_extra_pd1_allowance(void)
7784 +{
7785 + int orig_num_free = real_nr_free_pages(all_zones_mask), final;
7786 +
7787 + suspend_prepare_status(CLEAR_BAR, "Finding allowance for drivers.");
7788 +
7789 + suspend_console();
7790 + device_suspend(PMSG_FREEZE);
7791 + local_irq_disable(); /* irqs might have been re-enabled on us */
7792 + device_power_down(PMSG_FREEZE);
7793 +
7794 + final = real_nr_free_pages(all_zones_mask);
7795 +
7796 + device_power_up();
7797 + local_irq_enable();
7798 + device_resume();
7799 + resume_console();
7800 +
7801 + extra_pd1_pages_allowance = max(
7802 + orig_num_free - final + MIN_EXTRA_PAGES_ALLOWANCE,
7803 + MIN_EXTRA_PAGES_ALLOWANCE);
7804 +}
7805 +
7806 +/*
7807 + * Amount of storage needed, possibly taking into account the
7808 + * expected compression ratio and possibly also ignoring our
7809 + * allowance for extra pages.
7810 + */
7811 +static int main_storage_needed(int use_ecr,
7812 + int ignore_extra_pd1_allow)
7813 +{
7814 + return ((pagedir1.size + pagedir2.size +
7815 + (ignore_extra_pd1_allow ? 0 : extra_pd1_pages_allowance)) *
7816 + (use_ecr ? suspend_expected_compression_ratio() : 100) / 100);
7817 +}
7818 +
7819 +/*
7820 + * Storage needed for the image header, in bytes until the return.
7821 + */
7822 +static int header_storage_needed(void)
7823 +{
7824 + int bytes = (int) sizeof(struct suspend_header) +
7825 + suspend_header_storage_for_modules() +
7826 + suspend_pageflags_space_needed();
7827 +
7828 + return DIV_ROUND_UP(bytes, PAGE_SIZE);
7829 +}
7830 +
7831 +/*
7832 + * When freeing memory, pages from either pageset might be freed.
7833 + *
7834 + * When seeking to free memory to be able to suspend, for every ps1 page freed,
7835 + * we need 2 less pages for the atomic copy because there is one less page to
7836 + * copy and one more page into which data can be copied.
7837 + *
7838 + * Freeing ps2 pages saves us nothing directly. No more memory is available
7839 + * for the atomic copy. Indirectly, a ps1 page might be freed (slab?), but
7840 + * that's too much work to figure out.
7841 + *
7842 + * => ps1_to_free functions
7843 + *
7844 + * Of course if we just want to reduce the image size, because of storage
7845 + * limitations or an image size limit either ps will do.
7846 + *
7847 + * => any_to_free function
7848 + */
7849 +
7850 +static int highpages_ps1_to_free(void)
7851 +{
7852 + return max_t(int, 0, DIV_ROUND_UP(get_highmem_size(pagedir1) -
7853 + get_highmem_size(pagedir2), 2) - real_nr_free_high_pages());
7854 +}
7855 +
7856 +static int lowpages_ps1_to_free(void)
7857 +{
7858 + return max_t(int, 0, DIV_ROUND_UP(get_lowmem_size(pagedir1) +
7859 + extra_pd1_pages_allowance + MIN_FREE_RAM +
7860 + suspend_memory_for_modules() - get_lowmem_size(pagedir2) -
7861 + real_nr_free_low_pages() - extra_pages_allocated, 2));
7862 +}
7863 +
7864 +static int current_image_size(void)
7865 +{
7866 + return pagedir1.size + pagedir2.size + header_space_allocated;
7867 +}
7868 +
7869 +static int any_to_free(int use_image_size_limit)
7870 +{
7871 + int user_limit = (use_image_size_limit && image_size_limit > 0) ?
7872 + max_t(int, 0, current_image_size() - (image_size_limit << 8))
7873 + : 0;
7874 +
7875 + int storage_limit = max_t(int, 0,
7876 + main_storage_needed(1, 1) - storage_available);
7877 +
7878 + return max(user_limit, storage_limit);
7879 +}
7880 +
7881 +/* amount_needed
7882 + *
7883 + * Calculates the amount by which the image size needs to be reduced to meet
7884 + * our constraints.
7885 + */
7886 +static int amount_needed(int use_image_size_limit)
7887 +{
7888 + return max(highpages_ps1_to_free() + lowpages_ps1_to_free(),
7889 + any_to_free(use_image_size_limit));
7890 +}
7891 +
7892 +static int image_not_ready(int use_image_size_limit)
7893 +{
7894 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
7895 + "Amount still needed (%d) > 0:%d. Header: %d < %d: %d,"
7896 + " Storage allocd: %d < %d: %d.\n",
7897 + amount_needed(use_image_size_limit),
7898 + (amount_needed(use_image_size_limit) > 0),
7899 + header_space_allocated, header_storage_needed(),
7900 + header_space_allocated < header_storage_needed(),
7901 + main_storage_allocated,
7902 + main_storage_needed(1, 1),
7903 + main_storage_allocated < main_storage_needed(1, 1));
7904 +
7905 + suspend_cond_pause(0, NULL);
7906 +
7907 + return ((amount_needed(use_image_size_limit) > 0) ||
7908 + header_space_allocated < header_storage_needed() ||
7909 + main_storage_allocated < main_storage_needed(1, 1));
7910 +}
7911 +
7912 +static void display_stats(int always, int sub_extra_pd1_allow)
7913 +{
7914 + char buffer[255];
7915 + snprintf(buffer, 254,
7916 + "Free:%d(%d). Sets:%d(%d),%d(%d). Header:%d/%d. Nosave:%d-%d"
7917 + "=%d. Storage:%u/%u(%u=>%u). Needed:%d,%d,%d(%d,%d,%d,%d)\n",
7918 +
7919 + /* Free */
7920 + real_nr_free_pages(all_zones_mask),
7921 + real_nr_free_low_pages(),
7922 +
7923 + /* Sets */
7924 + pagedir1.size, pagedir1.size - get_highmem_size(pagedir1),
7925 + pagedir2.size, pagedir2.size - get_highmem_size(pagedir2),
7926 +
7927 + /* Header */
7928 + header_space_allocated, header_storage_needed(),
7929 +
7930 + /* Nosave */
7931 + num_nosave, extra_pages_allocated,
7932 + num_nosave - extra_pages_allocated,
7933 +
7934 + /* Storage */
7935 + main_storage_allocated,
7936 + storage_available,
7937 + main_storage_needed(1, sub_extra_pd1_allow),
7938 + main_storage_needed(1, 1),
7939 +
7940 + /* Needed */
7941 + lowpages_ps1_to_free(), highpages_ps1_to_free(),
7942 + any_to_free(1),
7943 + MIN_FREE_RAM, suspend_memory_for_modules(),
7944 + extra_pd1_pages_allowance, image_size_limit << 8);
7945 +
7946 + if (always)
7947 + printk(buffer);
7948 + else
7949 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1, buffer);
7950 +}
7951 +
7952 +/* generate_free_page_map
7953 + *
7954 + * Description: This routine generates a bitmap of free pages from the
7955 + * lists used by the memory manager. We then use the bitmap
7956 + * to quickly calculate which pages to save and in which
7957 + * pagesets.
7958 + */
7959 +static void generate_free_page_map(void)
7960 +{
7961 + int order, loop, cpu;
7962 + struct page *page;
7963 + unsigned long flags, i;
7964 + struct zone *zone;
7965 +
7966 + for_each_zone(zone) {
7967 + if (!populated_zone(zone))
7968 + continue;
7969 +
7970 + spin_lock_irqsave(&zone->lock, flags);
7971 +
7972 + for(i=0; i < zone->spanned_pages; i++)
7973 + ClearPageNosaveFree(pfn_to_page(
7974 + zone->zone_start_pfn + i));
7975 +
7976 + for (order = MAX_ORDER - 1; order >= 0; --order)
7977 + list_for_each_entry(page,
7978 + &zone->free_area[order].free_list, lru)
7979 + for(loop=0; loop < (1 << order); loop++)
7980 + SetPageNosaveFree(page+loop);
7981 +
7982 +
7983 + for_each_online_cpu(cpu) {
7984 + struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
7985 +
7986 + for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
7987 + struct per_cpu_pages *pcp;
7988 + struct page *page;
7989 +
7990 + pcp = &pset->pcp[i];
7991 + list_for_each_entry(page, &pcp->list, lru)
7992 + SetPageNosaveFree(page);
7993 + }
7994 + }
7995 +
7996 + spin_unlock_irqrestore(&zone->lock, flags);
7997 + }
7998 +}
7999 +
8000 +/* size_of_free_region
8001 + *
8002 + * Description: Return the number of pages that are free, beginning with and
8003 + * including this one.
8004 + */
8005 +static int size_of_free_region(struct page *page)
8006 +{
8007 + struct zone *zone = page_zone(page);
8008 + struct page *posn = page, *last_in_zone =
8009 + pfn_to_page(zone->zone_start_pfn) + zone->spanned_pages - 1;
8010 +
8011 + while (posn <= last_in_zone && PageNosaveFree(posn))
8012 + posn++;
8013 + return (posn - page);
8014 +}
8015 +
8016 +/* flag_image_pages
8017 + *
8018 + * This routine generates our lists of pages to be stored in each
8019 + * pageset. Since we store the data using extents, and adding new
8020 + * extents might allocate a new extent page, this routine may well
8021 + * be called more than once.
8022 + */
8023 +static void flag_image_pages(int atomic_copy)
8024 +{
8025 + int num_free = 0;
8026 + unsigned long loop;
8027 + struct zone *zone;
8028 +
8029 + pagedir1.size = 0;
8030 + pagedir2.size = 0;
8031 +
8032 + set_highmem_size(pagedir1, 0);
8033 + set_highmem_size(pagedir2, 0);
8034 +
8035 + num_nosave = 0;
8036 +
8037 + clear_dyn_pageflags(pageset1_map);
8038 +
8039 + generate_free_page_map();
8040 +
8041 + /*
8042 + * Pages not to be saved are marked Nosave irrespective of being reserved
8043 + */
8044 + for_each_zone(zone) {
8045 + int highmem = is_highmem(zone);
8046 +
8047 + if (!populated_zone(zone))
8048 + continue;
8049 +
8050 + for (loop = 0; loop < zone->spanned_pages; loop++) {
8051 + unsigned long pfn = zone->zone_start_pfn + loop;
8052 + struct page *page;
8053 + int chunk_size;
8054 +
8055 + if (!pfn_valid(pfn))
8056 + continue;
8057 +
8058 + page = pfn_to_page(pfn);
8059 +
8060 + chunk_size = size_of_free_region(page);
8061 + if (chunk_size) {
8062 + num_free += chunk_size;
8063 + loop += chunk_size - 1;
8064 + continue;
8065 + }
8066 +
8067 + if (highmem)
8068 + page = saveable_highmem_page(pfn);
8069 + else
8070 + page = saveable_page(pfn);
8071 +
8072 + if (!page) {
8073 + num_nosave++;
8074 + continue;
8075 + }
8076 +
8077 + if (PagePageset2(page)) {
8078 + pagedir2.size++;
8079 + if (PageHighMem(page))
8080 + inc_highmem_size(pagedir2);
8081 + else
8082 + SetPagePageset1Copy(page);
8083 + if (PageResave(page)) {
8084 + SetPagePageset1(page);
8085 + ClearPagePageset1Copy(page);
8086 + pagedir1.size++;
8087 + if (PageHighMem(page))
8088 + inc_highmem_size(pagedir1);
8089 + }
8090 + } else {
8091 + pagedir1.size++;
8092 + SetPagePageset1(page);
8093 + if (PageHighMem(page))
8094 + inc_highmem_size(pagedir1);
8095 + }
8096 + }
8097 + }
8098 +
8099 + if (atomic_copy)
8100 + return;
8101 +
8102 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 0,
8103 + "Count data pages: Set1 (%d) + Set2 (%d) + Nosave (%d) + "
8104 + "NumFree (%d) = %d.\n",
8105 + pagedir1.size, pagedir2.size, num_nosave, num_free,
8106 + pagedir1.size + pagedir2.size + num_nosave + num_free);
8107 +}
8108 +
8109 +void suspend_recalculate_image_contents(int atomic_copy)
8110 +{
8111 + clear_dyn_pageflags(pageset1_map);
8112 + if (!atomic_copy) {
8113 + int pfn;
8114 + BITMAP_FOR_EACH_SET(pageset2_map, pfn)
8115 + ClearPagePageset1Copy(pfn_to_page(pfn));
8116 + /* Need to call this before getting pageset1_size! */
8117 + suspend_mark_pages_for_pageset2();
8118 + }
8119 + flag_image_pages(atomic_copy);
8120 +
8121 + if (!atomic_copy) {
8122 + storage_available = suspendActiveAllocator->storage_available();
8123 + display_stats(0, 0);
8124 + }
8125 +}
8126 +
8127 +/* update_image
8128 + *
8129 + * Allocate [more] memory and storage for the image.
8130 + */
8131 +static void update_image(void)
8132 +{
8133 + int result, param_used, wanted, got;
8134 +
8135 + suspend_recalculate_image_contents(0);
8136 +
8137 + /* Include allowance for growth in pagedir1 while writing pagedir 2 */
8138 + wanted = pagedir1.size + extra_pd1_pages_allowance -
8139 + get_lowmem_size(pagedir2);
8140 + if (wanted > extra_pages_allocated) {
8141 + got = suspend_allocate_extra_pagedir_memory(wanted);
8142 + if (wanted < got) {
8143 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
8144 + "Want %d extra pages for pageset1, got %d.\n",
8145 + wanted, got);
8146 + return;
8147 + }
8148 + }
8149 +
8150 + thaw_kernel_threads();
8151 +
8152 + /*
8153 + * Allocate remaining storage space, if possible, up to the
8154 + * maximum we know we'll need. It's okay to allocate the
8155 + * maximum if the writer is the swapwriter, but
8156 + * we don't want to grab all available space on an NFS share.
8157 + * We therefore ignore the expected compression ratio here,
8158 + * thereby trying to allocate the maximum image size we could
8159 + * need (assuming compression doesn't expand the image), but
8160 + * don't complain if we can't get the full amount we're after.
8161 + */
8162 +
8163 + suspendActiveAllocator->allocate_storage(
8164 + min(storage_available, main_storage_needed(0, 0)));
8165 +
8166 + main_storage_allocated = suspendActiveAllocator->storage_allocated();
8167 +
8168 + param_used = header_storage_needed();
8169 +
8170 + result = suspendActiveAllocator->allocate_header_space(param_used);
8171 +
8172 + if (result)
8173 + suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
8174 + "Still need to get more storage space for header.\n");
8175 + else
8176 + header_space_allocated = param_used;
8177 +
8178 + if (freeze_processes()) {
8179 + set_result_state(SUSPEND_FREEZING_FAILED);
8180 + set_result_state(SUSPEND_ABORTED);
8181 + }
8182 +
8183 + allocate_checksum_pages();
8184 +
8185 + suspend_recalculate_image_contents(0);
8186 +}
8187 +
8188 +/* attempt_to_freeze
8189 + *
8190 + * Try to freeze processes.
8191 + */
8192 +
8193 +static int attempt_to_freeze(void)
8194 +{
8195 + int result;
8196 +
8197 + /* Stop processes before checking again */
8198 + thaw_processes();
8199 + suspend_prepare_status(CLEAR_BAR, "Freezing processes & syncing filesystems.");
8200 + result = freeze_processes();
8201 +
8202 + if (result) {
8203 + set_result_state(SUSPEND_ABORTED);
8204 + set_result_state(SUSPEND_FREEZING_FAILED);
8205 + }
8206 +
8207 + return result;
8208 +}
8209 +
8210 +/* eat_memory
8211 + *
8212 + * Try to free some memory, either to meet hard or soft constraints on the image
8213 + * characteristics.
8214 + *
8215 + * Hard constraints:
8216 + * - Pageset1 must be < half of memory;
8217 + * - We must have enough memory free at resume time to have pageset1
8218 + * be able to be loaded in pages that don't conflict with where it has to
8219 + * be restored.
8220 + * Soft constraints
8221 + * - User specificied image size limit.
8222 + */
8223 +static void eat_memory(void)
8224 +{
8225 + int amount_wanted = 0;
8226 + int free_flags = 0, did_eat_memory = 0;
8227 +
8228 + /*
8229 + * Note that if we have enough storage space and enough free memory, we
8230 + * may exit without eating anything. We give up when the last 10
8231 + * iterations ate no extra pages because we're not going to get much
8232 + * more anyway, but the few pages we get will take a lot of time.
8233 + *
8234 + * We freeze processes before beginning, and then unfreeze them if we
8235 + * need to eat memory until we think we have enough. If our attempts
8236 + * to freeze fail, we give up and abort.
8237 + */
8238 +
8239 + suspend_recalculate_image_contents(0);
8240 + amount_wanted = amount_needed(1);
8241 +
8242 + switch (image_size_limit) {
8243 + case -1: /* Don't eat any memory */
8244 + if (amount_wanted > 0) {
8245 + set_result_state(SUSPEND_ABORTED);
8246 + set_result_state(SUSPEND_WOULD_EAT_MEMORY);
8247 + return;
8248 + }
8249 + break;
8250 + case -2: /* Free caches only */
8251 + drop_pagecache();
8252 + suspend_recalculate_image_contents(0);
8253 + amount_wanted = amount_needed(1);
8254 + did_eat_memory = 1;
8255 + break;
8256 + default:
8257 + free_flags = GFP_ATOMIC | __GFP_HIGHMEM;
8258 + }
8259 +
8260 + if (amount_wanted > 0 && !test_result_state(SUSPEND_ABORTED) &&
8261 + image_size_limit != -1) {
8262 + struct zone *zone;
8263 + int zone_idx;
8264 +
8265 + suspend_prepare_status(CLEAR_BAR, "Seeking to free %dMB of memory.", MB(amount_wanted));
8266 +
8267 + thaw_kernel_threads();
8268 +
8269 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
8270 + int zone_type_free = max_t(int, (zone_idx == ZONE_HIGHMEM) ?
8271 + highpages_ps1_to_free() :
8272 + lowpages_ps1_to_free(), amount_wanted);
8273 +
8274 + if (zone_type_free < 0)
8275 + break;
8276 +
8277 + for_each_zone(zone) {
8278 + if (zone_idx(zone) != zone_idx)
8279 + continue;
8280 +
8281 + shrink_one_zone(zone, zone_type_free);
8282 +
8283 + did_eat_memory = 1;
8284 +
8285 + suspend_recalculate_image_contents(0);
8286 +
8287 + amount_wanted = amount_needed(1);
8288 + zone_type_free = max_t(int, (zone_idx == ZONE_HIGHMEM) ?
8289 + highpages_ps1_to_free() :
8290 + lowpages_ps1_to_free(), amount_wanted);
8291 +
8292 + if (zone_type_free < 0)
8293 + break;
8294 + }
8295 + }
8296 +
8297 + suspend_cond_pause(0, NULL);
8298 +
8299 + if (freeze_processes()) {
8300 + set_result_state(SUSPEND_FREEZING_FAILED);
8301 + set_result_state(SUSPEND_ABORTED);
8302 + }
8303 + }
8304 +
8305 + if (did_eat_memory) {
8306 + unsigned long orig_state = get_suspend_state();
8307 + /* Freeze_processes will call sys_sync too */
8308 + restore_suspend_state(orig_state);
8309 + suspend_recalculate_image_contents(0);
8310 + }
8311 +
8312 + /* Blank out image size display */
8313 + suspend_update_status(100, 100, NULL);
8314 +}
8315 +
8316 +/* suspend_prepare_image
8317 + *
8318 + * Entry point to the whole image preparation section.
8319 + *
8320 + * We do four things:
8321 + * - Freeze processes;
8322 + * - Ensure image size constraints are met;
8323 + * - Complete all the preparation for saving the image,
8324 + * including allocation of storage. The only memory
8325 + * that should be needed when we're finished is that
8326 + * for actually storing the image (and we know how
8327 + * much is needed for that because the modules tell
8328 + * us).
8329 + * - Make sure that all dirty buffers are written out.
8330 + */
8331 +#define MAX_TRIES 2
8332 +int suspend_prepare_image(void)
8333 +{
8334 + int result = 1, tries = 1;
8335 +
8336 + header_space_allocated = 0;
8337 + main_storage_allocated = 0;
8338 +
8339 + if (attempt_to_freeze())
8340 + return 1;
8341 +
8342 + if (!extra_pd1_pages_allowance)
8343 + get_extra_pd1_allowance();
8344 +
8345 + storage_available = suspendActiveAllocator->storage_available();
8346 +
8347 + if (!storage_available) {
8348 + printk(KERN_ERR "You need some storage available to be able to suspend.\n");
8349 + set_result_state(SUSPEND_ABORTED);
8350 + set_result_state(SUSPEND_NOSTORAGE_AVAILABLE);
8351 + return 1;
8352 + }
8353 +
8354 + do {
8355 + suspend_prepare_status(CLEAR_BAR, "Preparing Image. Try %d.", tries);
8356 +
8357 + eat_memory();
8358 +
8359 + if (test_result_state(SUSPEND_ABORTED))
8360 + break;
8361 +
8362 + update_image();
8363 +
8364 + tries++;
8365 +
8366 + } while (image_not_ready(1) && tries <= MAX_TRIES &&
8367 + !test_result_state(SUSPEND_ABORTED));
8368 +
8369 + result = image_not_ready(0);
8370 +
8371 + if (!test_result_state(SUSPEND_ABORTED)) {
8372 + if (result) {
8373 + display_stats(1, 0);
8374 + abort_suspend(SUSPEND_UNABLE_TO_PREPARE_IMAGE,
8375 + "Unable to successfully prepare the image.\n");
8376 + } else {
8377 + unlink_lru_lists();
8378 + suspend_cond_pause(1, "Image preparation complete.");
8379 + }
8380 + }
8381 +
8382 + return result;
8383 +}
8384 +
8385 +#ifdef CONFIG_SUSPEND2_EXPORTS
8386 +EXPORT_SYMBOL_GPL(real_nr_free_pages);
8387 +#endif
8388 diff -Naur linux-2.6.21-ck2/kernel/power/prepare_image.h linux-2.6.21-magellan-r11/kernel/power/prepare_image.h
8389 --- linux-2.6.21-ck2/kernel/power/prepare_image.h 1970-01-01 01:00:00.000000000 +0100
8390 +++ linux-2.6.21-magellan-r11/kernel/power/prepare_image.h 2007-08-17 15:57:25.000000000 +0200
8391 @@ -0,0 +1,34 @@
8392 +/*
8393 + * kernel/power/prepare_image.h
8394 + *
8395 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
8396 + *
8397 + * This file is released under the GPLv2.
8398 + *
8399 + */
8400 +
8401 +#include <asm/sections.h>
8402 +
8403 +extern int suspend_prepare_image(void);
8404 +extern void suspend_recalculate_image_contents(int storage_available);
8405 +extern int real_nr_free_pages(unsigned long zone_idx_mask);
8406 +extern int image_size_limit;
8407 +extern void suspend_free_extra_pagedir_memory(void);
8408 +extern int extra_pd1_pages_allowance;
8409 +
8410 +#define MIN_FREE_RAM 100
8411 +#define MIN_EXTRA_PAGES_ALLOWANCE 500
8412 +
8413 +#define all_zones_mask ((unsigned long) ((1 << MAX_NR_ZONES) - 1))
8414 +#ifdef CONFIG_HIGHMEM
8415 +#define real_nr_free_high_pages() (real_nr_free_pages(1 << ZONE_HIGHMEM))
8416 +#define real_nr_free_low_pages() (real_nr_free_pages(all_zones_mask - \
8417 + (1 << ZONE_HIGHMEM)))
8418 +#else
8419 +#define real_nr_free_high_pages() (0)
8420 +#define real_nr_free_low_pages() (real_nr_free_pages(all_zones_mask))
8421 +
8422 +/* For eat_memory function */
8423 +#define ZONE_HIGHMEM (MAX_NR_ZONES + 1)
8424 +#endif
8425 +
8426 diff -Naur linux-2.6.21-ck2/kernel/power/process.c linux-2.6.21-magellan-r11/kernel/power/process.c
8427 --- linux-2.6.21-ck2/kernel/power/process.c 2007-04-26 05:08:32.000000000 +0200
8428 +++ linux-2.6.21-magellan-r11/kernel/power/process.c 2007-08-17 15:57:25.000000000 +0200
8429 @@ -15,6 +15,8 @@
8430 #include <linux/syscalls.h>
8431 #include <linux/freezer.h>
8432
8433 +int freezer_state = 0;
8434 +
8435 /*
8436 * Timeout for stopping processes
8437 */
8438 @@ -179,10 +181,11 @@
8439 return nr_unfrozen;
8440
8441 sys_sync();
8442 + freezer_state = FREEZER_USERSPACE_FROZEN;
8443 nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
8444 if (nr_unfrozen)
8445 return nr_unfrozen;
8446 -
8447 + freezer_state = FREEZER_FULLY_ON;
8448 printk("done.\n");
8449 BUG_ON(in_atomic());
8450 return 0;
8451 @@ -200,7 +203,7 @@
8452 if (is_user_space(p) == !thaw_user_space)
8453 continue;
8454
8455 - if (!thaw_process(p))
8456 + if (!thaw_process(p) && p->state != TASK_TRACED)
8457 printk(KERN_WARNING " Strange, %s not stopped\n",
8458 p->comm );
8459 } while_each_thread(g, p);
8460 @@ -209,11 +212,31 @@
8461
8462 void thaw_processes(void)
8463 {
8464 + int old_state = freezer_state;
8465 +
8466 + if (old_state == FREEZER_OFF)
8467 + return;
8468 +
8469 + /*
8470 + * Change state beforehand because thawed tasks might submit I/O
8471 + * immediately.
8472 + */
8473 + freezer_state = FREEZER_OFF;
8474 +
8475 printk("Restarting tasks ... ");
8476 - thaw_tasks(FREEZER_KERNEL_THREADS);
8477 +
8478 + if (old_state == FREEZER_FULLY_ON)
8479 + thaw_tasks(FREEZER_KERNEL_THREADS);
8480 thaw_tasks(FREEZER_USER_SPACE);
8481 schedule();
8482 printk("done.\n");
8483 }
8484
8485 +void thaw_kernel_threads(void)
8486 +{
8487 + freezer_state = FREEZER_USERSPACE_FROZEN;
8488 + thaw_tasks(FREEZER_KERNEL_THREADS);
8489 +}
8490 +
8491 EXPORT_SYMBOL(refrigerator);
8492 +EXPORT_SYMBOL(freezer_state);
8493 diff -Naur linux-2.6.21-ck2/kernel/power/snapshot.c linux-2.6.21-magellan-r11/kernel/power/snapshot.c
8494 --- linux-2.6.21-ck2/kernel/power/snapshot.c 2007-04-26 05:08:32.000000000 +0200
8495 +++ linux-2.6.21-magellan-r11/kernel/power/snapshot.c 2007-08-17 15:57:25.000000000 +0200
8496 @@ -33,6 +33,7 @@
8497 #include <asm/io.h>
8498
8499 #include "power.h"
8500 +#include "suspend2_builtin.h"
8501
8502 /* List of PBEs needed for restoring the pages that were allocated before
8503 * the suspend and included in the suspend image, but have also been
8504 @@ -40,6 +41,13 @@
8505 * directly to their "original" page frames.
8506 */
8507 struct pbe *restore_pblist;
8508 +int resume_attempted;
8509 +EXPORT_SYMBOL_GPL(resume_attempted);
8510 +
8511 +#ifdef CONFIG_SUSPEND2
8512 +#include "pagedir.h"
8513 +int suspend_post_context_save(void);
8514 +#endif
8515
8516 /* Pointer to an auxiliary buffer (1 page) */
8517 static void *buffer;
8518 @@ -82,6 +90,11 @@
8519
8520 unsigned long get_safe_page(gfp_t gfp_mask)
8521 {
8522 +#ifdef CONFIG_SUSPEND2
8523 + if (suspend2_running)
8524 + return suspend_get_nonconflicting_page();
8525 +#endif
8526 +
8527 return (unsigned long)get_image_page(gfp_mask, PG_SAFE);
8528 }
8529
8530 @@ -604,7 +617,7 @@
8531 * and it isn't a part of a free chunk of pages.
8532 */
8533
8534 -static struct page *saveable_highmem_page(unsigned long pfn)
8535 +struct page *saveable_highmem_page(unsigned long pfn)
8536 {
8537 struct page *page;
8538
8539 @@ -646,7 +659,6 @@
8540 return n;
8541 }
8542 #else
8543 -static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
8544 static inline unsigned int count_highmem_pages(void) { return 0; }
8545 #endif /* CONFIG_HIGHMEM */
8546
8547 @@ -670,7 +682,7 @@
8548 * a free chunk of pages.
8549 */
8550
8551 -static struct page *saveable_page(unsigned long pfn)
8552 +struct page *saveable_page(unsigned long pfn)
8553 {
8554 struct page *page;
8555
8556 @@ -986,6 +998,11 @@
8557 {
8558 unsigned int nr_pages, nr_highmem;
8559
8560 +#ifdef CONFIG_SUSPEND2
8561 + if (suspend2_running)
8562 + return suspend_post_context_save();
8563 +#endif
8564 +
8565 printk("swsusp: critical section: \n");
8566
8567 drain_local_pages();
8568 diff -Naur linux-2.6.21-ck2/kernel/power/storage.c linux-2.6.21-magellan-r11/kernel/power/storage.c
8569 --- linux-2.6.21-ck2/kernel/power/storage.c 1970-01-01 01:00:00.000000000 +0100
8570 +++ linux-2.6.21-magellan-r11/kernel/power/storage.c 2007-08-17 15:57:25.000000000 +0200
8571 @@ -0,0 +1,288 @@
8572 +/*
8573 + * kernel/power/storage.c
8574 + *
8575 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
8576 + *
8577 + * This file is released under the GPLv2.
8578 + *
8579 + * Routines for talking to a userspace program that manages storage.
8580 + *
8581 + * The kernel side:
8582 + * - starts the userspace program;
8583 + * - sends messages telling it when to open and close the connection;
8584 + * - tells it when to quit;
8585 + *
8586 + * The user space side:
8587 + * - passes messages regarding status;
8588 + *
8589 + */
8590 +
8591 +#include <linux/suspend.h>
8592 +#include <linux/freezer.h>
8593 +
8594 +#include "sysfs.h"
8595 +#include "modules.h"
8596 +#include "netlink.h"
8597 +#include "storage.h"
8598 +#include "ui.h"
8599 +
8600 +static struct user_helper_data usm_helper_data;
8601 +static struct suspend_module_ops usm_ops;
8602 +static int message_received = 0;
8603 +static int usm_prepare_count = 0;
8604 +static int storage_manager_last_action = 0;
8605 +static int storage_manager_action = 0;
8606 +
8607 +static int usm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
8608 +{
8609 + int type;
8610 + int *data;
8611 +
8612 + type = nlh->nlmsg_type;
8613 +
8614 + /* A control message: ignore them */
8615 + if (type < NETLINK_MSG_BASE)
8616 + return 0;
8617 +
8618 + /* Unknown message: reply with EINVAL */
8619 + if (type >= USM_MSG_MAX)
8620 + return -EINVAL;
8621 +
8622 + /* All operations require privileges, even GET */
8623 + if (security_netlink_recv(skb, CAP_NET_ADMIN))
8624 + return -EPERM;
8625 +
8626 + /* Only allow one task to receive NOFREEZE privileges */
8627 + if (type == NETLINK_MSG_NOFREEZE_ME && usm_helper_data.pid != -1)
8628 + return -EBUSY;
8629 +
8630 + data = (int*)NLMSG_DATA(nlh);
8631 +
8632 + switch (type) {
8633 + case USM_MSG_SUCCESS:
8634 + case USM_MSG_FAILED:
8635 + message_received = type;
8636 + complete(&usm_helper_data.wait_for_process);
8637 + break;
8638 + default:
8639 + printk("Storage manager doesn't recognise message %d.\n", type);
8640 + }
8641 +
8642 + return 1;
8643 +}
8644 +
8645 +#ifdef CONFIG_NET
8646 +static int activations = 0;
8647 +
8648 +int suspend_activate_storage(int force)
8649 +{
8650 + int tries = 1;
8651 +
8652 + if (usm_helper_data.pid == -1 || !usm_ops.enabled)
8653 + return 0;
8654 +
8655 + message_received = 0;
8656 + activations++;
8657 +
8658 + if (activations > 1 && !force)
8659 + return 0;
8660 +
8661 + while ((!message_received || message_received == USM_MSG_FAILED) && tries < 2) {
8662 + suspend_prepare_status(DONT_CLEAR_BAR, "Activate storage attempt %d.\n", tries);
8663 +
8664 + init_completion(&usm_helper_data.wait_for_process);
8665 +
8666 + suspend_send_netlink_message(&usm_helper_data,
8667 + USM_MSG_CONNECT,
8668 + NULL, 0);
8669 +
8670 + /* Wait 2 seconds for the userspace process to make contact */
8671 + wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2*HZ);
8672 +
8673 + tries++;
8674 + }
8675 +
8676 + return 0;
8677 +}
8678 +
8679 +int suspend_deactivate_storage(int force)
8680 +{
8681 + if (usm_helper_data.pid == -1 || !usm_ops.enabled)
8682 + return 0;
8683 +
8684 + message_received = 0;
8685 + activations--;
8686 +
8687 + if (activations && !force)
8688 + return 0;
8689 +
8690 + init_completion(&usm_helper_data.wait_for_process);
8691 +
8692 + suspend_send_netlink_message(&usm_helper_data,
8693 + USM_MSG_DISCONNECT,
8694 + NULL, 0);
8695 +
8696 + wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2*HZ);
8697 +
8698 + if (!message_received || message_received == USM_MSG_FAILED) {
8699 + printk("Returning failure disconnecting storage.\n");
8700 + return 1;
8701 + }
8702 +
8703 + return 0;
8704 +}
8705 +#endif
8706 +
8707 +static void storage_manager_simulate(void)
8708 +{
8709 + printk("--- Storage manager simulate ---\n");
8710 + suspend_prepare_usm();
8711 + schedule();
8712 + printk("--- Activate storage 1 ---\n");
8713 + suspend_activate_storage(1);
8714 + schedule();
8715 + printk("--- Deactivate storage 1 ---\n");
8716 + suspend_deactivate_storage(1);
8717 + schedule();
8718 + printk("--- Cleanup usm ---\n");
8719 + suspend_cleanup_usm();
8720 + schedule();
8721 + printk("--- Storage manager simulate ends ---\n");
8722 +}
8723 +
8724 +static int usm_storage_needed(void)
8725 +{
8726 + return strlen(usm_helper_data.program);
8727 +}
8728 +
8729 +static int usm_save_config_info(char *buf)
8730 +{
8731 + int len = strlen(usm_helper_data.program);
8732 + memcpy(buf, usm_helper_data.program, len);
8733 + return len;
8734 +}
8735 +
8736 +static void usm_load_config_info(char *buf, int size)
8737 +{
8738 + /* Don't load the saved path if one has already been set */
8739 + if (usm_helper_data.program[0])
8740 + return;
8741 +
8742 + memcpy(usm_helper_data.program, buf, size);
8743 +}
8744 +
8745 +static int usm_memory_needed(void)
8746 +{
8747 + /* ball park figure of 32 pages */
8748 + return (32 * PAGE_SIZE);
8749 +}
8750 +
8751 +/* suspend_prepare_usm
8752 + */
8753 +int suspend_prepare_usm(void)
8754 +{
8755 + usm_prepare_count++;
8756 +
8757 + if (usm_prepare_count > 1 || !usm_ops.enabled)
8758 + return 0;
8759 +
8760 + usm_helper_data.pid = -1;
8761 +
8762 + if (!*usm_helper_data.program)
8763 + return 0;
8764 +
8765 + suspend_netlink_setup(&usm_helper_data);
8766 +
8767 + if (usm_helper_data.pid == -1)
8768 + printk("Suspend2 Storage Manager wanted, but couldn't start it.\n");
8769 +
8770 + suspend_activate_storage(0);
8771 +
8772 + return (usm_helper_data.pid != -1);
8773 +}
8774 +
8775 +void suspend_cleanup_usm(void)
8776 +{
8777 + usm_prepare_count--;
8778 +
8779 + if (usm_helper_data.pid > -1 && !usm_prepare_count) {
8780 + suspend_deactivate_storage(0);
8781 + suspend_netlink_close(&usm_helper_data);
8782 + }
8783 +}
8784 +
8785 +static void storage_manager_activate(void)
8786 +{
8787 + if (storage_manager_action == storage_manager_last_action)
8788 + return;
8789 +
8790 + if (storage_manager_action)
8791 + suspend_prepare_usm();
8792 + else
8793 + suspend_cleanup_usm();
8794 +
8795 + storage_manager_last_action = storage_manager_action;
8796 +}
8797 +
8798 +/*
8799 + * User interface specific /sys/power/suspend2 entries.
8800 + */
8801 +
8802 +static struct suspend_sysfs_data sysfs_params[] = {
8803 + { SUSPEND2_ATTR("simulate_atomic_copy", SYSFS_RW),
8804 + .type = SUSPEND_SYSFS_DATA_NONE,
8805 + .write_side_effect = storage_manager_simulate,
8806 + },
8807 +
8808 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
8809 + SYSFS_INT(&usm_ops.enabled, 0, 1, 0)
8810 + },
8811 +
8812 + { SUSPEND2_ATTR("program", SYSFS_RW),
8813 + SYSFS_STRING(usm_helper_data.program, 254, 0)
8814 + },
8815 +
8816 + { SUSPEND2_ATTR("activate_storage", SYSFS_RW),
8817 + SYSFS_INT(&storage_manager_action, 0, 1, 0),
8818 + .write_side_effect = storage_manager_activate,
8819 + }
8820 +};
8821 +
8822 +static struct suspend_module_ops usm_ops = {
8823 + .type = MISC_MODULE,
8824 + .name = "Userspace Storage Manager",
8825 + .directory = "storage_manager",
8826 + .module = THIS_MODULE,
8827 + .storage_needed = usm_storage_needed,
8828 + .save_config_info = usm_save_config_info,
8829 + .load_config_info = usm_load_config_info,
8830 + .memory_needed = usm_memory_needed,
8831 +
8832 + .sysfs_data = sysfs_params,
8833 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
8834 +};
8835 +
8836 +/* suspend_usm_sysfs_init
8837 + * Description: Boot time initialisation for user interface.
8838 + */
8839 +int s2_usm_init(void)
8840 +{
8841 + usm_helper_data.nl = NULL;
8842 + usm_helper_data.program[0] = '\0';
8843 + usm_helper_data.pid = -1;
8844 + usm_helper_data.skb_size = 0;
8845 + usm_helper_data.pool_limit = 6;
8846 + usm_helper_data.netlink_id = NETLINK_SUSPEND2_USM;
8847 + usm_helper_data.name = "userspace storage manager";
8848 + usm_helper_data.rcv_msg = usm_user_rcv_msg;
8849 + usm_helper_data.interface_version = 1;
8850 + usm_helper_data.must_init = 0;
8851 + init_completion(&usm_helper_data.wait_for_process);
8852 +
8853 + return suspend_register_module(&usm_ops);
8854 +}
8855 +
8856 +void s2_usm_exit(void)
8857 +{
8858 + suspend_unregister_module(&usm_ops);
8859 +}
8860 diff -Naur linux-2.6.21-ck2/kernel/power/storage.h linux-2.6.21-magellan-r11/kernel/power/storage.h
8861 --- linux-2.6.21-ck2/kernel/power/storage.h 1970-01-01 01:00:00.000000000 +0100
8862 +++ linux-2.6.21-magellan-r11/kernel/power/storage.h 2007-08-17 15:57:25.000000000 +0200
8863 @@ -0,0 +1,53 @@
8864 +/*
8865 + * kernel/power/storage.h
8866 + *
8867 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
8868 + *
8869 + * This file is released under the GPLv2.
8870 + */
8871 +
8872 +#ifdef CONFIG_NET
8873 +int suspend_prepare_usm(void);
8874 +void suspend_cleanup_usm(void);
8875 +
8876 +int suspend_activate_storage(int force);
8877 +int suspend_deactivate_storage(int force);
8878 +extern int s2_usm_init(void);
8879 +extern void s2_usm_exit(void);
8880 +#else
8881 +static inline int s2_usm_init(void) { return 0; }
8882 +static inline void s2_usm_exit(void) { }
8883 +
8884 +static inline int suspend_activate_storage(int force)
8885 +{
8886 + return 0;
8887 +}
8888 +
8889 +static inline int suspend_deactivate_storage(int force)
8890 +{
8891 + return 0;
8892 +}
8893 +
8894 +static inline int suspend_prepare_usm(void) { return 0; }
8895 +static inline void suspend_cleanup_usm(void) { }
8896 +#endif
8897 +
8898 +enum {
8899 + USM_MSG_BASE = 0x10,
8900 +
8901 + /* Kernel -> Userspace */
8902 + USM_MSG_CONNECT = 0x30,
8903 + USM_MSG_DISCONNECT = 0x31,
8904 + USM_MSG_SUCCESS = 0x40,
8905 + USM_MSG_FAILED = 0x41,
8906 +
8907 + USM_MSG_MAX,
8908 +};
8909 +
8910 +#ifdef CONFIG_NET
8911 +extern __init int suspend_usm_init(void);
8912 +extern __exit void suspend_usm_cleanup(void);
8913 +#else
8914 +#define suspend_usm_init() do { } while(0)
8915 +#define suspend_usb_cleanup() do { } while(0)
8916 +#endif
8917 diff -Naur linux-2.6.21-ck2/kernel/power/suspend.c linux-2.6.21-magellan-r11/kernel/power/suspend.c
8918 --- linux-2.6.21-ck2/kernel/power/suspend.c 1970-01-01 01:00:00.000000000 +0100
8919 +++ linux-2.6.21-magellan-r11/kernel/power/suspend.c 2007-08-17 15:57:25.000000000 +0200
8920 @@ -0,0 +1,1022 @@
8921 +/*
8922 + * kernel/power/suspend.c
8923 + */
8924 +/** \mainpage Suspend2.
8925 + *
8926 + * Suspend2 provides support for saving and restoring an image of
8927 + * system memory to an arbitrary storage device, either on the local computer,
8928 + * or across some network. The support is entirely OS based, so Suspend2
8929 + * works without requiring BIOS, APM or ACPI support. The vast majority of the
8930 + * code is also architecture independant, so it should be very easy to port
8931 + * the code to new architectures. Suspend includes support for SMP, 4G HighMem
8932 + * and preemption. Initramfses and initrds are also supported.
8933 + *
8934 + * Suspend2 uses a modular design, in which the method of storing the image is
8935 + * completely abstracted from the core code, as are transformations on the data
8936 + * such as compression and/or encryption (multiple 'modules' can be used to
8937 + * provide arbitrary combinations of functionality). The user interface is also
8938 + * modular, so that arbitrarily simple or complex interfaces can be used to
8939 + * provide anything from debugging information through to eye candy.
8940 + *
8941 + * \section Copyright
8942 + *
8943 + * Suspend2 is released under the GPLv2.
8944 + *
8945 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu><BR>
8946 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz><BR>
8947 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr><BR>
8948 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)<BR>
8949 + *
8950 + * \section Credits
8951 + *
8952 + * Nigel would like to thank the following people for their work:
8953 + *
8954 + * Bernard Blackham <bernard@blackham.com.au><BR>
8955 + * Web page & Wiki administration, some coding. A person without whom
8956 + * Suspend would not be where it is.
8957 + *
8958 + * Michael Frank <mhf@linuxmail.org><BR>
8959 + * Extensive testing and help with improving stability. I was constantly
8960 + * amazed by the quality and quantity of Michael's help.
8961 + *
8962 + * Pavel Machek <pavel@ucw.cz><BR>
8963 + * Modifications, defectiveness pointing, being with Gabor at the very beginning,
8964 + * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. Even
8965 + * though Pavel and I disagree on the direction suspend to disk should take, I
8966 + * appreciate the valuable work he did in helping Gabor get the concept working.
8967 + *
8968 + * ..and of course the myriads of Suspend2 users who have helped diagnose
8969 + * and fix bugs, made suggestions on how to improve the code, proofread
8970 + * documentation, and donated time and money.
8971 + *
8972 + * Thanks also to corporate sponsors:
8973 + *
8974 + * <B>Redhat.</B>Sometime employer from May 2006 (my fault, not Redhat's!).
8975 + *
8976 + * <B>Cyclades.com.</B> Nigel's employers from Dec 2004 until May 2006, who
8977 + * allowed him to work on Suspend and PM related issues on company time.
8978 + *
8979 + * <B>LinuxFund.org.</B> Sponsored Nigel's work on Suspend for four months Oct 2003
8980 + * to Jan 2004.
8981 + *
8982 + * <B>LAC Linux.</B> Donated P4 hardware that enabled development and ongoing
8983 + * maintenance of SMP and Highmem support.
8984 + *
8985 + * <B>OSDL.</B> Provided access to various hardware configurations, make occasional
8986 + * small donations to the project.
8987 + */
8988 +
8989 +#include <linux/suspend.h>
8990 +#include <linux/module.h>
8991 +#include <linux/freezer.h>
8992 +#include <linux/utsrelease.h>
8993 +#include <linux/cpu.h>
8994 +#include <linux/console.h>
8995 +#include <asm/uaccess.h>
8996 +
8997 +#include "modules.h"
8998 +#include "sysfs.h"
8999 +#include "prepare_image.h"
9000 +#include "io.h"
9001 +#include "ui.h"
9002 +#include "power_off.h"
9003 +#include "storage.h"
9004 +#include "checksum.h"
9005 +#include "cluster.h"
9006 +#include "suspend2_builtin.h"
9007 +
9008 +/*! Pageset metadata. */
9009 +struct pagedir pagedir2 = {2};
9010 +
9011 +static int get_pmsem = 0, got_pmsem;
9012 +static mm_segment_t oldfs;
9013 +static atomic_t actions_running;
9014 +static int block_dump_save;
9015 +extern int block_dump;
9016 +
9017 +int do_suspend2_step(int step);
9018 +
9019 +/*
9020 + * Basic clean-up routine.
9021 + */
9022 +void suspend_finish_anything(int suspend_or_resume)
9023 +{
9024 + if (!atomic_dec_and_test(&actions_running))
9025 + return;
9026 +
9027 + suspend_cleanup_modules(suspend_or_resume);
9028 + suspend_put_modules();
9029 + clear_suspend_state(SUSPEND_RUNNING);
9030 + set_fs(oldfs);
9031 + if (suspend_or_resume) {
9032 + block_dump = block_dump_save;
9033 + set_cpus_allowed(current, CPU_MASK_ALL);
9034 + }
9035 +}
9036 +
9037 +/*
9038 + * Basic set-up routine.
9039 + */
9040 +int suspend_start_anything(int suspend_or_resume)
9041 +{
9042 + if (atomic_add_return(1, &actions_running) != 1) {
9043 + if (suspend_or_resume) {
9044 + printk("Can't start a cycle when actions are "
9045 + "already running.\n");
9046 + atomic_dec(&actions_running);
9047 + return -EBUSY;
9048 + } else
9049 + return 0;
9050 + }
9051 +
9052 + oldfs = get_fs();
9053 + set_fs(KERNEL_DS);
9054 +
9055 + if (!suspendActiveAllocator) {
9056 + /* Be quiet if we're not trying to suspend or resume */
9057 + if (suspend_or_resume)
9058 + printk("No storage allocator is currently active. "
9059 + "Rechecking whether we can use one.\n");
9060 + suspend_attempt_to_parse_resume_device(!suspend_or_resume);
9061 + }
9062 +
9063 + set_suspend_state(SUSPEND_RUNNING);
9064 +
9065 + if (suspend_get_modules()) {
9066 + printk("Suspend2: Get modules failed!\n");
9067 + goto out_err;
9068 + }
9069 +
9070 + if (suspend_initialise_modules(suspend_or_resume)) {
9071 + printk("Suspend2: Initialise modules failed!\n");
9072 + goto out_err;
9073 + }
9074 +
9075 + if (suspend_or_resume) {
9076 + block_dump_save = block_dump;
9077 + block_dump = 0;
9078 + set_cpus_allowed(current, CPU_MASK_CPU0);
9079 + }
9080 +
9081 + return 0;
9082 +
9083 +out_err:
9084 + if (suspend_or_resume)
9085 + block_dump_save = block_dump;
9086 + suspend_finish_anything(suspend_or_resume);
9087 + return -EBUSY;
9088 +}
9089 +
9090 +/*
9091 + * Allocate & free bitmaps.
9092 + */
9093 +static int allocate_bitmaps(void)
9094 +{
9095 + if (allocate_dyn_pageflags(&pageset1_map) ||
9096 + allocate_dyn_pageflags(&pageset1_copy_map) ||
9097 + allocate_dyn_pageflags(&pageset2_map) ||
9098 + allocate_dyn_pageflags(&io_map) ||
9099 + allocate_dyn_pageflags(&page_resave_map))
9100 + return 1;
9101 +
9102 + return 0;
9103 +}
9104 +
9105 +static void free_bitmaps(void)
9106 +{
9107 + free_dyn_pageflags(&pageset1_map);
9108 + free_dyn_pageflags(&pageset1_copy_map);
9109 + free_dyn_pageflags(&pageset2_map);
9110 + free_dyn_pageflags(&io_map);
9111 + free_dyn_pageflags(&page_resave_map);
9112 +}
9113 +
9114 +static int io_MB_per_second(int read_write)
9115 +{
9116 + return (suspend_io_time[read_write][1]) ?
9117 + MB((unsigned long) suspend_io_time[read_write][0]) * HZ /
9118 + suspend_io_time[read_write][1] : 0;
9119 +}
9120 +
9121 +/* get_debug_info
9122 + * Functionality: Store debug info in a buffer.
9123 + */
9124 +#define SNPRINTF(a...) len += snprintf_used(((char *)buffer) + len, \
9125 + count - len - 1, ## a)
9126 +static int get_suspend_debug_info(const char *buffer, int count)
9127 +{
9128 + int len = 0;
9129 +
9130 + SNPRINTF("Suspend2 debugging info:\n");
9131 + SNPRINTF("- Suspend core : %s\n", SUSPEND_CORE_VERSION);
9132 + SNPRINTF("- Kernel Version : %s\n", UTS_RELEASE);
9133 + SNPRINTF("- Compiler vers. : %d.%d\n", __GNUC__, __GNUC_MINOR__);
9134 + SNPRINTF("- Attempt number : %d\n", nr_suspends);
9135 + SNPRINTF("- Parameters : %ld %ld %ld %d %d %ld\n",
9136 + suspend_result,
9137 + suspend_action,
9138 + suspend_debug_state,
9139 + suspend_default_console_level,
9140 + image_size_limit,
9141 + suspend2_poweroff_method);
9142 + SNPRINTF("- Overall expected compression percentage: %d.\n",
9143 + 100 - suspend_expected_compression_ratio());
9144 + len+= suspend_print_module_debug_info(((char *) buffer) + len,
9145 + count - len - 1);
9146 + if (suspend_io_time[0][1]) {
9147 + if ((io_MB_per_second(0) < 5) || (io_MB_per_second(1) < 5)) {
9148 + SNPRINTF("- I/O speed: Write %d KB/s",
9149 + (KB((unsigned long) suspend_io_time[0][0]) * HZ /
9150 + suspend_io_time[0][1]));
9151 + if (suspend_io_time[1][1])
9152 + SNPRINTF(", Read %d KB/s",
9153 + (KB((unsigned long) suspend_io_time[1][0]) * HZ /
9154 + suspend_io_time[1][1]));
9155 + } else {
9156 + SNPRINTF("- I/O speed: Write %d MB/s",
9157 + (MB((unsigned long) suspend_io_time[0][0]) * HZ /
9158 + suspend_io_time[0][1]));
9159 + if (suspend_io_time[1][1])
9160 + SNPRINTF(", Read %d MB/s",
9161 + (MB((unsigned long) suspend_io_time[1][0]) * HZ /
9162 + suspend_io_time[1][1]));
9163 + }
9164 + SNPRINTF(".\n");
9165 + }
9166 + else
9167 + SNPRINTF("- No I/O speed stats available.\n");
9168 + SNPRINTF("- Extra pages : %d used/%d.\n",
9169 + extra_pd1_pages_used, extra_pd1_pages_allowance);
9170 +
9171 + return len;
9172 +}
9173 +
9174 +/*
9175 + * do_cleanup
9176 + */
9177 +
9178 +static void do_cleanup(int get_debug_info)
9179 +{
9180 + int i = 0;
9181 + char *buffer = NULL;
9182 +
9183 + if (get_debug_info)
9184 + suspend_prepare_status(DONT_CLEAR_BAR, "Cleaning up...");
9185 + relink_lru_lists();
9186 +
9187 + free_checksum_pages();
9188 +
9189 + if (get_debug_info)
9190 + buffer = (char *) get_zeroed_page(GFP_ATOMIC);
9191 +
9192 + if (buffer)
9193 + i = get_suspend_debug_info(buffer, PAGE_SIZE);
9194 +
9195 + suspend_free_extra_pagedir_memory();
9196 +
9197 + pagedir1.size = pagedir2.size = 0;
9198 + set_highmem_size(pagedir1, 0);
9199 + set_highmem_size(pagedir2, 0);
9200 +
9201 + restore_avenrun();
9202 +
9203 + thaw_processes();
9204 +
9205 +#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
9206 + if (test_action_state(SUSPEND_KEEP_IMAGE) &&
9207 + !test_result_state(SUSPEND_ABORTED)) {
9208 + suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9209 + "Suspend2: Not invalidating the image due "
9210 + "to Keep Image being enabled.\n");
9211 + set_result_state(SUSPEND_KEPT_IMAGE);
9212 + } else
9213 +#endif
9214 + if (suspendActiveAllocator)
9215 + suspendActiveAllocator->invalidate_image();
9216 +
9217 + free_bitmaps();
9218 +
9219 + if (buffer && i) {
9220 + /* Printk can only handle 1023 bytes, including
9221 + * its level mangling. */
9222 + for (i = 0; i < 3; i++)
9223 + printk("%s", buffer + (1023 * i));
9224 + free_page((unsigned long) buffer);
9225 + }
9226 +
9227 + if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9228 + enable_nonboot_cpus();
9229 + suspend_cleanup_console();
9230 +
9231 + suspend_deactivate_storage(0);
9232 +
9233 + clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
9234 + clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
9235 + clear_suspend_state(SUSPEND_NOW_RESUMING);
9236 +
9237 + if (got_pmsem) {
9238 + mutex_unlock(&pm_mutex);
9239 + got_pmsem = 0;
9240 + }
9241 +}
9242 +
9243 +static int check_still_keeping_image(void)
9244 +{
9245 + if (test_action_state(SUSPEND_KEEP_IMAGE)) {
9246 + printk("Image already stored: powering down immediately.");
9247 + do_suspend2_step(STEP_SUSPEND_POWERDOWN);
9248 + return 1; /* Just in case we're using S3 */
9249 + }
9250 +
9251 + printk("Invalidating previous image.\n");
9252 + suspendActiveAllocator->invalidate_image();
9253 +
9254 + return 0;
9255 +}
9256 +
9257 +static int suspend_init(void)
9258 +{
9259 + suspend_result = 0;
9260 +
9261 + printk(KERN_INFO "Suspend2: Initiating a software suspend cycle.\n");
9262 +
9263 + nr_suspends++;
9264 +
9265 + save_avenrun();
9266 +
9267 + suspend_io_time[0][0] = suspend_io_time[0][1] =
9268 + suspend_io_time[1][0] = suspend_io_time[1][1] = 0;
9269 +
9270 + if (!test_suspend_state(SUSPEND_CAN_SUSPEND) ||
9271 + allocate_bitmaps())
9272 + return 0;
9273 +
9274 + suspend_prepare_console();
9275 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) ||
9276 + !disable_nonboot_cpus())
9277 + return 1;
9278 +
9279 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9280 + set_result_state(SUSPEND_ABORTED);
9281 + return 0;
9282 +}
9283 +
9284 +static int can_suspend(void)
9285 +{
9286 + if (get_pmsem) {
9287 + if (!mutex_trylock(&pm_mutex)) {
9288 + printk("Suspend2: Failed to obtain pm_mutex.\n");
9289 + dump_stack();
9290 + set_result_state(SUSPEND_ABORTED);
9291 + set_result_state(SUSPEND_PM_SEM);
9292 + return 0;
9293 + }
9294 + got_pmsem = 1;
9295 + }
9296 +
9297 + if (!test_suspend_state(SUSPEND_CAN_SUSPEND))
9298 + suspend_attempt_to_parse_resume_device(0);
9299 +
9300 + if (!test_suspend_state(SUSPEND_CAN_SUSPEND)) {
9301 + printk("Suspend2: Software suspend is disabled.\n"
9302 + "This may be because you haven't put something along "
9303 + "the lines of\n\nresume2=swap:/dev/hda1\n\n"
9304 + "in lilo.conf or equivalent. (Where /dev/hda1 is your "
9305 + "swap partition).\n");
9306 + set_result_state(SUSPEND_ABORTED);
9307 + if (!got_pmsem) {
9308 + mutex_unlock(&pm_mutex);
9309 + got_pmsem = 0;
9310 + }
9311 + return 0;
9312 + }
9313 +
9314 + return 1;
9315 +}
9316 +
9317 +static int do_power_down(void)
9318 +{
9319 + /* If switching images fails, do normal powerdown */
9320 + if (poweroff_resume2[0])
9321 + do_suspend2_step(STEP_RESUME_ALT_IMAGE);
9322 +
9323 + suspend_cond_pause(1, "About to power down or reboot.");
9324 + suspend2_power_down();
9325 +
9326 + /* If we return, it's because we suspended to ram */
9327 + if (read_pageset2(1))
9328 + panic("Attempt to reload pagedir 2 failed. Try rebooting.");
9329 +
9330 + barrier();
9331 + mb();
9332 + do_cleanup(1);
9333 + return 0;
9334 +}
9335 +
9336 +/*
9337 + * __save_image
9338 + * Functionality : High level routine which performs the steps necessary
9339 + * to save the image after preparatory steps have been taken.
9340 + * Key Assumptions : Processes frozen, sufficient memory available, drivers
9341 + * suspended.
9342 + */
9343 +static int __save_image(void)
9344 +{
9345 + int temp_result;
9346 +
9347 + suspend_prepare_status(DONT_CLEAR_BAR, "Starting to save the image..");
9348 +
9349 + suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9350 + " - Final values: %d and %d.\n",
9351 + pagedir1.size, pagedir2.size);
9352 +
9353 + suspend_cond_pause(1, "About to write pagedir2.");
9354 +
9355 + calculate_check_checksums(0);
9356 +
9357 + temp_result = write_pageset(&pagedir2);
9358 +
9359 + if (temp_result == -1 || test_result_state(SUSPEND_ABORTED))
9360 + return 1;
9361 +
9362 + suspend_cond_pause(1, "About to copy pageset 1.");
9363 +
9364 + if (test_result_state(SUSPEND_ABORTED))
9365 + return 1;
9366 +
9367 + suspend_deactivate_storage(1);
9368 +
9369 + suspend_prepare_status(DONT_CLEAR_BAR, "Doing atomic copy.");
9370 +
9371 + suspend2_in_suspend = 1;
9372 +
9373 + suspend_console();
9374 + if (device_suspend(PMSG_FREEZE)) {
9375 + set_result_state(SUSPEND_DEVICE_REFUSED);
9376 + set_result_state(SUSPEND_ABORTED);
9377 + goto ResumeConsole;
9378 + }
9379 +
9380 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG) &&
9381 + disable_nonboot_cpus()) {
9382 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9383 + set_result_state(SUSPEND_ABORTED);
9384 + } else
9385 + temp_result = suspend2_suspend();
9386 +
9387 + /* We return here at resume time too! */
9388 + if (!suspend2_in_suspend && pm_ops && pm_ops->finish &&
9389 + suspend2_poweroff_method > 3)
9390 + pm_ops->finish(suspend2_poweroff_method);
9391 +
9392 + if (test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9393 + enable_nonboot_cpus();
9394 +
9395 + device_resume();
9396 +
9397 +ResumeConsole:
9398 + resume_console();
9399 +
9400 + if (suspend_activate_storage(1))
9401 + panic("Failed to reactivate our storage.");
9402 +
9403 + if (temp_result || test_result_state(SUSPEND_ABORTED))
9404 + return 1;
9405 +
9406 + /* Resume time? */
9407 + if (!suspend2_in_suspend) {
9408 + copyback_post();
9409 + return 0;
9410 + }
9411 +
9412 + /* Nope. Suspending. So, see if we can save the image... */
9413 +
9414 + suspend_update_status(pagedir2.size,
9415 + pagedir1.size + pagedir2.size,
9416 + NULL);
9417 +
9418 + if (test_result_state(SUSPEND_ABORTED))
9419 + goto abort_reloading_pagedir_two;
9420 +
9421 + suspend_cond_pause(1, "About to write pageset1.");
9422 +
9423 + suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
9424 + "-- Writing pageset1\n");
9425 +
9426 + temp_result = write_pageset(&pagedir1);
9427 +
9428 + /* We didn't overwrite any memory, so no reread needs to be done. */
9429 + if (test_action_state(SUSPEND_TEST_FILTER_SPEED))
9430 + return 1;
9431 +
9432 + if (temp_result == 1 || test_result_state(SUSPEND_ABORTED))
9433 + goto abort_reloading_pagedir_two;
9434 +
9435 + suspend_cond_pause(1, "About to write header.");
9436 +
9437 + if (test_result_state(SUSPEND_ABORTED))
9438 + goto abort_reloading_pagedir_two;
9439 +
9440 + temp_result = write_image_header();
9441 +
9442 + if (test_action_state(SUSPEND_TEST_BIO))
9443 + return 1;
9444 +
9445 + if (!temp_result && !test_result_state(SUSPEND_ABORTED))
9446 + return 0;
9447 +
9448 +abort_reloading_pagedir_two:
9449 + temp_result = read_pageset2(1);
9450 +
9451 + /* If that failed, we're sunk. Panic! */
9452 + if (temp_result)
9453 + panic("Attempt to reload pagedir 2 while aborting "
9454 + "a suspend failed.");
9455 +
9456 + return 1;
9457 +}
9458 +
9459 +/*
9460 + * do_save_image
9461 + *
9462 + * Save the prepared image.
9463 + */
9464 +
9465 +static int do_save_image(void)
9466 +{
9467 + int result = __save_image();
9468 + if (!suspend2_in_suspend || result)
9469 + do_cleanup(1);
9470 + return result;
9471 +}
9472 +
9473 +
9474 +/* do_prepare_image
9475 + *
9476 + * Seek to initialise and prepare an image to be saved. On failure,
9477 + * cleanup.
9478 + */
9479 +
9480 +static int do_prepare_image(void)
9481 +{
9482 + if (suspend_activate_storage(0))
9483 + return 1;
9484 +
9485 + /*
9486 + * If kept image and still keeping image and suspending to RAM, we will
9487 + * return 1 after suspending and resuming (provided the power doesn't
9488 + * run out.
9489 + */
9490 +
9491 + if (!can_suspend() ||
9492 + (test_result_state(SUSPEND_KEPT_IMAGE) &&
9493 + check_still_keeping_image()))
9494 + goto cleanup;
9495 +
9496 + if (suspend_init() && !suspend_prepare_image() &&
9497 + !test_result_state(SUSPEND_ABORTED))
9498 + return 0;
9499 +
9500 +cleanup:
9501 + do_cleanup(0);
9502 + return 1;
9503 +}
9504 +
9505 +static int do_check_can_resume(void)
9506 +{
9507 + char *buf = (char *) get_zeroed_page(GFP_KERNEL);
9508 + int result = 0;
9509 +
9510 + if (!buf)
9511 + return 0;
9512 +
9513 + /* Only interested in first byte, so throw away return code. */
9514 + image_exists_read(buf, PAGE_SIZE);
9515 +
9516 + if (buf[0] == '1')
9517 + result = 1;
9518 +
9519 + free_page((unsigned long) buf);
9520 + return result;
9521 +}
9522 +
9523 +/*
9524 + * We check if we have an image and if so we try to resume.
9525 + */
9526 +static int do_load_atomic_copy(void)
9527 +{
9528 + int read_image_result = 0;
9529 +
9530 + if (sizeof(swp_entry_t) != sizeof(long)) {
9531 + printk(KERN_WARNING "Suspend2: The size of swp_entry_t != size"
9532 + " of long. Please report this!\n");
9533 + return 1;
9534 + }
9535 +
9536 + if (!resume2_file[0])
9537 + printk(KERN_WARNING "Suspend2: "
9538 + "You need to use a resume2= command line parameter to "
9539 + "tell Suspend2 where to look for an image.\n");
9540 +
9541 + suspend_activate_storage(0);
9542 +
9543 + if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK)) &&
9544 + !suspend_attempt_to_parse_resume_device(0)) {
9545 + /*
9546 + * Without a usable storage device we can do nothing -
9547 + * even if noresume is given
9548 + */
9549 +
9550 + if (!suspendNumAllocators)
9551 + printk(KERN_ALERT "Suspend2: "
9552 + "No storage allocators have been registered.\n");
9553 + else
9554 + printk(KERN_ALERT "Suspend2: "
9555 + "Missing or invalid storage location "
9556 + "(resume2= parameter). Please correct and "
9557 + "rerun lilo (or equivalent) before "
9558 + "suspending.\n");
9559 + suspend_deactivate_storage(0);
9560 + return 1;
9561 + }
9562 +
9563 + read_image_result = read_pageset1(); /* non fatal error ignored */
9564 +
9565 + if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
9566 + printk(KERN_WARNING "Suspend2: Resuming disabled as requested.\n");
9567 + clear_suspend_state(SUSPEND_NORESUME_SPECIFIED);
9568 + }
9569 +
9570 + suspend_deactivate_storage(0);
9571 +
9572 + if (read_image_result)
9573 + return 1;
9574 +
9575 + return 0;
9576 +}
9577 +
9578 +static void prepare_restore_load_alt_image(int prepare)
9579 +{
9580 + static dyn_pageflags_t pageset1_map_save, pageset1_copy_map_save;
9581 +
9582 + if (prepare) {
9583 + pageset1_map_save = pageset1_map;
9584 + pageset1_map = NULL;
9585 + pageset1_copy_map_save = pageset1_copy_map;
9586 + pageset1_copy_map = NULL;
9587 + set_suspend_state(SUSPEND_LOADING_ALT_IMAGE);
9588 + suspend_reset_alt_image_pageset2_pfn();
9589 + } else {
9590 + if (pageset1_map)
9591 + free_dyn_pageflags(&pageset1_map);
9592 + pageset1_map = pageset1_map_save;
9593 + if (pageset1_copy_map)
9594 + free_dyn_pageflags(&pageset1_copy_map);
9595 + pageset1_copy_map = pageset1_copy_map_save;
9596 + clear_suspend_state(SUSPEND_NOW_RESUMING);
9597 + clear_suspend_state(SUSPEND_LOADING_ALT_IMAGE);
9598 + }
9599 +}
9600 +
9601 +int pre_resume_freeze(void)
9602 +{
9603 + if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG)) {
9604 + suspend_prepare_status(DONT_CLEAR_BAR, "Disable nonboot cpus.");
9605 + if (disable_nonboot_cpus()) {
9606 + set_result_state(SUSPEND_CPU_HOTPLUG_FAILED);
9607 + set_result_state(SUSPEND_ABORTED);
9608 + return 1;
9609 + }
9610 + }
9611 +
9612 + suspend_prepare_status(DONT_CLEAR_BAR, "Freeze processes.");
9613 +
9614 + if (freeze_processes()) {
9615 + printk("Some processes failed to suspend\n");
9616 + return 1;
9617 + }
9618 +
9619 + return 0;
9620 +}
9621 +
9622 +void post_resume_thaw(void)
9623 +{
9624 + thaw_processes();
9625 + if (!test_action_state(SUSPEND_LATE_CPU_HOTPLUG))
9626 + enable_nonboot_cpus();
9627 +}
9628 +
9629 +int do_suspend2_step(int step)
9630 +{
9631 + int result;
9632 +
9633 + switch (step) {
9634 + case STEP_SUSPEND_PREPARE_IMAGE:
9635 + return do_prepare_image();
9636 + case STEP_SUSPEND_SAVE_IMAGE:
9637 + return do_save_image();
9638 + case STEP_SUSPEND_POWERDOWN:
9639 + return do_power_down();
9640 + case STEP_RESUME_CAN_RESUME:
9641 + return do_check_can_resume();
9642 + case STEP_RESUME_LOAD_PS1:
9643 + return do_load_atomic_copy();
9644 + case STEP_RESUME_DO_RESTORE:
9645 + /*
9646 + * If we succeed, this doesn't return.
9647 + * Instead, we return from do_save_image() in the
9648 + * suspended kernel.
9649 + */
9650 + result = suspend_atomic_restore();
9651 + if (result)
9652 + post_resume_thaw();
9653 + return result;
9654 + case STEP_RESUME_ALT_IMAGE:
9655 + printk("Trying to resume alternate image.\n");
9656 + suspend2_in_suspend = 0;
9657 + save_restore_resume2(SAVE, NOQUIET);
9658 + prepare_restore_load_alt_image(1);
9659 + if (!do_check_can_resume()) {
9660 + printk("Nothing to resume from.\n");
9661 + goto out;
9662 + }
9663 + if (!do_load_atomic_copy()) {
9664 + printk("Failed to load image.\n");
9665 + suspend_atomic_restore();
9666 + }
9667 +out:
9668 + prepare_restore_load_alt_image(0);
9669 + save_restore_resume2(RESTORE, NOQUIET);
9670 + break;
9671 + }
9672 +
9673 + return 0;
9674 +}
9675 +
9676 +/* -- Functions for kickstarting a suspend or resume --- */
9677 +
9678 +/*
9679 + * Check if we have an image and if so try to resume.
9680 + */
9681 +void __suspend2_try_resume(void)
9682 +{
9683 + set_suspend_state(SUSPEND_TRYING_TO_RESUME);
9684 + resume_attempted = 1;
9685 +
9686 + if (do_suspend2_step(STEP_RESUME_CAN_RESUME) &&
9687 + !do_suspend2_step(STEP_RESUME_LOAD_PS1))
9688 + do_suspend2_step(STEP_RESUME_DO_RESTORE);
9689 +
9690 + do_cleanup(0);
9691 +
9692 + clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
9693 + clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
9694 + clear_suspend_state(SUSPEND_NOW_RESUMING);
9695 +}
9696 +
9697 +/* Wrapper for when called from init/do_mounts.c */
9698 +void _suspend2_try_resume(void)
9699 +{
9700 + resume_attempted = 1;
9701 +
9702 + if (suspend_start_anything(SYSFS_RESUMING))
9703 + return;
9704 +
9705 + /* Unlock will be done in do_cleanup */
9706 + mutex_lock(&pm_mutex);
9707 + got_pmsem = 1;
9708 +
9709 + __suspend2_try_resume();
9710 +
9711 + /*
9712 + * For initramfs, we have to clear the boot time
9713 + * flag after trying to resume
9714 + */
9715 + clear_suspend_state(SUSPEND_BOOT_TIME);
9716 + suspend_finish_anything(SYSFS_RESUMING);
9717 +}
9718 +
9719 +/*
9720 + * _suspend2_try_suspend
9721 + * Functionality :
9722 + * Called From : drivers/acpi/sleep/main.c
9723 + * kernel/reboot.c
9724 + */
9725 +int _suspend2_try_suspend(int have_pmsem)
9726 +{
9727 + int result = 0, sys_power_disk = 0;
9728 +
9729 + if (!atomic_read(&actions_running)) {
9730 + /* Came in via /sys/power/disk */
9731 + if (suspend_start_anything(SYSFS_SUSPENDING))
9732 + return -EBUSY;
9733 + sys_power_disk = 1;
9734 + }
9735 +
9736 + get_pmsem = !have_pmsem;
9737 +
9738 + if (strlen(poweroff_resume2)) {
9739 + attempt_to_parse_po_resume_device2();
9740 +
9741 + if (!strlen(poweroff_resume2)) {
9742 + printk("Poweroff resume2 now invalid. Aborting.\n");
9743 + goto out;
9744 + }
9745 + }
9746 +
9747 + if ((result = do_suspend2_step(STEP_SUSPEND_PREPARE_IMAGE)))
9748 + goto out;
9749 +
9750 + if (test_action_state(SUSPEND_FREEZER_TEST)) {
9751 + do_cleanup(0);
9752 + goto out;
9753 + }
9754 +
9755 + if ((result = do_suspend2_step(STEP_SUSPEND_SAVE_IMAGE)))
9756 + goto out;
9757 +
9758 + /* This code runs at resume time too! */
9759 + if (suspend2_in_suspend)
9760 + result = do_suspend2_step(STEP_SUSPEND_POWERDOWN);
9761 +out:
9762 + if (sys_power_disk)
9763 + suspend_finish_anything(SYSFS_SUSPENDING);
9764 + return result;
9765 +}
9766 +
9767 +/*
9768 + * This array contains entries that are automatically registered at
9769 + * boot. Modules and the console code register their own entries separately.
9770 + */
9771 +static struct suspend_sysfs_data sysfs_params[] = {
9772 + { SUSPEND2_ATTR("extra_pages_allowance", SYSFS_RW),
9773 + SYSFS_INT(&extra_pd1_pages_allowance, 0, INT_MAX, 0)
9774 + },
9775 +
9776 + { SUSPEND2_ATTR("image_exists", SYSFS_RW),
9777 + SYSFS_CUSTOM(image_exists_read, image_exists_write,
9778 + SYSFS_NEEDS_SM_FOR_BOTH)
9779 + },
9780 +
9781 + { SUSPEND2_ATTR("resume2", SYSFS_RW),
9782 + SYSFS_STRING(resume2_file, 255, SYSFS_NEEDS_SM_FOR_WRITE),
9783 + .write_side_effect = attempt_to_parse_resume_device2,
9784 + },
9785 +
9786 + { SUSPEND2_ATTR("poweroff_resume2", SYSFS_RW),
9787 + SYSFS_STRING(poweroff_resume2, 255, SYSFS_NEEDS_SM_FOR_WRITE),
9788 + .write_side_effect = attempt_to_parse_po_resume_device2,
9789 + },
9790 + { SUSPEND2_ATTR("debug_info", SYSFS_READONLY),
9791 + SYSFS_CUSTOM(get_suspend_debug_info, NULL, 0)
9792 + },
9793 +
9794 + { SUSPEND2_ATTR("ignore_rootfs", SYSFS_RW),
9795 + SYSFS_BIT(&suspend_action, SUSPEND_IGNORE_ROOTFS, 0)
9796 + },
9797 +
9798 + { SUSPEND2_ATTR("image_size_limit", SYSFS_RW),
9799 + SYSFS_INT(&image_size_limit, -2, INT_MAX, 0)
9800 + },
9801 +
9802 + { SUSPEND2_ATTR("last_result", SYSFS_RW),
9803 + SYSFS_UL(&suspend_result, 0, 0, 0)
9804 + },
9805 +
9806 + { SUSPEND2_ATTR("no_multithreaded_io", SYSFS_RW),
9807 + SYSFS_BIT(&suspend_action, SUSPEND_NO_MULTITHREADED_IO, 0)
9808 + },
9809 +
9810 + { SUSPEND2_ATTR("full_pageset2", SYSFS_RW),
9811 + SYSFS_BIT(&suspend_action, SUSPEND_PAGESET2_FULL, 0)
9812 + },
9813 +
9814 + { SUSPEND2_ATTR("reboot", SYSFS_RW),
9815 + SYSFS_BIT(&suspend_action, SUSPEND_REBOOT, 0)
9816 + },
9817 +
9818 +#ifdef CONFIG_SOFTWARE_SUSPEND
9819 + { SUSPEND2_ATTR("replace_swsusp", SYSFS_RW),
9820 + SYSFS_BIT(&suspend_action, SUSPEND_REPLACE_SWSUSP, 0)
9821 + },
9822 +#endif
9823 +
9824 + { SUSPEND2_ATTR("resume_commandline", SYSFS_RW),
9825 + SYSFS_STRING(suspend2_nosave_commandline, COMMAND_LINE_SIZE, 0)
9826 + },
9827 +
9828 + { SUSPEND2_ATTR("version", SYSFS_READONLY),
9829 + SYSFS_STRING(SUSPEND_CORE_VERSION, 0, 0)
9830 + },
9831 +
9832 + { SUSPEND2_ATTR("no_load_direct", SYSFS_RW),
9833 + SYSFS_BIT(&suspend_action, SUSPEND_NO_DIRECT_LOAD, 0)
9834 + },
9835 +
9836 + { SUSPEND2_ATTR("freezer_test", SYSFS_RW),
9837 + SYSFS_BIT(&suspend_action, SUSPEND_FREEZER_TEST, 0)
9838 + },
9839 +
9840 + { SUSPEND2_ATTR("test_bio", SYSFS_RW),
9841 + SYSFS_BIT(&suspend_action, SUSPEND_TEST_BIO, 0)
9842 + },
9843 +
9844 + { SUSPEND2_ATTR("test_filter_speed", SYSFS_RW),
9845 + SYSFS_BIT(&suspend_action, SUSPEND_TEST_FILTER_SPEED, 0)
9846 + },
9847 +
9848 + { SUSPEND2_ATTR("slow", SYSFS_RW),
9849 + SYSFS_BIT(&suspend_action, SUSPEND_SLOW, 0)
9850 + },
9851 +
9852 + { SUSPEND2_ATTR("no_pageset2", SYSFS_RW),
9853 + SYSFS_BIT(&suspend_action, SUSPEND_NO_PAGESET2, 0)
9854 + },
9855 +
9856 + { SUSPEND2_ATTR("late_cpu_hotplug", SYSFS_RW),
9857 + SYSFS_BIT(&suspend_action, SUSPEND_LATE_CPU_HOTPLUG, 0)
9858 + },
9859 +
9860 +#if defined(CONFIG_ACPI)
9861 + { SUSPEND2_ATTR("powerdown_method", SYSFS_RW),
9862 + SYSFS_UL(&suspend2_poweroff_method, 0, 5, 0)
9863 + },
9864 +#endif
9865 +
9866 +#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
9867 + { SUSPEND2_ATTR("keep_image", SYSFS_RW),
9868 + SYSFS_BIT(&suspend_action, SUSPEND_KEEP_IMAGE, 0)
9869 + },
9870 +#endif
9871 +};
9872 +
9873 +struct suspend2_core_fns my_fns = {
9874 + .get_nonconflicting_page = __suspend_get_nonconflicting_page,
9875 + .post_context_save = __suspend_post_context_save,
9876 + .try_suspend = _suspend2_try_suspend,
9877 + .try_resume = _suspend2_try_resume,
9878 +};
9879 +
9880 +static __init int core_load(void)
9881 +{
9882 + int i,
9883 + numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
9884 +
9885 + printk("Suspend v" SUSPEND_CORE_VERSION "\n");
9886 +
9887 + if (s2_sysfs_init())
9888 + return 1;
9889 +
9890 + for (i=0; i< numfiles; i++)
9891 + suspend_register_sysfs_file(&suspend2_subsys.kset.kobj,
9892 + &sysfs_params[i]);
9893 +
9894 + s2_core_fns = &my_fns;
9895 +
9896 + if (s2_checksum_init())
9897 + return 1;
9898 + if (s2_cluster_init())
9899 + return 1;
9900 + if (s2_usm_init())
9901 + return 1;
9902 + if (s2_ui_init())
9903 + return 1;
9904 +
9905 +#ifdef CONFIG_SOFTWARE_SUSPEND
9906 + /* Overriding resume2= with resume=? */
9907 + if (test_action_state(SUSPEND_REPLACE_SWSUSP) && resume_file[0])
9908 + strncpy(resume2_file, resume_file, 256);
9909 +#endif
9910 +
9911 + return 0;
9912 +}
9913 +
9914 +#ifdef MODULE
9915 +static __exit void core_unload(void)
9916 +{
9917 + int i,
9918 + numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
9919 +
9920 + s2_ui_exit();
9921 + s2_checksum_exit();
9922 + s2_cluster_exit();
9923 + s2_usm_exit();
9924 +
9925 + for (i=0; i< numfiles; i++)
9926 + suspend_unregister_sysfs_file(&suspend2_subsys.kset.kobj,
9927 + &sysfs_params[i]);
9928 +
9929 + s2_core_fns = NULL;
9930 +
9931 + s2_sysfs_exit();
9932 +}
9933 +MODULE_LICENSE("GPL");
9934 +module_init(core_load);
9935 +module_exit(core_unload);
9936 +#else
9937 +late_initcall(core_load);
9938 +#endif
9939 +
9940 +#ifdef CONFIG_SUSPEND2_EXPORTS
9941 +EXPORT_SYMBOL_GPL(pagedir2);
9942 +#endif
9943 diff -Naur linux-2.6.21-ck2/kernel/power/suspend.h linux-2.6.21-magellan-r11/kernel/power/suspend.h
9944 --- linux-2.6.21-ck2/kernel/power/suspend.h 1970-01-01 01:00:00.000000000 +0100
9945 +++ linux-2.6.21-magellan-r11/kernel/power/suspend.h 2007-08-17 15:57:25.000000000 +0200
9946 @@ -0,0 +1,182 @@
9947 +/*
9948 + * kernel/power/suspend.h
9949 + *
9950 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
9951 + *
9952 + * This file is released under the GPLv2.
9953 + *
9954 + * It contains declarations used throughout swsusp.
9955 + *
9956 + */
9957 +
9958 +#ifndef KERNEL_POWER_SUSPEND_H
9959 +#define KERNEL_POWER_SUSPEND_H
9960 +
9961 +#include <linux/delay.h>
9962 +#include <linux/bootmem.h>
9963 +#include <linux/suspend.h>
9964 +#include <linux/dyn_pageflags.h>
9965 +#include <asm/setup.h>
9966 +#include "pageflags.h"
9967 +
9968 +#define SUSPEND_CORE_VERSION "2.2.10"
9969 +
9970 +/* == Action states == */
9971 +
9972 +enum {
9973 + SUSPEND_REBOOT,
9974 + SUSPEND_PAUSE,
9975 + SUSPEND_SLOW,
9976 + SUSPEND_LOGALL,
9977 + SUSPEND_CAN_CANCEL,
9978 + SUSPEND_KEEP_IMAGE,
9979 + SUSPEND_FREEZER_TEST,
9980 + SUSPEND_SINGLESTEP,
9981 + SUSPEND_PAUSE_NEAR_PAGESET_END,
9982 + SUSPEND_TEST_FILTER_SPEED,
9983 + SUSPEND_TEST_BIO,
9984 + SUSPEND_NO_PAGESET2,
9985 + SUSPEND_PM_PREPARE_CONSOLE,
9986 + SUSPEND_IGNORE_ROOTFS,
9987 + SUSPEND_REPLACE_SWSUSP,
9988 + SUSPEND_RETRY_RESUME,
9989 + SUSPEND_PAGESET2_FULL,
9990 + SUSPEND_ABORT_ON_RESAVE_NEEDED,
9991 + SUSPEND_NO_MULTITHREADED_IO,
9992 + SUSPEND_NO_DIRECT_LOAD,
9993 + SUSPEND_LATE_CPU_HOTPLUG,
9994 +};
9995 +
9996 +extern unsigned long suspend_action;
9997 +
9998 +#define clear_action_state(bit) (test_and_clear_bit(bit, &suspend_action))
9999 +#define test_action_state(bit) (test_bit(bit, &suspend_action))
10000 +
10001 +/* == Result states == */
10002 +
10003 +enum {
10004 + SUSPEND_ABORTED,
10005 + SUSPEND_ABORT_REQUESTED,
10006 + SUSPEND_NOSTORAGE_AVAILABLE,
10007 + SUSPEND_INSUFFICIENT_STORAGE,
10008 + SUSPEND_FREEZING_FAILED,
10009 + SUSPEND_UNEXPECTED_ALLOC,
10010 + SUSPEND_KEPT_IMAGE,
10011 + SUSPEND_WOULD_EAT_MEMORY,
10012 + SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY,
10013 + SUSPEND_ENCRYPTION_SETUP_FAILED,
10014 + SUSPEND_PM_SEM,
10015 + SUSPEND_DEVICE_REFUSED,
10016 + SUSPEND_EXTRA_PAGES_ALLOW_TOO_SMALL,
10017 + SUSPEND_UNABLE_TO_PREPARE_IMAGE,
10018 + SUSPEND_FAILED_MODULE_INIT,
10019 + SUSPEND_FAILED_MODULE_CLEANUP,
10020 + SUSPEND_FAILED_IO,
10021 + SUSPEND_OUT_OF_MEMORY,
10022 + SUSPEND_IMAGE_ERROR,
10023 + SUSPEND_PLATFORM_PREP_FAILED,
10024 + SUSPEND_CPU_HOTPLUG_FAILED,
10025 +};
10026 +
10027 +extern unsigned long suspend_result;
10028 +
10029 +#define set_result_state(bit) (test_and_set_bit(bit, &suspend_result))
10030 +#define clear_result_state(bit) (test_and_clear_bit(bit, &suspend_result))
10031 +#define test_result_state(bit) (test_bit(bit, &suspend_result))
10032 +
10033 +/* == Debug sections and levels == */
10034 +
10035 +/* debugging levels. */
10036 +enum {
10037 + SUSPEND_STATUS = 0,
10038 + SUSPEND_ERROR = 2,
10039 + SUSPEND_LOW,
10040 + SUSPEND_MEDIUM,
10041 + SUSPEND_HIGH,
10042 + SUSPEND_VERBOSE,
10043 +};
10044 +
10045 +enum {
10046 + SUSPEND_ANY_SECTION,
10047 + SUSPEND_EAT_MEMORY,
10048 + SUSPEND_IO,
10049 + SUSPEND_HEADER,
10050 + SUSPEND_WRITER,
10051 + SUSPEND_MEMORY,
10052 +};
10053 +
10054 +extern unsigned long suspend_debug_state;
10055 +
10056 +#define set_debug_state(bit) (test_and_set_bit(bit, &suspend_debug_state))
10057 +#define clear_debug_state(bit) (test_and_clear_bit(bit, &suspend_debug_state))
10058 +#define test_debug_state(bit) (test_bit(bit, &suspend_debug_state))
10059 +
10060 +/* == Steps in suspending == */
10061 +
10062 +enum {
10063 + STEP_SUSPEND_PREPARE_IMAGE,
10064 + STEP_SUSPEND_SAVE_IMAGE,
10065 + STEP_SUSPEND_POWERDOWN,
10066 + STEP_RESUME_CAN_RESUME,
10067 + STEP_RESUME_LOAD_PS1,
10068 + STEP_RESUME_DO_RESTORE,
10069 + STEP_RESUME_READ_PS2,
10070 + STEP_RESUME_GO,
10071 + STEP_RESUME_ALT_IMAGE,
10072 +};
10073 +
10074 +/* == Suspend states ==
10075 + (see also include/linux/suspend.h) */
10076 +
10077 +#define get_suspend_state() (suspend_state)
10078 +#define restore_suspend_state(saved_state) \
10079 + do { suspend_state = saved_state; } while(0)
10080 +
10081 +/* == Module support == */
10082 +
10083 +struct suspend2_core_fns {
10084 + int (*post_context_save)(void);
10085 + unsigned long (*get_nonconflicting_page)(void);
10086 + int (*try_suspend)(int have_pmsem);
10087 + void (*try_resume)(void);
10088 +};
10089 +
10090 +extern struct suspend2_core_fns *s2_core_fns;
10091 +
10092 +/* == All else == */
10093 +#define KB(x) ((x) << (PAGE_SHIFT - 10))
10094 +#define MB(x) ((x) >> (20 - PAGE_SHIFT))
10095 +
10096 +extern int suspend_start_anything(int suspend_or_resume);
10097 +extern void suspend_finish_anything(int suspend_or_resume);
10098 +
10099 +extern int save_image_part1(void);
10100 +extern int suspend_atomic_restore(void);
10101 +
10102 +extern int _suspend2_try_suspend(int have_pmsem);
10103 +extern void __suspend2_try_resume(void);
10104 +
10105 +extern int __suspend_post_context_save(void);
10106 +
10107 +extern unsigned int nr_suspends;
10108 +extern char resume2_file[256];
10109 +extern char poweroff_resume2[256];
10110 +
10111 +extern void copyback_post(void);
10112 +extern int suspend2_suspend(void);
10113 +extern int extra_pd1_pages_used;
10114 +
10115 +extern int suspend_io_time[2][2];
10116 +
10117 +#define SECTOR_SIZE 512
10118 +
10119 +extern int suspend_early_boot_message
10120 + (int can_erase_image, int default_answer, char *warning_reason, ...);
10121 +
10122 +static inline int load_direct(struct page *page)
10123 +{
10124 + return test_action_state(SUSPEND_NO_DIRECT_LOAD) ? 0 : PagePageset1Copy(page);
10125 +}
10126 +
10127 +extern int pre_resume_freeze(void);
10128 +#endif
10129 diff -Naur linux-2.6.21-ck2/kernel/power/suspend2_builtin.c linux-2.6.21-magellan-r11/kernel/power/suspend2_builtin.c
10130 --- linux-2.6.21-ck2/kernel/power/suspend2_builtin.c 1970-01-01 01:00:00.000000000 +0100
10131 +++ linux-2.6.21-magellan-r11/kernel/power/suspend2_builtin.c 2007-08-17 15:57:25.000000000 +0200
10132 @@ -0,0 +1,289 @@
10133 +/*
10134 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10135 + *
10136 + * This file is released under the GPLv2.
10137 + */
10138 +#include <linux/module.h>
10139 +#include <linux/resume-trace.h>
10140 +#include <linux/syscalls.h>
10141 +#include <linux/kernel.h>
10142 +#include <linux/swap.h>
10143 +#include <linux/syscalls.h>
10144 +#include <linux/bio.h>
10145 +#include <linux/root_dev.h>
10146 +#include <linux/freezer.h>
10147 +#include <linux/reboot.h>
10148 +#include <linux/writeback.h>
10149 +#include <linux/tty.h>
10150 +#include <linux/crypto.h>
10151 +#include <linux/cpu.h>
10152 +#include <linux/dyn_pageflags.h>
10153 +#include "io.h"
10154 +#include "suspend.h"
10155 +#include "extent.h"
10156 +#include "block_io.h"
10157 +#include "netlink.h"
10158 +#include "prepare_image.h"
10159 +#include "ui.h"
10160 +#include "sysfs.h"
10161 +#include "pagedir.h"
10162 +#include "modules.h"
10163 +#include "suspend2_builtin.h"
10164 +
10165 +#ifdef CONFIG_SUSPEND2_CORE_EXPORTS
10166 +#ifdef CONFIG_SOFTWARE_SUSPEND
10167 +EXPORT_SYMBOL_GPL(resume_file);
10168 +#endif
10169 +
10170 +EXPORT_SYMBOL_GPL(max_pfn);
10171 +EXPORT_SYMBOL_GPL(free_dyn_pageflags);
10172 +EXPORT_SYMBOL_GPL(clear_dynpageflag);
10173 +EXPORT_SYMBOL_GPL(test_dynpageflag);
10174 +EXPORT_SYMBOL_GPL(set_dynpageflag);
10175 +EXPORT_SYMBOL_GPL(get_next_bit_on);
10176 +EXPORT_SYMBOL_GPL(allocate_dyn_pageflags);
10177 +EXPORT_SYMBOL_GPL(clear_dyn_pageflags);
10178 +
10179 +#ifdef CONFIG_X86_64
10180 +EXPORT_SYMBOL_GPL(restore_processor_state);
10181 +EXPORT_SYMBOL_GPL(save_processor_state);
10182 +#endif
10183 +
10184 +EXPORT_SYMBOL_GPL(kernel_shutdown_prepare);
10185 +EXPORT_SYMBOL_GPL(drop_pagecache);
10186 +EXPORT_SYMBOL_GPL(restore_pblist);
10187 +EXPORT_SYMBOL_GPL(pm_mutex);
10188 +EXPORT_SYMBOL_GPL(pm_restore_console);
10189 +EXPORT_SYMBOL_GPL(super_blocks);
10190 +EXPORT_SYMBOL_GPL(next_zone);
10191 +
10192 +EXPORT_SYMBOL_GPL(freeze_processes);
10193 +EXPORT_SYMBOL_GPL(thaw_processes);
10194 +EXPORT_SYMBOL_GPL(thaw_kernel_threads);
10195 +EXPORT_SYMBOL_GPL(shrink_all_memory);
10196 +EXPORT_SYMBOL_GPL(shrink_one_zone);
10197 +EXPORT_SYMBOL_GPL(saveable_page);
10198 +EXPORT_SYMBOL_GPL(swsusp_arch_suspend);
10199 +EXPORT_SYMBOL_GPL(swsusp_arch_resume);
10200 +EXPORT_SYMBOL_GPL(pm_ops);
10201 +EXPORT_SYMBOL_GPL(pm_prepare_console);
10202 +EXPORT_SYMBOL_GPL(follow_page);
10203 +EXPORT_SYMBOL_GPL(machine_halt);
10204 +EXPORT_SYMBOL_GPL(block_dump);
10205 +EXPORT_SYMBOL_GPL(unlink_lru_lists);
10206 +EXPORT_SYMBOL_GPL(relink_lru_lists);
10207 +EXPORT_SYMBOL_GPL(power_subsys);
10208 +EXPORT_SYMBOL_GPL(machine_power_off);
10209 +EXPORT_SYMBOL_GPL(suspend_enter);
10210 +EXPORT_SYMBOL_GPL(first_online_pgdat);
10211 +EXPORT_SYMBOL_GPL(next_online_pgdat);
10212 +EXPORT_SYMBOL_GPL(machine_restart);
10213 +EXPORT_SYMBOL_GPL(saved_command_line);
10214 +EXPORT_SYMBOL_GPL(tasklist_lock);
10215 +#ifdef CONFIG_SUSPEND_SMP
10216 +EXPORT_SYMBOL_GPL(disable_nonboot_cpus);
10217 +EXPORT_SYMBOL_GPL(enable_nonboot_cpus);
10218 +#endif
10219 +#endif
10220 +
10221 +#ifdef CONFIG_SUSPEND2_USERUI_EXPORTS
10222 +EXPORT_SYMBOL_GPL(kmsg_redirect);
10223 +#ifndef CONFIG_COMPAT
10224 +EXPORT_SYMBOL_GPL(sys_ioctl);
10225 +#endif
10226 +#endif
10227 +
10228 +#if defined(CONFIG_SUSPEND2_USERUI_EXPORTS) || defined(CONFIG_SUSPEND2_CORE_EXPORTS)
10229 +EXPORT_SYMBOL_GPL(console_printk);
10230 +#endif
10231 +#ifdef CONFIG_SUSPEND2_SWAP_EXPORTS /* Suspend swap specific */
10232 +EXPORT_SYMBOL_GPL(sys_swapon);
10233 +EXPORT_SYMBOL_GPL(sys_swapoff);
10234 +EXPORT_SYMBOL_GPL(si_swapinfo);
10235 +EXPORT_SYMBOL_GPL(map_swap_page);
10236 +EXPORT_SYMBOL_GPL(get_swap_page);
10237 +EXPORT_SYMBOL_GPL(swap_free);
10238 +EXPORT_SYMBOL_GPL(get_swap_info_struct);
10239 +#endif
10240 +
10241 +#ifdef CONFIG_SUSPEND2_FILE_EXPORTS
10242 +/* Suspend_file specific */
10243 +extern char * __initdata root_device_name;
10244 +
10245 +EXPORT_SYMBOL_GPL(ROOT_DEV);
10246 +EXPORT_SYMBOL_GPL(root_device_name);
10247 +EXPORT_SYMBOL_GPL(sys_unlink);
10248 +EXPORT_SYMBOL_GPL(sys_mknod);
10249 +#endif
10250 +
10251 +/* Swap or file */
10252 +#if defined(CONFIG_SUSPEND2_FILE_EXPORTS) || defined(CONFIG_SUSPEND2_SWAP_EXPORTS)
10253 +EXPORT_SYMBOL_GPL(bio_set_pages_dirty);
10254 +EXPORT_SYMBOL_GPL(name_to_dev_t);
10255 +#endif
10256 +
10257 +#if defined(CONFIG_SUSPEND2_EXPORTS) || defined(CONFIG_SUSPEND2_CORE_EXPORTS)
10258 +EXPORT_SYMBOL_GPL(snprintf_used);
10259 +#endif
10260 +struct suspend2_core_fns *s2_core_fns;
10261 +EXPORT_SYMBOL_GPL(s2_core_fns);
10262 +
10263 +dyn_pageflags_t pageset1_map;
10264 +dyn_pageflags_t pageset1_copy_map;
10265 +EXPORT_SYMBOL_GPL(pageset1_map);
10266 +EXPORT_SYMBOL_GPL(pageset1_copy_map);
10267 +
10268 +unsigned long suspend_result = 0;
10269 +unsigned long suspend_debug_state = 0;
10270 +int suspend_io_time[2][2];
10271 +struct pagedir pagedir1 = {1};
10272 +
10273 +EXPORT_SYMBOL_GPL(suspend_io_time);
10274 +EXPORT_SYMBOL_GPL(suspend_debug_state);
10275 +EXPORT_SYMBOL_GPL(suspend_result);
10276 +EXPORT_SYMBOL_GPL(pagedir1);
10277 +
10278 +unsigned long suspend_get_nonconflicting_page(void)
10279 +{
10280 + return s2_core_fns->get_nonconflicting_page();
10281 +}
10282 +
10283 +int suspend_post_context_save(void)
10284 +{
10285 + return s2_core_fns->post_context_save();
10286 +}
10287 +
10288 +int suspend2_try_suspend(int have_pmsem)
10289 +{
10290 + if (!s2_core_fns)
10291 + return -ENODEV;
10292 +
10293 + return s2_core_fns->try_suspend(have_pmsem);
10294 +}
10295 +
10296 +void suspend2_try_resume(void)
10297 +{
10298 + if (s2_core_fns)
10299 + s2_core_fns->try_resume();
10300 +}
10301 +
10302 +int suspend2_lowlevel_builtin(void)
10303 +{
10304 + int error = 0;
10305 +
10306 + save_processor_state();
10307 + if ((error = swsusp_arch_suspend()))
10308 + printk(KERN_ERR "Error %d suspending\n", error);
10309 + /* Restore control flow appears here */
10310 + restore_processor_state();
10311 +
10312 + return error;
10313 +}
10314 +
10315 +EXPORT_SYMBOL_GPL(suspend2_lowlevel_builtin);
10316 +
10317 +unsigned long suspend_compress_bytes_in, suspend_compress_bytes_out;
10318 +EXPORT_SYMBOL_GPL(suspend_compress_bytes_in);
10319 +EXPORT_SYMBOL_GPL(suspend_compress_bytes_out);
10320 +
10321 +#ifdef CONFIG_SUSPEND2_REPLACE_SWSUSP
10322 +unsigned long suspend_action = (1 << SUSPEND_REPLACE_SWSUSP) | (1 << SUSPEND_PAGESET2_FULL);
10323 +#else
10324 +unsigned long suspend_action = 1 << SUSPEND_PAGESET2_FULL;
10325 +#endif
10326 +EXPORT_SYMBOL_GPL(suspend_action);
10327 +
10328 +unsigned long suspend_state = ((1 << SUSPEND_BOOT_TIME) |
10329 + (1 << SUSPEND_IGNORE_LOGLEVEL) |
10330 + (1 << SUSPEND_IO_STOPPED));
10331 +EXPORT_SYMBOL_GPL(suspend_state);
10332 +
10333 +/* The number of suspends we have started (some may have been cancelled) */
10334 +unsigned int nr_suspends;
10335 +EXPORT_SYMBOL_GPL(nr_suspends);
10336 +
10337 +char resume2_file[256] = CONFIG_SUSPEND2_DEFAULT_RESUME2;
10338 +EXPORT_SYMBOL_GPL(resume2_file);
10339 +
10340 +int suspend2_running = 0;
10341 +EXPORT_SYMBOL_GPL(suspend2_running);
10342 +
10343 +int suspend2_in_suspend __nosavedata;
10344 +EXPORT_SYMBOL_GPL(suspend2_in_suspend);
10345 +
10346 +unsigned long suspend2_nosave_state1 __nosavedata = 0;
10347 +unsigned long suspend2_nosave_state2 __nosavedata = 0;
10348 +int suspend2_nosave_state3 __nosavedata = 0;
10349 +int suspend2_nosave_io_speed[2][2] __nosavedata;
10350 +__nosavedata char suspend2_nosave_commandline[COMMAND_LINE_SIZE];
10351 +
10352 +__nosavedata struct pbe *restore_highmem_pblist;
10353 +
10354 +#ifdef CONFIG_SUSPEND2_CORE_EXPORTS
10355 +#ifdef CONFIG_HIGHMEM
10356 +EXPORT_SYMBOL_GPL(nr_free_highpages);
10357 +EXPORT_SYMBOL_GPL(saveable_highmem_page);
10358 +EXPORT_SYMBOL_GPL(restore_highmem_pblist);
10359 +#endif
10360 +
10361 +EXPORT_SYMBOL_GPL(suspend2_nosave_state1);
10362 +EXPORT_SYMBOL_GPL(suspend2_nosave_state2);
10363 +EXPORT_SYMBOL_GPL(suspend2_nosave_state3);
10364 +EXPORT_SYMBOL_GPL(suspend2_nosave_io_speed);
10365 +EXPORT_SYMBOL_GPL(suspend2_nosave_commandline);
10366 +#endif
10367 +
10368 +/* -- Commandline Parameter Handling ---
10369 + *
10370 + * Resume setup: obtain the storage device.
10371 + */
10372 +static int __init resume2_setup(char *str)
10373 +{
10374 + if (!*str)
10375 + return 0;
10376 +
10377 + strncpy(resume2_file, str, 255);
10378 + return 0;
10379 +}
10380 +
10381 +/*
10382 + * Allow the user to specify that we should ignore any image found and
10383 + * invalidate the image if necesssary. This is equivalent to running
10384 + * the task queue and a sync and then turning off the power. The same
10385 + * precautions should be taken: fsck if you're not journalled.
10386 + */
10387 +static int __init noresume2_setup(char *str)
10388 +{
10389 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
10390 + return 0;
10391 +}
10392 +
10393 +static int __init suspend_retry_resume_setup(char *str)
10394 +{
10395 + set_suspend_state(SUSPEND_RETRY_RESUME);
10396 + return 0;
10397 +}
10398 +
10399 +#ifndef CONFIG_SOFTWARE_SUSPEND
10400 +static int __init resume_setup(char *str)
10401 +{
10402 + if (!*str)
10403 + return 0;
10404 +
10405 + strncpy(resume2_file, str, 255);
10406 + return 0;
10407 +}
10408 +
10409 +static int __init noresume_setup(char *str)
10410 +{
10411 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
10412 + return 0;
10413 +}
10414 +__setup("noresume", noresume_setup);
10415 +__setup("resume=", resume_setup);
10416 +#endif
10417 +
10418 +__setup("noresume2", noresume2_setup);
10419 +__setup("resume2=", resume2_setup);
10420 +__setup("suspend_retry_resume", suspend_retry_resume_setup);
10421 +
10422 diff -Naur linux-2.6.21-ck2/kernel/power/suspend2_builtin.h linux-2.6.21-magellan-r11/kernel/power/suspend2_builtin.h
10423 --- linux-2.6.21-ck2/kernel/power/suspend2_builtin.h 1970-01-01 01:00:00.000000000 +0100
10424 +++ linux-2.6.21-magellan-r11/kernel/power/suspend2_builtin.h 2007-08-17 15:57:25.000000000 +0200
10425 @@ -0,0 +1,35 @@
10426 +/*
10427 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10428 + *
10429 + * This file is released under the GPLv2.
10430 + */
10431 +#include <linux/dyn_pageflags.h>
10432 +#include <asm/setup.h>
10433 +
10434 +extern struct suspend2_core_fns *s2_core_fns;
10435 +extern unsigned long suspend_compress_bytes_in, suspend_compress_bytes_out;
10436 +extern unsigned long suspend_action;
10437 +extern unsigned int nr_suspends;
10438 +extern char resume2_file[256];
10439 +extern int suspend2_in_suspend;
10440 +
10441 +extern unsigned long suspend2_nosave_state1 __nosavedata;
10442 +extern unsigned long suspend2_nosave_state2 __nosavedata;
10443 +extern int suspend2_nosave_state3 __nosavedata;
10444 +extern int suspend2_nosave_io_speed[2][2] __nosavedata;
10445 +extern __nosavedata char suspend2_nosave_commandline[COMMAND_LINE_SIZE];
10446 +extern __nosavedata struct pbe *restore_highmem_pblist;
10447 +
10448 +int suspend2_lowlevel_builtin(void);
10449 +
10450 +extern dyn_pageflags_t __nosavedata suspend2_nosave_origmap;
10451 +extern dyn_pageflags_t __nosavedata suspend2_nosave_copymap;
10452 +
10453 +#ifdef CONFIG_HIGHMEM
10454 +extern __nosavedata struct zone_data *suspend2_nosave_zone_list;
10455 +extern __nosavedata unsigned long suspend2_nosave_max_pfn;
10456 +#endif
10457 +
10458 +extern unsigned long suspend_get_nonconflicting_page(void);
10459 +extern int suspend_post_context_save(void);
10460 +extern int suspend2_try_suspend(int have_pmsem);
10461 diff -Naur linux-2.6.21-ck2/kernel/power/suspend_block_io.c linux-2.6.21-magellan-r11/kernel/power/suspend_block_io.c
10462 --- linux-2.6.21-ck2/kernel/power/suspend_block_io.c 1970-01-01 01:00:00.000000000 +0100
10463 +++ linux-2.6.21-magellan-r11/kernel/power/suspend_block_io.c 2007-08-17 15:57:25.000000000 +0200
10464 @@ -0,0 +1,1020 @@
10465 +/*
10466 + * kernel/power/suspend_block_io.c
10467 + *
10468 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
10469 + *
10470 + * Distributed under GPLv2.
10471 + *
10472 + * This file contains block io functions for suspend2. These are
10473 + * used by the swapwriter and it is planned that they will also
10474 + * be used by the NFSwriter.
10475 + *
10476 + */
10477 +
10478 +#include <linux/blkdev.h>
10479 +#include <linux/syscalls.h>
10480 +#include <linux/suspend.h>
10481 +
10482 +#include "suspend.h"
10483 +#include "sysfs.h"
10484 +#include "modules.h"
10485 +#include "prepare_image.h"
10486 +#include "block_io.h"
10487 +#include "ui.h"
10488 +
10489 +static int pr_index;
10490 +
10491 +#if 0
10492 +#define PR_DEBUG(a, b...) do { if (pr_index < 20) printk(a, ##b); } while(0)
10493 +#else
10494 +#define PR_DEBUG(a, b...) do { } while(0)
10495 +#endif
10496 +
10497 +#define MAX_OUTSTANDING_IO 2048
10498 +#define SUBMIT_BATCH_SIZE 128
10499 +
10500 +static int max_outstanding_io = MAX_OUTSTANDING_IO;
10501 +static int submit_batch_size = SUBMIT_BATCH_SIZE;
10502 +
10503 +struct io_info {
10504 + struct bio *sys_struct;
10505 + sector_t first_block;
10506 + struct page *bio_page, *dest_page;
10507 + int writing, readahead_index;
10508 + struct block_device *dev;
10509 + struct list_head list;
10510 +};
10511 +
10512 +static LIST_HEAD(ioinfo_ready_for_cleanup);
10513 +static DEFINE_SPINLOCK(ioinfo_ready_lock);
10514 +
10515 +static LIST_HEAD(ioinfo_submit_batch);
10516 +static DEFINE_SPINLOCK(ioinfo_submit_lock);
10517 +
10518 +static LIST_HEAD(ioinfo_busy);
10519 +static DEFINE_SPINLOCK(ioinfo_busy_lock);
10520 +
10521 +static struct io_info *waiting_on;
10522 +
10523 +static atomic_t submit_batch;
10524 +static int submit_batched(void);
10525 +
10526 +/* [Max] number of I/O operations pending */
10527 +static atomic_t outstanding_io;
10528 +
10529 +static int extra_page_forward = 0;
10530 +
10531 +static volatile unsigned long suspend_readahead_flags[
10532 + DIV_ROUND_UP(MAX_OUTSTANDING_IO, BITS_PER_LONG)];
10533 +static spinlock_t suspend_readahead_flags_lock = SPIN_LOCK_UNLOCKED;
10534 +static struct page *suspend_readahead_pages[MAX_OUTSTANDING_IO];
10535 +static int readahead_index, readahead_submit_index;
10536 +
10537 +static int current_stream;
10538 +/* 0 = Header, 1 = Pageset1, 2 = Pageset2 */
10539 +struct extent_iterate_saved_state suspend_writer_posn_save[3];
10540 +
10541 +/* Pointer to current entry being loaded/saved. */
10542 +struct extent_iterate_state suspend_writer_posn;
10543 +
10544 +/* Not static, so that the allocators can setup and complete
10545 + * writing the header */
10546 +char *suspend_writer_buffer;
10547 +int suspend_writer_buffer_posn;
10548 +
10549 +int suspend_read_fd;
10550 +
10551 +static struct suspend_bdev_info *suspend_devinfo;
10552 +
10553 +int suspend_header_bytes_used = 0;
10554 +
10555 +DEFINE_MUTEX(suspend_bio_mutex);
10556 +
10557 +/*
10558 + * __suspend_bio_cleanup_one
10559 + *
10560 + * Description: Clean up after completing I/O on a page.
10561 + * Arguments: struct io_info: Data for I/O to be completed.
10562 + */
10563 +static void __suspend_bio_cleanup_one(struct io_info *io_info)
10564 +{
10565 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
10566 + "Cleanup IO: [%p]\n", io_info);
10567 +
10568 + if (!io_info->writing && io_info->readahead_index == -1) {
10569 + char *from, *to;
10570 + /*
10571 + * Copy the page we read into the buffer our caller provided.
10572 + */
10573 + to = (char *) kmap(io_info->dest_page);
10574 + from = (char *) kmap(io_info->bio_page);
10575 + memcpy(to, from, PAGE_SIZE);
10576 + kunmap(io_info->dest_page);
10577 + kunmap(io_info->bio_page);
10578 + }
10579 +
10580 + if (io_info->writing || io_info->readahead_index == -1) {
10581 + /* Sanity check */
10582 + if (page_count(io_info->bio_page) != 2)
10583 + printk(KERN_EMERG "Cleanup IO: Page count on page %p"
10584 + " is %d. Not good!\n",
10585 + io_info->bio_page,
10586 + page_count(io_info->bio_page));
10587 + put_page(io_info->bio_page);
10588 + __free_page(io_info->bio_page);
10589 + } else
10590 + put_page(io_info->bio_page);
10591 +
10592 + bio_put(io_info->sys_struct);
10593 + io_info->sys_struct = NULL;
10594 +}
10595 +
10596 +/* __suspend_io_cleanup
10597 + */
10598 +
10599 +static void suspend_bio_cleanup_one(void *data)
10600 +{
10601 + struct io_info *io_info = (struct io_info *) data;
10602 + int readahead_index;
10603 + unsigned long flags;
10604 +
10605 + readahead_index = io_info->readahead_index;
10606 + list_del_init(&io_info->list);
10607 + __suspend_bio_cleanup_one(io_info);
10608 +
10609 + if (readahead_index > -1) {
10610 + int index = readahead_index/BITS_PER_LONG;
10611 + int bit = readahead_index - (index * BITS_PER_LONG);
10612 + spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
10613 + set_bit(bit, &suspend_readahead_flags[index]);
10614 + spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
10615 + }
10616 +
10617 + if (waiting_on == io_info)
10618 + waiting_on = NULL;
10619 + kfree(io_info);
10620 + atomic_dec(&outstanding_io);
10621 +}
10622 +
10623 +/* suspend_cleanup_some_completed_io
10624 + *
10625 + * NB: This is designed so that multiple callers can be in here simultaneously.
10626 + */
10627 +
10628 +static void suspend_cleanup_some_completed_io(void)
10629 +{
10630 + int num_cleaned = 0;
10631 + struct io_info *first;
10632 + unsigned long flags;
10633 +
10634 + spin_lock_irqsave(&ioinfo_ready_lock, flags);
10635 + while(!list_empty(&ioinfo_ready_for_cleanup)) {
10636 + first = list_entry(ioinfo_ready_for_cleanup.next,
10637 + struct io_info, list);
10638 +
10639 + list_del_init(&first->list);
10640 +
10641 + spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10642 + suspend_bio_cleanup_one((void *) first);
10643 + spin_lock_irqsave(&ioinfo_ready_lock, flags);
10644 +
10645 + num_cleaned++;
10646 + if (num_cleaned == submit_batch_size)
10647 + break;
10648 + }
10649 + spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10650 +}
10651 +
10652 +/* do_bio_wait
10653 + *
10654 + * Actions taken when we want some I/O to get run.
10655 + *
10656 + * Submit any I/O that's batched up (if we're not already doing
10657 + * that, unplug queues, schedule and clean up whatever we can.
10658 + */
10659 +static void do_bio_wait(void)
10660 +{
10661 + int num_submitted = 0;
10662 +
10663 + /* Don't want to wait on I/O we haven't submitted! */
10664 + num_submitted = submit_batched();
10665 +
10666 + kblockd_flush();
10667 +
10668 + io_schedule();
10669 +
10670 + suspend_cleanup_some_completed_io();
10671 +}
10672 +
10673 +/*
10674 + * suspend_finish_all_io
10675 + *
10676 + * Description: Finishes all IO and frees all IO info struct pages.
10677 + */
10678 +static void suspend_finish_all_io(void)
10679 +{
10680 + /* Wait for all I/O to complete. */
10681 + while (atomic_read(&outstanding_io))
10682 + do_bio_wait();
10683 +}
10684 +
10685 +/*
10686 + * wait_on_readahead
10687 + *
10688 + * Wait until a particular readahead is ready.
10689 + */
10690 +static void suspend_wait_on_readahead(int readahead_index)
10691 +{
10692 + int index = readahead_index / BITS_PER_LONG;
10693 + int bit = readahead_index - index * BITS_PER_LONG;
10694 +
10695 + /* read_ahead_index is the one we want to return */
10696 + while (!test_bit(bit, &suspend_readahead_flags[index]))
10697 + do_bio_wait();
10698 +}
10699 +
10700 +/*
10701 + * readahead_done
10702 + *
10703 + * Returns whether the readahead requested is ready.
10704 + */
10705 +
10706 +static int suspend_readahead_ready(int readahead_index)
10707 +{
10708 + int index = readahead_index / BITS_PER_LONG;
10709 + int bit = readahead_index - (index * BITS_PER_LONG);
10710 +
10711 + return test_bit(bit, &suspend_readahead_flags[index]);
10712 +}
10713 +
10714 +/* suspend_readahead_prepare
10715 + * Set up for doing readahead on an image */
10716 +static int suspend_prepare_readahead(int index)
10717 +{
10718 + unsigned long new_page = get_zeroed_page(GFP_ATOMIC | __GFP_NOWARN);
10719 +
10720 + if(!new_page)
10721 + return -ENOMEM;
10722 +
10723 + suspend_readahead_pages[index] = virt_to_page(new_page);
10724 + return 0;
10725 +}
10726 +
10727 +/* suspend_readahead_cleanup
10728 + * Clean up structures used for readahead */
10729 +static void suspend_cleanup_readahead(int page)
10730 +{
10731 + __free_page(suspend_readahead_pages[page]);
10732 + suspend_readahead_pages[page] = 0;
10733 + return;
10734 +}
10735 +
10736 +/*
10737 + * suspend_end_bio
10738 + *
10739 + * Description: Function called by block driver from interrupt context when I/O
10740 + * is completed. This is the reason we use spinlocks in
10741 + * manipulating the io_info lists.
10742 + * Nearly the fs/buffer.c version, but we want to mark the page as
10743 + * done in our own structures too.
10744 + */
10745 +
10746 +static int suspend_end_bio(struct bio *bio, unsigned int num, int err)
10747 +{
10748 + struct io_info *io_info = bio->bi_private;
10749 + unsigned long flags;
10750 +
10751 + spin_lock_irqsave(&ioinfo_busy_lock, flags);
10752 + list_del_init(&io_info->list);
10753 + spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
10754 +
10755 + spin_lock_irqsave(&ioinfo_ready_lock, flags);
10756 + list_add_tail(&io_info->list, &ioinfo_ready_for_cleanup);
10757 + spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
10758 + return 0;
10759 +}
10760 +
10761 +/**
10762 + * submit - submit BIO request.
10763 + * @writing: READ or WRITE.
10764 + * @io_info: IO info structure.
10765 + *
10766 + * Based on Patrick's pmdisk code from long ago:
10767 + * "Straight from the textbook - allocate and initialize the bio.
10768 + * If we're writing, make sure the page is marked as dirty.
10769 + * Then submit it and carry on."
10770 + *
10771 + * With a twist, though - we handle block_size != PAGE_SIZE.
10772 + * Caller has already checked that our page is not fragmented.
10773 + */
10774 +
10775 +static int submit(struct io_info *io_info)
10776 +{
10777 + struct bio *bio = NULL;
10778 + unsigned long flags;
10779 +
10780 + while (!bio) {
10781 + bio = bio_alloc(GFP_ATOMIC,1);
10782 + if (!bio)
10783 + do_bio_wait();
10784 + }
10785 +
10786 + bio->bi_bdev = io_info->dev;
10787 + bio->bi_sector = io_info->first_block;
10788 + bio->bi_private = io_info;
10789 + bio->bi_end_io = suspend_end_bio;
10790 + io_info->sys_struct = bio;
10791 +
10792 + if (bio_add_page(bio, io_info->bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
10793 + printk("ERROR: adding page to bio at %lld\n",
10794 + (unsigned long long) io_info->first_block);
10795 + bio_put(bio);
10796 + return -EFAULT;
10797 + }
10798 +
10799 + if (io_info->writing)
10800 + bio_set_pages_dirty(bio);
10801 +
10802 + spin_lock_irqsave(&ioinfo_busy_lock, flags);
10803 + list_add_tail(&io_info->list, &ioinfo_busy);
10804 + spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
10805 +
10806 + submit_bio(io_info->writing, bio);
10807 +
10808 + return 0;
10809 +}
10810 +
10811 +/*
10812 + * submit a batch. The submit function can wait on I/O, so we have
10813 + * simple locking to avoid infinite recursion.
10814 + */
10815 +static int submit_batched(void)
10816 +{
10817 + static int running_already = 0;
10818 + struct io_info *first;
10819 + unsigned long flags;
10820 + int num_submitted = 0;
10821 +
10822 + if (running_already)
10823 + return 0;
10824 +
10825 + running_already = 1;
10826 + spin_lock_irqsave(&ioinfo_submit_lock, flags);
10827 + while(!list_empty(&ioinfo_submit_batch)) {
10828 + first = list_entry(ioinfo_submit_batch.next, struct io_info,
10829 + list);
10830 + list_del_init(&first->list);
10831 + atomic_dec(&submit_batch);
10832 + spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10833 + submit(first);
10834 + spin_lock_irqsave(&ioinfo_submit_lock, flags);
10835 + num_submitted++;
10836 + if (num_submitted == submit_batch_size)
10837 + break;
10838 + }
10839 + spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10840 + running_already = 0;
10841 +
10842 + return num_submitted;
10843 +}
10844 +
10845 +static void add_to_batch(struct io_info *io_info)
10846 +{
10847 + unsigned long flags;
10848 + int waiting;
10849 +
10850 + /* Put our prepared I/O struct on the batch list. */
10851 + spin_lock_irqsave(&ioinfo_submit_lock, flags);
10852 + list_add_tail(&io_info->list, &ioinfo_submit_batch);
10853 + waiting = atomic_add_return(1, &submit_batch);
10854 + spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
10855 +
10856 + if (waiting >= submit_batch_size)
10857 + submit_batched();
10858 +}
10859 +
10860 +/*
10861 + * get_io_info_struct
10862 + *
10863 + * Description: Get an I/O struct.
10864 + * Returns: Pointer to the struct prepared for use.
10865 + */
10866 +static struct io_info *get_io_info_struct(void)
10867 +{
10868 + struct io_info *this = NULL;
10869 +
10870 + do {
10871 + while (atomic_read(&outstanding_io) >= max_outstanding_io)
10872 + do_bio_wait();
10873 +
10874 + this = kmalloc(sizeof(struct io_info), GFP_ATOMIC);
10875 + } while (!this);
10876 +
10877 + INIT_LIST_HEAD(&this->list);
10878 + return this;
10879 +}
10880 +
10881 +/*
10882 + * suspend_do_io
10883 + *
10884 + * Description: Prepare and start a read or write operation.
10885 + * Note that we use our own buffer for reading or writing.
10886 + * This simplifies doing readahead and asynchronous writing.
10887 + * We can begin a read without knowing the location into which
10888 + * the data will eventually be placed, and the buffer passed
10889 + * for a write can be reused immediately (essential for the
10890 + * modules system).
10891 + * Failure? What's that?
10892 + * Returns: The io_info struct created.
10893 + */
10894 +static int suspend_do_io(int writing, struct block_device *bdev, long block0,
10895 + struct page *page, int readahead_index, int syncio)
10896 +{
10897 + struct io_info *io_info;
10898 + unsigned long buffer_virt = 0;
10899 + char *to, *from;
10900 +
10901 + io_info = get_io_info_struct();
10902 +
10903 + /* Done before submitting to avoid races. */
10904 + if (syncio)
10905 + waiting_on = io_info;
10906 +
10907 + /* Get our local buffer */
10908 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
10909 + "Start_IO: [%p]", io_info);
10910 +
10911 + /* Copy settings to the io_info struct */
10912 + io_info->writing = writing;
10913 + io_info->dev = bdev;
10914 + io_info->first_block = block0;
10915 + io_info->dest_page = page;
10916 + io_info->readahead_index = readahead_index;
10917 +
10918 + if (io_info->readahead_index == -1) {
10919 + while (!(buffer_virt = get_zeroed_page(GFP_ATOMIC | __GFP_NOWARN)))
10920 + do_bio_wait();
10921 +
10922 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
10923 + "[ALLOC BUFFER]->%d",
10924 + real_nr_free_pages(all_zones_mask));
10925 + io_info->bio_page = virt_to_page(buffer_virt);
10926 + } else {
10927 + unsigned long flags;
10928 + int index = io_info->readahead_index / BITS_PER_LONG;
10929 + int bit = io_info->readahead_index - index * BITS_PER_LONG;
10930 +
10931 + spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
10932 + clear_bit(bit, &suspend_readahead_flags[index]);
10933 + spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
10934 +
10935 + io_info->bio_page = page;
10936 + }
10937 +
10938 + /* If writing, copy our data. The data is probably in
10939 + * lowmem, but we cannot be certain. If there is no
10940 + * compression/encryption, we might be passed the
10941 + * actual source page's address. */
10942 + if (writing) {
10943 + to = (char *) buffer_virt;
10944 + from = kmap_atomic(page, KM_USER1);
10945 + memcpy(to, from, PAGE_SIZE);
10946 + kunmap_atomic(from, KM_USER1);
10947 + }
10948 +
10949 + /* Submit the page */
10950 + get_page(io_info->bio_page);
10951 +
10952 + suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
10953 + "-> (PRE BRW) %d\n", real_nr_free_pages(all_zones_mask));
10954 +
10955 + if (syncio)
10956 + submit(io_info);
10957 + else
10958 + add_to_batch(io_info);
10959 +
10960 + atomic_inc(&outstanding_io);
10961 +
10962 + if (syncio)
10963 + do { do_bio_wait(); } while (waiting_on);
10964 +
10965 + return 0;
10966 +}
10967 +
10968 +/* We used to use bread here, but it doesn't correctly handle
10969 + * blocksize != PAGE_SIZE. Now we create a submit_info to get the data we
10970 + * want and use our normal routines (synchronously).
10971 + */
10972 +
10973 +static int suspend_bdev_page_io(int writing, struct block_device *bdev,
10974 + long pos, struct page *page)
10975 +{
10976 + return suspend_do_io(writing, bdev, pos, page, -1, 1);
10977 +}
10978 +
10979 +static int suspend_bio_memory_needed(void)
10980 +{
10981 + /* We want to have at least enough memory so as to have
10982 + * max_outstanding_io transactions on the fly at once. If we
10983 + * can do more, fine. */
10984 + return (max_outstanding_io * (PAGE_SIZE + sizeof(struct request) +
10985 + sizeof(struct bio) + sizeof(struct io_info)));
10986 +}
10987 +
10988 +static void suspend_set_devinfo(struct suspend_bdev_info *info)
10989 +{
10990 + suspend_devinfo = info;
10991 +}
10992 +
10993 +static void dump_block_chains(void)
10994 +{
10995 + int i;
10996 +
10997 + for (i = 0; i < suspend_writer_posn.num_chains; i++) {
10998 + struct extent *this;
10999 +
11000 + printk("Chain %d:", i);
11001 +
11002 + this = (suspend_writer_posn.chains + i)->first;
11003 +
11004 + if (!this)
11005 + printk(" (Empty)");
11006 +
11007 + while (this) {
11008 + printk(" [%lu-%lu]%s", this->minimum, this->maximum,
11009 + this->next ? "," : "");
11010 + this = this->next;
11011 + }
11012 +
11013 + printk("\n");
11014 + }
11015 +
11016 + for (i = 0; i < 3; i++)
11017 + printk("Posn %d: Chain %d, extent %d, offset %lu.\n", i,
11018 + suspend_writer_posn_save[i].chain_num,
11019 + suspend_writer_posn_save[i].extent_num,
11020 + suspend_writer_posn_save[i].offset);
11021 +}
11022 +static int forward_extra_blocks(void)
11023 +{
11024 + int i;
11025 +
11026 + for (i = 1; i < suspend_devinfo[suspend_writer_posn.current_chain].
11027 + blocks_per_page; i++)
11028 + suspend_extent_state_next(&suspend_writer_posn);
11029 +
11030 + if (suspend_extent_state_eof(&suspend_writer_posn)) {
11031 + printk("Extent state eof.\n");
11032 + dump_block_chains();
11033 + return -ENODATA;
11034 + }
11035 +
11036 + return 0;
11037 +}
11038 +
11039 +static int forward_one_page(void)
11040 +{
11041 + int at_start = (suspend_writer_posn.current_chain == -1);
11042 +
11043 + /* Have to go forward one to ensure we're on the right chain,
11044 + * before we can know how many more blocks to skip.*/
11045 + suspend_extent_state_next(&suspend_writer_posn);
11046 +
11047 + if (!at_start && forward_extra_blocks())
11048 + return -ENODATA;
11049 +
11050 + if (extra_page_forward) {
11051 + extra_page_forward = 0;
11052 + return forward_one_page();
11053 + }
11054 +
11055 + return 0;
11056 +}
11057 +
11058 +/* Used in reading header, to jump to 2nd page after getting 1st page
11059 + * direct from image header. */
11060 +static void set_extra_page_forward(void)
11061 +{
11062 + extra_page_forward = 1;
11063 +}
11064 +
11065 +static int suspend_bio_rw_page(int writing, struct page *page,
11066 + int readahead_index, int sync)
11067 +{
11068 + struct suspend_bdev_info *dev_info;
11069 +
11070 + if (test_action_state(SUSPEND_TEST_FILTER_SPEED))
11071 + return 0;
11072 +
11073 + if (forward_one_page()) {
11074 + printk("Failed to advance a page in the extent data.\n");
11075 + return -ENODATA;
11076 + }
11077 +
11078 + if (current_stream == 0 && writing &&
11079 + suspend_writer_posn.current_chain == suspend_writer_posn_save[2].chain_num &&
11080 + suspend_writer_posn.current_offset == suspend_writer_posn_save[2].offset) {
11081 + dump_block_chains();
11082 + BUG();
11083 + }
11084 +
11085 + dev_info = &suspend_devinfo[suspend_writer_posn.current_chain];
11086 +
11087 + return suspend_do_io(writing, dev_info->bdev,
11088 + suspend_writer_posn.current_offset <<
11089 + dev_info->bmap_shift,
11090 + page, readahead_index, sync);
11091 +}
11092 +
11093 +static int suspend_rw_init(int writing, int stream_number)
11094 +{
11095 + suspend_header_bytes_used = 0;
11096 +
11097 + suspend_extent_state_restore(&suspend_writer_posn,
11098 + &suspend_writer_posn_save[stream_number]);
11099 +
11100 + suspend_writer_buffer_posn = writing ? 0 : PAGE_SIZE;
11101 +
11102 + current_stream = stream_number;
11103 +
11104 + readahead_index = readahead_submit_index = -1;
11105 +
11106 + pr_index = 0;
11107 +
11108 + return 0;
11109 +}
11110 +
11111 +static void suspend_read_header_init(void)
11112 +{
11113 + readahead_index = readahead_submit_index = -1;
11114 +}
11115 +
11116 +static int suspend_rw_cleanup(int writing)
11117 +{
11118 + if (writing && suspend_bio_rw_page(WRITE,
11119 + virt_to_page(suspend_writer_buffer), -1, 0))
11120 + return -EIO;
11121 +
11122 + if (writing && current_stream == 2)
11123 + suspend_extent_state_save(&suspend_writer_posn,
11124 + &suspend_writer_posn_save[1]);
11125 +
11126 + suspend_finish_all_io();
11127 +
11128 + if (!writing)
11129 + while (readahead_index != readahead_submit_index) {
11130 + suspend_cleanup_readahead(readahead_index);
11131 + readahead_index++;
11132 + if (readahead_index == max_outstanding_io)
11133 + readahead_index = 0;
11134 + }
11135 +
11136 + current_stream = 0;
11137 +
11138 + return 0;
11139 +}
11140 +
11141 +static int suspend_bio_read_page_with_readahead(void)
11142 +{
11143 + static int last_result;
11144 + unsigned long *virt;
11145 +
11146 + if (readahead_index == -1) {
11147 + last_result = 0;
11148 + readahead_index = readahead_submit_index = 0;
11149 + }
11150 +
11151 + /* Start a new readahead? */
11152 + if (last_result) {
11153 + /* We failed to submit a read, and have cleaned up
11154 + * all the readahead previously submitted */
11155 + if (readahead_submit_index == readahead_index) {
11156 + abort_suspend(SUSPEND_FAILED_IO, "Failed to submit"
11157 + " a read and no readahead left.\n");
11158 + return -EIO;
11159 + }
11160 + goto wait;
11161 + }
11162 +
11163 + do {
11164 + if (suspend_prepare_readahead(readahead_submit_index))
11165 + break;
11166 +
11167 + last_result = suspend_bio_rw_page(READ,
11168 + suspend_readahead_pages[readahead_submit_index],
11169 + readahead_submit_index, SUSPEND_ASYNC);
11170 + if (last_result) {
11171 + printk("Begin read chunk for page %d returned %d.\n",
11172 + readahead_submit_index, last_result);
11173 + suspend_cleanup_readahead(readahead_submit_index);
11174 + break;
11175 + }
11176 +
11177 + readahead_submit_index++;
11178 +
11179 + if (readahead_submit_index == max_outstanding_io)
11180 + readahead_submit_index = 0;
11181 +
11182 + } while((!last_result) && (readahead_submit_index != readahead_index) &&
11183 + (!suspend_readahead_ready(readahead_index)));
11184 +
11185 +wait:
11186 + suspend_wait_on_readahead(readahead_index);
11187 +
11188 + virt = kmap_atomic(suspend_readahead_pages[readahead_index], KM_USER1);
11189 + memcpy(suspend_writer_buffer, virt, PAGE_SIZE);
11190 + kunmap_atomic(virt, KM_USER1);
11191 +
11192 + suspend_cleanup_readahead(readahead_index);
11193 +
11194 + readahead_index++;
11195 + if (readahead_index == max_outstanding_io)
11196 + readahead_index = 0;
11197 +
11198 + return 0;
11199 +}
11200 +
11201 +/*
11202 + *
11203 + */
11204 +
11205 +static int suspend_rw_buffer(int writing, char *buffer, int buffer_size)
11206 +{
11207 + int bytes_left = buffer_size;
11208 +
11209 + /* Read/write a chunk of the header */
11210 + while (bytes_left) {
11211 + char *source_start = buffer + buffer_size - bytes_left;
11212 + char *dest_start = suspend_writer_buffer + suspend_writer_buffer_posn;
11213 + int capacity = PAGE_SIZE - suspend_writer_buffer_posn;
11214 + char *to = writing ? dest_start : source_start;
11215 + char *from = writing ? source_start : dest_start;
11216 +
11217 + if (bytes_left <= capacity) {
11218 + if (test_debug_state(SUSPEND_HEADER))
11219 + printk("Copy %d bytes %d-%d from %p to %p.\n",
11220 + bytes_left,
11221 + suspend_header_bytes_used,
11222 + suspend_header_bytes_used + bytes_left,
11223 + from, to);
11224 + memcpy(to, from, bytes_left);
11225 + suspend_writer_buffer_posn += bytes_left;
11226 + suspend_header_bytes_used += bytes_left;
11227 + return 0;
11228 + }
11229 +
11230 + /* Complete this page and start a new one */
11231 + if (test_debug_state(SUSPEND_HEADER))
11232 + printk("Copy %d bytes (%d-%d) from %p to %p.\n",
11233 + capacity,
11234 + suspend_header_bytes_used,
11235 + suspend_header_bytes_used + capacity,
11236 + from, to);
11237 + memcpy(to, from, capacity);
11238 + bytes_left -= capacity;
11239 + suspend_header_bytes_used += capacity;
11240 +
11241 + if (!writing) {
11242 + if (test_suspend_state(SUSPEND_TRY_RESUME_RD))
11243 + sys_read(suspend_read_fd,
11244 + suspend_writer_buffer, BLOCK_SIZE);
11245 + else
11246 + if (suspend_bio_read_page_with_readahead())
11247 + return -EIO;
11248 + } else if (suspend_bio_rw_page(WRITE,
11249 + virt_to_page(suspend_writer_buffer),
11250 + -1, SUSPEND_ASYNC))
11251 + return -EIO;
11252 +
11253 + suspend_writer_buffer_posn = 0;
11254 + suspend_cond_pause(0, NULL);
11255 + }
11256 +
11257 + return 0;
11258 +}
11259 +
11260 +/*
11261 + * suspend_bio_read_chunk
11262 + *
11263 + * Read a (possibly compressed and/or encrypted) page from the image,
11264 + * into buffer_page, returning it's index and the buffer size.
11265 + *
11266 + * If asynchronous I/O is requested, use readahead.
11267 + */
11268 +
11269 +static int suspend_bio_read_chunk(unsigned long *index, struct page *buffer_page,
11270 + unsigned int *buf_size, int sync)
11271 +{
11272 + int result;
11273 + char *buffer_virt = kmap(buffer_page);
11274 +
11275 + pr_index++;
11276 +
11277 + while (!mutex_trylock(&suspend_bio_mutex))
11278 + do_bio_wait();
11279 +
11280 + if ((result = suspend_rw_buffer(READ, (char *) index,
11281 + sizeof(unsigned long)))) {
11282 + abort_suspend(SUSPEND_FAILED_IO,
11283 + "Read of index returned %d.\n", result);
11284 + goto out;
11285 + }
11286 +
11287 + if ((result = suspend_rw_buffer(READ, (char *) buf_size, sizeof(int)))) {
11288 + abort_suspend(SUSPEND_FAILED_IO,
11289 + "Read of buffer size is %d.\n", result);
11290 + goto out;
11291 + }
11292 +
11293 + result = suspend_rw_buffer(READ, buffer_virt, *buf_size);
11294 + if (result)
11295 + abort_suspend(SUSPEND_FAILED_IO,
11296 + "Read of data returned %d.\n", result);
11297 +
11298 + PR_DEBUG("%d: Index %ld, %d bytes.\n", pr_index, *index, *buf_size);
11299 +out:
11300 + mutex_unlock(&suspend_bio_mutex);
11301 + kunmap(buffer_page);
11302 + if (result)
11303 + abort_suspend(SUSPEND_FAILED_IO,
11304 + "Returning %d from suspend_bio_read_chunk.\n", result);
11305 + return result;
11306 +}
11307 +
11308 +/*
11309 + * suspend_bio_write_chunk
11310 + *
11311 + * Write a (possibly compressed and/or encrypted) page to the image from
11312 + * the buffer, together with it's index and buffer size.
11313 + */
11314 +
11315 +static int suspend_bio_write_chunk(unsigned long index, struct page *buffer_page,
11316 + unsigned int buf_size)
11317 +{
11318 + int result;
11319 + char *buffer_virt = kmap(buffer_page);
11320 +
11321 + pr_index++;
11322 +
11323 + while (!mutex_trylock(&suspend_bio_mutex))
11324 + do_bio_wait();
11325 +
11326 + if ((result = suspend_rw_buffer(WRITE, (char *) &index,
11327 + sizeof(unsigned long))))
11328 + goto out;
11329 +
11330 + if ((result = suspend_rw_buffer(WRITE, (char *) &buf_size, sizeof(int))))
11331 + goto out;
11332 +
11333 + result = suspend_rw_buffer(WRITE, buffer_virt, buf_size);
11334 +
11335 + PR_DEBUG("%d: Index %ld, %d bytes.\n", pr_index, index, buf_size);
11336 +out:
11337 + mutex_unlock(&suspend_bio_mutex);
11338 + kunmap(buffer_page);
11339 + return result;
11340 +}
11341 +
11342 +/*
11343 + * suspend_rw_header_chunk
11344 + *
11345 + * Read or write a portion of the header.
11346 + */
11347 +
11348 +static int suspend_rw_header_chunk(int writing,
11349 + struct suspend_module_ops *owner,
11350 + char *buffer, int buffer_size)
11351 +{
11352 + if (owner) {
11353 + owner->header_used += buffer_size;
11354 + if (owner->header_used > owner->header_requested) {
11355 + printk(KERN_EMERG "Suspend2 module %s is using more"
11356 + "header space (%u) than it requested (%u).\n",
11357 + owner->name,
11358 + owner->header_used,
11359 + owner->header_requested);
11360 + return buffer_size;
11361 + }
11362 + }
11363 +
11364 + return suspend_rw_buffer(writing, buffer, buffer_size);
11365 +}
11366 +
11367 +/*
11368 + * write_header_chunk_finish
11369 + *
11370 + * Flush any buffered writes in the section of the image.
11371 + */
11372 +static int write_header_chunk_finish(void)
11373 +{
11374 + return suspend_bio_rw_page(WRITE, virt_to_page(suspend_writer_buffer),
11375 + -1, 0) ? -EIO : 0;
11376 +}
11377 +
11378 +static int suspend_bio_storage_needed(void)
11379 +{
11380 + return 2 * sizeof(int);
11381 +}
11382 +
11383 +static int suspend_bio_save_config_info(char *buf)
11384 +{
11385 + int *ints = (int *) buf;
11386 + ints[0] = max_outstanding_io;
11387 + ints[1] = submit_batch_size;
11388 + return 2 * sizeof(int);
11389 +}
11390 +
11391 +static void suspend_bio_load_config_info(char *buf, int size)
11392 +{
11393 + int *ints = (int *) buf;
11394 + max_outstanding_io = ints[0];
11395 + submit_batch_size = ints[1];
11396 +}
11397 +
11398 +static int suspend_bio_initialise(int starting_cycle)
11399 +{
11400 + suspend_writer_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
11401 +
11402 + return suspend_writer_buffer ? 0 : -ENOMEM;
11403 +}
11404 +
11405 +static void suspend_bio_cleanup(int finishing_cycle)
11406 +{
11407 + if (suspend_writer_buffer) {
11408 + free_page((unsigned long) suspend_writer_buffer);
11409 + suspend_writer_buffer = NULL;
11410 + }
11411 +}
11412 +
11413 +struct suspend_bio_ops suspend_bio_ops = {
11414 + .bdev_page_io = suspend_bdev_page_io,
11415 + .finish_all_io = suspend_finish_all_io,
11416 + .forward_one_page = forward_one_page,
11417 + .set_extra_page_forward = set_extra_page_forward,
11418 + .set_devinfo = suspend_set_devinfo,
11419 + .read_chunk = suspend_bio_read_chunk,
11420 + .write_chunk = suspend_bio_write_chunk,
11421 + .rw_init = suspend_rw_init,
11422 + .rw_cleanup = suspend_rw_cleanup,
11423 + .read_header_init = suspend_read_header_init,
11424 + .rw_header_chunk = suspend_rw_header_chunk,
11425 + .write_header_chunk_finish = write_header_chunk_finish,
11426 +};
11427 +
11428 +static struct suspend_sysfs_data sysfs_params[] = {
11429 + { SUSPEND2_ATTR("max_outstanding_io", SYSFS_RW),
11430 + SYSFS_INT(&max_outstanding_io, 16, MAX_OUTSTANDING_IO, 0),
11431 + },
11432 +
11433 + { SUSPEND2_ATTR("submit_batch_size", SYSFS_RW),
11434 + SYSFS_INT(&submit_batch_size, 16, SUBMIT_BATCH_SIZE, 0),
11435 + }
11436 +};
11437 +
11438 +static struct suspend_module_ops suspend_blockwriter_ops =
11439 +{
11440 + .name = "Block I/O",
11441 + .type = MISC_MODULE,
11442 + .directory = "block_io",
11443 + .module = THIS_MODULE,
11444 + .memory_needed = suspend_bio_memory_needed,
11445 + .storage_needed = suspend_bio_storage_needed,
11446 + .save_config_info = suspend_bio_save_config_info,
11447 + .load_config_info = suspend_bio_load_config_info,
11448 + .initialise = suspend_bio_initialise,
11449 + .cleanup = suspend_bio_cleanup,
11450 +
11451 + .sysfs_data = sysfs_params,
11452 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
11453 +};
11454 +
11455 +static __init int suspend_block_io_load(void)
11456 +{
11457 + return suspend_register_module(&suspend_blockwriter_ops);
11458 +}
11459 +
11460 +#ifdef CONFIG_SUSPEND2_FILE_EXPORTS
11461 +EXPORT_SYMBOL_GPL(suspend_read_fd);
11462 +#endif
11463 +#if defined(CONFIG_SUSPEND2_FILE_EXPORTS) || defined(CONFIG_SUSPEND2_SWAP_EXPORTS)
11464 +EXPORT_SYMBOL_GPL(suspend_writer_posn);
11465 +EXPORT_SYMBOL_GPL(suspend_writer_posn_save);
11466 +EXPORT_SYMBOL_GPL(suspend_writer_buffer);
11467 +EXPORT_SYMBOL_GPL(suspend_writer_buffer_posn);
11468 +EXPORT_SYMBOL_GPL(suspend_header_bytes_used);
11469 +EXPORT_SYMBOL_GPL(suspend_bio_ops);
11470 +#endif
11471 +#ifdef MODULE
11472 +static __exit void suspend_block_io_unload(void)
11473 +{
11474 + suspend_unregister_module(&suspend_blockwriter_ops);
11475 +}
11476 +
11477 +module_init(suspend_block_io_load);
11478 +module_exit(suspend_block_io_unload);
11479 +MODULE_LICENSE("GPL");
11480 +MODULE_AUTHOR("Nigel Cunningham");
11481 +MODULE_DESCRIPTION("Suspend2 block io functions");
11482 +#else
11483 +late_initcall(suspend_block_io_load);
11484 +#endif
11485 diff -Naur linux-2.6.21-ck2/kernel/power/suspend_compress.c linux-2.6.21-magellan-r11/kernel/power/suspend_compress.c
11486 --- linux-2.6.21-ck2/kernel/power/suspend_compress.c 1970-01-01 01:00:00.000000000 +0100
11487 +++ linux-2.6.21-magellan-r11/kernel/power/suspend_compress.c 2007-08-17 15:57:25.000000000 +0200
11488 @@ -0,0 +1,436 @@
11489 +/*
11490 + * kernel/power/compression.c
11491 + *
11492 + * Copyright (C) 2003-2007 Nigel Cunningham (nigel at suspend2 net)
11493 + *
11494 + * This file is released under the GPLv2.
11495 + *
11496 + * This file contains data compression routines for suspend,
11497 + * using cryptoapi.
11498 + */
11499 +
11500 +#include <linux/module.h>
11501 +#include <linux/suspend.h>
11502 +#include <linux/highmem.h>
11503 +#include <linux/vmalloc.h>
11504 +#include <linux/crypto.h>
11505 +
11506 +#include "suspend2_builtin.h"
11507 +#include "suspend.h"
11508 +#include "modules.h"
11509 +#include "sysfs.h"
11510 +#include "io.h"
11511 +#include "ui.h"
11512 +
11513 +static int suspend_expected_compression = 0;
11514 +
11515 +static struct suspend_module_ops suspend_compression_ops;
11516 +static struct suspend_module_ops *next_driver;
11517 +
11518 +static char suspend_compressor_name[32] = "lzf";
11519 +
11520 +static DEFINE_MUTEX(stats_lock);
11521 +
11522 +struct cpu_context {
11523 + u8 * page_buffer;
11524 + struct crypto_comp *transform;
11525 + unsigned int len;
11526 + char *buffer_start;
11527 +};
11528 +
11529 +static DEFINE_PER_CPU(struct cpu_context, contexts);
11530 +
11531 +static int suspend_compress_prepare_result;
11532 +
11533 +/*
11534 + * suspend_compress_cleanup
11535 + *
11536 + * Frees memory allocated for our labours.
11537 + */
11538 +static void suspend_compress_cleanup(int suspend_or_resume)
11539 +{
11540 + int cpu;
11541 +
11542 + if (!suspend_or_resume)
11543 + return;
11544 +
11545 + for_each_online_cpu(cpu) {
11546 + struct cpu_context *this = &per_cpu(contexts, cpu);
11547 + if (this->transform) {
11548 + crypto_free_comp(this->transform);
11549 + this->transform = NULL;
11550 + }
11551 +
11552 + if (this->page_buffer)
11553 + free_page((unsigned long) this->page_buffer);
11554 +
11555 + this->page_buffer = NULL;
11556 + }
11557 +}
11558 +
11559 +/*
11560 + * suspend_crypto_prepare
11561 + *
11562 + * Prepare to do some work by allocating buffers and transforms.
11563 + */
11564 +static int suspend_compress_crypto_prepare(void)
11565 +{
11566 + int cpu;
11567 +
11568 + if (!*suspend_compressor_name) {
11569 + printk("Suspend2: Compression enabled but no compressor name set.\n");
11570 + return 1;
11571 + }
11572 +
11573 + for_each_online_cpu(cpu) {
11574 + struct cpu_context *this = &per_cpu(contexts, cpu);
11575 + this->transform = crypto_alloc_comp(suspend_compressor_name,
11576 + 0, 0);
11577 + if (IS_ERR(this->transform)) {
11578 + printk("Suspend2: Failed to initialise the %s "
11579 + "compression transform.\n",
11580 + suspend_compressor_name);
11581 + this->transform = NULL;
11582 + return 1;
11583 + }
11584 +
11585 + this->page_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
11586 +
11587 + if (!this->page_buffer) {
11588 + printk(KERN_ERR
11589 + "Failed to allocate a page buffer for suspend2 "
11590 + "encryption driver.\n");
11591 + return -ENOMEM;
11592 + }
11593 + }
11594 +
11595 + return 0;
11596 +}
11597 +
11598 +/*
11599 + * suspend_compress_init
11600 + */
11601 +
11602 +static int suspend_compress_init(int suspend_or_resume)
11603 +{
11604 + if (!suspend_or_resume)
11605 + return 0;
11606 +
11607 + suspend_compress_bytes_in = suspend_compress_bytes_out = 0;
11608 +
11609 + next_driver = suspend_get_next_filter(&suspend_compression_ops);
11610 +
11611 + if (!next_driver) {
11612 + printk("Compression Driver: Argh! Nothing follows me in"
11613 + " the pipeline!\n");
11614 + return -ECHILD;
11615 + }
11616 +
11617 + suspend_compress_prepare_result = suspend_compress_crypto_prepare();
11618 +
11619 + return 0;
11620 +}
11621 +
11622 +/*
11623 + * suspend_compress_rw_init()
11624 + */
11625 +
11626 +int suspend_compress_rw_init(int rw, int stream_number)
11627 +{
11628 + if (suspend_compress_prepare_result) {
11629 + printk("Failed to initialise compression algorithm.\n");
11630 + if (rw == READ)
11631 + return -ENODEV;
11632 + else
11633 + suspend_compression_ops.enabled = 0;
11634 + }
11635 +
11636 + return 0;
11637 +}
11638 +
11639 +/*
11640 + * suspend_compress_write_chunk()
11641 + *
11642 + * Compress a page of data, buffering output and passing on filled
11643 + * pages to the next module in the pipeline.
11644 + *
11645 + * Buffer_page: Pointer to a buffer of size PAGE_SIZE, containing
11646 + * data to be compressed.
11647 + *
11648 + * Returns: 0 on success. Otherwise the error is that returned by later
11649 + * modules, -ECHILD if we have a broken pipeline or -EIO if
11650 + * zlib errs.
11651 + */
11652 +static int suspend_compress_write_chunk(unsigned long index,
11653 + struct page *buffer_page, unsigned int buf_size)
11654 +{
11655 + int ret, cpu = smp_processor_id();
11656 + struct cpu_context *ctx = &per_cpu(contexts, cpu);
11657 +
11658 + if (!ctx->transform)
11659 + return next_driver->write_chunk(index, buffer_page, buf_size);
11660 +
11661 + ctx->buffer_start = kmap(buffer_page);
11662 +
11663 + ctx->len = buf_size;
11664 +
11665 + ret = crypto_comp_compress(ctx->transform,
11666 + ctx->buffer_start, buf_size,
11667 + ctx->page_buffer, &ctx->len);
11668 +
11669 + kunmap(buffer_page);
11670 +
11671 + if (ret) {
11672 + printk("Compression failed.\n");
11673 + goto failure;
11674 + }
11675 +
11676 + mutex_lock(&stats_lock);
11677 + suspend_compress_bytes_in += buf_size;
11678 + suspend_compress_bytes_out += ctx->len;
11679 + mutex_unlock(&stats_lock);
11680 +
11681 + if (ctx->len < buf_size) /* some compression */
11682 + ret = next_driver->write_chunk(index,
11683 + virt_to_page(ctx->page_buffer),
11684 + ctx->len);
11685 + else
11686 + ret = next_driver->write_chunk(index, buffer_page, buf_size);
11687 +
11688 +failure:
11689 + return ret;
11690 +}
11691 +
11692 +/*
11693 + * suspend_compress_read_chunk()
11694 + * @buffer_page: struct page *. Pointer to a buffer of size PAGE_SIZE.
11695 + * @sync: int. Whether the previous module (or core) wants its data
11696 + * synchronously.
11697 + *
11698 + * Retrieve data from later modules and decompress it until the input buffer
11699 + * is filled.
11700 + * Zero if successful. Error condition from me or from downstream on failure.
11701 + */
11702 +static int suspend_compress_read_chunk(unsigned long *index,
11703 + struct page *buffer_page, unsigned int *buf_size, int sync)
11704 +{
11705 + int ret, cpu = smp_processor_id();
11706 + unsigned int len;
11707 + unsigned int outlen = PAGE_SIZE;
11708 + char *buffer_start;
11709 + struct cpu_context *ctx = &per_cpu(contexts, cpu);
11710 +
11711 + if (!ctx->transform)
11712 + return next_driver->read_chunk(index, buffer_page, buf_size,
11713 + sync);
11714 +
11715 + /*
11716 + * All our reads must be synchronous - we can't decompress
11717 + * data that hasn't been read yet.
11718 + */
11719 +
11720 + *buf_size = PAGE_SIZE;
11721 +
11722 + ret = next_driver->read_chunk(index, buffer_page, &len, SUSPEND_SYNC);
11723 +
11724 + /* Error or uncompressed data */
11725 + if (ret || len == PAGE_SIZE)
11726 + return ret;
11727 +
11728 + buffer_start = kmap(buffer_page);
11729 + memcpy(ctx->page_buffer, buffer_start, len);
11730 + ret = crypto_comp_decompress(
11731 + ctx->transform,
11732 + ctx->page_buffer,
11733 + len, buffer_start, &outlen);
11734 + if (ret)
11735 + abort_suspend(SUSPEND_FAILED_IO,
11736 + "Compress_read returned %d.\n", ret);
11737 + else if (outlen != PAGE_SIZE) {
11738 + abort_suspend(SUSPEND_FAILED_IO,
11739 + "Decompression yielded %d bytes instead of %ld.\n",
11740 + outlen, PAGE_SIZE);
11741 + ret = -EIO;
11742 + *buf_size = outlen;
11743 + }
11744 + kunmap(buffer_page);
11745 + return ret;
11746 +}
11747 +
11748 +/*
11749 + * suspend_compress_print_debug_stats
11750 + * @buffer: Pointer to a buffer into which the debug info will be printed.
11751 + * @size: Size of the buffer.
11752 + *
11753 + * Print information to be recorded for debugging purposes into a buffer.
11754 + * Returns: Number of characters written to the buffer.
11755 + */
11756 +
11757 +static int suspend_compress_print_debug_stats(char *buffer, int size)
11758 +{
11759 + int pages_in = suspend_compress_bytes_in >> PAGE_SHIFT,
11760 + pages_out = suspend_compress_bytes_out >> PAGE_SHIFT;
11761 + int len;
11762 +
11763 + /* Output the compression ratio achieved. */
11764 + if (*suspend_compressor_name)
11765 + len = snprintf_used(buffer, size, "- Compressor is '%s'.\n",
11766 + suspend_compressor_name);
11767 + else
11768 + len = snprintf_used(buffer, size, "- Compressor is not set.\n");
11769 +
11770 + if (pages_in)
11771 + len+= snprintf_used(buffer+len, size - len,
11772 + " Compressed %ld bytes into %ld (%d percent compression).\n",
11773 + suspend_compress_bytes_in,
11774 + suspend_compress_bytes_out,
11775 + (pages_in - pages_out) * 100 / pages_in);
11776 + return len;
11777 +}
11778 +
11779 +/*
11780 + * suspend_compress_compression_memory_needed
11781 + *
11782 + * Tell the caller how much memory we need to operate during suspend/resume.
11783 + * Returns: Unsigned long. Maximum number of bytes of memory required for
11784 + * operation.
11785 + */
11786 +static int suspend_compress_memory_needed(void)
11787 +{
11788 + return 2 * PAGE_SIZE;
11789 +}
11790 +
11791 +static int suspend_compress_storage_needed(void)
11792 +{
11793 + return 4 * sizeof(unsigned long) + strlen(suspend_compressor_name) + 1;
11794 +}
11795 +
11796 +/*
11797 + * suspend_compress_save_config_info
11798 + * @buffer: Pointer to a buffer of size PAGE_SIZE.
11799 + *
11800 + * Save informaton needed when reloading the image at resume time.
11801 + * Returns: Number of bytes used for saving our data.
11802 + */
11803 +static int suspend_compress_save_config_info(char *buffer)
11804 +{
11805 + int namelen = strlen(suspend_compressor_name) + 1;
11806 + int total_len;
11807 +
11808 + *((unsigned long *) buffer) = suspend_compress_bytes_in;
11809 + *((unsigned long *) (buffer + 1 * sizeof(unsigned long))) =
11810 + suspend_compress_bytes_out;
11811 + *((unsigned long *) (buffer + 2 * sizeof(unsigned long))) =
11812 + suspend_expected_compression;
11813 + *((unsigned long *) (buffer + 3 * sizeof(unsigned long))) = namelen;
11814 + strncpy(buffer + 4 * sizeof(unsigned long), suspend_compressor_name,
11815 + namelen);
11816 + total_len = 4 * sizeof(unsigned long) + namelen;
11817 + return total_len;
11818 +}
11819 +
11820 +/* suspend_compress_load_config_info
11821 + * @buffer: Pointer to the start of the data.
11822 + * @size: Number of bytes that were saved.
11823 + *
11824 + * Description: Reload information needed for decompressing the image at
11825 + * resume time.
11826 + */
11827 +static void suspend_compress_load_config_info(char *buffer, int size)
11828 +{
11829 + int namelen;
11830 +
11831 + suspend_compress_bytes_in = *((unsigned long *) buffer);
11832 + suspend_compress_bytes_out = *((unsigned long *) (buffer + 1 * sizeof(unsigned long)));
11833 + suspend_expected_compression = *((unsigned long *) (buffer + 2 *
11834 + sizeof(unsigned long)));
11835 + namelen = *((unsigned long *) (buffer + 3 * sizeof(unsigned long)));
11836 + strncpy(suspend_compressor_name, buffer + 4 * sizeof(unsigned long),
11837 + namelen);
11838 + return;
11839 +}
11840 +
11841 +/*
11842 + * suspend_expected_compression_ratio
11843 + *
11844 + * Description: Returns the expected ratio between data passed into this module
11845 + * and the amount of data output when writing.
11846 + * Returns: 100 if the module is disabled. Otherwise the value set by the
11847 + * user via our sysfs entry.
11848 + */
11849 +
11850 +static int suspend_compress_expected_ratio(void)
11851 +{
11852 + if (!suspend_compression_ops.enabled)
11853 + return 100;
11854 + else
11855 + return 100 - suspend_expected_compression;
11856 +}
11857 +
11858 +/*
11859 + * data for our sysfs entries.
11860 + */
11861 +static struct suspend_sysfs_data sysfs_params[] = {
11862 + {
11863 + SUSPEND2_ATTR("expected_compression", SYSFS_RW),
11864 + SYSFS_INT(&suspend_expected_compression, 0, 99, 0)
11865 + },
11866 +
11867 + {
11868 + SUSPEND2_ATTR("enabled", SYSFS_RW),
11869 + SYSFS_INT(&suspend_compression_ops.enabled, 0, 1, 0)
11870 + },
11871 +
11872 + {
11873 + SUSPEND2_ATTR("algorithm", SYSFS_RW),
11874 + SYSFS_STRING(suspend_compressor_name, 31, 0)
11875 + }
11876 +};
11877 +
11878 +/*
11879 + * Ops structure.
11880 + */
11881 +static struct suspend_module_ops suspend_compression_ops = {
11882 + .type = FILTER_MODULE,
11883 + .name = "Compressor",
11884 + .directory = "compression",
11885 + .module = THIS_MODULE,
11886 + .initialise = suspend_compress_init,
11887 + .cleanup = suspend_compress_cleanup,
11888 + .memory_needed = suspend_compress_memory_needed,
11889 + .print_debug_info = suspend_compress_print_debug_stats,
11890 + .save_config_info = suspend_compress_save_config_info,
11891 + .load_config_info = suspend_compress_load_config_info,
11892 + .storage_needed = suspend_compress_storage_needed,
11893 + .expected_compression = suspend_compress_expected_ratio,
11894 +
11895 + .rw_init = suspend_compress_rw_init,
11896 +
11897 + .write_chunk = suspend_compress_write_chunk,
11898 + .read_chunk = suspend_compress_read_chunk,
11899 +
11900 + .sysfs_data = sysfs_params,
11901 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
11902 +};
11903 +
11904 +/* ---- Registration ---- */
11905 +
11906 +static __init int suspend_compress_load(void)
11907 +{
11908 + return suspend_register_module(&suspend_compression_ops);
11909 +}
11910 +
11911 +#ifdef MODULE
11912 +static __exit void suspend_compress_unload(void)
11913 +{
11914 + suspend_unregister_module(&suspend_compression_ops);
11915 +}
11916 +
11917 +module_init(suspend_compress_load);
11918 +module_exit(suspend_compress_unload);
11919 +MODULE_LICENSE("GPL");
11920 +MODULE_AUTHOR("Nigel Cunningham");
11921 +MODULE_DESCRIPTION("Compression Support for Suspend2");
11922 +#else
11923 +late_initcall(suspend_compress_load);
11924 +#endif
11925 diff -Naur linux-2.6.21-ck2/kernel/power/suspend_file.c linux-2.6.21-magellan-r11/kernel/power/suspend_file.c
11926 --- linux-2.6.21-ck2/kernel/power/suspend_file.c 1970-01-01 01:00:00.000000000 +0100
11927 +++ linux-2.6.21-magellan-r11/kernel/power/suspend_file.c 2007-08-17 15:57:25.000000000 +0200
11928 @@ -0,0 +1,1131 @@
11929 +/*
11930 + * kernel/power/suspend_file.c
11931 + *
11932 + * Copyright (C) 2005-2007 Nigel Cunningham (nigel at suspend2 net)
11933 + *
11934 + * Distributed under GPLv2.
11935 + *
11936 + * This file encapsulates functions for usage of a simple file as a
11937 + * backing store. It is based upon the swapallocator, and shares the
11938 + * same basic working. Here, though, we have nothing to do with
11939 + * swapspace, and only one device to worry about.
11940 + *
11941 + * The user can just
11942 + *
11943 + * echo Suspend2 > /path/to/my_file
11944 + *
11945 + * and
11946 + *
11947 + * echo /path/to/my_file > /sys/power/suspend2/suspend_file/target
11948 + *
11949 + * then put what they find in /sys/power/suspend2/resume2
11950 + * as their resume2= parameter in lilo.conf (and rerun lilo if using it).
11951 + *
11952 + * Having done this, they're ready to suspend and resume.
11953 + *
11954 + * TODO:
11955 + * - File resizing.
11956 + */
11957 +
11958 +#include <linux/suspend.h>
11959 +#include <linux/module.h>
11960 +#include <linux/blkdev.h>
11961 +#include <linux/file.h>
11962 +#include <linux/stat.h>
11963 +#include <linux/mount.h>
11964 +#include <linux/statfs.h>
11965 +#include <linux/syscalls.h>
11966 +#include <linux/namei.h>
11967 +#include <linux/fs.h>
11968 +#include <linux/root_dev.h>
11969 +
11970 +#include "suspend.h"
11971 +#include "sysfs.h"
11972 +#include "modules.h"
11973 +#include "ui.h"
11974 +#include "extent.h"
11975 +#include "io.h"
11976 +#include "storage.h"
11977 +#include "block_io.h"
11978 +
11979 +static struct suspend_module_ops suspend_fileops;
11980 +
11981 +/* Details of our target. */
11982 +
11983 +char suspend_file_target[256];
11984 +static struct inode *target_inode;
11985 +static struct file *target_file;
11986 +static struct block_device *suspend_file_target_bdev;
11987 +static dev_t resume_file_dev_t;
11988 +static int used_devt = 0;
11989 +static int setting_suspend_file_target = 0;
11990 +static sector_t target_firstblock = 0, target_header_start = 0;
11991 +static int target_storage_available = 0;
11992 +static int target_claim = 0;
11993 +
11994 +static char HaveImage[] = "HaveImage\n";
11995 +static char NoImage[] = "Suspend2\n";
11996 +#define sig_size (sizeof(HaveImage) + 1)
11997 +
11998 +struct suspend_file_header {
11999 + char sig[sig_size];
12000 + int resumed_before;
12001 + unsigned long first_header_block;
12002 +};
12003 +
12004 +extern char *__initdata root_device_name;
12005 +
12006 +/* Header Page Information */
12007 +static int header_pages_allocated;
12008 +
12009 +/* Main Storage Pages */
12010 +static int main_pages_allocated, main_pages_requested;
12011 +
12012 +#define target_is_normal_file() (S_ISREG(target_inode->i_mode))
12013 +
12014 +static struct suspend_bdev_info devinfo;
12015 +
12016 +/* Extent chain for blocks */
12017 +static struct extent_chain block_chain;
12018 +
12019 +/* Signature operations */
12020 +enum {
12021 + GET_IMAGE_EXISTS,
12022 + INVALIDATE,
12023 + MARK_RESUME_ATTEMPTED,
12024 + UNMARK_RESUME_ATTEMPTED,
12025 +};
12026 +
12027 +static void set_devinfo(struct block_device *bdev, int target_blkbits)
12028 +{
12029 + devinfo.bdev = bdev;
12030 + if (!target_blkbits) {
12031 + devinfo.bmap_shift = devinfo.blocks_per_page = 0;
12032 + } else {
12033 + devinfo.bmap_shift = target_blkbits - 9;
12034 + devinfo.blocks_per_page = (1 << (PAGE_SHIFT - target_blkbits));
12035 + }
12036 +}
12037 +
12038 +static int adjust_for_extra_pages(int unadjusted)
12039 +{
12040 + return (unadjusted << PAGE_SHIFT) / (PAGE_SIZE + sizeof(unsigned long)
12041 + + sizeof(int));
12042 +}
12043 +
12044 +static int suspend_file_storage_available(void)
12045 +{
12046 + int result = 0;
12047 + struct block_device *bdev=suspend_file_target_bdev;
12048 +
12049 + if (!target_inode)
12050 + return 0;
12051 +
12052 + switch (target_inode->i_mode & S_IFMT) {
12053 + case S_IFSOCK:
12054 + case S_IFCHR:
12055 + case S_IFIFO: /* Socket, Char, Fifo */
12056 + return -1;
12057 + case S_IFREG: /* Regular file: current size - holes + free
12058 + space on part */
12059 + result = target_storage_available;
12060 + break;
12061 + case S_IFBLK: /* Block device */
12062 + if (!bdev->bd_disk) {
12063 + printk("bdev->bd_disk null.\n");
12064 + return 0;
12065 + }
12066 +
12067 + result = (bdev->bd_part ?
12068 + bdev->bd_part->nr_sects :
12069 + bdev->bd_disk->capacity) >> (PAGE_SHIFT - 9);
12070 + }
12071 +
12072 + return adjust_for_extra_pages(result);
12073 +}
12074 +
12075 +static int has_contiguous_blocks(int page_num)
12076 +{
12077 + int j;
12078 + sector_t last = 0;
12079 +
12080 + for (j = 0; j < devinfo.blocks_per_page; j++) {
12081 + sector_t this = bmap(target_inode,
12082 + page_num * devinfo.blocks_per_page + j);
12083 +
12084 + if (!this || (last && (last + 1) != this))
12085 + break;
12086 +
12087 + last = this;
12088 + }
12089 +
12090 + return (j == devinfo.blocks_per_page);
12091 +}
12092 +
12093 +static int size_ignoring_ignored_pages(void)
12094 +{
12095 + int mappable = 0, i;
12096 +
12097 + if (!target_is_normal_file())
12098 + return suspend_file_storage_available();
12099 +
12100 + for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT) ; i++)
12101 + if (has_contiguous_blocks(i))
12102 + mappable++;
12103 +
12104 + return mappable;
12105 +}
12106 +
12107 +static void __populate_block_list(int min, int max)
12108 +{
12109 + if (test_action_state(SUSPEND_TEST_BIO))
12110 + printk("Adding extent %d-%d.\n", min << devinfo.bmap_shift,
12111 + ((max + 1) << devinfo.bmap_shift) - 1);
12112 +
12113 + suspend_add_to_extent_chain(&block_chain, min, max);
12114 +}
12115 +
12116 +static void populate_block_list(void)
12117 +{
12118 + int i;
12119 + int extent_min = -1, extent_max = -1, got_header = 0;
12120 +
12121 + if (block_chain.first)
12122 + suspend_put_extent_chain(&block_chain);
12123 +
12124 + if (!target_is_normal_file()) {
12125 + if (target_storage_available > 0)
12126 + __populate_block_list(devinfo.blocks_per_page,
12127 + (target_storage_available + 1) *
12128 + devinfo.blocks_per_page - 1);
12129 + return;
12130 + }
12131 +
12132 + for (i = 0; i < (target_inode->i_size >> PAGE_SHIFT); i++) {
12133 + sector_t new_sector;
12134 +
12135 + if (!has_contiguous_blocks(i))
12136 + continue;
12137 +
12138 + new_sector = bmap(target_inode,
12139 + (i * devinfo.blocks_per_page));
12140 +
12141 + /*
12142 + * Ignore the first block in the file.
12143 + * It gets the header.
12144 + */
12145 + if (new_sector == target_firstblock >> devinfo.bmap_shift) {
12146 + got_header = 1;
12147 + continue;
12148 + }
12149 +
12150 + /*
12151 + * I'd love to be able to fill in holes and resize
12152 + * files, but not yet...
12153 + */
12154 +
12155 + if (new_sector == extent_max + 1)
12156 + extent_max+= devinfo.blocks_per_page;
12157 + else {
12158 + if (extent_min > -1)
12159 + __populate_block_list(extent_min,
12160 + extent_max);
12161 +
12162 + extent_min = new_sector;
12163 + extent_max = extent_min +
12164 + devinfo.blocks_per_page - 1;
12165 + }
12166 + }
12167 +
12168 + if (extent_min > -1)
12169 + __populate_block_list(extent_min, extent_max);
12170 +}
12171 +
12172 +static void suspend_file_cleanup(int finishing_cycle)
12173 +{
12174 + if (suspend_file_target_bdev) {
12175 + if (target_claim) {
12176 + bd_release(suspend_file_target_bdev);
12177 + target_claim = 0;
12178 + }
12179 +
12180 + if (used_devt) {
12181 + blkdev_put(suspend_file_target_bdev);
12182 + used_devt = 0;
12183 + }
12184 + suspend_file_target_bdev = NULL;
12185 + target_inode = NULL;
12186 + set_devinfo(NULL, 0);
12187 + target_storage_available = 0;
12188 + }
12189 +
12190 + if (target_file > 0) {
12191 + filp_close(target_file, NULL);
12192 + target_file = NULL;
12193 + }
12194 +}
12195 +
12196 +/*
12197 + * reopen_resume_devt
12198 + *
12199 + * Having opened resume2= once, we remember the major and
12200 + * minor nodes and use them to reopen the bdev for checking
12201 + * whether an image exists (possibly when starting a resume).
12202 + */
12203 +static void reopen_resume_devt(void)
12204 +{
12205 + suspend_file_target_bdev = open_by_devnum(resume_file_dev_t, FMODE_READ);
12206 + if (IS_ERR(suspend_file_target_bdev)) {
12207 + printk("Got a dev_num (%lx) but failed to open it.\n",
12208 + (unsigned long) resume_file_dev_t);
12209 + return;
12210 + }
12211 + target_inode = suspend_file_target_bdev->bd_inode;
12212 + set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12213 +}
12214 +
12215 +static void suspend_file_get_target_info(char *target, int get_size,
12216 + int resume2)
12217 +{
12218 + if (target_file)
12219 + suspend_file_cleanup(0);
12220 +
12221 + if (!target || !strlen(target))
12222 + return;
12223 +
12224 + target_file = filp_open(target, O_RDWR, 0);
12225 +
12226 + if (IS_ERR(target_file) || !target_file) {
12227 +
12228 + if (!resume2) {
12229 + printk("Open file %s returned %p.\n",
12230 + target, target_file);
12231 + target_file = NULL;
12232 + return;
12233 + }
12234 +
12235 + target_file = NULL;
12236 + resume_file_dev_t = name_to_dev_t(target);
12237 + if (!resume_file_dev_t) {
12238 + struct kstat stat;
12239 + int error = vfs_stat(target, &stat);
12240 + printk("Open file %s returned %p and name_to_devt "
12241 + "failed.\n", target, target_file);
12242 + if (error)
12243 + printk("Stating the file also failed."
12244 + " Nothing more we can do.\n");
12245 + else
12246 + resume_file_dev_t = stat.rdev;
12247 + return;
12248 + }
12249 +
12250 + suspend_file_target_bdev = open_by_devnum(resume_file_dev_t,
12251 + FMODE_READ);
12252 + if (IS_ERR(suspend_file_target_bdev)) {
12253 + printk("Got a dev_num (%lx) but failed to open it.\n",
12254 + (unsigned long) resume_file_dev_t);
12255 + return;
12256 + }
12257 + used_devt = 1;
12258 + target_inode = suspend_file_target_bdev->bd_inode;
12259 + } else
12260 + target_inode = target_file->f_mapping->host;
12261 +
12262 + if (S_ISLNK(target_inode->i_mode) || S_ISDIR(target_inode->i_mode) ||
12263 + S_ISSOCK(target_inode->i_mode) || S_ISFIFO(target_inode->i_mode)) {
12264 + printk("File support works with regular files, character "
12265 + "files and block devices.\n");
12266 + goto cleanup;
12267 + }
12268 +
12269 + if (!used_devt) {
12270 + if (S_ISBLK(target_inode->i_mode)) {
12271 + suspend_file_target_bdev = I_BDEV(target_inode);
12272 + if (!bd_claim(suspend_file_target_bdev, &suspend_fileops))
12273 + target_claim = 1;
12274 + } else
12275 + suspend_file_target_bdev = target_inode->i_sb->s_bdev;
12276 + resume_file_dev_t = suspend_file_target_bdev->bd_dev;
12277 + }
12278 +
12279 + set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12280 +
12281 + if (get_size)
12282 + target_storage_available = size_ignoring_ignored_pages();
12283 +
12284 + if (!resume2)
12285 + target_firstblock = bmap(target_inode, 0) << devinfo.bmap_shift;
12286 +
12287 + return;
12288 +cleanup:
12289 + target_inode = NULL;
12290 + if (target_file) {
12291 + filp_close(target_file, NULL);
12292 + target_file = NULL;
12293 + }
12294 + set_devinfo(NULL, 0);
12295 + target_storage_available = 0;
12296 +}
12297 +
12298 +static int parse_signature(struct suspend_file_header *header)
12299 +{
12300 + int have_image = !memcmp(HaveImage, header->sig, sizeof(HaveImage) - 1);
12301 + int no_image_header = !memcmp(NoImage, header->sig, sizeof(NoImage) - 1);
12302 +
12303 + if (no_image_header)
12304 + return 0;
12305 +
12306 + if (!have_image)
12307 + return -1;
12308 +
12309 + if (header->resumed_before)
12310 + set_suspend_state(SUSPEND_RESUMED_BEFORE);
12311 + else
12312 + clear_suspend_state(SUSPEND_RESUMED_BEFORE);
12313 +
12314 + target_header_start = header->first_header_block;
12315 + return 1;
12316 +}
12317 +
12318 +/* prepare_signature */
12319 +
12320 +static int prepare_signature(struct suspend_file_header *current_header,
12321 + unsigned long first_header_block)
12322 +{
12323 + strncpy(current_header->sig, HaveImage, sizeof(HaveImage));
12324 + current_header->resumed_before = 0;
12325 + current_header->first_header_block = first_header_block;
12326 + return 0;
12327 +}
12328 +
12329 +static int suspend_file_storage_allocated(void)
12330 +{
12331 + if (!target_inode)
12332 + return 0;
12333 +
12334 + if (target_is_normal_file())
12335 + return (int) target_storage_available;
12336 + else
12337 + return header_pages_allocated + main_pages_requested;
12338 +}
12339 +
12340 +static int suspend_file_release_storage(void)
12341 +{
12342 + if (test_action_state(SUSPEND_KEEP_IMAGE) &&
12343 + test_suspend_state(SUSPEND_NOW_RESUMING))
12344 + return 0;
12345 +
12346 + suspend_put_extent_chain(&block_chain);
12347 +
12348 + header_pages_allocated = 0;
12349 + main_pages_allocated = 0;
12350 + main_pages_requested = 0;
12351 + return 0;
12352 +}
12353 +
12354 +static int __suspend_file_allocate_storage(int main_storage_requested,
12355 + int header_storage);
12356 +
12357 +static int suspend_file_allocate_header_space(int space_requested)
12358 +{
12359 + int i;
12360 +
12361 + if (!block_chain.first && __suspend_file_allocate_storage(
12362 + main_pages_requested, space_requested)) {
12363 + printk("Failed to allocate space for the header.\n");
12364 + return -ENOSPC;
12365 + }
12366 +
12367 + suspend_extent_state_goto_start(&suspend_writer_posn);
12368 + suspend_bio_ops.forward_one_page(); /* To first page */
12369 +
12370 + for (i = 0; i < space_requested; i++) {
12371 + if (suspend_bio_ops.forward_one_page()) {
12372 + printk("Out of space while seeking to allocate "
12373 + "header pages,\n");
12374 + header_pages_allocated = i;
12375 + return -ENOSPC;
12376 + }
12377 + }
12378 +
12379 + header_pages_allocated = space_requested;
12380 +
12381 + /* The end of header pages will be the start of pageset 2 */
12382 + suspend_extent_state_save(&suspend_writer_posn,
12383 + &suspend_writer_posn_save[2]);
12384 + return 0;
12385 +}
12386 +
12387 +static int suspend_file_allocate_storage(int space_requested)
12388 +{
12389 + if (__suspend_file_allocate_storage(space_requested,
12390 + header_pages_allocated))
12391 + return -ENOSPC;
12392 +
12393 + main_pages_requested = space_requested;
12394 + return -ENOSPC;
12395 +}
12396 +
12397 +static int __suspend_file_allocate_storage(int main_space_requested,
12398 + int header_space_requested)
12399 +{
12400 + int result = 0;
12401 +
12402 + int extra_pages = DIV_ROUND_UP(main_space_requested *
12403 + (sizeof(unsigned long) + sizeof(int)), PAGE_SIZE);
12404 + int pages_to_get = main_space_requested + extra_pages +
12405 + header_space_requested;
12406 + int blocks_to_get = pages_to_get - block_chain.size;
12407 +
12408 + /* Only release_storage reduces the size */
12409 + if (blocks_to_get < 1)
12410 + return 0;
12411 +
12412 + populate_block_list();
12413 +
12414 + suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
12415 + "Finished with block_chain.size == %d.\n",
12416 + block_chain.size);
12417 +
12418 + if (block_chain.size < pages_to_get) {
12419 + printk("Block chain size (%d) < header pages (%d) + extra pages (%d) + main pages (%d) (=%d pages).\n",
12420 + block_chain.size, header_pages_allocated, extra_pages,
12421 + main_space_requested, pages_to_get);
12422 + result = -ENOSPC;
12423 + }
12424 +
12425 + main_pages_requested = main_space_requested;
12426 + main_pages_allocated = main_space_requested + extra_pages;
12427 +
12428 + suspend_file_allocate_header_space(header_pages_allocated);
12429 + return result;
12430 +}
12431 +
12432 +static int suspend_file_write_header_init(void)
12433 +{
12434 + suspend_extent_state_goto_start(&suspend_writer_posn);
12435 +
12436 + suspend_writer_buffer_posn = suspend_header_bytes_used = 0;
12437 +
12438 + /* Info needed to bootstrap goes at the start of the header.
12439 + * First we save the basic info needed for reading, including the number
12440 + * of header pages. Then we save the structs containing data needed
12441 + * for reading the header pages back.
12442 + * Note that even if header pages take more than one page, when we
12443 + * read back the info, we will have restored the location of the
12444 + * next header page by the time we go to use it.
12445 + */
12446 +
12447 + suspend_bio_ops.rw_header_chunk(WRITE, &suspend_fileops,
12448 + (char *) &suspend_writer_posn_save,
12449 + sizeof(suspend_writer_posn_save));
12450 +
12451 + suspend_bio_ops.rw_header_chunk(WRITE, &suspend_fileops,
12452 + (char *) &devinfo, sizeof(devinfo));
12453 +
12454 + suspend_serialise_extent_chain(&suspend_fileops, &block_chain);
12455 +
12456 + return 0;
12457 +}
12458 +
12459 +static int suspend_file_write_header_cleanup(void)
12460 +{
12461 + struct suspend_file_header *header;
12462 +
12463 + /* Write any unsaved data */
12464 + if (suspend_writer_buffer_posn)
12465 + suspend_bio_ops.write_header_chunk_finish();
12466 +
12467 + suspend_bio_ops.finish_all_io();
12468 +
12469 + suspend_extent_state_goto_start(&suspend_writer_posn);
12470 + suspend_bio_ops.forward_one_page();
12471 +
12472 + /* Adjust image header */
12473 + suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12474 + target_firstblock,
12475 + virt_to_page(suspend_writer_buffer));
12476 +
12477 + header = (struct suspend_file_header *) suspend_writer_buffer;
12478 +
12479 + prepare_signature(header,
12480 + suspend_writer_posn.current_offset <<
12481 + devinfo.bmap_shift);
12482 +
12483 + suspend_bio_ops.bdev_page_io(WRITE, suspend_file_target_bdev,
12484 + target_firstblock,
12485 + virt_to_page(suspend_writer_buffer));
12486 +
12487 + suspend_bio_ops.finish_all_io();
12488 +
12489 + return 0;
12490 +}
12491 +
12492 +/* HEADER READING */
12493 +
12494 +#ifdef CONFIG_DEVFS_FS
12495 +int create_dev(char *name, dev_t dev, char *devfs_name);
12496 +#else
12497 +static int create_dev(char *name, dev_t dev, char *devfs_name)
12498 +{
12499 + sys_unlink(name);
12500 + return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
12501 +}
12502 +#endif
12503 +
12504 +static int rd_init(void)
12505 +{
12506 + suspend_writer_buffer_posn = 0;
12507 +
12508 + create_dev("/dev/root", ROOT_DEV, root_device_name);
12509 + create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
12510 +
12511 + suspend_read_fd = sys_open("/dev/root", O_RDONLY, 0);
12512 + if (suspend_read_fd < 0)
12513 + goto out;
12514 +
12515 + sys_read(suspend_read_fd, suspend_writer_buffer, BLOCK_SIZE);
12516 +
12517 + memcpy(&suspend_writer_posn_save,
12518 + suspend_writer_buffer + suspend_writer_buffer_posn,
12519 + sizeof(suspend_writer_posn_save));
12520 +
12521 + suspend_writer_buffer_posn += sizeof(suspend_writer_posn_save);
12522 +
12523 + return 0;
12524 +out:
12525 + sys_unlink("/dev/ram");
12526 + sys_unlink("/dev/root");
12527 + return -EIO;
12528 +}
12529 +
12530 +static int file_init(void)
12531 +{
12532 + suspend_writer_buffer_posn = 0;
12533 +
12534 + /* Read suspend_file configuration */
12535 + suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12536 + target_header_start,
12537 + virt_to_page((unsigned long) suspend_writer_buffer));
12538 +
12539 + return 0;
12540 +}
12541 +
12542 +/*
12543 + * read_header_init()
12544 + *
12545 + * Ramdisk support based heavily on init/do_mounts_rd.c
12546 + *
12547 + * Description:
12548 + * 1. Attempt to read the device specified with resume2=.
12549 + * 2. Check the contents of the header for our signature.
12550 + * 3. Warn, ignore, reset and/or continue as appropriate.
12551 + * 4. If continuing, read the suspend_file configuration section
12552 + * of the header and set up block device info so we can read
12553 + * the rest of the header & image.
12554 + *
12555 + * Returns:
12556 + * May not return if user choose to reboot at a warning.
12557 + * -EINVAL if cannot resume at this time. Booting should continue
12558 + * normally.
12559 + */
12560 +
12561 +static int suspend_file_read_header_init(void)
12562 +{
12563 + int result;
12564 + struct block_device *tmp;
12565 +
12566 + if (test_suspend_state(SUSPEND_TRY_RESUME_RD))
12567 + result = rd_init();
12568 + else
12569 + result = file_init();
12570 +
12571 + if (result) {
12572 + printk("FileAllocator read header init: Failed to initialise "
12573 + "reading the first page of data.\n");
12574 + return result;
12575 + }
12576 +
12577 + memcpy(&suspend_writer_posn_save,
12578 + suspend_writer_buffer + suspend_writer_buffer_posn,
12579 + sizeof(suspend_writer_posn_save));
12580 +
12581 + suspend_writer_buffer_posn += sizeof(suspend_writer_posn_save);
12582 +
12583 + tmp = devinfo.bdev;
12584 +
12585 + memcpy(&devinfo,
12586 + suspend_writer_buffer + suspend_writer_buffer_posn,
12587 + sizeof(devinfo));
12588 +
12589 + devinfo.bdev = tmp;
12590 + suspend_writer_buffer_posn += sizeof(devinfo);
12591 +
12592 + suspend_bio_ops.read_header_init();
12593 + suspend_extent_state_goto_start(&suspend_writer_posn);
12594 + suspend_bio_ops.set_extra_page_forward();
12595 +
12596 + suspend_header_bytes_used = suspend_writer_buffer_posn;
12597 +
12598 + return suspend_load_extent_chain(&block_chain);
12599 +}
12600 +
12601 +static int suspend_file_read_header_cleanup(void)
12602 +{
12603 + suspend_bio_ops.rw_cleanup(READ);
12604 + return 0;
12605 +}
12606 +
12607 +static int suspend_file_signature_op(int op)
12608 +{
12609 + char *cur;
12610 + int result = 0, changed = 0;
12611 + struct suspend_file_header *header;
12612 +
12613 + if(suspend_file_target_bdev <= 0)
12614 + return -1;
12615 +
12616 + cur = (char *) get_zeroed_page(GFP_ATOMIC);
12617 + if (!cur) {
12618 + printk("Unable to allocate a page for reading the image "
12619 + "signature.\n");
12620 + return -ENOMEM;
12621 + }
12622 +
12623 + suspend_bio_ops.bdev_page_io(READ, suspend_file_target_bdev,
12624 + target_firstblock,
12625 + virt_to_page(cur));
12626 +
12627 + header = (struct suspend_file_header *) cur;
12628 + result = parse_signature(header);
12629 +
12630 + switch (op) {
12631 + case INVALIDATE:
12632 + if (result == -1)
12633 + goto out;
12634 +
12635 + strcpy(header->sig, NoImage);
12636 + header->resumed_before = 0;
12637 + result = changed = 1;
12638 + break;
12639 + case MARK_RESUME_ATTEMPTED:
12640 + if (result == 1) {
12641 + header->resumed_before = 1;
12642 + changed = 1;
12643 + }
12644 + break;
12645 + case UNMARK_RESUME_ATTEMPTED:
12646 + if (result == 1) {
12647 + header->resumed_before = 0;
12648 + changed = 1;
12649 + }
12650 + break;
12651 + }
12652 +
12653 + if (changed)
12654 + suspend_bio_ops.bdev_page_io(WRITE, suspend_file_target_bdev,
12655 + target_firstblock,
12656 + virt_to_page(cur));
12657 +
12658 +out:
12659 + suspend_bio_ops.finish_all_io();
12660 + free_page((unsigned long) cur);
12661 + return result;
12662 +}
12663 +
12664 +/* Print debug info
12665 + *
12666 + * Description:
12667 + */
12668 +
12669 +static int suspend_file_print_debug_stats(char *buffer, int size)
12670 +{
12671 + int len = 0;
12672 +
12673 + if (suspendActiveAllocator != &suspend_fileops) {
12674 + len = snprintf_used(buffer, size, "- FileAllocator inactive.\n");
12675 + return len;
12676 + }
12677 +
12678 + len = snprintf_used(buffer, size, "- FileAllocator active.\n");
12679 +
12680 + len+= snprintf_used(buffer+len, size-len, " Storage available for image: "
12681 + "%ld pages.\n",
12682 + suspend_file_storage_allocated());
12683 +
12684 + return len;
12685 +}
12686 +
12687 +/*
12688 + * Storage needed
12689 + *
12690 + * Returns amount of space in the image header required
12691 + * for the suspend_file's data.
12692 + *
12693 + * We ensure the space is allocated, but actually save the
12694 + * data from write_header_init and therefore don't also define a
12695 + * save_config_info routine.
12696 + */
12697 +static int suspend_file_storage_needed(void)
12698 +{
12699 + return sig_size + strlen(suspend_file_target) + 1 +
12700 + 3 * sizeof(struct extent_iterate_saved_state) +
12701 + sizeof(devinfo) +
12702 + sizeof(struct extent_chain) - 2 * sizeof(void *) +
12703 + (2 * sizeof(unsigned long) * block_chain.num_extents);
12704 +}
12705 +
12706 +/*
12707 + * suspend_file_invalidate_image
12708 + *
12709 + */
12710 +static int suspend_file_invalidate_image(void)
12711 +{
12712 + int result;
12713 +
12714 + suspend_file_release_storage();
12715 +
12716 + result = suspend_file_signature_op(INVALIDATE);
12717 + if (result == 1 && !nr_suspends)
12718 + printk(KERN_WARNING "Suspend2: Image invalidated.\n");
12719 +
12720 + return result;
12721 +}
12722 +
12723 +/*
12724 + * Image_exists
12725 + *
12726 + */
12727 +
12728 +static int suspend_file_image_exists(void)
12729 +{
12730 + if (!suspend_file_target_bdev)
12731 + reopen_resume_devt();
12732 +
12733 + return suspend_file_signature_op(GET_IMAGE_EXISTS);
12734 +}
12735 +
12736 +/*
12737 + * Mark resume attempted.
12738 + *
12739 + * Record that we tried to resume from this image.
12740 + */
12741 +
12742 +static void suspend_file_mark_resume_attempted(int mark)
12743 +{
12744 + suspend_file_signature_op(mark ? MARK_RESUME_ATTEMPTED:
12745 + UNMARK_RESUME_ATTEMPTED);
12746 +}
12747 +
12748 +static void suspend_file_set_resume2(void)
12749 +{
12750 + char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
12751 + char *buffer2 = (char *) get_zeroed_page(GFP_ATOMIC);
12752 + unsigned long sector = bmap(target_inode, 0);
12753 + int offset = 0;
12754 +
12755 + if (suspend_file_target_bdev) {
12756 + set_devinfo(suspend_file_target_bdev, target_inode->i_blkbits);
12757 +
12758 + bdevname(suspend_file_target_bdev, buffer2);
12759 + offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12760 + "/dev/%s", buffer2);
12761 +
12762 + if (sector)
12763 + offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12764 + ":0x%lx", sector << devinfo.bmap_shift);
12765 + } else
12766 + offset += snprintf(buffer + offset, PAGE_SIZE - offset,
12767 + "%s is not a valid target.", suspend_file_target);
12768 +
12769 + sprintf(resume2_file, "file:%s", buffer);
12770 +
12771 + free_page((unsigned long) buffer);
12772 + free_page((unsigned long) buffer2);
12773 +
12774 + suspend_attempt_to_parse_resume_device(1);
12775 +}
12776 +
12777 +static int __test_suspend_file_target(char *target, int resume_time, int quiet)
12778 +{
12779 + suspend_file_get_target_info(target, 0, resume_time);
12780 + if (suspend_file_signature_op(GET_IMAGE_EXISTS) > -1) {
12781 + if (!quiet)
12782 + printk("Suspend2: FileAllocator: File signature found.\n");
12783 + if (!resume_time)
12784 + suspend_file_set_resume2();
12785 +
12786 + suspend_bio_ops.set_devinfo(&devinfo);
12787 + suspend_writer_posn.chains = &block_chain;
12788 + suspend_writer_posn.num_chains = 1;
12789 +
12790 + if (!resume_time)
12791 + set_suspend_state(SUSPEND_CAN_SUSPEND);
12792 + return 0;
12793 + }
12794 +
12795 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
12796 +
12797 + if (quiet)
12798 + return 1;
12799 +
12800 + if (*target)
12801 + printk("Suspend2: FileAllocator: Sorry. No signature found at"
12802 + " %s.\n", target);
12803 + else
12804 + if (!resume_time)
12805 + printk("Suspend2: FileAllocator: Sorry. Target is not"
12806 + " set for suspending.\n");
12807 +
12808 + return 1;
12809 +}
12810 +
12811 +static void test_suspend_file_target(void)
12812 +{
12813 + setting_suspend_file_target = 1;
12814 +
12815 + printk("Suspend2: Suspending %sabled.\n",
12816 + __test_suspend_file_target(suspend_file_target, 0, 1) ?
12817 + "dis" : "en");
12818 +
12819 + setting_suspend_file_target = 0;
12820 +}
12821 +
12822 +/*
12823 + * Parse Image Location
12824 + *
12825 + * Attempt to parse a resume2= parameter.
12826 + * Swap Writer accepts:
12827 + * resume2=file:DEVNAME[:FIRSTBLOCK]
12828 + *
12829 + * Where:
12830 + * DEVNAME is convertable to a dev_t by name_to_dev_t
12831 + * FIRSTBLOCK is the location of the first block in the file.
12832 + * BLOCKSIZE is the logical blocksize >= SECTOR_SIZE & <= PAGE_SIZE,
12833 + * mod SECTOR_SIZE == 0 of the device.
12834 + * Data is validated by attempting to read a header from the
12835 + * location given. Failure will result in suspend_file refusing to
12836 + * save an image, and a reboot with correct parameters will be
12837 + * necessary.
12838 + */
12839 +
12840 +static int suspend_file_parse_sig_location(char *commandline,
12841 + int only_writer, int quiet)
12842 +{
12843 + char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
12844 + int result = -EINVAL, target_blocksize = 0;
12845 +
12846 + if (strncmp(commandline, "file:", 5)) {
12847 + if (!only_writer)
12848 + return 1;
12849 + } else
12850 + commandline += 5;
12851 +
12852 + /*
12853 + * Don't check signature again if we're beginning a cycle. If we already
12854 + * did the initialisation successfully, assume we'll be okay when it comes
12855 + * to resuming.
12856 + */
12857 + if (suspend_file_target_bdev)
12858 + return 0;
12859 +
12860 + devstart = thischar = commandline;
12861 + while ((*thischar != ':') && (*thischar != '@') &&
12862 + ((thischar - commandline) < 250) && (*thischar))
12863 + thischar++;
12864 +
12865 + if (*thischar == ':') {
12866 + colon = thischar;
12867 + *colon = 0;
12868 + thischar++;
12869 + }
12870 +
12871 + while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
12872 + thischar++;
12873 +
12874 + if (*thischar == '@') {
12875 + at_symbol = thischar;
12876 + *at_symbol = 0;
12877 + }
12878 +
12879 + /*
12880 + * For the suspend_file, you can be able to resume, but not suspend,
12881 + * because the resume2= is set correctly, but the suspend_file_target
12882 + * isn't.
12883 + *
12884 + * We may have come here as a result of setting resume2 or
12885 + * suspend_file_target. We only test the suspend_file target in the
12886 + * former case (it's already done in the later), and we do it before
12887 + * setting the block number ourselves. It will overwrite the values
12888 + * given on the command line if we don't.
12889 + */
12890 +
12891 + if (!setting_suspend_file_target)
12892 + __test_suspend_file_target(suspend_file_target, 1, 0);
12893 +
12894 + if (colon)
12895 + target_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
12896 + else
12897 + target_firstblock = 0;
12898 +
12899 + if (at_symbol) {
12900 + target_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
12901 + if (target_blocksize & (SECTOR_SIZE - 1)) {
12902 + printk("FileAllocator: Blocksizes are multiples of %d.\n", SECTOR_SIZE);
12903 + result = -EINVAL;
12904 + goto out;
12905 + }
12906 + }
12907 +
12908 + if (!quiet)
12909 + printk("Suspend2 FileAllocator: Testing whether you can resume:\n");
12910 +
12911 + suspend_file_get_target_info(commandline, 0, 1);
12912 +
12913 + if (!suspend_file_target_bdev || IS_ERR(suspend_file_target_bdev)) {
12914 + suspend_file_target_bdev = NULL;
12915 + result = -1;
12916 + goto out;
12917 + }
12918 +
12919 + if (target_blocksize)
12920 + set_devinfo(suspend_file_target_bdev, ffs(target_blocksize));
12921 +
12922 + result = __test_suspend_file_target(commandline, 1, 0);
12923 +
12924 +out:
12925 + if (result)
12926 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
12927 +
12928 + if (!quiet)
12929 + printk("Resuming %sabled.\n", result ? "dis" : "en");
12930 +
12931 + if (colon)
12932 + *colon = ':';
12933 + if (at_symbol)
12934 + *at_symbol = '@';
12935 +
12936 + return result;
12937 +}
12938 +
12939 +/* suspend_file_save_config_info
12940 + *
12941 + * Description: Save the target's name, not for resume time, but for all_settings.
12942 + * Arguments: Buffer: Pointer to a buffer of size PAGE_SIZE.
12943 + * Returns: Number of bytes used for saving our data.
12944 + */
12945 +
12946 +static int suspend_file_save_config_info(char *buffer)
12947 +{
12948 + strcpy(buffer, suspend_file_target);
12949 + return strlen(suspend_file_target) + 1;
12950 +}
12951 +
12952 +/* suspend_file_load_config_info
12953 + *
12954 + * Description: Reload target's name.
12955 + * Arguments: Buffer: Pointer to the start of the data.
12956 + * Size: Number of bytes that were saved.
12957 + */
12958 +
12959 +static void suspend_file_load_config_info(char *buffer, int size)
12960 +{
12961 + strcpy(suspend_file_target, buffer);
12962 +}
12963 +
12964 +static int suspend_file_initialise(int starting_cycle)
12965 +{
12966 + if (starting_cycle) {
12967 + if (suspendActiveAllocator != &suspend_fileops)
12968 + return 0;
12969 +
12970 + if (starting_cycle & SYSFS_SUSPEND && !*suspend_file_target) {
12971 + printk("FileAllocator is the active writer, "
12972 + "but no filename has been set.\n");
12973 + return 1;
12974 + }
12975 + }
12976 +
12977 + if (suspend_file_target)
12978 + suspend_file_get_target_info(suspend_file_target, starting_cycle, 0);
12979 +
12980 + if (starting_cycle && (suspend_file_image_exists() == -1)) {
12981 + printk("%s is does not have a valid signature for suspending.\n",
12982 + suspend_file_target);
12983 + return 1;
12984 + }
12985 +
12986 + return 0;
12987 +}
12988 +
12989 +static struct suspend_sysfs_data sysfs_params[] = {
12990 +
12991 + {
12992 + SUSPEND2_ATTR("target", SYSFS_RW),
12993 + SYSFS_STRING(suspend_file_target, 256, SYSFS_NEEDS_SM_FOR_WRITE),
12994 + .write_side_effect = test_suspend_file_target,
12995 + },
12996 +
12997 + {
12998 + SUSPEND2_ATTR("enabled", SYSFS_RW),
12999 + SYSFS_INT(&suspend_fileops.enabled, 0, 1, 0),
13000 + .write_side_effect = attempt_to_parse_resume_device2,
13001 + }
13002 +};
13003 +
13004 +static struct suspend_module_ops suspend_fileops = {
13005 + .type = WRITER_MODULE,
13006 + .name = "File Allocator",
13007 + .directory = "file",
13008 + .module = THIS_MODULE,
13009 + .print_debug_info = suspend_file_print_debug_stats,
13010 + .save_config_info = suspend_file_save_config_info,
13011 + .load_config_info = suspend_file_load_config_info,
13012 + .storage_needed = suspend_file_storage_needed,
13013 + .initialise = suspend_file_initialise,
13014 + .cleanup = suspend_file_cleanup,
13015 +
13016 + .storage_available = suspend_file_storage_available,
13017 + .storage_allocated = suspend_file_storage_allocated,
13018 + .release_storage = suspend_file_release_storage,
13019 + .allocate_header_space = suspend_file_allocate_header_space,
13020 + .allocate_storage = suspend_file_allocate_storage,
13021 + .image_exists = suspend_file_image_exists,
13022 + .mark_resume_attempted = suspend_file_mark_resume_attempted,
13023 + .write_header_init = suspend_file_write_header_init,
13024 + .write_header_cleanup = suspend_file_write_header_cleanup,
13025 + .read_header_init = suspend_file_read_header_init,
13026 + .read_header_cleanup = suspend_file_read_header_cleanup,
13027 + .invalidate_image = suspend_file_invalidate_image,
13028 + .parse_sig_location = suspend_file_parse_sig_location,
13029 +
13030 + .sysfs_data = sysfs_params,
13031 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
13032 +};
13033 +
13034 +/* ---- Registration ---- */
13035 +static __init int suspend_file_load(void)
13036 +{
13037 + suspend_fileops.rw_init = suspend_bio_ops.rw_init;
13038 + suspend_fileops.rw_cleanup = suspend_bio_ops.rw_cleanup;
13039 + suspend_fileops.read_chunk = suspend_bio_ops.read_chunk;
13040 + suspend_fileops.write_chunk = suspend_bio_ops.write_chunk;
13041 + suspend_fileops.rw_header_chunk = suspend_bio_ops.rw_header_chunk;
13042 +
13043 + return suspend_register_module(&suspend_fileops);
13044 +}
13045 +
13046 +#ifdef MODULE
13047 +static __exit void suspend_file_unload(void)
13048 +{
13049 + suspend_unregister_module(&suspend_fileops);
13050 +}
13051 +
13052 +module_init(suspend_file_load);
13053 +module_exit(suspend_file_unload);
13054 +MODULE_LICENSE("GPL");
13055 +MODULE_AUTHOR("Nigel Cunningham");
13056 +MODULE_DESCRIPTION("Suspend2 FileAllocator");
13057 +#else
13058 +late_initcall(suspend_file_load);
13059 +#endif
13060 diff -Naur linux-2.6.21-ck2/kernel/power/suspend_swap.c linux-2.6.21-magellan-r11/kernel/power/suspend_swap.c
13061 --- linux-2.6.21-ck2/kernel/power/suspend_swap.c 1970-01-01 01:00:00.000000000 +0100
13062 +++ linux-2.6.21-magellan-r11/kernel/power/suspend_swap.c 2007-08-17 15:57:25.000000000 +0200
13063 @@ -0,0 +1,1262 @@
13064 +/*
13065 + * kernel/power/suspend_swap.c
13066 + *
13067 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
13068 + *
13069 + * Distributed under GPLv2.
13070 + *
13071 + * This file encapsulates functions for usage of swap space as a
13072 + * backing store.
13073 + */
13074 +
13075 +#include <linux/suspend.h>
13076 +#include <linux/module.h>
13077 +#include <linux/blkdev.h>
13078 +#include <linux/swapops.h>
13079 +#include <linux/swap.h>
13080 +#include <linux/syscalls.h>
13081 +
13082 +#include "suspend.h"
13083 +#include "sysfs.h"
13084 +#include "modules.h"
13085 +#include "io.h"
13086 +#include "ui.h"
13087 +#include "extent.h"
13088 +#include "block_io.h"
13089 +
13090 +static struct suspend_module_ops suspend_swapops;
13091 +
13092 +#define SIGNATURE_VER 6
13093 +
13094 +/* --- Struct of pages stored on disk */
13095 +
13096 +union diskpage {
13097 + union swap_header swh; /* swh.magic is the only member used */
13098 +};
13099 +
13100 +union p_diskpage {
13101 + union diskpage *pointer;
13102 + char *ptr;
13103 + unsigned long address;
13104 +};
13105 +
13106 +/* Devices used for swap */
13107 +static struct suspend_bdev_info devinfo[MAX_SWAPFILES];
13108 +
13109 +/* Extent chains for swap & blocks */
13110 +struct extent_chain swapextents;
13111 +struct extent_chain block_chain[MAX_SWAPFILES];
13112 +
13113 +static dev_t header_dev_t;
13114 +static struct block_device *header_block_device;
13115 +static unsigned long headerblock;
13116 +
13117 +/* For swapfile automatically swapon/off'd. */
13118 +static char swapfilename[32] = "";
13119 +static int suspend_swapon_status;
13120 +
13121 +/* Header Page Information */
13122 +static int header_pages_allocated;
13123 +
13124 +/* Swap Pages */
13125 +static int main_pages_allocated, main_pages_requested;
13126 +
13127 +/* User Specified Parameters. */
13128 +
13129 +static unsigned long resume_firstblock;
13130 +static int resume_blocksize;
13131 +static dev_t resume_swap_dev_t;
13132 +static struct block_device *resume_block_device;
13133 +
13134 +struct sysinfo swapinfo;
13135 +static int suspend_swap_invalidate_image(void);
13136 +
13137 +/* Block devices open. */
13138 +struct bdev_opened
13139 +{
13140 + dev_t device;
13141 + struct block_device *bdev;
13142 + int claimed;
13143 +};
13144 +
13145 +/*
13146 + * Entry MAX_SWAPFILES is the resume block device, which may
13147 + * not be a swap device enabled when we suspend.
13148 + * Entry MAX_SWAPFILES + 1 is the header block device, which
13149 + * is needed before we find out which slot it occupies.
13150 + */
13151 +static struct bdev_opened *bdev_info_list[MAX_SWAPFILES + 2];
13152 +
13153 +static void close_bdev(int i)
13154 +{
13155 + struct bdev_opened *this = bdev_info_list[i];
13156 +
13157 + if (this->claimed)
13158 + bd_release(this->bdev);
13159 +
13160 + /* Release our reference. */
13161 + blkdev_put(this->bdev);
13162 +
13163 + /* Free our info. */
13164 + kfree(this);
13165 +
13166 + bdev_info_list[i] = NULL;
13167 +}
13168 +
13169 +static void close_bdevs(void)
13170 +{
13171 + int i;
13172 +
13173 + for (i = 0; i < MAX_SWAPFILES; i++)
13174 + if (bdev_info_list[i])
13175 + close_bdev(i);
13176 +
13177 + resume_block_device = header_block_device = NULL;
13178 +}
13179 +
13180 +static struct block_device *open_bdev(int index, dev_t device, int display_errs)
13181 +{
13182 + struct bdev_opened *this;
13183 + struct block_device *bdev;
13184 +
13185 + if (bdev_info_list[index] && (bdev_info_list[index]->device == device)){
13186 + bdev = bdev_info_list[index]->bdev;
13187 + return bdev;
13188 + }
13189 +
13190 + if (bdev_info_list[index] && bdev_info_list[index]->device != device)
13191 + close_bdev(index);
13192 +
13193 + bdev = open_by_devnum(device, FMODE_READ);
13194 +
13195 + if (IS_ERR(bdev) || !bdev) {
13196 + if (display_errs)
13197 + suspend_early_boot_message(1,SUSPEND_CONTINUE_REQ,
13198 + "Failed to get access to block device "
13199 + "\"%x\" (error %d).\n Maybe you need "
13200 + "to run mknod and/or lvmsetup in an "
13201 + "initrd/ramfs?", device, bdev);
13202 + return ERR_PTR(-EINVAL);
13203 + }
13204 +
13205 + this = kmalloc(sizeof(struct bdev_opened), GFP_KERNEL);
13206 + if (!this) {
13207 + printk(KERN_WARNING "Suspend2: Failed to allocate memory for "
13208 + "opening a bdev.");
13209 + return ERR_PTR(-ENOMEM);
13210 + }
13211 +
13212 + bdev_info_list[index] = this;
13213 + this->device = device;
13214 + this->bdev = bdev;
13215 +
13216 + if (index < MAX_SWAPFILES)
13217 + devinfo[index].bdev = bdev;
13218 +
13219 + return bdev;
13220 +}
13221 +
13222 +/* Must be silent - might be called from cat /sys/power/suspend2/debug_info
13223 + * Returns 0 if was off, -EBUSY if was on, error value otherwise.
13224 + */
13225 +static int enable_swapfile(void)
13226 +{
13227 + int activateswapresult = -EINVAL;
13228 +
13229 + if (suspend_swapon_status)
13230 + return 0;
13231 +
13232 + if (swapfilename[0]) {
13233 + /* Attempt to swap on with maximum priority */
13234 + activateswapresult = sys_swapon(swapfilename, 0xFFFF);
13235 + if ((activateswapresult) && (activateswapresult != -EBUSY))
13236 + printk("Suspend2: The swapfile/partition specified by "
13237 + "/sys/power/suspend2/suspend_swap/swapfile "
13238 + "(%s) could not be turned on (error %d). "
13239 + "Attempting to continue.\n",
13240 + swapfilename, activateswapresult);
13241 + if (!activateswapresult)
13242 + suspend_swapon_status = 1;
13243 + }
13244 + return activateswapresult;
13245 +}
13246 +
13247 +/* Returns 0 if was on, -EINVAL if was off, error value otherwise */
13248 +static int disable_swapfile(void)
13249 +{
13250 + int result = -EINVAL;
13251 +
13252 + if (!suspend_swapon_status)
13253 + return 0;
13254 +
13255 + if (swapfilename[0]) {
13256 + result = sys_swapoff(swapfilename);
13257 + if (result == -EINVAL)
13258 + return 0; /* Wasn't on */
13259 + if (!result)
13260 + suspend_swapon_status = 0;
13261 + }
13262 +
13263 + return result;
13264 +}
13265 +
13266 +static int try_to_parse_resume_device(char *commandline, int quiet)
13267 +{
13268 + struct kstat stat;
13269 + int error = 0;
13270 +
13271 + resume_swap_dev_t = name_to_dev_t(commandline);
13272 +
13273 + if (!resume_swap_dev_t) {
13274 + struct file *file = filp_open(commandline, O_RDONLY, 0);
13275 +
13276 + if (!IS_ERR(file) && file) {
13277 + vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
13278 + filp_close(file, NULL);
13279 + } else
13280 + error = vfs_stat(commandline, &stat);
13281 + if (!error)
13282 + resume_swap_dev_t = stat.rdev;
13283 + }
13284 +
13285 + if (!resume_swap_dev_t) {
13286 + if (quiet)
13287 + return 1;
13288 +
13289 + if (test_suspend_state(SUSPEND_TRYING_TO_RESUME))
13290 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
13291 + "Failed to translate \"%s\" into a device id.\n",
13292 + commandline);
13293 + else
13294 + printk("Suspend2: Can't translate \"%s\" into a device "
13295 + "id yet.\n", commandline);
13296 + return 1;
13297 + }
13298 +
13299 + resume_block_device = open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 0);
13300 + if (IS_ERR(resume_block_device)) {
13301 + if (!quiet)
13302 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
13303 + "Failed to get access to \"%s\", where"
13304 + " the swap header should be found.",
13305 + commandline);
13306 + return 1;
13307 + }
13308 +
13309 + return 0;
13310 +}
13311 +
13312 +/*
13313 + * If we have read part of the image, we might have filled memory with
13314 + * data that should be zeroed out.
13315 + */
13316 +static void suspend_swap_noresume_reset(void)
13317 +{
13318 + memset((char *) &devinfo, 0, sizeof(devinfo));
13319 +}
13320 +
13321 +static int parse_signature(char *header, int restore)
13322 +{
13323 + int type = -1;
13324 +
13325 + if (!memcmp("SWAP-SPACE",header,10))
13326 + return 0;
13327 + else if (!memcmp("SWAPSPACE2",header,10))
13328 + return 1;
13329 +
13330 + else if (!memcmp("S1SUSP",header,6))
13331 + type = 2;
13332 + else if (!memcmp("S2SUSP",header,6))
13333 + type = 3;
13334 + else if (!memcmp("S1SUSPEND",header,9))
13335 + type = 4;
13336 +
13337 + else if (!memcmp("z",header,1))
13338 + type = 12;
13339 + else if (!memcmp("Z",header,1))
13340 + type = 13;
13341 +
13342 + /*
13343 + * Put bdev of suspend header in last byte of swap header
13344 + * (unsigned short)
13345 + */
13346 + if (type > 11) {
13347 + dev_t *header_ptr = (dev_t *) &header[1];
13348 + unsigned char *headerblocksize_ptr =
13349 + (unsigned char *) &header[5];
13350 + u32 *headerblock_ptr = (u32 *) &header[6];
13351 + header_dev_t = *header_ptr;
13352 + /*
13353 + * We are now using the highest bit of the char to indicate
13354 + * whether we have attempted to resume from this image before.
13355 + */
13356 + clear_suspend_state(SUSPEND_RESUMED_BEFORE);
13357 + if (((int) *headerblocksize_ptr) & 0x80)
13358 + set_suspend_state(SUSPEND_RESUMED_BEFORE);
13359 + headerblock = (unsigned long) *headerblock_ptr;
13360 + }
13361 +
13362 + if ((restore) && (type > 5)) {
13363 + /* We only reset our own signatures */
13364 + if (type & 1)
13365 + memcpy(header,"SWAPSPACE2",10);
13366 + else
13367 + memcpy(header,"SWAP-SPACE",10);
13368 + }
13369 +
13370 + return type;
13371 +}
13372 +
13373 +/*
13374 + * prepare_signature
13375 + */
13376 +static int prepare_signature(dev_t bdev, unsigned long block,
13377 + char *current_header)
13378 +{
13379 + int current_type = parse_signature(current_header, 0);
13380 + dev_t *header_ptr = (dev_t *) (&current_header[1]);
13381 + unsigned long *headerblock_ptr =
13382 + (unsigned long *) (&current_header[6]);
13383 +
13384 + if ((current_type > 1) && (current_type < 6))
13385 + return 1;
13386 +
13387 + /* At the moment, I don't have a way to handle the block being
13388 + * > 32 bits. Not enough room in the signature and no way to
13389 + * safely put the data elsewhere. */
13390 +
13391 + if (BITS_PER_LONG == 64 && ffs(block) > 31) {
13392 + suspend_prepare_status(DONT_CLEAR_BAR,
13393 + "Header sector requires 33+ bits. "
13394 + "Would not be able to resume.");
13395 + return 1;
13396 + }
13397 +
13398 + if (current_type & 1)
13399 + current_header[0] = 'Z';
13400 + else
13401 + current_header[0] = 'z';
13402 + *header_ptr = bdev;
13403 + /* prev is the first/last swap page of the resume area */
13404 + *headerblock_ptr = (unsigned long) block;
13405 + return 0;
13406 +}
13407 +
13408 +static int __suspend_swap_allocate_storage(int main_storage_requested,
13409 + int header_storage);
13410 +
13411 +static int suspend_swap_allocate_header_space(int space_requested)
13412 +{
13413 + int i;
13414 +
13415 + if (!swapextents.size && __suspend_swap_allocate_storage(
13416 + main_pages_requested, space_requested)) {
13417 + printk("Failed to allocate space for the header.\n");
13418 + return -ENOSPC;
13419 + }
13420 +
13421 + suspend_extent_state_goto_start(&suspend_writer_posn);
13422 + suspend_bio_ops.forward_one_page(); /* To first page */
13423 +
13424 + for (i = 0; i < space_requested; i++) {
13425 + if (suspend_bio_ops.forward_one_page()) {
13426 + printk("Out of space while seeking to allocate "
13427 + "header pages,\n");
13428 + header_pages_allocated = i;
13429 + return -ENOSPC;
13430 + }
13431 +
13432 + }
13433 +
13434 + header_pages_allocated = space_requested;
13435 +
13436 + /* The end of header pages will be the start of pageset 2;
13437 + * we are now sitting on the first pageset2 page. */
13438 + suspend_extent_state_save(&suspend_writer_posn,
13439 + &suspend_writer_posn_save[2]);
13440 + return 0;
13441 +}
13442 +
13443 +static void get_main_pool_phys_params(void)
13444 +{
13445 + struct extent *extentpointer = NULL;
13446 + unsigned long address;
13447 + int i, extent_min = -1, extent_max = -1, last_chain = -1;
13448 +
13449 + for (i = 0; i < MAX_SWAPFILES; i++)
13450 + if (block_chain[i].first)
13451 + suspend_put_extent_chain(&block_chain[i]);
13452 +
13453 + suspend_extent_for_each(&swapextents, extentpointer, address) {
13454 + swp_entry_t swap_address = extent_val_to_swap_entry(address);
13455 + pgoff_t offset = swp_offset(swap_address);
13456 + unsigned swapfilenum = swp_type(swap_address);
13457 + struct swap_info_struct *sis = get_swap_info_struct(swapfilenum);
13458 + sector_t new_sector = map_swap_page(sis, offset);
13459 +
13460 + if ((new_sector == extent_max + 1) &&
13461 + (last_chain == swapfilenum))
13462 + extent_max++;
13463 + else {
13464 + if (extent_min > -1) {
13465 + if (test_action_state(SUSPEND_TEST_BIO))
13466 + printk("Adding extent chain %d %d-%d.\n",
13467 + swapfilenum,
13468 + extent_min <<
13469 + devinfo[last_chain].bmap_shift,
13470 + extent_max <<
13471 + devinfo[last_chain].bmap_shift);
13472 +
13473 + suspend_add_to_extent_chain(
13474 + &block_chain[last_chain],
13475 + extent_min, extent_max);
13476 + }
13477 + extent_min = extent_max = new_sector;
13478 + last_chain = swapfilenum;
13479 + }
13480 + }
13481 +
13482 + if (extent_min > -1) {
13483 + if (test_action_state(SUSPEND_TEST_BIO))
13484 + printk("Adding extent chain %d %d-%d.\n",
13485 + last_chain,
13486 + extent_min <<
13487 + devinfo[last_chain].bmap_shift,
13488 + extent_max <<
13489 + devinfo[last_chain].bmap_shift);
13490 + suspend_add_to_extent_chain(
13491 + &block_chain[last_chain],
13492 + extent_min, extent_max);
13493 + }
13494 +
13495 + suspend_swap_allocate_header_space(header_pages_allocated);
13496 +}
13497 +
13498 +static int suspend_swap_storage_allocated(void)
13499 +{
13500 + return main_pages_requested + header_pages_allocated;
13501 +}
13502 +
13503 +static int suspend_swap_storage_available(void)
13504 +{
13505 + si_swapinfo(&swapinfo);
13506 + return (((int) swapinfo.freeswap + main_pages_allocated) * PAGE_SIZE /
13507 + (PAGE_SIZE + sizeof(unsigned long) + sizeof(int)));
13508 +}
13509 +
13510 +static int suspend_swap_initialise(int starting_cycle)
13511 +{
13512 + if (!starting_cycle)
13513 + return 0;
13514 +
13515 + enable_swapfile();
13516 +
13517 + if (resume_swap_dev_t && !resume_block_device &&
13518 + IS_ERR(resume_block_device =
13519 + open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 1)))
13520 + return 1;
13521 +
13522 + return 0;
13523 +}
13524 +
13525 +static void suspend_swap_cleanup(int ending_cycle)
13526 +{
13527 + if (ending_cycle)
13528 + disable_swapfile();
13529 +
13530 + close_bdevs();
13531 +}
13532 +
13533 +static int suspend_swap_release_storage(void)
13534 +{
13535 + int i = 0;
13536 +
13537 + if (test_action_state(SUSPEND_KEEP_IMAGE) &&
13538 + test_suspend_state(SUSPEND_NOW_RESUMING))
13539 + return 0;
13540 +
13541 + header_pages_allocated = 0;
13542 + main_pages_allocated = 0;
13543 +
13544 + if (swapextents.first) {
13545 + /* Free swap entries */
13546 + struct extent *extentpointer;
13547 + unsigned long extentvalue;
13548 + suspend_extent_for_each(&swapextents, extentpointer,
13549 + extentvalue)
13550 + swap_free(extent_val_to_swap_entry(extentvalue));
13551 +
13552 + suspend_put_extent_chain(&swapextents);
13553 +
13554 + for (i = 0; i < MAX_SWAPFILES; i++)
13555 + if (block_chain[i].first)
13556 + suspend_put_extent_chain(&block_chain[i]);
13557 + }
13558 +
13559 + return 0;
13560 +}
13561 +
13562 +static int suspend_swap_allocate_storage(int space_requested)
13563 +{
13564 + if (!__suspend_swap_allocate_storage(space_requested,
13565 + header_pages_allocated)) {
13566 + main_pages_requested = space_requested;
13567 + return 0;
13568 + }
13569 +
13570 + return -ENOSPC;
13571 +}
13572 +
13573 +static void free_swap_range(unsigned long min, unsigned long max)
13574 +{
13575 + int j;
13576 +
13577 + for (j = min; j < max; j++)
13578 + swap_free(extent_val_to_swap_entry(j));
13579 +}
13580 +
13581 +/*
13582 + * Round robin allocation (where swap storage has the same priority).
13583 + * could make this very inefficient, so we track extents allocated on
13584 + * a per-swapfiles basis.
13585 + */
13586 +static int __suspend_swap_allocate_storage(int main_space_requested,
13587 + int header_space_requested)
13588 +{
13589 + int i, result = 0, first[MAX_SWAPFILES], pages_to_get, extra_pages, gotten = 0;
13590 + unsigned long extent_min[MAX_SWAPFILES], extent_max[MAX_SWAPFILES];
13591 +
13592 + extra_pages = DIV_ROUND_UP(main_space_requested * (sizeof(unsigned long)
13593 + + sizeof(int)), PAGE_SIZE);
13594 + pages_to_get = main_space_requested + extra_pages +
13595 + header_space_requested - swapextents.size;
13596 +
13597 + if (pages_to_get < 1)
13598 + return 0;
13599 +
13600 + for (i=0; i < MAX_SWAPFILES; i++) {
13601 + struct swap_info_struct *si = get_swap_info_struct(i);
13602 + if ((devinfo[i].bdev = si->bdev))
13603 + devinfo[i].dev_t = si->bdev->bd_dev;
13604 + devinfo[i].bmap_shift = 3;
13605 + devinfo[i].blocks_per_page = 1;
13606 + first[i] = 1;
13607 + }
13608 +
13609 + for(i=0; i < pages_to_get; i++) {
13610 + swp_entry_t entry;
13611 + unsigned long new_value;
13612 + unsigned swapfilenum;
13613 +
13614 + entry = get_swap_page();
13615 + if (!entry.val)
13616 + break;
13617 +
13618 + swapfilenum = swp_type(entry);
13619 + new_value = swap_entry_to_extent_val(entry);
13620 +
13621 + if (first[swapfilenum]) {
13622 + first[swapfilenum] = 0;
13623 + extent_min[swapfilenum] = new_value;
13624 + extent_max[swapfilenum] = new_value;
13625 + gotten++;
13626 + continue;
13627 + }
13628 +
13629 + if (new_value == extent_max[swapfilenum] + 1) {
13630 + extent_max[swapfilenum]++;
13631 + gotten++;
13632 + continue;
13633 + }
13634 +
13635 + if (suspend_add_to_extent_chain(&swapextents,
13636 + extent_min[swapfilenum],
13637 + extent_max[swapfilenum])) {
13638 + free_swap_range(extent_min[swapfilenum],
13639 + extent_max[swapfilenum]);
13640 + swap_free(entry);
13641 + gotten -= (extent_max[swapfilenum] -
13642 + extent_min[swapfilenum]);
13643 + break;
13644 + } else {
13645 + extent_min[swapfilenum] = new_value;
13646 + extent_max[swapfilenum] = new_value;
13647 + gotten++;
13648 + }
13649 + }
13650 +
13651 + for (i = 0; i < MAX_SWAPFILES; i++)
13652 + if (!first[i] && suspend_add_to_extent_chain(&swapextents,
13653 + extent_min[i], extent_max[i])) {
13654 + free_swap_range(extent_min[i], extent_max[i]);
13655 + gotten -= (extent_max[i] - extent_min[i]);
13656 + }
13657 +
13658 + if (gotten < pages_to_get)
13659 + result = -ENOSPC;
13660 +
13661 + main_pages_allocated += gotten;
13662 + get_main_pool_phys_params();
13663 + return result;
13664 +}
13665 +
13666 +static int suspend_swap_write_header_init(void)
13667 +{
13668 + int i, result;
13669 + struct swap_info_struct *si;
13670 +
13671 + suspend_extent_state_goto_start(&suspend_writer_posn);
13672 +
13673 + suspend_writer_buffer_posn = suspend_header_bytes_used = 0;
13674 +
13675 + /* Info needed to bootstrap goes at the start of the header.
13676 + * First we save the positions and devinfo, including the number
13677 + * of header pages. Then we save the structs containing data needed
13678 + * for reading the header pages back.
13679 + * Note that even if header pages take more than one page, when we
13680 + * read back the info, we will have restored the location of the
13681 + * next header page by the time we go to use it.
13682 + */
13683 +
13684 + /* Forward one page will be done prior to the read */
13685 + for (i = 0; i < MAX_SWAPFILES; i++) {
13686 + si = get_swap_info_struct(i);
13687 + if (si->swap_file)
13688 + devinfo[i].dev_t = si->bdev->bd_dev;
13689 + else
13690 + devinfo[i].dev_t = (dev_t) 0;
13691 + }
13692 +
13693 + if ((result = suspend_bio_ops.rw_header_chunk(WRITE,
13694 + &suspend_swapops,
13695 + (char *) &suspend_writer_posn_save,
13696 + sizeof(suspend_writer_posn_save))))
13697 + return result;
13698 +
13699 + if ((result = suspend_bio_ops.rw_header_chunk(WRITE,
13700 + &suspend_swapops,
13701 + (char *) &devinfo, sizeof(devinfo))))
13702 + return result;
13703 +
13704 + for (i=0; i < MAX_SWAPFILES; i++)
13705 + suspend_serialise_extent_chain(&suspend_swapops, &block_chain[i]);
13706 +
13707 + return 0;
13708 +}
13709 +
13710 +static int suspend_swap_write_header_cleanup(void)
13711 +{
13712 + int result;
13713 + struct swap_info_struct *si;
13714 +
13715 + /* Write any unsaved data */
13716 + if (suspend_writer_buffer_posn)
13717 + suspend_bio_ops.write_header_chunk_finish();
13718 +
13719 + suspend_bio_ops.finish_all_io();
13720 +
13721 + suspend_extent_state_goto_start(&suspend_writer_posn);
13722 + suspend_bio_ops.forward_one_page();
13723 +
13724 + /* Adjust swap header */
13725 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
13726 + resume_firstblock,
13727 + virt_to_page(suspend_writer_buffer));
13728 +
13729 + si = get_swap_info_struct(suspend_writer_posn.current_chain);
13730 + result = prepare_signature(si->bdev->bd_dev,
13731 + suspend_writer_posn.current_offset,
13732 + ((union swap_header *) suspend_writer_buffer)->magic.magic);
13733 +
13734 + if (!result)
13735 + suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
13736 + resume_firstblock,
13737 + virt_to_page(suspend_writer_buffer));
13738 +
13739 + suspend_bio_ops.finish_all_io();
13740 +
13741 + return result;
13742 +}
13743 +
13744 +/* ------------------------- HEADER READING ------------------------- */
13745 +
13746 +/*
13747 + * read_header_init()
13748 + *
13749 + * Description:
13750 + * 1. Attempt to read the device specified with resume2=.
13751 + * 2. Check the contents of the swap header for our signature.
13752 + * 3. Warn, ignore, reset and/or continue as appropriate.
13753 + * 4. If continuing, read the suspend_swap configuration section
13754 + * of the header and set up block device info so we can read
13755 + * the rest of the header & image.
13756 + *
13757 + * Returns:
13758 + * May not return if user choose to reboot at a warning.
13759 + * -EINVAL if cannot resume at this time. Booting should continue
13760 + * normally.
13761 + */
13762 +
13763 +static int suspend_swap_read_header_init(void)
13764 +{
13765 + int i, result = 0;
13766 +
13767 + suspend_header_bytes_used = 0;
13768 +
13769 + if (!header_dev_t) {
13770 + printk("read_header_init called when we haven't "
13771 + "verified there is an image!\n");
13772 + return -EINVAL;
13773 + }
13774 +
13775 + /*
13776 + * If the header is not on the resume_swap_dev_t, get the resume device first.
13777 + */
13778 + if (header_dev_t != resume_swap_dev_t) {
13779 + header_block_device = open_bdev(MAX_SWAPFILES + 1,
13780 + header_dev_t, 1);
13781 +
13782 + if (IS_ERR(header_block_device))
13783 + return PTR_ERR(header_block_device);
13784 + } else
13785 + header_block_device = resume_block_device;
13786 +
13787 + /*
13788 + * Read suspend_swap configuration.
13789 + * Headerblock size taken into account already.
13790 + */
13791 + suspend_bio_ops.bdev_page_io(READ, header_block_device,
13792 + headerblock << 3,
13793 + virt_to_page((unsigned long) suspend_writer_buffer));
13794 +
13795 + memcpy(&suspend_writer_posn_save, suspend_writer_buffer, 3 * sizeof(struct extent_iterate_saved_state));
13796 +
13797 + suspend_writer_buffer_posn = 3 * sizeof(struct extent_iterate_saved_state);
13798 + suspend_header_bytes_used += 3 * sizeof(struct extent_iterate_saved_state);
13799 +
13800 + memcpy(&devinfo, suspend_writer_buffer + suspend_writer_buffer_posn, sizeof(devinfo));
13801 +
13802 + suspend_writer_buffer_posn += sizeof(devinfo);
13803 + suspend_header_bytes_used += sizeof(devinfo);
13804 +
13805 + /* Restore device info */
13806 + for (i = 0; i < MAX_SWAPFILES; i++) {
13807 + dev_t thisdevice = devinfo[i].dev_t;
13808 + struct block_device *result;
13809 +
13810 + devinfo[i].bdev = NULL;
13811 +
13812 + if (!thisdevice)
13813 + continue;
13814 +
13815 + if (thisdevice == resume_swap_dev_t) {
13816 + devinfo[i].bdev = resume_block_device;
13817 + bdev_info_list[i] = bdev_info_list[MAX_SWAPFILES];
13818 + bdev_info_list[MAX_SWAPFILES] = NULL;
13819 + continue;
13820 + }
13821 +
13822 + if (thisdevice == header_dev_t) {
13823 + devinfo[i].bdev = header_block_device;
13824 + bdev_info_list[i] = bdev_info_list[MAX_SWAPFILES + 1];
13825 + bdev_info_list[MAX_SWAPFILES + 1] = NULL;
13826 + continue;
13827 + }
13828 +
13829 + result = open_bdev(i, thisdevice, 1);
13830 + if (IS_ERR(result))
13831 + return PTR_ERR(result);
13832 + }
13833 +
13834 + suspend_bio_ops.read_header_init();
13835 + suspend_extent_state_goto_start(&suspend_writer_posn);
13836 + suspend_bio_ops.set_extra_page_forward();
13837 +
13838 + for (i = 0; i < MAX_SWAPFILES && !result; i++)
13839 + result = suspend_load_extent_chain(&block_chain[i]);
13840 +
13841 + return result;
13842 +}
13843 +
13844 +static int suspend_swap_read_header_cleanup(void)
13845 +{
13846 + suspend_bio_ops.rw_cleanup(READ);
13847 + return 0;
13848 +}
13849 +
13850 +/* suspend_swap_invalidate_image
13851 + *
13852 + */
13853 +static int suspend_swap_invalidate_image(void)
13854 +{
13855 + union p_diskpage cur;
13856 + int result = 0;
13857 + char newsig[11];
13858 +
13859 + cur.address = get_zeroed_page(GFP_ATOMIC);
13860 + if (!cur.address) {
13861 + printk("Unable to allocate a page for restoring the swap signature.\n");
13862 + return -ENOMEM;
13863 + }
13864 +
13865 + /*
13866 + * If nr_suspends == 0, we must be booting, so no swap pages
13867 + * will be recorded as used yet.
13868 + */
13869 +
13870 + if (nr_suspends > 0)
13871 + suspend_swap_release_storage();
13872 +
13873 + /*
13874 + * We don't do a sanity check here: we want to restore the swap
13875 + * whatever version of kernel made the suspend image.
13876 + *
13877 + * We need to write swap, but swap may not be enabled so
13878 + * we write the device directly
13879 + */
13880 +
13881 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
13882 + resume_firstblock,
13883 + virt_to_page(cur.pointer));
13884 +
13885 + result = parse_signature(cur.pointer->swh.magic.magic, 1);
13886 +
13887 + if (result < 5)
13888 + goto out;
13889 +
13890 + strncpy(newsig, cur.pointer->swh.magic.magic, 10);
13891 + newsig[10] = 0;
13892 +
13893 + suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
13894 + resume_firstblock,
13895 + virt_to_page(cur.pointer));
13896 +
13897 + if (!nr_suspends)
13898 + printk(KERN_WARNING "Suspend2: Image invalidated.\n");
13899 +out:
13900 + suspend_bio_ops.finish_all_io();
13901 + free_page(cur.address);
13902 + return 0;
13903 +}
13904 +
13905 +/*
13906 + * workspace_size
13907 + *
13908 + * Description:
13909 + * Returns the number of bytes of RAM needed for this
13910 + * code to do its work. (Used when calculating whether
13911 + * we have enough memory to be able to suspend & resume).
13912 + *
13913 + */
13914 +static int suspend_swap_memory_needed(void)
13915 +{
13916 + return 1;
13917 +}
13918 +
13919 +/*
13920 + * Print debug info
13921 + *
13922 + * Description:
13923 + */
13924 +static int suspend_swap_print_debug_stats(char *buffer, int size)
13925 +{
13926 + int len = 0;
13927 + struct sysinfo sysinfo;
13928 +
13929 + if (suspendActiveAllocator != &suspend_swapops) {
13930 + len = snprintf_used(buffer, size, "- SwapAllocator inactive.\n");
13931 + return len;
13932 + }
13933 +
13934 + len = snprintf_used(buffer, size, "- SwapAllocator active.\n");
13935 + if (swapfilename[0])
13936 + len+= snprintf_used(buffer+len, size-len,
13937 + " Attempting to automatically swapon: %s.\n", swapfilename);
13938 +
13939 + si_swapinfo(&sysinfo);
13940 +
13941 + len+= snprintf_used(buffer+len, size-len, " Swap available for image: %ld pages.\n",
13942 + (int) sysinfo.freeswap + suspend_swap_storage_allocated());
13943 +
13944 + return len;
13945 +}
13946 +
13947 +/*
13948 + * Storage needed
13949 + *
13950 + * Returns amount of space in the swap header required
13951 + * for the suspend_swap's data. This ignores the links between
13952 + * pages, which we factor in when allocating the space.
13953 + *
13954 + * We ensure the space is allocated, but actually save the
13955 + * data from write_header_init and therefore don't also define a
13956 + * save_config_info routine.
13957 + */
13958 +static int suspend_swap_storage_needed(void)
13959 +{
13960 + int i, result;
13961 + result = sizeof(suspend_writer_posn_save) + sizeof(devinfo);
13962 +
13963 + for (i = 0; i < MAX_SWAPFILES; i++) {
13964 + result += 3 * sizeof(int);
13965 + result += (2 * sizeof(unsigned long) *
13966 + block_chain[i].num_extents);
13967 + }
13968 +
13969 + return result;
13970 +}
13971 +
13972 +/*
13973 + * Image_exists
13974 + */
13975 +static int suspend_swap_image_exists(void)
13976 +{
13977 + int signature_found;
13978 + union p_diskpage diskpage;
13979 +
13980 + if (!resume_swap_dev_t) {
13981 + printk("Not even trying to read header "
13982 + "because resume_swap_dev_t is not set.\n");
13983 + return 0;
13984 + }
13985 +
13986 + if (!resume_block_device &&
13987 + IS_ERR(resume_block_device =
13988 + open_bdev(MAX_SWAPFILES, resume_swap_dev_t, 1))) {
13989 + printk("Failed to open resume dev_t (%x).\n", resume_swap_dev_t);
13990 + return 0;
13991 + }
13992 +
13993 + diskpage.address = get_zeroed_page(GFP_ATOMIC);
13994 +
13995 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
13996 + resume_firstblock,
13997 + virt_to_page(diskpage.ptr));
13998 + suspend_bio_ops.finish_all_io();
13999 +
14000 + signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14001 + free_page(diskpage.address);
14002 +
14003 + if (signature_found < 2) {
14004 + printk("Suspend2: Normal swapspace found.\n");
14005 + return 0; /* Normal swap space */
14006 + } else if (signature_found == -1) {
14007 + printk(KERN_ERR "Suspend2: Unable to find a signature. Could "
14008 + "you have moved a swap file?\n");
14009 + return 0;
14010 + } else if (signature_found < 6) {
14011 + printk("Suspend2: Detected another implementation's signature.\n");
14012 + return 0;
14013 + } else if ((signature_found >> 1) != SIGNATURE_VER) {
14014 + if ((!(test_suspend_state(SUSPEND_NORESUME_SPECIFIED))) &&
14015 + suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
14016 + "Found a different style suspend image signature.")) {
14017 + set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
14018 + printk("Suspend2: Dectected another implementation's signature.\n");
14019 + }
14020 + }
14021 +
14022 + return 1;
14023 +}
14024 +
14025 +/*
14026 + * Mark resume attempted.
14027 + *
14028 + * Record that we tried to resume from this image.
14029 + */
14030 +static void suspend_swap_mark_resume_attempted(int mark)
14031 +{
14032 + union p_diskpage diskpage;
14033 + int signature_found;
14034 +
14035 + if (!resume_swap_dev_t) {
14036 + printk("Not even trying to record attempt at resuming"
14037 + " because resume_swap_dev_t is not set.\n");
14038 + return;
14039 + }
14040 +
14041 + diskpage.address = get_zeroed_page(GFP_ATOMIC);
14042 +
14043 + suspend_bio_ops.bdev_page_io(READ, resume_block_device,
14044 + resume_firstblock,
14045 + virt_to_page(diskpage.ptr));
14046 + signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14047 +
14048 + switch (signature_found) {
14049 + case 12:
14050 + case 13:
14051 + diskpage.pointer->swh.magic.magic[5] &= ~0x80;
14052 + if (mark)
14053 + diskpage.pointer->swh.magic.magic[5] |= 0x80;
14054 + break;
14055 + }
14056 +
14057 + suspend_bio_ops.bdev_page_io(WRITE, resume_block_device,
14058 + resume_firstblock,
14059 + virt_to_page(diskpage.ptr));
14060 + suspend_bio_ops.finish_all_io();
14061 + free_page(diskpage.address);
14062 + return;
14063 +}
14064 +
14065 +/*
14066 + * Parse Image Location
14067 + *
14068 + * Attempt to parse a resume2= parameter.
14069 + * Swap Writer accepts:
14070 + * resume2=swap:DEVNAME[:FIRSTBLOCK][@BLOCKSIZE]
14071 + *
14072 + * Where:
14073 + * DEVNAME is convertable to a dev_t by name_to_dev_t
14074 + * FIRSTBLOCK is the location of the first block in the swap file
14075 + * (specifying for a swap partition is nonsensical but not prohibited).
14076 + * Data is validated by attempting to read a swap header from the
14077 + * location given. Failure will result in suspend_swap refusing to
14078 + * save an image, and a reboot with correct parameters will be
14079 + * necessary.
14080 + */
14081 +static int suspend_swap_parse_sig_location(char *commandline,
14082 + int only_allocator, int quiet)
14083 +{
14084 + char *thischar, *devstart, *colon = NULL, *at_symbol = NULL;
14085 + union p_diskpage diskpage;
14086 + int signature_found, result = -EINVAL, temp_result;
14087 +
14088 + if (strncmp(commandline, "swap:", 5)) {
14089 + /*
14090 + * Failing swap:, we'll take a simple
14091 + * resume2=/dev/hda2, but fall through to
14092 + * other allocators if /dev/ isn't matched.
14093 + */
14094 + if (strncmp(commandline, "/dev/", 5))
14095 + return 1;
14096 + } else
14097 + commandline += 5;
14098 +
14099 + devstart = thischar = commandline;
14100 + while ((*thischar != ':') && (*thischar != '@') &&
14101 + ((thischar - commandline) < 250) && (*thischar))
14102 + thischar++;
14103 +
14104 + if (*thischar == ':') {
14105 + colon = thischar;
14106 + *colon = 0;
14107 + thischar++;
14108 + }
14109 +
14110 + while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
14111 + thischar++;
14112 +
14113 + if (*thischar == '@') {
14114 + at_symbol = thischar;
14115 + *at_symbol = 0;
14116 + }
14117 +
14118 + if (colon)
14119 + resume_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
14120 + else
14121 + resume_firstblock = 0;
14122 +
14123 + clear_suspend_state(SUSPEND_CAN_SUSPEND);
14124 + clear_suspend_state(SUSPEND_CAN_RESUME);
14125 +
14126 + /* Legacy */
14127 + if (at_symbol) {
14128 + resume_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
14129 + if (resume_blocksize & (SECTOR_SIZE - 1)) {
14130 + if (!quiet)
14131 + printk("SwapAllocator: Blocksizes are multiples"
14132 + "of %d!\n", SECTOR_SIZE);
14133 + return -EINVAL;
14134 + }
14135 + resume_firstblock = resume_firstblock *
14136 + (resume_blocksize / SECTOR_SIZE);
14137 + }
14138 +
14139 + temp_result = try_to_parse_resume_device(devstart, quiet);
14140 +
14141 + if (colon)
14142 + *colon = ':';
14143 + if (at_symbol)
14144 + *at_symbol = '@';
14145 +
14146 + if (temp_result)
14147 + return -EINVAL;
14148 +
14149 + diskpage.address = get_zeroed_page(GFP_ATOMIC);
14150 + if (!diskpage.address) {
14151 + printk(KERN_ERR "Suspend2: SwapAllocator: Failed to allocate "
14152 + "a diskpage for I/O.\n");
14153 + return -ENOMEM;
14154 + }
14155 +
14156 + temp_result = suspend_bio_ops.bdev_page_io(READ,
14157 + resume_block_device,
14158 + resume_firstblock,
14159 + virt_to_page(diskpage.ptr));
14160 +
14161 + suspend_bio_ops.finish_all_io();
14162 +
14163 + if (temp_result) {
14164 + printk(KERN_ERR "Suspend2: SwapAllocator: Failed to submit "
14165 + "I/O.\n");
14166 + goto invalid;
14167 + }
14168 +
14169 + signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
14170 +
14171 + if (signature_found != -1) {
14172 + if (!quiet)
14173 + printk("Suspend2: SwapAllocator: Signature found.\n");
14174 + result = 0;
14175 +
14176 + suspend_bio_ops.set_devinfo(devinfo);
14177 + suspend_writer_posn.chains = &block_chain[0];
14178 + suspend_writer_posn.num_chains = MAX_SWAPFILES;
14179 + set_suspend_state(SUSPEND_CAN_SUSPEND);
14180 + set_suspend_state(SUSPEND_CAN_RESUME);
14181 + } else
14182 + if (!quiet)
14183 + printk(KERN_ERR "Suspend2: SwapAllocator: No swap "
14184 + "signature found at specified location.\n");
14185 +invalid:
14186 + free_page((unsigned long) diskpage.address);
14187 + return result;
14188 +
14189 +}
14190 +
14191 +static int header_locations_read_sysfs(const char *page, int count)
14192 +{
14193 + int i, printedpartitionsmessage = 0, len = 0, haveswap = 0;
14194 + struct inode *swapf = 0;
14195 + int zone;
14196 + char *path_page = (char *) __get_free_page(GFP_KERNEL);
14197 + char *path, *output = (char *) page;
14198 + int path_len;
14199 +
14200 + if (!page)
14201 + return 0;
14202 +
14203 + for (i = 0; i < MAX_SWAPFILES; i++) {
14204 + struct swap_info_struct *si = get_swap_info_struct(i);
14205 +
14206 + if (!si->swap_file)
14207 + continue;
14208 +
14209 + if (S_ISBLK(si->swap_file->f_mapping->host->i_mode)) {
14210 + haveswap = 1;
14211 + if (!printedpartitionsmessage) {
14212 + len += sprintf(output + len,
14213 + "For swap partitions, simply use the "
14214 + "format: resume2=swap:/dev/hda1.\n");
14215 + printedpartitionsmessage = 1;
14216 + }
14217 + } else {
14218 + path_len = 0;
14219 +
14220 + path = d_path(si->swap_file->f_dentry,
14221 + si->swap_file->f_vfsmnt,
14222 + path_page,
14223 + PAGE_SIZE);
14224 + path_len = snprintf(path_page, 31, "%s", path);
14225 +
14226 + haveswap = 1;
14227 + swapf = si->swap_file->f_mapping->host;
14228 + if (!(zone = bmap(swapf,0))) {
14229 + len+= sprintf(output + len,
14230 + "Swapfile %s has been corrupted. Reuse"
14231 + " mkswap on it and try again.\n",
14232 + path_page);
14233 + } else {
14234 + char name_buffer[255];
14235 + len+= sprintf(output + len, "For swapfile `%s`,"
14236 + " use resume2=swap:/dev/%s:0x%x.\n",
14237 + path_page,
14238 + bdevname(si->bdev, name_buffer),
14239 + zone << (swapf->i_blkbits - 9));
14240 + }
14241 +
14242 + }
14243 + }
14244 +
14245 + if (!haveswap)
14246 + len = sprintf(output, "You need to turn on swap partitions "
14247 + "before examining this file.\n");
14248 +
14249 + free_page((unsigned long) path_page);
14250 + return len;
14251 +}
14252 +
14253 +static struct suspend_sysfs_data sysfs_params[] = {
14254 + {
14255 + SUSPEND2_ATTR("swapfilename", SYSFS_RW),
14256 + SYSFS_STRING(swapfilename, 255, 0)
14257 + },
14258 +
14259 + {
14260 + SUSPEND2_ATTR("headerlocations", SYSFS_READONLY),
14261 + SYSFS_CUSTOM(header_locations_read_sysfs, NULL, 0)
14262 + },
14263 +
14264 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
14265 + SYSFS_INT(&suspend_swapops.enabled, 0, 1, 0),
14266 + .write_side_effect = attempt_to_parse_resume_device2,
14267 + }
14268 +};
14269 +
14270 +static struct suspend_module_ops suspend_swapops = {
14271 + .type = WRITER_MODULE,
14272 + .name = "Swap Allocator",
14273 + .directory = "swap",
14274 + .module = THIS_MODULE,
14275 + .memory_needed = suspend_swap_memory_needed,
14276 + .print_debug_info = suspend_swap_print_debug_stats,
14277 + .storage_needed = suspend_swap_storage_needed,
14278 + .initialise = suspend_swap_initialise,
14279 + .cleanup = suspend_swap_cleanup,
14280 +
14281 + .noresume_reset = suspend_swap_noresume_reset,
14282 + .storage_available = suspend_swap_storage_available,
14283 + .storage_allocated = suspend_swap_storage_allocated,
14284 + .release_storage = suspend_swap_release_storage,
14285 + .allocate_header_space = suspend_swap_allocate_header_space,
14286 + .allocate_storage = suspend_swap_allocate_storage,
14287 + .image_exists = suspend_swap_image_exists,
14288 + .mark_resume_attempted = suspend_swap_mark_resume_attempted,
14289 + .write_header_init = suspend_swap_write_header_init,
14290 + .write_header_cleanup = suspend_swap_write_header_cleanup,
14291 + .read_header_init = suspend_swap_read_header_init,
14292 + .read_header_cleanup = suspend_swap_read_header_cleanup,
14293 + .invalidate_image = suspend_swap_invalidate_image,
14294 + .parse_sig_location = suspend_swap_parse_sig_location,
14295 +
14296 + .sysfs_data = sysfs_params,
14297 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
14298 +};
14299 +
14300 +/* ---- Registration ---- */
14301 +static __init int suspend_swap_load(void)
14302 +{
14303 + suspend_swapops.rw_init = suspend_bio_ops.rw_init;
14304 + suspend_swapops.rw_cleanup = suspend_bio_ops.rw_cleanup;
14305 + suspend_swapops.read_chunk = suspend_bio_ops.read_chunk;
14306 + suspend_swapops.write_chunk = suspend_bio_ops.write_chunk;
14307 + suspend_swapops.rw_header_chunk = suspend_bio_ops.rw_header_chunk;
14308 +
14309 + return suspend_register_module(&suspend_swapops);
14310 +}
14311 +
14312 +#ifdef MODULE
14313 +static __exit void suspend_swap_unload(void)
14314 +{
14315 + suspend_unregister_module(&suspend_swapops);
14316 +}
14317 +
14318 +module_init(suspend_swap_load);
14319 +module_exit(suspend_swap_unload);
14320 +MODULE_LICENSE("GPL");
14321 +MODULE_AUTHOR("Nigel Cunningham");
14322 +MODULE_DESCRIPTION("Suspend2 SwapAllocator");
14323 +#else
14324 +late_initcall(suspend_swap_load);
14325 +#endif
14326 diff -Naur linux-2.6.21-ck2/kernel/power/suspend_userui.c linux-2.6.21-magellan-r11/kernel/power/suspend_userui.c
14327 --- linux-2.6.21-ck2/kernel/power/suspend_userui.c 1970-01-01 01:00:00.000000000 +0100
14328 +++ linux-2.6.21-magellan-r11/kernel/power/suspend_userui.c 2007-08-17 15:57:25.000000000 +0200
14329 @@ -0,0 +1,649 @@
14330 +/*
14331 + * kernel/power/user_ui.c
14332 + *
14333 + * Copyright (C) 2005-2007 Bernard Blackham
14334 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
14335 + *
14336 + * This file is released under the GPLv2.
14337 + *
14338 + * Routines for Suspend2's user interface.
14339 + *
14340 + * The user interface code talks to a userspace program via a
14341 + * netlink socket.
14342 + *
14343 + * The kernel side:
14344 + * - starts the userui program;
14345 + * - sends text messages and progress bar status;
14346 + *
14347 + * The user space side:
14348 + * - passes messages regarding user requests (abort, toggle reboot etc)
14349 + *
14350 + */
14351 +
14352 +#define __KERNEL_SYSCALLS__
14353 +
14354 +#include <linux/suspend.h>
14355 +#include <linux/freezer.h>
14356 +#include <linux/console.h>
14357 +#include <linux/ctype.h>
14358 +#include <linux/tty.h>
14359 +#include <linux/vt_kern.h>
14360 +#include <linux/module.h>
14361 +#include <linux/reboot.h>
14362 +#include <linux/kmod.h>
14363 +#include <linux/security.h>
14364 +#include <linux/syscalls.h>
14365 +
14366 +#include "sysfs.h"
14367 +#include "modules.h"
14368 +#include "suspend.h"
14369 +#include "ui.h"
14370 +#include "netlink.h"
14371 +#include "power_off.h"
14372 +
14373 +static char local_printf_buf[1024]; /* Same as printk - should be safe */
14374 +
14375 +static struct user_helper_data ui_helper_data;
14376 +static struct suspend_module_ops userui_ops;
14377 +static int orig_kmsg;
14378 +
14379 +static char lastheader[512];
14380 +static int lastheader_message_len;
14381 +static int ui_helper_changed; /* Used at resume-time so don't overwrite value
14382 + set from initrd/ramfs. */
14383 +
14384 +/* Number of distinct progress amounts that userspace can display */
14385 +static int progress_granularity = 30;
14386 +
14387 +DECLARE_WAIT_QUEUE_HEAD(userui_wait_for_key);
14388 +
14389 +static void ui_nl_set_state(int n)
14390 +{
14391 + /* Only let them change certain settings */
14392 + static const int suspend_action_mask =
14393 + (1 << SUSPEND_REBOOT) | (1 << SUSPEND_PAUSE) | (1 << SUSPEND_SLOW) |
14394 + (1 << SUSPEND_LOGALL) | (1 << SUSPEND_SINGLESTEP) |
14395 + (1 << SUSPEND_PAUSE_NEAR_PAGESET_END);
14396 +
14397 + suspend_action = (suspend_action & (~suspend_action_mask)) |
14398 + (n & suspend_action_mask);
14399 +
14400 + if (!test_action_state(SUSPEND_PAUSE) &&
14401 + !test_action_state(SUSPEND_SINGLESTEP))
14402 + wake_up_interruptible(&userui_wait_for_key);
14403 +}
14404 +
14405 +static void userui_post_atomic_restore(void)
14406 +{
14407 + suspend_send_netlink_message(&ui_helper_data,
14408 + USERUI_MSG_POST_ATOMIC_RESTORE, NULL, 0);
14409 +}
14410 +
14411 +static int userui_storage_needed(void)
14412 +{
14413 + return sizeof(ui_helper_data.program) + 1 + sizeof(int);
14414 +}
14415 +
14416 +static int userui_save_config_info(char *buf)
14417 +{
14418 + *((int *) buf) = progress_granularity;
14419 + memcpy(buf + sizeof(int), ui_helper_data.program, sizeof(ui_helper_data.program));
14420 + return sizeof(ui_helper_data.program) + sizeof(int) + 1;
14421 +}
14422 +
14423 +static void userui_load_config_info(char *buf, int size)
14424 +{
14425 + progress_granularity = *((int *) buf);
14426 + size -= sizeof(int);
14427 +
14428 + /* Don't load the saved path if one has already been set */
14429 + if (ui_helper_changed)
14430 + return;
14431 +
14432 + if (size > sizeof(ui_helper_data.program))
14433 + size = sizeof(ui_helper_data.program);
14434 +
14435 + memcpy(ui_helper_data.program, buf + sizeof(int), size);
14436 + ui_helper_data.program[sizeof(ui_helper_data.program)-1] = '\0';
14437 +}
14438 +
14439 +static void set_ui_program_set(void)
14440 +{
14441 + ui_helper_changed = 1;
14442 +}
14443 +
14444 +static int userui_memory_needed(void)
14445 +{
14446 + /* ball park figure of 128 pages */
14447 + return (128 * PAGE_SIZE);
14448 +}
14449 +
14450 +/* suspend_update_status
14451 + *
14452 + * Description: Update the progress bar and (if on) in-bar message.
14453 + * Arguments: UL value, maximum: Current progress percentage (value/max).
14454 + * const char *fmt, ...: Message to be displayed in the middle
14455 + * of the progress bar.
14456 + * Note that a NULL message does not mean that any previous
14457 + * message is erased! For that, you need suspend_prepare_status with
14458 + * clearbar on.
14459 + * Returns: Unsigned long: The next value where status needs to be updated.
14460 + * This is to reduce unnecessary calls to update_status.
14461 + */
14462 +static unsigned long userui_update_status(unsigned long value,
14463 + unsigned long maximum, const char *fmt, ...)
14464 +{
14465 + static int last_step = -1;
14466 + struct userui_msg_params msg;
14467 + int bitshift;
14468 + int this_step;
14469 + unsigned long next_update;
14470 +
14471 + if (ui_helper_data.pid == -1)
14472 + return 0;
14473 +
14474 + if ((!maximum) || (!progress_granularity))
14475 + return maximum;
14476 +
14477 + if (value < 0)
14478 + value = 0;
14479 +
14480 + if (value > maximum)
14481 + value = maximum;
14482 +
14483 + /* Try to avoid math problems - we can't do 64 bit math here
14484 + * (and shouldn't need it - anyone got screen resolution
14485 + * of 65536 pixels or more?) */
14486 + bitshift = fls(maximum) - 16;
14487 + if (bitshift > 0) {
14488 + unsigned long temp_maximum = maximum >> bitshift;
14489 + unsigned long temp_value = value >> bitshift;
14490 + this_step = (int)
14491 + (temp_value * progress_granularity / temp_maximum);
14492 + next_update = (((this_step + 1) * temp_maximum /
14493 + progress_granularity) + 1) << bitshift;
14494 + } else {
14495 + this_step = (int) (value * progress_granularity / maximum);
14496 + next_update = ((this_step + 1) * maximum /
14497 + progress_granularity) + 1;
14498 + }
14499 +
14500 + if (this_step == last_step)
14501 + return next_update;
14502 +
14503 + memset(&msg, 0, sizeof(msg));
14504 +
14505 + msg.a = this_step;
14506 + msg.b = progress_granularity;
14507 +
14508 + if (fmt) {
14509 + va_list args;
14510 + va_start(args, fmt);
14511 + vsnprintf(msg.text, sizeof(msg.text), fmt, args);
14512 + va_end(args);
14513 + msg.text[sizeof(msg.text)-1] = '\0';
14514 + }
14515 +
14516 + suspend_send_netlink_message(&ui_helper_data, USERUI_MSG_PROGRESS,
14517 + &msg, sizeof(msg));
14518 + last_step = this_step;
14519 +
14520 + return next_update;
14521 +}
14522 +
14523 +/* userui_message.
14524 + *
14525 + * Description: This function is intended to do the same job as printk, but
14526 + * without normally logging what is printed. The point is to be
14527 + * able to get debugging info on screen without filling the logs
14528 + * with "1/534. ^M 2/534^M. 3/534^M"
14529 + *
14530 + * It may be called from an interrupt context - can't sleep!
14531 + *
14532 + * Arguments: int mask: The debugging section(s) this message belongs to.
14533 + * int level: The level of verbosity of this message.
14534 + * int restartline: Whether to output a \r or \n with this line
14535 + * (\n if we're logging all output).
14536 + * const char *fmt, ...: Message to be displayed a la printk.
14537 + */
14538 +static void userui_message(unsigned long section, unsigned long level,
14539 + int normally_logged, const char *fmt, ...)
14540 +{
14541 + struct userui_msg_params msg;
14542 +
14543 + if ((level) && (level > console_loglevel))
14544 + return;
14545 +
14546 + memset(&msg, 0, sizeof(msg));
14547 +
14548 + msg.a = section;
14549 + msg.b = level;
14550 + msg.c = normally_logged;
14551 +
14552 + if (fmt) {
14553 + va_list args;
14554 + va_start(args, fmt);
14555 + vsnprintf(msg.text, sizeof(msg.text), fmt, args);
14556 + va_end(args);
14557 + msg.text[sizeof(msg.text)-1] = '\0';
14558 + }
14559 +
14560 + if (test_action_state(SUSPEND_LOGALL))
14561 + printk("%s\n", msg.text);
14562 +
14563 + suspend_send_netlink_message(&ui_helper_data, USERUI_MSG_MESSAGE,
14564 + &msg, sizeof(msg));
14565 +}
14566 +
14567 +static void wait_for_key_via_userui(void)
14568 +{
14569 + DECLARE_WAITQUEUE(wait, current);
14570 +
14571 + add_wait_queue(&userui_wait_for_key, &wait);
14572 + set_current_state(TASK_INTERRUPTIBLE);
14573 +
14574 + interruptible_sleep_on(&userui_wait_for_key);
14575 +
14576 + set_current_state(TASK_RUNNING);
14577 + remove_wait_queue(&userui_wait_for_key, &wait);
14578 +}
14579 +
14580 +static char userui_wait_for_keypress(int timeout)
14581 +{
14582 + int fd;
14583 + char key = '\0';
14584 + struct termios t, t_backup;
14585 +
14586 + if (ui_helper_data.pid != -1) {
14587 + wait_for_key_via_userui();
14588 + key = ' ';
14589 + goto out;
14590 + }
14591 +
14592 + /* We should be guaranteed /dev/console exists after populate_rootfs() in
14593 + * init/main.c
14594 + */
14595 + if ((fd = sys_open("/dev/console", O_RDONLY, 0)) < 0) {
14596 + printk("Couldn't open /dev/console.\n");
14597 + goto out;
14598 + }
14599 +
14600 + if (sys_ioctl(fd, TCGETS, (long)&t) < 0)
14601 + goto out_close;
14602 +
14603 + memcpy(&t_backup, &t, sizeof(t));
14604 +
14605 + t.c_lflag &= ~(ISIG|ICANON|ECHO);
14606 + t.c_cc[VMIN] = 0;
14607 + if (timeout)
14608 + t.c_cc[VTIME] = timeout*10;
14609 +
14610 + if (sys_ioctl(fd, TCSETS, (long)&t) < 0)
14611 + goto out_restore;
14612 +
14613 + while (1) {
14614 + if (sys_read(fd, &key, 1) <= 0) {
14615 + key = '\0';
14616 + break;
14617 + }
14618 + key = tolower(key);
14619 + if (test_suspend_state(SUSPEND_SANITY_CHECK_PROMPT)) {
14620 + if (key == 'c') {
14621 + set_suspend_state(SUSPEND_CONTINUE_REQ);
14622 + break;
14623 + } else if (key == ' ')
14624 + break;
14625 + } else
14626 + break;
14627 + }
14628 +
14629 +out_restore:
14630 + sys_ioctl(fd, TCSETS, (long)&t_backup);
14631 +out_close:
14632 + sys_close(fd);
14633 +out:
14634 + return key;
14635 +}
14636 +
14637 +/* suspend_prepare_status
14638 + * Description: Prepare the 'nice display', drawing the header and version,
14639 + * along with the current action and perhaps also resetting the
14640 + * progress bar.
14641 + * Arguments:
14642 + * int clearbar: Whether to reset the progress bar.
14643 + * const char *fmt, ...: The action to be displayed.
14644 + */
14645 +static void userui_prepare_status(int clearbar, const char *fmt, ...)
14646 +{
14647 + va_list args;
14648 +
14649 + if (fmt) {
14650 + va_start(args, fmt);
14651 + lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
14652 + va_end(args);
14653 + }
14654 +
14655 + if (clearbar)
14656 + suspend_update_status(0, 1, NULL);
14657 +
14658 + suspend_message(0, SUSPEND_STATUS, 1, lastheader, NULL);
14659 +
14660 + if (ui_helper_data.pid == -1)
14661 + printk(KERN_EMERG "%s\n", lastheader);
14662 +}
14663 +
14664 +/* abort_suspend
14665 + *
14666 + * Description: Begin to abort a cycle. If this wasn't at the user's request
14667 + * (and we're displaying output), tell the user why and wait for
14668 + * them to acknowledge the message.
14669 + * Arguments: A parameterised string (imagine this is printk) to display,
14670 + * telling the user why we're aborting.
14671 + */
14672 +
14673 +static void userui_abort_suspend(int result_code, const char *fmt, ...)
14674 +{
14675 + va_list args;
14676 + int printed_len = 0;
14677 +
14678 + set_result_state(result_code);
14679 + if (!test_result_state(SUSPEND_ABORTED)) {
14680 + if (!test_result_state(SUSPEND_ABORT_REQUESTED)) {
14681 + va_start(args, fmt);
14682 + printed_len = vsnprintf(local_printf_buf,
14683 + sizeof(local_printf_buf), fmt, args);
14684 + va_end(args);
14685 + if (ui_helper_data.pid != -1)
14686 + printed_len = sprintf(local_printf_buf + printed_len,
14687 + " (Press SPACE to continue)");
14688 + suspend_prepare_status(CLEAR_BAR, local_printf_buf);
14689 +
14690 + if (ui_helper_data.pid != -1)
14691 + suspend_wait_for_keypress(0);
14692 + }
14693 + /* Turn on aborting flag */
14694 + set_result_state(SUSPEND_ABORTED);
14695 + }
14696 +}
14697 +
14698 +/* request_abort_suspend
14699 + *
14700 + * Description: Handle the user requesting the cancellation of a suspend by
14701 + * pressing escape.
14702 + * Callers: Invoked from a netlink packet from userspace when the user presses
14703 + * escape.
14704 + */
14705 +static void request_abort_suspend(void)
14706 +{
14707 + if (test_result_state(SUSPEND_ABORT_REQUESTED))
14708 + return;
14709 +
14710 + if (test_suspend_state(SUSPEND_NOW_RESUMING)) {
14711 + suspend_prepare_status(CLEAR_BAR, "Escape pressed. "
14712 + "Powering down again.");
14713 + set_suspend_state(SUSPEND_STOP_RESUME);
14714 + while (!test_suspend_state(SUSPEND_IO_STOPPED))
14715 + schedule();
14716 + if (suspendActiveAllocator->mark_resume_attempted)
14717 + suspendActiveAllocator->mark_resume_attempted(0);
14718 + suspend2_power_down();
14719 + } else {
14720 + suspend_prepare_status(CLEAR_BAR, "--- ESCAPE PRESSED :"
14721 + " ABORTING SUSPEND ---");
14722 + set_result_state(SUSPEND_ABORTED);
14723 + set_result_state(SUSPEND_ABORT_REQUESTED);
14724 +
14725 + wake_up_interruptible(&userui_wait_for_key);
14726 + }
14727 +}
14728 +
14729 +static int userui_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
14730 +{
14731 + int type;
14732 + int *data;
14733 +
14734 + type = nlh->nlmsg_type;
14735 +
14736 + /* A control message: ignore them */
14737 + if (type < NETLINK_MSG_BASE)
14738 + return 0;
14739 +
14740 + /* Unknown message: reply with EINVAL */
14741 + if (type >= USERUI_MSG_MAX)
14742 + return -EINVAL;
14743 +
14744 + /* All operations require privileges, even GET */
14745 + if (security_netlink_recv(skb, CAP_NET_ADMIN))
14746 + return -EPERM;
14747 +
14748 + /* Only allow one task to receive NOFREEZE privileges */
14749 + if (type == NETLINK_MSG_NOFREEZE_ME && ui_helper_data.pid != -1) {
14750 + printk("Got NOFREEZE_ME request when ui_helper_data.pid is %d.\n", ui_helper_data.pid);
14751 + return -EBUSY;
14752 + }
14753 +
14754 + data = (int*)NLMSG_DATA(nlh);
14755 +
14756 + switch (type) {
14757 + case USERUI_MSG_ABORT:
14758 + request_abort_suspend();
14759 + break;
14760 + case USERUI_MSG_GET_STATE:
14761 + suspend_send_netlink_message(&ui_helper_data,
14762 + USERUI_MSG_GET_STATE, &suspend_action,
14763 + sizeof(suspend_action));
14764 + break;
14765 + case USERUI_MSG_GET_DEBUG_STATE:
14766 + suspend_send_netlink_message(&ui_helper_data,
14767 + USERUI_MSG_GET_DEBUG_STATE,
14768 + &suspend_debug_state,
14769 + sizeof(suspend_debug_state));
14770 + break;
14771 + case USERUI_MSG_SET_STATE:
14772 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14773 + return -EINVAL;
14774 + ui_nl_set_state(*data);
14775 + break;
14776 + case USERUI_MSG_SET_DEBUG_STATE:
14777 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14778 + return -EINVAL;
14779 + suspend_debug_state = (*data);
14780 + break;
14781 + case USERUI_MSG_SPACE:
14782 + wake_up_interruptible(&userui_wait_for_key);
14783 + break;
14784 + case USERUI_MSG_GET_POWERDOWN_METHOD:
14785 + suspend_send_netlink_message(&ui_helper_data,
14786 + USERUI_MSG_GET_POWERDOWN_METHOD,
14787 + &suspend2_poweroff_method,
14788 + sizeof(suspend2_poweroff_method));
14789 + break;
14790 + case USERUI_MSG_SET_POWERDOWN_METHOD:
14791 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14792 + return -EINVAL;
14793 + suspend2_poweroff_method = (*data);
14794 + break;
14795 + case USERUI_MSG_GET_LOGLEVEL:
14796 + suspend_send_netlink_message(&ui_helper_data,
14797 + USERUI_MSG_GET_LOGLEVEL,
14798 + &suspend_default_console_level,
14799 + sizeof(suspend_default_console_level));
14800 + break;
14801 + case USERUI_MSG_SET_LOGLEVEL:
14802 + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
14803 + return -EINVAL;
14804 + suspend_default_console_level = (*data);
14805 + break;
14806 + }
14807 +
14808 + return 1;
14809 +}
14810 +
14811 +/* userui_cond_pause
14812 + *
14813 + * Description: Potentially pause and wait for the user to tell us to continue.
14814 + * We normally only pause when @pause is set.
14815 + * Arguments: int pause: Whether we normally pause.
14816 + * char *message: The message to display. Not parameterised
14817 + * because it's normally a constant.
14818 + */
14819 +
14820 +static void userui_cond_pause(int pause, char *message)
14821 +{
14822 + int displayed_message = 0, last_key = 0;
14823 +
14824 + while (last_key != 32 &&
14825 + ui_helper_data.pid != -1 &&
14826 + (!test_result_state(SUSPEND_ABORTED)) &&
14827 + ((test_action_state(SUSPEND_PAUSE) && pause) ||
14828 + (test_action_state(SUSPEND_SINGLESTEP)))) {
14829 + if (!displayed_message) {
14830 + suspend_prepare_status(DONT_CLEAR_BAR,
14831 + "%s Press SPACE to continue.%s",
14832 + message ? message : "",
14833 + (test_action_state(SUSPEND_SINGLESTEP)) ?
14834 + " Single step on." : "");
14835 + displayed_message = 1;
14836 + }
14837 + last_key = suspend_wait_for_keypress(0);
14838 + }
14839 + schedule();
14840 +}
14841 +
14842 +/* userui_prepare_console
14843 + *
14844 + * Description: Prepare a console for use, save current settings.
14845 + * Returns: Boolean: Whether an error occured. Errors aren't
14846 + * treated as fatal, but a warning is printed.
14847 + */
14848 +static void userui_prepare_console(void)
14849 +{
14850 + orig_kmsg = kmsg_redirect;
14851 + kmsg_redirect = fg_console + 1;
14852 +
14853 + ui_helper_data.pid = -1;
14854 +
14855 + if (!userui_ops.enabled)
14856 + return;
14857 +
14858 + if (!*ui_helper_data.program) {
14859 + printk("suspend_userui: program not configured. suspend_userui disabled.\n");
14860 + return;
14861 + }
14862 +
14863 + suspend_netlink_setup(&ui_helper_data);
14864 +
14865 + return;
14866 +}
14867 +
14868 +/* userui_cleanup_console
14869 + *
14870 + * Description: Restore the settings we saved above.
14871 + */
14872 +
14873 +static void userui_cleanup_console(void)
14874 +{
14875 + if (ui_helper_data.pid > -1)
14876 + suspend_netlink_close(&ui_helper_data);
14877 +
14878 + kmsg_redirect = orig_kmsg;
14879 +}
14880 +
14881 +/*
14882 + * User interface specific /sys/power/suspend2 entries.
14883 + */
14884 +
14885 +static struct suspend_sysfs_data sysfs_params[] = {
14886 +#if defined(CONFIG_NET) && defined(CONFIG_SYSFS)
14887 + { SUSPEND2_ATTR("enable_escape", SYSFS_RW),
14888 + SYSFS_BIT(&suspend_action, SUSPEND_CAN_CANCEL, 0)
14889 + },
14890 +
14891 + { SUSPEND2_ATTR("pause_between_steps", SYSFS_RW),
14892 + SYSFS_BIT(&suspend_action, SUSPEND_PAUSE, 0)
14893 + },
14894 +
14895 + { SUSPEND2_ATTR("enabled", SYSFS_RW),
14896 + SYSFS_INT(&userui_ops.enabled, 0, 1, 0)
14897 + },
14898 +
14899 + { SUSPEND2_ATTR("progress_granularity", SYSFS_RW),
14900 + SYSFS_INT(&progress_granularity, 1, 2048, 0)
14901 + },
14902 +
14903 + { SUSPEND2_ATTR("program", SYSFS_RW),
14904 + SYSFS_STRING(ui_helper_data.program, 255, 0),
14905 + .write_side_effect = set_ui_program_set,
14906 + },
14907 +#endif
14908 +};
14909 +
14910 +static struct suspend_module_ops userui_ops = {
14911 + .type = MISC_MODULE,
14912 + .name = "Userspace UI",
14913 + .shared_directory = "Basic User Interface",
14914 + .module = THIS_MODULE,
14915 + .storage_needed = userui_storage_needed,
14916 + .save_config_info = userui_save_config_info,
14917 + .load_config_info = userui_load_config_info,
14918 + .memory_needed = userui_memory_needed,
14919 + .sysfs_data = sysfs_params,
14920 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
14921 +};
14922 +
14923 +static struct ui_ops my_ui_ops = {
14924 + .post_atomic_restore = userui_post_atomic_restore,
14925 + .update_status = userui_update_status,
14926 + .message = userui_message,
14927 + .prepare_status = userui_prepare_status,
14928 + .abort = userui_abort_suspend,
14929 + .cond_pause = userui_cond_pause,
14930 + .prepare = userui_prepare_console,
14931 + .cleanup = userui_cleanup_console,
14932 + .wait_for_key = userui_wait_for_keypress,
14933 +};
14934 +
14935 +/* suspend_console_sysfs_init
14936 + * Description: Boot time initialisation for user interface.
14937 + */
14938 +
14939 +static __init int s2_user_ui_init(void)
14940 +{
14941 + int result;
14942 +
14943 + ui_helper_data.nl = NULL;
14944 + ui_helper_data.program[0] = '\0';
14945 + ui_helper_data.pid = -1;
14946 + ui_helper_data.skb_size = sizeof(struct userui_msg_params);
14947 + ui_helper_data.pool_limit = 6;
14948 + ui_helper_data.netlink_id = NETLINK_SUSPEND2_USERUI;
14949 + ui_helper_data.name = "userspace ui";
14950 + ui_helper_data.rcv_msg = userui_user_rcv_msg;
14951 + ui_helper_data.interface_version = 7;
14952 + ui_helper_data.must_init = 0;
14953 + ui_helper_data.not_ready = userui_cleanup_console;
14954 + init_completion(&ui_helper_data.wait_for_process);
14955 + result = suspend_register_module(&userui_ops);
14956 + if (!result)
14957 + result = s2_register_ui_ops(&my_ui_ops);
14958 + if (result)
14959 + suspend_unregister_module(&userui_ops);
14960 +
14961 + return result;
14962 +}
14963 +
14964 +#ifdef MODULE
14965 +static __exit void s2_user_ui_exit(void)
14966 +{
14967 + s2_remove_ui_ops(&my_ui_ops);
14968 + suspend_unregister_module(&userui_ops);
14969 +}
14970 +
14971 +module_init(s2_user_ui_init);
14972 +module_exit(s2_user_ui_exit);
14973 +MODULE_AUTHOR("Nigel Cunningham");
14974 +MODULE_DESCRIPTION("Suspend2 Userui Support");
14975 +MODULE_LICENSE("GPL");
14976 +#else
14977 +late_initcall(s2_user_ui_init);
14978 +#endif
14979 diff -Naur linux-2.6.21-ck2/kernel/power/sysfs.c linux-2.6.21-magellan-r11/kernel/power/sysfs.c
14980 --- linux-2.6.21-ck2/kernel/power/sysfs.c 1970-01-01 01:00:00.000000000 +0100
14981 +++ linux-2.6.21-magellan-r11/kernel/power/sysfs.c 2007-08-17 15:57:25.000000000 +0200
14982 @@ -0,0 +1,347 @@
14983 +/*
14984 + * kernel/power/sysfs.c
14985 + *
14986 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
14987 + *
14988 + * This file is released under the GPLv2.
14989 + *
14990 + * This file contains support for sysfs entries for tuning Suspend2.
14991 + *
14992 + * We have a generic handler that deals with the most common cases, and
14993 + * hooks for special handlers to use.
14994 + */
14995 +
14996 +#include <linux/suspend.h>
14997 +#include <linux/module.h>
14998 +#include <asm/uaccess.h>
14999 +
15000 +#include "sysfs.h"
15001 +#include "suspend.h"
15002 +#include "storage.h"
15003 +
15004 +static int suspend_sysfs_initialised = 0;
15005 +
15006 +static void suspend_initialise_sysfs(void);
15007 +
15008 +static struct suspend_sysfs_data sysfs_params[];
15009 +
15010 +#define to_sysfs_data(_attr) container_of(_attr, struct suspend_sysfs_data, attr)
15011 +
15012 +static void suspend2_main_wrapper(void)
15013 +{
15014 + _suspend2_try_suspend(0);
15015 +}
15016 +
15017 +static ssize_t suspend2_attr_show(struct kobject *kobj, struct attribute *attr,
15018 + char *page)
15019 +{
15020 + struct suspend_sysfs_data *sysfs_data = to_sysfs_data(attr);
15021 + int len = 0;
15022 +
15023 + if (suspend_start_anything(0))
15024 + return -EBUSY;
15025 +
15026 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_READ)
15027 + suspend_prepare_usm();
15028 +
15029 + switch (sysfs_data->type) {
15030 + case SUSPEND_SYSFS_DATA_CUSTOM:
15031 + len = (sysfs_data->data.special.read_sysfs) ?
15032 + (sysfs_data->data.special.read_sysfs)(page, PAGE_SIZE)
15033 + : 0;
15034 + break;
15035 + case SUSPEND_SYSFS_DATA_BIT:
15036 + len = sprintf(page, "%d\n",
15037 + -test_bit(sysfs_data->data.bit.bit,
15038 + sysfs_data->data.bit.bit_vector));
15039 + break;
15040 + case SUSPEND_SYSFS_DATA_INTEGER:
15041 + len = sprintf(page, "%d\n",
15042 + *(sysfs_data->data.integer.variable));
15043 + break;
15044 + case SUSPEND_SYSFS_DATA_LONG:
15045 + len = sprintf(page, "%ld\n",
15046 + *(sysfs_data->data.a_long.variable));
15047 + break;
15048 + case SUSPEND_SYSFS_DATA_UL:
15049 + len = sprintf(page, "%lu\n",
15050 + *(sysfs_data->data.ul.variable));
15051 + break;
15052 + case SUSPEND_SYSFS_DATA_STRING:
15053 + len = sprintf(page, "%s\n",
15054 + sysfs_data->data.string.variable);
15055 + break;
15056 + }
15057 + /* Side effect routine? */
15058 + if (sysfs_data->read_side_effect)
15059 + sysfs_data->read_side_effect();
15060 +
15061 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_READ)
15062 + suspend_cleanup_usm();
15063 +
15064 + suspend_finish_anything(0);
15065 +
15066 + return len;
15067 +}
15068 +
15069 +#define BOUND(_variable, _type) \
15070 + if (*_variable < sysfs_data->data._type.minimum) \
15071 + *_variable = sysfs_data->data._type.minimum; \
15072 + else if (*_variable > sysfs_data->data._type.maximum) \
15073 + *_variable = sysfs_data->data._type.maximum;
15074 +
15075 +static ssize_t suspend2_attr_store(struct kobject *kobj, struct attribute *attr,
15076 + const char *my_buf, size_t count)
15077 +{
15078 + int assigned_temp_buffer = 0, result = count;
15079 + struct suspend_sysfs_data *sysfs_data = to_sysfs_data(attr);
15080 +
15081 + if (suspend_start_anything((sysfs_data->flags & SYSFS_SUSPEND_OR_RESUME)))
15082 + return -EBUSY;
15083 +
15084 + ((char *) my_buf)[count] = 0;
15085 +
15086 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_WRITE)
15087 + suspend_prepare_usm();
15088 +
15089 + switch (sysfs_data->type) {
15090 + case SUSPEND_SYSFS_DATA_CUSTOM:
15091 + if (sysfs_data->data.special.write_sysfs)
15092 + result = (sysfs_data->data.special.write_sysfs)
15093 + (my_buf, count);
15094 + break;
15095 + case SUSPEND_SYSFS_DATA_BIT:
15096 + {
15097 + int value = simple_strtoul(my_buf, NULL, 0);
15098 + if (value)
15099 + set_bit(sysfs_data->data.bit.bit,
15100 + (sysfs_data->data.bit.bit_vector));
15101 + else
15102 + clear_bit(sysfs_data->data.bit.bit,
15103 + (sysfs_data->data.bit.bit_vector));
15104 + }
15105 + break;
15106 + case SUSPEND_SYSFS_DATA_INTEGER:
15107 + {
15108 + int *variable = sysfs_data->data.integer.variable;
15109 + *variable = simple_strtol(my_buf, NULL, 0);
15110 + BOUND(variable, integer);
15111 + break;
15112 + }
15113 + case SUSPEND_SYSFS_DATA_LONG:
15114 + {
15115 + long *variable = sysfs_data->data.a_long.variable;
15116 + *variable = simple_strtol(my_buf, NULL, 0);
15117 + BOUND(variable, a_long);
15118 + break;
15119 + }
15120 + case SUSPEND_SYSFS_DATA_UL:
15121 + {
15122 + unsigned long *variable = sysfs_data->data.ul.variable;
15123 + *variable = simple_strtoul(my_buf, NULL, 0);
15124 + BOUND(variable, ul);
15125 + break;
15126 + }
15127 + break;
15128 + case SUSPEND_SYSFS_DATA_STRING:
15129 + {
15130 + int copy_len = count;
15131 + char *variable =
15132 + sysfs_data->data.string.variable;
15133 +
15134 + if (sysfs_data->data.string.max_length &&
15135 + (copy_len > sysfs_data->data.string.max_length))
15136 + copy_len = sysfs_data->data.string.max_length;
15137 +
15138 + if (!variable) {
15139 + sysfs_data->data.string.variable =
15140 + variable = (char *) get_zeroed_page(GFP_ATOMIC);
15141 + assigned_temp_buffer = 1;
15142 + }
15143 + strncpy(variable, my_buf, copy_len);
15144 + if ((copy_len) &&
15145 + (my_buf[copy_len - 1] == '\n'))
15146 + variable[count - 1] = 0;
15147 + variable[count] = 0;
15148 + }
15149 + break;
15150 + }
15151 +
15152 + /* Side effect routine? */
15153 + if (sysfs_data->write_side_effect)
15154 + sysfs_data->write_side_effect();
15155 +
15156 + /* Free temporary buffers */
15157 + if (assigned_temp_buffer) {
15158 + free_page((unsigned long) sysfs_data->data.string.variable);
15159 + sysfs_data->data.string.variable = NULL;
15160 + }
15161 +
15162 + if (sysfs_data->flags & SYSFS_NEEDS_SM_FOR_WRITE)
15163 + suspend_cleanup_usm();
15164 +
15165 + suspend_finish_anything(sysfs_data->flags & SYSFS_SUSPEND_OR_RESUME);
15166 +
15167 + return result;
15168 +}
15169 +
15170 +static struct sysfs_ops suspend2_sysfs_ops = {
15171 + .show = &suspend2_attr_show,
15172 + .store = &suspend2_attr_store,
15173 +};
15174 +
15175 +static struct kobj_type suspend2_ktype = {
15176 + .sysfs_ops = &suspend2_sysfs_ops,
15177 +};
15178 +
15179 +decl_subsys(suspend2, &suspend2_ktype, NULL);
15180 +
15181 +/* Non-module sysfs entries.
15182 + *
15183 + * This array contains entries that are automatically registered at
15184 + * boot. Modules and the console code register their own entries separately.
15185 + *
15186 + * NB: If you move do_suspend, change suspend_write_sysfs's test so that
15187 + * suspend_start_anything still gets a 1 when the user echos > do_suspend!
15188 + */
15189 +
15190 +static struct suspend_sysfs_data sysfs_params[] = {
15191 + { SUSPEND2_ATTR("do_suspend", SYSFS_WRITEONLY),
15192 + SYSFS_CUSTOM(NULL, NULL, SYSFS_SUSPENDING),
15193 + .write_side_effect = suspend2_main_wrapper
15194 + },
15195 +
15196 + { SUSPEND2_ATTR("do_resume", SYSFS_WRITEONLY),
15197 + SYSFS_CUSTOM(NULL, NULL, SYSFS_RESUMING),
15198 + .write_side_effect = __suspend2_try_resume
15199 + },
15200 +
15201 +};
15202 +
15203 +void remove_suspend2_sysdir(struct kobject *kobj)
15204 +{
15205 + if (!kobj)
15206 + return;
15207 +
15208 + kobject_unregister(kobj);
15209 +
15210 + kfree(kobj);
15211 +}
15212 +
15213 +struct kobject *make_suspend2_sysdir(char *name)
15214 +{
15215 + struct kobject *kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
15216 + int err;
15217 +
15218 + if(!kobj) {
15219 + printk("Suspend2: Can't allocate kobject for sysfs dir!\n");
15220 + return NULL;
15221 + }
15222 +
15223 + err = kobject_set_name(kobj, "%s", name);
15224 +
15225 + if (err) {
15226 + kfree(kobj);
15227 + return NULL;
15228 + }
15229 +
15230 + kobj->kset = &suspend2_subsys.kset;
15231 +
15232 + err = kobject_register(kobj);
15233 +
15234 + if (err)
15235 + kfree(kobj);
15236 +
15237 + return err ? NULL : kobj;
15238 +}
15239 +
15240 +/* suspend_register_sysfs_file
15241 + *
15242 + * Helper for registering a new /sysfs/suspend2 entry.
15243 + */
15244 +
15245 +int suspend_register_sysfs_file(
15246 + struct kobject *kobj,
15247 + struct suspend_sysfs_data *suspend_sysfs_data)
15248 +{
15249 + int result;
15250 +
15251 + if (!suspend_sysfs_initialised)
15252 + suspend_initialise_sysfs();
15253 +
15254 + if ((result = sysfs_create_file(kobj, &suspend_sysfs_data->attr)))
15255 + printk("Suspend2: sysfs_create_file for %s returned %d.\n",
15256 + suspend_sysfs_data->attr.name, result);
15257 +
15258 + return result;
15259 +}
15260 +
15261 +/* suspend_unregister_sysfs_file
15262 + *
15263 + * Helper for removing unwanted /sys/power/suspend2 entries.
15264 + *
15265 + */
15266 +void suspend_unregister_sysfs_file(struct kobject *kobj,
15267 + struct suspend_sysfs_data *suspend_sysfs_data)
15268 +{
15269 + sysfs_remove_file(kobj, &suspend_sysfs_data->attr);
15270 +}
15271 +
15272 +void suspend_cleanup_sysfs(void)
15273 +{
15274 + int i,
15275 + numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
15276 +
15277 + if (!suspend_sysfs_initialised)
15278 + return;
15279 +
15280 + for (i=0; i< numfiles; i++)
15281 + suspend_unregister_sysfs_file(&suspend2_subsys.kset.kobj,
15282 + &sysfs_params[i]);
15283 +
15284 + kobj_set_kset_s(&suspend2_subsys.kset, power_subsys);
15285 + subsystem_unregister(&suspend2_subsys);
15286 +
15287 + suspend_sysfs_initialised = 0;
15288 +}
15289 +
15290 +/* suspend_initialise_sysfs
15291 + *
15292 + * Initialise the /sysfs/suspend2 directory.
15293 + */
15294 +
15295 +static void suspend_initialise_sysfs(void)
15296 +{
15297 + int i, error;
15298 + int numfiles = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data);
15299 +
15300 + if (suspend_sysfs_initialised)
15301 + return;
15302 +
15303 + /* Make our suspend2 directory a child of /sys/power */
15304 + kobj_set_kset_s(&suspend2_subsys.kset, power_subsys);
15305 + error = subsystem_register(&suspend2_subsys);
15306 +
15307 + if (error)
15308 + return;
15309 +
15310 + /* Make it use the .store and .show routines above */
15311 + kobj_set_kset_s(&suspend2_subsys.kset, suspend2_subsys);
15312 +
15313 + suspend_sysfs_initialised = 1;
15314 +
15315 + for (i=0; i< numfiles; i++)
15316 + suspend_register_sysfs_file(&suspend2_subsys.kset.kobj,
15317 + &sysfs_params[i]);
15318 +}
15319 +
15320 +int s2_sysfs_init(void)
15321 +{
15322 + suspend_initialise_sysfs();
15323 + return 0;
15324 +}
15325 +
15326 +void s2_sysfs_exit(void)
15327 +{
15328 + suspend_cleanup_sysfs();
15329 +}
15330 diff -Naur linux-2.6.21-ck2/kernel/power/sysfs.h linux-2.6.21-magellan-r11/kernel/power/sysfs.h
15331 --- linux-2.6.21-ck2/kernel/power/sysfs.h 1970-01-01 01:00:00.000000000 +0100
15332 +++ linux-2.6.21-magellan-r11/kernel/power/sysfs.h 2007-08-17 15:57:25.000000000 +0200
15333 @@ -0,0 +1,132 @@
15334 +/*
15335 + * kernel/power/sysfs.h
15336 + *
15337 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
15338 + *
15339 + * This file is released under the GPLv2.
15340 + *
15341 + * It provides declarations for suspend to use in managing
15342 + * /sysfs/suspend2. When we switch to kobjects,
15343 + * this will become redundant.
15344 + *
15345 + */
15346 +
15347 +#include <linux/sysfs.h>
15348 +#include "power.h"
15349 +
15350 +struct suspend_sysfs_data {
15351 + struct attribute attr;
15352 + int type;
15353 + int flags;
15354 + union {
15355 + struct {
15356 + unsigned long *bit_vector;
15357 + int bit;
15358 + } bit;
15359 + struct {
15360 + int *variable;
15361 + int minimum;
15362 + int maximum;
15363 + } integer;
15364 + struct {
15365 + long *variable;
15366 + long minimum;
15367 + long maximum;
15368 + } a_long;
15369 + struct {
15370 + unsigned long *variable;
15371 + unsigned long minimum;
15372 + unsigned long maximum;
15373 + } ul;
15374 + struct {
15375 + char *variable;
15376 + int max_length;
15377 + } string;
15378 + struct {
15379 + int (*read_sysfs) (const char *buffer, int count);
15380 + int (*write_sysfs) (const char *buffer, int count);
15381 + void *data;
15382 + } special;
15383 + } data;
15384 +
15385 + /* Side effects routines. Used, eg, for reparsing the
15386 + * resume2 entry when it changes */
15387 + void (*read_side_effect) (void);
15388 + void (*write_side_effect) (void);
15389 + struct list_head sysfs_data_list;
15390 +};
15391 +
15392 +enum {
15393 + SUSPEND_SYSFS_DATA_NONE = 1,
15394 + SUSPEND_SYSFS_DATA_CUSTOM,
15395 + SUSPEND_SYSFS_DATA_BIT,
15396 + SUSPEND_SYSFS_DATA_INTEGER,
15397 + SUSPEND_SYSFS_DATA_UL,
15398 + SUSPEND_SYSFS_DATA_LONG,
15399 + SUSPEND_SYSFS_DATA_STRING
15400 +};
15401 +
15402 +#define SUSPEND2_ATTR(_name, _mode) \
15403 + .attr = {.name = _name , .mode = _mode }
15404 +
15405 +#define SYSFS_BIT(_ul, _bit, _flags) \
15406 + .type = SUSPEND_SYSFS_DATA_BIT, \
15407 + .flags = _flags, \
15408 + .data = { .bit = { .bit_vector = _ul, .bit = _bit } }
15409 +
15410 +#define SYSFS_INT(_int, _min, _max, _flags) \
15411 + .type = SUSPEND_SYSFS_DATA_INTEGER, \
15412 + .flags = _flags, \
15413 + .data = { .integer = { .variable = _int, .minimum = _min, \
15414 + .maximum = _max } }
15415 +
15416 +#define SYSFS_UL(_ul, _min, _max, _flags) \
15417 + .type = SUSPEND_SYSFS_DATA_UL, \
15418 + .flags = _flags, \
15419 + .data = { .ul = { .variable = _ul, .minimum = _min, \
15420 + .maximum = _max } }
15421 +
15422 +#define SYSFS_LONG(_long, _min, _max, _flags) \
15423 + .type = SUSPEND_SYSFS_DATA_LONG, \
15424 + .flags = _flags, \
15425 + .data = { .a_long = { .variable = _long, .minimum = _min, \
15426 + .maximum = _max } }
15427 +
15428 +#define SYSFS_STRING(_string, _max_len, _flags) \
15429 + .type = SUSPEND_SYSFS_DATA_STRING, \
15430 + .flags = _flags, \
15431 + .data = { .string = { .variable = _string, .max_length = _max_len } }
15432 +
15433 +#define SYSFS_CUSTOM(_read, _write, _flags) \
15434 + .type = SUSPEND_SYSFS_DATA_CUSTOM, \
15435 + .flags = _flags, \
15436 + .data = { .special = { .read_sysfs = _read, .write_sysfs = _write } }
15437 +
15438 +#define SYSFS_WRITEONLY 0200
15439 +#define SYSFS_READONLY 0444
15440 +#define SYSFS_RW 0644
15441 +
15442 +/* Flags */
15443 +#define SYSFS_NEEDS_SM_FOR_READ 1
15444 +#define SYSFS_NEEDS_SM_FOR_WRITE 2
15445 +#define SYSFS_SUSPEND 4
15446 +#define SYSFS_RESUME 8
15447 +#define SYSFS_SUSPEND_OR_RESUME (SYSFS_SUSPEND | SYSFS_RESUME)
15448 +#define SYSFS_SUSPENDING (SYSFS_SUSPEND | SYSFS_NEEDS_SM_FOR_WRITE)
15449 +#define SYSFS_RESUMING (SYSFS_RESUME | SYSFS_NEEDS_SM_FOR_WRITE)
15450 +#define SYSFS_NEEDS_SM_FOR_BOTH \
15451 + (SYSFS_NEEDS_SM_FOR_READ | SYSFS_NEEDS_SM_FOR_WRITE)
15452 +
15453 +int suspend_register_sysfs_file(struct kobject *kobj,
15454 + struct suspend_sysfs_data *suspend_sysfs_data);
15455 +void suspend_unregister_sysfs_file(struct kobject *kobj,
15456 + struct suspend_sysfs_data *suspend_sysfs_data);
15457 +
15458 +extern struct subsystem suspend2_subsys;
15459 +
15460 +struct kobject *make_suspend2_sysdir(char *name);
15461 +void remove_suspend2_sysdir(struct kobject *obj);
15462 +extern void suspend_cleanup_sysfs(void);
15463 +
15464 +extern int s2_sysfs_init(void);
15465 +extern void s2_sysfs_exit(void);
15466 diff -Naur linux-2.6.21-ck2/kernel/power/ui.c linux-2.6.21-magellan-r11/kernel/power/ui.c
15467 --- linux-2.6.21-ck2/kernel/power/ui.c 1970-01-01 01:00:00.000000000 +0100
15468 +++ linux-2.6.21-magellan-r11/kernel/power/ui.c 2007-08-17 15:57:25.000000000 +0200
15469 @@ -0,0 +1,235 @@
15470 +/*
15471 + * kernel/power/ui.c
15472 + *
15473 + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
15474 + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
15475 + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
15476 + * Copyright (C) 2002-2007 Nigel Cunningham (nigel at suspend2 net)
15477 + *
15478 + * This file is released under the GPLv2.
15479 + *
15480 + * Routines for Suspend2's user interface.
15481 + *
15482 + * The user interface code talks to a userspace program via a
15483 + * netlink socket.
15484 + *
15485 + * The kernel side:
15486 + * - starts the userui program;
15487 + * - sends text messages and progress bar status;
15488 + *
15489 + * The user space side:
15490 + * - passes messages regarding user requests (abort, toggle reboot etc)
15491 + *
15492 + */
15493 +
15494 +#define __KERNEL_SYSCALLS__
15495 +
15496 +#include <linux/suspend.h>
15497 +#include <linux/freezer.h>
15498 +#include <linux/console.h>
15499 +#include <linux/ctype.h>
15500 +#include <linux/tty.h>
15501 +#include <linux/vt_kern.h>
15502 +#include <linux/module.h>
15503 +#include <linux/reboot.h>
15504 +#include <linux/kmod.h>
15505 +#include <linux/security.h>
15506 +#include <linux/syscalls.h>
15507 +
15508 +#include "sysfs.h"
15509 +#include "modules.h"
15510 +#include "suspend.h"
15511 +#include "ui.h"
15512 +#include "netlink.h"
15513 +#include "power_off.h"
15514 +
15515 +static char local_printf_buf[1024]; /* Same as printk - should be safe */
15516 +struct ui_ops *s2_current_ui;
15517 +
15518 +/*! The console log level we default to. */
15519 +int suspend_default_console_level = 0;
15520 +
15521 +/* suspend_early_boot_message()
15522 + * Description: Handle errors early in the process of booting.
15523 + * The user may press C to continue booting, perhaps
15524 + * invalidating the image, or space to reboot.
15525 + * This works from either the serial console or normally
15526 + * attached keyboard.
15527 + *
15528 + * Note that we come in here from init, while the kernel is
15529 + * locked. If we want to get events from the serial console,
15530 + * we need to temporarily unlock the kernel.
15531 + *
15532 + * suspend_early_boot_message may also be called post-boot.
15533 + * In this case, it simply printks the message and returns.
15534 + *
15535 + * Arguments: int Whether we are able to erase the image.
15536 + * int default_answer. What to do when we timeout. This
15537 + * will normally be continue, but the user might
15538 + * provide command line options (__setup) to override
15539 + * particular cases.
15540 + * Char *. Pointer to a string explaining why we're moaning.
15541 + */
15542 +
15543 +#define say(message, a...) printk(KERN_EMERG message, ##a)
15544 +#define message_timeout 25 /* message_timeout * 10 must fit in 8 bits */
15545 +
15546 +int suspend_early_boot_message(int message_detail, int default_answer, char *warning_reason, ...)
15547 +{
15548 + unsigned long orig_state = get_suspend_state(), continue_req = 0;
15549 + unsigned long orig_loglevel = console_loglevel;
15550 + va_list args;
15551 + int printed_len;
15552 +
15553 + if (warning_reason) {
15554 + va_start(args, warning_reason);
15555 + printed_len = vsnprintf(local_printf_buf,
15556 + sizeof(local_printf_buf),
15557 + warning_reason,
15558 + args);
15559 + va_end(args);
15560 + }
15561 +
15562 + if (!test_suspend_state(SUSPEND_BOOT_TIME)) {
15563 + printk("Suspend2: %s\n", local_printf_buf);
15564 + return default_answer;
15565 + }
15566 +
15567 + /* We might be called directly from do_mounts_initrd if the
15568 + * user fails to set up their initrd properly. We need to
15569 + * enable the keyboard handler by setting the running flag */
15570 + set_suspend_state(SUSPEND_RUNNING);
15571 +
15572 +#if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE)
15573 + console_loglevel = 7;
15574 +
15575 + say("=== Suspend2 ===\n\n");
15576 + if (warning_reason) {
15577 + say("BIG FAT WARNING!! %s\n\n", local_printf_buf);
15578 + switch (message_detail) {
15579 + case 0:
15580 + say("If you continue booting, note that any image WILL NOT BE REMOVED.\n");
15581 + say("Suspend is unable to do so because the appropriate modules aren't\n");
15582 + say("loaded. You should manually remove the image to avoid any\n");
15583 + say("possibility of corrupting your filesystem(s) later.\n");
15584 + break;
15585 + case 1:
15586 + say("If you want to use the current suspend image, reboot and try\n");
15587 + say("again with the same kernel that you suspended from. If you want\n");
15588 + say("to forget that image, continue and the image will be erased.\n");
15589 + break;
15590 + }
15591 + say("Press SPACE to reboot or C to continue booting with this kernel\n\n");
15592 + say("Default action if you don't select one in %d seconds is: %s.\n",
15593 + message_timeout,
15594 + default_answer == SUSPEND_CONTINUE_REQ ?
15595 + "continue booting" : "reboot");
15596 + } else {
15597 + say("BIG FAT WARNING!!\n\n");
15598 + say("You have tried to resume from this image before.\n");
15599 + say("If it failed once, it may well fail again.\n");
15600 + say("Would you like to remove the image and boot normally?\n");
15601 + say("This will be equivalent to entering noresume2 on the\n");
15602 + say("kernel command line.\n\n");
15603 + say("Press SPACE to remove the image or C to continue resuming.\n\n");
15604 + say("Default action if you don't select one in %d seconds is: %s.\n",
15605 + message_timeout,
15606 + !!default_answer ?
15607 + "continue resuming" : "remove the image");
15608 + }
15609 + console_loglevel = orig_loglevel;
15610 +
15611 + set_suspend_state(SUSPEND_SANITY_CHECK_PROMPT);
15612 + clear_suspend_state(SUSPEND_CONTINUE_REQ);
15613 +
15614 + if (suspend_wait_for_keypress(message_timeout) == 0) /* We timed out */
15615 + continue_req = !!default_answer;
15616 + else
15617 + continue_req = test_suspend_state(SUSPEND_CONTINUE_REQ);
15618 +
15619 + if ((warning_reason) && (!continue_req))
15620 + machine_restart(NULL);
15621 +
15622 + restore_suspend_state(orig_state);
15623 + if (continue_req)
15624 + set_suspend_state(SUSPEND_CONTINUE_REQ);
15625 +
15626 +#endif /* CONFIG_VT or CONFIG_SERIAL_CONSOLE */
15627 + return -EIO;
15628 +}
15629 +#undef say
15630 +
15631 +/*
15632 + * User interface specific /sys/power/suspend2 entries.
15633 + */
15634 +
15635 +static struct suspend_sysfs_data sysfs_params[] = {
15636 +#if defined(CONFIG_NET) && defined(CONFIG_SYSFS)
15637 + { SUSPEND2_ATTR("default_console_level", SYSFS_RW),
15638 + SYSFS_INT(&suspend_default_console_level, 0, 7, 0)
15639 + },
15640 +
15641 + { SUSPEND2_ATTR("debug_sections", SYSFS_RW),
15642 + SYSFS_UL(&suspend_debug_state, 0, 1 << 30, 0)
15643 + },
15644 +
15645 + { SUSPEND2_ATTR("log_everything", SYSFS_RW),
15646 + SYSFS_BIT(&suspend_action, SUSPEND_LOGALL, 0)
15647 + },
15648 +#endif
15649 + { SUSPEND2_ATTR("pm_prepare_console", SYSFS_RW),
15650 + SYSFS_BIT(&suspend_action, SUSPEND_PM_PREPARE_CONSOLE, 0)
15651 + }
15652 +};
15653 +
15654 +static struct suspend_module_ops userui_ops = {
15655 + .type = MISC_MODULE,
15656 + .name = "Basic User Interface",
15657 + .directory = "user_interface",
15658 + .module = THIS_MODULE,
15659 + .sysfs_data = sysfs_params,
15660 + .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct suspend_sysfs_data),
15661 +};
15662 +
15663 +int s2_register_ui_ops(struct ui_ops *this_ui)
15664 +{
15665 + if (s2_current_ui) {
15666 + printk("Only one Suspend2 user interface module can be loaded"
15667 + " at a time.");
15668 + return -EBUSY;
15669 + }
15670 +
15671 + s2_current_ui = this_ui;
15672 +
15673 + return 0;
15674 +}
15675 +
15676 +void s2_remove_ui_ops(struct ui_ops *this_ui)
15677 +{
15678 + if (s2_current_ui != this_ui)
15679 + return;
15680 +
15681 + s2_current_ui = NULL;
15682 +}
15683 +
15684 +/* suspend_console_sysfs_init
15685 + * Description: Boot time initialisation for user interface.
15686 + */
15687 +
15688 +int s2_ui_init(void)
15689 +{
15690 + return suspend_register_module(&userui_ops);
15691 +}
15692 +
15693 +void s2_ui_exit(void)
15694 +{
15695 + suspend_unregister_module(&userui_ops);
15696 +}
15697 +
15698 +#ifdef CONFIG_SUSPEND2_EXPORTS
15699 +EXPORT_SYMBOL_GPL(s2_current_ui);
15700 +EXPORT_SYMBOL_GPL(suspend_early_boot_message);
15701 +EXPORT_SYMBOL_GPL(s2_register_ui_ops);
15702 +EXPORT_SYMBOL_GPL(s2_remove_ui_ops);
15703 +EXPORT_SYMBOL_GPL(suspend_default_console_level);
15704 +#endif
15705 diff -Naur linux-2.6.21-ck2/kernel/power/ui.h linux-2.6.21-magellan-r11/kernel/power/ui.h
15706 --- linux-2.6.21-ck2/kernel/power/ui.h 1970-01-01 01:00:00.000000000 +0100
15707 +++ linux-2.6.21-magellan-r11/kernel/power/ui.h 2007-08-17 15:57:25.000000000 +0200
15708 @@ -0,0 +1,108 @@
15709 +/*
15710 + * kernel/power/ui.h
15711 + *
15712 + * Copyright (C) 2004-2007 Nigel Cunningham (nigel at suspend2 net)
15713 + */
15714 +
15715 +enum {
15716 + DONT_CLEAR_BAR,
15717 + CLEAR_BAR
15718 +};
15719 +
15720 +enum {
15721 + /* Userspace -> Kernel */
15722 + USERUI_MSG_ABORT = 0x11,
15723 + USERUI_MSG_SET_STATE = 0x12,
15724 + USERUI_MSG_GET_STATE = 0x13,
15725 + USERUI_MSG_GET_DEBUG_STATE = 0x14,
15726 + USERUI_MSG_SET_DEBUG_STATE = 0x15,
15727 + USERUI_MSG_SPACE = 0x18,
15728 + USERUI_MSG_GET_POWERDOWN_METHOD = 0x1A,
15729 + USERUI_MSG_SET_POWERDOWN_METHOD = 0x1B,
15730 + USERUI_MSG_GET_LOGLEVEL = 0x1C,
15731 + USERUI_MSG_SET_LOGLEVEL = 0x1D,
15732 +
15733 + /* Kernel -> Userspace */
15734 + USERUI_MSG_MESSAGE = 0x21,
15735 + USERUI_MSG_PROGRESS = 0x22,
15736 + USERUI_MSG_POST_ATOMIC_RESTORE = 0x25,
15737 +
15738 + USERUI_MSG_MAX,
15739 +};
15740 +
15741 +struct userui_msg_params {
15742 + unsigned long a, b, c, d;
15743 + char text[255];
15744 +};
15745 +
15746 +struct ui_ops {
15747 + char (*wait_for_key) (int timeout);
15748 + unsigned long (*update_status) (unsigned long value,
15749 + unsigned long maximum, const char *fmt, ...);
15750 + void (*prepare_status) (int clearbar, const char *fmt, ...);
15751 + void (*cond_pause) (int pause, char *message);
15752 + void (*abort)(int result_code, const char *fmt, ...);
15753 + void (*prepare)(void);
15754 + void (*cleanup)(void);
15755 + void (*post_atomic_restore)(void);
15756 + void (*message)(unsigned long section, unsigned long level,
15757 + int normally_logged, const char *fmt, ...);
15758 +};
15759 +
15760 +extern struct ui_ops *s2_current_ui;
15761 +
15762 +#define suspend_update_status(val, max, fmt, args...) \
15763 + (s2_current_ui ? (s2_current_ui->update_status) (val, max, fmt, ##args) : max)
15764 +
15765 +#define suspend_wait_for_keypress(timeout) \
15766 + (s2_current_ui ? (s2_current_ui->wait_for_key) (timeout) : 0)
15767 +
15768 +#define suspend_ui_post_atomic_restore(void) \
15769 + do { if (s2_current_ui) \
15770 + (s2_current_ui->post_atomic_restore)(); \
15771 + } while(0)
15772 +
15773 +#define suspend_prepare_console(void) \
15774 + do { if (s2_current_ui) \
15775 + (s2_current_ui->prepare)(); \
15776 + } while(0)
15777 +
15778 +#define suspend_cleanup_console(void) \
15779 + do { if (s2_current_ui) \
15780 + (s2_current_ui->cleanup)(); \
15781 + } while(0)
15782 +
15783 +#define abort_suspend(result, fmt, args...) \
15784 + do { if (s2_current_ui) \
15785 + (s2_current_ui->abort)(result, fmt, ##args); \
15786 + else { \
15787 + set_result_state(SUSPEND_ABORTED); \
15788 + set_result_state(result); \
15789 + } \
15790 + } while(0)
15791 +
15792 +#define suspend_cond_pause(pause, message) \
15793 + do { if (s2_current_ui) \
15794 + (s2_current_ui->cond_pause)(pause, message); \
15795 + } while(0)
15796 +
15797 +#define suspend_prepare_status(clear, fmt, args...) \
15798 + do { if (s2_current_ui) \
15799 + (s2_current_ui->prepare_status)(clear, fmt, ##args); \
15800 + else \
15801 + printk(fmt, ##args); \
15802 + } while(0)
15803 +
15804 +extern int suspend_default_console_level;
15805 +
15806 +#define suspend_message(sn, lev, log, fmt, a...) \
15807 +do { \
15808 + if (s2_current_ui && (!sn || test_debug_state(sn))) \
15809 + s2_current_ui->message(sn, lev, log, fmt, ##a); \
15810 +} while(0)
15811 +
15812 +__exit void suspend_ui_cleanup(void);
15813 +extern int s2_ui_init(void);
15814 +extern void s2_ui_exit(void);
15815 +extern int s2_register_ui_ops(struct ui_ops *this_ui);
15816 +extern void s2_remove_ui_ops(struct ui_ops *this_ui);
15817 diff -Naur linux-2.6.21-ck2/kernel/printk.c linux-2.6.21-magellan-r11/kernel/printk.c
15818 --- linux-2.6.21-ck2/kernel/printk.c 2007-04-26 05:08:32.000000000 +0200
15819 +++ linux-2.6.21-magellan-r11/kernel/printk.c 2007-08-17 15:57:25.000000000 +0200
15820 @@ -32,6 +32,7 @@
15821 #include <linux/bootmem.h>
15822 #include <linux/syscalls.h>
15823 #include <linux/jiffies.h>
15824 +#include <linux/suspend.h>
15825
15826 #include <asm/uaccess.h>
15827
15828 @@ -92,9 +93,9 @@
15829 * The indices into log_buf are not constrained to log_buf_len - they
15830 * must be masked before subscripting
15831 */
15832 -static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */
15833 -static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */
15834 -static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */
15835 +static unsigned long POSS_NOSAVE log_start; /* Index into log_buf: next char to be read by syslog() */
15836 +static unsigned long POSS_NOSAVE con_start; /* Index into log_buf: next char to be sent to consoles */
15837 +static unsigned long POSS_NOSAVE log_end; /* Index into log_buf: most-recently-written-char + 1 */
15838
15839 /*
15840 * Array of consoles built from command line options (console=)
15841 @@ -117,10 +118,10 @@
15842
15843 #ifdef CONFIG_PRINTK
15844
15845 -static char __log_buf[__LOG_BUF_LEN];
15846 -static char *log_buf = __log_buf;
15847 -static int log_buf_len = __LOG_BUF_LEN;
15848 -static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
15849 +static char POSS_NOSAVE __log_buf[__LOG_BUF_LEN];
15850 +static char POSS_NOSAVE *log_buf = __log_buf;
15851 +static int POSS_NOSAVE log_buf_len = __LOG_BUF_LEN;
15852 +static unsigned long POSS_NOSAVE logged_chars; /* Number of chars produced since last read+clear operation */
15853
15854 static int __init log_buf_len_setup(char *str)
15855 {
15856 @@ -739,12 +740,14 @@
15857 acquire_console_sem();
15858 console_suspended = 1;
15859 }
15860 +EXPORT_SYMBOL(suspend_console);
15861
15862 void resume_console(void)
15863 {
15864 console_suspended = 0;
15865 release_console_sem();
15866 }
15867 +EXPORT_SYMBOL(resume_console);
15868 #endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
15869
15870 /**
15871 diff -Naur linux-2.6.21-ck2/kernel/timer.c linux-2.6.21-magellan-r11/kernel/timer.c
15872 --- linux-2.6.21-ck2/kernel/timer.c 2007-04-26 05:08:32.000000000 +0200
15873 +++ linux-2.6.21-magellan-r11/kernel/timer.c 2007-08-17 15:57:25.000000000 +0200
15874 @@ -1240,6 +1240,38 @@
15875
15876 EXPORT_SYMBOL(avenrun);
15877
15878 +static unsigned long avenrun_save[3];
15879 +/*
15880 + * save_avenrun - Record the values prior to starting a hibernation cycle.
15881 + * We do this to make the work done in hibernation invisible to userspace
15882 + * post-suspend. Some programs, including some MTAs, watch the load average
15883 + * and stop work until it lowers. Without this, they would stop working for
15884 + * a while post-resume, unnecessarily.
15885 + */
15886 +
15887 +void save_avenrun(void)
15888 +{
15889 + avenrun_save[0] = avenrun[0];
15890 + avenrun_save[1] = avenrun[1];
15891 + avenrun_save[2] = avenrun[2];
15892 +}
15893 +
15894 +EXPORT_SYMBOL_GPL(save_avenrun);
15895 +
15896 +void restore_avenrun(void)
15897 +{
15898 + if (!avenrun_save[0])
15899 + return;
15900 +
15901 + avenrun[0] = avenrun_save[0];
15902 + avenrun[1] = avenrun_save[1];
15903 + avenrun[2] = avenrun_save[2];
15904 +
15905 + avenrun_save[0] = 0;
15906 +}
15907 +
15908 +EXPORT_SYMBOL_GPL(restore_avenrun);
15909 +
15910 /*
15911 * calc_load - given tick count, update the avenrun load estimates.
15912 * This is called while holding a write_lock on xtime_lock.
15913 diff -Naur linux-2.6.21-ck2/lib/Kconfig linux-2.6.21-magellan-r11/lib/Kconfig
15914 --- linux-2.6.21-ck2/lib/Kconfig 2007-04-26 05:08:32.000000000 +0200
15915 +++ linux-2.6.21-magellan-r11/lib/Kconfig 2007-08-17 15:57:25.000000000 +0200
15916 @@ -47,6 +47,9 @@
15917 depends on AUDIT && !AUDIT_ARCH
15918 default y
15919
15920 +config DYN_PAGEFLAGS
15921 + bool
15922 +
15923 #
15924 # compression support is select'ed if needed
15925 #
15926 diff -Naur linux-2.6.21-ck2/lib/Makefile linux-2.6.21-magellan-r11/lib/Makefile
15927 --- linux-2.6.21-ck2/lib/Makefile 2007-04-26 05:08:32.000000000 +0200
15928 +++ linux-2.6.21-magellan-r11/lib/Makefile 2007-08-17 15:57:25.000000000 +0200
15929 @@ -38,6 +38,9 @@
15930 endif
15931
15932 obj-$(CONFIG_BITREVERSE) += bitrev.o
15933 +
15934 +obj-$(CONFIG_DYN_PAGEFLAGS) += dyn_pageflags.o
15935 +
15936 obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
15937 obj-$(CONFIG_CRC16) += crc16.o
15938 obj-$(CONFIG_CRC32) += crc32.o
15939 diff -Naur linux-2.6.21-ck2/lib/dyn_pageflags.c linux-2.6.21-magellan-r11/lib/dyn_pageflags.c
15940 --- linux-2.6.21-ck2/lib/dyn_pageflags.c 1970-01-01 01:00:00.000000000 +0100
15941 +++ linux-2.6.21-magellan-r11/lib/dyn_pageflags.c 2007-08-17 15:57:25.000000000 +0200
15942 @@ -0,0 +1,312 @@
15943 +/*
15944 + * lib/dyn_pageflags.c
15945 + *
15946 + * Copyright (C) 2004-2006 Nigel Cunningham <nigel@suspend2.net>
15947 + *
15948 + * This file is released under the GPLv2.
15949 + *
15950 + * Routines for dynamically allocating and releasing bitmaps
15951 + * used as pseudo-pageflags.
15952 + */
15953 +
15954 +#include <linux/module.h>
15955 +#include <linux/dyn_pageflags.h>
15956 +#include <linux/bootmem.h>
15957 +#include <linux/mm.h>
15958 +
15959 +#if 0
15960 +#define PR_DEBUG(a, b...) do { printk(a, ##b); } while(0)
15961 +#else
15962 +#define PR_DEBUG(a, b...) do { } while(0)
15963 +#endif
15964 +
15965 +#define pages_for_zone(zone) \
15966 + (DIV_ROUND_UP((zone)->spanned_pages, (PAGE_SIZE << 3)))
15967 +
15968 +/*
15969 + * clear_dyn_pageflags(dyn_pageflags_t pagemap)
15970 + *
15971 + * Clear an array used to store local page flags.
15972 + *
15973 + */
15974 +
15975 +void clear_dyn_pageflags(dyn_pageflags_t pagemap)
15976 +{
15977 + int i = 0, zone_idx, node_id = 0;
15978 + struct zone *zone;
15979 + struct pglist_data *pgdat;
15980 +
15981 + BUG_ON(!pagemap);
15982 +
15983 + for_each_online_pgdat(pgdat) {
15984 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
15985 + zone = &pgdat->node_zones[zone_idx];
15986 +
15987 + if (!populated_zone(zone))
15988 + continue;
15989 +
15990 + for (i = 0; i < pages_for_zone(zone); i++)
15991 + memset((pagemap[node_id][zone_idx][i]), 0,
15992 + PAGE_SIZE);
15993 + }
15994 + node_id++;
15995 + }
15996 +}
15997 +
15998 +/*
15999 + * free_dyn_pageflags(dyn_pageflags_t pagemap)
16000 + *
16001 + * Free a dynamically allocated pageflags bitmap. For Suspend2 usage, we
16002 + * support data being relocated from slab to pages that don't conflict
16003 + * with the image that will be copied back. This is the reason for the
16004 + * PageSlab tests below.
16005 + *
16006 + */
16007 +void free_dyn_pageflags(dyn_pageflags_t *pagemap)
16008 +{
16009 + int i = 0, zone_pages, node_id = -1, zone_idx;
16010 + struct zone *zone;
16011 + struct pglist_data *pgdat;
16012 +
16013 + if (!*pagemap)
16014 + return;
16015 +
16016 + PR_DEBUG("Seeking to free dyn_pageflags %p.\n", pagemap);
16017 +
16018 + for_each_online_pgdat(pgdat) {
16019 + node_id++;
16020 +
16021 + PR_DEBUG("Node id %d.\n", node_id);
16022 +
16023 + if (!(*pagemap)[node_id]) {
16024 + PR_DEBUG("Node %d unallocated.\n", node_id);
16025 + continue;
16026 + }
16027 +
16028 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
16029 + zone = &pgdat->node_zones[zone_idx];
16030 + if (!populated_zone(zone)) {
16031 + PR_DEBUG("Node %d zone %d unpopulated.\n", node_id, zone_idx);
16032 + continue;
16033 + }
16034 +
16035 + if (!(*pagemap)[node_id][zone_idx]) {
16036 + PR_DEBUG("Node %d zone %d unallocated.\n", node_id, zone_idx);
16037 + continue;
16038 + }
16039 +
16040 + PR_DEBUG("Node id %d. Zone %d.\n", node_id, zone_idx);
16041 +
16042 + zone_pages = pages_for_zone(zone);
16043 +
16044 + for (i = 0; i < zone_pages; i++) {
16045 + PR_DEBUG("Node id %d. Zone %d. Page %d.\n", node_id, zone_idx, i);
16046 + free_page((unsigned long)(*pagemap)[node_id][zone_idx][i]);
16047 + }
16048 +
16049 + kfree((*pagemap)[node_id][zone_idx]);
16050 + }
16051 + PR_DEBUG("Free node %d (%p).\n", node_id, pagemap[node_id]);
16052 + kfree((*pagemap)[node_id]);
16053 + }
16054 +
16055 + PR_DEBUG("Free map pgdat list at %p.\n", pagemap);
16056 + kfree(*pagemap);
16057 +
16058 + *pagemap = NULL;
16059 + PR_DEBUG("Done.\n");
16060 + return;
16061 +}
16062 +
16063 +static int try_alloc_dyn_pageflag_part(int nr_ptrs, void **ptr)
16064 +{
16065 + *ptr = kzalloc(sizeof(void *) * nr_ptrs, GFP_ATOMIC);
16066 + PR_DEBUG("Got %p. Putting it in %p.\n", *ptr, ptr);
16067 +
16068 + if (*ptr)
16069 + return 0;
16070 +
16071 + printk("Error. Unable to allocate memory for dynamic pageflags.");
16072 + return -ENOMEM;
16073 +}
16074 +
16075 +/*
16076 + * allocate_dyn_pageflags
16077 + *
16078 + * Allocate a bitmap for dynamic page flags.
16079 + *
16080 + */
16081 +int allocate_dyn_pageflags(dyn_pageflags_t *pagemap)
16082 +{
16083 + int i, zone_idx, zone_pages, node_id = 0;
16084 + struct zone *zone;
16085 + struct pglist_data *pgdat;
16086 +
16087 + if (*pagemap) {
16088 + PR_DEBUG("Pagemap %p already allocated.\n", pagemap);
16089 + return 0;
16090 + }
16091 +
16092 + PR_DEBUG("Seeking to allocate dyn_pageflags %p.\n", pagemap);
16093 +
16094 + for_each_online_pgdat(pgdat)
16095 + node_id++;
16096 +
16097 + if (try_alloc_dyn_pageflag_part(node_id, (void **) pagemap))
16098 + return -ENOMEM;
16099 +
16100 + node_id = 0;
16101 +
16102 + for_each_online_pgdat(pgdat) {
16103 + PR_DEBUG("Node %d.\n", node_id);
16104 +
16105 + if (try_alloc_dyn_pageflag_part(MAX_NR_ZONES,
16106 + (void **) &(*pagemap)[node_id]))
16107 + return -ENOMEM;
16108 +
16109 + for (zone_idx = 0; zone_idx < MAX_NR_ZONES; zone_idx++) {
16110 + PR_DEBUG("Zone %d of %d.\n", zone_idx, MAX_NR_ZONES);
16111 +
16112 + zone = &pgdat->node_zones[zone_idx];
16113 +
16114 + if (!populated_zone(zone)) {
16115 + PR_DEBUG("Node %d zone %d unpopulated - won't allocate.\n", node_id, zone_idx);
16116 + continue;
16117 + }
16118 +
16119 + zone_pages = pages_for_zone(zone);
16120 +
16121 + PR_DEBUG("Node %d zone %d (needs %d pages).\n", node_id, zone_idx, zone_pages);
16122 +
16123 + if (try_alloc_dyn_pageflag_part(zone_pages,
16124 + (void **) &(*pagemap)[node_id][zone_idx]))
16125 + return -ENOMEM;
16126 +
16127 + for (i = 0; i < zone_pages; i++) {
16128 + unsigned long address = get_zeroed_page(GFP_ATOMIC);
16129 + if (!address) {
16130 + PR_DEBUG("Error. Unable to allocate memory for "
16131 + "dynamic pageflags.");
16132 + free_dyn_pageflags(pagemap);
16133 + return -ENOMEM;
16134 + }
16135 + PR_DEBUG("Node %d zone %d. Page %d.\n", node_id, zone_idx, i);
16136 + (*pagemap)[node_id][zone_idx][i] =
16137 + (unsigned long *) address;
16138 + }
16139 + }
16140 + node_id++;
16141 + }
16142 +
16143 + PR_DEBUG("Done.\n");
16144 + return 0;
16145 +}
16146 +
16147 +#define GET_BIT_AND_UL(bitmap, page) \
16148 + struct zone *zone = page_zone(page); \
16149 + unsigned long zone_pfn = page_to_pfn(page) - zone->zone_start_pfn; \
16150 + int node = page_to_nid(page); \
16151 + int zone_num = zone_idx(zone); \
16152 + int pagenum = PAGENUMBER(zone_pfn); \
16153 + int page_offset = PAGEINDEX(zone_pfn); \
16154 + unsigned long *ul = ((*bitmap)[node][zone_num][pagenum]) + page_offset; \
16155 + int bit = PAGEBIT(zone_pfn);
16156 +
16157 +/*
16158 + * test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16159 + *
16160 + * Is the page flagged in the given bitmap?
16161 + *
16162 + */
16163 +
16164 +int test_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16165 +{
16166 + GET_BIT_AND_UL(bitmap, page);
16167 + return test_bit(bit, ul);
16168 +}
16169 +
16170 +/*
16171 + * set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16172 + *
16173 + * Set the flag for the page in the given bitmap.
16174 + *
16175 + */
16176 +
16177 +void set_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16178 +{
16179 + GET_BIT_AND_UL(bitmap, page);
16180 + set_bit(bit, ul);
16181 +}
16182 +
16183 +/*
16184 + * clear_dynpageflags(dyn_pageflags_t *bitmap, struct page *page)
16185 + *
16186 + * Clear the flag for the page in the given bitmap.
16187 + *
16188 + */
16189 +
16190 +void clear_dynpageflag(dyn_pageflags_t *bitmap, struct page *page)
16191 +{
16192 + GET_BIT_AND_UL(bitmap, page);
16193 + clear_bit(bit, ul);
16194 +}
16195 +
16196 +/*
16197 + * get_next_bit_on(dyn_pageflags_t bitmap, int counter)
16198 + *
16199 + * Given a pfn (possibly -1), find the next pfn in the bitmap that
16200 + * is set. If there are no more flags set, return -1.
16201 + *
16202 + */
16203 +
16204 +unsigned long get_next_bit_on(dyn_pageflags_t bitmap, unsigned long counter)
16205 +{
16206 + struct page *page;
16207 + struct zone *zone;
16208 + unsigned long *ul = NULL;
16209 + unsigned long zone_offset;
16210 + int pagebit, zone_num, first = (counter == (max_pfn + 1)), node;
16211 +
16212 + if (first)
16213 + counter = first_online_pgdat()->node_zones->zone_start_pfn;
16214 +
16215 + page = pfn_to_page(counter);
16216 + zone = page_zone(page);
16217 + node = zone->zone_pgdat->node_id;
16218 + zone_num = zone_idx(zone);
16219 + zone_offset = counter - zone->zone_start_pfn;
16220 +
16221 + if (first)
16222 + goto test;
16223 +
16224 + do {
16225 + zone_offset++;
16226 +
16227 + if (zone_offset >= zone->spanned_pages) {
16228 + do {
16229 + zone = next_zone(zone);
16230 + if (!zone)
16231 + return max_pfn + 1;
16232 + } while(!zone->spanned_pages);
16233 +
16234 + zone_num = zone_idx(zone);
16235 + node = zone->zone_pgdat->node_id;
16236 + zone_offset = 0;
16237 + }
16238 +test:
16239 + pagebit = PAGEBIT(zone_offset);
16240 +
16241 + if (!pagebit || !ul)
16242 + ul = (bitmap[node][zone_num][PAGENUMBER(zone_offset)])
16243 + + PAGEINDEX(zone_offset);
16244 +
16245 + if (!(*ul & ~((1 << pagebit) - 1))) {
16246 + zone_offset += BITS_PER_LONG - pagebit - 1;
16247 + continue;
16248 + }
16249 +
16250 + } while(!test_bit(pagebit, ul));
16251 +
16252 + return zone->zone_start_pfn + zone_offset;
16253 +}
16254 +
16255 diff -Naur linux-2.6.21-ck2/lib/vsprintf.c linux-2.6.21-magellan-r11/lib/vsprintf.c
16256 --- linux-2.6.21-ck2/lib/vsprintf.c 2007-04-26 05:08:32.000000000 +0200
16257 +++ linux-2.6.21-magellan-r11/lib/vsprintf.c 2007-08-17 15:57:25.000000000 +0200
16258 @@ -236,6 +236,29 @@
16259 return buf;
16260 }
16261
16262 +/*
16263 + * vsnprintf_used
16264 + *
16265 + * Functionality : Print a string with parameters to a buffer of a
16266 + * limited size. Unlike vsnprintf, we return the number
16267 + * of bytes actually put in the buffer, not the number
16268 + * that would have been put in if it was big enough.
16269 + */
16270 +int snprintf_used(char *buffer, int buffer_size, const char *fmt, ...)
16271 +{
16272 + int result;
16273 + va_list args;
16274 +
16275 + if (!buffer_size)
16276 + return 0;
16277 +
16278 + va_start(args, fmt);
16279 + result = vsnprintf(buffer, buffer_size, fmt, args);
16280 + va_end(args);
16281 +
16282 + return result > buffer_size ? buffer_size : result;
16283 +}
16284 +
16285 /**
16286 * vsnprintf - Format a string and place it in a buffer
16287 * @buf: The buffer to place the result into
16288 diff -Naur linux-2.6.21-ck2/mm/vmscan.c linux-2.6.21-magellan-r11/mm/vmscan.c
16289 --- linux-2.6.21-ck2/mm/vmscan.c 2007-08-17 15:53:11.000000000 +0200
16290 +++ linux-2.6.21-magellan-r11/mm/vmscan.c 2007-08-17 16:04:22.000000000 +0200
16291 @@ -657,6 +657,28 @@
16292 return nr_taken;
16293 }
16294
16295 +/* return_lru_pages puts a list of pages back on a zone's lru lists. */
16296 +
16297 +static void return_lru_pages(struct list_head *page_list, struct zone *zone,
16298 + struct pagevec *pvec)
16299 +{
16300 + while (!list_empty(page_list)) {
16301 + struct page *page = lru_to_page(page_list);
16302 + VM_BUG_ON(PageLRU(page));
16303 + SetPageLRU(page);
16304 + list_del(&page->lru);
16305 + if (PageActive(page))
16306 + add_page_to_active_list(zone, page);
16307 + else
16308 + add_page_to_inactive_list(zone, page);
16309 + if (!pagevec_add(pvec, page)) {
16310 + spin_unlock_irq(&zone->lru_lock);
16311 + __pagevec_release(pvec);
16312 + spin_lock_irq(&zone->lru_lock);
16313 + }
16314 + }
16315 +}
16316 +
16317 /*
16318 * shrink_inactive_list() is a helper for shrink_zone(). It returns the number
16319 * of reclaimed pages
16320 @@ -674,7 +696,6 @@
16321 lru_add_drain();
16322 spin_lock_irq(&zone->lru_lock);
16323 do {
16324 - struct page *page;
16325 unsigned long nr_taken;
16326 unsigned long nr_scan;
16327 unsigned long nr_freed;
16328 @@ -704,21 +725,7 @@
16329 /*
16330 * Put back any unfreeable pages.
16331 */
16332 - while (!list_empty(&page_list)) {
16333 - page = lru_to_page(&page_list);
16334 - VM_BUG_ON(PageLRU(page));
16335 - SetPageLRU(page);
16336 - list_del(&page->lru);
16337 - if (PageActive(page))
16338 - add_page_to_active_list(zone, page);
16339 - else
16340 - add_page_to_inactive_list(zone, page);
16341 - if (!pagevec_add(&pvec, page)) {
16342 - spin_unlock_irq(&zone->lru_lock);
16343 - __pagevec_release(&pvec);
16344 - spin_lock_irq(&zone->lru_lock);
16345 - }
16346 - }
16347 + return_lru_pages(&page_list, zone, &pvec);
16348 } while (nr_scanned < max_scan);
16349 spin_unlock(&zone->lru_lock);
16350 done:
16351 @@ -1339,6 +1346,72 @@
16352
16353 #define WT_EXPIRY (HZ * 5) /* Time to wakeup watermark_timer */
16354
16355 +struct lru_save {
16356 + struct zone *zone;
16357 + struct list_head active_list;
16358 + struct list_head inactive_list;
16359 + struct lru_save *next;
16360 +};
16361 +
16362 +struct lru_save *lru_save_list;
16363 +
16364 +void unlink_lru_lists(void)
16365 +{
16366 + struct zone *zone;
16367 +
16368 + for_each_zone(zone) {
16369 + struct lru_save *this;
16370 + unsigned long moved, scanned;
16371 +
16372 + if (!zone->spanned_pages)
16373 + continue;
16374 +
16375 + this = (struct lru_save *)
16376 + kzalloc(sizeof(struct lru_save), GFP_ATOMIC);
16377 +
16378 + BUG_ON(!this);
16379 +
16380 + this->next = lru_save_list;
16381 + lru_save_list = this;
16382 +
16383 + this->zone = zone;
16384 +
16385 + spin_lock_irq(&zone->lru_lock);
16386 + INIT_LIST_HEAD(&this->active_list);
16387 + INIT_LIST_HEAD(&this->inactive_list);
16388 + moved = isolate_lru_pages(zone_page_state(zone, NR_ACTIVE),
16389 + &zone->active_list, &this->active_list,
16390 + &scanned);
16391 + __mod_zone_page_state(zone, NR_ACTIVE, -moved);
16392 + moved = isolate_lru_pages(zone_page_state(zone, NR_INACTIVE),
16393 + &zone->inactive_list, &this->inactive_list,
16394 + &scanned);
16395 + __mod_zone_page_state(zone, NR_INACTIVE, -moved);
16396 + spin_unlock_irq(&zone->lru_lock);
16397 + }
16398 +}
16399 +
16400 +void relink_lru_lists(void)
16401 +{
16402 + while(lru_save_list) {
16403 + struct lru_save *this = lru_save_list;
16404 + struct zone *zone = this->zone;
16405 + struct pagevec pvec;
16406 +
16407 + pagevec_init(&pvec, 1);
16408 +
16409 + lru_save_list = this->next;
16410 +
16411 + spin_lock_irq(&zone->lru_lock);
16412 + return_lru_pages(&this->active_list, zone, &pvec);
16413 + return_lru_pages(&this->inactive_list, zone, &pvec);
16414 + spin_unlock_irq(&zone->lru_lock);
16415 + pagevec_release(&pvec);
16416 +
16417 + kfree(this);
16418 + }
16419 +}
16420 +
16421 /*
16422 * The background pageout daemon, started as a kernel thread
16423 * from the init process.
16424 @@ -1386,8 +1459,6 @@
16425 for ( ; ; ) {
16426 unsigned long new_order;
16427
16428 - try_to_freeze();
16429 -
16430 /* kswapd has been busy so delay watermark_timer */
16431 mod_timer(&pgdat->watermark_timer, jiffies + WT_EXPIRY);
16432 prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
16433 @@ -1401,12 +1472,20 @@
16434 order = new_order;
16435 } else {
16436 set_user_nice(tsk, 0);
16437 - schedule();
16438 + if (!freezing(current))
16439 + schedule();
16440 +
16441 order = pgdat->kswapd_max_order;
16442 }
16443 finish_wait(&pgdat->kswapd_wait, &wait);
16444
16445 - balance_pgdat(pgdat, order);
16446 + if (!try_to_freeze()) {
16447 + /* We can speed up thawing tasks if we don't call
16448 + * balance_pgdat after returning from the refrigerator
16449 + */
16450 + balance_pgdat(pgdat, order);
16451 + }
16452 +
16453 }
16454 return 0;
16455 }
16456 @@ -1422,6 +1501,9 @@
16457 if (!populated_zone(zone))
16458 return;
16459
16460 + if (freezer_is_on())
16461 + return;
16462 +
16463 pgdat = zone->zone_pgdat;
16464 if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0))
16465 return;
16466 @@ -1437,6 +1519,91 @@
16467 }
16468
16469 #ifdef CONFIG_PM
16470 +void shrink_one_zone(struct zone *zone, int total_to_free)
16471 +{
16472 + int prio;
16473 + unsigned long still_to_free = total_to_free;
16474 + struct scan_control sc = {
16475 + .gfp_mask = GFP_KERNEL,
16476 + .may_swap = 0,
16477 + .may_writepage = 1,
16478 + .swappiness = vm_swappiness,
16479 + };
16480 +
16481 + if (!populated_zone(zone) || zone->all_unreclaimable)
16482 + return;
16483 +
16484 + if (still_to_free <= 0)
16485 + return;
16486 +
16487 + if (is_highmem(zone))
16488 + sc.gfp_mask |= __GFP_HIGHMEM;
16489 +
16490 + for (prio = DEF_PRIORITY; prio >= 0; prio--) {
16491 + unsigned long to_free, just_freed, orig_size;
16492 + unsigned long old_nr_active;
16493 +
16494 + to_free = min(zone_page_state(zone, NR_ACTIVE) +
16495 + zone_page_state(zone, NR_INACTIVE),
16496 + still_to_free);
16497 +
16498 + if (to_free <= 0)
16499 + return;
16500 +
16501 + sc.swap_cluster_max = to_free -
16502 + zone_page_state(zone, NR_INACTIVE);
16503 +
16504 + do {
16505 + old_nr_active = zone_page_state(zone, NR_ACTIVE);
16506 + zone->nr_scan_active = sc.swap_cluster_max - 1;
16507 + shrink_active_list(sc.swap_cluster_max, zone, &sc,
16508 + prio);
16509 + zone->nr_scan_active = 0;
16510 +
16511 + sc.swap_cluster_max = to_free - zone_page_state(zone,
16512 + NR_INACTIVE);
16513 +
16514 + } while (sc.swap_cluster_max > 0 &&
16515 + zone_page_state(zone, NR_ACTIVE) > old_nr_active);
16516 +
16517 + to_free = min(zone_page_state(zone, NR_ACTIVE) +
16518 + zone_page_state(zone, NR_INACTIVE),
16519 + still_to_free);
16520 +
16521 + do {
16522 + orig_size = zone_page_state(zone, NR_ACTIVE) +
16523 + zone_page_state(zone, NR_INACTIVE);
16524 + zone->nr_scan_inactive = to_free;
16525 + sc.swap_cluster_max = to_free;
16526 + shrink_inactive_list(to_free, zone, &sc);
16527 + just_freed = (orig_size -
16528 + (zone_page_state(zone, NR_ACTIVE) +
16529 + zone_page_state(zone, NR_INACTIVE)));
16530 + zone->nr_scan_inactive = 0;
16531 + still_to_free -= just_freed;
16532 + to_free -= just_freed;
16533 + } while (just_freed > 0 && still_to_free > 0);
16534 + };
16535 +
16536 + while (still_to_free > 0) {
16537 + unsigned long nr_slab = global_page_state(NR_SLAB_RECLAIMABLE);
16538 + struct reclaim_state reclaim_state;
16539 +
16540 + if (nr_slab > still_to_free)
16541 + nr_slab = still_to_free;
16542 +
16543 + reclaim_state.reclaimed_slab = 0;
16544 + shrink_slab(nr_slab, sc.gfp_mask, nr_slab);
16545 + if (!reclaim_state.reclaimed_slab)
16546 + break;
16547 +
16548 + still_to_free -= reclaim_state.reclaimed_slab;
16549 + }
16550 +
16551 + return;
16552 +}
16553 +
16554 +
16555 /*
16556 * Helper function for shrink_all_memory(). Tries to reclaim 'nr_pages' pages
16557 * from LRU lists system-wide, for given pass and priority, and returns the