~ubuntu-branches/ubuntu/saucy/lvm2/saucy-proposed

« back to all changes in this revision

Viewing changes to lib/cache/lvmetad.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2012-08-14 14:35:57 UTC
  • mfrom: (3.1.25 sid)
  • Revision ID: package-import@ubuntu.com-20120814143557-93aill2tp3kf3o30
Tags: 2.02.95-4ubuntu1
* Merge from Debian unstable, remaining changes:
  - debian/patches/avoid-dev-block.patch: Prefer any other device name over
    names in /dev/block/ since lvm.conf won't handle this.
  - debian/rules:
    - copy .po file to .pot file for Rosetta (Ubuntu specific).
  - debian/{dmsetup,lvm2}-udeb.install:
    - install initramfs and udev hooks in udebs (Debian bug 504341).
  - auto-start VGs as their PVs are discovered (Ubuntu specific):
    - add debian/tree/lvm2/lib/udev/rules.d/85-lvm2.rules: use watershed plus
      the sledgehammer of vgscan/vgchange to turn on VGs as they come online.
    - debian/tree/lvm2/usr/share/initramfs-tools/scripts/hooks/lvm2:
      - add 85-lvm2.rules to the list of udev rules to copy.
      - depend on udev.
    - debian/control:
      - add versioned Depend on watershed in lvm2 for udev rules.
      - add Depends on watershed-udeb in lvm2-udeb for udev rules.
      - add versioned Depend/Breaks on udev in dmsetup for udev rules.
      - add Depend on initramfs-tools in dmsetup so system is not potentially
        rendered unbootable by out-of-order dpkg configuration.
    - debian/rules:
      - do not install local-top scripts since Ubuntu mounts root using udev.
      - do not install init scripts for lvm2, since udev starts LVM.
    - debian/lvm2.postinst: handle missing lvm2 init script.
    - debian/tree/dmsetup/lib/udev/rules.d/60-persistent-storage-dm.rules:
      watch dm devices for changes with inotify
  - add mountroot failure hooks to help fix bad boots (Debian bug 468115):
    - debian/tree/lvm2/usr/share/initramfs-tools/scripts/init-premount/lvm2
  - remaining changes to upstream event manager packages (Debian bug 514706):
    - debian/rules:
      - enable dmeventd during configure.
    - debian/dmeventd.{8,manpages}: install dmeventd files.
  - rename debian/clvm.defaults to debian/clvm.default so it is installed
    correctly.
  - debian/control: add dmsetup-udeb to libdevmapper1.02.1-udeb recommends.
  - debian/rules: make sure dmsetup and lvm2 initramfs-tools scripts are
    executable.  When the Ubuntu-specific ones are added with a patch,
    they may lose their executable bit.
  - Add and install clvmd resource agent
  - Add dependency on libudev-dev to libdevmapper-dev so that the .pc file
    works.
  - debian/{clvmd.ra,clvm.init}:
    - create /run/lvm if it doesn't exist.
  - debian/clvm.init:
    - exit 3 if not running on status action.
  - Call dh_installman so that our dmeventd manpage actually gets installed
  - Install the missing fsadm manpage.

 * libdevmapper-dev:
  - move .so symlinks and pkgconfig files to multiarched locations.
  - mark libdevmapper-dev M-A: same

 * libdevmapper-event1.02.1:
  - Add Breaks: dmeventd (<< 2.02.95-4ubuntu1) due to debian symbol rename

 * debian/lvm2.{preinst,postinst,postrm}:
  - Implement removal of obsolete /etc/init.d/lvm2 conffile, which
    should not have been re-introduced in Quantal.

 * Dropped Changes, included in Debian:
  - Mostly included packages for upstream event manager (Debian bug 514706).
  - debian/patches/rules-subdir.patch: removed as reordering will cause
    build failure with dmeventd.
  - debian/patches/libdm-event-static.patch: removed as other static libs
    aren't being built anymore either.
  - Update symbols for libdevmapper-event.
  - Update libdevmapper-event, dmeventd descriptions to match Debian
    boilerplate.

 * Disappeared Changes:
  - Don't install documentation in udebs. No diff found, but no docs are
    installed into udebs either.

 * Resurected Changes:
  - corrected dropping the wrong init script. Now clvm.init is shipped
    and lvm2.init is dropped in favor of udev rules as per original
    intention (LP: #1037033).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2012 Red Hat, Inc.
 
3
 *
 
4
 * This file is part of LVM2.
 
5
 *
 
6
 * This copyrighted material is made available to anyone wishing to use,
 
7
 * modify, copy, or redistribute it subject to the terms and conditions
 
8
 * of the GNU Lesser General Public License v.2.1.
 
9
 *
 
10
 * You should have received a copy of the GNU Lesser General Public License
 
11
 * along with this program; if not, write to the Free Software Foundation,
 
12
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
13
 */
 
14
 
 
15
#include "lib.h"
 
16
#include "toolcontext.h"
 
17
#include "metadata.h"
 
18
#include "device.h"
 
19
#include "lvmetad.h"
 
20
#include "lvmcache.h"
 
21
#include "lvmetad-client.h"
 
22
#include "format-text.h" // TODO for disk_locn, used as a DA representation
 
23
#include "filter.h"
 
24
 
 
25
static int _using_lvmetad = 0;
 
26
static daemon_handle _lvmetad;
 
27
 
 
28
void lvmetad_init(void)
 
29
{
 
30
        const char *socket = getenv("LVM_LVMETAD_SOCKET");
 
31
        if (_using_lvmetad) { /* configured by the toolcontext */
 
32
                _lvmetad = lvmetad_open(socket ?: DEFAULT_RUN_DIR "/lvmetad.socket");
 
33
                if (_lvmetad.socket_fd < 0 || _lvmetad.error) {
 
34
                        log_warn("WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning.", strerror(_lvmetad.error));
 
35
                        _using_lvmetad = 0;
 
36
                }
 
37
        }
 
38
}
 
39
 
 
40
/*
 
41
 * Helper; evaluate the reply from lvmetad, check for errors, print diagnostics
 
42
 * and return a summary success/failure exit code.
 
43
 *
 
44
 * If found is set, *found indicates whether or not device exists,
 
45
 * and missing device is not treated as an error.
 
46
 */
 
47
static int _lvmetad_handle_reply(daemon_reply reply, const char *action, const char *object,
 
48
                                 int *found)
 
49
{
 
50
        if (reply.error) {
 
51
                log_error("Request to %s %s%sin lvmetad gave response %s.",
 
52
                          action, object, *object ? " " : "", strerror(reply.error));
 
53
                return 0;
 
54
        }
 
55
 
 
56
        /* All OK? */
 
57
        if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
 
58
                if (found)
 
59
                        *found = 1;
 
60
                return 1;
 
61
        }
 
62
 
 
63
        /* Unknown device permitted? */
 
64
        if (found && !strcmp(daemon_reply_str(reply, "response", ""), "unknown")) {
 
65
                log_very_verbose("Request to %s %s%sin lvmetad did not find object.",
 
66
                                 action, object, *object ? " " : "");
 
67
                *found = 0;
 
68
                return 1;
 
69
        }
 
70
 
 
71
        log_error("Request to %s %s%sin lvmetad gave response %s. Reason: %s",
 
72
                  action, object, *object ? " " : "", 
 
73
                  daemon_reply_str(reply, "response", "<missing>"),
 
74
                  daemon_reply_str(reply, "reason", "<missing>"));
 
75
 
 
76
        return 0;
 
77
}
 
