1 /* $NetBSD: snapshot_manip.c,v 1.1.1.3 2009/12/02 00:26:37 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of LVM2. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "lib.h" 19 #include "metadata.h" 20 #include "toolcontext.h" 21 #include "lv_alloc.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->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 return lv_is_visible(origin_from_cow(lv)); 43 } 44 45 return lv->status & VISIBLE_LV ? 1 : 0; 46 } 47 48 int lv_is_virtual_origin(const struct logical_volume *lv) 49 { 50 return (lv->status & VIRTUAL_ORIGIN) ? 1 : 0; 51 } 52 53 54 /* Given a cow LV, return the snapshot lv_segment that uses it */ 55 struct lv_segment *find_cow(const struct logical_volume *lv) 56 { 57 return lv->snapshot; 58 } 59 60 /* Given a cow LV, return its origin */ 61 struct logical_volume *origin_from_cow(const struct logical_volume *lv) 62 { 63 return lv->snapshot->origin; 64 } 65 66 void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin, 67 struct logical_volume *cow, uint32_t chunk_size) 68 { 69 seg->chunk_size = chunk_size; 70 seg->origin = origin; 71 seg->cow = cow; 72 73 lv_set_hidden(cow); 74 75 cow->snapshot = seg; 76 77 origin->origin_count++; 78 79 /* FIXME Assumes an invisible origin belongs to a sparse device */ 80 if (!lv_is_visible(origin)) 81 origin->status |= VIRTUAL_ORIGIN; 82 83 seg->lv->status |= (SNAPSHOT | VIRTUAL); 84 85 dm_list_add(&origin->snapshot_segs, &seg->origin_list); 86 } 87 88 int vg_add_snapshot(struct logical_volume *origin, 89 struct logical_volume *cow, union lvid *lvid, 90 uint32_t extent_count, uint32_t chunk_size) 91 { 92 struct logical_volume *snap; 93 struct lv_segment *seg; 94 95 /* 96 * Is the cow device already being used ? 97 */ 98 if (lv_is_cow(cow)) { 99 log_error("'%s' is already in use as a snapshot.", cow->name); 100 return 0; 101 } 102 103 if (cow == origin) { 104 log_error("Snapshot and origin LVs must differ."); 105 return 0; 106 } 107 108 if (!(snap = lv_create_empty("snapshot%d", 109 lvid, LVM_READ | LVM_WRITE | VISIBLE_LV, 110 ALLOC_INHERIT, origin->vg))) 111 return_0; 112 113 snap->le_count = extent_count; 114 115 if (!(seg = alloc_snapshot_seg(snap, 0, 0))) 116 return_0; 117 118 init_snapshot_seg(seg, origin, cow, chunk_size); 119 120 return 1; 121 } 122 123 int vg_remove_snapshot(struct logical_volume *cow) 124 { 125 dm_list_del(&cow->snapshot->origin_list); 126 cow->snapshot->origin->origin_count--; 127 128 if (!lv_remove(cow->snapshot->lv)) { 129 log_error("Failed to remove internal snapshot LV %s", 130 cow->snapshot->lv->name); 131 return 0; 132 } 133 134 cow->snapshot = NULL; 135 lv_set_visible(cow); 136 137 return 1; 138 } 139