提交 d29b20cd 编写于 作者: J J. Bruce Fields

nfsd4: clean up open owners on OPEN failure

If process_open1() creates a new open owner, but the open later fails,
the current code will leave the open owner around.  It won't be on the
close_lru list, and the client isn't expected to send a CLOSE, so it
will hang around as long as the client does.

Similarly, if process_open1() removes an existing open owner from the
close lru, anticipating that an open owner that previously had no
associated stateid's now will, but the open subsequently fails, then
we'll again be left with the same leak.

Fix both problems.
Reported-by: NBryan Schumaker <bjschuma@netapp.com>
Signed-off-by: NJ. Bruce Fields <bfields@redhat.com>
上级 bcf130f9
...@@ -409,6 +409,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -409,6 +409,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
*/ */
status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
out: out:
nfsd4_cleanup_open_state(open, status);
if (open->op_openowner) if (open->op_openowner)
cstate->replay_owner = &open->op_openowner->oo_owner; cstate->replay_owner = &open->op_openowner->oo_owner;
else else
......
...@@ -2320,7 +2320,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str ...@@ -2320,7 +2320,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
return NULL; return NULL;
oo->oo_owner.so_is_open_owner = 1; oo->oo_owner.so_is_open_owner = 1;
oo->oo_owner.so_seqid = open->op_seqid; oo->oo_owner.so_seqid = open->op_seqid;
oo->oo_flags = 0; oo->oo_flags = NFS4_OO_NEW;
oo->oo_time = 0; oo->oo_time = 0;
oo->oo_last_closed_stid = NULL; oo->oo_last_closed_stid = NULL;
INIT_LIST_HEAD(&oo->oo_close_lru); INIT_LIST_HEAD(&oo->oo_close_lru);
...@@ -2526,7 +2526,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, ...@@ -2526,7 +2526,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
open->op_openowner = NULL; open->op_openowner = NULL;
goto new_owner; goto new_owner;
} }
list_del_init(&oo->oo_close_lru);
return nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); return nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
new_owner: new_owner:
oo = alloc_init_open_stateowner(strhashval, clp, open); oo = alloc_init_open_stateowner(strhashval, clp, open);
...@@ -2946,6 +2945,23 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf ...@@ -2946,6 +2945,23 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
return status; return status;
} }
void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
{
if (open->op_openowner) {
struct nfs4_openowner *oo = open->op_openowner;
if (!list_empty(&oo->oo_owner.so_stateids))
list_del_init(&oo->oo_close_lru);
if (oo->oo_flags & NFS4_OO_NEW) {
if (status) {
release_openowner(oo);
open->op_openowner = NULL;
} else
oo->oo_flags &= ~NFS4_OO_NEW;
}
}
}
__be32 __be32
nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
clientid_t *clid) clientid_t *clid)
......
...@@ -359,6 +359,7 @@ struct nfs4_openowner { ...@@ -359,6 +359,7 @@ struct nfs4_openowner {
time_t oo_time; /* time of placement on so_close_lru */ time_t oo_time; /* time of placement on so_close_lru */
#define NFS4_OO_CONFIRMED 1 #define NFS4_OO_CONFIRMED 1
#define NFS4_OO_PURGE_CLOSE 2 #define NFS4_OO_PURGE_CLOSE 2
#define NFS4_OO_NEW 4
unsigned char oo_flags; unsigned char oo_flags;
}; };
......
...@@ -554,6 +554,7 @@ extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *, ...@@ -554,6 +554,7 @@ extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
struct nfsd4_open *open); struct nfsd4_open *open);
extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open *open); struct svc_fh *current_fh, struct nfsd4_open *open);
extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc); struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
extern __be32 nfsd4_close(struct svc_rqst *rqstp, extern __be32 nfsd4_close(struct svc_rqst *rqstp,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册