Skip to content

Commit

Permalink
z3fold: simplify freeing slots
Browse files Browse the repository at this point in the history
commit fc54886 upstream.

Patch series "z3fold: stability / rt fixes".

Address z3fold stability issues under stress load, primarily in the
reclaim and free aspects.  Besides, it fixes the locking problems that
were only seen in real-time kernel configuration.

This patch (of 3):

There used to be two places in the code where slots could be freed, namely
when freeing the last allocated handle from the slots and when releasing
the z3fold header these slots aree linked to.  The logic to decide on
whether to free certain slots was complicated and error prone in both
functions and it led to failures in RT case.

To fix that, make free_handle() the single point of freeing slots.

Link: https://lkml.kernel.org/r/20201209145151.18994-1-vitaly.wool@konsulko.com
Link: https://lkml.kernel.org/r/20201209145151.18994-2-vitaly.wool@konsulko.com
Signed-off-by: Vitaly Wool <vitaly.wool@konsulko.com>
Tested-by: Mike Galbraith <efault@gmx.de>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
vwool authored and gregkh committed Dec 30, 2020
1 parent e885d1c commit b8b1d4e
Showing 1 changed file with 13 additions and 42 deletions.
55 changes: 13 additions & 42 deletions mm/z3fold.c
Expand Up @@ -90,7 +90,7 @@ struct z3fold_buddy_slots {
* be enough slots to hold all possible variants
*/
unsigned long slot[BUDDY_MASK + 1];
unsigned long pool; /* back link + flags */
unsigned long pool; /* back link */
rwlock_t lock;
};
#define HANDLE_FLAG_MASK (0x03)
Expand Down Expand Up @@ -181,13 +181,6 @@ enum z3fold_page_flags {
PAGE_CLAIMED, /* by either reclaim or free */
};

/*
* handle flags, go under HANDLE_FLAG_MASK
*/
enum z3fold_handle_flags {
HANDLES_ORPHANED = 0,
};

/*
* Forward declarations
*/
Expand Down Expand Up @@ -303,10 +296,9 @@ static inline void put_z3fold_header(struct z3fold_header *zhdr)
z3fold_page_unlock(zhdr);
}

static inline void free_handle(unsigned long handle)
static inline void free_handle(unsigned long handle, struct z3fold_header *zhdr)
{
struct z3fold_buddy_slots *slots;
struct z3fold_header *zhdr;
int i;
bool is_free;

Expand All @@ -316,22 +308,13 @@ static inline void free_handle(unsigned long handle)
if (WARN_ON(*(unsigned long *)handle == 0))
return;

zhdr = handle_to_z3fold_header(handle);
slots = handle_to_slots(handle);
write_lock(&slots->lock);
*(unsigned long *)handle = 0;
if (zhdr->slots == slots) {
write_unlock(&slots->lock);
return; /* simple case, nothing else to do */
}
if (zhdr->slots != slots)
zhdr->foreign_handles--;

/* we are freeing a foreign handle if we are here */
zhdr->foreign_handles--;
is_free = true;
if (!test_bit(HANDLES_ORPHANED, &slots->pool)) {
write_unlock(&slots->lock);
return;
}
for (i = 0; i <= BUDDY_MASK; i++) {
if (slots->slot[i]) {
is_free = false;
Expand All @@ -343,6 +326,8 @@ static inline void free_handle(unsigned long handle)
if (is_free) {
struct z3fold_pool *pool = slots_to_pool(slots);

if (zhdr->slots == slots)
zhdr->slots = NULL;
kmem_cache_free(pool->c_handle, slots);
}
}
Expand Down Expand Up @@ -525,8 +510,6 @@ static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
{
struct page *page = virt_to_page(zhdr);
struct z3fold_pool *pool = zhdr_to_pool(zhdr);
bool is_free = true;
int i;

WARN_ON(!list_empty(&zhdr->buddy));
set_bit(PAGE_STALE, &page->private);
Expand All @@ -536,21 +519,6 @@ static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
list_del_init(&page->lru);
spin_unlock(&pool->lock);

/* If there are no foreign handles, free the handles array */
read_lock(&zhdr->slots->lock);
for (i = 0; i <= BUDDY_MASK; i++) {
if (zhdr->slots->slot[i]) {
is_free = false;
break;
}
}
if (!is_free)
set_bit(HANDLES_ORPHANED, &zhdr->slots->pool);
read_unlock(&zhdr->slots->lock);

if (is_free)
kmem_cache_free(pool->c_handle, zhdr->slots);

if (locked)
z3fold_page_unlock(zhdr);

Expand Down Expand Up @@ -973,6 +941,9 @@ static inline struct z3fold_header *__z3fold_alloc(struct z3fold_pool *pool,
}
}

if (zhdr && !zhdr->slots)
zhdr->slots = alloc_slots(pool,
can_sleep ? GFP_NOIO : GFP_ATOMIC);
return zhdr;
}

Expand Down Expand Up @@ -1270,7 +1241,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
}

if (!page_claimed)
free_handle(handle);
free_handle(handle, zhdr);
if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list)) {
atomic64_dec(&pool->pages_nr);
return;
Expand Down Expand Up @@ -1429,19 +1400,19 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
ret = pool->ops->evict(pool, middle_handle);
if (ret)
goto next;
free_handle(middle_handle);
free_handle(middle_handle, zhdr);
}
if (first_handle) {
ret = pool->ops->evict(pool, first_handle);
if (ret)
goto next;
free_handle(first_handle);
free_handle(first_handle, zhdr);
}
if (last_handle) {
ret = pool->ops->evict(pool, last_handle);
if (ret)
goto next;
free_handle(last_handle);
free_handle(last_handle, zhdr);
}
next:
if (test_bit(PAGE_HEADLESS, &page->private)) {
Expand Down

0 comments on commit b8b1d4e

Please sign in to comment.