Skip to content

Commit 61b483a

Browse files
author
Sergey Truschev
committed
fio: add xattr ioengines
The patch introduce ioengines that allow to measure extended attributes access: filesetxattr for xattrs value setting, filegetxattr - for lookup. Signed-off-by: Sergei Truschev <[email protected]>
1 parent 1eb3ade commit 61b483a

File tree

6 files changed

+312
-15
lines changed

6 files changed

+312
-15
lines changed

HOWTO.rst

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2332,6 +2332,18 @@ I/O engine
23322332
This engine is to measure file lookup and meta data access.
23332333
Example job file: filestat-ioengine.fio.
23342334

2335+
**filesetxattr**
2336+
Simply set files extended attributes via setxattr(). You need to set 'filesize'
2337+
and 'nrfiles', so that files will be created.
2338+
This engine is to measure extended attributes access.
2339+
Example job file: filexattr-ioengine.fio.
2340+
2341+
**filelistxattr**
2342+
Simply list and then get all files extended attributes via listxattr and getxattr.
2343+
You need to set 'filesize' and 'nrfiles', so that files will be created.
2344+
This engine is to measure extended attributes access.
2345+
Example job file: filexattr-ioengine.fio.
2346+
23352347
**filedelete**
23362348
Simply delete the files by unlink() and do no I/O to them. You need to set 'filesize'
23372349
and 'nrfiles', so that the files will be created.
@@ -4854,17 +4866,21 @@ writes in the example above). In the order listed, they denote:
48544866
For file and directory operation engines, **clat** denotes the time
48554867
to complete one file or directory operation.
48564868

4857-
**filecreate engine**:the time cost to create a new file
4869+
**filecreate engine**: the time cost to create a new file
48584870

4859-
**filestat engine**: the time cost to look up an existing file
4871+
**filestat engine**: the time cost to look up an existing file
48604872

4861-
**filedelete engine**:the time cost to delete a file
4873+
**filesetxattr engine**:the time cost to set a bunch of file extended attributes
48624874

4863-
**dircreate engine**: the time cost to create a new directory
4875+
**filestat engine**: the time cost to look up all file extended attributes
48644876

4865-
**dirstat engine**: the time cost to look up an existing directory
4877+
**filedelete engine**: the time cost to delete a file
48664878

4867-
**dirdelete engine**: the time cost to delete a directory
4879+
**dircreate engine**: the time cost to create a new directory
4880+
4881+
**dirstat engine**: the time cost to look up an existing directory
4882+
4883+
**dirdelete engine**: the time cost to delete a directory
48684884

48694885
**lat**
48704886
Total latency. Same names as slat and clat, this denotes the time from
@@ -4896,17 +4912,19 @@ writes in the example above). In the order listed, they denote:
48964912
fundamental index to denote the performance.
48974913
It means how many files or directories can be operated per second.
48984914

4899-
**filecreate engine**:number of files can be created per second
4915+
**filecreate engine**: number of files can be created per second
4916+
4917+
**filestat engine**: number of files can be looked up per second
49004918

4901-
**filestat engine**: number of files can be looked up per second
4919+
**filesetxattr engine**: number of files for which extended attributes can been set per second
49024920

4903-
**filedelete engine**:number of files can be deleted per second
4921+
**filelistxattr engine**:number of all file extended attributes fetches per second
49044922

4905-
**dircreate engine**: number of directories can be created per second
4923+
**dircreate engine**: number of directories can be created per second
49064924

4907-
**dirstat engine**: number of directories can be looked up per second
4925+
**dirstat engine**: number of directories can be looked up per second
49084926

4909-
**dirdelete engine**: number of directories can be deleted per second
4927+
**dirdelete engine**: number of directories can be deleted per second
49104928

49114929
**lat (nsec/usec/msec)**
49124930
The distribution of I/O completion latencies. This is the time from when

engines/fileoperations.c

Lines changed: 246 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#include <errno.h>
1111
#include <sys/types.h>
1212
#include <sys/stat.h>
13+
#ifndef _WIN32
14+
#include <sys/xattr.h>
15+
#endif
1316
#include <unistd.h>
1417
#include "../fio.h"
1518
#include "../optgroup.h"
@@ -31,13 +34,45 @@ struct filestat_options {
3134
unsigned int stat_type;
3235
};
3336

37+
struct xattr_options {
38+
void* pad;
39+
int size;
40+
int count;
41+
};
42+
3443
enum {
3544
FIO_FILESTAT_STAT = 1,
3645
FIO_FILESTAT_LSTAT = 2,
3746
FIO_FILESTAT_STATX = 3,
3847
};
3948

