OSDN Git Service

xprtrdma: Improve locking around rpcrdma_rep destruction
authorChuck Lever <chuck.lever@oracle.com>
Sat, 24 Apr 2021 19:02:28 +0000 (15:02 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 26 Apr 2021 13:22:29 +0000 (09:22 -0400)
Currently rpcrdma_reps_destroy() assumes that, at transport
tear-down, the content of the rb_free_reps list is the same as the
content of the rb_all_reps list. Although that is usually true,
using the rb_all_reps list should be more reliable because of
the way it's managed. And, rpcrdma_reps_unmap() uses rb_all_reps;
these two functions should both traverse the "all" list.

Ensure that all rpcrdma_reps are always destroyed whether they are
on the rep free list or not.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
net/sunrpc/xprtrdma/verbs.c

index 1b599a6..2bc4589 100644 (file)
@@ -1007,16 +1007,23 @@ out:
        return NULL;
 }
 
-/* No locking needed here. This function is invoked only by the
- * Receive completion handler, or during transport shutdown.
- */
-static void rpcrdma_rep_destroy(struct rpcrdma_rep *rep)
+static void rpcrdma_rep_free(struct rpcrdma_rep *rep)
 {
-       list_del(&rep->rr_all);
        rpcrdma_regbuf_free(rep->rr_rdmabuf);
        kfree(rep);
 }
 
+static void rpcrdma_rep_destroy(struct rpcrdma_rep *rep)
+{
+       struct rpcrdma_buffer *buf = &rep->rr_rxprt->rx_buf;
+
+       spin_lock(&buf->rb_lock);
+       list_del(&rep->rr_all);
+       spin_unlock(&buf->rb_lock);
+
+       rpcrdma_rep_free(rep);
+}
+
 static struct rpcrdma_rep *rpcrdma_rep_get_locked(struct rpcrdma_buffer *buf)
 {
        struct llist_node *node;
@@ -1049,8 +1056,18 @@ static void rpcrdma_reps_destroy(struct rpcrdma_buffer *buf)
 {
        struct rpcrdma_rep *rep;
 
-       while ((rep = rpcrdma_rep_get_locked(buf)) != NULL)
-               rpcrdma_rep_destroy(rep);
+       spin_lock(&buf->rb_lock);
+       while ((rep = list_first_entry_or_null(&buf->rb_all_reps,
+                                              struct rpcrdma_rep,
+                                              rr_all)) != NULL) {
+               list_del(&rep->rr_all);
+               spin_unlock(&buf->rb_lock);
+
+               rpcrdma_rep_free(rep);
+
+               spin_lock(&buf->rb_lock);
+       }
+       spin_unlock(&buf->rb_lock);
 }
 
 /**