summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/rds/rdma.c14
-rw-r--r--net/rds/rds.h5
2 files changed, 17 insertions, 2 deletions
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
index f360a7b3b5fe..078090d292fa 100644
--- a/net/rds/rdma.c
+++ b/net/rds/rdma.c
@@ -117,6 +117,7 @@ void __rds_put_mr_final(struct kref *kref)
struct rds_mr *mr = container_of(kref, struct rds_mr, r_kref);
rds_destroy_mr(mr);
+ sock_put(rds_rs_to_sk(mr->r_sock));
kfree(mr);
}
@@ -243,7 +244,11 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
kref_init(&mr->r_kref);
RB_CLEAR_NODE(&mr->r_rb_node);
mr->r_trans = rs->rs_transport;
+ /* The MR can outlive its socket: a socket reference is held
+ * until the final kref is dropped in __rds_put_mr_final().
+ */
mr->r_sock = rs;
+ sock_hold(rds_rs_to_sk(rs));
if (args->flags & RDS_RDMA_USE_ONCE)
mr->r_use_once = 1;
@@ -759,7 +764,12 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
RB_CLEAR_NODE(&local_odp_mr->r_rb_node);
kref_init(&local_odp_mr->r_kref);
local_odp_mr->r_trans = rs->rs_transport;
+ /* The MR can outlive its socket: a socket
+ * reference is held until the final kref is
+ * dropped in __rds_put_mr_final().
+ */
local_odp_mr->r_sock = rs;
+ sock_hold(rds_rs_to_sk(rs));
local_odp_mr->r_trans_private =
rs->rs_transport->get_mr(
NULL, 0, rs, &local_odp_mr->r_key, NULL,
@@ -768,7 +778,9 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
ret = PTR_ERR(local_odp_mr->r_trans_private);
rdsdebug("get_mr ret %d %p\"", ret,
local_odp_mr->r_trans_private);
- kfree(local_odp_mr);
+ local_odp_mr->r_trans_private = NULL;
+ kref_put(&local_odp_mr->r_kref,
+ __rds_put_mr_final);
ret = -EOPNOTSUPP;
goto out_pages;
}
diff --git a/net/rds/rds.h b/net/rds/rds.h
index 14bff7440b79..2db49573dacd 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -320,7 +320,10 @@ struct rds_mr {
unsigned int r_invalidate:1;
unsigned int r_write:1;
- struct rds_sock *r_sock; /* back pointer to the socket that owns us */
+ struct rds_sock *r_sock; /* socket that owns us; counted
+ * reference, dropped by
+ * __rds_put_mr_final()
+ */
struct rds_transport *r_trans;
void *r_trans_private;
};