Subversion Repositories HelenOS

Rev

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

Rev 4583 Rev 4611
Line 61... Line 61...
61
 
61
 
62
typedef struct {
62
typedef struct {
63
    fibril_mutex_t lock;
63
    fibril_mutex_t lock;
64
    size_t block_size;      /**< Block size. */
64
    size_t block_size;      /**< Block size. */
65
    unsigned block_count;       /**< Total number of blocks. */
65
    unsigned block_count;       /**< Total number of blocks. */
-
 
66
    unsigned blocks_cached;     /**< Number of cached blocks. */
66
    hash_table_t block_hash;
67
    hash_table_t block_hash;
67
    link_t free_head;
68
    link_t free_head;
68
    enum cache_mode mode;
69
    enum cache_mode mode;
69
} cache_t;
70
} cache_t;
70
 
71
 
71
typedef struct {
72
typedef struct {
72
    link_t link;
73
    link_t link;
73
    dev_handle_t dev_handle;
74
    dev_handle_t dev_handle;
74
    int dev_phone;
75
    int dev_phone;
-
 
76
    fibril_mutex_t com_area_lock;
75
    void *com_area;
77
    void *com_area;
76
    size_t com_size;
78
    size_t com_size;
77
    void *bb_buf;
79
    void *bb_buf;
78
    off_t bb_off;
80
    off_t bb_off;
79
    size_t bb_size;
81
    size_t bb_size;
Line 110... Line 112...
110
        return ENOMEM;
112
        return ENOMEM;
111
   
113
   
112
    link_initialize(&devcon->link);
114
    link_initialize(&devcon->link);
113
    devcon->dev_handle = dev_handle;
115
    devcon->dev_handle = dev_handle;
114
    devcon->dev_phone = dev_phone;
116
    devcon->dev_phone = dev_phone;
-
 
117
    fibril_mutex_initialize(&devcon->com_area_lock);
115
    devcon->com_area = com_area;
118
    devcon->com_area = com_area;
116
    devcon->com_size = com_size;
119
    devcon->com_size = com_size;
117
    devcon->bb_buf = NULL;
120
    devcon->bb_buf = NULL;
118
    devcon->bb_off = 0;
121
    devcon->bb_off = 0;
119
    devcon->bb_size = 0;
122
    devcon->bb_size = 0;
Line 209... Line 212...
209
        return EEXIST;
212
        return EEXIST;
210
    bb_buf = malloc(size);
213
    bb_buf = malloc(size);
211
    if (!bb_buf)
214
    if (!bb_buf)
212
        return ENOMEM;
215
        return ENOMEM;
213
   
216
   
-
 
217
    fibril_mutex_lock(&devcon->com_area_lock);
214
    rc = read_block(devcon, 0, size);
218
    rc = read_block(devcon, 0, size);
215
    if (rc != EOK) {
219
    if (rc != EOK) {
-
 
220
        fibril_mutex_unlock(&devcon->com_area_lock);
216
            free(bb_buf);
221
            free(bb_buf);
217
        return rc;
222
        return rc;
218
    }
223
    }
219
 
-
 
220
    memcpy(bb_buf, devcon->com_area, size);
224
    memcpy(bb_buf, devcon->com_area, size);
-
 
225
    fibril_mutex_unlock(&devcon->com_area_lock);
221
 
226
 
222
    devcon->bb_buf = bb_buf;
227
    devcon->bb_buf = bb_buf;
223
    devcon->bb_off = off;
228
    devcon->bb_off = off;
224
    devcon->bb_size = size;
229
    devcon->bb_size = size;
225
 
230
 
Line 269... Line 274...
269
   
274
   
270
    fibril_mutex_initialize(&cache->lock);
275
    fibril_mutex_initialize(&cache->lock);
271
    list_initialize(&cache->free_head);
276
    list_initialize(&cache->free_head);
272
    cache->block_size = size;
277
    cache->block_size = size;
273
    cache->block_count = blocks;
278
    cache->block_count = blocks;
-
 
279
    cache->blocks_cached = 0;
274
    cache->mode = mode;
280
    cache->mode = mode;
275
 
281
 
276
    if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
282
    if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
277
        &cache_ops)) {
283
        &cache_ops)) {
278
        free(cache);
284
        free(cache);
Line 281... Line 287...
281
 
287
 
282
    devcon->cache = cache;
288
    devcon->cache = cache;
283
    return EOK;
289
    return EOK;
284
}
290
}
285
 
