This statistical information contains general information about all kio requests for the last STAT_TIMER_PERIOD time. Made by analogy with /.vstorage.info/iostat statistics of user-mod client.
example: read 109 445645 26415104 4096 4096 4096 write 0 0 0 0 0 0 sync 0 0 Signed-off-by: Pavel Butsykin <pbutsy...@virtuozzo.com> --- fs/fuse/kio/pcs/fuse_stat.c | 183 +++++++++++++++++++++++++++++++++++++++++++- fs/fuse/kio/pcs/fuse_stat.h | 30 +++++++- fs/fuse/kio/pcs/pcs_map.c | 1 + 3 files changed, 209 insertions(+), 5 deletions(-) diff --git a/fs/fuse/kio/pcs/fuse_stat.c b/fs/fuse/kio/pcs/fuse_stat.c index da8428ebe600..aa8e70fc9fd6 100644 --- a/fs/fuse/kio/pcs/fuse_stat.c +++ b/fs/fuse/kio/pcs/fuse_stat.c @@ -1,11 +1,169 @@ #include <net/sock.h> #include <linux/types.h> +#include "pcs_req.h" #include "fuse_stat.h" #include "pcs_cluster.h" extern struct super_block *fuse_control_sb; + +static inline void fuse_val_stat_update(struct fuse_val_stat *s, u64 val) +{ + if (!s->events) + s->val_min = s->val_max = val; + else if (val < s->val_min) + s->val_min = val; + else if (val > s->val_max) + s->val_max = val; + s->val_total += val; + ++s->events; +} + +static inline void fuse_val_cnt_up(struct fuse_val_cnt *c) +{ + if (!c->glob.events) { + c->glob = c->curr; + } else { + c->glob.val_min = min(c->curr.val_min, c->glob.val_min); + c->glob.val_max = max(c->curr.val_max, c->glob.val_max); + c->glob.val_total = c->curr.val_total + c->glob.val_total; + c->glob.events = c->curr.events + c->glob.events; + } + c->last = c->curr; + memset(&c->curr, 0, sizeof(c->curr)); +} + +static inline unsigned long long fuse_evt_rate(struct fuse_val_stat const* s, unsigned period) +{ + return DIV_ROUND_UP(s->events, period); +} + +static inline unsigned long long fuse_val_rate(struct fuse_val_stat const* s, unsigned period) +{ + return DIV_ROUND_UP(s->val_total, period); +} + +static inline unsigned long long fuse_val_aver(struct fuse_val_stat const* s) +{ + return s->events ? s->val_total / s->events : 0; +} + +static inline unsigned long long fuse_val_cnt_total(struct fuse_val_cnt const* c) +{ + return c->curr.val_total + c->glob.val_total; +} + +static inline unsigned long long fuse_val_cnt_events(struct fuse_val_cnt const* c) +{ + return c->curr.events + c->glob.events; +} + +#define EVT_RATE(s) fuse_evt_rate(&(s), STAT_TIMER_PERIOD) +#define VAL_RATE(s) fuse_val_rate(&(s), STAT_TIMER_PERIOD) +#define VAL_AVER(s) fuse_val_aver(&(s)) +#define CNT_TOTAL(c) fuse_val_cnt_total(&(c)) +#define CNT_EVENTS(c) fuse_val_cnt_events(&(c)) + +static int pcs_fuse_iostat_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct pcs_fuse_stat *stat; + struct pcs_fuse_io_stat io_stat; + + if (!inode) + return 0; + + mutex_lock(&fuse_mutex); + stat = inode->i_private; + if (!stat) { + mutex_unlock(&fuse_mutex); + return 0; + } + + seq_printf(m, "# operation ops/sec bytes/sec total req_min req_avg req_max (bytes)\n"); + + spin_lock(&stat->lock); + io_stat = stat->io; + spin_unlock(&stat->lock); + + seq_printf(m, "read %-8llu %-11llu %-16llu %-6llu %-6llu %-6llu\n", + EVT_RATE(io_stat.read_bytes.last), VAL_RATE(io_stat.read_bytes.last), + CNT_TOTAL(io_stat.read_bytes), io_stat.read_bytes.last.val_min, + VAL_AVER(io_stat.read_bytes.last), io_stat.read_bytes.last.val_max); + seq_printf(m, "write %-8llu %-11llu %-16llu %-6llu %-6llu %-6llu\n", + EVT_RATE(io_stat.write_bytes.last), VAL_RATE(io_stat.write_bytes.last), + CNT_TOTAL(io_stat.write_bytes), io_stat.write_bytes.last.val_min, + VAL_AVER(io_stat.write_bytes.last), io_stat.write_bytes.last.val_max); + seq_printf(m, "sync %-8llu %-16llu\n", + EVT_RATE(io_stat.flush_cnt.last), CNT_EVENTS(io_stat.flush_cnt)); + mutex_unlock(&fuse_mutex); + + return 0; +} + +static int pcs_fuse_iostat_open(struct inode *inode, struct file *file) +{ + return single_open(file, pcs_fuse_iostat_show, inode); +} + +static const struct file_operations pcs_fuse_iostat_ops = { + .owner = THIS_MODULE, + .open = pcs_fuse_iostat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline +struct fuse_val_cnt *req_stat_entry(struct pcs_fuse_io_stat *io, u32 type) +{ + switch (type) { + case PCS_CS_READ_RESP: + return &io->read_bytes; + case PCS_CS_WRITE_SYNC_RESP: + case PCS_CS_WRITE_RESP: + return &io->write_bytes; + case PCS_CS_SYNC_RESP: + return &io->flush_cnt; + default: + break; + } + WARN_ON_ONCE(1); + return NULL; +} + +void pcs_fuse_stat_io_count(struct pcs_int_request *ireq, struct pcs_msg *resp) +{ + struct pcs_cluster_core *cc = ireq->cc; + struct pcs_fuse_stat *stat = &cc->stat; + struct pcs_cs_iohdr *h = (struct pcs_cs_iohdr *)msg_inline_head(resp); + struct fuse_val_cnt *se = req_stat_entry(&stat->io, h->hdr.type); + u64 size = h->hdr.type != PCS_CS_SYNC_RESP ? ireq->iochunk.size : 0; + + if (unlikely(!se)) + return; + + spin_lock(&stat->lock); + fuse_val_stat_update(&se->curr, size); + spin_unlock(&stat->lock); +} + +static void pcs_fuse_stat_work(struct work_struct *w) +{ + struct pcs_cluster_core *cc = + container_of(w, struct pcs_cluster_core, stat.work.work); + struct pcs_fuse_stat *stat = &cc->stat; + + spin_lock(&stat->lock); + fuse_val_cnt_up(&stat->io.read_bytes); + fuse_val_cnt_up(&stat->io.write_bytes); + fuse_val_cnt_up(&stat->io.flush_cnt); + spin_unlock(&stat->lock); + + mod_delayed_work(cc->wq, &cc->stat.work, STAT_TIMER_PERIOD * HZ); +} + static struct dentry *fuse_kio_add_dentry(struct dentry *parent, struct fuse_conn *fc, const char *name, @@ -50,8 +208,9 @@ static void fuse_kio_rm_dentry(struct dentry *dentry) void pcs_fuse_stat_init(struct pcs_fuse_stat *stat) { - struct fuse_conn *fc = - container_of(stat, struct pcs_fuse_cluster, cc.stat)->fc; + struct pcs_cluster_core *cc = + container_of(stat, struct pcs_cluster_core, stat); + struct fuse_conn *fc = container_of(cc,struct pcs_fuse_cluster, cc)->fc; mutex_lock(&fuse_mutex); if (!fuse_control_sb) @@ -66,7 +225,18 @@ void pcs_fuse_stat_init(struct pcs_fuse_stat *stat) goto out; } - /* Stat initialize */ + memset(&stat->io.read_bytes, 0, sizeof(stat->io.read_bytes)); + memset(&stat->io.write_bytes, 0, sizeof(stat->io.write_bytes)); + memset(&stat->io.flush_cnt, 0, sizeof(stat->io.flush_cnt)); + + spin_lock_init(&stat->lock); + INIT_DELAYED_WORK(&stat->work, pcs_fuse_stat_work); + mod_delayed_work(cc->wq, &stat->work, STAT_TIMER_PERIOD * HZ); + + stat->iostat = fuse_kio_add_dentry(stat->kio_stat, fc, "iostat", + S_IFREG | S_IRUSR, 1, NULL, + &pcs_fuse_iostat_ops, stat); + out: mutex_unlock(&fuse_mutex); } @@ -77,7 +247,12 @@ void pcs_fuse_stat_fini(struct pcs_fuse_stat *stat) return; mutex_lock(&fuse_mutex); - if (fuse_control_sb) + if (fuse_control_sb) { + if (stat->iostat) + fuse_kio_rm_dentry(stat->iostat); fuse_kio_rm_dentry(stat->kio_stat); + } mutex_unlock(&fuse_mutex); + + cancel_delayed_work_sync(&stat->work); } diff --git a/fs/fuse/kio/pcs/fuse_stat.h b/fs/fuse/kio/pcs/fuse_stat.h index 14687ffd83f2..d25a4c2c4bd7 100644 --- a/fs/fuse/kio/pcs/fuse_stat.h +++ b/fs/fuse/kio/pcs/fuse_stat.h @@ -1,11 +1,39 @@ #ifndef _FUSE_STAT_H_ #define _FUSE_STAT_H_ 1 +#define STAT_TIMER_PERIOD 5 + +struct fuse_val_stat { + u64 events; + u64 val_total; + u64 val_min; + u64 val_max; +}; + +struct fuse_val_cnt { + struct fuse_val_stat curr; + struct fuse_val_stat last; + struct fuse_val_stat glob; +}; + +struct pcs_fuse_io_stat { + struct fuse_val_cnt read_bytes; + struct fuse_val_cnt write_bytes; + struct fuse_val_cnt flush_cnt; +}; + struct pcs_fuse_stat { + struct pcs_fuse_io_stat io; + struct delayed_work work; + spinlock_t lock; + struct dentry *kio_stat; + struct dentry *iostat; }; void pcs_fuse_stat_init(struct pcs_fuse_stat *stat); void pcs_fuse_stat_fini(struct pcs_fuse_stat *stat); -#endif /* _FUSE_STAT_H_ */ \ No newline at end of file +void pcs_fuse_stat_io_count(struct pcs_int_request *ireq, struct pcs_msg *resp); + +#endif /* _FUSE_STAT_H_ */ diff --git a/fs/fuse/kio/pcs/pcs_map.c b/fs/fuse/kio/pcs/pcs_map.c index 2e30f0461101..b795a45cc376 100644 --- a/fs/fuse/kio/pcs/pcs_map.c +++ b/fs/fuse/kio/pcs/pcs_map.c @@ -2701,6 +2701,7 @@ static int commit_sync_info(struct pcs_int_request *req, max_iolat = srec->sync.ts_io; } } + pcs_fuse_stat_io_count(req, resp); cs_log_io_times(req, resp, max_iolat); evaluate_dirty_status(m); -- 2.15.1 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel