home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / io / bmi / bmi.c < prev    next >
C/C++ Source or Header  |  2010-04-30  |  62KB  |  2,366 lines

  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.  
  32. static int bmi_initialized_count = 0;
  33. static gen_mutex_t bmi_initialize_mutex = GEN_MUTEX_INITIALIZER;
  34.  
  35. /*
  36.  * List of BMI addrs currently managed.
  37.  */
  38. static ref_list_p cur_ref_list = NULL;
  39.  
  40. /* array to keep up with active contexts */
  41. static int context_array[BMI_MAX_CONTEXTS] = { 0 };
  42. static gen_mutex_t context_mutex = GEN_MUTEX_INITIALIZER;
  43. static gen_mutex_t ref_mutex = GEN_MUTEX_INITIALIZER;
  44.  
  45. static QLIST_HEAD(forget_list);
  46. static gen_mutex_t forget_list_mutex = GEN_MUTEX_INITIALIZER;
  47.  
  48. struct 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.  */
  57. static QLIST_HEAD(bmi_addr_force_drop_list);
  58. static gen_mutex_t bmi_addr_force_drop_list_mutex = GEN_MUTEX_INITIALIZER;
  59. struct 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__
  70. extern struct bmi_method_ops bmi_tcp_ops;
  71. #endif
  72. #ifdef __STATIC_METHOD_BMI_GM__
  73. extern struct bmi_method_ops bmi_gm_ops;
  74. #endif
  75. #ifdef __STATIC_METHOD_BMI_MX__
  76. extern struct bmi_method_ops bmi_mx_ops;
  77. #endif
  78. #ifdef __STATIC_METHOD_BMI_IB__
  79. extern struct bmi_method_ops bmi_ib_ops;
  80. #endif
  81. #ifdef __STATIC_METHOD_BMI_PORTALS__
  82. extern struct bmi_method_ops bmi_portals_ops;
  83. #endif
  84. #ifdef __STATIC_METHOD_BMI_ZOID__
  85. extern struct bmi_method_ops bmi_zoid_ops;
  86. #endif
  87.  
  88. static 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.  */
  115. static int known_method_count = 0;
  116. static 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.  */
  125. static int active_method_count = 0;
  126. static gen_mutex_t active_method_count_mutex = GEN_MUTEX_INITIALIZER;
  127.  
  128. static struct bmi_method_ops **active_method_table = NULL;
  129.  
  130. struct 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.  
  137. static struct method_usage_t * expected_method_usage = NULL;
  138. static struct method_usage_t * unexpected_method_usage = NULL;
  139.  
  140. static const int usage_iters_starvation = 100000;
  141. static const int usage_iters_active = 10000;
  142. static int global_flags;
  143.  
  144. static int activate_method(const char *name, const char *listen_addr,
  145.     int flags);
  146. static void bmi_addr_drop(ref_st_p tmp_ref);
  147. static void bmi_addr_force_drop(ref_st_p ref, ref_list_p ref_list);
  148. static void bmi_check_forget_list(void);
  149. static 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.  */
  162. int 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.  */
  370. int 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.  */
  519. int 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.  */
  567. int 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.  
  618. out:
  619.  
  620.     gen_mutex_unlock(&context_mutex);
  621.     return(ret);
  622. }
  623.  
  624.  
  625. /** Destroys a context previous generated with BMI_open_context().
  626.  */
  627. void 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.  */
  657. int 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.  */
  697. int 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.  */
  736. int 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.  */
  775. int 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.  */
  817. int 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.  */
  930. static void
  931. construct_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.  */
  984. int 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.  */
  1071. int 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.  */
  1160. const 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.  */
  1189. const 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.  */
  1217. void *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.  */
  1249. int 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.  */
  1278. int 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.  */
  1309. int 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.  */
  1417. int 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.  */
  1505. int 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.  */
  1581. int 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.  */
  1713. int 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.  */
  1781. int 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.  */
  1848. int 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.  */
  1913. int 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.  */
  1966. BMI_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.  
  1998. int 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.  */
  2023. void 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.  */
  2047. static 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.  */
  2070. static int
  2071. activate_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.  
  2162. int bmi_errno_to_pvfs(int error)
  2163. {
  2164.     int bmi_errno = error;
  2165.  
  2166. #define __CASE(err)                      \
  2167. case -err: bmi_errno = -BMI_##err; break;\
  2168. case 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.  */
  2235. static 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.  */
  2276. static 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.  */
  2312. static 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.  */
  2329. static 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.  */
  2366.