Exemple #1
0
/**
 * Create a volume in a given group
 *
 * @param[in] params The parsed command array
 *
 * The real parameters passed in the array are:
 *  - UUID of the group in which the volume has to be created
 *  - Name of the volume to create
 *  - UUID of the volume to create
 *  - Size of the volume to create (in KB)
 *
 * @return 0 on success, a negative error code on failure
 */
static int
vrt_cmd_volume_create(const struct VrtVolumeCreate *cmd)
{
    vrt_group_t *group;
    vrt_volume_t *volume;
    int ret;

    EXA_ASSERT(cmd->volume_size > 0);

    exalog_debug("create volume '%s': size %" PRIu64 " KB",
                 cmd->volume_name, cmd->volume_size);

    group = vrt_get_group_from_uuid(&cmd->group_uuid);
    if (group == NULL)
    {
	exalog_debug("Unknown group " UUID_FMT, UUID_VAL(&cmd->group_uuid));
	return -VRT_ERR_UNKNOWN_GROUP_UUID;
    }


    /* !!! All sizes in 'cmd' are in KB and VRT internal functions want sizes in
     * sectors.
     */
    ret = vrt_group_create_volume(group, &volume, &cmd->volume_uuid, cmd->volume_name,
                                  KBYTES_2_SECTORS(cmd->volume_size));

    if (ret != EXA_SUCCESS)
    {
        exalog_error("Can't create volume '%s' in group '%s': %s(%d)",
                     cmd->volume_name, group->name, exa_error_msg(ret), ret);
	vrt_group_unref(group);
	return ret;
    }

    EXA_ASSERT(volume != NULL);

    /* wipe the newly created volume
     *
     * FIXME: This code is called from all the clients while it should be done
     * only once. To do so we should add a new RPC and trigger the wipping from
     * admind.
     */
    /* Let only one node (the first one) do the wipe */
    if (vrt_node_get_upnode_id() == 0)
    {
        ret = vrt_group_wipe_volume(group, volume);
        if (ret != EXA_SUCCESS)
        {
            exalog_error("Can't wipe volume '%s' in group '%s': %s(%d)",
                         volume->name, group->name, exa_error_msg(ret), ret);
            /* Rollback volume creation */
            vrt_group_delete_volume(group, volume);
            vrt_group_unref(group);
            return ret;
        }
    }

    vrt_group_unref(group);
    return EXA_SUCCESS;
}
Exemple #2
0
static void write_result(int msg_sock, const char *result)
{
  int skip = 0;

  if (result == NULL || msg_sock < 0)
    return;

  do
    {
      int rv;
      do
	rv = os_send(msg_sock, result + skip, strlen(result) - skip);
      while (rv == -EINTR);

      if (rv < 0 && rv != -EAGAIN)
	{
	  exalog_error("Error '%s' while sending result '%s'",
                       exa_error_msg(rv), result);
	  break;
	}

      if (rv > 0)
	skip += rv;

    } while (skip < strlen(result));
}
Exemple #3
0
static void
local_exa_fscreate(int thr_nb, void *msg)
{
    int ret = EXA_SUCCESS;
    struct fscreate_info *info = msg;
    const fs_definition_t *fs_definition;

    if (info->nodeid != adm_my_id)
    {
        ret = -ADMIND_ERR_NOTHINGTODO;
        goto local_exa_fscreate_end;
    }

    fs_definition = fs_get_definition(info->fs.fstype);
    if (!fs_definition)
    {
        ret = -EXA_ERR_INVALID_PARAM;
        goto local_exa_fscreate_end;
    }

    EXA_ASSERT(fs_definition->create_fs);
    ret = fs_definition->create_fs(thr_nb, &info->fs);

local_exa_fscreate_end:
    exalog_debug("local_exa_fscreate() = %s", exa_error_msg(ret));
    admwrk_ack(thr_nb, ret);
}
Exemple #4
0
/**
 * 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;
}
Exemple #5
0
/** select a free connection
 *
 * \param[in] sock_xml: socket on which it receives commands.
 */
static void
handle_connection(int msg_sock)
{
  int i;
  static cl_error_desc_t busy = { .code = -EXA_ERR_ADM_BUSY,
                                  .msg  = "Too many connections."};

  /* Search free slot in connection array */
  for (i = 0; i < MAX_CONNECTION; i++)
    {
      if (connectlist[i].uid == CMD_UID_INVALID && connectlist[i].fd == -1)
	{
	  exalog_debug("CONNECTION %d: Using sock %d", i, msg_sock);

	  /* uid is set when the command is actually scheduled */
	  connectlist[i].fd = msg_sock;
	  FD_SET(msg_sock, &setSocks);
	  return;
	}
    }

  /*
   * No free connection found. We disconnect the caller now because we
   * are no room in our connectionlist
   */
  exalog_error("All connections are busy sock=%d", msg_sock);

  cli_command_end_complete(msg_sock, &busy);
  os_closesocket(msg_sock);
}

/*-------------------------------------------------------------------------*/
/** \brief Connection thread: wait on xml message to pass the command
 * to the work thread.
 *
 * \param[in] sock_xml_proto: socket xml on which it receives commands.
 * \return the selected working thread or a negative error code
 *
 */
/*-------------------------------------------------------------------------*/
static void
accept_new_client(void)
{
  int fd = os_accept(listen_fd, NULL, NULL);

  exalog_debug("Got an incoming XML Request on socket: %d", fd);
  if (fd < 0)
    {
      exalog_error("Failed during admind xml connection accept: error=%s",
                   exa_error_msg(-fd));
      return;
    }

  handle_connection(fd);
}
Exemple #6
0
/**
 * Read and process an event from the network mailbox.
 *
 * \param[in,out] pi  Ping info
 *
 * \return 1 if processed an event, 0 if not, and negative error code otherwise
 */