78
 
 
79
static int _read_mda(struct lvmcache_info *info,
 
80
                     struct format_type *fmt,
 
81
                     const struct dm_config_node *cn)
 
82
{
 
83
        struct metadata_area_ops *ops;
 
84
 
 
85
        dm_list_iterate_items(ops, &fmt->mda_ops)
 
86
                if (ops->mda_import_text && ops->mda_import_text(info, cn))
 
87
                        return 1;
 
88
 
 
89
        return 0;
 
90
}
 
91
 
 
92
static struct lvmcache_info *_pv_populate_lvmcache(
 
93
        struct cmd_context *cmd, struct dm_config_node *cn, dev_t fallback)
 
94
{
 
95
        struct device *device;
 
96
        struct id pvid, vgid;
 
97
        char mda_id[32];
 
98
        char da_id[32];
 
99
        int i = 0;
 
100
        struct dm_config_node *mda = NULL;
 
101
        struct dm_config_node *da = NULL;
 
102
        uint64_t offset, size;
 
103
        struct lvmcache_info *info;
 
104
        const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL),
 
105
                   *vgid_txt = dm_config_find_str(cn->child, "vgid", NULL),
 
106
                   *vgname = dm_config_find_str(cn->child, "vgname", NULL),
 
107
                   *fmt_name = dm_config_find_str(cn->child, "format", NULL);
 
