source: mainline/uspace/srv/bd/hr/metadata/native.c@ 15e51b05

Last change on this file since 15e51b05 was 15e51b05, checked in by Miroslav Cimerman <mc@…>, 3 months ago

hr: check extent number

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 * Copyright (c) 2025 Miroslav Cimerman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup hr
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <adt/list.h>
37#include <block.h>
38#include <byteorder.h>
39#include <errno.h>
40#include <inttypes.h>
41#include <io/log.h>
42#include <loc.h>
43#include <mem.h>
44#include <uuid.h>
45#include <stdlib.h>
46#include <stdio.h>
47#include <str.h>
48#include <types/uuid.h>
49
50#include "../io.h"
51#include "../util.h"
52#include "../var.h"
53
54#include "native.h"
55
56/* not exposed */
57static void *meta_native_alloc_struct(void);
58static void meta_native_encode(void *, void *);
59static errno_t meta_native_decode(const void *, void *);
60static errno_t meta_native_get_block(service_id_t, void **);
61static errno_t meta_native_write_block(service_id_t, const void *);
62static bool meta_native_has_valid_magic(const void *);
63
64static errno_t meta_native_probe(service_id_t, void **);
65static errno_t meta_native_init_vol2meta(hr_volume_t *);
66static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *);
67static errno_t meta_native_erase_block(service_id_t);
68static bool meta_native_compare_uuids(const void *, const void *);
69static void meta_native_inc_counter(hr_volume_t *);
70static errno_t meta_native_save(hr_volume_t *, bool);
71static errno_t meta_native_save_ext(hr_volume_t *, size_t, bool);
72static const char *meta_native_get_devname(const void *);
73static hr_level_t meta_native_get_level(const void *);
74static uint64_t meta_native_get_data_offset(void);
75static size_t meta_native_get_size(void);
76static uint8_t meta_native_get_flags(void);
77static hr_metadata_type_t meta_native_get_type(void);
78static void meta_native_dump(const void *);
79
80hr_superblock_ops_t metadata_native_ops = {
81 .probe = meta_native_probe,
82 .init_vol2meta = meta_native_init_vol2meta,
83 .init_meta2vol = meta_native_init_meta2vol,
84 .erase_block = meta_native_erase_block,
85 .compare_uuids = meta_native_compare_uuids,
86 .inc_counter = meta_native_inc_counter,
87 .save = meta_native_save,
88 .save_ext = meta_native_save_ext,
89 .get_devname = meta_native_get_devname,
90 .get_level = meta_native_get_level,
91 .get_data_offset = meta_native_get_data_offset,
92 .get_size = meta_native_get_size,
93 .get_flags = meta_native_get_flags,
94 .get_type = meta_native_get_type,
95 .dump = meta_native_dump
96};
97
98static errno_t meta_native_probe(service_id_t svc_id, void **rmd)
99{
100 errno_t rc;
101 void *meta_block;
102
103 void *metadata_struct = meta_native_alloc_struct();
104 if (metadata_struct == NULL)
105 return ENOMEM;
106
107 rc = meta_native_get_block(svc_id, &meta_block);
108 if (rc != EOK)
109 goto error;
110
111 rc = meta_native_decode(meta_block, metadata_struct);
112
113 free(meta_block);
114
115 if (rc != EOK)
116 goto error;
117
118 *rmd = metadata_struct;
119 return EOK;
120
121error:
122 free(metadata_struct);
123 return rc;
124}
125
126static errno_t meta_native_init_vol2meta(hr_volume_t *vol)
127{
128 HR_DEBUG("%s()", __func__);
129
130 hr_metadata_t *md = calloc(1, sizeof(*md));
131 if (md == NULL)
132 return ENOMEM;
133
134 str_cpy(md->magic, HR_NATIVE_MAGIC_SIZE, HR_NATIVE_MAGIC_STR);
135
136 md->version = HR_NATIVE_METADATA_VERSION;
137
138 md->counter = 0;
139
140 uuid_t uuid;
141 /* rndgen */
142 fibril_usleep(1000);
143 errno_t rc = uuid_generate(&uuid);
144 if (rc != EOK)
145 return rc;
146
147 memcpy(md->uuid, &uuid, HR_NATIVE_UUID_LEN);
148
149 md->data_blkno = vol->data_blkno;
150 md->truncated_blkno = vol->truncated_blkno;
151 md->extent_no = vol->extent_no;
152 md->level = vol->level;
153 md->layout = vol->layout;
154 md->strip_size = vol->strip_size;
155 md->bsize = vol->bsize;
156 memcpy(md->devname, vol->devname, HR_DEVNAME_LEN);
157
158 vol->in_mem_md = md;
159
160 return EOK;
161}
162
163static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol)
164{
165 HR_DEBUG("%s()", __func__);
166
167 hr_metadata_t *main_meta = NULL;
168 uint64_t max_counter_val = 0;
169
170 list_foreach(*list, link, struct dev_list_member, iter) {
171 hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md;
172 if (iter_meta->counter >= max_counter_val) {
173 max_counter_val = iter_meta->counter;
174 main_meta = iter_meta;
175 }
176 }
177
178 assert(main_meta != NULL);
179
180 vol->data_blkno = main_meta->data_blkno;
181 vol->truncated_blkno = main_meta->truncated_blkno;
182 vol->data_offset = meta_native_get_data_offset();
183 vol->extent_no = main_meta->extent_no;
184 /* vol->level = main_meta->level; */ /* already set */
185 vol->layout = main_meta->layout;
186 vol->strip_size = main_meta->strip_size;
187 vol->bsize = main_meta->bsize;
188 /* already set */
189 /* memcpy(vol->devname, main_meta->devname, HR_DEVNAME_LEN); */
190
191 if (vol->extent_no > HR_MAX_EXTENTS) {
192 HR_DEBUG("Assembled volume has %u extents (max = %u)",
193 (unsigned)vol->extent_no, HR_MAX_EXTENTS);
194 return EINVAL;
195 }
196
197 vol->in_mem_md = calloc(1, sizeof(hr_metadata_t));
198 if (vol->in_mem_md == NULL)
199 return ENOMEM;
200 memcpy(vol->in_mem_md, main_meta, sizeof(hr_metadata_t));
201
202 list_foreach(*list, link, struct dev_list_member, iter) {
203 hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md;
204
205 vol->extents[iter_meta->index].svc_id = iter->svc_id;
206 iter->fini = false;
207
208 hr_ext_state_t final_ext_state = HR_EXT_INVALID;
209 if (iter_meta->counter == max_counter_val) {
210 if (iter_meta->rebuild_pos > 0) {
211 final_ext_state = HR_EXT_REBUILD;
212 vol->rebuild_blk = iter_meta->rebuild_pos;
213 } else {
214 final_ext_state = HR_EXT_ONLINE;
215 }
216 }
217
218 vol->extents[iter_meta->index].state = final_ext_state;
219 }
220
221 for (size_t i = 0; i < vol->extent_no; i++) {
222 if (vol->extents[i].state == HR_EXT_NONE)
223 vol->extents[i].state = HR_EXT_MISSING;
224 }
225
226 return EOK;
227}
228
229static errno_t meta_native_erase_block(service_id_t dev)
230{
231 HR_DEBUG("%s()", __func__);
232
233 errno_t rc;
234 size_t bsize;
235
236 rc = block_get_bsize(dev, &bsize);
237 if (rc != EOK)
238 return rc;
239
240 void *zero_block = calloc(1, bsize);
241 if (zero_block == NULL)
242 return ENOMEM;
243
244 rc = meta_native_write_block(dev, zero_block);
245 return rc;
246}
247
248static bool meta_native_compare_uuids(const void *m1p, const void *m2p)
249{
250 const hr_metadata_t *m1 = m1p;
251 const hr_metadata_t *m2 = m2p;
252 if (memcmp(m1->uuid, m2->uuid, HR_NATIVE_UUID_LEN) == 0)
253 return true;
254
255 return false;
256}
257
258static void meta_native_inc_counter(hr_volume_t *vol)
259{
260 fibril_mutex_lock(&vol->md_lock);
261
262 hr_metadata_t *md = vol->in_mem_md;
263
264 md->counter++;
265
266 fibril_mutex_unlock(&vol->md_lock);
267}
268
269static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback)
270{
271 HR_DEBUG("%s()", __func__);
272
273 fibril_rwlock_read_lock(&vol->extents_lock);
274
275 for (size_t i = 0; i < vol->extent_no; i++)
276 meta_native_save_ext(vol, i, with_state_callback);
277
278 fibril_rwlock_read_unlock(&vol->extents_lock);
279
280 return EOK;
281}
282
283static errno_t meta_native_save_ext(hr_volume_t *vol, size_t ext_idx,
284 bool with_state_callback)
285{
286 HR_DEBUG("%s()", __func__);
287
288 assert(fibril_rwlock_is_locked(&vol->extents_lock));
289
290 void *md_block = hr_calloc_waitok(1, vol->bsize);
291
292 hr_metadata_t *md = (hr_metadata_t *)vol->in_mem_md;
293
294 hr_extent_t *ext = &vol->extents[ext_idx];
295
296 fibril_rwlock_read_lock(&vol->states_lock);
297 hr_ext_state_t s = ext->state;
298 fibril_rwlock_read_unlock(&vol->states_lock);
299
300 if (s != HR_EXT_ONLINE && s != HR_EXT_REBUILD) {
301 return EINVAL;
302 }
303
304 fibril_mutex_lock(&vol->md_lock);
305
306 md->index = ext_idx;
307 if (s == HR_EXT_REBUILD)
308 md->rebuild_pos = vol->rebuild_blk;
309 else
310 md->rebuild_pos = 0;
311 meta_native_encode(md, md_block);
312 errno_t rc = meta_native_write_block(ext->svc_id, md_block);
313 if (rc != EOK && with_state_callback)
314 vol->hr_ops.ext_state_cb(vol, ext_idx, rc);
315
316 fibril_mutex_unlock(&vol->md_lock);
317
318 if (with_state_callback)
319 vol->hr_ops.vol_state_eval(vol);
320
321 free(md_block);
322 return EOK;
323}
324
325static const char *meta_native_get_devname(const void *md_v)
326{
327 const hr_metadata_t *md = md_v;
328
329 return md->devname;
330}
331
332static hr_level_t meta_native_get_level(const void *md_v)
333{
334 const hr_metadata_t *md = md_v;
335
336 return md->level;
337}
338
339static uint64_t meta_native_get_data_offset(void)
340{
341 return HR_NATIVE_DATA_OFF;
342}
343
344static size_t meta_native_get_size(void)
345{
346 return HR_NATIVE_META_SIZE;
347}
348
349static uint8_t meta_native_get_flags(void)
350{
351 uint8_t flags = 0;
352
353 flags |= HR_METADATA_HOTSPARE_SUPPORT;
354 flags |= HR_METADATA_ALLOW_REBUILD;
355
356 return flags;
357}
358
359static hr_metadata_type_t meta_native_get_type(void)
360{
361 return HR_METADATA_NATIVE;
362}
363
364static void meta_native_dump(const void *md_v)
365{
366 HR_DEBUG("%s()", __func__);
367
368 const hr_metadata_t *metadata = md_v;
369
370 printf("\tmagic: %s\n", metadata->magic);
371 printf("\tUUID: ");
372 for (size_t i = 0; i < HR_NATIVE_UUID_LEN; ++i) {
373 printf("%.2X", metadata->uuid[i]);
374 if (i + 1 < HR_NATIVE_UUID_LEN)
375 printf(" ");
376 }
377 printf("\n");
378 printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno);
379 printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno);
380 printf("\tcounter: %" PRIu64 "\n", metadata->counter);
381 printf("\tversion: %" PRIu32 "\n", metadata->version);
382 printf("\textent_no: %" PRIu32 "\n", metadata->extent_no);
383 printf("\tindex: %" PRIu32 "\n", metadata->index);
384 printf("\tlevel: %" PRIu32 "\n", metadata->level);
385 printf("\tlayout: %" PRIu32 "\n", metadata->layout);
386 printf("\tstrip_size: %" PRIu32 "\n", metadata->strip_size);
387 printf("\tbsize: %" PRIu32 "\n", metadata->bsize);
388 printf("\tdevname: %s\n", metadata->devname);
389}
390
391static void *meta_native_alloc_struct(void)
392{
393 return calloc(1, sizeof(hr_metadata_t));
394}
395
396static void meta_native_encode(void *md_v, void *block)
397{
398 HR_DEBUG("%s()", __func__);
399
400 const hr_metadata_t *metadata = md_v;
401
402 /*
403 * Use scratch metadata for easier encoding without the need
404 * for manualy specifying offsets.
405 */
406 hr_metadata_t scratch_md;
407
408 memcpy(scratch_md.magic, metadata->magic, HR_NATIVE_MAGIC_SIZE);
409 memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN);
410
411 scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno);
412 scratch_md.truncated_blkno = host2uint64_t_le(
413 metadata->truncated_blkno);
414 scratch_md.counter = host2uint64_t_le(metadata->counter);
415 scratch_md.rebuild_pos = host2uint64_t_le(metadata->rebuild_pos);
416 scratch_md.version = host2uint32_t_le(metadata->version);
417 scratch_md.extent_no = host2uint32_t_le(metadata->extent_no);
418 scratch_md.index = host2uint32_t_le(metadata->index);
419 scratch_md.level = host2uint32_t_le(metadata->level);
420 scratch_md.layout = host2uint32_t_le(metadata->layout);
421 scratch_md.strip_size = host2uint32_t_le(metadata->strip_size);
422 scratch_md.bsize = host2uint32_t_le(metadata->bsize);
423 memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN);
424
425 memcpy(block, &scratch_md, sizeof(hr_metadata_t));
426}
427
428static errno_t meta_native_decode(const void *block, void *md_v)
429{
430 HR_DEBUG("%s()", __func__);
431
432 hr_metadata_t *metadata = md_v;
433
434 /*
435 * Use scratch metadata for easier decoding without the need
436 * for manualy specifying offsets.
437 */
438 hr_metadata_t scratch_md;
439 memcpy(&scratch_md, block, sizeof(hr_metadata_t));
440
441 memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE);
442 if (!meta_native_has_valid_magic(metadata))
443 return EINVAL;
444
445 memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN);
446
447 metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno);
448 metadata->truncated_blkno = uint64_t_le2host(
449 scratch_md.truncated_blkno);
450 metadata->counter = uint64_t_le2host(scratch_md.counter);
451 metadata->rebuild_pos = uint64_t_le2host(scratch_md.rebuild_pos);
452 metadata->version = uint32_t_le2host(scratch_md.version);
453 metadata->extent_no = uint32_t_le2host(scratch_md.extent_no);
454 metadata->index = uint32_t_le2host(scratch_md.index);
455 metadata->level = uint32_t_le2host(scratch_md.level);
456 metadata->layout = uint32_t_le2host(scratch_md.layout);
457 metadata->strip_size = uint32_t_le2host(scratch_md.strip_size);
458 metadata->bsize = uint32_t_le2host(scratch_md.bsize);
459 memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN);
460
461 if (metadata->version != 1)
462 return EINVAL;
463
464 return EOK;
465}
466
467static errno_t meta_native_get_block(service_id_t dev, void **rblock)
468{
469 HR_DEBUG("%s()", __func__);
470
471 errno_t rc;
472 uint64_t blkno;
473 size_t bsize;
474 void *block;
475
476 if (rblock == NULL)
477 return EINVAL;
478
479 rc = block_get_bsize(dev, &bsize);
480 if (rc != EOK)
481 return rc;
482
483 if (bsize < sizeof(hr_metadata_t))
484 return EINVAL;
485
486 rc = block_get_nblocks(dev, &blkno);
487 if (rc != EOK)
488 return rc;
489
490 if (blkno < HR_NATIVE_META_SIZE)
491 return EINVAL;
492
493 block = malloc(bsize);
494 if (block == NULL)
495 return ENOMEM;
496
497 rc = hr_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block);
498 /*
499 * XXX: here maybe call vol state event or the state callback...
500 *
501 * but need to pass vol pointer
502 */
503 if (rc != EOK) {
504 free(block);
505 return rc;
506 }
507
508 *rblock = block;
509 return EOK;
510}
511
512static errno_t meta_native_write_block(service_id_t dev, const void *block)
513{
514 HR_DEBUG("%s()", __func__);
515
516 errno_t rc;
517 uint64_t blkno;
518 size_t bsize;
519
520 rc = block_get_bsize(dev, &bsize);
521 if (rc != EOK)
522 return rc;
523
524 if (bsize < sizeof(hr_metadata_t))
525 return EINVAL;
526
527 rc = block_get_nblocks(dev, &blkno);
528 if (rc != EOK)
529 return rc;
530
531 if (blkno < HR_NATIVE_META_SIZE)
532 return EINVAL;
533
534 rc = hr_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block);
535
536 return rc;
537}
538
539static bool meta_native_has_valid_magic(const void *md_v)
540{
541 HR_DEBUG("%s()", __func__);
542
543 const hr_metadata_t *md = md_v;
544
545 if (str_lcmp(md->magic, HR_NATIVE_MAGIC_STR, HR_NATIVE_MAGIC_SIZE) != 0)
546 return false;
547
548 return true;
549}
550
551/** @}
552 */
Note: See TracBrowser for help on using the repository browser.