Changes in uspace/lib/block/libblock.c [867e2555:5716e9a] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/block/libblock.c
r867e2555 r5716e9a 2 2 * Copyright (c) 2008 Jakub Jermar 3 3 * Copyright (c) 2008 Martin Decky 4 * Copyright (c) 2011 Martin Sucha5 4 * All rights reserved. 6 5 * … … 52 51 #include <macros.h> 53 52 #include <mem.h> 54 #include <malloc.h>55 #include <stdio.h>56 53 #include <sys/typefmt.h> 57 54 #include <stacktrace.h> … … 60 57 static FIBRIL_MUTEX_INITIALIZE(dcl_lock); 61 58 /** Device connection list head. */ 62 static LIST_INITIALIZE(dcl );63 64 #define CACHE_BUCKETS_LOG2 65 #define CACHE_BUCKETS 59 static LIST_INITIALIZE(dcl_head); 60 61 #define CACHE_BUCKETS_LOG2 10 62 #define CACHE_BUCKETS (1 << CACHE_BUCKETS_LOG2) 66 63 67 64 typedef struct { 68 65 fibril_mutex_t lock; 69 size_t lblock_size; 70 unsigned blocks_cluster; 71 unsigned block_count; 72 unsigned blocks_cached; 66 size_t lblock_size; /**< Logical block size. */ 67 unsigned blocks_cluster; /**< Physical blocks per block_t */ 68 unsigned block_count; /**< Total number of blocks. */ 69 unsigned blocks_cached; /**< Number of cached blocks. */ 73 70 hash_table_t block_hash; 74 li st_t free_list;71 link_t free_head; 75 72 enum cache_mode mode; 76 73 } cache_t; … … 79 76 link_t link; 80 77 devmap_handle_t devmap_handle; 81 async_sess_t *sess;78 int dev_phone; 82 79 fibril_mutex_t comm_area_lock; 83 80 void *comm_area; … … 85 82 void *bb_buf; 86 83 aoff64_t bb_addr; 87 size_t pblock_size; 84 size_t pblock_size; /**< Physical block size. */ 88 85 cache_t *cache; 89 86 } devcon_t; 90 87 91 static int read_blocks(devcon_t * , aoff64_t, size_t);92 static int write_blocks(devcon_t * , aoff64_t, size_t);93 static int get_block_size( async_sess_t *, size_t *);94 static int get_num_blocks( async_sess_t *, aoff64_t *);95 static aoff64_t ba_ltop(devcon_t * , aoff64_t);88 static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt); 89 static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt); 90 static int get_block_size(int dev_phone, size_t *bsize); 91 static int get_num_blocks(int dev_phone, aoff64_t *nblocks); 92 static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba); 96 93 97 94 static devcon_t *devcon_search(devmap_handle_t devmap_handle) 98 95 { 96 link_t *cur; 97 99 98 fibril_mutex_lock(&dcl_lock); 100 101 list_foreach(dcl, cur) { 99 for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { 102 100 devcon_t *devcon = list_get_instance(cur, devcon_t, link); 103 101 if (devcon->devmap_handle == devmap_handle) { … … 106 104 } 107 105 } 108 109 106 fibril_mutex_unlock(&dcl_lock); 110 107 return NULL; 111 108 } 112 109 113 static int devcon_add(devmap_handle_t devmap_handle, async_sess_t *sess, 114 size_t bsize, void *comm_area, size_t comm_size) 115 { 110 static int devcon_add(devmap_handle_t devmap_handle, int dev_phone, size_t bsize, 111 void *comm_area, size_t comm_size) 112 { 113 link_t *cur; 116 114 devcon_t *devcon; 117 115 118 116 if (comm_size < bsize) 119 117 return EINVAL; 120 118 121 119 devcon = malloc(sizeof(devcon_t)); 122 120 if (!devcon) … … 125 123 link_initialize(&devcon->link); 126 124 devcon->devmap_handle = devmap_handle; 127 devcon-> sess = sess;125 devcon->dev_phone = dev_phone; 128 126 fibril_mutex_initialize(&devcon->comm_area_lock); 129 127 devcon->comm_area = comm_area; … … 133 131 devcon->pblock_size = bsize; 134 132 devcon->cache = NULL; 135 133 136 134 fibril_mutex_lock(&dcl_lock); 137 list_foreach(dcl, cur) {135 for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { 138 136 devcon_t *d = list_get_instance(cur, devcon_t, link); 139 137 if (d->devmap_handle == devmap_handle) { … … 143 141 } 144 142 } 145 list_append(&devcon->link, &dcl );143 list_append(&devcon->link, &dcl_head); 146 144 fibril_mutex_unlock(&dcl_lock); 147 145 return EOK; … … 155 153 } 156 154 157 int block_init(exch_mgmt_t mgmt, devmap_handle_t devmap_handle, 158 size_t comm_size) 159 { 160 void *comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE, 155 int block_init(devmap_handle_t devmap_handle, size_t comm_size) 156 { 157 int rc; 158 int dev_phone; 159 void *comm_area; 160 size_t bsize; 161 162 comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE, 161 163 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 162 if (!comm_area) 164 if (!comm_area) { 163 165 return ENOMEM; 164 165 async_sess_t *sess = devmap_device_connect(mgmt, devmap_handle, 166 167 if ( !sess) {166 } 167 168 dev_phone = devmap_device_connect(devmap_handle, IPC_FLAG_BLOCKING); 169 if (dev_phone < 0) { 168 170 munmap(comm_area, comm_size); 169 return ENOENT; 170 } 171 172 async_exch_t *exch = async_exchange_begin(sess); 173 int rc = async_share_out_start(exch, comm_area, 171 return dev_phone; 172 } 173 174 rc = async_share_out_start(dev_phone, comm_area, 174 175 AS_AREA_READ | AS_AREA_WRITE); 175 async_exchange_end(exch); 176 176 if (rc != EOK) { 177 munmap(comm_area, comm_size); 178 async_hangup(dev_phone); 179 return rc; 180 } 181 182 if (get_block_size(dev_phone, &bsize) != EOK) { 183 munmap(comm_area, comm_size); 184 async_hangup(dev_phone); 185 return rc; 186 } 187 188 rc = devcon_add(devmap_handle, dev_phone, bsize, comm_area, comm_size); 177 189 if (rc != EOK) { 178 190 munmap(comm_area, comm_size); 179 async_hangup( sess);191 async_hangup(dev_phone); 180 192 return rc; 181 193 } 182 183 size_t bsize; 184 rc = get_block_size(sess, &bsize); 185 186 if (rc != EOK) { 187 munmap(comm_area, comm_size); 188 async_hangup(sess); 189 return rc; 190 } 191 192 rc = devcon_add(devmap_handle, sess, bsize, comm_area, comm_size); 193 if (rc != EOK) { 194 munmap(comm_area, comm_size); 195 async_hangup(sess); 196 return rc; 197 } 198 194 199 195 return EOK; 200 196 } … … 207 203 if (devcon->cache) 208 204 (void) block_cache_fini(devmap_handle); 209 205 210 206 devcon_remove(devcon); 211 207 212 208 if (devcon->bb_buf) 213 209 free(devcon->bb_buf); 214 210 215 211 munmap(devcon->comm_area, devcon->comm_size); 216 async_hangup(devcon-> sess);217 218 free(devcon); 212 async_hangup(devcon->dev_phone); 213 214 free(devcon); 219 215 } 220 216 … … 258 254 static hash_index_t cache_hash(unsigned long *key) 259 255 { 260 return MERGE_LOUP32(key[0], key[1])& (CACHE_BUCKETS - 1);256 return *key & (CACHE_BUCKETS - 1); 261 257 } 262 258 … … 264 260 { 265 261 block_t *b = hash_table_get_instance(item, block_t, hash_link); 266 return b->lba == MERGE_LOUP32(key[0], key[1]);262 return b->lba == *key; 267 263 } 268 264 … … 291 287 292 288 fibril_mutex_initialize(&cache->lock); 293 list_initialize(&cache->free_ list);289 list_initialize(&cache->free_head); 294 290 cache->lblock_size = size; 295 291 cache->block_count = blocks; … … 305 301 cache->blocks_cluster = cache->lblock_size / devcon->pblock_size; 306 302 307 if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 2,303 if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1, 308 304 &cache_ops)) { 309 305 free(cache); … … 332 328 * bother with the cache and block locks because we are single-threaded. 333 329 */ 334 while (!list_empty(&cache->free_ list)) {335 block_t *b = list_get_instance( list_first(&cache->free_list),330 while (!list_empty(&cache->free_head)) { 331 block_t *b = list_get_instance(cache->free_head.next, 336 332 block_t, free_link); 337 333 … … 344 340 } 345 341 346 unsigned long key[2] = { 347 LOWER32(b->lba), 348 UPPER32(b->lba) 349 }; 350 hash_table_remove(&cache->block_hash, key, 2); 342 unsigned long key = b->lba; 343 hash_table_remove(&cache->block_hash, &key, 1); 351 344 352 345 free(b->data); … … 367 360 if (cache->blocks_cached < CACHE_LO_WATERMARK) 368 361 return true; 369 if (!list_empty(&cache->free_ list))362 if (!list_empty(&cache->free_head)) 370 363 return false; 371 364 return true; … … 401 394 block_t *b; 402 395 link_t *l; 403 unsigned long key[2] = { 404 LOWER32(ba), 405 UPPER32(ba) 406 }; 407 396 unsigned long key = ba; 408 397 int rc; 409 398 … … 420 409 421 410 fibril_mutex_lock(&cache->lock); 422 l = hash_table_find(&cache->block_hash, key);411 l = hash_table_find(&cache->block_hash, &key); 423 412 if (l) { 424 413 found: … … 458 447 * Try to recycle a block from the free list. 459 448 */ 449 unsigned long temp_key; 460 450 recycle: 461 if (list_empty(&cache->free_ list)) {451 if (list_empty(&cache->free_head)) { 462 452 fibril_mutex_unlock(&cache->lock); 463 453 rc = ENOMEM; 464 454 goto out; 465 455 } 466 l = list_first(&cache->free_list);456 l = cache->free_head.next; 467 457 b = list_get_instance(l, block_t, free_link); 468 458 … … 479 469 */ 480 470 list_remove(&b->free_link); 481 list_append(&b->free_link, &cache->free_ list);471 list_append(&b->free_link, &cache->free_head); 482 472 fibril_mutex_unlock(&cache->lock); 483 473 fibril_mutex_lock(&devcon->comm_area_lock); … … 505 495 goto retry; 506 496 } 507 l = hash_table_find(&cache->block_hash, key);497 l = hash_table_find(&cache->block_hash, &key); 508 498 if (l) { 509 499 /* … … 528 518 */ 529 519 list_remove(&b->free_link); 530 unsigned long temp_key[2] = { 531 LOWER32(b->lba), 532 UPPER32(b->lba) 533 }; 534 hash_table_remove(&cache->block_hash, temp_key, 2); 520 temp_key = b->lba; 521 hash_table_remove(&cache->block_hash, &temp_key, 1); 535 522 } 536 523 … … 540 527 b->lba = ba; 541 528 b->pba = ba_ltop(devcon, b->lba); 542 hash_table_insert(&cache->block_hash, key, &b->hash_link);529 hash_table_insert(&cache->block_hash, &key, &b->hash_link); 543 530 544 531 /* … … 652 639 * Take the block out of the cache and free it. 653 640 */ 654 unsigned long key[2] = { 655 LOWER32(block->lba), 656 UPPER32(block->lba) 657 }; 658 hash_table_remove(&cache->block_hash, key, 2); 641 unsigned long key = block->lba; 642 hash_table_remove(&cache->block_hash, &key, 1); 659 643 fibril_mutex_unlock(&block->lock); 660 644 free(block->data); … … 677 661 goto retry; 678 662 } 679 list_append(&block->free_link, &cache->free_ list);663 list_append(&block->free_link, &cache->free_head); 680 664 } 681 665 fibril_mutex_unlock(&block->lock); … … 821 805 assert(devcon); 822 806 823 return get_block_size(devcon-> sess, bsize);807 return get_block_size(devcon->dev_phone, bsize); 824 808 } 825 809 … … 833 817 int block_get_nblocks(devmap_handle_t devmap_handle, aoff64_t *nblocks) 834 818 { 835 devcon_t *devcon = devcon_search(devmap_handle); 836 assert(devcon); 837 838 return get_num_blocks(devcon->sess, nblocks); 839 } 840 841 /** Read bytes directly from the device (bypass cache) 842 * 843 * @param devmap_handle Device handle of the block device. 844 * @param abs_offset Absolute offset in bytes where to start reading 845 * @param bytes Number of bytes to read 846 * @param data Buffer that receives the data 847 * 848 * @return EOK on success or negative error code on failure. 849 */ 850 int block_read_bytes_direct(devmap_handle_t devmap_handle, aoff64_t abs_offset, 851 size_t bytes, void *data) 852 { 853 int rc; 854 size_t phys_block_size; 855 size_t buf_size; 856 void *buffer; 857 aoff64_t first_block; 858 aoff64_t last_block; 859 size_t blocks; 860 size_t offset; 861 862 rc = block_get_bsize(devmap_handle, &phys_block_size); 863 if (rc != EOK) { 864 return rc; 865 } 866 867 /* calculate data position and required space */ 868 first_block = abs_offset / phys_block_size; 869 offset = abs_offset % phys_block_size; 870 last_block = (abs_offset + bytes - 1) / phys_block_size; 871 blocks = last_block - first_block + 1; 872 buf_size = blocks * phys_block_size; 873 874 /* read the data into memory */ 875 buffer = malloc(buf_size); 876 if (buffer == NULL) { 877 return ENOMEM; 878 } 879 880 rc = block_read_direct(devmap_handle, first_block, blocks, buffer); 881 if (rc != EOK) { 882 free(buffer); 883 return rc; 884 } 885 886 /* copy the data from the buffer */ 887 memcpy(data, buffer + offset, bytes); 888 free(buffer); 889 890 return EOK; 819 devcon_t *devcon; 820 821 devcon = devcon_search(devmap_handle); 822 assert(devcon); 823 824 return get_num_blocks(devcon->dev_phone, nblocks); 891 825 } 892 826 … … 902 836 static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt) 903 837 { 904 assert(devcon);905 906 as ync_exch_t *exch = async_exchange_begin(devcon->sess);907 int rc = async_req_3_0(exch, BD_READ_BLOCKS, LOWER32(ba),838 int rc; 839 840 assert(devcon); 841 rc = async_req_3_0(devcon->dev_phone, BD_READ_BLOCKS, LOWER32(ba), 908 842 UPPER32(ba), cnt); 909 async_exchange_end(exch);910 911 843 if (rc != EOK) { 912 844 printf("Error %d reading %zu blocks starting at block %" PRIuOFF64 … … 917 849 #endif 918 850 } 919 920 851 return rc; 921 852 } … … 932 863 static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt) 933 864 { 934 assert(devcon);935 936 as ync_exch_t *exch = async_exchange_begin(devcon->sess);937 int rc = async_req_3_0(exch, BD_WRITE_BLOCKS, LOWER32(ba),865 int rc; 866 867 assert(devcon); 868 rc = async_req_3_0(devcon->dev_phone, BD_WRITE_BLOCKS, LOWER32(ba), 938 869 UPPER32(ba), cnt); 939 async_exchange_end(exch);940 941 870 if (rc != EOK) { 942 871 printf("Error %d writing %zu blocks starting at block %" PRIuOFF64 … … 946 875 #endif 947 876 } 948 949 877 return rc; 950 878 } 951 879 952 880 /** Get block size used by the device. */ 953 static int get_block_size( async_sess_t *sess, size_t *bsize)881 static int get_block_size(int dev_phone, size_t *bsize) 954 882 { 955 883 sysarg_t bs; 956 957 async_exch_t *exch = async_exchange_begin(sess); 958 int rc = async_req_0_1(exch, BD_GET_BLOCK_SIZE, &bs); 959 async_exchange_end(exch); 960 884 int rc; 885 886 rc = async_req_0_1(dev_phone, BD_GET_BLOCK_SIZE, &bs); 961 887 if (rc == EOK) 962 888 *bsize = (size_t) bs; 963 889 964 890 return rc; 965 891 } 966 892 967 893 /** Get total number of blocks on block device. */ 968 static int get_num_blocks(async_sess_t *sess, aoff64_t *nblocks) 969 { 970 sysarg_t nb_l; 971 sysarg_t nb_h; 972 973 async_exch_t *exch = async_exchange_begin(sess); 974 int rc = async_req_0_2(exch, BD_GET_NUM_BLOCKS, &nb_l, &nb_h); 975 async_exchange_end(exch); 976 977 if (rc == EOK) 894 static int get_num_blocks(int dev_phone, aoff64_t *nblocks) 895 { 896 sysarg_t nb_l, nb_h; 897 int rc; 898 899 rc = async_req_0_2(dev_phone, BD_GET_NUM_BLOCKS, &nb_l, &nb_h); 900 if (rc == EOK) { 978 901 *nblocks = (aoff64_t) MERGE_LOUP32(nb_l, nb_h); 979 902 } 903 980 904 return rc; 981 905 }
Note:
See TracChangeset
for help on using the changeset viewer.