Commit 58d9714a authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Send RENEW requests to the server only when we're holding state

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 5043e900
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -231,6 +232,51 @@ void nfs_return_all_delegations(struct super_block *sb) ...@@ -231,6 +232,51 @@ void nfs_return_all_delegations(struct super_block *sb)
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
int nfs_do_expire_all_delegations(void *ptr)
{
struct nfs4_client *clp = ptr;
struct nfs_delegation *delegation;
struct inode *inode;
int err = 0;
allow_signal(SIGKILL);
restart:
spin_lock(&clp->cl_lock);
if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
goto out;
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
goto out;
list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
inode = igrab(delegation->inode);
if (inode == NULL)
continue;
spin_unlock(&clp->cl_lock);
err = nfs_inode_return_delegation(inode);
iput(inode);
if (!err)
goto restart;
}
out:
spin_unlock(&clp->cl_lock);
nfs4_put_client(clp);
module_put_and_exit(0);
}
void nfs_expire_all_delegations(struct nfs4_client *clp)
{
struct task_struct *task;
__module_get(THIS_MODULE);
atomic_inc(&clp->cl_count);
task = kthread_run(nfs_do_expire_all_delegations, clp,
"%u.%u.%u.%u-delegreturn",
NIPQUAD(clp->cl_addr));
if (!IS_ERR(task))
return;
nfs4_put_client(clp);
module_put(THIS_MODULE);
}
/* /*
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error. * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
*/ */
......
...@@ -30,6 +30,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s ...@@ -30,6 +30,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
void nfs_return_all_delegations(struct super_block *sb); void nfs_return_all_delegations(struct super_block *sb);
void nfs_expire_all_delegations(struct nfs4_client *clp);
void nfs_handle_cb_pathdown(struct nfs4_client *clp); void nfs_handle_cb_pathdown(struct nfs4_client *clp);
void nfs_delegation_mark_reclaim(struct nfs4_client *clp); void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
......
...@@ -39,6 +39,7 @@ struct idmap; ...@@ -39,6 +39,7 @@ struct idmap;
enum nfs4_client_state { enum nfs4_client_state {
NFS4CLNT_STATE_RECOVER = 0, NFS4CLNT_STATE_RECOVER = 0,
NFS4CLNT_LEASE_EXPIRED,
}; };
/* /*
......
...@@ -63,6 +63,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf ...@@ -63,6 +63,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[]; extern struct rpc_procinfo nfs4_procedures[];
...@@ -765,6 +766,15 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf ...@@ -765,6 +766,15 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf
return -EACCES; return -EACCES;
} }
int nfs4_recover_expired_lease(struct nfs_server *server)
{
struct nfs4_client *clp = server->nfs4_state;
if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
nfs4_schedule_state_recovery(clp);
return nfs4_wait_clnt_recover(server->client, clp);
}
/* /*
* OPEN_EXPIRED: * OPEN_EXPIRED:
* reclaim state on the server after a network partition. * reclaim state on the server after a network partition.
...@@ -840,6 +850,9 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred ...@@ -840,6 +850,9 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
int open_flags = flags & (FMODE_READ|FMODE_WRITE); int open_flags = flags & (FMODE_READ|FMODE_WRITE);
int err; int err;
err = nfs4_recover_expired_lease(server);
if (err != 0)
return err;
/* Protect against reboot recovery - NOTE ORDER! */ /* Protect against reboot recovery - NOTE ORDER! */
down_read(&clp->cl_sem); down_read(&clp->cl_sem);
/* Protect against delegation recall */ /* Protect against delegation recall */
...@@ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st ...@@ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
int status; int status;
/* Protect against reboot recovery conflicts */ /* Protect against reboot recovery conflicts */
down_read(&clp->cl_sem);
status = -ENOMEM; status = -ENOMEM;
if (!(sp = nfs4_get_state_owner(server, cred))) { if (!(sp = nfs4_get_state_owner(server, cred))) {
dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
goto out_err; goto out_err;
} }
status = nfs4_recover_expired_lease(server);
if (status != 0)
goto out_err;
down_read(&clp->cl_sem);
status = -ENOMEM;
opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr);
if (opendata == NULL) if (opendata == NULL)
goto err_put_state_owner; goto err_put_state_owner;
...@@ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) ...@@ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp)
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
clp->cl_lease_time = fsinfo.lease_time * HZ; clp->cl_lease_time = fsinfo.lease_time * HZ;
clp->cl_last_renewal = now; clp->cl_last_renewal = now;
clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
return status; return status;
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/nfs4.h> #include <linux/nfs4.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_PROC
...@@ -68,7 +69,7 @@ nfs4_renew_state(void *data) ...@@ -68,7 +69,7 @@ nfs4_renew_state(void *data)
dprintk("%s: start\n", __FUNCTION__); dprintk("%s: start\n", __FUNCTION__);
/* Are there any active superblocks? */ /* Are there any active superblocks? */
if (list_empty(&clp->cl_superblocks)) if (list_empty(&clp->cl_superblocks))
goto out; goto out;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
lease = clp->cl_lease_time; lease = clp->cl_lease_time;
last = clp->cl_last_renewal; last = clp->cl_last_renewal;
...@@ -76,6 +77,12 @@ nfs4_renew_state(void *data) ...@@ -76,6 +77,12 @@ nfs4_renew_state(void *data)
timeout = (2 * lease) / 3 + (long)last - (long)now; timeout = (2 * lease) / 3 + (long)last - (long)now;
/* Are we close to a lease timeout? */ /* Are we close to a lease timeout? */
if (time_after(now, last + lease/3)) { if (time_after(now, last + lease/3)) {
if (list_empty(&clp->cl_state_owners)) {
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
spin_unlock(&clp->cl_lock);
nfs_expire_all_delegations(clp);
goto out;
}
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
/* Queue an asynchronous RENEW. */ /* Queue an asynchronous RENEW. */
nfs4_proc_async_renew(clp); nfs4_proc_async_renew(clp);
......
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