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+
3443enum {
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+
209414static 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+
407642static 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
417656static 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