Subversion Repositories HelenOS

Rev

Rev 4153 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4153 Rev 4581
Line 35... Line 35...
35
 * @brief
35
 * @brief
36
 */
36
 */
37
 
37
 
38
#include "libblock.h"
38
#include "libblock.h"
39
#include "../../srv/vfs/vfs.h"
39
#include "../../srv/vfs/vfs.h"
40
#include "../../srv/rd/rd.h"
-
 
41
#include <ipc/devmap.h>
40
#include <ipc/devmap.h>
-
 
41
#include <ipc/bd.h>
42
#include <ipc/services.h>
42
#include <ipc/services.h>
43
#include <errno.h>
43
#include <errno.h>
44
#include <sys/mman.h>
44
#include <sys/mman.h>
45
#include <async.h>
45
#include <async.h>
46
#include <ipc/ipc.h>
46
#include <ipc/ipc.h>
47
#include <as.h>
47
#include <as.h>
48
#include <assert.h>
48
#include <assert.h>
49
#include <futex.h>
49
#include <fibril_sync.h>
50
#include <libadt/list.h>
50
#include <adt/list.h>
51
#include <libadt/hash_table.h>
51
#include <adt/hash_table.h>
-
 
52
#include <mem.h>
52
 
53
 
53
/** Lock protecting the device connection list */
54
/** Lock protecting the device connection list */
54
static futex_t dcl_lock = FUTEX_INITIALIZER;
55
static FIBRIL_MUTEX_INITIALIZE(dcl_lock);
55
/** Device connection list head. */
56
/** Device connection list head. */
56
static LIST_INITIALIZE(dcl_head);
57
static LIST_INITIALIZE(dcl_head);
57
 
58
 
58
#define CACHE_BUCKETS_LOG2      10
59
#define CACHE_BUCKETS_LOG2      10
59
#define CACHE_BUCKETS           (1 << CACHE_BUCKETS_LOG2)
60
#define CACHE_BUCKETS           (1 << CACHE_BUCKETS_LOG2)
60
 
61
 
61
typedef struct {
62
typedef struct {
62
    futex_t lock;
63
    fibril_mutex_t lock;
63
    size_t block_size;      /**< Block size. */
64
    size_t block_size;      /**< Block size. */
64
    unsigned block_count;       /**< Total number of blocks. */
65
    unsigned block_count;       /**< Total number of blocks. */
65
    hash_table_t block_hash;
66
    hash_table_t block_hash;
66
    link_t free_head;
67
    link_t free_head;
-
 
68
    enum cache_mode mode;
67
} cache_t;
69
} cache_t;
68
 
70
 
69
typedef struct {
71
typedef struct {
70
    link_t link;
72
    link_t link;
71
    int dev_handle;
73
    dev_handle_t dev_handle;
72
    int dev_phone;
74
    int dev_phone;
73
    void *com_area;
75
    void *com_area;
74
    size_t com_size;
76
    size_t com_size;
75
    void *bb_buf;
77
    void *bb_buf;
76
    off_t bb_off;
78
    off_t bb_off;
77
    size_t bb_size;
79
    size_t bb_size;
78
    cache_t *cache;
80
    cache_t *cache;
79
} devcon_t;
81
} devcon_t;
80
 
82
 
-
 
83
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size,
-
 
84
    const void *src);
-
 
85
 
81
static devcon_t *devcon_search(dev_handle_t dev_handle)
86
static devcon_t *devcon_search(dev_handle_t dev_handle)
82
{
87
{
83
    link_t *cur;
88
    link_t *cur;
84
 
89
 
85
    futex_down(&dcl_lock);
90
    fibril_mutex_lock(&dcl_lock);
86
    for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
91
    for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
87
        devcon_t *devcon = list_get_instance(cur, devcon_t, link);
92
        devcon_t *devcon = list_get_instance(cur, devcon_t, link);
88
        if (devcon->dev_handle == dev_handle) {
93
        if (devcon->dev_handle == dev_handle) {
89
            futex_up(&dcl_lock);
94
            fibril_mutex_unlock(&dcl_lock);
90
            return devcon;
95
            return devcon;
91
        }
96
        }
92
    }
97
    }
93
    futex_up(&dcl_lock);
98
    fibril_mutex_unlock(&dcl_lock);
94
    return NULL;
99
    return NULL;
95
}
100
}
96
 
101
 
97
static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area,
102
static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area,
98
   size_t com_size)
103
   size_t com_size)
Line 112... Line 117...
112
    devcon->bb_buf = NULL;
117
    devcon->bb_buf = NULL;
