int ext4_block_set(struct ext4_blockdev *bdev, struct ext4_block *b) { ext4_assert(bdev && b); ext4_assert(b->buf); if (!bdev->bdif->ph_refctr) return EIO; return ext4_bcache_free(bdev->bc, b); }
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; }
int ext4_block_cache_shake(struct ext4_blockdev *bdev) { int r = EOK; struct ext4_buf *buf; if (bdev->bc->dont_shake) return EOK; bdev->bc->dont_shake = true; while (!RB_EMPTY(&bdev->bc->lru_root) && ext4_bcache_is_full(bdev->bc)) { buf = ext4_buf_lowest_lru(bdev->bc); ext4_assert(buf); if (ext4_bcache_test_flag(buf, BC_DIRTY)) { r = ext4_block_flush_buf(bdev, buf); if (r != EOK) break; } ext4_bcache_drop_buf(bdev->bc, buf); } bdev->bc->dont_shake = false; return r; }
int ext4_block_init(struct ext4_blockdev *bdev) { int rc; ext4_assert(bdev); ext4_assert(bdev->open && bdev->close && bdev->bread && bdev->bwrite); /*Low level block init*/ rc = bdev->open(bdev); if(rc != EOK) return rc; bdev->flags |= EXT4_BDEV_INITIALIZED; return EOK; }
int ext4_block_bind_bcache(struct ext4_blockdev *bdev, struct ext4_bcache *bc) { ext4_assert(bdev && bc); bdev->bc = bc; bc->bdev = bdev; return EOK; }
static void ext4_bdif_unlock(struct ext4_blockdev *bdev) { if (!bdev->bdif->unlock) return; int r = bdev->bdif->unlock(bdev); ext4_assert(r == EOK); }
void ext4_block_set_lb_size(struct ext4_blockdev *bdev, uint32_t lb_bsize) { /*Logical block size has to be multiply of physical */ ext4_assert(!(lb_bsize % bdev->bdif->ph_bsize)); bdev->lg_bsize = lb_bsize; bdev->lg_bcnt = bdev->part_size / lb_bsize; }
int ext4_block_fini(struct ext4_blockdev *bdev) { ext4_assert(bdev); bdev->flags &= ~(EXT4_BDEV_INITIALIZED); /*Low level block fini*/ return bdev->close(bdev); }
int ext4_block_cache_flush(struct ext4_blockdev *bdev) { while (!SLIST_EMPTY(&bdev->bc->dirty_list)) { int r; struct ext4_buf *buf = SLIST_FIRST(&bdev->bc->dirty_list); ext4_assert(buf); r = ext4_block_flush_buf(bdev, buf); if (r != EOK) return r; } return EOK; }
int ext4_blocks_set_direct(struct ext4_blockdev *bdev, const void *buf, uint64_t lba, uint32_t cnt) { uint64_t pba; uint32_t pb_cnt; ext4_assert(bdev && buf); pba = (lba * bdev->lg_bsize + bdev->part_offset) / bdev->bdif->ph_bsize; pb_cnt = bdev->lg_bsize / bdev->bdif->ph_bsize; return ext4_bdif_bwrite(bdev, buf, pba, pb_cnt * cnt); }
int ext4_block_fini(struct ext4_blockdev *bdev) { ext4_assert(bdev); if (!bdev->bdif->ph_refctr) return EOK; bdev->bdif->ph_refctr--; if (bdev->bdif->ph_refctr) return EOK; /*Low level block fini*/ return bdev->bdif->close(bdev); }
int ext4_blocks_get_direct(struct ext4_blockdev *bdev, void *buf, uint64_t lba, uint32_t cnt) { uint64_t pba; uint32_t pb_cnt; ext4_assert(bdev && buf); pba = (lba * bdev->lg_bsize) / bdev->ph_bsize; pb_cnt = bdev->lg_bsize / bdev->ph_bsize; bdev->bread_ctr++; return bdev->bread(bdev, buf, pba, pb_cnt * cnt); }
int ext4_block_set(struct ext4_blockdev *bdev, struct ext4_block *b) { uint64_t pba; uint32_t pb_cnt; int r; ext4_assert(bdev && b); if(!(bdev->flags & EXT4_BDEV_INITIALIZED)) return EIO; /*Doesn,t need to write.*/ if(!b->dirty && !bdev->bc->dirty[b->cache_id]){ ext4_bcache_free(bdev->bc, b, 0); return EOK; } /*Free cache delay mode*/ if(bdev->cache_write_back){ /*Free cahe block and mark as free delayed*/ return ext4_bcache_free(bdev->bc, b, bdev->cache_write_back); } if(bdev->bc->refctr[b->cache_id] > 1){ bdev->bc->dirty[b->cache_id] = true; return ext4_bcache_free(bdev->bc, b, 0); } pba = (b->lb_id * bdev->lg_bsize) / bdev->ph_bsize; pb_cnt = bdev->lg_bsize / bdev->ph_bsize; #if CONFIG_EXT4_READONLY r = EOK; #else r = bdev->bwrite(bdev, b->data, pba, pb_cnt); #endif bdev->bc->dirty[b->cache_id] = false; if(r != EOK){ b->dirty = false; ext4_bcache_free(bdev->bc, b, 0); return r; } bdev->bwrite_ctr++; b->dirty = false; ext4_bcache_free(bdev->bc, b, 0); return EOK; }
int ext4_block_init(struct ext4_blockdev *bdev) { int rc; ext4_assert(bdev); ext4_assert(bdev->bdif); ext4_assert(bdev->bdif->open && bdev->bdif->close && bdev->bdif->bread && bdev->bdif->bwrite); if (bdev->bdif->ph_refctr) { bdev->bdif->ph_refctr++; return EOK; } /*Low level block init*/ rc = bdev->bdif->open(bdev); if (rc != EOK) return rc; bdev->bdif->ph_refctr = 1; return EOK; }
int ext4_blocks_set_direct(struct ext4_blockdev *bdev, const void *buf, uint64_t lba, uint32_t cnt) { uint64_t pba; uint32_t pb_cnt; ext4_assert(bdev && buf); pba = (lba * bdev->lg_bsize) / bdev->ph_bsize; pb_cnt = bdev->lg_bsize / bdev->ph_bsize; bdev->bwrite_ctr++; #if CONFIG_EXT4_READONLY return EOK; #else return bdev->bwrite(bdev, buf, pba, pb_cnt * cnt); #endif }
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; }
int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off, void *buf, uint32_t len) { uint64_t block_idx; uint64_t block_end; uint32_t blen; uint32_t unalg; int r = EOK; uint8_t *p = (void *)buf; ext4_assert(bdev && buf); if(!(bdev->flags & EXT4_BDEV_INITIALIZED)) return EIO; block_idx = off / bdev->ph_bsize; block_end = block_idx + len / bdev->ph_bsize; if(!(block_end < bdev->ph_bcnt)) return EINVAL; /*Ups. Out of range operation*/ /*OK lets deal with the first possible unaligned block*/ unalg = (off & (bdev->ph_bsize - 1)); if(unalg){ uint32_t rlen = (bdev->ph_bsize - unalg) > len ? len : (bdev->ph_bsize - unalg); r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1); if(r != EOK) return r; memcpy(p, bdev->ph_bbuf + unalg, rlen); p += rlen; len -= rlen; block_idx++; } /*Aligned data*/ blen = len / bdev->ph_bsize; r = bdev->bread(bdev, p, block_idx, blen); if(r != EOK) return r; p += bdev->ph_bsize * blen; len -= bdev->ph_bsize * blen; block_idx += blen; /*Rest of the data*/ if(len){ r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1); if(r != EOK) return r; memcpy(p, bdev->ph_bbuf, len); } return r; }
int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off, void *buf, uint32_t len) { uint64_t block_idx; uint32_t blen; uint32_t unalg; int r = EOK; uint8_t *p = (void *)buf; ext4_assert(bdev && buf); if (!bdev->bdif->ph_refctr) return EIO; if (off + len > bdev->part_size) return EINVAL; /*Ups. Out of range operation*/ block_idx = ((off + bdev->part_offset) / bdev->bdif->ph_bsize); /*OK lets deal with the first possible unaligned block*/ unalg = (off & (bdev->bdif->ph_bsize - 1)); if (unalg) { uint32_t rlen = (bdev->bdif->ph_bsize - unalg) > len ? len : (bdev->bdif->ph_bsize - unalg); r = ext4_bdif_bread(bdev, bdev->bdif->ph_bbuf, block_idx, 1); if (r != EOK) return r; memcpy(p, bdev->bdif->ph_bbuf + unalg, rlen); p += rlen; len -= rlen; block_idx++; } /*Aligned data*/ blen = len / bdev->bdif->ph_bsize; r = ext4_bdif_bread(bdev, p, block_idx, blen); if (r != EOK) return r; p += bdev->bdif->ph_bsize * blen; len -= bdev->bdif->ph_bsize * blen; block_idx += blen; /*Rest of the data*/ if (len) { r = ext4_bdif_bread(bdev, bdev->bdif->ph_bbuf, block_idx, 1); if (r != EOK) return r; memcpy(p, bdev->bdif->ph_bbuf, len); } return r; }