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