211 lines
6.7 KiB
C
211 lines
6.7 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
namcache.h
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
The NAME_CACHE structure is used to remember the name strings of recent
|
|||
|
operations performed at the server so the client can suppress redundant
|
|||
|
requests. For example if an open has recently failed with file not found and
|
|||
|
the client app tries it again with an upcased string then we can fail it
|
|||
|
immediately with STATUS_OBJECT_NAME_NOT_FOUND without hitting the server. In
|
|||
|
general the algorithm is to put a time window and SMB operation count limit on
|
|||
|
the NAME_CACHE entry. The time window is usually 2 seconds so if NAME_CACHE
|
|||
|
entry is more than 2 seconds old the match will fail and the request will go to
|
|||
|
the server. If the request fails again at the server the NAME_CACHE is updated
|
|||
|
with another 2 second window. If the SMB operation count doesn't match then one
|
|||
|
or more SMBs have been sent to the server which could make this NAME_CACHE entry
|
|||
|
invalid. So again this operation will get sent to the server.
|
|||
|
|
|||
|
A NAME_CACHE struct has a mini-rdr portion and an RDBSS portion. The mini-rdr
|
|||
|
portion has a context field (see below), an NTSTATUS field for the result of a
|
|||
|
prior server operation on this name entry and a context extension pointer for
|
|||
|
some additional mini-rdr specific storage that can be co-allocated with the
|
|||
|
NAME_CACHE structure. See RxNameCacheInitialize().
|
|||
|
|
|||
|
The SMB operation count is an example of mini-rdr specific state which could be
|
|||
|
saved in the context field of MRX_NAME_CACHE. When the wrapper routine
|
|||
|
RxNameCacheCheckEntry() is called it will perform an equality check between the
|
|||
|
context field and a supplied parameter as part of finding a match in the name
|
|||
|
cache. When a NAME_CACHE entry is created or updated it is the mini-rdr's job
|
|||
|
to supply an appropriate value for this field.
|
|||
|
|
|||
|
The RDBSS portion of the NAME_CACHE struct contains the name (in a UNICODE
|
|||
|
STRING) and the expiration time of the entry. The MaximumEntries field is used
|
|||
|
to limit the number of NAME_CACHE entries created in case a poorly behaved
|
|||
|
program were to generate a large number of opens with bad file names and so
|
|||
|
consume large quanities of pool.
|
|||
|
|
|||
|
The NAME_CACHE_CONTROL struct is used to manage a given name cache. It has
|
|||
|
a free list, an active list and a lock used to synchronize updates.
|
|||
|
|
|||
|
Currently there are name caches for:
|
|||
|
1. OBJECT_NAME_NOT_FOUND - 2 second window, any SMB op sent to the
|
|||
|
server will invalidate it. This is because you could have the case
|
|||
|
where the client app has a file (foo) open which an app on the server could
|
|||
|
use to signal the creation of a file (bar) on the server. When the client
|
|||
|
reads file foo and learns that file bar has been created on the
|
|||
|
server then a hit in the name cache which matches bar can't return an
|
|||
|
error. So this optimization only handles the case of successive file
|
|||
|
opens on the same file which does not yet exist. Happens in WORD.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Orbits [davidor] 9-Sep-1996
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#ifndef _NAME_CACHE_DEFINED_
|
|||
|
#define _NAME_CACHE_DEFINED_
|
|||
|
|
|||
|
|
|||
|
#ifdef __cplusplus
|
|||
|
typedef struct _MRX_NAME_CACHE_ : public MRX_NORMAL_NODE_HEADER {
|
|||
|
#else // !__cplusplus
|
|||
|
typedef struct _MRX_NAME_CACHE_ {
|
|||
|
MRX_NORMAL_NODE_HEADER;
|
|||
|
#endif // __cplusplus
|
|||
|
|
|||
|
// !!!! changes above this require realignment with fcb.h
|
|||
|
|
|||
|
ULONG Context; // Operation Count snapshot when entry made
|
|||
|
PVOID ContextExtension; // Pointer to mini-rdr extension area
|
|||
|
NTSTATUS PriorStatus; // Saved Status from last attempt at operation
|
|||
|
|
|||
|
} MRX_NAME_CACHE, *PMRX_NAME_CACHE;
|
|||
|
|
|||
|
|
|||
|
#ifdef __cplusplus
|
|||
|
typedef struct _NAME_CACHE : public MRX_NAME_CACHE {
|
|||
|
// I didn't find any use of the spacer in the union below,
|
|||
|
// and the MRX_NAME_CACHE is by definition larger than
|
|||
|
// MRX_NORMAL_NODE_HEADER, so I didn't worry about the union
|
|||
|
#else // !__cplusplus
|
|||
|
typedef struct _NAME_CACHE {
|
|||
|
//
|
|||
|
// The portion of NAME_CACHE visible to mini redirectors.
|
|||
|
//
|
|||
|
union {
|
|||
|
MRX_NAME_CACHE;
|
|||
|
struct {
|
|||
|
MRX_NORMAL_NODE_HEADER spacer;
|
|||
|
};
|
|||
|
};
|
|||
|
#endif // __cplusplus
|
|||
|
//
|
|||
|
// The portion of NAME_CACHE visible to RDBSS.
|
|||
|
//
|
|||
|
LARGE_INTEGER ExpireTime; // Time when entry expires
|
|||
|
LIST_ENTRY Link; // Entry on free or active list
|
|||
|
UNICODE_STRING Name; // Cached name
|
|||
|
ULONG HashValue; // Hash value of name
|
|||
|
BOOLEAN CaseInsensitive; // Controls name string compare
|
|||
|
|
|||
|
} NAME_CACHE, *PNAME_CACHE;
|
|||
|
|
|||
|
|
|||
|
typedef struct _NAME_CACHE_CONTROL_ {
|
|||
|
|
|||
|
FAST_MUTEX NameCacheLock; // Lock to synchronize access to the list
|
|||
|
LIST_ENTRY ActiveList; // List of active name cache entries
|
|||
|
LIST_ENTRY FreeList; // Free list of NAME_CACHE structs
|
|||
|
ULONG EntryCount; // Current number of NAME_CACHE entries allocated
|
|||
|
ULONG MaximumEntries; // Max number of entries we will allocate
|
|||
|
ULONG MRxNameCacheSize; // Size of Mini-rdr storage area in entry
|
|||
|
//
|
|||
|
// Stats
|
|||
|
//
|
|||
|
ULONG NumberActivates; // Number of times cache was updated
|
|||
|
ULONG NumberChecks; // Number of times cache was checked
|
|||
|
ULONG NumberNameHits; // Number of times a valid match was returned
|
|||
|
ULONG NumberNetOpsSaved; // Number of times mini-rdr saved a net op
|
|||
|
|
|||
|
ULONG Spare[4];
|
|||
|
|
|||
|
} NAME_CACHE_CONTROL, *PNAME_CACHE_CONTROL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Return status for RxNameCacheCheckEntry()
|
|||
|
//
|
|||
|
typedef enum _RX_NC_CHECK_STATUS {
|
|||
|
RX_NC_SUCCESS = 0,
|
|||
|
RX_NC_TIME_EXPIRED,
|
|||
|
RX_NC_MRXCTX_FAIL
|
|||
|
} RX_NC_CHECK_STATUS;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Mini-rdr function to count the number of times the cached state avoided
|
|||
|
// a trip to the server.
|
|||
|
//
|
|||
|
#define RxNameCacheOpSaved(_NCC) (_NCC)->NumberNetOpsSaved += 1
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
RxNameCacheInitialize(
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN ULONG MRxNameCacheSize,
|
|||
|
IN ULONG MaximumEntries
|
|||
|
);
|
|||
|
|
|||
|
PNAME_CACHE
|
|||
|
RxNameCacheCreateEntry (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN PUNICODE_STRING Name,
|
|||
|
IN BOOLEAN CaseInsensitive
|
|||
|
);
|
|||
|
|
|||
|
PNAME_CACHE
|
|||
|
RxNameCacheFetchEntry (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN PUNICODE_STRING Name
|
|||
|
);
|
|||
|
|
|||
|
RX_NC_CHECK_STATUS
|
|||
|
RxNameCacheCheckEntry (
|
|||
|
IN PNAME_CACHE NameCache,
|
|||
|
IN ULONG MRxContext
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
RxNameCacheActivateEntry (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN PNAME_CACHE NameCache,
|
|||
|
IN ULONG LifeTime,
|
|||
|
IN ULONG MRxContext
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
RxNameCacheExpireEntry (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN PNAME_CACHE NameCache
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
RxNameCacheExpireEntryWithShortName (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN PUNICODE_STRING Name
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
RxNameCacheFreeEntry (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl,
|
|||
|
IN PNAME_CACHE NameCache
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
RxNameCacheFinalize (
|
|||
|
IN PNAME_CACHE_CONTROL NameCacheCtl
|
|||
|
);
|
|||
|
|
|||
|
#endif // _NAME_CACHE_DEFINED_
|
|||
|
|