root/trunk/src/io/bmi/bmi.c @ 8211

Revision 8211, 60.6 KB (checked in by slang, 3 years ago)

Patch that gives expected/unexpected its own method_plan. Fixes test_unexepected/test_context race. From Dries Kimpe.

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7/** \file
8 *  \ingroup bmiint
9 *
10 *  Top-level BMI network interface routines.
11 */
12
13#include <errno.h>
14#include <string.h>
15#include <assert.h>
16#include <time.h>
17#include <sys/time.h>
18#include <stdio.h>
19
20#include "bmi.h"
21#include "bmi-method-support.h"
22#include "bmi-method-callback.h"
23#include "gossip.h"
24#include "reference-list.h"
25#include "op-list.h"
26#include "gen-locks.h"
27#include "str-utils.h"
28#include "id-generator.h"
29#include "pvfs2-internal.h"
30#include "pvfs2-debug.h"
31
32static int bmi_initialized_count = 0;
33static gen_mutex_t bmi_initialize_mutex = GEN_MUTEX_INITIALIZER;
34
35/*
36 * List of BMI addrs currently managed.
37 */
38static ref_list_p cur_ref_list = NULL;
39
40/* array to keep up with active contexts */
41static int context_array[BMI_MAX_CONTEXTS] = { 0 };
42static gen_mutex_t context_mutex = GEN_MUTEX_INITIALIZER;
43static gen_mutex_t ref_mutex = GEN_MUTEX_INITIALIZER;
44
45static QLIST_HEAD(forget_list);
46static gen_mutex_t forget_list_mutex = GEN_MUTEX_INITIALIZER;
47
48struct forget_item
49{
50    struct qlist_head link;
51    BMI_addr_t addr;
52};
53
54/*
55 * BMI trigger to reap all method resources for inactive addresses.
56 */
57static QLIST_HEAD(bmi_addr_force_drop_list);
58static gen_mutex_t bmi_addr_force_drop_list_mutex = GEN_MUTEX_INITIALIZER;
59struct drop_item
60{
61    struct qlist_head link;
62    char  *method_name;
63};
64
65/*
66 * Static list of defined BMI methods.  These are pre-compiled into
67 * the client libraries and into the server.
68 */
69#ifdef __STATIC_METHOD_BMI_TCP__
70extern struct bmi_method_ops bmi_tcp_ops;
71#endif
72#ifdef __STATIC_METHOD_BMI_GM__
73extern struct bmi_method_ops bmi_gm_ops;
74#endif
75#ifdef __STATIC_METHOD_BMI_MX__
76extern struct bmi_method_ops bmi_mx_ops;
77#endif
78#ifdef __STATIC_METHOD_BMI_IB__
79extern struct bmi_method_ops bmi_ib_ops;
80#endif
81#ifdef __STATIC_METHOD_BMI_PORTALS__
82extern struct bmi_method_ops bmi_portals_ops;
83#endif
84#ifdef __STATIC_METHOD_BMI_ZOID__
85extern struct bmi_method_ops bmi_zoid_ops;
86#endif
87
88static struct bmi_method_ops *const static_methods[] = {
89#ifdef __STATIC_METHOD_BMI_TCP__
90    &bmi_tcp_ops,
91#endif
92#ifdef __STATIC_METHOD_BMI_GM__
93    &bmi_gm_ops,
94#endif
95#ifdef __STATIC_METHOD_BMI_MX__
96    &bmi_mx_ops,
97#endif
98#ifdef __STATIC_METHOD_BMI_IB__
99    &bmi_ib_ops,
100#endif
101#ifdef __STATIC_METHOD_BMI_PORTALS__
102    &bmi_portals_ops,
103#endif
104#ifdef __STATIC_METHOD_BMI_ZOID__
105    &bmi_zoid_ops,
106#endif
107    NULL
108};
109
110/*
111 * List of "known" BMI methods.  This is dynamic, starting with
112 * just the static ones above, and perhaps adding more if we turn
113 * back on dynamic module loading.
114 */
115static int known_method_count = 0;
116static struct bmi_method_ops **known_method_table = 0;
117
118/*
119 * List of active BMI methods.  These are the ones that will be
120 * dealt with for a test call, for example.  On a client, known methods
121 * become active only when someone calls BMI_addr_lookup().  On
122 * a server, all possibly active methods are known at startup time
123 * because we listen on them for the duration.
124 */
125static int active_method_count = 0;
126static gen_mutex_t active_method_count_mutex = GEN_MUTEX_INITIALIZER;
127
128static struct bmi_method_ops **active_method_table = NULL;
129
130struct method_usage_t {
131    int iters_polled;  /* how many iterations since this method was polled */
132    int iters_active;  /* how many iterations since this method had action */
133    int plan;
134    int flags;
135};
136
137static struct method_usage_t * expected_method_usage = NULL;
138static struct method_usage_t * unexpected_method_usage = NULL;
139
140static const int usage_iters_starvation = 100000;
141static const int usage_iters_active = 10000;
142static int global_flags;
143
144static int activate_method(const char *name, const char *listen_addr,
145    int flags);
146static void bmi_addr_drop(ref_st_p tmp_ref);
147static void bmi_addr_force_drop(ref_st_p ref, ref_list_p ref_list);
148static void bmi_check_forget_list(void);
149static void bmi_check_addr_force_drop (void);
150
151/** Initializes the BMI layer.  Must be called before any other BMI
152 *  functions.
153 *
154 *  \param method_list a comma separated list of BMI methods to
155 *         use
156 *  \param listen_addr a comma separated list of addresses to listen on
157 *         for each method (if needed)
158 *  \param flags initialization flags
159 *
160 *  \return 0 on success, -errno on failure
161 */
162int BMI_initialize(const char *method_list,
163                   const char *listen_addr,
164                   int flags)
165{
166    int ret = -1;
167    int i = 0, j = 0;
168    char **requested_methods = NULL;
169    char **listen_addrs = NULL;
170    char *this_addr = NULL;
171    char *proto = NULL;
172    int addr_count = 0;
173
174    gen_mutex_lock(&bmi_initialize_mutex);
175    if(bmi_initialized_count > 0)
176    {
177        /* Already initialized! Just increment ref count and return. */
178        ++bmi_initialized_count;
179        gen_mutex_unlock(&bmi_initialize_mutex);
180        return 0;
181    }
182    ++bmi_initialized_count;
183    gen_mutex_unlock(&bmi_initialize_mutex);
184
185    global_flags = flags;
186
187    /* server must specify method list at startup, optional for client */
188    if (flags & BMI_INIT_SERVER) {
189        if (!listen_addr || !method_list)
190            return bmi_errno_to_pvfs(-EINVAL);
191    } else {
192        if (listen_addr)
193            return bmi_errno_to_pvfs(-EINVAL);
194        if (flags) {
195            gossip_lerr("Warning: flags ignored on client.\n");
196        }
197    }
198
199    /* make sure that id generator is initialized if not already */
200    ret = id_gen_safe_initialize();
201    if(ret < 0)
202    {
203        return(ret);
204    }
205
206    /* make a new reference list */
207    cur_ref_list = ref_list_new();
208    if (!cur_ref_list)
209    {
210        ret = bmi_errno_to_pvfs(-ENOMEM);
211        goto bmi_initialize_failure;
212    }
213
214    /* initialize the known method list from the null-terminated static list */
215    known_method_count = sizeof(static_methods) / sizeof(static_methods[0]) - 1;
216    known_method_table = malloc(
217        known_method_count * sizeof(*known_method_table));
218    if (!known_method_table)
219        return bmi_errno_to_pvfs(-ENOMEM);
220    memcpy(known_method_table, static_methods,
221        known_method_count * sizeof(*known_method_table));
222
223    gen_mutex_lock(&active_method_count_mutex);
224    if (!method_list) {
225        /* nothing active until lookup */
226        active_method_count = 0;
227    } else {
228        /* split and initialize the requested method list */
229        int numreq = PINT_split_string_list(&requested_methods, method_list);
230        if (numreq < 1)
231        {
232            gossip_lerr("Error: bad method list.\n");
233            ret = bmi_errno_to_pvfs(-EINVAL);
234            gen_mutex_unlock(&active_method_count_mutex);
235            goto bmi_initialize_failure;
236        }
237
238        /* Today is that day! */
239        addr_count = PINT_split_string_list(&listen_addrs, listen_addr);
240       
241        for (i=0; i<numreq; i++) {
242
243            /* assume the method name is bmi_<proto>, and find the <proto>
244             * part
245             */
246            proto = strstr(requested_methods[i], "bmi_");
247            if(!proto)
248            {
249                gossip_err("%s: Invalid method name: %s.  Method names "
250                           "must start with 'bmi_'\n",
251                           __func__, requested_methods[i]);
252                ret = -EINVAL;
253                gen_mutex_unlock(&active_method_count_mutex);
254                goto bmi_initialize_failure;
255            }
256            proto += 4;
257
258            /* match the proper listen addr to the method */
259            for(j=0; j<addr_count; ++j)
260            {
261                /* we don't want a strstr here in case the addr has
262                 * the proto as part of the hostname
263                 */
264                if(!strncmp(listen_addrs[j], proto, strlen(proto)))
265                {
266                    /* found the right addr */
267                    this_addr = listen_addrs[j];
268                    break;
269                }
270            }
271               
272            if(!this_addr)
273            {
274                /* couldn't find the right listen addr */
275                gossip_err("%s: Failed to find an appropriate listening "
276                           "address for the bmi method: %s\n",
277                           __func__, requested_methods[i]);
278                ret = -EINVAL;
279                gen_mutex_unlock(&active_method_count_mutex);
280                goto bmi_initialize_failure;
281            }
282
283            ret = activate_method(requested_methods[i], this_addr, flags);
284            if (ret < 0) {
285                ret = bmi_errno_to_pvfs(ret);
286                gen_mutex_unlock(&active_method_count_mutex);
287                goto bmi_initialize_failure;
288            }
289            free(requested_methods[i]);
290        }
291        free(requested_methods);
292        if(listen_addrs)
293        {
294            PINT_free_string_list(listen_addrs, addr_count);
295            listen_addrs = NULL;
296        }
297    }
298    gen_mutex_unlock(&active_method_count_mutex);
299
300    return (0);
301
302  bmi_initialize_failure:
303
304    /* kill reference list */
305    if (cur_ref_list)
306    {
307        ref_list_cleanup(cur_ref_list);
308    }
309
310    gen_mutex_lock(&active_method_count_mutex);
311    /* look for loaded methods and shut down */
312    if (active_method_table)
313    {
314        for (i = 0; i < active_method_count; i++)
315        {
316            if (active_method_table[i])
317            {
318                active_method_table[i]->finalize();
319            }
320        }
321        free(active_method_table);
322    }
323
324    if (known_method_table) {
325        free(known_method_table);
326        known_method_count = 0;
327    }
328
329    /* get rid of method string list */
330    if (requested_methods)
331    {
332        for (i = 0; i < active_method_count; i++)
333        {
334            if (requested_methods[i])
335            {
336                free(requested_methods[i]);
337            }
338        }
339        free(requested_methods);
340    }
341
342    if(listen_addrs)
343    {
344        PINT_free_string_list(listen_addrs, addr_count);
345    }
346
347    active_method_count = 0;
348    gen_mutex_unlock(&active_method_count_mutex);
349
350    /* shut down id generator */
351    id_gen_safe_finalize();
352
353    return (ret);
354}
355
356/* the following is the old BMI_initialize() function that used dl to
357 * pull in method modules dynamically.  Just hanging around as an
358 * example...
359 */
360#if 0
361/* BMI_initialize()
362 *
363 * Initializes the BMI layer.  Must be called before any other BMI
364 * functions.  module_string is a comma separated list of BMI modules to
365 * use, listen_addr is a comma separated list of addresses to listen on
366 * for each module (if needed), and flags are initialization flags.
367 *
368 * returns 0 on success, -errno on failure
369 */
370int BMI_initialize(const char *module_string,
371                   const char *listen_addr,
372                   int flags)
373{
374
375    int ret = -1;
376    int i = 0;
377    char **modules = NULL;
378    void *meth_mod = NULL;
379    char *mod_error = NULL;
380    method_addr_p new_addr = NULL;
381    op_list_p olp = NULL;
382
383    /* TODO: this is a hack to make sure we get all of the symbols loaded
384     * into the library... is there a better way?
385     */
386    olp = op_list_new();
387    op_list_cleanup(olp);
388
389    if (((flags & BMI_INIT_SERVER) && (!listen_addr)) || !module_string)
390    {
391        return (bmi_errno_to_pvfs(-EINVAL));
392    }
393
394    /* separate out the module list */
395    active_method_count = PINT_split_string_list(
396        &modules, module_string);
397    if (active_method_count < 1)
398    {
399        gossip_lerr("Error: bad module list.\n");
400        ret = bmi_errno_to_pvfs(-EINVAL);
401        goto bmi_initialize_failure;
402    }
403
404    /* create a table to keep up with the method modules */
405    active_method_table = (struct bmi_method_ops **)malloc(
406        active_method_count * sizeof(struct bmi_method_ops *));
407    if (!active_method_table)
408    {
409        ret = bmi_errno_to_pvfs(-ENOMEM);
410        goto bmi_initialize_failure;
411    }
412
413    /* iterate through each method in the list and load its module */
414    for (i = 0; i < active_method_count; i++)
415    {
416        meth_mod = dlopen(modules[i], RTLD_NOW);
417        if (!meth_mod)
418        {
419            gossip_lerr("Error: could not open module: %s\n", dlerror());
420            ret = bmi_errno_to_pvfs(-EINVAL);
421            goto bmi_initialize_failure;
422        }
423        dlerror();
424
425        active_method_table[i] = (struct bmi_method_ops *)
426            dlsym(meth_mod, "method_interface");
427        mod_error = dlerror();
428        if (mod_error)
429        {
430            gossip_lerr("Error: module load: %s\n", mod_error);
431            ret = bmi_errno_to_pvfs(-EINVAL);
432            goto bmi_initialize_failure;
433        }
434    }
435
436    /* make a new reference list */
437    cur_ref_list = ref_list_new();
438    if (!cur_ref_list)
439    {
440        ret = bmi_errno_to_pvfs(-ENOMEM);
441        goto bmi_initialize_failure;
442    }
443
444    /* initialize methods */
445    for (i = 0; i < active_method_count; i++)
446    {
447        if (flags & BMI_INIT_SERVER)
448        {
449            if ((new_addr =
450                 active_method_table[i]->
451                 BMI_meth_method_addr_lookup(listen_addr)) != NULL)
452            {
453                /* this is a bit of a hack */
454                new_addr->method_type = i;
455                ret = active_method_table[i]->BMI_meth_initialize(
456                    new_addr, i, flags);
457            }
458            else
459            {
460                ret = -1;
461            }
462        }
463        else
464        {
465            ret = active_method_table[i]->BMI_meth_initialize(
466                NULL, i, flags);
467        }
468        if (ret < 0)
469        {
470            gossip_lerr("Error: initializing module: %s\n", modules[i]);
471            goto bmi_initialize_failure;
472        }
473    }
474
475    return (0);
476
477  bmi_initialize_failure:
478
479    /* kill reference list */
480    if (cur_ref_list)
481    {
482        ref_list_cleanup(cur_ref_list);
483    }
484
485    /* look for loaded methods and shut down */
486    if (active_method_table)
487    {
488        for (i = 0; i < active_method_count; i++)
489        {
490            if (active_method_table[i])
491            {
492                active_method_table[i]->BMI_meth_finalize();
493            }
494        }
495        free(active_method_table);
496    }
497
498    /* get rid of method string list */
499    if (modules)
500    {
501        for (i = 0; i < active_method_count; i++)
502        {
503            if (modules[i])
504            {
505                free(modules[i]);
506            }
507        }
508        free(modules);
509    }
510
511    return (ret);
512}
513#endif /* 0 */
514
515/** Shuts down the BMI layer.
516 *
517 * \return 0.
518 */
519int BMI_finalize(void)
520{
521    int i = -1;
522
523    gen_mutex_lock(&bmi_initialize_mutex);
524    --bmi_initialized_count;
525    if(bmi_initialized_count > 0)
526    {
527        gen_mutex_unlock(&bmi_initialize_mutex);
528        return 0;
529    }
530    gen_mutex_unlock(&bmi_initialize_mutex);
531
532    gen_mutex_lock(&active_method_count_mutex);
533    /* attempt to shut down active methods */
534    for (i = 0; i < active_method_count; i++)
535    {
536        active_method_table[i]->finalize();
537    }
538    active_method_count = 0;
539    free(active_method_table);
540    gen_mutex_unlock(&active_method_count_mutex);
541
542    free(known_method_table);
543    known_method_count = 0;
544
545    if (expected_method_usage)
546        free(expected_method_usage);
547
548    if (unexpected_method_usage)
549       free(unexpected_method_usage);
550
551    /* destroy the reference list */
552    /* (side effect: destroys all method addresses as well) */
553    ref_list_cleanup(cur_ref_list);
554
555    /* shut down id generator */
556    id_gen_safe_finalize();
557
558    return (0);
559}
560
561/** Creates a new context to be used for communication.  This can be
562 *  used, for example, to distinguish between operations posted by
563 *  different threads.
564 *
565 *  \return 0 on success, -errno on failure.
566 */
567int BMI_open_context(bmi_context_id* context_id)
568{
569    int context_index;
570    int i;
571    int ret = 0;
572
573    gen_mutex_lock(&context_mutex);
574
575    /* find an unused context id */
576    for(context_index=0; context_index<BMI_MAX_CONTEXTS; context_index++)
577    {
578        if(context_array[context_index] == 0)
579        {
580            break;
581        }
582    }
583
584    if(context_index >= BMI_MAX_CONTEXTS)
585    {
586        /* we don't have any more available! */
587        gen_mutex_unlock(&context_mutex);
588        return(bmi_errno_to_pvfs(-EBUSY));
589    }
590
591    gen_mutex_lock(&active_method_count_mutex);
592    /* tell all of the modules about the new context */
593    for (i = 0; i < active_method_count; i++)
594    {
595        ret = active_method_table[i]->open_context(
596            context_index);
597        if(ret < 0)
598        {
599            /*
600              one of them failed; kill this context in the previous
601              modules
602            */
603            --i;
604            while (i >= 0)
605            {
606                active_method_table[i]->close_context(
607                    context_index);
608                --i;
609            }
610            goto out;
611        }
612    }
613    gen_mutex_unlock(&active_method_count_mutex);
614
615    context_array[context_index] = 1;
616    *context_id = context_index;
617
618out:
619
620    gen_mutex_unlock(&context_mutex);
621    return(ret);
622}
623
624
625/** Destroys a context previous generated with BMI_open_context().
626 */
627void BMI_close_context(bmi_context_id context_id)
628{
629    int i;
630
631    gen_mutex_lock(&context_mutex);
632
633    if(!context_array[context_id])
634    {
635        gen_mutex_unlock(&context_mutex);
636        return;
637    }
638
639    /* tell all of the modules to get rid of this context */
640    gen_mutex_lock(&active_method_count_mutex);
641    for (i = 0; i < active_method_count; i++)
642    {
643        active_method_table[i]->close_context(context_id);
644    }
645    context_array[context_id] = 0;
646    gen_mutex_unlock(&active_method_count_mutex);
647
648    gen_mutex_unlock(&context_mutex);
649    return;
650}
651
652
653/** Submits receive operations for subsequent service.
654 *
655 *  \return 0 on success, -errno on failure.
656 */
657int BMI_post_recv(bmi_op_id_t * id,
658                  BMI_addr_t src,
659                  void *buffer,
660                  bmi_size_t expected_size,
661                  bmi_size_t * actual_size,
662                  enum bmi_buffer_type buffer_type,
663                  bmi_msg_tag_t tag,
664                  void *user_ptr,
665                  bmi_context_id context_id,
666                  bmi_hint hints)
667{
668    ref_st_p tmp_ref = NULL;
669    int ret = -1;
670
671    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
672                 "BMI_post_recv: addr: %ld, offset: 0x%lx, size: %ld, tag: %d\n",
673                 (long)src, (long)buffer, (long)expected_size, (int)tag);
674
675    *id = 0;
676
677    gen_mutex_lock(&ref_mutex);
678    tmp_ref = ref_list_search_addr(cur_ref_list, src);
679    if (!tmp_ref)
680    {
681        gen_mutex_unlock(&ref_mutex);
682        return (bmi_errno_to_pvfs(-EPROTO));
683    }
684    gen_mutex_unlock(&ref_mutex);
685
686    ret = tmp_ref->interface->post_recv(
687        id, tmp_ref->method_addr, buffer, expected_size, actual_size,
688        buffer_type, tag, user_ptr, context_id, (PVFS_hint)hints);
689    return (ret);
690}
691
692
693/** Submits send operations for subsequent service.
694 *
695 *  \return 0 on success, -errno on failure.
696 */
697int BMI_post_send(bmi_op_id_t * id,
698                  BMI_addr_t dest,
699                  const void *buffer,
700                  bmi_size_t size,
701                  enum bmi_buffer_type buffer_type,
702                  bmi_msg_tag_t tag,
703                  void *user_ptr,
704                  bmi_context_id context_id,
705                  bmi_hint hints)
706{
707    ref_st_p tmp_ref = NULL;
708    int ret = -1;
709
710    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
711                 "BMI_post_send: addr: %ld, offset: 0x%lx, size: %ld, tag: %d\n",
712                 (long)dest, (long)buffer, (long)size, (int)tag);
713
714    *id = 0;
715
716    gen_mutex_lock(&ref_mutex);
717    tmp_ref = ref_list_search_addr(cur_ref_list, dest);
718    if (!tmp_ref)
719    {
720        gen_mutex_unlock(&ref_mutex);
721        return (bmi_errno_to_pvfs(-EPROTO));
722    }
723    gen_mutex_unlock(&ref_mutex);
724
725    ret = tmp_ref->interface->post_send(
726        id, tmp_ref->method_addr, buffer, size, buffer_type, tag,
727        user_ptr, context_id, (PVFS_hint)hints);
728    return (ret);
729}
730
731
732/** Submits unexpected send operations for subsequent service.
733 *
734 *  \return 0 on success, -errno on failure.
735 */
736int BMI_post_sendunexpected(bmi_op_id_t * id,
737                            BMI_addr_t dest,
738                            const void *buffer,
739                            bmi_size_t size,
740                            enum bmi_buffer_type buffer_type,
741                            bmi_msg_tag_t tag,
742                            void *user_ptr,
743                            bmi_context_id context_id,
744                            bmi_hint hints)
745{
746    ref_st_p tmp_ref = NULL;
747    int ret = -1;
748
749    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
750        "BMI_post_sendunexpected: addr: %ld, offset: 0x%lx, size: %ld, tag: %d\n",
751        (long)dest, (long)buffer, (long)size, (int)tag);
752
753    *id = 0;
754
755    gen_mutex_lock(&ref_mutex);
756    tmp_ref = ref_list_search_addr(cur_ref_list, dest);
757    if (!tmp_ref)
758    {
759        gen_mutex_unlock(&ref_mutex);
760        return (bmi_errno_to_pvfs(-EPROTO));
761    }
762    gen_mutex_unlock(&ref_mutex);
763
764    ret = tmp_ref->interface->post_sendunexpected(
765        id, tmp_ref->method_addr, buffer, size, buffer_type, tag,
766        user_ptr, context_id, (PVFS_hint)hints);
767    return (ret);
768}
769
770
771/** Checks to see if a particular message has completed.
772 *
773 *  \return 0 on success, -errno on failure.
774 */
775int BMI_test(bmi_op_id_t id,
776             int *outcount,
777             bmi_error_code_t * error_code,
778             bmi_size_t * actual_size,
779             void **user_ptr,
780             int max_idle_time_ms,
781             bmi_context_id context_id)
782{
783    struct method_op *target_op = NULL;
784    int ret = -1;
785
786    if (max_idle_time_ms < 0)
787        return (bmi_errno_to_pvfs(-EINVAL));
788
789    *outcount = 0;
790
791    target_op = id_gen_fast_lookup(id);
792    assert(target_op->op_id == id);
793
794    ret = active_method_table[
795        target_op->addr->method_type]->test(
796            id, outcount, error_code, actual_size, user_ptr,
797            max_idle_time_ms, context_id);
798
799    /* return 1 if anything completed */
800    if (ret == 0 && *outcount == 1)
801    {
802        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
803                     "BMI_test completing: %llu\n", llu(id));
804        return (1);
805    }
806    return (ret);
807}
808
809
810/** Checks to see if any messages from the specified list have completed.
811 *
812 * \return 0 on success, -errno on failure.
813 *
814 * XXX: never used.  May want to add adaptive polling strategy of testcontext
815 * if it becomes used again.
816 */
817int BMI_testsome(int incount,
818                 bmi_op_id_t * id_array,
819                 int *outcount,
820                 int *index_array,
821                 bmi_error_code_t * error_code_array,
822                 bmi_size_t * actual_size_array,
823                 void **user_ptr_array,
824                 int max_idle_time_ms,
825                 bmi_context_id context_id)
826{
827    int ret = 0;
828    int idle_per_method = 0;
829    bmi_op_id_t* tmp_id_array;
830    int i,j;
831    struct method_op *query_op;
832    int need_to_test;
833    int tmp_outcount;
834    int tmp_active_method_count;
835
836    gen_mutex_lock(&active_method_count_mutex);
837    tmp_active_method_count = active_method_count;
838    gen_mutex_unlock(&active_method_count_mutex);
839
840    if (max_idle_time_ms < 0)
841        return (bmi_errno_to_pvfs(-EINVAL));
842
843    *outcount = 0;
844
845    if (tmp_active_method_count == 1) {
846        /* shortcircuit for perhaps common case of only one method */
847        ret = active_method_table[0]->testsome(
848            incount, id_array, outcount, index_array,
849            error_code_array, actual_size_array, user_ptr_array,
850            max_idle_time_ms, context_id);
851
852        /* return 1 if anything completed */
853        if (ret == 0 && *outcount > 0)
854            return (1);
855        else
856            return ret;
857    }
858
859    /* TODO: do something more clever here */
860    if (max_idle_time_ms)
861    {
862        idle_per_method = max_idle_time_ms / tmp_active_method_count;
863        if (!idle_per_method)
864            idle_per_method = 1;
865    }
866
867    tmp_id_array = (bmi_op_id_t*)malloc(incount*sizeof(bmi_op_id_t));
868    if(!tmp_id_array)
869        return(bmi_errno_to_pvfs(-ENOMEM));
870
871    /* iterate over each active method */
872    for(i=0; i<tmp_active_method_count; i++)
873    {
874        /* setup the tmp id array with only operations that match
875         * that method
876         */
877        need_to_test = 0;
878        for(j=0; j<incount; j++)
879        {
880            if(id_array[j])
881            {
882                query_op = (struct method_op*)
883                    id_gen_fast_lookup(id_array[j]);
884                assert(query_op->op_id == id_array[j]);
885                if(query_op->addr->method_type == i)
886                {
887                    tmp_id_array[j] = id_array[j];
888                    need_to_test++;
889                }
890            }
891        }
892
893        /* call testsome if we found any ops for this method */
894        if(need_to_test)
895        {
896            tmp_outcount = 0;
897            ret = active_method_table[i]->testsome(
898                need_to_test, tmp_id_array, &tmp_outcount,
899                &(index_array[*outcount]),
900                &(error_code_array[*outcount]),
901                &(actual_size_array[*outcount]),
902                user_ptr_array ? &(user_ptr_array[*outcount]) : 0,
903                idle_per_method,
904                context_id);
905            if(ret < 0)
906            {
907                /* can't recover from this... */
908                gossip_lerr("Error: critical BMI_testsome failure.\n");
909                goto out;
910            }
911            *outcount += tmp_outcount;
912        }
913    }
914
915  out:
916    free(tmp_id_array);
917
918    if(ret == 0 && *outcount > 0)
919        return(1);
920    else
921        return(0);
922}
923
924
925/*
926 * If some method was recently active, poll it again for speed,
927 * but be sure not to starve any method.  If multiple active,
928 * poll them all.  Return idle_time per method too.
929 */
930static void
931construct_poll_plan(struct method_usage_t * method_usage,
932      int nmeth, int *idle_time_ms)
933{
934    int i, numplan;
935
936    numplan = 0;
937    for (i=0; i<nmeth; i++) {
938        ++method_usage[i].iters_polled;
939        ++method_usage[i].iters_active;
940        method_usage[i].plan = 0;
941        if ((method_usage[i].iters_active <= usage_iters_active) &&
942            (!(method_usage[i].flags & BMI_METHOD_FLAG_NO_POLLING))){
943            /* recently busy, poll */
944            if (0) gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
945                         "%s: polling active meth %d: %d / %d\n", __func__, i,
946                         method_usage[i].iters_active, usage_iters_active);
947            method_usage[i].plan = 1;
948            ++numplan;
949            *idle_time_ms = 0;  /* busy polling */
950        } else if (method_usage[i].iters_polled >= usage_iters_starvation) {
951            /* starving, time to poke this one */
952            if (0) gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
953                         "%s: polling starving meth %d: %d / %d\n", __func__, i,
954                         method_usage[i].iters_polled, usage_iters_starvation);
955            method_usage[i].plan = 1;
956            ++numplan;
957        }
958    }
959
960    /* if nothing is starving or busy, poll everybody */
961    if (numplan == 0) {
962        for (i=0; i<nmeth; i++)
963            method_usage[i].plan = 1;
964        numplan = nmeth;
965
966        /* spread idle time evenly */
967        if (*idle_time_ms) {
968            *idle_time_ms /= numplan;
969            if (*idle_time_ms == 0)
970                *idle_time_ms = 1;
971        }
972        /* note that BMI_testunexpected is always called with idle_time 0 */
973        if (0) gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
974                     "%s: polling all %d methods, idle %d ms\n", __func__,
975                     numplan, *idle_time_ms);
976    }
977}
978
979
980/** Checks to see if any unexpected messages have completed.
981 *
982 *  \return 0 on success, -errno on failure.
983 */
984int BMI_testunexpected(int incount,
985                       int *outcount,
986                       struct BMI_unexpected_info *info_array,
987                       int max_idle_time_ms)
988{
989    int i = 0;
990    int ret = -1;
991    int position = 0;
992    int tmp_outcount = 0;
993    struct bmi_method_unexpected_info sub_info[incount];
994    ref_st_p tmp_ref = NULL;
995    int tmp_active_method_count = 0;
996
997    /* figure out if we need to drop any stale addresses */
998    bmi_check_forget_list();
999    bmi_check_addr_force_drop();
1000
1001    gen_mutex_lock(&active_method_count_mutex);
1002    tmp_active_method_count = active_method_count;
1003    gen_mutex_unlock(&active_method_count_mutex);
1004
1005    if (max_idle_time_ms < 0)
1006        return (bmi_errno_to_pvfs(-EINVAL));
1007
1008    *outcount = 0;
1009
1010    construct_poll_plan(unexpected_method_usage,
1011          tmp_active_method_count, &max_idle_time_ms);
1012
1013    while (position < incount && i < tmp_active_method_count)
1014    {
1015        if (unexpected_method_usage[i].plan) {
1016            ret = active_method_table[i]->testunexpected(
1017                (incount - position), &tmp_outcount,
1018                (&(sub_info[position])), max_idle_time_ms);
1019            if (ret < 0)
1020            {
1021                /* can't recover from this */
1022                gossip_lerr("Error: critical BMI_testunexpected failure.\n");
1023                return (ret);
1024            }
1025            position += tmp_outcount;
1026            (*outcount) += tmp_outcount;
1027            unexpected_method_usage[i].iters_polled = 0;
1028            if (ret)
1029                unexpected_method_usage[i].iters_active = 0;
1030        }
1031        i++;
1032    }
1033
1034    for (i = 0; i < (*outcount); i++)
1035    {
1036        info_array[i].error_code = sub_info[i].error_code;
1037        info_array[i].buffer = sub_info[i].buffer;
1038        info_array[i].size = sub_info[i].size;
1039        info_array[i].tag = sub_info[i].tag;
1040        gen_mutex_lock(&ref_mutex);
1041        tmp_ref = ref_list_search_method_addr(
1042            cur_ref_list, sub_info[i].addr);
1043        if (!tmp_ref)
1044        {
1045            /* yeah, right */
1046            gossip_lerr("Error: critical BMI_testunexpected failure.\n");
1047            gen_mutex_unlock(&ref_mutex);
1048            return (bmi_errno_to_pvfs(-EPROTO));
1049        }
1050        if(global_flags & BMI_AUTO_REF_COUNT)
1051        {
1052            tmp_ref->ref_count++;
1053        }
1054        gen_mutex_unlock(&ref_mutex);
1055        info_array[i].addr = tmp_ref->bmi_addr;
1056    }
1057    /* return 1 if anything completed */
1058    if (ret == 0 && *outcount > 0)
1059    {
1060        return (1);
1061    }
1062    return (0);
1063}
1064
1065
1066/** Checks to see if any messages from the specified context have
1067 *  completed.
1068 *
1069 *  \returns 0 on success, -errno on failure.
1070 */
1071int BMI_testcontext(int incount,
1072                    bmi_op_id_t* out_id_array,
1073                    int *outcount,
1074                    bmi_error_code_t * error_code_array,
1075                    bmi_size_t * actual_size_array,
1076                    void **user_ptr_array,
1077                    int max_idle_time_ms,
1078                    bmi_context_id context_id)
1079{
1080    int i = 0;
1081    int ret = -1;
1082    int position = 0;
1083    int tmp_outcount = 0;
1084    int tmp_active_method_count = 0;
1085    struct timespec ts;
1086
1087    gen_mutex_lock(&active_method_count_mutex);
1088    tmp_active_method_count = active_method_count;
1089    gen_mutex_unlock(&active_method_count_mutex);
1090
1091    if (max_idle_time_ms < 0)
1092        return (bmi_errno_to_pvfs(-EINVAL));
1093
1094    *outcount = 0;
1095
1096    if(tmp_active_method_count < 1)
1097    {
1098        /* nothing active yet, just snooze and return */
1099        if(max_idle_time_ms > 0)
1100        {
1101            ts.tv_sec = 0;
1102            ts.tv_nsec = 2000;
1103            nanosleep(&ts, NULL);
1104        }
1105        return(0);
1106    }
1107
1108    construct_poll_plan(expected_method_usage,
1109          tmp_active_method_count, &max_idle_time_ms);
1110
1111    while (position < incount && i < tmp_active_method_count)
1112    {
1113        if (expected_method_usage[i].plan) {
1114            ret = active_method_table[i]->testcontext(
1115                incount - position,
1116                &out_id_array[position],
1117                &tmp_outcount,
1118                &error_code_array[position],
1119                &actual_size_array[position],
1120                user_ptr_array ?  &user_ptr_array[position] : NULL,
1121                max_idle_time_ms,
1122                context_id);
1123            if (ret < 0)
1124            {
1125                /* can't recover from this */
1126                gossip_lerr("Error: critical BMI_testcontext failure.\n");
1127                return (ret);
1128            }
1129            position += tmp_outcount;
1130            (*outcount) += tmp_outcount;
1131            expected_method_usage[i].iters_polled = 0;
1132            if (ret)
1133                expected_method_usage[i].iters_active = 0;
1134        }
1135        i++;
1136    }
1137
1138    /* return 1 if anything completed */
1139    if (ret == 0 && *outcount > 0)
1140    {
1141        for(i=0; i<*outcount; i++)
1142        {
1143            gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1144                "BMI_testcontext completing: %llu\n", llu(out_id_array[i]));
1145        }
1146        return (1);
1147    }
1148    return (0);
1149
1150}
1151
1152
1153/** Performs a reverse lookup, returning the string (URL style)
1154 *  address for a given opaque address.
1155 *
1156 *  NOTE: caller must not free or modify returned string
1157 *
1158 *  \return Pointer to string on success, NULL on failure.
1159 */
1160const char* BMI_addr_rev_lookup(BMI_addr_t addr)
1161{
1162    ref_st_p tmp_ref = NULL;
1163    char* tmp_str = NULL;
1164
1165    /* find a reference that matches this address */
1166    gen_mutex_lock(&ref_mutex);
1167    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1168    if (!tmp_ref)
1169    {
1170        gen_mutex_unlock(&ref_mutex);
1171        return (NULL);
1172    }
1173    gen_mutex_unlock(&ref_mutex);
1174   
1175    tmp_str = tmp_ref->id_string;
1176
1177    return(tmp_str);
1178}
1179
1180/** Performs a reverse lookup, returning a string
1181 *  address for a given opaque address.  Works on any address, even those
1182 *  generated unexpectedly, but only gives hostname instead of full
1183 *  BMI URL style address
1184 *
1185 *  NOTE: caller must not free or modify returned string
1186 *
1187 *  \return Pointer to string on success, NULL on failure.
1188 */
1189const char* BMI_addr_rev_lookup_unexpected(BMI_addr_t addr)
1190{
1191    ref_st_p tmp_ref = NULL;
1192
1193    /* find a reference that matches this address */
1194    gen_mutex_lock(&ref_mutex);
1195    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1196    if (!tmp_ref)
1197    {
1198        gen_mutex_unlock(&ref_mutex);
1199        return ("UNKNOWN");
1200    }
1201    gen_mutex_unlock(&ref_mutex);
1202   
1203    if(!tmp_ref->interface->rev_lookup_unexpected)
1204    {
1205        return("UNKNOWN");
1206    }
1207
1208    return(tmp_ref->interface->rev_lookup_unexpected(
1209        tmp_ref->method_addr));
1210}
1211
1212
1213/** Allocates memory that can be used in native mode by the BMI layer.
1214 *
1215 *  \return Pointer to buffer on success, NULL on failure.
1216 */
1217void *BMI_memalloc(BMI_addr_t addr,
1218                   bmi_size_t size,
1219                   enum bmi_op_type send_recv)
1220{
1221    void *new_buffer = NULL;
1222    ref_st_p tmp_ref = NULL;
1223
1224    /* find a reference that matches this address */
1225    gen_mutex_lock(&ref_mutex);
1226    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1227    if (!tmp_ref)
1228    {
1229        gen_mutex_unlock(&ref_mutex);
1230        return (NULL);
1231    }
1232    gen_mutex_unlock(&ref_mutex);
1233
1234    /* allocate the buffer using the method's mechanism */
1235    new_buffer = tmp_ref->interface->memalloc(size, send_recv);
1236
1237    return (new_buffer);
1238}
1239
1240/** Frees memory that was allocated with BMI_memalloc().
1241 *
1242 *  \return 0 on success, -errno on failure.
1243 */
1244int BMI_memfree(BMI_addr_t addr,
1245                void *buffer,
1246                bmi_size_t size,
1247                enum bmi_op_type send_recv)
1248{
1249    ref_st_p tmp_ref = NULL;
1250    int ret = -1;
1251
1252    /* find a reference that matches this address */
1253    gen_mutex_lock(&ref_mutex);
1254    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1255    if (!tmp_ref)
1256    {
1257        gen_mutex_unlock(&ref_mutex);
1258        return (bmi_errno_to_pvfs(-EINVAL));
1259    }
1260    gen_mutex_unlock(&ref_mutex);
1261
1262    /* free the memory */
1263    ret = tmp_ref->interface->memfree(buffer, size, send_recv);
1264
1265    return (ret);
1266}
1267
1268/** Acknowledge that an unexpected message has been
1269 * serviced that was returned from BMI_test_unexpected().
1270 *
1271 *  \return 0 on success, -errno on failure.
1272 */
1273int BMI_unexpected_free(BMI_addr_t addr,
1274                void *buffer)
1275{
1276    ref_st_p tmp_ref = NULL;
1277    int ret = -1;
1278
1279    /* find a reference that matches this address */
1280    gen_mutex_lock(&ref_mutex);
1281    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1282    if (!tmp_ref)
1283    {
1284        gen_mutex_unlock(&ref_mutex);
1285        return (bmi_errno_to_pvfs(-EINVAL));
1286    }
1287    gen_mutex_unlock(&ref_mutex);
1288
1289    if (!tmp_ref->interface->unexpected_free)
1290    {
1291        gossip_err("unimplemented unexpected_free callback\n");
1292        return bmi_errno_to_pvfs(-EOPNOTSUPP);
1293    }
1294    /* free the memory */
1295    ret = tmp_ref->interface->unexpected_free(buffer);
1296
1297    return (ret);
1298}
1299
1300/** Pass in optional parameters.
1301 *
1302 *  \return 0 on success, -errno on failure.
1303 */
1304int BMI_set_info(BMI_addr_t addr,
1305                 int option,
1306                 void *inout_parameter)
1307{
1308    int ret = -1;
1309    int i = 0;
1310    ref_st_p tmp_ref = NULL;
1311
1312    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1313                 "[BMI CONTROL]: %s: set_info: %llu option: %d\n",
1314                 __func__, llu(addr), option);
1315    /* if the addr is NULL, then the set_info should apply to all
1316     * available methods.
1317     */
1318    if (!addr)
1319    {
1320        if (!active_method_table)
1321        {
1322            return (bmi_errno_to_pvfs(-EINVAL));
1323        }
1324        gen_mutex_lock(&active_method_count_mutex);
1325        for (i = 0; i < active_method_count; i++)
1326        {
1327            ret = active_method_table[i]->set_info(
1328                option, inout_parameter);
1329            /* we bail out if even a single set_info fails */
1330            if (ret < 0)
1331            {
1332                gossip_lerr(
1333                    "Error: failure on set_info to method: %d\n", i);
1334                gen_mutex_unlock(&active_method_count_mutex);
1335                return (ret);
1336            }
1337        }
1338        gen_mutex_unlock(&active_method_count_mutex);
1339        return (0);
1340    }
1341
1342    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1343                 "[BMI CONTROL]: %s: searching for ref %llu\n",
1344                 __func__, llu(addr));
1345    /* find a reference that matches this address */
1346    gen_mutex_lock(&ref_mutex);
1347    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1348    if (!tmp_ref)
1349    {
1350        gen_mutex_unlock(&ref_mutex);
1351        return (bmi_errno_to_pvfs(-EINVAL));
1352    }
1353
1354    /* shortcut address reference counting */
1355    if(option == BMI_INC_ADDR_REF)
1356    {
1357        tmp_ref->ref_count++;
1358        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1359                     "[BMI CONTROL]: %s: incremented ref %llu to: %d\n",
1360                     __func__, llu(addr), tmp_ref->ref_count);
1361        gen_mutex_unlock(&ref_mutex);
1362        return(0);
1363    }
1364    if(option == BMI_DEC_ADDR_REF)
1365    {
1366        tmp_ref->ref_count--;
1367        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1368                     "[BMI CONTROL]: %s: decremented ref %llu to: %d\n",
1369                     __func__, llu(addr), tmp_ref->ref_count);
1370        assert(tmp_ref->ref_count >= 0);
1371
1372        if(tmp_ref->ref_count == 0)
1373        {
1374            bmi_addr_drop(tmp_ref);
1375        }
1376        gen_mutex_unlock(&ref_mutex);
1377        return(0);
1378    }
1379
1380    /* if the caller requests a TCP specific close socket action */
1381    if (option == BMI_TCP_CLOSE_SOCKET)
1382    {
1383        /* check to see if the address is in fact a tcp address */
1384        if(strcmp(tmp_ref->interface->method_name, "bmi_tcp") == 0)
1385        {
1386            /* take the same action as in the BMI_DEC_ADDR_REF case to clean
1387             * out the entire address structure and anything linked to it so
1388             * that the next addr_lookup starts from scratch
1389             */
1390            gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1391                         "[BMI CONTROL]: %s: Closing bmi_tcp "
1392                         "connection at caller's request.\n",
1393                         __func__);
1394            ref_list_rem(cur_ref_list, addr);
1395            dealloc_ref_st(tmp_ref);
1396        }
1397        gen_mutex_unlock(&ref_mutex);
1398        return 0;
1399    }
1400
1401    gen_mutex_unlock(&ref_mutex);
1402
1403    ret = tmp_ref->interface->set_info(option, inout_parameter);
1404
1405    return (ret);
1406}
1407
1408/** Query for optional parameters.
1409 *
1410 *  \return 0 on success, -errno on failure.
1411 */
1412int BMI_get_info(BMI_addr_t addr,
1413                 int option,
1414                 void *inout_parameter)
1415{
1416    int i = 0;
1417    int maxsize = 0;
1418    int tmp_maxsize;
1419    int ret = 0;
1420    ref_st_p tmp_ref = NULL;
1421
1422    switch (option)
1423    {
1424        /* check to see if the interface is initialized */
1425    case BMI_CHECK_INIT:
1426        gen_mutex_lock(&active_method_count_mutex);
1427        if (active_method_count > 0)
1428        {
1429            gen_mutex_unlock(&active_method_count_mutex);
1430            return (0);
1431        }
1432        else
1433        {
1434            gen_mutex_unlock(&active_method_count_mutex);
1435            return (bmi_errno_to_pvfs(-ENETDOWN));
1436        }
1437    case BMI_CHECK_MAXSIZE:
1438        gen_mutex_lock(&active_method_count_mutex);
1439        for (i = 0; i < active_method_count; i++)
1440        {
1441            ret = active_method_table[i]->get_info(
1442                option, &tmp_maxsize);
1443            if (ret < 0)
1444            {
1445                return (ret);
1446            }
1447            if (i == 0)
1448            {
1449                maxsize = tmp_maxsize;
1450            }
1451            else
1452            {
1453                if (tmp_maxsize < maxsize)
1454                    maxsize = tmp_maxsize;
1455            }
1456            *((int *) inout_parameter) = maxsize;
1457        }
1458        gen_mutex_unlock(&active_method_count_mutex);
1459        break;
1460    case BMI_GET_METH_ADDR:
1461        gen_mutex_lock(&ref_mutex);
1462        tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1463        if(!tmp_ref)
1464        {
1465            gen_mutex_unlock(&ref_mutex);
1466            return (bmi_errno_to_pvfs(-EINVAL));
1467        }
1468        gen_mutex_unlock(&ref_mutex);
1469        *((void**) inout_parameter) = tmp_ref->method_addr;
1470        break;
1471    case BMI_GET_UNEXP_SIZE:
1472        gen_mutex_lock(&ref_mutex);
1473        tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1474        if(!tmp_ref)
1475        {
1476            gen_mutex_unlock(&ref_mutex);
1477            return (bmi_errno_to_pvfs(-EINVAL));
1478        }
1479        gen_mutex_unlock(&ref_mutex);
1480        ret = tmp_ref->interface->get_info(
1481            option, inout_parameter);
1482        if(ret < 0)
1483        {
1484            return ret;
1485        }
1486        break;
1487
1488    default:
1489        return (bmi_errno_to_pvfs(-ENOSYS));
1490    }
1491    return (0);
1492}
1493
1494/** Given a string representation of a host/network address and a BMI
1495 * address handle, return whether the BMI address handle is part of the wildcard
1496 * address range specified by the string.
1497 * \return 1 on success, -errno on failure and 0 if it is not part of
1498 * the specified range
1499 */
1500int BMI_query_addr_range (BMI_addr_t addr, const char *id_string, int netmask)
1501{
1502    int ret = -1;
1503    int i = 0, failed = 1;
1504    int provided_method_length = 0;
1505    char *ptr, *provided_method_name = NULL;
1506    ref_st_p tmp_ref = NULL;
1507
1508    if((strlen(id_string)+1) > BMI_MAX_ADDR_LEN)
1509    {
1510        return(bmi_errno_to_pvfs(-ENAMETOOLONG));
1511    }
1512    /* lookup the provided address */
1513    gen_mutex_lock(&ref_mutex);
1514    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1515    if (!tmp_ref)
1516    {
1517        gen_mutex_unlock(&ref_mutex);
1518        return (bmi_errno_to_pvfs(-EPROTO));
1519    }
1520    gen_mutex_unlock(&ref_mutex);
1521
1522    ptr = strchr(id_string, ':');
1523    if (ptr == NULL)
1524    {
1525        return (bmi_errno_to_pvfs(-EINVAL));
1526    }
1527    ret = -EPROTO;
1528    provided_method_length = (unsigned long) ptr - (unsigned long) id_string;
1529    provided_method_name = (char *) calloc(provided_method_length + 1, sizeof(char));
1530    if (provided_method_name == NULL)
1531    {
1532        return bmi_errno_to_pvfs(-ENOMEM);
1533    }
1534    strncpy(provided_method_name, id_string, provided_method_length);
1535
1536    /* Now we will run through each method looking for one that
1537     * matches the specified wildcard address.
1538     */
1539    i = 0;
1540    gen_mutex_lock(&active_method_count_mutex);
1541    while (i < active_method_count)
1542    {
1543        const char *active_method_name = active_method_table[i]->method_name + 4;
1544        /* provided name matches this interface */
1545        if (!strncmp(active_method_name, provided_method_name, provided_method_length))
1546        {
1547            int (*meth_fnptr)(bmi_method_addr_p, const char *, int);
1548            failed = 0;
1549            if ((meth_fnptr = active_method_table[i]->query_addr_range) == NULL)
1550            {
1551                ret = -ENOSYS;
1552                gossip_lerr("Error: method doesn't implement querying address range/wildcards! Cannot implement FS export options!\n");
1553                failed = 1;
1554                break;
1555            }
1556            /* pass it into the specific bmi layer */
1557            ret = meth_fnptr(tmp_ref->method_addr, id_string, netmask);
1558            if (ret < 0)
1559                failed = 1;
1560            break;
1561        }
1562        i++;
1563    }
1564    gen_mutex_unlock(&active_method_count_mutex);
1565    free(provided_method_name);
1566    if (failed)
1567        return bmi_errno_to_pvfs(ret);
1568    return ret;
1569}
1570
1571/** Resolves the string representation of a host address into a BMI
1572 *  address handle.
1573 *
1574 *  \return 0 on success, -errno on failure.
1575 */
1576int BMI_addr_lookup(BMI_addr_t * new_addr,
1577                    const char *id_string)
1578{
1579
1580    ref_st_p new_ref = NULL;
1581    bmi_method_addr_p meth_addr = NULL;
1582    int ret = -1;
1583    int i = 0;
1584    int failed;
1585
1586    if((strlen(id_string)+1) > BMI_MAX_ADDR_LEN)
1587    {
1588        return(bmi_errno_to_pvfs(-ENAMETOOLONG));
1589    }
1590
1591    /* set the addr to zero in case we fail */
1592    *new_addr = 0;
1593
1594    /* First we want to check to see if this host has already been
1595     * discovered! */
1596    gen_mutex_lock(&ref_mutex);
1597    new_ref = ref_list_search_str(cur_ref_list, id_string);
1598    gen_mutex_unlock(&ref_mutex);
1599
1600    if (new_ref)
1601    {
1602        /* we found it. */
1603        *new_addr = new_ref->bmi_addr;
1604        return (0);
1605    }
1606
1607    /* Now we will run through each method looking for one that
1608     * responds successfully.  It is assumed that they are already
1609     * listed in order of preference
1610     */
1611    i = 0;
1612    gen_mutex_lock(&active_method_count_mutex);
1613    while ((i < active_method_count) &&
1614           !(meth_addr = active_method_table[i]->method_addr_lookup(id_string)))
1615    {
1616        i++;
1617    }
1618
1619    /* if not found, try to bring it up now */
1620    failed = 0;
1621    if (!meth_addr) {
1622        for (i=0; i<known_method_count; i++) {
1623            const char *name;
1624            /* only bother with those not active */
1625            int j;
1626            for (j=0; j<active_method_count; j++)
1627                if (known_method_table[i] == active_method_table[j])
1628                    break;
1629            if (j < active_method_count)
1630                continue;
1631
1632            /* well-known that mapping is "x" -> "bmi_x" */
1633            name = known_method_table[i]->method_name + 4;
1634            if (!strncmp(id_string, name, strlen(name))) {
1635                ret = activate_method(known_method_table[i]->method_name, 0, 0);
1636                if (ret < 0) {
1637                    failed = 1;
1638                    break;
1639                }
1640                meth_addr = known_method_table[i]->
1641                    method_addr_lookup(id_string);
1642                i = active_method_count - 1;  /* point at the new one */
1643                break;
1644            }
1645        }
1646    }
1647    gen_mutex_unlock(&active_method_count_mutex);
1648    if (failed)
1649        return bmi_errno_to_pvfs(ret);
1650
1651    /* make sure one was successful */
1652    if (!meth_addr)
1653    {
1654        return bmi_errno_to_pvfs(-ENOPROTOOPT);
1655    }
1656
1657    /* create a new reference for the addr */
1658    new_ref = alloc_ref_st();
1659    if (!new_ref)
1660    {
1661        ret = bmi_errno_to_pvfs(-ENOMEM);
1662        goto bmi_addr_lookup_failure;
1663    }
1664
1665    /* fill in the details */
1666    new_ref->method_addr = meth_addr;
1667    meth_addr->parent = new_ref;
1668    new_ref->id_string = (char *) malloc(strlen(id_string) + 1);
1669    if (!new_ref->id_string)
1670    {
1671        ret = bmi_errno_to_pvfs(errno);
1672        goto bmi_addr_lookup_failure;
1673    }
1674    strcpy(new_ref->id_string, id_string);
1675    new_ref->interface = active_method_table[i];
1676
1677    /* keep up with the reference and we are done */
1678    gen_mutex_lock(&ref_mutex);
1679    ref_list_add(cur_ref_list, new_ref);
1680    gen_mutex_unlock(&ref_mutex);
1681
1682    *new_addr = new_ref->bmi_addr;
1683    return (0);
1684
1685  bmi_addr_lookup_failure:
1686
1687    if (meth_addr)
1688    {
1689        active_method_table[i]->set_info(
1690            BMI_DROP_ADDR, meth_addr);
1691    }
1692
1693    if (new_ref)
1694    {
1695        dealloc_ref_st(new_ref);
1696    }
1697
1698    return (ret);
1699}
1700
1701
1702/** Similar to BMI_post_send(), except that the source buffer is
1703 *  replaced by a list of (possibly non contiguous) buffers.
1704 *
1705 *  \return 0 on success, 1 on immediate successful completion,
1706 *  -errno on failure.
1707 */
1708int BMI_post_send_list(bmi_op_id_t * id,
1709                       BMI_addr_t dest,
1710                       const void *const *buffer_list,
1711                       const bmi_size_t *size_list,
1712                       int list_count,
1713                       /* "total_size" is the sum of the size list */
1714                       bmi_size_t total_size,
1715                       enum bmi_buffer_type buffer_type,
1716                       bmi_msg_tag_t tag,
1717                       void *user_ptr,
1718                       bmi_context_id context_id,
1719                       bmi_hint hints)
1720{
1721    ref_st_p tmp_ref = NULL;
1722    int ret = -1;
1723
1724#ifndef GOSSIP_DISABLE_DEBUG
1725    int i;
1726
1727    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1728        "BMI_post_send_list: addr: %ld, count: %d, total_size: %ld, tag: %d\n",
1729        (long)dest, list_count, (long)total_size, (int)tag);
1730
1731    for(i=0; i<list_count; i++)
1732    {
1733        gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1734            "   element %d: offset: 0x%lx, size: %ld\n",
1735            i, (long)buffer_list[i], (long)size_list[i]);
1736    }
1737#endif
1738
1739    *id = 0;
1740
1741    gen_mutex_lock(&ref_mutex);
1742    tmp_ref = ref_list_search_addr(cur_ref_list, dest);
1743    if (!tmp_ref)
1744    {
1745        gen_mutex_unlock(&ref_mutex);
1746        return (bmi_errno_to_pvfs(-EPROTO));
1747    }
1748    gen_mutex_unlock(&ref_mutex);
1749
1750    if (tmp_ref->interface->post_send_list)
1751    {
1752        ret = tmp_ref->interface->post_send_list(
1753            id, tmp_ref->method_addr, buffer_list, size_list,
1754            list_count, total_size, buffer_type, tag, user_ptr,
1755            context_id, (PVFS_hint)hints);
1756
1757        return (ret);
1758    }
1759
1760    gossip_lerr("Error: method doesn't implement send_list.\n");
1761    gossip_lerr("Error: send_list emulation not yet available.\n");
1762
1763    return (bmi_errno_to_pvfs(-ENOSYS));
1764}
1765
1766
1767/** Similar to BMI_post_recv(), except that the dest buffer is
1768 *  replaced by a list of (possibly non contiguous) buffers
1769 *
1770 *  \param total_expected_size the sum of the size list.
1771 *  \param total_actual_size the aggregate amt that was received.
1772 *
1773 *  \return 0 on success, 1 on immediate successful completion,
1774 *  -errno on failure.
1775 */
1776int BMI_post_recv_list(bmi_op_id_t * id,
1777                       BMI_addr_t src,
1778                       void *const *buffer_list,
1779                       const bmi_size_t *size_list,
1780                       int list_count,
1781                       bmi_size_t total_expected_size,
1782                       bmi_size_t * total_actual_size,
1783                       enum bmi_buffer_type buffer_type,
1784                       bmi_msg_tag_t tag,
1785                       void *user_ptr,
1786                       bmi_context_id context_id,
1787                       bmi_hint hints)
1788{
1789    ref_st_p tmp_ref = NULL;
1790    int ret = -1;
1791
1792#ifndef GOSSIP_DISABLE_DEBUG
1793    int i;
1794
1795    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1796        "BMI_post_recv_list: addr: %ld, count: %d, total_size: %ld, tag: %d\n",
1797        (long)src, list_count, (long)total_expected_size, (int)tag);
1798
1799    for(i=0; i<list_count; i++)
1800    {
1801        gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1802            "   element %d: offset: 0x%lx, size: %ld\n",
1803            i, (long)buffer_list[i], (long)size_list[i]);
1804    }
1805#endif
1806
1807    *id = 0;
1808
1809    gen_mutex_lock(&ref_mutex);
1810    tmp_ref = ref_list_search_addr(cur_ref_list, src);
1811    if (!tmp_ref)
1812    {
1813        gen_mutex_unlock(&ref_mutex);
1814        return (bmi_errno_to_pvfs(-EPROTO));
1815    }
1816    gen_mutex_unlock(&ref_mutex);
1817
1818    if (tmp_ref->interface->post_recv_list)
1819    {
1820        ret = tmp_ref->interface->post_recv_list(
1821            id, tmp_ref->method_addr, buffer_list, size_list,
1822            list_count, total_expected_size, total_actual_size,
1823            buffer_type, tag, user_ptr, context_id, (PVFS_hint)hints);
1824
1825        return (ret);
1826    }
1827
1828    gossip_lerr("Error: method doesn't implement recv_list.\n");
1829    gossip_lerr("Error: recv_list emulation not yet available.\n");
1830
1831    return (bmi_errno_to_pvfs(-ENOSYS));
1832}
1833
1834
1835/** Similar to BMI_post_sendunexpected(), except that the source buffer is
1836 *  replaced by a list of (possibly non contiguous) buffers.
1837 *
1838 *  \param total_size the sum of the size list.
1839 *
1840 *  \return 0 on success, 1 on immediate successful completion,
1841 *  -errno on failure.
1842 */
1843int BMI_post_sendunexpected_list(bmi_op_id_t * id,
1844                                 BMI_addr_t dest,
1845                                 const void *const *buffer_list,
1846                                 const bmi_size_t *size_list,
1847                                 int list_count,
1848                                 bmi_size_t total_size,
1849                                 enum bmi_buffer_type buffer_type,
1850                                 bmi_msg_tag_t tag,
1851                                 void *user_ptr,
1852                                 bmi_context_id context_id,
1853                                 bmi_hint hints)
1854{
1855    ref_st_p tmp_ref = NULL;
1856    int ret = -1;
1857
1858#ifndef GOSSIP_DISABLE_DEBUG
1859    int i;
1860
1861    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1862        "BMI_post_sendunexpected_list: addr: %ld, count: %d, "
1863                 "total_size: %ld, tag: %d\n",  (long)dest, list_count,
1864                 (long)total_size, (int)tag);
1865
1866    for(i=0; i<list_count; i++)
1867    {
1868        gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1869            "   element %d: offset: 0x%lx, size: %ld\n",
1870            i, (long)buffer_list[i], (long)size_list[i]);
1871    }
1872#endif
1873
1874    *id = 0;
1875
1876    gen_mutex_lock(&ref_mutex);
1877    tmp_ref = ref_list_search_addr(cur_ref_list, dest);
1878    if (!tmp_ref)
1879    {
1880        gen_mutex_unlock(&ref_mutex);
1881        return (bmi_errno_to_pvfs(-EPROTO));
1882    }
1883    gen_mutex_unlock(&ref_mutex);
1884
1885    if (tmp_ref->interface->post_send_list)
1886    {
1887        ret = tmp_ref->interface->post_sendunexpected_list(
1888            id, tmp_ref->method_addr, buffer_list, size_list,
1889            list_count, total_size, buffer_type, tag, user_ptr,
1890            context_id, (PVFS_hint)hints);
1891
1892        return (ret);
1893    }
1894
1895    gossip_lerr("Error: method doesn't implement sendunexpected_list.\n");
1896    gossip_lerr("Error: send_list emulation not yet available.\n");
1897
1898    return (bmi_errno_to_pvfs(-ENOSYS));
1899}
1900
1901
1902/** Attempts to cancel a pending operation that has not yet completed.
1903 *  Caller must still test to gather error code after calling this
1904 *  function even if it returns 0.
1905 *
1906 *  \return 0 on success, -errno on failure.
1907 */
1908int BMI_cancel(bmi_op_id_t id,
1909               bmi_context_id context_id)
1910{
1911    struct method_op *target_op = NULL;
1912    int ret = -1;
1913
1914    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1915                 "%s: cancel id %llu\n", __func__, llu(id));
1916
1917    target_op = id_gen_fast_lookup(id);
1918    if(target_op == NULL)
1919    {
1920        /* if we can't find the operation, then assume it has already
1921         * completed naturally.
1922         */
1923        return(0);
1924    }
1925
1926    assert(target_op->op_id == id);
1927
1928    if(active_method_table[target_op->addr->method_type]->cancel)
1929    {
1930        ret = active_method_table[
1931            target_op->addr->method_type]->cancel(
1932                id, context_id);
1933    }
1934    else
1935    {
1936        gossip_err("Error: BMI_cancel() unimplemented "
1937                   "for this module.\n");
1938        ret = bmi_errno_to_pvfs(-ENOSYS);
1939    }
1940
1941    return (ret);
1942}
1943
1944/**************************************************************
1945 * method callback functions
1946 */
1947
1948/* bmi_method_addr_reg_callback()
1949 *
1950 * Used by the methods to register new addresses when they are
1951 * discovered.  Only call this method when the device gets an
1952 * unexpected receive from a new peer, i.e., if you do the equivalent
1953 * of a socket accept() and get a new connection.
1954 *
1955 * Do not call this function for active lookups, that is from your
1956 * method_addr_lookup.  BMI already knows about the address in
1957 * this case, since the user provided it.
1958 *
1959 * returns 0 on success, -errno on failure
1960 */
1961BMI_addr_t bmi_method_addr_reg_callback(bmi_method_addr_p map)
1962{
1963    ref_st_p new_ref = NULL;
1964
1965    /* NOTE: we are trusting the method to make sure that we really
1966     * don't know about the address yet.  No verification done here.
1967     */
1968
1969    /* create a new reference structure */
1970    new_ref = alloc_ref_st();
1971    if (!new_ref)
1972    {
1973        return 0;
1974    }
1975
1976    /*
1977      fill in the details; we don't have an id string for this one.
1978    */
1979    new_ref->method_addr = map;
1980    new_ref->id_string = NULL;
1981    map->parent = new_ref;
1982
1983    /* check the method_type from the method_addr pointer to know
1984     * which interface to use */
1985    new_ref->interface = active_method_table[map->method_type];
1986
1987    /* add the reference structure to the list */
1988    ref_list_add(cur_ref_list, new_ref);
1989
1990    return new_ref->bmi_addr;
1991}
1992
1993int bmi_method_addr_forget_callback(BMI_addr_t addr)
1994{
1995    struct forget_item* tmp_item = NULL;
1996
1997    tmp_item = (struct forget_item*)malloc(sizeof(struct forget_item));
1998    if(!tmp_item)
1999    {
2000        return(bmi_errno_to_pvfs(-ENOMEM));
2001    }
2002
2003    tmp_item->addr = addr;
2004
2005    /* add to queue of items that we want the BMI control layer to consider
2006     * deallocating
2007     */
2008    gen_mutex_lock(&forget_list_mutex);
2009    qlist_add(&tmp_item->link, &forget_list);
2010    gen_mutex_unlock(&forget_list_mutex);
2011
2012    return (0);
2013}
2014
2015/*
2016 * Signal BMI to drop inactive connections for this method.
2017 */
2018void bmi_method_addr_drop_callback (char* method_name)
2019{
2020    struct drop_item *item =
2021        (struct drop_item *) malloc(sizeof(struct drop_item));
2022
2023    /*
2024     * If we can't allocate, just return.
2025     * Maybe this will succeed next time.
2026     */
2027    if (!item) return;
2028
2029    item->method_name = method_name;
2030   
2031    gen_mutex_lock(&bmi_addr_force_drop_list_mutex);
2032    qlist_add(&item->link, &bmi_addr_force_drop_list);
2033    gen_mutex_unlock(&bmi_addr_force_drop_list_mutex);
2034
2035    return;
2036}
2037
2038
2039/**
2040 * Try to increase method_usage_t struct to include room for a new method.
2041 */
2042static int grow_method_usage (struct method_usage_t ** p, int newflags)
2043{
2044    struct method_usage_t * x = *p;
2045    *p = malloc((active_method_count + 1) * sizeof(**p));
2046    if (!*p) {
2047        *p = x;
2048        return 0;
2049    }
2050    if (active_method_count) {
2051        memcpy(*p, x, active_method_count * sizeof(**p));
2052        free(x);
2053    }
2054    memset(&((*p)[active_method_count]), 0, sizeof(**p));
2055    (*p)[active_method_count].flags = newflags;
2056
2057    return 1;
2058 }
2059
2060/*
2061 * Attempt to insert this name into the list of active methods,
2062 * and bring it up.
2063 * NOTE: assumes caller has protected active_method_count with a mutex lock
2064 */
2065static int
2066activate_method(const char *name, const char *listen_addr, int flags)
2067{
2068    int i, ret;
2069    void *x;
2070    struct bmi_method_ops *meth;
2071    bmi_method_addr_p new_addr;
2072
2073    /* already active? */
2074    for (i=0; i<active_method_count; i++)
2075        if (!strcmp(active_method_table[i]->method_name, name)) break;
2076    if (i < active_method_count)
2077    {
2078        return 0;
2079    }
2080
2081    /* is the method known? */
2082    for (i=0; i<known_method_count; i++)
2083        if (!strcmp(known_method_table[i]->method_name, name)) break;
2084    if (i == known_method_count) {
2085        gossip_lerr("Error: no method available for %s.\n", name);
2086        return -ENOPROTOOPT;
2087    }
2088    meth = known_method_table[i];
2089
2090    /*
2091     * Later: try to load a dynamic module, growing the known method
2092     * table and search it again.
2093     */
2094
2095    /* toss it into the active table */
2096    x = active_method_table;
2097    active_method_table = malloc(
2098        (active_method_count + 1) * sizeof(*active_method_table));
2099    if (!active_method_table) {
2100        active_method_table = x;
2101        return -ENOMEM;
2102    }
2103    if (active_method_count) {
2104        memcpy(active_method_table, x,
2105            active_method_count * sizeof(*active_method_table));
2106        free(x);
2107    }
2108    active_method_table[active_method_count] = meth;
2109
2110    if (!grow_method_usage (&unexpected_method_usage, meth->flags))
2111       return -ENOMEM;
2112
2113    /**
2114     * If we run out of memory here, the unexpected_method_usage will be
2115     * larger than strictly required but there is no memory leak.
2116     */
2117
2118    if (!grow_method_usage (&expected_method_usage, meth->flags))
2119       return -ENOMEM;
2120
2121    ++active_method_count;
2122
2123    /* initialize it */
2124    new_addr = 0;
2125    if (listen_addr) {
2126        new_addr = meth->method_addr_lookup(listen_addr);
2127        if (!new_addr) {
2128            gossip_err(
2129                "Error: failed to lookup listen address %s for method %s.\n",
2130                listen_addr, name);
2131            --active_method_count;
2132            return -EINVAL;
2133        }
2134        /* this is a bit of a hack */
2135        new_addr->method_type = active_method_count - 1;
2136    }
2137    ret = meth->initialize(new_addr, active_method_count - 1, flags);
2138    if (ret < 0) {
2139        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
2140          "failed to initialize method %s.\n", name);
2141        --active_method_count;
2142        return ret;
2143    }
2144
2145    /* tell it about any open contexts */
2146    for (i=0; i<BMI_MAX_CONTEXTS; i++)
2147        if (context_array[i]) {
2148            ret = meth->open_context(i);
2149            if (ret < 0)
2150                break;
2151        }
2152
2153    return ret;
2154}
2155
2156 
2157int bmi_errno_to_pvfs(int error)
2158{
2159    int bmi_errno = error;
2160
2161#define __CASE(err)                      \
2162case -err: bmi_errno = -BMI_##err; break;\
2163case err: bmi_errno = BMI_##err; break
2164
2165    switch(error)
2166    {
2167        __CASE(EPERM);
2168        __CASE(ENOENT);
2169        __CASE(EINTR);
2170        __CASE(EIO);
2171        __CASE(ENXIO);
2172        __CASE(EBADF);
2173        __CASE(EAGAIN);
2174        __CASE(ENOMEM);
2175        __CASE(EFAULT);
2176        __CASE(EBUSY);
2177        __CASE(EEXIST);
2178        __CASE(ENODEV);
2179        __CASE(ENOTDIR);
2180        __CASE(EISDIR);
2181        __CASE(EINVAL);
2182        __CASE(EMFILE);
2183        __CASE(EFBIG);
2184        __CASE(ENOSPC);
2185        __CASE(EROFS);
2186        __CASE(EMLINK);
2187        __CASE(EPIPE);
2188        __CASE(EDEADLK);
2189        __CASE(ENAMETOOLONG);
2190        __CASE(ENOLCK);
2191        __CASE(ENOSYS);
2192        __CASE(ENOTEMPTY);
2193        __CASE(ELOOP);
2194        __CASE(ENOMSG);
2195        __CASE(ENODATA);
2196        __CASE(ETIME);
2197        __CASE(EREMOTE);
2198        __CASE(EPROTO);
2199        __CASE(EBADMSG);
2200        __CASE(EOVERFLOW);
2201        __CASE(EMSGSIZE);
2202        __CASE(EPROTOTYPE);
2203        __CASE(ENOPROTOOPT);
2204        __CASE(EPROTONOSUPPORT);
2205        __CASE(EOPNOTSUPP);
2206        __CASE(EADDRINUSE);
2207        __CASE(EADDRNOTAVAIL);
2208        __CASE(ENETDOWN);
2209        __CASE(ENETUNREACH);
2210        __CASE(ENETRESET);
2211        __CASE(ENOBUFS);
2212        __CASE(ETIMEDOUT);
2213        __CASE(ECONNREFUSED);
2214        __CASE(EHOSTDOWN);
2215        __CASE(EHOSTUNREACH);
2216        __CASE(EALREADY);
2217        __CASE(EACCES);
2218        __CASE(ECONNRESET);
2219#undef __CASE
2220    }
2221    return bmi_errno;
2222}
2223
2224/* bmi_check_forget_list()
2225 *
2226 * Scans queue of items that methods have suggested that we forget about
2227 *
2228 * no return value
2229 */
2230static void bmi_check_forget_list(void)
2231{
2232    BMI_addr_t tmp_addr;
2233    struct forget_item* tmp_item;
2234    ref_st_p tmp_ref = NULL;
2235   
2236    gen_mutex_lock(&forget_list_mutex);
2237    while(!qlist_empty(&forget_list))
2238    {
2239        tmp_item = qlist_entry(forget_list.next, struct forget_item,
2240            link);     
2241        qlist_del(&tmp_item->link);
2242        /* item is off of the list; unlock for a moment while we work on
2243         * this addr
2244         */
2245        gen_mutex_unlock(&forget_list_mutex);
2246        tmp_addr = tmp_item->addr;
2247        free(tmp_item);
2248
2249        gen_mutex_lock(&ref_mutex);
2250        tmp_ref = ref_list_search_addr(cur_ref_list, tmp_addr);
2251        if(tmp_ref && tmp_ref->ref_count == 0)
2252        {
2253            bmi_addr_drop(tmp_ref);
2254        }   
2255        gen_mutex_unlock(&ref_mutex);
2256
2257        gen_mutex_lock(&forget_list_mutex);
2258    }
2259    gen_mutex_unlock(&forget_list_mutex);
2260
2261    return;
2262}
2263
2264/* bmi_addr_drop
2265 *
2266 * Destroys a complete BMI address, including asking the method to clean up
2267 * its portion.  Will query the method for permission before proceeding
2268 *
2269 * NOTE: must be called with ref list mutex held
2270 */
2271static void bmi_addr_drop(ref_st_p tmp_ref)
2272{
2273    struct method_drop_addr_query query;
2274    query.response = 0;
2275    query.addr = tmp_ref->method_addr;
2276    int ret = 0;
2277
2278    /* reference count is zero; ask module if it wants us to discard
2279     * the address; TCP will tell us to drop addresses for which the
2280     * socket has died with no possibility of reconnect
2281     */
2282    ret = tmp_ref->interface->get_info(BMI_DROP_ADDR_QUERY,
2283        &query);
2284    if(ret == 0 && query.response == 1)
2285    {
2286        /* kill the address */
2287        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
2288            "[BMI CONTROL]: %s: bmi discarding address: %llu\n",
2289            __func__, llu(tmp_ref->bmi_addr));
2290        ref_list_rem(cur_ref_list, tmp_ref->bmi_addr);
2291        /* NOTE: this triggers request to module to free underlying
2292         * resources if it wants to
2293         */
2294        dealloc_ref_st(tmp_ref);
2295    }
2296    return;
2297}
2298
2299
2300/* bmi_addr_force_drop
2301 *
2302 * Destroys a complete BMI address, including forcing the method to clean up
2303 * its portion.
2304 *
2305 * NOTE: must be called with ref list mutex held
2306 */
2307static void bmi_addr_force_drop(ref_st_p ref, ref_list_p ref_list)
2308{
2309    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
2310                 "[BMI CONTROL]: %s: bmi discarding address: %llu\n",
2311                 __func__, llu(ref->bmi_addr));
2312
2313    ref_list_rem(ref_list, ref->bmi_addr);
2314    dealloc_ref_st(ref);
2315
2316    return;
2317}
2318
2319/*
2320 * bmi_check_addr_force_drop
2321 *
2322 * Checks to see if any method has requested freeing resources.
2323 */
2324static void bmi_check_addr_force_drop (void)
2325{
2326    struct drop_item *drop_item = NULL;
2327    ref_st_p          ref_item = NULL;
2328
2329    gen_mutex_lock(&bmi_addr_force_drop_list_mutex);
2330    while (!qlist_empty(&bmi_addr_force_drop_list))
2331    {
2332        drop_item = qlist_entry(qlist_pop(&bmi_addr_force_drop_list),
2333                                struct drop_item,
2334                                link);
2335        gen_mutex_unlock(&bmi_addr_force_drop_list_mutex);
2336        gen_mutex_lock(&ref_mutex);
2337        qlist_for_each_entry(ref_item, cur_ref_list, list_link)
2338        {
2339             if ((ref_item->ref_count == 0) &&
2340                 (ref_item->interface->method_name == drop_item->method_name))
2341             {
2342                 bmi_addr_force_drop(ref_item, cur_ref_list);
2343             }
2344        }
2345        gen_mutex_unlock(&ref_mutex);
2346        gen_mutex_lock(&bmi_addr_force_drop_list_mutex);
2347    }
2348    gen_mutex_unlock(&bmi_addr_force_drop_list_mutex);
2349
2350    return;
2351}
2352
2353/*
2354 * Local variables:
2355 *  c-indent-level: 4
2356 *  c-basic-offset: 4
2357 * End:
2358 *
2359 * vim: ts=8 sts=4 sw=4 expandtab
2360 */
Note: See TracBrowser for help on using the browser.