mmap syscall problem

Michal Simek
2009-07-03T12:37:43+00:00

Hi all,

I am trying to solve problem with mmap syscall on Microblaze which I have.
I am running mmap01 test program from LTP. In attachment is hacked
version and inline version is below too.

Here is the simple mmap test description
1. open temp file
2. write there hello word (in my case ABCDn EFGHn - for better tracing
0x41424344 0a20 45464748 0a20)
3. then find a place for allocation of mmap
4. before mmap fill this place with A - whole place (0x41 in hex)
5. then called mmap - map file with string to place which was filled by A.
6a. Correct behavior is that this place must contain only the same data
as was in file (not any A chars) (the rest of chars should be zero)
6b. Wrong behavior is that this place contain any (0x41) data - which is
my case

The facts which I know:
1. Problem is not relate with caches - We tried to run in on system
without cache and the problem is the same
2. Microblaze implementation of sys-mmap02 is the same as is for sparc,
blackfin, m68k and others.
Arnd: Anyway maybe worth to move sys-mmap2 to any generic location. What
do you think?

I copy&paste two output of that program. First checking loop show that
there are old data and second that
data are correct from address 0x10026010. Every run I am getting
different values - sometimes

First log
# ./mmap
dummy 0x10005050, addr 0x10026000, sbrk 0x100006c0 0x1000
file size=0x18, first writing addr=0x10026018
0x10026000: 0x41414141
0x10026004: 0x41414141
0x10026008: 0x41414141
0x1002600c: 0x41414141
0x10026010: 0x41414141
0x10026014: 0x41414141
0x10026018: 0x41414141
0x1002601c: 0x41414141
0x10026020: 0x41414141
0x10026024: 0x41414141
0x10026028: 0x41414141
0x1002602c: 0x41414141
0x10026030: 0x41414141
0x10026034: 0x41414141
0x10026038: 0x41414141
0x1002600c: 0x41414141
0x10026010: 0x626c6120
0x10026014: 0x626c610a
0x10026018: 0x11121300
0x1002601c: 0x00000000
0x10026020: 0x00000000
0x10026024: 0x00000000
0x10026028: 0x00000000
0x1002602c: 0x00000000
0x10026030: 0x00000000
0x10026034: 0x00000000
0x10026038: 0x00000000

Do you have any idea what could be wrong?

Thanks for your hints,
Michal


/*
 *
 *   Copyright (c) International Business Machines  Corp., 2001
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/*
 * Test Name: mmap01
 *
 * Test Description:
 *  Verify that, mmap() succeeds when used to map a file where size of the
 *  file is not a multiple of the page size, the memory area beyond the end
 *  of the file to the end of the page is accessible. Also, verify that
 *  this area is all zeroed and the modifications done to this area are
 *  not written to the file.
 *
 * Expected Result:
 *  mmap() should succeed returning the address of the mapped region.
 *  The memory area beyond the end of file to the end of page should be
 *  filled with zero.
 *  The changes beyond the end of file should not get written to the file.
 *
 * Algorithm:
 *  Setup:
 *   Setup signal handling.
 *   Pause for SIGUSR1 if option specified.
 *   Create temporary directory.
 *
 *  Test:
 *   Loop if the proper options are given.
 *   Execute system call
 *   Check return code, if system call failed (return=-1)
 *    Log the errno and Issue a FAIL message.
 *   Otherwise,
 *    Verify the Functionality of system call
 *      if successful,
 *        Issue Functionality-Pass message.
 *      Otherwise,
 *        Issue Functionality-Fail message.
 *  Cleanup:
 *   Print timing stats if options given
 *   Delete the temporary directory created.
 *
 * Usage:  <for command-line>
 *  mmap01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
 *     where,  -c n : Run n copies concurrently.
 *             -f   : Turn off functionality Testing.
 *           -i n : Execute test n times.
 *           -I x : Execute test for x seconds.
 *           -P x : Pause for x seconds between iterations.
 *           -t   : Turn on syscall timing.
 *
 * HISTORY
 *    07/2001 Ported by Wayne Boyer
 *
 * RESTRICTIONS:
 *  None.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/shm.h>

#define TEMPFILE    "mmapfile"

char *TCID = "mmap01";        /* Test program identifier.    */
int TST-TOTAL = 1;        /* Total number of test cases. */
extern int Tst-count;        /* Test Case counter for tst-* routines */
char *addr;            /* addr of memory mapped region */
char *dummy;            /* dummy string */
size-t page-sz;            /* system page size */
size-t file-sz;            /* mapped file size */
int fildes;            /* file descriptor for tempfile */
char Cmd-buffer[BUFSIZ];    /* command buffer to hold test command */

