diff options
Diffstat (limited to 'kernel/power/snapshot.c')
| -rw-r--r-- | kernel/power/snapshot.c | 88 |
1 files changed, 21 insertions, 67 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 5f91a07c4eac..5d2ab836e998 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -205,8 +205,7 @@ static void chain_free(struct chain_allocator *ca, int clear_page_nosave) | |||
| 205 | * objects. The main list's elements are of type struct zone_bitmap | 205 | * objects. The main list's elements are of type struct zone_bitmap |
| 206 | * and each of them corresonds to one zone. For each zone bitmap | 206 | * and each of them corresonds to one zone. For each zone bitmap |
| 207 | * object there is a list of objects of type struct bm_block that | 207 | * object there is a list of objects of type struct bm_block that |
| 208 | * represent each blocks of bit chunks in which information is | 208 | * represent each blocks of bitmap in which information is stored. |
| 209 | * stored. | ||
| 210 | * | 209 | * |
| 211 | * struct memory_bitmap contains a pointer to the main list of zone | 210 | * struct memory_bitmap contains a pointer to the main list of zone |
| 212 | * bitmap objects, a struct bm_position used for browsing the bitmap, | 211 | * bitmap objects, a struct bm_position used for browsing the bitmap, |
| @@ -224,26 +223,27 @@ static void chain_free(struct chain_allocator *ca, int clear_page_nosave) | |||
| 224 | * pfns that correspond to the start and end of the represented zone. | 223 | * pfns that correspond to the start and end of the represented zone. |
| 225 | * | 224 | * |
| 226 | * struct bm_block contains a pointer to the memory page in which | 225 | * struct bm_block contains a pointer to the memory page in which |
| 227 | * information is stored (in the form of a block of bit chunks | 226 | * information is stored (in the form of a block of bitmap) |
| 228 | * of type unsigned long each). It also contains the pfns that | 227 | * It also contains the pfns that correspond to the start and end of |
| 229 | * correspond to the start and end of the represented memory area and | 228 | * the represented memory area. |
| 230 | * the number of bit chunks in the block. | ||
| 231 | */ | 229 | */ |
| 232 | 230 | ||
| 233 | #define BM_END_OF_MAP (~0UL) | 231 | #define BM_END_OF_MAP (~0UL) |
| 234 | 232 | ||
| 235 | #define BM_CHUNKS_PER_BLOCK (PAGE_SIZE / sizeof(long)) | ||
| 236 | #define BM_BITS_PER_CHUNK (sizeof(long) << 3) | ||
| 237 | #define BM_BITS_PER_BLOCK (PAGE_SIZE << 3) | 233 | #define BM_BITS_PER_BLOCK (PAGE_SIZE << 3) |
| 238 | 234 | ||
| 239 | struct bm_block { | 235 | struct bm_block { |
| 240 | struct bm_block *next; /* next element of the list */ | 236 | struct bm_block *next; /* next element of the list */ |
| 241 | unsigned long start_pfn; /* pfn represented by the first bit */ | 237 | unsigned long start_pfn; /* pfn represented by the first bit */ |
| 242 | unsigned long end_pfn; /* pfn represented by the last bit plus 1 */ | 238 | unsigned long end_pfn; /* pfn represented by the last bit plus 1 */ |
| 243 | unsigned int size; /* number of bit chunks */ | 239 | unsigned long *data; /* bitmap representing pages */ |
| 244 | unsigned long *data; /* chunks of bits representing pages */ | ||
| 245 | }; | 240 | }; |
| 246 | 241 | ||
| 242 | static inline unsigned long bm_block_bits(struct bm_block *bb) | ||
| 243 | { | ||
| 244 | return bb->end_pfn - bb->start_pfn; | ||
| 245 | } | ||
| 246 | |||
| 247 | struct zone_bitmap { | 247 | struct zone_bitmap { |
| 248 | struct zone_bitmap *next; /* next element of the list */ | 248 | struct zone_bitmap *next; /* next element of the list */ |
| 249 | unsigned long start_pfn; /* minimal pfn in this zone */ | 249 | unsigned long start_pfn; /* minimal pfn in this zone */ |
| @@ -257,7 +257,6 @@ struct zone_bitmap { | |||
| 257 | struct bm_position { | 257 | struct bm_position { |
| 258 | struct zone_bitmap *zone_bm; | 258 | struct zone_bitmap *zone_bm; |
| 259 | struct bm_block *block; | 259 | struct bm_block *block; |
| 260 | int chunk; | ||
| 261 | int bit; | 260 | int bit; |
| 262 | }; | 261 | }; |
| 263 | 262 | ||
| @@ -272,12 +271,6 @@ struct memory_bitmap { | |||
| 272 | 271 | ||
| 273 | /* Functions that operate on memory bitmaps */ | 272 | /* Functions that operate on memory bitmaps */ |
| 274 | 273 | ||
| 275 | static inline void memory_bm_reset_chunk(struct memory_bitmap *bm) | ||
| 276 | { | ||
| 277 | bm->cur.chunk = 0; | ||
| 278 | bm->cur.bit = -1; | ||
| 279 | } | ||
| 280 | |||
| 281 | static void memory_bm_position_reset(struct memory_bitmap *bm) | 274 | static void memory_bm_position_reset(struct memory_bitmap *bm) |
| 282 | { | 275 | { |
| 283 | struct zone_bitmap *zone_bm; | 276 | struct zone_bitmap *zone_bm; |
| @@ -285,7 +278,7 @@ static void memory_bm_position_reset(struct memory_bitmap *bm) | |||
| 285 | zone_bm = bm->zone_bm_list; | 278 | zone_bm = bm->zone_bm_list; |
| 286 | bm->cur.zone_bm = zone_bm; | 279 | bm->cur.zone_bm = zone_bm; |
| 287 | bm->cur.block = zone_bm->bm_blocks; | 280 | bm->cur.block = zone_bm->bm_blocks; |
| 288 | memory_bm_reset_chunk(bm); | 281 | bm->cur.bit = 0; |
| 289 | } | 282 | } |
| 290 | 283 | ||
| 291 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); | 284 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); |
| @@ -394,12 +387,10 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) | |||
| 394 | bb->start_pfn = pfn; | 387 | bb->start_pfn = pfn; |
| 395 | if (nr >= BM_BITS_PER_BLOCK) { | 388 | if (nr >= BM_BITS_PER_BLOCK) { |
| 396 | pfn += BM_BITS_PER_BLOCK; | 389 | pfn += BM_BITS_PER_BLOCK; |
| 397 | bb->size = BM_CHUNKS_PER_BLOCK; | ||
| 398 | nr -= BM_BITS_PER_BLOCK; | 390 | nr -= BM_BITS_PER_BLOCK; |
| 399 | } else { | 391 | } else { |
| 400 | /* This is executed only once in the loop */ | 392 | /* This is executed only once in the loop */ |
| 401 | pfn += nr; | 393 | pfn += nr; |
| 402 | bb->size = DIV_ROUND_UP(nr, BM_BITS_PER_CHUNK); | ||
| 403 | } | 394 | } |
| 404 | bb->end_pfn = pfn; | 395 | bb->end_pfn = pfn; |
| 405 | bb = bb->next; | 396 | bb = bb->next; |
| @@ -478,8 +469,8 @@ static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, | |||
| 478 | } | 469 | } |
| 479 | zone_bm->cur_block = bb; | 470 | zone_bm->cur_block = bb; |
| 480 | pfn -= bb->start_pfn; | 471 | pfn -= bb->start_pfn; |
| 481 | *bit_nr = pfn % BM_BITS_PER_CHUNK; | 472 | *bit_nr = pfn; |
| 482 | *addr = bb->data + pfn / BM_BITS_PER_CHUNK; | 473 | *addr = bb->data; |
| 483 | return 0; | 474 | return 0; |
| 484 | } | 475 | } |
| 485 | 476 | ||
| @@ -528,36 +519,6 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) | |||
| 528 | return test_bit(bit, addr); | 519 | return test_bit(bit, addr); |
| 529 | } | 520 | } |
| 530 | 521 | ||
| 531 | /* Two auxiliary functions for memory_bm_next_pfn */ | ||
| 532 | |||
| 533 | /* Find the first set bit in the given chunk, if there is one */ | ||
| 534 | |||
| 535 | static inline int next_bit_in_chunk(int bit, unsigned long *chunk_p) | ||
| 536 | { | ||
| 537 | bit++; | ||
| 538 | while (bit < BM_BITS_PER_CHUNK) { | ||
| 539 | if (test_bit(bit, chunk_p)) | ||
| 540 | return bit; | ||
| 541 | |||
| 542 | bit++; | ||
| 543 | } | ||
| 544 | return -1; | ||
| 545 | } | ||
| 546 | |||
| 547 | /* Find a chunk containing some bits set in given block of bits */ | ||
| 548 | |||
| 549 | static inline int next_chunk_in_block(int n, struct bm_block *bb) | ||
| 550 | { | ||
| 551 | n++; | ||
| 552 | while (n < bb->size) { | ||
| 553 | if (bb->data[n]) | ||
| 554 | return n; | ||
| 555 | |||
| 556 | n++; | ||
| 557 | } | ||
| 558 | return -1; | ||
| 559 | } | ||
| 560 | |||
| 561 | /** | 522 | /** |
| 562 | * memory_bm_next_pfn - find the pfn that corresponds to the next set bit | 523 | * memory_bm_next_pfn - find the pfn that corresponds to the next set bit |
| 563 | * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is | 524 | * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is |
| @@ -571,40 +532,33 @@ static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) | |||
| 571 | { | 532 | { |
| 572 | struct zone_bitmap *zone_bm; | 533 | struct zone_bitmap *zone_bm; |
| 573 | struct bm_block *bb; | 534 | struct bm_block *bb; |
| 574 | int chunk; | ||
| 575 | int bit; | 535 | int bit; |
| 576 | 536 | ||
| 577 | do { | 537 | do { |
| 578 | bb = bm->cur.block; | 538 | bb = bm->cur.block; |
| 579 | do { | 539 | do { |
| 580 | chunk = bm->cur.chunk; | ||
| 581 | bit = bm->cur.bit; | 540 | bit = bm->cur.bit; |
| 582 | do { | 541 | bit = find_next_bit(bb->data, bm_block_bits(bb), bit); |
| 583 | bit = next_bit_in_chunk(bit, bb->data + chunk); | 542 | if (bit < bm_block_bits(bb)) |
| 584 | if (bit >= 0) | 543 | goto Return_pfn; |
| 585 | goto Return_pfn; | 544 | |
| 586 | |||
| 587 | chunk = next_chunk_in_block(chunk, bb); | ||
| 588 | bit = -1; | ||
| 589 | } while (chunk >= 0); | ||
| 590 | bb = bb->next; | 545 | bb = bb->next; |
| 591 | bm->cur.block = bb; | 546 | bm->cur.block = bb; |
| 592 | memory_bm_reset_chunk(bm); | 547 | bm->cur.bit = 0; |
| 593 | } while (bb); | 548 | } while (bb); |
| 594 | zone_bm = bm->cur.zone_bm->next; | 549 | zone_bm = bm->cur.zone_bm->next; |
| 595 | if (zone_bm) { | 550 | if (zone_bm) { |
| 596 | bm->cur.zone_bm = zone_bm; | 551 | bm->cur.zone_bm = zone_bm; |
| 597 | bm->cur.block = zone_bm->bm_blocks; | 552 | bm->cur.block = zone_bm->bm_blocks; |
| 598 | memory_bm_reset_chunk(bm); | 553 | bm->cur.bit = 0; |
| 599 | } | 554 | } |
| 600 | } while (zone_bm); | 555 | } while (zone_bm); |
| 601 | memory_bm_position_reset(bm); | 556 | memory_bm_position_reset(bm); |
| 602 | return BM_END_OF_MAP; | 557 | return BM_END_OF_MAP; |
| 603 | 558 | ||
| 604 | Return_pfn: | 559 | Return_pfn: |
| 605 | bm->cur.chunk = chunk; | 560 | bm->cur.bit = bit + 1; |
| 606 | bm->cur.bit = bit; | 561 | return bb->start_pfn + bit; |
| 607 | return bb->start_pfn + chunk * BM_BITS_PER_CHUNK + bit; | ||
| 608 | } | 562 | } |
| 609 | 563 | ||
| 610 | /** | 564 | /** |
