From 88e89be263ff9890ac2e3a62d422b9be0649da86 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Wed, 9 Jan 2008 20:49:12 +0000 Subject: - Fix the test harness (Rusty Russell) - Add eventfd support (Rusty Russell) --- ChangeLog | 11 ++++++ Makefile | 5 +++ harness/Makefile | 35 +++++++++++++---- harness/cases/12.t | 6 ++- harness/cases/14.t | 5 ++- harness/cases/15.t | 94 ++++++++++++++++++++++++++++++++++++++++++++++ harness/cases/16.t | 94 ++++++++++++++++++++++++++++++++++++++++++++++ harness/cases/5.t | 9 ++++- harness/cases/7.t | 3 ++ harness/cases/8.t | 43 ++++++--------------- harness/cases/aio_setup.h | 10 +++++ harness/cases/common-7-8.h | 3 +- harness/main.c | 1 + harness/runtests.sh | 2 +- libaio.spec | 6 ++- src/libaio.h | 51 ++++++++++++++++++++----- 16 files changed, 323 insertions(+), 55 deletions(-) create mode 100644 harness/cases/15.t create mode 100644 harness/cases/16.t diff --git a/ChangeLog b/ChangeLog index ddcf6e3..b1536b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +0.3.107 + - Make tests compile again on modern systems (warnings + -Werror) + - Add 'make partcheck' and don't require manual setup for testing. + - Change test harness to compile against this dir, not global install + - Fix 5.t for archs where PROT_WRITE mappings are readable. + - Allow sending of SIGXFSZ on aio over limits + - Explicitly specify bash for runtests.sh + - Put deprecating comments on never-merged io_prep_poll + - Add io_prep_preadv and io_prep_pwritev + - Add eventfd support (io_set_eventfd). + 0.4.0 - remove libredhat-kernel - add rough outline for man pages diff --git a/Makefile b/Makefile index 53f9bd0..4cedbc9 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,11 @@ all: install: @$(MAKE) -C src install prefix=$(prefix) includedir=$(includedir) libdir=$(libdir) +check: + @$(MAKE) -C harness check + +partcheck: all + @$(MAKE) -C harness partcheck clean: @$(MAKE) -C src clean diff --git a/harness/Makefile b/harness/Makefile index d2483fd..0bb8e3d 100644 --- a/harness/Makefile +++ b/harness/Makefile @@ -1,37 +1,56 @@ # foo. TEST_SRCS:=$(shell find cases/ -name \*.t | sort -n -t/ -k2) -PROGS:=$(patsubst %.t,%.p,$(TEST_SRCS)) +EXTRAPROGS:=cases/8.p cases/10.p +PARTPROGS:=$(filter-out $(EXTRAPROGS), $(patsubst %.t,%.p,$(TEST_SRCS))) +PROGS:=$(PARTPROGS) $(EXTRAPROGS) HARNESS_SRCS:=main.c # io_queue.c -CFLAGS=-Wall -Werror -g -O -laio +CFLAGS=-Wall -Werror -I../src -g -O #-lpthread -lrt all: $(PROGS) $(PROGS): %.p: %.t $(HARNESS_SRCS) - $(CC) $(CFLAGS) -DTEST_NAME=\"$<\" -o $@ main.c + $(CC) $(CFLAGS) -DTEST_NAME=\"$<\" -o $@ main.c ../src/libaio.a clean: rm -f $(PROGS) *.o runtests.out rofile wofile rwfile .PHONY: -testdir/rofile: .PHONY +testdir/rofile: testdir .PHONY rm -f $@ echo "test" >$@ chmod 400 $@ -testdir/wofile: .PHONY +testdir/wofile: testdir .PHONY rm -f $@ echo "test" >$@ chmod 200 $@ -testdir/rwfile: .PHONY +testdir/rwfile: testdir .PHONY rm -f $@ echo "test" >$@ chmod 600 $@ -check: $(PROGS) testdir/rofile testdir/rwfile testdir/wofile - ./runtests.sh $(PROGS) +testdir testdir.enospc testdir.ext2: + mkdir $@ +root: .PHONY + @if [ `id -u` -ne 0 ]; then echo Need root for check, try partcheck >&2; exit 1; fi + +partcheck: $(PARTPROGS) testdir/rofile testdir/rwfile testdir/wofile + ./runtests.sh $(PARTPROGS) + +ext2.img: + dd if=/dev/zero bs=1M count=10 of=$@ + mke2fs -F -b 4096 $@ + +extracheck: $(EXTRAPROGS) root testdir.ext2 testdir.enospc ext2.img + mount -o loop -t ext2 ext2-enospc.img testdir.enospc + ./runtests.sh cases/10.p; ret=$$?; umount testdir.enospc; exit $$ret + mount -o loop -t ext2 ext2.img testdir.ext2 + ./runtests.sh cases/8.p; ret=$$?; umount testdir.ext2; exit $$ret + +check: partcheck extracheck diff --git a/harness/cases/12.t b/harness/cases/12.t index 3499204..e87d1dc 100644 --- a/harness/cases/12.t +++ b/harness/cases/12.t @@ -20,11 +20,15 @@ int test_main(void) { int res, status; pid_t pid; + sigset_t set; if (attempt_io_submit(io_ctx, 0, NULL, 0)) return 1; - sigblock(sigmask(SIGCHLD) | siggetmask()); + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, NULL); + fflush(NULL); pid = fork(); assert(pid != -1); diff --git a/harness/cases/14.t b/harness/cases/14.t index 514622b..87773e3 100644 --- a/harness/cases/14.t +++ b/harness/cases/14.t @@ -61,11 +61,14 @@ int test_main(void) { int res, status; pid_t pid; + sigset_t set; if (attempt_io_submit(io_ctx, 0, NULL, 0)) return 1; - sigblock(sigmask(SIGCHLD) | siggetmask()); + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, NULL); fflush(NULL); pid = fork(); assert(pid != -1); diff --git a/harness/cases/15.t b/harness/cases/15.t new file mode 100644 index 0000000..933d008 --- /dev/null +++ b/harness/cases/15.t @@ -0,0 +1,94 @@ +/* 15.t +- pwritev and preadv tests. +*/ +#include "aio_setup.h" +#include +#include +#include + +int test_main(void) +{ +#define SIZE 512 +#define NUM_IOV 10 + char buf[SIZE*NUM_IOV]; + struct iovec iov[NUM_IOV]; + int rwfd; + int status = 0, res, i; + + rwfd = open("testdir/rwfile", O_RDWR); assert(rwfd != -1); + res = ftruncate(rwfd, sizeof(buf)); assert(res == 0); + + for (i = 0; i < NUM_IOV; i++) { + iov[i].iov_base = buf + i*SIZE; + iov[i].iov_len = SIZE; + memset(iov[i].iov_base, i, SIZE); + } + status |= attempt_rw(rwfd, iov, NUM_IOV, 0, WRITEV, SIZE*NUM_IOV); + res = pread(rwfd, buf, sizeof(buf), 0); assert(res == sizeof(buf)); + for (i = 0; i < NUM_IOV; i++) { + unsigned int j; + for (j = 0; j < SIZE; j++) { + if (buf[i*SIZE + j] != i) { + printf("Unexpected value after writev at %i\n", + i*SIZE + j); + status |= 1; + break; + } + } + } + if (!status) + printf("Checking memory: [Success]\n"); + + memset(buf, 0, sizeof(buf)); + status |= attempt_rw(rwfd, iov, NUM_IOV, 0, READV, SIZE*NUM_IOV); + for (i = 0; i < NUM_IOV; i++) { + unsigned int j; + for (j = 0; j < SIZE; j++) { + if (buf[i*SIZE + j] != i) { + printf("Unexpected value after readv at %i\n", + i*SIZE + j); + status |= 1; + break; + } + } + } + + /* Check that offset works. */ + status |= attempt_rw(rwfd, iov+1, NUM_IOV-1, SIZE, WRITEV, + SIZE*(NUM_IOV-1)); + memset(buf, 0, sizeof(buf)); + res = pread(rwfd, buf, sizeof(buf), 0); assert(res == sizeof(buf)); + for (i = 1; i < NUM_IOV; i++) { + unsigned int j; + for (j = 0; j < SIZE; j++) { + if (buf[i*SIZE + j] != i) { + printf("Unexpected value after offset writev at %i\n", + i*SIZE + j); + status |= 1; + break; + } + } + } + if (!status) + printf("Checking memory: [Success]\n"); + + memset(buf, 0, sizeof(buf)); + status |= attempt_rw(rwfd, iov+1, NUM_IOV-1, SIZE, READV, + SIZE*(NUM_IOV-1)); + for (i = 1; i < NUM_IOV; i++) { + unsigned int j; + for (j = 0; j < SIZE; j++) { + if (buf[i*SIZE + j] != i) { + printf("Unexpected value after offset readv at %i\n", + i*SIZE + j); + status |= 1; + break; + } + } + } + if (!status) + printf("Checking memory: [Success]\n"); + + return status; +} + diff --git a/harness/cases/16.t b/harness/cases/16.t new file mode 100644 index 0000000..c3157cc --- /dev/null +++ b/harness/cases/16.t @@ -0,0 +1,94 @@ +/* 16.t +- eventfd tests. +*/ +#include +#include +#include /* For SYS_xxx definitions */ + +#ifndef SYS_eventfd +#if defined(__i386__) +#define SYS_eventfd 323 +#elif defined(__x86_64__) +#define SYS_eventfd 284 +#elif defined(__ia64__) +#define SYS_eventfd 1309 +#elif defined(__PPC__) +#define SYS_eventfd 307 +#elif defined(__s390__) +#define SYS_eventfd 318 +#elif defined(__alpha__) +#define SYS_eventfd 478 +#else +#error define SYS_eventfd for your arch! +#endif +#endif + +int test_main(void) +{ + /* 10 MB takes long enough that we would fail if eventfd + * returned immediately. */ +#define SIZE 10000000 + char *buf; + struct io_event io_event; + struct iocb iocb; + struct iocb *iocbs[] = { &iocb }; + int rwfd, efd; + int res; + io_context_t io_ctx; + uint64_t event; + struct timespec notime = { .tv_sec = 0, .tv_nsec = 0 }; + + buf = malloc(SIZE); assert(buf); + efd = syscall(SYS_eventfd, 0); + if (efd < 0) { + if (errno == ENOSYS) { + printf("No eventfd support. [SKIPPING]\n"); + exit(0); + } + err(1, "Failed to get eventfd"); + } + + rwfd = open("testdir/rwfile", O_RDWR); assert(rwfd != -1); + res = ftruncate(rwfd, 0); assert(res == 0); + memset(buf, 0x42, SIZE); + + /* Write test. */ + res = io_queue_init(1024, &io_ctx); assert(res == 0); + io_prep_pwrite(&iocb, rwfd, buf, SIZE, 0); + io_set_eventfd(&iocb, efd); + res = io_submit(io_ctx, 1, iocbs); assert(res == 1); + + alarm(30); + res = read(efd, &event, sizeof(event)); assert(res == sizeof(event)); + assert(event == 1); + + /* This should now be ready. */ + res = io_getevents(io_ctx, 0, 1, &io_event, ¬ime); + if (res != 1) + err(1, "io_getevents did not return 1 event after eventfd"); + assert(io_event.res == SIZE); + printf("eventfd write test [SUCCESS]\n"); + + /* Read test. */ + memset(buf, 0, SIZE); + io_prep_pread(&iocb, rwfd, buf, SIZE, 0); + io_set_eventfd(&iocb, efd); + res = io_submit(io_ctx, 1, iocbs); assert(res == 1); + + alarm(30); + res = read(efd, &event, sizeof(event)); assert(res == sizeof(event)); + assert(event == 1); + + /* This should now be ready. */ + res = io_getevents(io_ctx, 0, 1, &io_event, ¬ime); + if (res != 1) + err(1, "io_getevents did not return 1 event after eventfd"); + assert(io_event.res == SIZE); + + for (res = 0; res < SIZE; res++) + assert(buf[res] == 0x42); + printf("eventfd read test [SUCCESS]\n"); + + return 0; +} + diff --git a/harness/cases/5.t b/harness/cases/5.t index 7669fd7..2b4b4bb 100644 --- a/harness/cases/5.t +++ b/harness/cases/5.t @@ -3,6 +3,7 @@ */ #include "aio_setup.h" #include +#include int test_main(void) { @@ -40,7 +41,13 @@ int test_main(void) assert(buf != (char *)-1); status |= attempt_rw(rwfd, buf, SIZE, 0, READ, SIZE); - status |= attempt_rw(rwfd, buf, SIZE, 0, WRITE, -EFAULT); + + /* Whether PROT_WRITE is readable is arch-dependent. So compare + * against read result. */ + res = read(rwfd, buf, SIZE); + if (res < 0) + res = -errno; + status |= attempt_rw(rwfd, buf, SIZE, 0, WRITE, res); return status; } diff --git a/harness/cases/7.t b/harness/cases/7.t index d2d6cbc..f877d8a 100644 --- a/harness/cases/7.t +++ b/harness/cases/7.t @@ -9,12 +9,15 @@ */ #include +#include void SET_RLIMIT(long long limit) { struct rlimit rlim; int res; + /* Seems that we do send SIGXFSZ, but hard to fix... */ + signal(SIGXFSZ, SIG_IGN); rlim.rlim_cur = limit; assert(rlim.rlim_cur == limit); rlim.rlim_max = limit; assert(rlim.rlim_max == limit); diff --git a/harness/cases/8.t b/harness/cases/8.t index 8a3d83e..e59199f 100644 --- a/harness/cases/8.t +++ b/harness/cases/8.t @@ -2,44 +2,23 @@ - Ditto for the above three tests at the offset maximum (largest possible ext2/3 file size.) (8.t) */ -#include - -#define EXT2_OLD_SUPER_MAGIC 0xEF51 -#define EXT2_SUPER_MAGIC 0xEF53 +#include +#include long long get_fs_limit(int fd) { - struct statfs s; - int res; - long long lim = 0; - - res = fstatfs(fd, &s); assert(res == 0); + long long min = 0, max = 9223372036854775807LL; + char c = 0; - switch(s.f_type) { - case EXT2_OLD_SUPER_MAGIC: - case EXT2_SUPER_MAGIC: -#if 0 - { - long long tmp; - tmp = s.f_bsize / 4; - /* 12 direct + indirect block + dind + tind */ - lim = 12 + tmp + tmp * tmp + tmp * tmp * tmp; - lim *= s.f_bsize; - printf("limit(%ld) = %Ld\n", (long)s.f_bsize, lim); - } -#endif - switch(s.f_bsize) { - case 4096: lim = 2199023251456; break; - default: - printf("unknown ext2 blocksize %ld\n", (long)s.f_bsize); - exit(3); + while (max - min > 1) { + if (pwrite64(fd, &c, 1, (min + max) / 2) == -1) + max = (min + max) / 2; + else { + ftruncate(fd, 0); + min = (min + max) / 2; } - break; - default: - printf("unknown filesystem 0x%08lx\n", (long)s.f_type); - exit(3); } - return lim; + return max; } #define SET_RLIMIT(x) do ; while (0) diff --git a/harness/cases/aio_setup.h b/harness/cases/aio_setup.h index 37c9618..1914915 100644 --- a/harness/cases/aio_setup.h +++ b/harness/cases/aio_setup.h @@ -1,3 +1,4 @@ +#include io_context_t io_ctx; #define BAD_CTX ((io_context_t)-1) @@ -58,6 +59,9 @@ int sync_submit(struct iocb *iocb) #define WRITE 'w' #define READ_SILENT 'R' #define WRITE_SILENT 'W' +#define READV '<' +#define WRITEV '>' + int attempt_rw(int fd, void *buf, int count, long long pos, int rw, int expect) { struct iocb iocb; @@ -75,6 +79,12 @@ int attempt_rw(int fd, void *buf, int count, long long pos, int rw, int expect) case WRITE: io_prep_pwrite(&iocb, fd, buf, count, pos); break; + case WRITEV: + io_prep_pwritev(&iocb, fd, buf, count, pos); + break; + case READV: + io_prep_preadv(&iocb, fd, buf, count, pos); + break; } if (!silent) { diff --git a/harness/cases/common-7-8.h b/harness/cases/common-7-8.h index 3ec2bb4..fc54bbf 100644 --- a/harness/cases/common-7-8.h +++ b/harness/cases/common-7-8.h @@ -2,6 +2,7 @@ */ #include "aio_setup.h" +#include #include #define SIZE 512 @@ -13,7 +14,7 @@ int test_main(void) int status = 0, res; long long limit; - rwfd = open(FILENAME, O_RDWR); assert(rwfd != -1); + rwfd = open(FILENAME, O_RDWR|O_CREAT, 0600); assert(rwfd != -1); res = ftruncate(rwfd, 0); assert(res == 0); buf = malloc(SIZE); assert(buf != NULL); memset(buf, 0, SIZE); diff --git a/harness/main.c b/harness/main.c index 74b2764..e8f0143 100644 --- a/harness/main.c +++ b/harness/main.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include diff --git a/harness/runtests.sh b/harness/runtests.sh index d763d88..717c72a 100755 --- a/harness/runtests.sh +++ b/harness/runtests.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash passes=0 fails=0 diff --git a/libaio.spec b/libaio.spec index bdcc5b2..a7c17c5 100644 --- a/libaio.spec +++ b/libaio.spec @@ -1,5 +1,5 @@ Name: libaio -Version: 0.3.106 +Version: 0.3.107 Release: 1 Summary: Linux-native asynchronous I/O access library Copyright: LGPL @@ -59,6 +59,10 @@ make install prefix=$RPM_BUILD_ROOT/usr \ %attr(0644,root,root) %{_libdir}/libaio.a %changelog +* Wed Jan 9 2008 Jeff Moyer - 0.3.107-1 +- Fix the test harness (Rusty Russell) +- Add eventfd support (Rusty Russell) + * Tue Jan 3 2006 Jeff Moyer - 0.3.106-1 - Add a .proc directive for the ia64_aio_raw_syscall macro. This sounds a lot like the previous entry, but that one fixed the __ia64_raw_syscall macro, diff --git a/src/libaio.h b/src/libaio.h index 6574601..6cdde32 100644 --- a/src/libaio.h +++ b/src/libaio.h @@ -33,7 +33,6 @@ extern "C" { struct timespec; struct sockaddr; struct iovec; -struct iocb; typedef struct io_context *io_context_t; @@ -44,8 +43,10 @@ typedef enum io_iocb_cmd { IO_CMD_FSYNC = 2, IO_CMD_FDSYNC = 3, - IO_CMD_POLL = 5, + IO_CMD_POLL = 5, /* Never implemented in mainline, see io_prep_poll */ IO_CMD_NOOP = 6, + IO_CMD_PREADV = 7, + IO_CMD_PWRITEV = 8, } io_iocb_cmd_t; #if defined(__i386__) /* little endian, 32 bits */ @@ -89,7 +90,9 @@ struct io_iocb_common { PADDEDptr(void *buf, __pad1); PADDEDul(nbytes, __pad2); long long offset; - long long __pad3, __pad4; + long long __pad3; + unsigned flags; + unsigned resfd; }; /* result code is the amount read or -'ve errno */ struct io_iocb_vector { @@ -169,20 +172,44 @@ static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t c iocb->u.c.offset = offset; } -static inline void io_prep_poll(struct iocb *iocb, int fd, int events) +static inline void io_prep_preadv(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset) { memset(iocb, 0, sizeof(*iocb)); iocb->aio_fildes = fd; - iocb->aio_lio_opcode = IO_CMD_POLL; + iocb->aio_lio_opcode = IO_CMD_PREADV; iocb->aio_reqprio = 0; - iocb->u.poll.events = events; + iocb->u.c.buf = (void *)iov; + iocb->u.c.nbytes = iovcnt; + iocb->u.c.offset = offset; +} + +static inline void io_prep_pwritev(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset) +{ + memset(iocb, 0, sizeof(*iocb)); + iocb->aio_fildes = fd; + iocb->aio_lio_opcode = IO_CMD_PWRITEV; + iocb->aio_reqprio = 0; + iocb->u.c.buf = (void *)iov; + iocb->u.c.nbytes = iovcnt; + iocb->u.c.offset = offset; +} + +/* Jeff Moyer says this was implemented in Red Hat AS2.1 and RHEL3. + * AFAICT, it was never in mainline, and should not be used. --RR */ +static inline void io_prep_poll(struct iocb *iocb, int fd, int events) +{ + memset(iocb, 0, sizeof(*iocb)); + iocb->aio_fildes = fd; + iocb->aio_lio_opcode = IO_CMD_POLL; + iocb->aio_reqprio = 0; + iocb->u.poll.events = events; } static inline int io_poll(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd, int events) { - io_prep_poll(iocb, fd, events); - io_set_callback(iocb, cb); - return io_submit(ctx, 1, &iocb); + io_prep_poll(iocb, fd, events); + io_set_callback(iocb, cb); + return io_submit(ctx, 1, &iocb); } static inline void io_prep_fsync(struct iocb *iocb, int fd) @@ -215,6 +242,12 @@ static inline int io_fdsync(io_context_t ctx, struct iocb *iocb, io_callback_t c return io_submit(ctx, 1, &iocb); } +static inline void io_set_eventfd(struct iocb *iocb, int eventfd) +{ + iocb->u.c.flags |= (1 << 0) /* IOCB_FLAG_RESFD */; + iocb->u.c.resfd = eventfd; +} + #ifdef __cplusplus } #endif -- cgit v1.2.1