Commit e4bdda1b authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  NFSv4: Fix a regression in the NFSv4 state manager
  NFSv4: Release the sequence id before restarting a CLOSE rpc call
  nfs41: fix session fore channel negotiation
  nfs41: do not zero seqid portion of stateid on close
  nfs: run state manager in privileged mode
  nfs: make recovery state manager operations privileged
  nfs: enforce FIFO ordering of operations trying to acquire slot
  rpc: add a new priority in RPC task
  nfs: remove rpc_task argument from nfs4_find_slot
  rpc: add rpc_queue_empty function
  nfs: change nfs4_do_setlk params to identify recovery type
  nfs: do not do a LOOKUP after open
  nfs: minor cleanup of session draining
parents 74f3ae74 38045412
...@@ -108,6 +108,10 @@ enum { ...@@ -108,6 +108,10 @@ enum {
NFS_OWNER_RECLAIM_NOGRACE NFS_OWNER_RECLAIM_NOGRACE
}; };
#define NFS_LOCK_NEW 0
#define NFS_LOCK_RECLAIM 1
#define NFS_LOCK_EXPIRED 2
/* /*
* struct nfs4_state maintains the client-side state for a given * struct nfs4_state maintains the client-side state for a given
* (state_owner,inode) tuple (OPEN) or state_owner (LOCK). * (state_owner,inode) tuple (OPEN) or state_owner (LOCK).
...@@ -282,6 +286,7 @@ extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter); ...@@ -282,6 +286,7 @@ extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid);
extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
extern void nfs_release_seqid(struct nfs_seqid *seqid);
extern void nfs_free_seqid(struct nfs_seqid *seqid); extern void nfs_free_seqid(struct nfs_seqid *seqid);
extern const nfs4_stateid zero_stateid; extern const nfs4_stateid zero_stateid;
......
This diff is collapsed.
...@@ -135,16 +135,30 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) ...@@ -135,16 +135,30 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp)
return status; return status;
} }
static void nfs41_end_drain_session(struct nfs_client *clp, static void nfs4_end_drain_session(struct nfs_client *clp)
struct nfs4_session *ses)
{ {
if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) struct nfs4_session *ses = clp->cl_session;
rpc_wake_up(&ses->fc_slot_table.slot_tbl_waitq); int max_slots;
if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) {
spin_lock(&ses->fc_slot_table.slot_tbl_lock);
max_slots = ses->fc_slot_table.max_slots;
while (max_slots--) {
struct rpc_task *task;
task = rpc_wake_up_next(&ses->fc_slot_table.
slot_tbl_waitq);
if (!task)
break;
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
}
spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
}
} }
static int nfs41_begin_drain_session(struct nfs_client *clp, static int nfs4_begin_drain_session(struct nfs_client *clp)
struct nfs4_session *ses)
{ {
struct nfs4_session *ses = clp->cl_session;
struct nfs4_slot_table *tbl = &ses->fc_slot_table; struct nfs4_slot_table *tbl = &ses->fc_slot_table;
spin_lock(&tbl->slot_tbl_lock); spin_lock(&tbl->slot_tbl_lock);
...@@ -162,16 +176,13 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -162,16 +176,13 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
{ {
int status; int status;
status = nfs41_begin_drain_session(clp, clp->cl_session); nfs4_begin_drain_session(clp);
if (status != 0)
goto out;
status = nfs4_proc_exchange_id(clp, cred); status = nfs4_proc_exchange_id(clp, cred);
if (status != 0) if (status != 0)
goto out; goto out;
status = nfs4_proc_create_session(clp); status = nfs4_proc_create_session(clp);
if (status != 0) if (status != 0)
goto out; goto out;
nfs41_end_drain_session(clp, clp->cl_session);
nfs41_setup_state_renewal(clp); nfs41_setup_state_renewal(clp);
nfs_mark_client_ready(clp, NFS_CS_READY); nfs_mark_client_ready(clp, NFS_CS_READY);
out: out:
...@@ -755,16 +766,21 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) ...@@ -755,16 +766,21 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter)
return new; return new;
} }
void nfs_free_seqid(struct nfs_seqid *seqid) void nfs_release_seqid(struct nfs_seqid *seqid)
{ {
if (!list_empty(&seqid->list)) { if (!list_empty(&seqid->list)) {
struct rpc_sequence *sequence = seqid->sequence->sequence; struct rpc_sequence *sequence = seqid->sequence->sequence;
spin_lock(&sequence->lock); spin_lock(&sequence->lock);
list_del(&seqid->list); list_del_init(&seqid->list);
spin_unlock(&sequence->lock); spin_unlock(&sequence->lock);
rpc_wake_up(&sequence->wait); rpc_wake_up(&sequence->wait);
} }
}
void nfs_free_seqid(struct nfs_seqid *seqid)
{
nfs_release_seqid(seqid);
kfree(seqid); kfree(seqid);
} }
...@@ -1257,13 +1273,9 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) ...@@ -1257,13 +1273,9 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
static int nfs4_reset_session(struct nfs_client *clp) static int nfs4_reset_session(struct nfs_client *clp)
{ {
struct nfs4_session *ses = clp->cl_session;
int status; int status;
status = nfs41_begin_drain_session(clp, ses); nfs4_begin_drain_session(clp);
if (status != 0)
return status;
status = nfs4_proc_destroy_session(clp->cl_session); status = nfs4_proc_destroy_session(clp->cl_session);
if (status && status != -NFS4ERR_BADSESSION && if (status && status != -NFS4ERR_BADSESSION &&
status != -NFS4ERR_DEADSESSION) { status != -NFS4ERR_DEADSESSION) {
...@@ -1279,19 +1291,17 @@ static int nfs4_reset_session(struct nfs_client *clp) ...@@ -1279,19 +1291,17 @@ static int nfs4_reset_session(struct nfs_client *clp)
out: out:
/* /*
* Let the state manager reestablish state * Let the state manager reestablish state
* without waking other tasks yet.
*/ */
if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
/* Wake up the next rpc task */ status == 0)
nfs41_end_drain_session(clp, ses);
if (status == 0)
nfs41_setup_state_renewal(clp); nfs41_setup_state_renewal(clp);
}
return status; return status;
} }
#else /* CONFIG_NFS_V4_1 */ #else /* CONFIG_NFS_V4_1 */
static int nfs4_reset_session(struct nfs_client *clp) { return 0; } static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
...@@ -1382,6 +1392,7 @@ static void nfs4_state_manager(struct nfs_client *clp) ...@@ -1382,6 +1392,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
goto out_error; goto out_error;
} }
nfs4_end_drain_session(clp);
if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
nfs_client_return_marked_delegations(clp); nfs_client_return_marked_delegations(clp);
continue; continue;
...@@ -1398,6 +1409,7 @@ static void nfs4_state_manager(struct nfs_client *clp) ...@@ -1398,6 +1409,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
out_error: out_error:
printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
" with error %d\n", clp->cl_hostname, -status); " with error %d\n", clp->cl_hostname, -status);
nfs4_end_drain_session(clp);
nfs4_clear_state_manager_bit(clp); nfs4_clear_state_manager_bit(clp);
} }
......
...@@ -173,7 +173,8 @@ struct rpc_task_setup { ...@@ -173,7 +173,8 @@ struct rpc_task_setup {
#define RPC_PRIORITY_LOW (-1) #define RPC_PRIORITY_LOW (-1)
#define RPC_PRIORITY_NORMAL (0) #define RPC_PRIORITY_NORMAL (0)
#define RPC_PRIORITY_HIGH (1) #define RPC_PRIORITY_HIGH (1)
#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) #define RPC_PRIORITY_PRIVILEGED (2)
#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_PRIVILEGED - RPC_PRIORITY_LOW)
struct rpc_timer { struct rpc_timer {
struct timer_list timer; struct timer_list timer;
...@@ -229,6 +230,7 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *, ...@@ -229,6 +230,7 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *,
void rpc_wake_up(struct rpc_wait_queue *); void rpc_wake_up(struct rpc_wait_queue *);
struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
void rpc_wake_up_status(struct rpc_wait_queue *, int); void rpc_wake_up_status(struct rpc_wait_queue *, int);
int rpc_queue_empty(struct rpc_wait_queue *);
void rpc_delay(struct rpc_task *, unsigned long); void rpc_delay(struct rpc_task *, unsigned long);
void * rpc_malloc(struct rpc_task *, size_t); void * rpc_malloc(struct rpc_task *, size_t);
void rpc_free(void *); void rpc_free(void *);
...@@ -254,6 +256,16 @@ static inline int rpc_wait_for_completion_task(struct rpc_task *task) ...@@ -254,6 +256,16 @@ static inline int rpc_wait_for_completion_task(struct rpc_task *task)
return __rpc_wait_for_completion_task(task, NULL); return __rpc_wait_for_completion_task(task, NULL);
} }
static inline void rpc_task_set_priority(struct rpc_task *task, unsigned char prio)
{
task->tk_priority = prio - RPC_PRIORITY_LOW;
}
static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char prio)
{
return (task->tk_priority + RPC_PRIORITY_LOW == prio);
}
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
static inline const char * rpc_qname(struct rpc_wait_queue *q) static inline const char * rpc_qname(struct rpc_wait_queue *q)
{ {
......
...@@ -210,6 +210,7 @@ void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qnam ...@@ -210,6 +210,7 @@ void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qnam
{ {
__rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY); __rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY);
} }
EXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue);
void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
{ {
...@@ -384,6 +385,20 @@ static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct r ...@@ -384,6 +385,20 @@ static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct r
__rpc_do_wake_up_task(queue, task); __rpc_do_wake_up_task(queue, task);
} }
/*
* Tests whether rpc queue is empty
*/
int rpc_queue_empty(struct rpc_wait_queue *queue)
{
int res;
spin_lock_bh(&queue->lock);
res = queue->qlen;
spin_unlock_bh(&queue->lock);
return (res == 0);
}
EXPORT_SYMBOL_GPL(rpc_queue_empty);
/* /*
* Wake up a task on a specific queue * Wake up a task on a specific queue
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment