diff --git a/WHATS_NEW b/WHATS_NEW index ebc58a033..cf5f8c9cc 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,8 @@ Version 2.02.06 - ================================= + Create a log header for replacement in-sync mirror log. + Use set_lv() and dev_set() to wipe sections of devices. + Add mirror_in_sync() flag to avoid unnecessary resync on activation. Add mirror_library description to example.conf. Fix uuid_from_num() buffer overrun. Make SIZE_SHORT the default for display_size(). diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index a499288bb..f0fd39305 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -602,7 +602,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer) return _aligned_io(&where, buffer, 1); } -int dev_zero(struct device *dev, uint64_t offset, size_t len) +int dev_set(struct device *dev, uint64_t offset, size_t len, int value) { size_t s; char buffer[4096]; @@ -620,7 +620,7 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len) " sectors", dev_name(dev), offset >> SECTOR_SHIFT, len >> SECTOR_SHIFT); - memset(buffer, 0, sizeof(buffer)); + memset(buffer, value, sizeof(buffer)); while (1) { s = len > sizeof(buffer) ? sizeof(buffer) : len; if (!dev_write(dev, offset, s, buffer)) diff --git a/lib/device/device.h b/lib/device/device.h index 6a68a8fa1..4dc08e64d 100644 --- a/lib/device/device.h +++ b/lib/device/device.h @@ -80,7 +80,7 @@ const char *dev_name(const struct device *dev); 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); +int dev_set(struct device *dev, uint64_t offset, size_t len, int value); void dev_flush(struct device *dev); struct device *dev_create_file(const char *filename, struct device *dev, diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c index b7708819e..40d17a165 100644 --- a/lib/format1/disk-rep.c +++ b/lib/format1/disk-rep.c @@ -576,7 +576,7 @@ static int _write_lvs(struct disk_list *data) pos = data->pvd.lv_on_disk.base; - if (!dev_zero(data->dev, pos, data->pvd.lv_on_disk.size)) { + if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) { log_error("Couldn't zero lv area on device '%s'", dev_name(data->dev)); return 0; diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index 4cec0142f..f831e1a47 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -1073,9 +1073,9 @@ static int _mda_setup(const struct format_type *fmt, if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1, mda_size1)) return 0; - if (!dev_zero((struct device *) pv->dev, start1, - (size_t) (mda_size1 > - wipe_size ? : mda_size1))) { + if (!dev_set((struct device *) pv->dev, start1, + (size_t) (mda_size1 > + wipe_size ? : mda_size1), 0)) { log_error("Failed to wipe new metadata area"); return 0; } @@ -1119,9 +1119,9 @@ static int _mda_setup(const struct format_type *fmt, if (mda_size2) { if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2, mda_size2)) return 0; - if (!dev_zero(pv->dev, start2, - (size_t) (mda_size1 > - wipe_size ? : mda_size1))) { + if (!dev_set(pv->dev, start2, + (size_t) (mda_size1 > + wipe_size ? : mda_size1), 0)) { log_error("Failed to wipe new metadata area"); return 0; } diff --git a/lib/log/log.c b/lib/log/log.c index 80501f97d..08673daf4 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -45,6 +45,7 @@ static int _security_level = SECURITY_LEVEL; static char _cmd_name[30] = ""; static char _msg_prefix[30] = " "; static int _already_logging = 0; +static int _mirror_in_sync = 0; static lvm2_log_fn_t _lvm2_log_fn = NULL; @@ -175,6 +176,11 @@ void init_security_level(int level) _security_level = level; } +void init_mirror_in_sync(int in_sync) +{ + _mirror_in_sync = in_sync; +} + void init_cmd_name(int status) { _log_cmd_name = status; @@ -239,6 +245,11 @@ int security_level() return _security_level; } +int mirror_in_sync(void) +{ + return _mirror_in_sync; +} + void init_debug(int level) { _debug_level = level; diff --git a/lib/log/log.h b/lib/log/log.h index 7db9ea04e..e8afd4d71 100644 --- a/lib/log/log.h +++ b/lib/log/log.h @@ -73,6 +73,7 @@ void init_indent(int indent); void init_ignorelockingfailure(int level); void init_lockingfailed(int level); void init_security_level(int level); +void init_mirror_in_sync(int in_sync); void set_cmd_name(const char *cmd_name); @@ -85,6 +86,7 @@ int debug_level(void); int ignorelockingfailure(void); int lockingfailed(void); int security_level(void); +int mirror_in_sync(void); /* Suppress messages to stdout/stderr (1) or everywhere (2) */ /* Returns previous setting */ diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c index da599537d..c1abfb475 100644 --- a/lib/mirror/mirrored.c +++ b/lib/mirror/mirrored.c @@ -245,6 +245,9 @@ static int _add_log(struct dev_manager *dm, struct lv_segment *seg, return 0; } + if (mirror_in_sync() && !(seg->status & PVMOVE)) + log_flags |= DM_NOSYNC; + if (_block_on_error_available && !(seg->status & PVMOVE)) log_flags |= DM_BLOCK_ON_ERROR; diff --git a/tools/args.h b/tools/args.h index 64867eaed..5967c446d 100644 --- a/tools/args.h +++ b/tools/args.h @@ -45,6 +45,7 @@ arg(type_ARG, '\0', "type", segtype_arg) arg(alloc_ARG, '\0', "alloc", alloc_arg) arg(separator_ARG, '\0', "separator", string_arg) arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL) +arg(nosync_ARG, '\0', "nosync", NULL) /* Allow some variations */ arg(resizable_ARG, '\0', "resizable", yes_no_arg) diff --git a/tools/lvconvert.c b/tools/lvconvert.c index 2e4c0ae5b..b4f10921d 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -327,7 +327,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l if (!(log_lv = create_mirror_log(cmd, lv->vg, ah, lp->alloc, - lv->name))) { + lv->name, 0))) { log_error("Failed to create mirror log."); return 0; } @@ -390,7 +390,7 @@ static int lvconvert_snapshot(struct cmd_context *cmd, if (!lp->zero) log_error("WARNING: \"%s\" not zeroed", lv->name); - else if (!zero_lv(cmd, lv)) { + else if (!set_lv(cmd, lv, 0)) { log_error("Aborting. Failed to wipe snapshot " "exception store."); return 0; diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 23c0f3ee1..14752cdcf 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -646,7 +646,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) lp->region_size); if (!(log_lv = create_mirror_log(cmd, vg, ah, lp->alloc, - lv_name))) { + lv_name, 0))) { log_error("Failed to create mirror log."); return 0; } @@ -730,7 +730,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) } if ((lp->zero || lp->snapshot) && activation()) { - if (!zero_lv(cmd, lv) && lp->snapshot) { + if (!set_lv(cmd, lv, 0) && lp->snapshot) { /* FIXME Remove the failed lv we just added */ log_error("Aborting. Failed to wipe snapshot " "exception store. Remove new LV and retry."); diff --git a/tools/pvcreate.c b/tools/pvcreate.c index 9fd75719f..ddc28b198 100644 --- a/tools/pvcreate.c +++ b/tools/pvcreate.c @@ -96,7 +96,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name) (yes_no_prompt("Software RAID md superblock " "detected on %s. Wipe it? [y/n] ", name) == 'y'))) { log_print("Wiping software RAID md superblock on %s", name); - if (!dev_zero(dev, md_superblock, 4)) { + if (!dev_set(dev, md_superblock, 4, 0)) { log_error("Failed to wipe RAID md superblock on %s", name); return 0; @@ -225,7 +225,7 @@ static int pvcreate_single(struct cmd_context *cmd, const char *pv_name, goto error; } - if (!dev_zero(dev, UINT64_C(0), (size_t) 2048)) { + if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) { log_error("%s not wiped: aborting", pv_name); dev_close(dev); goto error; diff --git a/tools/toollib.c b/tools/toollib.c index 7afbd0c4b..4efe7d3cf 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -15,10 +15,15 @@ #include "tools.h" #include "lv_alloc.h" +#include "xlate.h" #include #include +/* From linux/drivers/md/dm-log.c */ +#define MIRROR_MAGIC 0x4D695272 +#define MIRROR_DISK_VERSION 2 + /* Command line args */ unsigned arg_count(struct cmd_context *cmd, int a) { @@ -1111,9 +1116,9 @@ int generate_log_name_format(struct volume_group *vg __attribute((unused)), } /* - * Volumes may be zeroed to remove old application data. + * Initialize the LV with 'value'. */ -int zero_lv(struct cmd_context *cmd, struct logical_volume *lv) +int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value) { struct device *dev; char *name; @@ -1126,27 +1131,80 @@ int zero_lv(struct cmd_context *cmd, struct logical_volume *lv) * (I know the device is at least 4k, but not 32k) */ if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) { - log_error("Name allocation failed - device not zeroed"); + log_error("Name allocation failed - device not cleared"); return 0; } if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir, lv->vg->name, lv->name) < 0) { - log_error("Name too long - device not zeroed (%s)", lv->name); + log_error("Name too long - device not cleared (%s)", lv->name); return 0; } - log_verbose("Zeroing start of logical volume \"%s\"", lv->name); + log_verbose("Clearing start of logical volume \"%s\"", lv->name); if (!(dev = dev_cache_get(name, NULL))) { - log_error("%s: not found: device not zeroed", name); + log_error("%s: not found: device not cleared", name); return 0; } if (!dev_open_quiet(dev)) return 0; - dev_zero(dev, UINT64_C(0), (size_t) 4096); + dev_set(dev, UINT64_C(0), (size_t) 4096, value); + dev_close_immediate(dev); + + return 1; +} + + +/* + * This function writes a new header to the mirror log header to the lv + * + * Returns: 1 on success, 0 on failure + */ +static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv) +{ + struct device *dev; + char *name; + struct { /* The mirror log header */ + uint32_t magic; + uint32_t version; + uint64_t nr_regions; + } log_header; + + log_header.magic = xlate32(MIRROR_MAGIC); + log_header.version = xlate32(MIRROR_DISK_VERSION); + log_header.nr_regions = xlate64((uint64_t)-1); + + if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) { + log_error("Name allocation failed - log header not written (%s)", + lv->name); + return 0; + } + + if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir, + lv->vg->name, lv->name) < 0) { + log_error("Name too long - log header not written (%s)", lv->name); + return 0; + } + + log_verbose("Writing log header to device, %s", lv->name); + + if (!(dev = dev_cache_get(name, NULL))) { + log_error("%s: not found: log header not written", name); + return 0; + } + + if (!dev_open_quiet(dev)) + return 0; + + if (!dev_write(dev, UINT64_C(0), sizeof(log_header), &log_header)) { + log_error("Failed to write log header to %s", name); + dev_close_immediate(dev); + return 0; + } + dev_close_immediate(dev); return 1; @@ -1156,7 +1214,8 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd, struct volume_group *vg, struct alloc_handle *ah, alloc_policy_t alloc, - const char *lv_name) + const char *lv_name, + int in_sync) { struct logical_volume *log_lv; char *log_name; @@ -1201,12 +1260,18 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd, goto error; } - if (activation() && !zero_lv(cmd, log_lv)) { + if (activation() && !set_lv(cmd, log_lv, in_sync)) { log_error("Aborting. Failed to wipe mirror log. " "Remove new LV and retry."); goto error; } + if (!_write_log_header(cmd, log_lv)) { + log_error("Aborting. Failed to write mirror log header. " + "Remove new LV and retry."); + goto error; + } + if (!deactivate_lv(cmd, log_lv)) { log_error("Aborting. Failed to deactivate mirror log. " "Remove new LV and retry."); diff --git a/tools/toollib.h b/tools/toollib.h index 9e58d7d2a..ec9f7f07c 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -97,8 +97,9 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd, struct volume_group *vg, struct alloc_handle *ah, alloc_policy_t alloc, - const char *lv_name); + const char *lv_name, + int in_sync); -int zero_lv(struct cmd_context *cmd, struct logical_volume *lv); +int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value); #endif