]> sourceware.org Git - lvm2.git/commitdiff
Add sparse devices: lvcreate -s --virtualoriginsize (hidden zero origin).
authorAlasdair Kergon <agk@redhat.com>
Sat, 25 Apr 2009 01:17:59 +0000 (01:17 +0000)
committerAlasdair Kergon <agk@redhat.com>
Sat, 25 Apr 2009 01:17:59 +0000 (01:17 +0000)
Add lvs origin_size field.
Fix linux configure --enable-debug to exclude -O2.

Still a few rough edges, but hopefully usable now:
  lvcreate -s vg1 -L 100M --virtualoriginsize 1T

15 files changed:
WHATS_NEW
lib/format_text/flags.c
lib/metadata/metadata-exported.h
lib/metadata/metadata.h
lib/metadata/snapshot_manip.c
lib/report/columns.h
lib/report/report.c
man/lvcreate.8.in
man/lvs.8.in
tools/args.h
tools/commands.h
tools/lvchange.c
tools/lvcreate.c
tools/lvremove.c
tools/toollib.c

index 8ddd4305074a3265e55df2cf0ad874244c730398..6d51ab0d03a55a8ed70a2f1b6b097f9a0d746cce 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,8 @@
 Version 2.02.46 - 
 ================================
+  Add sparse devices: lvcreate -s --virtualoriginsize (hidden zero origin).
+  Add lvs origin_size field.
+  Fix linux configure --enable-debug to exclude -O2.
   Implement lvconvert --repair, for repairing partially failed mirrors.
   Fix vgreduce --removemissing failure exit code.
   Fix remote metadata backup for clvmd.
index eb281b6b1fa3335ba9b3d254902a8d7261ea022c..46bb95d2b66923edbc0ceaa3139331a2bb69eee9 100644 (file)
@@ -65,6 +65,7 @@ static struct flag _lv_flags[] = {
        {CONVERTING, NULL, 0},
        {PARTIAL_LV, NULL, 0},
        {POSTORDER_FLAG, NULL, 0},
+       {VIRTUAL_ORIGIN, NULL, 0},
        {0, NULL, 0}
 };
 
index c95f7444cf5d4772ac51f47025a15e7e3bf50c34..3b13e378c9724ac9b39eea414412d87049b35a94 100644 (file)
@@ -77,6 +77,7 @@ struct pv_segment;
 
 //#define POSTORDER_FLAG       0x02000000U /* Not real flags, reserved for
 //#define POSTORDER_OPEN_FLAG  0x04000000U    temporary use inside vg_read_internal. */
+//#define VIRTUAL_ORIGIN       0x08000000U     /* LV - internal use only */
 
 #define LVM_READ               0x00000100U     /* LV VG */
 #define LVM_WRITE              0x00000200U     /* LV VG */
@@ -531,6 +532,7 @@ struct lv_segment *first_seg(const struct logical_volume *lv);
 * Useful functions for managing snapshots.
 */
 int lv_is_origin(const struct logical_volume *lv);
+int lv_is_virtual_origin(const struct logical_volume *lv);
 int lv_is_cow(const struct logical_volume *lv);
 int lv_is_visible(const struct logical_volume *lv);
 
index 843e0bf185a6a25e31110bb375ee3eb11e98a5ec..eff2380c273d7a2c3f4d305923752f1aac198dc5 100644 (file)
@@ -81,6 +81,7 @@
 
 #define POSTORDER_FLAG         0x02000000U /* Not real flags, reserved for  */
 #define POSTORDER_OPEN_FLAG    0x04000000U /* temporary use inside vg_read_internal. */
+#define VIRTUAL_ORIGIN         0x08000000U     /* LV - internal use only */
 
 //#define LVM_READ                     0x00000100U     /* LV VG */
 //#define LVM_WRITE                    0x00000200U     /* LV VG */
