mmap syscall problem
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 ABCD\n EFGH\n - 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 ------------ 0x10026000: 0x41424344 0x10026004: 0x0a204546 0x10026008: 0x47480a20 0x1002600c: 0x626c6120 0x10026010: 0x626c6120 0x10026014: 0x626c610a 0x10026018: 0x11121300 0x1002601c: 0x00000000 0x10026020: 0x00000000 0x10026024: 0x00000000 0x10026028: 0x00000000 0x1002602c: 0x00000000 0x10026030: 0x00000000 0x10026034: 0x00000000 0x10026038: 0x00000000
Second 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: 0x626c6120 0x10026014: 0x626c610a 0x10026018: 0x11121300 0x1002601c: 0x00000000 0x10026020: 0x00000000 0x10026024: 0x00000000 0x10026028: 0x00000000 0x1002602c: 0x00000000 0x10026030: 0x00000000 0x10026034: 0x00000000 0x10026038: 0x00000000 ------------ 0x10026000: 0x41424344 0x10026004: 0x0a204546 0x10026008: 0x47480a20 0x1002600c: 0x626c6120 0x10026010: 0x626c6120 0x10026014: 0x626c610a 0x10026018: 0x11121300 0x1002601c: 0x00000000 0x10026020: 0x00000000 0x10026024: 0x00000000 0x10026028: 0x00000000 0x1002602c: 0x00000000 0x10026030: 0x00000000 0x10026034: 0x00000000 0x10026038: 0x00000000
If I add any code which do any loop for delay program a little bit - program passed that's why
I think that my problem could be related with any timing issue. I tried to run that test on x86 and there is no problem with that test but doesn't mean that
the problem is not there too (just x86 is much faster than Microblaze)
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[] = "ABCD\n EFGH\n"; //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%x\n", 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%x\n", test, *test);
test++;
}/* test with printf - on nfs works, on initramfs sometimes failed */
printf("hello\n");/* 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%x\n", 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%08x\n", 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("------------\n");
file = (int *)addr;
for( i = 0; i<(15); i++) {
printf("0x%x: 0x%08x\n", file, *file);
file++;
}
/*
* 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);
}
}Signature · 3 lines
Michal Simek, Ing. (M.Eng) PetaLogix - Linux Solutions for a Reconfigurable World w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663
/*
*
* 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[] = "ABCD\n EFGH\n"; //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%x\n", 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%x\n", test, *test);
test++;
}/* test with printf - on nfs works, on initramfs sometimes failed */
printf("hello\n");/* 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%x\n", 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%08x\n", 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("------------\n");
file = (int *)addr;
for( i = 0; i<(15); i++) {
printf("0x%x: 0x%08x\n", file, *file);
file++;
}
/*
* 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);
}
}Quoted 3 lines · Michal Simek
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.
Quoted 2 lines
Arnd: Anyway maybe worth to move
sys_mmap2to 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 <><
------------------------------------------------------------------------------
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list
Quoted 11 lines · Arnd Bergmann
Quoted 4 lines · Michal Simek
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.
Quoted 2 lines
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.
Quoted 4 lines
For -nommu, there are a number of ristrictions from
Documentation/nommu-mmap.txt, in particular,MAP_FIXEDis forbidden, as isPROT_WRITEwith regular files.
This test can'b be run on noMMU.
Michal
Quoted 14 lines
Quoted 5 lines
Arnd: Anyway maybe worth to move
sys_mmap2to 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 <><
Signature · 3 lines
Michal Simek, Ing. (M.Eng) PetaLogix - Linux Solutions for a Reconfigurable World w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663
Quoted 4 lines · Michal Simek
Quoted 3 lines
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 -- the cache controller is still busy writing back the data when you start reading it from DRAM through the cache alias.
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 <><
Quoted 9 lines · Arnd Bergmann
Quoted 6 lines · Michal Simek
Quoted 4 lines
Does this happen on microblaze-mmu or microblaze-nommu, or both? The mmap code for the two is very different.
For MMU code.
Quoted 8 lines
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 -- the cache controller is still busy writing back the data when you start reading it from DRAM through the cache alias.
I don't think so because we run that test on Microblaze without caches and test failed too.
I think that this is sufficient test to tell that the problem is not relate with caches.
Michal
Quoted 6 lines
If this is your problem, then you need to implement
flush_dcache_page()and other functions that maintain cache consistency. SeeDocumentation/cachetlb.txtand http://www.linuxjournal.com/article/7105Arnd <><
Signature · 3 lines
Michal Simek, Ing. (M.Eng) PetaLogix - Linux Solutions for a Reconfigurable World w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663
Quoted 18 lines · Michal Simek
Quoted 9 lines · Arnd Bergmann
Quoted 6 lines · Michal Simek
Quoted 4 lines
Does this happen on microblaze-mmu or microblaze-nommu, or both? The mmap code for the two is very different.
For MMU code.
Quoted 8 lines
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 -- the cache controller is still busy writing back the data when you start reading it from DRAM through the cache alias.
Quoted 5 lines
I don't think so because we run that test on Microblaze without caches and test failed too.
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.
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).
Quoted 30 lines · Paul Mundt
Quoted 22 lines · Michal Simek
Quoted 11 lines · Arnd Bergmann
Quoted 8 lines · Michal Simek
Quoted 5 lines
Does this happen on microblaze-mmu or microblaze-nommu, or both? The mmap code for the two is very different.
For MMU code.
Quoted 9 lines
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 -- the cache controller is still busy writing back the data when you start reading it from DRAM through the cache alias.
Quoted 6 lines
I don't think so because we run that test on Microblaze without caches and test failed too.
I think that this is sufficient test to tell that the problem is not relate with caches.
Quoted 7 lines
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 likePAGE_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.
Quoted 4 lines
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.cfor a better idea).
Thanks,
Michal
Signature · 3 lines
Michal Simek, Ing. (M.Eng) PetaLogix - Linux Solutions for a Reconfigurable World w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663
Quoted 8 lines · Michal Simek
Quoted 8 lines
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 likePAGE_SIZE* 4.
Quoted 4 lines
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.
There may still be a problem with data being queued in some write buffers that don't get flushed before reading back from another address.
What happens in a simple user space program that mmaps the same page to two addresses? Something like
#include <sys/mman.h>
#include <fcntl.h>
int main(void)
{
int fd = open("existing-4k-file", O_RDWR);
char *p1 = mmap(0, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
char *p2 = mmap(p1 + 4096, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, 0);
*p1 = 0xaa; *p2 = 0x55;
return *p1; /* returns 0xaa if broken, 0x55 if correct */
}Arnd <><
Quoted 26 lines · Arnd Bergmann
Quoted 8 lines · Michal Simek
Quoted 8 lines
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 likePAGE_SIZE* 4.Quoted 5 lines
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.There may still be a problem with data being queued in some write buffers that don't get flushed before reading back from another address.
What happens in a simple user space program that mmaps the same page to two addresses? Something like
#include <
sys/mman.h>
#include <fcntl.h>
int main(void)
Quoted 9 lines
{
int fd = open("existing-4k-file", O_RDWR);
char *p1 = mmap(0, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
char *p2 = mmap(p1 + 4096, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, 0);
*p1 = 0xaa; *p2 = 0x55;I closed fd too.
close(fd);
Quoted 3 lines
return *p1; /* returns 0xaa if broken, 0x55 if correct */ }
# ls -la existing-4k-file -rw-rw-r-- 1 monstr monstr 4096 Jul 6 2009 existing-4k-file
# ./test-arnd # echo $? 85 # dd if=existing-4k-file of=/dev/console count=1 2>/dev/null U#
in file is first char U (0x55) which is IMO correct.
Michal
Quoted 2 lines
Arnd <><
Signature · 10 lines
Michal Simek, Ing. (M.Eng) PetaLogix - Linux Solutions for a Reconfigurable World w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663 ------------------------------------------------------------------------------ _______________________________________________ Ltp-list mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ltp-list
Quoted 6 lines · Michal Simek
Quoted 2 lines
*p1 = 0xaa; *p2 = 0x55;I closed fd too.
close(fd);Quoted 2 lines
return *p1; /* returns 0xaa if broken, 0x55 if correct */ }
If you close the fd between the assignment and reading from the pointer again, the test case becomes invalid because of timing. Closing the fd before the '*p1 = 0xaa' should be fine, but unnecessary.
I also realized that you might need to mark the pointers as 'volatile' so that the compiler has to do the operations in order.
Quoted 7 lines
Quoted 1 line
# ls -la existing-4k-file -rw-rw-r-- 1 monstr monstr 4096 Jul 6 2009 existing-4k-file# ./test-arnd # echo $? 85
Ok, so inside a single task, this does not happen.
Quoted 4 lines
# dd if=existing-4k-file of=/dev/console count=1 2>/dev/null U#in file is first char U (
0x55) which is IMO correct.
Right, though that was not part of the test, I'd expect this in the file even if the return value was broken.
Arnd <><
Quoted 12 lines · Arnd Bergmann
Quoted 9 lines · Michal Simek
Quoted 3 lines
*p1 = 0xaa; *p2 = 0x55;I closed fd too.
close(fd);Quoted 3 lines
return *p1; /* returns 0xaa if broken, 0x55 if correct */ }
Quoted 10 lines
If you close the fd between the assignment and reading from the pointer again, the test case becomes invalid because of timing. Closing the fd before the '*p1 =
0xaa' should be fine, but unnecessary.I also realized that you might need to mark the pointers as 'volatile' so that the compiler has to do the operations in order.
The result are the same. I tried to run mmap test which are in LTP and only first one failed.
Do you have any ideas what buffer could caused that problems?
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
# ls -la existing-4k-file -rw-rw-r-- 1 monstr monstr 4096 Jul 6 2009 existing-4k-file
Quoted 7 lines
Quoted 4 lines
# ./test-arnd # echo $? 85Ok, so inside a single task, this does not happen.
I print output in that task and there is 0x55 too.
Quoted 10 lines
Quoted 6 lines
# dd if=existing-4k-file of=/dev/console count=1 2>/dev/null U#in file is first char U (
0x55) which is IMO correct.Right, though that was not part of the test, I'd expect this in the file even if the return value was broken.
Not in case that mmap is completely broken. This test confirm that mmap map that fd and is possible to write there.
Thanks,
Michal
Quoted 2 lines
Arnd <><
Signature · 3 lines
Michal Simek, Ing. (M.Eng) PetaLogix - Linux Solutions for a Reconfigurable World w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663
Quoted 6 lines · Arnd Bergmann
What happens in a simple user space program that mmaps the same page to two addresses? Something like
#include <
sys/mman.h>
#include <fcntl.h>
int main(void)
Quoted 11 lines
{
int fd = open("existing-4k-file", O_RDWR);
char *p1 = mmap(0, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
char *p2 = mmap(p1 + 4096, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, 0);
*p1 = 0xaa; *p2 = 0x55;
return *p1; /* returns 0xaa if broken, 0x55 if correct */
}Strictly speaking, doesn't that need a barrier of some sort between the two assignments? I mean, how is gcc supposed to intuit that p1 and p2 alias each other and it needs to reload *p1 before returning that value?
(And in more complicated code, I could even see the compiler re-ordering those two assignments, so the in-file value is different as well as the return; value)