xref: /linux/net/sunrpc/xprtrdma/ib_client.c (revision c2a96b7f187fb6a455836d4a6e113947ff11de97)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (c) 2024 Oracle.  All rights reserved.
4  */
5 
6 /* #include <linux/module.h>
7 #include <linux/slab.h> */
8 #include <linux/xarray.h>
9 #include <linux/types.h>
10 #include <linux/kref.h>
11 #include <linux/completion.h>
12 
13 #include <linux/sunrpc/svc_rdma.h>
14 #include <linux/sunrpc/rdma_rn.h>
15 
16 #include "xprt_rdma.h"
17 #include <trace/events/rpcrdma.h>
18 
19 /* Per-ib_device private data for rpcrdma */
20 struct rpcrdma_device {
21 	struct kref		rd_kref;
22 	unsigned long		rd_flags;
23 	struct ib_device	*rd_device;
24 	struct xarray		rd_xa;
25 	struct completion	rd_done;
26 };
27 
28 #define RPCRDMA_RD_F_REMOVING	(0)
29 
30 static struct ib_client rpcrdma_ib_client;
31 
32 /*
33  * Listeners have no associated device, so we never register them.
34  * Note that ib_get_client_data() does not check if @device is
35  * NULL for us.
36  */
37 static struct rpcrdma_device *rpcrdma_get_client_data(struct ib_device *device)
38 {
39 	if (!device)
40 		return NULL;
41 	return ib_get_client_data(device, &rpcrdma_ib_client);
42 }
43 
44 /**
45  * rpcrdma_rn_register - register to get device removal notifications
46  * @device: device to monitor
47  * @rn: notification object that wishes to be notified
48  * @done: callback to notify caller of device removal
49  *
50  * Returns zero on success. The callback in rn_done is guaranteed
51  * to be invoked when the device is removed, unless this notification
52  * is unregistered first.
53  *
54  * On failure, a negative errno is returned.
55  */
56 int rpcrdma_rn_register(struct ib_device *device,
57 			struct rpcrdma_notification *rn,
58 			void (*done)(struct rpcrdma_notification *rn))
59 {
60 	struct rpcrdma_device *rd = rpcrdma_get_client_data(device);
61 
62 	if (!rd || test_bit(RPCRDMA_RD_F_REMOVING, &rd->rd_flags))
63 		return -ENETUNREACH;
64 
65 	kref_get(&rd->rd_kref);
66 	if (xa_alloc(&rd->rd_xa, &rn->rn_index, rn, xa_limit_32b, GFP_KERNEL) < 0)
67 		return -ENOMEM;
68 	rn->rn_done = done;
69 	return 0;
70 }
71 
72 static void rpcrdma_rn_release(struct kref *kref)
73 {
74 	struct rpcrdma_device *rd = container_of(kref, struct rpcrdma_device,
75 						 rd_kref);
76 
77 	trace_rpcrdma_client_completion(rd->rd_device);
78 	complete(&rd->rd_done);
79 }
80 
81 /**
82  * rpcrdma_rn_unregister - stop device removal notifications
83  * @device: monitored device
84  * @rn: notification object that no longer wishes to be notified
85  */
86 void rpcrdma_rn_unregister(struct ib_device *device,
87 			   struct rpcrdma_notification *rn)
88 {
89 	struct rpcrdma_device *rd = rpcrdma_get_client_data(device);
90 
91 	if (!rd)
92 		return;
93 
94 	xa_erase(&rd->rd_xa, rn->rn_index);
95 	kref_put(&rd->rd_kref, rpcrdma_rn_release);
96 }
97 
98 /**
99  * rpcrdma_add_one - ib_client device insertion callback
100  * @device: device about to be inserted
101  *
102  * Returns zero on success. xprtrdma private data has been allocated
103  * for this device. On failure, a negative errno is returned.
104  */
105 static int rpcrdma_add_one(struct ib_device *device)
106 {
107 	struct rpcrdma_device *rd;
108 
109 	rd = kzalloc(sizeof(*rd), GFP_KERNEL);
110 	if (!rd)
111 		return -ENOMEM;
112 
113 	kref_init(&rd->rd_kref);
114 	xa_init_flags(&rd->rd_xa, XA_FLAGS_ALLOC1);
115 	rd->rd_device = device;
116 	init_completion(&rd->rd_done);
117 	ib_set_client_data(device, &rpcrdma_ib_client, rd);
118 
119 	trace_rpcrdma_client_add_one(device);
120 	return 0;
121 }
122 
123 /**
124  * rpcrdma_remove_one - ib_client device removal callback
125  * @device: device about to be removed
126  * @client_data: this module's private per-device data
127  *
128  * Upon return, all transports associated with @device have divested
129  * themselves from IB hardware resources.
130  */
131 static void rpcrdma_remove_one(struct ib_device *device,
132 			       void *client_data)
133 {
134 	struct rpcrdma_device *rd = client_data;
135 	struct rpcrdma_notification *rn;
136 	unsigned long index;
137 
138 	trace_rpcrdma_client_remove_one(device);
139 
140 	set_bit(RPCRDMA_RD_F_REMOVING, &rd->rd_flags);
141 	xa_for_each(&rd->rd_xa, index, rn)
142 		rn->rn_done(rn);
143 
144 	/*
145 	 * Wait only if there are still outstanding notification
146 	 * registrants for this device.
147 	 */
148 	if (!refcount_dec_and_test(&rd->rd_kref.refcount)) {
149 		trace_rpcrdma_client_wait_on(device);
150 		wait_for_completion(&rd->rd_done);
151 	}
152 
153 	trace_rpcrdma_client_remove_one_done(device);
154 	kfree(rd);
155 }
156 
157 static struct ib_client rpcrdma_ib_client = {
158 	.name		= "rpcrdma",
159 	.add		= rpcrdma_add_one,
160 	.remove		= rpcrdma_remove_one,
161 };
162 
163 /**
164  * rpcrdma_ib_client_unregister - unregister ib_client for xprtrdma
165  *
166  * cel: watch for orphaned rpcrdma_device objects on module unload
167  */
168 void rpcrdma_ib_client_unregister(void)
169 {
170 	ib_unregister_client(&rpcrdma_ib_client);
171 }
172 
173 /**
174  * rpcrdma_ib_client_register - register ib_client for rpcrdma
175  *
176  * Returns zero on success, or a negative errno.
177  */
178 int rpcrdma_ib_client_register(void)
179 {
180 	return ib_register_client(&rpcrdma_ib_client);
181 }
182