NFSv4: Send RENEW requests to the server only when we're holding state
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
5043e900f5
commit
58d9714a44
@ -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
|
||||
|
||||
@ -68,7 +69,7 @@ nfs4_renew_state(void *data)
|
||||
dprintk("%s: start\n", __FUNCTION__);
|
||||
/* Are there any active superblocks? */
|
||||
if (list_empty(&clp->cl_superblocks))
|
||||
goto out;
|
||||
goto out;
|
||||
spin_lock(&clp->cl_lock);
|
||||
lease = clp->cl_lease_time;
|
||||
last = clp->cl_last_renewal;
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user