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_
|
||
|