Commit 70431bfd authored by David Howells's avatar David Howells Committed by Steve French

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 #8:
 - Abstract cache invalidation into a helper function.
 - Fix some checkpatch warnings[3].

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: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarJeff Layton <jlayton@kernel.org>
cc: Steve French <smfrench@gmail.com>
cc: Shyam Prasad N <nspmangalore@gmail.com>
cc: linux-cifs@vger.kernel.org
cc: linux-cachefs@redhat.com
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@warthog.procyon.org.uk/ [2]
Link: https://lore.kernel.org/r/CAH2r5muTanw9pJqzAHd01d9A8keeChkzGsCEH6=0rHutVLAF-A@mail.gmail.com/ [3]
Link: https://lore.kernel.org/r/163819671009.215744.11230627184193298714.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906982979.143852.10672081929614953210.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967187187.1823006.247415138444991444.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021579335.640689.2681324337038770579.stgit@warthog.procyon.org.uk/ # v4
Link: https://lore.kernel.org/r/3462849.1641593783@warthog.procyon.org.uk/ # v5
Link: https://lore.kernel.org/r/1318953.1642024578@warthog.procyon.org.uk/ # v6
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent ba978e83
...@@ -188,7 +188,7 @@ config CIFS_SMB_DIRECT ...@@ -188,7 +188,7 @@ config CIFS_SMB_DIRECT
config CIFS_FSCACHE config CIFS_FSCACHE
bool "Provide CIFS client caching support" 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 help
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data 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 to be cached locally on disk through the general filesystem cache
......
...@@ -25,7 +25,7 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o ...@@ -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_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 cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
......
// SPDX-License-Identifier: LGPL-2.1
/*
* CIFS filesystem cache index structure definitions
*
* Copyright (c) 2010 Novell, Inc.
* Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
*
*/
#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,
};
...@@ -397,6 +397,9 @@ static void ...@@ -397,6 +397,9 @@ static void
cifs_evict_inode(struct inode *inode) cifs_evict_inode(struct inode *inode)
{ {
truncate_inode_pages_final(&inode->i_data); 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); clear_inode(inode);
} }
...@@ -721,6 +724,12 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) ...@@ -721,6 +724,12 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)
} }
#endif #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) static int cifs_drop_inode(struct inode *inode)
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
...@@ -733,6 +742,7 @@ static int cifs_drop_inode(struct inode *inode) ...@@ -733,6 +742,7 @@ static int cifs_drop_inode(struct inode *inode)
static const struct super_operations cifs_super_ops = { static const struct super_operations cifs_super_ops = {
.statfs = cifs_statfs, .statfs = cifs_statfs,
.alloc_inode = cifs_alloc_inode, .alloc_inode = cifs_alloc_inode,
.write_inode = cifs_write_inode,
.free_inode = cifs_free_inode, .free_inode = cifs_free_inode,
.drop_inode = cifs_drop_inode, .drop_inode = cifs_drop_inode,
.evict_inode = cifs_evict_inode, .evict_inode = cifs_evict_inode,
...@@ -1625,13 +1635,9 @@ init_cifs(void) ...@@ -1625,13 +1635,9 @@ init_cifs(void)
goto out_destroy_cifsoplockd_wq; goto out_destroy_cifsoplockd_wq;
} }
rc = cifs_fscache_register();
if (rc)
goto out_destroy_deferredclose_wq;
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (rc) if (rc)
goto out_unreg_fscache; goto out_destroy_deferredclose_wq;
rc = cifs_init_mids(); rc = cifs_init_mids();
if (rc) if (rc)
...@@ -1693,8 +1699,6 @@ init_cifs(void) ...@@ -1693,8 +1699,6 @@ init_cifs(void)
cifs_destroy_mids(); cifs_destroy_mids();
out_destroy_inodecache: out_destroy_inodecache:
cifs_destroy_inodecache(); cifs_destroy_inodecache();
out_unreg_fscache:
cifs_fscache_unregister();
out_destroy_deferredclose_wq: out_destroy_deferredclose_wq:
destroy_workqueue(deferredclose_wq); destroy_workqueue(deferredclose_wq);
out_destroy_cifsoplockd_wq: out_destroy_cifsoplockd_wq:
...@@ -1730,7 +1734,6 @@ exit_cifs(void) ...@@ -1730,7 +1734,6 @@ exit_cifs(void)
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
cifs_destroy_mids(); cifs_destroy_mids();
cifs_destroy_inodecache(); cifs_destroy_inodecache();
cifs_fscache_unregister();
destroy_workqueue(deferredclose_wq); destroy_workqueue(deferredclose_wq);
destroy_workqueue(cifsoplockd_wq); destroy_workqueue(cifsoplockd_wq);
destroy_workqueue(decrypt_wq); destroy_workqueue(decrypt_wq);
......
...@@ -668,9 +668,6 @@ struct TCP_Server_Info { ...@@ -668,9 +668,6 @@ struct TCP_Server_Info {
unsigned int total_read; /* total amount of data read in this pass */ unsigned int total_read; /* total amount of data read in this pass */
atomic_t in_send; /* requests trying to send */ atomic_t in_send; /* requests trying to send */
atomic_t num_waiters; /* blocked waiting to get in sendrecv */ 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 #ifdef CONFIG_CIFS_STATS2
atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */ atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */
atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */ atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */
...@@ -1112,7 +1109,7 @@ struct cifs_tcon { ...@@ -1112,7 +1109,7 @@ struct cifs_tcon {
__u32 max_bytes_copy; __u32 max_bytes_copy;
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
u64 resource_id; /* server resource id */ u64 resource_id; /* server resource id */
struct fscache_cookie *fscache; /* cookie for share */ struct fscache_volume *fscache; /* cookie for share */
#endif #endif
struct list_head pending_opens; /* list of incomplete opens */ struct list_head pending_opens; /* list of incomplete opens */
struct cached_fid crfid; /* Cached root fid */ struct cached_fid crfid; /* Cached root fid */
......
...@@ -1444,10 +1444,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) ...@@ -1444,10 +1444,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
cifs_crypto_secmech_release(server); 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); kfree(server->session_key.response);
server->session_key.response = NULL; server->session_key.response = NULL;
server->session_key.len = 0; server->session_key.len = 0;
...@@ -1609,14 +1605,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, ...@@ -1609,14 +1605,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
spin_unlock(&cifs_tcp_ses_lock); 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 echo request delayed work */
queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
...@@ -3128,6 +3116,7 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx) ...@@ -3128,6 +3116,7 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
* Inside cifs_fscache_get_super_cookie it checks * Inside cifs_fscache_get_super_cookie it checks
* that we do not get super cookie twice. * that we do not get super cookie twice.
*/ */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
cifs_fscache_get_super_cookie(tcon); cifs_fscache_get_super_cookie(tcon);
out: out:
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "fs_context.h" #include "fs_context.h"
#include "cifs_ioctl.h" #include "cifs_ioctl.h"
#include "fscache.h"
static void static void
renew_parental_timestamps(struct dentry *direntry) renew_parental_timestamps(struct dentry *direntry)
...@@ -507,8 +508,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -507,8 +508,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
server->ops->close(xid, tcon, &fid); server->ops->close(xid, tcon, &fid);
cifs_del_pending_open(&open); cifs_del_pending_open(&open);
rc = -ENOMEM; rc = -ENOMEM;
goto out;
} }
fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
file->f_mode & FMODE_WRITE);
out: out:
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
out_free_xid: out_free_xid:
......
...@@ -376,8 +376,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) ...@@ -376,8 +376,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
struct super_block *sb = inode->i_sb; 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 * Delete any outstanding lock records. We'll lose them when the file
* is closed anyway. * is closed anyway.
...@@ -570,7 +568,7 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -570,7 +568,7 @@ int cifs_open(struct inode *inode, struct file *file)
spin_lock(&CIFS_I(inode)->deferred_lock); spin_lock(&CIFS_I(inode)->deferred_lock);
cifs_del_deferred_close(cfile); cifs_del_deferred_close(cfile);
spin_unlock(&CIFS_I(inode)->deferred_lock); spin_unlock(&CIFS_I(inode)->deferred_lock);
goto out; goto use_cache;
} else { } else {
_cifsFileInfo_put(cfile, true, false); _cifsFileInfo_put(cfile, true, false);
} }
...@@ -632,8 +630,6 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -632,8 +630,6 @@ int cifs_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
cifs_fscache_set_inode_cookie(inode, file);
if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
/* /*
* Time to set mode which we can not set earlier due to * Time to set mode which we can not set earlier due to
...@@ -652,6 +648,15 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -652,6 +648,15 @@ int cifs_open(struct inode *inode, struct file *file)
cfile->pid); 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))
cifs_invalidate_cache(file_inode(file),
FSCACHE_INVAL_DIO_WRITE);
out: out:
free_dentry_path(page); free_dentry_path(page);
free_xid(xid); free_xid(xid);
...@@ -876,6 +881,8 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -876,6 +881,8 @@ int cifs_close(struct inode *inode, struct file *file)
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_deferred_close *dclose; struct cifs_deferred_close *dclose;
cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE);
if (file->private_data != NULL) { if (file->private_data != NULL) {
cfile = file->private_data; cfile = file->private_data;
file->private_data = NULL; file->private_data = NULL;
...@@ -886,7 +893,6 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -886,7 +893,6 @@ int cifs_close(struct inode *inode, struct file *file)
dclose) { dclose) {
if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) { if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
inode->i_ctime = inode->i_mtime = current_time(inode); inode->i_ctime = inode->i_mtime = current_time(inode);
cifs_fscache_update_inode_cookie(inode);
} }
spin_lock(&cinode->deferred_lock); spin_lock(&cinode->deferred_lock);
cifs_add_deferred_close(cfile, dclose); cifs_add_deferred_close(cfile, dclose);
...@@ -4198,10 +4204,12 @@ static vm_fault_t ...@@ -4198,10 +4204,12 @@ static vm_fault_t
cifs_page_mkwrite(struct vm_fault *vmf) cifs_page_mkwrite(struct vm_fault *vmf)
{ {
struct page *page = vmf->page; 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); lock_page(page);
return VM_FAULT_LOCKED; return VM_FAULT_LOCKED;
...@@ -4275,8 +4283,6 @@ cifs_readv_complete(struct work_struct *work) ...@@ -4275,8 +4283,6 @@ cifs_readv_complete(struct work_struct *work)
if (rdata->result == 0 || if (rdata->result == 0 ||
(rdata->result == -EAGAIN && got_bytes)) (rdata->result == -EAGAIN && got_bytes))
cifs_readpage_to_fscache(rdata->mapping->host, page); 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); got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
...@@ -4593,11 +4599,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -4593,11 +4599,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
kref_put(&rdata->refcount, cifs_readdata_release); 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); free_xid(xid);
return rc; return rc;
} }
...@@ -4801,17 +4802,19 @@ static int cifs_release_page(struct page *page, gfp_t gfp) ...@@ -4801,17 +4802,19 @@ static int cifs_release_page(struct page *page, gfp_t gfp)
{ {
if (PagePrivate(page)) if (PagePrivate(page))
return 0; return 0;
if (PageFsCache(page)) {
return cifs_fscache_release_page(page, gfp); 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, static void cifs_invalidate_page(struct page *page, unsigned int offset,
unsigned int length) unsigned int length)
{ {
struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); wait_on_page_fscache(page);
if (offset == 0 && length == PAGE_SIZE)
cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
} }
static int cifs_launder_page(struct page *page) static int cifs_launder_page(struct page *page)
...@@ -4831,7 +4834,7 @@ static int cifs_launder_page(struct page *page) ...@@ -4831,7 +4834,7 @@ static int cifs_launder_page(struct page *page)
if (clear_page_dirty_for_io(page)) if (clear_page_dirty_for_io(page))
rc = cifs_writepage_locked(page, &wbc); rc = cifs_writepage_locked(page, &wbc);
cifs_fscache_invalidate_page(page, page->mapping->host); wait_on_page_fscache(page);
return rc; return rc;
} }
...@@ -4988,6 +4991,19 @@ static void cifs_swap_deactivate(struct file *file) ...@@ -4988,6 +4991,19 @@ static void cifs_swap_deactivate(struct file *file)
/* do we need to unpin (or unlock) the 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 = { const struct address_space_operations cifs_addr_ops = {
.readpage = cifs_readpage, .readpage = cifs_readpage,
.readpages = cifs_readpages, .readpages = cifs_readpages,
...@@ -4995,7 +5011,7 @@ const struct address_space_operations cifs_addr_ops = { ...@@ -4995,7 +5011,7 @@ const struct address_space_operations cifs_addr_ops = {
.writepages = cifs_writepages, .writepages = cifs_writepages,
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = cifs_set_page_dirty,
.releasepage = cifs_release_page, .releasepage = cifs_release_page,
.direct_IO = cifs_direct_io, .direct_IO = cifs_direct_io,
.invalidatepage = cifs_invalidate_page, .invalidatepage = cifs_invalidate_page,
...@@ -5020,7 +5036,7 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { ...@@ -5020,7 +5036,7 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.writepages = cifs_writepages, .writepages = cifs_writepages,
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = cifs_set_page_dirty,
.releasepage = cifs_release_page, .releasepage = cifs_release_page,
.invalidatepage = cifs_invalidate_page, .invalidatepage = cifs_invalidate_page,
.launder_page = cifs_launder_page, .launder_page = cifs_launder_page,
......
This diff is collapsed.
...@@ -13,84 +13,71 @@ ...@@ -13,84 +13,71 @@
#include "cifsglob.h" #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 { struct cifs_fscache_volume_coherency_data {
u64 resource_id; /* unique server resource id */ __le64 resource_id; /* unique server resource id */
__le64 vol_create_time; __le64 vol_create_time;
u32 vol_serial_number; __le32 vol_serial_number;
} __packed; } __packed;
/* /*
* Auxiliary data attached to CIFS inode within the cache * Coherency data attached to CIFS inode within the cache.
*/ */
struct cifs_fscache_inode_auxdata { struct cifs_fscache_inode_coherency_data {
u64 last_write_time_sec; __le64 last_write_time_sec;
u64 last_change_time_sec; __le64 last_change_time_sec;
u32 last_write_time_nsec; __le32 last_write_time_nsec;
u32 last_change_time_nsec; __le32 last_change_time_nsec;
u64 eof;
}; };
/* #ifdef CONFIG_CIFS_FSCACHE
* 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);
/* /*
* fscache.c * fscache.c
*/ */
extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); extern int cifs_fscache_get_super_cookie(struct cifs_tcon *);
extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
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_super_cookie(struct cifs_tcon *);
extern void cifs_fscache_get_inode_cookie(struct inode *inode);
extern void cifs_fscache_release_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_unuse_inode_cookie(struct inode *inode, bool update);
extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
extern void cifs_fscache_reset_inode_cookie(struct inode *); 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_fscache_release_page(struct page *page, gfp_t gfp);
extern int __cifs_readpage_from_fscache(struct inode *, struct page *); extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
extern int __cifs_readpages_from_fscache(struct inode *, extern int __cifs_readpages_from_fscache(struct inode *,
struct address_space *, struct address_space *,
struct list_head *, struct list_head *,
unsigned *); unsigned *);
extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
extern void __cifs_readpage_to_fscache(struct inode *, struct page *); extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
static inline void cifs_fscache_invalidate_page(struct page *page, static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode)
struct inode *inode)
{ {
if (PageFsCache(page)) return CIFS_I(inode)->fscache;
__cifs_fscache_invalidate_page(page, inode);
} }
static inline void cifs_fscache_wait_on_page_write(struct inode *inode, static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags)
struct page *page)
{ {
if (PageFsCache(page)) struct cifs_fscache_inode_coherency_data cd;
__cifs_fscache_wait_on_page_write(inode, page);
}
static inline void cifs_fscache_uncache_page(struct inode *inode, cifs_fscache_fill_coherency(inode, &cd);
struct page *page) fscache_invalidate(cifs_inode_cookie(inode), &cd,
{ i_size_read(inode), flags);
if (PageFsCache(page))
__cifs_fscache_uncache_page(inode, page);
} }
static inline int cifs_readpage_from_fscache(struct inode *inode, static inline int cifs_readpage_from_fscache(struct inode *inode,
...@@ -120,41 +107,21 @@ static inline void cifs_readpage_to_fscache(struct inode *inode, ...@@ -120,41 +107,21 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
__cifs_readpage_to_fscache(inode, page); __cifs_readpage_to_fscache(inode, page);
} }
static inline void cifs_fscache_readpages_cancel(struct inode *inode, #else /* CONFIG_CIFS_FSCACHE */
struct list_head *pages) 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_get_super_cookie(struct cifs_tcon *tcon) { return 0; }
static inline int cifs_fscache_register(void) { return 0; } static inline void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {}
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 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_release_inode_cookie(struct inode *inode) {}
static inline void cifs_fscache_update_inode_cookie(struct inode *inode) {} static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) {}
static inline void cifs_fscache_set_inode_cookie(struct inode *inode, static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; }
struct file *filp) {} static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {}
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 int static inline int
cifs_readpage_from_fscache(struct inode *inode, struct page *page) cifs_readpage_from_fscache(struct inode *inode, struct page *page)
...@@ -173,11 +140,6 @@ static inline int cifs_readpages_from_fscache(struct inode *inode, ...@@ -173,11 +140,6 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
static inline void cifs_readpage_to_fscache(struct inode *inode, static inline void cifs_readpage_to_fscache(struct inode *inode,
struct page *page) {} struct page *page) {}
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
struct list_head *pages)
{
}
#endif /* CONFIG_CIFS_FSCACHE */ #endif /* CONFIG_CIFS_FSCACHE */
#endif /* _CIFS_FSCACHE_H */ #endif /* _CIFS_FSCACHE_H */
...@@ -1304,10 +1304,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) ...@@ -1304,10 +1304,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
inode->i_flags |= S_NOATIME | S_NOCMTIME; inode->i_flags |= S_NOATIME | S_NOCMTIME;
if (inode->i_state & I_NEW) { if (inode->i_state & I_NEW) {
inode->i_ino = hash; inode->i_ino = hash;
#ifdef CONFIG_CIFS_FSCACHE cifs_fscache_get_inode_cookie(inode);
/* initialize per-inode cache cookie pointer */
CIFS_I(inode)->fscache = NULL;
#endif
unlock_new_inode(inode); unlock_new_inode(inode);
} }
} }
...@@ -1376,6 +1373,7 @@ struct inode *cifs_root_iget(struct super_block *sb) ...@@ -1376,6 +1373,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
iget_failed(inode); iget_failed(inode);
inode = ERR_PTR(rc); inode = ERR_PTR(rc);
} }
out: out:
kfree(path); kfree(path);
free_xid(xid); free_xid(xid);
...@@ -2263,6 +2261,8 @@ cifs_dentry_needs_reval(struct dentry *dentry) ...@@ -2263,6 +2261,8 @@ cifs_dentry_needs_reval(struct dentry *dentry)
int int
cifs_invalidate_mapping(struct inode *inode) cifs_invalidate_mapping(struct inode *inode)
{ {
struct cifs_fscache_inode_coherency_data cd;
struct cifsInodeInfo *cifsi = CIFS_I(inode);
int rc = 0; int rc = 0;
if (inode->i_mapping && inode->i_mapping->nrpages != 0) { if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
...@@ -2272,7 +2272,8 @@ cifs_invalidate_mapping(struct inode *inode) ...@@ -2272,7 +2272,8 @@ cifs_invalidate_mapping(struct inode *inode)
__func__, 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; return rc;
} }
...@@ -2777,8 +2778,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) ...@@ -2777,8 +2778,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
goto out; goto out;
if ((attrs->ia_valid & ATTR_SIZE) && 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); truncate_setsize(inode, attrs->ia_size);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
}
setattr_copy(&init_user_ns, inode, attrs); setattr_copy(&init_user_ns, inode, attrs);
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -2973,8 +2976,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2973,8 +2976,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
goto cifs_setattr_exit; goto cifs_setattr_exit;
if ((attrs->ia_valid & ATTR_SIZE) && 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); truncate_setsize(inode, attrs->ia_size);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
}
setattr_copy(&init_user_ns, inode, attrs); setattr_copy(&init_user_ns, inode, attrs);
mark_inode_dirty(inode); mark_inode_dirty(inode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment