Bug 10224 - Kernel Memory Bug with memory mapping (mmap)
Summary: Kernel Memory Bug with memory mapping (mmap)
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: kernel
Version: 6.1
Hardware: i386
OS: Linux
high
high
Target Milestone: ---
Assignee: Michael K. Johnson
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2000-03-17 16:26 UTC by Keith Ansell
Modified: 2008-05-01 15:37 UTC (History)
0 users

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2000-04-27 16:30:12 UTC
Embargoed:


Attachments (Terms of Use)

Description Keith Ansell 2000-03-17 16:26:33 UTC
Kernel running out of system file descriptors when using memory
mapping.

Platform intel 686, Redhat 6.1.

We have ported our Database management tool to redhat linux from
NCR SVR4, IBM AIX 4.2, Windows NT 4.0, Sco Open Server 5.4,
Unixware 2.1 & Unixware 7.1 etc.

The system is designed around memory mapping and uses the follow
formula to access the database.

The database is split up into 1 Megabyte files (pools) and can
only open upto eleven pools, each pool is mapped in 4k pages,
giving us a total of 512 pages per pool, we map upto a maximum
of 2000 pages this is our high water mark and once reached we
unmap 1000 pages.

The problem seems to be that when a pool is closed and there are
still mapped pages linked to that pool Linux copies or duplicates
the file descriptor, this file descriptor is deducted from the
system table of file descriptors and therefore causing the system
to lose upto 2000 file descriptors per user from it's default
of 4096.

This software works on all the other operating systems we have
ported too, for example:-
we currently have a very large user (1000 users and growing)
running on NCR's SVR4 unix and our application, this user wants
to switch from his NCR svr4 system to a DELL machine running
RedHat Linux, in total this user will switch 3000 networked users
from NCR to RedHat linux this year.

All this depends on this problem been resolved.

I have attacted an example program that needs to be run from root,
that shows the problem.

Source Program.


Program Name : "t"


#include <fstream.h>
#include <sys/mman.h>
#include "sys/time.h"
#include "sys/resource.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "iostream.h"
#include "stdio.h"
#include "error.h"



void OpenFileTest(void) {
	const char * fn = "XXX";
	int last,fd;
	int count = 0;
	int start=open(fn, O_CREAT | O_RDONLY, S_IRWXU);
	while(1) {
		count=open(fn, O_CREAT | O_RDONLY, S_IRWXU);
		if ( count == -1 	) {
			perror("dup failed!");
			cerr << "Target set to " << last << endl;
			break;
		}
		last=count;
	}
	for (int loop=start;loop <= last; loop++) {
		fd =close(loop);
		if ( fd == -1 	) {
		   cerr << "<" << loop << "> " ;
			perror("Close failed!");
			break;
		}
	}
};

void main(void) {
	int fd;
	struct rlimit *rlim;
	fd = getrlimit(RLIMIT_NOFILE,rlim);
	rlim->rlim_max=15120;
	rlim->rlim_cur=15120;
	fd = setrlimit(RLIMIT_NOFILE,rlim);
	if ( fd == -1 	)
	{
		perror("Setrlimit failed!");
		exit;
	}
	fd = getrlimit(RLIMIT_NOFILE,rlim);
	cerr << " rlim data,  current <" << rlim->rlim_cur << "> ";
	cerr << " max <" << rlim->rlim_max << ">." << endl;
	while(1) {
		const char * Path="ZZZZ";
		fstream F(Path, ios::in | ios::out, filebuf::openprot);
		fd = F.rdbuf()->fd();
		cerr << "fd:" << fd << endl;
		caddr_t Addr;
		const int Length = 4096;
		int Offset = 0;
	if ((Addr = (caddr_t) mmap(NULL, Length, PROT_READ | PROT_WRITE,
			MAP_SHARED, fd, Offset)) == MAP_FAILED) {
		perror("Map1 failed");
		exit;
	}
	Offset += Length;
	if ((Addr = (caddr_t) mmap(NULL, Length, PROT_READ | PROT_WRITE,
			MAP_SHARED, fd, Offset)) == MAP_FAILED) {
		perror("Map2 failed");
		exit;
	}

	OpenFileTest();
	F.close();
	cin.get();
	}
};

login as root

compile line :-
  g++ t.C -o t

touch ZZZZ

to execute :-
./t


The fd count is reduced by 1 with each loop.

This is a major problem and is stopping us from releasing our software on
RedHat Linux.

Regards
       Keith Ansell.

Comment 1 Doug Ledford 2000-04-27 16:30:59 UTC
This is exactly what the kernel should do in this particular case.  Closing a
file does not, and should not according to specs, result in a mmap mapping going
away.  The fact that the linux kernel uses an internal struct file with each
mmap'ing means that as your program does as you are suggesting, the number of
kernel file handles is growing constantly.  In order to work around this, you
could up the number of file structs the kernel is allowed to allocate by doing
something like:

echo "40960" > /proc/sys/fs/file-max

to increase from the default 4096 file structs to 40960.  The other alternative
is to unmmap the memory areas of a pool before switching to the next one.  Those
would be the only alternatives I am aware of on a 2.2 kernel.  I'm not aware of
the status of this particular problem in relation to the upcoming 2.4 kernel's
mmap code.


Note You need to log in before you can comment on or make changes to this bug.