Skip to content

Commit fc54886

Browse files
vwooltorvalds
authored andcommitted
z3fold: simplify freeing slots
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>
1 parent 2484be0 commit fc54886

File tree

1 file changed

+13
-42
lines changed

1 file changed

+13
-42
lines changed

mm/z3fold.c

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ struct z3fold_buddy_slots {
9090
* be enough slots to hold all possible variants
9191
*/
9292
unsigned long slot[BUDDY_MASK + 1];
93-
unsigned long pool; /* back link + flags */
93+
unsigned long pool; /* back link */
9494
rwlock_t lock;
9595
};
9696
#define HANDLE_FLAG_MASK (0x03)
@@ -181,13 +181,6 @@ enum z3fold_page_flags {
181181
PAGE_CLAIMED, /* by either reclaim or free */
182182
};
183183

184-
/*
185-
* handle flags, go under HANDLE_FLAG_MASK
186-
*/
187-
enum z3fold_handle_flags {
188-
HANDLES_ORPHANED = 0,
189-
};
190-
191184
/*
192185
* Forward declarations
193186
*/
@@ -303,10 +296,9 @@ static inline void put_z3fold_header(struct z3fold_header *zhdr)
303296
z3fold_page_unlock(zhdr);
304297
}
305298

306-
static inline void free_handle(unsigned long handle)
299+
static inline void free_handle(unsigned long handle, struct z3fold_header *zhdr)
307300
{
308301
struct z3fold_buddy_slots *slots;
309-
struct z3fold_header *zhdr;
310302
int i;
311303
bool is_free;
312304

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

319-
zhdr = handle_to_z3fold_header(handle);
320311
slots = handle_to_slots(handle);
321312
write_lock(&slots->lock);
322313
*(unsigned long *)handle = 0;
323-
if (zhdr->slots == slots) {
324-
write_unlock(&slots->lock);
325-
return; /* simple case, nothing else to do */
326-
}
314+
if (zhdr->slots != slots)
315+
zhdr->foreign_handles--;
327316

328-
/* we are freeing a foreign handle if we are here */
329-
zhdr->foreign_handles--;
330317
is_free = true;
331-
if (!test_bit(HANDLES_ORPHANED, &slots->pool)) {
332-
write_unlock(&slots->lock);
333-
return;
334-
}
335318
for (i = 0; i <= BUDDY_MASK; i++) {
336319
if (slots->slot[i]) {
337320
is_free = false;
@@ -343,6 +326,8 @@ static inline void free_handle(unsigned long handle)
343326
if (is_free) {
344327
struct z3fold_pool *pool = slots_to_pool(slots);
345328

329+
if (zhdr->slots == slots)
330+
zhdr->slots = NULL;
346331
kmem_cache_free(pool->c_handle, slots);
347332
}
348333
}
@@ -525,8 +510,6 @@ static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
525510
{
526511
struct page *page = virt_to_page(zhdr);
527512
struct z3fold_pool *pool = zhdr_to_pool(zhdr);
528-
bool is_free = true;
529-
int i;
530513

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

539-
/* If there are no foreign handles, free the handles array */
540-
read_lock(&zhdr->slots->lock);
541-
for (i = 0; i <= BUDDY_MASK; i++) {
542-
if (zhdr->slots->slot[i]) {
543-
is_free = false;
544-
break;
545-
}
546-
}
547-
if (!is_free)
548-
set_bit(HANDLES_ORPHANED, &zhdr->slots->pool);
549-
read_unlock(&zhdr->slots->lock);
550-
551-
if (is_free)
552-
kmem_cache_free(pool->c_handle, zhdr->slots);
553-
554522
if (locked)
555523
z3fold_page_unlock(zhdr);
556524

@@ -973,6 +941,9 @@ static inline struct z3fold_header *__z3fold_alloc(struct z3fold_pool *pool,
973941
}
974942
}
975943

944+
if (zhdr && !zhdr->slots)
945+
zhdr->slots = alloc_slots(pool,
946+
can_sleep ? GFP_NOIO : GFP_ATOMIC);
976947
return zhdr;
977948
}
978949

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

12721243
if (!page_claimed)
1273-
free_handle(handle);
1244+
free_handle(handle, zhdr);
12741245
if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list)) {
12751246
atomic64_dec(&pool->pages_nr);
12761247
return;
@@ -1429,19 +1400,19 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
14291400
ret = pool->ops->evict(pool, middle_handle);
14301401
if (ret)
14311402
goto next;
1432-
free_handle(middle_handle);
1403+
free_handle(middle_handle, zhdr);
14331404
}
14341405
if (first_handle) {
14351406
ret = pool->ops->evict(pool, first_handle);
14361407
if (ret)
14371408
goto next;
1438-
free_handle(first_handle);
1409+
free_handle(first_handle, zhdr);
14391410
}
14401411
if (last_handle) {
14411412
ret = pool->ops->evict(pool, last_handle);
14421413
if (ret)
14431414
goto next;
1444-
free_handle(last_handle);
1415+
free_handle(last_handle, zhdr);
14451416
}
14461417
next:
14471418
if (test_bit(PAGE_HEADLESS, &page->private)) {

0 commit comments

Comments
 (0)