Improve shred throughput with adaptive chunksize #98
@@ -0,0 +1,92 @@
|
|||||||
|
# reHDD Code Style - clang-format configuration
|
||||||
|
# Based on analyzed codebase formatting
|
||||||
|
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
# Indentation
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
|
||||||
|
# Braces
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
# Allman style:
|
||||||
|
# if (condition)
|
||||||
|
# {
|
||||||
|
# statement;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Spacing
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
|
||||||
|
# Alignment
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
|
||||||
|
# Line breaks
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
|
||||||
|
# Column limit
|
||||||
|
ColumnLimit: 0
|
||||||
|
# 0 = no limit (observed in the code)
|
||||||
|
|
||||||
|
# Breaking
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakStringLiterals: false
|
||||||
|
|
||||||
|
# Pointers and references
|
||||||
|
PointerAlignment: Left
|
||||||
|
# Type *variable (not Type* variable)
|
||||||
|
|
||||||
|
# Include sorting
|
||||||
|
SortIncludes: false
|
||||||
|
# Keep includes in original order
|
||||||
|
|
||||||
|
# Comments
|
||||||
|
ReflowComments: false
|
||||||
|
# Don't reformat comments
|
||||||
|
|
||||||
|
# Access modifiers
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
# public: is outdented
|
||||||
|
|
||||||
|
# Constructor initializers
|
||||||
|
ConstructorInitializerIndentWidth: 6
|
||||||
|
# Observed 6 spaces for initializer lists
|
||||||
|
|
||||||
|
# Other
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
FixNamespaceComments: true
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 100
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
+48
-4
@@ -16,9 +16,28 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#define CHUNK_SIZE 1024 * 1024 * 32 // amount of bytes that are overwritten at once --> 32MB
|
// Adaptive chunk size optimization - uncomment to enable
|
||||||
#define TFNG_DATA_SIZE CHUNK_SIZE // amount of bytes used by tfng
|
#define ADAPTIVE_CHUNK_SIZE
|
||||||
|
|
||||||
|
// Chunk size configuration
|
||||||
|
#define CHUNK_SIZE_START 1024 * 1024 * 32 // Starting chunk size: 32MB
|
||||||
|
#define CHUNK_SIZE_MIN 1024 * 1024 * 4 // Minimum chunk size: 4MB
|
||||||
|
#define CHUNK_SIZE_MAX 1024 * 1024 * 128 // Maximum chunk size: 128MB
|
||||||
|
#define CHUNK_SIZE_STEP_UP 1024 * 1024 * 2 // Increase step: 2MB
|
||||||
|
#define CHUNK_SIZE_STEP_DOWN 1024 * 1024 * 4 // Decrease step: 4MB
|
||||||
|
#define CHUNK_MEASURE_INTERVAL 64 // Measure performance every 64 chunks
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
// Use max buffer size when adaptive mode is enabled
|
||||||
|
#define CHUNK_SIZE CHUNK_SIZE_MAX
|
||||||
|
#define TFNG_DATA_SIZE CHUNK_SIZE_MAX
|
||||||
|
#else
|
||||||
|
// Use fixed chunk size when adaptive mode is disabled
|
||||||
|
#define CHUNK_SIZE CHUNK_SIZE_START
|
||||||
|
#define TFNG_DATA_SIZE CHUNK_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
// #define DEMO_DRIVE_SIZE 1024*1024*256L // 256MB
|
// #define DEMO_DRIVE_SIZE 1024*1024*256L // 256MB
|
||||||
// #define DEMO_DRIVE_SIZE 1024*1024*1024L // 1GB
|
// #define DEMO_DRIVE_SIZE 1024*1024*1024L // 1GB
|
||||||
@@ -33,22 +52,47 @@ protected:
|
|||||||
public:
|
public:
|
||||||
Shred();
|
Shred();
|
||||||
~Shred();
|
~Shred();
|
||||||
int shredDrive(Drive *drive, int *ipSignalFd);
|
int shredDrive(Drive* drive, int* ipSignalFd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
fileDescriptor randomSrcFileDiscr;
|
fileDescriptor randomSrcFileDiscr;
|
||||||
fileDescriptor driveFileDiscr;
|
fileDescriptor driveFileDiscr;
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
unsigned char* caTfngData; // Dynamic buffer allocation for adaptive mode
|
||||||
|
unsigned char* caReadBuffer; // Dynamic buffer allocation for adaptive mode
|
||||||
|
#else
|
||||||
unsigned char caTfngData[TFNG_DATA_SIZE];
|
unsigned char caTfngData[TFNG_DATA_SIZE];
|
||||||
unsigned char caReadBuffer[CHUNK_SIZE];
|
unsigned char caReadBuffer[CHUNK_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned long ulDriveByteSize;
|
unsigned long ulDriveByteSize;
|
||||||
unsigned long ulDriveByteOverallCount = 0; // all bytes shredded in all iterations + checking -> used for progress calculation
|
unsigned long ulDriveByteOverallCount = 0; // all bytes shredded in all iterations + checking -> used for progress calculation
|
||||||
double d32Percent = 0.0;
|
double d32Percent = 0.0;
|
||||||
double d32TmpPercent = 0.0;
|
double d32TmpPercent = 0.0;
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
// Adaptive chunk size optimization members
|
||||||
|
size_t currentChunkSize;
|
||||||
|
size_t bestChunkSize;
|
||||||
|
unsigned int chunkCounter;
|
||||||
|
std::chrono::high_resolution_clock::time_point measurementStartTime;
|
||||||
|
double bestThroughputMBps;
|
||||||
|
double lastThroughputMBps;
|
||||||
|
unsigned long bytesWrittenInMeasurement;
|
||||||
|
bool throughputIncreasing;
|
||||||
|
|
||||||
|
// Adaptive methods
|
||||||
|
void startMeasurement();
|
||||||
|
void evaluateThroughput(Drive* drive);
|
||||||
|
void adjustChunkSize(Drive* drive);
|
||||||
|
size_t getCurrentChunkSize() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
inline double calcProgress();
|
inline double calcProgress();
|
||||||
int iRewindDrive(fileDescriptor file);
|
int iRewindDrive(fileDescriptor file);
|
||||||
long getDriveSizeInBytes(fileDescriptor file);
|
long getDriveSizeInBytes(fileDescriptor file);
|
||||||
unsigned int uiCalcChecksum(fileDescriptor file, Drive *drive, int *ipSignalFd);
|
unsigned int uiCalcChecksum(fileDescriptor file, Drive* drive, int* ipSignalFd);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -49,7 +49,7 @@ public:
|
|||||||
|
|
||||||
static void initTUI();
|
static void initTUI();
|
||||||
|
|
||||||
void updateTUI(std::list<Drive> *plistDrives, uint8_t u8SelectedEntry);
|
void updateTUI(std::list<Drive>* plistDrives, uint8_t u8SelectedEntry);
|
||||||
|
|
||||||
static enum UserInput readUserInput();
|
static enum UserInput readUserInput();
|
||||||
|
|
||||||
@@ -60,28 +60,28 @@ private:
|
|||||||
static std::string sRamUsage;
|
static std::string sRamUsage;
|
||||||
static std::string sLocalTime;
|
static std::string sLocalTime;
|
||||||
|
|
||||||
WINDOW *overview;
|
WINDOW* overview;
|
||||||
WINDOW *systemview;
|
WINDOW* systemview;
|
||||||
WINDOW *detailview;
|
WINDOW* detailview;
|
||||||
WINDOW *menuview;
|
WINDOW* menuview;
|
||||||
WINDOW *dialog;
|
WINDOW* dialog;
|
||||||
WINDOW *smartWarning;
|
WINDOW* smartWarning;
|
||||||
|
|
||||||
static void centerTitle(WINDOW *pwin, const char *title);
|
static void centerTitle(WINDOW* pwin, const char* title);
|
||||||
static WINDOW *createOverViewWindow(int iXSize, int iYSize);
|
static WINDOW* createOverViewWindow(int iXSize, int iYSize);
|
||||||
static WINDOW *createDetailViewWindow(int iXSize, int iYSize, int iXStart, Drive &drive);
|
static WINDOW* createDetailViewWindow(int iXSize, int iYSize, int iXStart, Drive& drive);
|
||||||
static WINDOW *overwriteDetailViewWindow(int iXSize, int iYSize, int iXStart);
|
static WINDOW* overwriteDetailViewWindow(int iXSize, int iYSize, int iXStart);
|
||||||
static WINDOW *createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, int iListIndex, std::string sModelFamily, std::string sSerial, std::string sCapacity, std::string sState, std::string sTime, std::string sSpeed, std::string sTemp, std::string sConnection, bool bSelected);
|
static WINDOW* createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, int iListIndex, std::string sModelFamily, std::string sSerial, std::string sCapacity, std::string sState, std::string sTime, std::string sSpeed, std::string sTemp, std::string sConnection, bool bSelected);
|
||||||
static WINDOW *createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart);
|
static WINDOW* createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart);
|
||||||
static WINDOW *createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, struct MenuState menustate);
|
static WINDOW* createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, struct MenuState menustate);
|
||||||
static WINDOW *createDialog(int iXSize, int iYSize, int iXStart, int iYStart, std::string selectedTask, std::string optionA, std::string optionB);
|
static WINDOW* createDialog(int iXSize, int iYSize, int iXStart, int iYStart, std::string selectedTask, std::string optionA, std::string optionB);
|
||||||
static WINDOW *createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, std::string sPath, std::string sModelFamily, std::string sModelName, std::string sSerial, std::string sProgress);
|
static WINDOW* createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, std::string sPath, std::string sModelFamily, std::string sModelName, std::string sSerial, std::string sProgress);
|
||||||
static WINDOW *createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, std::string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount, uint32_t u32Temperature);
|
static WINDOW* createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, std::string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount, uint32_t u32Temperature);
|
||||||
static WINDOW *createZeroChecksumWarning(int iXSize, int iYSize, int iXStart, int iYStart, std::string sPath, std::string sModelFamily, std::string sModelName, std::string sSerial, uint32_t u32Checksum);
|
static WINDOW* createZeroChecksumWarning(int iXSize, int iYSize, int iXStart, int iYStart, std::string sPath, std::string sModelFamily, std::string sModelName, std::string sSerial, uint32_t u32Checksum);
|
||||||
|
|
||||||
void displaySelectedDrive(Drive &drive, int stdscrX, int stdscrY);
|
void displaySelectedDrive(Drive& drive, int stdscrX, int stdscrY);
|
||||||
std::string formatTimeDuration(time_t u32Duration);
|
std::string formatTimeDuration(time_t u32Duration);
|
||||||
std::string formatSpeed(time_t u32ShredTimeDelta, unsigned long ulWrittenBytes);
|
std::string formatSpeed(time_t u32ShredTimeDelta, unsigned long ulWrittenBytes);
|
||||||
static void vTruncateText(std::string *psText, uint16_t u16MaxLenght);
|
static void vTruncateText(std::string* psText, uint16_t u16MaxLenght);
|
||||||
};
|
};
|
||||||
#endif // TUI_H_
|
#endif // TUI_H_
|
||||||
|
|||||||
+234
-27
@@ -17,27 +17,184 @@ extern "C"
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const static char *randomsrc = (char *)"/dev/urandom";
|
const static char* randomsrc = (char*)"/dev/urandom";
|
||||||
|
|
||||||
Shred::Shred()
|
Shred::Shred()
|
||||||
{
|
{
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
// Allocate aligned buffers for maximum chunk size
|
||||||
|
if (posix_memalign((void**)&caTfngData, 4096, CHUNK_SIZE_MAX) != 0)
|
||||||
|
{
|
||||||
|
Logger::logThis()->error("Failed to allocate aligned buffer for tfng data");
|
||||||
|
caTfngData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posix_memalign((void**)&caReadBuffer, 4096, CHUNK_SIZE_MAX) != 0)
|
||||||
|
{
|
||||||
|
Logger::logThis()->error("Failed to allocate aligned buffer for read buffer");
|
||||||
|
caReadBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize adaptive tracking variables
|
||||||
|
currentChunkSize = CHUNK_SIZE_START;
|
||||||
|
bestChunkSize = CHUNK_SIZE_START;
|
||||||
|
chunkCounter = 0;
|
||||||
|
bestThroughputMBps = 0.0;
|
||||||
|
lastThroughputMBps = 0.0;
|
||||||
|
bytesWrittenInMeasurement = 0;
|
||||||
|
throughputIncreasing = true;
|
||||||
|
|
||||||
|
Logger::logThis()->info("Adaptive chunk size optimization ENABLED - Starting with " +
|
||||||
|
to_string(currentChunkSize / (1024 * 1024)) + " MB chunks");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Shred::~Shred()
|
Shred::~Shred()
|
||||||
{
|
{
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
if (caTfngData != nullptr)
|
||||||
|
{
|
||||||
|
free(caTfngData);
|
||||||
|
caTfngData = nullptr;
|
||||||
|
}
|
||||||
|
if (caReadBuffer != nullptr)
|
||||||
|
{
|
||||||
|
free(caReadBuffer);
|
||||||
|
caReadBuffer = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
/**
|
||||||
|
* \brief Start performance measurement interval
|
||||||
|
* \return void
|
||||||
|
*/
|
||||||
|
void Shred::startMeasurement()
|
||||||
|
{
|
||||||
|
measurementStartTime = std::chrono::high_resolution_clock::now();
|
||||||
|
bytesWrittenInMeasurement = 0;
|
||||||
|
chunkCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief shred drive with shred
|
* \brief Evaluate throughput after measurement interval and adjust chunk size
|
||||||
* \param pointer of Drive instance
|
* \param pointer to Drive instance
|
||||||
* \return void
|
* \return void
|
||||||
*/
|
*/
|
||||||
int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
void Shred::evaluateThroughput(Drive* drive)
|
||||||
|
{
|
||||||
|
auto measurementEndTime = std::chrono::high_resolution_clock::now();
|
||||||
|
std::chrono::duration<double> elapsed = measurementEndTime - measurementStartTime;
|
||||||
|
double elapsedSeconds = elapsed.count();
|
||||||
|
|
||||||
|
if (elapsedSeconds > 0.0)
|
||||||
|
{
|
||||||
|
double throughputMBps = (bytesWrittenInMeasurement / (1024.0 * 1024.0)) / elapsedSeconds;
|
||||||
|
lastThroughputMBps = throughputMBps;
|
||||||
|
|
||||||
|
Logger::logThis()->info("Throughput measurement - ChunkSize: " +
|
||||||
|
to_string(currentChunkSize / (1024 * 1024)) + " MB, " +
|
||||||
|
"Throughput: " + to_string((int)throughputMBps) + " MB/s, " +
|
||||||
|
"Best: " + to_string((int)bestThroughputMBps) + " MB/s" +
|
||||||
|
" - Drive: " + drive->getSerial());
|
||||||
|
|
||||||
|
// Check if this is better than our best
|
||||||
|
if (throughputMBps > bestThroughputMBps)
|
||||||
|
{
|
||||||
|
bestThroughputMBps = throughputMBps;
|
||||||
|
bestChunkSize = currentChunkSize;
|
||||||
|
throughputIncreasing = true;
|
||||||
|
|
||||||
|
Logger::logThis()->info("NEW BEST throughput: " + to_string((int)bestThroughputMBps) +
|
||||||
|
" MB/s with " + to_string(currentChunkSize / (1024 * 1024)) +
|
||||||
|
" MB chunks - Drive: " + drive->getSerial());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throughputIncreasing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust chunk size for next measurement interval
|
||||||
|
adjustChunkSize(drive);
|
||||||
|
|
||||||
|
// Start new measurement
|
||||||
|
startMeasurement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adjust chunk size based on throughput trend
|
||||||
|
* \param pointer to Drive instance
|
||||||
|
* \return void
|
||||||
|
*/
|
||||||
|
void Shred::adjustChunkSize(Drive* drive)
|
||||||
|
{
|
||||||
|
size_t oldChunkSize = currentChunkSize;
|
||||||
|
|
||||||
|
if (throughputIncreasing)
|
||||||
|
{
|
||||||
|
// Throughput is improving - increase chunk size
|
||||||
|
currentChunkSize += CHUNK_SIZE_STEP_UP;
|
||||||
|
|
||||||
|
// Clamp to maximum
|
||||||
|
if (currentChunkSize > CHUNK_SIZE_MAX)
|
||||||
|
{
|
||||||
|
currentChunkSize = CHUNK_SIZE_MAX;
|
||||||
|
Logger::logThis()->info("Reached maximum chunk size: " +
|
||||||
|
to_string(currentChunkSize / (1024 * 1024)) + " MB" +
|
||||||
|
" - Drive: " + drive->getSerial());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Throughput decreased - decrease chunk size to find sweet spot
|
||||||
|
if (currentChunkSize > CHUNK_SIZE_STEP_DOWN)
|
||||||
|
{
|
||||||
|
currentChunkSize -= CHUNK_SIZE_STEP_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp to minimum
|
||||||
|
if (currentChunkSize < CHUNK_SIZE_MIN)
|
||||||
|
{
|
||||||
|
currentChunkSize = CHUNK_SIZE_MIN;
|
||||||
|
Logger::logThis()->info("Reached minimum chunk size: " +
|
||||||
|
to_string(currentChunkSize / (1024 * 1024)) + " MB" +
|
||||||
|
" - Drive: " + drive->getSerial());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldChunkSize != currentChunkSize)
|
||||||
|
{
|
||||||
|
Logger::logThis()->info("Adjusted chunk size: " +
|
||||||
|
to_string(oldChunkSize / (1024 * 1024)) + " MB -> " +
|
||||||
|
to_string(currentChunkSize / (1024 * 1024)) + " MB" +
|
||||||
|
" - Drive: " + drive->getSerial());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get current chunk size for adaptive mode
|
||||||
|
* \return current chunk size in bytes
|
||||||
|
*/
|
||||||
|
size_t Shred::getCurrentChunkSize() const
|
||||||
|
{
|
||||||
|
return currentChunkSize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief shred drive with shred
|
||||||
|
* \param pointer of Drive instance
|
||||||
|
* \param file descriptor for signaling
|
||||||
|
* \return 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int Shred::shredDrive(Drive* drive, int* ipSignalFd)
|
||||||
{
|
{
|
||||||
ostringstream address;
|
ostringstream address;
|
||||||
address << (void const *)&(*drive);
|
address << (void const*)&(*drive);
|
||||||
Logger::logThis()->info("Shred-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
Logger::logThis()->info("Shred-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
||||||
drive->bWasShredStarted = true; // Mark drive as partly shredded
|
drive->bWasShredStarted = true;
|
||||||
drive->bWasShredded = false;
|
drive->bWasShredded = false;
|
||||||
drive->setTaskPercentage(0.0);
|
drive->setTaskPercentage(0.0);
|
||||||
drive->u32DriveChecksumAfterShredding = UINT32_MAX;
|
drive->u32DriveChecksumAfterShredding = UINT32_MAX;
|
||||||
@@ -54,9 +211,18 @@ int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DRYRUN
|
#ifndef DRYRUN
|
||||||
const char *cpDrivePath = drive->getPath().c_str();
|
const char* cpDrivePath = drive->getPath().c_str();
|
||||||
unsigned char ucKey[TFNG_KEY_SIZE];
|
unsigned char ucKey[TFNG_KEY_SIZE];
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
// Validate buffers were allocated
|
||||||
|
if (caTfngData == nullptr || caReadBuffer == nullptr)
|
||||||
|
{
|
||||||
|
Logger::logThis()->error("Shred-Task: Aligned buffers not allocated! - Drive: " + drive->getSerial());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// open random source
|
// open random source
|
||||||
randomSrcFileDiscr = open(randomsrc, O_RDONLY | O_LARGEFILE);
|
randomSrcFileDiscr = open(randomsrc, O_RDONLY | O_LARGEFILE);
|
||||||
if (randomSrcFileDiscr == -1)
|
if (randomSrcFileDiscr == -1)
|
||||||
@@ -94,41 +260,59 @@ int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
|||||||
|
|
||||||
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
|
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
|
||||||
Drive::ShredSpeed shredSpeed = drive->sShredSpeed.load();
|
Drive::ShredSpeed shredSpeed = drive->sShredSpeed.load();
|
||||||
shredSpeed.chronoShredTimestamp = std::chrono::system_clock::now(); // set inital timestamp for speed metric
|
shredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();
|
||||||
shredSpeed.ulSpeedMetricBytesWritten = 0U; // uses to calculate speed metric
|
shredSpeed.ulSpeedMetricBytesWritten = 0U;
|
||||||
drive->sShredSpeed.store(shredSpeed);
|
drive->sShredSpeed.store(shredSpeed);
|
||||||
|
|
||||||
#ifdef LOG_LEVEL_HIGH
|
#ifdef LOG_LEVEL_HIGH
|
||||||
Logger::logThis()->info("Shred-Task: Bytes-Size of Drive: " + to_string(this->ulDriveByteSize) + " - Drive: " + drive->getSerial());
|
Logger::logThis()->info("Shred-Task: Bytes-Size of Drive: " + to_string(this->ulDriveByteSize) + " - Drive: " + drive->getSerial());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
// Start first measurement interval
|
||||||
|
startMeasurement();
|
||||||
|
#endif
|
||||||
|
|
||||||
for (unsigned int uiShredIterationCounter = 0U; uiShredIterationCounter < SHRED_ITERATIONS; uiShredIterationCounter++)
|
for (unsigned int uiShredIterationCounter = 0U; uiShredIterationCounter < SHRED_ITERATIONS; uiShredIterationCounter++)
|
||||||
{
|
{
|
||||||
unsigned long ulDriveByteCounter = 0U; // used for one shred-iteration to keep track of the current drive position
|
unsigned long ulDriveByteCounter = 0U;
|
||||||
|
|
||||||
if (uiShredIterationCounter == (SHRED_ITERATIONS - 1))
|
if (uiShredIterationCounter == (SHRED_ITERATIONS - 1))
|
||||||
{
|
{
|
||||||
// last shred iteration --> overwrite (just the write chunk) bytes with zeros instead with random data
|
// last shred iteration --> overwrite (just the write chunk) bytes with zeros instead with random data
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
memset(caTfngData, 0U, CHUNK_SIZE_MAX);
|
||||||
|
#else
|
||||||
memset(caTfngData, 0U, CHUNK_SIZE);
|
memset(caTfngData, 0U, CHUNK_SIZE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ulDriveByteCounter < ulDriveByteSize)
|
while (ulDriveByteCounter < ulDriveByteSize)
|
||||||
{
|
{
|
||||||
int iBytesToShred = 0; // Bytes that will be overwritten in this chunk-iteration
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
size_t activeChunkSize = getCurrentChunkSize();
|
||||||
|
#else
|
||||||
|
size_t activeChunkSize = CHUNK_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int iBytesToShred = 0;
|
||||||
|
|
||||||
if (uiShredIterationCounter != (SHRED_ITERATIONS - 1))
|
if (uiShredIterationCounter != (SHRED_ITERATIONS - 1))
|
||||||
{
|
{
|
||||||
// NOT last shred iteration --> generate new random data
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
tfng_prng_genrandom(caTfngData, activeChunkSize);
|
||||||
|
#else
|
||||||
tfng_prng_genrandom(caTfngData, TFNG_DATA_SIZE);
|
tfng_prng_genrandom(caTfngData, TFNG_DATA_SIZE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ulDriveByteSize - ulDriveByteCounter) < CHUNK_SIZE)
|
if ((ulDriveByteSize - ulDriveByteCounter) < activeChunkSize)
|
||||||
{
|
{
|
||||||
iBytesToShred = (ulDriveByteSize - ulDriveByteCounter);
|
iBytesToShred = (ulDriveByteSize - ulDriveByteCounter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iBytesToShred = CHUNK_SIZE;
|
iBytesToShred = activeChunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iByteShredded = write(driveFileDiscr, caTfngData, iBytesToShred);
|
int iByteShredded = write(driveFileDiscr, caTfngData, iBytesToShred);
|
||||||
@@ -148,17 +332,28 @@ int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
|||||||
|
|
||||||
ulDriveByteCounter += iByteShredded;
|
ulDriveByteCounter += iByteShredded;
|
||||||
ulDriveByteOverallCount += iByteShredded;
|
ulDriveByteOverallCount += iByteShredded;
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
bytesWrittenInMeasurement += iByteShredded;
|
||||||
|
chunkCounter++;
|
||||||
|
|
||||||
|
// Evaluate throughput after measurement interval
|
||||||
|
if (chunkCounter >= CHUNK_MEASURE_INTERVAL)
|
||||||
|
{
|
||||||
|
evaluateThroughput(drive);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
d32Percent = this->calcProgress();
|
d32Percent = this->calcProgress();
|
||||||
|
|
||||||
#ifdef LOG_LEVEL_HIGH
|
#ifdef LOG_LEVEL_HIGH
|
||||||
Logger::logThis()->info("Shred-Task: ByteCount: " + to_string(ulDriveByteCounter) + " - iteration: " + to_string((uiShredIterationCounter + 1)) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
|
Logger::logThis()->info("Shred-Task: ByteCount: " + to_string(ulDriveByteCounter) + " - iteration: " + to_string((uiShredIterationCounter + 1)) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((d32Percent - d32TmpPercent) >= 0.01)
|
if ((d32Percent - d32TmpPercent) >= 0.01)
|
||||||
{
|
{
|
||||||
// set shred percantage
|
|
||||||
drive->setTaskPercentage(d32TmpPercent);
|
drive->setTaskPercentage(d32TmpPercent);
|
||||||
d32TmpPercent = d32Percent;
|
d32TmpPercent = d32Percent;
|
||||||
// signal process in shreding
|
|
||||||
write(*ipSignalFd, "A", 1);
|
write(*ipSignalFd, "A", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,26 +363,32 @@ int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
|||||||
d32Percent = 0.00;
|
d32Percent = 0.00;
|
||||||
d32TmpPercent = 0.00;
|
d32TmpPercent = 0.00;
|
||||||
ulDriveByteCounter = 0U;
|
ulDriveByteCounter = 0U;
|
||||||
Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial());
|
Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial());
|
||||||
cleanup();
|
cleanup();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// end one chunk write
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != iRewindDrive(driveFileDiscr))
|
if (0 != iRewindDrive(driveFileDiscr))
|
||||||
{
|
{
|
||||||
Logger::logThis()->error("Shred-Task: Unable to rewind drive! - Drive: " + drive->getSerial());
|
Logger::logThis()->error("Shred-Task: Unable to rewind drive! - Drive: " + drive->getSerial());
|
||||||
cleanup();
|
cleanup();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// end one shred iteration
|
|
||||||
}
|
}
|
||||||
// end of all shred iteratio
|
|
||||||
|
|
||||||
tfng_prng_seedkey(NULL); // reset random generator
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
Logger::logThis()->info("Shred completed - Optimal chunk size: " +
|
||||||
|
to_string(bestChunkSize / (1024 * 1024)) + " MB, " +
|
||||||
|
"Best throughput: " + to_string((int)bestThroughputMBps) + " MB/s" +
|
||||||
|
" - Drive: " + drive->getSerial());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tfng_prng_seedkey(NULL);
|
||||||
|
|
||||||
drive->bWasShredded = true;
|
drive->bWasShredded = true;
|
||||||
Logger::logThis()->info("Shred-Task finished - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
Logger::logThis()->info("Shred-Task finished - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
||||||
|
|
||||||
#ifdef ZERO_CHECK
|
#ifdef ZERO_CHECK
|
||||||
drive->state = Drive::TaskState::CHECK_ACTIVE;
|
drive->state = Drive::TaskState::CHECK_ACTIVE;
|
||||||
Logger::logThis()->info("Check-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
Logger::logThis()->info("Check-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
||||||
@@ -219,10 +420,9 @@ int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief calc shredding progress in %
|
* \brief calc shredding progress in %
|
||||||
* \param current byte index of the drive
|
|
||||||
* \param current shred iteration
|
|
||||||
* \return double percentage
|
* \return double percentage
|
||||||
*/
|
*/
|
||||||
double Shred::calcProgress()
|
double Shred::calcProgress()
|
||||||
@@ -230,7 +430,7 @@ double Shred::calcProgress()
|
|||||||
unsigned int uiMaxShredIteration = SHRED_ITERATIONS;
|
unsigned int uiMaxShredIteration = SHRED_ITERATIONS;
|
||||||
|
|
||||||
#ifdef ZERO_CHECK
|
#ifdef ZERO_CHECK
|
||||||
uiMaxShredIteration++; // increment because we will check after SHRED_ITERATIONS the drive for non-zero bytes
|
uiMaxShredIteration++;
|
||||||
#endif
|
#endif
|
||||||
if (this->ulDriveByteSize == 0)
|
if (this->ulDriveByteSize == 0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
@@ -273,20 +473,27 @@ long Shred::getDriveSizeInBytes(fileDescriptor file)
|
|||||||
return liDriveSizeTmp;
|
return liDriveSizeTmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Shred::uiCalcChecksum(fileDescriptor file, Drive *drive, int *ipSignalFd)
|
unsigned int Shred::uiCalcChecksum(fileDescriptor file, Drive* drive, int* ipSignalFd)
|
||||||
{
|
{
|
||||||
unsigned int uiChecksum = 0;
|
unsigned int uiChecksum = 0;
|
||||||
unsigned long ulDriveByteCounter = 0U;
|
unsigned long ulDriveByteCounter = 0U;
|
||||||
|
|
||||||
|
#ifdef ADAPTIVE_CHUNK_SIZE
|
||||||
|
size_t checkChunkSize = CHUNK_SIZE_MAX;
|
||||||
|
#else
|
||||||
|
size_t checkChunkSize = CHUNK_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
while (ulDriveByteCounter < ulDriveByteSize)
|
while (ulDriveByteCounter < ulDriveByteSize)
|
||||||
{
|
{
|
||||||
int iBytesToCheck = 0;
|
int iBytesToCheck = 0;
|
||||||
if ((ulDriveByteSize - ulDriveByteCounter) < CHUNK_SIZE)
|
if ((ulDriveByteSize - ulDriveByteCounter) < checkChunkSize)
|
||||||
{
|
{
|
||||||
iBytesToCheck = (ulDriveByteSize - ulDriveByteCounter);
|
iBytesToCheck = (ulDriveByteSize - ulDriveByteCounter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iBytesToCheck = CHUNK_SIZE;
|
iBytesToCheck = checkChunkSize;
|
||||||
}
|
}
|
||||||
int iReadBytes = read(file, caReadBuffer, iBytesToCheck);
|
int iReadBytes = read(file, caReadBuffer, iBytesToCheck);
|
||||||
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
|
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
|
||||||
|
|||||||
Reference in New Issue
Block a user