]>
Commit | Line | Data |
---|---|---|
6e91eeef | 1 | /* |
67cdbd7e | 2 | * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. |
ea0cdd28 | 3 | * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. |
6e91eeef | 4 | * |
6606c3ae | 5 | * This file is part of LVM2. |
6e91eeef | 6 | * |
6606c3ae AK |
7 | * This copyrighted material is made available to anyone wishing to use, |
8 | * modify, copy, or redistribute it subject to the terms and conditions | |
be684599 | 9 | * of the GNU Lesser General Public License v.2.1. |
6e91eeef | 10 | * |
be684599 | 11 | * You should have received a copy of the GNU Lesser General Public License |
6606c3ae AK |
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 | |
6e91eeef AK |
14 | */ |
15 | ||
16 | #include "tools.h" | |
3fc3e48c | 17 | #include "lv_alloc.h" |
6e91eeef | 18 | |
8c5bcdab | 19 | static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent) |
a421f743 | 20 | { |
08f1ddea | 21 | char uuid[64] __attribute__((aligned(8))); |
a421f743 AK |
22 | |
23 | if (vg->pv_count == 1) { | |
24 | log_error("Volume Groups must always contain at least one PV"); | |
25 | return 0; | |
26 | } | |
27 | ||
c51b9fff AK |
28 | if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) |
29 | return_0; | |
a421f743 AK |
30 | |
31 | log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name); | |
32 | ||
33 | if (pvl->pv->pe_alloc_count) { | |
8c5bcdab AK |
34 | if (!silent) |
35 | log_error("LVs still present on PV with UUID %s: " | |
36 | "Can't remove from VG %s", uuid, vg->name); | |
a421f743 AK |
37 | return 0; |
38 | } | |
39 | ||
40 | vg->free_count -= pvl->pv->pe_count; | |
41 | vg->extent_count -= pvl->pv->pe_count; | |
0adfbfd5 | 42 | del_pvl_from_vgs(vg, pvl); |
84f48499 | 43 | free_pv_fid(pvl->pv); |
a421f743 AK |
44 | |
45 | return 1; | |
46 | } | |
47 | ||
8c5bcdab AK |
48 | static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg) |
49 | { | |
50 | struct pv_list *pvl; | |
51 | struct lv_list *lvl; | |
52 | int r = 1; | |
53 | ||
2c44337b | 54 | dm_list_iterate_items(lvl, &vg->lvs) |
8c5bcdab AK |
55 | if (lvl->lv->status & PARTIAL_LV) { |
56 | log_warn("WARNING: Partial LV %s needs to be repaired " | |
57 | "or removed. ", lvl->lv->name); | |
58 | r = 0; | |
59 | } | |
60 | ||
61 | if (!r) { | |
62 | cmd->handles_missing_pvs = 1; | |
616c6208 PR |
63 | log_error("There are still partial LVs in VG %s.", vg->name); |
64 | log_error("To remove them unconditionally use: vgreduce --removemissing --force."); | |
8c5bcdab AK |
65 | log_warn("Proceeding to remove empty missing PVs."); |
66 | } | |
67 | ||
2c44337b | 68 | dm_list_iterate_items(pvl, &vg->pvs) { |
770dc81b | 69 | if (pvl->pv->dev && !is_missing_pv(pvl->pv)) |
8c5bcdab AK |
70 | continue; |
71 | if (r && !_remove_pv(vg, pvl, 0)) | |
72 | return_0; | |
73 | } | |
74 | ||
75 | return r; | |
76 | } | |
77 | ||
a421f743 AK |
78 | static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) |
79 | { | |
ed6ff5d2 | 80 | struct lv_list *lvl; |
a421f743 | 81 | struct logical_volume *lv; |
3fc3e48c | 82 | |
ed6ff5d2 | 83 | cmd->partial_activation = 1; |
3fc3e48c | 84 | |
ed6ff5d2 PR |
85 | restart: |
86 | vg_mark_partial_lvs(vg, 1); | |
532dae48 | 87 | |
ed6ff5d2 PR |
88 | dm_list_iterate_items(lvl, &vg->lvs) { |
89 | lv = lvl->lv; | |
532dae48 | 90 | |
ed6ff5d2 PR |
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)) | |
c51b9fff | 95 | return_0; |
ed6ff5d2 | 96 | goto restart; |
079ac15e | 97 | } |
3fc3e48c | 98 | |
ed6ff5d2 PR |
99 | if (arg_count(cmd, mirrorsonly_ARG) &&!(lv->status & MIRRORED)) { |
100 | log_error("Non-mirror-image LV %s found: can't remove.", lv->name); | |
101 | continue; | |
3fc3e48c | 102 | } |
3fc3e48c | 103 | |
ed6ff5d2 PR |
104 | if (!lv_is_visible(lv)) |
105 | continue; | |
106 | log_warn("Removing partial LV %s.", lv->name); | |
6fa41e8a | 107 | if (!lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0)) |
ed6ff5d2 PR |
108 | return_0; |
109 | goto restart; | |
3fc3e48c AK |
110 | } |
111 | } | |
112 | ||
ed6ff5d2 PR |
113 | _consolidate_vg(cmd, vg); |
114 | ||
a421f743 AK |
115 | return 1; |
116 | } | |
117 | ||
5a52dca9 | 118 | /* Or take pv_name instead? */ |
a421f743 | 119 | static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, |
72b2cb61 | 120 | struct physical_volume *pv, |
08f1ddea | 121 | void *handle __attribute__((unused))) |
5a52dca9 AK |
122 | { |
123 | struct pv_list *pvl; | |
043b1362 | 124 | struct volume_group *orphan_vg = NULL; |
043b1362 | 125 | int r = ECMD_FAILED; |
1b8de4cb | 126 | const char *name = pv_dev_name(pv); |
5a52dca9 | 127 | |
ff77bb1a | 128 | if (pv_pe_alloc_count(pv)) { |
5a52dca9 AK |
129 | log_error("Physical volume \"%s\" still in use", name); |
130 | return ECMD_FAILED; | |
131 | } | |
132 | ||
133 | if (vg->pv_count == 1) { | |
134 | log_error("Can't remove final physical volume \"%s\" from " | |
135 | "volume group \"%s\"", name, vg->name); | |
136 | return ECMD_FAILED; | |
137 | } | |
138 | ||
5a820745 | 139 | if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { |
6eb44b50 AK |
140 | log_error("Can't get lock for orphan PVs"); |
141 | return ECMD_FAILED; | |
142 | } | |
143 | ||
5a52dca9 AK |
144 | pvl = find_pv_in_vg(vg, name); |
145 | ||
043b1362 | 146 | if (!archive(vg)) |
651ff9b3 | 147 | goto_bad; |
6e91eeef | 148 | |
5a52dca9 AK |
149 | log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name); |
150 | ||
151 | if (pvl) | |
11647ad0 | 152 | del_pvl_from_vgs(vg, pvl); |
5a52dca9 | 153 | |
bb097a97 | 154 | pv->vg_name = vg->fid->fmt->orphan_vg_name; |
3fc3e48c | 155 | pv->status = ALLOCATABLE_PV; |
15db9fcf | 156 | |
ff77bb1a | 157 | if (!dev_get_size(pv_dev(pv), &pv->size)) { |
1b8de4cb | 158 | log_error("%s: Couldn't get size.", pv_dev_name(pv)); |
043b1362 | 159 | goto bad; |
15db9fcf AK |
160 | } |
161 | ||
ff77bb1a DW |
162 | vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv); |
163 | vg->extent_count -= pv_pe_count(pv); | |
5a52dca9 | 164 | |
542ef24d | 165 | orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name, |
4c35d6de | 166 | NULL, 0); |
542ef24d DW |
167 | |
168 | if (vg_read_error(orphan_vg)) | |
043b1362 | 169 | goto bad; |
6eb44b50 AK |
170 | |
171 | if (!vg_split_mdas(cmd, vg, orphan_vg) || !vg->pv_count) { | |
172 | log_error("Cannot remove final metadata area on \"%s\" from \"%s\"", | |
173 | name, vg->name); | |
043b1362 | 174 | goto bad; |
6eb44b50 AK |
175 | } |
176 | ||
914c9723 | 177 | if (!vg_write(vg) || !vg_commit(vg)) { |
5a52dca9 AK |
178 | log_error("Removal of physical volume \"%s\" from " |
179 | "\"%s\" failed", name, vg->name); | |
043b1362 | 180 | goto bad; |
5a52dca9 AK |
181 | } |
182 | ||
3b97e8d6 | 183 | if (!pv_write(cmd, pv, 0)) { |
5a52dca9 AK |
184 | log_error("Failed to clear metadata from physical " |
185 | "volume \"%s\" " | |
186 | "after removal from \"%s\"", name, vg->name); | |
043b1362 | 187 | goto bad; |
5a52dca9 AK |
188 | } |
189 | ||
190 | backup(vg); | |
191 | ||
192 | log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name); | |
043b1362 MB |
193 | r = ECMD_PROCESSED; |
194 | bad: | |
84f48499 PR |
195 | if (pvl) |
196 | free_pv_fid(pvl->pv); | |
077a6755 | 197 | unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS); |
043b1362 | 198 | return r; |
5a52dca9 | 199 | } |
a421f743 | 200 | |
60274aba | 201 | int vgreduce(struct cmd_context *cmd, int argc, char **argv) |
6e91eeef AK |
202 | { |
203 | struct volume_group *vg; | |
aec21154 | 204 | const char *vg_name; |
043b1362 | 205 | int ret = ECMD_FAILED; |
8c5bcdab AK |
206 | int fixed = 1; |
207 | int repairing = arg_count(cmd, removemissing_ARG); | |
1f164ad9 | 208 | int saved_ignore_suspended_devices = ignore_suspended_devices(); |
6e826bb6 | 209 | int locked = 0; |
6e91eeef | 210 | |
8c5bcdab | 211 | if (!argc && !repairing) { |
6e91eeef AK |
212 | log_error("Please give volume group name and " |
213 | "physical volume paths"); | |
214 | return EINVALID_CMD_LINE; | |
215 | } | |
8c5bcdab | 216 | |
eae8784a | 217 | if (!argc) { /* repairing */ |
a421f743 AK |
218 | log_error("Please give volume group name"); |
219 | return EINVALID_CMD_LINE; | |
220 | } | |
221 | ||
8c5bcdab | 222 | if (arg_count(cmd, mirrorsonly_ARG) && !repairing) { |
c9dcba6b AK |
223 | log_error("--mirrorsonly requires --removemissing"); |
224 | return EINVALID_CMD_LINE; | |
225 | } | |
226 | ||
8c5bcdab | 227 | if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) { |
6e91eeef AK |
228 | log_error("Please enter physical volume paths or option -a"); |
229 | return EINVALID_CMD_LINE; | |
230 | } | |
231 | ||
6fda126d | 232 | if (argc > 1 && arg_count(cmd, all_ARG)) { |
6e91eeef AK |
233 | log_error("Option -a and physical volume paths mutually " |
234 | "exclusive"); | |
235 | return EINVALID_CMD_LINE; | |
236 | } | |
237 | ||
8c5bcdab | 238 | if (argc > 1 && repairing) { |
a421f743 AK |
239 | log_error("Please only specify the volume group"); |
240 | return EINVALID_CMD_LINE; | |
241 | } | |
242 | ||
9397354a | 243 | vg_name = skip_dev_dir(cmd, argv[0], NULL); |
6e91eeef AK |
244 | argv++; |
245 | argc--; | |
246 | ||
08907484 | 247 | log_verbose("Finding volume group \"%s\"", vg_name); |
7d0e6e80 | 248 | |
19089ba3 | 249 | if (repairing) { |
1f164ad9 | 250 | init_ignore_suspended_devices(1); |
19089ba3 PR |
251 | cmd->handles_missing_pvs = 1; |
252 | } | |
1f164ad9 | 253 | |
542ef24d DW |
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) | |
651ff9b3 | 257 | goto_out; |
6e91eeef | 258 | |
542ef24d DW |
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)) | |
651ff9b3 | 262 | goto_out; |
dc4d7417 | 263 | |
6e826bb6 ZK |
264 | locked = !vg_read_error(vg); |
265 | ||
8c5bcdab | 266 | if (repairing) { |
542ef24d | 267 | if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) { |
a421f743 AK |
268 | log_error("Volume group \"%s\" is already consistent", |
269 | vg_name); | |
043b1362 MB |
270 | ret = ECMD_PROCESSED; |
271 | goto out; | |
a421f743 | 272 | } |
f53c6aa6 | 273 | |
077a6755 | 274 | release_vg(vg); |
542ef24d DW |
275 | log_verbose("Trying to open VG %s for recovery...", vg_name); |
276 | ||
277 | vg = vg_read_for_update(cmd, vg_name, NULL, | |
278 | READ_ALLOW_INCONSISTENT | |
279 | | READ_ALLOW_EXPORTED); | |
280 | ||
6e826bb6 | 281 | locked |= !vg_read_error(vg); |
542ef24d DW |
282 | if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY |
283 | && vg_read_error(vg) != FAILED_INCONSISTENT) | |
651ff9b3 | 284 | goto_out; |
542ef24d | 285 | |
043b1362 | 286 | if (!archive(vg)) |
651ff9b3 | 287 | goto_out; |
f53c6aa6 | 288 | |
8c5bcdab | 289 | if (arg_count(cmd, force_ARG)) { |
043b1362 | 290 | if (!_make_vg_consistent(cmd, vg)) |
651ff9b3 | 291 | goto_out; |
8c5bcdab AK |
292 | } else |
293 | fixed = _consolidate_vg(cmd, vg); | |
a421f743 | 294 | |
914c9723 | 295 | if (!vg_write(vg) || !vg_commit(vg)) { |
a421f743 AK |
296 | log_error("Failed to write out a consistent VG for %s", |
297 | vg_name); | |
043b1362 | 298 | goto out; |
a421f743 | 299 | } |
a421f743 AK |
300 | backup(vg); |
301 | ||
cd978f74 | 302 | if (fixed) { |
8c5bcdab AK |
303 | log_print("Wrote out consistent volume group %s", |
304 | vg_name); | |
cd978f74 MB |
305 | ret = ECMD_PROCESSED; |
306 | } else | |
307 | ret = ECMD_FAILED; | |
a421f743 AK |
308 | |
309 | } else { | |
043b1362 | 310 | if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) |
651ff9b3 | 311 | goto_out; |
a421f743 AK |
312 | |
313 | /* FIXME: Pass private struct through to all these functions */ | |
314 | /* and update in batch here? */ | |
21a98eda | 315 | ret = process_each_pv(cmd, argc, argv, vg, READ_FOR_UPDATE, 0, NULL, |
a421f743 AK |
316 | _vgreduce_single); |
317 | ||
318 | } | |
043b1362 | 319 | out: |
1f164ad9 | 320 | init_ignore_suspended_devices(saved_ignore_suspended_devices); |
6e826bb6 ZK |
321 | if (locked) |
322 | unlock_vg(cmd, vg_name); | |
323 | ||
324 | release_vg(vg); | |
7d0e6e80 AK |
325 | |
326 | return ret; | |
6e91eeef AK |
327 | |
328 | /******* FIXME | |
329 | log_error ("no empty physical volumes found in volume group \"%s\"", vg_name); | |
cc282870 | 330 | |
6e91eeef AK |
331 | log_verbose |
332 | ("volume group \"%s\" will be reduced by %d physical volume%s", | |
333 | vg_name, np, np > 1 ? "s" : ""); | |
08907484 HM |
334 | log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"", |
335 | vg_name, pv_names[p]); | |
6e91eeef AK |
336 | |
337 | log_print | |
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); | |
341 | ********/ | |
342 | ||
343 | } |