mirror of https://gitee.com/openkylin/linux.git
drm/ttm: Pass GFP flags in order to avoid deadlock.
Commit 7dc19d5a
"drivers: convert shrinkers to new count/scan API" added
deadlock warnings that ttm_page_pool_free() and ttm_dma_page_pool_free()
are currently doing GFP_KERNEL allocation.
But these functions did not get updated to receive gfp_t argument.
This patch explicitly passes sc->gfp_mask or GFP_KERNEL to these functions,
and removes the deadlock warning.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: stable <stable@kernel.org> [2.6.35+]
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
71336e011d
commit
a91576d791
|
@ -297,8 +297,10 @@ static void ttm_pool_update_free_locked(struct ttm_page_pool *pool,
|
||||||
*
|
*
|
||||||
* @pool: to free the pages from
|
* @pool: to free the pages from
|
||||||
* @free_all: If set to true will free all pages in pool
|
* @free_all: If set to true will free all pages in pool
|
||||||
|
* @gfp: GFP flags.
|
||||||
**/
|
**/
|
||||||
static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free)
|
static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free,
|
||||||
|
gfp_t gfp)
|
||||||
{
|
{
|
||||||
unsigned long irq_flags;
|
unsigned long irq_flags;
|
||||||
struct page *p;
|
struct page *p;
|
||||||
|
@ -309,8 +311,7 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free)
|
||||||
if (NUM_PAGES_TO_ALLOC < nr_free)
|
if (NUM_PAGES_TO_ALLOC < nr_free)
|
||||||
npages_to_free = NUM_PAGES_TO_ALLOC;
|
npages_to_free = NUM_PAGES_TO_ALLOC;
|
||||||
|
|
||||||
pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
|
pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), gfp);
|
||||||
GFP_KERNEL);
|
|
||||||
if (!pages_to_free) {
|
if (!pages_to_free) {
|
||||||
pr_err("Failed to allocate memory for pool free operation\n");
|
pr_err("Failed to allocate memory for pool free operation\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -382,9 +383,7 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free)
|
||||||
*
|
*
|
||||||
* XXX: (dchinner) Deadlock warning!
|
* XXX: (dchinner) Deadlock warning!
|
||||||
*
|
*
|
||||||
* ttm_page_pool_free() does memory allocation using GFP_KERNEL. that means
|
* We need to pass sc->gfp_mask to ttm_page_pool_free().
|
||||||
* this can deadlock when called a sc->gfp_mask that is not equal to
|
|
||||||
* GFP_KERNEL.
|
|
||||||
*
|
*
|
||||||
* This code is crying out for a shrinker per pool....
|
* This code is crying out for a shrinker per pool....
|
||||||
*/
|
*/
|
||||||
|
@ -408,7 +407,8 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||||
if (shrink_pages == 0)
|
if (shrink_pages == 0)
|
||||||
break;
|
break;
|
||||||
pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
|
pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
|
||||||
shrink_pages = ttm_page_pool_free(pool, nr_free);
|
shrink_pages = ttm_page_pool_free(pool, nr_free,
|
||||||
|
sc->gfp_mask);
|
||||||
freed += nr_free - shrink_pages;
|
freed += nr_free - shrink_pages;
|
||||||
}
|
}
|
||||||
mutex_unlock(&lock);
|
mutex_unlock(&lock);
|
||||||
|
@ -710,7 +710,7 @@ static void ttm_put_pages(struct page **pages, unsigned npages, int flags,
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&pool->lock, irq_flags);
|
spin_unlock_irqrestore(&pool->lock, irq_flags);
|
||||||
if (npages)
|
if (npages)
|
||||||
ttm_page_pool_free(pool, npages);
|
ttm_page_pool_free(pool, npages, GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -850,7 +850,8 @@ void ttm_page_alloc_fini(void)
|
||||||
ttm_pool_mm_shrink_fini(_manager);
|
ttm_pool_mm_shrink_fini(_manager);
|
||||||
|
|
||||||
for (i = 0; i < NUM_POOLS; ++i)
|
for (i = 0; i < NUM_POOLS; ++i)
|
||||||
ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES);
|
ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES,
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
kobject_put(&_manager->kobj);
|
kobject_put(&_manager->kobj);
|
||||||
_manager = NULL;
|
_manager = NULL;
|
||||||
|
|
|
@ -411,8 +411,10 @@ static void ttm_dma_page_put(struct dma_pool *pool, struct dma_page *d_page)
|
||||||
*
|
*
|
||||||
* @pool: to free the pages from
|
* @pool: to free the pages from
|
||||||
* @nr_free: If set to true will free all pages in pool
|
* @nr_free: If set to true will free all pages in pool
|
||||||
|
* @gfp: GFP flags.
|
||||||
**/
|
**/
|
||||||
static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free)
|
static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free,
|
||||||
|
gfp_t gfp)
|
||||||
{
|
{
|
||||||
unsigned long irq_flags;
|
unsigned long irq_flags;
|
||||||
struct dma_page *dma_p, *tmp;
|
struct dma_page *dma_p, *tmp;
|
||||||
|
@ -430,8 +432,7 @@ static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free)
|
||||||
npages_to_free, nr_free);
|
npages_to_free, nr_free);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
|
pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), gfp);
|
||||||
GFP_KERNEL);
|
|
||||||
|
|
||||||
if (!pages_to_free) {
|
if (!pages_to_free) {
|
||||||
pr_err("%s: Failed to allocate memory for pool free operation\n",
|
pr_err("%s: Failed to allocate memory for pool free operation\n",
|
||||||
|
@ -530,7 +531,7 @@ static void ttm_dma_free_pool(struct device *dev, enum pool_type type)
|
||||||
if (pool->type != type)
|
if (pool->type != type)
|
||||||
continue;
|
continue;
|
||||||
/* Takes a spinlock.. */
|
/* Takes a spinlock.. */
|
||||||
ttm_dma_page_pool_free(pool, FREE_ALL_PAGES);
|
ttm_dma_page_pool_free(pool, FREE_ALL_PAGES, GFP_KERNEL);
|
||||||
WARN_ON(((pool->npages_in_use + pool->npages_free) != 0));
|
WARN_ON(((pool->npages_in_use + pool->npages_free) != 0));
|
||||||
/* This code path is called after _all_ references to the
|
/* This code path is called after _all_ references to the
|
||||||
* struct device has been dropped - so nobody should be
|
* struct device has been dropped - so nobody should be
|
||||||
|
@ -983,7 +984,7 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
|
||||||
|
|
||||||
/* shrink pool if necessary (only on !is_cached pools)*/
|
/* shrink pool if necessary (only on !is_cached pools)*/
|
||||||
if (npages)
|
if (npages)
|
||||||
ttm_dma_page_pool_free(pool, npages);
|
ttm_dma_page_pool_free(pool, npages, GFP_KERNEL);
|
||||||
ttm->state = tt_unpopulated;
|
ttm->state = tt_unpopulated;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
|
EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
|
||||||
|
@ -993,10 +994,7 @@ EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
|
||||||
*
|
*
|
||||||
* XXX: (dchinner) Deadlock warning!
|
* XXX: (dchinner) Deadlock warning!
|
||||||
*
|
*
|
||||||
* ttm_dma_page_pool_free() does GFP_KERNEL memory allocation, and so attention
|
* We need to pass sc->gfp_mask to ttm_dma_page_pool_free().
|
||||||
* needs to be paid to sc->gfp_mask to determine if this can be done or not.
|
|
||||||
* GFP_KERNEL memory allocation in a GFP_ATOMIC reclaim context woul dbe really
|
|
||||||
* bad.
|
|
||||||
*
|
*
|
||||||
* I'm getting sadder as I hear more pathetical whimpers about needing per-pool
|
* I'm getting sadder as I hear more pathetical whimpers about needing per-pool
|
||||||
* shrinkers
|
* shrinkers
|
||||||
|
@ -1030,7 +1028,8 @@ ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||||
if (++idx < pool_offset)
|
if (++idx < pool_offset)
|
||||||
continue;
|
continue;
|
||||||
nr_free = shrink_pages;
|
nr_free = shrink_pages;
|
||||||
shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free);
|
shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free,
|
||||||
|
sc->gfp_mask);
|
||||||
freed += nr_free - shrink_pages;
|
freed += nr_free - shrink_pages;
|
||||||
|
|
||||||
pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n",
|
pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n",
|
||||||
|
|
Loading…
Reference in New Issue