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,47 @@ 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+ #ifndef _WIN32
50+ static struct fio_option xattr_options [] = {
51+ {
52+ .name = "xattr_size" ,
53+ .lname = "xattr_size" ,
54+ .type = FIO_OPT_INT ,
55+ .off1 = offsetof(struct xattr_options , size ),
56+ .help = "Specify the size of the extended attribute to be set." ,
57+ .def = "512" ,
58+ .category = FIO_OPT_C_ENGINE ,
59+ .group = FIO_OPT_G_FILEXATTR ,
60+ },
61+ {
62+ .name = "xattr_count" ,
63+ .lname = "xattr_count" ,
64+ .type = FIO_OPT_INT ,
65+ .off1 = offsetof(struct xattr_options , count ),
66+ .help = "Specify the number of the extended attributes to be set." ,
67+ .def = "1" ,
68+ .category = FIO_OPT_C_ENGINE ,
69+ .group = FIO_OPT_G_FILEXATTR ,
70+ },
71+ {
72+ .name = NULL ,
73+ }
74+ };
75+ #endif
76+
77+ static struct fio_option stat_options [] = {
4178 {
4279 .name = "stat_type" ,
4380 .lname = "stat_type" ,
@@ -206,6 +243,178 @@ static int stat_file(struct thread_data *td, struct fio_file *f)
206243 return 0 ;
207244}
208245
246+ #ifndef _WIN32
247+ static int file_setxattr (struct thread_data * td , struct fio_file * f )
248+ {
249+ struct xattr_options * o = td -> eo ;
250+ struct timespec start ;
251+ int attrcount ;
252+ char attrname [256 ];
253+ char * attrval ;
254+ int ret ;
255+
256+ dprint (FD_FILE , "fd setxattr %s, count = %i, size = %i\n" , f -> file_name ,
257+ o -> count , o -> size );
258+
259+ if (f -> filetype != FIO_TYPE_FILE ) {
260+ log_err ("fio: only files are supported\n" );
261+ return 1 ;
262+ }
263+ if (!strcmp (f -> file_name , "-" )) {
264+ log_err ("fio: can't read/write to stdin/out\n" );
265+ return 1 ;
266+ }
267+
268+ if (!td -> o .disable_lat )
269+ fio_gettime (& start , NULL );
270+
271+ attrcount = o -> count ;
272+ while (attrcount > 0 ) {
273+ attrval = malloc (o -> size );
274+ snprintf (attrname , 256 , "user.fio_xattr_%i" , attrcount -- );
275+ #ifdef __linux__
276+ ret = setxattr (f -> file_name , attrname , attrval , o -> size , 0 );
277+ #elif defined (__APPLE__ )
278+ ret = setxattr (f -> file_name , attrname , attrval , o -> size , 0 , 0 );
279+ #else
280+ ret = -1 ;
281+ #endif
282+ free (attrval );
283+
284+ if (ret == -1 ) {
285+ char buf [FIO_VERROR_SIZE ];
286+ int e = errno ;
287+
288+ snprintf (buf , sizeof (buf ), "setxattr(%s)" , f -> file_name );
289+ td_verror (td , e , buf );
290+ return 1 ;
291+ }
292+ }
293+
294+ if (!td -> o .disable_lat ) {
295+ struct fc_data * data = td -> io_ops_data ;
296+ uint64_t nsec ;
297+
298+ nsec = ntime_since_now (& start );
299+ add_clat_sample (td , data -> stat_ddir , nsec , 0 , NULL );
300+ }
301+
302+ return 0 ;
303+ }
304+
305+ static int file_listxattr (struct thread_data * td , struct fio_file * f )
306+ {
307+ struct timespec start ;
308+
309+ ssize_t buflen ;
310+ ssize_t vallen ;
311+ size_t namelen ;
312+ char * attrname ;
313+ char * attrbuf ;
314+ char * attrval ;
315+
316+ const char * errfn ;
317+ char buf [FIO_VERROR_SIZE ];
318+ int e ;
319+
320+ dprint (FD_FILE , "fd listxattr %s\n" , f -> file_name );
321+
322+ if (f -> filetype != FIO_TYPE_FILE ) {
323+ log_err ("fio: only files are supported\n" );
324+ return 1 ;
325+ }
326+ if (!strcmp (f -> file_name , "-" )) {
327+ log_err ("fio: can't read/write to stdin/out\n" );
328+ return 1 ;
329+ }
330+
331+ if (!td -> o .disable_lat )
332+ fio_gettime (& start , NULL );
333+
334+ #ifdef __linux__
335+ buflen = listxattr (f -> file_name , NULL , 0 );
336+ #elif defined (__APPLE__ )
337+ buflen = listxattr (f -> file_name , NULL , 0 , 0 );
338+ #else
339+ buflen = -1 ;
340+ #endif
341+ if (buflen == -1 ) {
342+ errfn = "listxattr" ;
343+ goto err ;
344+ } else if (buflen == 0 ) {
345+ return 0 ;
346+ }
347+
348+ attrbuf = malloc (buflen );
349+ #ifdef __linux__
350+ buflen = listxattr (f -> file_name , attrbuf , buflen );
351+ #elif defined (__APPLE__ )
352+ buflen = listxattr (f -> file_name , attrbuf , buflen , 0 );
353+ #else
354+ buflen = -1 ;
355+ #endif
356+ if (buflen == -1 ) {
357+ errfn = "listxattr" ;
358+ goto err_cleanup ;
359+ }
360+
361+ attrname = attrbuf ;
362+ while (buflen > 0 ) {
363+ #ifdef __linux__
364+ vallen = getxattr (f -> file_name , attrname , NULL , 0 );
365+ #elif defined (__APPLE__ )
366+ vallen = getxattr (f -> file_name , attrname , NULL , 0 , 0 , 0 );
367+ #else
368+ vallen = -1 ;
369+ #endif
370+ if (vallen == -1 ) {
371+ errfn = "getxattr" ;
372+ goto err_cleanup ;
373+ }
374+
375+ if (vallen > 0 ) {
376+ attrval = malloc (vallen );
377+ #ifdef __linux__
378+ vallen = getxattr (f -> file_name , attrname , attrval , vallen );
379+ #elif defined (__APPLE__ )
380+ vallen = getxattr (f -> file_name , attrname , attrval , vallen , 0 , 0 );
381+ #else
382+ vallen = -1 ;
383+ #endif
384+ free (attrval );
385+ if (vallen == -1 ) {
386+ errfn = "getxattr" ;
387+ goto err_cleanup ;
388+ }
389+ }
390+
391+ namelen = strlen (attrname ) + 1 ;
392+ buflen -= namelen ;
393+ attrname += namelen ;
394+ }
395+
396+ free (attrbuf );
397+
398+ if (!td -> o .disable_lat ) {
399+ struct fc_data * data = td -> io_ops_data ;
400+ uint64_t nsec ;
401+
402+ nsec = ntime_since_now (& start );
403+ add_clat_sample (td , data -> stat_ddir , nsec , 0 , NULL );
404+ }
405+
406+ return 0 ;
407+
408+ err_cleanup :
409+ free (attrbuf );
410+ err :
411+ e = errno ;
412+ snprintf (buf , sizeof (buf ), "%s(%s)" , errfn , f -> file_name );
413+ td_verror (td , e , buf );
414+ return 1 ;
415+ }
416+ #endif
417+
209418static int delete_file (struct thread_data * td , struct fio_file * f )
210419{
211420 struct timespec start ;
@@ -341,7 +550,7 @@ static struct ioengine_ops ioengine_filestat = {
341550 .open_file = stat_file ,
342551 .flags = FIO_SYNCIO | FIO_FAKEIO |
343552 FIO_NOSTATS | FIO_NOFILEHASH ,
344- .options = options ,
553+ .options = stat_options ,
345554 .option_struct_size = sizeof (struct filestat_options ),
346555};
347556
@@ -385,7 +594,7 @@ static struct ioengine_ops ioengine_dirstat = {
385594 .unlink_file = remove_dir ,
386595 .flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
387596 FIO_NOSTATS | FIO_NOFILEHASH ,
388- .options = options ,
597+ .options = stat_options ,
389598 .option_struct_size = sizeof (struct filestat_options ),
390599};
391600
@@ -404,6 +613,36 @@ static struct ioengine_ops ioengine_dirdelete = {
404613 FIO_NOSTATS | FIO_NOFILEHASH ,
405614};
406615
616+ #ifndef _WIN32
617+ static struct ioengine_ops ioengine_filesetxattr = {
618+ .name = "filesetxattr" ,
619+ .version = FIO_IOOPS_VERSION ,
620+ .init = init ,
621+ .cleanup = cleanup ,
622+ .queue = queue_io ,
623+ .invalidate = invalidate_do_nothing ,
624+ .get_file_size = generic_get_file_size ,
625+ .open_file = file_setxattr ,
626+ .flags = FIO_SYNCIO | FIO_FAKEIO |
627+ FIO_NOSTATS | FIO_NOFILEHASH ,
628+ .options = xattr_options ,
629+ .option_struct_size = sizeof (struct xattr_options ),
630+ };
631+
632+ static struct ioengine_ops ioengine_filelistxattr = {
633+ .name = "filelistxattr" ,
634+ .version = FIO_IOOPS_VERSION ,
635+ .init = init ,
636+ .invalidate = invalidate_do_nothing ,
637+ .cleanup = cleanup ,
638+ .queue = queue_io ,
639+ .get_file_size = generic_get_file_size ,
640+ .open_file = file_listxattr ,
641+ .flags = FIO_SYNCIO | FIO_FAKEIO |
642+ FIO_NOSTATS | FIO_NOFILEHASH ,
643+ };
644+ #endif
645+
407646static void fio_init fio_fileoperations_register (void )
408647{
409648 register_ioengine (& ioengine_filecreate );
@@ -412,6 +651,10 @@ static void fio_init fio_fileoperations_register(void)
412651 register_ioengine (& ioengine_dircreate );
413652 register_ioengine (& ioengine_dirstat );
414653 register_ioengine (& ioengine_dirdelete );
654+ #ifndef _WIN32
655+ register_ioengine (& ioengine_filesetxattr );
656+ register_ioengine (& ioengine_filelistxattr );
657+ #endif
415658}
416659
417660static void fio_exit fio_fileoperations_unregister (void )
@@ -422,4 +665,8 @@ static void fio_exit fio_fileoperations_unregister(void)
422665 unregister_ioengine (& ioengine_dircreate );
423666 unregister_ioengine (& ioengine_dirstat );
424667 unregister_ioengine (& ioengine_dirdelete );
668+ #ifndef _WIN32
669+ unregister_ioengine (& ioengine_filesetxattr );
670+ unregister_ioengine (& ioengine_filelistxattr );
671+ #endif
425672}
0 commit comments