Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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

parent 5043e900
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -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 @@ void nfs_return_all_delegations(struct super_block *sb)
	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.
 */
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct idmap;

enum nfs4_client_state {
	NFS4CLNT_STATE_RECOVER  = 0,
	NFS4CLNT_LEASE_EXPIRED,
};

/*
+19 −1
Original line number Diff line number Diff line
@@ -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 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf
	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;
+8 −1
Original line number Diff line number Diff line
@@ -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);