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