[Devel] [PATCH v2 09/14] fs/fuse kio: implement fstat statistics info

Pavel Butsykin pbutsykin at virtuozzo.com
Fri May 24 18:54:58 MSK 2019


This statistic shows information about all open kio files. Made by analogy with
.vstorage.info/fstat statistics of user-mod client.

example:
# rw open/age inactive handles rd/sec rbytes/sec rtotal        wr/sec wbytes/sec wtotal      sync/sec stotal  rmin   ravg   rmax   wmin   wavg   wmax   path
rw      2/5750    0       0    987    4039476    248864768     0      0          0             0      0       4096   4096   4096   0      0      0      /fio_test/randasyncread_jobs24_4k.1.0
rw      2/5750    0       0    60     243303     87810048      0      0          0             0      0       4096   4096   4096   0      0      0      /fio_test/randasyncread_jobs24_4k.0.0

Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
---
 fs/fuse/kio/pcs/fuse_stat.c        | 99 ++++++++++++++++++++++++++++++++++++++
 fs/fuse/kio/pcs/fuse_stat.h        |  6 +++
 fs/fuse/kio/pcs/pcs_client_types.h |  3 ++
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c |  7 ++-
 4 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/fs/fuse/kio/pcs/fuse_stat.c b/fs/fuse/kio/pcs/fuse_stat.c
index 20691955a2f1..51a4ee106497 100644
--- a/fs/fuse/kio/pcs/fuse_stat.c
+++ b/fs/fuse/kio/pcs/fuse_stat.c
@@ -148,6 +148,96 @@ static void fuse_iostat_up(struct pcs_fuse_io_stat_sync *iostat)
 	spin_unlock(&iostat->lock);
 }
 
