2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <wait.h>
2N/A#include <sys/time.h>
2N/A#include <syslog.h>
2N/A
2N/A#include <meta.h>
2N/A#include <sys/lvm/mdio.h>
2N/A#include <sys/lvm/md_mddb.h>
2N/A#include <sys/lvm/md_mirror.h>
2N/A
2N/A#define MAX_N_ARGS 64
2N/A#define MAX_ARG_LEN 1024
2N/A#define MAX_SLEEPS 99
2N/A#define SLEEP_MOD 5
2N/A
2N/A/* we reserve 1024 bytes for stdout and the same for stderr */
2N/A#define MAX_OUT 1024
2N/A#define MAX_ERR 1024
2N/A#define JUNK 128 /* used to flush stdout and stderr */
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_cmd(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A
2N/A /*
2N/A * We are given one string containing all the arguments
2N/A * For execvp() we have to regenerate the arguments again
2N/A */
2N/A int arg; /* argument that is currently been built */
2N/A int index; /* runs through arg above */
2N/A int i; /* helper for for loop */
2N/A char *argv[MAX_N_ARGS]; /* argument array for execvp */
2N/A char *cp; /* runs through the given command line string */
2N/A char *command = NULL; /* the command we call locally */
2N/A int pout[2]; /* pipe for stdout */
2N/A int perr[2]; /* pipe for stderr */
2N/A pid_t pid; /* process id */
2N/A
2N/A cp = msg->msg_event_data;
2N/A arg = 0;
2N/A index = 0;
2N/A
2N/A /* init the args array alloc the first one and null out the rest */
2N/A argv[0] = Malloc(MAX_ARG_LEN);
2N/A for (i = 1; i < MAX_N_ARGS; i++) {
2N/A argv[i] = NULL;
2N/A }
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A
2N/A while (*cp != '\0') {
2N/A if (arg == MAX_N_ARGS) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: too many arguments specified\n"));
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A goto out;
2N/A }
2N/A if (index == MAX_ARG_LEN) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: argument too long\n"));
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A if ((*cp != ' ') && (*cp != '\t')) {
2N/A /*
2N/A * No space or tab: copy char into current
2N/A * argv and advance both pointers
2N/A */
2N/A
2N/A argv[arg][index] = *cp;
2N/A cp++; /* next char in command line */
2N/A index++; /* next char in argument */
2N/A } else {
2N/A /*
2N/A * space or tab: terminate current argv,
2N/A * advance arg, reset pointer into arg,
2N/A * advance pointer in command line
2N/A */
2N/A argv[arg][index] = '\0';
2N/A arg++; /* next argument */
2N/A argv[arg] = Malloc(MAX_ARG_LEN);
2N/A cp++; /* next char in command line */
2N/A index = 0; /* starts at char 0 */
2N/A }
2N/A }
2N/A /* terminate the last real argument */
2N/A argv[arg][index] = '\0';
2N/A /* the last argument is an NULL pointer */
2N/A argv[++arg] = NULL;
2N/A if (pipe(pout) < 0) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: pipe failed\n"));
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A goto out;
2N/A }
2N/A if (pipe(perr) < 0) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: pipe failed\n"));
2N/A (void) close(pout[0]);
2N/A (void) close(pout[1]);
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A goto out;
2N/A }
2N/A command = Strdup(argv[0]);
2N/A (void) strcat(argv[0], ".rpc_call");
2N/A pid = fork1();
2N/A if (pid == (pid_t)-1) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: fork failed\n"));
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A (void) close(pout[0]);
2N/A (void) close(pout[1]);
2N/A (void) close(perr[0]);
2N/A (void) close(perr[1]);
2N/A goto out;
2N/A } else if (pid == (pid_t)0) {
2N/A /* child */
2N/A (void) close(0);
2N/A /* close the reading channels of pout and perr */
2N/A (void) close(pout[0]);
2N/A (void) close(perr[0]);
2N/A /* redirect stdout */
2N/A if (dup2(pout[1], 1) < 0) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: dup2 failed\n"));
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A return;
2N/A }
2N/A
2N/A /* redirect stderr */
2N/A if (dup2(perr[1], 2) < 0) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "PANIC: dup2 failed\n"));
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A return;
2N/A }
2N/A
2N/A (void) execvp(command, (char *const *)argv);
2N/A perror("execvp");
2N/A _exit(1);
2N/A } else {
2N/A /* parent process */
2N/A int stat_loc;
2N/A char *out, *err; /* for stdout and stderr of child */
2N/A int i; /* index into the aboves */
2N/A char junk[JUNK];
2N/A int out_done = 0;
2N/A int err_done = 0;
2N/A int out_read = 0;
2N/A int err_read = 0;
2N/A int maxfd;
2N/A fd_set rset;
2N/A
2N/A
2N/A /* close the writing channels of pout and perr */
2N/A (void) close(pout[1]);
2N/A (void) close(perr[1]);
2N/A resp->mmr_out = Malloc(MAX_OUT);
2N/A resp->mmr_err = Malloc(MAX_ERR);
2N/A resp->mmr_out_size = MAX_OUT;
2N/A resp->mmr_err_size = MAX_ERR;
2N/A out = resp->mmr_out;
2N/A err = resp->mmr_err;
2N/A FD_ZERO(&rset);
2N/A while ((out_done == 0) || (err_done == 0)) {
2N/A FD_SET(pout[0], &rset);
2N/A FD_SET(perr[0], &rset);
2N/A maxfd = max(pout[0], perr[0]) + 1;
2N/A (void) select(maxfd, &rset, NULL, NULL, NULL);
2N/A
2N/A /*
2N/A * Did the child produce some output to stdout?
2N/A * If so, read it until we either reach the end of the
2N/A * output or until we read MAX_OUT bytes.
2N/A * Whatever comes first.
2N/A * In case we already read MAX_OUT bytes we simply
2N/A * read away the output into a junk buffer.
2N/A * Just to make the child happy
2N/A */
2N/A if (FD_ISSET(pout[0], &rset)) {
2N/A if (MAX_OUT - out_read - 1 > 0) {
2N/A i = read(pout[0], out,
2N/A MAX_OUT - out_read);
2N/A out_read += i;
2N/A out += i;
2N/A } else {
2N/A /* buffer full, empty stdout */
2N/A i = read(pout[0], junk, JUNK);
2N/A }
2N/A if (i == 0) {
2N/A /* stdout is closed by child */
2N/A out_done++;
2N/A }
2N/A }
2N/A /* same comment as above | sed -e 's/stdout/stderr/' */
2N/A if (FD_ISSET(perr[0], &rset)) {
2N/A if (MAX_ERR - err_read - 1 > 0) {
2N/A i = read(perr[0], err,
2N/A MAX_ERR - err_read);
2N/A err_read += i;
2N/A err += i;
2N/A } else {
2N/A /* buffer full, empty stderr */
2N/A i = read(perr[0], junk, JUNK);
2N/A }
2N/A if (i == 0) {
2N/A /* stderr is closed by child */
2N/A err_done++;
2N/A }
2N/A }
2N/A }
2N/A resp->mmr_out[out_read] = '\0';
2N/A resp->mmr_err[err_read] = '\0';
2N/A
2N/A while (waitpid(pid, &stat_loc, 0) < 0) {
2N/A if (errno != EINTR) {
2N/A resp->mmr_comm_state = MDMNE_HANDLER_FAILED;
2N/A break;
2N/A }
2N/A }
2N/A if (errno == 0)
2N/A resp->mmr_exitval = WEXITSTATUS(stat_loc);
2N/A
2N/A (void) close(pout[0]);
2N/A (void) close(perr[0]);
2N/A }
2N/Aout:
2N/A for (i = 0; i < MAX_N_ARGS; i++) {
2N/A if (argv[i] != NULL) {
2N/A free(argv[i]);
2N/A }
2N/A }
2N/A if (command != NULL) {
2N/A Free(command);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This is for checking if a metadevice is opened, and for
2N/A * locking in case it is not and for
2N/A * unlocking a locked device
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_clu(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A if (msg->msg_type == MD_MN_MSG_CLU_CHECK) {
2N/A md_isopen_t *d;
2N/A int ret;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_isopen_t *)(void *)msg->msg_event_data;
2N/A ret = metaioctl(MD_IOCISOPEN, d, &(d->mde), NULL);
2N/A /*
2N/A * In case the ioctl succeeded, return the open state of
2N/A * the metadevice. Otherwise we return the error the ioctl
2N/A * produced. As this is not zero, no attempt is made to
2N/A * remove/rename the metadevice later
2N/A */
2N/A
2N/A if (ret == 0) {
2N/A resp->mmr_exitval = d->isopen;
2N/A } else {
2N/A /*
2N/A * When doing a metaclear, one node after the other
2N/A * does the two steps:
2N/A * - check on all nodes if this md is opened.
2N/A * - remove the md locally.
2N/A * When the 2nd node asks all nodes if the md is
2N/A * open it starts with the first node.
2N/A * As this already removed the md, the check
2N/A * returns MDE_UNIT_NOT_SETUP.
2N/A * In order to not keep the 2nd node from proceeding,
2N/A * we map this to an Ok.
2N/A */
2N/A if (mdismderror(&(d->mde), MDE_UNIT_NOT_SETUP)) {
2N/A mdclrerror(&(d->mde));
2N/A ret = 0;
2N/A }
2N/A
2N/A resp->mmr_exitval = ret;
2N/A }
2N/A }
2N/A}
2N/A
2N/A/* handler for MD_MN_MSG_REQUIRE_OWNER */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_req_owner(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_set_mmown_params_t setown;
2N/A md_mn_req_owner_t *d;
2N/A int ret, n = 0;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_req_owner_t *)(void *)msg->msg_event_data;
2N/A
2N/A (void) memset(&setown, 0, sizeof (setown));
2N/A MD_SETDRIVERNAME(&setown, MD_MIRROR, MD_MIN2SET(d->mnum))
2N/A setown.d.mnum = d->mnum;
2N/A setown.d.owner = d->owner;
2N/A
2N/A /* Retry ownership change if we get EAGAIN returned */
2N/A while ((ret = metaioctl(MD_MN_SET_MM_OWNER, &setown, &setown.mde, NULL))
2N/A != 0) {
2N/A md_sys_error_t *ip =
2N/A &setown.mde.info.md_error_info_t_u.sys_error;
2N/A if (ip->errnum != EAGAIN) {
2N/A break;
2N/A }
2N/A if (n++ >= 10) {
2N/A break;
2N/A }
2N/A (void) sleep(1);
2N/A }
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * handler for MD_MN_MSG_CHOOSE_OWNER
2N/A * This is called when a mirror resync has no owner. The master node generates
2N/A * this message which is not broadcast to the other nodes. The message is
2N/A * required as the kernel does not have access to the nodelist for the set.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_choose_owner(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_chowner_t chownermsg;
2N/A md_mn_msg_chooseid_t *d;
2N/A int ret = 0;
2N/A int nodecnt;
2N/A int nodeno;
2N/A uint_t nodeid;
2N/A uint_t myflags;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A md_set_desc *sd;
2N/A md_mnnode_desc *nd;
2N/A md_error_t mde = mdnullerror;
2N/A md_mn_result_t *resp1 = NULL;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_chooseid_t *)(void *)msg->msg_event_data;
2N/A
2N/A /*
2N/A * The node to be chosen will be the resync count for the set
2N/A * modulo the number of live nodes in the set
2N/A */
2N/A setno = MD_MIN2SET(d->msg_chooseid_mnum);
2N/A if ((sp = metasetnosetname(setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_CHOOSE_OWNER: Invalid setno %d\n"), setno);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A if ((sd = metaget_setdesc(sp, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_CHOOSE_OWNER: Invalid set pointer\n"));
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A /* Count the number of live nodes */
2N/A nodecnt = 0;
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A if (nd->nd_flags & MD_MN_NODE_ALIVE)
2N/A nodecnt++;
2N/A nd = nd->nd_next;
2N/A }
2N/A nodeno = (d->msg_chooseid_rcnt%nodecnt);
2N/A
2N/A /*
2N/A * If we've been called with msg_chooseid_set_node set TRUE then we
2N/A * are simply re-setting the owner id to ensure consistency across
2N/A * the cluster.
2N/A * If the flag is reset (B_FALSE) we are requesting a new owner to be
2N/A * determined.
2N/A */
2N/A if (d->msg_chooseid_set_node) {
2N/A nodeid = d->msg_chooseid_rcnt;
2N/A } else {
2N/A /* scan the nodelist looking for the required node */
2N/A nodecnt = 0;
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A if (nd->nd_flags & MD_MN_NODE_ALIVE) {
2N/A if (nodecnt == nodeno)
2N/A break;
2N/A nodecnt++;
2N/A }
2N/A nd = nd->nd_next;
2N/A }
2N/A nodeid = nd->nd_nodeid;
2N/A }
2N/A
2N/A /* Send message to all nodes to make ownership change */
2N/A chownermsg.msg_chowner_mnum = d->msg_chooseid_mnum;
2N/A chownermsg.msg_chowner_nodeid = nodeid;
2N/A myflags = MD_MSGF_NO_LOG;
2N/A
2N/A /* inherit some flags from the parent message */
2N/A myflags |= msg->msg_flags & MD_MSGF_INHERIT_BITS;
2N/A
2N/A ret = mdmn_send_message(MD_MIN2SET(d->msg_chooseid_mnum),
2N/A MD_MN_MSG_CHANGE_OWNER, myflags, 0, (char *)&chownermsg,
2N/A sizeof (chownermsg), &resp1, &mde);
2N/A if (resp1 != NULL)
2N/A free_result(resp1);
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_CHANGE_OWNER
2N/A * This is called when we are perfoming a resync and wish to change from
2N/A * no mirror owner to an owner chosen by the master.
2N/A * This mesage is only relevant for the new owner, the message will be
2N/A * ignored by all other nodes
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_change_owner(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_set_mmown_params_t setown;
2N/A md_mn_msg_chowner_t *d;
2N/A int ret = 0;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A md_set_desc *sd;
2N/A md_error_t mde = mdnullerror;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_chowner_t *)(void *)msg->msg_event_data;
2N/A
2N/A setno = MD_MIN2SET(d->msg_chowner_mnum);
2N/A if ((sp = metasetnosetname(setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_CHANGE_OWNER: Invalid setno %d\n"), setno);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A if ((sd = metaget_setdesc(sp, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_CHANGE_OWNER: Invalid set pointer\n"));
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A if (d->msg_chowner_nodeid == sd->sd_mn_mynode->nd_nodeid) {
2N/A /*
2N/A * If we are the chosen owner, issue ioctl to make the
2N/A * ownership change
2N/A */
2N/A (void) memset(&setown, 0, sizeof (md_set_mmown_params_t));
2N/A setown.d.mnum = d->msg_chowner_mnum;
2N/A setown.d.owner = d->msg_chowner_nodeid;
2N/A setown.d.flags = MD_MN_MM_SPAWN_THREAD;
2N/A MD_SETDRIVERNAME(&setown, MD_MIRROR,
2N/A MD_MIN2SET(d->msg_chowner_mnum));
2N/A
2N/A /*
2N/A * Single shot at changing the the owner, if it fails EAGAIN,
2N/A * another node must have become the owner while we are in the
2N/A * process of making this choice.
2N/A */
2N/A
2N/A ret = metaioctl(MD_MN_SET_MM_OWNER, &setown,
2N/A &(setown.mde), NULL);
2N/A if (ret == EAGAIN)
2N/A ret = 0;
2N/A }
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/* handler for MD_MN_MSG_SUSPEND_WRITES */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_susp_write(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A /* Suspend writes to a region of a mirror */
2N/A md_suspend_wr_params_t suspwr_ioc;
2N/A md_mn_msg_suspwr_t *d;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_suspwr_t *)(void *)msg->msg_event_data;
2N/A
2N/A (void) memset(&suspwr_ioc, 0, sizeof (md_suspend_wr_params_t));
2N/A MD_SETDRIVERNAME(&suspwr_ioc, MD_MIRROR,
2N/A MD_MIN2SET(d->msg_suspwr_mnum));
2N/A suspwr_ioc.mnum = d->msg_suspwr_mnum;
2N/A ret = metaioctl(MD_MN_SUSPEND_WRITES, &suspwr_ioc,
2N/A &(suspwr_ioc.mde), NULL);
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * handler for MD_MN_MSG_STATE_UPDATE_RESWR
2N/A * This functions update a submirror component state and then resumes writes
2N/A * to the mirror
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_state_upd_reswr(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A /* Update the state of the component of a mirror */
2N/A md_set_state_params_t setstate_ioc;
2N/A md_mn_msg_stch_t *d;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_stch_t *)(void *)msg->msg_event_data;
2N/A
2N/A (void) memset(&setstate_ioc, 0, sizeof (md_set_state_params_t));
2N/A MD_SETDRIVERNAME(&setstate_ioc, MD_MIRROR,
2N/A MD_MIN2SET(d->msg_stch_mnum));
2N/A setstate_ioc.mnum = d->msg_stch_mnum;
2N/A setstate_ioc.sm = d->msg_stch_sm;
2N/A setstate_ioc.comp = d->msg_stch_comp;
2N/A setstate_ioc.state = d->msg_stch_new_state;
2N/A setstate_ioc.hs_id = d->msg_stch_hs_id;
2N/A ret = metaioctl(MD_MN_SET_STATE, &setstate_ioc,
2N/A &(setstate_ioc.mde), NULL);
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * submessage generator for MD_MN_MSG_STATE_UPDATE and MD_MN_MSG_STATE_UPDATE2
2N/A * This generates 2 messages, the first is SUSPEND_WRITES and
2N/A * depending on the type of the original message the second one is
2N/A * either STATE_UPDATE_RESWR or STATE_UPDATE_RESWR2 which actually does
2N/A * the same, but runs on a higher class.
2N/A */
2N/Aint
2N/Amdmn_smgen_state_upd(md_mn_msg_t *msg, md_mn_msg_t *msglist[])
2N/A{
2N/A md_mn_msg_t *nmsg;
2N/A md_mn_msg_stch_t *d;
2N/A md_mn_msg_stch_t *stch_data;
2N/A md_mn_msg_suspwr_t *suspwr_data;
2N/A
2N/A d = (md_mn_msg_stch_t *)(void *)msg->msg_event_data;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG; /* Don't log submessages */
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_SUSPEND_WRITES;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_suspwr_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_suspwr_t));
2N/A suspwr_data = (md_mn_msg_suspwr_t *)(void *)nmsg->msg_event_data;
2N/A suspwr_data->msg_suspwr_mnum = d->msg_stch_mnum;
2N/A msglist[0] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG; /* Don't log submessages */
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A if (msg->msg_type == MD_MN_MSG_STATE_UPDATE2) {
2N/A nmsg->msg_type = MD_MN_MSG_STATE_UPDATE_RESWR2;
2N/A } else {
2N/A nmsg->msg_type = MD_MN_MSG_STATE_UPDATE_RESWR;
2N/A }
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_stch_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_stch_t));
2N/A stch_data = (md_mn_msg_stch_t *)(void *)nmsg->msg_event_data;
2N/A stch_data->msg_stch_mnum = d->msg_stch_mnum;
2N/A stch_data->msg_stch_sm = d->msg_stch_sm;
2N/A stch_data->msg_stch_comp = d->msg_stch_comp;
2N/A stch_data->msg_stch_new_state = d->msg_stch_new_state;
2N/A stch_data->msg_stch_hs_id = d->msg_stch_hs_id;
2N/A msglist[1] = nmsg;
2N/A return (2); /* Return the number of submessages generated */
2N/A}
2N/A
2N/A/*
2N/A * handler for MD_MN_MSG_ALLOCATE_HOTSPARE and MD_MN_MSG_ALLOCATE_HOTSPARE2
2N/A * This sends a message to all nodes requesting them to allocate a hotspare
2N/A * for the specified component. The component is specified by the mnum of
2N/A * the mirror, the submirror index and the component index.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_allocate_hotspare(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A /* Allocate a hotspare for a mirror component */
2N/A md_alloc_hotsp_params_t allochsp_ioc;
2N/A md_mn_msg_allochsp_t *d;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_allochsp_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&allochsp_ioc, 0,
2N/A sizeof (md_alloc_hotsp_params_t));
2N/A MD_SETDRIVERNAME(&allochsp_ioc, MD_MIRROR,
2N/A MD_MIN2SET(d->msg_allochsp_mnum));
2N/A allochsp_ioc.mnum = d->msg_allochsp_mnum;
2N/A allochsp_ioc.sm = d->msg_allochsp_sm;
2N/A allochsp_ioc.comp = d->msg_allochsp_comp;
2N/A allochsp_ioc.hs_id = d->msg_allochsp_hs_id;
2N/A ret = metaioctl(MD_MN_ALLOCATE_HOTSPARE, &allochsp_ioc,
2N/A &(allochsp_ioc.mde), NULL);
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * handler for MD_MN_MSG_RESYNC_STARTING,MD_MN_MSG_RESYNC_FIRST,
2N/A * MD_MN_MSG_RESYNC_NEXT, MD_MN_MSG_RESYNC_FINISH, MD_MN_MSG_RESYNC_PHASE_DONE
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_resync(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_resync_t *d;
2N/A md_mn_rs_params_t respar;
2N/A mddb_setflags_config_t sf;
2N/A md_error_t ep = mdnullerror;
2N/A mdsetname_t *sp;
2N/A int ret;
2N/A int smi;
2N/A int start_flag = 1;
2N/A int sleep_count = 0;
2N/A unsigned int sleep_time = 2;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_resync_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&respar, 0, sizeof (respar));
2N/A MD_SETDRIVERNAME(&respar, MD_MIRROR,
2N/A MD_MIN2SET(d->msg_resync_mnum))
2N/A respar.msg_type = (int)msg->msg_type;
2N/A respar.mnum = d->msg_resync_mnum;
2N/A respar.rs_type = d->msg_resync_type;
2N/A respar.rs_start = d->msg_resync_start;
2N/A respar.rs_size = d->msg_resync_rsize;
2N/A respar.rs_done = d->msg_resync_done;
2N/A respar.rs_2_do = d->msg_resync_2_do;
2N/A respar.rs_originator = d->msg_originator;
2N/A respar.rs_flags = d->msg_resync_flags;
2N/A
2N/A for (smi = 0; smi < NMIRROR; smi++) {
2N/A respar.rs_sm_state[smi] = d->msg_sm_state[smi];
2N/A respar.rs_sm_flags[smi] = d->msg_sm_flags[smi];
2N/A }
2N/A
2N/A /*
2N/A * Prior to running the resync thread first check that the start_step
2N/A * flag (MD_SET_MN_START_RC) added by metaclust's MC_START step has been
2N/A * removed from the set record flags. Ordinarily, this would be removed
2N/A * at MC_STEP4 in metaclust - need to ensure this has happened on all
2N/A * nodes.
2N/A */
2N/A (void) memset(&sf, 0, sizeof (sf));
2N/A sf.sf_setno = MD_MIN2SET(d->msg_resync_mnum);
2N/A sf.sf_flags = MDDB_NM_GET;
2N/A /* Use magic to help protect ioctl against attack. */
2N/A sf.sf_magic = MDDB_SETFLAGS_MAGIC;
2N/A if ((sp = metasetnosetname(sf.sf_setno, &ep)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MDMN_DO_RESYNC: Invalid setno = %d\n"),
2N/A sf.sf_setno);
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A /* start_flag always true initially */
2N/A while (start_flag) {
2N/A if (metaioctl(MD_MN_GET_SETFLAGS, &sf, &sf.sf_mde, NULL) != 0) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MDMN_DO_RESYNC: Could not get start_step "
2N/A "flag for set %s - returning\n"),
2N/A sp->setname);
2N/A (void) mdstealerror(&(resp->mmr_ep), &sf.sf_mde);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A /* metaioctl returns successfully - is start flag cleared? */
2N/A if (sf.sf_setflags & MD_SET_MN_START_RC) {
2N/A start_flag = 1;
2N/A (void) sleep(sleep_time);
2N/A sleep_count++;
2N/A if ((sleep_count == 1) ||
2N/A (sleep_count % SLEEP_MOD) == 0) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MDMN_DO_RESYNC: Waiting for start_step "
2N/A "flag for set %s to be cleared\n"),
2N/A sp->setname);
2N/A }
2N/A if (sleep_count == MAX_SLEEPS) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MDMN_DO_RESYNC: Could not clear "
2N/A "start_step flag for set %s "
2N/A "- returning\n"), sp->setname);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A } else {
2N/A start_flag = 0;
2N/A }
2N/A }
2N/A
2N/A ret = metaioctl(MD_MN_RESYNC, &respar, &respar.mde, NULL);
2N/A if (ret) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &respar.mde);
2N/A }
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * handler for MD_MN_MSG_SETSYNC
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_setsync(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_setsync_t *d;
2N/A md_resync_ioctl_t ri;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_setsync_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&ri, 0, sizeof (ri));
2N/A MD_SETDRIVERNAME(&ri, MD_MIRROR, MD_MIN2SET(d->setsync_mnum))
2N/A ri.ri_mnum = d->setsync_mnum;
2N/A ri.ri_copysize = d->setsync_copysize;
2N/A ri.ri_flags = d->setsync_flags;
2N/A
2N/A ret = metaioctl(MD_MN_SETSYNC, &ri, &ri.mde, NULL);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * handler for MD_MN_MSG_SET_CAP. As this handler can deal with both mirrors
2N/A * and soft partitions, the driver name that is required for the ioctl call
2N/A * is included in the message.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_set_cap(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_setcap_t *d;
2N/A md_mn_setcap_params_t setcap_ioc;
2N/A minor_t mnum;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_setcap_t *)((void *)(msg->msg_event_data));
2N/A mnum = d->msg_setcap_mnum;
2N/A
2N/A (void) memset(&setcap_ioc, 0, sizeof (setcap_ioc));
2N/A
2N/A MD_SETDRIVERNAME(&setcap_ioc, d->msg_setcap_driver, MD_MIN2SET(mnum));
2N/A setcap_ioc.mnum = mnum;
2N/A setcap_ioc.sc_set = d->msg_setcap_set;
2N/A
2N/A ret = metaioctl(MD_MN_SET_CAP, &setcap_ioc, &setcap_ioc.mde, NULL);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Dummy handler for various CLASS0 messages like
2N/A * MD_MN_MSG_VERBOSITY / MD_MN_MSG_RESUME / MD_MN_MSG_SUSPEND ...
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_dummy(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_exitval = 0;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A}
2N/A
2N/A/*
2N/A * Overall description of mdcommd support that keeps all nodes in-sync
2N/A * with the ondisk diskset mddbs.
2N/A *
2N/A * All configuration changes to the mddb - addition/deletion of metadevices
2N/A * or replicas must use a CLASS1 message to block out these changes.
2N/A * Changes to the state of existing replicas do not need to block CLASS1
2N/A * since there is no conflict when just updating the state of a replica.
2N/A *
2N/A * Error encountered when master writes to mddbs:
2N/A * As the master updates parts of the mddbs, flags are updated describing
2N/A * what has been written. When all locks are dropped (either in
2N/A * mddb_setexit or mdioctl), a PARSE message will be generated to all
2N/A * nodes with an index list of known good mddbs and the parse flags.
2N/A * The master node ignore the parse message since it sent it.
2N/A * The slave nodes re-read in the changed part of the mddb using the list
2N/A * of known good replicas that was passed.
2N/A * PARSE message does not block CLASS1.
2N/A * The PARSE message must be the highest class message. Since this
2N/A * message could be sent on any ioctl, this PARSE message class must
2N/A * be higher than any other class message that could issue an ioctl.
2N/A *
2N/A * Master Slave1 Slave2
2N/A * Handles_error
2N/A * PARSE PARSE PARSE
2N/A *
2N/A *
2N/A * Add/Delete mddbs can occur from the following commands:
2N/A * metadb -s set_name -a/-d
2N/A * metaset -s set_name -a/-d disk
2N/A * metaset -s set_name -b
2N/A *
2N/A * The metadb/metaset command is run on the node executing the command
2N/A * and sends an ATTACH/DETACH message to the master node blocking CLASS1
2N/A * messages on all nodes until this message is finished. The master
2N/A * node generates 3 submessages of BLOCK, SM_ATTACH/SM_DETACH, UNBLOCK.
2N/A * The BLOCK message is only run on the master node and will BLOCK
2N/A * the PARSE messages from being sent to the nodes.
2N/A * The SM_ATTACH/SM_DETACH message is run on all nodes and actually adds or
2N/A * removes the replica(s) from the given disk slice.
2N/A * The UNBLOCK message is only run on the master node and allows the
2N/A * sending of PARSE messages.
2N/A *
2N/A * Master Slave1 Slave2
2N/A * Add mddb cmd
2N/A * ATTACH msg to master
2N/A * BLOCK
2N/A * ATTACH ATTACH ATTACH
2N/A * UNBLOCK
2N/A * PARSE PARSE PARSE
2N/A * ATTACH msg finished
2N/A *
2N/A * Add/Delete host side information from the following commands:
2N/A * metaset -s set_name -a/-d -h
2N/A *
2N/A * The metaset command is run on the node executing the command and
2N/A * sends a DB_NEWSIDE/DB_DELSIDE message and a MD_NEWSIDE/MD_DELSIDE
2N/A * message whenever a host is added to or deleted from the diskset.
2N/A *
2N/A * The side information contains the major name and minor number
2N/A * associated with a disk slice from a certain node's perspective
2N/A * in an (failed) effort to support clustered systems that don't have the
2N/A * same device name for a physical device. (The original designers of
2N/A * SVM eventually took the shortcut of assuming that all device names
2N/A * are the same on all systems, but left the side information in the
2N/A * mddb and namespace.) The side information is used for disk slices
2N/A * that contain mddbs and/or are components for metadevices.
2N/A *
2N/A * The DB_NEWSIDE/DELSIDE command adds or deletes the side information
2N/A * for each mddb for the host being added or deleted.
2N/A * The MD_ADDSIDE/MD_DELSIDE command adds or deletes the side information
2N/A * for all disk slice components that are in the namespace records for
2N/A * the host being added or deleted.
2N/A *
2N/A * The DB_NEWSIDE/DB_DELSIDE message does not change any mddb records
2N/A * and only needs to be executed on the master node since the slave
2N/A * nodes will be brought up to date by the PARSE message that is
2N/A * generated as a result of a change to the mddb.
2N/A * The MD_ADDSIDE/MD_DELSIDE message does modify the records in the mddb
2N/A * and needs to be run on all nodes. The message must block class1
2N/A * messages so that record changing commands don't interfere.
2N/A *
2N/A * Master Slave1 Slave2
2N/A * Add host
2N/A * DB_NEWSIDE msg to master
2N/A * DB_NEWSIDE
2N/A * PARSE PARSE PARSE
2N/A * DB_NEWSIDE msg finished
2N/A * MD_NEWSIDE msg to master
2N/A * MD_NEWSIDE MD_NEWSIDE MD_NEWSIDE
2N/A * MD_NEWSIDE msg finished
2N/A *
2N/A *
2N/A * Optimized resync record failure:
2N/A * When any node sees a failure to write an optimized resync record
2N/A * that node notifies the master node of the replica that failed.
2N/A * The master node handles the error and updates the rest of the
2N/A * nodes using a PARSE message. The PARSE message also calls
2N/A * fixoptrecord on each slave node causing each node to fix up
2N/A * the optimized resync records that are owned by that node (the mirror
2N/A * owner code also sets the optimized resync record owner). The master
2N/A * node will fix up all optimized resync records that have no owner or
2N/A * are owned by the master node.
2N/A *
2N/A * Master Slave1 Slave2
2N/A * Optimized Record Failure
2N/A * OPTRECERR msg to master
2N/A * Master handles opt rec failure
2N/A * PARSE PARSE PARSE
2N/A * OPTRECERR msg finished
2N/A * Slave rewrites optimized record
2N/A *
2N/A */
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_MDDB_PARSE which send parse messages to the
2N/A * slave nodes in order to keep the incore view of the mddbs the
2N/A * same on all nodes.
2N/A *
2N/A * Since master node generated the mddb parse message, do nothing
2N/A * if this is the master node.
2N/A *
2N/A * If this is a slave node, send the parse message down to the kernel
2N/A * where this node will re-read in parts of the mddbs.
2N/A *
2N/A */
2N/Avoid
2N/Amdmn_do_mddb_parse(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_mddb_parse_t *d;
2N/A mddb_parse_parm_t mpp;
2N/A int ret = 0;
2N/A int i;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_mddb_parse_t *)((void *)(msg->msg_event_data));
2N/A
2N/A if (flags & MD_MSGF_ON_MASTER)
2N/A return;
2N/A
2N/A (void) memset(&mpp, 0, sizeof (mpp));
2N/A mpp.c_setno = msg->msg_setno;
2N/A mpp.c_parse_flags = d->msg_parse_flags;
2N/A for (i = 0; i < MDDB_NLB; i++) {
2N/A mpp.c_lb_flags[i] = d->msg_lb_flags[i];
2N/A }
2N/A ret = metaioctl(MD_MN_MDDB_PARSE, &mpp, &mpp.c_mde, NULL);
2N/A if (ret)
2N/A (void) mdstealerror(&(resp->mmr_ep), &mpp.c_mde);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_MDDB_BLOCK which blocks the generation
2N/A * of parse messages from this node.
2N/A *
2N/A * This is needed when attaching/detaching mddbs on the master and the
2N/A * slave node is unable to handle a parse message until the slave node
2N/A * has done the attach/detach of the mddbs. So, master node will block
2N/A * the parse messages, execute the attach/detach on all nodes and
2N/A * then unblock the parse messages which causes the parse message to
2N/A * be sent to all nodes.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_mddb_block(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_mddb_block_t *d;
2N/A mddb_block_parm_t mbp;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_mddb_block_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&mbp, 0, sizeof (mbp));
2N/A mbp.c_setno = msg->msg_setno;
2N/A mbp.c_blk_flags = d->msg_block_flags;
2N/A ret = metaioctl(MD_MN_MDDB_BLOCK, &mbp, &mbp.c_mde, NULL);
2N/A if (ret)
2N/A (void) mdstealerror(&(resp->mmr_ep), &mbp.c_mde);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Submessage generator for MD_MN_MSG_META_DB_ATTACH which generates
2N/A * a BLOCK message on the master node only, a MD_MN_MSG_SM_MDDB_ATTACH
2N/A * message on all nodes and then an UNBLOCK message on the master only.
2N/A */
2N/Aint
2N/Amdmn_smgen_mddb_attach(md_mn_msg_t *msg, md_mn_msg_t *msglist[])
2N/A{
2N/A md_mn_msg_t *nmsg;
2N/A md_mn_msg_meta_db_attach_t *d;
2N/A md_mn_msg_meta_db_attach_t *attach_d;
2N/A md_mn_msg_mddb_block_t *block_d;
2N/A
2N/A d = (md_mn_msg_meta_db_attach_t *)(void *)msg->msg_event_data;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = (MD_MSGF_NO_LOG | MD_MSGF_NO_BCAST);
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_MDDB_BLOCK;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_mddb_block_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_mddb_block_t));
2N/A block_d = (md_mn_msg_mddb_block_t *)(void *)nmsg->msg_event_data;
2N/A block_d->msg_block_flags = MDDB_BLOCK_PARSE;
2N/A msglist[0] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A /* Don't log submessages and panic on inconsistent results */
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG |
2N/A MD_MSGF_PANIC_WHEN_INCONSISTENT;
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_SM_MDDB_ATTACH;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_meta_db_attach_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_meta_db_attach_t));
2N/A attach_d = (md_mn_msg_meta_db_attach_t *)
2N/A (void *)nmsg->msg_event_data;
2N/A attach_d->msg_l_dev = d->msg_l_dev;
2N/A attach_d->msg_cnt = d->msg_cnt;
2N/A attach_d->msg_dbsize = d->msg_dbsize;
2N/A (void) strncpy(attach_d->msg_dname, d->msg_dname, 16);
2N/A attach_d->msg_splitname = d->msg_splitname;
2N/A attach_d->msg_options = d->msg_options;
2N/A msglist[1] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = (MD_MSGF_NO_LOG | MD_MSGF_NO_BCAST);
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_MDDB_BLOCK;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_mddb_block_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_mddb_block_t));
2N/A block_d = (md_mn_msg_mddb_block_t *)(void *)nmsg->msg_event_data;
2N/A block_d->msg_block_flags = MDDB_UNBLOCK_PARSE;
2N/A msglist[2] = nmsg;
2N/A
2N/A return (3); /* Return the number of submessages generated */
2N/A}
2N/A
2N/A/*
2N/A * Submessage generator for MD_MN_MSG_META_DB_DETACH which generates
2N/A * a BLOCK message on the master node only, a MD_MN_MSG_SM_MDDB_DETACH
2N/A * message on all nodes and then an UNBLOCK message on the master only.
2N/A */
2N/Aint
2N/Amdmn_smgen_mddb_detach(md_mn_msg_t *msg, md_mn_msg_t *msglist[])
2N/A{
2N/A md_mn_msg_t *nmsg;
2N/A md_mn_msg_meta_db_detach_t *d;
2N/A md_mn_msg_meta_db_detach_t *detach_d;
2N/A md_mn_msg_mddb_block_t *block_d;
2N/A
2N/A d = (md_mn_msg_meta_db_detach_t *)(void *)msg->msg_event_data;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = (MD_MSGF_NO_LOG | MD_MSGF_NO_BCAST);
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_MDDB_BLOCK;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_mddb_block_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_mddb_block_t));
2N/A block_d = (md_mn_msg_mddb_block_t *)(void *)nmsg->msg_event_data;
2N/A block_d->msg_block_flags = MDDB_BLOCK_PARSE;
2N/A msglist[0] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A /* Don't log submessages and panic on inconsistent results */
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG |
2N/A MD_MSGF_PANIC_WHEN_INCONSISTENT;
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_SM_MDDB_DETACH;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_meta_db_detach_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_meta_db_detach_t));
2N/A detach_d = (md_mn_msg_meta_db_detach_t *)
2N/A (void *)nmsg->msg_event_data;
2N/A detach_d->msg_splitname = d->msg_splitname;
2N/A msglist[1] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = (MD_MSGF_NO_LOG | MD_MSGF_NO_BCAST);
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_MDDB_BLOCK;
2N/A nmsg->msg_event_size = sizeof (md_mn_msg_mddb_block_t);
2N/A nmsg->msg_event_data = Zalloc(sizeof (md_mn_msg_mddb_block_t));
2N/A block_d = (md_mn_msg_mddb_block_t *)(void *)nmsg->msg_event_data;
2N/A block_d->msg_block_flags = MDDB_UNBLOCK_PARSE;
2N/A msglist[2] = nmsg;
2N/A
2N/A return (3); /* Return the number of submessages generated */
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_SM_MDDB_ATTACH which is used to attach mddbs.
2N/A *
2N/A * Used when running:
2N/A * metadb -s set_name -a
2N/A * metaset -s set_name -a/-d disk
2N/A * metaset -s set_name -b
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_sm_mddb_attach(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_meta_db_attach_t *d;
2N/A struct mddb_config c;
2N/A int i;
2N/A int ret = 0;
2N/A md_error_t ep = mdnullerror;
2N/A char *name, *add_name;
2N/A mdname_t *np;
2N/A mdsetname_t *sp;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_meta_db_attach_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&c, 0, sizeof (c));
2N/A c.c_setno = msg->msg_setno;
2N/A c.c_locator.l_dev = meta_cmpldev(d->msg_l_dev);
2N/A (void) strncpy(c.c_locator.l_driver, d->msg_dname,
2N/A sizeof (c.c_locator.l_driver));
2N/A c.c_devname = d->msg_splitname;
2N/A c.c_locator.l_mnum = meta_getminor(d->msg_l_dev);
2N/A c.c_multi_node = 1;
2N/A if ((sp = metasetnosetname(c.c_setno, &ep)) == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A (void) strcpy(c.c_setname, sp->setname);
2N/A c.c_sideno = getmyside(sp, &ep);
2N/A if (c.c_sideno == MD_SIDEWILD) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A name = splicename(&d->msg_splitname);
2N/A np = metaname(&sp, name, LOGICAL_DEVICE, &ep);
2N/A Free(name);
2N/A if (np == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A /*
2N/A * All nodes in MN diskset must do meta_check_replica
2N/A * since this causes the shared namespace to be
2N/A * populated by the md driver names while checking
2N/A * to see if this device is already in use as a
2N/A * metadevice.
2N/A */
2N/A if (meta_check_replica(sp, np, d->msg_options, 0,
2N/A (d->msg_cnt * d->msg_dbsize), &ep)) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A for (i = 0; i < d->msg_cnt; i++) {
2N/A c.c_locator.l_blkno = i * d->msg_dbsize + 16;
2N/A if (setup_med_cfg(sp, &c,
2N/A (d->msg_options & MDCHK_SET_FORCE), &ep)) {
2N/A ret = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A break;
2N/A }
2N/A ret = metaioctl(MD_DB_NEWDEV, &c, &c.c_mde, NULL);
2N/A /* If newdev was successful, continue with attach */
2N/A if (ret == 0) {
2N/A if (meta_db_addsidenms(sp, np, c.c_locator.l_blkno,
2N/A DB_ADDSIDENMS_NO_BCAST, &ep)) {
2N/A ret = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A break;
2N/A }
2N/A } else {
2N/A (void) mdstealerror(&(resp->mmr_ep), &c.c_mde);
2N/A break;
2N/A }
2N/A }
2N/A add_name = splicename(&d->msg_splitname);
2N/A if ((np = metaname(&sp, add_name, LOGICAL_DEVICE, &ep)) != NULL) {
2N/A meta_invalidate_name(np);
2N/A } else {
2N/A ret = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A }
2N/A Free(add_name);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_SM_MDDB_DETACH which is used to detach mddbs.
2N/A *
2N/A * Used when running:
2N/A * metadb -s set_name -d
2N/A * metaset -s set_name -a/-d disk
2N/A * metaset -s set_name -b
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_sm_mddb_detach(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_meta_db_detach_t *d;
2N/A struct mddb_config c;
2N/A int i;
2N/A int ret = 0;
2N/A md_error_t ep = mdnullerror;
2N/A char *name, *del_name;
2N/A mdname_t *np;
2N/A mdsetname_t *sp;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_meta_db_detach_t *)((void *)(msg->msg_event_data));
2N/A
2N/A if ((sp = metasetnosetname(msg->msg_setno, &ep)) == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A (void) memset(&c, 0, sizeof (c));
2N/A c.c_setno = msg->msg_setno;
2N/A if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) {
2N/A resp->mmr_exitval = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &c.c_mde);
2N/A return;
2N/A }
2N/A i = 0;
2N/A del_name = splicename(&d->msg_splitname);
2N/A while (i < c.c_dbcnt) {
2N/A c.c_id = i;
2N/A if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) {
2N/A ret = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &c.c_mde);
2N/A break;
2N/A }
2N/A name = splicename(&c.c_devname);
2N/A if (strcmp(name, del_name) != 0) {
2N/A Free(name);
2N/A i++;
2N/A continue;
2N/A }
2N/A Free(name);
2N/A /* Found a match - delete mddb */
2N/A if (metaioctl(MD_DB_DELDEV, &c, &c.c_mde, NULL) != 0) {
2N/A ret = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &c.c_mde);
2N/A break;
2N/A }
2N/A /* Not incrementing "i" intentionally (dbcnt is changed) */
2N/A }
2N/A if ((np = metaname(&sp, del_name, LOGICAL_DEVICE, &ep)) != NULL) {
2N/A meta_invalidate_name(np);
2N/A } else {
2N/A ret = -1;
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A }
2N/A Free(del_name);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_META_DB_NEWSIDE which is used to update the
2N/A * side information for each diskset mddb when a new host has been
2N/A * added to the diskset. The side information is the /dev/dsk/ctds name
2N/A * that the new node would use to access each mddb.
2N/A *
2N/A * Since this routine makes no changes to the records in the diskset mddb,
2N/A * this routine only needs to be run on the master node. The master node's
2N/A * kernel code will detect that portions of the mddb have changed and
2N/A * will send a parse message to all nodes to re-parse parts of the mddb.
2N/A *
2N/A * Used when running:
2N/A * metaset -s set_name -a -h new_hostname
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_meta_db_newside(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_meta_db_newside_t *d;
2N/A struct mddb_config c;
2N/A int ret = 0;
2N/A mdsetname_t *sp;
2N/A md_error_t ep = mdnullerror;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_meta_db_newside_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&c, 0, sizeof (c));
2N/A c.c_setno = msg->msg_setno;
2N/A c.c_locator.l_dev = meta_cmpldev(d->msg_l_dev);
2N/A c.c_locator.l_blkno = d->msg_blkno;
2N/A (void) strncpy(c.c_locator.l_driver, d->msg_dname,
2N/A sizeof (c.c_locator.l_driver));
2N/A c.c_devname = d->msg_splitname;
2N/A c.c_locator.l_mnum = d->msg_mnum;
2N/A c.c_multi_node = 1;
2N/A if ((sp = metasetnosetname(c.c_setno, &ep)) == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A (void) strcpy(c.c_setname, sp->setname);
2N/A c.c_sideno = d->msg_sideno;
2N/A
2N/A if ((ret = metaioctl(MD_DB_NEWSIDE, &c, &c.c_mde, NULL)) != 0) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &c.c_mde);
2N/A }
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_META_DB_DELSIDE which is used to remove the
2N/A * side information for each diskset mddb when a host has been
2N/A * deleted from the diskset. The side information is the /dev/dsk/ctds name
2N/A * that the node would use to access each mddb.
2N/A *
2N/A * Since this routine makes no changes to the records in the diskset mddb,
2N/A * this routine only needs to be run on the master node. The master node's
2N/A * kernel code will detect that portions of the mddb have changed and
2N/A * will send a parse message to all nodes to re-parse parts of the mddb.
2N/A *
2N/A * Used when running:
2N/A * metaset -s set_name -d -h hostname
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_meta_db_delside(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_meta_db_delside_t *d;
2N/A mddb_config_t c;
2N/A int ret = 0;
2N/A mdsetname_t *sp;
2N/A md_error_t ep = mdnullerror;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_meta_db_delside_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&c, 0, sizeof (c));
2N/A c.c_setno = msg->msg_setno;
2N/A c.c_locator.l_dev = meta_cmpldev(d->msg_l_dev);
2N/A c.c_locator.l_blkno = d->msg_blkno;
2N/A c.c_multi_node = 1;
2N/A if ((sp = metasetnosetname(c.c_setno, &ep)) == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A (void) strcpy(c.c_setname, sp->setname);
2N/A c.c_sideno = d->msg_sideno;
2N/A
2N/A if ((ret = metaioctl(MD_DB_DELSIDE, &c, &c.c_mde, NULL)) != 0) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &c.c_mde);
2N/A }
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_META_MD_ADDSIDE which is used to add the
2N/A * side information for each diskset metadevice component (if that
2N/A * component is a disk) when a host has been added to the diskset.
2N/A * The side information is the /dev/dsk/ctds name that the node would
2N/A * use to access the metadevice component.
2N/A *
2N/A * This routine makes changes to the mddb records and must be run
2N/A * on all nodes.
2N/A *
2N/A * Used when running:
2N/A * metaset -s set_name -a -h new_hostname
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_meta_md_addside(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_meta_md_addside_t *d;
2N/A mdnm_params_t nm;
2N/A mdsetname_t *sp;
2N/A char *cname, *dname;
2N/A minor_t mnum;
2N/A int done, i;
2N/A md_error_t ep = mdnullerror;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_meta_md_addside_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&nm, 0, sizeof (nm));
2N/A if ((sp = metasetnosetname(msg->msg_setno, &ep)) == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A /* While loop continues until IOCNXTKEY_NM gives nm.key of KEYWILD */
2N/A /*CONSTCOND*/
2N/A while (1) {
2N/A char *drvnm = NULL;
2N/A
2N/A nm.mde = mdnullerror;
2N/A nm.setno = msg->msg_setno;
2N/A nm.side = d->msg_otherside;
2N/A if (metaioctl(MD_IOCNXTKEY_NM, &nm, &nm.mde, NULL) != 0) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &nm.mde);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A /* Normal exit path is to eventually get a KEYWILD */
2N/A if (nm.key == MD_KEYWILD) {
2N/A resp->mmr_exitval = 0;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Okay we have a valid key
2N/A * Let's see if it is hsp or not
2N/A */
2N/A nm.devname = (uintptr_t)meta_getnmentbykey(msg->msg_setno,
2N/A d->msg_otherside, nm.key, &drvnm, NULL, NULL, &ep);
2N/A if (nm.devname == NULL || drvnm == NULL) {
2N/A if (nm.devname)
2N/A Free((void *)(uintptr_t)nm.devname);
2N/A if (drvnm)
2N/A Free((void *)(uintptr_t)drvnm);
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * If it is hsp add here
2N/A */
2N/A if (strcmp(drvnm, MD_HOTSPARES) == 0) {
2N/A if (add_name(sp, d->msg_sideno, nm.key, MD_HOTSPARES,
2N/A minor(NODEV), (char *)(uintptr_t)nm.devname,
2N/A NULL, NULL, &ep) == -1) {
2N/A Free((void *)(uintptr_t)nm.devname);
2N/A Free((void *)(uintptr_t)drvnm);
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A } else {
2N/A Free((void *)(uintptr_t)nm.devname);
2N/A Free((void *)(uintptr_t)drvnm);
2N/A continue;
2N/A }
2N/A }
2N/A
2N/A nm.side = d->msg_sideno;
2N/A if ((done = meta_getside_devinfo(sp,
2N/A (char *)(uintptr_t)nm.devname,
2N/A d->msg_sideno, &cname, &dname, &mnum, &ep)) == -1) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A Free((void *)(uintptr_t)nm.devname);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A Free((void *)(uintptr_t)nm.devname);
2N/A Free((void *)(uintptr_t)drvnm);
2N/A
2N/A if (done != 1) {
2N/A Free(cname);
2N/A Free(dname);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * The device reference count can be greater than 1 if
2N/A * more than one softpart is configured on top of the
2N/A * same device. If this is the case then we want to
2N/A * increment the count to sync up with the other sides.
2N/A */
2N/A for (i = 0; i < nm.ref_count; i++) {
2N/A if (add_name(sp, d->msg_sideno, nm.key, dname, mnum,
2N/A cname, NULL, NULL, &ep) == -1) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A Free(cname);
2N/A Free(dname);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A }
2N/A Free(cname);
2N/A Free(dname);
2N/A }
2N/A
2N/A /*NOTREACHED*/
2N/A}
2N/A/*
2N/A * Handler for MD_MN_MSG_META_MD_DELSIDE which is used to delete the
2N/A * side information for each diskset metadevice component (if that
2N/A * component is a disk) when a host has been removed from the diskset.
2N/A * The side information is the /dev/dsk/ctds name that the node would
2N/A * use to access the metadevice component.
2N/A *
2N/A * This routine makes changes to the mddb records and must be run
2N/A * on all nodes.
2N/A *
2N/A * Used when running:
2N/A * metaset -s set_name -d -h hostname
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_meta_md_delside(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_meta_md_delside_t *d;
2N/A mdnm_params_t nm;
2N/A mdsetname_t *sp;
2N/A md_error_t ep = mdnullerror;
2N/A int i;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_meta_md_delside_t *)((void *)(msg->msg_event_data));
2N/A
2N/A if ((sp = metasetnosetname(msg->msg_setno, &ep)) == NULL) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A (void) memset(&nm, 0, sizeof (nm));
2N/A nm.key = MD_KEYWILD;
2N/A /*CONSTCOND*/
2N/A while (1) {
2N/A nm.mde = mdnullerror;
2N/A nm.setno = msg->msg_setno;
2N/A nm.side = MD_SIDEWILD;
2N/A if (metaioctl(MD_IOCNXTKEY_NM, &nm, &nm.mde, NULL) != 0) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &nm.mde);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A /* Normal exit path is to eventually get a KEYWILD */
2N/A if (nm.key == MD_KEYWILD) {
2N/A resp->mmr_exitval = 0;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * The device reference count can be greater than 1 if
2N/A * more than one softpart is configured on top of the
2N/A * same device. If this is the case then we want to
2N/A * decrement the count to zero so the entry can be
2N/A * actually removed.
2N/A */
2N/A for (i = 0; i < nm.ref_count; i++) {
2N/A if (del_name(sp, d->msg_sideno, nm.key, &ep) == -1) {
2N/A (void) mdstealerror(&(resp->mmr_ep), &ep);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*NOTREACHED*/
2N/A}
2N/A
2N/A/*
2N/A * Handler for MD_MN_MSG_MDDB_OPTRECERR which is used to notify
2N/A * the master node that a node has seen an error when attempting to
2N/A * write to the optimized resync records that reside on 2 of the diskset
2N/A * mddbs. Master node will mark the failed replica in error and this
2N/A * will send a parse message to all nodes to re-read parts of the mddb
2N/A * and to fix their optimized resync records based on this information.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_mddb_optrecerr(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_mddb_optrecerr_t *d;
2N/A mddb_optrec_parm_t mop;
2N/A int ret;
2N/A int i;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_mddb_optrecerr_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&mop, 0, sizeof (mop));
2N/A mop.c_setno = msg->msg_setno;
2N/A for (i = 0; i < 2; i++) {
2N/A mop.c_recerr[i] = d->msg_recerr[i];
2N/A }
2N/A ret = metaioctl(MD_MN_MDDB_OPTRECFIX, &mop, &mop.c_mde, NULL);
2N/A if (ret)
2N/A (void) mdstealerror(&(resp->mmr_ep), &mop.c_mde);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/Aint
2N/Amdmn_smgen_test6(md_mn_msg_t *msg, md_mn_msg_t **msglist)
2N/A{
2N/A md_mn_msg_t *nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG; /* Don't log submessages */
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_TEST2;
2N/A nmsg->msg_event_size = sizeof ("test2");
2N/A nmsg->msg_event_data = Strdup("test2");
2N/A msglist[0] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG; /* Don't log submessages */
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_TEST2;
2N/A nmsg->msg_event_size = sizeof ("test2");
2N/A nmsg->msg_event_data = Strdup("test2");
2N/A msglist[1] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG; /* Don't log submessages */
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_TEST3;
2N/A nmsg->msg_event_size = sizeof ("test3");
2N/A nmsg->msg_event_data = Strdup("test3");
2N/A msglist[2] = nmsg;
2N/A
2N/A nmsg = Zalloc(sizeof (md_mn_msg_t));
2N/A MSGID_COPY(&(msg->msg_msgid), &(nmsg->msg_msgid));
2N/A
2N/A nmsg->msg_flags = MD_MSGF_NO_LOG; /* Don't log submessages */
2N/A nmsg->msg_setno = msg->msg_setno;
2N/A nmsg->msg_type = MD_MN_MSG_TEST4;
2N/A nmsg->msg_event_size = sizeof ("test4");
2N/A nmsg->msg_event_data = Strdup("test4");
2N/A msglist[3] = nmsg;
2N/A
2N/A return (4); /* Return the number of submessages generated */
2N/A}
2N/A
2N/A/*
2N/A * This is to send an MD_IOCSET ioctl to all nodes to create a soft
2N/A * partition.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_iocset(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_iocset_t *d;
2N/A int ret;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A mdname_t *np;
2N/A md_error_t mde = mdnullerror;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_iocset_t *)(void *)msg->msg_event_data;
2N/A
2N/A setno = MD_MIN2SET(d->iocset_params.mnum);
2N/A if ((sp = metasetnosetname(setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_IOCSET: Invalid setno %d\n"), setno);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Device should be in the namespace already
2N/A */
2N/A if ((np = metamnumname(&sp, d->iocset_params.mnum, 1, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_IOCSET: Invalid mnum %d\n"),
2N/A d->iocset_params.mnum);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Create unit structure
2N/A */
2N/A d->iocset_params.mdp = (uintptr_t)&d->unit; /* set pointer to unit */
2N/A ret = metaioctl(MD_IOCSET, &(d->iocset_params), &mde, np->cname);
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * This is to update the status of a softpart
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_sp_setstat(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_sp_setstat_t *d;
2N/A int ret;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A minor_t mnum;
2N/A md_error_t mde = mdnullerror;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_sp_setstat_t *)(void *)msg->msg_event_data;
2N/A
2N/A mnum = d->sp_setstat_mnum;
2N/A setno = MD_MIN2SET(mnum);
2N/A if ((sp = metasetnosetname(setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_IOCSET: Invalid setno %d\n"), setno);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A ret = meta_sp_setstatus(sp, &mnum, 1, d->sp_setstat_status, &mde);
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * This is to add a key to the namespace
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_addkeyname(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_addkeyname_t *d;
2N/A int ret;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A md_error_t mde = mdnullerror;
2N/A mdname_t *compnp;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_addkeyname_t *)(void *)msg->msg_event_data;
2N/A
2N/A setno = d->addkeyname_setno;
2N/A if ((sp = metasetnosetname(setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_ADDKEYNAME: Invalid setno %d\n"), setno);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A compnp = metaname(&sp, d->addkeyname_name, UNKNOWN, &mde);
2N/A if (compnp != NULL) {
2N/A ret = add_key_name(sp, compnp, NULL, &mde);
2N/A if (ret < 0)
2N/A resp->mmr_exitval = -1;
2N/A else
2N/A resp->mmr_exitval = compnp->key;
2N/A } else {
2N/A resp->mmr_exitval = -1;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This is to delete a key from the namespace
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_delkeyname(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_delkeyname_t *d;
2N/A int ret;
2N/A set_t setno;
2N/A mdsetname_t *sp;
2N/A md_error_t mde = mdnullerror;
2N/A mdname_t *compnp;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_delkeyname_t *)(void *)msg->msg_event_data;
2N/A
2N/A setno = d->delkeyname_setno;
2N/A if ((sp = metasetnosetname(setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_DELKEYNAME: Invalid setno %d\n"), setno);
2N/A resp->mmr_exitval = -1;
2N/A return;
2N/A }
2N/A
2N/A compnp = metadevname(&sp, d->delkeyname_dev, &mde);
2N/A if (compnp != NULL) {
2N/A /*
2N/A * Reset the key value for the name. This is required because
2N/A * any previous call of del_key_name for the same component
2N/A * will have resulted in the key value being reset to MD_KEYBAD
2N/A * even though there may still be references to this component.
2N/A */
2N/A compnp->key = d->delkeyname_key;
2N/A ret = del_key_name(sp, compnp, &mde);
2N/A resp->mmr_exitval = ret;
2N/A } else {
2N/A resp->mmr_exitval = -1;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This is to get the value of tstate from the master node. We use this
2N/A * to get the ABR state of a metadevice from the master.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_get_tstate(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_gettstate_t *d;
2N/A int ret;
2N/A uint_t tstate;
2N/A md_error_t mde = mdnullerror;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_gettstate_t *)(void *)msg->msg_event_data;
2N/A
2N/A ret = meta_get_tstate(d->gettstate_dev, &tstate, &mde);
2N/A if (ret != 0) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_GET_TSTATE: Invalid dev %llx\n"), d->gettstate_dev);
2N/A tstate = 0;
2N/A }
2N/A resp->mmr_exitval = tstate;
2N/A}
2N/A
2N/A/*
2N/A * This is to get the mirror ABR state and the state of its submirrors from
2N/A * the master node. We need this to ensure consistent output from metastat
2N/A * when a new node joins the cluster during a resync. Without this the
2N/A * submirror status will be incorrect until the whole resync is complete which
2N/A * may take days for very large metadevices.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_get_mirstate(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_mir_state_t *d;
2N/A md_mn_msg_mir_state_res_t *res; /* Results */
2N/A set_t setno;
2N/A mdsetname_t *sp; /* Set name */
2N/A mdname_t *mirnp; /* Mirror name */
2N/A md_error_t mde = mdnullerror;
2N/A mm_unit_t *mm; /* Mirror */
2N/A int smi;
2N/A uint_t tstate;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A resp->mmr_out_size = sizeof (md_mn_msg_mir_state_res_t);
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = Malloc(resp->mmr_out_size);
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_mir_state_t *)(void *)msg->msg_event_data;
2N/A res = (md_mn_msg_mir_state_res_t *)(void *)resp->mmr_out;
2N/A
2N/A /* Validate set information from minor number */
2N/A setno = MD_MIN2SET(d->mir_state_mnum);
2N/A sp = metasetnosetname(setno, &mde);
2N/A if (sp == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_GET_MIRROR_STATE: Invalid set %d\n"), setno);
2N/A resp->mmr_exitval = 1; /* Failure */
2N/A Free(resp->mmr_out);
2N/A resp->mmr_out_size = 0;
2N/A return;
2N/A }
2N/A
2N/A /* Construct mirror name from minor number */
2N/A mirnp = metamnumname(&sp, d->mir_state_mnum, 0, &mde);
2N/A if (mirnp == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_GET_MIRROR_STATE: Invalid minor %lx\n"),
2N/A d->mir_state_mnum);
2N/A resp->mmr_exitval = 2; /* Failure */
2N/A Free(resp->mmr_out);
2N/A resp->mmr_out_size = 0;
2N/A return;
2N/A }
2N/A
2N/A /* Get common mirror structure */
2N/A mm = (mm_unit_t *)meta_get_mdunit(sp, mirnp, &mde);
2N/A if (mm == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_GET_MIRROR_STATE: Invalid mirror minor %x\n"),
2N/A d->mir_state_mnum);
2N/A resp->mmr_exitval = 3; /* Failure */
2N/A Free(resp->mmr_out);
2N/A resp->mmr_out_size = 0;
2N/A return;
2N/A }
2N/A
2N/A if (meta_get_tstate(d->mir_state_mnum, &tstate, &mde) != 0) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_GET_MIRROR_STATE: Invalid minor %lx\n"),
2N/A d->mir_state_mnum);
2N/A resp->mmr_exitval = 4; /* Failure */
2N/A Free(resp->mmr_out);
2N/A resp->mmr_out_size = 0;
2N/A return;
2N/A }
2N/A /*
2N/A * Fill in the sm_state/sm_flags value in the results structure which
2N/A * gets passed back to the message originator
2N/A */
2N/A resp->mmr_exitval = 0;
2N/A for (smi = 0; (smi < NMIRROR); smi++) {
2N/A mm_submirror_t *mmsp = &mm->un_sm[smi];
2N/A res->sm_state[smi] = mmsp->sm_state;
2N/A res->sm_flags[smi] = mmsp->sm_flags;
2N/A }
2N/A /* Returm value of tstate for mirror */
2N/A res->mir_tstate = tstate;
2N/A}
2N/A
2N/A/*
2N/A * This is to issue an ioctl to call poke_hotspares
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_poke_hotspares(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A
2N/A md_mn_poke_hotspares_t pokehsp;
2N/A md_mn_msg_pokehsp_t *d;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_pokehsp_t *)(void *)msg->msg_event_data;
2N/A
2N/A (void) memset(&pokehsp, 0, sizeof (pokehsp));
2N/A MD_SETDRIVERNAME(&pokehsp, MD_MIRROR, d->pokehsp_setno);
2N/A
2N/A resp->mmr_exitval = metaioctl(MD_MN_POKE_HOTSPARES, &pokehsp,
2N/A &pokehsp.mde, NULL);
2N/A}
2N/A
2N/A/*
2N/A * Called to create a softpart during a metarecover operation
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_addmdname(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_addmdname_t *d;
2N/A md_error_t mde = mdnullerror;
2N/A mdsetname_t *sp;
2N/A int init = 0;
2N/A mdkey_t key;
2N/A minor_t mnum;
2N/A
2N/A resp->mmr_comm_state = MDMNE_ACK; /* Ok state */;
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A d = (md_mn_msg_addmdname_t *)(void *)msg->msg_event_data;
2N/A
2N/A if ((sp = metasetnosetname(d->addmdname_setno, &mde)) == NULL) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_ADDMDNAME: Invalid setno %d\n"),
2N/A d->addmdname_setno);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * If device node does not exist then init it
2N/A */
2N/A if (!is_existing_meta_hsp(sp, d->addmdname_name)) {
2N/A if ((key = meta_init_make_device(&sp, d->addmdname_name,
2N/A &mde)) <= 0) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
2N/A "MD_MN_MSG_ADDMDNAME: Invalid name %s\n"),
2N/A d->addmdname_name);
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A init = 1;
2N/A }
2N/A
2N/A /*
2N/A * We should have it
2N/A */
2N/A if (metaname(&sp, d->addmdname_name, META_DEVICE, &mde) == NULL) {
2N/A
2N/A if (init) {
2N/A if (meta_getnmentbykey(sp->setno, MD_SIDEWILD,
2N/A key, NULL, &mnum, NULL, &mde) != NULL) {
2N/A (void) metaioctl(
2N/A MD_IOCREM_DEV, &mnum, &mde, NULL);
2N/A }
2N/A (void) del_self_name(sp, key, &mde);
2N/A }
2N/A
2N/A resp->mmr_exitval = 1;
2N/A return;
2N/A }
2N/A
2N/A resp->mmr_exitval = 0;
2N/A}
2N/A
2N/A/*
2N/A * This is used to issue a MD_MN_RR_DIRTY ioctl to the mirror.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_mark_dirty(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_rr_dirty_t *d;
2N/A md_mn_rr_dirty_params_t rp;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_rr_dirty_t *)((void *)(msg->msg_event_data));
2N/A
2N/A (void) memset(&rp, 0, sizeof (rp));
2N/A MD_SETDRIVERNAME(&rp, MD_MIRROR, MD_MIN2SET(d->rr_mnum))
2N/A rp.rr_mnum = d->rr_mnum;
2N/A rp.rr_nodeid = d->rr_nodeid;
2N/A rp.rr_start = (ushort_t)((d->rr_range >> 16) & 0xffff);
2N/A rp.rr_end = (ushort_t)(d->rr_range & 0xffff);
2N/A
2N/A ret = metaioctl(MD_MN_RR_DIRTY, &rp, &rp.mde, NULL);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}
2N/A
2N/A/*
2N/A * This is used to issue a MD_MN_RR_CLEAN ioctl to the mirror.
2N/A */
2N/A/*ARGSUSED*/
2N/Avoid
2N/Amdmn_do_mark_clean(md_mn_msg_t *msg, uint_t flags, md_mn_result_t *resp)
2N/A{
2N/A md_mn_msg_rr_clean_t *d;
2N/A md_mn_rr_clean_params_t *rcp;
2N/A int ret;
2N/A
2N/A resp->mmr_out_size = 0;
2N/A resp->mmr_err_size = 0;
2N/A resp->mmr_out = NULL;
2N/A resp->mmr_err = NULL;
2N/A resp->mmr_comm_state = MDMNE_ACK;
2N/A d = (md_mn_msg_rr_clean_t *)((void *)(msg->msg_event_data));
2N/A
2N/A rcp = Zalloc(sizeof (struct md_mn_rr_clean_params) +
2N/A MDMN_MSG_RR_CLEAN_DATA_BYTES(d));
2N/A MD_SETDRIVERNAME(rcp, MD_MIRROR, MD_MIN2SET(d->rr_mnum))
2N/A rcp->rr_mnum = d->rr_mnum;
2N/A rcp->rr_nodeid = d->rr_nodeid;
2N/A rcp->rr_start_size = d->rr_start_size;
2N/A (void) memcpy(MDMN_RR_CLEAN_PARAMS_DATA(rcp), MDMN_MSG_RR_CLEAN_DATA(d),
2N/A MDMN_MSG_RR_CLEAN_DATA_BYTES(d));
2N/A
2N/A ret = metaioctl(MD_MN_RR_CLEAN, rcp, &rcp->mde, NULL);
2N/A
2N/A Free(rcp);
2N/A
2N/A resp->mmr_exitval = ret;
2N/A}