]> sourceware.org Git - lvm2.git/blame - tools/lvresize.c
Move from 2-step to 3-step on-disk metadata commit.
[lvm2.git] / tools / lvresize.c
CommitLineData
03a8a07d 1/*
1832f310 2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
6606c3ae 3 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
03a8a07d 4 *
6606c3ae 5 * This file is part of LVM2.
03a8a07d 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
9 * of the GNU General Public License v.2.
03a8a07d
AK
10 *
11 * You should have received a copy of the GNU 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
03a8a07d
AK
14 */
15
16#include "tools.h"
17
1a9ea74d
AK
18#define SIZE_BUF 128
19
241913fe 20struct lvresize_params {
8ef2b021 21 const char *vg_name;
241913fe
AK
22 const char *lv_name;
23
24 uint32_t stripes;
25 uint32_t stripe_size;
26
27 struct segment_type *segtype;
28
241913fe
AK
29 /* size */
30 uint32_t extents;
31 uint64_t size;
32 sign_t sign;
03a8a07d
AK
33
34 enum {
35 LV_ANY = 0,
36 LV_REDUCE = 1,
37 LV_EXTEND = 2
241913fe
AK
38 } resize;
39
1a9ea74d
AK
40 int resizefs;
41 int nofsck;
42
241913fe
AK
43 int argc;
44 char **argv;
45};
46
47static int _read_params(struct cmd_context *cmd, int argc, char **argv,
48 struct lvresize_params *lp)
49{
50 const char *cmd_name;
51 char *st;
52
53 lp->sign = SIGN_NONE;
54 lp->resize = LV_ANY;
03a8a07d 55
60274aba 56 cmd_name = command_name(cmd);
03a8a07d 57 if (!strcmp(cmd_name, "lvreduce"))
241913fe 58 lp->resize = LV_REDUCE;
03a8a07d 59 if (!strcmp(cmd_name, "lvextend"))
241913fe 60 lp->resize = LV_EXTEND;
03a8a07d 61
6fda126d 62 if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
03a8a07d 63 log_error("Please specify either size or extents (not both)");
241913fe 64 return 0;
03a8a07d
AK
65 }
66
6fda126d 67 if (arg_count(cmd, extents_ARG)) {
241913fe
AK
68 lp->extents = arg_uint_value(cmd, extents_ARG, 0);
69 lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
03a8a07d
AK
70 }
71
1832f310 72 /* Size returned in kilobyte units; held in sectors */
6fda126d 73 if (arg_count(cmd, size_ARG)) {
241913fe
AK
74 lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
75 lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
03a8a07d
AK
76 }
77
241913fe 78 if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
03a8a07d 79 log_error("Negative argument not permitted - use lvreduce");
241913fe 80 return 0;
03a8a07d
AK
81 }
82
241913fe 83 if (lp->resize == LV_REDUCE && lp->sign == SIGN_PLUS) {
03a8a07d 84 log_error("Positive sign not permitted - use lvextend");
241913fe 85 return 0;
03a8a07d
AK
86 }
87
1a9ea74d
AK
88 lp->resizefs = arg_count(cmd, resizefs_ARG) ? 1 : 0;
89 lp->nofsck = arg_count(cmd, nofsck_ARG) ? 1 : 0;
90
03a8a07d
AK
91 if (!argc) {
92 log_error("Please provide the logical volume name");
241913fe 93 return 0;
03a8a07d
AK
94 }
95
241913fe 96 lp->lv_name = argv[0];
03a8a07d
AK
97 argv++;
98 argc--;
99
241913fe 100 if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
03a8a07d 101 log_error("Please provide a volume group name");
241913fe 102 return 0;
03a8a07d
AK
103 }
104
241913fe
AK
105 if ((st = strrchr(lp->lv_name, '/')))
106 lp->lv_name = st + 1;
03a8a07d 107
241913fe
AK
108 lp->argc = argc;
109 lp->argv = argv;
110
111 return 1;
112}
7d0e6e80 113
241913fe
AK
114static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
115{
116 struct volume_group *vg;
117 struct logical_volume *lv;
118 struct snapshot *snap;
119 struct lvinfo info;
120 uint32_t stripesize_extents = 0;
121 uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
122 uint32_t extents_used = 0;
123 uint32_t size_rest;
a0a23eff 124 alloc_policy_t alloc;
241913fe
AK
125 char *lock_lvid;
126 struct lv_list *lvl;
127 int consistent = 1;
128 struct lv_segment *seg;
129 uint32_t seg_extents;
130 uint32_t sz, str;
7f0dc9c4 131 struct list *pvh = NULL;
1a9ea74d
AK
132 char size_buf[SIZE_BUF];
133 char lv_path[PATH_MAX];
241913fe
AK
134
135 if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
136 log_error("Volume group %s doesn't exist", lp->vg_name);
7f0dc9c4 137 return ECMD_FAILED;
03a8a07d
AK
138 }
139
6fda126d
AK
140 if (vg->status & EXPORTED_VG) {
141 log_error("Volume group %s is exported", vg->name);
7f0dc9c4 142 return ECMD_FAILED;
6fda126d 143 }
f53c6aa6 144
6fda126d 145 if (!(vg->status & LVM_WRITE)) {
241913fe 146 log_error("Volume group %s is read-only", lp->vg_name);
7f0dc9c4 147 return ECMD_FAILED;
6fda126d 148 }
f53c6aa6 149
03a8a07d 150 /* does LV exist? */
241913fe 151 if (!(lvl = find_lv_in_vg(vg, lp->lv_name))) {
03a8a07d 152 log_error("Logical volume %s not found in volume group %s",
241913fe 153 lp->lv_name, lp->vg_name);
7f0dc9c4 154 return ECMD_FAILED;
03a8a07d
AK
155 }
156
25b73380
AK
157 if (arg_count(cmd, stripes_ARG)) {
158 if (vg->fid->fmt->features & FMT_SEGMENTS)
241913fe 159 lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
25b73380
AK
160 else
161 log_print("Varied striping not supported. Ignoring.");
162 }
163
164 if (arg_count(cmd, stripesize_ARG)) {
fdd4f3c0
AK
165 if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
166 log_error("Stripesize may not be negative.");
7f0dc9c4 167 return ECMD_FAILED;
fdd4f3c0 168 }
25b73380 169 if (vg->fid->fmt->features & FMT_SEGMENTS)
241913fe
AK
170 lp->stripe_size = 2 * arg_uint_value(cmd,
171 stripesize_ARG, 0);
25b73380
AK
172 else
173 log_print("Varied stripesize not supported. Ignoring.");
174 }
175
f868d635 176 lv = lvl->lv;
03a8a07d 177
6e03b44c
AK
178 if (lv->status & LOCKED) {
179 log_error("Can't resize locked LV %s", lv->name);
7f0dc9c4 180 return ECMD_FAILED;
6e03b44c
AK
181 }
182
0ec78e98
AK
183 if (lv_is_origin(lv)) {
184 log_error("Snapshot origin volumes cannot be resized yet.");
185 return ECMD_FAILED;
186 }
187
a0a23eff 188 alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc);
7f0dc9c4 189
241913fe
AK
190 if (lp->size) {
191 if (lp->size % vg->extent_size) {
192 if (lp->sign == SIGN_MINUS)
193 lp->size -= lp->size % vg->extent_size;
03a8a07d 194 else
241913fe
AK
195 lp->size += vg->extent_size -
196 (lp->size % vg->extent_size);
03a8a07d
AK
197
198 log_print("Rounding up size to full physical extent %s",
30bab85b 199 display_size(cmd, (uint64_t) lp->size,
8ef2b021 200 SIZE_SHORT));
03a8a07d
AK
201 }
202
241913fe 203 lp->extents = lp->size / vg->extent_size;
03a8a07d
AK
204 }
205
241913fe
AK
206 if (lp->sign == SIGN_PLUS)
207 lp->extents += lv->le_count;
03a8a07d 208
241913fe
AK
209 if (lp->sign == SIGN_MINUS) {
210 if (lp->extents >= lv->le_count) {
03a8a07d 211 log_error("Unable to reduce %s below 1 extent",
241913fe 212 lp->lv_name);
7f0dc9c4 213 return EINVALID_CMD_LINE;
03a8a07d
AK
214 }
215
241913fe 216 lp->extents = lv->le_count - lp->extents;
03a8a07d
AK
217 }
218
241913fe 219 if (!lp->extents) {
03a8a07d 220 log_error("New size of 0 not permitted");
7f0dc9c4 221 return EINVALID_CMD_LINE;
03a8a07d
AK
222 }
223
241913fe 224 if (lp->extents == lv->le_count) {
03a8a07d 225 log_error("New size (%d extents) matches existing size "
241913fe 226 "(%d extents)", lp->extents, lv->le_count);
7f0dc9c4 227 return EINVALID_CMD_LINE;
03a8a07d
AK
228 }
229
241913fe 230 seg_size = lp->extents - lv->le_count;
25b73380 231
1832f310
AK
232 /* Use segment type of last segment */
233 list_iterate_items(seg, &lv->segments) {
241913fe 234 lp->segtype = seg->segtype;
1832f310
AK
235 }
236
237 /* FIXME Support LVs with mixed segment types */
241913fe
AK
238 if (lp->segtype != (struct segment_type *) arg_ptr_value(cmd, type_ARG,
239 lp->segtype)) {
240 log_error("VolumeType does not match (%s)", lp->segtype->name);
7f0dc9c4 241 return EINVALID_CMD_LINE;
1832f310
AK
242 }
243
52dc2139 244 /* If extending, find stripes, stripesize & size of last segment */
241913fe
AK
245 if ((lp->extents > lv->le_count) &&
246 !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
f2b7349e 247 list_iterate_items(seg, &lv->segments) {
1832f310
AK
248 if (!(seg->segtype->flags & SEG_AREAS_STRIPED))
249 continue;
b8c919b4 250
579944d3 251 sz = seg->stripe_size;
b8c919b4 252 str = seg->area_count;
52dc2139 253
da4e57f2 254 if ((seg_stripesize && seg_stripesize != sz
241913fe
AK
255 && !lp->stripe_size) ||
256 (seg_stripes && seg_stripes != str && !lp->stripes)) {
52dc2139
AK
257 log_error("Please specify number of "
258 "stripes (-i) and stripesize (-I)");
7f0dc9c4 259 return EINVALID_CMD_LINE;
52dc2139
AK
260 }
261
262 seg_stripesize = sz;
263 seg_stripes = str;
264 }
265
241913fe
AK
266 if (!lp->stripes)
267 lp->stripes = seg_stripes;
52dc2139 268
241913fe 269 if (!lp->stripe_size && lp->stripes > 1) {
25b73380
AK
270 if (seg_stripesize) {
271 log_print("Using stripesize of last segment "
272 "%dKB", seg_stripesize / 2);
241913fe 273 lp->stripe_size = seg_stripesize;
25b73380 274 } else {
7f0dc9c4
AK
275 lp->stripe_size =
276 find_config_int(cmd->cft->root,
8ef2b021 277 "metadata/stripesize",
8ef2b021 278 DEFAULT_STRIPESIZE) * 2;
25b73380 279 log_print("Using default stripesize %dKB",
241913fe 280 lp->stripe_size / 2);
25b73380
AK
281 }
282 }
52dc2139
AK
283 }
284
285 /* If reducing, find stripes, stripesize & size of last segment */
241913fe 286 if (lp->extents < lv->le_count) {
25b73380 287 extents_used = 0;
52dc2139 288
241913fe 289 if (lp->stripes || lp->stripe_size)
52dc2139
AK
290 log_error("Ignoring stripes and stripesize arguments "
291 "when reducing");
52dc2139 292
f2b7349e 293 list_iterate_items(seg, &lv->segments) {
579944d3
AK
294 seg_extents = seg->len;
295
4922197a 296 if (seg->segtype->flags & SEG_AREAS_STRIPED) {
b8c919b4
AK
297 seg_stripesize = seg->stripe_size;
298 seg_stripes = seg->area_count;
299 }
52dc2139 300
241913fe 301 if (lp->extents <= extents_used + seg_extents)
52dc2139
AK
302 break;
303
304 extents_used += seg_extents;
305 }
306
241913fe
AK
307 seg_size = lp->extents - extents_used;
308 lp->stripe_size = seg_stripesize;
309 lp->stripes = seg_stripes;
52dc2139
AK
310 }
311
241913fe 312 if (lp->stripes > 1 && !lp->stripe_size) {
25b73380 313 log_error("Stripesize for striped segment should not be 0!");
7f0dc9c4 314 return EINVALID_CMD_LINE;
d4e5f63e 315 }
5a52dca9 316
241913fe
AK
317 if ((lp->stripes > 1)) {
318 if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
d4e5f63e
AK
319 stripesize_extents = 1;
320
241913fe 321 if ((size_rest = seg_size % (lp->stripes * stripesize_extents))) {
d4e5f63e
AK
322 log_print("Rounding size (%d extents) down to stripe "
323 "boundary size for segment (%d extents)",
241913fe
AK
324 lp->extents, lp->extents - size_rest);
325 lp->extents = lp->extents - size_rest;
d4e5f63e 326 }
da4e57f2 327 }
52dc2139 328
241913fe 329 if (lp->extents == lv->le_count) {
52dc2139 330 log_error("New size (%d extents) matches existing size "
241913fe 331 "(%d extents)", lp->extents, lv->le_count);
7f0dc9c4 332 return EINVALID_CMD_LINE;
52dc2139
AK
333 }
334
241913fe
AK
335 if (lp->extents < lv->le_count) {
336 if (lp->resize == LV_EXTEND) {
03a8a07d
AK
337 log_error("New size given (%d extents) not larger "
338 "than existing size (%d extents)",
241913fe 339 lp->extents, lv->le_count);
7f0dc9c4 340 return EINVALID_CMD_LINE;
03a8a07d 341 } else
241913fe 342 lp->resize = LV_REDUCE;
03a8a07d
AK
343 }
344
241913fe
AK
345 if (lp->extents > lv->le_count) {
346 if (lp->resize == LV_REDUCE) {
03a8a07d 347 log_error("New size given (%d extents) not less than "
241913fe 348 "existing size (%d extents)", lp->extents,
03a8a07d 349 lv->le_count);
7f0dc9c4 350 return EINVALID_CMD_LINE;
03a8a07d 351 } else
241913fe 352 lp->resize = LV_EXTEND;
03a8a07d
AK
353 }
354
241913fe
AK
355 if (lp->resize == LV_REDUCE) {
356 if (lp->argc)
03a8a07d 357 log_print("Ignoring PVs on command line when reducing");
1a9ea74d 358 } else if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc,
eabaa339 359 lp->argv, 1) : &vg->pvs)) {
1a9ea74d
AK
360 stack;
361 return ECMD_FAILED;
362 }
03a8a07d 363
1a9ea74d 364 if (lp->resize == LV_REDUCE || lp->resizefs) {
25b73380
AK
365 memset(&info, 0, sizeof(info));
366
e9c761b8 367 if (!lv_info(lv, &info, 1) && driver_version(NULL, 0)) {
25b73380 368 log_error("lv_info failed: aborting");
7f0dc9c4 369 return ECMD_FAILED;
41967a02
AK
370 }
371
1a9ea74d
AK
372 if (lp->resizefs && !info.exists) {
373 log_error("Logical volume %s must be activated "
374 "before resizing filesystem", lp->lv_name);
375 return ECMD_FAILED;
376 }
377
378 if (info.exists && !lp->resizefs && (lp->resize == LV_REDUCE)) {
03a8a07d 379 log_print("WARNING: Reducing active%s logical volume "
41967a02 380 "to %s", info.open_count ? " and open" : "",
241913fe 381 display_size(cmd, (uint64_t) lp->extents *
30bab85b 382 vg->extent_size,
4c64ed4c 383 SIZE_SHORT));
03a8a07d
AK
384
385 log_print("THIS MAY DESTROY YOUR DATA "
386 "(filesystem etc.)");
03a8a07d 387
1a9ea74d
AK
388 if (!arg_count(cmd, force_ARG)) {
389 if (yes_no_prompt("Do you really want to "
390 "reduce %s? [y/n]: ",
391 lp->lv_name) == 'n') {
392 log_print("Logical volume %s NOT "
393 "reduced", lp->lv_name);
394 return ECMD_FAILED;
395 }
03a8a07d
AK
396 }
397 }
1a9ea74d 398 }
03a8a07d 399
1a9ea74d
AK
400 if (lp->resizefs) {
401 if (lvm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir,
402 lp->vg_name, lp->lv_name) < 0) {
403 log_error("Couldn't create LV path for %s",
404 lp->lv_name);
7f0dc9c4 405 return ECMD_FAILED;
241913fe 406 }
614a4508 407
1a9ea74d
AK
408 if (lvm_snprintf(size_buf, SIZE_BUF, "%" PRIu64,
409 (uint64_t) lp->extents * vg->extent_size / 2)
410 < 0) {
411 log_error("Couldn't generate new LV size string");
7f0dc9c4 412 return ECMD_FAILED;
1a9ea74d 413 }
03a8a07d 414
1a9ea74d
AK
415 if (!lp->nofsck) {
416 if (!exec_cmd("fsadm", "check", lv_path, NULL)) {
417 stack;
418 return ECMD_FAILED;
419 }
8ef2b021
AK
420 }
421
1a9ea74d
AK
422 if (lp->resize == LV_REDUCE) {
423 if (!exec_cmd("fsadm", "resize", lv_path, size_buf)) {
424 stack;
425 return ECMD_FAILED;
426 }
241913fe 427 }
1a9ea74d 428 }
614a4508 429
1a9ea74d
AK
430 if (!archive(vg)) {
431 stack;
432 return ECMD_FAILED;
433 }
03a8a07d 434
1a9ea74d
AK
435 log_print("%sing logical volume %s to %s",
436 (lp->resize == LV_REDUCE) ? "Reduc" : "Extend",
437 lp->lv_name,
438 display_size(cmd, (uint64_t) lp->extents * vg->extent_size,
439 SIZE_SHORT));
440
441 if (lp->resize == LV_REDUCE) {
442 if (!lv_reduce(vg->fid, lv, lv->le_count - lp->extents)) {
7f0dc9c4
AK
443 stack;
444 return ECMD_FAILED;
241913fe 445 }
1a9ea74d
AK
446 } else if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes,
447 lp->stripe_size, 0u,
448 lp->extents - lv->le_count,
449 NULL, 0u, 0u, pvh, alloc)) {
450 stack;
451 return ECMD_FAILED;
03a8a07d
AK
452 }
453
03a8a07d 454 /* store vg on disk(s) */
25b73380 455 if (!vg_write(vg)) {
914c9723 456 stack;
7f0dc9c4 457 return ECMD_FAILED;
cc8b2cd7 458 }
03a8a07d 459
6fda126d 460 backup(vg);
cc219483 461
914c9723
AK
462 /* If snapshot, must suspend all associated devices */
463 if ((snap = find_cow(lv)))
464 lock_lvid = snap->origin->lvid.s;
465 else
466 lock_lvid = lv->lvid.s;
467
23289e6d 468 if (!suspend_lv(cmd, lock_lvid)) {
241913fe 469 log_error("Failed to suspend %s", lp->lv_name);
914c9723 470 vg_revert(vg);
7f0dc9c4 471 return ECMD_FAILED;
914c9723
AK
472 }
473
474 if (!vg_commit(vg)) {
475 stack;
23289e6d 476 resume_lv(cmd, lock_lvid);
7f0dc9c4 477 return ECMD_FAILED;
914c9723
AK
478 }
479
23289e6d 480 if (!resume_lv(cmd, lock_lvid)) {
241913fe 481 log_error("Problem reactivating %s", lp->lv_name);
7f0dc9c4 482 return ECMD_FAILED;
cc8b2cd7 483 }
03a8a07d 484
241913fe 485 log_print("Logical volume %s successfully resized", lp->lv_name);
03a8a07d 486
1a9ea74d
AK
487 if (lp->resizefs && (lp->resize == LV_EXTEND)) {
488 if (!exec_cmd("fsadm", "resize", lv_path, size_buf)) {
489 stack;
490 return ECMD_FAILED;
491 }
492 }
493
cfb7bfc7 494 return ECMD_PROCESSED;
03a8a07d 495}
241913fe
AK
496
497int lvresize(struct cmd_context *cmd, int argc, char **argv)
498{
499 struct lvresize_params lp;
500 int r;
501
502 memset(&lp, 0, sizeof(lp));
503
504 if (!_read_params(cmd, argc, argv, &lp))
505 return EINVALID_CMD_LINE;
506
507 log_verbose("Finding volume group %s", lp.vg_name);
508 if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
509 log_error("Can't get lock for %s", lp.vg_name);
510 return ECMD_FAILED;
511 }
512
513 if (!(r = _lvresize(cmd, &lp)))
514 stack;
515
516 unlock_vg(cmd, lp.vg_name);
517
518 return r;
519}
This page took 0.105789 seconds and 5 git commands to generate.