[core] add alternate cheat mode for fast zeroing

* Ctrl-Alt-Z can now be used to zero a drive, while skipping blocks that are detected empty
* Depending on your hardware, as well as the existing drive content, this strategy can greatly
  speed up zeroing operations, especially if the flash memory's read speed is much higher than
  its write speed.
* Closes #1174
This commit is contained in:
René van der Zee 2018-07-06 12:35:22 +01:00 committed by Pete Batard
parent a394b9731a
commit 77bf5c8a49
5 changed files with 91 additions and 16 deletions

View File

@ -19,6 +19,7 @@ o Version 1.0.24 (2018.??.??)
- *NEW* MSG_087
- *NEW* MSG_172
- *NEW* MSG_199
- *NEW* MSG_306
o Version 1.0.23 (2018.03.27)
- All positioning ('m', 's') has now been removed as well as some controls, for the 3.0 UI redesign

View File

@ -567,6 +567,7 @@ t MSG_303 "Show the log"
t MSG_304 "Create a disk image of the selected device"
t MSG_305 "Use this option to indicate whether you want to use this device to install Windows on another disk, "
"or if you want to run Windows directly from this drive (Windows To Go)."
t MSG_306 "Fast-zeroing drive: %0.1f%% completed"
################################################################################
############################# TRANSLATOR END COPY ##############################

View File

@ -62,7 +62,7 @@ static int task_number = 0;
extern const int nb_steps[FS_MAX];
extern uint32_t dur_mins, dur_secs;
static int fs_index = 0, wintogo_index = -1;
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, enable_file_indexing, write_as_image;
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing, write_as_image;
uint8_t *grub2_buf = NULL;
long grub2_len;
static BOOL WritePBR(HANDLE hLogicalDrive);
@ -1548,11 +1548,12 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
{
BOOL s, ret = FALSE;
LARGE_INTEGER li;
DWORD rSize, wSize, BufSize;
DWORD rSize, wSize, xSize, BufSize;
uint64_t wb, target_size = hSourceImage?img_report.image_size:SelectedDrive.DiskSize;
int64_t bled_ret;
uint8_t *buffer = NULL;
int i;
uint8_t *cmp_buffer = NULL;
int i, throttle_fast_zeroing = 0;
// We poked the MBR and other stuff, so we need to rewind
li.QuadPart = 0;
@ -1572,7 +1573,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
goto out;
}
} else {
uprintf(hSourceImage?"Writing Image...":"Zeroing drive...");
uprintf(hSourceImage?"Writing Image...":fast_zeroing?"Fast-zeroing drive...":"Zeroing drive...");
// Our buffer size must be a multiple of the sector size and *ALIGNED* to the sector size
BufSize = ((DD_BUFFER_SIZE + SelectedDrive.SectorSize - 1) / SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
buffer = (uint8_t*)_mm_malloc(BufSize, SelectedDrive.SectorSize);
@ -1581,12 +1582,18 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
uprintf("Could not allocate disk write buffer");
goto out;
}
// Sanity check
if ((uintptr_t)buffer % SelectedDrive.SectorSize != 0) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT;
uprintf("Write buffer is not aligned");
assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0);
// Clear buffer
memset(buffer, fast_zeroing ? 0xff : 0x00, BufSize);
cmp_buffer = (uint8_t*)_mm_malloc(BufSize, SelectedDrive.SectorSize);
if (cmp_buffer == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY;
uprintf("Could not allocate disk comparison buffer");
goto out;
}
assert((uintptr_t)cmp_buffer % SelectedDrive.SectorSize == 0);
// Don't bother trying for something clever, using double buffering overlapped and whatnot:
// With Windows' default optimizations, sync read + sync write for sequential operations
@ -1596,7 +1603,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
if (GetTickCount64() > LastRefresh + MAX_REFRESH) {
LastRefresh = GetTickCount64();
format_percent = (100.0f*wb) / (1.0f*target_size);
PrintInfo(0, hSourceImage?MSG_261:MSG_286, format_percent);
PrintInfo(0, hSourceImage?MSG_261:fast_zeroing?MSG_306:MSG_286, format_percent);
UpdateProgress(OP_FORMAT, format_percent);
}
@ -1618,6 +1625,61 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
// WriteFile fails unless the size is a multiple of sector size
if (rSize % SelectedDrive.SectorSize != 0)
rSize = ((rSize + SelectedDrive.SectorSize - 1) / SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
// Fast-zeroing: Depending on your hardware, reading from flash may be much faster than writing, so
// we might speed things up by skipping empty blocks, or skipping the write if the data is the same.
// Notes: A block is declared empty when all bits are either 0 (zeros) or 1 (flash block erased).
// Also, a back-off strategy is used to limit reading.
if (throttle_fast_zeroing) {
throttle_fast_zeroing--;
} else if ((fast_zeroing) && (hSourceImage == NULL)) { // currently only enabled for erase
CHECK_FOR_USER_CANCEL;
// Read block and compare against the block that needs to be written
s = ReadFile(hPhysicalDrive, cmp_buffer, rSize, &xSize, NULL);
if ((!s) || (xSize != rSize) ) {
uprintf("Read error: Could not read data for comparison - %s", WindowsErrorString());
goto out;
}
// erase or write
if (hSourceImage == NULL) {
// Erase, check for an empty block
int *ptr = (int*)(cmp_buffer);
// Get first element
int value = ptr[0];
// Check all bits are the same
if ((value != 0) && (value != -1)) {
goto blocknotempty;
}
// Compare the rest of the block against the first element
for (i = 1; i < (int)(rSize/sizeof(int)); i++) {
if (ptr[i] != value)
goto blocknotempty;
}
// Block is empty, skip write
wSize = rSize;
continue;
blocknotempty:
;
} else if (memcmp(cmp_buffer, buffer, rSize) == 0) {
// Write, block is unchanged, skip write
wSize = rSize;
continue;
}
// Move the file pointer position back for writing
li.QuadPart = wb;
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) {
uprintf("Error: Could not reset position - %s", WindowsErrorString());
goto out;
}
// throttle read operations
throttle_fast_zeroing = 15;
}
for (i = 1; i <= WRITE_RETRIES; i++) {
CHECK_FOR_USER_CANCEL;
s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL);
@ -1649,6 +1711,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
ret = TRUE;
out:
safe_mm_free(buffer);
safe_mm_free(cmp_buffer);
return ret;
}

