cifs: enable fscache usage even for files opened as rw
authorShyam Prasad N <sprasad@microsoft.com>
Tue, 10 Aug 2021 10:22:28 +0000 (10:22 +0000)
committerSteve French <stfrench@microsoft.com>
Wed, 25 Aug 2021 20:45:10 +0000 (15:45 -0500)
So far, the fscache implementation we had supports only
a small set of use cases. Particularly for files opened
with O_RDONLY.

This commit enables it even for rw based file opens. It
also enables the reuse of cached data in case of mount
option (cache=singleclient) where it is guaranteed that
this is the only client (and server) which operates on
the files. There's also a single line change in fscache.c
to get around a bug seen in fscache.

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Acked-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifsfs.c
fs/cifs/cifssmb.c
fs/cifs/file.c
fs/cifs/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c

index 64b71c4..6e4fc42 100644 (file)
@@ -399,7 +399,6 @@ cifs_evict_inode(struct inode *inode)
 {
        truncate_inode_pages_final(&inode->i_data);
        clear_inode(inode);
-       cifs_fscache_release_inode_cookie(inode);
 }
 
 static void
index 65d1a65..f207de8 100644 (file)
@@ -2101,6 +2101,7 @@ cifs_writev_complete(struct work_struct *work)
                else if (wdata->result < 0)
                        SetPageError(page);
                end_page_writeback(page);
+               cifs_readpage_to_fscache(inode, page);
                put_page(page);
        }
        if (wdata->result != -EAGAIN)
index bb98fbd..d021647 100644 (file)
@@ -377,6 +377,8 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
        struct cifsLockInfo *li, *tmp;
        struct super_block *sb = inode->i_sb;
 
+       cifs_fscache_release_inode_cookie(inode);
+
        /*
         * Delete any outstanding lock records. We'll lose them when the file
         * is closed anyway.
@@ -882,8 +884,10 @@ int cifs_close(struct inode *inode, struct file *file)
                if ((cinode->oplock == CIFS_CACHE_RHW_FLG) &&
                    cinode->lease_granted &&
                    dclose) {
-                       if (test_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags))
+                       if (test_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
                                inode->i_ctime = inode->i_mtime = current_time(inode);
+                               cifs_fscache_update_inode_cookie(inode);
+                       }
                        spin_lock(&cinode->deferred_lock);
                        cifs_add_deferred_close(cfile, dclose);
                        if (cfile->deferred_close_scheduled &&
@@ -4170,6 +4174,10 @@ static vm_fault_t
 cifs_page_mkwrite(struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
+       struct file *file = vmf->vma->vm_file;
+       struct inode *inode = file_inode(file);
+
+       cifs_fscache_wait_on_page_write(inode, page);
 
        lock_page(page);
        return VM_FAULT_LOCKED;
@@ -4235,13 +4243,16 @@ cifs_readv_complete(struct work_struct *work)
                    (rdata->result == -EAGAIN && got_bytes)) {
                        flush_dcache_page(page);
                        SetPageUptodate(page);
-               }
+               } else
+                       SetPageError(page);
 
                unlock_page(page);
 
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes))
                        cifs_readpage_to_fscache(rdata->mapping->host, page);
+               else
+                       cifs_fscache_uncache_page(rdata->mapping->host, page);
 
                got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
 
index dd62503..fab47fa 100644 (file)
@@ -176,29 +176,34 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
                auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
 
                cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
+               /* fscache_relinquish_cookie does not seem to update auxdata */
+               fscache_update_cookie(cifsi->fscache, &auxdata);
                fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
                cifsi->fscache = NULL;
        }
 }
 
-static void cifs_fscache_disable_inode_cookie(struct inode *inode)
+void cifs_fscache_update_inode_cookie(struct inode *inode)
 {
+       struct cifs_fscache_inode_auxdata auxdata;
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        if (cifsi->fscache) {
+               memset(&auxdata, 0, sizeof(auxdata));
+               auxdata.eof = cifsi->server_eof;
+               auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
+               auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
+               auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
+               auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
+
                cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
-               fscache_uncache_all_inode_pages(cifsi->fscache, inode);
-               fscache_relinquish_cookie(cifsi->fscache, NULL, true);
-               cifsi->fscache = NULL;
+               fscache_update_cookie(cifsi->fscache, &auxdata);
        }
 }
 
 void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
 {
-       if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
-               cifs_fscache_disable_inode_cookie(inode);
-       else
-               cifs_fscache_enable_inode_cookie(inode);
+       cifs_fscache_enable_inode_cookie(inode);
 }
 
 void cifs_fscache_reset_inode_cookie(struct inode *inode)