static int
net_mbox_event(ping_info_t *pi)
{
  ExamsgMID mid;
  static char msg[sizeof(ExamsgNetRqst) + sizeof(Examsg)];
  int s;

  if (network_status() != 0)
    return 0;

  s = examsgMboxRecv(EXAMSG_NETMBOX_ID, &mid, sizeof(mid),
	             msg, sizeof(msg));
  if (s == 0) /* Nothing to read */
      return 0;

  if (s <= sizeof(ExamsgNetRqst))
    {
      exalog_error("received %d bytes, error %s", s, exa_error_msg(s));
      return -EINVAL;
    }

  s = network_send(&mid, (ExamsgNetRqst *)msg);
  if (s < 0)
    {
      if (network_manageable(s))
	{
	  remember_unsent(&mid, msg, sizeof(msg));
	  return s;
	}

      exalog_error("net mailbox event: error %s", exa_error_msg(s));
      return -EIO;
    }

  reset_ping(pi);

  return 1;
}
/** \brief Implements the get_cluster_name command
 *
 * Just return the current cluster name
 */
static void
cluster_get_cluster_name(int thr_nb, void *dummy, cl_error_desc_t *err_desc)
{
  if (!adm_cluster.created)
    {
      set_error(err_desc, -EXA_ERR_ADMIND_NOCONFIG,
                exa_error_msg(-EXA_ERR_ADMIND_NOCONFIG));
      return;
    }

  send_payload_str(adm_cluster.name);

  set_success(err_desc);
}
Exemple #8
0
static int vrt_cmd_group_resync(const struct vrt_group_resync_request *cmd)
{

    struct vrt_group *group;
    int err;

    group = vrt_get_group_from_uuid(&cmd->group_uuid);
    if (group == NULL)
        return -VRT_ERR_UNKNOWN_GROUP_UUID;

    err = vrt_group_resync(group, &cmd->nodes);
    if (err != EXA_SUCCESS)
        exalog_error("Resync failed: %s (%d)", exa_error_msg(err), err);

    vrt_group_unref(group);

    return err;
}
Exemple #9
0
/**
 * Send a ping to all instances of Csupd using examsg.
 *
 * \param[in] cluster  Cluster
 * \param[in] view     View to send
 */
void
sup_send_ping(const sup_cluster_t *cluster, const sup_view_t *view)
{
  sup_ping_msg_t ping_msg;
  int err;

  ping_msg.any.type = EXAMSG_SUP_PING;

  ping_msg.ping.sender = cluster->self->id;
  ping_msg.ping.incarnation = cluster->self->incarnation;

  sup_view_copy(&ping_msg.ping.view, view);

  EXA_ASSERT(sup_check_ping(&ping_msg.ping, 'S'));

  err = examsgSendNoBlock(sup_mh, EXAMSG_CMSGD_ID, EXAMSG_LOCALHOST,
                          &ping_msg, sizeof(ping_msg));
  if (err != sizeof(ping_msg))
    __debug("cannot send ping : %s (%d)", exa_error_msg(err), err);
}
Exemple #10
0
/**
 * Set up the messaging.
 *
 * \param[in] local_id  Local node's id
 *
 * \return true if successfull, false otherwise
 */
