[Devel] [PATCH RHEL7 COMMIT] fuse kio: Fix unbalanced queueing and dequeueing pcs_map_entry::sync_work

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 25 19:01:49 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-693.21.1.vz7.50.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.21.1.vz7.50.15
------>
commit 866950b8028871e9b461f1c987110bfdad631df6
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date:   Mon Jun 25 19:01:49 2018 +0300

    fuse kio: Fix unbalanced queueing and dequeueing pcs_map_entry::sync_work
    
    timer_pending() can't be reliable indicator of delayed work
    is queued. In case of timer has fired and the work has just
    queued to workqueue, this code increments counter the second
    time, while the work function will decrement it only once.
    
    This patch makes counter incremented only in case of the work
    has scheduled, and makes it decremented only in case of real
    cancel has occured.
    
    Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
    Reviewed-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_map.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_map.c b/fs/fuse/kio/pcs/pcs_map.c
index 217644409528..a3bf48a8ea93 100644
--- a/fs/fuse/kio/pcs/pcs_map.c
+++ b/fs/fuse/kio/pcs/pcs_map.c
@@ -519,18 +519,21 @@ static void map_sync_work_add(struct pcs_map_entry *m, unsigned long timeout)
 
 	assert_spin_locked(&m->lock);
 
-	if (!timer_pending(&m->sync_work.timer))
+	if (WARN_ON_ONCE(m->state & PCS_MAP_DEAD))
+		return;
+	/*
+	 * Note, that work func takes m->lock on all paths,
+	 * so it can't put map before we get it below.
+	 */
+	if (!mod_delayed_work(cc->wq, &m->sync_work, timeout))
 		__pcs_map_get(m);
-	mod_delayed_work(cc->wq, &m->sync_work, timeout);
 }
 static void map_sync_work_del(struct pcs_map_entry *m)
 {
 	assert_spin_locked(&m->lock);
 
-	if (!timer_pending(&m->sync_work.timer))
-		return;
-	cancel_delayed_work(&m->sync_work);
-	pcs_map_put_locked(m);
+	if (cancel_delayed_work(&m->sync_work))
+		pcs_map_put_locked(m);
 }
 static void sync_timer_work(struct work_struct *w);
 
@@ -3049,7 +3052,8 @@ static void sync_timer_work(struct work_struct *w)
 	err = prepare_map_flush_ireq(m, &sreq);
 	if (err) {
 		spin_lock(&m->lock);
-		map_sync_work_add(m, HZ);
+		if (!(m->state & PCS_MAP_DEAD))
+			map_sync_work_add(m, HZ);
 		spin_unlock(&m->lock);
 	} else {
 		if (sreq)


More information about the Devel mailing list