108
        dev_t devt = dm_config_find_int(cn->child, "device", 0);
 
109
        uint64_t devsize = dm_config_find_int64(cn->child, "dev_size", 0),
 
110
                 label_sector = dm_config_find_int64(cn->child, "label_sector", 0);
 
111
 
 
112
        struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL;
 
113
 
 
114
        if (!fmt) {
 
115
                log_error("PV %s not recognised. Is the device missing?", pvid_txt);
 
116
                return NULL;
 
117
        }
 
118
 
 
119
        device = dev_cache_get_by_devt(devt, cmd->filter);
 
120
        if (!device && fallback)
 
121
                device = dev_cache_get_by_devt(fallback, cmd->filter);
 
122
 
 
123
        if (!device) {
 
124
                log_error("No device found for PV %s.", pvid_txt);
 
125
                return NULL;
 
126
        }
 
127
 
 
128
        if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) {
 
129
                log_error("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
 
130
                return NULL;
 
131
        }
 
132
 
 
133
        if (vgid_txt)
 
134
                id_read_format(&vgid, vgid_txt);
 
135
        else
 
136
                strcpy((char*)&vgid, fmt->orphan_vg_name);
 
137
 
 
138
        if (!vgname)
 
139
                vgname = fmt->orphan_vg_name;
 
140
 
 
141
        info = lvmcache_add(fmt->labeller, (const char *)&pvid, device,
 
142
                            vgname, (const char *)&vgid, 0);
 
143
 
 
144
        lvmcache_get_label(info)->sector = label_sector;
 
145
        lvmcache_set_device_size(info, devsize);
 
146
        lvmcache_del_das(info);
 
147
        lvmcache_del_mdas(info);
 
148
 
 
149
        do {
 
150
                sprintf(mda_id, "mda%d", i);
 
151
                mda = dm_config_find_node(cn->child, mda_id);
 
152
                if (mda)
 
153
                        _read_mda(info, fmt, mda);
 
154
                ++i;
 
155
        } while (mda);
 
156
 
 
157
        i = 0;
 
158
        do {
 
159
                sprintf(da_id, "da%d", i);
 
160
                da = dm_config_find_node(cn->child, da_id);
 
161
                if (da) {
 
162
                        if (!dm_config_get_uint64(da->child, "offset", &offset)) return_0;
 
163
                        if (!dm_config_get_uint64(da->child, "size", &size)) return_0;
 
164
                        lvmcache_add_da(info, offset, size);
 
165
                }
 
166
                ++i;
 
167
        } while (da);
 
168
 
 
169
        return info;
 
170
}
 
171
 
 
172
struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
 