113
    devcon->bb_off = 0;
118
    devcon->bb_off = 0;
114
    devcon->bb_size = 0;
119
    devcon->bb_size = 0;
115
    devcon->cache = NULL;
120
    devcon->cache = NULL;
116
 
121
 
117
    futex_down(&dcl_lock);
122
    fibril_mutex_lock(&dcl_lock);
118
    for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
123
    for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
119
        devcon_t *d = list_get_instance(cur, devcon_t, link);
124
        devcon_t *d = list_get_instance(cur, devcon_t, link);
120
        if (d->dev_handle == dev_handle) {
125
        if (d->dev_handle == dev_handle) {
121
            futex_up(&dcl_lock);
126
            fibril_mutex_unlock(&dcl_lock);
122
            free(devcon);
127
            free(devcon);
123
            return EEXIST;
128
            return EEXIST;
124
        }
129
        }
125
    }
130
    }
126
    list_append(&devcon->link, &dcl_head);
131
    list_append(&devcon->link, &dcl_head);
127
    futex_up(&dcl_lock);
132
    fibril_mutex_unlock(&dcl_lock);
128
    return EOK;
133
    return EOK;
129
}
134
}
130
 
135
 
131
static void devcon_remove(devcon_t *devcon)
136
static void devcon_remove(devcon_t *devcon)
132
{
137
{
133
    futex_down(&dcl_lock);
138
    fibril_mutex_lock(&dcl_lock);
134
    list_remove(&devcon->link);
139
    list_remove(&devcon->link);
135
    futex_up(&dcl_lock);
140
    fibril_mutex_unlock(&dcl_lock);
136
}
141
}
137
 
142
 
138
int block_init(dev_handle_t dev_handle, size_t com_size)
143
int block_init(dev_handle_t dev_handle, size_t com_size)
139
{
144
{
140
    int rc;
145
    int rc;
Line 144... Line 149...
144
    com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE,
149
    com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE,
145
        MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
150
        MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
146
    if (!com_area) {
151
    if (!com_area) {
147
        return ENOMEM;
152
        return ENOMEM;
148
    }
153
    }
149
    dev_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP,
-
 
150
        DEVMAP_CONNECT_TO_DEVICE, dev_handle);
-
 
151
 
154
 
-
 
155
    dev_phone = devmap_device_connect(dev_handle, IPC_FLAG_BLOCKING);
152
    if (dev_phone < 0) {
156
    if (dev_phone < 0) {
153
        munmap(com_area, com_size);
157
        munmap(com_area, com_size);
154
        return dev_phone;
158
        return dev_phone;
155
    }
159
    }
156
 
160
 
Line 248... Line 252...
248
    .hash = cache_hash,
252
    .hash = cache_hash,
249
    .compare = cache_compare,
253
    .compare = cache_compare,
250
    .remove_callback = cache_remove_callback
254
    .remove_callback = cache_remove_callback
251
};
255
};
252
 
256
 
253
int block_cache_init(dev_handle_t dev_handle, size_t size, unsigned blocks)
257
int block_cache_init(dev_handle_t dev_handle, size_t size, unsigned blocks,
-
 
258
    enum cache_mode mode)
254
{
259
{
255
    devcon_t *devcon = devcon_search(dev_handle);
260
    devcon_t *devcon = devcon_search(dev_handle);
256
    cache_t *cache;
261
    cache_t *cache;
257
    if (!devcon)
262
    if (!devcon)
258
        return ENOENT;
263
        return ENOENT;
Line 260... Line 265...
260
        return EEXIST;
265
        return EEXIST;
261
    cache = malloc(sizeof(cache_t));
266
    cache = malloc(sizeof(cache_t));
262
    if (!cache)
267
    if (!cache)
263
        return ENOMEM;
268
        return ENOMEM;
264
   
269
   
265
    futex_initialize(&cache->lock, 1);
270
    fibril_mutex_initialize(&cache->lock);
266
    list_initialize(&cache->free_head);
271
    list_initialize(&cache->free_head);
267
    cache->block_size = size;
272
    cache->block_size = size;
268
    cache->block_count = blocks;
273
    cache->block_count = blocks;
-
 
274
    cache->mode = mode;
269
 
275
 
270
    if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
276
    if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
271
        &cache_ops)) {
277
        &cache_ops)) {
272
        free(cache);
278
        free(cache);
273
        return ENOMEM;
279
        return ENOMEM;
Line 282... Line 288...
282
    return true;
288
    return true;
283
}
289
}
284
 
290
 
