]> sourceware.org Git - lvm2.git/commitdiff
Thin supports snapshots
authorZdenek Kabelac <zkabelac@redhat.com>
Mon, 7 Nov 2011 11:03:47 +0000 (11:03 +0000)
committerZdenek Kabelac <zkabelac@redhat.com>
Mon, 7 Nov 2011 11:03:47 +0000 (11:03 +0000)
Full support for thin snapshots.
Create and remove is supported.

TODO: lvconvert support is not yes available.

lib/metadata/lv_manip.c
lib/metadata/merge.c
lib/metadata/metadata.h
lib/metadata/thin_manip.c
lib/report/report.c
lib/thin/thin.c
tools/lvcreate.c

index d4b349426dd756d5af3cf5400dcb71b4b9b83cd6..588118eeb6d5e4799674fdddd8d7ab2b57e38eec 100644 (file)
@@ -255,9 +255,16 @@ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
        dm_list_init(&seg->thin_messages);
 
        if (thin_pool_lv) {
-               seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
-               if (!attach_pool_lv(seg, thin_pool_lv))
-                       return_NULL;
+               /* If this thin volume, thin snapshot is being created */
+               if (lv_is_thin_volume(thin_pool_lv)) {
+                       seg->transaction_id = first_seg(first_seg(thin_pool_lv)->pool_lv)->transaction_id;
+                       if (!attach_pool_lv(seg, first_seg(thin_pool_lv)->pool_lv, thin_pool_lv))
+                               return_NULL;
+               } else {
+                       seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
+                       if (!attach_pool_lv(seg, thin_pool_lv, NULL))
+                               return_NULL;
+               }
        }
 
        if (log_lv && !attach_mirror_log(seg, log_lv))
@@ -4004,8 +4011,20 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
 
        status |= lp->permission | VISIBLE_LV;
 
-       /* FIXME Thin snapshots are different */
-       if (lp->snapshot) {
+       if (lp->snapshot && lp->thin) {
+               if (!(org = find_lv(vg, lp->origin))) {
+                       log_error("Couldn't find origin volume '%s'.",
+                                 lp->origin);
+                       return NULL;
+               }
+
+               if (org->status & LOCKED) {
+                       log_error("Snapshots of locked devices are not supported.");
+                       return NULL;
+               }
+
+               lp->voriginextents = org->le_count;
+       } else if (lp->snapshot) {
                if (!activation()) {
                        log_error("Can't create snapshot without using "
                                  "device-mapper kernel driver");
@@ -4074,7 +4093,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
                return NULL;
        }
 
-       if (lp->snapshot && (lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
+       if (lp->snapshot && !lp->thin && (lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
                log_error("Unable to create a snapshot smaller than 2 chunks.");
                return NULL;
        }
@@ -4105,7 +4124,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
        }
 
        /* The snapshot segment gets created later */
-       if (lp->snapshot &&
+       if (lp->snapshot && !lp->thin &&
            !(lp->segtype = get_segtype_from_string(cmd, "striped")))
                return_NULL;
 
@@ -4173,7 +4192,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
                       lp->mirrors,
                       seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size,
                       seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents,
-                      seg_is_thin_volume(lp) ? lp->pool : NULL, lp->pvh, lp->alloc))
+                      seg_is_thin_volume(lp) ? (org ? org->name : lp->pool) : NULL, lp->pvh, lp->alloc))
                return_NULL;
 
        if (seg_is_thin_pool(lp)) {
@@ -4221,6 +4240,24 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
        init_dmeventd_monitor(lp->activation_monitoring);
 
        if (seg_is_thin(lp)) {
+
+               /* For thin snapshot suspend active thin origin first */
+               if (org && lv_is_active(org)) {
+                       if (!suspend_lv(cmd, org)) {
+                               log_error("Failed to suspend thin origin %s.",
+                                         org->name);
+                               goto revert_new_lv;
+                       } else if (!resume_lv(cmd, org)) {
+                               log_error("Failed to resume thin origin %s.",
+                                         org->name);
+                               goto revert_new_lv;
+                       }
+                       /* At this point snapshot is active in kernel thin mda */
+                       if (!update_pool_lv(first_seg(org)->pool_lv, 0)) {
+                               stack;
+                               goto deactivate_and_revert_new_lv;
+                       }
+               }
                if (((lp->activate == CHANGE_AY) ||
                     (lp->activate == CHANGE_AE) ||
                     (lp->activate == CHANGE_ALY))) {
@@ -4261,7 +4298,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
                goto deactivate_and_revert_new_lv;
        }
 
-       if (lp->snapshot) {
+       if (lp->snapshot && !lp->thin) {
                /* Reset permission after zeroing */
                if (!(lp->permission & LVM_WRITE))
                        lv->status &= ~LVM_WRITE;
index fbfa579e86197e4e6ccc96414806a31fb8688159..e691176fcc7ea020de81d2f5c362565f1c7bd84d 100644 (file)
@@ -373,6 +373,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                        seg_found++;
                if (seg->pool_metadata_lv == lv || seg->pool_lv == lv)
                        seg_found++;
+               if (seg_is_thin_volume(seg) && seg->origin == lv)
+                       seg_found++;
                if (!seg_found) {
                        log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32
                                  ", but missing ptr from %s to %s",
index 06e820ce3362a81a83dd1d0e58e311bc1e1fa56a..a8d28e980a8d93f10d0bc400da7ff458ebd503f8 100644 (file)
@@ -456,7 +456,8 @@ int attach_pool_metadata_lv(struct lv_segment *seg,
                            struct logical_volume *pool_metadata_lv);
 int attach_pool_data_lv(struct lv_segment *seg,
                        struct logical_volume *pool_data_lv);
-int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv);
+int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
+                  struct logical_volume *origin_lv);
 int detach_pool_lv(struct lv_segment *seg);
 int attach_pool_message(struct lv_segment *seg, dm_thin_message_t type,
                        struct logical_volume *lv, uint32_t delete_id,
index c23ec52a57f49355f33499b93c9c7b21fe20665d..ed50d8efab4d92a9dfba023eff823a6118c12ca8 100644 (file)
@@ -39,10 +39,15 @@ int attach_pool_data_lv(struct lv_segment *seg, struct logical_volume *pool_data
        return 1;
 }
 
-int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv)
+int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
+                  struct logical_volume *origin)
 {
        seg->pool_lv = pool_lv;
        seg->lv->status |= THIN_VOLUME;
+       seg->origin = origin;
+
+       if (origin && !add_seg_to_segs_using_this_lv(origin, seg))
+               return_0;
 
        return add_seg_to_segs_using_this_lv(pool_lv, seg);
 }
@@ -50,6 +55,7 @@ int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv)
 int detach_pool_lv(struct lv_segment *seg)
 {
        struct lv_thin_message *tmsg, *tmp;
+       struct seg_list *sl, *tsl;
 
        if (!seg->pool_lv || !lv_is_thin_pool(seg->pool_lv)) {
                log_error(INTERNAL_ERROR "LV %s is not a thin volume",
@@ -78,7 +84,30 @@ int detach_pool_lv(struct lv_segment *seg)
                                 NULL, seg->device_id, 0))
                return_0;
 
-       return remove_seg_from_segs_using_this_lv(seg->pool_lv, seg);
+       if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg))
+               return_0;
+
+       if (seg->origin &&
+           !remove_seg_from_segs_using_this_lv(seg->origin, seg))
+               return_0;
+
+       /* If thin origin, remove it from related thin snapshots */
+       /*
+        * TODO: map removal of origin as snapshot lvconvert --merge?
+        * i.e. rename thin snapshot to origin thin origin
+        */
+       dm_list_iterate_items_safe(sl, tsl, &seg->lv->segs_using_this_lv) {
+               if (!seg_is_thin_volume(sl->seg) ||
+                   (seg->lv != sl->seg->origin))
+                       continue;
+
+               if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg))
+                       return_0;
+               /* Thin snapshot is now regular thin volume */
+               sl->seg->origin = NULL;
+       }
+
+       return 1;
 }
 
 int attach_pool_message(struct lv_segment *seg, dm_thin_message_t type,
index 4781f3a87c12a2b3c6f298d4eb1130a9324b193a..8b493cc3641a558e8c7b5d64ff58f21408b7ef21 100644 (file)
@@ -309,6 +309,9 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
        if (lv_is_cow(lv))
                return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
 
+       if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
+               return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private);
+
        dm_report_field_set_value(field, "", NULL);
        return 1;
 }
