splice.c revision 36167d82e5f49dee91c6d2cd426068edee90e36f
12866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe/*
22866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe * splice io engine
32866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe *
42866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe */
52866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe#include <stdio.h>
62866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe#include <stdlib.h>
72866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe#include <unistd.h>
82866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe#include <errno.h>
92866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe#include <assert.h>
102866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe#include <sys/poll.h>
115f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe
125f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe#include "../fio.h"
135f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe#include "../os.h"
142866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1534cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe#ifdef FIO_HAVE_SPLICE
1634cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe
172866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboestruct spliceio_data {
182866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	int pipe[2];
192866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe};
202866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
212866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe/*
222866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe * For splice reading, we unfortunately cannot (yet) vmsplice the other way.
232866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe * So just splice the data from the file into the pipe, and use regular
242866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe * read to fill the buffer. Doesn't make a lot of sense, but...
252866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe */
262866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboestatic int fio_splice_read(struct thread_data *td, struct io_u *io_u)
272866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe{
282866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	struct spliceio_data *sd = td->io_ops->data;
2953cdc6864f7471b28cc9b40a5314ab43e5b1cb5eJens Axboe	struct fio_file *f = io_u->file;
302866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	int ret, ret2, buflen;
312866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	off_t offset;
322866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	void *p;
332866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
342866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	offset = io_u->offset;
35cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe	buflen = io_u->xfer_buflen;
36cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe	p = io_u->xfer_buf;
372866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	while (buflen) {
382866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		int this_len = buflen;
392866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
402866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		if (this_len > SPLICE_DEF_SIZE)
412866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			this_len = SPLICE_DEF_SIZE;
422866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
4353cdc6864f7471b28cc9b40a5314ab43e5b1cb5eJens Axboe		ret = splice(f->fd, &offset, sd->pipe[1], NULL, this_len, SPLICE_F_MORE);
442866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		if (ret < 0) {
452866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			if (errno == ENODATA || errno == EAGAIN)
462866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe				continue;
472866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
482866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			return errno;
492866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		}
502866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
512866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		buflen -= ret;
522866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
532866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		while (ret) {
542866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			ret2 = read(sd->pipe[0], p, ret);
552866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			if (ret2 < 0)
562866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe				return errno;
572866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
582866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			ret -= ret2;
592866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			p += ret2;
602866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		}
612866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	}
622866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
63cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe	return io_u->xfer_buflen;
642866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe}
652866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
662866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe/*
672866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe * For splice writing, we can vmsplice our data buffer directly into a
682866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe * pipe and then splice that to a file.
692866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe */
702866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboestatic int fio_splice_write(struct thread_data *td, struct io_u *io_u)
712866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe{
722866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	struct spliceio_data *sd = td->io_ops->data;
732866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	struct iovec iov[1] = {
742866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		{
75cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe			.iov_base = io_u->xfer_buf,
76cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe			.iov_len = io_u->xfer_buflen,
772866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		}
782866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	};
792866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	struct pollfd pfd = { .fd = sd->pipe[1], .events = POLLOUT, };
8053cdc6864f7471b28cc9b40a5314ab43e5b1cb5eJens Axboe	struct fio_file *f = io_u->file;
812866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	off_t off = io_u->offset;
822866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	int ret, ret2;
832866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
842866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	while (iov[0].iov_len) {
852866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		if (poll(&pfd, 1, -1) < 0)
862866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			return errno;
872866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
882866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		ret = vmsplice(sd->pipe[1], iov, 1, SPLICE_F_NONBLOCK);
892866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		if (ret < 0)
902866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			return errno;
912866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
922866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		iov[0].iov_len -= ret;
932866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		iov[0].iov_base += ret;
942866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
952866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		while (ret) {
9653cdc6864f7471b28cc9b40a5314ab43e5b1cb5eJens Axboe			ret2 = splice(sd->pipe[0], NULL, f->fd, &off, ret, 0);
972866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			if (ret2 < 0)
982866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe				return errno;
992866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1002866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			ret -= ret2;
1012866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		}
1022866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	}
1032866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
104cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe	return io_u->xfer_buflen;
1052866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe}
1062866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1072866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboestatic int fio_spliceio_queue(struct thread_data *td, struct io_u *io_u)
1082866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe{
109cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe	int ret;
1102866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1112866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	if (io_u->ddir == DDIR_READ)
1122866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		ret = fio_splice_read(td, io_u);
11387dc1ab1b4df7b977f60e3d43533a896e2ee665bJens Axboe	else if (io_u->ddir == DDIR_WRITE)
1142866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		ret = fio_splice_write(td, io_u);
11587dc1ab1b4df7b977f60e3d43533a896e2ee665bJens Axboe	else
11687dc1ab1b4df7b977f60e3d43533a896e2ee665bJens Axboe		ret = fsync(io_u->file->fd);
1172866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
118cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe	if (ret != (int) io_u->xfer_buflen) {
1192866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		if (ret > 0) {
120cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe			io_u->resid = io_u->xfer_buflen - ret;
121cec6b55da1c282b5b91ad346c7804171fccf151eJens Axboe			io_u->error = 0;
12236167d82e5f49dee91c6d2cd426068edee90e36fJens Axboe			return FIO_Q_COMPLETED;
1232866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		} else
1242866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe			io_u->error = errno;
1252866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	}
1262866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
12736167d82e5f49dee91c6d2cd426068edee90e36fJens Axboe	if (io_u->error)
12895bcd815e5ce55d6cdd8eb83bda5ee411f37bdc9Jens Axboe		td_verror(td, io_u->error);
1292866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
13036167d82e5f49dee91c6d2cd426068edee90e36fJens Axboe	return FIO_Q_COMPLETED;
1312866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe}
1322866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1332866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboestatic void fio_spliceio_cleanup(struct thread_data *td)
1342866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe{
1352866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	struct spliceio_data *sd = td->io_ops->data;
1362866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1372866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	if (sd) {
1382866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		close(sd->pipe[0]);
1392866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		close(sd->pipe[1]);
1402866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		free(sd);
1412866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		td->io_ops->data = NULL;
1422866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	}
1432866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe}
1442866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1452866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboestatic int fio_spliceio_init(struct thread_data *td)
1462866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe{
1472866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	struct spliceio_data *sd = malloc(sizeof(*sd));
1482866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1492866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	if (pipe(sd->pipe) < 0) {
1502866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		td_verror(td, errno);
1512866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		free(sd);
1522866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe		return 1;
1532866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	}
1542866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1552866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	td->io_ops->data = sd;
1562866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	return 0;
1572866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe}
1582866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe
1595f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboestatic struct ioengine_ops ioengine = {
1602866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	.name		= "splice",
1612866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	.version	= FIO_IOOPS_VERSION,
1622866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	.init		= fio_spliceio_init,
1632866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	.queue		= fio_spliceio_queue,
1642866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	.cleanup	= fio_spliceio_cleanup,
1652866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe	.flags		= FIO_SYNCIO,
1662866c82d598e30604d8a92723c664ee6ced90fb0Jens Axboe};
16734cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe
16834cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe#else /* FIO_HAVE_SPLICE */
16934cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe
17034cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe/*
17134cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe * When we have a proper configure system in place, we simply wont build
17234cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe * and install this io engine. For now install a crippled version that
17334cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe * just complains and fails to load.
17434cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe */
17534cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboestatic int fio_spliceio_init(struct thread_data fio_unused *td)
17634cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe{
17734cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe	fprintf(stderr, "fio: splice not available\n");
17834cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe	return 1;
17934cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe}
18034cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe
1815f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboestatic struct ioengine_ops ioengine = {
18234cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe	.name		= "splice",
18334cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe	.version	= FIO_IOOPS_VERSION,
18434cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe	.init		= fio_spliceio_init,
18534cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe};
18634cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe
18734cfcdafa994a0a75120e498c51eda08bde5df72Jens Axboe#endif
1885f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe
1895f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboestatic void fio_init fio_spliceio_register(void)
1905f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe{
1915f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe	register_ioengine(&ioengine);
1925f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe}
1935f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe
1945f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboestatic void fio_exit fio_spliceio_unregister(void)
1955f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe{
1965f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe	unregister_ioengine(&ioengine);
1975f350952eff89948bfbf1eb6ac4d3d08a9109581Jens Axboe}
198