Whamcloud - gitweb
LU-56 lnet: cleanup for rtrpool and LNet counter
[fs/lustre-release.git] / lnet / lnet / 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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * lnet/lnet/peer.c
35  */
36
37 #define DEBUG_SUBSYSTEM S_LNET
38
39 #include <lnet/lib-lnet.h>
40
41 int
42 lnet_peer_table_create(void)
43 {
44         struct lnet_peer_table  *ptable;
45         cfs_list_t              *hash;
46         int                     j;
47
48         LIBCFS_ALLOC(ptable, sizeof(*ptable));
49         if (ptable == NULL) {
50                 CERROR("Failed to allocate cpu-partition peer tables\n");
51                 return -ENOMEM;
52         }
53
54         the_lnet.ln_peer_table = ptable;
55
56         do { /* we will have per CPT peer-tables iterate them by then */
57                 CFS_INIT_LIST_HEAD(&ptable->pt_deathrow);
58
59                 LIBCFS_ALLOC(hash, LNET_PEER_HASH_SIZE * sizeof(*hash));
60                 if (hash == NULL) {
61                         CERROR("Failed to create peer hash table\n");
62                         lnet_peer_table_destroy();
63                         return -ENOMEM;
64                 }
65
66                 for (j = 0; j < LNET_PEER_HASH_SIZE; j++)
67                         CFS_INIT_LIST_HEAD(&hash[j]);
68                 ptable->pt_hash = hash; /* sign of initialization */
69         } while (0);
70
71         return 0;
72 }
73
74 void
75 lnet_peer_table_destroy(void)
76 {
77         struct lnet_peer_table  *ptable;
78         cfs_list_t              *hash;
79         int                     j;
80
81         if (the_lnet.ln_peer_table == NULL)
82                 return;
83
84         ptable = the_lnet.ln_peer_table;
85
86         do { /* we will have per CPT peer-tables iterate them by then */
87                 hash = ptable->pt_hash;
88                 if (hash == NULL) /* not intialized */
89                         break;
90
91                 LASSERT(cfs_list_empty(&ptable->pt_deathrow));
92
93                 ptable->pt_hash = NULL;
94                 for (j = 0; j < LNET_PEER_HASH_SIZE; j++)
95                         LASSERT(cfs_list_empty(&hash[j]));
96
97                 LIBCFS_FREE(hash, LNET_PEER_HASH_SIZE * sizeof(*hash));
98         } while (0);
99
100         LIBCFS_FREE(ptable, sizeof(*ptable));
101         the_lnet.ln_peer_table = NULL;
102 }
103
104 void
105 lnet_peer_table_cleanup(void)
106 {
107         struct lnet_peer_table  *ptable;
108         int                     j;
109
110         LASSERT(the_lnet.ln_shutdown);  /* i.e. no new peers */
111         ptable = the_lnet.ln_peer_table;
112
113         do { /* we will have per CPT peer-tables iterate them by then */
114                 LNET_LOCK();
115
116                 for (j = 0; j < LNET_PEER_HASH_SIZE; j++) {
117                         cfs_list_t *peers = &ptable->pt_hash[j];
118
119                         while (!cfs_list_empty(peers)) {
120                                 lnet_peer_t *lp = cfs_list_entry(peers->next,
121                                                                  lnet_peer_t,
122                                                                  lp_hashlist);
123                                 cfs_list_del_init(&lp->lp_hashlist);
124                                 /* lose hash table's ref */
125                                 lnet_peer_decref_locked(lp);
126                         }
127                 }
128
129                 LNET_UNLOCK();
130         } while (0);
131
132         do { /* we will have per CPT peer-tables iterate them by then */
133                 CFS_LIST_HEAD   (deathrow);
134                 lnet_peer_t     *lp;
135
136                 LNET_LOCK();
137
138                 for (j = 3; ptable->pt_number != 0; j++) {
139                         LNET_UNLOCK();
140
141                         if ((j & (j - 1)) == 0) {
142                                 CDEBUG(D_WARNING,
143                                        "Waiting for %d peers on peer table\n",
144                                        ptable->pt_number);
145                         }
146                         cfs_pause(cfs_time_seconds(1) / 2);
147                         LNET_LOCK();
148                 }
149                 cfs_list_splice_init(&ptable->pt_deathrow, &deathrow);
150
151                 LNET_UNLOCK();
152
153                 while (!cfs_list_empty(&deathrow)) {
154                         lp = cfs_list_entry(deathrow.next,
155                                             lnet_peer_t, lp_hashlist);
156                         cfs_list_del(&lp->lp_hashlist);
157                         LIBCFS_FREE(lp, sizeof(*lp));
158                 }
159         } while (0);
160 }
161
162 void
163 lnet_destroy_peer_locked(lnet_peer_t *lp)
164 {
165         struct lnet_peer_table *ptable = the_lnet.ln_peer_table;
166
167         LASSERT(lp->lp_refcount == 0);
168         LASSERT(lp->lp_rtr_refcount == 0);
169         LASSERT(cfs_list_empty(&lp->lp_txq));
170         LASSERT(cfs_list_empty(&lp->lp_hashlist));
171         LASSERT(lp->lp_txqnob == 0);
172
173         LASSERT(ptable->pt_number > 0);
174         ptable->pt_number--;
175
176         lnet_ni_decref_locked(lp->lp_ni);
177         lp->lp_ni = NULL;
178
179         cfs_list_add(&lp->lp_hashlist, &ptable->pt_deathrow);
180 }
181
182 lnet_peer_t *
183 lnet_find_peer_locked(lnet_nid_t nid)
184 {
185         cfs_list_t      *peers;
186         lnet_peer_t     *lp;
187
188         if (the_lnet.ln_shutdown)
189                 return NULL;
190
191         peers = &the_lnet.ln_peer_table->pt_hash[lnet_nid2peerhash(nid)];
192         cfs_list_for_each_entry(lp, peers, lp_hashlist) {
193                 if (lp->lp_nid == nid) {
194                         lnet_peer_addref_locked(lp);
195                         return lp;
196                 }
197         }
198
199         return NULL;
200 }
201
202 int
203 lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid)
204 {
205         struct lnet_peer_table  *ptable = the_lnet.ln_peer_table;
206         lnet_peer_t             *lp = NULL;
207         lnet_peer_t             *lp2;
208
209         lp = lnet_find_peer_locked(nid);
210         if (lp != NULL) {
211                 *lpp = lp;
212                 return 0;
213         }
214
215         if (!cfs_list_empty(&ptable->pt_deathrow)) {
216                 lp = cfs_list_entry(ptable->pt_deathrow.next,
217                                     lnet_peer_t, lp_hashlist);
218                 cfs_list_del(&lp->lp_hashlist);
219         }
220
221         LNET_UNLOCK();
222
223         if (lp != NULL)
224                 memset(lp, 0, sizeof(*lp));
225         else
226                 LIBCFS_ALLOC(lp, sizeof(*lp));
227
228         if (lp == NULL) {
229                 *lpp = NULL;
230                 LNET_LOCK();
231                 return -ENOMEM;
232         }
233
234         CFS_INIT_LIST_HEAD(&lp->lp_txq);
235         CFS_INIT_LIST_HEAD(&lp->lp_rtrq);
236         CFS_INIT_LIST_HEAD(&lp->lp_routes);
237
238         lp->lp_notify = 0;
239         lp->lp_notifylnd = 0;
240         lp->lp_notifying = 0;
241         lp->lp_alive_count = 0;
242         lp->lp_timestamp = 0;
243         lp->lp_alive = !lnet_peers_start_down(); /* 1 bit!! */
244         lp->lp_last_alive = cfs_time_current(); /* assumes alive */
245         lp->lp_last_query = 0; /* haven't asked NI yet */
246         lp->lp_ping_timestamp = 0;
247         lp->lp_ping_version = LNET_PROTO_PING_UNKNOWN;
248         lp->lp_nid = nid;
249         lp->lp_refcount = 2;                    /* 1 for caller; 1 for hash */
250         lp->lp_rtr_refcount = 0;
251
252         LNET_LOCK();
253
254         lp2 = lnet_find_peer_locked(nid);
255         if (lp2 != NULL) {
256                 cfs_list_add(&lp->lp_hashlist, &ptable->pt_deathrow);
257
258                 if (the_lnet.ln_shutdown) {
259                         lnet_peer_decref_locked(lp2);
260                         *lpp = NULL;
261                         return -ESHUTDOWN;
262                 }
263
264                 *lpp = lp2;
265                 return 0;
266         }
267                 
268         lp->lp_ni = lnet_net2ni_locked(LNET_NIDNET(nid));
269         if (lp->lp_ni == NULL) {
270                 cfs_list_add(&lp->lp_hashlist, &ptable->pt_deathrow);
271
272                 *lpp = NULL;
273                 return the_lnet.ln_shutdown ? -ESHUTDOWN : -EHOSTUNREACH;
274         }
275
276         lp->lp_txcredits    =
277         lp->lp_mintxcredits = lp->lp_ni->ni_peertxcredits;
278         lp->lp_rtrcredits    =
279         lp->lp_minrtrcredits = lnet_peer_buffer_credits(lp->lp_ni);
280
281         /* can't add peers after shutdown starts */
282         LASSERT (!the_lnet.ln_shutdown);
283
284         cfs_list_add_tail(&lp->lp_hashlist,
285                           &ptable->pt_hash[lnet_nid2peerhash(nid)]);
286         ptable->pt_version++;
287         ptable->pt_number++;
288
289         *lpp = lp;
290         return 0;
291 }
292
293 void
294 lnet_debug_peer(lnet_nid_t nid)
295 {
296         char        *aliveness = "NA";
297         int          rc;
298         lnet_peer_t *lp;
299
300         LNET_LOCK();
301
302         rc = lnet_nid2peer_locked(&lp, nid);
303         if (rc != 0) {
304                 LNET_UNLOCK();
305                 CDEBUG(D_WARNING, "No peer %s\n", libcfs_nid2str(nid));
306                 return;
307         }
308
309         if (lnet_isrouter(lp) || lnet_peer_aliveness_enabled(lp))
310                 aliveness = lp->lp_alive ? "up" : "down";
311
312         CDEBUG(D_WARNING, "%-24s %4d %5s %5d %5d %5d %5d %5d %ld\n",
313                libcfs_nid2str(lp->lp_nid), lp->lp_refcount,
314                aliveness, lp->lp_ni->ni_peertxcredits,
315                lp->lp_rtrcredits, lp->lp_minrtrcredits,
316                lp->lp_txcredits, lp->lp_mintxcredits, lp->lp_txqnob);
317
318         lnet_peer_decref_locked(lp);
319
320         LNET_UNLOCK();
321 }