Whamcloud - gitweb
smash the HEAD with the contents of b_cmd. HEAD_PRE_CMD_SMASH and
[fs/lustre-release.git] / lustre / portals / portals / 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 (nal_cb_t *nal)
45 {
46         return PTL_OK;
47 }
48
49 void
50 kportal_descriptor_cleanup (nal_cb_t *nal)
51 {
52 }
53 #else
54
55 int
56 lib_freelist_init (nal_cb_t *nal, lib_freelist_t *fl, int n, int size)
57 {
58         char *space;
59
60         LASSERT (n > 0);
61
62         size += offsetof (lib_freeobj_t, fo_contents);
63
64         space = nal->cb_malloc (nal, n * size);
65         if (space == NULL)
66                 return (PTL_NO_SPACE);
67
68         INIT_LIST_HEAD (&fl->fl_list);
69         fl->fl_objs = space;
70         fl->fl_nobjs = n;
71         fl->fl_objsize = size;
72
73         do
74         {
75                 memset (space, 0, size);
76                 list_add ((struct list_head *)space, &fl->fl_list);
77                 space += size;
78         } while (--n != 0);
79
80         return (PTL_OK);
81 }
82
83 void
84 lib_freelist_fini (nal_cb_t *nal, lib_freelist_t *fl)
85 {
86         struct list_head *el;
87         int               count;
88
89         if (fl->fl_nobjs == 0)
90                 return;
91
92         count = 0;
93         for (el = fl->fl_list.next; el != &fl->fl_list; el = el->next)
94                 count++;
95
96         LASSERT (count == fl->fl_nobjs);
97
98         nal->cb_free (nal, fl->fl_objs, fl->fl_nobjs * fl->fl_objsize);
99         memset (fl, 0, sizeof (fl));
100 }
101
102 int
103 kportal_descriptor_setup (nal_cb_t *nal)
104 {
105         /* NB on failure caller must still call kportal_descriptor_cleanup */
106         /*               ******                                            */
107         int rc;
108
109         memset (&nal->ni.ni_free_mes,  0, sizeof (nal->ni.ni_free_mes));
110         memset (&nal->ni.ni_free_msgs, 0, sizeof (nal->ni.ni_free_msgs));
111         memset (&nal->ni.ni_free_mds,  0, sizeof (nal->ni.ni_free_mds));
112         memset (&nal->ni.ni_free_eqs,  0, sizeof (nal->ni.ni_free_eqs));
113
114         rc = lib_freelist_init (nal, &nal->ni.ni_free_mes,
115                                 MAX_MES, sizeof (lib_me_t));
116         if (rc != PTL_OK)
117                 return (rc);
118
119         rc = lib_freelist_init (nal, &nal->ni.ni_free_msgs,
120                                 MAX_MSGS, sizeof (lib_msg_t));
121         if (rc != PTL_OK)
122                 return (rc);
123
124         rc = lib_freelist_init (nal, &nal->ni.ni_free_mds,
125                                 MAX_MDS, sizeof (lib_md_t));
126         if (rc != PTL_OK)
127                 return (rc);
128
129         rc = lib_freelist_init (nal, &nal->ni.ni_free_eqs,
130                                 MAX_EQS, sizeof (lib_eq_t));
131         return (rc);
132 }
133
134 void
135 kportal_descriptor_cleanup (nal_cb_t *nal)
136 {
137         lib_freelist_fini (nal, &nal->ni.ni_free_mes);
138         lib_freelist_fini (nal, &nal->ni.ni_free_msgs);
139         lib_freelist_fini (nal, &nal->ni.ni_free_mds);
140         lib_freelist_fini (nal, &nal->ni.ni_free_eqs);
141 }
142
143 #endif
144
145 __u64
146 lib_create_interface_cookie (nal_cb_t *nal)
147 {
148         /* NB the interface cookie in wire handles guards against delayed
149          * replies and ACKs appearing valid in a new instance of the same
150          * interface.  Initialisation time, even if it's only implemented
151          * to millisecond resolution is probably easily good enough. */
152         struct timeval tv;
153         __u64          cookie;
154 #ifndef __KERNEL__
155         int            rc = gettimeofday (&tv, NULL);
156         LASSERT (rc == 0);
157 #else
158         do_gettimeofday(&tv);
159 #endif
160         cookie = tv.tv_sec;
161         cookie *= 1000000;
162         cookie += tv.tv_usec;
163         return (cookie);
164 }
165
166 int
167 lib_setup_handle_hash (nal_cb_t *nal) 
168 {
169         lib_ni_t *ni = &nal->ni;
170         int       i;
171         
172         /* Arbitrary choice of hash table size */
173 #ifdef __KERNEL__
174         ni->ni_lh_hash_size = PAGE_SIZE / sizeof (struct list_head);
175 #else
176         ni->ni_lh_hash_size = (MAX_MES + MAX_MDS + MAX_EQS)/4;
177 #endif
178         ni->ni_lh_hash_table = 
179                 (struct list_head *)nal->cb_malloc (nal, ni->ni_lh_hash_size
180                                                     * sizeof (struct list_head));
181         if (ni->ni_lh_hash_table == NULL)
182                 return (PTL_NO_SPACE);
183         
184         for (i = 0; i < ni->ni_lh_hash_size; i++)
185                 INIT_LIST_HEAD (&ni->ni_lh_hash_table[i]);
186
187         ni->ni_next_object_cookie = PTL_COOKIE_TYPES;
188         
189         return (PTL_OK);
190 }
191
192 void
193 lib_cleanup_handle_hash (nal_cb_t *nal)
194 {
195         lib_ni_t *ni = &nal->ni;
196
197         if (ni->ni_lh_hash_table == NULL)
198                 return;
199         
200         nal->cb_free (nal, ni->ni_lh_hash_table,
201                       ni->ni_lh_hash_size * sizeof (struct list_head));
202 }
203
204 lib_handle_t *
205 lib_lookup_cookie (nal_cb_t *nal, __u64 cookie, int type) 
206 {
207         /* ALWAYS called with statelock held */
208         lib_ni_t            *ni = &nal->ni;
209         struct list_head    *list;
210         struct list_head    *el;
211         unsigned int         hash;
212
213         if ((cookie & (PTL_COOKIE_TYPES - 1)) != type)
214                 return (NULL);
215         
216         hash = ((unsigned int)cookie) % ni->ni_lh_hash_size;
217         list = &ni->ni_lh_hash_table[hash];
218         
219         list_for_each (el, list) {
220                 lib_handle_t *lh = list_entry (el, lib_handle_t, lh_hash_chain);
221                 
222                 if (lh->lh_cookie == cookie)
223                         return (lh);
224         }
225         
226         return (NULL);
227 }
228
229 void
230 lib_initialise_handle (nal_cb_t *nal, lib_handle_t *lh, int type) 
231 {
232         /* ALWAYS called with statelock held */
233         lib_ni_t       *ni = &nal->ni;
234         unsigned int    hash;
235
236         LASSERT (type >= 0 && type < PTL_COOKIE_TYPES);
237         lh->lh_cookie = ni->ni_next_object_cookie | type;
238         ni->ni_next_object_cookie += PTL_COOKIE_TYPES;
239         
240         hash = ((unsigned int)lh->lh_cookie) % ni->ni_lh_hash_size;
241         list_add (&lh->lh_hash_chain, &ni->ni_lh_hash_table[hash]);
242 }
243
244 void
245 lib_invalidate_handle (nal_cb_t *nal, lib_handle_t *lh)
246 {
247         list_del (&lh->lh_hash_chain);
248 }
249
250 int
251 lib_init(nal_cb_t * nal, ptl_nid_t nid, ptl_pid_t pid, int gsize,
252          ptl_pt_index_t ptl_size, ptl_ac_index_t acl_size)
253 {
254         int       rc = PTL_OK;
255         lib_ni_t *ni = &nal->ni;
256         int i;
257         ENTRY;
258
259         /* NB serialised in PtlNIInit() */
260
261         if (ni->refcnt != 0) {                       /* already initialised */
262                 ni->refcnt++;
263                 goto out;
264         }
265
266         lib_assert_wire_constants ();
267         
268         /*
269          * Allocate the portal table for this interface
270          * and all per-interface objects.
271          */
272         memset(&ni->counters, 0, sizeof(lib_counters_t));
273
274         rc = kportal_descriptor_setup (nal);
275         if (rc != PTL_OK)
276                 goto out;
277
278         INIT_LIST_HEAD (&ni->ni_active_msgs);
279         INIT_LIST_HEAD (&ni->ni_active_mds);
280         INIT_LIST_HEAD (&ni->ni_active_eqs);
281
282         INIT_LIST_HEAD (&ni->ni_test_peers);
283
284         ni->ni_interface_cookie = lib_create_interface_cookie (nal);
285         ni->ni_next_object_cookie = 0;
286         rc = lib_setup_handle_hash (nal);
287         if (rc != PTL_OK)
288                 goto out;
289         
290         ni->nid = nid;
291         ni->pid = pid;
292
293         ni->num_nodes = gsize;
294         ni->tbl.size = ptl_size;
295
296         ni->tbl.tbl = nal->cb_malloc(nal, sizeof(struct list_head) * ptl_size);
297         if (ni->tbl.tbl == NULL) {
298                 rc = PTL_NO_SPACE;
299                 goto out;
300         }
301
302         for (i = 0; i < ptl_size; i++)
303                 INIT_LIST_HEAD(&(ni->tbl.tbl[i]));
304
305         ni->debug = PTL_DEBUG_NONE;
306         ni->up = 1;
307         ni->refcnt++;
308
309  out:
310         if (rc != PTL_OK) {
311                 lib_cleanup_handle_hash (nal);
312                 kportal_descriptor_cleanup (nal);
313         }
314
315         RETURN (rc);
316 }
317
318 int
319 lib_fini(nal_cb_t * nal)
320 {
321         lib_ni_t *ni = &nal->ni;
322         int       idx;
323
324         ni->refcnt--;
325
326         if (ni->refcnt != 0)
327                 goto out;
328
329         /* NB no stat_lock() since this is the last reference.  The NAL
330          * should have shut down already, so it should be safe to unlink
331          * and free all descriptors, even those that appear committed to a
332          * network op (eg MD with non-zero pending count)
333          */
334
335         for (idx = 0; idx < ni->tbl.size; idx++)
336                 while (!list_empty (&ni->tbl.tbl[idx])) {
337                         lib_me_t *me = list_entry (ni->tbl.tbl[idx].next,
338                                                    lib_me_t, me_list);
339
340                         CERROR ("Active me %p on exit\n", me);
341                         list_del (&me->me_list);
342                         lib_me_free (nal, me);
343                 }
344
345         while (!list_empty (&ni->ni_active_mds)) {
346                 lib_md_t *md = list_entry (ni->ni_active_mds.next,
347                                            lib_md_t, md_list);
348
349                 CERROR ("Active md %p on exit\n", md);
350                 list_del (&md->md_list);
351                 lib_md_free (nal, md);
352         }
353
354         while (!list_empty (&ni->ni_active_eqs)) {
355                 lib_eq_t *eq = list_entry (ni->ni_active_eqs.next,
356                                            lib_eq_t, eq_list);
357
358                 CERROR ("Active eq %p on exit\n", eq);
359                 list_del (&eq->eq_list);
360                 lib_eq_free (nal, eq);
361         }
362
363         while (!list_empty (&ni->ni_active_msgs)) {
364                 lib_msg_t *msg = list_entry (ni->ni_active_msgs.next,
365                                              lib_msg_t, msg_list);
366
367                 CERROR ("Active msg %p on exit\n", msg);
368                 list_del (&msg->msg_list);
369                 lib_msg_free (nal, msg);
370         }
371
372         nal->cb_free(nal, ni->tbl.tbl, sizeof(struct list_head) * ni->tbl.size);
373         ni->up = 0;
374
375         lib_cleanup_handle_hash (nal);
376         kportal_descriptor_cleanup (nal);
377
378  out:
379         return (PTL_OK);
380 }