173
{
 
174
        struct volume_group *vg = NULL;
 
175
        daemon_reply reply;
 
176
        char uuid[64];
 
177
        struct format_instance *fid;
 
178
        struct format_instance_ctx fic;
 
179
        struct dm_config_node *top;
 
180
        const char *name;
 
181
        const char *fmt_name;
 
182
        struct format_type *fmt;
 
183
        struct dm_config_node *pvcn;
 
184
        struct pv_list *pvl;
 
185
        struct lvmcache_info *info;
 
186
 
 
187
        if (!_using_lvmetad)
 
188
                return NULL;
 
189
 
 
190
        if (vgid) {
 
191
                if (!id_write_format((const struct id*)vgid, uuid, sizeof(uuid)))
 
192
                        return_0;
 
193
                reply = daemon_send_simple(_lvmetad, "vg_lookup", "uuid = %s", uuid, NULL);
 
194
        } else {
 
195
                if (!vgname)
 
196
                        log_error(INTERNAL_ERROR "VG name required (VGID not available)");
 
197
                reply = daemon_send_simple(_lvmetad, "vg_lookup", "name = %s", vgname, NULL);
 
198
        }
 
199
 
 
200
        if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
 
201
 
 
202
                top = dm_config_find_node(reply.cft->root, "metadata");
 
203
                name = daemon_reply_str(reply, "name", NULL);
 
204
 
 
205
                /* fall back to lvm2 if we don't know better */
 
206
                fmt_name = dm_config_find_str(top, "metadata/format", "lvm2");
 
207
                if (!(fmt = get_format_by_name(cmd, fmt_name))) {
 
208
                        log_error(INTERNAL_ERROR
 
209
                                  "We do not know the format (%s) reported by lvmetad.",
 
210
                                  fmt_name);
 
211
                        goto out;
 
212
                }
 
213
 
 
214
                fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
 
215
                fic.context.vg_ref.vg_name = name;
 
216
                fic.context.vg_ref.vg_id = vgid;
 
217
 
 
218
                if (!(fid = fmt->ops->create_instance(fmt, &fic)))
 
219
                        goto_out;
 
220
 
 
221
                if ((pvcn = dm_config_find_node(top, "metadata/physical_volumes")))
 
222
                        for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
 
223
                                _pv_populate_lvmcache(cmd, pvcn, 0);
 
224
 
 
225
                top->key = name;
 
226
                if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
 
227
                        goto_out;
 
228
 
 
229
                dm_list_iterate_items(pvl, &vg->pvs) {
 
230
                        if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
 
231
                                pvl->pv->label_sector = lvmcache_get_label(info)->sector;
 
232
                                pvl->pv->dev = lvmcache_device(info);
 
233
                                if (!lvmcache_fid_add_mdas_pv(info, fid)) {
 
234
                                        vg = NULL;
 
235
                                        goto_out;       /* FIXME error path */
 
236
                                }
 
237
                        } /* else probably missing */
 
238
                }
 
239
 
 
240
                lvmcache_update_vg(vg, 0);
 
241
        }
 
242
 
 
243
out:
 
244
        daemon_reply_destroy(reply);
 
245
 
 
246
        return vg;
 
247
}
 
248
 
 
249
struct _fixup_baton {
 
250
        int i;
 
251
        int find;
 
252
        int ignore;
 
253
};
 
254
 
 
255
static int _fixup_ignored(struct metadata_area *mda, void *baton) {
 
256
        struct _fixup_baton *b = baton;
 
257
        if (b->i == b->find)
 
258
                mda_set_ignored(mda, b->ignore);
 
259
        b->i ++;
 
260
        return 1;
 
261
}
 
262
 
 
263
int lvmetad_vg_update(struct volume_group *vg)
 
