[Devel] [PATCH VZ9 1/2] fs/fuse/kio: corrupted cs_accel state variable

Alexey Kuznetsov kuznet at virtuozzo.com
Mon Oct 20 11:34:07 MSK 2025


Variable parent_N shared between states was put to data private
to one particular state and overwritten while state switches.

The core reason for this sad mistake was aliasing between anonymous
union member and the same member looking like it is common.
It was obvious this is a way to trouble, but desire to minimize
patch size was overwhelming. Fix this.

Affects: #VSTOR-109945

Signed-off-by: Alexey Kuznetsov <kuznet at virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_cluster.c  |  8 ++++----
 fs/fuse/kio/pcs/pcs_cs.c       | 18 +++++++++---------
 fs/fuse/kio/pcs/pcs_cs_accel.c | 12 ++++++------
 fs/fuse/kio/pcs/pcs_map.c      | 10 +++++-----
 fs/fuse/kio/pcs/pcs_req.h      | 12 ++----------
 5 files changed, 26 insertions(+), 34 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_cluster.c b/fs/fuse/kio/pcs/pcs_cluster.c
index 710087c..c475d04 100644
--- a/fs/fuse/kio/pcs/pcs_cluster.c
+++ b/fs/fuse/kio/pcs/pcs_cluster.c
@@ -245,8 +245,8 @@ static void fiemap_process_one(struct fiemap_iterator *fiter)
 		fiter->apireq.size = sreq->iochunk.size = DENTRY_CHUNK_SIZE(di) - sreq->iochunk.offset;
 	sreq->iochunk.csl = NULL;
 	sreq->iochunk.banned_cs.val = 0;
-	sreq->iochunk.msg.destructor = NULL;
-	sreq->iochunk.msg.rpc = NULL;
+	sreq->iochunk.ir.msg.destructor = NULL;
+	sreq->iochunk.ir.msg.rpc = NULL;
 
 	pcs_sreq_attach(sreq, &fiter->ireq);
 	sreq->complete_cb = pcs_sreq_complete;
@@ -403,8 +403,8 @@ static noinline void __pcs_cc_process_ireq_rw(struct pcs_int_request *ireq)
 		sreq->iochunk.size = len;
 		sreq->iochunk.csl = NULL;
 		sreq->iochunk.banned_cs.val = 0;
-		sreq->iochunk.msg.destructor = NULL;
-		sreq->iochunk.msg.rpc = NULL;
+		sreq->iochunk.ir.msg.destructor = NULL;
+		sreq->iochunk.ir.msg.rpc = NULL;
 
 		pcs_sreq_attach(sreq, ireq);
 		sreq->complete_cb = pcs_sreq_complete;
