root/branches/cu-security-branch/src/io/bmi/bmi.c @ 8397

Revision 8397, 60.7 KB (checked in by nlmills, 3 years ago)

initial merge with Orange-Branch. much will be broken

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    /* initialize buffer, if not NULL. */
1238    if (new_buffer)
1239    {
1240       memset(new_buffer,0,size);
1241    }
1242    return (new_buffer);
1243}
1244
1245/** Frees memory that was allocated with BMI_memalloc().
1246 *
1247 *  \return 0 on success, -errno on failure.
1248 */
1249int BMI_memfree(BMI_addr_t addr,
1250                void *buffer,
1251                bmi_size_t size,
1252                enum bmi_op_type send_recv)
1253{
1254    ref_st_p tmp_ref = NULL;
1255    int ret = -1;
1256
1257    /* find a reference that matches this address */
1258    gen_mutex_lock(&ref_mutex);
1259    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1260    if (!tmp_ref)
1261    {
1262        gen_mutex_unlock(&ref_mutex);
1263        return (bmi_errno_to_pvfs(-EINVAL));
1264    }
1265    gen_mutex_unlock(&ref_mutex);
1266
1267    /* free the memory */
1268    ret = tmp_ref->interface->memfree(buffer, size, send_recv);
1269
1270    return (ret);
1271}
1272
1273/** Acknowledge that an unexpected message has been
1274 * serviced that was returned from BMI_test_unexpected().
1275 *
1276 *  \return 0 on success, -errno on failure.
1277 */
1278int BMI_unexpected_free(BMI_addr_t addr,
1279                void *buffer)
1280{
1281    ref_st_p tmp_ref = NULL;
1282    int ret = -1;
1283
1284    /* find a reference that matches this address */
1285    gen_mutex_lock(&ref_mutex);
1286    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1287    if (!tmp_ref)
1288    {
1289        gen_mutex_unlock(&ref_mutex);
1290        return (bmi_errno_to_pvfs(-EINVAL));
1291    }
1292    gen_mutex_unlock(&ref_mutex);
1293
1294    if (!tmp_ref->interface->unexpected_free)
1295    {
1296        gossip_err("unimplemented unexpected_free callback\n");
1297        return bmi_errno_to_pvfs(-EOPNOTSUPP);
1298    }
1299    /* free the memory */
1300    ret = tmp_ref->interface->unexpected_free(buffer);
1301
1302    return (ret);
1303}
1304
1305/** Pass in optional parameters.
1306 *
1307 *  \return 0 on success, -errno on failure.
1308 */
1309int BMI_set_info(BMI_addr_t addr,
1310                 int option,
1311                 void *inout_parameter)
1312{
1313    int ret = -1;
1314    int i = 0;
1315    ref_st_p tmp_ref = NULL;
1316
1317    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1318                 "[BMI CONTROL]: %s: set_info: %llu option: %d\n",
1319                 __func__, llu(addr), option);
1320    /* if the addr is NULL, then the set_info should apply to all
1321     * available methods.
1322     */
1323    if (!addr)
1324    {
1325        if (!active_method_table)
1326        {
1327            return (bmi_errno_to_pvfs(-EINVAL));
1328        }
1329        gen_mutex_lock(&active_method_count_mutex);
1330        for (i = 0; i < active_method_count; i++)
1331        {
1332            ret = active_method_table[i]->set_info(
1333                option, inout_parameter);
1334            /* we bail out if even a single set_info fails */
1335            if (ret < 0)
1336            {
1337                gossip_lerr(
1338                    "Error: failure on set_info to method: %d\n", i);
1339                gen_mutex_unlock(&active_method_count_mutex);
1340                return (ret);
1341            }
1342        }
1343        gen_mutex_unlock(&active_method_count_mutex);
1344        return (0);
1345    }
1346
1347    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1348                 "[BMI CONTROL]: %s: searching for ref %llu\n",
1349                 __func__, llu(addr));
1350    /* find a reference that matches this address */
1351    gen_mutex_lock(&ref_mutex);
1352    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1353    if (!tmp_ref)
1354    {
1355        gen_mutex_unlock(&ref_mutex);
1356        return (bmi_errno_to_pvfs(-EINVAL));
1357    }
1358
1359    /* shortcut address reference counting */
1360    if(option == BMI_INC_ADDR_REF)
1361    {
1362        tmp_ref->ref_count++;
1363        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1364                     "[BMI CONTROL]: %s: incremented ref %llu to: %d\n",
1365                     __func__, llu(addr), tmp_ref->ref_count);
1366        gen_mutex_unlock(&ref_mutex);
1367        return(0);
1368    }
1369    if(option == BMI_DEC_ADDR_REF)
1370    {
1371        tmp_ref->ref_count--;
1372        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1373                     "[BMI CONTROL]: %s: decremented ref %llu to: %d\n",
1374                     __func__, llu(addr), tmp_ref->ref_count);
1375        assert(tmp_ref->ref_count >= 0);
1376
1377        if(tmp_ref->ref_count == 0)
1378        {
1379            bmi_addr_drop(tmp_ref);
1380        }
1381        gen_mutex_unlock(&ref_mutex);
1382        return(0);
1383    }
1384
1385    /* if the caller requests a TCP specific close socket action */
1386    if (option == BMI_TCP_CLOSE_SOCKET)
1387    {
1388        /* check to see if the address is in fact a tcp address */
1389        if(strcmp(tmp_ref->interface->method_name, "bmi_tcp") == 0)
1390        {
1391            /* take the same action as in the BMI_DEC_ADDR_REF case to clean
1392             * out the entire address structure and anything linked to it so
1393             * that the next addr_lookup starts from scratch
1394             */
1395            gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1396                         "[BMI CONTROL]: %s: Closing bmi_tcp "
1397                         "connection at caller's request.\n",
1398                         __func__);
1399            ref_list_rem(cur_ref_list, addr);
1400            dealloc_ref_st(tmp_ref);
1401        }
1402        gen_mutex_unlock(&ref_mutex);
1403        return 0;
1404    }
1405
1406    gen_mutex_unlock(&ref_mutex);
1407
1408    ret = tmp_ref->interface->set_info(option, inout_parameter);
1409
1410    return (ret);
1411}
1412
1413/** Query for optional parameters.
1414 *
1415 *  \return 0 on success, -errno on failure.
1416 */
1417int BMI_get_info(BMI_addr_t addr,
1418                 int option,
1419                 void *inout_parameter)
1420{
1421    int i = 0;
1422    int maxsize = 0;
1423    int tmp_maxsize;
1424    int ret = 0;
1425    ref_st_p tmp_ref = NULL;
1426
1427    switch (option)
1428    {
1429        /* check to see if the interface is initialized */
1430    case BMI_CHECK_INIT:
1431        gen_mutex_lock(&active_method_count_mutex);
1432        if (active_method_count > 0)
1433        {
1434            gen_mutex_unlock(&active_method_count_mutex);
1435            return (0);
1436        }
1437        else
1438        {
1439            gen_mutex_unlock(&active_method_count_mutex);
1440            return (bmi_errno_to_pvfs(-ENETDOWN));
1441        }
1442    case BMI_CHECK_MAXSIZE:
1443        gen_mutex_lock(&active_method_count_mutex);
1444        for (i = 0; i < active_method_count; i++)
1445        {
1446            ret = active_method_table[i]->get_info(
1447                option, &tmp_maxsize);
1448            if (ret < 0)
1449            {
1450                return (ret);
1451            }
1452            if (i == 0)
1453            {
1454                maxsize = tmp_maxsize;
1455            }
1456            else
1457            {
1458                if (tmp_maxsize < maxsize)
1459                    maxsize = tmp_maxsize;
1460            }
1461            *((int *) inout_parameter) = maxsize;
1462        }
1463        gen_mutex_unlock(&active_method_count_mutex);
1464        break;
1465    case BMI_GET_METH_ADDR:
1466        gen_mutex_lock(&ref_mutex);
1467        tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1468        if(!tmp_ref)
1469        {
1470            gen_mutex_unlock(&ref_mutex);
1471            return (bmi_errno_to_pvfs(-EINVAL));
1472        }
1473        gen_mutex_unlock(&ref_mutex);
1474        *((void**) inout_parameter) = tmp_ref->method_addr;
1475        break;
1476    case BMI_GET_UNEXP_SIZE:
1477        gen_mutex_lock(&ref_mutex);
1478        tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1479        if(!tmp_ref)
1480        {
1481            gen_mutex_unlock(&ref_mutex);
1482            return (bmi_errno_to_pvfs(-EINVAL));
1483        }
1484        gen_mutex_unlock(&ref_mutex);
1485        ret = tmp_ref->interface->get_info(
1486            option, inout_parameter);
1487        if(ret < 0)
1488        {
1489            return ret;
1490        }
1491        break;
1492
1493    default:
1494        return (bmi_errno_to_pvfs(-ENOSYS));
1495    }
1496    return (0);
1497}
1498
1499/** Given a string representation of a host/network address and a BMI
1500 * address handle, return whether the BMI address handle is part of the wildcard
1501 * address range specified by the string.
1502 * \return 1 on success, -errno on failure and 0 if it is not part of
1503 * the specified range
1504 */
1505int BMI_query_addr_range (BMI_addr_t addr, const char *id_string, int netmask)
1506{
1507    int ret = -1;
1508    int i = 0, failed = 1;
1509    int provided_method_length = 0;
1510    char *ptr, *provided_method_name = NULL;
1511    ref_st_p tmp_ref = NULL;
1512
1513    if((strlen(id_string)+1) > BMI_MAX_ADDR_LEN)
1514    {
1515        return(bmi_errno_to_pvfs(-ENAMETOOLONG));
1516    }
1517    /* lookup the provided address */
1518    gen_mutex_lock(&ref_mutex);
1519    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
1520    if (!tmp_ref)
1521    {
1522        gen_mutex_unlock(&ref_mutex);
1523        return (bmi_errno_to_pvfs(-EPROTO));
1524    }
1525    gen_mutex_unlock(&ref_mutex);
1526
1527    ptr = strchr(id_string, ':');
1528    if (ptr == NULL)
1529    {
1530        return (bmi_errno_to_pvfs(-EINVAL));
1531    }
1532    ret = -EPROTO;
1533    provided_method_length = (unsigned long) ptr - (unsigned long) id_string;
1534    provided_method_name = (char *) calloc(provided_method_length + 1, sizeof(char));
1535    if (provided_method_name == NULL)
1536    {
1537        return bmi_errno_to_pvfs(-ENOMEM);
1538    }
1539    strncpy(provided_method_name, id_string, provided_method_length);
1540
1541    /* Now we will run through each method looking for one that
1542     * matches the specified wildcard address.
1543     */
1544    i = 0;
1545    gen_mutex_lock(&active_method_count_mutex);
1546    while (i < active_method_count)
1547    {
1548        const char *active_method_name = active_method_table[i]->method_name + 4;
1549        /* provided name matches this interface */
1550        if (!strncmp(active_method_name, provided_method_name, provided_method_length))
1551        {
1552            int (*meth_fnptr)(bmi_method_addr_p, const char *, int);
1553            failed = 0;
1554            if ((meth_fnptr = active_method_table[i]->query_addr_range) == NULL)
1555            {
1556                ret = -ENOSYS;
1557                gossip_lerr("Error: method doesn't implement querying address range/wildcards! Cannot implement FS export options!\n");
1558                failed = 1;
1559                break;
1560            }
1561            /* pass it into the specific bmi layer */
1562            ret = meth_fnptr(tmp_ref->method_addr, id_string, netmask);
1563            if (ret < 0)
1564                failed = 1;
1565            break;
1566        }
1567        i++;
1568    }
1569    gen_mutex_unlock(&active_method_count_mutex);
1570    free(provided_method_name);
1571    if (failed)
1572        return bmi_errno_to_pvfs(ret);
1573    return ret;
1574}
1575
1576/** Resolves the string representation of a host address into a BMI
1577 *  address handle.
1578 *
1579 *  \return 0 on success, -errno on failure.
1580 */
1581int BMI_addr_lookup(BMI_addr_t * new_addr,
1582                    const char *id_string)
1583{
1584
1585    ref_st_p new_ref = NULL;
1586    bmi_method_addr_p meth_addr = NULL;
1587    int ret = -1;
1588    int i = 0;
1589    int failed;
1590
1591    if((strlen(id_string)+1) > BMI_MAX_ADDR_LEN)
1592    {
1593        return(bmi_errno_to_pvfs(-ENAMETOOLONG));
1594    }
1595
1596    /* set the addr to zero in case we fail */
1597    *new_addr = 0;
1598
1599    /* First we want to check to see if this host has already been
1600     * discovered! */
1601    gen_mutex_lock(&ref_mutex);
1602    new_ref = ref_list_search_str(cur_ref_list, id_string);
1603    gen_mutex_unlock(&ref_mutex);
1604
1605    if (new_ref)
1606    {
1607        /* we found it. */
1608        *new_addr = new_ref->bmi_addr;
1609        return (0);
1610    }
1611
1612    /* Now we will run through each method looking for one that
1613     * responds successfully.  It is assumed that they are already
1614     * listed in order of preference
1615     */
1616    i = 0;
1617    gen_mutex_lock(&active_method_count_mutex);
1618    while ((i < active_method_count) &&
1619           !(meth_addr = active_method_table[i]->method_addr_lookup(id_string)))
1620    {
1621        i++;
1622    }
1623
1624    /* if not found, try to bring it up now */
1625    failed = 0;
1626    if (!meth_addr) {
1627        for (i=0; i<known_method_count; i++) {
1628            const char *name;
1629            /* only bother with those not active */
1630            int j;
1631            for (j=0; j<active_method_count; j++)
1632                if (known_method_table[i] == active_method_table[j])
1633                    break;
1634            if (j < active_method_count)
1635                continue;
1636
1637            /* well-known that mapping is "x" -> "bmi_x" */
1638            name = known_method_table[i]->method_name + 4;
1639            if (!strncmp(id_string, name, strlen(name))) {
1640                ret = activate_method(known_method_table[i]->method_name, 0, 0);
1641                if (ret < 0) {
1642                    failed = 1;
1643                    break;
1644                }
1645                meth_addr = known_method_table[i]->
1646                    method_addr_lookup(id_string);
1647                i = active_method_count - 1;  /* point at the new one */
1648                break;
1649            }
1650        }
1651    }
1652    gen_mutex_unlock(&active_method_count_mutex);
1653    if (failed)
1654        return bmi_errno_to_pvfs(ret);
1655
1656    /* make sure one was successful */
1657    if (!meth_addr)
1658    {
1659        return bmi_errno_to_pvfs(-ENOPROTOOPT);
1660    }
1661
1662    /* create a new reference for the addr */
1663    new_ref = alloc_ref_st();
1664    if (!new_ref)
1665    {
1666        ret = bmi_errno_to_pvfs(-ENOMEM);
1667        goto bmi_addr_lookup_failure;
1668    }
1669
1670    /* fill in the details */
1671    new_ref->method_addr = meth_addr;
1672    meth_addr->parent = new_ref;
1673    new_ref->id_string = (char *) malloc(strlen(id_string) + 1);
1674    if (!new_ref->id_string)
1675    {
1676        ret = bmi_errno_to_pvfs(errno);
1677        goto bmi_addr_lookup_failure;
1678    }
1679    strcpy(new_ref->id_string, id_string);
1680    new_ref->interface = active_method_table[i];
1681
1682    /* keep up with the reference and we are done */
1683    gen_mutex_lock(&ref_mutex);
1684    ref_list_add(cur_ref_list, new_ref);
1685    gen_mutex_unlock(&ref_mutex);
1686
1687    *new_addr = new_ref->bmi_addr;
1688    return (0);
1689
1690  bmi_addr_lookup_failure:
1691
1692    if (meth_addr)
1693    {
1694        active_method_table[i]->set_info(
1695            BMI_DROP_ADDR, meth_addr);
1696    }
1697
1698    if (new_ref)
1699    {
1700        dealloc_ref_st(new_ref);
1701    }
1702
1703    return (ret);
1704}
1705
1706
1707/** Similar to BMI_post_send(), except that the source buffer is
1708 *  replaced by a list of (possibly non contiguous) buffers.
1709 *
1710 *  \return 0 on success, 1 on immediate successful completion,
1711 *  -errno on failure.
1712 */
1713int BMI_post_send_list(bmi_op_id_t * id,
1714                       BMI_addr_t dest,
1715                       const void *const *buffer_list,
1716                       const bmi_size_t *size_list,
1717                       int list_count,
1718                       /* "total_size" is the sum of the size list */
1719                       bmi_size_t total_size,
1720                       enum bmi_buffer_type buffer_type,
1721                       bmi_msg_tag_t tag,
1722                       void *user_ptr,
1723                       bmi_context_id context_id,
1724                       bmi_hint hints)
1725{
1726    ref_st_p tmp_ref = NULL;
1727    int ret = -1;
1728
1729#ifndef GOSSIP_DISABLE_DEBUG
1730    int i;
1731
1732    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1733        "BMI_post_send_list: addr: %ld, count: %d, total_size: %ld, tag: %d\n",
1734        (long)dest, list_count, (long)total_size, (int)tag);
1735
1736    for(i=0; i<list_count; i++)
1737    {
1738        gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1739            "   element %d: offset: 0x%lx, size: %ld\n",
1740            i, (long)buffer_list[i], (long)size_list[i]);
1741    }
1742#endif
1743
1744    *id = 0;
1745
1746    gen_mutex_lock(&ref_mutex);
1747    tmp_ref = ref_list_search_addr(cur_ref_list, dest);
1748    if (!tmp_ref)
1749    {
1750        gen_mutex_unlock(&ref_mutex);
1751        return (bmi_errno_to_pvfs(-EPROTO));
1752    }
1753    gen_mutex_unlock(&ref_mutex);
1754
1755    if (tmp_ref->interface->post_send_list)
1756    {
1757        ret = tmp_ref->interface->post_send_list(
1758            id, tmp_ref->method_addr, buffer_list, size_list,
1759            list_count, total_size, buffer_type, tag, user_ptr,
1760            context_id, (PVFS_hint)hints);
1761
1762        return (ret);
1763    }
1764
1765    gossip_lerr("Error: method doesn't implement send_list.\n");
1766    gossip_lerr("Error: send_list emulation not yet available.\n");
1767
1768    return (bmi_errno_to_pvfs(-ENOSYS));
1769}
1770
1771
1772/** Similar to BMI_post_recv(), except that the dest buffer is
1773 *  replaced by a list of (possibly non contiguous) buffers
1774 *
1775 *  \param total_expected_size the sum of the size list.
1776 *  \param total_actual_size the aggregate amt that was received.
1777 *
1778 *  \return 0 on success, 1 on immediate successful completion,
1779 *  -errno on failure.
1780 */
1781int BMI_post_recv_list(bmi_op_id_t * id,
1782                       BMI_addr_t src,
1783                       void *const *buffer_list,
1784                       const bmi_size_t *size_list,
1785                       int list_count,
1786                       bmi_size_t total_expected_size,
1787                       bmi_size_t * total_actual_size,
1788                       enum bmi_buffer_type buffer_type,
1789                       bmi_msg_tag_t tag,
1790                       void *user_ptr,
1791                       bmi_context_id context_id,
1792                       bmi_hint hints)
1793{
1794    ref_st_p tmp_ref = NULL;
1795    int ret = -1;
1796
1797#ifndef GOSSIP_DISABLE_DEBUG
1798    int i;
1799
1800    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1801        "BMI_post_recv_list: addr: %ld, count: %d, total_size: %ld, tag: %d\n",
1802        (long)src, list_count, (long)total_expected_size, (int)tag);
1803
1804    for(i=0; i<list_count; i++)
1805    {
1806        gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1807            "   element %d: offset: 0x%lx, size: %ld\n",
1808            i, (long)buffer_list[i], (long)size_list[i]);
1809    }
1810#endif
1811
1812    *id = 0;
1813
1814    gen_mutex_lock(&ref_mutex);
1815    tmp_ref = ref_list_search_addr(cur_ref_list, src);
1816    if (!tmp_ref)
1817    {
1818        gen_mutex_unlock(&ref_mutex);
1819        return (bmi_errno_to_pvfs(-EPROTO));
1820    }
1821    gen_mutex_unlock(&ref_mutex);
1822
1823    if (tmp_ref->interface->post_recv_list)
1824    {
1825        ret = tmp_ref->interface->post_recv_list(
1826            id, tmp_ref->method_addr, buffer_list, size_list,
1827            list_count, total_expected_size, total_actual_size,
1828            buffer_type, tag, user_ptr, context_id, (PVFS_hint)hints);
1829
1830        return (ret);
1831    }
1832
1833    gossip_lerr("Error: method doesn't implement recv_list.\n");
1834    gossip_lerr("Error: recv_list emulation not yet available.\n");
1835
1836    return (bmi_errno_to_pvfs(-ENOSYS));
1837}
1838
1839
1840/** Similar to BMI_post_sendunexpected(), except that the source buffer is
1841 *  replaced by a list of (possibly non contiguous) buffers.
1842 *
1843 *  \param total_size the sum of the size list.
1844 *
1845 *  \return 0 on success, 1 on immediate successful completion,
1846 *  -errno on failure.
1847 */
1848int BMI_post_sendunexpected_list(bmi_op_id_t * id,
1849                                 BMI_addr_t dest,
1850                                 const void *const *buffer_list,
1851                                 const bmi_size_t *size_list,
1852                                 int list_count,
1853                                 bmi_size_t total_size,
1854                                 enum bmi_buffer_type buffer_type,
1855                                 bmi_msg_tag_t tag,
1856                                 void *user_ptr,
1857                                 bmi_context_id context_id,
1858                                 bmi_hint hints)
1859{
1860    ref_st_p tmp_ref = NULL;
1861    int ret = -1;
1862
1863#ifndef GOSSIP_DISABLE_DEBUG
1864    int i;
1865
1866    gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1867        "BMI_post_sendunexpected_list: addr: %ld, count: %d, "
1868                 "total_size: %ld, tag: %d\n",  (long)dest, list_count,
1869                 (long)total_size, (int)tag);
1870
1871    for(i=0; i<list_count; i++)
1872    {
1873        gossip_debug(GOSSIP_BMI_DEBUG_OFFSETS,
1874            "   element %d: offset: 0x%lx, size: %ld\n",
1875            i, (long)buffer_list[i], (long)size_list[i]);
1876    }
1877#endif
1878
1879    *id = 0;
1880
1881    gen_mutex_lock(&ref_mutex);
1882    tmp_ref = ref_list_search_addr(cur_ref_list, dest);
1883    if (!tmp_ref)
1884    {
1885        gen_mutex_unlock(&ref_mutex);
1886        return (bmi_errno_to_pvfs(-EPROTO));
1887    }
1888    gen_mutex_unlock(&ref_mutex);
1889
1890    if (tmp_ref->interface->post_send_list)
1891    {
1892        ret = tmp_ref->interface->post_sendunexpected_list(
1893            id, tmp_ref->method_addr, buffer_list, size_list,
1894            list_count, total_size, buffer_type, tag, user_ptr,
1895            context_id, (PVFS_hint)hints);
1896
1897        return (ret);
1898    }
1899
1900    gossip_lerr("Error: method doesn't implement sendunexpected_list.\n");
1901    gossip_lerr("Error: send_list emulation not yet available.\n");
1902
1903    return (bmi_errno_to_pvfs(-ENOSYS));
1904}
1905
1906
1907/** Attempts to cancel a pending operation that has not yet completed.
1908 *  Caller must still test to gather error code after calling this
1909 *  function even if it returns 0.
1910 *
1911 *  \return 0 on success, -errno on failure.
1912 */
1913int BMI_cancel(bmi_op_id_t id,
1914               bmi_context_id context_id)
1915{
1916    struct method_op *target_op = NULL;
1917    int ret = -1;
1918
1919    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
1920                 "%s: cancel id %llu\n", __func__, llu(id));
1921
1922    target_op = id_gen_fast_lookup(id);
1923    if(target_op == NULL)
1924    {
1925        /* if we can't find the operation, then assume it has already
1926         * completed naturally.
1927         */
1928        return(0);
1929    }
1930
1931    assert(target_op->op_id == id);
1932
1933    if(active_method_table[target_op->addr->method_type]->cancel)
1934    {
1935        ret = active_method_table[
1936            target_op->addr->method_type]->cancel(
1937                id, context_id);
1938    }
1939    else
1940    {
1941        gossip_err("Error: BMI_cancel() unimplemented "
1942                   "for this module.\n");
1943        ret = bmi_errno_to_pvfs(-ENOSYS);
1944    }
1945
1946    return (ret);
1947}
1948
1949/**************************************************************
1950 * method callback functions
1951 */
1952
1953/* bmi_method_addr_reg_callback()
1954 *
1955 * Used by the methods to register new addresses when they are
1956 * discovered.  Only call this method when the device gets an
1957 * unexpected receive from a new peer, i.e., if you do the equivalent
1958 * of a socket accept() and get a new connection.
1959 *
1960 * Do not call this function for active lookups, that is from your
1961 * method_addr_lookup.  BMI already knows about the address in
1962 * this case, since the user provided it.
1963 *
1964 * returns 0 on success, -errno on failure
1965 */
1966BMI_addr_t bmi_method_addr_reg_callback(bmi_method_addr_p map)
1967{
1968    ref_st_p new_ref = NULL;
1969
1970    /* NOTE: we are trusting the method to make sure that we really
1971     * don't know about the address yet.  No verification done here.
1972     */
1973
1974    /* create a new reference structure */
1975    new_ref = alloc_ref_st();
1976    if (!new_ref)
1977    {
1978        return 0;
1979    }
1980
1981    /*
1982      fill in the details; we don't have an id string for this one.
1983    */
1984    new_ref->method_addr = map;
1985    new_ref->id_string = NULL;
1986    map->parent = new_ref;
1987
1988    /* check the method_type from the method_addr pointer to know
1989     * which interface to use */
1990    new_ref->interface = active_method_table[map->method_type];
1991
1992    /* add the reference structure to the list */
1993    ref_list_add(cur_ref_list, new_ref);
1994
1995    return new_ref->bmi_addr;
1996}
1997
1998int bmi_method_addr_forget_callback(BMI_addr_t addr)
1999{
2000    struct forget_item* tmp_item = NULL;
2001
2002    tmp_item = (struct forget_item*)malloc(sizeof(struct forget_item));
2003    if(!tmp_item)
2004    {
2005        return(bmi_errno_to_pvfs(-ENOMEM));
2006    }
2007
2008    tmp_item->addr = addr;
2009
2010    /* add to queue of items that we want the BMI control layer to consider
2011     * deallocating
2012     */
2013    gen_mutex_lock(&forget_list_mutex);
2014    qlist_add(&tmp_item->link, &forget_list);
2015    gen_mutex_unlock(&forget_list_mutex);
2016
2017    return (0);
2018}
2019
2020/*
2021 * Signal BMI to drop inactive connections for this method.
2022 */
2023void bmi_method_addr_drop_callback (char* method_name)
2024{
2025    struct drop_item *item =
2026        (struct drop_item *) malloc(sizeof(struct drop_item));
2027
2028    /*
2029     * If we can't allocate, just return.
2030     * Maybe this will succeed next time.
2031     */
2032    if (!item) return;
2033
2034    item->method_name = method_name;
2035   
2036    gen_mutex_lock(&bmi_addr_force_drop_list_mutex);
2037    qlist_add(&item->link, &bmi_addr_force_drop_list);
2038    gen_mutex_unlock(&bmi_addr_force_drop_list_mutex);
2039
2040    return;
2041}
2042
2043
2044/**
2045 * Try to increase method_usage_t struct to include room for a new method.
2046 */
2047static int grow_method_usage (struct method_usage_t ** p, int newflags)
2048{
2049    struct method_usage_t * x = *p;
2050    *p = malloc((active_method_count + 1) * sizeof(**p));
2051    if (!*p) {
2052        *p = x;
2053        return 0;
2054    }
2055    if (active_method_count) {
2056        memcpy(*p, x, active_method_count * sizeof(**p));
2057        free(x);
2058    }
2059    memset(&((*p)[active_method_count]), 0, sizeof(**p));
2060    (*p)[active_method_count].flags = newflags;
2061
2062    return 1;
2063 }
2064
2065/*
2066 * Attempt to insert this name into the list of active methods,
2067 * and bring it up.
2068 * NOTE: assumes caller has protected active_method_count with a mutex lock
2069 */
2070static int
2071activate_method(const char *name, const char *listen_addr, int flags)
2072{
2073    int i, ret;
2074    void *x;
2075    struct bmi_method_ops *meth;
2076    bmi_method_addr_p new_addr;
2077
2078    /* already active? */
2079    for (i=0; i<active_method_count; i++)
2080        if (!strcmp(active_method_table[i]->method_name, name)) break;
2081    if (i < active_method_count)
2082    {
2083        return 0;
2084    }
2085
2086    /* is the method known? */
2087    for (i=0; i<known_method_count; i++)
2088        if (!strcmp(known_method_table[i]->method_name, name)) break;
2089    if (i == known_method_count) {
2090        gossip_lerr("Error: no method available for %s.\n", name);
2091        return -ENOPROTOOPT;
2092    }
2093    meth = known_method_table[i];
2094
2095    /*
2096     * Later: try to load a dynamic module, growing the known method
2097     * table and search it again.
2098     */
2099
2100    /* toss it into the active table */
2101    x = active_method_table;
2102    active_method_table = malloc(
2103        (active_method_count + 1) * sizeof(*active_method_table));
2104    if (!active_method_table) {
2105        active_method_table = x;
2106        return -ENOMEM;
2107    }
2108    if (active_method_count) {
2109        memcpy(active_method_table, x,
2110            active_method_count * sizeof(*active_method_table));
2111        free(x);
2112    }
2113    active_method_table[active_method_count] = meth;
2114
2115    if (!grow_method_usage (&unexpected_method_usage, meth->flags))
2116       return -ENOMEM;
2117
2118    /**
2119     * If we run out of memory here, the unexpected_method_usage will be
2120     * larger than strictly required but there is no memory leak.
2121     */
2122
2123    if (!grow_method_usage (&expected_method_usage, meth->flags))
2124       return -ENOMEM;
2125
2126    ++active_method_count;
2127
2128    /* initialize it */
2129    new_addr = 0;
2130    if (listen_addr) {
2131        new_addr = meth->method_addr_lookup(listen_addr);
2132        if (!new_addr) {
2133            gossip_err(
2134                "Error: failed to lookup listen address %s for method %s.\n",
2135                listen_addr, name);
2136            --active_method_count;
2137            return -EINVAL;
2138        }
2139        /* this is a bit of a hack */
2140        new_addr->method_type = active_method_count - 1;
2141    }
2142    ret = meth->initialize(new_addr, active_method_count - 1, flags);
2143    if (ret < 0) {
2144        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
2145          "failed to initialize method %s.\n", name);
2146        --active_method_count;
2147        return ret;
2148    }
2149
2150    /* tell it about any open contexts */
2151    for (i=0; i<BMI_MAX_CONTEXTS; i++)
2152        if (context_array[i]) {
2153            ret = meth->open_context(i);
2154            if (ret < 0)
2155                break;
2156        }
2157
2158    return ret;
2159}
2160
2161 
2162int bmi_errno_to_pvfs(int error)
2163{
2164    int bmi_errno = error;
2165
2166#define __CASE(err)                      \
2167case -err: bmi_errno = -BMI_##err; break;\
2168case err: bmi_errno = BMI_##err; break
2169
2170    switch(error)
2171    {
2172        __CASE(EPERM);
2173        __CASE(ENOENT);
2174        __CASE(EINTR);
2175        __CASE(EIO);
2176        __CASE(ENXIO);
2177        __CASE(EBADF);
2178        __CASE(EAGAIN);
2179        __CASE(ENOMEM);
2180        __CASE(EFAULT);
2181        __CASE(EBUSY);
2182        __CASE(EEXIST);
2183        __CASE(ENODEV);
2184        __CASE(ENOTDIR);
2185        __CASE(EISDIR);
2186        __CASE(EINVAL);
2187        __CASE(EMFILE);
2188        __CASE(EFBIG);
2189        __CASE(ENOSPC);
2190        __CASE(EROFS);
2191        __CASE(EMLINK);
2192        __CASE(EPIPE);
2193        __CASE(EDEADLK);
2194        __CASE(ENAMETOOLONG);
2195        __CASE(ENOLCK);
2196        __CASE(ENOSYS);
2197        __CASE(ENOTEMPTY);
2198        __CASE(ELOOP);
2199        __CASE(ENOMSG);
2200        __CASE(ENODATA);
2201        __CASE(ETIME);
2202        __CASE(EREMOTE);
2203        __CASE(EPROTO);
2204        __CASE(EBADMSG);
2205        __CASE(EOVERFLOW);
2206        __CASE(EMSGSIZE);
2207        __CASE(EPROTOTYPE);
2208        __CASE(ENOPROTOOPT);
2209        __CASE(EPROTONOSUPPORT);
2210        __CASE(EOPNOTSUPP);
2211        __CASE(EADDRINUSE);
2212        __CASE(EADDRNOTAVAIL);
2213        __CASE(ENETDOWN);
2214        __CASE(ENETUNREACH);
2215        __CASE(ENETRESET);
2216        __CASE(ENOBUFS);
2217        __CASE(ETIMEDOUT);
2218        __CASE(ECONNREFUSED);
2219        __CASE(EHOSTDOWN);
2220        __CASE(EHOSTUNREACH);
2221        __CASE(EALREADY);
2222        __CASE(EACCES);
2223        __CASE(ECONNRESET);
2224#undef __CASE
2225    }
2226    return bmi_errno;
2227}
2228
2229/* bmi_check_forget_list()
2230 *
2231 * Scans queue of items that methods have suggested that we forget about
2232 *
2233 * no return value
2234 */
2235static void bmi_check_forget_list(void)
2236{
2237    BMI_addr_t tmp_addr;
2238    struct forget_item* tmp_item;
2239    ref_st_p tmp_ref = NULL;
2240   
2241    gen_mutex_lock(&forget_list_mutex);
2242    while(!qlist_empty(&forget_list))
2243    {
2244        tmp_item = qlist_entry(forget_list.next, struct forget_item,
2245            link);     
2246        qlist_del(&tmp_item->link);
2247        /* item is off of the list; unlock for a moment while we work on
2248         * this addr
2249         */
2250        gen_mutex_unlock(&forget_list_mutex);
2251        tmp_addr = tmp_item->addr;
2252        free(tmp_item);
2253
2254        gen_mutex_lock(&ref_mutex);
2255        tmp_ref = ref_list_search_addr(cur_ref_list, tmp_addr);
2256        if(tmp_ref && tmp_ref->ref_count == 0)
2257        {
2258            bmi_addr_drop(tmp_ref);
2259        }   
2260        gen_mutex_unlock(&ref_mutex);
2261
2262        gen_mutex_lock(&forget_list_mutex);
2263    }
2264    gen_mutex_unlock(&forget_list_mutex);
2265
2266    return;
2267}
2268
2269/* bmi_addr_drop
2270 *
2271 * Destroys a complete BMI address, including asking the method to clean up
2272 * its portion.  Will query the method for permission before proceeding
2273 *
2274 * NOTE: must be called with ref list mutex held
2275 */
2276static void bmi_addr_drop(ref_st_p tmp_ref)
2277{
2278    struct method_drop_addr_query query;
2279    query.response = 0;
2280    query.addr = tmp_ref->method_addr;
2281    int ret = 0;
2282
2283    /* reference count is zero; ask module if it wants us to discard
2284     * the address; TCP will tell us to drop addresses for which the
2285     * socket has died with no possibility of reconnect
2286     */
2287    ret = tmp_ref->interface->get_info(BMI_DROP_ADDR_QUERY,
2288        &query);
2289    if(ret == 0 && query.response == 1)
2290    {
2291        /* kill the address */
2292        gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
2293            "[BMI CONTROL]: %s: bmi discarding address: %llu\n",
2294            __func__, llu(tmp_ref->bmi_addr));
2295        ref_list_rem(cur_ref_list, tmp_ref->bmi_addr);
2296        /* NOTE: this triggers request to module to free underlying
2297         * resources if it wants to
2298         */
2299        dealloc_ref_st(tmp_ref);
2300    }
2301    return;
2302}
2303
2304
2305/* bmi_addr_force_drop
2306 *
2307 * Destroys a complete BMI address, including forcing the method to clean up
2308 * its portion.
2309 *
2310 * NOTE: must be called with ref list mutex held
2311 */
2312static void bmi_addr_force_drop(ref_st_p ref, ref_list_p ref_list)
2313{
2314    gossip_debug(GOSSIP_BMI_DEBUG_CONTROL,
2315                 "[BMI CONTROL]: %s: bmi discarding address: %llu\n",
2316                 __func__, llu(ref->bmi_addr));
2317
2318    ref_list_rem(ref_list, ref->bmi_addr);
2319    dealloc_ref_st(ref);
2320
2321    return;
2322}
2323
2324/*
2325 * bmi_check_addr_force_drop
2326 *
2327 * Checks to see if any method has requested freeing resources.
2328 */
2329static void bmi_check_addr_force_drop (void)
2330{
2331    struct drop_item *drop_item = NULL;
2332    ref_st_p          ref_item = NULL;
2333
2334    gen_mutex_lock(&bmi_addr_force_drop_list_mutex);
2335    while (!qlist_empty(&bmi_addr_force_drop_list))
2336    {
2337        drop_item = qlist_entry(qlist_pop(&bmi_addr_force_drop_list),
2338                                struct drop_item,
2339                                link);
2340        gen_mutex_unlock(&bmi_addr_force_drop_list_mutex);
2341        gen_mutex_lock(&ref_mutex);
2342        qlist_for_each_entry(ref_item, cur_ref_list, list_link)
2343        {
2344             if ((ref_item->ref_count == 0) &&
2345                 (ref_item->interface->method_name == drop_item->method_name))
2346             {
2347                 bmi_addr_force_drop(ref_item, cur_ref_list);
2348             }
2349        }
2350        gen_mutex_unlock(&ref_mutex);
2351        gen_mutex_lock(&bmi_addr_force_drop_list_mutex);
2352    }
2353    gen_mutex_unlock(&bmi_addr_force_drop_list_mutex);
2354
2355    return;
2356}
2357
2358/*
2359 * Local variables:
2360 *  c-indent-level: 4
2361 *  c-basic-offset: 4
2362 * End:
2363 *
2364 * vim: ts=8 sts=4 sw=4 expandtab
2365 */
Note: See TracBrowser for help on using the browser.