Re: [PATCH v3] vfs: fix a bug when we do some dio reads with append dio writes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Sorry for the delay... this has turned out to be a somewhat more
complicated investigation than I'd first expected. In fact there are
still a few things I don't yet understand, however I thought I'd let you
know how I'm getting on in the mean time.

So I started looking at GFS2, since thats what I'm most familiar with.
I've found a couple of bugs which I'm about to post patches for,
although even with those patches GFS2 doesn't pass the test all the
time, although it does get through the test some of the time, and it
does last longer than ext4.

Since I wondered whether I was just lucky running the test against XFS,
I've run it again several times, and I still have not seen a single
failure on XFS.

In order to gain a bit more information about the problem, I added a few
more things to the printf, and in particular I note that under GFS2 I
see ret (the amount of data read) at various different sizes. On ext4,
ret is always the full 1M buffer size. So I assume that is the
difference which your patch was intended to cure.

However, I also printed out j, the offset where the first error occurs,
and in both the ext4 and gfs2 cases, that offset is 0, and after exactly
4096 bytes, there is an 'a'. I'd have expected to see a number of pages
of 'a' followed by zero pages, but instead, I'm seeing a single zero
page followed by at least one 'a'. I've not extended my instrumentation
to print out a list of which pages are zero and which 'a', but that is
an unexpected result.

Some tracing shows that with the additional GFS2 patches, the data does
get written to disk correctly, ahead of the read which is issued. Also
since the test does allocating writes, GFS2 will fall back to buffered
I/O for that, and only the read is direct I/O, so since we see similar
results in the GFS2 and ext4 cases, this missing first page which is
common to both looks like it might be related to the read side of
things.

I'm attaching my updated version of your test program, which I'd like to
add to our test suite in due course, if you have no objections.

So far I'm not sure what causes the missing first page issue though...
I'll keep looking in the mean time,

Steve.

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#include <pthread.h>

#define BUF_ALIGN	1024

struct writer_data {
	int fd;
	size_t blksize;
	char *buf;
};

static void *writer(void *arg)
{
	struct writer_data *data = (struct writer_data *)arg;
	int ret;

	ret = write(data->fd, data->buf, data->blksize);
	if (ret < 0)
		fprintf(stderr, "write file failed: %s\n", strerror(errno));

	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t tid;
	struct writer_data wdata;
	size_t max_blocks = 10 * 1024;
	size_t blksize = 1 * 1024 * 1024;
	char *rbuf, *wbuf;
	int readfd, writefd;
	int i, j;
	int k;

	if (argc < 2) {
		fprintf(stderr, "usage: %s [filename]\n", argv[0]);
		exit(1);
	}

	writefd = open(argv[1], O_CREAT|O_DIRECT|O_WRONLY|O_APPEND|O_TRUNC, S_IRWXU);
	if (writefd < 0) {
		fprintf(stderr, "failed to open wfile: %s\n", strerror(errno));
		exit(1);
	}
	readfd = open(argv[1], O_DIRECT|O_RDONLY, S_IRWXU);
	if (readfd < 0) {
		fprintf(stderr, "failed to open rfile: %s\n", strerror(errno));
		exit(1);
	}

	if (posix_memalign((void **)&wbuf, BUF_ALIGN, blksize)) {
		fprintf(stderr, "failed to alloc memory: %s\n", strerror(errno));
		exit(1);
	}

	if (posix_memalign((void **)&rbuf, 4096, blksize)) {
		fprintf(stderr, "failed to alloc memory: %s\n", strerror(errno));
		exit(1);
	}

	memset(wbuf, 'a', blksize);

	wdata.fd = writefd;
	wdata.blksize = blksize;
	wdata.buf = wbuf;

	for (i = 0; i < max_blocks; i++) {
		void *retval;
		int ret;

		ret = pthread_create(&tid, NULL, writer, &wdata);
		if (ret) {
			fprintf(stderr, "create thread failed: %s\n", strerror(errno));
			exit(1);
		}

		memset(rbuf, 'b', blksize);
		do {
			ret = pread(readfd, rbuf, blksize, i * blksize);
		} while (ret <= 0);

		if (ret < 0) {
			fprintf(stderr, "read file failed: %s\n", strerror(errno));
			exit(1);
		}

		if (pthread_join(tid, &retval)) {
			fprintf(stderr, "pthread join failed: %s\n", strerror(errno));
			exit(1);
		}

		if (ret >= 0) {
			for (j = 0; j < ret; j++) {
				if (rbuf[j] != 'a') {
					char c = rbuf[j];
					fprintf(stderr, "encounter an error: offset %ld, j=%ld, ret=%ld rbuf[j]=0x%02x\n",
						i, j, ret, rbuf[j]);
					for(k = j; k < ret; k++) {
						if (rbuf[k] != c)
							break;
					}
					fprintf(stderr, "0x%02x continues for %d bytes, next=0x%02x\n", c, k - j, rbuf[k]);
					goto err;
				}
			}
		}
	}

err:
	free(wbuf);
	free(rbuf);

	return 0;
}

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux