]> sourceware.org Git - lvm2.git/blob - tools/vgreduce.c
f500b553add140c40ddb74255aeb677cfac34d63
[lvm2.git] / tools / vgreduce.c
1 /*
2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
4 *
5 * This file is part of LVM2.
6 *
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.
10 *
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
14 */
15
16 #include "tools.h"
17
18 struct vgreduce_params {
19 int force;
20 int fixed;
21 int already_consistent;
22 };
23
24 static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
25 {
26 char uuid[64] __attribute__((aligned(8)));
27
28 if (vg->pv_count == 1) {
29 log_error("Volume Groups must always contain at least one PV.");
30 return 0;
31 }
32
33 if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
34 return_0;
35
36 log_verbose("Removing PV with UUID %s from VG %s.", uuid, vg->name);
37
38 if (pvl->pv->pe_alloc_count) {
39 if (!silent)
40 log_error("LVs still present on PV with UUID %s: "
41 "Can't remove from VG %s.", uuid, vg->name);
42 return 0;
43 }
44
45 vg->free_count -= pvl->pv->pe_count;
46 vg->extent_count -= pvl->pv->pe_count;
47 del_pvl_from_vgs(vg, pvl);
48 free_pv_fid(pvl->pv);
49
50 return 1;
51 }
52
53 static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
54 {
55 struct pv_list *pvl;
56 struct lv_list *lvl;
57 int r = 1;
58
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);
63 r = 0;
64 }
65
66 if (!r) {
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.");
73 }
74
75 dm_list_iterate_items(pvl, &vg->pvs) {
76 if (pvl->pv->dev && !is_missing_pv(pvl->pv))
77 continue;
78 if (r && !_remove_pv(vg, pvl, 0))
79 return_0;
80 }
81
82 return r;
83 }
84
85 static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
86 {
87 struct lv_list *lvl;
88 struct logical_volume *lv;
89
90 cmd->partial_activation = 1;
91
92 restart:
93 vg_mark_partial_lvs(vg, 1);
94
95 dm_list_iterate_items(lvl, &vg->lvs) {
96 lv = lvl->lv;
97
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))
102 return_0;
103 goto restart;
104 }
105
106 if (lv_is_mirror(lv)) {
107 if (!mirror_remove_missing(cmd, lv, 1))
108 return_0;
109 goto restart;
110 }
111
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);
114 continue;
115 }
116
117 if (!lv_is_visible(lv))
118 continue;
119
120 log_warn("WARNING: Removing partial LV %s.", display_lvname(lv));
121
122 if (!lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0))
123 return_0;
124 goto restart;
125 }
126 }
127
128 _consolidate_vg(cmd, vg);
129
130 return 1;
131 }
132
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)))
137 {
138 int r;
139
140 if (!vg_check_status(vg, LVM_WRITE | RESIZEABLE_VG))
141 return ECMD_FAILED;
142
143 r = vgreduce_single(cmd, vg, pv, 1);
144 if (!r)
145 return ECMD_FAILED;
146
147 return ECMD_PROCESSED;
148 }
149
150 static int _vgreduce_repair_single(struct cmd_context *cmd, const char *vg_name,
151 struct volume_group *vg, struct processing_handle *handle)
152 {
153 struct vgreduce_params *vp = (struct vgreduce_params *) handle->custom_handle;
154
155 if (!vg_missing_pv_count(vg)) {
156 vp->already_consistent = 1;
157 return ECMD_PROCESSED;
158 }
159
160 if (vp->force) {
161 if (!_make_vg_consistent(cmd, vg))
162 return_ECMD_FAILED;
163 vp->fixed = 1;
164 } else
165 vp->fixed = _consolidate_vg(cmd, vg);
166
167 if (!vg_write(vg) || !vg_commit(vg)) {
168 log_error("Failed to write out a consistent VG for %s", vg_name);
169 return ECMD_FAILED;
170 }
171
172 return ECMD_PROCESSED;
173 }
174
175 int vgreduce(struct cmd_context *cmd, int argc, char **argv)
176 {
177 struct processing_handle *handle;
178 struct vgreduce_params vp = { 0 };
179 const char *vg_name;
180 int repairing = arg_is_set(cmd, removemissing_ARG);
181 int saved_ignore_suspended_devices = ignore_suspended_devices();
182 int ret;
183
184 if (!argc && !repairing) {
185 log_error("Please give volume group name and "
186 "physical volume paths.");
187 return EINVALID_CMD_LINE;
188 }
189
190 if (!argc) { /* repairing */
191 log_error("Please give volume group name.");
192 return EINVALID_CMD_LINE;
193 }
194
195 if (arg_is_set(cmd, mirrorsonly_ARG) && !repairing) {
196 log_error("--mirrorsonly requires --removemissing.");
197 return EINVALID_CMD_LINE;
198 }
199
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;
203 }
204
205 if (argc > 1 && arg_is_set(cmd, all_ARG)) {
206 log_error("Option -a and physical volume paths mutually "
207 "exclusive.");
208 return EINVALID_CMD_LINE;
209 }
210
211 if (argc > 1 && repairing) {
212 log_error("Please only specify the volume group.");
213 return EINVALID_CMD_LINE;
214 }
215
216 vg_name = skip_dev_dir(cmd, argv[0], NULL);
217 argv++;
218 argc--;
219
220 if (!lock_global(cmd, "ex"))
221 return_ECMD_FAILED;
222
223 clear_hint_file(cmd);
224
225 if (!(handle = init_processing_handle(cmd, NULL))) {
226 log_error("Failed to initialize processing handle.");
227 return ECMD_FAILED;
228 }
229 handle->custom_handle = &vp;
230
231 if (!repairing) {
232 /* FIXME: Pass private struct through to all these functions */
233 /* and update in batch afterwards? */
234
235 ret = process_each_pv(cmd, argc, argv, vg_name, 0, READ_FOR_UPDATE,
236 handle, _vgreduce_single);
237
238 goto out;
239 }
240
241 /*
242 * VG repair (removemissing)
243 */
244
245 vp.force = arg_count(cmd, force_ARG);
246
247 cmd->handles_missing_pvs = 1;
248
249 init_ignore_suspended_devices(1);
250
251 process_each_vg(cmd, 0, NULL, vg_name, NULL, READ_FOR_UPDATE,
252 0, handle, &_vgreduce_repair_single);
253
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;
260 } else
261 ret = ECMD_FAILED;
262 out:
263 init_ignore_suspended_devices(saved_ignore_suspended_devices);
264 destroy_processing_handle(cmd, handle);
265
266 return ret;
267 }
This page took 0.053866 seconds and 6 git commands to generate.