1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <sys/vfstab.h> 32 #include <meta.h> 33 #include <libsvm.h> 34 #include <svm.h> 35 #include <sdssc.h> 36 37 38 extern int mod_unload(char *modname); 39 static int inited = 0; 40 41 /* 42 * FUNCTION: init_metalib 43 * initialize libmeta only once. 44 * 45 * RETURN VALUES: 46 * 0 - SUCCESS 47 * -1 - FAIL 48 */ 49 50 static int 51 init_metalib() 52 { 53 int largc = 1; 54 char *largv = "libsvm"; 55 md_error_t status = mdnullerror; 56 57 if (!inited) { 58 if (md_init_nosig(largc, &largv, 0, 1, &status) != 0 || 59 meta_check_root(&status) != 0) { 60 return (-1); 61 } 62 inited = 1; 63 } 64 return (RET_SUCCESS); 65 } 66 67 /* 68 * FUNCTION: reset_metalib 69 * 70 * INPUT: ptr to md_error_t 71 */ 72 73 static void 74 reset_metalib(md_error_t *ep) 75 { 76 inited = 0; 77 (void) close_admin(ep); 78 } 79 80 /* 81 * FUNCTION: metahalt 82 * halt the metadb 83 * 84 */ 85 86 static void 87 metahalt() 88 { 89 mdsetname_t *sp; 90 md_error_t status = mdnullerror; 91 92 (void) init_metalib(); 93 if ((sp = metasetname(MD_LOCAL_NAME, &status)) == NULL) { 94 return; 95 } 96 if (meta_lock(sp, TRUE, &status)) { 97 return; 98 } 99 if (metaioctl(MD_HALT, NULL, &status, NULL) != 0) { 100 debug_printf("metahalt(): errno %d\n", 101 status.info.md_error_info_t_u.sys_error.errnum); 102 } 103 (void) meta_unlock(sp, &status); 104 reset_metalib(&status); 105 } 106 107 /* 108 * FUNCTION: svm_stop 109 * Halt the SDS/SVM configuration and unload md module. 110 * 111 * RETURN VALUES: 112 * 0 - SUCCESS 113 * RET_ERROR 114 */ 115 116 #define MAX_TIMEOUT 1800 117 int 118 svm_stop() 119 { 120 int rval = RET_SUCCESS; 121 int timeval = 0; 122 int sleep_int = 5; 123 124 metahalt(); 125 126 if ((rval = mod_unload(MD_MODULE)) != 0) { 127 timeval += sleep_int; 128 (void) sleep(sleep_int); 129 while (timeval < MAX_TIMEOUT) { 130 if ((rval = mod_unload(MD_MODULE)) == 0) { 131 debug_printf("svm_stop(): mod_unload succeeded." 132 " Time %d\n", timeval); 133 134 break; 135 } 136 137 debug_printf("svm_stop(): mod_unload failed. Trying " 138 "in %d s (%d)\n", sleep_int, timeval); 139 140 timeval += sleep_int; 141 (void) sleep(sleep_int); 142 metahalt(); 143 } 144 145 if (rval != 0) { 146 rval = RET_ERROR; 147 debug_printf("svm_stop(): mod_unload FAILED!\n"); 148 } 149 } 150 151 return (rval); 152 } 153 154 /* 155 * FUNCTION: get_rootmetadevice 156 * parses the vfstab to return the metadevice 157 * 158 * INPUT: 159 * mount point 160 * mdname - pointer to string pointer that will contain the 161 * metadevice name. Caller must free the allocated space. 162 * RETURN VALUES: 163 * mdname - md root device name 164 * 0 - SUCCESS 165 * !0 - FAIL 166 * > 0 errno 167 * RET_ERROR 168 */ 169 170 int 171 get_rootmetadevice(char *mntpath, char **mdname) 172 { 173 struct vfstab v; 174 FILE *fp; 175 int rval = RET_SUCCESS; 176 char *cp; 177 char vfstab_name[PATH_MAX + 1]; 178 179 if (mdname == NULL) 180 return (EINVAL); 181 182 *mdname = NULL; 183 184 if (snprintf(vfstab_name, PATH_MAX + 1, "%s%s", mntpath, VFSTAB) < 0) 185 return (ENOMEM); 186 187 debug_printf("get_rootmetadevice(): mntpath %s %s\n", mntpath, 188 vfstab_name); 189 190 if ((fp = fopen(vfstab_name, "r")) == NULL) { 191 rval = errno; 192 return (rval); 193 } 194 195 if ((rval = getvfsfile(fp, &v, ROOT_MNTPT)) != 0) { 196 goto out; 197 } 198 199 200 debug_printf("get_rootmetadevice(): vfs_special %s\n", v.vfs_special); 201 if (strstr(v.vfs_special, ROOT_METADEVICE) == NULL) { 202 /* md device not found */ 203 rval = RET_ERROR; 204 goto out; 205 } 206 207 /* found a match fill it and return */ 208 cp = v.vfs_special + strlen(ROOT_METADEVICE); 209 210 *mdname = (char *)malloc(strlen(cp) + 1); 211 212 if (*mdname == NULL) { 213 rval = ENOMEM; 214 goto out; 215 } 216 (void) strcpy(*mdname, cp); 217 debug_printf("get_rootmetadevice(): *mdname %s rval %d\n", 218 *mdname, rval); 219 out: 220 (void) fclose(fp); 221 return (rval); 222 } 223 224 /* 225 * FUNCTION: create_diskset_links 226 * Create the diskset name symlinks in /dev/md from the diskset 227 * names found in the set records. These are normally created 228 * in rpc.metad when you create the set but those symlinks are 229 * sitting out on the real system disk and we're running off the 230 * devfs that got created when we booted off the install image. 231 */ 232 233 void 234 create_diskset_links() 235 { 236 int max_sets; 237 int i; 238 md_error_t error = mdnullerror; 239 240 /* 241 * Resolve the function pointers for libsds_sc so that we can 242 * snarf the set records. 243 */ 244 (void) sdssc_bind_library(); 245 (void) init_metalib(); 246 247 if ((max_sets = get_max_sets(&error)) == 0) { 248 debug_printf("create_diskset_links(): get_max_sets failed\n"); 249 mdclrerror(&error); 250 return; 251 } 252 253 for (i = 1; i < max_sets; i++) { 254 md_set_record *sr; 255 char setname[MAXPATHLEN]; 256 char setnum[MAXPATHLEN]; 257 258 if ((sr = metad_getsetbynum(i, &error)) == NULL) { 259 mdclrerror(&error); 260 continue; 261 } 262 263 (void) snprintf(setname, MAXPATHLEN, "/dev/md/%s", 264 sr->sr_setname); 265 (void) snprintf(setnum, MAXPATHLEN, "shared/%d", i); 266 /* 267 * Ignore failures to create the symlink. This could 268 * happen because suninstall is restartable so the 269 * symlink might have already been created. 270 */ 271 (void) symlink(setnum, setname); 272 } 273 } 274 275 /* 276 * FUNCTION: svm_alloc 277 * Return a pointer to an opaque piece of zeroed memory. 278 * 279 * RETURN VALUES: 280 * Non null - SUCCESS 281 * NULL - FAIL 282 */ 283 284 svm_info_t * 285 svm_alloc() 286 { 287 return ((svm_info_t *)calloc(1, sizeof (svm_info_t))); 288 } 289 290 /* 291 * FUNCTION: svm_free 292 * 293 * INPUT: pointer to struct svm_info 294 */ 295 296 void 297 svm_free(svm_info_t *svmp) 298 { 299 int i; 300 301 if (svmp == NULL) 302 return; 303 304 for (i = 0; i < svmp->count; i++) { 305 free(svmp->md_comps[i]); 306 } 307 free(svmp->root_md); 308 free(svmp); 309 } 310 311 /* 312 * FUNCTION: get_mdcomponents 313 * Given "uname" metadevice, return the physical components 314 * of that metadevice. 315 * 316 * INPUT: 317 * uname - metadevice name 318 * 319 * RETURN VALUES: 320 * svmp - structure containing md name and components 321 * RET_SUCCESS 322 * RET_ERROR 323 * 324 */ 325 326 int 327 get_mdcomponents(char *uname, svm_info_t **svmpp) 328 { 329 330 svm_info_t *svmp; 331 md_error_t status, *ep; 332 mdname_t *namep; 333 mdnamelist_t *nlp = NULL; 334 mdnamelist_t *p; 335 mdsetname_t *sp = NULL; 336 char *strp = NULL; 337 int rval, cnt; 338 339 rval = RET_SUCCESS; 340 cnt = 0; 341 status = mdnullerror; 342 ep = &status; 343 svmp = *svmpp; 344 345 (void) init_metalib(); 346 347 debug_printf("get_mdcomponents(): Enter unit name %s\n", uname); 348 349 if (((namep = metaname(&sp, uname, ep)) == NULL) || 350 (metachkmeta(namep, ep) != 0)) { 351 debug_printf("get_mdcomponents(): " 352 "metaname or metachkmeta failed\n"); 353 mdclrerror(ep); 354 return (RET_ERROR); 355 } 356 357 debug_printf("get_mdcomponents(): meta_getdevs %s\n", namep->cname); 358 359 if ((meta_getdevs(sp, namep, &nlp, ep)) < 0) { 360 debug_printf("get_mdcomponents(): " 361 "comp %s - meta_getdevs failed\n", uname); 362 metafreenamelist(nlp); 363 mdclrerror(ep); 364 return (RET_ERROR); 365 } 366 367 /* compute the number of devices */ 368 369 for (p = nlp, cnt = 0; p != NULL; p = p->next, cnt++) 370 ; 371 372 /* 373 * Need to add n -1 components since slvmp already has space 374 * for one device. 375 */ 376 377 svmp = (svm_info_t *)realloc(svmp, sizeof (svm_info_t) + 378 (sizeof (char *) * (cnt - 1))); 379 380 if (svmp == NULL) { 381 debug_printf("get_mdcomponents(): realloc of svmp failed\n"); 382 metafreenamelist(nlp); 383 return (RET_ERROR); 384 } 385 386 387 for (p = nlp, cnt = 0; p != NULL; p = p->next, cnt++) { 388 mdname_t *devnp = p->namep; 389 390 if ((strp = strdup(devnp->cname)) == NULL) { 391 rval = RET_ERROR; 392 break; 393 } 394 svmp->md_comps[cnt] = strp; 395 } 396 397 /* count is set to the number of devices in the list */ 398 399 svmp->count = cnt; 400 svmp->root_md = strdup(uname); 401 if (rval == RET_SUCCESS && svmp->root_md != NULL) { 402 debug_printf("get_mdcomponents(): root_md %s count %d \n", 403 svmp->root_md, svmp->count); 404 for (cnt = 0; cnt < svmp->count; cnt++) 405 debug_printf("get_mdcomponents(): %s\n", 406 svmp->md_comps[cnt]); 407 } else { 408 rval = RET_ERROR; 409 svm_free(svmp); 410 svmp = NULL; 411 debug_printf("get_mdcomponents(): malloc failed\n"); 412 413 } 414 415 416 metafreenamelist(nlp); 417 *svmpp = svmp; 418 return (rval); 419 } 420 421 422 /* 423 * FUNCTION: svm_get_components 424 * return svm_infop with the components of a metadevice. 425 * 426 * INPUT: 427 * md_device - eg. /dev/md/dsk/d10, /dev/md/foo/dsk/d10, or 428 * /dev/md/shared/1/dsk/d10 429 * 430 * RETURN: 431 * 0 - SUCCESS 432 * !0 - FAIL 433 */ 434 435 int 436 svm_get_components(char *md_device, svm_info_t **svmpp) 437 { 438 int len; 439 440 /* 441 * If this is a named diskset with a shared name 442 * (e.g. /dev/md/shared/1/dsk/d10) call get_mdcomponents with 443 * the diskset and metadevice name (e.g. foo/d10). 444 * Otherwise this is a regular name (e.g. /dev/md/dsk/d10 or 445 * /dev/md/foo/dsk/d10 or d10 or foo/d10) all of which 446 * get_mdcomponents can handle directly. 447 */ 448 449 len = strlen("/dev/md/shared/"); 450 if (strncmp(md_device, "/dev/md/shared/", len) == 0) { 451 int numlen; 452 int setnum; 453 char *cp; 454 char *slashp; 455 char mdname[MAXPATHLEN]; 456 mdsetname_t *sp; 457 md_error_t error = mdnullerror; 458 459 cp = md_device + len; 460 461 if ((slashp = strstr(cp, "/")) == NULL) 462 return (RET_ERROR); 463 numlen = slashp - cp; 464 if (numlen >= MAXPATHLEN - 1) 465 return (RET_ERROR); 466 467 (void) strlcpy(mdname, cp, numlen + 1); 468 /* setnum now contains the diskset number */ 469 setnum = atoi(mdname); 470 if ((sp = metasetnosetname(setnum, &error)) == NULL || 471 !mdisok(&error)) 472 return (RET_ERROR); 473 474 cp = slashp + 1; 475 /* cp now pointing at dsk/... */ 476 if ((slashp = strstr(cp, "/")) == NULL) 477 return (RET_ERROR); 478 479 (void) snprintf(mdname, MAXPATHLEN, "%s/%s", sp->setname, 480 slashp + 1); 481 /* mdname now contains diskset and metadevice name e.g. foo/d10 */ 482 483 debug_printf("svm_get_components(): mdname %s\n", mdname); 484 return (get_mdcomponents(mdname, svmpp)); 485 486 } else { 487 debug_printf("svm_get_components(): md_device %s\n", md_device); 488 return (get_mdcomponents(md_device, svmpp)); 489 } 490 } 491