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

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

libfdisk should not depend on libblock nor should it access the block devices directly.

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