Exemple #1
0
/*
  wait until we have finished initial recoveries before we start the
  monitoring events
 */
static void ctdb_wait_until_recovered(struct tevent_context *ev,
				      struct tevent_timer *te,
				      struct timeval t, void *private_data)
{
	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
	int ret;
	static int count = 0;

	count++;

	if (count < 60 || count%600 == 0) { 
		DEBUG(DEBUG_NOTICE,("CTDB_WAIT_UNTIL_RECOVERED\n"));
		if (ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_STOPPED) {
			DEBUG(DEBUG_NOTICE,("Node is STOPPED. Node will NOT recover.\n"));
		}
	}

	if (ctdb->vnn_map->generation == INVALID_GENERATION) {
		ctdb->db_persistent_startup_generation = INVALID_GENERATION;

		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
				 timeval_current_ofs(1, 0),
				 ctdb_wait_until_recovered, ctdb);
		return;
	}

	if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
		ctdb->db_persistent_startup_generation = INVALID_GENERATION;

		DEBUG(DEBUG_NOTICE,(__location__ " in recovery. Wait one more second\n"));
		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
				 timeval_current_ofs(1, 0),
				 ctdb_wait_until_recovered, ctdb);
		return;
	}


	if (!fast_start && timeval_elapsed(&ctdb->last_recovery_finished) < (ctdb->tunable.rerecovery_timeout + 3)) {
		ctdb->db_persistent_startup_generation = INVALID_GENERATION;

		DEBUG(DEBUG_NOTICE,(__location__ " wait for pending recoveries to end. Wait one more second.\n"));

		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
				 timeval_current_ofs(1, 0),
				 ctdb_wait_until_recovered, ctdb);
		return;
	}

	if (ctdb->vnn_map->generation == ctdb->db_persistent_startup_generation) {
		DEBUG(DEBUG_INFO,(__location__ " skip ctdb_recheck_persistent_health() "
				  "until the next recovery\n"));
		tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
				 timeval_current_ofs(1, 0),
				 ctdb_wait_until_recovered, ctdb);
		return;
	}

	ctdb->db_persistent_startup_generation = ctdb->vnn_map->generation;
	ret = ctdb_recheck_persistent_health(ctdb);
	if (ret != 0) {
		ctdb->db_persistent_check_errors++;
		if (ctdb->db_persistent_check_errors < ctdb->max_persistent_check_errors) {
			DEBUG(ctdb->db_persistent_check_errors==1?DEBUG_ERR:DEBUG_WARNING,
			      (__location__ "ctdb_recheck_persistent_health() "
			      "failed (%llu of %llu times) - retry later\n",
			      (unsigned long long)ctdb->db_persistent_check_errors,
			      (unsigned long long)ctdb->max_persistent_check_errors));
			tevent_add_timer(ctdb->ev,
					 ctdb->monitor->monitor_context,
					 timeval_current_ofs(1, 0),
					 ctdb_wait_until_recovered, ctdb);
			return;
		}
		DEBUG(DEBUG_ALERT,(__location__
				  "ctdb_recheck_persistent_health() failed (%llu times) - prepare shutdown\n",
				  (unsigned long long)ctdb->db_persistent_check_errors));
		ctdb_shutdown_sequence(ctdb, 11);
		/* In case above returns due to duplicate shutdown */
		return;
	}
	ctdb->db_persistent_check_errors = 0;

	tevent_add_timer(ctdb->ev, ctdb->monitor->monitor_context,
			 timeval_current(), ctdb_run_startup, ctdb);
}
Exemple #2
0
/*
  process a control request
 */
