1/*
2 * glusterfs engine
3 *
4 * common Glusterfs's gfapi interface
5 *
6 */
7
8#include "gfapi.h"
9
10struct fio_option gfapi_options[] = {
11	{
12	 .name = "volume",
13	 .lname = "Glusterfs volume",
14	 .type = FIO_OPT_STR_STORE,
15	 .help = "Name of the Glusterfs volume",
16	 .off1 = offsetof(struct gf_options, gf_vol),
17	 .category = FIO_OPT_C_ENGINE,
18	 .group = FIO_OPT_G_GFAPI,
19	 },
20	{
21	 .name = "brick",
22	 .lname = "Glusterfs brick name",
23	 .type = FIO_OPT_STR_STORE,
24	 .help = "Name of the Glusterfs brick to connect",
25	 .off1 = offsetof(struct gf_options, gf_brick),
26	 .category = FIO_OPT_C_ENGINE,
27	 .group = FIO_OPT_G_GFAPI,
28	 },
29	{
30	 .name = NULL,
31	 },
32};
33
34int fio_gf_setup(struct thread_data *td)
35{
36	int r = 0;
37	struct gf_data *g = NULL;
38	struct gf_options *opt = td->eo;
39	struct stat sb = { 0, };
40
41	dprint(FD_IO, "fio setup\n");
42
43	if (td->io_ops->data)
44		return 0;
45
46	g = malloc(sizeof(struct gf_data));
47	if (!g) {
48		log_err("malloc failed.\n");
49		return -ENOMEM;
50	}
51	g->fs = NULL;
52	g->fd = NULL;
53	g->aio_events = NULL;
54
55	g->fs = glfs_new(opt->gf_vol);
56	if (!g->fs) {
57		log_err("glfs_new failed.\n");
58		goto cleanup;
59	}
60	glfs_set_logging(g->fs, "/tmp/fio_gfapi.log", 7);
61	/* default to tcp */
62	r = glfs_set_volfile_server(g->fs, "tcp", opt->gf_brick, 0);
63	if (r) {
64		log_err("glfs_set_volfile_server failed.\n");
65		goto cleanup;
66	}
67	r = glfs_init(g->fs);
68	if (r) {
69		log_err("glfs_init failed. Is glusterd running on brick?\n");
70		goto cleanup;
71	}
72	sleep(2);
73	r = glfs_lstat(g->fs, ".", &sb);
74	if (r) {
75		log_err("glfs_lstat failed.\n");
76		goto cleanup;
77	}
78	dprint(FD_FILE, "fio setup %p\n", g->fs);
79	td->io_ops->data = g;
80	return 0;
81cleanup:
82	if (g->fs)
83		glfs_fini(g->fs);
84	free(g);
85	td->io_ops->data = NULL;
86	return r;
87}
88
89void fio_gf_cleanup(struct thread_data *td)
90{
91	struct gf_data *g = td->io_ops->data;
92
93	if (g) {
94		if (g->aio_events)
95			free(g->aio_events);
96		if (g->fd)
97			glfs_close(g->fd);
98		if (g->fs)
99			glfs_fini(g->fs);
100		free(g);
101		td->io_ops->data = NULL;
102	}
103}
104
105int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
106{
107	struct stat buf;
108	int ret;
109	struct gf_data *g = td->io_ops->data;
110
111	dprint(FD_FILE, "get file size %s\n", f->file_name);
112
113	if (!g || !g->fs) {
114		return 0;
115	}
116	if (fio_file_size_known(f))
117		return 0;
118
119	ret = glfs_lstat(g->fs, f->file_name, &buf);
120	if (ret < 0) {
121		log_err("glfs_lstat failed.\n");
122		return ret;
123	}
124
125	f->real_file_size = buf.st_size;
126	fio_file_set_size_known(f);
127
128	return 0;
129
130}
131
132int fio_gf_open_file(struct thread_data *td, struct fio_file *f)
133{
134
135	int flags = 0;
136	int ret = 0;
137	struct gf_data *g = td->io_ops->data;
138	struct stat sb = { 0, };
139
140	if (td_write(td)) {
141		if (!read_only)
142			flags = O_RDWR;
143	} else if (td_read(td)) {
144		if (!read_only)
145			flags = O_RDWR;
146		else
147			flags = O_RDONLY;
148	}
149
150	if (td->o.odirect)
151		flags |= OS_O_DIRECT;
152	if (td->o.sync_io)
153		flags |= O_SYNC;
154
155	dprint(FD_FILE, "fio file %s open mode %s td rw %s\n", f->file_name,
156	       flags & O_RDONLY ? "ro" : "rw", td_read(td) ? "read" : "write");
157	g->fd = glfs_creat(g->fs, f->file_name, flags, 0644);
158	if (!g->fd) {
159		ret = errno;
160		log_err("glfs_creat failed.\n");
161		return ret;
162	}
163	/* file for read doesn't exist or shorter than required, create/extend it */
164	if (td_read(td)) {
165		if (glfs_lstat(g->fs, f->file_name, &sb)
166		    || sb.st_size < f->real_file_size) {
167			dprint(FD_FILE, "fio extend file %s from %ld to %ld\n",
168			       f->file_name, sb.st_size, f->real_file_size);
169			ret = glfs_ftruncate(g->fd, f->real_file_size);
170			if (ret) {
171				log_err("failed fio extend file %s to %ld\n",
172					f->file_name, f->real_file_size);
173			} else {
174				unsigned long long left;
175				unsigned int bs;
176				char *b;
177				int r;
178
179				/* fill the file, copied from extend_file */
180				b = malloc(td->o.max_bs[DDIR_WRITE]);
181
182				left = f->real_file_size;
183				while (left && !td->terminate) {
184					bs = td->o.max_bs[DDIR_WRITE];
185					if (bs > left)
186						bs = left;
187
188					fill_io_buffer(td, b, bs, bs);
189
190					r = glfs_write(g->fd, b, bs, 0);
191					dprint(FD_IO,
192					       "fio write %d of %ld file %s\n",
193					       r, f->real_file_size,
194					       f->file_name);
195
196					if (r > 0) {
197						left -= r;
198						continue;
199					} else {
200						if (r < 0) {
201							int __e = errno;
202
203							if (__e == ENOSPC) {
204								if (td->o.
205								    fill_device)
206									break;
207								log_info
208								    ("fio: ENOSPC on laying out "
209								     "file, stopping\n");
210								break;
211							}
212							td_verror(td, errno,
213								  "write");
214						} else
215							td_verror(td, EIO,
216								  "write");
217
218						break;
219					}
220				}
221
222				if (b)
223					free(b);
224				glfs_lseek(g->fd, 0, SEEK_SET);
225
226				if (td->terminate && td->o.unlink) {
227					dprint(FD_FILE, "terminate unlink %s\n",
228					       f->file_name);
229					glfs_unlink(g->fs, f->file_name);
230				} else if (td->o.create_fsync) {
231					if (glfs_fsync(g->fd) < 0) {
232						dprint(FD_FILE,
233						       "failed to sync, close %s\n",
234						       f->file_name);
235						td_verror(td, errno, "fsync");
236						glfs_close(g->fd);
237						g->fd = NULL;
238						return 1;
239					}
240				}
241			}
242		}
243	}
244#if defined(GFAPI_USE_FADVISE)
245	{
246		int r = 0;
247		if (td_random(td)) {
248			r = glfs_fadvise(g->fd, 0, f->real_file_size,
249					 POSIX_FADV_RANDOM);
250		} else {
251			r = glfs_fadvise(g->fd, 0, f->real_file_size,
252					 POSIX_FADV_SEQUENTIAL);
253		}
254		if (r) {
255			dprint(FD_FILE, "fio %p fadvise %s status %d\n", g->fs,
256			       f->file_name, r);
257		}
258	}
259#endif
260	dprint(FD_FILE, "fio %p created %s\n", g->fs, f->file_name);
261	f->fd = -1;
262	f->shadow_fd = -1;
263	td->o.open_files ++;
264	return ret;
265}
266
267int fio_gf_close_file(struct thread_data *td, struct fio_file *f)
268{
269	int ret = 0;
270	struct gf_data *g = td->io_ops->data;
271
272	dprint(FD_FILE, "fd close %s\n", f->file_name);
273
274	if (g) {
275		if (g->fd && glfs_close(g->fd) < 0)
276			ret = errno;
277		g->fd = NULL;
278	}
279
280	return ret;
281}
282
283int fio_gf_unlink_file(struct thread_data *td, struct fio_file *f)
284{
285	int ret = 0;
286	struct gf_data *g = td->io_ops->data;
287
288	dprint(FD_FILE, "fd unlink %s\n", f->file_name);
289
290	if (g) {
291		if (g->fd && glfs_close(g->fd) < 0)
292			ret = errno;
293
294		glfs_unlink(g->fs, f->file_name);
295
296		if (g->fs)
297			glfs_fini(g->fs);
298
299		g->fd = NULL;
300		free(g);
301	}
302	td->io_ops->data = NULL;
303
304	return ret;
305}
306