1 /* $NetBSD: striped.c,v 1.1.1.2 2009/12/02 00:26:47 haad Exp $ */
2
3 /*
4 * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 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 "toolcontext.h"
20 #include "segtype.h"
21 #include "display.h"
22 #include "text_export.h"
23 #include "text_import.h"
24 #include "config.h"
25 #include "str_list.h"
26 #include "targets.h"
27 #include "lvm-string.h"
28 #include "activate.h"
29 #include "pv_alloc.h"
30 #include "metadata.h"
31
_striped_name(const struct lv_segment * seg)32 static const char *_striped_name(const struct lv_segment *seg)
33 {
34 return (seg->area_count == 1) ? "linear" : seg->segtype->name;
35 }
36
_striped_display(const struct lv_segment * seg)37 static void _striped_display(const struct lv_segment *seg)
38 {
39 uint32_t s;
40
41 if (seg->area_count == 1)
42 display_stripe(seg, 0, " ");
43 else {
44 log_print(" Stripes\t\t%u", seg->area_count);
45
46 if (seg->lv->vg->cmd->si_unit_consistency)
47 log_print(" Stripe size\t\t%s",
48 display_size(seg->lv->vg->cmd,
49 (uint64_t) seg->stripe_size));
50 else
51 log_print(" Stripe size\t\t%u KB",
52 seg->stripe_size / 2);
53
54 for (s = 0; s < seg->area_count; s++) {
55 log_print(" Stripe %d:", s);
56 display_stripe(seg, s, " ");
57 }
58 }
59 log_print(" ");
60 }
61
_striped_text_import_area_count(struct config_node * sn,uint32_t * area_count)62 static int _striped_text_import_area_count(struct config_node *sn, uint32_t *area_count)
63 {
64 if (!get_config_uint32(sn, "stripe_count", area_count)) {
65 log_error("Couldn't read 'stripe_count' for "
66 "segment '%s'.", config_parent_name(sn));
67 return 0;
68 }
69
70 return 1;
71 }
72
_striped_text_import(struct lv_segment * seg,const struct config_node * sn,struct dm_hash_table * pv_hash)73 static int _striped_text_import(struct lv_segment *seg, const struct config_node *sn,
74 struct dm_hash_table *pv_hash)
75 {
76 struct config_node *cn;
77
78 if ((seg->area_count != 1) &&
79 !get_config_uint32(sn, "stripe_size", &seg->stripe_size)) {
80 log_error("Couldn't read stripe_size for segment %s "
81 "of logical volume %s.", config_parent_name(sn), seg->lv->name);
82 return 0;
83 }
84
85 if (!(cn = find_config_node(sn, "stripes"))) {
86 log_error("Couldn't find stripes array for segment %s "
87 "of logical volume %s.", config_parent_name(sn), seg->lv->name);
88 return 0;
89 }
90
91 seg->area_len /= seg->area_count;
92
93 return text_import_areas(seg, sn, cn, pv_hash, 0);
94 }
95
_striped_text_export(const struct lv_segment * seg,struct formatter * f)96 static int _striped_text_export(const struct lv_segment *seg, struct formatter *f)
97 {
98
99 outf(f, "stripe_count = %u%s", seg->area_count,
100 (seg->area_count == 1) ? "\t# linear" : "");
101
102 if (seg->area_count > 1)
103 out_size(f, (uint64_t) seg->stripe_size,
104 "stripe_size = %u", seg->stripe_size);
105
106 return out_areas(f, seg, "stripe");
107 }
108
109 /*
110 * Test whether two segments could be merged by the current merging code
111 */
_striped_segments_compatible(struct lv_segment * first,struct lv_segment * second)112 static int _striped_segments_compatible(struct lv_segment *first,
113 struct lv_segment *second)
114 {
115 uint32_t width;
116 unsigned s;
117
118 if ((first->area_count != second->area_count) ||
119 (first->stripe_size != second->stripe_size))
120 return 0;
121
122 for (s = 0; s < first->area_count; s++) {
123
124 /* FIXME Relax this to first area type != second area type */
125 /* plus the additional AREA_LV checks needed */
126 if ((seg_type(first, s) != AREA_PV) ||
127 (seg_type(second, s) != AREA_PV))
128 return 0;
129
130 width = first->area_len;
131
132 if ((seg_pv(first, s) !=
133 seg_pv(second, s)) ||
134 (seg_pe(first, s) + width !=
135 seg_pe(second, s)))
136 return 0;
137 }
138
139 if (!str_list_lists_equal(&first->tags, &second->tags))
140 return 0;
141
142 return 1;
143 }
144
_striped_merge_segments(struct lv_segment * seg1,struct lv_segment * seg2)145 static int _striped_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
146 {
147 uint32_t s;
148
149 if (!_striped_segments_compatible(seg1, seg2))
150 return 0;
151
152 seg1->len += seg2->len;
153 seg1->area_len += seg2->area_len;
154
155 for (s = 0; s < seg1->area_count; s++)
156 if (seg_type(seg1, s) == AREA_PV)
157 merge_pv_segments(seg_pvseg(seg1, s),
158 seg_pvseg(seg2, s));
159
160 return 1;
161 }
162
163 #ifdef DEVMAPPER_SUPPORT
_striped_add_target_line(struct dev_manager * dm,struct dm_pool * mem __attribute ((unused)),struct cmd_context * cmd __attribute ((unused)),void ** target_state __attribute ((unused)),struct lv_segment * seg,struct dm_tree_node * node,uint64_t len,uint32_t * pvmove_mirror_count __attribute ((unused)))164 static int _striped_add_target_line(struct dev_manager *dm,
165 struct dm_pool *mem __attribute((unused)),
166 struct cmd_context *cmd __attribute((unused)),
167 void **target_state __attribute((unused)),
168 struct lv_segment *seg,
169 struct dm_tree_node *node, uint64_t len,
170 uint32_t *pvmove_mirror_count __attribute((unused)))
171 {
172 if (!seg->area_count) {
173 log_error("Internal error: striped add_target_line called "
174 "with no areas for %s.", seg->lv->name);
175 return 0;
176 }
177 if (seg->area_count == 1) {
178 if (!dm_tree_node_add_linear_target(node, len))
179 return_0;
180 } else if (!dm_tree_node_add_striped_target(node, len,
181 seg->stripe_size))
182 return_0;
183
184 return add_areas_line(dm, seg, node, 0u, seg->area_count);
185 }
186
_striped_target_present(struct cmd_context * cmd,const struct lv_segment * seg __attribute ((unused)),unsigned * attributes __attribute ((unused)))187 static int _striped_target_present(struct cmd_context *cmd,
188 const struct lv_segment *seg __attribute((unused)),
189 unsigned *attributes __attribute((unused)))
190 {
191 static int _striped_checked = 0;
192 static int _striped_present = 0;
193
194 if (!_striped_checked)
195 _striped_present = target_present(cmd, "linear", 0) &&
196 target_present(cmd, "striped", 0);
197
198 _striped_checked = 1;
199
200 return _striped_present;
201 }
202 #endif
203
_striped_destroy(const struct segment_type * segtype)204 static void _striped_destroy(const struct segment_type *segtype)
205 {
206 dm_free((void *)segtype);
207 }
208
209 static struct segtype_handler _striped_ops = {
210 .name = _striped_name,
211 .display = _striped_display,
212 .text_import_area_count = _striped_text_import_area_count,
213 .text_import = _striped_text_import,
214 .text_export = _striped_text_export,
215 .merge_segments = _striped_merge_segments,
216 #ifdef DEVMAPPER_SUPPORT
217 .add_target_line = _striped_add_target_line,
218 .target_present = _striped_target_present,
219 #endif
220 .destroy = _striped_destroy,
221 };
222
init_striped_segtype(struct cmd_context * cmd)223 struct segment_type *init_striped_segtype(struct cmd_context *cmd)
224 {
225 struct segment_type *segtype = dm_malloc(sizeof(*segtype));
226
227 if (!segtype)
228 return_NULL;
229
230 segtype->cmd = cmd;
231 segtype->ops = &_striped_ops;
232 segtype->name = "striped";
233 segtype->private = NULL;
234 segtype->flags =
235 SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
236
237 log_very_verbose("Initialised segtype: %s", segtype->name);
238
239 return segtype;
240 }
241