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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 659ebd86 was 53e3950, checked in by Jiri Svoboda <jiri@…>, 10 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
RevLine 
[28ed0d95]1/*
[e11c527]2 * Copyright (c) 2016 Jiri Svoboda
[28ed0d95]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>
[78d50bd]37#include <bd_srv.h>
38#include <block.h>
[28ed0d95]39#include <errno.h>
40#include <io/log.h>
[78d50bd]41#include <loc.h>
42#include <stdio.h>
[28ed0d95]43#include <stdlib.h>
44#include <task.h>
[6a0d4ce2]45#include <vbd.h>
[28ed0d95]46
47#include "disk.h"
48#include "types/vbd.h"
49
[372df8f]50static fibril_mutex_t vbds_disks_lock;
[28ed0d95]51static list_t vbds_disks; /* of vbds_disk_t */
[e11c527]52static fibril_mutex_t vbds_parts_lock;
[78d50bd]53static list_t vbds_parts; /* of vbds_part_t */
54
[372df8f]55static category_id_t part_cid;
56
[3a43785]57static int vbds_disk_parts_add(vbds_disk_t *, label_t *);
[e11c527]58static int vbds_disk_parts_remove(vbds_disk_t *, vbds_rem_flag_t);
[3a43785]59
[78d50bd]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
[6439741]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
[c43db5f]75static vbd_part_id_t vbds_part_id = 1;
76
[78d50bd]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}
[28ed0d95]91
[3a9cf35]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
[372df8f]117int vbds_disks_init(void)
[28ed0d95]118{
[372df8f]119 int rc;
120
121 fibril_mutex_initialize(&vbds_disks_lock);
[28ed0d95]122 list_initialize(&vbds_disks);
[e11c527]123 fibril_mutex_initialize(&vbds_parts_lock);
[78d50bd]124 list_initialize(&vbds_parts);
[372df8f]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
[3a9cf35]136/** Check for new/removed disk devices */
[372df8f]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;
[3a9cf35]143 vbds_disk_t *cur, *next;
[372df8f]144 int rc;
145
[3a9cf35]146 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disks_check_new()");
147
[372df8f]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
[3a9cf35]165 list_foreach(vbds_disks, ldisks, vbds_disk_t, disk)
166 disk->present = false;
167
[372df8f]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;
[3a9cf35]174 disk->present = true;
[372df8f]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 }
[3a9cf35]187 } else {
188 log_msg(LOG_DEFAULT, LVL_DEBUG, "Disk %lu already known",
189 (unsigned long) svcs[i]);
[372df8f]190 }
191 }
192
[3a9cf35]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
[372df8f]209 fibril_mutex_unlock(&vbds_disks_lock);
210 return EOK;
[28ed0d95]211}
212
[372df8f]213
[28ed0d95]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
[e11c527]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
[c43db5f]241static int vbds_part_by_pid(vbds_part_id_t partid, vbds_part_t **rpart)
242{
[55f8c6e7]243 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_by_pid(%zu)", partid);
[c43db5f]244
[e11c527]245 fibril_mutex_lock(&vbds_parts_lock);
246
[c43db5f]247 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
[55f8c6e7]248 log_msg(LOG_DEFAULT, LVL_DEBUG, "%zu == %zu ?", part->pid, partid);
[c43db5f]249 if (part->pid == partid) {
[55f8c6e7]250 log_msg(LOG_DEFAULT, LVL_DEBUG, "Found match.");
[e11c527]251 vbds_part_add_ref(part);
252 fibril_mutex_unlock(&vbds_parts_lock);
[c43db5f]253 *rpart = part;
254 return EOK;
255 }
256 }
257
[e11c527]258 fibril_mutex_unlock(&vbds_parts_lock);
[55f8c6e7]259 log_msg(LOG_DEFAULT, LVL_DEBUG, "No match.");
[c43db5f]260 return ENOENT;
261}
262
263static int vbds_part_by_svcid(service_id_t svcid, vbds_part_t **rpart)
[78d50bd]264{
[55f8c6e7]265 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_by_svcid(%zu)", svcid);
[3faa03d]266
[e11c527]267 fibril_mutex_lock(&vbds_parts_lock);
268
[78d50bd]269 list_foreach(vbds_parts, lparts, vbds_part_t, part) {
[55f8c6e7]270 log_msg(LOG_DEFAULT, LVL_DEBUG, "%zu == %zu ?", part->svc_id, svcid);
[c43db5f]271 if (part->svc_id == svcid) {
[55f8c6e7]272 log_msg(LOG_DEFAULT, LVL_DEBUG, "Found match.");
[e11c527]273 vbds_part_add_ref(part);
274 fibril_mutex_unlock(&vbds_parts_lock);
[78d50bd]275 *rpart = part;
276 return EOK;
277 }
278 }
279
[e11c527]280 fibril_mutex_unlock(&vbds_parts_lock);
[55f8c6e7]281 log_msg(LOG_DEFAULT, LVL_DEBUG, "No match.");
[78d50bd]282 return ENOENT;
283}
284
[99c23405]285/** Add partition to our inventory based on liblabel partition structure */
[6bc542b]286static int vbds_part_add(vbds_disk_t *disk, label_part_t *lpart,
287 vbds_part_t **rpart)
[28ed0d95]288{
289 vbds_part_t *part;
[c43db5f]290 service_id_t psid = 0;
[78d50bd]291 label_part_info_t lpinfo;
292 int rc;
[28ed0d95]293
[55f8c6e7]294 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_add(%s, %p)",
[78d50bd]295 disk->svc_name, lpart);
[28ed0d95]296
[b7a4d06]297 label_part_get_info(lpart, &lpinfo);
298
[28ed0d95]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
[e11c527]305 fibril_rwlock_initialize(&part->lock);
306
[28ed0d95]307 part->lpart = lpart;
308 part->disk = disk;
[c43db5f]309 part->pid = ++vbds_part_id;
310 part->svc_id = psid;
[78d50bd]311 part->block0 = lpinfo.block0;
312 part->nblocks = lpinfo.nblocks;
[e11c527]313 atomic_set(&part->refcnt, 1);
[78d50bd]314
315 bd_srvs_init(&part->bds);
316 part->bds.ops = &vbds_bd_ops;
317 part->bds.sarg = part;
318
[6439741]319 if (lpinfo.pkind != lpk_extended) {
320 rc = vbds_part_svc_register(part);
[e11c527]321 if (rc != EOK) {
322 free(part);
[6439741]323 return EIO;
[e11c527]324 }
[6439741]325 }
326
[28ed0d95]327 list_append(&part->ldisk, &disk->parts);
[e11c527]328 fibril_mutex_lock(&vbds_parts_lock);
[78d50bd]329 list_append(&part->lparts, &vbds_parts);
[e11c527]330 fibril_mutex_unlock(&vbds_parts_lock);
[28ed0d95]331
[55f8c6e7]332 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_add -> %p", part);
[3a43785]333
[6bc542b]334 if (rpart != NULL)
335 *rpart = part;
[28ed0d95]336 return EOK;
337}
338
[99c23405]339/** Remove partition from our inventory leaving only the underlying liblabel
340 * partition structure.
[e11c527]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
[99c23405]345 */
[e11c527]346static int vbds_part_remove(vbds_part_t *part, vbds_rem_flag_t flag,
347 label_part_t **rlpart)
[99c23405]348{
349 label_part_t *lpart;
350 int rc;
351
[55f8c6e7]352 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_remove(%p)", part);
[99c23405]353
[e11c527]354 fibril_rwlock_write_lock(&part->lock);
[99c23405]355 lpart = part->lpart;
356
[e11c527]357 if ((flag & vrf_force) == 0 && part->open_cnt > 0) {
358 fibril_rwlock_write_unlock(&part->lock);
[55f8c6e7]359 log_msg(LOG_DEFAULT, LVL_DEBUG, "part->open_cnt = %d",
[3a43785]360 part->open_cnt);
[99c23405]361 return EBUSY;
[3a43785]362 }
[99c23405]363
[c43db5f]364 if (part->svc_id != 0) {
[6439741]365 rc = vbds_part_svc_unregister(part);
[e11c527]366 if (rc != EOK) {
367 fibril_rwlock_write_unlock(&part->lock);
[c43db5f]368 return EIO;
[e11c527]369 }
[c43db5f]370 }
[99c23405]371
372 list_remove(&part->ldisk);
[e11c527]373 fibril_mutex_lock(&vbds_parts_lock);
[99c23405]374 list_remove(&part->lparts);
[e11c527]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);
[99c23405]380
381 if (rlpart != NULL)
382 *rlpart = lpart;
383 return EOK;
384}
385
[3a43785]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. */
[e11c527]410static int vbds_disk_parts_remove(vbds_disk_t *disk, vbds_rem_flag_t flag)
[3a43785]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);
[e11c527]419 rc = vbds_part_remove(part, flag, NULL);
[3a43785]420 if (rc != EOK)
421 return rc;
422
423 link = list_first(&disk->parts);
424 }
425
426 return EOK;
427}
428
[372df8f]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
[28ed0d95]448int vbds_disk_add(service_id_t sid)
449{
[3faa03d]450 label_t *label = NULL;
[78d50bd]451 vbds_disk_t *disk = NULL;
452 bool block_inited = false;
453 size_t block_size;
[53e3950]454 aoff64_t nblocks;
[28ed0d95]455 int rc;
456
[55f8c6e7]457 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_add(%zu)", sid);
[28ed0d95]458
459 /* Check for duplicates */
460 rc = vbds_disk_by_svcid(sid, &disk);
461 if (rc == EOK)
[ff381a7]462 return EEXIST;
[28ed0d95]463
464 disk = calloc(1, sizeof(vbds_disk_t));
465 if (disk == NULL)
466 return ENOMEM;
467
[78d50bd]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
[55f8c6e7]475 log_msg(LOG_DEFAULT, LVL_DEBUG, "block_init(%zu)", sid);
[ff381a7]476 rc = block_init(sid, 2048);
[78d50bd]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
[53e3950]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
[78d50bd]500 block_inited = true;
501
[28ed0d95]502 rc = label_open(sid, &label);
[78d50bd]503 if (rc != EOK) {
[55f8c6e7]504 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
[3faa03d]505 disk->svc_name);
[78d50bd]506 rc = EIO;
[28ed0d95]507 goto error;
[78d50bd]508 }
[28ed0d95]509
510 disk->svc_id = sid;
511 disk->label = label;
[78d50bd]512 disk->block_size = block_size;
[53e3950]513 disk->nblocks = nblocks;
[3a9cf35]514 disk->present = true;
[78d50bd]515
[28ed0d95]516 list_initialize(&disk->parts);
517 list_append(&disk->ldisks, &vbds_disks);
518
[3faa03d]519 log_msg(LOG_DEFAULT, LVL_NOTE, "Recognized disk label. Adding partitions.");
520
[3a43785]521 (void) vbds_disk_parts_add(disk, label);
[28ed0d95]522 return EOK;
523error:
[78d50bd]524 label_close(label);
[603c1d1f]525 if (block_inited) {
[55f8c6e7]526 log_msg(LOG_DEFAULT, LVL_DEBUG, "block_fini(%zu)", sid);
[78d50bd]527 block_fini(sid);
[603c1d1f]528 }
[78d50bd]529 if (disk != NULL)
530 free(disk->svc_name);
[28ed0d95]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
[55f8c6e7]540 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_remove(%zu)", sid);
[28ed0d95]541
542 rc = vbds_disk_by_svcid(sid, &disk);
543 if (rc != EOK)
544 return rc;
545
[e11c527]546 rc = vbds_disk_parts_remove(disk, vrf_force);
[3a43785]547 if (rc != EOK) {
548 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
549 return rc;
550 }
551
[28ed0d95]552 list_remove(&disk->ldisks);
553 label_close(disk->label);
[55f8c6e7]554 log_msg(LOG_DEFAULT, LVL_DEBUG, "block_fini(%zu)", sid);
[603c1d1f]555 block_fini(sid);
[28ed0d95]556 free(disk);
557 return EOK;
558}
559
[372df8f]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
[b7a4d06]589int vbds_disk_info(service_id_t sid, vbd_disk_info_t *info)
[28ed0d95]590{
[1626cd4]591 vbds_disk_t *disk;
592 label_info_t linfo;
593 int rc;
594
[55f8c6e7]595 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_info(%zu)", sid);
[1626cd4]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);
[6a0db524]602 if (rc != EOK)
603 return rc;
[1626cd4]604
605 info->ltype = linfo.ltype;
[b7a4d06]606 info->flags = linfo.flags;
[1626cd4]607 info->ablock0 = linfo.ablock0;
608 info->anblocks = linfo.anblocks;
609 info->block_size = disk->block_size;
[53e3950]610 info->nblocks = disk->nblocks;
[55f8c6e7]611 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_disk_info - block_size=%zu",
[c02d098]612 info->block_size);
[1626cd4]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)
[c43db5f]639 id_buf[pos] = part->pid;
[1626cd4]640 pos++;
641 }
642
[28ed0d95]643 return EOK;
644}
645
646int vbds_label_create(service_id_t sid, label_type_t ltype)
647{
648 label_t *label;
[6a0db524]649 label_info_t linfo;
[28ed0d95]650 vbds_disk_t *disk;
[f63a0073]651 int rc, rc2;
[28ed0d95]652
[55f8c6e7]653 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu)", sid);
[28ed0d95]654
[3a43785]655 /* Find disk */
[28ed0d95]656 rc = vbds_disk_by_svcid(sid, &disk);
[3a43785]657 if (rc != EOK)
658 return rc;
[28ed0d95]659
[55f8c6e7]660 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - label_close", sid);
[603c1d1f]661
[6a0db524]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
[3a43785]672 /* Close dummy label first */
[e11c527]673 rc = vbds_disk_parts_remove(disk, vrf_none);
[603c1d1f]674 if (rc != EOK) {
[3a43785]675 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
676 return rc;
[603c1d1f]677 }
678
[3a43785]679 label_close(disk->label);
680 disk->label = NULL;
[603c1d1f]681
[55f8c6e7]682 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - label_create", sid);
[603c1d1f]683
[28ed0d95]684 rc = label_create(sid, ltype, &label);
685 if (rc != EOK)
686 goto error;
687
[3a43785]688 (void) vbds_disk_parts_add(disk, label);
[28ed0d95]689 disk->label = label;
[603c1d1f]690
[55f8c6e7]691 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - success", sid);
[28ed0d95]692 return EOK;
693error:
[55f8c6e7]694 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_create(%zu) - failure", sid);
[3a43785]695 if (disk->label == NULL) {
[f63a0073]696 rc2 = label_open(sid, &label);
697 if (rc2 != EOK) {
[55f8c6e7]698 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
[3a43785]699 disk->svc_name);
[f63a0073]700 return rc2;
[3a43785]701 }
[f63a0073]702
703 disk->label = label;
704 (void) vbds_disk_parts_add(disk, label);
[603c1d1f]705 }
[3a43785]706
[28ed0d95]707 return rc;
708}
709
710int vbds_label_delete(service_id_t sid)
711{
712 vbds_disk_t *disk;
[3a43785]713 label_t *label;
[28ed0d95]714 int rc;
715
[55f8c6e7]716 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_label_delete(%zu)", sid);
[28ed0d95]717
718 rc = vbds_disk_by_svcid(sid, &disk);
719 if (rc != EOK)
720 return rc;
721
[e11c527]722 rc = vbds_disk_parts_remove(disk, vrf_none);
[3a43785]723 if (rc != EOK) {
724 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
725 return rc;
726 }
727
[28ed0d95]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
[3a43785]734 disk->label = NULL;
735
736 rc = label_open(disk->svc_id, &label);
737 if (rc != EOK) {
[55f8c6e7]738 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to open label in disk %s.",
[3a43785]739 disk->svc_name);
740 return EIO;
741 }
742
743 (void) vbds_disk_parts_add(disk, label);
744 disk->label = label;
[28ed0d95]745 return EOK;
746}
747
[6a0d4ce2]748int vbds_part_get_info(vbds_part_id_t partid, vbd_part_info_t *pinfo)
[28ed0d95]749{
[78d50bd]750 vbds_part_t *part;
[1626cd4]751 label_part_info_t lpinfo;
[78d50bd]752 int rc;
753
[c43db5f]754 rc = vbds_part_by_pid(partid, &part);
[78d50bd]755 if (rc != EOK)
756 return rc;
757
[e11c527]758 fibril_rwlock_read_lock(&part->lock);
759 if (part->lpart == NULL) {
760 fibril_rwlock_read_unlock(&part->lock);
761 return ENOENT;
762 }
763
[1626cd4]764 label_part_get_info(part->lpart, &lpinfo);
765
766 pinfo->index = lpinfo.index;
[b7a4d06]767 pinfo->pkind = lpinfo.pkind;
[1626cd4]768 pinfo->block0 = lpinfo.block0;
769 pinfo->nblocks = lpinfo.nblocks;
[4b6635a7]770 pinfo->svc_id = part->svc_id;
[e11c527]771 vbds_part_del_ref(part);
772 fibril_rwlock_read_unlock(&part->lock);
773
[28ed0d95]774 return EOK;
775}
776
[6bc542b]777int vbds_part_create(service_id_t sid, vbd_part_spec_t *pspec,
778 vbds_part_id_t *rpart)
[28ed0d95]779{
[78d50bd]780 vbds_disk_t *disk;
781 vbds_part_t *part;
[6bc542b]782 label_part_spec_t lpspec;
[78d50bd]783 label_part_t *lpart;
784 int rc;
785
[55f8c6e7]786 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_create(%zu)", sid);
[44fe800]787
[78d50bd]788 rc = vbds_disk_by_svcid(sid, &disk);
789 if (rc != EOK) {
[55f8c6e7]790 log_msg(LOG_DEFAULT, LVL_ERROR, "Disk %zu not found",
[78d50bd]791 sid);
792 goto error;
793 }
794
[55f8c6e7]795 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_crate(%zu): "
[b598460a]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
[6bc542b]801 label_pspec_init(&lpspec);
802 lpspec.index = pspec->index;
803 lpspec.block0 = pspec->block0;
804 lpspec.nblocks = pspec->nblocks;
[c02d098]805 lpspec.hdr_blocks = pspec->hdr_blocks;
[b7a4d06]806 lpspec.pkind = pspec->pkind;
[6bc542b]807 lpspec.ptype = pspec->ptype;
808
809 rc = label_part_create(disk->label, &lpspec, &lpart);
[78d50bd]810 if (rc != EOK) {
811 log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating partition.");
812 goto error;
813 }
814
[6439741]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
[6bc542b]821 rc = vbds_part_add(disk, lpart, &part);
[78d50bd]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
[6bc542b]833 if (rpart != NULL)
[c43db5f]834 *rpart = part->pid;
[28ed0d95]835 return EOK;
[78d50bd]836error:
837 return rc;
[28ed0d95]838}
839
[78d50bd]840int vbds_part_delete(vbds_part_id_t partid)
[28ed0d95]841{
[78d50bd]842 vbds_part_t *part;
[99c23405]843 vbds_disk_t *disk;
844 label_part_t *lpart;
[78d50bd]845 int rc;
846
[c43db5f]847 rc = vbds_part_by_pid(partid, &part);
[78d50bd]848 if (rc != EOK)
849 return rc;
850
[99c23405]851 disk = part->disk;
852
[e11c527]853 rc = vbds_part_remove(part, vrf_none, &lpart);
[78d50bd]854 if (rc != EOK)
855 return rc;
856
[99c23405]857 rc = label_part_destroy(lpart);
[e11c527]858 vbds_part_del_ref(part);
[99c23405]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
[6439741]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
[78d50bd]876 return EOK;
877}
878
[f57ccb5]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) {
[55f8c6e7]887 log_msg(LOG_DEFAULT, LVL_DEBUG, "Disk %zu not found",
[f57ccb5]888 sid);
889 goto error;
890 }
891
892 rc = label_suggest_ptype(disk->label, pcnt, ptype);
893 if (rc != EOK) {
[55f8c6e7]894 log_msg(LOG_DEFAULT, LVL_DEBUG, "label_suggest_ptype() failed");
[f57ccb5]895 goto error;
896 }
897
898 return EOK;
899error:
900 return rc;
901}
902
[78d50bd]903static int vbds_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
904{
905 vbds_part_t *part = bd_srv_part(bd);
906
[55f8c6e7]907 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_open()");
[e11c527]908 fibril_rwlock_write_lock(&part->lock);
[78d50bd]909 part->open_cnt++;
[e11c527]910 fibril_rwlock_write_unlock(&part->lock);
[78d50bd]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
[55f8c6e7]918 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_close()");
[e11c527]919
920 /* Grabbing writer lock also forces all I/O to complete */
921
922 fibril_rwlock_write_lock(&part->lock);
[78d50bd]923 part->open_cnt--;
[e11c527]924 fibril_rwlock_write_unlock(&part->lock);
[78d50bd]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;
[e11c527]933 int rc;
[78d50bd]934
[55f8c6e7]935 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_read_blocks()");
[e11c527]936 fibril_rwlock_read_lock(&part->lock);
[78d50bd]937
[e11c527]938 if (cnt * part->disk->block_size < size) {
939 fibril_rwlock_read_unlock(&part->lock);
[78d50bd]940 return EINVAL;
[e11c527]941 }
[78d50bd]942
[e11c527]943 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK) {
944 fibril_rwlock_read_unlock(&part->lock);
[78d50bd]945 return ELIMIT;
[e11c527]946 }
947
948 rc = block_read_direct(part->disk->svc_id, gba, cnt, buf);
949 fibril_rwlock_read_unlock(&part->lock);
[78d50bd]950
[e11c527]951 return rc;
[78d50bd]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;
[e11c527]958 int rc;
[78d50bd]959
[55f8c6e7]960 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_sync_cache()");
[e11c527]961 fibril_rwlock_read_lock(&part->lock);
[78d50bd]962
963 /* XXX Allow full-disk sync? */
964 if (ba != 0 || cnt != 0) {
[e11c527]965 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK) {
966 fibril_rwlock_read_unlock(&part->lock);
[78d50bd]967 return ELIMIT;
[e11c527]968 }
[78d50bd]969 } else {
970 gba = 0;
971 }
972
[e11c527]973 rc = block_sync_cache(part->disk->svc_id, gba, cnt);
974 fibril_rwlock_read_unlock(&part->lock);
975 return rc;
[78d50bd]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;
[e11c527]983 int rc;
[78d50bd]984
[55f8c6e7]985 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_write_blocks()");
[e11c527]986 fibril_rwlock_read_lock(&part->lock);
[78d50bd]987
[e11c527]988 if (cnt * part->disk->block_size < size) {
989 fibril_rwlock_read_unlock(&part->lock);
[78d50bd]990 return EINVAL;
[e11c527]991 }
[78d50bd]992
[e11c527]993 if (vbds_bsa_translate(part, ba, cnt, &gba) != EOK) {
994 fibril_rwlock_read_unlock(&part->lock);
[78d50bd]995 return ELIMIT;
[e11c527]996 }
[78d50bd]997
[e11c527]998 rc = block_write_direct(part->disk->svc_id, gba, cnt, buf);
999 fibril_rwlock_read_unlock(&part->lock);
1000 return rc;
[78d50bd]1001}
1002
1003static int vbds_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
1004{
[3faa03d]1005 vbds_part_t *part = bd_srv_part(bd);
1006
[55f8c6e7]1007 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_get_block_size()");
[e11c527]1008
1009 fibril_rwlock_read_lock(&part->lock);
[3faa03d]1010 *rsize = part->disk->block_size;
[e11c527]1011 fibril_rwlock_read_unlock(&part->lock);
1012
[78d50bd]1013 return EOK;
1014}
1015
1016static int vbds_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
1017{
[3faa03d]1018 vbds_part_t *part = bd_srv_part(bd);
1019
[55f8c6e7]1020 log_msg(LOG_DEFAULT, LVL_DEBUG2, "vbds_bd_get_num_blocks()");
[e11c527]1021
1022 fibril_rwlock_read_lock(&part->lock);
[3faa03d]1023 *rnb = part->nblocks;
[e11c527]1024 fibril_rwlock_read_unlock(&part->lock);
1025
[78d50bd]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;
[c43db5f]1033 service_id_t svcid;
[78d50bd]1034
[55f8c6e7]1035 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn()");
[3faa03d]1036
[ff381a7]1037 svcid = IPC_GET_ARG2(*icall);
[78d50bd]1038
[55f8c6e7]1039 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn() - svcid=%zu", svcid);
[3faa03d]1040
[c43db5f]1041 rc = vbds_part_by_svcid(svcid, &part);
[78d50bd]1042 if (rc != EOK) {
[55f8c6e7]1043 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_bd_conn() - partition "
[3faa03d]1044 "not found.");
[78d50bd]1045 async_answer_0(iid, EINVAL);
1046 return;
1047 }
1048
[55f8c6e7]1049 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_bd_conn() - call bd_conn");
[78d50bd]1050 bd_conn(iid, icall, &part->bds);
[e11c527]1051 vbds_part_del_ref(part);
[78d50bd]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;
[28ed0d95]1062 return EOK;
1063}
1064
[6439741]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
[55f8c6e7]1081 log_msg(LOG_DEFAULT, LVL_DEBUG, "loc_service_register('%s')",
[edebb4a1]1082 name);
[6439741]1083 rc = loc_service_register(name, &psid);
1084 if (rc != EOK) {
1085 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering "
[372df8f]1086 "service %s (%d).", name, rc);
[6439741]1087 free(name);
1088 free(part);
1089 return EIO;
1090 }
1091
[372df8f]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
[6439741]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
[55f8c6e7]1118 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_svc_unregister("
[3a43785]1119 "disk->svc_name='%s', id=%zu)", part->disk->svc_name, part->svc_id);
1120
[6439741]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
[55f8c6e7]1136 log_msg(LOG_DEFAULT, LVL_DEBUG, "vbds_part_indices_update()");
[6439741]1137
[e11c527]1138 fibril_mutex_lock(&vbds_parts_lock);
1139
[6439741]1140 /* First unregister services for partitions whose index has changed */
1141 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
[e11c527]1142 fibril_rwlock_write_lock(&part->lock);
[6439741]1143 if (part->svc_id != 0 && part->lpart->index != part->reg_idx) {
1144 rc = vbds_part_svc_unregister(part);
1145 if (rc != EOK) {
[e11c527]1146 fibril_rwlock_write_unlock(&part->lock);
1147 fibril_mutex_unlock(&vbds_parts_lock);
[55f8c6e7]1148 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
[6439741]1149 "un-registering partition.");
1150 return EIO;
1151 }
1152 }
[e11c527]1153
1154 fibril_rwlock_write_unlock(&part->lock);
[6439741]1155 }
1156
1157 /* Now re-register those services under the new indices */
1158 list_foreach(disk->parts, ldisk, vbds_part_t, part) {
[e11c527]1159 fibril_rwlock_write_lock(&part->lock);
[6439741]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) {
[e11c527]1164 fibril_rwlock_write_unlock(&part->lock);
1165 fibril_mutex_unlock(&vbds_parts_lock);
[55f8c6e7]1166 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
[6439741]1167 "re-registering partition.");
1168 return EIO;
1169 }
1170 }
[e11c527]1171
1172 fibril_rwlock_write_unlock(&part->lock);
[6439741]1173 }
1174
[e11c527]1175 fibril_mutex_unlock(&vbds_parts_lock);
1176
[6439741]1177 return EOK;
1178}
1179
[28ed0d95]1180/** @}
1181 */
Note: See TracBrowser for help on using the repository browser.