Add 'lib_only' build target.
[lwext4.git] / lwext4 / ext4_blockdev.c
index 3af65104171bf0b3dd1d11daf646e989f81ea90c..23ad9ee3467368699090a6c921ad5186a3c17cab 100644 (file)
@@ -65,6 +65,7 @@ static int ext4_bdif_bread(struct ext4_blockdev *bdev, void *buf,
 {
        ext4_bdif_lock(bdev);
        int r = bdev->bdif->bread(bdev, buf, blk_id, blk_cnt);
+       bdev->bdif->bread_ctr++;
        ext4_bdif_unlock(bdev);
        return r;
 }
@@ -74,6 +75,7 @@ static int ext4_bdif_bwrite(struct ext4_blockdev *bdev, const void *buf,
 {
        ext4_bdif_lock(bdev);
        int r = bdev->bdif->bwrite(bdev, buf, blk_id, blk_cnt);
+       bdev->bdif->bwrite_ctr++;
        ext4_bdif_unlock(bdev);
        return r;
 }
@@ -116,7 +118,7 @@ void ext4_block_set_lb_size(struct ext4_blockdev *bdev, uint64_t lb_bsize)
        ext4_assert(!(lb_bsize % bdev->bdif->ph_bsize));
 
        bdev->lg_bsize = lb_bsize;
-       bdev->lg_bcnt = (bdev->bdif->ph_bcnt * bdev->bdif->ph_bsize) / lb_bsize;
+       bdev->lg_bcnt = bdev->part_size / lb_bsize;
 }
 
 int ext4_block_fini(struct ext4_blockdev *bdev)
@@ -138,46 +140,66 @@ int ext4_block_flush_buf(struct ext4_blockdev *bdev, struct ext4_buf *buf)
 {
        int r;
        struct ext4_bcache *bc = bdev->bc;
-       /*Only flushing unreferenced buffer is allowed.*/
-       ext4_assert(!buf->refctr);
 
-       if (ext4_bcache_test_flag(buf, BC_DIRTY)) {
+       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)
+                       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)
+               if (buf->end_write) {
+                       bc->dont_shake = true;
                        buf->end_write(bc, buf, r, buf->end_write_arg);
-
+                       bc->dont_shake = false;
+               }
        }
        return EOK;
 }
 
+int ext4_block_flush_lba(struct ext4_blockdev *bdev, uint64_t lba)
+{
+       int r = EOK;
+       struct ext4_buf *buf;
+       struct ext4_block b;
+       buf = ext4_bcache_find_get(bdev->bc, &b, lba);
+       if (buf) {
+               r = ext4_block_flush_buf(bdev, buf);
+               ext4_bcache_free(bdev->bc, &b);
+       }
+       return r;
+}
+
 int ext4_block_cache_shake(struct ext4_blockdev *bdev)
 {
+       int r = EOK;
        struct ext4_buf *buf;
+       if (bdev->bc->dont_shake)
+               return EOK;
+
        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)) {
-                       int r = ext4_block_flush_buf(bdev, buf);
+                       r = ext4_block_flush_buf(bdev, buf);
                        if (r != EOK)
-                               return r;
+                               break;
 
                }
 
                ext4_bcache_drop_buf(bdev->bc, buf);
        }
-       return EOK;
+       return r;
 }
 
 int ext4_block_get_noread(struct ext4_blockdev *bdev, struct ext4_block *b,
@@ -256,11 +278,9 @@ int ext4_blocks_get_direct(struct ext4_blockdev *bdev, void *buf, uint64_t lba,
 
        ext4_assert(bdev && buf);
 
-       pba = (lba * bdev->lg_bsize) / bdev->bdif->ph_bsize;
-       pba += bdev->ph_blk_offset;
+       pba = (lba * bdev->lg_bsize + bdev->part_offset) / bdev->bdif->ph_bsize;
        pb_cnt = bdev->lg_bsize / bdev->bdif->ph_bsize;
 
-       bdev->bread_ctr++;
        return ext4_bdif_bread(bdev, buf, pba, pb_cnt * cnt);
 }
 
@@ -272,11 +292,9 @@ int ext4_blocks_set_direct(struct ext4_blockdev *bdev, const void *buf,
 
        ext4_assert(bdev && buf);
 
-       pba = (lba * bdev->lg_bsize) / bdev->bdif->ph_bsize;
-       pba += bdev->ph_blk_offset;
+       pba = (lba * bdev->lg_bsize + bdev->part_offset) / bdev->bdif->ph_bsize;
        pb_cnt = bdev->lg_bsize / bdev->bdif->ph_bsize;
 
-       bdev->bwrite_ctr++;
        return ext4_bdif_bwrite(bdev, buf, pba, pb_cnt * cnt);
 }
 
@@ -284,7 +302,6 @@ int ext4_block_writebytes(struct ext4_blockdev *bdev, uint64_t off,
                          const void *buf, uint32_t len)
 {
        uint64_t block_idx;
-       uint64_t block_end;
        uint32_t blen;
        uint32_t unalg;
        int r = EOK;
@@ -296,12 +313,11 @@ int ext4_block_writebytes(struct ext4_blockdev *bdev, uint64_t off,
        if (!bdev->bdif->ph_refctr)
                return EIO;
 
-       block_idx = (off / bdev->bdif->ph_bsize) + bdev->ph_blk_offset;
-       block_end = block_idx + len / bdev->bdif->ph_bsize;
-
-       if (!(block_end < bdev->bdif->ph_bcnt))
+       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) {
@@ -354,7 +370,6 @@ 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;
@@ -366,12 +381,11 @@ int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off, void *buf,
        if (!bdev->bdif->ph_refctr)
                return EIO;
 
-       block_idx = (off / bdev->bdif->ph_bsize) + bdev->ph_blk_offset;
-       block_end = block_idx + len / bdev->bdif->ph_bsize;
-
-       if (!(block_end < bdev->bdif->ph_bcnt))
+       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) {
@@ -415,11 +429,22 @@ int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off, void *buf,
        return r;
 }
 
-int ext4_block_cache_write_back(struct ext4_blockdev *bdev, uint8_t on_off)
+int ext4_block_cache_flush(struct ext4_blockdev *bdev)
 {
-       int r;
-       struct ext4_buf *buf;
+       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_block_cache_write_back(struct ext4_blockdev *bdev, uint8_t on_off)
+{
        if (on_off)
                bdev->cache_write_back++;
 
@@ -429,17 +454,8 @@ int ext4_block_cache_write_back(struct ext4_blockdev *bdev, uint8_t on_off)
        if (bdev->cache_write_back)
                return EOK;
 
-       /*Flush all delayed cache blocks*/
-       while (!SLIST_EMPTY(&bdev->bc->dirty_list)) {
-
-               buf = SLIST_FIRST(&bdev->bc->dirty_list);
-               ext4_assert(buf);
-               r = ext4_block_flush_buf(bdev, buf);
-               if (r != EOK)
-                       return r;
-
-       }
-       return EOK;
+       /*Flush data in all delayed cache blocks*/
+       return ext4_block_cache_flush(bdev);
 }
 
 /**