i386 mmap(2) fixed for LTP

Marcin Cieslak saper at SYSTEM.PL
Mon Sep 18 17:37:10 PDT 2006


Hallo,

Using my mmap fingerprinter (see amd64 post above) I have managed
to compare basic mmap(2) behaviour between real Linux and FreeBSD machine.

Our mmap(2) allows you map write-only file for writing, Linux
is giving up immediately on that. (Probably because they always
need the file to be open for reading as well and then they add PROT_READ 
internally).

Using this patch I guess we have all mmap()-related LTP issues solved.
This fixes outstanding map07 test.

I guess that writev03 and writev04 - that started to fail after my initial quick 
fix for mmap() - were just false positives initially.
Since linuxolator mmap() added PROT_READ that gave access to whole iovec
address space, writev() calls suceeded although not in a way meant by author tests:

http://sf.net/tracker/index.php?func=detail&aid=1561083&group_id=3382&atid=103382

The only thing left is the amd64 part of the fix for mmap(2).
Please feel free to review.

-- 
               << Marcin Cieslak // saper at system.pl >>

Index: /usr/src/sys/i386/linux/linux_machdep.c
===================================================================
RCS file: /usr/home/ncvs/src/sys/i386/linux/linux_machdep.c,v
retrieving revision 1.48.2.1
diff -u -u -r1.48.2.1 linux_machdep.c
--- /usr/src/sys/i386/linux/linux_machdep.c	4 Aug 2005 23:25:32 -0000	1.48.2.1
+++ /usr/src/sys/i386/linux/linux_machdep.c	19 Sep 2006 00:34:53 -0000
@@ -31,6 +31,8 @@

  #include <sys/param.h>
  #include <sys/systm.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
  #include <sys/imgact.h>
  #include <sys/lock.h>
  #include <sys/malloc.h>
@@ -469,9 +471,19 @@
  		off_t pos;
  	} */ bsd_args;
  	int error;
+	struct file *fp;

  	error = 0;
  	bsd_args.flags = 0;
+	fp = NULL;
+
+	/* Linux mmap(2):
+	 * You must specify exactly one of MAP_SHARED and MAP_PRIVATE.
+	 */
+	if (! ((linux_args->flags & LINUX_MAP_SHARED) ^
+		(linux_args->flags & LINUX_MAP_PRIVATE)))
+		return EINVAL;
+
  	if (linux_args->flags & LINUX_MAP_SHARED)
  		bsd_args.flags |= MAP_SHARED;
  	if (linux_args->flags & LINUX_MAP_PRIVATE)
@@ -549,11 +561,34 @@
  		bsd_args.len  = linux_args->len;
  	}

-	bsd_args.prot = linux_args->prot | PROT_READ;	/* always required */
-	if (linux_args->flags & LINUX_MAP_ANON)
+	bsd_args.prot = linux_args->prot;
+	if (linux_args->flags & LINUX_MAP_ANON) {
  		bsd_args.fd = -1;
-	else
+	} else {
+		/*
+		 * Linux follows Solaris mmap(2) description:
+		 * The file descriptor fildes is opened with
+		 * read permission, regardless of the
+		 * protection options specified.
+		 * If PROT_WRITE is specified, the application
+		 * must have opened the file descriptor
+		 * fildes with write permission unless
+		 * MAP_PRIVATE is specified in the flags
+		 * argument as described below.
+		 */
+		
+		if ((error = fget(td, linux_args->fd, &fp)) != 0)
+                        return error;
+		if (fp->f_type != DTYPE_VNODE)
+			return EINVAL;
+
+		/* Linux mmap() just fails for O_WRONLY files */
+		if (! (fp->f_flag & FREAD))
+			return EACCES;
+
  		bsd_args.fd = linux_args->fd;
+		fdrop(fp, td);
+	}
  	bsd_args.pos = linux_args->pos;
  	bsd_args.pad = 0;




More information about the freebsd-emulation mailing list