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