291
 
-
 
292
#define CACHE_LO_WATERMARK  10  
-
 
293
#define CACHE_HI_WATERMARK  20  
286
static bool cache_can_grow(cache_t *cache)
294
static bool cache_can_grow(cache_t *cache)
287
{
295
{
-
 
296
    if (cache->blocks_cached < CACHE_LO_WATERMARK)
-
 
297
        return true;
-
 
298
    if (!list_empty(&cache->free_head))
-
 
299
        return false;
288
    return true;
300
    return true;
289
}
301
}
290
 
302
 
291
static void block_initialize(block_t *b)
303
static void block_initialize(block_t *b)
292
{
304
{
Line 313... Line 325...
313
    devcon_t *devcon;
325
    devcon_t *devcon;
314
    cache_t *cache;
326
    cache_t *cache;
315
    block_t *b;
327
    block_t *b;
316
    link_t *l;
328
    link_t *l;
317
    unsigned long key = boff;
329
    unsigned long key = boff;
-
 
330
    bn_t oboff;
318
   
331
   
319
    devcon = devcon_search(dev_handle);
332
    devcon = devcon_search(dev_handle);
320
 
333
 
321
    assert(devcon);
334
    assert(devcon);
322
    assert(devcon->cache);
335
    assert(devcon->cache);
Line 353... Line 366...
353
            b->data = malloc(cache->block_size);
366
            b->data = malloc(cache->block_size);
354
            if (!b->data) {
367
            if (!b->data) {
355
                free(b);
368
                free(b);
356
                goto recycle;
369
                goto recycle;
357
            }
370
            }
-
 
371
            cache->blocks_cached++;
358
        } else {
372
        } else {
359
            /*
373
            /*
360
             * Try to recycle a block from the free list.
374
             * Try to recycle a block from the free list.
361
             */
375
             */
362
            unsigned long temp_key;
376
            unsigned long temp_key;
363
recycle:
377
recycle:
364
            assert(!list_empty(&cache->free_head));
378
            assert(!list_empty(&cache->free_head));
365
            l = cache->free_head.next;
379
            l = cache->free_head.next;
366
            list_remove(l);
380
            list_remove(l);
367
            b = hash_table_get_instance(l, block_t, hash_link);
381
            b = list_get_instance(l, block_t, free_link);
368
            sync = b->dirty;
382
            sync = b->dirty;
-
 
383
            oboff = b->boff;
369
            temp_key = b->boff;
384
            temp_key = b->boff;
370
            hash_table_remove(&cache->block_hash, &temp_key, 1);
385
            hash_table_remove(&cache->block_hash, &temp_key, 1);
371
        }
386
        }
372
 
387
 
373
        block_initialize(b);
388
        block_initialize(b);
Line 387... Line 402...
387
        if (sync) {
402
        if (sync) {
388
            /*
403
            /*
389
             * The block is dirty and needs to be written back to
404
             * The block is dirty and needs to be written back to
390
             * the device before we can read in the new contents.
405
             * the device before we can read in the new contents.
391
             */
406
             */
392
            abort();    /* TODO: block_write() */
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);
393
        }
412
        }
394
        if (!(flags & BLOCK_FLAGS_NOREAD)) {
413
        if (!(flags & BLOCK_FLAGS_NOREAD)) {
395
            /*
414
            /*
396
             * The block contains old or no data. We need to read
415
             * The block contains old or no data. We need to read
397
             * the new contents from the device.
416
             * the new contents from the device.
398
             */
417
             */
-
 
418
            fibril_mutex_lock(&devcon->com_area_lock);
399
            rc = read_block(devcon, b->boff, cache->block_size);
419
            rc = read_block(devcon, b->boff, cache->block_size);
400
            assert(rc == EOK);
420
            assert(rc == EOK);
401
            memcpy(b->data, devcon->com_area, cache->block_size);
421
            memcpy(b->data, devcon->com_area, cache->block_size);
-
 
422
            fibril_mutex_unlock(&devcon->com_area_lock);
402
        }
423
        }
403
 
424
 
404
        fibril_mutex_unlock(&b->lock);
425
        fibril_mutex_unlock(&b->lock);
