Branch data Line data Source code
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 : :
22 : 0 : int lv_is_origin(const struct logical_volume *lv)
23 : : {
24 : 0 : return lv->origin_count ? 1 : 0;
25 : : }
26 : :
27 : 0 : int lv_is_cow(const struct logical_volume *lv)
28 : : {
29 [ # # ][ # # ]: 0 : return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0;
30 : : }
31 : :
32 : 0 : int lv_is_visible(const struct logical_volume *lv)
33 : : {
34 [ # # ]: 0 : if (lv->status & SNAPSHOT)
35 : 0 : return 0;
36 : :
37 [ # # ]: 0 : if (lv_is_cow(lv)) {
38 [ # # ]: 0 : if (lv_is_virtual_origin(origin_from_cow(lv)))
39 : 0 : return 1;
40 : :
41 [ # # ]: 0 : if (lv_is_merging_cow(lv))
42 : 0 : return 0;
43 : :
44 : 0 : return lv_is_visible(origin_from_cow(lv));
45 : : }
46 : :
47 : 0 : return lv->status & VISIBLE_LV ? 1 : 0;
48 : : }
49 : :
50 : 0 : int lv_is_virtual_origin(const struct logical_volume *lv)
51 : : {
52 : 0 : return (lv->status & VIRTUAL_ORIGIN) ? 1 : 0;
53 : : }
54 : :
55 : 0 : int lv_is_merging_origin(const struct logical_volume *origin)
56 : : {
57 : 0 : return (origin->status & MERGING) ? 1 : 0;
58 : : }
59 : :
60 : 0 : struct lv_segment *find_merging_cow(const struct logical_volume *origin)
61 : : {
62 [ # # ]: 0 : if (!lv_is_merging_origin(origin))
63 : 0 : return NULL;
64 : :
65 : 0 : return find_cow(origin);
66 : : }
67 : :
68 : 0 : int lv_is_merging_cow(const struct logical_volume *snapshot)
69 : : {
70 : : /* checks lv_segment's status to see if cow is merging */
71 : 0 : return (find_cow(snapshot)->status & MERGING) ? 1 : 0;
72 : : }
73 : :
74 : : /* Given a cow LV, return the snapshot lv_segment that uses it */
75 : 0 : struct lv_segment *find_cow(const struct logical_volume *lv)
76 : : {
77 : 0 : return lv->snapshot;
78 : : }
79 : :
80 : : /* Given a cow LV, return its origin */
81 : 0 : struct logical_volume *origin_from_cow(const struct logical_volume *lv)
82 : : {
83 : 0 : return lv->snapshot->origin;
84 : : }
85 : :
86 : 0 : void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
87 : : struct logical_volume *cow, uint32_t chunk_size, int merge)
88 : : {
89 : 0 : seg->chunk_size = chunk_size;
90 : 0 : seg->origin = origin;
91 : 0 : seg->cow = cow;
92 : :
93 : 0 : lv_set_hidden(cow);
94 : :
95 : 0 : cow->snapshot = seg;
96 : :
97 : 0 : origin->origin_count++;
98 : :
99 : : /* FIXME Assumes an invisible origin belongs to a sparse device */
100 [ # # ]: 0 : if (!lv_is_visible(origin))
101 : 0 : origin->status |= VIRTUAL_ORIGIN;
102 : :
103 : 0 : seg->lv->status |= (SNAPSHOT | VIRTUAL);
104 [ # # ]: 0 : if (merge)
105 : 0 : init_snapshot_merge(seg, origin);
106 : :
107 : 0 : dm_list_add(&origin->snapshot_segs, &seg->origin_list);
108 : 0 : }
109 : :
110 : 0 : void init_snapshot_merge(struct lv_segment *cow_seg,
111 : : struct logical_volume *origin)
112 : : {
113 : : /*
114 : : * Even though lv_is_visible(cow_seg->lv) returns 0,
115 : : * the cow_seg->lv (name: snapshotX) is _not_ hidden;
116 : : * this is part of the lvm2 snapshot fiction. Must
117 : : * clear VISIBLE_LV directly (lv_set_visible can't)
118 : : * - cow_seg->lv->status is used to control whether 'lv'
119 : : * (with user provided snapshot LV name) is visible
120 : : * - this also enables vg_validate() to succeed with
121 : : * merge metadata (cow_seg->lv is now "internal")
122 : : */
123 : 0 : cow_seg->lv->status &= ~VISIBLE_LV;
124 : 0 : cow_seg->status |= MERGING;
125 : 0 : origin->snapshot = cow_seg;
126 : 0 : origin->status |= MERGING;
127 : 0 : }
128 : :
129 : 0 : void clear_snapshot_merge(struct logical_volume *origin)
130 : : {
131 : : /* clear merge attributes */
132 : 0 : origin->snapshot->status &= ~MERGING;
133 : 0 : origin->snapshot = NULL;
134 : 0 : origin->status &= ~MERGING;
135 : 0 : }
136 : :
137 : 0 : int vg_add_snapshot(struct logical_volume *origin,
138 : : struct logical_volume *cow, union lvid *lvid,
139 : : uint32_t extent_count, uint32_t chunk_size)
140 : : {
141 : : struct logical_volume *snap;
142 : : struct lv_segment *seg;
143 : :
144 : : /*
145 : : * Is the cow device already being used ?
146 : : */
147 [ # # ]: 0 : if (lv_is_cow(cow)) {
148 : 0 : log_error("'%s' is already in use as a snapshot.", cow->name);
149 : 0 : return 0;
150 : : }
151 : :
152 [ # # ]: 0 : if (cow == origin) {
153 : 0 : log_error("Snapshot and origin LVs must differ.");
154 : 0 : return 0;
155 : : }
156 : :
157 [ # # ]: 0 : if (!(snap = lv_create_empty("snapshot%d",
158 : : lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
159 : : ALLOC_INHERIT, origin->vg)))
160 : 0 : return_0;
161 : :
162 : 0 : snap->le_count = extent_count;
163 : :
164 [ # # ]: 0 : if (!(seg = alloc_snapshot_seg(snap, 0, 0)))
165 : 0 : return_0;
166 : :
167 : 0 : init_snapshot_seg(seg, origin, cow, chunk_size, 0);
168 : :
169 : 0 : return 1;
170 : : }
171 : :
172 : 0 : int vg_remove_snapshot(struct logical_volume *cow)
173 : : {
174 : 0 : int preload_origin = 0;
175 : 0 : struct logical_volume *origin = origin_from_cow(cow);
176 : :
177 : 0 : dm_list_del(&cow->snapshot->origin_list);
178 : 0 : origin->origin_count--;
179 [ # # ]: 0 : if (find_merging_cow(origin) == find_cow(cow)) {
180 : 0 : clear_snapshot_merge(origin);
181 : : /*
182 : : * preload origin to:
183 : : * - allow proper release of -cow
184 : : * - avoid allocations with other devices suspended
185 : : * when transitioning from "snapshot-merge" to
186 : : * "snapshot-origin after a merge completes.
187 : : */
188 : 0 : preload_origin = 1;
189 : : }
190 : :
191 [ # # ]: 0 : if (!lv_remove(cow->snapshot->lv)) {
192 : 0 : log_error("Failed to remove internal snapshot LV %s",
193 : : cow->snapshot->lv->name);
194 : 0 : return 0;
195 : : }
196 : :
197 : 0 : cow->snapshot = NULL;
198 : 0 : lv_set_visible(cow);
199 : :
200 [ # # ]: 0 : if (preload_origin) {
201 [ # # ]: 0 : if (!vg_write(origin->vg))
202 : 0 : return_0;
203 [ # # ][ # # ]: 0 : if (!suspend_lv(origin->vg->cmd, origin)) {
[ # # ]
204 : 0 : log_error("Failed to refresh %s without snapshot.",
205 : : origin->name);
206 : 0 : return 0;
207 : : }
208 [ # # ]: 0 : if (!vg_commit(origin->vg))
209 : 0 : return_0;
210 [ # # ][ # # ]: 0 : if (!resume_lv(origin->vg->cmd, origin)) {
[ # # ]
211 : 0 : log_error("Failed to resume %s.", origin->name);
212 : 0 : return 0;
213 : : }
214 : : }
215 : :
216 : 0 : return 1;
217 : : }
|