264
{
 
265
        char *buf = NULL;
 
266
        daemon_reply reply;
 
267
        struct dm_hash_node *n;
 
268
        struct metadata_area *mda;
 
269
        char mda_id[128], *num;
 
270
        struct pv_list *pvl;
 
271
        struct lvmcache_info *info;
 
272
        struct _fixup_baton baton;
 
273
 
 
274
        if (!vg)
 
275
                return 0;
 
276
 
 
277
        if (!_using_lvmetad)
 
278
                return 1; /* fake it */
 
279
 
 
280
        /* TODO. This is not entirely correct, since export_vg_to_buffer
 
281
         * adds trailing nodes to the buffer. We may need to use
 
282
         * export_vg_to_config_tree and format the buffer ourselves. It
 
283
         * does, however, work for now, since the garbage is well
 
284
         * formatted and has no conflicting keys with the rest of the
 
285
         * request.  */
 
286
        if (!export_vg_to_buffer(vg, &buf)) {
 
287
                log_error("Could not format VG metadata.");
 
288
                return 0;
 
289
        }
 
290
 
 
291
        reply = daemon_send_simple(_lvmetad, "vg_update", "vgname = %s", vg->name,
 
292
                                   "metadata = %b", strchr(buf, '{'), NULL);
 
293
        dm_free(buf);
 
294
 
 
295
        if (!_lvmetad_handle_reply(reply, "update VG", vg->name, NULL)) {
 
296
                daemon_reply_destroy(reply);
 
297
                return 0;
 
298
        }
 
299
 
 
300
        daemon_reply_destroy(reply);
 
301
 
 
302
        n = (vg->fid && vg->fid->metadata_areas_index) ?
 
303
                dm_hash_get_first(vg->fid->metadata_areas_index) : NULL;
 
304
        while (n) {
 
305
                mda = dm_hash_get_data(vg->fid->metadata_areas_index, n);
 
306
                strcpy(mda_id, dm_hash_get_key(vg->fid->metadata_areas_index, n));
 
307
                if ((num = strchr(mda_id, '_'))) {
 
308
                        *num = 0;
 
309
                        ++num;
 
310
                        if ((info = lvmcache_info_from_pvid(mda_id, 0))) {
 
311
                                memset(&baton, 0, sizeof(baton));
 
312
                                baton.find = atoi(num);
 
313
                                baton.ignore = mda_is_ignored(mda);
 
314
                                lvmcache_foreach_mda(info, _fixup_ignored, &baton);
 
315
                        }
 
316
                }
 
317
                n = dm_hash_get_next(vg->fid->metadata_areas_index, n);
 
318
        }
 
319
 
 
320
        dm_list_iterate_items(pvl, &vg->pvs) {
 
321
                /* NB. the PV fmt pointer is sometimes wrong during vgconvert */
 
322
                if (pvl->pv->dev && !lvmetad_pv_found(pvl->pv->id, pvl->pv->dev,
 
323
                                                      vg->fid ? vg->fid->fmt : pvl->pv->fmt,
 
324
                                                      pvl->pv->label_sector, NULL))
 
325
                        return 0;
 
326
        }
 
327
 
 
328
        return 1;
 
329
}
 
330
 
 
331
int lvmetad_vg_remove(struct volume_group *vg)
 
332
{
 
333
        char uuid[64];
 
334
        daemon_reply reply;
 
335
        int result;
 
336
 
 
337
        if (!_using_lvmetad)
 
338
                return 1; /* just fake it */
 
339
 
 
340
        if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
 
341
                return_0;
 
342
 
 
343
        reply = daemon_send_simple(_lvmetad, "vg_remove", "uuid = %s", uuid, NULL);
 
344
 
 
345
        result = _lvmetad_handle_reply(reply, "remove VG", vg->name, NULL);
 
346
 
 
347
        daemon_reply_destroy(reply);
 
348
 
 
349
        return result;
 
350
}
 
351
 
 
352
int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found)
 
353
{
 
354
        char uuid[64];
 
355
        daemon_reply reply;
 
356
        int result = 0;
 
357
        struct dm_config_node *cn;
 
358
 
 
359
        if (!_using_lvmetad)
 
360
                return_0;
 
361
 
 
362
        if (!id_write_format(&pvid, uuid, sizeof(uuid)))
 
363
                return_0;
 
364
 
 
365
        reply = daemon_send_simple(_lvmetad, "pv_lookup", "uuid = %s", uuid, NULL);
 
366
 
 
367
        if (!_lvmetad_handle_reply(reply, "lookup PV", "", found))
 
368
                goto_out;
 
369
 
 
370
        if (found && !*found)
 
371
                goto out_success;
 
372
 
 
373
        if (!(cn = dm_config_find_node(reply.cft->root, "physical_volume")))
 
374
                goto_out;
 
375
        else if (!_pv_populate_lvmcache(cmd, cn, 0))
 
376
                goto_out;
 
377
 
 
378
out_success:
 
379
        result = 1;
 
380
 
 
381
out:
 
382
        daemon_reply_destroy(reply);
 
383
 
 
384
        return result;
 
385
}
 
386
 
 
387
int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found)
 
