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

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

Break liblabel dependency on libblock.

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