1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #include <string.h>
30*0Sstevel@tonic-gate #include <libintl.h>
31*0Sstevel@tonic-gate
32*0Sstevel@tonic-gate #include "libdiskmgt.h"
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gate #include "volume_error.h"
35*0Sstevel@tonic-gate #include "volume_defaults.h"
36*0Sstevel@tonic-gate #include "volume_devconfig.h"
37*0Sstevel@tonic-gate #include "volume_dlist.h"
38*0Sstevel@tonic-gate #include "volume_output.h"
39*0Sstevel@tonic-gate #include "volume_request.h"
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate #include "layout_concat.h"
42*0Sstevel@tonic-gate #include "layout_device_cache.h"
43*0Sstevel@tonic-gate #include "layout_device_util.h"
44*0Sstevel@tonic-gate #include "layout_discovery.h"
45*0Sstevel@tonic-gate #include "layout_dlist_util.h"
46*0Sstevel@tonic-gate #include "layout_messages.h"
47*0Sstevel@tonic-gate #include "layout_request.h"
48*0Sstevel@tonic-gate #include "layout_slice.h"
49*0Sstevel@tonic-gate #include "layout_svm_util.h"
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gate #define _LAYOUT_CONCAT_C
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate static int
54*0Sstevel@tonic-gate compose_concat_within_hba(
55*0Sstevel@tonic-gate devconfig_t *request,
56*0Sstevel@tonic-gate dlist_t *hbas,
57*0Sstevel@tonic-gate uint64_t nbytes,
58*0Sstevel@tonic-gate devconfig_t **concat);
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate static int
61*0Sstevel@tonic-gate assemble_concat(
62*0Sstevel@tonic-gate devconfig_t *request,
63*0Sstevel@tonic-gate dlist_t *comps,
64*0Sstevel@tonic-gate devconfig_t **concat);
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gate /*
67*0Sstevel@tonic-gate * FUNCTION: layout_concat(devconfig_t *request, uint64_t nbytes,
68*0Sstevel@tonic-gate * dlist_t **results)
69*0Sstevel@tonic-gate *
70*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t of the current request
71*0Sstevel@tonic-gate * nbytes - the desired capacity of the concat
72*0Sstevel@tonic-gate *
73*0Sstevel@tonic-gate * OUPUT: results - pointer to a list of composed volumes
74*0Sstevel@tonic-gate *
75*0Sstevel@tonic-gate * RETURNS: int - 0 on success
76*0Sstevel@tonic-gate * !0 otherwise.
77*0Sstevel@tonic-gate *
78*0Sstevel@tonic-gate * PURPOSE: Main layout driver for composing concat volumes.
79*0Sstevel@tonic-gate *
80*0Sstevel@tonic-gate * Attempts to construct a concat of size nbytes.
81*0Sstevel@tonic-gate *
82*0Sstevel@tonic-gate * Several different layout strategies are tried in order
83*0Sstevel@tonic-gate * of preference until one succeeds or there are none left.
84*0Sstevel@tonic-gate *
85*0Sstevel@tonic-gate * 1 - concat within an HBA
86*0Sstevel@tonic-gate * . requires sufficient space available on the HBA
87*0Sstevel@tonic-gate *
88*0Sstevel@tonic-gate * 2 - concat across all available similar HBAs
89*0Sstevel@tonic-gate *
90*0Sstevel@tonic-gate * 3 - concat across all available HBAs
91*0Sstevel@tonic-gate *
92*0Sstevel@tonic-gate * get available HBAs
93*0Sstevel@tonic-gate *
94*0Sstevel@tonic-gate * group HBAs by characteristics
95*0Sstevel@tonic-gate * for (each HBA grouping) and (concat not composed) {
96*0Sstevel@tonic-gate * select next HBA group
97*0Sstevel@tonic-gate * for (strategy[1,2]) and (concat not composed) {
98*0Sstevel@tonic-gate * compose concat using HBAs in group
99*0Sstevel@tonic-gate * }
100*0Sstevel@tonic-gate * }
101*0Sstevel@tonic-gate *
102*0Sstevel@tonic-gate * if (concat not composed) {
103*0Sstevel@tonic-gate * for (strategy[3]) and (concat not composed) {
104*0Sstevel@tonic-gate * compose concat using all HBAs
105*0Sstevel@tonic-gate * }
106*0Sstevel@tonic-gate * }
107*0Sstevel@tonic-gate *
108*0Sstevel@tonic-gate * if (concat composed) {
109*0Sstevel@tonic-gate * append composed concat to results
110*0Sstevel@tonic-gate * }
111*0Sstevel@tonic-gate */
112*0Sstevel@tonic-gate int
layout_concat(devconfig_t * request,uint64_t nbytes,dlist_t ** results)113*0Sstevel@tonic-gate layout_concat(
114*0Sstevel@tonic-gate devconfig_t *request,
115*0Sstevel@tonic-gate uint64_t nbytes,
116*0Sstevel@tonic-gate dlist_t **results)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate /*
119*0Sstevel@tonic-gate * these enums define the # of strategies and the preference order
120*0Sstevel@tonic-gate * in which they are tried
121*0Sstevel@tonic-gate */
122*0Sstevel@tonic-gate typedef enum {
123*0Sstevel@tonic-gate CONCAT_WITHIN_SIMILAR_HBA = 0,
124*0Sstevel@tonic-gate CONCAT_ACROSS_SIMILAR_HBAS,
125*0Sstevel@tonic-gate N_SIMILAR_HBA_STRATEGIES
126*0Sstevel@tonic-gate } similar_hba_strategy_order_t;
127*0Sstevel@tonic-gate
128*0Sstevel@tonic-gate typedef enum {
129*0Sstevel@tonic-gate CONCAT_ACROSS_ANY_HBAS = 0,
130*0Sstevel@tonic-gate N_ANY_HBA_STRATEGIES
131*0Sstevel@tonic-gate } any_hba_strategy_order_t;
132*0Sstevel@tonic-gate
133*0Sstevel@tonic-gate dlist_t *usable_hbas = NULL;
134*0Sstevel@tonic-gate dlist_t *similar_hba_groups = NULL;
135*0Sstevel@tonic-gate dlist_t *iter = NULL;
136*0Sstevel@tonic-gate devconfig_t *concat = NULL;
137*0Sstevel@tonic-gate
138*0Sstevel@tonic-gate int error = 0;
139*0Sstevel@tonic-gate
140*0Sstevel@tonic-gate (error = get_usable_hbas(&usable_hbas));
141*0Sstevel@tonic-gate if (error != 0) {
142*0Sstevel@tonic-gate volume_set_error(gettext("There are no usable HBAs."));
143*0Sstevel@tonic-gate return (error);
144*0Sstevel@tonic-gate }
145*0Sstevel@tonic-gate
146*0Sstevel@tonic-gate print_layout_volume_msg(devconfig_type_to_str(TYPE_CONCAT), nbytes);
147*0Sstevel@tonic-gate
148*0Sstevel@tonic-gate if (dlist_length(usable_hbas) == 0) {
149*0Sstevel@tonic-gate print_no_hbas_msg();
150*0Sstevel@tonic-gate return (-1);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate error = group_similar_hbas(usable_hbas, &similar_hba_groups);
154*0Sstevel@tonic-gate if (error != 0) {
155*0Sstevel@tonic-gate return (error);
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gate for (iter = similar_hba_groups;
159*0Sstevel@tonic-gate (error == 0) && (concat == NULL) && (iter != NULL);
160*0Sstevel@tonic-gate iter = iter->next) {
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate dlist_t *hbas = (dlist_t *)iter->obj;
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate similar_hba_strategy_order_t order;
165*0Sstevel@tonic-gate
166*0Sstevel@tonic-gate for (order = CONCAT_WITHIN_SIMILAR_HBA;
167*0Sstevel@tonic-gate (order < N_SIMILAR_HBA_STRATEGIES) &&
168*0Sstevel@tonic-gate (concat == NULL) && (error == 0);
169*0Sstevel@tonic-gate order++) {
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate dlist_t *selhbas = NULL;
172*0Sstevel@tonic-gate dlist_t *disks = NULL;
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate switch (order) {
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gate case CONCAT_WITHIN_SIMILAR_HBA:
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate error = select_hbas_with_n_disks(
179*0Sstevel@tonic-gate request, hbas, 1, &selhbas, &disks);
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gate if (error == 0) {
182*0Sstevel@tonic-gate
183*0Sstevel@tonic-gate /* BEGIN CSTYLED */
184*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
185*0Sstevel@tonic-gate gettext(" -->Strategy 1: use disks from a single HBA - concat within HBA\n"));
186*0Sstevel@tonic-gate /* END CSTYLED */
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate error = compose_concat_within_hba(
189*0Sstevel@tonic-gate request, selhbas, nbytes, &concat);
190*0Sstevel@tonic-gate }
191*0Sstevel@tonic-gate
192*0Sstevel@tonic-gate break;
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate case CONCAT_ACROSS_SIMILAR_HBAS:
195*0Sstevel@tonic-gate
196*0Sstevel@tonic-gate error = select_hbas_with_n_disks(
197*0Sstevel@tonic-gate request, hbas, 1, &selhbas, &disks);
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate if (error == 0) {
200*0Sstevel@tonic-gate
201*0Sstevel@tonic-gate /* BEGIN CSTYLED */
202*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE,
203*0Sstevel@tonic-gate gettext(" -->Strategy 2: use disks from all similar HBAs - concat across HBAs\n"));
204*0Sstevel@tonic-gate /* END CSTYLED */
205*0Sstevel@tonic-gate
206*0Sstevel@tonic-gate error = populate_concat(
207*0Sstevel@tonic-gate request, nbytes, disks,
208*0Sstevel@tonic-gate NULL, &concat);
209*0Sstevel@tonic-gate }
210*0Sstevel@tonic-gate
211*0Sstevel@tonic-gate break;
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate default:
214*0Sstevel@tonic-gate break;
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate
217*0Sstevel@tonic-gate dlist_free_items(disks, NULL);
218*0Sstevel@tonic-gate dlist_free_items(selhbas, NULL);
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate
222*0Sstevel@tonic-gate for (iter = similar_hba_groups; iter != NULL; iter = iter->next) {
223*0Sstevel@tonic-gate dlist_free_items((dlist_t *)iter->obj, NULL);
224*0Sstevel@tonic-gate }
225*0Sstevel@tonic-gate dlist_free_items(similar_hba_groups, NULL);
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gate /* try all HBAs */
228*0Sstevel@tonic-gate if (concat == NULL && error == 0) {
229*0Sstevel@tonic-gate
230*0Sstevel@tonic-gate any_hba_strategy_order_t order;
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate for (order = CONCAT_ACROSS_ANY_HBAS;
233*0Sstevel@tonic-gate (order < N_ANY_HBA_STRATEGIES) &&
234*0Sstevel@tonic-gate (concat == NULL) && (error == 0);
235*0Sstevel@tonic-gate order++) {
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gate dlist_t *selhbas = NULL;
238*0Sstevel@tonic-gate dlist_t *disks = NULL;
239*0Sstevel@tonic-gate
240*0Sstevel@tonic-gate switch (order) {
241*0Sstevel@tonic-gate
242*0Sstevel@tonic-gate case CONCAT_ACROSS_ANY_HBAS:
243*0Sstevel@tonic-gate
244*0Sstevel@tonic-gate error = select_hbas_with_n_disks(
245*0Sstevel@tonic-gate request, usable_hbas, 1, &selhbas, &disks);
246*0Sstevel@tonic-gate
247*0Sstevel@tonic-gate if (error == 0) {
248*0Sstevel@tonic-gate
249*0Sstevel@tonic-gate /* BEGIN CSTYLED */
250*0Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
251*0Sstevel@tonic-gate gettext(" -->Strategy 3: use disks from all available HBAs - concat across HBAs\n"));
252*0Sstevel@tonic-gate /* END CSTYLED */
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate error = populate_concat(
255*0Sstevel@tonic-gate request, nbytes, disks,
256*0Sstevel@tonic-gate NULL, &concat);
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gate break;
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate default:
262*0Sstevel@tonic-gate break;
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate
265*0Sstevel@tonic-gate dlist_free_items(disks, NULL);
266*0Sstevel@tonic-gate dlist_free_items(selhbas, NULL);
267*0Sstevel@tonic-gate }
268*0Sstevel@tonic-gate }
269*0Sstevel@tonic-gate
270*0Sstevel@tonic-gate if (concat != NULL) {
271*0Sstevel@tonic-gate
272*0Sstevel@tonic-gate dlist_t *item = dlist_new_item(concat);
273*0Sstevel@tonic-gate if (item == NULL) {
274*0Sstevel@tonic-gate error = ENOMEM;
275*0Sstevel@tonic-gate } else {
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate *results = dlist_append(item, *results, AT_TAIL);
278*0Sstevel@tonic-gate
279*0Sstevel@tonic-gate print_layout_success_msg();
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate } else if (error != 0) {
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate print_debug_failure_msg(
285*0Sstevel@tonic-gate devconfig_type_to_str(TYPE_CONCAT),
286*0Sstevel@tonic-gate get_error_string(error));
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate } else {
289*0Sstevel@tonic-gate
290*0Sstevel@tonic-gate print_insufficient_resources_msg(
291*0Sstevel@tonic-gate devconfig_type_to_str(TYPE_CONCAT));
292*0Sstevel@tonic-gate error = -1;
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate
295*0Sstevel@tonic-gate return (error);
296*0Sstevel@tonic-gate }
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate static int
compose_concat_within_hba(devconfig_t * request,dlist_t * hbas,uint64_t nbytes,devconfig_t ** concat)299*0Sstevel@tonic-gate compose_concat_within_hba(
300*0Sstevel@tonic-gate devconfig_t *request,
301*0Sstevel@tonic-gate dlist_t *hbas,
302*0Sstevel@tonic-gate uint64_t nbytes,
303*0Sstevel@tonic-gate devconfig_t **concat)
304*0Sstevel@tonic-gate {
305*0Sstevel@tonic-gate int error = 0;
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate dlist_t *iter = NULL;
308*0Sstevel@tonic-gate
309*0Sstevel@tonic-gate for (iter = hbas;
310*0Sstevel@tonic-gate (iter != NULL) && (*concat == NULL) && (error == 0);
311*0Sstevel@tonic-gate iter = iter->next) {
312*0Sstevel@tonic-gate
313*0Sstevel@tonic-gate dm_descriptor_t hba = (uintptr_t)iter->obj;
314*0Sstevel@tonic-gate dlist_t *disks = NULL;
315*0Sstevel@tonic-gate uint64_t space = 0;
316*0Sstevel@tonic-gate char *name;
317*0Sstevel@tonic-gate
318*0Sstevel@tonic-gate /* check for sufficient space on the HBA */
319*0Sstevel@tonic-gate ((error = get_display_name(hba, &name)) != 0) ||
320*0Sstevel@tonic-gate (error = hba_get_avail_disks_and_space(request,
321*0Sstevel@tonic-gate hba, &disks, &space));
322*0Sstevel@tonic-gate
323*0Sstevel@tonic-gate if (error == 0) {
324*0Sstevel@tonic-gate if (space >= nbytes) {
325*0Sstevel@tonic-gate error = populate_concat(request, nbytes, disks,
326*0Sstevel@tonic-gate NULL, concat);
327*0Sstevel@tonic-gate } else {
328*0Sstevel@tonic-gate print_hba_insufficient_space_msg(name, space);
329*0Sstevel@tonic-gate }
330*0Sstevel@tonic-gate }
331*0Sstevel@tonic-gate
332*0Sstevel@tonic-gate dlist_free_items(disks, NULL);
333*0Sstevel@tonic-gate }
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate return (error);
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gate /*
339*0Sstevel@tonic-gate * FUNCTION: populate_concat(devconfig_t *request, uint64_t nbytes,
340*0Sstevel@tonic-gate * dlist_t *disks, dlist_t *othervols,
341*0Sstevel@tonic-gate * devconfig_t **concat)
342*0Sstevel@tonic-gate *
343*0Sstevel@tonic-gate * INPUT: request - pointer to a request devconfig_t
344*0Sstevel@tonic-gate * nbytes - desired concat size
345*0Sstevel@tonic-gate * disks - pointer to a list of availalb disks
346*0Sstevel@tonic-gate * othervols - pointer to a list of other volumes whose
347*0Sstevel@tonic-gate * composition may affect this concat
348*0Sstevel@tonic-gate * (e.g., submirrors of the same mirror)
349*0Sstevel@tonic-gate *
350*0Sstevel@tonic-gate * OUTPUT: concat - pointer to a devconfig_t to hold resulting concat
351*0Sstevel@tonic-gate *
352*0Sstevel@tonic-gate * RETURNS: int - 0 on success
353*0Sstevel@tonic-gate * !0 otherwise.
354*0Sstevel@tonic-gate *
355*0Sstevel@tonic-gate * PURPOSE: Helper to populate a concat with the specified aggregate
356*0Sstevel@tonic-gate * capacity using slices on disks in the input list.
357*0Sstevel@tonic-gate *
358*0Sstevel@tonic-gate * If the othervols list is not empty, the slice components
359*0Sstevel@tonic-gate * chosen for the concat must not on the same disks as any
360*0Sstevel@tonic-gate * of the other volumes.
361*0Sstevel@tonic-gate *
362*0Sstevel@tonic-gate * If sufficient slice components can be found, the concat
363*0Sstevel@tonic-gate * is assembled and returned.
364*0Sstevel@tonic-gate */
365*0Sstevel@tonic-gate int
populate_concat(devconfig_t * request,uint64_t nbytes,dlist_t * disks,dlist_t * othervols,devconfig_t ** concat)366*0Sstevel@tonic-gate populate_concat(
367*0Sstevel@tonic-gate devconfig_t *request,
368*0Sstevel@tonic-gate uint64_t nbytes,
369*0Sstevel@tonic-gate dlist_t *disks,
370*0Sstevel@tonic-gate dlist_t *othervols,
371*0Sstevel@tonic-gate devconfig_t **concat)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate dlist_t *other_hbas = NULL;
374*0Sstevel@tonic-gate dlist_t *other_disks = NULL;
375*0Sstevel@tonic-gate
376*0Sstevel@tonic-gate dlist_t *slices = NULL;
377*0Sstevel@tonic-gate dlist_t *comps = NULL;
378*0Sstevel@tonic-gate
379*0Sstevel@tonic-gate uint16_t npaths = 0;
380*0Sstevel@tonic-gate uint64_t capacity = 0;
381*0Sstevel@tonic-gate int error = 0;
382*0Sstevel@tonic-gate
383*0Sstevel@tonic-gate *concat = NULL;
384*0Sstevel@tonic-gate
385*0Sstevel@tonic-gate ((error = disks_get_avail_slices(request, disks, &slices)) != 0) ||
386*0Sstevel@tonic-gate (error = get_volume_npaths(request, &npaths));
387*0Sstevel@tonic-gate if (error != 0) {
388*0Sstevel@tonic-gate dlist_free_items(slices, NULL);
389*0Sstevel@tonic-gate return (error);
390*0Sstevel@tonic-gate }
391*0Sstevel@tonic-gate
392*0Sstevel@tonic-gate print_populate_volume_msg(devconfig_type_to_str(TYPE_CONCAT), nbytes);
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate if (slices == NULL) {
395*0Sstevel@tonic-gate print_populate_no_slices_msg();
396*0Sstevel@tonic-gate return (0);
397*0Sstevel@tonic-gate }
398*0Sstevel@tonic-gate
399*0Sstevel@tonic-gate /* determine HBAs and disks used by othervols */
400*0Sstevel@tonic-gate error = get_hbas_and_disks_used_by_volumes(othervols,
401*0Sstevel@tonic-gate &other_hbas, &other_disks);
402*0Sstevel@tonic-gate if (error != 0) {
403*0Sstevel@tonic-gate dlist_free_items(other_hbas, NULL);
404*0Sstevel@tonic-gate dlist_free_items(other_disks, NULL);
405*0Sstevel@tonic-gate return (error);
406*0Sstevel@tonic-gate }
407*0Sstevel@tonic-gate
408*0Sstevel@tonic-gate print_populate_choose_slices_msg();
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate while (capacity < nbytes) {
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate devconfig_t *comp = NULL;
413*0Sstevel@tonic-gate dlist_t *item = NULL;
414*0Sstevel@tonic-gate dlist_t *rmvd = NULL;
415*0Sstevel@tonic-gate char *cname = NULL;
416*0Sstevel@tonic-gate uint64_t csize = 0;
417*0Sstevel@tonic-gate
418*0Sstevel@tonic-gate /* BEGIN CSTYLED */
419*0Sstevel@tonic-gate /*
420*0Sstevel@tonic-gate * 1st B_TRUE: require a different disk than those used by
421*0Sstevel@tonic-gate * comps and othervols
422*0Sstevel@tonic-gate * 1st B_FALSE: slice with size less that requested is acceptable
423*0Sstevel@tonic-gate * 2nd B_FALSE: do not add an extra cylinder when resizing slice,
424*0Sstevel@tonic-gate * this is only necessary for Stripe components whose sizes
425*0Sstevel@tonic-gate * get rounded down to an interlace multiple and then down
426*0Sstevel@tonic-gate * to a cylinder boundary.
427*0Sstevel@tonic-gate *
428*0Sstevel@tonic-gate */
429*0Sstevel@tonic-gate /* END CSTYLED */
430*0Sstevel@tonic-gate error = choose_slice((nbytes-capacity), npaths, slices, comps,
431*0Sstevel@tonic-gate other_hbas, other_disks, B_TRUE, B_FALSE, B_FALSE, &comp);
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate if ((error == 0) && (comp != NULL)) {
434*0Sstevel@tonic-gate
435*0Sstevel@tonic-gate item = dlist_new_item(comp);
436*0Sstevel@tonic-gate if (item == NULL) {
437*0Sstevel@tonic-gate error = ENOMEM;
438*0Sstevel@tonic-gate } else {
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate /* add selected component to comp list */
441*0Sstevel@tonic-gate comps = dlist_append(item, comps, AT_HEAD);
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate /* remove it from the available list */
444*0Sstevel@tonic-gate slices = dlist_remove_equivalent_item(slices, (void *) comp,
445*0Sstevel@tonic-gate compare_devconfig_and_descriptor_names, &rmvd);
446*0Sstevel@tonic-gate
447*0Sstevel@tonic-gate if (rmvd != NULL) {
448*0Sstevel@tonic-gate free(rmvd);
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate
451*0Sstevel@tonic-gate /* add the component slice to the used list */
452*0Sstevel@tonic-gate if ((error = devconfig_get_name(comp, &cname)) == 0) {
453*0Sstevel@tonic-gate error = add_used_slice_by_name(cname);
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate /* increment concat's capacity */
457*0Sstevel@tonic-gate if ((error == 0) &&
458*0Sstevel@tonic-gate (error = devconfig_get_size(comp, &csize)) == 0) {
459*0Sstevel@tonic-gate capacity += csize;
460*0Sstevel@tonic-gate }
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate } else {
464*0Sstevel@tonic-gate /* no possible slice */
465*0Sstevel@tonic-gate break;
466*0Sstevel@tonic-gate }
467*0Sstevel@tonic-gate }
468*0Sstevel@tonic-gate
469*0Sstevel@tonic-gate dlist_free_items(slices, NULL);
470*0Sstevel@tonic-gate dlist_free_items(other_hbas, NULL);
471*0Sstevel@tonic-gate dlist_free_items(other_disks, NULL);
472*0Sstevel@tonic-gate
473*0Sstevel@tonic-gate if (capacity >= nbytes) {
474*0Sstevel@tonic-gate
475*0Sstevel@tonic-gate error = assemble_concat(request, comps, concat);
476*0Sstevel@tonic-gate
477*0Sstevel@tonic-gate if (error == 0) {
478*0Sstevel@tonic-gate print_populate_success_msg();
479*0Sstevel@tonic-gate } else {
480*0Sstevel@tonic-gate /* undo any slicing done for the concat */
481*0Sstevel@tonic-gate dlist_free_items(comps, free_devconfig_object);
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate
484*0Sstevel@tonic-gate } else if (error == 0) {
485*0Sstevel@tonic-gate
486*0Sstevel@tonic-gate if (capacity > 0) {
487*0Sstevel@tonic-gate dlist_free_items(comps, free_devconfig_object);
488*0Sstevel@tonic-gate print_insufficient_capacity_msg(capacity);
489*0Sstevel@tonic-gate } else {
490*0Sstevel@tonic-gate print_populate_no_slices_msg();
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate }
494*0Sstevel@tonic-gate
495*0Sstevel@tonic-gate return (error);
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate
498*0Sstevel@tonic-gate /*
499*0Sstevel@tonic-gate * FUNCTION: populate_explicit_concat(devconfig_t *request,
500*0Sstevel@tonic-gate * dlist_t **results)
501*0Sstevel@tonic-gate *
502*0Sstevel@tonic-gate * INPUT: request - pointer to a request devconfig_t
503*0Sstevel@tonic-gate *
504*0Sstevel@tonic-gate * OUTPUT: results - pointer to a list of volume devconfig_t results
505*0Sstevel@tonic-gate *
506*0Sstevel@tonic-gate * RETURNS: int - 0 on success
507*0Sstevel@tonic-gate * !0 otherwise.
508*0Sstevel@tonic-gate *
509*0Sstevel@tonic-gate * PURPOSE: Processes the input concat request that specifies explicit
510*0Sstevel@tonic-gate * slice components.
511*0Sstevel@tonic-gate *
512*0Sstevel@tonic-gate * The components have already been validated and reserved,
513*0Sstevel@tonic-gate * all that is required is to create devconfig_t structs
514*0Sstevel@tonic-gate * for each requested slice.
515*0Sstevel@tonic-gate *
516*0Sstevel@tonic-gate * The net size of the concat is determined by the slice
517*0Sstevel@tonic-gate * components.
518*0Sstevel@tonic-gate *
519*0Sstevel@tonic-gate * The concat devconfig_t is assembled and appended to the
520*0Sstevel@tonic-gate * results list.
521*0Sstevel@tonic-gate *
522*0Sstevel@tonic-gate * This function is also called from
523*0Sstevel@tonic-gate * layout_mirror.populate_explicit_mirror()
524*0Sstevel@tonic-gate */
525*0Sstevel@tonic-gate int
populate_explicit_concat(devconfig_t * request,dlist_t ** results)526*0Sstevel@tonic-gate populate_explicit_concat(
527*0Sstevel@tonic-gate devconfig_t *request,
528*0Sstevel@tonic-gate dlist_t **results)
529*0Sstevel@tonic-gate {
530*0Sstevel@tonic-gate int error = 0;
531*0Sstevel@tonic-gate
532*0Sstevel@tonic-gate dlist_t *comps = NULL;
533*0Sstevel@tonic-gate dlist_t *iter = NULL;
534*0Sstevel@tonic-gate dlist_t *item = NULL;
535*0Sstevel@tonic-gate
536*0Sstevel@tonic-gate devconfig_t *concat = NULL;
537*0Sstevel@tonic-gate
538*0Sstevel@tonic-gate print_layout_explicit_msg(devconfig_type_to_str(TYPE_CONCAT));
539*0Sstevel@tonic-gate
540*0Sstevel@tonic-gate /* assemble components */
541*0Sstevel@tonic-gate iter = devconfig_get_components(request);
542*0Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) {
543*0Sstevel@tonic-gate
544*0Sstevel@tonic-gate devconfig_t *rqst = (devconfig_t *)iter->obj;
545*0Sstevel@tonic-gate dm_descriptor_t rqst_slice = NULL;
546*0Sstevel@tonic-gate char *rqst_name = NULL;
547*0Sstevel@tonic-gate devconfig_t *comp = NULL;
548*0Sstevel@tonic-gate
549*0Sstevel@tonic-gate /* slice components have been validated */
550*0Sstevel@tonic-gate /* turn each into a devconfig_t */
551*0Sstevel@tonic-gate ((error = devconfig_get_name(rqst, &rqst_name)) != 0) ||
552*0Sstevel@tonic-gate (error = slice_get_by_name(rqst_name, &rqst_slice)) ||
553*0Sstevel@tonic-gate (error = create_devconfig_for_slice(rqst_slice, &comp));
554*0Sstevel@tonic-gate
555*0Sstevel@tonic-gate if (error == 0) {
556*0Sstevel@tonic-gate
557*0Sstevel@tonic-gate print_layout_explicit_added_msg(rqst_name);
558*0Sstevel@tonic-gate
559*0Sstevel@tonic-gate item = dlist_new_item((void *)comp);
560*0Sstevel@tonic-gate if (item == NULL) {
561*0Sstevel@tonic-gate error = ENOMEM;
562*0Sstevel@tonic-gate } else {
563*0Sstevel@tonic-gate comps = dlist_append(item, comps, AT_TAIL);
564*0Sstevel@tonic-gate }
565*0Sstevel@tonic-gate }
566*0Sstevel@tonic-gate }
567*0Sstevel@tonic-gate
568*0Sstevel@tonic-gate if (error == 0) {
569*0Sstevel@tonic-gate error = assemble_concat(request, comps, &concat);
570*0Sstevel@tonic-gate }
571*0Sstevel@tonic-gate
572*0Sstevel@tonic-gate if (error == 0) {
573*0Sstevel@tonic-gate if ((item = dlist_new_item(concat)) == NULL) {
574*0Sstevel@tonic-gate error = ENOMEM;
575*0Sstevel@tonic-gate } else {
576*0Sstevel@tonic-gate *results = dlist_append(item, *results, AT_TAIL);
577*0Sstevel@tonic-gate print_populate_success_msg();
578*0Sstevel@tonic-gate }
579*0Sstevel@tonic-gate } else {
580*0Sstevel@tonic-gate dlist_free_items(comps, free_devconfig);
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate
583*0Sstevel@tonic-gate return (error);
584*0Sstevel@tonic-gate }
585*0Sstevel@tonic-gate
586*0Sstevel@tonic-gate /*
587*0Sstevel@tonic-gate * FUNCTION: assemble_concat(devconfig_t *request, dlist_t *comps,
588*0Sstevel@tonic-gate * devconfig_t **concat)
589*0Sstevel@tonic-gate *
590*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t of the current request
591*0Sstevel@tonic-gate * comps - pointer to a list of slice components
592*0Sstevel@tonic-gate *
593*0Sstevel@tonic-gate * OUPUT: concat - pointer to a devconfig_t to hold final concat
594*0Sstevel@tonic-gate *
595*0Sstevel@tonic-gate * RETURNS: int - 0 on success
596*0Sstevel@tonic-gate * !0 otherwise.
597*0Sstevel@tonic-gate *
598*0Sstevel@tonic-gate * PURPOSE: Helper which creates and populates a concat devconfig_t
599*0Sstevel@tonic-gate * struct using information from the input request and the
600*0Sstevel@tonic-gate * list of slice components.
601*0Sstevel@tonic-gate *
602*0Sstevel@tonic-gate * Determines the name of the concat either from the request
603*0Sstevel@tonic-gate * or from the default naming scheme.
604*0Sstevel@tonic-gate *
605*0Sstevel@tonic-gate * Attaches the input list of components to the devconfig.
606*0Sstevel@tonic-gate */
607*0Sstevel@tonic-gate static int
assemble_concat(devconfig_t * request,dlist_t * comps,devconfig_t ** concat)608*0Sstevel@tonic-gate assemble_concat(
609*0Sstevel@tonic-gate devconfig_t *request,
610*0Sstevel@tonic-gate dlist_t *comps,
611*0Sstevel@tonic-gate devconfig_t **concat)
612*0Sstevel@tonic-gate {
613*0Sstevel@tonic-gate char *name = NULL;
614*0Sstevel@tonic-gate int error = 0;
615*0Sstevel@tonic-gate
616*0Sstevel@tonic-gate if ((error = new_devconfig(concat, TYPE_CONCAT)) == 0) {
617*0Sstevel@tonic-gate /* set concat name, use requested name if specified */
618*0Sstevel@tonic-gate if ((error = devconfig_get_name(request, &name)) != 0) {
619*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) {
620*0Sstevel@tonic-gate volume_set_error(gettext("error getting requested name\n"));
621*0Sstevel@tonic-gate } else {
622*0Sstevel@tonic-gate error = 0;
623*0Sstevel@tonic-gate }
624*0Sstevel@tonic-gate }
625*0Sstevel@tonic-gate
626*0Sstevel@tonic-gate if (error == 0) {
627*0Sstevel@tonic-gate if (name == NULL) {
628*0Sstevel@tonic-gate if ((error = get_next_volume_name(&name,
629*0Sstevel@tonic-gate TYPE_CONCAT)) == 0) {
630*0Sstevel@tonic-gate error = devconfig_set_name(*concat, name);
631*0Sstevel@tonic-gate free(name);
632*0Sstevel@tonic-gate }
633*0Sstevel@tonic-gate } else {
634*0Sstevel@tonic-gate error = devconfig_set_name(*concat, name);
635*0Sstevel@tonic-gate }
636*0Sstevel@tonic-gate }
637*0Sstevel@tonic-gate }
638*0Sstevel@tonic-gate
639*0Sstevel@tonic-gate if (error == 0) {
640*0Sstevel@tonic-gate
641*0Sstevel@tonic-gate /* compute and save true size of concat */
642*0Sstevel@tonic-gate if (error == 0) {
643*0Sstevel@tonic-gate uint64_t nblks = 0;
644*0Sstevel@tonic-gate dlist_t *iter;
645*0Sstevel@tonic-gate
646*0Sstevel@tonic-gate for (iter = comps;
647*0Sstevel@tonic-gate (error == 0) && (iter != NULL);
648*0Sstevel@tonic-gate iter = iter->next) {
649*0Sstevel@tonic-gate
650*0Sstevel@tonic-gate devconfig_t *comp = (devconfig_t *)iter->obj;
651*0Sstevel@tonic-gate uint64_t comp_nblks = 0;
652*0Sstevel@tonic-gate
653*0Sstevel@tonic-gate if ((error = devconfig_get_size_in_blocks(comp,
654*0Sstevel@tonic-gate &comp_nblks)) == 0) {
655*0Sstevel@tonic-gate nblks += comp_nblks;
656*0Sstevel@tonic-gate }
657*0Sstevel@tonic-gate }
658*0Sstevel@tonic-gate
659*0Sstevel@tonic-gate if (error == 0) {
660*0Sstevel@tonic-gate error = devconfig_set_size_in_blocks(*concat, nblks);
661*0Sstevel@tonic-gate }
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate }
664*0Sstevel@tonic-gate
665*0Sstevel@tonic-gate if (error == 0) {
666*0Sstevel@tonic-gate devconfig_set_components(*concat, comps);
667*0Sstevel@tonic-gate } else {
668*0Sstevel@tonic-gate free_devconfig(*concat);
669*0Sstevel@tonic-gate *concat = NULL;
670*0Sstevel@tonic-gate }
671*0Sstevel@tonic-gate
672*0Sstevel@tonic-gate return (error);
673*0Sstevel@tonic-gate }
674