[RHEL7,COMMIT] fs/fuse kio_pcs: NULL pointer dereference on access m->mapping->chunk_size_bits

Submitted by Konstantin Khorenko on Oct. 31, 2018, 1:02 p.m.

Details

Message ID 201810311302.w9VD2pOA023507@finist-ce7.sw.ru
State New
Series "fs/fuse kio_pcs: NULL pointer dereference on access m->mapping->chunk_size_bits"
Headers show

Commit Message

Konstantin Khorenko Oct. 31, 2018, 1:02 p.m.
The commit is pushed to "branch-rh7-3.10.0-862.14.4.vz7.72.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.14.4.vz7.72.15
------>
commit 6fe1acd868dc910f1038eb2efd9dfcbb9b234b2f
Author: Pavel Butsykin <pbutsykin@virtuozzo.com>
Date:   Wed Oct 31 16:02:51 2018 +0300

    fs/fuse kio_pcs: NULL pointer dereference on access m->mapping->chunk_size_bits
    
    Inside map_chunk_start()/map_chunk_end() there is dereference m->mapping,
    which can be NULL in case of map dead. But in fact it's impossible in this
    place, because maps are dropped only on shrink which is protected from
    simultaneous execution with other IO.
    
    But anyway let's fix dereference m->mapping of a dead map and add WARN_ON_ONCE()
    to facilitate catching this race in case it occurs.
    
    Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
    Reviewed-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    
    =====================
    Patchset description:
    
    FUSE KIO: Mapping truncate fixes
    
    https://jira.sw.ru/browse/PSBM-89539
---
 fs/fuse/kio/pcs/pcs_map.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 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 8579b5eb8bc9..ea85c8652b3d 100644
--- a/fs/fuse/kio/pcs/pcs_map.c
+++ b/fs/fuse/kio/pcs/pcs_map.c
@@ -1192,6 +1192,9 @@  static void pcs_map_queue_resolve(struct pcs_map_entry * m, struct pcs_int_reque
 	/* This should not happen unless aio_dio/fsync vs truncate race */
 	if (m->state & PCS_MAP_DEAD) {
 		spin_unlock(&m->lock);
+
+		/* If this happens, it's assumed this is a bug that needs to be fixed */
+		WARN_ON_ONCE(1);
 		list_add(&ireq->list, &l);
 		pcs_ireq_queue_fail(&l, PCS_ERR_NET_ABORT);
 		return;
@@ -2289,12 +2292,13 @@  void map_submit(struct pcs_map_entry * m, struct pcs_int_request *ireq)
 
 	do {
 		struct pcs_cs_list *csl = NULL;
+		u64 map_start, map_end;
 
 		spin_lock(&m->lock);
 		if (ireq->type == PCS_IREQ_IOCHUNK && !(ireq->flags & IREQ_F_MAPPED))
 			ireq->iochunk.hbuf.map_version = m->version;
 
-		if (!(m->state & (1 << direction))) {
+		if (!(m->state & (1 << direction)) || m->state & PCS_MAP_DEAD) {
 			spin_unlock(&m->lock);
 			pcs_map_queue_resolve(m, ireq, direction);
 			return;
@@ -2302,18 +2306,21 @@  void map_submit(struct pcs_map_entry * m, struct pcs_int_request *ireq)
 		csl = m->cs_list;
 		if (csl)
 			cslist_get(csl);
+
+		map_start = map_chunk_start(m);
+		map_end = map_chunk_end(m);
 		spin_unlock(&m->lock);
 
 		if (ireq->type != PCS_IREQ_FLUSH && !(ireq->flags & IREQ_F_MAPPED)) {
 			u64 pos = ireq->iochunk.chunk + ireq->iochunk.offset;
-			u64 len = map_chunk_end(m) - pos;
+			u64 len = map_end - pos;
 
 			/*
 			 * For non variable chunks all alligment should be done
 			 * inside pcs_cc_process_ireq_ioreq();
 			 */
-			BUG_ON(pos < map_chunk_start(m));
-			BUG_ON(ireq->iochunk.chunk != map_chunk_start(m));
+			BUG_ON(pos < map_start);
+			BUG_ON(ireq->iochunk.chunk != map_start);
 			BUG_ON(ireq->iochunk.offset != pos - ireq->iochunk.chunk);
 			if (ireq->iochunk.size > len) {
 				if (ireq->iochunk.cmd == PCS_REQ_T_FIEMAP) {
@@ -2328,7 +2335,7 @@  void map_submit(struct pcs_map_entry * m, struct pcs_int_request *ireq)
 						pcs_map_put(ireq->iochunk.map);
 						ireq->iochunk.map = NULL;
 					}
-					ireq->iochunk.chunk = map_chunk_end(m);
+					ireq->iochunk.chunk = map_end;
 					ireq->iochunk.offset = 0;
 					pcs_cc_submit(ireq->dentry->cluster, ireq);
 					ireq = sreq;