source: mainline/uspace/srv/bd/hr/metadata/native.c@ 9ee9c60b

Last change on this file since 9ee9c60b was eabc094c, checked in by Miroslav Cimerman <mc@…>, 2 months ago

hr: add superblock erasure op

  • Property mode set to 100644
File size: 13.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 "../util.h"
51#include "../var.h"
52
53#include "native.h"
54
55static void *meta_native_alloc_struct(void);
56static errno_t meta_native_init_vol2meta(const hr_volume_t *, void *);
57static errno_t meta_native_init_meta2vol(const list_t *, hr_volume_t *);
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 errno_t meta_native_erase_block(service_id_t);
63static bool meta_native_has_valid_magic(const void *);
64static bool meta_native_compare_uuids(const void *, const void *);
65static void meta_native_inc_counter(void *);
66static errno_t meta_native_save(hr_volume_t *, bool);
67static const char *meta_native_get_devname(const void *);
68static hr_level_t meta_native_get_level(const void *);
69static uint64_t meta_native_get_data_offset(void);
70static size_t meta_native_get_size(void);
71static uint8_t meta_native_get_flags(void);
72static hr_metadata_type_t meta_native_get_type(void);
73static void meta_native_dump(const void *);
74
75hr_superblock_ops_t metadata_native_ops = {
76 .alloc_struct = meta_native_alloc_struct,
77 .init_vol2meta = meta_native_init_vol2meta,
78 .init_meta2vol = meta_native_init_meta2vol,
79 .encode = meta_native_encode,
80 .decode = meta_native_decode,
81 .get_block = meta_native_get_block,
82 .write_block = meta_native_write_block,
83 .erase_block = meta_native_erase_block,
84 .has_valid_magic = meta_native_has_valid_magic,
85 .compare_uuids = meta_native_compare_uuids,
86 .inc_counter = meta_native_inc_counter,
87 .save = meta_native_save,
88 .get_devname = meta_native_get_devname,
89 .get_level = meta_native_get_level,
90 .get_data_offset = meta_native_get_data_offset,
91 .get_size = meta_native_get_size,
92 .get_flags = meta_native_get_flags,
93 .get_type = meta_native_get_type,
94 .dump = meta_native_dump
95};
96
97static void *meta_native_alloc_struct(void)
98{
99 return calloc(1, sizeof(hr_metadata_t));
100}
101
102static errno_t meta_native_init_vol2meta(const hr_volume_t *vol, void *md_v)
103{
104 HR_DEBUG("%s()", __func__);
105
106 hr_metadata_t *md = md_v;
107
108 str_cpy(md->magic, HR_NATIVE_MAGIC_SIZE, HR_NATIVE_MAGIC_STR);
109
110 md->version = HR_NATIVE_METADATA_VERSION;
111
112 md->counter = 0;
113
114 uuid_t uuid;
115 /* rndgen */
116 fibril_usleep(1000);
117 errno_t rc = uuid_generate(&uuid);
118 if (rc != EOK)
119 return rc;
120
121 /* XXX: for now we just copy byte by byte as "encoding" */
122 memcpy(md->uuid, &uuid, HR_NATIVE_UUID_LEN);
123 /* uuid_encode(&uuid, metadata->uuid); */
124
125 md->data_blkno = vol->data_blkno;
126 md->truncated_blkno = vol->truncated_blkno;
127 md->data_offset = vol->data_offset;
128 md->extent_no = vol->extent_no;
129 md->level = vol->level;
130 md->layout = vol->layout;
131 md->strip_size = vol->strip_size;
132 md->bsize = vol->bsize;
133 memcpy(md->devname, vol->devname, HR_DEVNAME_LEN);
134
135 return EOK;
136}
137
138static errno_t meta_native_init_meta2vol(const list_t *list, hr_volume_t *vol)
139{
140 HR_DEBUG("%s()", __func__);
141
142 hr_metadata_t *main_meta = NULL;
143 uint64_t max_counter_val = 0;
144
145 list_foreach(*list, link, struct dev_list_member, iter) {
146 hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md;
147 if (iter_meta->counter >= max_counter_val) {
148 max_counter_val = iter_meta->counter;
149 main_meta = iter_meta;
150 }
151 }
152
153 assert(main_meta != NULL);
154
155 vol->data_blkno = main_meta->data_blkno;
156 vol->truncated_blkno = main_meta->truncated_blkno;
157 vol->data_offset = main_meta->data_offset;
158 vol->extent_no = main_meta->extent_no;
159 /* vol->level = main_meta->level; */ /* already set */
160 vol->layout = main_meta->layout;
161 vol->strip_size = main_meta->strip_size;
162 vol->bsize = main_meta->bsize;
163 /* already set */
164 /* memcpy(vol->devname, main_meta->devname, HR_DEVNAME_LEN); */
165 memcpy(vol->in_mem_md, main_meta, sizeof(hr_metadata_t));
166
167 list_foreach(*list, link, struct dev_list_member, iter) {
168 hr_metadata_t *iter_meta = (hr_metadata_t *)iter->md;
169
170 vol->extents[iter_meta->index].svc_id = iter->svc_id;
171 iter->fini = false;
172
173 if (iter_meta->counter == max_counter_val)
174 vol->extents[iter_meta->index].state = HR_EXT_ONLINE;
175 else
176 vol->extents[iter_meta->index].state = HR_EXT_INVALID;
177 }
178
179 for (size_t i = 0; i < vol->extent_no; i++) {
180 if (vol->extents[i].state == HR_EXT_NONE)
181 vol->extents[i].state = HR_EXT_MISSING;
182 }
183
184 return EOK;
185}
186
187static void meta_native_encode(void *md_v, void *block)
188{
189 HR_DEBUG("%s()", __func__);
190
191 const hr_metadata_t *metadata = md_v;
192
193 /*
194 * Use scratch metadata for easier encoding without the need
195 * for manualy specifying offsets.
196 */
197 hr_metadata_t scratch_md;
198
199 memcpy(scratch_md.magic, metadata->magic, HR_NATIVE_MAGIC_SIZE);
200 memcpy(scratch_md.uuid, metadata->uuid, HR_NATIVE_UUID_LEN);
201 /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */
202
203 scratch_md.data_blkno = host2uint64_t_le(metadata->data_blkno);
204 scratch_md.truncated_blkno = host2uint64_t_le(
205 metadata->truncated_blkno);
206 scratch_md.data_offset = host2uint64_t_le(metadata->data_offset);
207 scratch_md.counter = host2uint64_t_le(metadata->counter);
208 scratch_md.version = host2uint32_t_le(metadata->version);
209 scratch_md.extent_no = host2uint32_t_le(metadata->extent_no);
210 scratch_md.index = host2uint32_t_le(metadata->index);
211 scratch_md.level = host2uint32_t_le(metadata->level);
212 scratch_md.layout = host2uint32_t_le(metadata->layout);
213 scratch_md.strip_size = host2uint32_t_le(metadata->strip_size);
214 scratch_md.bsize = host2uint32_t_le(metadata->bsize);
215 memcpy(scratch_md.devname, metadata->devname, HR_DEVNAME_LEN);
216
217 memcpy(block, &scratch_md, sizeof(hr_metadata_t));
218}
219
220static errno_t meta_native_decode(const void *block, void *md_v)
221{
222 HR_DEBUG("%s()", __func__);
223
224 hr_metadata_t *metadata = md_v;
225
226 /*
227 * Use scratch metadata for easier decoding without the need
228 * for manualy specifying offsets.
229 */
230 hr_metadata_t scratch_md;
231 memcpy(&scratch_md, block, sizeof(hr_metadata_t));
232
233 memcpy(metadata->magic, scratch_md.magic, HR_NATIVE_MAGIC_SIZE);
234 memcpy(metadata->uuid, scratch_md.uuid, HR_NATIVE_UUID_LEN);
235 /* uuid_decode((uint8_t *)scratch_md.uuid, (uuid_t *)metadata->uuid); */
236
237 metadata->data_blkno = uint64_t_le2host(scratch_md.data_blkno);
238 metadata->truncated_blkno = uint64_t_le2host(
239 scratch_md.truncated_blkno);
240 metadata->data_offset = uint64_t_le2host(scratch_md.data_offset);
241 metadata->counter = uint64_t_le2host(scratch_md.counter);
242 metadata->version = uint32_t_le2host(scratch_md.version);
243 metadata->extent_no = uint32_t_le2host(scratch_md.extent_no);
244 metadata->index = uint32_t_le2host(scratch_md.index);
245 metadata->level = uint32_t_le2host(scratch_md.level);
246 metadata->layout = uint32_t_le2host(scratch_md.layout);
247 metadata->strip_size = uint32_t_le2host(scratch_md.strip_size);
248 metadata->bsize = uint32_t_le2host(scratch_md.bsize);
249 memcpy(metadata->devname, scratch_md.devname, HR_DEVNAME_LEN);
250
251 return EOK;
252}
253
254static errno_t meta_native_get_block(service_id_t dev, void **rblock)
255{
256 HR_DEBUG("%s()", __func__);
257
258 errno_t rc;
259 uint64_t blkno;
260 size_t bsize;
261 void *block;
262
263 if (rblock == NULL)
264 return EINVAL;
265
266 rc = block_get_bsize(dev, &bsize);
267 if (rc != EOK)
268 return rc;
269
270 if (bsize < sizeof(hr_metadata_t))
271 return EINVAL;
272
273 rc = block_get_nblocks(dev, &blkno);
274 if (rc != EOK)
275 return rc;
276
277 if (blkno < HR_NATIVE_META_SIZE)
278 return EINVAL;
279
280 block = malloc(bsize);
281 if (block == NULL)
282 return ENOMEM;
283
284 rc = block_read_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block);
285 /*
286 * XXX: here maybe call vol state event or the state callback...
287 *
288 * but need to pass vol pointer
289 */
290 if (rc != EOK) {
291 free(block);
292 return rc;
293 }
294
295 *rblock = block;
296 return EOK;
297}
298
299static errno_t meta_native_write_block(service_id_t dev, const void *block)
300{
301 HR_DEBUG("%s()", __func__);
302
303 errno_t rc;
304 uint64_t blkno;
305 size_t bsize;
306
307 rc = block_get_bsize(dev, &bsize);
308 if (rc != EOK)
309 return rc;
310
311 if (bsize < sizeof(hr_metadata_t))
312 return EINVAL;
313
314 rc = block_get_nblocks(dev, &blkno);
315 if (rc != EOK)
316 return rc;
317
318 if (blkno < HR_NATIVE_META_SIZE)
319 return EINVAL;
320
321 rc = block_write_direct(dev, blkno - 1, HR_NATIVE_META_SIZE, block);
322
323 return rc;
324}
325
326static errno_t meta_native_erase_block(service_id_t dev)
327{
328 HR_DEBUG("%s()", __func__);
329
330 errno_t rc;
331 size_t bsize;
332
333 rc = block_get_bsize(dev, &bsize);
334 if (rc != EOK)
335 return rc;
336
337 void *zero_block = calloc(1, bsize);
338 if (zero_block == NULL)
339 return ENOMEM;
340
341 rc = meta_native_write_block(dev, zero_block);
342 return rc;
343}
344
345static bool meta_native_has_valid_magic(const void *md_v)
346{
347 HR_DEBUG("%s()", __func__);
348
349 const hr_metadata_t *md = md_v;
350
351 if (str_lcmp(md->magic, HR_NATIVE_MAGIC_STR, HR_NATIVE_MAGIC_SIZE) != 0)
352 return false;
353
354 return true;
355}
356
357static bool meta_native_compare_uuids(const void *m1p, const void *m2p)
358{
359 const hr_metadata_t *m1 = m1p;
360 const hr_metadata_t *m2 = m2p;
361 if (memcmp(m1->uuid, m2->uuid, HR_NATIVE_UUID_LEN) == 0)
362 return true;
363
364 return false;
365}
366
367static void meta_native_inc_counter(void *md_v)
368{
369 hr_metadata_t *md = md_v;
370
371 md->counter++;
372}
373
374/*
375 * XXX: finish this fcn documentation
376 *
377 * Returns ENOMEM else EOK
378 */
379static errno_t meta_native_save(hr_volume_t *vol, bool with_state_callback)
380{
381 HR_DEBUG("%s()", __func__);
382
383 errno_t rc = EOK;
384
385 void *md_block = calloc(1, vol->bsize);
386 if (md_block == NULL)
387 return ENOMEM;
388
389 hr_metadata_t *md = (hr_metadata_t *)vol->in_mem_md;
390
391 fibril_rwlock_read_lock(&vol->extents_lock);
392
393 fibril_mutex_lock(&vol->md_lock);
394
395 for (size_t i = 0; i < vol->extent_no; i++) {
396 hr_extent_t *ext = &vol->extents[i];
397
398 fibril_rwlock_read_lock(&vol->states_lock);
399
400 /* TODO: special case for REBUILD */
401 if (ext->state != HR_EXT_ONLINE) {
402 fibril_rwlock_read_unlock(&vol->states_lock);
403 continue;
404 }
405
406 fibril_rwlock_read_unlock(&vol->states_lock);
407
408 md->index = i;
409 meta_native_encode(md, md_block);
410 rc = meta_native_write_block(ext->svc_id, md_block);
411 if (with_state_callback && rc != EOK)
412 vol->hr_ops.ext_state_cb(vol, i, rc);
413 }
414
415 fibril_mutex_unlock(&vol->md_lock);
416
417 fibril_rwlock_read_unlock(&vol->extents_lock);
418
419 if (with_state_callback)
420 vol->hr_ops.vol_state_eval(vol);
421
422 free(md_block);
423 return EOK;
424}
425
426static const char *meta_native_get_devname(const void *md_v)
427{
428 const hr_metadata_t *md = md_v;
429
430 return md->devname;
431}
432
433static hr_level_t meta_native_get_level(const void *md_v)
434{
435 const hr_metadata_t *md = md_v;
436
437 return md->level;
438}
439
440static uint64_t meta_native_get_data_offset(void)
441{
442 return HR_NATIVE_DATA_OFF;
443}
444
445static size_t meta_native_get_size(void)
446{
447 return HR_NATIVE_META_SIZE;
448}
449
450static uint8_t meta_native_get_flags(void)
451{
452 uint8_t flags = 0;
453
454 flags |= HR_METADATA_HOTSPARE_SUPPORT;
455
456 return flags;
457}
458
459static hr_metadata_type_t meta_native_get_type(void)
460{
461 return HR_METADATA_NATIVE;
462}
463
464static void meta_native_dump(const void *md_v)
465{
466 HR_DEBUG("%s()", __func__);
467
468 const hr_metadata_t *metadata = md_v;
469
470 printf("\tmagic: %s\n", metadata->magic);
471 printf("\tUUID: ");
472 for (size_t i = 0; i < HR_NATIVE_UUID_LEN; ++i) {
473 printf("%.2X", metadata->uuid[i]);
474 if (i + 1 < HR_NATIVE_UUID_LEN)
475 printf(" ");
476 }
477 printf("\n");
478 printf("\tdata_blkno: %" PRIu64 "\n", metadata->data_blkno);
479 printf("\ttruncated_blkno: %" PRIu64 "\n", metadata->truncated_blkno);
480 printf("\tdata_offset: %" PRIu64 "\n", metadata->data_offset);
481 printf("\tcounter: %" PRIu64 "\n", metadata->counter);
482 printf("\tversion: %" PRIu32 "\n", metadata->version);
483 printf("\textent_no: %" PRIu32 "\n", metadata->extent_no);
484 printf("\tindex: %" PRIu32 "\n", metadata->index);
485 printf("\tlevel: %" PRIu32 "\n", metadata->level);
486 printf("\tlayout: %" PRIu32 "\n", metadata->layout);
487 printf("\tstrip_size: %" PRIu32 "\n", metadata->strip_size);
488 printf("\tbsize: %" PRIu32 "\n", metadata->bsize);
489 printf("\tdevname: %s\n", metadata->devname);
490}
491
492/** @}
493 */
Note: See TracBrowser for help on using the repository browser.