| 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 */ |
|---|
| 74 | static PINT_server_status_flag server_status_flag; |
|---|
| 75 | |
|---|
| 76 | /* All parameters read in from the configuration file */ |
|---|
| 77 | static 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 | */ |
|---|
| 82 | static int signal_recvd_flag = 0; |
|---|
| 83 | static pid_t server_controlling_pid = 0; |
|---|
| 84 | |
|---|
| 85 | static PINT_event_id PINT_sm_event_id; |
|---|
| 86 | |
|---|
| 87 | /* A list of all serv_op's posted for unexpected message alone */ |
|---|
| 88 | QLIST_HEAD(posted_sop_list); |
|---|
| 89 | /* A list of all serv_op's posted for expected messages alone */ |
|---|
| 90 | QLIST_HEAD(inprogress_sop_list); |
|---|
| 91 | /* A list of all serv_op's that are started automatically without requests */ |
|---|
| 92 | static QLIST_HEAD(noreq_sop_list); |
|---|
| 93 | |
|---|
| 94 | /* this is used externally by some server state machines */ |
|---|
| 95 | job_context_id server_job_context = -1; |
|---|
| 96 | |
|---|
| 97 | typedef 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 | |
|---|
| 106 | static options_t s_server_options = { 0, 0, 1, NULL, NULL}; |
|---|
| 107 | static char fs_conf[PATH_MAX]; |
|---|
| 108 | static 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 | */ |
|---|
| 114 | PINT_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 | */ |
|---|
| 129 | static job_id_t *server_job_id_array = NULL; |
|---|
| 130 | static void **server_completed_job_p_array = NULL; |
|---|
| 131 | static job_status_s *server_job_status_array = NULL; |
|---|
| 132 | |
|---|
| 133 | /* Prototypes for internal functions */ |
|---|
| 134 | static int server_initialize( |
|---|
| 135 | PINT_server_status_flag *server_status_flag, |
|---|
| 136 | job_status_s *job_status_structs); |
|---|
| 137 | static int server_initialize_subsystems( |
|---|
| 138 | PINT_server_status_flag *server_status_flag); |
|---|
| 139 | static int server_setup_signal_handlers(void); |
|---|
| 140 | static int server_purge_unexpected_recv_machines(void); |
|---|
| 141 | static int server_setup_process_environment(int background); |
|---|
| 142 | static int server_shutdown( |
|---|
| 143 | PINT_server_status_flag status, |
|---|
| 144 | int ret, int sig); |
|---|
| 145 | static void reload_config(void); |
|---|
| 146 | static void server_sig_handler(int sig); |
|---|
| 147 | static void hup_sighandler(int sig, siginfo_t *info, void *secret); |
|---|
| 148 | static int server_parse_cmd_line_args(int argc, char **argv); |
|---|
| 149 | #ifdef __PVFS2_SEGV_BACKTRACE__ |
|---|
| 150 | static void bt_sighandler(int sig, siginfo_t *info, void *secret); |
|---|
| 151 | #endif |
|---|
| 152 | static int create_pidfile(char *pidfile); |
|---|
| 153 | static void write_pidfile(int fd); |
|---|
| 154 | static void remove_pidfile(void); |
|---|
| 155 | static int generate_shm_key_hint(int* server_index); |
|---|
| 156 | |
|---|
| 157 | static void precreate_pool_finalize(void); |
|---|
| 158 | static int precreate_pool_initialize(int server_index); |
|---|
| 159 | |
|---|
| 160 | static int precreate_pool_setup_server(const char* host, PVFS_ds_type type, |
|---|
| 161 | PVFS_fs_id fsid, PVFS_handle* pool_handle); |
|---|
| 162 | static 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); |
|---|
| 164 | static int precreate_pool_count( |
|---|
| 165 | PVFS_fs_id fsid, PVFS_handle pool_handle, int* count); |
|---|
| 166 | |
|---|
| 167 | static TROVE_method_id trove_coll_to_method_callback(TROVE_coll_id); |
|---|
| 168 | |
|---|
| 169 | |
|---|
| 170 | struct server_configuration_s *PINT_get_server_config(void) |
|---|
| 171 | { |
|---|
| 172 | return &server_config; |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | int 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 | */ |
|---|
| 435 | static int create_pidfile(char *pidfile) |
|---|
| 436 | { |
|---|
| 437 | return open(pidfile, (O_CREAT | O_WRONLY | O_TRUNC), 0644); |
|---|
| 438 | } |
|---|
| 439 | |
|---|
| 440 | static 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 | |
|---|
| 461 | static 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 | */ |
|---|
| 477 | static 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 | */ |
|---|
| 588 | static 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 | */ |
|---|
| 666 | static 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 | |
|---|
| 1176 | static 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 | */ |
|---|
| 1240 | static 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 | */ |
|---|
| 1284 | static 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 | |
|---|
| 1299 | static 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 | |
|---|
| 1473 | static 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 | |
|---|
| 1652 | static 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 | |
|---|
| 1686 | static 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 | |
|---|
| 1703 | static 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 | */ |
|---|
| 1902 | int 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 | */ |
|---|
| 1950 | static 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 | */ |
|---|
| 1985 | int 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 | */ |
|---|
| 2071 | int 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 | */ |
|---|
| 2119 | int 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 | */ |
|---|
| 2156 | int 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 | |
|---|
| 2205 | int 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 | |
|---|
| 2215 | struct 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 | */ |
|---|
| 2227 | struct 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 | |
|---|
| 2250 | static 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 |
|---|
| 2263 | void 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 | */ |
|---|
| 2306 | static 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 | */ |
|---|
| 2351 | static 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 | */ |
|---|
| 2533 | static 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 | */ |
|---|
| 2551 | static 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 | */ |
|---|
| 2676 | static 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 | */ |
|---|
| 2727 | static 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 | */ |
|---|