Fix_direct I/O, fdatasync

This fixes the following problems.
1. Fdatasync is incorrectly called when in direct I/O mode when
no --directio command line option is present, i.e when it
automatically determines whether direct or cached should be used.
2. When multiple drives are wiped if any of those drives do not
support direct I/O then they would have would have had fdatasync
incorrectly disabled. There was no record of I/O mode on a per
drive basis.
3. Direct I/O on a static pass always called fdatasync as there
was no code present to set the SyncRate to 0 when in direct I/O
mode.
This commit is contained in:
PartialVolume
2026-01-02 01:14:12 +00:00
parent bd1e8af845
commit 94548ad739
4 changed files with 43 additions and 22 deletions

View File

@@ -59,6 +59,13 @@ typedef enum nwipe_select_t_ {
NWIPE_SELECT_DISABLED // Do not wipe this device and do not allow it to be selected.
} nwipe_select_t;
/* 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;
#define NWIPE_KNOB_SPEEDRING_SIZE 30
#define NWIPE_KNOB_SPEEDRING_GRANULARITY 10
@@ -199,6 +206,7 @@ typedef struct nwipe_context_t_
char HPA_size_text[NWIPE_DEVICE_SIZE_TXT_LENGTH]; // Human readable size bytes, KB, MB, GB ..
int HPA_display_toggle_state; // 0 or 1 Used to toggle between "[1TB] [ 33C]" and [HDA STATUS]
time_t HPA_toggle_time; // records a time, then if for instance 3 seconds has elapsed the display changes
nwipe_io_mode_t io_mode; // specific I/O method for a given drive, direct or cached.
int test_use1;
int test_use2;

View File

@@ -738,10 +738,12 @@ int main( int argc, char** argv )
if( open_flags & O_DIRECT )
{
io_desc = "direct I/O (O_DIRECT)";
c2[i]->io_mode = NWIPE_IO_MODE_DIRECT;
}
else
{
io_desc = "cached I/O";
c2[i]->io_mode = NWIPE_IO_MODE_CACHED;
}
nwipe_log( NWIPE_LOG_NOTICE, "Using %s on device '%s'.", io_desc, c2[i]->device_name );

View File

@@ -23,6 +23,8 @@
#ifndef OPTIONS_H_
#define OPTIONS_H_
#include "method.h"
/* Program knobs. */
#define NWIPE_KNOB_IDENTITY_SIZE 512
#define NWIPE_KNOB_LABEL_SIZE 128
@@ -47,13 +49,6 @@ 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.
@@ -77,7 +72,8 @@ 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_io_mode_t io_mode; // Global runtime I/O mode selection (auto/direct/cached), note in auto mode each
// drive may use a different I/O mode if directIO isn't supported on a given drive.
} nwipe_options_t;
extern nwipe_options_t nwipe_options;

View File

@@ -386,18 +386,22 @@ int nwipe_random_pass( NWIPE_METHOD_SIGNATURE )
int syncRate = nwipe_options.sync;
/* For direct I/O we do not need periodic fdatasync(), I/O errors are detected
* at write() time. Keep sync for cached I/O only. */
if( nwipe_options.io_mode == NWIPE_IO_MODE_DIRECT )
{
syncRate = 0;
}
/* Select effective I/O block size (e.g. 4 MiB, never smaller than st_blksize). */
io_blocksize = nwipe_effective_io_blocksize( c );
/* Compute the per-write sync rate based on io_blocksize and old semantics. */
syncRate = nwipe_compute_sync_rate_for_device( c, io_blocksize );
/* For direct I/O we do not need periodic fdatasync(), I/O errors are detected
* at write() time. Keep sync for cached I/O only. */
if( c->io_mode == NWIPE_IO_MODE_DIRECT )
{
syncRate = 0;
nwipe_log( NWIPE_LOG_NOTICE, "Disabled fdatasync for %s, DirectI/O in use.", c->device_name );
}
else /* for cached I/O only */
{
/* Compute the per-write sync rate based on io_blocksize and old semantics. */
syncRate = nwipe_compute_sync_rate_for_device( c, io_blocksize );
}
int i = 0;
int idx;
@@ -824,6 +828,22 @@ int nwipe_static_pass( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern )
u64 z = c->device_size;
int syncRate = nwipe_options.sync;
io_blocksize = nwipe_effective_io_blocksize( c );
/* For direct I/O we do not need periodic fdatasync(), I/O errors are detected
* at write() time. Keep sync for cached I/O only. */
if( c->io_mode == NWIPE_IO_MODE_DIRECT )
{
syncRate = 0;
nwipe_log( NWIPE_LOG_NOTICE, "Disabled fdatasync for %s, DirectI/O in use.", c->device_name );
}
else /* for cached I/O only */
{
/* Compute per-write sync rate (same semantics as random pass). */
syncRate = nwipe_compute_sync_rate_for_device( c, io_blocksize );
}
int i = 0;
if( pattern == NULL )
@@ -838,11 +858,6 @@ int nwipe_static_pass( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern )
return -1;
}
io_blocksize = nwipe_effective_io_blocksize( c );
/* Compute per-write sync rate (same semantics as random pass). */
syncRate = nwipe_compute_sync_rate_for_device( c, io_blocksize );
/*
* For static patterns we want enough buffer space to always have a
* contiguous window of "io_blocksize" bytes available starting at any