All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zorro Lang <zlang@redhat.com>
To: Brian Foster <bfoster@redhat.com>,
	fstests@vger.kernel.org, axboe@kernel.dk,
	io-uring@vger.kernel.org
Subject: Re: [PATCH v3 4/4] fsx: add IO_URING test
Date: Mon, 7 Sep 2020 00:27:27 +0800	[thread overview]
Message-ID: <20200906162727.GC2937@dhcp-12-102.nay.redhat.com> (raw)
In-Reply-To: <20200906155516.GB2937@dhcp-12-102.nay.redhat.com>

On Sun, Sep 06, 2020 at 11:55:16PM +0800, Zorro Lang wrote:
> On Thu, Sep 03, 2020 at 08:44:13AM -0400, Brian Foster wrote:
> > On Sun, Aug 23, 2020 at 02:30:32PM +0800, Zorro Lang wrote:
> > > New IO_URING test for fsx, use -U option to enable IO_URING test.
> > > 
> > > Signed-off-by: Zorro Lang <zlang@redhat.com>
> > > ---
> > 
> > Note that this one doesn't compile if one of the ifdefs doesn't evaluate
> > true:
> > 
> > fsx.c:2551:6: error: #elif with no expression
> >  2551 | #elif
> >       |      ^
> >     [CC]    fsx
> > fsx.c: In function 'fsx_rw':
> > fsx.c:2551:6: error: #elif with no expression
> >  2551 | #elif
> >       |      ^
> > gmake[2]: *** [Makefile:52: fsx] Error 1
> > gmake[1]: *** [include/buildrules:30: ltp] Error 2
> > make: *** [Makefile:53: default] Error 2
> > 
> > I suspect you want to replace both of those with #else. Otherwise mostly
> > some aesthetic comments...
> 
> Sorry, that's truely a mistake, I'll fix it :)
> 
> > 
> > >  ltp/fsx.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++-----
> > >  1 file changed, 144 insertions(+), 14 deletions(-)
> > > 
> > > diff --git a/ltp/fsx.c b/ltp/fsx.c
> > > index 7c76655a..05663528 100644
> > > --- a/ltp/fsx.c
> > > +++ b/ltp/fsx.c
> > ...
> > > @@ -176,21 +179,17 @@ int	integrity = 0;			/* -i flag */
> > >  int	fsxgoodfd = 0;
> > >  int	o_direct;			/* -Z */
> > >  int	aio = 0;
> > > +int	uring = 0;
> > >  int	mark_nr = 0;
> > >  
> > >  int page_size;
> > >  int page_mask;
> > >  int mmap_mask;
> > > -#ifdef AIO
> > > -int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset);
> > > +int fsx_rw(int rw, int fd, char *buf, unsigned len, unsigned offset);
> > >  #define READ 0
> > >  #define WRITE 1
> > > -#define fsxread(a,b,c,d)	aio_rw(READ, a,b,c,d)
> > > -#define fsxwrite(a,b,c,d)	aio_rw(WRITE, a,b,c,d)
> > > -#else
> > > -#define fsxread(a,b,c,d)	read(a,b,c)
> > > -#define fsxwrite(a,b,c,d)	write(a,b,c)
> > > -#endif
> > > +#define fsxread(a,b,c,d)	fsx_rw(READ, a,b,c,d)
> > > +#define fsxwrite(a,b,c,d)	fsx_rw(WRITE, a,b,c,d)
> > >  
> > 
> > Could we do the refactoring that introduces fsx_rw and shuffles around
> > some of the existing AIO in an initial refactoring patch?
> 
> May I save this pre-patch, if you don't insist on that :-P
> 
> > 
> > >  const char *replayops = NULL;
> > >  const char *recordops = NULL;
> > ...
> > > @@ -2425,13 +2427,131 @@ out_error:
> > >  	errno = -ret;
> > >  	return -1;
> > >  }
> > > +#endif
> > > +
> > > +#ifdef URING
> > 
> > A whitespace line here...
> > 
> > > +struct io_uring ring;
> > > +#define URING_ENTRIES	1024
> > 
> > ... and here would help readability.
> > 
> > > +int
> > > +uring_setup()
> > > +{
> > > +	int ret;
> > > +
> > > +	ret = io_uring_queue_init(URING_ENTRIES, &ring, 0);
> > > +	if (ret != 0) {
> > > +		fprintf(stderr, "uring_setup: io_uring_queue_init failed: %s\n",
> > > +                        strerror(ret));
> > > +                return -1;
> > > +        }
> > > +        return 0;
> > 
> > Looks like some whitespace damage here.
> > 
> > Also, the fsstress patch has a io_uring_queue_exit() call but I don't
> > see one in this patch. Is that not needed?
> 
> There's not aio_destroy() either. I think due to fsstress is a multi-process
> test, so it'd like to destroy io_uring or aio at each process end. But fsx is
> a pure single process test, the io_uring or aio will destroyed when fsx exit.
> I can add io_uring_queue_exit() and aio_destroy() if you think it would be
> better.
> 
> > 
> > > +}
> > >  
> > > -int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
> > > +int
> > > +__uring_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
> > 
> > Do we still need the __ in the function names here and for __aio_rw()?
> 
> I don't think it's needed. I use the "__" just due to the old __aio_rw() has. I
> can remove both "__" of __aio_rw and __uring_rw.
> 
> > 
> > >  {
> > > +	struct io_uring_sqe	*sqe;
> > > +	struct io_uring_cqe	*cqe;
> > > +	struct iovec		iovec;
> > >  	int ret;
> > > +	int res, res2 = 0;
> > > +	char *p = buf;
> > > +	unsigned l = len;
> > > +	unsigned o = offset;
> > > +
> > > +
> > > +	/*
> > > +	 * Due to io_uring tries non-blocking IOs (especially read), that
> > > +	 * always cause 'normal' short reading. To avoid this short read
> > > +	 * fail, try to loop read/write (escpecilly read) data.
> > > +	 */
> > > + uring_loop:
> > > +	sqe = io_uring_get_sqe(&ring);
> > > +	if (!sqe) {
> > > +		fprintf(stderr, "uring_rw: io_uring_get_sqe failed: %s\n",
> > > +		        strerror(errno));
> > > +		return -1;
> > > +        }
> > > +
> > > +	iovec.iov_base = p;
> > > +	iovec.iov_len = l;
> > > +	if (rw == READ) {
> > > +		io_uring_prep_readv(sqe, fd, &iovec, 1, o);
> > > +	} else {
> > > +		io_uring_prep_writev(sqe, fd, &iovec, 1, o);
> > > +	}
> > > +
> > > +	ret = io_uring_submit_and_wait(&ring, 1);
> > > +	if (ret != 1) {
> > > +		fprintf(stderr, "errcode=%d\n", -ret);
> > > +		fprintf(stderr, "uring %s: io_uring_submit failed: %s\n",
> > > +		        rw == READ ? "read":"write", strerror(-ret));
> > > +		goto uring_error;
> > > +	}
> > > +
> > > +	ret = io_uring_wait_cqe(&ring, &cqe);
> > > +	if (ret < 0) {
> > > +		if (ret == 0)
> > 
> > That doesn't look right since we only get here if ret < 0.
> 
> Thanks, it should be (ret <= 0)

Sorry, I just checked io_uring_wait_cqe() code, it returns 0 on success.
So my "if (ret == 0)" checking is totally wrong, I'll remove it :)

/*
 * Return an IO completion, waiting for it if necessary. Returns 0 with
 * cqe_ptr filled in on success, -errno on failure.
 */
static inline int io_uring_wait_cqe(struct io_uring *ring,
                                    struct io_uring_cqe **cqe_ptr)

> 
> > 
> > > +			fprintf(stderr, "uring %s: no events available\n",
> > > +			        rw == READ ? "read":"write");
> > > +		else {
> > > +			fprintf(stderr, "errcode=%d\n", -ret);
> > > +			fprintf(stderr, "uring %s: io_uring_wait_cqe failed: %s\n",
> > > +			        rw == READ ? "read":"write", strerror(-ret));
> > > +		}
> > > +		goto uring_error;
> > > +	}
> > > +	res = cqe->res;
> > > +	io_uring_cqe_seen(&ring, cqe);
> > > +
> > > +	res2 += res;
> > > +	if (len != res2) {
> > > +		if (res > 0) {
> > > +			o += res;
> > > +			l -= res;
> > > +			p += res;
> > > +			if (l > 0)
> > > +				goto uring_loop;
> > > +		} else if (res < 0) {
> > > +			ret = res;
> > > +			fprintf(stderr, "errcode=%d\n", -ret);
> > > +			fprintf(stderr, "uring %s: io_uring failed: %s\n",
> > > +			        rw == READ ? "read":"write", strerror(-ret));
> > > +			goto uring_error;
> > 
> > Can we elevate the error checks into the top level rather than nesting
> > logic like this? It's a little confusing to read and it looks
> > particularly odd since we've already done res2 += res before we get
> > here.
> > 
> > Also I'm wondering if this whole function would read a little better as
> > a do {} while() loop rather than using a label and goto.
> 
> Sure, I'll try to change that.
> 
> > 
> > > +		} else {
> > > +			fprintf(stderr, "uring %s bad io length: %d instead of %u\n",
> > > +			        rw == READ ? "read":"write", res2, len);
> > > +		}
> > > +	}
> > > +	return res2;
> > > +
> > > + uring_error:
> > > +	/*
> > > +	 * The caller expects error return in traditional libc
> > > +	 * convention, i.e. -1 and the errno set to error.
> > > +	 */
> > > +	errno = -ret;
> > > +	return -1;
> > > +}
> > > +#endif
> > > +
> > > +int fsx_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
> > > +{
> > > +	int ret = -1;
> > >  
> > >  	if (aio) {
> > > +#ifdef AIO
> > >  		ret = __aio_rw(rw, fd, buf, len, offset);
> > > +#elif
> > > +		fprintf(stderr, "io_rw: need AIO support!\n");
> > > +		exit(111);
> > > +#endif
> > > +	} else if (uring) {
> > > +#ifdef URING
> > > +		ret = __uring_rw(rw, fd, buf, len, offset);
> > > +#elif
> > > +		fprintf(stderr, "io_rw: need IO_URING support!\n");
> > > +		exit(111);
> > > +#endif
> > 
> > I think the ifdefs would be cleaner if used to define stubbed out
> > variants of the associated functions. E.g.:
> > 
> > #ifdef URING
> > int
> > __uring_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
> > {
> > 	<do uring I/O>
> > }
> > #else
> > int
> > __uring_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
> > {
> > 	fprintf(stderr, "io_rw: need IO_URING support!\n");
> > 	exit(111);
> > }
> > #endif
> 
> Sure, will do that.
> 
> Thanks for your review, Brian!
> Zorro
> 
> > 
> > Brian
> > 
> > >  	} else {
> > >  		if (rw == READ)
> > >  			ret = read(fd, buf, len);
> > > @@ -2441,8 +2561,6 @@ int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
> > >  	return ret;
> > >  }
> > >  
> > > -#endif
> > > -
> > >  #define test_fallocate(mode) __test_fallocate(mode, #mode)
> > >  
> > >  int
> > > @@ -2496,7 +2614,7 @@ main(int argc, char **argv)
> > >  	setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
> > >  
> > >  	while ((ch = getopt_long(argc, argv,
> > > -				 "b:c:dfg:i:j:kl:m:no:p:qr:s:t:w:xyABD:EFJKHzCILN:OP:RS:WXZ",
> > > +				 "b:c:dfg:i:j:kl:m:no:p:qr:s:t:w:xyABD:EFJKHzCILN:OP:RS:UWXZ",
> > >  				 longopts, NULL)) != EOF)
> > >  		switch (ch) {
> > >  		case 'b':
> > > @@ -2604,6 +2722,9 @@ main(int argc, char **argv)
> > >  		case 'A':
> > >  		        aio = 1;
> > >  			break;
> > > +		case 'U':
> > > +		        uring = 1;
> > > +			break;
> > >  		case 'D':
> > >  			debugstart = getnum(optarg, &endp);
> > >  			if (debugstart < 1)
> > > @@ -2694,6 +2815,11 @@ main(int argc, char **argv)
> > >  	if (argc != 1)
> > >  		usage();
> > >  
> > > +	if (aio && uring) {
> > > +		fprintf(stderr, "-A and -U shouldn't be used together\n");
> > > +		usage();
> > > +	}
> > > +
> > >  	if (integrity && !dirpath) {
> > >  		fprintf(stderr, "option -i <logdev> requires -P <dirpath>\n");
> > >  		usage();
> > > @@ -2784,6 +2910,10 @@ main(int argc, char **argv)
> > >  	if (aio) 
> > >  		aio_setup();
> > >  #endif
> > > +#ifdef URING
> > > +	if (uring)
> > > +		uring_setup();
> > > +#endif
> > >  
> > >  	if (!(o_flags & O_TRUNC)) {
> > >  		off_t ret;
> > > -- 
> > > 2.20.1
> > > 


  reply	other threads:[~2020-09-06 16:13 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-23  6:30 [PATCH v3 0/4] fsstress,fsx: add io_uring test and do some fix Zorro Lang
2020-08-23  6:30 ` [PATCH v3 1/4] fsstress: add IO_URING read and write operations Zorro Lang
2020-09-03 12:42   ` Brian Foster
2020-09-03 14:07     ` Jens Axboe
2020-08-23  6:30 ` [PATCH v3 2/4] fsstress: reduce the number of events when io_setup Zorro Lang
2020-09-03 12:42   ` Brian Foster
2020-08-23  6:30 ` [PATCH v3 3/4] fsstress: fix memory leak in do_aio_rw Zorro Lang
2020-09-03 12:43   ` Brian Foster
2020-08-23  6:30 ` [PATCH v3 4/4] fsx: add IO_URING test Zorro Lang
2020-09-03 12:44   ` Brian Foster
2020-09-06 15:55     ` Zorro Lang
2020-09-06 16:27       ` Zorro Lang [this message]
2020-09-01  5:16 ` [PATCH v3 0/4] fsstress,fsx: add io_uring test and do some fix Zorro Lang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200906162727.GC2937@dhcp-12-102.nay.redhat.com \
    --to=zlang@redhat.com \
    --cc=axboe@kernel.dk \
    --cc=bfoster@redhat.com \
    --cc=fstests@vger.kernel.org \
    --cc=io-uring@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.