16ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya/*
26ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * Custom fio(1) engine that submits synchronous atomic writes to file.
36ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya *
4b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya * Copyright (C) 2013 Fusion-io, Inc.
5b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya * Author: Santhosh Kumar Koundinya (skoundinya@fusionio.com).
66ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya *
76ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * This program is free software; you can redistribute it and/or modify it
86ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * under the terms of the GNU General Public License as published by the Free
915a6f166ed6fe0f221539b8ffea55905ed25b440Jens Axboe * Software Foundation; under version 2 of the License.
106ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya *
116ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * This program is distributed in the hope that it will be useful, but WITHOUT
126ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
136ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License version
146ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * 2 for more details.
156ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya *
166ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * You should have received a copy of the GNU General Public License Version 2
176ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya * along with this program; if not see <http://www.gnu.org/licenses/>
186ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya */
196ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
206ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya#include <stdlib.h>
216ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya#include <stdint.h>
226ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
236ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya#include "../fio.h"
246ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
25b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya#include <nvm/nvm_primitives.h>
266ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
274728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu#define NUM_ATOMIC_CAPABILITIES (5)
284728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu
29b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinyastruct fas_data {
30b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_handle_t nvm_handle;
31b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	size_t xfer_buf_align;
32b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	size_t xfer_buflen_align;
33b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	size_t xfer_buflen_max;
34b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	size_t sector_size;
356ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya};
366ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
376ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyastatic int queue(struct thread_data *td, struct io_u *io_u)
386ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya{
396ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	int rc;
40b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	struct fas_data *d = (struct fas_data *) io_u->file->engine_data;
416ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
426ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	if (io_u->ddir != DDIR_WRITE) {
43b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, EINVAL, "only writes supported", "io_u->ddir");
44b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = -EINVAL;
456ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya		goto out;
466ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
47b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
48b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if ((size_t) io_u->xfer_buf % d->xfer_buf_align) {
49b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, EINVAL, "unaligned data buffer", "io_u->xfer_buf");
50b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = -EINVAL;
516ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya		goto out;
526ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
53b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
54b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if (io_u->xfer_buflen % d->xfer_buflen_align) {
55b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, EINVAL, "unaligned data size", "io_u->xfer_buflen");
56b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = -EINVAL;
576ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya		goto out;
586ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
596ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
60b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if (io_u->xfer_buflen > d->xfer_buflen_max) {
61b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, EINVAL, "data too big", "io_u->xfer_buflen");
62b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = -EINVAL;
63b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		goto out;
646ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
656ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
66b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	rc = nvm_atomic_write(d->nvm_handle, (uint64_t) io_u->xfer_buf,
67b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		io_u->xfer_buflen, io_u->offset / d->sector_size);
686ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	if (rc == -1) {
69b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_verror(td, errno, "nvm_atomic_write");
70b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = -errno;
716ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya		goto out;
726ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
73b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	rc = FIO_Q_COMPLETED;
746ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyaout:
756ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	if (rc < 0)
76b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		io_u->error = -rc;
776ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
786ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	return rc;
796ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya}
806ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
816ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyastatic int open_file(struct thread_data *td, struct fio_file *f)
826ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya{
836ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	int rc;
84b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	int fio_unused close_file_rc;
85b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	struct fas_data *d;
86b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_version_t nvm_version;
874728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu	nvm_capability_t nvm_capability[NUM_ATOMIC_CAPABILITIES];
88b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
896ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
906ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	d = malloc(sizeof(*d));
916ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	if (!d) {
92b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_verror(td, ENOMEM, "malloc");
93b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = ENOMEM;
946ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya		goto error;
956ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
96b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	d->nvm_handle = -1;
97c11a9ddfb9a53f9faa78b72fc79be2f46addc8aaJens Axboe	f->engine_data = (uintptr_t) d;
986ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
996ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	rc = generic_open_file(td, f);
1006ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
101b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if (rc)
102b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		goto free_engine_data;
103b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
104b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	/* Set the version of the library as seen when engine is compiled */
105b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_version.major = NVM_PRIMITIVES_API_MAJOR;
106b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_version.minor = NVM_PRIMITIVES_API_MINOR;
107b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_version.micro = NVM_PRIMITIVES_API_MICRO;
108b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
109b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	d->nvm_handle = nvm_get_handle(f->fd, &nvm_version);
110b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if (d->nvm_handle == -1) {
111b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, errno, "nvm_get_handle failed", "nvm_get_handle");
112b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = errno;
113b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		goto close_file;
114b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	}
115b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
116b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_capability[0].cap_id = NVM_CAP_ATOMIC_WRITE_START_ALIGN_ID;
117b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_capability[1].cap_id = NVM_CAP_ATOMIC_WRITE_MULTIPLICITY_ID;
118b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_capability[2].cap_id = NVM_CAP_ATOMIC_WRITE_MAX_VECTOR_SIZE_ID;
119b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	nvm_capability[3].cap_id = NVM_CAP_SECTOR_SIZE_ID;
1204728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu	nvm_capability[4].cap_id = NVM_CAP_ATOMIC_MAX_IOV_ID;
1214728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu	rc = nvm_get_capabilities(d->nvm_handle, nvm_capability,
1224728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu                                  NUM_ATOMIC_CAPABILITIES, false);
123b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if (rc == -1) {
124b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, errno, "error in getting atomic write capabilities", "nvm_get_capabilities");
125b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = errno;
126b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		goto close_file;
1274728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu	} else if (rc < NUM_ATOMIC_CAPABILITIES) {
128b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		td_vmsg(td, EINVAL, "couldn't get all the atomic write capabilities" , "nvm_get_capabilities");
129b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		rc = ECANCELED;
130b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		goto close_file;
131b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	}
132b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	/* Reset rc to 0 because we got all capabilities we needed */
133b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	rc = 0;
134b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	d->xfer_buf_align = nvm_capability[0].cap_value;
135b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	d->xfer_buflen_align = nvm_capability[1].cap_value;
1364728b3c82f07612d64b79a67adc31dd9ca3c79fcChandra Mallarapu	d->xfer_buflen_max = d->xfer_buflen_align * nvm_capability[2].cap_value * nvm_capability[4].cap_value;
137b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	d->sector_size = nvm_capability[3].cap_value;
138b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
1396ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyaout:
1406ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	return rc;
141b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinyaclose_file:
142b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	close_file_rc = generic_close_file(td, f);
143b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinyafree_engine_data:
144b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	free(d);
1456ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyaerror:
1466ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	f->fd = -1;
147c11a9ddfb9a53f9faa78b72fc79be2f46addc8aaJens Axboe	f->engine_data = 0;
1486ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	goto out;
1496ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya}
1506ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
1516ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyastatic int close_file(struct thread_data *td, struct fio_file *f)
1526ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya{
153b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	struct fas_data *d = (struct fas_data *) f->engine_data;
154b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya
155b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya	if (d) {
156b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		if (d->nvm_handle != -1)
157b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya			nvm_release_handle(d->nvm_handle);
158b2c77c25cac5eb49f6966c46aeef7a17d831e5b1Santhosh Koundinya		free(d);
159c11a9ddfb9a53f9faa78b72fc79be2f46addc8aaJens Axboe		f->engine_data = 0;
1606ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	}
1616ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
1626ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	return generic_close_file(td, f);
1636ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya}
1646ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
1656ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyastatic struct ioengine_ops ioengine = {
1666ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.name = "fusion-aw-sync",
1676ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.version = FIO_IOOPS_VERSION,
1686ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.queue = queue,
1696ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.open_file = open_file,
1706ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.close_file = close_file,
1716ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.get_file_size = generic_get_file_size,
1726ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	.flags = FIO_SYNCIO | FIO_RAWIO | FIO_MEMALIGN
1736ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya};
1746ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
1756ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyastatic void fio_init fio_fusion_aw_init(void)
1766ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya{
1776ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	register_ioengine(&ioengine);
1786ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya}
1796ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya
1806ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinyastatic void fio_exit fio_fusion_aw_exit(void)
1816ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya{
1826ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya	unregister_ioengine(&ioengine);
1836ef63580ab6e3d73f205d05b126dbeb33e0508bcSanthosh Koundinya}
184