*/
 #include <linux/config.h>
 #include <linux/completion.h>
+#include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
        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.
  */
 
 
 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);
 
 
 enum nfs4_client_state {
        NFS4CLNT_STATE_RECOVER  = 0,
+       NFS4CLNT_LEASE_EXPIRED,
 };
 
 /*
 
 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[];
 
        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.
        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 */
        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;
                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;
 
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include "nfs4_fs.h"
+#include "delegation.h"
 
 #define NFSDBG_FACILITY        NFSDBG_PROC
 
        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;
        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);