]>
Commit | Line | Data |
---|---|---|
b1713d28 JT |
1 | /* |
2 | * Copyright (C) 2001 Sistina Software (UK) Limited. | |
3 | * | |
1b9fcf48 | 4 | * This file is released under the LGPL. |
b1713d28 JT |
5 | */ |
6 | ||
a381c45a | 7 | #include "metadata.h" |
b1713d28 | 8 | #include "activate.h" |
6d52fb46 | 9 | #include "ll-activate.h" |
78125be9 | 10 | #include "display.h" |
f047219b | 11 | #include "log.h" |
f7a14956 | 12 | #include "fs.h" |
41b2fd5f | 13 | #include "lvm-string.h" |
12137231 JT |
14 | #include "names.h" |
15 | ||
16 | #include <limits.h> | |
fdc7af23 | 17 | #include <linux/kdev_t.h> |
5986ec94 | 18 | #include <fcntl.h> |
12137231 | 19 | |
6d52fb46 | 20 | #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) |
b1713d28 | 21 | |
fae0c576 AK |
22 | int library_version(char *version, size_t size) |
23 | { | |
24 | if (!dm_get_library_version(version, size)) | |
25 | return 0; | |
26 | return 1; | |
27 | } | |
28 | ||
fae0c576 AK |
29 | int driver_version(char *version, size_t size) |
30 | { | |
31 | int r = 0; | |
32 | struct dm_task *dmt; | |
33 | ||
34 | log_very_verbose("Getting driver version"); | |
35 | if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) { | |
36 | stack; | |
37 | return 0; | |
38 | } | |
39 | ||
40 | if (!dm_task_run(dmt)) | |
41 | log_error("Failed to get driver version"); | |
42 | ||
43 | if (!dm_task_get_driver_version(dmt, version, size)) | |
44 | goto out; | |
45 | ||
46 | r = 1; | |
47 | ||
48 | out: | |
49 | dm_task_destroy(dmt); | |
50 | ||
51 | return r; | |
52 | } | |
53 | ||
6d52fb46 | 54 | static int _query(struct logical_volume *lv, int (*fn)(const char *)) |
37ed70b9 | 55 | { |
6d52fb46 | 56 | char buffer[128]; |
4a624ca0 | 57 | |
6d52fb46 | 58 | if (!build_dm_name(buffer, sizeof(buffer), "", |
12137231 JT |
59 | lv->vg->name, lv->name)) { |
60 | stack; | |
6d52fb46 | 61 | return -1; |
12137231 | 62 | } |
4a624ca0 | 63 | |
6d52fb46 | 64 | return fn(buffer); |
4a624ca0 AK |
65 | } |
66 | ||
a62ee8ad AK |
67 | |
68 | /* | |
fdc7af23 | 69 | * These three functions return the number of LVs in the state, |
a62ee8ad AK |
70 | * or -1 on error. |
71 | */ | |
94b8220f | 72 | int lv_active(struct logical_volume *lv) |
2ba80b43 | 73 | { |
6d52fb46 | 74 | return _query(lv, device_active); |
37ed70b9 JT |
75 | } |
76 | ||
2bc25b54 AK |
77 | int lv_suspended(struct logical_volume *lv) |
78 | { | |
6d52fb46 | 79 | return _query(lv, device_suspended); |
2bc25b54 AK |
80 | } |
81 | ||
94b8220f | 82 | int lv_open_count(struct logical_volume *lv) |
2ba80b43 | 83 | { |
6d52fb46 JT |
84 | return _query(lv, device_open_count); |
85 | } | |
86 | ||
a62ee8ad AK |
87 | |
88 | /* | |
89 | * Returns 1 if info structure populated, else 0 on failure. | |
90 | */ | |
6d52fb46 JT |
91 | int lv_info(struct logical_volume *lv, struct dm_info *info) |
92 | { | |
93 | char buffer[128]; | |
2ba80b43 | 94 | |
6d52fb46 JT |
95 | if (!build_dm_name(buffer, sizeof(buffer), "", |
96 | lv->vg->name, lv->name)) { | |
2ba80b43 | 97 | stack; |
a62ee8ad | 98 | return 0; |
2ba80b43 JT |
99 | } |
100 | ||
6d52fb46 | 101 | return device_info(buffer, info); |
2ba80b43 JT |
102 | } |
103 | ||
fdc7af23 JT |
104 | static inline int _read_only_lv(struct logical_volume *lv) |
105 | { | |
106 | return (lv->status & LVM_WRITE) && (lv->vg->status & LVM_WRITE); | |
107 | } | |
6c4ee296 | 108 | |
5986ec94 | 109 | int _lv_activate_named(struct logical_volume *lv, const char *name) |
6d52fb46 | 110 | { |
fdc7af23 JT |
111 | int r = 0; |
112 | struct dm_task *dmt; | |
6c4ee296 | 113 | |
6d52fb46 JT |
114 | if (test_mode()) { |
115 | _skip("Activation of '%s'.", lv->name); | |
116 | return 0; | |
6c4ee296 JT |
117 | } |
118 | ||
fdc7af23 JT |
119 | /* |
120 | * Create a task. | |
121 | */ | |
5986ec94 | 122 | if (!(dmt = setup_dm_task(name, DM_DEVICE_CREATE))) { |
6d52fb46 JT |
123 | stack; |
124 | return 0; | |
125 | } | |
a299e388 | 126 | |
fdc7af23 JT |
127 | /* |
128 | * Populate it. | |
129 | */ | |
130 | if (!device_populate_lv(dmt, lv)) { | |
80f9662b JT |
131 | stack; |
132 | return 0; | |
133 | } | |
134 | ||
fdc7af23 JT |
135 | /* |
136 | * Do we want a specific minor number ? | |
137 | */ | |
138 | if (lv->minor >= 0) { | |
139 | if (!dm_task_set_minor(dmt, MINOR(lv->minor))) { | |
140 | log_error("Failed to set minor number for %s to %d " | |
141 | "during activation.", lv->name, lv->minor); | |
142 | goto out; | |
143 | } else | |
144 | log_very_verbose("Set minor number for %s to %d.", | |
145 | lv->name, lv->minor); | |
146 | } | |
147 | ||
148 | /* | |
149 | * Read only ? | |
150 | */ | |
151 | if (!_read_only_lv(lv)) { | |
152 | if (!dm_task_set_ro(dmt)) { | |
153 | log_error("Failed to set %s read-only during " | |
154 | "activation.", lv->name); | |
155 | goto out; | |
156 | } else | |
157 | log_very_verbose("Activating %s read-only", lv->name); | |
158 | } | |
159 | ||
160 | /* | |
161 | * Load this into the kernel. | |
162 | */ | |
163 | if (!(r = dm_task_run(dmt))) { | |
164 | log_err("Activation failed."); | |
165 | goto out; | |
166 | } | |
167 | ||
fdc7af23 JT |
168 | out: |
169 | dm_task_destroy(dmt); | |
170 | log_verbose("Logical volume %s%s activated", lv->name, | |
171 | r == 1 ? "" : " not"); | |
172 | return r; | |
173 | } | |
174 | ||
5986ec94 JT |
175 | int lv_activate(struct logical_volume *lv) |
176 | { | |
177 | char buffer[128]; | |
178 | ||
179 | /* | |
180 | * Decide what we're going to call this device. | |
181 | */ | |
182 | if (!build_dm_name(buffer, sizeof(buffer), "", | |
183 | lv->vg->name, lv->name)) { | |
184 | stack; | |
185 | return 0; | |
186 | } | |
187 | ||
188 | if (!_lv_activate_named(lv, buffer) || | |
189 | !fs_add_lv(lv, lv->minor)) { | |
190 | stack; | |
191 | return 0; | |
192 | } | |
193 | ||
194 | return 1; | |
195 | } | |
196 | ||
fdc7af23 JT |
197 | static int _reload(const char *name, struct logical_volume *lv) |
198 | { | |
199 | int r = 0; | |
200 | struct dm_task *dmt; | |
201 | ||
202 | /* | |
203 | * Create a task. | |
204 | */ | |
205 | if (!(dmt = setup_dm_task(name, DM_DEVICE_RELOAD))) { | |
206 | stack; | |
207 | return 0; | |
208 | } | |
209 | ||
210 | /* | |
211 | * Populate it. | |
212 | */ | |
213 | if (!device_populate_lv(dmt, lv)) { | |
214 | stack; | |
215 | return 0; | |
216 | } | |
217 | ||
218 | /* | |
219 | * Load this into the kernel. | |
220 | */ | |
221 | if (!(r = dm_task_run(dmt))) { | |
222 | log_err("Activation failed."); | |
223 | goto out; | |
224 | } | |
225 | ||
226 | /* | |
227 | * Create device nodes and symbolic links. | |
228 | */ | |
229 | if (!fs_add_lv(lv, lv->minor)) | |
230 | stack; | |
231 | ||
232 | out: | |
233 | dm_task_destroy(dmt); | |
234 | log_verbose("Logical volume %s%s re-activated", lv->name, | |
235 | r == 1 ? "" : " not"); | |
236 | return r; | |
80f9662b JT |
237 | } |
238 | ||
6d52fb46 | 239 | int lv_reactivate(struct logical_volume *lv) |
b1713d28 | 240 | { |
6d52fb46 JT |
241 | int r; |
242 | char buffer[128]; | |
e15559aa | 243 | |
6d52fb46 JT |
244 | if (test_mode()) { |
245 | _skip("Reactivation of '%s'.", lv->name); | |
ae2bb665 JT |
246 | return 0; |
247 | } | |
b1713d28 | 248 | |
fdc7af23 JT |
249 | /* |
250 | * Decide what we're going to call this device. | |
251 | */ | |
6d52fb46 JT |
252 | if (!build_dm_name(buffer, sizeof(buffer), "", |
253 | lv->vg->name, lv->name)) { | |
254 | stack; | |
255 | return 0; | |
ae2bb665 JT |
256 | } |
257 | ||
fdc7af23 JT |
258 | /* |
259 | * Suspend the device if it isn't already. | |
260 | */ | |
6d52fb46 JT |
261 | if (!device_suspended(buffer) && !device_suspend(buffer)) { |
262 | stack; | |
263 | return 0; | |
12a6fcd3 | 264 | } |
2bc25b54 | 265 | |
fdc7af23 | 266 | r = _reload(buffer, lv); |
2bc25b54 | 267 | |
6d52fb46 | 268 | if (!device_resume(buffer)) { |
ae2bb665 | 269 | stack; |
6d52fb46 JT |
270 | return 0; |
271 | } | |
ae2bb665 | 272 | |
ae2bb665 | 273 | return r; |
b1713d28 | 274 | } |
a381c45a | 275 | |
6d52fb46 | 276 | int lv_deactivate(struct logical_volume *lv) |
0a5e4a14 | 277 | { |
6d52fb46 | 278 | char buffer[128]; |
c2d72fd4 | 279 | |
6d52fb46 JT |
280 | log_very_verbose("Deactivating %s", lv->name); |
281 | if (test_mode()) { | |
282 | _skip("Deactivating '%s'.", lv->name); | |
283 | return 0; | |
284 | } | |
37ed70b9 | 285 | |
6d52fb46 JT |
286 | if (!build_dm_name(buffer, sizeof(buffer), "", |
287 | lv->vg->name, lv->name)) { | |
288 | stack; | |
289 | return 0; | |
290 | } | |
37ed70b9 | 291 | |
6d52fb46 | 292 | if (!device_deactivate(buffer)) { |
37ed70b9 JT |
293 | stack; |
294 | return 0; | |
295 | } | |
296 | ||
6d52fb46 | 297 | fs_del_lv(lv); |
37ed70b9 | 298 | |
6d52fb46 | 299 | return 1; |
37ed70b9 JT |
300 | } |
301 | ||
4a624ca0 AK |
302 | int lv_suspend(struct logical_volume *lv) |
303 | { | |
6d52fb46 | 304 | char buffer[128]; |
4a624ca0 | 305 | |
6d52fb46 JT |
306 | log_very_verbose("Suspending %s", lv->name); |
307 | if (test_mode()) { | |
308 | _skip("Suspending '%s'.", lv->name); | |
c2d72fd4 | 309 | return 0; |
6d52fb46 | 310 | } |
c2d72fd4 | 311 | |
6d52fb46 JT |
312 | if (!build_dm_name(buffer, sizeof(buffer), "", |
313 | lv->vg->name, lv->name)) { | |
37ed70b9 JT |
314 | stack; |
315 | return 0; | |
316 | } | |
0a5e4a14 | 317 | |
6d52fb46 | 318 | if (!device_suspend(buffer)) { |
37ed70b9 JT |
319 | stack; |
320 | return 0; | |
321 | } | |
0a5e4a14 | 322 | |
6d52fb46 | 323 | fs_del_lv(lv); |
0a5e4a14 | 324 | |
6d52fb46 JT |
325 | return 1; |
326 | } | |
4a624ca0 | 327 | |
6d52fb46 | 328 | int lv_rename(const char *old_name, struct logical_volume *lv) |
ae2bb665 | 329 | { |
6d52fb46 JT |
330 | int r = 0; |
331 | char new_name[PATH_MAX]; | |
ab269099 JT |
332 | struct dm_task *dmt; |
333 | ||
6d52fb46 JT |
334 | if (test_mode()) { |
335 | _skip("Rename '%s' to '%s'.", old_name, lv->name); | |
c2d72fd4 | 336 | return 0; |
6d52fb46 | 337 | } |
c2d72fd4 | 338 | |
6d52fb46 | 339 | if (!(dmt = setup_dm_task(old_name, DM_DEVICE_RENAME))) { |
ae2bb665 JT |
340 | stack; |
341 | return 0; | |
342 | } | |
343 | ||
6d52fb46 JT |
344 | if (!build_dm_name(new_name, sizeof(new_name), "", |
345 | lv->vg->name, lv->name)) { | |
ae2bb665 | 346 | stack; |
6d52fb46 JT |
347 | return 0; |
348 | } | |
ae2bb665 | 349 | |
6d52fb46 JT |
350 | if (!dm_task_set_newname(dmt, new_name)) { |
351 | stack; | |
352 | r = 0; | |
353 | goto end; | |
354 | } | |
f7a14956 | 355 | |
6d52fb46 JT |
356 | if (!dm_task_run(dmt)) { |
357 | stack; | |
358 | r = 0; | |
359 | goto end; | |
360 | } | |
361 | ||
362 | fs_rename_lv(old_name, lv); | |
f7a14956 | 363 | |
6d52fb46 JT |
364 | end: |
365 | dm_task_destroy(dmt); | |
ae2bb665 JT |
366 | return r; |
367 | } | |
368 | ||
5986ec94 JT |
369 | /* |
370 | * Zero the start of a cow store so the driver spots that it is a | |
371 | * new store. | |
372 | */ | |
373 | int lv_setup_cow_store(struct logical_volume *lv) | |
374 | { | |
375 | char buffer[128]; | |
376 | char path[PATH_MAX]; | |
377 | struct device *dev; | |
378 | ||
379 | /* | |
380 | * Decide what we're going to call this device. | |
381 | */ | |
382 | if (!build_dm_name(buffer, sizeof(buffer), "cow_init", | |
383 | lv->vg->name, lv->name)) { | |
384 | stack; | |
385 | return 0; | |
386 | } | |
387 | ||
388 | if (!_lv_activate_named(lv, buffer)) { | |
389 | log_err("Unable to activate cow store logical volume."); | |
390 | return 0; | |
391 | } | |
392 | ||
393 | /* FIXME: hard coded dir */ | |
394 | if (lvm_snprintf(path, sizeof(path), "/dev/device-mapper/%s", | |
395 | buffer) < 0) { | |
396 | log_error("Name too long - device not zeroed (%s)", | |
397 | lv->name); | |
398 | return 0; | |
399 | } | |
400 | ||
401 | if (!(dev = dev_cache_get(path, NULL))) { | |
402 | log_error("\"%s\" not found: device not zeroed", path); | |
403 | return 0; | |
404 | } | |
405 | ||
406 | if (!(dev_open(dev, O_WRONLY))) | |
407 | return 0; | |
408 | ||
409 | dev_zero(dev, 0, 4096); | |
410 | dev_close(dev); | |
411 | ||
412 | return 1; | |
413 | } | |
414 | ||
6d52fb46 | 415 | |
37ed70b9 JT |
416 | int activate_lvs_in_vg(struct volume_group *vg) |
417 | { | |
418 | struct list *lvh; | |
419 | struct logical_volume *lv; | |
94b8220f | 420 | int count = 0; |
37ed70b9 JT |
421 | |
422 | list_iterate(lvh, &vg->lvs) { | |
f868d635 | 423 | lv = list_item(lvh, struct lv_list)->lv; |
94b8220f | 424 | count += (!lv_active(lv) && lv_activate(lv)); |
37ed70b9 JT |
425 | } |
426 | ||
427 | return count; | |
428 | } | |
429 | ||
a381c45a AK |
430 | int deactivate_lvs_in_vg(struct volume_group *vg) |
431 | { | |
0a5e4a14 | 432 | struct list *lvh; |
37ed70b9 | 433 | struct logical_volume *lv; |
94b8220f | 434 | int count = 0; |
37ed70b9 JT |
435 | |
436 | list_iterate(lvh, &vg->lvs) { | |
f868d635 | 437 | lv = list_item(lvh, struct lv_list)->lv; |
94b8220f | 438 | count += ((lv_active(lv) == 1) && lv_deactivate(lv)); |
37ed70b9 | 439 | } |
0a5e4a14 | 440 | |
37ed70b9 | 441 | return count; |
a381c45a | 442 | } |
f047219b AK |
443 | |
444 | int lvs_in_vg_activated(struct volume_group *vg) | |
445 | { | |
37ed70b9 JT |
446 | struct list *lvh; |
447 | struct logical_volume *lv; | |
94b8220f | 448 | int count = 0; |
37ed70b9 JT |
449 | |
450 | list_iterate(lvh, &vg->lvs) { | |
f868d635 | 451 | lv = list_item(lvh, struct lv_list)->lv; |
94b8220f | 452 | count += (lv_active(lv) == 1); |
37ed70b9 JT |
453 | } |
454 | ||
455 | return count; | |
f047219b | 456 | } |
2ba80b43 JT |
457 | |
458 | int lvs_in_vg_opened(struct volume_group *vg) | |
459 | { | |
460 | struct list *lvh; | |
461 | struct logical_volume *lv; | |
94b8220f | 462 | int count = 0; |
2ba80b43 JT |
463 | |
464 | list_iterate(lvh, &vg->lvs) { | |
f868d635 | 465 | lv = list_item(lvh, struct lv_list)->lv; |
94b8220f | 466 | count += (lv_open_count(lv) == 1); |
2ba80b43 JT |
467 | } |
468 | ||
469 | return count; | |
470 | } |