Imported Upstream version 2.02.79
[platform/upstream/device-mapper.git] / lib / metadata / snapshot_manip.c
1 /*
2  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
4  *
5  * This file is part of LVM2.
6  *
7  * This copyrighted material is made available to anyone wishing to use,
8  * modify, copy, or redistribute it subject to the terms and conditions
9  * of the GNU Lesser General Public License v.2.1.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  */
15
16 #include "lib.h"
17 #include "metadata.h"
18 #include "locking.h"
19 #include "toolcontext.h"
20 #include "lv_alloc.h"
21 #include "activate.h"
22
23 int lv_is_origin(const struct logical_volume *lv)
24 {
25         return lv->origin_count ? 1 : 0;
26 }
27
28 int lv_is_cow(const struct logical_volume *lv)
29 {
30         return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0;
31 }
32
33 int lv_is_visible(const struct logical_volume *lv)
34 {
35         if (lv->status & SNAPSHOT)
36                 return 0;
37
38         if (lv_is_cow(lv)) {
39                 if (lv_is_virtual_origin(origin_from_cow(lv)))
40                         return 1;
41
42                 if (lv_is_merging_cow(lv))
43                         return 0;
44
45                 return lv_is_visible(origin_from_cow(lv));
46         }
47
48         return lv->status & VISIBLE_LV ? 1 : 0;
49 }
50
51 int lv_is_virtual_origin(const struct logical_volume *lv)
52 {
53         return (lv->status & VIRTUAL_ORIGIN) ? 1 : 0;
54 }
55
56 int lv_is_merging_origin(const struct logical_volume *origin)
57 {
58         return (origin->status & MERGING) ? 1 : 0;
59 }
60
61 struct lv_segment *find_merging_cow(const struct logical_volume *origin)
62 {
63         if (!lv_is_merging_origin(origin))
64                 return NULL;
65
66         return find_cow(origin);
67 }
68
69 int lv_is_merging_cow(const struct logical_volume *snapshot)
70 {
71         /* checks lv_segment's status to see if cow is merging */
72         return (find_cow(snapshot)->status & MERGING) ? 1 : 0;
73 }
74
75 /* Given a cow LV, return the snapshot lv_segment that uses it */
76 struct lv_segment *find_cow(const struct logical_volume *lv)
77 {
78         return lv->snapshot;
79 }
80
81 /* Given a cow LV, return its origin */
82 struct logical_volume *origin_from_cow(const struct logical_volume *lv)
83 {
84         return lv->snapshot->origin;
85 }
86
87 void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
88                        struct logical_volume *cow, uint32_t chunk_size, int merge)
89 {
90         seg->chunk_size = chunk_size;
91         seg->origin = origin;
92         seg->cow = cow;
93
94         lv_set_hidden(cow);
95
96         cow->snapshot = seg;
97
98         origin->origin_count++;
99
100         /* FIXME Assumes an invisible origin belongs to a sparse device */
101         if (!lv_is_visible(origin))
102                 origin->status |= VIRTUAL_ORIGIN;
103
104         seg->lv->status |= (SNAPSHOT | VIRTUAL);
105         if (merge)
106                 init_snapshot_merge(seg, origin);
107
108         dm_list_add(&origin->snapshot_segs, &seg->origin_list);
109 }
110
111 void init_snapshot_merge(struct lv_segment *cow_seg,
112                          struct logical_volume *origin)
113 {
114         /*
115          * Even though lv_is_visible(cow_seg->lv) returns 0,
116          * the cow_seg->lv (name: snapshotX) is _not_ hidden;
117          * this is part of the lvm2 snapshot fiction.  Must
118          * clear VISIBLE_LV directly (lv_set_visible can't)
119          * - cow_seg->lv->status is used to control whether 'lv'
120          *   (with user provided snapshot LV name) is visible
121          * - this also enables vg_validate() to succeed with
122          *   merge metadata (cow_seg->lv is now "internal")
123          */
124         cow_seg->lv->status &= ~VISIBLE_LV;
125         cow_seg->status |= MERGING;
126         origin->snapshot = cow_seg;
127         origin->status |= MERGING;
128 }
129
130 void clear_snapshot_merge(struct logical_volume *origin)
131 {
132         /* clear merge attributes */
133         origin->snapshot->status &= ~MERGING;
134         origin->snapshot = NULL;
135         origin->status &= ~MERGING;
136 }
137
138 int vg_add_snapshot(struct logical_volume *origin,
139                     struct logical_volume *cow, union lvid *lvid,
140                     uint32_t extent_count, uint32_t chunk_size)
141 {
142         struct logical_volume *snap;
143         struct lv_segment *seg;
144
145         /*
146          * Is the cow device already being used ?
147          */
148         if (lv_is_cow(cow)) {
149                 log_error("'%s' is already in use as a snapshot.", cow->name);
150                 return 0;
151         }
152
153         if (cow == origin) {
154                 log_error("Snapshot and origin LVs must differ.");
155                 return 0;
156         }
157
158         if (!(snap = lv_create_empty("snapshot%d",
159                                      lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
160                                      ALLOC_INHERIT, origin->vg)))
161                 return_0;
162
163         snap->le_count = extent_count;
164
165         if (!(seg = alloc_snapshot_seg(snap, 0, 0)))
166                 return_0;
167
168         init_snapshot_seg(seg, origin, cow, chunk_size, 0);
169
170         return 1;
171 }
172
173 int vg_remove_snapshot(struct logical_volume *cow)
174 {
175         int preload_origin = 0;
176         struct logical_volume *origin = origin_from_cow(cow);
177
178         dm_list_del(&cow->snapshot->origin_list);
179         origin->origin_count--;
180
181         if (find_merging_cow(origin) == find_cow(cow)) {
182                 clear_snapshot_merge(origin);
183                 /*
184                  * preload origin IFF "snapshot-merge" target is active
185                  * - IMPORTANT: avoids preload if onactivate merge is pending
186                  */
187                 if (lv_has_target_type(origin->vg->cmd->mem, origin, NULL,
188                                        "snapshot-merge")) {
189                         /*
190                          * preload origin to:
191                          * - allow proper release of -cow
192                          * - avoid allocations with other devices suspended
193                          *   when transitioning from "snapshot-merge" to
194                          *   "snapshot-origin after a merge completes.
195                          */
196                         preload_origin = 1;
197                 }
198         }
199
200         if (!lv_remove(cow->snapshot->lv)) {
201                 log_error("Failed to remove internal snapshot LV %s",
202                           cow->snapshot->lv->name);
203                 return 0;
204         }
205
206         cow->snapshot = NULL;
207         lv_set_visible(cow);
208
209         if (preload_origin) {
210                 if (!vg_write(origin->vg))
211                         return_0;
212                 if (!suspend_lv(origin->vg->cmd, origin)) {
213                         log_error("Failed to refresh %s without snapshot.",
214                                   origin->name);
215                         return 0;
216                 }
217                 if (!vg_commit(origin->vg))
218                         return_0;
219                 if (!resume_lv(origin->vg->cmd, origin)) {
220                         log_error("Failed to resume %s.", origin->name);
221                         return 0;
222                 }
223         }
224
225         return 1;
226 }