388
{
 
389
        int result = 0;
 
390
        daemon_reply reply;
 
391
        struct dm_config_node *cn;
 
392
 
 
393
        if (!_using_lvmetad)
 
394
                return_0;
 
395
 
 
396
        reply = daemon_send_simple(_lvmetad, "pv_lookup", "device = %d", dev->dev, NULL);
 
397
 
 
398
        if (!_lvmetad_handle_reply(reply, "lookup PV", dev_name(dev), found))
 
399
                goto_out;
 
400
 
 
401
        if (found && !*found)
 
402
                goto out_success;
 
403
 
 
404
        cn = dm_config_find_node(reply.cft->root, "physical_volume");
 
405
        if (!cn || !_pv_populate_lvmcache(cmd, cn, dev->dev))
 
406
                goto_out;
 
407
 
 
408
out_success:
 
409
        result = 1;
 
410
 
 
411
out:
 
412
        daemon_reply_destroy(reply);
 
413
        return result;
 
414
}
 
415
 
 
416
int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
 
417
{
 
418
        daemon_reply reply;
 
419
        struct dm_config_node *cn;
 
420
 
 
421
        if (!_using_lvmetad)
 
422
                return 1;
 
423
 
 
424
        reply = daemon_send_simple(_lvmetad, "pv_list", NULL);
 
425
 
 
426
        if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) {
 
427
                daemon_reply_destroy(reply);
 
428
                return_0;
 
429
        }
 
430
 
 
431
        if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes")))
 
432
                for (cn = cn->child; cn; cn = cn->sib)
 
433
                        _pv_populate_lvmcache(cmd, cn, 0);
 
434
 
 
435
        daemon_reply_destroy(reply);
 
436
 
 
437
        return 1;
 
438
}
 
439
 
 
440
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
 
441
{
 
442
        struct volume_group *tmp;
 
443
        struct id vgid;
 
444
        const char *vgid_txt;
 
445
        daemon_reply reply;
 
446
        struct dm_config_node *cn;
 
447
 
 
448
        if (!_using_lvmetad)
 
449
                return 1;
 
450
 
 
451
        reply = daemon_send_simple(_lvmetad, "vg_list", NULL);
 
452
 
 
453
        if (!_lvmetad_handle_reply(reply, "list VGs", "", NULL)) {
 
454
                daemon_reply_destroy(reply);
 
455
                return_0;
 
456
        }
 
457
 
 
458
        if ((cn = dm_config_find_node(reply.cft->root, "volume_groups")))
 
459
                for (cn = cn->child; cn; cn = cn->sib) {
 
460
                        vgid_txt = cn->key;
 
461
                        if (!id_read_format(&vgid, vgid_txt)) {
 
462
                                stack;
 
463
                                continue;
 
464
                        }
 
465
 
 
466
                        /* the call to lvmetad_vg_lookup will poke the VG into lvmcache */
 
467
                        tmp = lvmetad_vg_lookup(cmd, NULL, (const char*)&vgid);
 
468
                        release_vg(tmp);
 
469
                }
 
470
 
 
471
        daemon_reply_destroy(reply);
 
472
        return 1;
 
473
}
 
474
 
 
475
struct _print_mda_baton {
 
476
        int i;
 
477
        char *buffer;
 
478
};
 
479
 
 
480
static int _print_mda(struct metadata_area *mda, void *baton)
 
481
{
 
482
        int result = 0;
 
483
        struct _print_mda_baton *b = baton;
 
484
        char *buf, *mda_txt;
 
485
 
 
486
        if (!mda->ops->mda_export_text) /* do nothing */
 
487
                return 1;
 
488
 
 
489
        buf = b->buffer;
 
490
        mda_txt = mda->ops->mda_export_text(mda);
 
491
        if (!dm_asprintf(&b->buffer, "%s mda%i { %s }", b->buffer ?: "", b->i, mda_txt))
 
492
                goto_out;
 
493
        b->i ++;
 
494
        result = 1;
 
495
out:
 
496
        dm_free(mda_txt);
 
497
        dm_free(buf);
 
498
        return result;
 
499
}
 
500
 
 
501
static int _print_da(struct disk_locn *da, void *baton)
 
