2007-12-11 04:57:37

by NeilBrown

[permalink] [raw]
Subject: [PATCH] memory leak when mounting and unmounting -onolock filesystems



Hi Trond,

We found that a machine which made moderately heavy use of
'automount' was leaking some nfs data structures - particularly the
4K allocated by rpc_alloc_iostats.
It turns out that this only happens with filesystems with -onolock
set.

The problem is that if NFS_MOUNT_NONLM is set, nfs_start_lockd doesn't
set server->destroy, so when the filesystem is unmounted, the
->client_acl is not shutdown, and so several resources are still
held. Multiple mount/umount cycles will slowly eat away memory
several pages at a time.

The following patch seems the simplest fix, but it may not be what you
prefer. Arguably nfs_start_lockd isn't really the right place to set
server->destroy as it relates to both lockd and client_acl. Maybe
->destroy could be set at the end of nfs_init_server in the no-error
case.

It looks like this bug was introduced by
54ceac4515986030c2502960be620198dd8fe25b
so has been present since 2.6.19 (we found it in 2.6.22).

NeilBrown



Signed-off-by: NeilBrown <[email protected]>

diff .prev/fs/nfs/client.c ./fs/nfs/client.c
--- .prev/fs/nfs/client.c 2007-12-11 15:42:54.000000000 +1100
+++ ./fs/nfs/client.c 2007-12-11 15:44:19.000000000 +1100
@@ -432,9 +432,9 @@ static int nfs_start_lockd(struct nfs_se
IPPROTO_TCP : IPPROTO_UDP);
if (error < 0)
server->flags |= NFS_MOUNT_NONLM;
- else
- server->destroy = nfs_destroy_server;
out:
+ if (! error)
+ server->destroy = nfs_destroy_server;
return error;
}




2007-12-11 16:09:33

by Trond Myklebust

[permalink] [raw]
Subject: Re: [PATCH] memory leak when mounting and unmounting -onolock filesystems

On Tue, 2007-12-11 at 15:57 +1100, Neil Brown wrote:
> The problem is that if NFS_MOUNT_NONLM is set, nfs_start_lockd doesn't
> set server->destroy, so when the filesystem is unmounted, the
> ->client_acl is not shutdown, and so several resources are still
> held. Multiple mount/umount cycles will slowly eat away memory
> several pages at a time.

Hi Neil,

How about the following alternative for 2.6.24, and then we plan on
getting rid of ->destroy() altogether in 2.6.25?

Cheers
Trond
---------------------------------------------------
commit 2c29e75b2908f760c45bbf934f81b8a8af867770
Author: Trond Myklebust <[email protected]>
Date: Tue Dec 11 11:05:19 2007 -0500

NFSv2/v3: Fix a memory leak when using -onolock

Neil Brown said:
> Hi Trond,
>
> We found that a machine which made moderately heavy use of
> 'automount' was leaking some nfs data structures - particularly the
> 4K allocated by rpc_alloc_iostats.
> It turns out that this only happens with filesystems with -onolock
> set.

> The problem is that if NFS_MOUNT_NONLM is set, nfs_start_lockd doesn't
> set server->destroy, so when the filesystem is unmounted, the
> ->client_acl is not shutdown, and so several resources are still
> held. Multiple mount/umount cycles will slowly eat away memory
> several pages at a time.

Signed-off-by: Trond Myklebust <[email protected]>

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 70587f3..a6f6254 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -410,9 +410,6 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
*/
static void nfs_destroy_server(struct nfs_server *server)
{
- if (!IS_ERR(server->client_acl))
- rpc_shutdown_client(server->client_acl);
-
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */
}
@@ -755,6 +752,9 @@ void nfs_free_server(struct nfs_server *server)

if (server->destroy != NULL)
server->destroy(server);
+
+ if (!IS_ERR(server->client_acl))
+ rpc_shutdown_client(server->client_acl);
if (!IS_ERR(server->client))
rpc_shutdown_client(server->client);




2007-12-11 20:31:13

by NeilBrown

[permalink] [raw]
Subject: Re: [PATCH] memory leak when mounting and unmounting -onolock filesystems

On Tuesday December 11, [email protected] wrote:
> On Tue, 2007-12-11 at 15:57 +1100, Neil Brown wrote:
> > The problem is that if NFS_MOUNT_NONLM is set, nfs_start_lockd doesn't
> > set server->destroy, so when the filesystem is unmounted, the
> > ->client_acl is not shutdown, and so several resources are still
> > held. Multiple mount/umount cycles will slowly eat away memory
> > several pages at a time.
>
> Hi Neil,
>
> How about the following alternative for 2.6.24, and then we plan on
> getting rid of ->destroy() altogether in 2.6.25?
>

Yep, that looks good. Thanks.

Acked-by: NeilBrown <[email protected]>

NeilBrown

> Cheers
> Trond
> ---------------------------------------------------
> commit 2c29e75b2908f760c45bbf934f81b8a8af867770
> Author: Trond Myklebust <[email protected]>
> Date: Tue Dec 11 11:05:19 2007 -0500
>
> NFSv2/v3: Fix a memory leak when using -onolock
>
> Neil Brown said:
> > Hi Trond,
> >
> > We found that a machine which made moderately heavy use of
> > 'automount' was leaking some nfs data structures - particularly the
> > 4K allocated by rpc_alloc_iostats.
> > It turns out that this only happens with filesystems with -onolock
> > set.
>
> > The problem is that if NFS_MOUNT_NONLM is set, nfs_start_lockd doesn't
> > set server->destroy, so when the filesystem is unmounted, the
> > ->client_acl is not shutdown, and so several resources are still
> > held. Multiple mount/umount cycles will slowly eat away memory
> > several pages at a time.
>
> Signed-off-by: Trond Myklebust <[email protected]>
>
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index 70587f3..a6f6254 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -410,9 +410,6 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
> */
> static void nfs_destroy_server(struct nfs_server *server)
> {
> - if (!IS_ERR(server->client_acl))
> - rpc_shutdown_client(server->client_acl);
> -
> if (!(server->flags & NFS_MOUNT_NONLM))
> lockd_down(); /* release rpc.lockd */
> }
> @@ -755,6 +752,9 @@ void nfs_free_server(struct nfs_server *server)
>
> if (server->destroy != NULL)
> server->destroy(server);
> +
> + if (!IS_ERR(server->client_acl))
> + rpc_shutdown_client(server->client_acl);
> if (!IS_ERR(server->client))
> rpc_shutdown_client(server->client);
>
>