Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/block/libblock.c

    r867e2555 r5716e9a  
    22 * Copyright (c) 2008 Jakub Jermar
    33 * Copyright (c) 2008 Martin Decky
    4  * Copyright (c) 2011 Martin Sucha
    54 * All rights reserved.
    65 *
     
    5251#include <macros.h>
    5352#include <mem.h>
    54 #include <malloc.h>
    55 #include <stdio.h>
    5653#include <sys/typefmt.h>
    5754#include <stacktrace.h>
     
    6057static FIBRIL_MUTEX_INITIALIZE(dcl_lock);
    6158/** Device connection list head. */
    62 static LIST_INITIALIZE(dcl);
    63 
    64 #define CACHE_BUCKETS_LOG2  10
    65 #define CACHE_BUCKETS       (1 << CACHE_BUCKETS_LOG2)
     59static LIST_INITIALIZE(dcl_head);
     60
     61#define CACHE_BUCKETS_LOG2              10
     62#define CACHE_BUCKETS                   (1 << CACHE_BUCKETS_LOG2)
    6663
    6764typedef struct {
    6865        fibril_mutex_t lock;
    69         size_t lblock_size;       /**< Logical block size. */
    70         unsigned blocks_cluster;  /**< Physical blocks per block_t */
    71         unsigned block_count;     /**< Total number of blocks. */
    72         unsigned blocks_cached;   /**< Number of cached blocks. */
     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. */
    7370        hash_table_t block_hash;
    74         list_t free_list;
     71        link_t free_head;
    7572        enum cache_mode mode;
    7673} cache_t;
     
    7976        link_t link;
    8077        devmap_handle_t devmap_handle;
    81         async_sess_t *sess;
     78        int dev_phone;
    8279        fibril_mutex_t comm_area_lock;
    8380        void *comm_area;
     
    8582        void *bb_buf;
    8683        aoff64_t bb_addr;
    87         size_t pblock_size;  /**< Physical block size. */
     84        size_t pblock_size;             /**< Physical block size. */
    8885        cache_t *cache;
    8986} devcon_t;
    9087
    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);
     88static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt);
     89static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt);
     90static int get_block_size(int dev_phone, size_t *bsize);
     91static int get_num_blocks(int dev_phone, aoff64_t *nblocks);
     92static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba);
    9693
    9794static devcon_t *devcon_search(devmap_handle_t devmap_handle)
    9895{
     96        link_t *cur;
     97
    9998        fibril_mutex_lock(&dcl_lock);
    100        
    101         list_foreach(dcl, cur) {
     99        for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
    102100                devcon_t *devcon = list_get_instance(cur, devcon_t, link);
    103101                if (devcon->devmap_handle == devmap_handle) {
     
    106104                }
    107105        }
    108        
    109106        fibril_mutex_unlock(&dcl_lock);
    110107        return NULL;
    111108}
    112109
    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 {
     110static 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;
    116114        devcon_t *devcon;
    117        
     115
    118116        if (comm_size < bsize)
    119117                return EINVAL;
    120        
     118
    121119        devcon = malloc(sizeof(devcon_t));
    122120        if (!devcon)
     
    125123        link_initialize(&devcon->link);
    126124        devcon->devmap_handle = devmap_handle;
    127         devcon->sess = sess;
     125        devcon->dev_phone = dev_phone;
    128126        fibril_mutex_initialize(&devcon->comm_area_lock);
    129127        devcon->comm_area = comm_area;
     
    133131        devcon->pblock_size = bsize;
    134132        devcon->cache = NULL;
    135        
     133
    136134        fibril_mutex_lock(&dcl_lock);
    137         list_foreach(dcl, cur) {
     135        for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
    138136                devcon_t *d = list_get_instance(cur, devcon_t, link);
    139137                if (d->devmap_handle == devmap_handle) {
     
    143141                }
    144142        }
    145         list_append(&devcon->link, &dcl);
     143        list_append(&devcon->link, &dcl_head);
    146144        fibril_mutex_unlock(&dcl_lock);
    147145        return EOK;
     
    155153}
    156154
    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,
     155int 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,
    161163            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
    162         if (!comm_area)
     164        if (!comm_area) {
    163165                return ENOMEM;
    164        
    165         async_sess_t *sess = devmap_device_connect(mgmt, devmap_handle,
    166             IPC_FLAG_BLOCKING);
    167         if (!sess) {
     166        }
     167
     168        dev_phone = devmap_device_connect(devmap_handle, IPC_FLAG_BLOCKING);
     169        if (dev_phone < 0) {
    168170                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,
    174175            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);
    177189        if (rc != EOK) {
    178190                munmap(comm_area, comm_size);
    179                 async_hangup(sess);
     191                async_hangup(dev_phone);
    180192                return rc;
    181193        }
    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
    199195        return EOK;
    200196}
     
    207203        if (devcon->cache)
    208204                (void) block_cache_fini(devmap_handle);
    209        
     205
    210206        devcon_remove(devcon);
    211        
     207
    212208        if (devcon->bb_buf)
    213209                free(devcon->bb_buf);
    214        
     210
    215211        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);   
    219215}
    220216
     
    258254static hash_index_t cache_hash(unsigned long *key)
    259255{
    260         return MERGE_LOUP32(key[0], key[1]) & (CACHE_BUCKETS - 1);
     256        return *key & (CACHE_BUCKETS - 1);
    261257}
    262258
     
    264260{
    265261        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;
    267263}
    268264
     
    291287       
    292288        fibril_mutex_initialize(&cache->lock);
    293         list_initialize(&cache->free_list);
     289        list_initialize(&cache->free_head);
    294290        cache->lblock_size = size;
    295291        cache->block_count = blocks;
     
    305301        cache->blocks_cluster = cache->lblock_size / devcon->pblock_size;
    306302
    307         if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 2,
     303        if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
    308304            &cache_ops)) {
    309305                free(cache);
     
    332328         * bother with the cache and block locks because we are single-threaded.
    333329         */
    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,
    336332                    block_t, free_link);
    337333
     
    344340                }
    345341
    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);
    351344               
    352345                free(b->data);
     
    367360        if (cache->blocks_cached < CACHE_LO_WATERMARK)
    368361                return true;
    369         if (!list_empty(&cache->free_list))
     362        if (!list_empty(&cache->free_head))
    370363                return false;
    371364        return true;
     
    401394        block_t *b;
    402395        link_t *l;
    403         unsigned long key[2] = {
    404                 LOWER32(ba),
    405                 UPPER32(ba)
    406         };
    407 
     396        unsigned long key = ba;
    408397        int rc;
    409398       
     
    420409
    421410        fibril_mutex_lock(&cache->lock);
    422         l = hash_table_find(&cache->block_hash, key);
     411        l = hash_table_find(&cache->block_hash, &key);
    423412        if (l) {
    424413found:
     
    458447                         * Try to recycle a block from the free list.
    459448                         */
     449                        unsigned long temp_key;
    460450recycle:
    461                         if (list_empty(&cache->free_list)) {
     451                        if (list_empty(&cache->free_head)) {
    462452                                fibril_mutex_unlock(&cache->lock);
    463453                                rc = ENOMEM;
    464454                                goto out;
    465455                        }
    466                         l = list_first(&cache->free_list);
     456                        l = cache->free_head.next;
    467457                        b = list_get_instance(l, block_t, free_link);
    468458
     
    479469                                 */
    480470                                list_remove(&b->free_link);
    481                                 list_append(&b->free_link, &cache->free_list);
     471                                list_append(&b->free_link, &cache->free_head);
    482472                                fibril_mutex_unlock(&cache->lock);
    483473                                fibril_mutex_lock(&devcon->comm_area_lock);
     
    505495                                        goto retry;
    506496                                }
    507                                 l = hash_table_find(&cache->block_hash, key);
     497                                l = hash_table_find(&cache->block_hash, &key);
    508498                                if (l) {
    509499                                        /*
     
    528518                         */
    529519                        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);
    535522                }
    536523
     
    540527                b->lba = ba;
    541528                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);
    543530
    544531                /*
     
    652639                         * Take the block out of the cache and free it.
    653640                         */
    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);
    659643                        fibril_mutex_unlock(&block->lock);
    660644                        free(block->data);
     
    677661                        goto retry;
    678662                }
    679                 list_append(&block->free_link, &cache->free_list);
     663                list_append(&block->free_link, &cache->free_head);
    680664        }
    681665        fibril_mutex_unlock(&block->lock);
     
    821805        assert(devcon);
    822806       
    823         return get_block_size(devcon->sess, bsize);
     807        return get_block_size(devcon->dev_phone, bsize);
    824808}
    825809
     
    833817int block_get_nblocks(devmap_handle_t devmap_handle, aoff64_t *nblocks)
    834818{
    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);
    891825}
    892826
     
    902836static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
    903837{
    904         assert(devcon);
    905        
    906         async_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),
    908842            UPPER32(ba), cnt);
    909         async_exchange_end(exch);
    910        
    911843        if (rc != EOK) {
    912844                printf("Error %d reading %zu blocks starting at block %" PRIuOFF64
     
    917849#endif
    918850        }
    919        
    920851        return rc;
    921852}
     
    932863static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
    933864{
    934         assert(devcon);
    935        
    936         async_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),
    938869            UPPER32(ba), cnt);
    939         async_exchange_end(exch);
    940        
    941870        if (rc != EOK) {
    942871                printf("Error %d writing %zu blocks starting at block %" PRIuOFF64
     
    946875#endif
    947876        }
    948        
    949877        return rc;
    950878}
    951879
    952880/** Get block size used by the device. */
    953 static int get_block_size(async_sess_t *sess, size_t *bsize)
     881static int get_block_size(int dev_phone, size_t *bsize)
    954882{
    955883        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);
    961887        if (rc == EOK)
    962888                *bsize = (size_t) bs;
    963        
     889
    964890        return rc;
    965891}
    966892
    967893/** 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)
     894static 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) {
    978901                *nblocks = (aoff64_t) MERGE_LOUP32(nb_l, nb_h);
    979        
     902        }
     903
    980904        return rc;
    981905}
Note: See TracChangeset for help on using the changeset viewer.