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 / server / pvfs2-server.c < prev    next >
C/C++ Source or Header  |  2010-10-26  |  89KB  |  2,702 lines

  1. /*
  2.  * (C) 2001 Clemson University and The University of Chicago
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.  
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include <unistd.h>
  13. #include <fcntl.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <signal.h>
  17. #include <assert.h>
  18. #include <getopt.h>
  19.  
  20. #ifdef __PVFS2_SEGV_BACKTRACE__
  21. #include <execinfo.h>
  22.  
  23. #ifndef __USE_GNU
  24. #define __USE_GNU
  25. #endif
  26.  
  27. #include <ucontext.h>
  28. #endif
  29.  
  30. #define __PINT_REQPROTO_ENCODE_FUNCS_C
  31.  
  32. #include "bmi.h"
  33. #include "gossip.h"
  34. #include "job.h"
  35. #include "trove.h"
  36. #include "pvfs2-debug.h"
  37. #include "pvfs2-storage.h"
  38. #include "PINT-reqproto-encode.h"
  39. #include "pvfs2-server.h"
  40. #include "state-machine.h"
  41. #include "mkspace.h"
  42. #include "server-config.h"
  43. #include "quicklist.h"
  44. #include "pint-dist-utils.h"
  45. #include "pint-perf-counter.h"
  46. #include "id-generator.h"
  47. #include "job-time-mgr.h"
  48. #include "pint-cached-config.h"
  49. #include "pvfs2-internal.h"
  50. #include "src/server/request-scheduler/request-scheduler.h"
  51. #include "pint-event.h"
  52. #include "pint-util.h"
  53.  
  54. #ifndef PVFS2_VERSION
  55. #define PVFS2_VERSION "Unknown"
  56. #endif
  57.  
  58. #ifdef __PVFS2_TROVE_THREADED__
  59. #ifdef __PVFS2_TROVE_AIO_THREADED__
  60. #define SERVER_STORAGE_MODE "aio-threaded"
  61. #else
  62. #define SERVER_STORAGE_MODE "threaded"
  63. #endif
  64. #else
  65. #define SERVER_STORAGE_MODE "non-threaded"
  66. #endif
  67.  
  68. #define PVFS2_VERSION_REQUEST 0xFF
  69.  
  70. /* this controls how many jobs we will test for per job_testcontext()
  71.  * call. NOTE: this is currently independent of the config file
  72.  * parameter that governs how many unexpected BMI jobs are kept posted
  73.  * at any given time
  74.  */
  75. #define PVFS_SERVER_TEST_COUNT 64
  76.  
  77. /* track performance counters for the server */
  78. static struct PINT_perf_key server_keys[] =
  79. {
  80.     {"bytes read", PINT_PERF_READ, 0},
  81.     {"bytes written", PINT_PERF_WRITE, 0},
  82.     {"metadata reads", PINT_PERF_METADATA_READ, PINT_PERF_PRESERVE},
  83.     {"metadata writes", PINT_PERF_METADATA_WRITE, PINT_PERF_PRESERVE},
  84.     {"metadata dspace ops", PINT_PERF_METADATA_DSPACE_OPS, PINT_PERF_PRESERVE},
  85.     {"metadata keyval ops", PINT_PERF_METADATA_KEYVAL_OPS, PINT_PERF_PRESERVE},
  86.     {"request scheduler", PINT_PERF_REQSCHED, PINT_PERF_PRESERVE},
  87.     {NULL, 0, 0},
  88. };
  89.  
  90. /* For the switch statement to know what interfaces to shutdown */
  91. static PINT_server_status_flag server_status_flag;
  92.  
  93. /* All parameters read in from the configuration file */
  94. static struct server_configuration_s server_config;
  95.  
  96. /* A flag to stop the main loop from processing and handle the signal
  97.  * after all threads complete and are no longer blocking.
  98.  */
  99. static int signal_recvd_flag = 0;
  100. static pid_t server_controlling_pid = 0;
  101.  
  102. static PINT_event_id PINT_sm_event_id;
  103.  
  104. /* A list of all serv_op's posted for unexpected message alone */
  105. QLIST_HEAD(posted_sop_list);
  106. /* A list of all serv_op's posted for expected messages alone */
  107. QLIST_HEAD(inprogress_sop_list);
  108. /* A list of all serv_op's that are started automatically without requests */
  109. static QLIST_HEAD(noreq_sop_list);
  110.  
  111. /* this is used externally by some server state machines */
  112. job_context_id server_job_context = -1;
  113.  
  114. typedef struct
  115. {
  116.     int server_remove_storage_space;
  117.     int server_create_storage_space;
  118.     int server_background;
  119.     char *pidfile;
  120.     char *server_alias;
  121. } options_t;
  122.  
  123. static options_t s_server_options = { 0, 0, 1, NULL, NULL};
  124. static char *fs_conf = NULL;
  125.  
  126. /* each of the elements in this array consists of a string and its length.
  127.  * we're able to use sizeof here because sizeof an inlined string ("") gives
  128.  * the length of the string with the null terminator
  129.  */
  130. PINT_server_trove_keys_s Trove_Common_Keys[] =
  131. {
  132.     {ROOT_HANDLE_KEYSTR, ROOT_HANDLE_KEYLEN},
  133.     {DIRECTORY_ENTRY_KEYSTR, DIRECTORY_ENTRY_KEYLEN},
  134.     {DATAFILE_HANDLES_KEYSTR, DATAFILE_HANDLES_KEYLEN},
  135.     {METAFILE_DIST_KEYSTR, METAFILE_DIST_KEYLEN},
  136.     {SYMLINK_TARGET_KEYSTR, SYMLINK_TARGET_KEYLEN},
  137.     {METAFILE_LAYOUT_KEYSTR, METAFILE_LAYOUT_KEYLEN},
  138.     {NUM_DFILES_REQ_KEYSTR, NUM_DFILES_REQ_KEYLEN}
  139. };
  140.  
  141. /* These three are used continuously in our wait loop.  They could be
  142.  * relatively large, so rather than allocate them on the stack, we'll
  143.  * make them dynamically allocated globals.
  144.  */
  145. static job_id_t *server_job_id_array = NULL;
  146. static void **server_completed_job_p_array = NULL;
  147. static job_status_s *server_job_status_array = NULL;
  148.  
  149. /* Prototypes for internal functions */
  150. static int server_initialize(
  151.     PINT_server_status_flag *server_status_flag,
  152.     job_status_s *job_status_structs);
  153. static int server_initialize_subsystems(
  154.     PINT_server_status_flag *server_status_flag);
  155. static int server_setup_signal_handlers(void);
  156. static int server_purge_unexpected_recv_machines(void);
  157. static int server_setup_process_environment(int background);
  158. static int server_shutdown(
  159.     PINT_server_status_flag status,
  160.     int ret, int sig);
  161. static void reload_config(void);
  162. static void server_sig_handler(int sig);
  163. static void hup_sighandler(int sig, siginfo_t *info, void *secret);
  164. static int server_parse_cmd_line_args(int argc, char **argv);
  165. #ifdef __PVFS2_SEGV_BACKTRACE__
  166. static void bt_sighandler(int sig, siginfo_t *info, void *secret);
  167. #endif
  168. static int create_pidfile(char *pidfile);
  169. static void write_pidfile(int fd);
  170. static void remove_pidfile(void);
  171. static int generate_shm_key_hint(int* server_index);
  172.  
  173. static void precreate_pool_finalize(void);
  174. static int precreate_pool_initialize(int server_index);
  175.  
  176. static int precreate_pool_setup_server(const char* host, PVFS_ds_type type,
  177.     PVFS_fs_id fsid, PVFS_handle* pool_handle);
  178. static int precreate_pool_launch_refiller(const char* host, PVFS_ds_type type, 
  179.     PVFS_BMI_addr_t addr, PVFS_fs_id fsid, PVFS_handle pool_handle);
  180. static int precreate_pool_count(
  181.     PVFS_fs_id fsid, PVFS_handle pool_handle, int* count);
  182.  
  183. static TROVE_method_id trove_coll_to_method_callback(TROVE_coll_id);
  184.  
  185.  
  186. struct server_configuration_s *PINT_get_server_config(void)
  187. {
  188.     return &server_config;
  189. }
  190.  
  191. int main(int argc, char **argv)
  192. {
  193.     int ret = -1, siglevel = 0;
  194.     struct PINT_smcb *tmp_op = NULL;
  195.     uint64_t debug_mask = 0;
  196.  
  197. #ifdef WITH_MTRACE
  198.     mtrace();
  199. #endif
  200.  
  201.     /* Passed to server shutdown function */
  202.     server_status_flag = SERVER_DEFAULT_INIT;
  203.  
  204.     /* Enable the gossip interface to send out stderr and set an
  205.      * initial debug mask so that we can output errors at startup.
  206.      */
  207.     gossip_enable_stderr();
  208.     gossip_set_debug_mask(1, GOSSIP_SERVER_DEBUG);
  209.  
  210.     server_status_flag |= SERVER_GOSSIP_INIT;
  211.  
  212.     /* Determine initial server configuration, looking at both command
  213.      * line arguments and the configuration file.
  214.      */
  215.     ret = server_parse_cmd_line_args(argc, argv);
  216.     if (ret == PVFS2_VERSION_REQUEST)
  217.     {
  218.         return 0;
  219.     }
  220.     else if (ret != 0)
  221.     {
  222.         goto server_shutdown;
  223.     }
  224.  
  225.     gossip_debug_fp(stderr, 'S', GOSSIP_LOGSTAMP_DATETIME,
  226.                     "PVFS2 Server on node %s version %s starting...\n",
  227.                     s_server_options.server_alias, PVFS2_VERSION);
  228.  
  229.     /* code to handle older two config file format */
  230.  
  231.     ret = PINT_parse_config(&server_config, fs_conf, s_server_options.server_alias);
  232.     if (ret)
  233.     {
  234.         gossip_err("Error: Please check your config files.\n");
  235.         gossip_err("Error: Server aborting.\n");
  236.         ret = -PVFS_EINVAL;
  237.         goto server_shutdown;
  238.     }
  239.  
  240.     server_status_flag |= SERVER_CONFIG_INIT;
  241.  
  242.     if (!PINT_config_is_valid_configuration(&server_config))
  243.     {
  244.         gossip_err("Error: Invalid configuration; aborting.\n");
  245.         ret = -PVFS_EINVAL;
  246.         goto server_shutdown;
  247.     }
  248.  
  249.     /* reset gossip debug mask based on configuration settings */
  250.     debug_mask = PVFS_debug_eventlog_to_mask(server_config.event_logging);
  251.     gossip_set_debug_mask(1, debug_mask);
  252.     gossip_set_logstamp(server_config.logstamp_type);
  253.     gossip_debug(GOSSIP_SERVER_DEBUG,"Logging %s (mask %llu)\n",
  254.                  server_config.event_logging, llu(debug_mask));
  255.  
  256.     /* remove storage space and exit if requested */
  257.     if (s_server_options.server_remove_storage_space)
  258.     {
  259.         ret = PINT_config_pvfs2_rmspace(&server_config);
  260.         if(ret < 0)
  261.         {
  262.             goto server_shutdown;
  263.         }
  264.         gossip_set_debug_mask(1, GOSSIP_SERVER_DEBUG);
  265.         gossip_debug(GOSSIP_SERVER_DEBUG, "PVFS2 Server: storage space removed. Exiting.\n");
  266.         gossip_set_debug_mask(1, debug_mask);
  267.         return(0);
  268.     }
  269.  
  270.     /* create storage space and exit if requested */
  271.     if (s_server_options.server_create_storage_space)
  272.     {
  273.         ret = PINT_config_pvfs2_mkspace(&server_config);
  274.         if(ret < 0)
  275.         {
  276.             goto server_shutdown;
  277.         }
  278.         gossip_set_debug_mask(1, GOSSIP_SERVER_DEBUG);
  279.         gossip_debug(GOSSIP_SERVER_DEBUG, "PVFS2 Server: storage space created. Exiting.\n");
  280.         gossip_set_debug_mask(1, debug_mask);
  281.         return(0);
  282.     }
  283.  
  284.     server_job_id_array = (job_id_t *)
  285.         malloc(PVFS_SERVER_TEST_COUNT * sizeof(job_id_t));
  286.     server_completed_job_p_array = (void **)
  287.         malloc(PVFS_SERVER_TEST_COUNT * sizeof(void *));
  288.     server_job_status_array = (job_status_s *)
  289.         malloc(PVFS_SERVER_TEST_COUNT * sizeof(job_status_s));
  290.  
  291.     if (!server_job_id_array ||
  292.         !server_completed_job_p_array ||
  293.         !server_job_status_array)
  294.     {
  295.         if (server_job_id_array)
  296.         {
  297.             free(server_job_id_array);
  298.             server_job_id_array = NULL;
  299.         }
  300.         if (server_completed_job_p_array)
  301.         {
  302.             free(server_completed_job_p_array);
  303.             server_completed_job_p_array = NULL;
  304.         }
  305.         if (server_job_status_array)
  306.         {
  307.             free(server_job_status_array);
  308.             server_job_status_array = NULL;
  309.         }
  310.         gossip_err("Error: failed to allocate arrays for "
  311.                    "tracking completed jobs.\n");
  312.         goto server_shutdown;
  313.     }
  314.     server_status_flag |= SERVER_JOB_OBJS_ALLOCATED;
  315.  
  316.     /* Initialize the server (many many steps) */
  317.     ret = server_initialize(&server_status_flag, server_job_status_array);
  318.     if (ret < 0)
  319.     {
  320.         gossip_err("Error: Could not initialize server; aborting.\n");
  321.         goto server_shutdown;
  322.     }
  323.  
  324. #ifndef __PVFS2_DISABLE_PERF_COUNTERS__
  325.     /* kick off performance update state machine */
  326.     ret = server_state_machine_alloc_noreq(PVFS_SERV_PERF_UPDATE,
  327.         &(tmp_op));
  328.     if (ret == 0)
  329.     {
  330.         ret = server_state_machine_start_noreq(tmp_op);
  331.     }
  332.     if (ret < 0)
  333.     {
  334.         PVFS_perror_gossip("Error: failed to start perf update "
  335.                     "state machine.\n", ret);
  336.         goto server_shutdown;
  337.     }
  338. #endif
  339.  
  340.     /* kick off timer for expired jobs */
  341.     ret = server_state_machine_alloc_noreq(
  342.         PVFS_SERV_JOB_TIMER, &(tmp_op));
  343.     if (ret == 0)
  344.     {
  345.         ret = server_state_machine_start_noreq(tmp_op);
  346.     }
  347.     if (ret < 0)
  348.     {
  349.         PVFS_perror_gossip("Error: failed to start job timer "
  350.                            "state machine.\n", ret);
  351.         goto server_shutdown;
  352.     }
  353.  
  354.     gossip_debug_fp(stderr, 'S', GOSSIP_LOGSTAMP_DATETIME,
  355.                     "PVFS2 Server ready.\n");
  356.  
  357.     /* Initialization complete; process server requests indefinitely. */
  358.     for ( ;; )  
  359.     {
  360.         int i, comp_ct = PVFS_SERVER_TEST_COUNT;
  361.  
  362.         if (signal_recvd_flag != 0)
  363.         {
  364.             /* If the signal is a SIGHUP, catch and reload configuration */
  365.             if (signal_recvd_flag == SIGHUP)
  366.             {
  367.                 reload_config();
  368.                 signal_recvd_flag = 0; /* Reset the flag */
  369.             }
  370.             else
  371.             {
  372.                 /*
  373.                  * If we received a signal and we have drained all the state
  374.                  * machines that were in progress, we initiate a shutdown of
  375.                  * the server. Find out if we can exit now * by checking if
  376.                  * all s_ops (for expected messages) have either finished or
  377.                  * timed out,
  378.                  */
  379.                 if (qlist_empty(&inprogress_sop_list))
  380.                 {
  381.                     ret = 0;
  382.                     siglevel = signal_recvd_flag;
  383.                     goto server_shutdown;
  384.                 }
  385.                 /* not completed. continue... */
  386.             }
  387.         }
  388.         ret = job_testcontext(server_job_id_array,
  389.                               &comp_ct,
  390.                               server_completed_job_p_array,
  391.                               server_job_status_array,
  392.                               PVFS2_SERVER_DEFAULT_TIMEOUT_MS,
  393.                               server_job_context);
  394.         if (ret < 0)
  395.         {
  396.             gossip_lerr("pvfs2-server panic; main loop aborting\n");
  397.             goto server_shutdown;
  398.         }
  399.  
  400.         /*
  401.           Loop through the completed jobs and handle whatever comes
  402.           next
  403.         */
  404.         for (i = 0; i < comp_ct; i++)
  405.         {
  406.             /* int unexpected_msg = 0; */
  407.             struct PINT_smcb *smcb = server_completed_job_p_array[i];
  408.  
  409.                /* NOTE: PINT_state_machine_next() is a function that
  410.                 * is shared with the client-side state machine
  411.                 * processing, so it is defined in the src/common
  412.                 * directory.
  413.                 */
  414.             ret = PINT_state_machine_continue(
  415.                     smcb, &server_job_status_array[i]);
  416.  
  417.             if (SM_ACTION_ISERR(ret)) /* ret < 0 */
  418.             {
  419.                 PVFS_perror_gossip("Error: state machine processing error", ret);
  420.                 ret = 0;
  421.             }
  422.  
  423.             /* else ret == SM_ACTION_DEFERED */
  424.         }
  425.     }
  426.  
  427.   server_shutdown:
  428.     server_shutdown(server_status_flag, ret, siglevel);
  429.     /* NOTE: the server_shutdown() function does not return; it always ends
  430.      * by calling exit.  This point in the code should never be reached.
  431.      */
  432.     return -1;
  433. }
  434.  
  435. /*
  436.  * Manipulate the pid file.  Don't bother returning an error in
  437.  * the write stage, since there's nothing that can be done about it.
  438.  */
  439. static int create_pidfile(char *pidfile)
  440. {
  441.     return open(pidfile, (O_CREAT | O_WRONLY | O_TRUNC), 0644);
  442. }
  443.  
  444. static void write_pidfile(int fd)
  445. {
  446.     pid_t pid = getpid();
  447.     char pid_str[16] = {0};
  448.     int len;
  449.     int ret;
  450.  
  451.     snprintf(pid_str, 16, "%d\n", pid);
  452.     len = strlen(pid_str);
  453.     ret = write(fd, pid_str, len);
  454.     if(ret < len)
  455.     {
  456.         gossip_err("Error: failed to write pid file.\n");
  457.         close(fd);
  458.         remove_pidfile();
  459.         return;
  460.     }
  461.     close(fd);
  462.     return;
  463. }
  464.  
  465. static void remove_pidfile(void)
  466. {
  467.     assert(s_server_options.pidfile);
  468.     unlink(s_server_options.pidfile);
  469. }
  470.  
  471. /* server_initialize()
  472.  *
  473.  * Handles:
  474.  * - backgrounding, redirecting logging
  475.  * - initializing all the subsystems (BMI, Trove, etc.)
  476.  * - setting up the state table used to map new requests to
  477.  *   state machines
  478.  * - allocating and posting the initial unexpected message jobs
  479.  * - setting up signal handlers
  480.  */
  481. static int server_initialize(
  482.     PINT_server_status_flag *server_status_flag,
  483.     job_status_s *job_status_structs)
  484. {
  485.     int ret = 0, i = 0; 
  486.     FILE *dummy;
  487.     uint64_t debug_mask = 0;
  488.     
  489.     assert(server_config.logfile != NULL);
  490.  
  491.     if(!strcmp(server_config.logtype, "file"))
  492.     {
  493.         dummy = fopen(server_config.logfile, "a");
  494.         if (dummy == NULL)
  495.         {
  496.             int tmp_errno = errno;
  497.             gossip_err("error opening log file %s\n",
  498.                     server_config.logfile);
  499.             return -tmp_errno;
  500.         }
  501.         fclose(dummy);
  502.     }
  503.  
  504.     /* redirect gossip to specified target if backgrounded */
  505.     if (s_server_options.server_background)
  506.     {
  507.         if(!freopen("/dev/null", "r", stdin))
  508.             gossip_err("Error: failed to reopen stdin.\n");
  509.         if(!freopen("/dev/null", "w", stdout))
  510.             gossip_err("Error: failed to reopen stdout.\n");
  511.         if(!freopen("/dev/null", "w", stderr))
  512.             gossip_err("Error: failed to reopen stderr.\n");
  513.  
  514.         if(!strcmp(server_config.logtype, "syslog"))
  515.         {
  516.             ret = gossip_enable_syslog(LOG_INFO);
  517.         }
  518.         else if(!strcmp(server_config.logtype, "file"))
  519.         {
  520.             ret = gossip_enable_file(server_config.logfile, "a");
  521.         }
  522.         else
  523.         {
  524.             ret = gossip_enable_stderr();
  525.         }
  526.  
  527.         if (ret < 0)
  528.         {
  529.             gossip_err("error opening log file %s\n",
  530.                         server_config.logfile);
  531.             return ret;
  532.         }
  533.         /* log starting message again so it appears in log file, not just
  534.          * console
  535.          */
  536.         gossip_set_debug_mask(1, GOSSIP_SERVER_DEBUG);
  537.         gossip_debug(GOSSIP_SERVER_DEBUG,
  538.            "PVFS2 Server version %s starting.\n", PVFS2_VERSION);
  539.         debug_mask = PVFS_debug_eventlog_to_mask(server_config.event_logging);
  540.         gossip_set_debug_mask(1, debug_mask);
  541.     }
  542.  
  543.     /* handle backgrounding, setting up working directory, and so on. */
  544.     ret = server_setup_process_environment(
  545.         s_server_options.server_background);
  546.     if (ret < 0)
  547.     {
  548.         gossip_err("Error: Could not start server; aborting.\n");
  549.         return ret;
  550.     }
  551.  
  552.     /* Initialize the bmi, flow, trove and job interfaces */
  553.     ret = server_initialize_subsystems(server_status_flag);
  554.     if (ret < 0)
  555.     {
  556.         gossip_err("Error: Could not initialize server interfaces; "
  557.                    "aborting.\n");
  558.         return ret;
  559.     }
  560.  
  561.     *server_status_flag |= SERVER_STATE_MACHINE_INIT;
  562.  
  563.     /* Post starting set of BMI unexpected msg buffers */
  564.     for (i = 0; i < server_config.initial_unexpected_requests; i++)
  565.     {
  566.         ret = server_post_unexpected_recv(&job_status_structs[i]);
  567.         if (ret < 0)
  568.         {
  569.             gossip_err("Error posting unexpected recv\n");
  570.             return ret;
  571.         }
  572.     }
  573.  
  574.     *server_status_flag |= SERVER_BMI_UNEXP_POST_INIT;
  575.  
  576.     ret = server_setup_signal_handlers();
  577.  
  578.     *server_status_flag |= SERVER_SIGNAL_HANDLER_INIT;
  579.  
  580.     gossip_debug(GOSSIP_SERVER_DEBUG,
  581.                  "Initialization completed successfully.\n");
  582.  
  583.     return ret;
  584. }
  585.  
  586. /* server_setup_process_environment()
  587.  *
  588.  * performs normal daemon initialization steps
  589.  *
  590.  * returns 0 on success, -PVFS_EINVAL on failure (details will be logged to
  591.  * gossip)
  592.  */
  593. static int server_setup_process_environment(int background)
  594. {
  595.     pid_t new_pid = 0;
  596.     int pid_fd = -1;
  597.  
  598.     /*
  599.      * Manage a pid file if requested (for init scripts).  Create
  600.      * the file in the parent before the chdir, but let the child
  601.      * write his pid and delete it when exiting.
  602.      */
  603.     if (s_server_options.pidfile)
  604.     {
  605.         pid_fd = create_pidfile(s_server_options.pidfile);
  606.         if (pid_fd < 0)
  607.         {
  608.             gossip_err("Failed to create pid file %s: %s\n",
  609.                        s_server_options.pidfile, strerror(errno));
  610.             return(-PVFS_EINVAL);
  611.         }
  612.     }
  613.  
  614.     if (chdir("/"))
  615.     {
  616.         gossip_err("cannot change working directory to \"/\" "
  617.                     "(errno = %x). aborting.\n", errno);
  618.         return(-PVFS_EINVAL);
  619.     }
  620.  
  621.     umask(0077);
  622.  
  623.     if (background)
  624.     {
  625.         new_pid = fork();
  626.         if (new_pid < 0)
  627.         {
  628.             gossip_err("error in fork() system call (errno = %x). "
  629.                         "aborting.\n", errno);
  630.             return(-PVFS_EINVAL);
  631.         }
  632.         else if (new_pid > 0)
  633.         {
  634.             /* exit parent */
  635.             exit(0);
  636.         }
  637.  
  638.         new_pid = setsid();
  639.         if (new_pid < 0)
  640.         {
  641.             gossip_err("error in setsid() system call.  aborting.\n");
  642.             return(-PVFS_EINVAL);
  643.         }
  644.     }
  645.     if (pid_fd >= 0)
  646.     {
  647.         /* note: pid_fd closed by write_pidfile() */
  648.         write_pidfile(pid_fd);
  649.         atexit(remove_pidfile);
  650.     }
  651.     server_controlling_pid = getpid();
  652.     return 0;
  653. }
  654.  
  655. /* server_initialize_subsystems()
  656.  *
  657.  * This:
  658.  * - initializes distribution subsystem
  659.  * - initializes encoding/decoding subsystem
  660.  * - initializes BMI
  661.  * - initializes Trove
  662.  *   - finds the collection IDs for all file systems
  663.  *   - gets a context from Trove
  664.  *   - tells Trove what handles are to be used
  665.  *     for each file system (collection)
  666.  * - initializes the flow subsystem
  667.  * - initializes the job subsystem
  668.  *   - gets a job context
  669.  * - initialize the request scheduler
  670.  */
  671. static int server_initialize_subsystems(
  672.     PINT_server_status_flag *server_status_flag)
  673. {
  674.     int ret = -PVFS_EINVAL;
  675.     char *cur_merged_handle_range = NULL;
  676.     PINT_llist *cur = NULL;
  677.     struct filesystem_configuration_s *cur_fs;
  678.     TROVE_context_id trove_context = -1;
  679.     char buf[16] = {0};
  680.     PVFS_fs_id orig_fsid=0;
  681.     PVFS_ds_flags init_flags = 0;
  682.     int bmi_flags = BMI_INIT_SERVER;
  683.     int shm_key_hint;
  684.     int server_index;
  685.  
  686.     if(server_config.enable_events)
  687.     {
  688.         ret = PINT_event_init(PINT_EVENT_TRACE_TAU);
  689.         if (ret < 0)
  690.         {
  691.             gossip_err("Error initializing event interface.\n");
  692.             return (ret);
  693.         }
  694.  
  695.         /* Define the state machine event:
  696.          *   START: (client_id, request_id, rank, handle, op_id)
  697.          *   STOP: ()
  698.          */
  699.         PINT_event_define_event(
  700.             NULL, "sm", "%d%d%d%llu%d", "", &PINT_sm_event_id);
  701.  
  702.         *server_status_flag |= SERVER_EVENT_INIT;
  703.     }
  704.  
  705.     /* Initialize distributions */
  706.     ret = PINT_dist_initialize(0);
  707.     if (ret < 0)
  708.     {
  709.         gossip_err("Error initializing distribution interface.\n");
  710.         return ret;
  711.     }
  712.     *server_status_flag |= SERVER_DIST_INIT;
  713.  
  714.     ret = PINT_encode_initialize();
  715.     if (ret < 0)
  716.     {
  717.         gossip_err("PINT_encode_initialize() failed.\n");
  718.         return ret;
  719.     }
  720.  
  721.     *server_status_flag |= SERVER_ENCODER_INIT;
  722.  
  723.     gossip_debug(GOSSIP_SERVER_DEBUG,
  724.                  "Passing %s as BMI listen address.\n",
  725.                  server_config.host_id);
  726.  
  727.     /* does the configuration dictate that we bind to a specific address? */
  728.     if(server_config.tcp_bind_specific)
  729.     {
  730.         bmi_flags |= BMI_TCP_BIND_SPECIFIC;
  731.     }
  732.  
  733.     /* Have bmi automatically increment reference count on addresses any
  734.      * time a new unexpected message appears.  The server will decrement it
  735.      * once it has completed processing related to that request.
  736.      */
  737.     bmi_flags |= BMI_AUTO_REF_COUNT;
  738.  
  739.     ret = BMI_initialize(server_config.bmi_modules, 
  740.                          server_config.host_id,
  741.                          bmi_flags);
  742.     if (ret < 0)
  743.     {
  744.         PVFS_perror_gossip("Error: BMI_initialize", ret);
  745.         return ret;
  746.     }
  747. #ifdef USE_TRUSTED
  748.     /* Pass the server_config file pointer to the lower
  749.      * levels for the trusted connections related functions to be
  750.      * called
  751.      */
  752.     BMI_set_info(0, BMI_TRUSTED_CONNECTION, (void *) &server_config);
  753.     gossip_debug(GOSSIP_SERVER_DEBUG, "Enabling trusted connections!\n");
  754. #endif
  755.     *server_status_flag |= SERVER_BMI_INIT;
  756.  
  757.     ret = trove_collection_setinfo(0, 0, TROVE_DB_CACHE_SIZE_BYTES,
  758.                                    &server_config.db_cache_size_bytes);
  759.     /* this should never fail */
  760.     assert(ret == 0);
  761.     ret = trove_collection_setinfo(0, 0, TROVE_MAX_CONCURRENT_IO,
  762.                                    &server_config.trove_max_concurrent_io);
  763.     /* this should never fail */
  764.     assert(ret == 0);
  765.  
  766.     /* help trove chose a differentiating shm key if needed for Berkeley DB */
  767.     shm_key_hint = generate_shm_key_hint(&server_index);
  768.     gossip_debug(GOSSIP_SERVER_DEBUG, "Server using shm key hint: %d\n", shm_key_hint);
  769.     ret = trove_collection_setinfo(0, 0, TROVE_SHM_KEY_HINT, &shm_key_hint);
  770.     assert(ret == 0);
  771.  
  772.     if(server_config.db_cache_type && (!strcmp(server_config.db_cache_type,
  773.                                                "mmap")))
  774.     {
  775.         /* set db cache type to mmap rather than sys */
  776.         init_flags |= TROVE_DB_CACHE_MMAP;
  777.     }
  778.  
  779.     /* Set the buffer size according to configuration file */
  780.     BMI_set_info(0, BMI_TCP_BUFFER_SEND_SIZE, 
  781.                  (void *)&server_config.tcp_buffer_size_send);
  782.     BMI_set_info(0, BMI_TCP_BUFFER_RECEIVE_SIZE, 
  783.                  (void *)&server_config.tcp_buffer_size_receive);
  784.  
  785.     ret = trove_initialize(
  786.         server_config.trove_method, 
  787.         trove_coll_to_method_callback,
  788.         server_config.data_path,
  789.         server_config.meta_path,
  790.         init_flags);
  791.     if (ret < 0)
  792.     {
  793.         PVFS_perror_gossip("Error: trove_initialize", ret);
  794.  
  795.         gossip_err("\n***********************************************\n");
  796.         gossip_err("Invalid Storage Space: %s or %s\n\n",
  797.                    server_config.data_path, server_config.meta_path);
  798.         gossip_err("Storage initialization failed.  The most "
  799.                    "common reason\nfor this is that the storage space "
  800.                    "has not yet been\ncreated or is located on a "
  801.                    "partition that has not yet\nbeen mounted.  "
  802.                    "If you'd like to create the storage space,\n"
  803.                    "re-run this program with a -f option.\n");
  804.         gossip_err("\n***********************************************\n");
  805.         return ret;
  806.     }
  807.  
  808.     *server_status_flag |= SERVER_TROVE_INIT;
  809.  
  810.     ret = PINT_cached_config_initialize();
  811.     if(ret < 0)
  812.     {
  813.         gossip_err("Error initializing cached_config interface.\n");
  814.         return(ret);
  815.     }
  816.  
  817.     /* initialize the flow interface */
  818.     ret = PINT_flow_initialize(server_config.flow_modules, 0);
  819.  
  820.     if (ret < 0)
  821.     {
  822.         PVFS_perror_gossip("Error: PINT_flow_initialize", ret);
  823.         return ret;
  824.     }
  825.  
  826.     *server_status_flag |= SERVER_FLOW_INIT;
  827.  
  828.     cur = server_config.file_systems;
  829.     while(cur)
  830.     {
  831.         cur_fs = PINT_llist_head(cur);
  832.         if (!cur_fs)
  833.         {
  834.             break;
  835.         }
  836.  
  837.         ret = PINT_cached_config_handle_load_mapping(cur_fs);
  838.         if(ret)
  839.         {
  840.             PVFS_perror("Error: PINT_handle_load_mapping", ret);
  841.             return(ret);
  842.         }
  843.  
  844.         /*
  845.            set storage hints if any.  if any of these fail, we
  846.            can't error out since they're just hints.  thus, we
  847.            complain in logging and continue.
  848.            */
  849.         ret = trove_collection_setinfo(
  850.             cur_fs->coll_id, 0,
  851.             TROVE_DIRECTIO_THREADS_NUM,
  852.             (void *)&cur_fs->directio_thread_num);
  853.         if (ret < 0)
  854.         {
  855.             gossip_err("Error setting directio threads num\n");
  856.         }
  857.  
  858.         ret = trove_collection_setinfo(
  859.             cur_fs->coll_id, 0,
  860.             TROVE_DIRECTIO_OPS_PER_QUEUE,
  861.             (void *)&cur_fs->directio_ops_per_queue);
  862.         if (ret < 0)
  863.         {
  864.             gossip_err("Error setting directio ops per queue\n");
  865.         }
  866.  
  867.         ret = trove_collection_setinfo(
  868.             cur_fs->coll_id, 0,
  869.             TROVE_DIRECTIO_TIMEOUT,
  870.             (void *)&cur_fs->directio_timeout);
  871.         if (ret < 0)
  872.         {
  873.             gossip_err("Error setting directio threads num\n");
  874.         }
  875.  
  876.         ret = trove_collection_lookup(
  877.             cur_fs->trove_method,
  878.             cur_fs->file_system_name, &(orig_fsid), NULL, NULL);
  879.  
  880.         if (ret < 0)
  881.         {
  882.             gossip_err("Error initializing filesystem %s\n",
  883.                         cur_fs->file_system_name);
  884.             return ret;
  885.         }
  886.  
  887.         if(orig_fsid != cur_fs->coll_id)
  888.         {
  889.             gossip_err("Error: configuration file does not match storage collection.\n");
  890.             gossip_err("   storage file fs_id: %d\n", (int)orig_fsid);
  891.             gossip_err("   config  file fs_id: %d\n", (int)cur_fs->coll_id);
  892.             gossip_err("Warning: This most likely means that the configuration\n");
  893.             gossip_err("   files have been regenerated without destroying and\n");
  894.             gossip_err("   recreating the corresponding storage collection.\n");
  895.             return(-PVFS_ENODEV);
  896.         }
  897.  
  898.         /*
  899.          * get a range string that combines all handles for both meta
  900.          * and data ranges specified in the config file.
  901.          *
  902.          * the server isn't concerned with what allocation of handles
  903.          * are meta and which are data at this level, so we lump them
  904.          * all together and hand them to trove-handle-mgmt.
  905.          */
  906.         cur_merged_handle_range =
  907.             PINT_config_get_merged_handle_range_str(
  908.                 &server_config, cur_fs);
  909.  
  910.         /*
  911.          * error out if we're not configured to house either a meta or
  912.          * data handle range at all.
  913.          */
  914.         if (!cur_merged_handle_range)
  915.         {
  916.             gossip_err("Error: Invalid handle range for host %s "
  917.                         "(alias %s) specified in file system %s\n",
  918.                         server_config.host_id,
  919.                         PINT_config_get_host_alias_ptr(
  920.                             &server_config, server_config.host_id),
  921.                         cur_fs->file_system_name);
  922.             return -1;
  923.         }
  924.         else
  925.         {
  926.             ret = trove_open_context(cur_fs->coll_id, &trove_context);
  927.             if (ret < 0)
  928.             {
  929.                 gossip_err("Error initializing trove context\n");
  930.                 return ret;
  931.             }
  932.  
  933.             /*
  934.               set storage hints if any.  if any of these fail, we
  935.               can't error out since they're just hints.  thus, we
  936.               complain in logging and continue.
  937.             */
  938.             ret = trove_collection_setinfo(
  939.                 cur_fs->coll_id, trove_context, 
  940.                 TROVE_COLLECTION_HANDLE_TIMEOUT,
  941.                 (void *)&cur_fs->handle_recycle_timeout_sec);
  942.             if (ret < 0)
  943.             {
  944.                 gossip_err("Error setting handle timeout\n");
  945.             }
  946.  
  947.             if (cur_fs->attr_cache_keywords &&
  948.                 cur_fs->attr_cache_size &&
  949.                 cur_fs->attr_cache_max_num_elems)
  950.             {
  951.                 ret = trove_collection_setinfo(
  952.                     cur_fs->coll_id, trove_context, 
  953.                     TROVE_COLLECTION_ATTR_CACHE_KEYWORDS,
  954.                     (void *)cur_fs->attr_cache_keywords);
  955.                 if (ret < 0)
  956.                 {
  957.                     gossip_err("Error setting attr cache keywords\n");
  958.                 }
  959.                 ret = trove_collection_setinfo(
  960.                     cur_fs->coll_id, trove_context, 
  961.                     TROVE_COLLECTION_ATTR_CACHE_SIZE,
  962.                     (void *)&cur_fs->attr_cache_size);
  963.                 if (ret < 0)
  964.                 {
  965.                     gossip_err("Error setting attr cache size\n");
  966.                 }
  967.                 ret = trove_collection_setinfo(
  968.                     cur_fs->coll_id, trove_context, 
  969.                     TROVE_COLLECTION_ATTR_CACHE_MAX_NUM_ELEMS,
  970.                     (void *)&cur_fs->attr_cache_max_num_elems);
  971.                 if (ret < 0)
  972.                 {
  973.                     gossip_err("Error setting attr cache max num elems\n");
  974.                 }
  975.                 ret = trove_collection_setinfo(
  976.                     cur_fs->coll_id, trove_context, 
  977.                     TROVE_COLLECTION_ATTR_CACHE_INITIALIZE,
  978.                     (void *)0);
  979.                 if (ret < 0)
  980.                 {
  981.                     gossip_err("Error initializing the attr cache\n");
  982.                 }
  983.             }
  984.  
  985.             /*
  986.               add configured merged handle range for this host/fs.
  987.               NOTE: if the attr cache was properly configured above,
  988.               this next setinfo may have the opportunity to cache
  989.               a number of attributes on startup during an iterate.
  990.             */
  991.             ret = trove_collection_setinfo(
  992.                 cur_fs->coll_id, trove_context,
  993.                 TROVE_COLLECTION_HANDLE_RANGES,
  994.                 (void *)cur_merged_handle_range);
  995.             if (ret < 0)
  996.             {
  997.                 gossip_err("Error adding handle range %s to "
  998.                             "filesystem %s\n",
  999.                             cur_merged_handle_range,
  1000.                             cur_fs->file_system_name);
  1001.                 return ret;
  1002.             }
  1003.  
  1004.             ret = trove_collection_setinfo(
  1005.                 cur_fs->coll_id, trove_context,
  1006.                 TROVE_COLLECTION_COALESCING_HIGH_WATERMARK,
  1007.                 (void *)&cur_fs->coalescing_high_watermark);
  1008.             if(ret < 0)
  1009.             {
  1010.                 gossip_err("Error setting coalescing high watermark\n");
  1011.                 return ret;
  1012.             }
  1013.  
  1014.             ret = trove_collection_setinfo(
  1015.                 cur_fs->coll_id, trove_context,
  1016.                 TROVE_COLLECTION_COALESCING_LOW_WATERMARK,
  1017.                 (void *)&cur_fs->coalescing_low_watermark);
  1018.             if(ret < 0)
  1019.             {
  1020.                 gossip_err("Error setting coalescing low watermark\n");
  1021.                 return ret;
  1022.             }
  1023.             
  1024.             ret = trove_collection_setinfo(
  1025.                 cur_fs->coll_id, trove_context,
  1026.                 TROVE_COLLECTION_META_SYNC_MODE,
  1027.                 (void *)&cur_fs->trove_sync_meta);
  1028.             if(ret < 0)
  1029.             {
  1030.                 gossip_err("Error setting coalescing low watermark\n");
  1031.                 return ret;
  1032.             } 
  1033.             
  1034.             ret = trove_collection_setinfo(
  1035.                 cur_fs->coll_id, trove_context,
  1036.                 TROVE_COLLECTION_IMMEDIATE_COMPLETION,
  1037.                 (void *)&cur_fs->immediate_completion);
  1038.             if(ret < 0)
  1039.             {
  1040.                 gossip_err("Error setting trove immediate completion\n");
  1041.                 return ret;
  1042.             } 
  1043.  
  1044.             gossip_debug(GOSSIP_SERVER_DEBUG, "File system %s using "
  1045.                          "handles:\n\t%s\n", cur_fs->file_system_name,
  1046.                          cur_merged_handle_range);
  1047.  
  1048.             gossip_debug(GOSSIP_SERVER_DEBUG, "Sync on metadata update "
  1049.                          "for %s: %s\n", cur_fs->file_system_name,
  1050.                          ((cur_fs->trove_sync_meta == TROVE_SYNC) ?
  1051.                           "yes" : "no"));
  1052.  
  1053.             gossip_debug(GOSSIP_SERVER_DEBUG, "Sync on I/O data update "
  1054.                          "for %s: %s\n", cur_fs->file_system_name,
  1055.                          ((cur_fs->trove_sync_data == TROVE_SYNC) ?
  1056.                           "yes" : "no"));
  1057.  
  1058.             gossip_debug(GOSSIP_SERVER_DEBUG, "Export options for "
  1059.                          "%s:\n RootSquash %s\n AllSquash %s\n ReadOnly %s\n"
  1060.                          " AnonUID %u\n AnonGID %u\n", cur_fs->file_system_name,
  1061.                          (cur_fs->exp_flags & TROVE_EXP_ROOT_SQUASH) ? "yes" : "no",
  1062.                          (cur_fs->exp_flags & TROVE_EXP_ALL_SQUASH)  ? "yes" : "no",
  1063.                          (cur_fs->exp_flags & TROVE_EXP_READ_ONLY)   ? "yes" : "no",
  1064.                          cur_fs->exp_anon_uid, cur_fs->exp_anon_gid);
  1065.  
  1066.             /* format and pass sync mode to the flow implementation */
  1067.             snprintf(buf, 16, "%d,%d", cur_fs->coll_id,
  1068.                      cur_fs->trove_sync_data);
  1069.             PINT_flow_setinfo(NULL, FLOWPROTO_DATA_SYNC_MODE, buf);
  1070.  
  1071.             trove_close_context(cur_fs->coll_id, trove_context);
  1072.             free(cur_merged_handle_range);
  1073.         }
  1074.  
  1075.         cur = PINT_llist_next(cur);
  1076.     }
  1077.  
  1078.     *server_status_flag |= SERVER_CACHED_CONFIG_INIT;
  1079.  
  1080.     gossip_debug(GOSSIP_SERVER_DEBUG,
  1081.                  "Storage Init Complete (%s)\n", SERVER_STORAGE_MODE);
  1082.     gossip_debug(GOSSIP_SERVER_DEBUG, "%d filesystem(s) initialized\n",
  1083.                  PINT_llist_count(server_config.file_systems));
  1084.  
  1085.     /*
  1086.      * Migrate database if needed
  1087.      */
  1088.     ret = trove_migrate(server_config.trove_method,
  1089.             server_config.data_path,
  1090.             server_config.meta_path);
  1091.     if (ret < 0)
  1092.     {
  1093.         gossip_err("trove_migrate failed: ret=%d\n", ret);
  1094.         return(ret);
  1095.     }
  1096.  
  1097.     ret = job_time_mgr_init();
  1098.     if(ret < 0)
  1099.     {
  1100.         PVFS_perror_gossip("Error: job_time_mgr_init", ret);
  1101.         return(ret);
  1102.     }
  1103.  
  1104.     *server_status_flag |= SERVER_JOB_TIME_MGR_INIT;
  1105.  
  1106.     /* initialize Job Interface */
  1107.     ret = job_initialize(0);
  1108.     if (ret < 0)
  1109.     {
  1110.         PVFS_perror_gossip("Error: job_initialize", ret);
  1111.         return ret;
  1112.     }
  1113.  
  1114.     *server_status_flag |= SERVER_JOB_INIT;
  1115.     
  1116.     ret = job_open_context(&server_job_context);
  1117.     if (ret < 0)
  1118.     {
  1119.         gossip_err("Error opening job context.\n");
  1120.         return ret;
  1121.     }
  1122.  
  1123.     *server_status_flag |= SERVER_JOB_CTX_INIT;
  1124.  
  1125.     ret = PINT_req_sched_initialize();
  1126.     if (ret < 0)
  1127.     {
  1128.         PVFS_perror_gossip("Error: PINT_req_sched_intialize", ret);
  1129.         return ret;
  1130.     }
  1131.     *server_status_flag |= SERVER_REQ_SCHED_INIT;
  1132.  
  1133. #ifndef __PVFS2_DISABLE_PERF_COUNTERS__
  1134.     PINT_server_pc = PINT_perf_initialize(server_keys);
  1135.     if(!PINT_server_pc)
  1136.     {
  1137.         gossip_err("Error initializing performance counters.\n");
  1138.         return(ret);
  1139.     }
  1140.     *server_status_flag |= SERVER_PERF_COUNTER_INIT;
  1141. #endif
  1142.  
  1143.     ret = precreate_pool_initialize(server_index);
  1144.     if (ret < 0)
  1145.     {
  1146.         gossip_err("Error initializing precreate pool.\n");
  1147.         return (ret);
  1148.     }
  1149.  
  1150.     *server_status_flag |= SERVER_PRECREATE_INIT;
  1151.  
  1152.     return ret;
  1153. }
  1154.  
  1155. static int server_setup_signal_handlers(void)
  1156. {
  1157.     struct sigaction new_action;
  1158.     struct sigaction ign_action;
  1159.     struct sigaction hup_action;
  1160.     hup_action.sa_sigaction = (void *)hup_sighandler;
  1161.     sigemptyset (&hup_action.sa_mask);
  1162.     hup_action.sa_flags = SA_RESTART | SA_SIGINFO;
  1163. #ifdef __PVFS2_SEGV_BACKTRACE__
  1164.     struct sigaction segv_action;
  1165.  
  1166.     segv_action.sa_sigaction = (void *)bt_sighandler;
  1167.     sigemptyset (&segv_action.sa_mask);
  1168.     segv_action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONESHOT;
  1169. #endif
  1170.  
  1171.     /* Set up the structure to specify the new action. */
  1172.     new_action.sa_handler = server_sig_handler;
  1173.     sigemptyset (&new_action.sa_mask);
  1174.     new_action.sa_flags = 0;
  1175.  
  1176.     ign_action.sa_handler = SIG_IGN;
  1177.     sigemptyset (&ign_action.sa_mask);
  1178.     ign_action.sa_flags = 0;
  1179.  
  1180.     /* catch these */
  1181.     sigaction (SIGILL, &new_action, NULL);
  1182.     sigaction (SIGTERM, &new_action, NULL);
  1183.     sigaction (SIGHUP, &hup_action, NULL);
  1184.     sigaction (SIGINT, &new_action, NULL);
  1185.     sigaction (SIGQUIT, &new_action, NULL);
  1186. #ifdef __PVFS2_SEGV_BACKTRACE__
  1187.     sigaction (SIGSEGV, &segv_action, NULL);
  1188. #else
  1189.     sigaction (SIGSEGV, &new_action, NULL);
  1190. #endif
  1191.  
  1192.     /* ignore these */
  1193.     sigaction (SIGPIPE, &ign_action, NULL);
  1194.     sigaction (SIGUSR1, &ign_action, NULL);
  1195.     sigaction (SIGUSR2, &ign_action, NULL);
  1196.  
  1197.     return 0;
  1198. }
  1199.  
  1200. #ifdef __PVFS2_SEGV_BACKTRACE__
  1201.  
  1202. #if defined(REG_EIP)
  1203. #  define REG_INSTRUCTION_POINTER REG_EIP
  1204. #elif defined(REG_RIP)
  1205. #  define REG_INSTRUCTION_POINTER REG_RIP
  1206. #else
  1207. #  error Unknown instruction pointer location for your architecture, configure without --enable-segv-backtrace.
  1208. #endif
  1209.  
  1210. /* bt_signalhandler()
  1211.  *
  1212.  * prints a stack trace from a signal handler; code taken from a Linux
  1213.  * Journal article
  1214.  *
  1215.  * no return value
  1216.  */
  1217. static void bt_sighandler(int sig, siginfo_t *info, void *secret)
  1218. {
  1219.     void *trace[16];
  1220.     char **messages = (char **)NULL;
  1221.     int i, trace_size = 0;
  1222.     ucontext_t *uc = (ucontext_t *)secret;
  1223.  
  1224.     /* Do something useful with siginfo_t */
  1225.     if (sig == SIGSEGV)
  1226.     {
  1227.         gossip_err("PVFS2 server: signal %d, faulty address is %p, " 
  1228.             "from %p\n", sig, info->si_addr, 
  1229.             (void*)uc->uc_mcontext.gregs[REG_INSTRUCTION_POINTER]);
  1230.     }
  1231.     else
  1232.     {
  1233.         gossip_err("PVFS2 server: signal %d\n", sig);
  1234.     }
  1235.  
  1236.     trace_size = backtrace(trace, 16);
  1237.     /* overwrite sigaction with caller's address */
  1238.     trace[1] = (void *) uc->uc_mcontext.gregs[REG_INSTRUCTION_POINTER];
  1239.  
  1240.     messages = backtrace_symbols(trace, trace_size);
  1241.     /* skip first stack frame (points here) */
  1242.     for (i=1; i<trace_size; ++i)
  1243.         gossip_err("[bt] %s\n", messages[i]);
  1244.  
  1245.     signal_recvd_flag = sig;
  1246.     return;
  1247. }
  1248. #endif
  1249.  
  1250. /* hup_signalhandler()
  1251.  *
  1252.  * Reload mutable configuration values. If there are errors, leave server in
  1253.  * a running state.
  1254.  *
  1255.  * NOTE: this _only_ reloads configuration values related to squashing,
  1256.  * readonly, and trusted settings.  It does not allow reloading of arbitrary
  1257.  * configuration file settings.
  1258.  *
  1259.  * no return value
  1260.  */
  1261. static void hup_sighandler(int sig, siginfo_t *info, void *secret)
  1262. {
  1263.     uint64_t debug_mask;
  1264.     int debug_on;
  1265.  
  1266.     /* Let's make sure this message is printed out */
  1267.     gossip_get_debug_mask(&debug_on, &debug_mask); /* Need to set back later */
  1268.     gossip_set_debug_mask(1, GOSSIP_SERVER_DEBUG); /* Make sure debug set */
  1269.     gossip_debug(GOSSIP_SERVER_DEBUG, "PVFS2 received server: signal %d\n", sig);
  1270.     gossip_set_debug_mask(debug_on, debug_mask); /* Set to original values */
  1271.  
  1272.     /* Set the flag so the next server loop picks it up and reloads config */
  1273.     signal_recvd_flag = sig;
  1274. }
  1275.  
  1276. static void reload_config(void)
  1277. {
  1278.     struct server_configuration_s sighup_server_config;
  1279.     PINT_llist *orig_filesystems = NULL;
  1280.     PINT_llist *hup_filesystems  = NULL;
  1281.     struct filesystem_configuration_s *orig_fs;
  1282.     struct filesystem_configuration_s *hup_fs;
  1283.     int tmp_value = 0;
  1284.     char **tmp_ptr = NULL;
  1285.     int *tmp_int_ptr = NULL;
  1286.  
  1287.     /* We received a SIGHUP. Update configuration in place */
  1288.     if (PINT_parse_config(&sighup_server_config, fs_conf, s_server_options.server_alias) < 0)
  1289.     {
  1290.         gossip_err("Error: Please check your config files.\n");
  1291.         gossip_err("Error: SIGHUP unable to update configuration.\n");
  1292.         PINT_config_release(&sighup_server_config); /* Free memory */
  1293.     }
  1294.     else /* Successful load of config */
  1295.     {
  1296.         orig_filesystems = server_config.file_systems;
  1297.         /* Loop and update all stored file systems */
  1298.         while(orig_filesystems)
  1299.         {
  1300.             int found_matching_config = 0;
  1301.  
  1302.             orig_fs = PINT_llist_head(orig_filesystems);
  1303.             if(!orig_fs)
  1304.             {
  1305.                break;
  1306.             }
  1307.             hup_filesystems = sighup_server_config.file_systems;
  1308.  
  1309.             /* Find the matching fs from sighup */
  1310.             while(hup_filesystems)
  1311.             {
  1312.                 hup_fs = PINT_llist_head(hup_filesystems);
  1313.                 if ( !hup_fs )
  1314.                 {
  1315.                     break;
  1316.                 }
  1317.                 if( hup_fs->coll_id == orig_fs->coll_id )
  1318.                 {
  1319.                     found_matching_config = 1;
  1320.                     break;
  1321.                 }
  1322.                 hup_filesystems = PINT_llist_head(hup_filesystems);
  1323.             }
  1324.             if(!found_matching_config)
  1325.             {
  1326.                 gossip_err("Error: SIGHUP unable to update configuration"
  1327.                            "Matching configuration not found.\n");
  1328.                 break;
  1329.             }
  1330.             /* Update root squashing. Prelude is only place to accesses
  1331.              * these values, so no need to lock around them. Swap the
  1332.              * needed pointers so that server config gets new values,
  1333.              * and the old values get freed up
  1334.             */
  1335.             orig_fs->exp_flags = hup_fs->exp_flags;
  1336.  
  1337.             tmp_value = orig_fs->root_squash_count;
  1338.             orig_fs->root_squash_count = hup_fs->root_squash_count;
  1339.             hup_fs->root_squash_count = tmp_value;
  1340.  
  1341.             tmp_ptr = orig_fs->root_squash_hosts;
  1342.             orig_fs->root_squash_hosts = hup_fs->root_squash_hosts;
  1343.             hup_fs->root_squash_hosts = tmp_ptr;
  1344.  
  1345.             tmp_int_ptr = orig_fs->root_squash_netmasks;
  1346.             orig_fs->root_squash_netmasks = hup_fs->root_squash_netmasks;
  1347.             hup_fs->root_squash_netmasks = tmp_int_ptr;
  1348.  
  1349.             tmp_value = orig_fs->root_squash_exceptions_count;
  1350.             orig_fs->root_squash_exceptions_count = hup_fs->root_squash_exceptions_count;
  1351.             hup_fs->root_squash_exceptions_count = tmp_value;
  1352.  
  1353.             tmp_ptr = orig_fs->root_squash_exceptions_hosts;
  1354.             orig_fs->root_squash_exceptions_hosts = hup_fs->root_squash_exceptions_hosts;
  1355.             hup_fs->root_squash_exceptions_hosts = tmp_ptr;
  1356.  
  1357.             tmp_int_ptr = orig_fs->root_squash_exceptions_netmasks;
  1358.             orig_fs->root_squash_exceptions_netmasks = hup_fs->root_squash_exceptions_netmasks;
  1359.             hup_fs->root_squash_exceptions_netmasks = tmp_int_ptr;
  1360.  
  1361.             /* Update all squashing. Prelude is only place to accesses
  1362.              * these values, so no need to lock around them. Swap
  1363.              * pointers so that server config gets new values, and
  1364.              * the old values get freed up
  1365.              */
  1366.             tmp_value = orig_fs->all_squash_count;
  1367.             orig_fs->all_squash_count = hup_fs->all_squash_count;
  1368.             hup_fs->all_squash_count = tmp_value;
  1369.  
  1370.             tmp_ptr = orig_fs->all_squash_hosts;
  1371.             orig_fs->all_squash_hosts = hup_fs->all_squash_hosts;
  1372.             hup_fs->all_squash_hosts = tmp_ptr;
  1373.  
  1374.             tmp_int_ptr = orig_fs->all_squash_netmasks;
  1375.             orig_fs->all_squash_netmasks = hup_fs->all_squash_netmasks;
  1376.             hup_fs->all_squash_netmasks = tmp_int_ptr;
  1377.  
  1378.             /* Update read only. Prelude is only place to accesses
  1379.              * these values, so no need to lock around them. Swap
  1380.              * pointers so that server config gets new values, and
  1381.              * the old values get freed up
  1382.              */
  1383.             tmp_value = orig_fs->ro_count;
  1384.             orig_fs->ro_count = hup_fs->ro_count;
  1385.             hup_fs->ro_count = tmp_value;
  1386.  
  1387.             tmp_ptr = orig_fs->ro_hosts;
  1388.             orig_fs->ro_hosts = hup_fs->ro_hosts;
  1389.             hup_fs->ro_hosts = tmp_ptr;
  1390.  
  1391.             tmp_int_ptr = orig_fs->ro_netmasks;
  1392.            orig_fs->ro_netmasks = hup_fs->ro_netmasks;
  1393.             hup_fs->ro_netmasks = tmp_int_ptr;
  1394.  
  1395.             orig_fs->exp_anon_uid = hup_fs->exp_anon_uid;
  1396.             orig_fs->exp_anon_gid = hup_fs->exp_anon_gid;
  1397.  
  1398.             orig_filesystems = PINT_llist_next(orig_filesystems);
  1399.         }
  1400. #ifdef USE_TRUSTED
  1401.         server_config.ports_enabled = sighup_server_config.ports_enabled;
  1402.         server_config.allowed_ports[0] = sighup_server_config.allowed_ports[0];
  1403.         server_config.allowed_ports[1] = sighup_server_config.allowed_ports[1];
  1404.         server_config.network_enabled = sighup_server_config.network_enabled;
  1405.  
  1406.         tmp_value = server_config.allowed_networks_count;
  1407.         server_config.allowed_networks_count = sighup_server_config.allowed_networks_count;
  1408.         sighup_server_config.allowed_networks_count = tmp_value;
  1409.  
  1410.         tmp_ptr = server_config.allowed_networks;
  1411.         server_config.allowed_networks = sighup_server_config.allowed_networks;
  1412.         sighup_server_config.allowed_networks = tmp_ptr;
  1413.  
  1414.         tmp_int_ptr = server_config.allowed_masks;
  1415.         server_config.allowed_masks = sighup_server_config.allowed_masks;
  1416.         sighup_server_config.allowed_masks = tmp_int_ptr;
  1417.  
  1418.         /* security and security_dtor will be updated in a call
  1419.          * to BMI_set_info. Need to save old values so they are
  1420.          * deleted on cleanup
  1421.          */
  1422.         sighup_server_config.security = server_config.security;
  1423.         sighup_server_config.security_dtor = server_config.security_dtor;
  1424.  
  1425.         /* The set_info call grabs the interface_mutex, so we are
  1426.          * basically using that to lock this resource
  1427.          */
  1428.         BMI_set_info(0, BMI_TRUSTED_CONNECTION, (void *) &server_config);
  1429. #endif
  1430.         PINT_config_release(&sighup_server_config); /* Free memory */
  1431.     }
  1432. }
  1433.  
  1434. static int server_shutdown(
  1435.     PINT_server_status_flag status,
  1436.     int ret, int siglevel)
  1437. {
  1438.     if (siglevel == SIGSEGV)
  1439.     {
  1440.         gossip_err("SIGSEGV: skipping cleanup; exit now!\n");
  1441.         exit(EXIT_FAILURE);
  1442.     }
  1443.  
  1444.     gossip_debug(GOSSIP_SERVER_DEBUG,
  1445.                  "*** server shutdown in progress ***\n");
  1446.  
  1447.     free(s_server_options.server_alias);
  1448.  
  1449.     if (status & SERVER_PRECREATE_INIT)
  1450.     {
  1451.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting precreate pool "
  1452.                      "           [   ...   ]\n");
  1453.         precreate_pool_finalize();
  1454.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         precreate pool "
  1455.                      "           [ stopped ]\n");
  1456.     }
  1457.  
  1458.     if (status & SERVER_STATE_MACHINE_INIT)
  1459.     {
  1460.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting state machine "
  1461.                      "processor   [   ...   ]\n");
  1462.         PINT_state_machine_halt();
  1463.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         state machine "
  1464.                      "processor   [ stopped ]\n");
  1465.     }
  1466.  
  1467.     if (status & SERVER_CACHED_CONFIG_INIT)
  1468.     {
  1469.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting cached "
  1470.                      "config interface   [   ...   ]\n");
  1471.         PINT_cached_config_finalize();
  1472.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         cached "
  1473.                      "config interface   [ stopped ]\n");
  1474.     }
  1475.  
  1476.     if (status & SERVER_EVENT_INIT)
  1477.     {
  1478.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting event "
  1479.                      "profiling interface [   ...   ]\n");
  1480.         PINT_event_finalize();
  1481.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         event "
  1482.                      "profiling interface [ stopped ]\n");
  1483.     }
  1484.  
  1485.     if (status & SERVER_REQ_SCHED_INIT)
  1486.     {
  1487.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting request "
  1488.                      "scheduler         [   ...   ]\n");
  1489.         PINT_req_sched_finalize();
  1490.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         request "
  1491.                      "scheduler         [ stopped ]\n");
  1492.     }
  1493.         
  1494.     if (status & SERVER_JOB_CTX_INIT)
  1495.     {
  1496.         job_close_context(server_job_context);
  1497.     }
  1498.  
  1499.     if (status & SERVER_JOB_INIT)
  1500.     {
  1501.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting job "
  1502.                      "interface             [   ...   ]\n");
  1503.         job_finalize();
  1504.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         job "
  1505.                      "interface             [ stopped ]\n");
  1506.     }
  1507.  
  1508.     if (status & SERVER_JOB_TIME_MGR_INIT)
  1509.     {
  1510.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting job time "
  1511.                      "mgr interface    [   ...   ]\n");
  1512.         job_time_mgr_finalize();
  1513.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         job time "
  1514.                      "mgr interface    [ stopped ]\n");
  1515.     }
  1516.  
  1517.     if (status & SERVER_FLOW_INIT)
  1518.     {
  1519.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting flow "
  1520.                      "interface            [   ...   ]\n");
  1521.         PINT_flow_finalize();
  1522.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         flow "
  1523.                      "interface            [ stopped ]\n");
  1524.     }
  1525.  
  1526.     if (status & SERVER_BMI_INIT)
  1527.     {
  1528.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting bmi "
  1529.                      "interface             [   ...   ]\n");
  1530.         BMI_finalize();
  1531.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         bmi "
  1532.                      "interface             [ stopped ]\n");
  1533.     }
  1534.  
  1535.     if (status & SERVER_TROVE_INIT)
  1536.     {
  1537.         PINT_llist *cur;
  1538.         struct filesystem_configuration_s *cur_fs;
  1539.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting storage "
  1540.                      "interface         [   ...   ]\n");
  1541.  
  1542.         cur = server_config.file_systems;
  1543.         while(cur)
  1544.         {
  1545.             cur_fs = PINT_llist_head(cur);
  1546.             if (!cur_fs)
  1547.             {
  1548.                 break;
  1549.             }
  1550.             trove_collection_clear(cur_fs->trove_method, cur_fs->coll_id);
  1551.  
  1552.             cur = PINT_llist_next(cur);
  1553.         }
  1554.  
  1555.         trove_finalize(server_config.trove_method);
  1556.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         storage "
  1557.                      "interface         [ stopped ]\n");
  1558.     }
  1559.  
  1560.     if (status & SERVER_ENCODER_INIT)
  1561.     {
  1562.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting encoder "
  1563.                      "interface         [   ...   ]\n");
  1564.         PINT_encode_finalize();
  1565.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         encoder "
  1566.                      "interface         [ stopped ]\n");
  1567.     }
  1568.  
  1569.     if (status & SERVER_DIST_INIT)
  1570.     {
  1571.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting dist "
  1572.                      "interface            [   ...   ]\n");
  1573.         PINT_dist_finalize();
  1574.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         dist "
  1575.                      "interface            [ stopped ]\n");
  1576.     }
  1577.  
  1578.     if (status & SERVER_PERF_COUNTER_INIT)
  1579.     {
  1580.         gossip_debug(GOSSIP_SERVER_DEBUG, "[+] halting performance "
  1581.                      "interface     [   ...   ]\n");
  1582.         PINT_perf_finalize(PINT_server_pc);
  1583.         gossip_debug(GOSSIP_SERVER_DEBUG, "[-]         performance "
  1584.                      "interface     [ stopped ]\n");
  1585.     }
  1586.  
  1587.     if (status & SERVER_GOSSIP_INIT)
  1588.     {
  1589.         gossip_debug(GOSSIP_SERVER_DEBUG,
  1590.                      "[*] halting logging interface\n");
  1591.         gossip_disable();
  1592.     }
  1593.  
  1594.     if (status & SERVER_CONFIG_INIT)
  1595.     {
  1596.         PINT_config_release(&server_config);
  1597.     }
  1598.  
  1599.     if (status & SERVER_JOB_OBJS_ALLOCATED)
  1600.     {
  1601.         free(server_job_id_array);
  1602.         free(server_completed_job_p_array);
  1603.         free(server_job_status_array);
  1604.     }
  1605.  
  1606.     if(siglevel == 0 && ret != 0)
  1607.     {
  1608.         exit(EXIT_FAILURE);
  1609.     }
  1610.     exit(EXIT_SUCCESS);
  1611. }
  1612.  
  1613. static void server_sig_handler(int sig)
  1614. {
  1615.     struct sigaction new_action;
  1616.  
  1617.     if (getpid() == server_controlling_pid)
  1618.     {
  1619.         if (sig != SIGSEGV)
  1620.         {
  1621.             gossip_err("\nPVFS2 server got signal %d "
  1622.                        "(server_status_flag: %d)\n",
  1623.                        sig, (int)server_status_flag);
  1624.         }
  1625.  
  1626.         /* ignore further invocations of this signal */
  1627.         new_action.sa_handler = SIG_IGN;
  1628.         sigemptyset(&new_action.sa_mask);
  1629.         new_action.sa_flags = 0;
  1630.         sigaction (sig, &new_action, NULL);
  1631.  
  1632.         /* set the signal_recvd_flag on critical errors to cause the
  1633.          * server to exit gracefully on the next work cycle
  1634.          */
  1635.         signal_recvd_flag = sig;
  1636.         /*
  1637.          * iterate through all the machines that we had posted for
  1638.          * unexpected BMI messages and deallocate them.
  1639.          * From now the server will only try and finish operations
  1640.          * that are already in progress, wait for them to timeout
  1641.          * or complete before initiating shutdown
  1642.          */
  1643.         server_purge_unexpected_recv_machines();
  1644.     }
  1645. }
  1646.  
  1647. static void usage(int argc, char **argv)
  1648. {
  1649.     gossip_err("Usage: %s: [OPTIONS] <global_config_file> "
  1650.                "\n\n", argv[0]);
  1651.     gossip_err("  -d, --foreground\t"
  1652.                "will keep server in the foreground\n");
  1653.     gossip_err("  -f, --mkfs\t\twill cause server to "
  1654.                "create file system storage and exit\n");
  1655.     gossip_err("  -h, --help\t\twill show this message\n");
  1656.     gossip_err("  -r, --rmfs\t\twill cause server to "
  1657.                "remove file system storage and exit\n");
  1658.     gossip_err("  -v, --version\t\toutput version information "
  1659.                "and exit\n");
  1660.     gossip_err("  -p, --pidfile <file>\twrite process id to file\n");
  1661.     gossip_err("  -a, --alias <alias>\tuse the specified alias for this node\n");
  1662. }
  1663.  
  1664. static int server_parse_cmd_line_args(int argc, char **argv)
  1665. {
  1666.     int ret = 0, option_index = 0;
  1667.     int total_arguments = 0;
  1668.     const char *cur_option = NULL;
  1669.     static struct option long_opts[] =
  1670.     {
  1671.         {"foreground",0,0,0},
  1672.         {"mkfs",0,0,0},
  1673.         {"help",0,0,0},
  1674.         {"rmfs",0,0,0},
  1675.         {"version",0,0,0},
  1676.         {"pidfile",1,0,0},
  1677.         {"alias",0,0,0},
  1678.         {0,0,0,0}
  1679.     };
  1680.  
  1681.     while ((ret = getopt_long(argc, argv,"dfhrvp:a:e",
  1682.                               long_opts, &option_index)) != -1)
  1683.     {
  1684.         total_arguments++;
  1685.         switch (ret)
  1686.         {
  1687.             case 0:
  1688.                 cur_option = long_opts[option_index].name;
  1689.                 assert(cur_option);
  1690.  
  1691.                 if (strcmp("foreground", cur_option) == 0)
  1692.                 {
  1693.                     goto do_foreground;
  1694.                 }
  1695.                 else if (strcmp("mkfs", cur_option) == 0)
  1696.                 {
  1697.                     goto do_mkfs;
  1698.                 }
  1699.                 else if (strcmp("help", cur_option) == 0)
  1700.                 {
  1701.                     goto do_help;
  1702.                 }
  1703.                 else if (strcmp("rmfs", cur_option) == 0)
  1704.                 {
  1705.                     goto do_rmfs;
  1706.                 }
  1707.                 else if (strcmp("version", cur_option) == 0)
  1708.                 {
  1709.                     goto do_version;
  1710.                 }
  1711.                 else if (strcmp("pidfile", cur_option) == 0)
  1712.                 {
  1713.                     goto do_pidfile;
  1714.                 }
  1715.                 else if (strcmp("alias", cur_option) == 0)
  1716.                 {
  1717.                     goto do_alias;
  1718.                 }
  1719.                 break;
  1720.             case 'v':
  1721.           do_version:
  1722.                 printf("%s (mode: %s)\n", PVFS2_VERSION,
  1723.                        SERVER_STORAGE_MODE);
  1724.                 return PVFS2_VERSION_REQUEST;
  1725.             case 'r':
  1726.           do_rmfs:
  1727.                 s_server_options.server_remove_storage_space = 1;
  1728.             case 'f':
  1729.           do_mkfs:
  1730.                 s_server_options.server_create_storage_space = 1;
  1731.                 break;
  1732.             case 'd':
  1733.           do_foreground:
  1734.                 s_server_options.server_background = 0;
  1735.                 break;
  1736.             case 'p':
  1737.           do_pidfile:
  1738.                 total_arguments++;
  1739.                 s_server_options.pidfile = optarg;
  1740.                 if(optarg[0] != '/')
  1741.                 {
  1742.                     gossip_err("Error: pidfile must be specified with an absolute path.\n");
  1743.                     goto parse_cmd_line_args_failure;
  1744.                 }
  1745.                 break;
  1746.             case 'a':
  1747.           do_alias:
  1748.                 total_arguments++;
  1749.                 s_server_options.server_alias = strdup(optarg);
  1750.                 break;
  1751.             case '?':
  1752.             case 'h':
  1753.           do_help:
  1754.             default:
  1755.           parse_cmd_line_args_failure:
  1756.                 usage(argc, argv);
  1757.                 if(s_server_options.server_alias)
  1758.                 {
  1759.                     free(s_server_options.server_alias);
  1760.                 }
  1761.                 return 1;
  1762.         }
  1763.     }
  1764.  
  1765.     if(argc < optind)
  1766.     {
  1767.         gossip_err("Missing config file in command line arguments\n");
  1768.         goto parse_cmd_line_args_failure;
  1769.     }
  1770.  
  1771.     fs_conf = argv[optind++];
  1772.  
  1773.     if(argc - total_arguments > 2)
  1774.     {
  1775.         /* Assume user is passing in a server.conf.  Bit of a hack here to
  1776.          * support server.conf files in the old format by appending the
  1777.          * server.conf options onto the fs.conf.
  1778.          */
  1779.         gossip_err("The two config file format is no longer supported.  "
  1780.                    "Generate a single fs.conf that uses the new format with the "
  1781.                    "pvfs2-config-convert script.\n\n");
  1782.         goto parse_cmd_line_args_failure;
  1783.     }
  1784.  
  1785.     if (s_server_options.server_alias == NULL)
  1786.     {
  1787.         /* Try to guess the alias from the hostname */
  1788.         s_server_options.server_alias = PINT_util_guess_alias();
  1789.     }
  1790.     return 0;
  1791. }
  1792.  
  1793. /* server_post_unexpected_recv()
  1794.  *
  1795.  * Allocates space for an unexpected BMI message and posts this.
  1796.  *
  1797.  * Returns 0 on success, -PVFS_error on failure.
  1798.  */
  1799. int server_post_unexpected_recv(job_status_s *js_p)
  1800. {
  1801.     int ret = -PVFS_EINVAL;
  1802.     /* job_id_t j_id; */
  1803.     struct PINT_smcb *smcb = NULL;
  1804.     struct PINT_server_op *s_op;
  1805.  
  1806.     gossip_debug(GOSSIP_SERVER_DEBUG,
  1807.             "server_post_unexpected_recv\n");
  1808.  
  1809.     if (js_p)
  1810.     {
  1811.         ret = PINT_smcb_alloc(&smcb, BMI_UNEXPECTED_OP,
  1812.                 sizeof(struct PINT_server_op),
  1813.                 server_op_state_get_machine,
  1814.                 server_state_machine_terminate,
  1815.                 server_job_context);
  1816.         if (ret < 0)
  1817.         {
  1818.             gossip_lerr("Error: failed to allocate SMCB "
  1819.                         "of op type %x\n", BMI_UNEXPECTED_OP);
  1820.             return ret;
  1821.         }
  1822.         s_op = (struct PINT_server_op *)PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  1823.         memset(s_op, 0, sizeof(PINT_server_op));
  1824.         s_op->op = BMI_UNEXPECTED_OP;
  1825.         s_op->target_handle = PVFS_HANDLE_NULL;
  1826.         s_op->target_fs_id = PVFS_FS_ID_NULL;
  1827.         /* Add an unexpected s_ops to the list */
  1828.         qlist_add_tail(&s_op->next, &posted_sop_list);
  1829.  
  1830.         ret = PINT_state_machine_start(smcb, js_p);
  1831.         if(ret == SM_ACTION_TERMINATE)
  1832.         {
  1833.             /* error posting unexpected */
  1834.             PINT_smcb_free(smcb);
  1835.             return js_p->error_code;
  1836.         }
  1837.     }
  1838.     return ret;
  1839. }
  1840.  
  1841. /* server_purge_unexpected_recv_machines()
  1842.  *
  1843.  * removes any s_ops that were posted to field unexpected BMI messages
  1844.  *
  1845.  * returns 0 on success and -PVFS_errno on failure.
  1846.  */
  1847. static int server_purge_unexpected_recv_machines(void)
  1848. {
  1849.     struct qlist_head *tmp = NULL, *tmp2 = NULL;
  1850.  
  1851.     if (qlist_empty(&posted_sop_list))
  1852.     {
  1853.         gossip_err("WARNING: Found empty posted operation list!\n");
  1854.         return -PVFS_EINVAL;
  1855.     }
  1856.     qlist_for_each_safe (tmp, tmp2, &posted_sop_list)
  1857.     {
  1858.         PINT_server_op *s_op = qlist_entry(tmp, PINT_server_op, next);
  1859.  
  1860.         /* Remove s_op from the posted_sop_list */
  1861.         /* don't see a reason to remove this */
  1862.         /* will be removed in state machine */
  1863.         /* if and when message completes after cancellation */
  1864.         /* qlist_del(&s_op->next); */
  1865.  
  1866.         /* mark the message for cancellation */
  1867.         s_op->op_cancelled = 1;
  1868.  
  1869.         /* cancel the pending job_bmi_unexp operation */
  1870.         job_bmi_unexp_cancel(s_op->unexp_id);
  1871.     }
  1872.     return 0;
  1873. }
  1874.  
  1875. /* server_state_machine_start()
  1876.  *
  1877.  * initializes fields in the s_op structure and begins execution of
  1878.  * the appropriate state machine
  1879.  *
  1880.  * returns 0 on success, -PVFS_errno on failure
  1881.  */
  1882. int server_state_machine_start(
  1883.     PINT_smcb *smcb,
  1884.     job_status_s *js_p)
  1885. {
  1886.     PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  1887.     int ret = -PVFS_EINVAL;
  1888.     PVFS_id_gen_t tmp_id;
  1889.  
  1890.     gossip_debug(GOSSIP_SERVER_DEBUG,
  1891.             "server_state_machine_start %p\n",smcb);
  1892.  
  1893.     ret = PINT_decode(s_op->unexp_bmi_buff.buffer,
  1894.                       PINT_DECODE_REQ,
  1895.                       &s_op->decoded,
  1896.                       s_op->unexp_bmi_buff.addr,
  1897.                       s_op->unexp_bmi_buff.size);
  1898.  
  1899.     /* acknowledge that the unexpected buffer has been used up.
  1900.      * If *someone* decides to do in-place decoding, then we will have to move
  1901.      * this back to state_machine_complete().
  1902.      */
  1903.     if (ret == -PVFS_EPROTONOSUPPORT)
  1904.     {
  1905.         /* we have a protocol mismatch of some sort; try to trigger a
  1906.          * response that gives a helpful error on client side even
  1907.          * though we can't interpret what the client was asking for
  1908.          */
  1909.         ret = PINT_smcb_set_op(smcb, PVFS_SERV_PROTO_ERROR);
  1910.     }
  1911.     else if (ret == 0)
  1912.     {
  1913.         s_op->req  = (struct PVFS_server_req *)s_op->decoded.buffer;
  1914.         ret = PINT_smcb_set_op(smcb, s_op->req->op);
  1915.         s_op->op = s_op->req->op;
  1916.         PVFS_hint_add(&s_op->req->hints, PVFS_HINT_SERVER_ID_NAME, sizeof(uint32_t), &server_config.host_index);
  1917.         PVFS_hint_add(&s_op->req->hints, PVFS_HINT_OP_ID_NAME, sizeof(uint32_t), &s_op->req->op);
  1918.     }
  1919.     else
  1920.     {
  1921.         PVFS_perror_gossip("Error: PINT_decode failure", ret);
  1922.         return ret;
  1923.     }
  1924.     /* Remove s_op from posted_sop_list and move it to the inprogress_sop_list */
  1925.     qlist_del(&s_op->next);
  1926.     qlist_add_tail(&s_op->next, &inprogress_sop_list);
  1927.  
  1928.     /* set timestamp on the beginning of this state machine */
  1929.     id_gen_fast_register(&tmp_id, s_op);
  1930.  
  1931.     if(s_op->req)
  1932.     {
  1933.         gossip_debug(GOSSIP_SERVER_DEBUG, "client:%d, reqid:%d, rank:%d\n",
  1934.                      PINT_HINT_GET_CLIENT_ID(s_op->req->hints),
  1935.                      PINT_HINT_GET_REQUEST_ID(s_op->req->hints),
  1936.                      PINT_HINT_GET_RANK(s_op->req->hints));
  1937.         PINT_EVENT_START(PINT_sm_event_id, server_controlling_pid,
  1938.                          NULL, &s_op->event_id,
  1939.                          PINT_HINT_GET_CLIENT_ID(s_op->req->hints),
  1940.                          PINT_HINT_GET_REQUEST_ID(s_op->req->hints),
  1941.                          PINT_HINT_GET_RANK(s_op->req->hints),
  1942.                          PINT_HINT_GET_HANDLE(s_op->req->hints),
  1943.                          s_op->req->op);
  1944.         s_op->resp.op = s_op->req->op;
  1945.     }
  1946.  
  1947.     s_op->addr = s_op->unexp_bmi_buff.addr;
  1948.     s_op->tag  = s_op->unexp_bmi_buff.tag;
  1949.  
  1950.     if (!ret)
  1951.     {
  1952.         gossip_err("Error: server does not implement request type: %d\n",
  1953.                    (int)s_op->req->op);
  1954.         PINT_decode_release(&(s_op->decoded),PINT_DECODE_REQ);
  1955.         return -PVFS_ENOSYS;
  1956.     }
  1957.  
  1958.     return PINT_state_machine_invoke(smcb, js_p);
  1959. }
  1960.  
  1961. /* server_state_machine_alloc_noreq()
  1962.  * 
  1963.  * allocates and initializes a server state machine that can later be
  1964.  * started with server_state_machine_start_noreq()
  1965.  *
  1966.  * returns 0 on success, -PVFS_error on failure
  1967.  */
  1968. int server_state_machine_alloc_noreq(
  1969.     enum PVFS_server_op op,
  1970.     struct PINT_smcb **new_op)
  1971. {
  1972.     int ret = -PVFS_EINVAL;
  1973.  
  1974.     gossip_debug(GOSSIP_SERVER_DEBUG,
  1975.             "server_state_machine_alloc_noreq %d\n",op);
  1976.  
  1977.     if (new_op)
  1978.     {
  1979.         PINT_server_op *tmp_op;
  1980.         ret = PINT_smcb_alloc(new_op, op, 
  1981.                 sizeof(struct PINT_server_op),
  1982.                 server_op_state_get_machine,
  1983.                 server_state_machine_terminate,
  1984.                 server_job_context);
  1985.         if (ret < 0)
  1986.         {
  1987.             gossip_lerr("Error: failed to allocate SMCB "
  1988.                         "of op type %x\n", op);
  1989.             return ret;
  1990.         }
  1991.         tmp_op = PINT_sm_frame(*new_op, PINT_FRAME_CURRENT);
  1992.         tmp_op->op = op;
  1993.         tmp_op->target_handle = PVFS_HANDLE_NULL;
  1994.         tmp_op->target_fs_id = PVFS_FS_ID_NULL;
  1995.  
  1996.         /* NOTE: We do not add these state machines to the 
  1997.          * in-progress or posted sop lists 
  1998.          */
  1999.  
  2000.         ret = 0;
  2001.     }
  2002.     return ret;
  2003. }
  2004.  
  2005. /* server_state_machine_start_noreq()
  2006.  * 
  2007.  * similar in purpose to server_state_machine_start(), except that it
  2008.  * kicks off a state machine instance without first receiving a client
  2009.  * side request
  2010.  *
  2011.  * PINT_server_op structure must have been previously allocated using
  2012.  * server_state_machine_alloc_noreq().
  2013.  *
  2014.  * returns 0 on success, -PVFS_error on failure
  2015.  */
  2016. int server_state_machine_start_noreq(struct PINT_smcb *smcb)
  2017. {
  2018.     struct PINT_server_op *new_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  2019.     int ret = -PVFS_EINVAL;
  2020.     job_status_s tmp_status;
  2021.  
  2022.     gossip_debug(GOSSIP_SERVER_DEBUG,
  2023.             "server_state_machine_start_noreq %p\n",smcb);
  2024.  
  2025.     tmp_status.error_code = 0;
  2026.  
  2027.     if (new_op)
  2028.     {
  2029.  
  2030.         /* add to list of state machines started without a request */
  2031.         qlist_add_tail(&new_op->next, &noreq_sop_list);
  2032.  
  2033.         /* execute first state */
  2034.         ret = PINT_state_machine_start(smcb, &tmp_status);
  2035.         if (ret < 0)
  2036.         {
  2037.             gossip_lerr("Error: failed to start state machine.\n");
  2038.             return ret;
  2039.         }
  2040.     }
  2041.     return ret;
  2042. }
  2043.  
  2044. /* server_state_machine_complete()
  2045.  *
  2046.  * function to be called at the completion of state machine execution;
  2047.  * it frees up any resources associated with the state machine that were
  2048.  * allocated before the state machine started executing.  Also returns
  2049.  * appropriate return value to make the state machine stop transitioning
  2050.  *
  2051.  * returns 0
  2052.  */
  2053. int server_state_machine_complete(PINT_smcb *smcb)
  2054. {
  2055.     PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
  2056.     PVFS_id_gen_t tmp_id;
  2057.  
  2058.     gossip_debug(GOSSIP_SERVER_DEBUG,
  2059.             "server_state_machine_complete %p\n",smcb);
  2060.  
  2061.     /* set a timestamp on the completion of the state machine */
  2062.     id_gen_fast_register(&tmp_id, s_op);
  2063.  
  2064.     if(s_op->req)
  2065.     {
  2066.         PINT_EVENT_END(PINT_sm_event_id, server_controlling_pid,
  2067.                        NULL, s_op->event_id, 0);
  2068.     }
  2069.  
  2070.     /* release the decoding of the unexpected request */
  2071.     if (ENCODING_IS_VALID(s_op->decoded.enc_type))
  2072.     {
  2073.         PVFS_hint_free(s_op->decoded.stub_dec.req.hints);
  2074.  
  2075.         PINT_decode_release(&(s_op->decoded),PINT_DECODE_REQ);
  2076.     }
  2077.  
  2078.     gossip_ldebug(GOSSIP_BMI_DEBUG_TCP,"server_state_machine_complete: smcb op code (%d).\n"
  2079.                                       ,s_op->op);
  2080.     gossip_ldebug(GOSSIP_BMI_DEBUG_TCP,"server_state_machine_complete: "
  2081.                                        "s_op->unexp_bmi_buff.buffer (%p) "
  2082.                                        "\tNULL(%s).\n"
  2083.                                       ,s_op->unexp_bmi_buff.buffer
  2084.                                       ,s_op->unexp_bmi_buff.buffer ? "NO" : "YES");
  2085.  
  2086.     /* BMI_unexpected_free MUST execute BEFORE BMI_set_info, because BMI_set_info will */
  2087.     /* remove the addr info from the cur_ref_list if BMI_DEC_ADDR_REF causes the ref   */
  2088.     /* count to become zero.  The addr info holds the "unexpected-free" function       */
  2089.     /* pointer.                                                                        */
  2090.     BMI_unexpected_free(s_op->unexp_bmi_buff.addr, 
  2091.                         s_op->unexp_bmi_buff.buffer);
  2092.     BMI_set_info(s_op->unexp_bmi_buff.addr, BMI_DEC_ADDR_REF, NULL);
  2093.     s_op->unexp_bmi_buff.buffer = NULL;
  2094.  
  2095.  
  2096.    /* Remove s_op from the inprogress_sop_list */
  2097.     qlist_del(&s_op->next);
  2098.  
  2099.     return SM_ACTION_TERMINATE;
  2100. }
  2101.  
  2102. int server_state_machine_terminate(
  2103.         struct PINT_smcb *smcb, job_status_s *js_p)
  2104. {
  2105.     /* free the operation structure itself */
  2106.     gossip_debug(GOSSIP_SERVER_DEBUG,
  2107.             "server_state_machine_terminate %p\n",smcb);
  2108.     PINT_smcb_free(smcb);
  2109.     return SM_ACTION_TERMINATE;
  2110. }
  2111.  
  2112. struct server_configuration_s *get_server_config_struct(void)
  2113. {
  2114.     return &server_config;
  2115. }
  2116.  
  2117. /* server_op_get_machine()
  2118.  * 
  2119.  * looks up the state machine for the op * given and returns it, or
  2120.  * NULL of the op is out of range.
  2121.  * pointer to this function set in the control block of server state
  2122.  * machines.
  2123.  */
  2124. struct PINT_state_machine_s *server_op_state_get_machine(int op)
  2125. {
  2126.     gossip_debug(GOSSIP_SERVER_DEBUG,
  2127.             "server_op_state_get_machine %d\n",op);
  2128.  
  2129.     switch (op)
  2130.     {
  2131.     case BMI_UNEXPECTED_OP :
  2132.         {
  2133.             return &pvfs2_unexpected_sm;
  2134.             break;
  2135.         }
  2136.     default :
  2137.         {
  2138.             if (op >= 0 && op < PVFS_SERV_NUM_OPS)
  2139.                 return PINT_server_req_table[op].params->state_machine;
  2140.             else
  2141.                 return NULL;
  2142.             break;
  2143.         }
  2144.     }
  2145. }
  2146.  
  2147. static TROVE_method_id trove_coll_to_method_callback(TROVE_coll_id coll_id)
  2148. {
  2149.     struct filesystem_configuration_s * fs_config;
  2150.  
  2151.     fs_config = PINT_config_find_fs_id(&server_config, coll_id);
  2152.     if(!fs_config)
  2153.     {
  2154.         return server_config.trove_method;
  2155.     }
  2156.     return fs_config->trove_method;
  2157. }
  2158.  
  2159. #ifndef GOSSIP_DISABLE_DEBUG
  2160. void PINT_server_access_debug(PINT_server_op * s_op,
  2161.                               int64_t debug_mask,
  2162.                               const char * format,
  2163.                               ...)
  2164. {
  2165.     static char pint_access_buffer[GOSSIP_BUF_SIZE];
  2166.     struct passwd* pw;
  2167.     struct group* gr;
  2168.     va_list ap;
  2169.  
  2170.     if ((gossip_debug_on) &&
  2171.         (gossip_debug_mask & debug_mask) &&
  2172.         (gossip_facility))
  2173.     {
  2174.         va_start(ap, format);
  2175.  
  2176.         pw = getpwuid(s_op->req->credentials.uid);
  2177.         gr = getgrgid(s_op->req->credentials.gid);
  2178.         snprintf(pint_access_buffer, GOSSIP_BUF_SIZE,
  2179.             "%s.%s@%s H=%llu S=%p: %s: %s",
  2180.             ((pw) ? pw->pw_name : "UNKNOWN"),
  2181.             ((gr) ? gr->gr_name : "UNKNOWN"),
  2182.             BMI_addr_rev_lookup_unexpected(s_op->addr),
  2183.             llu(s_op->target_handle),
  2184.             s_op,
  2185.             PINT_map_server_op_to_string(s_op->req->op),
  2186.             format);
  2187.  
  2188.         __gossip_debug_va(debug_mask, 'A', pint_access_buffer, ap);
  2189.  
  2190.         va_end(ap);
  2191.     }
  2192. }
  2193. #endif
  2194.  
  2195. /* generate_shm_key_hint()
  2196.  *
  2197.  * Makes a best effort to produce a unique shm key (for Trove's Berkeley
  2198.  * DB use) for each server.  By default it will base this on the server's
  2199.  * position in the fs.conf, but it will fall back to using a random number
  2200.  *
  2201.  * returns integer key
  2202.  */
  2203. static int generate_shm_key_hint(int* server_index)
  2204. {
  2205.     struct host_alias_s *cur_alias = NULL;
  2206.     struct filesystem_configuration_s *first_fs;
  2207.  
  2208.     *server_index = 1;
  2209.  
  2210.     PINT_llist *cur = server_config.host_aliases;
  2211.  
  2212.     /* iterate through list of aliases in configuration file */
  2213.     while(cur)
  2214.     {
  2215.         cur_alias = PINT_llist_head(cur);
  2216.         if(!cur_alias)
  2217.         {
  2218.             break;
  2219.         }
  2220.         if(strcmp(cur_alias->bmi_address, server_config.host_id) == 0)
  2221.         {
  2222.             /* match */
  2223.             /* space the shm keys out by 10 to allow for Berkeley DB using 
  2224.              * using more than one key on each server
  2225.              */
  2226.             first_fs = PINT_llist_head(server_config.file_systems);
  2227.             return(first_fs->coll_id + (*server_index)*10);
  2228.         }
  2229.  
  2230.         (*server_index)++;
  2231.         cur = PINT_llist_next(cur);
  2232.     }
  2233.     
  2234.     /* If we reach this point, we didn't find this server in the alias list.
  2235.      * This is not a normal situation, but fall back to using a random
  2236.      * number for the key just to be safe.
  2237.      */
  2238.     srand((unsigned int)time(NULL));
  2239.     return(rand());
  2240. }
  2241.  
  2242. /* precreate_pool_initialize()
  2243.  * 
  2244.  * starts the infrastructure for managing pools of precreated handles
  2245.  *
  2246.  * returns 0 on success, -PVFS_error on failure
  2247.  */
  2248. static int precreate_pool_initialize(int server_index)
  2249. {
  2250.     PINT_llist *cur_f = server_config.file_systems;
  2251.     struct filesystem_configuration_s *cur_fs;
  2252.     int ret = -1;
  2253.     PVFS_handle pool_handle;
  2254.     int server_count;
  2255.     PVFS_BMI_addr_t* addr_array;
  2256.     const char* host;
  2257.     int i, j;
  2258.     int server_type;
  2259.     int handle_count = 0;
  2260.     int fs_count = 0;
  2261.     unsigned int types_to_pool = 0;
  2262.     struct server_configuration_s *user_opts = get_server_config_struct();
  2263.     assert(user_opts);
  2264.  
  2265.     /* iterate through list of file systems */
  2266.     while(cur_f)
  2267.     {
  2268.         cur_fs = PINT_llist_head(cur_f);
  2269.         if (!cur_fs)
  2270.         {
  2271.             break;
  2272.         }
  2273.  
  2274.         fs_count++;
  2275.  
  2276.         /* am I a meta server in this file system? */
  2277.         ret = PINT_cached_config_check_type(
  2278.             cur_fs->coll_id,
  2279.             server_config.host_id,
  2280.             &server_type);
  2281.         if(ret < 0)
  2282.         {
  2283.             gossip_err("Error: %s not found in configuration file.\n", 
  2284.                 server_config.host_id);
  2285.             gossip_err("Error: configuration file is inconsistent.\n");
  2286.             return(ret);
  2287.         }
  2288.         if(!(server_type & PINT_SERVER_TYPE_META))
  2289.         {
  2290.             /* This server is not a meta server for this file system; 
  2291.              * skip doing any precreate setup steps.
  2292.              */
  2293.             cur_f = PINT_llist_next(cur_f);
  2294.             continue;
  2295.         }
  2296.  
  2297.         /* how many servers do we have? */
  2298.         ret = PINT_cached_config_count_servers(
  2299.             cur_fs->coll_id, PINT_SERVER_TYPE_ALL, &server_count);
  2300.         if(ret < 0)
  2301.         {
  2302.             gossip_err("Error: unable to count servers for fsid: %d\n", 
  2303.                 (int)cur_fs->coll_id);
  2304.             return(ret);
  2305.         }
  2306.         
  2307.         addr_array = malloc(server_count*sizeof(PVFS_BMI_addr_t));
  2308.         if(!addr_array)
  2309.         {
  2310.             gossip_err("Error: unable to allocate book keeping information for "
  2311.                        "precreate pools.\n");
  2312.             return(-PVFS_ENOMEM);
  2313.         }
  2314.  
  2315.         /* resolve addrs for each I/O server */
  2316.         ret = PINT_cached_config_get_server_array(
  2317.             cur_fs->coll_id, PINT_SERVER_TYPE_ALL,
  2318.             addr_array, &server_count);
  2319.         if(ret < 0)
  2320.         {
  2321.             gossip_err("Error: unable retrieve servers for fsid: %d\n", 
  2322.                 (int)cur_fs->coll_id);
  2323.             return(ret);
  2324.         }
  2325.  
  2326.         for(i=0; i<server_count; i++)
  2327.         {
  2328.             host = PINT_cached_config_map_addr(
  2329.                 cur_fs->coll_id, addr_array[i], &server_type);
  2330.             if(!strcmp(host, server_config.host_id) == 0)
  2331.             {
  2332.                 /* this is a peer server */
  2333.                 /* make sure a pool exists for that server,type, fsid pair */
  2334.  
  2335.                 /* set ds type of handles to setup in the server's pool based
  2336.                  * on the server type */
  2337.                 types_to_pool = PVFS_TYPE_NONE;
  2338.                 if( (server_type & PINT_SERVER_TYPE_IO) != 0 )
  2339.                 {
  2340.                         types_to_pool |= PVFS_TYPE_DATAFILE; 
  2341.                 }
  2342.                 
  2343.                 if( (server_type & PINT_SERVER_TYPE_META) != 0 )
  2344.                 {
  2345.                     types_to_pool |= (PVFS_TYPE_METAFILE | PVFS_TYPE_DIRECTORY |
  2346.                                       PVFS_TYPE_SYMLINK | PVFS_TYPE_DIRDATA |
  2347.                                       PVFS_TYPE_INTERNAL);
  2348.                 }
  2349.  
  2350.                 /* for each possible bit in the ds_type mask check if we should
  2351.                  * create a pool for it */
  2352.                 for(j = 0; j < PVFS_DS_TYPE_COUNT; j++ )
  2353.                 {
  2354.                     PVFS_ds_type t;
  2355.                     int_to_PVFS_ds_type(j, &t);
  2356.                     
  2357.                     /* skip setting up a pool when it doesn't make sense i.e. 
  2358.                      * when the remote host doesn't have handle types we want.
  2359.                      * or in the special case that we don't get TYPE_NONE 
  2360.                      * handles from  IO servers*/
  2361.                     if(((t & types_to_pool) == 0 ) ||
  2362.                        ((t == PVFS_TYPE_NONE) && 
  2363.                         (server_type == PINT_SERVER_TYPE_IO)) )
  2364.                     {
  2365.                         continue;
  2366.                     }
  2367.  
  2368.                     gossip_debug(GOSSIP_SERVER_DEBUG, "%s: setting up pool on "
  2369.                                  "%s, type: %u, fs_id: %llu, handle: %llu\n",
  2370.                                  __func__, host, t, llu(cur_fs->coll_id), 
  2371.                                  llu(pool_handle));
  2372.                     ret = precreate_pool_setup_server(host, t, 
  2373.                         cur_fs->coll_id, &pool_handle);
  2374.                     if(ret < 0)
  2375.                     {
  2376.                         gossip_err("Error: precreate_pool_initialize failed to "
  2377.                                    "setup pool for %s, type %u\n", 
  2378.                                    server_config.host_id, t);
  2379.                         return(ret);
  2380.                     }
  2381.     
  2382.                     /* count current handles */
  2383.                     ret = precreate_pool_count(cur_fs->coll_id, pool_handle, 
  2384.                         &handle_count);
  2385.                     if(ret < 0)
  2386.                     {
  2387.                         gossip_err("Error: precreate_pool_initialize failed to "
  2388.                                    "count pool for %s\n", 
  2389.                                    server_config.host_id);
  2390.                         return(ret);
  2391.                     }
  2392.     
  2393.                     /* prepare the job interface to use this pool */
  2394.                     ret = job_precreate_pool_register_server(host, t,
  2395.                         cur_fs->coll_id, pool_handle, handle_count,
  2396.                         user_opts->precreate_batch_size);
  2397.     
  2398.                     /* launch sm to take care of refilling */
  2399.                     /* the refiller will only actually launch if the batch count
  2400.                      * for the specified type, t, is greater than 0. Otherwise,
  2401.                      * there is no reason to have a refiller running. */
  2402.                     ret = precreate_pool_launch_refiller(host, t, addr_array[i],
  2403.                         cur_fs->coll_id, pool_handle);
  2404.                     if(ret < 0)
  2405.                     {
  2406.                         gossip_err("Error: precreate_pool_initialize failed to "
  2407.                                    "launch refiller SM for %s\n", 
  2408.                                    server_config.host_id);
  2409.                         return(ret);
  2410.                     }
  2411.                 } // for each PVFS_ds_type
  2412.             }
  2413.         }
  2414.  
  2415.         job_precreate_pool_set_index(server_index);
  2416.  
  2417.         cur_f = PINT_llist_next(cur_f);
  2418.         free(addr_array); // local variable, malloc'd above to get BMI addrs
  2419.  
  2420.     }
  2421.  
  2422.     return(0);
  2423. }
  2424.  
  2425. /* precreate_pool_finalize()
  2426.  *
  2427.  * shuts down infrastructure for managing pools of precreated handles
  2428.  */
  2429. static void precreate_pool_finalize(void)
  2430. {
  2431.     /* TODO: anything to do here? */
  2432.     /* TODO: maybe try to stop pending refiller sms? */
  2433.     return;
  2434. }
  2435.  
  2436. /* precreate_pool_setup_server()
  2437.  *  
  2438.  * This function makes sure that a pool is present for the specified server,
  2439.  * fsid, and type
  2440.  *
  2441.  *  host: hostname of server the pool is associated with
  2442.  *  type: DS type of handles to store in the pool
  2443.  *  fsid: fsid of the filesystem the pool is associated with
  2444.  *  handle: out value of the handle of the pool
  2445.  *
  2446.  */
  2447. static int precreate_pool_setup_server(const char* host, PVFS_ds_type type, 
  2448.     PVFS_fs_id fsid, PVFS_handle* pool_handle)
  2449. {
  2450.     job_status_s js;
  2451.     job_id_t job_id;
  2452.     int ret;
  2453.     int outcount;
  2454.     PVFS_handle_extent_array ext_array;
  2455.  
  2456.     PVFS_ds_keyval key;
  2457.     PVFS_ds_keyval val;
  2458.  
  2459.     /* look for the pool handle for this server */
  2460.  
  2461.     /* the key for the pool must now be server name plus handle type. 
  2462.      * since the key is currently a string it makes some sense to keep 
  2463.      * the whole thing printable instead of just tacking on a PVFS_ds_type
  2464.      * to the end of the buffer. So, we'll sprint the type as an int and
  2465.      * tack that on the end. Better that just tacking the bits on? 
  2466.      * Maybe not. */
  2467.     char type_string[11] = { 0 }; /* 32 bit type only needs 10 digits */
  2468.     snprintf(type_string, 11, "%u", type);
  2469.  
  2470.     key.buffer_sz = strlen(host) + strlen(type_string) + 
  2471.                     strlen("precreate-pool-") + 2;
  2472.     key.buffer = malloc(key.buffer_sz);
  2473.     if(!key.buffer)
  2474.     {
  2475.         return(-ENOMEM);
  2476.     }
  2477.     snprintf((char*)key.buffer, key.buffer_sz, "precreate-pool-%s-%s", 
  2478.              host, type_string);
  2479.     key.read_sz = 0;
  2480.  
  2481.     val.buffer = pool_handle;
  2482.     val.buffer_sz = sizeof(*pool_handle);
  2483.     val.read_sz = 0;
  2484.  
  2485.     ret = job_trove_fs_geteattr(fsid, &key, &val, 0, NULL, 0, &js, 
  2486.         &job_id, server_job_context, NULL);
  2487.     while(ret == 0)
  2488.     {
  2489.         ret = job_test(job_id, &outcount, NULL, &js, 
  2490.             PVFS2_SERVER_DEFAULT_TIMEOUT_MS, server_job_context);
  2491.     }
  2492.     if(ret < 0)
  2493.     {
  2494.         gossip_err("Error: precreate_pool failed to read fs eattrs.\n");
  2495.         free(key.buffer);
  2496.         return(ret);
  2497.     }
  2498.     if(js.error_code && js.error_code != -TROVE_ENOENT)
  2499.     {
  2500.         gossip_err("Error: precreate_pool failed to read fs eattrs.\n");
  2501.         free(key.buffer);
  2502.         return(js.error_code);
  2503.     }
  2504.     else if(js.error_code == -TROVE_ENOENT)
  2505.     {
  2506.         /* handle doesn't exist yet; let's create it */
  2507.         gossip_debug(GOSSIP_SERVER_DEBUG, "precreate_pool didn't find handle "
  2508.                      "for %s, type %s; creating now.\n", host, type_string);
  2509.  
  2510.         /* find extent array for ourselves */
  2511.         ret = PINT_cached_config_get_server(
  2512.             fsid, server_config.host_id, PINT_SERVER_TYPE_META, &ext_array);
  2513.         if(ret < 0)
  2514.         {
  2515.             gossip_err("Error: PINT_cached_config_get_meta() failure.\n");
  2516.             free(key.buffer);
  2517.             return(ret);
  2518.         }
  2519.  
  2520.         /* create a trove object for the pool */
  2521.         ret = job_trove_dspace_create(fsid, &ext_array, PVFS_TYPE_INTERNAL,
  2522.             NULL, TROVE_SYNC, NULL, 0, &js, &job_id, server_job_context, NULL);
  2523.         while(ret == 0)
  2524.         {
  2525.             ret = job_test(job_id, &outcount, NULL, &js, 
  2526.                 PVFS2_SERVER_DEFAULT_TIMEOUT_MS, server_job_context);
  2527.         }
  2528.         if(ret < 0 || js.error_code)
  2529.         {
  2530.             gossip_err("Error: precreate_pool failed to create pool.\n");
  2531.             free(key.buffer);
  2532.             return(ret < 0 ? ret : js.error_code);
  2533.         }
  2534.  
  2535.         *pool_handle = js.handle;
  2536.  
  2537.         /* store reference to pool handle as collection eattr */
  2538.         ret = job_trove_fs_seteattr(fsid, &key, &val, TROVE_SYNC, NULL, 0, &js, 
  2539.             &job_id, server_job_context, NULL);
  2540.         while(ret == 0)
  2541.         {
  2542.             ret = job_test(job_id, &outcount, NULL, &js, 
  2543.                 PVFS2_SERVER_DEFAULT_TIMEOUT_MS, server_job_context);
  2544.         }
  2545.         if(ret < 0 || js.error_code)
  2546.         {
  2547.             gossip_err("Error: failed to record precreate pool handle.\n");
  2548.             gossip_err("Warning: fsck may be needed to recover lost handle.\n");
  2549.             free(key.buffer);
  2550.             return(ret < 0 ? ret : js.error_code);
  2551.         }
  2552.         gossip_debug(GOSSIP_SERVER_DEBUG, "precreate_pool created handle %llu "
  2553.                      "for %s, type %s.\n", llu(*pool_handle), host, 
  2554.                      type_string);
  2555.  
  2556.     }
  2557.     else
  2558.     {
  2559.         /* handle already exists */
  2560.         gossip_debug(GOSSIP_SERVER_DEBUG, "precreate_pool found handle %llu "
  2561.                      "for %s, type %s.\n", llu(*pool_handle), host, 
  2562.                      type_string);
  2563.     }
  2564.     free(key.buffer);
  2565.     return(0);
  2566. }
  2567.  
  2568. /* precreate_pool_count()
  2569.  *
  2570.  * counts the number of handles stored in a persistent precreate pool
  2571.  */
  2572. static int precreate_pool_count(
  2573.     PVFS_fs_id fsid, PVFS_handle pool_handle, int* count)
  2574. {
  2575.     int ret;
  2576.     job_status_s js;
  2577.     job_id_t job_id;
  2578.     int outcount;
  2579.     PVFS_ds_keyval_handle_info handle_info;
  2580.  
  2581.     /* try to get the current number of handles from the pool */
  2582.     ret = job_trove_keyval_get_handle_info(
  2583.         fsid, pool_handle, TROVE_KEYVAL_HANDLE_COUNT, &handle_info,
  2584.         NULL, 0, &js, &job_id, server_job_context, NULL);
  2585.     while(ret == 0)
  2586.     {
  2587.         ret = job_test(job_id, &outcount, NULL, &js, 
  2588.             PVFS2_SERVER_DEFAULT_TIMEOUT_MS, server_job_context);
  2589.     }
  2590.     if(ret < 0)
  2591.     {
  2592.         return(ret);
  2593.     }
  2594.     
  2595.     if(js.error_code == -TROVE_ENOENT)
  2596.     {
  2597.         /* this really means there aren't any keyvals there yet */
  2598.         handle_info.count = 0;
  2599.     }
  2600.     else if(js.error_code != 0)
  2601.     {
  2602.         return(js.error_code);
  2603.     }
  2604.  
  2605.     *count = handle_info.count;
  2606.  
  2607.     return(0);
  2608. }
  2609.  
  2610. /*
  2611.  * starts a precreate pool refiller state machine for the specified host and
  2612.  * type of handle.
  2613.  *    host: the remote host to get handles from
  2614.  *    type: the DS type of handle the refiller will be refilling
  2615.  *    addr: the BMI addr of the remote host
  2616.  *    fsid: the filesystem ID of the fs the pool refiller is associated with
  2617.  *    pool_handle: the handle of the pool itself
  2618.  *
  2619.  *    This will only be called for a host/type that matches and needs a filler
  2620.  *    so a remote server that is I/O only will only get refillers for datafile
  2621.  *    handles.
  2622.  */
  2623. static int precreate_pool_launch_refiller(const char* host, PVFS_ds_type type,
  2624.     PVFS_BMI_addr_t addr, PVFS_fs_id fsid, PVFS_handle pool_handle)
  2625. {
  2626.     struct PINT_smcb *tmp_smcb = NULL;
  2627.     struct PINT_server_op *s_op;
  2628.     int ret, index = 0;
  2629.     struct server_configuration_s *user_opts = get_server_config_struct();
  2630.  
  2631.     assert(user_opts);
  2632.     PVFS_ds_type_to_int(type, &index);
  2633.  
  2634.     if( user_opts->precreate_batch_size[index] == 0 )
  2635.     {
  2636.         gossip_debug(GOSSIP_SERVER_DEBUG, "%s: NOT launching refiller for "
  2637.                      "host %s, type %d, pool: %llu, batch_size is 0\n",
  2638.                      __func__, host, type, llu(pool_handle));
  2639.         return 0;
  2640.     }
  2641.  
  2642.     /* allocate smcb */
  2643.     ret = server_state_machine_alloc_noreq(PVFS_SERV_PRECREATE_POOL_REFILLER,
  2644.         &(tmp_smcb));
  2645.     if (ret < 0)
  2646.     {
  2647.         return(ret);
  2648.     }
  2649.  
  2650.     s_op = PINT_sm_frame(tmp_smcb, PINT_FRAME_CURRENT);
  2651.     s_op->u.precreate_pool_refiller.host = strdup(host);
  2652.     if(!s_op->u.precreate_pool_refiller.host)
  2653.     {
  2654.         PINT_smcb_free(tmp_smcb);
  2655.         return(ret);
  2656.     }
  2657.  
  2658.     /* set this refillers handle range based on the type of handle it will 
  2659.      * hold. If it's a datafile get an IO server range, otherwise get a meta
  2660.      * range. */
  2661.     ret = PINT_cached_config_get_server( fsid, host, 
  2662.               ((type == PVFS_TYPE_DATAFILE) ? PINT_SERVER_TYPE_IO : 
  2663.                                               PINT_SERVER_TYPE_META),
  2664.               &s_op->u.precreate_pool_refiller.handle_extent_array);
  2665.     if(ret < 0)
  2666.     {
  2667.         free(s_op->u.precreate_pool_refiller.host);
  2668.         PINT_smcb_free(tmp_smcb);
  2669.         return(ret);
  2670.     }
  2671.  
  2672.     gossip_debug(GOSSIP_SERVER_DEBUG, "%s: launching refiller for host %s, "
  2673.                  "type %d, pool: %llu, batch size %d (index %d)\n", __func__, 
  2674.                  s_op->u.precreate_pool_refiller.host, type, llu(pool_handle),
  2675.                  user_opts->precreate_batch_size[index], index);
  2676.  
  2677.     s_op->u.precreate_pool_refiller.pool_handle = pool_handle;
  2678.     s_op->u.precreate_pool_refiller.fsid = fsid;
  2679.     s_op->u.precreate_pool_refiller.type = type;
  2680.     s_op->u.precreate_pool_refiller.host_addr = addr;
  2681.  
  2682.     /* start sm */
  2683.     ret = server_state_machine_start_noreq(tmp_smcb);
  2684.     if (ret < 0)
  2685.     {
  2686.         free(s_op->u.precreate_pool_refiller.host);
  2687.         PINT_smcb_free(tmp_smcb);
  2688.         return(ret);
  2689.     }
  2690.  
  2691.     return(0);
  2692. }
  2693.  
  2694. /*
  2695.  * Local variables:
  2696.  *  c-indent-level: 4
  2697.  *  c-basic-offset: 4
  2698.  * End:
  2699.  *
  2700.  * vim: ts=8 sts=4 sw=4 expandtab
  2701.  */
  2702.