502
{
 
503
        struct _print_mda_baton *b;
 
504
        char *buf;
 
505
 
 
506
        if (!da)
 
507
                return 1;
 
508
 
 
509
        b = baton;
 
510
        buf = b->buffer;
 
511
        if (!dm_asprintf(&b->buffer, "%s da%i { offset = %" PRIu64
 
512
                         " size = %" PRIu64 " }",
 
513
                         b->buffer ?: "", b->i, da->offset, da->size))
 
514
        {
 
515
                dm_free(buf);
 
516
                return_0;
 
517
        }
 
518
        b->i ++;
 
519
        dm_free(buf);
 
520
 
 
521
        return 1;
 
522
}
 
523
 
 
524
static const char *_print_mdas(struct lvmcache_info *info)
 
525
{
 
526
        struct _print_mda_baton baton = { .i = 0, .buffer = NULL };
 
527
 
 
528
        if (!lvmcache_foreach_mda(info, &_print_mda, &baton))
 
529
                return NULL;
 
530
        baton.i = 0;
 
531
        if (!lvmcache_foreach_da(info, &_print_da, &baton))
 
532
                return NULL;
 
533
 
 
534
        return baton.buffer;
 
535
}
 
536
 
 
537
int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_type *fmt,
 
538
                     uint64_t label_sector, struct volume_group *vg)
 
539
{
 
540
        char uuid[64];
 
541
        daemon_reply reply;
 
542
        struct lvmcache_info *info;
 
543
        const char *mdas = NULL;
 
544
        char *pvmeta;
 
545
        char *buf = NULL;
 
546
        int result;
 
547
 
 
548
        if (!_using_lvmetad)
 
549
                return 1;
 
550
 
 
551
        if (!id_write_format(&pvid, uuid, sizeof(uuid)))
 
552
                return_0;
 
553
 
 
554
        /* FIXME A more direct route would be much preferable. */
 
555
        if ((info = lvmcache_info_from_pvid((const char *)&pvid, 0)))
 
556
                mdas = _print_mdas(info);
 
557
 
 
558
        if (!dm_asprintf(&pvmeta,
 
559
                         "{ device = %" PRIu64 "\n"
 
560
                         "  dev_size = %" PRIu64 "\n"
 
561
                         "  format = \"%s\"\n"
 
562
                         "  label_sector = %" PRIu64 "\n"
 
563
                         "  id = \"%s\"\n"
 
564
                         "  %s"
 
565
                         "}", device->dev,
 
566
                         info ? lvmcache_device_size(info) : 0,
 
567
                         fmt->name, label_sector, uuid, mdas ?: "")) {
 
568
                dm_free((char *)mdas);
 
569
                return_0;
 
570
        }
 
571
 
 
572
        dm_free((char *)mdas);
 
573
 
 
574
        if (vg) {
 
575
                /*
 
576
                 * TODO. This is not entirely correct, since export_vg_to_buffer
 
577
                 * adds trailing garbage to the buffer. We may need to use
 
578
                 * export_vg_to_config_tree and format the buffer ourselves. It
 
579
                 * does, however, work for now, since the garbage is well
 
580
                 * formatted and has no conflicting keys with the rest of the
 
581
                 * request.
 
582
                 */
 
583
                if (!export_vg_to_buffer(vg, &buf)) {
 
584
                        dm_free(pvmeta);
 
585
                        return_0;
 
586
                }
 
587
 
 
588
                reply = daemon_send_simple(_lvmetad,
 
589
                                           "pv_found",
 
590
                                           "pvmeta = %b", pvmeta,
 
591
                                           "vgname = %s", vg->name,
 
592
                                           "metadata = %b", strchr(buf, '{'),
 
593
                                           NULL);
 
594
        } else {
 
595
                /* There are no MDAs on this PV. */
 
596
                reply = daemon_send_simple(_lvmetad,
 
597
                                           "pv_found",
 
598
                                           "pvmeta = %b", pvmeta,
 
599
                                           NULL);
 
600
        }
 
601
 
 
602
        dm_free(pvmeta);
 
603
 
 
604
        result = _lvmetad_handle_reply(reply, "update PV", uuid, NULL);
 
605
        daemon_reply_destroy(reply);
 
606
 
 
607
        return result;
 
608
}
 
609
 
 
610
int lvmetad_pv_gone(dev_t device, const char *pv_name)
 
