Skip to content

Commit

Permalink
z3fold: limit use of stale list for allocation
Browse files Browse the repository at this point in the history
Currently if z3fold couldn't find an unbuddied page it would first try
to pull a page off the stale list.  The problem with this approach is
that we can't 100% guarantee that the page is not processed by the
workqueue thread at the same time unless we run cancel_work_sync() on
it, which we can't do if we're in an atomic context.  So let's just
limit stale list usage to non-atomic contexts only.

Link: http://lkml.kernel.org/r/47ab51e7-e9c1-d30e-ab17-f734dbc3abce@gmail.com
Signed-off-by: Vitaly Vul <vitaly.vul@sony.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: <Oleksiy.Avramchenko@sony.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Vitaly Wool authored and Linus Torvalds committed Apr 6, 2018
1 parent 605ca5e commit 5c9bab5
Showing 1 changed file with 19 additions and 16 deletions.
35 changes: 19 additions & 16 deletions mm/z3fold.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,24 +620,27 @@ static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
bud = FIRST;
}

spin_lock(&pool->stale_lock);
zhdr = list_first_entry_or_null(&pool->stale,
struct z3fold_header, buddy);
/*
* Before allocating a page, let's see if we can take one from the
* stale pages list. cancel_work_sync() can sleep so we must make
* sure it won't be called in case we're in atomic context.
*/
if (zhdr && (can_sleep || !work_pending(&zhdr->work))) {
list_del(&zhdr->buddy);
spin_unlock(&pool->stale_lock);
if (can_sleep)
page = NULL;
if (can_sleep) {
spin_lock(&pool->stale_lock);
zhdr = list_first_entry_or_null(&pool->stale,
struct z3fold_header, buddy);
/*
* Before allocating a page, let's see if we can take one from
* the stale pages list. cancel_work_sync() can sleep so we
* limit this case to the contexts where we can sleep
*/
if (zhdr) {
list_del(&zhdr->buddy);
spin_unlock(&pool->stale_lock);
cancel_work_sync(&zhdr->work);
page = virt_to_page(zhdr);
} else {
spin_unlock(&pool->stale_lock);
page = alloc_page(gfp);
page = virt_to_page(zhdr);
} else {
spin_unlock(&pool->stale_lock);
}
}
if (!page)
page = alloc_page(gfp);

if (!page)
return -ENOMEM;
Expand Down

0 comments on commit 5c9bab5

Please sign in to comment.