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 32 static const char *_striped_name(const struct lv_segment *seg) 33 { 34 return (seg->area_count == 1) ? "linear" : seg->segtype->name; 35 } 36 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 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 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 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 */ 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 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 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 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 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 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