Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[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 #ifdef PTL_USE_SLAB_CACHE
42 static int ptl_slab_users;
43
44 kmem_cache_t *ptl_md_slab;
45 kmem_cache_t *ptl_msg_slab;
46 kmem_cache_t *ptl_me_slab;
47 kmem_cache_t *ptl_eq_slab;
48
49 atomic_t md_in_use_count;
50 atomic_t msg_in_use_count;
51 atomic_t me_in_use_count;
52 atomic_t eq_in_use_count;
53
54 /* NB zeroing in ctor and on freeing ensures items that
55  * kmem_cache_validate() OK, but haven't been initialised
56  * as an MD/ME/EQ can't have valid handles
57  */
58 static void
59 ptl_md_slab_ctor (void *obj, kmem_cache_t *slab, unsigned long flags)
60 {
61         memset (obj, 0, sizeof (lib_md_t));
62 }
63
64 static void
65 ptl_me_slab_ctor (void *obj, kmem_cache_t *slab, unsigned long flags)
66 {
67         memset (obj, 0, sizeof (lib_me_t));
68 }
69
70 static void
71 ptl_eq_slab_ctor (void *obj, kmem_cache_t *slab, unsigned long flags)
72 {
73         memset (obj, 0, sizeof (lib_eq_t));
74 }
75
76 int
77 kportal_descriptor_setup (nal_cb_t *nal)
78 {
79         /* NB on failure caller must still call kportal_descriptor_cleanup */
80         /*               ******                                            */
81
82         /* We'll have 1 set of slabs for ALL the nals :) */
83
84         if (ptl_slab_users++)
85                 return 0;
86
87         ptl_md_slab = kmem_cache_create("portals_MD",
88                                         sizeof(lib_md_t), 0,
89                                         SLAB_HWCACHE_ALIGN,
90                                         ptl_md_slab_ctor, NULL);
91         if (!ptl_md_slab) {
92                 CERROR("couldn't allocate ptl_md_t slab");
93                 RETURN (PTL_NOSPACE);
94         }
95
96         /* NB no ctor for msgs; they don't need handle verification */
97         ptl_msg_slab = kmem_cache_create("portals_MSG",
98                                          sizeof(lib_msg_t), 0,
99                                          SLAB_HWCACHE_ALIGN,
100                                          NULL, NULL);
101         if (!ptl_msg_slab) {
102                 CERROR("couldn't allocate ptl_msg_t slab");
103                 RETURN (PTL_NOSPACE);
104         }
105
106         ptl_me_slab = kmem_cache_create("portals_ME",
107                                         sizeof(lib_me_t), 0,
108                                         SLAB_HWCACHE_ALIGN,
109                                         ptl_me_slab_ctor, NULL);
110         if (!ptl_me_slab) {
111                 CERROR("couldn't allocate ptl_me_t slab");
112                 RETURN (PTL_NOSPACE);
113         }
114
115         ptl_eq_slab = kmem_cache_create("portals_EQ",
116                                         sizeof(lib_eq_t), 0,
117                                         SLAB_HWCACHE_ALIGN,
118                                         ptl_eq_slab_ctor, NULL);
119         if (!ptl_eq_slab) {
120                 CERROR("couldn't allocate ptl_eq_t slab");
121                 RETURN (PTL_NOSPACE);
122         }
123
124         RETURN(PTL_OK);
125 }
126
127 void
128 kportal_descriptor_cleanup (nal_cb_t *nal)
129 {
130         int rc;
131
132         if (--ptl_slab_users != 0)
133                 return;
134
135         LASSERT (atomic_read (&md_in_use_count) == 0);
136         LASSERT (atomic_read (&me_in_use_count) == 0);
137         LASSERT (atomic_read (&eq_in_use_count) == 0);
138         LASSERT (atomic_read (&msg_in_use_count) == 0);
139
140         if (ptl_md_slab != NULL) {
141                 rc = kmem_cache_destroy(ptl_md_slab);
142                 if (rc != 0)
143                         CERROR("unable to free MD slab\n");
144         }
145         if (ptl_msg_slab != NULL) {
146                 rc = kmem_cache_destroy(ptl_msg_slab);
147                 if (rc != 0)
148                         CERROR("unable to free MSG slab\n");
149         }
150         if (ptl_me_slab != NULL) {
151                 rc = kmem_cache_destroy(ptl_me_slab);
152                 if (rc != 0)
153                         CERROR("unable to free ME slab\n");
154         }
155         if (ptl_eq_slab != NULL) {
156                 rc = kmem_cache_destroy(ptl_eq_slab);
157                 if (rc != 0)
158                         CERROR("unable to free EQ slab\n");
159         }
160 }
161 #else
162
163 int
164 lib_freelist_init (nal_cb_t *nal, lib_freelist_t *fl, int n, int size)
165 {
166         char *space;
167
168         LASSERT (n > 0);
169
170         size += offsetof (lib_freeobj_t, fo_contents);
171
172         space = nal->cb_malloc (nal, n * size);
173         if (space == NULL)
174                 return (PTL_NOSPACE);
175
176         INIT_LIST_HEAD (&fl->fl_list);
177         fl->fl_objs = space;
178         fl->fl_nobjs = n;
179         fl->fl_objsize = size;
180
181         do
182         {
183                 memset (space, 0, size);
184                 list_add ((struct list_head *)space, &fl->fl_list);
185                 space += size;
186         } while (--n != 0);
187
188         return (PTL_OK);
189 }
190
191 void
192 lib_freelist_fini (nal_cb_t *nal, lib_freelist_t *fl)
193 {
194         struct list_head *el;
195         int               count;
196
197         if (fl->fl_nobjs == 0)
198                 return;
199
200         count = 0;
201         for (el = fl->fl_list.next; el != &fl->fl_list; el = el->next)
202                 count++;
203
204         LASSERT (count == fl->fl_nobjs);
205
206         nal->cb_free (nal, fl->fl_objs, fl->fl_nobjs * fl->fl_objsize);
207         memset (fl, 0, sizeof (fl));
208 }
209
210 int
211 kportal_descriptor_setup (nal_cb_t *nal)
212 {
213         /* NB on failure caller must still call kportal_descriptor_cleanup */
214         /*               ******                                            */
215         int rc;
216
217         memset (&nal->ni.ni_free_mes,  0, sizeof (nal->ni.ni_free_mes));
218         memset (&nal->ni.ni_free_msgs, 0, sizeof (nal->ni.ni_free_msgs));
219         memset (&nal->ni.ni_free_mds,  0, sizeof (nal->ni.ni_free_mds));
220         memset (&nal->ni.ni_free_eqs,  0, sizeof (nal->ni.ni_free_eqs));
221
222         rc = lib_freelist_init (nal, &nal->ni.ni_free_mes,
223                                 MAX_MES, sizeof (lib_me_t));
224         if (rc != PTL_OK)
225                 return (rc);
226
227         rc = lib_freelist_init (nal, &nal->ni.ni_free_msgs,
228                                 MAX_MSGS, sizeof (lib_msg_t));
229         if (rc != PTL_OK)
230                 return (rc);
231
232         rc = lib_freelist_init (nal, &nal->ni.ni_free_mds,
233                                 MAX_MDS, sizeof (lib_md_t));
234         if (rc != PTL_OK)
235                 return (rc);
236
237         rc = lib_freelist_init (nal, &nal->ni.ni_free_eqs,
238                                 MAX_EQS, sizeof (lib_eq_t));
239         return (rc);
240 }
241
242 void
243 kportal_descriptor_cleanup (nal_cb_t *nal)
244 {
245         lib_freelist_fini (nal, &nal->ni.ni_free_mes);
246         lib_freelist_fini (nal, &nal->ni.ni_free_msgs);
247         lib_freelist_fini (nal, &nal->ni.ni_free_mds);
248         lib_freelist_fini (nal, &nal->ni.ni_free_eqs);
249 }
250
251 #endif
252
253 __u64
254 lib_create_interface_cookie (nal_cb_t *nal)
255 {
256         /* NB the interface cookie in wire handles guards against delayed
257          * replies and ACKs appearing valid in a new instance of the same
258          * interface.  Initialisation time, even if it's only implemented
259          * to millisecond resolution is probably easily good enough. */
260         struct timeval tv;
261         __u64          cookie;
262 #ifndef __KERNEL__
263         int            rc = gettimeofday (&tv, NULL);
264         LASSERT (rc == 0);
265 #else
266         do_gettimeofday(&tv);
267 #endif
268         cookie = tv.tv_sec;
269         cookie *= 1000000;
270         cookie += tv.tv_usec;
271         return (cookie);
272 }
273
274 int
275 lib_setup_handle_hash (nal_cb_t *nal) 
276 {
277         lib_ni_t *ni = &nal->ni;
278         int       i;
279         
280         /* Arbitrary choice of hash table size */
281 #ifdef __KERNEL__
282         ni->ni_lh_hash_size = PAGE_SIZE / sizeof (struct list_head);
283 #else
284         ni->ni_lh_hash_size = (MAX_MES + MAX_MDS + MAX_EQS)/4;
285 #endif
286         ni->ni_lh_hash_table = 
287                 (struct list_head *)nal->cb_malloc (nal, ni->ni_lh_hash_size
288                                                     * sizeof (struct list_head));
289         if (ni->ni_lh_hash_table == NULL)
290                 return (PTL_NOSPACE);
291         
292         for (i = 0; i < ni->ni_lh_hash_size; i++)
293                 INIT_LIST_HEAD (&ni->ni_lh_hash_table[i]);
294
295         ni->ni_next_object_cookie = PTL_COOKIE_TYPES;
296         
297         return (PTL_OK);
298 }
299
300 void
301 lib_cleanup_handle_hash (nal_cb_t *nal)
302 {
303         lib_ni_t *ni = &nal->ni;
304
305         if (ni->ni_lh_hash_table == NULL)
306                 return;
307         
308         nal->cb_free (nal, ni->ni_lh_hash_table,
309                       ni->ni_lh_hash_size * sizeof (struct list_head));
310 }
311
312 lib_handle_t *
313 lib_lookup_cookie (nal_cb_t *nal, __u64 cookie, int type) 
314 {
315         /* ALWAYS called with statelock held */
316         lib_ni_t            *ni = &nal->ni;
317         struct list_head    *list;
318         struct list_head    *el;
319         unsigned int         hash;
320
321         if ((cookie & (PTL_COOKIE_TYPES - 1)) != type)
322                 return (NULL);
323         
324         hash = ((unsigned int)cookie) % ni->ni_lh_hash_size;
325         list = &ni->ni_lh_hash_table[hash];
326         
327         list_for_each (el, list) {
328                 lib_handle_t *lh = list_entry (el, lib_handle_t, lh_hash_chain);
329                 
330                 if (lh->lh_cookie == cookie)
331                         return (lh);
332         }
333         
334         return (NULL);
335 }
336
337 void
338 lib_initialise_handle (nal_cb_t *nal, lib_handle_t *lh, int type) 
339 {
340         /* ALWAYS called with statelock held */
341         lib_ni_t       *ni = &nal->ni;
342         unsigned int    hash;
343
344         LASSERT (type >= 0 && type < PTL_COOKIE_TYPES);
345         lh->lh_cookie = ni->ni_next_object_cookie | type;
346         ni->ni_next_object_cookie += PTL_COOKIE_TYPES;
347         
348         hash = ((unsigned int)lh->lh_cookie) % ni->ni_lh_hash_size;
349         list_add (&lh->lh_hash_chain, &ni->ni_lh_hash_table[hash]);
350 }
351
352 void
353 lib_invalidate_handle (nal_cb_t *nal, lib_handle_t *lh)
354 {
355         list_del (&lh->lh_hash_chain);
356 }
357
358 int
359 lib_init(nal_cb_t * nal, ptl_nid_t nid, ptl_pid_t pid, int gsize,
360          ptl_pt_index_t ptl_size, ptl_ac_index_t acl_size)
361 {
362         int       rc = PTL_OK;
363         lib_ni_t *ni = &nal->ni;
364         int i;
365         ENTRY;
366
367         /* NB serialised in PtlNIInit() */
368
369         if (ni->refcnt != 0) {                       /* already initialised */
370                 ni->refcnt++;
371                 goto out;
372         }
373
374         lib_assert_wire_constants ();
375         
376         /*
377          * Allocate the portal table for this interface
378          * and all per-interface objects.
379          */
380         memset(&ni->counters, 0, sizeof(lib_counters_t));
381
382         rc = kportal_descriptor_setup (nal);
383         if (rc != PTL_OK)
384                 goto out;
385
386         INIT_LIST_HEAD (&ni->ni_active_msgs);
387         INIT_LIST_HEAD (&ni->ni_active_mds);
388         INIT_LIST_HEAD (&ni->ni_active_eqs);
389
390         INIT_LIST_HEAD (&ni->ni_test_peers);
391
392         ni->ni_interface_cookie = lib_create_interface_cookie (nal);
393         ni->ni_next_object_cookie = 0;
394         rc = lib_setup_handle_hash (nal);
395         if (rc != PTL_OK)
396                 goto out;
397         
398         ni->nid = nid;
399         ni->pid = pid;
400
401         ni->num_nodes = gsize;
402         ni->tbl.size = ptl_size;
403
404         ni->tbl.tbl = nal->cb_malloc(nal, sizeof(struct list_head) * ptl_size);
405         if (ni->tbl.tbl == NULL) {
406                 rc = PTL_NOSPACE;
407                 goto out;
408         }
409
410         for (i = 0; i < ptl_size; i++)
411                 INIT_LIST_HEAD(&(ni->tbl.tbl[i]));
412
413         ni->debug = PTL_DEBUG_NONE;
414         ni->up = 1;
415         ni->refcnt++;
416
417  out:
418         if (rc != PTL_OK) {
419                 lib_cleanup_handle_hash (nal);
420                 kportal_descriptor_cleanup (nal);
421         }
422
423         RETURN (rc);
424 }
425
426 int
427 lib_fini(nal_cb_t * nal)
428 {
429         lib_ni_t *ni = &nal->ni;
430         int       idx;
431
432         ni->refcnt--;
433
434         if (ni->refcnt != 0)
435                 goto out;
436
437         /* NB no stat_lock() since this is the last reference.  The NAL
438          * should have shut down already, so it should be safe to unlink
439          * and free all descriptors, even those that appear committed to a
440          * network op (eg MD with non-zero pending count)
441          */
442
443         for (idx = 0; idx < ni->tbl.size; idx++)
444                 while (!list_empty (&ni->tbl.tbl[idx])) {
445                         lib_me_t *me = list_entry (ni->tbl.tbl[idx].next,
446                                                    lib_me_t, me_list);
447
448                         CERROR ("Active me %p on exit\n", me);
449                         list_del (&me->me_list);
450                         lib_me_free (nal, me);
451                 }
452
453         while (!list_empty (&ni->ni_active_mds)) {
454                 lib_md_t *md = list_entry (ni->ni_active_mds.next,
455                                            lib_md_t, md_list);
456
457                 CERROR ("Active md %p on exit\n", md);
458                 list_del (&md->md_list);
459                 lib_md_free (nal, md);
460         }
461
462         while (!list_empty (&ni->ni_active_eqs)) {
463                 lib_eq_t *eq = list_entry (ni->ni_active_eqs.next,
464                                            lib_eq_t, eq_list);
465
466                 CERROR ("Active eq %p on exit\n", eq);
467                 list_del (&eq->eq_list);
468                 lib_eq_free (nal, eq);
469         }
470
471         while (!list_empty (&ni->ni_active_msgs)) {
472                 lib_msg_t *msg = list_entry (ni->ni_active_msgs.next,
473                                              lib_msg_t, msg_list);
474
475                 CERROR ("Active msg %p on exit\n", msg);
476                 list_del (&msg->msg_list);
477                 lib_msg_free (nal, msg);
478         }
479
480         nal->cb_free(nal, ni->tbl.tbl, sizeof(struct list_head) * ni->tbl.size);
481         ni->up = 0;
482
483         lib_cleanup_handle_hash (nal);
484         kportal_descriptor_cleanup (nal);
485
486  out:
487         return (PTL_OK);
488 }