2 # Captive project doc Cache Manager page Perl template.
3 # Copyright (C) 2003-2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; exactly version 2 of June 1991 is required
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 package project::captive::doc::CacheManager;
20 require 5.6.0; # at least 'use warnings;' but we need some 5.6.0+ modules anyway
21 our $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; };
31 BEGIN { Wuse 'project::captive::doc::Macros'; }
32 project::captive::doc::Macros->init(
33 "title"=>'Captive NTFS Developer Documentation: NT Cache Manager',
34 "rel_prev"=>'Reverse.pm',
35 "rel_next"=>'Details.pm',
42 <h1 id="cache_manager">NT Cache Manager</h1>
44 <p>Although there exist some 3rd party documents about
45 <span class="productname">NT Cache Manager</span> W32 subsystem such as
46 <span class="productname">@{[ a_href 'http://www.osr.com/ntinsider/1996/cacheman.htm',
47 'The NT Cache Manager Description' ]}</span> or
48 <span class="productname">@{[ a_href 'http://www.winntmag.com/Articles/Print.cfm?ArticleID=3864',
49 'Learn About NT'."'".'s File-system Cache' ]}</span>
50 they are definitely insufficient for compatible
51 <span class="productname">NT Cache Manager</span> reimplementation.</p>
53 <p><span class="productname">NT Cache Manager</span> is about mapping
54 filesystem objects such as regular file data, filesystem bitmap or
55 journalling zone (log file). It is also being used by the filesystem for
56 mapping of virtual volume files representing the whole underlying
57 filesystem device.</p>
59 <p>The original W32 <span class="productname">NT Cache Manager</span>
60 is much more complicated as it must coordinate its effort with
61 other W32 subsystems like mapping of executable files
62 (<span class="type">ImageSectionObject</span>), insufficient system
63 resources from <span class="productname">NT Memory Manager</span>
64 or general effort to perform caching features for system performance.</p>
65 <p><span class="productname">NT Cache Manager</span> of this project has much
66 simpler goal - it just needs to provide compatible
67 <span class="productname">NT Cache Manager</span> functionality while
68 the other goals of its W32 counterpart are left to be successfuly handled
69 by UNIX OS in much more efficient way.</p>
71 @{[ doc_img 'dia/cache-manager',
72 '<span class="productname">NT Cache Manager</span> Architecture' ]}
74 <p>Cache Manager objects are always bound to
75 <span class="type">FCB</span> (File Control Block).
76 <span class="type">FileObject</span> (or its associated
77 <span class="type">HANDLE</span>) serve only as reference
78 to <span class="type">FCB</span> and there can be multiple
79 <span class="type">FileObject</span>/<span class="type">HANDLE</span>
80 items for one <span class="type">FCB</span>. It is a bit misleading
81 you must use <span class="type">FileObject</span> pointer while calling
82 most of the Cache Manager functions.</p>
84 <p>Before using any other Cache Manager functions you must first call
85 <span class="function">CcInitializeCacheMap()</span>. You must give the
86 maximum mapped object offset. Each mapped object byte must have at most one
87 mapped memory location - no shared pages are allowed. Also any subsequent
88 mapping request is expected to be mapped into continuous memory region.
89 It implies you must reserve the memory region for possible future mapping
90 during the initial <span class="function">CcInitializeCacheMap()</span>
91 moment sized according to the given maximum mapped object offset.
92 This is the approach currently implemented by this project although it
93 cannot be used for 3rd party <span class="fname">ext2fsd.sys</span>
94 driver as it initialized Cache Manager by the whole media device size
95 and it surprisingly succeeds for original
96 <span class="productname">Microsoft Windows</span>
97 <span class="productname">Cache Manager</span>.
98 I expect the space reservation should be postponed to the first mapping
99 request and expect no multiple mappings will be done in the case
100 of memory-exceeding <span class="function">CcInitializeCacheMap()</span>
101 reservation request. <span class="function">CcSetFileSizes()</span>
102 changing the reserved memory area size may assume no existing Map
103 or Pin mappings exist. Only in the case of
104 <span class="constant">FO_STREAM_FILE</span> (virtual device file)
105 it is permitted to extend mapped size even in the case of existing
106 (and dirty) Map or Pin mappings.</p>
108 <p><span class="type">PCACHE_MANAGER_CALLBACKS</span> argument can be
112 <dt><span class="function">AcquireForReadAhead()</span>/<span class="function">ReleaseFromReadAhead()</span></dt>
114 <p>As any readahead functionality is optional these entries are
115 never used by Cache Manager implementation of this project.</p>
118 <dt><span class="function">AcquireForLazyWrite()</span>/<span class="function">ReleaseFromLazyWrite()</span></dt>
120 <p>Even the write-behind functionality is optional for Cache Manager.
121 It is being done in asynchronous way in the original
122 <span class="productname">Microsoft Windows</span>
123 <span class="productname">Cache Manager</span>.
124 implementation and it is ignored by Cache Manager implementation of
127 <p>Cache Manager does not need to write any data if not explicitely
128 requested by the driver. It is even expected to silently drop any
129 pending dirty data blocks during filesystem shutdown.
130 Forced dirty block write by function
131 <span class="function">CcFlushCache()</span> should be written without
132 any wrapping surrounding
133 <span class="function">AcquireForLazyWrite()</span>/<span class="function">ReleaseFromLazyWrite()</span>
138 <p><span class="function">CcUninitializeCacheMap()</span> is just
139 a suggestion for Cache Manager that driver will no longer reference
140 given <span class="type">SharedCacheMap</span>. The uninitialization
141 can be postponed to any later moment in original
142 <span class="productname">Microsoft Windows</span>
143 <span class="productname">Cache Manager</span>
144 as it may be locked by existing
145 <span class="type">ImageSectionObject</span>
146 of some file being executed etc.
147 <span id="sharedcachemap_leak">It is fatal to destroy
148 <span class="type">SharedCacheMap</span></span>
149 in the moment you see no other
150 references to it as the driver will access it for some moment
151 even after <span class="function">CcUninitializeCacheMap()</span>.
152 I am not sure if it is a bug of the driver or whether there are some rules
153 how long after <span class="function">CcUninitializeCacheMap()</span>
154 completion given <span class="type">SharedCacheMap</span> still exists.
155 Fortunately it is safe to never destroy
156 <span class="type">SharedCacheMap</span> and leave it leaked - everything
158 @{[ a_href 'Details.pm#sandbox','sandboxed environment' ]} soon anyway.</p>
160 <p>There exist Map and Pin type objects for each
161 <span class="type">SharedCacheMap</span> although they look very similiar.
162 Only these objects give you access to any memory data
163 — <span class="type">SharedCacheMap</span> only reserved the space
164 to ensure continuous mapping of the forthcoming mappings but it did not map
165 any data into it.</p>
167 <p>Mapping of 'new' Map or Pin will create the new object only in the case
168 no such mapping exists now. Otherwise you will just get the reference to
169 the existing object with increased usecount.</p>
174 <p>Map mapping is always at most one for each
175 <span class="type">SharedCacheMap</span>. Base offset/length of such
176 mapping have no meaning as there can be only single Map.</p>
178 <p>Apparently Map size can be arbitrary long according
179 to its <span class="type">SharedCacheMap</span> reserved space.</p>
181 <p>You cannot modify the memory mapped by Map in any way.
182 As it is the same memory area (address) as the pages used by Pin
183 objects you always access the last modified version by possible
184 Pin of the same page.</p>
189 <p>Pin mapping always represents just one physical page
190 (<span class="constant">PAGE_SIZE</span> – 4096 for i386).
191 Its base offset/length can be safely extended to be aligned to the
194 <p>Pin can have associated pair of oldest and newest
195 <span class="type">LSN</span> (Linear Sequence Number). It can be
196 set by <span class="function">CcSetDirtyPinnedData()</span>
197 and Cache Manager always tracks the lowest and highest
198 reported <span class="type">LSN</span> for each page.
199 <span class="type">LSN</span> is assumed to be
200 <span class="constant">0</span> if not set.</p>
202 <p>Any existing Pin mapping will be reused for further mappings
203 as long as it is not ThreadOwned. In the moment you use
204 <span class="function">CcSetBcbOwnerPointer()</span> you will detach
205 the associated Pin pages from its
206 <span class="type">SharedCacheMap</span>.
207 Although they will further act as valid Pin mappings they will be no
208 longer reused during new Pin mapping of the same page.
209 There can exist multiple Pin mappings of the same page (although
210 sharing the same memory space). This detaching must be implemented
212 @{[ a_href 'Details.pm#synchronous','single-threaded' ]} W32 implementation
213 of this project as it is affecting the behaviour of Cache Manager.
215 @{[ a_href 'CacheManager.pm#TraceFS','seen' ]} how to behave if multiple dirty Pin
216 mappings of the same page exist.</p>
220 <p>Only the pages not yet present in the memory must be read from the disk.
221 You must not read any pages you do not need to as the driver does not
222 expect it and it would corrupt its data buffers. There is just a strict
223 difference between <span class="function">CcPinRead()</span> and
224 <span class="function">CcPinMappedData()</span> function calls where
225 <span class="function">CcPinRead()</span> is required to re-read its data
226 blocks even if they were currently already Map mapped (unless it was already
227 also Pin mapped at least once). On the opposite side
228 <span class="function">CcPinMappedData()</span> must not re-read the given
229 blocks, moreover it blocks are required to be already Map mapped by the caller.</p>
231 <p>Cache Manager of this project will destroy Pin or Map mappings after
232 their last unreferencing (in opposite of
233 @{[ a_href '#sharedcachemap_leak','leaked <span class="type">SharedCacheMap</span>' ]}).
234 Despite it any dirty pages may still be held as the pages
235 (including their <span class="type">LSN</span>s) are cached associated
236 with <span class="type">SharedCacheMap</span>. It may be also possible
237 original <span class="productname">Microsoft Windows</span>
238 <span class="productname">Cache Manager</span>
239 postpones Pin mapping destroy to later time but it does not matter.</p>
242 <h2 id="TraceFS">TraceFS NT Cache Manager Tracer</h2>
244 <p>@{[ a_href '#cache_manager','Cache Manager behaviour' ]} would be hard
245 to analyze just by @{[ a_href '#reverse','reverse engineering' ]} as it
246 is pretty complicated code cooperating with many other W32 kernel
247 subsystems. It was chosen as easier way to trace it instead and validate
248 all the Cache Manager assumptions by Cache Manager simulator.</p>
250 @{[ doc_img 'dia/TraceFS','TraceFS Hooking' ]}
252 <p>You must prepare your driver to be hooked
253 (<span class="fname">ntfs.sys</span> in this case):</p>
255 <blockquote class="command">
256 <p>@{[ captive_srcfile './src/TraceFS/hookfs.pl' ]} ntfs.sys ./src/TraceFS/TraceFS-W32/TraceFS.sys >hooked/ntfs.sys</p>
259 <p>This <span class="fname">hooked/ntfs.sys</span> file must be replaced
260 in the <span class="fname">%System32%\\drivers</span> directory.
262 <span class="productname">Microsoft Windows</span>
263 has many backups of these system files such as
264 <span class="fname">%System32%\\dllcache</span> — delete them
267 <p>You also need to install
268 <span class="fname">./src/TraceFS/TraceFS-W32/TraceFS.sys</span>
269 into <span class="fname">%System32%\\drivers</span> directory
270 and import <span class="fname">TraceFS/TraceFS-W32/TraceFS.reg</span>
271 registry file to initialize the debug driver during system boot.</p>
273 <p>You can now pray a bit and snap the resulting Cache Manager tracing
274 from <span class="productname">WinDbg</span> by
275 @{[ a_href 'Reverse.pm#WinDbg','W32 remote kernel debugging' ]}:</p>
277 @{[ doc_img 'ntdebug-windbg-boot','Successfuly connected <span class="productname">WinDbg</span>' ]}
279 <p>The resulting trace file should be processed by
280 @{[ captive_srcfile './src/TraceFS/checktrace.pl' ]} Perl Cache Manager
281 implementation to validate its assumptions about Cache Manager behaviour.
282 Any seen incompatibilies will be reported — your target is to reach
283 as few error messages as possible.</p>
285 <p>KNOWN BUGS: Combination of message synchronization primitives and
286 implemented refusal to create journalling thread of
287 <span class="fname">ntfs.sys</span>
288 causes fatal system lockup in several advanced operations
289 such as setting compression attribute. Despite it more common operations
290 can be successfuly traced during the whole
291 <span class="productname">Microsoft Windows</span>
292 session including its final shutdown and such traces provide enough
293 material to be food to
294 @{[ captive_srcfile './src/TraceFS/checktrace.pl' ]} Perl Cache Manager
297 <h3 id="TraceFS_general">TraceFS for general API tracing</h3>
299 <p>Although TraceFS was up to now used only for tracing of
300 <span class="productname">NT Cache Manager</span> it can be easily
301 used ever for any other NT kernel API tracing. You need to provide
302 appropriate function wrappers in the main source file
303 @{[ captive_srcfile './src/TraceFS/TraceFS-W32/TraceFS.c' ]}.
304 Original system functions being wrapped should be called with their
305 original name. Your wrapping functions should have the first letter
306 of their name replaced by character
307 <span class="command">'T'</span>. Therefore wrapping of
308 <span class="function">CcInitializeCacheMap()</span> must be
309 done by your function
310 <span class="function">TcInitializeCacheMap()</span>.
311 Prototypes of both the wrapping and wrapped functions must be the same.
312 You must also export all the wrapped functions by
313 @{[ captive_srcfile './src/TraceFS/TraceFS-W32/TraceFS.def' ]}.
314 @{[ captive_srcfile './src/TraceFS/hookfs.pl' ]} has no hardcoded
315 function names – it will hook exactly the exported entries.</p>
317 <p>Framework for thread synchronizations and debug tracing is provided to
318 prevent mangling of messages while running by multiple threads at once.
319 Testing was done just on uniprocessor machine, SMP kernel may need some