1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32 
33 /** @file
34  *  @brief File system stress test.
35  *
36  *  This version of SGI fsstress has been modified to be single-threaded and to
37  *  work with the Reliance Edge POSIX-like API.
38  */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <limits.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <time.h>
45 
46 #include <redposix.h>
47 #include <redtests.h>
48 
49 #if FSSTRESS_SUPPORTED
50 
51     #include "redposixcompat.h"
52 
53     #include <redosserv.h>
54     #include <redutils.h>
55     #include <redmacs.h>
56     #include <redvolume.h>
57     #include <redgetopt.h>
58     #include <redtoolcmn.h>
59 
60     #if REDCONF_CHECKER == 1
61         #include <redcoreapi.h>
62     #endif
63 
64 
65 /*  Create POSIX types.  Use #define to avoid name conflicts in those
66  *  environments where the type names already exist.
67  */
68     #define off_t        int64_t
69     #define off64_t      off_t
70     #define ino_t        uint32_t
71     #define mode_t       uint16_t
72     #define __int64_t    int64_t
73 
74 
75 /** @brief Generate a random number.
76  *
77  *  @return A nonnegative random number.
78  */
79     #define random()    ( ( int ) ( RedRand32( NULL ) & 0x7FFFFFFF ) )
80 
81 
82 /** @brief Seed the random number generator.
83  */
84     #define srandom( seed )    RedRandSeed( seed )
85 
86 
87     #define _exit( status )    exit( status )
88     #define getpagesize()      4096U
89     #define getpid()           1
90 
91 
92 /** @brief Determine the maximum file size.
93  *
94  *  This is used for the MAXFSSIZE macro.
95  */
MaxFileSize(void)96     static uint64_t MaxFileSize( void )
97     {
98         REDSTATFS info;
99         int32_t iStatus;
100         REDSTATUS errnoSave = errno;
101         uint64_t ullMaxFileSize;
102 
103         iStatus = red_statvfs( "", &info );
104 
105         if( iStatus == 0 )
106         {
107             ullMaxFileSize = info.f_maxfsize;
108         }
109         else
110         {
111             /*  This function does not change errno.
112              */
113             errno = errnoSave;
114 
115             ullMaxFileSize = 0x7FFFFFFFU;
116         }
117 
118         return ullMaxFileSize;
119     }
120 
121 
122 /*-------------------------------------------------------------------
123  *   Simulated current working directory support
124  *  -------------------------------------------------------------------*/
125 
126 
127 /*  Forward declaration for red_chdir().
128  */
129     static int red_stat( const char * pszPath,
130                          REDSTAT * pStat );
131 
132 /*  The simulated CWD functions.
133  */
134     #undef chdir
135     #undef getcwd
136     #define chdir( path )          red_chdir( path )
137     #define getcwd( buf, size )    red_getcwd( buf, size )
138 
139 
140 /*  Redefine the path-based APIs to call MakeFullPath() on their arguments
141  *  since there is no CWD support in the red_*() APIs.
142  */
143     #undef open
144     #undef unlink
145     #undef mkdir
146     #undef rmdir
147     #undef rename
148     #undef link
149     #undef opendir
150     #define open( path, oflag )       red_open( MakeFullPath( path ), oflag )
151     #define unlink( path )            red_unlink( MakeFullPath( path ) )
152     #define mkdir( path )             red_mkdir( MakeFullPath( path ) )
153     #define rmdir( path )             red_rmdir( MakeFullPath( path ) )
154     #define rename( old, new )        red_rename( MakeFullPath( old ), MakeFullPath( new ) )
155     #define link( path, hardlink )    red_link( MakeFullPath( path ), MakeFullPath( hardlink ) )
156     #define opendir( path )           red_opendir( MakeFullPath( path ) )
157 
158     #define FSSTRESS_BUF_SIZE    1024U
159 
160 /*  Stores the simulated current working directory.
161  */
162     static char szLocalCwd[ FSSTRESS_BUF_SIZE ] = "/";
163 
164 
165 /** @brief Change the current working directory.
166  *
167  *  This function only supports a subset of what is possible with POSIX chdir().
168  *
169  *  @param pszPath  The new current working directory.
170  *
171  *  @return Upon successful completion, 0 shall be returned.  Otherwise, -1
172  *          shall be returned, and errno shall be set to indicate the error.
173  */
red_chdir(const char * pszPath)174     static int red_chdir( const char * pszPath )
175     {
176         uint32_t ulIdx;
177         int iErrno = 0;
178 
179         if( strcmp( pszPath, ".." ) == 0 )
180         {
181             uint32_t ulLastSlashIdx = 0U;
182 
183             /*  Chop off the last path separator and everything after it, so that
184              *  "/foo/bar/baz" becomes "/foo/bar", moving the CWD up one directory.
185              */
186             for( ulIdx = 0U; szLocalCwd[ ulIdx ] != '\0'; ulIdx++ )
187             {
188                 if( szLocalCwd[ ulIdx ] == '/' )
189                 {
190                     ulLastSlashIdx = ulIdx;
191                 }
192             }
193 
194             if( ulLastSlashIdx != 0U )
195             {
196                 szLocalCwd[ ulLastSlashIdx ] = '\0';
197             }
198         }
199         else
200         {
201             char szOldCwd[ FSSTRESS_BUF_SIZE ];
202 
203             /*  chdir() must have no effect on the CWD if it fails, so save the CWD
204              *  so we can revert it if necessary.
205              */
206             strcpy( szOldCwd, szLocalCwd );
207 
208             if( pszPath[ 0U ] == '/' )
209             {
210                 if( strlen( pszPath ) >= sizeof( szLocalCwd ) )
211                 {
212                     iErrno = RED_ENAMETOOLONG;
213                 }
214                 else
215                 {
216                     strcpy( szLocalCwd, pszPath );
217                 }
218             }
219             else
220             {
221                 ulIdx = strlen( szLocalCwd );
222 
223                 if( ( ulIdx + 1U + strlen( pszPath ) ) >= sizeof( szLocalCwd ) )
224                 {
225                     iErrno = RED_ENAMETOOLONG;
226                 }
227                 else
228                 {
229                     if( szLocalCwd[ 1U ] != '\0' )
230                     {
231                         szLocalCwd[ ulIdx ] = '/';
232                         ulIdx++;
233                     }
234 
235                     strcpy( &szLocalCwd[ ulIdx ], pszPath );
236                 }
237             }
238 
239             if( iErrno == 0 )
240             {
241                 REDSTAT s;
242                 int iStatus;
243 
244                 iStatus = red_stat( szLocalCwd, &s );
245 
246                 if( iStatus != 0 )
247                 {
248                     iErrno = errno;
249                 }
250                 else if( !S_ISDIR( s.st_mode ) )
251                 {
252                     iErrno = RED_ENOTDIR;
253                 }
254                 else
255                 {
256                     /*  No error, new CWD checks out.
257                      */
258                 }
259             }
260 
261             if( iErrno != 0 )
262             {
263                 strcpy( szLocalCwd, szOldCwd );
264             }
265         }
266 
267         if( iErrno != 0 )
268         {
269             errno = iErrno;
270         }
271 
272         return iErrno == 0 ? 0 : -1;
273     }
274 
275 
276 /** @brief Retrieve the current working directory.
277  *
278  *  @param pszBuf   On successful return, populated with the current working
279  *                  directory.  If NULL, memory will be allocated for the CWD
280  *                  and returned by this function.
281  *  @param nSize    The size of @p pszBuf.
282  *
283  *  @return On success, if @p pszBuf was non-NULL, returns @p pszBuf; if
284  *          @p pszBuf was NULL, returns an allocated buffer populated with the
285  *          CWD which must be freed by the caller.  On failure, returns NULL
286  *          and errno will be set.
287  */
red_getcwd(char * pszBuf,size_t nSize)288     static char * red_getcwd( char * pszBuf,
289                               size_t nSize )
290     {
291         char * pszRet;
292 
293         if( pszBuf == NULL )
294         {
295             pszRet = malloc( strlen( szLocalCwd ) + 1U );
296 
297             if( pszRet == NULL )
298             {
299                 errno = RED_ENOMEM;
300             }
301             else
302             {
303                 strcpy( pszRet, szLocalCwd );
304             }
305         }
306         else if( nSize < strlen( szLocalCwd ) + 1U )
307         {
308             errno = RED_ERANGE;
309             pszRet = NULL;
310         }
311         else
312         {
313             strcpy( pszBuf, szLocalCwd );
314             pszRet = pszBuf;
315         }
316 
317         return pszRet;
318     }
319 
320 
321 /** @brief Make a relative path into a fully qualified path.
322  *
323  *  @param pszName  The relative path.
324  *
325  *  @return On success, a pointer to a fully qualified path.  On error, NULL.
326  */
MakeFullPath(const char * pszName)327     static const char * MakeFullPath( const char * pszName )
328     {
329     #define         MAXVOLNAME    64U /* Enough for most configs. */
330         static char aszFullPath[ 2U ][ MAXVOLNAME + 1U + FSSTRESS_BUF_SIZE ];
331         static uint32_t ulWhich = 0U;
332 
333         char * pszFullPath = aszFullPath[ ulWhich ];
334         const char * pszVolume = gpRedVolConf->pszPathPrefix;
335         int32_t iLen;
336 
337         if( pszName[ 0U ] == '/' )
338         {
339             iLen = RedSNPrintf( pszFullPath, sizeof( aszFullPath[ 0U ] ), "%s%s", pszVolume, pszName );
340         }
341         else if( strcmp( pszName, "." ) == 0U )
342         {
343             iLen = RedSNPrintf( pszFullPath, sizeof( aszFullPath[ 0U ] ), "%s%s", pszVolume, szLocalCwd );
344         }
345         else if( ( szLocalCwd[ 0U ] == '/' ) && ( szLocalCwd[ 1U ] == '\0' ) )
346         {
347             iLen = RedSNPrintf( pszFullPath, sizeof( aszFullPath[ 0U ] ), "%s/%s", pszVolume, pszName );
348         }
349         else
350         {
351             iLen = RedSNPrintf( pszFullPath, sizeof( aszFullPath[ 0U ] ), "%s%s/%s", pszVolume, szLocalCwd, pszName );
352         }
353 
354         if( iLen == -1 )
355         {
356             /*  Insufficient path buffer space.
357              */
358             pszFullPath = NULL;
359         }
360         else
361         {
362             /*  Toggle between two full path arrays; a kluge to make rename() and
363              *  link() work correctly.
364              */
365             ulWhich ^= 1U;
366         }
367 
368         return pszFullPath;
369     }
370 
371 
372 /*-------------------------------------------------------------------
373  *   POSIX functions not implemented by the RED POSIX-like API
374  *  -------------------------------------------------------------------*/
375 
376     #define stat( p, s )          red_stat( p, s )
377     #define stat64( p, s )        stat( p, s )
378     #define lstat( p, s )         stat( p, s )
379     #define lstat64( p, s )       stat( p, s )
380     #define truncate( p, s )      red_truncate( p, s )
381     #define truncate64( p, s )    truncate( p, s )
382 
383 
384 /** @brief Get the status of a file or directory.
385  */
red_stat(const char * pszPath,REDSTAT * pStat)386     static int red_stat( const char * pszPath,
387                          REDSTAT * pStat )
388     {
389         int iFd;
390         int iRet;
391 
392         iFd = open( pszPath, O_RDONLY );
393         iRet = iFd;
394 
395         if( iFd != -1 )
396         {
397             iRet = fstat( iFd, pStat );
398 
399             ( void ) close( iFd );
400         }
401 
402         return iRet;
403     }
404 
405 
406 /** @brief Truncate a file to a specified length.
407  */
red_truncate(const char * pszPath,off_t llSize)408     static int red_truncate( const char * pszPath,
409                              off_t llSize )
410     {
411         int iFd;
412         int iRet;
413 
414         iFd = open( pszPath, O_WRONLY );
415         iRet = iFd;
416 
417         if( iFd != -1 )
418         {
419             iRet = ftruncate( iFd, llSize );
420 
421             ( void ) close( iFd );
422         }
423 
424         return iRet;
425     }
426 
427 
428 /*-------------------------------------------------------------------
429  *   Begin ported fsstress code
430  *  -------------------------------------------------------------------*/
431 
432 /* Stuff from xfscompat.h */
433 
434     #define MAXNAMELEN    ( REDCONF_NAME_MAX + 1U ) /* Assumed to include NUL */
435 
436     struct dioattr
437     {
438         int d_miniosz, d_maxiosz, d_mem;
439     };
440 
441     #define MIN( a, b )    ( ( a ) < ( b ) ? ( a ) : ( b ) )
442     #define MAX( a, b )    ( ( a ) > ( b ) ? ( a ) : ( b ) )
443 
444 /* End xfscompat.h */
445 
446 
447     typedef enum
448     {
449         OP_CREAT,
450         OP_FDATASYNC,
451         OP_FSYNC,
452         OP_GETDENTS,
453         OP_LINK,
454         OP_MKDIR,
455         OP_READ,
456         OP_RENAME,
457         OP_RMDIR,
458         OP_STAT,
459         OP_TRUNCATE,
460         OP_UNLINK,
461         OP_WRITE,
462         #if REDCONF_CHECKER == 1
463             OP_CHECK,
464         #endif
465         OP_LAST
466     } opty_t;
467 
468     typedef void (* opfnc_t) ( int,
469                                long );
470 
471     typedef struct opdesc
472     {
473         opty_t op;
474         const char * name;
475         opfnc_t func;
476         int freq;
477         int iswrite;
478     } opdesc_t;
479 
480     typedef struct fent
481     {
482         int id;
483         int parent;
484     } fent_t;
485 
486     typedef struct flist
487     {
488         int nfiles;
489         int nslots;
490         int tag;
491         fent_t * fents;
492     } flist_t;
493 
494     typedef struct pathname
495     {
496         int len;
497         char * path;
498     } pathname_t;
499 
500     #define FT_DIR             0
501     #define FT_DIRm            ( 1 << FT_DIR )
502     #define FT_REG             1
503     #define FT_REGm            ( 1 << FT_REG )
504     #define FT_SYM             2
505     #define FT_SYMm            ( 1 << FT_SYM )
506     #define FT_DEV             3
507     #define FT_DEVm            ( 1 << FT_DEV )
508     #define FT_RTF             4
509     #define FT_RTFm            ( 1 << FT_RTF )
510     #define FT_nft             5
511     #define FT_ANYm            ( ( 1 << FT_nft ) - 1 )
512     #define FT_REGFILE         ( FT_REGm | FT_RTFm )
513     #define FT_NOTDIR          ( FT_ANYm & ~FT_DIRm )
514 
515     #define FLIST_SLOT_INCR    16
516     #define NDCACHE            64
517 
518     #define MAXFSIZE           MaxFileSize()
519 
520     static void creat_f( int opno,
521                          long r );
522     static void fdatasync_f( int opno,
523                              long r );
524     static void fsync_f( int opno,
525                          long r );
526     static void getdents_f( int opno,
527                             long r );
528     static void link_f( int opno,
529                         long r );
530     static void mkdir_f( int opno,
531                          long r );
532     static void read_f( int opno,
533                         long r );
534     static void rename_f( int opno,
535                           long r );
536     static void rmdir_f( int opno,
537                          long r );
538     static void stat_f( int opno,
539                         long r );
540     static void truncate_f( int opno,
541                             long r );
542     static void unlink_f( int opno,
543                           long r );
544     static void write_f( int opno,
545                          long r );
546     #if REDCONF_CHECKER == 1
547         static void check_f( int opno,
548                              long r );
549     #endif
550 
551     static opdesc_t ops[] =
552     {
553         { OP_CREAT,     "creat",     creat_f,     4, 1 },
554         { OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
555         { OP_FSYNC,     "fsync",     fsync_f,     1, 1 },
556         { OP_GETDENTS,  "getdents",  getdents_f,  1, 0 },
557         { OP_LINK,      "link",      link_f,      1, 1 },
558         { OP_MKDIR,     "mkdir",     mkdir_f,     2, 1 },
559         { OP_READ,      "read",      read_f,      1, 0 },
560         { OP_RENAME,    "rename",    rename_f,    2, 1 },
561         { OP_RMDIR,     "rmdir",     rmdir_f,     1, 1 },
562         { OP_STAT,      "stat",      stat_f,      1, 0 },
563         { OP_TRUNCATE,  "truncate",  truncate_f,  2, 1 },
564         { OP_UNLINK,    "unlink",    unlink_f,    1, 1 },
565         { OP_WRITE,     "write",     write_f,     4, 1 },
566         #if REDCONF_CHECKER == 1
567         { OP_CHECK,     "check",     check_f,     1, 1 },
568         #endif
569     }, * ops_end;
570 
571     static flist_t flist[ FT_nft ] =
572     {
573         { 0, 0, 'd', NULL },
574         { 0, 0, 'f', NULL },
575         { 0, 0, 'l', NULL },
576         { 0, 0, 'c', NULL },
577         { 0, 0, 'r', NULL },
578     };
579 
580     static int dcache[ NDCACHE ];
581     static opty_t * freq_table;
582     static int freq_table_size;
583     static char * homedir;
584     static int * ilist;
585     static int ilistlen;
586     static off64_t maxfsize;
587     static int namerand;
588     static int nameseq;
589     static int nops;
590     static int operations = 1;
591     static int procid;
592     static int rtpct;
593     static unsigned long seed = 0;
594     static ino_t top_ino;
595     static int verbose = 0;
596 
597     static int delete_tree( const char * path );
598     static void add_to_flist( int fd,
599                               int it,
600                               int parent );
601     static void append_pathname( pathname_t * name,
602                                  const char * str );
603     static void check_cwd( void );
604     static int creat_path( pathname_t * name,
605                            mode_t mode );
606     static void dcache_enter( int dirid,
607                               int slot );
608     static void dcache_init( void );
609     static fent_t * dcache_lookup( int dirid );
610     static void dcache_purge( int dirid );
611     static void del_from_flist( int ft,
612                                 int slot );
613     static void doproc( void );
614     static void fent_to_name( pathname_t * name,
615                               flist_t * flp,
616                               fent_t * fep );
617     static void fix_parent( int oldid,
618                             int newid );
619     static void free_pathname( pathname_t * name );
620     static int generate_fname( fent_t * fep,
621                                int ft,
622                                pathname_t * name,
623                                int * idp,
624                                int * v );
625     static int get_fname( int which,
626                           long r,
627                           pathname_t * name,
628                           flist_t ** flpp,
629                           fent_t ** fepp,
630                           int * v );
631     static void init_pathname( pathname_t * name );
632     static int link_path( pathname_t * name1,
633                           pathname_t * name2 );
634     static int lstat64_path( pathname_t * name,
635                              REDSTAT * sbuf );
636     static void make_freq_table( void );
637     static int mkdir_path( pathname_t * name,
638                            mode_t mode );
639     static void namerandpad( int id,
640                              char * buf,
641                              int len );
642     static int open_path( pathname_t * name,
643                           int oflag );
644     static DIR * opendir_path( pathname_t * name );
645     static int rename_path( pathname_t * name1,
646                             pathname_t * name2 );
647     static int rmdir_path( pathname_t * name );
648     static void separate_pathname( pathname_t * name,
649                                    char * buf,
650                                    pathname_t * newname );
651     static int stat64_path( pathname_t * name,
652                             REDSTAT * sbuf );
653     static int truncate64_path( pathname_t * name,
654                                 off64_t length );
655     static int unlink_path( pathname_t * name );
656     static void usage( const char * progname );
657 
658 
659 /** @brief Parse parameters for fsstress.
660  *
661  *  @param argc         The number of arguments from main().
662  *  @param argv         The vector of arguments from main().
663  *  @param pParam       Populated with the fsstress parameters.
664  *  @param pbVolNum     If non-NULL, populated with the volume number.
665  *  @param ppszDevice   If non-NULL, populated with the device name argument or
666  *                      NULL if no device argument is provided.
667  *
668  *  @return The result of parsing the parameters.
669  */
FsstressParseParams(int argc,char * argv[],FSSTRESSPARAM * pParam,uint8_t * pbVolNum,const char ** ppszDevice)670     PARAMSTATUS FsstressParseParams( int argc,
671                                      char * argv[],
672                                      FSSTRESSPARAM * pParam,
673                                      uint8_t * pbVolNum,
674                                      const char ** ppszDevice )
675     {
676         int c;
677         uint8_t bVolNum;
678         const REDOPTION aLongopts[] =
679         {
680             { "no-cleanup", red_no_argument,       NULL, 'c' },
681             { "loops",      red_required_argument, NULL, 'l' },
682             { "nops",       red_required_argument, NULL, 'n' },
683             { "namepad",    red_no_argument,       NULL, 'r' },
684             { "seed",       red_required_argument, NULL, 's' },
685             { "verbose",    red_no_argument,       NULL, 'v' },
686             { "dev",        red_required_argument, NULL, 'D' },
687             { "help",       red_no_argument,       NULL, 'H' },
688             { NULL }
689         };
690 
691         /*  If run without parameters, treat as a help request.
692          */
693         if( argc <= 1 )
694         {
695             goto Help;
696         }
697 
698         /*  Assume no device argument to start with.
699          */
700         if( ppszDevice != NULL )
701         {
702             *ppszDevice = NULL;
703         }
704 
705         /*  Set default parameters.
706          */
707         FsstressDefaultParams( pParam );
708 
709         while( ( c = RedGetoptLong( argc, argv, "cl:n:rs:vD:H", aLongopts, NULL ) ) != -1 )
710         {
711             switch( c )
712             {
713                 case 'c': /* --no-cleanup */
714                     pParam->fNoCleanup = true;
715                     break;
716 
717                 case 'l': /* --loops */
718                     pParam->ulLoops = RedAtoI( red_optarg );
719                     break;
720 
721                 case 'n': /* --nops */
722                     pParam->ulNops = RedAtoI( red_optarg );
723                     break;
724 
725                 case 'r': /* --namepad */
726                     pParam->fNamePad = true;
727                     break;
728 
729                 case 's': /* --seed */
730                     pParam->ulSeed = RedAtoI( red_optarg );
731                     break;
732 
733                 case 'v': /* --verbose */
734                     pParam->fVerbose = true;
735                     break;
736 
737                 case 'D': /* --dev */
738 
739                     if( ppszDevice != NULL )
740                     {
741                         *ppszDevice = red_optarg;
742                     }
743 
744                     break;
745 
746                 case 'H': /* --help */
747                     goto Help;
748 
749                 case '?': /* Unknown or ambiguous option */
750                 case ':': /* Option missing required argument */
751                 default:
752                     goto BadOpt;
753             }
754         }
755 
756         /*  RedGetoptLong() has permuted argv to move all non-option arguments to
757          *  the end.  We expect to find a volume identifier.
758          */
759         if( red_optind >= argc )
760         {
761             RedPrintf( "Missing volume argument\n" );
762             goto BadOpt;
763         }
764 
765         bVolNum = RedFindVolumeNumber( argv[ red_optind ] );
766 
767         if( bVolNum == REDCONF_VOLUME_COUNT )
768         {
769             RedPrintf( "Error: \"%s\" is not a valid volume identifier.\n", argv[ red_optind ] );
770             goto BadOpt;
771         }
772 
773         if( pbVolNum != NULL )
774         {
775             *pbVolNum = bVolNum;
776         }
777 
778         red_optind++; /* Move past volume parameter. */
779 
780         if( red_optind < argc )
781         {
782             int32_t ii;
783 
784             for( ii = red_optind; ii < argc; ii++ )
785             {
786                 RedPrintf( "Error: Unexpected command-line argument \"%s\".\n", argv[ ii ] );
787             }
788 
789             goto BadOpt;
790         }
791 
792         return PARAMSTATUS_OK;
793 
794 BadOpt:
795 
796         RedPrintf( "%s - invalid parameters\n", argv[ 0U ] );
797         usage( argv[ 0U ] );
798         return PARAMSTATUS_BAD;
799 
800 Help:
801 
802         usage( argv[ 0U ] );
803         return PARAMSTATUS_HELP;
804     }
805 
806 
807 /** @brief Set default fsstress parameters.
808  *
809  *  @param pParam   Populated with the default fsstress parameters.
810  */
FsstressDefaultParams(FSSTRESSPARAM * pParam)811     void FsstressDefaultParams( FSSTRESSPARAM * pParam )
812     {
813         RedMemSet( pParam, 0U, sizeof( *pParam ) );
814         pParam->ulLoops = 1U;
815         pParam->ulNops = 10000U;
816     }
817 
818 
819 /** @brief Start fsstress.
820  *
821  *  @param pParam   fsstress parameters, either from FsstressParseParams() or
822  *                  constructed programatically.
823  *
824  *  @return Zero on success, otherwise nonzero.
825  */
FsstressStart(const FSSTRESSPARAM * pParam)826     int FsstressStart( const FSSTRESSPARAM * pParam )
827     {
828         char buf[ 10 ];
829         int fd;
830         int i;
831         int cleanup;
832         int loops;
833         int loopcntr = 1;
834 
835         nops = sizeof( ops ) / sizeof( ops[ 0 ] );
836         ops_end = &ops[ nops ];
837 
838         /*  Copy the already-parsed parameters into the traditional variables.
839          */
840         cleanup = pParam->fNoCleanup ? 1 : 0;
841         loops = pParam->ulLoops;
842         operations = pParam->ulNops;
843         namerand = pParam->fNamePad ? 1 : 0;
844         seed = pParam->ulSeed;
845         verbose = pParam->fVerbose ? 1 : 0;
846 
847         make_freq_table();
848 
849         while( ( loopcntr <= loops ) || ( loops == 0 ) )
850         {
851             RedSNPrintf( buf, sizeof( buf ), "fss%x", getpid() );
852             fd = creat( buf, 0666 );
853             maxfsize = ( off64_t ) MAXFSIZE;
854             dcache_init();
855 
856             if( !seed )
857             {
858                 seed = ( unsigned long ) RedOsClockGetTime();
859                 RedPrintf( "seed = %ld\n", seed );
860             }
861 
862             close( fd );
863             unlink( buf );
864             procid = 0;
865             doproc();
866 
867             if( cleanup == 0 )
868             {
869                 delete_tree( "/" );
870 
871                 for( i = 0; i < FT_nft; i++ )
872                 {
873                     flist[ i ].nslots = 0;
874                     flist[ i ].nfiles = 0;
875                     free( flist[ i ].fents );
876                     flist[ i ].fents = NULL;
877                 }
878             }
879 
880             loopcntr++;
881         }
882 
883         return 0;
884     }
885 
delete_tree(const char * path)886     static int delete_tree( const char * path )
887     {
888         REDSTAT sb;
889         DIR * dp;
890         REDDIRENT * dep;
891         char * childpath;
892         size_t len;
893         int e;
894 
895         e = stat( path, &sb );
896 
897         if( e )
898         {
899             return errno;
900         }
901 
902         if( !S_ISDIR( sb.st_mode ) )
903         {
904             return unlink( path ) ? errno : 0;
905         }
906 
907         dp = opendir( path );
908 
909         if( dp == NULL )
910         {
911             return errno;
912         }
913 
914         while( ( dep = readdir( dp ) ) != NULL )
915         {
916             len = strlen( path ) + 1 + strlen( dep->d_name ) + 1;
917             childpath = malloc( len );
918 
919             strcpy( childpath, path );
920 
921             if( childpath[ strlen( childpath ) - 1 ] != '/' )
922             {
923                 strcat( childpath, "/" );
924             }
925 
926             strcat( childpath, dep->d_name );
927 
928             e = delete_tree( childpath );
929 
930             free( childpath );
931 
932             if( e )
933             {
934                 break;
935             }
936         }
937 
938         if( ( e == 0 ) && ( strcmp( path, "/" ) != 0 ) )
939         {
940             e = rmdir( path ) ? errno : 0;
941         }
942 
943         closedir( dp );
944         return e;
945     }
946 
add_to_flist(int ft,int id,int parent)947     static void add_to_flist( int ft,
948                               int id,
949                               int parent )
950     {
951         fent_t * fep;
952         flist_t * ftp;
953 
954         ftp = &flist[ ft ];
955 
956         if( ftp->nfiles == ftp->nslots )
957         {
958             ftp->nslots += FLIST_SLOT_INCR;
959             ftp->fents = realloc( ftp->fents, ftp->nslots * sizeof( fent_t ) );
960         }
961 
962         fep = &ftp->fents[ ftp->nfiles++ ];
963         fep->id = id;
964         fep->parent = parent;
965     }
966 
append_pathname(pathname_t * name,const char * str)967     static void append_pathname( pathname_t * name,
968                                  const char * str )
969     {
970         int len;
971 
972         len = strlen( str );
973         #ifdef DEBUG
974             if( len && ( *str == '/' ) && ( name->len == 0 ) )
975             {
976                 RedPrintf( "fsstress: append_pathname failure\n" );
977                 chdir( homedir );
978                 abort();
979             }
980         #endif
981         name->path = realloc( name->path, name->len + 1 + len );
982         strcpy( &name->path[ name->len ], str );
983         name->len += len;
984     }
985 
check_cwd(void)986     static void check_cwd( void )
987     {
988         #ifdef DEBUG
989             REDSTAT statbuf;
990 
991             if( ( stat64( ".", &statbuf ) == 0 ) && ( statbuf.st_ino == top_ino ) )
992             {
993                 return;
994             }
995 
996             chdir( homedir );
997             RedPrintf( "fsstress: check_cwd failure\n" );
998             abort();
999         #endif /* ifdef DEBUG */
1000     }
1001 
creat_path(pathname_t * name,mode_t mode)1002     static int creat_path( pathname_t * name,
1003                            mode_t mode )
1004     {
1005         char buf[ MAXNAMELEN ];
1006         pathname_t newname;
1007         int rval;
1008 
1009         rval = creat( name->path, mode );
1010 
1011         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1012         {
1013             return rval;
1014         }
1015 
1016         separate_pathname( name, buf, &newname );
1017 
1018         if( chdir( buf ) == 0 )
1019         {
1020             rval = creat_path( &newname, mode );
1021             chdir( ".." );
1022         }
1023 
1024         free_pathname( &newname );
1025         return rval;
1026     }
1027 
dcache_enter(int dirid,int slot)1028     static void dcache_enter( int dirid,
1029                               int slot )
1030     {
1031         dcache[ dirid % NDCACHE ] = slot;
1032     }
1033 
dcache_init(void)1034     static void dcache_init( void )
1035     {
1036         int i;
1037 
1038         for( i = 0; i < NDCACHE; i++ )
1039         {
1040             dcache[ i ] = -1;
1041         }
1042     }
1043 
dcache_lookup(int dirid)1044     static fent_t * dcache_lookup( int dirid )
1045     {
1046         fent_t * fep;
1047         int i;
1048 
1049         i = dcache[ dirid % NDCACHE ];
1050 
1051         if( ( i >= 0 ) && ( ( fep = &flist[ FT_DIR ].fents[ i ] )->id == dirid ) )
1052         {
1053             return fep;
1054         }
1055 
1056         return NULL;
1057     }
1058 
dcache_purge(int dirid)1059     static void dcache_purge( int dirid )
1060     {
1061         int * dcp;
1062 
1063         dcp = &dcache[ dirid % NDCACHE ];
1064 
1065         if( ( *dcp >= 0 ) && ( flist[ FT_DIR ].fents[ *dcp ].id == dirid ) )
1066         {
1067             *dcp = -1;
1068         }
1069     }
1070 
del_from_flist(int ft,int slot)1071     static void del_from_flist( int ft,
1072                                 int slot )
1073     {
1074         flist_t * ftp;
1075 
1076         ftp = &flist[ ft ];
1077 
1078         if( ft == FT_DIR )
1079         {
1080             dcache_purge( ftp->fents[ slot ].id );
1081         }
1082 
1083         if( slot != ftp->nfiles - 1 )
1084         {
1085             if( ft == FT_DIR )
1086             {
1087                 dcache_purge( ftp->fents[ ftp->nfiles - 1 ].id );
1088             }
1089 
1090             ftp->fents[ slot ] = ftp->fents[ --ftp->nfiles ];
1091         }
1092         else
1093         {
1094             ftp->nfiles--;
1095         }
1096     }
1097 
dirid_to_fent(int dirid)1098     static fent_t * dirid_to_fent( int dirid )
1099     {
1100         fent_t * efep;
1101         fent_t * fep;
1102         flist_t * flp;
1103 
1104         if( ( fep = dcache_lookup( dirid ) ) )
1105         {
1106             return fep;
1107         }
1108 
1109         flp = &flist[ FT_DIR ];
1110 
1111         for( fep = flp->fents, efep = &fep[ flp->nfiles ]; fep < efep; fep++ )
1112         {
1113             if( fep->id == dirid )
1114             {
1115                 dcache_enter( dirid, ( int ) ( fep - flp->fents ) );
1116                 return fep;
1117             }
1118         }
1119 
1120         return NULL;
1121     }
1122 
doproc(void)1123     static void doproc( void )
1124     {
1125         REDSTAT statbuf;
1126         char buf[ 10 ];
1127         int opno;
1128         opdesc_t * p;
1129 
1130         RedSNPrintf( buf, sizeof( buf ), "p%x", procid );
1131         ( void ) mkdir( buf );
1132 
1133         if( ( chdir( buf ) < 0 ) || ( stat64( ".", &statbuf ) < 0 ) )
1134         {
1135             perror( buf );
1136             _exit( 1 );
1137         }
1138 
1139         top_ino = statbuf.st_ino;
1140         homedir = getcwd( NULL, 0 );
1141         seed += procid;
1142         srandom( seed );
1143 
1144         if( namerand )
1145         {
1146             namerand = random();
1147         }
1148 
1149         for( opno = 0; opno < operations; opno++ )
1150         {
1151             p = &ops[ freq_table[ random() % freq_table_size ] ];
1152 
1153             if( ( unsigned long ) p->func < 4096 )
1154             {
1155                 abort();
1156             }
1157 
1158             p->func( opno, random() );
1159         }
1160 
1161         free( homedir );
1162     }
1163 
fent_to_name(pathname_t * name,flist_t * flp,fent_t * fep)1164     static void fent_to_name( pathname_t * name,
1165                               flist_t * flp,
1166                               fent_t * fep )
1167     {
1168         char buf[ MAXNAMELEN ];
1169         int i;
1170         fent_t * pfep;
1171 
1172         if( fep == NULL )
1173         {
1174             return;
1175         }
1176 
1177         if( fep->parent != -1 )
1178         {
1179             pfep = dirid_to_fent( fep->parent );
1180             fent_to_name( name, &flist[ FT_DIR ], pfep );
1181             append_pathname( name, "/" );
1182         }
1183 
1184         i = RedSNPrintf( buf, sizeof( buf ), "%c%x", flp->tag, fep->id );
1185         namerandpad( fep->id, buf, i );
1186         append_pathname( name, buf );
1187     }
1188 
fix_parent(int oldid,int newid)1189     static void fix_parent( int oldid,
1190                             int newid )
1191     {
1192         fent_t * fep;
1193         flist_t * flp;
1194         int i;
1195         int j;
1196 
1197         for( i = 0, flp = flist; i < FT_nft; i++, flp++ )
1198         {
1199             for( j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++ )
1200             {
1201                 if( fep->parent == oldid )
1202                 {
1203                     fep->parent = newid;
1204                 }
1205             }
1206         }
1207     }
1208 
free_pathname(pathname_t * name)1209     static void free_pathname( pathname_t * name )
1210     {
1211         if( name->path )
1212         {
1213             free( name->path );
1214             name->path = NULL;
1215             name->len = 0;
1216         }
1217     }
1218 
generate_fname(fent_t * fep,int ft,pathname_t * name,int * idp,int * v)1219     static int generate_fname( fent_t * fep,
1220                                int ft,
1221                                pathname_t * name,
1222                                int * idp,
1223                                int * v )
1224     {
1225         char buf[ MAXNAMELEN ];
1226         flist_t * flp;
1227         int id;
1228         int j;
1229         int len;
1230 
1231         flp = &flist[ ft ];
1232         len = RedSNPrintf( buf, sizeof( buf ), "%c%x", flp->tag, id = nameseq++ );
1233         namerandpad( id, buf, len );
1234 
1235         if( fep )
1236         {
1237             fent_to_name( name, &flist[ FT_DIR ], fep );
1238             append_pathname( name, "/" );
1239         }
1240 
1241         append_pathname( name, buf );
1242         *idp = id;
1243         *v = verbose;
1244 
1245         for( j = 0; !*v && j < ilistlen; j++ )
1246         {
1247             if( ilist[ j ] == id )
1248             {
1249                 *v = 1;
1250                 break;
1251             }
1252         }
1253 
1254         return 1;
1255     }
1256 
get_fname(int which,long r,pathname_t * name,flist_t ** flpp,fent_t ** fepp,int * v)1257     static int get_fname( int which,
1258                           long r,
1259                           pathname_t * name,
1260                           flist_t ** flpp,
1261                           fent_t ** fepp,
1262                           int * v )
1263     {
1264         int c;
1265         fent_t * fep;
1266         flist_t * flp;
1267         int i;
1268         int j;
1269         int x;
1270 
1271         for( i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++ )
1272         {
1273             if( which & ( 1 << i ) )
1274             {
1275                 c += flp->nfiles;
1276             }
1277         }
1278 
1279         if( c == 0 )
1280         {
1281             if( flpp )
1282             {
1283                 *flpp = NULL;
1284             }
1285 
1286             if( fepp )
1287             {
1288                 *fepp = NULL;
1289             }
1290 
1291             *v = verbose;
1292             return 0;
1293         }
1294 
1295         x = ( int ) ( r % c );
1296 
1297         for( i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++ )
1298         {
1299             if( which & ( 1 << i ) )
1300             {
1301                 if( x < c + flp->nfiles )
1302                 {
1303                     fep = &flp->fents[ x - c ];
1304 
1305                     if( name )
1306                     {
1307                         fent_to_name( name, flp, fep );
1308                     }
1309 
1310                     if( flpp )
1311                     {
1312                         *flpp = flp;
1313                     }
1314 
1315                     if( fepp )
1316                     {
1317                         *fepp = fep;
1318                     }
1319 
1320                     *v = verbose;
1321 
1322                     for( j = 0; !*v && j < ilistlen; j++ )
1323                     {
1324                         if( ilist[ j ] == fep->id )
1325                         {
1326                             *v = 1;
1327                             break;
1328                         }
1329                     }
1330 
1331                     return 1;
1332                 }
1333 
1334                 c += flp->nfiles;
1335             }
1336         }
1337 
1338         #ifdef DEBUG
1339             RedPrintf( "fsstress: get_fname failure\n" );
1340             abort();
1341         #endif
1342         return -1;
1343     }
1344 
init_pathname(pathname_t * name)1345     static void init_pathname( pathname_t * name )
1346     {
1347         name->len = 0;
1348         name->path = NULL;
1349     }
1350 
link_path(pathname_t * name1,pathname_t * name2)1351     static int link_path( pathname_t * name1,
1352                           pathname_t * name2 )
1353     {
1354         char buf1[ MAXNAMELEN ];
1355         char buf2[ MAXNAMELEN ];
1356         int down1;
1357         pathname_t newname1;
1358         pathname_t newname2;
1359         int rval;
1360 
1361         rval = link( name1->path, name2->path );
1362 
1363         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1364         {
1365             return rval;
1366         }
1367 
1368         separate_pathname( name1, buf1, &newname1 );
1369         separate_pathname( name2, buf2, &newname2 );
1370 
1371         if( strcmp( buf1, buf2 ) == 0 )
1372         {
1373             if( chdir( buf1 ) == 0 )
1374             {
1375                 rval = link_path( &newname1, &newname2 );
1376                 chdir( ".." );
1377             }
1378         }
1379         else
1380         {
1381             if( strcmp( buf1, ".." ) == 0 )
1382             {
1383                 down1 = 0;
1384             }
1385             else if( strcmp( buf2, ".." ) == 0 )
1386             {
1387                 down1 = 1;
1388             }
1389             else if( strlen( buf1 ) == 0 )
1390             {
1391                 down1 = 0;
1392             }
1393             else if( strlen( buf2 ) == 0 )
1394             {
1395                 down1 = 1;
1396             }
1397             else
1398             {
1399                 down1 = MAX( newname1.len, 3 + name2->len ) <=
1400                         MAX( 3 + name1->len, newname2.len );
1401             }
1402 
1403             if( down1 )
1404             {
1405                 free_pathname( &newname2 );
1406                 append_pathname( &newname2, "../" );
1407                 append_pathname( &newname2, name2->path );
1408 
1409                 if( chdir( buf1 ) == 0 )
1410                 {
1411                     rval = link_path( &newname1, &newname2 );
1412                     chdir( ".." );
1413                 }
1414             }
1415             else
1416             {
1417                 free_pathname( &newname1 );
1418                 append_pathname( &newname1, "../" );
1419                 append_pathname( &newname1, name1->path );
1420 
1421                 if( chdir( buf2 ) == 0 )
1422                 {
1423                     rval = link_path( &newname1, &newname2 );
1424                     chdir( ".." );
1425                 }
1426             }
1427         }
1428 
1429         free_pathname( &newname1 );
1430         free_pathname( &newname2 );
1431         return rval;
1432     }
1433 
lstat64_path(pathname_t * name,REDSTAT * sbuf)1434     static int lstat64_path( pathname_t * name,
1435                              REDSTAT * sbuf )
1436     {
1437         char buf[ MAXNAMELEN ];
1438         pathname_t newname;
1439         int rval;
1440 
1441         rval = lstat64( name->path, sbuf );
1442 
1443         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1444         {
1445             return rval;
1446         }
1447 
1448         separate_pathname( name, buf, &newname );
1449 
1450         if( chdir( buf ) == 0 )
1451         {
1452             rval = lstat64_path( &newname, sbuf );
1453             chdir( ".." );
1454         }
1455 
1456         free_pathname( &newname );
1457         return rval;
1458     }
1459 
make_freq_table(void)1460     static void make_freq_table( void )
1461     {
1462         int f;
1463         int i;
1464         opdesc_t * p;
1465 
1466         for( p = ops, f = 0; p < ops_end; p++ )
1467         {
1468             f += p->freq;
1469         }
1470 
1471         freq_table = malloc( f * sizeof( *freq_table ) );
1472         freq_table_size = f;
1473 
1474         for( p = ops, i = 0; p < ops_end; p++ )
1475         {
1476             for( f = 0; f < p->freq; f++, i++ )
1477             {
1478                 freq_table[ i ] = p->op;
1479             }
1480         }
1481     }
1482 
mkdir_path(pathname_t * name,mode_t mode)1483     static int mkdir_path( pathname_t * name,
1484                            mode_t mode )
1485     {
1486         char buf[ MAXNAMELEN ];
1487         pathname_t newname;
1488         int rval;
1489 
1490         rval = mkdir( name->path );
1491 
1492         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1493         {
1494             return rval;
1495         }
1496 
1497         separate_pathname( name, buf, &newname );
1498 
1499         if( chdir( buf ) == 0 )
1500         {
1501             rval = mkdir_path( &newname, mode );
1502             chdir( ".." );
1503         }
1504 
1505         free_pathname( &newname );
1506         return rval;
1507     }
1508 
namerandpad(int id,char * buf,int len)1509     static void namerandpad( int id,
1510                              char * buf,
1511                              int len )
1512     {
1513         int bucket;
1514         static int buckets[ 8 ] = { 0 };
1515         static int bucket_count = 0;
1516         int bucket_value;
1517         int i;
1518         int padlen;
1519         int padmod;
1520 
1521         if( namerand == 0 )
1522         {
1523             return;
1524         }
1525 
1526         /*  buckets[] used to be a statically initialized array with the following
1527          *  initializer: { 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 }
1528          *
1529          *  The problem is that with Reliance Edge, the maximum name length might be
1530          *  less than 128.  So the below code populates buckets[] in a similar
1531          *  fashion but avoids name lengths longer than the maximum.  For example,
1532          *  if the max name is 20, the resulting array is { 2, 4, 8, 16, 20 }.
1533          */
1534         if( !bucket_count )
1535         {
1536             bucket_count = sizeof( buckets ) / sizeof( buckets[ 0 ] );
1537             bucket_value = 2;
1538 
1539             for( i = 0; i < bucket_count; i++ )
1540             {
1541                 if( ( bucket_value > 128 ) || ( bucket_value >= ( int ) MAXNAMELEN - 1 ) )
1542                 {
1543                     break;
1544                 }
1545 
1546                 buckets[ i ] = bucket_value;
1547                 bucket_value *= 2;
1548             }
1549 
1550             if( i < bucket_count )
1551             {
1552                 buckets[ i ] = MAXNAMELEN - 1;
1553                 i++;
1554             }
1555 
1556             bucket_count = i;
1557         }
1558 
1559         bucket = ( id ^ namerand ) % bucket_count;
1560         padmod = buckets[ bucket ] + 1 - len;
1561 
1562         if( padmod <= 0 )
1563         {
1564             return;
1565         }
1566 
1567         padlen = ( id ^ namerand ) % padmod;
1568 
1569         if( padlen )
1570         {
1571             memset( &buf[ len ], 'X', padlen );
1572             buf[ len + padlen ] = '\0';
1573         }
1574     }
1575 
open_path(pathname_t * name,int oflag)1576     static int open_path( pathname_t * name,
1577                           int oflag )
1578     {
1579         char buf[ MAXNAMELEN ];
1580         pathname_t newname;
1581         int rval;
1582 
1583         rval = open( name->path, oflag );
1584 
1585         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1586         {
1587             return rval;
1588         }
1589 
1590         separate_pathname( name, buf, &newname );
1591 
1592         if( chdir( buf ) == 0 )
1593         {
1594             rval = open_path( &newname, oflag );
1595             chdir( ".." );
1596         }
1597 
1598         free_pathname( &newname );
1599         return rval;
1600     }
1601 
opendir_path(pathname_t * name)1602     static DIR * opendir_path( pathname_t * name )
1603     {
1604         char buf[ MAXNAMELEN ];
1605         pathname_t newname;
1606         DIR * rval;
1607 
1608         rval = opendir( name->path );
1609 
1610         if( rval || ( errno != RED_ENAMETOOLONG ) )
1611         {
1612             return rval;
1613         }
1614 
1615         separate_pathname( name, buf, &newname );
1616 
1617         if( chdir( buf ) == 0 )
1618         {
1619             rval = opendir_path( &newname );
1620             chdir( ".." );
1621         }
1622 
1623         free_pathname( &newname );
1624         return rval;
1625     }
1626 
rename_path(pathname_t * name1,pathname_t * name2)1627     static int rename_path( pathname_t * name1,
1628                             pathname_t * name2 )
1629     {
1630         char buf1[ MAXNAMELEN ];
1631         char buf2[ MAXNAMELEN ];
1632         int down1;
1633         pathname_t newname1;
1634         pathname_t newname2;
1635         int rval;
1636 
1637         rval = rename( name1->path, name2->path );
1638 
1639         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1640         {
1641             return rval;
1642         }
1643 
1644         separate_pathname( name1, buf1, &newname1 );
1645         separate_pathname( name2, buf2, &newname2 );
1646 
1647         if( strcmp( buf1, buf2 ) == 0 )
1648         {
1649             if( chdir( buf1 ) == 0 )
1650             {
1651                 rval = rename_path( &newname1, &newname2 );
1652                 chdir( ".." );
1653             }
1654         }
1655         else
1656         {
1657             if( strcmp( buf1, ".." ) == 0 )
1658             {
1659                 down1 = 0;
1660             }
1661             else if( strcmp( buf2, ".." ) == 0 )
1662             {
1663                 down1 = 1;
1664             }
1665             else if( strlen( buf1 ) == 0 )
1666             {
1667                 down1 = 0;
1668             }
1669             else if( strlen( buf2 ) == 0 )
1670             {
1671                 down1 = 1;
1672             }
1673             else
1674             {
1675                 down1 = MAX( newname1.len, 3 + name2->len ) <=
1676                         MAX( 3 + name1->len, newname2.len );
1677             }
1678 
1679             if( down1 )
1680             {
1681                 free_pathname( &newname2 );
1682                 append_pathname( &newname2, "../" );
1683                 append_pathname( &newname2, name2->path );
1684 
1685                 if( chdir( buf1 ) == 0 )
1686                 {
1687                     rval = rename_path( &newname1, &newname2 );
1688                     chdir( ".." );
1689                 }
1690             }
1691             else
1692             {
1693                 free_pathname( &newname1 );
1694                 append_pathname( &newname1, "../" );
1695                 append_pathname( &newname1, name1->path );
1696 
1697                 if( chdir( buf2 ) == 0 )
1698                 {
1699                     rval = rename_path( &newname1, &newname2 );
1700                     chdir( ".." );
1701                 }
1702             }
1703         }
1704 
1705         free_pathname( &newname1 );
1706         free_pathname( &newname2 );
1707         return rval;
1708     }
1709 
rmdir_path(pathname_t * name)1710     static int rmdir_path( pathname_t * name )
1711     {
1712         char buf[ MAXNAMELEN ];
1713         pathname_t newname;
1714         int rval;
1715 
1716         rval = rmdir( name->path );
1717 
1718         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1719         {
1720             return rval;
1721         }
1722 
1723         separate_pathname( name, buf, &newname );
1724 
1725         if( chdir( buf ) == 0 )
1726         {
1727             rval = rmdir_path( &newname );
1728             chdir( ".." );
1729         }
1730 
1731         free_pathname( &newname );
1732         return rval;
1733     }
1734 
separate_pathname(pathname_t * name,char * buf,pathname_t * newname)1735     static void separate_pathname( pathname_t * name,
1736                                    char * buf,
1737                                    pathname_t * newname )
1738     {
1739         char * slash;
1740 
1741         init_pathname( newname );
1742         slash = strchr( name->path, '/' );
1743 
1744         if( slash == NULL )
1745         {
1746             buf[ 0 ] = '\0';
1747             return;
1748         }
1749 
1750         *slash = '\0';
1751         strcpy( buf, name->path );
1752         *slash = '/';
1753         append_pathname( newname, slash + 1 );
1754     }
1755 
stat64_path(pathname_t * name,REDSTAT * sbuf)1756     static int stat64_path( pathname_t * name,
1757                             REDSTAT * sbuf )
1758     {
1759         char buf[ MAXNAMELEN ];
1760         pathname_t newname;
1761         int rval;
1762 
1763         rval = stat64( name->path, sbuf );
1764 
1765         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1766         {
1767             return rval;
1768         }
1769 
1770         separate_pathname( name, buf, &newname );
1771 
1772         if( chdir( buf ) == 0 )
1773         {
1774             rval = stat64_path( &newname, sbuf );
1775             chdir( ".." );
1776         }
1777 
1778         free_pathname( &newname );
1779         return rval;
1780     }
1781 
truncate64_path(pathname_t * name,off64_t length)1782     static int truncate64_path( pathname_t * name,
1783                                 off64_t length )
1784     {
1785         char buf[ MAXNAMELEN ];
1786         pathname_t newname;
1787         int rval;
1788 
1789         rval = truncate64( name->path, length );
1790 
1791         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1792         {
1793             return rval;
1794         }
1795 
1796         separate_pathname( name, buf, &newname );
1797 
1798         if( chdir( buf ) == 0 )
1799         {
1800             rval = truncate64_path( &newname, length );
1801             chdir( ".." );
1802         }
1803 
1804         free_pathname( &newname );
1805         return rval;
1806     }
1807 
unlink_path(pathname_t * name)1808     static int unlink_path( pathname_t * name )
1809     {
1810         char buf[ MAXNAMELEN ];
1811         pathname_t newname;
1812         int rval;
1813 
1814         rval = unlink( name->path );
1815 
1816         if( ( rval >= 0 ) || ( errno != RED_ENAMETOOLONG ) )
1817         {
1818             return rval;
1819         }
1820 
1821         separate_pathname( name, buf, &newname );
1822 
1823         if( chdir( buf ) == 0 )
1824         {
1825             rval = unlink_path( &newname );
1826             chdir( ".." );
1827         }
1828 
1829         free_pathname( &newname );
1830         return rval;
1831     }
1832 
usage(const char * progname)1833     static void usage( const char * progname )
1834     {
1835         RedPrintf( "usage: %s VolumeID [Options]\n", progname );
1836         RedPrintf( "File system stress test.\n\n" );
1837         RedPrintf( "Where:\n" );
1838         RedPrintf( "  VolumeID\n" );
1839         RedPrintf( "      A volume number (e.g., 2) or a volume path prefix (e.g., VOL1: or /data)\n" );
1840         RedPrintf( "      of the volume to test.\n" );
1841         RedPrintf( "And 'Options' are any of the following:\n" );
1842         RedPrintf( "  --no-cleanup, -c\n" );
1843         RedPrintf( "      Specifies not to remove files (cleanup) after execution\n" );
1844         RedPrintf( "  --loops=count, -l count\n" );
1845         RedPrintf( "      Specifies the number of times the entire test should loop.  Use 0 for\n" );
1846         RedPrintf( "      infinite.  Default 1.\n" );
1847         RedPrintf( "  --nops=count, -n count\n" );
1848         RedPrintf( "      Specifies the number of operations to run (default 10000).\n" );
1849         RedPrintf( "  --namepad, -r\n" );
1850         RedPrintf( "      Specifies to use random name padding (resulting in longer names).\n" );
1851         RedPrintf( "  --seed=value, -s value\n" );
1852         RedPrintf( "      Specifies the seed for the random number generator (default timestamp).\n" );
1853         RedPrintf( "  --verbose, -v\n" );
1854         RedPrintf( "      Specifies verbose mode (without this, test is very quiet).\n" );
1855         RedPrintf( "  --dev=devname, -D devname\n" );
1856         RedPrintf( "      Specifies the device name.  This is typically only meaningful when\n" );
1857         RedPrintf( "      running the test on a host machine.  This can be \"ram\" to test on a RAM\n" );
1858         RedPrintf( "      disk, the path and name of a file disk (e.g., red.bin); or an OS-specific\n" );
1859         RedPrintf( "      reference to a device (on Windows, a drive letter like G: or a device name\n" );
1860         RedPrintf( "      like \\\\.\\PhysicalDrive7).\n" );
1861         RedPrintf( "  --help, -H\n" );
1862         RedPrintf( "      Prints this usage text and exits.\n\n" );
1863         RedPrintf( "Warning: This test will format the volume -- destroying all existing data.\n\n" );
1864     }
1865 
creat_f(int opno,long r)1866     static void creat_f( int opno,
1867                          long r )
1868     {
1869         int e;
1870         int e1;
1871         pathname_t f;
1872         int fd;
1873         fent_t * fep;
1874         int id;
1875         int parid;
1876         int type;
1877         int v;
1878         int v1;
1879         int esz = 0;
1880 
1881         if( !get_fname( FT_DIRm, r, NULL, NULL, &fep, &v1 ) )
1882         {
1883             parid = -1;
1884         }
1885         else
1886         {
1887             parid = fep->id;
1888         }
1889 
1890         init_pathname( &f );
1891         type = rtpct ? ( ( int ) ( random() % 100 ) > rtpct ? FT_REG : FT_RTF ) : FT_REG;
1892         e = generate_fname( fep, type, &f, &id, &v );
1893         v |= v1;
1894 
1895         if( !e )
1896         {
1897             if( v )
1898             {
1899                 fent_to_name( &f, &flist[ FT_DIR ], fep );
1900                 RedPrintf( "%d/%d: creat - no filename from %s\n",
1901                            procid, opno, f.path );
1902             }
1903 
1904             free_pathname( &f );
1905             return;
1906         }
1907 
1908         fd = creat_path( &f, 0666 );
1909         e = fd < 0 ? errno : 0;
1910         e1 = 0;
1911         check_cwd();
1912         esz = 0;
1913 
1914         if( fd >= 0 )
1915         {
1916             add_to_flist( type, id, parid );
1917             close( fd );
1918         }
1919 
1920         if( v )
1921         {
1922             RedPrintf( "%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
1923                        esz, e, e1 );
1924         }
1925 
1926         free_pathname( &f );
1927     }
1928 
fdatasync_f(int opno,long r)1929     static void fdatasync_f( int opno,
1930                              long r )
1931     {
1932         int e;
1933         pathname_t f;
1934         int fd;
1935         int v;
1936 
1937         init_pathname( &f );
1938 
1939         if( !get_fname( FT_REGFILE, r, &f, NULL, NULL, &v ) )
1940         {
1941             if( v )
1942             {
1943                 RedPrintf( "%d/%d: fdatasync - no filename\n",
1944                            procid, opno );
1945             }
1946 
1947             free_pathname( &f );
1948             return;
1949         }
1950 
1951         fd = open_path( &f, O_WRONLY );
1952         e = fd < 0 ? errno : 0;
1953         check_cwd();
1954 
1955         if( fd < 0 )
1956         {
1957             if( v )
1958             {
1959                 RedPrintf( "%d/%d: fdatasync - open %s failed %d\n",
1960                            procid, opno, f.path, e );
1961             }
1962 
1963             free_pathname( &f );
1964             return;
1965         }
1966 
1967         e = fdatasync( fd ) < 0 ? errno : 0;
1968 
1969         if( v )
1970         {
1971             RedPrintf( "%d/%d: fdatasync %s %d\n", procid, opno, f.path, e );
1972         }
1973 
1974         free_pathname( &f );
1975         close( fd );
1976     }
1977 
fsync_f(int opno,long r)1978     static void fsync_f( int opno,
1979                          long r )
1980     {
1981         int e;
1982         pathname_t f;
1983         int fd;
1984         int v;
1985 
1986         init_pathname( &f );
1987 
1988         if( !get_fname( FT_REGFILE, r, &f, NULL, NULL, &v ) )
1989         {
1990             if( v )
1991             {
1992                 RedPrintf( "%d/%d: fsync - no filename\n", procid, opno );
1993             }
1994 
1995             free_pathname( &f );
1996             return;
1997         }
1998 
1999         fd = open_path( &f, O_WRONLY );
2000         e = fd < 0 ? errno : 0;
2001         check_cwd();
2002 
2003         if( fd < 0 )
2004         {
2005             if( v )
2006             {
2007                 RedPrintf( "%d/%d: fsync - open %s failed %d\n",
2008                            procid, opno, f.path, e );
2009             }
2010 
2011             free_pathname( &f );
2012             return;
2013         }
2014 
2015         e = fsync( fd ) < 0 ? errno : 0;
2016 
2017         if( v )
2018         {
2019             RedPrintf( "%d/%d: fsync %s %d\n", procid, opno, f.path, e );
2020         }
2021 
2022         free_pathname( &f );
2023         close( fd );
2024     }
2025 
getdents_f(int opno,long r)2026     static void getdents_f( int opno,
2027                             long r )
2028     {
2029         DIR * dir;
2030         pathname_t f;
2031         int v;
2032 
2033         init_pathname( &f );
2034 
2035         if( !get_fname( FT_DIRm, r, &f, NULL, NULL, &v ) )
2036         {
2037             append_pathname( &f, "." );
2038         }
2039 
2040         dir = opendir_path( &f );
2041         check_cwd();
2042 
2043         if( dir == NULL )
2044         {
2045             if( v )
2046             {
2047                 RedPrintf( "%d/%d: getdents - can't open %s\n",
2048                            procid, opno, f.path );
2049             }
2050 
2051             free_pathname( &f );
2052             return;
2053         }
2054 
2055         while( readdir64( dir ) != NULL )
2056         {
2057             continue;
2058         }
2059 
2060         if( v )
2061         {
2062             RedPrintf( "%d/%d: getdents %s 0\n", procid, opno, f.path );
2063         }
2064 
2065         free_pathname( &f );
2066         closedir( dir );
2067     }
2068 
link_f(int opno,long r)2069     static void link_f( int opno,
2070                         long r )
2071     {
2072         int e;
2073         pathname_t f;
2074         fent_t * fep;
2075         flist_t * flp;
2076         int id;
2077         pathname_t l;
2078         int parid;
2079         int v;
2080         int v1;
2081 
2082         init_pathname( &f );
2083 
2084         if( !get_fname( FT_NOTDIR, r, &f, &flp, NULL, &v1 ) )
2085         {
2086             if( v1 )
2087             {
2088                 RedPrintf( "%d/%d: link - no file\n", procid, opno );
2089             }
2090 
2091             free_pathname( &f );
2092             return;
2093         }
2094 
2095         if( !get_fname( FT_DIRm, random(), NULL, NULL, &fep, &v ) )
2096         {
2097             parid = -1;
2098         }
2099         else
2100         {
2101             parid = fep->id;
2102         }
2103 
2104         v |= v1;
2105         init_pathname( &l );
2106         e = generate_fname( fep, ( int ) ( flp - flist ), &l, &id, &v1 );
2107         v |= v1;
2108 
2109         if( !e )
2110         {
2111             if( v )
2112             {
2113                 fent_to_name( &l, &flist[ FT_DIR ], fep );
2114                 RedPrintf( "%d/%d: link - no filename from %s\n",
2115                            procid, opno, l.path );
2116             }
2117 
2118             free_pathname( &l );
2119             free_pathname( &f );
2120             return;
2121         }
2122 
2123         e = link_path( &f, &l ) < 0 ? errno : 0;
2124         check_cwd();
2125 
2126         if( e == 0 )
2127         {
2128             add_to_flist( ( int ) ( flp - flist ), id, parid );
2129         }
2130 
2131         if( v )
2132         {
2133             RedPrintf( "%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
2134                        e );
2135         }
2136 
2137         free_pathname( &l );
2138         free_pathname( &f );
2139     }
2140 
mkdir_f(int opno,long r)2141     static void mkdir_f( int opno,
2142                          long r )
2143     {
2144         int e;
2145         pathname_t f;
2146         fent_t * fep;
2147         int id;
2148         int parid;
2149         int v;
2150         int v1;
2151 
2152         if( !get_fname( FT_DIRm, r, NULL, NULL, &fep, &v ) )
2153         {
2154             parid = -1;
2155         }
2156         else
2157         {
2158             parid = fep->id;
2159         }
2160 
2161         init_pathname( &f );
2162         e = generate_fname( fep, FT_DIR, &f, &id, &v1 );
2163         v |= v1;
2164 
2165         if( !e )
2166         {
2167             if( v )
2168             {
2169                 fent_to_name( &f, &flist[ FT_DIR ], fep );
2170                 RedPrintf( "%d/%d: mkdir - no filename from %s\n",
2171                            procid, opno, f.path );
2172             }
2173 
2174             free_pathname( &f );
2175             return;
2176         }
2177 
2178         e = mkdir_path( &f, 0777 ) < 0 ? errno : 0;
2179         check_cwd();
2180 
2181         if( e == 0 )
2182         {
2183             add_to_flist( FT_DIR, id, parid );
2184         }
2185 
2186         if( v )
2187         {
2188             RedPrintf( "%d/%d: mkdir %s %d\n", procid, opno, f.path, e );
2189         }
2190 
2191         free_pathname( &f );
2192     }
2193 
read_f(int opno,long r)2194     static void read_f( int opno,
2195                         long r )
2196     {
2197         char * buf;
2198         int e;
2199         pathname_t f;
2200         int fd;
2201         uint32_t len;
2202         __int64_t lr;
2203         off64_t off;
2204         REDSTAT stb;
2205         int v;
2206 
2207         init_pathname( &f );
2208 
2209         if( !get_fname( FT_REGFILE, r, &f, NULL, NULL, &v ) )
2210         {
2211             if( v )
2212             {
2213                 RedPrintf( "%d/%d: read - no filename\n", procid, opno );
2214             }
2215 
2216             free_pathname( &f );
2217             return;
2218         }
2219 
2220         fd = open_path( &f, O_RDONLY );
2221         e = fd < 0 ? errno : 0;
2222         check_cwd();
2223 
2224         if( fd < 0 )
2225         {
2226             if( v )
2227             {
2228                 RedPrintf( "%d/%d: read - open %s failed %d\n",
2229                            procid, opno, f.path, e );
2230             }
2231 
2232             free_pathname( &f );
2233             return;
2234         }
2235 
2236         if( fstat64( fd, &stb ) < 0 )
2237         {
2238             if( v )
2239             {
2240                 RedPrintf( "%d/%d: read - fstat64 %s failed %d\n",
2241                            procid, opno, f.path, errno );
2242             }
2243 
2244             free_pathname( &f );
2245             close( fd );
2246             return;
2247         }
2248 
2249         if( stb.st_size == 0 )
2250         {
2251             if( v )
2252             {
2253                 RedPrintf( "%d/%d: read - %s zero size\n", procid, opno,
2254                            f.path );
2255             }
2256 
2257             free_pathname( &f );
2258             close( fd );
2259             return;
2260         }
2261 
2262         lr = ( ( __int64_t ) random() << 32 ) + random();
2263         off = ( off64_t ) ( lr % stb.st_size );
2264         lseek64( fd, off, SEEK_SET );
2265         len = ( random() % ( getpagesize() * 4 ) ) + 1;
2266         buf = malloc( len );
2267         e = read( fd, buf, len ) < 0 ? errno : 0;
2268         free( buf );
2269 
2270         if( v )
2271         {
2272             RedPrintf( "%d/%d: read %s [%lld,%ld] %d\n",
2273                        procid, opno, f.path, ( long long ) off, ( long int ) len, e );
2274         }
2275 
2276         free_pathname( &f );
2277         close( fd );
2278     }
2279 
rename_f(int opno,long r)2280     static void rename_f( int opno,
2281                           long r )
2282     {
2283         fent_t * dfep;
2284         int e;
2285         pathname_t f;
2286         fent_t * fep;
2287         flist_t * flp;
2288         int id;
2289         pathname_t newf;
2290         int oldid;
2291         int parid;
2292         int v;
2293         int v1;
2294 
2295         init_pathname( &f );
2296 
2297         if( !get_fname( FT_ANYm, r, &f, &flp, &fep, &v1 ) )
2298         {
2299             if( v1 )
2300             {
2301                 RedPrintf( "%d/%d: rename - no filename\n", procid, opno );
2302             }
2303 
2304             free_pathname( &f );
2305             return;
2306         }
2307 
2308         if( !get_fname( FT_DIRm, random(), NULL, NULL, &dfep, &v ) )
2309         {
2310             parid = -1;
2311         }
2312         else
2313         {
2314             parid = dfep->id;
2315         }
2316 
2317         v |= v1;
2318         init_pathname( &newf );
2319         e = generate_fname( dfep, ( int ) ( flp - flist ), &newf, &id, &v1 );
2320         v |= v1;
2321 
2322         if( !e )
2323         {
2324             if( v )
2325             {
2326                 fent_to_name( &f, &flist[ FT_DIR ], dfep );
2327                 RedPrintf( "%d/%d: rename - no filename from %s\n",
2328                            procid, opno, f.path );
2329             }
2330 
2331             free_pathname( &newf );
2332             free_pathname( &f );
2333             return;
2334         }
2335 
2336         e = rename_path( &f, &newf ) < 0 ? errno : 0;
2337         check_cwd();
2338 
2339         if( e == 0 )
2340         {
2341             if( flp - flist == FT_DIR )
2342             {
2343                 oldid = fep->id;
2344                 fix_parent( oldid, id );
2345             }
2346 
2347             del_from_flist( ( int ) ( flp - flist ), ( int ) ( fep - flp->fents ) );
2348             add_to_flist( ( int ) ( flp - flist ), id, parid );
2349         }
2350 
2351         if( v )
2352         {
2353             RedPrintf( "%d/%d: rename %s to %s %d\n", procid, opno, f.path,
2354                        newf.path, e );
2355         }
2356 
2357         free_pathname( &newf );
2358         free_pathname( &f );
2359     }
2360 
rmdir_f(int opno,long r)2361     static void rmdir_f( int opno,
2362                          long r )
2363     {
2364         int e;
2365         pathname_t f;
2366         fent_t * fep;
2367         int v;
2368 
2369         init_pathname( &f );
2370 
2371         if( !get_fname( FT_DIRm, r, &f, NULL, &fep, &v ) )
2372         {
2373             if( v )
2374             {
2375                 RedPrintf( "%d/%d: rmdir - no directory\n", procid, opno );
2376             }
2377 
2378             free_pathname( &f );
2379             return;
2380         }
2381 
2382         e = rmdir_path( &f ) < 0 ? errno : 0;
2383         check_cwd();
2384 
2385         if( e == 0 )
2386         {
2387             del_from_flist( FT_DIR, ( int ) ( fep - flist[ FT_DIR ].fents ) );
2388         }
2389 
2390         if( v )
2391         {
2392             RedPrintf( "%d/%d: rmdir %s %d\n", procid, opno, f.path, e );
2393         }
2394 
2395         free_pathname( &f );
2396     }
2397 
stat_f(int opno,long r)2398     static void stat_f( int opno,
2399                         long r )
2400     {
2401         int e;
2402         pathname_t f;
2403         REDSTAT stb;
2404         int v;
2405 
2406         init_pathname( &f );
2407 
2408         if( !get_fname( FT_ANYm, r, &f, NULL, NULL, &v ) )
2409         {
2410             if( v )
2411             {
2412                 RedPrintf( "%d/%d: stat - no entries\n", procid, opno );
2413             }
2414 
2415             free_pathname( &f );
2416             return;
2417         }
2418 
2419         e = lstat64_path( &f, &stb ) < 0 ? errno : 0;
2420         check_cwd();
2421 
2422         if( v )
2423         {
2424             RedPrintf( "%d/%d: stat %s %d\n", procid, opno, f.path, e );
2425         }
2426 
2427         free_pathname( &f );
2428     }
2429 
truncate_f(int opno,long r)2430     static void truncate_f( int opno,
2431                             long r )
2432     {
2433         int e;
2434         pathname_t f;
2435         __int64_t lr;
2436         off64_t off;
2437         REDSTAT stb;
2438         int v;
2439 
2440         init_pathname( &f );
2441 
2442         if( !get_fname( FT_REGFILE, r, &f, NULL, NULL, &v ) )
2443         {
2444             if( v )
2445             {
2446                 RedPrintf( "%d/%d: truncate - no filename\n", procid, opno );
2447             }
2448 
2449             free_pathname( &f );
2450             return;
2451         }
2452 
2453         e = stat64_path( &f, &stb ) < 0 ? errno : 0;
2454         check_cwd();
2455 
2456         if( e > 0 )
2457         {
2458             if( v )
2459             {
2460                 RedPrintf( "%d/%d: truncate - stat64 %s failed %d\n",
2461                            procid, opno, f.path, e );
2462             }
2463 
2464             free_pathname( &f );
2465             return;
2466         }
2467 
2468         lr = ( ( __int64_t ) random() << 32 ) + random();
2469         off = lr % MIN( stb.st_size + ( 1024 * 1024 ), MAXFSIZE );
2470         off %= maxfsize;
2471         e = truncate64_path( &f, off ) < 0 ? errno : 0;
2472         check_cwd();
2473 
2474         if( v )
2475         {
2476             RedPrintf( "%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
2477                        ( long long ) off, e );
2478         }
2479 
2480         free_pathname( &f );
2481     }
2482 
unlink_f(int opno,long r)2483     static void unlink_f( int opno,
2484                           long r )
2485     {
2486         int e;
2487         pathname_t f;
2488         fent_t * fep;
2489         flist_t * flp;
2490         int v;
2491 
2492         init_pathname( &f );
2493 
2494         if( !get_fname( FT_NOTDIR, r, &f, &flp, &fep, &v ) )
2495         {
2496             if( v )
2497             {
2498                 RedPrintf( "%d/%d: unlink - no file\n", procid, opno );
2499             }
2500 
2501             free_pathname( &f );
2502             return;
2503         }
2504 
2505         e = unlink_path( &f ) < 0 ? errno : 0;
2506         check_cwd();
2507 
2508         if( e == 0 )
2509         {
2510             del_from_flist( ( int ) ( flp - flist ), ( int ) ( fep - flp->fents ) );
2511         }
2512 
2513         if( v )
2514         {
2515             RedPrintf( "%d/%d: unlink %s %d\n", procid, opno, f.path, e );
2516         }
2517 
2518         free_pathname( &f );
2519     }
2520 
write_f(int opno,long r)2521     static void write_f( int opno,
2522                          long r )
2523     {
2524         char * buf;
2525         int e;
2526         pathname_t f;
2527         int fd;
2528         uint32_t len;
2529         __int64_t lr;
2530         off64_t off;
2531         REDSTAT stb;
2532         int v;
2533 
2534         init_pathname( &f );
2535 
2536         if( !get_fname( FT_REGm, r, &f, NULL, NULL, &v ) )
2537         {
2538             if( v )
2539             {
2540                 RedPrintf( "%d/%d: write - no filename\n", procid, opno );
2541             }
2542 
2543             free_pathname( &f );
2544             return;
2545         }
2546 
2547         fd = open_path( &f, O_WRONLY );
2548         e = fd < 0 ? errno : 0;
2549         check_cwd();
2550 
2551         if( fd < 0 )
2552         {
2553             if( v )
2554             {
2555                 RedPrintf( "%d/%d: write - open %s failed %d\n",
2556                            procid, opno, f.path, e );
2557             }
2558 
2559             free_pathname( &f );
2560             return;
2561         }
2562 
2563         if( fstat64( fd, &stb ) < 0 )
2564         {
2565             if( v )
2566             {
2567                 RedPrintf( "%d/%d: write - fstat64 %s failed %d\n",
2568                            procid, opno, f.path, errno );
2569             }
2570 
2571             free_pathname( &f );
2572             close( fd );
2573             return;
2574         }
2575 
2576         lr = ( ( __int64_t ) random() << 32 ) + random();
2577         off = ( off64_t ) ( lr % MIN( stb.st_size + ( 1024 * 1024 ), MAXFSIZE ) );
2578         off %= maxfsize;
2579         lseek64( fd, off, SEEK_SET );
2580         len = ( random() % ( getpagesize() * 4 ) ) + 1;
2581         buf = malloc( len );
2582         memset( buf, nameseq & 0xff, len );
2583         e = write( fd, buf, len ) < 0 ? errno : 0;
2584         free( buf );
2585 
2586         if( v )
2587         {
2588             RedPrintf( "%d/%d: write %s [%lld,%ld] %d\n",
2589                        procid, opno, f.path, ( long long ) off, ( long int ) len, e );
2590         }
2591 
2592         free_pathname( &f );
2593         close( fd );
2594     }
2595 
2596 
2597     #if REDCONF_CHECKER == 1
check_f(int opno,long r)2598         static void check_f( int opno,
2599                              long r )
2600         {
2601             int32_t ret;
2602             const char * pszVolume = gpRedVolConf->pszPathPrefix;
2603 
2604             ( void ) r;
2605 
2606             errno = 0;
2607 
2608             ret = red_transact( pszVolume );
2609 
2610             if( ret == 0 )
2611             {
2612                 ret = red_umount( pszVolume );
2613 
2614                 if( ret == 0 )
2615                 {
2616                     int32_t ret2;
2617 
2618                     errno = -RedCoreVolCheck();
2619 
2620                     if( errno != 0 )
2621                     {
2622                         ret = -1;
2623                     }
2624 
2625                     ret2 = red_mount( pszVolume );
2626 
2627                     if( ret == 0 )
2628                     {
2629                         ret = ret2;
2630                     }
2631 
2632                     if( ret2 != 0 )
2633                     {
2634                         exit( 1 );
2635                     }
2636                 }
2637             }
2638 
2639             if( verbose )
2640             {
2641                 RedPrintf( "%d/%d: check %s %d\n", procid, opno, pszVolume, errno );
2642             }
2643         }
2644     #endif /* if REDCONF_CHECKER == 1 */
2645 
2646 
2647 #endif /* FSSTRESS_SUPPORTED */
2648