285
static void block_initialize(block_t *b)
291
static void block_initialize(block_t *b)
286
{
292
{
287
    futex_initialize(&b->lock, 1);
293
    fibril_mutex_initialize(&b->lock);
288
    b->refcnt = 1;
294
    b->refcnt = 1;
289
    b->dirty = false;
295
    b->dirty = false;
290
    rwlock_initialize(&b->contents_lock);
296
    fibril_rwlock_initialize(&b->contents_lock);
291
    link_initialize(&b->free_link);
297
    link_initialize(&b->free_link);
292
    link_initialize(&b->hash_link);
298
    link_initialize(&b->hash_link);
293
}
299
}
294
 
300
 
295
/** Instantiate a block in memory and get a reference to it.
301
/** Instantiate a block in memory and get a reference to it.
Line 314... Line 320...
314
 
320
 
315
    assert(devcon);
321
    assert(devcon);
316
    assert(devcon->cache);
322
    assert(devcon->cache);
317
   
323
   
318
    cache = devcon->cache;
324
    cache = devcon->cache;
319
    futex_down(&cache->lock);
325
    fibril_mutex_lock(&cache->lock);
320
    l = hash_table_find(&cache->block_hash, &key);
326
    l = hash_table_find(&cache->block_hash, &key);
321
    if (l) {
327
    if (l) {
322
        /*
328
        /*
323
         * We found the block in the cache.
329
         * We found the block in the cache.
324
         */
330
         */
325
        b = hash_table_get_instance(l, block_t, hash_link);
331
        b = hash_table_get_instance(l, block_t, hash_link);
326
        futex_down(&b->lock);
332
        fibril_mutex_lock(&b->lock);
327
        if (b->refcnt++ == 0)
333
        if (b->refcnt++ == 0)
328
            list_remove(&b->free_link);
334
            list_remove(&b->free_link);
329
        futex_up(&b->lock);
335
        fibril_mutex_unlock(&b->lock);
330
        futex_up(&cache->lock);
336
        fibril_mutex_unlock(&cache->lock);
