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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d5c1051 was d5c1051, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

"Obviously harmless" error handling tweaks.

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