diff mbox

[2/4] fsstress: add AIO read/write and fsync test

Message ID 1497629466-22647-2-git-send-email-zlang@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Zorro Lang June 16, 2017, 4:11 p.m. UTC
We found some bugs by aio read/write test, but there's not related
operations in fsstress. So add AIO test into fsstress to increase
AIO stress test.

Due to most kernels don't support aio fsync, so set its test
frequency to zero as default.

Signed-off-by: Zorro Lang <zlang@redhat.com>
---
 ltp/fsstress.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 214 insertions(+)

Comments

Eryu Guan July 11, 2017, 4:10 a.m. UTC | #1
On Sat, Jun 17, 2017 at 12:11:04AM +0800, Zorro Lang wrote:
> We found some bugs by aio read/write test, but there's not related
> operations in fsstress. So add AIO test into fsstress to increase
> AIO stress test.
> 
> Due to most kernels don't support aio fsync, so set its test
> frequency to zero as default.
> 
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> ---
>  ltp/fsstress.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 214 insertions(+)
> 
> diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> index 67cdb2f..4ff90d5 100644
> --- a/ltp/fsstress.c
> +++ b/ltp/fsstress.c
> @@ -36,6 +36,10 @@
>  #ifdef HAVE_SYS_PRCTL_H
>  #include <sys/prctl.h>
>  #endif
> +#ifdef AIO
> +#include <libaio.h>
> +io_context_t	io_ctx;
> +#endif
>  
>  #ifndef FS_IOC_GETFLAGS
>  #define FS_IOC_GETFLAGS                 _IOR('f', 1, long)
> @@ -55,9 +59,12 @@
>  #define FILELEN_MAX		(32*4096)
>  
>  typedef enum {
> +	OP_AFSYNC,
>  	OP_ALLOCSP,
> +	OP_AREAD,
>  	OP_ATTR_REMOVE,
>  	OP_ATTR_SET,
> +	OP_AWRITE,
>  	OP_BULKSTAT,
>  	OP_BULKSTAT1,
>  	OP_CHOWN,
> @@ -158,9 +165,12 @@ struct print_string {
>  #define	MAXFSIZE	((1ULL << 63) - 1ULL)
>  #define	MAXFSIZE32	((1ULL << 40) - 1ULL)
>  
> +void	afsync_f(int, long);
>  void	allocsp_f(int, long);
> +void	aread_f(int, long);
>  void	attr_remove_f(int, long);
>  void	attr_set_f(int, long);
> +void	awrite_f(int, long);
>  void	bulkstat_f(int, long);
>  void	bulkstat1_f(int, long);
>  void	chown_f(int, long);
> @@ -202,9 +212,12 @@ void	writev_f(int, long);
>  
>  opdesc_t	ops[] = {
>       /* { OP_ENUM, "name", function, freq, iswrite }, */
> +	{ OP_AFSYNC, "afsync", afsync_f, 0, 1 },
>  	{ OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
> +	{ OP_AREAD, "aread", aread_f, 1, 0 },
>  	{ OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
>  	{ OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
> +	{ OP_AWRITE, "awrite", awrite_f, 1, 1 },
>  	{ OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
>  	{ OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
>  	{ OP_CHOWN, "chown", chown_f, 3, 1 },
> @@ -587,8 +600,20 @@ int main(int argc, char **argv)
>  				}
>  			}
>  			procid = i;
> +#ifdef AIO
> +			if (io_setup(128, &io_ctx) != 0) {
> +				perror("io_setup failed");

It seems that libaio wrapper doesn't set errno on failure, it just
returns the negative errno value, so perror doesn't work as expected
here.

> +				exit(1);
> +			}
> +#endif
>  			for (i = 0; !loops || (i < loops); i++)
>  				doproc();
> +#ifdef AIO
> +			if(io_destroy(io_ctx) != 0) {
> +				perror("io_destroy failed");

Same here.

> +				return 1;
> +			}
> +#endif
>  			return 0;
>  		}
>  	}
> @@ -1708,6 +1733,62 @@ void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
>  }
>  
>  void
> +afsync_f(int opno, long r)
> +{
> +#ifdef AIO
> +	int		e;
> +	pathname_t	f;
> +	int		fd;
> +	int		v;
> +	struct iocb	iocb;
> +	struct iocb	*iocbs[] = { &iocb };
> +	struct io_event	event;
> +
> +	init_pathname(&f);
> +	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
> +		if (v)
> +			printf("%d/%d: afsync - no filename\n", procid, opno);
> +		free_pathname(&f);
> +		return;
> +	}
> +	fd = open_path(&f, O_WRONLY | O_DIRECT);
> +	e = fd < 0 ? errno : 0;
> +	check_cwd();
> +	if (fd < 0) {
> +		if (v)
> +			printf("%d/%d: afsync - open %s failed %d\n",
> +			       procid, opno, f.path, e);
> +		free_pathname(&f);
> +		return;
> +	}
> +
> +	io_prep_fsync(&iocb, fd);
> +	if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
> +		if (v)
> +			printf("%d/%d: afsync - io_submit %s %d\n",
> +			       procid, opno, f.path, e);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +	if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
> +		if (v)
> +			printf("%d/%d: afsync - io_getevents failed %d\n",
> +			       procid, opno, e);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +
> +	e = event.res2;
> +	if (v)
> +		printf("%d/%d: afsync %s %d\n", procid, opno, f.path, e);
> +	free_pathname(&f);
> +	close(fd);
> +#endif
> +}
> +
> +void
>  allocsp_f(int opno, long r)
>  {
>  	int		e;
> @@ -1761,6 +1842,131 @@ allocsp_f(int opno, long r)
>  	close(fd);
>  }
>  
> +#ifdef AIO
> +void
> +do_aio_rw(int opno, long r, int flags)
> +{
> +	__int64_t	align;
> +	char		*buf;
> +	struct dioattr	diob;
> +	int		e;
> +	pathname_t	f;
> +	int		fd;
> +	size_t		len;
> +	__int64_t	lr;
> +	off64_t		off;
> +	struct stat64	stb;
> +	int		v;
> +	char		st[1024];
> +	char		*dio_env;
> +	struct iocb	iocb;
> +	struct io_event	event;
> +	struct iocb	*iocbs[] = { &iocb };
> +	int		iswrite = (flags & (O_WRONLY | O_RDWR)) ? 1 : 0;
> +
> +	init_pathname(&f);
> +	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
> +		if (v)
> +			printf("%d/%d: do_aio_rw - no filename\n", procid, opno);
> +		free_pathname(&f);
> +		return;
> +	}
> +	fd = open_path(&f, flags|O_DIRECT);
> +	e = fd < 0 ? errno : 0;
> +	check_cwd();
> +	if (fd < 0) {
> +		if (v)
> +			printf("%d/%d: do_aio_rw - open %s failed %d\n",
> +			       procid, opno, f.path, e);
> +		free_pathname(&f);
> +		return;
> +	}
> +	if (fstat64(fd, &stb) < 0) {
> +		if (v)
> +			printf("%d/%d: do_aio_rw - fstat64 %s failed %d\n",
> +			       procid, opno, f.path, errno);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +	inode_info(st, sizeof(st), &stb, v);
> +	if (!iswrite && stb.st_size == 0) {
> +		if (v)
> +			printf("%d/%d: do_aio_rw - %s%s zero size\n", procid, opno,
> +			       f.path, st);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +	if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
> +		if (v)
> +			printf(
> +			"%d/%d: do_aio_rw - xfsctl(XFS_IOC_DIOINFO) %s%s failed %d\n",
> +				procid, opno, f.path, st, errno);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}

This means that only XFS has O_DIRECT coverage in fsstress, and
dread_f/dwrite_f have the same issue.. I think we can fall back to use
stb.st_blksize as the dio alignment size (maybe factor out a common
helper to do this). But that can be done in a separate patch.

Thanks,
Eryu

> +	dio_env = getenv("XFS_DIO_MIN");
> +	if (dio_env)
> +		diob.d_mem = diob.d_miniosz = atoi(dio_env);
> +	align = (__int64_t)diob.d_miniosz;
> +	lr = ((__int64_t)random() << 32) + random();
> +	len = (random() % FILELEN_MAX) + 1;
> +	len -= (len % align);
> +	if (len <= 0)
> +		len = align;
> +	else if (len > diob.d_maxiosz)
> +		len = diob.d_maxiosz;
> +	buf = memalign(diob.d_mem, len);
> +
> +	if (iswrite) {
> +		off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
> +		off -= (off % align);
> +		off %= maxfsize;
> +		memset(buf, nameseq & 0xff, len);
> +		io_prep_pwrite(&iocb, fd, buf, len, off);
> +	} else {
> +		off = (off64_t)(lr % stb.st_size);
> +		off -= (off % align);
> +		io_prep_pread(&iocb, fd, buf, len, off);
> +	}
> +	if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
> +		if (v)
> +			printf("%d/%d: %s - io_submit failed %d\n",
> +			       procid, opno, iswrite ? "awrite" : "aread", e);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +	if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
> +		if (v)
> +			printf("%d/%d: %s - io_getevents failed %d\n",
> +			       procid, opno, iswrite ? "awrite" : "aread", e);
> +		free_pathname(&f);
> +		close(fd);
> +		return;
> +	}
> +
> +	e = event.res != len ? event.res2 : 0;
> +	free(buf);
> +	if (v)
> +		printf("%d/%d: %s %s%s [%lld,%d] %d\n",
> +		       procid, opno, iswrite ? "awrite" : "aread",
> +		       f.path, st, (long long)off, (int)len, e);
> +	free_pathname(&f);
> +	close(fd);
> +}
> +#endif
> +
> +void
> +aread_f(int opno, long r)
> +{
> +#ifdef AIO
> +	do_aio_rw(opno, r, O_RDONLY);
> +#endif
> +}
> +
>  void
>  attr_remove_f(int opno, long r)
>  {
> @@ -1865,6 +2071,14 @@ attr_set_f(int opno, long r)
>  }
>  
>  void
> +awrite_f(int opno, long r)
> +{
> +#ifdef AIO
> +	do_aio_rw(opno, r, O_WRONLY);
> +#endif
> +}
> +
> +void
>  bulkstat_f(int opno, long r)
>  {
>  	int		count;
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe fstests" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe fstests" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index 67cdb2f..4ff90d5 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -36,6 +36,10 @@ 
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
 #endif
+#ifdef AIO
+#include <libaio.h>
+io_context_t	io_ctx;
+#endif
 
 #ifndef FS_IOC_GETFLAGS
 #define FS_IOC_GETFLAGS                 _IOR('f', 1, long)
@@ -55,9 +59,12 @@ 
 #define FILELEN_MAX		(32*4096)
 
 typedef enum {
+	OP_AFSYNC,
 	OP_ALLOCSP,
+	OP_AREAD,
 	OP_ATTR_REMOVE,
 	OP_ATTR_SET,
+	OP_AWRITE,
 	OP_BULKSTAT,
 	OP_BULKSTAT1,
 	OP_CHOWN,
@@ -158,9 +165,12 @@  struct print_string {
 #define	MAXFSIZE	((1ULL << 63) - 1ULL)
 #define	MAXFSIZE32	((1ULL << 40) - 1ULL)
 
+void	afsync_f(int, long);
 void	allocsp_f(int, long);
+void	aread_f(int, long);
 void	attr_remove_f(int, long);
 void	attr_set_f(int, long);
+void	awrite_f(int, long);
 void	bulkstat_f(int, long);
 void	bulkstat1_f(int, long);
 void	chown_f(int, long);
@@ -202,9 +212,12 @@  void	writev_f(int, long);
 
 opdesc_t	ops[] = {
      /* { OP_ENUM, "name", function, freq, iswrite }, */
+	{ OP_AFSYNC, "afsync", afsync_f, 0, 1 },
 	{ OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
+	{ OP_AREAD, "aread", aread_f, 1, 0 },
 	{ OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
 	{ OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
+	{ OP_AWRITE, "awrite", awrite_f, 1, 1 },
 	{ OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
 	{ OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
 	{ OP_CHOWN, "chown", chown_f, 3, 1 },
@@ -587,8 +600,20 @@  int main(int argc, char **argv)
 				}
 			}
 			procid = i;
+#ifdef AIO
+			if (io_setup(128, &io_ctx) != 0) {
+				perror("io_setup failed");
+				exit(1);
+			}
+#endif
 			for (i = 0; !loops || (i < loops); i++)
 				doproc();
+#ifdef AIO
+			if(io_destroy(io_ctx) != 0) {
+				perror("io_destroy failed");
+				return 1;
+			}
+#endif
 			return 0;
 		}
 	}
@@ -1708,6 +1733,62 @@  void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
 }
 
 void
+afsync_f(int opno, long r)
+{
+#ifdef AIO
+	int		e;
+	pathname_t	f;
+	int		fd;
+	int		v;
+	struct iocb	iocb;
+	struct iocb	*iocbs[] = { &iocb };
+	struct io_event	event;
+
+	init_pathname(&f);
+	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+		if (v)
+			printf("%d/%d: afsync - no filename\n", procid, opno);
+		free_pathname(&f);
+		return;
+	}
+	fd = open_path(&f, O_WRONLY | O_DIRECT);
+	e = fd < 0 ? errno : 0;
+	check_cwd();
+	if (fd < 0) {
+		if (v)
+			printf("%d/%d: afsync - open %s failed %d\n",
+			       procid, opno, f.path, e);
+		free_pathname(&f);
+		return;
+	}
+
+	io_prep_fsync(&iocb, fd);
+	if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
+		if (v)
+			printf("%d/%d: afsync - io_submit %s %d\n",
+			       procid, opno, f.path, e);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+	if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
+		if (v)
+			printf("%d/%d: afsync - io_getevents failed %d\n",
+			       procid, opno, e);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+
+	e = event.res2;
+	if (v)
+		printf("%d/%d: afsync %s %d\n", procid, opno, f.path, e);
+	free_pathname(&f);
+	close(fd);
+#endif
+}
+
+void
 allocsp_f(int opno, long r)
 {
 	int		e;
@@ -1761,6 +1842,131 @@  allocsp_f(int opno, long r)
 	close(fd);
 }
 
+#ifdef AIO
+void
+do_aio_rw(int opno, long r, int flags)
+{
+	__int64_t	align;
+	char		*buf;
+	struct dioattr	diob;
+	int		e;
+	pathname_t	f;
+	int		fd;
+	size_t		len;
+	__int64_t	lr;
+	off64_t		off;
+	struct stat64	stb;
+	int		v;
+	char		st[1024];
+	char		*dio_env;
+	struct iocb	iocb;
+	struct io_event	event;
+	struct iocb	*iocbs[] = { &iocb };
+	int		iswrite = (flags & (O_WRONLY | O_RDWR)) ? 1 : 0;
+
+	init_pathname(&f);
+	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+		if (v)
+			printf("%d/%d: do_aio_rw - no filename\n", procid, opno);
+		free_pathname(&f);
+		return;
+	}
+	fd = open_path(&f, flags|O_DIRECT);
+	e = fd < 0 ? errno : 0;
+	check_cwd();
+	if (fd < 0) {
+		if (v)
+			printf("%d/%d: do_aio_rw - open %s failed %d\n",
+			       procid, opno, f.path, e);
+		free_pathname(&f);
+		return;
+	}
+	if (fstat64(fd, &stb) < 0) {
+		if (v)
+			printf("%d/%d: do_aio_rw - fstat64 %s failed %d\n",
+			       procid, opno, f.path, errno);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+	inode_info(st, sizeof(st), &stb, v);
+	if (!iswrite && stb.st_size == 0) {
+		if (v)
+			printf("%d/%d: do_aio_rw - %s%s zero size\n", procid, opno,
+			       f.path, st);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+	if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
+		if (v)
+			printf(
+			"%d/%d: do_aio_rw - xfsctl(XFS_IOC_DIOINFO) %s%s failed %d\n",
+				procid, opno, f.path, st, errno);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+	dio_env = getenv("XFS_DIO_MIN");
+	if (dio_env)
+		diob.d_mem = diob.d_miniosz = atoi(dio_env);
+	align = (__int64_t)diob.d_miniosz;
+	lr = ((__int64_t)random() << 32) + random();
+	len = (random() % FILELEN_MAX) + 1;
+	len -= (len % align);
+	if (len <= 0)
+		len = align;
+	else if (len > diob.d_maxiosz)
+		len = diob.d_maxiosz;
+	buf = memalign(diob.d_mem, len);
+
+	if (iswrite) {
+		off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+		off -= (off % align);
+		off %= maxfsize;
+		memset(buf, nameseq & 0xff, len);
+		io_prep_pwrite(&iocb, fd, buf, len, off);
+	} else {
+		off = (off64_t)(lr % stb.st_size);
+		off -= (off % align);
+		io_prep_pread(&iocb, fd, buf, len, off);
+	}
+	if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
+		if (v)
+			printf("%d/%d: %s - io_submit failed %d\n",
+			       procid, opno, iswrite ? "awrite" : "aread", e);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+	if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
+		if (v)
+			printf("%d/%d: %s - io_getevents failed %d\n",
+			       procid, opno, iswrite ? "awrite" : "aread", e);
+		free_pathname(&f);
+		close(fd);
+		return;
+	}
+
+	e = event.res != len ? event.res2 : 0;
+	free(buf);
+	if (v)
+		printf("%d/%d: %s %s%s [%lld,%d] %d\n",
+		       procid, opno, iswrite ? "awrite" : "aread",
+		       f.path, st, (long long)off, (int)len, e);
+	free_pathname(&f);
+	close(fd);
+}
+#endif
+
+void
+aread_f(int opno, long r)
+{
+#ifdef AIO
+	do_aio_rw(opno, r, O_RDONLY);
+#endif
+}
+
 void
 attr_remove_f(int opno, long r)
 {
@@ -1865,6 +2071,14 @@  attr_set_f(int opno, long r)
 }
 
 void
+awrite_f(int opno, long r)
+{
+#ifdef AIO
+	do_aio_rw(opno, r, O_WRONLY);
+#endif
+}
+
+void
 bulkstat_f(int opno, long r)
 {
 	int		count;