index 39553820564c131849152537b5f6d789b7c296b2..1189dbdb3f313f060cd1de0a1d34805b069ddd14 100644 (file)
@@ -44,6 +44,12 @@ int lv_is_displayable(const struct logical_volume *lv)
        return (lv->status & VISIBLE_LV) || lv_is_cow(lv) ? 1 : 0;
 }
 
+int lv_is_virtual_origin(const struct logical_volume *lv)
+{
+       return (lv->status & VIRTUAL_ORIGIN) ? 1 : 0;
+}
+
+
 /* Given a cow LV, return the snapshot lv_segment that uses it */
 struct lv_segment *find_cow(const struct logical_volume *lv)
 {
@@ -105,6 +111,10 @@ int vg_add_snapshot(const char *name, struct logical_volume *origin,
 
        cow->status &= ~VISIBLE_LV;
 
+        /* FIXME Assumes an invisible origin belongs to a sparse device */
+        if (!lv_is_visible(origin))
+                origin->status |= VIRTUAL_ORIGIN;
+
        dm_list_add(&origin->snapshot_segs, &seg->origin_list);
 
        return 1;
index 90f8592ea2087afa4b49423f8973b79f20fd8435..707347bbdbc86d85a39c398061d162e9237638e0 100644 (file)
@@ -53,7 +53,7 @@
  */
 
 /* *INDENT-OFF* */
-FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid", "Unique identifier")
+FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid", "Unique identifier.")
 FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name", "Name.  LVs created for internal use are enclosed in brackets.")
 FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr", "Various attributes - see man page.")
 FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major", "Persistent major number or -1 if not persistent.")
@@ -64,11 +64,12 @@ FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor", "Currently assig
 FIELD(LVS, lv, NUM, "KRahead", lvid, 7, lvkreadahead, "lv_kernel_read_ahead", "Currently-in-use read ahead setting in current units.")
 FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size", "Size of LV in current units.")
 FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count", "Number of segments in LV.")
-FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV")
+FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV.")
+FIELD(LVS, lv, NUM, "OSize", lvid, 5, originsize, "origin_size", "For snapshots, the size of the origin device of this LV.")
 FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent", "For snapshots, the percentage full if LV is active.")
 FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent", "For mirrors and pvmove, current percentage in-sync.")
-FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove")
-FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, "convert_lv", "For lvconvert, Name of temporary LV created by lvconvert")
+FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove.")
+FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, "convert_lv", "For lvconvert, Name of temporary LV created by lvconvert.")
 FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
 FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
 FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
@@ -111,7 +112,7 @@ FIELD(VGS, vg, NUM, "#VMda", cmd, 5, vgmdas, "vg_mda_count", "Number of metadata
 FIELD(VGS, vg, NUM, "VMdaFree", cmd, 9, vgmdafree, "vg_mda_free", "Free metadata area space for this VG in current units.")
 FIELD(VGS, vg, NUM, "VMdaSize", cmd, 9, vgmdasize, "vg_mda_size", "Size of smallest metadata area for this VG in current units.")
 
-FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype", "Type of LV segment")
+FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype", "Type of LV segment.")
 FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes", "Number of stripes or mirror legs.")
 FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize", "For stripes, amount of data placed on one device before switching to the next.")
 FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size", "For stripes, amount of data placed on one device before switching to the next.")
index f603eeb7921e1870934ee8804b9b68eaebbd4203..91e2b98ac897b0de62bc419d7d1552ce96361310 100644 (file)
@@ -471,20 +471,6 @@ static int _segtype_disp(struct dm_report *rh __attribute((unused)),
        return 1;
 }
 
-static int _origin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
-                       struct dm_report_field *field,
-                       const void *data, void *private __attribute((unused)))
-{
-       const struct logical_volume *lv = (const struct logical_volume *) data;
-
-       if (lv_is_cow(lv))
-               return dm_report_field_string(rh, field,
-                                             (const char **) &origin_from_cow(lv)->name);
-
-       dm_report_field_set_value(field, "", NULL);
-       return 1;
-}
-
 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
                       struct dm_report_field *field,
                       const void *data, void *private __attribute((unused)))
