From 914c97239fe2dcc551ce28f2b1b40af8c7797369 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Fri, 4 Jul 2003 22:34:56 +0000 Subject: [PATCH] Another sync point - numerous fixes & clean ups. --- VERSION | 2 +- WHATS_NEW | 5 +- doc/example.conf | 16 +- include/.symlinks | 3 +- lib/Makefile.in | 3 +- lib/activate/activate.c | 61 +++-- lib/activate/activate.h | 2 + lib/activate/dev_manager.c | 354 ++++++++++++++++++++------ lib/activate/dev_manager.h | 1 + lib/activate/fs.c | 173 ++++++++++--- lib/activate/fs.h | 1 + lib/cache/{cache.c => lvmcache.c} | 161 ++++++++---- lib/cache/{cache.h => lvmcache.h} | 41 ++-- lib/commands/toolcontext.c | 45 ++-- lib/config/config.c | 102 ++++---- lib/config/config.h | 4 +- lib/config/defaults.h | 3 + lib/datastruct/list.h | 8 + lib/datastruct/lvm-types.h | 2 +- lib/device/dev-cache.c | 70 +++++- lib/device/dev-io.c | 395 ++++++++++++++++++++++-------- lib/device/device.h | 31 ++- lib/display/display.c | 2 + lib/format1/disk-rep.c | 37 ++- lib/format1/format1.c | 10 +- lib/format1/lvm1-label.c | 6 +- lib/format_text/format-text.c | 122 +++++---- lib/format_text/import-export.h | 2 +- lib/format_text/import.c | 13 +- lib/format_text/import_vsn1.c | 2 +- lib/format_text/text_label.c | 12 +- lib/label/label.c | 36 ++- lib/label/label.h | 2 +- lib/locking/file_locking.c | 16 ++ lib/locking/locking.c | 28 +-- lib/locking/no_locking.c | 10 + lib/log/log.c | 100 +++++++- lib/log/log.h | 10 +- lib/metadata/metadata.c | 104 ++++++-- lib/metadata/metadata.h | 4 + lib/metadata/mirror.c | 2 +- lib/misc/lib.h | 1 + lib/mm/memlock.c | 144 +++++++++++ lib/mm/memlock.h | 17 ++ lib/mm/xlate.h | 37 ++- lib/report/report.c | 11 +- libdm/datastruct/list.h | 8 + man/Makefile.in | 4 +- man/lvcreate.8 | 2 +- man/lvreduce.8 | 3 - tools/archive.c | 4 +- tools/lvchange.c | 78 +++--- tools/lvcreate.c | 22 +- tools/lvm.c | 2 +- tools/lvmdiskscan.c | 4 +- tools/lvremove.c | 5 +- tools/lvrename.c | 35 ++- tools/lvresize.c | 31 ++- tools/lvscan.c | 3 - tools/pvchange.c | 2 +- tools/pvcreate.c | 1 + tools/pvmove.c | 50 ++-- tools/pvscan.c | 2 +- tools/toollib.c | 64 ++++- tools/tools.h | 6 +- tools/vgchange.c | 4 +- tools/vgck.c | 1 + tools/vgcreate.c | 2 +- tools/vgdisplay.c | 2 + tools/vgexport.c | 2 +- tools/vgextend.c | 2 +- tools/vgimport.c | 2 +- tools/vgmerge.c | 2 +- tools/vgreduce.c | 4 +- tools/vgrename.c | 3 +- tools/vgscan.c | 2 +- tools/vgsplit.c | 6 +- 77 files changed, 1889 insertions(+), 680 deletions(-) rename lib/cache/{cache.c => lvmcache.c} (71%) rename lib/cache/{cache.h => lvmcache.h} (53%) create mode 100644 lib/mm/memlock.c create mode 100644 lib/mm/memlock.h diff --git a/VERSION b/VERSION index df9e82be0..ab978981f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.95.17-cvs (2003-04-24) +2.00.00-cvs (2003-07-04) diff --git a/WHATS_NEW b/WHATS_NEW index dea2ddd94..e4cbe9eb6 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -74,7 +74,7 @@ changes. What's not finished? ==================== The internal cache. If you turn on debugging output you'll see lots of -repeated disk reads, many of which will eventually get optimised out. +repeated messages, many of which will eventually get optimised out. --test sometimes causes a command to fail (e.g. vgconvert --test) even though the real command would work: again, fixing this is waiting for @@ -91,6 +91,3 @@ Display output. Some metadata information cannot yet be displayed. Recovery tools to salvage "lost" metadata directly from the disks: but we hope the new format will mean such tools are hardly ever needed! -pvmove will be enhanced to remove the volume group lock so that you can -run other commands alongside. - diff --git a/doc/example.conf b/doc/example.conf index 8e13f5487..1db94a858 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -104,6 +104,10 @@ log { # indent = 0 # command_names = 1 # prefix = " -- " + + # Set this if you want log messages during activation. + # Don't use this in low memory situations (can deadlock). + # activation = 0 } # Configuration of metadata backups and archiving. In LVM2 when we @@ -202,6 +206,15 @@ activation { # Size (in KB) of each copy operation when mirroring mirror_region_size = 512 + + # How much stack (in KB) to reserve for use while devices suspended + reserved_stack = 256 + + # How much memory (in KB) to reserve for use while devices suspended + reserved_memory = 8192 + + # Nice value used while devices suspended + process_priority = -18 } @@ -231,7 +244,8 @@ activation { # preferably on different (non-LV) filesystems, and with no other # on-disk metadata (pvmetadatacopies = 0). Or this can be in # addition to on-disk metadata areas. - # The feature was originally added to simplify testing. + # The feature was originally added to simplify testing and is not + # supported under low memory situations - the machine could lock up. # # Never edit any files in these directories by hand unless you # you are absolutely sure you know what you are doing! Use diff --git a/include/.symlinks b/include/.symlinks index b8232bb99..b5ae5f31f 100644 --- a/include/.symlinks +++ b/include/.symlinks @@ -1,5 +1,5 @@ ../lib/activate/activate.h -../lib/cache/cache.h +../lib/cache/lvmcache.h ../lib/commands/errors.h ../lib/commands/toolcontext.h ../lib/config/config.h @@ -24,6 +24,7 @@ ../lib/log/log.h ../lib/metadata/metadata.h ../lib/mm/dbg_malloc.h +../lib/mm/memlock.h ../lib/mm/pool.h ../lib/mm/xlate.h ../lib/misc/crc.h diff --git a/lib/Makefile.in b/lib/Makefile.in index 9625d1721..96308b75c 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -14,7 +14,7 @@ endif SOURCES=\ activate/activate.c \ - cache/cache.c \ + cache/lvmcache.c \ commands/toolcontext.c \ config/config.c \ datastruct/bitset.c \ @@ -49,6 +49,7 @@ SOURCES=\ misc/crc.c \ misc/lvm-file.c \ misc/lvm-string.c \ + mm/memlock.c \ mm/pool.c \ regex/matcher.c \ regex/parse_rx.c \ diff --git a/lib/activate/activate.c b/lib/activate/activate.c index ad72ee552..8d48ee5b4 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -7,6 +7,7 @@ #include "lib.h" #include "metadata.h" #include "activate.h" +#include "memlock.h" #include "display.h" #include "fs.h" #include "lvm-string.h" @@ -16,6 +17,7 @@ #include #include +#include #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) @@ -46,7 +48,8 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent) { return 0; } -int lv_mirror_percent(struct logical_volume *lv, float *percent, int wait) +int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent, + uint32_t *event_nr) { return 0; } @@ -74,6 +77,10 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s) { return 1; } +void activation_exit(void) +{ + return; +} #else /* DEVMAPPER_SUPPORT */ @@ -340,9 +347,6 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s) if (!(lv = lv_from_lvid(cmd, lvid_s))) return 0; - if (!activation()) - return 1; - if (test_mode()) { _skip("Suspending '%s'.", lv->name); return 1; @@ -353,8 +357,15 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s) return 0; } - if (info.exists && !info.suspended) - return _lv_suspend(lv); + if (!info.exists || info.suspended) + return 1; + + memlock_inc(); + if (!_lv_suspend(lv)) { + memlock_dec(); + fs_unlock(); + return 0; + } return 1; } @@ -380,8 +391,14 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s) return 0; } - if (info.exists && info.suspended) - return _lv_activate(lv); + if (!info.exists || !info.suspended) + return 1; + + if (!_lv_activate(lv)) + return 0; + + memlock_dec(); + fs_unlock(); return 1; } @@ -390,6 +407,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) { struct logical_volume *lv; struct lvinfo info; + int r; if (!activation()) return 1; @@ -407,16 +425,22 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s) return 0; } - if (info.exists) - return _lv_deactivate(lv); + if (!info.exists) + return 1; - return 1; + memlock_inc(); + r = _lv_deactivate(lv); + memlock_dec(); + fs_unlock(); + + return r; } int lv_activate(struct cmd_context *cmd, const char *lvid_s) { struct logical_volume *lv; struct lvinfo info; + int r; if (!activation()) return 1; @@ -434,10 +458,19 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s) return 0; } - if (!info.exists || info.suspended) - return _lv_activate(lv); + if (info.exists && !info.suspended) + return 1; - return 1; + memlock_inc(); + r = _lv_activate(lv); + memlock_dec(); + fs_unlock(); + + return r; } +void activation_exit(void) +{ + dev_manager_exit(); +} #endif diff --git a/lib/activate/activate.h b/lib/activate/activate.h index 1ab2d1588..17ddd3d0c 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -28,6 +28,8 @@ int activation(void); int driver_version(char *version, size_t size); int library_version(char *version, size_t size); +void activation_exit(void); + int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s); int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s); int lv_activate(struct cmd_context *cmd, const char *lvid_s); diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index 1d95c59ae..a86817261 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -48,7 +48,8 @@ enum { READWRITE = 3, SUSPENDED = 4, NOPROPAGATE = 5, - TOPLEVEL = 6 + TOPLEVEL = 6, + REMOVE = 7 }; enum { @@ -87,6 +88,9 @@ struct dev_layer { */ struct list pre_create; + /* Inverse of pre_create */ + struct list pre_suspend; + }; struct dl_list { @@ -149,7 +153,7 @@ static inline void _clear_flag(struct dev_layer *dl, int bit) dl->flags &= ~(1 << bit); } -static int _pre_list_add(struct pool *mem, struct list *pl, char *str) +static int _pre_list_add(struct pool *mem, struct list *pl, const char *str) { struct str_list *sl; struct list *plh; @@ -159,7 +163,10 @@ static int _pre_list_add(struct pool *mem, struct list *pl, char *str) return 0; } + /* Already in list? */ list_iterate(plh, pl) { + if (!strcmp(str, list_item(plh, struct str_list)->str)) + return 1; } if (!(sl = pool_alloc(mem, sizeof(*sl)))) { @@ -633,8 +640,14 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task) log_very_verbose("Activating %s read-only", dl->name); } - if (!(r = dm_task_run(dmt))) + if (!(r = dm_task_run(dmt))) { log_error("Couldn't load device '%s'.", dl->name); + if ((dl->lv->minor >= 0 || dl->lv->major >= 0) && + _get_flag(dl, VISIBLE)) + log_error("Perhaps the persistent device number " + "%d:%d is already in use?", + dl->lv->major, dl->lv->minor); + } if (!dm_task_get_info(dmt, &dl->info)) { stack; @@ -642,6 +655,15 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task) goto out; } + if (!dl->info.exists || !dl->info.live_table) { + stack; + r = 0; + goto out; + } + + log_very_verbose("Activated %s %s %03u:%03u", dl->name, + dl->dlid, dl->info.major, dl->info.minor); + if (r && _get_flag(dl, VISIBLE)) fs_add_lv(dl->lv, dl->name); @@ -753,6 +775,8 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt, const char *target = NULL; const char *trailing_space; int mirror_status; + struct dev_layer *dl; + char devbuf[10]; switch (seg->type) { case SEG_SNAPSHOT: @@ -819,15 +843,23 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt, (seg->area[s].u.pv.pv->pe_start + (esize * seg->area[s].u.pv.pe)), trailing_space); - else + else { + if (!(dl = hash_lookup(dm->layers, + seg->area[s].u.lv.lv->lvid.s))) { + log_error("device layer %s missing from hash", + seg->area[s].u.lv.lv->lvid.s); + return 0; + } + if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major, dl->info.minor)) { + log_error("Failed to format device number as dm target (%u,%u)", + dl->info.major, dl->info.minor); + return 0; + } tw = lvm_snprintf(params + w, sizeof(params) - w, - "%s/%s %" PRIu64 "%s", dm_dir(), - _build_name(dm->mem, - seg->lv->vg->name, - seg->area[s].u.lv.lv-> - name, NULL), + "%s %" PRIu64 "%s", devbuf, esize * seg->area[s].u.lv.le, trailing_space); + } if (tw < 0) goto error; @@ -874,13 +906,20 @@ static int _populate_origin(struct dev_manager *dm, { char *real; char params[PATH_MAX + 32]; + struct dev_layer *dlr; - if (!(real = _build_name(dm->mem, dm->vg_name, dl->lv->name, "real"))) { + if (!(real = _build_dlid(dm->mem, dl->lv->lvid.s, "real"))) { stack; return 0; } - if (lvm_snprintf(params, sizeof(params), "%s/%s", dm_dir(), real) == -1) { + if (!(dlr = hash_lookup(dm->layers, real))) { + log_error("Couldn't find real device layer %s in hash", real); + return 0; + } + + if (!dm_format_dev(params, sizeof(params), dlr->info.major, + dlr->info.minor)) { log_error("Couldn't create origin device parameters for '%s'.", real); return 0; @@ -903,25 +942,37 @@ static int _populate_snapshot(struct dev_manager *dm, char *origin, *cow; char params[PATH_MAX * 2 + 32]; struct snapshot *s; + struct dev_layer *dlo, *dlc; if (!(s = find_cow(dl->lv))) { log_error("Couldn't find snapshot for '%s'.", dl->lv->name); return 0; } - if (!(origin = _build_name(dm->mem, dm->vg_name, - s->origin->name, "real"))) { + if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) { stack; return 0; } - if (!(cow = _build_name(dm->mem, dm->vg_name, s->cow->name, "cow"))) { + if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) { stack; return 0; } - if (snprintf(params, sizeof(params), "%s/%s %s/%s P %d", - dm_dir(), origin, dm_dir(), cow, s->chunk_size) == -1) { + if (!(dlo = hash_lookup(dm->layers, origin))) { + log_error("Couldn't find origin device layer %s in hash", + origin); + return 0; + } + + if (!(dlc = hash_lookup(dm->layers, cow))) { + log_error("Couldn't find cow device layer %s in hash", cow); + return 0; + } + + if (snprintf(params, sizeof(params), "%03u:%03u %03u:%03u P %d", + dlo->info.major, dlo->info.minor, + dlc->info.major, dlc->info.minor, s->chunk_size) == -1) { stack; return 0; } @@ -1108,6 +1159,7 @@ static struct dev_layer *_create_dev(struct dev_manager *dm, char *name, dl->dlid = dlid; list_init(&dl->pre_create); + list_init(&dl->pre_suspend); if (!hash_insert(dm->layers, dl->dlid, dl)) { stack; @@ -1172,12 +1224,13 @@ static struct dev_layer *_lookup(struct dev_manager *dm, return dl; } -static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv) +static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv, + int was_origin) { /* * only one layer. */ - struct dev_layer *dl; + struct dev_layer *dl, *dlr; struct list *segh; struct lv_segment *seg; uint32_t s; @@ -1205,8 +1258,8 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv) continue; if (!_pre_list_add(dm->mem, &dl->pre_create, _build_dlid(dm->mem, - seg->area[s].u.lv.lv-> - lvid.s, NULL))) { + seg->area[s].u.lv. + lv->lvid.s, NULL))) { stack; return 0; } @@ -1214,6 +1267,27 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv) } } + if (!was_origin) + return 1; + + /* Deactivating the last snapshot */ + if (!(dlr = _create_layer(dm, "real", lv))) { + stack; + return 0; + } + + dlr->populate = _populate_vanilla; + _clear_flag(dlr, VISIBLE); + _clear_flag(dlr, TOPLEVEL); + _set_flag(dlr, REMOVE); + + /* add the dependency on the real device */ + if (!_pre_list_add(dm->mem, &dl->pre_create, + pool_strdup(dm->mem, dlr->dlid))) { + stack; + return 0; + } + return 1; } @@ -1259,7 +1333,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) /* * We only need to create an origin layer if one of our - * snapshots is in the active list. + * snapshots is in the active list */ list_iterate(sh, &dm->active_list) { active = list_item(sh, struct lv_list)->lv; @@ -1267,7 +1341,10 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) return _expand_origin_real(dm, lv); } - return _expand_vanilla(dm, lv); + /* + * We're deactivating the last snapshot + */ + return _expand_vanilla(dm, lv, 1); } static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv, @@ -1298,20 +1375,26 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv, _set_flag(dl, VISIBLE); _set_flag(dl, TOPLEVEL); - /* add the dependency on the real device */ + /* add the dependency on the cow device */ if (!_pre_list_add(dm->mem, &dl->pre_create, pool_strdup(dm->mem, cow_dlid))) { stack; return 0; } - /* add the dependency on the org device */ + /* add the dependency on the real origin device */ if (!_pre_list_add(dm->mem, &dl->pre_create, _build_dlid(dm->mem, s->origin->lvid.s, "real"))) { stack; return 0; } + /* add the dependency on the visible origin device */ + if (!_pre_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) { + stack; + return 0; + } + return 1; } @@ -1331,7 +1414,7 @@ static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv) else if (lv_is_origin(lv)) return _expand_origin(dm, lv); - return _expand_vanilla(dm, lv); + return _expand_vanilla(dm, lv, 0); } /* @@ -1355,7 +1438,7 @@ static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl, int flag) { struct list *sh; - char *dlid; + const char *dlid; struct dev_layer *dep; list_iterate(sh, &dl->pre_create) { @@ -1432,25 +1515,89 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag) return 1; } -static inline int _suspend_parent(struct dev_layer *parent) +static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl) { - return (!parent || !parent->info.exists || _suspend(parent)); + struct list *sh; + struct dev_layer *dep; + const char *dlid; + + list_iterate(sh, &dl->pre_suspend) { + dlid = list_item(sh, struct str_list)->str; + + if (!(dep = hash_lookup(dm->layers, dlid))) { + log_debug("_suspend_parents couldn't find device " + "layer '%s' - skipping.", dlid); + continue; + } + + if (!strcmp(dep->dlid, dl->dlid)) { + log_error("BUG: pre-suspend loop detected (%s)", dlid); + return 0; + } + + if (!_suspend_parents(dm, dep)) { + stack; + return 0; + } + + if (dep->info.exists & !_suspend(dep)) { + stack; + return 0; + } + } + + return 1; +} + +static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl) +{ + struct list *sh; + struct dev_layer *dep; + const char *dlid; + + list_iterate(sh, &dl->pre_create) { + dlid = list_item(sh, struct str_list)->str; + + if (!(dep = hash_lookup(dm->layers, dlid))) { + log_debug("_resume_with_deps couldn't find device " + "layer '%s' - skipping.", dlid); + continue; + } + + if (!strcmp(dep->dlid, dl->dlid)) { + log_error("BUG: pre-create loop detected (%s)", dlid); + return 0; + } + + if (!_resume_with_deps(dm, dep)) { + stack; + return 0; + } + } + + if (dl->info.exists & !_get_flag(dl, SUSPENDED) && + !_resume(dl)) { + stack; + return 0; + } + + return 1; } /* * Recurses through the tree, ensuring that devices are created * in correct order. */ -static int _create_rec(struct dev_manager *dm, struct dev_layer *dl, - struct dev_layer *parent) +static int _create_rec(struct dev_manager *dm, struct dev_layer *dl) { struct list *sh; struct dev_layer *dep; - char *dlid, *newname, *suffix; + const char *dlid; + char *newname, *suffix; - /* FIXME Create and use a _suspend_parents() function instead */ /* Suspend? */ - if (_get_flag(dl, SUSPENDED) && (!_suspend_parent || !_suspend(dl))) { + if (_get_flag(dl, SUSPENDED) && + (!_suspend_parents(dm, dl) || !_suspend(dl))) { stack; return 0; } @@ -1463,17 +1610,12 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl, return 0; } - if (!_suspend_parent(parent)) { - stack; - return 0; - } - if (!strcmp(dep->dlid, dl->dlid)) { log_error("BUG: pre-create loop detected (%s)", dlid); return 0; } - if (!_create_rec(dm, dep, dl)) { + if (!_create_rec(dm, dep)) { stack; return 0; } @@ -1486,7 +1628,7 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl, newname = _build_name(dm->mem, dm->vg_name, dl->lv->name, suffix); if (strcmp(newname, dl->name)) { - if (!_suspend_parent(parent) || + if (!_suspend_parents(dm, dl) || !_suspend(dl) || !_rename(dl, newname)) { stack; return 0; @@ -1496,7 +1638,7 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl, /* Create? */ if (!dl->info.exists) { - if (!_suspend_parent(parent) || + if (!_suspend_parents(dm, dl) || !_load(dm, dl, DM_DEVICE_CREATE)) { stack; return 0; @@ -1506,21 +1648,16 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl, /* Reload? */ if (_get_flag(dl, RELOAD) && - (!_suspend_parent(parent) || !_suspend(dl) || + (!_suspend_parents(dm, dl) || !_suspend(dl) || !_load(dm, dl, DM_DEVICE_RELOAD))) { stack; return 0; } - /* Resume? */ - if (!_get_flag(dl, SUSPENDED) && (!_suspend_parent || !_resume(dl))) { - stack; - return 0; - } - return 1; } + static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg) { struct list *lvh; @@ -1549,6 +1686,9 @@ static int _fill_in_remove_list(struct dev_manager *dm) hash_iterate(hn, dm->layers) { dl = hash_get_data(dm->layers, hn); + if (_get_flag(dl, REMOVE)) + _clear_flag(dl, ACTIVE); + if (!_get_flag(dl, ACTIVE)) { dll = pool_alloc(dm->mem, sizeof(*dll)); if (!dll) { @@ -1564,6 +1704,55 @@ static int _fill_in_remove_list(struct dev_manager *dm) return 1; } +static int _populate_pre_suspend_lists(struct dev_manager *dm) +{ + struct hash_node *hn; + struct dev_layer *dl; + struct list *sh; + const char *dlid; + struct dev_layer *dep; + + hash_iterate(hn, dm->layers) { + dl = hash_get_data(dm->layers, hn); + + list_iterate(sh, &dl->pre_suspend) { + dlid = list_item(sh, struct str_list)->str; + + if (!(dep = hash_lookup(dm->layers, dlid))) { + log_debug("_populate_pre_suspend_lists: " + "Couldn't find device layer '%s' - " + "skipping.", dlid); + continue; + } + + if (!_pre_list_add(dm->mem, &dep->pre_create, + dl->dlid)) { + stack; + return 0; + } + } + + list_iterate(sh, &dl->pre_create) { + dlid = list_item(sh, struct str_list)->str; + + if (!(dep = hash_lookup(dm->layers, dlid))) { + log_debug("_populate_pre_suspend_lists: " + "Couldn't find device layer '%s' - " + "skipping.", dlid); + continue; + } + + if (!_pre_list_add(dm->mem, &dep->pre_suspend, + dl->dlid)) { + stack; + return 0; + } + } + } + + return 1; +} + /* * Layers are removed in a top-down manner. */ @@ -1649,6 +1838,11 @@ static int _execute(struct dev_manager *dm, struct volume_group *vg) return 0; } + if (!_populate_pre_suspend_lists(dm)) { + stack; + return 0; + } + /* * Now only top level devices will be unmarked. */ @@ -1656,7 +1850,20 @@ static int _execute(struct dev_manager *dm, struct volume_group *vg) dl = hash_get_data(dm->layers, hn); if (_get_flag(dl, ACTIVE) && _get_flag(dl, TOPLEVEL)) - _create_rec(dm, dl, NULL); + if (!_create_rec(dm, dl)) { + stack; + return 0; + } + } + + /* Resume devices */ + hash_iterate(hn, dm->layers) { + dl = hash_get_data(dm->layers, hn); + + if (!_resume_with_deps(dm, dl)) { + stack; + return 0; + } } if (!_remove_old_layers(dm)) { @@ -1708,41 +1915,41 @@ static int _add_existing_layer(struct dev_manager *dm, const char *name) return 1; } -/* FIXME Get this info directly from the driver not the unreliable fs */ static int _scan_existing_devices(struct dev_manager *dm) { - const char *dev_dir = dm_dir(); - int r = 1; - const char *name; - struct dirent *dirent; - DIR *d; + int r = 0; + struct dm_names *names; + unsigned next = 0; - if (!(d = opendir(dev_dir))) { - log_sys_error("opendir", dev_dir); + struct dm_task *dmt; + + if (!(dmt = dm_task_create(DM_DEVICE_LIST))) return 0; - } - while ((dirent = readdir(d))) { - name = dirent->d_name; + if (!dm_task_run(dmt)) + goto out; - if (name[0] == '.') - continue; + if (!(names = dm_task_get_names(dmt))) + goto out; - /* - * Does this layer belong to us ? - */ - if (_belong_to_vg(dm->vg_name, name) && - !_add_existing_layer(dm, name)) { + r = 1; + if (!names->dev) + goto out; + + do { + names = (void *) names + next; + if (_belong_to_vg(dm->vg_name, names->name) && + !_add_existing_layer(dm, names->name)) { stack; r = 0; break; } - } - - if (closedir(d)) - log_sys_error("closedir", dev_dir); + next = names->next; + } while (next); + out: + dm_task_destroy(dmt); return r; } @@ -1953,3 +2160,8 @@ int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv) { return _action(dm, lv, SUSPEND); } + +void dev_manager_exit(void) +{ + dm_lib_exit(); +} diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h index 025957ce4..09350dc6f 100644 --- a/lib/activate/dev_manager.h +++ b/lib/activate/dev_manager.h @@ -19,6 +19,7 @@ struct dm_info; struct dev_manager *dev_manager_create(const char *vg_name, struct config_tree *cf); void dev_manager_destroy(struct dev_manager *dm); +void dev_manager_exit(void); /* * The device handler is responsible for creating all the layered diff --git a/lib/activate/fs.c b/lib/activate/fs.c index e116512b5..fbdfff90a 100644 --- a/lib/activate/fs.c +++ b/lib/activate/fs.c @@ -9,6 +9,7 @@ #include "toolcontext.h" #include "lvm-string.h" #include "lvm-file.h" +#include "memlock.h" #include #include @@ -17,12 +18,12 @@ #include #include -static int _mk_dir(struct volume_group *vg) +static int _mk_dir(const char *dev_dir, const char *vg_name) { char vg_path[PATH_MAX]; if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s", - vg->cmd->dev_dir, vg->name) == -1) { + dev_dir, vg_name) == -1) { log_error("Couldn't construct name of volume " "group directory."); return 0; @@ -40,12 +41,12 @@ static int _mk_dir(struct volume_group *vg) return 1; } -static int _rm_dir(struct volume_group *vg) +static int _rm_dir(const char *dev_dir, const char *vg_name) { char vg_path[PATH_MAX]; if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s", - vg->cmd->dev_dir, vg->name) == -1) { + dev_dir, vg_name) == -1) { log_error("Couldn't construct name of volume " "group directory."); return 0; @@ -93,37 +94,38 @@ static void _rm_blks(const char *dir) } } -static int _mk_link(struct logical_volume *lv, const char *dev) +static int _mk_link(const char *dev_dir, const char *vg_name, + const char *lv_name, const char *dev) { char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX]; char vg_path[PATH_MAX]; struct stat buf; if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s", - lv->vg->cmd->dev_dir, lv->vg->name) == -1) { + dev_dir, vg_name) == -1) { log_error("Couldn't create path for volume group dir %s", - lv->vg->name); + vg_name); return 0; } if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path, - lv->name) == -1) { + lv_name) == -1) { log_error("Couldn't create source pathname for " - "logical volume link %s", lv->name); + "logical volume link %s", lv_name); return 0; } if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s", dm_dir(), dev) == -1) { log_error("Couldn't create destination pathname for " - "logical volume link for %s", lv->name); + "logical volume link for %s", lv_name); return 0; } if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group", vg_path) == -1) { log_error("Couldn't create pathname for LVM1 group file for %s", - lv->vg->name); + vg_name); return 0; } @@ -167,13 +169,14 @@ static int _mk_link(struct logical_volume *lv, const char *dev) return 1; } -static int _rm_link(struct logical_volume *lv, const char *lv_name) +static int _rm_link(const char *dev_dir, const char *vg_name, + const char *lv_name) { struct stat buf; char lv_path[PATH_MAX]; if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s", - lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) { + dev_dir, vg_name, lv_name) == -1) { log_error("Couldn't determine link pathname."); return 0; } @@ -192,35 +195,143 @@ static int _rm_link(struct logical_volume *lv, const char *lv_name) return 1; } -int fs_add_lv(struct logical_volume *lv, const char *dev) +typedef enum { + FS_ADD, + FS_DEL, + FS_RENAME +} fs_op_t; + +static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, + const char *lv_name, const char *dev, + const char *old_lv_name) { - if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) { - stack; - return 0; + switch (type) { + case FS_ADD: + if (!_mk_dir(dev_dir, vg_name) || + !_mk_link(dev_dir, vg_name, lv_name, dev)) { + stack; + return 0; + } + break; + case FS_DEL: + if (!_rm_link(dev_dir, vg_name, lv_name) || + !_rm_dir(dev_dir, vg_name)) { + stack; + return 0; + } + break; + /* FIXME Use rename() */ + case FS_RENAME: + if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name)) + stack; + + if (!_mk_link(dev_dir, vg_name, lv_name, dev)) + stack; } return 1; } +static LIST_INIT(_fs_ops); + +struct fs_op_parms { + struct list list; + fs_op_t type; + char *dev_dir; + char *vg_name; + char *lv_name; + char *dev; + char *old_lv_name; + char names[0]; +}; + +static void _store_str(char **pos, char **ptr, const char *str) +{ + strcpy(*pos, str); + *ptr = *pos; + *pos += strlen(*ptr) + 1; +} + +static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, + const char *lv_name, const char *dev, + const char *old_lv_name) +{ + struct fs_op_parms *fsp; + size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) + + strlen(dev) + strlen(old_lv_name) + 5; + char *pos; + + if (!(fsp = dbg_malloc(sizeof(*fsp) + len))) { + log_error("No space to stack fs operation"); + return 0; + } + + pos = fsp->names; + fsp->type = type; + + _store_str(&pos, &fsp->dev_dir, dev_dir); + _store_str(&pos, &fsp->vg_name, vg_name); + _store_str(&pos, &fsp->lv_name, lv_name); + _store_str(&pos, &fsp->dev, dev); + _store_str(&pos, &fsp->old_lv_name, old_lv_name); + + list_add(&_fs_ops, &fsp->list); + + return 1; +} + +static void _pop_fs_ops(void) +{ + struct list *fsph, *fspht; + struct fs_op_parms *fsp; + + list_iterate_safe(fsph, fspht, &_fs_ops) { + fsp = list_item(fsph, struct fs_op_parms); + _do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name, + fsp->dev, fsp->old_lv_name); + list_del(&fsp->list); + dbg_free(fsp); + } +} + +static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, + const char *lv_name, const char *dev, const char *old_lv_name) +{ + if (memlock()) { + if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev, + old_lv_name)) { + stack; + return 0; + } + return 1; + } + + return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name); +} + +int fs_add_lv(struct logical_volume *lv, const char *dev) +{ + return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, + dev, ""); +} + int fs_del_lv(struct logical_volume *lv) { - if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) { - stack; - return 0; - } - - return 1; + return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, + "", ""); } -/* FIXME Use rename() */ int fs_rename_lv(struct logical_volume *lv, const char *dev, const char *old_name) { - if (old_name && !_rm_link(lv, old_name)) - stack; - - if (!_mk_link(lv, dev)) - stack; - - return 1; + return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name, + dev, old_name); +} + +void fs_unlock(void) +{ + if (!memlock()) { + dm_lib_release(); + _pop_fs_ops(); + } } diff --git a/lib/activate/fs.h b/lib/activate/fs.h index 5191f43bd..fc72d5a79 100644 --- a/lib/activate/fs.h +++ b/lib/activate/fs.h @@ -18,5 +18,6 @@ int fs_add_lv(struct logical_volume *lv, const char *dev); int fs_del_lv(struct logical_volume *lv); int fs_rename_lv(struct logical_volume *lv, const char *dev, const char *old_name); +void fs_unlock(void); #endif diff --git a/lib/cache/cache.c b/lib/cache/lvmcache.c similarity index 71% rename from lib/cache/cache.c rename to lib/cache/lvmcache.c index a3b5eccc1..5d4fb521b 100644 --- a/lib/cache/cache.c +++ b/lib/cache/lvmcache.c @@ -6,20 +6,23 @@ */ #include "lib.h" -#include "cache.h" +#include "lvmcache.h" #include "hash.h" #include "toolcontext.h" #include "dev-cache.h" #include "metadata.h" #include "filter.h" +#include "memlock.h" static struct hash_table *_pvid_hash = NULL; static struct hash_table *_vgid_hash = NULL; static struct hash_table *_vgname_hash = NULL; +static struct hash_table *_lock_hash = NULL; static struct list _vginfos; -int _has_scanned = 0; +static int _has_scanned = 0; +static int _vgs_locked = 0; -int cache_init(void) +int lvmcache_init(void) { list_init(&_vginfos); @@ -32,12 +35,52 @@ int cache_init(void) if (!(_pvid_hash = hash_create(128))) return 0; + if (!(_lock_hash = hash_create(128))) + return 0; + return 1; } -struct cache_vginfo *vginfo_from_vgname(const char *vgname) +void lvmcache_lock_vgname(const char *vgname, int read_only) { - struct cache_vginfo *vginfo; + if (!_lock_hash && !lvmcache_init()) { + log_error("Internal cache initialisation failed"); + return; + } + + if (!hash_insert(_lock_hash, vgname, (void *) 1)) + log_error("Cache locking failure for %s", vgname); + + _vgs_locked++; +} + +static int _vgname_is_locked(const char *vgname) __attribute__ ((unused)); +static int _vgname_is_locked(const char *vgname) +{ + if (!_lock_hash) + return 0; + + return hash_lookup(_lock_hash, vgname) ? 1 : 0; +} + +void lvmcache_unlock_vgname(const char *vgname) +{ + /* FIXME: Clear all CACHE_LOCKED flags in this vg */ + hash_remove(_lock_hash, vgname); + + /* FIXME Do this per-VG */ + if (!--_vgs_locked) + dev_close_all(); +} + +int vgs_locked(void) +{ + return _vgs_locked; +} + +struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname) +{ + struct lvmcache_vginfo *vginfo; if (!_vgname_hash) return NULL; @@ -50,7 +93,7 @@ struct cache_vginfo *vginfo_from_vgname(const char *vgname) const struct format_type *fmt_from_vgname(const char *vgname) { - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; if (!(vginfo = vginfo_from_vgname(vgname))) return NULL; @@ -58,9 +101,9 @@ const struct format_type *fmt_from_vgname(const char *vgname) return vginfo->fmt; } -struct cache_vginfo *vginfo_from_vgid(const char *vgid) +struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid) { - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; char id[ID_LEN + 1]; if (!_vgid_hash || !vgid) @@ -76,9 +119,9 @@ struct cache_vginfo *vginfo_from_vgid(const char *vgid) return vginfo; } -struct cache_info *info_from_pvid(const char *pvid) +struct lvmcache_info *info_from_pvid(const char *pvid) { - struct cache_info *info; + struct lvmcache_info *info; char id[ID_LEN + 1]; if (!_pvid_hash || !pvid) @@ -93,7 +136,7 @@ struct cache_info *info_from_pvid(const char *pvid) return info; } -static void _rescan_entry(struct cache_info *info) +static void _rescan_entry(struct lvmcache_info *info) { struct label *label; @@ -108,7 +151,7 @@ static int _scan_invalid(void) return 1; } -int cache_label_scan(struct cmd_context *cmd, int full_scan) +int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) { struct label *label; struct dev_iter *iter; @@ -125,7 +168,7 @@ int cache_label_scan(struct cmd_context *cmd, int full_scan) _scanning_in_progress = 1; - if (!_vgname_hash && !cache_init()) { + if (!_vgname_hash && !lvmcache_init()) { log_error("Internal cache initialisation failed"); goto out; } @@ -162,12 +205,12 @@ int cache_label_scan(struct cmd_context *cmd, int full_scan) return r; } -struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan) +struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan) { struct list *vgih, *vgnames; struct str_list *sl; - cache_label_scan(cmd, full_scan); + lvmcache_label_scan(cmd, full_scan); if (!(vgnames = pool_alloc(cmd->mem, sizeof(struct list)))) { log_error("vgnames list allocation failed"); @@ -183,7 +226,7 @@ struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan) } if (!(sl->str = pool_strdup(cmd->mem, list_item(vgih, - struct cache_vginfo)-> + struct lvmcache_vginfo)-> vgname))) { log_error("vgname allocation failed"); return NULL; @@ -197,34 +240,37 @@ struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan) struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid) { struct label *label; - struct cache_info *info; + struct lvmcache_info *info; /* Already cached ? */ if ((info = info_from_pvid((char *) pvid))) { if (label_read(info->dev, &label)) { - info = (struct cache_info *) label->info; + info = (struct lvmcache_info *) label->info; if (id_equal(pvid, (struct id *) &info->dev->pvid)) return info->dev; } } - cache_label_scan(cmd, 0); + lvmcache_label_scan(cmd, 0); /* Try again */ if ((info = info_from_pvid((char *) pvid))) { if (label_read(info->dev, &label)) { - info = (struct cache_info *) label->info; + info = (struct lvmcache_info *) label->info; if (id_equal(pvid, (struct id *) &info->dev->pvid)) return info->dev; } } - cache_label_scan(cmd, 1); + if (memlock()) + return NULL; + + lvmcache_label_scan(cmd, 1); /* Try again */ if ((info = info_from_pvid((char *) pvid))) { if (label_read(info->dev, &label)) { - info = (struct cache_info *) label->info; + info = (struct lvmcache_info *) label->info; if (id_equal(pvid, (struct id *) &info->dev->pvid)) return info->dev; } @@ -233,7 +279,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid) return NULL; } -static void _drop_vginfo(struct cache_info *info) +static void _drop_vginfo(struct lvmcache_info *info) { if (!list_empty(&info->list)) { list_del(&info->list); @@ -254,7 +300,7 @@ static void _drop_vginfo(struct cache_info *info) } /* Unused -void cache_del(struct cache_info *info) +void lvmcache_del(struct lvmcache_info *info) { if (info->dev->pvid[0] && _pvid_hash) hash_remove(_pvid_hash, info->dev->pvid); @@ -268,7 +314,7 @@ void cache_del(struct cache_info *info) return; } */ -static int _cache_update_pvid(struct cache_info *info, const char *pvid) +static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid) { if (!strcmp(info->dev->pvid, pvid)) return 1; @@ -277,14 +323,14 @@ static int _cache_update_pvid(struct cache_info *info, const char *pvid) } strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid)); if (!hash_insert(_pvid_hash, pvid, info)) { - log_error("_cache_update: pvid insertion failed: %s", pvid); + log_error("_lvmcache_update: pvid insertion failed: %s", pvid); return 0; } return 1; } -static int _cache_update_vgid(struct cache_info *info, const char *vgid) +static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid) { if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid))) @@ -297,18 +343,18 @@ static int _cache_update_vgid(struct cache_info *info, const char *vgid) strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid)); info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0'; - if (!hash_insert(_vgid_hash, vgid, info->vginfo)) { - log_error("_cache_update: vgid hash insertion failed: %s", - vgid); + if (!hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) { + log_error("_lvmcache_update: vgid hash insertion failed: %s", + info->vginfo->vgid); return 0; } return 1; } -int cache_update_vgname(struct cache_info *info, const char *vgname) +int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname) { - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; /* If vgname is NULL and we don't already have a vgname, * assume ORPHAN - we want every entry to have a vginfo @@ -326,7 +372,7 @@ int cache_update_vgname(struct cache_info *info, const char *vgname) /* Get existing vginfo or create new one */ if (!(vginfo = vginfo_from_vgname(vgname))) { if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) { - log_error("cache_update_vgname: list alloc failed"); + log_error("lvmcache_update_vgname: list alloc failed"); return 0; } memset(vginfo, 0, sizeof(*vginfo)); @@ -359,11 +405,11 @@ int cache_update_vgname(struct cache_info *info, const char *vgname) return 1; } -int cache_update_vg(struct volume_group *vg) +int lvmcache_update_vg(struct volume_group *vg) { struct list *pvh; struct physical_volume *pv; - struct cache_info *info; + struct lvmcache_info *info; char pvid_s[ID_LEN + 1]; int vgid_updated = 0; @@ -374,9 +420,9 @@ int cache_update_vg(struct volume_group *vg) strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1); /* FIXME Could pv->dev->pvid ever be different? */ if ((info = info_from_pvid(pvid_s))) { - cache_update_vgname(info, vg->name); + lvmcache_update_vgname(info, vg->name); if (!vgid_updated) { - _cache_update_vgid(info, (char *) &vg->id); + _lvmcache_update_vgid(info, (char *) &vg->id); vgid_updated = 1; } } @@ -385,15 +431,15 @@ int cache_update_vg(struct volume_group *vg) return 1; } -struct cache_info *cache_add(struct labeller *labeller, const char *pvid, - struct device *dev, - const char *vgname, const char *vgid) +struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, + struct device *dev, + const char *vgname, const char *vgid) { struct label *label; - struct cache_info *existing, *info; + struct lvmcache_info *existing, *info; char pvid_s[ID_LEN + 1]; - if (!_vgname_hash && !cache_init()) { + if (!_vgname_hash && !lvmcache_init()) { log_error("Internal cache initialisation failed"); return NULL; } @@ -408,7 +454,7 @@ struct cache_info *cache_add(struct labeller *labeller, const char *pvid, return NULL; } if (!(info = dbg_malloc(sizeof(*info)))) { - log_error("cache_info allocation failed"); + log_error("lvmcache_info allocation failed"); label_destroy(label); return NULL; } @@ -456,7 +502,7 @@ struct cache_info *cache_add(struct labeller *labeller, const char *pvid, info->fmt = (const struct format_type *) labeller->private; info->status |= CACHE_INVALID; - if (!_cache_update_pvid(info, pvid_s)) { + if (!_lvmcache_update_pvid(info, pvid_s)) { if (!existing) { dbg_free(info); label_destroy(label); @@ -464,7 +510,7 @@ struct cache_info *cache_add(struct labeller *labeller, const char *pvid, return NULL; } - if (!cache_update_vgname(info, vgname)) { + if (!lvmcache_update_vgname(info, vgname)) { if (!existing) { hash_remove(_pvid_hash, pvid_s); strcpy(info->dev->pvid, ""); @@ -474,14 +520,14 @@ struct cache_info *cache_add(struct labeller *labeller, const char *pvid, return NULL; } - if (!_cache_update_vgid(info, vgid)) + if (!_lvmcache_update_vgid(info, vgid)) /* Non-critical */ stack; return info; } -static void _cache_destroy_entry(struct cache_info *info) +static void _lvmcache_destroy_entry(struct lvmcache_info *info) { if (!list_empty(&info->list)) list_del(&info->list); @@ -490,14 +536,19 @@ static void _cache_destroy_entry(struct cache_info *info) dbg_free(info); } -static void _cache_destroy_vgnamelist(struct cache_vginfo *vginfo) +static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo) { if (vginfo->vgname) dbg_free(vginfo->vgname); dbg_free(vginfo); } -void cache_destroy(void) +static void _lvmcache_destroy_lockname(int present) +{ + /* Nothing to do */ +} + +void lvmcache_destroy(void) { _has_scanned = 0; @@ -507,15 +558,23 @@ void cache_destroy(void) } if (_pvid_hash) { - hash_iter(_pvid_hash, (iterate_fn) _cache_destroy_entry); + hash_iter(_pvid_hash, (iterate_fn) _lvmcache_destroy_entry); hash_destroy(_pvid_hash); _pvid_hash = NULL; } if (_vgname_hash) { - hash_iter(_vgname_hash, (iterate_fn) _cache_destroy_vgnamelist); + hash_iter(_vgname_hash, + (iterate_fn) _lvmcache_destroy_vgnamelist); hash_destroy(_vgname_hash); _vgname_hash = NULL; } + + if (_lock_hash) { + hash_iter(_lock_hash, (iterate_fn) _lvmcache_destroy_lockname); + hash_destroy(_lock_hash); + _lock_hash = NULL; + } + list_init(&_vginfos); } diff --git a/lib/cache/cache.h b/lib/cache/lvmcache.h similarity index 53% rename from lib/cache/cache.h rename to lib/cache/lvmcache.h index e790d302d..ebef2ba85 100644 --- a/lib/cache/cache.h +++ b/lib/cache/lvmcache.h @@ -15,24 +15,25 @@ #define ORPHAN "" -#define CACHE_INVALID 0x00000001 +#define CACHE_INVALID 0x00000001 +#define CACHE_LOCKED 0x00000002 /* LVM specific per-volume info */ /* Eventual replacement for struct physical_volume perhaps? */ -struct cache_vginfo { +struct lvmcache_vginfo { struct list list; /* Join these vginfos together */ - struct list infos; /* List head for cache_infos */ + struct list infos; /* List head for lvmcache_infos */ char *vgname; /* "" == orphan */ char vgid[ID_LEN + 1]; const struct format_type *fmt; }; -struct cache_info { +struct lvmcache_info { struct list list; /* Join VG members together */ struct list mdas; /* list head for metadata areas */ struct list das; /* list head for data areas */ - struct cache_vginfo *vginfo; /* NULL == unknown */ + struct lvmcache_vginfo *vginfo; /* NULL == unknown */ struct label *label; const struct format_type *fmt; struct device *dev; @@ -40,31 +41,35 @@ struct cache_info { uint32_t status; }; -int cache_init(void); -void cache_destroy(void); +int lvmcache_init(void); +void lvmcache_destroy(void); /* Set full_scan to 1 to reread every filtered device label */ -int cache_label_scan(struct cmd_context *cmd, int full_scan); +int lvmcache_label_scan(struct cmd_context *cmd, int full_scan); /* Add/delete a device */ -struct cache_info *cache_add(struct labeller *labeller, const char *pvid, - struct device *dev, - const char *vgname, const char *vgid); -void cache_del(struct cache_info *info); +struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, + struct device *dev, + const char *vgname, const char *vgid); +void lvmcache_del(struct lvmcache_info *info); /* Update things */ -int cache_update_vgname(struct cache_info *info, const char *vgname); -int cache_update_vg(struct volume_group *vg); +int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname); +int lvmcache_update_vg(struct volume_group *vg); + +void lvmcache_lock_vgname(const char *vgname, int read_only); +void lvmcache_unlock_vgname(const char *vgname); /* Queries */ const struct format_type *fmt_from_vgname(const char *vgname); -struct cache_vginfo *vginfo_from_vgname(const char *vgname); -struct cache_vginfo *vginfo_from_vgid(const char *vgid); -struct cache_info *info_from_pvid(const char *pvid); +struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname); +struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid); +struct lvmcache_info *info_from_pvid(const char *pvid); struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid); +int vgs_locked(void); /* Returns list of struct str_lists containing pool-allocated copy of vgnames */ /* Set full_scan to 1 to reread every filtered device label */ -struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan); +struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan); #endif diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 564658d01..496ac6160 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -20,6 +20,7 @@ #include "lvm-file.h" #include "format-text.h" #include "display.h" +#include "memlock.h" #ifdef HAVE_LIBDL #include "sharedlib.h" @@ -34,6 +35,10 @@ #include #include +#ifdef linux +# include +#endif + static FILE *_log; static int _get_env_vars(struct cmd_context *cmd) @@ -55,7 +60,7 @@ static int _get_env_vars(struct cmd_context *cmd) static void _init_logging(struct cmd_context *cmd) { - const char *open_mode = "a"; + int append = 1; time_t t; const char *log_file; @@ -100,16 +105,18 @@ static void _init_logging(struct cmd_context *cmd) /* Settings for logging to file */ if (find_config_int(cmd->cf->root, "log/overwrite", '/', DEFAULT_OVERWRITE)) - open_mode = "w"; + append = 0; log_file = find_config_str(cmd->cf->root, "log/file", '/', 0); - if (log_file) { - /* set up the logging */ - if (!(_log = fopen(log_file, open_mode))) - log_error("Couldn't open log file %s", log_file); - else - init_log(_log); - } + if (log_file) + init_log_file(log_file, append); + + log_file = find_config_str(cmd->cf->root, "log/activate_file", '/', 0); + if (log_file) + init_log_direct(log_file, append); + + init_log_while_suspended(find_config_int(cmd->cf->root, + "log/activation", '/', 0)); t = time(NULL); log_verbose("Logging initialised at %s", ctime(&t)); @@ -285,7 +292,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd) static int _init_filters(struct cmd_context *cmd) { - const char *lvm_cache; + const char *dev_cache; struct dev_filter *f3, *f4; struct stat st; char cache_file[PATH_MAX]; @@ -302,9 +309,9 @@ static int _init_filters(struct cmd_context *cmd) return 0; } - lvm_cache = + dev_cache = find_config_str(cmd->cf->root, "devices/cache", '/', cache_file); - if (!(f4 = persistent_filter_create(f3, lvm_cache))) { + if (!(f4 = persistent_filter_create(f3, dev_cache))) { log_error("Failed to create persistent device filter"); return 0; } @@ -316,11 +323,11 @@ static int _init_filters(struct cmd_context *cmd) if (!*cmd->sys_dir) cmd->dump_filter = 0; - if (!stat(lvm_cache, &st) && + if (!stat(dev_cache, &st) && (st.st_mtime > config_file_timestamp(cmd->cf)) && !persistent_filter_load(f4)) log_verbose("Failed to load existing device cache from %s", - lvm_cache); + dev_cache); cmd->filter = f4; @@ -411,6 +418,10 @@ struct cmd_context *create_toolcontext(struct arg *the_args) { struct cmd_context *cmd; +#ifdef M_MMAP_MAX + mallopt(M_MMAP_MAX, 0); +#endif + if (!setlocale(LC_ALL, "")) log_error("setlocale failed"); @@ -452,6 +463,8 @@ struct cmd_context *create_toolcontext(struct arg *the_args) return 0; } + memlock_init(cmd); + if (!_init_formats(cmd)) goto error; @@ -487,7 +500,8 @@ void destroy_toolcontext(struct cmd_context *cmd) if (cmd->dump_filter) persistent_filter_dump(cmd->filter); - cache_destroy(); + activation_exit(); + lvmcache_destroy(); label_exit(); _destroy_formats(&cmd->formats); cmd->filter->destroy(cmd->filter); @@ -496,6 +510,7 @@ void destroy_toolcontext(struct cmd_context *cmd) destroy_config_tree(cmd->cf); dbg_free(cmd); + release_log_memory(); dump_memory(); fin_log(); fin_syslog(); diff --git a/lib/config/config.c b/lib/config/config.c index 034b9b284..f51adf15d 100644 --- a/lib/config/config.c +++ b/lib/config/config.c @@ -110,14 +110,15 @@ void destroy_config_tree(struct config_tree *cf) pool_destroy(((struct cs *) cf)->mem); } -int read_config_fd(struct config_tree *cf, int fd, const char *file, +int read_config_fd(struct config_tree *cf, struct device *dev, off_t offset, size_t size, off_t offset2, size_t size2, checksum_fn_t checksum_fn, uint32_t checksum) { struct cs *c = (struct cs *) cf; struct parser *p; - off_t mmap_offset = 0; int r = 0; + int use_mmap = 1; + off_t mmap_offset = 0; if (!(p = pool_alloc(c->mem, sizeof(*p)))) { stack; @@ -125,47 +126,43 @@ int read_config_fd(struct config_tree *cf, int fd, const char *file, } p->mem = c->mem; - if (size2) { - /* FIXME Attempt adjacent mmaps MAP_FIXED into malloced space - * one page size larger than required... - */ + /* Only use mmap with regular files */ + if (!(dev->flags & DEV_REGULAR) || size2) + use_mmap = 0; + + if (use_mmap) { + mmap_offset = offset % getpagesize(); + /* memory map the file */ + p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ, + MAP_PRIVATE, dev_fd(dev), offset - mmap_offset); + if (p->fb == (caddr_t) (-1)) { + log_sys_error("mmap", dev_name(dev)); + goto out; + } + p->fb = p->fb + mmap_offset; + } else { if (!(p->fb = dbg_malloc(size + size2))) { stack; return 0; } - if (lseek(fd, offset, SEEK_SET) < 0) { - log_sys_error("lseek", file); + if (!dev_read(dev, (uint64_t) offset, size, p->fb)) { + log_error("Read from %s failed", dev_name(dev)); goto out; } - if (raw_read(fd, p->fb, size) != size) { - log_error("Circular read from %s failed", file); - goto out; + if (size2) { + if (!dev_read(dev, (uint64_t) offset2, size2, + p->fb + size)) { + log_error("Circular read from %s failed", + dev_name(dev)); + goto out; + } } - if (lseek(fd, offset2, SEEK_SET) < 0) { - log_sys_error("lseek", file); - goto out; - } - if (raw_read(fd, p->fb + size, size2) != size2) { - log_error("Circular read from %s failed", file); - goto out; - } - } else { - mmap_offset = offset % getpagesize(); - /* memory map the file */ - p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ, - MAP_PRIVATE, fd, offset - mmap_offset); - if (p->fb == (caddr_t) (-1)) { - log_sys_error("mmap", file); - goto out; - } - - p->fb = p->fb + mmap_offset; } if (checksum_fn && checksum != (checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size), p->fb + size, size2))) { - log_error("%s: Checksum error", file); + log_error("%s: Checksum error", dev_name(dev)); goto out; } @@ -183,12 +180,12 @@ int read_config_fd(struct config_tree *cf, int fd, const char *file, r = 1; out: - if (size2) + if (!use_mmap) dbg_free(p->fb); else { /* unmap the file */ if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) { - log_sys_error("munmap", file); + log_sys_error("munmap", dev_name(dev)); r = 0; } } @@ -200,7 +197,8 @@ int read_config_file(struct config_tree *cf, const char *file) { struct cs *c = (struct cs *) cf; struct stat info; - int r = 1, fd; + struct device *dev; + int r = 1; if (stat(file, &info)) { log_sys_error("stat", file); @@ -217,15 +215,20 @@ int read_config_file(struct config_tree *cf, const char *file) return 1; } - if ((fd = open(file, O_RDONLY)) < 0) { - log_sys_error("open", file); + if (!(dev = dev_create_file(file, NULL, NULL))) { + stack; return 0; } - r = read_config_fd(cf, fd, file, 0, (size_t) info.st_size, 0, 0, + if (!dev_open_flags(dev, O_RDONLY, 0, 0)) { + stack; + return 0; + } + + r = read_config_fd(cf, dev, 0, (size_t) info.st_size, 0, 0, (checksum_fn_t) NULL, 0); - close(fd); + dev_close(dev); c->timestamp = info.st_mtime; c->filename = pool_strdup(c->mem, file); @@ -249,7 +252,8 @@ int reload_config_file(struct config_tree **cf) struct cs *c = (struct cs *) *cf; struct cs *new_cs; struct stat info; - int r, fd; + struct device *dev; + int r; if (!c->filename) return 0; @@ -279,19 +283,25 @@ int reload_config_file(struct config_tree **cf) return 0; } - if ((fd = open(c->filename, O_RDONLY)) < 0) { - log_sys_error("open", c->filename); - return 0; - } - if (!(new_cf = create_config_tree())) { log_error("Allocation of new config_tree failed"); return 0; } - r = read_config_fd(new_cf, fd, c->filename, 0, (size_t) info.st_size, + if (!(dev = dev_create_file(c->filename, NULL, NULL))) { + stack; + return 0; + } + + if (!dev_open_flags(dev, O_RDONLY, 0, 0)) { + stack; + return 0; + } + + r = read_config_fd(new_cf, dev, 0, (size_t) info.st_size, 0, 0, (checksum_fn_t) NULL, 0); - close(fd); + + dev_close(dev); if (r) { new_cs = (struct cs *) new_cf; diff --git a/lib/config/config.h b/lib/config/config.h index 872d07e1a..6f7d41397 100644 --- a/lib/config/config.h +++ b/lib/config/config.h @@ -7,6 +7,8 @@ #ifndef _LVM_CONFIG_H #define _LVM_CONFIG_H +#include "device.h" + enum { CFG_STRING, CFG_FLOAT, @@ -39,7 +41,7 @@ void destroy_config_tree(struct config_tree *cf); typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size); -int read_config_fd(struct config_tree *cf, int fd, const char *file, +int read_config_fd(struct config_tree *cf, struct device *dev, off_t offset, size_t size, off_t offset2, size_t size2, checksum_fn_t checksum_fn, uint32_t checksum); diff --git a/lib/config/defaults.h b/lib/config/defaults.h index 5b7fe782a..bcebfa04f 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -53,6 +53,9 @@ #ifdef DEVMAPPER_SUPPORT # define DEFAULT_ACTIVATION 1 +# define DEFAULT_RESERVED_MEMORY 8192 +# define DEFAULT_RESERVED_STACK 256 +# define DEFAULT_PROCESS_PRIORITY -18 #else # define DEFAULT_ACTIVATION 0 #endif diff --git a/lib/datastruct/list.h b/lib/datastruct/list.h index 6041c1dac..df3d32aea 100644 --- a/lib/datastruct/list.h +++ b/lib/datastruct/list.h @@ -13,6 +13,8 @@ struct list { struct list *n, *p; }; +#define LIST_INIT(name) struct list name = { &(name), &(name) } + static inline void list_init(struct list *head) { head->n = head->p = head; @@ -64,6 +66,9 @@ static inline struct list *list_next(struct list *head, struct list *elem) #define list_iterate(v, head) \ for (v = (head)->n; v != head; v = v->n) +#define list_uniterate(v, head, start) \ + for (v = (start)->p; v != head; v = v->p) + #define list_iterate_safe(v, t, head) \ for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) @@ -81,6 +86,9 @@ static inline unsigned int list_size(const struct list *head) #define list_item(v, t) \ ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list)) +#define list_struct_base(v, t, h) \ + ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h)) + /* Given a known element in a known structure, locate another */ #define struct_field(v, t, e, f) \ (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f) diff --git a/lib/datastruct/lvm-types.h b/lib/datastruct/lvm-types.h index e9c15e446..b7a807d6c 100644 --- a/lib/datastruct/lvm-types.h +++ b/lib/datastruct/lvm-types.h @@ -17,7 +17,7 @@ struct str_list { struct list list; - char *str; + const char *str; }; #endif diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index 37644ef46..6f896c002 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -42,7 +42,44 @@ static struct { static int _insert(const char *path, int rec); -static struct device *_create_dev(dev_t d) +struct device *dev_create_file(const char *filename, struct device *dev, + struct str_list *alias) +{ + int allocate = !dev; + + if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) { + log_error("struct device allocation failed"); + return NULL; + } + if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) { + log_error("struct str_list allocation failed"); + dbg_free(dev); + return NULL; + } + if (!(alias->str = dbg_strdup(filename))) { + log_error("filename strdup failed"); + if (allocate) { + dbg_free(dev); + dbg_free(alias); + } + return NULL; + } + dev->flags = DEV_REGULAR; + if (allocate) + dev->flags |= DEV_ALLOCED; + list_init(&dev->aliases); + list_add(&dev->aliases, &alias->list); + dev->end = UINT64_C(0); + dev->dev = 0; + dev->fd = -1; + dev->open_count = 0; + memset(dev->pvid, 0, sizeof(dev->pvid)); + list_init(&dev->open_list); + + return dev; +} + +static struct device *_dev_create(dev_t d) { struct device *dev; @@ -50,12 +87,14 @@ static struct device *_create_dev(dev_t d) log_error("struct device allocation failed"); return NULL; } - + dev->flags = 0; list_init(&dev->aliases); dev->dev = d; dev->fd = -1; - dev->flags = 0; + dev->open_count = 0; + dev->end = UINT64_C(0); memset(dev->pvid, 0, sizeof(dev->pvid)); + list_init(&dev->open_list); return dev; } @@ -175,7 +214,7 @@ static int _insert_dev(const char *path, dev_t d) if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) d))) { /* create new device */ - if (!(dev = _create_dev(d))) { + if (!(dev = _dev_create(d))) { stack; return 0; } @@ -402,20 +441,31 @@ int dev_cache_add_dir(const char *path) /* Check cached device name is still valid before returning it */ /* This should be a rare occurrence */ +/* set quiet if the cache is expected to be out-of-date */ /* FIXME Make rest of code pass/cache struct device instead of dev_name */ -const char *dev_name_confirmed(struct device *dev) +const char *dev_name_confirmed(struct device *dev, int quiet) { struct stat buf; - char *name; + const char *name; int r; while ((r = stat(name = list_item(dev->aliases.n, struct str_list)->str, &buf)) || (buf.st_rdev != dev->dev)) { - if (r < 0) - log_sys_error("stat", name); - log_error("Path %s no longer valid for device(%d,%d)", - name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev)); + if (r < 0) { + if (quiet) + log_sys_debug("stat", name); + else + log_sys_error("stat", name); + } + if (quiet) + log_debug("Path %s no longer valid for device(%d,%d)", + name, (int) MAJOR(dev->dev), + (int) MINOR(dev->dev)); + else + log_error("Path %s no longer valid for device(%d,%d)", + name, (int) MAJOR(dev->dev), + (int) MINOR(dev->dev)); /* Remove the incorrect hash entry */ hash_remove(_cache.names, name); diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index 267dea263..897e7c008 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -8,6 +8,8 @@ #include "lvm-types.h" #include "device.h" #include "metadata.h" +#include "lvmcache.h" +#include "memlock.h" #include #include @@ -17,14 +19,188 @@ #ifdef linux # define u64 uint64_t /* Missing without __KERNEL__ */ +# undef WNOHANG /* Avoid redefinition */ +# undef WUNTRACED /* Avoid redefinition */ # include /* For block ioctl definitions */ # define BLKSIZE_SHIFT SECTOR_SHIFT +#else +# include +# define BLKBSZGET DKIOCGETBLOCKSIZE +# define BLKSSZGET DKIOCGETBLOCKSIZE +# define BLKGETSIZE64 DKIOCGETBLOCKCOUNT +# define BLKFLSBUF DKIOCSYNCHRONIZECACHE +# define BLKSIZE_SHIFT 0 +# ifndef O_DIRECT +# define O_DIRECT 0 +# endif #endif -/* FIXME 64 bit offset!!! +/* FIXME Use _llseek for 64-bit _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); + if (_llseek((unsigned) fd, (ulong) (offset >> 32), (ulong) (offset & 0xFFFFFFFF), &pos, SEEK_SET) < 0) { */ +static LIST_INIT(_open_devices); + +/*----------------------------------------------------------------- + * The standard io loop that keeps submitting an io until it's + * all gone. + *---------------------------------------------------------------*/ +static int _io(struct device_area *where, void *buffer, int should_write) +{ + int fd = dev_fd(where->dev); + ssize_t n = 0; + size_t total = 0; + + if (fd < 0) { + log_error("Attempt to read an unopened device (%s).", + dev_name(where->dev)); + return 0; + } + + /* + * Skip all writes in test mode. + */ + if (should_write && test_mode()) + return 1; + + if (where->size > SSIZE_MAX) { + log_error("Read size too large: %" PRIu64, where->size); + return 0; + } + + if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) { + log_sys_error("lseek", dev_name(where->dev)); + return 0; + } + + while (total < (size_t) where->size) { + do + n = should_write ? + write(fd, buffer, (size_t) where->size - total) : + read(fd, buffer, (size_t) where->size - total); + while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); + + if (n <= 0) + break; + + total += n; + buffer += n; + } + + return (total == (size_t) where->size); +} + +/*----------------------------------------------------------------- + * LVM2 uses O_DIRECT when performing metadata io, which requires + * block size aligned accesses. If any io is not aligned we have + * to perform the io via a bounce buffer, obviously this is quite + * inefficient. + *---------------------------------------------------------------*/ + +/* + * Get the sector size from an _open_ device. + */ +static int _get_block_size(struct device *dev, unsigned int *size) +{ + int s; + + if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) { + log_sys_error("ioctl BLKBSZGET", dev_name(dev)); + return 0; + } + + *size = (unsigned int) s; + return 1; +} + +/* + * Widens a region to be an aligned region. + */ +static void _widen_region(unsigned int block_size, struct device_area *region, + struct device_area *result) +{ + uint64_t mask = block_size - 1, delta; + memcpy(result, region, sizeof(*result)); + + /* adjust the start */ + delta = result->start & mask; + if (delta) { + result->start -= delta; + result->size += delta; + } + + /* adjust the end */ + delta = (result->start + result->size) & mask; + if (delta) + result->size += block_size - delta; +} + +static int _aligned_io(struct device_area *where, void *buffer, + int should_write) +{ + void *bounce; + unsigned int block_size = 0; + uintptr_t mask; + struct device_area widened; + + if (!(where->dev->flags & DEV_REGULAR) && + !_get_block_size(where->dev, &block_size)) { + stack; + return 0; + } + + if (!block_size) + block_size = SECTOR_SIZE * 2; + + _widen_region(block_size, where, &widened); + + /* Do we need to use a bounce buffer? */ + mask = block_size - 1; + if (!memcmp(where, &widened, sizeof(widened)) && + !((uintptr_t) buffer & mask)) + return _io(where, buffer, should_write); + + /* Allocate a bounce buffer with an extra block */ + if (!(bounce = alloca((size_t) widened.size + block_size))) { + log_error("Bounce buffer alloca failed"); + return 0; + } + + /* + * Realign start of bounce buffer (using the extra sector) + */ + if (((uintptr_t) bounce) & mask) + bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask); + + /* channel the io through the bounce buffer */ + if (!_io(&widened, bounce, 0)) { + if (!should_write) { + stack; + return 0; + } + /* FIXME pre-extend the file */ + memset(bounce, '\n', widened.size); + } + + if (should_write) { + memcpy(bounce + (where->start - widened.start), buffer, + (size_t) where->size); + + /* ... then we write */ + return _io(&widened, bounce, 1); + } + + memcpy(buffer, bounce + (where->start - widened.start), + (size_t) where->size); + + return 1; +} + +/*----------------------------------------------------------------- + * Public functions + *---------------------------------------------------------------*/ + int dev_get_size(struct device *dev, uint64_t *size) { int fd; @@ -70,54 +246,106 @@ int dev_get_sectsize(struct device *dev, uint32_t *size) return 1; } -static void _flush(int fd) +void dev_flush(struct device *dev) { - if (ioctl(fd, BLKFLSBUF, 0) >= 0) + if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0) return; - if (fsync(fd) >= 0) + if (fsync(dev->fd) >= 0) return; sync(); } -int dev_open(struct device *dev, int flags) +int dev_open_flags(struct device *dev, int flags, int direct, int quiet) { struct stat buf; - const char *name = dev_name_confirmed(dev); + const char *name; - if (!name) { + if (dev->fd >= 0) { + dev->open_count++; + return 1; + } + + if (memlock()) + log_error("WARNING: dev_open(%s) called while suspended", + dev_name(dev)); + + if (dev->flags & DEV_REGULAR) + name = dev_name(dev); + else if (!(name = dev_name_confirmed(dev, quiet))) { stack; return 0; } - if (dev->fd >= 0) { - log_error("Device '%s' has already been opened", name); - return 0; - } - - if ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev)) { + if (!(dev->flags & DEV_REGULAR) && + ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) { log_error("%s: stat failed: Has device name changed?", name); return 0; } - if ((dev->fd = open(name, flags)) < 0) { + if (direct) + flags |= O_DIRECT; + + if ((dev->fd = open(name, flags, 0777)) < 0) { log_sys_error("open", name); return 0; } - if ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev)) { + dev->open_count = 1; + dev->flags &= ~DEV_ACCESSED_W; + + if (!(dev->flags & DEV_REGULAR) && + ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) { log_error("%s: fstat failed: Has device name changed?", name); dev_close(dev); dev->fd = -1; return 0; } - _flush(dev->fd); - dev->flags = 0; +#if !O_DIRECT + if (!(dev->flags & DEV_REGULAR)) + dev_flush(dev); +#endif + + if ((flags & O_CREAT) && !(flags & O_TRUNC)) { + dev->end = lseek(dev->fd, (off_t) 0, SEEK_END); + } + + list_add(&_open_devices, &dev->open_list); + log_debug("Opened %s", dev_name(dev)); return 1; } +int dev_open_quiet(struct device *dev) +{ + /* FIXME Open O_RDONLY if vg read lock? */ + return dev_open_flags(dev, O_RDWR, 1, 1); +} + +int dev_open(struct device *dev) +{ + /* FIXME Open O_RDONLY if vg read lock? */ + return dev_open_flags(dev, O_RDWR, 1, 0); +} + +static void _close(struct device *dev) +{ + if (close(dev->fd)) + log_sys_error("close", dev_name(dev)); + dev->fd = -1; + list_del(&dev->open_list); + + log_debug("Closed %s", dev_name(dev)); + + if (dev->flags & DEV_ALLOCED) { + dbg_free((void *) list_item(dev->aliases.n, struct str_list)-> + str); + dbg_free(dev->aliases.n); + dbg_free(dev); + } +} + int dev_close(struct device *dev) { if (dev->fd < 0) { @@ -125,126 +353,91 @@ int dev_close(struct device *dev) "which is not open.", dev_name(dev)); return 0; } - +#if !O_DIRECT if (dev->flags & DEV_ACCESSED_W) - _flush(dev->fd); + dev_flush(dev); +#endif - if (close(dev->fd)) - log_sys_error("close", dev_name(dev)); - - dev->fd = -1; + /* FIXME lookup device in cache to get vgname and see if it's locked? */ + if (--dev->open_count < 1 && !vgs_locked()) + _close(dev); return 1; } -ssize_t raw_read(int fd, void *buf, size_t count) +void dev_close_all(void) { - ssize_t n = 0, tot = 0; + struct list *doh, *doht; + struct device *dev; - if (count > SSIZE_MAX) - return -1; - - while (tot < (signed) count) { - do - n = read(fd, buf, count - tot); - while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); - - if (n <= 0) - return tot ? tot : n; - - tot += n; - buf += n; + list_iterate_safe(doh, doht, &_open_devices) { + dev = list_struct_base(doh, struct device, open_list); + if (dev->open_count < 1) + _close(dev); } - - return tot; } -ssize_t dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) +int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) { - const char *name = dev_name(dev); - int fd = dev->fd; - /* loff_t pos; */ + struct device_area where; - if (fd < 0) { - log_err("Attempt to read an unopened device (%s).", name); + if (!dev->open_count) return 0; - } - /* if (_llseek((unsigned) fd, (ulong) (offset >> 32), (ulong) (offset & 0xFFFFFFFF), &pos, SEEK_SET) < 0) { */ - if (lseek(fd, (off_t) offset, SEEK_SET) < 0) { - log_sys_error("lseek", name); - return 0; - } + where.dev = dev; + where.start = offset; + where.size = len; - return raw_read(fd, buffer, len); + return _aligned_io(&where, buffer, 0); } -static int _write(int fd, const void *buf, size_t count) +/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after. + * But fails if concurrent processes writing + */ + +/* FIXME pre-extend the file */ +int dev_append(struct device *dev, size_t len, void *buffer) { - ssize_t n = 0; - int tot = 0; + int r; - /* Skip all writes */ - if (test_mode()) - return count; + if (!dev->open_count) + return 0; - while (tot < count) { - do - n = write(fd, buf, count - tot); - while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); + r = dev_write(dev, dev->end, len, buffer); + dev->end += (uint64_t) len; - if (n <= 0) - return tot ? tot : n; - - tot += n; - buf += n; - } - - return tot; +#if !O_DIRECT + dev_flush(dev); +#endif + return r; } -int64_t dev_write(struct device * dev, uint64_t offset, size_t len, - void *buffer) +int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer) { - const char *name = dev_name(dev); - int fd = dev->fd; + struct device_area where; - if (fd < 0) { - log_error("Attempt to write to unopened device %s", name); + if (!dev->open_count) return 0; - } - if (lseek(fd, (off_t) offset, SEEK_SET) < 0) { - log_sys_error("lseek", name); - return 0; - } + where.dev = dev; + where.start = offset; + where.size = len; dev->flags |= DEV_ACCESSED_W; - return _write(fd, buffer, len); + return _aligned_io(&where, buffer, 1); } int dev_zero(struct device *dev, uint64_t offset, size_t len) { - int64_t r; size_t s; char buffer[4096]; - int already_open; - already_open = dev_is_open(dev); - - if (!already_open && !dev_open(dev, O_RDWR)) { + if (!dev_open(dev)) { stack; return 0; } - if (lseek(dev->fd, (off_t) offset, SEEK_SET) < 0) { - log_sys_error("lseek", dev_name(dev)); - if (!already_open && !dev_close(dev)) - stack; - return 0; - } - if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE)) log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t, dev_name(dev), offset, len); @@ -256,21 +449,17 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len) memset(buffer, 0, sizeof(buffer)); while (1) { s = len > sizeof(buffer) ? sizeof(buffer) : len; - r = _write(dev->fd, buffer, s); - - if (r <= 0) + if (!dev_write(dev, offset, s, buffer)) break; - len -= r; - if (!len) { - r = 1; + len -= s; + if (!len) break; - } } dev->flags |= DEV_ACCESSED_W; - if (!already_open && !dev_close(dev)) + if (!dev_close(dev)) stack; /* FIXME: Always display error */ diff --git a/lib/device/device.h b/lib/device/device.h index 9576cef7f..eb3b6ec01 100644 --- a/lib/device/device.h +++ b/lib/device/device.h @@ -8,8 +8,11 @@ #define _LVM_DEVICE_H #include "uuid.h" +#include #define DEV_ACCESSED_W 0x00000001 /* Device written to? */ +#define DEV_REGULAR 0x00000002 /* Regular file? */ +#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */ /* * All devices in LVM will be represented by one of these. @@ -21,7 +24,10 @@ struct device { /* private */ int fd; + int open_count; uint32_t flags; + uint64_t end; + struct list open_list; char pvid[ID_LEN + 1]; }; @@ -43,20 +49,26 @@ struct device_area { int dev_get_size(struct device *dev, uint64_t *size); int dev_get_sectsize(struct device *dev, uint32_t *size); -int dev_open(struct device *dev, int flags); +/* Use quiet version if device number could change e.g. when opening LV */ +int dev_open(struct device *dev); +int dev_open_quiet(struct device *dev); +int dev_open_flags(struct device *dev, int flags, int append, int quiet); int dev_close(struct device *dev); +void dev_close_all(void); static inline int dev_fd(struct device *dev) { return dev->fd; } -ssize_t raw_read(int fd, void *buf, size_t count); - -ssize_t dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer); -int64_t dev_write(struct device *dev, uint64_t offset, size_t len, - void *buffer); +int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer); +int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer); +int dev_append(struct device *dev, size_t len, void *buffer); int dev_zero(struct device *dev, uint64_t offset, size_t len); +void dev_flush(struct device *dev); + +struct device *dev_create_file(const char *filename, struct device *dev, + struct str_list *alias); static inline const char *dev_name(const struct device *dev) { @@ -65,12 +77,7 @@ static inline const char *dev_name(const struct device *dev) } /* Return a valid device name from the alias list; NULL otherwise */ -const char *dev_name_confirmed(struct device *dev); - -static inline int dev_is_open(struct device *dev) -{ - return dev->fd >= 0 ? 1 : 0; -} +const char *dev_name_confirmed(struct device *dev, int quiet); /* FIXME Check partition type if appropriate */ diff --git a/lib/display/display.c b/lib/display/display.c index 0ca22e5ce..f521a9c91 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -75,6 +75,7 @@ uint64_t units_to_bytes(const char *units, char *unit_type) break; case 's': v *= SECTOR_SIZE; + break; case 'b': case 'B': v *= UINT64_C(1); @@ -82,6 +83,7 @@ uint64_t units_to_bytes(const char *units, char *unit_type) #define KILO UINT64_C(1024) case 'k': v *= KILO; + break; case 'm': v *= KILO * KILO; break; diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c index a7aef0bdd..950ef018b 100644 --- a/lib/format1/disk-rep.c +++ b/lib/format1/disk-rep.c @@ -9,7 +9,7 @@ #include "pool.h" #include "xlate.h" #include "filter.h" -#include "cache.h" +#include "lvmcache.h" #include @@ -130,7 +130,7 @@ static int _munge_formats(struct pv_disk *pvd) static int _read_pvd(struct device *dev, struct pv_disk *pvd) { - if (dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd) != sizeof(*pvd)) { + if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) { log_very_verbose("Failed to read PV data from %s", dev_name(dev)); return 0; @@ -155,7 +155,7 @@ static int _read_pvd(struct device *dev, struct pv_disk *pvd) static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) { - if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk)) + if (!dev_read(dev, pos, sizeof(*disk), disk)) fail; _xlate_lvd(disk); @@ -167,7 +167,7 @@ static int _read_vgd(struct disk_list *data) { struct vg_disk *vgd = &data->vgd; uint64_t pos = data->pvd.vg_on_disk.base; - if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd)) + if (!dev_read(data->dev, pos, sizeof(*vgd), vgd)) fail; _xlate_vgd(vgd); @@ -184,8 +184,7 @@ static int _read_uuids(struct disk_list *data) uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; while (pos < end && num_read < data->vgd.pv_cur) { - if (dev_read(data->dev, pos, sizeof(buffer), buffer) != - sizeof(buffer)) + if (!dev_read(data->dev, pos, sizeof(buffer), buffer)) fail; if (!(ul = pool_alloc(data->mem, sizeof(*ul)))) @@ -244,7 +243,7 @@ static int _read_extents(struct disk_list *data) if (!extents) fail; - if (dev_read(data->dev, pos, len, extents) != len) + if (!dev_read(data->dev, pos, len, extents)) fail; _xlate_extents(extents, data->pvd.pe_total); @@ -279,7 +278,7 @@ static struct disk_list *__read_disk(const struct format_type *fmt, { struct disk_list *dl = pool_alloc(mem, sizeof(*dl)); const char *name = dev_name(dev); - struct cache_info *info; + struct lvmcache_info *info; if (!dl) { stack; @@ -296,8 +295,8 @@ static struct disk_list *__read_disk(const struct format_type *fmt, goto bad; } - if (!(info = cache_add(fmt->labeller, dl->pvd.pv_uuid, dev, - dl->pvd.vg_name, NULL))) + if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev, + dl->pvd.vg_name, NULL))) stack; else { info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT; @@ -365,7 +364,7 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, { struct disk_list *r; - if (!dev_open(dev, O_RDONLY)) { + if (!dev_open(dev)) { stack; return NULL; } @@ -415,13 +414,13 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, struct device *dev; struct disk_list *data = NULL; struct list *vgih; - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; /* Fast path if we already saw this VG and cached the list of PVs */ if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) && vginfo->infos.n) { list_iterate(vgih, &vginfo->infos) { - dev = list_item(vgih, struct cache_info)->dev; + dev = list_item(vgih, struct lvmcache_info)->dev; if (dev && !(data = read_disk(fmt, dev, mem, vg_name))) break; _add_pv_to_list(head, data); @@ -463,7 +462,7 @@ static int _write_vgd(struct disk_list *data) uint64_t pos = data->pvd.vg_on_disk.base; _xlate_vgd(vgd); - if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd)) + if (!dev_write(data->dev, pos, sizeof(*vgd), vgd)) fail; _xlate_vgd(vgd); @@ -486,7 +485,7 @@ static int _write_uuids(struct disk_list *data) } ul = list_item(uh, struct uuid_list); - if (dev_write(data->dev, pos, NAME_LEN, ul->uuid) != NAME_LEN) + if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid)) fail; pos += NAME_LEN; @@ -498,7 +497,7 @@ static int _write_uuids(struct disk_list *data) static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) { _xlate_lvd(disk); - if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk)) + if (!dev_write(dev, pos, sizeof(*disk), disk)) fail; _xlate_lvd(disk); @@ -542,7 +541,7 @@ static int _write_extents(struct disk_list *data) uint64_t pos = data->pvd.pe_on_disk.base; _xlate_extents(extents, data->pvd.pe_total); - if (dev_write(data->dev, pos, len, extents) != len) + if (!dev_write(data->dev, pos, len, extents)) fail; _xlate_extents(extents, data->pvd.pe_total); @@ -574,7 +573,7 @@ static int _write_pvd(struct disk_list *data) memcpy(buf, &data->pvd, sizeof(struct pv_disk)); _xlate_pvd((struct pv_disk *) buf); - if (dev_write(data->dev, pos, size, buf) != size) { + if (!dev_write(data->dev, pos, size, buf)) { dbg_free(buf); fail; } @@ -640,7 +639,7 @@ static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data) { int r; - if (!dev_open(data->dev, O_WRONLY)) { + if (!dev_open(data->dev)) { stack; return 0; } diff --git a/lib/format1/format1.c b/lib/format1/format1.c index 0434c77ed..593ea8825 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -12,7 +12,7 @@ #include "list.h" #include "display.h" #include "toolcontext.h" -#include "cache.h" +#include "lvmcache.h" #include "lvm1-label.h" #include "format1.h" @@ -248,7 +248,7 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg, fid->fmt->cmd->filter) && write_disks(fid->fmt, &pvds)); - cache_update_vg(vg); + lvmcache_update_vg(vg); pool_destroy(mem); return r; } @@ -381,10 +381,10 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, struct disk_list *dl; struct list pvs; struct label *label; - struct cache_info *info; + struct lvmcache_info *info; - if (!(info = cache_add(fmt->labeller, (char *) &pv->id, pv->dev, - pv->vg_name, NULL))) { + if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev, + pv->vg_name, NULL))) { stack; return 0; } diff --git a/lib/format1/lvm1-label.c b/lib/format1/lvm1-label.c index 9dc6a18f2..10226dad8 100644 --- a/lib/format1/lvm1-label.c +++ b/lib/format1/lvm1-label.c @@ -10,7 +10,7 @@ #include "label.h" #include "metadata.h" #include "xlate.h" -#include "cache.h" +#include "lvmcache.h" #include #include @@ -49,9 +49,9 @@ static int _read(struct labeller *l, struct device *dev, char *buf, struct label **label) { struct pv_disk *pvd = (struct pv_disk *) buf; - struct cache_info *info; + struct lvmcache_info *info; - if (!(info = cache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) + if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) return 0; *label = info->label; diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index e8e342c03..e3be7bb85 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -20,6 +20,7 @@ #include "crc.h" #include "xlate.h" #include "label.h" +#include "memlock.h" #include #include @@ -107,8 +108,7 @@ static struct mda_header *_raw_read_mda_header(const struct format_type *fmt, return NULL; } - if (dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah) != - MDA_HEADER_SIZE) { + if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) { stack; pool_free(fmt->cmd->mem, mdah); return NULL; @@ -156,8 +156,7 @@ static int _raw_write_mda_header(const struct format_type *fmt, MDA_HEADER_SIZE - sizeof(mdah->checksum_xl))); - if (dev_write(dev, start_byte, MDA_HEADER_SIZE, mdah) - != MDA_HEADER_SIZE) { + if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, mdah)) { stack; pool_free(fmt->cmd->mem, mdah); return 0; @@ -178,9 +177,8 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area, /* FIXME Ignore if checksum incorrect!!! */ while (rlocn->offset) { - if (dev_read(dev_area->dev, dev_area->start + rlocn->offset, - sizeof(vgnamebuf), vgnamebuf) - != sizeof(vgnamebuf)) { + if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset, + sizeof(vgnamebuf), vgnamebuf)) { stack; return NULL; } @@ -214,7 +212,7 @@ static int _raw_holds_vgname(struct format_instance *fid, { int r = 0; - if (!dev_open(dev_area->dev, O_RDONLY)) { + if (!dev_open(dev_area->dev)) { stack; return 0; } @@ -239,7 +237,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid, char *desc; uint32_t wrap = 0; - if (!dev_open(area->dev, O_RDONLY)) { + if (!dev_open(area->dev)) { stack; return NULL; } @@ -264,8 +262,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid, } /* FIXME 64-bit */ - if (!(vg = text_vg_import_fd(fid, dev_name(area->dev), - dev_fd(area->dev), + if (!(vg = text_vg_import_fd(fid, NULL, area->dev, (off_t) (area->start + rlocn->offset), (uint32_t) (rlocn->size - wrap), (off_t) (area->start + MDA_HEADER_SIZE), @@ -321,7 +318,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, if (!found) return 1; - if (!dev_open(mdac->area.dev, O_RDWR)) { + if (!dev_open(mdac->area.dev)) { stack; return 0; } @@ -370,9 +367,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, mdac->rlocn.offset, mdac->rlocn.size - new_wrap); /* Write text out, circularly */ - if (dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset, - (size_t) (mdac->rlocn.size - new_wrap), - buf) != mdac->rlocn.size - new_wrap) { + if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset, + (size_t) (mdac->rlocn.size - new_wrap), buf)) { stack; goto out; } @@ -382,11 +378,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, dev_name(mdac->area.dev), mdac->area.start + MDA_HEADER_SIZE, new_wrap); - if (dev_write(mdac->area.dev, - mdac->area.start + MDA_HEADER_SIZE, - (size_t) new_wrap, - buf + mdac->rlocn.size - new_wrap) - != new_wrap) { + if (!dev_write(mdac->area.dev, + mdac->area.start + MDA_HEADER_SIZE, + (size_t) new_wrap, + buf + mdac->rlocn.size - new_wrap)) { stack; goto out; } @@ -403,7 +398,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, r = 1; out: - if (!dev_close(mdac->area.dev)) + if (!r && !dev_close(mdac->area.dev)) stack; return r; @@ -432,11 +427,6 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg, if (!found) return 1; - if (!dev_open(mdac->area.dev, O_RDWR)) { - stack; - return 0; - } - if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area))) { stack; goto out; @@ -469,6 +459,33 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg, return r; } +/* Close metadata area devices */ +static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg, + struct metadata_area *mda) +{ + struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; + struct physical_volume *pv; + struct list *pvh; + int found = 0; + + /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ + list_iterate(pvh, &vg->pvs) { + pv = list_item(pvh, struct pv_list)->pv; + if (pv->dev == mdac->area.dev) { + found = 1; + break; + } + } + + if (!found) + return 1; + + if (!dev_close(mdac->area.dev)) + stack; + + return 1; +} + static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { @@ -477,7 +494,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg, struct raw_locn *rlocn; int r = 0; - if (!dev_open(mdac->area.dev, O_RDWR)) { + if (!dev_open(mdac->area.dev)) { stack; return 0; } @@ -738,7 +755,7 @@ static int _scan_file(const struct format_type *fmt) fid = _create_text_instance(fmt, NULL, NULL); if ((vg = _vg_read_file_name(fid, vgname, path))) - cache_update_vg(vg); + lvmcache_update_vg(vg); } if (closedir(d)) @@ -753,13 +770,10 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area, { struct raw_locn *rlocn; struct mda_header *mdah; - int already_open; unsigned int len; int r = 0; - already_open = dev_is_open(dev_area->dev); - - if (!already_open && !dev_open(dev_area->dev, O_RDONLY)) { + if (!dev_open(dev_area->dev)) { stack; return 0; } @@ -772,8 +786,8 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area, rlocn = mdah->raw_locns; while (rlocn->offset) { - if (dev_read(dev_area->dev, dev_area->start + rlocn->offset, - size, buf) != (signed) size) { + if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset, + size, buf)) { stack; goto out; } @@ -797,7 +811,7 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area, } out: - if (!already_open && dev_close(dev_area->dev)) + if (!dev_close(dev_area->dev)) stack; return r; @@ -824,7 +838,7 @@ static int _scan_raw(const struct format_type *fmt) sizeof(vgnamebuf))) { if ((vg = _vg_read_raw_area(&fid, vgnamebuf, &rl->dev_area))) - cache_update_vg(vg); + lvmcache_update_vg(vg); } } @@ -960,7 +974,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, struct list *mdas, int64_t label_sector) { struct label *label; - struct cache_info *info; + struct lvmcache_info *info; struct mda_context *mdac; struct list *mdash; struct metadata_area *mda; @@ -970,8 +984,8 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, /* FIXME Test mode don't update cache? */ - if (!(info = cache_add(fmt->labeller, (char *) &pv->id, pv->dev, - ORPHAN, NULL))) { + if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev, + ORPHAN, NULL))) { stack; return 0; } @@ -1035,7 +1049,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, return 0; } - if (!dev_open(pv->dev, O_RDWR)) { + if (!dev_open(pv->dev)) { stack; return 0; } @@ -1121,7 +1135,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name, { struct label *label; struct device *dev; - struct cache_info *info; + struct lvmcache_info *info; struct metadata_area *mda, *mda_new; struct mda_context *mdac, *mdac_new; struct list *mdah, *dah; @@ -1137,7 +1151,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name, stack; return 0; } - info = (struct cache_info *) label->info; + info = (struct lvmcache_info *) label->info; /* Have we already cached vgname? */ if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname && @@ -1147,12 +1161,15 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name, } /* Perform full scan and try again */ - cache_label_scan(fmt->cmd, 1); + if (!memlock()) { + lvmcache_label_scan(fmt->cmd, 1); - if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname && - _get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid, - pv)) { - return 1; + if (info->vginfo && info->vginfo->vgname && + *info->vginfo->vgname && + _get_pv_from_vg(info->fmt, info->vginfo->vgname, + info->dev->pvid, pv)) { + return 1; + } } /* Orphan */ @@ -1251,7 +1268,8 @@ static struct metadata_area_ops _metadata_text_raw_ops = { vg_read:_vg_read_raw, vg_write:_vg_write_raw, vg_remove:_vg_remove_raw, - vg_commit:_vg_commit_raw + vg_commit:_vg_commit_raw, + vg_revert:_vg_revert_raw }; /* pvmetadatasize in sectors */ @@ -1265,7 +1283,7 @@ static int _pv_setup(const struct format_type *fmt, struct metadata_area *mda, *mda_new, *mda2; struct mda_context *mdac, *mdac_new, *mdac2; struct list *pvmdas, *pvmdash, *mdash; - struct cache_info *info; + struct lvmcache_info *info; int found; uint64_t pe_end = 0; @@ -1357,7 +1375,7 @@ static struct format_instance *_create_text_instance(const struct format_type struct raw_list *rl; struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh; char path[PATH_MAX]; - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) { log_error("Couldn't allocate format instance object."); @@ -1425,13 +1443,13 @@ static struct format_instance *_create_text_instance(const struct format_type } /* Scan PVs in VG for any further MDAs */ - cache_label_scan(fmt->cmd, 0); + lvmcache_label_scan(fmt->cmd, 0); if (!(vginfo = vginfo_from_vgname(vgname))) { stack; goto out; } list_iterate(infoh, &vginfo->infos) { - mdas = &(list_item(infoh, struct cache_info)->mdas); + mdas = &(list_item(infoh, struct lvmcache_info)->mdas); list_iterate(mdash, mdas) { mda = list_item(mdash, struct metadata_area); mdac = diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h index f630285c9..87ec5c771 100644 --- a/lib/format_text/import-export.h +++ b/lib/format_text/import-export.h @@ -54,7 +54,7 @@ struct volume_group *text_vg_import_file(struct format_instance *fid, time_t *when, char **desc); struct volume_group *text_vg_import_fd(struct format_instance *fid, const char *file, - int fd, + struct device *dev, off_t offset, uint32_t size, off_t offset2, uint32_t size2, checksum_fn_t checksum_fn, diff --git a/lib/format_text/import.c b/lib/format_text/import.c index 8d8acd1e7..3cd6760a2 100644 --- a/lib/format_text/import.c +++ b/lib/format_text/import.c @@ -11,14 +11,14 @@ #include "display.h" #include "hash.h" #include "toolcontext.h" -#include "cache.h" +#include "lvmcache.h" /* FIXME Use tidier inclusion method */ static struct text_vg_version_ops *(_text_vsn_list[2]); struct volume_group *text_vg_import_fd(struct format_instance *fid, const char *file, - int fd, + struct device *dev, off_t offset, uint32_t size, off_t offset2, uint32_t size2, checksum_fn_t checksum_fn, @@ -45,10 +45,9 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid, goto out; } - if ((fd == -1 && !read_config_file(cf, file)) || - (fd != -1 && !read_config_fd(cf, fd, file, offset, size, - offset2, size2, checksum_fn, - checksum))) { + if ((!dev && !read_config_file(cf, file)) || + (dev && !read_config_fd(cf, dev, offset, size, + offset2, size2, checksum_fn, checksum))) { log_error("Couldn't read volume group metadata."); goto out; } @@ -78,6 +77,6 @@ struct volume_group *text_vg_import_file(struct format_instance *fid, const char *file, time_t *when, char **desc) { - return text_vg_import_fd(fid, file, -1, 0, 0, 0, 0, NULL, 0, + return text_vg_import_fd(fid, file, NULL, 0, 0, 0, 0, NULL, 0, when, desc); } diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index 41e1d29f1..f2475fc98 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -11,7 +11,7 @@ #include "display.h" #include "hash.h" #include "toolcontext.h" -#include "cache.h" +#include "lvmcache.h" typedef int (*section_fn) (struct format_instance * fid, struct pool * mem, struct volume_group * vg, struct config_node * pvn, diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c index 08006c6a1..e3dd09fdf 100644 --- a/lib/format_text/text_label.c +++ b/lib/format_text/text_label.c @@ -27,7 +27,7 @@ static int _write(struct label *label, char *buf) { struct label_header *lh = (struct label_header *) buf; struct pv_header *pvhdr; - struct cache_info *info; + struct lvmcache_info *info; struct disk_locn *pvh_dlocn_xl; struct list *mdash, *dash; struct metadata_area *mda; @@ -40,7 +40,7 @@ static int _write(struct label *label, char *buf) strncpy(lh->type, label->type, sizeof(label->type)); pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl)); - info = (struct cache_info *) label->info; + info = (struct lvmcache_info *) label->info; pvhdr->device_size_xl = xlate64(info->device_size); memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id)); @@ -185,7 +185,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf, { struct label_header *lh = (struct label_header *) buf; struct pv_header *pvhdr; - struct cache_info *info; + struct lvmcache_info *info; struct disk_locn *dlocn_xl; uint64_t offset; struct list *mdah; @@ -195,7 +195,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf, pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl)); - if (!(info = cache_add(l, pvhdr->pv_uuid, dev, NULL, NULL))) + if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL))) return 0; *label = info->label; @@ -230,7 +230,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf, mdac = (struct mda_context *) mda->metadata_locn; if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf, sizeof(vgnamebuf))) { - cache_update_vgname(info, vgnamebuf); + lvmcache_update_vgname(info, vgnamebuf); } } @@ -241,7 +241,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf, static void _destroy_label(struct labeller *l, struct label *label) { - struct cache_info *info = (struct cache_info *) label->info; + struct lvmcache_info *info = (struct lvmcache_info *) label->info; if (info->mdas.n) del_mdas(&info->mdas); diff --git a/lib/label/label.c b/lib/label/label.c index 1af5443da..dc549dafd 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -9,7 +9,7 @@ #include "list.h" #include "crc.h" #include "xlate.h" -#include "cache.h" +#include "lvmcache.h" #include #include @@ -104,21 +104,17 @@ static struct labeller *_find_labeller(struct device *dev, char *buf, struct list *lih; struct labeller_i *li; struct labeller *r = NULL; - int already_open; struct label_header *lh; uint64_t sector; int found = 0; char readbuf[LABEL_SCAN_SIZE]; - already_open = dev_is_open(dev); - - if (!already_open && !dev_open(dev, O_RDONLY)) { + if (!dev_open(dev)) { stack; return NULL; } - if (dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf) != - LABEL_SCAN_SIZE) { + if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) { log_debug("%s: Failed to read label area", dev_name(dev)); goto out; } @@ -178,7 +174,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf, log_very_verbose("%s: No label detected", dev_name(dev)); out: - if (!already_open && !dev_close(dev)) + if (!dev_close(dev)) stack; return r; @@ -200,13 +196,18 @@ int label_remove(struct device *dev) log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev)); - if (!dev_open(dev, O_RDWR)) { + if (!dev_open(dev)) { stack; return 0; } - if (dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf) != - LABEL_SCAN_SIZE) { + /* + * We flush the device just in case someone is stupid + * enough to be trying to import an open pv into lvm. + */ + dev_flush(dev); + + if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) { log_debug("%s: Failed to read label area", dev_name(dev)); goto out; } @@ -236,8 +237,8 @@ int label_remove(struct device *dev) if (wipe) { log_info("%s: Wiping label at sector %" PRIu64, dev_name(dev), sector); - if (dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE, - buf) != LABEL_SIZE) { + if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE, + buf)) { log_error("Failed to remove label from %s at " "sector %" PRIu64, dev_name(dev), sector); @@ -278,7 +279,6 @@ int label_write(struct device *dev, struct label *label) char buf[LABEL_SIZE]; struct label_header *lh = (struct label_header *) buf; int r = 1; - int already_open; if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) { log_error("Label sector %" PRIu64 " beyond range (%ld)", @@ -298,21 +298,19 @@ int label_write(struct device *dev, struct label *label) lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE - ((void *) &lh->offset_xl - (void *) lh))); - already_open = dev_is_open(dev); - if (!already_open && dev_open(dev, O_RDWR)) { + if (!dev_open(dev)) { stack; return 0; } log_info("%s: Writing label to sector %" PRIu64, dev_name(dev), label->sector); - if (dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf) != - LABEL_SIZE) { + if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) { log_debug("Failed to write label to %s", dev_name(dev)); r = 0; } - if (!already_open && dev_close(dev)) + if (!dev_close(dev)) stack; return r; diff --git a/lib/label/label.h b/lib/label/label.h index b2dbc825f..56e518b9e 100644 --- a/lib/label/label.h +++ b/lib/label/label.h @@ -7,7 +7,7 @@ #ifndef _LVM_LABEL_H #define _LVM_LABEL_H -#include "cache.h" +#include "lvmcache.h" #include "uuid.h" #include "device.h" diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c index 04b1511ea..6867cc6c0 100644 --- a/lib/locking/file_locking.c +++ b/lib/locking/file_locking.c @@ -13,6 +13,7 @@ #include "defaults.h" #include "lvm-file.h" #include "lvm-string.h" +#include "lvmcache.h" #include #include @@ -202,24 +203,39 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource, else lvm_snprintf(lockfile, sizeof(lockfile), "%s/V_%s", _lock_dir, resource); + if (!_lock_file(lockfile, flags)) return 0; + + switch (flags & LCK_TYPE_MASK) { + case LCK_UNLOCK: + lvmcache_unlock_vgname(resource); + break; + default: + lvmcache_lock_vgname(resource, + (flags & LCK_TYPE_MASK) == + LCK_READ); + } break; case LCK_LV: switch (flags & LCK_TYPE_MASK) { case LCK_UNLOCK: + log_debug("Unlocking LV %s", resource); if (!lv_resume_if_active(cmd, resource)) return 0; break; case LCK_READ: + log_debug("Locking LV %s (R)", resource); if (!lv_activate(cmd, resource)) return 0; break; case LCK_WRITE: + log_debug("Locking LV %s (W)", resource); if (!lv_suspend_if_active(cmd, resource)) return 0; break; case LCK_EXCL: + log_debug("Locking LV %s (EX)", resource); if (!lv_deactivate(cmd, resource)) return 0; break; diff --git a/lib/locking/locking.c b/lib/locking/locking.c index 0278dbefc..fca0a9cf8 100644 --- a/lib/locking/locking.c +++ b/lib/locking/locking.c @@ -14,33 +14,19 @@ #include #include -#include #include +#include static struct locking_type _locking; static sigset_t _oldset; static int _lock_count = 0; /* Number of locks held */ -static int _write_lock_held = 0; static int _signals_blocked = 0; static void _block_signals(int flags) { sigset_t set; - /* Stop process memory getting swapped out */ -#ifdef MCL_CURRENT - if (!_write_lock_held && (flags & LCK_SCOPE_MASK) == LCK_LV && - (flags & LCK_TYPE_MASK) == LCK_WRITE) { - if (mlockall(MCL_CURRENT | MCL_FUTURE)) - log_sys_error("mlockall", ""); - else { - log_very_verbose("Locking memory"); - _write_lock_held = 1; - } - } -#endif - if (_signals_blocked) return; @@ -61,17 +47,6 @@ static void _block_signals(int flags) static void _unblock_signals(void) { -#ifdef MCL_CURRENT - if (!_lock_count && _write_lock_held) { - if (munlockall()) { - log_very_verbose("Unlocking memory"); - log_sys_error("munlockall", ""); - } - - _write_lock_held = 0; - } -#endif - /* Don't unblock signals while any locks are held */ if (!_signals_blocked || _lock_count) return; @@ -91,7 +66,6 @@ void reset_locking(void) int was_locked = _lock_count; _lock_count = 0; - _write_lock_held = 0; _locking.reset_locking(); diff --git a/lib/locking/no_locking.c b/lib/locking/no_locking.c index 79f23b883..f849152d2 100644 --- a/lib/locking/no_locking.c +++ b/lib/locking/no_locking.c @@ -10,6 +10,7 @@ #include "locking_types.h" #include "lvm-string.h" #include "activate.h" +#include "lvmcache.h" #include @@ -32,6 +33,15 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource, { switch (flags & LCK_SCOPE_MASK) { case LCK_VG: + switch (flags & LCK_TYPE_MASK) { + case LCK_UNLOCK: + lvmcache_unlock_vgname(resource); + break; + default: + lvmcache_lock_vgname(resource, + (flags & LCK_TYPE_MASK) == + LCK_READ); + } break; case LCK_LV: switch (flags & LCK_TYPE_MASK) { diff --git a/lib/log/log.c b/lib/log/log.c index 17f6caac3..21778ad90 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -5,11 +5,16 @@ */ #include "lib.h" +#include "device.h" +#include "memlock.h" +#include "lvm-string.h" #include #include -static FILE *_log = 0; +static FILE *_log_file; +static struct device _log_dev; +static struct str_list _log_dev_alias; static int _verbose_level = 0; static int _test = 0; @@ -17,16 +22,45 @@ static int _partial = 0; static int _pvmove = 0; static int _debug_level = 0; static int _syslog = 0; +static int _log_to_file = 0; +static int _log_direct = 0; +static int _log_while_suspended = 0; static int _indent = 1; static int _log_cmd_name = 0; static int _log_suppress = 0; static int _ignorelockingfailure = 0; static char _cmd_name[30] = ""; static char _msg_prefix[30] = " "; +static int _already_logging = 0; -void init_log(FILE *fp) +void init_log_file(const char *log_file, int append) { - _log = fp; + const char *open_mode = append ? "a" : "w"; + + if (!(_log_file = fopen(log_file, open_mode))) { + log_sys_error("fopen", log_file); + return; + } + + _log_to_file = 1; +} + +void init_log_direct(const char *log_file, int append) +{ + const char *filename; + int open_flags = append ? 0 : O_TRUNC; + + filename = dbg_strdup(log_file); + dev_create_file(filename, &_log_dev, &_log_dev_alias); + if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0)) + return; + + _log_direct = 1; +} + +void init_log_while_suspended(int log_while_suspended) +{ + _log_while_suspended = log_while_suspended; } void init_syslog(int facility) @@ -40,9 +74,23 @@ void log_suppress(int suppress) _log_suppress = suppress; } -void fin_log() +void release_log_memory(void) { - _log = 0; + dbg_free((char *) _log_dev_alias.str); + _log_dev_alias.str = "activate_log file"; +} + +void fin_log(void) +{ + if (_log_direct) { + dev_close(&_log_dev); + _log_direct = 0; + } + + if (_log_to_file) { + fclose(_log_file); + _log_to_file = 0; + } } void fin_syslog() @@ -136,6 +184,8 @@ int debug_level() void print_log(int level, const char *file, int line, const char *format, ...) { va_list ap; + char buf[1024]; + int bufused, n; if (!_log_suppress) { va_start(ap, format); @@ -194,20 +244,48 @@ void print_log(int level, const char *file, int line, const char *format, ...) if (level > _debug_level) return; - if (_log) { - fprintf(_log, "%s:%d %s%s", file, line, _cmd_name, _msg_prefix); + if (_log_to_file && (_log_while_suspended || !memlock())) { + fprintf(_log_file, "%s:%d %s%s", file, line, _cmd_name, + _msg_prefix); va_start(ap, format); - vfprintf(_log, format, ap); + vfprintf(_log_file, format, ap); va_end(ap); - fprintf(_log, "\n"); - fflush(_log); + fprintf(_log_file, "\n"); + fflush(_log_file); } - if (_syslog) { + if (_syslog && (_log_while_suspended || !memlock())) { va_start(ap, format); vsyslog(level, format, ap); va_end(ap); } + + /* FIXME This code is unfinished - pre-extend & condense. */ + if (!_already_logging && _log_direct && memlock()) { + _already_logging = 1; + memset(&buf, ' ', sizeof(buf)); + bufused = 0; + if ((n = lvm_snprintf(buf, sizeof(buf) - bufused - 1, + "%s:%d %s%s", file, line, _cmd_name, + _msg_prefix)) == -1) + goto done; + + bufused += n; + + va_start(ap, format); + n = vsnprintf(buf + bufused - 1, sizeof(buf) - bufused - 1, + format, ap); + va_end(ap); + bufused += n; + + done: + buf[bufused - 1] = '\n'; + buf[bufused] = '\n'; + buf[sizeof(buf) - 1] = '\n'; + /* FIXME real size bufused */ + dev_append(&_log_dev, sizeof(buf), buf); + _already_logging = 0; + } } diff --git a/lib/log/log.h b/lib/log/log.h index a28866f79..927c7eb6f 100644 --- a/lib/log/log.h +++ b/lib/log/log.h @@ -39,8 +39,11 @@ #define _LOG_ERR 3 #define _LOG_FATAL 2 -void init_log(FILE *fp); +void init_log_file(const char *log_file, int append); +void init_log_direct(const char *log_file, int append); +void init_log_while_suspended(int log_while_suspended); void fin_log(void); +void release_log_memory(void); void init_syslog(int facility); void fin_syslog(void); @@ -66,6 +69,9 @@ int ignorelockingfailure(void); /* Suppress messages to stdout/stderr */ void log_suppress(int suppress); +/* Suppress messages to syslog */ +void syslog_suppress(int suppress); + void print_log(int level, const char *file, int line, const char *format, ...) __attribute__ ((format(printf, 4, 5))); @@ -90,5 +96,7 @@ void print_log(int level, const char *file, int line, const char *format, ...) log_err("%s: %s failed: %s", y, x, strerror(errno)) #define log_sys_very_verbose(x, y) \ log_info("%s: %s failed: %s", y, x, strerror(errno)) +#define log_sys_debug(x, y) \ + log_debug("%s: %s failed: %s", y, x, strerror(errno)) #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 79449c169..7d15d9144 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software (UK) Limited. + * Copyright (C) 2001-2003 Sistina Software (UK) Limited. * * This file is released under the LGPL. */ @@ -10,7 +10,8 @@ #include "metadata.h" #include "toolcontext.h" #include "lvm-string.h" -#include "cache.h" +#include "lvmcache.h" +#include "memlock.h" static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg, const char *pv_name) @@ -437,11 +438,14 @@ int vg_remove(struct volume_group *vg) return 1; } +/* + * After vg_write() returns success, + * caller MUST call either vg_commit() or vg_revert() + */ int vg_write(struct volume_group *vg) { - struct list *mdah; + struct list *mdah, *mdah2; struct metadata_area *mda; - int cache_updated = 0; if (vg->status & PARTIAL_VG) { log_error("Cannot change metadata for partial volume group %s", @@ -461,21 +465,61 @@ int vg_write(struct volume_group *vg) mda = list_item(mdah, struct metadata_area); if (!mda->ops->vg_write(vg->fid, vg, mda)) { stack; + /* Revert */ + list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) { + mda = list_item(mdah2, struct metadata_area); + if (mda->ops->vg_revert && + !mda->ops->vg_revert(vg->fid, vg, mda)) { + stack; + } + } return 0; } } + return 1; +} + +/* Commit pending changes */ +int vg_commit(struct volume_group *vg) +{ + struct list *mdah; + struct metadata_area *mda; + int cache_updated = 0; + int failed = 0; + /* Commit to each copy of the metadata area */ list_iterate(mdah, &vg->fid->metadata_areas) { mda = list_item(mdah, struct metadata_area); - if (!cache_updated) { - cache_update_vg(vg); - cache_updated = 1; - } + failed = 0; if (mda->ops->vg_commit && !mda->ops->vg_commit(vg->fid, vg, mda)) { stack; - return 0; + failed = 1; + } + /* Update cache first time we succeed */ + if (!failed && !cache_updated) { + lvmcache_update_vg(vg); + cache_updated = 1; + } + + } + + /* If at least one mda commit succeeded, it was committed */ + return cache_updated; +} + +/* Don't commit any pending changes */ +int vg_revert(struct volume_group *vg) +{ + struct list *mdah; + struct metadata_area *mda; + + list_iterate(mdah, &vg->fid->metadata_areas) { + mda = list_item(mdah, struct metadata_area); + if (mda->ops->vg_revert && + !mda->ops->vg_revert(vg->fid, vg, mda)) { + stack; } } @@ -485,7 +529,7 @@ int vg_write(struct volume_group *vg) /* Make orphan PVs look like a VG */ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd) { - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; struct list *ih; struct device *dev; struct pv_list *pvl; @@ -511,7 +555,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd) } list_iterate(ih, &vginfo->infos) { - dev = list_item(ih, struct cache_info)->dev; + dev = list_item(ih, struct lvmcache_info)->dev; if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL))) { continue; } @@ -552,9 +596,13 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname, /* Find the vgname in the cache */ /* If it's not there we must do full scan to be completely sure */ if (!(fmt = fmt_from_vgname(vgname))) { - cache_label_scan(cmd, 0); + lvmcache_label_scan(cmd, 0); if (!(fmt = fmt_from_vgname(vgname))) { - cache_label_scan(cmd, 1); + if (memlock()) { + stack; + return NULL; + } + lvmcache_label_scan(cmd, 1); if (!(fmt = fmt_from_vgname(vgname))) { stack; return NULL; @@ -593,7 +641,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname, return NULL; } - cache_update_vg(correct_vg); + lvmcache_update_vg(correct_vg); if (inconsistent) { if (!*consistent) @@ -634,10 +682,10 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname, */ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) { - char *vgname; - struct list *vgnames, *slh; + // const char *vgname; + // struct list *vgnames, *slh; struct volume_group *vg; - struct cache_vginfo *vginfo; + struct lvmcache_vginfo *vginfo; int consistent = 0; /* Is corresponding vgname already cached? */ @@ -654,7 +702,14 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) } } - /* The slow way - full scan required to cope with vgrename */ + return NULL; + + /* FIXME Need a genuine read by ID here - don't vg_read by name! */ + /* FIXME Disabled vgrenames while active for now because we aren't + * allowed to do a full scan here any more. */ + +/*** FIXME Cope with vgrename here + // The slow way - full scan required to cope with vgrename if (!(vgnames = get_vgs(cmd, 1))) { log_error("vg_read_by_vgid: get_vgs failed"); return NULL; @@ -663,7 +718,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) list_iterate(slh, vgnames) { vgname = list_item(slh, struct str_list)->str; if (!vgname || !*vgname) - continue; /* FIXME Unnecessary? */ + continue; // FIXME Unnecessary? consistent = 0; if ((vg = vg_read(cmd, vgname, &consistent)) && !strncmp(vg->id.uuid, vgid, ID_LEN)) { @@ -677,6 +732,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) } return NULL; +***/ } /* Only called by activate.c */ @@ -713,7 +769,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, { struct physical_volume *pv; struct label *label; - struct cache_info *info; + struct lvmcache_info *info; struct device *dev; if (!(dev = dev_cache_get(pv_name, cmd->filter))) { @@ -726,7 +782,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, return 0; } - info = (struct cache_info *) label->info; + info = (struct lvmcache_info *) label->info; if (label_sector && *label_sector) *label_sector = label->sector; @@ -751,13 +807,13 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, /* May return empty list */ struct list *get_vgs(struct cmd_context *cmd, int full_scan) { - return cache_get_vgnames(cmd, full_scan); + return lvmcache_get_vgnames(cmd, full_scan); } struct list *get_pvs(struct cmd_context *cmd) { struct list *results; - char *vgname; + const char *vgname; struct list *pvh, *tmp; struct list *vgnames, *slh; struct volume_group *vg; @@ -765,7 +821,7 @@ struct list *get_pvs(struct cmd_context *cmd) int old_partial; int old_pvmove; - cache_label_scan(cmd, 0); + lvmcache_label_scan(cmd, 0); if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) { log_error("PV list allocation failed"); diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 2bd000997..0e4d3ec0d 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -126,6 +126,8 @@ struct metadata_area_ops { struct metadata_area * mda); int (*vg_commit) (struct format_instance * fid, struct volume_group * vg, struct metadata_area * mda); + int (*vg_revert) (struct format_instance * fid, + struct volume_group * vg, struct metadata_area * mda); int (*vg_remove) (struct format_instance * fi, struct volume_group * vg, struct metadata_area * mda); }; @@ -338,6 +340,8 @@ struct format_handler { * Utility functions */ int vg_write(struct volume_group *vg); +int vg_commit(struct volume_group *vg); +int vg_revert(struct volume_group *vg); struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, int *consistent); struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid); diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index e0c7ba225..c68be61a3 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -68,7 +68,6 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, return 1; } -/* Remove a temporary mirror */ int remove_pvmove_mirrors(struct volume_group *vg, struct logical_volume *lv_mirr) { @@ -226,6 +225,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, } } next_lv: + ; } return lvs; diff --git a/lib/misc/lib.h b/lib/misc/lib.h index 2462e15a9..1f45890c7 100644 --- a/lib/misc/lib.h +++ b/lib/misc/lib.h @@ -11,6 +11,7 @@ #define _LVM_LIB_H #define _REENTRANT +#define _GNU_SOURCE #include "log.h" #include "dbg_malloc.h" diff --git a/lib/mm/memlock.c b/lib/mm/memlock.c new file mode 100644 index 000000000..49d6c1a92 --- /dev/null +++ b/lib/mm/memlock.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2003 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#include "lib.h" +#include "memlock.h" +#include "pool.h" +#include "defaults.h" + +#include +#include +#include +#include +#include +#include + +#ifndef DEVMAPPER_SUPPORT + +void memlock_inc(void) +{ + return; +} +void memlock_dec(void) +{ + return; +} +int memlock(void) +{ + return 0; +} + +#else /* DEVMAPPER_SUPPORT */ + +static size_t _size_stack; +static size_t _size_malloc_tmp; +static size_t _size_malloc = 2000000; + +static void *_malloc_mem = NULL; +static int _memlock_count = 0; +static int _priority; +static int _default_priority; + +static void _touch_memory(void *mem, size_t size) +{ + size_t pagesize = getpagesize(); + void *pos = mem; + void *end = mem + size - sizeof(long); + + while (pos < end) { + *(long *) pos = 1; + pos += pagesize; + } +} + +static void _allocate_memory(void) +{ + void *stack_mem, *temp_malloc_mem; + + if ((stack_mem = alloca(_size_stack))) + _touch_memory(stack_mem, _size_stack); + + if ((temp_malloc_mem = malloc(_size_malloc_tmp))) + _touch_memory(temp_malloc_mem, _size_malloc_tmp); + + if ((_malloc_mem = malloc(_size_malloc))) + _touch_memory(_malloc_mem, _size_malloc); + + free(temp_malloc_mem); +} + +static void _release_memory(void) +{ + free(_malloc_mem); +} + +/* Stop memory getting swapped out */ +static void _lock_memory(void) +{ +#ifdef MCL_CURRENT + if (mlockall(MCL_CURRENT | MCL_FUTURE)) + log_sys_error("mlockall", ""); + else + log_very_verbose("Locking memory"); +#endif + _allocate_memory(); + + errno = 0; + if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno) + log_sys_error("getpriority", ""); + else + if (setpriority(PRIO_PROCESS, 0, _default_priority)) + log_error("setpriority %u failed: %s", + _default_priority, strerror(errno)); +} + +static void _unlock_memory(void) +{ +#ifdef MCL_CURRENT + if (munlockall()) + log_sys_error("munlockall", ""); + else + log_very_verbose("Unlocking memory"); +#endif + _release_memory(); + if (setpriority(PRIO_PROCESS, 0, _priority)) + log_error("setpriority %u failed: %s", _priority, + strerror(errno)); +} + +void memlock_inc(void) +{ + if (!_memlock_count++) + _lock_memory(); + log_debug("memlock_count inc to %d", _memlock_count); +} + +void memlock_dec(void) +{ + if (_memlock_count && (!--_memlock_count)) + _unlock_memory(); + log_debug("memlock_count dec to %d", _memlock_count); +} + +int memlock(void) +{ + return _memlock_count; +} + +void memlock_init(struct cmd_context *cmd) +{ + _size_stack = find_config_int(cmd->cf->root, + "activation/reserved_stack", + '/', DEFAULT_RESERVED_STACK) * 1024; + _size_malloc_tmp = find_config_int(cmd->cf->root, + "activation/reserved_memory", + '/', DEFAULT_RESERVED_MEMORY) * 1024; + _default_priority = find_config_int(cmd->cf->root, + "activation/process_priority", + '/', DEFAULT_PROCESS_PRIORITY); +} + +#endif diff --git a/lib/mm/memlock.h b/lib/mm/memlock.h new file mode 100644 index 000000000..53a2a85a7 --- /dev/null +++ b/lib/mm/memlock.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#ifndef LVM_MEMLOCK_H +#define LVM_MEMLOCK_H + +#include "toolcontext.h" + +void memlock_inc(void); +void memlock_dec(void); +int memlock(void); +void memlock_init(struct cmd_context *cmd); + +#endif diff --git a/lib/mm/xlate.h b/lib/mm/xlate.h index 4af5c59f3..05a9e5b52 100644 --- a/lib/mm/xlate.h +++ b/lib/mm/xlate.h @@ -8,10 +8,37 @@ #ifndef _LVM_XLATE_H #define _LVM_XLATE_H -#include - -#define xlate16(x) __cpu_to_le16((x)) -#define xlate32(x) __cpu_to_le32((x)) -#define xlate64(x) __cpu_to_le64((x)) +#ifdef linux +# include +# define xlate16(x) __cpu_to_le16((x)) +# define xlate32(x) __cpu_to_le32((x)) +# define xlate64(x) __cpu_to_le64((x)) +#else +# include +# if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN) +# error "Undefined or unrecognised BYTE_ORDER"; +# endif +# if BYTE_ORDER == LITTLE_ENDIAN +# define xlate16(x) (x) +# define xlate32(x) (x) +# define xlate64(x) (x) +# else +# define xlate16(x) (((x) & 0x00ffU) << 8 | \ + ((x) & 0xff00U) >> 8) +# define xlate32(x) (((x) & 0x000000ffU) << 24 | \ + ((x) & 0xff000000U) >> 24 | \ + ((x) & 0x0000ff00U) << 8 | \ + ((x) & 0x00ff0000U) >> 8) +# define xlate64(x) (((x) & 0x00000000000000ffU) << 56 | \ + ((x) & 0xff00000000000000U) >> 56 | \ + ((x) & 0x000000000000ff00U) << 40 | \ + ((x) & 0x00ff000000000000U) >> 40 | \ + ((x) & 0x0000000000ff0000U) << 24 | \ + ((x) & 0x0000ff0000000000U) >> 24 | \ + ((x) & 0x00000000ff000000U) << 8 | \ + ((x) & 0x000000ff00000000U) >> 8) +# endif +#endif #endif diff --git a/lib/report/report.c b/lib/report/report.c index 92aa3c239..97adeb900 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -213,8 +213,13 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field, /* Snapshot dropped? */ if ((snap = find_cow(lv)) && (!lv_snapshot_percent(snap->cow, &snap_percent) || - snap_percent < 0)) + snap_percent < 0 || snap_percent >= 100)) { repstr[0] = toupper(repstr[0]); + if (info.suspended) + repstr[4] = 'S'; + else + repstr[4] = 'I'; + } } else { repstr[4] = '-'; @@ -582,6 +587,7 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field, { const struct logical_volume *lv = (const struct logical_volume *) data; struct snapshot *snap; + struct lvinfo info; float snap_percent; uint64_t *sortval; char *repstr; @@ -591,7 +597,8 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field, return 0; } - if (!(snap = find_cow(lv))) { + if (!(snap = find_cow(lv)) || + (lv_info(snap->cow, &info) && !info.exists)) { field->report_string = ""; *sortval = UINT64_C(0); field->sort_value = sortval; diff --git a/libdm/datastruct/list.h b/libdm/datastruct/list.h index 6041c1dac..df3d32aea 100644 --- a/libdm/datastruct/list.h +++ b/libdm/datastruct/list.h @@ -13,6 +13,8 @@ struct list { struct list *n, *p; }; +#define LIST_INIT(name) struct list name = { &(name), &(name) } + static inline void list_init(struct list *head) { head->n = head->p = head; @@ -64,6 +66,9 @@ static inline struct list *list_next(struct list *head, struct list *elem) #define list_iterate(v, head) \ for (v = (head)->n; v != head; v = v->n) +#define list_uniterate(v, head, start) \ + for (v = (start)->p; v != head; v = v->p) + #define list_iterate_safe(v, t, head) \ for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) @@ -81,6 +86,9 @@ static inline unsigned int list_size(const struct list *head) #define list_item(v, t) \ ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list)) +#define list_struct_base(v, t, h) \ + ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h)) + /* Given a known element in a known structure, locate another */ #define struct_field(v, t, e, f) \ (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f) diff --git a/man/Makefile.in b/man/Makefile.in index 30c70b2e6..41331b169 100644 --- a/man/Makefile.in +++ b/man/Makefile.in @@ -23,8 +23,8 @@ VPATH = @srcdir@ MAN5=lvm.conf.5 MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \ lvreduce.8 lvremove.8 lvrename.8 lvs.8 lvscan.8 pvchange.8 \ - pvcreate.8 pvdisplay.8 pvremove.8 pvs.8 pvscan.8 vgcfgbackup.8 \ - vgcfgrestore.8 vgchange.8 vgck.8 vgcreate.8 \ + pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 pvs.8 pvscan.8 \ + vgcfgbackup.8 vgcfgrestore.8 vgchange.8 vgck.8 vgcreate.8 \ vgconvert.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \ vgrename.8 vgs.8 vgscan.8 MAN5DIR=${mandir}/man5 diff --git a/man/lvcreate.8 b/man/lvcreate.8 index ed4ab82c3..e4e3c008b 100644 --- a/man/lvcreate.8 +++ b/man/lvcreate.8 @@ -31,7 +31,7 @@ the volume group can be extended ( see .B vgextend(8) ) with other physical volumes or by reducing existing logical volumes of this volume group in size ( see -.B lvreduce(8), e2fsadm(8) +.B lvreduce(8) ). .br The second form supports the creation of snapshot logical volumes which diff --git a/man/lvreduce.8 b/man/lvreduce.8 index d9ce55e59..c56a87239 100644 --- a/man/lvreduce.8 +++ b/man/lvreduce.8 @@ -17,9 +17,6 @@ You should therefore ensure that the (eg) filesystem on the volume is resized .i before running lvreduce so that the extents that are to be removed are not in use. -If the filesystem is ext2 then you can use the -.B e2fsadm(8) -command to both resize the filesystem and the logical volume together. .br. Shrinking snapshot logical volumes (see .B lvcreate(8) diff --git a/tools/archive.c b/tools/archive.c index 9e37ee5d4..1fb8f57af 100644 --- a/tools/archive.c +++ b/tools/archive.c @@ -234,7 +234,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg) { struct list *pvh; struct physical_volume *pv; - struct cache_info *info; + struct lvmcache_info *info; /* * FIXME: Check that the PVs referenced in the backup are @@ -270,7 +270,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg) } } - if (!vg_write(vg)) { + if (!vg_write(vg) || !vg_commit(vg)) { stack; return 0; } diff --git a/tools/lvchange.c b/tools/lvchange.c index 42ab1f083..3190f5de0 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -49,20 +49,25 @@ static int lvchange_permission(struct cmd_context *cmd, lv->name); } - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { - log_error("Failed to lock %s", lv->name); - return 0; - } - log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) { - /* FIXME: Attempt reversion? */ - unlock_lv(cmd, lv->lvid.s); + stack; return 0; } backup(lv->vg); + if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { + log_error("Failed to lock %s", lv->name); + vg_revert(lv->vg); + return 0; + } + + if (!vg_commit(lv->vg)) { + unlock_lv(cmd, lv->lvid.s); + return 0; + } + log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!unlock_lv(cmd, lv->lvid.s)) { log_error("Problem reactivating %s", lv->name); @@ -138,20 +143,25 @@ static int lvchange_contiguous(struct cmd_context *cmd, lv->name); } - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { - log_error("Failed to lock %s", lv->name); - return 0; - } - log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) { - /* FIXME: Attempt reversion? */ - unlock_lv(cmd, lv->lvid.s); + stack; return 0; } backup(lv->vg); + if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { + log_error("Failed to lock %s", lv->name); + vg_revert(lv->vg); + return 0; + } + + if (!vg_commit(lv->vg)) { + unlock_lv(cmd, lv->lvid.s); + return 0; + } + if (!unlock_lv(cmd, lv->lvid.s)) { log_error("Problem reactivating %s", lv->name); return 0; @@ -186,20 +196,26 @@ static int lvchange_readahead(struct cmd_context *cmd, log_verbose("Setting read ahead to %u for \"%s\"", read_ahead, lv->name); - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { - log_error("Failed to lock %s", lv->name); - return 0; - } - log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) { - /* FIXME: Attempt reversion? */ - unlock_lv(cmd, lv->lvid.s); + stack; return 0; } backup(lv->vg); + if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { + log_error("Failed to lock %s", lv->name); + vg_revert(lv->vg); + return 0; + } + + if (!vg_commit(lv->vg)) { + unlock_lv(cmd, lv->lvid.s); + return 0; + } + + log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!unlock_lv(cmd, lv->lvid.s)) { log_error("Problem reactivating %s", lv->name); return 0; @@ -245,20 +261,26 @@ static int lvchange_persistent(struct cmd_context *cmd, "for \"%s\"", lv->major, lv->minor, lv->name); } - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { - log_error("Failed to lock %s", lv->name); - return 0; - } - log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) { - /* FIXME: Attempt reversion? */ - unlock_lv(cmd, lv->lvid.s); + stack; return 0; } backup(lv->vg); + if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { + log_error("Failed to lock %s", lv->name); + vg_revert(lv->vg); + return 0; + } + + if (!vg_commit(lv->vg)) { + unlock_lv(cmd, lv->lvid.s); + return 0; + } + + log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!unlock_lv(cmd, lv->lvid.s)) { log_error("Problem reactivating %s", lv->name); return 0; diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 214ac2fa7..4d11716f4 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -187,7 +187,7 @@ static int _read_stripe_params(struct lvcreate_params *lp, log_print("Using default stripesize %dKB", lp->stripe_size / 2); } - if (argc && argc < lp->stripes) { + if (argc && (unsigned) argc < lp->stripes) { log_error("Too few physical volumes on " "command line for %d-way striping", lp->stripes); return 0; @@ -324,7 +324,7 @@ static int _zero_lv(struct cmd_context *cmd, struct logical_volume *lv) return 0; } - if (!(dev_open(dev, O_WRONLY))) + if (!dev_open_quiet(dev)) return 0; dev_zero(dev, UINT64_C(0), (size_t) 4096); @@ -458,13 +458,22 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; /* store vg on disk(s) */ - if (!vg_write(vg)) + if (!vg_write(vg)) { + stack; return 0; + } + + backup(vg); + + if (!vg_commit(vg)) { + stack; + return 0; + } if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE)) { if (lp->snapshot) /* FIXME Remove the failed lv we just added */ - log_error("Aborting. Failed to wipe snapshot " + log_error("Aborting. Failed to activate snapshot " "exception store. Remove new LV and retry."); else log_error("Failed to activate new LV."); @@ -489,6 +498,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; } + /* FIXME write/commit/backup sequence issue */ if (!lock_vol(cmd, org->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { log_error("Failed to lock origin %s", org->name); return 0; @@ -500,7 +510,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) } /* store vg on disk(s) */ - if (!vg_write(vg)) + if (!vg_write(vg) || !vg_commit(vg)) return 0; if (!unlock_lv(cmd, org->lvid.s)) { @@ -508,7 +518,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; } } - + /* FIXME out of sequence */ backup(vg); log_print("Logical volume \"%s\" created", lv->name); diff --git a/tools/lvm.c b/tools/lvm.c index 304f0a233..8bde7e8e7 100644 --- a/tools/lvm.c +++ b/tools/lvm.c @@ -752,7 +752,7 @@ static int _run_command(struct cmd_context *cmd, int argc, char **argv) out: if (test_mode()) { log_verbose("Test mode: Wiping internal cache"); - cache_destroy(); + lvmcache_destroy(); } cmd->current_settings = cmd->default_settings; diff --git a/tools/lvmdiskscan.c b/tools/lvmdiskscan.c index 80efb63ba..74399f462 100644 --- a/tools/lvmdiskscan.c +++ b/tools/lvmdiskscan.c @@ -64,10 +64,10 @@ static int _check_device(struct cmd_context *cmd, struct device *dev) char buffer; uint64_t size; - if (!dev_open(dev, 0)) { + if (!dev_open(dev)) { return 0; } - if (dev_read(dev, UINT64_C(0), (size_t) 1, &buffer) != 1) { + if (!dev_read(dev, UINT64_C(0), (size_t) 1, &buffer)) { dev_close(dev); return 0; } diff --git a/tools/lvremove.c b/tools/lvremove.c index 9d45ad6ab..cc5dc72bd 100644 --- a/tools/lvremove.c +++ b/tools/lvremove.c @@ -93,6 +93,9 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, backup(vg); + if (!vg_commit(vg)) + return ECMD_FAILED; + log_print("Logical volume \"%s\" successfully removed", lv->name); return 0; } @@ -104,6 +107,6 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL, + return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL, &lvremove_single); } diff --git a/tools/lvrename.c b/tools/lvrename.c index 80278670f..35e1b230c 100644 --- a/tools/lvrename.c +++ b/tools/lvrename.c @@ -148,26 +148,38 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) goto error; } - if (!archive(lv->vg)) - goto error; - - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD | - LCK_NONBLOCK)) + if (!archive(lv->vg)) { + stack; goto error; + } if (!(lv->name = pool_strdup(cmd->mem, lv_name_new))) { log_error("Failed to allocate space for new name"); - goto lverror; + goto error; } log_verbose("Writing out updated volume group"); - if (!vg_write(vg)) - goto lverror; - - unlock_lv(cmd, lv->lvid.s); + if (!vg_write(vg)) { + stack; + goto error; + } backup(lv->vg); + if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD | + LCK_NONBLOCK)) { + stack; + goto error; + } + + if (!vg_commit(vg)) { + stack; + unlock_lv(cmd, lv->lvid.s); + goto error; + } + + unlock_lv(cmd, lv->lvid.s); + unlock_vg(cmd, vg_name); log_print("Renamed \"%s\" to \"%s\" in volume group \"%s\"", @@ -175,9 +187,6 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) return 0; - lverror: - unlock_lv(cmd, lv->lvid.s); - error: unlock_vg(cmd, vg_name); return ECMD_FAILED; diff --git a/tools/lvresize.c b/tools/lvresize.c index e22eb3f39..bb604d926 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -24,6 +24,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) { struct volume_group *vg; struct logical_volume *lv; + struct snapshot *snap; struct lvinfo info; uint32_t extents = 0; uint32_t size = 0; @@ -34,7 +35,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) sign_t sign = SIGN_NONE; char *lv_name; const char *vg_name; - char *st; + char *st, *lock_lvid; const char *cmd_name; struct list *pvh, *segh; struct lv_list *lvl; @@ -368,21 +369,33 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) goto error; } - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { - log_error("Can't get lock for %s", lv_name); - goto error; - } - /* store vg on disk(s) */ if (!vg_write(vg)) { - /* FIXME: Attempt reversion? */ - unlock_lv(cmd, lv->lvid.s); + stack; goto error; } backup(vg); - if (!unlock_lv(cmd, lv->lvid.s)) { + /* If snapshot, must suspend all associated devices */ + if ((snap = find_cow(lv))) + lock_lvid = snap->origin->lvid.s; + else + lock_lvid = lv->lvid.s; + + if (!lock_vol(cmd, lock_lvid, LCK_LV_SUSPEND | LCK_HOLD)) { + log_error("Can't get lock for %s", lv_name); + vg_revert(vg); + goto error; + } + + if (!vg_commit(vg)) { + stack; + unlock_lv(cmd, lock_lvid); + goto error; + } + + if (!unlock_lv(cmd, lock_lvid)) { log_error("Problem reactivating %s", lv_name); goto error; } diff --git a/tools/lvscan.c b/tools/lvscan.c index c7833adac..e25d3f024 100644 --- a/tools/lvscan.c +++ b/tools/lvscan.c @@ -47,8 +47,6 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv, display_size(cmd, lv->size / 2, SIZE_SHORT), get_alloc_string(lv->alloc)); - /* FIXME sprintf? */ - lv_total++; lv_capacity_total += lv->size; @@ -65,5 +63,4 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv) return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL, &lvscan_single); - } diff --git a/tools/pvchange.c b/tools/pvchange.c index 5f33c1831..5bdfc2853 100644 --- a/tools/pvchange.c +++ b/tools/pvchange.c @@ -122,7 +122,7 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv, log_verbose("Updating physical volume \"%s\"", pv_name); if (*pv->vg_name) { - if (!vg_write(vg)) { + if (!vg_write(vg) || !vg_commit(vg)) { unlock_vg(cmd, pv->vg_name); log_error("Failed to store physical volume \"%s\" in " "volume group \"%s\"", pv_name, vg->name); diff --git a/tools/pvcreate.c b/tools/pvcreate.c index 5211b2da4..cedf6a312 100644 --- a/tools/pvcreate.c +++ b/tools/pvcreate.c @@ -39,6 +39,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name) } /* is there a pv here already */ + /* FIXME Use partial mode here? */ if (!(pv = pv_read(cmd, name, NULL, NULL))) return 1; diff --git a/tools/pvmove.c b/tools/pvmove.c index 1ad200fba..b027f0f37 100644 --- a/tools/pvmove.c +++ b/tools/pvmove.c @@ -204,6 +204,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr, *lv; struct list *lvh; + /* FIXME Cope with non-contiguous => splitting existing segments */ if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d", LVM_READ | LVM_WRITE, ALLOC_CONTIGUOUS, vg))) { @@ -220,6 +221,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, list_init(*lvs_changed); + /* Find segments to be moved and set up mirrors */ list_iterate(lvh, &vg->lvs) { lv = list_item(lvh, struct lv_list)->lv; if ((lv == lv_mirr) || (lv_name && strcmp(lv->name, lv_name))) @@ -251,6 +253,14 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv_mirr, struct list *lvs_changed, int first_time) { + log_verbose("Updating volume group metadata"); + if (!vg_write(vg)) { + log_error("ABORTING: Volume group metadata update failed."); + return 0; + } + + backup(vg); + if (!lock_lvs(cmd, lvs_changed, LCK_LV_SUSPEND | LCK_HOLD)) { stack; return 0; @@ -260,12 +270,12 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg, if (!lock_vol(cmd, lv_mirr->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) { stack; unlock_lvs(cmd, lvs_changed); + vg_revert(vg); return 0; } } - log_verbose("Updating volume group metadata"); - if (!vg_write(vg)) { + if (!vg_commit(vg)) { log_error("ABORTING: Volume group metadata update failed."); if (!first_time) unlock_lv(cmd, lv_mirr->lvid.s); @@ -273,8 +283,6 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg, return 0; } - backup(vg); - if (first_time) { if (!lock_vol(cmd, lv_mirr->lvid.s, LCK_LV_ACTIVATE)) { log_error @@ -308,6 +316,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name, struct logical_volume *lv_mirr; int first_time = 1; + /* Find PV (in VG) */ if (!(pv = _find_pv_by_name(cmd, pv_name))) { stack; return EINVALID_CMD_LINE; @@ -321,6 +330,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name, } } + /* Read VG */ log_verbose("Finding volume group \"%s\"", pv->vg_name); if (!(vg = _get_vg(cmd, pv->vg_name))) { @@ -340,6 +350,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name, return ECMD_FAILED; } + /* Ensure mirror LV is active */ if (!lock_vol(cmd, lv_mirr->lvid.s, LCK_LV_ACTIVATE)) { log_error ("ABORTING: Temporary mirror activation failed."); @@ -398,6 +409,17 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, { int r = 1; + if (!remove_pvmove_mirrors(vg, lv_mirr)) { + log_error("ABORTING: Removal of temporary mirror failed"); + return 0; + } + + if (!vg_write(vg)) { + log_error("ABORTING: Failed to write new data locations " + "to disk."); + return 0; + } + if (!lock_lvs(cmd, lvs_changed, LCK_LV_SUSPEND | LCK_HOLD)) { log_error("Locking LVs to remove temporary mirror failed"); r = 0; @@ -408,16 +430,10 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, r = 0; } - if (!remove_pvmove_mirrors(vg, lv_mirr)) { - log_error("ABORTING: Removal of temporary mirror failed"); - unlock_lv(cmd, lv_mirr->lvid.s); - unlock_lvs(cmd, lvs_changed); - return 0; - } - - if (!vg_write(vg)) { + if (!vg_commit(vg)) { log_error("ABORTING: Failed to write new data locations " "to disk."); + vg_revert(vg); unlock_lv(cmd, lv_mirr->lvid.s); unlock_lvs(cmd, lvs_changed); return 0; @@ -435,22 +451,21 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, r = 0; } + unlock_lvs(cmd, lvs_changed); + if (!lv_remove(vg, lv_mirr)) { log_error("ABORTING: Removal of temporary pvmove LV failed"); - unlock_lvs(cmd, lvs_changed); return 0; } log_verbose("Writing out final volume group after pvmove"); - if (!vg_write(vg)) { + if (!vg_write(vg) || !vg_commit(vg)) { log_error("ABORTING: Failed to write new data locations " "to disk."); - unlock_lvs(cmd, lvs_changed); return 0; } - unlock_lvs(cmd, lvs_changed); - + /* FIXME backup positioning */ backup(vg); return r; @@ -466,7 +481,6 @@ static int _check_pvmove_status(struct cmd_context *cmd, float segment_percent = 0.0, overall_percent = 0.0; uint32_t event_nr = 0; - /* By default, caller should not retry */ *finished = 1; if (!lv_mirror_percent(lv_mirr, !parms->interval, &segment_percent, diff --git a/tools/pvscan.c b/tools/pvscan.c index b52458711..0ea4b8755 100644 --- a/tools/pvscan.c +++ b/tools/pvscan.c @@ -134,7 +134,7 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv) persistent_filter_wipe(cmd->filter); log_verbose("Wiping internal cache"); - cache_destroy(); + lvmcache_destroy(); log_verbose("Walking through all physical volumes"); if (!(pvslist = get_pvs(cmd))) diff --git a/tools/toollib.c b/tools/toollib.c index 1b49acb79..15bb6890b 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -76,13 +76,31 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, log_verbose("Using logical volume(s) on command line"); for (; opt < argc; opt++) { char *lv_name = argv[opt]; + char *vgname_def; int vgname_provided = 1; + int dev_dir_found = 0; /* Do we have a vgname or lvname? */ vgname = lv_name; + if (*vgname == '/') { + while (*vgname == '/') + vgname++; + vgname--; + } if (!strncmp(vgname, cmd->dev_dir, - strlen(cmd->dev_dir))) + strlen(cmd->dev_dir))) { vgname += strlen(cmd->dev_dir); + dev_dir_found = 1; + while (*vgname == '/') + vgname++; + } + if (*vgname == '/') { + log_error("\"%s\": Invalid path for Logical " + "Volume", lv_name); + if (ret_max < ECMD_FAILED) + ret_max = ECMD_FAILED; + continue; + } if (strchr(vgname, '/')) { /* Must be an LV */ vgname_provided = 0; @@ -93,6 +111,12 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, } } + if (!dev_dir_found && + (vgname_def = default_vgname(cmd))) { + vgname_provided = 0; + vgname = vgname_def; + } + log_verbose("Finding volume group \"%s\"", vgname); if (!lock_vol(cmd, vgname, lock_type)) { log_error("Can't lock %s: skipping", vgname); @@ -238,13 +262,18 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, struct list *slh, *vgnames; struct volume_group *vg; - char *vg_name; + const char *vg_name; char *dev_dir = cmd->dev_dir; if (argc) { log_verbose("Using volume group(s) on command line"); for (; opt < argc; opt++) { vg_name = argv[opt]; + if (*vg_name == '/') { + while (*vg_name == '/') + vg_name++; + vg_name--; + } if (!strncmp(vg_name, dev_dir, strlen(dev_dir))) vg_name += strlen(dev_dir); if (strchr(vg_name, '/')) { @@ -378,16 +407,34 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name) const char *vg_name = lv_name; char *st; char *dev_dir = cmd->dev_dir; + int dev_dir_provided = 0; /* Path supplied? */ if (vg_name && strchr(vg_name, '/')) { /* Strip dev_dir (optional) */ - if (!strncmp(vg_name, dev_dir, strlen(dev_dir))) + if (*vg_name == '/') { + while (*vg_name == '/') + vg_name++; + vg_name--; + } + if (!strncmp(vg_name, dev_dir, strlen(dev_dir))) { vg_name += strlen(dev_dir); + dev_dir_provided = 1; + while (*vg_name == '/') + vg_name++; + } + if (*vg_name == '/') { + log_error("\"%s\": Invalid path for Logical " + "Volume", lv_name); + return 0; + } + + /* Require exactly one set of consecutive slashes */ + if ((st = strchr(vg_name, '/'))) + while (*st == '/') + st++; - /* Require exactly one slash */ - /* FIXME But allow for consecutive slashes */ - if (!(st = strchr(vg_name, '/')) || (strchr(st + 1, '/'))) { + if (!strchr(vg_name, '/') || strchr(st, '/')) { log_error("\"%s\": Invalid path for Logical Volume", lv_name); return 0; @@ -424,6 +471,11 @@ char *default_vgname(struct cmd_context *cmd) return 0; /* Strip dev_dir (optional) */ + if (*vg_path == '/') { + while (*vg_path == '/') + vg_path++; + vg_path--; + } if (!strncmp(vg_path, dev_dir, strlen(dev_dir))) vg_path += strlen(dev_dir); diff --git a/tools/tools.h b/tools/tools.h index 4ce91fe42..d3d9cbb8d 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -14,7 +14,7 @@ #include "log.h" #include "activate.h" #include "archive.h" -#include "cache.h" +#include "lvmcache.h" #include "config.h" #include "defaults.h" #include "dbg_malloc.h" @@ -72,7 +72,7 @@ struct arg { const char *long_arg; int (*fn) (struct cmd_context * cmd, struct arg * a); - int count; + unsigned int count; char *value; int32_t i_value; uint32_t ui_value; @@ -111,7 +111,7 @@ int units_arg(struct cmd_context *cmd, struct arg *a); char yes_no_prompt(const char *prompt, ...); /* we use the enums to access the switches */ -static inline const int arg_count(struct cmd_context *cmd, int a) +static inline const unsigned int arg_count(struct cmd_context *cmd, int a) { return cmd->args[a].count; } diff --git a/tools/vgchange.c b/tools/vgchange.c index 2e9ed17f3..b85fe9be3 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -111,7 +111,7 @@ static void _vgchange_resizeable(struct cmd_context *cmd, else vg->status &= ~RESIZEABLE_VG; - if (!vg_write(vg)) + if (!vg_write(vg) || !vg_commit(vg)) return; backup(vg); @@ -144,7 +144,7 @@ static void _vgchange_logicalvolume(struct cmd_context *cmd, vg->max_lv = max_lv; - if (!vg_write(vg)) + if (!vg_write(vg) || !vg_commit(vg)) return; backup(vg); diff --git a/tools/vgck.c b/tools/vgck.c index 5cd9a8585..6a6eb1ec7 100644 --- a/tools/vgck.c +++ b/tools/vgck.c @@ -38,6 +38,7 @@ static int vgck_single(struct cmd_context *cmd, const char *vg_name, return ECMD_FAILED; } + /* FIXME: free */ return 0; } diff --git a/tools/vgcreate.c b/tools/vgcreate.c index 52a29c0c7..707dc01cd 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -110,7 +110,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) } /* Store VG on disk(s) */ - if (!vg_write(vg)) { + if (!vg_write(vg) || !vg_commit(vg)) { unlock_vg(cmd, vg_name); unlock_vg(cmd, ""); return ECMD_FAILED; diff --git a/tools/vgdisplay.c b/tools/vgdisplay.c index 7a4e4beda..e81e05d56 100644 --- a/tools/vgdisplay.c +++ b/tools/vgdisplay.c @@ -89,6 +89,8 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + /* FIXME -D disk_ARG is now redundant */ + /********* FIXME: Do without this - or else 2(+) passes! Figure out longest volume group name for (c = opt; opt < argc; opt++) { diff --git a/tools/vgexport.c b/tools/vgexport.c index 5e521f015..59208f2d6 100644 --- a/tools/vgexport.c +++ b/tools/vgexport.c @@ -55,7 +55,7 @@ static int vgexport_single(struct cmd_context *cmd, const char *vg_name, vg->status |= EXPORTED_VG; - if (!vg_write(vg)) + if (!vg_write(vg) || !vg_commit(vg)) goto error; backup(vg); diff --git a/tools/vgextend.c b/tools/vgextend.c index 0cb9f0731..a391b1a00 100644 --- a/tools/vgextend.c +++ b/tools/vgextend.c @@ -92,7 +92,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) "physical volumes", vg_name, argc); /* store vg on disk(s) */ - if (!vg_write(vg)) + if (!vg_write(vg) || !vg_commit(vg)) goto error; backup(vg); diff --git a/tools/vgimport.c b/tools/vgimport.c index d515caada..03b25911b 100644 --- a/tools/vgimport.c +++ b/tools/vgimport.c @@ -45,7 +45,7 @@ static int vgimport_single(struct cmd_context *cmd, const char *vg_name, vg->status &= ~EXPORTED_VG; - if (!vg_write(vg)) + if (!vg_write(vg) || !vg_commit(vg)) goto error; backup(vg); diff --git a/tools/vgmerge.c b/tools/vgmerge.c index 959edc660..58c980e9a 100644 --- a/tools/vgmerge.c +++ b/tools/vgmerge.c @@ -165,7 +165,7 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, /* store it on disks */ log_verbose("Writing out updated volume group"); - if (!vg_write(vg_to)) { + if (!vg_write(vg_to) || !vg_commit(vg_to)) { goto error; } diff --git a/tools/vgreduce.c b/tools/vgreduce.c index 6ec664657..0d39d4bb7 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -204,7 +204,7 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, vg->free_count -= pv->pe_count - pv->pe_alloc_count; vg->extent_count -= pv->pe_count; - if (!vg_write(vg)) { + if (!vg_write(vg) || !vg_commit(vg)) { log_error("Removal of physical volume \"%s\" from " "\"%s\" failed", name, vg->name); return ECMD_FAILED; @@ -308,7 +308,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv) vg->status &= ~PARTIAL_VG; vg->status |= LVM_WRITE; - if (!vg_write(vg)) { + if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to write out a consistent VG for %s", vg_name); unlock_vg(cmd, vg_name); diff --git a/tools/vgrename.c b/tools/vgrename.c index c1d3fbe3a..9b485cdfd 100644 --- a/tools/vgrename.c +++ b/tools/vgrename.c @@ -93,6 +93,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) } if (lvs_in_vg_activated(vg_old)) { + unlock_vg(cmd, vg_name_old); log_error("Volume group \"%s\" still has active LVs", vg_name_old); /* FIXME Remove this restriction */ @@ -136,7 +137,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) /* store it on disks */ log_verbose("Writing out updated volume group"); - if (!vg_write(vg_old)) { + if (!vg_write(vg_old) || !vg_commit(vg_old)) { goto error; } diff --git a/tools/vgscan.c b/tools/vgscan.c index 0af067d79..7710c48bc 100644 --- a/tools/vgscan.c +++ b/tools/vgscan.c @@ -54,7 +54,7 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv) persistent_filter_wipe(cmd->filter); log_verbose("Wiping internal cache"); - cache_destroy(); + lvmcache_destroy(); log_print("Reading all physical volumes. This may take a while..."); diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 4d598d716..4cce6fe3f 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -258,13 +258,13 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) if (!archive(vg_to)) goto error; - if (!vg_write(vg_to)) + if (!vg_write(vg_to) || !vg_commit(vg_to)) goto error; backup(vg_to); /* Write out updated old VG */ - if (!vg_write(vg_from)) + if (!vg_write(vg_from) || !vg_commit(vg_from)) goto error; backup(vg_from); @@ -279,7 +279,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) vg_to->status &= ~EXPORTED_VG; - if (!vg_write(vg_to)) + if (!vg_write(vg_to) || !vg_write(vg_to)) goto error; backup(vg_to);