Commit a656eb75 authored by Olaf Kirch's avatar Olaf Kirch Committed by Roland Dreier

IB/fmr_pool: Flush serial numbers can get out of sync

Normally, the serial numbers for flush requests and flushes executed
for an FMR pool should be in sync.

However, if the FMR pool flushes dirty FMRs because the
dirty_watermark was reached, we wake up the cleanup thread and let it
do its stuff.  As a side effect, the cleanup thread increments
pool->flush_ser, which leaves it one higher than pool->req_ser.  The
next time the user calls ib_flush_fmr_pool(), the cleanup thread will
be woken up, but ib_flush_fmr_pool() won't wait for the flush to
complete because flush_ser is already past req_ser.  This means the
FMRs that the user expects to be flushed may not have all been flushed
when the function returns.

Fix this by telling the cleanup thread to do work exclusively by
incrementing req_ser, and by moving the comparison of dirty_len and
dirty_watermark into ib_fmr_pool_unmap().
Signed-off-by: default avatarOlaf Kirch <olaf.kirch@oracle.com>
parent 2fe7e6f7
...@@ -182,8 +182,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) ...@@ -182,8 +182,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
struct ib_fmr_pool *pool = pool_ptr; struct ib_fmr_pool *pool = pool_ptr;
do { do {
if (pool->dirty_len >= pool->dirty_watermark || if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
ib_fmr_batch_release(pool); ib_fmr_batch_release(pool);
atomic_inc(&pool->flush_ser); atomic_inc(&pool->flush_ser);
...@@ -194,8 +193,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) ...@@ -194,8 +193,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
} }
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (pool->dirty_len < pool->dirty_watermark && if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
!kthread_should_stop()) !kthread_should_stop())
schedule(); schedule();
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
...@@ -511,10 +509,12 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) ...@@ -511,10 +509,12 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
list_add_tail(&fmr->list, &pool->free_list); list_add_tail(&fmr->list, &pool->free_list);
} else { } else {
list_add_tail(&fmr->list, &pool->dirty_list); list_add_tail(&fmr->list, &pool->dirty_list);
++pool->dirty_len; if (++pool->dirty_len >= pool->dirty_watermark) {
atomic_inc(&pool->req_ser);
wake_up_process(pool->thread); wake_up_process(pool->thread);
} }
} }
}
#ifdef DEBUG #ifdef DEBUG
if (fmr->ref_count < 0) if (fmr->ref_count < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment