Changeset 8b51009 in mainline
- Timestamp:
- 2025-03-28T23:37:16Z (3 months ago)
- Children:
- 0437dd5
- Parents:
- 7bfe468
- git-author:
- Miroslav Cimerman <mc@…> (2025-03-28 23:25:57)
- git-committer:
- Miroslav Cimerman <mc@…> (2025-03-28 23:37:16)
- Location:
- uspace
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/hrctl/hrctl.c
r7bfe468 r8b51009 1 1 /* 2 * Copyright (c) 202 4Miroslav Cimerman2 * Copyright (c) 2025 Miroslav Cimerman 3 3 * All rights reserved. 4 4 * … … 45 45 #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" 46 46 47 static void 48 static errno_t 49 static errno_t 47 static void usage(void); 48 static errno_t fill_config_devs(int, char **, int, hr_config_t *); 49 static errno_t load_config(const char *, hr_config_t *); 50 50 51 51 static const char usage_str[] = … … 53 53 "\n" 54 54 "Options:\n" 55 " -h, --help display this helpand exit\n"55 " -h, --help display this message and exit\n" 56 56 " -C, --create-file=PATH create an array from file,\n" 57 57 " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n" 58 " -A, --a ssemble-file=PATH create an array from file\n"58 " -A, --auto-assemble try to auto assemble all valid arrays\n" 59 59 " -s, --status display status of active arrays\n" 60 60 " -H, --hotspare=DEV add hotspare extent\n" … … 62 62 " -F, --fail-extent fail an extent, use with -D and set it before\n" 63 63 " -c, --create=NAME create new array\n" 64 " -a, --assemble=NAME assemble an existing array\n"64 " -a, --assemble=NAME assemble from specified extents\n" 65 65 " -n non-zero number of devices\n" 66 66 " -l, --level=LEVEL set the RAID level,\n" … … 95 95 { "level", required_argument, 0, 'l' }, 96 96 { "create-file", required_argument, 0, 'C' }, 97 { "a ssemble-file", required_argument, 0, 'A' },97 { "auto-assemble", no_argument, 0, 'A' }, 98 98 { "destroy", required_argument, 0, 'D' }, 99 99 { "fail-extent", required_argument, 0, 'F' }, … … 253 253 254 254 while (c != -1) { 255 c = getopt_long(argc, argv, "hsC:c:A :a:l:0145Ln:D:F:H:",255 c = getopt_long(argc, argv, "hsC:c:Aa:l:0145Ln:D:F:H:", 256 256 long_options, NULL); 257 257 switch (c) { … … 282 282 break; 283 283 case 'A': 284 rc = load_config(optarg, cfg); 285 if (rc != EOK) { 286 printf("hrctl: failed to load config\n"); 287 free(cfg); 288 return 1; 289 } 290 assemble = true; 291 goto skip; 284 size_t cnt; 285 rc = hr_auto_assemble(&cnt); 286 if (rc != EOK) { 287 /* XXX: here have own error codes */ 288 printf("hrctl: auto assemble rc: %s\n", 289 str_error(rc)); 290 } else { 291 printf("hrctl: auto assembled %lu volumes\n", 292 cnt); 293 } 294 return rc; 292 295 case 'a': 293 296 if (str_size(optarg) > sizeof(cfg->devname) - 1) { … … 303 306 free(cfg); 304 307 if (rc != EOK) { 305 if (rc == ENOENT) 306 printf("hrctl: service named \"%s\" does not exist\n", 307 optarg); 308 return 1; 308 printf("hrctl: got %s\n", str_error(rc)); 309 return rc; 309 310 } 310 311 return 0; -
uspace/lib/device/include/hr.h
r7bfe468 r8b51009 118 118 extern void hr_sess_destroy(hr_t *); 119 119 extern errno_t hr_create(hr_t *, hr_config_t *, bool); 120 extern errno_t hr_auto_assemble(size_t *); 120 121 extern errno_t hr_stop(const char *, long); 121 122 extern errno_t hr_add_hotspare(service_id_t, service_id_t); -
uspace/lib/device/include/ipc/hr.h
r7bfe468 r8b51009 1 1 /* 2 * Copyright (c) 202 4Miroslav Cimerman2 * Copyright (c) 2025 Miroslav Cimerman 3 3 * All rights reserved. 4 4 * … … 41 41 HR_CREATE = IPC_FIRST_USER_METHOD, 42 42 HR_ASSEMBLE, 43 HR_AUTO_ASSEMBLE, 43 44 HR_STOP, 44 45 HR_ADD_HOTSPARE, -
uspace/lib/device/src/hr.c
r7bfe468 r8b51009 115 115 } 116 116 117 errno_t hr_auto_assemble(size_t *rassembled_cnt) 118 { 119 hr_t *hr; 120 errno_t rc; 121 size_t assembled_cnt; 122 123 rc = hr_sess_init(&hr); 124 if (rc != EOK) 125 return rc; 126 127 async_exch_t *exch = async_exchange_begin(hr->sess); 128 if (exch == NULL) { 129 rc = EINVAL; 130 goto error; 131 } 132 133 aid_t req = async_send_0(exch, HR_AUTO_ASSEMBLE, NULL); 134 135 rc = async_data_read_start(exch, &assembled_cnt, sizeof(size_t)); 136 if (rc != EOK) { 137 async_exchange_end(exch); 138 async_forget(req); 139 return rc; 140 } 141 142 async_exchange_end(exch); 143 async_wait_for(req, &rc); 144 145 if (rassembled_cnt != NULL) 146 *rassembled_cnt = assembled_cnt; 147 error: 148 hr_sess_destroy(hr); 149 return rc; 150 } 151 117 152 static errno_t print_vol_info(size_t index, hr_vol_info_t *vol_info) 118 153 { … … 218 253 rc = async_req_2_0(exch, HR_STOP, svc_id, extent); 219 254 async_exchange_end(exch); 220 221 if (rc != EOK)222 goto error;223 255 error: 224 256 hr_sess_destroy(hr); -
uspace/srv/bd/hr/hr.c
r7bfe468 r8b51009 59 59 60 60 loc_srv_t *hr_srv; 61 62 static fibril_mutex_t hr_volumes_lock; 63 static list_t hr_volumes; 61 list_t hr_volumes; 62 fibril_rwlock_t hr_volumes_lock; 64 63 65 64 static service_id_t ctl_sid; 66 65 67 static hr_volume_t *hr_get_volume(service_id_t svc_id)68 { 69 HR_DEBUG(" hr_get_volume(): (%" PRIun ")\n", svc_id);70 71 fibril_mutex_lock(&hr_volumes_lock);72 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {73 if (vol->svc_id == svc_id) {74 fibril_mutex_unlock(&hr_volumes_lock);75 return vol; 76 }77 }78 79 fibril_mutex_unlock(&hr_volumes_lock);80 return NULL; 81 } 82 83 static errno_t hr_remove_volume(service_id_t svc_id) 84 { 85 HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); 86 87 fibril_mutex_lock(&hr_volumes_lock);88 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) {89 if (vol->svc_id == svc_id) {90 hr_fpool_destroy(vol->fge);91 hr_fini_devs(vol);92 list_remove(&vol->lvolumes); 93 free(vol);94 fibril_mutex_unlock(&hr_volumes_lock);95 return EOK;96 }97 }98 99 fibril_mutex_unlock(&hr_volumes_lock); 100 return ENOENT;66 static void hr_auto_assemble_srv(ipc_call_t *icall) 67 { 68 HR_DEBUG("%s()", __func__); 69 70 errno_t rc; 71 size_t size; 72 size_t assembled_cnt = 0; 73 ipc_call_t call; 74 75 if (!async_data_read_receive(&call, &size)) { 76 async_answer_0(icall, EREFUSED); 77 return; 78 } 79 80 if (size != sizeof(size_t)) { 81 async_answer_0(icall, EINVAL); 82 return; 83 } 84 85 rc = hr_util_try_auto_assemble(&assembled_cnt); 86 if (rc != EOK) { 87 async_answer_0(&call, rc); 88 async_answer_0(icall, rc); 89 return; 90 } 91 92 rc = async_data_read_finalize(&call, &assembled_cnt, size); 93 if (rc != EOK) { 94 async_answer_0(&call, rc); 95 async_answer_0(icall, rc); 96 return; 97 } 98 99 async_answer_0(icall, EOK); 101 100 } 102 101 … … 154 153 } 155 154 156 new_volume = calloc(1, sizeof(hr_volume_t));157 if ( new_volume == NULL) {155 rc = hr_create_vol_struct(&new_volume, cfg->level); 156 if (rc != EOK) { 158 157 free(cfg); 159 async_answer_0(icall, ENOMEM); 160 return; 161 } 162 163 hr_fpool_t *fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); 164 if (fge == NULL) { 165 free(new_volume); 166 free(cfg); 167 async_answer_0(icall, ENOMEM); 168 return; 169 } 170 new_volume->fge = fge; 158 async_answer_0(icall, rc); 159 return; 160 } 171 161 172 162 str_cpy(new_volume->devname, HR_DEVNAME_LEN, cfg->devname); … … 176 166 new_volume->extent_no = cfg->dev_no; 177 167 178 if (assemble) {179 if (cfg->level != HR_LVL_UNKNOWN)180 HR_WARN("level manually set when assembling, ingoring");181 new_volume->level = HR_LVL_UNKNOWN;182 }183 184 168 rc = hr_init_devs(new_volume); 185 169 if (rc != EOK) { … … 188 172 async_answer_0(icall, rc); 189 173 return; 174 } 175 176 if (assemble) { 177 if (cfg->level != HR_LVL_UNKNOWN) 178 HR_DEBUG("level manually set when assembling, ingoring"); 179 new_volume->level = HR_LVL_UNKNOWN; 190 180 } 191 181 … … 201 191 } 202 192 203 switch (new_volume->level) {204 case HR_LVL_1:205 if (!assemble)206 new_volume->layout = 0x00; /* XXX: yet unused */207 new_volume->hr_ops.create = hr_raid1_create;208 new_volume->hr_ops.init = hr_raid1_init;209 new_volume->hr_ops.status_event = hr_raid1_status_event;210 new_volume->hr_ops.add_hotspare = hr_raid1_add_hotspare;211 break;212 case HR_LVL_0:213 if (!assemble)214 new_volume->layout = 0x00;215 new_volume->hr_ops.create = hr_raid0_create;216 new_volume->hr_ops.init = hr_raid0_init;217 new_volume->hr_ops.status_event = hr_raid0_status_event;218 break;219 case HR_LVL_4:220 if (!assemble)221 new_volume->layout = HR_RLQ_RAID4_N;222 new_volume->hr_ops.create = hr_raid5_create;223 new_volume->hr_ops.init = hr_raid5_init;224 new_volume->hr_ops.status_event = hr_raid5_status_event;225 new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare;226 break;227 case HR_LVL_5:228 if (!assemble)229 new_volume->layout = HR_RLQ_RAID5_NR;230 new_volume->hr_ops.create = hr_raid5_create;231 new_volume->hr_ops.init = hr_raid5_init;232 new_volume->hr_ops.status_event = hr_raid5_status_event;233 new_volume->hr_ops.add_hotspare = hr_raid5_add_hotspare;234 break;235 default:236 HR_DEBUG("unkown level: %d, aborting\n", new_volume->level);237 rc = EINVAL;238 goto error;239 }240 241 193 if (!assemble) { 242 194 new_volume->hr_ops.init(new_volume); … … 249 201 } 250 202 251 fibril_mutex_initialize(&new_volume->lock); /* XXX: will remove this */252 253 fibril_rwlock_initialize(&new_volume->extents_lock);254 fibril_rwlock_initialize(&new_volume->states_lock);255 256 fibril_mutex_initialize(&new_volume->hotspare_lock);257 258 list_initialize(&new_volume->range_lock_list);259 fibril_mutex_initialize(&new_volume->range_lock_list_lock);260 261 atomic_init(&new_volume->rebuild_blk, 0);262 atomic_init(&new_volume->state_dirty, false);263 264 203 rc = new_volume->hr_ops.create(new_volume); 265 204 if (rc != EOK) 266 205 goto error; 267 206 268 fibril_ mutex_lock(&hr_volumes_lock);207 fibril_rwlock_write_lock(&hr_volumes_lock); 269 208 list_append(&new_volume->lvolumes, &hr_volumes); 270 fibril_ mutex_unlock(&hr_volumes_lock);209 fibril_rwlock_write_unlock(&hr_volumes_lock); 271 210 272 211 if (assemble) { … … 283 222 error: 284 223 free(cfg); 285 free(fge); 286 hr_fini_devs(new_volume); 287 free(new_volume); 224 hr_destroy_vol_struct(new_volume); 288 225 async_answer_0(icall, rc); 289 226 } … … 313 250 return; 314 251 } 315 rc = loc_service_unregister(hr_srv, svc_id);316 252 } else { 317 253 fibril_rwlock_write_lock(&vol->states_lock); … … 370 306 size_t size; 371 307 372 fibril_ mutex_lock(&hr_volumes_lock);308 fibril_rwlock_read_lock(&hr_volumes_lock); 373 309 374 310 vol_cnt = list_count(&hr_volumes); … … 419 355 } 420 356 421 fibril_ mutex_unlock(&hr_volumes_lock);357 fibril_rwlock_read_unlock(&hr_volumes_lock); 422 358 async_answer_0(icall, EOK); 423 359 return; 424 360 error: 425 fibril_ mutex_unlock(&hr_volumes_lock);361 fibril_rwlock_read_unlock(&hr_volumes_lock); 426 362 async_answer_0(&call, rc); 427 363 async_answer_0(icall, rc); … … 450 386 case HR_ASSEMBLE: 451 387 hr_create_srv(&call, true); 388 break; 389 case HR_AUTO_ASSEMBLE: 390 hr_auto_assemble_srv(&call); 452 391 break; 453 392 case HR_STOP: … … 497 436 } 498 437 499 fibril_ mutex_initialize(&hr_volumes_lock);438 fibril_rwlock_initialize(&hr_volumes_lock); 500 439 list_initialize(&hr_volumes); 501 440 -
uspace/srv/bd/hr/superblock.c
r7bfe468 r8b51009 52 52 static errno_t read_metadata(service_id_t, hr_metadata_t *); 53 53 static errno_t hr_fill_meta_from_vol(hr_volume_t *, hr_metadata_t *); 54 static errno_t validate_meta(hr_metadata_t *);55 54 56 55 errno_t hr_write_meta_to_vol(hr_volume_t *vol) … … 71 70 goto error; 72 71 72 /* rndgen */ 73 fibril_usleep(1000); 74 rc = uuid_generate(&uuid); 75 if (rc != EOK) 76 goto error; 77 78 /* XXX: for now we just copy byte by byte as "encoding" */ 79 memcpy(metadata->uuid, &uuid, sizeof(HR_UUID_LEN)); 80 /* uuid_encode(&uuid, metadata->uuid); */ 81 73 82 for (i = 0; i < vol->extent_no; i++) { 74 83 metadata->index = host2uint32_t_le(i); 75 76 rc = uuid_generate(&uuid);77 if (rc != EOK)78 goto error;79 uuid_encode(&uuid, metadata->uuid);80 84 81 85 rc = block_write_direct(vol->extents[i].svc_id, HR_META_OFF, … … 84 88 goto error; 85 89 86 /* rndgen */87 fibril_usleep(1000);88 90 } 89 91 error: … … 100 102 uuid_t uuid; 101 103 104 /* XXX: use scratchpad */ 102 105 metadata = calloc(1, HR_META_SIZE * vol->bsize); 103 106 if (metadata == NULL) … … 152 155 } 153 156 154 metadata->magic = host2uint64_t_le(HR_MAGIC); 155 metadata->version = host2uint32_t_le(~(0U)); /* unused */ 157 /* XXX: use scratchpad */ 158 str_cpy(metadata->magic, HR_MAGIC_SIZE, HR_MAGIC_STR); 159 metadata->nblocks = host2uint64_t_le(vol->nblocks); 160 metadata->data_blkno = host2uint64_t_le(vol->data_blkno); 161 metadata->truncated_blkno = host2uint64_t_le(vol->truncated_blkno); 162 metadata->data_offset = host2uint64_t_le(vol->data_offset); 163 metadata->counter = host2uint64_t_le(~(0UL)); /* XXX: unused */ 164 metadata->version = host2uint32_t_le(~(0U)); /* XXX: unused */ 156 165 metadata->extent_no = host2uint32_t_le(vol->extent_no); 157 166 /* index filled separately for each extent */ … … 159 168 metadata->layout = host2uint32_t_le(vol->layout); 160 169 metadata->strip_size = host2uint32_t_le(vol->strip_size); 161 metadata->nblocks = host2uint64_t_le(vol->nblocks); 162 metadata->data_blkno = host2uint64_t_le(vol->data_blkno); 163 metadata->data_offset = host2uint64_t_le(vol->data_offset); 164 metadata->counter = host2uint64_t_le(~(0UL)); /* unused */ 165 /* UUID generated separately for each extent */ 170 metadata->bsize = host2uint32_t_le(vol->bsize); 166 171 str_cpy(metadata->devname, HR_DEVNAME_LEN, vol->devname); 167 172 … … 169 174 } 170 175 171 static errno_t validate_meta(hr_metadata_t *md) 172 { 173 if (uint64_t_le2host(md->magic) != HR_MAGIC) { 174 HR_ERROR("invalid magic\n"); 175 return EINVAL; 176 } 177 return EOK; 176 bool hr_valid_md_magic(hr_metadata_t *md) 177 { 178 if (str_lcmp(md->magic, HR_MAGIC_STR, HR_MAGIC_SIZE) != 0) 179 return false; 180 181 return true; 178 182 } 179 183 … … 203 207 if (rc != EOK) 204 208 goto end; 205 rc = validate_meta(metadata); 206 if (rc != EOK) 209 if (!hr_valid_md_magic(metadata)) 207 210 goto end; 208 211 md_order_indices[i] = uint32_t_le2host(metadata->index); … … 244 247 vol->data_blkno = uint64_t_le2host(metadata->data_blkno); 245 248 vol->data_offset = uint64_t_le2host(metadata->data_offset); 249 vol->bsize = uint32_t_le2host(metadata->bsize); 246 250 vol->counter = uint64_t_le2host(0x00); /* unused */ 247 251 … … 274 278 } 275 279 280 errno_t hr_get_metadata_block(service_id_t dev, void **rblock) 281 { 282 HR_DEBUG("%s()", __func__); 283 errno_t rc; 284 uint64_t blkno; 285 size_t bsize; 286 void *block; 287 288 rc = block_get_bsize(dev, &bsize); 289 if (rc != EOK) 290 return rc; 291 292 if (bsize < sizeof(hr_metadata_t)) 293 return EINVAL; 294 295 rc = block_get_nblocks(dev, &blkno); 296 if (rc != EOK) 297 return rc; 298 299 if (blkno < HR_META_OFF + HR_META_SIZE) 300 return EINVAL; 301 302 block = malloc(bsize); 303 if (block == NULL) 304 return ENOMEM; 305 306 rc = block_read_direct(dev, HR_META_OFF, HR_META_SIZE, block); 307 if (rc != EOK) { 308 free(block); 309 return rc; 310 } 311 312 if (rblock == NULL) { 313 free(block); 314 return EINVAL; 315 } 316 317 *rblock = block; 318 return EOK; 319 } 320 321 void hr_decode_metadata_from_block(void *block, hr_metadata_t *metadata) 322 { 323 /* 324 * Use scratch metadata for easier decoding without the need 325 * for manualy specifying offsets. 326 */ 327 hr_metadata_t scratch_md; 328 memcpy(&scratch_md, block, sizeof(hr_metadata_t)); 329 330 memcpy(metadata->magic, scratch_md.magic, HR_MAGIC_SIZE); 331 memcpy(metadata->uuid, scratch_md.uuid, HR_UUID_LEN); 332 metadata->nblocks = uint64_t_le2host(scratch_md.nblocks); 333 metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno); 334 metadata->truncated_blkno = uint64_t_le2host( 335 scratch_md.truncated_blkno); 336 metadata->data_offset = uint64_t_le2host(scratch_md.data_offset); 337 metadata->counter = uint64_t_le2host(scratch_md.counter); 338 metadata->version = uint32_t_le2host(scratch_md.version); 339 metadata->extent_no = uint32_t_le2host(scratch_md.extent_no); 340 metadata->index = uint32_t_le2host(scratch_md.index); 341 metadata->level = uint32_t_le2host(scratch_md.level); 342 metadata->layout = uint32_t_le2host(scratch_md.layout); 343 metadata->strip_size = uint32_t_le2host(scratch_md.strip_size); 344 metadata->bsize = uint64_t_le2host(scratch_md.bsize); 345 memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN); 346 } 347 348 void hr_metadata_dump(hr_metadata_t *metadata) 349 { 350 printf("\tmagic: %s\n", metadata->magic); 351 printf("\tUUID: "); 352 for (size_t i = 0; i < HR_UUID_LEN; ++i) { 353 printf("%.2X", metadata->uuid[i]); 354 if (i + 1 < HR_UUID_LEN) 355 printf(" "); 356 } 357 printf("\n"); 358 printf("\tnblocks: %lu\n", metadata->nblocks); 359 printf("\tdata_blkno: %lu\n", metadata->data_blkno); 360 printf("\ttruncated_blkno: %lu\n", metadata->truncated_blkno); 361 printf("\tdata_offset: %lu\n", metadata->data_offset); 362 printf("\tcounter: %lu\n", metadata->counter); 363 printf("\tversion: %u\n", metadata->version); 364 printf("\textent_no: %u\n", metadata->extent_no); 365 printf("\tindex: %u\n", metadata->index); 366 printf("\tlevel: %u\n", metadata->level); 367 printf("\tlayout: %u\n", metadata->layout); 368 printf("\tstrip_size: %u\n", metadata->strip_size); 369 printf("\tdevname: %s\n", metadata->devname); 370 } 371 276 372 /** @} 277 373 */ -
uspace/srv/bd/hr/superblock.h
r7bfe468 r8b51009 1 1 /* 2 * Copyright (c) 202 4Miroslav Cimerman2 * Copyright (c) 2025 Miroslav Cimerman 3 3 * All rights reserved. 4 4 * … … 39 39 #include "var.h" 40 40 41 #define HR_META_SIZE 42 #define HR_META_OFF 43 #define HR_DATA_OFF (HR_META_SIZE + HR_META_OFF)41 #define HR_META_SIZE 1 /* in blocks */ 42 #define HR_META_OFF 7 /* in blocks */ 43 #define HR_DATA_OFF (HR_META_OFF + HR_META_SIZE) 44 44 45 #define HR_MAGIC 0x4420492041205248LLU 46 #define HR_UUID_LEN 16 45 #define HR_MAGIC_STR "HelenRAID" 46 #define HR_MAGIC_SIZE 16 47 #define HR_UUID_LEN 16 48 /* #define HR_METADATA_VERSION 0 */ 47 49 48 typedef struct hr_metadata { 49 uint64_t magic; 50 uint32_t version; /* unused XXX */ 51 uint32_t extent_no; 50 typedef struct hr_metadata hr_metadata_t; 51 typedef struct hr_volume hr_volume_t; 52 52 53 uint32_t index; /* index of disk in array */ 54 uint32_t level; 55 uint32_t layout; 56 uint32_t strip_size; 53 struct hr_metadata { 54 char magic[HR_MAGIC_SIZE]; 57 55 58 uint64_t nblocks; /* all blocks */ 59 uint64_t data_blkno; /* usable blocks */ 56 uint8_t uuid[HR_UUID_LEN]; 60 57 61 uint64_t data_offset; /* block where data starts */ 58 /* TODO: change to blkno */ 59 uint64_t nblocks; /* all blocks */ 60 uint64_t data_blkno; /* usable blocks */ 62 61 63 uint64_t counter; /* unused */ 62 uint64_t truncated_blkno; /* usable blocks */ 63 uint64_t data_offset; 64 64 65 uint8_t uuid[HR_UUID_LEN]; 65 uint64_t counter; /* yet unused */ 66 uint32_t version; /* yet unused */ 67 uint32_t extent_no; 66 68 67 char devname[HR_DEVNAME_LEN]; 68 } hr_metadata_t; 69 uint32_t index; /* index of extent in volume */ 70 uint32_t level; 71 uint32_t layout; 72 uint32_t strip_size; 69 73 70 extern errno_t hr_write_meta_to_vol(hr_volume_t *); 71 extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); 72 extern errno_t hr_fill_vol_from_meta(hr_volume_t *); 74 uint32_t bsize; 75 76 char devname[HR_DEVNAME_LEN]; 77 }; 78 79 extern errno_t hr_write_meta_to_vol(hr_volume_t *); 80 extern errno_t hr_write_meta_to_ext(hr_volume_t *, size_t); 81 extern errno_t hr_fill_vol_from_meta(hr_volume_t *); 82 extern errno_t hr_get_metadata_block(service_id_t, void **); 83 extern void hr_decode_metadata_from_block(void *, hr_metadata_t *); 84 extern void hr_metadata_dump(hr_metadata_t *); 85 extern bool hr_valid_md_magic(hr_metadata_t *); 73 86 74 87 #endif -
uspace/srv/bd/hr/util.c
r7bfe468 r8b51009 41 41 #include <io/log.h> 42 42 #include <loc.h> 43 #include <mem.h> 43 44 #include <stdatomic.h> 44 45 #include <stdlib.h> 45 46 #include <stdio.h> 46 47 #include <str_error.h> 47 48 #include <vbd.h> 49 50 #include "io.h" 51 #include "superblock.h" 48 52 #include "util.h" 49 53 #include "var.h" … … 56 60 57 61 extern loc_srv_t *hr_srv; 62 extern list_t hr_volumes; 63 extern fibril_rwlock_t hr_volumes_lock; 64 65 errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) 66 { 67 errno_t rc; 68 69 hr_volume_t *vol = calloc(1, sizeof(hr_volume_t)); 70 if (vol == NULL) 71 return ENOMEM; 72 73 vol->level = level; 74 75 switch (level) { 76 case HR_LVL_1: 77 vol->hr_ops.create = hr_raid1_create; 78 vol->hr_ops.init = hr_raid1_init; 79 vol->hr_ops.status_event = hr_raid1_status_event; 80 vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; 81 break; 82 case HR_LVL_0: 83 vol->hr_ops.create = hr_raid0_create; 84 vol->hr_ops.init = hr_raid0_init; 85 vol->hr_ops.status_event = hr_raid0_status_event; 86 break; 87 case HR_LVL_4: 88 vol->hr_ops.create = hr_raid5_create; 89 vol->hr_ops.init = hr_raid5_init; 90 vol->hr_ops.status_event = hr_raid5_status_event; 91 vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; 92 break; 93 case HR_LVL_5: 94 vol->hr_ops.create = hr_raid5_create; 95 vol->hr_ops.init = hr_raid5_init; 96 vol->hr_ops.status_event = hr_raid5_status_event; 97 vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; 98 break; 99 default: 100 HR_DEBUG("unkown level: %d, aborting\n", vol->level); 101 rc = EINVAL; 102 goto error; 103 } 104 105 vol->fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); 106 if (vol->fge == NULL) { 107 rc = ENOMEM; 108 goto error; 109 } 110 111 vol->status = HR_VOL_NONE; 112 113 for (size_t i = 0; i < HR_MAX_EXTENTS; ++i) 114 vol->extents[i].status = HR_EXT_MISSING; 115 116 for (size_t i = 0; i < HR_MAX_HOTSPARES; ++i) 117 vol->extents[i].status = HR_EXT_MISSING; 118 119 fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ 120 121 fibril_rwlock_initialize(&vol->extents_lock); 122 fibril_rwlock_initialize(&vol->states_lock); 123 124 fibril_mutex_initialize(&vol->hotspare_lock); 125 126 list_initialize(&vol->range_lock_list); 127 fibril_mutex_initialize(&vol->range_lock_list_lock); 128 129 atomic_init(&vol->rebuild_blk, 0); 130 atomic_init(&vol->state_dirty, false); 131 atomic_init(&vol->open_cnt, 0); 132 133 *rvol = vol; 134 135 return EOK; 136 error: 137 free(vol); 138 return rc; 139 } 140 141 void hr_destroy_vol_struct(hr_volume_t *vol) 142 { 143 if (vol == NULL) 144 return; 145 146 hr_fpool_destroy(vol->fge); 147 hr_fini_devs(vol); 148 free(vol->in_mem_md); 149 free(vol); 150 } 151 152 hr_volume_t *hr_get_volume(service_id_t svc_id) 153 { 154 HR_DEBUG("hr_get_volume(): (%" PRIun ")\n", svc_id); 155 156 hr_volume_t *rvol = NULL; 157 158 fibril_rwlock_read_lock(&hr_volumes_lock); 159 list_foreach(hr_volumes, lvolumes, hr_volume_t, iter) { 160 if (iter->svc_id == svc_id) { 161 rvol = iter; 162 break; 163 } 164 } 165 166 fibril_rwlock_read_unlock(&hr_volumes_lock); 167 return rvol; 168 } 169 170 errno_t hr_remove_volume(service_id_t svc_id) 171 { 172 HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); 173 174 errno_t rc; 175 176 fibril_rwlock_write_lock(&hr_volumes_lock); 177 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { 178 if (vol->svc_id == svc_id) { 179 int open_cnt = atomic_load_explicit(&vol->open_cnt, 180 memory_order_relaxed); 181 /* 182 * The "atomicity" of this if condition is provided 183 * by the write lock - no new bd connection can 184 * come, because we need to get the bd_srvs_t from 185 * volume, which we get from the list. 186 * (see hr_client_conn() in hr.c) 187 */ 188 if (open_cnt > 0) { 189 fibril_rwlock_write_unlock(&hr_volumes_lock); 190 return EBUSY; 191 } 192 list_remove(&vol->lvolumes); 193 fibril_rwlock_write_unlock(&hr_volumes_lock); 194 195 hr_destroy_vol_struct(vol); 196 197 rc = loc_service_unregister(hr_srv, svc_id); 198 return rc; 199 } 200 } 201 202 fibril_rwlock_write_unlock(&hr_volumes_lock); 203 return ENOENT; 204 } 58 205 59 206 errno_t hr_init_devs(hr_volume_t *vol) … … 419 566 } 420 567 568 struct svc_id_linked { 569 link_t link; 570 service_id_t svc_id; 571 hr_metadata_t *md; 572 bool inited; 573 bool md_present; 574 }; 575 576 static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, 577 bool inited, hr_metadata_t *md) 578 { 579 errno_t rc = EOK; 580 struct svc_id_linked *to_add; 581 582 to_add = malloc(sizeof(struct svc_id_linked)); 583 if (to_add == NULL) { 584 rc = ENOMEM; 585 goto error; 586 } 587 to_add->svc_id = svc_id; 588 to_add->inited = inited; 589 590 if (md != NULL) { 591 to_add->md = malloc(sizeof(hr_metadata_t)); 592 if (to_add->md == NULL) { 593 rc = ENOMEM; 594 goto error; 595 } 596 to_add->md_present = true; 597 memcpy(to_add->md, md, sizeof(*md)); 598 } else { 599 to_add->md_present = false; 600 } 601 602 list_append(&to_add->link, list); 603 604 error: 605 return rc; 606 } 607 608 static void free_svc_id_linked(struct svc_id_linked *p) 609 { 610 if (p->md_present) 611 free(p->md); 612 free(p); 613 } 614 615 static void free_svc_id_list(list_t *list) 616 { 617 struct svc_id_linked *dev_id; 618 while (!list_empty(list)) { 619 dev_id = list_pop(list, struct svc_id_linked, link); 620 free_svc_id_linked(dev_id); 621 } 622 } 623 624 static errno_t hr_fill_disk_part_svcs_list(list_t *list) 625 { 626 errno_t rc; 627 size_t disk_count; 628 service_id_t *disk_svcs = NULL; 629 vbd_t *vbd = NULL; 630 631 rc = vbd_create(&vbd); 632 if (rc != EOK) 633 goto error; 634 635 rc = vbd_get_disks(vbd, &disk_svcs, &disk_count); 636 if (rc != EOK) 637 goto error; 638 639 for (size_t i = 0; i < disk_count; i++) { 640 vbd_disk_info_t disk_info; 641 rc = vbd_disk_info(vbd, disk_svcs[i], &disk_info); 642 if (rc != EOK) 643 goto error; 644 645 if (disk_info.ltype == lt_none) { 646 rc = hr_add_svc_linked_to_list(list, disk_svcs[i], false, NULL); 647 if (rc != EOK) 648 goto error; 649 } else { 650 size_t part_count; 651 service_id_t *part_ids = NULL; 652 rc = vbd_label_get_parts(vbd, disk_svcs[i], &part_ids, &part_count); 653 if (rc != EOK) 654 goto error; 655 656 for (size_t j = 0; j < part_count; j++) { 657 vbd_part_info_t part_info; 658 rc = vbd_part_get_info(vbd, part_ids[j], &part_info); 659 if (rc != EOK) { 660 free(part_ids); 661 goto error; 662 } 663 664 rc = hr_add_svc_linked_to_list(list, 665 part_info.svc_id, false, NULL); 666 if (rc != EOK) { 667 free(part_ids); 668 goto error; 669 } 670 } 671 672 free(part_ids); 673 } 674 } 675 676 free(disk_svcs); 677 vbd_destroy(vbd); 678 return EOK; 679 error: 680 free_svc_id_list(list); 681 if (disk_svcs != NULL) 682 free(disk_svcs); 683 vbd_destroy(vbd); 684 685 return rc; 686 } 687 688 static errno_t block_init_dev_list(list_t *list) 689 { 690 list_foreach_safe(*list, cur_link, next_link) { 691 struct svc_id_linked *iter; 692 iter = list_get_instance(cur_link, struct svc_id_linked, link); 693 694 if (iter->inited) 695 continue; 696 697 errno_t rc = block_init(iter->svc_id); 698 699 /* already used as an extent of active volume */ 700 /* XXX: figure out how it is with hotspares too */ 701 if (rc == EEXIST) { 702 list_remove(cur_link); 703 free_svc_id_linked(iter); 704 continue; 705 } 706 707 if (rc != EOK) 708 return rc; 709 710 iter->inited = true; 711 } 712 713 return EOK; 714 } 715 716 static void block_fini_dev_list(list_t *list) 717 { 718 list_foreach(*list, link, struct svc_id_linked, iter) { 719 if (iter->inited) { 720 block_fini(iter->svc_id); 721 iter->inited = false; 722 } 723 } 724 } 725 726 static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *devlist, 727 service_id_t svc_id, hr_metadata_t *md_main) 728 { 729 errno_t rc = EOK; 730 731 list_foreach(*devlist, link, struct svc_id_linked, iter) { 732 if (iter->svc_id == svc_id) 733 continue; 734 void *md_block; 735 hr_metadata_t md; 736 rc = hr_get_metadata_block(iter->svc_id, &md_block); 737 if (rc != EOK) 738 goto error; 739 hr_decode_metadata_from_block(md_block, &md); 740 741 free(md_block); 742 743 if (!hr_valid_md_magic(&md)) 744 continue; 745 746 if (memcmp(md_main->uuid, md.uuid, HR_UUID_LEN) != 0) 747 continue; 748 749 /* 750 * XXX: can I assume bsize and everything is fine when 751 * UUID matches? 752 */ 753 754 rc = hr_add_svc_linked_to_list(rlist, iter->svc_id, true, &md); 755 if (rc != EOK) 756 goto error; 757 } 758 759 return EOK; 760 error: 761 free_svc_id_list(rlist); 762 return rc; 763 } 764 765 static errno_t hr_util_assemble_from_matching_list(list_t *list) 766 { 767 HR_DEBUG("%s()", __func__); 768 769 errno_t rc = EOK; 770 771 hr_metadata_t *main_md = NULL; 772 size_t max_counter_val = 0; 773 774 list_foreach(*list, link, struct svc_id_linked, iter) { 775 hr_metadata_dump(iter->md); 776 if (iter->md->counter >= max_counter_val) { 777 max_counter_val = iter->md->counter; 778 main_md = iter->md; 779 } 780 } 781 782 assert(main_md != NULL); 783 784 hr_volume_t *vol; 785 rc = hr_create_vol_struct(&vol, (hr_level_t)main_md->level); 786 if (rc != EOK) 787 goto error; 788 789 vol->nblocks = main_md->nblocks; 790 vol->data_blkno = main_md->data_blkno; 791 vol->truncated_blkno = main_md->truncated_blkno; 792 vol->data_offset = main_md->data_offset; 793 vol->counter = main_md->counter; 794 vol->metadata_version = main_md->version; 795 vol->extent_no = main_md->extent_no; 796 vol->level = main_md->level; 797 vol->layout = main_md->layout; 798 vol->strip_size = main_md->strip_size; 799 vol->bsize = main_md->bsize; 800 memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); 801 802 list_foreach(*list, link, struct svc_id_linked, iter) { 803 vol->extents[iter->md->index].svc_id = iter->svc_id; 804 if (iter->md->counter == max_counter_val) 805 vol->extents[iter->md->index].status = HR_EXT_ONLINE; 806 else 807 vol->extents[iter->md->index].status = HR_EXT_INVALID; 808 } 809 810 rc = vol->hr_ops.create(vol); 811 if (rc != EOK) 812 goto error; 813 814 fibril_rwlock_write_lock(&hr_volumes_lock); 815 816 list_foreach(hr_volumes, lvolumes, hr_volume_t, other) { 817 uint8_t *our_uuid = vol->in_mem_md->uuid; 818 uint8_t *other_uuid = other->in_mem_md->uuid; 819 if (memcmp(our_uuid, other_uuid, HR_UUID_LEN) == 0) { 820 rc = EEXIST; 821 fibril_rwlock_write_unlock(&hr_volumes_lock); 822 goto error; 823 } 824 } 825 826 /* 827 * XXX: register it here 828 * ... if it fails on EEXIST try different name... like + 1 on the end 829 */ 830 831 list_append(&vol->lvolumes, &hr_volumes); 832 833 fibril_rwlock_write_unlock(&hr_volumes_lock); 834 835 return EOK; 836 error: 837 hr_destroy_vol_struct(vol); 838 return rc; 839 } 840 841 errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) 842 { 843 HR_DEBUG("%s()", __func__); 844 845 /* 846 * scan partitions or disks: 847 * 848 * When we find a metadata block with valid 849 * magic, take UUID and try to find other matching 850 * UUIDs. 851 * 852 * We ignore extents that are a part of already 853 * active volumes. (even when the counter is lower 854 * on active volumes... XXX: use timestamp as initial counter value 855 * when assembling, or writing dirty metadata?) 856 */ 857 858 size_t asm_cnt = 0; 859 errno_t rc; 860 list_t dev_id_list; 861 862 list_initialize(&dev_id_list); 863 rc = hr_fill_disk_part_svcs_list(&dev_id_list); 864 if (rc != EOK) 865 goto error; 866 867 rc = block_init_dev_list(&dev_id_list); 868 if (rc != EOK) 869 goto error; 870 871 struct svc_id_linked *iter; 872 while (!list_empty(&dev_id_list)) { 873 iter = list_pop(&dev_id_list, struct svc_id_linked, link); 874 875 printf("svc_id: %lu\n", iter->svc_id); 876 877 void *metadata_block; 878 hr_metadata_t metadata; 879 880 rc = hr_get_metadata_block(iter->svc_id, &metadata_block); 881 if (rc != EOK) 882 goto error; 883 884 hr_decode_metadata_from_block(metadata_block, &metadata); 885 886 free(metadata_block); 887 888 if (!hr_valid_md_magic(&metadata)) { 889 printf("BAD magic\n"); 890 block_fini(iter->svc_id); 891 free_svc_id_linked(iter); 892 continue; 893 } 894 895 hr_metadata_dump(&metadata); 896 897 char *svc_name = NULL; 898 rc = loc_service_get_name(iter->svc_id, &svc_name); 899 if (rc != EOK) 900 goto error; 901 902 HR_DEBUG("found valid metadata on %s, " 903 "will try to match other extents\n", svc_name); 904 905 free(svc_name); 906 907 list_t matching_svcs_list; 908 list_initialize(&matching_svcs_list); 909 910 rc = hr_util_get_matching_md_svcs_list(&matching_svcs_list, 911 &dev_id_list, iter->svc_id, &metadata); 912 if (rc != EOK) 913 goto error; 914 915 /* add current iter to list as well */ 916 rc = hr_add_svc_linked_to_list(&matching_svcs_list, 917 iter->svc_id, true, &metadata); 918 if (rc != EOK) { 919 free_svc_id_list(&matching_svcs_list); 920 goto error; 921 } 922 923 /* remove matching list members from dev_id_list */ 924 list_foreach(matching_svcs_list, link, struct svc_id_linked, 925 iter2) { 926 printf("matching svc_id: %lu\n", iter2->svc_id); 927 struct svc_id_linked *to_remove; 928 list_foreach_safe(dev_id_list, cur_link, next_link) { 929 to_remove = list_get_instance(cur_link, 930 struct svc_id_linked, link); 931 if (to_remove->svc_id == iter2->svc_id) { 932 list_remove(cur_link); 933 free_svc_id_linked(to_remove); 934 } 935 } 936 } 937 938 rc = hr_util_assemble_from_matching_list(&matching_svcs_list); 939 switch (rc) { 940 case EOK: 941 asm_cnt++; 942 break; 943 case EEXIST: 944 /* 945 * A race is detected this way, because we don't want 946 * to hold the hr_volumes list lock for a long time, 947 * for all assembly attempts. XXX: discuss... 948 */ 949 rc = EOK; 950 break; 951 default: 952 block_fini_dev_list(&matching_svcs_list); 953 free_svc_id_list(&matching_svcs_list); 954 goto error; 955 } 956 957 free_svc_id_list(&matching_svcs_list); 958 } 959 960 error: 961 if (rassembled_cnt != NULL) 962 *rassembled_cnt = asm_cnt; 963 964 block_fini_dev_list(&dev_id_list); 965 free_svc_id_list(&dev_id_list); 966 967 return rc; 968 } 969 421 970 /** @} 422 971 */ -
uspace/srv/bd/hr/util.h
r7bfe468 r8b51009 51 51 log_msg(LOG_DEFAULT, LVL_ERROR, format, ##__VA_ARGS__) 52 52 53 extern errno_t hr_init_devs(hr_volume_t *); 54 extern void hr_fini_devs(hr_volume_t *); 55 extern errno_t hr_register_volume(hr_volume_t *); 56 extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); 57 extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); 58 extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); 59 extern void hr_update_ext_status(hr_volume_t *, size_t, hr_ext_status_t); 60 extern void hr_update_hotspare_status(hr_volume_t *, size_t, hr_ext_status_t); 61 extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); 62 extern void hr_update_ext_svc_id(hr_volume_t *, size_t, service_id_t); 63 extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, service_id_t); 64 extern void hr_sync_all_extents(hr_volume_t *); 65 extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); 66 extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, 53 54 extern errno_t hr_create_vol_struct(hr_volume_t **, hr_level_t); 55 extern void hr_destroy_vol_struct(hr_volume_t *); 56 extern hr_volume_t *hr_get_volume(service_id_t); 57 extern errno_t hr_remove_volume(service_id_t); 58 extern errno_t hr_init_devs(hr_volume_t *); 59 extern void hr_fini_devs(hr_volume_t *); 60 extern errno_t hr_register_volume(hr_volume_t *); 61 extern errno_t hr_check_devs(hr_volume_t *, uint64_t *, size_t *); 62 extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t); 63 extern void hr_add_ba_offset(hr_volume_t *, uint64_t *); 64 extern void hr_update_ext_status(hr_volume_t *, size_t, 65 hr_ext_status_t); 66 extern void hr_update_hotspare_status(hr_volume_t *, size_t, 67 hr_ext_status_t); 68 extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t); 69 extern void hr_update_ext_svc_id(hr_volume_t *, size_t, 70 service_id_t); 71 extern void hr_update_hotspare_svc_id(hr_volume_t *, size_t, 72 service_id_t); 73 extern void hr_sync_all_extents(hr_volume_t *); 74 extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t); 75 extern void hr_mark_vol_state_dirty(hr_volume_t *); 76 extern void hr_range_lock_release(hr_range_lock_t *); 77 extern hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *, uint64_t, 67 78 uint64_t); 68 extern void hr_range_lock_release(hr_range_lock_t *); 69 extern void hr_mark_vol_state_dirty(hr_volume_t *); 79 extern errno_t hr_util_try_auto_assemble(size_t *); 70 80 71 81 #endif -
uspace/srv/bd/hr/var.h
r7bfe468 r8b51009 42 42 #include <fibril_synch.h> 43 43 #include <hr.h> 44 #include <stdatomic.h> 44 45 45 46 #include "fge.h" 47 #include "superblock.h" 46 48 47 49 #define NAME "hr" … … 50 52 struct hr_volume; 51 53 typedef struct hr_volume hr_volume_t; 54 typedef struct hr_metadata hr_metadata_t; 52 55 53 56 typedef struct hr_ops { … … 69 72 hr_fpool_t *fge; /* fibril pool */ 70 73 74 uint32_t metadata_version; /* XXX: yet unused */ 75 76 hr_metadata_t *in_mem_md; /* TODO: implement */ 77 71 78 /* invariants */ 72 79 size_t extent_no; /* number of extents */ 73 80 size_t bsize; /* block size */ 74 81 uint64_t nblocks; /* no. of all usable blocks */ 82 uint64_t truncated_blkno; /* blkno per extent */ 75 83 uint64_t data_blkno; /* no. of user usable blocks */ 76 84 uint64_t data_offset; /* user data offset in blocks */ … … 91 99 _Atomic bool state_dirty; /* dirty state */ 92 100 93 /* 94 * XXX: unportable for 32-bit? 95 * 96 * Add macros for locking or atomic increment depending 97 * on the platform? 98 */ 101 /* XXX: atomic_uint_least64_t? */ 99 102 _Atomic uint64_t rebuild_blk; /* rebuild position */ 103 _Atomic int open_cnt; /* open/close() counter */ 100 104 uint64_t counter; /* TODO: metadata syncing */ 101 105 hr_vol_status_t status; /* volume status */
Note:
See TracChangeset
for help on using the changeset viewer.