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

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

Let VBD handle unlabeled devices too. Now volsrv only cares about partitions.

  • Property mode set to 100644
File size: 21.2 KB
Line 
1/*
2 * Copyright (c) 2015 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 list_t vbds_parts; /* of vbds_part_t */
53
54static category_id_t part_cid;
55
56static int vbds_bd_open(bd_srvs_t *, bd_srv_t *);
57static int vbds_bd_close(bd_srv_t *);
58static int vbds_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
59static int vbds_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
60static int vbds_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *,
61 size_t);
62static int vbds_bd_get_block_size(bd_srv_t *, size_t *);
63static int vbds_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
64
65static int vbds_bsa_translate(vbds_part_t *, aoff64_t, size_t, aoff64_t *);
66
67static int vbds_part_svc_register(vbds_part_t *);
68static int vbds_part_svc_unregister(vbds_part_t *);
69static int vbds_part_indices_update(vbds_disk_t *);
70
71static vbd_part_id_t vbds_part_id = 1;
72
73static bd_ops_t vbds_bd_ops = {
74 .open = vbds_bd_open,
75 .close = vbds_bd_close,
76 .read_blocks = vbds_bd_read_blocks,
77 .sync_cache = vbds_bd_sync_cache,
78 .write_blocks = vbds_bd_write_blocks,
79 .get_block_size = vbds_bd_get_block_size,
80 .get_num_blocks = vbds_bd_get_num_blocks
81};
82
83static vbds_part_t *bd_srv_part(bd_srv_t *bd)
84{
85 return (vbds_part_t *)bd->srvs->sarg;
86}
87
88int vbds_disks_init(void)
89{
90 int rc;
91
92 fibril_mutex_initialize(&vbds_disks_lock);
93 list_initialize(&vbds_disks);
94 list_initialize(&vbds_parts);
95
96 rc = loc_category_get_id("partition", &part_cid, 0);
97 if (rc != EOK) {
98 log_msg(LOG_DEFAULT, LVL_ERROR, "Error looking up partition "
99 "category.");
100 return EIO;
101 }
102
103 return EOK;
104}
105
106/** Check for new disk devices */
107static int vbds_disks_check_new(void)
108{
109 bool already_known;
110 category_id_t disk_cat;
111 service_id_t *svcs;
112 size_t count, i;
113 int rc;
114
115 fibril_mutex_lock(&vbds_disks_lock);
116
117 rc = loc_category_get_id("disk", &disk_cat, IPC_FLAG_BLOCKING);
118 if (rc != EOK) {
119 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'disk'.");
120 fibril_mutex_unlock(&vbds_disks_lock);
121 return ENOENT;
122 }
123
124 rc = loc_category_get_svcs(disk_cat, &svcs, &count);
125 if (rc != EOK) {
126 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of disk "
127 "devices.");
128 fibril_mutex_unlock(&vbds_disks_lock);
129 return EIO;
130 }
131
132 for (i = 0; i < count; i++) {
133 already_known = false;
134
135 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
136 if (disk->svc_id == svcs[i]) {
137 already_known = true;
138 break;
139 }
140 }
141
142 if (!already_known) {
143 log_msg(LOG_DEFAULT, LVL_NOTE, "Found disk '%lu'",
144 (unsigned long) svcs[i]);
145 rc = vbds_disk_add(svcs[i]);
146 if (rc != EOK) {
147 log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add "
148 "disk.");
149 }
150 }
151 }
152
153 fibril_mutex_unlock(&vbds_disks_lock);
154 return EOK;
155}
156
157
158static int vbds_disk_by_svcid(service_id_t sid, vbds_disk_t **rdisk)
159{
160 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
161 if (disk->svc_id == sid) {
162 *rdisk = disk;
163 return EOK;
164 }
165 }
166
167 return ENOENT;
168}
169
170static int vbds_part_by_pid(vbds_part_id_t partid, vbds_part_t **rpart)
171{
172 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_by_pid(%zu)", partid);
173
174 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
175 log_msg(LOG_DEFAULT, LVL_NOTE, "%zu == %zu ?", part->pid, partid);
176 if (part->pid == partid) {
177 log_msg(LOG_DEFAULT, LVL_NOTE, "Found match.");
178 *rpart = part;
179 return EOK;
180 }
181 }
182
183 log_msg(LOG_DEFAULT, LVL_NOTE, "No match.");
184 return ENOENT;
185}
186
187static int vbds_part_by_svcid(service_id_t svcid, vbds_part_t **rpart)
188{
189 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_by_svcid(%zu)", svcid);
190
191 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
192 log_msg(LOG_DEFAULT, LVL_NOTE, "%zu == %zu ?", part->svc_id, svcid);
193 if (part->svc_id == svcid) {
194 log_msg(LOG_DEFAULT, LVL_NOTE, "Found match.");
195 *rpart = part;
196 return EOK;
197 }
198 }
199
200 log_msg(LOG_DEFAULT, LVL_NOTE, "No match.");
201 return ENOENT;
202}
203
204/** Add partition to our inventory based on liblabel partition structure */
205static int vbds_part_add(vbds_disk_t *disk, label_part_t *lpart,
206 vbds_part_t **rpart)
207{
208 vbds_part_t *part;
209 service_id_t psid = 0;
210 label_part_info_t lpinfo;
211 int rc;
212
213 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_add(%s, %p)",
214 disk->svc_name, lpart);
215
216 label_part_get_info(lpart, &lpinfo);
217
218 part = calloc(1, sizeof(vbds_part_t));
219 if (part == NULL) {
220 log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
221 return ENOMEM;
222 }
223
224 part->lpart = lpart;
225 part->disk = disk;
226 part->pid = ++vbds_part_id;
227 part->svc_id = psid;
228 part->block0 = lpinfo.block0;
229 part->nblocks = lpinfo.nblocks;
230
231 bd_srvs_init(&part->bds);
232 part->bds.ops = &vbds_bd_ops;
233 part->bds.sarg = part;
234
235 if (lpinfo.pkind != lpk_extended) {
236 rc = vbds_part_svc_register(part);
237 if (rc != EOK)
238 return EIO;
239 }
240
241 list_append(&part->ldisk, &disk->parts);
242 list_append(&part->lparts, &vbds_parts);
243
244 if (rpart != NULL)
245 *rpart = part;
246 return EOK;
247}
248
249/** Remove partition from our inventory leaving only the underlying liblabel
250 * partition structure.
251 */
252static int vbds_part_remove(vbds_part_t *part, label_part_t **rlpart)
253{
254 label_part_t *lpart;
255 int rc;
256
257 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_remove(%p)", part);
258
259 lpart = part->lpart;
260
261 if (part->open_cnt > 0)
262 return EBUSY;
263
264 if (part->svc_id != 0) {
265 rc = vbds_part_svc_unregister(part);
266 if (rc != EOK)
267 return EIO;
268 }
269
270 list_remove(&part->ldisk);
271 list_remove(&part->lparts);
272 free(part);
273
274 if (rlpart != NULL)
275 *rlpart = lpart;
276 return EOK;
277}
278
279static void vbds_disk_cat_change_cb(void)
280{
281 (void) vbds_disks_check_new();
282}
283
284int vbds_disk_discovery_start(void)
285{
286 int rc;
287
288 rc = loc_register_cat_change_cb(vbds_disk_cat_change_cb);
289 if (rc != EOK) {
290 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
291 "for disk discovery (%d).", rc);
292 return rc;
293 }
294
295 return vbds_disks_check_new();
296}
297
298int vbds_disk_add(service_id_t sid)
299{
300 label_t *label = NULL;
301 label_part_t *part;
302 vbds_disk_t *disk = NULL;
303 bool block_inited = false;
304 size_t block_size;
305 int rc;
306
307 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_add(%zu)", sid);
308
309 /* Check for duplicates */
310 rc = vbds_disk_by_svcid(sid, &disk);
311 if (rc == EOK)
312 return EEXISTS;
313
314 disk = calloc(1, sizeof(vbds_disk_t));
315 if (disk == NULL)
316 return ENOMEM;
317
318 rc = loc_service_get_name(sid, &disk->svc_name);
319 if (rc != EOK) {
320 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting disk service name.");
321 rc = EIO;
322 goto error;
323 }
324
325 log_msg(LOG_DEFAULT, LVL_NOTE, "block_init(%zu)", sid);
326 rc = block_init(EXCHANGE_SERIALIZE, sid, 2048);
327 if (rc != EOK) {
328 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening block device %s.",
329 disk->svc_name);
330 rc = EIO;
331 goto error;
332 }
333
334 rc = block_get_bsize(sid, &block_size);
335 if (rc != EOK) {
336 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting block size of %s.",
337 disk->svc_name);
338 rc = EIO;
339 goto error;
340 }
341
342 block_inited = true;
343
344 rc = label_open(sid, &label);
345 if (rc != EOK) {
346 log_msg(LOG_DEFAULT, LVL_NOTE, "Label in disk %s not recognized.",
347 disk->svc_name);
348 rc = EIO;
349 goto error;
350 }
351
352 disk->svc_id = sid;
353 disk->label = label;
354 disk->block_size = block_size;
355
356 list_initialize(&disk->parts);
357 list_append(&disk->ldisks, &vbds_disks);
358
359 log_msg(LOG_DEFAULT, LVL_NOTE, "Recognized disk label. Adding partitions.");
360
361 part = label_part_first(label);
362 while (part != NULL) {
363 rc = vbds_part_add(disk, part, NULL);
364 if (rc != EOK) {
365 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding partition "
366 "(disk %s)", disk->svc_name);
367 }
368
369 part = label_part_next(part);
370 }
371
372 return EOK;
373error:
374 label_close(label);
375 if (block_inited) {
376 log_msg(LOG_DEFAULT, LVL_NOTE, "block_fini(%zu)", sid);
377 block_fini(sid);
378 }
379 if (disk != NULL)
380 free(disk->svc_name);
381 free(disk);
382 return rc;
383}
384
385int vbds_disk_remove(service_id_t sid)
386{
387 vbds_disk_t *disk;
388 int rc;
389
390 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_remove(%zu)", sid);
391
392 rc = vbds_disk_by_svcid(sid, &disk);
393 if (rc != EOK)
394 return rc;
395
396 list_remove(&disk->ldisks);
397 label_close(disk->label);
398 log_msg(LOG_DEFAULT, LVL_NOTE, "block_fini(%zu)", sid);
399 block_fini(sid);
400 free(disk);
401 return EOK;
402}
403
404/** Get list of disks as array of service IDs. */
405int vbds_disk_get_ids(service_id_t *id_buf, size_t buf_size, size_t *act_size)
406{
407 size_t act_cnt;
408 size_t buf_cnt;
409
410 fibril_mutex_lock(&vbds_disks_lock);
411
412 buf_cnt = buf_size / sizeof(service_id_t);
413
414 act_cnt = list_count(&vbds_disks);
415 *act_size = act_cnt * sizeof(service_id_t);
416
417 if (buf_size % sizeof(service_id_t) != 0) {
418 fibril_mutex_unlock(&vbds_disks_lock);
419 return EINVAL;
420 }
421
422 size_t pos = 0;
423 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
424 if (pos < buf_cnt)
425 id_buf[pos] = disk->svc_id;
426 pos++;
427 }
428
429 fibril_mutex_unlock(&vbds_disks_lock);
430 return EOK;
431}
432
433int vbds_disk_info(service_id_t sid, vbd_disk_info_t *info)
434{
435 vbds_disk_t *disk;
436 label_info_t linfo;
437 int rc;
438
439 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_info(%zu)", sid);
440
441 rc = vbds_disk_by_svcid(sid, &disk);
442 if (rc != EOK)
443 return rc;
444
445 rc = label_get_info(disk->label, &linfo);
446
447 info->ltype = linfo.ltype;
448 info->flags = linfo.flags;
449 info->ablock0 = linfo.ablock0;
450 info->anblocks = linfo.anblocks;
451 info->block_size = disk->block_size;
452 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_info - block_size=%zu",
453 info->block_size);
454 return EOK;
455}
456
457int vbds_get_parts(service_id_t sid, service_id_t *id_buf, size_t buf_size,
458 size_t *act_size)
459{
460 vbds_disk_t *disk;
461 size_t act_cnt;
462 size_t buf_cnt;
463 int rc;
464
465 rc = vbds_disk_by_svcid(sid, &disk);
466 if (rc != EOK)
467 return rc;
468
469 buf_cnt = buf_size / sizeof(service_id_t);
470
471 act_cnt = list_count(&disk->parts);
472 *act_size = act_cnt * sizeof(service_id_t);
473
474 if (buf_size % sizeof(service_id_t) != 0)
475 return EINVAL;
476
477 size_t pos = 0;
478 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
479 if (pos < buf_cnt)
480 id_buf[pos] = part->pid;
481 pos++;
482 }
483
484 return EOK;
485}
486
487
488int vbds_label_create(service_id_t sid, label_type_t ltype)
489{
490 label_t *label;
491 vbds_disk_t *disk;
492 bool block_inited = false;
493 size_t block_size;
494 int rc;
495
496 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu)", sid);
497
498 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - chkdup", sid);
499
500 /* Check for duplicates */
501 rc = vbds_disk_by_svcid(sid, &disk);
502 if (rc == EOK)
503 return EEXISTS;
504
505 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - alloc", sid);
506
507 disk = calloc(1, sizeof(vbds_disk_t));
508 if (disk == NULL)
509 return ENOMEM;
510
511 rc = loc_service_get_name(sid, &disk->svc_name);
512 if (rc != EOK) {
513 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting disk service name.");
514 rc = EIO;
515 goto error;
516 }
517
518 log_msg(LOG_DEFAULT, LVL_NOTE, "block_init(%zu)", sid);
519 rc = block_init(EXCHANGE_SERIALIZE, sid, 2048);
520 if (rc != EOK) {
521 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening block device %s.",
522 disk->svc_name);
523 rc = EIO;
524 goto error;
525 }
526
527 rc = block_get_bsize(sid, &block_size);
528 if (rc != EOK) {
529 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting block size of %s.",
530 disk->svc_name);
531 rc = EIO;
532 goto error;
533 }
534
535 block_inited = true;
536
537 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - label_create", sid);
538
539 rc = label_create(sid, ltype, &label);
540 if (rc != EOK)
541 goto error;
542
543 disk->svc_id = sid;
544 disk->label = label;
545 disk->block_size = block_size;
546 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create: block_size=%zu",
547 block_size);
548 list_initialize(&disk->parts);
549
550 list_append(&disk->ldisks, &vbds_disks);
551
552 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - success", sid);
553 return EOK;
554error:
555 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - failure", sid);
556 if (block_inited) {
557 log_msg(LOG_DEFAULT, LVL_NOTE, "block_fini(%zu)", sid);
558 block_fini(sid);
559 }
560 if (disk != NULL)
561 free(disk->svc_name);
562 free(disk);
563 return rc;
564}
565
566int vbds_label_delete(service_id_t sid)
567{
568 vbds_disk_t *disk;
569 int rc;
570
571 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_delete(%zu)", sid);
572
573 rc = vbds_disk_by_svcid(sid, &disk);
574 if (rc != EOK)
575 return rc;
576
577 rc = label_destroy(disk->label);
578 if (rc != EOK) {
579 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
580 return rc;
581 }
582
583 list_remove(&disk->ldisks);
584 log_msg(LOG_DEFAULT, LVL_NOTE, "block_fini(%zu)", sid);
585 block_fini(sid);
586 free(disk);
587 return EOK;
588}
589
590int vbds_part_get_info(vbds_part_id_t partid, vbd_part_info_t *pinfo)
591{
592 vbds_part_t *part;
593 label_part_info_t lpinfo;
594 int rc;
595
596 rc = vbds_part_by_pid(partid, &part);
597 if (rc != EOK)
598 return rc;
599
600 label_part_get_info(part->lpart, &lpinfo);
601
602 pinfo->index = lpinfo.index;
603 pinfo->pkind = lpinfo.pkind;
604 pinfo->block0 = lpinfo.block0;
605 pinfo->nblocks = lpinfo.nblocks;
606 return EOK;
607}
608
609int vbds_part_create(service_id_t sid, vbd_part_spec_t *pspec,
610 vbds_part_id_t *rpart)
611{
612 vbds_disk_t *disk;
613 vbds_part_t *part;
614 label_part_spec_t lpspec;
615 label_part_t *lpart;
616 int rc;
617
618 rc = vbds_disk_by_svcid(sid, &disk);
619 if (rc != EOK) {
620 log_msg(LOG_DEFAULT, LVL_NOTE, "Disk %zu not found",
621 sid);
622 goto error;
623 }
624
625 label_pspec_init(&lpspec);
626 lpspec.index = pspec->index;
627 lpspec.block0 = pspec->block0;
628 lpspec.nblocks = pspec->nblocks;
629 lpspec.hdr_blocks = pspec->hdr_blocks;
630 lpspec.pkind = pspec->pkind;
631 lpspec.ptype = pspec->ptype;
632
633 rc = label_part_create(disk->label, &lpspec, &lpart);
634 if (rc != EOK) {
635 log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating partition.");
636 goto error;
637 }
638
639 rc = vbds_part_indices_update(disk);
640 if (rc != EOK) {
641 log_msg(LOG_DEFAULT, LVL_ERROR, "Error updating partition indices");
642 goto error;
643 }
644
645 rc = vbds_part_add(disk, lpart, &part);
646 if (rc != EOK) {
647 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed while creating "
648 "partition.");
649 rc = label_part_destroy(lpart);
650 if (rc != EOK)
651 log_msg(LOG_DEFAULT, LVL_ERROR,
652 "Cannot roll back partition creation.");
653 rc = EIO;
654 goto error;
655 }
656
657 if (rpart != NULL)
658 *rpart = part->pid;
659 return EOK;
660error:
661 return rc;
662}
663
664int vbds_part_delete(vbds_part_id_t partid)
665{
666 vbds_part_t *part;
667 vbds_disk_t *disk;
668 label_part_t *lpart;
669 int rc;
670
671 rc = vbds_part_by_pid(partid, &part);
672 if (rc != EOK)
673 return rc;
674
675 disk = part->disk;
676
677 rc = vbds_part_remove(part, &lpart);
678 if (rc != EOK)
679 return rc;
680
681 rc = label_part_destroy(lpart);
682 if (rc != EOK) {
683 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting partition");
684
685 /* Try rolling back */
686 rc = vbds_part_add(disk, lpart, NULL);
687 if (rc != EOK)
688 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed rolling back.");
689
690 return EIO;
691 }
692
693 rc = vbds_part_indices_update(disk);
694 if (rc != EOK) {
695 log_msg(LOG_DEFAULT, LVL_ERROR, "Error updating partition indices");
696 return EIO;
697 }
698
699 return EOK;
700}
701
702int vbds_suggest_ptype(service_id_t sid, label_pcnt_t pcnt,
703 label_ptype_t *ptype)
704{
705 vbds_disk_t *disk;
706 int rc;
707
708 rc = vbds_disk_by_svcid(sid, &disk);
709 if (rc != EOK) {
710 log_msg(LOG_DEFAULT, LVL_NOTE, "Disk %zu not found",
711 sid);
712 goto error;
713 }
714
715 rc = label_suggest_ptype(disk->label, pcnt, ptype);
716 if (rc != EOK) {
717 log_msg(LOG_DEFAULT, LVL_NOTE, "label_suggest_ptype() failed");
718 goto error;
719 }
720
721 return EOK;
722error:
723 return rc;
724}
725
726static int vbds_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
727{
728 vbds_part_t *part = bd_srv_part(bd);
729
730 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_open()");
731 part->open_cnt++;
732 return EOK;
733}
734
735static int vbds_bd_close(bd_srv_t *bd)
736{
737 vbds_part_t *part = bd_srv_part(bd);
738
739 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_close()");
740 part->open_cnt--;
741 return EOK;
742}
743
744static int vbds_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
745 void *buf, size_t size)
746{
747 vbds_part_t *part = bd_srv_part(bd);
748 aoff64_t gba;
749
750 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_read_blocks()");
751
752 if (cnt * part->disk->block_size < size)
753 return EINVAL;
754
755 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK)
756 return ELIMIT;
757
758 return block_read_direct(part->disk->svc_id, gba, cnt, buf);
759}
760
761static int vbds_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt)
762{
763 vbds_part_t *part = bd_srv_part(bd);
764 aoff64_t gba;
765
766 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_sync_cache()");
767
768 /* XXX Allow full-disk sync? */
769 if (ba != 0 || cnt != 0) {
770 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK)
771 return ELIMIT;
772 } else {
773 gba = 0;
774 }
775
776 return block_sync_cache(part->disk->svc_id, gba, cnt);
777}
778
779static int vbds_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
780 const void *buf, size_t size)
781{
782 vbds_part_t *part = bd_srv_part(bd);
783 aoff64_t gba;
784
785 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_write_blocks()");
786
787 if (cnt * part->disk->block_size < size)
788 return EINVAL;
789
790 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK)
791 return ELIMIT;
792
793 return block_write_direct(part->disk->svc_id, gba, cnt, buf);
794}
795
796static int vbds_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
797{
798 vbds_part_t *part = bd_srv_part(bd);
799
800 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_get_block_size()");
801 *rsize = part->disk->block_size;
802 return EOK;
803}
804
805static int vbds_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
806{
807 vbds_part_t *part = bd_srv_part(bd);
808
809 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_get_num_blocks()");
810 *rnb = part->nblocks;
811 return EOK;
812}
813
814void vbds_bd_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
815{
816 vbds_part_t *part;
817 int rc;
818 service_id_t svcid;
819
820 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_conn()");
821
822 svcid = IPC_GET_ARG1(*icall);
823
824 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_conn() - svcid=%zu", svcid);
825
826 rc = vbds_part_by_svcid(svcid, &part);
827 if (rc != EOK) {
828 log_msg(LOG_DEFAULT, LVL_NOTE, "vbd_bd_conn() - partition "
829 "not found.");
830 async_answer_0(iid, EINVAL);
831 return;
832 }
833
834 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_bd_conn() - call bd_conn");
835 bd_conn(iid, icall, &part->bds);
836}
837
838/** Translate block segment address with range checking. */
839static int vbds_bsa_translate(vbds_part_t *part, aoff64_t ba, size_t cnt,
840 aoff64_t *gba)
841{
842 if (ba + cnt > part->nblocks)
843 return ELIMIT;
844
845 *gba = part->block0 + ba;
846 return EOK;
847}
848
849/** Register service for partition */
850static int vbds_part_svc_register(vbds_part_t *part)
851{
852 char *name;
853 service_id_t psid;
854 int idx;
855 int rc;
856
857 idx = part->lpart->index;
858
859 rc = asprintf(&name, "%sp%u", part->disk->svc_name, idx);
860 if (rc < 0) {
861 log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
862 return ENOMEM;
863 }
864
865 rc = loc_service_register(name, &psid);
866 if (rc != EOK) {
867 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering "
868 "service %s (%d).", name, rc);
869 free(name);
870 free(part);
871 return EIO;
872 }
873
874 rc = loc_service_add_to_cat(psid, part_cid);
875 if (rc != EOK) {
876 log_msg(LOG_DEFAULT, LVL_ERROR, "Failled adding partition "
877 "service %s to partition category.", name);
878 free(name);
879 free(part);
880
881 rc = loc_service_unregister(psid);
882 if (rc != EOK) {
883 log_msg(LOG_DEFAULT, LVL_ERROR, "Error unregistering "
884 "service. Rollback failed.");
885 }
886 return EIO;
887 }
888
889 free(name);
890 part->svc_id = psid;
891 part->reg_idx = idx;
892 return EOK;
893}
894
895/** Unregister service for partition */
896static int vbds_part_svc_unregister(vbds_part_t *part)
897{
898 int rc;
899
900 rc = loc_service_unregister(part->svc_id);
901 if (rc != EOK)
902 return EIO;
903
904 part->svc_id = 0;
905 part->reg_idx = 0;
906 return EOK;
907}
908
909/** Update service names for any partition whose index has changed. */
910static int vbds_part_indices_update(vbds_disk_t *disk)
911{
912 label_part_info_t lpinfo;
913 int rc;
914
915 log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_indices_update()");
916
917 /* First unregister services for partitions whose index has changed */
918 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
919 if (part->svc_id != 0 && part->lpart->index != part->reg_idx) {
920 rc = vbds_part_svc_unregister(part);
921 if (rc != EOK) {
922 log_msg(LOG_DEFAULT, LVL_NOTE, "Error "
923 "un-registering partition.");
924 return EIO;
925 }
926 }
927 }
928
929 /* Now re-register those services under the new indices */
930 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
931 label_part_get_info(part->lpart, &lpinfo);
932 if (part->svc_id == 0 && lpinfo.pkind != lpk_extended) {
933 rc = vbds_part_svc_register(part);
934 if (rc != EOK) {
935 log_msg(LOG_DEFAULT, LVL_NOTE, "Error "
936 "re-registering partition.");
937 return EIO;
938 }
939 }
940 }
941
942 return EOK;
943}
944
945/** @}
946 */
Note: See TracBrowser for help on using the repository browser.