331
    } else {
337
    } else {
332
        /*
338
        /*
333
         * The block was not found in the cache.
339
         * The block was not found in the cache.
334
         */
340
         */
335
        int rc;
341
        int rc;
Line 376... Line 382...
376
        /*
382
        /*
377
         * Lock the block before releasing the cache lock. Thus we don't
383
         * Lock the block before releasing the cache lock. Thus we don't
378
         * kill concurent operations on the cache while doing I/O on the
384
         * kill concurent operations on the cache while doing I/O on the
379
         * block.
385
         * block.
380
         */
386
         */
381
        futex_down(&b->lock);
387
        fibril_mutex_lock(&b->lock);
382
        futex_up(&cache->lock);
388
        fibril_mutex_unlock(&cache->lock);
383
 
389
 
384
        if (sync) {
390
        if (sync) {
385
            /*
391
            /*
386
             * The block is dirty and needs to be written back to
392
             * The block is dirty and needs to be written back to
387
             * the device before we can read in the new contents.
393
             * the device before we can read in the new contents.
Line 396... Line 402...
396
            rc = block_read(dev_handle, &bufpos, &buflen, &pos,
402
            rc = block_read(dev_handle, &bufpos, &buflen, &pos,
397
                b->data, cache->block_size, cache->block_size);
403
                b->data, cache->block_size, cache->block_size);
398
            assert(rc == EOK);
404
            assert(rc == EOK);
399
        }
405
        }
400
 
406
 
401
        futex_up(&b->lock);
407
        fibril_mutex_unlock(&b->lock);
402
    }
408
    }
403
    return b;
409
    return b;
404
}
410
}
405
 
411
 
406
/** Release a reference to a block.
412
/** Release a reference to a block.
Line 411... Line 417...
411
 */
417
 */
412
void block_put(block_t *block)
418
void block_put(block_t *block)
413
{
419
{
414
    devcon_t *devcon = devcon_search(block->dev_handle);
420
    devcon_t *devcon = devcon_search(block->dev_handle);
415
    cache_t *cache;
421
    cache_t *cache;
-
 
422
    int rc;
416
 
423
 
417
    assert(devcon);
424
    assert(devcon);
418
    assert(devcon->cache);
425
    assert(devcon->cache);
419
 
426
 
420
    cache = devcon->cache;
427
    cache = devcon->cache;
421
    futex_down(&cache->lock);
428
    fibril_mutex_lock(&cache->lock);
422
    futex_down(&block->lock);
429
    fibril_mutex_lock(&block->lock);
423
    if (!--block->refcnt) {
430
    if (!--block->refcnt) {
424
        /*
431
        /*
425
         * Last reference to the block was dropped, put the block on the
432
         * Last reference to the block was dropped, put the block on the
426
         * free list.
433
         * free list.
427
         */
434
         */
428
        list_append(&block->free_link, &cache->free_head);
435
        list_append(&block->free_link, &cache->free_head);
-
 
436
        if (cache->mode != CACHE_MODE_WB && block->dirty) {
-
 
437
            rc = write_block(devcon, block->boff, block->size,
-
 
438
                block->data);
-
 
439
            assert(rc == EOK);
-
 
440
 
-
 
441
            block->dirty = false;
-
 
442
        }
429
    }
443
    }
430
    futex_up(&block->lock);
444
    fibril_mutex_unlock(&block->lock);
431
    futex_up(&cache->lock);
445
    fibril_mutex_unlock(&cache->lock);
432
}
446
}
433
 
447
 
434
/** Read data from a block device.
448
/** Read data from a block device.
435
 *
449
 *
436
 * @param dev_handle    Device handle of the block device.
450
 * @param dev_handle    Device handle of the block device.
Line 444... Line 458...
444
 * @param block_size    Block size to be used for the transfer.
458
 * @param block_size    Block size to be used for the transfer.
445
 *
459
 *
446
 * @return      EOK on success or a negative return code on failure.
460
 * @return      EOK on success or a negative return code on failure.
447
 */
461
 */
448
int
462
int
449
block_read(int dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, void *dst,
463
block_read(dev_handle_t dev_handle, off_t *bufpos, size_t *buflen, off_t *pos,
450
    size_t size, size_t block_size)
464
    void *dst, size_t size, size_t block_size)
451
{
465
{
452
    off_t offset = 0;
466
    off_t offset = 0;
453
    size_t left = size;
467
    size_t left = size;
454
    devcon_t *devcon = devcon_search(dev_handle);
468
    devcon_t *devcon = devcon_search(dev_handle);
455
    assert(devcon);
469
    assert(devcon);
Line 472... Line 486...
472
            *bufpos += rd;
486
            *bufpos += rd;
473
            *pos += rd;
487
            *pos += rd;
474
            left -= rd;
488
            left -= rd;
475
        }
489
        }
476
       
490
       
477
        if (*bufpos == *buflen) {
491
        if (*bufpos == (off_t) *buflen) {
478
            /* Refill the communication buffer with a new block. */
492
            /* Refill the communication buffer with a new block. */
479
            ipcarg_t retval;
493
            ipcarg_t retval;
480
            int rc = async_req_2_1(devcon->dev_phone, RD_READ_BLOCK,
494
            int rc = async_req_2_1(devcon->dev_phone, BD_READ_BLOCK,
481
                *pos / block_size, block_size, &retval);
495
                *pos / block_size, block_size, &retval);
482
            if ((rc != EOK) || (retval != EOK))
496
            if ((rc != EOK) || (retval != EOK))
483
                return (rc != EOK ? rc : retval);
497
                return (rc != EOK ? rc : (int) retval);
484
           
498
           
485
            *bufpos = 0;
499
            *bufpos = 0;
486
            *buflen = block_size;
500
            *buflen = block_size;
487
        }
501
        }
488
    }
502
    }
489
   
503
   
490
    return EOK;
504
    return EOK;
491
}
505
}
492
 
506
 
-
 
507
/** Write block to block device.
-
 
508
 *
-
 
509
 * @param devcon    Device connection.
-
 
510
 * @param boff      Block index.
-
 
511
 * @param block_size    Block size.
-
 
512
 * @param src       Buffer containing the data to write.
-
 
513
 *
-
 
514
 * @return      EOK on success or negative error code on failure.
-
 
515
 */
-
 
516
static int write_block(devcon_t *devcon, bn_t boff, size_t block_size,
-
 
517
    const void *src)
-
 
518
{
-
 
519
    ipcarg_t retval;
-
 
520
    int rc;
-
 
521
 
-
 
522
    assert(devcon);
-
 
523
    memcpy(devcon->com_area, src, block_size);
-
 
524
   
-
 
525
    rc = async_req_2_1(devcon->dev_phone, BD_WRITE_BLOCK,
-
 
526
        boff, block_size, &retval);
-
 
527
    if ((rc != EOK) || (retval != EOK))
-
 
528
        return (rc != EOK ? rc : (int) retval);
-
 
529
 
-
 
530
    return EOK;
-
 
531
}
-
 
532
 
493
/** @}
533
/** @}
494
 */
534
 */