]>
Commit | Line | Data |
---|---|---|
269930c0 | 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. |
269930c0 | 4 | * |
6606c3ae AK |
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 | |
be684599 | 9 | * of the GNU Lesser General Public License v.2.1. |
6606c3ae | 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 | |
269930c0 AK |
14 | */ |
15 | ||
25d42d50 | 16 | #include "tools.h" |
7424de5b | 17 | #include "lv_alloc.h" |
5c9d70c9 | 18 | #include "xlate.h" |
269930c0 | 19 | |
cc219483 | 20 | #include <sys/stat.h> |
1a9ea74d | 21 | #include <sys/wait.h> |
cc219483 | 22 | |
8a2fc586 AK |
23 | const char *command_name(struct cmd_context *cmd) |
24 | { | |
25 | return cmd->command->name; | |
26 | } | |
27 | ||
08c060cf AK |
28 | /* |
29 | * Strip dev_dir if present | |
30 | */ | |
aec21154 | 31 | const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name, |
9397354a | 32 | unsigned *dev_dir_found) |
08c060cf | 33 | { |
9397354a AK |
34 | const char *dmdir = dm_dir(); |
35 | size_t dmdir_len = strlen(dmdir), vglv_sz; | |
36 | char *vgname, *lvname, *layer, *vglv; | |
08c060cf | 37 | |
9397354a | 38 | /* FIXME Do this properly */ |
08c060cf AK |
39 | if (*vg_name == '/') { |
40 | while (*vg_name == '/') | |
41 | vg_name++; | |
42 | vg_name--; | |
43 | } | |
44 | ||
9397354a AK |
45 | /* Reformat string if /dev/mapper found */ |
46 | if (!strncmp(vg_name, dmdir, dmdir_len) && vg_name[dmdir_len] == '/') { | |
47 | if (dev_dir_found) | |
48 | *dev_dir_found = 1; | |
49 | vg_name += dmdir_len; | |
50 | while (*vg_name == '/') | |
51 | vg_name++; | |
52 | ||
53 | if (!dm_split_lvm_name(cmd->mem, vg_name, &vgname, &lvname, &layer) || | |
54 | *layer) { | |
55 | log_error("skip_dev_dir: Couldn't split up device name %s", | |
56 | vg_name); | |
aec21154 | 57 | return vg_name; |
9397354a AK |
58 | } |
59 | vglv_sz = strlen(vgname) + strlen(lvname) + 2; | |
60 | if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) || | |
61 | dm_snprintf(vglv, vglv_sz, "%s%s%s", vgname, | |
62 | *lvname ? "/" : "", | |
63 | lvname) < 0) { | |
64 | log_error("vg/lv string alloc failed"); | |
aec21154 | 65 | return vg_name; |
9397354a AK |
66 | } |
67 | return vglv; | |
68 | } | |
69 | ||
08c060cf | 70 | if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir))) { |
9397354a AK |
71 | if (dev_dir_found) |
72 | *dev_dir_found = 1; | |
08c060cf AK |
73 | vg_name += strlen(cmd->dev_dir); |
74 | while (*vg_name == '/') | |
75 | vg_name++; | |
9397354a AK |
76 | } else if (dev_dir_found) |
77 | *dev_dir_found = 0; | |
08c060cf | 78 | |
aec21154 | 79 | return vg_name; |
08c060cf AK |
80 | } |
81 | ||
68e4adb5 AK |
82 | /* |
83 | * Metadata iteration functions | |
84 | */ | |
08c9ff43 | 85 | int process_each_lv_in_vg(struct cmd_context *cmd, |
7b45e46a | 86 | struct volume_group *vg, |
2c44337b AK |
87 | const struct dm_list *arg_lvnames, |
88 | const struct dm_list *tags, | |
04a6dd77 | 89 | struct dm_list *failed_lvnames, |
5a52dca9 | 90 | void *handle, |
6c4f65fe | 91 | process_single_lv_fn_t process_single_lv) |
7f3859bb | 92 | { |
3a30d1db | 93 | int ret_max = ECMD_PROCESSED; |
7f3859bb | 94 | int ret = 0; |
72b2cb61 AK |
95 | unsigned process_all = 0; |
96 | unsigned process_lv = 0; | |
97 | unsigned tags_supplied = 0; | |
98 | unsigned lvargs_supplied = 0; | |
99 | unsigned lvargs_matched = 0; | |
04a6dd77 | 100 | char *lv_name; |
f2b7349e | 101 | struct lv_list *lvl; |
7f3859bb | 102 | |
d6b1de30 | 103 | if (!vg_check_status(vg, EXPORTED_VG)) |
7f3859bb | 104 | return ECMD_FAILED; |
f53c6aa6 | 105 | |
2c44337b | 106 | if (tags && !dm_list_empty(tags)) |
cf6dd251 AK |
107 | tags_supplied = 1; |
108 | ||
2c44337b | 109 | if (arg_lvnames && !dm_list_empty(arg_lvnames)) |
cf6dd251 AK |
110 | lvargs_supplied = 1; |
111 | ||
112 | /* Process all LVs in this VG if no restrictions given */ | |
113 | if (!tags_supplied && !lvargs_supplied) | |
114 | process_all = 1; | |
115 | ||
116 | /* Or if VG tags match */ | |
117 | if (!process_lv && tags_supplied && | |
eb82bd05 | 118 | str_list_match_list(tags, &vg->tags, NULL)) { |
cf6dd251 | 119 | process_all = 1; |
1a51586c | 120 | } |
cf6dd251 | 121 | |
98c92abf ZK |
122 | /* |
123 | * FIXME: In case of remove it goes through deleted entries, | |
124 | * but it works since entries are allocated from vg mem pool. | |
125 | */ | |
2c44337b | 126 | dm_list_iterate_items(lvl, &vg->lvs) { |
072893aa AK |
127 | if (lvl->lv->status & SNAPSHOT) |
128 | continue; | |
129 | ||
e858ac15 ZK |
130 | /* Skip availability change for non-virt snaps when processing all LVs */ |
131 | /* FIXME: pass process_all to process_single_lv() */ | |
132 | if (process_all && arg_count(cmd, available_ARG) && | |
133 | lv_is_cow(lvl->lv) && !lv_is_virtual_origin(origin_from_cow(lvl->lv))) | |
134 | continue; | |
135 | ||
99113cc5 | 136 | if (lv_is_virtual_origin(lvl->lv) && !arg_count(cmd, all_ARG)) |
36a1d9e9 AK |
137 | continue; |
138 | ||
e6f562ab AK |
139 | /* |
140 | * Only let hidden LVs through it --all was used or the LVs | |
141 | * were specifically named on the command line. | |
142 | */ | |
143 | if (!lvargs_supplied && !lv_is_visible(lvl->lv) && !arg_count(cmd, all_ARG)) | |
144 | continue; | |
145 | ||
cf6dd251 AK |
146 | /* Should we process this LV? */ |
147 | if (process_all) | |
148 | process_lv = 1; | |
149 | else | |
150 | process_lv = 0; | |
151 | ||
152 | /* LV tag match? */ | |
153 | if (!process_lv && tags_supplied && | |
eb82bd05 | 154 | str_list_match_list(tags, &lvl->lv->tags, NULL)) { |
cf6dd251 | 155 | process_lv = 1; |
1a51586c | 156 | } |
cf6dd251 AK |
157 | |
158 | /* LV name match? */ | |
e3adcd79 AK |
159 | if (lvargs_supplied && |
160 | str_list_match_item(arg_lvnames, lvl->lv->name)) { | |
cf6dd251 | 161 | process_lv = 1; |
e3adcd79 AK |
162 | lvargs_matched++; |
163 | } | |
cf6dd251 AK |
164 | |
165 | if (!process_lv) | |
166 | continue; | |
167 | ||
f467cd17 | 168 | lvl->lv->vg->cmd_missing_vgs = 0; |
6c4f65fe | 169 | ret = process_single_lv(cmd, lvl->lv, handle); |
04a6dd77 ZK |
170 | if (ret != ECMD_PROCESSED && failed_lvnames) { |
171 | lv_name = dm_pool_strdup(cmd->mem, lvl->lv->name); | |
172 | if (!lv_name || | |
173 | !str_list_add(cmd->mem, failed_lvnames, lv_name)) { | |
174 | log_error("Allocation failed for str_list."); | |
175 | return ECMD_FAILED; | |
176 | } | |
f467cd17 ZK |
177 | if (lvl->lv->vg->cmd_missing_vgs) |
178 | ret = ECMD_PROCESSED; | |
04a6dd77 | 179 | } |
7f3859bb AK |
180 | if (ret > ret_max) |
181 | ret_max = ret; | |
0a62e014 ZK |
182 | if (sigint_caught()) { |
183 | stack; | |
7379c678 | 184 | return ret_max; |
0a62e014 | 185 | } |
7f3859bb AK |
186 | } |
187 | ||
2c44337b | 188 | if (lvargs_supplied && lvargs_matched != dm_list_size(arg_lvnames)) { |
98c92abf ZK |
189 | /* |
190 | * FIXME: lvm supports removal of LV with all its dependencies | |
191 | * this leads to miscalculation that depends on the order of args. | |
192 | */ | |
e3adcd79 AK |
193 | log_error("One or more specified logical volume(s) not found."); |
194 | if (ret_max < ECMD_FAILED) | |
195 | ret_max = ECMD_FAILED; | |
196 | } | |
197 | ||
7f3859bb | 198 | return ret_max; |
7f3859bb AK |
199 | } |
200 | ||
60274aba | 201 | int process_each_lv(struct cmd_context *cmd, int argc, char **argv, |
13e8c7e4 | 202 | uint32_t flags, void *handle, |
6c4f65fe | 203 | process_single_lv_fn_t process_single_lv) |
9b7742bb AK |
204 | { |
205 | int opt = 0; | |
3a30d1db | 206 | int ret_max = ECMD_PROCESSED; |
9b7742bb | 207 | int ret = 0; |
9b7742bb | 208 | |
2c44337b AK |
209 | struct dm_list *tags_arg; |
210 | struct dm_list *vgnames; /* VGs to process */ | |
60f13f01 | 211 | struct str_list *sll, *strl; |
f467cd17 ZK |
212 | struct cmd_vg *cvl_vg; |
213 | struct dm_list cmd_vgs; | |
214 | struct dm_list failed_lvnames; | |
2c44337b AK |
215 | struct dm_list tags, lvnames; |
216 | struct dm_list arg_lvnames; /* Cmdline vgname or vgname/lvname */ | |
aaa7f4c9 | 217 | struct dm_list arg_vgnames; |
cf6dd251 AK |
218 | char *vglv; |
219 | size_t vglv_sz; | |
9b7742bb | 220 | |
8ef2b021 | 221 | const char *vgname; |
9b7742bb | 222 | |
2c44337b AK |
223 | dm_list_init(&tags); |
224 | dm_list_init(&arg_lvnames); | |
f467cd17 | 225 | dm_list_init(&failed_lvnames); |
cf6dd251 | 226 | |
9b7742bb AK |
227 | if (argc) { |
228 | log_verbose("Using logical volume(s) on command line"); | |
2c44337b | 229 | dm_list_init(&arg_vgnames); |
cf6dd251 | 230 | |
9b7742bb | 231 | for (; opt < argc; opt++) { |
cf6dd251 | 232 | const char *lv_name = argv[opt]; |
1d2f212a | 233 | const char *tmp_lv_name; |
914c9723 | 234 | char *vgname_def; |
9397354a | 235 | unsigned dev_dir_found = 0; |
5a52dca9 | 236 | |
cf6dd251 | 237 | /* Do we have a tag or vgname or lvname? */ |
5a52dca9 | 238 | vgname = lv_name; |
cf6dd251 AK |
239 | |
240 | if (*vgname == '@') { | |
10955b82 | 241 | if (!validate_tag(vgname + 1)) { |
cf6dd251 AK |
242 | log_error("Skipping invalid tag %s", |
243 | vgname); | |
244 | continue; | |
245 | } | |
246 | if (!str_list_add(cmd->mem, &tags, | |
2262b320 | 247 | dm_pool_strdup(cmd->mem, |
cf6dd251 AK |
248 | vgname + 1))) { |
249 | log_error("strlist allocation failed"); | |
250 | return ECMD_FAILED; | |
251 | } | |
252 | continue; | |
253 | } | |
254 | ||
255 | /* FIXME Jumbled parsing */ | |
9397354a AK |
256 | vgname = skip_dev_dir(cmd, vgname, &dev_dir_found); |
257 | ||
914c9723 AK |
258 | if (*vgname == '/') { |
259 | log_error("\"%s\": Invalid path for Logical " | |
cf6dd251 | 260 | "Volume", argv[opt]); |
914c9723 AK |
261 | if (ret_max < ECMD_FAILED) |
262 | ret_max = ECMD_FAILED; | |
263 | continue; | |
264 | } | |
cf6dd251 | 265 | lv_name = vgname; |
1d2f212a | 266 | if ((tmp_lv_name = strchr(vgname, '/'))) { |
5a52dca9 | 267 | /* Must be an LV */ |
1d2f212a | 268 | lv_name = tmp_lv_name; |
cf6dd251 AK |
269 | while (*lv_name == '/') |
270 | lv_name++; | |
271 | if (!(vgname = extract_vgname(cmd, vgname))) { | |
0a62e014 ZK |
272 | if (ret_max < ECMD_FAILED) { |
273 | stack; | |
5a52dca9 | 274 | ret_max = ECMD_FAILED; |
0a62e014 | 275 | } |
5a52dca9 AK |
276 | continue; |
277 | } | |
cf6dd251 | 278 | } else if (!dev_dir_found && |
1a51586c | 279 | (vgname_def = default_vgname(cmd))) { |
914c9723 | 280 | vgname = vgname_def; |
cf6dd251 AK |
281 | } else |
282 | lv_name = NULL; | |
914c9723 | 283 | |
cf6dd251 | 284 | if (!str_list_add(cmd->mem, &arg_vgnames, |
2262b320 | 285 | dm_pool_strdup(cmd->mem, vgname))) { |
cf6dd251 | 286 | log_error("strlist allocation failed"); |
f53c6aa6 AK |
287 | return ECMD_FAILED; |
288 | } | |
289 | ||
cf6dd251 AK |
290 | if (!lv_name) { |
291 | if (!str_list_add(cmd->mem, &arg_lvnames, | |
2262b320 | 292 | dm_pool_strdup(cmd->mem, |
1a51586c | 293 | vgname))) { |
cf6dd251 AK |
294 | log_error("strlist allocation failed"); |
295 | return ECMD_FAILED; | |
296 | } | |
297 | } else { | |
298 | vglv_sz = strlen(vgname) + strlen(lv_name) + 2; | |
2262b320 | 299 | if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) || |
0550c1b6 | 300 | dm_snprintf(vglv, vglv_sz, "%s/%s", vgname, |
cf6dd251 AK |
301 | lv_name) < 0) { |
302 | log_error("vg/lv string alloc failed"); | |
303 | return ECMD_FAILED; | |
304 | } | |
1a9ea74d | 305 | if (!str_list_add(cmd->mem, &arg_lvnames, vglv)) { |
cf6dd251 AK |
306 | log_error("strlist allocation failed"); |
307 | return ECMD_FAILED; | |
308 | } | |
9b7742bb | 309 | } |
9b7742bb | 310 | } |
cf6dd251 | 311 | vgnames = &arg_vgnames; |
1a51586c | 312 | } |
cf6dd251 | 313 | |
2c44337b | 314 | if (!argc || !dm_list_empty(&tags)) { |
93ea3969 | 315 | log_verbose("Finding all logical volumes"); |
dc9ef7a0 AK |
316 | if (!lvmetad_vg_list_to_lvmcache(cmd)) |
317 | stack; | |
38220f9f | 318 | if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) { |
9b7742bb | 319 | log_error("No volume groups found"); |
29e94d95 | 320 | return ret_max; |
9b7742bb | 321 | } |
cf6dd251 AK |
322 | } |
323 | ||
2c44337b | 324 | dm_list_iterate_items(strl, vgnames) { |
60f13f01 | 325 | vgname = strl->str; |
f467cd17 ZK |
326 | dm_list_init(&cmd_vgs); |
327 | if (!(cvl_vg = cmd_vg_add(cmd->mem, &cmd_vgs, | |
328 | vgname, NULL, flags))) { | |
329 | stack; | |
330 | return ECMD_FAILED; | |
331 | } | |
dc4d7417 | 332 | |
f467cd17 | 333 | if (!cmd_vg_read(cmd, &cmd_vgs)) { |
2b82bd79 | 334 | free_cmd_vgs(&cmd_vgs); |
13e8c7e4 DW |
335 | if (ret_max < ECMD_FAILED) { |
336 | log_error("Skipping volume group %s", vgname); | |
dc4d7417 | 337 | ret_max = ECMD_FAILED; |
651ff9b3 AK |
338 | } else |
339 | stack; | |
dc4d7417 AK |
340 | continue; |
341 | } | |
342 | ||
cf6dd251 | 343 | tags_arg = &tags; |
2c44337b AK |
344 | dm_list_init(&lvnames); /* LVs to be processed in this VG */ |
345 | dm_list_iterate_items(sll, &arg_lvnames) { | |
cf6dd251 AK |
346 | const char *vg_name = sll->str; |
347 | const char *lv_name = strchr(vg_name, '/'); | |
348 | ||
349 | if ((!lv_name && !strcmp(vg_name, vgname))) { | |
350 | /* Process all LVs in this VG */ | |
351 | tags_arg = NULL; | |
2c44337b | 352 | dm_list_init(&lvnames); |
cf6dd251 | 353 | break; |
5bd1cb41 | 354 | } else if (!strncmp(vg_name, vgname, strlen(vgname)) && lv_name && |
21bc3664 | 355 | strlen(vgname) == (size_t) (lv_name - vg_name)) { |
cf6dd251 | 356 | if (!str_list_add(cmd->mem, &lvnames, |
2262b320 | 357 | dm_pool_strdup(cmd->mem, |
8b7fc0da | 358 | lv_name + 1))) { |
1a51586c | 359 | log_error("strlist allocation failed"); |
2b82bd79 | 360 | free_cmd_vgs(&cmd_vgs); |
1a51586c | 361 | return ECMD_FAILED; |
5a52dca9 | 362 | } |
9b7742bb | 363 | } |
9b7742bb | 364 | } |
cf6dd251 | 365 | |
f467cd17 ZK |
366 | while (!sigint_caught()) { |
367 | ret = process_each_lv_in_vg(cmd, cvl_vg->vg, &lvnames, | |
368 | tags_arg, &failed_lvnames, | |
369 | handle, process_single_lv); | |
5ec549ca | 370 | if (ret != ECMD_PROCESSED) { |
0a62e014 | 371 | stack; |
f467cd17 | 372 | break; |
0a62e014 | 373 | } |
f467cd17 | 374 | |
5ec549ca ZK |
375 | if (dm_list_empty(&failed_lvnames)) |
376 | break; | |
377 | ||
f467cd17 ZK |
378 | /* Try again with failed LVs in this VG */ |
379 | dm_list_init(&lvnames); | |
380 | dm_list_splice(&lvnames, &failed_lvnames); | |
381 | ||
2b82bd79 | 382 | free_cmd_vgs(&cmd_vgs); |
f467cd17 | 383 | if (!cmd_vg_read(cmd, &cmd_vgs)) { |
0a62e014 | 384 | stack; |
f467cd17 ZK |
385 | ret = ECMD_FAILED; /* break */ |
386 | break; | |
387 | } | |
388 | } | |
cf6dd251 AK |
389 | if (ret > ret_max) |
390 | ret_max = ret; | |
f467cd17 | 391 | |
2b82bd79 | 392 | free_cmd_vgs(&cmd_vgs); |
0e833522 | 393 | /* FIXME: logic for breaking command is not consistent */ |
0a62e014 ZK |
394 | if (sigint_caught()) { |
395 | stack; | |
0e833522 | 396 | return ECMD_FAILED; |
0a62e014 | 397 | } |
9b7742bb AK |
398 | } |
399 | ||
400 | return ret_max; | |
401 | } | |
402 | ||
c54a9405 AK |
403 | int process_each_segment_in_pv(struct cmd_context *cmd, |
404 | struct volume_group *vg, | |
405 | struct physical_volume *pv, | |
406 | void *handle, | |
6c4f65fe | 407 | process_single_pvseg_fn_t process_single_pvseg) |
c54a9405 AK |
408 | { |
409 | struct pv_segment *pvseg; | |
0377a6de | 410 | struct pv_list *pvl; |
223c62e7 | 411 | const char *vg_name = NULL; |
3a30d1db | 412 | int ret_max = ECMD_PROCESSED; |
c54a9405 | 413 | int ret; |
043b1362 | 414 | struct volume_group *old_vg = vg; |
d66abfb8 | 415 | struct pv_segment _free_pv_segment = { .pv = pv }; |
223c62e7 | 416 | |
81c74829 | 417 | if (is_pv(pv) && !vg && !is_orphan(pv)) { |
223c62e7 | 418 | vg_name = pv_vg_name(pv); |
223c62e7 | 419 | |
13e8c7e4 DW |
420 | vg = vg_read(cmd, vg_name, NULL, 0); |
421 | if (vg_read_error(vg)) { | |
077a6755 | 422 | release_vg(vg); |
e5f7352b AK |
423 | log_error("Skipping volume group %s", vg_name); |
424 | return ECMD_FAILED; | |
223c62e7 | 425 | } |
0377a6de MB |
426 | |
427 | /* | |
428 | * Replace possibly incomplete PV structure with new one | |
429 | * allocated in vg_read_internal() path. | |
430 | */ | |
431 | if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) { | |
432 | log_error("Unable to find %s in volume group %s", | |
433 | pv_dev_name(pv), vg_name); | |
077a6755 | 434 | unlock_and_release_vg(cmd, vg, vg_name); |
685be1dc | 435 | return ECMD_FAILED; |
0377a6de MB |
436 | } |
437 | ||
438 | pv = pvl->pv; | |
223c62e7 | 439 | } |
c54a9405 | 440 | |
d66abfb8 | 441 | if (dm_list_empty(&pv->segments)) { |
6c4f65fe | 442 | ret = process_single_pvseg(cmd, NULL, &_free_pv_segment, handle); |
c54a9405 AK |
443 | if (ret > ret_max) |
444 | ret_max = ret; | |
d66abfb8 MB |
445 | } else |
446 | dm_list_iterate_items(pvseg, &pv->segments) { | |
6c4f65fe | 447 | ret = process_single_pvseg(cmd, vg, pvseg, handle); |
d66abfb8 MB |
448 | if (ret > ret_max) |
449 | ret_max = ret; | |
450 | if (sigint_caught()) | |
451 | break; | |
452 | } | |
c54a9405 | 453 | |
223c62e7 AK |
454 | if (vg_name) |
455 | unlock_vg(cmd, vg_name); | |
043b1362 | 456 | if (!old_vg) |
077a6755 | 457 | release_vg(vg); |
223c62e7 | 458 | |
c54a9405 AK |
459 | return ret_max; |
460 | } | |
461 | ||
4c64ed4c AK |
462 | int process_each_segment_in_lv(struct cmd_context *cmd, |
463 | struct logical_volume *lv, | |
464 | void *handle, | |
6c4f65fe | 465 | process_single_seg_fn_t process_single_seg) |
4c64ed4c | 466 | { |
4c64ed4c | 467 | struct lv_segment *seg; |
3a30d1db | 468 | int ret_max = ECMD_PROCESSED; |
4c64ed4c AK |
469 | int ret; |
470 | ||
2c44337b | 471 | dm_list_iterate_items(seg, &lv->segments) { |
6c4f65fe | 472 | ret = process_single_seg(cmd, seg, handle); |
4c64ed4c AK |
473 | if (ret > ret_max) |
474 | ret_max = ret; | |
0e833522 | 475 | /* FIXME: logic for breaking command is not consistent */ |
7379c678 | 476 | if (sigint_caught()) |
0e833522 | 477 | return ECMD_FAILED; |
4c64ed4c AK |
478 | } |
479 | ||
480 | return ret_max; | |
481 | } | |
482 | ||
cf6dd251 | 483 | static int _process_one_vg(struct cmd_context *cmd, const char *vg_name, |
a5fe5a7c | 484 | const char *vgid, |
2c44337b | 485 | struct dm_list *tags, struct dm_list *arg_vgnames, |
13e8c7e4 | 486 | uint32_t flags, void *handle, int ret_max, |
6c4f65fe | 487 | process_single_vg_fn_t process_single_vg) |
cf6dd251 | 488 | { |
2ad07c07 ZK |
489 | struct dm_list cmd_vgs; |
490 | struct cmd_vg *cvl_vg; | |
cf6dd251 AK |
491 | int ret = 0; |
492 | ||
cf6dd251 | 493 | log_verbose("Finding volume group \"%s\"", vg_name); |
cf6dd251 | 494 | |
2ad07c07 ZK |
495 | dm_list_init(&cmd_vgs); |
496 | if (!(cvl_vg = cmd_vg_add(cmd->mem, &cmd_vgs, vg_name, vgid, flags))) | |
497 | return_0; | |
498 | ||
499 | for (;;) { | |
500 | /* FIXME: consistent handling of command break */ | |
501 | if (sigint_caught()) { | |
b51cd542 | 502 | ret = ECMD_FAILED; |
2ad07c07 ZK |
503 | break; |
504 | } | |
505 | if (!cmd_vg_read(cmd, &cmd_vgs)) | |
506 | /* Allow FAILED_INCONSISTENT through only for vgcfgrestore */ | |
507 | if (vg_read_error(cvl_vg->vg) && | |
508 | (!((flags & READ_ALLOW_INCONSISTENT) && | |
509 | (vg_read_error(cvl_vg->vg) == FAILED_INCONSISTENT)))) { | |
510 | ret = ECMD_FAILED; | |
511 | break; | |
512 | } | |
dc4d7417 | 513 | |
2ad07c07 ZK |
514 | if (!dm_list_empty(tags) && |
515 | /* Only process if a tag matches or it's on arg_vgnames */ | |
516 | !str_list_match_item(arg_vgnames, vg_name) && | |
eb82bd05 | 517 | !str_list_match_list(tags, &cvl_vg->vg->tags, NULL)) |
2ad07c07 ZK |
518 | break; |
519 | ||
520 | ret = process_single_vg(cmd, vg_name, cvl_vg->vg, handle); | |
521 | ||
522 | if (vg_read_error(cvl_vg->vg)) /* FAILED_INCONSISTENT */ | |
523 | break; | |
524 | ||
525 | if (!cvl_vg->vg->cmd_missing_vgs) | |
526 | break; | |
527 | ||
2b82bd79 | 528 | free_cmd_vgs(&cmd_vgs); |
66086ce9 MB |
529 | } |
530 | ||
2b82bd79 | 531 | free_cmd_vgs(&cmd_vgs); |
cf6dd251 | 532 | |
2ad07c07 | 533 | return (ret > ret_max) ? ret : ret_max; |
cf6dd251 AK |
534 | } |
535 | ||
6fda126d | 536 | int process_each_vg(struct cmd_context *cmd, int argc, char **argv, |
13e8c7e4 | 537 | uint32_t flags, void *handle, |
6c4f65fe | 538 | process_single_vg_fn_t process_single_vg) |
25d42d50 AK |
539 | { |
540 | int opt = 0; | |
3a30d1db | 541 | int ret_max = ECMD_PROCESSED; |
25d42d50 | 542 | |
cf6dd251 | 543 | struct str_list *sl; |
2c44337b AK |
544 | struct dm_list *vgnames, *vgids; |
545 | struct dm_list arg_vgnames, tags; | |
25d42d50 | 546 | |
a5fe5a7c | 547 | const char *vg_name, *vgid; |
7d0e6e80 | 548 | |
2c44337b AK |
549 | dm_list_init(&tags); |
550 | dm_list_init(&arg_vgnames); | |
cf6dd251 | 551 | |
25d42d50 AK |
552 | if (argc) { |
553 | log_verbose("Using volume group(s) on command line"); | |
cf6dd251 | 554 | |
7d0e6e80 AK |
555 | for (; opt < argc; opt++) { |
556 | vg_name = argv[opt]; | |
cf6dd251 | 557 | if (*vg_name == '@') { |
10955b82 | 558 | if (!validate_tag(vg_name + 1)) { |
cf6dd251 AK |
559 | log_error("Skipping invalid tag %s", |
560 | vg_name); | |
b68cc099 AK |
561 | if (ret_max < EINVALID_CMD_LINE) |
562 | ret_max = EINVALID_CMD_LINE; | |
cf6dd251 AK |
563 | continue; |
564 | } | |
565 | if (!str_list_add(cmd->mem, &tags, | |
2262b320 | 566 | dm_pool_strdup(cmd->mem, |
cf6dd251 AK |
567 | vg_name + 1))) { |
568 | log_error("strlist allocation failed"); | |
569 | return ECMD_FAILED; | |
570 | } | |
571 | continue; | |
572 | } | |
573 | ||
9397354a | 574 | vg_name = skip_dev_dir(cmd, vg_name, NULL); |
25b73380 AK |
575 | if (strchr(vg_name, '/')) { |
576 | log_error("Invalid volume group name: %s", | |
577 | vg_name); | |
b68cc099 AK |
578 | if (ret_max < EINVALID_CMD_LINE) |
579 | ret_max = EINVALID_CMD_LINE; | |
25b73380 AK |
580 | continue; |
581 | } | |
cf6dd251 | 582 | if (!str_list_add(cmd->mem, &arg_vgnames, |
2262b320 | 583 | dm_pool_strdup(cmd->mem, vg_name))) { |
cf6dd251 AK |
584 | log_error("strlist allocation failed"); |
585 | return ECMD_FAILED; | |
7d0e6e80 | 586 | } |
7d0e6e80 | 587 | } |
cf6dd251 AK |
588 | |
589 | vgnames = &arg_vgnames; | |
590 | } | |
591 | ||
2c44337b | 592 | if (!argc || !dm_list_empty(&tags)) { |
93ea3969 | 593 | log_verbose("Finding all volume groups"); |
dc9ef7a0 AK |
594 | if (!lvmetad_vg_list_to_lvmcache(cmd)) |
595 | stack; | |
38220f9f | 596 | if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) { |
25d42d50 | 597 | log_error("No volume groups found"); |
29e94d95 | 598 | return ret_max; |
25d42d50 | 599 | } |
2c44337b | 600 | dm_list_iterate_items(sl, vgids) { |
a5fe5a7c | 601 | vgid = sl->str; |
8e5f7cf3 | 602 | if (!(vgid) || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) |
a5fe5a7c AK |
603 | continue; |
604 | ret_max = _process_one_vg(cmd, vg_name, vgid, &tags, | |
605 | &arg_vgnames, | |
13e8c7e4 | 606 | flags, handle, |
6c4f65fe | 607 | ret_max, process_single_vg); |
7379c678 PR |
608 | if (sigint_caught()) |
609 | return ret_max; | |
a5fe5a7c AK |
610 | } |
611 | } else { | |
2c44337b | 612 | dm_list_iterate_items(sl, vgnames) { |
a5fe5a7c | 613 | vg_name = sl->str; |
d38bf361 | 614 | if (is_orphan_vg(vg_name)) |
a5fe5a7c AK |
615 | continue; /* FIXME Unnecessary? */ |
616 | ret_max = _process_one_vg(cmd, vg_name, NULL, &tags, | |
617 | &arg_vgnames, | |
13e8c7e4 | 618 | flags, handle, |
6c4f65fe | 619 | ret_max, process_single_vg); |
7379c678 PR |
620 | if (sigint_caught()) |
621 | return ret_max; | |
a5fe5a7c | 622 | } |
25d42d50 AK |
623 | } |
624 | ||
625 | return ret_max; | |
626 | } | |
677a06d5 | 627 | |
60274aba | 628 | int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, |
2c44337b | 629 | const struct dm_list *tags, void *handle, |
6c4f65fe | 630 | process_single_pv_fn_t process_single_pv) |
7f3859bb | 631 | { |
3a30d1db | 632 | int ret_max = ECMD_PROCESSED; |
7f3859bb | 633 | int ret = 0; |
f2b7349e | 634 | struct pv_list *pvl; |
7f3859bb | 635 | |
2c44337b AK |
636 | dm_list_iterate_items(pvl, &vg->pvs) { |
637 | if (tags && !dm_list_empty(tags) && | |
eb82bd05 | 638 | !str_list_match_list(tags, &pvl->pv->tags, NULL)) { |
cf6dd251 | 639 | continue; |
1a51586c | 640 | } |
6c4f65fe | 641 | if ((ret = process_single_pv(cmd, vg, pvl->pv, handle)) > ret_max) |
cc282870 | 642 | ret_max = ret; |
7379c678 PR |
643 | if (sigint_caught()) |
644 | return ret_max; | |
cf6dd251 | 645 | } |
cc282870 JT |
646 | |
647 | return ret_max; | |
7f3859bb AK |
648 | } |
649 | ||
c29d2465 | 650 | static int _process_all_devs(struct cmd_context *cmd, void *handle, |
6c4f65fe | 651 | process_single_pv_fn_t process_single_pv) |
c29d2465 AK |
652 | { |
653 | struct physical_volume *pv; | |
654 | struct physical_volume pv_dummy; | |
655 | struct dev_iter *iter; | |
656 | struct device *dev; | |
657 | ||
3a30d1db | 658 | int ret_max = ECMD_PROCESSED; |
c29d2465 AK |
659 | int ret = 0; |
660 | ||
728074ac | 661 | if (!scan_vgs_for_pvs(cmd, 1)) { |
814d9d5b AK |
662 | stack; |
663 | return ECMD_FAILED; | |
664 | } | |
665 | ||
b9565b40 | 666 | if (!(iter = dev_iter_create(cmd->filter, 1))) { |
c29d2465 AK |
667 | log_error("dev_iter creation failed"); |
668 | return ECMD_FAILED; | |
669 | } | |
670 | ||
671 | while ((dev = dev_iter_get(iter))) { | |
3cac20f8 | 672 | if (!(pv = pv_read(cmd, dev_name(dev), 0, 0))) { |
c29d2465 | 673 | memset(&pv_dummy, 0, sizeof(pv_dummy)); |
2c44337b AK |
674 | dm_list_init(&pv_dummy.tags); |
675 | dm_list_init(&pv_dummy.segments); | |
c29d2465 AK |
676 | pv_dummy.dev = dev; |
677 | pv_dummy.fmt = NULL; | |
678 | pv = &pv_dummy; | |
679 | } | |
6c4f65fe | 680 | ret = process_single_pv(cmd, NULL, pv, handle); |
84f48499 PR |
681 | |
682 | free_pv_fid(pv); | |
683 | ||
c29d2465 AK |
684 | if (ret > ret_max) |
685 | ret_max = ret; | |
7379c678 | 686 | if (sigint_caught()) |
fb697f28 | 687 | break; |
c29d2465 AK |
688 | } |
689 | ||
690 | dev_iter_destroy(iter); | |
691 | ||
692 | return ret_max; | |
693 | } | |
694 | ||
772cac09 MB |
695 | /* |
696 | * If the lock_type is LCK_VG_READ (used only in reporting commands), | |
697 | * we lock VG_GLOBAL to enable use of metadata cache. | |
698 | * This can pause alongide pvscan or vgscan process for a while. | |
699 | */ | |
6fda126d | 700 | int process_each_pv(struct cmd_context *cmd, int argc, char **argv, |
21a98eda | 701 | struct volume_group *vg, uint32_t flags, |
ea0cdd28 | 702 | int scan_label_only, void *handle, |
6c4f65fe | 703 | process_single_pv_fn_t process_single_pv) |
6e91eeef AK |
704 | { |
705 | int opt = 0; | |
3a30d1db | 706 | int ret_max = ECMD_PROCESSED; |
6e91eeef | 707 | int ret = 0; |
21a98eda | 708 | int lock_global = !(flags & READ_WITHOUT_LOCK) && !(flags & READ_FOR_UPDATE); |
6e91eeef | 709 | |
e586401e | 710 | struct pv_list *pvl; |
4c64ed4c | 711 | struct physical_volume *pv; |
2c44337b AK |
712 | struct dm_list *pvslist, *vgnames; |
713 | struct dm_list tags; | |
cf6dd251 | 714 | struct str_list *sll; |
bad35c65 | 715 | char *at_sign, *tagname; |
fb3226a3 | 716 | int scanned = 0; |
cf6dd251 | 717 | |
2c44337b | 718 | dm_list_init(&tags); |
6e91eeef | 719 | |
3c0cfa8f | 720 | if (lock_global && !lock_vol(cmd, VG_GLOBAL, LCK_VG_READ)) { |
772cac09 MB |
721 | log_error("Unable to obtain global lock."); |
722 | return ECMD_FAILED; | |
723 | } | |
724 | ||
6e91eeef AK |
725 | if (argc) { |
726 | log_verbose("Using physical volume(s) on command line"); | |
727 | for (; opt < argc; opt++) { | |
e59e2f7c | 728 | dm_unescape_colons_and_at_signs(argv[opt], NULL, &at_sign); |
bad35c65 PR |
729 | if (at_sign && (at_sign == argv[opt])) { |
730 | tagname = at_sign + 1; | |
cf6dd251 | 731 | |
10955b82 | 732 | if (!validate_tag(tagname)) { |
cf6dd251 AK |
733 | log_error("Skipping invalid tag %s", |
734 | tagname); | |
e3adcd79 AK |
735 | if (ret_max < EINVALID_CMD_LINE) |
736 | ret_max = EINVALID_CMD_LINE; | |
cf6dd251 AK |
737 | continue; |
738 | } | |
739 | if (!str_list_add(cmd->mem, &tags, | |
2262b320 | 740 | dm_pool_strdup(cmd->mem, |
cf6dd251 AK |
741 | tagname))) { |
742 | log_error("strlist allocation failed"); | |
772cac09 | 743 | goto bad; |
cf6dd251 AK |
744 | } |
745 | continue; | |
746 | } | |
4c64ed4c AK |
747 | if (vg) { |
748 | if (!(pvl = find_pv_in_vg(vg, argv[opt]))) { | |
749 | log_error("Physical Volume \"%s\" not " | |
750 | "found in Volume Group " | |
751 | "\"%s\"", argv[opt], | |
752 | vg->name); | |
cfb7bfc7 | 753 | ret_max = ECMD_FAILED; |
4c64ed4c AK |
754 | continue; |
755 | } | |
756 | pv = pvl->pv; | |
757 | } else { | |
3cac20f8 | 758 | if (!(pv = pv_read(cmd, argv[opt], |
30581623 | 759 | 1, scan_label_only))) { |
4c64ed4c AK |
760 | log_error("Failed to read physical " |
761 | "volume \"%s\"", argv[opt]); | |
cfb7bfc7 | 762 | ret_max = ECMD_FAILED; |
4c64ed4c AK |
763 | continue; |
764 | } | |
fb3226a3 | 765 | |
67cdbd7e AK |
766 | /* |
767 | * If a PV has no MDAs it may appear to be an | |
fb3226a3 AK |
768 | * orphan until the metadata is read off |
769 | * another PV in the same VG. Detecting this | |
770 | * means checking every VG by scanning every | |
771 | * PV on the system. | |
67cdbd7e | 772 | */ |
15fdc8d3 | 773 | if (!scanned && is_orphan(pv) && |
30581623 PR |
774 | !dm_list_size(&pv->fid->metadata_areas_in_use) && |
775 | !dm_list_size(&pv->fid->metadata_areas_ignored)) { | |
ea0cdd28 | 776 | if (!scan_label_only && |
728074ac | 777 | !scan_vgs_for_pvs(cmd, 1)) { |
fb3226a3 AK |
778 | stack; |
779 | ret_max = ECMD_FAILED; | |
780 | continue; | |
781 | } | |
782 | scanned = 1; | |
84f48499 | 783 | free_pv_fid(pv); |
fb3226a3 | 784 | if (!(pv = pv_read(cmd, argv[opt], |
3cac20f8 | 785 | 1, |
7b1c853b | 786 | scan_label_only))) { |
fb3226a3 AK |
787 | log_error("Failed to read " |
788 | "physical volume " | |
789 | "\"%s\"", argv[opt]); | |
790 | ret_max = ECMD_FAILED; | |
791 | continue; | |
792 | } | |
793 | } | |
6e91eeef | 794 | } |
4c64ed4c | 795 | |
6c4f65fe | 796 | ret = process_single_pv(cmd, vg, pv, handle); |
84f48499 PR |
797 | |
798 | /* | |
799 | * Free PV only if we called pv_read before, | |
800 | * otherwise the PV structure is part of the VG. | |
801 | */ | |
802 | if (!vg) | |
803 | free_pv_fid(pv); | |
804 | ||
6e91eeef AK |
805 | if (ret > ret_max) |
806 | ret_max = ret; | |
7379c678 | 807 | if (sigint_caught()) |
772cac09 | 808 | goto out; |
6e91eeef | 809 | } |
38220f9f | 810 | if (!dm_list_empty(&tags) && (vgnames = get_vgnames(cmd, 1)) && |
2c44337b AK |
811 | !dm_list_empty(vgnames)) { |
812 | dm_list_iterate_items(sll, vgnames) { | |
21a98eda PR |
813 | vg = vg_read(cmd, sll->str, NULL, flags); |
814 | if (vg_read_error(vg)) { | |
1b25b6e0 | 815 | ret_max = ECMD_FAILED; |
077a6755 | 816 | release_vg(vg); |
651ff9b3 | 817 | stack; |
223c62e7 AK |
818 | continue; |
819 | } | |
dc4d7417 | 820 | |
cf6dd251 AK |
821 | ret = process_each_pv_in_vg(cmd, vg, &tags, |
822 | handle, | |
6c4f65fe | 823 | process_single_pv); |
223c62e7 | 824 | |
077a6755 | 825 | unlock_and_release_vg(cmd, vg, sll->str); |
223c62e7 | 826 | |
cf6dd251 AK |
827 | if (ret > ret_max) |
828 | ret_max = ret; | |
7379c678 | 829 | if (sigint_caught()) |
772cac09 | 830 | goto out; |
cf6dd251 AK |
831 | } |
832 | } | |
6e91eeef | 833 | } else { |
4c64ed4c AK |
834 | if (vg) { |
835 | log_verbose("Using all physical volume(s) in " | |
836 | "volume group"); | |
cf6dd251 | 837 | ret = process_each_pv_in_vg(cmd, vg, NULL, handle, |
6c4f65fe | 838 | process_single_pv); |
cfb7bfc7 AK |
839 | if (ret > ret_max) |
840 | ret_max = ret; | |
7379c678 | 841 | if (sigint_caught()) |
772cac09 | 842 | goto out; |
c29d2465 | 843 | } else if (arg_count(cmd, all_ARG)) { |
6c4f65fe | 844 | ret = _process_all_devs(cmd, handle, process_single_pv); |
c29d2465 AK |
845 | if (ret > ret_max) |
846 | ret_max = ret; | |
7379c678 | 847 | if (sigint_caught()) |
772cac09 | 848 | goto out; |
4c64ed4c AK |
849 | } else { |
850 | log_verbose("Scanning for physical volume names"); | |
772cac09 | 851 | |
dae08226 | 852 | lvmcache_seed_infos_from_lvmetad(cmd); |
8ef2b021 | 853 | if (!(pvslist = get_pvs(cmd))) |
772cac09 | 854 | goto bad; |
4c64ed4c | 855 | |
2c44337b | 856 | dm_list_iterate_items(pvl, pvslist) { |
6c4f65fe | 857 | ret = process_single_pv(cmd, NULL, pvl->pv, |
f2b7349e | 858 | handle); |
84f48499 | 859 | free_pv_fid(pvl->pv); |
4c64ed4c AK |
860 | if (ret > ret_max) |
861 | ret_max = ret; | |
7379c678 | 862 | if (sigint_caught()) |
772cac09 | 863 | goto out; |
4c64ed4c AK |
864 | } |
865 | } | |
6e91eeef | 866 | } |
772cac09 MB |
867 | out: |
868 | if (lock_global) | |
869 | unlock_vg(cmd, VG_GLOBAL); | |
6e91eeef | 870 | return ret_max; |
772cac09 MB |
871 | bad: |
872 | if (lock_global) | |
873 | unlock_vg(cmd, VG_GLOBAL); | |
874 | ||
875 | return ECMD_FAILED; | |
6e91eeef AK |
876 | } |
877 | ||
68e4adb5 AK |
878 | /* |
879 | * Determine volume group name from a logical volume name | |
880 | */ | |
8ef2b021 | 881 | const char *extract_vgname(struct cmd_context *cmd, const char *lv_name) |
9b7742bb | 882 | { |
8ef2b021 | 883 | const char *vg_name = lv_name; |
642c2e96 | 884 | char *st; |
25b73380 | 885 | char *dev_dir = cmd->dev_dir; |
cfd658da AK |
886 | |
887 | /* Path supplied? */ | |
642c2e96 | 888 | if (vg_name && strchr(vg_name, '/')) { |
d9bc7ffe | 889 | /* Strip dev_dir (optional) */ |
914c9723 AK |
890 | if (*vg_name == '/') { |
891 | while (*vg_name == '/') | |
892 | vg_name++; | |
893 | vg_name--; | |
894 | } | |
895 | if (!strncmp(vg_name, dev_dir, strlen(dev_dir))) { | |
27723780 | 896 | vg_name += strlen(dev_dir); |
914c9723 AK |
897 | while (*vg_name == '/') |
898 | vg_name++; | |
899 | } | |
900 | if (*vg_name == '/') { | |
901 | log_error("\"%s\": Invalid path for Logical " | |
902 | "Volume", lv_name); | |
903 | return 0; | |
904 | } | |
cf6dd251 | 905 | |
914c9723 AK |
906 | /* Require exactly one set of consecutive slashes */ |
907 | if ((st = strchr(vg_name, '/'))) | |
908 | while (*st == '/') | |
909 | st++; | |
cfd658da | 910 | |
0775e806 | 911 | if (!st || strchr(st, '/')) { |
08907484 | 912 | log_error("\"%s\": Invalid path for Logical Volume", |
9b7742bb | 913 | lv_name); |
cfd658da AK |
914 | return 0; |
915 | } | |
916 | ||
2262b320 | 917 | vg_name = dm_pool_strdup(cmd->mem, vg_name); |
cfd658da AK |
918 | if (!vg_name) { |
919 | log_error("Allocation of vg_name failed"); | |
920 | return 0; | |
921 | } | |
922 | ||
923 | *strchr(vg_name, '/') = '\0'; | |
924 | return vg_name; | |
925 | } | |
642c2e96 | 926 | |
25b73380 | 927 | if (!(vg_name = default_vgname(cmd))) { |
642c2e96 | 928 | if (lv_name) |
08907484 | 929 | log_error("Path required for Logical Volume \"%s\"", |
9b7742bb | 930 | lv_name); |
642c2e96 AK |
931 | return 0; |
932 | } | |
9b7742bb | 933 | |
642c2e96 AK |
934 | return vg_name; |
935 | } | |
936 | ||
68e4adb5 AK |
937 | /* |
938 | * Extract default volume group name from environment | |
939 | */ | |
25b73380 | 940 | char *default_vgname(struct cmd_context *cmd) |
642c2e96 | 941 | { |
aec21154 | 942 | const char *vg_path; |
642c2e96 | 943 | |
cfd658da | 944 | /* Take default VG from environment? */ |
9b7742bb | 945 | vg_path = getenv("LVM_VG_NAME"); |
642c2e96 | 946 | if (!vg_path) |
cfd658da | 947 | return 0; |
cfd658da | 948 | |
9397354a | 949 | vg_path = skip_dev_dir(cmd, vg_path, NULL); |
cfd658da AK |
950 | |
951 | if (strchr(vg_path, '/')) { | |
08907484 HM |
952 | log_error("Environment Volume Group in LVM_VG_NAME invalid: " |
953 | "\"%s\"", vg_path); | |
cfd658da AK |
954 | return 0; |
955 | } | |
956 | ||
2262b320 | 957 | return dm_pool_strdup(cmd->mem, vg_path); |
cfd658da | 958 | } |
cc282870 | 959 | |
68e4adb5 AK |
960 | /* |
961 | * Process physical extent range specifiers | |
962 | */ | |
9766c3c9 | 963 | static int _add_pe_range(struct dm_pool *mem, const char *pvname, |
2c44337b | 964 | struct dm_list *pe_ranges, uint32_t start, uint32_t count) |
b8c919b4 | 965 | { |
eabaa339 | 966 | struct pe_range *per; |
b8c919b4 | 967 | |
9766c3c9 AK |
968 | log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32 |
969 | " on %s", start, count, pvname); | |
b8c919b4 AK |
970 | |
971 | /* Ensure no overlap with existing areas */ | |
2c44337b | 972 | dm_list_iterate_items(per, pe_ranges) { |
eabaa339 AK |
973 | if (((start < per->start) && (start + count - 1 >= per->start)) |
974 | || ((start >= per->start) && | |
975 | (per->start + per->count - 1) >= start)) { | |
9766c3c9 AK |
976 | log_error("Overlapping PE ranges specified (%" PRIu32 |
977 | "-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")" | |
978 | " on %s", | |
eabaa339 | 979 | start, start + count - 1, per->start, |
9766c3c9 | 980 | per->start + per->count - 1, pvname); |
b8c919b4 AK |
981 | return 0; |
982 | } | |
983 | } | |
984 | ||
2262b320 | 985 | if (!(per = dm_pool_alloc(mem, sizeof(*per)))) { |
b8c919b4 AK |
986 | log_error("Allocation of list failed"); |
987 | return 0; | |
988 | } | |
989 | ||
eabaa339 AK |
990 | per->start = start; |
991 | per->count = count; | |
2c44337b | 992 | dm_list_add(pe_ranges, &per->list); |
b8c919b4 AK |
993 | |
994 | return 1; | |
995 | } | |
996 | ||
3851b7a3 JM |
997 | static int xstrtouint32(const char *s, char **p, int base, uint32_t *result) |
998 | { | |
999 | unsigned long ul; | |
1000 | ||
1001 | errno = 0; | |
1002 | ul = strtoul(s, p, base); | |
1003 | if (errno || *p == s || (uint32_t) ul != ul) | |
1004 | return -1; | |
1005 | *result = ul; | |
1006 | return 0; | |
1007 | } | |
1008 | ||
2c44337b | 1009 | static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges, |
9766c3c9 | 1010 | const char *pvname, uint32_t size) |
b8c919b4 AK |
1011 | { |
1012 | char *endptr; | |
1013 | uint32_t start, end; | |
1014 | ||
1015 | /* Default to whole PV */ | |
1016 | if (!c) { | |
c51b9fff AK |
1017 | if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size)) |
1018 | return_0; | |
b8c919b4 AK |
1019 | return 1; |
1020 | } | |
1021 | ||
1022 | while (*c) { | |
1023 | if (*c != ':') | |
1024 | goto error; | |
1025 | ||
1026 | c++; | |
1027 | ||
1028 | /* Disallow :: and :\0 */ | |
1029 | if (*c == ':' || !*c) | |
1030 | goto error; | |
1031 | ||
1032 | /* Default to whole range */ | |
1033 | start = UINT32_C(0); | |
1034 | end = size - 1; | |
1035 | ||
1036 | /* Start extent given? */ | |
1037 | if (isdigit(*c)) { | |
3851b7a3 | 1038 | if (xstrtouint32(c, &endptr, 10, &start)) |
b8c919b4 AK |
1039 | goto error; |
1040 | c = endptr; | |
1041 | /* Just one number given? */ | |
1042 | if (!*c || *c == ':') | |
1043 | end = start; | |
1044 | } | |
1045 | /* Range? */ | |
1046 | if (*c == '-') { | |
1047 | c++; | |
1048 | if (isdigit(*c)) { | |
3851b7a3 | 1049 | if (xstrtouint32(c, &endptr, 10, &end)) |
b8c919b4 AK |
1050 | goto error; |
1051 | c = endptr; | |
1052 | } | |
1053 | } | |
1054 | if (*c && *c != ':') | |
1055 | goto error; | |
1056 | ||
1057 | if ((start > end) || (end > size - 1)) { | |
1058 | log_error("PE range error: start extent %" PRIu32 " to " | |
1059 | "end extent %" PRIu32, start, end); | |
1060 | return 0; | |
1061 | } | |
1062 | ||
c51b9fff AK |
1063 | if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1)) |
1064 | return_0; | |
b8c919b4 AK |
1065 | |
1066 | } | |
1067 | ||
1068 | return 1; | |
1069 | ||
1070 | error: | |
1071 | log_error("Physical extent parsing error at %s", c); | |
1072 | return 0; | |
1073 | } | |
1074 | ||
9766c3c9 | 1075 | static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl, |
2c44337b | 1076 | char *colon, int allocatable_only, struct dm_list *r) |
cf6dd251 AK |
1077 | { |
1078 | const char *pvname; | |
9766c3c9 | 1079 | struct pv_list *new_pvl = NULL, *pvl2; |
2c44337b | 1080 | struct dm_list *pe_ranges; |
cf6dd251 | 1081 | |
1b8de4cb | 1082 | pvname = pv_dev_name(pvl->pv); |
eabaa339 | 1083 | if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) { |
cf6dd251 | 1084 | log_error("Physical volume %s not allocatable", pvname); |
9766c3c9 | 1085 | return 1; |
cf6dd251 AK |
1086 | } |
1087 | ||
770dc81b | 1088 | if (allocatable_only && is_missing_pv(pvl->pv)) { |
54120cb2 PR |
1089 | log_error("Physical volume %s is missing", pvname); |
1090 | return 1; | |
1091 | } | |
1092 | ||
eabaa339 AK |
1093 | if (allocatable_only && |
1094 | (pvl->pv->pe_count == pvl->pv->pe_alloc_count)) { | |
b8f47d5f | 1095 | log_error("No free extents on physical volume \"%s\"", pvname); |
9766c3c9 | 1096 | return 1; |
cf6dd251 AK |
1097 | } |
1098 | ||
2c44337b | 1099 | dm_list_iterate_items(pvl2, r) |
9766c3c9 AK |
1100 | if (pvl->pv->dev == pvl2->pv->dev) { |
1101 | new_pvl = pvl2; | |
1102 | break; | |
1103 | } | |
21e094d9 | 1104 | |
9766c3c9 AK |
1105 | if (!new_pvl) { |
1106 | if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) { | |
b8f47d5f | 1107 | log_error("Unable to allocate physical volume list."); |
9766c3c9 AK |
1108 | return 0; |
1109 | } | |
cf6dd251 | 1110 | |
9766c3c9 | 1111 | memcpy(new_pvl, pvl, sizeof(*new_pvl)); |
cf6dd251 | 1112 | |
9766c3c9 AK |
1113 | if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) { |
1114 | log_error("Allocation of pe_ranges list failed"); | |
1115 | return 0; | |
1116 | } | |
2c44337b | 1117 | dm_list_init(pe_ranges); |
9766c3c9 | 1118 | new_pvl->pe_ranges = pe_ranges; |
2c44337b | 1119 | dm_list_add(r, &new_pvl->list); |
cf6dd251 | 1120 | } |
cf6dd251 | 1121 | |
eabaa339 | 1122 | /* Determine selected physical extents */ |
1b8de4cb | 1123 | if (!_parse_pes(mem, colon, new_pvl->pe_ranges, pv_dev_name(pvl->pv), |
c51b9fff AK |
1124 | pvl->pv->pe_count)) |
1125 | return_0; | |
cf6dd251 | 1126 | |
9766c3c9 | 1127 | return 1; |
cf6dd251 AK |
1128 | } |
1129 | ||
2c44337b | 1130 | struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc, |
eabaa339 | 1131 | char **argv, int allocatable_only) |
cc282870 | 1132 | { |
2c44337b | 1133 | struct dm_list *r; |
cf6dd251 | 1134 | struct pv_list *pvl; |
2c44337b | 1135 | struct dm_list tags, arg_pvnames; |
bad35c65 PR |
1136 | char *pvname = NULL; |
1137 | char *colon, *at_sign, *tagname; | |
cc282870 JT |
1138 | int i; |
1139 | ||
1140 | /* Build up list of PVs */ | |
2262b320 | 1141 | if (!(r = dm_pool_alloc(mem, sizeof(*r)))) { |
cc282870 JT |
1142 | log_error("Allocation of list failed"); |
1143 | return NULL; | |
1144 | } | |
2c44337b | 1145 | dm_list_init(r); |
cc282870 | 1146 | |
2c44337b AK |
1147 | dm_list_init(&tags); |
1148 | dm_list_init(&arg_pvnames); | |
cf6dd251 | 1149 | |
cc282870 | 1150 | for (i = 0; i < argc; i++) { |
e59e2f7c | 1151 | dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign); |
bad35c65 PR |
1152 | |
1153 | if (at_sign && (at_sign == argv[i])) { | |
1154 | tagname = at_sign + 1; | |
10955b82 | 1155 | if (!validate_tag(tagname)) { |
cf6dd251 AK |
1156 | log_error("Skipping invalid tag %s", tagname); |
1157 | continue; | |
1158 | } | |
2c44337b | 1159 | dm_list_iterate_items(pvl, &vg->pvs) { |
cf6dd251 | 1160 | if (str_list_match_item(&pvl->pv->tags, |
63aead84 | 1161 | tagname)) { |
9766c3c9 AK |
1162 | if (!_create_pv_entry(mem, pvl, NULL, |
1163 | allocatable_only, | |
c51b9fff AK |
1164 | r)) |
1165 | return_NULL; | |
cf6dd251 | 1166 | } |
b8c919b4 | 1167 | } |
cc282870 | 1168 | continue; |
cc282870 JT |
1169 | } |
1170 | ||
cf6dd251 | 1171 | pvname = argv[i]; |
b8c919b4 | 1172 | |
bad35c65 PR |
1173 | if (colon && !(pvname = dm_pool_strndup(mem, pvname, |
1174 | (unsigned) (colon - pvname)))) { | |
1175 | log_error("Failed to clone PV name"); | |
1176 | return NULL; | |
b8c919b4 | 1177 | } |
b8c919b4 | 1178 | |
1a51586c | 1179 | if (!(pvl = find_pv_in_vg(vg, pvname))) { |
b8f47d5f AK |
1180 | log_error("Physical Volume \"%s\" not found in " |
1181 | "Volume Group \"%s\"", pvname, vg->name); | |
1a51586c AK |
1182 | return NULL; |
1183 | } | |
c51b9fff AK |
1184 | if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r)) |
1185 | return_NULL; | |
cc282870 JT |
1186 | } |
1187 | ||
2c44337b | 1188 | if (dm_list_empty(r)) |
cf6dd251 AK |
1189 | log_error("No specified PVs have space available"); |
1190 | ||
2c44337b | 1191 | return dm_list_empty(r) ? NULL : r; |
cc282870 | 1192 | } |
b8c919b4 | 1193 | |
2c44337b | 1194 | struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl) |
b8c919b4 | 1195 | { |
2c44337b | 1196 | struct dm_list *r; |
b8c919b4 AK |
1197 | struct pv_list *pvl, *new_pvl; |
1198 | ||
1199 | /* Build up list of PVs */ | |
2262b320 | 1200 | if (!(r = dm_pool_alloc(mem, sizeof(*r)))) { |
b8c919b4 AK |
1201 | log_error("Allocation of list failed"); |
1202 | return NULL; | |
1203 | } | |
2c44337b | 1204 | dm_list_init(r); |
b8c919b4 | 1205 | |
2c44337b | 1206 | dm_list_iterate_items(pvl, pvsl) { |
2262b320 | 1207 | if (!(new_pvl = dm_pool_zalloc(mem, sizeof(*new_pvl)))) { |
b8c919b4 AK |
1208 | log_error("Unable to allocate physical volume list."); |
1209 | return NULL; | |
1210 | } | |
1211 | ||
1212 | memcpy(new_pvl, pvl, sizeof(*new_pvl)); | |
2c44337b | 1213 | dm_list_add(r, &new_pvl->list); |
b8c919b4 AK |
1214 | } |
1215 | ||
1216 | return r; | |
1217 | } | |
1a9ea74d | 1218 | |
c6ea6bf5 DW |
1219 | void vgcreate_params_set_defaults(struct vgcreate_params *vp_def, |
1220 | struct volume_group *vg) | |
1221 | { | |
1222 | if (vg) { | |
1223 | vp_def->vg_name = NULL; | |
1224 | vp_def->extent_size = vg->extent_size; | |
1225 | vp_def->max_pv = vg->max_pv; | |
1226 | vp_def->max_lv = vg->max_lv; | |
1227 | vp_def->alloc = vg->alloc; | |
1228 | vp_def->clustered = vg_is_clustered(vg); | |
12eadbab | 1229 | vp_def->vgmetadatacopies = vg->mda_copies; |
c6ea6bf5 DW |
1230 | } else { |
1231 | vp_def->vg_name = NULL; | |
1232 | vp_def->extent_size = DEFAULT_EXTENT_SIZE * 2; | |
1233 | vp_def->max_pv = DEFAULT_MAX_PV; | |
1234 | vp_def->max_lv = DEFAULT_MAX_LV; | |
1235 | vp_def->alloc = DEFAULT_ALLOC_POLICY; | |
1236 | vp_def->clustered = DEFAULT_CLUSTERED; | |
12eadbab | 1237 | vp_def->vgmetadatacopies = DEFAULT_VGMETADATACOPIES; |
c6ea6bf5 DW |
1238 | } |
1239 | } | |
1240 | ||
b8daca85 | 1241 | /* |
2a924b3e | 1242 | * Set members of struct vgcreate_params from cmdline arguments. |
b8daca85 DW |
1243 | * Do preliminary validation with arg_*() interface. |
1244 | * Further, more generic validation is done in validate_vgcreate_params(). | |
d865615e | 1245 | * This function is to remain in tools directory. |
b8daca85 | 1246 | */ |
2a924b3e DW |
1247 | int vgcreate_params_set_from_args(struct cmd_context *cmd, |
1248 | struct vgcreate_params *vp_new, | |
1249 | struct vgcreate_params *vp_def) | |
b8daca85 | 1250 | { |
2a924b3e | 1251 | vp_new->vg_name = skip_dev_dir(cmd, vp_def->vg_name, NULL); |
8868a4ff DW |
1252 | vp_new->max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG, |
1253 | vp_def->max_lv); | |
1254 | vp_new->max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, | |
1255 | vp_def->max_pv); | |
f3c17731 | 1256 | vp_new->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, vp_def->alloc); |
b8daca85 DW |
1257 | |
1258 | /* Units of 512-byte sectors */ | |
8868a4ff DW |
1259 | vp_new->extent_size = |
1260 | arg_uint_value(cmd, physicalextentsize_ARG, vp_def->extent_size); | |
b8daca85 DW |
1261 | |
1262 | if (arg_count(cmd, clustered_ARG)) | |
67cdbd7e | 1263 | vp_new->clustered = |
8868a4ff DW |
1264 | !strcmp(arg_str_value(cmd, clustered_ARG, |
1265 | vp_def->clustered ? "y":"n"), "y"); | |
b8daca85 DW |
1266 | else |
1267 | /* Default depends on current locking type */ | |
8868a4ff | 1268 | vp_new->clustered = locking_is_clustered(); |
b8daca85 | 1269 | |
fbf6b89a | 1270 | if (arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) { |
b8daca85 DW |
1271 | log_error("Physical extent size may not be negative"); |
1272 | return 1; | |
1273 | } | |
1274 | ||
be3510b2 MB |
1275 | if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) { |
1276 | log_error("Physical extent size cannot be larger than %s", | |
1277 | display_size(cmd, (uint64_t) MAX_EXTENT_SIZE)); | |
1278 | return 1; | |
1279 | } | |
1280 | ||
fbf6b89a | 1281 | if (arg_sign_value(cmd, maxlogicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) { |
b8daca85 DW |
1282 | log_error("Max Logical Volumes may not be negative"); |
1283 | return 1; | |
1284 | } | |
1285 | ||
fbf6b89a | 1286 | if (arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) { |
b8daca85 DW |
1287 | log_error("Max Physical Volumes may not be negative"); |
1288 | return 1; | |
1289 | } | |
1290 | ||
9e111ef6 | 1291 | if (arg_count(cmd, metadatacopies_ARG)) { |
12eadbab | 1292 | vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, |
9e111ef6 DW |
1293 | DEFAULT_VGMETADATACOPIES); |
1294 | } else if (arg_count(cmd, vgmetadatacopies_ARG)) { | |
12eadbab | 1295 | vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG, |
9e111ef6 DW |
1296 | DEFAULT_VGMETADATACOPIES); |
1297 | } else { | |
12eadbab | 1298 | vp_new->vgmetadatacopies = find_config_tree_int(cmd, |
9e111ef6 DW |
1299 | "metadata/vgmetadatacopies", |
1300 | DEFAULT_VGMETADATACOPIES); | |
1301 | } | |
1302 | ||
b8daca85 DW |
1303 | return 0; |
1304 | } | |
3ad47d16 PR |
1305 | |
1306 | int lv_refresh(struct cmd_context *cmd, struct logical_volume *lv) | |
1307 | { | |
df13cf08 MS |
1308 | int r = 0; |
1309 | ||
31943693 MB |
1310 | if (!cmd->partial_activation && (lv->status & PARTIAL_LV)) { |
1311 | log_error("Refusing refresh of partial LV %s. Use --partial to override.", | |
1312 | lv->name); | |
1313 | goto out; | |
1314 | } | |
1315 | ||
df13cf08 MS |
1316 | r = suspend_lv(cmd, lv); |
1317 | if (!r) | |
1318 | goto_out; | |
1319 | ||
1320 | r = resume_lv(cmd, lv); | |
1321 | if (!r) | |
1322 | goto_out; | |
1323 | ||
df06d9ac MS |
1324 | /* |
1325 | * check if snapshot merge should be polled | |
1326 | * - unfortunately: even though the dev_manager will clear | |
1327 | * the lv's merge attributes if a merge is not possible; | |
1328 | * it is clearing a different instance of the lv (as | |
1329 | * retrieved with lv_from_lvid) | |
1330 | * - fortunately: polldaemon will immediately shutdown if the | |
1331 | * origin doesn't have a status with a snapshot percentage | |
1332 | */ | |
c79b4251 | 1333 | if (background_polling() && lv_is_origin(lv) && lv_is_merging_origin(lv)) |
df06d9ac MS |
1334 | lv_spawn_background_polling(cmd, lv); |
1335 | ||
df13cf08 MS |
1336 | out: |
1337 | return r; | |
3ad47d16 | 1338 | } |
da1ba4ed PR |
1339 | |
1340 | int vg_refresh_visible(struct cmd_context *cmd, struct volume_group *vg) | |
1341 | { | |
1342 | struct lv_list *lvl; | |
1343 | int r = 1; | |
21e094d9 | 1344 | |
41449383 ZK |
1345 | sigint_allow(); |
1346 | dm_list_iterate_items(lvl, &vg->lvs) { | |
1347 | if (sigint_caught()) | |
1348 | return_0; | |
1349 | ||
da1ba4ed PR |
1350 | if (lv_is_visible(lvl->lv)) |
1351 | if (!lv_refresh(cmd, lvl->lv)) | |
1352 | r = 0; | |
41449383 ZK |
1353 | } |
1354 | ||
1355 | sigint_restore(); | |
21e094d9 | 1356 | |
da1ba4ed PR |
1357 | return r; |
1358 | } | |
93bbc31c AK |
1359 | |
1360 | void lv_spawn_background_polling(struct cmd_context *cmd, | |
1361 | struct logical_volume *lv) | |
1362 | { | |
1363 | const char *pvname; | |
1364 | ||
5b6fad12 AK |
1365 | if ((lv->status & PVMOVE) && |
1366 | (pvname = get_pvmove_pvname_from_lv_mirr(lv))) { | |
1367 | log_verbose("Spawning background pvmove process for %s", | |
1368 | pvname); | |
1369 | pvmove_poll(cmd, pvname, 1); | |
1370 | } else if ((lv->status & LOCKED) && | |
93bbc31c AK |
1371 | (pvname = get_pvmove_pvname_from_lv(lv))) { |
1372 | log_verbose("Spawning background pvmove process for %s", | |
1373 | pvname); | |
1374 | pvmove_poll(cmd, pvname, 1); | |
1375 | } | |
1376 | ||
c52678ee | 1377 | if (lv->status & (CONVERTING|MERGING)) { |
93bbc31c AK |
1378 | log_verbose("Spawning background lvconvert process for %s", |
1379 | lv->name); | |
1380 | lvconvert_poll(cmd, lv, 1); | |
1381 | } | |
1382 | } | |
f900ba63 DW |
1383 | |
1384 | /* | |
1385 | * Intial sanity checking of non-recovery related command-line arguments. | |
1386 | * | |
1387 | * Output arguments: | |
1388 | * pp: structure allocated by caller, fields written / validated here | |
1389 | */ | |
accb1738 | 1390 | int pvcreate_params_validate(struct cmd_context *cmd, |
f900ba63 DW |
1391 | int argc, char **argv, |
1392 | struct pvcreate_params *pp) | |
1393 | { | |
1394 | if (!argc) { | |
1395 | log_error("Please enter a physical volume path"); | |
1396 | return 0; | |
1397 | } | |
1398 | ||
f900ba63 | 1399 | pp->yes = arg_count(cmd, yes_ARG); |
f3c17731 | 1400 | pp->force = (force_t) arg_count(cmd, force_ARG); |
f900ba63 DW |
1401 | |
1402 | if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) { | |
1403 | log_error("labelsector must be less than %lu", | |
1404 | LABEL_SCAN_SECTORS); | |
1405 | return 0; | |
1406 | } else { | |
1407 | pp->labelsector = arg_int64_value(cmd, labelsector_ARG, | |
1408 | DEFAULT_LABELSECTOR); | |
1409 | } | |
1410 | ||
1411 | if (!(cmd->fmt->features & FMT_MDAS) && | |
0ddb66ef | 1412 | (arg_count(cmd, pvmetadatacopies_ARG) || |
f900ba63 DW |
1413 | arg_count(cmd, metadatasize_ARG) || |
1414 | arg_count(cmd, dataalignment_ARG) || | |
1415 | arg_count(cmd, dataalignmentoffset_ARG))) { | |
1416 | log_error("Metadata and data alignment parameters only " | |
1417 | "apply to text format."); | |
1418 | return 0; | |
1419 | } | |
1420 | ||
0ddb66ef DW |
1421 | if (arg_count(cmd, pvmetadatacopies_ARG) && |
1422 | arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) { | |
f900ba63 DW |
1423 | log_error("Metadatacopies may only be 0, 1 or 2"); |
1424 | return 0; | |
1425 | } | |
1426 | ||
a5bf7001 | 1427 | if (arg_count(cmd, metadataignore_ARG)) { |
12eadbab | 1428 | pp->metadataignore = !strcmp(arg_str_value(cmd, |
7985f80c DW |
1429 | metadataignore_ARG, |
1430 | DEFAULT_PVMETADATAIGNORE_STR), | |
1431 | "y"); | |
1432 | } else { | |
12eadbab | 1433 | pp->metadataignore = !strcmp(find_config_tree_str(cmd, |
7985f80c DW |
1434 | "metadata/pvmetadataignore", |
1435 | DEFAULT_PVMETADATAIGNORE_STR), | |
1436 | "y"); | |
a5bf7001 DW |
1437 | } |
1438 | if (arg_count(cmd, pvmetadatacopies_ARG) && | |
1439 | !arg_int_value(cmd, pvmetadatacopies_ARG, -1) && | |
12eadbab | 1440 | pp->metadataignore) { |
a5bf7001 DW |
1441 | log_error("metadataignore only applies to metadatacopies > 0"); |
1442 | return 0; | |
1443 | } | |
1444 | ||
f900ba63 DW |
1445 | if (arg_count(cmd, zero_ARG)) |
1446 | pp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n"); | |
1447 | ||
fbf6b89a | 1448 | if (arg_sign_value(cmd, dataalignment_ARG, SIGN_NONE) == SIGN_MINUS) { |
f900ba63 DW |
1449 | log_error("Physical volume data alignment may not be negative"); |
1450 | return 0; | |
1451 | } | |
1452 | pp->data_alignment = arg_uint64_value(cmd, dataalignment_ARG, UINT64_C(0)); | |
1453 | ||
1ef10bd8 | 1454 | if (pp->data_alignment > UINT32_MAX) { |
f900ba63 DW |
1455 | log_error("Physical volume data alignment is too big."); |
1456 | return 0; | |
1457 | } | |
1458 | ||
1459 | if (pp->data_alignment && pp->pe_start) { | |
1460 | if (pp->pe_start % pp->data_alignment) | |
1461 | log_warn("WARNING: Ignoring data alignment %" PRIu64 | |
1462 | " incompatible with --restorefile value (%" | |
1463 | PRIu64").", pp->data_alignment, pp->pe_start); | |
1464 | pp->data_alignment = 0; | |
1465 | } | |
1466 | ||
fbf6b89a | 1467 | if (arg_sign_value(cmd, dataalignmentoffset_ARG, SIGN_NONE) == SIGN_MINUS) { |
f900ba63 DW |
1468 | log_error("Physical volume data alignment offset may not be negative"); |
1469 | return 0; | |
1470 | } | |
1471 | pp->data_alignment_offset = arg_uint64_value(cmd, dataalignmentoffset_ARG, UINT64_C(0)); | |
1472 | ||
1ef10bd8 | 1473 | if (pp->data_alignment_offset > UINT32_MAX) { |
f900ba63 DW |
1474 | log_error("Physical volume data alignment offset is too big."); |
1475 | return 0; | |
1476 | } | |
1477 | ||
1478 | if (pp->data_alignment_offset && pp->pe_start) { | |
1479 | log_warn("WARNING: Ignoring data alignment offset %" PRIu64 | |
1480 | " incompatible with --restorefile value (%" | |
1481 | PRIu64").", pp->data_alignment_offset, pp->pe_start); | |
1482 | pp->data_alignment_offset = 0; | |
1483 | } | |
1484 | ||
fbf6b89a | 1485 | if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { |
f900ba63 DW |
1486 | log_error("Metadata size may not be negative"); |
1487 | return 0; | |
1488 | } | |
1489 | ||
1490 | pp->pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0)); | |
1491 | if (!pp->pvmetadatasize) | |
1492 | pp->pvmetadatasize = find_config_tree_int(cmd, | |
1493 | "metadata/pvmetadatasize", | |
1494 | DEFAULT_PVMETADATASIZE); | |
1495 | ||
0ddb66ef | 1496 | pp->pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); |
f900ba63 DW |
1497 | if (pp->pvmetadatacopies < 0) |
1498 | pp->pvmetadatacopies = find_config_tree_int(cmd, | |
1499 | "metadata/pvmetadatacopies", | |
1500 | DEFAULT_PVMETADATACOPIES); | |
1501 | ||
1502 | return 1; | |
1503 | } | |
1504 | ||
a6bc975a MS |
1505 | int get_activation_monitoring_mode(struct cmd_context *cmd, |
1506 | int *monitoring_mode) | |
1507 | { | |
1508 | *monitoring_mode = DEFAULT_DMEVENTD_MONITOR; | |
1509 | ||
1510 | if (arg_count(cmd, monitor_ARG) && | |
d50c6d4b PR |
1511 | (arg_count(cmd, ignoremonitoring_ARG) || |
1512 | arg_count(cmd, sysinit_ARG))) { | |
1513 | log_error("--ignoremonitoring or --sysinit option not allowed with --monitor option"); | |
a6bc975a MS |
1514 | return 0; |
1515 | } | |
1516 | ||
1517 | if (arg_count(cmd, monitor_ARG)) | |
1518 | *monitoring_mode = arg_int_value(cmd, monitor_ARG, | |
1519 | DEFAULT_DMEVENTD_MONITOR); | |
1520 | else if (is_static() || arg_count(cmd, ignoremonitoring_ARG) || | |
d50c6d4b | 1521 | arg_count(cmd, sysinit_ARG) || |
a6bc975a MS |
1522 | !find_config_tree_bool(cmd, "activation/monitoring", |
1523 | DEFAULT_DMEVENTD_MONITOR)) | |
1524 | *monitoring_mode = DMEVENTD_MONITOR_IGNORE; | |
b73c1824 | 1525 | |
a6bc975a MS |
1526 | return 1; |
1527 | } | |
68176be1 AK |
1528 | |
1529 | /* | |
1530 | * Generic stripe parameter checks. | |
1531 | */ | |
1532 | static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes, | |
1533 | uint32_t *stripe_size) | |
1534 | { | |
1535 | if (*stripes == 1 && *stripe_size) { | |
1536 | log_print("Ignoring stripesize argument with single stripe"); | |
1537 | *stripe_size = 0; | |
1538 | } | |
1539 | ||
1540 | if (*stripes > 1 && !*stripe_size) { | |
1541 | *stripe_size = find_config_tree_int(cmd, "metadata/stripesize", DEFAULT_STRIPESIZE) * 2; | |
1542 | log_print("Using default stripesize %s", | |
1543 | display_size(cmd, (uint64_t) *stripe_size)); | |
1544 | } | |
1545 | ||
1546 | if (*stripes < 1 || *stripes > MAX_STRIPES) { | |
1547 | log_error("Number of stripes (%d) must be between %d and %d", | |
1548 | *stripes, 1, MAX_STRIPES); | |
1549 | return 0; | |
1550 | } | |
1551 | ||
1552 | if (*stripes > 1 && (*stripe_size < STRIPE_SIZE_MIN || | |
1553 | *stripe_size & (*stripe_size - 1))) { | |
1554 | log_error("Invalid stripe size %s", | |
1555 | display_size(cmd, (uint64_t) *stripe_size)); | |
1556 | return 0; | |
1557 | } | |
1558 | ||
1559 | return 1; | |
1560 | } | |
1561 | ||
1562 | /* | |
1563 | * The stripe size is limited by the size of a uint32_t, but since the | |
1564 | * value given by the user is doubled, and the final result must be a | |
1565 | * power of 2, we must divide UINT_MAX by four and add 1 (to round it | |
1566 | * up to the power of 2) | |
1567 | */ | |
1568 | int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size) | |
1569 | { | |
1570 | /* stripes_long_ARG takes precedence (for lvconvert) */ | |
b51cd542 | 1571 | *stripes = arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1); |
68176be1 AK |
1572 | |
1573 | *stripe_size = arg_uint_value(cmd, stripesize_ARG, 0); | |
1574 | if (*stripe_size) { | |
fbf6b89a | 1575 | if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) { |
68176be1 AK |
1576 | log_error("Negative stripesize is invalid"); |
1577 | return 0; | |
1578 | } | |
1579 | ||
301c2b88 | 1580 | if(arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) { |
68176be1 AK |
1581 | log_error("Stripe size cannot be larger than %s", |
1582 | display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT)); | |
1583 | return 0; | |
1584 | } | |
1585 | } | |
1586 | ||
1587 | return _validate_stripe_params(cmd, stripes, stripe_size); | |
1588 | } | |
1589 | ||
b51cd542 AK |
1590 | /* FIXME move to lib */ |
1591 | static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag) | |
1592 | { | |
1593 | if (addtag) { | |
1594 | if (!str_list_add(pv->fmt->cmd->mem, &pv->tags, tag)) { | |
1595 | log_error("Failed to add tag %s to physical volume %s", | |
1596 | tag, pv_dev_name(pv)); | |
1597 | return 0; | |
1598 | } | |
462835fa ZK |
1599 | } else |
1600 | str_list_del(&pv->tags, tag); | |
b51cd542 AK |
1601 | |
1602 | return 1; | |
1603 | } | |
1604 | ||
1605 | /* Set exactly one of VG, LV or PV */ | |
1606 | int change_tag(struct cmd_context *cmd, struct volume_group *vg, | |
1607 | struct logical_volume *lv, struct physical_volume *pv, int arg) | |
1608 | { | |
1609 | const char *tag; | |
1610 | struct arg_value_group_list *current_group; | |
1611 | ||
1612 | dm_list_iterate_items(current_group, &cmd->arg_value_groups) { | |
1613 | if (!grouped_arg_is_set(current_group->arg_values, arg)) | |
1614 | continue; | |
1615 | ||
1616 | if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) { | |
1617 | log_error("Failed to get tag"); | |
1618 | return 0; | |
1619 | } | |
1620 | ||
1621 | if (vg && !vg_change_tag(vg, tag, arg == addtag_ARG)) | |
1622 | return_0; | |
1623 | else if (lv && !lv_change_tag(lv, tag, arg == addtag_ARG)) | |
1624 | return_0; | |
1625 | else if (pv && !_pv_change_tag(pv, tag, arg == addtag_ARG)) | |
1626 | return_0; | |
1627 | } | |
1628 | ||
1629 | return 1; | |
1630 | } | |
b18e1fd5 | 1631 | |
4fbde014 ZK |
1632 | /* Return percents of extents and avoid overflow, with optional roundup */ |
1633 | uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup) | |
b18e1fd5 | 1634 | { |
4fbde014 ZK |
1635 | return (uint32_t)(((uint64_t)percents * (uint64_t)count + |
1636 | ((roundup) ? 99 : 0)) / 100); | |
b18e1fd5 | 1637 | } |