static bool preallocate_file_sparse (int fd, uint64_t length) { const char zero = '\0'; bool success = 0; if (!length) success = true; #ifdef HAVE_FALLOCATE64 if (!success) /* fallocate64 is always preferred, so try it first */ success = !fallocate64 (fd, 0, 0, length); #endif if (!success) /* fallback: the old-style seek-and-write */ success = (lseek (fd, length-1, SEEK_SET) != -1) && (write (fd, &zero, 1) != -1) && (ftruncate (fd, length) != -1); return success; }
TEST(fcntl, fallocate_EINVAL) { TemporaryFile tf; #if !defined(__GLIBC__) errno = 0; ASSERT_EQ(-1, fallocate(tf.fd, 0, 0, -1)); ASSERT_EQ(EINVAL, errno); errno = 0; ASSERT_EQ(-1, fallocate64(tf.fd, 0, 0, -1)); ASSERT_EQ(EINVAL, errno); #endif errno = 0; ASSERT_EQ(EINVAL, posix_fallocate(tf.fd, 0, -1)); ASSERT_EQ(0, errno); errno = 0; ASSERT_EQ(EINVAL, posix_fallocate64(tf.fd, 0, -1)); ASSERT_EQ(0, errno); }
TEST(fcntl, fallocate) { TemporaryFile tf; struct stat sb; ASSERT_EQ(0, fstat(tf.fd, &sb)); ASSERT_EQ(0, sb.st_size); #if !defined(__GLIBC__) ASSERT_EQ(0, fallocate(tf.fd, 0, 0, 1)); ASSERT_EQ(0, fstat(tf.fd, &sb)); ASSERT_EQ(1, sb.st_size); ASSERT_EQ(0, fallocate64(tf.fd, 0, 0, 2)); ASSERT_EQ(0, fstat(tf.fd, &sb)); ASSERT_EQ(2, sb.st_size); #endif ASSERT_EQ(0, posix_fallocate(tf.fd, 0, 3)); ASSERT_EQ(0, fstat(tf.fd, &sb)); ASSERT_EQ(3, sb.st_size); ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, 4)); ASSERT_EQ(0, fstat(tf.fd, &sb)); ASSERT_EQ(4, sb.st_size); }
static bool preallocate_file_full (const char * filename, uint64_t length) { bool success = 0; #ifdef WIN32 HANDLE hFile = CreateFile (filename, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0); if (hFile != INVALID_HANDLE_VALUE) { LARGE_INTEGER li; li.QuadPart = length; success = SetFilePointerEx (hFile, li, NULL, FILE_BEGIN) && SetEndOfFile (hFile); CloseHandle (hFile); } #else int flags = O_RDWR | O_CREAT | O_LARGEFILE; int fd = open (filename, flags, 0666); if (fd >= 0) { # ifdef HAVE_FALLOCATE64 if (!success) { success = !fallocate64 (fd, 0, 0, length); } # endif # ifdef HAVE_XFS_XFS_H if (!success && platform_test_xfs_fd (fd)) { xfs_flock64_t fl; fl.l_whence = 0; fl.l_start = 0; fl.l_len = length; success = !xfsctl (NULL, fd, XFS_IOC_RESVSP64, &fl); } # endif # ifdef SYS_DARWIN if (!success) { fstore_t fst; fst.fst_flags = F_ALLOCATECONTIG; fst.fst_posmode = F_PEOFPOSMODE; fst.fst_offset = 0; fst.fst_length = length; fst.fst_bytesalloc = 0; success = !fcntl (fd, F_PREALLOCATE, &fst); } # endif #undef HAVE_POSIX_FALLOCATE # ifdef HAVE_POSIX_FALLOCATE if (!success) { success = !posix_fallocate (fd, 0, length); } # endif #define MINSLEEP 3 #define MAXSLEEP 40000 #define INCRFACT 1.9 #define DECRFACT 3 #define BLCKSIZE 32768 #define TSTEVERYBYTES 524288 #define TSTEVERYBLKS TSTEVERYBYTES/BLCKSIZE if (!success) /* if nothing else works, do it the old-fashioned way */ { struct timeval lastTime, thisTime; // Set up buffer with 0s. unsigned int block_size = BLCKSIZE; uint8_t buf[ block_size ]; memset (buf, 0, sizeof (buf)); // Set up speed test counters. unsigned int testEveryBytes = TSTEVERYBYTES; unsigned int testEveryIters = TSTEVERYBLKS; unsigned int itersUntilTest = testEveryIters; long lastTook = 0; long currentTook = 0; gettimeofday(&lastTime, NULL); unsigned int sleep = MINSLEEP; unsigned int lastSlept = 0; unsigned int size=length; success = true; while (success && (length > 0)) { if (itersUntilTest == 0) { gettimeofday(&thisTime, NULL); currentTook = thisTime.tv_sec*1000000 + thisTime.tv_usec - lastTime.tv_sec*1000000 - lastTime.tv_usec - lastSlept; if (currentTook > lastTook) { sleep = MIN(sleep * INCRFACT, MAXSLEEP); } else if (currentTook < lastTook) { sleep = MAX(sleep / DECRFACT, MINSLEEP); } lastSlept = 0; lastTook = currentTook; lastTime = thisTime; itersUntilTest = testEveryIters; fprintf (stderr, "{\"TR_PREALLOC\":%d,\"filename\":\"%s\"}\n", (int)(100.f*(float)(size - length)/(float)size), filename); //fprintf (stderr, "Will sleep %d usec on every write.\n", sleep); } const int thisPass = MIN (length, sizeof (buf)); success = write (fd, buf, thisPass) == thisPass; length -= thisPass; --itersUntilTest; usleep(sleep); lastSlept = lastSlept + sleep; } } /* if (!success) // if nothing else works, do it the old-fashioned way { uint8_t buf[ 32768 ]; memset (buf, 0, sizeof (buf)); success = true; while (success && (length > 0)) { const int thisPass = MIN (length, sizeof (buf)); success = write (fd, buf, thisPass) == thisPass; length -= thisPass; usleep(9000); } } */ close (fd); } #endif return success; }
static bool preallocate_file_full( const char * filename, uint64_t length ) { bool success = 0; #ifdef WIN32 HANDLE hFile = CreateFile( filename, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0 ); if( hFile != INVALID_HANDLE_VALUE ) { LARGE_INTEGER li; li.QuadPart = length; success = SetFilePointerEx( hFile, li, NULL, FILE_BEGIN ) && SetEndOfFile( hFile ); CloseHandle( hFile ); } #else int flags = O_RDWR | O_CREAT | O_LARGEFILE; int fd = open( filename, flags, 0666 ); if( fd >= 0 ) { # ifdef HAVE_FALLOCATE64 if( !success ) { success = !fallocate64( fd, 0, 0, length ); } # endif # ifdef HAVE_XFS_XFS_H if( !success && platform_test_xfs_fd( fd ) ) { xfs_flock64_t fl; fl.l_whence = 0; fl.l_start = 0; fl.l_len = length; success = !xfsctl( NULL, fd, XFS_IOC_RESVSP64, &fl ); } # endif # ifdef SYS_DARWIN if( !success ) { fstore_t fst; fst.fst_flags = F_ALLOCATECONTIG; fst.fst_posmode = F_PEOFPOSMODE; fst.fst_offset = 0; fst.fst_length = length; fst.fst_bytesalloc = 0; success = !fcntl( fd, F_PREALLOCATE, &fst ); } # endif # ifdef HAVE_POSIX_FALLOCATE if( !success ) { success = !posix_fallocate( fd, 0, length ); } # endif if( !success ) /* if nothing else works, do it the old-fashioned way */ { uint8_t buf[ 4096 ]; memset( buf, 0, sizeof( buf ) ); success = true; while ( success && ( length > 0 ) ) { const int thisPass = MIN( length, sizeof( buf ) ); success = write( fd, buf, thisPass ) == thisPass; length -= thisPass; } } close( fd ); } #endif return success; }
// There is no fallocate for 32-bit off_t, so we need to widen and call fallocate64. int fallocate(int fd, int mode, off_t offset, off_t length) { return fallocate64(fd, mode, static_cast<off64_t>(offset), static_cast<off64_t>(length)); }