bool
sup_setup_messaging(exa_nodeid_t local_id)
{
  int err;

  sup_mh = examsgInit(EXAMSG_CSUPD_ID);
  if (!sup_mh)
    return false;

  /* Create local mailbox, buffer at most SUP_MAX_PING_MSG ping messages */
  err = examsgAddMbox(sup_mh, EXAMSG_CSUPD_ID, SUP_MAX_PING_MSG,
	              sizeof(sup_ping_msg_t));
  if (err)
    {
      __error("cannot create mailbox : %s (%d)", exa_error_msg(err), err);
      if (sup_mh)
        examsgExit(sup_mh);
      return false;
    }

  return true;
}
Exemple #11
0
static const char *status_info_str(rdev_req_status_t status)
{
    return status < 0 ? exa_error_msg(status) : exa_rdev_status_name(status);
}
Exemple #12
0
int main(int argc, char *argv[])
{
  bool static_init_ok = false;
  const char *action;
  int err = 0;

  self = os_program_name(argv[0]);

  if (argc <= 1)
  {
      usage();
      err = 1;
      goto done;
  }

  err = examsg_static_init(EXAMSG_STATIC_GET);
  if (err != 0)
  {
      fprintf(stderr, "examsg_static_init failed: %s (%d)\n", exa_error_msg(-err), err);
      goto done;
  }
  static_init_ok = true;

  mh = examsgInit(EXAMSG_TEST_ID);
  if (!mh)
  {
      fprintf(stderr, "examsgInit failed\n");
      goto done;
  }

  err = examsgAddMbox(mh, examsgOwner(mh), 3, EXAMSG_MSG_MAX);
  if (err != 0)
  {
      fprintf(stderr, "examsgAddMbox failed: %s (%d)\n", exa_error_msg(-err), err);
      goto done;
  }

  action = argv[1];
  if (strcmp(action, "is_fs_mounted") == 0)
  {
      int m;

      if (argc != 3)
      {
          usage();
          goto done;
      }

      m = fsd_is_fs_mounted(mh, argv[2]);
      if (m < 0)
          err = m;
  }
  else if (strcmp(action, "is_mountpoint_used") == 0)
  {
      int u;

      if (argc != 3)
      {
          usage();
          goto done;
      }

      u = fsd_is_mountpoint_used(mh, argv[2]);
      if (u < 0)
          err = u;
  }
  else if (strcmp(action, "prepare_gfs") == 0)
  {
      fs_data_t fs;
      size_t sz;

      if (argc != 3)
      {
          usage();
          goto done;
      }

      COMPILE_TIME_ASSERT(sizeof("sfs") <= sizeof(fs.fstype));
      os_strlcpy(fs.fstype, "sfs", sizeof(fs.fstype));

      sz = os_strlcpy(fs.clustered.gfs.lock_protocol, argv[2],
                      sizeof(fs.clustered.gfs.lock_protocol));
      if (sz >= sizeof(fs.clustered.gfs.lock_protocol))
      {
          fprintf(stderr, "Invalid lock protocol: '%s' (too long)\n", argv[2]);
          goto done;
      }

      err = fsd_prepare(mh, &fs);
  }
  else if (strcmp(action, "mount") == 0)
  {
      fs_data_t fs;
      size_t sz;

      if (argc != 7)
      {
          usage();
          goto done;
      }

      sz = os_strlcpy(fs.fstype, argv[2], sizeof(fs.fstype));
      if (sz >= sizeof(fs.fstype))
      {
          fprintf(stderr, "Invalid fs type: '%s' (too long)\n", argv[2]);
          goto done;
      }

      sz = os_strlcpy(fs.mountpoint, argv[3], sizeof(fs.mountpoint));
      if (sz >= sizeof(fs.mountpoint))
      {
          fprintf(stderr, "Invalid mountpoint: '%s' (too long)\n", argv[3]);
          goto done;
      }

      sz = os_strlcpy(fs.devpath, argv[4], sizeof(fs.devpath));
      if (sz >= sizeof(fs.devpath))
      {
          fprintf(stderr, "Invalid dev path: '%s' (too long)\n", argv[4]);
          goto done;
      }

      err = fsd_mount(mh, &fs, 1 , 0, argv[5], argv[6]);
  }
  else if (strcmp(action, "umount") == 0)
  {
      fs_data_t fs;
      size_t sz;

      if (argc != 6)
      {
          usage();
          goto done;
      }

      sz = os_strlcpy(fs.mountpoint, argv[2], sizeof(fs.mountpoint));
      if (sz >= sizeof(fs.mountpoint))
      {
          fprintf(stderr, "Invalid mountpoint: '%s' (too long)\n", argv[2]);
          goto done;
      }

      sz = os_strlcpy(fs.devpath, argv[3], sizeof(fs.devpath));
      if (sz >= sizeof(fs.devpath))
      {
          fprintf(stderr, "Invalid dev path: '%s' (too long)\n", argv[3]);
          goto done;
      }

      err = fsd_umount(mh, &fs, argv[5], argv[6]);
  }
  else if (strcmp(action, "unload") == 0)
  {
      fs_data_t fs;
      size_t sz;

      if (argc != 3)
      {
          usage();
          goto done;
      }

      sz = os_strlcpy(fs.fstype, argv[2], sizeof(fs.fstype));
      if (sz >= sizeof(fs.fstype))
      {
          fprintf(stderr, "Invalid fs type: '%s' (too long)\n", argv[2]);
          goto done;
      }

      err = fsd_unload(mh, &fs);
  }
  else if (strcmp(action, "create_local") == 0)
  {
      if (argc != 4)
      {
          usage();
          goto done;
      }

      err = fsd_fs_create_local(mh, argv[2], argv[3]);
  }
  else if (strcmp(action, "create_gfs") == 0)
  {
      fs_data_t fs;
      size_t sz;

      if (argc != 7)
      {
          usage();
          goto done;
      }

      COMPILE_TIME_ASSERT(sizeof("sfs") <= sizeof(fs.fstype))
      sz = os_strlcpy(fs.fstype, "sfs", sizeof(fs.fstype));

      sz = os_strlcpy(fs.devpath, argv[2], sizeof(fs.devpath));
      if (sz >= sizeof(fs.devpath))
      {
          fprintf(stderr, "Invalid dev path: '%s' (too long)\n", argv[2]);
          goto done;
      }

      sz = os_strlcpy(fs.clustered.gfs.lock_protocol, argv[3],
                      sizeof(fs.clustered.gfs.lock_protocol));
      if (sz >= sizeof(fs.clustered.gfs.lock_protocol))
      {
          fprintf(stderr, "Invalid lock protocol: '%s' (too long)\n", argv[3]);
          goto done;
      }

      if (to_uint64(argv[4], &fs.sizeKB) != EXA_SUCCESS)
      {
          fprintf(stderr, "Invalid size: '%s'\n", argv[4]);
          goto done;
      }

      sz = os_strlcpy(fs.clustered.gfs.uuid, argv[5], sizeof(fs.clustered.gfs.uuid));
      if (sz >= sizeof(fs.clustered.gfs.uuid))
      {
          fprintf(stderr, "Invalid GFS uuid: '%s' (too long)\n", argv[5]);
          goto done;
      }

      if (to_uint64(argv[6], &fs.clustered.gfs.nb_logs) != EXA_SUCCESS)
      {
          fprintf(stderr, "Invalid number of logs: '%s'\n", argv[6]);
          goto done;
      }

      err = fsd_fs_create_gfs(mh, &fs);
  }
  else if (strcmp(action, "dfinfo") == 0)
  {
      struct fsd_capa buf;

      if (argc != 3)
      {
          usage();
          goto done;
      }

      err = fsd_df(mh, argv[2], &buf);
      if (err == 0)
          printf("size=%"PRId64" bytes\n"
                 "used=%"PRId64" bytes\n"
                 "free=%"PRId64" bytes\n",
                 buf.size, buf.used, buf.free);
  }
  else if (strcmp(action, "resize") == 0)
  {
      uint64_t size_kb;

      if (argc != 6)
      {
          usage();
          goto done;
      }

      if (to_uint64(argv[5], &size_kb) != EXA_SUCCESS)
      {
          fprintf(stderr, "Invalid new size: '%s'\n", argv[5]);
          goto done;
      }

      err = fsd_resize(mh, argv[2], argv[3], argv[4], size_kb);
  }
  else if (strcmp(action, "prepare_resize") == 0)
  {
      if (argc != 4)
      {
          usage();
          goto done;
      }

      err = fsd_prepare_resize(mh, argv[2], argv[3]);
  }
  else if (strcmp(action, "read_shm") == 0)
  {
      read_shm();
  }
  else if (strcmp(action, "add_logs") == 0)
  {
      fs_data_t fs;
      int num_logs, actual_num_logs;
      size_t sz;

      if (argc != 4)
      {
          usage();
          goto done;
      }

      COMPILE_TIME_ASSERT(sizeof("sfs") <= sizeof(fs.fstype));
      os_strlcpy(fs.fstype, "sfs", sizeof(fs.fstype));

      sz = os_strlcpy(fs.devpath, argv[2], sizeof(fs.devpath));
      if (sz >= sizeof(fs.devpath))
      {
          fprintf(stderr, "Invalid dev path: '%s' (too long)\n", argv[2]);
          goto done;
      }

      if (to_int(argv[3], &num_logs) != EXA_SUCCESS)
      {
          fprintf(stderr, "Invalid number of logs: '%s'\n", argv[3]);
          goto done;
      }

      actual_num_logs = fsd_set_gfs_logs(mh, &fs, num_logs);
      if (actual_num_logs < 0)
          err = actual_num_logs;
      else
      {
	  examsgDelMbox(mh, EXAMSG_TEST_ID);
	  printf("Number of logs after the operation: %d\n", actual_num_logs);
      }
  }
  else
      usage();

  if (err != 0)
      fprintf(stderr, "Action finished with error %d: %s\n", err,
              exa_error_msg(-err));

done:

  examsgDelMbox(mh, EXAMSG_TEST_ID);

  if (mh != NULL)
      examsgExit(mh);

  if (static_init_ok)
      examsg_static_clean(EXAMSG_STATIC_RELEASE);

  return err == 0 ? 0 : 1;
}
Exemple #13
0
/** \brief Implements the fscreate command
 *
 * - Set nodes started and stopped.
 * - Set nodes mounted and unmounted.
 * - Add it to the config tree with status NOK
 * - This command runs the FS-specific check and create command: creation
 *   of new volumes is done through specific FS function
 * - Update status to OK in the config file.
 */
