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