@@ -310,6 +315,8 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
        int ret;
 
+       WARN_ON(!cifsi->fscache);
+
        cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
                 __func__, cifsi->fscache, page, inode);
        ret = fscache_write_page(cifsi->fscache, page,
@@ -334,3 +341,21 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
        fscache_wait_on_page_write(cookie, page);
        fscache_uncache_page(cookie, page);
 }
+
+void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct fscache_cookie *cookie = cifsi->fscache;
+
+       cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
+       fscache_wait_on_page_write(cookie, page);
+}
+
+void __cifs_fscache_uncache_page(struct inode *inode, struct page *page)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct fscache_cookie *cookie = cifsi->fscache;
+
+       cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
+       fscache_uncache_page(cookie, page);
+}
index 3d55cb2..82e856b 100644 (file)
@@ -55,10 +55,13 @@ extern void cifs_fscache_get_super_cookie(struct cifs_tcon *);
 extern void cifs_fscache_release_super_cookie(struct cifs_tcon *);
 
 extern void cifs_fscache_release_inode_cookie(struct inode *);
+extern void cifs_fscache_update_inode_cookie(struct inode *inode);
 extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
 extern void cifs_fscache_reset_inode_cookie(struct inode *);
 
 extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
+extern void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page);
+extern void __cifs_fscache_uncache_page(struct inode *inode, struct page *page);
 extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
 extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
 extern int __cifs_readpages_from_fscache(struct inode *,
@@ -76,6 +79,20 @@ static inline void cifs_fscache_invalidate_page(struct page *page,
                __cifs_fscache_invalidate_page(page, inode);
 }
 
+static inline void cifs_fscache_wait_on_page_write(struct inode *inode,
+                                                  struct page *page)
+{
+       if (PageFsCache(page))
+               __cifs_fscache_wait_on_page_write(inode, page);
+}
+
+static inline void cifs_fscache_uncache_page(struct inode *inode,
+                                                  struct page *page)
+{
+       if (PageFsCache(page))
+               __cifs_fscache_uncache_page(inode, page);
+}
+
 static inline int cifs_readpage_from_fscache(struct inode *inode,
                                             struct page *page)
 {
@@ -123,6 +140,7 @@ static inline void
 cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {}
 
 static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
+static inline void cifs_fscache_update_inode_cookie(struct inode *inode) {}
 static inline void cifs_fscache_set_inode_cookie(struct inode *inode,
                                                 struct file *filp) {}
 static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {}
@@ -133,6 +151,11 @@ static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
 
 static inline void cifs_fscache_invalidate_page(struct page *page,
                        struct inode *inode) {}
+static inline void cifs_fscache_wait_on_page_write(struct inode *inode,
+                                                  struct page *page) {}
+static inline void cifs_fscache_uncache_page(struct inode *inode,
+                                                  struct page *page) {}
+
 static inline int
 cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
index 65f8a70..50c01cf 100644 (file)
@@ -2297,6 +2297,7 @@ cifs_revalidate_mapping(struct inode *inode)
 {
        int rc;
        unsigned long *flags = &CIFS_I(inode)->flags;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
        /* swapfiles are not supposed to be shared */
        if (IS_SWAPFILE(inode))
@@ -2308,11 +2309,16 @@ cifs_revalidate_mapping(struct inode *inode)
                return rc;
 
        if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) {
+               /* for cache=singleclient, do not invalidate */
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
+                       goto skip_invalidate;
+
                rc = cifs_invalidate_mapping(inode);
                if (rc)
                        set_bit(CIFS_INO_INVALID_MAPPING, flags);
        }
 
+skip_invalidate:
        clear_bit_unlock(CIFS_INO_LOCK, flags);
        smp_mb__after_atomic();
        wake_up_bit(flags, CIFS_INO_LOCK);