mirror of
https://github.com/martijnvanbrummelen/nwipe.git
synced 2026-02-20 13:42:14 +00:00
Merge pull request #683 from Knogle/feature/large-io-buffers-direct-io
Improve wipe I/O throughput with large aligned buffers and optional O_DIRECT
This commit is contained in:
93
src/nwipe.c
93
src/nwipe.c
@@ -27,6 +27,11 @@
|
||||
#define _POSIX_SOURCE
|
||||
#endif
|
||||
|
||||
/* Enable GNU extensions so that O_DIRECT is visible from <fcntl.h>. */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -59,6 +64,18 @@
|
||||
#include "hpa_dco.h"
|
||||
#include "conf.h"
|
||||
#include <libconfig.h>
|
||||
#include <fcntl.h> /* O_DIRECT, O_RDWR, ... */
|
||||
|
||||
#ifdef NWIPE_USE_DIRECT_IO
|
||||
#ifndef O_DIRECT
|
||||
/*
|
||||
* Some platforms or libcs do not define O_DIRECT at all. Defining it
|
||||
* as 0 makes the flag a no-op and keeps the code buildable.
|
||||
* On Linux/glibc, <fcntl.h> via nwipe.h will provide a real O_DIRECT.
|
||||
*/
|
||||
#define O_DIRECT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int terminate_signal;
|
||||
int user_abort;
|
||||
@@ -478,8 +495,80 @@ int main( int argc, char** argv )
|
||||
/* Initialise the wipe_status flag, -1 = wipe not yet started */
|
||||
c2[i]->wipe_status = -1;
|
||||
|
||||
/* Open the file for reads and writes. */
|
||||
c2[i]->device_fd = open( c2[i]->device_name, O_RDWR );
|
||||
/* Open the file for reads and writes, honoring the configured I/O mode. */
|
||||
int open_flags = O_RDWR;
|
||||
|
||||
#ifdef NWIPE_USE_DIRECT_IO
|
||||
/*
|
||||
* Decide whether to request O_DIRECT based on the runtime I/O mode:
|
||||
* auto -> try O_DIRECT, fall back to cached I/O if needed
|
||||
* direct -> force O_DIRECT, fail hard if not supported
|
||||
* cached -> do not request O_DIRECT at all
|
||||
*/
|
||||
if( nwipe_options.io_mode == NWIPE_IO_MODE_DIRECT || nwipe_options.io_mode == NWIPE_IO_MODE_AUTO )
|
||||
{
|
||||
open_flags |= O_DIRECT;
|
||||
}
|
||||
#endif
|
||||
|
||||
c2[i]->device_fd = open( c2[i]->device_name, open_flags );
|
||||
|
||||
#ifdef NWIPE_USE_DIRECT_IO
|
||||
if( c2[i]->device_fd < 0 && ( errno == EINVAL || errno == EOPNOTSUPP ) )
|
||||
{
|
||||
if( nwipe_options.io_mode == NWIPE_IO_MODE_DIRECT )
|
||||
{
|
||||
/*
|
||||
* User explicitly requested direct I/O: do not silently
|
||||
* fall back. Mark the device as unusable and continue.
|
||||
*/
|
||||
nwipe_perror( errno, __FUNCTION__, "open" );
|
||||
nwipe_log( NWIPE_LOG_FATAL,
|
||||
"O_DIRECT requested via --directio but not supported on '%s'.",
|
||||
c2[i]->device_name );
|
||||
c2[i]->select = NWIPE_SELECT_DISABLED;
|
||||
continue;
|
||||
}
|
||||
else if( nwipe_options.io_mode == NWIPE_IO_MODE_AUTO )
|
||||
{
|
||||
/*
|
||||
* Auto mode: transparently fall back to cached I/O and
|
||||
* log a warning.
|
||||
*/
|
||||
nwipe_log( NWIPE_LOG_WARNING,
|
||||
"O_DIRECT not supported on '%s', falling back to cached I/O.",
|
||||
c2[i]->device_name );
|
||||
|
||||
open_flags &= ~O_DIRECT;
|
||||
c2[i]->device_fd = open( c2[i]->device_name, open_flags );
|
||||
}
|
||||
}
|
||||
|
||||
if( c2[i]->device_fd >= 0 )
|
||||
{
|
||||
const char* io_desc;
|
||||
|
||||
if( open_flags & O_DIRECT )
|
||||
{
|
||||
io_desc = "direct I/O (O_DIRECT)";
|
||||
}
|
||||
else
|
||||
{
|
||||
io_desc = "cached I/O";
|
||||
}
|
||||
|
||||
nwipe_log( NWIPE_LOG_NOTICE, "Using %s on device '%s'.", io_desc, c2[i]->device_name );
|
||||
}
|
||||
#endif /* NWIPE_USE_DIRECT_IO */
|
||||
|
||||
/* Check the open() result (after any fallback logic). */
|
||||
if( c2[i]->device_fd < 0 )
|
||||
{
|
||||
nwipe_perror( errno, __FUNCTION__, "open" );
|
||||
nwipe_log( NWIPE_LOG_WARNING, "Unable to open device '%s'.", c2[i]->device_name );
|
||||
c2[i]->select = NWIPE_SELECT_DISABLED;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check the open() result. */
|
||||
if( c2[i]->device_fd < 0 )
|
||||
|
||||
@@ -161,6 +161,11 @@ int nwipe_options_parse( int argc, char** argv )
|
||||
/* Verify that wipe patterns are being written to the device. */
|
||||
{ "verify", required_argument, 0, 0 },
|
||||
|
||||
/* I/O mode selection: auto/direct/cached. */
|
||||
{ "directio", no_argument, 0, 0 },
|
||||
{ "cachedio", no_argument, 0, 0 },
|
||||
{ "io-mode", required_argument, 0, 0 },
|
||||
|
||||
/* Enables a field on the PDF that holds a tag that identifies the host computer */
|
||||
{ "pdftag", no_argument, 0, 0 },
|
||||
|
||||
@@ -207,6 +212,7 @@ int nwipe_options_parse( int argc, char** argv )
|
||||
nwipe_options.sync = DEFAULT_SYNC_RATE;
|
||||
nwipe_options.verbose = 0;
|
||||
nwipe_options.verify = NWIPE_VERIFY_LAST;
|
||||
nwipe_options.io_mode = NWIPE_IO_MODE_AUTO; /* Default: auto-select I/O mode. */
|
||||
nwipe_options.PDFtag = 0;
|
||||
memset( nwipe_options.logfile, '\0', sizeof( nwipe_options.logfile ) );
|
||||
memset( nwipe_options.PDFreportpath, '\0', sizeof( nwipe_options.PDFreportpath ) );
|
||||
@@ -421,6 +427,40 @@ int nwipe_options_parse( int argc, char** argv )
|
||||
exit( EINVAL );
|
||||
}
|
||||
|
||||
/* I/O mode selection options. */
|
||||
|
||||
if( strcmp( nwipe_options_long[i].name, "directio" ) == 0 )
|
||||
{
|
||||
nwipe_options.io_mode = NWIPE_IO_MODE_DIRECT;
|
||||
break;
|
||||
}
|
||||
|
||||
if( strcmp( nwipe_options_long[i].name, "cachedio" ) == 0 )
|
||||
{
|
||||
nwipe_options.io_mode = NWIPE_IO_MODE_CACHED;
|
||||
break;
|
||||
}
|
||||
|
||||
if( strcmp( nwipe_options_long[i].name, "io-mode" ) == 0 )
|
||||
{
|
||||
if( strcmp( optarg, "auto" ) == 0 )
|
||||
{
|
||||
nwipe_options.io_mode = NWIPE_IO_MODE_AUTO;
|
||||
}
|
||||
else if( strcmp( optarg, "direct" ) == 0 )
|
||||
{
|
||||
nwipe_options.io_mode = NWIPE_IO_MODE_DIRECT;
|
||||
}
|
||||
else if( strcmp( optarg, "cached" ) == 0 )
|
||||
{
|
||||
nwipe_options.io_mode = NWIPE_IO_MODE_CACHED;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( stderr, "Error: Unknown I/O mode '%s' (expected auto|direct|cached).\n", optarg );
|
||||
exit( EINVAL );
|
||||
}
|
||||
}
|
||||
if( strcmp( nwipe_options_long[i].name, "pdftag" ) == 0 )
|
||||
{
|
||||
nwipe_options.PDFtag = 1;
|
||||
@@ -818,6 +858,9 @@ void display_help()
|
||||
puts( " last - Verify after the last pass" );
|
||||
puts( " all - Verify every pass" );
|
||||
puts( " " );
|
||||
puts( " --directio Force direct I/O (O_DIRECT); fail if not supported" );
|
||||
puts( " --cachedio Force kernel cached I/O; never attempt O_DIRECT" );
|
||||
puts( " --io-mode=MODE I/O mode: auto (default), direct, cached\n" );
|
||||
puts( " Please mind that HMG IS5 enhanced always verifies the" );
|
||||
puts( " last (PRNG) pass regardless of this option.\n" );
|
||||
puts( " -m, --method=METHOD The wiping method. See man page for more details." );
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#define MAX_DRIVE_PATH_LENGTH 200 // e.g. /dev/sda is only 8 characters long, so 200 should be plenty.
|
||||
#define DEFAULT_SYNC_RATE 100000
|
||||
#define PATHNAME_MAX 2048
|
||||
#define NWIPE_USE_DIRECT_IO
|
||||
|
||||
/* Function prototypes for loading options from the environment and command line. */
|
||||
int nwipe_options_parse( int argc, char** argv );
|
||||
@@ -46,6 +47,13 @@ void nwipe_options_log( void );
|
||||
/* Function to display help text */
|
||||
void display_help();
|
||||
|
||||
/* I/O mode for data path: auto, direct, or cached. */
|
||||
typedef enum {
|
||||
NWIPE_IO_MODE_AUTO = 0, /* Try O_DIRECT, fall back to cached I/O if not supported. */
|
||||
NWIPE_IO_MODE_DIRECT, /* Force O_DIRECT, fail if not supported. */
|
||||
NWIPE_IO_MODE_CACHED /* Force cached I/O, never attempt O_DIRECT. */
|
||||
} nwipe_io_mode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int autonuke; // Do not prompt the user for confirmation when set.
|
||||
@@ -69,6 +77,7 @@ typedef struct
|
||||
int PDF_preview_details; // 0=Disable preview Org/Cust/date/time before drive selection, 1=Enable Preview
|
||||
int PDFtag; // Enable display of hostID, such as UUID or serial no. on PDF report.
|
||||
nwipe_verify_t verify; // A flag to indicate whether writes should be verified.
|
||||
nwipe_io_mode_t io_mode; // Runtime I/O mode selection (auto/direct/cached).
|
||||
} nwipe_options_t;
|
||||
|
||||
extern nwipe_options_t nwipe_options;
|
||||
|
||||
797
src/pass.c
797
src/pass.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user