@@ -537,6 +523,19 @@ static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
        return 1;
 }
 
+static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
+                       struct dm_report_field *field,
+                       const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+
+       if (lv_is_cow(lv))
+               return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
+
+       dm_report_field_set_value(field, "", NULL);
+       return 1;
+}
+
 static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
                        struct dm_report_field *field,
                        const void *data, void *private __attribute((unused)))
@@ -723,7 +722,24 @@ static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
        if (lv_is_cow(seg->lv))
                size = (uint64_t) find_cow(seg->lv)->chunk_size;
        else
-               size = 0;
+               size = UINT64_C(0);
+
+       return _size64_disp(rh, mem, field, &size, private);
+}
+
+static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
+                           struct dm_report_field *field,
+                           const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+       uint64_t size;
+
+       if (lv_is_cow(lv))
+               size = (uint64_t) find_cow(lv)->len * lv->vg->extent_size;
+       else if (lv_is_origin(lv))
+               size = lv->size;
+       else
+               size = UINT64_C(0);
 
        return _size64_disp(rh, mem, field, &size, private);
 }
index 2a9f7ea572c63b2c4bb3a9c64679ee26f5899065..d01cb2c94edd8ba126ad049f484f835e3ad25e26 100644 (file)
@@ -25,7 +25,9 @@ VolumeGroupName [PhysicalVolumePath...]
 {\-l|\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
  \-L|\-\-size LogicalVolumeSize[kKmMgGtT]}
 [\-c|\-\-chunksize ChunkSize]
-\-s|\-\-snapshot \-n|\-\-name SnapshotLogicalVolumeName OriginalLogicalVolumePath
+\-n|\-\-name SnapshotLogicalVolumeName 
+\-s|\-\-snapshot
+[OriginalLogicalVolumePath | VolumeGroupName \-\-virtualoriginsize VirtualOriginSize]
 .SH DESCRIPTION
 lvcreate creates a new logical volume in a volume group ( see
 .B vgcreate(8), vgchange(8)
@@ -144,6 +146,19 @@ to grow it. Shrinking a snapshot is supported by
 as well. Run
 .B lvdisplay(8)
 on the snapshot in order to check how much data is allocated to it.
+Note that a small amount of the space you allocate to the snapshot is
+used to track the locations of the chunks of data, so you should 
+allocate slightly more space than you actually need and monitor the
+rate at which the snapshot data is growing so you can avoid running out
+of space.
+.TP
+.I \-\-virtualoriginsize VirtualOriginSize
+In conjunction with \-\-snapshot, create a sparse device of the given size
+(in MB by default).  Anything written to the device will be returned when
+reading from it.  Reading from other areas of the device will return
+blocks of zeros.  It is implemented by creating a hidden virtual device of the
+requested size using the zero target.  A suffix of _vorigin is used for
+this device.
 .TP
 .I \-Z, \-\-zero y|n
 Controls zeroing of the first KB of data in the new logical volume.
@@ -180,6 +195,11 @@ contains a file system, you can mount the snapshot logical volume on an
 arbitrary directory in order to access the contents of the filesystem to run
 a backup while the original filesystem continues to get updated.
 
+"lvcreate --virtualoriginsize 1T --size 100M --snapshot --name sparse vg1"
+.br
+creates a sparse device named /dev/vg1/sparse of size 1TB with space for just
+under 100MB of actual data on it.
+
 .SH SEE ALSO
 .BR lvm (8), 
 .BR vgcreate (8), 
index c6b11607552521b245594d7930332324ab6a9adb..a053e2cea24821439f9b06cd3c1fbaa72fd362bc 100644 (file)
@@ -39,7 +39,7 @@ Comma-separated ordered list of columns.  Precede the list with '+' to append
 to the default selection of columns instead of replacing it.  Column names are: 
 lv_uuid, lv_name, lv_attr, lv_major, lv_minor, lv_kernel_major, lv_kernel_minor,
 lv_size, seg_count, origin, snap_percent,
-copy_percent, move_pv, lv_tags,
+copy_percent, move_pv, lv_tags, origin_size,
 segtype, stripes,
 stripesize, chunksize, seg_start, seg_size, seg_tags, devices,
 regionsize, mirror_log, modules.
index 90952598cb02ba7d1405fa97e265a40460150266..c3f233200cf5026da9100d3aab1ab3b7901027d4 100644 (file)
@@ -58,6 +58,7 @@ arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0)
 arg(unquoted_ARG, '\0', "unquoted", NULL, 0)
 arg(rows_ARG, '\0', "rows", NULL, 0)
 arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0)
+arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
 
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
index fa3b98c4a2ca4c1aa54ad21f68b4e5fbb0ef8f99..18495288834331a3c1a6b381b2206ae70c7647ca 100644 (file)
@@ -163,13 +163,15 @@ xx(lvcreate,
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]\n"
-   "\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
+   "\t[OriginalLogicalVolume[Path] |\n"
+   "\t VolumeGroupName[Path] --virtualoriginsize VirtualOriginSize]]\n"
+   "\t[PhysicalVolumePath...]\n\n",
 
    addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
    corelog_ARG, extents_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
    name_ARG, nosync_ARG, permission_ARG, persistent_ARG, readahead_ARG,
    regionsize_ARG, size_ARG, snapshot_ARG, stripes_ARG, stripesize_ARG,
-   test_ARG, type_ARG, zero_ARG)
+   test_ARG, type_ARG, virtualoriginsize_ARG, zero_ARG)
 
 xx(lvdisplay,
    "Display information about a logical volume",
index fb60f6bdd2b90170f85d3abcaedccff29b7aeafa..2696a95b3bf2895fbfb673f42b7c7c9d3da583cb 100644 (file)
@@ -559,7 +559,8 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                return ECMD_FAILED;
        }
 
-       if (lv_is_cow(lv)) {
+       if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv)) &&
+           arg_count(cmd, available_ARG)) {
                log_error("Can't change snapshot logical volume \"%s\"",
                          lv->name);
                return ECMD_FAILED;
index 78dc6b3a532fd3f6f7ad83bcd6f628eba2d5fd86..8975470aa853e899a5be91210f646f9fe26b0688 100644 (file)
@@ -43,6 +43,8 @@ struct lvcreate_params {
        /* size */
        uint32_t extents;
        uint64_t size;
+       uint32_t voriginextents;
+       uint64_t voriginsize;
        percent_t percent;
 
        uint32_t permission;
@@ -64,7 +66,7 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
        if (arg_count(cmd, name_ARG))
                lp->lv_name = arg_value(cmd, name_ARG);
 
-       if (lp->snapshot) {
+       if (lp->snapshot && !arg_count(cmd, virtualoriginsize_ARG)) {
                if (!argc) {
                        log_err("Please specify a logical volume to act as "
                                "the snapshot origin.");
@@ -175,6 +177,20 @@ static int _read_size_params(struct lvcreate_params *lp,
                lp->percent = PERCENT_NONE;
        }
 
+       /* Size returned in kilobyte units; held in sectors */
+       if (arg_count(cmd, virtualoriginsize_ARG)) {
+               if (arg_sign_value(cmd, virtualoriginsize_ARG, 0) == SIGN_MINUS) {
+                       log_error("Negative virtual origin size is invalid");
+                       return 0;
+               }
+               lp->voriginsize = arg_uint64_value(cmd, virtualoriginsize_ARG,
+                                                  UINT64_C(0));
+               if (!lp->voriginsize) {
+                       log_error("Virtual origin size may not be zero");
+                       return 0;
+               }
+       }
+
        return 1;
 }
 
@@ -390,6 +406,10 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
                        log_error("-c is only available with snapshots");
                        return 0;
                }
+               if (arg_count(cmd, virtualoriginsize_ARG)) {
+                       log_error("--virtualoriginsize is only available with snapshots");
+                       return 0;
+               }
        }
 
        if (lp->mirrors > 1) {
@@ -511,12 +531,73 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
        return 1;
 }
 
+static uint64_t _extents_from_size(struct cmd_context *cmd, uint64_t size,
+                                  uint32_t extent_size)
+{
+       if (size % extent_size) {
+               size += extent_size - size % extent_size;
+               log_print("Rounding up size to full physical extent %s",
+                         display_size(cmd, size));
+       }
+
+       if (size > (uint64_t) UINT32_MAX * extent_size) {
+               log_error("Volume too large (%s) for extent size %s. "
+                         "Upper limit is %s.",
+                         display_size(cmd, size),
+                         display_size(cmd, (uint64_t) extent_size),
+                         display_size(cmd, (uint64_t) UINT32_MAX *
+                                      extent_size));
+               return 0;
+       }
+
+       return (uint64_t) size / extent_size;
+}
+
+static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
+                                                    struct volume_group *vg,
+                                                    const char *lv_name,
+                                                    uint32_t permission,
+                                                    uint64_t voriginextents)
+{
+       const struct segment_type *segtype;
+       size_t len;
+       char *vorigin_name;
+       struct logical_volume *lv;
+       
+       if (!(segtype = get_segtype_from_string(cmd, "zero"))) {
+               log_error("Zero segment type for virtual origin not found");
+               return 0;
+       }
+
+       len = strlen(lv_name) + 32;
+       if (!(vorigin_name = alloca(len)) ||
+           dm_snprintf(vorigin_name, len, "%s_vorigin", lv_name) < 0) {
+               log_error("Virtual origin name allocation failed.");
+               return 0;
+       }
+
+       if (!(lv = lv_create_empty(vorigin_name, NULL, permission,
+                                  ALLOC_INHERIT, 0, vg)))
+               return_0;
+
+       if (!lv_extend(lv, segtype, 1, 0, 1, voriginextents, NULL, 0u, 0u,
+                      NULL, ALLOC_INHERIT))
+               return_0;
+
+       /* store vg on disk(s) */
+       if (!vg_write(vg) || !vg_commit(vg))
+               return_0;
+
+       backup(vg);
+
+       return lv;
+}
+
 static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
                     struct lvcreate_params *lp)
 {
        uint32_t size_rest;
        uint32_t status = 0;
-       uint64_t tmp_size;
        struct logical_volume *lv, *org = NULL;
        struct dm_list *pvh;
        const char *tag = NULL;
@@ -562,28 +643,14 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
                return 0;
        }
 
