NFSv4: Send RENEW requests to the server only when we're holding state
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 3 Jan 2006 08:55:24 +0000 (09:55 +0100)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 6 Jan 2006 19:58:46 +0000 (14:58 -0500)
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4renewd.c

index 618a327027b3a1215e6d0cfd720d7d1813e18c88..75dfb1c717a0dcea68d9ee65e3233a216700a5b4 100644 (file)
@@ -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.
  */
index 2fcc30de924bc4d24006208b23704c6c980145d3..fbc50ec271c54f51a2e36750d89139f67c3aac93 100644 (file)
@@ -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);
index 1d4c5b339b4d96792adb6d43286213d4af331d99..75fe646c28ab63906c9fd376458dae41627a3bef 100644 (file)
@@ -39,6 +39,7 @@ struct idmap;
 
 enum nfs4_client_state {
        NFS4CLNT_STATE_RECOVER  = 0,
+       NFS4CLNT_LEASE_EXPIRED,
 };
 
 /*
index 46623ac3ce862aa90284edd1a490b69478ee7637..cc33a1c32cfba19183f960404675ad42be073f46 100644 (file)
@@ -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;
index a3001628ad32dff1ffce1b4174bec53031710e95..f62c2f7a4ffbda8717d037a57f5f3b17cfbbd6c5 100644 (file)
@@ -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);