Beispiel #1
0
int ext4_block_flush_buf(struct ext4_blockdev *bdev, struct ext4_buf *buf)
{
	int r;
	struct ext4_bcache *bc = bdev->bc;

	if (ext4_bcache_test_flag(buf, BC_DIRTY) &&
	    ext4_bcache_test_flag(buf, BC_UPTODATE)) {
		r = ext4_blocks_set_direct(bdev, buf->data, buf->lba, 1);
		if (r) {
			if (buf->end_write) {
				bc->dont_shake = true;
				buf->end_write(bc, buf, r, buf->end_write_arg);
				bc->dont_shake = false;
			}

			return r;
		}

		ext4_bcache_remove_dirty_node(bc, buf);
		ext4_bcache_clear_flag(buf, BC_DIRTY);
		if (buf->end_write) {
			bc->dont_shake = true;
			buf->end_write(bc, buf, r, buf->end_write_arg);
			bc->dont_shake = false;
		}
	}
	return EOK;
}
Beispiel #2
0
int ext4_block_cache_write_back(struct ext4_blockdev *bdev,
    uint8_t on_off)
{
    int r;
    uint32_t i;

    if(on_off)
        bdev->cache_write_back++;

    if(!on_off && bdev->cache_write_back)
        bdev->cache_write_back--;

    /*Flush all delayed cache blocks*/
    if(!bdev->cache_write_back){
        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;

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

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

            /*Reduce refered block count*/
            bdev->bc->ref_blocks--;
        }
    }
    return EOK;
}
Beispiel #3
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;
}