2014-03-24 03:54:51

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH 0/5][RESEND]NFSD/SUNRPC: Fix memory leak for the backchannel

When using pynfs test-site, I found some memory leak for the backchannel.

Kinglong Mee (5):
NFSD: Using free_conn free connection
NFSD: Free backchannel xprt in bc_destroy
SUNRPC: New helper for creating client with rpc_xprt
NFSD/SUNRPC: Check rpc_xprt out of xs_setup_bc_tcp
SUNRPC: Clear xpt_bc_xprt if xs_setup_bc_tcp failed

fs/nfsd/nfs4callback.c | 19 ++++++++++++++-
fs/nfsd/nfs4state.c | 3 ++-
include/linux/sunrpc/clnt.h | 2 ++
include/linux/sunrpc/xprt.h | 13 +++++++++-
net/sunrpc/clnt.c | 58 ++++++++++++++++++++++++++-------------------
net/sunrpc/xprt.c | 12 ----------
net/sunrpc/xprtsock.c | 15 +++++-------
7 files changed, 73 insertions(+), 49 deletions(-)

--
1.8.5.3


2014-03-24 03:57:06

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH 1/5][RESEND] NFSD: Using free_conn free connection

Connection from alloc_conn must be freed through free_conn,
otherwise, the reference of svc_xprt will never be put.

Signed-off-by: Kinglong Mee <[email protected]>
---
fs/nfsd/nfs4state.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d5d070f..d7efc4b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2287,7 +2287,8 @@ out:
if (!list_empty(&clp->cl_revoked))
seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
out_no_session:
- kfree(conn);
+ if (conn)
+ free_conn(conn);
spin_unlock(&nn->client_lock);
return status;
out_put_session:
--
1.8.5.3

2014-03-31 21:37:49

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 0/5][RESEND]NFSD/SUNRPC: Fix memory leak for the backchannel

On Mon, Mar 24, 2014 at 11:54:45AM +0800, Kinglong Mee wrote:
> When using pynfs test-site, I found some memory leak for the backchannel.

All applied, thanks.--b.

>
> Kinglong Mee (5):
> NFSD: Using free_conn free connection
> NFSD: Free backchannel xprt in bc_destroy
> SUNRPC: New helper for creating client with rpc_xprt
> NFSD/SUNRPC: Check rpc_xprt out of xs_setup_bc_tcp
> SUNRPC: Clear xpt_bc_xprt if xs_setup_bc_tcp failed
>
> fs/nfsd/nfs4callback.c | 19 ++++++++++++++-
> fs/nfsd/nfs4state.c | 3 ++-
> include/linux/sunrpc/clnt.h | 2 ++
> include/linux/sunrpc/xprt.h | 13 +++++++++-
> net/sunrpc/clnt.c | 58 ++++++++++++++++++++++++++-------------------
> net/sunrpc/xprt.c | 12 ----------
> net/sunrpc/xprtsock.c | 15 +++++-------
> 7 files changed, 73 insertions(+), 49 deletions(-)
>
> --
> 1.8.5.3

2014-03-24 03:59:06

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH 3/5][RESEND] SUNRPC: New helper for creating client with rpc_xprt

Signed-off-by: Kinglong Mee <[email protected]>
---
include/linux/sunrpc/clnt.h | 2 ++
net/sunrpc/clnt.c | 58 ++++++++++++++++++++++++++-------------------
2 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 8af2804..70736b9 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -130,6 +130,8 @@ struct rpc_create_args {
#define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT (1UL << 9)

struct rpc_clnt *rpc_create(struct rpc_create_args *args);
+struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
+ struct rpc_xprt *xprt);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
const struct rpc_program *, u32);
void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 0edada9..3c9a0f0 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -438,6 +438,38 @@ out_no_rpciod:
return ERR_PTR(err);
}

+struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
+ struct rpc_xprt *xprt)
+{
+ struct rpc_clnt *clnt = NULL;
+
+ clnt = rpc_new_client(args, xprt, NULL);
+ if (IS_ERR(clnt))
+ return clnt;
+
+ if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
+ int err = rpc_ping(clnt);
+ if (err != 0) {
+ rpc_shutdown_client(clnt);
+ return ERR_PTR(err);
+ }
+ }
+
+ clnt->cl_softrtry = 1;
+ if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
+ clnt->cl_softrtry = 0;
+
+ if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
+ clnt->cl_autobind = 1;
+ if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
+ clnt->cl_discrtry = 1;
+ if (!(args->flags & RPC_CLNT_CREATE_QUIET))
+ clnt->cl_chatty = 1;
+
+ return clnt;
+}
+EXPORT_SYMBOL_GPL(rpc_create_xprt);
+
/**
* rpc_create - create an RPC client and transport with one call
* @args: rpc_clnt create argument structure
@@ -451,7 +483,6 @@ out_no_rpciod:
struct rpc_clnt *rpc_create(struct rpc_create_args *args)
{
struct rpc_xprt *xprt;
- struct rpc_clnt *clnt;
struct xprt_create xprtargs = {
.net = args->net,
.ident = args->protocol,
@@ -515,30 +546,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
xprt->resvport = 0;

- clnt = rpc_new_client(args, xprt, NULL);
- if (IS_ERR(clnt))
- return clnt;
-
- if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
- int err = rpc_ping(clnt);
- if (err != 0) {
- rpc_shutdown_client(clnt);
- return ERR_PTR(err);
- }
- }
-
- clnt->cl_softrtry = 1;
- if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
- clnt->cl_softrtry = 0;
-
- if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
- clnt->cl_autobind = 1;
- if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
- clnt->cl_discrtry = 1;
- if (!(args->flags & RPC_CLNT_CREATE_QUIET))
- clnt->cl_chatty = 1;
-
- return clnt;
+ return rpc_create_xprt(args, xprt);
}
EXPORT_SYMBOL_GPL(rpc_create);

--
1.8.5.3

2014-03-24 04:00:36

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH 5/5][RESEND] SUNRPC: Clear xpt_bc_xprt if xs_setup_bc_tcp failed

Don't move the assign of args->bc_xprt->xpt_bc_xprt out of xs_setup_bc_tcp,
because rpc_ping (which is in rpc_create) will using it.

Signed-off-by: Kinglong Mee <[email protected]>
---
net/sunrpc/xprtsock.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 252a56e..e8acd9b 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2986,6 +2986,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)

if (try_module_get(THIS_MODULE))
return xprt;
+
+ args->bc_xprt->xpt_bc_xprt = NULL;
xprt_put(xprt);
ret = ERR_PTR(-EINVAL);
out_err:
--
1.8.5.3

2014-03-24 04:00:12

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH 4/5][RESEND] NFSD/SUNRPC: Check rpc_xprt out of xs_setup_bc_tcp

Besides checking rpc_xprt out of xs_setup_bc_tcp,
increase it's reference (it's important).

Signed-off-by: Kinglong Mee <[email protected]>
---
fs/nfsd/nfs4callback.c | 19 ++++++++++++++++++-
include/linux/sunrpc/xprt.h | 13 ++++++++++++-
net/sunrpc/xprt.c | 12 ------------
net/sunrpc/xprtsock.c | 9 ---------
4 files changed, 30 insertions(+), 23 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 7f05cd1..39c8ef8 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -32,6 +32,7 @@
*/

#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/slab.h>
#include "nfsd.h"
@@ -635,6 +636,22 @@ static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc
}
}

+static struct rpc_clnt *create_backchannel_client(struct rpc_create_args *args)
+{
+ struct rpc_xprt *xprt;
+
+ if (args->protocol != XPRT_TRANSPORT_BC_TCP)
+ return rpc_create(args);
+
+ xprt = args->bc_xprt->xpt_bc_xprt;
+ if (xprt) {
+ xprt_get(xprt);
+ return rpc_create_xprt(args, xprt);
+ }
+
+ return rpc_create(args);
+}
+
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
{
struct rpc_timeout timeparms = {
@@ -674,7 +691,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
args.authflavor = ses->se_cb_sec.flavor;
}
/* Create RPC client */
- client = rpc_create(&args);
+ client = create_backchannel_client(&args);
if (IS_ERR(client)) {
dprintk("NFSD: couldn't create callback client: %ld\n",
PTR_ERR(client));
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 8097b9d..3e5efb2 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -295,13 +295,24 @@ int xprt_adjust_timeout(struct rpc_rqst *req);
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
void xprt_release(struct rpc_task *task);
-struct rpc_xprt * xprt_get(struct rpc_xprt *xprt);
void xprt_put(struct rpc_xprt *xprt);
struct rpc_xprt * xprt_alloc(struct net *net, size_t size,
unsigned int num_prealloc,
unsigned int max_req);
void xprt_free(struct rpc_xprt *);

+/**
+ * xprt_get - return a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+static inline struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
+{
+ if (atomic_inc_not_zero(&xprt->count))
+ return xprt;
+ return NULL;
+}
+
static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
{
return p + xprt->tsh_size;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 7d4df99..d173f79 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1383,15 +1383,3 @@ void xprt_put(struct rpc_xprt *xprt)
if (atomic_dec_and_test(&xprt->count))
xprt_destroy(xprt);
}
-
-/**
- * xprt_get - return a reference to an RPC transport.
- * @xprt: pointer to the transport
- *
- */
-struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
-{
- if (atomic_inc_not_zero(&xprt->count))
- return xprt;
- return NULL;
-}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index da882af..252a56e 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2927,15 +2927,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
struct svc_sock *bc_sock;
struct rpc_xprt *ret;

- if (args->bc_xprt->xpt_bc_xprt) {
- /*
- * This server connection already has a backchannel
- * transport; we can't create a new one, as we wouldn't
- * be able to match replies based on xid any more. So,
- * reuse the already-existing one:
- */
- return args->bc_xprt->xpt_bc_xprt;
- }
xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
xprt_tcp_slot_table_entries);
if (IS_ERR(xprt))
--
1.8.5.3

2014-03-24 03:58:27

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH 2/5][RESEND] NFSD: Free backchannel xprt in bc_destroy

Backchannel xprt isn't freed right now.
Free it in bc_destroy, and put the reference of THIS_MODULE.

Signed-off-by: Kinglong Mee <[email protected]>
---
net/sunrpc/xprtsock.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 2cbafa7..da882af 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2549,6 +2549,10 @@ static void bc_close(struct rpc_xprt *xprt)

static void bc_destroy(struct rpc_xprt *xprt)
{
+ dprintk("RPC: bc_destroy xprt %p\n", xprt);
+
+ xs_xprt_free(xprt);
+ module_put(THIS_MODULE);
}

static struct rpc_xprt_ops xs_local_ops = {
--
1.8.5.3