4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
28 #include <sys/mkdev.h>
38 #include <sys/nsctl/rdcerr.h>
39 #include <sys/nsctl/rdc_ioctl.h>
40 #include <sys/nsctl/librdc.h>
41 #include <sys/nsctl/cfg.h>
42 #include <sys/nsctl/nsc_hash.h>
43 #include <sys/nsctl/sv.h>
45 #include <sys/unistat/spcs_dtrinkets.h>
46 #include <sys/unistat/spcs_etrinkets.h>
47 #include <sys/unistat/spcs_s.h>
48 #include <sys/unistat/spcs_s_u.h>
49 #include <sys/unistat/spcs_s_impl.h>
50 #include <sys/unistat/spcs_errors.h>
52 typedef struct volcount_s
{
56 hash_node_t
**volhash
= NULL
;
59 config2buf(char *buf
, rdcconfig_t
*rdc
)
61 snprintf(buf
, CFG_MAX_BUF
, "%s %s %s %s %s %s %s %s %s %s %s",
62 rdc
->phost
, rdc
->pfile
, rdc
->pbmp
, rdc
->shost
, rdc
->sfile
,
63 rdc
->sbmp
, rdc
->direct
, rdc
->mode
, rdc
->group
? rdc
->group
: "",
64 rdc
->ctag
? rdc
->ctag
: "", rdc
->options
? rdc
->options
: "");
74 load_rdc_vols(CFGFILE
*cfg
)
77 char key
[ CFG_MAX_KEY
];
78 char buf
[ CFG_MAX_BUF
];
79 char *vol
, *bmp
, *host1
, *host2
;
86 cfg_rewind(cfg
, CFG_SEC_CONF
);
87 volhash
= nsc_create_hash();
88 for (set
= 1; /*CSTYLED*/; set
++) {
89 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d", set
);
90 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
)) {
94 host1
= strtok(buf
, " ");
95 vol
= strtok(NULL
, " ");
96 bmp
= strtok(NULL
, " ");
98 if (!self_check(host1
)) {
99 /* next one had better be ours */
100 host2
= strtok(NULL
, " ");
101 vol
= strtok(NULL
, " ");
102 bmp
= strtok(NULL
, " ");
104 if (!self_check(host2
)) {
109 /* primary vol may be used more than once */
110 volcount
= (volcount_t
*)nsc_lookup(volhash
, vol
);
114 volcount
= (volcount_t
*)malloc(sizeof (volcount_t
));
116 nsc_insert_node(volhash
, volcount
, vol
);
119 /* bitmap ought to be only used once */
120 volcount
= (volcount_t
*)nsc_lookup(volhash
, bmp
);
125 volcount
= (volcount_t
*)malloc(sizeof (volcount_t
));
127 nsc_insert_node(volhash
, volcount
, bmp
);
133 sv_enable_one_nocfg(char *vol
)
139 bzero(&svc
, sizeof (svc
));
140 if (stat(vol
, &sb
) != 0) {
141 rdc_set_error(NULL
, RDC_OS
, 0, "unable to stat %s", vol
);
144 if (!S_ISCHR(sb
.st_mode
)) {
145 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
, "%s is not"
146 " a character device", vol
);
150 svc
.svc_major
= major(sb
.st_rdev
);
151 svc
.svc_minor
= minor(sb
.st_rdev
);
152 strncpy(svc
.svc_path
, vol
, sizeof (svc
.svc_path
));
154 fd
= open(SV_DEVICE
, O_RDONLY
);
156 rdc_set_error(NULL
, RDC_OS
, 0, 0);
160 svc
.svc_flag
= (NSC_DEVICE
| NSC_CACHE
);
161 svc
.svc_error
= spcs_s_ucreate();
163 if (ioctl(fd
, SVIOC_ENABLE
, &svc
) < 0) {
164 if (errno
!= SV_EENABLED
) {
165 rdc_set_error(&svc
.svc_error
, RDC_INTERNAL
,
171 spcs_log("sv", NULL
, gettext("enabled %s"), svc
.svc_path
);
178 sv_enable_nocfg(rdcconfig_t
*rdc
)
184 char vol
[NSC_MAXPATH
];
185 char bmp
[NSC_MAXPATH
];
189 if (self_check(rdc
->phost
)) {
190 strncpy(vol
, rdc
->pfile
, NSC_MAXPATH
);
191 strncpy(bmp
, rdc
->pbmp
, NSC_MAXPATH
);
193 strncpy(vol
, rdc
->sfile
, NSC_MAXPATH
);
194 strncpy(bmp
, rdc
->sbmp
, NSC_MAXPATH
);
197 bzero(&svcv
, sizeof (svcv
));
198 bzero(&svcb
, sizeof (svcb
));
200 if ((stat(vol
, &stbv
) != 0) || (stat(bmp
, &stbb
) != 0))
203 if ((!S_ISCHR(stbv
.st_mode
)) || (!S_ISCHR(stbb
.st_mode
)))
206 svcv
.svc_major
= major(stbv
.st_rdev
);
207 svcb
.svc_minor
= minor(stbb
.st_rdev
);
209 strncpy(svcv
.svc_path
, vol
, sizeof (svcv
.svc_path
));
210 strncpy(svcb
.svc_path
, bmp
, sizeof (svcb
.svc_path
));
212 fd
= open(SV_DEVICE
, O_RDONLY
);
216 /* SV enable the volume */
217 svcv
.svc_flag
= (NSC_DEVICE
| NSC_CACHE
);
218 svcv
.svc_error
= spcs_s_ucreate();
220 if (ioctl(fd
, SVIOC_ENABLE
, &svcv
) < 0) {
221 if (errno
!= SV_EENABLED
) {
222 spcs_log("sv", &svcv
.svc_error
,
223 gettext("unable to enable %s"),
225 spcs_s_ufree(&svcv
.svc_error
);
230 /* SV enable the bitmap disable the vol on error */
231 svcb
.svc_flag
= (NSC_DEVICE
| NSC_CACHE
);
232 svcb
.svc_error
= spcs_s_ucreate();
234 if (ioctl(fd
, SVIOC_ENABLE
, &svcb
) < 0) {
235 if (errno
!= SV_EENABLED
) {
236 spcs_log("sv", &svcb
.svc_error
,
237 gettext("unable to enable %s"),
239 if (ioctl(fd
, SVIOC_DISABLE
, &svcv
) < 0)
240 spcs_log("sv", &svcv
.svc_error
,
241 gettext("unable to disable %s"),
244 spcs_s_ufree(&svcv
.svc_error
);
245 spcs_s_ufree(&svcb
.svc_error
);
251 spcs_log("sv", NULL
, gettext("enabled %s"), svcv
.svc_path
);
252 spcs_log("sv", NULL
, gettext("enabled %s"), svcb
.svc_path
);
253 spcs_s_ufree(&svcv
.svc_error
);
254 spcs_s_ufree(&svcb
.svc_error
);
264 do_autosv_enable(CFGFILE
*cfg
, rdcconfig_t
*rdc
)
266 char vol
[NSC_MAXPATH
];
267 char bmp
[NSC_MAXPATH
];
270 cfg_load_dsvols(cfg
);
271 cfg_load_shadows(cfg
);
274 if (self_check(rdc
->phost
)) {
275 strncpy(vol
, rdc
->pfile
, NSC_MAXPATH
);
276 strncpy(bmp
, rdc
->pbmp
, NSC_MAXPATH
);
278 strncpy(vol
, rdc
->sfile
, NSC_MAXPATH
);
279 strncpy(bmp
, rdc
->sbmp
, NSC_MAXPATH
);
281 if (nsc_lookup(volhash
, vol
) == NULL
) {
282 if (cfg_vol_enable(cfg
, vol
, rdc
->ctag
, "sndr") < 0) {
283 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
284 "auto sv enable failed for %s", vol
);
288 if (nsc_lookup(volhash
, bmp
) == NULL
) {
289 if (cfg_vol_enable(cfg
, bmp
, rdc
->ctag
, "sndr") < 0) {
290 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
291 "auto sv enable failed for %s", vol
);
296 nsc_remove_all(volhash
, free
);
299 cfg_unload_shadows();
307 do_autosv_disable(CFGFILE
*cfg
, rdcconfig_t
*rdc
)
309 char vol
[NSC_MAXPATH
];
310 char bmp
[NSC_MAXPATH
];
314 cfg_load_dsvols(cfg
);
315 cfg_load_shadows(cfg
);
318 if (self_check(rdc
->phost
)) {
319 strncpy(vol
, rdc
->pfile
, NSC_MAXPATH
);
320 strncpy(bmp
, rdc
->pbmp
, NSC_MAXPATH
);
322 strncpy(vol
, rdc
->sfile
, NSC_MAXPATH
);
323 strncpy(bmp
, rdc
->sbmp
, NSC_MAXPATH
);
326 vc
= nsc_lookup(volhash
, vol
);
327 if (vc
&& (vc
->count
== 1)) {
328 if (cfg_vol_disable(cfg
, vol
, rdc
->ctag
, "sndr") < 0)
329 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
330 "auto sv disable failed for %s", vol
);
332 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
333 "Unable to find %s in config", vol
);
335 vc
= nsc_lookup(volhash
, bmp
);
336 if (vc
&& (vc
->count
== 1)) {
337 if (cfg_vol_disable(cfg
, bmp
, rdc
->ctag
, "sndr") < 0)
338 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
339 "auto sv disable failed for %s", bmp
);
342 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
343 "Unable to find %s in config", bmp
);
351 * do sv enables for the appropriate vol
352 * and bitmap. If called without persistance
353 * it will follow a chain and sv enable all
354 * otherwise, it will enable only the one
358 sv_enable(CFGFILE
*cfg
, rdcconfig_t
*rdcs
)
360 rdcconfig_t
*rdcp
= NULL
;
363 if (!rdcp
->persist
) {
365 return (sv_enable_nocfg(rdcp
));
367 } else if (cfg
== NULL
) {
373 do_autosv_enable(cfg
, rdcp
);
379 sv_disable(CFGFILE
*cfg
, rdcconfig_t
*rdcs
)
384 if (!rdcp
->persist
) { /* don't disable */
388 } else if (cfg
== NULL
) {
394 do_autosv_disable(cfg
, rdcp
);
401 * disable the appropriate bitmap in rdc
402 * and replace it with bitmap
405 sv_reconfig(CFGFILE
*cfg
, rdcconfig_t
*rdc
, char *oldbmp
, char *newbmp
)
411 if (!rdcp
->persist
) { /* just enable, don't disable */
413 sv_enable_one_nocfg(newbmp
);
415 } else if (rdcp
->persist
) { /* do sv disable and enable */
419 cfg_load_dsvols(cfg
);
420 cfg_load_shadows(cfg
);
423 vc
= (volcount_t
*)nsc_lookup(volhash
, oldbmp
);
424 if (vc
&& (vc
->count
== 1)) {
425 if (cfg_vol_disable(cfg
, oldbmp
, rdc
->ctag
, "sndr") < 0)
426 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
427 "auto sv disable failed for %s", oldbmp
);
430 if (nsc_lookup(volhash
, newbmp
) == NULL
) {
431 if (cfg_vol_enable(cfg
,
432 newbmp
, rdc
->ctag
, "sndr") < 0) {
434 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
435 "auto sv enable failed for %s", newbmp
);
439 nsc_remove_all(volhash
, free
);
442 cfg_unload_shadows();
459 * this adds the successfully created rdc sets to libdscfg,
460 * also, as auto_sv stuff is part of libdscfg, it does the
461 * auto_sv stuff and enables the correct volumes
464 add_to_rdc_cfg(rdcconfig_t
*rdcs
)
471 buf
= calloc(CFG_MAX_BUF
, sizeof (char));
473 rdc_set_error(NULL
, RDC_OS
, RDC_FATAL
, NULL
);
477 if ((cfg
= cfg_open(NULL
)) == NULL
) {
478 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
481 if ((cfg_lock(cfg
, CFG_WRLOCK
)) < 0) {
482 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
488 buf
= config2buf(buf
, rdcp
);
489 if ((sv_enable(cfg
, rdcp
) < 0) ||
490 (cfg_put_cstring(cfg
, "sndr", buf
, CFG_MAX_BUF
) < 0)) {
491 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
497 if (!cfg_commit(cfg
)) {
498 rdc_set_error(NULL
, RDC_DSCFG
, 0, NULL
);
508 cfg_lookup(CFGFILE
*cfg
, char *shost
, char *sfile
)
510 char buf
[CFG_MAX_BUF
];
511 char key
[CFG_MAX_KEY
];
515 numsets
= cfg_get_num_entries(cfg
, "sndr");
516 for (setnum
= 1; setnum
<= numsets
; setnum
++) {
517 bzero(key
, CFG_MAX_KEY
);
518 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.shost", setnum
);
519 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
520 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
523 if (strncmp(buf
, shost
, strlen(shost
)))
526 bzero(key
, CFG_MAX_KEY
);
527 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.secondary", setnum
);
528 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
529 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
532 if (strncmp(buf
, sfile
, strlen(sfile
)))
540 remove_from_rdc_cfg(rdcconfig_t
*rdcs
)
544 char key
[CFG_MAX_KEY
];
547 cfg
= cfg_open(NULL
);
548 cfg_lock(cfg
, CFG_WRLOCK
);
551 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d",
552 cfg_lookup(cfg
, rdcp
->shost
, rdcp
->sfile
));
553 if ((sv_disable(cfg
, rdcp
) < 0) ||
554 (cfg_put_cstring(cfg
, key
, NULL
, 0)) < 0) {
555 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
565 replace_entry(int offset
, char *entry
)
571 * this will set the value at "field" in dscfg to the
572 * value contained in entry.
573 * for things like bitmap reconfigs, only pass one rdc
577 replace_cfgfield(rdcconfig_t
*rdc
, char *field
, char *entry
)
581 char key
[CFG_MAX_KEY
];
582 char newentry
[CFG_MAX_BUF
];
583 char oldbmp
[CFG_MAX_BUF
];
588 if (strncmp(field
, "pbitmap", NSC_MAXPATH
) == 0)
590 if (strncmp(field
, "sbitmap", NSC_MAXPATH
) == 0)
593 bzero(newentry
, sizeof (newentry
));
594 if (!entry
|| strlen(entry
) == 0)
597 strncpy(newentry
, entry
, CFG_MAX_BUF
);
600 if ((cfg
= cfg_open(NULL
)) == NULL
) {
601 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
604 if ((cfg_lock(cfg
, CFG_WRLOCK
)) < 0) {
605 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
611 if ((setnum
= cfg_lookup(cfg
, rdcp
->shost
, rdcp
->sfile
)) < 0) {
612 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
615 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.%s", setnum
, field
);
616 if (!((ispbmp
|| issbmp
) &&
617 (cfg_get_cstring(cfg
, key
, oldbmp
, CFG_MAX_BUF
)) == 0)) {
618 rdc_set_error(NULL
, RDC_DSCFG
, 0, "unable to get %s",
621 if (((ispbmp
&& self_check(rdcp
->phost
)) ||
622 (issbmp
&& self_check(rdcp
->shost
))) &&
623 (sv_reconfig(cfg
, rdcp
, oldbmp
, newentry
) < 0)) {
624 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
625 "unable to sv reconfig %s to %s", oldbmp
, newentry
);
629 if ((cfg_put_cstring(cfg
, key
, newentry
, CFG_MAX_BUF
)) < 0) {
630 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
642 * used by RDC_OPT_REVERSE_ROLE
643 * swaps primary info and secondary info
646 reverse_in_cfg(rdcconfig_t
*rdc
)
649 rdcconfig_t
*rdcp
= NULL
;
650 char key
[CFG_MAX_KEY
];
653 if ((cfg
= cfg_open(NULL
)) == NULL
) {
654 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
657 if ((cfg_lock(cfg
, CFG_WRLOCK
)) < 0) {
658 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
664 if ((setnum
= cfg_lookup(cfg
, rdcp
->shost
, rdcp
->sfile
)) < 0) {
665 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
668 bzero(key
, CFG_MAX_KEY
);
669 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.phost", setnum
);
670 if ((cfg_put_cstring(cfg
, key
, rdcp
->shost
, CFG_MAX_BUF
)) < 0) {
671 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
674 bzero(key
, CFG_MAX_KEY
);
675 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.primary", setnum
);
676 if ((cfg_put_cstring(cfg
, key
, rdcp
->sfile
, CFG_MAX_BUF
)) < 0) {
677 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
680 bzero(key
, CFG_MAX_KEY
);
681 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.pbitmap", setnum
);
682 if ((cfg_put_cstring(cfg
, key
, rdcp
->sbmp
, CFG_MAX_BUF
)) < 0) {
683 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
686 bzero(key
, CFG_MAX_KEY
);
687 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.shost", setnum
);
688 if ((cfg_put_cstring(cfg
, key
, rdcp
->phost
, CFG_MAX_BUF
)) < 0) {
689 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
692 bzero(key
, CFG_MAX_KEY
);
693 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.secondary", setnum
);
694 if ((cfg_put_cstring(cfg
, key
, rdcp
->pfile
, CFG_MAX_BUF
)) < 0) {
695 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
698 bzero(key
, CFG_MAX_KEY
);
699 snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.sbitmap", setnum
);
700 if ((cfg_put_cstring(cfg
, key
, rdcp
->pbmp
, CFG_MAX_BUF
)) < 0) {
701 rdc_set_error(NULL
, RDC_DSCFG
, 0, 0);
706 if (!cfg_commit(cfg
)) {