static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, 
				     struct ctdb_req_control_old *c,
				     TDB_DATA indata,
				     TDB_DATA *outdata, uint32_t srcnode,
				     const char **errormsg,
				     bool *async_reply)
{
	uint32_t opcode = c->opcode;
	uint64_t srvid = c->srvid;
	uint32_t client_id = c->client_id;

	switch (opcode) {
	case CTDB_CONTROL_PROCESS_EXISTS: {
		CHECK_CONTROL_DATA_SIZE(sizeof(pid_t));
		return ctdb_control_process_exists(ctdb, *(pid_t *)indata.dptr);
	}

	case CTDB_CONTROL_SET_DEBUG: {
		CHECK_CONTROL_DATA_SIZE(sizeof(int32_t));
		DEBUGLEVEL = *(int32_t *)indata.dptr;
		return 0;
	}

	case CTDB_CONTROL_GET_DEBUG: {
		CHECK_CONTROL_DATA_SIZE(0);
		outdata->dptr = (uint8_t *)&(DEBUGLEVEL);
		outdata->dsize = sizeof(DEBUGLEVEL);
		return 0;
	}

	case CTDB_CONTROL_STATISTICS: {
		CHECK_CONTROL_DATA_SIZE(0);
		ctdb->statistics.memory_used = talloc_total_size(NULL);
		ctdb->statistics.num_clients = ctdb->num_clients;
		ctdb->statistics.frozen = (ctdb_db_all_frozen(ctdb) ? 1 : 0);
		ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE);
		ctdb->statistics.statistics_current_time = timeval_current();

		outdata->dptr = (uint8_t *)&ctdb->statistics;
		outdata->dsize = sizeof(ctdb->statistics);
		return 0;
	}

	case CTDB_CONTROL_GET_ALL_TUNABLES: {
		CHECK_CONTROL_DATA_SIZE(0);
		outdata->dptr = (uint8_t *)&ctdb->tunable;
		outdata->dsize = sizeof(ctdb->tunable);
		return 0;
	}

	case CTDB_CONTROL_DUMP_MEMORY: {
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_dump_memory(ctdb, outdata);
	}

	case CTDB_CONTROL_STATISTICS_RESET: {
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(0);
		ZERO_STRUCT(ctdb->statistics);
		for (ctdb_db = ctdb->db_list;
		     ctdb_db != NULL;
		     ctdb_db = ctdb_db->next) {
			ctdb_db_statistics_reset(ctdb_db);
		}
		ctdb->statistics.statistics_start_time = timeval_current();
		return 0;
	}

	case CTDB_CONTROL_GETVNNMAP:
		return ctdb_control_getvnnmap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_GET_DBMAP:
		return ctdb_control_getdbmap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_GET_NODEMAPv4:
		return control_not_implemented("GET_NODEMAPv4", "GET_NODEMAP");

	case CTDB_CONTROL_GET_NODEMAP:
		return ctdb_control_getnodemap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_GET_NODES_FILE:
		return ctdb_control_getnodesfile(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_RELOAD_NODES_FILE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_reload_nodes_file(ctdb, opcode);

	case CTDB_CONTROL_SET_DB_STICKY: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		return ctdb_set_db_sticky(ctdb, ctdb_db);
	}

	case CTDB_CONTROL_SETVNNMAP:
		return ctdb_control_setvnnmap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_PULL_DB: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb));
		return ctdb_control_pull_db(ctdb, indata, outdata);

	case CTDB_CONTROL_SET_DMASTER: 
		return control_not_implemented("SET_DMASTER", NULL);

	case CTDB_CONTROL_PUSH_DB:
		return ctdb_control_push_db(ctdb, indata);

	case CTDB_CONTROL_GET_RECMODE: {
		return ctdb->recovery_mode;
	}

	case CTDB_CONTROL_SET_RECMASTER: {
		return ctdb_control_set_recmaster(ctdb, opcode, indata);
	}

	case CTDB_CONTROL_GET_RECMASTER:
		return ctdb->recovery_master;

	case CTDB_CONTROL_GET_PID:
		return getpid();

	case CTDB_CONTROL_GET_PNN:
		return ctdb->pnn;

	case CTDB_CONTROL_PING:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb->num_clients;

	case CTDB_CONTROL_GET_RUNSTATE:
		CHECK_CONTROL_DATA_SIZE(0);
		outdata->dptr = (uint8_t *)&ctdb->runstate;
		outdata->dsize = sizeof(uint32_t);
		return 0;


	case CTDB_CONTROL_SET_DB_READONLY: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		return ctdb_set_db_readonly(ctdb, ctdb_db);
	}
	case CTDB_CONTROL_GET_DBNAME: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		outdata->dptr = discard_const(ctdb_db->db_name);
		outdata->dsize = strlen(ctdb_db->db_name)+1;
		return 0;
	}

	case CTDB_CONTROL_GETDBPATH: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		outdata->dptr = discard_const(ctdb_db->db_path);
		outdata->dsize = strlen(ctdb_db->db_path)+1;
		return 0;
	}

	case CTDB_CONTROL_DB_ATTACH:
	  return ctdb_control_db_attach(ctdb, indata, outdata, srvid, false, client_id, c, async_reply);

	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
	  return ctdb_control_db_attach(ctdb, indata, outdata, srvid, true, client_id, c, async_reply);

	case CTDB_CONTROL_SET_CALL:
		return control_not_implemented("SET_CALL", NULL);

	case CTDB_CONTROL_TRAVERSE_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
		return ctdb_control_traverse_start(ctdb, indata, outdata, srcnode, client_id);

	case CTDB_CONTROL_TRAVERSE_START_EXT:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start_ext));
		return ctdb_control_traverse_start_ext(ctdb, indata, outdata, srcnode, client_id);

	case CTDB_CONTROL_TRAVERSE_ALL:
		return ctdb_control_traverse_all(ctdb, indata, outdata);

	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
		return ctdb_control_traverse_all_ext(ctdb, indata, outdata);

	case CTDB_CONTROL_TRAVERSE_DATA:
		return ctdb_control_traverse_data(ctdb, indata, outdata);

	case CTDB_CONTROL_TRAVERSE_KILL:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
		return ctdb_control_traverse_kill(ctdb, indata, outdata, srcnode);

	case CTDB_CONTROL_REGISTER_SRVID:
		return daemon_register_message_handler(ctdb, client_id, srvid);

	case CTDB_CONTROL_DEREGISTER_SRVID:
		return daemon_deregister_message_handler(ctdb, client_id, srvid);

	case CTDB_CONTROL_CHECK_SRVIDS:
		return daemon_check_srvids(ctdb, indata, outdata);

	case CTDB_CONTROL_ENABLE_SEQNUM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_ltdb_enable_seqnum(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_UPDATE_SEQNUM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		return ctdb_ltdb_update_seqnum(ctdb, *(uint32_t *)indata.dptr, srcnode);

	case CTDB_CONTROL_FREEZE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_freeze(ctdb, c, async_reply);

	case CTDB_CONTROL_THAW:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_thaw(ctdb, (uint32_t)c->srvid, true);

	case CTDB_CONTROL_SET_RECMODE:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		return ctdb_control_set_recmode(ctdb, c, indata, async_reply, errormsg);

	case CTDB_CONTROL_GET_MONMODE: 
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_monitoring_mode(ctdb);
		
	case CTDB_CONTROL_ENABLE_MONITOR: 
		CHECK_CONTROL_DATA_SIZE(0);
		ctdb_enable_monitoring(ctdb);
		return 0;
	
	case CTDB_CONTROL_RUN_EVENTSCRIPTS: 
		return ctdb_run_eventscripts(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_DISABLE_MONITOR: 
		CHECK_CONTROL_DATA_SIZE(0);
		ctdb_disable_monitoring(ctdb);
		return 0;

	case CTDB_CONTROL_SHUTDOWN:
		DEBUG(DEBUG_NOTICE,("Received SHUTDOWN command.\n"));
		ctdb_shutdown_sequence(ctdb, 0);
		/* In case above returns due to duplicate shutdown */
		return 0;

	case CTDB_CONTROL_TAKEOVER_IPv4:
		return control_not_implemented("TAKEOVER_IPv4", "TAKEOVER_IP");

	case CTDB_CONTROL_TAKEOVER_IP:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
		return ctdb_control_takeover_ip(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_RELEASE_IPv4:
		return control_not_implemented("RELEASE_IPv4", "RELEASE_IP");

	case CTDB_CONTROL_RELEASE_IP:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
		return ctdb_control_release_ip(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_IPREALLOCATED:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_ipreallocated(ctdb, c, async_reply);

	case CTDB_CONTROL_GET_PUBLIC_IPSv4:
		return control_not_implemented("GET_PUBLIC_IPSv4",
					       "GET_PUBLIC_IPS");

	case CTDB_CONTROL_GET_PUBLIC_IPS:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_public_ips(ctdb, c, outdata);

	case CTDB_CONTROL_TCP_CLIENT:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_client(ctdb, client_id, indata);

	case CTDB_CONTROL_STARTUP: 
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_startup(ctdb, srcnode);

	case CTDB_CONTROL_TCP_ADD: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_add(ctdb, indata, false);

	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_add(ctdb, indata, true);

	case CTDB_CONTROL_TCP_REMOVE: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_remove(ctdb, indata);

	case CTDB_CONTROL_SET_TUNABLE:
		return ctdb_control_set_tunable(ctdb, indata);

	case CTDB_CONTROL_GET_TUNABLE:
		return ctdb_control_get_tunable(ctdb, indata, outdata);

	case CTDB_CONTROL_LIST_TUNABLES:
		return ctdb_control_list_tunables(ctdb, outdata);

	case CTDB_CONTROL_MODIFY_FLAGS:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_node_flag_change));
		return ctdb_control_modflags(ctdb, indata);

	case CTDB_CONTROL_KILL_TCP: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_kill_tcp(ctdb, indata);

	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
		CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
		return ctdb_control_get_tcp_tickle_list(ctdb, indata, outdata);

	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
		/* data size is verified in the called function */
		return ctdb_control_set_tcp_tickle_list(ctdb, indata);

	case CTDB_CONTROL_REGISTER_SERVER_ID: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
		return ctdb_control_register_server_id(ctdb, client_id, indata);

	case CTDB_CONTROL_UNREGISTER_SERVER_ID: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
		return ctdb_control_unregister_server_id(ctdb, indata);

	case CTDB_CONTROL_CHECK_SERVER_ID: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
		return ctdb_control_check_server_id(ctdb, indata);

	case CTDB_CONTROL_GET_SERVER_ID_LIST:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_server_id_list(ctdb, outdata);

	case CTDB_CONTROL_PERSISTENT_STORE:
		return control_not_implemented("PERSISTENT_STORE", NULL);

	case CTDB_CONTROL_UPDATE_RECORD:
		return ctdb_control_update_record(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
		return ctdb_control_send_gratious_arp(ctdb, indata);

	case CTDB_CONTROL_TRANSACTION_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_transaction_start(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_TRANSACTION_COMMIT:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_WIPE_DATABASE:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
		return ctdb_control_wipe_database(ctdb, indata);

	case CTDB_CONTROL_UPTIME:
		return ctdb_control_uptime(ctdb, outdata);

	case CTDB_CONTROL_START_RECOVERY:
		return ctdb_control_start_recovery(ctdb, c, async_reply);

	case CTDB_CONTROL_END_RECOVERY:
		return ctdb_control_end_recovery(ctdb, c, async_reply);

	case CTDB_CONTROL_TRY_DELETE_RECORDS:
		return ctdb_control_try_delete_records(ctdb, indata, outdata);

	case CTDB_CONTROL_ADD_PUBLIC_IP:
		return ctdb_control_add_public_address(ctdb, indata);

	case CTDB_CONTROL_DEL_PUBLIC_IP:
		return ctdb_control_del_public_address(ctdb, c, indata,
						       async_reply);

	case CTDB_CONTROL_GET_CAPABILITIES:
		return ctdb_control_get_capabilities(ctdb, outdata);

	case CTDB_CONTROL_START_PERSISTENT_UPDATE:
		return ctdb_control_start_persistent_update(ctdb, c, indata);

	case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
		return ctdb_control_cancel_persistent_update(ctdb, c, indata);

	case CTDB_CONTROL_TRANS2_COMMIT:
	case CTDB_CONTROL_TRANS2_COMMIT_RETRY:
		return control_not_implemented("TRANS2_COMMIT", "TRANS3_COMMIT");

	case CTDB_CONTROL_TRANS2_ERROR:
		return control_not_implemented("TRANS2_ERROR", NULL);

	case CTDB_CONTROL_TRANS2_FINISHED:
		return control_not_implemented("TRANS2_FINISHED", NULL);

	case CTDB_CONTROL_TRANS2_ACTIVE:
		return control_not_implemented("TRANS2_ACTIVE", NULL);

	case CTDB_CONTROL_TRANS3_COMMIT:
		return ctdb_control_trans3_commit(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_RECD_PING:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_recd_ping(ctdb);

	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_get_event_script_status(ctdb, *(uint32_t *)indata.dptr, outdata);

	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
		CHECK_CONTROL_DATA_SIZE(sizeof(double));
		CTDB_UPDATE_RECLOCK_LATENCY(ctdb, "recd reclock", reclock.recd, *((double *)indata.dptr));
		return 0;
	case CTDB_CONTROL_GET_RECLOCK_FILE:
		CHECK_CONTROL_DATA_SIZE(0);
		if (ctdb->recovery_lock_file != NULL) {
			outdata->dptr  = discard_const(ctdb->recovery_lock_file);
			outdata->dsize = strlen(ctdb->recovery_lock_file) + 1;
		}
		return 0;
	case CTDB_CONTROL_SET_RECLOCK_FILE: {
		char *t;

		if (indata.dsize == 0) {
			TALLOC_FREE(ctdb->recovery_lock_file);
			return 0;
		}

		/* Return silent success if unchanged.  Recovery
		 * master updates all nodes on each recovery - we
		 * don't need the extra memory allocation or log
		 * message each time. */
		if (ctdb->recovery_lock_file != NULL &&
		    strcmp(discard_const(indata.dptr),
			   ctdb->recovery_lock_file) == 0) {
			return 0;
		}

		t = talloc_strdup(ctdb, discard_const(indata.dptr));
		if (t == NULL) {
			DEBUG(DEBUG_ERR, ("Out of memory in SET_RECLOCK_FILE\n"));
			return -1;
		}

		talloc_free(ctdb->recovery_lock_file);
		ctdb->recovery_lock_file = t;
		DEBUG(DEBUG_NOTICE, ("Updated recovery lock file to %s\n", t));

		return 0;
	}

	case CTDB_CONTROL_STOP_NODE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_stop_node(ctdb);

	case CTDB_CONTROL_CONTINUE_NODE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_continue_node(ctdb);

	case CTDB_CONTROL_SET_NATGWSTATE:
		return control_not_implemented("SET_NATGWSTATE", NULL);

	case CTDB_CONTROL_SET_LMASTERROLE: {
		uint32_t lmasterrole;

		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		lmasterrole = *(uint32_t *)indata.dptr;
		if (lmasterrole == 0) {
			ctdb->capabilities &= ~CTDB_CAP_LMASTER;
		} else {
			ctdb->capabilities |= CTDB_CAP_LMASTER;
		}
		return 0;
	}

	case CTDB_CONTROL_SET_RECMASTERROLE: {
		uint32_t recmasterrole;

		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		recmasterrole = *(uint32_t *)indata.dptr;
		if (recmasterrole == 0) {
			ctdb->capabilities &= ~CTDB_CAP_RECMASTER;
		} else {
			ctdb->capabilities |= CTDB_CAP_RECMASTER;
		}
		return 0;
	}

	case CTDB_CONTROL_ENABLE_SCRIPT:
		return ctdb_control_enable_script(ctdb, indata);

	case CTDB_CONTROL_DISABLE_SCRIPT:
		return ctdb_control_disable_script(ctdb, indata);

	case CTDB_CONTROL_SET_BAN_STATE:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_state));
		return ctdb_control_set_ban_state(ctdb, indata);

	case CTDB_CONTROL_GET_BAN_STATE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_ban_state(ctdb, outdata);

	case CTDB_CONTROL_SET_DB_PRIORITY:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_db_priority));
		return ctdb_control_set_db_priority(ctdb, indata, client_id);

	case CTDB_CONTROL_GET_DB_PRIORITY: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		return ctdb_db->priority;
	}

	case CTDB_CONTROL_TRANSACTION_CANCEL:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_transaction_cancel(ctdb);

	case CTDB_CONTROL_REGISTER_NOTIFY:
		return ctdb_control_register_notify(ctdb, client_id, indata);

	case CTDB_CONTROL_DEREGISTER_NOTIFY:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
		return ctdb_control_deregister_notify(ctdb, client_id, indata);

	case CTDB_CONTROL_GET_LOG:
		return control_not_implemented("GET_LOG", NULL);

	case CTDB_CONTROL_CLEAR_LOG:
		return control_not_implemented("CLEAR_LOG", NULL);

	case CTDB_CONTROL_GET_DB_SEQNUM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
		return ctdb_control_get_db_seqnum(ctdb, indata, outdata);

	case CTDB_CONTROL_DB_SET_HEALTHY:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_set_healthy(ctdb, indata);

	case CTDB_CONTROL_DB_GET_HEALTH:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_get_health(ctdb, indata, outdata);

	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
		CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
		return ctdb_control_get_public_ip_info(ctdb, c, indata, outdata);

	case CTDB_CONTROL_GET_IFACES:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_ifaces(ctdb, c, outdata);

	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_iface));
		return ctdb_control_set_iface_link(ctdb, c, indata);

	case CTDB_CONTROL_GET_STAT_HISTORY:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_stat_history(ctdb, c, outdata);

	case CTDB_CONTROL_SCHEDULE_FOR_DELETION: {
		struct ctdb_control_schedule_for_deletion *d;
		size_t size = offsetof(struct ctdb_control_schedule_for_deletion, key);
		CHECK_CONTROL_MIN_DATA_SIZE(size);
		d = (struct ctdb_control_schedule_for_deletion *)indata.dptr;
		size += d->keylen;
		CHECK_CONTROL_DATA_SIZE(size);
		return ctdb_control_schedule_for_deletion(ctdb, indata);
	}
	case CTDB_CONTROL_GET_DB_STATISTICS:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_get_db_statistics(ctdb, *(uint32_t *)indata.dptr, outdata);

	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_reload_public_ips(ctdb, c, async_reply);

	case CTDB_CONTROL_RECEIVE_RECORDS:
		return ctdb_control_receive_records(ctdb, indata, outdata);

	case CTDB_CONTROL_DB_DETACH:
		return ctdb_control_db_detach(ctdb, indata, client_id);

	case CTDB_CONTROL_DB_FREEZE:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_freeze(ctdb, c, *(uint32_t *)indata.dptr,
					      async_reply);

	case CTDB_CONTROL_DB_THAW:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_DB_TRANSACTION_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
		return ctdb_control_db_transaction_start(ctdb, indata);

	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
		return ctdb_control_db_transaction_commit(ctdb, indata);

	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_transaction_cancel(ctdb, indata);

	case CTDB_CONTROL_DB_PULL:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb_ext));
		return ctdb_control_db_pull(ctdb, c, indata, outdata);

	case CTDB_CONTROL_DB_PUSH_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb_ext));
		return ctdb_control_db_push_start(ctdb, indata);

	case CTDB_CONTROL_DB_PUSH_CONFIRM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_push_confirm(ctdb, indata, outdata);

	default:
		DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
		return -1;
	}
}