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 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/*
2N/A * Just in case we're not in a build environment, make sure that
2N/A * TEXT_DOMAIN gets set to something.
2N/A */
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*
2N/A * Mediator functions
2N/A */
2N/A
2N/A#include <meta.h>
2N/A#include <metamed.h>
2N/A#include <dlfcn.h>
2N/A#include <sdssc.h>
2N/A
2N/A/*
2N/A * There are too many external factors that affect the timing of the
2N/A * operations, so we set the timeout to a very large value, in this
2N/A * case 1 day, which should handle HW timeouts, large configurations,
2N/A * and other potential delays.
2N/A */
2N/A#define CL_LONG_TMO 86400L /* 1 day */
2N/A#define CL_MEDIUM_TMO 3600L /* 1 hour */
2N/A#define CL_SHORT_TMO 600L /* 10 minutes */
2N/A#define CL_DEF_TMO 10L /* 10 seconds */
2N/A
2N/Astatic md_timeval32_t def_rpcb_timeout = { MD_CLNT_CREATE_TOUT, 0 };
2N/A
2N/A/*
2N/A * RPC handle
2N/A */
2N/Atypedef struct {
2N/A char *hostname;
2N/A CLIENT *clntp;
2N/A} med_handle_t;
2N/A
2N/A/*
2N/A * Data to be sent from med_clnt_create_timed to med_create_helper via
2N/A * meta_client_create_retry.
2N/A */
2N/Atypedef struct {
2N/A rpcprog_t mcd_program; /* RPC program designation */
2N/A rpcvers_t mcd_version; /* RPC version */
2N/A char *mcd_nettype; /* Type of network to use for RPC */
2N/A} med_create_data_t;
2N/A
2N/A/*
2N/A * Perform the work of actually doing the clnt_create for
2N/A * meta_client_create_retry.
2N/A */
2N/Astatic CLIENT *
2N/Amed_create_helper(char *hostname, void *private, struct timeval *time_out)
2N/A{
2N/A med_create_data_t *cd = (med_create_data_t *)private;
2N/A
2N/A return (clnt_create_timed(hostname, cd->mcd_program, cd->mcd_version,
2N/A cd->mcd_nettype, time_out));
2N/A}
2N/A
2N/Astatic
2N/ACLIENT *med_clnt_create_timed(
2N/A char *hostname,
2N/A const ulong_t prog,
2N/A const ulong_t vers,
2N/A char *nettype,
2N/A const md_timeval32_t *tp
2N/A)
2N/A{
2N/A med_create_data_t cd; /* Create data. */
2N/A
2N/A cd.mcd_program = prog;
2N/A cd.mcd_version = vers;
2N/A cd.mcd_nettype = nettype;
2N/A return (meta_client_create_retry(hostname, med_create_helper,
2N/A (void *)&cd, (time_t)tp->tv_sec, NULL));
2N/A}
2N/A
2N/A/*
2N/A * Set the timeout value for this client handle.
2N/A */
2N/Astatic int
2N/Acl_sto_medd(
2N/A CLIENT *clntp,
2N/A char *hostname,
2N/A long time_out,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_timeval32_t nto;
2N/A
2N/A (void) memset(&nto, '\0', sizeof (nto));
2N/A
2N/A nto.tv_sec = time_out;
2N/A
2N/A if (clnt_control(clntp, CLSET_TIMEOUT, (char *)&nto) != TRUE)
2N/A return (mdrpcerror(ep, clntp, hostname,
2N/A dgettext(TEXT_DOMAIN, "metad client set timeout")));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * close RPC connection
2N/A */
2N/Astatic void
2N/Aclose_medd(
2N/A med_handle_t *hp
2N/A)
2N/A{
2N/A assert(hp != NULL);
2N/A if (hp->hostname != NULL) {
2N/A Free(hp->hostname);
2N/A }
2N/A if (hp->clntp != NULL) {
2N/A auth_destroy(hp->clntp->cl_auth);
2N/A clnt_destroy(hp->clntp);
2N/A }
2N/A Free(hp);
2N/A}
2N/A
2N/A/*
2N/A * open RPC connection to rpc.medd
2N/A */
2N/Astatic med_handle_t *
2N/Aopen_medd(
2N/A char *hostname,
2N/A long time_out,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A CLIENT *clntp;
2N/A med_handle_t *hp;
2N/A
2N/A /* default to local host */
2N/A if ((hostname == NULL) || (*hostname == '\0'))
2N/A hostname = mynode();
2N/A
2N/A /* open RPC connection */
2N/A assert(hostname != NULL);
2N/A if ((clntp = med_clnt_create_timed(hostname, MED_PROG, MED_VERS,
2N/A "tcp", &def_rpcb_timeout)) == NULL) {
2N/A if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
2N/A clnt_pcreateerror(hostname);
2N/A (void) mdrpccreateerror(ep, hostname,
2N/A "medd med_clnt_create_timed");
2N/A return (NULL);
2N/A } else {
2N/A auth_destroy(clntp->cl_auth);
2N/A clntp->cl_auth = authsys_create_default();
2N/A assert(clntp->cl_auth != NULL);
2N/A }
2N/A
2N/A if (cl_sto_medd(clntp, hostname, time_out, ep) != 0)
2N/A return (NULL);
2N/A
2N/A /* return connection */
2N/A hp = Zalloc(sizeof (*hp));
2N/A hp->hostname = Strdup(hostname);
2N/A hp->clntp = clntp;
2N/A
2N/A return (hp);
2N/A}
2N/A
2N/A/*
2N/A * steal and convert med_err_t
2N/A */
2N/Aint
2N/Ameddstealerror(
2N/A md_error_t *ep,
2N/A med_err_t *medep
2N/A)
2N/A{
2N/A char buf[BUFSIZ];
2N/A char *p = buf;
2N/A size_t psize = BUFSIZ;
2N/A char *emsg;
2N/A int rval = -1;
2N/A
2N/A /* no error */
2N/A if (medep->med_errno == 0) {
2N/A /* assert(medep->name == NULL); */
2N/A rval = 0;
2N/A goto out;
2N/A }
2N/A
2N/A /* steal error */
2N/A if ((medep->med_node != NULL) && (medep->med_node[0] != '\0')) {
2N/A (void) snprintf(p, psize, "%s: ", medep->med_node);
2N/A p = &buf[strlen(buf)];
2N/A psize = buf + BUFSIZ - p;
2N/A }
2N/A
2N/A if ((medep->med_misc != NULL) && (medep->med_misc[0] != '\0')) {
2N/A (void) snprintf(p, psize, "%s: ", medep->med_misc);
2N/A p = &buf[strlen(buf)];
2N/A psize = buf + BUFSIZ - p;
2N/A }
2N/A
2N/A if (medep->med_errno < 0) {
2N/A if ((emsg = med_errnum_to_str(medep->med_errno)) != NULL)
2N/A (void) snprintf(p, psize, "%s", emsg);
2N/A else
2N/A (void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
2N/A "unknown mediator errno %d\n"), medep->med_errno);
2N/A } else {
2N/A if ((emsg = strerror(medep->med_errno)) != NULL)
2N/A (void) snprintf(p, psize, "%s", emsg);
2N/A else
2N/A (void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
2N/A "errno %d out of range"), medep->med_errno);
2N/A }
2N/A (void) mderror(ep, MDE_MED_ERROR, buf);
2N/A
2N/A /* cleanup, return success */
2N/Aout:
2N/A if (medep->med_node != NULL)
2N/A Free(medep->med_node);
2N/A if (medep->med_misc != NULL)
2N/A Free(medep->med_misc);
2N/A (void) memset(medep, 0, sizeof (*medep));
2N/A return (rval);
2N/A}
2N/A
2N/Astatic med_handle_t *
2N/Aopen_medd_wrap(
2N/A md_h_t *mdhp,
2N/A long time_out,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp = NULL;
2N/A int i;
2N/A char *hnm;
2N/A
2N/A assert(mdhp && mdhp->a_cnt > 0);
2N/A
2N/A /* Loop through the hosts listed */
2N/A i = min(mdhp->a_cnt, MAX_HOST_ADDRS) - 1;
2N/A for (; i >= 0; i--) {
2N/A hnm = mdhp->a_nm[i];
2N/A
2N/A if ((hp = open_medd(hnm, time_out, ep)) == NULL) {
2N/A if (mdanyrpcerror(ep) && i != 0) {
2N/A mdclrerror(ep);
2N/A continue;
2N/A }
2N/A }
2N/A return (hp);
2N/A }
2N/A
2N/A rpc_createerr.cf_stat = RPC_CANTSEND;
2N/A rpc_createerr.cf_error.re_status = 0;
2N/A (void) mdrpccreateerror(ep, mdhp->a_nm[0],
2N/A dgettext(TEXT_DOMAIN, "medd open wrap"));
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic int
2N/Asetup_med_transtab(md_error_t *ep)
2N/A{
2N/A mddb_med_t_parm_t *tp = NULL;
2N/A struct stat statb;
2N/A int i;
2N/A size_t alloc_size = 0;
2N/A int err = 0;
2N/A
2N/A
2N/A if ((tp = Zalloc(sizeof (mddb_med_t_parm_t))) == NULL)
2N/A return (mdsyserror(ep, ENOMEM, "setup_med_transtab"));
2N/A
2N/A if (metaioctl(MD_MED_GET_TLEN, tp, &tp->med_tp_mde, NULL) != 0) {
2N/A err = mdstealerror(ep, &tp->med_tp_mde);
2N/A goto out;
2N/A }
2N/A
2N/A if (tp->med_tp_setup == 1)
2N/A goto out;
2N/A
2N/A alloc_size = (sizeof (mddb_med_t_parm_t) - sizeof (mddb_med_t_ent_t)) +
2N/A (sizeof (mddb_med_t_ent_t) * tp->med_tp_nents);
2N/A
2N/A if ((tp = Realloc(tp, alloc_size)) == NULL) {
2N/A err = mdsyserror(ep, ENOMEM, "setup_med_transtab");
2N/A goto out;
2N/A }
2N/A
2N/A if (metaioctl(MD_MED_GET_T, tp, &tp->med_tp_mde, NULL) != 0) {
2N/A err = mdstealerror(ep, &tp->med_tp_mde);
2N/A goto out;
2N/A }
2N/A
2N/A for (i = 0; i < tp->med_tp_nents; i++) {
2N/A if (meta_stat(tp->med_tp_ents[i].med_te_nm, &statb) == -1) {
2N/A md_perror("setup_med_transtab(): stat():");
2N/A tp->med_tp_ents[i].med_te_dev = NODEV64;
2N/A } else {
2N/A tp->med_tp_ents[i].med_te_dev =
2N/A meta_expldev(statb.st_rdev);
2N/A }
2N/A }
2N/A
2N/A if (metaioctl(MD_MED_SET_T, tp, &tp->med_tp_mde, NULL) != 0)
2N/A err = mdstealerror(ep, &tp->med_tp_mde);
2N/A
2N/Aout:
2N/A Free(tp);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Externals
2N/A */
2N/A
2N/A/*
2N/A * NULLPROC - just returns a response
2N/A */
2N/Aint
2N/Aclnt_med_null(
2N/A char *hostname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_err_t res;
2N/A
2N/A /* initialize */
2N/A mdclrerror(ep);
2N/A
2N/A /* do it */
2N/A if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_null_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hostname,
2N/A dgettext(TEXT_DOMAIN, "medd nullproc"));
2N/A
2N/A close_medd(hp);
2N/A
2N/A xdr_free(xdr_med_err_t, (char *)&res);
2N/A
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Update the mediator information on the mediator.
2N/A * This function does the same functionality as
2N/A * clnt_med_upd_data() except that it takes different
2N/A * argument so that host which is just a mediator, can
2N/A * still update its mediator record.
2N/A */
2N/Aint
2N/Aclnt_user_med_upd_data(
2N/A md_h_t *mdhp,
2N/A bool_t obandiskset,
2N/A char *setname,
2N/A uint_t setnum,
2N/A med_data_t *meddp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_upd_data_args_t args;
2N/A med_err_t res;
2N/A
2N/A /* Initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&args, 0, sizeof (args));
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* Build args */
2N/A if (obandiskset)
2N/A args.med.med_caller = Strdup(MED_MN_CALLER);
2N/A else
2N/A args.med.med_caller = Strdup(mynode());
2N/A
2N/A args.med.med_setname = Strdup(setname);
2N/A args.med.med_setno = setnum;
2N/A args.med_data = *meddp;
2N/A
2N/A if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hp->hostname,
2N/A dgettext(TEXT_DOMAIN, "medd get record"));
2N/A else
2N/A (void) meddstealerror(ep, &res);
2N/A
2N/A close_medd(hp);
2N/A
2N/A xdr_free(xdr_med_upd_data_args_t, (char *)&args);
2N/A xdr_free(xdr_med_err_t, (char *)&res);
2N/A
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Get the mediator information from the client.
2N/A * The code does same functinality as clnt_med_get_data()
2N/A * except that it takes different arguments so that
2N/A * host which doesn't have set information, can still
2N/A * get access to mediator information
2N/A */
2N/Aint
2N/Aclnt_user_med_get_data(
2N/A md_h_t *mdhp,
2N/A bool_t obandiskset,
2N/A char *setname,
2N/A uint_t setnum,
2N/A med_data_t *meddp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A int rval = -1;
2N/A med_handle_t *hp;
2N/A med_args_t args;
2N/A med_get_data_res_t res;
2N/A
2N/A /* Initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&args, 0, sizeof (args));
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* Build args */
2N/A if (obandiskset)
2N/A args.med.med_caller = Strdup(MED_MN_CALLER);
2N/A else
2N/A args.med.med_caller = Strdup(mynode());
2N/A
2N/A args.med.med_setname = Strdup(setname);
2N/A args.med.med_setno = setnum;
2N/A
2N/A if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hp->hostname,
2N/A dgettext(TEXT_DOMAIN, "medd get record"));
2N/A else
2N/A (void) meddstealerror(ep, &res.med_status);
2N/A
2N/A close_medd(hp);
2N/A
2N/A if (mdisok(ep)) {
2N/A /* copy the mediator data in meddp */
2N/A (void) memmove(meddp, &res.med_data, sizeof (med_data_t));
2N/A rval = 0;
2N/A }
2N/A
2N/A xdr_free(xdr_med_args_t, (char *)&args);
2N/A xdr_free(xdr_med_get_data_res_t, (char *)&res);
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Update the mediator information on the mediator.
2N/A * *** This is not normally called from user code, the kernel does this! ***
2N/A */
2N/Aint
2N/Aclnt_med_upd_data(
2N/A md_h_t *mdhp,
2N/A mdsetname_t *sp,
2N/A med_data_t *meddp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_upd_data_args_t args;
2N/A med_err_t res;
2N/A md_set_desc *sd;
2N/A
2N/A /* initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&args, 0, sizeof (args));
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* build args */
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (MD_MNSET_DESC(sd))
2N/A /*
2N/A * In the MN diskset, use a generic nodename, multiowner, as
2N/A * the node initiating the RPC request. This allows
2N/A * any node to access mediator information.
2N/A *
2N/A * MN diskset reconfig cycle forces consistent
2N/A * view of set/node/drive/mediator information across all nodes
2N/A * in the MN diskset. This allows the relaxation of
2N/A * node name checking in rpc.metamedd for MN disksets.
2N/A *
2N/A * In the traditional diskset, only a calling node that is
2N/A * in the mediator record's diskset nodelist can access
2N/A * mediator data.
2N/A */
2N/A args.med.med_caller = Strdup(MED_MN_CALLER);
2N/A else
2N/A args.med.med_caller = Strdup(mynode());
2N/A args.med.med_setname = Strdup(sp->setname);
2N/A args.med.med_setno = sp->setno;
2N/A args.med_data = *meddp;
2N/A
2N/A /* do it */
2N/A if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hp->hostname,
2N/A dgettext(TEXT_DOMAIN, "medd update data"));
2N/A else
2N/A (void) meddstealerror(ep, &res);
2N/A
2N/A close_medd(hp);
2N/A
2N/A xdr_free(xdr_med_upd_data_args_t, (char *)&args);
2N/A xdr_free(xdr_med_err_t, (char *)&res);
2N/A
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Get the mediator data for this client from the mediator
2N/A */
2N/Aint
2N/Aclnt_med_get_data(
2N/A md_h_t *mdhp,
2N/A mdsetname_t *sp,
2N/A med_data_t *meddp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_args_t args;
2N/A med_get_data_res_t res;
2N/A int rval = -1;
2N/A md_set_desc *sd;
2N/A
2N/A /* initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&args, 0, sizeof (args));
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* build args */
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (MD_MNSET_DESC(sd))
2N/A /*
2N/A * In the MN diskset, use a generic nodename, multiowner, as
2N/A * the node initiating the RPC request. This allows
2N/A * any node to access mediator information.
2N/A *
2N/A * MN diskset reconfig cycle forces consistent
2N/A * view of set/node/drive/mediator information across all nodes
2N/A * in the MN diskset. This allows the relaxation of
2N/A * node name checking in rpc.metamedd for MN disksets.
2N/A *
2N/A * In the traditional diskset, only a calling node that is
2N/A * in the mediator record's diskset nodelist can access
2N/A * mediator data.
2N/A */
2N/A args.med.med_caller = Strdup(MED_MN_CALLER);
2N/A else
2N/A args.med.med_caller = Strdup(mynode());
2N/A args.med.med_setname = Strdup(sp->setname);
2N/A args.med.med_setno = sp->setno;
2N/A
2N/A /* do it */
2N/A if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hp->hostname,
2N/A dgettext(TEXT_DOMAIN, "medd get data"));
2N/A else
2N/A (void) meddstealerror(ep, &res.med_status);
2N/A
2N/A close_medd(hp);
2N/A
2N/A if (mdisok(ep)) {
2N/A /* do something with the results */
2N/A (void) memmove(meddp, &res.med_data, sizeof (med_data_t));
2N/A rval = 0;
2N/A }
2N/A
2N/A xdr_free(xdr_med_args_t, (char *)&args);
2N/A xdr_free(xdr_med_get_data_res_t, (char *)&res);
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * Update the mediator record on the mediator.
2N/A */
2N/Aint
2N/Aclnt_med_upd_rec(
2N/A md_h_t *mdhp,
2N/A mdsetname_t *sp,
2N/A med_rec_t *medrp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_upd_rec_args_t args;
2N/A med_err_t res;
2N/A md_set_desc *sd;
2N/A
2N/A /* initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&args, 0, sizeof (args));
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* build args */
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (MD_MNSET_DESC(sd))
2N/A /*
2N/A * In the MN diskset, use a generic nodename, multiowner, as
2N/A * the node initiating the RPC request. This allows
2N/A * any node to access mediator information.
2N/A *
2N/A * MN diskset reconfig cycle forces consistent
2N/A * view of set/node/drive/mediator information across all nodes
2N/A * in the MN diskset. This allows the relaxation of
2N/A * node name checking in rpc.metamedd for MN disksets.
2N/A *
2N/A * In the traditional diskset, only a calling node that is
2N/A * in the mediator record's diskset nodelist can access
2N/A * mediator data.
2N/A */
2N/A args.med.med_caller = Strdup(MED_MN_CALLER);
2N/A else
2N/A args.med.med_caller = Strdup(mynode());
2N/A args.med.med_setname = Strdup(sp->setname);
2N/A args.med.med_setno = sp->setno;
2N/A args.med_flags = 0;
2N/A args.med_rec = *medrp; /* structure assignment */
2N/A
2N/A /* do it */
2N/A if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_upd_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hp->hostname,
2N/A dgettext(TEXT_DOMAIN, "medd update record"));
2N/A else
2N/A (void) meddstealerror(ep, &res);
2N/A
2N/A close_medd(hp);
2N/A
2N/A xdr_free(xdr_med_upd_rec_args_t, (char *)&args);
2N/A xdr_free(xdr_med_err_t, (char *)&res);
2N/A
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Get the mediator record for this client from the mediator
2N/A */
2N/Aint
2N/Aclnt_med_get_rec(
2N/A md_h_t *mdhp,
2N/A mdsetname_t *sp,
2N/A med_rec_t *medrp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_args_t args;
2N/A med_get_rec_res_t res;
2N/A int rval = -1;
2N/A md_set_desc *sd;
2N/A
2N/A /* initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&args, 0, sizeof (args));
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* build args */
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (MD_MNSET_DESC(sd))
2N/A /*
2N/A * In the MN diskset, use a generic nodename, multiowner, as
2N/A * the node initiating the RPC request. This allows
2N/A * any node to access mediator information.
2N/A *
2N/A * MN diskset reconfig cycle forces consistent
2N/A * view of set/node/drive/mediator information across all nodes
2N/A * in the MN diskset. This allows the relaxation of
2N/A * node name checking in rpc.metamedd for MN disksets.
2N/A *
2N/A * In the traditional diskset, only a calling node that is
2N/A * in the mediator record's diskset nodelist can access
2N/A * mediator data.
2N/A */
2N/A args.med.med_caller = Strdup(MED_MN_CALLER);
2N/A else
2N/A args.med.med_caller = Strdup(mynode());
2N/A args.med.med_setname = Strdup(sp->setname);
2N/A args.med.med_setno = sp->setno;
2N/A
2N/A /* do it */
2N/A if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_get_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hp->hostname,
2N/A dgettext(TEXT_DOMAIN, "medd get record"));
2N/A else
2N/A (void) meddstealerror(ep, &res.med_status);
2N/A
2N/A close_medd(hp);
2N/A
2N/A if (mdisok(ep)) {
2N/A /* do something with the results */
2N/A (void) memmove(medrp, &res.med_rec, sizeof (med_rec_t));
2N/A rval = 0;
2N/A }
2N/A
2N/A xdr_free(xdr_med_args_t, (char *)&args);
2N/A xdr_free(xdr_med_get_rec_res_t, (char *)&res);
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/A/*
2N/A * Get the name of the host from the mediator daemon.
2N/A */
2N/Aint
2N/Aclnt_med_hostname(
2N/A char *hostname,
2N/A char **ret_hostname,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A med_handle_t *hp;
2N/A med_hnm_res_t res;
2N/A int rval = -1;
2N/A
2N/A /* initialize */
2N/A mdclrerror(ep);
2N/A (void) memset(&res, 0, sizeof (res));
2N/A
2N/A /* No args */
2N/A
2N/A /* do it */
2N/A if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (med_hostname_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
2N/A (void) mdrpcerror(ep, hp->clntp, hostname,
2N/A dgettext(TEXT_DOMAIN, "medd hostname"));
2N/A else
2N/A (void) meddstealerror(ep, &res.med_status);
2N/A
2N/A close_medd(hp);
2N/A
2N/A if (mdisok(ep)) {
2N/A /* do something with the results */
2N/A rval = 0;
2N/A
2N/A if (ret_hostname != NULL)
2N/A *ret_hostname = Strdup(res.med_hnm);
2N/A }
2N/A
2N/A xdr_free(xdr_med_hnm_res_t, (char *)&res);
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/Aint
2N/Ameta_med_hnm2ip(md_hi_arr_t *mp, md_error_t *ep)
2N/A{
2N/A int i, j;
2N/A int max_meds;
2N/A
2N/A if ((max_meds = get_max_meds(ep)) == 0)
2N/A return (-1);
2N/A
2N/A for (i = 0; i < max_meds; i++) {
2N/A mp->n_lst[i].a_flg = 0;
2N/A /* See if this is the local host */
2N/A if (mp->n_lst[i].a_cnt > 0 &&
2N/A strcmp(mp->n_lst[i].a_nm[0], mynode()) == NULL)
2N/A mp->n_lst[i].a_flg |= NMIP_F_LOCAL;
2N/A
2N/A for (j = 0; j < mp->n_lst[i].a_cnt; j++) {
2N/A struct hostent *hp;
2N/A char *hnm = mp->n_lst[i].a_nm[j];
2N/A
2N/A /*
2N/A * Cluster nodename support
2N/A *
2N/A * See if the clustering code can give us an IP addr
2N/A * for the stored name. If not, find it the old way
2N/A * which will use the public interface.
2N/A */
2N/A if (sdssc_get_priv_ipaddr(mp->n_lst[i].a_nm[j],
2N/A (struct in_addr *)&mp->n_lst[i].a_ip[j]) !=
2N/A SDSSC_OKAY) {
2N/A if ((hp = gethostbyname(hnm)) == NULL)
2N/A return (mdsyserror(ep, EADDRNOTAVAIL,
2N/A hnm));
2N/A
2N/A /* We only do INET addresses */
2N/A if (hp->h_addrtype != AF_INET)
2N/A return (mdsyserror(ep, EPFNOSUPPORT,
2N/A hnm));
2N/A
2N/A /* We take the first address only */
2N/A if (*hp->h_addr_list) {
2N/A (void) memmove(&mp->n_lst[i].a_ip[j],
2N/A *hp->h_addr_list,
2N/A sizeof (struct in_addr));
2N/A } else
2N/A return (mdsyserror(ep, EADDRNOTAVAIL,
2N/A hnm));
2N/A }
2N/A
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Ameta_h2hi(md_h_arr_t *mdhp, md_hi_arr_t *mdhip, md_error_t *ep)
2N/A{
2N/A int i, j;
2N/A int max_meds;
2N/A
2N/A if ((max_meds = get_max_meds(ep)) == 0)
2N/A return (-1);
2N/A
2N/A mdhip->n_cnt = mdhp->n_cnt;
2N/A
2N/A for (i = 0; i < max_meds; i++) {
2N/A mdhip->n_lst[i].a_flg = 0;
2N/A mdhip->n_lst[i].a_cnt = mdhp->n_lst[i].a_cnt;
2N/A if (mdhp->n_lst[i].a_cnt == 0)
2N/A continue;
2N/A for (j = 0; j < mdhp->n_lst[i].a_cnt; j++)
2N/A (void) strcpy(mdhip->n_lst[i].a_nm[j],
2N/A mdhp->n_lst[i].a_nm[j]);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Ameta_hi2h(md_hi_arr_t *mdhip, md_h_arr_t *mdhp, md_error_t *ep)
2N/A{
2N/A int i, j;
2N/A int max_meds;
2N/A
2N/A if ((max_meds = get_max_meds(ep)) == 0)
2N/A return (-1);
2N/A
2N/A mdhp->n_cnt = mdhip->n_cnt;
2N/A for (i = 0; i < max_meds; i++) {
2N/A mdhp->n_lst[i].a_cnt = mdhip->n_lst[i].a_cnt;
2N/A if (mdhip->n_lst[i].a_cnt == 0)
2N/A continue;
2N/A for (j = 0; j < mdhip->n_lst[i].a_cnt; j++)
2N/A (void) strcpy(mdhp->n_lst[i].a_nm[j],
2N/A mdhip->n_lst[i].a_nm[j]);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Asetup_med_cfg(
2N/A mdsetname_t *sp,
2N/A mddb_config_t *cp,
2N/A int force,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_set_desc *sd;
2N/A int i;
2N/A int max_meds;
2N/A
2N/A if (metaislocalset(sp))
2N/A return (0);
2N/A
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (setup_med_transtab(ep))
2N/A return (-1);
2N/A
2N/A if (meta_h2hi(&sd->sd_med, &cp->c_med, ep))
2N/A return (-1);
2N/A
2N/A /* Make sure the ip addresses are current */
2N/A if (meta_med_hnm2ip(&cp->c_med, ep))
2N/A return (-1);
2N/A
2N/A if (force)
2N/A return (0);
2N/A
2N/A if ((max_meds = get_max_meds(ep)) == 0)
2N/A return (-1);
2N/A
2N/A /* Make sure metamedd still running on host - only chk nodename */
2N/A for (i = 0; i < max_meds; i++) {
2N/A char *hostname;
2N/A char *hnm;
2N/A
2N/A if (sd->sd_med.n_lst[i].a_cnt == 0)
2N/A continue;
2N/A
2N/A hnm = sd->sd_med.n_lst[i].a_nm[0];
2N/A
2N/A if (clnt_med_hostname(hnm, &hostname, ep))
2N/A return (mddserror(ep, MDE_DS_NOMEDONHOST, sp->setno,
2N/A hnm, NULL, sp->setname));
2N/A Free(hostname);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * This is a general routine to get mediator information from
2N/A * file /etc/lvm/meddb. Commands medstat and metainit use this
2N/A * routine to get mediator information from all mediator hosts or update
2N/A * its mediator record respectively.
2N/A */
2N/Aint
2N/Ameta_mediator_info_from_file(char *sname, int verbose, md_error_t *ep)
2N/A{
2N/A uint_t c;
2N/A int i;
2N/A int j;
2N/A int fd;
2N/A int rec_size;
2N/A char *setname;
2N/A uint_t setnum;
2N/A med_rec_t *rec_buf = NULL;
2N/A med_db_hdr_t *dbhbr;
2N/A med_rec_t *medrecp;
2N/A med_data_t medd;
2N/A med_data_t save_medd;
2N/A md_h_t mdh;
2N/A uint_t latest_med_dat_cc = 0;
2N/A int retval = 0;
2N/A int medok = 0;
2N/A int golden = 0;
2N/A bool_t obandiskset;
2N/A int isSetFound = 0;
2N/A
2N/A /* Open the meddb file */
2N/A if ((fd = open(MED_DB_FILE, O_RDONLY, 0)) == -1) {
2N/A
2N/A /*
2N/A * During the start up of the SVM services, this function
2N/A * will be called with an empty sname. In that case it is
2N/A * entirely possible for the MED_DB_FILE not to exist.
2N/A * If so, then no need to report an error.
2N/A */
2N/A if (sname != NULL) {
2N/A (void) mdsyserror(ep, errno, MED_DB_FILE);
2N/A mde_perror(ep, dgettext(TEXT_DOMAIN,
2N/A "Error in opening meddb file"));
2N/A return (1);
2N/A }
2N/A return (0);
2N/A }
2N/A
2N/A /* Initialize rec_size */
2N/A rec_size = roundup(sizeof (med_rec_t), DEV_BSIZE);
2N/A
2N/A /* Allocate a record buffer */
2N/A if ((rec_buf = malloc(rec_size)) == NULL) {
2N/A (void) mdsyserror(ep, errno, MED_DB_FILE);
2N/A mde_perror(ep, dgettext(TEXT_DOMAIN,
2N/A "Error in allocating memory"));
2N/A goto out;
2N/A }
2N/A
2N/A /* read the file header */
2N/A if ((read(fd, rec_buf, rec_size)) != rec_size) {
2N/A (void) mdsyserror(ep, EINVAL, MED_DB_FILE);
2N/A mde_perror(ep, dgettext(TEXT_DOMAIN,
2N/A "Error in reading mediator record"));
2N/A goto out;
2N/A }
2N/A
2N/A dbhbr = (med_db_hdr_t *)rec_buf;
2N/A
2N/A /* Number of records in the mediator file */
2N/A c = dbhbr->med_dbh_nm;
2N/A
2N/A for (i = 0; i < c; i++) {
2N/A (void) memset(rec_buf, 0, rec_size);
2N/A
2N/A if (read(fd, rec_buf, rec_size) == -1) {
2N/A (void) mdsyserror(ep, errno, MED_DB_FILE);
2N/A mde_perror(ep, dgettext(TEXT_DOMAIN,
2N/A "Error in reading mediator record"));
2N/A goto out;
2N/A }
2N/A
2N/A medrecp = (med_rec_t *)rec_buf;
2N/A
2N/A /*
2N/A * For oban diskset first entry in the rec_nodes field is
2N/A * "multiowner" and all other entries are empty.
2N/A * Check if this is really multiowner diskset.
2N/A */
2N/A
2N/A if ((strcmp(medrecp->med_rec_nodes[0], MED_MN_CALLER) == 0) &&
2N/A (medrecp->med_rec_nodes[1][0] == '\0'))
2N/A obandiskset = TRUE;
2N/A else
2N/A obandiskset = FALSE;
2N/A
2N/A if (sname != NULL) {
2N/A /*
2N/A * Continue if the set name is not in our interest.
2N/A * This is required when this routine is called
2N/A * from medstat
2N/A */
2N/A
2N/A if (strcmp(sname, medrecp->med_rec_snm) != 0) {
2N/A continue;
2N/A }
2N/A
2N/A if (verbose)
2N/A (void) printf("%8.8s\t\t%6.6s\t%6.6s\n",
2N/A gettext("Mediator"), gettext("Status"),
2N/A gettext("Golden"));
2N/A
2N/A isSetFound = 1;
2N/A setname = sname;
2N/A } else {
2N/A setname = medrecp->med_rec_snm;
2N/A }
2N/A setnum = medrecp->med_rec_sn;
2N/A (void) memset(&medd, '\0', sizeof (medd));
2N/A (void) memset(&mdh, '\0', sizeof (mdh));
2N/A (void) memset(&save_medd, '\0', sizeof (save_medd));
2N/A latest_med_dat_cc = 0;
2N/A
2N/A for (j = 0; j < MED_MAX_HOSTS; j++) {
2N/A /*
2N/A * It is possible for the n_lst[j] slot to be empty
2N/A * if the mediator node has already been removed so
2N/A * go to the next slot.
2N/A */
2N/A if (medrecp->med_rec_meds.n_lst[j].a_cnt == 0)
2N/A continue;
2N/A mdh = medrecp->med_rec_meds.n_lst[j];
2N/A
2N/A if ((sname != NULL) && (verbose))
2N/A (void) printf("%-17.17s\t",
2N/A medrecp->med_rec_meds.n_lst[j].a_nm[0]);
2N/A
2N/A if (clnt_user_med_get_data(&mdh, obandiskset,
2N/A setname, setnum, &medd, ep) == -1) {
2N/A if (sname == NULL) {
2N/A continue;
2N/A } else {
2N/A if (mdanyrpcerror(ep)) {
2N/A if (verbose)
2N/A (void) printf("%s\n",
2N/A gettext("Unreach"
2N/A "able"));
2N/A continue;
2N/A } else if (mdiserror(ep,
2N/A MDE_MED_ERROR)) {
2N/A if (verbose)
2N/A (void) printf("%s\n",
2N/A gettext("Bad"));
2N/A } else {
2N/A if (verbose)
2N/A (void) printf("%s\n",
2N/A gettext("Fatal"));
2N/A }
2N/A mde_perror(ep, "");
2N/A if (mdiserror(ep, MDE_MED_ERROR))
2N/A continue;
2N/A goto out;
2N/A }
2N/A } else {
2N/A /*
2N/A * Make sure this node has the correct value
2N/A * for the mediator record. If not we want the
2N/A * highest value from the other nodes. Save it
2N/A * for updating once the loop through all the
2N/A * mediator nodes has completed.
2N/A */
2N/A if (sname == NULL) {
2N/A if (latest_med_dat_cc <
2N/A medd.med_dat_cc) {
2N/A latest_med_dat_cc =
2N/A medd.med_dat_cc;
2N/A (void) memcpy(&save_medd, &medd,
2N/A sizeof (medd));
2N/A }
2N/A } else {
2N/A if (verbose)
2N/A (void) printf("%s",
2N/A gettext("Ok"));
2N/A if (medd.med_dat_fl & MED_DFL_GOLDEN) {
2N/A if (verbose)
2N/A (void) printf("\t%s",
2N/A gettext("Yes"));
2N/A golden++;
2N/A } else {
2N/A if (verbose)
2N/A (void) printf("\t%s",
2N/A gettext("No"));
2N/A }
2N/A if (verbose)
2N/A (void) printf("\n");
2N/A medok++;
2N/A }
2N/A }
2N/A }
2N/A if (sname == NULL) {
2N/A
2N/A /*
2N/A * Mediators only become active when there are
2N/A * replica updates to the sets and this can only
2N/A * occur when there is a disk in the set.
2N/A * If there are no disks found then the save_medd
2N/A * structure will be empty. If save_medd is empty,
2N/A * do not update the set.
2N/A */
2N/A if (save_medd.med_dat_sn == 0)
2N/A continue;
2N/A /*
2N/A * Update the latest mediator information
2N/A * on this node
2N/A */
2N/A (void) strlcpy(mdh.a_nm[0], mynode(),
2N/A sizeof (mdh.a_nm[0]));
2N/A mdh.a_cnt = 1;
2N/A if (clnt_user_med_upd_data(&mdh, obandiskset,
2N/A setname, setnum, &save_medd, ep) == -1) {
2N/A /*
2N/A * We had some errors while updaing the
2N/A * record. This means this metaset is
2N/A * not updated with latest mediator
2N/A * information.
2N/A */
2N/A mde_perror(ep, "");
2N/A }
2N/A
2N/A } else {
2N/A if (golden) {
2N/A retval = 0;
2N/A goto out;
2N/A }
2N/A if (medok < ((medrecp->med_rec_meds.n_cnt / 2) + 1))
2N/A retval = 1;
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A if ((sname != NULL) && (isSetFound == 0)) {
2N/A (void) mderror(ep, MDE_NO_SET, sname);
2N/A mde_perror(ep, "");
2N/A retval = 1;
2N/A }
2N/A if (rec_buf != NULL)
2N/A Free(rec_buf);
2N/A if (close(fd) < 0) {
2N/A (void) mdsyserror(ep, errno, MED_DB_FILE);
2N/A mde_perror(ep, dgettext(TEXT_DOMAIN,
2N/A "Error in closing meddb file"));
2N/A return (1);
2N/A }
2N/A return (retval);
2N/A}