source: mainline/uspace/srv/bd/hr/util.c@ 9f15da1

Last change on this file since 9f15da1 was 23df41b, checked in by Miroslav Cimerman <mc@…>, 7 months ago

hr: move hr_process_deferred_invalidations() to util

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