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

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

Merge mainline changes.

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