/* * rpmemd_req_set_attr -- handle set attributes request */ static int rpmemd_req_set_attr(struct rpmemd_obc *obc, void *arg, const struct rpmem_pool_attr *pool_attr) { RPMEMD_ASSERT(arg != NULL); RPMEMD_LOG(NOTICE, "set attributes request"); struct rpmemd *rpmemd = (struct rpmemd *)arg; RPMEMD_ASSERT(rpmemd->pool != NULL); int ret; int status = 0; int err_send = 1; ret = rpmemd_db_pool_set_attr(rpmemd->pool, pool_attr); if (ret) { ret = -1; status = rpmemd_db_get_status(errno); goto err_set_attr; } RPMEMD_LOG(NOTICE, "new pool attributes:"); rpmemd_print_pool_attr(pool_attr); ret = rpmemd_obc_set_attr_resp(obc, status); if (ret) goto err_set_attr_resp; return ret; err_set_attr_resp: err_send = 0; err_set_attr: if (err_send) ret = rpmemd_obc_set_attr_resp(obc, status); return ret; }
/* * rpmemd_req_close -- handle close request */ static int rpmemd_req_close(struct rpmemd_obc *obc, void *arg) { RPMEMD_ASSERT(arg != NULL); RPMEMD_LOG(NOTICE, "close request"); struct rpmemd *rpmemd = (struct rpmemd *)arg; rpmemd->closing = 1; int ret; int status = 0; if (!rpmemd->pool) { RPMEMD_LOG(ERR, "pool not opened"); status = RPMEM_ERR_FATAL; return rpmemd_obc_close_resp(rpmemd->obc, status); } ret = rpmemd_fip_stop(rpmemd); if (ret) { status = RPMEM_ERR_FATAL; } else { rpmemd_fip_close(rpmemd->fip); rpmemd_fip_fini(rpmemd->fip); } int remove = rpmemd->created && status; ret = rpmemd_close_pool(rpmemd, remove); RPMEMD_LOG(NOTICE, "close request response (status = %u)", status); ret = rpmemd_obc_close_resp(rpmemd->obc, status); return ret; }
/* * rpmemd_fip_cq_thread -- completion queue worker thread */ static void * rpmemd_fip_cq_thread(void *arg) { struct rpmemd_fip *fip = arg; struct fi_cq_err_entry err; const char *str_err; ssize_t sret; int ret = 0; while (!fip->closing) { sret = fi_cq_sread(fip->cq, fip->cq_entries, fip->cq_size, NULL, RPMEM_FIP_CQ_WAIT_MS); if (unlikely(fip->closing)) break; if (unlikely(sret == -FI_EAGAIN)) continue; if (unlikely(sret < 0)) { ret = (int)sret; goto err_cq_read; } for (ssize_t i = 0; i < sret; i++) { struct fi_cq_msg_entry *entry = &fip->cq_entries[i]; RPMEMD_ASSERT(entry->op_context); struct rpmemd_fip_lane *lanep = entry->op_context; /* signal lane about SEND completion */ if (entry->flags & FI_SEND) rpmem_fip_lane_signal(&lanep->lane, FI_SEND); /* add lane to worker's ring buffer */ if (entry->flags & FI_RECV) { ret = rpmemd_fip_worker_push(lanep->worker, lanep); } if (ret) goto err; } } return 0; err_cq_read: sret = fi_cq_readerr(fip->cq, &err, 0); if (sret < 0) { RPMEMD_FI_ERR((int)sret, "error reading from completion queue: " "cannot read error from completion queue"); goto err; } str_err = fi_cq_strerror(fip->cq, err.prov_errno, NULL, NULL, 0); RPMEMD_LOG(ERR, "error reading from completion queue: %s", str_err); err: return (void *)(uintptr_t)ret; }
/* * rpmemd_req_close -- handle close request */ static int rpmemd_req_close(struct rpmemd_obc *obc, void *arg) { RPMEMD_ASSERT(arg != NULL); struct rpmemd *rpmemd = (struct rpmemd *)arg; rpmemd->closing = 1; int ret; int status = 0; if (!rpmemd->pool) { RPMEMD_LOG(ERR, "pool not opened"); status = RPMEM_ERR_FATAL; return rpmemd_obc_close_resp(rpmemd->obc, status); } rpmemd_db_pool_close(rpmemd->db, rpmemd->pool); ret = rpmemd_fip_process_stop(rpmemd->fip); if (ret) { RPMEMD_LOG(ERR, "!stopping fip process failed"); status = errno; } ret = rpmemd_obc_close_resp(rpmemd->obc, status); if (!ret) rpmemd_fip_wait_close(rpmemd->fip, -1); rpmemd_fip_close(rpmemd->fip); rpmemd_fip_fini(rpmemd->fip); return ret; }
/* * parse_cl_args -- (internal) parse command line arguments */ static void parse_cl_args(int argc, char *argv[], struct rpmemd_config *config, const char **config_file, uint64_t *cl_options) { RPMEMD_ASSERT(argv != NULL); RPMEMD_ASSERT(config != NULL); int opt; int option_index = 0; while ((opt = getopt_long(argc, argv, optstr, options, &option_index)) != -1) { if (opt == -1) break; switch (opt) { case 'c': (*config_file) = optarg; break; case 'r': config->rm_poolset = optarg; break; case 'h': print_help(argv[0]); exit(0); case 'V': print_version(); exit(0); break; default: if (set_option((enum rpmemd_option)opt, optarg, config) == 0) { *cl_options |= (uint64_t)(1 << opt); } else { print_usage(argv[0]); exit(-1); } } } }
/* * rpmemd_fip_stop_thread -- stop background thread for in-band connection */ static int rpmemd_fip_stop_thread(struct rpmemd *rpmemd) { RPMEMD_ASSERT(rpmemd->fip_running); void *tret; errno = pthread_join(rpmemd->fip_thread, &tret); if (errno) RPMEMD_LOG(ERR, "!waiting for in-band thread"); int ret = (int)(uintptr_t)tret; if (ret) RPMEMD_LOG(ERR, "in-band thread failed -- '%d'", ret); return ret; }
/* * rpmemd_fip_set_attr -- save required attributes in rpmemd_fip handle */ static void rpmemd_fip_set_attr(struct rpmemd_fip *fip, struct rpmemd_fip_attr *attr) { fip->addr = attr->addr; fip->size = attr->size; fip->nthreads = attr->nthreads; fip->persist_method = attr->persist_method; fip->persist = attr->persist; rpmemd_fip_set_nlanes(fip, attr->nlanes); fip->cq_size = rpmem_fip_cq_size(fip->nlanes, fip->persist_method, RPMEM_FIP_NODE_SERVER); RPMEMD_ASSERT(fip->persist_method < MAX_RPMEM_PM); fip->ops = &rpmemd_fip_ops[fip->persist_method]; }
/* * rpmemd_req_open -- handle open request */ static int rpmemd_req_open(struct rpmemd_obc *obc, void *arg, const struct rpmem_req_attr *req) { RPMEMD_ASSERT(arg != NULL); RPMEMD_LOG(NOTICE, "open request:"); rpmemd_print_req_attr(req); struct rpmemd *rpmemd = (struct rpmemd *)arg; int ret; int status = 0; int err_send = 1; struct rpmem_resp_attr resp; memset(&resp, 0, sizeof(resp)); struct rpmem_pool_attr pool_attr; memset(&pool_attr, 0, sizeof(pool_attr)); if (rpmemd->pool) { RPMEMD_LOG(ERR, "pool already opened"); ret = -1; status = RPMEM_ERR_FATAL; goto err_pool_opened; } rpmemd->pool_desc = strdup(req->pool_desc); if (!rpmemd->pool_desc) { RPMEMD_LOG(ERR, "!allocating pool descriptor"); ret = -1; status = RPMEM_ERR_FATAL; goto err_strdup; } rpmemd->pool = rpmemd_db_pool_open(rpmemd->db, req->pool_desc, 0, &pool_attr); if (!rpmemd->pool) { ret = -1; status = rpmemd_db_get_status(errno); goto err_pool_open; } RPMEMD_LOG(NOTICE, "pool attributes:"); rpmemd_print_pool_attr(&pool_attr); ret = rpmemd_check_pool(rpmemd, req, &status); if (ret) goto err_pool_check; ret = rpmemd_common_fip_init(rpmemd, req, &resp, &status); if (ret) goto err_fip_init; RPMEMD_LOG(NOTICE, "open request response: (status = %u)", status); if (!status) rpmemd_print_resp_attr(&resp); ret = rpmemd_obc_open_resp(rpmemd->obc, status, &resp, &pool_attr); if (ret) goto err_open_resp; ret = rpmemd_fip_start_thread(rpmemd); if (ret) goto err_fip_start; return 0; err_fip_start: err_open_resp: err_send = 0; rpmemd_fip_fini(rpmemd->fip); err_fip_init: err_pool_check: rpmemd_db_pool_close(rpmemd->db, rpmemd->pool); err_pool_open: free(rpmemd->pool_desc); err_strdup: err_pool_opened: if (err_send) ret = rpmemd_obc_open_resp(rpmemd->obc, status, &resp, &pool_attr); rpmemd->closing = 1; return ret; }
/* * rpmemd_fip_init -- initialize fabric provider */ struct rpmemd_fip * rpmemd_fip_init(const char *node, const char *service, struct rpmemd_fip_attr *attr, struct rpmem_resp_attr *resp, enum rpmem_err *err) { int ret; RPMEMD_ASSERT(resp); RPMEMD_ASSERT(err); RPMEMD_ASSERT(attr); RPMEMD_ASSERT(attr->persist); RPMEMD_ASSERT(attr->nthreads); struct rpmemd_fip *fip = calloc(1, sizeof(*fip)); if (!fip) { RPMEMD_LOG(ERR, "!allocating fabric handle"); *err = RPMEM_ERR_FATAL; return NULL; } ret = rpmemd_fip_getinfo(fip, service, node, attr->provider); if (ret) { *err = RPMEM_ERR_BADPROVIDER; goto err_getinfo; } rpmemd_fip_set_attr(fip, attr); ret = rpmemd_fip_init_fabric_res(fip); if (ret) { *err = RPMEM_ERR_FATAL; goto err_init_fabric_res; } ret = rpmemd_fip_init_memory(fip); if (ret) { *err = RPMEM_ERR_FATAL; goto err_init_memory; } ret = fip->ops->init(fip); if (ret) { *err = RPMEM_ERR_FATAL; goto err_init; } ret = fi_listen(fip->pep); if (ret) { *err = RPMEM_ERR_FATAL_CONN; goto err_fi_listen; } ret = rpmemd_fip_set_resp(fip, resp); if (ret) { *err = RPMEM_ERR_FATAL; goto err_set_resp; } return fip; err_set_resp: RPMEMD_FI_CLOSE(fip->pep, "closing passive endpoint"); err_fi_listen: fip->ops->fini(fip); err_init: rpmemd_fip_fini_memory(fip); err_init_memory: rpmemd_fip_fini_fabric_res(fip); err_init_fabric_res: fi_freeinfo(fip->fi); err_getinfo: free(fip); return NULL; }
/* * parse_config_file -- (internal) parse config file */ static int parse_config_file(const char *filename, struct rpmemd_config *config, uint64_t disabled) { RPMEMD_ASSERT(filename != NULL); FILE *file = fopen(filename, "r"); if (file == NULL) { if (filename != RPMEMD_DEFAULT_CONFIG_FILE) { RPMEMD_LOG(ERR, "!%s", filename); goto error_fopen; } else goto default_config_missing; } uint8_t line_max_increased = 0; uint64_t line_max = CONFIG_LINE_SIZE_INIT; uint64_t line_num = 1; char *line = (char *)malloc(sizeof(char) * line_max); if (line == NULL) { RPMEMD_LOG(ERR, "!malloc"); goto error_malloc_line; } char *line_copy = (char *)malloc(sizeof(char) * line_max); if (line_copy == NULL) { RPMEMD_LOG(ERR, "!malloc"); goto error_malloc_line_copy; } struct rpmemd_special_chars_pos pos; do { memset(&pos, INT32_MAX, sizeof(pos)); if (get_config_line(file, &line, &line_max, &line_max_increased, &pos) != 0) goto error; if (line_max_increased) { line_copy = (char *)realloc(line_copy, sizeof(char) * line_max); if (line_copy == NULL) { RPMEMD_LOG(ERR, "!malloc"); goto error_malloc_line_copy; } line_max_increased = 0; } if (pos.EOL_char != INVALID_CHAR_POS) { strcpy(line_copy, line); parse_config_line(line_copy, &pos, config, disabled); if (errno != 0) { size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0'; RPMEMD_LOG(ERR, "Invalid config file line at " "%s:%lu\n%s", filename, line_num, line); goto error; } } ++line_num; } while (pos.EOL_char != INVALID_CHAR_POS); free(line_copy); free(line); fclose(file); default_config_missing: return 0; error: free(line_copy); error_malloc_line_copy: free(line); error_malloc_line: fclose(file); error_fopen: return -1; }
int main(int argc, char *argv[]) { START(argc, argv, "rpmemd_log"); if (argc < 4) { USAGE(); return 1; } const char *log_op = argv[1]; const char *log_type = argv[2]; const char *file = argv[3]; int do_fatal = 0; int do_assert = 0; if (strcmp(log_op, "fatal") == 0) { do_fatal = 1; } else if (strcmp(log_op, "assert") == 0) { do_assert = 1; } else if (strcmp(log_op, "log") == 0) { } else { USAGE(); return 1; } enum test_log_type type; if (strcmp(log_type, "stdout") == 0) { type = TEST_STDOUT; } else if (strcmp(log_type, "file") == 0) { type = TEST_FILE; } else if (strcmp(log_type, "syslog") == 0) { type = TEST_SYSLOG; } else { USAGE(); return 1; } int fd_stdout = -1; FILE *stdout_fh = NULL; switch (type) { case TEST_STDOUT: /* * Duplicate stdout file descriptor in order to preserve * the file list after redirecting the stdout to a file. */ fd_stdout = dup(1); UT_ASSERTne(fd_stdout, -1); close(1); stdout_fh = fopen(file, "a"); UT_ASSERTne(stdout_fh, NULL); break; case TEST_SYSLOG: syslog_fh = fopen(file, "a"); UT_ASSERTne(syslog_fh, NULL); break; default: break; } /* * Check an invalid configuration */ int ret; ret = rpmemd_log_init("rpmemd_log", file, 1); UT_ASSERTne(ret, 0); switch (type) { case TEST_STDOUT: ret = rpmemd_log_init("rpmemd_log", NULL, 0); UT_ASSERTeq(ret, 0); break; case TEST_SYSLOG: ret = rpmemd_log_init("rpmemd_log", NULL, 1); UT_ASSERTeq(ret, 0); break; case TEST_FILE: ret = rpmemd_log_init("rpmemd_log", file, 0); UT_ASSERTeq(ret, 0); break; default: break; } if (do_fatal) { RPMEMD_FATAL("fatal"); } else if (do_assert) { RPMEMD_ASSERT(1); RPMEMD_ASSERT(0); } else { test_all_log_messages(); } rpmemd_log_close(); switch (type) { case TEST_STDOUT: /* restore the original stdout file descriptor */ fclose(stdout_fh); UT_ASSERTeq(dup2(fd_stdout, 1), 1); close(fd_stdout); break; case TEST_SYSLOG: fclose(syslog_fh); break; default: break; } DONE(NULL); }
/* * rpmemd_req_open -- handle open request */ static int rpmemd_req_open(struct rpmemd_obc *obc, void *arg, const struct rpmem_req_attr *req) { RPMEMD_ASSERT(arg != NULL); struct rpmemd *rpmemd = (struct rpmemd *)arg; int ret; int status = 0; int err_send = 1; struct rpmem_resp_attr resp; memset(&resp, 0, sizeof(resp)); struct rpmem_pool_attr pool_attr; memset(&pool_attr, 0, sizeof(pool_attr)); if (rpmemd->pool) { RPMEMD_LOG(ERR, "pool already opened"); status = RPMEM_ERR_FATAL; goto err_pool_opened; } rpmemd->pool = rpmemd_db_pool_open(rpmemd->db, req->pool_desc, 0, &pool_attr); if (!rpmemd->pool) { status = rpmemd_db_get_status(errno); goto err_pool_open; } ret = rpmemd_check_pool(rpmemd, req, &status); if (ret) goto err_pool_check; ret = rpmemd_common_fip_init(rpmemd, req, &resp, &status); if (ret) goto err_fip_init; ret = rpmemd_obc_open_resp(rpmemd->obc, status, &resp, &pool_attr); if (ret) { err_send = 0; goto err_open_resp; } ret = rpmemd_fip_accept(rpmemd->fip); if (ret) { status = RPMEM_ERR_FATAL_CONN; goto err_accept; } ret = rpmemd_fip_process_start(rpmemd->fip); if (ret) { status = RPMEM_ERR_FATAL_CONN; goto err_process_start; } return 0; err_process_start: rpmemd_fip_close(rpmemd->fip); err_accept: err_send = 0; err_open_resp: rpmemd_fip_fini(rpmemd->fip); err_fip_init: err_pool_check: rpmemd_db_pool_close(rpmemd->db, rpmemd->pool); err_pool_open: err_pool_opened: if (err_send) ret = rpmemd_obc_open_resp(rpmemd->obc, status, &resp, &pool_attr); rpmemd->closing = 1; return ret; }
/* * rpmemd_common_fip_init -- initialize fabric provider */ static int rpmemd_common_fip_init(struct rpmemd *rpmemd, const struct rpmem_req_attr *req, struct rpmem_resp_attr *resp, int *status) { void *addr = (void *)((uintptr_t)rpmemd->pool->pool_addr + POOL_HDR_SIZE); struct rpmemd_fip_attr fip_attr = { .addr = addr, .size = req->pool_size, .nlanes = req->nlanes, .nthreads = rpmemd->nthreads, .provider = req->provider, .persist_method = rpmemd->persist_method, .persist = rpmemd->persist, }; const char *node = rpmemd_get_ssh_addr(); enum rpmem_err err; rpmemd->fip = rpmemd_fip_init(node, NULL, &fip_attr, resp, &err); if (!rpmemd->fip) { *status = (int)err; goto err_fip_init; } return 0; err_fip_init: return -1; } /* * rpmemd_req_create -- handle create request */ static int rpmemd_req_create(struct rpmemd_obc *obc, void *arg, const struct rpmem_req_attr *req, const struct rpmem_pool_attr *pool_attr) { RPMEMD_ASSERT(arg != NULL); struct rpmemd *rpmemd = (struct rpmemd *)arg; int ret; int status = 0; int err_send = 1; struct rpmem_resp_attr resp; memset(&resp, 0, sizeof(resp)); if (rpmemd->pool) { RPMEMD_LOG(ERR, "pool already opened"); status = RPMEM_ERR_FATAL; goto err_pool_opened; } rpmemd->pool = rpmemd_db_pool_create(rpmemd->db, req->pool_desc, 0, (struct rpmem_pool_attr *)pool_attr); if (!rpmemd->pool) { status = rpmemd_db_get_status(errno); goto err_pool_create; } ret = rpmemd_check_pool(rpmemd, req, &status); if (ret) goto err_pool_check; ret = rpmemd_common_fip_init(rpmemd, req, &resp, &status); if (ret) goto err_fip_init; ret = rpmemd_obc_create_resp(rpmemd->obc, status, &resp); if (ret) { err_send = 0; goto err_create_resp; } ret = rpmemd_fip_accept(rpmemd->fip); if (ret) { status = RPMEM_ERR_FATAL_CONN; goto err_accept; } ret = rpmemd_fip_process_start(rpmemd->fip); if (ret) { status = RPMEM_ERR_FATAL_CONN; goto err_process_start; } return 0; err_process_start: rpmemd_fip_close(rpmemd->fip); err_accept: err_send = 0; err_create_resp: rpmemd_fip_fini(rpmemd->fip); err_fip_init: err_pool_check: rpmemd_db_pool_close(rpmemd->db, rpmemd->pool); rpmemd_db_pool_remove(rpmemd->db, req->pool_desc); err_pool_create: err_pool_opened: if (err_send) ret = rpmemd_obc_create_resp(rpmemd->obc, status, &resp); rpmemd->closing = 1; return ret; }