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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 struct vgreduce_params
{
21 int already_consistent
;
24 static int _remove_pv(struct volume_group
*vg
, struct pv_list
*pvl
, int silent
)
26 char uuid
[64] __attribute__((aligned(8)));
28 if (vg
->pv_count
== 1) {
29 log_error("Volume Groups must always contain at least one PV.");
33 if (!id_write_format(&pvl
->pv
->id
, uuid
, sizeof(uuid
)))
36 log_verbose("Removing PV with UUID %s from VG %s.", uuid
, vg
->name
);
38 if (pvl
->pv
->pe_alloc_count
) {
40 log_error("LVs still present on PV with UUID %s: "
41 "Can't remove from VG %s.", uuid
, vg
->name
);
45 vg
->free_count
-= pvl
->pv
->pe_count
;
46 vg
->extent_count
-= pvl
->pv
->pe_count
;
47 del_pvl_from_vgs(vg
, pvl
);
53 static int _consolidate_vg(struct cmd_context
*cmd
, struct volume_group
*vg
)
59 dm_list_iterate_items(lvl
, &vg
->lvs
)
60 if (lv_is_partial(lvl
->lv
)) {
61 log_warn("WARNING: Partial LV %s needs to be repaired "
62 "or removed. ", lvl
->lv
->name
);
67 cmd
->handles_missing_pvs
= 1;
68 log_error("There are still partial LVs in VG %s.", vg
->name
);
69 log_error("To remove them unconditionally use: vgreduce --removemissing --force.");
70 log_error("To remove them unconditionally from mirror LVs use: vgreduce"
71 " --removemissing --mirrorsonly --force.");
72 log_warn("WARNING: Proceeding to remove empty missing PVs.");
75 dm_list_iterate_items(pvl
, &vg
->pvs
) {
76 if (pvl
->pv
->dev
&& !is_missing_pv(pvl
->pv
))
78 if (r
&& !_remove_pv(vg
, pvl
, 0))
85 static int _make_vg_consistent(struct cmd_context
*cmd
, struct volume_group
*vg
)
88 struct logical_volume
*lv
;
90 cmd
->partial_activation
= 1;
93 vg_mark_partial_lvs(vg
, 1);
95 dm_list_iterate_items(lvl
, &vg
->lvs
) {
98 /* Are any segments of this LV on missing PVs? */
99 if (lv_is_partial(lv
)) {
100 if (seg_is_raid(first_seg(lv
))) {
101 if (!lv_raid_remove_missing(lv
))
106 if (lv_is_mirror(lv
)) {
107 if (!mirror_remove_missing(cmd
, lv
, 1))
112 if (arg_is_set(cmd
, mirrorsonly_ARG
) && !lv_is_mirrored(lv
)) {
113 log_error("Non-mirror-image LV %s found: can't remove.", lv
->name
);
117 if (!lv_is_visible(lv
))
120 log_warn("WARNING: Removing partial LV %s.", display_lvname(lv
));
122 if (!lv_remove_with_dependencies(cmd
, lv
, DONT_PROMPT
, 0))
128 _consolidate_vg(cmd
, vg
);
133 /* Or take pv_name instead? */
134 static int _vgreduce_single(struct cmd_context
*cmd
, struct volume_group
*vg
,
135 struct physical_volume
*pv
,
136 struct processing_handle
*handle
__attribute__((unused
)))
140 if (!vg_check_status(vg
, LVM_WRITE
| RESIZEABLE_VG
))
143 r
= vgreduce_single(cmd
, vg
, pv
, 1);
147 return ECMD_PROCESSED
;
150 static int _vgreduce_repair_single(struct cmd_context
*cmd
, const char *vg_name
,
151 struct volume_group
*vg
, struct processing_handle
*handle
)
153 struct vgreduce_params
*vp
= (struct vgreduce_params
*) handle
->custom_handle
;
155 if (!vg_missing_pv_count(vg
)) {
156 vp
->already_consistent
= 1;
157 return ECMD_PROCESSED
;
161 if (!_make_vg_consistent(cmd
, vg
))
165 vp
->fixed
= _consolidate_vg(cmd
, vg
);
167 if (!vg_write(vg
) || !vg_commit(vg
)) {
168 log_error("Failed to write out a consistent VG for %s", vg_name
);
172 return ECMD_PROCESSED
;
175 int vgreduce(struct cmd_context
*cmd
, int argc
, char **argv
)
177 struct processing_handle
*handle
;
178 struct vgreduce_params vp
= { 0 };
180 int repairing
= arg_is_set(cmd
, removemissing_ARG
);
181 int saved_ignore_suspended_devices
= ignore_suspended_devices();
184 if (!argc
&& !repairing
) {
185 log_error("Please give volume group name and "
186 "physical volume paths.");
187 return EINVALID_CMD_LINE
;
190 if (!argc
) { /* repairing */
191 log_error("Please give volume group name.");
192 return EINVALID_CMD_LINE
;
195 if (arg_is_set(cmd
, mirrorsonly_ARG
) && !repairing
) {
196 log_error("--mirrorsonly requires --removemissing.");
197 return EINVALID_CMD_LINE
;
200 if (argc
== 1 && !arg_is_set(cmd
, all_ARG
) && !repairing
) {
201 log_error("Please enter physical volume paths or option -a.");
202 return EINVALID_CMD_LINE
;
205 if (argc
> 1 && arg_is_set(cmd
, all_ARG
)) {
206 log_error("Option -a and physical volume paths mutually "
208 return EINVALID_CMD_LINE
;
211 if (argc
> 1 && repairing
) {
212 log_error("Please only specify the volume group.");
213 return EINVALID_CMD_LINE
;
216 vg_name
= skip_dev_dir(cmd
, argv
[0], NULL
);
220 if (!lock_global(cmd
, "ex"))
223 clear_hint_file(cmd
);
225 if (!(handle
= init_processing_handle(cmd
, NULL
))) {
226 log_error("Failed to initialize processing handle.");
229 handle
->custom_handle
= &vp
;
232 /* FIXME: Pass private struct through to all these functions */
233 /* and update in batch afterwards? */
235 ret
= process_each_pv(cmd
, argc
, argv
, vg_name
, 0, READ_FOR_UPDATE
,
236 handle
, _vgreduce_single
);
242 * VG repair (removemissing)
245 vp
.force
= arg_count(cmd
, force_ARG
);
247 cmd
->handles_missing_pvs
= 1;
249 init_ignore_suspended_devices(1);
251 process_each_vg(cmd
, 0, NULL
, vg_name
, NULL
, READ_FOR_UPDATE
,
252 0, handle
, &_vgreduce_repair_single
);
254 if (vp
.already_consistent
) {
255 log_print_unless_silent("Volume group \"%s\" is already consistent.", vg_name
);
256 ret
= ECMD_PROCESSED
;
257 } else if (vp
.fixed
) {
258 log_print_unless_silent("Wrote out consistent volume group %s.", vg_name
);
259 ret
= ECMD_PROCESSED
;
263 init_ignore_suspended_devices(saved_ignore_suspended_devices
);
264 destroy_processing_handle(cmd
, handle
);