-       if (lp->size) {
-               /* No of 512-byte sectors */
-               tmp_size = lp->size;
-
-               if (tmp_size % vg->extent_size) {
-                       tmp_size += vg->extent_size - tmp_size %
-                           vg->extent_size;
-                       log_print("Rounding up size to full physical extent %s",
-                                 display_size(cmd, tmp_size));
-               }
+       if (lp->size &&
+           !(lp->extents = _extents_from_size(cmd, lp->size, vg->extent_size)))
+               return_0;
 
-               if (tmp_size > (uint64_t) UINT32_MAX * vg->extent_size) {
-                       log_error("Volume too large (%s) for extent size %s. "
-                                 "Upper limit is %s.",
-                                 display_size(cmd, tmp_size),
-                                 display_size(cmd, (uint64_t) vg->extent_size),
-                                 display_size(cmd, (uint64_t) UINT32_MAX *
-                                                  vg->extent_size));
-                       return 0;
-               }
-               lp->extents = (uint64_t) tmp_size / vg->extent_size;
-       }
+       if (lp->voriginsize &&
+           !(lp->voriginextents = _extents_from_size(cmd, lp->voriginsize,
+                                                     vg->extent_size)))
+               return_0;
 
        /*
         * Create the pv list.
@@ -645,37 +712,49 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
                        log_error("Clustered snapshots are not yet supported.");
                        return 0;
                }
-               if (!(org = find_lv(vg, lp->origin))) {
-                       log_err("Couldn't find origin volume '%s'.",
-                               lp->origin);
-                       return 0;
-               }
-               if (lv_is_cow(org)) {
-                       log_error("Snapshots of snapshots are not supported "
-                                 "yet.");
-                       return 0;
-               }
-               if (org->status & LOCKED) {
-                       log_error("Snapshots of locked devices are not "
-                                 "supported yet");
-                       return 0;
-               }
-               if (org->status & MIRROR_IMAGE ||
-                   org->status & MIRROR_LOG ||
-                   org->status & MIRRORED) {
-                       log_error("Snapshots and mirrors may not yet be mixed.");
-                       return 0;
-               }
 
                /* Must zero cow */
                status |= LVM_WRITE;
 
