From 3601e21cd05e84de594569eb7c488f4d6444d957 Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Wed, 15 Feb 2012 21:24:33 +0100 Subject: [PATCH 79/84] lsbd: add queue, clean and write stats This patch adds detailed block clean and block write statistics. Signed-off-by: Krzysztof Mazur --- drivers/block/lsbd.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/drivers/block/lsbd.c b/drivers/block/lsbd.c index b9da2df..8e77350 100644 --- a/drivers/block/lsbd.c +++ b/drivers/block/lsbd.c @@ -83,6 +83,16 @@ struct lsbd_partition { unsigned int size; }; +struct lsbd_hist { + unsigned int clean; + unsigned int aclean; + + unsigned int rewrite; + unsigned int high; + unsigned int normal; + unsigned int total; +}; + struct lsbd { unsigned int id; kdev_t dev; @@ -112,6 +122,8 @@ struct lsbd { unsigned long queue_move_drop; unsigned long queue_move_skip; + struct lsbd_hist *hist; + rwlock_t lcache_lock; lsbd_lcache_t *lcache; unsigned int cur_lcache; @@ -1312,12 +1324,19 @@ static int lsbd_mount(struct lsbd *p) ret = lsbd_load_params(p); if (ret) return ret; + + p->hist = kmalloc(p->sectors_per_block * sizeof(*p->hist), + GFP_KERNEL); + if (p->hist == NULL) + return -ENOMEM; + memset(p->hist, 0, p->sectors_per_block * sizeof(*p->hist)); lsbd_check_sectors(p); lsbd_read_lcache(p); MOD_INC_USE_COUNT; ret = lsbd_start(p); if (ret) { + kfree(p->hist); MOD_DEC_USE_COUNT; return ret; } @@ -1539,6 +1558,7 @@ static int lsbd_ioctl(struct inode *inode, struct file *file, if (p->tsk != NULL) { lsbd_stop(p); lsbd_reset_dev(p); + kfree(p->hist); MOD_DEC_USE_COUNT; } @@ -2027,6 +2047,8 @@ static void lsbd_clean_block(struct lsbd *p) unsigned int ptab_offset; u32 ptab_checksum; int mirrored; + unsigned int clean_sectors = 0; + unsigned int aclean_sectors = 0; retry: block++; @@ -2106,9 +2128,14 @@ retry: "lcache %d\n", block, i, sector_id, s, sector); - if (lsbd_sector_eq(p, sector, s)) + clean_sectors++; + if (lsbd_sector_eq(p, sector, s)) { lsbd_rewrite_sector(p, block, i + 1, §s[i]); + aclean_sectors++; + } } + p->hist[clean_sectors].clean++; + p->hist[aclean_sectors].aclean++; brelse(bh); lsbd_put_buffer(p, bh); @@ -2307,6 +2334,10 @@ static int lsbd_write_block(struct lsbd *p) struct lsbd_request *r; unsigned int i; int mirrored = 0; + unsigned int hist_rewrite = 0; + unsigned int hist_normal = 0; + unsigned int hist_high = 0; + unsigned int hist_total = 0; p->cur_block++; if (p->cur_block >= p->blocks) @@ -2416,6 +2447,15 @@ static int lsbd_write_block(struct lsbd *p) r->bh = NULL; } wbh[i + 1] = r->bh; + + if (r->queue == LSBD_QUEUE_MOVE) + hist_rewrite++; + else if (r->queue == LSBD_QUEUE_HIGH) + hist_high++; + else if (r->queue == LSBD_QUEUE_NORMAL) + hist_normal++; + hist_total++; + kfree(r); if (!move) up(&p->req_sem); @@ -2425,6 +2465,11 @@ static int lsbd_write_block(struct lsbd *p) wbh[i + 1] = NULL; } } + + p->hist[hist_rewrite].rewrite++; + p->hist[hist_high].high++; + p->hist[hist_normal].normal++; + p->hist[hist_total].total++; b->ptab_checksum = cpu_to_be32(lsbd_checksum(bh[0]->b_data + be32_to_cpu(b->ptab_offset), (p->sectors_per_block - 1) @@ -2528,6 +2573,7 @@ static int lsbd_thread(void *data) for (;;) { DECLARE_WAITQUEUE(wait, current); int wq_len; + unsigned int clean_blocks; want_write = 0; want_clean = 0; @@ -2540,7 +2586,14 @@ static int lsbd_thread(void *data) want_write = 1; wq_len = p->wqueue_len; spin_unlock_irq(&p->wqueue_lock); - want_clean = (lsbd_clean_blocks(p) < LSBD_CLEAN_WINDOW); + + clean_blocks = lsbd_clean_blocks(p); + if (clean_blocks < LSBD_CLEAN_WINDOW) { + want_clean = 1; + } else if (clean_blocks < LSBD_CLEAN_HIGH) { + want_clean = wq_len < p->sectors_per_block - 1; + } + if (!(want_write || want_clean || p->stop)) schedule(); __set_current_state(TASK_RUNNING); @@ -2574,12 +2627,6 @@ static int lsbd_thread(void *data) for (i = 0; i < blocks; i++) lsbd_clean_block(p); - } else if (wq_len < p->sectors_per_block - 1) { - unsigned int blocks = p->mirrored ? 2 : 1; - - if (lsbd_clean_blocks(p) < LSBD_CLEAN_HIGH) - for (i = 0; i < blocks; i++) - lsbd_clean_block(p); } while (want_write && (lsbd_clean_blocks(p) > 1)) { @@ -2665,6 +2712,7 @@ static void lsbd_seq_stop(struct seq_file *seq, void *v) static int lsbd_seq_show(struct seq_file *seq, void *v) { struct lsbd *p = v; + unsigned int i; if (v == (void *) 1) { seq_printf(seq, "LSBD 0.0\n\n"); @@ -2689,6 +2737,21 @@ static int lsbd_seq_show(struct seq_file *seq, void *v) p->sectors_written, p->blocks_written); seq_printf(seq, " move: %ld %ld\n", p->queue_move_drop, p->queue_move_skip); + seq_printf(seq, " qlen: %d %d %d %d\n", + p->wqueue_qlen[LSBD_QUEUE_MOVE], + p->wqueue_qlen[LSBD_QUEUE_HIGH], + p->wqueue_qlen[LSBD_QUEUE_NORMAL], + p->wqueue_len); + for (i = 0; i < p->sectors_per_block; i++) + seq_printf(seq, " hist[%3d]: %7d %7d %7d %7d %7d %7d\n", + i, + p->hist[i].clean, + p->hist[i].aclean, + p->hist[i].rewrite, + p->hist[i].high, + p->hist[i].normal, + p->hist[i].total); + seq_printf(seq, " status: %s ( %ld %ld %ld )\n", lsbd_status(p), p->read_errors, p->uncorrectable, p->write_errors); -- 1.8.4.652.g0d6e0ce