]>
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; |
90423c12 | 238 | int changed = 0; |
c6f3701a ZK |
239 | uint32_t size_rest; |
240 | uint32_t stripesize_extents; | |
8675b317 | 241 | |
7a0b0db1 | 242 | if (lcp->size && |
9963d071 | 243 | !(lp->extents = extents_from_size(vg->cmd, lcp->size, |
8675b317 DW |
244 | vg->extent_size))) |
245 | return_0; | |
246 | ||
247 | if (lp->voriginsize && | |
9963d071 | 248 | !(lp->voriginextents = extents_from_size(vg->cmd, lp->voriginsize, |
8675b317 DW |
249 | vg->extent_size))) |
250 | return_0; | |
251 | ||
252 | /* | |
8842d526 | 253 | * Create the pv list before we parse lcp->percent - might be |
8675b317 DW |
254 | * PERCENT_PVSs |
255 | */ | |
e6479dff | 256 | if (lcp->pv_count) { |
8675b317 | 257 | if (!(lp->pvh = create_pv_list(vg->cmd->mem, vg, |
e6479dff | 258 | lcp->pv_count, lcp->pvs, 1))) |
8675b317 DW |
259 | return_0; |
260 | } else | |
261 | lp->pvh = &vg->pvs; | |
262 | ||
8842d526 | 263 | switch(lcp->percent) { |
8675b317 | 264 | case PERCENT_VG: |
4fbde014 | 265 | lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); |
8675b317 DW |
266 | break; |
267 | case PERCENT_FREE: | |
4fbde014 | 268 | lp->extents = percent_of_extents(lp->extents, vg->free_count, 0); |
8675b317 DW |
269 | break; |
270 | case PERCENT_PVS: | |
ba3851fd | 271 | if (!lcp->pv_count) |
4fbde014 | 272 | lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); |
ba3851fd MB |
273 | else { |
274 | pv_extent_count = pv_list_extents_free(lp->pvh); | |
4fbde014 | 275 | lp->extents = percent_of_extents(lp->extents, pv_extent_count, 0); |
8675b317 | 276 | } |
8675b317 DW |
277 | break; |
278 | case PERCENT_LV: | |
279 | log_error("Please express size as %%VG, %%PVS, or " | |
280 | "%%FREE."); | |
281 | return 0; | |
5bc2af26 MS |
282 | case PERCENT_ORIGIN: |
283 | if (lp->snapshot && lp->origin && | |
284 | !(origin = find_lv(vg, lp->origin))) { | |
285 | log_error("Couldn't find origin volume '%s'.", | |
286 | lp->origin); | |
287 | return 0; | |
288 | } | |
fc218865 ZK |
289 | if (!origin) { |
290 | log_error(INTERNAL_ERROR "Couldn't find origin volume."); | |
291 | return 0; | |
292 | } | |
4fbde014 | 293 | lp->extents = percent_of_extents(lp->extents, origin->le_count, 0); |
5bc2af26 | 294 | break; |
8675b317 DW |
295 | case PERCENT_NONE: |
296 | break; | |
297 | } | |
b8cac455 | 298 | |
c6f3701a ZK |
299 | if (!(stripesize_extents = lp->stripe_size / vg->extent_size)) |
300 | stripesize_extents = 1; | |
301 | ||
302 | if ((lcp->percent != PERCENT_NONE) && lp->stripes && | |
303 | (size_rest = lp->extents % (lp->stripes * stripesize_extents)) && | |
304 | (vg->free_count < lp->extents - size_rest + (lp->stripes * stripesize_extents))) { | |
305 | log_print("Rounding size (%d extents) down to stripe boundary " | |
306 | "size (%d extents)", lp->extents, | |
307 | lp->extents - size_rest); | |
308 | lp->extents = lp->extents - size_rest; | |
309 | } | |
310 | ||
79c42c66 | 311 | if (lp->create_thin_pool) { |
90423c12 | 312 | if (!arg_count(vg->cmd, poolmetadatasize_ARG)) { |
79c42c66 ZK |
313 | /* Defaults to nr_pool_blocks * 64b */ |
314 | lp->poolmetadatasize = (uint64_t) lp->extents * vg->extent_size / | |
315 | (uint64_t) (lp->chunk_size * (SECTOR_SIZE / UINT64_C(64))); | |
316 | ||
90423c12 ZK |
317 | /* Check if we could eventually use bigger chunk size */ |
318 | if (!arg_count(vg->cmd, chunksize_ARG)) { | |
319 | while ((lp->poolmetadatasize > | |
320 | (DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) && | |
321 | (lp->chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE)) { | |
322 | lp->chunk_size <<= 1; | |
323 | lp->poolmetadatasize >>= 1; | |
324 | changed++; | |
325 | } | |
326 | if (changed) | |
327 | log_verbose("Changed chunksize to %u sectors.", | |
328 | lp->chunk_size); | |
329 | } | |
330 | } | |
331 | ||
79c42c66 ZK |
332 | if (lp->poolmetadatasize > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) { |
333 | if (arg_count(vg->cmd, poolmetadatasize_ARG)) | |
334 | log_warn("WARNING: Maximum supported pool metadata size is 16GB."); | |
335 | lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; | |
336 | } else if (lp->poolmetadatasize < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) { | |
337 | if (arg_count(vg->cmd, poolmetadatasize_ARG)) | |
338 | log_warn("WARNING: Minimum supported pool metadata size is 2M."); | |
339 | lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE; | |
340 | } | |
341 | ||
342 | log_verbose("Setting pool metadata size to %" PRIu64 " sectors.", | |
343 | lp->poolmetadatasize); | |
344 | ||
345 | if (!(lp->poolmetadataextents = | |
346 | extents_from_size(vg->cmd, lp->poolmetadatasize, vg->extent_size))) | |
347 | return_0; | |
348 | } | |
b8cac455 | 349 | |
8675b317 DW |
350 | return 1; |
351 | } | |
352 | ||
052360e9 | 353 | static int _read_size_params(struct lvcreate_params *lp, |
8842d526 | 354 | struct lvcreate_cmdline_params *lcp, |
72b2cb61 | 355 | struct cmd_context *cmd) |
052360e9 | 356 | { |
9ac61d2b | 357 | if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) { |
1832f310 | 358 | log_error("Please specify either size or extents (not both)"); |
052360e9 | 359 | return 0; |
642c2e96 AK |
360 | } |
361 | ||
9ac61d2b AK |
362 | if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) { |
363 | log_error("Please specify either size or extents"); | |
364 | return 0; | |
365 | } | |
366 | ||
fdd4f3c0 | 367 | if (arg_count(cmd, extents_ARG)) { |
fbf6b89a | 368 | if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) { |
fdd4f3c0 AK |
369 | log_error("Negative number of extents is invalid"); |
370 | return 0; | |
371 | } | |
8ef2b021 | 372 | lp->extents = arg_uint_value(cmd, extents_ARG, 0); |
8842d526 | 373 | lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE); |
fdd4f3c0 | 374 | } |
052360e9 JT |
375 | |
376 | /* Size returned in kilobyte units; held in sectors */ | |
fdd4f3c0 | 377 | if (arg_count(cmd, size_ARG)) { |
fbf6b89a | 378 | if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) { |
fdd4f3c0 AK |
379 | log_error("Negative size is invalid"); |
380 | return 0; | |
381 | } | |
7a0b0db1 | 382 | lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)); |
8842d526 | 383 | lcp->percent = PERCENT_NONE; |
fdd4f3c0 | 384 | } |
052360e9 | 385 | |
9ac61d2b AK |
386 | /* If size/extents given with thin, then we are creating a thin pool */ |
387 | if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG))) | |
388 | lp->create_thin_pool = 1; | |
389 | ||
b8cac455 ZK |
390 | if (arg_count(cmd, poolmetadatasize_ARG)) { |
391 | if (!seg_is_thin(lp)) { | |
392 | log_error("--poolmetadatasize may only be specified when allocating the thin pool."); | |
393 | return 0; | |
394 | } | |
fbf6b89a | 395 | if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { |
b8cac455 ZK |
396 | log_error("Negative poolmetadatasize is invalid."); |
397 | return 0; | |
398 | } | |
399 | lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0)); | |
400 | } | |
401 | ||
87f42fda | 402 | /* Size returned in kilobyte units; held in sectors */ |
154753db | 403 | if (arg_count(cmd, virtualsize_ARG)) { |
9ac61d2b AK |
404 | if (seg_is_thin_pool(lp)) { |
405 | log_error("Virtual size in incompatible with thin_pool segment type."); | |
406 | return 0; | |
407 | } | |
fbf6b89a | 408 | if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) { |
87f42fda AK |
409 | log_error("Negative virtual origin size is invalid"); |
410 | return 0; | |
411 | } | |
154753db | 412 | lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG, |
87f42fda AK |
413 | UINT64_C(0)); |
414 | if (!lp->voriginsize) { | |
415 | log_error("Virtual origin size may not be zero"); | |
416 | return 0; | |
417 | } | |
9ac61d2b AK |
418 | } else { |
419 | /* No virtual size given, so no thin LV to create. */ | |
f582793f | 420 | if (seg_is_thin_volume(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool"))) |
9ac61d2b AK |
421 | return_0; |
422 | ||
423 | lp->thin = 0; | |
87f42fda AK |
424 | } |
425 | ||
052360e9 JT |
426 | return 1; |
427 | } | |
428 | ||
f18ef244 DW |
429 | /* |
430 | * Generic mirror parameter checks. | |
431 | * FIXME: Should eventually be moved into lvm library. | |
432 | */ | |
08f1ddea | 433 | static int _validate_mirror_params(const struct cmd_context *cmd __attribute__((unused)), |
bf4f5b21 | 434 | const struct lvcreate_params *lp) |
60f13f01 | 435 | { |
916490f8 | 436 | int pagesize = lvm_getpagesize(); |
60f13f01 AK |
437 | |
438 | if (lp->region_size & (lp->region_size - 1)) { | |
439 | log_error("Region size (%" PRIu32 ") must be a power of 2", | |
440 | lp->region_size); | |
441 | return 0; | |
442 | } | |
443 | ||
5c24f56b AK |
444 | if (lp->region_size % (pagesize >> SECTOR_SHIFT)) { |
445 | log_error("Region size (%" PRIu32 ") must be a multiple of " | |
446 | "machine memory page size (%d)", | |
447 | lp->region_size, pagesize >> SECTOR_SHIFT); | |
448 | return 0; | |
449 | } | |
450 | ||
12ccdb25 AK |
451 | if (!lp->region_size) { |
452 | log_error("Non-zero region size must be supplied."); | |
453 | return 0; | |
454 | } | |
455 | ||
f18ef244 DW |
456 | return 1; |
457 | } | |
458 | ||
459 | static int _read_mirror_params(struct lvcreate_params *lp, | |
cd3ae9bc | 460 | struct cmd_context *cmd) |
f18ef244 DW |
461 | { |
462 | int region_size; | |
463 | const char *mirrorlog; | |
f3ac7d1b | 464 | int corelog = arg_count(cmd, corelog_ARG); |
19583d11 | 465 | |
2b849ab4 | 466 | mirrorlog = arg_str_value(cmd, mirrorlog_ARG, |
f3ac7d1b | 467 | corelog ? "core" : DEFAULT_MIRRORLOG); |
2b849ab4 | 468 | |
7a369d37 JEB |
469 | if (strcmp("core", mirrorlog) && corelog) { |
470 | log_error("Please use only one of --mirrorlog or --corelog"); | |
471 | return 0; | |
472 | } | |
473 | ||
474 | if (!strcmp("mirrored", mirrorlog)) { | |
475 | lp->log_count = 2; | |
476 | } else if (!strcmp("disk", mirrorlog)) { | |
77dd1c0e | 477 | lp->log_count = 1; |
f3ac7d1b | 478 | } else if (!strcmp("core", mirrorlog)) |
77dd1c0e | 479 | lp->log_count = 0; |
edb3374d AK |
480 | else { |
481 | log_error("Unknown mirrorlog type: %s", mirrorlog); | |
482 | return 0; | |
19583d11 JEB |
483 | } |
484 | ||
edb3374d AK |
485 | log_verbose("Setting logging type to %s", mirrorlog); |
486 | ||
a8fb89ad | 487 | lp->nosync = arg_is_set(cmd, nosync_ARG); |
f17f6814 | 488 | |
f18ef244 | 489 | if (arg_count(cmd, regionsize_ARG)) { |
fbf6b89a | 490 | if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) { |
f18ef244 DW |
491 | log_error("Negative regionsize is invalid"); |
492 | return 0; | |
493 | } | |
204a12e5 | 494 | lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0); |
f18ef244 DW |
495 | } else { |
496 | region_size = 2 * find_config_tree_int(cmd, | |
497 | "activation/mirror_region_size", | |
498 | DEFAULT_MIRROR_REGION_SIZE); | |
499 | if (region_size < 0) { | |
500 | log_error("Negative regionsize in configuration file " | |
501 | "is invalid"); | |
502 | return 0; | |
503 | } | |
504 | lp->region_size = region_size; | |
505 | } | |
506 | ||
507 | if (!_validate_mirror_params(cmd, lp)) | |
508 | return 0; | |
509 | ||
60f13f01 AK |
510 | return 1; |
511 | } | |
512 | ||
cac52ca4 JEB |
513 | static int _read_raid_params(struct lvcreate_params *lp, |
514 | struct cmd_context *cmd) | |
515 | { | |
516 | if (!segtype_is_raid(lp->segtype)) | |
517 | return 1; | |
518 | ||
519 | if (arg_count(cmd, corelog_ARG) || | |
520 | arg_count(cmd, mirrorlog_ARG)) { | |
521 | log_error("Log options not applicable to %s segtype", | |
522 | lp->segtype->name); | |
523 | return 0; | |
524 | } | |
525 | ||
526 | /* | |
527 | * get_stripe_params is called before _read_raid_params | |
528 | * and already sets: | |
529 | * lp->stripes | |
530 | * lp->stripe_size | |
531 | * | |
532 | * For RAID 4/5/6, these values must be set. | |
533 | */ | |
870762d8 JEB |
534 | if (!segtype_is_mirrored(lp->segtype) && |
535 | (lp->stripes <= lp->segtype->parity_devs)) { | |
536 | log_error("Number of stripes must be at least %d for %s", | |
537 | lp->segtype->parity_devs + 1, lp->segtype->name); | |
cac52ca4 JEB |
538 | return 0; |
539 | } | |
540 | ||
541 | /* | |
542 | * _read_mirror_params is called before _read_raid_params | |
543 | * and already sets: | |
544 | * lp->nosync | |
545 | * lp->region_size | |
546 | * | |
547 | * But let's ensure that programmers don't reorder | |
548 | * that by checking and warning if they aren't set. | |
549 | */ | |
550 | if (!lp->region_size) { | |
9ac61d2b AK |
551 | log_error(INTERNAL_ERROR "region_size not set."); |
552 | return 0; | |
553 | } | |
554 | ||
555 | return 1; | |
556 | } | |
557 | ||
558 | static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd) | |
559 | { | |
560 | unsigned pagesize; | |
561 | ||
fbf6b89a ZK |
562 | lp->activate = (activation_change_t) |
563 | arg_uint_value(cmd, available_ARG, CHANGE_AY); | |
9ac61d2b AK |
564 | |
565 | if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) { | |
566 | if (lp->zero && !seg_is_thin(lp)) { | |
567 | log_error("--available n requires --zero n"); | |
568 | return 0; | |
569 | } | |
570 | } | |
571 | ||
572 | /* | |
573 | * Read ahead. | |
574 | */ | |
575 | lp->read_ahead = arg_uint_value(cmd, readahead_ARG, | |
576 | cmd->default_settings.read_ahead); | |
577 | pagesize = lvm_getpagesize() >> SECTOR_SHIFT; | |
578 | if (lp->read_ahead != DM_READ_AHEAD_AUTO && | |
579 | lp->read_ahead != DM_READ_AHEAD_NONE && | |
580 | lp->read_ahead % pagesize) { | |
581 | if (lp->read_ahead < pagesize) | |
582 | lp->read_ahead = pagesize; | |
583 | else | |
584 | lp->read_ahead = (lp->read_ahead / pagesize) * pagesize; | |
585 | log_warn("WARNING: Overriding readahead to %u sectors, a multiple " | |
586 | "of %uK page size.", lp->read_ahead, pagesize >> 1); | |
587 | } | |
588 | ||
589 | /* | |
590 | * Permissions. | |
591 | */ | |
592 | lp->permission = arg_uint_value(cmd, permission_ARG, | |
593 | LVM_READ | LVM_WRITE); | |
594 | ||
595 | if (lp->thin && !(lp->permission & LVM_WRITE)) { | |
596 | log_error("Read-only thin volumes are not currently supported."); | |
597 | return 0; | |
598 | } | |
599 | ||
600 | /* Must not zero read only volume */ | |
601 | if (!(lp->permission & LVM_WRITE)) | |
602 | lp->zero = 0; | |
603 | ||
b343d75a AK |
604 | if (arg_count(cmd, major_ARG) > 1) { |
605 | log_error("Option -j/--major may not be repeated."); | |
606 | return 0; | |
607 | } | |
608 | ||
609 | if (arg_count(cmd, minor_ARG) > 1) { | |
610 | log_error("Option --minor may not be repeated."); | |
611 | return 0; | |
612 | } | |
613 | ||
9ac61d2b AK |
614 | lp->minor = arg_int_value(cmd, minor_ARG, -1); |
615 | lp->major = arg_int_value(cmd, major_ARG, -1); | |
616 | ||
617 | /* Persistent minor */ | |
618 | if (arg_count(cmd, persistent_ARG)) { | |
619 | if (lp->create_thin_pool && !lp->thin) { | |
620 | log_error("--persistent is not permitted when creating a thin pool device."); | |
621 | return 0; | |
622 | } | |
623 | if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) { | |
624 | if (lp->minor == -1) { | |
625 | log_error("Please specify minor number with " | |
626 | "--minor when using -My"); | |
627 | return 0; | |
628 | } | |
629 | if (lp->major == -1) { | |
630 | log_error("Please specify major number with " | |
631 | "--major when using -My"); | |
632 | return 0; | |
633 | } | |
634 | } else { | |
635 | if ((lp->minor != -1) || (lp->major != -1)) { | |
636 | log_error("--major and --minor incompatible " | |
637 | "with -Mn"); | |
638 | return 0; | |
639 | } | |
640 | } | |
641 | } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) { | |
642 | log_error("--major and --minor require -My"); | |
cac52ca4 JEB |
643 | return 0; |
644 | } | |
645 | ||
646 | return 1; | |
647 | } | |
648 | ||
8842d526 DW |
649 | static int _lvcreate_params(struct lvcreate_params *lp, |
650 | struct lvcreate_cmdline_params *lcp, | |
651 | struct cmd_context *cmd, | |
8a2fc586 | 652 | int argc, char **argv) |
052360e9 | 653 | { |
a0a23eff | 654 | int contiguous; |
f8452d8c | 655 | struct arg_value_group_list *current_group; |
cac52ca4 | 656 | const char *segtype_str; |
f8452d8c | 657 | const char *tag; |
a0a23eff | 658 | |
fdf8038f | 659 | memset(lp, 0, sizeof(*lp)); |
8842d526 | 660 | memset(lcp, 0, sizeof(*lcp)); |
f8452d8c | 661 | dm_list_init(&lp->tags); |
fdf8038f | 662 | |
052360e9 | 663 | /* |
1832f310 | 664 | * Check selected options are compatible and determine segtype |
052360e9 | 665 | */ |
0ed2af7f | 666 | // FIXME -m0 implies *striped* |
9ac61d2b AK |
667 | if (arg_count(cmd, thin_ARG) && arg_count(cmd,mirrors_ARG)) { |
668 | log_error("--thin and --mirrors are incompatible."); | |
669 | return 0; | |
670 | } | |
671 | ||
0ed2af7f AK |
672 | // FIXME -m0 implies *striped* |
673 | ||
9ac61d2b | 674 | /* Set default segtype */ |
cac52ca4 | 675 | if (arg_count(cmd, mirrors_ARG)) |
d8b1aa19 | 676 | segtype_str = find_config_tree_str(cmd, "global/mirror_segtype_default", DEFAULT_MIRROR_SEGTYPE); |
9ac61d2b AK |
677 | else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) |
678 | segtype_str = "thin"; | |
679 | else | |
680 | segtype_str = "striped"; | |
cac52ca4 | 681 | |
1281a5e3 ZK |
682 | segtype_str = arg_str_value(cmd, type_ARG, segtype_str); |
683 | ||
684 | if (!(lp->segtype = get_segtype_from_string(cmd, segtype_str))) | |
685 | return_0; | |
1832f310 | 686 | |
ef78ebf3 | 687 | if (seg_unknown(lp)) { |
1281a5e3 | 688 | log_error("Unable to create LV with unknown segment type %s.", segtype_str); |
ef78ebf3 AK |
689 | return 0; |
690 | } | |
691 | ||
154753db | 692 | if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) || |
9ac61d2b | 693 | (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG))) |
1832f310 AK |
694 | lp->snapshot = 1; |
695 | ||
9ac61d2b AK |
696 | if (seg_is_thin_pool(lp)) { |
697 | if (lp->snapshot) { | |
698 | log_error("Snapshots are incompatible with thin_pool segment_type."); | |
699 | return 0; | |
700 | } | |
701 | lp->create_thin_pool = 1; | |
702 | } | |
703 | ||
704 | if (seg_is_thin_volume(lp)) | |
705 | lp->thin = 1; | |
706 | ||
60f13f01 AK |
707 | lp->mirrors = 1; |
708 | ||
cac52ca4 | 709 | /* Default to 2 mirrored areas if '--type mirror|raid1' */ |
09c4fd3f | 710 | if (segtype_is_mirrored(lp->segtype)) |
60f13f01 AK |
711 | lp->mirrors = 2; |
712 | ||
713 | if (arg_count(cmd, mirrors_ARG)) { | |
714 | lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; | |
f989a555 JEB |
715 | if (lp->mirrors == 1) { |
716 | if (segtype_is_mirrored(lp->segtype)) { | |
0ed2af7f | 717 | log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name); |
f989a555 JEB |
718 | return 0; |
719 | } | |
60f13f01 | 720 | log_print("Redundant mirrors argument: default is 0"); |
f989a555 | 721 | } |
fbf6b89a | 722 | if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) { |
7424de5b AK |
723 | log_error("Mirrors argument may not be negative"); |
724 | return 0; | |
725 | } | |
60f13f01 AK |
726 | } |
727 | ||
9ac61d2b AK |
728 | if (lp->snapshot && arg_count(cmd, zero_ARG)) { |
729 | log_error("-Z is incompatible with snapshots"); | |
730 | return 0; | |
fdf8038f | 731 | } |
052360e9 | 732 | |
cac52ca4 | 733 | if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) { |
60f13f01 AK |
734 | if (lp->snapshot) { |
735 | log_error("mirrors and snapshots are currently " | |
736 | "incompatible"); | |
737 | return 0; | |
738 | } | |
f17f6814 AK |
739 | } else { |
740 | if (arg_count(cmd, corelog_ARG)) { | |
741 | log_error("--corelog is only available with mirrors"); | |
742 | return 0; | |
743 | } | |
de828433 | 744 | |
dfafb8fb JEB |
745 | if (arg_count(cmd, mirrorlog_ARG)) { |
746 | log_error("--mirrorlog is only available with mirrors"); | |
747 | return 0; | |
748 | } | |
749 | ||
de828433 AK |
750 | if (arg_count(cmd, nosync_ARG)) { |
751 | log_error("--nosync is only available with mirrors"); | |
752 | return 0; | |
753 | } | |
60f13f01 AK |
754 | } |
755 | ||
1832f310 | 756 | if (activation() && lp->segtype->ops->target_present && |
81680dce | 757 | !lp->segtype->ops->target_present(cmd, NULL, NULL)) { |
1832f310 AK |
758 | log_error("%s: Required device-mapper target(s) not " |
759 | "detected in your kernel", lp->segtype->name); | |
760 | return 0; | |
761 | } | |
762 | ||
8a2fc586 | 763 | if (!_lvcreate_name_params(lp, cmd, &argc, &argv) || |
8842d526 | 764 | !_read_size_params(lp, lcp, cmd) || |
68176be1 | 765 | !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) || |
cac52ca4 | 766 | !_read_mirror_params(lp, cmd) || |
79c42c66 | 767 | !_read_raid_params(lp, cmd)) |
c51b9fff | 768 | return_0; |
d53f88d7 | 769 | |
9ac61d2b AK |
770 | if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG)) |
771 | log_warn("WARNING: Ignoring --chunksize with thin snapshots."); | |
772 | else if (lp->thin && !lp->create_thin_pool) { | |
773 | if (arg_count(cmd, chunksize_ARG)) | |
774 | log_warn("WARNING: Ignoring --chunksize when using an existing pool."); | |
775 | } else if (lp->snapshot || lp->create_thin_pool) { | |
fbf6b89a | 776 | if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) { |
9ac61d2b AK |
777 | log_error("Negative chunk size is invalid"); |
778 | return 0; | |
779 | } | |
3bc41748 ZK |
780 | if (lp->snapshot) { |
781 | lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8); | |
782 | if (lp->chunk_size < 8 || lp->chunk_size > 1024 || | |
783 | (lp->chunk_size & (lp->chunk_size - 1))) { | |
784 | log_error("Chunk size must be a power of 2 in the " | |
785 | "range 4K to 512K"); | |
786 | return 0; | |
787 | } | |
788 | } else { | |
34a45b00 ZK |
789 | lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, |
790 | DM_THIN_MIN_DATA_BLOCK_SIZE); | |
3bc41748 ZK |
791 | if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) || |
792 | (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE) || | |
793 | (lp->chunk_size & (lp->chunk_size - 1))) { | |
794 | log_error("Chunk size must be a power of 2 in the " | |
34a45b00 ZK |
795 | "range %uK to %uK", |
796 | (DM_THIN_MIN_DATA_BLOCK_SIZE / 2), | |
797 | (DM_THIN_MAX_DATA_BLOCK_SIZE / 2)); | |
3bc41748 ZK |
798 | return 0; |
799 | } | |
9ac61d2b | 800 | } |
3bc41748 | 801 | log_verbose("Setting chunksize to %u sectors.", lp->chunk_size); |
e586401e | 802 | |
9ac61d2b AK |
803 | if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) |
804 | return_0; | |
805 | } else { | |
806 | if (arg_count(cmd, chunksize_ARG)) { | |
807 | log_error("-c is only available with snapshots and thin pools"); | |
453cdee5 AK |
808 | return 0; |
809 | } | |
810 | } | |
811 | ||
052360e9 | 812 | /* |
9ac61d2b | 813 | * Should we zero the lv. |
052360e9 | 814 | */ |
9ac61d2b AK |
815 | lp->zero = strcmp(arg_str_value(cmd, zero_ARG, |
816 | (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); | |
052360e9 | 817 | |
5800aa5c MB |
818 | if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) { |
819 | log_error("Only up to %d images in mirror supported currently.", | |
820 | DEFAULT_MIRROR_MAX_IMAGES); | |
821 | return 0; | |
822 | } | |
823 | ||
052360e9 | 824 | /* |
9ac61d2b | 825 | * Allocation parameters |
052360e9 | 826 | */ |
9ac61d2b | 827 | contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); |
e0096cab | 828 | |
9ac61d2b | 829 | lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; |
052360e9 | 830 | |
fbf6b89a | 831 | lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc); |
052360e9 | 832 | |
9ac61d2b AK |
833 | if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) { |
834 | log_error("Conflicting contiguous and alloc arguments"); | |
ed8c4d99 | 835 | return 0; |
642c2e96 AK |
836 | } |
837 | ||
f8452d8c AK |
838 | dm_list_iterate_items(current_group, &cmd->arg_value_groups) { |
839 | if (!grouped_arg_is_set(current_group->arg_values, addtag_ARG)) | |
840 | continue; | |
841 | ||
842 | if (!(tag = grouped_arg_str_value(current_group->arg_values, addtag_ARG, NULL))) { | |
843 | log_error("Failed to get tag"); | |
844 | return 0; | |
845 | } | |
846 | ||
847 | if (!str_list_add(cmd->mem, &lp->tags, tag)) { | |
9ac61d2b | 848 | log_error("Unable to allocate memory for tag %s", tag); |
f8452d8c AK |
849 | return 0; |
850 | } | |
9ac61d2b | 851 | } |
9091827c | 852 | |
e6479dff DW |
853 | lcp->pv_count = argc; |
854 | lcp->pvs = argv; | |
642c2e96 | 855 | |
052360e9 JT |
856 | return 1; |
857 | } | |
858 | ||
9ac61d2b AK |
859 | static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp, |
860 | struct lvcreate_cmdline_params *lcp) | |
861 | { | |
862 | struct lv_list *lvl; | |
863 | ||
864 | if (!lp->thin && !lp->create_thin_pool) { | |
865 | log_error("Please specify device size(s)."); | |
866 | return 0; | |
867 | } | |
868 | ||
869 | if (lp->thin && !lp->create_thin_pool) { | |
870 | if (arg_count(vg->cmd, chunksize_ARG)) { | |
871 | log_error("Only specify --chunksize when originally creating the thin pool."); | |
872 | return 0; | |
873 | } | |
874 | ||
875 | if (lcp->pv_count) { | |
876 | log_error("Only specify Physical volumes when allocating the thin pool."); | |
877 | return 0; | |
878 | } | |
879 | ||
880 | if (arg_count(vg->cmd, alloc_ARG)) { | |
881 | log_error("--alloc may only be specified when allocating the thin pool."); | |
882 | return 0; | |
883 | } | |
884 | ||
b8cac455 ZK |
885 | if (arg_count(vg->cmd, poolmetadatasize_ARG)) { |
886 | log_error("--poolmetadatasize may only be specified when allocating the thin pool."); | |
887 | return 0; | |
888 | } | |
889 | ||
9ac61d2b AK |
890 | if (arg_count(vg->cmd, stripesize_ARG)) { |
891 | log_error("--stripesize may only be specified when allocating the thin pool."); | |
892 | return 0; | |
893 | } | |
894 | ||
895 | if (arg_count(vg->cmd, stripes_ARG)) { | |
896 | log_error("--stripes may only be specified when allocating the thin pool."); | |
897 | return 0; | |
898 | } | |
899 | ||
900 | if (arg_count(vg->cmd, contiguous_ARG)) { | |
901 | log_error("--contiguous may only be specified when allocating the thin pool."); | |
902 | return 0; | |
903 | } | |
904 | ||
905 | if (arg_count(vg->cmd, zero_ARG)) { | |
906 | log_error("--zero may only be specified when allocating the thin pool."); | |
907 | return 0; | |
908 | } | |
909 | } | |
910 | ||
911 | if (lp->create_thin_pool && lp->pool) { | |
912 | if (find_lv_in_vg(vg, lp->pool)) { | |
913 | log_error("Pool %s already exists in Volume group %s.", lp->pool, vg->name); | |
914 | return 0; | |
915 | } | |
916 | } else if (lp->pool) { | |
917 | if (!(lvl = find_lv_in_vg(vg, lp->pool))) { | |
918 | log_error("Pool %s not found in Volume group %s.", lp->pool, vg->name); | |
919 | return 0; | |
920 | } | |
b88362ff | 921 | if (!lv_is_thin_pool(lvl->lv)) { |
9ac61d2b AK |
922 | log_error("Logical volume %s is not a thin pool.", lp->pool); |
923 | return 0; | |
924 | } | |
925 | } else if (!lp->create_thin_pool) { | |
926 | log_error("Please specify name of existing pool."); | |
927 | return 0; | |
928 | } | |
929 | ||
930 | if (!lp->thin && lp->lv_name) { | |
931 | log_error("--name may only be given when creating a new thin Logical volume or snapshot."); | |
932 | return 0; | |
933 | } | |
934 | ||
935 | if (!lp->thin) { | |
936 | if (arg_count(vg->cmd, readahead_ARG)) { | |
937 | log_error("--readhead may only be given when creating a new thin Logical volume or snapshot."); | |
938 | return 0; | |
939 | } | |
940 | if (arg_count(vg->cmd, permission_ARG)) { | |
941 | log_error("--permission may only be given when creating a new thin Logical volume or snapshot."); | |
942 | return 0; | |
943 | } | |
944 | if (arg_count(vg->cmd, persistent_ARG)) { | |
945 | log_error("--persistent may only be given when creating a new thin Logical volume or snapshot."); | |
946 | return 0; | |
947 | } | |
948 | } | |
949 | ||
950 | return 1; | |
951 | } | |
952 | ||
953 | /* | |
954 | * Ensure the set of thin parameters extracted from the command line is consistent. | |
955 | */ | |
956 | static int _validate_internal_thin_processing(const struct lvcreate_params *lp) | |
957 | { | |
958 | int r = 1; | |
959 | ||
960 | /* | |
961 | The final state should be one of: | |
962 | thin create_thin_pool snapshot origin pool | |
963 | 1 1 0 0 y/n - create new pool and a thin LV in it | |
964 | 1 0 0 0 y - create new thin LV in existing pool | |
965 | 0 1 0 0 y/n - create new pool only | |
966 | 1 0 1 1 y - create thin snapshot of existing thin LV | |
967 | */ | |
968 | ||
969 | if (!lp->create_thin_pool && !lp->pool) { | |
970 | log_error(INTERNAL_ERROR "--thinpool not identified."); | |
971 | r = 0; | |
972 | } | |
973 | ||
974 | if ((lp->snapshot && !lp->origin) || (!lp->snapshot && lp->origin)) { | |
975 | log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified."); | |
976 | r = 0; | |
977 | } | |
978 | ||
979 | if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) { | |
980 | log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified."); | |
981 | r = 0; | |
982 | } | |
983 | ||
984 | if (!lp->thin && !lp->create_thin_pool) { | |
985 | log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use."); | |
986 | r = 0; | |
987 | } | |
988 | ||
989 | if (seg_is_thin_pool(lp) && lp->thin) { | |
990 | log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type."); | |
991 | r = 0; | |
992 | } | |
993 | ||
994 | return r; | |
995 | } | |
996 | ||
052360e9 JT |
997 | int lvcreate(struct cmd_context *cmd, int argc, char **argv) |
998 | { | |
e5f7352b | 999 | int r = ECMD_PROCESSED; |
052360e9 | 1000 | struct lvcreate_params lp; |
8842d526 | 1001 | struct lvcreate_cmdline_params lcp; |
e5f7352b | 1002 | struct volume_group *vg; |
052360e9 | 1003 | |
8842d526 | 1004 | if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv)) |
cfb7bfc7 | 1005 | return EINVALID_CMD_LINE; |
052360e9 | 1006 | |
e5f7352b | 1007 | log_verbose("Finding volume group \"%s\"", lp.vg_name); |
b8b3508c | 1008 | vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0); |
4c611a22 | 1009 | if (vg_read_error(vg)) { |
077a6755 | 1010 | release_vg(vg); |
651ff9b3 | 1011 | stack; |
cfb7bfc7 | 1012 | return ECMD_FAILED; |
4c611a22 | 1013 | } |
052360e9 | 1014 | |
0d505fb4 | 1015 | if (lp.snapshot && lp.origin && !_determine_snapshot_type(vg, &lp)) { |
9ac61d2b AK |
1016 | r = ECMD_FAILED; |
1017 | goto_out; | |
1018 | } | |
1019 | ||
1020 | if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) { | |
1021 | r = ECMD_FAILED; | |
1022 | goto_out; | |
1023 | } | |
1024 | ||
a538e369 ZK |
1025 | /* |
1026 | * Check activation parameters to support inactive thin snapshot creation | |
1027 | * FIXME: anything else needs to be moved past _determine_snapshot_type()? | |
1028 | */ | |
1029 | if (!_read_activation_params(&lp, cmd)) { | |
1030 | r = ECMD_FAILED; | |
1031 | goto_out; | |
1032 | } | |
1033 | ||
651ff9b3 | 1034 | if (!_update_extents_params(vg, &lp, &lcp)) { |
ba3851fd MB |
1035 | r = ECMD_FAILED; |
1036 | goto_out; | |
651ff9b3 | 1037 | } |
8675b317 | 1038 | |
9ac61d2b AK |
1039 | if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) { |
1040 | r = ECMD_FAILED; | |
1041 | goto_out; | |
1042 | } | |
1043 | ||
1044 | if (lp.create_thin_pool) | |
1045 | log_verbose("Making thin pool %s in VG %s using segtype %s", | |
1046 | lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name); | |
1047 | ||
1048 | if (lp.thin) | |
1049 | log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s", | |
1050 | lp.lv_name ? : "with generated name", | |
f2e3d659 AK |
1051 | lp.pool ? : "with generated name", lp.vg_name, |
1052 | lp.snapshot ? " as snapshot of " : "", | |
9ac61d2b AK |
1053 | lp.snapshot ? lp.origin : "", lp.segtype->name); |
1054 | ||
651ff9b3 AK |
1055 | if (!lv_create_single(vg, &lp)) { |
1056 | stack; | |
e5f7352b | 1057 | r = ECMD_FAILED; |
651ff9b3 | 1058 | } |
ba3851fd | 1059 | out: |
077a6755 | 1060 | unlock_and_release_vg(cmd, vg, lp.vg_name); |
052360e9 | 1061 | return r; |
642c2e96 | 1062 | } |