611
{
 
612
        int result;
 
613
        int found;
 
614
 
 
615
        if (!_using_lvmetad)
 
616
                return 1;
 
617
 
 
618
        daemon_reply reply = daemon_send_simple(_lvmetad, "pv_gone", "device = %d", device, NULL);
 
619
 
 
620
        result = _lvmetad_handle_reply(reply, "drop PV", pv_name, &found);
 
621
        /* We don't care whether or not the daemon had the PV cached. */
 
622
 
 
623
        daemon_reply_destroy(reply);
 
624
 
 
625
        return result;
 
626
}
 
627
 
 
628
int lvmetad_pv_gone_by_dev(struct device *dev)
 
629
{
 
630
        return lvmetad_pv_gone(dev->dev, dev_name(dev));
 
631
}
 
632
 
 
633
int lvmetad_active(void)
 
634
{
 
635
        return _using_lvmetad;
 
636
}
 
637
 
 
638
void lvmetad_set_active(int active)
 
639
{
 
640
        _using_lvmetad = active;
 
641
}
 
642
 
 
643
/*
 
644
 * The following code implements pvscan --cache.
 
645
 */
 
646
 
 
647
struct _pvscan_lvmetad_baton {
 
648
        struct volume_group *vg;
 
649
        struct format_instance *fid;
 
650
};
 
651
 
 
652
static int _pvscan_lvmetad_single(struct metadata_area *mda, void *baton)
 
653
{
 
654
        struct _pvscan_lvmetad_baton *b = baton;
 
655
        struct volume_group *this = mda->ops->vg_read(b->fid, "", mda, 1);
 
656
 
 
657
        /* FIXME Also ensure contents match etc. */
 
658
        if (!b->vg || this->seqno > b->vg->seqno)
 
659
                b->vg = this;
 
660
        else if (b->vg)
 
661
                release_vg(this);
 
662
 
 
663
        return 1;
 
664
}
 
665
 
 
666
int pvscan_lvmetad_single(struct cmd_context *cmd, struct device *dev)
 
667
{
 
668
        struct label *label;
 
669
        struct lvmcache_info *info;
 
670
        struct physical_volume pv;
 
671
        struct _pvscan_lvmetad_baton baton;
 
672
        /* Create a dummy instance. */
 
673
        struct format_instance_ctx fic = { .type = 0 };
 
674
 
 
675
        if (!lvmetad_active()) {
 
676
                log_error("Cannot proceed since lvmetad is not active.");
 
677
                return 0;
 
678
        }
 
679
 
 
680
        if (!label_read(dev, &label, 0)) {
 
681
                log_print("No PV label found on %s.", dev_name(dev));
 
682
                if (!lvmetad_pv_gone_by_dev(dev))
 
683
                        goto_bad;
 
684
                return 1;
 
685
        }
 
686
 
 
687
        info = (struct lvmcache_info *) label->info;
 
688
        memset(&pv, 0, sizeof(pv));
 
689
 
 
690
        baton.vg = NULL;
 
691
        baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info),
 
692
                                                             &fic);
 
693
 
 
694
        lvmcache_foreach_mda(info, _pvscan_lvmetad_single, &baton);
 
695
        if (!baton.vg)
 
696
                lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
 
697
 
 
698
        /*
 
699
         * NB. If this command failed and we are relying on lvmetad to have an
 
700
         * *exact* image of the system, the lvmetad instance that went out of
 
701
         * sync needs to be killed.
 
702
         */
 
703
        if (!lvmetad_pv_found(*(struct id *)dev->pvid, dev, lvmcache_fmt(info),
 
704
                              label->sector, baton.vg)) {
 
705
                release_vg(baton.vg);
 
706
                goto_bad;
 
707
        }
 
708
 
 
709
        release_vg(baton.vg);
 
710
        return 1;
 
711
 
 
712
bad:
 
713
        /* FIXME kill lvmetad automatically if we can */
 
714
        log_error("Update of lvmetad failed. This is a serious problem.\n  "
 
715
                  "It is strongly recommended that you restart lvmetad immediately.");
 
716
        return 0;
 
717
}