OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [kernel/] [power/] [swap.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/kernel/power/swap.c
3
 *
4
 * This file provides functions for reading the suspend image from
5
 * and writing it to a swap partition.
6
 *
7
 * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
8
 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
9
 *
10
 * This file is released under the GPLv2.
11
 *
12
 */
13
 
14
#include <linux/module.h>
15
#include <linux/file.h>
16
#include <linux/utsname.h>
17
#include <linux/version.h>
18
#include <linux/delay.h>
19
#include <linux/bitops.h>
20
#include <linux/genhd.h>
21
#include <linux/device.h>
22
#include <linux/buffer_head.h>
23
#include <linux/bio.h>
24
#include <linux/blkdev.h>
25
#include <linux/swap.h>
26
#include <linux/swapops.h>
27
#include <linux/pm.h>
28
 
29
#include "power.h"
30
 
31
extern char resume_file[];
32
 
33
#define SWSUSP_SIG      "S1SUSPEND"
34
 
35
struct swsusp_header {
36
        char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
37
        sector_t image;
38
        unsigned int flags;     /* Flags to pass to the "boot" kernel */
39
        char    orig_sig[10];
40
        char    sig[10];
41
} __attribute__((packed));
42
 
43
static struct swsusp_header *swsusp_header;
44
 
45
/*
46
 * General things
47
 */
48
 
49
static unsigned short root_swap = 0xffff;
50
static struct block_device *resume_bdev;
51
 
52
/**
53
 *      submit - submit BIO request.
54
 *      @rw:    READ or WRITE.
55
 *      @off    physical offset of page.
56
 *      @page:  page we're reading or writing.
57
 *      @bio_chain: list of pending biod (for async reading)
58
 *
59
 *      Straight from the textbook - allocate and initialize the bio.
60
 *      If we're reading, make sure the page is marked as dirty.
61
 *      Then submit it and, if @bio_chain == NULL, wait.
62
 */
63
static int submit(int rw, pgoff_t page_off, struct page *page,
64
                        struct bio **bio_chain)
65
{
66
        struct bio *bio;
67
 
68
        bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
69
        if (!bio)
70
                return -ENOMEM;
71
        bio->bi_sector = page_off * (PAGE_SIZE >> 9);
72
        bio->bi_bdev = resume_bdev;
73
        bio->bi_end_io = end_swap_bio_read;
74
 
75
        if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
76
                printk("swsusp: ERROR: adding page to bio at %ld\n", page_off);
77
                bio_put(bio);
78
                return -EFAULT;
79
        }
80
 
81
        lock_page(page);
82
        bio_get(bio);
83
 
84
        if (bio_chain == NULL) {
85
                submit_bio(rw | (1 << BIO_RW_SYNC), bio);
86
                wait_on_page_locked(page);
87
                if (rw == READ)
88
                        bio_set_pages_dirty(bio);
89
                bio_put(bio);
90
        } else {
91
                if (rw == READ)
92
                        get_page(page); /* These pages are freed later */
93
                bio->bi_private = *bio_chain;
94
                *bio_chain = bio;
95
                submit_bio(rw | (1 << BIO_RW_SYNC), bio);
96
        }
97
        return 0;
98
}
99
 
100
static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
101
{
102
        return submit(READ, page_off, virt_to_page(addr), bio_chain);
103
}
104
 
105
static int bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
106
{
107
        return submit(WRITE, page_off, virt_to_page(addr), bio_chain);
108
}
109
 
110
static int wait_on_bio_chain(struct bio **bio_chain)
111
{
112
        struct bio *bio;
113
        struct bio *next_bio;
114
        int ret = 0;
115
 
116
        if (bio_chain == NULL)
117
                return 0;
118
 
119
        bio = *bio_chain;
120
        if (bio == NULL)
121
                return 0;
122
        while (bio) {
123
                struct page *page;
124
 
125
                next_bio = bio->bi_private;
126
                page = bio->bi_io_vec[0].bv_page;
127
                wait_on_page_locked(page);
128
                if (!PageUptodate(page) || PageError(page))
129
                        ret = -EIO;
130
                put_page(page);
131
                bio_put(bio);
132
                bio = next_bio;
133
        }
134
        *bio_chain = NULL;
135
        return ret;
136
}
137
 
