xref: /titanic_41/usr/src/cmd/avs/sv/svboot.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/mkdev.h>
29 #include <sys/param.h>
30 #include <fcntl.h>
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <locale.h>
37 #include <unistd.h>
38 #include <libgen.h>
39 #include <nsctl.h>
40 
41 #include <sys/unistat/spcs_s.h>
42 #include <sys/unistat/spcs_s_u.h>
43 #include <sys/unistat/spcs_errors.h>
44 
45 #include <sys/nsctl/sv.h>
46 #include <sys/nsctl/sv_impl.h>
47 
48 #include <sys/nsctl/cfg.h>
49 
50 
51 static int sv_max_devices;
52 
53 
54 /*
55  * Pathnames.
56  */
57 
58 static const caddr_t sv_rpath = SV_DEVICE;
59 
60 /*
61  * Functions.
62  */
63 
64 static void resume_dev(int, sv_name_t *);
65 static void suspend_dev(int, const caddr_t);
66 static int read_libcfg(sv_name_t svn[]);
67 static void resume_sv();
68 static void suspend_sv();
69 static void prepare_unload_sv();
70 
71 
72 /*
73  * support for the special cluster tag "local" to be used with -C in a
74  * cluster for local volumes.
75  */
76 
77 #define	SV_LOCAL_TAG	"local"
78 
79 static caddr_t program;
80 static caddr_t cfg_cluster_tag;
81 
82 
83 static void
usage(void)84 usage(void)
85 {
86 	(void) fprintf(stderr, gettext("usage:\n"));
87 
88 	(void) fprintf(stderr, gettext(
89 	    "\t%s -h                     help\n"), program);
90 
91 	(void) fprintf(stderr, gettext(
92 	    "\t%s [-C tag] -r            resume all sv devices\n"), program);
93 
94 	(void) fprintf(stderr, gettext(
95 	    "\t%s [-C tag] -s            suspend all sv devices\n"), program);
96 
97 	(void) fprintf(stderr, gettext(
98 	    "\t%s -u                     prepare for sv unload\n"), program);
99 }
100 
101 
102 static void
message(caddr_t prefix,spcs_s_info_t * status,caddr_t string,va_list ap)103 message(caddr_t prefix, spcs_s_info_t *status, caddr_t string, va_list ap)
104 {
105 	(void) fprintf(stderr, "%s: %s: ", program, prefix);
106 	(void) vfprintf(stderr, string, ap);
107 	(void) fprintf(stderr, "\n");
108 
109 	if (status) {
110 		spcs_s_report(*status, stderr);
111 		spcs_s_ufree(status);
112 	}
113 }
114 
115 
116 static void
error(spcs_s_info_t * status,caddr_t string,...)117 error(spcs_s_info_t *status, caddr_t string, ...)
118 {
119 	va_list ap;
120 	va_start(ap, string);
121 
122 	message(gettext("error"), status, string, ap);
123 
124 	va_end(ap);
125 	exit(1);
126 }
127 
128 
129 static void
warn(spcs_s_info_t * status,caddr_t string,...)130 warn(spcs_s_info_t *status, caddr_t string, ...)
131 {
132 	va_list ap;
133 	va_start(ap, string);
134 
135 	message(gettext("warning"), status, string, ap);
136 
137 	va_end(ap);
138 }
139 
140 
141 static void
sv_get_maxdevs(void)142 sv_get_maxdevs(void)
143 {
144 	sv_name_t svn[1];
145 	sv_list_t svl;
146 	int fd;
147 
148 	if (sv_max_devices > 0)
149 		return;
150 
151 	fd = open(sv_rpath, O_RDONLY);
152 	if (fd < 0)
153 		error(NULL, gettext("unable to open %s: %s"),
154 			sv_rpath, strerror(errno));
155 
156 	bzero(&svl, sizeof (svl));
157 	bzero(&svn[0], sizeof (svn));
158 
159 	svl.svl_names = &svn[0];
160 	svl.svl_error = spcs_s_ucreate();
161 
162 	if (ioctl(fd, SVIOC_LIST, &svl) < 0)
163 		error(&svl.svl_error, gettext("unable to get max devs"));
164 
165 	spcs_s_ufree(&svl.svl_error);
166 	sv_max_devices = svl.svl_maxdevs;
167 
168 	(void) close(fd);
169 }
170 
171 
172 static sv_name_t *
sv_alloc_svnames(void)173 sv_alloc_svnames(void)
174 {
175 	sv_name_t *svn = NULL;
176 
177 	sv_get_maxdevs();
178 
179 	svn = calloc(sv_max_devices, sizeof (*svn));
180 	if (svn == NULL) {
181 		error(NULL, "unable to allocate %ld bytes of memory",
182 		    sv_max_devices * sizeof (*svn));
183 	}
184 
185 	return (svn);
186 }
187 
188 int
main(int argc,char * argv[])189 main(int argc, char *argv[])
190 {
191 	extern int optind;
192 	extern char *optarg;
193 	int Cflag, resume, suspend, unload;
194 	int opt;
195 
196 	(void) setlocale(LC_ALL, "");
197 	(void) textdomain("svboot");
198 
199 	program = strdup(basename(argv[0]));
200 
201 	Cflag = unload = resume = suspend = 0;
202 
203 	while ((opt = getopt(argc, argv, "C:hrsu")) != EOF) {
204 		switch (opt) {
205 
206 		case 'C':
207 			if (Cflag) {
208 				warn(NULL,
209 				    gettext("-C specified multiple times"));
210 				usage();
211 				exit(2);
212 				/* NOTREACHED */
213 			}
214 
215 			Cflag++;
216 			cfg_cluster_tag = optarg;
217 			break;
218 
219 		case 'r':
220 			resume++;
221 			break;
222 
223 		case 's':
224 			suspend++;
225 			break;
226 
227 		case 'u':
228 			unload++;
229 			break;
230 
231 		case 'h':
232 			usage();
233 			exit(0);
234 
235 		case '?':	/* FALLTHRU */
236 
237 		default:
238 			usage();
239 			exit(2);
240 			/* NOTREACHED */
241 		}
242 	}
243 
244 
245 	/*
246 	 * Usage checks
247 	 */
248 
249 	if ((resume + suspend + unload) > 1) {
250 		warn(NULL, gettext("-r , -s and -u are mutually exclusive"));
251 		usage();
252 		exit(2);
253 	}
254 
255 	if (!resume && !suspend && !unload) {
256 		warn(NULL, gettext("option required"));
257 		usage();
258 		exit(2);
259 	}
260 
261 	if (optind != argc) {
262 		usage();
263 		exit(2);
264 	}
265 
266 
267 	/*
268 	 * Check for the special (local) cluster tag
269 	 */
270 
271 	if (cfg_cluster_tag != NULL &&
272 	    strcmp(cfg_cluster_tag, SV_LOCAL_TAG) == 0)
273 		cfg_cluster_tag = "-";
274 
275 	/*
276 	 * Process commands
277 	 */
278 
279 	if (resume)
280 		resume_sv();
281 	else if (suspend)
282 		suspend_sv();
283 	else if (unload)
284 		prepare_unload_sv();
285 
286 	return (0);
287 }
288 
289 
290 static void
resume_sv()291 resume_sv()
292 {
293 	int index;
294 	sv_name_t *svn;
295 	int cnt;
296 	int fd;
297 
298 	svn = sv_alloc_svnames();
299 
300 	index = read_libcfg(svn);
301 
302 	fd = open(sv_rpath, O_RDONLY);
303 	if (fd < 0) {
304 		warn(NULL, gettext("unable to open %s: %s"),
305 			svn->svn_path, strerror(errno));
306 		return;
307 	}
308 
309 	for (cnt = 0; cnt < index; cnt++) {
310 
311 		/*
312 		 * Check for more data.
313 		 */
314 		if (svn[cnt].svn_path[0] == '\0') {
315 			/*
316 			 * This was set when reading sv.conf.  After the last
317 			 * line svn_path was set to \0, so we are finished.
318 			 * We shouldn't get here, but put this in just in
319 			 * case.
320 			 */
321 			break;
322 		}
323 		resume_dev(fd, &svn[cnt]);
324 	}
325 	(void) close(fd);
326 }
327 
328 
329 static void
resume_dev(int fd,sv_name_t * svn)330 resume_dev(int fd, sv_name_t *svn)
331 {
332 	struct stat stb;
333 	sv_conf_t svc;
334 
335 	bzero(&svc, sizeof (svc));
336 
337 	if (stat(svn->svn_path, &stb) != 0) {
338 		warn(NULL, gettext("unable to access %s: %s"),
339 			svn->svn_path, strerror(errno));
340 		return;
341 	}
342 
343 	svc.svc_major = major(stb.st_rdev);
344 	svc.svc_minor = minor(stb.st_rdev);
345 	(void) strncpy(svc.svc_path, svn->svn_path, sizeof (svc.svc_path));
346 
347 	svc.svc_flag = svn->svn_mode;
348 	svc.svc_error = spcs_s_ucreate();
349 
350 	if (ioctl(fd, SVIOC_ENABLE, &svc) < 0) {
351 		spcs_log("sv", &svc.svc_error,
352 		    gettext("%s: unable to resume %s"),
353 		    program, svn->svn_path);
354 
355 		warn(&svc.svc_error, gettext("unable to resume %s"),
356 			svn->svn_path);
357 		return;
358 	}
359 
360 	spcs_log("sv", NULL, gettext("%s: resume %s"),
361 	    program, svn->svn_path);
362 
363 	spcs_s_ufree(&svc.svc_error);
364 }
365 
366 
367 /*
368  * This routine parses the config file and
369  * stores the data in the svn array.  The return value is the number
370  * of entries read from conf_file.  If an error occurs the error()
371  * routine is called (which exits the program).
372  */
373 static int
read_libcfg(sv_name_t svn[])374 read_libcfg(sv_name_t svn[])
375 {
376 	char rdev[CFG_MAX_BUF];
377 	char key[CFG_MAX_KEY];
378 	struct stat stb;
379 	int i;
380 	int setnumber;
381 	int index = 0;		/* Current location in svn array	*/
382 	sv_name_t *cur_svn;	/* Pointer to svn[index]		*/
383 	CFGFILE *cfg;
384 
385 	if ((cfg = cfg_open("")) == NULL) {
386 		error(NULL, gettext("Error opening config: %s"),
387 		    strerror(errno));
388 	}
389 
390 	cfg_resource(cfg, cfg_cluster_tag);
391 	if (!cfg_lock(cfg, CFG_RDLOCK)) {
392 		error(NULL, gettext("Error locking config: %s"),
393 		    strerror(errno));
394 	}
395 
396 	for (i = 0; /*CSTYLED*/; i++) {
397 		setnumber = i + 1;
398 
399 		bzero(rdev, CFG_MAX_BUF);
400 		(void) snprintf(key, sizeof (key), "sv.set%d.vol", setnumber);
401 		if (cfg_get_cstring(cfg, key, rdev, sizeof (rdev)) < 0)
402 			break;
403 
404 		/* Check to see if the raw device is present */
405 		if (stat(rdev, &stb) != 0) {
406 			warn(NULL, gettext("unable to access %s: %s"),
407 			    rdev, strerror(errno));
408 			continue;
409 		}
410 
411 		if (!S_ISCHR(stb.st_mode)) {
412 			warn(NULL, gettext("%s is not a character device"),
413 			    rdev);
414 			continue;
415 		}
416 
417 		cur_svn = &svn[index];  /* For easier reading below */
418 
419 		if (strlen(rdev) >= sizeof (cur_svn->svn_path)) {
420 			warn(NULL, gettext(
421 			    "raw device name (%s) longer than %d characters"),
422 			    rdev,
423 			    (sizeof (cur_svn->svn_path) - 1));
424 			continue;
425 		}
426 
427 		(void) strcpy(cur_svn->svn_path, rdev);
428 		cur_svn->svn_mode = (NSC_DEVICE | NSC_CACHE);
429 
430 		index++;
431 	}
432 
433 	cfg_close(cfg);
434 
435 	/* Set the last path to NULL */
436 	svn[index].svn_path[0] = '\0';
437 
438 	return (index);
439 }
440 
441 
442 static void
suspend_dev(int fd,const caddr_t path)443 suspend_dev(int fd, const caddr_t path)
444 {
445 	struct stat stb;
446 	sv_conf_t svc;
447 
448 	if (stat(path, &stb) < 0) {
449 		svc.svc_major = (major_t)-1;
450 		svc.svc_minor = (minor_t)-1;
451 	} else {
452 		svc.svc_major = major(stb.st_rdev);
453 		svc.svc_minor = minor(stb.st_rdev);
454 	}
455 
456 	(void) strcpy(svc.svc_path, path);
457 	svc.svc_error = spcs_s_ucreate();
458 
459 	if (ioctl(fd, SVIOC_DISABLE, &svc) < 0) {
460 		if (errno != SV_EDISABLED) {
461 			spcs_log("sv", &svc.svc_error,
462 			    gettext("%s: unable to suspend %s"),
463 			    program, path);
464 
465 			warn(&svc.svc_error,
466 				gettext("unable to suspend %s"), path);
467 			return;
468 		}
469 	}
470 
471 	spcs_log("sv", NULL, gettext("%s: suspend %s"), program, path);
472 
473 	spcs_s_ufree(&svc.svc_error);
474 }
475 
476 
477 static void
suspend_sv(void)478 suspend_sv(void)
479 {
480 	sv_name_t *svn, *svn_system;	/* Devices in system */
481 	sv_list_t svl_system;
482 	int i;
483 	int fd;
484 
485 	svn_system = sv_alloc_svnames();
486 
487 	svl_system.svl_count = read_libcfg(svn_system);
488 
489 	if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
490 		warn(NULL, gettext("unable to open %s: %s"),
491 			sv_rpath, strerror(errno));
492 		return;
493 	}
494 
495 	for (i = 0; i < svl_system.svl_count; i++) {
496 		if (*svn_system[i].svn_path == '\0')
497 			break;
498 
499 		svn = &svn_system[i];
500 		suspend_dev(fd, svn->svn_path);
501 	}
502 
503 	(void) close(fd);
504 }
505 
506 
507 /*
508  * Check kernel's sv_ndevices and thread sets,
509  * if empty then change kernel state to allow unload,
510  * and sleep SV_WAIT_UNLAOD (10 seconds).
511  *
512  * Only called in pkgrm time.
513  */
514 static void
prepare_unload_sv(void)515 prepare_unload_sv(void)
516 {
517 	int fd;
518 	int rc = 0;
519 
520 	if ((fd = open(sv_rpath, O_RDONLY)) < 0) {
521 		warn(NULL, gettext("unable to open %s: %s"),
522 			sv_rpath, strerror(errno));
523 		return;
524 	}
525 
526 	if (ioctl(fd, SVIOC_UNLOAD, &rc) < 0)
527 		error(NULL, gettext("unable to unload"));
528 
529 	if (rc != 0)
530 		error(NULL, gettext("still has active devices or threads"));
531 
532 	(void) close(fd);
533 }
534