From: Yu Kuai <yuku...@huawei.com> IO fast path will set bits to dirty, and those dirty bits will be cleared by daemon after IO is done. llbitmap_barrier is used to synchronize between IO path and daemon;
IO path: 1) try to grab a reference, if succeed, set expire time after 5s and return; 2) if failed to grab a reference, wait for daemon to finish clearing dirty bits; Daemon(Daemon will be waken up every daemon_sleep seconds): For each page: 1) check if page expired, if not skip this page; for expired page: 2) suspend the page and wait for inflight write IO to be done; 3) change dirty page to clean; 4) resume the page; Signed-off-by: Yu Kuai <yuku...@huawei.com> --- drivers/md/md-llbitmap.c | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c index 315a4eb7627c..994ca0be3d17 100644 --- a/drivers/md/md-llbitmap.c +++ b/drivers/md/md-llbitmap.c @@ -435,6 +435,14 @@ static void llbitmap_write_page(struct llbitmap *llbitmap, int idx) } } +static void active_release(struct percpu_ref *ref) +{ + struct llbitmap_barrier *barrier = + container_of(ref, struct llbitmap_barrier, active); + + wake_up(&barrier->wait); +} + static int llbitmap_cache_pages(struct llbitmap *llbitmap) { int nr_pages = (llbitmap->chunks + BITMAP_SB_SIZE + PAGE_SIZE - 1) / PAGE_SIZE; @@ -562,3 +570,41 @@ static enum llbitmap_state llbitmap_state_machine(struct llbitmap *llbitmap, return state; } + +static void llbitmap_raise_barrier(struct llbitmap *llbitmap, int page_idx) +{ + struct llbitmap_barrier *barrier = &llbitmap->barrier[page_idx]; + +retry: + if (likely(percpu_ref_tryget_live(&barrier->active))) { + WRITE_ONCE(barrier->expire, jiffies + BARRIER_IDLE * HZ); + return; + } + + wait_event(barrier->wait, !percpu_ref_is_dying(&barrier->active)); + goto retry; +} + +static void llbitmap_release_barrier(struct llbitmap *llbitmap, int page_idx) +{ + struct llbitmap_barrier *barrier = &llbitmap->barrier[page_idx]; + + percpu_ref_put(&barrier->active); +} + +static void llbitmap_suspend(struct llbitmap *llbitmap, int page_idx) +{ + struct llbitmap_barrier *barrier = &llbitmap->barrier[page_idx]; + + percpu_ref_kill(&barrier->active); + wait_event(barrier->wait, percpu_ref_is_zero(&barrier->active)); +} + +static void llbitmap_resume(struct llbitmap *llbitmap, int page_idx) +{ + struct llbitmap_barrier *barrier = &llbitmap->barrier[page_idx]; + + barrier->expire = LONG_MAX; + percpu_ref_resurrect(&barrier->active); + wake_up(&barrier->wait); +} -- 2.39.2