Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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);
    }
}
Ejemplo n.º 3
0
/**
 * 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);
    }
}
Ejemplo n.º 4
0
/** \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);
}
Ejemplo n.º 5
0
/**
 * 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;
	}
    }
}
Ejemplo n.º 6
0
/*
 * 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(&eth.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(&eth.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(&eth.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);
}
Ejemplo n.º 7
0
/* 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(&eth.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(&eth.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(&eth.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(&eth.send_list[i].root->free,
                                  request->payload, -1);
                    request_reset(request);
                    break;

                case DATA_TRANSFER_ERROR:
                    nbd_list_post(&eth.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);
}
Ejemplo n.º 8
0
/**
 * 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);
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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);
  }
}
Ejemplo n.º 11
0
ut_setup()
{
    exalog_as(EXAMSG_TEST_ID);
    os_random_init();
}
Ejemplo n.º 12
0
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;
}