658 lines
14 KiB
C
658 lines
14 KiB
C
/**************************************************************************
|
|
* *
|
|
* Copyright (C) 1986, Silicon Graphics, Inc. *
|
|
* *
|
|
* These coded instructions, statements, and computer programs contain *
|
|
* unpublished proprietary information of Silicon Graphics, Inc., and *
|
|
* are protected by Federal copyright law. They may not be disclosed *
|
|
* to third parties or copied or duplicated in any form, in whole or *
|
|
* in part, without the prior written consent of Silicon Graphics, Inc. *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#ident "$Revision: 1.10 $ $Author: tee $"
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <malloc.h>
|
|
#include <sys/param.h>
|
|
#include <sys/sysmacros.h>
|
|
|
|
char *filename;
|
|
struct stat statbuf;
|
|
int a_sh_0_end;
|
|
int a_sh_8_4;
|
|
int a_sh_2_16;
|
|
int a_pr_0_end;
|
|
int a_pr_2_16;
|
|
char *pattern = "XXXXXXX XXXXXXX XXXXXXX XXXXXXX XXXXXXX XXXXXXX XXXXXXX XXXXXXX\n";
|
|
|
|
static int pagesize;
|
|
#undef _PAGESZ
|
|
#define _PAGESZ pagesize
|
|
#undef NBPC
|
|
#undef btoc
|
|
#define NBPC pagesize
|
|
#define btoc(X) ((((unsigned)(X)) + pagesize - 1)/pagesize)
|
|
|
|
#define NMAPPEDFILES 10
|
|
#define NPAGES 20
|
|
#define LINESIZE 64
|
|
#define NLINES NPAGES * NBPC / LINESIZE
|
|
|
|
char *rbuf;
|
|
|
|
#define LOUD 0
|
|
#define SOFT 1
|
|
#define QUIET 2
|
|
|
|
struct mappedfiles {
|
|
caddr_t Address; /* mapped virtual address */
|
|
int Len; /* length */
|
|
int Prot; /* protections */
|
|
int Flags; /* flags, of course */
|
|
int Fo; /* index into openfile[] array */
|
|
off_t Off; /* file offset of mapping */
|
|
} mappedfile[] = {
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
{ 0, 0, 0, 0, 0, 0 } ,
|
|
};
|
|
|
|
struct openfiles {
|
|
int fd;
|
|
char *name;
|
|
} openedfile[] = {
|
|
{ -1, "rdonly" } ,
|
|
{ -1, "wronly" } ,
|
|
{ -1, "rdwr" } ,
|
|
{ -1, "???" } ,
|
|
};
|
|
|
|
void bail(void);
|
|
pid_t child(off_t offset, int npages, int key, int writeback);
|
|
int map(caddr_t address, int length, int prot, int flags, int fo, off_t offset);
|
|
int checksums(char *p, int npages, int key, int volume);
|
|
pid_t cmapsum(char *address, int length, int protections, int flags, int fd, off_t offset, int keyout, int keyin, int playc);
|
|
int openfile(char *filename, int mode);
|
|
int mysync(caddr_t address, int length, int flags, int mindx);
|
|
|
|
void
|
|
do_prot(int prot)
|
|
{
|
|
printf("prot: ");
|
|
if (prot & PROT_READ) printf("read, ");
|
|
if (prot & PROT_WRITE) printf("write, ");
|
|
if (prot & PROT_EXECUTE) printf("exec, ");
|
|
}
|
|
|
|
void
|
|
do_flags(int flags)
|
|
{
|
|
printf("type: ");
|
|
if ((flags & MAP_TYPE) == 0) printf("none, ");
|
|
else {
|
|
if (flags & MAP_SHARED) printf("shared, ");
|
|
if (flags & MAP_PRIVATE) printf("private, ");
|
|
}
|
|
if (flags & MAP_FIXED) printf("map fixed, ");
|
|
if (flags & MAP_RENAME) printf("map rename, ");
|
|
}
|
|
|
|
void
|
|
do_mapped(int mindx)
|
|
{
|
|
printf("addr: 0x%x, len: 0x%x, foffset 0x%x, ",
|
|
mappedfile[mindx].Address,
|
|
mappedfile[mindx].Len, mappedfile[mindx].Off);
|
|
do_prot(mappedfile[mindx].Prot);
|
|
do_flags(mappedfile[mindx].Flags);
|
|
}
|
|
|
|
#define addr(resource) mappedfile[resource].Address
|
|
#define len(resource) mappedfile[resource].Len
|
|
#define pglen(resource) btoc(mappedfile[resource].Len)
|
|
#define off(resource) mappedfile[resource].Off
|
|
#define release(resource) mappedfile[resource].Address = 0
|
|
|
|
|
|
int
|
|
map(caddr_t address, int length, int prot, int flags, int fo, off_t offset)
|
|
{
|
|
register caddr_t vaddr;
|
|
register int i;
|
|
|
|
for (i = 0; i < NMAPPEDFILES; i++) {
|
|
if (mappedfile[i].Address == 0)
|
|
break;
|
|
}
|
|
if (i == NMAPPEDFILES) {
|
|
printf("msync:ERROR:mapped file test table overflow! quitting!\n");
|
|
exit(1);
|
|
}
|
|
|
|
printf("msync:%d:mapping %s(fd %d): addr 0x%x, off: 0x%x, len: 0x%x ",
|
|
getpid(), openedfile[fo].name, openedfile[fo].fd, address, offset,length);
|
|
do_prot(prot), do_flags(flags);
|
|
|
|
errno = 0;
|
|
vaddr = mmap(address, length, prot, flags, openedfile[fo].fd, offset);
|
|
if (errno) {
|
|
perror("msync:ERROR:mmap");
|
|
return(-1);
|
|
}
|
|
printf("returned 0x%x\n", vaddr);
|
|
mappedfile[i].Address = vaddr;
|
|
mappedfile[i].Len = length;
|
|
mappedfile[i].Prot = prot;
|
|
mappedfile[i].Flags = flags;
|
|
mappedfile[i].Fo = fo;
|
|
mappedfile[i].Off = offset;
|
|
return(i);
|
|
}
|
|
|
|
int
|
|
mysync(caddr_t address, int length, int flags, int mindx)
|
|
{
|
|
printf("msync:msync(0x%x, 0x%x, ", address, length);
|
|
|
|
if (flags & MS_ASYNC) {
|
|
printf("MS_ASYNC");
|
|
if (flags & MS_INVALIDATE)
|
|
printf("|MS_INVALIDATE");
|
|
printf(")");
|
|
} else if (flags & MS_INVALIDATE)
|
|
printf("MS_INVALIDATE)");
|
|
else
|
|
printf("0x%x)", flags);
|
|
|
|
printf(" -- file mapped ");
|
|
do_mapped(mindx);
|
|
|
|
errno = 0;
|
|
msync(address, length, flags);
|
|
if (errno) {
|
|
perror("msync:ERROR:msync");
|
|
return(-1);
|
|
}
|
|
printf("returned OK\n");
|
|
return(0);
|
|
}
|
|
|
|
unmap(address, length, mindx)
|
|
register caddr_t address;
|
|
register int length, mindx;
|
|
{
|
|
printf("msync:munmap(0x%x, 0x%x), file mapped ", address, length);
|
|
do_mapped(mindx);
|
|
|
|
errno = 0;
|
|
if (munmap(address, length)) {
|
|
perror("msync:ERROR:munmap");
|
|
return(-1);
|
|
}
|
|
printf("returned OK\n");
|
|
return(0);
|
|
}
|
|
|
|
|
|
void
|
|
makesums(char *p, int npages, int key)
|
|
{
|
|
int i;
|
|
char a; /* msb */
|
|
char b; /* */
|
|
char c; /* lsb */
|
|
|
|
printf("msync:Making checksums: %d pages from 0x%x, key %d\n", npages, p,key);
|
|
|
|
a = b = 0;
|
|
while (key >= 100) {
|
|
a++;
|
|
key -= 100;
|
|
}
|
|
while (key >= 10) {
|
|
b++;
|
|
key -= 10;
|
|
}
|
|
c = key;
|
|
a += '0', b += '0', c += '0';
|
|
|
|
for (i = 0; i < npages; i++, p += NBPC) {
|
|
*(p+2) = c++;
|
|
*(p+1) = b;
|
|
*(p) = a;
|
|
if (c > '9') {
|
|
c = '0';
|
|
if (++b > '9') {
|
|
b = '0';
|
|
++a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
checksums(char *p, int npages, int key, int volume)
|
|
{
|
|
char a; /* msb */
|
|
char b; /* */
|
|
char c; /* lsb */
|
|
int j;
|
|
int nerrors = 0;
|
|
|
|
if (volume != QUIET)
|
|
printf("msync:Doing checksums: %d pages from 0x%x, key %d\n",
|
|
npages, p, key);
|
|
|
|
a = b = 0;
|
|
while (key >= 100) {
|
|
a++;
|
|
key -= 100;
|
|
}
|
|
while (key >= 10) {
|
|
b++;
|
|
key -= 10;
|
|
}
|
|
c = key;
|
|
a += '0', b += '0', c += '0';
|
|
|
|
for (j = 0; j < npages; j++, p += NBPC) {
|
|
if ((*p != a) || (*(p+1) != b) || (*(p+2) != c)) {
|
|
nerrors++;
|
|
if (volume == LOUD) {
|
|
printf("msync:page %d failed! -- got %c %c %c instead of %c %c %c\n",
|
|
j, *p, *(p+1), *(p+2), a, b, c);
|
|
bail();
|
|
}
|
|
}
|
|
c++;
|
|
if (c > '9') {
|
|
c = '0';
|
|
if (++b > '9') {
|
|
b = '0';
|
|
++a;
|
|
}
|
|
}
|
|
}
|
|
return(nerrors);
|
|
}
|
|
|
|
int
|
|
openfile(char *filename, int mode)
|
|
{
|
|
int fd;
|
|
|
|
errno = 0;
|
|
fd = open(filename, mode);
|
|
if (errno) {
|
|
perror("msync:ERROR:open");
|
|
abort();
|
|
}
|
|
return(fd);
|
|
}
|
|
|
|
void
|
|
catch_sig(sig)
|
|
{
|
|
printf("msync:got signal %d", sig);
|
|
exit(0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
FILE *f;
|
|
int i;
|
|
int keyout1, keyin1;
|
|
int keyout2, keyin2;
|
|
int keyout3, keyin3;
|
|
off_t offset1, offset2;
|
|
int size, prot, playchar;
|
|
char *p;
|
|
|
|
pagesize = getpagesize();
|
|
setlinebuf(stdout);
|
|
if (argc > 1)
|
|
filename = argv[1];
|
|
else
|
|
filename = tempnam(NULL, "Tmap1");
|
|
printf("msync:(more) Implicit i/o tests, using file %s\n", filename);
|
|
|
|
printf("msync:Creating %s\n", filename);
|
|
f = fopen(filename, "w+");
|
|
if (f == NULL) {
|
|
perror("msync:ERROR:mmap test, fopen");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Create a file of NPAGES pages
|
|
*/
|
|
|
|
rbuf = (char *)malloc(NPAGES*NBPC);
|
|
if (rbuf == NULL) {
|
|
perror("msync:ERROR:mmap test, malloc");
|
|
bail();
|
|
}
|
|
for (i = 0 ; i < NLINES ; i++) {
|
|
if (fwrite(pattern, 1, 64, f) != 64) {
|
|
perror("msync:ERROR:mmap test, fwrite");
|
|
bail();
|
|
}
|
|
}
|
|
fclose(f);
|
|
|
|
/*
|
|
* Now we'll open the file three ways,
|
|
* O_RDONLY, O_WRONLY, and O_RDWR.
|
|
*/
|
|
errno = 0;
|
|
chmod(filename, 0777);
|
|
if (errno) {
|
|
perror("msync:ERROR:mmap test, chmod");
|
|
bail();
|
|
}
|
|
openedfile[O_RDONLY].fd = openfile(filename, O_RDONLY);
|
|
openedfile[O_WRONLY].fd = openfile(filename, O_WRONLY);
|
|
openedfile[O_RDWR].fd = openfile(filename, O_RDWR);
|
|
if (errno) {
|
|
perror("msync:ERROR:mmap test, open");
|
|
bail();
|
|
}
|
|
|
|
if ((a_sh_0_end = map(NULL, 20*NBPC, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, O_RDWR, NULL)) < 0)
|
|
bail();
|
|
|
|
/*
|
|
* Sync the file then have child read file.
|
|
* Child should be able to see our changes.
|
|
* pg 0 0 0 chksum 0 0 9
|
|
* pg 0 0 1 chksum 0 1 0
|
|
* ... ...
|
|
* pg 0 1 9 chksum 0 2 8
|
|
*/
|
|
keyout1 = 9, keyin1 = 0;
|
|
makesums(addr(a_sh_0_end), pglen(a_sh_0_end), keyout1);
|
|
mysync(addr(a_sh_0_end), len(a_sh_0_end), 0, a_sh_0_end);
|
|
child(off(a_sh_0_end), pglen(a_sh_0_end), keyout1, keyin1);
|
|
wait((int *)0);
|
|
checksums(addr(a_sh_0_end), pglen(a_sh_0_end),
|
|
keyin1 == 0 ? keyout1 : keyin1, LOUD);
|
|
|
|
/*
|
|
* Write new checksums.
|
|
* pg 0 0 0 chksum 0 0 2
|
|
* pg 0 0 1 chksum 0 0 3
|
|
* ... ...
|
|
* pg 0 1 9 chksum 0 2 1
|
|
*/
|
|
keyout1 = 2, keyin1 = 4;
|
|
makesums(addr(a_sh_0_end), pglen(a_sh_0_end), keyout1);
|
|
/*
|
|
* Sync the file w/ MS_INVALIDATE, and
|
|
* have child write back a new checksum key.
|
|
* pg 0 0 0 chksum 0 0 4
|
|
* pg 0 0 1 chksum 0 0 5
|
|
* ... ...
|
|
* pg 0 1 9 chksum 0 2 3
|
|
* Check checksums based on new checksum key.
|
|
*/
|
|
mysync(addr(a_sh_0_end), len(a_sh_0_end), MS_INVALIDATE, a_sh_0_end);
|
|
child(off(a_sh_0_end), pglen(a_sh_0_end), keyout1, keyin1);
|
|
wait((int *)0);
|
|
checksums(addr(a_sh_0_end), pglen(a_sh_0_end), keyin1, LOUD);
|
|
|
|
|
|
keyout1 = 13, keyin1 = 11, playchar = 24;
|
|
offset1 = 8 * NBPC, size = 10 * NBPC;
|
|
prot = PROT_READ | PROT_WRITE;
|
|
/*
|
|
* Now spawn off another child that maps the same file,
|
|
* reading and writing. This creates a separate region.
|
|
* Child writes checksums based on keyin.
|
|
* pg 0 0 8 chksum 0 1 9 (was 0 1 2)
|
|
* pg 0 0 9 chksum 0 2 0
|
|
* ... ...
|
|
* pg 0 1 7 chksum 0 2 3
|
|
*
|
|
* Child doesn't return until keyout checksum is found in offset page:
|
|
* pg 0 0 8 chksum 0 2 1 (was 0 1 9)
|
|
*/
|
|
cmapsum(0, size, prot, MAP_SHARED, O_RDWR, offset1,
|
|
keyin1, keyout1, playchar);
|
|
|
|
keyout2 = 20, keyin2 = 3, playchar = 31;
|
|
offset2 = 6 * NBPC, size = 9 * NBPC;
|
|
prot = PROT_READ | PROT_WRITE;
|
|
/*
|
|
* Now spawn off another child that maps the same file,
|
|
* reading and writing. This creates a separate region.
|
|
* Child writes checksums based on keyin.
|
|
* pg 0 0 6 chksum 0 0 9 (was 0 1 7)
|
|
* pg 0 0 7 chksum 0 1 0
|
|
* ... ...
|
|
* pg 0 1 4 chksum 0 1 7
|
|
*
|
|
* Child doesn't return until keyout checksum is found in offset page:
|
|
* pg 0 0 6 chksum 0 2 6 (was 0 ? ?)
|
|
*/
|
|
cmapsum(0, size, prot, MAP_SHARED, O_RDWR, offset2,
|
|
keyin2, keyout2, playchar);
|
|
|
|
p = addr(a_sh_0_end) + offset1;
|
|
/* ``keyout1'' checksum lets child return
|
|
* pg 0 0 8 chksum 0 2 1 (was 0 1 1)
|
|
*/
|
|
makesums(p, 1, keyout1);
|
|
wait((int *)0);
|
|
|
|
p = addr(a_sh_0_end) + offset2;
|
|
/* ``keyout2'' checksum lets child return
|
|
* pg 0 0 6 chksum 0 2 6 (was 0 1 1)
|
|
*/
|
|
makesums(p, 1, keyout2);
|
|
wait((int *)0);
|
|
wait((int *)0);
|
|
|
|
/* NOW, do our msync(.... MS_INVALIDATE) test */
|
|
keyout3 = 2, keyin3 = 5;
|
|
/*
|
|
* pg 0 0 0 chksum 0 0 2 (was ? ? ?)
|
|
* pg 0 0 1 chksum 0 0 3
|
|
* ... ...
|
|
* pg 0 1 9 chksum 0 2 1
|
|
*/
|
|
makesums(addr(a_sh_0_end), pglen(a_sh_0_end), keyout3);
|
|
mysync(addr(a_sh_0_end), len(a_sh_0_end), MS_INVALIDATE, a_sh_0_end);
|
|
child(off(a_sh_0_end), pglen(a_sh_0_end), keyout3, keyin3);
|
|
wait((int *)0);
|
|
/*
|
|
* Look for our new checksums...
|
|
*
|
|
* pg 0 0 0 chksum 0 0 5 (was 0 0 2)
|
|
* pg 0 0 1 chksum 0 0 6
|
|
* ... ...
|
|
* pg 0 1 9 chksum 0 2 4
|
|
*/
|
|
checksums(addr(a_sh_0_end), 20, keyin3, LOUD);
|
|
unlink(filename);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Fork child.
|
|
* Child maps fd beginning at offset for length bytes, etc.
|
|
* We return child's pid to parent.
|
|
* Child makes checksums based on keyout value; parent spins until
|
|
* it sees those checksums in its mapping of the file.
|
|
* Now child spins until it sees keyin checksums in its mapping.
|
|
* While spinning, child does reads and writes on non-checksum areas,
|
|
* performing sanity checks.
|
|
*/
|
|
|
|
pid_t
|
|
cmapsum(char *address,
|
|
int length,
|
|
int protections,
|
|
int flags,
|
|
int fd,
|
|
off_t offset,
|
|
int keyout,
|
|
int keyin,
|
|
int playc)
|
|
{
|
|
int mindx, i;
|
|
char *p, b, c;
|
|
int forkid;
|
|
int iteration = 0;
|
|
int nerrors = 0;
|
|
|
|
forkid = fork();
|
|
|
|
if (forkid == -1) {
|
|
printf("msync:ERROR:fork failed, exiting!\n");
|
|
bail();
|
|
}
|
|
|
|
/* parent */
|
|
if (forkid != 0) {
|
|
p = addr(a_sh_0_end) + offset;
|
|
/* spin until child has written new checksums */
|
|
while (checksums(p, btoc(length), keyout, SOFT)) {
|
|
sleep(1);
|
|
}
|
|
if ((checksums(p, btoc(length), keyin, QUIET)) == 0) {
|
|
fprintf(stderr, "msync:OUCH -- child got ahead of us!\n");
|
|
kill(forkid, 9);
|
|
bail();
|
|
}
|
|
return(forkid);
|
|
}
|
|
|
|
if ((mindx = map(address, length, protections, flags, fd, offset)) < 0){
|
|
fprintf(stderr, "msync:OUCH: child quitting early!!\n");
|
|
exit(1);
|
|
}
|
|
p = addr(mindx);
|
|
b = 0x20;
|
|
for (i = 0; i < btoc(length); i++) {
|
|
*(p+playc) = b;
|
|
p += ctob(1);
|
|
}
|
|
makesums(addr(mindx), pglen(mindx), keyout);
|
|
|
|
while (checksums(addr(mindx), 1, keyin, QUIET)) {
|
|
p = addr(mindx);
|
|
for (i = 0; i < btoc(length); i++) {
|
|
c = *(p+playc);
|
|
if (c != b) {
|
|
nerrors++;
|
|
}
|
|
if (++c > 0x7e)
|
|
c = 0x20;
|
|
*(p+playc) = c;
|
|
p += ctob(1);
|
|
}
|
|
iteration++;
|
|
if (++b > 0x7e)
|
|
b = 0x20;
|
|
}
|
|
sleep(1);
|
|
fprintf(stderr, "msync:cmapsum: got %d errors in %d iterations\n",
|
|
nerrors, iteration);
|
|
exit(1);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
pid_t
|
|
child(off_t offset, int npages, int key, int writeback)
|
|
{
|
|
int i;
|
|
int forkid;
|
|
ssize_t retval;
|
|
int fd = openedfile[O_RDWR].fd;
|
|
|
|
forkid = fork();
|
|
if (forkid == -1) {
|
|
printf("msync:fork failed, exiting!\n");
|
|
bail();
|
|
}
|
|
/* parent */
|
|
if (forkid)
|
|
return(forkid);
|
|
/* child */
|
|
if (forkid == 0) {
|
|
errno = 0;
|
|
lseek(fd, offset, 0);
|
|
if (errno) {
|
|
perror("msync:child lseek");
|
|
exit(1);
|
|
}
|
|
retval = read(fd, rbuf, npages * NBPC);
|
|
if (errno) {
|
|
perror("msync:child read");
|
|
exit(1);
|
|
}
|
|
if (retval != npages * NBPC) {
|
|
fprintf(stderr, "msync:OUCH! read returned 0x%x, not 0x%x\n",
|
|
retval, NPAGES*NBPC);
|
|
}
|
|
/*
|
|
* fake up a mapped file structure so we can call checksums
|
|
*/
|
|
for (i = 0; i < NMAPPEDFILES; i++) {
|
|
if (mappedfile[i].Address == 0)
|
|
break;
|
|
}
|
|
mappedfile[i].Address = rbuf;
|
|
mappedfile[i].Len = NPAGES;
|
|
mappedfile[i].Prot = 0;
|
|
mappedfile[i].Flags = 0;
|
|
mappedfile[i].Fo = O_RDWR;
|
|
mappedfile[i].Off = 0;
|
|
|
|
checksums(rbuf, npages, key, 0);
|
|
|
|
if (writeback) {
|
|
lseek(fd, offset, 0);
|
|
makesums(rbuf, npages, writeback);
|
|
retval = write(fd, rbuf, npages * NBPC);
|
|
if (errno) {
|
|
perror("msync:child write");
|
|
exit(1);
|
|
}
|
|
if (retval != npages * NBPC) {
|
|
fprintf(stderr, "msync:OUCH! write returned 0x%x, not 0x%x\n",
|
|
retval, NPAGES*NBPC);
|
|
}
|
|
}
|
|
mappedfile[i].Address = 0;
|
|
|
|
exit(0);
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
void
|
|
bail(void)
|
|
{
|
|
unlink(filename);
|
|
abort();
|
|
}
|