smb3-Am running some tests on this now (various cifs.ko xfstest regression tests) Lightly updated to remove checkpatch warnings (see attached) On Tue, Jan 18, 2022 at 7:55 AM David Howells <dhowells@xxxxxxxxxx> wrote: > > Change the cifs filesystem to take account of the changes to fscache's > indexing rewrite and reenable caching in cifs. > > The following changes have been made: > > (1) The fscache_netfs struct is no more, and there's no need to register > the filesystem as a whole. > > (2) The session cookie is now an fscache_volume cookie, allocated with > fscache_acquire_volume(). That takes three parameters: a string > representing the "volume" in the index, a string naming the cache to > use (or NULL) and a u64 that conveys coherency metadata for the > volume. > > For cifs, I've made it render the volume name string as: > > "cifs,<ipaddress>,<sharename>" > > where the sharename has '/' characters replaced with ';'. > > This probably needs rethinking a bit as the total name could exceed > the maximum filename component length. > > Further, the coherency data is currently just set to 0. It needs > something else doing with it - I wonder if it would suffice simply to > sum the resource_id, vol_create_time and vol_serial_number or maybe > hash them. > > (3) The fscache_cookie_def is no more and needed information is passed > directly to fscache_acquire_cookie(). The cache no longer calls back > into the filesystem, but rather metadata changes are indicated at > other times. > > fscache_acquire_cookie() is passed the same keying and coherency > information as before. > > (4) The functions to set/reset cookies are removed and > fscache_use_cookie() and fscache_unuse_cookie() are used instead. > > fscache_use_cookie() is passed a flag to indicate if the cookie is > opened for writing. fscache_unuse_cookie() is passed updates for the > metadata if we changed it (ie. if the file was opened for writing). > > These are called when the file is opened or closed. > > (5) cifs_setattr_*() are made to call fscache_resize() to change the size > of the cache object. > > (6) The functions to read and write data are stubbed out pending a > conversion to use netfslib. > > Changes > ======= > ver #7: > - Removed the accidentally added-back call to get the super cookie in > cifs_root_iget(). > - Fixed the right call to cifs_fscache_get_super_cookie() to take account > of the "-o fsc" mount flag. > > ver #6: > - Moved the change of gfpflags_allow_blocking() to current_is_kswapd() for > cifs here. > - Fixed one of the error paths in cifs_atomic_open() to jump around the > call to use the cookie. > - Fixed an additional successful return in the middle of cifs_open() to > use the cookie on the way out. > - Only get a volume cookie (and thus inode cookies) when "-o fsc" is > supplied to mount. > > ver #5: > - Fixed a couple of bits of cookie handling[2]: > - The cookie should be released in cifs_evict_inode(), not > cifsFileInfo_put_final(). The cookie needs to persist beyond file > closure so that writepages will be able to write to it. > - fscache_use_cookie() needs to be called in cifs_atomic_open() as it is > for cifs_open(). > > ver #4: > - Fixed the use of sizeof with memset. > - tcon->vol_create_time is __le64 so doesn't need cpu_to_le64(). > > ver #3: > - Canonicalise the cifs coherency data to make the cache portable. > - Set volume coherency data. > > ver #2: > - Use gfpflags_allow_blocking() rather than using flag directly. > - Upgraded to -rc4 to allow for upstream changes[1]. > - fscache_acquire_volume() now returns errors. > > Signed-off-by: David Howells <dhowells@xxxxxxxxxx> > Acked-by: Jeff Layton <jlayton@xxxxxxxxxx> > cc: Steve French <smfrench@xxxxxxxxx> > cc: Shyam Prasad N <nspmangalore@xxxxxxxxx> > cc: linux-cifs@xxxxxxxxxxxxxxx > cc: linux-cachefs@xxxxxxxxxx > Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=23b55d673d7527b093cd97b7c217c82e70cd1af0 [1] > Link: https://lore.kernel.org/r/3419813.1641592362@xxxxxxxxxxxxxxxxxxxxxx/ [2] > Link: https://lore.kernel.org/r/163819671009.215744.11230627184193298714.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v1 > Link: https://lore.kernel.org/r/163906982979.143852.10672081929614953210.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v2 > Link: https://lore.kernel.org/r/163967187187.1823006.247415138444991444.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v3 > Link: https://lore.kernel.org/r/164021579335.640689.2681324337038770579.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v4 > Link: https://lore.kernel.org/r/3462849.1641593783@xxxxxxxxxxxxxxxxxxxxxx/ # v5 > Link: https://lore.kernel.org/r/1318953.1642024578@xxxxxxxxxxxxxxxxxxxxxx/ # v6 > --- > > fs/cifs/Kconfig | 2 > fs/cifs/Makefile | 2 > fs/cifs/cache.c | 105 ---------------- > fs/cifs/cifsfs.c | 19 ++- > fs/cifs/cifsglob.h | 5 - > fs/cifs/connect.c | 15 -- > fs/cifs/dir.c | 5 + > fs/cifs/file.c | 70 +++++++---- > fs/cifs/fscache.c | 333 ++++++++++++---------------------------------------- > fs/cifs/fscache.h | 126 ++++++-------------- > fs/cifs/inode.c | 19 ++- > 11 files changed, 197 insertions(+), 504 deletions(-) > delete mode 100644 fs/cifs/cache.c > > diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig > index 346ae8716deb..3b7e3b9e4fd2 100644 > --- a/fs/cifs/Kconfig > +++ b/fs/cifs/Kconfig > @@ -188,7 +188,7 @@ config CIFS_SMB_DIRECT > > config CIFS_FSCACHE > bool "Provide CIFS client caching support" > - depends on CIFS=m && FSCACHE_OLD_API || CIFS=y && FSCACHE_OLD_API=y > + depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y > help > Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data > to be cached locally on disk through the general filesystem cache > diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile > index 87fcacdf3de7..cc8fdcb35b71 100644 > --- a/fs/cifs/Makefile > +++ b/fs/cifs/Makefile > @@ -25,7 +25,7 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o > > cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o > > -cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o > +cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o > > cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o > > diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c > deleted file mode 100644 > index 8be57aaedab6..000000000000 > --- a/fs/cifs/cache.c > +++ /dev/null > @@ -1,105 +0,0 @@ > -// SPDX-License-Identifier: LGPL-2.1 > -/* > - * CIFS filesystem cache index structure definitions > - * > - * Copyright (c) 2010 Novell, Inc. > - * Authors(s): Suresh Jayaraman (sjayaraman@xxxxxxx> > - * > - */ > -#include "fscache.h" > -#include "cifs_debug.h" > - > -/* > - * CIFS filesystem definition for FS-Cache > - */ > -struct fscache_netfs cifs_fscache_netfs = { > - .name = "cifs", > - .version = 0, > -}; > - > -/* > - * Register CIFS for caching with FS-Cache > - */ > -int cifs_fscache_register(void) > -{ > - return fscache_register_netfs(&cifs_fscache_netfs); > -} > - > -/* > - * Unregister CIFS for caching > - */ > -void cifs_fscache_unregister(void) > -{ > - fscache_unregister_netfs(&cifs_fscache_netfs); > -} > - > -/* > - * Server object for FS-Cache > - */ > -const struct fscache_cookie_def cifs_fscache_server_index_def = { > - .name = "CIFS.server", > - .type = FSCACHE_COOKIE_TYPE_INDEX, > -}; > - > -static enum > -fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, > - const void *data, > - uint16_t datalen, > - loff_t object_size) > -{ > - struct cifs_fscache_super_auxdata auxdata; > - const struct cifs_tcon *tcon = cookie_netfs_data; > - > - if (datalen != sizeof(auxdata)) > - return FSCACHE_CHECKAUX_OBSOLETE; > - > - memset(&auxdata, 0, sizeof(auxdata)); > - auxdata.resource_id = tcon->resource_id; > - auxdata.vol_create_time = tcon->vol_create_time; > - auxdata.vol_serial_number = tcon->vol_serial_number; > - > - if (memcmp(data, &auxdata, datalen) != 0) > - return FSCACHE_CHECKAUX_OBSOLETE; > - > - return FSCACHE_CHECKAUX_OKAY; > -} > - > -/* > - * Superblock object for FS-Cache > - */ > -const struct fscache_cookie_def cifs_fscache_super_index_def = { > - .name = "CIFS.super", > - .type = FSCACHE_COOKIE_TYPE_INDEX, > - .check_aux = cifs_fscache_super_check_aux, > -}; > - > -static enum > -fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, > - const void *data, > - uint16_t datalen, > - loff_t object_size) > -{ > - struct cifs_fscache_inode_auxdata auxdata; > - struct cifsInodeInfo *cifsi = cookie_netfs_data; > - > - if (datalen != sizeof(auxdata)) > - return FSCACHE_CHECKAUX_OBSOLETE; > - > - 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; > - > - if (memcmp(data, &auxdata, datalen) != 0) > - return FSCACHE_CHECKAUX_OBSOLETE; > - > - return FSCACHE_CHECKAUX_OKAY; > -} > - > -const struct fscache_cookie_def cifs_fscache_inode_object_def = { > - .name = "CIFS.uniqueid", > - .type = FSCACHE_COOKIE_TYPE_DATAFILE, > - .check_aux = cifs_fscache_inode_check_aux, > -}; > diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c > index dca42aa87d30..26cf2193c9a2 100644 > --- a/fs/cifs/cifsfs.c > +++ b/fs/cifs/cifsfs.c > @@ -396,6 +396,9 @@ static void > cifs_evict_inode(struct inode *inode) > { > truncate_inode_pages_final(&inode->i_data); > + if (inode->i_state & I_PINNING_FSCACHE_WB) > + cifs_fscache_unuse_inode_cookie(inode, true); > + cifs_fscache_release_inode_cookie(inode); > clear_inode(inode); > } > > @@ -720,6 +723,12 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) > } > #endif > > +static int cifs_write_inode(struct inode *inode, struct writeback_control *wbc) > +{ > + fscache_unpin_writeback(wbc, cifs_inode_cookie(inode)); > + return 0; > +} > + > static int cifs_drop_inode(struct inode *inode) > { > struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); > @@ -732,6 +741,7 @@ static int cifs_drop_inode(struct inode *inode) > static const struct super_operations cifs_super_ops = { > .statfs = cifs_statfs, > .alloc_inode = cifs_alloc_inode, > + .write_inode = cifs_write_inode, > .free_inode = cifs_free_inode, > .drop_inode = cifs_drop_inode, > .evict_inode = cifs_evict_inode, > @@ -1624,13 +1634,9 @@ init_cifs(void) > goto out_destroy_cifsoplockd_wq; > } > > - rc = cifs_fscache_register(); > - if (rc) > - goto out_destroy_deferredclose_wq; > - > rc = cifs_init_inodecache(); > if (rc) > - goto out_unreg_fscache; > + goto out_destroy_deferredclose_wq; > > rc = cifs_init_mids(); > if (rc) > @@ -1692,8 +1698,6 @@ init_cifs(void) > cifs_destroy_mids(); > out_destroy_inodecache: > cifs_destroy_inodecache(); > -out_unreg_fscache: > - cifs_fscache_unregister(); > out_destroy_deferredclose_wq: > destroy_workqueue(deferredclose_wq); > out_destroy_cifsoplockd_wq: > @@ -1729,7 +1733,6 @@ exit_cifs(void) > cifs_destroy_request_bufs(); > cifs_destroy_mids(); > cifs_destroy_inodecache(); > - cifs_fscache_unregister(); > destroy_workqueue(deferredclose_wq); > destroy_workqueue(cifsoplockd_wq); > destroy_workqueue(decrypt_wq); > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h > index be74606724c7..ba6fbb1ad8f3 100644 > --- a/fs/cifs/cifsglob.h > +++ b/fs/cifs/cifsglob.h > @@ -659,9 +659,6 @@ struct TCP_Server_Info { > unsigned int total_read; /* total amount of data read in this pass */ > atomic_t in_send; /* requests trying to send */ > atomic_t num_waiters; /* blocked waiting to get in sendrecv */ > -#ifdef CONFIG_CIFS_FSCACHE > - struct fscache_cookie *fscache; /* client index cache cookie */ > -#endif > #ifdef CONFIG_CIFS_STATS2 > atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */ > atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */ > @@ -1117,7 +1114,7 @@ struct cifs_tcon { > __u32 max_bytes_copy; > #ifdef CONFIG_CIFS_FSCACHE > u64 resource_id; /* server resource id */ > - struct fscache_cookie *fscache; /* cookie for share */ > + struct fscache_volume *fscache; /* cookie for share */ > #endif > struct list_head pending_opens; /* list of incomplete opens */ > struct cached_fid crfid; /* Cached root fid */ > diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c > index 1060164b984a..598be9890f2a 100644 > --- a/fs/cifs/connect.c > +++ b/fs/cifs/connect.c > @@ -1396,10 +1396,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) > > cifs_crypto_secmech_release(server); > > - /* fscache server cookies are based on primary channel only */ > - if (!CIFS_SERVER_IS_CHAN(server)) > - cifs_fscache_release_client_cookie(server); > - > kfree(server->session_key.response); > server->session_key.response = NULL; > server->session_key.len = 0; > @@ -1559,14 +1555,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, > list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); > spin_unlock(&cifs_tcp_ses_lock); > > - /* fscache server cookies are based on primary channel only */ > - if (!CIFS_SERVER_IS_CHAN(tcp_ses)) > - cifs_fscache_get_client_cookie(tcp_ses); > -#ifdef CONFIG_CIFS_FSCACHE > - else > - tcp_ses->fscache = tcp_ses->primary_server->fscache; > -#endif /* CONFIG_CIFS_FSCACHE */ > - > /* queue echo request delayed work */ > queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); > > @@ -3069,7 +3057,8 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx) > * Inside cifs_fscache_get_super_cookie it checks > * that we do not get super cookie twice. > */ > - cifs_fscache_get_super_cookie(tcon); > + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) > + cifs_fscache_get_super_cookie(tcon); > > out: > mnt_ctx->server = server; > diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c > index 6e8e7cc26ae2..ce9b22aecfba 100644 > --- a/fs/cifs/dir.c > +++ b/fs/cifs/dir.c > @@ -22,6 +22,7 @@ > #include "cifs_unicode.h" > #include "fs_context.h" > #include "cifs_ioctl.h" > +#include "fscache.h" > > static void > renew_parental_timestamps(struct dentry *direntry) > @@ -507,8 +508,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, > server->ops->close(xid, tcon, &fid); > cifs_del_pending_open(&open); > rc = -ENOMEM; > + goto out; > } > > + fscache_use_cookie(cifs_inode_cookie(file_inode(file)), > + file->f_mode & FMODE_WRITE); > + > out: > cifs_put_tlink(tlink); > out_free_xid: > diff --git a/fs/cifs/file.c b/fs/cifs/file.c > index 9fee3af83a73..fb77ca1a15d8 100644 > --- a/fs/cifs/file.c > +++ b/fs/cifs/file.c > @@ -376,8 +376,6 @@ 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. > @@ -570,7 +568,7 @@ int cifs_open(struct inode *inode, struct file *file) > spin_lock(&CIFS_I(inode)->deferred_lock); > cifs_del_deferred_close(cfile); > spin_unlock(&CIFS_I(inode)->deferred_lock); > - goto out; > + goto use_cache; > } else { > _cifsFileInfo_put(cfile, true, false); > } > @@ -632,8 +630,6 @@ int cifs_open(struct inode *inode, struct file *file) > goto out; > } > > - cifs_fscache_set_inode_cookie(inode, file); > - > if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { > /* > * Time to set mode which we can not set earlier due to > @@ -652,6 +648,19 @@ int cifs_open(struct inode *inode, struct file *file) > cfile->pid); > } > > +use_cache: > + fscache_use_cookie(cifs_inode_cookie(file_inode(file)), > + file->f_mode & FMODE_WRITE); > + if (file->f_flags & O_DIRECT && > + (!((file->f_flags & O_ACCMODE) != O_RDONLY) || > + file->f_flags & O_APPEND)) { > + struct cifs_fscache_inode_coherency_data cd; > + cifs_fscache_fill_coherency(file_inode(file), &cd); > + fscache_invalidate(cifs_inode_cookie(file_inode(file)), > + &cd, i_size_read(file_inode(file)), > + FSCACHE_INVAL_DIO_WRITE); > + } > + > out: > free_dentry_path(page); > free_xid(xid); > @@ -876,6 +885,8 @@ int cifs_close(struct inode *inode, struct file *file) > struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); > struct cifs_deferred_close *dclose; > > + cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE); > + > if (file->private_data != NULL) { > cfile = file->private_data; > file->private_data = NULL; > @@ -886,7 +897,6 @@ int cifs_close(struct inode *inode, struct file *file) > dclose) { > if (test_and_clear_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); > @@ -4198,10 +4208,12 @@ 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); > +#ifdef CONFIG_CIFS_FSCACHE > + if (PageFsCache(page) && > + wait_on_page_fscache_killable(page) < 0) > + return VM_FAULT_RETRY; > +#endif > > lock_page(page); > return VM_FAULT_LOCKED; > @@ -4275,8 +4287,6 @@ cifs_readv_complete(struct work_struct *work) > 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); > > @@ -4593,11 +4603,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, > kref_put(&rdata->refcount, cifs_readdata_release); > } > > - /* Any pages that have been shown to fscache but didn't get added to > - * the pagecache must be uncached before they get returned to the > - * allocator. > - */ > - cifs_fscache_readpages_cancel(mapping->host, page_list); > free_xid(xid); > return rc; > } > @@ -4801,17 +4806,19 @@ static int cifs_release_page(struct page *page, gfp_t gfp) > { > if (PagePrivate(page)) > return 0; > - > - return cifs_fscache_release_page(page, gfp); > + if (PageFsCache(page)) { > + if (current_is_kswapd() || !(gfp & __GFP_FS)) > + return false; > + wait_on_page_fscache(page); > + } > + fscache_note_page_release(cifs_inode_cookie(page->mapping->host)); > + return true; > } > > static void cifs_invalidate_page(struct page *page, unsigned int offset, > unsigned int length) > { > - struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); > - > - if (offset == 0 && length == PAGE_SIZE) > - cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); > + wait_on_page_fscache(page); > } > > static int cifs_launder_page(struct page *page) > @@ -4831,7 +4838,7 @@ static int cifs_launder_page(struct page *page) > if (clear_page_dirty_for_io(page)) > rc = cifs_writepage_locked(page, &wbc); > > - cifs_fscache_invalidate_page(page, page->mapping->host); > + wait_on_page_fscache(page); > return rc; > } > > @@ -4988,6 +4995,19 @@ static void cifs_swap_deactivate(struct file *file) > /* do we need to unpin (or unlock) the file */ > } > > +/* > + * Mark a page as having been made dirty and thus needing writeback. We also > + * need to pin the cache object to write back to. > + */ > +#ifdef CONFIG_CIFS_FSCACHE > +static int cifs_set_page_dirty(struct page *page) > +{ > + return fscache_set_page_dirty(page, cifs_inode_cookie(page->mapping->host)); > +} > +#else > +#define cifs_set_page_dirty __set_page_dirty_nobuffers > +#endif > + > const struct address_space_operations cifs_addr_ops = { > .readpage = cifs_readpage, > .readpages = cifs_readpages, > @@ -4995,7 +5015,7 @@ const struct address_space_operations cifs_addr_ops = { > .writepages = cifs_writepages, > .write_begin = cifs_write_begin, > .write_end = cifs_write_end, > - .set_page_dirty = __set_page_dirty_nobuffers, > + .set_page_dirty = cifs_set_page_dirty, > .releasepage = cifs_release_page, > .direct_IO = cifs_direct_io, > .invalidatepage = cifs_invalidate_page, > @@ -5020,7 +5040,7 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { > .writepages = cifs_writepages, > .write_begin = cifs_write_begin, > .write_end = cifs_write_end, > - .set_page_dirty = __set_page_dirty_nobuffers, > + .set_page_dirty = cifs_set_page_dirty, > .releasepage = cifs_release_page, > .invalidatepage = cifs_invalidate_page, > .launder_page = cifs_launder_page, > diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c > index 003c5f1f4dfb..efaac4d5ff55 100644 > --- a/fs/cifs/fscache.c > +++ b/fs/cifs/fscache.c > @@ -12,250 +12,136 @@ > #include "cifs_fs_sb.h" > #include "cifsproto.h" > > -/* > - * Key layout of CIFS server cache index object > - */ > -struct cifs_server_key { > - __u64 conn_id; > -} __packed; > - > -/* > - * Get a cookie for a server object keyed by {IPaddress,port,family} tuple > - */ > -void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) > -{ > - struct cifs_server_key key; > - > - /* > - * Check if cookie was already initialized so don't reinitialize it. > - * In the future, as we integrate with newer fscache features, > - * we may want to instead add a check if cookie has changed > - */ > - if (server->fscache) > - return; > - > - memset(&key, 0, sizeof(key)); > - key.conn_id = server->conn_id; > - > - server->fscache = > - fscache_acquire_cookie(cifs_fscache_netfs.primary_index, > - &cifs_fscache_server_index_def, > - &key, sizeof(key), > - NULL, 0, > - server, 0, true); > - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", > - __func__, server, server->fscache); > -} > - > -void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) > +static void cifs_fscache_fill_volume_coherency( > + struct cifs_tcon *tcon, > + struct cifs_fscache_volume_coherency_data *cd) > { > - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", > - __func__, server, server->fscache); > - fscache_relinquish_cookie(server->fscache, NULL, false); > - server->fscache = NULL; > + memset(cd, 0, sizeof(*cd)); > + cd->resource_id = cpu_to_le64(tcon->resource_id); > + cd->vol_create_time = tcon->vol_create_time; > + cd->vol_serial_number = cpu_to_le32(tcon->vol_serial_number); > } > > -void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) > +int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) > { > + struct cifs_fscache_volume_coherency_data cd; > struct TCP_Server_Info *server = tcon->ses->server; > + struct fscache_volume *vcookie; > + const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr; > + size_t slen, i; > char *sharename; > - struct cifs_fscache_super_auxdata auxdata; > + char *key; > + int ret = -ENOMEM; > > - /* > - * Check if cookie was already initialized so don't reinitialize it. > - * In the future, as we integrate with newer fscache features, > - * we may want to instead add a check if cookie has changed > - */ > - if (tcon->fscache) > - return; > + tcon->fscache = NULL; > + switch (sa->sa_family) { > + case AF_INET: > + case AF_INET6: > + break; > + default: > + cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); > + return -EINVAL; > + } > + > + memset(&key, 0, sizeof(key)); > > sharename = extract_sharename(tcon->treeName); > if (IS_ERR(sharename)) { > cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); > - tcon->fscache = NULL; > - return; > + return -EINVAL; > } > > - memset(&auxdata, 0, sizeof(auxdata)); > - auxdata.resource_id = tcon->resource_id; > - auxdata.vol_create_time = tcon->vol_create_time; > - auxdata.vol_serial_number = tcon->vol_serial_number; > + slen = strlen(sharename); > + for (i = 0; i < slen; i++) > + if (sharename[i] == '/') > + sharename[i] = ';'; > + > + key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename); > + if (!key) > + goto out; > + > + cifs_fscache_fill_volume_coherency(tcon, &cd); > + vcookie = fscache_acquire_volume(key, > + NULL, /* preferred_cache */ > + &cd, sizeof(cd)); > + cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie); > + if (IS_ERR(vcookie)) { > + if (vcookie != ERR_PTR(-EBUSY)) { > + ret = PTR_ERR(vcookie); > + goto out_2; > + } > + pr_err("Cache volume key already in use (%s)\n", key); > + vcookie = NULL; > + } > > - tcon->fscache = > - fscache_acquire_cookie(server->fscache, > - &cifs_fscache_super_index_def, > - sharename, strlen(sharename), > - &auxdata, sizeof(auxdata), > - tcon, 0, true); > + tcon->fscache = vcookie; > + ret = 0; > +out_2: > + kfree(key); > +out: > kfree(sharename); > - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", > - __func__, server->fscache, tcon->fscache); > + return ret; > } > > void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) > { > - struct cifs_fscache_super_auxdata auxdata; > - > - memset(&auxdata, 0, sizeof(auxdata)); > - auxdata.resource_id = tcon->resource_id; > - auxdata.vol_create_time = tcon->vol_create_time; > - auxdata.vol_serial_number = tcon->vol_serial_number; > + struct cifs_fscache_volume_coherency_data cd; > > cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); > - fscache_relinquish_cookie(tcon->fscache, &auxdata, false); > - tcon->fscache = NULL; > -} > - > -static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi, > - struct cifs_tcon *tcon) > -{ > - struct cifs_fscache_inode_auxdata auxdata; > > - 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; > - > - cifsi->fscache = > - fscache_acquire_cookie(tcon->fscache, > - &cifs_fscache_inode_object_def, > - &cifsi->uniqueid, sizeof(cifsi->uniqueid), > - &auxdata, sizeof(auxdata), > - cifsi, cifsi->vfs_inode.i_size, true); > + cifs_fscache_fill_volume_coherency(tcon, &cd); > + fscache_relinquish_volume(tcon->fscache, &cd, false); > + tcon->fscache = NULL; > } > > -static void cifs_fscache_enable_inode_cookie(struct inode *inode) > +void cifs_fscache_get_inode_cookie(struct inode *inode) > { > + struct cifs_fscache_inode_coherency_data cd; > struct cifsInodeInfo *cifsi = CIFS_I(inode); > struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); > struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); > > - if (cifsi->fscache) > - return; > - > - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)) > - return; > - > - cifs_fscache_acquire_inode_cookie(cifsi, tcon); > + cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); > > - cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", > - __func__, tcon->fscache, cifsi->fscache); > + cifsi->fscache = > + fscache_acquire_cookie(tcon->fscache, 0, > + &cifsi->uniqueid, sizeof(cifsi->uniqueid), > + &cd, sizeof(cd), > + i_size_read(&cifsi->vfs_inode)); > } > > -void cifs_fscache_release_inode_cookie(struct inode *inode) > +void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) > { > - 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; > + if (update) { > + struct cifs_fscache_inode_coherency_data cd; > + loff_t i_size = i_size_read(inode); > > - 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; > + cifs_fscache_fill_coherency(inode, &cd); > + fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size); > + } else { > + fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL); > } > } > > -void cifs_fscache_update_inode_cookie(struct inode *inode) > +void cifs_fscache_release_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_update_cookie(cifsi->fscache, &auxdata); > - } > -} > - > -void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) > -{ > - cifs_fscache_enable_inode_cookie(inode); > -} > - > -void cifs_fscache_reset_inode_cookie(struct inode *inode) > -{ > - struct cifsInodeInfo *cifsi = CIFS_I(inode); > - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); > - struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); > - struct fscache_cookie *old = cifsi->fscache; > - > - if (cifsi->fscache) { > - /* retire the current fscache cache and get a new one */ > - fscache_relinquish_cookie(cifsi->fscache, NULL, true); > - > - cifs_fscache_acquire_inode_cookie(cifsi, tcon); > - cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n", > - __func__, cifsi->fscache, old); > + fscache_relinquish_cookie(cifsi->fscache, false); > + cifsi->fscache = NULL; > } > } > > -int cifs_fscache_release_page(struct page *page, gfp_t gfp) > -{ > - if (PageFsCache(page)) { > - struct inode *inode = page->mapping->host; > - struct cifsInodeInfo *cifsi = CIFS_I(inode); > - > - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", > - __func__, page, cifsi->fscache); > - if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) > - return 0; > - } > - > - return 1; > -} > - > -static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx, > - int error) > -{ > - cifs_dbg(FYI, "%s: (0x%p/%d)\n", __func__, page, error); > - if (!error) > - SetPageUptodate(page); > - unlock_page(page); > -} > - > /* > * Retrieve a page from FS-Cache > */ > int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) > { > - int ret; > - > cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", > __func__, CIFS_I(inode)->fscache, page, inode); > - ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page, > - cifs_readpage_from_fscache_complete, > - NULL, > - GFP_KERNEL); > - switch (ret) { > - > - case 0: /* page found in fscache, read submitted */ > - cifs_dbg(FYI, "%s: submitted\n", __func__); > - return ret; > - case -ENOBUFS: /* page won't be cached */ > - case -ENODATA: /* page not in cache */ > - cifs_dbg(FYI, "%s: %d\n", __func__, ret); > - return 1; > - > - default: > - cifs_dbg(VFS, "unknown error ret = %d\n", ret); > - } > - return ret; > + return -ENOBUFS; // Needs conversion to using netfslib > } > > /* > @@ -266,78 +152,19 @@ int __cifs_readpages_from_fscache(struct inode *inode, > struct list_head *pages, > unsigned *nr_pages) > { > - int ret; > - > cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n", > __func__, CIFS_I(inode)->fscache, *nr_pages, inode); > - ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping, > - pages, nr_pages, > - cifs_readpage_from_fscache_complete, > - NULL, > - mapping_gfp_mask(mapping)); > - switch (ret) { > - case 0: /* read submitted to the cache for all pages */ > - cifs_dbg(FYI, "%s: submitted\n", __func__); > - return ret; > - > - case -ENOBUFS: /* some pages are not cached and can't be */ > - case -ENODATA: /* some pages are not cached */ > - cifs_dbg(FYI, "%s: no page\n", __func__); > - return 1; > - > - default: > - cifs_dbg(FYI, "unknown error ret = %d\n", ret); > - } > - > - return ret; > + return -ENOBUFS; // Needs conversion to using netfslib > } > > 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, > - cifsi->vfs_inode.i_size, GFP_KERNEL); > - if (ret != 0) > - fscache_uncache_page(cifsi->fscache, page); > -} > - > -void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages) > -{ > - cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n", > - __func__, CIFS_I(inode)->fscache, inode); > - fscache_readpages_cancel(CIFS_I(inode)->fscache, pages); > -} > - > -void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) > -{ > - 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); > - 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); > + // Needs conversion to using netfslib > } > diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h > index 9baa1d0f22bd..0fc3f9252c84 100644 > --- a/fs/cifs/fscache.h > +++ b/fs/cifs/fscache.h > @@ -13,84 +13,62 @@ > > #include "cifsglob.h" > > -#ifdef CONFIG_CIFS_FSCACHE > - > /* > - * Auxiliary data attached to CIFS superblock within the cache > + * Coherency data attached to CIFS volume within the cache > */ > -struct cifs_fscache_super_auxdata { > - u64 resource_id; /* unique server resource id */ > +struct cifs_fscache_volume_coherency_data { > + __le64 resource_id; /* unique server resource id */ > __le64 vol_create_time; > - u32 vol_serial_number; > + __le32 vol_serial_number; > } __packed; > > /* > - * Auxiliary data attached to CIFS inode within the cache > + * Coherency data attached to CIFS inode within the cache. > */ > -struct cifs_fscache_inode_auxdata { > - u64 last_write_time_sec; > - u64 last_change_time_sec; > - u32 last_write_time_nsec; > - u32 last_change_time_nsec; > - u64 eof; > +struct cifs_fscache_inode_coherency_data { > + __le64 last_write_time_sec; > + __le64 last_change_time_sec; > + __le32 last_write_time_nsec; > + __le32 last_change_time_nsec; > }; > > -/* > - * cache.c > - */ > -extern struct fscache_netfs cifs_fscache_netfs; > -extern const struct fscache_cookie_def cifs_fscache_server_index_def; > -extern const struct fscache_cookie_def cifs_fscache_super_index_def; > -extern const struct fscache_cookie_def cifs_fscache_inode_object_def; > - > -extern int cifs_fscache_register(void); > -extern void cifs_fscache_unregister(void); > +#ifdef CONFIG_CIFS_FSCACHE > > /* > * fscache.c > */ > -extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); > -extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *); > -extern void cifs_fscache_get_super_cookie(struct cifs_tcon *); > +extern int cifs_fscache_get_super_cookie(struct cifs_tcon *); > extern void cifs_fscache_release_super_cookie(struct cifs_tcon *); > > +extern void cifs_fscache_get_inode_cookie(struct inode *); > 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_unuse_inode_cookie(struct inode *, bool); > + > +static inline > +void cifs_fscache_fill_coherency(struct inode *inode, > + struct cifs_fscache_inode_coherency_data *cd) > +{ > + struct cifsInodeInfo *cifsi = CIFS_I(inode); > + > + memset(cd, 0, sizeof(*cd)); > + cd->last_write_time_sec = cpu_to_le64(cifsi->vfs_inode.i_mtime.tv_sec); > + cd->last_write_time_nsec = cpu_to_le32(cifsi->vfs_inode.i_mtime.tv_nsec); > + cd->last_change_time_sec = cpu_to_le64(cifsi->vfs_inode.i_ctime.tv_sec); > + cd->last_change_time_nsec = cpu_to_le32(cifsi->vfs_inode.i_ctime.tv_nsec); > +} > + > > -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 *, > struct address_space *, > struct list_head *, > unsigned *); > -extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *); > - > extern void __cifs_readpage_to_fscache(struct inode *, struct page *); > > -static inline void cifs_fscache_invalidate_page(struct page *page, > - struct inode *inode) > +static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) > { > - if (PageFsCache(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); > + return CIFS_I(inode)->fscache; > } > > static inline int cifs_readpage_from_fscache(struct inode *inode, > @@ -120,41 +98,20 @@ static inline void cifs_readpage_to_fscache(struct inode *inode, > __cifs_readpage_to_fscache(inode, page); > } > > -static inline void cifs_fscache_readpages_cancel(struct inode *inode, > - struct list_head *pages) > +#else /* CONFIG_CIFS_FSCACHE */ > +static inline > +void cifs_fscache_fill_coherency(struct inode *inode, > + struct cifs_fscache_inode_coherency_data *cd) > { > - if (CIFS_I(inode)->fscache) > - return __cifs_fscache_readpages_cancel(inode, pages); > } > > -#else /* CONFIG_CIFS_FSCACHE */ > -static inline int cifs_fscache_register(void) { return 0; } > -static inline void cifs_fscache_unregister(void) {} > - > -static inline void > -cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {} > -static inline void > -cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {} > -static inline void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) {} > -static inline void > -cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} > +static inline int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) { return 0; } > +static inline void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} > > +static inline void cifs_fscache_get_inode_cookie(struct inode *inode) {} > 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) {} > -static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp) > -{ > - return 1; /* May release page */ > -} > - > -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 void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) {} > +static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; } > > static inline int > cifs_readpage_from_fscache(struct inode *inode, struct page *page) > @@ -173,11 +130,6 @@ static inline int cifs_readpages_from_fscache(struct inode *inode, > static inline void cifs_readpage_to_fscache(struct inode *inode, > struct page *page) {} > > -static inline void cifs_fscache_readpages_cancel(struct inode *inode, > - struct list_head *pages) > -{ > -} > - > #endif /* CONFIG_CIFS_FSCACHE */ > > #endif /* _CIFS_FSCACHE_H */ > diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c > index 279622e4eb1c..9b93e7d3e0e1 100644 > --- a/fs/cifs/inode.c > +++ b/fs/cifs/inode.c > @@ -1298,10 +1298,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) > inode->i_flags |= S_NOATIME | S_NOCMTIME; > if (inode->i_state & I_NEW) { > inode->i_ino = hash; > -#ifdef CONFIG_CIFS_FSCACHE > - /* initialize per-inode cache cookie pointer */ > - CIFS_I(inode)->fscache = NULL; > -#endif > + cifs_fscache_get_inode_cookie(inode); > unlock_new_inode(inode); > } > } > @@ -1370,6 +1367,7 @@ struct inode *cifs_root_iget(struct super_block *sb) > iget_failed(inode); > inode = ERR_PTR(rc); > } > + > out: > kfree(path); > free_xid(xid); > @@ -2257,6 +2255,8 @@ cifs_dentry_needs_reval(struct dentry *dentry) > int > cifs_invalidate_mapping(struct inode *inode) > { > + struct cifs_fscache_inode_coherency_data cd; > + struct cifsInodeInfo *cifsi = CIFS_I(inode); > int rc = 0; > > if (inode->i_mapping && inode->i_mapping->nrpages != 0) { > @@ -2266,7 +2266,8 @@ cifs_invalidate_mapping(struct inode *inode) > __func__, inode); > } > > - cifs_fscache_reset_inode_cookie(inode); > + cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); > + fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0); > return rc; > } > > @@ -2771,8 +2772,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) > goto out; > > if ((attrs->ia_valid & ATTR_SIZE) && > - attrs->ia_size != i_size_read(inode)) > + attrs->ia_size != i_size_read(inode)) { > truncate_setsize(inode, attrs->ia_size); > + fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); > + } > > setattr_copy(&init_user_ns, inode, attrs); > mark_inode_dirty(inode); > @@ -2967,8 +2970,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) > goto cifs_setattr_exit; > > if ((attrs->ia_valid & ATTR_SIZE) && > - attrs->ia_size != i_size_read(inode)) > + attrs->ia_size != i_size_read(inode)) { > truncate_setsize(inode, attrs->ia_size); > + fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); > + } > > setattr_copy(&init_user_ns, inode, attrs); > mark_inode_dirty(inode); > > -- Thanks, Steve
From cb7057158b3d7033da73b302601ac3623a2b5810 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@xxxxxxxxxx> Date: Tue, 18 Jan 2022 13:55:13 +0000 Subject: [PATCH] cifs: Support fscache indexing rewrite Change the cifs filesystem to take account of the changes to fscache's indexing rewrite and reenable caching in cifs. The following changes have been made: (1) The fscache_netfs struct is no more, and there's no need to register the filesystem as a whole. (2) The session cookie is now an fscache_volume cookie, allocated with fscache_acquire_volume(). That takes three parameters: a string representing the "volume" in the index, a string naming the cache to use (or NULL) and a u64 that conveys coherency metadata for the volume. For cifs, I've made it render the volume name string as: "cifs,<ipaddress>,<sharename>" where the sharename has '/' characters replaced with ';'. This probably needs rethinking a bit as the total name could exceed the maximum filename component length. Further, the coherency data is currently just set to 0. It needs something else doing with it - I wonder if it would suffice simply to sum the resource_id, vol_create_time and vol_serial_number or maybe hash them. (3) The fscache_cookie_def is no more and needed information is passed directly to fscache_acquire_cookie(). The cache no longer calls back into the filesystem, but rather metadata changes are indicated at other times. fscache_acquire_cookie() is passed the same keying and coherency information as before. (4) The functions to set/reset cookies are removed and fscache_use_cookie() and fscache_unuse_cookie() are used instead. fscache_use_cookie() is passed a flag to indicate if the cookie is opened for writing. fscache_unuse_cookie() is passed updates for the metadata if we changed it (ie. if the file was opened for writing). These are called when the file is opened or closed. (5) cifs_setattr_*() are made to call fscache_resize() to change the size of the cache object. (6) The functions to read and write data are stubbed out pending a conversion to use netfslib. Changes ======= ver #7: - Removed the accidentally added-back call to get the super cookie in cifs_root_iget(). - Fixed the right call to cifs_fscache_get_super_cookie() to take account of the "-o fsc" mount flag. ver #6: - Moved the change of gfpflags_allow_blocking() to current_is_kswapd() for cifs here. - Fixed one of the error paths in cifs_atomic_open() to jump around the call to use the cookie. - Fixed an additional successful return in the middle of cifs_open() to use the cookie on the way out. - Only get a volume cookie (and thus inode cookies) when "-o fsc" is supplied to mount. ver #5: - Fixed a couple of bits of cookie handling[2]: - The cookie should be released in cifs_evict_inode(), not cifsFileInfo_put_final(). The cookie needs to persist beyond file closure so that writepages will be able to write to it. - fscache_use_cookie() needs to be called in cifs_atomic_open() as it is for cifs_open(). ver #4: - Fixed the use of sizeof with memset. - tcon->vol_create_time is __le64 so doesn't need cpu_to_le64(). ver #3: - Canonicalise the cifs coherency data to make the cache portable. - Set volume coherency data. ver #2: - Use gfpflags_allow_blocking() rather than using flag directly. - Upgraded to -rc4 to allow for upstream changes[1]. - fscache_acquire_volume() now returns errors. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> Acked-by: Jeff Layton <jlayton@xxxxxxxxxx> cc: Steve French <smfrench@xxxxxxxxx> cc: Shyam Prasad N <nspmangalore@xxxxxxxxx> cc: linux-cifs@xxxxxxxxxxxxxxx cc: linux-cachefs@xxxxxxxxxx Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=23b55d673d7527b093cd97b7c217c82e70cd1af0 [1] Link: https://lore.kernel.org/r/3419813.1641592362@xxxxxxxxxxxxxxxxxxxxxx/ [2] Link: https://lore.kernel.org/r/163819671009.215744.11230627184193298714.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v1 Link: https://lore.kernel.org/r/163906982979.143852.10672081929614953210.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v2 Link: https://lore.kernel.org/r/163967187187.1823006.247415138444991444.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v3 Link: https://lore.kernel.org/r/164021579335.640689.2681324337038770579.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v4 Link: https://lore.kernel.org/r/3462849.1641593783@xxxxxxxxxxxxxxxxxxxxxx/ # v5 Link: https://lore.kernel.org/r/1318953.1642024578@xxxxxxxxxxxxxxxxxxxxxx/ # v6 Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/Kconfig | 2 +- fs/cifs/Makefile | 2 +- fs/cifs/cache.c | 105 -------------- fs/cifs/cifsfs.c | 19 +-- fs/cifs/cifsglob.h | 5 +- fs/cifs/connect.c | 15 +- fs/cifs/dir.c | 5 + fs/cifs/file.c | 70 ++++++---- fs/cifs/fscache.c | 333 +++++++++++---------------------------------- fs/cifs/fscache.h | 126 ++++++----------- fs/cifs/inode.c | 19 ++- 11 files changed, 197 insertions(+), 504 deletions(-) delete mode 100644 fs/cifs/cache.c diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 346ae8716deb..3b7e3b9e4fd2 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -188,7 +188,7 @@ config CIFS_SMB_DIRECT config CIFS_FSCACHE bool "Provide CIFS client caching support" - depends on CIFS=m && FSCACHE_OLD_API || CIFS=y && FSCACHE_OLD_API=y + depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y help Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data to be cached locally on disk through the general filesystem cache diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 87fcacdf3de7..cc8fdcb35b71 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -25,7 +25,7 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o -cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o +cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c deleted file mode 100644 index 8be57aaedab6..000000000000 --- a/fs/cifs/cache.c +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1 -/* - * CIFS filesystem cache index structure definitions - * - * Copyright (c) 2010 Novell, Inc. - * Authors(s): Suresh Jayaraman (sjayaraman@xxxxxxx> - * - */ -#include "fscache.h" -#include "cifs_debug.h" - -/* - * CIFS filesystem definition for FS-Cache - */ -struct fscache_netfs cifs_fscache_netfs = { - .name = "cifs", - .version = 0, -}; - -/* - * Register CIFS for caching with FS-Cache - */ -int cifs_fscache_register(void) -{ - return fscache_register_netfs(&cifs_fscache_netfs); -} - -/* - * Unregister CIFS for caching - */ -void cifs_fscache_unregister(void) -{ - fscache_unregister_netfs(&cifs_fscache_netfs); -} - -/* - * Server object for FS-Cache - */ -const struct fscache_cookie_def cifs_fscache_server_index_def = { - .name = "CIFS.server", - .type = FSCACHE_COOKIE_TYPE_INDEX, -}; - -static enum -fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, - const void *data, - uint16_t datalen, - loff_t object_size) -{ - struct cifs_fscache_super_auxdata auxdata; - const struct cifs_tcon *tcon = cookie_netfs_data; - - if (datalen != sizeof(auxdata)) - return FSCACHE_CHECKAUX_OBSOLETE; - - memset(&auxdata, 0, sizeof(auxdata)); - auxdata.resource_id = tcon->resource_id; - auxdata.vol_create_time = tcon->vol_create_time; - auxdata.vol_serial_number = tcon->vol_serial_number; - - if (memcmp(data, &auxdata, datalen) != 0) - return FSCACHE_CHECKAUX_OBSOLETE; - - return FSCACHE_CHECKAUX_OKAY; -} - -/* - * Superblock object for FS-Cache - */ -const struct fscache_cookie_def cifs_fscache_super_index_def = { - .name = "CIFS.super", - .type = FSCACHE_COOKIE_TYPE_INDEX, - .check_aux = cifs_fscache_super_check_aux, -}; - -static enum -fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, - const void *data, - uint16_t datalen, - loff_t object_size) -{ - struct cifs_fscache_inode_auxdata auxdata; - struct cifsInodeInfo *cifsi = cookie_netfs_data; - - if (datalen != sizeof(auxdata)) - return FSCACHE_CHECKAUX_OBSOLETE; - - 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; - - if (memcmp(data, &auxdata, datalen) != 0) - return FSCACHE_CHECKAUX_OBSOLETE; - - return FSCACHE_CHECKAUX_OKAY; -} - -const struct fscache_cookie_def cifs_fscache_inode_object_def = { - .name = "CIFS.uniqueid", - .type = FSCACHE_COOKIE_TYPE_DATAFILE, - .check_aux = cifs_fscache_inode_check_aux, -}; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 36b2e0cb9736..199edac0cb59 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -397,6 +397,9 @@ static void cifs_evict_inode(struct inode *inode) { truncate_inode_pages_final(&inode->i_data); + if (inode->i_state & I_PINNING_FSCACHE_WB) + cifs_fscache_unuse_inode_cookie(inode, true); + cifs_fscache_release_inode_cookie(inode); clear_inode(inode); } @@ -721,6 +724,12 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) } #endif +static int cifs_write_inode(struct inode *inode, struct writeback_control *wbc) +{ + fscache_unpin_writeback(wbc, cifs_inode_cookie(inode)); + return 0; +} + static int cifs_drop_inode(struct inode *inode) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -733,6 +742,7 @@ static int cifs_drop_inode(struct inode *inode) static const struct super_operations cifs_super_ops = { .statfs = cifs_statfs, .alloc_inode = cifs_alloc_inode, + .write_inode = cifs_write_inode, .free_inode = cifs_free_inode, .drop_inode = cifs_drop_inode, .evict_inode = cifs_evict_inode, @@ -1625,13 +1635,9 @@ init_cifs(void) goto out_destroy_cifsoplockd_wq; } - rc = cifs_fscache_register(); - if (rc) - goto out_destroy_deferredclose_wq; - rc = cifs_init_inodecache(); if (rc) - goto out_unreg_fscache; + goto out_destroy_deferredclose_wq; rc = cifs_init_mids(); if (rc) @@ -1693,8 +1699,6 @@ init_cifs(void) cifs_destroy_mids(); out_destroy_inodecache: cifs_destroy_inodecache(); -out_unreg_fscache: - cifs_fscache_unregister(); out_destroy_deferredclose_wq: destroy_workqueue(deferredclose_wq); out_destroy_cifsoplockd_wq: @@ -1730,7 +1734,6 @@ exit_cifs(void) cifs_destroy_request_bufs(); cifs_destroy_mids(); cifs_destroy_inodecache(); - cifs_fscache_unregister(); destroy_workqueue(deferredclose_wq); destroy_workqueue(cifsoplockd_wq); destroy_workqueue(decrypt_wq); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cace0818d510..48b343d03430 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -668,9 +668,6 @@ struct TCP_Server_Info { unsigned int total_read; /* total amount of data read in this pass */ atomic_t in_send; /* requests trying to send */ atomic_t num_waiters; /* blocked waiting to get in sendrecv */ -#ifdef CONFIG_CIFS_FSCACHE - struct fscache_cookie *fscache; /* client index cache cookie */ -#endif #ifdef CONFIG_CIFS_STATS2 atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */ atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */ @@ -1112,7 +1109,7 @@ struct cifs_tcon { __u32 max_bytes_copy; #ifdef CONFIG_CIFS_FSCACHE u64 resource_id; /* server resource id */ - struct fscache_cookie *fscache; /* cookie for share */ + struct fscache_volume *fscache; /* cookie for share */ #endif struct list_head pending_opens; /* list of incomplete opens */ struct cached_fid crfid; /* Cached root fid */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 453aba3c2ad6..11a22a30ee14 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1444,10 +1444,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) cifs_crypto_secmech_release(server); - /* fscache server cookies are based on primary channel only */ - if (!CIFS_SERVER_IS_CHAN(server)) - cifs_fscache_release_client_cookie(server); - kfree(server->session_key.response); server->session_key.response = NULL; server->session_key.len = 0; @@ -1609,14 +1605,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); spin_unlock(&cifs_tcp_ses_lock); - /* fscache server cookies are based on primary channel only */ - if (!CIFS_SERVER_IS_CHAN(tcp_ses)) - cifs_fscache_get_client_cookie(tcp_ses); -#ifdef CONFIG_CIFS_FSCACHE - else - tcp_ses->fscache = tcp_ses->primary_server->fscache; -#endif /* CONFIG_CIFS_FSCACHE */ - /* queue echo request delayed work */ queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); @@ -3128,7 +3116,8 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx) * Inside cifs_fscache_get_super_cookie it checks * that we do not get super cookie twice. */ - cifs_fscache_get_super_cookie(tcon); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) + cifs_fscache_get_super_cookie(tcon); out: mnt_ctx->server = server; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 6e8e7cc26ae2..ce9b22aecfba 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -22,6 +22,7 @@ #include "cifs_unicode.h" #include "fs_context.h" #include "cifs_ioctl.h" +#include "fscache.h" static void renew_parental_timestamps(struct dentry *direntry) @@ -507,8 +508,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, server->ops->close(xid, tcon, &fid); cifs_del_pending_open(&open); rc = -ENOMEM; + goto out; } + fscache_use_cookie(cifs_inode_cookie(file_inode(file)), + file->f_mode & FMODE_WRITE); + out: cifs_put_tlink(tlink); out_free_xid: diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 9fee3af83a73..fb77ca1a15d8 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -376,8 +376,6 @@ 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. @@ -570,7 +568,7 @@ int cifs_open(struct inode *inode, struct file *file) spin_lock(&CIFS_I(inode)->deferred_lock); cifs_del_deferred_close(cfile); spin_unlock(&CIFS_I(inode)->deferred_lock); - goto out; + goto use_cache; } else { _cifsFileInfo_put(cfile, true, false); } @@ -632,8 +630,6 @@ int cifs_open(struct inode *inode, struct file *file) goto out; } - cifs_fscache_set_inode_cookie(inode, file); - if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { /* * Time to set mode which we can not set earlier due to @@ -652,6 +648,19 @@ int cifs_open(struct inode *inode, struct file *file) cfile->pid); } +use_cache: + fscache_use_cookie(cifs_inode_cookie(file_inode(file)), + file->f_mode & FMODE_WRITE); + if (file->f_flags & O_DIRECT && + (!((file->f_flags & O_ACCMODE) != O_RDONLY) || + file->f_flags & O_APPEND)) { + struct cifs_fscache_inode_coherency_data cd; + + cifs_fscache_fill_coherency(file_inode(file), &cd); + fscache_invalidate(cifs_inode_cookie(file_inode(file)), + &cd, i_size_read(file_inode(file)), + FSCACHE_INVAL_DIO_WRITE); + } out: free_dentry_path(page); free_xid(xid); @@ -876,6 +885,8 @@ int cifs_close(struct inode *inode, struct file *file) struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_deferred_close *dclose; + cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE); + if (file->private_data != NULL) { cfile = file->private_data; file->private_data = NULL; @@ -886,7 +897,6 @@ int cifs_close(struct inode *inode, struct file *file) dclose) { if (test_and_clear_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); @@ -4198,10 +4208,12 @@ 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); +#ifdef CONFIG_CIFS_FSCACHE + if (PageFsCache(page) && + wait_on_page_fscache_killable(page) < 0) + return VM_FAULT_RETRY; +#endif lock_page(page); return VM_FAULT_LOCKED; @@ -4275,8 +4287,6 @@ cifs_readv_complete(struct work_struct *work) 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); @@ -4593,11 +4603,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, kref_put(&rdata->refcount, cifs_readdata_release); } - /* Any pages that have been shown to fscache but didn't get added to - * the pagecache must be uncached before they get returned to the - * allocator. - */ - cifs_fscache_readpages_cancel(mapping->host, page_list); free_xid(xid); return rc; } @@ -4801,17 +4806,19 @@ static int cifs_release_page(struct page *page, gfp_t gfp) { if (PagePrivate(page)) return 0; - - return cifs_fscache_release_page(page, gfp); + if (PageFsCache(page)) { + if (current_is_kswapd() || !(gfp & __GFP_FS)) + return false; + wait_on_page_fscache(page); + } + fscache_note_page_release(cifs_inode_cookie(page->mapping->host)); + return true; } static void cifs_invalidate_page(struct page *page, unsigned int offset, unsigned int length) { - struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); - - if (offset == 0 && length == PAGE_SIZE) - cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); + wait_on_page_fscache(page); } static int cifs_launder_page(struct page *page) @@ -4831,7 +4838,7 @@ static int cifs_launder_page(struct page *page) if (clear_page_dirty_for_io(page)) rc = cifs_writepage_locked(page, &wbc); - cifs_fscache_invalidate_page(page, page->mapping->host); + wait_on_page_fscache(page); return rc; } @@ -4988,6 +4995,19 @@ static void cifs_swap_deactivate(struct file *file) /* do we need to unpin (or unlock) the file */ } +/* + * Mark a page as having been made dirty and thus needing writeback. We also + * need to pin the cache object to write back to. + */ +#ifdef CONFIG_CIFS_FSCACHE +static int cifs_set_page_dirty(struct page *page) +{ + return fscache_set_page_dirty(page, cifs_inode_cookie(page->mapping->host)); +} +#else +#define cifs_set_page_dirty __set_page_dirty_nobuffers +#endif + const struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, @@ -4995,7 +5015,7 @@ const struct address_space_operations cifs_addr_ops = { .writepages = cifs_writepages, .write_begin = cifs_write_begin, .write_end = cifs_write_end, - .set_page_dirty = __set_page_dirty_nobuffers, + .set_page_dirty = cifs_set_page_dirty, .releasepage = cifs_release_page, .direct_IO = cifs_direct_io, .invalidatepage = cifs_invalidate_page, @@ -5020,7 +5040,7 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { .writepages = cifs_writepages, .write_begin = cifs_write_begin, .write_end = cifs_write_end, - .set_page_dirty = __set_page_dirty_nobuffers, + .set_page_dirty = cifs_set_page_dirty, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, .launder_page = cifs_launder_page, diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 003c5f1f4dfb..efaac4d5ff55 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -12,250 +12,136 @@ #include "cifs_fs_sb.h" #include "cifsproto.h" -/* - * Key layout of CIFS server cache index object - */ -struct cifs_server_key { - __u64 conn_id; -} __packed; - -/* - * Get a cookie for a server object keyed by {IPaddress,port,family} tuple - */ -void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) -{ - struct cifs_server_key key; - - /* - * Check if cookie was already initialized so don't reinitialize it. - * In the future, as we integrate with newer fscache features, - * we may want to instead add a check if cookie has changed - */ - if (server->fscache) - return; - - memset(&key, 0, sizeof(key)); - key.conn_id = server->conn_id; - - server->fscache = - fscache_acquire_cookie(cifs_fscache_netfs.primary_index, - &cifs_fscache_server_index_def, - &key, sizeof(key), - NULL, 0, - server, 0, true); - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", - __func__, server, server->fscache); -} - -void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) +static void cifs_fscache_fill_volume_coherency( + struct cifs_tcon *tcon, + struct cifs_fscache_volume_coherency_data *cd) { - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", - __func__, server, server->fscache); - fscache_relinquish_cookie(server->fscache, NULL, false); - server->fscache = NULL; + memset(cd, 0, sizeof(*cd)); + cd->resource_id = cpu_to_le64(tcon->resource_id); + cd->vol_create_time = tcon->vol_create_time; + cd->vol_serial_number = cpu_to_le32(tcon->vol_serial_number); } -void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) +int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) { + struct cifs_fscache_volume_coherency_data cd; struct TCP_Server_Info *server = tcon->ses->server; + struct fscache_volume *vcookie; + const struct sockaddr *sa = (struct sockaddr *)&server->dstaddr; + size_t slen, i; char *sharename; - struct cifs_fscache_super_auxdata auxdata; + char *key; + int ret = -ENOMEM; - /* - * Check if cookie was already initialized so don't reinitialize it. - * In the future, as we integrate with newer fscache features, - * we may want to instead add a check if cookie has changed - */ - if (tcon->fscache) - return; + tcon->fscache = NULL; + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family); + return -EINVAL; + } + + memset(&key, 0, sizeof(key)); sharename = extract_sharename(tcon->treeName); if (IS_ERR(sharename)) { cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__); - tcon->fscache = NULL; - return; + return -EINVAL; } - memset(&auxdata, 0, sizeof(auxdata)); - auxdata.resource_id = tcon->resource_id; - auxdata.vol_create_time = tcon->vol_create_time; - auxdata.vol_serial_number = tcon->vol_serial_number; + slen = strlen(sharename); + for (i = 0; i < slen; i++) + if (sharename[i] == '/') + sharename[i] = ';'; + + key = kasprintf(GFP_KERNEL, "cifs,%pISpc,%s", sa, sharename); + if (!key) + goto out; + + cifs_fscache_fill_volume_coherency(tcon, &cd); + vcookie = fscache_acquire_volume(key, + NULL, /* preferred_cache */ + &cd, sizeof(cd)); + cifs_dbg(FYI, "%s: (%s/0x%p)\n", __func__, key, vcookie); + if (IS_ERR(vcookie)) { + if (vcookie != ERR_PTR(-EBUSY)) { + ret = PTR_ERR(vcookie); + goto out_2; + } + pr_err("Cache volume key already in use (%s)\n", key); + vcookie = NULL; + } - tcon->fscache = - fscache_acquire_cookie(server->fscache, - &cifs_fscache_super_index_def, - sharename, strlen(sharename), - &auxdata, sizeof(auxdata), - tcon, 0, true); + tcon->fscache = vcookie; + ret = 0; +out_2: + kfree(key); +out: kfree(sharename); - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", - __func__, server->fscache, tcon->fscache); + return ret; } void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) { - struct cifs_fscache_super_auxdata auxdata; - - memset(&auxdata, 0, sizeof(auxdata)); - auxdata.resource_id = tcon->resource_id; - auxdata.vol_create_time = tcon->vol_create_time; - auxdata.vol_serial_number = tcon->vol_serial_number; + struct cifs_fscache_volume_coherency_data cd; cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); - fscache_relinquish_cookie(tcon->fscache, &auxdata, false); - tcon->fscache = NULL; -} - -static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi, - struct cifs_tcon *tcon) -{ - struct cifs_fscache_inode_auxdata auxdata; - 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; - - cifsi->fscache = - fscache_acquire_cookie(tcon->fscache, - &cifs_fscache_inode_object_def, - &cifsi->uniqueid, sizeof(cifsi->uniqueid), - &auxdata, sizeof(auxdata), - cifsi, cifsi->vfs_inode.i_size, true); + cifs_fscache_fill_volume_coherency(tcon, &cd); + fscache_relinquish_volume(tcon->fscache, &cd, false); + tcon->fscache = NULL; } -static void cifs_fscache_enable_inode_cookie(struct inode *inode) +void cifs_fscache_get_inode_cookie(struct inode *inode) { + struct cifs_fscache_inode_coherency_data cd; struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); - if (cifsi->fscache) - return; - - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)) - return; - - cifs_fscache_acquire_inode_cookie(cifsi, tcon); + cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); - cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", - __func__, tcon->fscache, cifsi->fscache); + cifsi->fscache = + fscache_acquire_cookie(tcon->fscache, 0, + &cifsi->uniqueid, sizeof(cifsi->uniqueid), + &cd, sizeof(cd), + i_size_read(&cifsi->vfs_inode)); } -void cifs_fscache_release_inode_cookie(struct inode *inode) +void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) { - 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; + if (update) { + struct cifs_fscache_inode_coherency_data cd; + loff_t i_size = i_size_read(inode); - 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; + cifs_fscache_fill_coherency(inode, &cd); + fscache_unuse_cookie(cifs_inode_cookie(inode), &cd, &i_size); + } else { + fscache_unuse_cookie(cifs_inode_cookie(inode), NULL, NULL); } } -void cifs_fscache_update_inode_cookie(struct inode *inode) +void cifs_fscache_release_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_update_cookie(cifsi->fscache, &auxdata); - } -} - -void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) -{ - cifs_fscache_enable_inode_cookie(inode); -} - -void cifs_fscache_reset_inode_cookie(struct inode *inode) -{ - struct cifsInodeInfo *cifsi = CIFS_I(inode); - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); - struct fscache_cookie *old = cifsi->fscache; - - if (cifsi->fscache) { - /* retire the current fscache cache and get a new one */ - fscache_relinquish_cookie(cifsi->fscache, NULL, true); - - cifs_fscache_acquire_inode_cookie(cifsi, tcon); - cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n", - __func__, cifsi->fscache, old); + fscache_relinquish_cookie(cifsi->fscache, false); + cifsi->fscache = NULL; } } -int cifs_fscache_release_page(struct page *page, gfp_t gfp) -{ - if (PageFsCache(page)) { - struct inode *inode = page->mapping->host; - struct cifsInodeInfo *cifsi = CIFS_I(inode); - - cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", - __func__, page, cifsi->fscache); - if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) - return 0; - } - - return 1; -} - -static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx, - int error) -{ - cifs_dbg(FYI, "%s: (0x%p/%d)\n", __func__, page, error); - if (!error) - SetPageUptodate(page); - unlock_page(page); -} - /* * Retrieve a page from FS-Cache */ int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) { - int ret; - cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n", __func__, CIFS_I(inode)->fscache, page, inode); - ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page, - cifs_readpage_from_fscache_complete, - NULL, - GFP_KERNEL); - switch (ret) { - - case 0: /* page found in fscache, read submitted */ - cifs_dbg(FYI, "%s: submitted\n", __func__); - return ret; - case -ENOBUFS: /* page won't be cached */ - case -ENODATA: /* page not in cache */ - cifs_dbg(FYI, "%s: %d\n", __func__, ret); - return 1; - - default: - cifs_dbg(VFS, "unknown error ret = %d\n", ret); - } - return ret; + return -ENOBUFS; // Needs conversion to using netfslib } /* @@ -266,78 +152,19 @@ int __cifs_readpages_from_fscache(struct inode *inode, struct list_head *pages, unsigned *nr_pages) { - int ret; - cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n", __func__, CIFS_I(inode)->fscache, *nr_pages, inode); - ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping, - pages, nr_pages, - cifs_readpage_from_fscache_complete, - NULL, - mapping_gfp_mask(mapping)); - switch (ret) { - case 0: /* read submitted to the cache for all pages */ - cifs_dbg(FYI, "%s: submitted\n", __func__); - return ret; - - case -ENOBUFS: /* some pages are not cached and can't be */ - case -ENODATA: /* some pages are not cached */ - cifs_dbg(FYI, "%s: no page\n", __func__); - return 1; - - default: - cifs_dbg(FYI, "unknown error ret = %d\n", ret); - } - - return ret; + return -ENOBUFS; // Needs conversion to using netfslib } 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, - cifsi->vfs_inode.i_size, GFP_KERNEL); - if (ret != 0) - fscache_uncache_page(cifsi->fscache, page); -} - -void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages) -{ - cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n", - __func__, CIFS_I(inode)->fscache, inode); - fscache_readpages_cancel(CIFS_I(inode)->fscache, pages); -} - -void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) -{ - 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); - 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); + // Needs conversion to using netfslib } diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 9baa1d0f22bd..0fc3f9252c84 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -13,84 +13,62 @@ #include "cifsglob.h" -#ifdef CONFIG_CIFS_FSCACHE - /* - * Auxiliary data attached to CIFS superblock within the cache + * Coherency data attached to CIFS volume within the cache */ -struct cifs_fscache_super_auxdata { - u64 resource_id; /* unique server resource id */ +struct cifs_fscache_volume_coherency_data { + __le64 resource_id; /* unique server resource id */ __le64 vol_create_time; - u32 vol_serial_number; + __le32 vol_serial_number; } __packed; /* - * Auxiliary data attached to CIFS inode within the cache + * Coherency data attached to CIFS inode within the cache. */ -struct cifs_fscache_inode_auxdata { - u64 last_write_time_sec; - u64 last_change_time_sec; - u32 last_write_time_nsec; - u32 last_change_time_nsec; - u64 eof; +struct cifs_fscache_inode_coherency_data { + __le64 last_write_time_sec; + __le64 last_change_time_sec; + __le32 last_write_time_nsec; + __le32 last_change_time_nsec; }; -/* - * cache.c - */ -extern struct fscache_netfs cifs_fscache_netfs; -extern const struct fscache_cookie_def cifs_fscache_server_index_def; -extern const struct fscache_cookie_def cifs_fscache_super_index_def; -extern const struct fscache_cookie_def cifs_fscache_inode_object_def; - -extern int cifs_fscache_register(void); -extern void cifs_fscache_unregister(void); +#ifdef CONFIG_CIFS_FSCACHE /* * fscache.c */ -extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); -extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *); -extern void cifs_fscache_get_super_cookie(struct cifs_tcon *); +extern int cifs_fscache_get_super_cookie(struct cifs_tcon *); extern void cifs_fscache_release_super_cookie(struct cifs_tcon *); +extern void cifs_fscache_get_inode_cookie(struct inode *pinode); 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_unuse_inode_cookie(struct inode *pinode, bool update); + +static inline +void cifs_fscache_fill_coherency(struct inode *inode, + struct cifs_fscache_inode_coherency_data *cd) +{ + struct cifsInodeInfo *cifsi = CIFS_I(inode); + + memset(cd, 0, sizeof(*cd)); + cd->last_write_time_sec = cpu_to_le64(cifsi->vfs_inode.i_mtime.tv_sec); + cd->last_write_time_nsec = cpu_to_le32(cifsi->vfs_inode.i_mtime.tv_nsec); + cd->last_change_time_sec = cpu_to_le64(cifsi->vfs_inode.i_ctime.tv_sec); + cd->last_change_time_nsec = cpu_to_le32(cifsi->vfs_inode.i_ctime.tv_nsec); +} + -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 *, struct address_space *, struct list_head *, unsigned *); -extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *); - extern void __cifs_readpage_to_fscache(struct inode *, struct page *); -static inline void cifs_fscache_invalidate_page(struct page *page, - struct inode *inode) +static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { - if (PageFsCache(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); + return CIFS_I(inode)->fscache; } static inline int cifs_readpage_from_fscache(struct inode *inode, @@ -120,41 +98,20 @@ static inline void cifs_readpage_to_fscache(struct inode *inode, __cifs_readpage_to_fscache(inode, page); } -static inline void cifs_fscache_readpages_cancel(struct inode *inode, - struct list_head *pages) +#else /* CONFIG_CIFS_FSCACHE */ +static inline +void cifs_fscache_fill_coherency(struct inode *inode, + struct cifs_fscache_inode_coherency_data *cd) { - if (CIFS_I(inode)->fscache) - return __cifs_fscache_readpages_cancel(inode, pages); } -#else /* CONFIG_CIFS_FSCACHE */ -static inline int cifs_fscache_register(void) { return 0; } -static inline void cifs_fscache_unregister(void) {} - -static inline void -cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {} -static inline void -cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {} -static inline void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) {} -static inline void -cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} +static inline int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) { return 0; } +static inline void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} +static inline void cifs_fscache_get_inode_cookie(struct inode *inode) {} 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) {} -static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp) -{ - return 1; /* May release page */ -} - -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 void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) {} +static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; } static inline int cifs_readpage_from_fscache(struct inode *inode, struct page *page) @@ -173,11 +130,6 @@ static inline int cifs_readpages_from_fscache(struct inode *inode, static inline void cifs_readpage_to_fscache(struct inode *inode, struct page *page) {} -static inline void cifs_fscache_readpages_cancel(struct inode *inode, - struct list_head *pages) -{ -} - #endif /* CONFIG_CIFS_FSCACHE */ #endif /* _CIFS_FSCACHE_H */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index baa197edd8c5..7d8b3ceb2af3 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1304,10 +1304,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) inode->i_flags |= S_NOATIME | S_NOCMTIME; if (inode->i_state & I_NEW) { inode->i_ino = hash; -#ifdef CONFIG_CIFS_FSCACHE - /* initialize per-inode cache cookie pointer */ - CIFS_I(inode)->fscache = NULL; -#endif + cifs_fscache_get_inode_cookie(inode); unlock_new_inode(inode); } } @@ -1376,6 +1373,7 @@ struct inode *cifs_root_iget(struct super_block *sb) iget_failed(inode); inode = ERR_PTR(rc); } + out: kfree(path); free_xid(xid); @@ -2263,6 +2261,8 @@ cifs_dentry_needs_reval(struct dentry *dentry) int cifs_invalidate_mapping(struct inode *inode) { + struct cifs_fscache_inode_coherency_data cd; + struct cifsInodeInfo *cifsi = CIFS_I(inode); int rc = 0; if (inode->i_mapping && inode->i_mapping->nrpages != 0) { @@ -2272,7 +2272,8 @@ cifs_invalidate_mapping(struct inode *inode) __func__, inode); } - cifs_fscache_reset_inode_cookie(inode); + cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd); + fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0); return rc; } @@ -2777,8 +2778,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) goto out; if ((attrs->ia_valid & ATTR_SIZE) && - attrs->ia_size != i_size_read(inode)) + attrs->ia_size != i_size_read(inode)) { truncate_setsize(inode, attrs->ia_size); + fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); + } setattr_copy(&init_user_ns, inode, attrs); mark_inode_dirty(inode); @@ -2973,8 +2976,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) goto cifs_setattr_exit; if ((attrs->ia_valid & ATTR_SIZE) && - attrs->ia_size != i_size_read(inode)) + attrs->ia_size != i_size_read(inode)) { truncate_setsize(inode, attrs->ia_size); + fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); + } setattr_copy(&init_user_ns, inode, attrs); mark_inode_dirty(inode); -- 2.32.0