405
    }
426
    }
406
    return b;
427
    return b;
Line 424... Line 445...
424
    cache = devcon->cache;
445
    cache = devcon->cache;
425
    fibril_mutex_lock(&cache->lock);
446
    fibril_mutex_lock(&cache->lock);
426
    fibril_mutex_lock(&block->lock);
447
    fibril_mutex_lock(&block->lock);
427
    if (!--block->refcnt) {
448
    if (!--block->refcnt) {
428
        /*
449
        /*
429
         * Last reference to the block was dropped, put the block on the
450
         * Last reference to the block was dropped. Either free the
-
 
451
         * block or put it on the free list.
-
 
452
         */
-
 
453
        if (cache->blocks_cached > CACHE_HI_WATERMARK) {
-
 
454
            /*
-
 
455
             * Currently there are too many cached blocks.
-
 
456
             */
-
 
457
            if (block->dirty) {
-
 
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);
-
 
465
            }
-
 
466
            /*
-
 
467
             * Take the block out of the cache and free it.
-
 
468
             */
-
 
469
            unsigned long key = block->boff;
-
 
470
            hash_table_remove(&cache->block_hash, &key, 1);
430
         * free list.
471
            free(block);
-
 
472
            free(block->data);
-
 
473
            cache->blocks_cached--;
-
 
474
            fibril_mutex_unlock(&cache->lock);
-
 
475
            return;
-
 
476
        }
-
 
477
        /*
-
 
478
         * Put the block on the free list.
431
         */
479
         */
432
        list_append(&block->free_link, &cache->free_head);
480
        list_append(&block->free_link, &cache->free_head);
433
        if (cache->mode != CACHE_MODE_WB && block->dirty) {
481
        if (cache->mode != CACHE_MODE_WB && block->dirty) {
-
 
482
            fibril_mutex_lock(&devcon->com_area_lock);
434
            memcpy(devcon->com_area, block->data, block->size);
483
            memcpy(devcon->com_area, block->data, block->size);
435
            rc = write_block(devcon, block->boff, block->size);
484
            rc = write_block(devcon, block->boff, block->size);
436
            assert(rc == EOK);
485
            assert(rc == EOK);
-
 
486
            fibril_mutex_unlock(&devcon->com_area_lock);
437
 
487
 
438
            block->dirty = false;
488
            block->dirty = false;
439
        }
489
        }
440
    }
490
    }
441
    fibril_mutex_unlock(&block->lock);
491
    fibril_mutex_unlock(&block->lock);
Line 462... Line 512...
462
    off_t offset = 0;
512
    off_t offset = 0;
463
    size_t left = size;
513
    size_t left = size;
464
    devcon_t *devcon = devcon_search(dev_handle);
514
    devcon_t *devcon = devcon_search(dev_handle);
465
    assert(devcon);
515
    assert(devcon);
466
   
516
   
-
 
517
    fibril_mutex_lock(&devcon->com_area_lock);
467
    while (left > 0) {
518
    while (left > 0) {
468
        size_t rd;
519
        size_t rd;
469
       
520
       
470
        if (*bufpos + left < *buflen)
521
        if (*bufpos + left < *buflen)
471
            rd = left;
522
            rd = left;
Line 487... Line 538...
487
        if (*bufpos == (off_t) *buflen) {
538
        if (*bufpos == (off_t) *buflen) {
488
            /* Refill the communication buffer with a new block. */
539
            /* Refill the communication buffer with a new block. */
489
            int rc;
540
            int rc;
490
 
541
 
491
            rc = read_block(devcon, *pos / block_size, block_size);
542
            rc = read_block(devcon, *pos / block_size, block_size);
492
            if (rc != EOK)
543
            if (rc != EOK) {
-
 
544
                fibril_mutex_unlock(&devcon->com_area_lock);
493
                return rc;
545
                return rc;
-
 
546
            }
494
           
547
           
495
            *bufpos = 0;
548
            *bufpos = 0;
496
            *buflen = block_size;
549
            *buflen = block_size;
497
        }
550
        }
498
    }
551
    }
-
 
552
    fibril_mutex_unlock(&devcon->com_area_lock);
499
   
553
   
500
    return EOK;
554
    return EOK;
501
}
555
}
502
 
556
 
503
/** Read block from block device.
557
/** Read block from block device.