Esempio n. 1
0
/*
  send a reply for a ctdb control
 */
void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c,
                                TDB_DATA *outdata, int32_t status, const char *errormsg)
{
    struct ctdb_reply_control *r;
    size_t len;

    /* some controls send no reply */
    if (c->flags & CTDB_CTRL_FLAG_NOREPLY) {
        return;
    }

    len = offsetof(struct ctdb_reply_control, data) + (outdata?outdata->dsize:0);
    if (errormsg) {
        len += strlen(errormsg);
    }
    r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REPLY_CONTROL, len, struct ctdb_reply_control);
    CTDB_NO_MEMORY_VOID(ctdb, r);

    r->hdr.destnode     = c->hdr.srcnode;
    r->hdr.reqid        = c->hdr.reqid;
    r->status           = status;
    r->datalen          = outdata?outdata->dsize:0;
    if (outdata && outdata->dsize) {
        memcpy(&r->data[0], outdata->dptr, outdata->dsize);
    }
    if (errormsg) {
        r->errorlen = strlen(errormsg);
        memcpy(&r->data[r->datalen], errormsg, r->errorlen);
    }

    ctdb_queue_packet_opcode(ctdb, &r->hdr, c->opcode);

    talloc_free(r);
}
Esempio n. 2
0
/*
  message handler for when we are in daemon mode. This redirects the message
  to the right client
 */
static void daemon_message_handler(uint64_t srvid, TDB_DATA data,
				   void *private_data)
{
	struct ctdb_client *client = talloc_get_type(private_data, struct ctdb_client);
	struct ctdb_req_message *r;
	int len;

	/* construct a message to send to the client containing the data */
	len = offsetof(struct ctdb_req_message, data) + data.dsize;
	r = ctdbd_allocate_pkt(client->ctdb, client->ctdb, CTDB_REQ_MESSAGE,
			       len, struct ctdb_req_message);
	CTDB_NO_MEMORY_VOID(client->ctdb, r);

	talloc_set_name_const(r, "req_message packet");

	r->srvid         = srvid;
	r->datalen       = data.dsize;
	memcpy(&r->data[0], data.dptr, data.dsize);

	daemon_queue_send(client, &r->hdr);

	talloc_free(r);
}
Esempio n. 3
0
/*
 * Schedule a new lock child process
 * Set up callback handler and timeout handler
 */
