lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 14 Oct 2014 20:59:23 +0900
From:	Heesub Shin <heesub.shin@...sung.com>
To:	Andrew Morton <akpm@...ux-foundation.org>,
	Seth Jennings <sjennings@...iantweb.net>
Cc:	Nitin Gupta <ngupta@...are.org>, Dan Streetman <ddstreet@...e.org>,
	linux-mm@...ck.org, linux-kernel@...r.kernel.org,
	Sunae Seo <sunae.seo@...sung.com>,
	Heesub Shin <heesub.shin@...sung.com>
Subject: [RFC PATCH 4/9] mm/zbud: remove first|last_chunks from zbud_header

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@...sung.com>
---
 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@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists