Subject: kern/884: mmap bug in nullfs
To: None <gnats-admin@NetBSD.ORG>
From: Jan Sparud <sparud@cs.chalmers.se>
List: netbsd-bugs
Date: 03/20/1995 11:35:14
>Number:         884
>Category:       kern
>Synopsis:       mmapping files in nullfs's doesn't work correctly
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Mar 20 11:35:12 1995
>Originator:     Jan Sparud
>Organization:
	
>Release:        NetBSD-current, mid-March
>Environment:
The bug was detected on both NetBSD/i386(various Pentiums) and 
NetBSD/sparc(IPX, 32MB).
System: NetBSD butthead 1.0A NetBSD 1.0A (BEAVIS) #0: Tue Mar 7 16:18:29 MET 1995 sparud@butthead:/home/beavis/usr/src/sys/arch/i386/compile/BEAVIS i386


>Description:
Assume that you mmap a file in a null file system and then munmap it.
If you after this change the file and then mmap it again it will have 
the same contents as when mmapping it the first time.

>How-To-Repeat:

butthead(690)pwd
/usr/local
butthead(691)mkdir dir
butthead(692)mkdir dir.null
butthead(693)mount -t null /usr/local/dir /usr/local/dir.null
butthead(694)vi dir.null/file
(type in some characters, then save the file)
butthead(695)vi dir.null/file
(change something in the file, then save it)
butthead(696)vi dir.null/file

Now, the file looks like it did when we saved it the first time (but it 
has the correct length). Vi uses mmap to read a file (if it exists) and 
uses write to save it. It seems as the first time you mmap a file it gets 
cached, and everytime you mmap it afterwards the cache is used, even if 
the file has changed.

The following program shows what happens. The first argument is a file
(that should be in a null file system). The file is created and the text 
"abc\n" is written to it. Then the file is closed and reopened and the text
"def\n" is added. After this the file is mmapped and the contents is printed.
The output is :
abc
def

If given a second argument, the program mmaps/munmaps the file between the 
two writes. Now the output is:
abc

(The file actually has the correct length, but it is padded with zeros.)

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

main(int argc, char *argv[])
{
  char *contents;
  int fd;
  struct stat sb;

  if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC)) < 0)
    err(1, "Cannot create %s!\n", argv[1]);
  write(fd, "abc\n", 4); 
  close(fd);

  if (argc > 2) {
    if ((fd = open(argv[1], O_RDONLY)) < 0)
      err(1, "Cannot reopen %s!\n", argv[1]);
    if (fstat(fd, &sb) ||
	(contents = mmap((caddr_t)0,(size_t)sb.st_size, PROT_READ, 
			 MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1)
      err(1, "Couldn't mmap %d", argv[1]);
    munmap(contents, 0);
    close(fd);
  }
  
  if ((fd = open(argv[1], O_WRONLY | O_APPEND)) < 0)
    err(1, "Cannot reopen %s!\n", argv[1]);
  write(fd, "def\n", 4); 
  close(fd);

  if ((fd = open(argv[1], O_RDONLY)) < 0)
    err(1, "Cannot reopen %s!\n", argv[1]);
  
  if (fstat(fd, &sb) ||
      (contents = mmap((caddr_t)0, (size_t)sb.st_size, PROT_READ, 
		       MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1)
    err(1, "Couldn't mmap %d", argv[1]);
  else
    printf("%s\n", contents);
}

>Fix:

>Audit-Trail:
>Unformatted: