diff options
Diffstat (limited to 'usr/src/lib/librdc/common/rdcpersist.c')
-rw-r--r-- | usr/src/lib/librdc/common/rdcpersist.c | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/usr/src/lib/librdc/common/rdcpersist.c b/usr/src/lib/librdc/common/rdcpersist.c new file mode 100644 index 0000000000..703c8eef11 --- /dev/null +++ b/usr/src/lib/librdc/common/rdcpersist.c @@ -0,0 +1,716 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mkdev.h> +#include <fcntl.h> +#include <unistd.h> +#include <stropts.h> +#include <stdio.h> +#include <errno.h> +#include <libintl.h> +#include <locale.h> +#include <stdlib.h> + +#include <sys/nsctl/rdcerr.h> +#include <sys/nsctl/rdc_ioctl.h> +#include <sys/nsctl/librdc.h> +#include <sys/nsctl/cfg.h> +#include <sys/nsctl/nsc_hash.h> +#include <sys/nsctl/sv.h> + +#include <sys/unistat/spcs_dtrinkets.h> +#include <sys/unistat/spcs_etrinkets.h> +#include <sys/unistat/spcs_s.h> +#include <sys/unistat/spcs_s_u.h> +#include <sys/unistat/spcs_s_impl.h> +#include <sys/unistat/spcs_errors.h> + +typedef struct volcount_s { + int count; +} volcount_t; + +hash_node_t **volhash = NULL; + +char * +config2buf(char *buf, rdcconfig_t *rdc) +{ + snprintf(buf, CFG_MAX_BUF, "%s %s %s %s %s %s %s %s %s %s %s", + rdc->phost, rdc->pfile, rdc->pbmp, rdc->shost, rdc->sfile, + rdc->sbmp, rdc->direct, rdc->mode, rdc->group ? rdc->group : "", + rdc->ctag ? rdc->ctag : "", rdc->options ? rdc->options : ""); + return (buf); + +} + +/* + * SV type functions. + */ + +static void +load_rdc_vols(CFGFILE *cfg) +{ + int set; + char key[ CFG_MAX_KEY ]; + char buf[ CFG_MAX_BUF ]; + char *vol, *bmp, *host1, *host2; + volcount_t *volcount; + + if (volhash) { + return; + } + + cfg_rewind(cfg, CFG_SEC_CONF); + volhash = nsc_create_hash(); + for (set = 1; /*CSTYLED*/; set++) { + snprintf(key, CFG_MAX_KEY, "sndr.set%d", set); + if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)) { + break; + } + + host1 = strtok(buf, " "); + vol = strtok(NULL, " "); + bmp = strtok(NULL, " "); + + if (!self_check(host1)) { + /* next one had better be ours */ + host2 = strtok(NULL, " "); + vol = strtok(NULL, " "); + bmp = strtok(NULL, " "); + + if (!self_check(host2)) { + continue; + } + } + + /* primary vol may be used more than once */ + volcount = (volcount_t *)nsc_lookup(volhash, vol); + if (volcount) { + volcount->count++; + } else { + volcount = (volcount_t *)malloc(sizeof (volcount_t)); + volcount->count = 1; + nsc_insert_node(volhash, volcount, vol); + } + + /* bitmap ought to be only used once */ + volcount = (volcount_t *)nsc_lookup(volhash, bmp); + if (volcount) { + /* argh */ + volcount->count++; + } else { + volcount = (volcount_t *)malloc(sizeof (volcount_t)); + volcount->count = 1; + nsc_insert_node(volhash, volcount, bmp); + } + } +} + +int +sv_enable_one_nocfg(char *vol) +{ + struct stat sb; + sv_conf_t svc; + int fd; + + bzero(&svc, sizeof (svc)); + if (stat(vol, &sb) != 0) { + rdc_set_error(NULL, RDC_OS, 0, "unable to stat %s", vol); + return (-1); + } + if (!S_ISCHR(sb.st_mode)) { + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, "%s is not" + " a character device", vol); + return (-1); + } + + svc.svc_major = major(sb.st_rdev); + svc.svc_minor = minor(sb.st_rdev); + strncpy(svc.svc_path, vol, sizeof (svc.svc_path)); + + fd = open(SV_DEVICE, O_RDONLY); + if (fd < 0) { + rdc_set_error(NULL, RDC_OS, 0, 0); + return (-1); + } + + svc.svc_flag = (NSC_DEVICE | NSC_CACHE); + svc.svc_error = spcs_s_ucreate(); + + if (ioctl(fd, SVIOC_ENABLE, &svc) < 0) { + if (errno != SV_EENABLED) { + rdc_set_error(&svc.svc_error, RDC_INTERNAL, + RDC_NONFATAL, 0); + return (-1); + } + } + + spcs_log("sv", NULL, gettext("enabled %s"), svc.svc_path); + + close(fd); + return (1); +} + +int +sv_enable_nocfg(rdcconfig_t *rdc) +{ + struct stat stbv; + struct stat stbb; + sv_conf_t svcv; + sv_conf_t svcb; + char vol[NSC_MAXPATH]; + char bmp[NSC_MAXPATH]; + int fd = -1; + + + if (self_check(rdc->phost)) { + strncpy(vol, rdc->pfile, NSC_MAXPATH); + strncpy(bmp, rdc->pbmp, NSC_MAXPATH); + } else { + strncpy(vol, rdc->sfile, NSC_MAXPATH); + strncpy(bmp, rdc->sbmp, NSC_MAXPATH); + } + + bzero(&svcv, sizeof (svcv)); + bzero(&svcb, sizeof (svcb)); + + if ((stat(vol, &stbv) != 0) || (stat(bmp, &stbb) != 0)) + return (-1); + + if ((!S_ISCHR(stbv.st_mode)) || (!S_ISCHR(stbb.st_mode))) + return (-1); + + svcv.svc_major = major(stbv.st_rdev); + svcb.svc_minor = minor(stbb.st_rdev); + + strncpy(svcv.svc_path, vol, sizeof (svcv.svc_path)); + strncpy(svcb.svc_path, bmp, sizeof (svcb.svc_path)); + + fd = open(SV_DEVICE, O_RDONLY); + if (fd < 0) + return (-1); + + /* SV enable the volume */ + svcv.svc_flag = (NSC_DEVICE | NSC_CACHE); + svcv.svc_error = spcs_s_ucreate(); + + if (ioctl(fd, SVIOC_ENABLE, &svcv) < 0) { + if (errno != SV_EENABLED) { + spcs_log("sv", &svcv.svc_error, + gettext("unable to enable %s"), + svcv.svc_path); + spcs_s_ufree(&svcv.svc_error); + return (-1); + } + } + + /* SV enable the bitmap disable the vol on error */ + svcb.svc_flag = (NSC_DEVICE | NSC_CACHE); + svcb.svc_error = spcs_s_ucreate(); + + if (ioctl(fd, SVIOC_ENABLE, &svcb) < 0) { + if (errno != SV_EENABLED) { + spcs_log("sv", &svcb.svc_error, + gettext("unable to enable %s"), + svcb.svc_path); + if (ioctl(fd, SVIOC_DISABLE, &svcv) < 0) + spcs_log("sv", &svcv.svc_error, + gettext("unable to disable %s"), + svcv.svc_path); + + spcs_s_ufree(&svcv.svc_error); + spcs_s_ufree(&svcb.svc_error); + return (-1); + } + } + + + spcs_log("sv", NULL, gettext("enabled %s"), svcv.svc_path); + spcs_log("sv", NULL, gettext("enabled %s"), svcb.svc_path); + spcs_s_ufree(&svcv.svc_error); + spcs_s_ufree(&svcb.svc_error); + + + if (fd >= 0) + (void) close(fd); + + return (1); +} + +int +do_autosv_enable(CFGFILE *cfg, rdcconfig_t *rdc) +{ + char vol[NSC_MAXPATH]; + char bmp[NSC_MAXPATH]; + + cfg_load_svols(cfg); + cfg_load_dsvols(cfg); + cfg_load_shadows(cfg); + load_rdc_vols(cfg); + + if (self_check(rdc->phost)) { + strncpy(vol, rdc->pfile, NSC_MAXPATH); + strncpy(bmp, rdc->pbmp, NSC_MAXPATH); + } else { + strncpy(vol, rdc->sfile, NSC_MAXPATH); + strncpy(bmp, rdc->sbmp, NSC_MAXPATH); + } + if (nsc_lookup(volhash, vol) == NULL) { + if (cfg_vol_enable(cfg, vol, rdc->ctag, "sndr") < 0) { + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "auto sv enable failed for %s", vol); + return (-1); + } + } + if (nsc_lookup(volhash, bmp) == NULL) { + if (cfg_vol_enable(cfg, bmp, rdc->ctag, "sndr") < 0) { + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "auto sv enable failed for %s", vol); + return (-1); + } + } + + nsc_remove_all(volhash, free); + volhash = NULL; + + cfg_unload_shadows(); + cfg_unload_dsvols(); + cfg_unload_svols(); + + return (1); +} + +int +do_autosv_disable(CFGFILE *cfg, rdcconfig_t *rdc) +{ + char vol[NSC_MAXPATH]; + char bmp[NSC_MAXPATH]; + volcount_t *vc; + + cfg_load_svols(cfg); + cfg_load_dsvols(cfg); + cfg_load_shadows(cfg); + load_rdc_vols(cfg); + + if (self_check(rdc->phost)) { + strncpy(vol, rdc->pfile, NSC_MAXPATH); + strncpy(bmp, rdc->pbmp, NSC_MAXPATH); + } else { + strncpy(vol, rdc->sfile, NSC_MAXPATH); + strncpy(bmp, rdc->sbmp, NSC_MAXPATH); + } + + vc = nsc_lookup(volhash, vol); + if (vc && (vc->count == 1)) { + if (cfg_vol_disable(cfg, vol, rdc->ctag, "sndr") < 0) + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "auto sv disable failed for %s", vol); + } else if (!vc) { + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "Unable to find %s in config", vol); + } + vc = nsc_lookup(volhash, bmp); + if (vc && (vc->count == 1)) { + if (cfg_vol_disable(cfg, bmp, rdc->ctag, "sndr") < 0) + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "auto sv disable failed for %s", bmp); + + } else if (!vc) { + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "Unable to find %s in config", bmp); + } + + return (1); + +} + +/* + * do sv enables for the appropriate vol + * and bitmap. If called without persistance + * it will follow a chain and sv enable all + * otherwise, it will enable only the one + * set. + */ +int +sv_enable(CFGFILE *cfg, rdcconfig_t *rdcs) +{ + rdcconfig_t *rdcp = NULL; + + rdcp = rdcs; + if (!rdcp->persist) { + + return (sv_enable_nocfg(rdcp)); + + } else if (cfg == NULL) { + + return (-1); + + } + + do_autosv_enable(cfg, rdcp); + + return (1); +} + +int +sv_disable(CFGFILE *cfg, rdcconfig_t *rdcs) +{ + rdcconfig_t *rdcp; + + rdcp = rdcs; + if (!rdcp->persist) { /* don't disable */ + + return (1); + + } else if (cfg == NULL) { + + return (-1); + + } + + do_autosv_disable(cfg, rdcp); + + return (1); + +} + +/* + * disable the appropriate bitmap in rdc + * and replace it with bitmap + */ +int +sv_reconfig(CFGFILE *cfg, rdcconfig_t *rdc, char *oldbmp, char *newbmp) +{ + rdcconfig_t *rdcp; + int fail = 0; + + rdcp = rdc; + if (!rdcp->persist) { /* just enable, don't disable */ + + sv_enable_one_nocfg(newbmp); + + } else if (rdcp->persist) { /* do sv disable and enable */ + volcount_t *vc; + + cfg_load_svols(cfg); + cfg_load_dsvols(cfg); + cfg_load_shadows(cfg); + load_rdc_vols(cfg); + + vc = (volcount_t *)nsc_lookup(volhash, oldbmp); + if (vc && (vc->count == 1)) { + if (cfg_vol_disable(cfg, oldbmp, rdc->ctag, "sndr") < 0) + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "auto sv disable failed for %s", oldbmp); + + } + if (nsc_lookup(volhash, newbmp) == NULL) { + if (cfg_vol_enable(cfg, + newbmp, rdc->ctag, "sndr") < 0) { + + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "auto sv enable failed for %s", newbmp); + fail++; + } + } + nsc_remove_all(volhash, free); + volhash = NULL; + + cfg_unload_shadows(); + cfg_unload_dsvols(); + cfg_unload_svols(); + if (fail) + return (-1); + + } + return (1); + +} + +/* + * SNDR functions + */ + +/* + * add_to_rdc_cfg + * this adds the successfully created rdc sets to libdscfg, + * also, as auto_sv stuff is part of libdscfg, it does the + * auto_sv stuff and enables the correct volumes + */ +int +add_to_rdc_cfg(rdcconfig_t *rdcs) +{ + CFGFILE *cfg; + rdcconfig_t *rdcp; + char *buf; + + + buf = calloc(CFG_MAX_BUF, sizeof (char)); + if (!buf) { + rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL); + return (NULL); + } + + if ((cfg = cfg_open(NULL)) == NULL) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + + rdcp = rdcs; + while (rdcp) { + buf = config2buf(buf, rdcp); + if ((sv_enable(cfg, rdcp) < 0) || + (cfg_put_cstring(cfg, "sndr", buf, CFG_MAX_BUF) < 0)) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + free(buf); + return (-1); + } + rdcp = rdcp->next; + } + if (!cfg_commit(cfg)) { + rdc_set_error(NULL, RDC_DSCFG, 0, NULL); + return (-1); + } + + cfg_close(cfg); + + return (0); +} + +int +cfg_lookup(CFGFILE *cfg, char *shost, char *sfile) +{ + char buf[CFG_MAX_BUF]; + char key[CFG_MAX_KEY]; + int setnum; + int numsets = 0; + + numsets = cfg_get_num_entries(cfg, "sndr"); + for (setnum = 1; setnum <= numsets; setnum++) { + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.shost", setnum); + if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + if (strncmp(buf, shost, strlen(shost))) + continue; + + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.secondary", setnum); + if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + if (strncmp(buf, sfile, strlen(sfile))) + continue; + break; + } + return (setnum); +} + +void +remove_from_rdc_cfg(rdcconfig_t *rdcs) +{ + CFGFILE *cfg; + rdcconfig_t *rdcp; + char key[CFG_MAX_KEY]; + + rdcp = rdcs; + cfg = cfg_open(NULL); + cfg_lock(cfg, CFG_WRLOCK); + + while (rdcp) { + snprintf(key, CFG_MAX_KEY, "sndr.set%d", + cfg_lookup(cfg, rdcp->shost, rdcp->sfile)); + if ((sv_disable(cfg, rdcp) < 0) || + (cfg_put_cstring(cfg, key, NULL, 0)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + } + + rdcp = rdcp->next; + } + cfg_commit(cfg); + cfg_close(cfg); +} +/*ARGSUSED*/ +int +replace_entry(int offset, char *entry) +{ + return (1); +} + +/* + * this will set the value at "field" in dscfg to the + * value contained in entry. + * for things like bitmap reconfigs, only pass one rdc + * not a chain + */ +int +replace_cfgfield(rdcconfig_t *rdc, char *field, char *entry) +{ + CFGFILE *cfg; + rdcconfig_t *rdcp; + char key[CFG_MAX_KEY]; + char newentry[CFG_MAX_BUF]; + char oldbmp[CFG_MAX_BUF]; + int setnum; + int ispbmp = 0; + int issbmp = 0; + + if (strncmp(field, "pbitmap", NSC_MAXPATH) == 0) + ispbmp++; + if (strncmp(field, "sbitmap", NSC_MAXPATH) == 0) + issbmp++; + + bzero(newentry, sizeof (newentry)); + if (!entry || strlen(entry) == 0) + *newentry = '-'; + else + strncpy(newentry, entry, CFG_MAX_BUF); + + + if ((cfg = cfg_open(NULL)) == NULL) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + + rdcp = rdc; + while (rdcp) { + if ((setnum = cfg_lookup(cfg, rdcp->shost, rdcp->sfile)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + snprintf(key, CFG_MAX_KEY, "sndr.set%d.%s", setnum, field); + if (!((ispbmp || issbmp) && + (cfg_get_cstring(cfg, key, oldbmp, CFG_MAX_BUF)) == 0)) { + rdc_set_error(NULL, RDC_DSCFG, 0, "unable to get %s", + key); + } + if (((ispbmp && self_check(rdcp->phost)) || + (issbmp && self_check(rdcp->shost))) && + (sv_reconfig(cfg, rdcp, oldbmp, newentry) < 0)) { + rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, + "unable to sv reconfig %s to %s", oldbmp, newentry); + return (-1); + } + + if ((cfg_put_cstring(cfg, key, newentry, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + rdcp = rdcp->next; + } + cfg_commit(cfg); + cfg_close(cfg); + return (1); +} + +/* + * reverse_in_cfg + * used by RDC_OPT_REVERSE_ROLE + * swaps primary info and secondary info + */ +int +reverse_in_cfg(rdcconfig_t *rdc) +{ + CFGFILE *cfg; + rdcconfig_t *rdcp = NULL; + char key[CFG_MAX_KEY]; + int setnum; + + if ((cfg = cfg_open(NULL)) == NULL) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + return (-1); + } + + rdcp = rdc; + while (rdcp) { + if ((setnum = cfg_lookup(cfg, rdcp->shost, rdcp->sfile)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.phost", setnum); + if ((cfg_put_cstring(cfg, key, rdcp->shost, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.primary", setnum); + if ((cfg_put_cstring(cfg, key, rdcp->sfile, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.pbitmap", setnum); + if ((cfg_put_cstring(cfg, key, rdcp->sbmp, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.shost", setnum); + if ((cfg_put_cstring(cfg, key, rdcp->phost, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.secondary", setnum); + if ((cfg_put_cstring(cfg, key, rdcp->pfile, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + bzero(key, CFG_MAX_KEY); + snprintf(key, CFG_MAX_KEY, "sndr.set%d.sbitmap", setnum); + if ((cfg_put_cstring(cfg, key, rdcp->pbmp, CFG_MAX_BUF)) < 0) { + rdc_set_error(NULL, RDC_DSCFG, 0, 0); + goto badconfig; + } + rdcp = rdcp->next; + } + if (!cfg_commit(cfg)) { + cfg_close(cfg); + return (-1); + } + cfg_close(cfg); + return (0); + +badconfig: + cfg_close(cfg); + return (-1); +} |