Whamcloud - gitweb
9d97bc1640431b9a86cc47cdcb3278ed0a8b1352
[fs/lustre-release.git] / lnet / lnet / lib-init.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * lib/lib-init.c
5  * Start up the internal library and clear all structures
6  * Called by the NAL when it initializes.  Safe to call multiple times.
7  *
8  *  Copyright (c) 2001-2003 Cluster File Systems, Inc.
9  *  Copyright (c) 2001-2002 Sandia National Laboratories
10  *
11  *   This file is part of Lustre, http://www.sf.net/projects/lustre/
12  *
13  *   Lustre is free software; you can redistribute it and/or
14  *   modify it under the terms of version 2 of the GNU General Public
15  *   License as published by the Free Software Foundation.
16  *
17  *   Lustre is distributed in the hope that it will be useful,
18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *   GNU General Public License for more details.
21  *
22  *   You should have received a copy of the GNU General Public License
23  *   along with Lustre; if not, write to the Free Software
24  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26
27 # define DEBUG_SUBSYSTEM S_PORTALS
28 #include <portals/lib-p30.h>
29
30 #ifdef __KERNEL__
31 # include <linux/string.h>      /* for memset() */
32 # include <linux/kp30.h>
33 # ifdef KERNEL_ADDR_CACHE
34 #  include <compute/OS/addrCache/cache.h>
35 # endif
36 #else
37 # include <string.h>
38 # include <sys/time.h>
39 #endif
40
41 #ifndef PTL_USE_LIB_FREELIST
42
43 int
44 kportal_descriptor_setup (lib_nal_t *nal,
45                           ptl_ni_limits_t *requested_limits,
46                           ptl_ni_limits_t *actual_limits)
47 {
48         /* Ignore requested limits! */
49         actual_limits->max_mes = INT_MAX;
50         actual_limits->max_mds = INT_MAX;
51         actual_limits->max_eqs = INT_MAX;
52
53         return PTL_OK;
54 }
55
56 void
57 kportal_descriptor_cleanup (lib_nal_t *nal)
58 {
59 }
60 #else
61
62 int
63 lib_freelist_init (lib_nal_t *nal, lib_freelist_t *fl, int n, int size)
64 {
65         char *space;
66
67         LASSERT (n > 0);
68
69         size += offsetof (lib_freeobj_t, fo_contents);
70
71         PORTAL_ALLOC(space, n * size);
72         if (space == NULL)
73                 return (PTL_NO_SPACE);
74
75         INIT_LIST_HEAD (&fl->fl_list);
76         fl->fl_objs = space;
77         fl->fl_nobjs = n;
78         fl->fl_objsize = size;
79
80         do
81         {
82                 memset (space, 0, size);
83                 list_add ((struct list_head *)space, &fl->fl_list);
84                 space += size;
85         } while (--n != 0);
86
87         return (PTL_OK);
88 }
89
90 void
91 lib_freelist_fini (lib_nal_t *nal, lib_freelist_t *fl)
92 {
93         struct list_head *el;
94         int               count;
95
96         if (fl->fl_nobjs == 0)
97                 return;
98
99         count = 0;
100         for (el = fl->fl_list.next; el != &fl->fl_list; el = el->next)
101                 count++;
102
103         LASSERT (count == fl->fl_nobjs);
104
105         PORTAL_FREE(fl->fl_objs, fl->fl_nobjs * fl->fl_objsize);
106         memset (fl, 0, sizeof (fl));
107 }
108
109 int
110 kportal_descriptor_setup (lib_nal_t *nal,
111                           ptl_ni_limits_t *requested_limits,
112                           ptl_ni_limits_t *actual_limits)
113 {
114         /* NB on failure caller must still call kportal_descriptor_cleanup */
115         /*               ******                                            */
116         lib_ni_t  *ni = &nal->libnal_ni;
117         int        rc;
118
119         memset (&ni->ni_free_mes,  0, sizeof (ni->ni_free_mes));
120         memset (&ni->ni_free_msgs, 0, sizeof (ni->ni_free_msgs));
121         memset (&ni->ni_free_mds,  0, sizeof (ni->ni_free_mds));
122         memset (&ni->ni_free_eqs,  0, sizeof (ni->ni_free_eqs));
123
124         /* Ignore requested limits! */
125         actual_limits->max_mes = MAX_MES;
126         actual_limits->max_mds = MAX_MDS;
127         actual_limits->max_eqs = MAX_EQS;
128         /* Hahahah what a load of bollocks.  There's nowhere to
129          * specify the max # messages in-flight */
130
131         rc = lib_freelist_init (nal, &ni->ni_free_mes,
132                                 MAX_MES, sizeof (lib_me_t));
133         if (rc != PTL_OK)
134                 return (rc);
135
136         rc = lib_freelist_init (nal, &ni->ni_free_msgs,
137                                 MAX_MSGS, sizeof (lib_msg_t));
138         if (rc != PTL_OK)
139                 return (rc);
140
141         rc = lib_freelist_init (nal, &ni->ni_free_mds,
142                                 MAX_MDS, sizeof (lib_md_t));
143         if (rc != PTL_OK)
144                 return (rc);
145
146         rc = lib_freelist_init (nal, &ni->ni_free_eqs,
147                                 MAX_EQS, sizeof (lib_eq_t));
148         return (rc);
149 }
150
151 void
152 kportal_descriptor_cleanup (lib_nal_t *nal)
153 {
154         lib_ni_t   *ni = &nal->libnal_ni;
155         
156         lib_freelist_fini (nal, &ni->ni_free_mes);
157         lib_freelist_fini (nal, &ni->ni_free_msgs);
158         lib_freelist_fini (nal, &ni->ni_free_mds);
159         lib_freelist_fini (nal, &ni->ni_free_eqs);
160 }
161
162 #endif
163
164 __u64
165 lib_create_interface_cookie (lib_nal_t *nal)
166 {
167         /* NB the interface cookie in wire handles guards against delayed
168          * replies and ACKs appearing valid in a new instance of the same
169          * interface.  Initialisation time, even if it's only implemented
170          * to millisecond resolution is probably easily good enough. */
171         struct timeval tv;
172         __u64          cookie;
173 #ifndef __KERNEL__
174         int            rc = gettimeofday (&tv, NULL);
175         LASSERT (rc == 0);
176 #else
177         do_gettimeofday(&tv);
178 #endif
179         cookie = tv.tv_sec;
180         cookie *= 1000000;
181         cookie += tv.tv_usec;
182         return (cookie);
183 }
184
185 int
186 lib_setup_handle_hash (lib_nal_t *nal) 
187 {
188         lib_ni_t *ni = &nal->libnal_ni;
189         int       i;
190         
191         /* Arbitrary choice of hash table size */
192 #ifdef __KERNEL__
193         ni->ni_lh_hash_size = PAGE_SIZE / sizeof (struct list_head);
194 #else
195         ni->ni_lh_hash_size = (MAX_MES + MAX_MDS + MAX_EQS)/4;
196 #endif
197         PORTAL_ALLOC(ni->ni_lh_hash_table,
198                      ni->ni_lh_hash_size * sizeof (struct list_head));
199         if (ni->ni_lh_hash_table == NULL)
200                 return (PTL_NO_SPACE);
201         
202         for (i = 0; i < ni->ni_lh_hash_size; i++)
203                 INIT_LIST_HEAD (&ni->ni_lh_hash_table[i]);
204
205         ni->ni_next_object_cookie = PTL_COOKIE_TYPES;
206         
207         return (PTL_OK);
208 }
209
210 void
211 lib_cleanup_handle_hash (lib_nal_t *nal)
212 {
213         lib_ni_t *ni = &nal->libnal_ni;
214
215         if (ni->ni_lh_hash_table == NULL)
216                 return;
217         
218         PORTAL_FREE(ni->ni_lh_hash_table,
219                     ni->ni_lh_hash_size * sizeof (struct list_head));
220 }
221
222 lib_handle_t *
223 lib_lookup_cookie (lib_nal_t *nal, __u64 cookie, int type) 
224 {
225         /* ALWAYS called with statelock held */
226         lib_ni_t            *ni = &nal->libnal_ni;
227         struct list_head    *list;
228         struct list_head    *el;
229         unsigned int         hash;
230
231         if ((cookie & (PTL_COOKIE_TYPES - 1)) != type)
232                 return (NULL);
233         
234         hash = ((unsigned int)cookie) % ni->ni_lh_hash_size;
235         list = &ni->ni_lh_hash_table[hash];
236         
237         list_for_each (el, list) {
238                 lib_handle_t *lh = list_entry (el, lib_handle_t, lh_hash_chain);
239                 
240                 if (lh->lh_cookie == cookie)
241                         return (lh);
242         }
243         
244         return (NULL);
245 }
246
247 void
248 lib_initialise_handle (lib_nal_t *nal, lib_handle_t *lh, int type) 
249 {
250         /* ALWAYS called with statelock held */
251         lib_ni_t       *ni = &nal->libnal_ni;
252         unsigned int    hash;
253
254         LASSERT (type >= 0 && type < PTL_COOKIE_TYPES);
255         lh->lh_cookie = ni->ni_next_object_cookie | type;
256         ni->ni_next_object_cookie += PTL_COOKIE_TYPES;
257         
258         hash = ((unsigned int)lh->lh_cookie) % ni->ni_lh_hash_size;
259         list_add (&lh->lh_hash_chain, &ni->ni_lh_hash_table[hash]);
260 }
261
262 void
263 lib_invalidate_handle (lib_nal_t *nal, lib_handle_t *lh)
264 {
265         list_del (&lh->lh_hash_chain);
266 }
267
268 int
269 lib_init(lib_nal_t *libnal, nal_t *apinal, 
270          ptl_process_id_t process_id,
271          ptl_ni_limits_t *requested_limits,
272          ptl_ni_limits_t *actual_limits)
273 {
274         int       rc = PTL_OK;
275         lib_ni_t *ni = &libnal->libnal_ni;
276         int       ptl_size;
277         int       i;
278         ENTRY;
279
280         /* NB serialised in PtlNIInit() */
281
282         lib_assert_wire_constants ();
283
284         /* Setup the API nal with the lib API handling functions */
285         apinal->nal_get_id    = lib_api_get_id;
286         apinal->nal_ni_status = lib_api_ni_status;
287         apinal->nal_ni_dist   = lib_api_ni_dist;
288         apinal->nal_fail_nid  = lib_api_fail_nid;
289         apinal->nal_me_attach = lib_api_me_attach;
290         apinal->nal_me_insert = lib_api_me_insert;
291         apinal->nal_me_unlink = lib_api_me_unlink;
292         apinal->nal_md_attach = lib_api_md_attach;
293         apinal->nal_md_bind   = lib_api_md_bind;
294         apinal->nal_md_unlink = lib_api_md_unlink;
295         apinal->nal_md_update = lib_api_md_update;
296         apinal->nal_eq_alloc  = lib_api_eq_alloc;
297         apinal->nal_eq_free   = lib_api_eq_free;
298         apinal->nal_eq_poll   = lib_api_eq_poll;
299         apinal->nal_put       = lib_api_put;
300         apinal->nal_get       = lib_api_get;
301
302         apinal->nal_data      = libnal;
303         ni->ni_api            = apinal;
304
305         rc = kportal_descriptor_setup (libnal, requested_limits, 
306                                        &ni->ni_actual_limits);
307         if (rc != PTL_OK)
308                 goto out;
309
310         memset(&ni->ni_counters, 0, sizeof(lib_counters_t));
311
312         INIT_LIST_HEAD (&ni->ni_active_msgs);
313         INIT_LIST_HEAD (&ni->ni_active_mds);
314         INIT_LIST_HEAD (&ni->ni_active_eqs);
315         INIT_LIST_HEAD (&ni->ni_test_peers);
316
317 #ifdef __KERNEL__
318         spin_lock_init (&ni->ni_lock);
319         init_waitqueue_head (&ni->ni_waitq);
320 #else
321         pthread_mutex_init(&ni->ni_mutex, NULL);
322         pthread_cond_init(&ni->ni_cond, NULL);
323 #endif
324
325         ni->ni_interface_cookie = lib_create_interface_cookie (libnal);
326         ni->ni_next_object_cookie = 0;
327         rc = lib_setup_handle_hash (libnal);
328         if (rc != PTL_OK)
329                 goto out;
330         
331         ni->ni_pid = process_id;
332
333         if (requested_limits != NULL)
334                 ptl_size = requested_limits->max_pt_index + 1;
335         else
336                 ptl_size = 64;
337
338         ni->ni_portals.size = ptl_size;
339         PORTAL_ALLOC(ni->ni_portals.tbl,
340                      ptl_size * sizeof(struct list_head));
341         if (ni->ni_portals.tbl == NULL) {
342                 rc = PTL_NO_SPACE;
343                 goto out;
344         }
345
346         for (i = 0; i < ptl_size; i++)
347                 INIT_LIST_HEAD(&(ni->ni_portals.tbl[i]));
348
349         /* max_{mes,mds,eqs} set in kportal_descriptor_setup */
350
351         /* We don't have an access control table! */
352         ni->ni_actual_limits.max_ac_index = -1;
353
354         ni->ni_actual_limits.max_pt_index = ptl_size - 1;
355         ni->ni_actual_limits.max_md_iovecs = PTL_MD_MAX_IOV;
356         ni->ni_actual_limits.max_me_list = INT_MAX;
357
358         /* We don't support PtlGetPut! */
359         ni->ni_actual_limits.max_getput_md = 0;
360
361         if (actual_limits != NULL)
362                 *actual_limits = ni->ni_actual_limits;
363
364  out:
365         if (rc != PTL_OK) {
366                 lib_cleanup_handle_hash (libnal);
367                 kportal_descriptor_cleanup (libnal);
368         }
369
370         RETURN (rc);
371 }
372
373 int
374 lib_fini(lib_nal_t *nal)
375 {
376         lib_ni_t *ni = &nal->libnal_ni;
377         int       idx;
378
379         /* NB no state_lock() since this is the last reference.  The NAL
380          * should have shut down already, so it should be safe to unlink
381          * and free all descriptors, even those that appear committed to a
382          * network op (eg MD with non-zero pending count)
383          */
384
385         for (idx = 0; idx < ni->ni_portals.size; idx++)
386                 while (!list_empty (&ni->ni_portals.tbl[idx])) {
387                         lib_me_t *me = list_entry (ni->ni_portals.tbl[idx].next,
388                                                    lib_me_t, me_list);
389
390                         CERROR ("Active me %p on exit\n", me);
391                         list_del (&me->me_list);
392                         lib_me_free (nal, me);
393                 }
394
395         while (!list_empty (&ni->ni_active_mds)) {
396                 lib_md_t *md = list_entry (ni->ni_active_mds.next,
397                                            lib_md_t, md_list);
398
399                 CERROR ("Active md %p on exit\n", md);
400                 list_del (&md->md_list);
401                 lib_md_free (nal, md);
402         }
403
404         while (!list_empty (&ni->ni_active_eqs)) {
405                 lib_eq_t *eq = list_entry (ni->ni_active_eqs.next,
406                                            lib_eq_t, eq_list);
407
408                 CERROR ("Active eq %p on exit\n", eq);
409                 list_del (&eq->eq_list);
410                 lib_eq_free (nal, eq);
411         }
412
413         while (!list_empty (&ni->ni_active_msgs)) {
414                 lib_msg_t *msg = list_entry (ni->ni_active_msgs.next,
415                                              lib_msg_t, msg_list);
416
417                 CERROR ("Active msg %p on exit\n", msg);
418                 list_del (&msg->msg_list);
419                 lib_msg_free (nal, msg);
420         }
421
422         PORTAL_FREE(ni->ni_portals.tbl,  
423                     ni->ni_portals.size * sizeof(struct list_head));
424
425         lib_cleanup_handle_hash (nal);
426         kportal_descriptor_cleanup (nal);
427
428 #ifndef __KERNEL__
429         pthread_mutex_destroy(&ni->ni_mutex);
430         pthread_cond_destroy(&ni->ni_cond);
431 #endif
432
433         return (PTL_OK);
434 }