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.
27 * This file contains the glue code that allows the NWS software to
28 * determine whether a cluster disk service is local to this node or
31 * See PSARC/1999/462 for more information on the interfaces from
32 * suncluster that are used here.
35 #include <sys/types.h>
37 #include <sys/mkdev.h>
48 #include <sys/ncall/ncall.h>
49 #include <sys/nsctl/nsc_hash.h>
51 #include "cfg_cluster.h"
59 static scconf_nodeid_t cl_nodeid
= (uint_t
)0xffff;
60 static char *cl_nodename
= NULL
;
62 static void *libscstat
;
63 static void *libscconf
;
65 static hash_node_t
**schash
;
66 static int init_sc_entry();
68 typedef struct hash_data_s
{
69 scstat_node_name_t scstat_node_name
;
75 int cl_initialized
= 0;
79 * Tell the linker to keep quiet.
82 #pragma weak scconf_get_nodename
83 #pragma weak scconf_strerr
84 #pragma weak scconf_get_ds_by_devt
86 #pragma weak scstat_get_ds_status
87 #pragma weak scstat_free_ds_status
88 #pragma weak scstat_strerr
92 * Initialise the library if we have not done so before.
96 * This must -never- be called from any command that can be started
97 * from /usr/cluster/lib/sc/run_reserve (and hence
98 * /usr/cluster/sbin/reconfig) or the system will deadlock
99 * during switchover. This includes:
101 * - svadm (no options, "print") -- called during sv switchover
102 * - all boot commands
104 * - grab this node's cluster nodeid
105 * - attempt to dlopen() the suncluster shared libraries we need
106 * - grab this node's cluster nodename
110 * -1 - error, errno is set
114 cfg_cluster_init(void)
116 const char *scconf
= "/usr/cluster/lib/libscconf.so.1";
117 const char *scstat
= "/usr/cluster/lib/libscstat.so.1";
119 char errbuf
[SCCONF_MAXSTRINGLEN
];
128 * First check to see if we really are a cluster as clinfo -n can lie
130 if (cl_nodeid
== 0xffff) {
131 rc
= system("/usr/sbin/clinfo");
132 if (rc
!= -1 && WEXITSTATUS(rc
) == 1) {
139 pipe
= popen("/usr/sbin/clinfo -n 2>/dev/null || echo 0", "r");
142 fprintf(stderr
, "unable to get nodeid: %s\n",
148 if ((rc
= fscanf(pipe
, "%d", &id
)) != 1) {
150 fprintf(stderr
, "unable to get nodeid: %s\n",
161 /* Already loaded the Sun Cluster device tree */
166 * Try and dlopen the various libraries that we need
169 libscconf
= dlopen(scconf
, RTLD_LAZY
| RTLD_GLOBAL
);
170 if (libscconf
== NULL
)
173 libscstat
= dlopen(scstat
, RTLD_LAZY
| RTLD_GLOBAL
);
174 if (libscstat
== NULL
)
177 err
= scconf_get_nodename(id
, &name
);
178 if (err
== SCCONF_EPERM
) {
180 } else if (err
!= SCCONF_NOERR
) {
182 scconf_strerr(errbuf
, err
);
183 fprintf(stderr
, "scconf_get_nodename: %d: %s\n", err
, errbuf
);
189 /* Load the Sun Cluster device tree */
194 error
: /* error cleanup */
213 * Return the SunCluster nodeid of this node.
216 * >0 - running in a SunCluster (value is nodeid of this node)
217 * 0 - not running in a cluster
218 * -1 - failure; errno is set
224 if (cfg_cluster_init() >= 0)
225 return ((int)cl_nodeid
);
232 return (cfg_issuncluster());
236 * cfg_l_dgname_islocal()
237 * Check if disk group is local on a non-SunCluster.
239 * Returns as cfg_dgname_islocal().
243 cfg_l_dgname_islocal(char *dgname
, char **othernode
)
245 const char *metaset
= "/usr/sbin/metaset -s %s -o > /dev/null 2>&1";
249 if (snprintf(command
, sizeof (command
), metaset
, dgname
) >=
255 rc
= system(command
);
260 if (WEXITSTATUS(rc
) != 0) {
262 /* metaset doesn't tell us */
263 *othernode
= "unknown";
274 * cfg_dgname_islocal(char *dgname, char **othernode)
275 * -- determine if the named disk service is mastered on this node
277 * If the disk service is mastered on another node, that nodename
278 * will be returned in othernode (if not NULL). It is up to the
279 * calling program to call free() on this value at a later time to
280 * free the memory allocated.
283 * 1 - disk service is mastered on this node
284 * 0 - disk service is not mastered on this node (*othernode set)
285 * -1 - error (errno will be set)
289 cfg_dgname_islocal(char *dgname
, char **othernode
)
293 if (dgname
== NULL
|| *dgname
== '\0' || othernode
== NULL
) {
298 /* Handle non-cluster configurations */
299 if (cfg_cluster_init() < 0) {
301 } else if (cl_nodeid
== 0) {
302 /* it has to be local */
307 * lookup the current diskgroup name
309 if (data
= (hash_data_t
*)nsc_lookup(schash
, dgname
)) {
310 if (strcmp(data
->scstat_node_name
, cl_nodename
)) {
312 *othernode
= strdup(data
->scstat_node_name
);
325 * parse the disk group name from the a device pathname on a non-SunCluster.
327 * Returns as cfg_dgname().
331 cfg_l_dgname(const char *pathname
, char *buffer
, size_t buflen
)
333 const char *dev
= "/dev/";
334 const char *vx
= "vx/";
335 const char *md
= "md/";
336 const char *dsk
= "dsk/";
337 const char *start
, *cp
;
340 bzero(buffer
, buflen
);
344 if (strncmp(pathname
, dev
, ll
) != 0) {
345 /* not a device pathname */
347 return ((char *)NULL
);
350 start
= pathname
+ ll
;
352 if (strncmp(start
, vx
, (ll
= strlen(vx
))) == 0) {
355 * /dev/vx/{r}dsk/dgname/partition
362 if (*start
== 'r' && strncmp((start
+ 1), dsk
, ll
) == 0)
364 else if (strncmp(start
, dsk
, ll
) == 0)
375 for (cp
= start
, len
= 0; *cp
!= '\0' && *cp
!= '/'; cp
++)
376 len
++; /* count length of dgname */
386 "cfg_dgname: parse error: *cp = '%c', expected '/'\n", *cp
);
388 return ((char *)NULL
);
393 cp
++; /* skip the NULL */
397 if ((*cp
!= 'r' || strncmp((cp
+ 1), dsk
, ll
) != 0) &&
398 strncmp(cp
, dsk
, ll
) != 0) {
406 return ((char *)NULL
);
409 (void) strncpy(buffer
, start
, len
);
416 * determine which cluster resource group the pathname belongs to, if any
419 * NULL - error (errno is set)
420 * ptr to NULL-string - no dgname
421 * pointer to string - dgname
425 cfg_dgname(const char *pathname
, char *buffer
, size_t buflen
)
427 scconf_errno_t conferr
;
431 char errbuf
[SCCONF_MAXSTRINGLEN
];
434 bzero(buffer
, buflen
);
436 if (pathname
== NULL
|| *pathname
== '\0') {
438 return ((char *)NULL
);
441 /* Handle non-cluster configurations */
442 if (cfg_cluster_init() < 0) {
444 return ((char *)NULL
);
445 } else if (cl_nodeid
== 0) {
446 /* must be local - return NULL-string dgname */
450 if (stat(pathname
, &stb
) < 0) {
452 return ((char *)NULL
);
455 conferr
= scconf_get_ds_by_devt(major(stb
.st_rdev
),
456 minor(stb
.st_rdev
), &dsname
);
458 if (conferr
== SCCONF_ENOEXIST
) {
460 } else if (conferr
!= SCCONF_NOERR
) {
462 scconf_strerr(errbuf
, conferr
);
464 "scconf_get_ds_by_devt: %d: %s\n", conferr
, errbuf
);
467 return ((char *)NULL
);
470 strncpy(buffer
, dsname
, buflen
);
480 * Add an entry into the sclist and the schash for future lookups.
484 * This must -never- be called from any command that can be started
485 * from /usr/cluster/lib/sc/run_reserve (and hence
486 * /usr/cluster/sbin/reconfig) or the system will deadlock
487 * during switchover. This includes:
489 * - svadm (no options, "print") -- called during sv switchover
490 * - all boot commands
493 * -1 An error occurred.
495 * 1 Entry already exists.
500 scstat_ds_node_state_t
*dsn
;
501 scstat_ds_name_t dsname
;
502 scstat_ds_t
*dsstatus
, *dsp
;
505 char errbuf
[SCCONF_MAXSTRINGLEN
];
511 * Allocate a hash table
513 if ((schash
= nsc_create_hash()) == NULL
)
517 * the API is broken here - the function is written to expect
518 * the first argument to be (scstat_ds_name_t), but the function
519 * declaration in scstat.h requires (scstat_ds_name_t *).
521 * We just cast it to get rid of the compiler warnings.
522 * If "dsname" is NULL, information for all device services is returned
526 /* LINTED pointer alignment */
527 err
= scstat_get_ds_status((scstat_ds_name_t
*)dsname
, &dsstatus
);
528 if (err
!= SCSTAT_ENOERR
) {
530 scstat_strerr(err
, errbuf
);
531 fprintf(stderr
, "scstat_get_ds_status(): %d: %s\n",
538 if (dsstatus
== NULL
) {
544 * Traverse scstat_ds list, saving away resource in out hash table
546 for (dsp
= dsstatus
; dsp
; dsp
= dsp
->scstat_ds_next
) {
548 /* Skip over NULL scstat_ds_name's */
549 if ((dsp
->scstat_ds_name
== NULL
) ||
550 (dsp
->scstat_ds_name
[0] == '\0'))
553 /* See element exits already, error if so */
554 if (nsc_lookup(schash
, dsp
->scstat_ds_name
)) {
555 fprintf(stderr
, "scstat_get_ds_status: duplicate %s",
556 dsp
->scstat_ds_name
);
561 /* Traverse the node status list */
562 for (dsn
= dsp
->scstat_node_state_list
; dsn
;
563 dsn
= dsn
->scstat_node_next
) {
565 * Only keep trace of primary nodes
567 if (dsn
->scstat_node_state
!= SCSTAT_PRIMARY
)
570 /* Create an element to insert */
571 hdp
= (hash_data_t
*)malloc(sizeof (hash_data_t
));
572 hdp
->scstat_node_name
= strdup(dsn
->scstat_node_name
);
573 nsc_insert_node(schash
, hdp
, dsp
->scstat_ds_name
);
578 * Free up scstat resources
580 scstat_free_ds_status(dsstatus
);