page_mkwrite should only be called with Uptodate pages, so we should
only need to flush incompatible snap contexts.

Signed-off-by: Jeff Layton <[email protected]>
---
 fs/ceph/addr.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index d8a8803f0e65..e02d8915376f 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1692,6 +1692,8 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
        inode_inc_iversion_raw(inode);
 
        do {
+               struct ceph_snap_context *snapc;
+
                lock_page(page);
 
                if (page_mkwrite_check_truncate(page, inode) < 0) {
@@ -1700,13 +1702,26 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault 
*vmf)
                        break;
                }
 
-               err = ceph_update_writeable_page(vma->vm_file, off, len, page);
-               if (err >= 0) {
+               snapc = ceph_find_incompatible(inode, page);
+               if (!snapc) {
                        /* success.  we'll keep the page locked. */
                        set_page_dirty(page);
                        ret = VM_FAULT_LOCKED;
+                       break;
                }
-       } while (err == -EAGAIN);
+
+               unlock_page(page);
+
+               if (IS_ERR(snapc)) {
+                       ret = VM_FAULT_SIGBUS;
+                       break;
+               }
+
+               ceph_queue_writeback(inode);
+               err = wait_event_killable(ci->i_cap_wq,
+                               context_is_writeable_or_written(inode, snapc));
+               ceph_put_snap_context(snapc);
+       } while (err == 0);
 
        if (ret == VM_FAULT_LOCKED ||
            ci->i_inline_version != CEPH_INLINE_NONE) {
-- 
2.26.2


--
Linux-cachefs mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to