]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
fs: dlm: fix race in nodeid2con
authorAlexander Aring <aahringo@redhat.com>
Wed, 30 Sep 2020 22:37:29 +0000 (18:37 -0400)
committerDavid Teigland <teigland@redhat.com>
Thu, 1 Oct 2020 14:25:07 +0000 (09:25 -0500)
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 <aahringo@redhat.com>
Signed-off-by: David Teigland <teigland@redhat.com>
fs/dlm/lowcomms.c

index b7b7360be609e4c60452e508e6ef17803b82bfa4..79f56f16bc2cec2732e6a811b87839e6338dd193 100644 (file)
@@ -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);