summaryrefslogtreecommitdiff
path: root/mm/zbud.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/zbud.c')
-rw-r--r--mm/zbud.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/mm/zbud.c b/mm/zbud.c
index d8a181fd779b..09ab957e2b10 100644
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -357,13 +357,15 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
struct zbud_header *zhdr = NULL;
enum buddy bud;
struct page *page;
+ unsigned long flags;
+ int found = 0;
if (!size || (gfp & __GFP_HIGHMEM))
return -EINVAL;
if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
return -ENOSPC;
chunks = size_to_chunks(size);
- spin_lock(&pool->lock);
+ spin_lock_irqsave(&pool->lock, flags);
/* First, try to find an unbuddied zbud page. */
zhdr = NULL;
@@ -376,16 +378,17 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
bud = FIRST;
else
bud = LAST;
+ found = 1;
goto found;
}
}
/* Couldn't find unbuddied zbud page, create new one */
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
page = alloc_page(gfp);
if (!page)
return -ENOMEM;
- spin_lock(&pool->lock);
+ spin_lock_irqsave(&pool->lock, flags);
pool->pages_nr++;
zhdr = init_zbud_page(page);
bud = FIRST;
@@ -411,7 +414,9 @@ found:
list_add(&zhdr->lru, &pool->lru);
*handle = encode_handle(zhdr, bud);
- spin_unlock(&pool->lock);
+ if ((gfp & __GFP_ZERO) && found)
+ memset((void *)*handle, 0, size);
+ spin_unlock_irqrestore(&pool->lock, flags);
return 0;
}
@@ -430,8 +435,9 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
{
struct zbud_header *zhdr;
int freechunks;
+ unsigned long flags;
- spin_lock(&pool->lock);
+ spin_lock_irqsave(&pool->lock, flags);
zhdr = handle_to_zbud_header(handle);
/* If first buddy, handle will be page aligned */
@@ -442,7 +448,7 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
if (zhdr->under_reclaim) {
/* zbud page is under reclaim, reclaim will free */
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
return;
}
@@ -460,7 +466,7 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
}
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
}
#define list_tail_entry(ptr, type, member) \
@@ -505,12 +511,13 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
{
int i, ret, freechunks;
struct zbud_header *zhdr;
+ unsigned long flags;
unsigned long first_handle = 0, last_handle = 0;
- spin_lock(&pool->lock);
+ spin_lock_irqsave(&pool->lock, flags);
if (!pool->ops || !pool->ops->evict || list_empty(&pool->lru) ||
retries == 0) {
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
return -EINVAL;
}
for (i = 0; i < retries; i++) {
@@ -529,7 +536,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
first_handle = encode_handle(zhdr, FIRST);
if (zhdr->last_chunks)
last_handle = encode_handle(zhdr, LAST);
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
/* Issue the eviction callback(s) */
if (first_handle) {
@@ -543,7 +550,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
goto next;
}
next:
- spin_lock(&pool->lock);
+ spin_lock_irqsave(&pool->lock, flags);
zhdr->under_reclaim = false;
if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
/*
@@ -552,7 +559,7 @@ next:
*/
free_zbud_page(zhdr);
pool->pages_nr--;
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
return 0;
} else if (zhdr->first_chunks == 0 ||
zhdr->last_chunks == 0) {
@@ -567,7 +574,7 @@ next:
/* add to beginning of LRU */
list_add(&zhdr->lru, &pool->lru);
}
- spin_unlock(&pool->lock);
+ spin_unlock_irqrestore(&pool->lock, flags);
return -EAGAIN;
}