root/branches/orange-next/src/server/pvfs2-server.c @ 8920

Revision 8920, 90.5 KB (checked in by mtmoore, 2 years ago)

change to #defined calls to uuids

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