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