138
/*
139
 * Saving part
140
 */
141
 
142
static int mark_swapfiles(sector_t start, unsigned int flags)
143
{
144
        int error;
145
 
146
        bio_read_page(swsusp_resume_block, swsusp_header, NULL);
147
        if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
148
            !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
149
                memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
150
                memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
151
                swsusp_header->image = start;
152
                swsusp_header->flags = flags;
153
                error = bio_write_page(swsusp_resume_block,
154
                                        swsusp_header, NULL);
155
        } else {
156
                printk(KERN_ERR "swsusp: Swap header not found!\n");
157
                error = -ENODEV;
158
        }
159
        return error;
160
}
161
 
162
/**
163
 *      swsusp_swap_check - check if the resume device is a swap device
164
 *      and get its index (if so)
165
 */
166
 
167
static int swsusp_swap_check(void) /* This is called before saving image */
168
{
169
        int res;
170
 
171
        res = swap_type_of(swsusp_resume_device, swsusp_resume_block,
172
                        &resume_bdev);
173
        if (res < 0)
174
                return res;
175
 
176
        root_swap = res;
177
        res = blkdev_get(resume_bdev, FMODE_WRITE, O_RDWR);
178
        if (res)
179
                return res;
180
 
181
        res = set_blocksize(resume_bdev, PAGE_SIZE);
182
        if (res < 0)
183
                blkdev_put(resume_bdev);
184
 
185
        return res;
186
}
187
 
188
/**
189
 *      write_page - Write one page to given swap location.
190
 *      @buf:           Address we're writing.
191
 *      @offset:        Offset of the swap page we're writing to.
192
 *      @bio_chain:     Link the next write BIO here
193
 */
194
 
195
static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
196
{
197
        void *src;
198
 
199
        if (!offset)
200
                return -ENOSPC;
201
 
202
        if (bio_chain) {
203
                src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
204
                if (src) {
205
                        memcpy(src, buf, PAGE_SIZE);
206
                } else {
207
                        WARN_ON_ONCE(1);
208
                        bio_chain = NULL;       /* Go synchronous */
209
                        src = buf;
210
                }
211
        } else {
212
                src = buf;
213
        }
214
        return bio_write_page(offset, src, bio_chain);
215
}
216
 
217
/*
218
 *      The swap map is a data structure used for keeping track of each page
219
 *      written to a swap partition.  It consists of many swap_map_page
220
 *      structures that contain each an array of MAP_PAGE_SIZE swap entries.
221
 *      These structures are stored on the swap and linked together with the
222
 *      help of the .next_swap member.
223
 *
224
 *      The swap map is created during suspend.  The swap map pages are
225
 *      allocated and populated one at a time, so we only need one memory
226
 *      page to set up the entire structure.
227
 *
228
 *      During resume we also only need to use one swap_map_page structure
229
 *      at a time.
230
 */
231
 
232
#define MAP_PAGE_ENTRIES        (PAGE_SIZE / sizeof(sector_t) - 1)
233
 
234
struct swap_map_page {
235
        sector_t entries[MAP_PAGE_ENTRIES];
236
        sector_t next_swap;
237
};
238
 
239
/**
240
 *      The swap_map_handle structure is used for handling swap in
241
 *      a file-alike way
242
 */
243
 
244
struct swap_map_handle {
245
        struct swap_map_page *cur;
246
        sector_t cur_swap;
247
        unsigned int k;
248
};
249
 
250
static void release_swap_writer(struct swap_map_handle *handle)
251
{
252
        if (handle->cur)
253
                free_page((unsigned long)handle->cur);
254
        handle->cur = NULL;
255
}
256
 
257
static int get_swap_writer(struct swap_map_handle *handle)
258
{
259
        handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
260
        if (!handle->cur)
261
                return -ENOMEM;
262
        handle->cur_swap = alloc_swapdev_block(root_swap);
263
        if (!handle->cur_swap) {
264
                release_swap_writer(handle);
265
                return -ENOSPC;
266
        }
267
        handle->k = 0;
268
        return 0;
269
}
270
 
