int main(int argc, char *argv[]) { exalog_as(EXAMSG_TEST_ID); exalog_configure(EXAMSG_TEST_ID, EXALOG_LEVEL_DEBUG); exalog_debug("You should see this"); exalog_error("You should see this too"); exalog_configure(EXAMSG_TEST_ID, EXALOG_LEVEL_ERROR); exalog_debug("You shouldn't see this"); exalog_error("But you should see this"); return 0; }
/** * Start the thread * * \return void */ static void fsd_workthread_run(void * arg) { struct daemon_request_queue *queue = arg; exalog_as(EXAMSG_FSD_ID); while (1) { FSRequest req; ExamsgID from; /* fsd_queue_get_request() blocks until a request income */ daemon_request_queue_get_request(queue, &req, sizeof(req), &from); /* handle the request and send the reply */ fsd_handle_fs_request(queue, &req, from); } }
/** * Thread responsible for accepting connections * * It's a separate thread because we accept do some memory allocation and we * must avoid that in recv thread. * * @param unused Unused parameter */ static void accept_thread(void *unused) { exalog_as(EXAMSG_ISCSI_ID); while (algopr_run) { exa_nodeid_t node_id; const char *ip_addr; struct sockaddr_in client_address; int size = sizeof(client_address); int sock = os_accept(eth.accept_sock, (struct sockaddr *)&client_address, &size); if (sock < 0) continue; /* it's a false accept */ ip_addr = os_inet_ntoa(client_address.sin_addr); if (!suspended) { exalog_warning("Closing incoming connection from %s while not" " suspended.", ip_addr); __close_socket(sock); continue; } internal_setsock_opt(sock, SOCK_FLAGS); node_id = get_peer_id_from_ip_addr(ip_addr); if (!EXA_NODEID_VALID(node_id)) { exalog_warning("Closing incoming connection from unknown node %s.", ip_addr); __close_socket(sock); continue; } set_peer_socket(node_id, ip_addr, sock); } }
/** \brief Initialization of examsgd daemon. * * Command line must contain the node name and the interface name to use * for control messages. * * Accepts hidden option -d (debugging mode). * * \param[in] argc Argument count. * \param[in] argv Array of argument values. * * \return exit code. */ int daemon_init(int argc, char *argv[]) { int s; /* getopt variables */ static struct option long_opts[] = { { "cluster-id", required_argument, NULL, 'c' }, { "help", no_argument, NULL, 'h' }, { "hostname", required_argument, NULL, 'N' }, { "incarnation", required_argument, NULL, 'I' }, { "mcast-addr", required_argument, NULL, 'm' }, { "mcast-port", required_argument, NULL, 'p' }, { "node-id", required_argument, NULL, 'i' }, { "node-name", required_argument, NULL, 'n' }, { "stats", no_argument, NULL, 's' }, { NULL, 0, NULL, 0 } }; int long_idx, c; char *e; extern char *optarg; extern int optind; /* configurable options and default values */ const char *node_name = NULL; const char *hostname = NULL; const char *mgroup = EXAMSG_MCASTIP; unsigned short mport = EXAMSG_PORT; unsigned short inca = 0; exa_uuid_t cluster_uuid; exa_nodeid_t nodeid; bool err = false; uuid_zero(&cluster_uuid); nodeid = EXA_NODEID_NONE; /* options parsing */ while ((c = os_getopt_long(argc, argv, "c:dhi:I:m:n:N:p:s", long_opts, &long_idx)) != -1) switch (c) { case 'c': if (uuid_scan(optarg, &cluster_uuid) < 0) { fprintf(stderr, "invalid cluster id: '%s'\n", optarg); return -EINVAL; } break; case 'i': nodeid = (exa_nodeid_t)strtol(optarg, &e, 10); if (*e || !EXA_NODEID_VALID(nodeid)) { fprintf(stderr, "invalid node id: '%s'\n", optarg); return -EINVAL; } break; case 'I': inca = (unsigned short)strtol(optarg, &e, 10); if (*e || inca == 0) { fprintf(stderr, "invalid incarnation: '%s'\n", optarg); return -EINVAL; } break; /* multicast group */ case 'm': mgroup = optarg; break; case 'n': node_name = optarg; break; /* hostname */ case 'N': hostname = optarg; break; /* communication port */ case 'p': mport = strtol(optarg, &e, 0); if (*e != '\0') { fprintf(stderr, "invalid port number '%s'\n", optarg); return -EINVAL; } break; case 's': examsg_show_stats(); return 0; break; /* usage */ case 'h': case '?': default: usage(argv[0]); return -EINVAL; } if (uuid_is_zero(&cluster_uuid)) { fprintf(stderr, "missing cluster id\n"); err = true; } if (nodeid == EXA_NODEID_NONE) { fprintf(stderr, "missing node id\n"); err = true; } if (node_name == NULL) { fprintf(stderr, "missing node name\n"); err = true; } if (hostname == NULL) { fprintf(stderr, "missing hostname\n"); err = true; } if (inca == 0) { fprintf(stderr, "missing incarnation\n"); err = true; } if (err) return -EINVAL; /* Get cluster id, number of nodes, node id, node name and interface parameters */ if (argc - optind != 0) { fprintf(stderr, "stray parameters\n"); usage(argv[0]); return -EINVAL; } signal(SIGTERM, sig_term); signal(SIGINT, sig_term); s = examsg_static_init(EXAMSG_STATIC_GET); if (s) { fprintf(stderr, "Can't initialize messaging layer."); return s; } exalog_static_init(); /* Log as exa_msgd by default */ exalog_as(EXAMSG_CMSGD_ID); #ifdef USE_YAOURT if (yaourt_init()) exalog_debug("Yaourt: Examsgd init OK"); else exalog_warning("Yaourt: Examsgd init FAILED (%s)", yaourt_error); #endif /* set up network communication */ return startup(&cluster_uuid, node_name, hostname, nodeid, mgroup, mport, inca); }
/** * Thread processing network events (coming from other nodes). * * This routine may set the network status to down as a side-effect * of calling network_recv(), and sets said status to up when the * network comes back. * * \param[in] dummy Unused * * \return NULL */ static void net_events_routine(void *dummy) { int dest_mbox; ExamsgMID mid; size_t size; char *msg; int s; exalog_as(EXAMSG_CMSGD_ID); exalog_trace("network events routine started"); while (!quit) { int status = network_status(); bool retry; if (status == -ENETDOWN) { network_waitup(); network_set_status(0); } do { s = network_recv(net_mh, &mid, &msg, &size, &dest_mbox); retry = (s < 0 && network_manageable(s) && s != -ENETDOWN); if (retry) os_sleep(1); } while (retry); /* Succeeded, the network status is ok */ if (s > 0 && status != 0) network_set_status(0); if (s == 0 || s == -ENETDOWN) continue; EXA_ASSERT(s > 0); /* Ping from another node for keepalive */ if (((ExamsgAny *)msg)->type == EXAMSG_PING) { EXA_ASSERT(dest_mbox == EXAMSG_CMSGD_ID); exalog_trace("received an EXAMSG_PING from %u:%s", mid.netid.node, mid.host); continue; } exalog_trace("delivering %" PRIzu " bytes to %d", size, dest_mbox); s = examsgMboxSend(&mid, examsgOwner(net_mh), dest_mbox, msg, size); switch (s) { case -ENXIO: /* The mailbox does not exist (yet). This is not an error: csupd may * not be started yet and we receive an examsg for it. * XXX Doesn't sound too good to me, and we should at least check that * the destination is indeed csupd */ break; case -ENOSPC: mailbox_full(dest_mbox, &mid, (Examsg *)msg); break; default: EXA_ASSERT_VERBOSE(s == size + sizeof(mid), "Error %d delivering message to %d", s, dest_mbox); break; } } }
/* * thread responsible for receiving data for a client or a server * note when we add client, this client is effectively added in the receive queue * only few second later due to the select timeout of 3 seconds * and there are the same problem for the deleteion of a client */ static void algopr_receive_thread(void *unused) { struct pending_request pending_requests[EXA_MAX_NODES_NUMBER]; exa_select_handle_t *sh = exa_select_new_handle(); int i; int ret; payload_t *payload = NULL; struct nbd_root_list root_list_recv; /* FIXME: handle the case when we have more than 1024 open file (limit of fd_set) */ fd_set fds; exalog_as(EXAMSG_ISCSI_ID); nbd_init_root(EXA_MAX_NODES_NUMBER, sizeof(payload_t), &root_list_recv); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) request_reset(&pending_requests[i]); while (algopr_run) { int nfds = 0; FD_ZERO(&fds); /* if one node is added or deleted, this deletion or addition are effective after this */ os_thread_mutex_lock(&peers_lock); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) { int fd_act = __get_peer_socket(i); if (fd_act < 0) { payload_t *temp_payload; temp_payload = request_reset(&pending_requests[i]); if (temp_payload != NULL) { if (pending_requests[i].big_buffer) nbd_list_post(ð.root_list_big_recv.free, temp_payload->buffer, -1); nbd_list_post(&root_list_recv.free, temp_payload, -1); } temp_payload = NULL; continue; } FD_SET(fd_act, &fds); nfds = fd_act > nfds ? fd_act : nfds; } os_thread_mutex_unlock(&peers_lock); ret = exa_select_in(sh, nfds + 1, &fds); if (ret != 0 && ret != -EFAULT) exalog_error("Select upon receive failed: %s (%d)", os_strerror(-ret), ret); os_thread_mutex_lock(&peers_lock); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) { struct pending_request *req; int fd_act; fd_act = __get_peer_socket(i); if (fd_act < 0 || !FD_ISSET(fd_act, &fds)) continue; req = &pending_requests[i]; /* WARNING payload is kept from an iteration of while loop to * another, so the variable MUST be global. */ /* FIXME Remove the nbdlist which is useless as we already know * that we NEED EXA_MAX_NODES_NUMBER payload_t elements to be able * to receive simultaneously from EXA_MAX_NODES_NUMBER nodes * FIXME the LISTWAIT flag below is WRONG because waiting here * would mean deadlock... hopefully there are enough elements, and * we never wait.... */ if (payload == NULL) { payload = nbd_list_remove(&root_list_recv.free, NULL, LISTWAIT); EXA_ASSERT(payload != NULL); } if (request_init_transfer(payload, req) == 1) payload = NULL; ret = request_receive(fd_act, req); if (ret == DATA_TRANSFER_NEED_BIG_BUFFER) { req->payload->buffer = nbd_list_remove(ð.root_list_big_recv.free, NULL, LISTWAIT); EXA_ASSERT(req->payload->buffer != NULL); req->big_buffer = true; /* here we just continue because it is forbidden to call * request_receive without passing into select (as sockets are * blocking, we may remain blocked on the recv of nothing) */ continue; } if (ret == DATA_TRANSFER_PENDING) continue; if (ret == DATA_TRANSFER_ERROR) { payload_t *temp_payload = request_reset(req); if (req->big_buffer) nbd_list_post(ð.root_list_big_recv.free, temp_payload->buffer, -1); nbd_list_post(&root_list_recv.free, temp_payload, -1); __disconnect_from_peer(i); if (!suspended) exalog_warning("Failed receiving from peer %" PRInodeid " (socket %d): transfer error.", i, fd_act); continue; } if (ret == DATA_TRANSFER_COMPLETE) { payload_t *_payload = request_reset(req); /* update data network checking data */ algopr_new_msg(_payload->payload, _payload->size1, _payload->buffer, _payload->size2); nbd_list_post(&root_list_recv.free, _payload, -1); } } os_thread_mutex_unlock(&peers_lock); } nbd_close_root(&root_list_recv); exa_select_delete_handle(sh); }
/* thread for asynchronously sending data for a client or a server */ static void algopr_send_thread(void *unused) { struct pending_request pending_requests[EXA_MAX_NODES_NUMBER]; int i; exa_select_handle_t *sh = exa_select_new_handle(); exalog_as(EXAMSG_ISCSI_ID); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) request_reset(&pending_requests[i]); while (algopr_run) { fd_set fds; int nfds = 0; bool active_sock = false; FD_ZERO(&fds); /* if one node is added or deleted, this deletion or addition are effective after this */ os_thread_mutex_lock(&peers_lock); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) { int fd_act = __get_peer_socket(i); if (fd_act < 0) { /* release all buffer of clients who's sockets were closed */ payload_t *payload = request_reset(&pending_requests[i]); if (payload != NULL) nbd_list_post(ð.send_list[i].root->free, payload, -1); /* release all pending messages for node i: connection is dead, * those messages will never be delivered anyway. */ drop_all_messages_for_node(i); continue; } if (!pending_requests[i].used) { /* pick a new request if no one is in progress for this peer */ payload_t *payload = nbd_list_remove(ð.send_list[i], NULL, LISTNOWAIT); if (payload) request_init_transfer(payload, &pending_requests[i]); } if (pending_requests[i].used) { /* if buffers are waiting to be sent, add peer to select list */ FD_SET(fd_act, &fds); nfds = fd_act > nfds ? fd_act : nfds; active_sock = true; } } os_thread_mutex_unlock(&peers_lock); if (!active_sock) { wq_wait(ð.wq_send); /* we were waiting for new requests to send, someone signaled us * so restart the loop and look for new request. */ continue; } exa_select_out(sh, nfds + 1, &fds); os_thread_mutex_lock(&peers_lock); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) { struct pending_request *request = &pending_requests[i]; int fd_act = __get_peer_socket(i); if (fd_act >= 0 && pending_requests[i].used && FD_ISSET(fd_act, &fds)) { /* send remaining data if any */ int ret = request_send(fd_act, request); switch (ret) { case DATA_TRANSFER_COMPLETE: nbd_list_post(ð.send_list[i].root->free, request->payload, -1); request_reset(request); break; case DATA_TRANSFER_ERROR: nbd_list_post(ð.send_list[i].root->free, request->payload, -1); request_reset(request); break; case DATA_TRANSFER_PENDING: break; } } } os_thread_mutex_unlock(&peers_lock); } exa_select_delete_handle(sh); }
/** * Main thread to process disk, each disk have an instance of this thread * @param p the (device_t *) that describe this disk * @return */ void exa_td_main(void *p) { bool pending_io = false; device_t *disk_device; char myname[32]; exalog_as(EXAMSG_NBD_SERVER_ID); disk_device = (device_t *)p; os_snprintf(myname, 31, "serv%s", disk_device->path); exa_thread_name_set(myname); memset(&disk_device->locked_zone, 0xEE, sizeof(disk_device->locked_zone)); disk_device->nb_locked_zone = 0; #define run (!disk_device->exit_thread) while (run) { int err; header_t *req = pick_one_req(disk_device); if (req == NULL && pending_io) { /* NOTE: This code make the thread to wait for the completion * of at least one IO for an indefinite time (it calls * 'exa_rdev_wait_one_request'). If during this time a new * request occurs it will not be sent to the disk and I think it * can cause some performance problems. * * The point here is that we must poll the block device to be * noticed of the IO completion. One can convince himself of the * problem by looking at 'exa_rdev_make_request_new' * prototype. This function sends a new request to a device but * it also gets the reply for some other request. */ err = wait_and_complete_one_io(disk_device); if (err == RDEV_REQUEST_ALL_ENDED) pending_io = false; continue; } else if (req == NULL && !pending_io) do { req = wait_new_req(disk_device, 200 /* timeout in ms */); } while (req == NULL && run); /* If req != NULL, the request must be handled otherwise it would be * leaked. So even if run is false, we submit the IO and then exit the * loop, the wait_for_all_completion will eventually make sure that any * pending IOs was answerd. */ if (req == NULL) break; /* being here means a req needs to be handled */ EXA_ASSERT(req != NULL); do { err = submit_req(disk_device, &req); if (err == RDEV_REQUEST_NOT_ENOUGH_FREE_REQ) { /* There was no room in kernel for this IO, thus * we try to complete pending IOs to make some free * space in kernel. */ int err2 = wait_and_complete_one_io(disk_device); /* There MUST be pending IOs thus kernel cannot return * RDEV_REQUEST_ALL_ENDED */ EXA_ASSERT(err2 != RDEV_REQUEST_ALL_ENDED); } else pending_io = true; } while (err == RDEV_REQUEST_NOT_ENOUGH_FREE_REQ); EXA_ASSERT(means_finished(err) || err == RDEV_REQUEST_NONE_ENDED); if (means_finished(err)) handle_completed_io(disk_device, req); } /* Before leaving, make sure that all requests were successfully answerd * by kernel. */ __wait_for_all_completion(disk_device); }
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; }
static void disk_checking_thread(void *dummy) { exalog_as(EXAMSG_RDEV_ID); while (!quit) { int rdev_need_check = false; struct adm_disk *disk; adm_node_lock_disk_removal(); adm_node_for_each_disk(adm_myself(), disk) { if (disk->local->rdev_req != NULL) { int state, last_state; last_state = disk->local->state; state = exa_rdev_test(disk->local->rdev_req, rdev_check_buffer, RDEV_SUPERBLOCK_SIZE); /* if exa_rdev_test returns an error, the disk is considered in failure * as we have no mean to know what really happened. */ if (state < 0) { exalog_error("testing rdev '%s' " UUID_FMT " failed: %s (%d)", disk->path, UUID_VAL(&disk->uuid), exa_error_msg(state), state); state = EXA_RDEV_STATUS_FAIL; } if (state != last_state) { if (state == EXA_RDEV_STATUS_FAIL) rdev_need_check = true; disk->local->state = state; } } } adm_node_unlock_disk_removal(); if (quit) break; if (rdev_need_check) { instance_event_msg_t msg; int ret; msg.any.type = EXAMSG_EVMGR_INST_EVENT; msg.event.id = EXAMSG_RDEV_ID; msg.event.state = INSTANCE_CHECK_DOWN; msg.event.node_id = adm_myself()->id; exalog_info("... broadcasting action: rdev check down"); ret = examsgSend(mh, EXAMSG_ADMIND_EVMGR_ID, EXAMSG_ALLHOSTS, &msg, sizeof(msg)); EXA_ASSERT(ret == sizeof(msg)); } os_sleep(DISK_CHECK_INTERVAL); } }
ut_setup() { exalog_as(EXAMSG_TEST_ID); os_random_init(); }
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; }