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