Blame view

kernel/power/block_io.c 2.37 KB
8a0d613fa   Jiri Slaby   PM / Hibernate: S...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  /*
   * This file provides functions for block I/O operations on swap/file.
   *
   * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
   * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
   *
   * This file is released under the GPLv2.
   */
  
  #include <linux/bio.h>
  #include <linux/kernel.h>
  #include <linux/pagemap.h>
  #include <linux/swap.h>
  
  #include "power.h"
  
  /**
   *	submit - submit BIO request.
   *	@rw:	READ or WRITE.
   *	@off	physical offset of page.
   *	@page:	page we're reading or writing.
   *	@bio_chain: list of pending biod (for async reading)
   *
   *	Straight from the textbook - allocate and initialize the bio.
   *	If we're reading, make sure the page is marked as dirty.
   *	Then submit it and, if @bio_chain == NULL, wait.
   */
  static int submit(int rw, struct block_device *bdev, sector_t sector,
  		struct page *page, struct bio **bio_chain)
  {
721a9602e   Jens Axboe   block: kill off R...
31
  	const int bio_rw = rw | REQ_SYNC;
8a0d613fa   Jiri Slaby   PM / Hibernate: S...
32
33
34
35
36
37
38
39
  	struct bio *bio;
  
  	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
  	bio->bi_sector = sector;
  	bio->bi_bdev = bdev;
  	bio->bi_end_io = end_swap_bio_read;
  
  	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
0fef8b1e8   Randy Dunlap   PM / Hibernate: F...
40
41
42
  		printk(KERN_ERR "PM: Adding page to bio failed at %llu
  ",
  			(unsigned long long)sector);
8a0d613fa   Jiri Slaby   PM / Hibernate: S...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  		bio_put(bio);
  		return -EFAULT;
  	}
  
  	lock_page(page);
  	bio_get(bio);
  
  	if (bio_chain == NULL) {
  		submit_bio(bio_rw, bio);
  		wait_on_page_locked(page);
  		if (rw == READ)
  			bio_set_pages_dirty(bio);
  		bio_put(bio);
  	} else {
  		if (rw == READ)
  			get_page(page);	/* These pages are freed later */
  		bio->bi_private = *bio_chain;
  		*bio_chain = bio;
  		submit_bio(bio_rw, bio);
  	}
  	return 0;
  }
  
  int hib_bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
  {
  	return submit(READ, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
  			virt_to_page(addr), bio_chain);
  }
  
  int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
  {
  	return submit(WRITE, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
  			virt_to_page(addr), bio_chain);
  }
  
  int hib_wait_on_bio_chain(struct bio **bio_chain)
  {
  	struct bio *bio;
  	struct bio *next_bio;
  	int ret = 0;
  
  	if (bio_chain == NULL)
  		return 0;
  
  	bio = *bio_chain;
  	if (bio == NULL)
  		return 0;
  	while (bio) {
  		struct page *page;
  
  		next_bio = bio->bi_private;
  		page = bio->bi_io_vec[0].bv_page;
  		wait_on_page_locked(page);
  		if (!PageUptodate(page) || PageError(page))
  			ret = -EIO;
  		put_page(page);
  		bio_put(bio);
  		bio = next_bio;
  	}
  	*bio_chain = NULL;
  	return ret;
  }