diff mbox series

btrfs: add io_stats to sysfs for dio fallbacks

Message ID 20250121183751.201556-1-maharmstone@fb.com (mailing list archive)
State New
Headers show
Series btrfs: add io_stats to sysfs for dio fallbacks | expand

Commit Message

Mark Harmstone Jan. 21, 2025, 6:36 p.m. UTC
For O_DIRECT reads and writes, both the buffer address and the file offset
need to be aligned to the block size. Otherwise, btrfs falls back to
doing buffered I/O, which is probably not what you want. It also creates
portability issues, as not all filesystems do this.

Add a new sysfs entry io_stats, to record how many times DIO falls back
to doing buffered I/O. The intention is that once this is recorded, we
can investigate the programs running on any machine where this isn't 0.

Signed-off-by: Mark Harmstone <maharmstone@fb.com>
---
 fs/btrfs/direct-io.c |  6 ++++++
 fs/btrfs/file.c      |  9 +++++++++
 fs/btrfs/fs.h        |  8 ++++++++
 fs/btrfs/sysfs.c     | 15 +++++++++++++++
 4 files changed, 38 insertions(+)
diff mbox series

Patch

diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c
index 8567af46e16f..d388acf10f47 100644
--- a/fs/btrfs/direct-io.c
+++ b/fs/btrfs/direct-io.c
@@ -946,6 +946,12 @@  ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
 		goto out;
 	}
 
+	/*
+	 * We're falling back to buffered writes, increase the
+	 * dio_write_fallback counter.
+	 */
+	atomic_inc(&fs_info->io_stats.dio_write_fallback);
+
 	pos = iocb->ki_pos;
 	written_buffered = btrfs_buffered_write(iocb, from);
 	if (written_buffered < 0) {
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 36f51c311bb1..f74091482cb6 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3644,10 +3644,19 @@  static ssize_t btrfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	ssize_t ret = 0;
 
 	if (iocb->ki_flags & IOCB_DIRECT) {
+		struct btrfs_fs_info *fs_info;
+
 		ret = btrfs_direct_read(iocb, to);
 		if (ret < 0 || !iov_iter_count(to) ||
 		    iocb->ki_pos >= i_size_read(file_inode(iocb->ki_filp)))
 			return ret;
+
+		/*
+		 * We're falling back to buffered reads, increase the
+		 * dio_read_fallback counter.
+		 */
+		fs_info = BTRFS_I(iocb->ki_filp->f_inode)->root->fs_info;
+		atomic_inc(&fs_info->io_stats.dio_read_fallback);
 	}
 
 	return filemap_read(iocb, to, ret);
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
index b572d6b9730b..e659fb12cae6 100644
--- a/fs/btrfs/fs.h
+++ b/fs/btrfs/fs.h
@@ -406,6 +406,12 @@  struct btrfs_commit_stats {
 	u64 total_commit_dur;
 };
 
+/* Store data about I/O stats, exported via sysfs. */
+struct btrfs_io_stats {
+	atomic_t dio_read_fallback;
+	atomic_t dio_write_fallback;
+};
+
 struct btrfs_fs_info {
 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
 	unsigned long flags;
@@ -851,6 +857,8 @@  struct btrfs_fs_info {
 	/* Updates are not protected by any lock */
 	struct btrfs_commit_stats commit_stats;
 
+	struct btrfs_io_stats io_stats;
+
 	/*
 	 * Last generation where we dropped a non-relocation root.
 	 * Use btrfs_set_last_root_drop_gen() and btrfs_get_last_root_drop_gen()
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 53b846d99ece..4dc772bc7e7b 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -1526,6 +1526,20 @@  static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj,
 BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
 	      btrfs_bg_reclaim_threshold_store);
 
+static ssize_t btrfs_io_stats_show(struct kobject *kobj,
+				   struct kobj_attribute *a, char *buf)
+{
+	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+
+	return sysfs_emit(buf,
+			"dio_read_fallback %u\n"
+			"dio_write_fallback %u\n",
+			atomic_read(&fs_info->io_stats.dio_read_fallback),
+			atomic_read(&fs_info->io_stats.dio_write_fallback));
+}
+
+BTRFS_ATTR(, io_stats, btrfs_io_stats_show);
+
 #ifdef CONFIG_BTRFS_EXPERIMENTAL
 static ssize_t btrfs_offload_csum_show(struct kobject *kobj,
 				       struct kobj_attribute *a, char *buf)
@@ -1586,6 +1600,7 @@  static const struct attribute *btrfs_attrs[] = {
 	BTRFS_ATTR_PTR(, bg_reclaim_threshold),
 	BTRFS_ATTR_PTR(, commit_stats),
 	BTRFS_ATTR_PTR(, temp_fsid),
+	BTRFS_ATTR_PTR(, io_stats),
 #ifdef CONFIG_BTRFS_EXPERIMENTAL
 	BTRFS_ATTR_PTR(, offload_csum),
 #endif