fusd.tex 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013
  1. %
  2. %
  3. % FUSD - Framework for User-Space Devices
  4. % Programming Manual & Tutorial
  5. %
  6. % Jeremy Elson, (c) 2001 Sensoria Corporation, 2003 UCLA
  7. % Released under open-source, BSD license
  8. % See LICENSE file for full license
  9. %
  10. % $Id: fusd.tex,v 1.63 2003/08/20 22:00:55 jelson Exp $
  11. \documentclass{article}
  12. \addtolength{\topmargin}{-.5in} % repairing LaTeX's huge margins...
  13. \addtolength{\textheight}{1in} % more margin hacking
  14. \addtolength{\textwidth}{1.5in}
  15. \addtolength{\oddsidemargin}{-0.75in}
  16. \addtolength{\evensidemargin}{-0.75in}
  17. \usepackage{graphicx,float,alltt,tabularx}
  18. \usepackage{wrapfig,floatflt}
  19. \usepackage{amsmath}
  20. \usepackage{latexsym}
  21. \usepackage{moreverb}
  22. \usepackage{times}
  23. \usepackage{html}
  24. %\usepackage{draftcopy}
  25. %\setcounter{bottomnumber}{3}
  26. %\renewcommand{\topfraction}{0}
  27. %\renewcommand{\bottomfraction}{0.7}
  28. %\renewcommand{\textfraction}{0}
  29. %\renewcommand{\floatpagefraction}{2.0}
  30. \renewcommand{\topfraction}{1.0}
  31. \renewcommand{\bottomfraction}{1.0}
  32. \renewcommand{\textfraction}{0.0}
  33. \renewcommand{\floatpagefraction}{0.9}
  34. \floatstyle{ruled}
  35. \newfloat{Program}{tp}{lop}
  36. \title{FUSD:
  37. A Linux {\bf F}ramework for {\bf U}ser-{\bf S}pace {\bf D}evices}
  38. \author{Jeremy Elson\\
  39. jelson@circlemud.org\\
  40. http://www.circlemud.org/\tilde{}jelson/software/fusd}
  41. \date{19 August 2003, Documentation for FUSD 1.10}
  42. \begin{document}
  43. %%%%%%%%%%%%%%%%%%%%%%%%% Title Page %%%%%%%%%%%%%%%%%%%%%%%%%
  44. \begin{center}
  45. \begin{latexonly}\vspace*{2in}\end{latexonly}
  46. {\Huge FUSD:} \\
  47. \vspace{2\baselineskip}
  48. {\huge A Linux {\bf F}ramework for {\bf U}ser-{\bf S}pace {\bf D}evices}
  49. \begin{latexonly}\vspace{2in}\end{latexonly}
  50. \vspace{\baselineskip}
  51. \vfill
  52. {\large Jeremy Elson \\
  53. \begin{latexonly}\vspace{.5\baselineskip}\end{latexonly}}
  54. \vspace{\baselineskip}
  55. {\tt jelson@circlemud.org\\
  56. http://www.circlemud.org/jelson/software/fusd}
  57. \vspace{2\baselineskip}
  58. 19 August 2003\\
  59. Documentation for FUSD 1.10\\
  60. \end{center}
  61. \thispagestyle{empty}
  62. \clearpage
  63. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  64. \begin{latexonly}
  65. \pagenumbering{roman}
  66. \tableofcontents
  67. \bigskip
  68. \listof{Program}{List of Example Programs}
  69. \setlength{\parskip}{10pt}
  70. \clearpage
  71. \end{latexonly}
  72. % This resets the page counter to 1
  73. \pagenumbering{arabic}
  74. \addtolength{\parskip}{0.5\baselineskip}
  75. \section{Introduction}
  76. \subsection{What is FUSD?}
  77. FUSD (pronounced {\em fused}) is a Linux framework for proxying device
  78. file callbacks into user-space, allowing device files to be
  79. implemented by daemons instead of kernel code. Despite being
  80. implemented in user-space, FUSD devices can look and act just like any
  81. other file under /dev which is implemented by kernel callbacks.
  82. A user-space device driver can do many of the things that kernel
  83. drivers can't, such as perform a long-running computation, block while
  84. waiting for an event, or read files from the file system. Unlike
  85. kernel drivers, a user-space device driver can {\em use other device
  86. drivers}---that is, access the network, talk to a serial port, get
  87. interactive input from the user, pop up GUI windows, or read from
  88. disks. User-space drivers implemented using FUSD can be much easier
  89. to debug; it is impossible for them to crash the machine, are easily
  90. traceable using tools such as {\tt gdb}, and can be killed and
  91. restarted without rebooting even if they become corrupted. FUSD
  92. drivers don't have to be in C---Perl, Python, or any other language
  93. that knows how to read from and write to a file descriptor can work
  94. with FUSD. User-space drivers can be swapped out, whereas kernel
  95. drivers lock physical memory.
  96. Of course, as with almost everything, there are trade-offs.
  97. User-space drivers are slower than kernel drivers because they require
  98. three times as many system calls, and additional memory copies (see
  99. section~\ref{performance}). User-space drivers can not receive
  100. interrupts, and do not have the full power to modify arbitrary kernel
  101. data structures as kernel drivers do. Despite these limitations, we
  102. have found user-space device drivers to be a powerful programming
  103. paradigm with a wide variety of uses (see Section~\ref{use-cases}).
  104. FUSD is free software, distributed under a GPL-compatible license (the
  105. ``new'' BSD license, with the advertising clause removed).
  106. \subsection{How does FUSD work?}
  107. FUSD drivers are conceptually similar to kernel drivers: a set of
  108. callback functions called in response to system calls made on file
  109. descriptors by user programs. FUSD's C library provides a device
  110. registration function, similar to the kernel's {\tt
  111. devfs\_register\_chrdev()} function, to create new devices. {\tt
  112. fusd\_register()} accepts the device name and a structure full of
  113. pointers. Those pointers are callback functions which are called in
  114. response to certain user system calls---for example, when a process
  115. tries to open, close, read from, or write to the device file. The
  116. callback functions should conform to the standard definitions of POSIX
  117. system call behavior. In many ways, the user-space FUSD callback
  118. functions are identical to their kernel counterparts.
  119. Perhaps the best way to show what FUSD does is by example.
  120. Program~\ref{helloworld.c} is a simple FUSD device driver. When the
  121. program is run, a device called {\tt /dev/hello-world} appears under
  122. the {\tt /dev} directory. If that device is read (e.g., using {\tt
  123. cat}), the read returns {\tt Hello, world!} followed by an EOF.
  124. Finally, when the driver is stopped (e.g., by hitting Control-C), the
  125. device file disappears.
  126. \begin{Program}
  127. \listinginput[5]{1}{helloworld.c.example}
  128. \caption{helloworld.c: A simple program using FUSD to
  129. create {\tt /dev/hello-world}}
  130. \label{helloworld.c}
  131. \end{Program}
  132. On line 40 of the source, we use {\tt fusd\_register()} to create the
  133. {\tt /dev/hello-world} device, passing pointers to callbacks for the
  134. open(), close() and read() system calls. (Lines 36--39 use the GNU C
  135. extension that allows initializer field naming; the 2.4 series of
  136. Linux kernels use also that extension for the same purpose.) The
  137. ``Hello, World'' read() callback itself is virtually identical to what
  138. a kernel driver for this device would look like. It can inspect and
  139. modify the user's file pointer, copy data into the user-provided
  140. buffer, control the system call return value (either positive, EOF, or
  141. error), and so forth.
  142. The proxying of kernel system calls that makes this kind of program
  143. possible is implemented by FUSD, using a combination of a kernel
  144. module and cooperating user-space library. The kernel module
  145. implements a character device, {\tt /dev/fusd}, which is used as a
  146. control channel between the two. fusd\_register() uses this channel
  147. to send a message to the FUSD kernel module, telling the name of the
  148. device the user wants to register. The kernel module, in turn,
  149. registers that device with the kernel proper using devfs. devfs and
  150. the kernel don't know anything unusual is happening; it appears from
  151. their point of view that the registered devices are simply being
  152. implemented by the FUSD module.
  153. Later, when kernel makes a callback due to a system call (e.g.\ when
  154. the character device file is opened or read), the FUSD kernel module's
  155. callback blocks the calling process, marshals the arguments of the
  156. callback into a message and sends it to user-space. Once there, the
  157. library half of FUSD unmarshals it and calls whatever user-space
  158. callback the FUSD driver passed to fusd\_register(). When that
  159. user-space callback returns a value, the process happens in reverse:
  160. the return value and its side-effects are marshaled by the library
  161. and sent to the kernel. The FUSD kernel module unmarshals this
  162. message, matches it up with a corresponding outstanding request, and
  163. completes the system call. The calling process is completely unaware
  164. of this trickery; it simply enters the kernel once, blocks, unblocks,
  165. and returns from the system call---just as it would for any other
  166. blocking call.
  167. One of the primary design goals of FUSD is {\em stability}. It should
  168. not be possible for a FUSD driver to corrupt or crash the kernel,
  169. either due to error or malice. Of course, a buggy driver itself may
  170. corrupt itself (e.g., due to a buffer overrun). However, strict error
  171. checking is implemented at the user-kernel boundary which should
  172. prevent drivers from corrupting the kernel or any other user-space
  173. process---including the errant driver's own clients, and other FUSD
  174. drivers.
  175. \subsection{What FUSD {\em Isn't}}
  176. FUSD looks similar to certain other Linux facilities that are already
  177. available. It also skirts near a few of the kernel's hot-button
  178. political issues. So, to avoid confusion, we present a list of
  179. things that FUSD is {\em not}.
  180. \begin{itemize}
  181. \item {\bf A FUSD driver is not a kernel module.} Kernel modules
  182. allow---well, modularity of kernel code. They let you insert and
  183. remove kernel modules dynamically after the kernel boots. However,
  184. once inserted, the kernel modules are actually part of the kernel
  185. proper. They run in the kernel's address space, with all the same
  186. privileges and restrictions that native kernel code does. A FUSD
  187. device driver, in contrast, is more similar to a daemon---a program
  188. that runs as a user-space process, with a process ID.
  189. \item {\bf FUSD is not, and doesn't replace, devfs.} When a FUSD
  190. driver registers a FUSD device, it automatically creates a device file
  191. in {\tt /dev}. However, FUSD is not a replacement for devfs---quite
  192. the contrary, FUSD creates those device files by {\em using} devfs.
  193. In a normal Linux system, only kernel modules proper---not user-space
  194. programs---can register with devfs (see above).
  195. \item {\bf FUSD is not UDI.} UDI, the \htmladdnormallinkfoot{Uniform
  196. Driver Interface}{http://www.projectudi.org}, aims to create a binary
  197. API for drivers that is uniform across operating systems. It's true
  198. that FUSD could conceivably be used for a similar purpose (inasmuch as
  199. it defines a system call messaging structure). However, this was not
  200. the goal of FUSD as much as an accidental side effect. We do not
  201. advocate publishing drivers in binary-only form, even though FUSD does
  202. make this possible in some cases.
  203. \item {\bf FUSD is not an attempt to turn Linux into a microkernel.}
  204. We aren't trying to port existing drivers into user-space for a
  205. variety of reasons (not the least of which is performance). We've
  206. used FUSD as a tool to write new drivers that are much easier from
  207. user-space than they would be in the kernel; see
  208. Section~\ref{use-cases} for use cases.
  209. \end{itemize}
  210. \subsection{Related Work}
  211. FUSD is a new implementation, but certainly not a new idea---the
  212. theory of its operation is the same as any microkernel operating
  213. system. A microkernel (roughly speaking) is one that implements only
  214. very basic resource protection and message passing in the kernel.
  215. Implementation of device drivers, file systems, network stacks, and so
  216. forth are relegated to userspace. Patrick Bridges maintains a list of
  217. such \htmladdnormallinkfoot{microkernel operating systems}{http://www.cs.arizona.edu/people/bridges/os/microkernel.html}.
  218. Also related is the idea of a user-space filesystem, which has been
  219. implemented in a number of contexts. Some examples include Klaus
  220. Schauser's \htmladdnormallinkfoot{UFO
  221. Project}{http://www.cs.ucsb.edu/projects/ufo/index.html} for Solaris,
  222. and Jeremy Fitzhardinge's (no longer maintained)
  223. \htmladdnormallinkfoot{UserFS}{http://www.goop.org/~jeremy/userfs/}
  224. for Linux 1.x. The \htmladdnormallinkfoot{UFO
  225. paper}{http://www.cs.ucsb.edu/projects/ufo/97-usenix-ufo.ps} is also
  226. notable because it has a good survey of similar projects that
  227. integrate user-space code with system calls.
  228. \subsection{Limitations and Future Work}
  229. In its current form, FUSD is useful and has proven to be quite
  230. stable---we use it in production systems. However, it does have some
  231. limitations that could benefit from the attention of developers.
  232. Contributions to correct any of these deficiencies are welcomed!
  233. (Many of these limitations will not make sense without having read the
  234. rest of the documentation first.)
  235. \begin{itemize}
  236. \item Currently, FUSD only supports implementation of character
  237. devices. Block devices and network devices are not supported yet.
  238. \item The kernel has 15 different callbacks in its {\tt
  239. file\_operations} structure. The current version of FUSD does not
  240. proxy some of the more obscure ones out to userspace.
  241. \item Currently, all system calls that FUSD understands are proxied
  242. from the FUSD kernel module to userspace. Only the userspace library
  243. knows which callbacks have actually been registered by the FUSD
  244. driver. For example, the kernel may proxy a write() system call to
  245. user-space even if the driver has not registered a write() callback
  246. with fusd\_register().
  247. fusd\_register() should, but currently does not, tell the kernel
  248. module which callbacks it wants to receive, per-device. This will be
  249. more efficient because it will prevent useless system calls for
  250. unsupported operations. In addition, it will lead to more logical and
  251. consistent behavior by allowing the kernel to use its default
  252. implementations of certain functions such as writev(), instead of
  253. being fooled into thinking the driver has an implementation of it in
  254. cases where it doesn't.
  255. \item It should be possible to write a FUSD library in any language
  256. that supports reads and writes on raw file descriptors. In the
  257. future, it might be possible to write FUSD device drivers in a variety
  258. of languages---Perl, Python, maybe even Java. However, the current
  259. implementation has only a C library.
  260. \item It's possible for drivers that use FUSD to deadlock---for
  261. example, if a driver tries to open itself. In this one case, FUSD
  262. returns {\tt -EDEADLOCK}. However, deadlock protection should be
  263. expanded to more general detection of cycles of arbitrary length.
  264. \item FUSD should provide a /proc interface that gives debugging and
  265. status information, and allows parameter tuning.
  266. \item FUSD was written with efficiency in mind, but a number of
  267. important optimizations have not yet been implemented. Specifically,
  268. we'd like to try to reduce the number of memory copies by using a
  269. buffer shared between user and kernel space to pass messages.
  270. \item FUSD currently requires devfs, which is used to dynamically
  271. create device files under {\tt /dev} when a FUSD driver registers
  272. itself. This is, perhaps, the most convenient and useful paradigm
  273. for FUSD. However, some users have asked if it's possible to use FUSD
  274. without devfs. This should be possible if FUSD drivers bind to device
  275. major numbers instead of device file names.
  276. \end{itemize}
  277. \subsection{Author Contact Information and Acknowledgments}
  278. The original version of FUSD was written by Jeremy Elson
  279. \htmladdnormallink{(jelson@circlemud.org)}{mailto:jelson@circlemud.org}
  280. and Lewis Girod at Sensoria Corporation.
  281. Sensoria no longer maintains public releases of FUSD, but the same
  282. authors have since forked the last public release and continue to
  283. maintain FUSD from the University of California, Los Angeles.
  284. If you have bug reports, patches, suggestions, or any other comments,
  285. please feel free to contact the authors.
  286. FUSD has two
  287. \htmladdnormallinkfoot{SourceForge}{http://www.sourceforge.net}-host
  288. mailing lists: a low-traffic list for announcements ({\tt fusd-announce})
  289. and a list for general discussion ({\tt fusd-devel}). Subscription
  290. information for both lists is available at the
  291. \htmladdnormallink{SourceForge's FUSD mailing list
  292. page}{http://sourceforge.net/mail/?group_id=36326}.
  293. For the latest releases and information about FUSD, please see the
  294. \htmladdnormallinkfoot{official FUSD home
  295. page}{http://www.circlemud.org/jelson/software/fusd}.
  296. \subsection{Licensing Information}
  297. FUSD is free software, distributed under a GPL-compatible license (the
  298. ``new'' BSD license, with the advertising clause removed). The
  299. license is enumerated in its entirety below.
  300. Copyright (c) 2001, Sensoria Corporation; (c) 2003 University of
  301. California, Los Angeles. All rights reserved.
  302. Redistribution and use in source and binary forms, with or without
  303. modification, are permitted provided that the following conditions are
  304. met:
  305. \begin{itemize}
  306. \item Redistributions of source code must retain the above copyright
  307. notice, this list of conditions and the following disclaimer.
  308. \item Redistributions in binary form must reproduce the above
  309. copyright notice, this list of conditions and the following disclaimer
  310. in the documentation and/or other materials provided with the
  311. distribution.
  312. \item Neither the names of Sensoria Corporation or UCLA, nor the
  313. names of other contributors may be used to endorse or promote products
  314. derived from this software without specific prior written permission.
  315. \end{itemize}
  316. THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
  317. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  318. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  319. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
  320. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  321. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  322. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  323. BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  324. WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  325. OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  326. IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  327. \section{Why use FUSD?}
  328. \label{use-cases}
  329. One basic question about FUSD that one might ask is: what is it good
  330. for? Why use it? In this section, we describe some of the situations
  331. in which FUSD has been the solution for us.
  332. \subsection{Device Driver Layering}
  333. A problem that comes up frequently in modern operating systems is
  334. contention for a single resource by multiple competing processes. In
  335. UNIX, it's the job of a device driver to coordinate access to such
  336. resources. By accepting requests from user processes and (for
  337. example) queuing and serializing them, it becomes safe for processes
  338. that know nothing about each other to make requests in parallel to the
  339. same resource. Of course, kernel drivers do this job already, but
  340. they typically operate on top of hardware directly. However, kernel
  341. drivers can't easily be layered on top of {\em other device drivers}.
  342. For example, consider a device such as a modem that is connected to a
  343. host via a serial port. Let's say we want to implement a device
  344. driver that allows multiple users to dial the telephone (e.g., {\tt
  345. echo 1-310-555-1212 > /dev/phone-dialer}). Such a driver should be
  346. layered {\em on top of} the serial port driver---that is, it most
  347. likely wants to write to {\tt /dev/ttyS0}, not directly to the UART
  348. hardware itself.
  349. While it is possible to write to a logical file from within a kernel
  350. device driver, it is both tricky and considered bad practice. In the
  351. \htmladdnormallinkfoot{words of kernel hacker Dick Johnson}
  352. {http://www.uwsg.indiana.edu/hypermail/linux/kernel/0005.3/0061.html},
  353. ``You should never write a [kernel] module that requires reading or
  354. writing to any logical device. The kernel is the thing that translates
  355. physical I/O to logical I/O. Attempting to perform logical I/O in the
  356. kernel is effectively going backwards.''
  357. With FUSD, it's possible to layer device drivers because the driver is
  358. a user-space process, not a kernel module. A FUSD implementation of
  359. our hypothetical {\tt /dev/phone-dialer} can open {\tt /dev/ttyS0}
  360. just as any other process would.
  361. Typically, such layering is accomplished by system daemons. For
  362. example, the {\tt lpd} daemon manages printers at a high level. Since
  363. it is a user-space process, it can access the physical printer devices
  364. using kernel device drivers (for example, using printer or network
  365. drivers). There a number of advantages to using FUSD instead:
  366. \begin{itemize}
  367. \item Using FUSD, a daemon/driver can create a standard device file
  368. which is accessible by any program that knows how to use the POSIX
  369. system call interface. Some trickery is possible using named
  370. pipes and FIFOs, but quickly becomes difficult because of multiplexed
  371. writes from multiple processes.
  372. \item FUSD drivers receive the UID, GID, and process ID along with
  373. every file operation, allowing the same sorts of security policies to
  374. be implemented as would be possible with a real kernel driver. In
  375. contrast, writes to a named pipe, UDP, and so forth are ``anonymous.''
  376. \end{itemize}
  377. \subsection{Use of User-Space Libraries}
  378. Since a FUSD driver is just a regular user-space program, it can
  379. naturally use any of the enormous body of existing libraries that
  380. exist for almost any task. FUSD drivers can easily incorporate user
  381. interfaces, encryption, network protocols, threads, and almost
  382. anything else. In contrast, porting arbitrary C code into the kernel
  383. is difficult and usually a bad idea.
  384. \subsection{Driver Memory Protection}
  385. Since FUSD drivers run in their own process space, the rest of the
  386. system is protected from them. A buggy or malicious FUSD driver, at
  387. the very worst, can only corrupt itself. It's not possible for it to
  388. corrupt the kernel, other FUSD drivers, or even the processes that are
  389. using its devices. In contrast, a buggy kernel module can bring down
  390. any process in the system, or the entire kernel itself.
  391. \subsection{Giving libraries language independence and standard
  392. notification interfaces}
  393. One particularly interesting application of FUSD that we've found very
  394. useful is as a way to let regular user-space libraries export device
  395. file APIs. For example, imagine you had a library which factored
  396. large composite numbers. Typically, it might have a C
  397. interface---say, a function called {\tt int\ *factorize(int\ bignum)}.
  398. With FUSD, it's possible to create a device file interface---say, a
  399. device called {\tt /dev/factorize} to which clients can {\tt write(2)}
  400. a big number, then {\tt read(2)} back its factors.
  401. This may sound strange, but device file APIs have at least three
  402. advantages over a typical library API. First, it becomes much more
  403. language independent---any language that can make system calls can
  404. access the factorization library. Second, the factorization code is
  405. running in a different address space; if it crashes, it won't crash or
  406. corrupt the caller. Third, and most interestingly, it is possible to
  407. use {\tt select(2)} to wait for the factorization to complete. {\tt
  408. select(2)} would make it easy for a client to factor a large number
  409. while remaining responsive to {\em other} events that might happen in
  410. the meantime. In other words, FUSD allows normal user-space libraries
  411. to integrate seamlessly with UNIX's existing, POSIX-standard event
  412. notification interface: {\tt select(2)}.
  413. \subsection{Development and Debugging Convenience}
  414. FUSD processes can be developed and debugged with all the normal
  415. user-space tools. Buggy drivers won't crash the system, but instead
  416. dump cores that can be analyzed. All of your favorite visual
  417. debuggers, memory bounds checkers, leak detectors, profilers, and
  418. other tools can be applied to FUSD drivers as they would to any other
  419. program.
  420. \section{Installing FUSD}
  421. This section describes the installation procedure for FUSD. It
  422. assumes a good working knowledge of Linux system administration.
  423. \subsection{Prerequisites}
  424. Before installing FUSD, make sure you have all of the following
  425. packages installed and working correctly:
  426. \begin{itemize}
  427. \item {\bf Linux kernel 2.4.0 or later}. FUSD was developed under
  428. 2.4.0 and should work with any kernel in the 2.4 series.
  429. \item {\bf devfs installed and running.} FUSD dynamically registers
  430. devices using devfs, the Linux device filesystem by Richard Gooch.
  431. For FUSD to work, devfs must be installed and running on your system.
  432. For more information about devfs installation, see the
  433. \htmladdnormallinkfoot{devfs home
  434. page}{http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html}.
  435. Note that some distributions make installation devfs easier. RedHat
  436. 7.1, for example, already has all of the necessary daemons and
  437. configuration changes integrated. devfs can be installed simply by
  438. recompiling the kernel with devfs support enabled and reconfiguring
  439. LILO to pass {\tt "devfs=mount"} to the kernel.
  440. \end{itemize}
  441. \subsection{Compiling FUSD as a Kernel Module}
  442. Before compiling anything, take a look at the Makefile in FUSD's home
  443. directory. Adjust any constants that are not correct. In particular,
  444. make sure {\tt KERNEL\_HOME} correctly reflects the place where your
  445. kernel sources are installed, if they aren't in the default location
  446. of {\tt /usr/src/linux}.
  447. Then, type {\tt make}. It should generate a directory whose name
  448. looks something like {\tt obj.i686-linux}, or some variation depending
  449. on your architecture. Inside of that directory will be a number of
  450. files, including:
  451. \begin{itemize}
  452. \item kfusd.o -- The FUSD kernel module
  453. \item libfusd.a -- The C library used to talk to the kernel module
  454. \item Example programs -- linked against libfusd.a
  455. \end{itemize}
  456. Compilation of the kernel module will fail if the dependencies
  457. described in the previous section are not satisfied. The module must
  458. be compiled again Linux kernel must be v2.4.0 or later, and the kernel
  459. must have devfs support enabled.
  460. \subsection{Testing and Troubleshooting}
  461. Once everything has been compiled, give it a try to see if it actually
  462. does something. First, use {\tt insmod} to insert the FUSD kernel
  463. module, e.g. {\tt insmod obj.i686-linux/kfusd.o}. A greeting message
  464. similar to ``{\tt fusd: starting, Revision: 1.50}'' should appear in
  465. the kernel log (accessed using the {\tt dmesg} command, or by typing
  466. {\tt cat /proc/kmsg}). You can verify the module has been inserted by
  467. typing {\tt lsmod}, or alternatively {\tt cat /proc/modules}.
  468. Once the module has been inserted successfully, trying running the
  469. {\tt helloworld} example program. When run, the program should print
  470. a greeting message similar to {\tt /dev/hello-world should now exist -
  471. calling fusd\_run}. This means everything is working; the daemon is
  472. now blocked, waiting for requests to the new device. From another
  473. shell, type {\tt cat /dev/hello-world}. You should see {\tt Hello,
  474. world!} printed in response. Try killing the test program; the
  475. corresponding device file should disappear.
  476. If nothing seems to be working, try looking at the kernel message log
  477. (type {\tt dmesg} or {\tt cat /proc/kmsg}) to see if there are any
  478. errors. If nothing seems obviously wrong, try turning on FUSD kernel
  479. module debugging by defining {\tt CONFIG\_FUSD\_DEBUG} in kfusd.c,
  480. then recompiling and reinserting the module.
  481. \subsection{Installation}
  482. Typing {\tt make install} will copy the FUSD library, header files,
  483. and man pages into {\tt /usr/local}. The FUSD kernel module is {\em
  484. not} installed automatically because of variations among different
  485. Linux distributions in how this is accomplished. You may want to
  486. arrange to have the module start automatically on boot by (for
  487. example) copying it into {\tt /lib/modules/your-kernel-version}, and
  488. adding it to {\tt /etc/modules.conf}.
  489. \subsection{Making FUSD Part of the Kernel Proper}
  490. The earlier instructions, by default, create a FUSD kernel module.
  491. If desired, it's also very easy to build FUSD right into the kernel,
  492. instead:
  493. \begin{enumerate}
  494. \item Unpack the 2.4 kernel sources and copy all the files in the {\tt
  495. include} and {\tt kfusd} directories into your kernel source tree,
  496. under {\tt drivers/char}. For example, if FUSD is in
  497. your home directory, and your kernel is in {\tt /usr/src/linux}:
  498. \begin{verbatim}
  499. cp ~/fusd/kfusd/* ~/fusd/include/* /usr/src/linux/drivers/char
  500. \end{verbatim}
  501. \item Apply the patch found in FUSD's {\tt patches} directory to your
  502. kernel source tree. For example:
  503. \begin{verbatim}
  504. cd /usr/src/linux
  505. patch -p0 < ~/fusd/patches/fusd-inkernel.patch
  506. \end{verbatim}
  507. The FUSD in-kernel patch doesn't actually change any kernel sources
  508. proper; it just adds FUSD to the kernel configuration menu and
  509. Makefile.
  510. \item Using your kernel configurator of choice (e.g. {\tt make
  511. menuconfig}), turn on the FUSD options. It will be under the
  512. ``Character devices'' menu.
  513. \item Build and install the kernel as usual.
  514. \end{enumerate}
  515. \section{Basic Device Creation}
  516. Enough introduction---it's time to actually create a basic device
  517. driver using FUSD!
  518. This following sections will illustrate various techniques using
  519. example programs. To save space, interesting excerpts are shown
  520. instead of entire programs. However, the {\tt examples} directory
  521. of the FUSD distribution contains all the examples in their
  522. entirety. They can actually be compiled and run on a system with the
  523. FUSD kernel module installed.
  524. Where this text refers to example program line numbers, it refers to
  525. the line numbers printed alongside the excerpts in the manual---not
  526. the line numbers of the actual programs in the {\tt examples}
  527. directory.
  528. \subsection{Using {\tt fusd\_register} to create a new device}
  529. \label{using-fusd-register}
  530. We saw an example of a simple driver, helloworld.c, in
  531. Program~\ref{helloworld.c} on page~\pageref{helloworld.c}. Let's go
  532. back and examine that program now in more detail.
  533. The FUSD ball starts rolling when the {\tt fusd\_register} function is
  534. called, as shown on line 40. This function tells the FUSD kernel
  535. module:
  536. \begin{itemize}
  537. \item {\tt char *name}---The name of the device being created. The
  538. prefix (such as {\tt /dev/}) must match the location where devfs has
  539. been mounted. Names containing slashes (e.g., {\tt
  540. /dev/my-devices/dev1}) are legal; devfs creates subdirectories
  541. automatically.
  542. \item {\tt mode\_t mode}---The device's default permissions. This is
  543. usually specified using an octal constant with a leading 0---{\tt 0666}
  544. (readable and writable by everyone) instead of the incorrect decimal
  545. constant {\tt 666}.
  546. \item {\tt void *device\_info}---Private data that should be passed to
  547. callback functions for this device. The use of this field is
  548. described in Section~\ref{device-info}.
  549. \item {\tt struct fusd\_file\_operations *fops}---A structure containing
  550. pointers to the callback functions that should be called by FUSD
  551. in response to certain events.
  552. \end{itemize}
  553. If device registration is successful, {\tt fusd\_register} returns a
  554. {\em device handle}---a small integer $\ge0$. On errors, it returns
  555. -1 and sets the global variable {\tt errno} appropriately. In
  556. reality, the device handle you get is a plain old file descriptor,
  557. as we'll see in Section~\ref{selecting}.
  558. Although Program~\ref{helloworld.c} only calls {\tt fusd\_register}
  559. once, it can be called multiple times if the FUSD driver is handling
  560. more than one device as we'll see in Program~\ref{drums.c}.
  561. There is intentional similarity between {\tt fusd\_register()} and the
  562. kernel's device registration functions, such as {\tt
  563. devfs\_register()} and {\tt register\_chrdev()}. In many ways, FUSD's
  564. interface is meant to mirror the kernel interface as closely as
  565. possible.
  566. The {\tt fusd\_file\_operations} structure, defined in {\tt fusd.h},
  567. contains a list of callbacks that are used in response to different
  568. system calls executed on a file. It is similar to the kernel's {\tt
  569. file\_operations} structure, accepting callbacks for system calls such
  570. as {\tt open()}, {\tt close()}, {\tt read()}, {\tt write()}, and {\tt
  571. ioctl()}. For the most part, the prototypes of FUSD file operation
  572. callbacks are the same as their kernel cousins, with one important
  573. exception. The first argument of FUSD callbacks is always a pointer
  574. to a {\tt fusd\_file\_info} structure; it contains information that
  575. can be used to identify the file. This structure is used instead of
  576. the kernel's {\tt file} and {\tt inode} structures, and will be
  577. described in more detail later.
  578. In lines 35--38 of Program~\ref{helloworld.c}, we create and
  579. initialize a {\tt fusd\_file\_operations} structure. A GCC-specific C
  580. extension allows us to name structure fields explicitly in the
  581. initializer. This style may look strange, but it guards against
  582. errors in the future in case the order of fields in the structure ever
  583. changes. The 2.4 kernel series uses the same trick.
  584. After calling {\tt fusd\_register()} on line 40, the example program
  585. calls {\tt fusd\_run()} on line 44. This function turns control over
  586. to the FUSD framework. fusd\_run blocks the driver until one of the
  587. devices it registered needs to be serviced. Then, it calls the
  588. appropriate callback and blocks again until the next event.
  589. Now, imagine that a user types {\tt cat /dev/hello-world}. What
  590. happens? Recall first what the {\tt cat} program itself does: opens a
  591. file, reads from it until it receives an EOF (printing whatever it
  592. reads to stdout), then closes it. {\tt cat} works the same way
  593. regardless of what it's reading---be it a a FUSD device, a regular
  594. file, a serial port, or anything else. The {\tt strace} program is a
  595. great way to see this in action; see Appendix~\ref{strace} for
  596. details.
  597. \subsection{The {\tt open} and {\tt close} callbacks}
  598. \label{open-close}
  599. The first two callbacks that most drivers typically implement are {\tt
  600. open} and {\tt close}. Each of these two functions are passed just
  601. one argument---the {\tt fusd\_file\_info} structure that describes the
  602. instance of the file being opened or closed. Use of the information
  603. in that structure will be covered in more detail in
  604. Section~\ref{fusd-file-info}.
  605. The semantics of an {\tt open} callback's return value are exactly the
  606. same as inside the kernel:
  607. \begin{itemize}
  608. \item 0 means success, and the file is opened. If the file is allowed
  609. to open, the kernel returns a valid file descriptor to the client.
  610. Using that descriptor, other callbacks may be called for that file,
  611. including (at least) a {\tt close} callback.
  612. \item A negative number indicates a failure, and that the file should
  613. not be opened. Such return values should {\em always} be the
  614. specified as a negative {\tt errno} value such as {\tt -EPERM}, {\tt
  615. -EBUSY}, {\tt -ENODEV}, {\tt -ENOMEM}, and so on. For example, if the
  616. callback returns {\tt -EPERM}, the caller's {\tt open()} will return
  617. -1, with {\tt errno} set to {\tt EPERM}. A complete list of possible
  618. return values can be found in the Linux kernel sources, under {\tt
  619. include/asm/errno.h}.
  620. \end{itemize}
  621. If an {\tt open} callback returns 0 (success), a driver is {\em
  622. guaranteed} to receive exactly one {\tt close} callback for that file
  623. later. By the same token, the close callback {\em will not} be called
  624. if the open fails. Therefore, {\tt open} callbacks that can return
  625. failure must be sure to deallocate any resources they might have
  626. allocated before returning a failure.
  627. Let's return to our example in Program~\ref{helloworld.c}, which
  628. creates the {\tt /dev/hello-world} device. If a user types {\tt cat
  629. /dev/hello-world}, {\tt cat} will will use the {\tt open(2)} system
  630. call to open the file. FUSD will then proxy that system call to the
  631. driver and activate the callback that was registered as the {\tt open}
  632. callback. Recall from line 36 of Program~\ref{helloworld.c} that we
  633. registered {\tt do\_open\_or\_close}, which appears on line 8.
  634. In {\tt helloworld.c}, the {\tt open} callback always returns 0, or
  635. success. However, in a real driver, something more interesting will
  636. probably happen---permissions checks, memory allocation for
  637. state-keeping, and so forth. The corresponding {\em de}-allocation of
  638. those resources should occur in the {\tt close} callback, which is
  639. called when a user application calls {\tt close} on their file
  640. descriptor. {\tt close} callbacks are allowed to return error values,
  641. but this does not prevent the file from actually closing.
  642. \subsection{The {\tt read} callback}
  643. \label{read-callback}
  644. Returning to our {\tt cat /dev/hello-world} example, what happens
  645. after the {\tt open} is successful? Next, {\tt cat} will try to use
  646. {\tt read(2)}, which will get proxied by FUSD to the function {\tt
  647. do\_read} on line 13. This function takes some additional arguments
  648. that we didn't see in the open and close callbacks:
  649. \begin{itemize}
  650. \item {\tt struct fusd\_file\_info *file}---The first argument to all
  651. callbacks, containing information which describes the file; see
  652. Section~\ref{fusd-file-info}.
  653. \item {\tt char *user\_buffer}---The buffer that the callback should use to
  654. write data that it is returning to the user.
  655. \item {\tt size\_t user\_length}---The maximum number of bytes
  656. requested by the user. The driver is allowed to return fewer bytes,
  657. but should never write more then {\tt user\_length} bytes into {\tt
  658. user\_buffer}.
  659. \item {\tt loff\_t *offset}---A pointer to an integer which represents
  660. the caller's offset into the file (i.e., the user's file pointer).
  661. This value can be modified by the callback; any change will be
  662. propagated back to the user's file pointer inside the kernel.
  663. \end{itemize}
  664. The semantics of the return value are the same as if the
  665. callback were being written inside the kernel itself:
  666. \begin{itemize}
  667. \item Positive return values indicate success. If the call is
  668. successful, and the driver has copied data into {\tt buffer}, the
  669. return value indicates how many bytes were copied. This number should
  670. never be greater than the {\tt user\_length} argument.
  671. \item A 0 return value indicates EOF has been reached on the file.
  672. \item As in the {\tt open} and {\tt close} callbacks, negative values
  673. (such as -EPERM, -EPIPE, or -ENOMEM) indicate errors. Such values will
  674. cause the user's {\tt read()} to return -1 with errno set
  675. appropriately.
  676. \end{itemize}
  677. The first time a read is done on a device file, the user's file
  678. pointer ({\tt *offset}) is 0. In the case of this first read, a
  679. greeting message of {\tt Hello, world!} is copied back to the user, as
  680. seen on line 24. The user's file pointer is then advanced. The next
  681. read therefore fails the comparison at line 20, falling straight
  682. through to return 0, or EOF.
  683. In this simple program, we also see an example of an error return on
  684. line 22: if the user tries to do a read smaller than the length of the
  685. greeting message, the read will fail with -EINVAL. (In an actual
  686. driver, it would normally not be an error for a user to provide a
  687. smaller read buffer than the size of the available data. The right
  688. way for drivers to handle this situation is to return partial data,
  689. then move {\tt *offset} forward so that the remainder is returned on
  690. the next {\tt read()}. We see an example of this in
  691. Program~\ref{echo.c}.)
  692. \subsection{The {\tt write} callback}
  693. Program~\ref{helloworld.c} illustrated how a driver could return data
  694. {\em to} a client using the {\tt read} callback. As you might expect, there
  695. is a corresponding {\tt write} callback that allows the driver to
  696. receive data {\em from} a client. {\tt write} takes four arguments,
  697. similar to the {\tt read} callback:
  698. \begin{itemize}
  699. \item {\tt struct fusd\_file\_info *file}---The first argument to all
  700. callbacks, containing information which describes the file; see
  701. Section~\ref{fusd-file-info}.
  702. \item {\tt const char *user\_buffer}---Pointer to data being written
  703. by the client (read-only).
  704. \item {\tt size\_t user\_length}---The number of bytes pointed to by
  705. {\tt user\_buffer}.
  706. \item {\tt loff\_t *offset}---A pointer to an integer which represents
  707. the caller's offset into the file (i.e., the user's file pointer).
  708. This value can be modified by the callback; any change will be
  709. propagated back to the user's file pointer inside the kernel.
  710. \end{itemize}
  711. The semantics of {\tt write}'s return value are the same as in a
  712. kernel callback:
  713. \begin{itemize}
  714. \item Positive return values indicate success and indicate how many
  715. bytes of the user's buffer were successfully written (i.e.,
  716. successfully processed by the driver in some way). The return value
  717. may be less than or equal to the {\tt user\_length} argument, but
  718. should never be greater.
  719. \item 0 should only be returned in response to a {\tt write} of length
  720. 0.
  721. \item Negative values (such as -EPERM, -EPIPE, or -ENOMEM) indicate
  722. errors. Such values will cause the user's {\tt write()} to return -1
  723. with errno set appropriately.
  724. \end{itemize}
  725. Program~\ref{echo.c}, echo.c, is an example implementation of a device
  726. ({\tt /dev/echo}) that uses both {\tt read()} and {\tt write()}
  727. callbacks. A client that tries to {\tt read()} from this device will
  728. get the contents of the most recent {\tt write()}. For example:\\
  729. \begin{minipage}{\textwidth}
  730. \vspace{\baselineskip}
  731. \begin{verbatim}
  732. % echo Hello there > /dev/echo
  733. % cat /dev/echo
  734. Hello there
  735. % echo Device drivers are fun > /dev/echo
  736. % cat /dev/echo
  737. Device drivers are fun
  738. \end{verbatim}
  739. \end{minipage}
  740. \begin{Program}
  741. \listinginput[5]{1}{echo.c.example}
  742. \caption{echo.c: Using both {\tt read} and {\tt write} callbacks}
  743. \label{echo.c}
  744. \end{Program}
  745. The implementation of {\tt /dev/echo} keeps a global variable, {\tt
  746. data}, which serves as a cache for the data most recently written to
  747. the driver by a client program. The driver does not assume the data
  748. is null-terminated, so it also keeps track of the number of bytes of
  749. data available. (These two variables appear on lines 1--2.)
  750. The driver's {\tt write} callback first frees any data which might
  751. have been allocated by a previous call to write (lines 26--29). Next,
  752. on line 33, it attempts to allocate new memory for the new data
  753. arriving. If the allocation fails, {\tt -ENOMEM} is returned to the
  754. client. If the allocation is successful, the driver copies the data
  755. into its local buffer and stores its length (lines 37--38). Finally,
  756. the driver tells the user that the entire buffer was consumed by
  757. returning a value equal to the number of bytes the user tried to write
  758. ({\tt user\_length}).
  759. The {\tt read} callback has some extra features that we did not see in
  760. Program~\ref{helloworld.c}'s {\tt read()} callback. The most
  761. important is that it allows the driver to read the available data {\em
  762. incrementally}, instead of requiring that the first {\tt read()}
  763. executed by the client has enough space for all the data the driver
  764. has available. In other words, a client can do two 50-byte reads,
  765. and expect the same effect as if it had done a single 100-byte read.
  766. This is implemented using {\tt *offset}, the user's file pointer. If
  767. the user is trying to read past the amount of data we have available,
  768. the driver returns EOF (lines 8--9). Normally, this happens after the
  769. client has finished reading data. However, in this driver, it might
  770. happen on a client's first read if nothing has been written to the
  771. driver yet or if the most recent write's memory allocation failed.
  772. If there is data to return, the driver computes the number of bytes
  773. that should be copied back to the client---the minimum of the number
  774. of bytes the user asked for, and the number of bytes of data that this
  775. client hasn't seen yet (line 12). This data is copied back to the
  776. user's buffer (line 15), and the user's file pointer is advanced
  777. accordingly (line 16). Finally, on line 19, the client is told how
  778. many bytes were copied to its buffer.
  779. \subsection{Unregistering a device with {\tt fusd\_unregister()}}
  780. All devices registered by a driver are unregistered automatically when
  781. the program exits (or crashes). However, the {\tt fusd\_unregister()}
  782. function can be used to unregister a device without terminating the
  783. entire driver. {\tt fusd\_unregister} takes one argument: a device
  784. handle (i.e., the return value from {\tt fusd\_register()}).
  785. A device can be unregistered at any time. Any client system calls
  786. that are pending when a device is unregistered will return immediately
  787. with an error. In this case, {\tt errno} will be set to {\tt -EPIPE}.
  788. \section{Using Information in {\tt fusd\_file\_info}}
  789. \label{fusd-file-info}
  790. We mentioned in the previous sections that the first argument to every
  791. callback is a pointer to a {\tt fusd\_file\_info} structure. This
  792. structure contains information that can be useful to driver
  793. implementers in deciding how to respond to a system call request.
  794. The fields of {\tt fusd\_file\_info} structures fall into several
  795. categories:
  796. \begin{itemize}
  797. \item {\em Read-only.} The driver can inspect the value, but changing
  798. it will have no effect.
  799. \begin{itemize}
  800. \item {\tt pid\_t pid}: The process ID of the process making the
  801. request
  802. \item {\tt uid\_t uid}: The user ID of the owner of the process making
  803. the request
  804. \item {\tt gid\_t gid}: The group ID of the owner of the process making
  805. the request
  806. \end{itemize}
  807. \item {\em Read-write.} Any changes to the value will be propagated
  808. back to the kernel and be written to the appropriate in-kernel
  809. structure.
  810. \begin{itemize}
  811. \item {\tt unsigned int flags}: A copy of the {\tt f\_flags} field in
  812. the kernel's {\tt file} structure. The flags are an or'd-together set
  813. of the kernel's {\tt O\_} series of flags: {\tt O\_NONBLOCK}, {\tt
  814. O\_APPEND}, {\tt O\_SYNC}, etc.
  815. \item {\tt void *device\_info}: The data passed to {\tt
  816. fusd\_register} when the device was registered; see
  817. Section~\ref{device-info} for details
  818. \item {\tt void *private\_data}: A generic per-file-descriptor pointer
  819. usable by the driver for its own purposes, such as to keep state (or a
  820. pointer to state) that should be maintained between operations on the
  821. same instance of an open file. It is guaranteed to be NULL when the
  822. file is first opened. See Section~\ref{private-data} for more
  823. details.
  824. \end{itemize}
  825. \item {\em Hidden fields.} The driver should not touch these fields
  826. (such as {\tt fd}). They contain state used by the FUSD library to
  827. generate the reply sent to the kernel.
  828. \end{itemize}
  829. {\bf Important note:} the value of the {\tt fusd\_file\_info} pointer
  830. itself has {\em no meaning}. Repeated requests on the same file
  831. descriptor {\em will not} generate callbacks with identical {\tt
  832. fusd\_file\_info} pointer values, as would be the case with an
  833. in-kernel driver. In other words, if a driver needs to keep state in
  834. between successive system calls on a user's file descriptor, it {\em
  835. must} store that state using the {\tt private\_data} field. The {\tt
  836. fusd\_file\_info} pointer itself is ephemeral; the data to which it
  837. points is persistent.
  838. Program~\ref{uid-filter.c} shows an example of how a driver might make
  839. use of the data in the {\tt fusd\_file\_info} structure. Much of the
  840. driver is identical to helloworld.c. However, instead of printing a
  841. static greeting, this new program generates a custom message each time
  842. the device file is read, as seen on line 25. The message contains the
  843. PID of the user process that requested the read ({\tt file->pid}).
  844. \begin{Program}
  845. \listinginput[5]{1}{uid-filter.c.example}
  846. \caption{uid-filter.c: Inspecting data in {\tt fusd\_file\_info} such
  847. as UID and PID of the calling process}
  848. \label{uid-filter.c}
  849. \end{Program}
  850. In addition, Program~\ref{uid-filter.c}'s {\tt open} callback does not
  851. return 0 (success) unconditionally as it did in
  852. Program~\ref{helloworld.c}. Instead, it checks (on line 7) to make
  853. sure the UID of the process trying to read from the device ({\tt
  854. file->uid}) matches the UID under which the driver itself is running
  855. ({\tt getuid()}). If they don't match, -EPERM is returned. In other
  856. words, only the user who ran the driver is allowed to read from the
  857. device that it creates. If any other user---including root!---tries
  858. to open it, a ``Permission denied'' error will be generated.
  859. \subsection{Registration of Multiple Devices, and Passing Data to Callbacks}
  860. \label{device-info}
  861. Device drivers frequently expose several different ``flavors'' of a
  862. device. For example, a single magnetic tape drive will often have
  863. many different device files in {\tt /dev}. Each device file
  864. represents a different combination of options such as
  865. rewind/no-rewind, or compressed/uncompressed. However, they access
  866. the same physical tape drive.
  867. Traditionally, the device file's {\em minor number} was used to
  868. communicate the desired options with device drivers. But, since devfs
  869. dynamically (and unpredictably) generates both major and minor numbers
  870. every time a device is registered, a different technique was
  871. developed. When using devfs, drivers are allowed to associate a value
  872. (of type {\tt void *}) with each device they register. This facility
  873. takes the place of the minor number.
  874. The devfs solution is also used by FUSD. The mysterious third
  875. argument to {\tt fusd\_register} that we mentioned in
  876. Section~\ref{using-fusd-register} is an arbitrary piece of data that
  877. can be passed to FUSD when a device is registered. Later, when a
  878. callback is activated, the contents of that argument are available in
  879. the {\tt device\_info} member of the {\tt fusd\_file\_info} structure.
  880. Program~\ref{drums.c} shows an example of this technique, inspired by
  881. Alessandro Rubini's similar devfs tutorial
  882. \htmladdnormallinkfoot{published in Linux
  883. Magazine}{http://www.linux.it/kerneldocs/devfs/}. It creates a number
  884. of devices in the {\tt /dev/drums} directory, each of which is useful
  885. for generating a different kind of ``sound''---{\tt /dev/drums/bam},
  886. {\tt /dev/drums/boom}, and so on. Reading from any of these devices
  887. will return a string equal to the device's name.
  888. \begin{Program}
  889. \listinginput[5]{1}{drums.c.example}
  890. \caption{drums.c: Passing private data to {\tt fusd\_register} and
  891. retrieving it from {\tt device\_info}}
  892. \label{drums.c}
  893. \end{Program}
  894. The first thing to notice about {\tt drums.c} is that it registers
  895. more than one FUSD device. In the loop starting in line 31, it calls
  896. {\tt fusd\_register()} once for every device named in {\tt
  897. drums\_strings} on line 1. When {\tt fusd\_run()} is called, it
  898. automatically watches every device the driver registered, and
  899. activates the callbacks associated with each device as needed.
  900. Although {\tt drums.c} uses the same set of callbacks for every device
  901. it registers (as can be seen on line 33), each device could have
  902. different callbacks if desired. (Not shown is the initialization of
  903. {\tt drums\_fops}, which assigns {\tt drums\_read} to be the {\tt
  904. read} callback.)
  905. If {\tt drums\_read} is called for all 6 types of drums, how does it
  906. know which device it's supposed to be servicing when it gets called?
  907. The answer is in the third argument of {\tt fusd\_register()}, which
  908. we were previously ignoring. Whatever value is passed to {\tt
  909. fusd\_register()} will be passed back to the callback in the {\tt
  910. device\_info} field of the {\tt fusd\_file\_info} structure. The name
  911. of the drum sound is passed to {\tt fusd\_register} on line 33, and
  912. later retrieved by the driver on line 12.
  913. Although this example uses a string as its {\tt device\_info}, the
  914. pointer can be used for anything---a mode number, a pointer to a
  915. configuration structure, and so on.
  916. \subsection{The difference between {\tt device\_info} and {\tt
  917. private\_data}}
  918. \label{private-data}
  919. As we mentioned in Section~\ref{fusd-file-info}, the {\tt
  920. fusd\_file\_info} structure has two seemingly similar fields, both of
  921. which can be used by drivers to store their own data: {\tt
  922. device\_info} and {\tt private\_data}. However, there is an important
  923. difference between them:
  924. \begin{itemize}
  925. \item {\tt private\_data} is stored {\em per file descriptor}. If 20
  926. processes open a FUSD device (or, one process opens a FUSD device 20
  927. times), each of those 20 file descriptors will have their own copy of
  928. {\tt private\_data} associated with them. This field is therefore
  929. useful to drivers that need to differentiate multiple requests to a
  930. single device that might be serviced in parallel. (Note that most
  931. UNIX variants, including Linux, do allow multiple processes to share a
  932. single file descriptor---specifically, if a process {\tt open}s a
  933. file, then {\tt fork}s. In this case, processes will also share a
  934. single copy of {\tt private\_data}.)
  935. The first time a FUSD driver sees {\tt private\_data} (in the {\tt
  936. open} callback), it is guaranteed to be NULL. Any changes to it by a
  937. driver callback will only affect the state associated with that single
  938. file descriptor.
  939. \item {\tt device\_info} is kept {\em per device}. That is, {\em all}
  940. clients of a device share a {\em single} copy of {\tt device\_info}.
  941. Unlike {\tt private\_data}, which is always initialized to NULL, {\tt
  942. device\_info} is always initialized to whatever value the driver
  943. passed to {\tt fusd\_register} as described in the previous section.
  944. If a callback changes the copy of {\tt device\_info} in the {\tt
  945. fusd\_file\_info} structure, this has no effect; {\tt device\_info}
  946. can only be set at registration time, with {\tt fusd\_register}.
  947. \end{itemize}
  948. In short, {\tt device\_info} is used to differentiate {\em devices}.
  949. {\tt private\_data} is used to differentiate {\em users of those
  950. devices}.
  951. Program~\ref{drums2.c}, drums2.c, illustrates the difference between
  952. {\tt device\_info} and {\tt private\_data}. Like the original
  953. drums.c, it creates a bunch of devices in {\tt /dev/drums/}, each of
  954. which ``plays'' a different sound. However, it also does something
  955. new: keeps track of how many times each device has been opened. Every
  956. read to any drum gives you the name of its sound as well as your
  957. unique ``user number''. And, instead of returning just a single line
  958. (as drums.c did), it will keep generating more ``sound'' every time a
  959. {\tt read()} system call arrives.
  960. \begin{Program}
  961. \listinginput[5]{1}{drums2.c.example}
  962. \caption{drums2.c: Using both {\tt device\_info} and {\tt private\_data}}
  963. \label{drums2.c}
  964. \end{Program}
  965. The trick is that we want to keep users separate from each other. For
  966. example, user one might type:\\
  967. \begin{minipage}{\textwidth}
  968. \vspace{\baselineskip}
  969. \begin{verbatim}
  970. % more /dev/drums/bam
  971. You are user 1 to hear a drum go 'bam'!
  972. You are user 1 to hear a drum go 'bam'!
  973. You are user 1 to hear a drum go 'bam'!
  974. ...
  975. \end{verbatim}
  976. \end{minipage}
  977. Meanwhile, another user in a different shell might type the same
  978. command at the same time, and get different results:\\
  979. \begin{minipage}{\textwidth}
  980. \vspace{\baselineskip}
  981. \begin{verbatim}
  982. % more /dev/drums/bam
  983. You are user 2 to hear a drum go 'bam'!
  984. You are user 2 to hear a drum go 'bam'!
  985. You are user 2 to hear a drum go 'bam'!
  986. ...
  987. \end{verbatim}
  988. \end{minipage}
  989. The idea is that no matter how long those two users go on reading
  990. their devices, the driver always generates a message that is specific
  991. to that user. The two users' data are not intermingled.
  992. To implement this, Program~\ref{drums2.c} introduces a new {\tt
  993. drum\_info} structure (lines 1-4), which keeps track of both the
  994. drum's name, and the number of time each drum device has been opened.
  995. An instance of this structure, {\tt drums}, is initialized on lines
  996. 4-8. Note that the call to {\tt fusd\_register} (line 45) now passes
  997. a pointer to a {\tt drum\_info} structure. (This {\tt drum\_info *}
  998. pointer is shared by every instance of a client that opens a
  999. particular type of drum.)
  1000. Each time a drum device is opened, its {\tt drum\_info} structure is
  1001. retrieved from {\tt device\_info} (line 15). Then, on line 18, the
  1002. {\tt num\_users} field is incremented and the new user number is
  1003. stored in {\tt fusd\_file\_info}'s {\tt private\_data} field. To
  1004. reiterate our earlier point: {\em {\tt device\_info} contains
  1005. information global to all users of a device, while {\tt private\_data}
  1006. has information specific to a particular user of the device.}
  1007. It's also worthwhile to note that when we increment {\tt num\_users}
  1008. on line 18, a simple {\tt num\_users++} is correct. If this was a
  1009. driver inside the kernel, we'd have to use something like {\tt
  1010. atomic\_inc()} because a plain {\tt i++} is not atomic. Such a
  1011. non-atomic statement will result in a race condition on SMP platforms,
  1012. if an interrupt handler also touches {\tt num\_users}, or in some
  1013. future Linux kernel that is preemptive. Since this FUSD driver is
  1014. just a plain, single-threaded user-space application, good old {\tt
  1015. ++} still works.
  1016. \section{Writing {\tt ioctl} Callbacks}
  1017. The POSIX API provides for a function called {\tt ioctl}, which allows
  1018. ``out-of-band'' configuration information to be passed to a device
  1019. driver through a file descriptor. Using FUSD, you can write a device
  1020. driver with a callback to handle {\tt ioctl} requests from clients.
  1021. For the most part, it's just like writing a callback for {\tt read} or
  1022. {\tt write}, as we've seen in previous sections. From the client's
  1023. point of view, {\tt ioctl} traditionally takes three arguments: a file
  1024. descriptor, a command number, and a pointer to any additional data
  1025. that might be required for the command.
  1026. \subsection{Using macros to generate {\tt ioctl} command numbers}
  1027. The Linux header file {\tt /usr/include/asm/ioctl.h} defines macros
  1028. that {\em must} be used to create the {\tt ioctl} command number.
  1029. These macros take various combinations of three arguments:
  1030. \begin{itemize}
  1031. \item {\tt type}---an 8-bit integer selected to be specific to the
  1032. device driver. {\tt type} should be chosen so as not to conflict with
  1033. other drivers that might be ``listening'' to the same file descriptor.
  1034. (Inside the kernel, for example, the TCP and IP stacks use distinct
  1035. numbers since an {\tt ioctl} sent to a socket file descriptor might be
  1036. examined by both stacks.)
  1037. \item {\tt number}---an 8-bit integer ``command number.'' Within a
  1038. driver, distinct numbers should be chosen for each different kind of
  1039. {\tt ioctl} command that the driver services.
  1040. \item {\tt data\_type}---The name of a type used to compute how many
  1041. bytes are exchanged between the client and the driver. This argument
  1042. is, for example, the name of a structure.
  1043. \end{itemize}
  1044. The macros used to generate command numbers are:
  1045. \begin{itemize}
  1046. \item {\tt \_IO(int type, int number)} -- used for a simple ioctl that
  1047. sends nothing but the type and number, and receives back nothing but
  1048. an (integer) retval.
  1049. \item {\tt \_IOR(int type, int number, data\_type)} -- used for an
  1050. ioctl that reads data {\em from} the device driver. The driver will
  1051. be allowed to return {\tt sizeof(data\_type)} bytes to the user.
  1052. \item {\tt \_IOW(int type, int number, data\_type)} -- similar to
  1053. \_IOR, but used to write data {\em to} the driver.
  1054. \item {\tt \_IORW(int type, int number, data\_type)} -- a combination
  1055. of {\tt \_IOR} and {\tt \_IOW}. That is, data is both written to the
  1056. driver and then read back from the driver by the client.
  1057. \end{itemize}
  1058. \begin{Program}
  1059. \listinginput[5]{1}{ioctl.h.example}
  1060. \caption{ioctl.h: Using the {\tt \_IO} macros to generate {\tt ioctl}
  1061. command numbers}
  1062. \label{ioctl.h}
  1063. \end{Program}
  1064. Program~\ref{ioctl.h} is an example header file showing the use of
  1065. these macros. In real programs, the client executing an ioctl and the
  1066. driver that services it must share the same header file.
  1067. \subsection{Example client calls and driver callbacks}
  1068. Program~\ref{ioctl-client.c} shows a client program that executes {\tt
  1069. ioctl}s using the ioctl command numbers defined in
  1070. Program~\ref{ioctl.h}. The {\tt ioctl\_data\_t} is
  1071. application-specific; our simple test program defines it as a
  1072. structure containing two arrays of characters. The first {\tt ioctl}
  1073. call (line 10) sends the command {\tt IOCTL\_TEST3}, which retrieves
  1074. strings {\em from} the driver. The second {\tt ioctl} uses the
  1075. command {\tt IOCTL\_TEST4} (line 18), which sends strings {\em to} the
  1076. driver.
  1077. \begin{Program}
  1078. \listinginput[5]{1}{ioctl-client.c.example}
  1079. \caption{ioctl-client.c: A program that makes {\tt ioctl} requests on
  1080. a file descriptor}
  1081. \label{ioctl-client.c}
  1082. \end{Program}
  1083. The portion of the FUSD driver that services these calls is shown in
  1084. Program~\ref{ioctl-server.c}.
  1085. \begin{Program}
  1086. \listinginput[5]{1}{ioctl-server.c.example}
  1087. \caption{ioctl-server.c: A driver that handles {\tt ioctl} requests}
  1088. \label{ioctl-server.c}
  1089. \end{Program}
  1090. The ioctl example header file and test programs shown in this document
  1091. (Programs~\ref{ioctl.h}, \ref{ioctl-client.c}, and
  1092. \ref{ioctl-server.c}) are actually contained in a larger, single
  1093. example program included in the FUSD distribution called {\tt
  1094. ioctl.c}. That source code shows other variations on calling and
  1095. servicing {\tt ioctl} commands.
  1096. \section{Integrating FUSD With Your Application Using {\tt fusd\_dispatch()}}
  1097. \label{selecting}
  1098. The example applications we've seen so far have something in common:
  1099. after initialization and device registration, they call {\tt
  1100. fusd\_run()}. This gives up control of the program's flow, turning it
  1101. over to the FUSD library instead. This worked fine for our simple
  1102. example programs, but doesn't work in a real program that needs to
  1103. wait for events other than FUSD callbacks. For this reason, our
  1104. framework provides another way to activate callbacks that does not
  1105. require the driver to give up control of its {\tt main()}.
  1106. \subsection{Using {\tt fusd\_dispatch()}}
  1107. Recall from Section~\ref{using-fusd-register} that {\tt
  1108. fusd\_register} returns a {\em file descriptor} for every device that
  1109. is successfully registered. This file descriptor can be used to
  1110. activate device callbacks ``manually,'' without passing control of the
  1111. application to {\tt fusd\_run()}. Whenever the file descriptor
  1112. becomes readable according to {\tt select(2)}, it should be passed to
  1113. {\tt fusd\_dispatch()}, which in turn will activate callbacks in the
  1114. same way that {\tt fusd\_run()} does. In other words, an application
  1115. can:
  1116. \begin{enumerate}
  1117. \item Save the file descriptors returned by {\tt fusd\_register()};
  1118. \item Add those FUSD file descriptors to an {\tt fd\_set} that is
  1119. passed to {\tt select}, along with any other file
  1120. descriptors that might be interesting to the application; and
  1121. \item Pass every FUSD file descriptor that {\tt select} indicates is
  1122. readable to {\tt fusd\_dispatch}.
  1123. \end{enumerate}
  1124. {\tt fusd\_dispatch()} returns 0 if at least one callback was
  1125. successfully activated. On error, -1 is returned with {\tt errno} set
  1126. appropriately. {\tt fusd\_dispatch()} will never block---if no
  1127. messages are available from the kernel, it will return -1 with {\tt
  1128. errno} set to {\tt EAGAIN}.
  1129. \subsection{Helper Functions for Constructing an {\tt fd\_set}}
  1130. The FUSD library provides two (optional) utility functions that can
  1131. make it easier to write applications that integrate FUSD into their
  1132. own {\tt select()} loops. Specifically:
  1133. \begin{itemize}
  1134. \item {\tt void fusd\_fdset\_add(fd\_set *set, int *max)}---is meant
  1135. to help construct an {\tt fd\_set} that will be passed as the
  1136. ``readable fds'' set to select. This function adds the file
  1137. descriptors of all previously registered FUSD devices to the fd\_set
  1138. {\tt set}. It assumes that {\tt set} has already been initialized by
  1139. the caller. The integer {\tt max} is updated to reflect the largest
  1140. file descriptor number in the set. {\tt max} is not changed if the
  1141. value passed to {\tt fusd\_fdset\_add} is already larger than the
  1142. largest FUSD file descriptor added to the set.
  1143. \item {\tt void fusd\_dispatch\_fdset(fd\_set *set)}---is meant to be
  1144. called on the {\tt fd\_set} that is {\em returned} by select. It
  1145. assumes that {\tt set} contains a set file descriptors that {\tt
  1146. select()} has indicated are readable. {\tt fusd\_dispatch\_fdset()}
  1147. calls {\tt fusd\_dispatch} on every descriptor in {\tt set} that is a
  1148. valid FUSD descriptor. Non-FUSD descriptors in {\tt set} are
  1149. ignored.
  1150. \end{itemize}
  1151. \begin{Program}
  1152. \listinginput[5]{1}{drums3.c.example}
  1153. \caption{drums3.c: Waiting for both FUSD and non-FUSD events in a
  1154. {\tt select} loop}
  1155. \label{drums3.c}
  1156. \end{Program}
  1157. The excerpt of {\tt drums3.c} shown in Program~\ref{drums3.c}
  1158. demonstrates the use of these helper functions. This program is
  1159. similar to the earlier drums.c example: it creates a number of musical
  1160. instruments such as {\tt /dev/drums/bam} and {\tt /dev/drums/boom}.
  1161. However, in addition to servicing its musical callbacks, the driver
  1162. also prints a prompt to standard input asking how ``loud'' the drums
  1163. should be. Instead of turning control of {\tt main()} over to {\tt
  1164. fusd\_run()} as in the previous examples, {\tt drums3} uses {\tt
  1165. select()} to simultaneously watch its FUSD file descriptors and standard
  1166. input. It responds to input from both sources.
  1167. On lines 2--5, an {\tt fd\_set} and its associated ``max'' value are
  1168. initialized to contain stdin's file descriptor. On line 9, we use
  1169. {\tt fusd\_fdset\_add} to add the FUSD file descriptors for all
  1170. registered devices. (Not shown in this excerpt is the device
  1171. registration, which is the same as the registration code we saw in
  1172. {\tt drums.c}.) On line 13 we call select, which blocks until one of
  1173. the fd's in the set is readable. On lines 17 and 18, we check to see
  1174. if standard input is readable; if so, a function is called which reads
  1175. the user's response from standard input and prints a new prompt.
  1176. Finally, on line 21, we call {\tt fusd\_dispatch\_fdset}, which in
  1177. turn will activate the callbacks for devices that have pending system
  1178. calls waiting to be serviced.
  1179. It's worth reiterating that drivers are not required to use the FUSD
  1180. helper functions {\tt fusd\_fdset\_add} and {\tt
  1181. fusd\_dispatch\_fdset}. If it's more convenient, a driver can
  1182. manually save all of the file descriptors returned by {\tt
  1183. fusd\_register}, construct its own {\tt fd\_set}, and then call {\tt
  1184. fusd\_dispatch} on each descriptor that is readable. This method is
  1185. sometimes required for integration with other frameworks that want to
  1186. take over your {\tt main()}. For example, the
  1187. \htmladdnormallinkfoot{GTK user interface
  1188. framework}{http://www.gtk.org} is event-driven and requires that you
  1189. pass control of your {\tt main} to it. However, it does allow you to
  1190. give it a file descriptor and a function pointer, saying ``Call this
  1191. callback when {\tt select} indicates this file descriptor has become
  1192. readable.'' A GTK application that implements FUSD devices can work
  1193. by giving GTK all the FUSD file descriptors individually, and calling
  1194. {\tt fusd\_dispatch()} when GTK calls the associated callbacks.
  1195. \section{Implementing Blocking System Calls}
  1196. All of the example drivers that we've seen until now have had an
  1197. important feature missing: they never had to {\em wait} for anything.
  1198. So far, a driver's response to a system call has always been
  1199. immediately available---allowing the driver to response immediately.
  1200. However, real devices are often not that lucky: they usually have to
  1201. wait for something to happen before completing a client's system call.
  1202. For example, a driver might be waiting for data to arrive from the
  1203. serial port or over the network, or even waiting for a user action.
  1204. In situations like this, a basic capability most device drivers must
  1205. have is the ability to {\em block} the caller. Blocking operations
  1206. are important because they provide a simple interface to user programs
  1207. that does flow control, rather than something more expensive like
  1208. continuous polling. For example, user programs expect to be able to
  1209. execute a statement like {\tt read(fd, buf, sizeof(buf))}, and expect
  1210. the read call to block (stop the flow of the calling program) until
  1211. data is available. This is much simpler and more efficient than
  1212. polling repeatedly.
  1213. In the following sections, we'll describe how to block and unblock
  1214. system calls for devices that use FUSD.
  1215. \subsection{Blocking the caller by blocking the driver}
  1216. The easiest (but least useful) way to block a client's system call is
  1217. simply to block the driver, too. For example, consider
  1218. Program~\ref{console-read.c}, which implements a device called {\tt
  1219. /dev/console-read}. Whenever a process tries to read from this
  1220. device, the driver prints a prompt to standard input, asking for a
  1221. reply. (The prompt appears in the shell the driver was run in, not
  1222. the shell that's trying to read from the device.) When the user
  1223. enters a line of text, the response is returned to the client that did
  1224. the original {\tt read()}. By blocking the driver waiting for the
  1225. reply, the client that issued the system call is blocked as well.
  1226. \begin{Program}
  1227. \listinginput[5]{1}{console-read.c.example}
  1228. \caption{console-read.c: A simple blocking system call}
  1229. \label{console-read.c}
  1230. \end{Program}
  1231. Blocking the driver this way is safe---unlike programming in the
  1232. kernel proper, where doing something like this would block the entire
  1233. system. It's also easy to implement, as seen from the example above.
  1234. However, it makes the driver unresponsive to system call requests that
  1235. might be coming from other clients. If another process tries to do
  1236. anything at all with a blocked driver's device---even an {\tt
  1237. open()}---it will block until the driver wakes up again. This
  1238. limitation makes blocking drivers inappropriate for any device driver
  1239. that expects to service more than one client at a time.
  1240. \subsection{Blocking the caller using {\tt -FUSD\_NOREPLY};
  1241. unblocking it using {\tt fusd\_return()}}
  1242. \label{fusd-noreply}
  1243. If a device driver expects more than one client at a time---as is
  1244. often the case---a slightly different programming model is needed for
  1245. system calls that can potentially block. Instead of blocking, the
  1246. driver immediately sends a message to the FUSD framework that says, in
  1247. essence, ``Don't unblock the client that issued this system call, but
  1248. continue sending additional system call requests that might be coming
  1249. from other clients.'' Driver callbacks can send this message to FUSD
  1250. by returning the special value {\tt -FUSD\_NOREPLY} instead of a
  1251. normal system call return value.
  1252. Before a callback blocks the caller by returning {\tt -FUSD\_NOREPLY},
  1253. it must save the {\tt fusd\_file\_info} pointer that was provided to
  1254. the callback as its first argument. Later, when an event occurs which
  1255. allows the client's blocked system call to complete, the driver should
  1256. call {\tt fusd\_return()}, which will unblock the calling process and
  1257. complete its system call. {\tt fusd\_return()} takes two arguments:
  1258. \begin{itemize}
  1259. \item The {\tt fusd\_file\_info} pointer that the callback saved
  1260. earlier; and
  1261. \item The system call's return value (in other words, the value that
  1262. would have been returned by the callback function had it not returned
  1263. {\tt -FUSD\_NOREPLY}). FUSD itself {\em does not} examine the return
  1264. value passed as the second argument to {\tt fusd\_return}; it simply
  1265. propagates that value back to the kernel as the return value of the
  1266. blocked system call.
  1267. \end{itemize}
  1268. Drivers should never call {\tt fusd\_return} more than once on a
  1269. single {\tt fusd\_file\_info} pointer. Doing so will have undefined
  1270. results, similar to calling {\tt free()} twice on the same pointer.
  1271. It also bears repeating that a callback can call {\em either} call
  1272. fusd\_return() explicitly {\em or} return a normal return value (i.e.,
  1273. not {\tt -FUSD\_NOREPLY}), but not both.
  1274. {\tt -FUSD\_NOREPLY} and {\tt fusd\_return()} make it easy for a
  1275. driver to block a process, then unblock it later when data becomes
  1276. available. When the callback returns {\tt -FUSD\_NOREPLY}, the driver
  1277. is freed up to wait for other events, even though the process making
  1278. the system call is still blocked. The driver can then wait for
  1279. something to happen that unblocks the original caller---for example,
  1280. another FUSD event, data from a serial port, or data from the network.
  1281. (Recall from Section~\ref{selecting} that a FUSD driver can
  1282. simultaneously wait for both FUSD and non-FUSD events.)
  1283. FUSD includes an example program, {\tt pager.c}, which demonstrates
  1284. these techniques. The pager driver implements a simple notification
  1285. interface which lets any number of ``waiters'' wait for a signal from
  1286. a ``notifier.'' All the waiters wait by trying to read from {\tt
  1287. /dev/pager/notify}. Those reads will block until a notifier writes
  1288. the string {\tt page} to {\tt /dev/pager/input}. It's easy to try
  1289. the application out---run the driver, and then open three other
  1290. shells. In two of them, type {\tt cat /dev/pager/notify}. The reads
  1291. will block. Then, in the third shell, type {\tt echo page >
  1292. /dev/pager/input}---the other two shells should become unblocked.
  1293. Let's take a look at how this application is implemented, step by
  1294. step.
  1295. \subsubsection{Keeping Per-Client State}
  1296. The first thing to notice about {\tt pager.c} is that it keeps {\em
  1297. per-client state}. That is, for every file descriptor open to the
  1298. driver, a structure is allocated that has information relating to that
  1299. file descriptor. Previous driver examples were, for the most part,
  1300. {\em reactive}---they received requests, and immediately generated
  1301. responses. Since there was never more than one request outstanding,
  1302. there was no need to keep a list of them. The pager application is
  1303. the first one that must keep track of an arbitrary number of requests
  1304. that might be outstanding at the same time. The first excerpt of {\tt
  1305. pager.c}, which appears in Program~\ref{pager-open.c}, shows the code
  1306. which creates this per-client state. Lines 1--6 define a structure,
  1307. {\tt pager\_client}, which keeps all the information we need about
  1308. each client attached to the driver. The {\tt open} callback for {\tt
  1309. /dev/pager/notify}, shown on lines 12--31, allocates memory for an
  1310. instance of this structure and adds it to a linked list. (If the
  1311. memory allocation fails, an error is returned to the client on line
  1312. 18; this will prevent the file from opening.) Note on line 25 that we
  1313. use the {\tt private\_data} field to store a pointer to the client
  1314. state; this allows the structure to be retrieved when later callbacks
  1315. on this file descriptor arrive. The memory is deallocated when the
  1316. file is closed; we'll see that in a later section.
  1317. \begin{Program}
  1318. \listinginput[5]{1}{pager-open.c.example}
  1319. \caption{pager.c (Part 1): Creating state for every client using the
  1320. driver}
  1321. \label{pager-open.c}
  1322. \end{Program}
  1323. Another thing to notice about the open callback is the use of the {\tt
  1324. last\_page\_seen} variable. The driver gives a sequence number to
  1325. every page it receives; {\tt last\_page\_seen} stores the number of
  1326. the most recent page seen by a client. When a new client arrives
  1327. (i.e., it opens {\tt /dev/pager/notify}), its {\tt last\_page\_seen}
  1328. state is set equal to the page that has most recently arrived; this
  1329. forces a new client to wait for the {\em next} page, rather than
  1330. immediately being notified of a page that has arrived in the past.
  1331. \subsubsection{Blocking and completing reads}
  1332. The next part of {\tt pager.c} is shown in Program~\ref{pager-read.c}.
  1333. The {\tt pager\_notify\_read} function seen on line 1 is registered as
  1334. the {\tt read} callback for the {\tt /dev/pager/notify} device. It
  1335. blocks the read request using the technique we described earlier: it
  1336. stores the {\tt fusd\_file\_info} pointer in that client's state
  1337. structure, and returns {\tt -FUSD\_NOREPLY}. (Note that the pointer
  1338. to the client's state structure comes from the {\tt private\_data}
  1339. field of {\tt fusd\_file\_info}, where the open callback stored it.)
  1340. \begin{Program}
  1341. \listinginput[5]{1}{pager-read.c.example}
  1342. \caption{pager.c (Part 2): Block clients' {\tt read} requests, and later
  1343. completing the blocked reads}
  1344. \label{pager-read.c}
  1345. \end{Program}
  1346. {\tt pager\_notify\_complete\_read} {\em unblocks} previously blocked
  1347. reads. This function first checks to see that there is, in fact, a blocked
  1348. read (line 19). It then checks to see if a page has arrived that the
  1349. client hasn't seen yet (line 23). Finally, it updates the client
  1350. state and unblocks the blocked read by calling {\tt fusd\_return}.
  1351. Note the second argument to {\tt fusd\_return} is a 0; as we
  1352. saw in Section~\ref{read-callback}, a 0 return value to a {\tt read}
  1353. system call means EOF. (The system call will be unblocked regardless
  1354. of the return value.)
  1355. {\tt pager\_notify\_complete\_read} is called every time a new page
  1356. arrives. New pages are processed by {\tt pager\_input\_write} (line
  1357. 34), which is the {\tt write} callback for {\tt /dev/pager/input}.
  1358. After recording the fact that a new page has arrived, it calls {\tt
  1359. pager\_notify\_complete\_read} for each client that has an open file
  1360. descriptor. This will complete the reads of any clients who have not
  1361. yet seen this new data, and have no effect on clients that don't have
  1362. outstanding reads.
  1363. There is another interesting point to notice about {\tt
  1364. pager\_notify\_read}. On line 12, after it stores the blocked system
  1365. call's pointer, but before we return {\tt -FUSD\_NOREPLY}, it calls
  1366. the completion function. This has the effect of returning any data
  1367. that might already be available back to the caller immediately. If
  1368. that happens, we will end up calling {\tt fusd\_return} {\em before}
  1369. we return {\tt -FUSD\_NOREPLY}. This probably seems strange, but it's
  1370. legal. Recall that a callback can call fusd\_return() explicitly {\em
  1371. or} return a normal (not {\tt -FUSD\_NOREPLY}) return value, but not
  1372. both; the order doesn't matter.
  1373. \subsubsection{Using {\tt fusd\_destroy()} to clean up client state}
  1374. \label{fusd-destroy}
  1375. Finally, let's take a look at one last aspect of the pager program:
  1376. how it cleans up the per-client state when a client leaves. This is
  1377. mostly straightforward, with one exception: a client may have an
  1378. outstanding read request out when a close request comes in. Normally,
  1379. a client can't make another system call request while a previous
  1380. system call is still blocked. However, the {\tt close} system call is
  1381. an exception: it gets called when a client dies (for example, if it
  1382. receives an interrupt signal). If a {\tt close} comes in while
  1383. another system call is still outstanding, the state associated with
  1384. the outstanding request should be freed to avoid a memory leak. The
  1385. {\tt fusd\_destroy} function is used to do this, seen on linen 12-14
  1386. of Program~\ref{pager-close.c}.
  1387. \begin{Program}
  1388. \listinginput[5]{1}{pager-close.c.example}
  1389. \caption{pager.c (Part 3): Cleaning up when a client leaves}
  1390. \label{pager-close.c}
  1391. \end{Program}
  1392. \subsection{Retrieving a blocked system call's arguments from a {\tt
  1393. fusd\_file\_info} pointer}
  1394. \label{logring}
  1395. In the previous section, we showed how the {\tt fusd\_return} function
  1396. can be used to specify the return value of a system call that was
  1397. previously blocked. However, many system calls have side effects in
  1398. addition to returning a value---for example, in a {\tt read()}
  1399. request, the data being returned has to be copied into the caller's
  1400. buffer. To facilitate this, FUSD provides accessor functions that let
  1401. drivers retrieve the arguments that had been passed to its callbacks
  1402. at the time the call was originally issued. For example, the {\tt
  1403. fusd\_get\_read\_buffer()} function will return a pointer to the data
  1404. buffer that is provided with {\tt read()} callbacks. Drivers can use
  1405. these accessor functions to affect change to a client {\em before}
  1406. calling {\tt fusd\_return()}.
  1407. The following accessor functions are available, all of which take a
  1408. single {\tt fusd\_file\_info *} argument:
  1409. \begin{itemize}
  1410. \item {\tt int char *fusd\_get\_read\_buffer}---The destination buffer
  1411. for data that a driver is returning to a process doing a {\tt read()}.
  1412. \item {\tt const char *fusd\_get\_write\_buffer}---The source buffer
  1413. containing data sent to the driver by a process doing a {\tt write()}.
  1414. \item {\tt fusd\_get\_length}---The length (in bytes) of the buffer
  1415. for either a {\tt read()} or a {\tt write()}.
  1416. \item {\tt loff\_t fusd\_get\_offset}---The file descriptor's byte
  1417. offset, typically used in {\tt read()} and {\tt write()} callbacks.
  1418. \item {\tt int fusd\_get\_ioctl\_request}---An ioctl's request
  1419. ``command number'' (i.e., the first argument of an ioctl).
  1420. \item {\tt int fusd\_get\_ioctl\_arg}---The second argument of an
  1421. ioctl for non-data-bearing {\tt ioctl} requests (i.e., {\tt \_IO}
  1422. commands).
  1423. \item {\tt void *fusd\_get\_ioctl\_buffer}---The data buffer for
  1424. data-bearing {\tt ioctl} requests ({\tt \_IOR}, {\tt \_IOW}, and
  1425. {\tt \_IORW} commands).
  1426. \item {\tt int fusd\_get\_poll\_diff\_cached\_state}---See
  1427. Section~\ref{selectable}.
  1428. \end{itemize}
  1429. We got away without using these accessor functions in our {\tt
  1430. pager.c} example because the pager doesn't actually return data---it
  1431. just blocks and unblocks {\tt read} calls. However, the FUSD
  1432. distribution contains another example program, {\tt logring}, that
  1433. demonstrates their use.
  1434. {\tt logring} makes it easy to access the most recent (and only the most
  1435. recent) output from a process. It works just like {\tt tail -f} on a
  1436. log file, except that the storage required never grows. This can be
  1437. useful in embedded systems where there isn't enough memory or disk
  1438. space for keeping complete log files, but the most recent debugging
  1439. messages are sometimes needed (e.g., after an error is observed).
  1440. {\tt logring} uses FUSD to implement a character device, {\tt
  1441. /dev/logring}, that acts like a named pipe that has a finite, circular
  1442. buffer. The size of the buffer is given as a command-line argument.
  1443. As more data is written into the buffer, the oldest data is discarded.
  1444. A process that reads from the logring device will first read the
  1445. existing buffer, then block and see new data as it's written, similar
  1446. to monitoring a log file using {\tt tail -f}.
  1447. You can run this example program by typing {\tt logring <logsize>},
  1448. where {\tt logsize} is the size of the circular buffer in bytes.
  1449. Then, type {\tt cat /dev/logring} in a shell. The {\tt cat} process
  1450. will block, waiting for data. From another shell, write to the
  1451. logring (e.g., {\tt echo Hi there > /dev/logring}). The {\tt cat}
  1452. process will see the message appear.
  1453. (This example program is based on {\em emlog}, a (real) Linux kernel
  1454. module with identical functionality. If you find logring useful, but
  1455. want to use it on a system that does not have FUSD, check out the
  1456. original
  1457. \htmladdnormallinkfoot{emlog}{http://www.circlemud.org/jelson/software/emlog}.)
  1458. \section{Implementing {\tt select}able Devices}
  1459. \label{selectable}
  1460. One important feature that almost every device driver in a system
  1461. should have is support for the {\tt select(2)} system call. {\tt
  1462. select} allows clients to assemble a set of file descriptors and ask
  1463. to be notified when one of them becomes readable or writable. This
  1464. simple feature is deceptively powerful---it allows clients to wait for
  1465. any number of a set of possible events to occur. This is
  1466. fundamentally different than (for example) a blocking read, which only
  1467. unblocks on one kind of event. In this section, we'll describe how
  1468. FUSD can be used to create a device whose state can be queried by a
  1469. client's call to {\tt select(2)}.
  1470. This section is limited to a discussion what a FUSD driver writer
  1471. needs to know to implement a selectable device. Details of the FUSD
  1472. implementation required to support this feature are described in
  1473. Section~\ref{poll-diff-implementation}
  1474. \subsection{Poll state and the {\tt poll\_diff} callback}
  1475. FUSD's implementation of selectable devices depends on the concept of
  1476. {\em poll state}. A file descriptor's poll state is a bitmask that
  1477. describes its current properties---readable, writable, or exception
  1478. raised. These three states correspond to {\tt select(2)}'s three
  1479. {\tt fd\_set}s. FUSD has constants used to describe these states:
  1480. \begin{itemize}
  1481. \item {\tt FUSD\_NOTIFY\_INPUT}---Input is available; a read will not
  1482. block.
  1483. \item {\tt FUSD\_NOTIFY\_OUTPUT}---Output space is available; a write
  1484. will not block.
  1485. \item {\tt FUSD\_NOTIFY\_EXCEPT}---An exception has occurred.
  1486. \end{itemize}
  1487. These constants can be combined with C's bitwise-or operator. For
  1488. example, a descriptor that is both readable and writable is expressed
  1489. as {\tt FUSD\_NOTIFY\_INPUT | FUSD\_NOTIFY\_OUTPUT}. 0 means a file
  1490. descriptor is not readable, not writable, and not in the exception
  1491. set.
  1492. For a FUSD device to be selectable, its driver must implement a
  1493. callback called {\tt poll\_diff}. This callback is very different
  1494. than the others; it is not a ``direct line'' between the client and
  1495. the driver as is the case with a call such as {\tt ioctl}. A driver's
  1496. response to {\tt poll\_diff} is {\em not} the return value seen by a
  1497. client's call to {\tt select}. When a client tries to {\tt select} on
  1498. a set of file descriptors, the kernel collects the responses from all
  1499. the appropriate callbacks---{\tt poll} for file descriptors managed by
  1500. kernel drivers, and {\tt poll\_diff} callbacks those managed by FUSD
  1501. drivers---and synthesizes all of that information into the return
  1502. value seen by the client.
  1503. FUSD keeps a cache of the poll state it has most recently received
  1504. from each FUSD device driver, initially assumed to be 0. This state
  1505. is returned to clients trying to {\tt select()} on devices managed by
  1506. those drivers. Under certain conditions, FUSD sends a query to the
  1507. driver in order to ensure that the kernel's poll state cache is up to
  1508. date. This query takes the form of a {\tt poll\_diff} callback
  1509. activation, which is given a single argument: the poll state that FUSD
  1510. currently has cached. The driver should consult its internal data
  1511. structures to determine the actual, current poll state (i.e., whether
  1512. or not buffers have readable data). Then:
  1513. \begin{itemize}
  1514. \item If the FUSD cache is incorrect (that is, the current true poll
  1515. state is different than FUSD's cached state), the current poll state
  1516. should be returned immediately.
  1517. \item If the FUSD cache is up to date (that is, it matches the real
  1518. current state), the callback should save the {\tt fusd\_file\_info}
  1519. pointer and return {\tt -FUSD\_NOREPLY}. Later, when the poll
  1520. state changes, the driver can call {\tt fusd\_return()} to update
  1521. FUSD's cache.
  1522. \end{itemize}
  1523. In other words, when a driver's {\tt poll\_diff} callback is
  1524. activated, the kernel is effectively saying to the driver, ``Here is
  1525. what I think the current poll state of this file descriptor is; let me
  1526. know when that state {\em changes}.'' The driver can either respond
  1527. immediately (if the kernel's cache is already known to be out of
  1528. date), or return {\tt -FUSD\_NOREPLY} if no update is immediately
  1529. necessary. Later, when the poll state changes (for example, if new
  1530. data arrives that makes a device readable), the driver can used its
  1531. saved {\tt fusd\_file\_info} pointer to send a poll state update to
  1532. the kernel.
  1533. When a FUSD driver sends a poll state update, it might (or might not)
  1534. have the effect of waking up a client that was blocked in {\tt
  1535. select(2)}. On the same note, it's worth reiterating that a {\tt
  1536. -FUSD\_NOREPLY} response to a {\tt poll\_diff} callback {\em does not}
  1537. necessarily block the client---other descriptors in the client's {\tt
  1538. select} set might be readable, for example.
  1539. \subsection{Receiving a {\tt poll\_diff} request when the previous one
  1540. has not been returned yet}
  1541. \label{multiple-polldiffs}
  1542. Calls such as {\tt read} and {\tt write} are synchronous from the
  1543. standpoint of an individual client---a request is made, and the
  1544. requester blocks until a reply is received. This means that there
  1545. can't ever be more than a single {\tt read} request outstanding for a
  1546. single client at a time. (The driver as a whole may be keeping track
  1547. of many outstanding {\tt read} requests in parallel, but no two of them will
  1548. be from the same client file descriptor.)
  1549. As we mentioned in the previous section, the {\tt poll\_diff} callback
  1550. is different from other callbacks. It is not part of a synchronous
  1551. request/reply sequence that causes the client to block. It is also an
  1552. interface to the {\em kernel}, not directly to the client. So, it
  1553. {\em is} possible to receive a {\tt poll\_diff} request while there is
  1554. already one outstanding. This happens if the kernel's poll state
  1555. cache changes, causing it to notify the driver that it has a new
  1556. cached value.
  1557. This is easy to handle; the client should simply
  1558. \begin{enumerate}
  1559. \item Destroy the old (now out-of-date) {\tt poll\_diff} request
  1560. using the {\tt fusd\_destroy} function we saw in
  1561. Section~\ref{fusd-destroy}.
  1562. \item Either respond to or save the new {\tt poll\_diff} request,
  1563. exactly as described in the previous section.
  1564. \end{enumerate}
  1565. The next section will show an example of this technique.
  1566. \subsection{Adding {\tt select} support to {\tt pager.c}}
  1567. Given the explanation of {\tt poll\_diff} in the previous sections, it
  1568. might seem that implementing a selectable device is a daunting task.
  1569. It's actually not as bad as it sounds---the example code may well be
  1570. shorter than its explanation!
  1571. \begin{Program}
  1572. \listinginput[5]{1}{pager-polldiff.c.example}
  1573. \caption{pager.c (Part 4): Supporting {\tt select(2)} by implementing a
  1574. {\tt poll\_diff} callback}
  1575. \label{pager-polldiff.c}
  1576. \end{Program}
  1577. Program~\ref{pager-polldiff.c} shows the implementation of {\tt
  1578. poll\_diff} in {\tt pager.c}, which makes its notification interface
  1579. ({\tt /dev/pager/notify}) selectable. It is decomposed into a ``top
  1580. half'' and ``bottom half'' function, exactly as we did for the
  1581. blocking {\tt read} implementation in Program~\ref{pager-read.c}.
  1582. First, on lines 1--20, we see the the callback for {\tt poll\_diff}
  1583. callback itself. It is virtually identical to the {\tt read} callback
  1584. in Program~\ref{pager-read.c}. The main difference is that it first
  1585. checks (on line 12) to see if a {\tt poll\_diff} request is already
  1586. outstanding when a new request comes in. If so, the out-of-date
  1587. request is destroyed using {\tt fusd\_destroy}, as we described in
  1588. Section~\ref{multiple-polldiffs}.
  1589. The bottom half is shown on lines 22-46. First, on lines 32--35, it
  1590. computes the current poll state---if a page has arrived that the
  1591. client hasn't seen yet, the file is readable; otherwise, it isn't.
  1592. Next, the driver compares the current poll state with the poll state
  1593. that the kernel has cached. If the kernel's cache is out of date, the
  1594. current state is returned to the kernel. Otherwise, it does nothing.
  1595. As with the {\tt read} callback we saw previously, notice that {\tt
  1596. pager\_notify\_complete\_polldiff} is called in two different cases:
  1597. \begin{enumerate}
  1598. \item It is called immediately from the {\tt pager\_notify\_polldiff}
  1599. callback itself. This causes the current poll state to be returned to
  1600. the kernel immediately when the request arrives if the driver already
  1601. knows the kernel's state needs to be updated.
  1602. \item It is called when new data arrives that causes the poll state to
  1603. change. Refer back to Program~\ref{pager-read.c} on
  1604. page~\pageref{pager-read.c}; in the callback that receives new pages,
  1605. notice on line 45 that the {\tt poll\_diff} completion function is called
  1606. alongside the {\tt read} completion function.
  1607. \end{enumerate}
  1608. With this {\tt poll\_diff} implementation, it is possible for a client
  1609. to open {\tt /dev/pager/notify}, and block in a {\tt select(2)} system
  1610. call. If another client writes {\tt page} to {\tt /dev/pager/input},
  1611. the first client's {\tt select} will unblock, indicating the file has
  1612. become readable.
  1613. For additional example code, take a look at the {\tt logring} example
  1614. program we first mentioned in Section~\ref{logring}. It also supports
  1615. {\tt select} by implementing a similar {\tt poll\_diff} callback.
  1616. \section{Performance of User-Space Devices}
  1617. \label{performance}
  1618. This section hasn't been written yet. I have some pretty graphs and
  1619. whatnot, but no time to write about them here before the release.
  1620. \section{FUSD Implementation Notes}
  1621. In this section, we describe some of the details of how FUSD is
  1622. implemented. It's not necessary to understand these details in order
  1623. to use FUSD. However, these notes can be useful for people who are
  1624. trying to understand the FUSD framework itself---hackers, debuggers,
  1625. or the generally curious.
  1626. \subsection{The situation with {\tt poll\_diff}}
  1627. \label{poll-diff-implementation}
  1628. In-kernel device drivers support select by implementing a callback
  1629. called {\tt poll}. This driver's callback is supposed to do two
  1630. things. First, it should return the current state of a file
  1631. descriptor---a combination of being readable, writable, or having
  1632. exceptions. Second, it should provide a pointer to one of the
  1633. driver's internal wait queues that will be awakened whenever the state
  1634. changes. The {\tt poll} call itself should never block---it should
  1635. just instantaneously report what the {\em current} state is.
  1636. FUSD's implementation of selectable devices is different, but attempts
  1637. to maintain three properties that we thought to be most important from
  1638. the point of view of a client using {\tt select}. Specifically:
  1639. \begin{enumerate}
  1640. \item The {\tt select(2)} call itself should never become blocked.
  1641. For example, if one file descriptor in its set isn't readable, that
  1642. shouldn't prevent it from reporting other file descriptors that are.
  1643. \item If {\tt select(2)} indicates a file descriptor is readable (or
  1644. writable), a read (or write) on that file descriptor shouldn't block.
  1645. \item Clients should be allowed to seamlessly {\tt select} on any set
  1646. of file descriptors, even if that set contains a mix of both FUSD and
  1647. non-FUSD devices.
  1648. \end{enumerate}
  1649. The FUSD kernel module keeps a cache of the driver's most recent
  1650. answer for each file descriptor, initially assumed to be 0. When the
  1651. kernel module's internal {\tt poll} callback is activated, it:
  1652. \begin{enumerate}
  1653. \item Dispatches a {\em non-}blocking {\tt poll\_diff} to the
  1654. associated user-space driver, asking for a cache update---if and only
  1655. if there isn't already an outstanding poll diff request out that has
  1656. the same value.
  1657. \item Immediately returns the cached value to the kernel
  1658. \end{enumerate}
  1659. In addition, the cached value's readable bit is cleared on every read;
  1660. the writable bit is cleared on every write. This is necessary to
  1661. prevent old poll state---which says ``device is readable''---from
  1662. being returned out of the cache when it might be invalid. FUSD
  1663. assumes that any read to a device can make it potentially unreadable.
  1664. This mechanism is what causes an updated poll diff to be sent to a
  1665. client before the previous one has been returned.
  1666. (this section isn't finished yet; fancy time diagrams coming someday)
  1667. \subsection{Restartable System Calls}
  1668. No time to write this section yet...
  1669. \appendix
  1670. \section{Using {\tt strace}}
  1671. \label{strace}
  1672. This section hasn't been written yet. Contributions are welcome.
  1673. \end{document}