static void cluster_fscreate(int thr_nb, void *data, cl_error_desc_t *err_desc)
{
  struct fscreate_params *fs_param = data;
  int error_val = EXA_SUCCESS, error_delete;
  struct adm_volume *volume;
  struct adm_group  *group;
  fs_data_t new_fs;
  const fs_definition_t *fs_definition;
  struct vrt_volume_info volume_info;

  exalog_info("received fscreate '%s:%s' "
              "--mountpoint='%s' --type='%s' --size=%" PRIu64
	      " --rg-size=%" PRIu64, fs_param->group_name, fs_param->volume_name,
	      fs_param->mountpoint, fs_param->type, fs_param->sizeKB,
	      fs_param->rg_sizeM);

  /* Check the license status to send warnings/errors */
  cmd_check_license_status();

  /* This is a workaround for bug #4600. */
  if (fs_param->sizeKB % 4 != 0)
  {
      set_error(err_desc, -EXA_ERR_INVALID_PARAM, "Size must be a multiple of 4KiB");
      return;
  }

  group = adm_group_get_group_by_name(fs_param->group_name);
  if (group == NULL)
    {
      set_error(err_desc, -ADMIND_ERR_UNKNOWN_GROUPNAME,
                NULL, fs_param->group_name);
      return;
    }

  /* The volume MUST NOT exist */
  if (adm_cluster_get_volume_by_name(group->name, fs_param->volume_name))
    {
      set_error(err_desc, -EXA_ERR_INVALID_PARAM,
	        "A file system or a volume with this name already exists");
      return;
    }

  fs_definition = fs_get_definition(fs_param->type);
  if (!fs_definition)
    {
      set_error(err_desc, -EXA_ERR_INVALID_PARAM, "Unknown file system type");
      return;
    }

  /* FIXME use cluster_vlcreate in place of vrt_master_volume_create */
  error_val = vrt_master_volume_create(thr_nb,
                                       group,
				       fs_param->volume_name,
                                       EXPORT_BDEV,
                                       fs_param->sizeKB,
                                       fs_definition->is_volume_private(),
				       adm_cluster_get_param_int("default_readahead"));

  if (error_val != EXA_SUCCESS)
      goto volume_delete;

  /* get the newly create volume */
  volume = adm_group_get_volume_by_name(group, fs_param->volume_name);

  /* Ask the vrt for the real size because "-s max" uses a size of "0" */
  if ((error_val = vrt_client_volume_info(adm_wt_get_localmb(),
                                          &group->uuid,
                                          &volume->uuid,
                                          &volume_info)) != EXA_SUCCESS)
    {
      goto volume_delete;
    }

  /* fill the structure with informations retrieved from the vrt */
  memset(&new_fs, 0, sizeof(new_fs));

  strlcpy(new_fs.fstype, fs_param->type, sizeof(new_fs.fstype));
  strlcpy(new_fs.mountpoint, fs_param->mountpoint, sizeof(new_fs.mountpoint));

  new_fs.sizeKB      = volume_info.size;
  new_fs.volume_uuid = volume->uuid;
  new_fs.transaction = 0;

  adm_volume_path(new_fs.devpath, sizeof(new_fs.devpath),
                  group->name, volume->name);

  /* Parse the filesystem-specific command parameters */
  if (fs_definition->parse_fscreate_parameters)
    {
      error_val = fs_definition->parse_fscreate_parameters(&new_fs,
							   fs_param->sfs_nb_logs,
							   fs_param->rg_sizeM);
      if (error_val != EXA_SUCCESS)
	goto volume_delete;
    }

  /* Write to tree, with INPROGRESS status */
  error_val = fs_update_tree(thr_nb, &new_fs);
  if (error_val != EXA_SUCCESS)
    goto volume_delete;

  exalog_debug("Set FS tree to NOK successfully");

    /* Perform clustered preparation specific to fs type */
    if (fs_definition->pre_create_fs)
    {
        error_val = fs_definition->pre_create_fs(thr_nb, &new_fs);
        if (error_val != EXA_SUCCESS)
            goto volume_delete;
    }

  /* Really create */
  error_val = pre_local_create_fs(thr_nb, &new_fs);

  if (error_val != EXA_SUCCESS)
    goto volume_delete;

  exalog_debug("Created FS successfully");

  /* Set transaction to COMMITTED */
  new_fs.transaction = 1;

  error_val = fs_update_tree(thr_nb, &new_fs);
  if (error_val != EXA_SUCCESS)
    goto volume_delete;

  exalog_debug("Set FS tree to COMMITTED successfully");

  set_success(err_desc);
  return;

volume_delete:
  /* retrieve the volume the was supposed to be created */
  volume = adm_group_get_volume_by_name(group, fs_param->volume_name);

  if (error_val == -ADMIND_ERR_NODE_DOWN ||
      error_val == -ADMIND_ERR_METADATA_CORRUPTION ||
      !volume)
    {
      set_error(err_desc, error_val, NULL);
      return;
    }
  /* Try to remove the volume in the config file.  If this fails
   * for any reason, silently ignore the error: the FS is rolled
   * back to an invalid status and cannot be started. The only way
   * out is to fsdelete it.
   */
  error_delete = vrt_master_volume_delete(thr_nb, volume, false);
  if (error_delete != EXA_SUCCESS)
    {
      exalog_error("Cannot delete file system: %s", exa_error_msg(error_delete));
    }

  set_error(err_desc, error_val, NULL);
  return;
}
Exemple #14
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;
}
Exemple #15
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;
}
Exemple #16
0
static void
local_exa_vldelete (int thr_nb, void *msg)
{
  struct adm_group *group;
  struct adm_volume *volume = NULL;
  int ret;         /* used for local function calls */
  int barrier_ret; /* used for barriers return values */
  int undo_ret;
  struct vldelete_info *info = msg;

  group = adm_group_get_group_by_name(info->group_name);
  if (group == NULL)
  {
    ret = -ADMIND_ERR_UNKNOWN_GROUPNAME;
    goto get_barrier;
  }

  volume = adm_group_get_volume_by_name(group, info->volume_name);
  if (volume == NULL)
  {
    ret = -ADMIND_ERR_UNKNOWN_VOLUMENAME;
    goto get_barrier;
  }

get_barrier:
  /*** Barrier: getting parameters ***/
  ret = EXA_SUCCESS;
  barrier_ret = admwrk_barrier(thr_nb, ret, "Getting parameters");
  if (barrier_ret != EXA_SUCCESS)
    goto local_exa_vldelete_end_no_resume;

  ret = vrt_group_suspend_threads_barrier(thr_nb, &group->uuid);
  if (ret != EXA_SUCCESS)
      goto local_exa_vldelete_end;

  /*** Action: mark the transaction as in-progress ***/
  /* This is an in-memory operation, we assume it won't fail */
  volume->committed = false;
  ret = conf_save_synchronous();
  EXA_ASSERT_VERBOSE(ret == EXA_SUCCESS, "%s", exa_error_msg(ret));

  /*** Barrier: mark the transaction as in-progress ***/
  barrier_ret = admwrk_barrier(thr_nb, ret, "Marking transaction as in-progress");
  if (barrier_ret == -ADMIND_ERR_NODE_DOWN)
    goto metadata_corruption;
  else if (barrier_ret != EXA_SUCCESS)
    goto local_exa_vldelete_end;

  /* XXX should errors be handled ? */
  lum_exports_remove_export_from_uuid(&volume->uuid);
  lum_exports_increment_version();
  lum_serialize_exports();

  /*** Action: delete the volume (in memory) through the VRT API ***/
  ret = vrt_client_volume_delete(adm_wt_get_localmb(), &group->uuid, &volume->uuid);

  /*** Barrier: delete the volume through the VRT API ***/
  barrier_ret = admwrk_barrier(thr_nb, ret, "Deleting volume");
  if (barrier_ret == -ADMIND_ERR_NODE_DOWN)
    goto metadata_corruption;
  else if (barrier_ret == -VRT_ERR_GROUP_NOT_ADMINISTRABLE)
    {
      /* Mark the transaction as committed, so that the volume is not
       * shown as "invalid" later.
       */
      volume->committed = true;
      undo_ret = conf_save_synchronous();
      EXA_ASSERT_VERBOSE(undo_ret == EXA_SUCCESS, "%s", exa_error_msg(undo_ret));
      goto local_exa_vldelete_end;
    }
  else if ((barrier_ret != EXA_SUCCESS) && !info->metadata_recovery)
    goto local_exa_vldelete_end;

  /*** Action: group sync SB (master) ***/
  ret = adm_vrt_group_sync_sb(thr_nb, group);

  /*** Barrier: group sync SB ***/
  barrier_ret = admwrk_barrier(thr_nb, ret,
			       "Syncing metadata on disk");
  if (barrier_ret == -ADMIND_ERR_NODE_DOWN)
    goto metadata_corruption;
  else if (barrier_ret != EXA_SUCCESS)
    goto local_exa_vldelete_end;

  /* Delete the volume from the configuration */
  adm_group_remove_volume(volume);
  adm_volume_free(volume);
  ret = conf_save_synchronous();
  EXA_ASSERT_VERBOSE(ret == EXA_SUCCESS, "%s", exa_error_msg(ret));

  barrier_ret = admwrk_barrier(thr_nb, ret, "Updating XML configuration");
  if (barrier_ret == -ADMIND_ERR_NODE_DOWN)
    goto metadata_corruption;

  goto local_exa_vldelete_end;

metadata_corruption:
  ret = -ADMIND_ERR_METADATA_CORRUPTION;

local_exa_vldelete_end:
    barrier_ret = vrt_group_resume_threads_barrier(thr_nb, &group->uuid);
    /* What to do if that fails... I don't know. */
    if (barrier_ret != 0)
        ret = barrier_ret;

local_exa_vldelete_end_no_resume:
  exalog_debug("local_exa_vldelete() = %s", exa_error_msg(ret));
  admwrk_ack(thr_nb, ret);
}
Exemple #17
0
/**
 * Initialize the RDEV service:
 * - start exa_rdev kernel module,
 * - allocate and initialize aligned buffers to read/writes superblocks.
 */
