pm: hibernation: simplify memory bitmap

This patch simplifies the memory bitmap manipulations.

- remove the member size in struct bm_block

It is not necessary for struct bm_block to have the number of bit chunks that
can be calculated by using end_pfn and start_pfn.

- use find_next_bit() for memory_bm_next_pfn

No need to invent the bitmap library only for the memory bitmap.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Akinobu Mita 2008-07-23 21:28:38 -07:00 committed by Linus Torvalds
parent 8111d1b552
commit 0d83304c7e

View file

@ -205,8 +205,7 @@ static void chain_free(struct chain_allocator *ca, int clear_page_nosave)
* objects. The main list's elements are of type struct zone_bitmap * objects. The main list's elements are of type struct zone_bitmap
* and each of them corresonds to one zone. For each zone bitmap * and each of them corresonds to one zone. For each zone bitmap
* object there is a list of objects of type struct bm_block that * object there is a list of objects of type struct bm_block that
* represent each blocks of bit chunks in which information is * represent each blocks of bitmap in which information is stored.
* stored.
* *
* struct memory_bitmap contains a pointer to the main list of zone * struct memory_bitmap contains a pointer to the main list of zone
* bitmap objects, a struct bm_position used for browsing the bitmap, * 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)
* pfns that correspond to the start and end of the represented zone. * pfns that correspond to the start and end of the represented zone.
* *
* struct bm_block contains a pointer to the memory page in which * struct bm_block contains a pointer to the memory page in which
* information is stored (in the form of a block of bit chunks * information is stored (in the form of a block of bitmap)
* of type unsigned long each). It also contains the pfns that * It also contains the pfns that correspond to the start and end of
* correspond to the start and end of the represented memory area and * the represented memory area.
* the number of bit chunks in the block.
*/ */
#define BM_END_OF_MAP (~0UL) #define BM_END_OF_MAP (~0UL)
#define BM_CHUNKS_PER_BLOCK (PAGE_SIZE / sizeof(long))
#define BM_BITS_PER_CHUNK (sizeof(long) << 3)
#define BM_BITS_PER_BLOCK (PAGE_SIZE << 3) #define BM_BITS_PER_BLOCK (PAGE_SIZE << 3)
struct bm_block { struct bm_block {
struct bm_block *next; /* next element of the list */ struct bm_block *next; /* next element of the list */
unsigned long start_pfn; /* pfn represented by the first bit */ unsigned long start_pfn; /* pfn represented by the first bit */
unsigned long end_pfn; /* pfn represented by the last bit plus 1 */ unsigned long end_pfn; /* pfn represented by the last bit plus 1 */
unsigned int size; /* number of bit chunks */ unsigned long *data; /* bitmap representing pages */
unsigned long *data; /* chunks of bits representing pages */
}; };
static inline unsigned long bm_block_bits(struct bm_block *bb)
{
return bb->end_pfn - bb->start_pfn;
}
struct zone_bitmap { struct zone_bitmap {
struct zone_bitmap *next; /* next element of the list */ struct zone_bitmap *next; /* next element of the list */
unsigned long start_pfn; /* minimal pfn in this zone */ unsigned long start_pfn; /* minimal pfn in this zone */
@ -257,7 +257,6 @@ struct zone_bitmap {
struct bm_position { struct bm_position {
struct zone_bitmap *zone_bm; struct zone_bitmap *zone_bm;
struct bm_block *block; struct bm_block *block;
int chunk;
int bit; int bit;
}; };
@ -272,12 +271,6 @@ struct memory_bitmap {
/* Functions that operate on memory bitmaps */ /* Functions that operate on memory bitmaps */
static inline void memory_bm_reset_chunk(struct memory_bitmap *bm)
{
bm->cur.chunk = 0;
bm->cur.bit = -1;
}
static void memory_bm_position_reset(struct memory_bitmap *bm) static void memory_bm_position_reset(struct memory_bitmap *bm)
{ {
struct zone_bitmap *zone_bm; struct zone_bitmap *zone_bm;
@ -285,7 +278,7 @@ static void memory_bm_position_reset(struct memory_bitmap *bm)
zone_bm = bm->zone_bm_list; zone_bm = bm->zone_bm_list;
bm->cur.zone_bm = zone_bm; bm->cur.zone_bm = zone_bm;
bm->cur.block = zone_bm->bm_blocks; bm->cur.block = zone_bm->bm_blocks;
memory_bm_reset_chunk(bm); bm->cur.bit = 0;
} }
static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); 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)
bb->start_pfn = pfn; bb->start_pfn = pfn;
if (nr >= BM_BITS_PER_BLOCK) { if (nr >= BM_BITS_PER_BLOCK) {
pfn += BM_BITS_PER_BLOCK; pfn += BM_BITS_PER_BLOCK;
bb->size = BM_CHUNKS_PER_BLOCK;
nr -= BM_BITS_PER_BLOCK; nr -= BM_BITS_PER_BLOCK;
} else { } else {
/* This is executed only once in the loop */ /* This is executed only once in the loop */
pfn += nr; pfn += nr;
bb->size = DIV_ROUND_UP(nr, BM_BITS_PER_CHUNK);
} }
bb->end_pfn = pfn; bb->end_pfn = pfn;
bb = bb->next; bb = bb->next;
@ -478,8 +469,8 @@ static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
} }
zone_bm->cur_block = bb; zone_bm->cur_block = bb;
pfn -= bb->start_pfn; pfn -= bb->start_pfn;
*bit_nr = pfn % BM_BITS_PER_CHUNK; *bit_nr = pfn;
*addr = bb->data + pfn / BM_BITS_PER_CHUNK; *addr = bb->data;
return 0; return 0;
} }
@ -528,36 +519,6 @@ static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
return test_bit(bit, addr); return test_bit(bit, addr);
} }
/* Two auxiliary functions for memory_bm_next_pfn */
/* Find the first set bit in the given chunk, if there is one */
static inline int next_bit_in_chunk(int bit, unsigned long *chunk_p)
{
bit++;
while (bit < BM_BITS_PER_CHUNK) {
if (test_bit(bit, chunk_p))
return bit;
bit++;
}
return -1;
}
/* Find a chunk containing some bits set in given block of bits */
static inline int next_chunk_in_block(int n, struct bm_block *bb)
{
n++;
while (n < bb->size) {
if (bb->data[n])
return n;
n++;
}
return -1;
}
/** /**
* memory_bm_next_pfn - find the pfn that corresponds to the next set bit * memory_bm_next_pfn - find the pfn that corresponds to the next set bit
* in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is * 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)
{ {
struct zone_bitmap *zone_bm; struct zone_bitmap *zone_bm;
struct bm_block *bb; struct bm_block *bb;
int chunk;
int bit; int bit;
do { do {
bb = bm->cur.block; bb = bm->cur.block;
do { do {
chunk = bm->cur.chunk;
bit = bm->cur.bit; bit = bm->cur.bit;
do { bit = find_next_bit(bb->data, bm_block_bits(bb), bit);
bit = next_bit_in_chunk(bit, bb->data + chunk); if (bit < bm_block_bits(bb))
if (bit >= 0)
goto Return_pfn; goto Return_pfn;
chunk = next_chunk_in_block(chunk, bb);
bit = -1;
} while (chunk >= 0);
bb = bb->next; bb = bb->next;
bm->cur.block = bb; bm->cur.block = bb;
memory_bm_reset_chunk(bm); bm->cur.bit = 0;
} while (bb); } while (bb);
zone_bm = bm->cur.zone_bm->next; zone_bm = bm->cur.zone_bm->next;
if (zone_bm) { if (zone_bm) {
bm->cur.zone_bm = zone_bm; bm->cur.zone_bm = zone_bm;
bm->cur.block = zone_bm->bm_blocks; bm->cur.block = zone_bm->bm_blocks;
memory_bm_reset_chunk(bm); bm->cur.bit = 0;
} }
} while (zone_bm); } while (zone_bm);
memory_bm_position_reset(bm); memory_bm_position_reset(bm);
return BM_END_OF_MAP; return BM_END_OF_MAP;
Return_pfn: Return_pfn:
bm->cur.chunk = chunk; bm->cur.bit = bit + 1;
bm->cur.bit = bit; return bb->start_pfn + bit;
return bb->start_pfn + chunk * BM_BITS_PER_CHUNK + bit;
} }
/** /**