Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

Bug 10224

Summary: Kernel Memory Bug with memory mapping (mmap)
Product: [Retired] Red Hat Linux Reporter: Keith Ansell <keitha>
Component: kernelAssignee: Michael K. Johnson <johnsonm>
Status: CLOSED NOTABUG QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: 6.1   
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2000-04-27 16:30:12 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

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.