Commit 86cfb041 authored by NeilBrown's avatar NeilBrown Committed by Trond Myklebust

NFS: Don't disconnect open-owner on NFS4ERR_BAD_SEQID

When an NFS4ERR_BAD_SEQID is received the open-owner is removed from
the ->state_owners rbtree so that it will no longer be used.

If any stateids attached to this open-owner are still in use, and if a
request using one gets an NFS4ERR_BAD_STATEID reply, this can for bad.

The state is marked as needing recovery and the nfs4_state_manager()
is scheduled to clean up.  nfs4_state_manager() finds states to be
recovered by walking the state_owners rbtree.  As the open-owner is
not in the rbtree, the bad state is not found so nfs4_state_manager()
completes having done nothing.  The request is then retried, with a
predicatable result (indefinite retries).

If the stateid is for a delegation, this open_owner will be used
to open files when the delegation is returned.  For that to work,
a new open-owner needs to be presented to the server.

This patch changes NFS4ERR_BAD_SEQID handling to leave the open-owner
in the rbtree but updates the 'create_time' so it looks like a new
open-owner.  With this the indefinite retries no longer happen.
Signed-off-by: default avatarNeilBrown <neilb@suse.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 3f8f2548
...@@ -494,21 +494,18 @@ nfs4_alloc_state_owner(struct nfs_server *server, ...@@ -494,21 +494,18 @@ nfs4_alloc_state_owner(struct nfs_server *server,
} }
static void static void
nfs4_drop_state_owner(struct nfs4_state_owner *sp) nfs4_reset_state_owner(struct nfs4_state_owner *sp)
{ {
struct rb_node *rb_node = &sp->so_server_node; /* This state_owner is no longer usable, but must
* remain in place so that state recovery can find it
if (!RB_EMPTY_NODE(rb_node)) { * and the opens associated with it.
struct nfs_server *server = sp->so_server; * It may also be used for new 'open' request to
struct nfs_client *clp = server->nfs_client; * return a delegation to the server.
* So update the 'create_time' so that it looks like
spin_lock(&clp->cl_lock); * a new state_owner. This will cause the server to
if (!RB_EMPTY_NODE(rb_node)) { * request an OPEN_CONFIRM to start a new sequence.
rb_erase(rb_node, &server->state_owners); */
RB_CLEAR_NODE(rb_node); sp->so_seqid.create_time = ktime_get();
}
spin_unlock(&clp->cl_lock);
}
} }
static void nfs4_free_state_owner(struct nfs4_state_owner *sp) static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
...@@ -1113,7 +1110,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) ...@@ -1113,7 +1110,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid); sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
if (status == -NFS4ERR_BAD_SEQID) if (status == -NFS4ERR_BAD_SEQID)
nfs4_drop_state_owner(sp); nfs4_reset_state_owner(sp);
if (!nfs4_has_session(sp->so_server->nfs_client)) if (!nfs4_has_session(sp->so_server->nfs_client))
nfs_increment_seqid(status, seqid); nfs_increment_seqid(status, seqid);
} }
......
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