xref: /freebsd-src/sbin/hastd/control.c (revision 5c2bc3db201a4fe8d7911cf816bea104d5dc2138)
132115b10SPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
432115b10SPawel Jakub Dawidek  * Copyright (c) 2009-2010 The FreeBSD Foundation
532115b10SPawel Jakub Dawidek  *
632115b10SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
732115b10SPawel Jakub Dawidek  * the FreeBSD Foundation.
832115b10SPawel Jakub Dawidek  *
932115b10SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1032115b10SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1132115b10SPawel Jakub Dawidek  * are met:
1232115b10SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1332115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1432115b10SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1532115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1632115b10SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1732115b10SPawel Jakub Dawidek  *
1832115b10SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1932115b10SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2032115b10SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2132115b10SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2232115b10SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2332115b10SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2432115b10SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2532115b10SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2632115b10SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2732115b10SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2832115b10SPawel Jakub Dawidek  * SUCH DAMAGE.
2932115b10SPawel Jakub Dawidek  */
3032115b10SPawel Jakub Dawidek 
3132115b10SPawel Jakub Dawidek #include <sys/types.h>
3232115b10SPawel Jakub Dawidek #include <sys/wait.h>
3332115b10SPawel Jakub Dawidek 
3432115b10SPawel Jakub Dawidek #include <errno.h>
3532115b10SPawel Jakub Dawidek #include <pthread.h>
36351b9a37SPawel Jakub Dawidek #include <signal.h>
3732115b10SPawel Jakub Dawidek #include <stdio.h>
3832115b10SPawel Jakub Dawidek #include <string.h>
390c24d8e2SPawel Jakub Dawidek #include <unistd.h>
4032115b10SPawel Jakub Dawidek 
4132115b10SPawel Jakub Dawidek #include "hast.h"
4232115b10SPawel Jakub Dawidek #include "hastd.h"
431fee97b0SPawel Jakub Dawidek #include "hast_checksum.h"
448cd3d45aSPawel Jakub Dawidek #include "hast_compression.h"
4532115b10SPawel Jakub Dawidek #include "hast_proto.h"
46a870e771SPawel Jakub Dawidek #include "hooks.h"
4732115b10SPawel Jakub Dawidek #include "nv.h"
4832115b10SPawel Jakub Dawidek #include "pjdlog.h"
4932115b10SPawel Jakub Dawidek #include "proto.h"
5032115b10SPawel Jakub Dawidek #include "subr.h"
5132115b10SPawel Jakub Dawidek 
5232115b10SPawel Jakub Dawidek #include "control.h"
5332115b10SPawel Jakub Dawidek 
540c24d8e2SPawel Jakub Dawidek void
550c24d8e2SPawel Jakub Dawidek child_cleanup(struct hast_resource *res)
560c24d8e2SPawel Jakub Dawidek {
570c24d8e2SPawel Jakub Dawidek 
580c24d8e2SPawel Jakub Dawidek 	proto_close(res->hr_ctrl);
590c24d8e2SPawel Jakub Dawidek 	res->hr_ctrl = NULL;
60022f07b6SPawel Jakub Dawidek 	if (res->hr_event != NULL) {
610c24d8e2SPawel Jakub Dawidek 		proto_close(res->hr_event);
620c24d8e2SPawel Jakub Dawidek 		res->hr_event = NULL;
63022f07b6SPawel Jakub Dawidek 	}
6432ecf620SPawel Jakub Dawidek 	if (res->hr_conn != NULL) {
6532ecf620SPawel Jakub Dawidek 		proto_close(res->hr_conn);
6632ecf620SPawel Jakub Dawidek 		res->hr_conn = NULL;
6732ecf620SPawel Jakub Dawidek 	}
680c24d8e2SPawel Jakub Dawidek 	res->hr_workerpid = 0;
690c24d8e2SPawel Jakub Dawidek }
700c24d8e2SPawel Jakub Dawidek 
7132115b10SPawel Jakub Dawidek static void
72a00829bbSPawel Jakub Dawidek control_set_role_common(struct hastd_config *cfg, struct nv *nvout,
73a00829bbSPawel Jakub Dawidek     uint8_t role, struct hast_resource *res, const char *name, unsigned int no)
7432115b10SPawel Jakub Dawidek {
75a870e771SPawel Jakub Dawidek 	int oldrole;
7632115b10SPawel Jakub Dawidek 
7732115b10SPawel Jakub Dawidek 	/* Name is always needed. */
78a00829bbSPawel Jakub Dawidek 	if (name != NULL)
7932115b10SPawel Jakub Dawidek 		nv_add_string(nvout, name, "resource%u", no);
8032115b10SPawel Jakub Dawidek 
8132115b10SPawel Jakub Dawidek 	if (res == NULL) {
82571fdd7eSPawel Jakub Dawidek 		PJDLOG_ASSERT(cfg != NULL);
83571fdd7eSPawel Jakub Dawidek 		PJDLOG_ASSERT(name != NULL);
84a00829bbSPawel Jakub Dawidek 
8532115b10SPawel Jakub Dawidek 		TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
8632115b10SPawel Jakub Dawidek 			if (strcmp(res->hr_name, name) == 0)
8732115b10SPawel Jakub Dawidek 				break;
8832115b10SPawel Jakub Dawidek 		}
8932115b10SPawel Jakub Dawidek 		if (res == NULL) {
9032115b10SPawel Jakub Dawidek 			nv_add_int16(nvout, EHAST_NOENTRY, "error%u", no);
9132115b10SPawel Jakub Dawidek 			return;
9232115b10SPawel Jakub Dawidek 		}
9332115b10SPawel Jakub Dawidek 	}
94571fdd7eSPawel Jakub Dawidek 	PJDLOG_ASSERT(res != NULL);
9532115b10SPawel Jakub Dawidek 
9632115b10SPawel Jakub Dawidek 	/* Send previous role back. */
9732115b10SPawel Jakub Dawidek 	nv_add_string(nvout, role2str(res->hr_role), "role%u", no);
9832115b10SPawel Jakub Dawidek 
9932115b10SPawel Jakub Dawidek 	/* Nothing changed, return here. */
10032115b10SPawel Jakub Dawidek 	if (role == res->hr_role)
10132115b10SPawel Jakub Dawidek 		return;
10232115b10SPawel Jakub Dawidek 
10332115b10SPawel Jakub Dawidek 	pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
10432115b10SPawel Jakub Dawidek 	pjdlog_info("Role changed to %s.", role2str(role));
10532115b10SPawel Jakub Dawidek 
10632115b10SPawel Jakub Dawidek 	/* Change role to the new one. */
107a870e771SPawel Jakub Dawidek 	oldrole = res->hr_role;
10832115b10SPawel Jakub Dawidek 	res->hr_role = role;
10932115b10SPawel Jakub Dawidek 	pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
11032115b10SPawel Jakub Dawidek 
11132115b10SPawel Jakub Dawidek 	/*
11232115b10SPawel Jakub Dawidek 	 * If previous role was primary or secondary we have to kill process
11332115b10SPawel Jakub Dawidek 	 * doing that work.
11432115b10SPawel Jakub Dawidek 	 */
11532115b10SPawel Jakub Dawidek 	if (res->hr_workerpid != 0) {
1162b1b224dSPawel Jakub Dawidek 		if (kill(res->hr_workerpid, SIGTERM) == -1) {
11732115b10SPawel Jakub Dawidek 			pjdlog_errno(LOG_WARNING,
11832115b10SPawel Jakub Dawidek 			    "Unable to kill worker process %u",
11932115b10SPawel Jakub Dawidek 			    (unsigned int)res->hr_workerpid);
12032115b10SPawel Jakub Dawidek 		} else if (waitpid(res->hr_workerpid, NULL, 0) !=
12132115b10SPawel Jakub Dawidek 		    res->hr_workerpid) {
12232115b10SPawel Jakub Dawidek 			pjdlog_errno(LOG_WARNING,
12332115b10SPawel Jakub Dawidek 			    "Error while waiting for worker process %u",
12432115b10SPawel Jakub Dawidek 			    (unsigned int)res->hr_workerpid);
12532115b10SPawel Jakub Dawidek 		} else {
12632115b10SPawel Jakub Dawidek 			pjdlog_debug(1, "Worker process %u stopped.",
12732115b10SPawel Jakub Dawidek 			    (unsigned int)res->hr_workerpid);
12832115b10SPawel Jakub Dawidek 		}
1290c24d8e2SPawel Jakub Dawidek 		child_cleanup(res);
13032115b10SPawel Jakub Dawidek 	}
13132115b10SPawel Jakub Dawidek 
13232115b10SPawel Jakub Dawidek 	/* Start worker process if we are changing to primary. */
13332115b10SPawel Jakub Dawidek 	if (role == HAST_ROLE_PRIMARY)
13432115b10SPawel Jakub Dawidek 		hastd_primary(res);
13532115b10SPawel Jakub Dawidek 	pjdlog_prefix_set("%s", "");
136a870e771SPawel Jakub Dawidek 	hook_exec(res->hr_exec, "role", res->hr_name, role2str(oldrole),
137a870e771SPawel Jakub Dawidek 	    role2str(res->hr_role), NULL);
13832115b10SPawel Jakub Dawidek }
13932115b10SPawel Jakub Dawidek 
140a00829bbSPawel Jakub Dawidek void
141a00829bbSPawel Jakub Dawidek control_set_role(struct hast_resource *res, uint8_t role)
142a00829bbSPawel Jakub Dawidek {
143a00829bbSPawel Jakub Dawidek 
144a00829bbSPawel Jakub Dawidek 	control_set_role_common(NULL, NULL, role, res, NULL, 0);
145a00829bbSPawel Jakub Dawidek }
146a00829bbSPawel Jakub Dawidek 
14732115b10SPawel Jakub Dawidek static void
14832115b10SPawel Jakub Dawidek control_status_worker(struct hast_resource *res, struct nv *nvout,
14932115b10SPawel Jakub Dawidek     unsigned int no)
15032115b10SPawel Jakub Dawidek {
15132115b10SPawel Jakub Dawidek 	struct nv *cnvin, *cnvout;
15232115b10SPawel Jakub Dawidek 	const char *str;
15332115b10SPawel Jakub Dawidek 	int error;
15432115b10SPawel Jakub Dawidek 
1550687d71eSMikolaj Golub 	cnvin = NULL;
15632115b10SPawel Jakub Dawidek 
15732115b10SPawel Jakub Dawidek 	/*
15832115b10SPawel Jakub Dawidek 	 * Prepare and send command to worker process.
15932115b10SPawel Jakub Dawidek 	 */
16032115b10SPawel Jakub Dawidek 	cnvout = nv_alloc();
1617a2b8368SMikolaj Golub 	nv_add_uint8(cnvout, CONTROL_STATUS, "cmd");
16232115b10SPawel Jakub Dawidek 	error = nv_error(cnvout);
16332115b10SPawel Jakub Dawidek 	if (error != 0) {
16479e82fe2SPawel Jakub Dawidek 		pjdlog_common(LOG_ERR, 0, error,
16579e82fe2SPawel Jakub Dawidek 		    "Unable to prepare control header");
16632115b10SPawel Jakub Dawidek 		goto end;
16732115b10SPawel Jakub Dawidek 	}
1682b1b224dSPawel Jakub Dawidek 	if (hast_proto_send(res, res->hr_ctrl, cnvout, NULL, 0) == -1) {
16932115b10SPawel Jakub Dawidek 		error = errno;
17079e82fe2SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to send control header");
17132115b10SPawel Jakub Dawidek 		goto end;
17232115b10SPawel Jakub Dawidek 	}
17332115b10SPawel Jakub Dawidek 
17432115b10SPawel Jakub Dawidek 	/*
17532115b10SPawel Jakub Dawidek 	 * Receive response.
17632115b10SPawel Jakub Dawidek 	 */
1772b1b224dSPawel Jakub Dawidek 	if (hast_proto_recv_hdr(res->hr_ctrl, &cnvin) == -1) {
17832115b10SPawel Jakub Dawidek 		error = errno;
17979e82fe2SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to receive control header");
18032115b10SPawel Jakub Dawidek 		goto end;
18132115b10SPawel Jakub Dawidek 	}
18232115b10SPawel Jakub Dawidek 
183911a2aa3SPawel Jakub Dawidek 	error = nv_get_int16(cnvin, "error");
18432115b10SPawel Jakub Dawidek 	if (error != 0)
18532115b10SPawel Jakub Dawidek 		goto end;
18632115b10SPawel Jakub Dawidek 
18732115b10SPawel Jakub Dawidek 	if ((str = nv_get_string(cnvin, "status")) == NULL) {
18832115b10SPawel Jakub Dawidek 		error = ENOENT;
18979e82fe2SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Field 'status' is missing.");
19032115b10SPawel Jakub Dawidek 		goto end;
19132115b10SPawel Jakub Dawidek 	}
19232115b10SPawel Jakub Dawidek 	nv_add_string(nvout, str, "status%u", no);
19332115b10SPawel Jakub Dawidek 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "dirty"), "dirty%u", no);
19432115b10SPawel Jakub Dawidek 	nv_add_uint32(nvout, nv_get_uint32(cnvin, "extentsize"),
19532115b10SPawel Jakub Dawidek 	    "extentsize%u", no);
19632115b10SPawel Jakub Dawidek 	nv_add_uint32(nvout, nv_get_uint32(cnvin, "keepdirty"),
19732115b10SPawel Jakub Dawidek 	    "keepdirty%u", no);
1983db86c39SPawel Jakub Dawidek 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_read"),
1993db86c39SPawel Jakub Dawidek 	    "stat_read%u", no);
2003db86c39SPawel Jakub Dawidek 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_write"),
2013db86c39SPawel Jakub Dawidek 	    "stat_write%u", no);
2023db86c39SPawel Jakub Dawidek 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_delete"),
2033db86c39SPawel Jakub Dawidek 	    "stat_delete%u", no);
2043db86c39SPawel Jakub Dawidek 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_flush"),
2053db86c39SPawel Jakub Dawidek 	    "stat_flush%u", no);
2063db86c39SPawel Jakub Dawidek 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_activemap_update"),
2073db86c39SPawel Jakub Dawidek 	    "stat_activemap_update%u", no);
2082adbba66SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_read_error"),
2092adbba66SMikolaj Golub 	    "stat_read_error%u", no);
2102adbba66SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_write_error"),
2112adbba66SMikolaj Golub 	    "stat_write_error%u", no);
2122adbba66SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_delete_error"),
2132adbba66SMikolaj Golub 	    "stat_delete_error%u", no);
2142adbba66SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_flush_error"),
2152adbba66SMikolaj Golub 	    "stat_flush_error%u", no);
2166b66c350SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "idle_queue_size"),
2176b66c350SMikolaj Golub 	    "idle_queue_size%u", no);
2186b66c350SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "local_queue_size"),
2196b66c350SMikolaj Golub 	    "local_queue_size%u", no);
2206b66c350SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "send_queue_size"),
2216b66c350SMikolaj Golub 	    "send_queue_size%u", no);
2226b66c350SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "recv_queue_size"),
2236b66c350SMikolaj Golub 	    "recv_queue_size%u", no);
2246b66c350SMikolaj Golub 	nv_add_uint64(nvout, nv_get_uint64(cnvin, "done_queue_size"),
2256b66c350SMikolaj Golub 	    "done_queue_size%u", no);
22632115b10SPawel Jakub Dawidek end:
22732115b10SPawel Jakub Dawidek 	if (cnvin != NULL)
22832115b10SPawel Jakub Dawidek 		nv_free(cnvin);
22932115b10SPawel Jakub Dawidek 	if (cnvout != NULL)
23032115b10SPawel Jakub Dawidek 		nv_free(cnvout);
23132115b10SPawel Jakub Dawidek 	if (error != 0)
23232115b10SPawel Jakub Dawidek 		nv_add_int16(nvout, error, "error");
23332115b10SPawel Jakub Dawidek }
23432115b10SPawel Jakub Dawidek 
23532115b10SPawel Jakub Dawidek static void
23632115b10SPawel Jakub Dawidek control_status(struct hastd_config *cfg, struct nv *nvout,
23732115b10SPawel Jakub Dawidek     struct hast_resource *res, const char *name, unsigned int no)
23832115b10SPawel Jakub Dawidek {
23932115b10SPawel Jakub Dawidek 
240571fdd7eSPawel Jakub Dawidek 	PJDLOG_ASSERT(cfg != NULL);
241571fdd7eSPawel Jakub Dawidek 	PJDLOG_ASSERT(nvout != NULL);
242571fdd7eSPawel Jakub Dawidek 	PJDLOG_ASSERT(name != NULL);
24332115b10SPawel Jakub Dawidek 
24432115b10SPawel Jakub Dawidek 	/* Name is always needed. */
24532115b10SPawel Jakub Dawidek 	nv_add_string(nvout, name, "resource%u", no);
24632115b10SPawel Jakub Dawidek 
24732115b10SPawel Jakub Dawidek 	if (res == NULL) {
24832115b10SPawel Jakub Dawidek 		TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
24932115b10SPawel Jakub Dawidek 			if (strcmp(res->hr_name, name) == 0)
25032115b10SPawel Jakub Dawidek 				break;
25132115b10SPawel Jakub Dawidek 		}
25232115b10SPawel Jakub Dawidek 		if (res == NULL) {
25332115b10SPawel Jakub Dawidek 			nv_add_int16(nvout, EHAST_NOENTRY, "error%u", no);
25432115b10SPawel Jakub Dawidek 			return;
25532115b10SPawel Jakub Dawidek 		}
25632115b10SPawel Jakub Dawidek 	}
257571fdd7eSPawel Jakub Dawidek 	PJDLOG_ASSERT(res != NULL);
25832115b10SPawel Jakub Dawidek 	nv_add_string(nvout, res->hr_provname, "provname%u", no);
25932115b10SPawel Jakub Dawidek 	nv_add_string(nvout, res->hr_localpath, "localpath%u", no);
26032115b10SPawel Jakub Dawidek 	nv_add_string(nvout, res->hr_remoteaddr, "remoteaddr%u", no);
2610b626a28SPawel Jakub Dawidek 	if (res->hr_sourceaddr[0] != '\0')
2620b626a28SPawel Jakub Dawidek 		nv_add_string(nvout, res->hr_sourceaddr, "sourceaddr%u", no);
26332115b10SPawel Jakub Dawidek 	switch (res->hr_replication) {
26432115b10SPawel Jakub Dawidek 	case HAST_REPLICATION_FULLSYNC:
26532115b10SPawel Jakub Dawidek 		nv_add_string(nvout, "fullsync", "replication%u", no);
26632115b10SPawel Jakub Dawidek 		break;
26732115b10SPawel Jakub Dawidek 	case HAST_REPLICATION_MEMSYNC:
26832115b10SPawel Jakub Dawidek 		nv_add_string(nvout, "memsync", "replication%u", no);
26932115b10SPawel Jakub Dawidek 		break;
27032115b10SPawel Jakub Dawidek 	case HAST_REPLICATION_ASYNC:
27132115b10SPawel Jakub Dawidek 		nv_add_string(nvout, "async", "replication%u", no);
27232115b10SPawel Jakub Dawidek 		break;
27332115b10SPawel Jakub Dawidek 	default:
27432115b10SPawel Jakub Dawidek 		nv_add_string(nvout, "unknown", "replication%u", no);
27532115b10SPawel Jakub Dawidek 		break;
27632115b10SPawel Jakub Dawidek 	}
2771fee97b0SPawel Jakub Dawidek 	nv_add_string(nvout, checksum_name(res->hr_checksum),
2781fee97b0SPawel Jakub Dawidek 	    "checksum%u", no);
2798cd3d45aSPawel Jakub Dawidek 	nv_add_string(nvout, compression_name(res->hr_compression),
2808cd3d45aSPawel Jakub Dawidek 	    "compression%u", no);
28132115b10SPawel Jakub Dawidek 	nv_add_string(nvout, role2str(res->hr_role), "role%u", no);
28214f200d9SMikolaj Golub 	nv_add_int32(nvout, res->hr_workerpid, "workerpid%u", no);
28332115b10SPawel Jakub Dawidek 
28432115b10SPawel Jakub Dawidek 	switch (res->hr_role) {
28532115b10SPawel Jakub Dawidek 	case HAST_ROLE_PRIMARY:
286571fdd7eSPawel Jakub Dawidek 		PJDLOG_ASSERT(res->hr_workerpid != 0);
28732115b10SPawel Jakub Dawidek 		/* FALLTHROUGH */
28832115b10SPawel Jakub Dawidek 	case HAST_ROLE_SECONDARY:
28932115b10SPawel Jakub Dawidek 		if (res->hr_workerpid != 0)
29032115b10SPawel Jakub Dawidek 			break;
29132115b10SPawel Jakub Dawidek 		/* FALLTHROUGH */
29232115b10SPawel Jakub Dawidek 	default:
29332115b10SPawel Jakub Dawidek 		return;
29432115b10SPawel Jakub Dawidek 	}
29532115b10SPawel Jakub Dawidek 
29632115b10SPawel Jakub Dawidek 	/*
29732115b10SPawel Jakub Dawidek 	 * If we are here, it means that we have a worker process, which we
29832115b10SPawel Jakub Dawidek 	 * want to ask some questions.
29932115b10SPawel Jakub Dawidek 	 */
30032115b10SPawel Jakub Dawidek 	control_status_worker(res, nvout, no);
30132115b10SPawel Jakub Dawidek }
30232115b10SPawel Jakub Dawidek 
30332115b10SPawel Jakub Dawidek void
30432115b10SPawel Jakub Dawidek control_handle(struct hastd_config *cfg)
30532115b10SPawel Jakub Dawidek {
30632115b10SPawel Jakub Dawidek 	struct proto_conn *conn;
30732115b10SPawel Jakub Dawidek 	struct nv *nvin, *nvout;
30832115b10SPawel Jakub Dawidek 	unsigned int ii;
30932115b10SPawel Jakub Dawidek 	const char *str;
31032115b10SPawel Jakub Dawidek 	uint8_t cmd, role;
31132115b10SPawel Jakub Dawidek 	int error;
31232115b10SPawel Jakub Dawidek 
3132b1b224dSPawel Jakub Dawidek 	if (proto_accept(cfg->hc_controlconn, &conn) == -1) {
31432115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to accept control connection");
31532115b10SPawel Jakub Dawidek 		return;
31632115b10SPawel Jakub Dawidek 	}
31732115b10SPawel Jakub Dawidek 
31819654a23SPawel Jakub Dawidek 	cfg->hc_controlin = conn;
31932115b10SPawel Jakub Dawidek 	nvin = nvout = NULL;
32032115b10SPawel Jakub Dawidek 	role = HAST_ROLE_UNDEF;
32132115b10SPawel Jakub Dawidek 
3222b1b224dSPawel Jakub Dawidek 	if (hast_proto_recv_hdr(conn, &nvin) == -1) {
32332115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to receive control header");
32432115b10SPawel Jakub Dawidek 		nvin = NULL;
32532115b10SPawel Jakub Dawidek 		goto close;
32632115b10SPawel Jakub Dawidek 	}
32732115b10SPawel Jakub Dawidek 
32832115b10SPawel Jakub Dawidek 	/* Obtain command code. 0 means that nv_get_uint8() failed. */
32932115b10SPawel Jakub Dawidek 	cmd = nv_get_uint8(nvin, "cmd");
33032115b10SPawel Jakub Dawidek 	if (cmd == 0) {
33132115b10SPawel Jakub Dawidek 		pjdlog_error("Control header is missing 'cmd' field.");
33232115b10SPawel Jakub Dawidek 		goto close;
33332115b10SPawel Jakub Dawidek 	}
33432115b10SPawel Jakub Dawidek 
33532115b10SPawel Jakub Dawidek 	/* Allocate outgoing nv structure. */
33632115b10SPawel Jakub Dawidek 	nvout = nv_alloc();
33732115b10SPawel Jakub Dawidek 	if (nvout == NULL) {
33832115b10SPawel Jakub Dawidek 		pjdlog_error("Unable to allocate header for control response.");
33932115b10SPawel Jakub Dawidek 		goto close;
34032115b10SPawel Jakub Dawidek 	}
34132115b10SPawel Jakub Dawidek 
34232115b10SPawel Jakub Dawidek 	error = 0;
34332115b10SPawel Jakub Dawidek 
34432115b10SPawel Jakub Dawidek 	str = nv_get_string(nvin, "resource0");
34532115b10SPawel Jakub Dawidek 	if (str == NULL) {
34632115b10SPawel Jakub Dawidek 		pjdlog_error("Control header is missing 'resource0' field.");
34732115b10SPawel Jakub Dawidek 		error = EHAST_INVALID;
34832115b10SPawel Jakub Dawidek 		goto fail;
34932115b10SPawel Jakub Dawidek 	}
3501768fba5SMikolaj Golub 	if (cmd == HASTCTL_CMD_SETROLE) {
35132115b10SPawel Jakub Dawidek 		role = nv_get_uint8(nvin, "role");
35232115b10SPawel Jakub Dawidek 		switch (role) {
353ed646d4dSPawel Jakub Dawidek 		case HAST_ROLE_INIT:
35432115b10SPawel Jakub Dawidek 		case HAST_ROLE_PRIMARY:
35532115b10SPawel Jakub Dawidek 		case HAST_ROLE_SECONDARY:
35632115b10SPawel Jakub Dawidek 			break;
35732115b10SPawel Jakub Dawidek 		default:
35832115b10SPawel Jakub Dawidek 			pjdlog_error("Invalid role received (%hhu).", role);
35932115b10SPawel Jakub Dawidek 			error = EHAST_INVALID;
36032115b10SPawel Jakub Dawidek 			goto fail;
36132115b10SPawel Jakub Dawidek 		}
36232115b10SPawel Jakub Dawidek 	}
36332115b10SPawel Jakub Dawidek 	if (strcmp(str, "all") == 0) {
36432115b10SPawel Jakub Dawidek 		struct hast_resource *res;
36532115b10SPawel Jakub Dawidek 
36632115b10SPawel Jakub Dawidek 		/* All configured resources. */
36732115b10SPawel Jakub Dawidek 
36832115b10SPawel Jakub Dawidek 		ii = 0;
36932115b10SPawel Jakub Dawidek 		TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
37032115b10SPawel Jakub Dawidek 			switch (cmd) {
3711768fba5SMikolaj Golub 			case HASTCTL_CMD_SETROLE:
372a00829bbSPawel Jakub Dawidek 				control_set_role_common(cfg, nvout, role, res,
37332115b10SPawel Jakub Dawidek 				    res->hr_name, ii++);
37432115b10SPawel Jakub Dawidek 				break;
3751768fba5SMikolaj Golub 			case HASTCTL_CMD_STATUS:
37632115b10SPawel Jakub Dawidek 				control_status(cfg, nvout, res, res->hr_name,
37732115b10SPawel Jakub Dawidek 				    ii++);
37832115b10SPawel Jakub Dawidek 				break;
37932115b10SPawel Jakub Dawidek 			default:
38032115b10SPawel Jakub Dawidek 				pjdlog_error("Invalid command received (%hhu).",
38132115b10SPawel Jakub Dawidek 				    cmd);
38232115b10SPawel Jakub Dawidek 				error = EHAST_UNIMPLEMENTED;
38332115b10SPawel Jakub Dawidek 				goto fail;
38432115b10SPawel Jakub Dawidek 			}
38532115b10SPawel Jakub Dawidek 		}
38632115b10SPawel Jakub Dawidek 	} else {
38732115b10SPawel Jakub Dawidek 		/* Only selected resources. */
38832115b10SPawel Jakub Dawidek 
38932115b10SPawel Jakub Dawidek 		for (ii = 0; ; ii++) {
39032115b10SPawel Jakub Dawidek 			str = nv_get_string(nvin, "resource%u", ii);
39132115b10SPawel Jakub Dawidek 			if (str == NULL)
39232115b10SPawel Jakub Dawidek 				break;
39332115b10SPawel Jakub Dawidek 			switch (cmd) {
3941768fba5SMikolaj Golub 			case HASTCTL_CMD_SETROLE:
395a00829bbSPawel Jakub Dawidek 				control_set_role_common(cfg, nvout, role, NULL,
396a00829bbSPawel Jakub Dawidek 				    str, ii);
39732115b10SPawel Jakub Dawidek 				break;
3981768fba5SMikolaj Golub 			case HASTCTL_CMD_STATUS:
39932115b10SPawel Jakub Dawidek 				control_status(cfg, nvout, NULL, str, ii);
40032115b10SPawel Jakub Dawidek 				break;
40132115b10SPawel Jakub Dawidek 			default:
40232115b10SPawel Jakub Dawidek 				pjdlog_error("Invalid command received (%hhu).",
40332115b10SPawel Jakub Dawidek 				    cmd);
40432115b10SPawel Jakub Dawidek 				error = EHAST_UNIMPLEMENTED;
40532115b10SPawel Jakub Dawidek 				goto fail;
40632115b10SPawel Jakub Dawidek 			}
40732115b10SPawel Jakub Dawidek 		}
40832115b10SPawel Jakub Dawidek 	}
40932115b10SPawel Jakub Dawidek 	if (nv_error(nvout) != 0)
41032115b10SPawel Jakub Dawidek 		goto close;
41132115b10SPawel Jakub Dawidek fail:
41232115b10SPawel Jakub Dawidek 	if (error != 0)
41332115b10SPawel Jakub Dawidek 		nv_add_int16(nvout, error, "error");
41432115b10SPawel Jakub Dawidek 
4152b1b224dSPawel Jakub Dawidek 	if (hast_proto_send(NULL, conn, nvout, NULL, 0) == -1)
41632115b10SPawel Jakub Dawidek 		pjdlog_errno(LOG_ERR, "Unable to send control response");
41732115b10SPawel Jakub Dawidek close:
41832115b10SPawel Jakub Dawidek 	if (nvin != NULL)
41932115b10SPawel Jakub Dawidek 		nv_free(nvin);
42032115b10SPawel Jakub Dawidek 	if (nvout != NULL)
42132115b10SPawel Jakub Dawidek 		nv_free(nvout);
42232115b10SPawel Jakub Dawidek 	proto_close(conn);
42319654a23SPawel Jakub Dawidek 	cfg->hc_controlin = NULL;
42432115b10SPawel Jakub Dawidek }
42532115b10SPawel Jakub Dawidek 
42632115b10SPawel Jakub Dawidek /*
42732115b10SPawel Jakub Dawidek  * Thread handles control requests from the parent.
42832115b10SPawel Jakub Dawidek  */
42932115b10SPawel Jakub Dawidek void *
43032115b10SPawel Jakub Dawidek ctrl_thread(void *arg)
43132115b10SPawel Jakub Dawidek {
43232115b10SPawel Jakub Dawidek 	struct hast_resource *res = arg;
43332115b10SPawel Jakub Dawidek 	struct nv *nvin, *nvout;
43432115b10SPawel Jakub Dawidek 	uint8_t cmd;
43532115b10SPawel Jakub Dawidek 
43632115b10SPawel Jakub Dawidek 	for (;;) {
4372b1b224dSPawel Jakub Dawidek 		if (hast_proto_recv_hdr(res->hr_ctrl, &nvin) == -1) {
43832115b10SPawel Jakub Dawidek 			if (sigexit_received)
43932115b10SPawel Jakub Dawidek 				pthread_exit(NULL);
44032115b10SPawel Jakub Dawidek 			pjdlog_errno(LOG_ERR,
44132115b10SPawel Jakub Dawidek 			    "Unable to receive control message");
442c56cf19eSPawel Jakub Dawidek 			kill(getpid(), SIGTERM);
443c56cf19eSPawel Jakub Dawidek 			pthread_exit(NULL);
44432115b10SPawel Jakub Dawidek 		}
44532115b10SPawel Jakub Dawidek 		cmd = nv_get_uint8(nvin, "cmd");
44632115b10SPawel Jakub Dawidek 		if (cmd == 0) {
44732115b10SPawel Jakub Dawidek 			pjdlog_error("Control message is missing 'cmd' field.");
44832115b10SPawel Jakub Dawidek 			nv_free(nvin);
44932115b10SPawel Jakub Dawidek 			continue;
45032115b10SPawel Jakub Dawidek 		}
45132115b10SPawel Jakub Dawidek 		nvout = nv_alloc();
45232115b10SPawel Jakub Dawidek 		switch (cmd) {
4537a2b8368SMikolaj Golub 		case CONTROL_STATUS:
45432115b10SPawel Jakub Dawidek 			if (res->hr_remotein != NULL &&
45532115b10SPawel Jakub Dawidek 			    res->hr_remoteout != NULL) {
45632115b10SPawel Jakub Dawidek 				nv_add_string(nvout, "complete", "status");
45732115b10SPawel Jakub Dawidek 			} else {
45832115b10SPawel Jakub Dawidek 				nv_add_string(nvout, "degraded", "status");
45932115b10SPawel Jakub Dawidek 			}
46032115b10SPawel Jakub Dawidek 			nv_add_uint32(nvout, (uint32_t)res->hr_extentsize,
46132115b10SPawel Jakub Dawidek 			    "extentsize");
46232115b10SPawel Jakub Dawidek 			if (res->hr_role == HAST_ROLE_PRIMARY) {
46332115b10SPawel Jakub Dawidek 				nv_add_uint32(nvout,
46432115b10SPawel Jakub Dawidek 				    (uint32_t)res->hr_keepdirty, "keepdirty");
46532115b10SPawel Jakub Dawidek 				nv_add_uint64(nvout,
46632115b10SPawel Jakub Dawidek 				    (uint64_t)(activemap_ndirty(res->hr_amp) *
46732115b10SPawel Jakub Dawidek 				    res->hr_extentsize), "dirty");
46832115b10SPawel Jakub Dawidek 			} else {
46932115b10SPawel Jakub Dawidek 				nv_add_uint32(nvout, (uint32_t)0, "keepdirty");
47032115b10SPawel Jakub Dawidek 				nv_add_uint64(nvout, (uint64_t)0, "dirty");
47132115b10SPawel Jakub Dawidek 			}
4723db86c39SPawel Jakub Dawidek 			nv_add_uint64(nvout, res->hr_stat_read, "stat_read");
4733db86c39SPawel Jakub Dawidek 			nv_add_uint64(nvout, res->hr_stat_write, "stat_write");
4743db86c39SPawel Jakub Dawidek 			nv_add_uint64(nvout, res->hr_stat_delete,
4753db86c39SPawel Jakub Dawidek 			    "stat_delete");
4763db86c39SPawel Jakub Dawidek 			nv_add_uint64(nvout, res->hr_stat_flush, "stat_flush");
4773db86c39SPawel Jakub Dawidek 			nv_add_uint64(nvout, res->hr_stat_activemap_update,
4783db86c39SPawel Jakub Dawidek 			    "stat_activemap_update");
4792adbba66SMikolaj Golub 			nv_add_uint64(nvout, res->hr_stat_read_error,
4802adbba66SMikolaj Golub 			    "stat_read_error");
4812adbba66SMikolaj Golub 			nv_add_uint64(nvout, res->hr_stat_write_error +
4822adbba66SMikolaj Golub 			    res->hr_stat_activemap_write_error,
4832adbba66SMikolaj Golub 			    "stat_write_error");
4842adbba66SMikolaj Golub 			nv_add_uint64(nvout, res->hr_stat_delete_error,
4852adbba66SMikolaj Golub 			    "stat_delete_error");
4862adbba66SMikolaj Golub 			nv_add_uint64(nvout, res->hr_stat_flush_error +
4872adbba66SMikolaj Golub 			    res->hr_stat_activemap_flush_error,
4882adbba66SMikolaj Golub 			    "stat_flush_error");
4896b66c350SMikolaj Golub 			res->output_status_aux(nvout);
490115f4e5cSPawel Jakub Dawidek 			nv_add_int16(nvout, 0, "error");
491115f4e5cSPawel Jakub Dawidek 			break;
4927a2b8368SMikolaj Golub 		case CONTROL_RELOAD:
493115f4e5cSPawel Jakub Dawidek 			/*
494115f4e5cSPawel Jakub Dawidek 			 * When parent receives SIGHUP and discovers that
495115f4e5cSPawel Jakub Dawidek 			 * something related to us has changes, it sends reload
496115f4e5cSPawel Jakub Dawidek 			 * message to us.
497115f4e5cSPawel Jakub Dawidek 			 */
498571fdd7eSPawel Jakub Dawidek 			PJDLOG_ASSERT(res->hr_role == HAST_ROLE_PRIMARY);
499115f4e5cSPawel Jakub Dawidek 			primary_config_reload(res, nvin);
500115f4e5cSPawel Jakub Dawidek 			nv_add_int16(nvout, 0, "error");
50132115b10SPawel Jakub Dawidek 			break;
50232115b10SPawel Jakub Dawidek 		default:
50332115b10SPawel Jakub Dawidek 			nv_add_int16(nvout, EINVAL, "error");
50432115b10SPawel Jakub Dawidek 			break;
50532115b10SPawel Jakub Dawidek 		}
506115f4e5cSPawel Jakub Dawidek 		nv_free(nvin);
50732115b10SPawel Jakub Dawidek 		if (nv_error(nvout) != 0) {
50832115b10SPawel Jakub Dawidek 			pjdlog_error("Unable to create answer on control message.");
50932115b10SPawel Jakub Dawidek 			nv_free(nvout);
51032115b10SPawel Jakub Dawidek 			continue;
51132115b10SPawel Jakub Dawidek 		}
5122b1b224dSPawel Jakub Dawidek 		if (hast_proto_send(NULL, res->hr_ctrl, nvout, NULL, 0) == -1) {
51332115b10SPawel Jakub Dawidek 			pjdlog_errno(LOG_ERR,
51432115b10SPawel Jakub Dawidek 			    "Unable to send reply to control message");
51532115b10SPawel Jakub Dawidek 		}
51632115b10SPawel Jakub Dawidek 		nv_free(nvout);
51732115b10SPawel Jakub Dawidek 	}
51832115b10SPawel Jakub Dawidek 	/* NOTREACHED */
51932115b10SPawel Jakub Dawidek 	return (NULL);
52032115b10SPawel Jakub Dawidek }
521