Whamcloud - gitweb
use generic LIST_HEAD macros instead of linux specific.
[fs/lustre-release.git] / lnet / lnet / peer.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * lib/lib-move.c
5  * Data movement routines
6  *
7  *  Copyright (c) 2001-2003 Cluster File Systems, Inc.
8  *
9  *   This file is part of Lustre, http://www.lustre.org
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #define DEBUG_SUBSYSTEM S_LNET
26
27 #include <lnet/lib-lnet.h>
28
29 int
30 lnet_create_peer_table(void)
31 {
32         struct list_head *hash;
33         int               i;
34
35         LASSERT (the_lnet.ln_peer_hash == NULL);
36         LIBCFS_ALLOC(hash, LNET_PEER_HASHSIZE * sizeof(struct list_head));
37         
38         if (hash == NULL) {
39                 CERROR("Can't allocate peer hash table\n");
40                 return -ENOMEM;
41         }
42
43         for (i = 0; i < LNET_PEER_HASHSIZE; i++)
44                 CFS_INIT_LIST_HEAD(&hash[i]);
45
46         the_lnet.ln_peer_hash = hash;
47         return 0;
48 }
49
50 void
51 lnet_destroy_peer_table(void)
52 {
53         int         i;
54
55         if (the_lnet.ln_peer_hash == NULL)
56                 return;
57
58         for (i = 0; i < LNET_PEER_HASHSIZE; i++)
59                 LASSERT (list_empty(&the_lnet.ln_peer_hash[i]));
60         
61         LIBCFS_FREE(the_lnet.ln_peer_hash,
62                     LNET_PEER_HASHSIZE * sizeof (struct list_head));
63         the_lnet.ln_peer_hash = NULL;
64 }
65
66 void
67 lnet_clear_peer_table(void)
68 {
69         int         i;
70
71         LASSERT (the_lnet.ln_shutdown);         /* i.e. no new peers */
72         
73         for (i = 0; i < LNET_PEER_HASHSIZE; i++) {
74                 struct list_head *peers = &the_lnet.ln_peer_hash[i];
75
76                 LNET_LOCK();
77                 while (!list_empty(peers)) {
78                         lnet_peer_t *lp = list_entry(peers->next,
79                                                      lnet_peer_t, lp_hashlist);
80                         
81                         list_del(&lp->lp_hashlist);
82                         lnet_peer_decref_locked(lp);   /* lose hash table's ref */
83                 }
84                 LNET_UNLOCK();
85         }
86
87         LNET_LOCK();
88         for (i = 3; the_lnet.ln_npeers != 0;i++) {
89                 LNET_UNLOCK();
90
91                 if ((i & (i-1)) == 0)
92                         CDEBUG(D_WARNING,"Waiting for %d peers\n", 
93                                the_lnet.ln_npeers);
94                 cfs_pause(cfs_time_seconds(1));
95
96                 LNET_LOCK();
97         }
98         LNET_UNLOCK();
99 }
100
101 void
102 lnet_destroy_peer_locked (lnet_peer_t *lp) 
103 {
104         lnet_ni_decref_locked(lp->lp_ni);
105         LNET_UNLOCK();
106
107         LASSERT (lp->lp_refcount == 0);
108         LASSERT (lp->lp_rtr_refcount == 0);
109         LASSERT (list_empty(&lp->lp_txq));
110         LASSERT (lp->lp_txqnob == 0);
111
112         LIBCFS_FREE(lp, sizeof(*lp));
113
114         LNET_LOCK();
115
116         LASSERT(the_lnet.ln_npeers > 0);
117         the_lnet.ln_npeers--;
118 }
119
120 lnet_peer_t *
121 lnet_find_peer_locked (lnet_nid_t nid)
122 {
123         unsigned int      idx = LNET_NIDADDR(nid) % LNET_PEER_HASHSIZE;
124         struct list_head *peers = &the_lnet.ln_peer_hash[idx];
125         struct list_head *tmp;
126         lnet_peer_t      *lp;
127
128         if (the_lnet.ln_shutdown)
129                 return NULL;
130
131         list_for_each (tmp, peers) {
132                 lp = list_entry(tmp, lnet_peer_t, lp_hashlist);
133                 
134                 if (lp->lp_nid == nid) {
135                         lnet_peer_addref_locked(lp);
136                         return lp;
137                 }
138         }
139         
140         return NULL;
141 }
142
143 int
144 lnet_nid2peer_locked(lnet_peer_t **lpp, lnet_nid_t nid)
145 {
146         lnet_peer_t    *lp;
147         lnet_peer_t    *lp2;
148
149         lp = lnet_find_peer_locked(nid);
150         if (lp != NULL) {
151                 *lpp = lp;
152                 return 0;
153         }
154         
155         LNET_UNLOCK();
156         
157         LIBCFS_ALLOC(lp, sizeof(*lp));
158         if (lp == NULL) {
159                 *lpp = NULL;
160                 LNET_LOCK();
161                 return -ENOMEM;
162         }
163
164         memset(lp, 0, sizeof(*lp));             /* zero counters etc */
165         
166         CFS_INIT_LIST_HEAD(&lp->lp_txq);
167         CFS_INIT_LIST_HEAD(&lp->lp_rtrq);
168         
169         lp->lp_alive = !lnet_peers_start_down(); /* 1 bit!! */
170         lp->lp_notify = 0;
171         lp->lp_notifylnd = 0;
172         lp->lp_notifying = 0;
173         lp->lp_alive_count = 0;
174         lp->lp_timestamp = 0;
175         lp->lp_ping_timestamp = 0;
176         lp->lp_nid = nid;
177         lp->lp_refcount = 2;                    /* 1 for caller; 1 for hash */
178         lp->lp_rtr_refcount = 0;
179
180         LNET_LOCK();
181
182         lp2 = lnet_find_peer_locked(nid);
183         if (lp2 != NULL) {
184                 LNET_UNLOCK();
185                 LIBCFS_FREE(lp, sizeof(*lp));
186                 LNET_LOCK();
187
188                 if (the_lnet.ln_shutdown) {
189                         lnet_peer_decref_locked(lp2);
190                         *lpp = NULL;
191                         return -ESHUTDOWN;
192                 }
193
194                 *lpp = lp2;
195                 return 0;
196         }
197                 
198         lp->lp_ni = lnet_net2ni_locked(LNET_NIDNET(nid));
199         if (lp->lp_ni == NULL) {
200                 LNET_UNLOCK();
201                 LIBCFS_FREE(lp, sizeof(*lp));
202                 LNET_LOCK();
203
204                 *lpp = NULL;
205                 return the_lnet.ln_shutdown ? -ESHUTDOWN : -EHOSTUNREACH;
206         }
207
208         lp->lp_txcredits = 
209                 lp->lp_mintxcredits = lp->lp_ni->ni_peertxcredits;
210
211         /* As a first approximation; allow this peer the same number of router
212          * buffers as it is allowed outstanding sends */
213         lp->lp_rtrcredits = lp->lp_minrtrcredits = lp->lp_txcredits;
214
215         LASSERT (!the_lnet.ln_shutdown);
216         /* can't add peers after shutdown starts */
217
218         list_add_tail(&lp->lp_hashlist, lnet_nid2peerhash(nid));
219         the_lnet.ln_npeers++;
220         the_lnet.ln_peertable_version++;
221         *lpp = lp;
222         return 0;
223 }
224
225 void
226 lnet_debug_peer(lnet_nid_t nid)
227 {
228         int          rc;
229         lnet_peer_t *lp;
230
231         LNET_LOCK();
232         
233         rc = lnet_nid2peer_locked(&lp, nid);
234         if (rc != 0) {
235                 LNET_UNLOCK();
236                 CDEBUG(D_WARNING, "No peer %s\n", libcfs_nid2str(nid));
237                 return;
238         }
239
240         CDEBUG(D_WARNING, "%-24s %4d %5s %5d %5d %5d %5d %5d %ld\n",
241                libcfs_nid2str(lp->lp_nid), lp->lp_refcount, 
242                !lnet_isrouter(lp) ? "~rtr" : (lp->lp_alive ? "up" : "down"),
243                lp->lp_ni->ni_peertxcredits, 
244                lp->lp_rtrcredits, lp->lp_minrtrcredits, 
245                lp->lp_txcredits, lp->lp_mintxcredits, lp->lp_txqnob);
246
247         lnet_peer_decref_locked(lp);
248
249         LNET_UNLOCK();
250 }