Source code of Windows XP (NT5)
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
/*++
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_
|