xref: /dragonfly/contrib/lvm2/dist/tools/lvcreate.c (revision dcd37f7d)
1 /*	$NetBSD: lvcreate.c,v 1.1.1.2 2009/12/02 00:25:50 haad Exp $	*/
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "tools.h"
19 #include "lv_alloc.h"
20 
21 #include <fcntl.h>
22 
23 struct lvcreate_cmdline_params {
24 	percent_t percent;
25 	uint64_t size;
26 	char **pvs;
27 	int pv_count;
28 };
29 
30 static int _lvcreate_name_params(struct lvcreate_params *lp,
31 				 struct cmd_context *cmd,
32 				 int *pargc, char ***pargv)
33 {
34 	int argc = *pargc;
35 	char **argv = *pargv, *ptr;
36 	char *vg_name;
37 
38 	lp->lv_name = arg_str_value(cmd, name_ARG, NULL);
39 
40 	if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
41 		if (!argc) {
42 			log_error("Please specify a logical volume to act as "
43 				  "the snapshot origin.");
44 			return 0;
45 		}
46 
47 		lp->origin = argv[0];
48 		(*pargv)++, (*pargc)--;
49 		if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
50 			log_error("The origin name should include the "
51 				  "volume group.");
52 			return 0;
53 		}
54 
55 		/* Strip the volume group from the origin */
56 		if ((ptr = strrchr(lp->origin, (int) '/')))
57 			lp->origin = ptr + 1;
58 
59 	} else {
60 		/*
61 		 * If VG not on command line, try -n arg and then
62 		 * environment.
63 		 */
64 		if (!argc) {
65 			if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
66 				log_error("Please provide a volume group name");
67 				return 0;
68 			}
69 
70 		} else {
71 			vg_name = skip_dev_dir(cmd, argv[0], NULL);
72 			if (strrchr(vg_name, '/')) {
73 				log_error("Volume group name expected "
74 					  "(no slash)");
75 				return 0;
76 			}
77 
78 			/*
79 			 * Ensure lv_name doesn't contain a
80 			 * different VG.
81 			 */
82 			if (lp->lv_name && strchr(lp->lv_name, '/')) {
83 				if (!(lp->vg_name =
84 				      extract_vgname(cmd, lp->lv_name)))
85 					return 0;
86 
87 				if (strcmp(lp->vg_name, vg_name)) {
88 					log_error("Inconsistent volume group "
89 						  "names "
90 						  "given: \"%s\" and \"%s\"",
91 						  lp->vg_name, vg_name);
92 					return 0;
93 				}
94 			}
95 
96 			lp->vg_name = vg_name;
97 			(*pargv)++, (*pargc)--;
98 		}
99 	}
100 
101 	if (!validate_name(lp->vg_name)) {
102 		log_error("Volume group name %s has invalid characters",
103 			  lp->vg_name);
104 		return 0;
105 	}
106 
107 	if (lp->lv_name) {
108 		if ((ptr = strrchr(lp->lv_name, '/')))
109 			lp->lv_name = ptr + 1;
110 
111 		if (!apply_lvname_restrictions(lp->lv_name))
112 			return_0;
113 
114 		if (!validate_name(lp->lv_name)) {
115 			log_error("Logical volume name \"%s\" is invalid",
116 				  lp->lv_name);
117 			return 0;
118 		}
119 	}
120 
121 	return 1;
122 }
123 
124 /*
125  * Update extents parameters based on other parameters which affect the size
126  * calcuation.
127  * NOTE: We must do this here because of the percent_t typedef and because we
128  * need the vg.
129  */
130 static int _update_extents_params(struct volume_group *vg,
131 				  struct lvcreate_params *lp,
132 				  struct lvcreate_cmdline_params *lcp)
133 {
134 	uint32_t pv_extent_count;
135 
136 	if (lcp->size &&
137 	    !(lp->extents = extents_from_size(vg->cmd, lcp->size,
138 					       vg->extent_size)))
139 		return_0;
140 
141 	if (lp->voriginsize &&
142 	    !(lp->voriginextents = extents_from_size(vg->cmd, lp->voriginsize,
143 						      vg->extent_size)))
144 		return_0;
145 
146 	/*
147 	 * Create the pv list before we parse lcp->percent - might be
148 	 * PERCENT_PVSs
149 	 */
150 	if (lcp->pv_count) {
151 		if (!(lp->pvh = create_pv_list(vg->cmd->mem, vg,
152 					   lcp->pv_count, lcp->pvs, 1)))
153 			return_0;
154 	} else
155 		lp->pvh = &vg->pvs;
156 
157 	switch(lcp->percent) {
158 		case PERCENT_VG:
159 			lp->extents = lp->extents * vg->extent_count / 100;
160 			break;
161 		case PERCENT_FREE:
162 			lp->extents = lp->extents * vg->free_count / 100;
163 			break;
164 		case PERCENT_PVS:
165 			if (!lcp->pv_count)
166 				lp->extents = lp->extents * vg->extent_count / 100;
167 			else {
168 				pv_extent_count = pv_list_extents_free(lp->pvh);
169 				lp->extents = lp->extents * pv_extent_count / 100;
170 			}
171 			break;
172 		case PERCENT_LV:
173 			log_error("Please express size as %%VG, %%PVS, or "
174 				  "%%FREE.");
175 			return 0;
176 		case PERCENT_NONE:
177 			break;
178 	}
179 	return 1;
180 }
181 
182 static int _read_size_params(struct lvcreate_params *lp,
183 			     struct lvcreate_cmdline_params *lcp,
184 			     struct cmd_context *cmd)
185 {
186 	if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
187 		log_error("Please specify either size or extents (not both)");
188 		return 0;
189 	}
190 
191 	if (arg_count(cmd, extents_ARG)) {
192 		if (arg_sign_value(cmd, extents_ARG, 0) == SIGN_MINUS) {
193 			log_error("Negative number of extents is invalid");
194 			return 0;
195 		}
196 		lp->extents = arg_uint_value(cmd, extents_ARG, 0);
197 		lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
198 	}
199 
200 	/* Size returned in kilobyte units; held in sectors */
201 	if (arg_count(cmd, size_ARG)) {
202 		if (arg_sign_value(cmd, size_ARG, 0) == SIGN_MINUS) {
203 			log_error("Negative size is invalid");
204 			return 0;
205 		}
206 		lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0));
207 		lcp->percent = PERCENT_NONE;
208 	}
209 
210 	/* Size returned in kilobyte units; held in sectors */
211 	if (arg_count(cmd, virtualsize_ARG)) {
212 		if (arg_sign_value(cmd, virtualsize_ARG, 0) == SIGN_MINUS) {
213 			log_error("Negative virtual origin size is invalid");
214 			return 0;
215 		}
216 		lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG,
217 						   UINT64_C(0));
218 		if (!lp->voriginsize) {
219 			log_error("Virtual origin size may not be zero");
220 			return 0;
221 		}
222 	}
223 
224 	return 1;
225 }
226 
227 /*
228  * Generic stripe parameter checks.
229  * FIXME: Should eventually be moved into lvm library.
230  */
231 static int _validate_stripe_params(struct cmd_context *cmd,
232 				   struct lvcreate_params *lp)
233 {
234 	if (lp->stripes == 1 && lp->stripe_size) {
235 		log_print("Ignoring stripesize argument with single stripe");
236 		lp->stripe_size = 0;
237 	}
238 
239 	if (lp->stripes > 1 && !lp->stripe_size) {
240 		lp->stripe_size = find_config_tree_int(cmd,
241 						  "metadata/stripesize",
242 						  DEFAULT_STRIPESIZE) * 2;
243 		log_print("Using default stripesize %s",
244 			  display_size(cmd, (uint64_t) lp->stripe_size));
245 	}
246 
247 	if (lp->stripes < 1 || lp->stripes > MAX_STRIPES) {
248 		log_error("Number of stripes (%d) must be between %d and %d",
249 			  lp->stripes, 1, MAX_STRIPES);
250 		return 0;
251 	}
252 
253 	/* MAX size check is in _lvcreate */
254 	if (lp->stripes > 1 && (lp->stripe_size < STRIPE_SIZE_MIN ||
255 				lp->stripe_size & (lp->stripe_size - 1))) {
256 		log_error("Invalid stripe size %s",
257 			  display_size(cmd, (uint64_t) lp->stripe_size));
258 		return 0;
259 	}
260 
261 	return 1;
262 }
263 
264 /* The stripe size is limited by the size of a uint32_t, but since the
265  * value given by the user is doubled, and the final result must be a
266  * power of 2, we must divide UINT_MAX by four and add 1 (to round it
267  * up to the power of 2) */
268 static int _read_stripe_params(struct lvcreate_params *lp,
269 			       struct cmd_context *cmd)
270 {
271 	if (arg_count(cmd, stripesize_ARG)) {
272 		if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
273 			log_error("Negative stripesize is invalid");
274 			return 0;
275 		}
276 		/* Check to make sure we won't overflow lp->stripe_size */
277 		if(arg_uint_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
278 			log_error("Stripe size cannot be larger than %s",
279 				  display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT));
280 			return 0;
281 		}
282 		lp->stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
283 	}
284 
285 
286 	if (!_validate_stripe_params(cmd, lp))
287 		return 0;
288 
289 	return 1;
290 }
291 
292 /*
293  * Generic mirror parameter checks.
294  * FIXME: Should eventually be moved into lvm library.
295  */
296 static int _validate_mirror_params(const struct cmd_context *cmd __attribute((unused)),
297 				   const struct lvcreate_params *lp)
298 {
299 	int pagesize = lvm_getpagesize();
300 
301 	if (lp->region_size & (lp->region_size - 1)) {
302 		log_error("Region size (%" PRIu32 ") must be a power of 2",
303 			  lp->region_size);
304 		return 0;
305 	}
306 
307 	if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
308 		log_error("Region size (%" PRIu32 ") must be a multiple of "
309 			  "machine memory page size (%d)",
310 			  lp->region_size, pagesize >> SECTOR_SHIFT);
311 		return 0;
312 	}
313 
314 	if (!lp->region_size) {
315 		log_error("Non-zero region size must be supplied.");
316 		return 0;
317 	}
318 
319 	return 1;
320 }
321 
322 static int _read_mirror_params(struct lvcreate_params *lp,
323 			       struct cmd_context *cmd)
324 {
325 	int region_size;
326 	const char *mirrorlog;
327 
328 	if (arg_count(cmd, corelog_ARG))
329 		lp->corelog = 1;
330 
331 	mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
332 				  lp->corelog ? "core" : DEFAULT_MIRRORLOG);
333 
334 	if (!strcmp("disk", mirrorlog)) {
335 		if (lp->corelog) {
336 			log_error("--mirrorlog disk and --corelog "
337 				  "are incompatible");
338 			return 0;
339 		}
340 		lp->corelog = 0;
341 	} else if (!strcmp("core", mirrorlog))
342 		lp->corelog = 1;
343 	else {
344 		log_error("Unknown mirrorlog type: %s", mirrorlog);
345 		return 0;
346 	}
347 
348 	log_verbose("Setting logging type to %s", mirrorlog);
349 
350 	lp->nosync = arg_is_set(cmd, nosync_ARG);
351 
352 	if (arg_count(cmd, regionsize_ARG)) {
353 		if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
354 			log_error("Negative regionsize is invalid");
355 			return 0;
356 		}
357 		lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
358 	} else {
359 		region_size = 2 * find_config_tree_int(cmd,
360 					"activation/mirror_region_size",
361 					DEFAULT_MIRROR_REGION_SIZE);
362 		if (region_size < 0) {
363 			log_error("Negative regionsize in configuration file "
364 				  "is invalid");
365 			return 0;
366 		}
367 		lp->region_size = region_size;
368 	}
369 
370 	if (!_validate_mirror_params(cmd, lp))
371 		return 0;
372 
373 	return 1;
374 }
375 
376 static int _lvcreate_params(struct lvcreate_params *lp,
377 			    struct lvcreate_cmdline_params *lcp,
378 			    struct cmd_context *cmd,
379 			    int argc, char **argv)
380 {
381 	int contiguous;
382 	unsigned pagesize;
383 
384 	memset(lp, 0, sizeof(*lp));
385 	memset(lcp, 0, sizeof(*lcp));
386 
387 	/*
388 	 * Check selected options are compatible and determine segtype
389 	 */
390 	lp->segtype = (const struct segment_type *)
391 	    arg_ptr_value(cmd, type_ARG,
392 			  get_segtype_from_string(cmd, "striped"));
393 
394 	lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
395 	if (arg_count(cmd, stripes_ARG) && lp->stripes == 1)
396 		log_print("Redundant stripes argument: default is 1");
397 
398 	if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) ||
399 	    arg_count(cmd, virtualsize_ARG))
400 		lp->snapshot = 1;
401 
402 	lp->mirrors = 1;
403 
404 	/* Default to 2 mirrored areas if --type mirror */
405 	if (seg_is_mirrored(lp))
406 		lp->mirrors = 2;
407 
408 	if (arg_count(cmd, mirrors_ARG)) {
409 		lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
410 		if (lp->mirrors == 1)
411 			log_print("Redundant mirrors argument: default is 0");
412 		if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
413 			log_error("Mirrors argument may not be negative");
414 			return 0;
415 		}
416 	}
417 
418 	if (lp->snapshot) {
419 		if (arg_count(cmd, zero_ARG)) {
420 			log_error("-Z is incompatible with snapshots");
421 			return 0;
422 		}
423 		if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
424 			log_error("Negative chunk size is invalid");
425 			return 0;
426 		}
427 		lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
428 		if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
429 		    (lp->chunk_size & (lp->chunk_size - 1))) {
430 			log_error("Chunk size must be a power of 2 in the "
431 				  "range 4K to 512K");
432 			return 0;
433 		}
434 		log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
435 
436 		if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
437 			return_0;
438 	} else {
439 		if (arg_count(cmd, chunksize_ARG)) {
440 			log_error("-c is only available with snapshots");
441 			return 0;
442 		}
443 	}
444 
445 	if (lp->mirrors > 1) {
446 		if (lp->snapshot) {
447 			log_error("mirrors and snapshots are currently "
448 				  "incompatible");
449 			return 0;
450 		}
451 
452 		if (lp->stripes > 1) {
453 			log_error("mirrors and stripes are currently "
454 				  "incompatible");
455 			return 0;
456 		}
457 
458 		if (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
459 			return_0;
460 	} else {
461 		if (arg_count(cmd, corelog_ARG)) {
462 			log_error("--corelog is only available with mirrors");
463 			return 0;
464 		}
465 
466 		if (arg_count(cmd, nosync_ARG)) {
467 			log_error("--nosync is only available with mirrors");
468 			return 0;
469 		}
470 	}
471 
472 	if (activation() && lp->segtype->ops->target_present &&
473 	    !lp->segtype->ops->target_present(cmd, NULL, NULL)) {
474 		log_error("%s: Required device-mapper target(s) not "
475 			  "detected in your kernel", lp->segtype->name);
476 		return 0;
477 	}
478 
479 	if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
480 	    !_read_size_params(lp, lcp, cmd) ||
481 	    !_read_stripe_params(lp, cmd) ||
482 	    !_read_mirror_params(lp, cmd))
483 		return_0;
484 
485 	/*
486 	 * Should we zero the lv.
487 	 */
488 	lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
489 		(lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n");
490 
491 	/*
492 	 * Alloc policy
493 	 */
494 	contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
495 
496 	lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
497 
498 	lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc);
499 
500 	if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
501 		log_error("Conflicting contiguous and alloc arguments");
502 		return 0;
503 	}
504 
505 	/*
506 	 * Read ahead.
507 	 */
508 	lp->read_ahead = arg_uint_value(cmd, readahead_ARG, DM_READ_AHEAD_NONE);
509 	pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
510 	if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
511 	    lp->read_ahead != DM_READ_AHEAD_NONE &&
512 	    lp->read_ahead % pagesize) {
513 		if (lp->read_ahead < pagesize)
514 			lp->read_ahead = pagesize;
515 		else
516 			lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
517 		log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
518 			    "of %uK page size.", lp->read_ahead, pagesize >> 1);
519 	}
520 
521 	/*
522 	 * Permissions.
523 	 */
524 	lp->permission = arg_uint_value(cmd, permission_ARG,
525 					LVM_READ | LVM_WRITE);
526 
527 	/* Must not zero read only volume */
528 	if (!(lp->permission & LVM_WRITE))
529 		lp->zero = 0;
530 
531 	lp->minor = arg_int_value(cmd, minor_ARG, -1);
532 	lp->major = arg_int_value(cmd, major_ARG, -1);
533 
534 	/* Persistent minor */
535 	if (arg_count(cmd, persistent_ARG)) {
536 		if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
537 			if (lp->minor == -1) {
538 				log_error("Please specify minor number with "
539 					  "--minor when using -My");
540 				return 0;
541 			}
542 			if (lp->major == -1) {
543 				log_error("Please specify major number with "
544 					  "--major when using -My");
545 				return 0;
546 			}
547 		} else {
548 			if ((lp->minor != -1) || (lp->major != -1)) {
549 				log_error("--major and --minor incompatible "
550 					  "with -Mn");
551 				return 0;
552 			}
553 		}
554 	} else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) {
555 		log_error("--major and --minor require -My");
556 		return 0;
557 	}
558 
559 	lp->tag = arg_str_value(cmd, addtag_ARG, NULL);
560 
561 	lcp->pv_count = argc;
562 	lcp->pvs = argv;
563 
564 	return 1;
565 }
566 
567 int lvcreate(struct cmd_context *cmd, int argc, char **argv)
568 {
569 	int r = ECMD_PROCESSED;
570 	struct lvcreate_params lp;
571 	struct lvcreate_cmdline_params lcp;
572 	struct volume_group *vg;
573 
574 	memset(&lp, 0, sizeof(lp));
575 
576 	if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv))
577 		return EINVALID_CMD_LINE;
578 
579 	log_verbose("Finding volume group \"%s\"", lp.vg_name);
580 	vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
581 	if (vg_read_error(vg)) {
582 		vg_release(vg);
583 		stack;
584 		return ECMD_FAILED;
585 	}
586 
587 	if (!_update_extents_params(vg, &lp, &lcp)) {
588 		r = ECMD_FAILED;
589 		goto_out;
590 	}
591 
592 	if (!lv_create_single(vg, &lp)) {
593 		stack;
594 		r = ECMD_FAILED;
595 	}
596 out:
597 	unlock_and_release_vg(cmd, vg, lp.vg_name);
598 	return r;
599 }
600