40-
static struct fio_option options[] = {
49+
static struct fio_option xattr_options[] = {
50+
{
51+
.name = "xattr_size",
52+
.lname = "xattr_size",
53+
.type = FIO_OPT_INT,
54+
.off1 = offsetof(struct xattr_options, size),
55+
.help = "Specify the size of the extended attribute to be set.",
56+
.def = "512",
57+
.category = FIO_OPT_C_ENGINE,
58+
.group = FIO_OPT_G_FILEXATTR,
59+
},
60+
{
61+
.name = "xattr_count",
62+
.lname = "xattr_count",
63+
.type = FIO_OPT_INT,
64+
.off1 = offsetof(struct xattr_options, count),
65+
.help = "Specify the number of the extended attributes to be set.",
66+
.def = "1",
67+
.category = FIO_OPT_C_ENGINE,
68+
.group = FIO_OPT_G_FILEXATTR,
69+
},
70+
{
71+
.name = NULL,
72+
}
73+
};
74+
75+
static struct fio_option stat_options[] = {
4176
{
4277
.name = "stat_type",
4378
.lname = "stat_type",
@@ -206,6 +241,176 @@ static int stat_file(struct thread_data *td, struct fio_file *f)
206241
return 0;
207242
}
208243

244+
static int file_setxattr(struct thread_data *td, struct fio_file *f)
245+
{
246+
struct xattr_options *o = td->eo;
247+
struct timespec start;
248+
int attrcount;
249+
char attrname[256];
250+
char *attrval;
251+
int ret;
252+
253+
dprint(FD_FILE, "fd setxattr %s, count = %i, size = %i\n", f->file_name,
254+
o->count, o->size);
255+
256+
if (f->filetype != FIO_TYPE_FILE) {
257+
log_err("fio: only files are supported\n");
258+
return 1;
259+
}
260+
if (!strcmp(f->file_name, "-")) {
261+
log_err("fio: can't read/write to stdin/out\n");
262+
return 1;
263+
}
264+
265+
if (!td->o.disable_lat)
266+
fio_gettime(&start, NULL);
267+
268+
attrcount = o->count;
269+
while (attrcount > 0) {
270+
attrval = malloc(o->size);
271+
snprintf(attrname, 256, "user.fio_xattr_%i", attrcount--);
272+
#ifdef __linux__
273+
ret = setxattr(f->file_name, attrname, attrval, o->size, 0);
274+
#elif defined (__APPLE__)
275+
ret = setxattr(f->file_name, attrname, attrval, o->size, 0, 0);
276+
#else
277+
ret = -1;
278+
#endif
279+
free(attrval);
280+
281+
if (ret == -1) {
282+
char buf[FIO_VERROR_SIZE];
283+
int e = errno;
284+
285+
snprintf(buf, sizeof(buf), "setxattr(%s)", f->file_name);
286+
td_verror(td, e, buf);
287+
return 1;
288+
}
289+
}
290+
291+
if (!td->o.disable_lat) {
292+
struct fc_data *data = td->io_ops_data;
293+
uint64_t nsec;
294+
295+
nsec = ntime_since_now(&start);
296+
add_clat_sample(td, data->stat_ddir, nsec, 0, NULL);
297+
}
298+
299+
return 0;
300+
}
301+
302+
static int file_listxattr(struct thread_data *td, struct fio_file *f)
303+
{
304+
struct timespec start;
305+
306+
ssize_t buflen;
307+
ssize_t vallen;
308+
size_t namelen;
309+
char *attrname;
310+
char *attrbuf;
311+
char *attrval;
312+
313+
const char *errfn;
314+
char buf[FIO_VERROR_SIZE];
315+
int e;
316+
317+
dprint(FD_FILE, "fd listxattr %s\n", f->file_name);
318+
319+
if (f->filetype != FIO_TYPE_FILE) {
320+
log_err("fio: only files are supported\n");
321+
return 1;
322+
}
323+
if (!strcmp(f->file_name, "-")) {
324+
log_err("fio: can't read/write to stdin/out\n");
325+
return 1;
326+
}
327+
328+
if (!td->o.disable_lat)
329+
fio_gettime(&start, NULL);
330+
331+
#ifdef __linux__
332+
buflen = listxattr(f->file_name, NULL, 0);
333+
#elif defined (__APPLE__)
334+
buflen = listxattr(f->file_name, NULL, 0, 0);
335+
#else
336+
buflen = -1;
337+
#endif
338+
if (buflen == -1) {
339+
errfn = "listxattr";
340+
goto err;
341+
} else if (buflen == 0) {
342+
return 0;
343+
}
344+
345+
attrbuf = malloc(buflen);
346+
#ifdef __linux__
347+
buflen = listxattr(f->file_name, attrbuf, buflen);
348+
#elif defined (__APPLE__)
349+
buflen = listxattr(f->file_name, attrbuf, buflen, 0);
350+
#else
351+
buflen = -1;
352+
#endif
353+
if (buflen == -1) {
354+
errfn = "listxattr";
355+
goto err_cleanup;
356+
}
357+
358+
attrname = attrbuf;
359+
while (buflen > 0) {
360+
#ifdef __linux__
361+
vallen = getxattr(f->file_name, attrname, NULL, 0);
362+
#elif defined (__APPLE__)
363+
vallen = getxattr(f->file_name, attrname, NULL, 0, 0, 0);
364+
#else
365+
vallen = -1;
366+
#endif
367+
if (vallen == -1) {
368+
errfn = "getxattr";
369+
goto err_cleanup;
370+
}
371+
372+
if (vallen > 0) {
373+
attrval = malloc(vallen);
374+
#ifdef __linux__
375+
vallen = getxattr(f->file_name, attrname, attrval, vallen);
376+
#elif defined (__APPLE__)
377+
vallen = getxattr(f->file_name, attrname, attrval, vallen, 0, 0);
378+
#else
379+
vallen = -1;
380+
#endif
381+
free(attrval);
382+
if (vallen == -1) {
383+
errfn = "getxattr";
384+
goto err_cleanup;
385+
}
386+
}
387+
388+
namelen = strlen(attrname) + 1;
389+
buflen -= namelen;
390+
attrname += namelen;
391+
}
392+
393+
free(attrbuf);
394+
395+
if (!td->o.disable_lat) {
396+
struct fc_data *data = td->io_ops_data;
397+
uint64_t nsec;
398+
399+
nsec = ntime_since_now(&start);
400+
add_clat_sample(td, data->stat_ddir, nsec, 0, NULL);
401+
}
402+
403+
return 0;
404+
405+
err_cleanup:
406+
free(attrbuf);
407+
err:
408+
e = errno;
409+
snprintf(buf, sizeof(buf), "%s(%s)", errfn, f->file_name);
410+
td_verror(td, e, buf);
411+
return 1;
412+
}
413+
209414
static int delete_file(struct thread_data *td, struct fio_file *f)
210415
{
211416
struct timespec start;
@@ -341,7 +546,7 @@ static struct ioengine_ops ioengine_filestat = {
341546
.open_file = stat_file,
342547
.flags = FIO_SYNCIO | FIO_FAKEIO |
343548
FIO_NOSTATS | FIO_NOFILEHASH,
344-
.options = options,
549+
.options = stat_options,
345550
.option_struct_size = sizeof(struct filestat_options),
346551
};
347552

@@ -385,7 +590,7 @@ static struct ioengine_ops ioengine_dirstat = {
385590
.unlink_file = remove_dir,
386591
.flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
387592
FIO_NOSTATS | FIO_NOFILEHASH,
388-
.options = options,
593+
.options = stat_options,
389594
.option_struct_size = sizeof(struct filestat_options),
390595
};
391596

@@ -404,6 +609,36 @@ static struct ioengine_ops ioengine_dirdelete = {
404609
FIO_NOSTATS | FIO_NOFILEHASH,
405610
};
406611

612+
#ifndef _WIN32
613+
static struct ioengine_ops ioengine_filesetxattr = {
614+
.name = "filesetxattr",
615+
.version = FIO_IOOPS_VERSION,
616+
.init = init,
617+
.cleanup = cleanup,
618+
.queue = queue_io,
619+
.invalidate = invalidate_do_nothing,
620+
.get_file_size = generic_get_file_size,
621+
.open_file = file_setxattr,
622+
.flags = FIO_SYNCIO | FIO_FAKEIO |
623+
FIO_NOSTATS | FIO_NOFILEHASH,
624+
.options = xattr_options,
625+
.option_struct_size = sizeof(struct xattr_options),
626+
};
627+
628+
static struct ioengine_ops ioengine_filelistxattr = {
629+
.name = "filelistxattr",
630+
.version = FIO_IOOPS_VERSION,
631+
.init = init,
632+
.invalidate = invalidate_do_nothing,
633+
.cleanup = cleanup,
634+
.queue = queue_io,
635+
.get_file_size = generic_get_file_size,
636+
.open_file = file_listxattr,
637+
.flags = FIO_SYNCIO | FIO_FAKEIO |
638+
FIO_NOSTATS | FIO_NOFILEHASH,
639+
};
640+
#endif
641+
407642
static void fio_init fio_fileoperations_register(void)
408643
{
409644
register_ioengine(&ioengine_filecreate);
@@ -412,6 +647,10 @@ static void fio_init fio_fileoperations_register(void)
412647
register_ioengine(&ioengine_dircreate);
413648
register_ioengine(&ioengine_dirstat);
414649
register_ioengine(&ioengine_dirdelete);
650+
#ifndef _WIN32
651+
register_ioengine(&ioengine_filesetxattr);
652+
register_ioengine(&ioengine_filelistxattr);
653+
#endif
415654
}
416655

417656
static void fio_exit fio_fileoperations_unregister(void)
@@ -422,4 +661,8 @@ static void fio_exit fio_fileoperations_unregister(void)
422661
unregister_ioengine(&ioengine_dircreate);
423662
unregister_ioengine(&ioengine_dirstat);
424663
unregister_ioengine(&ioengine_dirdelete);
664+
#ifndef _WIN32
665+
unregister_ioengine(&ioengine_filesetxattr);
666+
unregister_ioengine(&ioengine_filelistxattr);
667+
#endif
425668
}

0 commit comments

Comments
 (0)