NFSv4: State recovery cleanup
Use wait_on_bit() when waiting for state recovery to complete.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 4ad5981..1d4c5b3 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -38,7 +38,7 @@
((err) != NFSERR_NOFILEHANDLE))
enum nfs4_client_state {
- NFS4CLNT_OK = 0,
+ NFS4CLNT_STATE_RECOVER = 0,
};
/*
@@ -76,7 +76,6 @@
struct work_struct cl_renewd;
struct work_struct cl_recoverd;
- wait_queue_head_t cl_waitq;
struct rpc_wait_queue cl_rpcwaitq;
/* used for the setclientid verifier */
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 76d7d02..46623ac 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2736,7 +2736,7 @@
case -NFS4ERR_EXPIRED:
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL);
nfs4_schedule_state_recovery(clp);
- if (test_bit(NFS4CLNT_OK, &clp->cl_state))
+ if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0)
rpc_wake_up_task(task);
task->tk_status = 0;
return -EAGAIN;
@@ -2753,25 +2753,25 @@
return 0;
}
+static int nfs4_wait_bit_interruptible(void *word)
+{
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ schedule();
+ return 0;
+}
+
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
{
- DEFINE_WAIT(wait);
sigset_t oldset;
- int interruptible, res = 0;
+ int res;
might_sleep();
rpc_clnt_sigmask(clnt, &oldset);
- interruptible = TASK_UNINTERRUPTIBLE;
- if (clnt->cl_intr)
- interruptible = TASK_INTERRUPTIBLE;
- prepare_to_wait(&clp->cl_waitq, &wait, interruptible);
- nfs4_schedule_state_recovery(clp);
- if (clnt->cl_intr && signalled())
- res = -ERESTARTSYS;
- else if (!test_bit(NFS4CLNT_OK, &clp->cl_state))
- schedule();
- finish_wait(&clp->cl_waitq, &wait);
+ res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER,
+ nfs4_wait_bit_interruptible,
+ TASK_INTERRUPTIBLE);
rpc_clnt_sigunmask(clnt, &oldset);
return res;
}
@@ -2814,6 +2814,7 @@
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
+ nfs4_schedule_state_recovery(clp);
ret = nfs4_wait_clnt_recover(server->client, clp);
if (ret == 0)
exception->retry = 1;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 41a5f1a..4ebf4df 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -106,11 +106,10 @@
INIT_WORK(&clp->cl_recoverd, nfs4_recover_state, clp);
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
INIT_LIST_HEAD(&clp->cl_superblocks);
- init_waitqueue_head(&clp->cl_waitq);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
clp->cl_rpcclient = ERR_PTR(-EINVAL);
clp->cl_boot_time = CURRENT_TIME;
- clp->cl_state = 1 << NFS4CLNT_OK;
+ clp->cl_state = 0;
return clp;
}
@@ -193,7 +192,6 @@
list_del(&clp->cl_servers);
spin_unlock(&state_spinlock);
BUG_ON(!list_empty(&clp->cl_superblocks));
- wake_up_all(&clp->cl_waitq);
rpc_wake_up(&clp->cl_rpcwaitq);
nfs4_kill_renewd(clp);
nfs4_free_client(clp);
@@ -741,6 +739,15 @@
struct completion complete;
};
+static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
+{
+ smp_mb__before_clear_bit();
+ clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER);
+ rpc_wake_up(&clp->cl_rpcwaitq);
+}
+
/*
* State recovery routine
*/
@@ -760,9 +767,7 @@
wait_for_completion(&args.complete);
return;
out_failed_clear:
- set_bit(NFS4CLNT_OK, &clp->cl_state);
- wake_up_all(&clp->cl_waitq);
- rpc_wake_up(&clp->cl_rpcwaitq);
+ nfs4_clear_recover_bit(clp);
}
/*
@@ -773,7 +778,7 @@
{
if (!clp)
return;
- if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state))
+ if (test_and_set_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0)
schedule_work(&clp->cl_recoverd);
}
@@ -943,13 +948,11 @@
}
nfs_delegation_reap_unclaimed(clp);
out:
- set_bit(NFS4CLNT_OK, &clp->cl_state);
up_write(&clp->cl_sem);
unlock_kernel();
- wake_up_all(&clp->cl_waitq);
- rpc_wake_up(&clp->cl_rpcwaitq);
if (status == -NFS4ERR_CB_PATH_DOWN)
nfs_handle_cb_pathdown(clp);
+ nfs4_clear_recover_bit(clp);
nfs4_put_client(clp);
return 0;
out_error: