- list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
- status = nfs4_reclaim_open_state(ops, sp);
- if (status < 0) {
- if (status == -NFS4ERR_NO_GRACE) {
- ops = &nfs4_network_partition_recovery_ops;
- status = nfs4_reclaim_open_state(ops, sp);
+ for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
+ struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
+ status = nfs4_reclaim_open_state(sp, ops);
+ if (status < 0)
+ break;
+ }
+ nfs4_recovery_handle_error(clp, status);
+ return status;
+}
+
+static int nfs4_check_lease(struct nfs_client *clp)
+{
+ struct rpc_cred *cred;
+ int status = -NFS4ERR_EXPIRED;
+
+ /* Are there any open files on this volume? */
+ cred = nfs4_get_renew_cred(clp);
+ if (cred != NULL) {
+ /* Yes there are: try to renew the old lease */
+ status = nfs4_proc_renew(clp, cred);
+ put_rpccred(cred);
+ nfs4_recovery_handle_error(clp, status);
+ return status;
+ }
+
+ /* "reboot" to ensure we clear all state on the server */
+ clp->cl_boot_time = CURRENT_TIME;
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ return status;
+}
+
+static int nfs4_reclaim_lease(struct nfs_client *clp)
+{
+ struct rpc_cred *cred;
+ int status = -ENOENT;
+
+ cred = nfs4_get_setclientid_cred(clp);
+ if (cred != NULL) {
+ status = nfs4_init_client(clp, cred);
+ put_rpccred(cred);
+ /* Handle case where the user hasn't set up machine creds */
+ if (status == -EACCES && cred == clp->cl_machine_cred) {
+ nfs4_clear_machine_cred(clp);
+ status = -EAGAIN;
+ }
+ }
+ return status;
+}
+
+static int reclaimer(void *ptr)
+{
+ struct nfs_client *clp = ptr;
+ int status = 0;
+
+ allow_signal(SIGKILL);
+
+ /* Ensure exclusive access to NFSv4 state */
+ down_write(&clp->cl_sem);
+ while (!list_empty(&clp->cl_superblocks)) {
+ if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+ /* We're going to have to re-establish a clientid */
+ status = nfs4_reclaim_lease(clp);
+ if (status) {
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ if (status == -EAGAIN)
+ continue;
+ goto out_error;