Messages in this thread Patch in this message | | | Date | Fri, 14 Dec 2001 19:14:54 +0100 (CET) | From | Ingo Molnar <> | Subject | [patch] mempool-2.5.1-D1 |
| |
there is another thinko in the mempool code, reported by Suparna Bhattacharya. If mempool_alloc() is called from an IRQ context then we return too early. The correct behavior is to allocate GFP_ATOMIC, if that fails then we look at the pool and return an element, or return NULL.
Ingo --- linux/mm/mempool.c.orig Fri Dec 14 16:55:12 2001 +++ linux/mm/mempool.c Fri Dec 14 17:03:52 2001 @@ -176,7 +176,8 @@ * * this function only sleeps if the alloc_fn function sleeps or * returns NULL. Note that due to preallocation, this function - * *never* fails. + * *never* fails when called from process contexts. (it might + * fail if called from an IRQ context.) */ void * mempool_alloc(mempool_t *pool, int gfp_mask) { @@ -185,7 +186,7 @@ struct list_head *tmp; int curr_nr; DECLARE_WAITQUEUE(wait, current); - int gfp_nowait = gfp_mask & ~__GFP_WAIT; + int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); repeat_alloc: element = pool->alloc(gfp_nowait, pool->pool_data); @@ -196,15 +197,11 @@ * If the pool is less than 50% full then try harder * to allocate an element: */ - if (gfp_mask != gfp_nowait) { - if (pool->curr_nr <= pool->min_nr/2) { - element = pool->alloc(gfp_mask, pool->pool_data); - if (likely(element != NULL)) - return element; - } - } else - /* we must not sleep */ - return NULL; + if ((gfp_mask != gfp_nowait) && (pool->curr_nr <= pool->min_nr/2)) { + element = pool->alloc(gfp_mask, pool->pool_data); + if (likely(element != NULL)) + return element; + } /* * Kick the VM at this point. @@ -217,10 +214,12 @@ list_del(tmp); element = tmp; pool->curr_nr--; - spin_unlock_irqrestore(&pool->lock, flags); - - return element; + goto out_unlock; } + /* We must not sleep in the GFP_ATOMIC case */ + if (gfp_mask == gfp_nowait) + goto out_unlock; + add_wait_queue_exclusive(&pool->wait, &wait); set_task_state(current, TASK_UNINTERRUPTIBLE); @@ -236,6 +235,9 @@ remove_wait_queue(&pool->wait, &wait); goto repeat_alloc; +out_unlock: + spin_unlock_irqrestore(&pool->lock, flags); + return element; } /**
| |