void setup();            /* Main setup function of test */
void cleanup();            /* cleanup function for the test */

int main(int ac, char **av)
{
    int lc;            /* loop counter */
    char *msg;        /* message returned from parse-opts */
    int i;
    /* Perform global setup for test */
    struct stat stat-buf;
    char write-buf[] = "ABCDn EFGHn"; //41424344

    /* Creat a temporary file used for mapping */
    if ((fildes = open(TEMPFILE, O-RDWR | O-CREAT, 0666)) < 0) {
        printf( "open() on %s Failed, errno=%d : %s", TEMPFILE, errno,
strerror(errno));
        cleanup();
    }

    /* Write some data into temporary file */
    if (write(fildes, write-buf, strlen(write-buf)) != strlen(write-buf)) {
        printf("write() on %s Failed, errno=%d : %s", TEMPFILE, errno,
strerror(errno));
        cleanup();
    }

    /* Get the size of temporary file */
    if (stat(TEMPFILE, &stat-buf) < 0) {
        printf( "stat() on %s Failed, errno=%d : %s", TEMPFILE, errno,
strerror(errno));
        cleanup();
    }
    file-sz = stat-buf.st-size;

    /* Get the system page size */
    if ((page-sz = getpagesize()) < 0) {
        printf("getpagesize() fails to get system page size");
        cleanup();
    }

    /* Allocate and initialize dummy string of system page size bytes */
    if ((dummy = (char *)calloc(page-sz, sizeof(char))) == NULL) {
        printf("calloc() failed to allocate space");
        cleanup();
    }

    /*
     * Initialize addr to align with the first segment boundary address
     * above the break address of the process.
     */
    addr = (void *)(((intptr-t) sbrk(0) + (SHMLBA - 1)) & ~(SHMLBA - 1));

    printf("dummy 0x%x, addr 0x%x, sbrk 0x%x 0x%xn", dummy, addr, sbrk,
SHMLBA);

    /* Set the break address of the process to the addr plus one
     * page size.
     */
    if ((intptr-t) sbrk(SHMLBA + page-sz) == -1) {
        printf("sbrk(SHMLBA + page-sz) failed");
        cleanup();
    }

    /* Initialize one page region from addr with 'A' */
    memset(addr, 'A', page-sz);


#if 0
/* delayed loops */
/* Hera is one loop which read all data which are in addr -> all are
0x41414141 which is correct */
    int *test = (int *)addr;

    /* +1 caused that I read one word after allocated space */
    for( i = 0; i<(page-sz/4 + 1); i++) {
        printf("0x%x: 0x%xn", test, *test);
        test++;
    }


/* test with printf - on nfs works, on initramfs sometimes failed */
    printf("hellon");

/* test with syscall */
    sync();
#endif

        /*
         * Call mmap to map the temporary file beyond EOF
         * with write access.
         */
        errno = 0;
        addr = mmap(addr, page-sz, PROT-READ | PROT-WRITE,
                MAP-FILE | MAP-SHARED | MAP-FIXED, fildes, 0);

        /* Check for the return value of mmap() */
        if (addr == MAP-FAILED) {
            printf("mmap() Failed on %s, errno=%d : %s",
                 TEMPFILE, errno, strerror(errno));
        }


    printf("file size=0x%x, first writing addr=0x%xn", file-sz,
&addr[file-sz]);

/* 1. checking loop after mmap */
/* read fist 15 words mmap memory */
    int *file = (int *)addr;
    for( i = 0; i<(15); i++) {
        printf("0x%x: 0x%08xn", file, *file);
        file++;
    }

    /*
     * Initialize memory beyond file size
     */
    addr[file-sz] = 0x11;
    addr[file-sz + 1] = 0x12;
    addr[file-sz + 2] = 0x13;

/* 2. checking after writing - always is correct */
    printf("    /*
     * Synchronize the mapped memory region
     * with the file.
     */
    if (msync(addr, page-sz, MS-SYNC) != 0) {
        printf("msync() failed to "
                "synchronize mapped file, error:%d",
                errno);
        cleanup();
    }

    /* Create the command which will be executed in the test */
    sprintf(Cmd-buffer, "grep XYZ %s > /dev/null", TEMPFILE);


    /*
        * Now, Search for the pattern 'XYZ' in the
        * temporary file.  The pattern should not be
        * found and the return value should be 1.
        */
    if (system(Cmd-buffer) != 0) {
        printf("Functionality of mmap() successful");
    } else {
        printf("Specified pattern found in file");
    }




        /* Clean up things in case we are looping */
        /* Unmap the mapped memory */
        if (munmap(addr, page-sz) != 0) {
            printf("munmap() fails to unmap the "
                 "memory, errno=%d", errno);
        }




    /* Call cleanup() to undo setup done for the test. */
    cleanup();
     /*NOTREACHED*/ return 0;
}                /* End main */

/*
 * cleanup() - performs all ONE TIME cleanup for this test at
 *             completion or premature exit.
 *           Free the memory allocated to  variable.
 *           Remove the temporary directory created.
 */
void cleanup()
{
    /*
     * print timing stats if that option was specified.
     */
    close(fildes);

    /* Free the memory allocated for dummy string */
    if (dummy) {
        free(dummy);
    }
}












Re: mmap syscall problem by Arnd Bergmann on 2009-07-03T15:03:35+00:00
On Friday 03 July 2009, Michal Simek wrote:

> I am trying to solve problem with mmap syscall on Microblaze which I have.
> I am running mmap01 test program from LTP. In attachment is hacked
> version and inline version is below too.

Does this happen on microblaze-mmu or microblaze-nommu, or both?
The mmap code for the two is very different.

What file system is backing the temporary file?

For -nommu, there are a number of ristrictions from
Documentation/nommu-mmap.txt, in particular, MAP-FIXED is
forbidden, as is PROT-WRITE with regular files. 
 
> Arnd: Anyway maybe worth to move sys-mmap2 to any generic location. What
> do you think?

Yes, that would be good. I actually have a patch for that somewhere in
my playground repository, but it build-breaks some architectures in the
current state. I'm planning to fix that (and do the same for execve
and maybe some of the other remaining arch specific syscalls) at some
point.

	Arnd <><