-               if (!lv_info(cmd, org, &info, 0, 0)) {
-                       log_error("Check for existence of snapshot origin "
-                                 "'%s' failed.", org->name);
-                       return 0;
+               if (arg_count(cmd, virtualoriginsize_ARG))
+                       origin_active = 1;
+               else {
+
+                       if (!(org = find_lv(vg, lp->origin))) {
+                               log_error("Couldn't find origin volume '%s'.",
+                                         lp->origin);
+                               return 0;
+                       }
+                       if (lv_is_virtual_origin(lv)) {
+                               log_error("Can't share virtual origins. "
+                                         "Use --virtualoriginsize.");
+                               return 0;
+                       }
+                       if (lv_is_cow(org)) {
+                               log_error("Snapshots of snapshots are not "
+                                         "supported yet.");
+                               return 0;
+                       }
+                       if (org->status & LOCKED) {
+                               log_error("Snapshots of locked devices are not "
+                                         "supported yet");
+                               return 0;
+                       }
+                       if (org->status & MIRROR_IMAGE ||
+                           org->status & MIRROR_LOG ||
+                           org->status & MIRRORED) {
+                               log_error("Snapshots and mirrors may not yet "
+                                         "be mixed.");
+                               return 0;
+                       }
+       
+                       if (!lv_info(cmd, org, &info, 0, 0)) {
+                               log_error("Check for existence of snapshot "
+                                         "origin '%s' failed.", org->name);
+                               return 0;
+                       }
+                       origin_active = info.exists;
                }
-               origin_active = info.exists;
        }
 
        if (!lp->extents) {
@@ -828,6 +907,15 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
                        return 0;
                }
 
+               if (lp->voriginsize &&
+                   !(org = _create_virtual_origin(cmd, vg, lv->name,
+                                                  lp->permission,
+                                                  lp->voriginextents))) {
+                       log_error("Couldn't create virtual origin for LV %s",
+                                 lv->name);
+                       goto deactivate_and_revert_new_lv;
+               }
+
                /* cow LV remains active and becomes snapshot LV */
 
                if (!vg_add_snapshot(NULL, org, lv, NULL,
index 8b8401d626d119cb8f4128fe3eed3c1b95823a84..712f17535de6d444ae3880ff505e3008298129a5 100644 (file)
 static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
                           void *handle __attribute((unused)))
 {
+       struct logical_volume *origin;
+
+       /*
+        * If this is a sparse device, remove its origin too.
+        */
+        if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
+                lv = origin;
+
        if (!lv_remove_with_dependencies(cmd, lv, arg_count(cmd, force_ARG)))
                return ECMD_FAILED;
 
index dede1ec35c731c6634fcb261e493b0b944bc2016..aa33468ed61c32a1b642b08b540c2277e73ad044 100644 (file)
@@ -1229,6 +1229,12 @@ int apply_lvname_restrictions(const char *name)
                return 0;
        }
 
+       if (strstr(name, "_vorigin")) {
+               log_error("Names including \"_vorigin\" are reserved. "
+                         "Please choose a different LV name.");
+               return 0;
+       }
+
        return 1;
 }
 
This page took 0.062402 seconds and 5 git commands to generate.