271
static int swap_write_page(struct swap_map_handle *handle, void *buf,
272
                                struct bio **bio_chain)
273
{
274
        int error = 0;
275
        sector_t offset;
276
 
277
        if (!handle->cur)
278
                return -EINVAL;
279
        offset = alloc_swapdev_block(root_swap);
280
        error = write_page(buf, offset, bio_chain);
281
        if (error)
282
                return error;
283
        handle->cur->entries[handle->k++] = offset;
284
        if (handle->k >= MAP_PAGE_ENTRIES) {
285
                error = wait_on_bio_chain(bio_chain);
286
                if (error)
287
                        goto out;
288
                offset = alloc_swapdev_block(root_swap);
289
                if (!offset)
290
                        return -ENOSPC;
291
                handle->cur->next_swap = offset;
292
                error = write_page(handle->cur, handle->cur_swap, NULL);
293
                if (error)
294
                        goto out;
295
                memset(handle->cur, 0, PAGE_SIZE);
296
                handle->cur_swap = offset;
297
                handle->k = 0;
298
        }
299
 out:
300
        return error;
301
}
302
 
303
static int flush_swap_writer(struct swap_map_handle *handle)
304
{
305
        if (handle->cur && handle->cur_swap)
306
                return write_page(handle->cur, handle->cur_swap, NULL);
307
        else
308
                return -EINVAL;
309
}
310
 
311
/**
312
 *      save_image - save the suspend image data
313
 */
314
 
315
static int save_image(struct swap_map_handle *handle,
316
                      struct snapshot_handle *snapshot,
317
                      unsigned int nr_to_write)
318
{
319
        unsigned int m;
320
        int ret;
321
        int error = 0;
322
        int nr_pages;
323
        int err2;
324
        struct bio *bio;
325
        struct timeval start;
326
        struct timeval stop;
327
 
328
        printk("Saving image data pages (%u pages) ...     ", nr_to_write);
329
        m = nr_to_write / 100;
330
        if (!m)
331
                m = 1;
332
        nr_pages = 0;
333
        bio = NULL;
334
        do_gettimeofday(&start);
335
        do {
336
                ret = snapshot_read_next(snapshot, PAGE_SIZE);
337
                if (ret > 0) {
338
                        error = swap_write_page(handle, data_of(*snapshot),
339
                                                &bio);
340
                        if (error)
341
                                break;
342
                        if (!(nr_pages % m))
343
                                printk("\b\b\b\b%3d%%", nr_pages / m);
344
                        nr_pages++;
345
                }
346
        } while (ret > 0);
347
        err2 = wait_on_bio_chain(&bio);
348
        do_gettimeofday(&stop);
349
        if (!error)
350
                error = err2;
351
        if (!error)
352
                printk("\b\b\b\bdone\n");
353
        swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
354
        return error;
355
}
356
 
357
/**
358
 *      enough_swap - Make sure we have enough swap to save the image.
359
 *
360
 *      Returns TRUE or FALSE after checking the total amount of swap
361
 *      space avaiable from the resume partition.
362
 */
363
 
364
static int enough_swap(unsigned int nr_pages)
365
{
366
        unsigned int free_swap = count_swap_pages(root_swap, 1);
367
 
368
        pr_debug("swsusp: free swap pages: %u\n", free_swap);
369
        return free_swap > nr_pages + PAGES_FOR_IO;
370
}
371
 
372
/**
373
 *      swsusp_write - Write entire image and metadata.
374
 *      @flags: flags to pass to the "boot" kernel in the image header
375
 *
376
 *      It is important _NOT_ to umount filesystems at this point. We want
377
 *      them synced (in case something goes wrong) but we DO not want to mark
378
 *      filesystem clean: it is not. (And it does not matter, if we resume
379
 *      correctly, we'll mark system clean, anyway.)
380
 */
381
 
