From d8ac0fbcbffe0b8d384bb21e4db6b8765dfd7fe7 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Mon, 7 Jun 2004 19:10:21 +0000 Subject: [PATCH] Add read-only GFS pool support. --- Makefile.in | 1 + WHATS_NEW | 1 + configure | 34 ++- configure.in | 23 +- include/.symlinks | 1 + lib/Makefile.in | 12 + lib/commands/toolcontext.c | 11 + lib/format_pool/.exported_symbols | 1 + lib/format_pool/Makefile.in | 37 +++ lib/format_pool/disk_rep.c | 385 ++++++++++++++++++++++++++++++ lib/format_pool/disk_rep.h | 178 ++++++++++++++ lib/format_pool/format_pool.c | 361 ++++++++++++++++++++++++++++ lib/format_pool/format_pool.h | 25 ++ lib/format_pool/import_export.c | 309 ++++++++++++++++++++++++ lib/format_pool/pool_label.c | 108 +++++++++ lib/format_pool/pool_label.h | 23 ++ 16 files changed, 1506 insertions(+), 4 deletions(-) create mode 100644 lib/format_pool/.exported_symbols create mode 100644 lib/format_pool/Makefile.in create mode 100644 lib/format_pool/disk_rep.c create mode 100644 lib/format_pool/disk_rep.h create mode 100644 lib/format_pool/format_pool.c create mode 100644 lib/format_pool/format_pool.h create mode 100644 lib/format_pool/import_export.c create mode 100644 lib/format_pool/pool_label.c create mode 100644 lib/format_pool/pool_label.h diff --git a/Makefile.in b/Makefile.in index 489ba3bb4..f7b4d5238 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,6 +26,7 @@ SUBDIRS += lib tools ifeq ($(MAKECMDGOALS),distclean) SUBDIRS += lib/format1 \ + lib/format_pool \ lib/mirror \ lib/snapshot \ po \ diff --git a/WHATS_NEW b/WHATS_NEW index a2725f9c0..4d5fe2fa5 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.00.17 - ============================= + Add read-only GFS pool support. Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/ Fix rounding of large diplayed sizes. Suppress decimal point when using units of sectors/bytes. diff --git a/configure b/configure index 79859784f..22487fb85 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 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_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 POOL 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,8 @@ Optional Packages: --with-group=GROUP Set the group owner of installed files --with-lvm1=TYPE LVM1 metadata support: internal/shared/none TYPE=internal + --with-pool=TYPE GFS pool 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 @@ -3970,6 +3972,29 @@ if test x$LVM1 = xinternal; then CFLAGS="$CFLAGS -DLVM1_INTERNAL" fi + +# Check whether --with-pool or --without-pool was given. +if test "${with_pool+set}" = set; then + withval="$with_pool" + POOL="$withval" +else + POOL="internal" +fi; + +if [ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]; + then { { echo "$as_me:$LINENO: error: --with-pool parameter invalid +" >&5 +echo "$as_me: error: --with-pool parameter invalid +" >&2;} + { (exit 1); exit 1; }; } + exit +fi; + +if test x$POOL = xinternal; then + CFLAGS="$CFLAGS -DPOOL_INTERNAL" +fi + + # Check whether --enable-jobs or --disable-jobs was given. if test "${enable_jobs+set}" = set; then enableval="$enable_jobs" @@ -4662,7 +4687,7 @@ else HAVE_LIBDL=no fi -if [ \( "x$LVM1" = xshared -o \ +if [ \( "x$LVM1" = xshared -o "x$POOL" = 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 @@ -5169,7 +5194,8 @@ fi - 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" + + ac_config_files="$ac_config_files Makefile make.tmpl doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/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 @@ -5726,6 +5752,7 @@ 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/format_pool/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/format_pool/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" ;; @@ -5853,6 +5880,7 @@ s,@MSGFMT@,$MSGFMT,;t t s,@JOBS@,$JOBS,;t t s,@STATIC_LINK@,$STATIC_LINK,;t t s,@LVM1@,$LVM1,;t t +s,@POOL@,$POOL,;t t s,@SNAPSHOTS@,$SNAPSHOTS,;t t s,@MIRRORS@,$MIRRORS,;t t s,@OWNER@,$OWNER,;t t diff --git a/configure.in b/configure.in index e0a163696..2ae7629ea 100644 --- a/configure.in +++ b/configure.in @@ -121,6 +121,25 @@ if test x$LVM1 = xinternal; then CFLAGS="$CFLAGS -DLVM1_INTERNAL" fi +dnl -- format_pool inclusion type +AC_ARG_WITH(pool, + [ --with-pool=TYPE GFS pool metadata support: internal/shared/none + [TYPE=internal] ], + [ POOL="$withval" ], + [ POOL="internal" ]) + +if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]]; + then AC_MSG_ERROR( +--with-pool parameter invalid +) + exit +fi; + +if test x$POOL = xinternal; then + CFLAGS="$CFLAGS -DPOOL_INTERNAL" +fi + + AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2) dnl -- snapshots inclusion type @@ -246,7 +265,7 @@ else fi dnl Check for shared/static conflicts -if [[ \( "x$LVM1" = xshared -o \ +if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o \ "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ \) -a "x$STATIC_LINK" = xyes ]]; then AC_MSG_ERROR( @@ -325,6 +344,7 @@ fi AC_SUBST(JOBS) AC_SUBST(STATIC_LINK) AC_SUBST(LVM1) +AC_SUBST(POOL) AC_SUBST(SNAPSHOTS) AC_SUBST(MIRRORS) AC_SUBST(OWNER) @@ -360,6 +380,7 @@ doc/Makefile \ include/Makefile \ lib/Makefile \ lib/format1/Makefile \ +lib/format_pool/Makefile \ lib/mirror/Makefile \ lib/snapshot/Makefile \ man/Makefile \ diff --git a/include/.symlinks b/include/.symlinks index 7c350da62..74987de7c 100644 --- a/include/.symlinks +++ b/include/.symlinks @@ -21,6 +21,7 @@ ../lib/filters/filter-sysfs.h ../lib/filters/filter.h ../lib/format1/format1.h +../lib/format_pool/format_pool.h ../lib/format_text/format-text.h ../lib/format_text/text_export.h ../lib/format_text/text_import.h diff --git a/lib/Makefile.in b/lib/Makefile.in index c1f61f0d8..dd370ad3a 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -20,6 +20,10 @@ ifeq ("@LVM1@", "shared") SUBDIRS = format1 endif +ifeq ("@POOL@", "shared") + SUBDIRS += format_pool +endif + ifeq ("@SNAPSHOTS@", "shared") SUBDIRS += snapshot endif @@ -92,6 +96,14 @@ ifeq ("@LVM1@", "internal") format1/vg_number.c endif +ifeq ("@POOL@", "internal") + SOURCES +=\ + format_pool/disk_rep.c \ + format_pool/format_pool.c \ + format_pool/import_export.c \ + format_pool/pool_label.c +endif + ifeq ("@SNAPSHOTS@", "internal") SOURCES += snapshot/snapshot.c endif diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index ff8a90b76..423fefea8 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -44,6 +44,10 @@ #include "format1.h" #endif +#ifdef POOL_INTERNAL +#include "format_pool.h" +#endif + #include #include #include @@ -606,6 +610,13 @@ static int _init_formats(struct cmd_context *cmd) list_add(&cmd->formats, &fmt->list); #endif +#ifdef POOL_INTERNAL + if (!(fmt = init_pool_format(cmd))) + return 0; + fmt->library = NULL; + list_add(&cmd->formats, &fmt->list); +#endif + #ifdef HAVE_LIBDL /* Load any formats in shared libs */ if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) { diff --git a/lib/format_pool/.exported_symbols b/lib/format_pool/.exported_symbols new file mode 100644 index 000000000..e9fac2e80 --- /dev/null +++ b/lib/format_pool/.exported_symbols @@ -0,0 +1 @@ +init_format diff --git a/lib/format_pool/Makefile.in b/lib/format_pool/Makefile.in new file mode 100644 index 000000000..1c703fc70 --- /dev/null +++ b/lib/format_pool/Makefile.in @@ -0,0 +1,37 @@ +# +# 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 =\ + disk_rep.c \ + format_pool.c \ + import_export.c \ + pool_label.c + +LIB_SHARED = liblvm2formatpool.so + +include ../../make.tmpl + +.PHONY: install + +install: liblvm2format_pool.so + $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \ + $(libdir)/liblvm2formatpool.so.$(LIB_VERSION) + $(LN_S) -f liblvm2formatpool.so.$(LIB_VERSION) \ + $(libdir)/liblvm2formatpool.so + + diff --git a/lib/format_pool/disk_rep.c b/lib/format_pool/disk_rep.c new file mode 100644 index 000000000..b3a678a80 --- /dev/null +++ b/lib/format_pool/disk_rep.c @@ -0,0 +1,385 @@ +/* + * Copyright (C) 1997-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 "label.h" +#include "metadata.h" +#include "lvmcache.h" +#include "filter.h" +#include "list.h" +#include "xlate.h" + +#include "disk_rep.h" + +/* FIXME: memcpy might not be portable */ +#define CPIN_8(x, y, z) {memcpy((x), (y), (z));} +#define CPOUT_8(x, y, z) {memcpy((y), (x), (z));} +#define CPIN_16(x, y) {(x) = xlate16_be((y));} +#define CPOUT_16(x, y) {(y) = xlate16_be((x));} +#define CPIN_32(x, y) {(x) = xlate32_be((y));} +#define CPOUT_32(x, y) {(y) = xlate32_be((x));} +#define CPIN_64(x, y) {(x) = xlate64_be((y));} +#define CPOUT_64(x, y) {(y) = xlate64_be((x));} + +static int __read_pool_disk(const struct format_type *fmt, struct device *dev, + struct pool *mem, struct pool_list *pl, + const char *vg_name) +{ + char buf[512]; + + /* FIXME: Need to check the cache here first */ + if (!dev_read(dev, UINT64_C(0), 512, buf)) { + log_very_verbose("Failed to read PV data from %s", + dev_name(dev)); + return 0; + } + + if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL)) { + stack; + return 0; + } + + return 1; +} + +static void _add_pl_to_list(struct list *head, struct pool_list *data) +{ + struct list *pvdh; + struct pool_list *pl; + + list_iterate(pvdh, head) { + pl = list_item(pvdh, struct pool_list); + + if (id_equal(&data->pv_uuid, &pl->pv_uuid)) { + char uuid[ID_LEN + 7]; + + id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7); + + if (MAJOR(data->dev->dev) != md_major()) { + log_very_verbose("Ignoring duplicate PV %s on " + "%s", uuid, + dev_name(data->dev)); + return; + } + log_very_verbose("Duplicate PV %s - using md %s", + uuid, dev_name(data->dev)); + list_del(pvdh); + break; + } + } + list_add(head, &data->list); +} + +int read_pool_label(struct pool_list *pl, struct labeller *l, + struct device *dev, char *buf, struct label **label) +{ + struct lvmcache_info *info; + struct id pvid; + struct id vgid; + char uuid[ID_LEN + 7]; + struct pool_disk *pd = &pl->pd; + + pool_label_in(pd, buf); + + get_pool_pv_uuid(&pvid, pd); + id_write_format(&pvid, uuid, ID_LEN + 7); + log_debug("Calculated uuid %s for %s", uuid, dev_name(dev)); + + get_pool_vg_uuid(&vgid, pd); + id_write_format(&vgid, uuid, ID_LEN + 7); + log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name); + + if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name, + (char *) &vgid))) { + stack; + return 0; + } + if (label) + *label = info->label; + + info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT; + list_init(&info->mdas); + + info->status &= ~CACHE_INVALID; + + pl->dev = dev; + pl->pv = NULL; + memcpy(&pl->pv_uuid, &pvid, sizeof(pvid)); + + return 1; +} + +/** + * pool_label_out - copies a pool_label_t into a char buffer + * @pl: ptr to a pool_label_t struct + * @buf: ptr to raw space where label info will be copied + * + * This function is important because it takes care of all of + * the endian issues when copying to disk. This way, when + * machines of different architectures are used, they will + * be able to interpret ondisk labels correctly. Always use + * this function before writing to disk. + */ +void pool_label_out(struct pool_disk *pl, char *buf) +{ + struct pool_disk *bufpl = (struct pool_disk *) buf; + + CPOUT_64(pl->pl_magic, bufpl->pl_magic); + CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id); + CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); + CPOUT_32(pl->pl_version, bufpl->pl_version); + CPOUT_32(pl->pl_subpools, bufpl->pl_subpools); + CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id); + CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs); + CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid); + CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type); + CPOUT_64(pl->pl_blocks, bufpl->pl_blocks); + CPOUT_32(pl->pl_striping, bufpl->pl_striping); + CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); + CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); + CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight); + CPOUT_32(pl->pl_minor, bufpl->pl_minor); + CPOUT_32(pl->pl_padding, bufpl->pl_padding); + CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184); +} + +/** + * pool_label_in - copies a char buffer into a pool_label_t + * @pl: ptr to a pool_label_t struct + * @buf: ptr to raw space where label info is copied from + * + * This function is important because it takes care of all of + * the endian issues when information from disk is about to be + * used. This way, when machines of different architectures + * are used, they will be able to interpret ondisk labels + * correctly. Always use this function before using labels that + * were read from disk. + */ +void pool_label_in(struct pool_disk *pl, char *buf) +{ + struct pool_disk *bufpl = (struct pool_disk *) buf; + + CPIN_64(pl->pl_magic, bufpl->pl_magic); + CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id); + CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE); + CPIN_32(pl->pl_version, bufpl->pl_version); + CPIN_32(pl->pl_subpools, bufpl->pl_subpools); + CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id); + CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs); + CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid); + CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type); + CPIN_64(pl->pl_blocks, bufpl->pl_blocks); + CPIN_32(pl->pl_striping, bufpl->pl_striping); + CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs); + CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid); + CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight); + CPIN_32(pl->pl_minor, bufpl->pl_minor); + CPIN_32(pl->pl_padding, bufpl->pl_padding); + CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184); +} + +static char _calc_char(unsigned int id) +{ + /* + * [0-9A-Za-z!#] - 64 printable chars (6-bits) + */ + + if (id < 10) + return id + 48; + if (id < 36) + return (id - 10) + 65; + if (id < 62) + return (id - 36) + 97; + if (id == 62) + return '!'; + if (id == 63) + return '#'; + + return '%'; +} + +void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid) +{ + int i; + unsigned shifter = 0x003F; + + assert(ID_LEN == 32); + memset(uuid, 0, ID_LEN); + strcat(uuid, "POOL0000000000"); + + /* We grab the entire 64 bits (+2 that get shifted in) */ + for (i = 13; i < 24; i++) { + uuid[i] = _calc_char(((unsigned) poolid) & shifter); + poolid = poolid >> 6; + } + + /* We grab the entire 32 bits (+4 that get shifted in) */ + for (i = 24; i < 30; i++) { + uuid[i] = _calc_char((unsigned) (spid & shifter)); + spid = spid >> 6; + } + + /* + * Since we can only have 128 devices, we only worry about the + * last 12 bits + */ + for (i = 30; i < 32; i++) { + uuid[i] = _calc_char((unsigned) (devid & shifter)); + devid = devid >> 6; + } + +} + +static int _read_vg_pds(const struct format_type *fmt, struct pool *mem, + struct lvmcache_vginfo *vginfo, struct list *head, + uint32_t *devcount) +{ + + struct list *vgih = NULL; + struct device *dev; + struct pool_list *pl = NULL; + struct pool *tmpmem = NULL; + + uint32_t sp_count = 0; + uint32_t *sp_devs = NULL; + int i; + + /* FIXME: maybe should return a different error in memory + * allocation failure */ + if (!(tmpmem = pool_create(512))) { + stack; + return 0; + } + + list_iterate(vgih, &vginfo->infos) { + dev = list_item(vgih, struct lvmcache_info)->dev; + if (dev && + !(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname))) + break; + /* + * We need to keep track of the total expected number + * of devices per subpool + */ + if (!sp_count) { + sp_count = pl->pd.pl_subpools; + if (!(sp_devs = + pool_zalloc(tmpmem, + sizeof(uint32_t) * sp_count))) { + log_error("Unable to allocate %d 32-bit uints", + sp_count); + pool_destroy(tmpmem); + return 0; + } + } + /* + * watch out for a pool label with a different subpool + * count than the original - give up if it does + */ + if (sp_count != pl->pd.pl_subpools) + break; + + _add_pl_to_list(head, pl); + + if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0) + sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs; + } + + *devcount = 0; + for (i = 0; i < sp_count; i++) { + *devcount += sp_devs[i]; + } + + pool_destroy(tmpmem); + + if (pl && *pl->pd.pl_pool_name) + return 1; + + return 0; + +} + +int read_pool_pds(const struct format_type *fmt, const char *vg_name, + struct pool *mem, struct list *pdhead) +{ + struct lvmcache_vginfo *vginfo; + uint32_t totaldevs; + int full_scan = -1; + + do { + /* + * If the cache scanning doesn't work, this will never work + */ + if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) && + vginfo->infos.n) { + + if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) { + /* + * If we found all the devices we were + * expecting, return success + */ + if (list_size(pdhead) == totaldevs) + return 1; + + /* + * accept partial pool if we've done a full + * rescan of the cache + */ + if (full_scan > 0) + return 1; + } + } + /* Failed */ + list_init(pdhead); + + full_scan++; + if (full_scan > 1) { + log_debug("No devices for vg %s found in cache", + vg_name); + return 0; + } + lvmcache_label_scan(fmt->cmd, full_scan); + + } while (1); + +} + +struct pool_list *read_pool_disk(const struct format_type *fmt, + struct device *dev, struct pool *mem, + const char *vg_name) +{ + struct pool_list *pl; + + if (!dev_open(dev)) { + stack; + return NULL; + } + + if (!(pl = pool_zalloc(mem, sizeof(*pl)))) { + log_error("Unable to allocate pool list structure"); + return 0; + } + + if (!__read_pool_disk(fmt, dev, mem, pl, vg_name)) { + stack; + return NULL; + } + + if (!dev_close(dev)) + stack; + + return pl; + +} diff --git a/lib/format_pool/disk_rep.h b/lib/format_pool/disk_rep.h new file mode 100644 index 000000000..8d09d9617 --- /dev/null +++ b/lib/format_pool/disk_rep.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 1997-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 DISK_REP_FORMAT_POOL_H +#define DISK_REP_FORMAT_POOL_H + +#include "label.h" +#include "metadata.h" +#include "pool.h" + +/* From NSP.cf */ +#define NSPMajorVersion 4 +#define NSPMinorVersion 1 +#define NSPUpdateLevel 3 + +/* From pool_std.h */ +#define POOL_NAME_SIZE (256) +#define POOL_MAGIC 0x011670 +#define POOL_MAJOR (121) +#define POOL_MAX_DEVICES 128 + +/* When checking for version matching, the first two numbers ** +** are important for metadata formats, a.k.a pool labels. ** +** All the numbers are important when checking if the user ** +** space tools match up with the kernel module............. */ +#define POOL_VERSION (NSPMajorVersion << 16 | \ + NSPMinorVersion << 8 | \ + NSPUpdateLevel) + +/* Pool label is at the head of every pool disk partition */ +#define SIZEOF_POOL_LABEL (8192) + +/* in sectors */ +#define POOL_PE_SIZE (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) +#define POOL_PE_START (SIZEOF_POOL_LABEL >> SECTOR_SHIFT) + +/* Helper fxns */ +#define get_pool_vg_uuid(id, pd) do { get_pool_uuid((char *)(id), \ + (pd)->pl_pool_id, 0, 0); \ + } while(0) +#define get_pool_pv_uuid(id, pd) do { get_pool_uuid((char *)(id), \ + (pd)->pl_pool_id, \ + (pd)->pl_sp_id, \ + (pd)->pl_sp_devid); \ + } while(0) +#define get_pool_lv_uuid(id, pd) do { get_pool_uuid((char *)&(id)[0], \ + (pd)->pl_pool_id, 0, 0); \ + get_pool_uuid((char*)&(id)[1], \ + (pd)->pl_pool_id, 0, 0); \ + } while(0) + +struct pool_disk; +struct pool_list; +struct user_subpool; +struct user_device; + +/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */ + +/* Generic Labels */ +#define SPTYPE_DATA (0x00000000) + +/* GFS specific labels */ +#define SPTYPE_GFS_DATA (0x68011670) +#define SPTYPE_GFS_JOURNAL (0x69011670) + +struct sptype_name { + const char *name; + uint32_t label; +}; + +static const struct sptype_name sptype_names[] = { + {"data", SPTYPE_DATA}, + + {"gfs_data", SPTYPE_GFS_DATA}, + {"gfs_journal", SPTYPE_GFS_JOURNAL}, + + {"", 0x0} /* This must be the last flag. */ +}; + +struct pool_disk { + uint64_t pl_magic; /* Pool magic number */ + uint64_t pl_pool_id; /* Unique pool identifier */ + char pl_pool_name[POOL_NAME_SIZE]; /* Name of pool */ + uint32_t pl_version; /* Pool version */ + uint32_t pl_subpools; /* Number of subpools in this pool */ + uint32_t pl_sp_id; /* Subpool number within pool */ + uint32_t pl_sp_devs; /* Number of data partitions in this subpool */ + uint32_t pl_sp_devid; /* Partition number within subpool */ + uint32_t pl_sp_type; /* Partition type */ + uint64_t pl_blocks; /* Number of blocks in this partition */ + uint32_t pl_striping; /* Striping size within subpool */ + /* + * If the number of DMEP devices is zero, then the next field ** + * ** (pl_sp_dmepid) becomes the subpool ID for redirection. In ** + * ** other words, if this subpool does not have the capability ** + * ** to do DMEP, then it must specify which subpool will do it ** + * ** in it's place + */ + + /* + * While the next 3 field are no longer used, they must stay to keep ** + * ** backward compatibility........................................... + */ + uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */ + uint32_t pl_sp_dmepid; /* Dmep device number within subpool */ + uint32_t pl_sp_weight; /* if dmep dev, pref to using it */ + + uint32_t pl_minor; /* the pool minor number */ + uint32_t pl_padding; /* reminder - think about alignment */ + + /* + * Even though we're zeroing out 8k at the front of the disk before + * writing the label, putting this in + */ + char pl_reserve[184]; /* bump the structure size out to 512 bytes */ +}; + +struct pool_list { + struct list list; + struct pool_disk pd; + struct physical_volume *pv; + struct id pv_uuid; + struct device *dev; +}; + +struct user_subpool { + uint32_t initialized; + uint32_t id; + uint32_t striping; + uint32_t num_devs; + uint32_t type; + uint32_t dummy; + struct user_device *devs; +}; + +struct user_device { + uint32_t initialized; + uint32_t sp_id; + uint32_t devid; + uint32_t dummy; + uint64_t blocks; + struct physical_volume *pv; +}; + +int read_pool_label(struct pool_list *pl, struct labeller *l, + struct device *dev, char *buf, struct label **label); +void pool_label_out(struct pool_disk *pl, char *buf); +void pool_label_in(struct pool_disk *pl, char *buf); +void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid); +int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls); +int import_pool_lvs(struct volume_group *vg, struct pool *mem, + struct list *pls); +int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, + struct list *pvs, struct pool *mem, struct list *pls); +int import_pool_pv(const struct format_type *fmt, struct pool *mem, + struct volume_group *vg, struct physical_volume *pv, + struct pool_list *pl); +int import_pool_segments(struct list *lvs, struct pool *mem, + struct user_subpool *usp, int sp_count); +int read_pool_pds(const struct format_type *fmt, const char *vgname, + struct pool *mem, struct list *head); +struct pool_list *read_pool_disk(const struct format_type *fmt, + struct device *dev, struct pool *mem, + const char *vg_name); + +#endif /* DISK_REP_POOL_FORMAT_H */ diff --git a/lib/format_pool/format_pool.c b/lib/format_pool/format_pool.c new file mode 100644 index 000000000..b11d409b6 --- /dev/null +++ b/lib/format_pool/format_pool.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 1997-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 "label.h" +#include "metadata.h" +#include "hash.h" +#include "limits.h" +#include "list.h" +#include "display.h" +#include "toolcontext.h" +#include "lvmcache.h" +#include "disk_rep.h" +#include "format_pool.h" +#include "pool_label.h" + +#define FMT_POOL_NAME "pool" + +/* Must be called after pvs are imported */ +static struct user_subpool *_build_usp(struct list *pls, struct pool *mem, + int *sps) +{ + + struct list *plhs; + struct pool_list *pl; + struct user_subpool *usp = NULL, *cur_sp = NULL; + struct user_device *cur_dev = NULL; + + /* + * FIXME: Need to do some checks here - I'm tempted to add a + * user_pool structure and build the entire thing to check against. + */ + list_iterate(plhs, pls) { + pl = list_item(plhs, struct pool_list); + + *sps = pl->pd.pl_subpools; + if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) { + log_error("Unable to allocate %d subpool structures", + *sps); + return 0; + } + + if (cur_sp != &usp[pl->pd.pl_sp_id]) { + cur_sp = &usp[pl->pd.pl_sp_id]; + + cur_sp->id = pl->pd.pl_sp_id; + cur_sp->striping = pl->pd.pl_striping; + cur_sp->num_devs = pl->pd.pl_sp_devs; + cur_sp->type = pl->pd.pl_sp_type; + cur_sp->initialized = 1; + } + + if (!cur_sp->devs && + (!(cur_sp->devs = + pool_zalloc(mem, + sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) { + + log_error("Unable to allocate %d pool_device " + "structures", pl->pd.pl_sp_devs); + return 0; + } + cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid]; + cur_dev->sp_id = cur_sp->id; + cur_dev->devid = pl->pd.pl_sp_id; + cur_dev->blocks = pl->pd.pl_blocks; + cur_dev->pv = pl->pv; + cur_dev->initialized = 1; + + } + + return usp; +} + +static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count) +{ + int i, j; + + for (i = 0; i < sp_count; i++) { + if (!usp[i].initialized) { + log_error("Missing subpool %d in pool %s", i, vgname); + return 0; + } + for (j = 0; j < usp[i].num_devs; j++) { + if (!usp[i].devs[j].initialized) { + log_error("Missing device %d for subpool %d" + " in pool %s", j, i, vgname); + return 0; + } + + } + } + + return 1; +} + +static struct volume_group *_build_vg_from_pds(struct format_instance + *fid, struct pool *mem, + struct list *pds) +{ + struct pool *smem = fid->fmt->cmd->mem; + struct volume_group *vg = NULL; + struct user_subpool *usp = NULL; + int sp_count; + + if (!(vg = pool_zalloc(smem, sizeof(*vg)))) { + log_error("Unable to allocate volume group structure"); + return NULL; + } + + vg->cmd = fid->fmt->cmd; + vg->fid = fid; + vg->name = NULL; + vg->status = 0; + vg->extent_count = 0; + vg->pv_count = 0; + vg->lv_count = 0; + vg->snapshot_count = 0; + vg->seqno = 1; + vg->system_id = NULL; + list_init(&vg->pvs); + list_init(&vg->lvs); + list_init(&vg->snapshots); + list_init(&vg->tags); + + if (!import_pool_vg(vg, smem, pds)) { + stack; + return NULL; + } + + if (!import_pool_pvs(fid->fmt, vg, &vg->pvs, smem, pds)) { + stack; + return NULL; + } + + if (!import_pool_lvs(vg, smem, pds)) { + stack; + return NULL; + } + + /* + * I need an intermediate subpool structure that contains all the + * relevant info for this. Then i can iterate through the subpool + * structures for checking, and create the segments + */ + if (!(usp = _build_usp(pds, mem, &sp_count))) { + stack; + return NULL; + } + + /* + * check the subpool structures - we can't handle partial VGs in + * the pool format, so this will error out if we're missing PVs + */ + if (!_check_usp(vg->name, usp, sp_count)) { + stack; + return NULL; + } + + if (!import_pool_segments(&vg->lvs, smem, usp, sp_count)) { + stack; + return NULL; + } + + return vg; +} + +static struct volume_group *_vg_read(struct format_instance *fid, + const char *vg_name, + struct metadata_area *mda) +{ + struct pool *mem = pool_create(1024); + struct list pds; + struct volume_group *vg = NULL; + + list_init(&pds); + + /* We can safely ignore the mda passed in */ + + if (!mem) { + stack; + return NULL; + } + + /* Strip dev_dir if present */ + vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir); + + /* Read all the pvs in the vg */ + if (!read_pool_pds(fid->fmt, vg_name, mem, &pds)) { + stack; + goto out; + } + + /* Do the rest of the vg stuff */ + if (!(vg = _build_vg_from_pds(fid, mem, &pds))) { + stack; + goto out; + } + + out: + pool_destroy(mem); + return vg; +} + +static int _pv_setup(const struct format_type *fmt, + uint64_t pe_start, uint32_t extent_count, + uint32_t extent_size, + int pvmetadatacopies, + uint64_t pvmetadatasize, struct list *mdas, + struct physical_volume *pv, struct volume_group *vg) +{ + return 1; +} + +static int _pv_read(const struct format_type *fmt, const char *pv_name, + struct physical_volume *pv, struct list *mdas) +{ + struct pool *mem = pool_create(1024); + struct pool_list *pl; + struct device *dev; + int r = 0; + + log_very_verbose("Reading physical volume data %s from disk", pv_name); + + if (!mem) { + stack; + return 0; + } + + if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) { + stack; + goto out; + } + + /* + * I need to read the disk and populate a pv structure here + * I'll probably need to abstract some of this later for the + * vg_read code + */ + if (!(pl = read_pool_disk(fmt, dev, mem, NULL))) { + stack; + goto out; + } + + if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl)) { + stack; + goto out; + } + + pv->fmt = fmt; + + r = 1; + + out: + pool_destroy(mem); + return r; +} + +/* *INDENT-OFF* */ +static struct metadata_area_ops _metadata_format_pool_ops = { + vg_read:_vg_read, +}; +/* *INDENT-ON* */ + +static struct format_instance *_create_instance(const struct format_type *fmt, + const char *vgname, + void *private) +{ + struct format_instance *fid; + struct metadata_area *mda; + + if (!(fid = pool_zalloc(fmt->cmd->mem, sizeof(*fid)))) { + log_error("Unable to allocate format instance structure for " + "pool format"); + return NULL; + } + + fid->fmt = fmt; + list_init(&fid->metadata_areas); + + /* Define a NULL metadata area */ + if (!(mda = pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) { + log_error("Unable to allocate metadata area structure " + "for pool format"); + pool_free(fmt->cmd->mem, fid); + return NULL; + } + + mda->ops = &_metadata_format_pool_ops; + mda->metadata_locn = NULL; + list_add(&fid->metadata_areas, &mda->list); + + return fid; +} + +static void _destroy_instance(struct format_instance *fid) +{ + return; +} + +static void _destroy(const struct format_type *fmt) +{ + dbg_free((void *) fmt); +} + +/* *INDENT-OFF* */ +static struct format_handler _format_pool_ops = { + pv_read:_pv_read, + pv_setup:_pv_setup, + create_instance:_create_instance, + destroy_instance:_destroy_instance, + destroy:_destroy, +}; +/* *INDENT-ON */ + +#ifdef POOL_INTERNAL +struct format_type *init_pool_format(struct cmd_context *cmd) +#else /* Shared */ +struct format_type *init_format(struct cmd_context *cmd); +struct format_type *init_format(struct cmd_context *cmd) +#endif +{ + struct format_type *fmt = dbg_malloc(sizeof(*fmt)); + + if (!fmt) { + log_error("Unable to allocate format type structure for pool " + "format"); + return NULL; + } + + fmt->cmd = cmd; + fmt->ops = &_format_pool_ops; + fmt->name = FMT_POOL_NAME; + fmt->alias = NULL; + fmt->features = 0; + fmt->private = NULL; + + if (!(fmt->labeller = pool_labeller_create(fmt))) { + log_error("Couldn't create pool label handler."); + return NULL; + } + + if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) { + log_error("Couldn't register pool label handler."); + return NULL; + } + + return fmt; +} diff --git a/lib/format_pool/format_pool.h b/lib/format_pool/format_pool.h new file mode 100644 index 000000000..61472c7ec --- /dev/null +++ b/lib/format_pool/format_pool.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_FORMAT_POOL_H +#define _LVM_FORMAT_POOL_H + +#include "metadata.h" + +#ifdef POOL_INTERNAL +struct format_type *init_pool_format(struct cmd_context *cmd); +#endif + +#endif diff --git a/lib/format_pool/import_export.c b/lib/format_pool/import_export.c new file mode 100644 index 000000000..617521287 --- /dev/null +++ b/lib/format_pool/import_export.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 1997-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 "label.h" +#include "metadata.h" +#include "lvmcache.h" +#include "disk_rep.h" +#include "lv_alloc.h" +#include "str_list.h" +#include "display.h" +#include "segtypes.h" + +/* This file contains only imports at the moment... */ + +int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls) +{ + struct list *plhs; + struct pool_list *pl; + + list_iterate(plhs, pls) { + pl = list_item(plhs, struct pool_list); + + vg->extent_count += + ((pl->pd.pl_blocks) / POOL_PE_SIZE); + + vg->pv_count++; + + if (vg->name) + continue; + + vg->name = pool_strdup(mem, pl->pd.pl_pool_name); + get_pool_vg_uuid(&vg->id, &pl->pd); + vg->extent_size = POOL_PE_SIZE; + vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED; + vg->free_count = 0; + vg->max_lv = 1; + vg->max_pv = POOL_MAX_DEVICES; + vg->alloc = ALLOC_NORMAL; + vg->lv_count = 0; + } + + return 1; +} + +int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls) +{ + struct pool_list *pl; + struct list *plhs; + struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl)); + struct logical_volume *lv; + + if (!lvl) { + log_error("Unable to allocate lv list structure"); + return 0; + } + + if (!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) { + log_error("Unable to allocate logical volume structure"); + return 0; + } + + lv = lvl->lv; + lv->status = 0; + lv->vg = vg; + lv->alloc = ALLOC_NORMAL; + lv->size = 0; + lv->name = NULL; + lv->le_count = 0; + lv->read_ahead = 0; + list_init(&lv->segments); + list_init(&lv->tags); + + list_iterate(plhs, pls) { + pl = list_item(plhs, struct pool_list); + + lv->size += pl->pd.pl_blocks; + + if (lv->name) + continue; + + if (!(lv->name = pool_strdup(mem, pl->pd.pl_pool_name))) { + stack; + return 0; + } + + get_pool_lv_uuid(lv->lvid.id, &pl->pd); + log_debug("Calculated lv uuid for lv %s: %s", lv->name, + lv->lvid.s); + + lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE; + lv->major = POOL_MAJOR; + + /* for pool a minor of 0 is dynamic */ + if (pl->pd.pl_minor) { + lv->status |= FIXED_MINOR; + lv->minor = pl->pd.pl_minor; + } else { + lv->minor = -1; + } + list_init(&lv->segments); + list_init(&lv->tags); + } + + lv->le_count = lv->size / POOL_PE_SIZE; + lvl->lv = lv; + list_add(&vg->lvs, &lvl->list); + vg->lv_count++; + + return 1; +} + +int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, + struct list *pvs, struct pool *mem, struct list *pls) +{ + struct pv_list *pvl; + struct pool_list *pl; + struct list *plhs; + + list_iterate(plhs, pls) { + pl = list_item(plhs, struct pool_list); + + if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) { + log_error("Unable to allocate pv list structure"); + return 0; + } + if (!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) { + log_error("Unable to allocate pv structure"); + return 0; + } + if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) { + return 0; + } + pl->pv = pvl->pv; + pvl->mdas = NULL; + pvl->alloc_areas = NULL; + list_add(pvs, &pvl->list); + } + + return 1; +} + +int import_pool_pv(const struct format_type *fmt, struct pool *mem, + struct volume_group *vg, struct physical_volume *pv, + struct pool_list *pl) +{ + struct pool_disk *pd = &pl->pd; + + memset(pv, 0, sizeof(*pv)); + + get_pool_pv_uuid(&pv->id, pd); + pv->fmt = fmt; + + pv->dev = pl->dev; + if (!(pv->vg_name = pool_strdup(mem, pd->pl_pool_name))) { + log_error("Unable to duplicate vg_name string"); + return 0; + } + pv->status = 0; + pv->size = pd->pl_blocks; + pv->pe_size = POOL_PE_SIZE; + pv->pe_start = POOL_PE_START; + pv->pe_count = pv->size / POOL_PE_SIZE; + pv->pe_alloc_count = pv->pe_count; + + list_init(&pv->tags); + + return 1; +} + +static const char *_cvt_sptype(uint32_t sptype) +{ + int i; + for (i = 0; sptype_names[i].name[0]; i++) { + if (sptype == sptype_names[i].label) { + break; + } + } + log_debug("Found sptype %X and converted it to %s", + sptype, sptype_names[i].name); + return sptype_names[i].name; +} + +static int _add_stripe_seg(struct pool *mem, + struct user_subpool *usp, struct logical_volume *lv, + uint32_t *le_cur) +{ + struct lv_segment *seg; + int j; + + if (!(seg = alloc_lv_segment(mem, usp->num_devs))) { + log_error("Unable to allocate striped lv_segment structure"); + return 0; + } + if(usp->striping & (usp->striping - 1)) { + log_error("Stripe size must be a power of 2"); + return 0; + } + seg->stripe_size = usp->striping; + seg->status |= 0; + seg->le += *le_cur; + + /* add the subpool type to the segment tag list */ + str_list_add(mem, &seg->tags, _cvt_sptype(usp->type)); + + for (j = 0; j < usp->num_devs; j++) { + if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, + "striped"))) { + stack; + return 0; + } + + seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; + seg->len += seg->area_len; + *le_cur += seg->area_len; + seg->lv = lv; + + seg->area[j].type = AREA_PV; + seg->area[j].u.pv.pv = usp->devs[j].pv; + seg->area[j].u.pv.pe = 0; + } + list_add(&lv->segments, &seg->list); + return 1; +} + +static int _add_linear_seg(struct pool *mem, + struct user_subpool *usp, struct logical_volume *lv, + uint32_t *le_cur) +{ + struct lv_segment *seg; + int j; + + for (j = 0; j < usp->num_devs; j++) { + /* linear segments only have 1 data area */ + if (!(seg = alloc_lv_segment(mem, 1))) { + log_error("Unable to allocate linear lv_segment " + "structure"); + return 0; + } + seg->stripe_size = usp->striping; + seg->le += *le_cur; + seg->chunk_size = POOL_PE_SIZE; + seg->status |= 0; + if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, + "striped"))) { + stack; + return 0; + } + /* add the subpool type to the segment tag list */ + str_list_add(mem, &seg->tags, _cvt_sptype(usp->type)); + + seg->lv = lv; + + seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; + seg->len = seg->area_len; + *le_cur += seg->len; + seg->area[0].type = AREA_PV; + seg->area[0].u.pv.pv = usp->devs[j].pv; + seg->area[0].u.pv.pe = 0; + list_add(&lv->segments, &seg->list); + } + return 1; +} + +int import_pool_segments(struct list *lvs, struct pool *mem, + struct user_subpool *usp, int subpools) +{ + + struct list *lvhs; + struct lv_list *lvl; + struct logical_volume *lv; + uint32_t le_cur = 0; + int i; + + list_iterate(lvhs, lvs) { + lvl = list_item(lvhs, struct lv_list); + + lv = lvl->lv; + for (i = 0; i < subpools; i++) { + if (usp[i].striping) { + if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) { + stack; + return 0; + } + } else { + if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) { + stack; + return 0; + } + } + } + } + + return 1; + +} diff --git a/lib/format_pool/pool_label.c b/lib/format_pool/pool_label.c new file mode 100644 index 000000000..adc8c4cd3 --- /dev/null +++ b/lib/format_pool/pool_label.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 1997-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 "label.h" +#include "metadata.h" +#include "xlate.h" +#include "disk_rep.h" +#include "pool_label.h" + +#include +#include + +static void _not_supported(const char *op) +{ + log_error("The '%s' operation is not supported for the pool labeller.", + op); +} + +static int _can_handle(struct labeller *l, char *buf, uint64_t sector) +{ + + struct pool_disk pd; + + /* + * POOL label must always be in first sector + */ + if (sector) + return 0; + + pool_label_in(&pd, buf); + + /* can ignore 8 rightmost bits for ondisk format check */ + if ((pd.pl_magic == POOL_MAGIC) && + (pd.pl_version >> 8 == POOL_VERSION >> 8)) + return 1; + + return 0; +} + +static int _write(struct label *label, char *buf) +{ + _not_supported("write"); + return 0; +} + +static int _read(struct labeller *l, struct device *dev, char *buf, + struct label **label) +{ + struct pool_list pl; + + return read_pool_label(&pl, l, dev, buf, label); +} + +static int _initialise_label(struct labeller *l, struct label *label) +{ + strcpy(label->type, "POOL"); + + return 1; +} + +static void _destroy_label(struct labeller *l, struct label *label) +{ + return; +} + +static void _destroy(struct labeller *l) +{ + dbg_free(l); +} + +struct label_ops _pool_ops = { + can_handle:_can_handle, + write:_write, + read:_read, + verify:_can_handle, + initialise_label:_initialise_label, + destroy_label:_destroy_label, + destroy:_destroy +}; + +struct labeller *pool_labeller_create(struct format_type *fmt) +{ + struct labeller *l; + + if (!(l = dbg_malloc(sizeof(*l)))) { + log_error("Couldn't allocate labeller object."); + return NULL; + } + + l->ops = &_pool_ops; + l->private = (const void *) fmt; + + return l; +} diff --git a/lib/format_pool/pool_label.h b/lib/format_pool/pool_label.h new file mode 100644 index 000000000..3d86502b2 --- /dev/null +++ b/lib/format_pool/pool_label.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 1997-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_POOL_LABEL_H +#define _LVM_POOL_LABEL_H + +#include "metadata.h" + +struct labeller *pool_labeller_create(struct format_type *fmt); + +#endif -- 2.43.5