From: Alexander Aring Date: Wed, 30 Sep 2020 22:37:29 +0000 (-0400) Subject: fs: dlm: fix race in nodeid2con X-Git-Tag: v5.10-rc1~179^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4f2b30fd9b4bd6e3620fe55786df7fc5f89ad526;p=thirdparty%2Fkernel%2Flinux.git fs: dlm: fix race in nodeid2con This patch fixes a race in nodeid2con in cases that we parallel running a lookup and both will create a connection structure for the same nodeid. It's a rare case to create a new connection structure to keep reader lockless we just do a lookup inside the protection area again and drop previous work if this race happens. Fixes: a47666eb763cc ("fs: dlm: make connection hash lockless") Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index b7b7360be609e..79f56f16bc2ce 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -175,7 +175,7 @@ static struct connection *__find_con(int nodeid) */ static struct connection *nodeid2con(int nodeid, gfp_t alloc) { - struct connection *con = NULL; + struct connection *con, *tmp; int r; con = __find_con(nodeid); @@ -213,6 +213,20 @@ static struct connection *nodeid2con(int nodeid, gfp_t alloc) r = nodeid_hash(nodeid); spin_lock(&connections_lock); + /* Because multiple workqueues/threads calls this function it can + * race on multiple cpu's. Instead of locking hot path __find_con() + * we just check in rare cases of recently added nodes again + * under protection of connections_lock. If this is the case we + * abort our connection creation and return the existing connection. + */ + tmp = __find_con(nodeid); + if (tmp) { + spin_unlock(&connections_lock); + kfree(con->rx_buf); + kfree(con); + return tmp; + } + hlist_add_head_rcu(&con->list, &connection_hash[r]); spin_unlock(&connections_lock);