Commit b42a8a16 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: More aggressive caching if we have a delegation.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
parent 7129dfe5
...@@ -70,6 +70,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st ...@@ -70,6 +70,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
put_rpccred(cred); put_rpccred(cred);
delegation->cred = get_rpccred(cred); delegation->cred = get_rpccred(cred);
delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
NFS_I(inode)->delegation_state = delegation->type;
smp_wmb();
} }
/* /*
...@@ -96,6 +98,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct ...@@ -96,6 +98,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
if (nfsi->delegation == NULL) { if (nfsi->delegation == NULL) {
list_add(&delegation->super_list, &clp->cl_delegations); list_add(&delegation->super_list, &clp->cl_delegations);
nfsi->delegation = delegation; nfsi->delegation = delegation;
nfsi->delegation_state = delegation->type;
delegation = NULL; delegation = NULL;
} else { } else {
if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
...@@ -150,6 +153,7 @@ int nfs_inode_return_delegation(struct inode *inode) ...@@ -150,6 +153,7 @@ int nfs_inode_return_delegation(struct inode *inode)
if (delegation != NULL) { if (delegation != NULL) {
list_del_init(&delegation->super_list); list_del_init(&delegation->super_list);
nfsi->delegation = NULL; nfsi->delegation = NULL;
nfsi->delegation_state = 0;
} }
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
nfs_delegation_claim_opens(inode); nfs_delegation_claim_opens(inode);
...@@ -218,6 +222,7 @@ static int recall_thread(void *data) ...@@ -218,6 +222,7 @@ static int recall_thread(void *data)
sizeof(delegation->stateid.data)) == 0) { sizeof(delegation->stateid.data)) == 0) {
list_del_init(&delegation->super_list); list_del_init(&delegation->super_list);
nfsi->delegation = NULL; nfsi->delegation = NULL;
nfsi->delegation_state = 0;
args->result = 0; args->result = 0;
} else { } else {
delegation = NULL; delegation = NULL;
...@@ -302,6 +307,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) ...@@ -302,6 +307,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
continue; continue;
list_move(&delegation->super_list, &head); list_move(&delegation->super_list, &head);
NFS_I(delegation->inode)->delegation = NULL; NFS_I(delegation->inode)->delegation = NULL;
NFS_I(delegation->inode)->delegation_state = 0;
} }
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
while(!list_empty(&head)) { while(!list_empty(&head)) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#ifndef FS_NFS_DELEGATION_H #ifndef FS_NFS_DELEGATION_H
#define FS_NFS_DELEGATION_H #define FS_NFS_DELEGATION_H
#if defined(CONFIG_NFS_V4)
/* /*
* NFSv4 delegation * NFSv4 delegation
*/ */
...@@ -37,4 +38,19 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); ...@@ -37,4 +38,19 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
static inline int nfs_have_delegation(struct inode *inode, int flags)
{
flags &= FMODE_READ|FMODE_WRITE;
smp_rmb();
if ((NFS_I(inode)->delegation_state & flags) == flags)
return 1;
return 0;
}
#else
static inline int nfs_have_delegation(struct inode *inode, int flags)
{
return 0;
}
#endif
#endif #endif
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/namei.h> #include <linux/namei.h>
#include "delegation.h"
#define NFS_PARANOIA 1 #define NFS_PARANOIA 1
/* #define NFS_DEBUG_VERBOSE 1 */ /* #define NFS_DEBUG_VERBOSE 1 */
...@@ -887,6 +889,8 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -887,6 +889,8 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
return ret; return ret;
no_open: no_open:
dput(parent); dput(parent);
if (inode != NULL && nfs_have_delegation(inode, FMODE_READ))
return 1;
return nfs_lookup_revalidate(dentry, nd); return nfs_lookup_revalidate(dentry, nd);
} }
#endif /* CONFIG_NFSV4 */ #endif /* CONFIG_NFSV4 */
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_FILE #define NFSDBG_FACILITY NFSDBG_FILE
static int nfs_file_open(struct inode *, struct file *); static int nfs_file_open(struct inode *, struct file *);
...@@ -127,7 +129,7 @@ nfs_file_flush(struct file *file) ...@@ -127,7 +129,7 @@ nfs_file_flush(struct file *file)
if (!status) { if (!status) {
status = ctx->error; status = ctx->error;
ctx->error = 0; ctx->error = 0;
if (!status) if (!status && !nfs_have_delegation(inode, FMODE_READ))
__nfs_revalidate_inode(NFS_SERVER(inode), inode); __nfs_revalidate_inode(NFS_SERVER(inode), inode);
} }
unlock_kernel(); unlock_kernel();
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_VFS #define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1 #define NFS_PARANOIA 1
...@@ -1017,6 +1019,30 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) ...@@ -1017,6 +1019,30 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
return status; return status;
} }
int nfs_attribute_timeout(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
if (nfs_have_delegation(inode, FMODE_READ))
return 0;
return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
}
/**
* nfs_revalidate_inode - Revalidate the inode attributes
* @server - pointer to nfs_server struct
* @inode - pointer to inode struct
*
* Updates inode attribute information by retrieving the data from the server.
*/
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
&& !nfs_attribute_timeout(inode))
return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode);
}
/** /**
* nfs_begin_data_update * nfs_begin_data_update
* @inode - pointer to inode * @inode - pointer to inode
...@@ -1038,11 +1064,13 @@ void nfs_end_data_update(struct inode *inode) ...@@ -1038,11 +1064,13 @@ void nfs_end_data_update(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
/* Mark the attribute cache for revalidation */ if (!nfs_have_delegation(inode, FMODE_READ)) {
nfsi->flags |= NFS_INO_INVALID_ATTR; /* Mark the attribute cache for revalidation */
/* Directories and symlinks: invalidate page cache too */ nfsi->flags |= NFS_INO_INVALID_ATTR;
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) /* Directories and symlinks: invalidate page cache too */
nfsi->flags |= NFS_INO_INVALID_DATA; if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
nfsi->flags |= NFS_INO_INVALID_DATA;
}
nfsi->cache_change_attribute ++; nfsi->cache_change_attribute ++;
atomic_dec(&nfsi->data_updates); atomic_dec(&nfsi->data_updates);
} }
...@@ -1083,6 +1111,10 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1083,6 +1111,10 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
loff_t cur_size, new_isize; loff_t cur_size, new_isize;
int data_unstable; int data_unstable;
/* Do we hold a delegation? */
if (nfs_have_delegation(inode, FMODE_READ))
return 0;
/* Are we in the process of updating data on the server? */ /* Are we in the process of updating data on the server? */
data_unstable = nfs_caches_unstable(inode); data_unstable = nfs_caches_unstable(inode);
...@@ -1280,7 +1312,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign ...@@ -1280,7 +1312,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode))) || S_ISLNK(inode->i_mode)))
invalid &= ~NFS_INO_INVALID_DATA; invalid &= ~NFS_INO_INVALID_DATA;
nfsi->flags |= invalid; if (!nfs_have_delegation(inode, FMODE_READ))
nfsi->flags |= invalid;
return 0; return 0;
out_changed: out_changed:
...@@ -1437,8 +1470,6 @@ static struct file_system_type nfs_fs_type = { ...@@ -1437,8 +1470,6 @@ static struct file_system_type nfs_fs_type = {
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
#include "delegation.h"
static void nfs4_clear_inode(struct inode *); static void nfs4_clear_inode(struct inode *);
...@@ -1767,6 +1798,7 @@ static struct file_system_type nfs4_fs_type = { ...@@ -1767,6 +1798,7 @@ static struct file_system_type nfs4_fs_type = {
do { \ do { \
INIT_LIST_HEAD(&(nfsi)->open_states); \ INIT_LIST_HEAD(&(nfsi)->open_states); \
nfsi->delegation = NULL; \ nfsi->delegation = NULL; \
nfsi->delegation_state = 0; \
init_rwsem(&nfsi->rwsem); \ init_rwsem(&nfsi->rwsem); \
} while(0) } while(0)
#define register_nfs4fs() register_filesystem(&nfs4_fs_type) #define register_nfs4fs() register_filesystem(&nfs4_fs_type)
......
...@@ -63,6 +63,8 @@ ...@@ -63,6 +63,8 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE #define NFSDBG_FACILITY NFSDBG_PAGECACHE
#define MIN_POOL_WRITE (32) #define MIN_POOL_WRITE (32)
...@@ -382,8 +384,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) ...@@ -382,8 +384,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
/* /*
* Insert a write request into an inode * Insert a write request into an inode
*/ */
static inline int static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
int error; int error;
...@@ -395,6 +396,8 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req) ...@@ -395,6 +396,8 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
if (!nfsi->npages) { if (!nfsi->npages) {
igrab(inode); igrab(inode);
nfs_begin_data_update(inode); nfs_begin_data_update(inode);
if (nfs_have_delegation(inode, FMODE_WRITE))
nfsi->change_attr++;
} }
nfsi->npages++; nfsi->npages++;
atomic_inc(&req->wb_count); atomic_inc(&req->wb_count);
......
...@@ -185,6 +185,7 @@ struct nfs_inode { ...@@ -185,6 +185,7 @@ struct nfs_inode {
/* NFSv4 state */ /* NFSv4 state */
struct list_head open_states; struct list_head open_states;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
int delegation_state;
struct rw_semaphore rwsem; struct rw_semaphore rwsem;
#endif /* CONFIG_NFS_V4*/ #endif /* CONFIG_NFS_V4*/
...@@ -294,6 +295,8 @@ extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_a ...@@ -294,6 +295,8 @@ extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_a
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
extern int nfs_open(struct inode *, struct file *); extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *);
extern int nfs_attribute_timeout(struct inode *inode);
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_setattr(struct dentry *, struct iattr *); extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_begin_attr_update(struct inode *); extern void nfs_begin_attr_update(struct inode *);
...@@ -446,28 +449,6 @@ extern int nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *, ...@@ -446,28 +449,6 @@ extern int nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *,
* inline functions * inline functions
*/ */
static inline int nfs_attribute_timeout(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
}
/**
* nfs_revalidate_inode - Revalidate the inode attributes
* @server - pointer to nfs_server struct
* @inode - pointer to inode struct
*
* Updates inode attribute information by retrieving the data from the server.
*/
static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
&& !nfs_attribute_timeout(inode))
return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode);
}
static inline loff_t static inline loff_t
nfs_size_to_loff_t(__u64 size) nfs_size_to_loff_t(__u64 size)
{ {
......
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