[Cluster-devel] [RFC v5.13.8] fs: dlm: fix srcu idx value per msg

Alexander Aring aahringo at redhat.com
Tue Aug 24 20:40:01 UTC 2021


This patch fixes an issue if new_wq_entry() returns the same writequeue
entry and the idx field will be overwritten that was set by the previous
call. We need to make the handle per call and store the srcu idx value
there to avoid it.

Fixes: 7ae861bbfa0f ("fs: dlm: fix srcu read lock usage")
Signed-off-by: Alexander Aring <aahringo at redhat.com>
---
 fs/dlm/lowcomms.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 9bf920bee292..5ed0efc45ba6 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -119,7 +119,6 @@ struct writequeue_entry {
 	int len;
 	int end;
 	int users;
-	int idx; /* get()/commit() idx exchange */
 	struct connection *con;
 };
 
@@ -1447,9 +1446,14 @@ static struct writequeue_entry *new_wq_entry(struct connection *con, int len,
 	return e;
 };
 
+struct dlm_buffer_ctx {
+	struct writequeue_entry *e;
+	int idx; /* get()/commit() idx exchange */
+};
+
 void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
 {
-	struct writequeue_entry *e;
+	struct dlm_buffer_ctx *bctx;
 	struct connection *con;
 	int idx;
 
@@ -1468,39 +1472,48 @@ void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
 		return NULL;
 	}
 
-	e = new_wq_entry(con, len, allocation, ppc);
-	if (!e) {
+	bctx = kzalloc(sizeof(*bctx), GFP_NOFS);
+	if (!bctx) {
 		srcu_read_unlock(&connections_srcu, idx);
 		return NULL;
 	}
 
+	bctx->e = new_wq_entry(con, len, allocation, ppc);
+	if (!bctx->e) {
+		srcu_read_unlock(&connections_srcu, idx);
+		kfree(bctx);
+		return NULL;
+	}
+
 	/* we assume if successful commit must called */
-	e->idx = idx;
+	bctx->idx = idx;
 
-	return e;
+	return bctx;
 }
 
 void dlm_lowcomms_commit_buffer(void *mh)
 {
-	struct writequeue_entry *e = (struct writequeue_entry *)mh;
-	struct connection *con = e->con;
+	struct dlm_buffer_ctx *bctx = (struct dlm_buffer_ctx *)mh;
+	struct connection *con = bctx->e->con;
 	int users;
 
 	spin_lock(&con->writequeue_lock);
-	users = --e->users;
+	users = --bctx->e->users;
 	if (users)
 		goto out;
 
-	e->len = DLM_WQ_LENGTH_BYTES(e);
+	bctx->e->len = DLM_WQ_LENGTH_BYTES(bctx->e);
 	spin_unlock(&con->writequeue_lock);
 
 	queue_work(send_workqueue, &con->swork);
-	srcu_read_unlock(&connections_srcu, e->idx);
+	srcu_read_unlock(&connections_srcu, bctx->idx);
+	kfree(bctx);
 	return;
 
 out:
 	spin_unlock(&con->writequeue_lock);
-	srcu_read_unlock(&connections_srcu, e->idx);
+	srcu_read_unlock(&connections_srcu, bctx->idx);
+	kfree(bctx);
 	return;
 }
 
-- 
2.27.0




More information about the Cluster-devel mailing list