Merge "fs/buffer.c: Revoke LRU when trying to drop buffers"

This commit is contained in:
qctecmdr 2020-01-13 21:38:00 -08:00 • committed by Gerrit - the friendly Code Review server
commit 9281a8d0bd

View file

@ -1392,12 +1392,48 @@ static bool has_bh_in_lru(int cpu, void *dummy)
return 0;
}
static void __evict_bh_lru(void *arg)
{
struct bh_lru *b = &get_cpu_var(bh_lrus);
struct buffer_head *bh = arg;
int i;
for (i = 0; i < BH_LRU_SIZE; i++) {
if (b->bhs[i] == bh) {
brelse(b->bhs[i]);
b->bhs[i] = NULL;
goto out;
}
}
out:
put_cpu_var(bh_lrus);
}
static bool bh_exists_in_lru(int cpu, void *arg)
{
struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
struct buffer_head *bh = arg;
int i;
for (i = 0; i < BH_LRU_SIZE; i++) {
if (b->bhs[i] == bh)
return true;
}
return false;
}
void invalidate_bh_lrus(void)
{
on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
static void evict_bh_lrus(struct buffer_head *bh)
{
on_each_cpu_cond(bh_exists_in_lru, __evict_bh_lru, bh, 1, GFP_ATOMIC);
}
void set_bh_page(struct buffer_head *bh,
struct page *page, unsigned long offset)
{
@ -3238,8 +3274,15 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
bh = head;
do {
if (buffer_busy(bh))
goto failed;
if (buffer_busy(bh)) {
/*
* Check if the busy failure was due to an
* outstanding LRU reference
*/
evict_bh_lrus(bh);
if (buffer_busy(bh))
goto failed;
}
bh = bh->b_this_page;
} while (bh != head);