diff --git a/fs/fuse/kio/pcs/pcs_cs.c b/fs/fuse/kio/pcs/pcs_cs.c
index 8c1fdce..53bd520 100644
--- a/fs/fuse/kio/pcs/pcs_cs.c
+++ b/fs/fuse/kio/pcs/pcs_cs.c
@@ -381,7 +381,7 @@ static void cs_response_done(struct pcs_msg *msg)
 		pcs_map_verify_sync_state(ireq->dentry, ireq, msg);
 	} else {
 		FUSE_KTRACE(ireq->cc->fc, XID_FMT " IO error %d %lu, ireq:%p : %llu:%u+%u",
-		      XID_ARGS(ireq->iochunk.hbuf.hdr.xid), msg->error.value,
+		      XID_ARGS(ireq->iochunk.ir.hbuf.hdr.xid), msg->error.value,
 		      msg->error.remote ? (unsigned long)msg->error.offender.val : 0UL,
 		      ireq, (unsigned long long)ireq->iochunk.chunk,
 		      (unsigned)ireq->iochunk.offset,
@@ -488,9 +488,10 @@ static void cs_get_data(struct pcs_msg *msg, int offset, struct iov_iter *it, un
 	struct pcs_int_request *ireq = ireq_from_msg(msg);
 
 	if (offset < sizeof(struct pcs_cs_iohdr)) {
-		ireq->iochunk.hbuf_kv.iov_base = &ireq->iochunk.hbuf;
-		ireq->iochunk.hbuf_kv.iov_len = sizeof(struct pcs_cs_iohdr);
-		iov_iter_kvec(it, direction, &ireq->iochunk.hbuf_kv, 1, sizeof(struct pcs_cs_iohdr));
+		ireq->iochunk.ir.hbuf_kv.iov_base = &ireq->iochunk.ir.hbuf;
+		ireq->iochunk.ir.hbuf_kv.iov_len = sizeof(struct pcs_cs_iohdr);
+		iov_iter_kvec(it, direction, &ireq->iochunk.ir.hbuf_kv, 1,
+				  sizeof(struct pcs_cs_iohdr));
 		iov_iter_advance(it, offset);
 		TRACE("return msg:%p->size:%d off:%d it_len:%ld\n", msg, msg->size, offset, iov_iter_count(it));
 
@@ -624,8 +624,8 @@ static void ireq_complete_fo(struct pcs_int_request * ireq)
 		}
 		FUSE_TRACE_COMMIT(fc->ktrace);
 	}
-	ireq->iochunk.msg.destructor = NULL;
-	ireq->iochunk.msg.rpc = NULL;
+	ireq->iochunk.ir.msg.destructor = NULL;
+	ireq->iochunk.ir.msg.rpc = NULL;
 	ireq_complete(ireq);
 }
 
@@ -653,7 +653,7 @@ static void complete_fo_request(struct pcs_int_request * sreq)
 
 static void do_cs_submit(struct pcs_cs *cs, struct pcs_int_request *ireq)
 {
-	struct pcs_msg *msg = &ireq->iochunk.msg;
+	struct pcs_msg *msg = &ireq->iochunk.ir.msg;
 	struct pcs_cs_iohdr *ioh;
 	struct pcs_cs_list *csl = ireq->iochunk.csl;
 	struct pcs_map_entry *map = ireq->iochunk.map; /* ireq keeps reference to map */
@@ -665,7 +665,7 @@ static void do_cs_submit(struct pcs_cs *cs, struct pcs_int_request *ireq)
 	msg->private = cs;
 	msg->private2 = ireq;
 
-	ioh = &ireq->iochunk.hbuf;
+	ioh = &ireq->iochunk.ir.hbuf;
 	ioh->hdr.len = pcs_cs_msg_size(sizeof(struct pcs_cs_iohdr),
 				       storage_version);
 	aligned_msg = pcs_cs_use_aligned_io(storage_version);
@@ -741,7 +741,7 @@ static void do_cs_submit(struct pcs_cs *cs, struct pcs_int_request *ireq)
 
 	DTRACE(XID_FMT " About to send msg:%p, ireq:%p, cmd:%u,"
 		" id:"CUID_FMT" v:"VER_FMT" - %llu:%u+%u\n",
-		XID_ARGS(ireq->iochunk.hbuf.hdr.xid), msg, ireq,
+		XID_ARGS(ireq->iochunk.ir.hbuf.hdr.xid), msg, ireq,
 		ireq->iochunk.cmd, CUID_ARGS(ioh->uid),
 		VER_ARGS(ioh->map_version),
 		(unsigned long long)ireq->iochunk.chunk,
diff --git a/fs/fuse/kio/pcs/pcs_cs_accel.c b/fs/fuse/kio/pcs/pcs_cs_accel.c
index 036ca17..ef30ac8 100644
--- a/fs/fuse/kio/pcs/pcs_cs_accel.c
+++ b/fs/fuse/kio/pcs/pcs_cs_accel.c
@@ -510,8 +510,8 @@ static void __pcs_csa_final_completion(struct pcs_aio_req *areq)
 		/* Prepare ireq for restart in slow path */
 		ireq->flags |= IREQ_F_NO_ACCEL|IREQ_F_ACCELERROR;
 		ireq->flags &= ~IREQ_F_ONCE;
-		ireq->iochunk.msg.destructor = NULL;
-		ireq->iochunk.msg.rpc = NULL;
+		ireq->iochunk.ir.msg.destructor = NULL;
+		ireq->iochunk.ir.msg.rpc = NULL;
 	}
 
 out:
@@ -954,8 +954,8 @@ int pcs_csa_cs_submit(struct pcs_cs * cs, struct pcs_int_request * ireq)
 					return 1;
 				rcu_read_lock();
 				/* Clear state which could be rewritten by csa_submit */
-				ireq->iochunk.msg.destructor = NULL;
-				ireq->iochunk.msg.rpc = NULL;
+				ireq->iochunk.ir.msg.destructor = NULL;
+				ireq->iochunk.ir.msg.rpc = NULL;
 				ireq->flags |= IREQ_F_NO_ACCEL;
 			}
 		}
@@ -1041,8 +1041,8 @@ static void ireq_clear_acr(struct pcs_int_request * ireq)
 			ireq->iochunk.acr.awr[i].bvec_copy = NULL;
 		}
 	}
