Changes in uspace/lib/libblock/libblock.c [0da4e41:d68e4d5] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/libblock/libblock.c
r0da4e41 rd68e4d5 50 50 #include <adt/list.h> 51 51 #include <adt/hash_table.h> 52 #include <macros.h>53 52 #include <mem.h> 54 53 … … 63 62 typedef struct { 64 63 fibril_mutex_t lock; 65 size_t lblock_size; /**< Logical block size. */64 size_t block_size; /**< Block size. */ 66 65 unsigned block_count; /**< Total number of blocks. */ 67 66 unsigned blocks_cached; /**< Number of cached blocks. */ … … 75 74 dev_handle_t dev_handle; 76 75 int dev_phone; 77 fibril_mutex_t com m_area_lock;78 void *com m_area;79 size_t com m_size;76 fibril_mutex_t com_area_lock; 77 void *com_area; 78 size_t com_size; 80 79 void *bb_buf; 81 bn_t bb_addr;82 size_t pblock_size; /**< Physical block size. */80 off_t bb_off; 81 size_t bb_size; 83 82 cache_t *cache; 84 83 } devcon_t; 85 84 86 static int read_blocks(devcon_t *devcon, bn_t ba, size_t cnt); 87 static int write_blocks(devcon_t *devcon, bn_t ba, size_t cnt); 88 static int get_block_size(int dev_phone, size_t *bsize); 85 static int read_block(devcon_t *devcon, bn_t boff, size_t block_size); 86 static int write_block(devcon_t *devcon, bn_t boff, size_t block_size); 89 87 90 88 static devcon_t *devcon_search(dev_handle_t dev_handle) … … 104 102 } 105 103 106 static int devcon_add(dev_handle_t dev_handle, int dev_phone, size_t bsize,107 void *comm_area, size_t comm_size)104 static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area, 105 size_t com_size) 108 106 { 109 107 link_t *cur; 110 108 devcon_t *devcon; 111 112 if (comm_size < bsize)113 return EINVAL;114 109 115 110 devcon = malloc(sizeof(devcon_t)); … … 120 115 devcon->dev_handle = dev_handle; 121 116 devcon->dev_phone = dev_phone; 122 fibril_mutex_initialize(&devcon->com m_area_lock);123 devcon->com m_area = comm_area;124 devcon->com m_size = comm_size;117 fibril_mutex_initialize(&devcon->com_area_lock); 118 devcon->com_area = com_area; 119 devcon->com_size = com_size; 125 120 devcon->bb_buf = NULL; 126 devcon->bb_ addr= 0;127 devcon-> pblock_size = bsize;121 devcon->bb_off = 0; 122 devcon->bb_size = 0; 128 123 devcon->cache = NULL; 129 124 … … 149 144 } 150 145 151 int block_init(dev_handle_t dev_handle, size_t com m_size)146 int block_init(dev_handle_t dev_handle, size_t com_size) 152 147 { 153 148 int rc; 154 149 int dev_phone; 155 void *comm_area; 156 size_t bsize; 157 158 comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE, 150 void *com_area; 151 152 com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE, 159 153 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 160 if (!com m_area) {154 if (!com_area) { 161 155 return ENOMEM; 162 156 } … … 164 158 dev_phone = devmap_device_connect(dev_handle, IPC_FLAG_BLOCKING); 165 159 if (dev_phone < 0) { 166 munmap(com m_area, comm_size);160 munmap(com_area, com_size); 167 161 return dev_phone; 168 162 } 169 163 170 rc = async_share_out_start(dev_phone, comm_area,164 rc = ipc_share_out_start(dev_phone, com_area, 171 165 AS_AREA_READ | AS_AREA_WRITE); 172 166 if (rc != EOK) { 173 munmap(com m_area, comm_size);167 munmap(com_area, com_size); 174 168 ipc_hangup(dev_phone); 175 169 return rc; 176 170 } 177 178 if (get_block_size(dev_phone, &bsize) != EOK) { 179 munmap(comm_area, comm_size); 180 ipc_hangup(dev_phone); 181 return rc; 182 } 183 184 rc = devcon_add(dev_handle, dev_phone, bsize, comm_area, comm_size); 171 172 rc = devcon_add(dev_handle, dev_phone, com_area, com_size); 185 173 if (rc != EOK) { 186 munmap(com m_area, comm_size);174 munmap(com_area, com_size); 187 175 ipc_hangup(dev_phone); 188 176 return rc; … … 207 195 } 208 196 209 munmap(devcon->com m_area, devcon->comm_size);197 munmap(devcon->com_area, devcon->com_size); 210 198 ipc_hangup(devcon->dev_phone); 211 199 … … 213 201 } 214 202 215 int block_bb_read(dev_handle_t dev_handle, bn_t ba)203 int block_bb_read(dev_handle_t dev_handle, off_t off, size_t size) 216 204 { 217 205 void *bb_buf; … … 223 211 if (devcon->bb_buf) 224 212 return EEXIST; 225 bb_buf = malloc( devcon->pblock_size);213 bb_buf = malloc(size); 226 214 if (!bb_buf) 227 215 return ENOMEM; 228 229 fibril_mutex_lock(&devcon->com m_area_lock);230 rc = read_block s(devcon, 0, 1);216 217 fibril_mutex_lock(&devcon->com_area_lock); 218 rc = read_block(devcon, 0, size); 231 219 if (rc != EOK) { 232 fibril_mutex_unlock(&devcon->com m_area_lock);220 fibril_mutex_unlock(&devcon->com_area_lock); 233 221 free(bb_buf); 234 222 return rc; 235 223 } 236 memcpy(bb_buf, devcon->com m_area, devcon->pblock_size);237 fibril_mutex_unlock(&devcon->com m_area_lock);224 memcpy(bb_buf, devcon->com_area, size); 225 fibril_mutex_unlock(&devcon->com_area_lock); 238 226 239 227 devcon->bb_buf = bb_buf; 240 devcon->bb_addr = ba; 228 devcon->bb_off = off; 229 devcon->bb_size = size; 241 230 242 231 return EOK; … … 286 275 fibril_mutex_initialize(&cache->lock); 287 276 list_initialize(&cache->free_head); 288 cache-> lblock_size = size;277 cache->block_size = size; 289 278 cache->block_count = blocks; 290 279 cache->blocks_cached = 0; 291 280 cache->mode = mode; 292 293 /* No block size translation a.t.m. */294 assert(cache->lblock_size == devcon->pblock_size);295 281 296 282 if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1, … … 320 306 b->refcnt = 1; 321 307 b->dirty = false; 322 b->toxic = false;323 308 fibril_rwlock_initialize(&b->contents_lock); 324 309 link_initialize(&b->free_link); … … 328 313 /** Instantiate a block in memory and get a reference to it. 329 314 * 330 * @param block Pointer to where the function will store the331 * block pointer on success.332 315 * @param dev_handle Device handle of the block device. 333 316 * @param boff Block offset. … … 336 319 * device. 337 320 * 338 * @return EOK on success or a negative error code.339 */ 340 int block_get(block_t **block,dev_handle_t dev_handle, bn_t boff, int flags)321 * @return Block structure. 322 */ 323 block_t *block_get(dev_handle_t dev_handle, bn_t boff, int flags) 341 324 { 342 325 devcon_t *devcon; … … 345 328 link_t *l; 346 329 unsigned long key = boff; 347 int rc;330 bn_t oboff; 348 331 349 332 devcon = devcon_search(dev_handle); … … 353 336 354 337 cache = devcon->cache; 355 356 retry:357 rc = EOK;358 b = NULL;359 360 338 fibril_mutex_lock(&cache->lock); 361 339 l = hash_table_find(&cache->block_hash, &key); … … 368 346 if (b->refcnt++ == 0) 369 347 list_remove(&b->free_link); 370 if (b->toxic)371 rc = EIO;372 348 fibril_mutex_unlock(&b->lock); 373 349 fibril_mutex_unlock(&cache->lock); … … 376 352 * The block was not found in the cache. 377 353 */ 354 int rc; 355 bool sync = false; 356 378 357 if (cache_can_grow(cache)) { 379 358 /* … … 385 364 if (!b) 386 365 goto recycle; 387 b->data = malloc(cache-> lblock_size);366 b->data = malloc(cache->block_size); 388 367 if (!b->data) { 389 368 free(b); … … 397 376 unsigned long temp_key; 398 377 recycle: 399 if (list_empty(&cache->free_head)) { 400 fibril_mutex_unlock(&cache->lock); 401 rc = ENOMEM; 402 goto out; 403 } 378 assert(!list_empty(&cache->free_head)); 404 379 l = cache->free_head.next; 380 list_remove(l); 405 381 b = list_get_instance(l, block_t, free_link); 406 407 fibril_mutex_lock(&b->lock); 408 if (b->dirty) { 409 /* 410 * The block needs to be written back to the 411 * device before it changes identity. Do this 412 * while not holding the cache lock so that 413 * concurrency is not impeded. Also move the 414 * block to the end of the free list so that we 415 * do not slow down other instances of 416 * block_get() draining the free list. 417 */ 418 list_remove(&b->free_link); 419 list_append(&b->free_link, &cache->free_head); 420 fibril_mutex_unlock(&cache->lock); 421 fibril_mutex_lock(&devcon->comm_area_lock); 422 memcpy(devcon->comm_area, b->data, b->size); 423 rc = write_blocks(devcon, b->boff, 1); 424 fibril_mutex_unlock(&devcon->comm_area_lock); 425 if (rc != EOK) { 426 /* 427 * We did not manage to write the block 428 * to the device. Keep it around for 429 * another try. Hopefully, we will grab 430 * another block next time. 431 */ 432 fibril_mutex_unlock(&b->lock); 433 goto retry; 434 } 435 b->dirty = false; 436 if (!fibril_mutex_trylock(&cache->lock)) { 437 /* 438 * Somebody is probably racing with us. 439 * Unlock the block and retry. 440 */ 441 fibril_mutex_unlock(&b->lock); 442 goto retry; 443 } 444 445 } 446 fibril_mutex_unlock(&b->lock); 447 448 /* 449 * Unlink the block from the free list and the hash 450 * table. 451 */ 452 list_remove(&b->free_link); 382 sync = b->dirty; 383 oboff = b->boff; 453 384 temp_key = b->boff; 454 385 hash_table_remove(&cache->block_hash, &temp_key, 1); … … 457 388 block_initialize(b); 458 389 b->dev_handle = dev_handle; 459 b->size = cache-> lblock_size;390 b->size = cache->block_size; 460 391 b->boff = boff; 461 392 hash_table_insert(&cache->block_hash, &key, &b->hash_link); … … 463 394 /* 464 395 * Lock the block before releasing the cache lock. Thus we don't 465 * kill concur rent operations on the cache while doing I/O on466 * theblock.396 * kill concurent operations on the cache while doing I/O on the 397 * block. 467 398 */ 468 399 fibril_mutex_lock(&b->lock); 469 400 fibril_mutex_unlock(&cache->lock); 470 401 402 if (sync) { 403 /* 404 * The block is dirty and needs to be written back to 405 * the device before we can read in the new contents. 406 */ 407 fibril_mutex_lock(&devcon->com_area_lock); 408 memcpy(devcon->com_area, b->data, b->size); 409 rc = write_block(devcon, oboff, cache->block_size); 410 assert(rc == EOK); 411 fibril_mutex_unlock(&devcon->com_area_lock); 412 } 471 413 if (!(flags & BLOCK_FLAGS_NOREAD)) { 472 414 /* … … 474 416 * the new contents from the device. 475 417 */ 476 fibril_mutex_lock(&devcon->comm_area_lock); 477 rc = read_blocks(devcon, b->boff, 1); 478 memcpy(b->data, devcon->comm_area, cache->lblock_size); 479 fibril_mutex_unlock(&devcon->comm_area_lock); 480 if (rc != EOK) 481 b->toxic = true; 482 } else 483 rc = EOK; 418 fibril_mutex_lock(&devcon->com_area_lock); 419 rc = read_block(devcon, b->boff, cache->block_size); 420 assert(rc == EOK); 421 memcpy(b->data, devcon->com_area, cache->block_size); 422 fibril_mutex_unlock(&devcon->com_area_lock); 423 } 484 424 485 425 fibril_mutex_unlock(&b->lock); 486 426 } 487 out: 488 if ((rc != EOK) && b) { 489 assert(b->toxic); 490 (void) block_put(b); 491 b = NULL; 492 } 493 *block = b; 494 return rc; 427 return b; 495 428 } 496 429 … … 500 433 * 501 434 * @param block Block of which a reference is to be released. 502 * 503 * @return EOK on success or a negative error code. 504 */ 505 int block_put(block_t *block) 435 */ 436 void block_put(block_t *block) 506 437 { 507 438 devcon_t *devcon = devcon_search(block->dev_handle); 508 439 cache_t *cache; 509 unsigned blocks_cached; 510 enum cache_mode mode; 511 int rc = EOK; 440 int rc; 512 441 513 442 assert(devcon); … … 515 444 516 445 cache = devcon->cache; 517 518 retry:519 fibril_mutex_lock(&cache->lock);520 blocks_cached = cache->blocks_cached;521 mode = cache->mode;522 fibril_mutex_unlock(&cache->lock);523 524 /*525 * Determine whether to sync the block. Syncing the block is best done526 * when not holding the cache lock as it does not impede concurrency.527 * Since the situation may have changed when we unlocked the cache, the528 * blocks_cached and mode variables are mere hints. We will recheck the529 * conditions later when the cache lock is held again.530 */531 fibril_mutex_lock(&block->lock);532 if (block->toxic)533 block->dirty = false; /* will not write back toxic block */534 if (block->dirty && (block->refcnt == 1) &&535 (blocks_cached > CACHE_HI_WATERMARK || mode != CACHE_MODE_WB)) {536 fibril_mutex_lock(&devcon->comm_area_lock);537 memcpy(devcon->comm_area, block->data, block->size);538 rc = write_blocks(devcon, block->boff, 1);539 fibril_mutex_unlock(&devcon->comm_area_lock);540 block->dirty = false;541 }542 fibril_mutex_unlock(&block->lock);543 544 446 fibril_mutex_lock(&cache->lock); 545 447 fibril_mutex_lock(&block->lock); … … 547 449 /* 548 450 * Last reference to the block was dropped. Either free the 549 * block or put it on the free list. In case of an I/O error, 550 * free the block. 451 * block or put it on the free list. 551 452 */ 552 if ((cache->blocks_cached > CACHE_HI_WATERMARK) || 553 (rc != EOK)) { 453 if (cache->blocks_cached > CACHE_HI_WATERMARK) { 554 454 /* 555 * Currently there are too many cached blocks or there 556 * was an I/O error when writing the block back to the 557 * device. 455 * Currently there are too many cached blocks. 558 456 */ 559 457 if (block->dirty) { 560 /* 561 * We cannot sync the block while holding the 562 * cache lock. Release everything and retry. 563 */ 564 block->refcnt++; 565 fibril_mutex_unlock(&block->lock); 566 fibril_mutex_unlock(&cache->lock); 567 goto retry; 458 fibril_mutex_lock(&devcon->com_area_lock); 459 memcpy(devcon->com_area, block->data, 460 block->size); 461 rc = write_block(devcon, block->boff, 462 block->size); 463 assert(rc == EOK); 464 fibril_mutex_unlock(&devcon->com_area_lock); 568 465 } 569 466 /* … … 576 473 cache->blocks_cached--; 577 474 fibril_mutex_unlock(&cache->lock); 578 return rc;475 return; 579 476 } 580 477 /* 581 478 * Put the block on the free list. 582 479 */ 480 list_append(&block->free_link, &cache->free_head); 583 481 if (cache->mode != CACHE_MODE_WB && block->dirty) { 584 /* 585 * We cannot sync the block while holding the cache 586 * lock. Release everything and retry. 587 */ 588 block->refcnt++; 589 fibril_mutex_unlock(&block->lock); 590 fibril_mutex_unlock(&cache->lock); 591 goto retry; 592 } 593 list_append(&block->free_link, &cache->free_head); 482 fibril_mutex_lock(&devcon->com_area_lock); 483 memcpy(devcon->com_area, block->data, block->size); 484 rc = write_block(devcon, block->boff, block->size); 485 assert(rc == EOK); 486 fibril_mutex_unlock(&devcon->com_area_lock); 487 488 block->dirty = false; 489 } 594 490 } 595 491 fibril_mutex_unlock(&block->lock); 596 492 fibril_mutex_unlock(&cache->lock); 597 598 return rc;599 493 } 600 494 … … 614 508 */ 615 509 int block_seqread(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen, 616 off_t *pos, void *dst, size_t size )510 off_t *pos, void *dst, size_t size, size_t block_size) 617 511 { 618 512 off_t offset = 0; 619 513 size_t left = size; 620 size_t block_size; 621 devcon_t *devcon; 622 623 devcon = devcon_search(dev_handle); 514 devcon_t *devcon = devcon_search(dev_handle); 624 515 assert(devcon); 625 block_size = devcon->pblock_size; 626 627 fibril_mutex_lock(&devcon->comm_area_lock); 516 517 fibril_mutex_lock(&devcon->com_area_lock); 628 518 while (left > 0) { 629 519 size_t rd; … … 639 529 * destination buffer. 640 530 */ 641 memcpy(dst + offset, devcon->com m_area + *bufpos, rd);531 memcpy(dst + offset, devcon->com_area + *bufpos, rd); 642 532 offset += rd; 643 533 *bufpos += rd; … … 650 540 int rc; 651 541 652 rc = read_block s(devcon, *pos / block_size, 1);542 rc = read_block(devcon, *pos / block_size, block_size); 653 543 if (rc != EOK) { 654 fibril_mutex_unlock(&devcon->com m_area_lock);544 fibril_mutex_unlock(&devcon->com_area_lock); 655 545 return rc; 656 546 } … … 660 550 } 661 551 } 662 fibril_mutex_unlock(&devcon->com m_area_lock);552 fibril_mutex_unlock(&devcon->com_area_lock); 663 553 664 554 return EOK; 665 555 } 666 556 667 /** Read block s directly from device (bypass cache).668 * 669 * @param dev _handle Device handle of the block device.670 * @param b a Address of first block.671 * @param cnt Number of blocks.557 /** Read block from block device. 558 * 559 * @param devcon Device connection. 560 * @param boff Block index. 561 * @param block_size Block size. 672 562 * @param src Buffer for storing the data. 673 563 * 674 564 * @return EOK on success or negative error code on failure. 675 565 */ 676 int block_read_direct(dev_handle_t dev_handle, bn_t ba, size_t cnt, void *buf)677 { 678 devcon_t *devcon;566 static int read_block(devcon_t *devcon, bn_t boff, size_t block_size) 567 { 568 ipcarg_t retval; 679 569 int rc; 680 570 681 devcon = devcon_search(dev_handle);682 571 assert(devcon); 683 684 fibril_mutex_lock(&devcon->comm_area_lock); 685 686 rc = read_blocks(devcon, ba, cnt); 687 if (rc == EOK) 688 memcpy(buf, devcon->comm_area, devcon->pblock_size * cnt); 689 690 fibril_mutex_unlock(&devcon->comm_area_lock); 691 692 return rc; 693 } 694 695 /** Write blocks directly to device (bypass cache). 696 * 697 * @param dev_handle Device handle of the block device. 698 * @param ba Address of first block. 699 * @param cnt Number of blocks. 700 * @param src The data to be written. 572 rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK, boff, block_size, 573 &retval); 574 if ((rc != EOK) || (retval != EOK)) 575 return (rc != EOK ? rc : (int) retval); 576 577 return EOK; 578 } 579 580 /** Write block to block device. 581 * 582 * @param devcon Device connection. 583 * @param boff Block index. 584 * @param block_size Block size. 585 * @param src Buffer containing the data to write. 701 586 * 702 587 * @return EOK on success or negative error code on failure. 703 588 */ 704 int block_write_direct(dev_handle_t dev_handle, bn_t ba, size_t cnt, 705 const void *data) 706 { 707 devcon_t *devcon; 589 static int write_block(devcon_t *devcon, bn_t boff, size_t block_size) 590 { 591 ipcarg_t retval; 708 592 int rc; 709 593 710 devcon = devcon_search(dev_handle);711 594 assert(devcon); 712 713 fibril_mutex_lock(&devcon->comm_area_lock); 714 715 memcpy(devcon->comm_area, data, devcon->pblock_size * cnt); 716 rc = read_blocks(devcon, ba, cnt); 717 718 fibril_mutex_unlock(&devcon->comm_area_lock); 719 720 return rc; 721 } 722 723 /** Get device block size. 724 * 725 * @param dev_handle Device handle of the block device. 726 * @param bsize Output block size. 727 * 728 * @return EOK on success or negative error code on failure. 729 */ 730 int block_get_bsize(dev_handle_t dev_handle, size_t *bsize) 731 { 732 devcon_t *devcon; 733 734 devcon = devcon_search(dev_handle); 735 assert(devcon); 736 737 return get_block_size(devcon->dev_phone, bsize); 738 } 739 740 /** Read blocks from block device. 741 * 742 * @param devcon Device connection. 743 * @param ba Address of first block. 744 * @param cnt Number of blocks. 745 * @param src Buffer for storing the data. 746 * 747 * @return EOK on success or negative error code on failure. 748 */ 749 static int read_blocks(devcon_t *devcon, bn_t ba, size_t cnt) 750 { 751 int rc; 752 753 assert(devcon); 754 rc = async_req_3_0(devcon->dev_phone, BD_READ_BLOCKS, LOWER32(ba), 755 UPPER32(ba), cnt); 756 return rc; 757 } 758 759 /** Write block to block device. 760 * 761 * @param devcon Device connection. 762 * @param ba Address of first block. 763 * @param cnt Number of blocks. 764 * @param src Buffer containing the data to write. 765 * 766 * @return EOK on success or negative error code on failure. 767 */ 768 static int write_blocks(devcon_t *devcon, bn_t ba, size_t cnt) 769 { 770 int rc; 771 772 assert(devcon); 773 rc = async_req_3_0(devcon->dev_phone, BD_WRITE_BLOCKS, LOWER32(ba), 774 UPPER32(ba), cnt); 775 return rc; 776 } 777 778 /** Get block size used by the device. */ 779 static int get_block_size(int dev_phone, size_t *bsize) 780 { 781 ipcarg_t bs; 782 int rc; 783 784 rc = async_req_0_1(dev_phone, BD_GET_BLOCK_SIZE, &bs); 785 if (rc == EOK) 786 *bsize = (size_t) bs; 787 788 return rc; 595 rc = async_req_2_1(devcon->dev_phone, BD_WRITE_BLOCK, boff, block_size, 596 &retval); 597 if ((rc != EOK) || (retval != EOK)) 598 return (rc != EOK ? rc : (int) retval); 599 600 return EOK; 789 601 } 790 602
Note:
See TracChangeset
for help on using the changeset viewer.