Minimize the amount of pbat reading to find free pblks

* Keep track of full pbats.
 * Allow specifying whether pbat must be non-full in pbatcache_get().
This commit is contained in:
Tom Marshall 2019-11-06 14:58:04 -08:00
parent a2e4f303fd
commit 68956f70e8
3 changed files with 88 additions and 44 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);