mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Xiubo Li via B4 Relay <devnull+xiubo.li.clyso.com@kernel.org>
To: Ilya Dryomov <idryomov@gmail.com>,
	Alex Markuze <amarkuze@redhat.com>,
	 Viacheslav Dubeyko <slava@dubeyko.com>
Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Xiubo Li <xiubo.li@clyso.com>
Subject: [PATCH] ceph: flush the caps ceph_write_inode() queues from the delayed work
Date: Sat, 07 Nov 2026 03:52:27 +0100	[thread overview]
Message-ID: <20261107-ceph-write-inode-flush-v1-1-6d414faf9ccd@clyso.com> (raw)

From: Xiubo Li <xiubo.li@clyso.com>

ceph_write_inode() without WB_SYNC_ALL does not flush the dirty caps:
it sets CEPH_I_FLUSH and moves the inode to the front of the delayed
cap list, so that the caps go out once, after the data writeback.  But
ceph_check_caps() turns CEPH_I_FLUSH into CHECK_CAPS_FLUSH for every
caller, and a buffered write calls it whenever it puts its last Fw
reference.  So the next write after a writeback pass flushes the caps
at once.

A file under steady writeback, with the dirty page limit reached, gets
a writeback pass for nearly every write, and every write dirties Fw
again (mtime).  The client then sends a cap flush per few writes, and
the MDS journals each one.

Honour CEPH_I_FLUSH only in the delayed cap work, which the inode was
queued for.  Other callers still flush dirty caps when they send a cap
message for another reason, and fsync() and sync writeback flush them
as before.

16 writers on 4 lazyio mounts, each writing 47008-byte records
interleaved with the others' into one shared file (IOR, -t 47008
-b 47008), with the dirty page limit reached, mean of 2 runs each:

+--------------------------+-------+---------+---------+---------+
| metric                   | unit  |    base |   patch | speedup |
+--------------------------+-------+---------+---------+---------+
| write bandwidth          | GiB/s |   0.711 |   0.713 |   1.00x |
| cap messages, the file   |       |   78360 |     368 |         |
| MDS journal events       |       |   93470 |     600 |         |
| MDS journal latency, avg | ms    |    4197 |     556 |         |
+--------------------------+-------+---------+---------+---------+

write() latency in ms, 2 runs each pooled:

+-------+-----+-----+-----+-------+--------+----------+------+
|       | p50 | p90 | p95 | p99   | p99.9  | p99.99   | max  |
+-------+-----+-----+-----+-------+--------+----------+------+
| base  | 0.2 | 0.2 | 0.2 | 16-33 | 66-131 | 524-1049 | 8854 |
| patch | 0.2 | 0.2 | 0.3 | 16-33 | 66-131 | 66-131   | 2965 |
+-------+-----+-----+-----+-------+--------+----------+------+

The gain is in the cap and journal traffic, not in bandwidth: any file
that is written while it is under writeback sends far fewer cap
flushes to the MDS.

Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
---
 fs/ceph/caps.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index aca09351a094..d95eb2f42f42 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -2211,8 +2211,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
 		return;
 	}
 
-	if (ci->i_ceph_flags & CEPH_I_FLUSH)
-		flags |= CHECK_CAPS_FLUSH;
 	/*
 	 * A revoke whose response was deferred (see handle_cap_grant()) must
 	 * still be acknowledged.  Replay the forced flush here so that even a
@@ -5056,10 +5054,20 @@ static unsigned long check_delayed_caps_list(struct ceph_mds_client *mdsc,
 
 		inode = igrab(&ci->netfs.inode);
 		if (inode) {
+			/*
+			 * Flush the dirty caps that ceph_write_inode()
+			 * queued here.  Only this work does it: other cap
+			 * checks leave them for it, so that a file under
+			 * writeback does not flush them after every write.
+			 */
+			int flags = test_bit(CEPH_I_FLUSH_BIT,
+					     &ci->i_ceph_flags) ?
+				    CHECK_CAPS_FLUSH : 0;
+
 			spin_unlock(&mdsc->cap_delay_lock);
 			doutc(cl, "on %p %llx.%llx\n", inode,
 			      ceph_vinop(inode));
-			ceph_check_caps(ci, 0);
+			ceph_check_caps(ci, flags);
 			iput(inode);
 			spin_lock(&mdsc->cap_delay_lock);
 		}

---
base-commit: 5dcec86cc31f8144857c0d9bf2a7fa13b6e6f531
change-id: 20261107-ceph-write-inode-flush-dc67685cf521

Best regards,
--  
Xiubo Li <xiubo.li@clyso.com>



                 reply	other threads:[~2026-11-07  2:52 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20261107-ceph-write-inode-flush-v1-1-6d414faf9ccd@clyso.com \
    --to=devnull+xiubo.li.clyso.com@kernel.org \
    --cc=amarkuze@redhat.com \
    --cc=ceph-devel@vger.kernel.org \
    --cc=idryomov@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=slava@dubeyko.com \
    --cc=xiubo.li@clyso.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®