Replace entities with xi:include
[Samba.git] / docs / devel / architecture.xml
blobfb1fe52546369408e15352a0e5febd7c4781a98e
1 <?xml version="1.0" encoding="iso-8859-1"?>
2 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
3                 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
4   <!ENTITY % global_entities SYSTEM '../entities/global.entities'>
5   %global_entities;
6 ]>
7 <chapter id="architecture">
8 <chapterinfo>
9         <author>
10                 <firstname>Dan</firstname><surname>Shearer</surname>
11         </author>
12         <pubdate> November 1997</pubdate>
13 </chapterinfo>
15 <title>Samba Architecture</title>
17 <sect1>
18 <title>Introduction</title>
20 <para>
21 This document gives a general overview of how Samba works
22 internally. The Samba Team has tried to come up with a model which is
23 the best possible compromise between elegance, portability, security
24 and the constraints imposed by the very messy SMB and CIFS
25 protocol. 
26 </para>
28 <para>
29 It also tries to answer some of the frequently asked questions such as:
30 </para>
32 <orderedlist>
33 <listitem><para>
34         Is Samba secure when running on Unix? The xyz platform?
35         What about the root priveliges issue?
36 </para></listitem>
38 <listitem><para>Pros and cons of multithreading in various parts of Samba</para></listitem>
40 <listitem><para>Why not have a separate process for name resolution, WINS, and browsing?</para></listitem>
42 </orderedlist>
44 </sect1>
46 <sect1>
47 <title>Multithreading and Samba</title>
49 <para>
50 People sometimes tout threads as a uniformly good thing. They are very
51 nice in their place but are quite inappropriate for smbd. nmbd is
52 another matter, and multi-threading it would be very nice. 
53 </para>
55 <para>
56 The short version is that smbd is not multithreaded, and alternative
57 servers that take this approach under Unix (such as Syntax, at the
58 time of writing) suffer tremendous performance penalties and are less
59 robust. nmbd is not threaded either, but this is because it is not
60 possible to do it while keeping code consistent and portable across 35
61 or more platforms. (This drawback also applies to threading smbd.)
62 </para>
64 <para>
65 The longer versions is that there are very good reasons for not making
66 smbd multi-threaded.  Multi-threading would actually make Samba much
67 slower, less scalable, less portable and much less robust. The fact
68 that we use a separate process for each connection is one of Samba's
69 biggest advantages.
70 </para>
72 </sect1>
74 <sect1>
75 <title>Threading smbd</title>
77 <para>
78 A few problems that would arise from a threaded smbd are:
79 </para>
81 <orderedlist>
82 <listitem><para>
83         It's not only to create threads instead of processes, but you
84         must care about all variables if they have to be thread specific
85         (currently they would be global).
86 </para></listitem>
88 <listitem><para>
89         if one thread dies (eg. a seg fault) then all threads die. We can
90         immediately throw robustness out the window.
91 </para></listitem>
93 <listitem><para>
94         many of the system calls we make are blocking. Non-blocking
95         equivalents of many calls are either not available or are awkward (and
96         slow) to use. So while we block in one thread all clients are
97         waiting. Imagine if one share is a slow NFS filesystem and the others 
98         are fast, we will end up slowing all clients to the speed of NFS.
99 </para></listitem>
101 <listitem><para>
102         you can't run as a different uid in different threads. This means
103         we would have to switch uid/gid on _every_ SMB packet. It would be
104         horrendously slow.
105 </para></listitem>
107 <listitem><para>
108         the per process file descriptor limit would mean that we could only
109         support a limited number of clients.
110 </para></listitem>
112 <listitem><para>
113         we couldn't use the system locking calls as the locking context of
114         fcntl() is a process, not a thread.
115 </para></listitem>
117 </orderedlist>
119 </sect1>
121 <sect1>
122 <title>Threading nmbd</title>
124 <para>
125 This would be ideal, but gets sunk by portability requirements.
126 </para>
128 <para>
129 Andrew tried to write a test threads library for nmbd that used only
130 ansi-C constructs (using setjmp and longjmp). Unfortunately some OSes
131 defeat this by restricting longjmp to calling addresses that are
132 shallower than the current address on the stack (apparently AIX does
133 this). This makes a truly portable threads library impossible. So to
134 support all our current platforms we would have to code nmbd both with
135 and without threads, and as the real aim of threads is to make the
136 code clearer we would not have gained anything. (it is a myth that
137 threads make things faster. threading is like recursion, it can make
138 things clear but the same thing can always be done faster by some
139 other method)
140 </para>
142 <para>
143 Chris tried to spec out a general design that would abstract threading
144 vs separate processes (vs other methods?) and make them accessible
145 through some general API. This doesn't work because of the data
146 sharing requirements of the protocol (packets in the future depending
147 on packets now, etc.) At least, the code would work but would be very
148 clumsy, and besides the fork() type model would never work on Unix. (Is there an OS that it would work on, for nmbd?)
149 </para>
151 <para>
152 A fork() is cheap, but not nearly cheap enough to do on every UDP
153 packet that arrives. Having a pool of processes is possible but is
154 nasty to program cleanly due to the enormous amount of shared data (in
155 complex structures) between the processes. We can't rely on each
156 platform having a shared memory system.
157 </para>
159 </sect1>
161 <sect1>
162 <title>nbmd Design</title>
164 <para>
165 Originally Andrew used recursion to simulate a multi-threaded
166 environment, which use the stack enormously and made for really
167 confusing debugging sessions. Luke Leighton rewrote it to use a
168 queuing system that keeps state information on each packet.  The
169 first version used a single structure which was used by all the
170 pending states.  As the initialisation of this structure was
171 done by adding arguments, as the functionality developed, it got
172 pretty messy.  So, it was replaced with a higher-order function
173 and a pointer to a user-defined memory block.  This suddenly
174 made things much simpler: large numbers of functions could be
175 made static, and modularised.  This is the same principle as used
176 in NT's kernel, and achieves the same effect as threads, but in
177 a single process.
178 </para>
180 <para>
181 Then Jeremy rewrote nmbd. The packet data in nmbd isn't what's on the
182 wire. It's a nice format that is very amenable to processing but still
183 keeps the idea of a distinct packet. See "struct packet_struct" in
184 nameserv.h.  It has all the detail but none of the on-the-wire
185 mess. This makes it ideal for using in disk or memory-based databases
186 for browsing and WINS support. 
187 </para>
189 </sect1>
190 </chapter>