index ead082c210a09a4218d66463b9c2c130f5656c0b..cbdd2f3046ae134d12cc583ca7139394c13591e3 100644 (file)
@@ -317,7 +317,7 @@ static int _thin_text_import(struct lv_segment *seg,
                             struct dm_hash_table *pv_hash __attribute__((unused)))
 {
        const char *lv_name;
-       struct logical_volume *pool_lv;
+       struct logical_volume *pool_lv, *origin = NULL;
 
        if (!dm_config_get_str(sn, "thin_pool", &lv_name))
                return SEG_LOG_ERROR("Thin pool must be a string in");
@@ -325,9 +325,6 @@ static int _thin_text_import(struct lv_segment *seg,
        if (!(pool_lv = find_lv(seg->lv->vg, lv_name)))
                return SEG_LOG_ERROR("Unknown thin pool %s in", lv_name);
 
-       if (!attach_pool_lv(seg, pool_lv))
-               return_0;
-
        if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id))
                return SEG_LOG_ERROR("Could not read transaction_id for");
 
@@ -335,7 +332,7 @@ static int _thin_text_import(struct lv_segment *seg,
                if (!dm_config_get_str(sn, "origin", &lv_name))
                        return SEG_LOG_ERROR("Origin must be a string in");
 
-               if (!(seg->origin = find_lv(seg->lv->vg, lv_name)))
+               if (!(origin = find_lv(seg->lv->vg, lv_name)))
                        return SEG_LOG_ERROR("Unknown origin %s in", lv_name);
        }
 
@@ -346,6 +343,9 @@ static int _thin_text_import(struct lv_segment *seg,
                return SEG_LOG_ERROR("Unsupported value %u for device_id",
                                     seg->device_id);
 
+       if (!attach_pool_lv(seg, pool_lv, origin))
+               return_0;
+
        return 1;
 }
 
index e0cca2e4d4431f42e42166dbe2f942bf99f17ad9..ec48ae6d6ca8ee5ce33e4f09cfda9eded7d5df4d 100644 (file)
@@ -1013,13 +1013,6 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
                            lp.pool, lp.vg_name, lp.snapshot ? " as snapshot of " : "",
                            lp.snapshot ? lp.origin : "", lp.segtype->name);
 
-       /* FIXME Remove when thin snapshots are supported. */
-       if (lp.thin && lp.snapshot) {
-               log_error("Thin snapshots are not yet supported.");
-               r = ECMD_FAILED;
-               goto_out;
-       }
-
        if (!lv_create_single(vg, &lp)) {
                stack;
                r = ECMD_FAILED;
This page took 0.057014 seconds and 5 git commands to generate.