static int
rdev_init(int thr_nb)
{
  char path[OS_PATH_MAX];
  int err = 0;

  if (os_kmod_load("exa_rdev") != 0)
  {
    exalog_error("Failed to load kernel module 'exa_rdev'");
    return -ADMIND_ERR_MODULESTART;
  }

  /* Load the broken disks table */
  err = exa_env_make_path(path, sizeof(path), exa_env_cachedir(), "broken_disks");
  if (err != 0)
      return err;

  err = broken_disk_table_load(&broken_disks, path, true /* open_read_write */);
  if (err != 0)
  {
      exalog_error("Failed loading the broken disk table: %s (%d)",
                    exa_error_msg(err), err);
      return err;
  }

  /* Initialize the rdev module */
  err = exa_rdev_static_init(RDEV_STATIC_CREATE);
  if (err != 0)
  {
    exalog_error("Failed initializing rdev statics: %s (%d)", exa_error_msg(err), err);
    goto cleanup_broken;
  }

  exa_rdev_fd = exa_rdev_init();
  if (exa_rdev_fd <= 0)
  {
    err = exa_rdev_fd;
    exalog_error("Failed initializing rdev: %s (%d)", exa_error_msg(err), err);
    goto cleanup_broken;
  }

  mh = examsgInit(EXAMSG_RDEV_ID);
  if (!mh)
  {
      exalog_error("Failed initializing messaging for disk checking thread");
      err = -ENOMEM;
      goto cleanup_rdev_fd;
  }

  COMPILE_TIME_ASSERT(RDEV_SUPERBLOCK_SIZE <= SECTORS_TO_BYTES(RDEV_RESERVED_AREA_IN_SECTORS));

  rdev_check_buffer = os_aligned_malloc(RDEV_SUPERBLOCK_SIZE, 4096, NULL);
  if (!rdev_check_buffer)
  {
      exalog_error("Failed allocating disk checking buffer");
      err = -ENOMEM;
      goto cleanup_mh;
  }

  /* make sure the check thread will not quit */
  quit = false;

  /* launch the rdev checking thread */
  if (!exathread_create_named(&rdev_check_id, MIN_THREAD_STACK_SIZE,
                              disk_checking_thread, mh, "rdev_check"))
  {
      exalog_error("Failed creating disk checking thread");
      err = -EXA_ERR_DEFAULT;
      goto cleanup_rdev_check_buffer;
  }

  rdev_check_id_started = true;

  return EXA_SUCCESS;

cleanup_rdev_check_buffer:
    os_aligned_free(rdev_check_buffer);
    rdev_check_buffer = NULL;
cleanup_mh:
    examsgExit(mh);
    mh = NULL;
cleanup_rdev_fd:
    close(exa_rdev_fd);
    exa_rdev_fd = -1;
cleanup_broken:
    broken_disk_table_unload(&broken_disks);
    return err;
}
Exemple #18
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);
  }
}
Exemple #19
0
int adm_vrt_group_sync_sb(int thr_nb, struct adm_group *group)
{
  struct {
    bool group_is_started;
    bool can_write;
    bool have_disk_in_group;
  } info, reply;

  exa_nodeid_t nid;
  bool group_is_started_somewhere = false;
  int ret;
  int barrier_ret = EXA_SUCCESS;
  admwrk_request_t rpc;
  struct adm_disk *disk;
  int nb_nodes_with_writable_disks = 0;
  int nb_nodes_with_disks_in_group = 0;

  uint64_t old_sb_version, new_sb_version;

  COMPILE_TIME_ASSERT(sizeof(info) <= ADM_MAILBOX_PAYLOAD_PER_NODE);

  /* XXX maybe checking started is useless as administrable => started
   * and !administrable => return */
  info.group_is_started = group->started;
  info.can_write = false;
  info.have_disk_in_group = false;

  adm_group_for_each_disk(group, disk)
  {
      if (disk->node_id == adm_my_id)
      {
          info.have_disk_in_group = true;

          if (disk->up_in_vrt)
              info.can_write = true;
      }
  }

  admwrk_bcast(thr_nb, &rpc, EXAMSG_SERVICE_VRT_SB_SYNC, &info, sizeof(info));
  while (admwrk_get_bcast(&rpc, &nid, &reply, sizeof(reply), &ret))
  {
    if (ret == -ADMIND_ERR_NODE_DOWN)
    {
      barrier_ret = -ADMIND_ERR_NODE_DOWN;
      continue;
    }

    EXA_ASSERT(ret == EXA_SUCCESS);

    if (reply.can_write)
        nb_nodes_with_writable_disks++;

    if (reply.have_disk_in_group)
        nb_nodes_with_disks_in_group++;

    if (reply.group_is_started)
        group_is_started_somewhere = true;
  }

  if (barrier_ret != EXA_SUCCESS)
    return barrier_ret;

  /* do not write superblocks if the group is stopped on all nodes */
  if (!group_is_started_somewhere)
    return EXA_SUCCESS;

  if (nb_nodes_with_writable_disks < quotient_ceil64(nb_nodes_with_disks_in_group, 2))
      return -VRT_ERR_GROUP_NOT_ADMINISTRABLE;

  old_sb_version = sb_version_get_version(group->sb_version);
  new_sb_version = sb_version_new_version_prepare(group->sb_version);

  if (group->started)
  {
      ret = vrt_client_group_sync_sb(adm_wt_get_localmb(),
                                     &group->uuid, old_sb_version, new_sb_version);

      EXA_ASSERT_VERBOSE(ret == EXA_SUCCESS || ret == -ADMIND_ERR_NODE_DOWN,
                         "Synchronization of superblocks failed for group '%s' "
                         "UUID=" UUID_FMT ": %s (%d)", group->name,
                         UUID_VAL(&group->uuid), exa_error_msg(ret), ret);
  }
  else
      ret = EXA_SUCCESS;

  barrier_ret = admwrk_barrier(thr_nb, ret, "VRT: Preparing superblocks version");
  if (barrier_ret != EXA_SUCCESS)
    return barrier_ret;

  sb_version_new_version_done(group->sb_version);

  barrier_ret = admwrk_barrier(thr_nb, EXA_SUCCESS, "VRT: Writing superblocks version");

  /* Commit anyway, If we are here, we are sure that other nodes have done the
   * job too even if they crashed meanwhile */
  sb_version_new_version_commit(group->sb_version);

  return barrier_ret;
}
Exemple #20
0
/**
 * \brief receive a data from a socket.
 * When returning EXA_SUCCESS, xml_tree points on a valid xml tree.
 *
 * \param[in]  sock_fd   socket file descriptor of the incoming data
 * \param[out] xml_tree  Pointer on the xmlDocPtr pointing on a XML tree
 *                          extracted from the data read on the socket.
 *
 * \return EXA_SUCCESS or a negative error.
 */
