]>
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" |
78125be9 | 9 | #include "display.h" |
f047219b | 10 | #include "log.h" |
f7a14956 | 11 | #include "fs.h" |
41b2fd5f | 12 | #include "lvm-string.h" |
b1713d28 | 13 | |
fae0c576 AK |
14 | int library_version(char *version, size_t size) |
15 | { | |
16 | if (!dm_get_library_version(version, size)) | |
17 | return 0; | |
18 | return 1; | |
19 | } | |
20 | ||
4a624ca0 AK |
21 | static void _build_lv_name(char *buffer, size_t s, const char *vg_name, |
22 | const char *lv_name) | |
ab269099 | 23 | { |
4a624ca0 | 24 | snprintf(buffer, s, "%s_%s", vg_name, lv_name); |
ab269099 JT |
25 | } |
26 | ||
f2f26349 | 27 | static struct dm_task *_setup_task_with_name(struct logical_volume *lv, |
4a624ca0 | 28 | const char *lv_name, int task) |
37ed70b9 JT |
29 | { |
30 | char name[128]; | |
31 | struct dm_task *dmt; | |
32 | ||
33 | if (!(dmt = dm_task_create(task))) { | |
34 | stack; | |
35 | return NULL; | |
36 | } | |
37 | ||
4a624ca0 | 38 | _build_lv_name(name, sizeof(name), lv->vg->name, lv_name); |
37ed70b9 JT |
39 | dm_task_set_name(dmt, name); |
40 | ||
41 | return dmt; | |
42 | } | |
43 | ||
4a624ca0 AK |
44 | static struct dm_task *_setup_task(struct logical_volume *lv, int task) |
45 | { | |
46 | return _setup_task_with_name(lv, lv->name, task); | |
47 | } | |
48 | ||
fae0c576 AK |
49 | int driver_version(char *version, size_t size) |
50 | { | |
51 | int r = 0; | |
52 | struct dm_task *dmt; | |
53 | ||
54 | log_very_verbose("Getting driver version"); | |
55 | if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) { | |
56 | stack; | |
57 | return 0; | |
58 | } | |
59 | ||
60 | if (!dm_task_run(dmt)) | |
61 | log_error("Failed to get driver version"); | |
62 | ||
63 | if (!dm_task_get_driver_version(dmt, version, size)) | |
64 | goto out; | |
65 | ||
66 | r = 1; | |
67 | ||
68 | out: | |
69 | dm_task_destroy(dmt); | |
70 | ||
71 | return r; | |
72 | } | |
73 | ||
3080a754 | 74 | int lv_info(struct logical_volume *lv, struct dm_info *info) |
37ed70b9 | 75 | { |
ef8a0eae | 76 | int r = 0; |
37ed70b9 JT |
77 | struct dm_task *dmt; |
78 | ||
a299e388 | 79 | log_very_verbose("Getting device info for %s", lv->name); |
37ed70b9 JT |
80 | if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) { |
81 | stack; | |
82 | return 0; | |
83 | } | |
84 | ||
85 | if (!dm_task_run(dmt)) { | |
2ba80b43 | 86 | stack; |
ef8a0eae | 87 | goto out; |
2ba80b43 JT |
88 | } |
89 | ||
ef8a0eae JT |
90 | if (!dm_task_get_info(dmt, info)) { |
91 | stack; | |
92 | goto out; | |
93 | } | |
94 | r = 1; | |
2ba80b43 | 95 | |
ef8a0eae | 96 | out: |
2ba80b43 | 97 | dm_task_destroy(dmt); |
ef8a0eae | 98 | return r; |
2ba80b43 JT |
99 | } |
100 | ||
4a624ca0 AK |
101 | int lv_rename(const char *old_name, struct logical_volume *lv) |
102 | { | |
103 | int r = 0; | |
104 | char new_name[128]; | |
105 | struct dm_task *dmt; | |
106 | ||
107 | if (test_mode()) | |
108 | return 0; | |
109 | ||
110 | if (!(dmt = _setup_task_with_name(lv, old_name, DM_DEVICE_RENAME))) { | |
111 | stack; | |
112 | return 0; | |
113 | } | |
114 | ||
115 | _build_lv_name(new_name, sizeof(new_name), lv->vg->name, lv->name); | |
116 | ||
117 | if (!dm_task_set_newname(dmt, new_name)) { | |
118 | stack; | |
119 | r = 0; | |
120 | goto end; | |
121 | } | |
122 | ||
123 | if (!dm_task_run(dmt)) { | |
124 | stack; | |
125 | r = 0; | |
126 | goto end; | |
127 | } | |
128 | ||
129 | fs_rename_lv(old_name, lv); | |
130 | ||
131 | end: | |
132 | dm_task_destroy(dmt); | |
4a624ca0 AK |
133 | return r; |
134 | } | |
135 | ||
94b8220f | 136 | int lv_active(struct logical_volume *lv) |
2ba80b43 | 137 | { |
94b8220f | 138 | int r = -1; |
ef8a0eae | 139 | struct dm_info info; |
2ba80b43 | 140 | |
3080a754 | 141 | if (!lv_info(lv, &info)) { |
37ed70b9 | 142 | stack; |
94b8220f | 143 | return r; |
37ed70b9 JT |
144 | } |
145 | ||
a299e388 | 146 | log_very_verbose("%s is%s active", lv->name, info.exists ? "":" not"); |
ef8a0eae | 147 | return info.exists; |
37ed70b9 JT |
148 | } |
149 | ||
2bc25b54 AK |
150 | int lv_suspended(struct logical_volume *lv) |
151 | { | |
152 | int r = -1; | |
153 | struct dm_info info; | |
154 | ||
155 | if (!lv_info(lv, &info)) { | |
156 | stack; | |
157 | return r; | |
158 | } | |
159 | ||
f2f26349 | 160 | log_very_verbose("%s is%s suspended", lv->name, |
2bc25b54 AK |
161 | info.suspended ? "":" not"); |
162 | return info.suspended; | |
163 | } | |
164 | ||
94b8220f | 165 | int lv_open_count(struct logical_volume *lv) |
2ba80b43 | 166 | { |
94b8220f | 167 | int r = -1; |
ef8a0eae | 168 | struct dm_info info; |
2ba80b43 | 169 | |
3080a754 | 170 | if (!lv_info(lv, &info)) { |
2ba80b43 | 171 | stack; |
94b8220f | 172 | return r; |
2ba80b43 JT |
173 | } |
174 | ||
a299e388 | 175 | log_very_verbose("%s is open %d time(s)", lv->name, info.open_count); |
ef8a0eae | 176 | return info.open_count; |
2ba80b43 JT |
177 | } |
178 | ||
80f9662b | 179 | /* |
0bab6591 | 180 | * Emit a target for a given segment. |
80f9662b | 181 | */ |
0bab6591 | 182 | static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg) |
80f9662b JT |
183 | { |
184 | char params[1024]; | |
39497a44 | 185 | uint64_t esize = seg->lv->vg->extent_size; |
0bab6591 | 186 | uint32_t s, stripes = seg->stripes; |
b546cd6d | 187 | int w = 0, tw = 0; |
6c4ee296 JT |
188 | const char *no_space = |
189 | "Insufficient space to write target parameters."; | |
0bab6591 | 190 | |
6c4ee296 | 191 | if (stripes > 1) { |
41b2fd5f | 192 | tw = lvm_snprintf(params, sizeof(params), "%u %u ", |
6c4ee296 JT |
193 | stripes, seg->stripe_size); |
194 | ||
195 | if (tw < 0) { | |
196 | log_err(no_space); | |
197 | return 0; | |
198 | } | |
199 | ||
200 | w = tw; | |
201 | } | |
202 | ||
f2f26349 | 203 | |
6c4ee296 | 204 | for (s = 0; s < stripes; s++, w += tw) { |
4a624ca0 AK |
205 | /****** |
206 | log_debug("stripes: %d", stripes); | |
207 | log_debug("dev_name(seg->area[s].pv->dev): %s", | |
208 | dev_name(seg->area[s].pv->dev)); | |
209 | log_debug("esize: %" PRIu64, esize); | |
210 | log_debug("seg->area[s].pe: %" PRIu64, seg->area[s].pe); | |
211 | log_debug("seg->area[s].pv->pe_start: %" PRIu64, | |
212 | seg->area[s].pv->pe_start); | |
213 | *******/ | |
214 | ||
41b2fd5f | 215 | tw = lvm_snprintf(params + w, sizeof(params) - w, |
0bab6591 JT |
216 | "%s %" PRIu64 "%s", |
217 | dev_name(seg->area[s].pv->dev), | |
218 | (seg->area[s].pv->pe_start + | |
219 | (esize * seg->area[s].pe)), | |
220 | s == (stripes - 1) ? "" : " "); | |
221 | ||
222 | if (tw < 0) { | |
6c4ee296 | 223 | log_err(no_space); |
0bab6591 JT |
224 | return 0; |
225 | } | |
80f9662b JT |
226 | } |
227 | ||
a299e388 AK |
228 | log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s", |
229 | esize * seg->le, esize * seg->len, | |
230 | stripes == 1 ? "linear" : "striped", | |
231 | params); | |
232 | ||
39497a44 | 233 | if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len, |
0bab6591 JT |
234 | stripes == 1 ? "linear" : "striped", |
235 | params)) { | |
80f9662b JT |
236 | stack; |
237 | return 0; | |
238 | } | |
239 | ||
80f9662b JT |
240 | return 1; |
241 | } | |
242 | ||
37ed70b9 | 243 | int _load(struct logical_volume *lv, int task) |
b1713d28 | 244 | { |
ae2bb665 | 245 | int r = 0; |
ae2bb665 | 246 | struct dm_task *dmt; |
0bab6591 JT |
247 | struct list *segh; |
248 | struct stripe_segment *seg; | |
e15559aa | 249 | |
a299e388 | 250 | log_very_verbose("Generating devmapper parameters for %s", lv->name); |
37ed70b9 | 251 | if (!(dmt = _setup_task(lv, task))) { |
ae2bb665 JT |
252 | stack; |
253 | return 0; | |
254 | } | |
b1713d28 | 255 | |
0bab6591 JT |
256 | list_iterate(segh, &lv->segments) { |
257 | seg = list_item(segh, struct stripe_segment); | |
258 | if (!_emit_target(dmt, seg)) { | |
cf4a4a1f | 259 | log_error("Unable to activate logical volume '%s'", |
80f9662b | 260 | lv->name); |
ae2bb665 JT |
261 | goto out; |
262 | } | |
ae2bb665 JT |
263 | } |
264 | ||
2bc25b54 AK |
265 | if (!(lv->status & LVM_WRITE) && !dm_task_set_ro(dmt)) |
266 | log_error("Failed to set %s read-only during activation.", | |
267 | lv->name); | |
268 | ||
269 | ||
f047219b | 270 | if (!(r = dm_task_run(dmt))) |
ae2bb665 JT |
271 | stack; |
272 | ||
b546cd6d AK |
273 | log_verbose("Logical volume %s%s activated", lv->name, |
274 | r == 1 ? "" : " not"); | |
3080a754 | 275 | |
ae2bb665 | 276 | out: |
f047219b | 277 | dm_task_destroy(dmt); |
ae2bb665 | 278 | return r; |
b1713d28 | 279 | } |
a381c45a | 280 | |
37ed70b9 | 281 | /* FIXME: Always display error msg */ |
37ed70b9 | 282 | int lv_activate(struct logical_volume *lv) |
0a5e4a14 | 283 | { |
c2d72fd4 AK |
284 | if (test_mode()) |
285 | return 0; | |
286 | ||
a299e388 | 287 | log_very_verbose("Activating %s", lv->name); |
f7a14956 | 288 | return _load(lv, DM_DEVICE_CREATE) && fs_add_lv(lv); |
37ed70b9 JT |
289 | } |
290 | ||
291 | int _suspend(struct logical_volume *lv, int sus) | |
292 | { | |
293 | int r; | |
294 | struct dm_task *dmt; | |
295 | int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME; | |
296 | ||
a299e388 | 297 | log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", lv->name); |
37ed70b9 JT |
298 | if (!(dmt = _setup_task(lv, task))) { |
299 | stack; | |
300 | return 0; | |
301 | } | |
302 | ||
303 | if (!(r = dm_task_run(dmt))) | |
304 | log_err("Couldn't %s device '%s'", sus ? "suspend" : "resume", | |
305 | lv->name); | |
306 | ||
307 | dm_task_destroy(dmt); | |
308 | return r; | |
309 | } | |
310 | ||
4a624ca0 AK |
311 | int lv_suspend(struct logical_volume *lv) |
312 | { | |
313 | return _suspend(lv, 1); | |
314 | } | |
315 | ||
37ed70b9 JT |
316 | int lv_reactivate(struct logical_volume *lv) |
317 | { | |
318 | int r; | |
c2d72fd4 AK |
319 | |
320 | if (test_mode()) | |
321 | return 0; | |
322 | ||
2bc25b54 | 323 | if (!lv_suspended(lv) && !_suspend(lv, 1)) { |
37ed70b9 JT |
324 | stack; |
325 | return 0; | |
326 | } | |
0a5e4a14 | 327 | |
37ed70b9 | 328 | r = _load(lv, DM_DEVICE_RELOAD); |
ae2bb665 | 329 | |
37ed70b9 JT |
330 | if (!_suspend(lv, 0)) { |
331 | stack; | |
332 | return 0; | |
333 | } | |
0a5e4a14 | 334 | |
37ed70b9 | 335 | return r; |
0a5e4a14 AK |
336 | } |
337 | ||
4a624ca0 | 338 | |
ae2bb665 JT |
339 | int lv_deactivate(struct logical_volume *lv) |
340 | { | |
f047219b | 341 | int r; |
ab269099 JT |
342 | struct dm_task *dmt; |
343 | ||
a299e388 | 344 | log_very_verbose("Deactivating %s", lv->name); |
c2d72fd4 AK |
345 | if (test_mode()) |
346 | return 0; | |
347 | ||
37ed70b9 | 348 | if (!(dmt = _setup_task(lv, DM_DEVICE_REMOVE))) { |
ae2bb665 JT |
349 | stack; |
350 | return 0; | |
351 | } | |
352 | ||
f047219b | 353 | if (!(r = dm_task_run(dmt))) |
ae2bb665 JT |
354 | stack; |
355 | ||
ae2bb665 | 356 | dm_task_destroy(dmt); |
f7a14956 JT |
357 | |
358 | fs_del_lv(lv); | |
359 | ||
ae2bb665 JT |
360 | return r; |
361 | } | |
362 | ||
37ed70b9 JT |
363 | int activate_lvs_in_vg(struct volume_group *vg) |
364 | { | |
365 | struct list *lvh; | |
366 | struct logical_volume *lv; | |
94b8220f | 367 | int count = 0; |
37ed70b9 JT |
368 | |
369 | list_iterate(lvh, &vg->lvs) { | |
370 | lv = &(list_item(lvh, struct lv_list)->lv); | |
371 | ||
94b8220f | 372 | count += (!lv_active(lv) && lv_activate(lv)); |
37ed70b9 JT |
373 | } |
374 | ||
375 | return count; | |
376 | } | |
377 | ||
ae2bb665 JT |
378 | int lv_update_write_access(struct logical_volume *lv) |
379 | { | |
2bc25b54 AK |
380 | struct dm_info info; |
381 | ||
382 | if (!lv_info(lv, &info)) { | |
383 | stack; | |
384 | return 0; | |
385 | } | |
386 | ||
387 | if (!info.exists || info.suspended) | |
388 | /* Noop */ | |
389 | return 1; | |
390 | ||
391 | return lv_reactivate(lv); | |
ae2bb665 JT |
392 | } |
393 | ||
a381c45a AK |
394 | int deactivate_lvs_in_vg(struct volume_group *vg) |
395 | { | |
0a5e4a14 | 396 | struct list *lvh; |
37ed70b9 | 397 | struct logical_volume *lv; |
94b8220f | 398 | int count = 0; |
37ed70b9 JT |
399 | |
400 | list_iterate(lvh, &vg->lvs) { | |
401 | lv = &(list_item(lvh, struct lv_list)->lv); | |
0a5e4a14 | 402 | |
94b8220f | 403 | count += ((lv_active(lv) == 1) && lv_deactivate(lv)); |
37ed70b9 | 404 | } |
0a5e4a14 | 405 | |
37ed70b9 | 406 | return count; |
a381c45a | 407 | } |
f047219b AK |
408 | |
409 | int lvs_in_vg_activated(struct volume_group *vg) | |
410 | { | |
37ed70b9 JT |
411 | struct list *lvh; |
412 | struct logical_volume *lv; | |
94b8220f | 413 | int count = 0; |
37ed70b9 JT |
414 | |
415 | list_iterate(lvh, &vg->lvs) { | |
416 | lv = &(list_item(lvh, struct lv_list)->lv); | |
417 | ||
94b8220f | 418 | count += (lv_active(lv) == 1); |
37ed70b9 JT |
419 | } |
420 | ||
421 | return count; | |
f047219b | 422 | } |
2ba80b43 JT |
423 | |
424 | int lvs_in_vg_opened(struct volume_group *vg) | |
425 | { | |
426 | struct list *lvh; | |
427 | struct logical_volume *lv; | |
94b8220f | 428 | int count = 0; |
2ba80b43 JT |
429 | |
430 | list_iterate(lvh, &vg->lvs) { | |
431 | lv = &(list_item(lvh, struct lv_list)->lv); | |
432 | ||
94b8220f | 433 | count += (lv_open_count(lv) == 1); |
2ba80b43 JT |
434 | } |
435 | ||
436 | return count; | |
437 | } |