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 @@
*/
#include <linux/config.h>
#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
......@@ -231,6 +232,51 @@ restart:
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.
*/
......
......@@ -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);
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_delegation_mark_reclaim(struct nfs4_client *clp);
......
......@@ -39,6 +39,7 @@ struct idmap;
enum nfs4_client_state {
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
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_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 struct rpc_procinfo nfs4_procedures[];
......@@ -765,6 +766,15 @@ out:
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:
* 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
int open_flags = flags & (FMODE_READ|FMODE_WRITE);
int err;
err = nfs4_recover_expired_lease(server);
if (err != 0)
return err;
/* Protect against reboot recovery - NOTE ORDER! */
down_read(&clp->cl_sem);
/* Protect against delegation recall */
......@@ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
int status;
/* Protect against reboot recovery conflicts */
down_read(&clp->cl_sem);
status = -ENOMEM;
if (!(sp = nfs4_get_state_owner(server, cred))) {
dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
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);
if (opendata == NULL)
goto err_put_state_owner;
......@@ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp)
spin_lock(&clp->cl_lock);
clp->cl_lease_time = fsinfo.lease_time * HZ;
clp->cl_last_renewal = now;
clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
spin_unlock(&clp->cl_lock);
}
return status;
......
......@@ -54,6 +54,7 @@
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include "nfs4_fs.h"
#include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_PROC
......@@ -76,6 +77,12 @@ nfs4_renew_state(void *data)
timeout = (2 * lease) / 3 + (long)last - (long)now;
/* Are we close to a lease timeout? */
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);
/* Queue an asynchronous RENEW. */
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