source: mainline/uspace/srv/bd/vbd/disk.c@ 78edb5e

Last change on this file since 78edb5e was 4c6fd56, checked in by Jiri Svoboda <jiri@…>, 2 years ago

loc_server_register() should be callable more than once (API only)

Now loc_server_register() returns a pointer to a loc_srv_t object,
that is then passed to loc_service_register() and
loc_service_add_to_cat().

Added loc_server_unregister() that unregisters the server
and frees the loc_srv_t object.

Updated all callers. The implementation, however, is a stub.
It is not actually possible to call loc_server_register() more
than once, yet.

  • Property mode set to 100644
File size: 29.3 KB
Line 
1/*
2 * Copyright (c) 2023 Jiri Svoboda
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 vbd
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <adt/list.h>
37#include <bd_srv.h>
38#include <block.h>
39#include <errno.h>
40#include <str_error.h>
41#include <io/log.h>
42#include <label/empty.h>
43#include <label/label.h>
44#include <loc.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <task.h>
48#include <vbd.h>
49
50#include "disk.h"
51#include "types/vbd.h"
52
53loc_srv_t *vbds_srv;
54
55static fibril_mutex_t vbds_disks_lock;
56static list_t vbds_disks; /* of vbds_disk_t */
57static fibril_mutex_t vbds_parts_lock;
58static list_t vbds_parts; /* of vbds_part_t */
59
60static category_id_t part_cid;
61
62static errno_t vbds_disk_parts_add(vbds_disk_t *, label_t *);
63static errno_t vbds_disk_parts_remove(vbds_disk_t *, vbds_rem_flag_t);
64
65static errno_t vbds_bd_open(bd_srvs_t *, bd_srv_t *);
66static errno_t vbds_bd_close(bd_srv_t *);
67static errno_t vbds_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
68static errno_t vbds_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
69static errno_t vbds_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *,
70 size_t);
71static errno_t vbds_bd_get_block_size(bd_srv_t *, size_t *);
72static errno_t vbds_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
73
74static errno_t vbds_bsa_translate(vbds_part_t *, aoff64_t, size_t, aoff64_t *);
75
76static errno_t vbds_part_svc_register(vbds_part_t *);
77static errno_t vbds_part_svc_unregister(vbds_part_t *);
78static errno_t vbds_part_indices_update(vbds_disk_t *);
79
80static vbd_part_id_t vbds_part_id = 1;
81
82static errno_t vbds_label_get_bsize(void *, size_t *);
83static errno_t vbds_label_get_nblocks(void *, aoff64_t *);
84static errno_t vbds_label_read(void *, aoff64_t, size_t, void *);
85static errno_t vbds_label_write(void *, aoff64_t, size_t, const void *);
86
87/** Block device operations provided by VBD */
88static bd_ops_t vbds_bd_ops = {
89 .open = vbds_bd_open,
90 .close = vbds_bd_close,
91 .read_blocks = vbds_bd_read_blocks,
92 .sync_cache = vbds_bd_sync_cache,
93 .write_blocks = vbds_bd_write_blocks,
94 .get_block_size = vbds_bd_get_block_size,
95 .get_num_blocks = vbds_bd_get_num_blocks
96};
97
98/** Provide disk access to liblabel */
99static label_bd_ops_t vbds_label_bd_ops = {
100 .get_bsize = vbds_label_get_bsize,
101 .get_nblocks = vbds_label_get_nblocks,
102 .read = vbds_label_read,
103 .write = vbds_label_write
104};
105
106static vbds_part_t *bd_srv_part(bd_srv_t *bd)
107{
108 return (vbds_part_t *)bd->srvs->sarg;
109}
110
111static vbds_disk_t *vbds_disk_first(void)
112{
113 link_t *link;
114
115 link = list_first(&vbds_disks);
116 if (link == NULL)
117 return NULL;
118
119 return list_get_instance(link, vbds_disk_t, ldisks);
120}
121
122static vbds_disk_t *vbds_disk_next(vbds_disk_t *disk)
123{
124 link_t *link;
125
126 if (disk == NULL)
127 return NULL;
128
129 link = list_next(&disk->ldisks, &vbds_disks);
130 if (link == NULL)
131 return NULL;
132
133 return list_get_instance(link, vbds_disk_t, ldisks);
134}
135
136errno_t vbds_disks_init(void)
137{
138 errno_t rc;
139
140 fibril_mutex_initialize(&vbds_disks_lock);
141 list_initialize(&vbds_disks);
142 fibril_mutex_initialize(&vbds_parts_lock);
143 list_initialize(&vbds_parts);
144
145 rc = loc_category_get_id("partition", &part_cid, 0);
146 if (rc != EOK) {
147 log_msg(LOG_DEFAULT, LVL_ERROR, "Error looking up partition "
148 "category.");
149 return EIO;
150 }
151
152 return EOK;
153}
154
155/** Check for new/removed disk devices */
156static errno_t vbds_disks_check_new(void)
157{
158 bool already_known;
159 category_id_t disk_cat;
160 service_id_t *svcs;
161 size_t count, i;
162 vbds_disk_t *cur, *next;
163 errno_t rc;
164
165 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disks_check_new()");
166
167 fibril_mutex_lock(&vbds_disks_lock);
168
169 rc = loc_category_get_id("disk", &disk_cat, IPC_FLAG_BLOCKING);
170 if (rc != EOK) {
171 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'disk'.");
172 fibril_mutex_unlock(&vbds_disks_lock);
173 return ENOENT;
174 }
175
176 rc = loc_category_get_svcs(disk_cat, &svcs, &count);
177 if (rc != EOK) {
178 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of disk "
179 "devices.");
180 fibril_mutex_unlock(&vbds_disks_lock);
181 return EIO;
182 }
183
184 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk)
185 disk->present = false;
186
187 for (i = 0; i < count; i++) {
188 already_known = false;
189
190 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
191 if (disk->svc_id == svcs[i]) {
192 already_known = true;
193 disk->present = true;
194 break;
195 }
196 }
197
198 if (!already_known) {
199 log_msg(LOG_DEFAULT, LVL_NOTE, "Found disk '%lu'",
200 (unsigned long) svcs[i]);
201 rc = vbds_disk_add(svcs[i]);
202 if (rc != EOK) {
203 log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add "
204 "disk.");
205 }
206 } else {
207 log_msg(LOG_DEFAULT, LVL_DEBUG, "Disk %lu already known",
208 (unsigned long) svcs[i]);
209 }
210 }
211
212 cur = vbds_disk_first();
213 while (cur != NULL) {
214 next = vbds_disk_next(cur);
215 if (!cur->present) {
216 log_msg(LOG_DEFAULT, LVL_NOTE, "Disk '%lu' is gone",
217 (unsigned long) cur->svc_id);
218 rc = vbds_disk_remove(cur->svc_id);
219 if (rc != EOK) {
220 log_msg(LOG_DEFAULT, LVL_ERROR, "Could not "
221 "remove disk.");
222 }
223 }
224
225 cur = next;
226 }
227
228 fibril_mutex_unlock(&vbds_disks_lock);
229 return EOK;
230}
231
232static errno_t vbds_disk_by_svcid(service_id_t sid, vbds_disk_t **rdisk)
233{
234 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
235 if (disk->svc_id == sid) {
236 *rdisk = disk;
237 return EOK;
238 }
239 }
240
241 return ENOENT;
242}
243
244static void vbds_part_add_ref(vbds_part_t *part)
245{
246 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_part_add_ref");
247 refcount_up(&part->refcnt);
248}
249
250static void vbds_part_del_ref(vbds_part_t *part)
251{
252 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_part_del_ref");
253 if (refcount_down(&part->refcnt)) {
254 log_msg(LOG_DEFAULT, LVL_DEBUG2, " - free part");
255 free(part);
256 }
257}
258
259static errno_t vbds_part_by_pid(vbds_part_id_t partid, vbds_part_t **rpart)
260{
261 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_by_pid(%zu)", partid);
262
263 fibril_mutex_lock(&vbds_parts_lock);
264
265 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
266 log_msg(LOG_DEFAULT, LVL_DEBUG, "%zu == %zu ?", part->pid, partid);
267 if (part->pid == partid) {
268 log_msg(LOG_DEFAULT, LVL_DEBUG, "Found match.");
269 vbds_part_add_ref(part);
270 fibril_mutex_unlock(&vbds_parts_lock);
271 *rpart = part;
272 return EOK;
273 }
274 }
275
276 fibril_mutex_unlock(&vbds_parts_lock);
277 log_msg(LOG_DEFAULT, LVL_DEBUG, "No match.");
278 return ENOENT;
279}
280
281static errno_t vbds_part_by_svcid(service_id_t svcid, vbds_part_t **rpart)
282{
283 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_by_svcid(%zu)", svcid);
284
285 fibril_mutex_lock(&vbds_parts_lock);
286
287 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
288 log_msg(LOG_DEFAULT, LVL_DEBUG, "%zu == %zu ?", part->svc_id, svcid);
289 if (part->svc_id == svcid) {
290 log_msg(LOG_DEFAULT, LVL_DEBUG, "Found match.");
291 vbds_part_add_ref(part);
292 fibril_mutex_unlock(&vbds_parts_lock);
293 *rpart = part;
294 return EOK;
295 }
296 }
297
298 fibril_mutex_unlock(&vbds_parts_lock);
299 log_msg(LOG_DEFAULT, LVL_DEBUG, "No match.");
300 return ENOENT;
301}
302
303/** Add partition to our inventory based on liblabel partition structure */
304static errno_t vbds_part_add(vbds_disk_t *disk, label_part_t *lpart,
305 vbds_part_t **rpart)
306{
307 vbds_part_t *part;
308 service_id_t psid = 0;
309 label_part_info_t lpinfo;
310 errno_t rc;
311
312 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_add(%s, %p)",
313 disk->svc_name, lpart);
314
315 label_part_get_info(lpart, &lpinfo);
316
317 part = calloc(1, sizeof(vbds_part_t));
318 if (part == NULL) {
319 log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
320 return ENOMEM;
321 }
322
323 fibril_rwlock_initialize(&part->lock);
324
325 part->lpart = lpart;
326 part->disk = disk;
327 part->pid = ++vbds_part_id;
328 part->svc_id = psid;
329 part->block0 = lpinfo.block0;
330 part->nblocks = lpinfo.nblocks;
331 refcount_init(&part->refcnt);
332
333 bd_srvs_init(&part->bds);
334 part->bds.ops = &vbds_bd_ops;
335 part->bds.sarg = part;
336
337 if (lpinfo.pkind != lpk_extended) {
338 rc = vbds_part_svc_register(part);
339 if (rc != EOK) {
340 free(part);
341 return EIO;
342 }
343 }
344
345 list_append(&part->ldisk, &disk->parts);
346 fibril_mutex_lock(&vbds_parts_lock);
347 list_append(&part->lparts, &vbds_parts);
348 fibril_mutex_unlock(&vbds_parts_lock);
349
350 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_add -> %p", part);
351
352 if (rpart != NULL)
353 *rpart = part;
354 return EOK;
355}
356
357/** Remove partition from our inventory leaving only the underlying liblabel
358 * partition structure.
359 *
360 * @param part Partition
361 * @param flag If set to @c vrf_force, force removal even if partition is in use
362 * @param rlpart Place to store pointer to liblabel partition
363 *
364 */
365static errno_t vbds_part_remove(vbds_part_t *part, vbds_rem_flag_t flag,
366 label_part_t **rlpart)
367{
368 label_part_t *lpart;
369 errno_t rc;
370
371 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_remove(%p)", part);
372
373 fibril_rwlock_write_lock(&part->lock);
374 lpart = part->lpart;
375
376 if ((flag & vrf_force) == 0 && part->open_cnt > 0) {
377 fibril_rwlock_write_unlock(&part->lock);
378 log_msg(LOG_DEFAULT, LVL_DEBUG, "part->open_cnt = %d",
379 part->open_cnt);
380 return EBUSY;
381 }
382
383 if (part->svc_id != 0) {
384 rc = vbds_part_svc_unregister(part);
385 if (rc != EOK) {
386 fibril_rwlock_write_unlock(&part->lock);
387 return EIO;
388 }
389 }
390
391 list_remove(&part->ldisk);
392 fibril_mutex_lock(&vbds_parts_lock);
393 list_remove(&part->lparts);
394 fibril_mutex_unlock(&vbds_parts_lock);
395
396 vbds_part_del_ref(part);
397 part->lpart = NULL;
398 fibril_rwlock_write_unlock(&part->lock);
399
400 if (rlpart != NULL)
401 *rlpart = lpart;
402 return EOK;
403}
404
405/** Remove all disk partitions from our inventory leaving only the underlying
406 * liblabel partition structures.
407 */
408static errno_t vbds_disk_parts_add(vbds_disk_t *disk, label_t *label)
409{
410 label_part_t *part;
411 errno_t rc;
412
413 part = label_part_first(label);
414 while (part != NULL) {
415 rc = vbds_part_add(disk, part, NULL);
416 if (rc != EOK) {
417 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding partition "
418 "(disk %s)", disk->svc_name);
419 return rc;
420 }
421
422 part = label_part_next(part);
423 }
424
425 return EOK;
426}
427
428/** Remove all disk partitions from our inventory leaving only the underlying
429 * liblabel partition structures.
430 */
431static errno_t vbds_disk_parts_remove(vbds_disk_t *disk, vbds_rem_flag_t flag)
432{
433 link_t *link;
434 vbds_part_t *part;
435 errno_t rc;
436
437 link = list_first(&disk->parts);
438 while (link != NULL) {
439 part = list_get_instance(link, vbds_part_t, ldisk);
440 rc = vbds_part_remove(part, flag, NULL);
441 if (rc != EOK)
442 return rc;
443
444 link = list_first(&disk->parts);
445 }
446
447 return EOK;
448}
449
450static void vbds_disk_cat_change_cb(void *arg)
451{
452 (void) vbds_disks_check_new();
453}
454
455errno_t vbds_disk_discovery_start(void)
456{
457 errno_t rc;
458
459 rc = loc_register_cat_change_cb(vbds_disk_cat_change_cb, NULL);
460 if (rc != EOK) {
461 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
462 "for disk discovery: %s.", str_error(rc));
463 return rc;
464 }
465
466 return vbds_disks_check_new();
467}
468
469errno_t vbds_disk_add(service_id_t sid)
470{
471 label_t *label = NULL;
472 label_bd_t lbd;
473 vbds_disk_t *disk = NULL;
474 bool block_inited = false;
475 size_t block_size;
476 aoff64_t nblocks;
477 errno_t rc;
478
479 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_add(%zu)", sid);
480
481 /* Check for duplicates */
482 rc = vbds_disk_by_svcid(sid, &disk);
483 if (rc == EOK)
484 return EEXIST;
485
486 disk = calloc(1, sizeof(vbds_disk_t));
487 if (disk == NULL)
488 return ENOMEM;
489
490 /* Must be set before calling label_open */
491 disk->svc_id = sid;
492
493 rc = loc_service_get_name(sid, &disk->svc_name);
494 if (rc != EOK) {
495 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting disk service name.");
496 rc = EIO;
497 goto error;
498 }
499
500 log_msg(LOG_DEFAULT, LVL_DEBUG, "block_init(%zu)", sid);
501 rc = block_init(sid, 2048);
502 if (rc != EOK) {
503 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening block device %s.",
504 disk->svc_name);
505 rc = EIO;
506 goto error;
507 }
508
509 rc = block_get_bsize(sid, &block_size);
510 if (rc != EOK) {
511 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting block size of %s.",
512 disk->svc_name);
513 rc = EIO;
514 goto error;
515 }
516
517 rc = block_get_nblocks(sid, &nblocks);
518 if (rc != EOK) {
519 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting number of "
520 "blocks of %s.", disk->svc_name);
521 rc = EIO;
522 goto error;
523 }
524
525 block_inited = true;
526
527 lbd.ops = &vbds_label_bd_ops;
528 lbd.arg = (void *) disk;
529
530 rc = label_open(&lbd, &label);
531 if (rc != EOK) {
532 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
533 disk->svc_name);
534 rc = EIO;
535 goto error;
536 }
537
538 disk->label = label;
539 disk->block_size = block_size;
540 disk->nblocks = nblocks;
541 disk->present = true;
542
543 list_initialize(&disk->parts);
544 list_append(&disk->ldisks, &vbds_disks);
545
546 log_msg(LOG_DEFAULT, LVL_NOTE, "Recognized disk label. Adding partitions.");
547
548 (void) vbds_disk_parts_add(disk, label);
549 return EOK;
550error:
551 label_close(label);
552 if (block_inited) {
553 log_msg(LOG_DEFAULT, LVL_DEBUG, "block_fini(%zu)", sid);
554 block_fini(sid);
555 }
556 if (disk != NULL)
557 free(disk->svc_name);
558 free(disk);
559 return rc;
560}
561
562errno_t vbds_disk_remove(service_id_t sid)
563{
564 vbds_disk_t *disk;
565 errno_t rc;
566
567 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_remove(%zu)", sid);
568
569 rc = vbds_disk_by_svcid(sid, &disk);
570 if (rc != EOK)
571 return rc;
572
573 rc = vbds_disk_parts_remove(disk, vrf_force);
574 if (rc != EOK) {
575 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
576 return rc;
577 }
578
579 list_remove(&disk->ldisks);
580 label_close(disk->label);
581 log_msg(LOG_DEFAULT, LVL_DEBUG, "block_fini(%zu)", sid);
582 block_fini(sid);
583 free(disk);
584 return EOK;
585}
586
587/** Get list of disks as array of service IDs. */
588errno_t vbds_disk_get_ids(service_id_t *id_buf, size_t buf_size, size_t *act_size)
589{
590 size_t act_cnt;
591 size_t buf_cnt;
592
593 fibril_mutex_lock(&vbds_disks_lock);
594
595 buf_cnt = buf_size / sizeof(service_id_t);
596
597 act_cnt = list_count(&vbds_disks);
598 *act_size = act_cnt * sizeof(service_id_t);
599
600 if (buf_size % sizeof(service_id_t) != 0) {
601 fibril_mutex_unlock(&vbds_disks_lock);
602 return EINVAL;
603 }
604
605 size_t pos = 0;
606 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
607 if (pos < buf_cnt)
608 id_buf[pos] = disk->svc_id;
609 pos++;
610 }
611
612 fibril_mutex_unlock(&vbds_disks_lock);
613 return EOK;
614}
615
616errno_t vbds_disk_info(service_id_t sid, vbd_disk_info_t *info)
617{
618 vbds_disk_t *disk;
619 label_info_t linfo;
620 errno_t rc;
621
622 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_info(%zu)", sid);
623
624 rc = vbds_disk_by_svcid(sid, &disk);
625 if (rc != EOK)
626 return rc;
627
628 rc = label_get_info(disk->label, &linfo);
629 if (rc != EOK)
630 return rc;
631
632 info->ltype = linfo.ltype;
633 info->flags = linfo.flags;
634 info->ablock0 = linfo.ablock0;
635 info->anblocks = linfo.anblocks;
636 info->block_size = disk->block_size;
637 info->nblocks = disk->nblocks;
638 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_info - block_size=%zu",
639 info->block_size);
640 return EOK;
641}
642
643errno_t vbds_get_parts(service_id_t sid, service_id_t *id_buf, size_t buf_size,
644 size_t *act_size)
645{
646 vbds_disk_t *disk;
647 size_t act_cnt;
648 size_t buf_cnt;
649 errno_t rc;
650
651 rc = vbds_disk_by_svcid(sid, &disk);
652 if (rc != EOK)
653 return rc;
654
655 buf_cnt = buf_size / sizeof(service_id_t);
656
657 act_cnt = list_count(&disk->parts);
658 *act_size = act_cnt * sizeof(service_id_t);
659
660 if (buf_size % sizeof(service_id_t) != 0)
661 return EINVAL;
662
663 size_t pos = 0;
664 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
665 if (pos < buf_cnt)
666 id_buf[pos] = part->pid;
667 pos++;
668 }
669
670 return EOK;
671}
672
673errno_t vbds_label_create(service_id_t sid, label_type_t ltype)
674{
675 label_t *label;
676 label_bd_t lbd;
677 label_info_t linfo;
678 vbds_disk_t *disk;
679 errno_t rc, rc2;
680
681 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu)", sid);
682
683 /* Find disk */
684 rc = vbds_disk_by_svcid(sid, &disk);
685 if (rc != EOK)
686 return rc;
687
688 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - label_close", sid);
689
690 /* Verify that current label is a dummy label */
691 rc = label_get_info(disk->label, &linfo);
692 if (rc != EOK)
693 return rc;
694
695 if (linfo.ltype != lt_none) {
696 log_msg(LOG_DEFAULT, LVL_ERROR, "Label already exists.");
697 return EEXIST;
698 }
699
700 /* Close dummy label first */
701 rc = vbds_disk_parts_remove(disk, vrf_none);
702 if (rc != EOK) {
703 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
704 return rc;
705 }
706
707 label_close(disk->label);
708 disk->label = NULL;
709
710 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - label_create", sid);
711
712 lbd.ops = &vbds_label_bd_ops;
713 lbd.arg = (void *) disk;
714
715 rc = label_create(&lbd, ltype, &label);
716 if (rc != EOK)
717 goto error;
718
719 (void) vbds_disk_parts_add(disk, label);
720 disk->label = label;
721
722 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - success", sid);
723 return EOK;
724error:
725 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - failure", sid);
726 if (disk->label == NULL) {
727 lbd.ops = &vbds_label_bd_ops;
728 lbd.arg = (void *) disk;
729
730 rc2 = label_open(&lbd, &label);
731 if (rc2 != EOK) {
732 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
733 disk->svc_name);
734 return rc2;
735 }
736
737 disk->label = label;
738 (void) vbds_disk_parts_add(disk, label);
739 }
740
741 return rc;
742}
743
744errno_t vbds_label_delete(service_id_t sid)
745{
746 vbds_disk_t *disk;
747 label_t *label;
748 label_bd_t lbd;
749 errno_t rc;
750
751 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_delete(%zu)", sid);
752
753 rc = vbds_disk_by_svcid(sid, &disk);
754 if (rc != EOK)
755 return rc;
756
757 rc = vbds_disk_parts_remove(disk, vrf_none);
758 if (rc != EOK) {
759 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
760 return rc;
761 }
762
763 rc = label_destroy(disk->label);
764 if (rc != EOK) {
765 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
766 return rc;
767 }
768
769 disk->label = NULL;
770
771 lbd.ops = &vbds_label_bd_ops;
772 lbd.arg = (void *) disk;
773
774 rc = label_open(&lbd, &label);
775 if (rc != EOK) {
776 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
777 disk->svc_name);
778 return EIO;
779 }
780
781 (void) vbds_disk_parts_add(disk, label);
782 disk->label = label;
783 return EOK;
784}
785
786errno_t vbds_part_get_info(vbds_part_id_t partid, vbd_part_info_t *pinfo)
787{
788 vbds_part_t *part;
789 label_part_info_t lpinfo;
790 errno_t rc;
791
792 rc = vbds_part_by_pid(partid, &part);
793 if (rc != EOK)
794 return rc;
795
796 fibril_rwlock_read_lock(&part->lock);
797 if (part->lpart == NULL) {
798 fibril_rwlock_read_unlock(&part->lock);
799 return ENOENT;
800 }
801
802 label_part_get_info(part->lpart, &lpinfo);
803
804 pinfo->index = lpinfo.index;
805 pinfo->pkind = lpinfo.pkind;
806 pinfo->block0 = lpinfo.block0;
807 pinfo->nblocks = lpinfo.nblocks;
808 pinfo->svc_id = part->svc_id;
809 vbds_part_del_ref(part);
810 fibril_rwlock_read_unlock(&part->lock);
811
812 return EOK;
813}
814
815errno_t vbds_part_create(service_id_t sid, vbd_part_spec_t *pspec,
816 vbds_part_id_t *rpart)
817{
818 vbds_disk_t *disk;
819 vbds_part_t *part;
820 label_part_spec_t lpspec;
821 label_part_t *lpart;
822 errno_t rc;
823
824 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_create(%zu)", sid);
825
826 rc = vbds_disk_by_svcid(sid, &disk);
827 if (rc != EOK) {
828 log_msg(LOG_DEFAULT, LVL_ERROR, "Disk %zu not found",
829 sid);
830 goto error;
831 }
832
833 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_crate(%zu): "
834 "index=%d block0=%" PRIu64 " nblocks=%" PRIu64
835 " hdr_blocks=%" PRIu64 " pkind=%d",
836 sid, pspec->index, pspec->block0, pspec->nblocks, pspec->hdr_blocks,
837 pspec->pkind);
838
839 label_pspec_init(&lpspec);
840 lpspec.index = pspec->index;
841 lpspec.block0 = pspec->block0;
842 lpspec.nblocks = pspec->nblocks;
843 lpspec.hdr_blocks = pspec->hdr_blocks;
844 lpspec.pkind = pspec->pkind;
845 lpspec.ptype = pspec->ptype;
846
847 rc = label_part_create(disk->label, &lpspec, &lpart);
848 if (rc != EOK) {
849 log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating partition.");
850 goto error;
851 }
852
853 rc = label_part_empty(lpart);
854 if (rc != EOK) {
855 log_msg(LOG_DEFAULT, LVL_ERROR, "Error emptying partition.");
856 goto error;
857 }
858
859 rc = vbds_part_indices_update(disk);
860 if (rc != EOK) {
861 log_msg(LOG_DEFAULT, LVL_ERROR, "Error updating partition indices");
862 goto error;
863 }
864
865 rc = vbds_part_add(disk, lpart, &part);
866 if (rc != EOK) {
867 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed while creating "
868 "partition.");
869 rc = label_part_destroy(lpart);
870 if (rc != EOK)
871 log_msg(LOG_DEFAULT, LVL_ERROR,
872 "Cannot roll back partition creation.");
873 rc = EIO;
874 goto error;
875 }
876
877 if (rpart != NULL)
878 *rpart = part->pid;
879 return EOK;
880error:
881 return rc;
882}
883
884errno_t vbds_part_delete(vbds_part_id_t partid)
885{
886 vbds_part_t *part;
887 vbds_disk_t *disk;
888 label_part_t *lpart;
889 errno_t rc;
890
891 rc = vbds_part_by_pid(partid, &part);
892 if (rc != EOK)
893 return rc;
894
895 disk = part->disk;
896
897 rc = vbds_part_remove(part, vrf_none, &lpart);
898 if (rc != EOK)
899 return rc;
900
901 rc = label_part_destroy(lpart);
902 vbds_part_del_ref(part);
903 if (rc != EOK) {
904 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting partition");
905
906 /* Try rolling back */
907 rc = vbds_part_add(disk, lpart, NULL);
908 if (rc != EOK)
909 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed rolling back.");
910
911 return EIO;
912 }
913
914 rc = vbds_part_indices_update(disk);
915 if (rc != EOK) {
916 log_msg(LOG_DEFAULT, LVL_ERROR, "Error updating partition indices");
917 return EIO;
918 }
919
920 return EOK;
921}
922
923errno_t vbds_suggest_ptype(service_id_t sid, label_pcnt_t pcnt,
924 label_ptype_t *ptype)
925{
926 vbds_disk_t *disk;
927 errno_t rc;
928
929 rc = vbds_disk_by_svcid(sid, &disk);
930 if (rc != EOK) {
931 log_msg(LOG_DEFAULT, LVL_DEBUG, "Disk %zu not found",
932 sid);
933 goto error;
934 }
935
936 rc = label_suggest_ptype(disk->label, pcnt, ptype);
937 if (rc != EOK) {
938 log_msg(LOG_DEFAULT, LVL_DEBUG, "label_suggest_ptype() failed");
939 goto error;
940 }
941
942 return EOK;
943error:
944 return rc;
945}
946
947static errno_t vbds_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
948{
949 vbds_part_t *part = bd_srv_part(bd);
950
951 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_open()");
952 fibril_rwlock_write_lock(&part->lock);
953 part->open_cnt++;
954 fibril_rwlock_write_unlock(&part->lock);
955 return EOK;
956}
957
958static errno_t vbds_bd_close(bd_srv_t *bd)
959{
960 vbds_part_t *part = bd_srv_part(bd);
961
962 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_close()");
963
964 /* Grabbing writer lock also forces all I/O to complete */
965
966 fibril_rwlock_write_lock(&part->lock);
967 part->open_cnt--;
968 fibril_rwlock_write_unlock(&part->lock);
969 return EOK;
970}
971
972static errno_t vbds_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
973 void *buf, size_t size)
974{
975 vbds_part_t *part = bd_srv_part(bd);
976 aoff64_t gba;
977 errno_t rc;
978
979 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_read_blocks()");
980 fibril_rwlock_read_lock(&part->lock);
981
982 if (cnt * part->disk->block_size < size) {
983 fibril_rwlock_read_unlock(&part->lock);
984 return EINVAL;
985 }
986
987 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK) {
988 fibril_rwlock_read_unlock(&part->lock);
989 return ELIMIT;
990 }
991
992 rc = block_read_direct(part->disk->svc_id, gba, cnt, buf);
993 fibril_rwlock_read_unlock(&part->lock);
994
995 return rc;
996}
997
998static errno_t vbds_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt)
999{
1000 vbds_part_t *part = bd_srv_part(bd);
1001 aoff64_t gba;
1002 errno_t rc;
1003
1004 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_sync_cache()");
1005 fibril_rwlock_read_lock(&part->lock);
1006
1007 /* XXX Allow full-disk sync? */
1008 if (ba != 0 || cnt != 0) {
1009 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK) {
1010 fibril_rwlock_read_unlock(&part->lock);
1011 return ELIMIT;
1012 }
1013 } else {
1014 gba = 0;
1015 }
1016
1017 rc = block_sync_cache(part->disk->svc_id, gba, cnt);
1018 fibril_rwlock_read_unlock(&part->lock);
1019 return rc;
1020}
1021
1022static errno_t vbds_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
1023 const void *buf, size_t size)
1024{
1025 vbds_part_t *part = bd_srv_part(bd);
1026 aoff64_t gba;
1027 errno_t rc;
1028
1029 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_write_blocks()");
1030 fibril_rwlock_read_lock(&part->lock);
1031
1032 if (cnt * part->disk->block_size < size) {
1033 fibril_rwlock_read_unlock(&part->lock);
1034 return EINVAL;
1035 }
1036
1037 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK) {
1038 fibril_rwlock_read_unlock(&part->lock);
1039 return ELIMIT;
1040 }
1041
1042 rc = block_write_direct(part->disk->svc_id, gba, cnt, buf);
1043 fibril_rwlock_read_unlock(&part->lock);
1044 return rc;
1045}
1046
1047static errno_t vbds_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
1048{
1049 vbds_part_t *part = bd_srv_part(bd);
1050
1051 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_get_block_size()");
1052
1053 fibril_rwlock_read_lock(&part->lock);
1054 *rsize = part->disk->block_size;
1055 fibril_rwlock_read_unlock(&part->lock);
1056
1057 return EOK;
1058}
1059
1060static errno_t vbds_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
1061{
1062 vbds_part_t *part = bd_srv_part(bd);
1063
1064 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_get_num_blocks()");
1065
1066 fibril_rwlock_read_lock(&part->lock);
1067 *rnb = part->nblocks;
1068 fibril_rwlock_read_unlock(&part->lock);
1069
1070 return EOK;
1071}
1072
1073void vbds_bd_conn(ipc_call_t *icall, void *arg)
1074{
1075 vbds_part_t *part;
1076 errno_t rc;
1077 service_id_t svcid;
1078
1079 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn()");
1080
1081 svcid = ipc_get_arg2(icall);
1082
1083 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn() - svcid=%zu", svcid);
1084
1085 rc = vbds_part_by_svcid(svcid, &part);
1086 if (rc != EOK) {
1087 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_bd_conn() - partition "
1088 "not found.");
1089 async_answer_0(icall, EINVAL);
1090 return;
1091 }
1092
1093 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn() - call bd_conn");
1094 bd_conn(icall, &part->bds);
1095 vbds_part_del_ref(part);
1096}
1097
1098/** Translate block segment address with range checking. */
1099static errno_t vbds_bsa_translate(vbds_part_t *part, aoff64_t ba, size_t cnt,
1100 aoff64_t *gba)
1101{
1102 if (ba + cnt > part->nblocks)
1103 return ELIMIT;
1104
1105 *gba = part->block0 + ba;
1106 return EOK;
1107}
1108
1109/** Register service for partition */
1110static errno_t vbds_part_svc_register(vbds_part_t *part)
1111{
1112 char *name;
1113 service_id_t psid;
1114 int idx;
1115 errno_t rc;
1116
1117 idx = part->lpart->index;
1118
1119 if (asprintf(&name, "%sp%u", part->disk->svc_name, idx) < 0) {
1120 log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
1121 return ENOMEM;
1122 }
1123
1124 log_msg(LOG_DEFAULT, LVL_DEBUG, "loc_service_register('%s')",
1125 name);
1126 rc = loc_service_register(vbds_srv, name, &psid);
1127 if (rc != EOK) {
1128 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering "
1129 "service %s: %s.", name, str_error(rc));
1130 free(name);
1131 free(part);
1132 return EIO;
1133 }
1134
1135 rc = loc_service_add_to_cat(vbds_srv, psid, part_cid);
1136 if (rc != EOK) {
1137 log_msg(LOG_DEFAULT, LVL_ERROR, "Failled adding partition "
1138 "service %s to partition category.", name);
1139 free(name);
1140 free(part);
1141
1142 rc = loc_service_unregister(vbds_srv, psid);
1143 if (rc != EOK) {
1144 log_msg(LOG_DEFAULT, LVL_ERROR, "Error unregistering "
1145 "service. Rollback failed.");
1146 }
1147 return EIO;
1148 }
1149
1150 free(name);
1151 part->svc_id = psid;
1152 part->reg_idx = idx;
1153 return EOK;
1154}
1155
1156/** Unregister service for partition */
1157static errno_t vbds_part_svc_unregister(vbds_part_t *part)
1158{
1159 errno_t rc;
1160
1161 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_svc_unregister("
1162 "disk->svc_name='%s', id=%zu)", part->disk->svc_name, part->svc_id);
1163
1164 rc = loc_service_unregister(vbds_srv, part->svc_id);
1165 if (rc != EOK)
1166 return EIO;
1167
1168 part->svc_id = 0;
1169 part->reg_idx = 0;
1170 return EOK;
1171}
1172
1173/** Update service names for any partition whose index has changed. */
1174static errno_t vbds_part_indices_update(vbds_disk_t *disk)
1175{
1176 label_part_info_t lpinfo;
1177 errno_t rc;
1178
1179 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_indices_update()");
1180
1181 fibril_mutex_lock(&vbds_parts_lock);
1182
1183 /* First unregister services for partitions whose index has changed */
1184 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
1185 fibril_rwlock_write_lock(&part->lock);
1186 if (part->svc_id != 0 && part->lpart->index != part->reg_idx) {
1187 rc = vbds_part_svc_unregister(part);
1188 if (rc != EOK) {
1189 fibril_rwlock_write_unlock(&part->lock);
1190 fibril_mutex_unlock(&vbds_parts_lock);
1191 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
1192 "un-registering partition.");
1193 return EIO;
1194 }
1195 }
1196
1197 fibril_rwlock_write_unlock(&part->lock);
1198 }
1199
1200 /* Now re-register those services under the new indices */
1201 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
1202 fibril_rwlock_write_lock(&part->lock);
1203 label_part_get_info(part->lpart, &lpinfo);
1204 if (part->svc_id == 0 && lpinfo.pkind != lpk_extended) {
1205 rc = vbds_part_svc_register(part);
1206 if (rc != EOK) {
1207 fibril_rwlock_write_unlock(&part->lock);
1208 fibril_mutex_unlock(&vbds_parts_lock);
1209 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
1210 "re-registering partition.");
1211 return EIO;
1212 }
1213 }
1214
1215 fibril_rwlock_write_unlock(&part->lock);
1216 }
1217
1218 fibril_mutex_unlock(&vbds_parts_lock);
1219
1220 return EOK;
1221}
1222
1223/** Get block size wrapper for liblabel */
1224static errno_t vbds_label_get_bsize(void *arg, size_t *bsize)
1225{
1226 vbds_disk_t *disk = (vbds_disk_t *)arg;
1227 return block_get_bsize(disk->svc_id, bsize);
1228}
1229
1230/** Get number of blocks wrapper for liblabel */
1231static errno_t vbds_label_get_nblocks(void *arg, aoff64_t *nblocks)
1232{
1233 vbds_disk_t *disk = (vbds_disk_t *)arg;
1234 return block_get_nblocks(disk->svc_id, nblocks);
1235}
1236
1237/** Read blocks wrapper for liblabel */
1238static errno_t vbds_label_read(void *arg, aoff64_t ba, size_t cnt, void *buf)
1239{
1240 vbds_disk_t *disk = (vbds_disk_t *)arg;
1241 return block_read_direct(disk->svc_id, ba, cnt, buf);
1242}
1243
1244/** Write blocks wrapper for liblabel */
1245static errno_t vbds_label_write(void *arg, aoff64_t ba, size_t cnt, const void *data)
1246{
1247 vbds_disk_t *disk = (vbds_disk_t *)arg;
1248 return block_write_direct(disk->svc_id, ba, cnt, data);
1249}
1250
1251/** @}
1252 */
Note: See TracBrowser for help on using the repository browser.