nfs: make nfs3_call_state_t refcounted
There is no refcounting done of the nfs3_call_state_t structure, which seems to result in use-after-free problems in the NLM part of Gluster/NFS. The structure is initialized with two different functions, it is easier to have a single place to do this. The Gluster/NFS part will not use the refcounting, for now. This is being added to make the NLM code more stable. nfs3_call_state_wipe() will behave as before for Gluster/NFS, but cleanup is triggered through the refcounting now. This prevents major changes to the stable part of the NFS-server, and makes it possible to improve the NLM component separately. Change-Id: I2e15bcf12af74e8a46c2727e4a160e9444d29ece BUG: 1467313 Signed-off-by: Niels de Vos <ndevos@redhat.com> Reviewed-on: https://review.gluster.org/17696 Smoke: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Amar Tumballi <amarts@redhat.com> CentOS-regression: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com> Reviewed-by: jiffin tony Thottan <jthottan@redhat.com>
This commit is contained in:
parent
c7efdb8347
commit
daed52b8eb
@ -526,36 +526,8 @@ nfs3_solaris_zerolen_fh (struct nfs3_fh *fh, int fhlen)
|
||||
*/
|
||||
typedef ssize_t (*nfs3_serializer) (struct iovec outmsg, void *args);
|
||||
|
||||
nfs3_call_state_t *
|
||||
nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v)
|
||||
{
|
||||
nfs3_call_state_t *cs = NULL;
|
||||
|
||||
GF_VALIDATE_OR_GOTO (GF_NFS3, s, err);
|
||||
GF_VALIDATE_OR_GOTO (GF_NFS3, req, err);
|
||||
GF_VALIDATE_OR_GOTO (GF_NFS3, v, err);
|
||||
|
||||
cs = (nfs3_call_state_t *) mem_get (s->localpool);
|
||||
if (!cs) {
|
||||
gf_msg (GF_NFS3, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY,
|
||||
"out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset (cs, 0, sizeof (*cs));
|
||||
INIT_LIST_HEAD (&cs->entries.list);
|
||||
INIT_LIST_HEAD (&cs->openwait_q);
|
||||
cs->operrno = EINVAL;
|
||||
cs->req = req;
|
||||
cs->vol = v;
|
||||
cs->nfsx = s->nfsx;
|
||||
cs->nfs3state = s;
|
||||
err:
|
||||
return cs;
|
||||
}
|
||||
|
||||
void
|
||||
nfs3_call_state_wipe (nfs3_call_state_t *cs)
|
||||
static void
|
||||
__nfs3_call_state_wipe (nfs3_call_state_t *cs)
|
||||
{
|
||||
if (!cs)
|
||||
return;
|
||||
@ -586,6 +558,41 @@ nfs3_call_state_wipe (nfs3_call_state_t *cs)
|
||||
/* Already refd by fd_lookup, so no need to ref again. */
|
||||
}
|
||||
|
||||
nfs3_call_state_t *
|
||||
nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v)
|
||||
{
|
||||
nfs3_call_state_t *cs = NULL;
|
||||
|
||||
GF_VALIDATE_OR_GOTO (GF_NFS3, s, err);
|
||||
GF_VALIDATE_OR_GOTO (GF_NFS3, req, err);
|
||||
/* GF_VALIDATE_OR_GOTO (GF_NFS3, v, err); NLM sets this later */
|
||||
|
||||
cs = (nfs3_call_state_t *) mem_get (s->localpool);
|
||||
if (!cs) {
|
||||
gf_msg (GF_NFS3, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY,
|
||||
"out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset (cs, 0, sizeof (*cs));
|
||||
GF_REF_INIT (cs, __nfs3_call_state_wipe);
|
||||
INIT_LIST_HEAD (&cs->entries.list);
|
||||
INIT_LIST_HEAD (&cs->openwait_q);
|
||||
cs->operrno = EINVAL;
|
||||
cs->req = req;
|
||||
cs->vol = v;
|
||||
cs->nfsx = s->nfsx;
|
||||
cs->nfs3state = s;
|
||||
err:
|
||||
return cs;
|
||||
}
|
||||
|
||||
void
|
||||
nfs3_call_state_wipe (nfs3_call_state_t *cs)
|
||||
{
|
||||
GF_REF_PUT (cs);
|
||||
}
|
||||
|
||||
|
||||
#define nfs3_handle_call_state_init(nfs3state, calls, rq, vl ,opstat, errlabel)\
|
||||
do { \
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nlm4.h"
|
||||
#include "acl3-xdr.h"
|
||||
#include "acl3.h"
|
||||
#include "refcount.h"
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#define GF_NFS3 GF_NFS"-nfsv3"
|
||||
@ -184,6 +185,8 @@ typedef int (*nfs3_resume_fn_t) (void *cs);
|
||||
* Imagine the chaos if we need a mem-pool for each one of those sub-structures.
|
||||
*/
|
||||
struct nfs3_local {
|
||||
GF_REF_DECL;
|
||||
|
||||
rpcsvc_request_t *req;
|
||||
xlator_t *vol;
|
||||
nfs3_resume_fn_t resume_fn;
|
||||
|
@ -48,6 +48,9 @@ typedef ssize_t (*nlm4_serializer) (struct iovec outmsg, void *args);
|
||||
|
||||
extern void nfs3_call_state_wipe (nfs3_call_state_t *cs);
|
||||
|
||||
nfs3_call_state_t *
|
||||
nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v);
|
||||
|
||||
struct list_head nlm_client_list;
|
||||
gf_lock_t nlm_client_list_lk;
|
||||
|
||||
@ -67,9 +70,6 @@ int nlm_grace_period = 50;
|
||||
} \
|
||||
} while (0); \
|
||||
|
||||
nfs3_call_state_t *
|
||||
nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v);
|
||||
|
||||
#define nlm4_handle_call_state_init(nfs3state, calls, rq, opstat, errlabel)\
|
||||
do { \
|
||||
calls = nlm4_call_state_init ((nfs3state), (rq)); \
|
||||
@ -267,17 +267,10 @@ nlm4_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req)
|
||||
if ((!s) || (!req))
|
||||
return NULL;
|
||||
|
||||
cs = (nfs3_call_state_t *) mem_get (s->localpool);
|
||||
cs = nfs3_call_state_init (s, req, NULL);
|
||||
if (!cs)
|
||||
return NULL;
|
||||
|
||||
memset (cs, 0, sizeof (*cs));
|
||||
INIT_LIST_HEAD (&cs->entries.list);
|
||||
INIT_LIST_HEAD (&cs->openwait_q);
|
||||
cs->operrno = EINVAL;
|
||||
cs->req = req;
|
||||
cs->nfsx = s->nfsx;
|
||||
cs->nfs3state = s;
|
||||
cs->monitor = 1;
|
||||
|
||||
return cs;
|
||||
|
Loading…
x
Reference in New Issue
Block a user