Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "toolcontext.h"
18 : : #include "metadata.h"
19 : : #include "segtype.h"
20 : : #include "text_export.h"
21 : : #include "config.h"
22 : : #include "activate.h"
23 : : #include "str_list.h"
24 : : #ifdef DMEVENTD
25 : : # include "sharedlib.h"
26 : : # include "libdevmapper-event.h"
27 : : #endif
28 : :
29 : 0 : static const char *_snap_name(const struct lv_segment *seg)
30 : : {
31 : 0 : return seg->segtype->name;
32 : : }
33 : :
34 : 0 : static int _snap_text_import(struct lv_segment *seg, const struct config_node *sn,
35 : : struct dm_hash_table *pv_hash __attribute((unused)))
36 : : {
37 : : uint32_t chunk_size;
38 : : const char *org_name, *cow_name;
39 : : struct logical_volume *org, *cow;
40 : 0 : int old_suppress, merge = 0;
41 : :
42 [ # # ]: 0 : if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
43 : 0 : log_error("Couldn't read chunk size for snapshot.");
44 : 0 : return 0;
45 : : }
46 : :
47 : 0 : old_suppress = log_suppress(1);
48 : :
49 [ # # ]: 0 : if ((cow_name = find_config_str(sn, "merging_store", NULL))) {
50 [ # # ]: 0 : if (find_config_str(sn, "cow_store", NULL)) {
51 : 0 : log_suppress(old_suppress);
52 : 0 : log_error("Both snapshot cow and merging storage were specified.");
53 : 0 : return 0;
54 : : }
55 : 0 : merge = 1;
56 : : }
57 [ # # ]: 0 : else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
58 : 0 : log_suppress(old_suppress);
59 : 0 : log_error("Snapshot cow storage not specified.");
60 : 0 : return 0;
61 : : }
62 : :
63 [ # # ]: 0 : if (!(org_name = find_config_str(sn, "origin", NULL))) {
64 : 0 : log_suppress(old_suppress);
65 : 0 : log_error("Snapshot origin not specified.");
66 : 0 : return 0;
67 : : }
68 : :
69 : 0 : log_suppress(old_suppress);
70 : :
71 [ # # ]: 0 : if (!(cow = find_lv(seg->lv->vg, cow_name))) {
72 : 0 : log_error("Unknown logical volume specified for "
73 : : "snapshot cow store.");
74 : 0 : return 0;
75 : : }
76 : :
77 [ # # ]: 0 : if (!(org = find_lv(seg->lv->vg, org_name))) {
78 : 0 : log_error("Unknown logical volume specified for "
79 : : "snapshot origin.");
80 : 0 : return 0;
81 : : }
82 : :
83 : 0 : init_snapshot_seg(seg, org, cow, chunk_size, merge);
84 : :
85 : 0 : return 1;
86 : : }
87 : :
88 : 0 : static int _snap_text_export(const struct lv_segment *seg, struct formatter *f)
89 : : {
90 [ # # ]: 0 : outf(f, "chunk_size = %u", seg->chunk_size);
91 [ # # ]: 0 : outf(f, "origin = \"%s\"", seg->origin->name);
92 [ # # ]: 0 : if (!(seg->status & MERGING))
93 [ # # ]: 0 : outf(f, "cow_store = \"%s\"", seg->cow->name);
94 : : else
95 [ # # ]: 0 : outf(f, "merging_store = \"%s\"", seg->cow->name);
96 : :
97 : 0 : return 1;
98 : : }
99 : :
100 : 0 : static int _snap_target_status_compatible(const char *type)
101 : : {
102 : 0 : return (strcmp(type, "snapshot-merge") == 0);
103 : : }
104 : :
105 : : #ifdef DEVMAPPER_SUPPORT
106 : 0 : static int _snap_target_percent(void **target_state __attribute((unused)),
107 : : percent_range_t *percent_range,
108 : : struct dm_pool *mem __attribute((unused)),
109 : : struct cmd_context *cmd __attribute((unused)),
110 : : struct lv_segment *seg __attribute((unused)),
111 : : char *params, uint64_t *total_numerator,
112 : : uint64_t *total_denominator)
113 : : {
114 : : uint64_t total_sectors, sectors_allocated, metadata_sectors;
115 : : int r;
116 : :
117 : : /*
118 : : * snapshot target's percent format:
119 : : * <= 1.7.0: <sectors_allocated>/<total_sectors>
120 : : * >= 1.8.0: <sectors_allocated>/<total_sectors> <metadata_sectors>
121 : : */
122 : 0 : r = sscanf(params, "%" PRIu64 "/%" PRIu64 " %" PRIu64,
123 : : §ors_allocated, &total_sectors, &metadata_sectors);
124 [ # # ][ # # ]: 0 : if (r == 2 || r == 3) {
125 : 0 : *total_numerator += sectors_allocated;
126 : 0 : *total_denominator += total_sectors;
127 [ # # ][ # # ]: 0 : if (r == 3 && sectors_allocated == metadata_sectors)
128 : 0 : *percent_range = PERCENT_0;
129 [ # # ]: 0 : else if (sectors_allocated == total_sectors)
130 : 0 : *percent_range = PERCENT_100;
131 : : else
132 : 0 : *percent_range = PERCENT_0_TO_100;
133 [ # # ][ # # ]: 0 : } else if (!strcmp(params, "Invalid") ||
134 : 0 : !strcmp(params, "Merge failed"))
135 : 0 : *percent_range = PERCENT_INVALID;
136 : : else
137 : 0 : return 0;
138 : :
139 : 0 : return 1;
140 : : }
141 : :
142 : 0 : static int _snap_target_present(struct cmd_context *cmd,
143 : : const struct lv_segment *seg,
144 : : unsigned *attributes __attribute((unused)))
145 : : {
146 : : static int _snap_checked = 0;
147 : : static int _snap_merge_checked = 0;
148 : : static int _snap_present = 0;
149 : : static int _snap_merge_present = 0;
150 : :
151 [ # # ]: 0 : if (!_snap_checked) {
152 [ # # # # ]: 0 : _snap_present = target_present(cmd, "snapshot", 1) &&
153 : 0 : target_present(cmd, "snapshot-origin", 0);
154 : 0 : _snap_checked = 1;
155 : : }
156 : :
157 [ # # ][ # # ]: 0 : if (!_snap_merge_checked && seg && (seg->status & MERGING)) {
[ # # ]
158 : 0 : _snap_merge_present = target_present(cmd, "snapshot-merge", 0);
159 : 0 : _snap_merge_checked = 1;
160 [ # # # # ]: 0 : return _snap_present && _snap_merge_present;
161 : : }
162 : :
163 : 0 : return _snap_present;
164 : : }
165 : :
166 : : #ifdef DMEVENTD
167 : : static int _get_snapshot_dso_path(struct cmd_context *cmd, char **dso)
168 : : {
169 : : char *path;
170 : : const char *libpath;
171 : :
172 : : if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
173 : : log_error("Failed to allocate dmeventd library path.");
174 : : return 0;
175 : : }
176 : :
177 : : libpath = find_config_tree_str(cmd, "dmeventd/snapshot_library", NULL);
178 : : if (!libpath)
179 : : return 0;
180 : :
181 : : get_shared_library_path(cmd, libpath, path, PATH_MAX);
182 : :
183 : : *dso = path;
184 : :
185 : : return 1;
186 : : }
187 : :
188 : : static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
189 : : const char *dso,
190 : : const int timeout,
191 : : enum dm_event_mask mask)
192 : : {
193 : : struct dm_event_handler *dmevh;
194 : :
195 : : if (!(dmevh = dm_event_handler_create()))
196 : : return_0;
197 : :
198 : : if (dm_event_handler_set_dso(dmevh, dso))
199 : : goto fail;
200 : :
201 : : if (dm_event_handler_set_dev_name(dmevh, dmname))
202 : : goto fail;
203 : :
204 : : dm_event_handler_set_timeout(dmevh, timeout);
205 : : dm_event_handler_set_event_mask(dmevh, mask);
206 : : return dmevh;
207 : :
208 : : fail:
209 : : dm_event_handler_destroy(dmevh);
210 : : return NULL;
211 : : }
212 : :
213 : : static int _target_registered(struct lv_segment *seg, int *pending)
214 : : {
215 : : char *dso, *name;
216 : : struct logical_volume *lv;
217 : : struct volume_group *vg;
218 : : enum dm_event_mask evmask = 0;
219 : : struct dm_event_handler *dmevh;
220 : :
221 : : lv = seg->lv;
222 : : vg = lv->vg;
223 : :
224 : : *pending = 0;
225 : : if (!_get_snapshot_dso_path(vg->cmd, &dso))
226 : : return_0;
227 : :
228 : : if (!(name = build_dm_name(vg->cmd->mem, vg->name, seg->cow->name, NULL)))
229 : : return_0;
230 : :
231 : : if (!(dmevh = _create_dm_event_handler(name, dso, 0, DM_EVENT_ALL_ERRORS)))
232 : : return_0;
233 : :
234 : : if (dm_event_get_registered_device(dmevh, 0)) {
235 : : dm_event_handler_destroy(dmevh);
236 : : return 0;
237 : : }
238 : :
239 : : evmask = dm_event_handler_get_event_mask(dmevh);
240 : : if (evmask & DM_EVENT_REGISTRATION_PENDING) {
241 : : *pending = 1;
242 : : evmask &= ~DM_EVENT_REGISTRATION_PENDING;
243 : : }
244 : :
245 : : dm_event_handler_destroy(dmevh);
246 : :
247 : : return evmask;
248 : : }
249 : :
250 : : /* FIXME This gets run while suspended and performs banned operations. */
251 : : static int _target_set_events(struct lv_segment *seg,
252 : : int events __attribute((unused)), int set)
253 : : {
254 : : char *dso, *name;
255 : : struct volume_group *vg = seg->lv->vg;
256 : : struct dm_event_handler *dmevh;
257 : : int r;
258 : :
259 : : if (!_get_snapshot_dso_path(vg->cmd, &dso))
260 : : return_0;
261 : :
262 : : if (!(name = build_dm_name(vg->cmd->mem, vg->name, seg->cow->name, NULL)))
263 : : return_0;
264 : :
265 : : /* FIXME: make timeout configurable */
266 : : if (!(dmevh = _create_dm_event_handler(name, dso, 10,
267 : : DM_EVENT_ALL_ERRORS|DM_EVENT_TIMEOUT)))
268 : : return_0;
269 : :
270 : : r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
271 : : dm_event_handler_destroy(dmevh);
272 : : if (!r)
273 : : return_0;
274 : :
275 : : log_info("%s %s for events", set ? "Registered" : "Unregistered", name);
276 : :
277 : : return 1;
278 : : }
279 : :
280 : : static int _target_register_events(struct lv_segment *seg,
281 : : int events)
282 : : {
283 : : return _target_set_events(seg, events, 1);
284 : : }
285 : :
286 : : static int _target_unregister_events(struct lv_segment *seg,
287 : : int events)
288 : : {
289 : : return _target_set_events(seg, events, 0);
290 : : }
291 : :
292 : : #endif /* DMEVENTD */
293 : : #endif
294 : :
295 : 0 : static int _snap_modules_needed(struct dm_pool *mem,
296 : : const struct lv_segment *seg __attribute((unused)),
297 : : struct dm_list *modules)
298 : : {
299 [ # # ]: 0 : if (!str_list_add(mem, modules, "snapshot")) {
300 : 0 : log_error("snapshot string list allocation failed");
301 : 0 : return 0;
302 : : }
303 : :
304 : 0 : return 1;
305 : : }
306 : :
307 : 3 : static void _snap_destroy(const struct segment_type *segtype)
308 : : {
309 : 3 : dm_free((void *)segtype);
310 : 3 : }
311 : :
312 : : static struct segtype_handler _snapshot_ops = {
313 : : .name = _snap_name,
314 : : .text_import = _snap_text_import,
315 : : .text_export = _snap_text_export,
316 : : .target_status_compatible = _snap_target_status_compatible,
317 : : #ifdef DEVMAPPER_SUPPORT
318 : : .target_percent = _snap_target_percent,
319 : : .target_present = _snap_target_present,
320 : : #ifdef DMEVENTD
321 : : .target_monitored = _target_registered,
322 : : .target_monitor_events = _target_register_events,
323 : : .target_unmonitor_events = _target_unregister_events,
324 : : #endif
325 : : #endif
326 : : .modules_needed = _snap_modules_needed,
327 : : .destroy = _snap_destroy,
328 : : };
329 : :
330 : : #ifdef SNAPSHOT_INTERNAL
331 : 3 : struct segment_type *init_snapshot_segtype(struct cmd_context *cmd)
332 : : #else /* Shared */
333 : : struct segment_type *init_segtype(struct cmd_context *cmd);
334 : : struct segment_type *init_segtype(struct cmd_context *cmd)
335 : : #endif
336 : : {
337 : 3 : struct segment_type *segtype = dm_malloc(sizeof(*segtype));
338 : : #ifdef DMEVENTD
339 : : char *dso;
340 : : #endif
341 : :
342 [ - + ]: 3 : if (!segtype)
343 : 0 : return_NULL;
344 : :
345 : 3 : segtype->cmd = cmd;
346 : 3 : segtype->ops = &_snapshot_ops;
347 : 3 : segtype->name = "snapshot";
348 : 3 : segtype->private = NULL;
349 : 3 : segtype->flags = SEG_SNAPSHOT;
350 : :
351 : : #ifdef DMEVENTD
352 : : if (_get_snapshot_dso_path(cmd, &dso))
353 : : segtype->flags |= SEG_MONITORED;
354 : : #endif
355 : 3 : log_very_verbose("Initialised segtype: %s", segtype->name);
356 : :
357 : 3 : return segtype;
358 : : }
|