mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Flush disks before the emergency spindown
This commit is contained in:
parent
d2671e7627
commit
b549bffd4c
3 changed files with 166 additions and 0 deletions
|
|
@ -263,6 +263,11 @@ int main(int argc, char* argv[])
|
|||
spindown_argv[1] = "down";
|
||||
spindown_argv[2] = 0;
|
||||
|
||||
/* sync all disks */
|
||||
printf("Flush...\n");
|
||||
if (sync() != 0)
|
||||
printf("WARNING! Failed to flush disks!\n");
|
||||
|
||||
snapraid_main(2, spindown_argv);
|
||||
}
|
||||
}
|
||||
|
|
@ -408,6 +413,10 @@ int main(int argc, char* argv[])
|
|||
/* ignore sigpipe to allow spindown even if the terminal is closed */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* sync all disks */
|
||||
printf("Flush...\n");
|
||||
sync();
|
||||
|
||||
snapraid_main(2, spindown_argv);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
151
cmdline/mingw.c
151
cmdline/mingw.c
|
|
@ -1047,6 +1047,157 @@ int windows_fsync(int fd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int windows_vsync(const wchar_t* volume)
|
||||
{
|
||||
HANDLE h;
|
||||
DWORD bytes;
|
||||
|
||||
/* open the volume (volumeName already in \\?\Volume{GUID} format) */
|
||||
h = CreateFileW(volume, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
windows_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* "The FlushFileBuffers API can be used to flush all the outstanding data
|
||||
* and metadata on a single file or a whole volume. However, frequent use
|
||||
* of this API can cause reduced throughput. Internally, Windows uses the
|
||||
* SCSI Synchronize Cache or the IDE/ATAPI Flush cache commands."
|
||||
*
|
||||
* From:
|
||||
* "Windows Write Caching - Part 2 An overview for Application Developers"
|
||||
* http://winntfs.com/2012/11/29/windows-write-caching-part-2-an-overview-for-application-developers/
|
||||
*/
|
||||
if (!FlushFileBuffers(h)) {
|
||||
DWORD error = GetLastError();
|
||||
CloseHandle(h);
|
||||
|
||||
switch (error) {
|
||||
case ERROR_INVALID_HANDLE :
|
||||
/*
|
||||
* FlushFileBuffers returns this error if the handle
|
||||
* doesn't support buffering, like the console output.
|
||||
*
|
||||
* We had a report that also ATA-over-Ethernet returns
|
||||
* this error, but not enough sure to ignore it.
|
||||
* So, we use now an extended error reporting.
|
||||
*/
|
||||
log_fatal("Unexpected Windows INVALID_HANDLE error in FlushFileBuffers().\n");
|
||||
log_fatal("Are you using ATA-over-Ethernet ? Please report it.\n");
|
||||
|
||||
/* normal error processing */
|
||||
windows_errno(error);
|
||||
return -1;
|
||||
|
||||
case ERROR_ACCESS_DENIED :
|
||||
/*
|
||||
* FlushFileBuffers returns this error for read-only
|
||||
* data, that cannot have to be flushed.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
default :
|
||||
windows_errno(error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* lock the volume (may fail if volume is in use, which is fine) */
|
||||
if (!DeviceIoControl(h, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) {
|
||||
DWORD error = GetLastError();
|
||||
CloseHandle(h);
|
||||
|
||||
switch (error) {
|
||||
case ERROR_ACCESS_DENIED :
|
||||
/*
|
||||
* ERROR_ACCESS_DENIED (5) means volume is in use - this is expected and OK
|
||||
*/
|
||||
return 0;
|
||||
|
||||
default :
|
||||
windows_errno(error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock immediately - the lock/unlock cycle helps ensure consistency */
|
||||
if (!DeviceIoControl(h, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) {
|
||||
DWORD error = GetLastError();
|
||||
CloseHandle(h);
|
||||
windows_errno(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!CloseHandle(h)) {
|
||||
windows_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int windows_async(void)
|
||||
{
|
||||
HANDLE h;
|
||||
wchar_t volume[MAX_PATH];
|
||||
DWORD error = 0;
|
||||
DWORD count = 0;
|
||||
DWORD success = 0;
|
||||
|
||||
h = FindFirstVolumeW(volume, sizeof(volume) / sizeof(wchar_t));
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
windows_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
/* remove trailing backslash */
|
||||
size_t len = wcslen(volume);
|
||||
if (len > 0 && volume[len - 1] == L'\\')
|
||||
volume[len - 1] = L'\0';
|
||||
|
||||
++count;
|
||||
|
||||
if (windows_vsync(volume) == 0) {
|
||||
++success;
|
||||
} else {
|
||||
/* save the first error */
|
||||
if (error == 0)
|
||||
error = GetLastError();
|
||||
}
|
||||
} while (FindNextVolumeW(h, volume, sizeof(volume) / sizeof(wchar_t)));
|
||||
|
||||
/* if at least one failed */
|
||||
if (count != success) {
|
||||
FindVolumeClose(h);
|
||||
windows_errno(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = GetLastError();
|
||||
if (error != ERROR_NO_MORE_FILES) {
|
||||
FindVolumeClose(h);
|
||||
windows_errno(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!FindVolumeClose(h)) {
|
||||
windows_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windows_sync(void)
|
||||
{
|
||||
if (windows_async() != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windows_futimens(int fd, struct windows_timespec tv[2])
|
||||
{
|
||||
HANDLE h;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
#define HAVE_FSYNC 1
|
||||
#undef fsync
|
||||
#define fsync windows_fsync
|
||||
#define sync windows_sync
|
||||
#undef rename
|
||||
#define rename windows_rename
|
||||
#undef remove
|
||||
|
|
@ -232,6 +233,11 @@ int windows_fallocate(int fd, int mode, off64_t off, off64_t len);
|
|||
*/
|
||||
int windows_fsync(int fd);
|
||||
|
||||
/**
|
||||
* Like the C sync().
|
||||
*/
|
||||
int windows_sync(void);
|
||||
|
||||
/**
|
||||
* Like the C futimes().
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue