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