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

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

VBD should take note of devices disappearing.

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