diff options
Diffstat (limited to 'mm/zbud.c')
-rw-r--r-- | mm/zbud.c | 33 |
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; } |