source: mainline/uspace/srv/bd/hr/util.c@ 5fe0b9b5

Last change on this file since 5fe0b9b5 was e494d7b, checked in by Miroslav Cimerman <mc@…>, 8 months ago

hr: initialize hotspare states to MISSING

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[da5c257]1/*
[36661772]2 * Copyright (c) 2025 Miroslav Cimerman
[da5c257]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
[38e3c0a7]36#include <adt/list.h>
[da5c257]37#include <block.h>
38#include <errno.h>
[38e3c0a7]39#include <fibril_synch.h>
[da5c257]40#include <hr.h>
41#include <io/log.h>
42#include <loc.h>
[d6fe2a1]43#include <stdatomic.h>
[44ea48e]44#include <stdlib.h>
45#include <stdio.h>
[da5c257]46#include <str_error.h>
47
48#include "util.h"
[b0f1366]49#include "var.h"
[da5c257]50
[38e3c0a7]51#define HR_RL_LIST_LOCK(vol) (fibril_mutex_lock(&vol->range_lock_list_lock))
52#define HR_RL_LIST_UNLOCK(vol) \
53 (fibril_mutex_unlock(&vol->range_lock_list_lock))
54
55static bool hr_range_lock_overlap(hr_range_lock_t *, hr_range_lock_t *);
56
[da5c257]57extern loc_srv_t *hr_srv;
58
59errno_t hr_init_devs(hr_volume_t *vol)
60{
[d199a6f]61 HR_DEBUG("hr_init_devs()\n");
[da5c257]62
63 errno_t rc;
64 size_t i;
[5d96f427]65 hr_extent_t *extent;
[da5c257]66
[65706f1]67 for (i = 0; i < vol->extent_no; i++) {
[5d96f427]68 extent = &vol->extents[i];
69 if (extent->svc_id == 0) {
70 extent->status = HR_EXT_MISSING;
[e47a032]71 continue;
72 }
[5d96f427]73
[d199a6f]74 HR_DEBUG("hr_init_devs(): block_init() on (%lu)\n",
[5d96f427]75 extent->svc_id);
76 rc = block_init(extent->svc_id);
77 extent->status = HR_EXT_ONLINE;
78
[da5c257]79 if (rc != EOK) {
[d199a6f]80 HR_ERROR("hr_init_devs(): initing (%lu) failed, "
[5d96f427]81 "aborting\n", extent->svc_id);
[da5c257]82 break;
83 }
84 }
85
[e494d7b]86 for (i = 0; i < HR_MAX_HOTSPARES; i++)
87 vol->hotspares[i].status = HR_EXT_MISSING;
88
[da5c257]89 return rc;
90}
91
92void hr_fini_devs(hr_volume_t *vol)
93{
[d199a6f]94 HR_DEBUG("hr_fini_devs()\n");
[da5c257]95
96 size_t i;
97
[65706f1]98 for (i = 0; i < vol->extent_no; i++) {
[36661772]99 if (vol->extents[i].svc_id != 0) {
[d199a6f]100 HR_DEBUG("hr_fini_devs(): block_fini() on (%lu)\n",
[5d96f427]101 vol->extents[i].svc_id);
[e47a032]102 block_fini(vol->extents[i].svc_id);
[5d96f427]103 }
104 }
[da5c257]105}
106
[5d96f427]107errno_t hr_register_volume(hr_volume_t *vol)
[da5c257]108{
[d199a6f]109 HR_DEBUG("hr_register_volume()\n");
[b0f1366]110
[da5c257]111 errno_t rc;
112 service_id_t new_id;
113 category_id_t cat_id;
[44ea48e]114 char *fullname = NULL;
[5d96f427]115 char *devname = vol->devname;
[da5c257]116
[5d96f427]117 if (asprintf(&fullname, "devices/%s", devname) < 0)
[44ea48e]118 return ENOMEM;
119
120 rc = loc_service_register(hr_srv, fullname, &new_id);
[da5c257]121 if (rc != EOK) {
[d199a6f]122 HR_ERROR("unable to register device \"%s\": %s\n",
[5d96f427]123 fullname, str_error(rc));
[da5c257]124 goto error;
125 }
126
127 rc = loc_category_get_id("raid", &cat_id, IPC_FLAG_BLOCKING);
128 if (rc != EOK) {
[d199a6f]129 HR_ERROR("failed resolving category \"raid\": %s\n",
[5d96f427]130 str_error(rc));
[da5c257]131 goto error;
132 }
133
134 rc = loc_service_add_to_cat(hr_srv, new_id, cat_id);
135 if (rc != EOK) {
[d199a6f]136 HR_ERROR("failed adding \"%s\" to category \"raid\": %s\n",
[5d96f427]137 fullname, str_error(rc));
[da5c257]138 goto error;
139 }
140
[5d96f427]141 vol->svc_id = new_id;
[da5c257]142error:
[44ea48e]143 free(fullname);
[da5c257]144 return rc;
145}
146
[6b8e89b0]147errno_t hr_check_devs(hr_volume_t *vol, uint64_t *rblkno, size_t *rbsize)
[b0f1366]148{
[d199a6f]149 HR_DEBUG("hr_check_devs()\n");
[b0f1366]150
151 errno_t rc;
[e47a032]152 size_t i, bsize;
153 uint64_t nblocks;
154 size_t last_bsize = 0;
155 uint64_t last_nblocks = 0;
[b0f1366]156 uint64_t total_blocks = 0;
[5d96f427]157 hr_extent_t *extent;
[b0f1366]158
[65706f1]159 for (i = 0; i < vol->extent_no; i++) {
[5d96f427]160 extent = &vol->extents[i];
161 if (extent->status == HR_EXT_MISSING)
[e47a032]162 continue;
[5d96f427]163 rc = block_get_nblocks(extent->svc_id, &nblocks);
[b0f1366]164 if (rc != EOK)
165 goto error;
[e47a032]166 if (last_nblocks != 0 && nblocks != last_nblocks) {
[d199a6f]167 HR_ERROR("number of blocks differs\n");
[b0f1366]168 rc = EINVAL;
169 goto error;
170 }
[5d96f427]171
[b0f1366]172 total_blocks += nblocks;
173 last_nblocks = nblocks;
174 }
175
[65706f1]176 for (i = 0; i < vol->extent_no; i++) {
[5d96f427]177 extent = &vol->extents[i];
178 if (extent->status == HR_EXT_MISSING)
[e47a032]179 continue;
[5d96f427]180 rc = block_get_bsize(extent->svc_id, &bsize);
[b0f1366]181 if (rc != EOK)
182 goto error;
[e47a032]183 if (last_bsize != 0 && bsize != last_bsize) {
[d199a6f]184 HR_ERROR("block sizes differ\n");
[b0f1366]185 rc = EINVAL;
186 goto error;
187 }
[5d96f427]188
[b0f1366]189 last_bsize = bsize;
190 }
191
[1cfa162]192 if ((bsize % 512) != 0) {
[d199a6f]193 HR_ERROR("block size not multiple of 512\n");
[1cfa162]194 return EINVAL;
195 }
196
[6b8e89b0]197 if (rblkno != NULL)
198 *rblkno = total_blocks;
199 if (rbsize != NULL)
200 *rbsize = bsize;
[b0f1366]201error:
202 return rc;
203}
204
[4a2a6b8b]205errno_t hr_check_ba_range(hr_volume_t *vol, size_t cnt, uint64_t ba)
[b0f1366]206{
[4a2a6b8b]207 if (ba + cnt > vol->data_blkno)
[b0f1366]208 return ERANGE;
[4a2a6b8b]209 return EOK;
210}
[b0f1366]211
[4a2a6b8b]212void hr_add_ba_offset(hr_volume_t *vol, uint64_t *ba)
213{
[b0f1366]214 *ba = *ba + vol->data_offset;
215}
216
[a0c3080]217void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s)
[e47a032]218{
[36661772]219 if (vol->level != HR_LVL_0)
220 assert(fibril_rwlock_is_locked(&vol->extents_lock));
221
222 assert(fibril_rwlock_is_write_locked(&vol->states_lock));
223
[7a3529a8]224 assert(extent < vol->extent_no);
225
[a0c3080]226 hr_ext_status_t old = vol->extents[extent].status;
[37ffa4d]227 HR_WARN("\"%s\": changing extent %lu state: %s -> %s\n",
[a0c3080]228 vol->devname, extent, hr_get_ext_status_msg(old),
229 hr_get_ext_status_msg(s));
[e47a032]230 vol->extents[extent].status = s;
231}
232
[a0c3080]233void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s)
234{
[36661772]235 assert(fibril_mutex_is_locked(&vol->hotspare_lock));
236
[7a3529a8]237 assert(hs < vol->hotspare_no);
238
[a0c3080]239 hr_ext_status_t old = vol->hotspares[hs].status;
[37ffa4d]240 HR_WARN("\"%s\": changing hotspare %lu state: %s -> %s\n",
[a0c3080]241 vol->devname, hs, hr_get_ext_status_msg(old),
242 hr_get_ext_status_msg(s));
243 vol->hotspares[hs].status = s;
244}
245
[edc89bd8]246void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t new)
[a0c3080]247{
[36661772]248 assert(fibril_rwlock_is_write_locked(&vol->states_lock));
249
[37ffa4d]250 HR_WARN("\"%s\": changing volume state: %s -> %s\n", vol->devname,
[edc89bd8]251 hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(new));
252 vol->status = new;
253}
254
255void hr_update_ext_svc_id(hr_volume_t *vol, size_t extent, service_id_t new)
256{
257 if (vol->level != HR_LVL_0)
258 assert(fibril_rwlock_is_write_locked(&vol->extents_lock));
259
260 assert(extent < vol->extent_no);
261
262 service_id_t old = vol->extents[extent].svc_id;
263 HR_WARN("\"%s\": changing extent no. %lu svc_id: (%lu) -> (%lu)\n",
264 vol->devname, extent, old, new);
265 vol->extents[extent].svc_id = new;
266}
267
268void hr_update_hotspare_svc_id(hr_volume_t *vol, size_t hs, service_id_t new)
269{
270 assert(fibril_mutex_is_locked(&vol->hotspare_lock));
271
272 assert(hs < vol->hotspare_no);
273
274 service_id_t old = vol->hotspares[hs].svc_id;
275 HR_WARN("\"%s\": changing hotspare no. %lu svc_id: (%lu) -> (%lu)\n",
276 vol->devname, hs, old, new);
277 vol->hotspares[hs].svc_id = new;
[a0c3080]278}
279
[52af125]280/*
281 * Do a whole sync (ba = 0, cnt = 0) across all extents,
282 * and update extent status. *For now*, the caller has to
283 * update volume status after the syncs.
284 *
285 * TODO: add update_vol_status fcn ptr for each raid
286 */
287void hr_sync_all_extents(hr_volume_t *vol)
288{
289 errno_t rc;
290
291 fibril_mutex_lock(&vol->lock);
[65706f1]292 for (size_t i = 0; i < vol->extent_no; i++) {
[52af125]293 if (vol->extents[i].status != HR_EXT_ONLINE)
294 continue;
295 rc = block_sync_cache(vol->extents[i].svc_id, 0, 0);
[36661772]296 if (rc == ENOMEM || rc == ENOTSUP)
297 continue;
298 if (rc != EOK) {
[52af125]299 if (rc == ENOENT)
300 hr_update_ext_status(vol, i, HR_EXT_MISSING);
301 else if (rc != EOK)
302 hr_update_ext_status(vol, i, HR_EXT_FAILED);
303 }
304 }
305 fibril_mutex_unlock(&vol->lock);
306}
307
[e76e12d8]308size_t hr_count_extents(hr_volume_t *vol, hr_ext_status_t status)
309{
[36661772]310 if (vol->level != HR_LVL_0)
311 assert(fibril_rwlock_is_locked(&vol->extents_lock));
312 assert(fibril_rwlock_is_locked(&vol->states_lock));
313
[e76e12d8]314 size_t count = 0;
[38e3c0a7]315 for (size_t i = 0; i < vol->extent_no; i++)
[e76e12d8]316 if (vol->extents[i].status == status)
317 count++;
318
319 return count;
320}
321
[38e3c0a7]322hr_range_lock_t *hr_range_lock_acquire(hr_volume_t *vol, uint64_t ba,
323 uint64_t cnt)
324{
325 hr_range_lock_t *rl = malloc(sizeof(hr_range_lock_t));
326 if (rl == NULL)
327 return NULL;
328
329 rl->vol = vol;
330 rl->off = ba;
331 rl->len = cnt;
332
333 rl->pending = 1;
334 rl->ignore = false;
335
336 link_initialize(&rl->link);
337 fibril_mutex_initialize(&rl->lock);
338
339 fibril_mutex_lock(&rl->lock);
340
341again:
342 HR_RL_LIST_LOCK(vol);
343 list_foreach(vol->range_lock_list, link, hr_range_lock_t, rlp) {
344 if (rlp->ignore)
345 continue;
346 if (hr_range_lock_overlap(rlp, rl)) {
347 rlp->pending++;
348
349 HR_RL_LIST_UNLOCK(vol);
350
351 fibril_mutex_lock(&rlp->lock);
352
353 HR_RL_LIST_LOCK(vol);
354
355 rlp->pending--;
356
357 /*
358 * when ignore is set, after HR_RL_LIST_UNLOCK(),
359 * noone new is going to be able to start sleeping
360 * on the ignored range lock, only already waiting
361 * IOs will come through here
362 */
363 rlp->ignore = true;
364
365 fibril_mutex_unlock(&rlp->lock);
366
367 if (rlp->pending == 0) {
368 list_remove(&rlp->link);
369 free(rlp);
370 }
371
372 HR_RL_LIST_UNLOCK(vol);
373 goto again;
374 }
375 }
376
377 list_append(&rl->link, &vol->range_lock_list);
378
379 HR_RL_LIST_UNLOCK(vol);
380 return rl;
381}
382
383void hr_range_lock_release(hr_range_lock_t *rl)
384{
[36661772]385 if (rl == NULL)
386 return;
387
[38e3c0a7]388 HR_RL_LIST_LOCK(rl->vol);
389
390 rl->pending--;
391
392 fibril_mutex_unlock(&rl->lock);
393
394 if (rl->pending == 0) {
395 list_remove(&rl->link);
396 free(rl);
397 }
398
399 HR_RL_LIST_UNLOCK(rl->vol);
400}
401
402static bool hr_range_lock_overlap(hr_range_lock_t *rl1, hr_range_lock_t *rl2)
403{
404 uint64_t rl1_start = rl1->off;
405 uint64_t rl1_end = rl1->off + rl1->len - 1;
406 uint64_t rl2_start = rl2->off;
407 uint64_t rl2_end = rl2->off + rl2->len - 1;
408
409 /* one ends before the other starts */
410 if (rl1_end < rl2_start || rl2_end < rl1_start)
411 return false;
412
413 return true;
414}
415
[d6fe2a1]416void hr_mark_vol_state_dirty(hr_volume_t *vol)
417{
[d2da1be]418 atomic_store(&vol->state_dirty, true);
[d6fe2a1]419}
420
[da5c257]421/** @}
422 */
Note: See TracBrowser for help on using the repository browser.