[RFC PATCH 4/9] mm/zbud: remove first|last_chunks from zbud_header
From: Heesub Shin
Date: Tue Oct 14 2014 - 08:01:50 EST
The size information of each first and last buddy are stored into
first|last_chunks in struct zbud_header respectively. Put them into
page->private instead of zbud_header.
Signed-off-by: Heesub Shin <heesub.shin@xxxxxxxxxxx>
---
mm/zbud.c | 62 ++++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 36 insertions(+), 26 deletions(-)
diff --git a/mm/zbud.c b/mm/zbud.c
index a2390f6..193ea4f 100644
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -100,13 +100,9 @@ struct zbud_pool {
* struct zbud_header - zbud page metadata occupying the first chunk of each
* zbud page.
* @buddy: links the zbud page into the unbuddied lists in the pool
- * @first_chunks: the size of the first buddy in chunks, 0 if free
- * @last_chunks: the size of the last buddy in chunks, 0 if free
*/
struct zbud_header {
struct list_head buddy;
- unsigned int first_chunks;
- unsigned int last_chunks;
bool under_reclaim;
};
@@ -212,6 +208,17 @@ static int size_to_chunks(size_t size)
return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
}
+static void set_num_chunks(struct page *page, enum buddy bud, size_t chunks)
+{
+ page->private = (page->private & (0xffff << (16 * !bud))) |
+ ((chunks & 0xffff) << (16 * bud));
+}
+
+static size_t get_num_chunks(struct page *page, enum buddy bud)
+{
+ return (page->private >> (16 * bud)) & 0xffff;
+}
+
#define for_each_unbuddied_list(_iter, _begin) \
for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++)
@@ -219,8 +226,8 @@ static int size_to_chunks(size_t size)
static struct zbud_header *init_zbud_page(struct page *page)
{
struct zbud_header *zhdr = page_address(page);
- zhdr->first_chunks = 0;
- zhdr->last_chunks = 0;
+ set_num_chunks(page, FIRST, 0);
+ set_num_chunks(page, LAST, 0);
INIT_LIST_HEAD(&zhdr->buddy);
INIT_LIST_HEAD(&page->lru);
zhdr->under_reclaim = 0;
@@ -240,6 +247,7 @@ static void free_zbud_page(struct zbud_header *zhdr)
static unsigned long encode_handle(struct zbud_header *zhdr, enum buddy bud)
{
unsigned long handle;
+ struct page *page = virt_to_page(zhdr);
/*
* For now, the encoded handle is actually just the pointer to the data
@@ -252,7 +260,8 @@ static unsigned long encode_handle(struct zbud_header *zhdr, enum buddy bud)
/* skip over zbud header */
handle += ZHDR_SIZE_ALIGNED;
else /* bud == LAST */
- handle += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT);
+ handle += PAGE_SIZE -
+ (get_num_chunks(page, LAST) << CHUNK_SHIFT);
return handle;
}
@@ -263,13 +272,14 @@ static struct zbud_header *handle_to_zbud_header(unsigned long handle)
}
/* Returns the number of free chunks in a zbud page */
-static int num_free_chunks(struct zbud_header *zhdr)
+static int num_free_chunks(struct page *page)
{
/*
* Rather than branch for different situations, just use the fact that
* free buddies have a length of zero to simplify everything.
*/
- return NCHUNKS - zhdr->first_chunks - zhdr->last_chunks;
+ return NCHUNKS - get_num_chunks(page, FIRST)
+ - get_num_chunks(page, LAST);
}
/*****************
@@ -366,17 +376,17 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
zhdr = init_zbud_page(page);
found:
- if (zhdr->first_chunks == 0) {
- zhdr->first_chunks = chunks;
+ if (get_num_chunks(page, FIRST) == 0)
bud = FIRST;
- } else {
- zhdr->last_chunks = chunks;
+ else
bud = LAST;
- }
- if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0) {
+ set_num_chunks(page, bud, chunks);
+
+ if (get_num_chunks(page, FIRST) == 0 ||
+ get_num_chunks(page, LAST) == 0) {
/* Add to unbuddied list */
- freechunks = num_free_chunks(zhdr);
+ freechunks = num_free_chunks(page);
list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
}
@@ -413,9 +423,9 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
/* If first buddy, handle will be page aligned */
if ((handle - ZHDR_SIZE_ALIGNED) & ~PAGE_MASK)
- zhdr->last_chunks = 0;
+ set_num_chunks(page, LAST, 0);
else
- zhdr->first_chunks = 0;
+ set_num_chunks(page, FIRST, 0);
if (zhdr->under_reclaim) {
/* zbud page is under reclaim, reclaim will free */
@@ -423,7 +433,8 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
return;
}
- if (num_free_chunks(zhdr) == NCHUNKS) {
+ freechunks = num_free_chunks(page);
+ if (freechunks == NCHUNKS) {
/* Remove from existing unbuddied list */
list_del(&zhdr->buddy);
/* zbud page is empty, free */
@@ -432,7 +443,6 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
pool->pages_nr--;
} else {
/* Add to unbuddied list */
- freechunks = num_free_chunks(zhdr);
list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
}
@@ -503,9 +513,9 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
*/
first_handle = 0;
last_handle = 0;
- if (zhdr->first_chunks)
+ if (get_num_chunks(page, FIRST))
first_handle = encode_handle(zhdr, FIRST);
- if (zhdr->last_chunks)
+ if (get_num_chunks(page, LAST))
last_handle = encode_handle(zhdr, LAST);
spin_unlock(&pool->lock);
@@ -523,7 +533,8 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
next:
spin_lock(&pool->lock);
zhdr->under_reclaim = false;
- if (num_free_chunks(zhdr) == NCHUNKS) {
+ freechunks = num_free_chunks(page);
+ if (freechunks == NCHUNKS) {
/*
* Both buddies are now free, free the zbud page and
* return success.
@@ -532,10 +543,9 @@ next:
pool->pages_nr--;
spin_unlock(&pool->lock);
return 0;
- } else if (zhdr->first_chunks == 0 ||
- zhdr->last_chunks == 0) {
+ } else if (get_num_chunks(page, FIRST) == 0 ||
+ get_num_chunks(page, LAST) == 0) {
/* add to unbuddied list */
- freechunks = num_free_chunks(zhdr);
list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/