Whamcloud - gitweb
LU-10391 lnet: change lnet_notify() to take struct lnet_nid
[fs/lustre-release.git] / lnet / klnds / kfilnd / kfilnd_peer.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright 2022 Hewlett Packard Enterprise Development LP
24  */
25 /*
26  * This file is part of Lustre, http://www.lustre.org/
27  */
28 /*
29  * kfilnd peer management implementation.
30  */
31 #include "kfilnd_peer.h"
32 #include "kfilnd_dev.h"
33
34 static const struct rhashtable_params peer_cache_params = {
35         .head_offset = offsetof(struct kfilnd_peer, node),
36         .key_offset = offsetof(struct kfilnd_peer, nid),
37         .key_len = sizeof_field(struct kfilnd_peer, nid),
38         .automatic_shrinking = true,
39 };
40
41 /**
42  * kfilnd_peer_free() - RCU safe way to free a peer.
43  * @ptr: Pointer to peer.
44  * @arg: Unused.
45  */
46 static void kfilnd_peer_free(void *ptr, void *arg)
47 {
48         struct kfilnd_peer *peer = ptr;
49
50         CDEBUG(D_NET, "%s(0x%llx) peer entry freed\n",
51                libcfs_nid2str(peer->nid), peer->addr);
52
53         kfi_av_remove(peer->dev->kfd_av, &peer->addr, 1, 0);
54
55         kfree_rcu(peer, rcu_head);
56 }
57
58 /**
59  * kfilnd_peer_down() - Mark a peer as down.
60  * @peer: Peer to be downed.
61  */
62 void kfilnd_peer_down(struct kfilnd_peer *peer)
63 {
64         if (atomic_cmpxchg(&peer->remove_peer, 0, 1) == 0) {
65                 struct lnet_nid peer_nid;
66
67                 lnet_nid4_to_nid(peer->nid, &peer_nid);
68                 CDEBUG(D_NET, "%s(0x%llx) marked for removal from peer cache\n",
69                        libcfs_nidstr(&peer_nid), peer->addr);
70
71                 lnet_notify(peer->dev->kfd_ni, &peer_nid, false, false,
72                             peer->last_alive);
73         }
74 }
75
76 /**
77  * kfilnd_peer_put() - Return a reference for a peer.
78  * @peer: Peer where the reference should be returned.
79  */
80 void kfilnd_peer_put(struct kfilnd_peer *peer)
81 {
82         rcu_read_lock();
83
84         /* Return allocation reference if the peer was marked for removal. */
85         if (atomic_cmpxchg(&peer->remove_peer, 1, 2) == 1) {
86                 rhashtable_remove_fast(&peer->dev->peer_cache, &peer->node,
87                                        peer_cache_params);
88                 refcount_dec(&peer->cnt);
89
90                 CDEBUG(D_NET, "%s(0x%llx) removed from peer cache\n",
91                        libcfs_nid2str(peer->nid), peer->addr);
92         }
93
94         if (refcount_dec_and_test(&peer->cnt))
95                 kfilnd_peer_free(peer, NULL);
96
97         rcu_read_unlock();
98 }
99
100 u16 kfilnd_peer_target_rx_base(struct kfilnd_peer *peer)
101 {
102         int cpt = lnet_cpt_of_nid(peer->nid, peer->dev->kfd_ni);
103         struct kfilnd_ep *ep = peer->dev->cpt_to_endpoint[cpt];
104
105         return ep->end_context_id;
106 }
107
108 /**
109  * kfilnd_peer_get() - Get a reference for a peer.
110  * @dev: Device used to lookup peer.
111  * @nid: LNet NID of peer.
112  *
113  * Return: On success, pointer to a valid peer structed. Else, ERR_PTR.
114  */
115 struct kfilnd_peer *kfilnd_peer_get(struct kfilnd_dev *dev, lnet_nid_t nid)
116 {
117         char *node;
118         char *service;
119         int rc;
120         u32 nid_addr = LNET_NIDADDR(nid);
121         u32 net_num = LNET_NETNUM(LNET_NIDNET(nid));
122         struct kfilnd_peer *peer;
123         struct kfilnd_peer *clash_peer;
124
125 again:
126         /* Check the cache for a match. */
127         rcu_read_lock();
128         peer = rhashtable_lookup_fast(&dev->peer_cache, &nid,
129                                       peer_cache_params);
130         if (peer && !refcount_inc_not_zero(&peer->cnt))
131                 peer = NULL;
132         rcu_read_unlock();
133
134         if (peer)
135                 return peer;
136
137         /* Allocate a new peer for the cache. */
138         peer = kzalloc(sizeof(*peer), GFP_KERNEL);
139         if (!peer) {
140                 rc = -ENOMEM;
141                 goto err;
142         }
143
144         node = kasprintf(GFP_KERNEL, "%#x", nid_addr);
145         if (!node) {
146                 rc = -ENOMEM;
147                 goto err_free_peer;
148         }
149
150         service = kasprintf(GFP_KERNEL, "%u", net_num);
151         if (!service) {
152                 rc = -ENOMEM;
153                 goto err_free_node_str;
154         }
155
156         /* Use the KFI address vector to translate node and service string into
157          * a KFI address handle.
158          */
159         rc = kfi_av_insertsvc(dev->kfd_av, node, service, &peer->addr, 0, dev);
160
161         kfree(service);
162         kfree(node);
163
164         if (rc < 0) {
165                 goto err_free_peer;
166         } else if (rc != 1) {
167                 rc = -ECONNABORTED;
168                 goto err_free_peer;
169         }
170
171         peer->dev = dev;
172         peer->nid = nid;
173         atomic_set(&peer->rx_base, 0);
174         atomic_set(&peer->remove_peer, 0);
175         peer->local_session_key = kfilnd_dev_get_session_key(dev);
176
177         /* One reference for the allocation and another for get operation
178          * performed for this peer. The allocation reference is returned when
179          * the entry is marked for removal.
180          */
181         refcount_set(&peer->cnt, 2);
182
183         clash_peer = rhashtable_lookup_get_insert_fast(&dev->peer_cache,
184                                                        &peer->node,
185                                                        peer_cache_params);
186
187         if (clash_peer) {
188                 kfi_av_remove(dev->kfd_av, &peer->addr, 1, 0);
189                 kfree(peer);
190
191                 if (IS_ERR(clash_peer)) {
192                         rc = PTR_ERR(clash_peer);
193                         goto err;
194                 } else {
195                         goto again;
196                 }
197         }
198
199         kfilnd_peer_alive(peer);
200
201         CDEBUG(D_NET, "%s(0x%llx) peer entry allocated\n",
202                libcfs_nid2str(peer->nid), peer->addr);
203
204         return peer;
205
206 err_free_node_str:
207         kfree(node);
208 err_free_peer:
209         kfree(peer);
210 err:
211         return ERR_PTR(rc);
212 }
213
214 /**
215  * kfilnd_peer_get_kfi_addr() - Return kfi_addr_t used for eager untagged send
216  * kfi operations.
217  * @peer: Peer struct.
218  *
219  * The returned kfi_addr_t is updated to target a specific RX context. The
220  * address return by this function should not be used if a specific RX context
221  * needs to be targeted (i/e the response RX context for a bulk transfer
222  * operation).
223  *
224  * Return: kfi_addr_t.
225  */
226 kfi_addr_t kfilnd_peer_get_kfi_addr(struct kfilnd_peer *peer)
227 {
228         /* TODO: Support RX count by round-robining the generated kfi_addr_t's
229          * across multiple RX contexts using RX base and RX count.
230          */
231         return kfi_rx_addr(KFILND_BASE_ADDR(peer->addr),
232                            atomic_read(&peer->rx_base), KFILND_FAB_RX_CTX_BITS);
233 }
234
235 /**
236  * kfilnd_peer_update_rx_contexts() - Update the RX context for a peer.
237  * @peer: Peer to be updated.
238  * @rx_base: New RX base for peer.
239  * @rx_count: New RX count for peer.
240  */
241 void kfilnd_peer_update_rx_contexts(struct kfilnd_peer *peer,
242                                     unsigned int rx_base, unsigned int rx_count)
243 {
244         /* TODO: Support RX count. */
245         LASSERT(rx_count > 0);
246         atomic_set(&peer->rx_base, rx_base);
247 }
248
249 /**
250  * kfilnd_peer_alive() - Update when the peer was last alive.
251  * @peer: Peer to be updated.
252  */
253 void kfilnd_peer_alive(struct kfilnd_peer *peer)
254 {
255         peer->last_alive = ktime_get_seconds();
256
257         /* Ensure timestamp is committed to memory before used. */
258         smp_mb();
259 }
260
261 /**
262  * kfilnd_peer_destroy() - Destroy peer cache.
263  * @dev: Device peer cache to be destroyed.
264  */
265 void kfilnd_peer_destroy(struct kfilnd_dev *dev)
266 {
267         rhashtable_free_and_destroy(&dev->peer_cache, kfilnd_peer_free, NULL);
268 }
269
270 /**
271  * kfilnd_peer_init() - Initialize peer cache.
272  * @dev: Device peer cache to be initialized.
273  */
274 void kfilnd_peer_init(struct kfilnd_dev *dev)
275 {
276         rhashtable_init(&dev->peer_cache, &peer_cache_params);
277 }