win-power-mgmt-flush-test-20041003

The windows power management code responds to a request to suspend or
hibernate by performing a "fs flushvol" as the logged in user on each
of the SMB/CIFS mounted shares.  This can be very time consuming if
the cell servers cannot be reached.

This patch adds a test to ensure that there is at least one network
adapter in the machine which is not a loopback adapter.

While developing this patch other areas of concern have been raised.
The power management code waits a fixed period of time based upon
the hard dead timeout before allowing the suspend/hibernate to continue.
This allows the machine to shutdown even if there are active flush
operations being performed.  This defeats the benefit of performing
the flush at all.

A better mechanism could be developed if the functions called via
cm_IoctlFlushVolume returned and checked error codes.  Then it might
be possible to abandon the flush operation if a Server Not Reachable
state was obtained.

The power management flush operations will also not work on Terminal
Server.  This would be important in the case where a terminal server
is shutting down due to a switch over to a UPS.  The reason it does
not work on Terminal Server is that there is that it is not possible
for afsd_service.exe to enumerate the SMB/CIFS shares and impersonate
the individual logged in users.

It would be preferred for there to be a new cm_FlushAll() function
implemented which was not dependent on the use of the ioctl mechanism
for the purpose of identifying a volume ID or a user ID.
This commit is contained in:
Jeffrey Altman 2004-10-03 14:34:27 +00:00 committed by Jeffrey Altman
parent 3f2e943d43
commit 2469663d0d
4 changed files with 515 additions and 476 deletions

View File

@ -27,6 +27,9 @@
#include "afsd_flushvol.h"
#include "afsd_eventlog.h"
#include "lanahelper.h"
extern void afsi_log(char *pattern, ...);
static FLUSHVOLTHREADINFO gThreadInfo = {0};
static HANDLE gThreadHandle = NULL;
@ -48,6 +51,7 @@ afsd_ServicePerformFlushVolumeCmd(char *data)
register afs_int32 code;
struct ViceIoctl blob;
afsi_log("Flushing Volume \"%s\"",data);
memset(&blob, '\0', sizeof(blob));
code = pioctl(data, VIOC_FLUSHVOLUME, &blob, 0);
@ -74,6 +78,11 @@ afsd_ServicePerformFlushVolumes()
PCHAR pszShareName, pc;
afs_int32 afsRet = 0;
if ( lana_OnlyLoopback() ) {
// Nothing to do if we only have a loopback interface
return TRUE;
}
// Determine the root share name (\\AFS\ALL or \\<machine>-AFS\ALL),
// and the length of the server name prefix.
pszShareName = smb_GetSharename();
@ -143,8 +152,7 @@ afsd_ServicePerformFlushVolumes()
{
// got one!
// but we don't want to flush '\\[...]afs\all'
if (_stricmp(lpnr->lpRemoteName,
pszShareName) == 0)
if (_stricmp(lpnr->lpRemoteName, pszShareName) == 0)
continue;
++dwTotalVols;

View File

@ -32,7 +32,8 @@
// The following is defined if you want to receive Power notifications,
// including Hibernation, and also subsequent flushing of AFS volumes
//
#define REGISTER_POWER_NOTIFICATIONS
#define REGISTER_POWER_NOTIFICATIONS 1
#define FLUSH_VOLUME 1
//
// Check
*/
@ -130,7 +131,6 @@ afsd_ServiceFlushVolume(DWORD dwlpEventData)
{
dwRet = NO_ERROR;
}
else
{
/* flush was unsuccessful, or timeout - deny shutdown */
@ -276,7 +276,7 @@ afsd_ServiceControlHandlerEx(
case PBT_APMQUERYSUSPEND:
case PBT_APMQUERYSTANDBY:
#ifdef REGISTER_POWER_NOTIFICATIONS
#ifdef FLUSH_VOLUME
/* handle event */
dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
#else

View File

@ -394,6 +394,35 @@ extern "C" lana_number_t lana_FindLoopback(void)
return LANA_INVALID;
}
/* Returns TRUE if all adapters are loopback adapters */
extern "C" BOOL lana_OnlyLoopback(void)
{
NCB ncb;
LANA_ENUM lana_list;
int status;
int i;
memset(&ncb, 0, sizeof(ncb));
ncb.ncb_command = NCBENUM;
ncb.ncb_buffer = (UCHAR *) &lana_list;
ncb.ncb_length = sizeof(lana_list);
status = Netbios(&ncb);
if (status != 0) {
#ifndef NOLOGGING
afsi_log("Netbios NCBENUM failed: status %ld", status);
#endif
return FALSE;
}
for (i = 0; i < lana_list.length; i++) {
if (!lana_IsLoopback(lana_list.lana[i])) {
// Found one non-Loopback adapter
return FALSE;
}
}
// All adapters are loopback
return TRUE;
}
// Is the given lana a Windows Loopback Adapter?
// TODO: implement a better check for loopback
// TODO: also check for proper bindings (IPv4)

View File

@ -59,6 +59,8 @@ extern "C" {
lana_number_t lana_FindLoopback(void);
BOOL lana_OnlyLoopback(void);
BOOL lana_IsLoopback(lana_number_t lana);
long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags);