Viewing: directio.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
 * Use is subject to license terms.
 */
/*
 * This file is part of Lustre, http://www.lustre.org/
 */

#ifndef _GNU_SOURCE
#define  _GNU_SOURCE
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

/*
 * return index of the first byte not matching given byte
 * or buffer size if all bytes are matching
 */
static size_t check_bytes(const char *buf, int byte, size_t len)
{
	const char *p;

	for (p = buf; p < buf + len; p++)
		if (*p != byte)
			break;
	return p - buf;
}

int main(int argc, char **argv)
{
#ifdef O_DIRECT
	int fd;
	char *buf, *fname;
	int blocks, seek_blocks;
	long len;
	off64_t seek;
	struct stat64 st;
	char pad = 0xba;
	int action;
	int rc;

	if (argc < 5 || argc > 6) {
		printf("Usage: %s <read/write/rdwr/readhole> file seek nr_blocks [blocksize]\n",
		       argv[0]);
		return 1;
	}

	if (!strcmp(argv[1], "read")) {
		action = O_RDONLY;
	} else if (!strcmp(argv[1], "write")) {
		action = O_WRONLY;
	} else if (!strcmp(argv[1], "rdwr")) {
		action = O_RDWR;
	} else if (!strcmp(argv[1], "readhole")) {
		action = O_RDONLY;
		pad = 0;
	} else {
		printf("Usage: %s <read/write/rdwr> file seek nr_blocks [blocksize]\n",
		       argv[0]);
		return 1;
	}

	fname = argv[2];
	seek_blocks = strtoul(argv[3], 0, 0);
	blocks = strtoul(argv[4], 0, 0);
	if (!blocks) {
		printf("Usage: %s <read/write/rdwr> file seek nr_blocks [blocksize]\n",
		       argv[0]);
		return 1;
	}

	fd = open(fname, O_LARGEFILE | O_DIRECT | O_RDWR | O_CREAT, 0644);
	if (fd == -1) {
		printf("Cannot open %s:  %s\n", fname, strerror(errno));
		return 1;
	}

	if (argc >= 6) {
		st.st_blksize = strtoul(argv[5], 0, 0);
	} else if (fstat64(fd, &st) < 0) {
		printf("Cannot stat %s:  %s\n", fname, strerror(errno));
		return 1;
	}

	printf("directio on %s for %dx%lu bytes\n", fname, blocks,
	       (unsigned long)st.st_blksize);

	seek = (off64_t)seek_blocks * (off64_t)st.st_blksize;
	len = blocks * st.st_blksize;

	buf = mmap(0, len,
		   PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0);
	if (buf == MAP_FAILED) {
		printf("No memory %s\n", strerror(errno));
		return 1;
	}
	memset(buf, pad, len);

	if (action == O_WRONLY || action == O_RDWR) {
		if (lseek64(fd, seek, SEEK_SET) < 0) {
			printf("lseek64 failed: %s\n", strerror(errno));
			return 1;
		}

		rc = write(fd, buf, len);
		if (rc != len) {
			printf("Write error %s (rc = %d, len = %ld)\n",
			       strerror(errno), rc, len);
			return 1;
		}
	}

	if (action == O_RDONLY || action == O_RDWR) {
		if (lseek64(fd, seek, SEEK_SET) < 0) {
			printf("Cannot seek %s\n", strerror(errno));
			return 1;
		}
		/* reset all bytes to something nor 0x0 neither 0xab */
		memset(buf, 0x5e, len);
		rc = read(fd, buf, len);
		if (rc != len) {
			printf("Read error: %s rc = %d\n", strerror(errno), rc);
			return 1;
		}

		if (check_bytes(buf, pad, len) != len) {
			printf("Data mismatch\n");
			return 1;
		}
	}

	printf("PASS\n");
	return 0;
#else /* !O_DIRECT */
#warning O_DIRECT not defined, directio test will fail
	printf("O_DIRECT not defined\n");
	return 1;
#endif /* !O_DIRECT */
}