static int
receive(int sock_fd, char **buffer)
{
  int current_read = 0;
  char *buffer_receiving = NULL;

  EXA_ASSERT(buffer);

  *buffer = NULL;

  exalog_debug("SOCKET %d: XML Message processing", sock_fd);

  /* We read and merge each chunk of incomming data in the hope to get
   * the END of command. Here the input buffer is sized as to handle
   * all the command in one chunk, so not having the end of command is
   * an error. */
  do
    {
      int nb_car;
      char *new_buffer_receiving;

      if (current_read > PROTOCOL_BUFFER_MAX_SIZE)
	{
	  cl_error_desc_t error;
	  set_error(&error, -EXA_ERR_CMD_PARSING,
	           "Received command is bigger than our internal limit (%d bytes)",
		   PROTOCOL_BUFFER_MAX_SIZE);

	  exalog_error("Socket %d peer '%s': %s", sock_fd,
	               cli_peer_from_fd(sock_fd), error.msg);

	  cli_command_end_complete(sock_fd, &error);
	  /* Don't need the receiving buffer any more */
	  os_free(buffer_receiving);
	  return -EXA_ERR_CMD_PARSING;
	}

      new_buffer_receiving = os_realloc(buffer_receiving,
                                        PROTOCOL_BUFFER_LEN + current_read
                                        + sizeof(char)  /* for '\0' */);
      if (!new_buffer_receiving)
	{
	  os_free(buffer_receiving);
	  exalog_error("Socket %d peer '%s': Failed to realloc()", sock_fd,
	               cli_peer_from_fd(sock_fd));
	  return -ENOMEM;
	}

      buffer_receiving = new_buffer_receiving;

      do
	nb_car = os_recv(sock_fd, buffer_receiving + current_read,
			 PROTOCOL_BUFFER_LEN, 0);
      while (nb_car == -EINTR);

      if (nb_car == 0)
	{
	  exalog_debug("SOCKET %d: Error = Client did disconnect itself",
		       sock_fd);

	  os_free(buffer_receiving);
	  return -ECONNABORTED;
	}

      if (nb_car < 0 && errno != EAGAIN)
	{
	  if (nb_car == -ECONNRESET)
	    exalog_debug("SOCKET %d: Error %d", sock_fd, nb_car);
	  else
	    exalog_error("Socket %d peer '%s': %s (%d)", sock_fd,
		         cli_peer_from_fd(sock_fd), exa_error_msg(nb_car), nb_car);

	  os_free(buffer_receiving);
	  return nb_car;
	}

      if(nb_car > 0)
	current_read += nb_car;

      /* Make sure to be properly ended */
      buffer_receiving[current_read] = '\0';

      /* Make sure the XML input is complete */
    } while(xml_buffer_is_partial(buffer_receiving));

  exalog_debug("SOCKET %d: Receive Message lg = %" PRIzu " :  [%s]",
	       sock_fd, strlen(buffer_receiving), buffer_receiving);
  *buffer = buffer_receiving;

  return EXA_SUCCESS;
}
Exemple #21
0
/**
 * Process a connection that has incoming data.
 *
 * \param[in] conn_id  Connection id
 * \param[in] sock_fd  Connection socket
 */
