[RHEL7,COMMIT] fuse kio: Do not NULL used pcs_cs_link::cs during connection destruction

Submitted by Konstantin Khorenko on June 15, 2018, 12:04 p.m.

Details

Message ID 201806151204.w5FC4lNj010241@finist_ce7.work
State New
Series "fuse kio: Do not NULL used pcs_cs_link::cs during connection destruction"
Headers show

Commit Message

Konstantin Khorenko June 15, 2018, 12:04 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.9
------>
commit ae1cd3dd47d1cbc2acee8f3e89181a7641dd8531
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Fri Jun 15 15:04:47 2018 +0300

    fuse kio: Do not NULL used pcs_cs_link::cs during connection destruction
    
    fuse kio: Do not NULL used pcs_cs_link::cs during connection destruction
    
    From: Kirill Tkhai <ktkhai@virtuozzo.com>
    
    Some inodes may have assigned maps. They are evicted later
    than pcs_cs_isolate() NULLes pcs_cs_link::cs pointers. So,
    we mustn't have maps after pcs_cs_isolate() is finished.
    
    This patch makes pcs_cs_link::cs be NULLed in generic way,
    i.e. after the last reference to the list is dropped (via
    cslist_put()).
    
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    Acked-by: Alexey Kuznetsov <kuznet@virtuozzo.com>
    Reviewed-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_cs.c  | 10 +--------
 fs/fuse/kio/pcs/pcs_map.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fuse/kio/pcs/pcs_map.h |  1 +
 3 files changed, 56 insertions(+), 9 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/kio/pcs/pcs_cs.c b/fs/fuse/kio/pcs/pcs_cs.c
index b65e16be9f85..8345e92c4570 100644
--- a/fs/fuse/kio/pcs/pcs_cs.c
+++ b/fs/fuse/kio/pcs/pcs_cs.c
@@ -726,15 +726,7 @@  static void pcs_cs_isolate(struct pcs_cs *cs, struct list_head *dispose)
 		cancel_delayed_work(&cs->css->bl_work);
 	spin_unlock(&cs->css->lock);
 
-	while (!list_empty(&cs->map_list)) {
-		struct pcs_cs_link *csl = list_first_entry(&cs->map_list,
-							       struct pcs_cs_link,
-							       link);
-		rcu_assign_pointer(csl->cs, NULL);
-		cs->nmaps--;
-		list_del_init(&csl->link);
-	}
-
+	pcs_cs_truncate_maps(cs);
 
 	BUG_ON(cs->nmaps);
 
diff --git a/fs/fuse/kio/pcs/pcs_map.c b/fs/fuse/kio/pcs/pcs_map.c
index f20db1d5b3f9..8b8d81dae163 100644
--- a/fs/fuse/kio/pcs/pcs_map.c
+++ b/fs/fuse/kio/pcs/pcs_map.c
@@ -267,6 +267,60 @@  void map_truncate_tail(struct pcs_mapping * mapping, u64 offset)
 	pcs_ireq_queue_fail(&dispose, PCS_ERR_NET_ABORT);
 }
 
+void pcs_cs_truncate_maps(struct pcs_cs *cs)
+{
+	struct pcs_cs_list *cs_list;
+	struct pcs_cs_link *cs_link;
+	struct pcs_map_entry *m;
+	LIST_HEAD(map_list);
+	bool once = true;
+
+	cs->use_count++;
+again:
+	lockdep_assert_held(&cs->lock);
+
+	while (!list_empty(&cs->map_list)) {
+		cs_link = list_first_entry(&cs->map_list,
+					   struct pcs_cs_link, link);
+		list_move(&cs_link->link, &map_list);
+
+		cs_list = cs_link_to_cs_list(cs_link);
+		cslist_get(cs_list);
+		spin_unlock(&cs->lock);
+
+		rcu_read_lock();
+		m = rcu_dereference(cs_list->map);
+		if (!m)
+			goto skip;
+		spin_lock(&m->lock);
+		if (!list_empty(&m->queue)) {
+			WARN(once, "Not empty map queue\n");
+			once = false;
+		} else if (!(m->state & PCS_MAP_DEAD)) {
+			pcs_map_truncate(m, NULL);
+			map_del_lru(m);
+		}
+		spin_unlock(&m->lock);
+skip:
+		rcu_read_unlock();
+		/*
+		 * cs_link will be removed from map_list
+		 * on the final cslist_put(). Maybe now.
+		 */
+		cslist_put(cs_list);
+		spin_lock(&cs->lock);
+	}
+
+	list_splice(&map_list, &cs->map_list);
+	if (!list_empty(&cs->map_list)) {
+		spin_unlock(&cs->lock);
+		schedule_timeout_uninterruptible(HZ);
+		spin_lock(&cs->lock);
+		goto again;
+	}
+	cs->use_count--;
+}
+
 void pcs_mapping_invalidate(struct pcs_mapping * mapping)
 {
 	pcs_mapping_dump(mapping);
diff --git a/fs/fuse/kio/pcs/pcs_map.h b/fs/fuse/kio/pcs/pcs_map.h
index bc36983a7355..3eb380bd0b07 100644
--- a/fs/fuse/kio/pcs/pcs_map.h
+++ b/fs/fuse/kio/pcs/pcs_map.h
@@ -190,6 +190,7 @@  struct pcs_ioc_getmap;
 void pcs_map_complete(struct pcs_map_entry *m, struct pcs_ioc_getmap *omap);
 int pcs_map_encode_req(struct pcs_map_entry*m, struct pcs_ioc_getmap *map, int direction);
 void map_truncate_tail(struct pcs_mapping *mapping, u64 offset);
+void pcs_cs_truncate_maps(struct pcs_cs *cs);
 unsigned long pcs_map_shrink_scan(struct shrinker *,  struct shrink_control *sc);
 void ireq_drop_tokens(struct pcs_int_request * ireq);