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

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

VBD label creation and destruction needs adjusting.

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