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 /*
29 * Just in case we're not in a build environment, make sure that
30 * TEXT_DOMAIN gets set to something.
31 */
32 #if !defined(TEXT_DOMAIN)
33 #define TEXT_DOMAIN "SYS_TEST"
34 #endif
35
36 /*
37 * hotspares utilities
38 */
39
40 #include <meta.h>
41 #include <sys/lvm/md_hotspares.h>
42 #include <sys/lvm/md_convert.h>
43
44 /*
45 * FUNCTION: meta_get_hsp_names()
46 * INPUT: sp - the set name to get hotspares from
47 * options - options from the command line
48 * OUTPUT: hspnlpp - list of all hotspare names
49 * ep - return error pointer
50 * RETURNS: int - -1 if error, 0 success
51 * PURPOSE: returns a list of all hotspares in the metadb
52 * for all devices in the specified set
53 */
54 /*ARGSUSED*/
55 int
meta_get_hsp_names(mdsetname_t * sp,mdhspnamelist_t ** hspnlpp,int options,md_error_t * ep)56 meta_get_hsp_names(
57 mdsetname_t *sp,
58 mdhspnamelist_t **hspnlpp,
59 int options,
60 md_error_t *ep
61 )
62 {
63 md_i_getnum_t gn; /* MD_IOCGET_NUM params */
64 minor_t *minors = NULL;
65 minor_t *m_ptr;
66 int i;
67
68 /* we must have a set */
69 assert(sp != NULL);
70
71 (void) memset(&gn, 0, sizeof (gn));
72 MD_SETDRIVERNAME(&gn, MD_HOTSPARES, sp->setno);
73
74 /* get number of devices */
75 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
76 if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
77 mdclrerror(&gn.mde);
78 } else {
79 (void) mdstealerror(ep, &gn.mde);
80 return (-1);
81 }
82 }
83
84 if (gn.size > 0) {
85 /* malloc minor number buffer to be filled by ioctl */
86 if ((minors = (minor_t *)malloc(
87 gn.size * sizeof (minor_t))) == 0) {
88 return (ENOMEM);
89 }
90 gn.minors = (uintptr_t)minors;
91 if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
92 (void) mdstealerror(ep, &gn.mde);
93 free(minors);
94 return (-1);
95 }
96 m_ptr = minors;
97 for (i = 0; i < gn.size; i++) {
98 mdhspname_t *hspnp;
99
100
101 /* get name */
102 if ((hspnp = metahsphspname(&sp, *m_ptr, ep))
103 == NULL)
104 goto out;
105
106 /* append to list */
107 (void) metahspnamelist_append(hspnlpp, hspnp);
108
109 /* next device */
110 m_ptr++;
111 }
112 free(minors);
113 }
114 return (gn.size);
115
116 out:
117 if (minors != NULL)
118 free(minors);
119 metafreehspnamelist(*hspnlpp);
120 *hspnlpp = NULL;
121 return (-1);
122 }
123
124 /*
125 * get information of a specific hotspare pool from driver
126 */
127 static get_hsp_t *
get_hspinfo(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)128 get_hspinfo(
129 mdsetname_t *sp,
130 mdhspname_t *hspnp,
131 md_error_t *ep
132 )
133 {
134 md_i_get_t mig;
135
136 /* should have a set */
137 assert(sp != NULL);
138 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
139
140 /* get size of unit structure */
141 (void) memset(&mig, 0, sizeof (mig));
142 MD_SETDRIVERNAME(&mig, MD_HOTSPARES, sp->setno);
143 mig.id = hspnp->hsp;
144 if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
145 (void) mdstealerror(ep, &mig.mde);
146 return (NULL);
147 }
148
149 /* get actual unit structure */
150 assert(mig.size > 0);
151 mig.mdp = (uintptr_t)Zalloc(mig.size);
152 if (metaioctl(MD_IOCGET, &mig, &mig.mde, hspnp->hspname) != 0) {
153 (void) mdstealerror(ep, &mig.mde);
154 Free((void *)(uintptr_t)mig.mdp);
155 return (NULL);
156 }
157 return ((get_hsp_t *)(uintptr_t)mig.mdp);
158 }
159
160 /*
161 * free hotspare pool unit
162 */
163 void
meta_free_hsp(md_hsp_t * hspp)164 meta_free_hsp(
165 md_hsp_t *hspp
166 )
167 {
168 if (hspp->hotspares.hotspares_val != NULL) {
169 assert(hspp->hotspares.hotspares_len > 0);
170 Free(hspp->hotspares.hotspares_val);
171 }
172 Free(hspp);
173 }
174
175 /*
176 * get hotspare pool unit (common)
177 */
178 md_hsp_t *
meta_get_hsp_common(mdsetname_t * sp,mdhspname_t * hspnp,int fast,md_error_t * ep)179 meta_get_hsp_common(
180 mdsetname_t *sp,
181 mdhspname_t *hspnp,
182 int fast,
183 md_error_t *ep
184 )
185 {
186 get_hsp_t *ghsp;
187 md_hsp_t *hspp;
188 uint_t hsi;
189
190 /* must have set */
191 assert(sp != NULL);
192 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
193
194 /* short circuit */
195 if (hspnp->unitp != NULL)
196 return (hspnp->unitp);
197
198 /* get unit */
199 if ((ghsp = get_hspinfo(sp, hspnp, ep)) == NULL)
200 return (NULL);
201
202 /* allocate hsp */
203 hspp = Zalloc(sizeof (*hspp));
204
205 /* allocate hotspares */
206 hspp->hotspares.hotspares_len = ghsp->ghsp_nhotspares;
207
208 /* if empty hotspare pool, we are done */
209 if (hspp->hotspares.hotspares_len != 0)
210 hspp->hotspares.hotspares_val =
211 Zalloc(hspp->hotspares.hotspares_len *
212 sizeof (*hspp->hotspares.hotspares_val));
213
214 /* get name, refcount */
215 hspp->hspnamep = hspnp;
216 hspp->refcount = ghsp->ghsp_refcount;
217
218 /* get hotspares */
219 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
220 mdkey_t hs_key = ghsp->ghsp_hs_keys[hsi];
221 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
222 get_hs_params_t ghs;
223
224 /* get hotspare name */
225 hsp->hsnamep = metakeyname(&sp, hs_key, fast, ep);
226 if (hsp->hsnamep == NULL)
227 goto out;
228
229 /* get hotspare state */
230 (void) memset(&ghs, 0, sizeof (ghs));
231 MD_SETDRIVERNAME(&ghs, MD_HOTSPARES, sp->setno);
232 ghs.ghs_key = hs_key;
233 if (metaioctl(MD_IOCGET_HS, &ghs, &ghs.mde, NULL) != 0) {
234 (void) mdstealerror(ep, &ghs.mde);
235 goto out;
236 }
237 hsp->state = ghs.ghs_state;
238 hsp->size = ghs.ghs_number_blks;
239 hsp->timestamp = ghs.ghs_timestamp;
240 hsp->revision = ghs.ghs_revision;
241 }
242
243 /* cleanup, return success */
244 Free(ghsp);
245 hspnp->unitp = hspp;
246 return (hspp);
247
248 /* cleanup, return error */
249 out:
250 Free(ghsp);
251 meta_free_hsp(hspp);
252 return (NULL);
253 }
254
255 /*
256 * get hotspare pool unit
257 */
258 md_hsp_t *
meta_get_hsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)259 meta_get_hsp(
260 mdsetname_t *sp,
261 mdhspname_t *hspnp,
262 md_error_t *ep
263 )
264 {
265 return (meta_get_hsp_common(sp, hspnp, 0, ep));
266 }
267
268 /*
269 * check hotspare pool for dev
270 */
271 static int
in_hsp(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)272 in_hsp(
273 mdsetname_t *sp,
274 mdhspname_t *hspnp,
275 mdname_t *np,
276 diskaddr_t slblk,
277 diskaddr_t nblks,
278 md_error_t *ep
279 )
280 {
281 md_hsp_t *hspp;
282 uint_t i;
283
284 /* should be in the same set */
285 assert(sp != NULL);
286 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
287
288 /* get unit */
289 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
290 return (-1);
291
292 /* look in hotspares */
293 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
294 md_hs_t *hs = &hspp->hotspares.hotspares_val[i];
295 mdname_t *hsnp = hs->hsnamep;
296
297 /* check overlap */
298 if (metaismeta(hsnp))
299 continue;
300 if (meta_check_overlap(hspnp->hspname, np, slblk, nblks,
301 hsnp, 0, -1, ep) != 0)
302 return (-1);
303 }
304
305 /* return success */
306 return (0);
307 }
308
309 /*
310 * check to see if we're in a hotspare pool
311 */
312 int
meta_check_inhsp(mdsetname_t * sp,mdname_t * np,diskaddr_t slblk,diskaddr_t nblks,md_error_t * ep)313 meta_check_inhsp(
314 mdsetname_t *sp,
315 mdname_t *np,
316 diskaddr_t slblk,
317 diskaddr_t nblks,
318 md_error_t *ep
319 )
320 {
321 mdhspnamelist_t *hspnlp = NULL;
322 mdhspnamelist_t *p;
323 int rval = 0;
324
325 /* should have a set */
326 assert(sp != NULL);
327
328 /* for each hotspare pool */
329 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
330 return (-1);
331 for (p = hspnlp; (p != NULL); p = p->next) {
332 mdhspname_t *hspnp = p->hspnamep;
333
334 /* check hotspare pool */
335 if (in_hsp(sp, hspnp, np, slblk, nblks, ep) != 0) {
336 rval = -1;
337 break;
338 }
339 }
340
341 /* cleanup, return success */
342 metafreehspnamelist(hspnlp);
343 return (rval);
344 }
345
346 /*
347 * check hotspare
348 */
349 int
meta_check_hotspare(mdsetname_t * sp,mdname_t * np,md_error_t * ep)350 meta_check_hotspare(
351 mdsetname_t *sp,
352 mdname_t *np,
353 md_error_t *ep
354 )
355 {
356 mdchkopts_t options = (MDCHK_ALLOW_HS);
357
358 /* make sure we have a disk */
359 if (metachkcomp(np, ep) != 0)
360 return (-1);
361
362 /* check to ensure that it is not already in use */
363 if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
364 return (-1);
365 }
366
367 /* make sure it is in the set */
368 if (meta_check_inset(sp, np, ep) != 0)
369 return (-1);
370
371 /* make sure its not in a metadevice */
372 if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
373 return (-1);
374
375 /* return success */
376 return (0);
377 }
378
379 /*
380 * print hsp
381 */
382 static int
hsp_print(md_hsp_t * hspp,char * fname,FILE * fp,md_error_t * ep)383 hsp_print(
384 md_hsp_t *hspp,
385 char *fname,
386 FILE *fp,
387 md_error_t *ep
388 )
389 {
390 uint_t hsi;
391 int rval = -1;
392
393 /* print name */
394 if (fprintf(fp, "%s", hspp->hspnamep->hspname) == EOF)
395 goto out;
396
397 /* print hotspares */
398 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
399 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
400
401 /* print hotspare */
402 /*
403 * If the path is our standard /dev/rdsk or /dev/md/rdsk
404 * then just print out the cxtxdxsx or the dx, metainit
405 * will assume the default, otherwise we need the full
406 * pathname to make sure this works as we intend.
407 */
408 if ((strstr(hsp->hsnamep->rname, "/dev/rdsk") == NULL) &&
409 (strstr(hsp->hsnamep->rname, "/dev/md/rdsk") == NULL) &&
410 (strstr(hsp->hsnamep->rname, "/dev/td/") == NULL)) {
411 /* not standard path, print full pathname */
412 if (fprintf(fp, " %s", hsp->hsnamep->rname) == EOF)
413 goto out;
414 } else {
415 /* standard path, just print ctd or d value */
416 if (fprintf(fp, " %s", hsp->hsnamep->cname) == EOF)
417 goto out;
418 }
419 }
420
421 /* terminate last line */
422 if (fprintf(fp, "\n") == EOF)
423 goto out;
424
425 /* success */
426 rval = 0;
427
428 /* cleanup, return error */
429 out:
430 if (rval != 0)
431 (void) mdsyserror(ep, errno, fname);
432 return (rval);
433 }
434
435 /*
436 * hotspare state name
437 */
438 char *
hs_state_to_name(md_hs_t * hsp,md_timeval32_t * tvp)439 hs_state_to_name(
440 md_hs_t *hsp,
441 md_timeval32_t *tvp
442 )
443 {
444 hotspare_states_t state = hsp->state;
445
446 /* grab time */
447 if (tvp != NULL)
448 *tvp = hsp->timestamp;
449
450 switch (state) {
451 case HSS_AVAILABLE:
452 return (dgettext(TEXT_DOMAIN, "Available"));
453 case HSS_RESERVED:
454 return (dgettext(TEXT_DOMAIN, "In use"));
455 case HSS_BROKEN:
456 return (dgettext(TEXT_DOMAIN, "Broken"));
457 case HSS_UNUSED:
458 default:
459 return (dgettext(TEXT_DOMAIN, "invalid"));
460 }
461 }
462
463 /*
464 * report hsp
465 */
466 static int
hsp_report(md_hsp_t * hspp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep,mdsetname_t * sp)467 hsp_report(
468 md_hsp_t *hspp,
469 mdnamelist_t **nlpp,
470 char *fname,
471 FILE *fp,
472 mdprtopts_t options,
473 md_error_t *ep,
474 mdsetname_t *sp
475 )
476 {
477 uint_t hsi;
478 int rval = -1;
479 char *devid = "";
480 mdname_t *didnp = NULL;
481 uint_t len;
482 int large_hs_dev_cnt = 0;
483 int fn_hs_dev_cnt = 0;
484
485 if (options & PRINT_LARGEDEVICES) {
486 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
487 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
488 if (hsp->revision & MD_64BIT_META_DEV) {
489 large_hs_dev_cnt += 1;
490 if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
491 != 0)
492 goto out;
493 }
494 }
495
496 if (large_hs_dev_cnt == 0) {
497 rval = 0;
498 goto out;
499 }
500 }
501
502 if (options & PRINT_FN) {
503 if (!HSP_ID_IS_FN(hspp->hspnamep->hsp)) {
504 rval = 0;
505 goto out;
506 }
507 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
508 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
509 fn_hs_dev_cnt += 1;
510 if (meta_getdevs(sp, hsp->hsnamep, nlpp, ep)
511 != 0)
512 goto out;
513 }
514 }
515
516 /* print header */
517 if (hspp->hotspares.hotspares_len == 0) {
518 if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: is empty\n"),
519 hspp->hspnamep->hspname) == EOF) {
520 goto out;
521 }
522 } else if (hspp->hotspares.hotspares_len == 1) {
523
524 /*
525 * This allows the length
526 * of the ctd to vary from small to large without
527 * looking horrible.
528 */
529
530 len = strlen(hspp->hotspares.hotspares_val[0].hsnamep->cname);
531 /*
532 * if the length is to short to print out all of the header
533 * force the matter
534 */
535 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
536 len += 2;
537 if (options & PRINT_LARGEDEVICES) {
538 if (fprintf(fp,
539 "%s: 1 hot spare (1 big device)\n\t%-*.*s "
540 "%-12.12s%-8.6s\t\t%s\n",
541 hspp->hspnamep->hspname, len, len,
542 dgettext(TEXT_DOMAIN, "Device"),
543 dgettext(TEXT_DOMAIN, "Status"),
544 dgettext(TEXT_DOMAIN, "Length"),
545 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
546 goto out;
547 }
548 } else {
549 if (fprintf(fp,
550 "%s: 1 hot spare\n\t%-*.*s %-12.12s%-8.6s\t\t%s\n",
551 hspp->hspnamep->hspname, len, len,
552 dgettext(TEXT_DOMAIN, "Device"),
553 dgettext(TEXT_DOMAIN, "Status"),
554 dgettext(TEXT_DOMAIN, "Length"),
555 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
556 goto out;
557 }
558 }
559 } else {
560 /*
561 * This allows the length
562 * of the ctd to vary from small to large without
563 * looking horrible.
564 */
565 len = 0;
566 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
567 len = max(len, strlen(hspp->
568 hotspares.hotspares_val[hsi].hsnamep->cname));
569 }
570 len = max(len, strlen(dgettext(TEXT_DOMAIN, "Device")));
571 len += 2;
572 if (options & PRINT_LARGEDEVICES) {
573 if (fprintf(fp,
574 "%s: %u hot spares (%d big device(s))\n\t%-*.*s "
575 "%-12.12s%-8.6s\t\t%s\n",
576 hspp->hspnamep->hspname,
577 hspp->hotspares.hotspares_len,
578 large_hs_dev_cnt, len, len,
579 dgettext(TEXT_DOMAIN, "Device"),
580 dgettext(TEXT_DOMAIN, "Status"),
581 dgettext(TEXT_DOMAIN, "Length"),
582 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
583 goto out;
584 }
585 } else {
586 if (fprintf(fp, "%s: %u hot spares\n\t%-*.*s "
587 "%-12.12s%-8.6s\t\t%s\n",
588 hspp->hspnamep->hspname,
589 hspp->hotspares.hotspares_len, len, len,
590 dgettext(TEXT_DOMAIN, "Device"),
591 dgettext(TEXT_DOMAIN, "Status"),
592 dgettext(TEXT_DOMAIN, "Length"),
593 dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
594 goto out;
595 }
596 }
597 }
598
599 /* print hotspares */
600 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
601 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
602 char *cname = hsp->hsnamep->cname;
603 char *hs_state;
604 md_timeval32_t tv;
605 char *timep;
606 ddi_devid_t dtp;
607
608 /* populate the key in the name_p structure */
609 if ((didnp = metadevname(&sp, hsp->hsnamep->dev, ep)) == NULL) {
610 return (-1);
611 }
612
613 if (options & PRINT_LARGEDEVICES) {
614 if ((hsp->revision & MD_64BIT_META_DEV) == 0)
615 continue;
616 }
617 /* determine if devid does NOT exist */
618 if (options & PRINT_DEVID) {
619 if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
620 didnp->key, ep)) == NULL)
621 devid = dgettext(TEXT_DOMAIN, "No ");
622 else {
623 devid = dgettext(TEXT_DOMAIN, "Yes");
624 free(dtp);
625 }
626 }
627 /* print hotspare */
628 hs_state = hs_state_to_name(hsp, &tv);
629 /*
630 * This allows the length
631 * of the ctd to vary from small to large without
632 * looking horrible.
633 */
634 if (! (options & PRINT_TIMES)) {
635 if (fprintf(fp,
636 " %-*s %-12s %lld blocks\t%s\n",
637 len, cname, hs_state,
638 hsp->size, devid) == EOF) {
639 goto out;
640 }
641 } else {
642 timep = meta_print_time(&tv);
643
644 if (fprintf(fp,
645 " %-*s\t %-11s %8lld blocks%s\t%s\n",
646 len, cname, hs_state,
647 hsp->size, devid, timep) == EOF) {
648 goto out;
649 }
650 }
651 }
652
653 /* add extra line */
654 if (fprintf(fp, "\n") == EOF)
655 goto out;
656
657 /* success */
658 rval = 0;
659
660 /* cleanup, return error */
661 out:
662 if (rval != 0)
663 (void) mdsyserror(ep, errno, fname);
664 return (rval);
665 }
666
667 /*
668 * print/report hsp
669 */
670 int
meta_hsp_print(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)671 meta_hsp_print(
672 mdsetname_t *sp,
673 mdhspname_t *hspnp,
674 mdnamelist_t **nlpp,
675 char *fname,
676 FILE *fp,
677 mdprtopts_t options,
678 md_error_t *ep
679 )
680 {
681 md_hsp_t *hspp;
682
683 /* should have same set */
684 assert(sp != NULL);
685 assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
686 sp->setno == HSP_SET(hspnp->hsp));
687
688 /* print all hsps */
689 if (hspnp == NULL) {
690 mdhspnamelist_t *hspnlp = NULL;
691 mdhspnamelist_t *p;
692 int cnt;
693 int rval = 0;
694
695 if ((cnt = meta_get_hsp_names(sp, &hspnlp, options, ep)) < 0)
696 return (-1);
697 else if (cnt == 0)
698 return (0);
699
700 /* recurse */
701 for (p = hspnlp; (p != NULL); p = p->next) {
702 mdhspname_t *hspnp = p->hspnamep;
703
704 if (meta_hsp_print(sp, hspnp, nlpp, fname, fp,
705 options, ep) != 0)
706 rval = -1;
707 }
708
709 /* cleanup, return success */
710 metafreehspnamelist(hspnlp);
711 return (rval);
712 }
713
714 /* get unit structure */
715 if ((hspp = meta_get_hsp_common(sp, hspnp,
716 ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
717 return (-1);
718
719 /* print appropriate detail */
720 if (options & PRINT_SHORT)
721 return (hsp_print(hspp, fname, fp, ep));
722 else
723 return (hsp_report(hspp, nlpp, fname, fp, options, ep, sp));
724 }
725
726 /*
727 * check for valid hotspare pool
728 */
729 int
metachkhsp(mdsetname_t * sp,mdhspname_t * hspnp,md_error_t * ep)730 metachkhsp(
731 mdsetname_t *sp,
732 mdhspname_t *hspnp,
733 md_error_t *ep
734 )
735 {
736 if (meta_get_hsp(sp, hspnp, ep) == NULL)
737 return (-1);
738 return (0);
739 }
740
741 /*
742 * invalidate hotspare pool info
743 */
744 void
meta_invalidate_hsp(mdhspname_t * hspnp)745 meta_invalidate_hsp(
746 mdhspname_t *hspnp
747 )
748 {
749 md_hsp_t *hspp = hspnp->unitp;
750
751 /* free it up */
752 if (hspp == NULL)
753 return;
754 meta_free_hsp(hspp);
755
756 /* clear cache */
757 hspnp->unitp = NULL;
758 }
759
760 /*
761 * FUNCTION: del_hsp_name_mn_sides()
762 * INPUT: sp - set name
763 * curside - side of this node
764 * key - key of records to delete
765 * OUTPUT: ep - error information
766 * RETURNS: none.
767 * PURPOSE: There are name records for each side in a set. This
768 * function deletes the records associated with the specified
769 * key for all sides except curside. This function is used
770 * when the set is a multinode set.
771 */
772 static void
del_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)773 del_hsp_name_mn_sides(
774 mdsetname_t *sp,
775 md_set_desc *sd,
776 side_t curside,
777 mdkey_t key,
778 md_error_t *ep
779 )
780 {
781 md_error_t first_error = MDNULLERROR;
782 int error_seen = FALSE;
783 md_mnnode_desc *nd;
784
785 for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
786 if (nd->nd_nodeid == curside)
787 continue;
788 if (del_name(sp, nd->nd_nodeid, key, &first_error) == -1) {
789 if (error_seen == FALSE) {
790 error_seen = TRUE;
791 (void) mdstealerror(ep, &first_error);
792 }
793 }
794 }
795 }
796
797 /*
798 * FUNCTION: del_hsp_name_trad_sides()
799 * INPUT: sp - set name
800 * curside - side of this node
801 * key - key of records to delete
802 * OUTPUT: ep - error information
803 * RETURNS: none.
804 * PURPOSE: There are name records for each side in a set. This
805 * function deletes the records associated with the specified
806 * key for all sides except curside. This function is used
807 * when the set is a traditional set.
808 */
809 static void
del_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,md_error_t * ep)810 del_hsp_name_trad_sides(
811 mdsetname_t *sp,
812 md_set_desc *sd,
813 side_t curside,
814 mdkey_t key,
815 md_error_t *ep
816 )
817 {
818 int error_seen = FALSE;
819 md_error_t first_error = MDNULLERROR;
820 int i;
821
822 for (i = 0; i < MD_MAXSIDES; i++) {
823 if (i == curside)
824 continue;
825 if (sd->sd_nodes[i][0] != '\0') {
826 if (del_name(sp, i, key, &first_error) == -1) {
827 if (error_seen == FALSE) {
828 error_seen = TRUE;
829 (void) mdstealerror(ep, &first_error);
830 }
831 }
832 }
833 }
834 }
835
836 /*
837 * FUNCTION: del_hsp_keys()
838 * INPUT: sp - set name
839 * hspid - ID of records to delete
840 * OUTPUT: ep - error information
841 * RETURNS: 0 - success
842 * -1 - error
843 * PURPOSE: Remove the NM records associated with hspid from all sides
844 * of the set. Missing records are not considered to be an
845 * error. The key associated with the current side is removed
846 * last.
847 *
848 * This function is very similar to del_key_name(), except it
849 * does not require any device look up. This is because the
850 * hot spare pool is not a device.
851 */
852 static int
del_hsp_keys(mdsetname_t * sp,hsp_t hspid,md_error_t * ep)853 del_hsp_keys(mdsetname_t *sp, hsp_t hspid, md_error_t *ep)
854 {
855 md_error_t first_error = MDNULLERROR;
856 mdkey_t key = HSP_ID_TO_KEY(hspid);
857 md_set_desc *sd;
858 side_t thisside; /* Side # of this node. */
859
860 /*
861 * If there is no key, this means that the hot spare was created
862 * before the introduction of friendly names. Thus, the is no NM
863 * record and nothing for us to do in this function.
864 */
865 if (key == MD_KEYBAD)
866 return (0);
867
868 /* Find our current side */
869 mdclrerror(ep);
870 thisside = getmyside(sp, ep);
871 if (! mdisok(ep))
872 return (-1);
873
874 /*
875 * If not the local set, we need to process the non-local sides
876 * first.
877 */
878 if (!metaislocalset(sp)) {
879 if ((sd = metaget_setdesc(sp, ep)) == NULL)
880 return (-1);
881 if (MD_MNSET_DESC(sd)) {
882 /* Multinode set. Sides are in a linked list. */
883 del_hsp_name_mn_sides(sp, sd, thisside, key,
884 &first_error);
885 } else {
886 /* Sides are in an array. */
887 del_hsp_name_trad_sides(sp, sd, thisside, key,
888 &first_error);
889 }
890 }
891
892 /* Now delete the name for the current side. */
893 (void) del_name(sp, thisside, key, ep);
894 if (! mdisok(&first_error))
895 (void) mdstealerror(ep, &first_error);
896 return (mdisok(ep) ? 0 : -1);
897 }
898
899 /*
900 * FUNCTION: add_hsp_name_mn_sides()
901 * INPUT: sp - set name
902 * curside - side number for this node
903 * key - key to use for the name record
904 * hsp_name - name of the hot spare
905 * OUTPUT: ep - error information
906 * RETURNS: 0 indicates success, and -1 indicates failure.
907 * PURPOSE: Once the name record has been added for the current side,
908 * this function adds the record to the remaining sides. This
909 * function is to be used when the set is a multinode set.
910 * The side designated by curside will be ignored when adding
911 * records.
912 */
913 static int
add_hsp_name_mn_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,char * hsp_name,md_error_t * ep)914 add_hsp_name_mn_sides(
915 mdsetname_t *sp,
916 md_set_desc *sd,
917 side_t curside,
918 mdkey_t key,
919 char *hsp_name,
920 md_error_t *ep
921 )
922 {
923 md_mnnode_desc *nd;
924
925 for (nd = sd->sd_nodelist; nd; nd = nd->nd_next) {
926 if (nd->nd_nodeid == curside)
927 continue;
928 if (add_name(sp, nd->nd_nodeid, key, MD_HOTSPARES,
929 minor(NODEV), hsp_name, NULL, NULL, ep) == -1) {
930 return (-1);
931 }
932 }
933 return (0);
934 }
935
936 /*
937 * FUNCTION: add_hsp_name_trad_sides()
938 * INPUT: sp - set name
939 * curside - side number for this node
940 * key - key to use for the name record
941 * hsp_name - name of the hot spare
942 * OUTPUT: ep - error information
943 * RETURNS: 0 indicates success, and -1 indicates failure.
944 * PURPOSE: Once the name record has been added for the current side,
945 * this function adds the record to the remaining sides. This
946 * function is to be used when the set is a traditional set.
947 * The side designated by curside will be ignored when adding
948 * records.
949 */
950 static int
add_hsp_name_trad_sides(mdsetname_t * sp,md_set_desc * sd,side_t curside,mdkey_t key,char * hsp_name,md_error_t * ep)951 add_hsp_name_trad_sides(
952 mdsetname_t *sp,
953 md_set_desc *sd,
954 side_t curside,
955 mdkey_t key,
956 char *hsp_name,
957 md_error_t *ep
958 )
959 {
960 int i;
961
962 for (i = 0; i < MD_MAXSIDES; i++) {
963 if (i == curside)
964 continue;
965 if (sd->sd_nodes[i][0] != '\0') {
966 if (add_name(sp, i, key, MD_HOTSPARES, minor(NODEV),
967 hsp_name, NULL, NULL, ep) == -1) {
968 return (-1);
969 }
970 }
971 }
972 return (0);
973 }
974
975 /*
976 * FUNCTION: add_hsp_name()
977 * INPUT: sp - Name of the set containing the hsp
978 * hsp_name - Hot spare pool name to be added
979 * OUTPUT: ep - Error information
980 * RETURNS: If successful the key of the newly added record is
981 * returned. MD_KEYBAD is returned to indicate a failure.
982 * PURPOSE: This function creates a new NM record containing the name
983 * of the hotspare pool. A record containing the name is
984 * added to each active side, but the record is added first to
985 * the current side. This function is modeled on
986 * add_key_name() in meta_namespace. The difference is that
987 * there is no device associated with a hot spare pool
988 */
989 static hsp_t
add_hsp_name(mdsetname_t * sp,char * hsp_name,md_error_t * ep)990 add_hsp_name(
991 mdsetname_t *sp,
992 char *hsp_name,
993 md_error_t *ep
994 )
995 {
996 md_error_t ignore_error = MDNULLERROR;
997 mdkey_t key;
998 md_set_desc *sd;
999 side_t thisside; /* Side # of this node. */
1000
1001 if (sp == NULL) {
1002 (void) mderror(ep, MDE_NO_SET, NULL);
1003 return (MD_KEYBAD);
1004 }
1005 if (hsp_name == NULL) {
1006 (void) mderror(ep, MDE_INVAL_HSOP, NULL);
1007 return (MD_KEYBAD);
1008 }
1009
1010 mdclrerror(ep);
1011 thisside = getmyside(sp, ep);
1012 if (! mdisok(ep))
1013 return (MD_HSPID_WILD);
1014
1015 /* First add the record for the side of the current node. */
1016 key = add_name(sp, thisside, MD_KEYWILD, MD_HOTSPARES, minor(NODEV),
1017 hsp_name, NULL, NULL, ep);
1018 if (key == -1) {
1019 goto cleanup;
1020 }
1021
1022 /* Make sure that we can use the key */
1023 if (!HSP_KEY_OK(key)) {
1024 (void) mdhsperror(ep, MDE_HSP_CREATE_FAILURE, MD_HSPID_WILD,
1025 hsp_name);
1026 goto cleanup;
1027 }
1028
1029 /*
1030 * Now that we have a key, we will use it to add a record to the
1031 * rest of the sides in the set. For multinode sets, the sides are
1032 * in a linked list that is anchored on the set descriptor. For
1033 * traditional sets the side information is in an array in the set
1034 * descriptor.
1035 */
1036 if (!metaislocalset(sp)) {
1037 if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1038 goto cleanup;
1039 }
1040 if (MD_MNSET_DESC(sd)) {
1041 /* Multinode set. Sides are in linked list. */
1042 if (add_hsp_name_mn_sides(sp, sd, thisside, key,
1043 hsp_name, ep) == -1) {
1044 goto cleanup;
1045 }
1046 } else {
1047 /* Traditional set. Sides are in an array. */
1048 if (add_hsp_name_trad_sides(sp, sd, thisside, key,
1049 hsp_name, ep) == -1) {
1050 goto cleanup;
1051 }
1052 }
1053 }
1054
1055 return (KEY_TO_HSP_ID(sp->setno, key));
1056
1057 cleanup:
1058 /* Get rid records that we added. */
1059 (void) del_hsp_keys(sp, KEY_TO_HSP_ID(sp->setno, key), &ignore_error);
1060 return (MD_HSPID_WILD);
1061 }
1062
1063 /*
1064 * add hotspares and/or hotspare pool
1065 */
1066 int
meta_hs_add(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)1067 meta_hs_add(
1068 mdsetname_t *sp,
1069 mdhspname_t *hspnp,
1070 mdnamelist_t *hsnlp,
1071 mdcmdopts_t options,
1072 md_error_t *ep
1073 )
1074 {
1075 md_error_t ignore_error = MDNULLERROR;
1076 mdnamelist_t *p;
1077 set_hs_params_t shs;
1078 side_t thisside;
1079
1080 /* should have a set */
1081 assert(sp != NULL);
1082 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1083
1084 /* clear cache */
1085 meta_invalidate_hsp(hspnp);
1086
1087 /* setup hotspare pool info */
1088 (void) memset(&shs, 0, sizeof (shs));
1089 shs.shs_cmd = ADD_HOT_SPARE;
1090 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1091
1092 /* Get key for hot spare pool name record. */
1093 if (options & MDCMD_DOIT) {
1094 /* First see if the name record already exists. */
1095 mdclrerror(ep);
1096 thisside = getmyside(sp, ep);
1097 if (! mdisok(ep))
1098 return (-1);
1099 shs.shs_hot_spare_pool =
1100 meta_gethspnmentbyname(sp->setno, thisside,
1101 hspnp->hspname, ep);
1102 if (! mdisok(ep)) {
1103 /*
1104 * If the error is ENOENT, then we will create a
1105 * hot spare pool name records. For other types of
1106 * errors, however, we'll bail out.
1107 */
1108 if (! mdissyserror(ep, ENOENT))
1109 return (-1);
1110 mdclrerror(ep);
1111 /* make sure that the name isn't already in use */
1112 if (is_existing_metadevice(sp, hspnp->hspname))
1113 return (mderror(ep, MDE_NAME_IN_USE,
1114 hspnp->hspname));
1115 if ((shs.shs_hot_spare_pool =
1116 add_hsp_name(sp, hspnp->hspname, ep)) ==
1117 MD_HSPID_WILD) {
1118 return (-1);
1119 }
1120 }
1121 }
1122
1123 /* add empty hotspare pool */
1124 if (hsnlp == NULL) {
1125 shs.shs_options = HS_OPT_POOL;
1126 /* If DOIT is not set, it's a dryrun */
1127 if ((options & MDCMD_DOIT) == 0) {
1128 shs.shs_options |= HS_OPT_DRYRUN;
1129 }
1130 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
1131 hspnp->hspname) != 0) {
1132 if (options & MDCMD_DOIT) {
1133 (void) del_hsp_keys(sp,
1134 shs.shs_hot_spare_pool,
1135 &ignore_error);
1136 }
1137 return (mdstealerror(ep, &shs.mde));
1138 }
1139 goto success;
1140 }
1141
1142 /* add hotspares */
1143 shs.shs_options = HS_OPT_NONE;
1144 /* If DOIT is not set, it's a dryrun */
1145 if ((options & MDCMD_DOIT) == 0) {
1146 shs.shs_options |= HS_OPT_DRYRUN;
1147 }
1148 for (p = hsnlp; (p != NULL); p = p->next) {
1149 mdname_t *hsnp = p->namep;
1150 diskaddr_t size, label, start_blk;
1151
1152 /* should be in same set */
1153 assert(hspnp->hsp == MD_HSP_NONE ||
1154 sp->setno == HSP_SET(hspnp->hsp));
1155
1156 /* check it out */
1157 if (meta_check_hotspare(sp, hsnp, ep) != 0)
1158 return (-1);
1159 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1160 return (-1);
1161 else if (size == 0)
1162 return (mdsyserror(ep, ENOSPC, hsnp->cname));
1163 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1164 return (-1);
1165 if ((start_blk = metagetstart(sp, hsnp, ep))
1166 == MD_DISKADDR_ERROR)
1167 return (-1);
1168
1169 shs.shs_size_option = meta_check_devicesize(size);
1170
1171 /* In dryrun mode (DOIT not set) we must not alter the mddb */
1172 if (options & MDCMD_DOIT) {
1173 /* store name in namespace */
1174 if (add_key_name(sp, hsnp, NULL, ep) != 0)
1175 return (-1);
1176 }
1177
1178 /* add hotspare and/or hotspare pool */
1179 shs.shs_component_old = hsnp->dev;
1180 shs.shs_start_blk = start_blk;
1181 shs.shs_has_label = ((label > 0) ? 1 : 0);
1182 shs.shs_number_blks = size;
1183 shs.shs_key_old = hsnp->key;
1184 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1185 if ((options & MDCMD_DOIT) &&
1186 (shs.shs_options != HS_OPT_POOL)) {
1187 (void) del_key_name(sp, hsnp, ep);
1188 }
1189 return (mdstealerror(ep, &shs.mde));
1190 }
1191 }
1192
1193 /* print success message */
1194 success:
1195 if (options & MDCMD_PRINT) {
1196 if ((options & MDCMD_INIT) || (hsnlp == NULL)) {
1197 (void) printf(dgettext(TEXT_DOMAIN,
1198 "%s: Hotspare pool is setup\n"),
1199 hspnp->hspname);
1200 } else if (hsnlp->next == NULL) {
1201 (void) printf(dgettext(TEXT_DOMAIN,
1202 "%s: Hotspare is added\n"),
1203 hspnp->hspname);
1204 } else {
1205 (void) printf(dgettext(TEXT_DOMAIN,
1206 "%s: Hotspares are added\n"),
1207 hspnp->hspname);
1208 }
1209 (void) fflush(stdout);
1210 }
1211
1212 /* return success */
1213 return (0);
1214 }
1215
1216 /*
1217 * FUNCTION: meta_hsp_delete()
1218 * INPUT: sp - Name of the set containing the hsp
1219 * hspnp - Hot spare pool name information
1220 * options - Options from command line
1221 * OUTPUT: ep - Error information
1222 * RETURNS: 0 on success and -1 on failure.
1223 * PURPOSE: Common code to delete an empty hot spare pool.
1224 */
1225 static int
meta_hsp_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)1226 meta_hsp_delete(
1227 mdsetname_t *sp,
1228 mdhspname_t *hspnp,
1229 mdcmdopts_t options,
1230 md_error_t *ep
1231 )
1232 {
1233 set_hs_params_t shs;
1234
1235 /* setup hotspare pool info */
1236 (void) memset(&shs, 0, sizeof (shs));
1237 shs.shs_hot_spare_pool = hspnp->hsp;
1238 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1239 shs.shs_cmd = DELETE_HOT_SPARE;
1240 shs.shs_options = HS_OPT_POOL;
1241 /* If DOIT is not set, it's a dryrun */
1242 if ((options & MDCMD_DOIT) == 0) {
1243 shs.shs_options |= HS_OPT_DRYRUN;
1244 }
1245
1246 /* Remove hsp record. */
1247 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde,
1248 hspnp->hspname) != 0)
1249 return (mdstealerror(ep, &shs.mde));
1250
1251 /* Get rid of hsp NM records */
1252 if ((options & MDCMD_DOIT) &&
1253 (del_hsp_keys(sp, hspnp->hsp, ep) == -1)) {
1254 return (-1);
1255 }
1256 return (0);
1257 }
1258
1259 /*
1260 * delete hotspares from pool
1261 */
1262 int
meta_hs_delete(mdsetname_t * sp,mdhspname_t * hspnp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)1263 meta_hs_delete(
1264 mdsetname_t *sp,
1265 mdhspname_t *hspnp,
1266 mdnamelist_t *hsnlp,
1267 mdcmdopts_t options,
1268 md_error_t *ep
1269 )
1270 {
1271 mdnamelist_t *p;
1272 set_hs_params_t shs;
1273
1274 /* should have a set */
1275 assert(sp != NULL);
1276 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1277
1278 /* clear cache */
1279 meta_invalidate_hsp(hspnp);
1280
1281 /* setup hotspare pool info */
1282 (void) memset(&shs, 0, sizeof (shs));
1283 shs.shs_hot_spare_pool = hspnp->hsp;
1284 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1285 shs.shs_cmd = DELETE_HOT_SPARE;
1286
1287 /* delete empty hotspare pool */
1288 if (hsnlp == NULL) {
1289 if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
1290 return (-1);
1291 goto success;
1292 }
1293
1294 /* delete hotspares */
1295 shs.shs_options = HS_OPT_NONE;
1296 /* If DOIT is not set, it's a dryrun */
1297 if ((options & MDCMD_DOIT) == 0) {
1298 shs.shs_options |= HS_OPT_DRYRUN;
1299 }
1300 for (p = hsnlp; (p != NULL); p = p->next) {
1301 mdname_t *hsnp = p->namep;
1302
1303 /* should be in same set */
1304 assert(hspnp->hsp == MD_HSP_NONE ||
1305 sp->setno == HSP_SET(hspnp->hsp));
1306
1307 /* delete hotspare */
1308 shs.shs_component_old = hsnp->dev;
1309 meta_invalidate_name(hsnp);
1310 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0)
1311 return (mdstealerror(ep, &shs.mde));
1312 }
1313
1314 /* print success message */
1315 success:
1316 if (options & MDCMD_PRINT) {
1317 if (hsnlp == NULL) {
1318 (void) printf(dgettext(TEXT_DOMAIN,
1319 "%s: Hotspare pool is cleared\n"),
1320 hspnp->hspname);
1321 } else if (hsnlp->next == NULL) {
1322 (void) printf(dgettext(TEXT_DOMAIN,
1323 "%s: Hotspare is deleted\n"),
1324 hspnp->hspname);
1325 } else {
1326 (void) printf(dgettext(TEXT_DOMAIN,
1327 "%s: Hotspares are deleted\n"),
1328 hspnp->hspname);
1329 }
1330 (void) fflush(stdout);
1331 }
1332
1333 /* return success */
1334 return (0);
1335 }
1336
1337 /*
1338 * replace hotspare in pool
1339 */
1340 int
meta_hs_replace(mdsetname_t * sp,mdhspname_t * hspnp,mdname_t * oldnp,mdname_t * newnp,mdcmdopts_t options,md_error_t * ep)1341 meta_hs_replace(
1342 mdsetname_t *sp,
1343 mdhspname_t *hspnp,
1344 mdname_t *oldnp,
1345 mdname_t *newnp,
1346 mdcmdopts_t options,
1347 md_error_t *ep
1348 )
1349 {
1350 set_hs_params_t shs;
1351 diskaddr_t size, label, start_blk;
1352 md_dev64_t old_dev, new_dev;
1353 diskaddr_t new_start_blk, new_end_blk;
1354 int rebind;
1355 char *new_devidp = NULL;
1356 int ret;
1357 md_set_desc *sd;
1358
1359 /* should be in same set */
1360 assert(sp != NULL);
1361 assert(hspnp->hsp == MD_HSP_NONE || sp->setno == HSP_SET(hspnp->hsp));
1362
1363 /* save new binding incase this is a rebind where oldnp==newnp */
1364 new_dev = newnp->dev;
1365 new_start_blk = newnp->start_blk;
1366 new_end_blk = newnp->end_blk;
1367
1368 /* invalidate, then get the hotspare (fill in oldnp from metadb) */
1369 meta_invalidate_hsp(hspnp);
1370 if (meta_get_hsp(sp, hspnp, ep) == NULL)
1371 return (-1);
1372
1373 /* the old device binding is now established */
1374 if ((old_dev = oldnp->dev) == NODEV64)
1375 return (mdsyserror(ep, ENODEV, oldnp->cname));
1376
1377 /*
1378 * check for the case where oldnp and newnp indicate the same
1379 * device, but the dev_t of the device has changed between old
1380 * and new. This is called a rebind. On entry the dev_t
1381 * represents the new device binding determined from the
1382 * filesystem (meta_getdev). After calling meta_get_hsp
1383 * oldnp (and maybe newnp if this is a rebind) is updated based
1384 * to the old binding from the metadb (done by metakeyname).
1385 */
1386 if ((strcmp(oldnp->rname, newnp->rname) == 0) &&
1387 (old_dev != new_dev)) {
1388 rebind = 1;
1389 } else {
1390 rebind = 0;
1391 }
1392 if (rebind) {
1393 newnp->dev = new_dev;
1394 newnp->start_blk = new_start_blk;
1395 newnp->end_blk = new_end_blk;
1396 }
1397
1398 /*
1399 * Save a copy of the devid associated with the new disk, the reason
1400 * is that the meta_check_hotspare() call could cause the devid to
1401 * be changed to that of the devid that is currently stored in the
1402 * replica namespace for the disk in question. This devid could be
1403 * stale if we are replacing the disk. The function that overwrites
1404 * the devid is dr2drivedesc().
1405 */
1406 if (newnp->drivenamep->devid != NULL)
1407 new_devidp = Strdup(newnp->drivenamep->devid);
1408
1409 /* if it's a multi-node diskset clear new_devidp */
1410 if (!metaislocalset(sp)) {
1411 if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1412 Free(new_devidp);
1413 return (-1);
1414 }
1415 if (MD_MNSET_DESC(sd)) {
1416 Free(new_devidp);
1417 new_devidp = NULL;
1418 }
1419 }
1420
1421 /* check it out */
1422 if (meta_check_hotspare(sp, newnp, ep) != 0) {
1423 if ((! rebind) || (! mdisuseerror(ep, MDE_ALREADY))) {
1424 Free(new_devidp);
1425 return (-1);
1426 }
1427 mdclrerror(ep);
1428 }
1429 if ((size = metagetsize(newnp, ep)) == MD_DISKADDR_ERROR) {
1430 Free(new_devidp);
1431 return (-1);
1432 }
1433 if ((label = metagetlabel(newnp, ep)) == MD_DISKADDR_ERROR) {
1434 Free(new_devidp);
1435 return (-1);
1436 }
1437 if ((start_blk = metagetstart(sp, newnp, ep)) == MD_DISKADDR_ERROR) {
1438 Free(new_devidp);
1439 return (-1);
1440 }
1441 if (start_blk >= size) {
1442 (void) mdsyserror(ep, ENOSPC, newnp->cname);
1443 Free(new_devidp);
1444 return (-1);
1445 }
1446
1447 /*
1448 * Copy back the saved devid.
1449 */
1450 Free(newnp->drivenamep->devid);
1451 if (new_devidp != NULL) {
1452 newnp->drivenamep->devid = new_devidp;
1453 new_devidp = NULL;
1454 }
1455
1456 /* In dryrun mode (DOIT not set) we must not alter the mddb */
1457 if (options & MDCMD_DOIT) {
1458 /* store name in namespace */
1459 if (add_key_name(sp, newnp, NULL, ep) != 0)
1460 return (-1);
1461 }
1462
1463 if (rebind && !metaislocalset(sp)) {
1464 /*
1465 * We are 'rebind'ing a disk that is in a diskset so as well
1466 * as updating the diskset's namespace the local set needs
1467 * to be updated because it also contains a reference to the
1468 * disk in question.
1469 */
1470 ret = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET, newnp->cname,
1471 ep);
1472
1473 if (ret != METADEVADM_SUCCESS) {
1474 md_error_t xep = mdnullerror;
1475
1476 /*
1477 * In dryrun mode (DOIT not set) we must not alter
1478 * the mddb
1479 */
1480 if (options & MDCMD_DOIT) {
1481 (void) del_key_name(sp, newnp, &xep);
1482 mdclrerror(&xep);
1483 return (-1);
1484 }
1485 }
1486 }
1487
1488 /* replace hotspare */
1489 (void) memset(&shs, 0, sizeof (shs));
1490
1491 shs.shs_size_option = meta_check_devicesize(size);
1492
1493 shs.shs_cmd = REPLACE_HOT_SPARE;
1494 shs.shs_hot_spare_pool = hspnp->hsp;
1495 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1496 shs.shs_component_old = old_dev;
1497 shs.shs_options = HS_OPT_NONE;
1498 /* If DOIT is not set, it's a dryrun */
1499 if ((options & MDCMD_DOIT) == 0) {
1500 shs.shs_options |= HS_OPT_DRYRUN;
1501 }
1502 shs.shs_component_new = new_dev;
1503 shs.shs_start_blk = start_blk;
1504 shs.shs_has_label = ((label > 0) ? 1 : 0);
1505 shs.shs_number_blks = size;
1506 shs.shs_key_new = newnp->key;
1507 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1508 if (options & MDCMD_DOIT) {
1509 (void) del_key_name(sp, newnp, ep);
1510 }
1511 return (mdstealerror(ep, &shs.mde));
1512 }
1513
1514 /* clear cache */
1515 meta_invalidate_name(oldnp);
1516 meta_invalidate_name(newnp);
1517 meta_invalidate_hsp(hspnp);
1518
1519 /* let em know */
1520 if (options & MDCMD_PRINT) {
1521 (void) printf(dgettext(TEXT_DOMAIN,
1522 "%s: Hotspare %s is replaced with %s\n"),
1523 hspnp->hspname, oldnp->cname, newnp->cname);
1524 (void) fflush(stdout);
1525 }
1526
1527 /* return success */
1528 return (0);
1529 }
1530
1531 /*
1532 * enable hotspares
1533 */
1534 int
meta_hs_enable(mdsetname_t * sp,mdnamelist_t * hsnlp,mdcmdopts_t options,md_error_t * ep)1535 meta_hs_enable(
1536 mdsetname_t *sp,
1537 mdnamelist_t *hsnlp,
1538 mdcmdopts_t options,
1539 md_error_t *ep
1540 )
1541 {
1542 mdhspnamelist_t *hspnlp = NULL;
1543 mdhspnamelist_t *hspnp;
1544 set_hs_params_t shs;
1545 int rval = -1;
1546
1547 /* should have a set */
1548 assert(sp != NULL);
1549
1550 /* setup device info */
1551 (void) memset(&shs, 0, sizeof (shs));
1552 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1553 shs.shs_cmd = FIX_HOT_SPARE;
1554 shs.shs_options = HS_OPT_NONE;
1555 /* If DOIT is not set, it's a dryrun */
1556 if ((options & MDCMD_DOIT) == 0) {
1557 shs.shs_options |= HS_OPT_DRYRUN;
1558 }
1559
1560 /* get the list of hotspare names */
1561 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1562 goto out;
1563
1564 /* enable hotspares for each components */
1565 for (; (hsnlp != NULL); hsnlp = hsnlp->next) {
1566 mdname_t *hsnp = hsnlp->namep;
1567 md_dev64_t fs_dev;
1568 int rebind = 0;
1569 diskaddr_t size, label, start_blk;
1570
1571 /* get the file_system dev binding */
1572 if (meta_getdev(sp, hsnp, ep) != 0)
1573 return (-1);
1574 fs_dev = hsnp->dev;
1575
1576 /*
1577 * search for the component in each hotspare pool
1578 * and replace it (instead of enable) if the binding
1579 * has changed.
1580 */
1581 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1582 /*
1583 * in_hsp will call meta_get_hsp which will fill
1584 * in hspnp with metadb version of component
1585 */
1586 meta_invalidate_hsp(hspnp->hspnamep);
1587 if (in_hsp(sp, hspnp->hspnamep, hsnp, 0, -1, ep) != 0) {
1588 /*
1589 * check for the case where the dev_t has
1590 * changed between the filesystem and the
1591 * metadb. This is called a rebind, and
1592 * is handled by meta_hs_replace.
1593 */
1594 if (fs_dev != hsnp->dev) {
1595 /*
1596 * establish file system binding
1597 * with invalid start/end
1598 */
1599 rebind++;
1600 hsnp->dev = fs_dev;
1601 hsnp->start_blk = -1;
1602 hsnp->end_blk = -1;
1603 rval = meta_hs_replace(sp,
1604 hspnp->hspnamep,
1605 hsnp, hsnp, options, ep);
1606 if (rval != 0)
1607 goto out;
1608 }
1609 }
1610 }
1611 if (rebind)
1612 continue;
1613
1614 /* enable the component in all hotspares that use it */
1615 if (meta_check_hotspare(sp, hsnp, ep) != 0)
1616 goto out;
1617
1618 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR)
1619 goto out;
1620 if ((label = metagetlabel(hsnp, ep)) == MD_DISKADDR_ERROR)
1621 goto out;
1622 if ((start_blk = metagetstart(sp, hsnp, ep))
1623 == MD_DISKADDR_ERROR)
1624 goto out;
1625 if (start_blk >= size) {
1626 (void) mdsyserror(ep, ENOSPC, hsnp->cname);
1627 goto out;
1628 }
1629
1630 /* enable hotspare */
1631 shs.shs_component_old = hsnp->dev;
1632 shs.shs_component_new = hsnp->dev;
1633 shs.shs_start_blk = start_blk;
1634 shs.shs_has_label = ((label > 0) ? 1 : 0);
1635 shs.shs_number_blks = size;
1636 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, hsnp->cname) != 0) {
1637 rval = mdstealerror(ep, &shs.mde);
1638 goto out;
1639 }
1640
1641 /*
1642 * Are we dealing with a non-local set? If so need to update
1643 * the local namespace so that the disk record has the correct
1644 * devid.
1645 */
1646 if (!metaislocalset(sp)) {
1647 rval = meta_fixdevid(sp, DEV_UPDATE|DEV_LOCAL_SET,
1648 hsnp->cname, ep);
1649
1650 if (rval != METADEVADM_SUCCESS) {
1651 /*
1652 * Failed to update the local set. Nothing to
1653 * do here apart from report the error. The
1654 * namespace is most likely broken and some
1655 * form of remedial recovery is going to
1656 * be required.
1657 */
1658 mde_perror(ep, "");
1659 mdclrerror(ep);
1660 }
1661 }
1662
1663 /* clear cache */
1664 meta_invalidate_name(hsnp);
1665
1666 /* let em know */
1667 if (options & MDCMD_PRINT) {
1668 (void) printf(dgettext(TEXT_DOMAIN,
1669 "hotspare %s is enabled\n"),
1670 hsnp->cname);
1671 (void) fflush(stdout);
1672 }
1673 }
1674
1675 /* clear whole cache */
1676 for (hspnp = hspnlp; (hspnp != NULL); hspnp = hspnp->next) {
1677 meta_invalidate_hsp(hspnp->hspnamep);
1678 }
1679
1680
1681 /* return success */
1682 rval = 0;
1683
1684 out:
1685 if (hspnlp)
1686 metafreehspnamelist(hspnlp);
1687 return (rval);
1688 }
1689
1690 /*
1691 * check for dups in the hsp itself
1692 */
1693 static int
check_twice(md_hsp_t * hspp,uint_t hsi,md_error_t * ep)1694 check_twice(
1695 md_hsp_t *hspp,
1696 uint_t hsi,
1697 md_error_t *ep
1698 )
1699 {
1700 mdhspname_t *hspnp = hspp->hspnamep;
1701 mdname_t *thisnp;
1702 uint_t h;
1703
1704 thisnp = hspp->hotspares.hotspares_val[hsi].hsnamep;
1705 for (h = 0; (h < hsi); ++h) {
1706 md_hs_t *hsp = &hspp->hotspares.hotspares_val[h];
1707 mdname_t *hsnp = hsp->hsnamep;
1708
1709 if (meta_check_overlap(hspnp->hspname, thisnp, 0, -1,
1710 hsnp, 0, -1, ep) != 0)
1711 return (-1);
1712 }
1713 return (0);
1714 }
1715
1716 /*
1717 * check hsp
1718 */
1719 /*ARGSUSED2*/
1720 int
meta_check_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)1721 meta_check_hsp(
1722 mdsetname_t *sp,
1723 md_hsp_t *hspp,
1724 mdcmdopts_t options,
1725 md_error_t *ep
1726 )
1727 {
1728 mdhspname_t *hspnp = hspp->hspnamep;
1729 uint_t hsi;
1730
1731 /* check hotspares */
1732 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1733 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
1734 mdname_t *hsnp = hsp->hsnamep;
1735 diskaddr_t size;
1736
1737 /* check hotspare */
1738 if (meta_check_hotspare(sp, hsnp, ep) != 0)
1739 return (-1);
1740 if ((size = metagetsize(hsnp, ep)) == MD_DISKADDR_ERROR) {
1741 return (-1);
1742 } else if (size == 0) {
1743 return (mdsyserror(ep, ENOSPC, hspnp->hspname));
1744 }
1745
1746 /* check this hsp too */
1747 if (check_twice(hspp, hsi, ep) != 0)
1748 return (-1);
1749 }
1750
1751 /* return success */
1752 return (0);
1753 }
1754
1755 /*
1756 * create hsp
1757 */
1758 int
meta_create_hsp(mdsetname_t * sp,md_hsp_t * hspp,mdcmdopts_t options,md_error_t * ep)1759 meta_create_hsp(
1760 mdsetname_t *sp,
1761 md_hsp_t *hspp,
1762 mdcmdopts_t options,
1763 md_error_t *ep
1764 )
1765 {
1766 mdhspname_t *hspnp = hspp->hspnamep;
1767 mdnamelist_t *hsnlp = NULL;
1768 uint_t hsi;
1769 int rval = -1;
1770
1771 /* validate hsp */
1772 if (meta_check_hsp(sp, hspp, options, ep) != 0)
1773 return (-1);
1774
1775 /* if we're not doing anything, return success */
1776 if (! (options & MDCMD_DOIT))
1777 return (0);
1778
1779 /* create hsp */
1780 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
1781 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
1782 mdname_t *hsnp = hsp->hsnamep;
1783
1784 (void) metanamelist_append(&hsnlp, hsnp);
1785 }
1786 options |= MDCMD_INIT;
1787 rval = meta_hs_add(sp, hspnp, hsnlp, options, ep);
1788
1789 /* cleanup, return success */
1790 metafreenamelist(hsnlp);
1791 return (rval);
1792 }
1793
1794 /*
1795 * initialize hsp
1796 * NOTE: this functions is metainit(1m)'s command line parser!
1797 */
1798 int
meta_init_hsp(mdsetname_t ** spp,int argc,char * argv[],mdcmdopts_t options,md_error_t * ep)1799 meta_init_hsp(
1800 mdsetname_t **spp,
1801 int argc,
1802 char *argv[],
1803 mdcmdopts_t options,
1804 md_error_t *ep
1805 )
1806 {
1807 char *uname = argv[0];
1808 mdhspname_t *hspnp = NULL;
1809 md_hsp_t *hspp = NULL;
1810 uint_t hsi;
1811 int rval = -1;
1812
1813
1814 /* get hsp name */
1815 assert(argc > 0);
1816 if (argc < 1)
1817 goto syntax;
1818 if ((hspnp = metahspname(spp, uname, ep)) == NULL)
1819 goto out;
1820 assert(*spp != NULL);
1821 uname = hspnp->hspname;
1822
1823 if (!(options & MDCMD_NOLOCK)) {
1824 /* grab set lock */
1825 if (meta_lock(*spp, TRUE, ep))
1826 goto out;
1827
1828 if (meta_check_ownership(*spp, ep) != 0)
1829 goto out;
1830 }
1831
1832 /* see if it exists already */
1833 if (is_existing_metadevice(*spp, uname)) {
1834 mdname_t *np;
1835 if ((np = metaname(spp, uname, META_DEVICE, ep)) != NULL)
1836 if ((meta_get_unit(*spp, np, ep)) != NULL)
1837 return (mderror(ep, MDE_NAME_IN_USE, uname));
1838 }
1839
1840 if (meta_get_hsp(*spp, hspnp, ep) != NULL) {
1841 (void) mdhsperror(ep, MDE_HSP_ALREADY_SETUP,
1842 hspnp->hsp, uname);
1843 goto out;
1844 } else if (! mdishsperror(ep, MDE_INVAL_HSP)) {
1845 goto out;
1846 } else {
1847 mdclrerror(ep);
1848 }
1849 --argc, ++argv;
1850
1851 /* parse general options */
1852 optind = 0;
1853 opterr = 0;
1854 if (getopt(argc, argv, "") != -1)
1855 goto options;
1856
1857 /* allocate hsp */
1858 hspp = Zalloc(sizeof (*hspp));
1859 hspp->hotspares.hotspares_len = argc;
1860 if (argc > 0) {
1861 hspp->hotspares.hotspares_val =
1862 Zalloc(argc * sizeof (*hspp->hotspares.hotspares_val));
1863 }
1864
1865 /* setup pool */
1866 hspp->hspnamep = hspnp;
1867
1868 /* parse hotspares */
1869 for (hsi = 0; ((argc > 0) && (hsi < hspp->hotspares.hotspares_len));
1870 ++hsi) {
1871 md_hs_t *hsp = &hspp->hotspares.hotspares_val[hsi];
1872 mdname_t *hsnamep;
1873
1874 /* parse hotspare name */
1875 if ((hsnamep = metaname(spp, argv[0],
1876 LOGICAL_DEVICE, ep)) == NULL)
1877 goto out;
1878 hsp->hsnamep = hsnamep;
1879 --argc, ++argv;
1880 }
1881
1882 /* we should be at the end */
1883 if (argc != 0)
1884 goto syntax;
1885
1886 /* create hotspare pool */
1887 if (meta_create_hsp(*spp, hspp, options, ep) != 0)
1888 goto out;
1889 rval = 0; /* success */
1890 goto out;
1891
1892 /* syntax error */
1893 syntax:
1894 rval = meta_cook_syntax(ep, MDE_SYNTAX, uname, argc, argv);
1895 goto out;
1896
1897 /* options error */
1898 options:
1899 rval = meta_cook_syntax(ep, MDE_OPTION, uname, argc, argv);
1900 goto out;
1901
1902 /* cleanup, return error */
1903 out:
1904 if (hspp != NULL)
1905 meta_free_hsp(hspp);
1906 return (rval);
1907 }
1908
1909 /*
1910 * reset hotspare pool
1911 */
1912 int
meta_hsp_reset(mdsetname_t * sp,mdhspname_t * hspnp,mdcmdopts_t options,md_error_t * ep)1913 meta_hsp_reset(
1914 mdsetname_t *sp,
1915 mdhspname_t *hspnp,
1916 mdcmdopts_t options,
1917 md_error_t *ep
1918 )
1919 {
1920 md_hsp_t *hspp;
1921 set_hs_params_t shs;
1922 uint_t i;
1923 int rval = -1;
1924
1925 /* should have the same set */
1926 assert(sp != NULL);
1927 assert(hspnp == NULL || hspnp->hsp == MD_HSP_NONE ||
1928 sp->setno == HSP_SET(hspnp->hsp));
1929
1930 /* reset all hotspares */
1931 if (hspnp == NULL) {
1932 mdhspnamelist_t *hspnlp = NULL;
1933 mdhspnamelist_t *p;
1934
1935 /* for each hotspare pool */
1936 rval = 0;
1937 if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
1938 return (-1);
1939 for (p = hspnlp; (p != NULL); p = p->next) {
1940 /* reset hotspare pool */
1941 hspnp = p->hspnamep;
1942
1943 /*
1944 * If this is a multi-node set, we send a series
1945 * of individual metaclear commands.
1946 */
1947 if (meta_is_mn_set(sp, ep)) {
1948 if (meta_mn_send_metaclear_command(sp,
1949 hspnp->hspname, options, 0, ep) != 0) {
1950 rval = -1;
1951 break;
1952 }
1953 } else {
1954 if (meta_hsp_reset(sp, hspnp, options,
1955 ep) != 0) {
1956 rval = -1;
1957 break;
1958 }
1959 }
1960 }
1961
1962 /* cleanup, return success */
1963 metafreehspnamelist(hspnlp);
1964 return (rval);
1965 }
1966
1967 /* get unit structure */
1968 if ((hspp = meta_get_hsp(sp, hspnp, ep)) == NULL)
1969 return (-1);
1970
1971 /* make sure nobody owns us */
1972 if (hspp->refcount > 0) {
1973 return (mdhsperror(ep, MDE_HSP_IN_USE, hspnp->hsp,
1974 hspnp->hspname));
1975 }
1976
1977 /* clear hotspare pool members */
1978 (void) memset(&shs, 0, sizeof (shs));
1979 MD_SETDRIVERNAME(&shs, MD_HOTSPARES, sp->setno);
1980 shs.shs_cmd = DELETE_HOT_SPARE;
1981 shs.shs_hot_spare_pool = hspnp->hsp;
1982 for (i = 0; (i < hspp->hotspares.hotspares_len); ++i) {
1983 md_hs_t *hs = &hspp->hotspares.hotspares_val[i];
1984 mdname_t *hsnamep = hs->hsnamep;
1985
1986 /* clear cache */
1987 meta_invalidate_name(hsnamep);
1988
1989 /* clear hotspare */
1990 shs.shs_component_old = hsnamep->dev;
1991 shs.shs_options = HS_OPT_FORCE;
1992 /* If DOIT is not set, it's a dryrun */
1993 if ((options & MDCMD_DOIT) == 0) {
1994 shs.shs_options |= HS_OPT_DRYRUN;
1995 }
1996 if (metaioctl(MD_IOCSET_HS, &shs, &shs.mde, NULL) != 0) {
1997 (void) mdstealerror(ep, &shs.mde);
1998 goto out;
1999 }
2000 }
2001
2002 /* clear hotspare pool */
2003 if (meta_hsp_delete(sp, hspnp, options, ep) != 0)
2004 goto out;
2005 rval = 0; /* success */
2006
2007 /* let em know */
2008 if (options & MDCMD_PRINT) {
2009 (void) printf(dgettext(TEXT_DOMAIN,
2010 "%s: Hotspare pool is cleared\n"),
2011 hspnp->hspname);
2012 (void) fflush(stdout);
2013 }
2014
2015 /* clear subdevices (nothing to do) */
2016
2017 /* cleanup, return success */
2018 out:
2019 meta_invalidate_hsp(hspnp);
2020 return (rval);
2021 }
2022