2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
5 * This file is part of LVM2.
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.
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
19 static int _remove_pv(struct volume_group
*vg
, struct pv_list
*pvl
, int silent
)
21 char uuid
[64] __attribute__((aligned(8)));
23 if (vg
->pv_count
== 1) {
24 log_error("Volume Groups must always contain at least one PV");
28 if (!id_write_format(&pvl
->pv
->id
, uuid
, sizeof(uuid
)))
31 log_verbose("Removing PV with UUID %s from VG %s", uuid
, vg
->name
);
33 if (pvl
->pv
->pe_alloc_count
) {
35 log_error("LVs still present on PV with UUID %s: "
36 "Can't remove from VG %s", uuid
, vg
->name
);
40 vg
->free_count
-= pvl
->pv
->pe_count
;
41 vg
->extent_count
-= pvl
->pv
->pe_count
;
42 del_pvl_from_vgs(vg
, pvl
);
48 static int _consolidate_vg(struct cmd_context
*cmd
, struct volume_group
*vg
)
54 dm_list_iterate_items(lvl
, &vg
->lvs
)
55 if (lvl
->lv
->status
& PARTIAL_LV
) {
56 log_warn("WARNING: Partial LV %s needs to be repaired "
57 "or removed. ", lvl
->lv
->name
);
62 cmd
->handles_missing_pvs
= 1;
63 log_error("There are still partial LVs in VG %s.", vg
->name
);
64 log_error("To remove them unconditionally use: vgreduce --removemissing --force.");
65 log_warn("Proceeding to remove empty missing PVs.");
68 dm_list_iterate_items(pvl
, &vg
->pvs
) {
69 if (pvl
->pv
->dev
&& !is_missing_pv(pvl
->pv
))
71 if (r
&& !_remove_pv(vg
, pvl
, 0))
78 static int _make_vg_consistent(struct cmd_context
*cmd
, struct volume_group
*vg
)
81 struct logical_volume
*lv
;
83 cmd
->partial_activation
= 1;
86 vg_mark_partial_lvs(vg
, 1);
88 dm_list_iterate_items(lvl
, &vg
->lvs
) {
91 /* Are any segments of this LV on missing PVs? */
92 if (lv
->status
& PARTIAL_LV
) {
93 if (lv
->status
& MIRRORED
) {
94 if (!mirror_remove_missing(cmd
, lv
, 1))
99 if (arg_count(cmd
, mirrorsonly_ARG
) &&!(lv
->status
& MIRRORED
)) {
100 log_error("Non-mirror-image LV %s found: can't remove.", lv
->name
);
104 if (!lv_is_visible(lv
))
106 log_warn("Removing partial LV %s.", lv
->name
);
107 if (!lv_remove_with_dependencies(cmd
, lv
, DONT_PROMPT
, 0))
113 _consolidate_vg(cmd
, vg
);
118 /* Or take pv_name instead? */
119 static int _vgreduce_single(struct cmd_context
*cmd
, struct volume_group
*vg
,
120 struct physical_volume
*pv
,
121 void *handle
__attribute__((unused
)))
124 struct volume_group
*orphan_vg
= NULL
;
126 const char *name
= pv_dev_name(pv
);
128 if (pv_pe_alloc_count(pv
)) {
129 log_error("Physical volume \"%s\" still in use", name
);
133 if (vg
->pv_count
== 1) {
134 log_error("Can't remove final physical volume \"%s\" from "
135 "volume group \"%s\"", name
, vg
->name
);
139 if (!lock_vol(cmd
, VG_ORPHANS
, LCK_VG_WRITE
)) {
140 log_error("Can't get lock for orphan PVs");
144 pvl
= find_pv_in_vg(vg
, name
);
149 log_verbose("Removing \"%s\" from volume group \"%s\"", name
, vg
->name
);
152 del_pvl_from_vgs(vg
, pvl
);
154 pv
->vg_name
= vg
->fid
->fmt
->orphan_vg_name
;
155 pv
->status
= ALLOCATABLE_PV
;
157 if (!dev_get_size(pv_dev(pv
), &pv
->size
)) {
158 log_error("%s: Couldn't get size.", pv_dev_name(pv
));
162 vg
->free_count
-= pv_pe_count(pv
) - pv_pe_alloc_count(pv
);
163 vg
->extent_count
-= pv_pe_count(pv
);
165 orphan_vg
= vg_read_for_update(cmd
, vg
->fid
->fmt
->orphan_vg_name
,
168 if (vg_read_error(orphan_vg
))
171 if (!vg_split_mdas(cmd
, vg
, orphan_vg
) || !vg
->pv_count
) {
172 log_error("Cannot remove final metadata area on \"%s\" from \"%s\"",
177 if (!vg_write(vg
) || !vg_commit(vg
)) {
178 log_error("Removal of physical volume \"%s\" from "
179 "\"%s\" failed", name
, vg
->name
);
183 if (!pv_write(cmd
, pv
, 0)) {
184 log_error("Failed to clear metadata from physical "
186 "after removal from \"%s\"", name
, vg
->name
);
192 log_print("Removed \"%s\" from volume group \"%s\"", name
, vg
->name
);
196 free_pv_fid(pvl
->pv
);
197 unlock_and_release_vg(cmd
, orphan_vg
, VG_ORPHANS
);
201 int vgreduce(struct cmd_context
*cmd
, int argc
, char **argv
)
203 struct volume_group
*vg
;
205 int ret
= ECMD_FAILED
;
207 int repairing
= arg_count(cmd
, removemissing_ARG
);
208 int saved_ignore_suspended_devices
= ignore_suspended_devices();
211 if (!argc
&& !repairing
) {
212 log_error("Please give volume group name and "
213 "physical volume paths");
214 return EINVALID_CMD_LINE
;
217 if (!argc
) { /* repairing */
218 log_error("Please give volume group name");
219 return EINVALID_CMD_LINE
;
222 if (arg_count(cmd
, mirrorsonly_ARG
) && !repairing
) {
223 log_error("--mirrorsonly requires --removemissing");
224 return EINVALID_CMD_LINE
;
227 if (argc
== 1 && !arg_count(cmd
, all_ARG
) && !repairing
) {
228 log_error("Please enter physical volume paths or option -a");
229 return EINVALID_CMD_LINE
;
232 if (argc
> 1 && arg_count(cmd
, all_ARG
)) {
233 log_error("Option -a and physical volume paths mutually "
235 return EINVALID_CMD_LINE
;
238 if (argc
> 1 && repairing
) {
239 log_error("Please only specify the volume group");
240 return EINVALID_CMD_LINE
;
243 vg_name
= skip_dev_dir(cmd
, argv
[0], NULL
);
247 log_verbose("Finding volume group \"%s\"", vg_name
);
250 init_ignore_suspended_devices(1);
251 cmd
->handles_missing_pvs
= 1;
254 vg
= vg_read_for_update(cmd
, vg_name
, NULL
, READ_ALLOW_EXPORTED
);
255 if (vg_read_error(vg
) == FAILED_ALLOCATION
||
256 vg_read_error(vg
) == FAILED_NOTFOUND
)
259 /* FIXME We want to allow read-only VGs to be changed here? */
260 if (vg_read_error(vg
) && vg_read_error(vg
) != FAILED_READ_ONLY
261 && !arg_count(cmd
, removemissing_ARG
))
264 locked
= !vg_read_error(vg
);
267 if (!vg_read_error(vg
) && !vg_missing_pv_count(vg
)) {
268 log_error("Volume group \"%s\" is already consistent",
270 ret
= ECMD_PROCESSED
;
275 log_verbose("Trying to open VG %s for recovery...", vg_name
);
277 vg
= vg_read_for_update(cmd
, vg_name
, NULL
,
278 READ_ALLOW_INCONSISTENT
279 | READ_ALLOW_EXPORTED
);
281 locked
|= !vg_read_error(vg
);
282 if (vg_read_error(vg
) && vg_read_error(vg
) != FAILED_READ_ONLY
283 && vg_read_error(vg
) != FAILED_INCONSISTENT
)
289 if (arg_count(cmd
, force_ARG
)) {
290 if (!_make_vg_consistent(cmd
, vg
))
293 fixed
= _consolidate_vg(cmd
, vg
);
295 if (!vg_write(vg
) || !vg_commit(vg
)) {
296 log_error("Failed to write out a consistent VG for %s",
303 log_print("Wrote out consistent volume group %s",
305 ret
= ECMD_PROCESSED
;
310 if (!vg_check_status(vg
, EXPORTED_VG
| LVM_WRITE
| RESIZEABLE_VG
))
313 /* FIXME: Pass private struct through to all these functions */
314 /* and update in batch here? */
315 ret
= process_each_pv(cmd
, argc
, argv
, vg
, READ_FOR_UPDATE
, 0, NULL
,
320 init_ignore_suspended_devices(saved_ignore_suspended_devices
);
322 unlock_vg(cmd
, vg_name
);
329 log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
332 ("volume group \"%s\" will be reduced by %d physical volume%s",
333 vg_name, np, np > 1 ? "s" : "");
334 log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"",
335 vg_name, pv_names[p]);
338 ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:",
339 vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
340 log_print("%s", pv_this[p]->pv_name);