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