diff mbox series

ceph: fix the inline data handling

Message ID 20210222142332.256981-1-jlayton@kernel.org
State New
Headers show
Series ceph: fix the inline data handling | expand

Commit Message

Jeff Layton Feb. 22, 2021, 2:23 p.m. UTC
Patrick saw some testcase failures with inlined data enabled. While it
is true that the data is uninlined before write_begin is called, the
i_inline_version is not updated until much later, after the write is
complete, when the caps are dirtied.

Fix the code to allow for write_begin on the first page of a
still-inlined inode, as long as the page is still Uptodate.

Reported-by: Patrick Donnelly <pdonnell@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/ceph/addr.c | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

This is a fix for the netfs conversion. If this tests out OK, I'll plan
to fold this fix into the write_begin conversion.
diff mbox series

Patch

diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 7b0980980ac0..f7c3247616d9 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1234,29 +1234,30 @@  static int ceph_write_begin(struct file *file, struct address_space *mapping,
 	pgoff_t index = pos >> PAGE_SHIFT;
 	int r;
 
+	/*
+	 * Uninlining should have already been done and everything updated, EXCEPT
+	 * for inline_version sent to the MDS.
+	 */
 	if (ci->i_inline_version != CEPH_INLINE_NONE) {
-		/*
-		 * In principle, we should never get here, as the inode should have been uninlined
-		 * before we're allowed to write to the page (in write_iter or page_mkwrite).
-		 */
-		WARN_ONCE(1, "ceph: write_begin called on still-inlined inode!\n");
+		page = grab_cache_page_write_begin(mapping, index, flags);
+		if (!page)
+			return -ENOMEM;
 
 		/*
-		 * Uptodate inline data should have been added
-		 * into page cache while getting Fcr caps.
+		 * The inline_version on a new inode is set to 1. If that's the
+		 * case, then the page is brand new and isn't yet Uptodate.
 		 */
-		if (index == 0) {
-			r = -EINVAL;
+		r = 0;
+		if (index == 0 && ci->i_inline_version != 1) {
+			if (!PageUptodate(page)) {
+				WARN_ONCE(1, "ceph: write_begin called on still-inlined inode (inline_version %llu)!\n",
+					  ci->i_inline_version);
+				r = -EINVAL;
+			}
 			goto out;
 		}
-
-		page = grab_cache_page_write_begin(mapping, index, flags);
-		if (!page)
-			return -ENOMEM;
-
 		zero_user_segment(page, 0, PAGE_SIZE);
 		SetPageUptodate(page);
-		r = 0;
 		goto out;
 	}
 
@@ -1442,9 +1443,6 @@  static vm_fault_t ceph_filemap_fault(struct vm_fault *vmf)
 	return ret;
 }
 
-/*
- * Reuse write_begin here for simplicity.
- */
 static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
 {
 	struct vm_area_struct *vma = vmf->vma;