static void
handle_inputdata(int conn_id, int sock_fd)
{
  char *buffer = NULL;
  void *data = NULL;
  size_t data_size;
  adm_command_code_t cmd_code;
  const struct AdmCommand *command;
  exa_uuid_t cluster_uuid;
  cl_error_desc_t err_desc;
  int retval;

  /* Receive the xml tree parsed in message */
  retval = receive(sock_fd, &buffer);
  if (retval < 0)
    {
      if (retval == -ECONNRESET || retval == -ECONNABORTED)
	exalog_debug("CONNECTION %d: An error occurred : %d [%s]",
		     conn_id, retval, exa_error_msg(retval));
      else
	exalog_error("Socket %d peer '%s': An error occurred : %s (%d)",
		     sock_fd, cli_peer_from_fd(sock_fd), exa_error_msg(retval),
		     retval);

      close_connection(conn_id);
      return;
    }

  /* Parse the tree we just received and get a newly allocated payload data */
  xml_command_parse(buffer, &cmd_code, &cluster_uuid,
                    &data, &data_size, &err_desc);

  /* buffer is now parsed, let's free it */
  os_free(buffer);

  if (err_desc.code != EXA_SUCCESS)
    {
      /* No need to free data buffer if parsing returned an error */
      exalog_error("Failed to parse command on socket %d (from peer '%s'): %s (%d)",
	           sock_fd, cli_peer_from_fd(sock_fd), err_desc.msg, err_desc.code);

      cli_command_end_complete(sock_fd, &err_desc);
      return;
    }

  command = adm_command_find(cmd_code);
  EXA_ASSERT_VERBOSE(command, "Missing implementation of command #%d", cmd_code);

  connectlist[conn_id].uid = get_new_cmd_uid();
  retval = send_command_to_evmgr(connectlist[conn_id].uid,
                                 command,
				 &cluster_uuid, data, data_size);
  if (retval < 0)
    {
      if (retval == -EXA_ERR_ADM_BUSY)
        exalog_warning("Running command %s (request from %s) failed: %s",
                       adm_command_find(cmd_code)->msg,
                       cli_get_peername(connectlist[conn_id].uid),
                       exa_error_msg(retval));
      else
        exalog_error("Running command %s (request from %s) failed: %s (%d)",
                     adm_command_find(cmd_code)->msg,
		     cli_get_peername(connectlist[conn_id].uid),
                     exa_error_msg(retval), retval);

      set_error(&err_desc, retval, NULL);
      cli_command_end_complete(sock_fd, &err_desc);

      /* the command was not scheduled, reset the uid */
      connectlist[conn_id].uid = CMD_UID_INVALID;
    }

  os_free(data);
}
Exemple #22
0
int main(int argc, char **argv)
{
    int di;
    char *cp;
    int inFd = -1;
    int outFd = -1;
    int inCc = 0;
    int outCc;
    char *inFile;
    char *outFile;
    uint64_t blockSize, readSize;
    uint64_t size;
    uint64_t intotal;
    uint64_t outTotal;
    char *buf = NULL;
    char hex_output[16 * 2 + 1];

    self = strrchr(argv[0], '/');
    if (self == NULL)
        self = argv[0];
    else
        self++;

    /* Parse any options */
    if (argc != 5)
    {
        fprintf(stderr, "dd with md5 checksum.\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "usage: %s <if> <of> <bufsize> <count>\n", self);
        fprintf(stderr, "\n");
        fprintf(stderr, "    <if>       Input file\n");
        fprintf(stderr, "    <of>       Output file\n");
        fprintf(stderr, "    <bufsize>  Size of buffer\n");
        fprintf(stderr, "    <count>    Number of bytes to copy\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "NOTES:\n");
        fprintf(stderr, "  - The actual number of bytes copied may be greater"
                             " than the specified count\n"
                        "    because of the buffer size.\n");
        fprintf(stderr, "  - The computed md5 is appended to the end of the"
                             " output file (no idea why).\n");
        exit(1);
    }

    inFile  = argv[1];
    outFile = argv[2];

    if (to_uint64(argv[3], &blockSize) != EXA_SUCCESS)
    {
        error("invalid buffer size: '%s'", argv[3]);
        goto done;
    }

    if (to_uint64(argv[4], &size) != EXA_SUCCESS)
    {
        error("invalid byte count: '%s'", argv[4]);
        goto done;
    }

    if ((buf = malloc(blockSize)) == NULL)
    {
        error("alloc buffer: %s", exa_error_msg(-errno));
        goto done;
    }

    intotal  = 0;
    outTotal = 0;

    /* Open the source file*/
    inFd = open(inFile, 0);
    if (inFd < 0)
    {
        error("open input file %s: %s",inFile, exa_error_msg(-errno));
        goto done;
    }

    /* Open the dest file*/
    outFd = open(outFile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (outFd < 0)
    {
        error("open output file %s: %s",outFile, exa_error_msg(-errno));
        goto done;
    }

    lseek(inFd, 0, SEEK_SET);
    lseek(outFd, 0, SEEK_SET);

    readSize = blockSize;

    /* Write the file with block  */
    while (outTotal < size)
    {

        /* Read the source file */
        inCc = read(inFd, buf, readSize);
        if (inCc <= 0)
        {
            error("read: %s", exa_error_msg(-errno));
            goto done;
        }

        intotal += inCc;
        cp = buf;
        outCc = 0;

        /* Write on the dest file */
        while (outCc < inCc)
        {
            md5_state_t state;
            md5_byte_t digest[16];

            outCc = write(outFd, cp, inCc);
            if (outCc <= 0)
            {
                error("write: %s", exa_error_msg(-errno));
                goto done;
            }

            inCc -= outCc;
            outTotal += outCc;

            /* Manage the check sum */
            md5_init(&state);
            md5_append(&state, (const md5_byte_t *)cp,outCc);
            md5_finish(&state, digest);
            for (di = 0; di < 16; ++di)
                sprintf(hex_output + di * 2, "%02x", digest[di]);

            cp += outCc;
        }

        /* End of the file */
        if (size - outTotal < blockSize)
            readSize = size - outTotal;
    }

    lseek(outFd, 0,SEEK_END);
    if (write(outFd, hex_output, strlen(hex_output)) <= 0)
    {
        error("write md5: %s", exa_error_msg(-errno));
        goto done;
    }

done:
    if (inFd != -1 && close(inFd) != 0)
        error("close %s: %s", inFile, exa_error_msg(-errno));

    if (outFd != -1 && close(outFd) != 0)
        error("close %s: %s", outFile, exa_error_msg(-errno));

    sync();
    free(buf);

    return err ? 1 : 0;
}