&My::Web::footer call is deprecated now, use just: exit;
[www.jankratochvil.net.git] / project / captive / doc / CacheManager.pm
1 # $Id$
2 # Captive project doc Cache Manager page Perl template.
3 # Copyright (C) 2003-2005 Jan Kratochvil <project-www.jankratochvil.net@jankratochvil.net>
4
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
8
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.
13
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
17
18
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; };
22 our $CVS_ID=q$Id$;
23 use strict;
24 use warnings;
25
26 use My::Web;
27
28
29 sub handler
30 {
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',
36                 );
37
38
39 print <<"HERE";
40
41
42 <h1 id="cache_manager">NT Cache Manager</h1>
43
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&nbsp;File-system Cache' ]}</span>
50         they are definitely insufficient for compatible
51         <span class="productname">NT Cache Manager</span> reimplementation.</p>
52
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>
58
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>
70
71         @{[ doc_img 'dia/cache-manager',
72                         '<span class="productname">NT Cache Manager</span> Architecture' ]}
73
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>
83
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>
107
108         <p><span class="type">PCACHE_MANAGER_CALLBACKS</span> argument can be
109         safely ignored:</p>
110
111         <dl>
112                 <dt><span class="function">AcquireForReadAhead()</span>/<span class="function">ReleaseFromReadAhead()</span></dt>
113                 <dd>
114                         <p>As any readahead functionality is optional these entries are
115                         never used by Cache Manager implementation of this project.</p>
116                 </dd>
117
118                 <dt><span class="function">AcquireForLazyWrite()</span>/<span class="function">ReleaseFromLazyWrite()</span></dt>
119                 <dd>
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
125                         this project.</p>
126
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>
134                         pair.</p>
135                 </dd>
136         </dl>
137
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
157         gets clean in the
158         @{[ a_href 'Details.pm#sandbox','sandboxed environment' ]} soon anyway.</p>
159
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         &mdash; <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>
166
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>
170
171         <dl>
172                 <dt>Map</dt>
173                 <dd>
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>
177
178                         <p>Apparently Map size can be arbitrary long according
179                         to its <span class="type">SharedCacheMap</span> reserved space.</p>
180
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>
185                 </dd>
186
187                 <dt>Pin</dt>
188                 <dd>
189                         <p>Pin mapping always represents just one physical page
190                         (<span class="constant">PAGE_SIZE</span> &ndash; 4096 for i386).
191                         Its base offset/length can be safely extended to be aligned to the
192                         requested page.</p>
193
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>
201
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
211                         even in the
212                         @{[ a_href 'Details.pm#synchronous','single-threaded' ]} W32 implementation
213                         of this project as it is affecting the behaviour of Cache Manager.
214                         It was never
215                         @{[ a_href 'CacheManager.pm#TraceFS','seen' ]} how to behave if multiple dirty Pin
216                         mappings of the same page exist.</p>
217                 </dd>
218         </dl>
219
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&nbsp;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>
230
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>
240
241
242         <h2 id="TraceFS">TraceFS NT Cache Manager Tracer</h2>
243
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>
249
250                 @{[ doc_img 'dia/TraceFS','TraceFS Hooking' ]}
251
252                 <p>You must prepare your driver to be hooked
253                 (<span class="fname">ntfs.sys</span> in this case):</p>
254
255                 <blockquote class="command">
256                         <p>@{[ captive_srcfile './src/TraceFS/hookfs.pl' ]} ntfs.sys ./src/TraceFS/TraceFS-W32/TraceFS.sys &gt;hooked/ntfs.sys</p>
257                 </blockquote>
258
259                 <p>This <span class="fname">hooked/ntfs.sys</span> file must be replaced
260                 in the <span class="fname">%System32%\\drivers</span> directory.
261                 Beware as
262                 <span class="productname">Microsoft Windows</span>
263                 has many backups of these system files such as
264                 <span class="fname">%System32%\\dllcache</span> &mdash; delete them
265                 all!</p>
266
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>
272
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>
276
277                 @{[ doc_img 'ntdebug-windbg-boot','Successfuly connected <span class="productname">WinDbg</span>' ]}
278
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 &mdash; your target is to reach
283                 as few error messages as possible.</p>
284
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
295                 validator.</p>
296
297                 <h3 id="TraceFS_general">TraceFS for general API tracing</h3>
298
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 &ndash; it will hook exactly the exported entries.</p>
316
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
320                         fixes.</p>
321                 
322
323 HERE
324
325
326 exit;
327 }
328 1;