1 /*
2  * glusterfs engine
3  *
4  * common Glusterfs's gfapi interface
5  *
6  */
7 
8 #include "gfapi.h"
9 
10 struct 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 
fio_gf_setup(struct thread_data * td)34 int 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;
81 cleanup:
82 	if (g->fs)
83 		glfs_fini(g->fs);
84 	free(g);
85 	td->io_ops->data = NULL;
86 	return r;
87 }
88 
fio_gf_cleanup(struct thread_data * td)89 void 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 
fio_gf_get_file_size(struct thread_data * td,struct fio_file * f)105 int 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 
fio_gf_open_file(struct thread_data * td,struct fio_file * f)132 int 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 
fio_gf_close_file(struct thread_data * td,struct fio_file * f)267 int 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 
fio_gf_unlink_file(struct thread_data * td,struct fio_file * f)283 int 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