static void ctdb_lock_schedule(struct ctdb_context *ctdb)
{
	struct lock_context *lock_ctx, *next_ctx, *active_ctx;
	int ret;
	TALLOC_CTX *tmp_ctx;
	const char *helper = BINDIR "/ctdb_lock_helper";
	static const char *prog = NULL;
	char **args;

	if (prog == NULL) {
		const char *t;

		t = getenv("CTDB_LOCK_HELPER");
		if (t != NULL) {
			prog = talloc_strdup(ctdb, t);
		} else {
			prog = talloc_strdup(ctdb, helper);
		}
		CTDB_NO_MEMORY_VOID(ctdb, prog);
	}

	if (ctdb->lock_pending == NULL) {
		return;
	}

	/* Find a lock context with requests */
	lock_ctx = ctdb->lock_pending;
	while (lock_ctx != NULL) {
		next_ctx = lock_ctx->next;
		if (! lock_ctx->req_queue) {
			DEBUG(DEBUG_INFO, ("Removing lock context without lock requests\n"));
			DLIST_REMOVE(ctdb->lock_pending, lock_ctx);
			ctdb->lock_num_pending--;
			CTDB_DECREMENT_STAT(ctdb, locks.num_pending);
			if (lock_ctx->ctdb_db) {
				CTDB_DECREMENT_DB_STAT(lock_ctx->ctdb_db, locks.num_pending);
			}
			talloc_free(lock_ctx);
		} else {
			active_ctx = find_lock_context(ctdb->lock_current, lock_ctx->ctdb_db,
						       lock_ctx->key, lock_ctx->priority,
						       lock_ctx->type);
			if (active_ctx == NULL) {
				if (lock_ctx->ctdb_db == NULL ||
				    lock_ctx->ctdb_db->lock_num_current < MAX_LOCK_PROCESSES_PER_DB) {
					/* Found a lock context with lock requests */
					break;
				}
			}

			/* There is already a child waiting for the
			 * same key.  So don't schedule another child
			 * just yet.
			 */
		}
		lock_ctx = next_ctx;
	}

	if (lock_ctx == NULL) {
		return;
	}

	lock_ctx->child = -1;
	ret = pipe(lock_ctx->fd);
	if (ret != 0) {
		DEBUG(DEBUG_ERR, ("Failed to create pipe in ctdb_lock_schedule\n"));
		return;
	}

	set_close_on_exec(lock_ctx->fd[0]);

	/* Create data for child process */
	tmp_ctx = talloc_new(lock_ctx);
	if (tmp_ctx == NULL) {
		DEBUG(DEBUG_ERR, ("Failed to allocate memory for helper args\n"));
		close(lock_ctx->fd[0]);
		close(lock_ctx->fd[1]);
		return;
	}

	/* Create arguments for lock helper */
	args = lock_helper_args(tmp_ctx, lock_ctx, lock_ctx->fd[1]);
	if (args == NULL) {
		DEBUG(DEBUG_ERR, ("Failed to create lock helper args\n"));
		close(lock_ctx->fd[0]);
		close(lock_ctx->fd[1]);
		talloc_free(tmp_ctx);
		return;
	}

	lock_ctx->child = vfork();

	if (lock_ctx->child == (pid_t)-1) {
		DEBUG(DEBUG_ERR, ("Failed to create a child in ctdb_lock_schedule\n"));
		close(lock_ctx->fd[0]);
		close(lock_ctx->fd[1]);
		talloc_free(tmp_ctx);
		return;
	}


	/* Child process */
	if (lock_ctx->child == 0) {
		ret = execv(prog, args);
		if (ret < 0) {
			DEBUG(DEBUG_ERR, ("Failed to execute helper %s (%d, %s)\n",
					  prog, errno, strerror(errno)));
		}
		_exit(1);
	}

	/* Parent process */
	ctdb_track_child(ctdb, lock_ctx->child);
	close(lock_ctx->fd[1]);

	talloc_set_destructor(lock_ctx, ctdb_lock_context_destructor);

	talloc_free(tmp_ctx);

	/* Set up timeout handler */
	lock_ctx->ttimer = tevent_add_timer(ctdb->ev,
					    lock_ctx,
					    timeval_current_ofs(10, 0),
					    ctdb_lock_timeout_handler,
					    (void *)lock_ctx);
	if (lock_ctx->ttimer == NULL) {
		ctdb_kill(ctdb, lock_ctx->child, SIGKILL);
		lock_ctx->child = -1;
		talloc_set_destructor(lock_ctx, NULL);
		close(lock_ctx->fd[0]);
		return;
	}

	/* Set up callback */
	lock_ctx->tfd = tevent_add_fd(ctdb->ev,
				      lock_ctx,
				      lock_ctx->fd[0],
				      EVENT_FD_READ,
				      ctdb_lock_handler,
				      (void *)lock_ctx);
	if (lock_ctx->tfd == NULL) {
		TALLOC_FREE(lock_ctx->ttimer);
		ctdb_kill(ctdb, lock_ctx->child, SIGKILL);
		lock_ctx->child = -1;
		talloc_set_destructor(lock_ctx, NULL);
		close(lock_ctx->fd[0]);
		return;
	}
	tevent_fd_set_auto_close(lock_ctx->tfd);

	/* Move the context from pending to current */
	DLIST_REMOVE(ctdb->lock_pending, lock_ctx);
	ctdb->lock_num_pending--;
	DLIST_ADD_END(ctdb->lock_current, lock_ctx, NULL);
	if (lock_ctx->ctdb_db) {
		lock_ctx->ctdb_db->lock_num_current++;
		CTDB_INCREMENT_STAT(lock_ctx->ctdb, locks.num_current);
		CTDB_INCREMENT_DB_STAT(lock_ctx->ctdb_db, locks.num_current);
	}
}