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 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #define _LAYOUT_DLIST_UTIL_C
30
31 #include <assert.h>
32 #include <string.h>
33
34 #include <libintl.h>
35 #include <libdiskmgt.h>
36
37 #include "volume_devconfig.h"
38 #include "volume_dlist.h"
39 #include "volume_output.h"
40
41 #include "layout_device_cache.h"
42 #include "layout_dlist_util.h"
43 #include "layout_request.h"
44
45 #include "layout_slice.h" /* destroy_new_slice */
46 #include "layout_svm_util.h"
47
48 /*
49 * FUNCTION: compare_strings(void *str1, void *str2)
50 *
51 * INPUT: str1 - opaque pointer to a char *
52 * str2 - opaque pointer to a char *
53 *
54 * RETURNS: int - <0 - if str1 < str2
55 * 0 - if str1 == str2
56 * >0 - if str1 > str2
57 *
58 * PURPOSE: dlist_t helper which compares the two input strings.
59 *
60 * Comparison is done with string_case_compare()
61 */
62 int
compare_strings(void * str1,void * str2)63 compare_strings(
64 void *str1,
65 void *str2)
66 {
67 assert(str1 != NULL);
68 assert(str2 != NULL);
69
70 return (string_case_compare((char *)str1, (char *)str2));
71 }
72
73 /*
74 * FUNCTION: compare_devconfig_sizes(void *devconf1, void *devconf2)
75 *
76 * INPUT: devconf1 - opaque pointer
77 * devconf2 - opaque pointer
78 *
79 * RETURNS: int - <0 - if devconf1.size_in_blks < devconf2.size_in_blks
80 * 0 - if devconf1.size_in_blks == devconf2.size_in_blks
81 * >0 - if devconf1.size.in_blks > devconf2.size_in_blks
82 *
83 * PURPOSE: dlist_t helper which compares the sizes of two devconfig_t
84 * structs.
85 *
86 * Both input objects are assumed to be devconfig_t pointers.
87 */
88 int
compare_devconfig_sizes(void * devconf1,void * devconf2)89 compare_devconfig_sizes(
90 void *devconf1,
91 void *devconf2)
92 {
93 uint64_t size1 = 0;
94 uint64_t size2 = 0;
95
96 assert(devconf1 != NULL);
97 assert(devconf2 != NULL);
98
99 (void) devconfig_get_size_in_blocks((devconfig_t *)devconf1, &size1);
100 (void) devconfig_get_size_in_blocks((devconfig_t *)devconf2, &size2);
101
102 return (size1 - size2);
103 }
104
105 /*
106 * FUNCTION: compare_slice_sizes(void *desc1, void *desc2)
107 *
108 * INPUT: desc1 - opaque pointer to a dm_descriptor_t slice handle
109 * desc2 - opaque pointer to a dm_descriptor_t slice handle
110 *
111 * RETURNS: int - <0 - if desc1.slicesize < desc2.slicesize
112 * 0 - if desc1.slicesize == desc2.slicesize
113 * >0 - if desc1.slicesize > desc2.slicesize
114 *
115 * PURPOSE: dlist_t helper which compares the sizes of two slices
116 * represented as dm_descriptor_t handles.
117 */
118 int
compare_slice_sizes(void * desc1,void * desc2)119 compare_slice_sizes(
120 void *desc1,
121 void *desc2)
122 {
123 uint64_t size1 = 0;
124 uint64_t size2 = 0;
125
126 assert(desc1 != NULL);
127 assert(desc2 != NULL);
128
129 (void) slice_get_size((uintptr_t)desc1, &size1);
130 (void) slice_get_size((uintptr_t)desc2, &size2);
131
132 return (size1 - size2);
133 }
134
135 /*
136 * FUNCTION: compare_devconfig_and_descriptor_names(void *devconf,
137 * void *desc)
138 *
139 * INPUT: devconf - opaque pointer to a devconfig_t
140 * desc - opaque pointer to a dm_descriptor_t
141 *
142 * RETURNS: int - <0 - if devconf name is "less than" descr name
143 * 0 - if devconf name is "equal to" descr name
144 * >0 - if devconf name is "greater than" desc name
145 *
146 * PURPOSE: dlist_t helper which compares the name of a devconfig_t
147 * struct to the name for a dm_descriptor_t.
148 *
149 * Note that the order of the arguments is important.
150 * This function is intended to be passed into the various
151 * dlist_* functions which take a comparison function.
152 */
153 int
compare_devconfig_and_descriptor_names(void * devconf,void * desc)154 compare_devconfig_and_descriptor_names(
155 void *devconf,
156 void *desc)
157 {
158 char *volname = NULL;
159 char *descname = NULL;
160
161 assert(devconf != NULL);
162 assert(desc != NULL);
163
164 (void) devconfig_get_name((devconfig_t *)devconf, &volname);
165 (void) get_display_name((uintptr_t)desc, &descname);
166
167 return (string_case_compare(volname, descname));
168 }
169
170 /*
171 * FUNCTION: compare_string_to_devconfig_name(void *str, void *devconf)
172 *
173 * INPUT: str - opaque pointer to a char *str
174 * devconf - opaque pointer to a devconfig_t
175 *
176 * RETURNS: int - <0 - if devconf name is "less than" str
177 * 0 - if devconf name is "equal to" str
178 * >0 - if devconf name is "greater than" str
179 *
180 * PURPOSE: dlist_t helper which compares a string to the name of
181 * a devconfig_t struct.
182 */
183 int
compare_string_to_devconfig_name(void * str,void * devconf)184 compare_string_to_devconfig_name(
185 void *str,
186 void *devconf)
187 {
188 char *volname = NULL;
189
190 assert(str != NULL);
191 assert(devconf != NULL);
192
193 (void) devconfig_get_name((devconfig_t *)devconf, &volname);
194 if (volname == NULL) {
195 /* no memory for new string(s) */
196 return (-1);
197 }
198
199 return (string_case_compare(volname, (char *)str));
200 }
201
202 /*
203 * FUNCTION: free_devconfig_object(void *obj)
204 *
205 * INPUT: obj - an opaque pointer
206 *
207 * RETURNS: void
208 *
209 * PURPOSE: helper which decomposes a devconfig_t struct after a
210 * failed layout attempt.
211 *
212 * reclaims allocated space.
213 * releases reserved volume/HSP names
214 * undoes slicing
215 */
216 void
free_devconfig_object(void * obj)217 free_devconfig_object(
218 void *obj)
219 {
220 devconfig_t *dev = NULL;
221 char *name = NULL;
222 dlist_t *iter = NULL;
223 component_type_t type = TYPE_UNKNOWN;
224
225 if (obj == NULL) {
226 return;
227 }
228
229 dev = (devconfig_t *)obj;
230
231 (void) devconfig_get_type(dev, &type);
232 (void) devconfig_get_name(dev, &name);
233
234 oprintf(OUTPUT_DEBUG,
235 gettext(" -->decomposing %s\n"), name);
236
237 switch (type) {
238 case TYPE_MIRROR:
239 case TYPE_CONCAT:
240 case TYPE_RAID5:
241 case TYPE_HSP:
242 case TYPE_STRIPE:
243
244 /* release name */
245 if (devconfig_isA(dev, TYPE_HSP)) {
246 release_hsp_name(name);
247 } else {
248 release_volume_name(name);
249 }
250
251 /* decompose volume's components */
252 iter = devconfig_get_components(dev);
253 dlist_free_items(iter, free_devconfig_object);
254
255 (void) devconfig_set_components(dev, NULL);
256
257 break;
258
259 case TYPE_SLICE:
260
261 (void) destroy_new_slice(dev);
262
263 break;
264
265 default:
266 break;
267
268 }
269
270 free_devconfig(dev);
271 }
272
273 /*
274 * FUNCTION: compare_device_names(
275 * void *str1, void *str2)
276 *
277 * INPUT: str1 - opaque pointer
278 * str2 - opaque pointer
279 *
280 * RETURNS: int - <0 - if str1 < str2
281 * 0 - if str1 == str2
282 * >0 - if str1 > str2
283 *
284 * PURPOSE: dlist_t helper which compares two device name strings.
285 *
286 * Both names are assumed to be in CTD form.
287 *
288 * Either name may be fully qualified by an absolute
289 * path. If only one name is fully qualified, the
290 * leading path with be stripped off prior to the
291 * comparison.
292 *
293 * Uses string_case_compare() to compare the names.
294 */
295 int
compare_device_names(void * str1,void * str2)296 compare_device_names(
297 void *str1,
298 void *str2)
299 {
300 char *name1 = (char *)str1;
301 char *name2 = (char *)str2;
302
303 int val = 0;
304
305 assert(str1 != NULL);
306 assert(str2 != NULL);
307
308 /* if one doesn't start with '/', just compare device names */
309 if (*name1 != '/' || *name2 != '/') {
310
311 char *short1 = strrchr(name1, '/');
312 char *short2 = strrchr(name2, '/');
313
314 if (short1 == NULL) {
315 short1 = name1;
316 } else {
317 ++short1;
318 }
319
320 if (short2 == NULL) {
321 short2 = name2;
322 } else {
323 ++short2;
324 }
325
326 val = string_case_compare(short2, short1);
327
328 } else {
329
330 /* if they both start with '/', assume they're full paths */
331 val = string_case_compare(name2, name1);
332 }
333
334 return (val);
335 }
336
337 /*
338 * FUNCTION: compare_descriptors(
339 * void *desc1, void *desc2)
340 *
341 * INPUT: desc1 - opaque pointer
342 * desc2 - opaque pointer
343 *
344 * RETURNS: int - <0 - if desc1 < desc2
345 * 0 - if desc1 == desc2
346 * >0 - if desc1 > desc2
347 *
348 * PURPOSE: dlist_t helper which compares two dm_descriptor_t handles.
349 */
350 int
compare_descriptors(void * desc1,void * desc2)351 compare_descriptors(
352 void *desc1,
353 void *desc2)
354 {
355 assert(desc1 != NULL);
356 assert(desc2 != NULL);
357
358 return ((uintptr_t)desc1 - (uintptr_t)desc2);
359 }
360
361 /*
362 * FUNCTION: compare_descriptor_names(
363 * void *desc1, void *desc2)
364 *
365 * INPUT: desc1 - opaque pointer
366 * desc2 - opaque pointer
367 *
368 * RETURNS: int - <0 - if desc1.name < desc2.name
369 * 0 - if desc1.name == desc2.name
370 * >0 - if desc1.name > desc2.name
371 *
372 * PURPOSE: dlist_t helper which compares the names associated
373 * with the input dm_descriptor_t handles.
374 *
375 * Retrieves the names associated with both descriptors
376 * and compares them using string_case_compare.
377 */
378 int
compare_descriptor_names(void * desc1,void * desc2)379 compare_descriptor_names(
380 void *desc1,
381 void *desc2)
382 {
383 char *name1 = NULL;
384 char *name2 = NULL;
385
386 assert(desc1 != NULL);
387 assert(desc2 != NULL);
388
389 (void) get_name((uintptr_t)desc1, &name1);
390 (void) get_name((uintptr_t)desc2, &name2);
391
392 return (string_case_compare(name1, name2));
393 }
394
395 /*
396 * FUNCTION: compare_slices_on_same_hba(
397 * void *slice1, void *slice2)
398 *
399 * INPUT: slice1 - opaque pointer
400 * slice2 - opaque pointer
401 *
402 * RETURNS: int - 0 - if slice1 is on the same hba as slice2
403 * !0 - otherwise
404 *
405 * PURPOSE: dlist_t helper which checks whether slice1 is on the
406 * same hba as slice2
407 */
408 int
compare_slices_on_same_hba(void * slice1,void * slice2)409 compare_slices_on_same_hba(
410 void *slice1,
411 void *slice2)
412 {
413 char *name1, *name2;
414
415 /* Retrieve the names of the slices */
416 if (devconfig_get_name((devconfig_t *)slice1, &name1) == 0 &&
417 devconfig_get_name((devconfig_t *)slice2, &name2) == 0) {
418
419 dm_descriptor_t desc1, desc2;
420
421 /* Retrieve the disk descriptors for the slices */
422 if (get_disk_for_named_slice(name1, &desc1) == 0 &&
423 get_disk_for_named_slice(name2, &desc2) == 0) {
424
425 dlist_t *hbas1 = NULL;
426 dlist_t *hbas2 = NULL;
427
428 assert(desc1 != (dm_descriptor_t)0);
429 assert(desc2 != (dm_descriptor_t)0);
430
431 /* Retrieve list of HBA descriptors for the slices */
432 if (disk_get_hbas(desc1, &hbas1) == 0 &&
433 disk_get_hbas(desc2, &hbas2) == 0) {
434
435 dlist_t *itr1;
436
437 for (itr1 = hbas1; itr1 != NULL; itr1 = itr1->next) {
438 dm_descriptor_t hba1 = (uintptr_t)itr1->obj;
439 dlist_t *itr2;
440
441 for (itr2 = hbas2; itr2 != NULL; itr2 = itr2->next) {
442 dm_descriptor_t hba2 = (uintptr_t)itr2->obj;
443
444 if (hba1 == hba2) {
445 return (0);
446 }
447 }
448 }
449 }
450 }
451 }
452
453 return (1);
454 }
455