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 
_lvcreate_name_params(struct lvcreate_params * lp,struct cmd_context * cmd,int * pargc,char *** pargv)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  */
_update_extents_params(struct volume_group * vg,struct lvcreate_params * lp,struct lvcreate_cmdline_params * lcp)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 
_read_size_params(struct lvcreate_params * lp,struct lvcreate_cmdline_params * lcp,struct cmd_context * cmd)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  */
_validate_stripe_params(struct cmd_context * cmd,struct lvcreate_params * lp)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) */
_read_stripe_params(struct lvcreate_params * lp,struct cmd_context * cmd)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  */
_validate_mirror_params(const struct cmd_context * cmd __attribute ((unused)),const struct lvcreate_params * lp)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 
_read_mirror_params(struct lvcreate_params * lp,struct cmd_context * cmd)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 
_lvcreate_params(struct lvcreate_params * lp,struct lvcreate_cmdline_params * lcp,struct cmd_context * cmd,int argc,char ** argv)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 
lvcreate(struct cmd_context * cmd,int argc,char ** argv)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