1 /*
2 * glusterfs engine
3 *
4 * common Glusterfs's gfapi interface
5 *
6 */
7
8 #include "gfapi.h"
9 #include "../optgroup.h"
10
11 struct fio_option gfapi_options[] = {
12 {
13 .name = "volume",
14 .lname = "Glusterfs volume",
15 .type = FIO_OPT_STR_STORE,
16 .help = "Name of the Glusterfs volume",
17 .off1 = offsetof(struct gf_options, gf_vol),
18 .category = FIO_OPT_C_ENGINE,
19 .group = FIO_OPT_G_GFAPI,
20 },
21 {
22 .name = "brick",
23 .lname = "Glusterfs brick name",
24 .type = FIO_OPT_STR_STORE,
25 .help = "Name of the Glusterfs brick to connect",
26 .off1 = offsetof(struct gf_options, gf_brick),
27 .category = FIO_OPT_C_ENGINE,
28 .group = FIO_OPT_G_GFAPI,
29 },
30 {
31 .name = "single-instance",
32 .lname = "Single glusterfs instance",
33 .type = FIO_OPT_BOOL,
34 .help = "Only one glusterfs instance",
35 .off1 = offsetof(struct gf_options, gf_single_instance),
36 .category = FIO_OPT_C_ENGINE,
37 .group = FIO_OPT_G_GFAPI,
38 },
39 {
40 .name = NULL,
41 },
42 };
43
44 struct glfs_info {
45 struct flist_head list;
46 char *volume;
47 char *brick;
48 glfs_t *fs;
49 int refcount;
50 };
51
52 static pthread_mutex_t glfs_lock = PTHREAD_MUTEX_INITIALIZER;
53 static FLIST_HEAD(glfs_list_head);
54
fio_gf_new_fs(char * volume,char * brick)55 static glfs_t *fio_gf_new_fs(char *volume, char *brick)
56 {
57 int r = 0;
58 glfs_t *fs;
59 struct stat sb = { 0, };
60
61 fs = glfs_new(volume);
62 if (!fs) {
63 log_err("glfs_new failed.\n");
64 goto out;
65 }
66 glfs_set_logging(fs, "/tmp/fio_gfapi.log", 7);
67 /* default to tcp */
68 r = glfs_set_volfile_server(fs, "tcp", brick, 0);
69 if (r) {
70 log_err("glfs_set_volfile_server failed.\n");
71 goto out;
72 }
73 r = glfs_init(fs);
74 if (r) {
75 log_err("glfs_init failed. Is glusterd running on brick?\n");
76 goto out;
77 }
78 sleep(2);
79 r = glfs_lstat(fs, ".", &sb);
80 if (r) {
81 log_err("glfs_lstat failed.\n");
82 goto out;
83 }
84
85 out:
86 if (r) {
87 glfs_fini(fs);
88 fs = NULL;
89 }
90 return fs;
91 }
92
fio_gf_get_glfs(struct gf_options * opt,char * volume,char * brick)93 static glfs_t *fio_gf_get_glfs(struct gf_options *opt,
94 char *volume, char *brick)
95 {
96 struct glfs_info *glfs = NULL;
97 struct glfs_info *tmp;
98 struct flist_head *entry;
99
100 if (!opt->gf_single_instance)
101 return fio_gf_new_fs(volume, brick);
102
103 pthread_mutex_lock (&glfs_lock);
104
105 flist_for_each(entry, &glfs_list_head) {
106 tmp = flist_entry(entry, struct glfs_info, list);
107 if (!strcmp(volume, tmp->volume) &&
108 !strcmp(brick, tmp->brick)) {
109 glfs = tmp;
110 break;
111 }
112 }
113
114 if (glfs) {
115 glfs->refcount++;
116 } else {
117 glfs = malloc(sizeof(*glfs));
118 if (!glfs)
119 goto out;
120 INIT_FLIST_HEAD(&glfs->list);
121 glfs->refcount = 0;
122 glfs->volume = strdup(volume);
123 glfs->brick = strdup(brick);
124 glfs->fs = fio_gf_new_fs(volume, brick);
125 if (!glfs->fs) {
126 free(glfs);
127 glfs = NULL;
128 goto out;
129 }
130
131 flist_add_tail(&glfs->list, &glfs_list_head);
132 glfs->refcount = 1;
133 }
134
135 out:
136 pthread_mutex_unlock (&glfs_lock);
137
138 if (glfs)
139 return glfs->fs;
140 return NULL;
141 }
142
fio_gf_put_glfs(struct gf_options * opt,glfs_t * fs)143 static void fio_gf_put_glfs(struct gf_options *opt, glfs_t *fs)
144 {
145 struct glfs_info *glfs = NULL;
146 struct glfs_info *tmp;
147 struct flist_head *entry;
148
149 if (!opt->gf_single_instance) {
150 glfs_fini(fs);
151 return;
152 }
153
154 pthread_mutex_lock (&glfs_lock);
155
156 flist_for_each(entry, &glfs_list_head) {
157 tmp = flist_entry(entry, struct glfs_info, list);
158 if (tmp->fs == fs) {
159 glfs = tmp;
160 break;
161 }
162 }
163
164 if (!glfs) {
165 log_err("glfs not found to fini.\n");
166 } else {
167 glfs->refcount--;
168
169 if (glfs->refcount == 0) {
170 glfs_fini(glfs->fs);
171 free(glfs->volume);
172 free(glfs->brick);
173 flist_del(&glfs->list);
174 }
175 }
176
177 pthread_mutex_unlock (&glfs_lock);
178 }
179
fio_gf_setup(struct thread_data * td)180 int fio_gf_setup(struct thread_data *td)
181 {
182 struct gf_data *g = NULL;
183 struct gf_options *opt = td->eo;
184
185 dprint(FD_IO, "fio setup\n");
186
187 if (td->io_ops_data)
188 return 0;
189
190 g = malloc(sizeof(struct gf_data));
191 if (!g) {
192 log_err("malloc failed.\n");
193 return -ENOMEM;
194 }
195 g->fd = NULL;
196 g->aio_events = NULL;
197
198 g->fs = fio_gf_get_glfs(opt, opt->gf_vol, opt->gf_brick);
199 if (!g->fs)
200 goto cleanup;
201
202 dprint(FD_FILE, "fio setup %p\n", g->fs);
203 td->io_ops_data = g;
204 return 0;
205 cleanup:
206 free(g);
207 td->io_ops_data = NULL;
208 return -EIO;
209 }
210
fio_gf_cleanup(struct thread_data * td)211 void fio_gf_cleanup(struct thread_data *td)
212 {
213 struct gf_data *g = td->io_ops_data;
214
215 if (g) {
216 if (g->aio_events)
217 free(g->aio_events);
218 if (g->fd)
219 glfs_close(g->fd);
220 if (g->fs)
221 fio_gf_put_glfs(td->eo, g->fs);
222 free(g);
223 td->io_ops_data = NULL;
224 }
225 }
226
fio_gf_get_file_size(struct thread_data * td,struct fio_file * f)227 int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
228 {
229 struct stat buf;
230 int ret;
231 struct gf_data *g = td->io_ops_data;
232
233 dprint(FD_FILE, "get file size %s\n", f->file_name);
234
235 if (!g || !g->fs) {
236 return 0;
237 }
238 if (fio_file_size_known(f))
239 return 0;
240
241 ret = glfs_lstat(g->fs, f->file_name, &buf);
242 if (ret < 0) {
243 log_err("glfs_lstat failed.\n");
244 return ret;
245 }
246
247 f->real_file_size = buf.st_size;
248 fio_file_set_size_known(f);
249
250 return 0;
251
252 }
253
fio_gf_open_file(struct thread_data * td,struct fio_file * f)254 int fio_gf_open_file(struct thread_data *td, struct fio_file *f)
255 {
256
257 int flags = 0;
258 int ret = 0;
259 struct gf_data *g = td->io_ops_data;
260 struct stat sb = { 0, };
261
262 if (td_write(td)) {
263 if (!read_only)
264 flags = O_RDWR;
265 } else if (td_read(td)) {
266 if (!read_only)
267 flags = O_RDWR;
268 else
269 flags = O_RDONLY;
270 }
271
272 if (td->o.odirect)
273 flags |= OS_O_DIRECT;
274 flags |= td->o.sync_io;
275
276 dprint(FD_FILE, "fio file %s open mode %s td rw %s\n", f->file_name,
277 flags & O_RDONLY ? "ro" : "rw", td_read(td) ? "read" : "write");
278 g->fd = glfs_creat(g->fs, f->file_name, flags, 0644);
279 if (!g->fd) {
280 ret = errno;
281 log_err("glfs_creat failed.\n");
282 return ret;
283 }
284 /* file for read doesn't exist or shorter than required, create/extend it */
285 if (td_read(td)) {
286 if (glfs_lstat(g->fs, f->file_name, &sb)
287 || sb.st_size < f->real_file_size) {
288 dprint(FD_FILE, "fio extend file %s from %jd to %" PRIu64 "\n",
289 f->file_name, (intmax_t) sb.st_size, f->real_file_size);
290 #if defined(CONFIG_GF_NEW_API)
291 ret = glfs_ftruncate(g->fd, f->real_file_size, NULL, NULL);
292 #else
293 ret = glfs_ftruncate(g->fd, f->real_file_size);
294 #endif
295 if (ret) {
296 log_err("failed fio extend file %s to %" PRIu64 "\n",
297 f->file_name, f->real_file_size);
298 } else {
299 unsigned long long left;
300 unsigned int bs;
301 char *b;
302 int r;
303
304 /* fill the file, copied from extend_file */
305 b = malloc(td->o.max_bs[DDIR_WRITE]);
306
307 left = f->real_file_size;
308 while (left && !td->terminate) {
309 bs = td->o.max_bs[DDIR_WRITE];
310 if (bs > left)
311 bs = left;
312
313 fill_io_buffer(td, b, bs, bs);
314
315 r = glfs_write(g->fd, b, bs, 0);
316 dprint(FD_IO,
317 "fio write %d of %" PRIu64 " file %s\n",
318 r, f->real_file_size,
319 f->file_name);
320
321 if (r > 0) {
322 left -= r;
323 continue;
324 } else {
325 if (r < 0) {
326 int __e = errno;
327
328 if (__e == ENOSPC) {
329 if (td->o.
330 fill_device)
331 break;
332 log_info
333 ("fio: ENOSPC on laying out "
334 "file, stopping\n");
335 break;
336 }
337 td_verror(td, errno,
338 "write");
339 } else
340 td_verror(td, EIO,
341 "write");
342
343 break;
344 }
345 }
346
347 if (b)
348 free(b);
349 glfs_lseek(g->fd, 0, SEEK_SET);
350
351 if (td->terminate && td->o.unlink) {
352 dprint(FD_FILE, "terminate unlink %s\n",
353 f->file_name);
354 glfs_unlink(g->fs, f->file_name);
355 } else if (td->o.create_fsync) {
356 #if defined(CONFIG_GF_NEW_API)
357 if (glfs_fsync(g->fd, NULL, NULL) < 0) {
358 #else
359 if (glfs_fsync(g->fd) < 0) {
360 #endif
361 dprint(FD_FILE,
362 "failed to sync, close %s\n",
363 f->file_name);
364 td_verror(td, errno, "fsync");
365 glfs_close(g->fd);
366 g->fd = NULL;
367 return 1;
368 }
369 }
370 }
371 }
372 }
373 #if defined(GFAPI_USE_FADVISE)
374 {
375 int r = 0;
376 if (td_random(td)) {
377 r = glfs_fadvise(g->fd, 0, f->real_file_size,
378 POSIX_FADV_RANDOM);
379 } else {
380 r = glfs_fadvise(g->fd, 0, f->real_file_size,
381 POSIX_FADV_SEQUENTIAL);
382 }
383 if (r) {
384 dprint(FD_FILE, "fio %p fadvise %s status %d\n", g->fs,
385 f->file_name, r);
386 }
387 }
388 #endif
389 dprint(FD_FILE, "fio %p created %s\n", g->fs, f->file_name);
390 f->fd = -1;
391 f->shadow_fd = -1;
392 td->o.open_files ++;
393 return ret;
394 }
395
396 int fio_gf_close_file(struct thread_data *td, struct fio_file *f)
397 {
398 int ret = 0;
399 struct gf_data *g = td->io_ops_data;
400
401 dprint(FD_FILE, "fd close %s\n", f->file_name);
402
403 if (g) {
404 if (g->fd && glfs_close(g->fd) < 0)
405 ret = errno;
406 g->fd = NULL;
407 }
408
409 return ret;
410 }
411
412 int fio_gf_unlink_file(struct thread_data *td, struct fio_file *f)
413 {
414 int ret = 0;
415 struct gf_data *g = td->io_ops_data;
416
417 dprint(FD_FILE, "fd unlink %s\n", f->file_name);
418
419 if (g) {
420 if (g->fd && glfs_close(g->fd) < 0)
421 ret = errno;
422
423 glfs_unlink(g->fs, f->file_name);
424
425 if (g->fs)
426 glfs_fini(g->fs);
427
428 g->fd = NULL;
429 free(g);
430 }
431 td->io_ops_data = NULL;
432
433 return ret;
434 }
435