Whamcloud - gitweb
- merge 0.7rc1 from b_devel to HEAD (20030612 merge point)
[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         if (--ptl_slab_users != 0)
131                 return;
132
133         LASSERT (atomic_read (&md_in_use_count) == 0);
134         LASSERT (atomic_read (&me_in_use_count) == 0);
135         LASSERT (atomic_read (&eq_in_use_count) == 0);
136         LASSERT (atomic_read (&msg_in_use_count) == 0);
137
138         if (ptl_md_slab != NULL)
139                 kmem_cache_destroy(ptl_md_slab);
140         if (ptl_msg_slab != NULL)
141                 kmem_cache_destroy(ptl_msg_slab);
142         if (ptl_me_slab != NULL)
143                 kmem_cache_destroy(ptl_me_slab);
144         if (ptl_eq_slab != NULL)
145                 kmem_cache_destroy(ptl_eq_slab);
146 }
147 #else
148
149 int
150 lib_freelist_init (nal_cb_t *nal, lib_freelist_t *fl, int n, int size)
151 {
152         char *space;
153
154         LASSERT (n > 0);
155
156         size += offsetof (lib_freeobj_t, fo_contents);
157
158         space = nal->cb_malloc (nal, n * size);
159         if (space == NULL)
160                 return (PTL_NOSPACE);
161
162         INIT_LIST_HEAD (&fl->fl_list);
163         fl->fl_objs = space;
164         fl->fl_nobjs = n;
165         fl->fl_objsize = size;
166
167         do
168         {
169                 memset (space, 0, size);
170                 list_add ((struct list_head *)space, &fl->fl_list);
171                 space += size;
172         } while (--n != 0);
173
174         return (PTL_OK);
175 }
176
177 void
178 lib_freelist_fini (nal_cb_t *nal, lib_freelist_t *fl)
179 {
180         struct list_head *el;
181         int               count;
182
183         if (fl->fl_nobjs == 0)
184                 return;
185
186         count = 0;
187         for (el = fl->fl_list.next; el != &fl->fl_list; el = el->next)
188                 count++;
189
190         LASSERT (count == fl->fl_nobjs);
191
192         nal->cb_free (nal, fl->fl_objs, fl->fl_nobjs * fl->fl_objsize);
193         memset (fl, 0, sizeof (fl));
194 }
195
196 int
197 kportal_descriptor_setup (nal_cb_t *nal)
198 {
199         /* NB on failure caller must still call kportal_descriptor_cleanup */
200         /*               ******                                            */
201         int rc;
202
203         memset (&nal->ni.ni_free_mes,  0, sizeof (nal->ni.ni_free_mes));
204         memset (&nal->ni.ni_free_msgs, 0, sizeof (nal->ni.ni_free_msgs));
205         memset (&nal->ni.ni_free_mds,  0, sizeof (nal->ni.ni_free_mds));
206         memset (&nal->ni.ni_free_eqs,  0, sizeof (nal->ni.ni_free_eqs));
207
208         rc = lib_freelist_init (nal, &nal->ni.ni_free_mes,
209                                 MAX_MES, sizeof (lib_me_t));
210         if (rc != PTL_OK)
211                 return (rc);
212
213         rc = lib_freelist_init (nal, &nal->ni.ni_free_msgs,
214                                 MAX_MSGS, sizeof (lib_msg_t));
215         if (rc != PTL_OK)
216                 return (rc);
217
218         rc = lib_freelist_init (nal, &nal->ni.ni_free_mds,
219                                 MAX_MDS, sizeof (lib_md_t));
220         if (rc != PTL_OK)
221                 return (rc);
222
223         rc = lib_freelist_init (nal, &nal->ni.ni_free_eqs,
224                                 MAX_EQS, sizeof (lib_eq_t));
225         return (rc);
226 }
227
228 void
229 kportal_descriptor_cleanup (nal_cb_t *nal)
230 {
231         lib_freelist_fini (nal, &nal->ni.ni_free_mes);
232         lib_freelist_fini (nal, &nal->ni.ni_free_msgs);
233         lib_freelist_fini (nal, &nal->ni.ni_free_mds);
234         lib_freelist_fini (nal, &nal->ni.ni_free_eqs);
235 }
236
237 #endif
238
239 __u64
240 lib_create_interface_cookie (nal_cb_t *nal)
241 {
242         /* NB the interface cookie in wire handles guards against delayed
243          * replies and ACKs appearing valid in a new instance of the same
244          * interface.  Initialisation time, even if it's only implemented
245          * to millisecond resolution is probably easily good enough. */
246         struct timeval tv;
247         __u64          cookie;
248 #ifndef __KERNEL__
249         int            rc = gettimeofday (&tv, NULL);
250         LASSERT (rc == 0);
251 #else
252         do_gettimeofday(&tv);
253 #endif
254         cookie = tv.tv_sec;
255         cookie *= 1000000;
256         cookie += tv.tv_usec;
257         return (cookie);
258 }
259
260 int
261 lib_setup_handle_hash (nal_cb_t *nal) 
262 {
263         lib_ni_t *ni = &nal->ni;
264         int       i;
265         
266         /* Arbitrary choice of hash table size */
267 #ifdef __KERNEL__
268         ni->ni_lh_hash_size = PAGE_SIZE / sizeof (struct list_head);
269 #else
270         ni->ni_lh_hash_size = (MAX_MES + MAX_MDS + MAX_EQS)/4;
271 #endif
272         ni->ni_lh_hash_table = 
273                 (struct list_head *)nal->cb_malloc (nal, ni->ni_lh_hash_size
274                                                     * sizeof (struct list_head));
275         if (ni->ni_lh_hash_table == NULL)
276                 return (PTL_NOSPACE);
277         
278         for (i = 0; i < ni->ni_lh_hash_size; i++)
279                 INIT_LIST_HEAD (&ni->ni_lh_hash_table[i]);
280
281         ni->ni_next_object_cookie = PTL_COOKIE_TYPES;
282         
283         return (PTL_OK);
284 }
285
286 void
287 lib_cleanup_handle_hash (nal_cb_t *nal)
288 {
289         lib_ni_t *ni = &nal->ni;
290
291         if (ni->ni_lh_hash_table == NULL)
292                 return;
293         
294         nal->cb_free (nal, ni->ni_lh_hash_table,
295                       ni->ni_lh_hash_size * sizeof (struct list_head));
296 }
297
298 lib_handle_t *
299 lib_lookup_cookie (nal_cb_t *nal, __u64 cookie, int type) 
300 {
301         /* ALWAYS called with statelock held */
302         lib_ni_t            *ni = &nal->ni;
303         struct list_head    *list;
304         struct list_head    *el;
305         unsigned int         hash;
306
307         if ((cookie & (PTL_COOKIE_TYPES - 1)) != type)
308                 return (NULL);
309         
310         hash = ((unsigned int)cookie) % ni->ni_lh_hash_size;
311         list = &ni->ni_lh_hash_table[hash];
312         
313         list_for_each (el, list) {
314                 lib_handle_t *lh = list_entry (el, lib_handle_t, lh_hash_chain);
315                 
316                 if (lh->lh_cookie == cookie)
317                         return (lh);
318         }
319         
320         return (NULL);
321 }
322
323 void
324 lib_initialise_handle (nal_cb_t *nal, lib_handle_t *lh, int type) 
325 {
326         /* ALWAYS called with statelock held */
327         lib_ni_t       *ni = &nal->ni;
328         unsigned int    hash;
329
330         LASSERT (type >= 0 && type < PTL_COOKIE_TYPES);
331         lh->lh_cookie = ni->ni_next_object_cookie | type;
332         ni->ni_next_object_cookie += PTL_COOKIE_TYPES;
333         
334         hash = ((unsigned int)lh->lh_cookie) % ni->ni_lh_hash_size;
335         list_add (&lh->lh_hash_chain, &ni->ni_lh_hash_table[hash]);
336 }
337
338 void
339 lib_invalidate_handle (nal_cb_t *nal, lib_handle_t *lh)
340 {
341         list_del (&lh->lh_hash_chain);
342 }
343
344 int
345 lib_init(nal_cb_t * nal, ptl_nid_t nid, ptl_pid_t pid, int gsize,
346          ptl_pt_index_t ptl_size, ptl_ac_index_t acl_size)
347 {
348         int       rc = PTL_OK;
349         lib_ni_t *ni = &nal->ni;
350         int i;
351         ENTRY;
352
353         /* NB serialised in PtlNIInit() */
354
355         if (ni->refcnt != 0) {                       /* already initialised */
356                 ni->refcnt++;
357                 goto out;
358         }
359
360         lib_assert_wire_constants ();
361         
362         /*
363          * Allocate the portal table for this interface
364          * and all per-interface objects.
365          */
366         memset(&ni->counters, 0, sizeof(lib_counters_t));
367
368         rc = kportal_descriptor_setup (nal);
369         if (rc != PTL_OK)
370                 goto out;
371
372         INIT_LIST_HEAD (&ni->ni_active_msgs);
373         INIT_LIST_HEAD (&ni->ni_active_mds);
374         INIT_LIST_HEAD (&ni->ni_active_eqs);
375
376         INIT_LIST_HEAD (&ni->ni_test_peers);
377
378         ni->ni_interface_cookie = lib_create_interface_cookie (nal);
379         ni->ni_next_object_cookie = 0;
380         rc = lib_setup_handle_hash (nal);
381         if (rc != PTL_OK)
382                 goto out;
383         
384         ni->nid = nid;
385         ni->pid = pid;
386
387         ni->num_nodes = gsize;
388         ni->tbl.size = ptl_size;
389
390         ni->tbl.tbl = nal->cb_malloc(nal, sizeof(struct list_head) * ptl_size);
391         if (ni->tbl.tbl == NULL) {
392                 rc = PTL_NOSPACE;
393                 goto out;
394         }
395
396         for (i = 0; i < ptl_size; i++)
397                 INIT_LIST_HEAD(&(ni->tbl.tbl[i]));
398
399         ni->debug = PTL_DEBUG_NONE;
400         ni->up = 1;
401         ni->refcnt++;
402
403  out:
404         if (rc != PTL_OK) {
405                 lib_cleanup_handle_hash (nal);
406                 kportal_descriptor_cleanup (nal);
407         }
408
409         RETURN (rc);
410 }
411
412 int
413 lib_fini(nal_cb_t * nal)
414 {
415         lib_ni_t *ni = &nal->ni;
416         int       idx;
417
418         ni->refcnt--;
419
420         if (ni->refcnt != 0)
421                 goto out;
422
423         /* NB no stat_lock() since this is the last reference.  The NAL
424          * should have shut down already, so it should be safe to unlink
425          * and free all descriptors, even those that appear committed to a
426          * network op (eg MD with non-zero pending count)
427          */
428
429         for (idx = 0; idx < ni->tbl.size; idx++)
430                 while (!list_empty (&ni->tbl.tbl[idx])) {
431                         lib_me_t *me = list_entry (ni->tbl.tbl[idx].next,
432                                                    lib_me_t, me_list);
433
434                         CERROR ("Active me %p on exit\n", me);
435                         list_del (&me->me_list);
436                         lib_me_free (nal, me);
437                 }
438
439         while (!list_empty (&ni->ni_active_mds)) {
440                 lib_md_t *md = list_entry (ni->ni_active_mds.next,
441                                            lib_md_t, md_list);
442
443                 CERROR ("Active md %p on exit\n", md);
444                 list_del (&md->md_list);
445                 lib_md_free (nal, md);
446         }
447
448         while (!list_empty (&ni->ni_active_eqs)) {
449                 lib_eq_t *eq = list_entry (ni->ni_active_eqs.next,
450                                            lib_eq_t, eq_list);
451
452                 CERROR ("Active eq %p on exit\n", eq);
453                 list_del (&eq->eq_list);
454                 lib_eq_free (nal, eq);
455         }
456
457         while (!list_empty (&ni->ni_active_msgs)) {
458                 lib_msg_t *msg = list_entry (ni->ni_active_msgs.next,
459                                              lib_msg_t, msg_list);
460
461                 CERROR ("Active msg %p on exit\n", msg);
462                 list_del (&msg->msg_list);
463                 lib_msg_free (nal, msg);
464         }
465
466         nal->cb_free(nal, ni->tbl.tbl, sizeof(struct list_head) * ni->tbl.size);
467         ni->up = 0;
468
469         lib_cleanup_handle_hash (nal);
470         kportal_descriptor_cleanup (nal);
471
472  out:
473         return (PTL_OK);
474 }