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

Submitted by Konstantin Khorenko on June 25, 2018, 4:01 p.m.

Details

Message ID 201806251601.w5PG1n0i010936@finist_ce7.work
State New
Series "fuse kio: Fix unbalanced queueing and dequeueing pcs_map_entry::sync_work"
Headers show

Commit Message

Konstantin Khorenko June 25, 2018, 4:01 p.m.
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@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@virtuozzo.com>
    Reviewed-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_map.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

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)