2 * kernel/power/tuxonice_extent.c
4 * Copyright (C) 2003-2007 Nigel Cunningham (nigel at tuxonice net)
6 * Distributed under GPLv2.
8 * These functions encapsulate the manipulation of storage metadata. For
9 * pageflags, we use dynamically allocated bitmaps.
12 #include <linux/module.h>
13 #include <linux/suspend.h>
14 #include "tuxonice_modules.h"
15 #include "tuxonice_extent.h"
16 #include "tuxonice_ui.h"
21 * Returns a free extent. May fail, returning NULL instead.
23 static struct extent *toi_get_extent(void)
25 struct extent *result;
27 if (!(result = toi_kmalloc(2, sizeof(struct extent), TOI_ATOMIC_GFP)))
30 result->minimum = result->maximum = 0;
36 /* toi_put_extent_chain.
38 * Frees a whole chain of extents.
40 void toi_put_extent_chain(struct extent_chain *chain)
47 struct extent *next = this->next;
53 chain->first = chain->last_touched = NULL;
58 * toi_add_to_extent_chain
60 * Add an extent to an existing chain.
62 int toi_add_to_extent_chain(struct extent_chain *chain,
63 unsigned long minimum, unsigned long maximum)
65 struct extent *new_extent = NULL, *start_at;
67 /* Find the right place in the chain */
68 start_at = (chain->last_touched &&
69 (chain->last_touched->minimum < minimum)) ?
70 chain->last_touched : NULL;
72 if (!start_at && chain->first && chain->first->minimum < minimum)
73 start_at = chain->first;
75 while (start_at && start_at->next && start_at->next->minimum < minimum)
76 start_at = start_at->next;
78 if (start_at && start_at->maximum == (minimum - 1)) {
79 start_at->maximum = maximum;
81 /* Merge with the following one? */
83 start_at->maximum + 1 == start_at->next->minimum) {
84 struct extent *to_free = start_at->next;
85 start_at->maximum = start_at->next->maximum;
86 start_at->next = start_at->next->next;
91 chain->last_touched = start_at;
92 chain->size+= (maximum - minimum + 1);
97 new_extent = toi_get_extent();
99 printk("Error unable to append a new extent to the chain.\n");
103 chain->num_extents++;
104 chain->size+= (maximum - minimum + 1);
105 new_extent->minimum = minimum;
106 new_extent->maximum = maximum;
107 new_extent->next = NULL;
109 chain->last_touched = new_extent;
112 struct extent *next = start_at->next;
113 start_at->next = new_extent;
114 new_extent->next = next;
117 new_extent->next = chain->first;
118 chain->first = new_extent;
124 /* toi_serialise_extent_chain
126 * Write a chain in the image.
128 int toi_serialise_extent_chain(struct toi_module_ops *owner,
129 struct extent_chain *chain)
134 if ((ret = toiActiveAllocator->rw_header_chunk(WRITE, owner,
141 if ((ret = toiActiveAllocator->rw_header_chunk(WRITE, owner,
143 2 * sizeof(unsigned long))))
149 if (i != chain->num_extents) {
150 printk(KERN_EMERG "Saved %d extents but chain metadata says there "
151 "should be %d.\n", i, chain->num_extents);
158 /* toi_load_extent_chain
160 * Read back a chain saved in the image.
162 int toi_load_extent_chain(struct extent_chain *chain)
164 struct extent *this, *last = NULL;
167 if ((ret = toiActiveAllocator->rw_header_chunk(READ, NULL,
168 (char *) chain, 2 * sizeof(int)))) {
169 printk("Failed to read size of extent chain.\n");
173 for (i = 0; i < chain->num_extents; i++) {
174 this = toi_kmalloc(3, sizeof(struct extent), TOI_ATOMIC_GFP);
176 printk("Failed to allocate a new extent.\n");
180 if ((ret = toiActiveAllocator->rw_header_chunk(READ, NULL,
181 (char *) this, 2 * sizeof(unsigned long)))) {
182 printk("Failed to an extent.\n");
194 /* toi_extent_state_next
196 * Given a state, progress to the next valid entry. We may begin in an
197 * invalid state, as we do when invoked after extent_state_goto_start below.
199 * When using compression and expected_compression > 0, we let the image size
200 * be larger than storage, so we can validly run out of data to return.
202 unsigned long toi_extent_state_next(struct extent_iterate_state *state)
204 if (state->current_chain == state->num_chains)
207 if (state->current_extent) {
208 if (state->current_offset == state->current_extent->maximum) {
209 if (state->current_extent->next) {
210 state->current_extent = state->current_extent->next;
211 state->current_offset = state->current_extent->minimum;
213 state->current_extent = NULL;
214 state->current_offset = 0;
217 state->current_offset++;
220 while(!state->current_extent) {
221 int chain_num = ++(state->current_chain);
223 if (chain_num == state->num_chains)
226 state->current_extent = (state->chains + chain_num)->first;
228 if (!state->current_extent)
231 state->current_offset = state->current_extent->minimum;
234 return state->current_offset;
237 /* toi_extent_state_goto_start
239 * Find the first valid value in a group of chains.
241 void toi_extent_state_goto_start(struct extent_iterate_state *state)
243 state->current_chain = -1;
244 state->current_extent = NULL;
245 state->current_offset = 0;
248 /* toi_extent_start_save
250 * Given a state and a struct extent_state_store, save the current
251 * position in a format that can be used with relocated chains (at
254 void toi_extent_state_save(struct extent_iterate_state *state,
255 struct extent_iterate_saved_state *saved_state)
257 struct extent *extent;
259 saved_state->chain_num = state->current_chain;
260 saved_state->extent_num = 0;
261 saved_state->offset = state->current_offset;
263 if (saved_state->chain_num == -1)
266 extent = (state->chains + state->current_chain)->first;
268 while (extent != state->current_extent) {
269 saved_state->extent_num++;
270 extent = extent->next;
274 /* toi_extent_start_restore
276 * Restore the position saved by extent_state_save.
278 void toi_extent_state_restore(struct extent_iterate_state *state,
279 struct extent_iterate_saved_state *saved_state)
281 int posn = saved_state->extent_num;
283 if (saved_state->chain_num == -1) {
284 toi_extent_state_goto_start(state);
288 state->current_chain = saved_state->chain_num;
289 state->current_extent = (state->chains + state->current_chain)->first;
290 state->current_offset = saved_state->offset;
293 state->current_extent = state->current_extent->next;
296 #ifdef CONFIG_TOI_EXPORTS
297 EXPORT_SYMBOL_GPL(toi_add_to_extent_chain);
298 EXPORT_SYMBOL_GPL(toi_put_extent_chain);
299 EXPORT_SYMBOL_GPL(toi_load_extent_chain);
300 EXPORT_SYMBOL_GPL(toi_serialise_extent_chain);
301 EXPORT_SYMBOL_GPL(toi_extent_state_save);
302 EXPORT_SYMBOL_GPL(toi_extent_state_restore);
303 EXPORT_SYMBOL_GPL(toi_extent_state_goto_start);
304 EXPORT_SYMBOL_GPL(toi_extent_state_next);