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