From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Dave Chinner <david@fromorbit.com>,
Al Viro <viro@zeniv.linux.org.uk>,
linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH v4 4/9] fs: add optional iostats counters to struct super_block
Date: Sat, 5 Mar 2022 18:04:19 +0200 [thread overview]
Message-ID: <20220305160424.1040102-5-amir73il@gmail.com> (raw)
In-Reply-To: <20220305160424.1040102-1-amir73il@gmail.com>
With CONFIG_FS_IOSTATS, filesystems can opt-in to generic per-sb I/O
statistics by setting the FS_SB_IOSTATS fstype flag.
These counters will be used to collect per-sb I/O statistics and display
them in /proc/<pid>/mountstats.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
fs/Kconfig | 8 +++
fs/super.c | 6 ++
include/linux/fs.h | 11 +++-
include/linux/fs_iostats.h | 130 +++++++++++++++++++++++++++++++++++++
4 files changed, 153 insertions(+), 2 deletions(-)
create mode 100644 include/linux/fs_iostats.h
diff --git a/fs/Kconfig b/fs/Kconfig
index 6c7dc1387beb..394d9da6bda9 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -15,6 +15,14 @@ config VALIDATE_FS_PARSER
Enable this to perform validation of the parameter description for a
filesystem when it is registered.
+config FS_IOSTATS
+ bool "Enable generic filesystem I/O statistics"
+ help
+ Enable this to allow collecting filesystem I/O statistics and display
+ them in /proc/<pid>/mountstats.
+
+ Say N if unsure.
+
config FS_IOMAP
bool
diff --git a/fs/super.c b/fs/super.c
index f1d4a193602d..a18930693e54 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -36,6 +36,7 @@
#include <linux/lockdep.h>
#include <linux/user_namespace.h>
#include <linux/fs_context.h>
+#include <linux/fs_iostats.h>
#include <uapi/linux/mount.h>
#include "internal.h"
@@ -179,6 +180,7 @@ static void destroy_unused_super(struct super_block *s)
up_write(&s->s_umount);
list_lru_destroy(&s->s_dentry_lru);
list_lru_destroy(&s->s_inode_lru);
+ sb_iostats_destroy(s);
security_sb_free(s);
put_user_ns(s->s_user_ns);
kfree(s->s_subtype);
@@ -230,6 +232,9 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
if (security_sb_alloc(s))
goto fail;
+ if (type->fs_flags & FS_SB_IOSTATS && sb_iostats_init(s))
+ goto fail;
+
for (i = 0; i < SB_FREEZE_LEVELS; i++) {
if (__percpu_init_rwsem(&s->s_writers.rw_sem[i],
sb_writers_name[i],
@@ -290,6 +295,7 @@ static void __put_super(struct super_block *s)
WARN_ON(s->s_dentry_lru.node);
WARN_ON(s->s_inode_lru.node);
WARN_ON(!list_empty(&s->s_mounts));
+ sb_iostats_destroy(s);
security_sb_free(s);
fscrypt_sb_free(s);
put_user_ns(s->s_user_ns);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ecb64997c390..f8e7ec81ae0b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1455,6 +1455,8 @@ struct sb_writers {
struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS];
};
+struct sb_iostats;
+
struct super_block {
struct list_head s_list; /* Keep this first */
dev_t s_dev; /* search index; _not_ kdev_t */
@@ -1509,8 +1511,12 @@ struct super_block {
/* Granularity of c/m/atime in ns (cannot be worse than a second) */
u32 s_time_gran;
/* Time limits for c/m/atime in seconds */
- time64_t s_time_min;
- time64_t s_time_max;
+ time64_t s_time_min;
+ time64_t s_time_max;
+#ifdef CONFIG_FS_IOSTATS
+ /* Optional per-sb I/O stats */
+ struct sb_iostats *s_iostats;
+#endif
#ifdef CONFIG_FSNOTIFY
__u32 s_fsnotify_mask;
struct fsnotify_mark_connector __rcu *s_fsnotify_marks;
@@ -2435,6 +2441,7 @@ struct file_system_type {
#define FS_USERNS_MOUNT (1<<3) /* Can be mounted by userns root */
#define FS_DISALLOW_NOTIFY_PERM (1<<4) /* Disable fanotify permission events */
#define FS_ALLOW_IDMAP (1<<5) /* FS can handle vfs idmappings */
+#define FS_SB_IOSTATS (1<<6) /* FS has generic per-sb I/O stats */
#define FS_RENAME_DOES_D_MOVE (1<<15) /* FS will handle d_move() internally */
int (*init_fs_context)(struct fs_context *);
const struct fs_parameter_spec *parameters;
diff --git a/include/linux/fs_iostats.h b/include/linux/fs_iostats.h
new file mode 100644
index 000000000000..2db13e9e17fc
--- /dev/null
+++ b/include/linux/fs_iostats.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_FS_IOSTATS_H
+#define _LINUX_FS_IOSTATS_H
+
+#include <linux/fs.h>
+#include <linux/percpu_counter.h>
+#include <linux/slab.h>
+
+/* Similar to task_io_accounting members */
+enum {
+ SB_IOSTATS_CHARS_RD, /* bytes read via syscalls */
+ SB_IOSTATS_CHARS_WR, /* bytes written via syscalls */
+ SB_IOSTATS_SYSCALLS_RD, /* # of read syscalls */
+ SB_IOSTATS_SYSCALLS_WR, /* # of write syscalls */
+ SB_IOSTATS_COUNTERS_NUM
+};
+
+struct sb_iostats {
+ time64_t start_time;
+ struct percpu_counter counter[SB_IOSTATS_COUNTERS_NUM];
+};
+
+#ifdef CONFIG_FS_IOSTATS
+static inline struct sb_iostats *sb_iostats(struct super_block *sb)
+{
+ return sb->s_iostats;
+}
+
+static inline bool sb_has_iostats(struct super_block *sb)
+{
+ return !!sb->s_iostats;
+}
+
+/* Initialize per-sb I/O stats */
+static inline int sb_iostats_init(struct super_block *sb)
+{
+ int err;
+
+ if (sb->s_iostats)
+ return 0;
+
+ sb->s_iostats = kmalloc(sizeof(struct sb_iostats), GFP_KERNEL);
+ if (!sb->s_iostats)
+ return -ENOMEM;
+
+ err = percpu_counters_init(sb->s_iostats->counter,
+ SB_IOSTATS_COUNTERS_NUM, 0, GFP_KERNEL);
+ if (err) {
+ kfree(sb->s_iostats);
+ sb->s_iostats = NULL;
+ return err;
+ }
+
+ sb->s_iostats->start_time = ktime_get_seconds();
+ return 0;
+}
+
+static inline void sb_iostats_destroy(struct super_block *sb)
+{
+ if (!sb->s_iostats)
+ return;
+
+ percpu_counters_destroy(sb->s_iostats->counter,
+ SB_IOSTATS_COUNTERS_NUM);
+ kfree(sb->s_iostats);
+ sb->s_iostats = NULL;
+}
+
+static inline void sb_iostats_counter_inc(struct super_block *sb, int id)
+{
+ if (!sb->s_iostats)
+ return;
+
+ percpu_counter_inc_relaxed(&sb->s_iostats->counter[id]);
+}
+
+static inline void sb_iostats_counter_add(struct super_block *sb, int id,
+ s64 amt)
+{
+ if (!sb->s_iostats)
+ return;
+
+ percpu_counter_add_relaxed(&sb->s_iostats->counter[id], amt);
+}
+
+static inline s64 sb_iostats_counter_read(struct super_block *sb, int id)
+{
+ if (!sb->s_iostats)
+ return 0;
+
+ return percpu_counter_sum_positive(&sb->s_iostats->counter[id]);
+}
+
+#else /* !CONFIG_FS_IOSTATS */
+
+static inline struct sb_iostats *sb_iostats(struct super_block *sb)
+{
+ return NULL;
+}
+
+static inline bool sb_has_iostats(struct super_block *sb)
+{
+ return false;
+}
+
+static inline int sb_iostats_init(struct super_block *sb)
+{
+ return 0;
+}
+
+static inline void sb_iostats_destroy(struct super_block *sb)
+{
+}
+
+static inline void sb_iostats_counter_inc(struct super_block *sb, int id)
+{
+}
+
+static inline void sb_iostats_counter_add(struct super_block *sb, int id,
+ s64 amt)
+{
+}
+
+static inline s64 sb_iostats_counter_read(struct super_block *sb, int id)
+{
+ return 0;
+}
+#endif
+
+#endif /* _LINUX_FS_IOSTATS_H */
--
2.25.1
next prev parent reply other threads:[~2022-03-05 16:04 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-05 16:04 [PATCH v4 0/9] Generic per-sb io stats Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 1/9] lib/percpu_counter: add helpers for "relaxed" counters Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 2/9] lib/percpu_counter: add helpers for arrays of counters Amir Goldstein
2022-03-08 10:03 ` Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 3/9] fs: tidy up fs_flags definitions Amir Goldstein
2022-03-05 16:04 ` Amir Goldstein [this message]
2022-03-05 16:04 ` [PATCH v4 5/9] fs: collect per-sb io stats Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 6/9] fs: report " Amir Goldstein
2022-03-10 9:53 ` Miklos Szeredi
2022-03-10 10:45 ` Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 7/9] ovl: opt-in for " Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 8/9] fuse: " Amir Goldstein
2022-03-05 16:04 ` [PATCH v4 9/9] fs: enable per-sb io stats for all blockdev filesystems Amir Goldstein
2022-03-06 4:18 ` [PATCH v4 0/9] Generic per-sb io stats Theodore Ts'o
2022-03-06 7:55 ` Amir Goldstein
2022-03-07 0:14 ` Dave Chinner
2022-03-07 10:04 ` Amir Goldstein
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220305160424.1040102-5-amir73il@gmail.com \
--to=amir73il@gmail.com \
--cc=david@fromorbit.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.