NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/39145: kernel malloc() leak when combining nullfs and Linux emulation



>Number:         39145
>Category:       kern
>Synopsis:       kernel malloc() leak when combining nullfs and Linux emulation
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Jul 14 10:15:00 +0000 2008
>Originator:     Havard Eidnes
>Release:        NetBSD 4.0
>Organization:
        NORDUnet AS
>Environment:
System: NetBSD server.nordu.net 4.0 NetBSD 4.0 (SERVER) #2: Wed Jun 25 18:57:42 
CEST 2008  he%server.nordu.net@localhost:/usr/obj/sys/arch/i386/compile/SERVER 
i386
Architecture: i386
Machine: i386
>Description:

        There appears to be a memory leak related to malloc()ed memory
        in the kernel when nullfs mounts are used in combination with
        certain linux binaries, run under emulation.

        Case in point in our case: we use netbackup to take backups of
        this machine, which has a largish number of files:

server% df -ih
Filesystem       Size      Used     Avail Capacity  iused    ifree  %iused  
Mounted on
...
/dev/ld0g        172G      115G       48G    70%  2977222 41830968     6%   /a
...     
localhost:/a     172G      115G       48G    70%  2977247 41830943     6%   
/netbackup/a
...

        For now we have worked around the problem by instead using NFS
        mounts on 127.0.0.1 (as indicated above), so operationally for
        us this is no longer a major issue.  However, I wish to record
        my findings before I forget what I found out.

        We use alternate mount points for the data to be backed up to
        avoid the problem of the linux binary taking backups of the
        emulated linux tree when it wants to backup e.g. /usr/lib.

        A simple test involving "find . -type f | xargs cat >/dev/null"
        using NetBSD binaries on a null-mounted tree does not appear
        to trigger the problem.

        Investigation indicates that the leaked allocations are all
        8192 bytes in size.  I've modified the kernel malloc code to
        record how many allocations are done for each power-of-2 block
        size, and modified vmstat to print the information under
        "vmstat -m" (when KMEMSTATS is on), and have recorded the
        development of kernel mallocs in the "temp" category (where
        the leak appears to be).  An example:

Memory statistics by type                                Type  Kern
           Type InUse  MemUse HighUse   Limit   Requests Limit Limit Size(s)
...
           temp 13139 102221K 103220K 157287K  865753294     0     0 
16:9,32:7,64:3,128:0,256:1,512:39,1024:146,2048:171,4096:109,8192:12653,65536:1
...

        The memory which is leaked is being allocated done at
        line 198 in sys/miscfs/genfs/layer_subr.c:


        if ((error = getnewvnode(lmp->layerm_tag, mp, lmp->layerm_vnodeop_p,
                        &vp)) != 0)
                return (error);
        vp->v_type = lowervp->v_type;
        vp->v_flag |= VLAYER;

>>>     xp = malloc(lmp->layerm_size, M_TEMP, M_WAITOK);
        if (vp->v_type == VBLK || vp->v_type == VCHR) {
                MALLOC(vp->v_specinfo, struct specinfo *,
                    sizeof(struct specinfo), M_VNODE, M_WAITOK);
                vp->v_hashchain = NULL;
                vp->v_rdev = lowervp->v_rdev;
        }

        vp->v_data = xp;
        xp->layer_vnode = vp;
        xp->layer_lowervp = lowervp;
        xp->layer_flags = 0;


        This has been found by modifying the MALLOCLOG code to only
        record events related to the "temp" category, and to record
        actions related to malloc block sizes of 8192 bytes (luckily,
        malloc block sizes can be deduced for the "free" action as
        well), and by writing a small program to dump the MALLOCLOG
        ring buffer, and by post-processing the result (the
        refinements to narrow in on 8192-byte blocks came from the
        info below).

        If left unattended, this leak will eventually cause the kernel
        to run out of memory in kmem_map, which will either cause a
        panic or result in a hang (if KMEMSTATS is turned on).  (This
        hang in itself could be construed to be a bug in itself.)

        From looking at a plot of the development of the 8192-size
        blocks over time, it is clear that when we changed from null
        mounts to loopback NFS mounts, the growth in the number of
        8192-byte malloc()ed blocks in this category ceased to grow. 

        A summary of a partial ktrace the linux binary which performs
        the backups do when these leaks are accumulating shows the
        following number of system calls performed:

stat64          870
llseek          1425
time            9115
close           8843
read            10089
lstat64         439337
#271            7953
write           8527
brk             193
access          235
mmap2           9
getdents64      2962
fstat64         879
munmap          9
open            8842
chdir           1742
utime           7953
fcntl64         888

        I've tried to inspect the Linux compat code to find anything
        obvious being amiss, but sadly came up empty.  It's hard to
        find something which is missing (a missing free() somewhere,
        or a pointer being overwritten, or...).


>How-To-Repeat:
        Use a linux binary (in our case netbackup) to backup largish
        amounts of data on a null-mount.


>Fix:
        Sorry, don't know.



Home | Main Index | Thread Index | Old Index