xref: /titanic_41/usr/src/lib/lvm/libsvm/common/metainterfaces.c (revision 37714ae43602c675f9dc59b070bfdf9fa702872c)
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