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

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

Merge mainline changes.

  • Property mode set to 100644
File size: 22.6 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_DEBUG, "vbds_part_by_pid(%zu)", partid);
176
177 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
178 log_msg(LOG_DEFAULT, LVL_DEBUG, "%zu == %zu ?", part->pid, partid);
179 if (part->pid == partid) {
180 log_msg(LOG_DEFAULT, LVL_DEBUG, "Found match.");
181 *rpart = part;
182 return EOK;
183 }
184 }
185
186 log_msg(LOG_DEFAULT, LVL_DEBUG, "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_DEBUG, "vbds_part_by_svcid(%zu)", svcid);
193
194 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
195 log_msg(LOG_DEFAULT, LVL_DEBUG, "%zu == %zu ?", part->svc_id, svcid);
196 if (part->svc_id == svcid) {
197 log_msg(LOG_DEFAULT, LVL_DEBUG, "Found match.");
198 *rpart = part;
199 return EOK;
200 }
201 }
202
203 log_msg(LOG_DEFAULT, LVL_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "vbds_part_remove(%p)", part);
263
264 lpart = part->lpart;
265
266 if (part->open_cnt > 0) {
267 log_msg(LOG_DEFAULT, LVL_DEBUG, "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_DEBUG, "vbds_disk_add(%zu)", sid);
358
359 /* Check for duplicates */
360 rc = vbds_disk_by_svcid(sid, &disk);
361 if (rc == EOK)
362 return EEXIST;
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_DEBUG, "block_init(%zu)", sid);
376 rc = block_init(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_ERROR, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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 if (rc != EOK)
493 return rc;
494
495 info->ltype = linfo.ltype;
496 info->flags = linfo.flags;
497 info->ablock0 = linfo.ablock0;
498 info->anblocks = linfo.anblocks;
499 info->block_size = disk->block_size;
500 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_info - block_size=%zu",
501 info->block_size);
502 return EOK;
503}
504
505int vbds_get_parts(service_id_t sid, service_id_t *id_buf, size_t buf_size,
506 size_t *act_size)
507{
508 vbds_disk_t *disk;
509 size_t act_cnt;
510 size_t buf_cnt;
511 int rc;
512
513 rc = vbds_disk_by_svcid(sid, &disk);
514 if (rc != EOK)
515 return rc;
516
517 buf_cnt = buf_size / sizeof(service_id_t);
518
519 act_cnt = list_count(&disk->parts);
520 *act_size = act_cnt * sizeof(service_id_t);
521
522 if (buf_size % sizeof(service_id_t) != 0)
523 return EINVAL;
524
525 size_t pos = 0;
526 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
527 if (pos < buf_cnt)
528 id_buf[pos] = part->pid;
529 pos++;
530 }
531
532 return EOK;
533}
534
535int vbds_label_create(service_id_t sid, label_type_t ltype)
536{
537 label_t *label;
538 label_info_t linfo;
539 vbds_disk_t *disk;
540 int rc;
541
542 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu)", sid);
543
544 /* Find disk */
545 rc = vbds_disk_by_svcid(sid, &disk);
546 if (rc != EOK)
547 return rc;
548
549 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - label_close", sid);
550
551 /* Verify that current label is a dummy label */
552 rc = label_get_info(disk->label, &linfo);
553 if (rc != EOK)
554 return rc;
555
556 if (linfo.ltype != lt_none) {
557 log_msg(LOG_DEFAULT, LVL_ERROR, "Label already exists.");
558 return EEXIST;
559 }
560
561 /* Close dummy label first */
562 rc = vbds_disk_parts_remove(disk);
563 if (rc != EOK) {
564 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
565 return rc;
566 }
567
568 label_close(disk->label);
569 disk->label = NULL;
570
571 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - label_create", sid);
572
573 rc = label_create(sid, ltype, &label);
574 if (rc != EOK)
575 goto error;
576
577 (void) vbds_disk_parts_add(disk, label);
578 disk->label = label;
579
580 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - success", sid);
581 return EOK;
582error:
583 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - failure", sid);
584 if (disk->label == NULL) {
585 rc = label_open(sid, &label);
586 if (rc != EOK) {
587 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
588 disk->svc_name);
589 }
590 }
591
592 return rc;
593}
594
595int vbds_label_delete(service_id_t sid)
596{
597 vbds_disk_t *disk;
598 label_t *label;
599 int rc;
600
601 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_delete(%zu)", sid);
602
603 rc = vbds_disk_by_svcid(sid, &disk);
604 if (rc != EOK)
605 return rc;
606
607 rc = vbds_disk_parts_remove(disk);
608 if (rc != EOK) {
609 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
610 return rc;
611 }
612
613 rc = label_destroy(disk->label);
614 if (rc != EOK) {
615 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
616 return rc;
617 }
618
619 disk->label = NULL;
620
621 rc = label_open(disk->svc_id, &label);
622 if (rc != EOK) {
623 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
624 disk->svc_name);
625 return EIO;
626 }
627
628 (void) vbds_disk_parts_add(disk, label);
629 disk->label = label;
630 return EOK;
631}
632
633int vbds_part_get_info(vbds_part_id_t partid, vbd_part_info_t *pinfo)
634{
635 vbds_part_t *part;
636 label_part_info_t lpinfo;
637 int rc;
638
639 rc = vbds_part_by_pid(partid, &part);
640 if (rc != EOK)
641 return rc;
642
643 label_part_get_info(part->lpart, &lpinfo);
644
645 pinfo->index = lpinfo.index;
646 pinfo->pkind = lpinfo.pkind;
647 pinfo->block0 = lpinfo.block0;
648 pinfo->nblocks = lpinfo.nblocks;
649 pinfo->svc_id = part->svc_id;
650 return EOK;
651}
652
653int vbds_part_create(service_id_t sid, vbd_part_spec_t *pspec,
654 vbds_part_id_t *rpart)
655{
656 vbds_disk_t *disk;
657 vbds_part_t *part;
658 label_part_spec_t lpspec;
659 label_part_t *lpart;
660 int rc;
661
662 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_create(%zu)", sid);
663
664 rc = vbds_disk_by_svcid(sid, &disk);
665 if (rc != EOK) {
666 log_msg(LOG_DEFAULT, LVL_ERROR, "Disk %zu not found",
667 sid);
668 goto error;
669 }
670
671 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_crate(%zu): "
672 "index=%d block0=%" PRIu64 " nblocks=%" PRIu64
673 " hdr_blocks=%" PRIu64 " pkind=%d",
674 sid, pspec->index, pspec->block0, pspec->nblocks, pspec->hdr_blocks,
675 pspec->pkind);
676
677 label_pspec_init(&lpspec);
678 lpspec.index = pspec->index;
679 lpspec.block0 = pspec->block0;
680 lpspec.nblocks = pspec->nblocks;
681 lpspec.hdr_blocks = pspec->hdr_blocks;
682 lpspec.pkind = pspec->pkind;
683 lpspec.ptype = pspec->ptype;
684
685 rc = label_part_create(disk->label, &lpspec, &lpart);
686 if (rc != EOK) {
687 log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating partition.");
688 goto error;
689 }
690
691 rc = vbds_part_indices_update(disk);
692 if (rc != EOK) {
693 log_msg(LOG_DEFAULT, LVL_ERROR, "Error updating partition indices");
694 goto error;
695 }
696
697 rc = vbds_part_add(disk, lpart, &part);
698 if (rc != EOK) {
699 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed while creating "
700 "partition.");
701 rc = label_part_destroy(lpart);
702 if (rc != EOK)
703 log_msg(LOG_DEFAULT, LVL_ERROR,
704 "Cannot roll back partition creation.");
705 rc = EIO;
706 goto error;
707 }
708
709 if (rpart != NULL)
710 *rpart = part->pid;
711 return EOK;
712error:
713 return rc;
714}
715
716int vbds_part_delete(vbds_part_id_t partid)
717{
718 vbds_part_t *part;
719 vbds_disk_t *disk;
720 label_part_t *lpart;
721 int rc;
722
723 rc = vbds_part_by_pid(partid, &part);
724 if (rc != EOK)
725 return rc;
726
727 disk = part->disk;
728
729 rc = vbds_part_remove(part, &lpart);
730 if (rc != EOK)
731 return rc;
732
733 rc = label_part_destroy(lpart);
734 if (rc != EOK) {
735 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting partition");
736
737 /* Try rolling back */
738 rc = vbds_part_add(disk, lpart, NULL);
739 if (rc != EOK)
740 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed rolling back.");
741
742 return EIO;
743 }
744
745 rc = vbds_part_indices_update(disk);
746 if (rc != EOK) {
747 log_msg(LOG_DEFAULT, LVL_ERROR, "Error updating partition indices");
748 return EIO;
749 }
750
751 return EOK;
752}
753
754int vbds_suggest_ptype(service_id_t sid, label_pcnt_t pcnt,
755 label_ptype_t *ptype)
756{
757 vbds_disk_t *disk;
758 int rc;
759
760 rc = vbds_disk_by_svcid(sid, &disk);
761 if (rc != EOK) {
762 log_msg(LOG_DEFAULT, LVL_DEBUG, "Disk %zu not found",
763 sid);
764 goto error;
765 }
766
767 rc = label_suggest_ptype(disk->label, pcnt, ptype);
768 if (rc != EOK) {
769 log_msg(LOG_DEFAULT, LVL_DEBUG, "label_suggest_ptype() failed");
770 goto error;
771 }
772
773 return EOK;
774error:
775 return rc;
776}
777
778static int vbds_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
779{
780 vbds_part_t *part = bd_srv_part(bd);
781
782 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_open()");
783 part->open_cnt++;
784 return EOK;
785}
786
787static int vbds_bd_close(bd_srv_t *bd)
788{
789 vbds_part_t *part = bd_srv_part(bd);
790
791 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_close()");
792 part->open_cnt--;
793 return EOK;
794}
795
796static int vbds_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
797 void *buf, size_t size)
798{
799 vbds_part_t *part = bd_srv_part(bd);
800 aoff64_t gba;
801
802 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_read_blocks()");
803
804 if (cnt * part->disk->block_size < size)
805 return EINVAL;
806
807 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK)
808 return ELIMIT;
809
810 return block_read_direct(part->disk->svc_id, gba, cnt, buf);
811}
812
813static int vbds_bd_sync_cache(bd_srv_t *bd, aoff64_t ba, size_t cnt)
814{
815 vbds_part_t *part = bd_srv_part(bd);
816 aoff64_t gba;
817
818 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_sync_cache()");
819
820 /* XXX Allow full-disk sync? */
821 if (ba != 0 || cnt != 0) {
822 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK)
823 return ELIMIT;
824 } else {
825 gba = 0;
826 }
827
828 return block_sync_cache(part->disk->svc_id, gba, cnt);
829}
830
831static int vbds_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
832 const void *buf, size_t size)
833{
834 vbds_part_t *part = bd_srv_part(bd);
835 aoff64_t gba;
836
837 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_write_blocks()");
838
839 if (cnt * part->disk->block_size < size)
840 return EINVAL;
841
842 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK)
843 return ELIMIT;
844
845 return block_write_direct(part->disk->svc_id, gba, cnt, buf);
846}
847
848static int vbds_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
849{
850 vbds_part_t *part = bd_srv_part(bd);
851
852 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_get_block_size()");
853 *rsize = part->disk->block_size;
854 return EOK;
855}
856
857static int vbds_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
858{
859 vbds_part_t *part = bd_srv_part(bd);
860
861 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_get_num_blocks()");
862 *rnb = part->nblocks;
863 return EOK;
864}
865
866void vbds_bd_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
867{
868 vbds_part_t *part;
869 int rc;
870 service_id_t svcid;
871
872 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn()");
873
874 svcid = IPC_GET_ARG2(*icall);
875
876 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn() - svcid=%zu", svcid);
877
878 rc = vbds_part_by_svcid(svcid, &part);
879 if (rc != EOK) {
880 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_bd_conn() - partition "
881 "not found.");
882 async_answer_0(iid, EINVAL);
883 return;
884 }
885
886 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn() - call bd_conn");
887 bd_conn(iid, icall, &part->bds);
888}
889
890/** Translate block segment address with range checking. */
891static int vbds_bsa_translate(vbds_part_t *part, aoff64_t ba, size_t cnt,
892 aoff64_t *gba)
893{
894 if (ba + cnt > part->nblocks)
895 return ELIMIT;
896
897 *gba = part->block0 + ba;
898 return EOK;
899}
900
901/** Register service for partition */
902static int vbds_part_svc_register(vbds_part_t *part)
903{
904 char *name;
905 service_id_t psid;
906 int idx;
907 int rc;
908
909 idx = part->lpart->index;
910
911 rc = asprintf(&name, "%sp%u", part->disk->svc_name, idx);
912 if (rc < 0) {
913 log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
914 return ENOMEM;
915 }
916
917 log_msg(LOG_DEFAULT, LVL_DEBUG, "loc_service_register('%s')",
918 name);
919 rc = loc_service_register(name, &psid);
920 if (rc != EOK) {
921 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering "
922 "service %s (%d).", name, rc);
923 free(name);
924 free(part);
925 return EIO;
926 }
927
928 rc = loc_service_add_to_cat(psid, part_cid);
929 if (rc != EOK) {
930 log_msg(LOG_DEFAULT, LVL_ERROR, "Failled adding partition "
931 "service %s to partition category.", name);
932 free(name);
933 free(part);
934
935 rc = loc_service_unregister(psid);
936 if (rc != EOK) {
937 log_msg(LOG_DEFAULT, LVL_ERROR, "Error unregistering "
938 "service. Rollback failed.");
939 }
940 return EIO;
941 }
942
943 free(name);
944 part->svc_id = psid;
945 part->reg_idx = idx;
946 return EOK;
947}
948
949/** Unregister service for partition */
950static int vbds_part_svc_unregister(vbds_part_t *part)
951{
952 int rc;
953
954 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_svc_unregister("
955 "disk->svc_name='%s', id=%zu)", part->disk->svc_name, part->svc_id);
956
957 rc = loc_service_unregister(part->svc_id);
958 if (rc != EOK)
959 return EIO;
960
961 part->svc_id = 0;
962 part->reg_idx = 0;
963 return EOK;
964}
965
966/** Update service names for any partition whose index has changed. */
967static int vbds_part_indices_update(vbds_disk_t *disk)
968{
969 label_part_info_t lpinfo;
970 int rc;
971
972 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_indices_update()");
973
974 /* First unregister services for partitions whose index has changed */
975 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
976 if (part->svc_id != 0 && part->lpart->index != part->reg_idx) {
977 rc = vbds_part_svc_unregister(part);
978 if (rc != EOK) {
979 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
980 "un-registering partition.");
981 return EIO;
982 }
983 }
984 }
985
986 /* Now re-register those services under the new indices */
987 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
988 label_part_get_info(part->lpart, &lpinfo);
989 if (part->svc_id == 0 && lpinfo.pkind != lpk_extended) {
990 rc = vbds_part_svc_register(part);
991 if (rc != EOK) {
992 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
993 "re-registering partition.");
994 return EIO;
995 }
996 }
997 }
998
999 return EOK;
1000}
1001
1002/** @}
1003 */
Note: See TracBrowser for help on using the repository browser.