View File

@ -102,7 +102,7 @@ BOOL use_own_c32[NB_OLD_C32] = { FALSE, FALSE }, mbr_selected_by_user = FALSE;
BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE, right_to_left_mode = FALSE, has_uefi_csm;
BOOL enable_HDDs = FALSE, force_update = FALSE, enable_ntfs_compression = FALSE, no_confirmation_on_cancel = FALSE, lock_drive = TRUE;
BOOL advanced_mode_device, advanced_mode_format, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug;
BOOL use_fake_units, preserve_timestamps = FALSE;
BOOL use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALSE;
BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE, write_as_image = FALSE;
float fScale = 1.0f;
int dialog_showing = 0, selection_default = BT_IMAGE, windows_to_go_selection = 0, persistence_unit_selection = 0;
@ -3235,12 +3235,22 @@ relaunch:
// Alt-Z => Zero the drive
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Z')) {
zero_drive = TRUE;
fast_zeroing = FALSE;
// Simulate a button click for Start
PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0);
continue;
}
// Ctrl-Alt-Z => Zero the drive while trying to skip empty blocks
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'Z') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
zero_drive = TRUE;
fast_zeroing = TRUE;
// Simulate a button click for Start
PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0);
continue;
}
// Hazardous cheat modes require Ctrl + Alt
// Other hazardous cheat modes require Ctrl + Alt
// Ctrl-Alt-F => List non USB removable drives such as eSATA, etc - CAUTION!!!
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'F') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 3.2.1331"
CAPTION "Rufus 3.2.1332"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -392,8 +392,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,2,1331,0
PRODUCTVERSION 3,2,1331,0
FILEVERSION 3,2,1332,0
PRODUCTVERSION 3,2,1332,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -410,13 +410,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "3.2.1331"
VALUE "FileVersion", "3.2.1332"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2018 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "3.2.1331"
VALUE "ProductVersion", "3.2.1332"
END
END
BLOCK "VarFileInfo"