/** * Receive incoming pings through Examsg. * * \param[out] ping Received ping * * \return true if a ping was received, false otherwise */ bool sup_recv_ping(sup_ping_t *ping) { /* initialized to 0s, this will trigger a ping at the very beginning */ static struct timeval timeout = { 0, 0 }; ExamsgMID mid; sup_ping_msg_t msg; int err; err = examsgWaitTimeout(sup_mh, &timeout); if (err < 0 && err != -ETIME) { __error("encountered an error while waiting for messages : %s (%d)", exa_error_msg(err), err); return false; } if (err == -ETIME) { do_ping = true; timeout.tv_sec = ping_period; timeout.tv_usec = 0; return false; } err = examsgRecv(sup_mh, &mid, &msg, sizeof(msg)); /* XXX shouldn't happen (?) because of examsgWaitTimeout() above, * but it *does* happen at clstop */ if (err == 0) return false; if (err < 0) { __error("encountered an error while retrieving message : %s (%d)", exa_error_msg(err), err); return false; } EXA_ASSERT(err == sizeof(msg)); EXA_ASSERT(msg.any.type == EXAMSG_SUP_PING); *ping = msg.ping; return true; }
/** * Process an event from a local mailbox. * * \param[in,out] pi Ping info * * \return 1 if processed an event 0 if not, negative error code otherwise */ static int local_mbox_event(ping_info_t *pi) { ExamsgMID mid; static Examsg ev; int ev_size; int s; ev_size = examsgRecv(local_mh, &mid, &ev, sizeof(ev)); if (ev_size <= 0) return 0; switch (ev.any.type) { case EXAMSG_EXIT: { exa_nodeset_t dest_nodes; quit = true; exa_nodeset_single(&dest_nodes, mid.netid.node); examsgAckReply(local_mh, &ev, EXA_SUCCESS, mid.id, &dest_nodes); } /* Return 0 because, despite we received a message, we do not want the * main loop to continue to process messages as it is asked to stop now. * So returning 0 juste means here "no need to read anymore messages" */ return 0; case EXAMSG_SUP_PING: if (network_status() == 0) network_special_send(&mid, &ev, ev_size); break; case EXAMSG_ADDNODE: { exa_nodeset_t dest_nodes; examsg_node_info_msg_t *info = (examsg_node_info_msg_t *)&ev; s = network_add_node(info->node_id, info->node_name); exa_nodeset_single(&dest_nodes, mid.netid.node); examsgAckReply(local_mh, &ev, s, mid.id, &dest_nodes); } break; case EXAMSG_DELNODE: { exa_nodeset_t dest_nodes; s = network_del_node(((examsg_node_info_msg_t *)&ev)->node_id); exa_nodeset_single(&dest_nodes, mid.netid.node); examsgAckReply(local_mh, &ev, s, mid.id, &dest_nodes); } break; case EXAMSG_RETRANSMIT_REQ: if (network_status() == 0) { ExamsgRetransmitReq *retreq = (ExamsgRetransmitReq *)&ev; exalog_debug("will send a retransmit request for %d to %u", retreq->count, retreq->node_id); s = network_send_retransmit_req(retreq->node_id, retreq->count); EXA_ASSERT(s == 0); reset_ping(pi); } break; case EXAMSG_RETRANSMIT: if (network_status() == 0) { ExamsgRetransmit *retr = (ExamsgRetransmit *)&ev; exalog_debug("will retransmit messages: %d", retr->count); retransmit(retr->count); reset_ping(pi); } break; case EXAMSG_FENCE: { const examsgd_fencing_req_t *req = &((examsgd_fencing_req_msg_t *)&ev)->request; network_handle_fence_request(req); } break; case EXAMSG_NEW_COMER: reset_ping(pi); break; default: { exa_nodeset_t dest_nodes; exa_nodeset_single(&dest_nodes, mid.netid.node); examsgAckReply(local_mh, &ev, EINVAL, mid.id, &dest_nodes); exalog_error("got unknown message (type %d)", ev.any.type); EXA_ASSERT(false); } break; } return 1; }
static void check_internal_msg(void) { struct timeval timeout = { .tv_sec = 0, .tv_usec = EXAMSG_TIMEOUT }; static Examsg msg; command_end_t *end; int i, ret; ret = examsgWaitTimeout(cli_mh, &timeout); if (ret < 0 && ret != -ETIME) { exalog_error("Message wait failed %s (%d)", exa_error_msg(ret), ret); return; } if (ret == -ETIME) return; ret = examsgRecv(cli_mh, NULL, &msg, sizeof(msg)); if (ret == 0) return; EXA_ASSERT_VERBOSE(ret > 0, "Message receive failed: %s (%d)", exa_error_msg(ret), ret); if (ret < 0) exalog_error("Message receive failed: %s (%d)", exa_error_msg(ret), ret); /* The CLI server can only receive EXAMSG_ADM_CLUSTER_CMD_END messages for now */ EXA_ASSERT(msg.any.type == EXAMSG_ADM_CLUSTER_CMD_END); end = (command_end_t *)msg.payload; for (i = 0; i < MAX_CONNECTION; i++) if (end->cuid == connectlist[i].uid) { cli_command_end_complete(connectlist[i].fd, &end->err_desc); connectlist[i].uid = CMD_UID_INVALID; break; } EXA_ASSERT(i < MAX_CONNECTION); } static void check_tcp_connection(void) { static struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; fd_set setSave = setSocks; int ret, conn_id; do ret = os_select(FD_SETSIZE, &setSave, NULL, NULL, &timeout); while (ret == -EINTR); if (ret < 0) { /* FIXME should assert ? */ exalog_debug("Select failed %m"); return; } /* Check working sockets */ for (conn_id = 0; conn_id < MAX_CONNECTION; ++conn_id) { int sock_fd = connectlist[conn_id].fd; if (sock_fd >= 0 && FD_ISSET(sock_fd, &setSave)) handle_inputdata(conn_id, sock_fd); } /* Must be done at the end to make sure messages for current * working threads are processed first */ if (FD_ISSET(listen_fd, &setSave)) accept_new_client(); } /*-------------------------------------------------------------------------*/ /** \brief Connection thread: wait on xml message and pass the command * to the work thread. * * \param[in] sock_xml: socket xml on which it receives commands. * */ /*-------------------------------------------------------------------------*/ static void cli_server(void *data) { int i; /* Initialize exalog */ exalog_as(EXAMSG_ADMIND_ID); exalog_debug("cli_server: started"); /* Initialization */ FD_ZERO(&setSocks); FD_SET(listen_fd, &setSocks); for (i = 0; i < MAX_CONNECTION; i++) { connectlist[i].fd = -1; /* A command cannot be CMD_UID_INVALID, so CMD_UID_INVALID means here * no command running */ connectlist[i].uid = CMD_UID_INVALID; } while (!stop) { check_tcp_connection(); check_internal_msg(); } os_closesocket(listen_fd); os_net_cleanup(); examsgDelMbox(cli_mh, EXAMSG_ADMIND_CLISERVER_ID); examsgExit(cli_mh); } int cli_server_start(void) { listen_fd = listen_socket_port(ADMIND_SOCKET_PORT); if (listen_fd < 0) return listen_fd; cli_mh = examsgInit(EXAMSG_ADMIND_CLISERVER_ID); if (!cli_mh) return -EINVAL; /* The mailbox needs to be able to receive command end messages from the * event manager; as there can be at most MAX_CONNECTION client connections * we can receive at the time at most 10 command end messages. */ examsgAddMbox(cli_mh, EXAMSG_ADMIND_CLISERVER_ID, MAX_CONNECTION, sizeof(command_end_t)); stop = false; if (!exathread_create_named(&thr_xml_proto, ADMIND_THREAD_STACK_SIZE+MIN_THREAD_STACK_SIZE, &cli_server, NULL, "exa_adm_xml")) return -EXA_ERR_DEFAULT; return EXA_SUCCESS; }
void rebuild_helper_thread(void *p) { ExamsgHandle mh; int err; exalog_as(EXAMSG_NBD_SERVER_ID); /* initialize examsg framework */ mh = examsgInit(EXAMSG_NBD_LOCKING_ID); EXA_ASSERT(mh != NULL); err = examsgAddMbox(mh, EXAMSG_NBD_LOCKING_ID, 1, 5 * EXAMSG_MSG_MAX); EXA_ASSERT(err == 0); os_sem_post(&nbd_server.mailbox_sem); while (nbd_server.run) { device_t *device; ExamsgNbdLock nbd_lock_msg; ExamsgMID from; struct timeval timeout = { .tv_sec = 0, .tv_usec = 100000 }; exa_nodeset_t dest_nodes; err = examsgWaitTimeout(mh, &timeout); /* Just in order to check stopping the thread is required*/ if (err == -ETIME) continue; if (err != 0) { exalog_error("Locking thread encountered error %s (%d) while " "waiting in event loop.", exa_error_msg(err), err); continue; } err = examsgRecv(mh, &from, &nbd_lock_msg, sizeof(nbd_lock_msg)); /* No message */ if (err == 0) continue; if (err < 0) { exalog_error("Locking thread encountered error %s (%d) while " "receiving a messsage.", exa_error_msg(err), err); continue; } switch(nbd_lock_msg.any.type) { case EXAMSG_NBD_LOCK: /* find device from name */ /* FIXME devices lock is not held... it should */ device = find_device_from_uuid(&nbd_lock_msg.disk_uuid); if (device == NULL) { exalog_error("Unknown device with UUID " UUID_FMT, UUID_VAL(&nbd_lock_msg.disk_uuid)); err = -CMD_EXP_ERR_UNKNOWN_DEVICE; break; } if (nbd_lock_msg.lock) { err = exa_disk_lock_zone(device, nbd_lock_msg.locked_zone_start, nbd_lock_msg.locked_zone_size); EXA_ASSERT_VERBOSE(err == 0, "Trying to lock too many zone " "(>%d). Last zone not succesfully locked " "(start = %" PRId64 ", size = %" PRId64 " ) " "on device UUID " UUID_FMT, NBMAX_DISK_LOCKED_ZONES, nbd_lock_msg.locked_zone_start, nbd_lock_msg.locked_zone_size, UUID_VAL(&nbd_lock_msg.disk_uuid)); } else { err = exa_disk_unlock_zone(device, nbd_lock_msg.locked_zone_start, nbd_lock_msg.locked_zone_size); EXA_ASSERT_VERBOSE(err == 0, "Trying to unlock a never locked " "zone (unlocked zone start =%" PRId64 ", " "unlocked zone size = %" PRId64 ") on device" " UUID " UUID_FMT, nbd_lock_msg.locked_zone_start, nbd_lock_msg.locked_zone_size, UUID_VAL(&nbd_lock_msg.disk_uuid)); } break; default: /* error */ EXA_ASSERT_VERBOSE(false, "Locking thread got unknown message of" " type %d ", nbd_lock_msg.any.type); break; } exa_nodeset_single(&dest_nodes, from.netid.node); examsgAckReply(mh, (Examsg *)&nbd_lock_msg, err, from.id, &dest_nodes); } examsgDelMbox(mh, EXAMSG_NBD_LOCKING_ID); examsgExit(mh); } /** get the number of sector of the device * \param device_path the device to get the number of sector * \param nb_sectors64 the number of sectors of the device * \return nb_sectors the returned number of sector */ static int get_nb_sectors(const char *device_path, uint64_t *nb_sectors) { uint64_t device_size; /* in bytes */ int retval; int fd; /* We need the read access to get the size. */ if ((fd = os_disk_open_raw(device_path, OS_DISK_READ)) < 0) { exalog_error("cannot open device '%s' error=%s ", device_path, exa_error_msg(-fd)); return -CMD_EXP_ERR_OPEN_DEVICE; } retval = os_disk_get_size(fd, &device_size); if (retval < 0) { exalog_error("os_disk_get_size() error=%s", exa_error_msg(retval)); if (close(fd) != 0) exalog_error("can't EVEN close dev '%s'", device_path); return -EXA_ERR_IOCTL; } retval = close(fd); if (retval < 0) { retval = -errno; exalog_error("cannot close device '%s' error=%s ", device_path, exa_error_msg(retval)); return -CMD_EXP_ERR_CLOSE_DEVICE; } *nb_sectors = device_size / SECTOR_SIZE; /* remove the size of the reserved area for storing admind info */ *nb_sectors -= RDEV_RESERVED_AREA_IN_SECTORS; /* Align the size on 1K * this is the best we can do to have the same size of devices on 2.4 and 2.6 kernels due to * the fact that kernel 2.4 rounds the size of devices with 1 K */ *nb_sectors -= *nb_sectors % (1024 / SECTOR_SIZE); return EXA_SUCCESS; }