Subject: kern/9926: can't mmap() an LFS file correctly
To: None <gnats-bugs@gnats.netbsd.org>
From: IWAMOTO Toshihiro <iwamoto@sat.t.u-tokyo.ac.jp>
List: netbsd-bugs
Date: 04/18/2000 10:53:12
>Number:         9926
>Category:       kern
>Synopsis:       can't mmap() an LFS file correctly
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Apr 18 10:54:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     IWAMOTO Toshihiro
>Release:        NetBSD 1.4X
>Organization:
	
>Environment:
	
System: NetBSD miyuki.my.domain 1.4X NetBSD 1.4X (MASH) #27: Sun Apr 16 01:19:56 JST 2000 toshii@miyuki.my.domain:/usr/src/syssrc/sys/arch/i386/compile/MASH i386


>Description:
	If a file on LFS is enlarged after open() using ftruncate(),
	we cannot access the file content via mmap()'ed memory.

	This misbehavior prevents from emacs to be built on LFS,
	because it tries to do open()-ftruncate()-mmap() sequence
	at the stage of dumping (i.e. temacs -batch -l loadup dump).

>How-To-Repeat:
	Try to build emacs on LFS, or execute the following code.
	The process gets SEGV when it touches mmap()'ed memory.

#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>

int main(int argc, char** argv) {
  int fd;
  int i;
  char* p;

  unlink("hoge");
  fd=open("hoge", O_RDWR | O_CREAT, 0600);

  ftruncate(fd, 1024*1024);
  p = mmap(0, 1024*1024, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
  if (p == MAP_FAILED)
    perror("mmap");

  p[1000000]++;

  close(fd);
}

>Fix:
	I suspect around line 260 of /sys/ufs/lfs/lfs_inode.c.
	With the following patch, emacs can be built but cause
	filesystem corruption.
	Just calling uvm_vnp_uncache() suffice?

Index: lfs_inode.c
===================================================================
RCS file: /export/NetBSD-CVS/syssrc/sys/ufs/lfs/lfs_inode.c,v
retrieving revision 1.32
diff -u -r1.32 lfs_inode.c
--- lfs_inode.c 2000/03/30 12:41:13     1.32
+++ lfs_inode.c 2000/04/16 16:07:40
@@ -264,6 +264,7 @@
        /* If length is larger than the file, just update the times. */
        if (ip->i_ffs_size <= length) {
                ip->i_flag |= IN_CHANGE | IN_UPDATE;
+               ip->i_ffs_size = length;
                return (VOP_UPDATE(vp, NULL, NULL, 0));
        }

>Release-Note:
>Audit-Trail:
>Unformatted: