Mercurial > illumos > onarm
annotate usr/src/cmd/lvm/metassist/layout/layout_slice.c @ 13:f60a82e85167 default tip
Revert NEC's changes to fix krb5 build
author | Andrew Stormont <andyjstormont@gmail.com> |
---|---|
date | Fri, 02 Mar 2012 22:25:26 +0000 |
parents | 1a15d5aaf794 |
children |
rev | line source |
---|---|
0 | 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 2005 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
27 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 28 |
29 #include <sys/param.h> | |
30 #include <meta.h> | |
31 | |
32 #include "volume_string.h" | |
33 | |
34 #include "volume_devconfig.h" | |
35 #include "volume_error.h" | |
36 #include "volume_dlist.h" | |
37 #include "volume_output.h" | |
38 | |
39 #include "layout_device_cache.h" | |
40 #include "layout_device_util.h" | |
41 #include "layout_discovery.h" | |
42 #include "layout_dlist_util.h" | |
43 #include "layout_messages.h" | |
44 #include "layout_request.h" | |
45 #include "layout_slice.h" | |
46 | |
47 #define _LAYOUT_SLICE_C | |
48 | |
49 static int pick_from_best_hba_and_disk( | |
50 dlist_t *list, | |
51 dlist_t *used, | |
52 dm_descriptor_t *chosen); | |
53 | |
54 static int slice_has_same_disk_geom( | |
55 dm_descriptor_t slice, | |
56 dlist_t *used, | |
57 boolean_t *bool); | |
58 | |
59 static int slice_on_unique_disk( | |
60 dm_descriptor_t slice, | |
61 dlist_t *used, | |
62 dlist_t *othervols, | |
63 boolean_t *bool); | |
64 | |
65 static int slice_on_unique_hba( | |
66 dm_descriptor_t slice, | |
67 dlist_t *used, | |
68 dlist_t *othervols, | |
69 boolean_t *bool); | |
70 | |
71 static int slice_on_similar_bus( | |
72 dm_descriptor_t slice, | |
73 dlist_t *used, | |
74 boolean_t *bool); | |
75 | |
76 static int slice_has_n_paths( | |
77 dm_descriptor_t slice, | |
78 uint16_t npaths, | |
79 boolean_t *bool); | |
80 | |
81 static int compare_modslice_names( | |
82 void *obj1, | |
83 void *obj2); | |
84 | |
85 static int compare_string_to_modslice_name( | |
86 void *str, | |
87 void *modslice); | |
88 | |
89 static int create_new_slice( | |
90 dm_descriptor_t oslice, | |
91 uint64_t nbytes, | |
92 boolean_t add_extra_cyl, | |
93 devconfig_t **nslice); | |
94 | |
95 static int create_modified_slice( | |
96 dm_descriptor_t oslice, | |
97 char *oname, | |
98 uint32_t oindex, | |
99 uint64_t ostart, | |
100 uint64_t osize, | |
101 uint64_t bps, | |
102 char *nname, | |
103 uint32_t nindex, | |
104 uint64_t nsize, | |
105 devconfig_t **nslice); | |
106 | |
107 /* | |
108 * list to track resized slices | |
109 */ | |
110 static dlist_t *_modified_slices = NULL; | |
111 | |
112 /* | |
113 * struct to track used slices and their disks... | |
114 */ | |
115 typedef struct { | |
116 char *slicename; | |
117 dm_descriptor_t disk; | |
118 } usedslice_t; | |
119 | |
120 /* | |
121 * list to of usedslice_t to track slices that have been | |
122 * used for any reason. | |
123 */ | |
124 static dlist_t *_used_slices = NULL; | |
125 | |
126 static int add_used_slice_list_entry(char *slicename, dm_descriptor_t disk); | |
127 static int compare_usedslice_name_to_string(void *obj1, void *obj2); | |
128 static void free_used_slice(void *obj); | |
129 | |
130 /* | |
131 * list of slices reserved to be used for explicit | |
132 * volume requests | |
133 */ | |
134 static dlist_t *_rsvd_slices = NULL; | |
135 | |
136 /* | |
137 * list of slices needing to be removed (zeroed out) prior to | |
138 * applying any metassist modifications to the system. | |
139 */ | |
140 static dlist_t *_rmvd_slices = NULL; | |
141 | |
142 /* | |
143 * FUNCTION: choose_slice( | |
144 * uint64_t nbytes, | |
145 * uint16_t npaths, | |
146 * dlist_t *slices, | |
147 * dlist_t *used, | |
148 * dlist_t *used_hbas, | |
149 * dlist_t *used_disks, | |
150 * boolean_t unused_disk, | |
151 * boolean_t nbytes_is_min, | |
152 * boolean_t add_extra_cyl, | |
153 * devconfig_t **chosen) | |
154 * | |
155 * INPUT: nbytes - required size | |
156 * npaths - minimum required data paths | |
157 * *slices - slices from which to choose | |
158 * *used - slices used by the volume under construction | |
159 * *used_hbas - hbas used by other volumes relevant to | |
160 * the volume under construction | |
161 * *used_disks - disks used by other volumes relevant to | |
162 * the volume under construction | |
163 * unused_disk - if true, the chosen slice must be from an | |
164 * unused disk | |
165 * nbytes_is_min - if true, the chosen slice may be larger than | |
166 * nbytes. | |
167 * add_extra_cyl - passed to create_new_slice, see comment there. | |
168 * **chosen - pointer to hold the chosen slice | |
169 * | |
170 * RETURNS: int - 0 on success | |
171 * !0 otherwise | |
172 * | |
173 * PURPOSE: Choosen a slice from the list of those available. | |
174 * | |
175 * Of those available, choose in order of preference: | |
176 * | |
177 * - one on a unique HBA and disk that is of the exact size | |
178 * - one on a unique HBA and disk that is of sufficient size | |
179 * - one on unique HBA that is of the exact size | |
180 * - one on unique HBA that is of sufficient size | |
181 * - one on unique disk that is of the exact size | |
182 * - one on unique disk that is of sufficient size | |
183 * - one on any HBA that is of exact size | |
184 * - one on any HBA that is of sufficient size | |
185 * - one on a unique HBA that is the largest size | |
186 * - one on a unique disk that is the largest size | |
187 * - one on any HBA that is the largest size | |
188 * | |
189 * The function scans the available slices and builds lists of | |
190 * those meeting the criteria above. After the scan is complete, | |
191 * the lists are examined in order, the first non-empty list is | |
192 * chosen. If there are several possibilities in the chosen list, | |
193 * see if it is possible select the slice from the least used HBA | |
194 * and/or disk. | |
195 * | |
196 * If nbytes_is_min is true, the returned slice will be | |
197 * at least nbytes in capacity. | |
198 * | |
199 * If unused_disk is true, the returned slice will be from | |
200 * a disk with no other known uses. | |
201 */ | |
202 int | |
203 choose_slice( | |
204 uint64_t nbytes, | |
205 uint16_t npaths, | |
206 dlist_t *slices, | |
207 dlist_t *used, | |
208 dlist_t *used_hbas, | |
209 dlist_t *used_disks, | |
210 boolean_t unused_disk, | |
211 boolean_t nbytes_is_min, | |
212 boolean_t add_extra_cyl, | |
213 devconfig_t **chosen) | |
214 { | |
215 dlist_t *iter = NULL; | |
216 | |
217 dm_descriptor_t slice = NULL; | |
218 boolean_t resize = B_FALSE; | |
219 boolean_t verbose = (get_max_verbosity() == OUTPUT_VERBOSE); | |
220 | |
221 int error = 0; | |
222 | |
223 /* | |
224 * indexes into the list array: | |
225 * i -> unique controller 0 = yes, 1 = no | |
226 * j -> same bus type 0 = yes, 1 = no | |
227 * k -> unique disk 0 = yes, 1 = no | |
228 * l -> same disk geom 0 = yes, 1 = no | |
229 * m -> size 0 == exact, 1 = larger, 2 = any | |
230 */ | |
231 int i, j, k, l, m; | |
232 dlist_t *list[2][2][2][2][3]; | |
233 | |
234 /* output string arrays for each array dimension and index */ | |
235 char *uniqhba[2]; | |
236 char *samebus[2]; | |
237 char *uniqdisk[2]; | |
238 char *samegeom[2]; | |
239 char *sizes[3]; | |
240 | |
241 /* other output strings */ | |
242 char *look_msg = NULL; | |
243 char *npaths_msg = NULL; | |
244 char *samegeom_msg = NULL; | |
245 char *samebus_msg = NULL; | |
246 char *uniqhba_msg = NULL; | |
247 char *uniqdisk_msg = NULL; | |
248 char *exact_msg = NULL; | |
249 char *larger_msg = NULL; | |
250 char *smaller_msg = NULL; | |
251 char *insuff_paths = NULL; | |
252 char *too_small = NULL; | |
253 char *useddisk_msg = NULL; | |
254 | |
255 if (verbose == B_TRUE) { | |
256 /* only initialize the output strings if needed */ | |
257 | |
258 /* BEGIN CSTYLED */ | |
259 look_msg = gettext( | |
260 "\tlooking at slice: %s (%s)\n"); | |
261 npaths_msg = gettext( | |
262 "\t has the requested number of data paths (%d)\n"); | |
263 samegeom_msg = gettext( | |
264 "\t has the same disk geometry relative to used slices\n"); | |
265 samebus_msg = gettext( | |
266 "\t on a similar I/O bus/HBA relative to used slices\n"); | |
267 uniqhba_msg = gettext( | |
268 "\t on a unique HBA relative to used slices\n"); | |
269 uniqdisk_msg = gettext( | |
270 "\t on a unique disk relative to used slices\n"); | |
271 exact_msg = gettext( | |
272 "\t the exact size necessary\n"); | |
273 larger_msg = gettext( | |
274 "\t larger than necessary\n"); | |
275 smaller_msg = gettext( | |
276 "\t smaller than necessary\n"); | |
277 insuff_paths = gettext( | |
278 "\t rejected: not enough paths (%d requested)\n"); | |
279 too_small = gettext( | |
280 "\t rejected: too small\n"); | |
281 useddisk_msg = gettext( | |
282 "\t rejected: on a disk with other volume component(s)\n"); | |
283 | |
284 uniqhba[0] = gettext("unique HBA"); | |
285 uniqhba[1] = gettext("non unique HBA"); | |
286 samebus[0] = gettext("same bus type"); | |
287 samebus[1] = gettext("different bus type"); | |
288 uniqdisk[0] = gettext("unique disk"); | |
289 uniqdisk[1] = gettext("non unique disk"); | |
290 samegeom[0] = gettext("same geometry"); | |
291 samegeom[1] = gettext("different geometry"); | |
292 sizes[0] = gettext("an exact size slice"); | |
293 sizes[1] = gettext("a larger slice"); | |
294 sizes[2] = gettext("a smaller slice"); | |
295 | |
296 /* END CSTYLED */ | |
297 } | |
298 | |
299 /* init list array pointers */ | |
300 (void) memset(list, 0, 2*2*2*2*3 * sizeof (dlist_t *)); | |
301 | |
302 for (iter = slices; | |
303 (iter != NULL) && (error == 0); iter = iter->next) { | |
304 | |
305 dm_descriptor_t slice = (uintptr_t)iter->obj; | |
306 uint64_t snbytes = 0; | |
307 boolean_t uniqdisk = B_FALSE; | |
308 boolean_t uniqhba = B_FALSE; | |
309 boolean_t samegeom = B_FALSE; | |
310 boolean_t samebus = B_FALSE; | |
311 boolean_t paths = B_FALSE; | |
312 dlist_t *item = NULL; | |
313 | |
314 ((error = slice_get_size(slice, &snbytes)) != 0) || | |
315 (error = slice_has_n_paths(slice, npaths, &paths)) || | |
316 (error = slice_on_unique_hba(slice, used, used_hbas, &uniqhba)) || | |
317 (error = slice_on_unique_disk(slice, used, used_disks, | |
318 &uniqdisk)) || | |
319 (error = slice_on_similar_bus(slice, used, &samebus)) || | |
320 (error = slice_has_same_disk_geom(slice, used, &samegeom)); | |
321 if (error != 0) { | |
322 continue; | |
323 } | |
324 | |
325 if (verbose == B_TRUE) { | |
326 char *sname = NULL; | |
327 char *sizestr = NULL; | |
328 (void) get_display_name(slice, &sname); | |
329 if (bytes_to_sizestr(snbytes, &sizestr, | |
330 universal_units, B_FALSE) == 0) { | |
331 oprintf(OUTPUT_VERBOSE, look_msg, sname, sizestr); | |
332 free(sizestr); | |
333 } | |
334 } | |
335 | |
336 if (npaths > 1) { | |
337 if (paths && verbose) { | |
338 /* specifically asked for more paths, ... */ | |
339 oprintf(OUTPUT_VERBOSE, npaths_msg); | |
340 } | |
341 } else if (npaths == 1) { | |
342 /* every disk has at least 1 path */ | |
343 paths = B_TRUE; | |
344 } | |
345 | |
346 if (verbose == B_TRUE) { | |
347 if (uniqhba) { | |
348 oprintf(OUTPUT_VERBOSE, uniqhba_msg); | |
349 } | |
350 if (uniqdisk) { | |
351 oprintf(OUTPUT_VERBOSE, uniqdisk_msg); | |
352 } | |
353 | |
354 if (used != NULL) { | |
355 if (samebus) { | |
356 oprintf(OUTPUT_VERBOSE, samebus_msg); | |
357 } | |
358 if (samegeom) { | |
359 oprintf(OUTPUT_VERBOSE, samegeom_msg); | |
360 } | |
361 } | |
362 | |
363 if (snbytes > nbytes) { | |
364 oprintf(OUTPUT_VERBOSE, larger_msg); | |
365 } else if (snbytes == nbytes) { | |
366 oprintf(OUTPUT_VERBOSE, exact_msg); | |
367 } else { | |
368 oprintf(OUTPUT_VERBOSE, smaller_msg); | |
369 } | |
370 } | |
371 | |
372 /* filter slices not meeting minimum criteria */ | |
373 if (nbytes_is_min && (snbytes < nbytes)) { | |
374 /* not large enough */ | |
375 if (verbose == B_TRUE) { | |
376 oprintf(OUTPUT_VERBOSE, too_small); | |
377 } | |
378 continue; | |
379 } | |
380 | |
381 if (paths == B_FALSE) { | |
382 /* not connected thru enough paths */ | |
383 if (verbose == B_TRUE) { | |
384 oprintf(OUTPUT_VERBOSE, insuff_paths, npaths); | |
385 } | |
386 continue; | |
387 } | |
388 | |
389 if (uniqdisk != B_TRUE && unused_disk == TRUE) { | |
390 /* not on a unique disk */ | |
391 if (verbose == B_TRUE) { | |
392 oprintf(OUTPUT_VERBOSE, useddisk_msg); | |
393 } | |
394 continue; | |
395 } | |
396 | |
397 /* map slice properties into array indices */ | |
398 i = (uniqhba ? 0 : 1); | |
399 j = (samebus ? 0 : 1); | |
400 k = (uniqdisk ? 0 : 1); | |
401 l = (samegeom ? 0 : 1); | |
402 m = (snbytes == nbytes ? 0 : (snbytes > nbytes ? 1 : 2)); | |
403 | |
404 /* | |
405 * insert slice into the list array using derived indices. | |
406 * NB: lists of slices larger than necessary are kept in | |
407 * ascending order (results in best fit, not worst fit) | |
408 */ | |
409 if ((item = dlist_new_item((void*)(uintptr_t)slice)) == NULL) { | |
410 error = ENOMEM; | |
411 } else { | |
412 list[i][j][k][l][m] = | |
413 dlist_insert_ordered( | |
414 item, | |
415 list[i][j][k][l][m], | |
416 (m == 1 ? ASCENDING : DESCENDING), | |
417 compare_slice_sizes); | |
418 } | |
419 } | |
420 | |
421 /* | |
422 * Select a slice from one of the lists. | |
423 * | |
424 * The list with the combination of lowest indices | |
425 * is the most preferred list... in rough order: | |
426 * | |
427 * one on a unique HBA and disk that is of the exact size | |
428 * one on a unique HBA and disk that is of sufficient size (resize) | |
429 * one on unique HBA that is of the exact size | |
430 * one on unique HBA that is of sufficient size (resize) | |
431 * one on unique disk that is of the exact size | |
432 * one on unique disk that is of sufficient size (resize) | |
433 * one on any HBA that is of exact size | |
434 * one on any HBA that is of sufficient size (resize) | |
435 * one on a unique HBA that is the largest size | |
436 * one on a unique disk that is the largest size | |
437 * one on any HBA that is the largest size | |
438 */ | |
439 slice = NULL; | |
440 | |
441 for (i = 0; i < 2; i++) { | |
442 for (j = 0; j < 2; j++) { | |
443 for (k = 0; k < 2; k++) { | |
444 for (l = 0; l < 2; l++) { | |
445 for (m = 0; m < 3; m++) { | |
446 if (list[i][j][k][l][m] != NULL) { | |
447 | |
448 /* pick least used slice from this list */ | |
449 error = pick_from_best_hba_and_disk( | |
450 list[i][j][k][l][m], | |
451 used, &slice); | |
452 | |
453 resize = (m == 1); | |
454 | |
455 /* terminate all loops */ | |
456 goto stop; | |
457 } | |
458 } | |
459 } | |
460 } | |
461 } | |
462 } | |
463 stop: | |
464 | |
465 /* | |
466 * Slice chosen, is a resize necessary? | |
467 */ | |
468 if ((error == 0) && (slice != NULL)) { | |
469 | |
470 if (error == 0) { | |
471 if (verbose == B_TRUE) { | |
472 uint64_t snbytes = 0; | |
473 char *sname = NULL; | |
474 char *sizestr = NULL; | |
475 | |
476 (void) get_display_name(slice, &sname); | |
477 (void) slice_get_size(slice, &snbytes); | |
478 | |
479 if (bytes_to_sizestr(snbytes, &sizestr, | |
480 universal_units, B_FALSE) == 0) { | |
481 oprintf(OUTPUT_VERBOSE, | |
482 gettext(" selected %s (%s)\n" | |
483 " it is %s on a\n" | |
484 " %s (%s) and a\n" | |
485 " %s (%s)\n"), | |
486 sname, sizestr, | |
487 sizes[m], | |
488 uniqhba[i], samebus[j], | |
489 uniqdisk[k], samegeom[l]); | |
490 free(sizestr); | |
491 } | |
492 } | |
493 | |
494 if (resize) { | |
495 if (verbose == B_TRUE) { | |
496 oprintf(OUTPUT_VERBOSE, | |
497 gettext(" it has excess space, " | |
498 "resizing...\n")); | |
499 } | |
500 | |
501 error = create_new_slice(slice, nbytes, add_extra_cyl, | |
502 chosen); | |
503 if ((error == 0) && (*chosen != NULL) && verbose) { | |
504 oprintf(OUTPUT_VERBOSE, | |
505 gettext(" exactly resized\n")); | |
506 } | |
507 } | |
508 | |
509 if (error == 0) { | |
510 /* either no resize was necessary or the resize failed */ | |
511 if (*chosen == NULL) { | |
512 /* | |
513 * use the original slice as it is. | |
514 * Make a devconfig_t for it. | |
515 */ | |
516 error = create_devconfig_for_slice(slice, chosen); | |
517 } | |
518 } | |
519 } | |
520 } else if (slice == NULL) { | |
521 oprintf(OUTPUT_DEBUG, | |
522 gettext(" no possible slice\n")); | |
523 } | |
524 | |
525 for (i = 0; i < 2; i++) { | |
526 for (j = 0; j < 2; j++) { | |
527 for (k = 0; k < 2; k++) { | |
528 for (l = 0; l < 2; l++) { | |
529 for (m = 0; m < 3; m++) { | |
530 if (list[i][j][k][l][m] != NULL) { | |
531 dlist_free_items(list[i][j][k][l][m], NULL); | |
532 } | |
533 } | |
534 } | |
535 } | |
536 } | |
537 } | |
538 | |
539 return (error); | |
540 } | |
541 | |
542 /* | |
543 * FUNCTION: create_devconfig_for_slice(dm_descriptor_t slice, | |
544 * devconfig_t **nslice) | |
545 * | |
546 * INPUT: slice - dm_descriptor_t handle to an existing slice | |
547 * nslice - devconfig_t pointer to hold the new slice | |
548 * | |
549 * RETURNS: int - 0 on success | |
550 * !0 otherwise | |
551 * | |
552 * PURPOSE: Creates a devconfig_t struct representation of the input | |
553 * slice dm_descriptor. | |
554 */ | |
555 int | |
556 create_devconfig_for_slice( | |
557 dm_descriptor_t slice, | |
558 devconfig_t **nslice) | |
559 { | |
560 uint64_t nbytes = 0; | |
561 uint64_t nblks = 0; | |
562 uint64_t stblk = 0; | |
563 uint32_t index = 0; | |
564 char *name = NULL; | |
565 int error = 0; | |
566 | |
567 ((error = get_display_name(slice, &name)) != 0) || | |
568 (error = slice_get_size(slice, &nbytes)) || | |
569 (error = slice_get_size_in_blocks(slice, &nblks)) || | |
570 (error = slice_get_start_block(slice, &stblk)) || | |
571 (error = slice_get_index(slice, &index)); | |
572 if (error != 0) { | |
573 return (error); | |
574 } | |
575 | |
576 ((error = new_devconfig(nslice, TYPE_SLICE)) != 0) || | |
577 (error = devconfig_set_name(*nslice, name)) || | |
578 (error = devconfig_set_slice_index(*nslice, index)) || | |
579 (error = devconfig_set_slice_start_block(*nslice, stblk)) || | |
580 (error = devconfig_set_size_in_blocks(*nslice, nblks)) || | |
581 (error = devconfig_set_size(*nslice, nbytes)); | |
582 if (error != 0) { | |
583 free_devconfig(*nslice); | |
584 } | |
585 | |
586 return (error); | |
587 } | |
588 | |
589 /* | |
590 * FUNCTION: make_slicename_for_disk_and_index(dm_descriptor_t disk, | |
591 * uint32_t index, char **slicename) | |
592 * | |
593 * INPUT: disk - a dm_descriptor_t disk handle | |
594 * index - a slice index | |
595 * | |
596 * OUTPUT slicename - a char * pointer to hold the resulting slicename | |
597 * | |
598 * RETURNS: int - 0 on success | |
599 * !0 otherwise | |
600 * | |
601 * PURPOSE: Utility function to manufacture a new slice name given the | |
602 * "parent" disk and an available slice index. | |
603 * | |
604 * The caller should free the returned name when done with it. | |
605 */ | |
606 static int | |
607 make_slicename_for_disk_and_index( | |
608 dm_descriptor_t disk, | |
609 uint16_t index, | |
610 char **slicename) | |
611 { | |
612 char *dname; | |
613 int error = 0; | |
614 | |
615 if ((error = get_display_name(disk, &dname)) == 0) { | |
616 error = make_slicename_for_diskname_and_index(dname, | |
617 index, slicename); | |
618 } | |
619 | |
620 return (error); | |
621 } | |
622 | |
623 /* | |
624 * FUNCTION: make_slicename_for_diskname_and_index(char *diskname, | |
625 * uint32_t index, char **slicename) | |
626 * | |
627 * INPUT: diskname - a char * disk name | |
628 * index - a slice index | |
629 * | |
630 * OUTPUT slicename - a char * pointer to hold the resulting slicename | |
631 * | |
632 * RETURNS: int - 0 on success | |
633 * !0 otherwise | |
634 * | |
635 * PURPOSE: Utility function to manufacture a new slice name given the | |
636 * name of a disk and an available slice index. | |
637 * | |
638 * The caller should free the returned name when done with it. | |
639 */ | |
640 int | |
641 make_slicename_for_diskname_and_index( | |
642 char *diskname, | |
643 uint16_t index, | |
644 char **slicename) | |
645 { | |
646 int error = 0; | |
647 char buf[MAXNAMELEN+1]; | |
648 | |
649 (void) snprintf(buf, sizeof (buf), "%ss%u", diskname, index); | |
650 if ((*slicename = strdup(buf)) == NULL) { | |
651 *slicename = NULL; | |
652 error = ENOMEM; | |
653 } | |
654 | |
655 return (error); | |
656 } | |
657 | |
658 /* | |
659 * FUNCTION: create_new_slice(dm_descriptor_t oslice, uint64_t nbytes, | |
660 * boolean_t add_extra_cyl, devconfig_t **nslice) | |
661 * | |
662 * INPUT: oslice - dm_descriptor_t handle to an existing slice | |
663 * nbytes - desired minimum size of the new slice | |
664 * add_extra_cyl - boolean indicating whether the resized slice | |
665 * needs to be oversized by 1 cylinder to account for | |
666 * interlace rounding done for stripe components. | |
667 * nslice - devconfig_t pointer to hold the new slice | |
668 * | |
669 * RETURNS: int - 0 on success | |
670 * !0 otherwise | |
671 * | |
672 * PURPOSE: Creates a new slice object using space from the input slice. | |
673 * | |
674 * If there is an open slice slot in the disk VTOC, it will be | |
675 * reserved for the new slice. Space for the new slice will be | |
676 * taken from the original slice. | |
677 * | |
678 * If there is no open slice slot, the original slice will be | |
679 * returned as the usable new slice. | |
680 * | |
681 * The new slice will be of at least 'nbytes' bytes and possibly | |
682 * larger due to sector and cylinder boundary alignment. | |
683 * | |
684 * For EFI labeled disks, nbytes is rounded up to the next block | |
685 * boundary. | |
686 * | |
687 * For VTOC labeled disks, nbytes is rounded up to the next | |
688 * cylinder boundary. | |
689 * | |
690 * Additionally, if add_extra_cyl is true, the new slice will be | |
691 * made 1 cylinder larger than necessary. This accounts for the | |
692 * interlace rounding done within libmeta when computing the | |
693 * usable size of stripe components on disks with VTOC labels. | |
694 * Rounding the size up to the next cylinder boundary is not | |
695 * sufficient because libmeta will round this size down to an | |
696 * integral multiple of the stripe interlace and then round that | |
697 * result down to a cylinder boundary. This makes the usable | |
698 * size of the slice one cylinder smaller and possibly less than | |
699 * nbytes. Adding an extra cylinder ensures the usable size is | |
700 * greater than nbytes despite the rounding. | |
701 * | |
702 * If the resize is successful a pointer to the devconfig_t | |
703 * representing the new slice will be returned in "newslice". | |
704 * | |
705 * If the resize cannot be done, the newslice pointer will | |
706 * be NULL. | |
707 */ | |
708 static int | |
709 create_new_slice( | |
710 dm_descriptor_t oslice, | |
711 uint64_t nbytes, | |
712 boolean_t add_extra_cyl, | |
713 devconfig_t **nslice) | |
714 { | |
715 dm_descriptor_t odisk = NULL; | |
716 boolean_t efi = B_FALSE; | |
717 | |
718 char *oname = NULL; | |
719 uint64_t osize = 0; /* orig size (bytes) */ | |
720 uint64_t ostart = 0; /* orig start (byte) */ | |
721 uint64_t ostblk = 0; /* orig start (blk) */ | |
722 uint64_t nsize = 0; /* new size (bytes) */ | |
723 uint64_t bytes_per_sect = 0; | |
724 | |
725 uint32_t oindex = 0; | |
726 uint32_t nindex = oindex; | |
727 | |
728 int error = 0; | |
729 | |
730 *nslice = NULL; | |
731 | |
732 ((error = slice_get_disk(oslice, &odisk)) != 0) || | |
733 (error = slice_get_index(oslice, &oindex)); | |
734 if (error != 0) { | |
735 return (error); | |
736 } | |
737 | |
738 /* find an unused slice number, default to oindex */ | |
739 nindex = oindex; | |
740 if ((error = disk_get_available_slice_index(odisk, &nindex)) != 0) { | |
741 return (error); | |
742 } | |
743 | |
744 ((error = get_display_name(oslice, &oname)) != 0) || | |
745 (error = slice_get_size(oslice, &osize)) || | |
746 (error = slice_get_start(oslice, &ostart)) || | |
747 (error = slice_get_start_block(oslice, &ostblk)) || | |
748 (error = disk_get_is_efi(odisk, &efi)) || | |
749 (error = disk_get_blocksize(odisk, &bytes_per_sect)); | |
750 if (error != 0) { | |
751 return (error); | |
752 } | |
753 | |
754 if (efi) { | |
755 | |
756 /* EFI: round size to an integral number of blocks (sectors) */ | |
757 nsize = bytes_per_sect * | |
758 ((nbytes + (bytes_per_sect - 1)) / bytes_per_sect); | |
759 | |
760 oprintf(OUTPUT_DEBUG, | |
761 gettext(" " | |
762 "rounded up to %10.2f blocks\n"), | |
763 (double)(nsize/bytes_per_sect)); | |
764 | |
765 } else { | |
766 | |
767 /* VTOC: round size to an integral number of cylinders */ | |
768 uint64_t nhead = 0; | |
769 uint64_t nsect = 0; | |
770 uint64_t ncyls = 0; | |
771 | |
772 ((error = disk_get_ncylinders(odisk, &ncyls)) != 0) || | |
773 (error = disk_get_nheads(odisk, &nhead)) || | |
774 (error = disk_get_nsectors(odisk, &nsect)); | |
775 if (error == 0) { | |
776 uint64_t bytes_per_cyl = nhead * nsect * bytes_per_sect; | |
777 nsize = bytes_per_cyl * | |
778 ((nbytes + (bytes_per_cyl - 1)) / bytes_per_cyl); | |
779 | |
780 if (add_extra_cyl == TRUE) { | |
781 nsize += bytes_per_cyl; | |
782 } | |
783 | |
784 oprintf(OUTPUT_DEBUG, | |
785 gettext(" " | |
786 "rounded VTOC slice to %10.2f cylinders " | |
787 "(out of %llu)\n"), | |
788 (double)(nsize/bytes_per_cyl), ncyls); | |
789 } | |
790 } | |
791 | |
792 /* is sufficient space still available? */ | |
793 if (error == 0) { | |
794 if (osize == nsize) { | |
795 /* use existing slice as is */ | |
796 ((error = create_devconfig_for_slice(oslice, nslice)) != 0) || | |
797 (error = disk_reserve_index(odisk, (uint16_t)nindex)); | |
798 } else if (osize > nsize) { | |
799 | |
800 if (nindex == oindex) { | |
801 /* no more slices, resize existing slice */ | |
802 ((error = create_devconfig_for_slice(oslice, | |
803 nslice)) != 0) || | |
804 (error = devconfig_set_size(*nslice, nsize)) || | |
805 (error = devconfig_set_size_in_blocks(*nslice, | |
806 nsize/bytes_per_sect)); | |
807 (error = disk_reserve_index(odisk, (uint16_t)nindex)); | |
808 | |
809 } else { | |
810 /* make a new slice */ | |
811 char *nname = NULL; | |
812 | |
813 ((error = make_slicename_for_disk_and_index(odisk, | |
814 nindex, &nname)) != 0) || | |
815 (error = create_modified_slice(oslice, oname, oindex, | |
816 ostart, osize, bytes_per_sect, nname, nindex, nsize, | |
817 nslice)) || | |
818 /* mark the new slice's index as used */ | |
819 (error = disk_reserve_index(odisk, (uint16_t)nindex)); | |
820 | |
821 if ((error != 0) && (*nslice == NULL)) { | |
822 free(nname); | |
823 } | |
824 } | |
825 } | |
826 } | |
827 | |
828 return (error); | |
829 } | |
830 | |
831 /* | |
832 * FUNCTION: create_modified_slice(dm_descriptor_t oslice, char *oname, | |
833 * uint32_t oindex, uint64_t ostart, uint64_t osize, | |
834 * uint64_t bytes_per_sect, uint64_t nsize, | |
835 * char *nname, uint32_t nindex, devconfig_t **nslice) | |
836 * | |
837 * INPUT: oslice - dm_descriptor_t handle for the original slice | |
838 * oname - existing source slice name | |
839 * oindex - existing source slice VTOC index | |
840 * ostart - existing source slice start byte | |
841 * osize - existing source slice size in bytes | |
842 * bytes_per_sect - bytes per block (sector) for the disk | |
843 * nname - new slice name | |
844 * nindex - new slice VTOC index | |
845 * nsize - new slice size in bytes (cylinder and block aligned) | |
846 * | |
847 * SIDEEFFECTS: updates the module private list of modified slices | |
848 * | |
849 * OUTPUT: nslice - pointer to a devconfig_t to hold the new slice | |
850 * | |
851 * PURPOSE: create a new VTOC slice by taking space from an | |
852 * existing slice. | |
853 * | |
854 * The input size for the new slice is expected to be | |
855 * cylinder aligned. | |
856 */ | |
857 static int | |
858 create_modified_slice( | |
859 dm_descriptor_t oslice, | |
860 char *oname, | |
861 uint32_t oindex, | |
862 uint64_t ostart, | |
863 uint64_t osize, | |
864 uint64_t bytes_per_sect, | |
865 char *nname, | |
866 uint32_t nindex, | |
867 uint64_t nsize, | |
868 devconfig_t **nslice) | |
869 { | |
870 int error = 0; | |
871 | |
872 /* compute start sector and size in sectors for the new slice */ | |
873 | |
874 /* subtract nsize from original slice to get starting byte */ | |
875 uint64_t nstart = (ostart + osize) - nsize; | |
876 | |
877 /* convert starting byte to a sector */ | |
878 uint64_t nstblk = (uint64_t)(nstart / bytes_per_sect); | |
879 | |
880 /* convert nsize to an integral number of blocks (sectors) */ | |
881 uint64_t nblks = (uint64_t)(nsize / bytes_per_sect); | |
882 | |
883 /* create a modified slice record for the new slice */ | |
884 error = assemble_modified_slice(oslice, nname, nindex, | |
885 nstblk, nblks, nsize, nslice); | |
886 if (error != 0) { | |
887 free(nname); | |
888 return (error); | |
889 } | |
890 | |
891 /* update the existing source slice's new size */ | |
892 osize = osize - nsize; | |
893 (void) slice_set_size(oslice, osize); | |
894 | |
895 /* update/create the modified slice record gfor the source slice */ | |
896 error = assemble_modified_slice((dm_descriptor_t)0, | |
897 oname, oindex, (uint64_t)(ostart / bytes_per_sect), | |
898 (uint64_t)(osize / bytes_per_sect), | |
899 osize, NULL); | |
900 | |
901 return (error); | |
902 } | |
903 | |
904 /* | |
905 * FUNCTION: assemble_modified_slice(dm_descriptor_t src_slice, | |
906 * char *mod_name, uint32_t mod_index, | |
907 * uint64_t mod_stblk, uint64_t mod_nblks, | |
908 * uint64_t mod_size, devconfig_t **modslice) | |
909 * | |
910 * INPUT: src_slice - dm_descriptor_t handle of the slice space | |
911 * was taken from to create the modified slice | |
912 * mod_name - name of the modified slice | |
913 * mod_index - name of the modified slice | |
914 * mod_stblk - start block of the modified slice | |
915 * mod_nblks - size in blocks of the modified slice | |
916 * mod_size - size in bytes of the modified slice | |
917 * | |
918 * OUTPUT: mod_slice - if non-NULL, will be populated with a | |
919 * devconfig_t representing the modified slice. | |
920 * | |
921 * SIDEEFFECTS: adds or updates an entry in the modified slice list | |
922 * tracking the slices that have been explicitly modified | |
923 * by the layout code. | |
924 * | |
925 * RETURNS: int - 0 on success | |
926 * !0 otherwise | |
927 * | |
928 * PURPOSE: Utility function to which updates or creates a devconfig_t | |
929 * representing a slice that needs to be modified. | |
930 * | |
931 * If a modified slice record does not exist for the named | |
932 * slice, a new devconfig_t struct is allocated and added | |
933 * to the modified slice list. | |
934 * | |
935 * The existing or created devconfig_t struct is updated with | |
936 * the input values. | |
937 * | |
938 * The information about the slices in the modified slice list | |
939 * will eventually be handed to fmthard. | |
940 */ | |
941 int | |
942 assemble_modified_slice( | |
943 dm_descriptor_t src_slice, | |
944 char *mod_name, | |
945 uint32_t mod_index, | |
946 uint64_t mod_stblk, | |
947 uint64_t mod_nblks, | |
948 uint64_t mod_size, | |
949 devconfig_t **mod_slice) | |
950 { | |
951 devconfig_t *slice = NULL; | |
952 modslice_t *mstp = NULL; | |
953 dlist_t *item = NULL; | |
954 int error = 0; | |
955 | |
956 /* see if the slice has been modified before */ | |
957 if ((item = dlist_find(_modified_slices, mod_name, | |
958 compare_string_to_modslice_name)) != NULL) { | |
959 | |
960 /* yes, update the resize count and attributes */ | |
961 mstp = (modslice_t *)item->obj; | |
962 slice = mstp->slice_devcfg; | |
963 | |
964 mstp->times_modified += 1; | |
965 mstp->src_slice_desc = src_slice; | |
966 | |
967 ((error = devconfig_set_slice_start_block(slice, | |
968 mod_stblk)) != 0) || | |
969 (error = devconfig_set_size(slice, mod_size)) || | |
970 (error = devconfig_set_size_in_blocks(slice, mod_nblks)); | |
971 | |
972 } else { | |
973 | |
974 /* no, first modification... */ | |
975 /* create a devconfig_t representing the new slice */ | |
976 ((error = new_devconfig(&slice, TYPE_SLICE)) != 0) || | |
977 (error = devconfig_set_name(slice, mod_name)) || | |
978 (error = devconfig_set_slice_index(slice, mod_index)) || | |
979 (error = devconfig_set_slice_start_block(slice, mod_stblk)) || | |
980 (error = devconfig_set_size_in_blocks(slice, mod_nblks)) || | |
981 (error = devconfig_set_size(slice, mod_size)); | |
982 if (error == 0) { | |
983 /* add to list of modified slices */ | |
984 if ((mstp = (modslice_t *) | |
985 calloc(1, sizeof (modslice_t))) != NULL) { | |
986 | |
987 /* count # of times source slice has been modified */ | |
988 if (src_slice != (dm_descriptor_t)0) { | |
989 mstp->times_modified = 0; | |
990 } else { | |
991 mstp->times_modified = 1; | |
992 } | |
993 mstp->src_slice_desc = src_slice; | |
994 mstp->slice_devcfg = slice; | |
995 | |
996 if ((item = dlist_new_item(mstp)) != NULL) { | |
997 _modified_slices = | |
998 dlist_insert_ordered( | |
999 item, | |
1000 _modified_slices, | |
1001 ASCENDING, | |
1002 compare_modslice_names); | |
1003 } else { | |
1004 error = ENOMEM; | |
1005 } | |
1006 } else { | |
1007 error = ENOMEM; | |
1008 } | |
1009 } | |
1010 | |
1011 if (error != 0) { | |
1012 free_devconfig(mstp); | |
1013 free_devconfig(slice); | |
1014 } | |
1015 } | |
1016 | |
1017 if (error == 0) { | |
1018 oprintf(OUTPUT_DEBUG, | |
1019 " " | |
1020 "modified %s (start blk: %9llu, nblks: %9llu)\n", | |
1021 mod_name, mod_stblk, mod_nblks); | |
1022 | |
1023 /* return devconfig_t for modified slice */ | |
1024 if (mod_slice != NULL) { | |
1025 *mod_slice = slice; | |
1026 mstp->volume_component = B_TRUE; | |
1027 } | |
1028 } | |
1029 | |
1030 return (error); | |
1031 } | |
1032 | |
1033 /* | |
1034 * FUNCTION: dlist_t *get_modified_slices() | |
1035 * | |
1036 * RETURNS: pointer to the list of modslice_t structs representing | |
1037 * modified slices | |
1038 * | |
1039 * PURPOSE: public accessor to the list of slices modified while | |
1040 * processing a request. | |
1041 */ | |
1042 dlist_t * | |
1043 get_modified_slices() | |
1044 { | |
1045 return (_modified_slices); | |
1046 } | |
1047 | |
1048 /* | |
1049 * FUNCTION: free_modslice_object(void *obj) | |
1050 * | |
1051 * INPUT: obj - opaque pointer | |
1052 * | |
1053 * PURPOSE: Frees memory associated with a modslice_t struct. | |
1054 */ | |
1055 static void | |
1056 free_modslice_object( | |
1057 void *obj) | |
1058 { | |
1059 assert(obj != (modslice_t *)NULL); | |
1060 | |
1061 if (((modslice_t *)obj)->slice_devcfg != NULL) { | |
1062 if (((modslice_t *)obj)->volume_component != B_TRUE) { | |
1063 free_devconfig(((modslice_t *)obj)->slice_devcfg); | |
1064 } | |
1065 } | |
1066 | |
1067 free(obj); | |
1068 } | |
1069 | |
1070 /* | |
1071 * FUNCTION: void release_modified_slices() | |
1072 * | |
1073 * INPUT: none - | |
1074 * OUTPUT: none - | |
1075 * | |
1076 * PURPOSE: cleanup the module global list of slices modified | |
1077 * while processing a request. | |
1078 */ | |
1079 int | |
1080 release_modified_slices() | |
1081 { | |
1082 dlist_free_items(_modified_slices, free_modslice_object); | |
1083 _modified_slices = NULL; | |
1084 | |
1085 return (0); | |
1086 } | |
1087 | |
1088 /* | |
1089 * FUNCTION: destroy_new_slice(devconfig_t *dev) | |
1090 * | |
1091 * INPUT: dev - a devconfig_t pointer to a slice object | |
1092 * | |
1093 * RETURNS: int - 0 on success | |
1094 * !0 otherwise | |
1095 * | |
1096 * PURPOSE: Undoes slice creation done by create_new_slice(): | |
1097 * | |
1098 * release index | |
1099 * remove from used_slices | |
1100 * remove from modified_slices | |
1101 * return space to source slice | |
1102 * free memory | |
1103 */ | |
1104 int | |
1105 destroy_new_slice( | |
1106 devconfig_t *dev) | |
1107 { | |
1108 dm_descriptor_t disk = NULL; | |
1109 uint64_t size = 0; | |
1110 uint16_t index = 0; | |
1111 modslice_t *modified = NULL; | |
1112 dlist_t *item = NULL; | |
1113 char *name = NULL; | |
1114 int error = 0; | |
1115 | |
1116 ((error = devconfig_get_name(dev, &name)) != 0) || | |
1117 (error = devconfig_get_slice_index(dev, &index)) || | |
1118 (error = devconfig_get_size(dev, &size)) || | |
1119 (error = get_disk_for_named_slice(name, &disk)) || | |
1120 (error = disk_release_index(disk, index)) || | |
1121 (error = remove_used_slice_by_name(name)); | |
1122 if (error != 0) { | |
1123 return (error); | |
1124 } | |
1125 | |
1126 /* remove from the modified_slices list */ | |
1127 _modified_slices = | |
1128 dlist_remove_equivalent_item( | |
1129 _modified_slices, name, | |
1130 compare_string_to_modslice_name, &item); | |
1131 | |
1132 if (item != NULL) { | |
1133 modified = (modslice_t *)item->obj; | |
1134 free((void*) item); | |
1135 } | |
1136 | |
1137 /* space from an existing slice? if so reclaim it. */ | |
1138 if (modified != NULL) { | |
1139 | |
1140 dm_descriptor_t src = modified->src_slice_desc; | |
1141 char *srcname = NULL; | |
1142 dlist_t *srcitem = NULL; | |
1143 | |
1144 if (src != (dm_descriptor_t)0) { | |
1145 if ((error = get_display_name(src, &srcname)) == 0) { | |
1146 srcitem = | |
1147 dlist_find( | |
1148 _modified_slices, | |
1149 srcname, | |
1150 compare_string_to_modslice_name); | |
1151 } | |
1152 } | |
1153 | |
1154 if ((error == 0) && (srcitem != NULL)) { | |
1155 | |
1156 modslice_t *source = (modslice_t *)srcitem->obj; | |
1157 devconfig_t *srcdevcfg = NULL; | |
1158 uint64_t srcsize = NULL; | |
1159 uint64_t srcsizeblks = NULL; | |
1160 uint64_t inblks = NULL; | |
1161 | |
1162 srcdevcfg = source->slice_devcfg; | |
1163 source->times_modified -= 1; | |
1164 | |
1165 ((error = devconfig_get_size(srcdevcfg, &srcsize)) != 0) || | |
1166 (error = devconfig_set_size(srcdevcfg, srcsize + size)) || | |
1167 (error = slice_set_size(src, srcsize + size)) || | |
1168 (error = slice_get_size_in_blocks(src, &srcsizeblks)) || | |
1169 (error = devconfig_get_size_in_blocks(srcdevcfg, &inblks)); | |
1170 (error = devconfig_set_size_in_blocks(srcdevcfg, srcsizeblks)); | |
1171 | |
1172 if (error == 0) { | |
1173 | |
1174 /* was only modification undone? */ | |
1175 if (source->times_modified == 0) { | |
1176 | |
1177 _modified_slices = | |
1178 dlist_remove_equivalent_item( | |
1179 _modified_slices, srcname, | |
1180 compare_string_to_modslice_name, | |
1181 &srcitem); | |
1182 | |
1183 free_modslice_object((modslice_t *)srcitem->obj); | |
1184 free((void *)srcitem); | |
1185 } | |
1186 } | |
1187 } | |
1188 | |
1189 free_modslice_object(modified); | |
1190 } | |
1191 | |
1192 return (error); | |
1193 } | |
1194 | |
1195 /* | |
1196 * FUNCTION: pick_from_best_hba_and_disk(dlist_t *slices, | |
1197 * dlist_t *used, dm_descriptor_t *chosen) | |
1198 * | |
1199 * INPUT: slices - a dlist_t poitner to a list of slices | |
1200 * used - a dlist_t pointer to a list of used slices | |
1201 * chosen - a dm_descriptor_t pointer to hold the result | |
1202 * | |
1203 * RETURNS: int - 0 on success | |
1204 * !0 otherwise | |
1205 * | |
1206 * PURPOSE: Examines the input list of slices and chooses the one | |
1207 * that is on the least used HBA and disk. | |
1208 * | |
1209 * HBA and disk usage is determined by examining the input | |
1210 * list of used slices and counting the number of slices | |
1211 * each HBA and disk contributes. | |
1212 * | |
1213 * The HBA which contributes the fewest is selected, and | |
1214 * then the disk on that HBA which contributes the fewest | |
1215 * is selected. | |
1216 * | |
1217 * The largest slice from that disk is then returned. | |
1218 */ | |
1219 static int | |
1220 pick_from_best_hba_and_disk( | |
1221 dlist_t *slices, | |
1222 dlist_t *used, | |
1223 dm_descriptor_t *chosen) | |
1224 { | |
1225 dlist_t *iter = NULL; | |
1226 dlist_t *iter1 = NULL; | |
1227 dlist_t *iter2 = NULL; | |
1228 dlist_t *item = NULL; | |
1229 | |
1230 dlist_t *used_slice_hbas = NULL; | |
1231 | |
1232 int maxuses = 128; | |
1233 int maxslices = VTOC_SIZE; /* meta.h */ | |
1234 | |
1235 int i = 0; | |
1236 int error = 0; | |
1237 | |
1238 /* | |
1239 * allocate an array to hold lists of slices grouped by | |
1240 * HBA contribution... the list indexed by N is the list | |
1241 * of slices that are on HBAs contributing N slices | |
1242 */ | |
1243 dlist_t **prefhbas = (dlist_t **)calloc(maxuses, sizeof (dlist_t *)); | |
1244 | |
1245 /* | |
1246 * allocate an array to hold lists of slices grouped by | |
1247 * disk contribution... the list indexed by N is the list | |
1248 * of slices that are on disks contributing N slices | |
1249 */ | |
1250 dlist_t **prefdisks = (dlist_t **)calloc(maxslices, sizeof (dlist_t *)); | |
1251 | |
1252 *chosen = (dm_descriptor_t)0; | |
1253 | |
1254 if (prefhbas == NULL || prefdisks == NULL) { | |
1255 free(prefhbas); | |
1256 free(prefdisks); | |
1257 return (ENOMEM); | |
1258 } | |
1259 | |
1260 /* | |
1261 * precompute the used slices' lists of HBAS: iterate the list | |
1262 * of used slices and determine the HBA(s) each is connected thru. | |
1263 * construct a list of lists containing the HBAs. | |
1264 */ | |
1265 for (iter = used; | |
1266 (iter != NULL) && (error == 0); | |
1267 iter = iter->next) { | |
1268 | |
1269 devconfig_t *uslice = (devconfig_t *)iter->obj; | |
1270 dm_descriptor_t udisk = NULL; | |
1271 char *uname = NULL; | |
1272 dlist_t *uhbas = NULL; | |
1273 | |
1274 /* need to use disk to get to HBAs because */ | |
1275 /* the slice doesn't exist yet */ | |
1276 ((error = devconfig_get_name(uslice, &uname)) != 0) || | |
1277 (error = get_disk_for_named_slice(uname, &udisk)) || | |
1278 (error = disk_get_hbas(udisk, &uhbas)); | |
1279 if (error == 0) { | |
1280 if ((item = dlist_new_item((void *)uhbas)) == NULL) { | |
1281 error = ENOMEM; | |
1282 } else { | |
1283 used_slice_hbas = dlist_append( | |
1284 item, used_slice_hbas, AT_HEAD); | |
1285 } | |
1286 } | |
1287 } | |
1288 | |
1289 /* | |
1290 * iterate the list of chosen slices and for each, | |
1291 * determine how many other slices from its HBA(s) | |
1292 * are already being used... | |
1293 * | |
1294 * iter steps thru the list of slices | |
1295 * iter1 steps thru each of the slice's HBAs | |
1296 * iter2 steps thru the precomputed list of used slice's HBAs | |
1297 * dlist_contains then searches each used slice's HBAs | |
1298 * to see if it contains iter1's HBA | |
1299 * | |
1300 * If it does, increment the count for that HBA. | |
1301 */ | |
1302 for (iter = slices; | |
1303 (iter != NULL) && (error == 0); | |
1304 iter = iter->next) { | |
1305 | |
1306 dm_descriptor_t slice = (uintptr_t)iter->obj; | |
1307 dlist_t *hbas = NULL; | |
1308 int n = 0; /* # slices each HBA contributes */ | |
1309 | |
1310 if ((error = slice_get_hbas(slice, &hbas)) != 0) { | |
1311 continue; | |
1312 } | |
1313 | |
1314 for (iter1 = hbas; iter1 != NULL; iter1 = iter1->next) { | |
1315 for (iter2 = used_slice_hbas; iter2 != NULL; | |
1316 iter2 = iter2->next) { | |
1317 | |
1318 dlist_t *uhbas = (dlist_t *)iter2->obj; | |
1319 if (dlist_contains(uhbas, iter1->obj, | |
1320 compare_descriptor_names) == B_TRUE) { | |
1321 n++; | |
1322 } | |
1323 } | |
1324 } | |
1325 | |
1326 dlist_free_items(hbas, NULL); | |
1327 | |
1328 /* group slices from HBAs contributing more than maxuses */ | |
1329 if (n >= maxuses) { | |
1330 n = maxuses - 1; | |
1331 } | |
1332 | |
1333 /* add slice to list in descending size order */ | |
1334 if ((item = dlist_new_item((void*)(uintptr_t)slice)) == NULL) { | |
1335 error = ENOMEM; | |
1336 } else { | |
1337 prefhbas[n] = | |
1338 dlist_insert_ordered( | |
1339 item, | |
1340 prefhbas[n], | |
1341 DESCENDING, | |
1342 compare_slice_sizes); | |
1343 } | |
1344 } | |
1345 | |
1346 /* free list of lists of used slices HBAs */ | |
1347 for (iter = used_slice_hbas; iter != NULL; iter = iter->next) { | |
1348 dlist_free_items((dlist_t *)iter->obj, NULL); | |
1349 } | |
1350 dlist_free_items(used_slice_hbas, NULL); | |
1351 | |
1352 /* | |
1353 * Select the list of slices that are on the HBA(s) contributing | |
1354 * the fewest slices... iterate these slices and for each, detemmine | |
1355 * how many other slices from its disk are already being used... | |
1356 */ | |
1357 for (i = 0; (i < maxuses) && (error == 0); i++) { | |
1358 | |
1359 for (iter = (dlist_t *)prefhbas[i]; | |
1360 (iter != NULL) && (error == 0); | |
1361 iter = iter->next) { | |
1362 | |
1363 dm_descriptor_t slice = (uintptr_t)iter->obj; | |
1364 dm_descriptor_t disk; | |
1365 int n = 0; | |
1366 | |
1367 (void) slice_get_disk(slice, &disk); | |
1368 | |
1369 /* | |
1370 * count how many slices this slice's disk is contributing | |
1371 * by comparing it to the list of used slices | |
1372 */ | |
1373 for (iter1 = _used_slices; iter1 != NULL; iter1 = iter1->next) { | |
1374 usedslice_t *used = (usedslice_t *)iter1->obj; | |
1375 if (compare_descriptors((void *)(uintptr_t)disk, | |
1376 (void *)(uintptr_t)used->disk) == 0) { | |
1377 n++; | |
1378 } | |
1379 } | |
1380 | |
1381 /* add slice to list in descending size order */ | |
1382 if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) { | |
1383 error = ENOMEM; | |
1384 } else { | |
1385 prefdisks[n] = | |
1386 dlist_insert_ordered( | |
1387 item, | |
1388 prefdisks[n], | |
1389 DESCENDING, | |
1390 compare_slice_sizes); | |
1391 } | |
1392 } | |
1393 } | |
1394 | |
1395 if (error == 0) { | |
1396 /* select largest slice from least used disk */ | |
1397 for (i = 0; (i < maxslices) && (*chosen == NULL); i++) { | |
1398 if (prefdisks[i] != NULL) { | |
1399 *chosen = (uintptr_t)prefdisks[i]->obj; | |
1400 } | |
1401 } | |
1402 } | |
1403 | |
1404 for (i = 0; i < maxuses; i++) { | |
1405 dlist_free_items(prefhbas[i], NULL); | |
1406 } | |
1407 for (i = 0; i < maxslices; i++) { | |
1408 dlist_free_items(prefdisks[i], NULL); | |
1409 } | |
1410 | |
1411 free((void*)prefhbas); | |
1412 free((void*)prefdisks); | |
1413 | |
1414 return (error); | |
1415 } | |
1416 | |
1417 /* | |
1418 * FUNCTION: slice_on_unique_hba(dm_descriptor_t slice, | |
1419 * dlist_t *used, dlist_t *used_hbas, | |
1420 * boolean_t *unique) | |
1421 * | |
1422 * INPUT: slice - a dm_descriptor_t handle for the slice of interest | |
1423 * used - a dlist_t pointer to a list of used slices | |
1424 * used_hbas - a dlist_t pointer to a list of used_hbas | |
1425 * unique - a boolean_t pointer to hold the result | |
1426 * | |
1427 * RETURNS: int - 0 on success | |
1428 * !0 otherwise | |
1429 * | |
1430 * PURPOSE: Determines if the input slice is connected thru the same HBA | |
1431 * as a slice in the used list. | |
1432 * | |
1433 * Also checks to see if the input slice is connected thru any | |
1434 * HBA in the used_hbas list. | |
1435 * | |
1436 * If the slice is found to be on a unique HBA, bool is set | |
1437 * to B_TRUE, B_FALSE otherwise. | |
1438 */ | |
1439 static int | |
1440 slice_on_unique_hba( | |
1441 dm_descriptor_t slice, | |
1442 dlist_t *used, | |
1443 dlist_t *used_hbas, | |
1444 boolean_t *unique) | |
1445 { | |
1446 dlist_t *iter = NULL; | |
1447 dlist_t *iter1 = NULL; | |
1448 | |
1449 dlist_t *hbas = NULL; | |
1450 | |
1451 int error = 0; | |
1452 | |
1453 *unique = B_TRUE; | |
1454 | |
1455 if ((error = slice_get_hbas(slice, &hbas)) != 0) { | |
1456 return (error); | |
1457 } | |
1458 | |
1459 /* | |
1460 * check to see if any of slice's HBAs is the same | |
1461 * as the HBA for any of the used | |
1462 */ | |
1463 for (iter = used; | |
1464 (iter != NULL) && (*unique == B_TRUE) && (error == 0); | |
1465 iter = iter->next) { | |
1466 | |
1467 devconfig_t *dev = (devconfig_t *)iter->obj; | |
1468 if (devconfig_isA(dev, TYPE_SLICE)) { | |
1469 | |
1470 dm_descriptor_t odisk = NULL; | |
1471 char *oname = NULL; | |
1472 dlist_t *ohbas = NULL; | |
1473 | |
1474 /* get HBAs for other slice using its disk */ | |
1475 /* because the slice doesn't exist yet. */ | |
1476 ((error = devconfig_get_name(dev, &oname)) != 0) || | |
1477 (error = get_disk_for_named_slice(oname, &odisk)) || | |
1478 (error = disk_get_hbas(odisk, &ohbas)); | |
1479 | |
1480 /* any HBA overlap? */ | |
1481 for (iter1 = hbas; | |
1482 (iter1 != NULL) && (*unique == B_TRUE) && (error == 0); | |
1483 iter1 = iter1->next) { | |
1484 | |
1485 if (dlist_contains(ohbas, iter1->obj, | |
1486 compare_descriptor_names) == B_TRUE) { | |
1487 *unique = B_FALSE; | |
1488 } | |
1489 } | |
1490 dlist_free_items(ohbas, NULL); | |
1491 } | |
1492 } | |
1493 | |
1494 /* | |
1495 * check to see if any of slice's HBAs is the contained | |
1496 * in the list of used hbas | |
1497 */ | |
1498 for (iter = hbas; | |
1499 (iter != NULL) && (*unique == B_TRUE) && (error == 0); | |
1500 iter = iter->next) { | |
1501 if (dlist_contains(used_hbas, | |
1502 iter->obj, compare_descriptor_names) == B_TRUE) { | |
1503 *unique = B_FALSE; | |
1504 } | |
1505 } | |
1506 | |
1507 dlist_free_items(hbas, NULL); | |
1508 | |
1509 return (error); | |
1510 } | |
1511 | |
1512 /* | |
1513 * FUNCTION: slice_on_unique_disk(dm_descriptor_t slice, | |
1514 * dlist_t *used, dlist_t *used_disks, | |
1515 * boolean_t *unique) | |
1516 * | |
1517 * INPUT: slice - a dm_descriptor_t handle for the slice of interest | |
1518 * used - a dlist_t pointer to a list of used slices | |
1519 * othervols - a dlist_t pointer to a list of other volumes | |
1520 * bool - a boolean_t pointer to hold the result | |
1521 * | |
1522 * RETURNS: int - 0 on success | |
1523 * !0 otherwise | |
1524 * | |
1525 * PURPOSE: Determines if the input slice is on a drive that is not | |
1526 * part of any volume in the othervols list, or on the same | |
1527 * drive as any slice in the used list. | |
1528 * | |
1529 * If the slice is found to be on a unique disk, bool is set | |
1530 * to B_TRUE, B_FALSE otherwise. | |
1531 */ | |
1532 static int | |
1533 slice_on_unique_disk( | |
1534 dm_descriptor_t slice, | |
1535 dlist_t *used, | |
1536 dlist_t *used_disks, | |
1537 boolean_t *unique) | |
1538 { | |
1539 dm_descriptor_t disk = NULL; | |
1540 dlist_t *iter = NULL; | |
1541 int error = 0; | |
1542 | |
1543 *unique = B_TRUE; | |
1544 | |
1545 if ((error = slice_get_disk(slice, &disk)) != 0) { | |
1546 return (error); | |
1547 } | |
1548 | |
1549 /* | |
1550 * check to see if this disk is the same as the | |
1551 * disk for any of the used | |
1552 */ | |
1553 for (iter = used; | |
1554 (iter != NULL) && (*unique == B_TRUE) && (error == 0); | |
1555 iter = iter->next) { | |
1556 | |
1557 devconfig_t *dev = (devconfig_t *)iter->obj; | |
1558 | |
1559 if (devconfig_isA(dev, TYPE_SLICE)) { | |
1560 | |
1561 /* get disk for otherslice */ | |
1562 dm_descriptor_t odisk = NULL; | |
1563 char *oname = NULL; | |
1564 | |
1565 ((error = devconfig_get_name(dev, &oname)) != 0) || | |
1566 (error = get_disk_for_named_slice(oname, &odisk)); | |
1567 | |
1568 if ((error == 0) && | |
1569 (compare_descriptor_names((void*)(uintptr_t)disk, | |
1570 (void*)(uintptr_t)odisk) == 0)) { | |
1571 /* origslice is on same disk, stop */ | |
1572 *unique = B_FALSE; | |
1573 } | |
1574 } | |
1575 } | |
1576 | |
1577 /* check disk against the used disks */ | |
1578 if ((error == 0) && (*unique == B_TRUE) && | |
1579 dlist_contains(used_disks, (void *)(uintptr_t)disk, | |
1580 compare_descriptor_names) == B_TRUE) { | |
1581 *unique = B_FALSE; | |
1582 } | |
1583 | |
1584 return (error); | |
1585 } | |
1586 | |
1587 /* | |
1588 * FUNCTION: slice_has_same_disk_geom(dm_descriptor_t slice, | |
1589 * dlist_t *used, boolean_t *has_same_geom) | |
1590 * | |
1591 * INPUT: slice - a dm_descriptor_t handle for the slice of interest | |
1592 * used - a dlist_t pointer to a list of used slices | |
1593 * bool - a boolean_t pointer to hold the result | |
1594 * | |
1595 * RETURNS: int - 0 on success | |
1596 * !0 otherwise | |
1597 * | |
1598 * PURPOSE: Determines if the input slice is on a drive with similar | |
1599 * hardware geometry as the slices in the used list. | |
1600 * | |
1601 * If the slice is found to be on a disk with similar geometry, | |
1602 * bool is set to B_TRUE, B_FALSE otherwise. | |
1603 * | |
1604 * The comparison is based on the available disk geometry | |
1605 * information which may not be relevant or accurate for | |
1606 * EFI labeled disks, so the disk drive type needs to be | |
1607 * checked as well. | |
1608 */ | |
1609 static int | |
1610 slice_has_same_disk_geom( | |
1611 dm_descriptor_t slice, | |
1612 dlist_t *used, | |
1613 boolean_t *has_same_geom) | |
1614 { | |
1615 dm_descriptor_t disk = NULL; | |
1616 boolean_t efi = B_FALSE; | |
1617 uint64_t bsize = 0; | |
1618 uint64_t ncyls = 0; | |
1619 uint64_t nsects = 0; | |
1620 uint64_t nheads = 0; | |
1621 dlist_t *iter = NULL; | |
1622 int error = 0; | |
1623 | |
1624 *has_same_geom = B_TRUE; | |
1625 | |
1626 ((error = slice_get_disk(slice, &disk)) != 0) || | |
1627 (error = disk_get_is_efi(disk, &efi)) || | |
1628 (error = disk_get_blocksize(disk, &bsize)); | |
1629 | |
1630 if ((error == 0) && (efi == B_FALSE)) { | |
1631 ((error = disk_get_ncylinders(disk, &ncyls)) != 0) || | |
1632 (error = disk_get_nheads(disk, &nheads)) || | |
1633 (error = disk_get_nsectors(disk, &nsects)); | |
1634 } | |
1635 | |
1636 if (error != 0) { | |
1637 return (error); | |
1638 } | |
1639 | |
1640 /* | |
1641 * check to see if slice's disk has the same geometry | |
1642 * as the disks for the slices in the used list | |
1643 */ | |
1644 for (iter = used; | |
1645 (iter != NULL) && (*has_same_geom == B_TRUE) && (error = 0); | |
1646 iter = iter->next) { | |
1647 | |
1648 devconfig_t *dev = (devconfig_t *)iter->obj; | |
1649 | |
1650 if (devconfig_isA(dev, TYPE_SLICE)) { | |
1651 | |
1652 /* get disk info for otherslice */ | |
1653 dm_descriptor_t odisk = NULL; | |
1654 char *oname = NULL; | |
1655 boolean_t oefi = B_FALSE; | |
1656 uint64_t obsize = 0; | |
1657 uint64_t oncyls = 0; | |
1658 uint64_t onsects = 0; | |
1659 uint64_t onheads = 0; | |
1660 | |
1661 ((error = devconfig_get_name(dev, &oname)) != 0) || | |
1662 (error = get_disk_for_named_slice(oname, &odisk)) || | |
1663 (error = disk_get_is_efi(odisk, &oefi)) || | |
1664 (error = disk_get_blocksize(odisk, &obsize)); | |
1665 | |
1666 if ((error == 0) && (oefi == B_FALSE)) { | |
1667 ((error = disk_get_ncylinders(odisk, &oncyls)) != 0) || | |
1668 (error = disk_get_nheads(odisk, &onheads)) || | |
1669 (error = disk_get_nsectors(odisk, &onsects)); | |
1670 } | |
1671 | |
1672 if (error == 0) { | |
1673 if ((bsize != obsize) || (ncyls != oncyls) || | |
1674 (nsects != onsects) || (nheads != onheads)) { | |
1675 /* this disk has a different geometry */ | |
1676 *has_same_geom = B_FALSE; | |
1677 } | |
1678 } | |
1679 } | |
1680 } | |
1681 | |
1682 return (error); | |
1683 } | |
1684 | |
1685 /* | |
1686 * FUNCTION: slice_on_similar_bus(dm_descriptor_t slice, | |
1687 * dlist_t *used, boolean_t *on_smlr_bus) | |
1688 * | |
1689 * INPUT: slice - a dm_descriptor_t handle for the slice of interest | |
1690 * used - a dlist_t pointer to a list of used slices | |
1691 * bool - a boolean_t pointer to hold the result | |
1692 * | |
1693 * RETURNS: int - 0 on success | |
1694 * !0 otherwise | |
1695 * | |
1696 * PURPOSE: Determines if the input slice is connected thru a bus with | |
1697 * characteristics similar to the slices in the used list. | |
1698 * | |
1699 * If the slice is found to be on a similar bus, bool is set | |
1700 * to B_TRUE, B_FALSE otherwise. | |
1701 * | |
1702 * The comparison is actually between any of the HBA/controllers | |
1703 * thru which the slices are connected to the system. | |
1704 * If any are of similar type (e.g., fibre, SCSI) and | |
1705 * protocol (SCSI-2, -3, fast/wide), then the slices are | |
1706 * considered to be on similar busses. | |
1707 */ | |
1708 static int | |
1709 slice_on_similar_bus( | |
1710 dm_descriptor_t slice, | |
1711 dlist_t *used, | |
1712 boolean_t *on_smlr_bus) | |
1713 { | |
1714 dlist_t *iter = NULL; | |
1715 dlist_t *iter1 = NULL; | |
1716 dlist_t *hbas = NULL; | |
1717 int error = 0; | |
1718 | |
1719 /* if there are no used slices, then the bus is similar */ | |
1720 *on_smlr_bus = B_TRUE; | |
1721 if (dlist_length(used) == 0) { | |
1722 return (0); | |
1723 } | |
1724 | |
1725 (error = slice_get_hbas(slice, &hbas)); | |
1726 if (error != 0) { | |
1727 return (error); | |
1728 } | |
1729 | |
1730 /* if there are used slices, then make sure the bus is similar */ | |
1731 *on_smlr_bus = B_FALSE; | |
1732 for (iter = hbas; | |
1733 (iter != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0); | |
1734 iter = iter->next) { | |
1735 | |
1736 dm_descriptor_t hba = (uintptr_t)iter->obj; | |
1737 char *type = NULL; | |
1738 boolean_t fast80 = B_FALSE; | |
1739 boolean_t fast40 = B_FALSE; | |
1740 boolean_t fast20 = B_FALSE; | |
1741 boolean_t wide = B_FALSE; | |
1742 | |
1743 ((error = hba_get_type(hba, &type)) != 0) || | |
1744 (error = hba_is_fast_80(hba, &fast80)) || | |
1745 (error = hba_is_fast_40(hba, &fast40)) || | |
1746 (error = hba_is_fast_20(hba, &fast20)) || | |
1747 (error = hba_supports_wide(hba, &wide)); | |
1748 if (error != 0) { | |
1749 continue; | |
1750 } | |
1751 | |
1752 /* check against the HBAs for the used slices */ | |
1753 for (iter1 = used; | |
1754 (iter1 != NULL) && (*on_smlr_bus == B_FALSE) && (error == 0); | |
1755 iter1 = iter1->next) { | |
1756 | |
1757 devconfig_t *used = (devconfig_t *)iter1->obj; | |
1758 | |
1759 /* get HBAs for otherslice */ | |
1760 dm_descriptor_t udisk = NULL; | |
1761 char *uname = NULL; | |
1762 dlist_t *uhbas = NULL; | |
1763 dlist_t *iter2 = NULL; | |
1764 | |
1765 ((error = devconfig_get_name(used, &uname)) != 0) || | |
1766 (error = get_disk_for_named_slice(uname, &udisk)) || | |
1767 (error = disk_get_hbas(udisk, &uhbas)); | |
1768 | |
1769 for (iter2 = uhbas; | |
1770 (iter2 != NULL) && (*on_smlr_bus == B_FALSE) && | |
1771 (error == 0); | |
1772 iter2 = iter2 ->next) { | |
1773 | |
1774 dm_descriptor_t uhba = (uintptr_t)iter2->obj; | |
1775 char *utype = NULL; | |
1776 boolean_t ufast80 = B_FALSE; | |
1777 boolean_t ufast40 = B_FALSE; | |
1778 boolean_t ufast20 = B_FALSE; | |
1779 boolean_t uwide = B_FALSE; | |
1780 | |
1781 ((error = hba_get_type(uhba, &utype)) != 0) || | |
1782 (error = hba_is_fast_80(uhba, &ufast80)) || | |
1783 (error = hba_is_fast_40(uhba, &ufast40)) || | |
1784 (error = hba_is_fast_20(uhba, &ufast20)) || | |
1785 (error = hba_supports_wide(uhba, &uwide)); | |
1786 | |
1787 if (error == 0) { | |
1788 /* check sync speed ? */ | |
1789 if ((fast80 == ufast80) && (fast40 == ufast40) && | |
1790 (fast20 == ufast20) && (wide == uwide) && | |
1791 (type == utype)) { | |
1792 *on_smlr_bus = B_TRUE; | |
1793 } | |
1794 } | |
1795 } | |
1796 dlist_free_items(uhbas, NULL); | |
1797 } | |
1798 } | |
1799 | |
1800 dlist_free_items(hbas, NULL); | |
1801 | |
1802 return (error); | |
1803 } | |
1804 | |
1805 /* | |
1806 * FUNCTION: slice_has_n_paths(dm_descriptor_t slice, | |
1807 * uint16_t npaths, boolean_t *has_n_paths) | |
1808 * INPUT: slice - a dm_descriptor_t handle for the slice of interest | |
1809 * npaths - the number of paths desired | |
1810 * has_n_paths - a boolean_t pointer to hold the result | |
1811 * | |
1812 * RETURNS: int - 0 on success | |
1813 * !0 otherwise | |
1814 * | |
1815 * PURPOSE: Determines if the input slice is connected via npaths. | |
1816 * has_n_paths is set to B_TRUE if so, B_FALSE otherwise. | |
1817 * | |
1818 * In order for a disk to have multiple paths, MPXIO must | |
1819 * be enabled and these conditions should hold: | |
1820 * | |
1821 * Slice will have one drive object. | |
1822 * Drive will have one HBA (scsi_vhci) | |
1823 * Drive will have one alias. | |
1824 * Drive will have possibly > 1 paths. | |
1825 * | |
1826 * Getting the HBAs and aliases for the disk is relatively | |
1827 * expensive, so they aren't checked. The actual number of | |
1828 * paths is only checked if MPXIO is known to be enabled on | |
1829 * the system and the input npaths is > 1. | |
1830 */ | |
1831 static int | |
1832 slice_has_n_paths( | |
1833 dm_descriptor_t slice, | |
1834 uint16_t npaths, | |
1835 boolean_t *has_n_paths) | |
1836 { | |
1837 int error = 0; | |
1838 | |
1839 *has_n_paths = B_FALSE; | |
1840 | |
1841 if ((npaths > 1) && (is_mpxio_enabled() == B_TRUE)) { | |
1842 | |
1843 dm_descriptor_t disk = NULL; | |
1844 dlist_t *paths = NULL; | |
1845 | |
1846 ((error = slice_get_disk(slice, &disk)) != 0) || | |
1847 (error = disk_get_paths(disk, &paths)); | |
1848 | |
1849 if ((error == 0) && (dlist_length(paths) == npaths)) { | |
1850 *has_n_paths = B_TRUE; | |
1851 } | |
1852 dlist_free_items(paths, NULL); | |
1853 } | |
1854 | |
1855 return (error); | |
1856 } | |
1857 | |
1858 /* | |
1859 * FUNCTION: compare_string_to_modslice_name(void *str, void *modslice) | |
1860 * | |
1861 * INPUT: str - opaque char * pointer | |
1862 * modslice - opaque modslice_t pointer | |
1863 * | |
1864 * RETURNS: int - <0 - if str < modslice->slice_devcfg.name | |
1865 * 0 - if str == modslice->slice_devcfg.name | |
1866 * >0 - if str > modslice->slice_devcfg.name | |
1867 * | |
1868 * PURPOSE: dlist_t helper which compares the input string to | |
1869 * the name of a slice represented as modslice_t struct. | |
1870 * | |
1871 * Comparison is done via string_case_compare. | |
1872 */ | |
1873 static int | |
1874 compare_string_to_modslice_name( | |
1875 void *str, | |
1876 void *modslice) | |
1877 { | |
1878 char *name = NULL; | |
1879 | |
1880 assert(str != NULL); | |
1881 assert(modslice != NULL); | |
1882 | |
1883 (void) devconfig_get_name( | |
1884 ((modslice_t *)modslice)->slice_devcfg, &name); | |
1885 | |
1886 return (string_case_compare((char *)str, name)); | |
1887 } | |
1888 | |
1889 /* | |
1890 * FUNCTION: compare_modslice_names(void *obj1, void *obj2) | |
1891 * | |
1892 * INPUT: obj1 - opaque pointer | |
1893 * obj2 - opaque pointer | |
1894 * | |
1895 * RETURNS: int - <0 - if obj1 name < obj2 name | |
1896 * 0 - if obj1 name == obj2 name | |
1897 * >0 - if obj1 name > obj2 name | |
1898 * | |
1899 * PURPOSE: dlist_t helper which compares the names of two slices | |
1900 * represented as modslice_t structs. | |
1901 * | |
1902 * Comparison is done by string_case_compare | |
1903 */ | |
1904 static int | |
1905 compare_modslice_names( | |
1906 void *obj1, | |
1907 void *obj2) | |
1908 { | |
1909 char *name1 = NULL; | |
1910 char *name2 = NULL; | |
1911 | |
1912 assert(obj1 != NULL); | |
1913 assert(obj2 != NULL); | |
1914 | |
1915 (void) devconfig_get_name( | |
1916 ((modslice_t *)obj1)->slice_devcfg, &name1); | |
1917 (void) devconfig_get_name( | |
1918 ((modslice_t *)obj2)->slice_devcfg, &name2); | |
1919 | |
1920 return (string_case_compare(name1, name2)); | |
1921 } | |
1922 | |
1923 /* | |
1924 * FUNCTION: release_used_slices() | |
1925 * | |
1926 * PURPOSE: Helper which cleans up the module private list of used | |
1927 * slices. | |
1928 */ | |
1929 void | |
1930 release_used_slices() | |
1931 { | |
1932 dlist_free_items(_used_slices, free_used_slice); | |
1933 _used_slices = NULL; | |
1934 } | |
1935 | |
1936 static void | |
1937 free_used_slice( | |
1938 void *obj) | |
1939 { | |
1940 if (obj != NULL) { | |
1941 usedslice_t *used = (usedslice_t *)obj; | |
1942 free(used->slicename); | |
1943 free(used); | |
1944 } | |
1945 } | |
1946 | |
1947 /* | |
1948 * FUNCTION: is_used_slice(dm_descriptor_t slice, boolean_t *is_used) | |
1949 * | |
1950 * INPUT: slice - a dm_descriptor_t slice handle | |
1951 * | |
1952 * OUTPUT: is_reserved - pointer to a boolean_t to hold the | |
1953 * return result. | |
1954 * | |
1955 * PURPOSE: Helper which checks to see if the input slice | |
1956 * is in the used_slice list. | |
1957 * | |
1958 * Check the input name against any used slice name or alias. | |
1959 * is_used is set to B_TRUE if the input slice is already used, | |
1960 * B_FALSE otherwise. | |
1961 */ | |
1962 int | |
1963 is_used_slice( | |
1964 dm_descriptor_t slice, | |
1965 boolean_t *is_used) | |
1966 { | |
1967 char *name; | |
1968 int error = 0; | |
1969 | |
1970 if ((error = get_display_name(slice, &name)) == 0) { | |
1971 *is_used = dlist_contains(_used_slices, (void *)name, | |
1972 compare_usedslice_name_to_string); | |
1973 } | |
1974 | |
1975 return (error); | |
1976 } | |
1977 | |
1978 /* | |
1979 * FUNCTIONS: add_used_slice(dm_descriptor_t slice) | |
1980 * add_used_slice_by_name(char *slicename) | |
1981 * add_used_slice_list_entry(char *slice) | |
1982 * remove_used_slice_by_name(char *slicename) | |
1983 * | |
1984 * INPUT: diskset - a char * diskset name. | |
1985 * slice - a dm_descriptor_t slice handle | |
1986 * | |
1987 * RETURNS: int - 0 on success | |
1988 * !0 otherwise | |
1989 * | |
1990 * PURPOSE: Access or maintain the list of used slices. | |
1991 */ | |
1992 int | |
1993 add_used_slice( | |
1994 dm_descriptor_t slice) | |
1995 { | |
1996 dm_descriptor_t disk; | |
1997 char *name; | |
1998 int error = 0; | |
1999 | |
2000 assert(slice != (dm_descriptor_t)0); | |
2001 | |
2002 ((error = get_display_name(slice, &name)) != 0) || | |
2003 (error = slice_get_disk(slice, &disk)) || | |
2004 (error = add_used_slice_list_entry(name, disk)); | |
2005 | |
2006 return (error); | |
2007 } | |
2008 | |
2009 int | |
2010 add_used_slice_by_name( | |
2011 char *slicename) | |
2012 { | |
2013 dm_descriptor_t disk = (dm_descriptor_t)0; | |
2014 int error = 0; | |
2015 | |
2016 assert(slicename != NULL); | |
2017 | |
2018 /* find disk for slice */ | |
2019 error = get_disk_for_named_slice(slicename, &disk); | |
2020 if (error == 0) { | |
2021 error = add_used_slice_list_entry(slicename, disk); | |
2022 } | |
2023 | |
2024 return (error); | |
2025 } | |
2026 | |
2027 static int | |
2028 add_used_slice_list_entry( | |
2029 char *slicename, | |
2030 dm_descriptor_t disk) | |
2031 { | |
2032 usedslice_t *used = NULL; | |
2033 int error = 0; | |
2034 | |
2035 assert(slicename != NULL); | |
2036 assert(disk != (dm_descriptor_t)0); | |
2037 | |
2038 used = (usedslice_t *)calloc(1, sizeof (usedslice_t)); | |
2039 if (used == NULL) { | |
2040 error = ENOMEM; | |
2041 } else { | |
2042 | |
2043 used->disk = disk; | |
2044 if ((used->slicename = strdup(slicename)) == NULL) { | |
2045 free(used); | |
2046 error = ENOMEM; | |
2047 } else { | |
2048 dlist_t *item = dlist_new_item((void *) used); | |
2049 if (item == NULL) { | |
2050 free(used->slicename); | |
2051 free(used); | |
2052 error = ENOMEM; | |
2053 } else { | |
2054 _used_slices = | |
2055 dlist_append(item, _used_slices, AT_HEAD); | |
2056 } | |
2057 } | |
2058 } | |
2059 return (error); | |
2060 } | |
2061 | |
2062 int | |
2063 remove_used_slice_by_name( | |
2064 char *slice) | |
2065 { | |
2066 dlist_t *removed = NULL; | |
2067 | |
2068 _used_slices = | |
2069 dlist_remove_equivalent_item(_used_slices, (void *)slice, | |
2070 compare_usedslice_name_to_string, &removed); | |
2071 | |
2072 if (removed != NULL) { | |
2073 free_used_slice(removed->obj); | |
2074 removed->obj = NULL; | |
2075 free(removed); | |
2076 } | |
2077 | |
2078 return (0); | |
2079 } | |
2080 | |
2081 /* | |
2082 * FUNCTION: compare_usedslice_name_to_string(void *obj1, void *obj2) | |
2083 * INPUT: obj1 - opaque pointer | |
2084 * obj2 - opaque pointer | |
2085 * | |
2086 * RETURNS: int - <0 - if obj1 name < obj2 name | |
2087 * 0 - if obj1 name == obj2 name | |
2088 * >0 - if obj1 name > obj2 name | |
2089 * | |
2090 * PURPOSE: dlist_t helper which compares the names of a slice | |
2091 * represented as modslice_t struct to a string. | |
2092 * | |
2093 * obj1 is assumed to be a char * | |
2094 * obj2 is assumed to be a usedslice_t * | |
2095 * | |
2096 * Comparison is done via string_case_compare. | |
2097 */ | |
2098 static int | |
2099 compare_usedslice_name_to_string( | |
2100 void *obj1, | |
2101 void *obj2) | |
2102 { | |
2103 assert(obj1 != NULL); | |
2104 assert(obj2 != NULL); | |
2105 | |
2106 return (string_case_compare((char *)obj1, | |
2107 ((usedslice_t *)obj2)->slicename)); | |
2108 } | |
2109 | |
2110 /* | |
2111 * FUNCTION: disk_has_used_slice(dm_descriptor_t disk, boolean_t *hasused) | |
2112 * | |
2113 * INPUT: disk - a dm_descriptor_t disk handle. | |
2114 * inuse - a boolean_t pointer to hold the result | |
2115 * | |
2116 * RETURNS: int - 0 on success | |
2117 * !0 othersize. | |
2118 * | |
2119 * PURPOSE: Determines if any of the known used slices is on the | |
2120 * input disk. | |
2121 */ | |
2122 int | |
2123 disk_has_used_slice( | |
2124 dm_descriptor_t disk, | |
2125 boolean_t *hasused) | |
2126 { | |
2127 dlist_t *iter; | |
2128 int error = 0; | |
2129 | |
2130 *hasused = B_FALSE; | |
2131 for (iter = _used_slices; | |
2132 (iter != NULL) && (*hasused == B_FALSE); | |
2133 iter = iter->next) { | |
2134 | |
2135 usedslice_t *used = (usedslice_t *)iter->obj; | |
2136 | |
2137 /* compare used slice's disk to disk */ | |
2138 if (compare_descriptors((void *)(uintptr_t)disk, | |
2139 (void *)(uintptr_t)used->disk) == 0) { | |
2140 *hasused = B_TRUE; | |
2141 } | |
2142 } | |
2143 | |
2144 return (error); | |
2145 } | |
2146 | |
2147 /* | |
2148 * FUNCTION: add_reserved_slice(dm_descriptor_t slice) | |
2149 * | |
2150 * INPUT: slice - a dm_descriptor_t slice handle | |
2151 * | |
2152 * RETURNS: int - 0 on success | |
2153 * !0 otherwise. | |
2154 * | |
2155 * PURPOSE: Helper which remembers specfically requested slices | |
2156 * in a private list to ensure that the same slice isn't | |
2157 * requested more than once. | |
2158 * | |
2159 * Does not check to see if the slice already exists | |
2160 * in the list of reserved slices. Assumes that the | |
2161 * caller has checked using is_reserved_slice(). | |
2162 * | |
2163 * The reserved slice list is used by several functions: | |
2164 * | |
2165 * 1. layout_validate.validate_slice_components() adds user | |
2166 * requested slices to the list. | |
2167 * | |
2168 * 2. After all potentially usable slices have been scanned, | |
2169 * layout_validate.validate_reserved_slices() checks the | |
2170 * slices in the reserved and ensures that each slice is | |
2171 * actually usable as a volume component. | |
2172 * | |
2173 * 3. layout.disk_get_avail_space(), layout.disk_get_avail_slices() | |
2174 * exclude slices in the reserved list from being considered | |
2175 * available for general layout use. | |
2176 */ | |
2177 int | |
2178 add_reserved_slice( | |
2179 dm_descriptor_t slice) | |
2180 { | |
2181 dlist_t *item = NULL; | |
2182 | |
2183 if ((item = dlist_new_item((void *)(uintptr_t)slice)) == NULL) { | |
2184 return (ENOMEM); | |
2185 } | |
2186 | |
2187 _rsvd_slices = dlist_append(item, _rsvd_slices, AT_HEAD); | |
2188 | |
2189 return (0); | |
2190 } | |
2191 | |
2192 /* | |
2193 * FUNCTION: is_reserved_slice(dm_descriptor_t slice, | |
2194 * boolean_t *is_reserved) | |
2195 * | |
2196 * INPUT: slice - a dm_descriptor_t slice handle | |
2197 * | |
2198 * OUTPUT: is_reserved - pointer to a boolean_t to hold the | |
2199 * return result. | |
2200 * | |
2201 * PURPOSE: Helper which checks to see if the input slice | |
2202 * was previously reserved. | |
2203 * | |
2204 * Check the input name against any reserved slice | |
2205 * name or alias. is_reserved is set to B_TRUE if the | |
2206 * input slice is already reserved, B_FALSE otherwise. | |
2207 */ | |
2208 int | |
2209 is_reserved_slice( | |
2210 dm_descriptor_t slice, | |
2211 boolean_t *is_reserved) | |
2212 { | |
2213 *is_reserved = dlist_contains(_rsvd_slices, | |
2214 (void *)(uintptr_t)slice, compare_descriptor_names); | |
2215 | |
2216 return (0); | |
2217 } | |
2218 | |
2219 /* | |
2220 * FUNCTION: release_reserved_slice() | |
2221 * | |
2222 * PURPOSE: Helper which cleans up the module private list of reserved | |
2223 * slices. | |
2224 */ | |
2225 void | |
2226 release_reserved_slices() | |
2227 { | |
2228 dlist_free_items(_rsvd_slices, free); | |
2229 _rsvd_slices = NULL; | |
2230 } | |
2231 | |
2232 /* | |
2233 * FUNCTION: get_reserved_slices(dlist_t **list) | |
2234 * | |
2235 * OUTPUT: list - a dlist_t pointer to hold the returned list of | |
2236 * reserverd slices. | |
2237 * | |
2238 * RETURNS: int - 0 on success | |
2239 * !0 otherwise | |
2240 * | |
2241 * PURPOSE: Accessor to retrieve the current list of reserved slice | |
2242 * dm_descriptor_t handles. | |
2243 */ | |
2244 int | |
2245 get_reserved_slices( | |
2246 dlist_t **list) | |
2247 { | |
2248 *list = _rsvd_slices; | |
2249 | |
2250 return (0); | |
2251 } | |
2252 | |
2253 /* | |
2254 * FUNCTION: add_slice_to_remove(char *name, uint32_t index) | |
2255 * | |
2256 * INPUT: name - name of a slice | |
2257 * index - index for the slice | |
2258 * | |
2259 * RETURNS: int - 0 on success | |
2260 * !0 otherwise | |
2261 * | |
2262 * PURPOSE: Utility function to add the named slice to the list of | |
2263 * those that need to be "removed" by having their sizes | |
2264 * set to 0. | |
2265 */ | |
2266 int | |
2267 add_slice_to_remove( | |
2268 char *name, | |
2269 uint32_t index) | |
2270 { | |
2271 rmvdslice_t *rmvd = NULL; | |
2272 int error = 0; | |
2273 | |
2274 assert(name != NULL); | |
2275 | |
2276 rmvd = (rmvdslice_t *)calloc(1, sizeof (rmvdslice_t)); | |
2277 if (rmvd == NULL) { | |
2278 error = ENOMEM; | |
2279 } else { | |
2280 rmvd->slice_index = index; | |
2281 if ((rmvd->slice_name = strdup(name)) == NULL) { | |
2282 free(rmvd); | |
2283 error = ENOMEM; | |
2284 } else { | |
2285 dlist_t *item = dlist_new_item((void *) rmvd); | |
2286 if (item == NULL) { | |
2287 free(rmvd->slice_name); | |
2288 free(rmvd); | |
2289 error = ENOMEM; | |
2290 } else { | |
2291 _rmvd_slices = | |
2292 dlist_append(item, _rmvd_slices, AT_HEAD); | |
2293 } | |
2294 } | |
2295 } | |
2296 return (error); | |
2297 } | |
2298 | |
2299 /* | |
2300 * FUNCTION: get_removed_slices() | |
2301 * | |
2302 * RETURNS: dlist_t * - pointer to a list of rmvdslice_t structs | |
2303 * | |
2304 * PURPOSE: Accessor to retrieve the current list of names of slices | |
2305 * to be removed. | |
2306 */ | |
2307 dlist_t * | |
2308 get_slices_to_remove( | |
2309 dlist_t **list) | |
2310 { | |
2311 return (_rmvd_slices); | |
2312 } | |
2313 | |
2314 static void | |
2315 free_rmvd_slice( | |
2316 void *obj) | |
2317 { | |
2318 if (obj != NULL) { | |
2319 rmvdslice_t *rmvd = (rmvdslice_t *)obj; | |
2320 free(rmvd->slice_name); | |
2321 free(rmvd); | |
2322 } | |
2323 } | |
2324 | |
2325 /* | |
2326 * FUNCTION: release_removed_slices() | |
2327 * | |
2328 * PURPOSE: Helper which cleans up the module private list of removed | |
2329 * slices. | |
2330 */ | |
2331 void | |
2332 release_slices_to_remove() | |
2333 { | |
2334 dlist_free_items(_rmvd_slices, free_rmvd_slice); | |
2335 _rmvd_slices = NULL; | |
2336 } |