Re: mmap syscall problem by Michal Simek on 2009-07-06T06:32:38+00:00
Arnd Bergmann wrote:
> On Friday 03 July 2009, Michal Simek wrote:
>
>   
>> I am trying to solve problem with mmap syscall on Microblaze which I have.
>> I am running mmap01 test program from LTP. In attachment is hacked
>> version and inline version is below too.
>>     
>
> Does this happen on microblaze-mmu or microblaze-nommu, or both?
> The mmap code for the two is very different.
>   
For MMU code.

> What file system is backing the temporary file?
>   
I tested it on nfs and initramfs.
The behavior on both has the same symptoms but on initramfs is program
much faster
which is presumtive.

If I run that test, 10times or more and see the output. For example
first 4 tests failed the rest
passed. I look at cpu internals and from syscalls/context switch I see
that that 4 tests which failed
are not interrupted. The rest is interrupted and that tests passed. I
have accurate log for it if you want to see that behavior.
Interruption caused that "anything" in kernel give a time to finish any
work which caused that mmap
memory is consistent.
This behavior is seen in my previous email that depends on time when is
listing called.
Is there any part of kernel which should take care about it?

Thanks for any suggestion.


> For -nommu, there are a number of ristrictions from
> Documentation/nommu-mmap.txt, in particular, MAP-FIXED is
> forbidden, as is PROT-WRITE with regular files. 
>   
This test can'b be run on noMMU.


Michal



>  
>   
>> Arnd: Anyway maybe worth to move sys-mmap2 to any generic location. What
>> do you think?
>>     
>
> Yes, that would be good. I actually have a patch for that somewhere in
> my playground repository, but it build-breaks some architectures in the
> current state. I'm planning to fix that (and do the same for execve
> and maybe some of the other remaining arch specific syscalls) at some
> point.
>
> 	Arnd <><
>   



Re: mmap syscall problem by Arnd Bergmann on 2009-07-06T08:06:12+00:00
On Monday 06 July 2009, Michal Simek wrote:
> > Does this happen on microblaze-mmu or microblaze-nommu, or both?
> > The mmap code for the two is very different.
> >   
> For MMU code.