+static void fuse_fstat_up_itr(struct fuse_file *ff, struct pcs_dentry_info *di,
+			      void *ctx)
+{
+	struct fuse_io_cnt *fstat = &di->stat;
+	fuse_iostat_up(&fstat->io);
+}
+
+static void fuse_stat_files_up(struct pcs_cluster_core *cc)
+{
+	struct fuse_conn *fc = container_of(cc, struct pcs_fuse_cluster, cc)->fc;
+	if (fc) {
+		spin_lock(&fc->lock);
+		pcs_kio_file_list(fc, fuse_fstat_up_itr, NULL);
+		spin_unlock(&fc->lock);
+	}
+}
+
+static void fuse_kio_fstat_itr(struct fuse_file *ff, struct pcs_dentry_info *di,
+			       void *ctx)
+{
+	struct fuse_io_cnt *fstat = &di->stat;
+	struct pcs_fuse_io_stat_sync *iostat = &fstat->io;
+	struct seq_file *m = ctx;
+	umode_t mode = di->inode->inode.i_mode;
+	abs_time_t now = jiffies;
+	struct pcs_fuse_io_stat lstat, gstat;
+
+	seq_printf(m, "%s%s %7u/%-7llu %-7u %-4u ",
+		   mode & S_IRUGO ? "r": "", mode & S_IWUGO ? "w": "",
+		   atomic_read(&ff->count), (now - fstat->created_ts) / 1000, 0, 0);
+
+	spin_lock(&iostat->lock);
+	stat_period_read(iostat->LAST(iostat), &lstat);
+	gstat = iostat->glob;
+	spin_unlock(&iostat->lock);
+
+	seq_printf(m, "%-6llu %-10llu %-13llu ", EVT_RATE(lstat.read_bytes),
+		   VAL_RATE(lstat.read_bytes), gstat.read_bytes.val_total);
+	seq_printf(m, "%-6llu %-10llu %-13llu ", EVT_RATE(lstat.write_bytes),
+		   VAL_RATE(lstat.write_bytes), gstat.write_bytes.val_total);
+	seq_printf(m, "%-6llu %-7llu ", EVT_RATE(lstat.flush_cnt),
+		   gstat.flush_cnt.val_total);
+	seq_printf(m, "%-6llu %-6llu %-6llu ", CNT_MIN(lstat.read_bytes, gstat.read_bytes),
+		   VAL_AVER(gstat.read_bytes), CNT_MAX(lstat.read_bytes, gstat.read_bytes));
+	seq_printf(m, "%-6llu %-6llu %-6llu ", CNT_MIN(lstat.write_bytes, gstat.read_bytes),
+		   VAL_AVER(gstat.write_bytes), CNT_MAX(lstat.write_bytes, gstat.read_bytes));
+	seq_dentry(m, ff->ff_dentry, "");
+	seq_putc(m, '\n');
+}
+
+static int pcs_fuse_fstat_show(struct seq_file *m, void *v)
+{
+	struct inode *inode = m->private;
+	struct pcs_fuse_stat *stat;
+	struct fuse_conn *fc;
+
+	if (!inode)
+		return 0;
+
+	mutex_lock(&fuse_mutex);
+	stat = inode->i_private;
+	if (!stat)
+		goto out;
+
+	seq_printf(m, "# rw open/age inactive handles rd/sec rbytes/sec rtotal        wr/sec wbytes/sec wtotal      sync/sec stotal  rmin   ravg   rmax   wmin   wavg   wmax   path\n");
+
+	fc = container_of(stat, struct pcs_fuse_cluster, cc.stat)->fc;
+	if (fc) {
+		spin_lock(&fc->lock);
+		pcs_kio_file_list(fc, fuse_kio_fstat_itr, m);
+		spin_unlock(&fc->lock);
+	}
+out:
+	mutex_unlock(&fuse_mutex);
+	return 0;
+}
+
+static int pcs_fuse_fstat_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pcs_fuse_fstat_show, inode);
+}
+
+static const struct file_operations pcs_fuse_fstat_ops = {
+	.owner   = THIS_MODULE,
+	.open    = pcs_fuse_fstat_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+
 static void fuse_kio_stat_req_itr(struct fuse_file *ff, struct fuse_req *req,
 				  void *ctx)
 {
@@ -288,10 +378,12 @@ static void fuse_iostat_count(struct pcs_fuse_io_stat_sync *iostat,
 void pcs_fuse_stat_io_count(struct pcs_int_request *ireq, struct pcs_msg *resp)
 {
 	struct pcs_fuse_stat *stat = &ireq->cc->stat;
+	struct fuse_io_cnt *fstat = &ireq->dentry->stat;
 	struct pcs_cs_iohdr *h = (struct pcs_cs_iohdr *)msg_inline_head(resp);
 	u64 size = h->hdr.type != PCS_CS_SYNC_RESP ? ireq->iochunk.size : 0;
 
 	fuse_iostat_count(&stat->io, size, h->hdr.type);
+	fuse_iostat_count(&fstat->io, size, h->hdr.type);
 }
 
 static void pcs_fuse_stat_work(struct work_struct *w)
@@ -301,6 +393,7 @@ static void pcs_fuse_stat_work(struct work_struct *w)
 	struct pcs_fuse_stat *stat = &cc->stat;
 
 	fuse_iostat_up(&stat->io);
+	fuse_stat_files_up(cc);
 
 	mod_delayed_work(cc->wq, &cc->stat.work, STAT_TIMER_PERIOD * HZ);
 }
@@ -405,6 +498,10 @@ void pcs_fuse_stat_init(struct pcs_fuse_stat *stat)
 	stat->requests = fuse_kio_add_dentry(stat->kio_stat, fc, "requests",
 					     S_IFREG | S_IRUSR, 1, NULL,
 					     &pcs_fuse_requests_ops, stat);
+	stat->fstat = fuse_kio_add_dentry(stat->kio_stat, fc, "fstat",
+					  S_IFREG | S_IRUSR, 1, NULL,
+					  &pcs_fuse_fstat_ops, stat);
+
 	mutex_unlock(&fuse_mutex);
 	return;
 
@@ -425,6 +522,8 @@ void pcs_fuse_stat_fini(struct pcs_fuse_stat *stat)
 			fuse_kio_rm_dentry(stat->iostat);
 		if (stat->requests)
 			fuse_kio_rm_dentry(stat->requests);
+		if (stat->fstat)
+			fuse_kio_rm_dentry(stat->fstat);
 		fuse_kio_rm_dentry(stat->kio_stat);
 	}
 	mutex_unlock(&fuse_mutex);
diff --git a/fs/fuse/kio/pcs/fuse_stat.h b/fs/fuse/kio/pcs/fuse_stat.h
index 2a300c35213e..83bf0dc573f4 100644
--- a/fs/fuse/kio/pcs/fuse_stat.h
+++ b/fs/fuse/kio/pcs/fuse_stat.h
@@ -34,6 +34,12 @@ struct pcs_fuse_stat {
 	struct dentry *kio_stat;
 	struct dentry *iostat;
 	struct dentry *requests;
+	struct dentry *fstat;
+};
+
+struct fuse_io_cnt {
+	struct pcs_fuse_io_stat_sync io;
+	abs_time_t created_ts;
 };
 
 void pcs_fuse_stat_init(struct pcs_fuse_stat *stat);
diff --git a/fs/fuse/kio/pcs/pcs_client_types.h b/fs/fuse/kio/pcs/pcs_client_types.h
index 1be32cbbf285..2c9cbd1c23a6 100644
--- a/fs/fuse/kio/pcs/pcs_client_types.h
+++ b/fs/fuse/kio/pcs/pcs_client_types.h
@@ -4,6 +4,7 @@
 #include "pcs_prot_types.h"
 #include "pcs_mds_prot.h"
 #include "pcs_flow_detect.h"
+#include "fuse_stat.h"
 
 /* Values of lease. It is value, not bitmask. */
 #define PCS_LEASE_NONE		0
@@ -70,6 +71,8 @@ struct pcs_dentry_info {
 	struct fuse_inode	*inode;
 	struct list_head	kq;
 	spinlock_t		kq_lock;
+
+	struct fuse_io_cnt stat;
 };
 
 static inline void pcs_clear_fileinfo(struct pcs_dentry_info *i)
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 796d8db05aba..d65e0931728e 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -346,7 +346,11 @@ static int kpcs_do_file_open(struct fuse_conn *fc, struct file *file, struct ino
 	di->size.required = 0;
 	di->size.op = PCS_SIZE_INACTION;
 	INIT_WORK(&di->size.work, fuse_size_grow_work);
-
+	di->stat.created_ts = jiffies;
+	if (pcs_fuse_io_stat_alloc(&di->stat.io)) {
+		kfree(di);
+		return -ENOMEM;
+	}
 	pcs_mapping_init(&pfc->cc, &di->mapping);
 	pcs_set_fileinfo(di, &info);
 	di->cluster = &pfc->cc;
@@ -415,6 +419,7 @@ void kpcs_inode_release(struct fuse_inode *fi)
 	pcs_mapping_invalidate(&di->mapping);
 	pcs_mapping_deinit(&di->mapping);
 	/* TODO: properly destroy dentry info here!! */
+	pcs_fuse_io_stat_free(&di->stat.io);
 	kfree(di);
 }
 
-- 
2.15.1



More information about the Devel mailing list