diff --git a/Makefile.in b/Makefile.in index 4d9597b36..489ba3bb4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,6 +26,8 @@ SUBDIRS += lib tools ifeq ($(MAKECMDGOALS),distclean) SUBDIRS += lib/format1 \ + lib/mirror \ + lib/snapshot \ po \ test/mm test/device test/format1 test/regex test/filters endif diff --git a/WHATS_NEW b/WHATS_NEW index 7c864f007..dfc20b636 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,7 @@ Version 2.00.16 - ============================= + Begin separating out segment code. There's a lot of change here. + Compress any (obsolete) long LVM1 pvids encountered. Support for tagged config files. Don't abort operations if selinux present but disabled. Fix typo in configure which left HAVE_LIBDL unset. diff --git a/configure b/configure index 2e931b2fe..79859784f 100755 --- a/configure +++ b/configure @@ -309,7 +309,7 @@ ac_includes_default="\ #endif" ac_default_prefix=/usr -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os MSGFMT JOBS STATIC_LINK LVM1 OWNER GROUP CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LD_DEPS LD_FLAGS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os MSGFMT JOBS STATIC_LINK LVM1 SNAPSHOTS MIRRORS OWNER GROUP CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LD_DEPS LD_FLAGS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -864,6 +864,10 @@ Optional Packages: --with-group=GROUP Set the group owner of installed files --with-lvm1=TYPE LVM1 metadata support: internal/shared/none TYPE=internal + --with-snapshots=TYPE Snapshot support: internal/shared/none + TYPE=internal + --with-mirrors=TYPE Mirror support: internal/shared/none + TYPE=internal --with-localedir=DIR Translation files in DIR PREFIX/share/locale --with-confdir=DIR Configuration files in DIR /etc --with-staticdir=DIR Static binary in DIR EXEC_PREFIX/sbin @@ -3974,6 +3978,50 @@ else JOBS=-j2 fi; + +# Check whether --with-snapshots or --without-snapshots was given. +if test "${with_snapshots+set}" = set; then + withval="$with_snapshots" + SNAPSHOTS="$withval" +else + SNAPSHOTS="internal" +fi; + +if [ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]; + then { { echo "$as_me:$LINENO: error: --with-snapshots parameter invalid +" >&5 +echo "$as_me: error: --with-snapshots parameter invalid +" >&2;} + { (exit 1); exit 1; }; } + exit +fi; + +if test x$SNAPSHOTS = xinternal; then + CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL" +fi + + +# Check whether --with-mirrors or --without-mirrors was given. +if test "${with_mirrors+set}" = set; then + withval="$with_mirrors" + MIRRORS="$withval" +else + MIRRORS="internal" +fi; + +if [ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]; + then { { echo "$as_me:$LINENO: error: --with-mirrors parameter invalid +" >&5 +echo "$as_me: error: --with-mirrors parameter invalid +" >&2;} + { (exit 1); exit 1; }; } + exit +fi; + +if test x$MIRRORS = xinternal; then + CFLAGS="$CFLAGS -DMIRRORED_INTERNAL" +fi + # Check whether --enable-static_link or --disable-static_link was given. if test "${enable_static_link+set}" = set; then enableval="$enable_static_link" @@ -4614,7 +4662,9 @@ else HAVE_LIBDL=no fi -if [ "x$LVM1" = xshared -a "x$STATIC_LINK" = xyes ]; +if [ \( "x$LVM1" = xshared -o \ + "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ + \) -a "x$STATIC_LINK" = xyes ]; then { { echo "$as_me:$LINENO: error: Features cannot be 'shared' when building statically " >&5 echo "$as_me: error: Features cannot be 'shared' when building statically @@ -5117,7 +5167,9 @@ fi - ac_config_files="$ac_config_files Makefile make.tmpl doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile" + + + ac_config_files="$ac_config_files Makefile make.tmpl doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -5674,6 +5726,8 @@ do "include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; "lib/format1/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/format1/Makefile" ;; + "lib/mirror/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/mirror/Makefile" ;; + "lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;; "man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; "po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;; "tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; @@ -5799,6 +5853,8 @@ s,@MSGFMT@,$MSGFMT,;t t s,@JOBS@,$JOBS,;t t s,@STATIC_LINK@,$STATIC_LINK,;t t s,@LVM1@,$LVM1,;t t +s,@SNAPSHOTS@,$SNAPSHOTS,;t t +s,@MIRRORS@,$MIRRORS,;t t s,@OWNER@,$OWNER,;t t s,@GROUP@,$GROUP,;t t s,@CLDFLAGS@,$CLDFLAGS,;t t diff --git a/configure.in b/configure.in index c35f81a76..e0a163696 100644 --- a/configure.in +++ b/configure.in @@ -123,6 +123,42 @@ fi AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2) +dnl -- snapshots inclusion type +AC_ARG_WITH(snapshots, + [ --with-snapshots=TYPE Snapshot support: internal/shared/none + [TYPE=internal] ], + [ SNAPSHOTS="$withval" ], + [ SNAPSHOTS="internal" ]) + +if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]]; + then AC_MSG_ERROR( +--with-snapshots parameter invalid +) + exit +fi; + +if test x$SNAPSHOTS = xinternal; then + CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL" +fi + +dnl -- mirrors inclusion type +AC_ARG_WITH(mirrors, + [ --with-mirrors=TYPE Mirror support: internal/shared/none + [TYPE=internal] ], + [ MIRRORS="$withval" ], + [ MIRRORS="internal" ]) + +if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]]; + then AC_MSG_ERROR( +--with-mirrors parameter invalid +) + exit +fi; + +if test x$MIRRORS = xinternal; then + CFLAGS="$CFLAGS -DMIRRORED_INTERNAL" +fi + dnl Enables staticly-linked tools AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to their libraries statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no) @@ -210,7 +246,9 @@ else fi dnl Check for shared/static conflicts -if [[ "x$LVM1" = xshared -a "x$STATIC_LINK" = xyes ]]; +if [[ \( "x$LVM1" = xshared -o \ + "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ + \) -a "x$STATIC_LINK" = xyes ]]; then AC_MSG_ERROR( Features cannot be 'shared' when building statically ) @@ -287,6 +325,8 @@ fi AC_SUBST(JOBS) AC_SUBST(STATIC_LINK) AC_SUBST(LVM1) +AC_SUBST(SNAPSHOTS) +AC_SUBST(MIRRORS) AC_SUBST(OWNER) AC_SUBST(GROUP) AC_SUBST(CFLAGS) @@ -320,6 +360,8 @@ doc/Makefile \ include/Makefile \ lib/Makefile \ lib/format1/Makefile \ +lib/mirror/Makefile \ +lib/snapshot/Makefile \ man/Makefile \ po/Makefile \ tools/Makefile \ diff --git a/include/.symlinks b/include/.symlinks index 955007c28..7c350da62 100644 --- a/include/.symlinks +++ b/include/.symlinks @@ -1,4 +1,5 @@ ../lib/activate/activate.h +../lib/activate/targets.h ../lib/cache/lvmcache.h ../lib/commands/errors.h ../lib/commands/toolcontext.h @@ -21,11 +22,14 @@ ../lib/filters/filter.h ../lib/format1/format1.h ../lib/format_text/format-text.h +../lib/format_text/text_export.h +../lib/format_text/text_import.h ../lib/label/label.h ../lib/locking/locking.h ../lib/log/log.h ../lib/metadata/lv_alloc.h ../lib/metadata/metadata.h +../lib/metadata/segtypes.h ../lib/mm/dbg_malloc.h ../lib/mm/memlock.h ../lib/mm/pool.h diff --git a/lib/Makefile.in b/lib/Makefile.in index fa640597d..7d321cc36 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -20,6 +20,14 @@ ifeq ("@LVM1@", "shared") SUBDIRS = format1 endif +ifeq ("@SNAPSHOTS@", "shared") + SUBDIRS += snapshot +endif + +ifeq ("@MIRRORS@", "shared") + SUBDIRS += mirror +endif + SOURCES =\ activate/activate.c \ cache/lvmcache.c \ @@ -57,6 +65,7 @@ SOURCES =\ metadata/metadata.c \ metadata/mirror.c \ metadata/pv_map.c \ + metadata/segtypes.c \ metadata/snapshot_manip.c \ misc/crc.c \ misc/lvm-file.c \ @@ -67,6 +76,7 @@ SOURCES =\ regex/parse_rx.c \ regex/ttree.c \ report/report.c \ + striped/striped.c \ uuid/uuid.c ifeq ("@LVM1@", "internal") @@ -80,6 +90,14 @@ ifeq ("@LVM1@", "internal") format1/vg_number.c endif +ifeq ("@SNAPSHOTS@", "internal") + SOURCES += snapshot/snapshot.c +endif + +ifeq ("@MIRRORS@", "internal") + SOURCES += mirror/mirrored.c +endif + ifeq ("@DEBUG@", "yes") SOURCES += mm/dbg_malloc.c endif diff --git a/lib/activate/activate.c b/lib/activate/activate.c index ae9fa87ae..e5533680e 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -25,6 +25,7 @@ #include "toolcontext.h" #include "dev_manager.h" #include "str_list.h" +#include "config.h" #include #include @@ -341,7 +342,7 @@ static int _lv_info(const struct logical_volume *lv, int mknodes, if (!activation()) return 0; - if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { stack; return 0; } @@ -387,7 +388,7 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent) if (!activation()) return 0; - if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { stack; return 0; } @@ -419,7 +420,7 @@ int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent, if (!info.exists) return 0; - if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { stack; return 0; } @@ -462,7 +463,7 @@ static int _lv_activate_lv(struct logical_volume *lv) int r; struct dev_manager *dm; - if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { stack; return 0; } @@ -479,7 +480,7 @@ static int _lv_deactivate(struct logical_volume *lv) int r; struct dev_manager *dm; - if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { stack; return 0; } @@ -496,7 +497,7 @@ static int _lv_suspend_lv(struct logical_volume *lv) int r; struct dev_manager *dm; - if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) { + if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) { stack; return 0; } diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index 7cff1407d..2e61bed18 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -21,7 +21,11 @@ #include "lvm-string.h" #include "fs.h" #include "defaults.h" +#include "segtypes.h" +#include "display.h" #include "toolcontext.h" +#include "targets.h" +#include "config.h" #include #include @@ -65,12 +69,6 @@ enum { REMOVE = 7 }; -enum { - MIRR_DISABLED, - MIRR_RUNNING, - MIRR_COMPLETED -}; - typedef enum { ACTIVATE, DEACTIVATE, @@ -112,14 +110,14 @@ struct dl_list { }; static const char *stripe_filler = NULL; -static uint32_t mirror_region_size = 0; struct dev_manager { struct pool *mem; - struct config_tree *cft; + struct cmd_context *cmd; + const char *stripe_filler; - uint32_t mirror_region_size; + void *target_state; uint32_t pvmove_mirror_count; char *vg_name; @@ -336,7 +334,7 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info, static int _info(const char *name, const char *uuid, int mknodes, struct dm_info *info, struct pool *mem, char **uuid_out) { - if (!mknodes && uuid && *uuid && + if (!mknodes && uuid && *uuid && _info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists) return 1; @@ -427,18 +425,16 @@ static int _percent_run(struct dev_manager *dm, const char *name, uint64_t start, length; char *type = NULL; char *params = NULL; - float percent2; struct list *segh = &lv->segments; struct lv_segment *seg = NULL; + struct segment_type *segtype; - uint64_t numerator, denominator; uint64_t total_numerator = 0, total_denominator = 0; *percent = -1; if (!(dmt = _setup_task(name, uuid, event_nr, - wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS))) - { + wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS))) { stack; return 0; } @@ -471,40 +467,19 @@ static int _percent_run(struct dev_manager *dm, const char *name, if (!type || !params || strcmp(type, target_type)) continue; - /* Mirror? */ - if (!strcmp(type, "mirror")) { - log_debug("Mirror status: %s", params); - if (sscanf(params, "%*d %*x:%*x %*x:%*x %" PRIu64 - "/%" PRIu64, &numerator, - &denominator) != 2) { - log_error("Failure parsing mirror status: %s", - params); - goto out; - } - total_numerator += numerator; - total_denominator += denominator; - - if (seg && (seg->status & PVMOVE)) - seg->extents_moved = dm->mirror_region_size * - numerator / lv->vg->extent_size; + if (!(segtype = get_segtype_from_string(dm->cmd, type))) continue; + + if (segtype->ops->target_percent && + !segtype->ops->target_percent(&dm->target_state, dm->mem, + dm->cmd->cft, seg, params, + &total_numerator, + &total_denominator, + percent)) { + stack; + goto out; } - if (strcmp(type, "snapshot")) - continue; - - /* Snapshot */ - if (index(params, '/')) { - if (sscanf(params, "%" PRIu64 "/%" PRIu64, - &numerator, &denominator) == 2) { - total_numerator += numerator; - total_denominator += denominator; - } - continue; - } else if (sscanf(params, "%f", &percent2) == 1) { - *percent += percent2; - *percent /= 2; - } } while (next); if (lv && (segh = list_next(&lv->segments, segh))) { @@ -515,7 +490,7 @@ static int _percent_run(struct dev_manager *dm, const char *name, if (total_denominator) *percent = (float) total_numerator *100 / total_denominator; - else + else if (*percent < 0) *percent = 100; log_debug("LV percent: %f", *percent); @@ -633,9 +608,9 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task) 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); + 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)) { @@ -759,98 +734,26 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt, size_t paramsize) { uint64_t esize = seg->lv->vg->extent_size; - uint32_t s, start_area = 0u, areas = seg->area_count; - int w = 0, tw = 0; + int w = 0; const char *target = NULL; - const char *trailing_space; - int mirror_status; - struct dev_layer *dl; - char devbuf[10]; + int r; - switch (seg->type) { - case SEG_SNAPSHOT: + if (!seg->segtype->ops->compose_target_line) { log_error("_emit_target: Internal error: Can't handle " - "SEG_SNAPSHOT"); + "segment type %s", seg->segtype->name); return 0; - /* Target formats: - * linear [device offset]+ - * striped #stripes stripe_size [device offset]+ - * mirror log_type #log_params [log_params]* - * #mirrors [device offset]+ - */ - case SEG_STRIPED: - if (areas == 1) - target = "linear"; - else if (areas > 1) { - target = "striped"; - if ((tw = lvm_snprintf(params, paramsize, "%u %u ", - areas, seg->stripe_size)) < 0) - goto error; - w = tw; - } else { - log_error("_emit_target: Internal error: SEG_STRIPED " - "with no stripes"); - return 0; - } - break; - case SEG_MIRRORED: - mirror_status = MIRR_RUNNING; - if (seg->status & PVMOVE) { - if (seg->extents_moved == seg->area_len) { - mirror_status = MIRR_COMPLETED; - start_area = 1; - } else if (dm->pvmove_mirror_count++) { - mirror_status = MIRR_DISABLED; - areas = 1; - } - } - if (mirror_status != MIRR_RUNNING) { - target = "linear"; - break; - } - target = "mirror"; - if ((tw = lvm_snprintf(params, paramsize, "core 1 %u %u ", - dm->mirror_region_size, areas)) < 0) - goto error; - w = tw; - break; } - for (s = start_area; s < areas; s++, w += tw) { - trailing_space = (areas - s - 1) ? " " : ""; - if ((seg->area[s].type == AREA_PV && - (!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) || - (seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv)) - tw = lvm_snprintf(params + w, paramsize - w, - "%s 0%s", dm->stripe_filler, - trailing_space); - else if (seg->area[s].type == AREA_PV) - tw = lvm_snprintf(params + w, paramsize - w, - "%s %" PRIu64 "%s", - dev_name(seg->area[s].u.pv.pv->dev), - (seg->area[s].u.pv.pv->pe_start + - (esize * seg->area[s].u.pv.pe)), - trailing_space); - 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, paramsize - w, - "%s %" PRIu64 "%s", devbuf, - esize * seg->area[s].u.lv.le, - trailing_space); - } - - if (tw < 0) - goto error; + if ((r = seg->segtype->ops->compose_target_line(dm, dm->mem, + dm->cmd->cft, + &dm->target_state, seg, + params, paramsize, + &target, &w, + &dm-> + pvmove_mirror_count)) <= + 0) { + stack; + return r; } log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s", @@ -863,11 +766,62 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt, } return 1; +} - error: - log_debug("Insufficient space in params[%" PRIsize_t "] for target " - "parameters.", paramsize); - return -1; +int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, + char *params, size_t paramsize, int *pos, int start_area, + int areas) +{ + uint32_t s; + int tw = 0; + const char *trailing_space; + uint64_t esize = seg->lv->vg->extent_size; + struct dev_layer *dl; + char devbuf[10]; + + for (s = start_area; s < areas; s++, *pos += tw) { + trailing_space = (areas - s - 1) ? " " : ""; + if ((seg->area[s].type == AREA_PV && + (!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) || + (seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv)) + tw = lvm_snprintf(params + *pos, paramsize - *pos, + "%s 0%s", dm->stripe_filler, + trailing_space); + else if (seg->area[s].type == AREA_PV) + tw = lvm_snprintf(params + *pos, paramsize - *pos, + "%s %" PRIu64 "%s", + dev_name(seg->area[s].u.pv.pv->dev), + (seg->area[s].u.pv.pv->pe_start + + (esize * seg->area[s].u.pv.pe)), + trailing_space); + 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 + *pos, paramsize - *pos, + "%s %" PRIu64 "%s", devbuf, + esize * seg->area[s].u.lv.le, + trailing_space); + } + + if (tw < 0) { + stack; + return -1; + } + } + + return 1; } static int _emit_target(struct dev_manager *dm, struct dm_task *dmt, @@ -892,6 +846,9 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt, if (ret >= 0) return ret; + log_debug("Insufficient space in params[%" PRIsize_t + "] for target parameters.", paramsize); + paramsize *= 2; } while (paramsize < MAX_TARGET_PARAMSIZE); @@ -1023,8 +980,8 @@ static int _populate_snapshot(struct dev_manager *dm, /* * dev_manager implementation. */ -struct dev_manager *dev_manager_create(const char *vg_name, - struct config_tree *cft) +struct dev_manager *dev_manager_create(struct cmd_context *cmd, + const char *vg_name) { struct pool *mem; struct dev_manager *dm; @@ -1039,22 +996,16 @@ struct dev_manager *dev_manager_create(const char *vg_name, goto bad; } + dm->cmd = cmd; dm->mem = mem; - dm->cft = cft; + if (!stripe_filler) { - stripe_filler = find_config_str(cft->root, + stripe_filler = find_config_str(cmd->cft->root, "activation/missing_stripe_filler", DEFAULT_STRIPE_FILLER); } dm->stripe_filler = stripe_filler; - if (!mirror_region_size) { - mirror_region_size = 2 * find_config_int(cft->root, - "activation/mirror_region_size", - DEFAULT_MIRROR_REGION_SIZE); - } - dm->mirror_region_size = mirror_region_size; - if (!(dm->vg_name = pool_strdup(dm->mem, vg_name))) { stack; goto bad; @@ -1070,6 +1021,8 @@ struct dev_manager *dev_manager_create(const char *vg_name, list_init(&dm->remove_list); list_init(&dm->suspend_list); + dm->target_state = NULL; + return dm; bad: @@ -1282,15 +1235,13 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv, /* Add dependencies for any LVs that segments refer to */ list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); - if (seg->type != SEG_STRIPED && seg->type != SEG_MIRRORED) - continue; for (s = 0; s < seg->area_count; s++) { if (seg->area[s].type != AREA_LV) continue; if (!str_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; } @@ -1311,7 +1262,7 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv, _clear_flag(dlr, VISIBLE); _clear_flag(dlr, TOPLEVEL); _set_flag(dlr, REMOVE); - + /* add the dependency on the real device */ if (!str_list_add(dm->mem, &dl->pre_create, pool_strdup(dm->mem, dlr->dlid))) { @@ -1688,7 +1639,6 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl) return 1; } - static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg) { struct list *lvh; @@ -1756,8 +1706,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm) continue; } - if (!str_list_add(dm->mem, &dep->pre_create, - dl->dlid)) { + if (!str_list_add(dm->mem, &dep->pre_create, dl->dlid)) { stack; return 0; } @@ -1773,8 +1722,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm) continue; } - if (!str_list_add(dm->mem, &dep->pre_suspend, - dl->dlid)) { + if (!str_list_add(dm->mem, &dep->pre_suspend, dl->dlid)) { stack; return 0; } diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h index 1482d3348..2290679cd 100644 --- a/lib/activate/dev_manager.h +++ b/lib/activate/dev_manager.h @@ -16,17 +16,16 @@ #ifndef _LVM_DEV_MANAGER_H #define _LVM_DEV_MANAGER_H -#include "metadata.h" -#include "config.h" - +struct logical_volume; +struct cmd_context; struct dev_manager; struct dm_info; /* * Constructor and destructor. */ -struct dev_manager *dev_manager_create(const char *vg_name, - struct config_tree *cf); +struct dev_manager *dev_manager_create(struct cmd_context *cmd, + const char *vg_name); void dev_manager_destroy(struct dev_manager *dm); void dev_manager_exit(void); diff --git a/lib/activate/targets.h b/lib/activate/targets.h new file mode 100644 index 000000000..06f915234 --- /dev/null +++ b/lib/activate/targets.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LVM_TARGETS_H +#define _LVM_TARGETS_H + +struct dev_manager; +struct lv_segment; + +int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos, + int start_area, int areas); + +#endif diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h index cbfb3167d..a461cd321 100644 --- a/lib/cache/lvmcache.h +++ b/lib/cache/lvmcache.h @@ -20,7 +20,6 @@ #include "dev-cache.h" #include "uuid.h" #include "label.h" -#include "metadata.h" #define ORPHAN "" @@ -30,6 +29,10 @@ /* LVM specific per-volume info */ /* Eventual replacement for struct physical_volume perhaps? */ +struct cmd_context; +struct format_type; +struct volume_group; + struct lvmcache_vginfo { struct list list; /* Join these vginfos together */ struct list infos; /* List head for lvmcache_infos */ diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 883230b1e..7955dcaa4 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -33,6 +33,8 @@ #include "display.h" #include "memlock.h" #include "str_list.h" +#include "segtypes.h" +#include "lvmcache.h" #ifdef HAVE_LIBDL #include "sharedlib.h" @@ -662,6 +664,87 @@ static int _init_formats(struct cmd_context *cmd) return 0; } +static int _init_segtypes(struct cmd_context *cmd) +{ + struct segment_type *segtype; + +#ifdef HAVE_LIBDL + const struct config_node *cn; +#endif + + if (!(segtype = init_striped_segtype(cmd))) + return 0; + segtype->library = NULL; + list_add(&cmd->segtypes, &segtype->list); + +#ifdef SNAPSHOT_INTERNAL + if (!(segtype = init_snapshot_segtype(cmd))) + return 0; + segtype->library = NULL; + list_add(&cmd->segtypes, &segtype->list); +#endif + +#ifdef MIRRORED_INTERNAL + if (!(segtype = init_mirrored_segtype(cmd))) + return 0; + segtype->library = NULL; + list_add(&cmd->segtypes, &segtype->list); +#endif + +#ifdef HAVE_LIBDL + /* Load any formats in shared libs */ + if ((cn = find_config_node(cmd->cft->root, "global/segment_libraries"))) { + + struct config_value *cv; + struct segment_type *(*init_segtype_fn) (struct cmd_context *); + void *lib; + struct list *sgtl, *tmp; + struct segment_type *segtype2; + + for (cv = cn->v; cv; cv = cv->next) { + if (cv->type != CFG_STRING) { + log_error("Invalid string in config file: " + "global/segment_libraries"); + return 0; + } + if (!(lib = load_shared_library(cmd->cft, cv->v.str, + "segment type"))) { + stack; + return 0; + } + + if (!(init_segtype_fn = dlsym(lib, "init_segtype"))) { + log_error("Shared library %s does not contain " + "segment type functions", cv->v.str); + dlclose(lib); + return 0; + } + + if (!(segtype = init_segtype_fn(cmd))) + return 0; + segtype->library = lib; + list_add(&cmd->segtypes, &segtype->list); + + list_iterate_safe(sgtl, tmp, &cmd->segtypes) { + segtype2 = list_item(sgtl, struct segment_type); + if (!strcmp(segtype2->name, segtype->name)) { + log_error("Duplicate segment type %s: " + "unloading shared library %s", + segtype->name, cv->v.str); + list_del(&segtype->list); + segtype->ops->destroy(segtype); + dlclose(lib); + break; + } + + } + } + } +#endif + + return 1; +} + static int _init_hostname(struct cmd_context *cmd) { struct utsname uts; @@ -710,6 +793,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args) cmd->args = the_args; cmd->hosttags = 0; list_init(&cmd->formats); + list_init(&cmd->segtypes); list_init(&cmd->tags); list_init(&cmd->config_files); @@ -763,6 +847,9 @@ struct cmd_context *create_toolcontext(struct arg *the_args) if (!_init_formats(cmd)) goto error; + if (!_init_segtypes(cmd)) + goto error; + cmd->current_settings = cmd->default_settings; cmd->config_valid = 1; @@ -791,6 +878,24 @@ static void _destroy_formats(struct list *formats) } } +static void _destroy_segtypes(struct list *segtypes) +{ + struct list *sgtl, *tmp; + struct segment_type *segtype; + void *lib; + + list_iterate_safe(sgtl, tmp, segtypes) { + segtype = list_item(sgtl, struct segment_type); + list_del(&segtype->list); + lib = segtype->library; + segtype->ops->destroy(segtype); +#ifdef HAVE_LIBDL + if (lib) + dlclose(lib); +#endif + } +} + int refresh_toolcontext(struct cmd_context *cmd) { log_verbose("Reloading config files"); @@ -803,6 +908,7 @@ int refresh_toolcontext(struct cmd_context *cmd) activation_exit(); lvmcache_destroy(); label_exit(); + _destroy_segtypes(&cmd->segtypes); _destroy_formats(&cmd->formats); if (cmd->filter) { cmd->filter->destroy(cmd->filter); @@ -842,6 +948,9 @@ int refresh_toolcontext(struct cmd_context *cmd) if (!_init_formats(cmd)) return 0; + if (!_init_segtypes(cmd)) + return 0; + cmd->config_valid = 1; return 1; } @@ -854,6 +963,7 @@ void destroy_toolcontext(struct cmd_context *cmd) activation_exit(); lvmcache_destroy(); label_exit(); + _destroy_segtypes(&cmd->segtypes); _destroy_formats(&cmd->formats); cmd->filter->destroy(cmd->filter); pool_destroy(cmd->mem); diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h index 839716d64..34606f1f9 100644 --- a/lib/commands/toolcontext.h +++ b/lib/commands/toolcontext.h @@ -57,6 +57,7 @@ struct cmd_context { struct format_type *fmt_backup; /* Format to use for backups */ struct list formats; /* Available formats */ + struct list segtypes; /* Available segment types */ const char *hostname; const char *kernel_vsn; diff --git a/lib/display/display.c b/lib/display/display.c index 75315b57f..4a1aa921e 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -18,6 +18,7 @@ #include "display.h" #include "activate.h" #include "toolcontext.h" +#include "segtypes.h" #define SIZE_BUF 128 @@ -31,18 +32,7 @@ static struct { ALLOC_DEFAULT, "next free (default)"} }; -static struct { - segment_type_t segtype; - const char *str; -} _segtypes[] = { - { - SEG_STRIPED, "striped"}, { - SEG_MIRRORED, "mirror"}, { - SEG_SNAPSHOT, "snapshot"} -}; - static int _num_policies = sizeof(_policies) / sizeof(*_policies); -static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes); uint64_t units_to_bytes(const char *units, char *unit_type) { @@ -124,17 +114,6 @@ const char *get_alloc_string(alloc_policy_t alloc) return NULL; } -const char *get_segtype_string(segment_type_t segtype) -{ - int i; - - for (i = 0; i < _num_segtypes; i++) - if (_segtypes[i].segtype == segtype) - return _segtypes[i].str; - - return "unknown"; -} - alloc_policy_t get_alloc_from_string(const char *str) { int i; @@ -147,18 +126,6 @@ alloc_policy_t get_alloc_from_string(const char *str) return ALLOC_DEFAULT; } -segment_type_t get_segtype_from_string(const char *str) -{ - int i; - - for (i = 0; i < _num_segtypes; i++) - if (!strcmp(_segtypes[i].str, str)) - return _segtypes[i].segtype; - - log_error("Unrecognised segment type - using default (striped)"); - return SEG_STRIPED; -} - const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl) { int s; @@ -386,8 +353,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, snap_active = lv_snapshot_percent(snap->cow, &snap_percent); if (!snap_active || snap_percent < 0 || - snap_percent >= 100) - snap_active = 0; + snap_percent >= 100) snap_active = 0; log_print(" %s%s/%s [%s]", lv->vg->cmd->dev_dir, lv->vg->name, snap->cow->name, @@ -478,7 +444,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, return 0; } -static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre) +void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre) { switch (seg->area[s].type) { case AREA_PV: @@ -506,52 +472,18 @@ static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre) int lvdisplay_segments(struct logical_volume *lv) { - uint32_t s; - struct list *segh; struct lv_segment *seg; log_print("--- Segments ---"); - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); - + list_iterate_items(seg, &lv->segments) { log_print("Logical extent %u to %u:", seg->le, seg->le + seg->len - 1); - if (seg->type == SEG_STRIPED && seg->area_count == 1) - log_print(" Type\t\tlinear"); - else - log_print(" Type\t\t%s", - get_segtype_string(seg->type)); + log_print(" Type\t\t%s", seg->segtype->ops->name(seg)); - switch (seg->type) { - case SEG_STRIPED: - if (seg->area_count == 1) - _display_stripe(seg, 0, " "); - else { - log_print(" Stripes\t\t%u", seg->area_count); - log_print(" Stripe size\t\t%u KB", - seg->stripe_size / 2); - - for (s = 0; s < seg->area_count; s++) { - log_print(" Stripe %d:", s); - _display_stripe(seg, s, " "); - } - } - log_print(" "); - break; - case SEG_SNAPSHOT: - break; - case SEG_MIRRORED: - log_print(" Mirrors\t\t%u", seg->area_count); - log_print(" Mirror size\t\t%u", seg->area_len); - log_print(" Mirror original:"); - _display_stripe(seg, 0, " "); - log_print(" Mirror destination:"); - _display_stripe(seg, 1, " "); - log_print(" "); - break; - } + if (seg->segtype->ops->display) + seg->segtype->ops->display(seg); } log_print(" "); @@ -626,14 +558,12 @@ void vgdisplay_full(struct volume_group *vg) log_print("Alloc PE / Size %u / %s", vg->extent_count - vg->free_count, display_size(vg->cmd, ((uint64_t) - vg-> - extent_count + vg->extent_count - - vg-> - free_count) * - (vg-> - extent_size / - 2), + vg->free_count) + * + (vg->extent_size + / 2), SIZE_SHORT)); log_print("Free PE / Size %u / %s", vg->free_count, @@ -714,8 +644,8 @@ void vgdisplay_short(struct volume_group *vg) ((uint64_t) vg->extent_count - vg->free_count) * vg->extent_size / 2, SIZE_SHORT), display_size(vg->cmd, - (uint64_t) vg-> - free_count * + (uint64_t) + vg->free_count * vg->extent_size / 2, SIZE_SHORT)); return; diff --git a/lib/display/display.h b/lib/display/display.h index 1292fd75f..0fc3486ff 100644 --- a/lib/display/display.h +++ b/lib/display/display.h @@ -27,6 +27,7 @@ uint64_t units_to_bytes(const char *units, char *unit_type); /* Specify size in KB */ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl); char *display_uuid(char *uuidstr); +void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre); void pvdisplay_colons(struct physical_volume *pv); void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv, @@ -50,10 +51,4 @@ void vgdisplay_short(struct volume_group *vg); const char *get_alloc_string(alloc_policy_t alloc); alloc_policy_t get_alloc_from_string(const char *str); -/* - * Segment type display conversion routines. - */ -segment_type_t get_segtype_from_string(const char *str); -const char *get_segtype_string(segment_type_t segtype); - #endif diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c index aa0d964cc..bb96e8918 100644 --- a/lib/format1/disk-rep.c +++ b/lib/format1/disk-rep.c @@ -153,6 +153,10 @@ static int _munge_formats(struct pv_disk *pvd) memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN); } + /* If UUID is missing, create one */ + if (pvd->pv_uuid[0] == '\0') + uuid_from_num(pvd->pv_uuid, pvd->pv_number); + return 1; } @@ -193,10 +197,6 @@ int munge_pvd(struct device *dev, struct pv_disk *pvd) return 0; } - /* If UUID is missing, create one */ - if (pvd->pv_uuid[0] == '\0') - uuid_from_num(pvd->pv_uuid, pvd->pv_number); - /* If VG is exported, set VG name back to the real name */ _munge_exported_vg(pvd); diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h index b6b03229e..9f8167f06 100644 --- a/lib/format1/disk-rep.h +++ b/lib/format1/disk-rep.h @@ -216,7 +216,7 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg); int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd); -int import_extents(struct pool *mem, struct volume_group *vg, +int import_extents(struct cmd_context *cmd, struct volume_group *vg, struct list *pvds); int export_extents(struct disk_list *dl, uint32_t lv_num, struct logical_volume *lv, struct physical_volume *pv); diff --git a/lib/format1/format1.c b/lib/format1/format1.c index 20c965c56..39e28dc3c 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -164,7 +164,7 @@ static struct volume_group *_build_vg(struct format_instance *fid, if (!import_lvs(mem, vg, pvs)) goto bad; - if (!import_extents(mem, vg, pvs)) + if (!import_extents(fid->fmt->cmd, vg, pvs)) goto bad; if (!import_snapshots(mem, vg, pvs)) diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 33305fc4f..297056a5f 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -25,6 +25,7 @@ #include "lvm-string.h" #include "filter.h" #include "toolcontext.h" +#include "segtypes.h" #include @@ -380,9 +381,10 @@ int export_extents(struct disk_list *dl, uint32_t lv_num, seg = list_item(segh, struct lv_segment); for (s = 0; s < seg->area_count; s++) { - if (seg->type != SEG_STRIPED) { - log_error("Non-striped segment type in LV %s: " - "unsupported by format1", lv->name); + if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) { + log_error("Segment type %s in LV %s: " + "unsupported by format1", + seg->segtype->name, lv->name); return 0; } if (seg->area[s].type != AREA_PV) { diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c index 82828a1b6..851e7c251 100644 --- a/lib/format1/import-extents.c +++ b/lib/format1/import-extents.c @@ -19,6 +19,8 @@ #include "pool.h" #include "disk-rep.h" #include "lv_alloc.h" +#include "display.h" +#include "segtypes.h" /* * After much thought I have decided it is easier, @@ -201,16 +203,20 @@ static int _check_maps_are_complete(struct hash_table *maps) return 1; } -static int _read_linear(struct pool *mem, struct lv_map *lvm) +static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm) { uint32_t le = 0; struct lv_segment *seg; while (le < lvm->lv->le_count) { - seg = alloc_lv_segment(mem, 1); + seg = alloc_lv_segment(cmd->mem, 1); seg->lv = lvm->lv; - seg->type = SEG_STRIPED; + if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) { + stack; + return 0; + } + seg->le = le; seg->len = 0; seg->area_len = 0; @@ -251,13 +257,12 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg, if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) || (seg->area[st].u.pv.pv && lvm->map[le + st * len].pe != - seg->area[st].u.pv.pe + seg->len)) - return 0; + seg->area[st].u.pv.pe + seg->len)) return 0; return 1; } -static int _read_stripes(struct pool *mem, struct lv_map *lvm) +static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm) { uint32_t st, le = 0, len; struct lv_segment *seg; @@ -273,13 +278,16 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm) len = lvm->lv->le_count / lvm->stripes; while (le < len) { - if (!(seg = alloc_lv_segment(mem, lvm->stripes))) { + if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) { stack; return 0; } seg->lv = lvm->lv; - seg->type = SEG_STRIPED; + if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) { + stack; + return 0; + } seg->stripe_size = lvm->stripe_size; seg->area_count = lvm->stripes; seg->le = seg->area_count * le; @@ -312,20 +320,20 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm) return 1; } -static int _build_segments(struct pool *mem, struct lv_map *lvm) +static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm) { - return (lvm->stripes > 1 ? _read_stripes(mem, lvm) : - _read_linear(mem, lvm)); + return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) : + _read_linear(cmd, lvm)); } -static int _build_all_segments(struct pool *mem, struct hash_table *maps) +static int _build_all_segments(struct cmd_context *cmd, struct hash_table *maps) { struct hash_node *n; struct lv_map *lvm; for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) { lvm = (struct lv_map *) hash_get_data(maps, n); - if (!_build_segments(mem, lvm)) { + if (!_build_segments(cmd, lvm)) { stack; return 0; } @@ -334,7 +342,8 @@ static int _build_all_segments(struct pool *mem, struct hash_table *maps) return 1; } -int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds) +int import_extents(struct cmd_context *cmd, struct volume_group *vg, + struct list *pvds) { int r = 0; struct pool *scratch = pool_create(10 * 1024); @@ -360,7 +369,7 @@ int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds) goto out; } - if (!_build_all_segments(mem, maps)) { + if (!_build_all_segments(cmd, maps)) { log_err("Couldn't build extent segments."); goto out; } diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c index cdbafb703..724ffff67 100644 --- a/lib/format_text/archive.c +++ b/lib/format_text/archive.c @@ -380,4 +380,3 @@ int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname) return 1; } - diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 69b960e82..7ae3072c9 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -20,6 +20,8 @@ #include "pool.h" #include "display.h" #include "lvm-string.h" +#include "segtypes.h" +#include "text_export.h" #include #include @@ -74,14 +76,6 @@ static void _init(void) /* * Formatting functions. */ -static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); - -static int _out_hint(struct formatter *f, const char *fmt, ...) - __attribute__ ((format(printf, 2, 3))); - -static int _out(struct formatter *f, const char *fmt, ...) - __attribute__ ((format(printf, 2, 3))); #define MAX_INDENT 5 static void _inc_indent(struct formatter *f) @@ -206,7 +200,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s) * Appends a comment giving a size in more easily * readable form (eg, 4M instead of 8096). */ -static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...) +int out_size(struct formatter *f, uint64_t size, const char *fmt, ...) { char buffer[64]; va_list ap; @@ -226,7 +220,7 @@ static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...) * Appends a comment indicating that the line is * only a hint. */ -static int _out_hint(struct formatter *f, const char *fmt, ...) +int out_hint(struct formatter *f, const char *fmt, ...) { va_list ap; int r; @@ -241,7 +235,7 @@ static int _out_hint(struct formatter *f, const char *fmt, ...) /* * The normal output function. */ -static int _out(struct formatter *f, const char *fmt, ...) +int out_text(struct formatter *f, const char *fmt, ...) { va_list ap; int r; @@ -253,8 +247,6 @@ static int _out(struct formatter *f, const char *fmt, ...) return r; } -#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0) - static int _print_header(struct formatter *f, struct volume_group *vg, const char *desc) { @@ -262,17 +254,17 @@ static int _print_header(struct formatter *f, t = time(NULL); - _outf(f, "# Generated by LVM2: %s", ctime(&t)); - _outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\""); - _outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE); + outf(f, "# Generated by LVM2: %s", ctime(&t)); + outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\""); + outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE); f->nl(f); - _outf(f, "description = \"%s\"", desc); + outf(f, "description = \"%s\"", desc); f->nl(f); - _outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename, - _utsname.sysname, _utsname.nodename, _utsname.release, - _utsname.version, _utsname.machine); - _outf(f, "creation_time = %lu\t# %s", t, ctime(&t)); + outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename, + _utsname.sysname, _utsname.nodename, _utsname.release, + _utsname.version, _utsname.machine); + outf(f, "creation_time = %lu\t# %s", t, ctime(&t)); return 1; } @@ -286,34 +278,34 @@ static int _print_vg(struct formatter *f, struct volume_group *vg) return 0; } - _outf(f, "id = \"%s\"", buffer); + outf(f, "id = \"%s\"", buffer); - _outf(f, "seqno = %u", vg->seqno); + outf(f, "seqno = %u", vg->seqno); if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "status = %s", buffer); + outf(f, "status = %s", buffer); if (!list_empty(&vg->tags)) { if (!print_tags(&vg->tags, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "tags = %s", buffer); + outf(f, "tags = %s", buffer); } if (vg->system_id && *vg->system_id) - _outf(f, "system_id = \"%s\"", vg->system_id); + outf(f, "system_id = \"%s\"", vg->system_id); - if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u", - vg->extent_size)) { + if (!out_size(f, (uint64_t) vg->extent_size, "extent_size = %u", + vg->extent_size)) { stack; return 0; } - _outf(f, "max_lv = %u", vg->max_lv); - _outf(f, "max_pv = %u", vg->max_pv); + outf(f, "max_lv = %u", vg->max_lv); + outf(f, "max_pv = %u", vg->max_pv); return 1; } @@ -336,7 +328,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) char buffer[4096]; const char *name; - _outf(f, "physical_volumes {"); + outf(f, "physical_volumes {"); _inc_indent(f); list_iterate(pvh, &vg->pvs) { @@ -348,7 +340,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) } f->nl(f); - _outf(f, "%s {", name); + outf(f, "%s {", name); _inc_indent(f); if (!id_write_format(&pv->id, buffer, sizeof(buffer))) { @@ -356,8 +348,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) return 0; } - _outf(f, "id = \"%s\"", buffer); - if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) { + outf(f, "id = \"%s\"", buffer); + if (!out_hint(f, "device = \"%s\"", dev_name(pv->dev))) { stack; return 0; } @@ -367,119 +359,105 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) stack; return 0; } - _outf(f, "status = %s", buffer); + outf(f, "status = %s", buffer); if (!list_empty(&pv->tags)) { if (!print_tags(&pv->tags, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "tags = %s", buffer); + outf(f, "tags = %s", buffer); } - _outf(f, "pe_start = %" PRIu64, pv->pe_start); - if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count, - "pe_count = %u", pv->pe_count)) { + outf(f, "pe_start = %" PRIu64, pv->pe_start); + if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count, + "pe_count = %u", pv->pe_count)) { stack; return 0; } _dec_indent(f); - _outf(f, "}"); + outf(f, "}"); } _dec_indent(f); - _outf(f, "}"); + outf(f, "}"); return 1; } static int _print_segment(struct formatter *f, struct volume_group *vg, int count, struct lv_segment *seg) { - unsigned int s; - const char *name; - const char *type; char buffer[4096]; - _outf(f, "segment%u {", count); + outf(f, "segment%u {", count); _inc_indent(f); - _outf(f, "start_extent = %u", seg->le); - if (!_out_size(f, (uint64_t) seg->len * vg->extent_size, - "extent_count = %u", seg->len)) { + outf(f, "start_extent = %u", seg->le); + if (!out_size(f, (uint64_t) seg->len * vg->extent_size, + "extent_count = %u", seg->len)) { stack; return 0; } f->nl(f); - _outf(f, "type = \"%s\"", get_segtype_string(seg->type)); + outf(f, "type = \"%s\"", seg->segtype->name); if (!list_empty(&seg->tags)) { if (!print_tags(&seg->tags, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "tags = %s", buffer); + outf(f, "tags = %s", buffer); } - switch (seg->type) { - case SEG_SNAPSHOT: - _outf(f, "chunk_size = %u", seg->chunk_size); - _outf(f, "origin = \"%s\"", seg->origin->name); - _outf(f, "cow_store = \"%s\"", seg->cow->name); - break; - - case SEG_MIRRORED: - case SEG_STRIPED: - type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe"; - _outf(f, "%s_count = %u%s", type, seg->area_count, - (seg->area_count == 1) ? "\t# linear" : ""); - - if ((seg->type == SEG_MIRRORED) && (seg->status & PVMOVE)) - _out_size(f, (uint64_t) seg->extents_moved, - "extents_moved = %u", seg->extents_moved); - - if ((seg->type == SEG_STRIPED) && (seg->area_count > 1)) - _out_size(f, (uint64_t) seg->stripe_size, - "stripe_size = %u", seg->stripe_size); - - f->nl(f); - - _outf(f, "%ss = [", type); - _inc_indent(f); - - for (s = 0; s < seg->area_count; s++) { - switch (seg->area[s].type) { - case AREA_PV: - if (!(name = _get_pv_name(f, seg-> - area[s].u.pv.pv))) { - stack; - return 0; - } - - _outf(f, "\"%s\", %u%s", name, - seg->area[s].u.pv.pe, - (s == seg->area_count - 1) ? "" : ","); - break; - case AREA_LV: - _outf(f, "\"%s\", %u%s", - seg->area[s].u.lv.lv->name, - seg->area[s].u.lv.le, - (s == seg->area_count - 1) ? "" : ","); - } - } - - _dec_indent(f); - _outf(f, "]"); - break; + if (!seg->segtype->ops->text_export(seg, f)) { + stack; + return 0; } _dec_indent(f); - _outf(f, "}"); + outf(f, "}"); return 1; } +int out_areas(struct formatter *f, const struct lv_segment *seg, + const char *type) +{ + const char *name; + unsigned int s; + + f->nl(f); + + outf(f, "%ss = [", type); + _inc_indent(f); + + for (s = 0; s < seg->area_count; s++) { + switch (seg->area[s].type) { + case AREA_PV: + if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) { + stack; + return 0; + } + + outf(f, "\"%s\", %u%s", name, + seg->area[s].u.pv.pe, + (s == seg->area_count - 1) ? "" : ","); + break; + case AREA_LV: + outf(f, "\"%s\", %u%s", + seg->area[s].u.lv.lv->name, + seg->area[s].u.lv.le, + (s == seg->area_count - 1) ? "" : ","); + } + } + + _dec_indent(f); + outf(f, "]"); + return 1; +} + static int _count_segments(struct logical_volume *lv) { int r = 0; @@ -499,7 +477,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap, f->nl(f); - _outf(f, "snapshot%u {", count); + outf(f, "snapshot%u {", count); _inc_indent(f); if (!id_write_format(&snap->id, buffer, sizeof(buffer))) { @@ -507,25 +485,39 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap, return 0; } - _outf(f, "id = \"%s\"", buffer); - if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS, - buffer, sizeof(buffer))) { + outf(f, "id = \"%s\"", buffer); + + seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV; + if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "status = %s", buffer); - _outf(f, "segment_count = 1"); + outf(f, "status = %s", buffer); + outf(f, "segment_count = 1"); f->nl(f); - seg.type = SEG_SNAPSHOT; + if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd, + "snapshot"))) { + stack; + return 0; + } + seg.le = 0; seg.len = snap->origin->le_count; seg.origin = snap->origin; seg.cow = snap->cow; seg.chunk_size = snap->chunk_size; + /* FIXME Dummy values */ + list_init(&seg.list); + seg.lv = snap->cow; + seg.stripe_size = 0; + seg.area_count = 0; + seg.area_len = 0; + seg.extents_moved = 0; + /* Can't tag a snapshot independently of its origin */ list_init(&seg.tags); @@ -535,7 +527,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap, } _dec_indent(f); - _outf(f, "}"); + outf(f, "}"); return 1; } @@ -572,14 +564,14 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) if (list_empty(&vg->lvs)) return 1; - _outf(f, "logical_volumes {"); + outf(f, "logical_volumes {"); _inc_indent(f); list_iterate(lvh, &vg->lvs) { lv = list_item(lvh, struct lv_list)->lv; f->nl(f); - _outf(f, "%s {", lv->name); + outf(f, "%s {", lv->name); _inc_indent(f); /* FIXME: Write full lvid */ @@ -588,32 +580,32 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) return 0; } - _outf(f, "id = \"%s\"", buffer); + outf(f, "id = \"%s\"", buffer); if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "status = %s", buffer); + outf(f, "status = %s", buffer); if (!list_empty(&lv->tags)) { if (!print_tags(&lv->tags, buffer, sizeof(buffer))) { stack; return 0; } - _outf(f, "tags = %s", buffer); + outf(f, "tags = %s", buffer); } if (lv->alloc != ALLOC_DEFAULT) - _outf(f, "allocation_policy = \"%s\"", - get_alloc_string(lv->alloc)); + outf(f, "allocation_policy = \"%s\"", + get_alloc_string(lv->alloc)); if (lv->read_ahead) - _outf(f, "read_ahead = %u", lv->read_ahead); + outf(f, "read_ahead = %u", lv->read_ahead); if (lv->major >= 0) - _outf(f, "major = %d", lv->major); + outf(f, "major = %d", lv->major); if (lv->minor >= 0) - _outf(f, "minor = %d", lv->minor); - _outf(f, "segment_count = %u", _count_segments(lv)); + outf(f, "minor = %d", lv->minor); + outf(f, "segment_count = %u", _count_segments(lv)); f->nl(f); seg_count = 1; @@ -625,7 +617,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) } _dec_indent(f); - _outf(f, "}"); + outf(f, "}"); } if (!_print_snapshots(f, vg)) { @@ -634,7 +626,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) } _dec_indent(f); - _outf(f, "}"); + outf(f, "}"); return 1; } @@ -707,7 +699,7 @@ static int _text_vg_export(struct formatter *f, if (f->header && !_print_header(f, vg, desc)) fail; - if (!_out(f, "%s {", vg->name)) + if (!out_text(f, "%s {", vg->name)) fail; _inc_indent(f); @@ -724,7 +716,7 @@ static int _text_vg_export(struct formatter *f, fail; _dec_indent(f); - if (!_out(f, "}")) + if (!out_text(f, "}")) fail; if (!f->header && !_print_header(f, vg, desc)) @@ -804,4 +796,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf, return r; } -#undef _outf +#undef outf diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c index f9d16acf0..1a9bbb394 100644 --- a/lib/format_text/flags.c +++ b/lib/format_text/flags.c @@ -52,6 +52,7 @@ static struct flag _lv_flags[] = { {VISIBLE_LV, "VISIBLE"}, {PVMOVE, "PVMOVE"}, {LOCKED, "LOCKED"}, + {MIRRORED, NULL}, {0, NULL} }; @@ -99,7 +100,8 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size) } else first = 0; - if (!emit_to_buffer(&buffer, &size, "\"%s\"", + if (flags[f].description && + !emit_to_buffer(&buffer, &size, "\"%s\"", flags[f].description)) return 0; diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index 2995d6ab5..80afc0429 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -30,6 +30,7 @@ #include "xlate.h" #include "label.h" #include "memlock.h" +#include "lvmcache.h" #include #include @@ -928,8 +929,7 @@ static int _mda_setup(const struct format_type *fmt, /* FIXME If creating new mdas, wipe them! */ if (mda_size1) { if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1, - mda_size1)) - return 0; + mda_size1)) return 0; if (!dev_zero((struct device *) pv->dev, start1, (size_t) (mda_size1 > @@ -976,8 +976,7 @@ 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; + mda_size2)) return 0; if (!dev_zero(pv->dev, start2, (size_t) (mda_size1 > wipe_size ? wipe_size : mda_size1))) { @@ -1066,8 +1065,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, } } if (!add_da - (fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT, - UINT64_C(0))) { + (fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0))) { stack; return 0; } @@ -1139,8 +1137,7 @@ static int _add_raw(struct list *raw_list, struct device_area *dev_area) rl = list_item(rlh, struct raw_list); /* FIXME Check size/overlap consistency too */ if (rl->dev_area.dev == dev_area->dev && - rl->dev_area.start == dev_area->start) - return 1; + rl->dev_area.start == dev_area->start) return 1; } if (!(rl = dbg_malloc(sizeof(struct raw_list)))) { @@ -1334,11 +1331,10 @@ static int _pv_setup(const struct format_type *fmt, list_item(mdash, struct metadata_area); if (mda2->ops != - &_metadata_text_raw_ops) - continue; + &_metadata_text_raw_ops) continue; mdac2 = - (struct mda_context *) mda2-> - metadata_locn; + (struct mda_context *) + mda2->metadata_locn; if (!memcmp (&mdac2->area, &mdac->area, sizeof(mdac->area))) { @@ -1356,8 +1352,7 @@ static int _pv_setup(const struct format_type *fmt, } if (!(mdac_new = pool_alloc(fmt->cmd->mem, - sizeof(*mdac_new)))) - { + sizeof(*mdac_new)))) { stack; return 0; } @@ -1486,8 +1481,7 @@ static struct format_instance *_create_text_instance(const struct format_type } if (!(mdac_new = pool_alloc(fmt->cmd->mem, - sizeof(*mdac_new)))) - { + sizeof(*mdac_new)))) { stack; return NULL; } diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index 08eda5239..07f84a86c 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -22,6 +22,8 @@ #include "toolcontext.h" #include "lvmcache.h" #include "lv_alloc.h" +#include "segtypes.h" +#include "text_import.h" typedef int (*section_fn) (struct format_instance * fid, struct pool * mem, struct volume_group * vg, struct config_node * pvn, @@ -234,17 +236,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, struct logical_volume *lv, struct config_node *sn, struct hash_table *pv_hash) { - unsigned int s; - uint32_t area_count = 0; + uint32_t area_count = 0u; struct lv_segment *seg; struct config_node *cn; struct config_value *cv; - const char *seg_name = sn->key; uint32_t start_extent, extent_count; - uint32_t chunk_size, extents_moved = 0u, seg_status = 0u; - const char *org_name, *cow_name; - struct logical_volume *org, *cow, *lv1; - segment_type_t segtype; + struct segment_type *segtype; + const char *segtype_str; if (!(sn = sn->child)) { log_error("Empty segment section."); @@ -263,40 +261,26 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, return 0; } - segtype = SEG_STRIPED; /* Default */ + segtype_str = "striped"; + if ((cn = find_config_node(sn, "type"))) { cv = cn->v; if (!cv || !cv->v.str) { log_error("Segment type must be a string."); return 0; } - segtype = get_segtype_from_string(cv->v.str); + segtype_str = cv->v.str; } - if (segtype == SEG_STRIPED) { - if (!_read_int32(sn, "stripe_count", &area_count)) { - log_error("Couldn't read 'stripe_count' for " - "segment '%s'.", sn->key); - return 0; - } + if (!(segtype = get_segtype_from_string(vg->cmd, segtype_str))) { + stack; + return 0; } - if (segtype == SEG_MIRRORED) { - if (!_read_int32(sn, "mirror_count", &area_count)) { - log_error("Couldn't read 'mirror_count' for " - "segment '%s'.", sn->key); - return 0; - } - - if (find_config_node(sn, "extents_moved")) { - if (_read_uint32(sn, "extents_moved", &extents_moved)) - seg_status |= PVMOVE; - else { - log_error("Couldn't read 'extents_moved' for " - "segment '%s'.", sn->key); - return 0; - } - } + if (segtype->ops->text_import_area_count && + !segtype->ops->text_import_area_count(sn, &area_count)) { + stack; + return 0; } if (!(seg = alloc_lv_segment(mem, area_count))) { @@ -308,9 +292,16 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, seg->le = start_extent; seg->len = extent_count; seg->area_len = extent_count; - seg->type = segtype; - seg->status = seg_status; - seg->extents_moved = extents_moved; + seg->status = 0u; + seg->segtype = segtype; + seg->extents_moved = 0u; + seg->area_count = area_count; + + if (seg->segtype->ops->text_import && + !seg->segtype->ops->text_import(seg, sn, pv_hash)) { + stack; + return 0; + } /* Optional tags */ if ((cn = find_config_node(sn, "tags")) && @@ -320,145 +311,86 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, return 0; } - switch (segtype) { - case SEG_SNAPSHOT: - lv->status |= SNAPSHOT; - - if (!_read_uint32(sn, "chunk_size", &chunk_size)) { - log_error("Couldn't read chunk size for snapshot."); - return 0; - } - - log_suppress(1); - - if (!(cow_name = find_config_str(sn, "cow_store", NULL))) { - log_suppress(0); - log_error("Snapshot cow storage not specified."); - return 0; - } - - if (!(org_name = find_config_str(sn, "origin", NULL))) { - log_suppress(0); - log_error("Snapshot origin not specified."); - return 0; - } - - log_suppress(0); - - if (!(cow = find_lv(vg, cow_name))) { - log_error("Unknown logical volume specified for " - "snapshot cow store."); - return 0; - } - - if (!(org = find_lv(vg, org_name))) { - log_error("Unknown logical volume specified for " - "snapshot origin."); - return 0; - } - - if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) { - stack; - return 0; - } - break; - - case SEG_STRIPED: - if ((area_count != 1) && - !_read_int32(sn, "stripe_size", &seg->stripe_size)) { - log_error("Couldn't read stripe_size for segment '%s'.", - sn->key); - return 0; - } - - if (!(cn = find_config_node(sn, "stripes"))) { - log_error("Couldn't find stripes array for segment " - "'%s'.", sn->key); - return 0; - } - - seg->area_len /= area_count; - - case SEG_MIRRORED: - seg->area_count = area_count; - - if (!seg->area_count) { - log_error("Zero areas not allowed for segment '%s'", - sn->key); - return 0; - } - - if ((seg->type == SEG_MIRRORED) && - !(cn = find_config_node(sn, "mirrors"))) { - log_error("Couldn't find mirrors array for segment " - "'%s'.", sn->key); - return 0; - } - - for (cv = cn->v, s = 0; cv && s < seg->area_count; - s++, cv = cv->next) { - - /* first we read the pv */ - const char *bad = "Badly formed areas array for " - "segment '%s'."; - struct physical_volume *pv; - - if (cv->type != CFG_STRING) { - log_error(bad, sn->key); - return 0; - } - - if (!cv->next) { - log_error(bad, sn->key); - return 0; - } - - if (cv->next->type != CFG_INT) { - log_error(bad, sn->key); - return 0; - } - - /* FIXME Cope if LV not yet read in */ - if ((pv = hash_lookup(pv_hash, cv->v.str))) { - seg->area[s].type = AREA_PV; - seg->area[s].u.pv.pv = pv; - seg->area[s].u.pv.pe = cv->next->v.i; - /* - * Adjust extent counts in the pv and vg. - */ - pv->pe_alloc_count += seg->area_len; - vg->free_count -= seg->area_len; - - } else if ((lv1 = find_lv(vg, cv->v.str))) { - seg->area[s].type = AREA_LV; - seg->area[s].u.lv.lv = lv1; - seg->area[s].u.lv.le = cv->next->v.i; - } else { - log_error("Couldn't find volume '%s' " - "for segment '%s'.", - cv->v.str ? cv->v.str : "NULL", - seg_name); - return 0; - } - - cv = cv->next; - } - - /* - * Check we read the correct number of stripes. - */ - if (cv || (s < seg->area_count)) { - log_error("Incorrect number of areas in area array " - "for segment '%s'.", seg_name); - return 0; - } - - } - /* * Insert into correct part of segment list. */ _insert_segment(lv, seg); + + if (seg->segtype->flags & SEG_AREAS_MIRRORED) + lv->status |= MIRRORED; + + return 1; +} + +int text_import_areas(struct lv_segment *seg, const struct config_node *sn, + const struct config_node *cn, struct hash_table *pv_hash) +{ + unsigned int s; + struct config_value *cv; + struct logical_volume *lv1; + const char *seg_name = sn->key; + + if (!seg->area_count) { + log_error("Zero areas not allowed for segment '%s'", sn->key); + return 0; + } + + for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) { + + /* first we read the pv */ + const char *bad = "Badly formed areas array for " + "segment '%s'."; + struct physical_volume *pv; + + if (cv->type != CFG_STRING) { + log_error(bad, sn->key); + return 0; + } + + if (!cv->next) { + log_error(bad, sn->key); + return 0; + } + + if (cv->next->type != CFG_INT) { + log_error(bad, sn->key); + return 0; + } + + /* FIXME Cope if LV not yet read in */ + if ((pv = hash_lookup(pv_hash, cv->v.str))) { + seg->area[s].type = AREA_PV; + seg->area[s].u.pv.pv = pv; + seg->area[s].u.pv.pe = cv->next->v.i; + /* + * Adjust extent counts in the pv and vg. + */ + pv->pe_alloc_count += seg->area_len; + seg->lv->vg->free_count -= seg->area_len; + + } else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) { + seg->area[s].type = AREA_LV; + seg->area[s].u.lv.lv = lv1; + seg->area[s].u.lv.le = cv->next->v.i; + } else { + log_error("Couldn't find volume '%s' " + "for segment '%s'.", + cv->v.str ? cv->v.str : "NULL", seg_name); + return 0; + } + + cv = cv->next; + } + + /* + * Check we read the correct number of stripes. + */ + if (cv || (s < seg->area_count)) { + log_error("Incorrect number of areas in area array " + "for segment '%s'.", seg_name); + return 0; + } + return 1; } diff --git a/lib/format_text/text_export.h b/lib/format_text/text_export.h new file mode 100644 index 000000000..fdc42c1c0 --- /dev/null +++ b/lib/format_text/text_export.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LVM_TEXT_EXPORT_H +#define _LVM_TEXT_EXPORT_H + +#define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0) + +struct formatter; +struct lv_segment; + +int out_size(struct formatter *f, uint64_t size, const char *fmt, ...) + __attribute__ ((format(printf, 3, 4))); + +int out_hint(struct formatter *f, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); + +int out_text(struct formatter *f, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); + +int out_areas(struct formatter *f, const struct lv_segment *seg, + const char *type); + +#endif diff --git a/lib/format_text/text_import.h b/lib/format_text/text_import.h new file mode 100644 index 000000000..c6b8c717d --- /dev/null +++ b/lib/format_text/text_import.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LVM_TEXT_IMPORT_H +#define _LVM_TEXT_IMPORT_H + +struct lv_segment; +struct config_node; + +int text_import_areas(struct lv_segment *seg, const struct config_node *sn, + const struct config_node *cn, struct hash_table *pv_hash); + +#endif diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c index 321d41ad3..3cecf4bdb 100644 --- a/lib/format_text/text_label.c +++ b/lib/format_text/text_label.c @@ -18,6 +18,7 @@ #include "layout.h" #include "label.h" #include "xlate.h" +#include "lvmcache.h" #include #include diff --git a/lib/label/label.c b/lib/label/label.c index 815d62dda..030c103e0 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -19,6 +19,7 @@ #include "crc.h" #include "xlate.h" #include "lvmcache.h" +#include "metadata.h" #include #include @@ -78,6 +79,8 @@ void label_exit(void) li->l->ops->destroy(li->l); _free_li(li); } + + list_init(&_labellers); } int label_register_handler(const char *name, struct labeller *handler) diff --git a/lib/label/label.h b/lib/label/label.h index 4933db5e4..99f1164db 100644 --- a/lib/label/label.h +++ b/lib/label/label.h @@ -16,7 +16,6 @@ #ifndef _LVM_LABEL_H #define _LVM_LABEL_H -#include "lvmcache.h" #include "uuid.h" #include "device.h" @@ -25,6 +24,8 @@ #define LABEL_SCAN_SECTORS 4L #define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT) +struct labeller; + /* On disk - 32 bytes */ struct label_header { uint8_t id[8]; /* LABELONE */ diff --git a/lib/locking/locking.h b/lib/locking/locking.h index 70ce0e8bb..69f0664d1 100644 --- a/lib/locking/locking.h +++ b/lib/locking/locking.h @@ -13,7 +13,6 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "metadata.h" #include "uuid.h" #include "config.h" diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index e9982f505..197aa8bb8 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -20,6 +20,8 @@ #include "lvm-string.h" #include "toolcontext.h" #include "lv_alloc.h" +#include "display.h" +#include "segtypes.h" /* * These functions adjust the pe counts in pv's @@ -76,6 +78,7 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas) static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count, uint32_t stripe_size, + struct segment_type *segtype, struct pv_area **areas, uint32_t *ix) { uint32_t count, area_len, smallest; @@ -83,7 +86,9 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count, struct lv_segment *seg; int striped = 0; - striped = 1; + /* Striped or mirrored? */ + if (segtype->flags & SEG_AREAS_STRIPED) + striped = 1; count = lv->le_count - *ix; area_len = count / (striped ? area_count : 1); @@ -98,7 +103,7 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count, } seg->lv = lv; - seg->type = SEG_STRIPED; + seg->segtype = segtype; seg->le = *ix; seg->len = area_len * (striped ? area_count : 1); seg->area_len = area_len; @@ -116,6 +121,10 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count, list_add(&lv->segments, &seg->list); *ix += seg->len; + + if (!striped) + lv->status |= MIRRORED; + return 1; } @@ -135,7 +144,8 @@ static int _comp_area(const void *l, const void *r) static int _alloc_parallel(struct logical_volume *lv, struct list *pvms, uint32_t allocated, - uint32_t stripes, uint32_t stripe_size) + uint32_t stripes, uint32_t stripe_size, + uint32_t mirrors, struct segment_type *segtype) { int r = 0; struct list *pvmh; @@ -145,7 +155,15 @@ static int _alloc_parallel(struct logical_volume *lv, size_t len; uint32_t area_count; - area_count = stripes; + if (stripes > 1 && mirrors > 1) { + log_error("striped mirrors are not supported yet"); + return 0; + } + + if (stripes > 1) + area_count = stripes; + else + area_count = mirrors; list_iterate(pvmh, pvms) pv_count++; @@ -179,8 +197,8 @@ static int _alloc_parallel(struct logical_volume *lv, /* sort the areas so we allocate from the biggest */ qsort(areas, ix, sizeof(*areas), _comp_area); - if (!_alloc_parallel_area(lv, area_count, stripe_size, areas, - &allocated)) { + if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype, + areas, &allocated)) { stack; goto out; } @@ -215,7 +233,11 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix, } seg->lv = lv; - seg->type = SEG_STRIPED; + if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) { + stack; + return 0; + } + seg->le = *ix; seg->le = *ix; seg->len = count; seg->area_len = count; @@ -234,6 +256,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix, static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix, struct pv_map *map, struct pv_area *pva, + struct segment_type *segtype, struct physical_volume *mirrored_pv, uint32_t mirrored_pe) { @@ -251,7 +274,8 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix, } seg->lv = lv; - seg->type = SEG_MIRRORED; + seg->segtype = segtype; + seg->le = *ix; seg->status = 0u; seg->le = *ix; seg->len = count; @@ -321,6 +345,7 @@ static int _alloc_contiguous(struct logical_volume *lv, /* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */ static int _alloc_mirrored(struct logical_volume *lv, struct list *pvms, uint32_t allocated, + struct segment_type *segtype, struct physical_volume *mirrored_pv, uint32_t mirrored_pe) { @@ -343,7 +368,7 @@ static int _alloc_mirrored(struct logical_volume *lv, continue; } - if (!_alloc_mirrored_area(lv, &allocated, pvm, pva, + if (!_alloc_mirrored_area(lv, &allocated, pvm, pva, segtype, mirrored_pv, mirrored_pe)) { stack; return 0; @@ -400,7 +425,8 @@ static int _alloc_next_free(struct logical_volume *lv, */ static int _allocate(struct volume_group *vg, struct logical_volume *lv, struct list *allocatable_pvs, uint32_t allocated, - uint32_t stripes, uint32_t stripe_size, + struct segment_type *segtype, + uint32_t stripes, uint32_t stripe_size, uint32_t mirrors, struct physical_volume *mirrored_pv, uint32_t mirrored_pe, uint32_t status) { @@ -420,11 +446,12 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs))) goto out; - if (stripes > 1) - r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size); + if (stripes > 1 || mirrors > 1) + r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size, + mirrors, segtype); else if (mirrored_pv) - r = _alloc_mirrored(lv, pvms, allocated, mirrored_pv, + r = _alloc_mirrored(lv, pvms, allocated, segtype, mirrored_pv, mirrored_pe); else if (lv->alloc == ALLOC_CONTIGUOUS) r = _alloc_contiguous(lv, pvms, allocated); @@ -554,12 +581,51 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, return lv; } -struct logical_volume *lv_create(struct format_instance *fi, +int lv_extend(struct format_instance *fid, + struct logical_volume *lv, + struct segment_type *segtype, + uint32_t stripes, uint32_t stripe_size, + uint32_t mirrors, uint32_t extents, + struct physical_volume *mirrored_pv, uint32_t mirrored_pe, + uint32_t status, struct list *allocatable_pvs) +{ + uint32_t old_le_count = lv->le_count; + uint64_t old_size = lv->size; + + lv->le_count += extents; + lv->size += (uint64_t) extents *lv->vg->extent_size; + + if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, segtype, + stripes, stripe_size, mirrors, mirrored_pv, mirrored_pe, + status)) { + lv->le_count = old_le_count; + lv->size = old_size; + stack; + return 0; + } + + if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) { + log_err("Couldn't merge segments after extending " + "logical volume."); + return 0; + } + + if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) { + stack; + return 0; + } + + return 1; +} + +struct logical_volume *lv_create(struct format_instance *fid, const char *name, uint32_t status, alloc_policy_t alloc, + struct segment_type *segtype, uint32_t stripes, uint32_t stripe_size, + uint32_t mirrors, uint32_t extents, struct volume_group *vg, struct list *allocatable_pvs) @@ -585,21 +651,13 @@ struct logical_volume *lv_create(struct format_instance *fi, return NULL; } - if (!(lv = lv_create_empty(fi, name, "lvol%d", status, alloc, vg))) { + if (!(lv = lv_create_empty(fid, name, "lvol%d", status, alloc, vg))) { stack; return NULL; } - lv->size = (uint64_t) extents *vg->extent_size; - lv->le_count = extents; - - if (!_allocate(vg, lv, allocatable_pvs, 0u, stripes, stripe_size, - NULL, 0u, 0u)) { - stack; - return NULL; - } - - if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { + if (!lv_extend(fid, lv, segtype, stripes, stripe_size, mirrors, + extents, NULL, 0u, 0u, allocatable_pvs)) { stack; return NULL; } @@ -628,7 +686,7 @@ int lv_reduce(struct format_instance *fi, /* reduce this segment */ _put_extents(seg); seg->len -= count; - striped = (seg->type == SEG_STRIPED); + striped = seg->segtype->flags & SEG_AREAS_STRIPED; /* Caller must ensure exact divisibility */ if (striped && (count % seg->area_count)) { log_error("Segment extent reduction %" PRIu32 @@ -655,68 +713,6 @@ int lv_reduce(struct format_instance *fi, return 1; } -int lv_extend(struct format_instance *fi, - struct logical_volume *lv, - uint32_t stripes, uint32_t stripe_size, - uint32_t extents, struct list *allocatable_pvs) -{ - uint32_t old_le_count = lv->le_count; - uint64_t old_size = lv->size; - - lv->le_count += extents; - lv->size += (uint64_t) extents *lv->vg->extent_size; - - if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, - stripes, stripe_size, NULL, 0u, 0u)) { - lv->le_count = old_le_count; - lv->size = old_size; - stack; - return 0; - } - - if (!lv_merge_segments(lv)) { - log_err("Couldn't merge segments after extending " - "logical volume."); - return 0; - } - - if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { - stack; - return 0; - } - - return 1; -} - -int lv_extend_mirror(struct format_instance *fid, - struct logical_volume *lv, - struct physical_volume *mirrored_pv, - uint32_t mirrored_pe, - uint32_t extents, struct list *allocatable_pvs, - uint32_t status) -{ - uint32_t old_le_count = lv->le_count; - uint64_t old_size = lv->size; - - lv->le_count += extents; - lv->size += (uint64_t) extents *lv->vg->extent_size; - - if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, - 1, extents, mirrored_pv, mirrored_pe, status)) { - lv->le_count = old_le_count; - lv->size = old_size; - stack; - return 0; - } - - if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) { - stack; - return 0; - } - - return 1; -} - int lv_remove(struct volume_group *vg, struct logical_volume *lv) { struct list *segh; diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c index 81cbd924d..decd7051e 100644 --- a/lib/metadata/merge.c +++ b/lib/metadata/merge.c @@ -18,60 +18,20 @@ #include "toolcontext.h" #include "lv_alloc.h" #include "str_list.h" - -/* - * Test whether two segments could be merged by the current merging code - */ -static int _segments_compatible(struct lv_segment *first, - struct lv_segment *second) -{ - uint32_t width; - unsigned s; - - /* FIXME Relax the seg type restriction */ - if (!first || !second || - (first->type != SEG_STRIPED) || (second->type != first->type) || - (first->area_count != second->area_count) || - (first->stripe_size != second->stripe_size)) - return 0; - - for (s = 0; s < first->area_count; s++) { - - /* FIXME Relax this to first area type != second area type */ - /* plus the additional AREA_LV checks needed */ - if ((first->area[s].type != AREA_PV) || - (second->area[s].type != AREA_PV)) - return 0; - - width = first->area_len; - - if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) || - (first->area[s].u.pv.pe + width != second->area[s].u.pv.pe)) - return 0; - } - - if (!str_list_lists_equal(&first->tags, &second->tags)) - return 0; - - return 1; -} +#include "segtypes.h" /* * Attempt to merge two adjacent segments. - * Currently only supports SEG_STRIPED on AREA_PV. + * Currently only supports striped segments on AREA_PV. * Returns success if successful, in which case 'first' * gets adjusted to contain both areas. */ static int _merge(struct lv_segment *first, struct lv_segment *second) { + if (!first || !second || first->segtype != second->segtype || + !first->segtype->ops->merge_segments) return 0; - if (!_segments_compatible(first, second)) - return 0; - - first->len += second->len; - first->area_len += second->area_len; - - return 1; + return first->segtype->ops->merge_segments(first, second); } int lv_merge_segments(struct logical_volume *lv) @@ -126,15 +86,14 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg, uint32_t s; uint32_t offset = le - seg->le; - if (seg->type == SEG_SNAPSHOT) { - log_error("Unable to split the snapshot segment at LE %" PRIu32 - " in LV %s", le, lv->name); + if (!(seg->segtype->flags & SEG_CAN_SPLIT)) { + log_error("Unable to split the %s segment at LE %" PRIu32 + " in LV %s", seg->segtype->name, le, lv->name); return 0; } /* Clone the existing segment */ - if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, - seg->area_count))) { + if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) { log_error("Couldn't allocate new LV segment."); return 0; } @@ -148,7 +107,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg, } /* In case of a striped segment, the offset has to be / stripes */ - if (seg->type == SEG_STRIPED) + if (seg->segtype->flags & SEG_AREAS_STRIPED) offset /= seg->area_count; /* Adjust the PV mapping */ @@ -205,4 +164,3 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le) return 1; } - diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 6bd9a2006..dcefe6ebd 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -53,6 +53,7 @@ #define SNAPSHOT 0x00001000 /* LV - tmp internal use only */ #define PVMOVE 0x00002000 /* VG LV SEG */ #define LOCKED 0x00004000 /* LV */ +#define MIRRORED 0x00008000 /* LV - internal use only */ #define LVM_READ 0x00000100 /* LV VG */ #define LVM_WRITE 0x00000200 /* LV VG */ @@ -66,19 +67,13 @@ #define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */ #define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */ #define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */ - + typedef enum { ALLOC_DEFAULT, ALLOC_NEXT_FREE, ALLOC_CONTIGUOUS } alloc_policy_t; -typedef enum { - SEG_STRIPED, - SEG_SNAPSHOT, - SEG_MIRRORED -} segment_type_t; - typedef enum { AREA_PV, AREA_LV @@ -194,11 +189,12 @@ struct volume_group { struct list tags; }; +struct segment_type; struct lv_segment { struct list list; struct logical_volume *lv; - segment_type_t type; + struct segment_type *segtype; uint32_t le; uint32_t len; @@ -407,8 +403,10 @@ struct logical_volume *lv_create(struct format_instance *fi, const char *name, uint32_t status, alloc_policy_t alloc, + struct segment_type *segtype, uint32_t stripes, uint32_t stripe_size, + uint32_t mirrors, uint32_t extents, struct volume_group *vg, struct list *allocatable_pvs); @@ -424,18 +422,13 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, int lv_reduce(struct format_instance *fi, struct logical_volume *lv, uint32_t extents); -int lv_extend(struct format_instance *fi, +int lv_extend(struct format_instance *fid, struct logical_volume *lv, - uint32_t stripes, - uint32_t stripe_size, - uint32_t extents, struct list *allocatable_pvs); - -int lv_extend_mirror(struct format_instance *fid, - struct logical_volume *lv, - struct physical_volume *mirrored_pv, - uint32_t mirrored_pe, - uint32_t extents, struct list *allocatable_pvs, - uint32_t status); + struct segment_type *segtype, + uint32_t stripes, uint32_t stripe_size, + uint32_t mirrors, uint32_t extents, + struct physical_volume *mirrored_pv, uint32_t mirrored_pe, + uint32_t status, struct list *allocatable_pvs); /* lv must be part of vg->lvs */ int lv_remove(struct volume_group *vg, struct logical_volume *lv); diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index ac777d54a..5e058c16f 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -16,6 +16,8 @@ #include "lib.h" #include "metadata.h" #include "toolcontext.h" +#include "segtypes.h" +#include "display.h" /* * Replace any LV segments on given PV with temporary mirror. @@ -33,6 +35,12 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, struct lv_list *lvl; int lv_used = 0; uint32_t s, start_le, extent_count = 0u; + struct segment_type *segtype; + + if (!(segtype = get_segtype_from_string(lv->vg->cmd, "mirror"))) { + stack; + return 0; + } list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); @@ -52,11 +60,11 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, } start_le = lv_mirr->le_count; - if (!lv_extend_mirror(lv->vg->fid, lv_mirr, - seg->area[s].u.pv.pv, - seg->area[s].u.pv.pe, - seg->area_len, allocatable_pvs, - PVMOVE)) { + if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1, + seg->area_len, 0u, seg->area_len, + seg->area[s].u.pv.pv, + seg->area[s].u.pv.pe, + PVMOVE, allocatable_pvs)) { log_error("Allocation for temporary " "pvmove LV failed"); return 0; @@ -98,13 +106,14 @@ int remove_pvmove_mirrors(struct volume_group *vg, continue; if (!(mir_seg = find_seg_by_le(lv_mirr, - seg->area[s].u. - lv.le))) { + seg->area[s]. + u.lv.le))) { log_error("No segment found with LE"); return 0; } - if (mir_seg->type != SEG_MIRRORED || + if ((!(mir_seg->segtype->flags + & SEG_AREAS_MIRRORED)) || !(mir_seg->status & PVMOVE) || mir_seg->le != seg->area[s].u.lv.le || mir_seg->area_count != 2 || @@ -122,7 +131,13 @@ int remove_pvmove_mirrors(struct volume_group *vg, seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv; seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe; - mir_seg->type = SEG_STRIPED; + if (! + (mir_seg->segtype = + get_segtype_from_string(vg->cmd, + "striped"))) { + log_error("Missing striped segtype"); + return 0; + } mir_seg->area_count = 1; lv1->status &= ~LOCKED; @@ -141,7 +156,7 @@ struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume list_iterate(segh, &lv_mirr->segments) { seg = list_item(segh, struct lv_segment); - if (seg->type != SEG_MIRRORED) + if (!(seg->segtype->flags & SEG_AREAS_MIRRORED)) continue; if (seg->area[0].type != AREA_PV) continue; diff --git a/lib/metadata/segtypes.c b/lib/metadata/segtypes.c new file mode 100644 index 000000000..0024e29ce --- /dev/null +++ b/lib/metadata/segtypes.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "lib.h" +#include "toolcontext.h" +#include "segtypes.h" + +struct segment_type *get_segtype_from_string(struct cmd_context *cmd, + const char *str) +{ + struct segment_type *segtype; + + list_iterate_items(segtype, &cmd->segtypes) { + if (!strcmp(segtype->name, str)) + return segtype; + } + + log_error("Unrecognised segment type %s", str); + return NULL; +} diff --git a/lib/metadata/segtypes.h b/lib/metadata/segtypes.h new file mode 100644 index 000000000..3ebb2c730 --- /dev/null +++ b/lib/metadata/segtypes.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SEGTYPES_H +#define _SEGTYPES_H + +struct segtype_handler; +struct cmd_context; +struct config_tree; +struct lv_segment; +struct formatter; +struct config_node; +struct hash_table; +struct dev_manager; + +/* Feature flags */ +#define SEG_CAN_SPLIT 0x00000001 +#define SEG_AREAS_STRIPED 0x00000002 +#define SEG_AREAS_MIRRORED 0x00000004 +#define SEG_FORMAT1_SUPPORT 0x00000008 + +struct segment_type { + struct list list; + struct cmd_context *cmd; + uint32_t flags; + struct segtype_handler *ops; + const char *name; + void *library; + void *private; +}; + +struct segtype_handler { + const char *(*name) (const struct lv_segment * seg); + void (*display) (const struct lv_segment * seg); + int (*text_export) (const struct lv_segment * seg, + struct formatter * f); + int (*text_import_area_count) (struct config_node * sn, + uint32_t *area_count); + int (*text_import) (struct lv_segment * seg, + const struct config_node * sn, + struct hash_table * pv_hash); + int (*merge_segments) (struct lv_segment * seg1, + struct lv_segment * seg2); + int (*compose_target_line) (struct dev_manager * dm, struct pool * mem, + struct config_tree * cft, + void **target_state, + struct lv_segment * seg, char *params, + size_t paramsize, const char **target, + int *pos, uint32_t *pvmove_mirror_count); + int (*target_percent) (void **target_state, struct pool * mem, + struct config_tree * cft, + struct lv_segment * seg, char *params, + uint64_t *total_numerator, + uint64_t *total_denominator, float *percent); + int (*target_present) (void); + void (*destroy) (const struct segment_type * segtype); +}; + +struct segment_type *get_segtype_from_string(struct cmd_context *cmd, + const char *str); + +struct segment_type *init_striped_segtype(struct cmd_context *cmd); + +#ifdef SNAPSHOT_INTERNAL +struct segment_type *init_snapshot_segtype(struct cmd_context *cmd); +#endif + +#ifdef MIRRORED_INTERNAL +struct segment_type *init_mirrored_segtype(struct cmd_context *cmd); +#endif + +#endif diff --git a/lib/mirror/.exported_symbols b/lib/mirror/.exported_symbols new file mode 100644 index 000000000..1c92c6a39 --- /dev/null +++ b/lib/mirror/.exported_symbols @@ -0,0 +1 @@ +init_segtype diff --git a/lib/mirror/Makefile.in b/lib/mirror/Makefile.in new file mode 100644 index 000000000..66f33d50c --- /dev/null +++ b/lib/mirror/Makefile.in @@ -0,0 +1,31 @@ +# +# Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. +# Copyright (C) 2004 Red Hat, Inc. All rights reserved. +# +# This file is part of the LVM2. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU General Public License v.2. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +SOURCES = mirrored.c + +LIB_SHARED = liblvm2mirror.so + +include ../../make.tmpl + +.PHONY: install + +install: liblvm2mirror.so + $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ + $(libdir)/liblvm2mirror.so.$(LIB_VERSION) + $(LN_S) -f liblvm2mirror.so.$(LIB_VERSION) $(libdir)/liblvm2mirror.so + diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c new file mode 100644 index 000000000..846297c4a --- /dev/null +++ b/lib/mirror/mirrored.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "lib.h" +#include "pool.h" +#include "list.h" +#include "toolcontext.h" +#include "metadata.h" +#include "segtypes.h" +#include "display.h" +#include "text_export.h" +#include "text_import.h" +#include "config.h" +#include "defaults.h" +#include "lvm-string.h" +#include "targets.h" + +enum { + MIRR_DISABLED, + MIRR_RUNNING, + MIRR_COMPLETED +}; + +struct mirror_state { + uint32_t region_size; +}; + +static const char *_name(const struct lv_segment *seg) +{ + return seg->segtype->name; +} + +static void _display(const struct lv_segment *seg) +{ + log_print(" Mirrors\t\t%u", seg->area_count); + log_print(" Mirror size\t\t%u", seg->area_len); + log_print(" Mirror original:"); + display_stripe(seg, 0, " "); + log_print(" Mirror destination:"); + display_stripe(seg, 1, " "); + log_print(" "); + +} + +static int _text_import_area_count(struct config_node *sn, uint32_t *area_count) +{ + if (!get_config_uint32(sn, "mirror_count", area_count)) { + log_error("Couldn't read 'mirror_count' for " + "segment '%s'.", sn->key); + return 0; + } + + return 1; +} + +static int _text_import(struct lv_segment *seg, const struct config_node *sn, + struct hash_table *pv_hash) +{ + const struct config_node *cn; + + if (find_config_node(sn, "extents_moved")) { + if (get_config_uint32(sn, "extents_moved", &seg->extents_moved)) + seg->status |= PVMOVE; + else { + log_error("Couldn't read 'extents_moved' for " + "segment '%s'.", sn->key); + return 0; + } + } + + if (!(cn = find_config_node(sn, "mirrors"))) { + log_error("Couldn't find mirrors array for segment " + "'%s'.", sn->key); + return 0; + } + + return text_import_areas(seg, sn, cn, pv_hash); +} + +static int _text_export(const struct lv_segment *seg, struct formatter *f) +{ + outf(f, "mirror_count = %u", seg->area_count); + if (seg->status & PVMOVE) + out_size(f, (uint64_t) seg->extents_moved, + "extents_moved = %u", seg->extents_moved); + + return out_areas(f, seg, "mirror"); +} + +#ifdef DEVMAPPER_SUPPORT +static struct mirror_state *_init_target(struct pool *mem, + struct config_tree *cft) +{ + struct mirror_state *mirr_state; + + if (!(mirr_state = pool_alloc(mem, sizeof(*mirr_state)))) { + log_error("struct mirr_state allocation failed"); + return NULL; + } + + mirr_state->region_size = 2 * + find_config_int(cft->root, + "activation/mirror_region_size", + DEFAULT_MIRROR_REGION_SIZE); + + return mirr_state; +} + +static int _compose_target_line(struct dev_manager *dm, struct pool *mem, + struct config_tree *cft, void **target_state, + struct lv_segment *seg, char *params, + size_t paramsize, const char **target, int *pos, + uint32_t *pvmove_mirror_count) +{ + struct mirror_state *mirr_state; + int mirror_status = MIRR_RUNNING; + int areas = seg->area_count; + int start_area = 0u; + + if (!*target_state) + *target_state = _init_target(mem, cft); + + mirr_state = *target_state; + + /* mirror log_type #log_params [log_params]* + * #mirrors [device offset]+ + */ + if (seg->status & PVMOVE) { + if (seg->extents_moved == seg->area_len) { + mirror_status = MIRR_COMPLETED; + start_area = 1; + } else if (*pvmove_mirror_count++) { + mirror_status = MIRR_DISABLED; + areas = 1; + } + } + + if (mirror_status != MIRR_RUNNING) { + *target = "linear"; + } else { + *target = "mirror"; + if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ", + mirr_state->region_size, areas)) < 0) { + stack; + return -1; + } + } + + return compose_areas_line(dm, seg, params, paramsize, pos, start_area, + areas); + +} + +static int _target_percent(void **target_state, struct pool *mem, + struct config_tree *cft, struct lv_segment *seg, + char *params, uint64_t *total_numerator, + uint64_t *total_denominator, float *percent) +{ + struct mirror_state *mirr_state; + uint64_t numerator, denominator; + + if (!*target_state) + *target_state = _init_target(mem, cft); + + mirr_state = *target_state; + + log_debug("Mirror status: %s", params); + if (sscanf(params, "%*d %*x:%*x %*x:%*x %" PRIu64 + "/%" PRIu64, &numerator, &denominator) != 2) { + log_error("Failure parsing mirror status: %s", params); + return 0; + } + *total_numerator += numerator; + *total_denominator += denominator; + + if (seg && (seg->status & PVMOVE)) + seg->extents_moved = mirr_state->region_size * + numerator / seg->lv->vg->extent_size; + + return 1; +} +#endif + +static void _destroy(const struct segment_type *segtype) +{ + dbg_free((void *) segtype); +} + +static struct segtype_handler _mirrored_ops = { + name:_name, + display:_display, + text_import_area_count:_text_import_area_count, + text_import:_text_import, + text_export:_text_export, +#ifdef DEVMAPPER_SUPPORT + compose_target_line:_compose_target_line, + target_percent:_target_percent, +#endif + destroy:_destroy, +}; + +#ifdef MIRRORED_INTERNAL +struct segment_type *init_mirrored_segtype(struct cmd_context *cmd) +#else /* Shared */ +struct segment_type *init_segtype(struct cmd_context *cmd); +struct segment_type *init_segtype(struct cmd_context *cmd) +#endif +{ + struct segment_type *segtype = dbg_malloc(sizeof(*segtype)); + + if (!segtype) { + stack; + return NULL; + } + + segtype->cmd = cmd; + segtype->ops = &_mirrored_ops; + segtype->name = "mirror"; + segtype->private = NULL; + segtype->flags = SEG_CAN_SPLIT | SEG_AREAS_MIRRORED; + + return segtype; +} diff --git a/lib/report/report.c b/lib/report/report.c index 00f5bbce6..485bdd118 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -21,6 +21,7 @@ #include "lvm-string.h" #include "display.h" #include "activate.h" +#include "segtypes.h" /* * For macro use @@ -329,7 +330,7 @@ static int _segtype_disp(struct report_handle *rh, struct field *field, if (seg->area_count == 1) field->report_string = "linear"; else - field->report_string = get_segtype_string(seg->type); + field->report_string = seg->segtype->ops->name(seg); field->sort_value = (const void *) field->report_string; return 1; diff --git a/lib/snapshot/.exported_symbols b/lib/snapshot/.exported_symbols new file mode 100644 index 000000000..1c92c6a39 --- /dev/null +++ b/lib/snapshot/.exported_symbols @@ -0,0 +1 @@ +init_segtype diff --git a/lib/snapshot/Makefile.in b/lib/snapshot/Makefile.in new file mode 100644 index 000000000..876616139 --- /dev/null +++ b/lib/snapshot/Makefile.in @@ -0,0 +1,32 @@ +# +# Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. +# Copyright (C) 2004 Red Hat, Inc. All rights reserved. +# +# This file is part of the LVM2. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU General Public License v.2. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +SOURCES = snapshot.c + +LIB_SHARED = liblvm2snapshot.so + +include ../../make.tmpl + +.PHONY: install + +install: liblvm2snapshot.so + $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ + $(libdir)/liblvm2snapshot.so.$(LIB_VERSION) + $(LN_S) -f liblvm2snapshot.so.$(LIB_VERSION) \ + $(libdir)/liblvm2snapshot.so + diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c new file mode 100644 index 000000000..feb5faa96 --- /dev/null +++ b/lib/snapshot/snapshot.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "lib.h" +#include "pool.h" +#include "list.h" +#include "toolcontext.h" +#include "metadata.h" +#include "segtypes.h" +#include "text_export.h" +#include "config.h" + +static const char *_name(const struct lv_segment *seg) +{ + return seg->segtype->name; +} + +static int _text_import(struct lv_segment *seg, const struct config_node *sn, + struct hash_table *pv_hash) +{ + uint32_t chunk_size; + const char *org_name, *cow_name; + struct logical_volume *org, *cow; + + seg->lv->status |= SNAPSHOT; + + if (!get_config_uint32(sn, "chunk_size", &chunk_size)) { + log_error("Couldn't read chunk size for snapshot."); + return 0; + } + + log_suppress(1); + + if (!(cow_name = find_config_str(sn, "cow_store", NULL))) { + log_suppress(0); + log_error("Snapshot cow storage not specified."); + return 0; + } + + if (!(org_name = find_config_str(sn, "origin", NULL))) { + log_suppress(0); + log_error("Snapshot origin not specified."); + return 0; + } + + log_suppress(0); + + if (!(cow = find_lv(seg->lv->vg, cow_name))) { + log_error("Unknown logical volume specified for " + "snapshot cow store."); + return 0; + } + + if (!(org = find_lv(seg->lv->vg, org_name))) { + log_error("Unknown logical volume specified for " + "snapshot origin."); + return 0; + } + + if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], chunk_size)) { + stack; + return 0; + } + + return 1; +} + +static int _text_export(const struct lv_segment *seg, struct formatter *f) +{ + outf(f, "chunk_size = %u", seg->chunk_size); + outf(f, "origin = \"%s\"", seg->origin->name); + outf(f, "cow_store = \"%s\"", seg->cow->name); + + return 1; +} + +static int _target_percent(void **target_state, struct pool *mem, + struct config_tree *cft, struct lv_segment *seg, + char *params, uint64_t *total_numerator, + uint64_t *total_denominator, float *percent) +{ + float percent2; + uint64_t numerator, denominator; + + if (index(params, '/')) { + if (sscanf(params, "%" PRIu64 "/%" PRIu64, + &numerator, &denominator) == 2) { + *total_numerator += numerator; + *total_denominator += denominator; + } + } else if (sscanf(params, "%f", &percent2) == 1) { + *percent += percent2; + *percent /= 2; + } + + return 1; +} + +static void _destroy(const struct segment_type *segtype) +{ + dbg_free((void *) segtype); +} + +static struct segtype_handler _snapshot_ops = { + name:_name, + text_import:_text_import, + text_export:_text_export, + target_percent:_target_percent, + destroy:_destroy, +}; + +#ifdef SNAPSHOT_INTERNAL +struct segment_type *init_snapshot_segtype(struct cmd_context *cmd) +#else /* Shared */ +struct segment_type *init_segtype(struct cmd_context *cmd); +struct segment_type *init_segtype(struct cmd_context *cmd) +#endif +{ + struct segment_type *segtype = dbg_malloc(sizeof(*segtype)); + + if (!segtype) { + stack; + return NULL; + } + + segtype->cmd = cmd; + segtype->ops = &_snapshot_ops; + segtype->name = "snapshot"; + segtype->private = NULL; + segtype->flags = 0u; + + return segtype; +} diff --git a/lib/striped/striped.c b/lib/striped/striped.c new file mode 100644 index 000000000..3b06c3df3 --- /dev/null +++ b/lib/striped/striped.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "lib.h" +#include "pool.h" +#include "list.h" +#include "toolcontext.h" +#include "segtypes.h" +#include "display.h" +#include "text_export.h" +#include "text_import.h" +#include "config.h" +#include "str_list.h" +#include "targets.h" +#include "lvm-string.h" + +static const char *_name(const struct lv_segment *seg) +{ + return (seg->area_count == 1) ? "linear" : seg->segtype->name; +} + +static void _display(const struct lv_segment *seg) +{ + uint32_t s; + + if (seg->area_count == 1) + display_stripe(seg, 0, " "); + else { + log_print(" Stripes\t\t%u", seg->area_count); + log_print(" Stripe size\t\t%u KB", seg->stripe_size / 2); + + for (s = 0; s < seg->area_count; s++) { + log_print(" Stripe %d:", s); + display_stripe(seg, s, " "); + } + } + log_print(" "); +} + +static int _text_import_area_count(struct config_node *sn, uint32_t *area_count) +{ + if (!get_config_uint32(sn, "stripe_count", area_count)) { + log_error("Couldn't read 'stripe_count' for " + "segment '%s'.", sn->key); + return 0; + } + + return 1; +} + +static int _text_import(struct lv_segment *seg, const struct config_node *sn, + struct hash_table *pv_hash) +{ + struct config_node *cn; + + if ((seg->area_count != 1) && + !get_config_uint32(sn, "stripe_size", &seg->stripe_size)) { + log_error("Couldn't read stripe_size for segment '%s'.", + sn->key); + return 0; + } + + if (!(cn = find_config_node(sn, "stripes"))) { + log_error("Couldn't find stripes array for segment " + "'%s'.", sn->key); + return 0; + } + + seg->area_len /= seg->area_count; + + return text_import_areas(seg, sn, cn, pv_hash); +} + +static int _text_export(const struct lv_segment *seg, struct formatter *f) +{ + + outf(f, "stripe_count = %u%s", seg->area_count, + (seg->area_count == 1) ? "\t# linear" : ""); + + if (seg->area_count > 1) + out_size(f, (uint64_t) seg->stripe_size, + "stripe_size = %u", seg->stripe_size); + + return out_areas(f, seg, "stripe"); +} + +/* + * Test whether two segments could be merged by the current merging code + */ +static int _segments_compatible(struct lv_segment *first, + struct lv_segment *second) +{ + uint32_t width; + unsigned s; + + if ((first->area_count != second->area_count) || + (first->stripe_size != second->stripe_size)) return 0; + + for (s = 0; s < first->area_count; s++) { + + /* FIXME Relax this to first area type != second area type */ + /* plus the additional AREA_LV checks needed */ + if ((first->area[s].type != AREA_PV) || + (second->area[s].type != AREA_PV)) return 0; + + width = first->area_len; + + if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) || + (first->area[s].u.pv.pe + width != second->area[s].u.pv.pe)) + return 0; + } + + if (!str_list_lists_equal(&first->tags, &second->tags)) + return 0; + + return 1; +} + +static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) +{ + if (!_segments_compatible(seg1, seg2)) + return 0; + + seg1->len += seg2->len; + seg1->area_len += seg2->area_len; + + return 1; +} + +#ifdef DEVMAPPER_SUPPORT +static int _compose_target_line(struct dev_manager *dm, struct pool *mem, + struct config_tree *cft, void **target_state, + struct lv_segment *seg, char *params, + size_t paramsize, const char **target, int *pos, + uint32_t *pvmove_mirror_count) +{ + /* linear [device offset]+ + * striped #stripes stripe_size [device offset]+ */ + + if (seg->area_count == 1) + *target = "linear"; + else if (seg->area_count > 1) { + *target = "striped"; + if ((*pos = lvm_snprintf(params, paramsize, "%u %u ", + seg->area_count, + seg->stripe_size)) < 0) { + stack; + return -1; + } + } else { + log_error("Internal error: striped target with no stripes"); + return 0; + } + + return compose_areas_line(dm, seg, params, paramsize, pos, 0u, + seg->area_count); +} +#endif + +static void _destroy(const struct segment_type *segtype) +{ + dbg_free((void *) segtype); +} + +static struct segtype_handler _striped_ops = { + name:_name, + display:_display, + text_import_area_count:_text_import_area_count, + text_import:_text_import, + text_export:_text_export, + merge_segments:_merge_segments, +#ifdef DEVMAPPER_SUPPORT + compose_target_line:_compose_target_line, +#endif + destroy:_destroy, +}; + +struct segment_type *init_striped_segtype(struct cmd_context *cmd) +{ + struct segment_type *segtype = dbg_malloc(sizeof(*segtype)); + + if (!segtype) { + stack; + return NULL; + } + + segtype->cmd = cmd; + segtype->ops = &_striped_ops; + segtype->name = "striped"; + segtype->private = NULL; + segtype->flags = + SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT; + + return segtype; +} diff --git a/tools/lvcreate.c b/tools/lvcreate.c index afe4f0a04..9385ea400 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -33,6 +33,10 @@ struct lvcreate_params { uint32_t stripe_size; uint32_t chunk_size; + uint32_t mirrors; + + struct segment_type *segtype; + /* size */ uint32_t extents; uint64_t size; @@ -188,6 +192,11 @@ static int _read_stripe_params(struct lvcreate_params *lp, lp->stripes = arg_uint_value(cmd, stripes_ARG, 1); if (lp->stripes == 1) log_print("Redundant stripes argument: default is 1"); + else if (!(lp->segtype = get_segtype_from_string(cmd, + "striped"))) { + stack; + return 0; + } } if (arg_count(cmd, stripesize_ARG)) { @@ -466,8 +475,9 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) status |= LVM_WRITE; } - if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc, lp->stripes, - lp->stripe_size, lp->extents, vg, pvh))) + if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc, lp->segtype, + lp->stripes, lp->stripe_size, lp->mirrors, + lp->extents, vg, pvh))) return 0; if (lp->read_ahead) { diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 4efef72cf..168e57385 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, diff --git a/tools/lvresize.c b/tools/lvresize.c index a4c0b19de..f818c8873 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -39,6 +39,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) struct lv_segment *seg; uint32_t seg_extents; uint32_t sz, str; + struct segment_type *segtype; enum { LV_ANY = 0, @@ -196,8 +197,8 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) /* If extending, find stripes, stripesize & size of last segment */ if (extents > lv->le_count && !(stripes == 1 || (stripes > 1 && ssize))) { list_iterate_items(seg, &lv->segments) { - if (seg->type != SEG_STRIPED) - continue; + if (strcmp(seg->segtype->ops->name(seg), "striped")) + continue; /* Not striped */ sz = seg->stripe_size; str = seg->area_count; @@ -243,7 +244,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) list_iterate_items(seg, &lv->segments) { seg_extents = seg->len; - if (seg->type == SEG_STRIPED) { + if (seg->segtype->flags & SEG_AREAS_STRIPED) { seg_stripesize = seg->stripe_size; seg_stripes = seg->area_count; } @@ -354,9 +355,14 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) display_size(cmd, (uint64_t) extents * (vg->extent_size / 2), SIZE_SHORT)); + if (!(segtype = get_segtype_from_string(lv->vg->cmd, + "striped"))) { + stack; + return 0; + } - if (!lv_extend(vg->fid, lv, stripes, ssize, - extents - lv->le_count, pvh)) + if (!lv_extend(vg->fid, lv, segtype, stripes, ssize, 0u, + extents - lv->le_count, NULL, 0u, 0u, pvh)) goto error; } diff --git a/tools/tools.h b/tools/tools.h index a68d9cc6d..9e447e90f 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -43,6 +43,7 @@ #include "lvm-file.h" #include "lvm-string.h" #include "pool.h" +#include "segtypes.h" #include "str_list.h" #include "toolcontext.h" #include "toollib.h" diff --git a/tools/vgchange.c b/tools/vgchange.c index a298c64d1..a8f7cff0c 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -51,8 +51,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, return count; } -static int _vgchange_available(struct cmd_context *cmd, - struct volume_group *vg) +static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg) { int lv_open, active; int available = !strcmp(arg_str_value(cmd, available_ARG, "n"), "y");