-	ireq->iochunk.msg.destructor = NULL;
-	ireq->iochunk.msg.rpc = NULL;
+	ireq->iochunk.ir.msg.destructor = NULL;
+	ireq->iochunk.ir.msg.rpc = NULL;
 	ireq->flags |= IREQ_F_NO_ACCEL;
 }
 
diff --git a/fs/fuse/kio/pcs/pcs_map.c b/fs/fuse/kio/pcs/pcs_map.c
index 62b083b..2d95dc2 100644
--- a/fs/fuse/kio/pcs/pcs_map.c
+++ b/fs/fuse/kio/pcs/pcs_map.c
@@ -1371,7 +1371,7 @@ void map_notify_iochunk_error(struct pcs_int_request * sreq)
 	if (!m || (m->state & PCS_MAP_DEAD))
 		return;
 
-	map_notify_error(m, sreq, &sreq->iochunk.hbuf.map_version, sreq->iochunk.csl);
+	map_notify_error(m, sreq, &sreq->iochunk.ir.hbuf.map_version, sreq->iochunk.csl);
 }
 
 static void map_replicating(struct pcs_int_request *ireq)
@@ -1770,7 +1770,8 @@ void map_notify_soft_error(struct pcs_int_request *ireq)
 	if (pcs_if_error(&ireq->error))
 		map_notify_iochunk_error(ireq);
 
-	if (map_version_compare(&ireq->iochunk.hbuf.map_version, &ireq->iochunk.map->version) < 0)
+	if (map_version_compare(&ireq->iochunk.ir.hbuf.map_version,
+				&ireq->iochunk.map->version) < 0)
 		ireq->flags &= ~IREQ_F_ONCE;
 
 	pcs_deaccount_ireq(ireq, &err);
@@ -1973,8 +1973,8 @@ struct pcs_int_request *
 	sreq->iochunk.csl = NULL;
 	sreq->iochunk.banned_cs.val = 0;
 	sreq->complete_cb = ireq->complete_cb;
-	sreq->iochunk.msg.destructor = NULL;
-	sreq->iochunk.msg.rpc = NULL;
+	sreq->iochunk.ir.msg.destructor = NULL;
+	sreq->iochunk.ir.msg.rpc = NULL;
 	pcs_sreq_attach(sreq, ireq->completion_data.parent);
 
 	ireq->iochunk.size -= iochunk;
@@ -2472,7 +2472,7 @@ void map_submit(struct pcs_map_entry * m, struct pcs_int_request *ireq)
 
 		spin_lock(&m->lock);
 		if (ireq->type == PCS_IREQ_IOCHUNK && !(ireq->flags & IREQ_F_MAPPED))
-			ireq->iochunk.hbuf.map_version = m->version;
+			ireq->iochunk.ir.hbuf.map_version = m->version;
 
 		if (!(m->state & (1 << direction)) || (m->state & PCS_MAP_DEAD) ||
 		    map_chk_stale(m)) {
diff --git a/fs/fuse/kio/pcs/pcs_req.h b/fs/fuse/kio/pcs/pcs_req.h
index 94fcfdb..61d3575 100644
--- a/fs/fuse/kio/pcs/pcs_req.h
+++ b/fs/fuse/kio/pcs/pcs_req.h
@@ -93,7 +93,6 @@ struct pcs_iochunk_req {
 						 * A little ugly
 						 */
 	struct kvec		hbuf_kv;
-	struct pcs_int_request	*parent_N;
 };
 
 struct pcs_fo_req
@@ -183,15 +182,8 @@ struct pcs_int_request
 			u64			offset;
 			struct pcs_cs_list	*csl;
 			PCS_NODE_ID_T		banned_cs;
+			struct pcs_int_request	*parent_N;
 			union {
-				struct {
-					struct pcs_msg		msg;
-					struct pcs_cs_iohdr	hbuf;		/* Buffer for header.
-										 * A little ugly
-										 */
-					struct kvec		hbuf_kv;
-					struct pcs_int_request	*parent_N;
-				};
 				struct pcs_iochunk_req		ir;
 				struct pcs_fo_req		fo;
 				struct pcs_aio_req		ar;
@@ -383,7 +375,7 @@ static inline int pcs_sreq_detach(struct pcs_int_request * sreq)
 
 static inline struct pcs_int_request *ireq_from_msg(struct pcs_msg *msg)
 {
-	return container_of(msg, struct pcs_int_request, iochunk.msg);
+	return container_of(msg, struct pcs_int_request, iochunk.ir.msg);
 }
 
 static inline void ireq_process(struct pcs_int_request *ireq)
-- 
1.8.3.1



More information about the Devel mailing list