382
int swsusp_write(unsigned int flags)
383
{
384
        struct swap_map_handle handle;
385
        struct snapshot_handle snapshot;
386
        struct swsusp_info *header;
387
        int error;
388
 
389
        error = swsusp_swap_check();
390
        if (error) {
391
                printk(KERN_ERR "swsusp: Cannot find swap device, try "
392
                                "swapon -a.\n");
393
                return error;
394
        }
395
        memset(&snapshot, 0, sizeof(struct snapshot_handle));
396
        error = snapshot_read_next(&snapshot, PAGE_SIZE);
397
        if (error < PAGE_SIZE) {
398
                if (error >= 0)
399
                        error = -EFAULT;
400
 
401
                goto out;
402
        }
403
        header = (struct swsusp_info *)data_of(snapshot);
404
        if (!enough_swap(header->pages)) {
405
                printk(KERN_ERR "swsusp: Not enough free swap\n");
406
                error = -ENOSPC;
407
                goto out;
408
        }
409
        error = get_swap_writer(&handle);
410
        if (!error) {
411
                sector_t start = handle.cur_swap;
412
 
413
                error = swap_write_page(&handle, header, NULL);
414
                if (!error)
415
                        error = save_image(&handle, &snapshot,
416
                                        header->pages - 1);
417
 
418
                if (!error) {
419
                        flush_swap_writer(&handle);
420
                        printk("S");
421
                        error = mark_swapfiles(start, flags);
422
                        printk("|\n");
423
                }
424
        }
425
        if (error)
426
                free_all_swap_pages(root_swap);
427
 
428
        release_swap_writer(&handle);
429
 out:
430
        swsusp_close();
431
        return error;
432
}
433
 
434
/**
435
 *      The following functions allow us to read data using a swap map
436
 *      in a file-alike way
437
 */
438
 
439
static void release_swap_reader(struct swap_map_handle *handle)
440
{
441
        if (handle->cur)
442
                free_page((unsigned long)handle->cur);
443
        handle->cur = NULL;
444
}
445
 
446
static int get_swap_reader(struct swap_map_handle *handle, sector_t start)
447
{
448
        int error;
449
 
450
        if (!start)
451
                return -EINVAL;
452
 
453
        handle->cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
454
        if (!handle->cur)
455
                return -ENOMEM;
456
 
457
        error = bio_read_page(start, handle->cur, NULL);
458
        if (error) {
459
                release_swap_reader(handle);
460
                return error;
461
        }
462
        handle->k = 0;
463
        return 0;
464
}
465
 
466
static int swap_read_page(struct swap_map_handle *handle, void *buf,
467
                                struct bio **bio_chain)
468
{
469
        sector_t offset;
470
        int error;
471
 
472
        if (!handle->cur)
473
                return -EINVAL;
474
        offset = handle->cur->entries[handle->k];
475
        if (!offset)
476
                return -EFAULT;
477
        error = bio_read_page(offset, buf, bio_chain);
478
        if (error)
479
                return error;
480
        if (++handle->k >= MAP_PAGE_ENTRIES) {
481
                error = wait_on_bio_chain(bio_chain);
482
                handle->k = 0;
483
                offset = handle->cur->next_swap;
484
                if (!offset)
485
                        release_swap_reader(handle);
486
                else if (!error)
487
                        error = bio_read_page(offset, handle->cur, NULL);
488
        }
489
        return error;
490
}
491
 
492
/**
493
 *      load_image - load the image using the swap map handle
494
 *      @handle and the snapshot handle @snapshot
495
 *      (assume there are @nr_pages pages to load)
496
 */
497
 
498
static int load_image(struct swap_map_handle *handle,
499
                      struct snapshot_handle *snapshot,
500
                      unsigned int nr_to_read)
