]>
Commit | Line | Data |
---|---|---|
642c2e96 | 1 | /* |
67cdbd7e | 2 | * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. |
9ac61d2b | 3 | * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. |
642c2e96 | 4 | * |
6606c3ae | 5 | * This file is part of LVM2. |
642c2e96 | 6 | * |
6606c3ae AK |
7 | * This copyrighted material is made available to anyone wishing to use, |
8 | * modify, copy, or redistribute it subject to the terms and conditions | |
be684599 | 9 | * of the GNU Lesser General Public License v.2.1. |
6606c3ae | 10 | * |
be684599 | 11 | * You should have received a copy of the GNU Lesser General Public License |
6606c3ae AK |
12 | * along with this program; if not, write to the Free Software Foundation, |
13 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
642c2e96 AK |
14 | */ |
15 | ||
16 | #include "tools.h" | |
60f13f01 | 17 | #include "lv_alloc.h" |
cc219483 | 18 | |
fe827798 | 19 | #include <fcntl.h> |
642c2e96 | 20 | |
8842d526 | 21 | struct lvcreate_cmdline_params { |
8191fe4f | 22 | percent_type_t percent; |
7a0b0db1 | 23 | uint64_t size; |
e6479dff DW |
24 | char **pvs; |
25 | int pv_count; | |
8842d526 DW |
26 | }; |
27 | ||
9ac61d2b AK |
28 | static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name) |
29 | { | |
30 | /* Can't do anything */ | |
31 | if (!vg_name) | |
32 | return 1; | |
33 | ||
34 | /* If VG name already known, ensure this 2nd copy is identical */ | |
35 | if (lp->vg_name && strcmp(lp->vg_name, vg_name)) { | |
36 | log_error("Inconsistent volume group names " | |
37 | "given: \"%s\" and \"%s\"", | |
38 | lp->vg_name, vg_name); | |
39 | return 0; | |
40 | } | |
41 | lp->vg_name = vg_name; | |
42 | ||
43 | return 1; | |
44 | } | |
45 | ||
8a2fc586 AK |
46 | static int _lvcreate_name_params(struct lvcreate_params *lp, |
47 | struct cmd_context *cmd, | |
48 | int *pargc, char ***pargv) | |
052360e9 JT |
49 | { |
50 | int argc = *pargc; | |
51 | char **argv = *pargv, *ptr; | |
aec21154 | 52 | const char *vg_name; |
052360e9 | 53 | |
9ac61d2b AK |
54 | lp->pool = arg_str_value(cmd, thinpool_ARG, NULL); |
55 | ||
56 | /* If --thinpool contains VG name, extract it. */ | |
57 | if (lp->pool && strchr(lp->pool, '/')) { | |
58 | if (!(lp->vg_name = extract_vgname(cmd, lp->pool))) | |
59 | return 0; | |
60 | /* Strip VG from pool */ | |
61 | if ((ptr = strrchr(lp->pool, (int) '/'))) | |
62 | lp->pool = ptr + 1; | |
63 | } | |
64 | ||
a8fb89ad | 65 | lp->lv_name = arg_str_value(cmd, name_ARG, NULL); |
052360e9 | 66 | |
9ac61d2b AK |
67 | /* If --name contains VG name, extract it. */ |
68 | if (lp->lv_name && strchr(lp->lv_name, '/')) { | |
69 | if (!_set_vg_name(lp, extract_vgname(cmd, lp->lv_name))) | |
70 | return_0; | |
71 | ||
72 | /* Strip VG from lv_name */ | |
73 | if ((ptr = strrchr(lp->lv_name, (int) '/'))) | |
74 | lp->lv_name = ptr + 1; | |
75 | } | |
76 | ||
77 | /* Need an origin? */ | |
154753db | 78 | if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) { |
9ac61d2b | 79 | /* argv[0] might be origin or vg/origin */ |
052360e9 | 80 | if (!argc) { |
b8f47d5f AK |
81 | log_error("Please specify a logical volume to act as " |
82 | "the snapshot origin."); | |
052360e9 JT |
83 | return 0; |
84 | } | |
85 | ||
9ac61d2b AK |
86 | lp->origin = skip_dev_dir(cmd, argv[0], NULL); |
87 | if (strrchr(lp->origin, '/')) { | |
88 | if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin))) | |
89 | return_0; | |
90 | ||
91 | /* Strip the volume group from the origin */ | |
92 | if ((ptr = strrchr(lp->origin, (int) '/'))) | |
93 | lp->origin = ptr + 1; | |
94 | } | |
95 | ||
24d39aa1 ZK |
96 | if (!lp->vg_name && |
97 | !_set_vg_name(lp, extract_vgname(cmd, NULL))) | |
98 | return_0; | |
e903e37d | 99 | |
9ac61d2b | 100 | if (!lp->vg_name) { |
b8f47d5f AK |
101 | log_error("The origin name should include the " |
102 | "volume group."); | |
052360e9 JT |
103 | return 0; |
104 | } | |
105 | ||
9ac61d2b AK |
106 | (*pargv)++, (*pargc)--; |
107 | } else if (seg_is_thin(lp) && !lp->pool && argc) { | |
108 | /* argv[0] might be vg or vg/Pool */ | |
109 | ||
110 | vg_name = skip_dev_dir(cmd, argv[0], NULL); | |
111 | if (!strrchr(vg_name, '/')) { | |
112 | if (!_set_vg_name(lp, vg_name)) | |
113 | return_0; | |
114 | } else { | |
115 | lp->pool = vg_name; | |
116 | if (!_set_vg_name(lp, extract_vgname(cmd, lp->pool))) | |
117 | return_0; | |
e903e37d | 118 | |
24d39aa1 ZK |
119 | if (!lp->vg_name && |
120 | !_set_vg_name(lp, extract_vgname(cmd, NULL))) | |
121 | return_0; | |
e903e37d | 122 | |
9ac61d2b AK |
123 | if (!lp->vg_name) { |
124 | log_error("The pool name should include the " | |
125 | "volume group."); | |
126 | return 0; | |
127 | } | |
0eb83127 | 128 | |
9ac61d2b AK |
129 | /* Strip the volume group */ |
130 | if ((ptr = strrchr(lp->pool, (int) '/'))) | |
131 | lp->pool = ptr + 1; | |
132 | } | |
133 | ||
134 | (*pargv)++, (*pargc)--; | |
052360e9 JT |
135 | } else { |
136 | /* | |
9ac61d2b | 137 | * If VG not on command line, try environment default. |
052360e9 JT |
138 | */ |
139 | if (!argc) { | |
9ac61d2b | 140 | if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) { |
b8f47d5f | 141 | log_error("Please provide a volume group name"); |
052360e9 JT |
142 | return 0; |
143 | } | |
052360e9 | 144 | } else { |
9397354a | 145 | vg_name = skip_dev_dir(cmd, argv[0], NULL); |
cb8920e6 | 146 | if (strrchr(vg_name, '/')) { |
fdf8038f AK |
147 | log_error("Volume group name expected " |
148 | "(no slash)"); | |
149 | return 0; | |
150 | } | |
151 | ||
9ac61d2b AK |
152 | if (!_set_vg_name(lp, vg_name)) |
153 | return_0; | |
052360e9 | 154 | |
052360e9 JT |
155 | (*pargv)++, (*pargc)--; |
156 | } | |
642c2e96 AK |
157 | } |
158 | ||
d38bf361 AK |
159 | if (!validate_name(lp->vg_name)) { |
160 | log_error("Volume group name %s has invalid characters", | |
161 | lp->vg_name); | |
162 | return 0; | |
163 | } | |
164 | ||
b8c919b4 | 165 | if (lp->lv_name) { |
c51b9fff AK |
166 | if (!apply_lvname_restrictions(lp->lv_name)) |
167 | return_0; | |
5a52dca9 | 168 | |
b8c919b4 | 169 | if (!validate_name(lp->lv_name)) { |
8387b473 AK |
170 | log_error("Logical volume name \"%s\" is invalid", |
171 | lp->lv_name); | |
b8c919b4 AK |
172 | return 0; |
173 | } | |
7e4867f7 AK |
174 | } |
175 | ||
9ac61d2b AK |
176 | if (lp->pool) { |
177 | if (!apply_lvname_restrictions(lp->pool)) | |
178 | return_0; | |
179 | ||
180 | if (!validate_name(lp->pool)) { | |
181 | log_error("Logical volume name \"%s\" is invalid", | |
182 | lp->pool); | |
183 | return 0; | |
184 | } | |
185 | ||
186 | if (lp->lv_name && !strcmp(lp->lv_name, lp->pool)) { | |
187 | log_error("Logical volume name %s and pool name %s must be different.", | |
188 | lp->lv_name, lp->pool); | |
189 | return 0; | |
190 | } | |
191 | } | |
192 | ||
193 | return 1; | |
194 | } | |
195 | ||
196 | /* | |
197 | * Normal snapshot or thinly-provisioned snapshot? | |
198 | */ | |
199 | static int _determine_snapshot_type(struct volume_group *vg, | |
200 | struct lvcreate_params *lp) | |
201 | { | |
202 | struct lv_list *lvl; | |
9ac61d2b AK |
203 | |
204 | if (!(lvl = find_lv_in_vg(vg, lp->origin))) { | |
6e89eb9a ZK |
205 | log_error("Snapshot origin LV %s not found in Volume group %s.", |
206 | lp->origin, vg->name); | |
9ac61d2b AK |
207 | return 0; |
208 | } | |
209 | ||
95308c5f ZK |
210 | if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) { |
211 | if (!lv_is_thin_volume(lvl->lv)) { | |
212 | log_error("Please specify either size or extents with snapshots."); | |
213 | return 0; | |
214 | } | |
215 | ||
9ac61d2b AK |
216 | lp->thin = 1; |
217 | if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin"))) | |
218 | return_0; | |
219 | ||
bb6f9b10 | 220 | lp->pool = first_seg(lvl->lv)->pool_lv->name; |
9ac61d2b AK |
221 | } |
222 | ||
052360e9 JT |
223 | return 1; |
224 | } | |
225 | ||
8675b317 DW |
226 | /* |
227 | * Update extents parameters based on other parameters which affect the size | |
6e89eb9a | 228 | * calculation. |
8675b317 DW |
229 | * NOTE: We must do this here because of the percent_t typedef and because we |
230 | * need the vg. | |
231 | */ | |
232 | static int _update_extents_params(struct volume_group *vg, | |
8842d526 DW |
233 | struct lvcreate_params *lp, |
234 | struct lvcreate_cmdline_params *lcp) | |
8675b317 DW |
235 | { |
236 | uint32_t pv_extent_count; | |
5bc2af26 | 237 | struct logical_volume *origin = NULL; |
8675b317 | 238 | |
7a0b0db1 | 239 | if (lcp->size && |
9963d071 | 240 | !(lp->extents = extents_from_size(vg->cmd, lcp->size, |
8675b317 DW |
241 | vg->extent_size))) |
242 | return_0; | |
243 | ||
244 | if (lp->voriginsize && | |
9963d071 | 245 | !(lp->voriginextents = extents_from_size(vg->cmd, lp->voriginsize, |
8675b317 DW |
246 | vg->extent_size))) |
247 | return_0; | |
248 | ||
249 | /* | |
8842d526 | 250 | * Create the pv list before we parse lcp->percent - might be |
8675b317 DW |
251 | * PERCENT_PVSs |
252 | */ | |
e6479dff | 253 | if (lcp->pv_count) { |
8675b317 | 254 | if (!(lp->pvh = create_pv_list(vg->cmd->mem, vg, |
e6479dff | 255 | lcp->pv_count, lcp->pvs, 1))) |
8675b317 DW |
256 | return_0; |
257 | } else | |
258 | lp->pvh = &vg->pvs; | |
259 | ||
8842d526 | 260 | switch(lcp->percent) { |
8675b317 | 261 | case PERCENT_VG: |
4fbde014 | 262 | lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); |
8675b317 DW |
263 | break; |
264 | case PERCENT_FREE: | |
4fbde014 | 265 | lp->extents = percent_of_extents(lp->extents, vg->free_count, 0); |
8675b317 DW |
266 | break; |
267 | case PERCENT_PVS: | |
ba3851fd | 268 | if (!lcp->pv_count) |
4fbde014 | 269 | lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); |
ba3851fd MB |
270 | else { |
271 | pv_extent_count = pv_list_extents_free(lp->pvh); | |
4fbde014 | 272 | lp->extents = percent_of_extents(lp->extents, pv_extent_count, 0); |
8675b317 | 273 | } |
8675b317 DW |
274 | break; |
275 | case PERCENT_LV: | |
276 | log_error("Please express size as %%VG, %%PVS, or " | |
277 | "%%FREE."); | |
278 | return 0; | |
5bc2af26 MS |
279 | case PERCENT_ORIGIN: |
280 | if (lp->snapshot && lp->origin && | |
281 | !(origin = find_lv(vg, lp->origin))) { | |
282 | log_error("Couldn't find origin volume '%s'.", | |
283 | lp->origin); | |
284 | return 0; | |
285 | } | |
fc218865 ZK |
286 | if (!origin) { |
287 | log_error(INTERNAL_ERROR "Couldn't find origin volume."); | |
288 | return 0; | |
289 | } | |
4fbde014 | 290 | lp->extents = percent_of_extents(lp->extents, origin->le_count, 0); |
5bc2af26 | 291 | break; |
8675b317 DW |
292 | case PERCENT_NONE: |
293 | break; | |
294 | } | |
b8cac455 | 295 | |
79c42c66 ZK |
296 | if (lp->create_thin_pool) { |
297 | if (!arg_count(vg->cmd, poolmetadatasize_ARG)) | |
298 | /* Defaults to nr_pool_blocks * 64b */ | |
299 | lp->poolmetadatasize = (uint64_t) lp->extents * vg->extent_size / | |
300 | (uint64_t) (lp->chunk_size * (SECTOR_SIZE / UINT64_C(64))); | |
301 | ||
302 | if (lp->poolmetadatasize > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) { | |
303 | if (arg_count(vg->cmd, poolmetadatasize_ARG)) | |
304 | log_warn("WARNING: Maximum supported pool metadata size is 16GB."); | |
305 | lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; | |
306 | } else if (lp->poolmetadatasize < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) { | |
307 | if (arg_count(vg->cmd, poolmetadatasize_ARG)) | |
308 | log_warn("WARNING: Minimum supported pool metadata size is 2M."); | |
309 | lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE; | |
310 | } | |
311 | ||
312 | log_verbose("Setting pool metadata size to %" PRIu64 " sectors.", | |
313 | lp->poolmetadatasize); | |
314 | ||
315 | if (!(lp->poolmetadataextents = | |
316 | extents_from_size(vg->cmd, lp->poolmetadatasize, vg->extent_size))) | |
317 | return_0; | |
318 | } | |
b8cac455 | 319 | |
8675b317 DW |
320 | return 1; |
321 | } | |
322 | ||
052360e9 | 323 | static int _read_size_params(struct lvcreate_params *lp, |
8842d526 | 324 | struct lvcreate_cmdline_params *lcp, |
72b2cb61 | 325 | struct cmd_context *cmd) |
052360e9 | 326 | { |
9ac61d2b | 327 | if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) { |
1832f310 | 328 | log_error("Please specify either size or extents (not both)"); |
052360e9 | 329 | return 0; |
642c2e96 AK |
330 | } |
331 | ||
9ac61d2b AK |
332 | if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) { |
333 | log_error("Please specify either size or extents"); | |
334 | return 0; | |
335 | } | |
336 | ||
fdd4f3c0 | 337 | if (arg_count(cmd, extents_ARG)) { |
fbf6b89a | 338 | if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) { |
fdd4f3c0 AK |
339 | log_error("Negative number of extents is invalid"); |
340 | return 0; | |
341 | } | |
8ef2b021 | 342 | lp->extents = arg_uint_value(cmd, extents_ARG, 0); |
8842d526 | 343 | lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE); |
fdd4f3c0 | 344 | } |
052360e9 JT |
345 | |
346 | /* Size returned in kilobyte units; held in sectors */ | |
fdd4f3c0 | 347 | if (arg_count(cmd, size_ARG)) { |
fbf6b89a | 348 | if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) { |
fdd4f3c0 AK |
349 | log_error("Negative size is invalid"); |
350 | return 0; | |
351 | } | |
7a0b0db1 | 352 | lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)); |
8842d526 | 353 | lcp->percent = PERCENT_NONE; |
fdd4f3c0 | 354 | } |
052360e9 | 355 | |
9ac61d2b AK |
356 | /* If size/extents given with thin, then we are creating a thin pool */ |
357 | if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG))) | |
358 | lp->create_thin_pool = 1; | |
359 | ||
b8cac455 ZK |
360 | if (arg_count(cmd, poolmetadatasize_ARG)) { |
361 | if (!seg_is_thin(lp)) { | |
362 | log_error("--poolmetadatasize may only be specified when allocating the thin pool."); | |
363 | return 0; | |
364 | } | |
fbf6b89a | 365 | if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { |
b8cac455 ZK |
366 | log_error("Negative poolmetadatasize is invalid."); |
367 | return 0; | |
368 | } | |
369 | lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0)); | |
370 | } | |
371 | ||
87f42fda | 372 | /* Size returned in kilobyte units; held in sectors */ |
154753db | 373 | if (arg_count(cmd, virtualsize_ARG)) { |
9ac61d2b AK |
374 | if (seg_is_thin_pool(lp)) { |
375 | log_error("Virtual size in incompatible with thin_pool segment type."); | |
376 | return 0; | |
377 | } | |
fbf6b89a | 378 | if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) { |
87f42fda AK |
379 | log_error("Negative virtual origin size is invalid"); |
380 | return 0; | |
381 | } | |
154753db | 382 | lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG, |
87f42fda AK |
383 | UINT64_C(0)); |
384 | if (!lp->voriginsize) { | |
385 | log_error("Virtual origin size may not be zero"); | |
386 | return 0; | |
387 | } | |
9ac61d2b AK |
388 | } else { |
389 | /* No virtual size given, so no thin LV to create. */ | |
f582793f | 390 | if (seg_is_thin_volume(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool"))) |
9ac61d2b AK |
391 | return_0; |
392 | ||
393 | lp->thin = 0; | |
87f42fda AK |
394 | } |
395 | ||
052360e9 JT |
396 | return 1; |
397 | } | |
398 | ||
f18ef244 DW |
399 | /* |
400 | * Generic mirror parameter checks. | |
401 | * FIXME: Should eventually be moved into lvm library. | |
402 | */ | |
08f1ddea | 403 | static int _validate_mirror_params(const struct cmd_context *cmd __attribute__((unused)), |
bf4f5b21 | 404 | const struct lvcreate_params *lp) |
60f13f01 | 405 | { |
916490f8 | 406 | int pagesize = lvm_getpagesize(); |
60f13f01 AK |
407 | |
408 | if (lp->region_size & (lp->region_size - 1)) { | |
409 | log_error("Region size (%" PRIu32 ") must be a power of 2", | |
410 | lp->region_size); | |
411 | return 0; | |
412 | } | |
413 | ||
5c24f56b AK |
414 | if (lp->region_size % (pagesize >> SECTOR_SHIFT)) { |
415 | log_error("Region size (%" PRIu32 ") must be a multiple of " | |
416 | "machine memory page size (%d)", | |
417 | lp->region_size, pagesize >> SECTOR_SHIFT); | |
418 | return 0; | |
419 | } | |
420 | ||
12ccdb25 AK |
421 | if (!lp->region_size) { |
422 | log_error("Non-zero region size must be supplied."); | |
423 | return 0; | |
424 | } | |
425 | ||
f18ef244 DW |
426 | return 1; |
427 | } | |
428 | ||
429 | static int _read_mirror_params(struct lvcreate_params *lp, | |
cd3ae9bc | 430 | struct cmd_context *cmd) |
f18ef244 DW |
431 | { |
432 | int region_size; | |
433 | const char *mirrorlog; | |
f3ac7d1b | 434 | int corelog = arg_count(cmd, corelog_ARG); |
19583d11 | 435 | |
2b849ab4 | 436 | mirrorlog = arg_str_value(cmd, mirrorlog_ARG, |
f3ac7d1b | 437 | corelog ? "core" : DEFAULT_MIRRORLOG); |
2b849ab4 | 438 | |
7a369d37 JEB |
439 | if (strcmp("core", mirrorlog) && corelog) { |
440 | log_error("Please use only one of --mirrorlog or --corelog"); | |
441 | return 0; | |
442 | } | |
443 | ||
444 | if (!strcmp("mirrored", mirrorlog)) { | |
445 | lp->log_count = 2; | |
446 | } else if (!strcmp("disk", mirrorlog)) { | |
77dd1c0e | 447 | lp->log_count = 1; |
f3ac7d1b | 448 | } else if (!strcmp("core", mirrorlog)) |
77dd1c0e | 449 | lp->log_count = 0; |
edb3374d AK |
450 | else { |
451 | log_error("Unknown mirrorlog type: %s", mirrorlog); | |
452 | return 0; | |
19583d11 JEB |
453 | } |
454 | ||
edb3374d AK |
455 | log_verbose("Setting logging type to %s", mirrorlog); |
456 | ||
a8fb89ad | 457 | lp->nosync = arg_is_set(cmd, nosync_ARG); |
f17f6814 | 458 | |
f18ef244 | 459 | if (arg_count(cmd, regionsize_ARG)) { |
fbf6b89a | 460 | if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) { |
f18ef244 DW |
461 | log_error("Negative regionsize is invalid"); |
462 | return 0; | |
463 | } | |
204a12e5 | 464 | lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0); |
f18ef244 DW |
465 | } else { |
466 | region_size = 2 * find_config_tree_int(cmd, | |
467 | "activation/mirror_region_size", | |
468 | DEFAULT_MIRROR_REGION_SIZE); | |
469 | if (region_size < 0) { | |
470 | log_error("Negative regionsize in configuration file " | |
471 | "is invalid"); | |
472 | return 0; | |
473 | } | |
474 | lp->region_size = region_size; | |
475 | } | |
476 | ||
477 | if (!_validate_mirror_params(cmd, lp)) | |
478 | return 0; | |
479 | ||
60f13f01 AK |
480 | return 1; |
481 | } | |
482 | ||
cac52ca4 JEB |
483 | static int _read_raid_params(struct lvcreate_params *lp, |
484 | struct cmd_context *cmd) | |
485 | { | |
486 | if (!segtype_is_raid(lp->segtype)) | |
487 | return 1; | |
488 | ||
489 | if (arg_count(cmd, corelog_ARG) || | |
490 | arg_count(cmd, mirrorlog_ARG)) { | |
491 | log_error("Log options not applicable to %s segtype", | |
492 | lp->segtype->name); | |
493 | return 0; | |
494 | } | |
495 | ||
496 | /* | |
497 | * get_stripe_params is called before _read_raid_params | |
498 | * and already sets: | |
499 | * lp->stripes | |
500 | * lp->stripe_size | |
501 | * | |
502 | * For RAID 4/5/6, these values must be set. | |
503 | */ | |
870762d8 JEB |
504 | if (!segtype_is_mirrored(lp->segtype) && |
505 | (lp->stripes <= lp->segtype->parity_devs)) { | |
506 | log_error("Number of stripes must be at least %d for %s", | |
507 | lp->segtype->parity_devs + 1, lp->segtype->name); | |
cac52ca4 JEB |
508 | return 0; |
509 | } | |
510 | ||
511 | /* | |
512 | * _read_mirror_params is called before _read_raid_params | |
513 | * and already sets: | |
514 | * lp->nosync | |
515 | * lp->region_size | |
516 | * | |
517 | * But let's ensure that programmers don't reorder | |
518 | * that by checking and warning if they aren't set. | |
519 | */ | |
520 | if (!lp->region_size) { | |
9ac61d2b AK |
521 | log_error(INTERNAL_ERROR "region_size not set."); |
522 | return 0; | |
523 | } | |
524 | ||
525 | return 1; | |
526 | } | |
527 | ||
528 | static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd) | |
529 | { | |
530 | unsigned pagesize; | |
531 | ||
fbf6b89a ZK |
532 | lp->activate = (activation_change_t) |
533 | arg_uint_value(cmd, available_ARG, CHANGE_AY); | |
9ac61d2b AK |
534 | |
535 | if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) { | |
536 | if (lp->zero && !seg_is_thin(lp)) { | |
537 | log_error("--available n requires --zero n"); | |
538 | return 0; | |
539 | } | |
540 | } | |
541 | ||
542 | /* | |
543 | * Read ahead. | |
544 | */ | |
545 | lp->read_ahead = arg_uint_value(cmd, readahead_ARG, | |
546 | cmd->default_settings.read_ahead); | |
547 | pagesize = lvm_getpagesize() >> SECTOR_SHIFT; | |
548 | if (lp->read_ahead != DM_READ_AHEAD_AUTO && | |
549 | lp->read_ahead != DM_READ_AHEAD_NONE && | |
550 | lp->read_ahead % pagesize) { | |
551 | if (lp->read_ahead < pagesize) | |
552 | lp->read_ahead = pagesize; | |
553 | else | |
554 | lp->read_ahead = (lp->read_ahead / pagesize) * pagesize; | |
555 | log_warn("WARNING: Overriding readahead to %u sectors, a multiple " | |
556 | "of %uK page size.", lp->read_ahead, pagesize >> 1); | |
557 | } | |
558 | ||
559 | /* | |
560 | * Permissions. | |
561 | */ | |
562 | lp->permission = arg_uint_value(cmd, permission_ARG, | |
563 | LVM_READ | LVM_WRITE); | |
564 | ||
565 | if (lp->thin && !(lp->permission & LVM_WRITE)) { | |
566 | log_error("Read-only thin volumes are not currently supported."); | |
567 | return 0; | |
568 | } | |
569 | ||
570 | /* Must not zero read only volume */ | |
571 | if (!(lp->permission & LVM_WRITE)) | |
572 | lp->zero = 0; | |
573 | ||
574 | lp->minor = arg_int_value(cmd, minor_ARG, -1); | |
575 | lp->major = arg_int_value(cmd, major_ARG, -1); | |
576 | ||
577 | /* Persistent minor */ | |
578 | if (arg_count(cmd, persistent_ARG)) { | |
579 | if (lp->create_thin_pool && !lp->thin) { | |
580 | log_error("--persistent is not permitted when creating a thin pool device."); | |
581 | return 0; | |
582 | } | |
583 | if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) { | |
584 | if (lp->minor == -1) { | |
585 | log_error("Please specify minor number with " | |
586 | "--minor when using -My"); | |
587 | return 0; | |
588 | } | |
589 | if (lp->major == -1) { | |
590 | log_error("Please specify major number with " | |
591 | "--major when using -My"); | |
592 | return 0; | |
593 | } | |
594 | } else { | |
595 | if ((lp->minor != -1) || (lp->major != -1)) { | |
596 | log_error("--major and --minor incompatible " | |
597 | "with -Mn"); | |
598 | return 0; | |
599 | } | |
600 | } | |
601 | } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) { | |
602 | log_error("--major and --minor require -My"); | |
cac52ca4 JEB |
603 | return 0; |
604 | } | |
605 | ||
606 | return 1; | |
607 | } | |
608 | ||
8842d526 DW |
609 | static int _lvcreate_params(struct lvcreate_params *lp, |
610 | struct lvcreate_cmdline_params *lcp, | |
611 | struct cmd_context *cmd, | |
8a2fc586 | 612 | int argc, char **argv) |
052360e9 | 613 | { |
a0a23eff | 614 | int contiguous; |
f8452d8c | 615 | struct arg_value_group_list *current_group; |
cac52ca4 | 616 | const char *segtype_str; |
f8452d8c | 617 | const char *tag; |
a0a23eff | 618 | |
fdf8038f | 619 | memset(lp, 0, sizeof(*lp)); |
8842d526 | 620 | memset(lcp, 0, sizeof(*lcp)); |
f8452d8c | 621 | dm_list_init(&lp->tags); |
fdf8038f | 622 | |
052360e9 | 623 | /* |
1832f310 | 624 | * Check selected options are compatible and determine segtype |
052360e9 | 625 | */ |
0ed2af7f | 626 | // FIXME -m0 implies *striped* |
9ac61d2b AK |
627 | if (arg_count(cmd, thin_ARG) && arg_count(cmd,mirrors_ARG)) { |
628 | log_error("--thin and --mirrors are incompatible."); | |
629 | return 0; | |
630 | } | |
631 | ||
0ed2af7f AK |
632 | // FIXME -m0 implies *striped* |
633 | ||
9ac61d2b | 634 | /* Set default segtype */ |
cac52ca4 | 635 | if (arg_count(cmd, mirrors_ARG)) |
d8b1aa19 | 636 | segtype_str = find_config_tree_str(cmd, "global/mirror_segtype_default", DEFAULT_MIRROR_SEGTYPE); |
9ac61d2b AK |
637 | else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) |
638 | segtype_str = "thin"; | |
639 | else | |
640 | segtype_str = "striped"; | |
cac52ca4 | 641 | |
1281a5e3 ZK |
642 | segtype_str = arg_str_value(cmd, type_ARG, segtype_str); |
643 | ||
644 | if (!(lp->segtype = get_segtype_from_string(cmd, segtype_str))) | |
645 | return_0; | |
1832f310 | 646 | |
ef78ebf3 | 647 | if (seg_unknown(lp)) { |
1281a5e3 | 648 | log_error("Unable to create LV with unknown segment type %s.", segtype_str); |
ef78ebf3 AK |
649 | return 0; |
650 | } | |
651 | ||
154753db | 652 | if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) || |
9ac61d2b | 653 | (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG))) |
1832f310 AK |
654 | lp->snapshot = 1; |
655 | ||
9ac61d2b AK |
656 | if (seg_is_thin_pool(lp)) { |
657 | if (lp->snapshot) { | |
658 | log_error("Snapshots are incompatible with thin_pool segment_type."); | |
659 | return 0; | |
660 | } | |
661 | lp->create_thin_pool = 1; | |
662 | } | |
663 | ||
664 | if (seg_is_thin_volume(lp)) | |
665 | lp->thin = 1; | |
666 | ||
60f13f01 AK |
667 | lp->mirrors = 1; |
668 | ||
cac52ca4 | 669 | /* Default to 2 mirrored areas if '--type mirror|raid1' */ |
09c4fd3f | 670 | if (segtype_is_mirrored(lp->segtype)) |
60f13f01 AK |
671 | lp->mirrors = 2; |
672 | ||
673 | if (arg_count(cmd, mirrors_ARG)) { | |
674 | lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; | |
f989a555 JEB |
675 | if (lp->mirrors == 1) { |
676 | if (segtype_is_mirrored(lp->segtype)) { | |
0ed2af7f | 677 | log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name); |
f989a555 JEB |
678 | return 0; |
679 | } | |
60f13f01 | 680 | log_print("Redundant mirrors argument: default is 0"); |
f989a555 | 681 | } |
fbf6b89a | 682 | if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) { |
7424de5b AK |
683 | log_error("Mirrors argument may not be negative"); |
684 | return 0; | |
685 | } | |
60f13f01 AK |
686 | } |
687 | ||
9ac61d2b AK |
688 | if (lp->snapshot && arg_count(cmd, zero_ARG)) { |
689 | log_error("-Z is incompatible with snapshots"); | |
690 | return 0; | |
fdf8038f | 691 | } |
052360e9 | 692 | |
cac52ca4 | 693 | if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) { |
60f13f01 AK |
694 | if (lp->snapshot) { |
695 | log_error("mirrors and snapshots are currently " | |
696 | "incompatible"); | |
697 | return 0; | |
698 | } | |
f17f6814 AK |
699 | } else { |
700 | if (arg_count(cmd, corelog_ARG)) { | |
701 | log_error("--corelog is only available with mirrors"); | |
702 | return 0; | |
703 | } | |
de828433 | 704 | |
dfafb8fb JEB |
705 | if (arg_count(cmd, mirrorlog_ARG)) { |
706 | log_error("--mirrorlog is only available with mirrors"); | |
707 | return 0; | |
708 | } | |
709 | ||
de828433 AK |
710 | if (arg_count(cmd, nosync_ARG)) { |
711 | log_error("--nosync is only available with mirrors"); | |
712 | return 0; | |
713 | } | |
60f13f01 AK |
714 | } |
715 | ||
1832f310 | 716 | if (activation() && lp->segtype->ops->target_present && |
81680dce | 717 | !lp->segtype->ops->target_present(cmd, NULL, NULL)) { |
1832f310 AK |
718 | log_error("%s: Required device-mapper target(s) not " |
719 | "detected in your kernel", lp->segtype->name); | |
720 | return 0; | |
721 | } | |
722 | ||
8a2fc586 | 723 | if (!_lvcreate_name_params(lp, cmd, &argc, &argv) || |
8842d526 | 724 | !_read_size_params(lp, lcp, cmd) || |
68176be1 | 725 | !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) || |
cac52ca4 | 726 | !_read_mirror_params(lp, cmd) || |
79c42c66 | 727 | !_read_raid_params(lp, cmd)) |
c51b9fff | 728 | return_0; |
d53f88d7 | 729 | |
9ac61d2b AK |
730 | if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG)) |
731 | log_warn("WARNING: Ignoring --chunksize with thin snapshots."); | |
732 | else if (lp->thin && !lp->create_thin_pool) { | |
733 | if (arg_count(cmd, chunksize_ARG)) | |
734 | log_warn("WARNING: Ignoring --chunksize when using an existing pool."); | |
735 | } else if (lp->snapshot || lp->create_thin_pool) { | |
fbf6b89a | 736 | if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) { |
9ac61d2b AK |
737 | log_error("Negative chunk size is invalid"); |
738 | return 0; | |
739 | } | |
3bc41748 ZK |
740 | if (lp->snapshot) { |
741 | lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8); | |
742 | if (lp->chunk_size < 8 || lp->chunk_size > 1024 || | |
743 | (lp->chunk_size & (lp->chunk_size - 1))) { | |
744 | log_error("Chunk size must be a power of 2 in the " | |
745 | "range 4K to 512K"); | |
746 | return 0; | |
747 | } | |
748 | } else { | |
749 | lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, DM_THIN_MIN_DATA_BLOCK_SIZE); | |
750 | if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) || | |
751 | (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE) || | |
752 | (lp->chunk_size & (lp->chunk_size - 1))) { | |
753 | log_error("Chunk size must be a power of 2 in the " | |
754 | "range %uK to %uK", (DM_THIN_MIN_DATA_BLOCK_SIZE / 2), | |
755 | (DM_THIN_MIN_DATA_BLOCK_SIZE / 2)); | |
756 | return 0; | |
757 | } | |
9ac61d2b | 758 | } |
3bc41748 | 759 | log_verbose("Setting chunksize to %u sectors.", lp->chunk_size); |
e586401e | 760 | |
9ac61d2b AK |
761 | if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) |
762 | return_0; | |
763 | } else { | |
764 | if (arg_count(cmd, chunksize_ARG)) { | |
765 | log_error("-c is only available with snapshots and thin pools"); | |
453cdee5 AK |
766 | return 0; |
767 | } | |
768 | } | |
769 | ||
052360e9 | 770 | /* |
9ac61d2b | 771 | * Should we zero the lv. |
052360e9 | 772 | */ |
9ac61d2b AK |
773 | lp->zero = strcmp(arg_str_value(cmd, zero_ARG, |
774 | (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); | |
052360e9 | 775 | |
5800aa5c MB |
776 | if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) { |
777 | log_error("Only up to %d images in mirror supported currently.", | |
778 | DEFAULT_MIRROR_MAX_IMAGES); | |
779 | return 0; | |
780 | } | |
781 | ||
052360e9 | 782 | /* |
9ac61d2b | 783 | * Allocation parameters |
052360e9 | 784 | */ |
9ac61d2b | 785 | contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); |
e0096cab | 786 | |
9ac61d2b | 787 | lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; |
052360e9 | 788 | |
fbf6b89a | 789 | lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc); |
052360e9 | 790 | |
9ac61d2b AK |
791 | if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) { |
792 | log_error("Conflicting contiguous and alloc arguments"); | |
ed8c4d99 | 793 | return 0; |
642c2e96 AK |
794 | } |
795 | ||
f8452d8c AK |
796 | dm_list_iterate_items(current_group, &cmd->arg_value_groups) { |
797 | if (!grouped_arg_is_set(current_group->arg_values, addtag_ARG)) | |
798 | continue; | |
799 | ||
800 | if (!(tag = grouped_arg_str_value(current_group->arg_values, addtag_ARG, NULL))) { | |
801 | log_error("Failed to get tag"); | |
802 | return 0; | |
803 | } | |
804 | ||
805 | if (!str_list_add(cmd->mem, &lp->tags, tag)) { | |
9ac61d2b | 806 | log_error("Unable to allocate memory for tag %s", tag); |
f8452d8c AK |
807 | return 0; |
808 | } | |
9ac61d2b | 809 | } |
9091827c | 810 | |
e6479dff DW |
811 | lcp->pv_count = argc; |
812 | lcp->pvs = argv; | |
642c2e96 | 813 | |
052360e9 JT |
814 | return 1; |
815 | } | |
816 | ||
9ac61d2b AK |
817 | static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp, |
818 | struct lvcreate_cmdline_params *lcp) | |
819 | { | |
820 | struct lv_list *lvl; | |
821 | ||
822 | if (!lp->thin && !lp->create_thin_pool) { | |
823 | log_error("Please specify device size(s)."); | |
824 | return 0; | |
825 | } | |
826 | ||
827 | if (lp->thin && !lp->create_thin_pool) { | |
828 | if (arg_count(vg->cmd, chunksize_ARG)) { | |
829 | log_error("Only specify --chunksize when originally creating the thin pool."); | |
830 | return 0; | |
831 | } | |
832 | ||
833 | if (lcp->pv_count) { | |
834 | log_error("Only specify Physical volumes when allocating the thin pool."); | |
835 | return 0; | |
836 | } | |
837 | ||
838 | if (arg_count(vg->cmd, alloc_ARG)) { | |
839 | log_error("--alloc may only be specified when allocating the thin pool."); | |
840 | return 0; | |
841 | } | |
842 | ||
b8cac455 ZK |
843 | if (arg_count(vg->cmd, poolmetadatasize_ARG)) { |
844 | log_error("--poolmetadatasize may only be specified when allocating the thin pool."); | |
845 | return 0; | |
846 | } | |
847 | ||
9ac61d2b AK |
848 | if (arg_count(vg->cmd, stripesize_ARG)) { |
849 | log_error("--stripesize may only be specified when allocating the thin pool."); | |
850 | return 0; | |
851 | } | |
852 | ||
853 | if (arg_count(vg->cmd, stripes_ARG)) { | |
854 | log_error("--stripes may only be specified when allocating the thin pool."); | |
855 | return 0; | |
856 | } | |
857 | ||
858 | if (arg_count(vg->cmd, contiguous_ARG)) { | |
859 | log_error("--contiguous may only be specified when allocating the thin pool."); | |
860 | return 0; | |
861 | } | |
862 | ||
863 | if (arg_count(vg->cmd, zero_ARG)) { | |
864 | log_error("--zero may only be specified when allocating the thin pool."); | |
865 | return 0; | |
866 | } | |
867 | } | |
868 | ||
869 | if (lp->create_thin_pool && lp->pool) { | |
870 | if (find_lv_in_vg(vg, lp->pool)) { | |
871 | log_error("Pool %s already exists in Volume group %s.", lp->pool, vg->name); | |
872 | return 0; | |
873 | } | |
874 | } else if (lp->pool) { | |
875 | if (!(lvl = find_lv_in_vg(vg, lp->pool))) { | |
876 | log_error("Pool %s not found in Volume group %s.", lp->pool, vg->name); | |
877 | return 0; | |
878 | } | |
b88362ff | 879 | if (!lv_is_thin_pool(lvl->lv)) { |
9ac61d2b AK |
880 | log_error("Logical volume %s is not a thin pool.", lp->pool); |
881 | return 0; | |
882 | } | |
883 | } else if (!lp->create_thin_pool) { | |
884 | log_error("Please specify name of existing pool."); | |
885 | return 0; | |
886 | } | |
887 | ||
888 | if (!lp->thin && lp->lv_name) { | |
889 | log_error("--name may only be given when creating a new thin Logical volume or snapshot."); | |
890 | return 0; | |
891 | } | |
892 | ||
893 | if (!lp->thin) { | |
894 | if (arg_count(vg->cmd, readahead_ARG)) { | |
895 | log_error("--readhead may only be given when creating a new thin Logical volume or snapshot."); | |
896 | return 0; | |
897 | } | |
898 | if (arg_count(vg->cmd, permission_ARG)) { | |
899 | log_error("--permission may only be given when creating a new thin Logical volume or snapshot."); | |
900 | return 0; | |
901 | } | |
902 | if (arg_count(vg->cmd, persistent_ARG)) { | |
903 | log_error("--persistent may only be given when creating a new thin Logical volume or snapshot."); | |
904 | return 0; | |
905 | } | |
906 | } | |
907 | ||
908 | return 1; | |
909 | } | |
910 | ||
911 | /* | |
912 | * Ensure the set of thin parameters extracted from the command line is consistent. | |
913 | */ | |
914 | static int _validate_internal_thin_processing(const struct lvcreate_params *lp) | |
915 | { | |
916 | int r = 1; | |
917 | ||
918 | /* | |
919 | The final state should be one of: | |
920 | thin create_thin_pool snapshot origin pool | |
921 | 1 1 0 0 y/n - create new pool and a thin LV in it | |
922 | 1 0 0 0 y - create new thin LV in existing pool | |
923 | 0 1 0 0 y/n - create new pool only | |
924 | 1 0 1 1 y - create thin snapshot of existing thin LV | |
925 | */ | |
926 | ||
927 | if (!lp->create_thin_pool && !lp->pool) { | |
928 | log_error(INTERNAL_ERROR "--thinpool not identified."); | |
929 | r = 0; | |
930 | } | |
931 | ||
932 | if ((lp->snapshot && !lp->origin) || (!lp->snapshot && lp->origin)) { | |
933 | log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified."); | |
934 | r = 0; | |
935 | } | |
936 | ||
937 | if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) { | |
938 | log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified."); | |
939 | r = 0; | |
940 | } | |
941 | ||
942 | if (!lp->thin && !lp->create_thin_pool) { | |
943 | log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use."); | |
944 | r = 0; | |
945 | } | |
946 | ||
947 | if (seg_is_thin_pool(lp) && lp->thin) { | |
948 | log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type."); | |
949 | r = 0; | |
950 | } | |
951 | ||
952 | return r; | |
953 | } | |
954 | ||
052360e9 JT |
955 | int lvcreate(struct cmd_context *cmd, int argc, char **argv) |
956 | { | |
e5f7352b | 957 | int r = ECMD_PROCESSED; |
052360e9 | 958 | struct lvcreate_params lp; |
8842d526 | 959 | struct lvcreate_cmdline_params lcp; |
e5f7352b | 960 | struct volume_group *vg; |
052360e9 | 961 | |
8842d526 | 962 | if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv)) |
cfb7bfc7 | 963 | return EINVALID_CMD_LINE; |
052360e9 | 964 | |
e5f7352b | 965 | log_verbose("Finding volume group \"%s\"", lp.vg_name); |
b8b3508c | 966 | vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0); |
4c611a22 | 967 | if (vg_read_error(vg)) { |
077a6755 | 968 | release_vg(vg); |
651ff9b3 | 969 | stack; |
cfb7bfc7 | 970 | return ECMD_FAILED; |
4c611a22 | 971 | } |
052360e9 | 972 | |
0d505fb4 | 973 | if (lp.snapshot && lp.origin && !_determine_snapshot_type(vg, &lp)) { |
9ac61d2b AK |
974 | r = ECMD_FAILED; |
975 | goto_out; | |
976 | } | |
977 | ||
978 | if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) { | |
979 | r = ECMD_FAILED; | |
980 | goto_out; | |
981 | } | |
982 | ||
a538e369 ZK |
983 | /* |
984 | * Check activation parameters to support inactive thin snapshot creation | |
985 | * FIXME: anything else needs to be moved past _determine_snapshot_type()? | |
986 | */ | |
987 | if (!_read_activation_params(&lp, cmd)) { | |
988 | r = ECMD_FAILED; | |
989 | goto_out; | |
990 | } | |
991 | ||
651ff9b3 | 992 | if (!_update_extents_params(vg, &lp, &lcp)) { |
ba3851fd MB |
993 | r = ECMD_FAILED; |
994 | goto_out; | |
651ff9b3 | 995 | } |
8675b317 | 996 | |
9ac61d2b AK |
997 | if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) { |
998 | r = ECMD_FAILED; | |
999 | goto_out; | |
1000 | } | |
1001 | ||
1002 | if (lp.create_thin_pool) | |
1003 | log_verbose("Making thin pool %s in VG %s using segtype %s", | |
1004 | lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name); | |
1005 | ||
1006 | if (lp.thin) | |
1007 | log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s", | |
1008 | lp.lv_name ? : "with generated name", | |
f2e3d659 AK |
1009 | lp.pool ? : "with generated name", lp.vg_name, |
1010 | lp.snapshot ? " as snapshot of " : "", | |
9ac61d2b AK |
1011 | lp.snapshot ? lp.origin : "", lp.segtype->name); |
1012 | ||
651ff9b3 AK |
1013 | if (!lv_create_single(vg, &lp)) { |
1014 | stack; | |
e5f7352b | 1015 | r = ECMD_FAILED; |
651ff9b3 | 1016 | } |
ba3851fd | 1017 | out: |
077a6755 | 1018 | unlock_and_release_vg(cmd, vg, lp.vg_name); |
052360e9 | 1019 | return r; |
642c2e96 | 1020 | } |