diff --git a/dm-compress/lbatview.c b/dm-compress/lbatview.c index 93c3e09..cc37e00 100644 --- a/dm-compress/lbatview.c +++ b/dm-compress/lbatview.c @@ -149,58 +149,62 @@ lbatview_alloc_pblk(struct lbatview* lv) u32 zone_off; struct pbat* pbat; - if (!lv->pbat) { - lv->pbat = pbatcache_get(lv->pbatcache, zone); - if (!lv->pbat) { - printk(KERN_ERR "%s: pbatcache_get failed\n", __func__); + if (lv->pbat) { + pblk = pbat_alloc(lv->pbat); + if (pblk != PBLK_NONE) { + return pblk; + } + ret = pbatcache_put(lv->pbatcache, lv->pbat); + lv->pbat = NULL; + if (ret) { + printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); return PBLK_NONE; } } - pblk = pbat_alloc(lv->pbat); - if (pblk != PBLK_NONE) { - return pblk; - } - ret = pbatcache_put(lv->pbatcache, lv->pbat); - lv->pbat = NULL; - if (ret) { - printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); - return PBLK_NONE; + pbat = pbatcache_get(lv->pbatcache, zone, true); + if (pbat) { + pblk = pbat_alloc(pbat); + if (pblk != PBLK_NONE) { + lv->pbat = pbat; + return pblk; + } + ret = pbatcache_put(lv->pbatcache, pbat); + if (ret) { + printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); + return PBLK_NONE; + } } for (zone_off = 1; zone_off <= zone || zone + zone_off < lv->params->nr_zones; ++zone_off) { if (zone_off <= zone) { - pbat = pbatcache_get(lv->pbatcache, zone - zone_off); - if (!pbat) { - printk(KERN_ERR "%s: pbatcache_get failed\n", __func__); - return PBLK_NONE; - } - pblk = pbat_alloc(pbat); - if (pblk != PBLK_NONE) { - lv->pbat = pbat; - return pblk; - } - ret = pbatcache_put(lv->pbatcache, pbat); - if (ret) { - printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); - return PBLK_NONE; + pbat = pbatcache_get(lv->pbatcache, zone - zone_off, true); + if (pbat) { + pblk = pbat_alloc(pbat); + if (pblk != PBLK_NONE) { + lv->pbat = pbat; + return pblk; + } + ret = pbatcache_put(lv->pbatcache, pbat); + if (ret) { + printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); + return PBLK_NONE; + } } } if (zone + zone_off < lv->params->nr_zones) { - pbat = pbatcache_get(lv->pbatcache, zone + zone_off); - if (!pbat) { - printk(KERN_ERR "%s: pbatcache_get failed\n", __func__); - return PBLK_NONE; - } - pblk = pbat_alloc(pbat); - if (pblk != PBLK_NONE) { - lv->pbat = pbat; - return pblk; - } - ret = pbatcache_put(lv->pbatcache, pbat); - if (ret) { - printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); - return PBLK_NONE; + pbat = pbatcache_get(lv->pbatcache, zone + zone_off, true); + if (pbat) { + pblk = pbat_alloc(pbat); + if (pblk != PBLK_NONE) { + lv->pbat = pbat; + return pblk; + } + ret = pbatcache_put(lv->pbatcache, pbat); + if (ret) { + printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); + return PBLK_NONE; + } } } } @@ -222,7 +226,7 @@ lbatview_free_pblk(struct lbatview* lv, u64 pblk) printk(KERN_ERR "%s: pblk=%lu: zone out of bounds\n", __func__, (unsigned long)pblk); return -EINVAL; } - pbat = pbatcache_get(lv->pbatcache, pblk_zone); + pbat = pbatcache_get(lv->pbatcache, pblk_zone, false); if (!pbat) { printk(KERN_ERR "%s: pbatcache_get failed\n", __func__); return -EINVAL; diff --git a/dm-compress/pbat.c b/dm-compress/pbat.c index 44a3ce3..036d643 100644 --- a/dm-compress/pbat.c +++ b/dm-compress/pbat.c @@ -233,6 +233,7 @@ struct pbatcache { struct list_head cache_head; unsigned int cache_len; struct pbat* cache; + u8* full; }; size_t @@ -273,6 +274,7 @@ pbatcache_ctr(struct pbatcache* pc, } list_add_tail(&cache[n].list, &pc->cache_head); } + pc->full = kzalloc(DIV_ROUND_UP(params->nr_zones, BITS_PER_BYTE), GFP_KERNEL); return true; } @@ -283,6 +285,7 @@ pbatcache_dtr(struct pbatcache* pc) unsigned int n; struct pbat* pbat; + kfree(pc->full); for (n = 0; n < pc->cache_len; ++n) { pbat = &pc->cache[n]; if (!pbat) { @@ -301,11 +304,15 @@ pbatcache_dtr(struct pbatcache* pc) } struct pbat* -pbatcache_get(struct pbatcache* pc, u32 zone) +pbatcache_get(struct pbatcache* pc, u32 zone, bool avail) { struct pbat* pbat; mutex_lock(&pc->lock); + if (avail && cbd_bitmap_isset(pc->full, zone)) { + mutex_unlock(&pc->lock); + return NULL; + } list_for_each_entry(pbat, &pc->cache_head, list) { mutex_lock(&pbat->reflock); if (pbat->zone == zone) { @@ -362,6 +369,12 @@ pbatcache_put(struct pbatcache* pc, struct pbat* pbat) if (ret) { printk(KERN_ERR "%s: pbat_flush failed\n", __func__); } + if (pbat->full) { + cbd_bitmap_set(pc->full, pbat->zone); + } + else { + cbd_bitmap_reset(pc->full, pbat->zone); + } } mutex_unlock(&pbat->reflock); diff --git a/include/linux/dm-compress.h b/include/linux/dm-compress.h index 0507873..8e1b2c0 100644 --- a/include/linux/dm-compress.h +++ b/include/linux/dm-compress.h @@ -206,6 +206,33 @@ cbd_bitmap_free(u8* buf, u32 idx) buf[off] &= ~(1 << bit); } +static inline void +cbd_bitmap_set(u8* buf, u32 idx) +{ + u32 off = idx / BITS_PER_BYTE; + u32 bit = idx % BITS_PER_BYTE; + + buf[off] |= (1 << bit); +} + +static inline void +cbd_bitmap_reset(u8* buf, u32 idx) +{ + u32 off = idx / BITS_PER_BYTE; + u32 bit = idx % BITS_PER_BYTE; + + buf[off] &= ~(1 << bit); +} + +static inline bool +cbd_bitmap_isset(u8* buf, u32 idx) +{ + u32 off = idx / BITS_PER_BYTE; + u32 bit = idx % BITS_PER_BYTE; + + return buf[off] & (1 << bit); +} + static inline u32 @@ -512,7 +539,7 @@ bool pbatcache_ctr(struct pbatcache* pbatcache, struct cbd_params* params, u32 cache_pages); void pbatcache_dtr(struct pbatcache* pbatcache); struct pbat* - pbatcache_get(struct pbatcache* pbatcache, u32 zone); + pbatcache_get(struct pbatcache* pbatcache, u32 zone, bool avail); int pbatcache_put(struct pbatcache* pbatcache, struct pbat* pbat);