source: mainline/uspace/srv/bd/vbd/disk.c@ 774aa332

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 774aa332 was 774aa332, checked in by Jiri Svoboda <jiri@…>, 7 years ago

list_foreach loops with single-statement body are indented incorrectly.

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