1 /*        $NetBSD: lvresize.c,v 1.1.1.3 2009/12/02 00:25:53 haad Exp $          */
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2009 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 
20 #define SIZE_BUF 128
21 
22 struct lvresize_params {
23           const char *vg_name;
24           const char *lv_name;
25 
26           uint32_t stripes;
27           uint32_t stripe_size;
28           uint32_t mirrors;
29 
30           const struct segment_type *segtype;
31 
32           /* size */
33           uint32_t extents;
34           uint64_t size;
35           sign_t sign;
36           percent_t percent;
37 
38           enum {
39                     LV_ANY = 0,
40                     LV_REDUCE = 1,
41                     LV_EXTEND = 2
42           } resize;
43 
44           int resizefs;
45           int nofsck;
46 
47           int argc;
48           char **argv;
49 };
50 
_validate_stripesize(struct cmd_context * cmd,const struct volume_group * vg,struct lvresize_params * lp)51 static int _validate_stripesize(struct cmd_context *cmd,
52                                         const struct volume_group *vg,
53                                         struct lvresize_params *lp)
54 {
55           if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
56                     log_error("Stripesize may not be negative.");
57                     return 0;
58           }
59 
60           if (arg_uint_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
61                     log_error("Stripe size cannot be larger than %s",
62                                 display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT));
63                     return 0;
64           }
65 
66           if (!(vg->fid->fmt->features & FMT_SEGMENTS))
67                     log_warn("Varied stripesize not supported. Ignoring.");
68           else if (arg_uint_value(cmd, stripesize_ARG, 0) > vg->extent_size * 2) {
69                     log_error("Reducing stripe size %s to maximum, "
70                                 "physical extent size %s",
71                                 display_size(cmd,
72                                                (uint64_t) arg_uint_value(cmd, stripesize_ARG, 0)),
73                                 display_size(cmd, (uint64_t) vg->extent_size));
74                     lp->stripe_size = vg->extent_size;
75           } else
76                     lp->stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
77 
78           if (lp->mirrors) {
79                     log_error("Mirrors and striping cannot be combined yet.");
80                     return 0;
81           }
82           if (lp->stripe_size & (lp->stripe_size - 1)) {
83                     log_error("Stripe size must be power of 2");
84                     return 0;
85           }
86 
87           return 1;
88 }
89 
_request_confirmation(struct cmd_context * cmd,const struct volume_group * vg,const struct logical_volume * lv,const struct lvresize_params * lp)90 static int _request_confirmation(struct cmd_context *cmd,
91                                          const struct volume_group *vg,
92                                          const struct logical_volume *lv,
93                                          const struct lvresize_params *lp)
94 {
95           struct lvinfo info;
96 
97           memset(&info, 0, sizeof(info));
98 
99           if (!lv_info(cmd, lv, &info, 1, 0) && driver_version(NULL, 0)) {
100                     log_error("lv_info failed: aborting");
101                     return 0;
102           }
103 
104           if (lp->resizefs) {
105                     if (!info.exists) {
106                               log_error("Logical volume %s must be activated "
107                                           "before resizing filesystem", lp->lv_name);
108                               return 0;
109                     }
110                     return 1;
111           }
112 
113           if (!info.exists)
114                     return 1;
115 
116           log_warn("WARNING: Reducing active%s logical volume to %s",
117                      info.open_count ? " and open" : "",
118                      display_size(cmd, (uint64_t) lp->extents * vg->extent_size));
119 
120           log_warn("THIS MAY DESTROY YOUR DATA (filesystem etc.)");
121 
122           if (!arg_count(cmd, force_ARG)) {
123                     if (yes_no_prompt("Do you really want to reduce %s? [y/n]: ",
124                                           lp->lv_name) == 'n') {
125                               log_print("Logical volume %s NOT reduced", lp->lv_name);
126                               return 0;
127                     }
128                     if (sigint_caught())
129                               return 0;
130           }
131 
132           return 1;
133 }
134 
135 enum fsadm_cmd_e { FSADM_CMD_CHECK, FSADM_CMD_RESIZE };
136 #define FSADM_CMD "fsadm"
137 #define FSADM_CMD_MAX_ARGS 6
138 
139 /*
140  * FSADM_CMD --dry-run --verbose --force check lv_path
141  * FSADM_CMD --dry-run --verbose --force resize lv_path size
142  */
_fsadm_cmd(struct cmd_context * cmd,const struct volume_group * vg,const struct lvresize_params * lp,enum fsadm_cmd_e fcmd)143 static int _fsadm_cmd(struct cmd_context *cmd,
144                           const struct volume_group *vg,
145                           const struct lvresize_params *lp,
146                           enum fsadm_cmd_e fcmd)
147 {
148           char lv_path[PATH_MAX];
149           char size_buf[SIZE_BUF];
150           const char *argv[FSADM_CMD_MAX_ARGS + 2];
151           unsigned i = 0;
152 
153           argv[i++] = FSADM_CMD;
154 
155           if (test_mode())
156                     argv[i++] = "--dry-run";
157 
158           if (verbose_level() >= _LOG_NOTICE)
159                     argv[i++] = "--verbose";
160 
161           if (arg_count(cmd, force_ARG))
162                     argv[i++] = "--force";
163 
164           argv[i++] = (fcmd == FSADM_CMD_RESIZE) ? "resize" : "check";
165 
166           if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir, lp->vg_name,
167                               lp->lv_name) < 0) {
168                     log_error("Couldn't create LV path for %s", lp->lv_name);
169                     return 0;
170           }
171 
172           argv[i++] = lv_path;
173 
174           if (fcmd == FSADM_CMD_RESIZE) {
175                     if (dm_snprintf(size_buf, SIZE_BUF, "%" PRIu64 "K",
176                                         (uint64_t) lp->extents * vg->extent_size / 2) < 0) {
177                               log_error("Couldn't generate new LV size string");
178                               return 0;
179                     }
180 
181                     argv[i++] = size_buf;
182           }
183 
184           argv[i] = NULL;
185 
186           return exec_cmd(cmd, argv);
187 }
188 
_lvresize_params(struct cmd_context * cmd,int argc,char ** argv,struct lvresize_params * lp)189 static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
190                                   struct lvresize_params *lp)
191 {
192           const char *cmd_name;
193           char *st;
194           unsigned dev_dir_found = 0;
195 
196           lp->sign = SIGN_NONE;
197           lp->resize = LV_ANY;
198 
199           cmd_name = command_name(cmd);
200           if (!strcmp(cmd_name, "lvreduce"))
201                     lp->resize = LV_REDUCE;
202           if (!strcmp(cmd_name, "lvextend"))
203                     lp->resize = LV_EXTEND;
204 
205           /*
206            * Allow omission of extents and size if the user has given us
207            * one or more PVs.  Most likely, the intent was "resize this
208            * LV the best you can with these PVs"
209            */
210           if ((arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) == 0) &&
211               (argc >= 2)) {
212                     lp->extents = 100;
213                     lp->percent = PERCENT_PVS;
214                     lp->sign = SIGN_PLUS;
215           } else if ((arg_count(cmd, extents_ARG) +
216                         arg_count(cmd, size_ARG) != 1)) {
217                     log_error("Please specify either size or extents but not "
218                                 "both.");
219                     return 0;
220           }
221 
222           if (arg_count(cmd, extents_ARG)) {
223                     lp->extents = arg_uint_value(cmd, extents_ARG, 0);
224                     lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
225                     lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
226           }
227 
228           /* Size returned in kilobyte units; held in sectors */
229           if (arg_count(cmd, size_ARG)) {
230                     lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0));
231                     lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
232                     lp->percent = PERCENT_NONE;
233           }
234 
235           if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
236                     log_error("Negative argument not permitted - use lvreduce");
237                     return 0;
238           }
239 
240           if (lp->resize == LV_REDUCE && lp->sign == SIGN_PLUS) {
241                     log_error("Positive sign not permitted - use lvextend");
242                     return 0;
243           }
244 
245           lp->resizefs = arg_is_set(cmd, resizefs_ARG);
246           lp->nofsck = arg_is_set(cmd, nofsck_ARG);
247 
248           if (!argc) {
249                     log_error("Please provide the logical volume name");
250                     return 0;
251           }
252 
253           lp->lv_name = argv[0];
254           argv++;
255           argc--;
256 
257           if (!(lp->lv_name = skip_dev_dir(cmd, lp->lv_name, &dev_dir_found)) ||
258               !(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
259                     log_error("Please provide a volume group name");
260                     return 0;
261           }
262 
263           if (!validate_name(lp->vg_name)) {
264                     log_error("Volume group name %s has invalid characters",
265                                 lp->vg_name);
266                     return 0;
267           }
268 
269           if ((st = strrchr(lp->lv_name, '/')))
270                     lp->lv_name = st + 1;
271 
272           lp->argc = argc;
273           lp->argv = argv;
274 
275           return 1;
276 }
277 
_lvresize(struct cmd_context * cmd,struct volume_group * vg,struct lvresize_params * lp)278 static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
279                          struct lvresize_params *lp)
280 {
281           struct logical_volume *lv;
282           struct lvinfo info;
283           uint32_t stripesize_extents = 0;
284           uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
285           uint32_t seg_mirrors = 0;
286           uint32_t extents_used = 0;
287           uint32_t size_rest;
288           uint32_t pv_extent_count = 0;
289           alloc_policy_t alloc;
290           struct logical_volume *lock_lv;
291           struct lv_list *lvl;
292           struct lv_segment *seg;
293           uint32_t seg_extents;
294           uint32_t sz, str;
295           struct dm_list *pvh = NULL;
296 
297           /* does LV exist? */
298           if (!(lvl = find_lv_in_vg(vg, lp->lv_name))) {
299                     log_error("Logical volume %s not found in volume group %s",
300                                 lp->lv_name, lp->vg_name);
301                     return ECMD_FAILED;
302           }
303 
304           if (arg_count(cmd, stripes_ARG)) {
305                     if (vg->fid->fmt->features & FMT_SEGMENTS)
306                               lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
307                     else
308                               log_warn("Varied striping not supported. Ignoring.");
309           }
310 
311           if (arg_count(cmd, mirrors_ARG)) {
312                     if (vg->fid->fmt->features & FMT_SEGMENTS)
313                               lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
314                     else
315                               log_warn("Mirrors not supported. Ignoring.");
316                     if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
317                               log_error("Mirrors argument may not be negative");
318                               return EINVALID_CMD_LINE;
319                     }
320           }
321 
322           if (arg_count(cmd, stripesize_ARG) &&
323               !_validate_stripesize(cmd, vg, lp))
324                     return EINVALID_CMD_LINE;
325 
326           lv = lvl->lv;
327 
328           if (lv->status & LOCKED) {
329                     log_error("Can't resize locked LV %s", lv->name);
330                     return ECMD_FAILED;
331           }
332 
333           if (lv->status & CONVERTING) {
334                     log_error("Can't resize %s while lvconvert in progress", lv->name);
335                     return ECMD_FAILED;
336           }
337 
338           alloc = arg_uint_value(cmd, alloc_ARG, lv->alloc);
339 
340           if (lp->size) {
341                     if (lp->size % vg->extent_size) {
342                               if (lp->sign == SIGN_MINUS)
343                                         lp->size -= lp->size % vg->extent_size;
344                               else
345                                         lp->size += vg->extent_size -
346                                             (lp->size % vg->extent_size);
347 
348                               log_print("Rounding up size to full physical extent %s",
349                                           display_size(cmd, (uint64_t) lp->size));
350                     }
351 
352                     lp->extents = lp->size / vg->extent_size;
353           }
354 
355           if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc,
356                                                                  lp->argv, 1) : &vg->pvs)) {
357                     stack;
358                     return ECMD_FAILED;
359           }
360 
361           switch(lp->percent) {
362                     case PERCENT_VG:
363                               lp->extents = lp->extents * vg->extent_count / 100;
364                               break;
365                     case PERCENT_FREE:
366                               lp->extents = lp->extents * vg->free_count / 100;
367                               break;
368                     case PERCENT_LV:
369                               lp->extents = lp->extents * lv->le_count / 100;
370                               break;
371                     case PERCENT_PVS:
372                               if (lp->argc) {
373                                         pv_extent_count = pv_list_extents_free(pvh);
374                                         lp->extents = lp->extents * pv_extent_count / 100;
375                               } else
376                                         lp->extents = lp->extents * vg->extent_count / 100;
377                               break;
378                     case PERCENT_NONE:
379                               break;
380           }
381 
382           if (lp->sign == SIGN_PLUS)
383                     lp->extents += lv->le_count;
384 
385           if (lp->sign == SIGN_MINUS) {
386                     if (lp->extents >= lv->le_count) {
387                               log_error("Unable to reduce %s below 1 extent",
388                                           lp->lv_name);
389                               return EINVALID_CMD_LINE;
390                     }
391 
392                     lp->extents = lv->le_count - lp->extents;
393           }
394 
395           if (!lp->extents) {
396                     log_error("New size of 0 not permitted");
397                     return EINVALID_CMD_LINE;
398           }
399 
400           if (lp->extents == lv->le_count) {
401                     if (!lp->resizefs) {
402                               log_error("New size (%d extents) matches existing size "
403                                           "(%d extents)", lp->extents, lv->le_count);
404                               return EINVALID_CMD_LINE;
405                     }
406                     lp->resize = LV_EXTEND; /* lets pretend zero size extension */
407           }
408 
409           seg_size = lp->extents - lv->le_count;
410 
411           /* Use segment type of last segment */
412           dm_list_iterate_items(seg, &lv->segments) {
413                     lp->segtype = seg->segtype;
414           }
415 
416           /* FIXME Support LVs with mixed segment types */
417           if (lp->segtype != arg_ptr_value(cmd, type_ARG, lp->segtype)) {
418                     log_error("VolumeType does not match (%s)", lp->segtype->name);
419                     return EINVALID_CMD_LINE;
420           }
421 
422           /* If extending, find stripes, stripesize & size of last segment */
423           if ((lp->extents > lv->le_count) &&
424               !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
425                     dm_list_iterate_items(seg, &lv->segments) {
426                               if (!seg_is_striped(seg))
427                                         continue;
428 
429                               sz = seg->stripe_size;
430                               str = seg->area_count;
431 
432                               if ((seg_stripesize && seg_stripesize != sz &&
433                                    !lp->stripe_size) ||
434                                   (seg_stripes && seg_stripes != str && !lp->stripes)) {
435                                         log_error("Please specify number of "
436                                                     "stripes (-i) and stripesize (-I)");
437                                         return EINVALID_CMD_LINE;
438                               }
439 
440                               seg_stripesize = sz;
441                               seg_stripes = str;
442                     }
443 
444                     if (!lp->stripes)
445                               lp->stripes = seg_stripes;
446 
447                     if (!lp->stripe_size && lp->stripes > 1) {
448                               if (seg_stripesize) {
449                                         log_print("Using stripesize of last segment %s",
450                                                     display_size(cmd, (uint64_t) seg_stripesize));
451                                         lp->stripe_size = seg_stripesize;
452                               } else {
453                                         lp->stripe_size =
454                                                   find_config_tree_int(cmd,
455                                                                       "metadata/stripesize",
456                                                                       DEFAULT_STRIPESIZE) * 2;
457                                         log_print("Using default stripesize %s",
458                                                     display_size(cmd, (uint64_t) lp->stripe_size));
459                               }
460                     }
461           }
462 
463           /* If extending, find mirrors of last segment */
464           if ((lp->extents > lv->le_count)) {
465                     dm_list_iterate_back_items(seg, &lv->segments) {
466                               if (seg_is_mirrored(seg))
467                                         seg_mirrors = lv_mirror_count(seg->lv);
468                               else
469                                         seg_mirrors = 0;
470                               break;
471                     }
472                     if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
473                               log_print("Extending %" PRIu32 " mirror images.",
474                                           seg_mirrors);
475                               lp->mirrors = seg_mirrors;
476                     }
477                     if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
478                         (lp->mirrors != seg_mirrors)) {
479                               log_error("Cannot vary number of mirrors in LV yet.");
480                               return EINVALID_CMD_LINE;
481                     }
482           }
483 
484           /* If reducing, find stripes, stripesize & size of last segment */
485           if (lp->extents < lv->le_count) {
486                     extents_used = 0;
487 
488                     if (lp->stripes || lp->stripe_size || lp->mirrors)
489                               log_error("Ignoring stripes, stripesize and mirrors "
490                                           "arguments when reducing");
491 
492                     dm_list_iterate_items(seg, &lv->segments) {
493                               seg_extents = seg->len;
494 
495                               if (seg_is_striped(seg)) {
496                                         seg_stripesize = seg->stripe_size;
497                                         seg_stripes = seg->area_count;
498                               }
499 
500                               if (seg_is_mirrored(seg))
501                                         seg_mirrors = lv_mirror_count(seg->lv);
502                               else
503                                         seg_mirrors = 0;
504 
505                               if (lp->extents <= extents_used + seg_extents)
506                                         break;
507 
508                               extents_used += seg_extents;
509                     }
510 
511                     seg_size = lp->extents - extents_used;
512                     lp->stripe_size = seg_stripesize;
513                     lp->stripes = seg_stripes;
514                     lp->mirrors = seg_mirrors;
515           }
516 
517           if (lp->stripes > 1 && !lp->stripe_size) {
518                     log_error("Stripesize for striped segment should not be 0!");
519                     return EINVALID_CMD_LINE;
520           }
521 
522           if ((lp->stripes > 1)) {
523                     if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
524                               stripesize_extents = 1;
525 
526                     if ((size_rest = seg_size % (lp->stripes * stripesize_extents))) {
527                               log_print("Rounding size (%d extents) down to stripe "
528                                           "boundary size for segment (%d extents)",
529                                           lp->extents, lp->extents - size_rest);
530                               lp->extents = lp->extents - size_rest;
531                     }
532 
533                     if (lp->stripe_size < STRIPE_SIZE_MIN) {
534                               log_error("Invalid stripe size %s",
535                                           display_size(cmd, (uint64_t) lp->stripe_size));
536                               return EINVALID_CMD_LINE;
537                     }
538           }
539 
540           if (lp->extents < lv->le_count) {
541                     if (lp->resize == LV_EXTEND) {
542                               log_error("New size given (%d extents) not larger "
543                                           "than existing size (%d extents)",
544                                           lp->extents, lv->le_count);
545                               return EINVALID_CMD_LINE;
546                     }
547                     lp->resize = LV_REDUCE;
548           } else if (lp->extents > lv->le_count) {
549                     if (lp->resize == LV_REDUCE) {
550                               log_error("New size given (%d extents) not less than "
551                                           "existing size (%d extents)", lp->extents,
552                                           lv->le_count);
553                               return EINVALID_CMD_LINE;
554                     }
555                     lp->resize = LV_EXTEND;
556           }
557 
558           if (lv_is_origin(lv)) {
559                     if (lp->resize == LV_REDUCE) {
560                               log_error("Snapshot origin volumes cannot be reduced "
561                                           "in size yet.");
562                               return ECMD_FAILED;
563                     }
564 
565                     memset(&info, 0, sizeof(info));
566 
567                     if (lv_info(cmd, lv, &info, 0, 0) && info.exists) {
568                               log_error("Snapshot origin volumes can be resized "
569                                           "only while inactive: try lvchange -an");
570                               return ECMD_FAILED;
571                     }
572           }
573 
574           if ((lp->resize == LV_REDUCE) && lp->argc)
575                     log_warn("Ignoring PVs on command line when reducing");
576 
577           /* Request confirmation before operations that are often mistakes. */
578           if ((lp->resizefs || (lp->resize == LV_REDUCE)) &&
579               !_request_confirmation(cmd, vg, lv, lp)) {
580                     stack;
581                     return ECMD_FAILED;
582           }
583 
584           if (lp->resizefs) {
585                     if (!lp->nofsck &&
586                         !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_CHECK)) {
587                               stack;
588                               return ECMD_FAILED;
589                     }
590 
591                     if ((lp->resize == LV_REDUCE) &&
592                         !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE)) {
593                               stack;
594                               return ECMD_FAILED;
595                     }
596           }
597 
598           if (!archive(vg)) {
599                     stack;
600                     return ECMD_FAILED;
601           }
602 
603           log_print("%sing logical volume %s to %s",
604                       (lp->resize == LV_REDUCE) ? "Reduc" : "Extend",
605                       lp->lv_name,
606                       display_size(cmd, (uint64_t) lp->extents * vg->extent_size));
607 
608           if (lp->resize == LV_REDUCE) {
609                     if (!lv_reduce(lv, lv->le_count - lp->extents)) {
610                               stack;
611                               return ECMD_FAILED;
612                     }
613           } else if ((lp->extents > lv->le_count) && /* Ensure we extend */
614                        !lv_extend(lv, lp->segtype, lp->stripes,
615                                     lp->stripe_size, lp->mirrors,
616                                     lp->extents - lv->le_count,
617                                     NULL, 0u, 0u, pvh, alloc)) {
618                     stack;
619                     return ECMD_FAILED;
620           }
621 
622           /* store vg on disk(s) */
623           if (!vg_write(vg)) {
624                     stack;
625                     return ECMD_FAILED;
626           }
627 
628           /* If snapshot, must suspend all associated devices */
629           if (lv_is_cow(lv))
630                     lock_lv = origin_from_cow(lv);
631           else
632                     lock_lv = lv;
633 
634           if (!suspend_lv(cmd, lock_lv)) {
635                     log_error("Failed to suspend %s", lp->lv_name);
636                     vg_revert(vg);
637                     backup(vg);
638                     return ECMD_FAILED;
639           }
640 
641           if (!vg_commit(vg)) {
642                     stack;
643                     resume_lv(cmd, lock_lv);
644                     backup(vg);
645                     return ECMD_FAILED;
646           }
647 
648           if (!resume_lv(cmd, lock_lv)) {
649                     log_error("Problem reactivating %s", lp->lv_name);
650                     backup(vg);
651                     return ECMD_FAILED;
652           }
653 
654           backup(vg);
655 
656           log_print("Logical volume %s successfully resized", lp->lv_name);
657 
658           if (lp->resizefs && (lp->resize == LV_EXTEND) &&
659               !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE)) {
660                     stack;
661                     return ECMD_FAILED;
662           }
663 
664           return ECMD_PROCESSED;
665 }
666 
lvresize(struct cmd_context * cmd,int argc,char ** argv)667 int lvresize(struct cmd_context *cmd, int argc, char **argv)
668 {
669           struct lvresize_params lp;
670           struct volume_group *vg;
671           int r;
672 
673           memset(&lp, 0, sizeof(lp));
674 
675           if (!_lvresize_params(cmd, argc, argv, &lp))
676                     return EINVALID_CMD_LINE;
677 
678           log_verbose("Finding volume group %s", lp.vg_name);
679           vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
680           if (vg_read_error(vg)) {
681                     vg_release(vg);
682                     stack;
683                     return ECMD_FAILED;
684           }
685 
686           if (!(r = _lvresize(cmd, vg, &lp)))
687                     stack;
688 
689           unlock_and_release_vg(cmd, vg, lp.vg_name);
690 
691           return r;
692 }
693