
#define _GNU_SOURCE

#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define NUM_CHILDREN 8


int check_zero(char *buf, int size)
{
	int *iptr;

	iptr = (int *)buf;

	while (size > 0) {
		if (*iptr++ != 0) {
			fprintf(stderr, "non zero buffer at buf[%d]\n",
				((char *)iptr) - buf);
			return 1;
		}
		size -= 4;
	}
	return 0;	/* all zeros */
}

int dio_read(char *filename)
{
	int fd;
	int i;
	int r;
	char *bufptr;

	if (posix_memalign(&bufptr, 4096, 64*1024)) {
		perror("cannot malloc aligned memory");
		return;
	}

	while ((fd = open(filename, O_DIRECT|O_RDONLY)) < 0) {
	}
	fprintf(stderr, "dio_truncate: child reading file\n");
	while (1) {
		off_t offset;
		int bufoff;

		/* read the file, checking for zeros */
		offset = lseek(fd, SEEK_SET, 0);
		do {
			r = read(fd, bufptr, 64*1024);
			if (r > 0) {
				if ((bufoff = check_zero(bufptr, 64*1024))) {
					fprintf(stderr, "non-zero read at offset %d\n",
						offset + bufoff);
					exit(1);
				}
				offset += r;
			}
		} while (r > 0);
	}
}


void dio_append(char *filename, int fill)
{
	int fd;
	void *bufptr;
	int i;
	int w;

	fd = open(filename, O_DIRECT|O_WRONLY|O_CREAT, 0666);

	if (fd < 0) {
		perror("cannot create file");
		return;
	}

	if (posix_memalign(&bufptr, 4096, 64*1024)) {
		perror("cannot malloc aligned memory");
		return;
	}

	memset(bufptr, fill, 64*1024);

	for (i = 0; i < 1000; i++) {
		if ((w = write(fd, bufptr, 64*1024)) != 64*1024) {
			fprintf(stderr, "write %d returned %d\n", i, w);
		}
	}
	close(fd);
}

main(int argc, char **argv)
{
	int fd;
	int pid[NUM_CHILDREN];
	int num_children = 1;
	int i;
	char *filename = "file";

	for (i = 0; i < num_children; i++) {
		if ((pid[i] = fork()) == 0) {
			/* child */
			return dio_read(filename);
		} else if (pid[i] < 0) {
			/* error */
			perror("fork error");
			break;
		} else {
			/* Parent */
			continue;
		}
	}

	/*
	 * Parent creates a zero file using DIO.
	 * Truncates it to zero
	 * Create another file with '0xaa'
	 */
	for (i = 0; i < 100; i++) {
		dio_append(filename, 0);
		truncate(filename, 0);
		dio_append("junkfile", 0xaa);
		truncate("junkfile", 0);
	}

	for (i = 0; i < num_children; i++) {
		kill(pid[i], SIGTERM);
	}
}