501
{
502
        unsigned int m;
503
        int error = 0;
504
        struct timeval start;
505
        struct timeval stop;
506
        struct bio *bio;
507
        int err2;
508
        unsigned nr_pages;
509
 
510
        printk("Loading image data pages (%u pages) ...     ", nr_to_read);
511
        m = nr_to_read / 100;
512
        if (!m)
513
                m = 1;
514
        nr_pages = 0;
515
        bio = NULL;
516
        do_gettimeofday(&start);
517
        for ( ; ; ) {
518
                error = snapshot_write_next(snapshot, PAGE_SIZE);
519
                if (error <= 0)
520
                        break;
521
                error = swap_read_page(handle, data_of(*snapshot), &bio);
522
                if (error)
523
                        break;
524
                if (snapshot->sync_read)
525
                        error = wait_on_bio_chain(&bio);
526
                if (error)
527
                        break;
528
                if (!(nr_pages % m))
529
                        printk("\b\b\b\b%3d%%", nr_pages / m);
530
                nr_pages++;
531
        }
532
        err2 = wait_on_bio_chain(&bio);
533
        do_gettimeofday(&stop);
534
        if (!error)
535
                error = err2;
536
        if (!error) {
537
                printk("\b\b\b\bdone\n");
538
                snapshot_write_finalize(snapshot);
539
                if (!snapshot_image_loaded(snapshot))
540
                        error = -ENODATA;
541
        }
542
        swsusp_show_speed(&start, &stop, nr_to_read, "Read");
543
        return error;
544
}
545
 
546
/**
547
 *      swsusp_read - read the hibernation image.
548
 *      @flags_p: flags passed by the "frozen" kernel in the image header should
549
 *                be written into this memeory location
550
 */
551
 
552
int swsusp_read(unsigned int *flags_p)
553
{
554
        int error;
555
        struct swap_map_handle handle;
556
        struct snapshot_handle snapshot;
557
        struct swsusp_info *header;
558
 
559
        *flags_p = swsusp_header->flags;
560
        if (IS_ERR(resume_bdev)) {
561
                pr_debug("swsusp: block device not initialised\n");
562
                return PTR_ERR(resume_bdev);
563
        }
564
 
565
        memset(&snapshot, 0, sizeof(struct snapshot_handle));
566
        error = snapshot_write_next(&snapshot, PAGE_SIZE);
567
        if (error < PAGE_SIZE)
568
                return error < 0 ? error : -EFAULT;
569
        header = (struct swsusp_info *)data_of(snapshot);
570
        error = get_swap_reader(&handle, swsusp_header->image);
571
        if (!error)
572
                error = swap_read_page(&handle, header, NULL);
573
        if (!error)
574
                error = load_image(&handle, &snapshot, header->pages - 1);
575
        release_swap_reader(&handle);
576
 
577
        blkdev_put(resume_bdev);
578
 
579
        if (!error)
580
                pr_debug("swsusp: Reading resume file was successful\n");
581
        else
582
                pr_debug("swsusp: Error %d resuming\n", error);
583
        return error;
584
}
585
 
586
/**
587
 *      swsusp_check - Check for swsusp signature in the resume device
588
 */
589
 
590
int swsusp_check(void)
591
{
592
        int error;
593
 
594
        resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
595
        if (!IS_ERR(resume_bdev)) {
596
                set_blocksize(resume_bdev, PAGE_SIZE);
597
                memset(swsusp_header, 0, PAGE_SIZE);
598
                error = bio_read_page(swsusp_resume_block,
599
                                        swsusp_header, NULL);
600
                if (error)
601
                        return error;
602
 
603
                if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
604
                        memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
605
                        /* Reset swap signature now */
606
                        error = bio_write_page(swsusp_resume_block,
607
                                                swsusp_header, NULL);
608
                } else {
609
                        return -EINVAL;
610
                }
611
                if (error)
612
                        blkdev_put(resume_bdev);
613
                else
614
                        pr_debug("swsusp: Signature found, resuming\n");
615
        } else {
616
                error = PTR_ERR(resume_bdev);
617
        }
618
 
619
        if (error)
620
                pr_debug("swsusp: Error %d check for resume file\n", error);
621
 
622
        return error;
623
}
624
 
625
/**
626
 *      swsusp_close - close swap device.
627
 */
628
 
629
void swsusp_close(void)
630
{
631
        if (IS_ERR(resume_bdev)) {
632
                pr_debug("swsusp: block device not initialised\n");
633
                return;
634
        }
635
 
636
        blkdev_put(resume_bdev);
637
}
638
 
639
static int swsusp_header_init(void)
640
{
641
        swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
642
        if (!swsusp_header)
643
                panic("Could not allocate memory for swsusp_header\n");
644
        return 0;
645
}
646
 
647
core_initcall(swsusp_header_init);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.