Could this be a cache-aliasing problem? If your cache is 'virtually-indexed'
(most architectures are 'physically-indexed'), the kernel may have written
into different parts of the D-cache than what the user space is reading
from. If you have a write-through cache, that can explain why you only
see the stale data at the beginning of the page 
	Arnd <><

Re: mmap syscall problem by Michal Simek on 2009-07-06T12:07:31+00:00
Arnd Bergmann wrote:
> On Monday 06 July 2009, Michal Simek wrote:
>   
>>> Does this happen on microblaze-mmu or microblaze-nommu, or both?
>>> The mmap code for the two is very different.
>>>   
>>>       
>> For MMU code.
>>     
>
> Could this be a cache-aliasing problem? If your cache is 'virtually-indexed'
> (most architectures are 'physically-indexed'), the kernel may have written
> into different parts of the D-cache than what the user space is reading
> from. If you have a write-through cache, that can explain why you only
> see the stale data at the beginning of the page relate with caches.

Michal

> If this is your problem, then you need to implement flush-dcache-page()
> and other functions that maintain cache consistency. See
> Documentation/cachetlb.txt and http://www.linuxjournal.com/article/7105
>
> 	Arnd <><
>   



Re: mmap syscall problem by Paul Mundt on 2009-07-06T12:15:34+00:00
On Mon, Jul 06, 2009 at 02:07:06PM +0200, Michal Simek wrote:
> Arnd Bergmann wrote:
> > On Monday 06 July 2009, Michal Simek wrote:
> >   
> >>> Does this happen on microblaze-mmu or microblaze-nommu, or both?
> >>> The mmap code for the two is very different.
> >>>   
> >>>       
> >> For MMU code.
> >>     
> >
> > Could this be a cache-aliasing problem? If your cache is 'virtually-indexed'
> > (most architectures are 'physically-indexed'), the kernel may have written
> > into different parts of the D-cache than what the user space is reading
> > from. If you have a write-through cache, that can explain why you only
> > see the stale data at the beginning of the page > relate with caches.
> 
Not necessarily, even on platforms that manage aliases in hardware
mappings that violate the aliasing constraints can still result in
undefined behaviour, this really depends more on your cache controller
and MMU than anything else. I notice that microblaze sets SHMLBA to
PAGE-SIZE, you may want to see if this test still breaks after bumping it
up to something like PAGE-SIZE * 4.

This is unfortunately one of the areas where what POSIX says is possible
and what hardware can support are at odds (you can look through
arch/sh/mm/mmap.c for a better idea).

Re: mmap syscall problem by Michal Simek on 2009-07-06T12:54:30+00:00
Paul Mundt wrote:
> On Mon, Jul 06, 2009 at 02:07:06PM +0200, Michal Simek wrote:
>   
>> Arnd Bergmann wrote:
>>     
>>> On Monday 06 July 2009, Michal Simek wrote:
>>>   
>>>       
>>>>> Does this happen on microblaze-mmu or microblaze-nommu, or both?
>>>>> The mmap code for the two is very different.
>>>>>   
>>>>>       
>>>>>           
>>>> For MMU code.
>>>>     
>>>>         
>>> Could this be a cache-aliasing problem? If your cache is 'virtually-indexed'
>>> (most architectures are 'physically-indexed'), the kernel may have written
>>> into different parts of the D-cache than what the user space is reading
>>> from. If you have a write-through cache, that can explain why you only
>>> see the stale data at the beginning of the page >> I think that this is sufficient test to tell that the problem is not
>> relate with caches.
>>
>>     
> Not necessarily, even on platforms that manage aliases in hardware
> mappings that violate the aliasing constraints can still result in
> undefined behaviour, this really depends more on your cache controller
> and MMU than anything else. I notice that microblaze sets SHMLBA to
> PAGE-SIZE, you may want to see if this test still breaks after bumping it
> up to something like PAGE-SIZE * 4.
>   
Yes, test still break - behavior is the same. I don't have accurate
information about MMU unit
but I will ask a question about. We are able to turn off cache
controller directly in HW.
> This is unfortunately one of the areas where what POSIX says is possible
> and what hardware can support are at odds (you can look through
> arch/sh/mm/mmap.c for a better idea).
>   

Thanks,
Michal


Loading


$ This page is proudly powered by www.pubbs.net, you can see more at kernel archive | Partners: Global Manufacturers