xref: /dragonfly/contrib/lvm2/dist/lib/striped/striped.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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