Example #1
0
int ext4_block_get_noread(struct ext4_blockdev *bdev, struct ext4_block *b,
			  uint64_t lba)
{
	bool is_new;
	int r;

	ext4_assert(bdev && b);

	if (!bdev->bdif->ph_refctr)
		return EIO;

	if (!(lba < bdev->lg_bcnt))
		return ENXIO;

	b->lb_id = lba;

	/*If cache is full we have to (flush and) drop it anyway :(*/
	r = ext4_block_cache_shake(bdev);
	if (r != EOK)
		return r;

	r = ext4_bcache_alloc(bdev->bc, b, &is_new);
	if (r != EOK)
		return r;

	if (!b->data)
		return ENOMEM;

	return EOK;
}
Example #2
0
int ext4_block_get(struct ext4_blockdev *bdev, struct ext4_block *b,
    uint64_t lba)
{
    uint64_t pba;
    uint32_t pb_cnt;
    uint32_t i;
    bool is_new;
    int r;

    ext4_assert(bdev && b);

    if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
        return EIO;

    if(!(lba < bdev->lg_bcnt))
        return ERANGE;

    b->dirty = 0;
    b->lb_id = lba;

    /*If cache is full we have to flush it anyway :(*/
    if(ext4_bcache_is_full(bdev->bc) && bdev->cache_write_back){

        uint32_t free_candidate = bdev->bc->cnt;
        uint32_t min_lru = 0xFFFFFFFF;

        for (i = 0; i < bdev->bc->cnt; ++i) {
            /*Check if buffer free was delayed.*/
            if(!bdev->bc->free_delay[i])
                continue;

            /*Check reference counter.*/
            if(bdev->bc->refctr[i])
                continue;

            if(bdev->bc->lru_id[i] < min_lru){
                min_lru = bdev->bc->lru_id[i];
                free_candidate = i;
                continue;
            }
        }

        if(free_candidate < bdev->bc->cnt){
            /*Buffer free was delayed and have no reference. Flush it.*/
            r = ext4_blocks_set_direct(bdev,
                    bdev->bc->data + bdev->bc->itemsize * free_candidate,
                    bdev->bc->lba[free_candidate], 1);
            if(r != EOK)
                return r;

            /*No delayed anymore*/
            bdev->bc->free_delay[free_candidate] = 0;

            /*Reduce refered block count*/
            bdev->bc->ref_blocks--;
        }
    }


    r = ext4_bcache_alloc(bdev->bc, b, &is_new);
    if(r != EOK)
        return r;


    if(!is_new){
        /*Block is in cache. Read from physical device is not required*/
        return EOK;
    }

    if(!b->data)
        return ENOMEM;

    pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
    pb_cnt = bdev->lg_bsize / bdev->ph_bsize;

    r = bdev->bread(bdev, b->data, pba, pb_cnt);

    if(r != EOK){
        ext4_bcache_free(bdev->bc, b, 0);
        b->lb_id = 0;
        return r;
    }

    bdev->bread_ctr++;
    return EOK;
}