]> sourceware.org Git - lvm2.git/blame - tools/lvresize.c
o Try to improve NFS-safety for temporary file creation (unique name; O_APPEND
[lvm2.git] / tools / lvresize.c
CommitLineData
03a8a07d
AK
1/*
2 * Copyright (C) 2001 Sistina Software
3 *
4 * LVM is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * LVM is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with LVM; see the file COPYING. If not, write to
16 * the Free Software Foundation, 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 */
20
21#include "tools.h"
22
23int lvresize(int argc, char **argv)
24{
25 struct volume_group *vg;
26 struct logical_volume *lv;
27 uint32_t extents = 0;
28 uint32_t size = 0;
52dc2139
AK
29 uint32_t stripes = 0, stripesize = 0;
30 uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
31 uint32_t size_rest;
03a8a07d
AK
32 sign_t sign = SIGN_NONE;
33 char *lv_name, *vg_name;
34 char *st;
35 char *dummy;
36 const char *cmd_name;
579944d3 37 struct list *lvh, *pvh, *pvl, *segh;
03a8a07d
AK
38 int opt = 0;
39
40 enum {
41 LV_ANY = 0,
42 LV_REDUCE = 1,
43 LV_EXTEND = 2
44 } resize = LV_ANY;
45
46 cmd_name = command_name();
47 if (!strcmp(cmd_name, "lvreduce"))
48 resize = LV_REDUCE;
49 if (!strcmp(cmd_name, "lvextend"))
50 resize = LV_EXTEND;
51
52 if (arg_count(extents_ARG) + arg_count(size_ARG) != 1) {
53 log_error("Please specify either size or extents (not both)");
54 return EINVALID_CMD_LINE;
55 }
56
57 if (arg_count(extents_ARG)) {
58 extents = arg_int_value(extents_ARG, 0);
59 sign = arg_sign_value(extents_ARG, SIGN_NONE);
60 }
61
62 if (arg_count(size_ARG)) {
63 size = arg_int_value(size_ARG, 0);
64 sign = arg_sign_value(size_ARG, SIGN_NONE);
65 }
66
67 if (resize == LV_EXTEND && sign == SIGN_MINUS) {
68 log_error("Negative argument not permitted - use lvreduce");
69 return EINVALID_CMD_LINE;
70 }
71
72 if (resize == LV_REDUCE && sign == SIGN_PLUS) {
73 log_error("Positive sign not permitted - use lvextend");
74 return EINVALID_CMD_LINE;
75 }
76
52dc2139 77 if (arg_count(stripes_ARG)) {
da4e57f2
AK
78 log_print("Stripes not yet implemented in LVM2. Ignoring.");
79 stripes = arg_int_value(stripes_ARG, 1);
80 }
81
82 if (arg_count(stripesize_ARG))
83 stripesize = 2 * arg_int_value(stripesize_ARG, 0);
52dc2139 84
03a8a07d
AK
85 if (!argc) {
86 log_error("Please provide the logical volume name");
87 return EINVALID_CMD_LINE;
88 }
89
90 lv_name = argv[0];
91 argv++;
92 argc--;
93
94 if (!(vg_name = extract_vgname(fid, lv_name))) {
95 log_error("Please provide a volume group name");
96 return EINVALID_CMD_LINE;
97 }
98
99 if ((st = strrchr(lv_name, '/')))
100 lv_name = st + 1;
101
102 /* does VG exist? */
103 log_verbose("Finding volume group %s", vg_name);
104 if (!(vg = fid->ops->vg_read(fid, vg_name))) {
105 log_error("Volume group %s doesn't exist", vg_name);
106 return ECMD_FAILED;
107 }
108
3080a754 109/******* Remove requirement
03a8a07d
AK
110 if (!(vg->status & ACTIVE)) {
111 log_error("Volume group %s must be active before changing a "
112 "logical volume", vg_name);
113 return ECMD_FAILED;
114 }
3080a754 115********/
03a8a07d
AK
116
117 /* does LV exist? */
118 if (!(lvh = find_lv_in_vg(vg, lv_name))) {
119 log_error("Logical volume %s not found in volume group %s",
120 lv_name, vg_name);
121 return ECMD_FAILED;
122 }
123
124 lv = &list_item(lvh, struct lv_list)->lv;
125
3080a754 126/******* Remove requirement
03a8a07d
AK
127 if (!(lv->status & ACTIVE)) {
128 log_error("Logical volume %s must be active before change",
129 lv_name);
130 return ECMD_FAILED;
131 }
3080a754 132********/
03a8a07d
AK
133
134 if (size) {
135 /* No of 512-byte sectors */
136 extents = size * 2;
137
138 if (extents % vg->extent_size) {
139 char *s1;
140
141 if (sign == SIGN_MINUS)
142 extents -= extents % vg->extent_size;
143 else
144 extents += vg->extent_size -
145 (extents % vg->extent_size);
146
147 log_print("Rounding up size to full physical extent %s",
148 (s1 = display_size(extents / 2, SIZE_SHORT)));
149 dbg_free(s1);
150 }
151
152 extents /= vg->extent_size;
153 }
154
155 if (sign == SIGN_PLUS)
156 extents += lv->le_count;
157
158 if (sign == SIGN_MINUS) {
159 if (extents >= lv->le_count) {
160 log_error("Unable to reduce %s below 1 extent",
161 lv_name);
162 return EINVALID_CMD_LINE;
163 }
164
165 extents = lv->le_count - extents;
166 }
167
03a8a07d
AK
168 if (!extents) {
169 log_error("New size of 0 not permitted");
170 return EINVALID_CMD_LINE;
171 }
172
173 if (extents == lv->le_count) {
174 log_error("New size (%d extents) matches existing size "
175 "(%d extents)", extents, lv->le_count);
176 return EINVALID_CMD_LINE;
177 }
178
52dc2139 179 /* If extending, find stripes, stripesize & size of last segment */
3c762e6d 180 if (extents > lv->le_count &&
7a61472a 181 !(stripes == 1 || (stripes > 1 && stripesize))) {
579944d3
AK
182 list_iterate(segh, &lv->segments) {
183 struct stripe_segment *seg;
184 uint32_t sz, str;
185
186 seg = list_item(segh, struct stripe_segment);
187 sz = seg->stripe_size;
188 str = seg->stripes;
52dc2139 189
da4e57f2 190 if ((seg_stripesize && seg_stripesize != sz
52dc2139 191 && !stripesize) ||
da4e57f2 192 (seg_stripes && seg_stripes != str && !stripes)) {
52dc2139
AK
193 log_error("Please specify number of "
194 "stripes (-i) and stripesize (-I)");
195 return EINVALID_CMD_LINE;
196 }
197
198 seg_stripesize = sz;
199 seg_stripes = str;
200 }
201
3c762e6d 202 if (!stripesize && stripes > 1)
52dc2139
AK
203 stripesize = seg_stripesize;
204
205 if (!stripes)
206 stripes = seg_stripes;
207
208 seg_size = extents - lv->le_count;
209 }
210
211 /* If reducing, find stripes, stripesize & size of last segment */
212 if (extents < lv->le_count) {
213 uint32_t extents_used = 0;
214
215 if (stripes || stripesize)
216 log_error("Ignoring stripes and stripesize arguments "
217 "when reducing");
52dc2139 218
579944d3
AK
219 list_iterate(segh, &lv->segments) {
220 struct stripe_segment *seg;
221 uint32_t seg_extents;
222
223 seg = list_item(segh, struct stripe_segment);
224 seg_extents = seg->len;
225
226 seg_stripesize = seg->stripe_size;
227 seg_stripes = seg->stripes;
52dc2139
AK
228
229 if (extents <= extents_used + seg_extents)
230 break;
231
232 extents_used += seg_extents;
233 }
234
235 seg_size = extents - extents_used;
236 stripesize = seg_stripesize;
237 stripes = seg_stripes;
238 }
239
3c762e6d 240 if ((size_rest = seg_size % stripes)) {
da4e57f2
AK
241 log_print("Rounding size (%d extents) down to stripe boundary "
242 "size of last segment (%d extents)", extents,
243 extents - size_rest);
244 extents = extents - size_rest;
245 }
52dc2139
AK
246
247 if (extents == lv->le_count) {
248 log_error("New size (%d extents) matches existing size "
249 "(%d extents)", extents, lv->le_count);
250 return EINVALID_CMD_LINE;
251 }
252
03a8a07d
AK
253 if (extents < lv->le_count) {
254 if (resize == LV_EXTEND) {
255 log_error("New size given (%d extents) not larger "
256 "than existing size (%d extents)",
257 extents, lv->le_count);
258 return EINVALID_CMD_LINE;
259 } else
260 resize = LV_REDUCE;
261 }
262
263 if (extents > lv->le_count) {
264 if (resize == LV_REDUCE) {
265 log_error("New size given (%d extents) not less than "
266 "existing size (%d extents)", extents,
267 lv->le_count);
268 return EINVALID_CMD_LINE;
269 } else
270 resize = LV_EXTEND;
271 }
272
273 if (resize == LV_REDUCE) {
274 if (argc)
275 log_print("Ignoring PVs on command line when reducing");
276
3080a754 277 if (lv_active(lv)) {
03a8a07d
AK
278 dummy =
279 display_size(extents * vg->extent_size / 2,
280 SIZE_SHORT);
281 log_print("WARNING: Reducing active%s logical volume "
282 "to %s", lv_open_count(lv) ? " and open" : "",
283 dummy);
284
285 log_print("THIS MAY DESTROY YOUR DATA "
286 "(filesystem etc.)");
287 dbg_free(dummy);
288 }
289
290 if (!arg_count(force_ARG)) {
291 if (yes_no_prompt("Do you really want to reduce %s?"
292 " [y/n]: ", lv_name) == 'n') {
293 log_print("Logical volume %s NOT reduced",
294 lv_name);
295 return ECMD_FAILED;
296 }
297 }
298
b74c8033
AK
299 if (!lv_reduce(lv, lv->le_count - extents))
300 return ECMD_FAILED;
03a8a07d
AK
301 }
302
303 if (resize == LV_EXTEND && argc) {
304 /* Build up list of PVs */
305 if (!(pvh = pool_alloc(fid->cmd->mem, sizeof(struct list)))) {
306 log_error("pvh list allocation failed");
307 return ECMD_FAILED;
308 }
309 list_init(pvh);
310 for (; opt < argc; opt++) {
311 if (!(pvl = find_pv_in_vg(vg, argv[opt]))) {
312 log_error("Physical Volume %s not found in "
313 "Volume Group %s", argv[opt],
314 vg->name);
315 return EINVALID_CMD_LINE;
316 }
317 if (list_item(pvl, struct pv_list)->pv.pe_count ==
318 list_item(pvl, struct pv_list)->pv.pe_allocated) {
319 log_error("No free extents on physical volume"
320 " %s", argv[opt]);
321 continue;
322 /* FIXME Buy check not empty at end! */
323 }
324 list_add(pvh, pvl);
325 }
326 }
327
328 if (resize == LV_EXTEND) {
329 if (!argc) {
330 /* Use full list from VG */
331 pvh = &vg->pvs;
332 }
333 dummy = display_size(extents * vg->extent_size / 2, SIZE_SHORT);
334 log_print("Extending logical volume %s to %s", lv_name, dummy);
335 dbg_free(dummy);
336
b74c8033
AK
337 if (!lv_extend(lv, stripes, stripesize, extents - lv->le_count,
338 pvh))
339 return ECMD_FAILED;
03a8a07d
AK
340 }
341
342/********* FIXME Suspend lv ***********/
343
344 /* store vg on disk(s) */
345 if (!fid->ops->vg_write(fid, vg))
346 return ECMD_FAILED;
347
197c3f2a 348 backup(vg);
cc219483 349
03a8a07d
AK
350 /* FIXME Ensure it always displays errors? */
351 if (!lv_reactivate(lv))
352 return ECMD_FAILED;
353
354/********* FIXME Resume *********/
355
03a8a07d
AK
356 log_print("Logical volume %s successfully resized", lv_name);
357
358 return 0;
359}
This page took 0.061675 seconds and 5 git commands to generate.