Add stats

In /sys/fs/compress/device-name:
	lblk_size,
	pblk_used/total,
	lblk_used/total,
	pbat_r/w,
	lbatpblk_r/w,
	lbd_r/w
This commit is contained in:
Tom Marshall 2019-11-11 14:58:09 -08:00
parent c4aabad212
commit e70d283921
6 changed files with 232 additions and 15 deletions

View File

@ -52,6 +52,9 @@ struct compress
{
struct dm_dev* dev;
struct kobject kobj;
struct completion kobj_unregister;
struct compress_params kparams;
struct compress_stats kstats;
struct lbdcache* lc;
@ -59,6 +62,8 @@ struct compress
struct workqueue_struct* io_workq;
};
static struct kobject* compress_kobj;
static inline u64
blkdev_pblk_size(struct block_device *bdev)
{
@ -91,7 +96,6 @@ compress_read_header(struct compress* c)
pblkbuf = page_address(pblkpage);
iopagev[0] = pblkpage;
c->kparams.dev = c->dev->bdev;
ret = pblk_read_wait(&c->kparams, 0, 1, iopagev);
if (ret) {
printk(KERN_ERR "%s: failed to read header\n", __func__);
@ -155,6 +159,9 @@ compress_read_header(struct compress* c)
printk(KERN_INFO " nr_pblk=%lu\n", (unsigned long)header.params.nr_pblk);
printk(KERN_INFO " nr_zones=%u\n", (unsigned int)header.params.nr_zones);
printk(KERN_INFO " lblk_per_zone=%u\n", (unsigned int)header.params.lblk_per_zone);
printk(KERN_INFO "%s: stats...\n", __func__);
printk(KERN_INFO " pblk_used=%lu\n", (unsigned long)header.stats.pblk_alloc);
printk(KERN_INFO " lblk_used=%lu\n", (unsigned long)header.stats.lblk_alloc);
memcpy(&c->kparams.params, &header.params, sizeof(header.params));
memcpy(&c->kstats.stats, &header.stats, sizeof(header.stats));
@ -285,6 +292,158 @@ compress_io_work(struct work_struct* work)
}
#endif
/*** sysfs stuff ***/
typedef enum {
attr_lblk_size,
attr_pblk_used,
attr_pblk_total,
attr_lblk_used,
attr_lblk_total,
attr_pbat_r,
attr_pbat_w,
attr_lbatpblk_r,
attr_lbatpblk_w,
attr_lbd_r,
attr_lbd_w,
} attr_id_t;
struct compress_attr {
struct attribute attr;
short attr_id;
};
static ssize_t
compress_attr_show(struct kobject* kobj, struct attribute* attr,
char* buf)
{
struct compress* c = container_of(kobj, struct compress, kobj);
struct compress_attr* a = container_of(attr, struct compress_attr, attr);
u64 val = 0;
mutex_lock(&c->kstats.lock);
switch (a->attr_id) {
case attr_lblk_size:
val = PBLK_SIZE * lblk_per_pblk(&c->kparams.params);
break;
case attr_pblk_used:
val = c->kstats.stats.pblk_alloc;
break;
case attr_pblk_total:
val = pbat_len(&c->kparams.params) * PBLK_SIZE_BITS *
c->kparams.params.nr_zones;
break;
case attr_lblk_used:
val = c->kstats.stats.lblk_alloc;
break;
case attr_lblk_total:
val = c->kparams.params.lblk_per_zone *
c->kparams.params.nr_zones;
break;
case attr_pbat_r:
val = c->kstats.pbat_r;
break;
case attr_pbat_w:
val = c->kstats.pbat_w;
break;
case attr_lbatpblk_r:
val = c->kstats.lbatpblk_r;
break;
case attr_lbatpblk_w:
val = c->kstats.lbatpblk_w;
break;
case attr_lbd_r:
val = c->kstats.lbd_r;
break;
case attr_lbd_w:
val = c->kstats.lbd_w;
break;
}
mutex_unlock(&c->kstats.lock);
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)val);
}
#define COMPRESS_ATTR(_name,_mode,_id) \
static struct compress_attr compress_attr_##_name = { \
.attr = { .name = __stringify(_name), .mode = _mode }, \
.attr_id = attr_##_id, \
}
#define COMPRESS_ATTR_FUNC(_name,_mode) COMPRESS_ATTR(_name, _mode, _name)
COMPRESS_ATTR_FUNC(lblk_size, 0444);
COMPRESS_ATTR_FUNC(pblk_used, 0444);
COMPRESS_ATTR_FUNC(pblk_total, 0444);
COMPRESS_ATTR_FUNC(lblk_used, 0444);
COMPRESS_ATTR_FUNC(lblk_total, 0444);
COMPRESS_ATTR_FUNC(pbat_r, 0444);
COMPRESS_ATTR_FUNC(pbat_w, 0444);
COMPRESS_ATTR_FUNC(lbatpblk_r, 0444);
COMPRESS_ATTR_FUNC(lbatpblk_w, 0444);
COMPRESS_ATTR_FUNC(lbd_r, 0444);
COMPRESS_ATTR_FUNC(lbd_w, 0444);
#define ATTR_LIST(name) &compress_attr_##name.attr
static struct attribute* compress_attrs[] = {
ATTR_LIST(lblk_size),
ATTR_LIST(pblk_used),
ATTR_LIST(pblk_total),
ATTR_LIST(lblk_used),
ATTR_LIST(lblk_total),
ATTR_LIST(pbat_r),
ATTR_LIST(pbat_w),
ATTR_LIST(lbatpblk_r),
ATTR_LIST(lbatpblk_w),
ATTR_LIST(lbd_r),
ATTR_LIST(lbd_w),
NULL
};
#undef ATTR_LIST
static void
compress_sysfs_release(struct kobject* kobj)
{
struct compress* c = container_of(kobj, struct compress, kobj);
complete(&c->kobj_unregister);
}
static const struct sysfs_ops compress_attr_ops = {
.show = compress_attr_show,
};
static struct kobj_type compress_ktype = {
.default_attrs = compress_attrs,
.sysfs_ops = &compress_attr_ops,
.release = compress_sysfs_release,
};
static int
compress_register_sysfs(struct compress* c)
{
int err;
char name[32];
snprintf(name, sizeof(name), "%pg", c->dev->bdev);
init_completion(&c->kobj_unregister);
err = kobject_init_and_add(&c->kobj, &compress_ktype, compress_kobj, "%s", name);
if (err) {
kobject_put(&c->kobj);
wait_for_completion(&c->kobj_unregister);
}
return err;
}
static void
compress_unregister_sysfs(struct compress* c)
{
kobject_del(&c->kobj);
}
/*
* Usage:
* echo "<start_sector> <end_sector> compress <backing_device> <args...>" | dmsetup create <compress_name>
@ -363,13 +522,20 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = c;
backing_nr_pblks = blkdev_pblk_size(c->dev->bdev);
if ((backing_nr_pblks >> 48) != 0) {
ti->error = "Device too large";
ret = -EINVAL;
goto err;
}
ret = compress_register_sysfs(c);
if (ret) {
ti->error = "Failed to register sysfs";
goto err;
}
c->kparams.dev = c->dev->bdev;
mutex_init(&c->kstats.lock);
if (!cache_pages) {
/* Minimum of 1/1k RAM and 1/64k device size */
cache_pages = min((unsigned int)(totalram_pages >> 10),
@ -465,6 +631,7 @@ compress_dtr(struct dm_target *ti)
if (c->io_workq) {
destroy_workqueue(c->io_workq);
}
compress_unregister_sysfs(c);
dm_put_device(ti, c->dev);
kfree(c);
}
@ -518,6 +685,13 @@ static int __init
dm_compress_init(void)
{
int res;
compress_kobj = kobject_create_and_add("compress", fs_kobj);
if (!compress_kobj) {
printk(KERN_ERR "Failed to add sysfs kobj\n");
return -ENOMEM;
}
res = dm_register_target(&compress_target);
if (res < 0) {
printk(KERN_ERR "Failed to register dm-compress: %d\n", res);
@ -530,6 +704,11 @@ static void __exit
dm_compress_exit(void)
{
dm_unregister_target(&compress_target);
if (compress_kobj) {
kobject_put(compress_kobj);
compress_kobj = NULL;
}
}
module_init(dm_compress_init);

View File

@ -37,13 +37,16 @@ struct lbatpblk {
struct mutex lock;
struct compress_params* kparams;
struct compress_stats* kstats;
struct page* page;
u8* buf;
bool dirty;
};
static bool
lbatpblk_ctr(struct lbatpblk* lp, struct compress_params* kparams)
lbatpblk_ctr(struct lbatpblk* lp,
struct compress_params* kparams,
struct compress_stats* kstats)
{
memset(lp, 0, sizeof(struct lbatpblk));
INIT_LIST_HEAD(&lp->list);
@ -52,6 +55,7 @@ lbatpblk_ctr(struct lbatpblk* lp, struct compress_params* kparams)
lp->ref = 0;
mutex_init(&lp->lock);
lp->kparams = kparams;
lp->kstats = kstats;
lp->page = cbd_alloc_page();
if (!lp->page) {
return false;
@ -93,6 +97,9 @@ lbatpblk_flush(struct lbatpblk* lp)
iopagev[0] = lp->page;
pblk_write(lp->kparams, lp->pblk, 1, iopagev);
mutex_unlock(&lp->lock);
mutex_lock(&lp->kstats->lock);
++lp->kstats->lbatpblk_w;
mutex_unlock(&lp->kstats->lock);
return ret;
@ -111,6 +118,9 @@ lbatpblk_read(struct lbatpblk* lp)
pagev[0] = lp->page;
ret = pblk_read_wait(lp->kparams, lp->pblk, 1, pagev);
mutex_lock(&lp->kstats->lock);
++lp->kstats->lbatpblk_r;
mutex_unlock(&lp->kstats->lock);
return ret;
}
@ -166,7 +176,8 @@ lbatpblkcache_size(void)
bool
lbatpblkcache_ctr(struct lbatpblkcache* lpc,
struct compress_params* kparams, u32 cache_pages)
struct compress_params* kparams, struct compress_stats* kstats,
u32 cache_pages)
{
struct lbatpblk* cache;
u32 cache_len;
@ -190,7 +201,7 @@ lbatpblkcache_ctr(struct lbatpblkcache* lpc,
lpc->cache_len = cache_len;
lpc->cache = cache;
for (n = 0; n < cache_len; ++n) {
if (!lbatpblk_ctr(&cache[n], kparams)) {
if (!lbatpblk_ctr(&cache[n], kparams, kstats)) {
return false;
}
list_add_tail(&cache[n].list, &lpc->cache_head);

View File

@ -464,7 +464,7 @@ lbatviewcache_size(void)
bool
lbatviewcache_ctr(struct lbatviewcache* lvc,
struct compress_params* kparams, struct compress_stats* stats,
struct compress_params* kparams, struct compress_stats* kstats,
u32 cache_pages)
{
struct lbatview* cache;
@ -477,14 +477,14 @@ lbatviewcache_ctr(struct lbatviewcache* lvc,
if (!lvc->pc) {
return false;
}
if (!pbatcache_ctr(lvc->pc, kparams, cache_pages)) {
if (!pbatcache_ctr(lvc->pc, kparams, kstats, cache_pages)) {
return false;
}
lvc->lpc = kmalloc(lbatpblkcache_size(), GFP_KERNEL);
if (!lvc->lpc) {
return false;
}
if (!lbatpblkcache_ctr(lvc->lpc, kparams, cache_pages)) {
if (!lbatpblkcache_ctr(lvc->lpc, kparams, kstats, cache_pages)) {
return false;
}
/* lbatviewcache gets one entry per lbatpblk (XXX: 5/6?) */
@ -503,7 +503,7 @@ lbatviewcache_ctr(struct lbatviewcache* lvc,
lvc->cache_len = cache_len;
lvc->cache = cache;
for (n = 0; n < cache_len; ++n) {
if (!lbatview_ctr(&cache[n], kparams, stats, lvc->pc, lvc->lpc)) {
if (!lbatview_ctr(&cache[n], kparams, kstats, lvc->pc, lvc->lpc)) {
return false;
}
list_add_tail(&cache[n].list, &lvc->cache_head);

View File

@ -40,6 +40,7 @@ struct lbd {
struct mutex lock;
struct compress_params* kparams;
struct compress_stats* kstats;
struct lbatviewcache* lvc;
struct lbatview* lv;
void* percpu;
@ -251,6 +252,7 @@ lblk_decompress(struct lbd* lbd)
static bool
lbd_ctr(struct lbd* lbd,
struct compress_params* kparams,
struct compress_stats* kstats,
struct lbatviewcache* lvc,
void* percpu)
{
@ -265,6 +267,7 @@ lbd_ctr(struct lbd* lbd,
lbd->ref = 0;
mutex_init(&lbd->lock);
lbd->kparams = kparams;
lbd->kstats = kstats;
lbd->lvc = lvc;
lbd->lv = NULL;
lbd->percpu = percpu;
@ -357,6 +360,9 @@ lbd_flush(struct lbd* lbd)
iopagev[0] = lbd->pagev[n];
pblk_write(lbd->kparams, pblk, 1, iopagev);
}
mutex_lock(&lbd->kstats->lock);
++lbd->kstats->lbd_w;
mutex_unlock(&lbd->kstats->lock);
while (n < lblk_per_pblk(&lbd->kparams->params)) {
unlock_page(lbd->pagev[n]);
++n;
@ -422,6 +428,9 @@ lbd_read(struct lbd* lbd)
}
}
lbd->c_len = CBD_UNCOMPRESSED;
mutex_lock(&lbd->kstats->lock);
++lbd->kstats->lbd_r;
mutex_unlock(&lbd->kstats->lock);
out:
return ret;
@ -644,7 +653,7 @@ lbdcache_ctr(struct lbdcache* lc,
lc->cache_len = cache_len;
lc->cache = cache;
for (n = 0; n < cache_len; ++n) {
if (!lbd_ctr(&cache[n], kparams, lc->lvc, lc->percpu)) {
if (!lbd_ctr(&cache[n], kparams, kstats, lc->lvc, lc->percpu)) {
return false;
}
list_add_tail(&cache[n].lru_list, &lc->cache_head);

View File

@ -37,6 +37,7 @@ struct pbat {
struct mutex lock;
struct compress_params* kparams;
struct compress_stats* kstats;
bool full;
u32 last_alloc;
struct page** pagev;
@ -45,7 +46,8 @@ struct pbat {
static bool
pbat_ctr(struct pbat* pbat,
struct compress_params* kparams)
struct compress_params* kparams,
struct compress_stats* kstats)
{
u32 nr_pages = pbat_len(&kparams->params);
@ -56,6 +58,7 @@ pbat_ctr(struct pbat* pbat,
pbat->ref = 0;
mutex_init(&pbat->lock);
pbat->kparams = kparams;
pbat->kstats = kstats;
pbat->full = false;
pbat->last_alloc = 0;
pbat->pagev = kzalloc(nr_pages * sizeof(struct page*), GFP_KERNEL);
@ -121,6 +124,9 @@ pbat_flush(struct pbat* pbat)
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
pblk_write(pbat->kparams, pblk, nr_pages, pbat->pagev);
mutex_unlock(&pbat->lock);
mutex_lock(&pbat->kstats->lock);
++pbat->kstats->pbat_w;
mutex_unlock(&pbat->kstats->lock);
return ret;
@ -146,6 +152,9 @@ pbat_read(struct pbat* pbat)
}
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
ret = pblk_read_wait(pbat->kparams, pblk, nr_pages, pbat->pagev);
mutex_lock(&pbat->kstats->lock);
++pbat->kstats->pbat_r;
mutex_unlock(&pbat->kstats->lock);
return ret;
}
@ -250,7 +259,8 @@ pbatcache_size(void)
bool
pbatcache_ctr(struct pbatcache* pc,
struct compress_params* kparams, u32 cache_pages)
struct compress_params* kparams, struct compress_stats* kstats,
u32 cache_pages)
{
struct pbat* cache;
u32 cache_len;
@ -274,7 +284,7 @@ pbatcache_ctr(struct pbatcache* pc,
pc->cache_len = cache_len;
pc->cache = cache;
for (n = 0; n < cache_len; ++n) {
if (!pbat_ctr(&cache[n], kparams)) {
if (!pbat_ctr(&cache[n], kparams, kstats)) {
return false;
}
list_add_tail(&cache[n].list, &pc->cache_head);

View File

@ -519,6 +519,12 @@ struct compress_params {
struct compress_stats {
struct mutex lock;
struct cbd_stats stats;
u64 pbat_r;
u64 pbat_w;
u64 lbatpblk_r;
u64 lbatpblk_w;
u64 lbd_r;
u64 lbd_w;
};
typedef void (*pblk_endio_t)(struct bio*);
@ -551,7 +557,8 @@ int pbat_free(struct pbat* pbat, u64 pblk);
struct pbatcache;
size_t pbatcache_size(void);
bool pbatcache_ctr(struct pbatcache* pbatcache,
struct compress_params* kparams, u32 cache_pages);
struct compress_params* kparams, struct compress_stats* kstats,
u32 cache_pages);
void pbatcache_dtr(struct pbatcache* pbatcache);
struct pbat*
pbatcache_get(struct pbatcache* pbatcache, u32 zone, bool avail);
@ -565,7 +572,8 @@ void lbatpblk_put_buf(struct lbatpblk* lp);
struct lbatpblkcache;
size_t lbatpblkcache_size(void);
bool lbatpblkcache_ctr(struct lbatpblkcache* lpc,
struct compress_params* kparams, u32 cache_pages);
struct compress_params* kparams, struct compress_stats* kstats,
u32 cache_pages);
void lbatpblkcache_dtr(struct lbatpblkcache* lpc);
struct lbatpblk*
lbatpblkcache_get(struct lbatpblkcache* lpc, u64 pblk);