From 0f5535a756241dd697c135d13ae6b25e2fe519e7 Mon Sep 17 00:00:00 2001 From: xiphmont Date: Sat, 13 Jan 2007 08:39:56 +0000 Subject: [PATCH] Place personal working copy of fusd into revision control git-svn-id: http://svn.xiph.org/trunk/fusd@12312 0101bb08-14d6-0310-b084-bc0e0c8e3800 --- ChangeLog | 98 + LICENSE | 35 + Makefile | 38 + README | 139 ++ doc/.cvsignore | 7 + doc/Makefile | 24 + doc/fusd-html-docs.tar.gz | Bin 0 -> 390886 bytes doc/fusd.pdf | Bin 0 -> 186129 bytes doc/fusd.ps | 3951 +++++++++++++++++++++++++++++++++++++ doc/fusd.tex | 2013 +++++++++++++++++++ doc/html.sty | 1158 +++++++++++ doc/make-examples.pl | 50 + examples/console-read.c | 99 + examples/drums.c | 117 ++ examples/drums2.c | 144 ++ examples/drums3.c | 200 ++ examples/echo.c | 124 ++ examples/helloworld | Bin 0 -> 27353 bytes examples/helloworld.c | 91 + examples/ioctl.c | 292 +++ examples/logring.c | 455 +++++ examples/pager.c | 386 ++++ examples/uid-filter.c | 113 ++ include/fusd.h | 285 +++ include/fusd_msg.h | 151 ++ include/kfusd.h | 288 +++ kfusd/Makefile | 19 + kfusd/Module.symvers | 0 kfusd/kfusd.c | 2943 +++++++++++++++++++++++++++ libfusd/Makefile | 30 + libfusd/libfusd.c | 687 +++++++ make.include | 149 ++ 32 files changed, 14086 insertions(+) create mode 100644 ChangeLog create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 doc/.cvsignore create mode 100644 doc/Makefile create mode 100644 doc/fusd-html-docs.tar.gz create mode 100644 doc/fusd.pdf create mode 100644 doc/fusd.ps create mode 100644 doc/fusd.tex create mode 100644 doc/html.sty create mode 100755 doc/make-examples.pl create mode 100644 examples/console-read.c create mode 100644 examples/drums.c create mode 100644 examples/drums2.c create mode 100644 examples/drums3.c create mode 100644 examples/echo.c create mode 100755 examples/helloworld create mode 100644 examples/helloworld.c create mode 100644 examples/ioctl.c create mode 100644 examples/logring.c create mode 100644 examples/pager.c create mode 100644 examples/uid-filter.c create mode 100755 include/fusd.h create mode 100755 include/fusd_msg.h create mode 100755 include/kfusd.h create mode 100755 kfusd/Makefile create mode 100644 kfusd/Module.symvers create mode 100755 kfusd/kfusd.c create mode 100755 libfusd/Makefile create mode 100755 libfusd/libfusd.c create mode 100644 make.include diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..b5e7a63 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,98 @@ +v monty-1.11 January 11, 2007 + + Update for 2.6.recent (tested on 2.6.17 through 19) + Update module option code + Replace illegal type puns with unions + Eliminate all dead devfs code + Fix kernel panics caused by incorrect error handling + Build system updates + +v kor-1.10-11 April 9, 2006 + + Added fixes for kernels 2.6.15 and 2.6.12 (Thanks to Joachim Forster) + Fixed some compiler warnings on amd64 architecture + +v kor-1.10-10 Sept 17, 2005 + + Added support for kernels 2.6.13 + Broke previous kernels + +v kor-1.10-9: Jun 18, 2005 + + Added support for mmap + Added support for simultaneous requests on the same file descriptor + from separate processes. + +v kor-1.10-8: Feb 10, 2005 + + Fixed some shutdown issues for non-devfs systems. + +v kor-1.10-7: Feb 9, 2005 + + Modified to work udev + +v kor-1.10-6: Feb 17, 2004. + + Modified to work with the 2.6 kernel and devfs. + +v 1.10: August 19, 2003 + + First UCLA release -- no longer publically maintained or released + by Sensoria. This version is the UCLA (public) fork. + + Kernel module now, finally, has correct fine-grained locking that + does not assume atomicity of kernel code. In other words, FUSD is + now safe for SMP machines, preemptible kernels, etc. + + Python bindings have been contributed by Brian Warner. + + The old /dev/fusd control file has been moved into a subdirectory, + /dev/fusd/control. + + Human-readable status is now available in /dev/fusd/status. + + By doing an ioctl() on /dev/fusd/status, it can also give you + binary status information -- reads will return an array of + fusd_status_t structures. + + Many, many subtle bugs have been fixed (e.g. rare race + conditions). + + Lots of updates and bug-fixes to the documentation, which was + carefully read by a number of people who were actually trying to + use it. + + +v 1.04: February 5, 2002 + + Change from the point of view of clients: Selecting on an FD being + provided by a FUSD driver will return as part of the exception set + if the driver disappears. Useful for client programs that want to + gracefully handle driver crashes. + + Some changes to get semantics of poll_diff (closer to) correct - + will require some more changes later + + Reduced max number of messages dispatched per call to + fusd_dispatch. very slightly less efficient, but more fair. + + Protocol change - max name length now 47 instead of 31 + + Minor kernel module fixes: Fixed the malloc.h/slab.h confusion, + and added MODULE_LICENSE. + + Minor API change: fusd_register now takes a const char * + name instead of a char *name. + + +v 1.03: October 3, 2001 + Documentation fixs and a clarification of the license. + +v 1.02, +v 1.01: October 1, 2001 + Various Makefile issues fixed that were keeping the package from + building. + +v 1.00: September 28, 2001 + Initial public release. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6affe25 --- /dev/null +++ b/LICENSE @@ -0,0 +1,35 @@ + +FUSD is free software, distributed under a GPL-compatible license (the +``new'' BSD license, with the advertising clause removed). The +license is enumerated in its entirety below. + +------------------------------------------------------------------------- + +Copyright (c) 2001, Sensoria Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the Sensoria Corporation nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..671483a --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +##### +# +# Makefile for FUSD +# +PREFIX = /usr/local +LIBDIR = $(PREFIX)/lib +INCDIR = $(PREFIX)/include + +CC = gcc +LD = gcc +INSTALL = install +STRIP = strip +PREFIX = /usr/local +BINDIR = $(PREFIX)/bin +ETCDIR = /etc/$(TARGET) +MANDIR = $(PREFIX)/man + +GCF = -std=gnu99 -O2 -g -I../include +SCF = -fPIC +SLF = -shared -nostdlib + +export + +#################################################### + +SUBDIRS = kfusd libfusd + +default: + $(MAKE) -C libfusd + $(MAKE) -C kfusd + +install: + $(MAKE) -C libfusd install + $(MAKE) -C kfusd install + +clean: + $(MAKE) -C kfusd clean + $(MAKE) -C libfusd clean diff --git a/README b/README new file mode 100644 index 0000000..b4edb5c --- /dev/null +++ b/README @@ -0,0 +1,139 @@ + +FUSD: A Linux Framework for User-Space Devices +---------------------------------------------- + +Welcome to FUSD! + +This is FUSD snapshot 20070111, released 11 January 2007. You can get +the most recent source, along with online documentation, from xiph.org +SVN: + +http://svn.xiph.org/trunk/fusd + +There is extensive documentation available in the 'doc' directory. +The FUSD User Manual is available in PDF, Postscript, and HTML format. +Most of this documentation dates from earlier versions of fusd; until +it is fully updated, it may not cover all features that exist in the +current version of fusd. + +FUSD is free and open source software, released under a BSD-style +license. See the file 'LICENSE' for details. + + +QUICK START GUIDE +================= + +Instructions for the impatient: + +1- Make sure you're using a system running Linux 2.6.x with udev; this +version of fusd is incompatable with the now-deprecated devfs. If the +kernel is a packaged version from a distribution, also verify any +optional packages needed for building new kernel modules are also +installed. + +2- 'make ; make install' builds everything including examples, then +installs the libraries, includes and kernel module. + +3- Update the udev configuration (usually in /etc/udev/rules.d/) to +include the following rule: + + # fusd device + SUBSYSTEM=="fusd", NAME="fusd/%k" + +After updating, restart udevd (skill udevd; udevd -d). + +4- Insert the FUSD kernel module (modprobe kfusd) + +5- Verify the fusd devices /dev/fusd/status and /dev/fusd/control +exist. If the modprobe succeeds but no fusd devices appear, +doublecheck the udev rule config change and make sure udevd restarted +successfully. The kfusd kernel module must be inserted after udev has +been correctly configured and restarted. + +6- Try running the helloworld example program (examples/helloworld). +When helloworld is running, 'cat /dev/helloworld' should return +'Hello, world!'. + +7- For more information, read the User's Manual in the 'doc' directory. + +WHAT IS FUSD? +============= + +FUSD (pronounced "fused") is a Linux framework for proxying device +file callbacks into user-space, allowing device files to be +implemented by daemons instead of kernel code. Despite being +implemented in user-space, FUSD devices can look and act just like any +other file under /dev which is implemented by kernel callbacks. + +A user-space device driver can do many of the things that kernel +drivers can't, such as perform a long-running computation, block while +waiting for an event, or read files from the file system. Unlike +kernel drivers, a user-space device driver can use other device +drivers--that is, access the network, talk to a serial port, get +interactive input from the user, pop up GUI windows, or read from +disks. User-space drivers implemented using FUSD can be much easier to +debug; it is impossible for them to crash the machine, are easily +traceable using tools such as gdb, and can be killed and restarted +without rebooting. FUSD drivers don't have to be in C--Perl, Python, +or any other language that knows how to read from and write to a file +descriptor can work with FUSD. User-space drivers can be swapped out, +whereas kernel drivers lock physical memory. + +FUSD drivers are conceptually similar to kernel drivers: a set of +callback functions called in response to system calls made on file +descriptors by user programs. FUSD's C library provides a device +registration function, similar to the kernel's devfs_register_chrdev() +function, to create new devices. fusd_register() accepts the device +name and a structure full of pointers. Those pointers are callback +functions which are called in response to certain user system +calls--for example, when a process tries to open, close, read from, or +write to the device file. The callback functions should conform to +the standard definitions of POSIX system call behavior. In many ways, +the user-space FUSD callback functions are identical to their kernel +counterparts. + +The proxying of kernel system calls that makes this kind of program +possible is implemented by FUSD, using a combination of a kernel +module and cooperating user-space library. The kernel module +implements a character device, /dev/fusd, which is used as a control +channel between the two. fusd_register() uses this channel to send a +message to the FUSD kernel module, telling the name of the device the +user wants to register. The kernel module, in turn, registers that +device with the kernel proper using devfs. devfs and the kernel don't +know anything unusual is happening; it appears from their point of +view that the registered devices are simply being implemented by the +FUSD module. + +Later, when kernel makes a callback due to a system call (e.g. when +the character device file is opened or read), the FUSD kernel module's +callback blocks the calling process, marshals the arguments of the +callback into a message and sends it to user-space. Once there, the +library half of FUSD unmarshals it and calls whatever user-space +callback the FUSD driver passed to fusd_register(). When that +user-space callback returns a value, the process happens in reverse: +the return value and its side-effects are marshaled by the library +and sent to the kernel. The FUSD kernel module unmarshals this +message, matches it up with a corresponding outstanding request, and +completes the system call. The calling process is completely unaware +of this trickery; it simply enters the kernel once, blocks, unblocks, +and returns from the system call---just as it would for any other +blocking call. + +One of the primary design goals of FUSD is stability. It should +not be possible for a FUSD driver to corrupt or crash the kernel, +either due to error or malice. Of course, a buggy driver itself may +corrupt itself (e.g., due to a buffer overrun). However, strict error +checking is implemented at the user-kernel boundary which should +prevent drivers from corrupting the kernel or any other user-space +process---including the errant driver's own clients, and other FUSD +drivers. + +For more information, please see the comprehensive documentation in +the 'doc' directory. + + Jeremy Elson + August 19, 2003 + + updated, + Monty + January 11, 2007 diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..a91ce05 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,7 @@ +*.out +*.log +*.aux +*.dvi +*.toc +*.lop +*.[ch].example diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..be12586 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,24 @@ +default: docs + +clean: + @rm -f *.[ch].example + +examples: + @rm -f *.[ch].example + @./make-examples.pl ../examples/*.[ch] + +docs: examples + latex fusd + latex fusd + +html: + latex2html fusd + rm -f fusd/*.pl + rm -f fusd/images.* + rm -f fusd/WARNINGS + tar czvf fusd-html-docs.tar.gz fusd + +pdf: docs + dvips -t Letter -Ppdf -G0 fusd.dvi + ps2pdf fusd.ps + diff --git a/doc/fusd-html-docs.tar.gz b/doc/fusd-html-docs.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..65a4d50e4a5d7534e46c0dda5f32f9e65f6981ed GIT binary patch literal 390886 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 z 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
    l!r*2Iwky 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ð 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᙮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

    MaNNW2L98sh*`8l9Ts67eaFX-d>t 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°kIqKJw#Jl0wY#XiUX+DRlP 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 gC2C&vVUM-mOMf->-FSnO*7}G2>$c*Wm02$$l zd8w#UZ`*P5x7L`evmS2Lvfv~uQ7s<|+n&a#^r?gvz7zu13!oN@8(iH!UH;_D|Fvp0 zha=kC$a0)j#1-`zjBV~l6x4W8#0H7|ipbD(K|#2U#5+pSclaGS4&^X?xkpVVxD~RX z7suxDdDef$Ctdk9Ez6}*5_5za1iBBjV<@}fv%niZI^NNvtwT1OzlgtTQLoWc9IF_# zxSV=YbWWtP6oDNg$a=&_Z6Da$>!hBbk;kjw&f=cCKxY>Mpy5hd)$LXik>O^5NRl-u zMzN@ysvTM0F}Hgp&^)a&T`*(emI4j@Ik`_1K=^GN1~_m;4DsSk@lopT3LW=GK68O( z=P+ios1d#%YKtJyRpTgn!?}ThE=H!YLq_AXmVj^JnV~{h$HIn7RWNj~|1FR#I{v&f z>>ykIuxUZ=UU9=K8;!L_>-48aCs{g&PcsQzz>V_d=(1P#JL)y7Gy0U%tM)n17(p|^ z+60jE!EmnEnHB5Y&BLc3_La%y&*#ys_fDE6?-3aeXifL_=D9jl$VRnMrCP_I77j!5 z%cj}Q2T^YLVp`@aV=m~o{SCa|%N(pr6R*%dc3)rNt-RoAv{da&*p9~9H-j2nohc$I zY@`wZt~~bZWiKe_1EKt)s+~X@@Th_W=E$T3l>~lfM1pkQ;Md`{0E+;xTZ!Hq*#<_Fyef?0@LYClP<{~7q^91NktNF> zk!NO+Nz)7#o9*Kb5y);P5`6Glz(4mw24 z4k~v54KGB#kSIt_~jz>uB|`W1fZkNDbRBO}~HR*}wZC(e38 z-G~h5@4p^g2j4%Ot_g>Nl=+;{-6@YeE@C_;*uldbj4ryd2eZapaTU*B8#SA-Un7t+ zJ)^)^gu&!=%T{Evsm}+b9~p;+tRnra8eThUpL%KX?71N#OD;0C^i^@D=Wfp*jBx&Z za<#PLZ(1749dy`VE;Ifq&ETquJLY1i<5bwk-c0EJ&T+}Aoqe8@Kkb%H$DcW!lNP#v=3a6ro#pyZjyvLF$DN&HK|x1G`^YE zjeOkfpjyQ>3y8rqi0)qW zr+ox}YI&Y-DIq};6zWTgiFpIhS;O0TdB!6gUEVbIL{Jk=!z;JSMXdSpqitofL2;{X zFI&0kAzesJG&aeMi;l`g%FPBY$iAySZ>ewc6})+=jG%nLWH=<+!d-T8jIvZp*s|*R zkCh|yy&OYraS{qhCAtDOhhI?W*xZMZanESYiHcsBW?O=H@34&FqTM|w|ip^E&f3^J)?8k%p(PXTsirC{srg%*qL ze$`$gAOM2AwO#w8?%K&iN@+03D}@eCC;@mP!1p@Y1&;yE6aQsT>b8|F-HN^WDR!Ue zrybC~W9+vb93A?(xl~(=w^)YtN@<27fbR#Y$gv2$D^bEt1e&_v$1X+^Lv5W_vNp4h z^3udFXq^NQOgd_7m2j121LyIURWWZ2jiAB>5+H@#>$t_y(V6NyQ>njYw*JLq@Dp+D zH^lv;E1RRhaq8J!>(8R0o~a#@4*$aywX742ys7a7$Bbdk;qaJS+@5<^BK1=@Cx91G zqAABsDc#RuebOkWl4dgB*%`M16*?$b!)^0DNhJ{eb%HXls^>2 zVR?3C;%q|rDrSePQ5AwO2@`@oe@5qrp86(R0Kc;|XY$4#9P#DLIl1UxJKz@AEqnglD!ND5{ZP&BKY~H#;3qBO z)N%2_X9}5nMgjNL`prO3xb;1H+|32)GUsG?c|v9NsPY#Mo#2!^;7d$W9x?9ELYv=~ zmgsUIQ=!R6PdF$N>^4~+N#09;;s#>e!WS{hYQneH<{qC;YT*{eAW1_h2{&-*D-;xd z) z^vHP|2PERUXsYzuah*Qyb(y-PvJoQf6-0@5fXckC!= z%O?Utbm%wKhOFj^a90SadFDG4>gYNmIfe%kI3s)L{nVLlJ(LOgati)sOpb%u8vMQl z6YyjVvLl?q@Z;N$p|1dEo$CjLw=kCoZ0&D7Pw!z-soy+W=$!`0tVs(mw(_1)V+*S1 zcI7nT;#SgLc!+k6rnljYjPlhdGW`~7x?GiK(t*XC=iiKk;H|NfIp@fOs+(hL&3XP@ zx@^)hv)ibCH=Xu8T#LB{;ZGG6jm-&fZ5KJIp61EJeukhURqEZ7w4AF38KG4!_(d*_ zD1f^M-1)P`c?KT+#(Mc|Nb`8aS|#lrTqvegnGAvpge~j5=Y9pA^MxC4027@sr11Fs zK>ZeH-6QQ%On|%o?yCE+`U6h8{|7CWWwQRrGi=MO7_7p8 zZGX>(gy^lb3)C-X$RGn5Z09kTV4PloaBefutJ5ZNCB33I<;?*iAl|i0Z3K9IT^-J# z;C{V~4a6Z|kWm7bF!FuRhPtHKTV}Q`AnTA{F$kPN9dm zDQCB`$Fk!ySlF*K2N>7zeX=X;T(cBM=7-CPDg~h&R_ORxiQVsYYpH0pM`zns@B#3c zo|`xaKcOBxs=^;k9GLezsK(}yzYlPA2TT~y9kmUNu7H2t(}EZI(aPwcqNK4l5^J-U zvE?w2SWr+B6PLH!A)uf@Ks~XII5$HL=r z1CMKuPIUy)?8lyd?OeKt?vuwQj``xBx2wC4y)BxoUE4u{R>8MTO_u_wf!hIIEpbkbpUD4`G;+2RY;^qB$ml(P%O^GB#;LpP}n z{#~n{xGX^<{apGZNU$lHAOi@O^My*=S7?B0_ywa)rQaS|{HQz%SQ(Ax`i@=%9i z^DrvB+j(yWMF~3&UDL(-9atFFzQN8BE-u4#W62dh*<#!s*l0aF*x)q1+8s1}Xu)FD zK97&5O#<&RH=Z8T08Cv!NgZzXS?BU4JHQo~WpcN1n+ zJ2c$zx~1p96V>*1!|<&*o%T=3^_k?0U?6@57G*B`-_hf1X_+l}MegS z*e4%;S@o;_1qL3EpnMt7yPt|0s9v}?aB`g|gd7ArjS#R?)&7f?gduouznf*iR@0acUBaw}b zw0_PjH#UyEO(1|QC;?Nf?Ffda5c=!~P|S4i!BBwkLM9|8FvgEZ6_g9$-yk4XWUV@U zgcXj_mkwbYFBoG-lK0ALxI5c?)*$>W%Ka%`@cqwzb{Zv13oRW(wt8O2Ol}P`46!2E zp#DQ=JC_Vb+~l)0H!t7do0{gI(KqD9-l!Te4bA*Z$u9b^o7n=3bKdl|H;P&@pb`v8 zh6)JlUqSbj73?(giHk72%Bv}Ej`uLq0=SBRZd|FMO|~Vpm<<0_vnc3GvY)x|G+wTJ z65;)N`~~2Pf8LG&3!x7{t91IDz;>Ry4Dmn+mzX8L%%V^0$AQct-0R?3w_hwEs-~T4 zDyEGlJyWYZUTWTL4lcMMSuVCpyyeC$rEcwXO*$|}iz9q{V`zp&tLXVK{BdrVbPTu= zmKnS^c)TGp&t1ZQ402z9t#?hqe<8fTHf>Q|Y5rtIaI@GHrLnTiGhtSiWx-wx0n2U? z4iu3pyNA1Dhew=&MIQ}5}n1`xufJLJokZjG~XNJaty@nYn-0~6&1SY@OM#u4BIcdHP5pzU&Y5rRx$ z4PU*N1M_UHYsLA|ESD2hOcZ~_vKfig8c3Wr6*pjH3ca-wO0ef(gR)&VDw)z9@pPOs zt`4n2twgpiT~r>uQ*8-Pa{{DrCo`#~1e=C}zQf$Ez-t^$my3VbR1;X|zjxOmTTybk>T#4 zmB-1!!k)K1H}nFddU)g^K1X?_+`=*lzxrHh2uv(W4tx+y1Syd+#LplrKwM3T*~lA6 z?578(tGANX)U0P28L62sDc2CEq9>gWb^RL!pKGX_;l3s;hsn+dmq@t2q8g8T;qqiGlruD*2wm@#Twy0S|2b(-WHBL{n18o9%fV@BG2*hxSa7Ow zuxK#)9)2Vj;yJ_FLe8&1^Bm?vD#u)=#Bt{Uo!b3tLa(z|#-yj!0d5H0>!zl9ZF#pBf5<_s?xD=Xz-4AXvASgdHK$d zlMxTHGB-s%w>l)StYg5!*jc7d29FG1Duk1(hA6+^f!YOWUG<#lDY;E_XDWnH85n_I zVYI=^DlxK9HfEt=XUD6WB%%qogIJ#2<-rjA1jFi{Ih~Jzhzwvn=+sxm1j<32(fak>7M2_iwt4pGq z0gBWn1_Zned=dpBdkJ}0d~X-~Do_;kFW=w|4f+!Y-@ZG8Fxr=J7yF+h$d zvfjM1#H|MvfDGNcGcD8w;@{1!uPJBEhfqz}(%Vl*strA7a`F2Dr@=pY=4cQp zt{vzLAa9f0x&GFKxzVv3Sx`6NoEWX$e03Q2$^`&NwfQ^}+fK%ctk2tqyXpZOh=>bl9^``e4folVqfKbpy3Lth z(6uj-ek0@Vna(HLHn@t4Ur~SE`hG)tXmB-koYCa_#{Ip7Xd5ERbvs$J6bAm6?4g2o zkHJBs63eYrauKS_+j__duK!f)O82Oj1^Lr-_sNl(t73ci$EJv8CvOYM4D^Gob3?Ga zp%u+WYCr)YQ0V}WAUXZDpK`%E?~@ThBD*+PFN|3h?-&~XD6yI{cqw1pY6)jhzg4f>bjCv4EopqjnVQrnxL z<$vhW!#Sj`LJWt<(I}}K4zcBYz8Mu71^N{;S6|Dri(KNOhd)Dj_$pmALbG7~z^I>- z+U9wb9LDPP|J~trF0(1vZew4M#(qBlosm+hkH#>K#o&~OV;f_bmL$Tj8N%zEK)>|O zWSvyR2#ulpNEe61Jj48PvDfv$o<~R*4t^YEWHtt7^S3zlqq|YL)HbatjVrE&qm`2) z?JSLHKb7<3i6ca(f)mh&A@BTc4d)|ssI2iO!|K2TIpHJr=Na{TDUMOqyHE&>V1OPbrzI4dB+mUMJ?czS&ek!4;dU&=?*9VC_c2RL(0hmd~G( zlqxb#7zxC8R~+7%`_K?%Vt>m>yI%D}H#Cdne2TW8##ePaiJwYcV}jAY4?7;(PyA1L zo@nA?H#}O~LOi^1&$QMXb_o8iGQ=a6n;ucY`iVbjQsg1He-G3;qJgMfG~CamDonFV zJBVh`)!yH&uC(ecV1;=V*l_Rd2B|6iO6Li);lLwJyZvu|HNq2fNUIbeGa1rG(%`4F z06S-|Zcr<$Cg9>M^toPLduFTPzxQMXqfAapYRy+B8 z-urCah)s^Xn0-6PG_|sC;`l3y>&QRAAmm+xxGdlx0Af>H?&E)1-O{=Oy(llYIIp34 zb7hVq8md8ii%{uB)4>5BTJ}SGNwc&VeTFYB{md|~s6^io2uC93{16iSyVe28>;$fJsbd%1922SGS9pyk))IMUe5;BbNqvu1rs zXXm*W5)4F{=qa7VCa|@DA0zfg8P{d|q1(tJY0M-)-e+hIGgIeuq1y)E^jk6LaQ~q) z*q2^-VTokX8PNacbxLQlwVq59c{Q;jwb>jP0m zO_;dyOcjT!J9hq{l8z&K(EhfLz09m1-Hy+ya1z-HssZ>P9W~VL09OX+9cE};kikYOhvYBo z;Q?=({?k1Ok{?c!SF)rG_rz%>4ve~_0VXjFKio5(Q0!u%B6u=$h#wV2zHJQ+c%*Hc zoc=_i`@vI5n8(&~IGopdXdfHe%TgWc$|5|#j0%2mrz<_{3GERhL0YCtTB{I#gMH%E z@x4!F$%N;pOLL~$t$_%UE<*>Kebqt#%Om)`yNVv+mG#6Ls)+~8X6183U7%|BjR9{( z=y4=O()z79^DxWS@7gh~Av8y~>v!#Y2{f=vS&B6Va~7+`EpjeR1@E=D^^S;-PK4+^ zaMa@|*!TG$xI6FsCx=1Ozmolz#$={cHik|AZu}YtG9+3g1xE`Z)U=@HH8)F|H5)DO ztWr~8^ffu1al3^$FhJ?c5l*n!js?3l5~v_%wP$mLPwf|5^1Etz|BRiHzO|7LwFupb z0U?vpXBKPDPV)E=if1cRuuV283iZXut>}KLF3P#5#3zQl;K(Ph07LY+wss?Yy8FPS z+TgfYrxJb(1=Z}lB@rfV{TQpplqV4V&t8Cnea>s(D_*FwG7qXwalXW@6G3D>Qhsv6 z^(P}0W9DsKl8wg{&ZzH)~>Z&G`CDz1{ z+HS?$uc%MRWvW0=6v4<+gr{d^atVZEuPTCHhUTw*&<{;j-%ZIO@k-bj=fHqMbBnECC#F1m$l^hE~Y@Ci*>55i>AsgB!XJ*Vz3>7Nc6tz5J1?gb8dxW$*n{Y zqk_BtWlL0ag9)>BFSyDtMCVbGy==d+)`43s#uqD5 z5jG!5NI9KvULIC+8t!@;J{?AOoHtfY`?J7wlo03( zf4hgi);ME1Z}?(~R1TVj%7ibTas&LHn?f1-A|t0pb>`5jBCVkWX{)Z6$Q_}o5Wfg~ z__3p8qh?jjSR2cOoo923oKoj<+(uobr7YGE)(Q%IS#r`JbsAora7^)eZ7=NSk%^I= z)2!CP_HUosype+p4Oh;c{dK`MK2P|S?@dM>8}#rY zxmp}E* z@d=*&)D2GFO}YkKgQGYnltcjlF@0@X!=G1ZJ4>ce3Cb98;jA5E4Qm9to%jEATQFA~|b&5{betu#KtW zV22M@5PEq+sbri767zNw%M&#DgjJ~!wCd)(D1>uE&`HP2gW-YDZ)cp*7S%)_&h4j{ zgzT2{d(C>RqK@{!(4$%lK)@A?kN8VB2HAN<5Rl41lTt=KF~$hxk-LFpz*oQfF#cfY zR`Kr9Lq>J{Zc9!`>7^lj$M({3YEbf}xjkRhx`Je|4usnaG-6?BCRy9%aaIp1o|>$8 zo+`Hm`;TXr8sNSL9x3?IP7mq@Frrg4CA}uQWp3hlN^ELiWcdR#_=&Eo5>P)JE8NS1 zm<#pe_80IQ_6>>&Osm4?x1r3HSwt@t&84-hfbedZFZe$lZy`Q_HD5!A`fumui}D2v z8MOZ0^a2qE)a6lWC;=&e=O%h^8Y}J#*3i;q18sq41~KC?gTtO7A{Iq+(Qs{F5?$o+ z;uU99$bf6{9eL4%Ryl?=v%;Okx1+OIIB;N!Zr+>ZtFCBTtonh{A6u4(nLRc@nf)?C z6~~CI)M!jlHL(D}Ct_I(9fK%^*Y+i>Wv2n7=X6~Mf5Lx1WASdL(3K>wSMY~bUHRz& zl_&sdI4SyyKS$L8Frj&&2o_{z!iK>cC;|H+tMN<GJ*h|K`oLUi3TJD zGMch}X2HXWC09*utLs!_`w4!xYsHR?Oh$p4zkd&qVUM!wdLa$GR!+2iGFb6v%w zHqNO?&Y>wpGZ~E}QkJwPGgT2v4F#rv55#+SO-K|$)K1HK9D<-6X=UWW`)}B%qJcHy zt>!#yc&gGZscth73_#X9GCm&+O{h2>q^haRxZsy1>gK@;s5)gg<%}iCj|5lHEZh4F z+lZKGVVg}0@Wp`OG|m1nwl3tgb@DO`ep^F59E z__w)K+n#r>s{>A&8R)F0IdzIY65>l}n^UpRzLw@Jm+(Pq`JnHrm9#lY$j+;(~8detv43`#}OO&>nvpDO|-E zTU9YcgjecM6G9WO%lg|K&mlwuDGw#qLOzUlx@^sM4!>NEW)9kSe8%bGT5#=zX-f9( z%Y0YfNa(%{1QE2MRsO0l)u^iXNt>9Dd#n?t9qCxw*pSQ!GzuJlDus8Cb*Q{-Rn4FB@V0 z9e!-vMl>@fDwCX}{ghedMO9wGY+g9`?BA8>pOeZr?Wn{@ibU;413KHUd($C|01fNr zVr60**Df2pqAd%!_yP)Cf4$QGpxxhw8p+-av1Ur0Em$QncJMl$^cF;rbc7u(0c-v` zq~%QkqWdB%(lRvVEF)|PqvPTQx2!}J3QR#4N5v*_tdu+s))BQ<`4dL@cXcN+fL)M5 zQW)t)j6`l>n=N!9dKJCPowaGuu*#ltalRhWnMAeY0pxT)lG0?CDiyO=h3`NS;{2K z&o=xsYsgGkI2Z|R!I-h$avACB?1gcnZY5zbs&Ebq<#>)YCIba>4oaRqvYXg!k=^p7q|NH_P5{9Ete4uhg~=Nh&rOe zzr3yEa}16o)=AR8-1_$zD4mnRHF-&O7BX3UjMS2bh|~a4%^~GoA7Q~1iJj6D#w!p< zXF`LYf6~Z}lBfPG%U^*qw+m~&m&{Cj9s?08mJCDZy6j9yDQELLq73O?pdlZ3EqX#%U`YTE7vOOs=!`|&v))WDz z{1}jGObTJUT@F@D>LL;+T^VMrxS>{1yGW8)_U*8(PnvOF#y46QD|^@BrbR-iQXF|! z9fE?-wVB^Zo0b>3G_W`49R@? z4;?;_VycA7FwLJ~z1qb~{rQ6(h*C*$B2t;5ED2p=`h_aW1YBNubD@7h`sn(4{PvWA z3^mfNbylE<(NiX?!!+c-!x^%04a?PHDf9OWb<#uN6jPWgF(rMsO}&2KLc^)Az@yMY zITl{RRgh=uVV?MIc-CKyzFLP1+wPW5SBz8=uPsvwnldgqamSo=wJ; ztA-QpX&Xozg)KeKlzqoR6&-8d^{HRUH16xr_M7%F?MZen4pgI{qeUY^K8R6B`vmcV zIZv1IW8=_2Ng)LljpYl5ujuH&1B*u#uZVytI$EjVwjZ0uF%Obgj>=T#C*2%_Z)*2ldtY5)VP;19 z?l6Gp+hA`1dgmp*%0Bm#7$ac*rv=E+6>FHT zEta=}h#6EVWttHG4cWwI8DGyDAy5dm((4W;??zUxx{)K3nX7IRaEE)>x$=>$Y?6%A z^G;cp$4dY7<1c4(sIXqUrN9lrBiRe1JF9D*{zM$oOF2&PBNPUoBfXhLzd1>Zo}VPF z+XWUNvSX|^fOLn|vc&>)joyn|fchZN#H)o061!h=q5)Sel5@OxF0J`ZtNJe$BYE83 z=l9@C`Ugpc&-D+s6%&UGh8u$u3heCPgZRl=1!Sj$t4iwmH#A9*e!ooJ>N}i9X2u1V zIx-L_RGQ5b@L0^h+YZ<@4??(TdB0`a0%Dk(pRz@0m3Ix01WfR{l5=|Kh|au5{7p;m zm>Hx~K{Q8tVU&pXNtX$s?sN^5G$pL@Q~Z#AJ#zJ(c(HCjjQ_KO@xlzJOfMQ^Yug`2 ztqJW(l~-237@p~n!wdhEv#+JHrb(1Iw$84!+r1{8B>0XkHmMbNJzRAMs#zyQp7Xpt zLC<%%p7v7=7WZRgX7oqnb?~mFFipYq@78`-CX?V1tzRuGvapneI~g#29On|6YcN{= zBYV+^Vn@bGbznJL{D&(;)$lJJYlO$FKHHI~W9?*4>&~M(epJvWrMK>+GN>{l4C2G| z5m9H-^b?ZMfDT=>2pQB~6wlK0s8probIr}%JwBBv1H>|HKKJz0W5tdR_G-)Z_8Q0` zymUMBA663TZ{@Zzbecbcmdh&lnM8B~;a{du&R#oIg!WBJ%Qt*I56d0iJ_(rSG#JTPQp$FP_bii0q z+J81JG=DU!ABbNv8*ec9_rvGeRh4I@26NO{XPwdC z8$JDY<(q50YjHFLb3-M~{>`F+?y5%*pXWA!tHZ6X@x<@J+LVXUeXlU0S2ZPrN5ADuvsVuMXJS1PE8t1u zt&HITr45eVHAwmBYK|KhhVW7a+8Qak*&RWp1){1eOJvoNXqa5CE9ACUMG2q;R zp2~+H6kU(%+WIIAYuh#iT2m)HXbSup^_`Zgj4F}is#D{lC#`%-*vl7Vdx7)r$j+-J zDd_#BKAjDgdR8(?GllbpPj$bvR>5&@j#=2WLruXWIyIeB?H|<61OI4nf6GPPF;sC?0Y@$&UeXBBe-(S z0`PKINAz}*tUsuwSw5mng-=}2dyL8iUC33lci$=%x457TtQ;M%Jj`0;oDBf zF8VGMdZ}$N6xa93WR9<;LI3;JIZ9(wT@3~fk}E68tPvmI`V}rL;WxfkAbW|UD)Ok_ zHSl!-8Rh{~R$~+Mue$s<(S>OBVHf)CWJ?eF(Q2C!q%{cCGh>Tog#iIr0j`z}hTG23 zpV0e|tjdIs4*YAl&i5_;uJkWK9Vx2QgBbO61N+jQc=IXo9&Kx6c>0e-MQmj{8>G<- zVk;Ks&W)~5A3>X&UC`=P^vBAxK@3`t&-t zrf6SyTFN{W0NVDlnL;iO!~SF6!LC?#RTW;o#>xQh<|m0)WIJwH%_g#H$9?!xc8?)$ zhjM$Ic9VkOmkzNxy`CRt%Bw0z2RT?P3m&hxlF>QQ6hTa_mAUSvwVLdB-M;o0$xbTggL`G!$ zzrcIqvQK;+oP!j{Iklq;bz9+|5KPu^S&H`Dj=wB}JAmu2^kSW%F*#zd(fCK8A`Jd9 zXz0JT425PD<5e7$)({u8u91!}M6yqQO+xTB8I2zv*cdOnyTOY5DwfsWm}#US4KXuK zP-jf4SLolI<2NDam#&uoS<({JcuWu&Xi&Y`(Qekr(uQ@ zS;{!e%V&iDuvf+|m2^mn_gQVbXYB@&Z7qIs_(6}>F?lJ;gwlg%y}uD1B{WZ?86H6pP>Oq4>u4;jQ#{DLaq6KN! zU>6+Qvf=(x|F2}DQ9MqnhqDmunXgv0R+$kY(%oBmR2VMGMx!0QR|bx^&sHGt*ZC#5 ze_K;a`yB{h&R>k7c6knbWm#%JXrz|1=;_>z&i!*o*-Qduuu$Pg zfXG-t46&s~qx4{k3?x6nRYo<&*OQnUxDyG zOV+a+bUNgTw@7(w@Q0ayJJZm?1n zr9W2Hy={JgG-$HelV)75b>SlB;F7Ap<1tVSrsZc{yx%P3UI>XtD#r%q{OHD{zn`swesh$82OM zD6nhg%215?M$F_b^6t+o9q)XVrvR{@GVo(ONf}Vd$!DBPV(`r+(XEzf-gxRjt`qT=lpv=54&RQ z&mIn&0R=Ofy`Mvo;J8>kC;cElcwBPumV$F%#)B`d%6Q>gsqd00yMG>y2EK?^x6?X) znep$hp6y$q>%D=}{K7pj+pID2Xh7>vK+>@hFcNQ^%{JtOBcPspa;aEJzwvJ9Kg$M( z=8D9NvYhAyX5G?4dIE{PJk629#Nl;ALTpf&j~-y&t-}J^j39{*xDz6S+T_ZP=iF7! zSYv9c0&}_*!U9gQ4<0LmCNGo0aP4^?*sC7zsIJ<`UZ0h)SZ7}&RawJ1|7YjXaJ$@oMH$iL7vWXnb=VcOP5~!o7$aFEkm0CsYFAki*esl?4FAt7!uh7s zK5VLVMHK-S@-E&?bR_(E!PL|tOiNdhpH51Pl@djqIbEujNjJmv@zTlDV=(}lyl78F zZMz!|9=dZ*!1Z)=n5NW<(XJ9{@^LsaknTZM5<=sKP{JUDPGcSP^H8nV&*3=8y1hS` zF(nHQyc1DcGRlWkp+5U?y(}>Z=}E;LmqZ)dw}yW!26Lw9An&ymITMOw#HRb@i=X63 zGVVs1Nf8H3lI`$_Sy|rl*$F&{sJK4@yi~x;JVw~^--0T1?t{8!VuDZc^1XQXwc0~T z;qNocXVV?$IhiAL^!DaRYx`<0G|$bnJrxNVjoQ-GsSj#qQ$IbPG2VXT5)o>H9gI5= zpxDJokP~{Kw~~*eWQVSomW?ffuD*f#VB}0nK)%HZnM5$A%f3w$VpNhQWRAfA0zNP0 zN!f^zF{crQ+2BgD#)+4P$OR(Gsyjwm2=gKo-kxDLB?!l`R8tGB-T)uBv#NEU9`XAO ze?DJnvlyI$w69ib{Z4-Q)?|o`{TE~lO`t-*8?15&uf1CgT1#cVfI1=2omMq(#a>KZ zPZocEdk}6VWIlSAaJCHWs@|lEYpJzhMi0BP0=G_^@-EB#oB&@W?s2cLV%t%w9gCPX z7Jz7(5Smm_5Fsd}uM|o?Et5#YB9K8l5usIdgS9Q*+f_b}(-&4R#m}eRy=Tf_JQ;0} zj}iqIXQ(W!8r?=K7D+jyFYlhHHUTOh5Kk=0&tUhE|Bj|`VCak-HFY*q*mkOiBr2{H ze6Jt&?b++6mwtH8OH4?FRqwb$tBie7BCZs5_)BdY$ed6>f8c-|}g^ZC+# z4$-cba=W`h=wv|M?eTAq_rKG>EXso!>yIupqi9CRfwdp2@bGnlDTPwq0@(&Te~Nx) zzDUF#*&A%gF-ehMv^yjg3~+_{@AYzRW_z5qYS&#Q#>5p?z171$0qvy~cn)lTy#82d zXMxEkAL7auUW=l{a>`+rs>IUh3V*`8CUo+T3%o2)5Dn+e<(2=u{4OhZmL_#krT%2) zlJEWY)O!{m7S!2A=506g!nBLeOOtZg+3Laob{Y|fju5*wRa}#5uGUdvSc~1wx z@a4QzWcqdYtS&Bi`b1@~spwYD89FWnC3lDWSN*_;>2v@F)d0`8dgU3AxH$I5XY_ek zS#jZKYkcmh((OfJ?eYGcG<0HC0U5YTrZDnChdXj&frog(oUnwk{G&>1_Sm}gP^6Dl z`4k;X_H`-J)#j9}$}P02^J0d#JYQ3X=Doqo#qu!#Zi+8de3RKdPcw4qfmg>-_hRII zet*N=$KHfaSp@-m-g85vMAP#AAlcA>mJC+6SJkOd z2g##tDGF}a%vz&_wC%$TM0W=kZpuz&!*)L^_-C7S=l(CT{95u&2kQgs5vuop_5zSc z+U>~f5nf8Gu1mkJ&2Mr8q$p0CDGn-#Mb*-?(ObDR&j_y^%Qlk~(Vo(*JV^tKt;P=P z5u$lA7t}6`?}3ZiXay{H7IrVZ6V9>mk#Hgt7Eq@8-T;%@^GM_63F6ckcOa?K9JMq8lF^}Y zdjVD>ym92fhi&s}f^DPNwlzv>ILVP zz!ciAie{6hq<`Y#4Xb3rrXN-|)~JtZn6x2vNPmkV)zx>QcriMNOo8^hQLJd2-(eHy zX6S&I$@nH$zK%OeTy)tNLz__Q2H*CQ?@2Mz~y;-i=>>J=n z1Nt7RI7U78T(+K{z9flzz&0{Qr-wrI1jk!tfYQ13!-P`2_zTdl(XIVO>eR7z!$C8K zZND-6RgO&3KV<0;s3J^KkKWZNTtj8*oPxb75;mM<5oVbG6rXdiz;C#$pQ_E(yhgb? zf^j=`|Cugsc1rP|`=2bYJ{U!H{vRlMH1glv0Y7m$b&!&@3JiPF$q&QRI0@tB!SJAR z$+=`KO*tXJ$@=lGY}IjlJ`VGAD-yYddv<89K01ZTRKiNS34KCr2acoIgpqMXWtisn z!FhQSQgfzQH!k1%c56LASK;T4$Cez>O|KNjCzxA7t@06GmQ-Ze=upE8J?I2t{iUC# zi%Uw0NbQOzrFDJk=H^XF1u#DmeM5_fZ^nw!F~Z<}kuaLILS5!rnqIFW{I~ql|K1s> z@!!mY!vjMhdAkmRC)BrxiJjWJGfWa0P>R11hf5r$SF(1VtNnB?G>bliNNkQ^*yA+5 zA*ajsKRXWbw(`3uPYrMp`9`#0Xs5>PO2WitM7Q*I_#rI9wBX`-lXk3z^sNyfGLbB4 z5kR;g>_y{rH;q@{rn2Bmi4JX@XOxu|RIedYs2ybYE#S6IJHn~2{6@eR53?wEPB~bt zw_NN%?Sm-HTl>Dv!JN?X4Le?;8VOQ`u^wV+Vp9!BmNKn0^lk^vkp_!KKc?;%VK*t4 z+x7cBcD~9xEDp@Uh9XO@QA(QSQm(dg!0pScgmSYI&&YNfg4jVc*;6O3jhoz1`$aj) z<)(qRvEt~&X2G=5rMkafbUd47T;~wBaR6Z=T-H)FP6pm{Wk^L^Wu3<|W5#4e+53-& zpEh3m>DsqMJ__p

    EBo^T<`c&(Ds7!&nH>+}5w73FJk+`q^o4=?bpqMtXDRah9 zqNCYU!i@|R-j!PQtlMn@vJf4+uE7y}ZG3U?a?hh>rIJ<$X{MS#`E@n97jIz+n;v_E zb8b@>ZW?IULE@U5*fGv6Y{(r`qudEld~;gxDOHdqs#T0jYF`@fh*%>8p(rY~+NG-p znf6aKEJ(_GNTzBG$vWTAJND%L&f7!L>V6#4rRbOQCnxa znz{_1+nvQqwyi$Akk8UIrE&4AhVNfJ|33)sY7>r-rD+5gy-SNT9Sm;I!#&T#o4n8I ziG6z*L%w+A_ZxnY!|X$Rtx$OJ-$mTo=O~YxC0CCvgx;8`kMkLuk9;2ozm&1H zUJn=Fl4{uebajhSgq%nY6NAuBe-kIkX3R zcNvyvnce=%oh()DUuWqOm*8&b^}|AISftC2u{014=vA_`Q+|vxg*;Z?JIw`%F_9T# z2xYs1uiz(TX#6G;wJOBvCqGGQ*f0w*ZsBi-{w+=3hg%7GAZ+!AM? zvKwP-h5t8Bp)_K}9r(!*k{g4$%pbfhWtqlfkU5mrlTl7~%}tQylbDif>%m-8HMir-D;@D*NUQAWMH=j)r!mvxi_Wc|3{2w%5jK-ihq~<51673d)4Cu2$ ztmeZCFYFjNw*)d81a_!33~;WGQuGmb=RF6$e#xJuJNRbWS1EsW+N;H+>Yz*_#GpNK zqkM&(PcL=llWMA8?LseVb}6a&P$O>UN?Ab9qV@jkovxYbIQhn1+PMOW8&&sRMrtVR zxvXvR$H?Oj)Vlsqh=*4{%@wZK2%U;lGhayaikyLqtexuj!&v~B%HbrA~09MoIQiremgfq zH&0-^W?ry1nd?-#&@UENF5~(R-S({1SpKI%x}mtqXBDs^+MLin&lEhIuQX;wZjG6# z=p^LYZ&RKP=OERZ{V=-2V51od*Yd6ZuQAy^QPdSBqQ5_63+l#37ytsB_$^XvhGVE5 zoU`+`xQvPJid&~CyPX{1ZvnWJ>vGhq3JPow!jZXi|Cuxe)sK z6|0ILfPPe#FvG(Gv7dImJU->Vv164Glv+w+d1q$uTdHFvet(8eEIdt`HM>8#Q#=CQ zRIs`~-`0nezU6DLZepLemrh4cq3}o#1=WNU|6umUzIC6RoNm(lSHBe}yXlODCE6^R zv33dlZj%2bp}{EV)|aDTI!9BW=?Q#FVUnzkY7>}36__WOMq%6T{~nG=i^iGJHcR&K zb>}@@dyLWYyxAuL!B;njqzKvhsLe>@3Q&UyL`-`H~2)HAiW_j((ts&B9-;Jx#LYJk!me8Y7@ZZ7Q|E@_AZ)JMC%)hm(+HWvfRqJEeE%tlL z3fPti7Zqx|T;o8QMD~i{`W81fKLI~sJd=6cEZ-O)j~MEiN!St>peI_5q2#bx+EZM% zdjB?yk(VAHa(tMCw9eR9WB(j!^A!I=S7UF>5N=5l`@zu_wmZgkF-#Jyu=+t7tl%by zx`oWp<{zT;#5iG&9Jvi{;DIo^&F#gr58k3Wna$X`C?V>|dWh^F#m!WhS#D+Hfq>*} zBL1$um4y>t2-}17#>j;H{ZzR7TvM#!27O1DYejDyWTfwxaZ z7!4Llo-MSxD*IF1HwERo5mXc-$O{cY|M+gaLrOHj54CY@CnO8v=!! zB7mUtAPX%iQxo7gI4nvRpyclHwhImpc~MwtJq1UjU3^+iy2jKR)#Qdvm!nxQI$~sJ zKXo=1+oo3hFB=q{U}t|$)j`33F^Tq**cFnKPvv$oDsO1eJh>{pq-G-VbGB@b^-7$A z&FmJT`G}vp!xAI$$Kt~B zXd)LThV3c~;}-lT@FQoDxuCkD?51xB&o z-2gW|whN-Bh6t6yx5p&GsyJ%Cr zduL-OU9)cPOSq+;4y-?0)E(<84Nr#oy@Qx~m1^GQ>QZCfD#ZJwJAdQeFAKv?vDO3B z;{v7>s}CwnVVW;%uW}UG)6ulZ-prf^-p3utJ}$2nN-A=-TRdUZm0m=e?@YkZi%z2f zfok(<^0Six6G*|PXhKDheC$RUyA+g837yoNT2e4Ipa21xd^|p?kyEKwRggTg$anUN z>N^e|Qz!6!zTh~Ps!yE^lx`9<+%HT_RhCrAvN5>51@%kgF53-yb4zsZj7arRJdM1p z$_(NC{y*$IrLY3m6n~QmA8^P7v6~7K0hHBi5}SzHN{i-=oID6(o5`<8o5}9^-b4O? z4lT&4*pR3BKPJ4)(Y|w~3rPc)#U(DKE|Yk0r0Q!;P~ZRu~LbkCmw=ChK_ek<&0$j~o|5 zxiZ4%k%zq>Scl=y11TUXrDyYoYh#L1BJEJd#9-eO!btDK(;DZEIaa7t7*%!vHXP8D z&|a2o=sxXEq80ece(~)Kj7TQEbqC6?6bXaU5?}xNrM`e;qLLnVQEt%DHgEsX_-5=b zS~+}?%yoq6duXd;+q_MaYE9@mr&4{kYFFig{|?6)5gg)0<1zf8uoQc+_Z+eQ*uR4+pvyawo)sNtyQWS3ttJ+ z5^i4+wmJoYEBBycjN_;#WiN~&Gbqrcgd56|#MLRyZ1?1@%mLYarp5=j3Mwf}-xICl zb2*aAery|wQ^d-YFt*IyP6@A+R)Rm({>Gv*wSrW(g#Tg8P2Xp(tAuMEGq!-nGX z^ma33dJvnJ$|Rnul$k$&Zf&mk6;H9ee|TR$c18Ivb%^ySh@m2MUC&c5giQY8PcYI{ zP(~7I%q!^>QE-RJ(?miIa>a)|5~c6eKS^d8;~Fah5cle9=!M{l&-> zxxGUj#&oG|w|3r(V)$niNt~Nw$ibCQldk)X0T|F=IWzE1&KodGS3?3al^& z1qg_ao?RkdLFIo+E0_|s$%Yyyetn85j`N(B*O+$so+=jw(VP4>cK>vocc(zR0>Sf| z>1XZG{T4byneE3@?xCKjPdJpN(#1DPUIwqjAlvKx=6rba`8@5N`2#=EG@7Q{tDJch z5B%#E5Km$TaNU6tf4K*ARKu7CT3kqHc}6`t5=rr-@fIZlpge0Qe6|Qcj`V^1P;pZM zKEJhi0<86o{mka0UVl3Cd-r+f6!ireVV?0?9kPxwkIlU>-2!8Xbe$zfHia2@0@AYC zcq{t1hLP8t;<$fa^CM9XsPcv)M}-%xVXW9k^%?c=w3q9*oGDvm6ZZair0(mGlnGLQ z*5v{7cM=`AM{5oIfMF8_0q9pXzitgV9hSc&K1JGyh`g5}SXwP*ce2@tA{G@aGy}s8 z9dg@c9%zE+eZM|q1WB^-Y76v75U3tjbiJJBFj%$ZPY-v$L-9UWLrJDz@)W3d;2CrW z(El7|p_+!bEqaKE@2sFBT%}dI!^WQo?*^;N$ZpZH)auT7hF0^(npmRonOc5bRklaE-}JA9$ae#wVzcL)9yc}7JI(T8`-amb5I zrWApkvH;>1_nuAKkDf(IX9=QQFE>F9KezkMYem8zTz^A9U(gKz>!_4$JYCc{iRFK$ zAG65_;Gg!&uAaeaFyJ;UolJMe@HMoeSFdQEyave2QJz0~RIkt4_Vz2%Cgc6v=P;OL%RPwXNNxvc>fW zbdq^~%I4ReK+r5B(_bbZcLEKKW2dYixq*oKv+8rxzH7fTwE{_Bn$N5!J8|=%w8HT{ z#?b}V1aEi8N{i(SVD}jAZHlwA{CY)(XB=4t_2Fp-!mRcNI4wm|9D<`<;`652FkT}K zLcDq+{y}dfVuNzL%zjjrYlTTZx<=9pp`Sgb>nxwKvc8(WohyRipQEMgn6Pq0iOtC^ z!X7;n&t>LQb!UE?eD|2OV`(@O*Js-qd}(7CXodqIL`Rv5ZSt+L0`c`H(luhVLjmHF zeNS=WK3s)rU>&QY$$Rxh!-d0_fAoz)8iV0^LKrR`41SNPS_Rx;h-cCQOiae@;CQh4 zrGg%>9X3u%TGl2B;8ZEIn(dwAhg>#Xp#kdE=|v5#eN;6AhEe4zM^=v^QyXqkkN0QW zWvn_v7wM0HnKyrlcc7{9A`(5rw(CoVy9My$5lcYTohfe>-^GU%cL|7b zHaGW9CTBXUkaqFxQxTL2TF6CtEDP&ST~LZIndDL0xZ9D1@|~l#-H-)lYE-jHMe;eI zN&?+^?o^Gt;?>@c7D^;~#7tYswu5e^u3IlYz_LqnTh`{WCjni)i~>@GaApQs6z*ez zjLoy?k~Kq7WU6YM@pTJG{Z7~qwNycs@90g`u< z|L7+1w|7eZT!FBfZ4!Y4(gxA#8iT=2=C9m})(ycx4!M-tJY!rNlWSIE1FYZ8)cO@A zsWGYGo&aEFh)JTU)vs?%Rn-d{5&dI-)o z6oUhfC%)H}4u(Fa^r357mw>#4Jm0sXskTWHUwe|*Mk9d^xgzz{V#R5*rw222v#2%u z3Uj+nMFQ>btxhybyITnBN@^$j_ptL}!p(};54gWJYH14-@jnbUIwBWC5k?|6y)}Jf zU{(CC4y*Ktr(L-$4`EMlq#qHgmuw^AE-!eETXeC}@K6wqiA@2}->^Qeliokf@Fba= zY7I0-I-1~EV-!I3eMtV-!ocdjxS3FYP=F`*T~QDbPwtym)>F~x z%p7`j+neVAGJ~jP`ENiO5cCd&L1d#8;sfN((XrAV6d|~g#1D4}e%UCB{YT*Xy24Ca zFR}yM#2jFu>}Jm07Vkd+hg62RJyw5+NB%x#tD_1UO4qL)&$}*RY1O=+e3+d@!$VJ< zZ*2ie#`TLoj;_a~3D(Zgj;s>4@u<)2MRGl&8ZbklJK>+~R>?v<;rq6sm*>`JOFX-RWK$^e2N0-Q72*U6ViRKhL4vksy?I zafK4j=*68z4meRwR3eNRl23N}3A(si?TLV$l{oAYC(_U4Q&bo*63$}C`GK?n&@V60 zydpO+NAhj^-6EwlBGv1JSd)IyTi02OV)dm*{d$P;b{TLk?)kVuLUs(Mv?C=h)(#f7 z8c`Ee23yr5EdyR*{FfXduHF#iBF6bE5H<)I3?*>9*5SV>5;B9SYF9H+b29F}BK;YK zbEeVIW+L;q%tLh)v$Q_P0+@9*Z742;-#2k|@lPi$2zct^Y1=6R>n8tr3$wJJcM=g3 z_27H*gf)3DRyW!saa>A?qysuWrMnzX7$H}XQYcvvZ_C@@AjJOgYRy)SrH-6OHU*pl zX6gc;5jdoYyvk>R^_vXwtg3(gyaC_lOLmC2Qb!r!w+5V?oDhGRHc zB!GQF5Bbju17yGyfmvC$?L7AlkhXjjo2Ww!%(-`VfdE-;EDl?^&-U+Wc&upR2M1P? z&ff-bC0A}7hYsvZIOs)<05v|!TYA+Pk9(t}IT1#9UA)=_qbLDVqZy4RMkzO4z`Nbq z3QvhhyRTQHUC8zNAK`g718lqTkICU_q^XRt(9e<~W%8>@dsdOR3ZfoNW2-k4V{!DGems@Y``)fOT z2rTR;vObr(?qwlW53NJmmN9_1-~#`V=fOA+79 zGGmp&+B&){;wdSnI-msFcwAV8-6>*zNB#$@LKM-kcx@>>TgbqB>?_8~lmK)jp`_g( z_Xr3srUO+@R4kE%{bdHlW63aiRf+HWK7#onZ{PVu%VyO8BSaum((rt$L=YlE`CqTi zMj=vRW)8!DxaD9_L_Pgt#Po_DsS;@v!e0{nV+7xtq#H9rZb`dof*UhXlgI-_5wm4| zUAjNd-mKYhFZs@p!48qk#C%^5a*|Lu@fcD4$OnO@y%yhtbTi1NqTg&ue1+V+#C}qT zFa?~7BdPqC6$-@5i3kv8c>>x-1GvFp^3<8{o*}OrEie7}^n9PlMHHqWd>n5SQglQf za7A3MWAuPh;s<;m&Yw9!#s(6C)O$3?W6UMIlmSe>Q;${3YIg|MZX0$&4nVPb6_9dqg zV2CJbwZql<3v)q<4Az;ApXTsZBhUifI<6(K#uf#&l}g!x@Vt6<3I3V^clf&aqMZ!z zDb)rMMBAZ{(*Z7Ot3puiQ1)^3kAyw}>Tsc_^~MEuwW4WpeKnd?XV4Ag(~h*eZC#Qj`s0I#1G%5)x3q+U*hnKE}($c=}>#gch``8|3*mozFN~N%q0{0 z4PsZWG>P*D>ofP8R4=|qDG(p{$7ZKXJy{V>9ca31#Aq@-KPB4!C7&-4qmuLfZ&}Ip zp~0*FfhzDl6WCGB`*$Ua?bHkpxB}YET3yN4O_N3PyTTkg zsxRw06N`Pe0qAFz_8tV#9lHl8AbWk?+;Fk9{`oZqgo@#3iijp8AuqcP zqRc)0+S}uIMOQUlBlSscK^`_g7E*^CHMK+;^>X7k=0_X67cM`xgbvFfKOI~> zNaY2oN=>p#Lz;afb67m@=t}A?;&Lk)j8HN46S5sPsxL?*R#W2^QAVO- zyuN=z1hoR14lkM?r9!>vg}>{VEj4GtQKMDz6O9r}0aX{a|Cm^IthMzNq$3Rfg`$)S zanG;3@0vJ29=I}ZnFh@B&WmkboJ=jZ=pxM@qhm=}!LY02N1VWuS_#1)Ms8?qQliE_ z+W1>UVNYAl__mgux*RE)4aXtA-pW`e|(l8_qDa z%*+}#D$rIJ9PjKHcROO9YJGxgDxDfH#oTUkVS9kSH_UjJboc5?{O-l!DLD!ooZBKU zl0+oEZ3->ng2G{DsB3NLH}rcgZCf-KbPdE0G$yxw+TR{5D5_(EIU(=hTEf(5;s)hV zr!8uAbCtyl2~2~$bs~AEqdy5q0xz$6;xIGugo1{HP?fEd>o;%E%w_U$al(WRro;z^ zTI>NNN?WRj@TTxoYRXc23US;Az2xsu@)%eh-wq-=9=O6EuD^ro>9CEu3SmYiJw{Es zq*I+O6kM9GblA$MxC%`G){gZ8=i-m!g57%a#l+e;3UR`^+*O2JCI%Ce1CJ?Jq^v%{ zVq*3Ai-?b;Nh|yq6P69)C{-|XB+!U7a;g9M>;kD1)`g(PN>|3N@R;rLTIYSlJ%~+pKx}vMC*A>|GeUCP>F_5&zp>xc&B=!)4GYcF zkISXlpTvcej|i^7FzQW#O)2%}f$l*kf=x*pNRHoC_dfDxFRR^{cuL|8apO7ZQi#1YY)p!lZ^UO zoe|vACP4Ec+2Q-gH5=W%TWA>2bC&+^0!iLaV`k_1^7QUs?cI8e{A)$S!{6yc5Yn;v z8fV#SLrKk3s-)M1xpnZa_}#+H*0*uNnYL-KtGV2YiH+n$a#2cttz`?kJR3Oh|yMkuH5q5m)M=IzafDO zO{8IMndIfVn18H?$-wn&gu6f@Rqpf@p?@b)#Ho3mX)+D#N8n7bgMpfI(diukYqOIx z?u*jSrN1&@!%Ci-CQQHVxlCLgaDSWQmEWU7`5VtA3&PP!X5{T_6V7Q!zG*C*yIj05H~2MRt7+-~gG&TL#TmYV61IWt~bd zDZ;wz2&A-&iPnT-2&q?=E4A1kBouTO)JyuC9Y8*_;29-H8|L~zfE)2H&MW6?I2;zmk7J1{F`lLMmQv3@>vcuo{N0p!79B}+fbuD-W$|+@ zA3SEV1)U#fKR})7ZGEfOQNFEu|9ahr5qKSE$Vje-tCj3`d$$t;uTg*Jt)hshLCF?g zT@woydL17)vUxiV__u!lkHFx+;;{e1FaJ}QvDLbZ&TjAhr7|E)4{5pQFyS;s`iGMN zkr?2cV3h+z<^f*?up?Dd3TTngYt;gbswTDHNs*QqKKbfpjUj2b^1=0xhQiR>;myx% zPmdDoo0G&xQ< z8lb$qL*ZDGP_@^yK7rVVdvw0|4is;m*K#+S?^gv2TTbw39`ey-d6Cj7OhZzkqBt3_ z^WmaMVGuY_f_7cyVvLpjK?`9hT14_GwyD81!PlTQr~a+ z6X>@oDQKUl4Mnm{(DIbCoGPQ^QUzpp=(U+ett${glKXrK;@ z9qYBYca8QVGieFOID3`+M<6^%{v`~86k1v2@YGA0=vK=`7eSY|?Isramvo#7s#=t6 z`F9;L)CVb_D~OhHze4@R#T0agrANsH+503F4CSWUdPNp4m&8;4zv(jk$=$e~(E8c{A078drENg3D{xxi6%#VNR#6SF<)wO@lY z6XjOvyFL-hTbYnli7WA|_k~ie@6#bPSM^F*1%$n56Cxe1D4woFSA#V~;0A()a%*9> zZ}}JTvbF3=c+eE&#G$HfjlRk&8;_A`YEe?+;T?39g6fEs(Y785vs64uie6iFxNbT6 z`^!_$qv_ySyXJ}HtV7Ghnk(j#Htm};*^Z-BP^m3Y{IIGzAS#CCgo#qxq6<}vf$SKb zRIqFvcZEFjnK5E_(_LHo0tT{6W1fdz``YfJk4)b zA`SSLu`%RC2ir1V&LvSloUQ8Qk1`&2}iq8 z9xViJ{-m;#2>fi;zxd}s@5=ouJG%>YEo99Vm+$ymX#l3y6WnKqf?q>4-xmX= z#73B|6>Sl6L*E78_$93)nk7aQzCyn-c>(!sVH}QEQDC%9!+_Yf%oO6MjYe-n4LmJp zBZ}O+p@CkItCga=1$4C@=kn`nSwIvzt!5RMWQ@tjE z&_S9SN`lHGHtX(|M&uy)tDat3ixUXn!37e&;$!DaJ{wF>1+2DV{IWjpH)pHa&(HRk~ip-0Rw9{pwNaohh}7x2I4FxckvMCN>nnfCyUl&@;NS3!-Z zSyvD-`Fr{?1I1Rv%U8AGVxhB$Lh>u(>Zkpc~|JdU%4e zN8)GzmV`;OV&D;}R7K=bCQs*>J*dHx`gedkSawNj=VH2QIU4pb;2yw)fizXlSPw3m zK=PqH#9ikzpXasw&w}BIM#w`PSWV(YZHD~feg!vecAI}t2UPpmQY;Lg7M!{?zzV5< z0m*?v-M1!RSV%vQW5x}9NuIwcY)@$$muMU7xGPMqliJtG9Sm>`(m1lgkJloy27cvU z$a;uj`J{|h2C)qB;Zx3{SN(azMM1inZH(9+pYQ_EwWFhKO?3>KqMJ+y$DzkBUN zCs6@us*1f?wD;V9=Whw|qZ6JnX#v(28x4{Jv~BQUY+IlWA0cYN)35rVjDnK?#ST_S zsvzMb5dT6LP>E4XH(>e;wznQI=PbD@c1reklyUu6?FnKxB>I2a3`<*FN|f27Vf_S- zjQ@oi2lxUPUo%CRY2i=Tr&EfbhY9urdeO;!(sG^JIX2L zDZ3Qsd0$Yg@^PkQV*V5Dw3k@zqqd}7TX)@C%&0xEb<4<4j4%^N+$`+K@`S<9@=c>F ztL~moaCQ`?HMSw7wh9jukA7G=6>@a;J9HwLA?CwRXbAu*6lX&ZCtr7CwhvQm@aD_6!{#ZsO^uJ#*F08>X&>enMM323x_ z&Wj$&uLtolPL4ck7@7B)6d05%H?}oa@^W1Vhu17R4tnr^HN|7W6V@*TrPgG46xk8A zj94Utfsc7^&70Xrvk3dxEZgcegy~T15t!u!`o{`Nk>|q?$X%Ncu$)FKU(vnaod z^)a$6q<-uHcry(bf%zP&h-hhj_nc?c0v@bj5BtmRg_~uBW#H#@C@TMRMm@uq=220R zJyZgkt6tYSDQzp%{gqo!tVqR}-Ti5%^;u~S>_W3Dx7e}oCW^#phC>DQJua%>HtQW; zR!%+Vo*;7=IP}KBp<_NAOcO&DJ2MS`zEs^!#L|9Yio}J!IAoOCUI)F94AwB*53-=* zEx-f1PgsaHnXr26(>lt--vD2MaVd9DyQr1`hvwdJiaFM=6)hd>A&~Pxyn5O5hZfV| z4#Z?(i84Tc=nR@P3ppz37a>X$TSO(M$*yF;2^7o$SwsQ;#7H4Ip<0&!Uktf-Reye= z?nEl7qHu0$?vIjq_J9g_F2?^L@6A;NQe9HA{nSAcStau~;G7@DNh zy!dmzbHjZ2aK>7ec$s0YtREtsCsCs{kk?FxvU6_bFcMnt!1#W^_f@f}IPtDHOg;Mh z-6dE@%?dBPm1yZEX%F~egzsGbJRG}Pc5lf$|0U;kO&NEWkZf8o9Nmz+^kd661I-GV zsY0xc0RNSUT7|FgshBY7i+e6RoH*GKR%Yo#A0UmHX0@MU)Mu0sezj6pg z2p2SwN#7Ut;Fe)b3*F0uW2c)2Txt0h4gvE;;W`R=kVvi@T_Fj2jS`!^8?rfHJPYf~ zBRUhqK40(td=O^hxb=PAeGZS{G`yVj9#s1sny;|iMjh<{5G9^HpIlgDr0FO8cijw} z2xNwA8bCeZ7qlM>Mpa3f#nEdy8Cht30btHA4(^;VJ{E4|xO_h_ynY*wZX@VIKC&Di z%(0W%N~b)hi>L6mE;AkL0BGxGJK%~fchqP*5KJOG+FTFJQ-6W*WVS{^1F#ID7 zs+{l{t{=%1O|A`8cgyxRNl|P}%XgwpKG&@mu|A0I4@17gf(x@1<}dtqSrvAot`=4C zxf^d2bG3SxL#b?TJ=LF4$ZCp|C7(TgGGi}tp|YVqMyAF!s=Lz3#m{w72IKuWSFiH| zIH-s!xM$$^Pg)V%%?m}J2|4y}3Sh(&NnM=5!_Q@y+Z3Cr#1x!?{j2jfS z({PEKit2<^`R87)w*7rkjI((jVzTPh#&k-p;QDpfUh{fh-G2%M`dvUlG`j&gohpXY zl#6hzlm!r7CLvW;>52s+{a+CV(A}TMXXr|SwMnJ2e|BL&iv-^3Z{~l1Q!lO^J^{ax z$7$wHJL5EewDNDhiifI@wc`nbz7en*|*WcWFjzR2v&{eIG{BLo|iPO z!<84bWRjK@aYtk=J+S!1I%Jk5zLr4IwP*5Yy^b_!DQLl92MI+)%2y=dfi;tFwNfu} z=p#w-_lZ1jnzT-heL-$evqmy8M3VnI8I-?WA=wG08%4e#nM?{$I9CXGFY84HaCNkxvV0Q;b{Qxe5hX*{4V>F ziRVBN^glKIldOADAeM=^Aelg07w; zq!*a0j#~l!M1dl9BS;zv?ng|xVZ;&e$SiX;IP)$VO#^pT=pTr0!8Aay+1Ng=NRcpY zQeEZgm~uIW>|Ixev3L=9)LIkJ?`ua*zG3H zWZoti;9vE9ygSanW&M`p0{SWnBkngFX2+#(pW1|wI(1g~JT1thGlez7{JN+TiHw&b zo!APw8c3$AlIfg+_#GmF=ZU(LPo ze>2a1|G`7_n^B@D%tt%1{2`%A@?k_}vdtYTXmW(={W_s_7?KjjHZbvR`k#oyw`N2c zTN01S`^*BP-SnXBcK{h+6C)=*1wsvyDsD%Zh?7FGRD~O}_ zrFxbfTM3mc$=kW~dT8)eY9vvD{wA7?x=gyRiKV_Blxq)Sn2nJK5&u!>h7PjK&WZTl ze6)9&{5-yKNBbm+K#k`}e<1Y@Z9%{Dg-N@@>&rEB<5`V=EePaH^=z(;FOkl~p#{9m z)e(8*QcM}_CK2&pDirGp3sLMPJnE2vB#h*h5_L8=1DB(^nE)dS;Eg3g8QvWhnN(2i z_D$k3(Ci)RQi{B-4?Obo24M8$VY-;=f?b0~~d9OMkVHN6O`lvSb=LvG|G{NAD&# zZ^$C-W?G~ngnv0r&`rbD|DU*fDS)E@a#x$&CVE!$dx}I7zN`R{)~4>96`k$SOg-M; z(%#Jk9I7w%A<{+4kmr!<8Y=bWP;UErWDRi}(%F1ia^r`eG`%f~<*t!8a z{&RGUX7~1i{`~xvQdi*;KR!TH#=KN{`?oi}SYdeeZrUkNW6e%ZK0^E8bPOlzhHdud|08h{{b{z>} z9dI7tsmVk(-rfb52PBn<(031A?NGwR$=ZXGZSPq6);8+W+8@yX|MX=&g?G@;gCmje z;Di6uRs!IrKjepA1b$D{(EG@r63vVM&a;eIkHegR1PdS*j#`f|o&6&*MI$`mg%u=I z-~JK$toM-r!TC3U4-_DA5fMcLDSu2}vMX7|1ws2qgU;y@zq%1c(>hWstw)~kF96f7Z1|zl^w$&_ z&hq?gf0f*Og){&Fz4Ui4z}mB~m~R)oEJdj&^N&|svC*JemvVk@bLoX2GvGDL+_t~H zW>B_bTa!vdURBUEg^ZW8*zGR-Yxh=#?ol$}YOMCVkE>ruSxCh~^+a25>J=S1JFStBB1_}N#+Z49Zw%wpMCvGW!6G1+IvqxFYc?k1_ z>79S`K)@KPX1q4eJG#d6*T@^OTtgq<6-XqtlMiCyduE=dt*SPY>@@vz4|^~pfqH-+ zNaO;(!X`Lq0JAgXhErD)?qDk-w^>7X#--o66pd>4NhP%3QG`V+CaDQNah}J@y9uKS z;ZSm;iC>7o{~pu)j}3fvCT5FglM(NBJ|{=+X9r^^Nph$8DlX)$rs^5gk{>8Cb(M%wief#ZLkEpNn9e%L&d zkK8@g%ULU(?~p%YipmA&-%0bMVuA4|0v!{93`Kk{8`3IWFzJphp)EryeP{Kb1({*m zCWl1?l_KF1e9X0+M1=q>1J96d_q7UEzRdgOLmE{J8x8t*vgHBt2%tqr>>uN#sE`gY zZI@lNfg8QHJY{&1u)y?}09SROtLF>2I!L7fRlGLgO>o?90TIHEEJ1+?LJT(~kOh(;P(T(%7C}ltik8I^s2Y$> zk!WR6sIvHq8wi3__E!X1R1gc=n}EFby?Wm1A3g8%oclQ^lgZrgd}rp)B=^oezih2Y zcp0LauXF!hq7j0n92ZiO-nhrlNmBi_nB{?YiApbh(oT&O32}#Ni#R=V0fr=NfAb4s z_G2Od|G^#Gv07=ylHRd?(8KRg_x!1mTr--} z5W(cKuEx!czT`{xrWdoahk{$R6-v>B_L!pHo%iGl2d}hhoEcz{CYsCLQ&LztxDVRm z$MrKy!*a|`B`U9Z3IfC#Is-hJVk8@Lp7+qh*HjY$?QfdSR!*JnKl&;~n|tVKLU!6C z_r61Y(NBv8uA488as+Wp@x}YTL{GcNNjZQAugrB2XWxzfGKLrv;bkvr4uy7=?@>4% z{5`0Z*zUa&bN;qrc~E$YS{30UQeC_wTCurO_lLqhMEVm;gjblV`+CQmF#{9JhV|#m z8f`F~dGtRXBPwDZzg~wRGKBL6y3SuuIyU6d?=8|*e!IrU$|>N0va}8mV7I%2Zfa0%>0yFpiFpr`7xa_7TadE zsOiblqU6c0av`Ng2cG7+8zB;hXATc* zlf#;e7A?ZHQ)GrYF=}eqV>%BT%zN9qz^7VwKYN1NZNs(cNSDk7eC7F)7r!iTx?OtX zmyVW*;~($G?0SZ0r*p20x$hv>XC2eu>&p!G&s@}dk+B?pdAnw?8`zsq$2BT%?9WQc zH_+Y{R%BlGb8!SC_WCVVW_yw3hqp54Ucbv)c$W0pcU1Z#*Owu_HPdf3=eugt4CJ4j zuT(_jamO!I=62vXbh2LNff!yastq`2BDwTWc=p-qt)@aRhGu#OI?j z$DRGF6m*E&ZCe-hT!&_qP&n;$JT85w92R*`BBm#2tKzE`5qcD7(*$l*J0!_PoaZat z#My(#CR;u~y*+TF4Yg#n2O}uL>3e&Hnd%FT0XEqDD=3U+)uiMK1ptXek^L;F!rirT3dK?w(h)&GnpA0 zbu$5>O`of^Zb^AKS@v^t`9NmcXqvdw_B&kjb-bH_PKOU~i#juwyf1Aj>J?|Y;w(W8 zbxtu}dTaW^X2CH|5iXC;@wE^ayDn7P-U*I zwQL^y#GRNWnUpP!2`(_!81T1XR6S0p>x#1dw*146lHFIHed~Bi87GS$Ij{jUYFUJO zp;JwJp4<8!kjMyWr$iJ7TpIi_yd}<{peK)dB5^YT$Sfy?Y z|KXwZX2jKjnfoorlZgS+6{!~}w@=`(8d`D<0VX+4q^sog*n)Mlx!c>UesvT z{N$0+WD05L*fe)yL-tMUn?^ARQ#-bw-c@SSwMX1;&h*Z6eM5Co&l!tbFCwcP zO_uKOPI+3OI5bfig7$N_JKL)oE1pPUFR2P!4hBs*6+O(=V0%9De`KKfr5v@%;U-7z ztZY_#N`rSE(JikBU6S0Wg*xUZR5{IyI(5-?8&?s!kf;Q=`#QzFjXpW7)P6s2lHFNK zs=rp;H*sr5<#7eEI`Au{)KU|ZZ&WSYnq2ej4@N2P=QaAid{$TUMKkC7e#eIPg<0=1 zX|IQOBNd@uTu>|9Q=l7HV=$42tjnA?J%(1Cj9t3w{ME>U3Rh??3YTH@U?^&x=+G-o zu%q^BhI^uk`RGeM+$qa#F+^z)^8qo3R^m=RhAbFPAfK9T2|xxu;;=y8&@m%P;u+v`D=%&Gdti&IA5b}rZ^`jGhHF1NsEUAa!0flF*cXt9_}f7YX9lA936j8M z{zYw|_0Z^DXfy&1VZ3YC@7^KwjEoHsXk%l2=%r_@X9(#H(7TKg0QxWL&+iClvhWN5 zKm>ynCY|eKM?t8ZNv4u1&^cn! z0c$!nG@J!802g{7$e;l(coxYFAW*4fKpQ27bg}ZZ2Oy#a2D(H%R58j7Q2y^0ly?G5 zkU=Ky24YvMIsCb50wt3bMFGtKG7C>36ZlU1T%BzMZhzV;0wf2KSZ2TxIwcTt5`)eQ znHov~sZd3zkVOKBth;FmD@!^gTEUu zKp-~*A|rK~R6K+lET^IoKhctvu{7zxnLFR`6RJXaNL)D>eerAFCpDS9L2Y`vadaV*K0ak2H}V zeO4xd1mXk9v>-q*-GWnXueaJ^d;O0YgO3@*j~S!Y4BvtZEmROn$OPtZY-}73A_K|H zPzpYZFW~EAMOW3p>H&e!(*_BK(deRU3NS1jGNaRUY2nl(&~OMKg(6T2S_`BT!ubnF zml+BY$V6yuuC_^_Q$c_RMzZ+Q|MyoP1_lNO1_lNO1_lNO1_lNO1_lNO1_lNO1_lNO X1_lNO1_lNO=5NfebN?Ug000UAk`vB( literal 0 HcmV?d00001 diff --git a/doc/fusd.pdf b/doc/fusd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..32b21bf70eefdff16ac1f4c11c8ac917ad702208 GIT binary patch literal 186129 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%0AjY9! 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 7604 y(#include)g()2524 8932 +y(#include)g()2524 10261 y(#include)g("fusd.h")365 +11589 y Fi(5)2524 12917 y Fo(#define)g(GREETING)h("Hello,)f(world!\\n") +2524 15574 y(int)f(do_open_or_close\(struct)669 b(fusd_file_info)d +(*file\))2524 16902 y({)-133 18231 y Fi(10)2989 b Fo(return)665 +b(0;)g(/*)f(attempts)i(to)e(open)h(and)g(close)g(this)g(file)g(always)g +(succeed)g(*/)2524 19559 y(})2524 22216 y(int)f(do_read\(struct)j +(fusd_file_info)g(*file,)e(char)g(*user_buffer,)10494 +23544 y(size_t)g(user_length,)h(loff_t)f(*offset\))-133 +24873 y Fi(15)1661 b Fo({)3852 26201 y(int)665 b(retval)g(=)f(0;)3852 +28858 y(/*)g(The)h(first)g(read)g(to)g(the)f(device)i(returns)f(a)f +(greeting.)1330 b(The)665 b(second)g(read)4516 30186 +y(*)f(returns)i(EOF.)f(*/)-133 31514 y Fi(20)2989 b Fo(if)664 +b(\(*offset)i(==)f(0\))f({)5180 32843 y(if)h(\(user_length)h(<)e +(strlen\(GREETING\)\))6509 34171 y(retval)h(=)f(-EINVAL;)1330 +b(/*)665 b(the)f(user)h(must)g(supply)g(a)g(big)f(enough)i(buffer!)f +(*/)5180 35499 y(else)g({)6509 36828 y(memcpy\(user_buffer,)i +(GREETING,)f(strlen\(GREETING\)\);)h(/*)e(greet)g(user)g(*/)-133 +38156 y Fi(25)5646 b Fo(retval)665 b(=)f(strlen\(GREETING\);)j(/*)e +(retval)g(=)g(number)g(of)f(bytes)h(returned)h(*/)6509 +39484 y(*offset)f(+=)g(retval;)g(/*)g(advance)g(user's)g(file)g +(pointer)g(*/)5180 40813 y(})3852 42141 y(})-133 44798 +y Fi(30)2989 b Fo(return)665 b(retval;)2524 46126 y(})2524 +48783 y(int)f(main\(int)i(argc,)f(char)g(*argv[]\))2524 +50111 y({)-133 51440 y Fi(35)2989 b Fo(struct)665 b +(fusd_file_operations)j(fops)d(=)f({)5180 52768 y(open:)h +(do_open_or_close,)5180 54096 y(read:)g(do_read,)5180 +55425 y(close:)h(do_open_or_close)h(};)-133 58081 y Fi(40)2989 +b Fo(if)664 b(\(fusd_register\("/dev/hello-world",)671 +b(0666,)665 b(NULL,)g(&fops\))g(<)f(0\))5180 59410 y(perror\("Unable)j +(to)d(register)i(device"\);)3852 60738 y(else)f({)5180 +62066 y(printf\("/dev/hello-world)k(should)c(now)g(exist)g(-)f(calling) +h(fusd_run...\\n"\);)5180 63395 y(fusd_run\(\);)-133 +64723 y Fi(45)2989 b Fo(})3852 66051 y(return)665 b(0;)2524 +67380 y(})p 863 68874 V 25681 74071 a Fn(2)p eop +%%Page: 3 6 +3 5 bop 863 2974 a Fn(unusual)256 b(is)e(happening;)265 +b(it)254 b(appears)h(from)g(their)f(point)h(of)g(vie)-28 +b(w)255 b(that)g(the)g(re)-17 b(gistered)255 b(de)-28 +b(vices)257 b(are)d(simply)h(being)h(implemented)863 +4302 y(by)278 b(the)f(FUSD)h(module.)2524 6295 y(Later)-44 +b(,)408 b(when)383 b(k)-11 b(ernel)383 b(mak)-11 b(es)383 +b(a)f(callback)j(due)e(to)f(a)g(system)g(call)g(\(e.g.)g(when)i(the)e +(character)i(de)-28 b(vice)384 b(\002le)e(is)g(opened)i(or)863 +7623 y(read\),)286 b(the)e(FUSD)g(k)-11 b(ernel)285 b(module')-61 +b(s)285 b(callback)g(blocks)g(the)f(calling)g(process,)i(marshals)e +(the)g(ar)-20 b(guments)285 b(of)e(the)h(callback)i(into)863 +8951 y(a)403 b(message)g(and)h(sends)f(it)e(to)i(user)-22 +b(-space.)720 b(Once)404 b(there,)434 b(the)403 b(library)g(half)f(of)g +(FUSD)i(unmarshals)f(it)f(and)h(calls)g(whate)-28 b(v)-17 +b(er)863 10280 y(user)-22 b(-space)290 b(callback)i(the)e(FUSD)g(dri) +-28 b(v)-17 b(er)290 b(passed)h(to)e(fusd)p 23790 10280 +333 45 v 399 w(re)-17 b(gister\(\).)379 b(When)291 b(that)e(user)-22 +b(-space)290 b(callback)i(returns)d(a)h(v)-28 b(alue,)294 +b(the)863 11608 y(process)255 b(happens)h(in)e(re)-28 +b(v)-17 b(erse:)333 b(the)254 b(return)g(v)-28 b(alue)256 +b(and)f(its)e(side-ef)-28 b(fects)254 b(are)g(marshaled)h(by)g(the)f +(library)g(and)h(sent)f(to)g(the)g(k)-11 b(ernel.)863 +12936 y(The)302 b(FUSD)f(k)-11 b(ernel)301 b(module)i(unmarshals)e +(this)e(message,)308 b(matches)301 b(it)f(up)h(with)f(a)h +(corresponding)i(outstanding)f(request,)307 b(and)863 +14265 y(completes)g(the)f(system)f(call.)428 b(The)306 +b(calling)h(process)e(is)g(completely)i(una)-17 b(w)-11 +b(are)308 b(of)d(this)g(trick)-11 b(ery;)319 b(it)305 +b(simply)g(enters)g(the)h(k)-11 b(ernel)863 15593 y(once,)279 +b(blocks,)e(unblocks,)i(and)f(returns)f(from)g(the)g(system)g +(call\227just)f(as)h(it)f(w)-11 b(ould)278 b(for)f(an)-17 +b(y)279 b(other)e(blocking)i(call.)2524 17586 y(One)312 +b(of)f(the)h(primary)g(design)g(goals)g(of)g(FUSD)g(is)f +Fk(stability)p Fn(.)446 b(It)310 b(should)j(not)f(be)g(possible)g(for)e +(a)i(FUSD)h(dri)-28 b(v)-17 b(er)312 b(to)f(corrupt)863 +18914 y(or)286 b(crash)g(the)g(k)-11 b(ernel,)289 b(either)d(due)h(to)e +(error)h(or)f(malice.)371 b(Of)285 b(course,)j(a)e(b)-22 +b(uggy)288 b(dri)-28 b(v)-17 b(er)287 b(itself)d(may)j(corrupt)f +(itself)f(\(e.g.,)i(due)g(to)f(a)863 20242 y(b)-22 b(uf)-28 +b(fer)292 b(o)-17 b(v)g(errun\).)387 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)297 b(strict)290 b(error)h(checking)j(is)c(implemented)k +(at)d(the)g(user)-22 b(-k)-11 b(ernel)292 b(boundary)i(which)f(should)f +(pre)-28 b(v)-17 b(ent)863 21571 y(dri)-28 b(v)-17 b(ers)290 +b(from)f(corrupting)h(the)g(k)-11 b(ernel)290 b(or)f(an)-17 +b(y)291 b(other)e(user)-22 b(-space)290 b(process\227including)i(the)e +(errant)f(dri)-28 b(v)-17 b(er')-61 b(s)289 b(o)-28 b(wn)291 +b(clients,)h(and)863 22899 y(other)278 b(FUSD)g(dri)-28 +b(v)-17 b(ers.)863 26732 y Fj(1.3)1329 b(What)332 b(FUSD)g +Fh(Isn')-49 b(t)863 29472 y Fn(FUSD)388 b(looks)g(similar)e(to)h +(certain)h(other)g(Linux)h(f)-11 b(acilities)386 b(that)h(are)h +(already)g(a)-22 b(v)-28 b(ailable.)676 b(It)386 b(also)i(skirts)d +(near)j(a)g(fe)-28 b(w)388 b(of)f(the)863 30800 y(k)-11 +b(ernel')-61 b(s)277 b(hot-b)-22 b(utton)279 b(political)e(issues.)342 +b(So,)278 b(to)f(a)-22 b(v)g(oid)278 b(confusion,)g(we)g(present)f(a)g +(list)f(of)h(things)g(that)g(FUSD)h(is)e Fk(not)p Fn(.)2524 +33900 y Fg(\017)554 b Fl(A)344 b(FUSD)i(dri)-11 b(v)g(er)346 +b(is)e(not)h(a)g(k)-11 b(er)-17 b(nel)347 b(module.)548 +b Fn(K)-28 b(ernel)346 b(modules)g(allo)-28 b(w\227well,)363 +b(modularity)345 b(of)g(k)-11 b(ernel)346 b(code.)548 +b(The)-17 b(y)3631 35228 y(let)325 b(you)j(insert)d(and)j(remo)-17 +b(v)g(e)328 b(k)-11 b(ernel)327 b(modules)h(dynamically)g(after)e(the)h +(k)-11 b(ernel)327 b(boots.)491 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)341 b(once)328 b(inserted,)339 b(the)3631 +36556 y(k)-11 b(ernel)338 b(modules)h(are)g(actually)g(part)f(of)f(the) +h(k)-11 b(ernel)339 b(proper)-61 b(.)527 b(The)-17 b(y)340 +b(run)e(in)g(the)g(k)-11 b(ernel')-61 b(s)338 b(address)g(space,)354 +b(with)338 b(all)g(the)3631 37885 y(same)351 b(pri)-28 +b(vile)-17 b(ges)352 b(and)g(restrictions)e(that)h(nati)-28 +b(v)-17 b(e)352 b(k)-11 b(ernel)352 b(code)g(does.)566 +b(A)350 b(FUSD)i(de)-28 b(vice)353 b(dri)-28 b(v)-17 +b(er)-44 b(,)370 b(in)350 b(contrast,)370 b(is)349 b(more)3631 +39213 y(similar)275 b(to)i(a)h(daemon\227a)h(program)f(that)g(runs)e +(as)h(a)h(user)-22 b(-space)277 b(process,)h(with)f(a)g(process)g(ID.) +2524 41427 y Fg(\017)554 b Fl(FUSD)301 b(is)f(not,)306 +b(and)c(doesn't)f(r)-20 b(eplace,)308 b(de)-17 b(vfs.)415 +b Fn(When)301 b(a)g(FUSD)g(dri)-28 b(v)-17 b(er)302 b(re)-17 +b(gisters)300 b(a)g(FUSD)i(de)-28 b(vice,)308 b(it)300 +b(automatically)3631 42755 y(creates)339 b(a)f(de)-28 +b(vice)341 b(\002le)e(in)f Fo(/dev)p Fn(.)528 b(Ho)-28 +b(we)g(v)-17 b(er)-44 b(,)356 b(FUSD)339 b(is)e(not)i(a)g(replacement)i +(for)d(de)-28 b(vfs\227quite)339 b(the)g(contrary)-72 +b(,)355 b(FUSD)3631 44084 y(creates)424 b(those)g(de)-28 +b(vice)425 b(\002les)f(by)g Fk(using)g Fn(de)-28 b(vfs.)783 +b(In)424 b(a)f(normal)i(Linux)f(system,)460 b(only)425 +b(k)-11 b(ernel)424 b(modules)h(proper)-22 b(\227not)3631 +45412 y(user)g(-space)277 b(programs\227can)j(re)-17 +b(gister)276 b(with)h(de)-28 b(vfs)278 b(\(see)f(abo)-17 +b(v)g(e\).)2524 47626 y Fg(\017)554 b Fl(FUSD)214 b(is)f(not)i(UDI.)e +Fn(UDI,)h(the)g(Uniform)g(Dri)-28 b(v)-17 b(er)215 b(Interf)-11 +b(ace)26987 47224 y Ff(1)27430 47626 y Fn(,)226 b(aims)214 +b(to)g(create)h(a)f(binary)h(API)f(for)f(dri)-28 b(v)-17 +b(ers)215 b(that)f(is)f(uniform)3631 48954 y(across)338 +b(operating)j(systems.)527 b(It')-61 b(s)338 b(true)g(that)h(FUSD)h +(could)g(concei)-28 b(v)g(ably)343 b(be)c(used)h(for)e(a)h(similar)f +(purpose)i(\(inasmuch)3631 50283 y(as)360 b(it)f(de\002nes)j(a)e +(system)g(call)g(messaging)i(structure\).)592 b(Ho)-28 +b(we)g(v)-17 b(er)-44 b(,)383 b(this)359 b(w)-11 b(as)361 +b(not)f(the)h(goal)g(of)f(FUSD)h(as)f(much)h(as)f(an)3631 +51611 y(accidental)287 b(side)f(ef)-28 b(fect.)369 b(W)-89 +b(e)286 b(do)g(not)g(adv)-22 b(ocate)288 b(publishing)f(dri)-28 +b(v)-17 b(ers)286 b(in)f(binary-only)j(form,)e(e)-28 +b(v)-17 b(en)288 b(though)g(FUSD)e(does)3631 52939 y(mak)-11 +b(e)278 b(this)e(possible)h(in)g(some)h(cases.)2524 55153 +y Fg(\017)554 b Fl(FUSD)306 b(is)f(not)i(an)f(attempt)g(to)g(tur)-17 +b(n)307 b(Linux)g(into)f(a)g(micr)-20 b(ok)-11 b(er)-17 +b(nel.)433 b Fn(W)-89 b(e)307 b(aren')-20 b(t)306 b(trying)g(to)g(port) +g(e)-17 b(xisting)307 b(dri)-28 b(v)-17 b(ers)306 b(into)3631 +56482 y(user)-22 b(-space)323 b(for)g(a)g(v)-28 b(ariety)324 +b(of)f(reasons)g(\(not)g(the)g(least)g(of)g(which)h(is)e +(performance\).)482 b(W)-89 b(e')-55 b(v)-17 b(e)324 +b(used)g(FUSD)g(as)f(a)g(tool)g(to)3631 57810 y(write)314 +b(ne)-28 b(w)316 b(dri)-28 b(v)-17 b(ers)315 b(that)g(are)g(much)h +(easier)f(from)g(user)-22 b(-space)316 b(than)f(the)-17 +b(y)316 b(w)-11 b(ould)316 b(be)g(in)e(the)i(k)-11 b(ernel;)334 +b(see)315 b(Section)i(2)e(for)3631 59138 y(use)277 b(cases.)863 +62971 y Fj(1.4)1329 b(Related)332 b(W)-100 b(ork)863 +65711 y Fn(FUSD)418 b(is)e(a)h(ne)-28 b(w)418 b(implementation,)453 +b(b)-22 b(ut)418 b(certainly)f(not)g(a)h(ne)-28 b(w)418 +b(idea\227the)g(theory)g(of)e(its)g(operation)i(is)e(the)h(same)h(as)e +(an)-17 b(y)863 67039 y(microk)-11 b(ernel)280 b(operating)g(system.) +346 b(A)279 b(microk)-11 b(ernel)279 b(\(roughly)h(speaking\))f(is)f +(one)h(that)g(implements)g(only)g(v)-17 b(ery)279 b(basic)g(resource)p +863 67987 20076 45 v 2070 68728 a Fe(1)2457 69041 y Fd(http://www)-58 +b(.projectudi.or)-16 b(g)25681 74071 y Fn(3)p eop +%%Page: 4 7 +4 6 bop 863 2974 a Fn(protection)283 b(and)f(message)g(passing)g(in)f +(the)h(k)-11 b(ernel.)356 b(Implementation)284 b(of)d(de)-28 +b(vice)283 b(dri)-28 b(v)-17 b(ers,)282 b(\002le)g(systems,)f(netw)-11 +b(ork)283 b(stacks,)f(and)863 4302 y(so)277 b(forth)g(are)g(rele)-17 +b(g)-6 b(ated)280 b(to)c(userspace.)345 b(P)-17 b(atrick)278 +b(Bridges)g(maintains)f(a)g(list)f(of)h(such)h(microk)-11 +b(ernel)278 b(operating)h(systems)47733 3900 y Ff(2)48175 +4302 y Fn(.)2524 6295 y(Also)243 b(related)i(is)e(the)i(idea)g(of)f(a)g +(user)-22 b(-space)245 b(\002lesystem,)251 b(which)245 +b(has)f(been)i(implemented)g(in)e(a)g(number)i(of)e(conte)-17 +b(xts.)334 b(Some)863 7623 y(e)-17 b(xamples)332 b(include)f(Klaus)f +(Schauser')-61 b(s)330 b(UFO)h(Project)22599 7221 y Ff(3)23372 +7623 y Fn(for)e(Solaris,)342 b(and)331 b(Jeremy)f(Fitzhardinge')-61 +b(s)331 b(\(no)f(longer)g(maintained\))863 8951 y(UserFS)4183 +8550 y Ff(4)5023 8951 y Fn(for)396 b(Linux)i(1.x.)702 +b(The)397 b(UFO)g(paper)19297 8550 y Ff(5)20138 8951 +y Fn(is)e(also)i(notable)h(because)h(it)c(has)i(a)g(good)h(surv)-17 +b(e)g(y)398 b(of)f(similar)e(projects)i(that)863 10280 +y(inte)-17 b(grate)278 b(user)-22 b(-space)278 b(code)h(with)e(system)g +(calls.)863 14076 y Fj(1.5)1329 b(Limitations)333 b(and)e(Futur)-24 +b(e)331 b(W)-100 b(ork)863 16815 y Fn(In)282 b(its)e(current)i(form,)g +(FUSD)h(is)e(useful)g(and)i(has)f(pro)-17 b(v)g(en)284 +b(to)e(be)g(quite)g(stable\227we)h(use)e(it)g(in)h(production)h +(systems.)357 b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)863 +18144 y(it)312 b(does)i(ha)-22 b(v)-17 b(e)315 b(some)e(limitations)g +(that)g(could)h(bene\002t)h(from)d(the)i(attention)g(of)f(de)-28 +b(v)-17 b(elopers.)453 b(Contrib)-22 b(utions)314 b(to)f(correct)h(an) +-17 b(y)314 b(of)863 19472 y(these)h(de\002ciencies)i(are)d(welcomed!) +457 b(\(Man)-17 b(y)316 b(of)e(these)h(limitations)e(will)h(not)g(mak) +-11 b(e)316 b(sense)e(without)h(ha)-22 b(ving)316 b(read)f(the)g(rest)e +(of)863 20801 y(the)278 b(documentation)i(\002rst.\))2524 +23695 y Fg(\017)554 b Fn(Currently)-72 b(,)373 b(FUSD)356 +b(only)f(supports)f(implementation)i(of)e(character)i(de)-28 +b(vices.)576 b(Block)356 b(de)-28 b(vices)356 b(and)f(netw)-11 +b(ork)355 b(de)-28 b(vices)3631 25023 y(are)277 b(not)g(supported)i +(yet.)2524 27155 y Fg(\017)554 b Fn(The)335 b(k)-11 b(ernel)335 +b(has)g(15)g(dif)-28 b(ferent)334 b(callbacks)i(in)e(its)f +Fo(file)p 25893 27155 333 45 v 400 w(operations)i Fn(structure.)515 +b(The)336 b(current)f(v)-17 b(ersion)335 b(of)f(FUSD)3631 +28484 y(does)277 b(not)h(proxy)g(some)g(of)e(the)i(more)f(obscure)i +(ones)e(out)h(to)f(userspace.)2524 30616 y Fg(\017)554 +b Fn(Currently)-72 b(,)298 b(all)293 b(system)g(calls)g(that)h(FUSD)g +(understands)i(are)d(proxied)i(from)e(the)h(FUSD)h(k)-11 +b(ernel)294 b(module)h(to)f(userspace.)3631 31944 y(Only)341 +b(the)g(userspace)h(library)e(kno)-28 b(ws)342 b(which)f(callbacks)h +(ha)-22 b(v)-17 b(e)343 b(actually)f(been)g(re)-17 b(gistered)341 +b(by)g(the)g(FUSD)h(dri)-28 b(v)-17 b(er)-61 b(.)534 +b(F)-17 b(or)3631 33272 y(e)g(xample,)398 b(the)373 b(k)-11 +b(ernel)374 b(may)f(proxy)h(a)f(write\(\))e(system)h(call)h(to)f(user) +-22 b(-space)374 b(e)-28 b(v)-17 b(en)375 b(if)c(the)i(dri)-28 +b(v)-17 b(er)374 b(has)e(not)h(re)-17 b(gistered)374 +b(a)3631 34601 y(write\(\))275 b(callback)k(with)e(fusd)p +15101 34601 V 399 w(re)-17 b(gister\(\).)3631 36331 y(fusd)p +5603 36331 V 398 w(re)g(gister\(\))238 b(should,)247 +b(b)-22 b(ut)239 b(currently)g(does)g(not,)247 b(tell)238 +b(the)h(k)-11 b(ernel)239 b(module)h(which)g(callbacks)g(it)e(w)-11 +b(ants)239 b(to)f(recei)-28 b(v)-17 b(e,)248 b(per)-22 +b(-)3631 37659 y(de)-28 b(vice.)424 b(This)303 b(will)g(be)h(more)g(ef) +-28 b(\002cient)305 b(because)g(it)e(will)f(pre)-28 b(v)-17 +b(ent)306 b(useless)d(system)g(calls)g(for)g(unsupported)j(operations.) +3631 38987 y(In)380 b(addition,)408 b(it)381 b(will)f(lead)i(to)f(more) +g(logical)h(and)g(consistent)g(beha)-22 b(vior)383 b(by)e(allo)-28 +b(wing)383 b(the)e(k)-11 b(ernel)382 b(to)f(use)h(its)d(def)-11 +b(ault)3631 40316 y(implementations)336 b(of)f(certain)h(functions)g +(such)g(as)f(write)-28 b(v\(\),)349 b(instead)335 b(of)g(being)i +(fooled)f(into)f(thinking)h(the)g(dri)-28 b(v)-17 b(er)336 +b(has)3631 41644 y(an)277 b(implementation)i(of)e(it)f(in)h(cases)h +(where)g(it)e(doesn')-20 b(t.)2524 43776 y Fg(\017)554 +b Fn(It)370 b(should)j(be)g(possible)f(to)f(write)g(a)h(FUSD)h(library) +f(in)f(an)-17 b(y)374 b(language)g(that)e(supports)g(reads)g(and)h +(writes)e(on)h(ra)-17 b(w)373 b(\002le)3631 45104 y(descriptors.)336 +b(In)257 b(the)h(future,)j(it)256 b(might)h(be)h(possible)f(to)g(write) +g(FUSD)h(de)-28 b(vice)260 b(dri)-28 b(v)-17 b(ers)257 +b(in)g(a)h(v)-28 b(ariety)258 b(of)f(languages\227Perl,)3631 +46433 y(Python,)278 b(maybe)h(e)-28 b(v)-17 b(en)279 +b(Ja)-22 b(v)-28 b(a.)345 b(Ho)-28 b(we)g(v)-17 b(er)-44 +b(,)279 b(the)e(current)h(implementation)h(has)e(only)h(a)f(C)g +(library)-72 b(.)2524 48565 y Fg(\017)554 b Fn(It')-61 +b(s)378 b(possible)i(for)f(dri)-28 b(v)-17 b(ers)380 +b(that)g(use)h(FUSD)f(to)g(deadlock\227for)j(e)-17 b(xample,)407 +b(if)379 b(a)h(dri)-28 b(v)-17 b(er)381 b(tries)e(to)g(open)j(itself.) +650 b(In)380 b(this)3631 49893 y(one)270 b(case,)i(FUSD)e(returns)f +Fo(-EDEADLOCK)p Fn(.)i(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)273 +b(deadlock)f(protection)f(should)g(be)f(e)-17 b(xpanded)273 +b(to)d(more)g(general)3631 51221 y(detection)278 b(of)f(c)-17 +b(ycles)279 b(of)d(arbitrary)h(length.)2524 53353 y Fg(\017)554 +b Fn(FUSD)324 b(should)g(pro)-17 b(vide)325 b(a)f(/proc)g(interf)-11 +b(ace)324 b(that)f(gi)-28 b(v)-17 b(es)325 b(deb)-22 +b(ugging)326 b(and)f(status)d(information,)336 b(and)324 +b(allo)-28 b(ws)324 b(parameter)3631 54682 y(tuning.)2524 +56814 y Fg(\017)554 b Fn(FUSD)412 b(w)-11 b(as)412 b(written)f(with)h +(ef)-28 b(\002cienc)-17 b(y)415 b(in)c(mind,)446 b(b)-22 +b(ut)412 b(a)g(number)h(of)e(important)i(optimizations)g(ha)-22 +b(v)-17 b(e)413 b(not)f(yet)g(been)3631 58142 y(implemented.)340 +b(Speci\002cally)-72 b(,)266 b(we')-55 b(d)261 b(lik)-11 +b(e)261 b(to)g(try)f(to)h(reduce)h(the)g(number)g(of)e(memory)j(copies) +e(by)h(using)f(a)g(b)-22 b(uf)-28 b(fer)261 b(shared)3631 +59470 y(between)279 b(user)e(and)h(k)-11 b(ernel)278 +b(space)g(to)f(pass)g(messages.)2524 61602 y Fg(\017)554 +b Fn(FUSD)272 b(currently)g(requires)f(de)-28 b(vfs,)272 +b(which)h(is)d(used)i(to)f(dynamically)i(create)f(de)-28 +b(vice)273 b(\002les)e(under)i Fo(/dev)e Fn(when)i(a)e(FUSD)3631 +62931 y(dri)-28 b(v)-17 b(er)273 b(re)-17 b(gisters)272 +b(itself.)341 b(This)272 b(is,)h(perhaps,)h(the)f(most)g(con)-44 +b(v)-17 b(enient)276 b(and)e(useful)f(paradigm)h(for)e(FUSD.)i(Ho)-28 +b(we)g(v)-17 b(er)-44 b(,)276 b(some)3631 64259 y(users)305 +b(ha)-22 b(v)-17 b(e)309 b(ask)-11 b(ed)307 b(if)f(it')-61 +b(s)305 b(possible)h(to)h(use)f(FUSD)i(without)f(de)-28 +b(vfs.)432 b(This)306 b(should)i(be)f(possible)f(if)g(FUSD)h(dri)-28 +b(v)-17 b(ers)307 b(bind)3631 65587 y(to)276 b(de)-28 +b(vice)280 b(major)d(numbers)h(instead)g(of)f(de)-28 +b(vice)279 b(\002le)e(names.)p 863 66453 20076 45 v 2070 +67194 a Fe(2)2457 67507 y Fd(http://www)-58 b +(.cs.arizona.edu/people/bridges/os/microk)-9 b(ernel.html)2070 +68275 y Fe(3)2457 68588 y Fd(http://www)-58 b(.cs.ucsb)-35 +b(.edu/projects/ufo/inde)-13 b(x.html)2070 69356 y Fe(4)2457 +69669 y Fd(http://www)-58 b(.goop.or)-16 b(g/)223 b(jeremy/userfs/)2070 +70437 y Fe(5)2457 70750 y Fd(http://www)-58 b(.cs.ucsb)-35 +b(.edu/projects/ufo/97-usenix-ufo.ps)25681 74071 y Fn(4)p +eop +%%Page: 5 8 +5 7 bop 863 2974 a Fj(1.6)1329 b(A)-66 b(uthor)331 b(Contact)i(Inf)-33 +b(ormation)331 b(and)g(Ackno)-13 b(wledgments)863 5714 +y Fn(The)290 b(original)f(v)-17 b(ersion)290 b(of)f(FUSD)h(w)-11 +b(as)289 b(written)f(by)i(Jeremy)f(Elson)h(\(jelson@circlemud.or)-20 +b(g\))290 b(and)g(Le)-28 b(wis)289 b(Girod)g(at)g(Sensoria)863 +7042 y(Corporation.)492 b(Sensoria)327 b(no)g(longer)g(maintains)f +(public)i(releases)e(of)g(FUSD,)g(b)-22 b(ut)327 b(the)f(same)h +(authors)f(ha)-22 b(v)-17 b(e)328 b(since)f(fork)-11 +b(ed)327 b(the)863 8370 y(last)276 b(public)j(release)e(and)h(continue) +h(to)e(maintain)h(FUSD)g(from)f(the)h(Uni)-28 b(v)-17 +b(ersity)278 b(of)e(California,)i(Los)f(Angeles.)2524 +10363 y(If)f(you)i(ha)-22 b(v)-17 b(e)279 b(b)-22 b(ug)278 +b(reports,)e(patches,)i(suggestions,)g(or)f(an)-17 b(y)278 +b(other)g(comments,)g(please)g(feel)f(free)g(to)g(contact)i(the)e +(authors.)2524 12355 y(FUSD)263 b(has)f(tw)-11 b(o)262 +b(SourceF)-17 b(or)d(ge)14879 11954 y Ff(6)15326 12355 +y Fn(-host)261 b(mailing)i(lists:)334 b(a)262 b(lo)-28 +b(w-traf)g(\002c)263 b(list)d(for)i(announcements)k(\()p +Fo(fusd-announce)p Fn(\))d(and)863 13684 y(a)346 b(list)e(for)h +(general)i(discussion)f(\()p Fo(fusd-devel)p Fn(\).)549 +b(Subscription)347 b(information)f(for)f(both)i(lists)c(is)i(a)-22 +b(v)-28 b(ailable)347 b(at)f(the)g(Source-)863 15012 +y(F)-17 b(or)d(ge')-61 b(s)278 b(FUSD)g(mailing)g(list)d(page.)2524 +17005 y(F)-17 b(or)277 b(the)h(latest)e(releases)h(and)i(information)e +(about)i(FUSD,)f(please)g(see)f(the)g(of)-28 b(\002cial)278 +b(FUSD)g(home)h(page)43521 16603 y Ff(7)43966 17005 y +Fn(.)863 20837 y Fj(1.7)1329 b(Licensing)331 b(Inf)-33 +b(ormation)863 23577 y Fn(FUSD)294 b(is)e(free)h(softw)-11 +b(are,)297 b(distrib)-22 b(uted)293 b(under)h(a)f(GPL-compatible)j +(license)e(\(the)f(\223ne)-28 b(w\224)295 b(BSD)f(license,)j(with)c +(the)h(adv)-17 b(ertising)863 24905 y(clause)278 b(remo)-17 +b(v)g(ed\).)346 b(The)278 b(license)f(is)g(enumerated)i(in)e(its)f +(entirety)h(belo)-28 b(w)-72 b(.)2524 26898 y(Cop)-11 +b(yright)250 b(\(c\))f(2001,)256 b(Sensoria)251 b(Corporation;)260 +b(\(c\))248 b(2003)j(Uni)-28 b(v)-17 b(ersity)251 b(of)e(California,) +255 b(Los)249 b(Angeles.)335 b(All)249 b(rights)g(reserv)-17 +b(ed.)2524 28891 y(Redistrib)-22 b(ution)318 b(and)h(use)g(in)f(source) +g(and)i(binary)f(forms,)327 b(with)318 b(or)g(without)g +(modi\002cation,)331 b(are)318 b(permitted)h(pro)-17 +b(vided)320 b(that)863 30219 y(the)278 b(follo)-28 b(wing)278 +b(conditions)g(are)f(met:)2524 33097 y Fg(\017)554 b +Fn(Redistrib)-22 b(utions)266 b(of)g(source)h(code)h(must)e(retain)g +(the)h(abo)-17 b(v)g(e)269 b(cop)-11 b(yright)268 b(notice,)h(this)d +(list)e(of)i(conditions)i(and)f(the)g(follo)-28 b(w-)3631 +34425 y(ing)277 b(disclaimer)-61 b(.)2524 36639 y Fg(\017)554 +b Fn(Redistrib)-22 b(utions)375 b(in)f(binary)i(form)f(must)f +(reproduce)k(the)d(abo)-17 b(v)g(e)378 b(cop)-11 b(yright)376 +b(notice,)400 b(this)374 b(list)g(of)g(conditions)j(and)f(the)3631 +37968 y(follo)-28 b(wing)278 b(disclaimer)f(in)g(the)g(documentation)k +(and/or)d(other)f(materials)g(pro)-17 b(vided)279 b(with)e(the)h +(distrib)-22 b(ution.)2524 40182 y Fg(\017)554 b Fn(Neither)330 +b(the)g(names)h(of)f(Sensoria)h(Corporation)g(or)f(UCLA,)g(nor)h(the)f +(names)h(of)e(other)i(contrib)-22 b(utors)330 b(may)h(be)f(used)h(to) +3631 41510 y(endorse)278 b(or)f(promote)h(products)g(deri)-28 +b(v)-17 b(ed)279 b(from)e(this)f(softw)-11 b(are)277 +b(without)h(speci\002c)g(prior)f(written)f(permission.)2524 +44388 y(THIS)317 b(SOFTW)-133 b(ARE)319 b(IS)e(PR)-44 +b(O)-55 b(VIDED)317 b(BY)g(THE)h(A)-61 b(UTHORS)318 b(AND)g(CONTRIB)-11 +b(UT)-20 b(ORS)319 b(\223)-89 b(AS)318 b(IS\224)g(AND)f(ANY)g(EX-)863 +45716 y(PRESS)238 b(OR)f(IMPLIED)g(W)-133 b(ARRANTIES,)238 +b(INCLUDING,)g(B)-11 b(UT)237 b(NO)-44 b(T)236 b(LIMITED)h(T)-20 +b(O,)237 b(THE)g(IMPLIED)g(W)-133 b(ARRANTIES)863 47045 +y(OF)437 b(MERCHANT)-103 b(ABILITY)440 b(AND)d(FITNESS)h(FOR)f(A)g(P) +-102 b(AR)-66 b(TICULAR)439 b(PURPOSE)g(ARE)e(DISCLAIMED.)h(IN)e(NO)863 +48373 y(EVENT)301 b(SHALL)f(THE)g(A)-61 b(UTHORS)301 +b(OR)f(CONTRIB)-11 b(UT)-20 b(ORS)302 b(BE)e(LIABLE)g(FOR)g(ANY)g +(DIRECT)-82 b(,)300 b(INDIRECT)-82 b(,)300 b(INCI-)863 +49701 y(DENT)-103 b(AL,)234 b(SPECIAL,)f(EXEMPLAR)-72 +b(Y)-143 b(,)234 b(OR)f(CONSEQ)-11 b(UENTIAL)235 b(D)-44 +b(AMA)g(GES)233 b(\(INCLUDING,)f(B)-11 b(UT)232 b(NO)-44 +b(T)233 b(LIMITED)863 51030 y(T)-20 b(O,)314 b(PR)-44 +b(OCUREMENT)316 b(OF)d(SUBSTITUTE)j(GOODS)f(OR)e(SER)-89 +b(VICES;)316 b(LOSS)e(OF)g(USE,)g(D)-44 b(A)-123 b(T)-103 +b(A,)314 b(OR)f(PR)-44 b(OFITS;)315 b(OR)863 52358 y(B)-11 +b(USINESS)351 b(INTERR)-44 b(UPTION\))351 b(HO)-39 b(WEVER)351 +b(CA)-61 b(USED)351 b(AND)e(ON)h(ANY)f(THEOR)-72 b(Y)351 +b(OF)f(LIABILITY)-143 b(,)349 b(WHETHER)863 53686 y(IN)294 +b(CONTRA)-44 b(CT)-82 b(,)295 b(STRICT)g(LIABILITY)-143 +b(,)294 b(OR)g(T)-20 b(OR)-66 b(T)295 b(\(INCLUDING)f(NEGLIGENCE)i(OR)e +(O)-44 b(THER)-61 b(WISE\))295 b(ARISING)863 55015 y(IN)371 +b(ANY)i(W)-133 b(A)-116 b(Y)371 b(OUT)i(OF)f(THE)g(USE)g(OF)h(THIS)f +(SOFTW)-133 b(ARE,)373 b(EVEN)g(IF)f(AD)-44 b(VISED)372 +b(OF)g(THE)g(POSSIBILITY)i(OF)863 56343 y(SUCH)278 b(D)-44 +b(AMA)g(GE.)863 60743 y Fm(2)1594 b(Wh)-24 b(y)399 b(use)g(FUSD?)863 +63882 y Fn(One)240 b(basic)f(question)h(about)g(FUSD)g(that)f(one)g +(might)g(ask)g(is:)323 b(what)240 b(is)e(it)f(good)k(for?)330 +b(Wh)-6 b(y)240 b(use)f(it?)331 b(In)238 b(this)g(section,)247 +b(we)239 b(describe)863 65210 y(some)278 b(of)e(the)i(situations)f(in)g +(which)h(FUSD)g(has)f(been)i(the)e(solution)h(for)e(us.)p +863 65934 20076 45 v 2070 66675 a Fe(6)2457 66987 y Fd(http://www)-58 +b(.sourcefor)-16 b(ge.net)2070 67746 y Fe(7)2457 68059 +y Fd(http://www)-58 b(.circlemud.or)-16 b(g/jelson/softw)-9 +b(are/fusd)25681 74071 y Fn(5)p eop +%%Page: 6 9 +6 8 bop 863 2974 a Fj(2.1)1329 b(De)-20 b(vice)332 b(Dri)-13 +b(v)g(er)331 b(Lay)-13 b(ering)863 5714 y Fn(A)309 b(problem)g(that)g +(comes)h(up)f(frequently)h(in)e(modern)i(operating)h(systems)d(is)f +(contention)k(for)d(a)h(single)g(resource)g(by)h(multiple)863 +7042 y(competing)260 b(processes.)338 b(In)257 b(UNIX,)h(it')-61 +b(s)257 b(the)h(job)g(of)g(a)g(de)-28 b(vice)260 b(dri)-28 +b(v)-17 b(er)259 b(to)f(coordinate)i(access)f(to)f(such)h(resources.) +337 b(By)258 b(accepting)863 8370 y(requests)327 b(from)f(user)h +(processes)g(and)h(\(for)d(e)-17 b(xample\))329 b(queuing)g(and)f +(serializing)e(them,)340 b(it)326 b(becomes)i(safe)f(for)f(processes)h +(that)863 9699 y(kno)-28 b(w)273 b(nothing)g(about)f(each)h(other)e(to) +g(mak)-11 b(e)273 b(requests)e(in)g(parallel)h(to)f(the)g(same)h +(resource.)342 b(Of)271 b(course,)h(k)-11 b(ernel)272 +b(dri)-28 b(v)-17 b(ers)272 b(do)g(this)863 11027 y(job)g(already)-72 +b(,)274 b(b)-22 b(ut)271 b(the)-17 b(y)273 b(typically)f(operate)h(on)f +(top)g(of)f(hardw)-11 b(are)273 b(directly)-72 b(.)342 +b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)275 b(k)-11 b(ernel)272 +b(dri)-28 b(v)-17 b(ers)272 b(can')-20 b(t)272 b(easily)f(be)i(layered) +863 12355 y(on)278 b(top)f(of)g Fk(other)h(de)-17 b(vice)279 +b(driver)-11 b(s)p Fn(.)2524 14348 y(F)-17 b(or)252 b(e)-17 +b(xample,)259 b(consider)253 b(a)f(de)-28 b(vice)255 +b(such)d(as)g(a)g(modem)i(that)e(is)f(connected)k(to)d(a)g(host)g(via)g +(a)g(serial)f(port.)335 b(Let')-61 b(s)252 b(say)g(we)g(w)-11 +b(ant)863 15676 y(to)271 b(implement)g(a)g(de)-28 b(vice)272 +b(dri)-28 b(v)-17 b(er)272 b(that)e(allo)-28 b(ws)271 +b(multiple)g(users)f(to)g(dial)h(the)f(telephone)j(\(e.g.,)f +Fo(echo)664 b(1-310-555-1212)j(>)863 17005 y(/dev/phone-dialer)p +Fn(\).)403 b(Such)298 b(a)e(dri)-28 b(v)-17 b(er)297 +b(should)g(be)g(layered)h Fk(on)f(top)f(of)g Fn(the)h(serial)e(port)i +(dri)-28 b(v)-17 b(er)-22 b(\227that)297 b(is,)j(it)295 +b(most)h(lik)-11 b(ely)863 18333 y(w)g(ants)277 b(to)g(write)g(to)g +Fo(/dev/ttyS0)p Fn(,)h(not)f(directly)h(to)f(the)g(U)-44 +b(AR)-66 b(T)277 b(hardw)-11 b(are)279 b(itself.)2524 +20325 y(While)272 b(it)g(is)g(possible)h(to)g(write)f(to)h(a)g(logical) +g(\002le)h(from)e(within)h(a)g(k)-11 b(ernel)273 b(de)-28 +b(vice)275 b(dri)-28 b(v)-17 b(er)-44 b(,)274 b(it)e(is)g(both)i(trick) +-17 b(y)273 b(and)h(considered)863 21654 y(bad)438 b(practice.)823 +b(In)437 b(the)g(w)-11 b(ords)436 b(of)h(k)-11 b(ernel)437 +b(hack)-11 b(er)439 b(Dick)e(Johnson)27919 21252 y Ff(8)28363 +21654 y Fn(,)476 b(\223Y)-122 b(ou)439 b(should)e(ne)-28 +b(v)-17 b(er)439 b(write)d(a)h([k)-11 b(ernel])437 b(module)h(that)863 +22982 y(requires)266 b(reading)i(or)d(writing)h(to)f(an)-17 +b(y)268 b(logical)f(de)-28 b(vice.)341 b(The)267 b(k)-11 +b(ernel)267 b(is)e(the)h(thing)g(that)g(translates)g(ph)-6 +b(ysical)267 b(I/O)f(to)f(logical)i(I/O.)863 24310 y(Attempting)278 +b(to)f(perform)g(logical)h(I/O)e(in)h(the)h(k)-11 b(ernel)278 +b(is)e(ef)-28 b(fecti)g(v)-17 b(ely)279 b(going)f(backw)-11 +b(ards.)-77 b(\224)2524 26303 y(W)-44 b(ith)227 b(FUSD,)j(it')-61 +b(s)227 b(possible)h(to)h(layer)g(de)-28 b(vice)230 b(dri)-28 +b(v)-17 b(ers)229 b(because)i(the)e(dri)-28 b(v)-17 b(er)229 +b(is)e(a)i(user)-22 b(-space)229 b(process,)239 b(not)229 +b(a)f(k)-11 b(ernel)230 b(module.)863 27631 y(A)289 b(FUSD)g +(implementation)i(of)d(our)h(h)-6 b(ypothetical)292 b +Fo(/dev/phone-dialer)f Fn(can)f(open)g Fo(/dev/ttyS0)g +Fn(just)e(as)g(an)-17 b(y)290 b(other)863 28960 y(process)278 +b(w)-11 b(ould.)2524 30952 y(T)-89 b(ypically)-72 b(,)261 +b(such)256 b(layering)g(is)f(accomplished)j(by)d(system)g(daemons.)338 +b(F)-17 b(or)256 b(e)-17 b(xample,)262 b(the)255 b Fo(lpd)h +Fn(daemon)h(manages)h(printers)863 32281 y(at)390 b(a)g(high)h(le)-28 +b(v)-17 b(el.)683 b(Since)391 b(it)e(is)g(a)h(user)-22 +b(-space)391 b(process,)418 b(it)389 b(can)i(access)g(the)f(ph)-6 +b(ysical)391 b(printer)f(de)-28 b(vices)392 b(using)e(k)-11 +b(ernel)391 b(de)-28 b(vice)863 33609 y(dri)g(v)-17 b(ers)278 +b(\(for)e(e)-17 b(xample,)279 b(using)e(printer)g(or)g(netw)-11 +b(ork)278 b(dri)-28 b(v)-17 b(ers\).)343 b(There)279 +b(a)e(number)h(of)f(adv)-28 b(antages)280 b(to)d(using)h(FUSD)g +(instead:)2524 36487 y Fg(\017)554 b Fn(Using)378 b(FUSD,)g(a)g +(daemon/dri)-28 b(v)-17 b(er)382 b(can)d(create)f(a)h(standard)f(de)-28 +b(vice)381 b(\002le)d(which)h(is)e(accessible)i(by)f(an)-17 +b(y)380 b(program)f(that)3631 37815 y(kno)-28 b(ws)247 +b(ho)-28 b(w)248 b(to)e(use)h(the)g(POSIX)g(system)f(call)h(interf)-11 +b(ace.)334 b(Some)247 b(trick)-11 b(ery)247 b(is)f(possible)g(using)h +(named)i(pipes)e(and)g(FIFOs,)3631 39144 y(b)-22 b(ut)277 +b(quickly)h(becomes)h(dif)-28 b(\002cult)278 b(because)h(of)e(multiple) +-17 b(x)g(ed)280 b(writes)c(from)g(multiple)i(processes.)2524 +41358 y Fg(\017)554 b Fn(FUSD)248 b(dri)-28 b(v)-17 b(ers)248 +b(recei)-28 b(v)-17 b(e)249 b(the)f(UID,)f(GID,)g(and)h(process)g(ID)f +(along)i(with)e(e)-28 b(v)-17 b(ery)249 b(\002le)f(operation,)255 +b(allo)-28 b(wing)249 b(the)e(same)h(sorts)3631 42686 +y(of)301 b(security)i(policies)f(to)g(be)h(implemented)h(as)e(w)-11 +b(ould)303 b(be)g(possible)f(with)g(a)g(real)g(k)-11 +b(ernel)303 b(dri)-28 b(v)-17 b(er)-61 b(.)420 b(In)302 +b(contrast,)308 b(writes)301 b(to)3631 44014 y(a)277 +b(named)i(pipe,)e(UDP)-123 b(,)278 b(and)g(so)f(forth)f(are)i(\223anon) +-17 b(ymous.)-77 b(\224)863 47847 y Fj(2.2)1329 b(Use)332 +b(of)g(User)-49 b(-Space)331 b(Libraries)863 50587 y +Fn(Since)240 b(a)f(FUSD)h(dri)-28 b(v)-17 b(er)239 b(is)f(just)g(a)h +(re)-17 b(gular)240 b(user)-22 b(-space)239 b(program,)248 +b(it)238 b(can)h(naturally)h(use)f(an)-17 b(y)240 b(of)f(the)g +(enormous)h(body)h(of)d(e)-17 b(xisting)863 51915 y(libraries)314 +b(that)i(e)-17 b(xist)315 b(for)f(almost)h(an)-17 b(y)317 +b(task.)458 b(FUSD)316 b(dri)-28 b(v)-17 b(ers)315 b(can)h(easily)g +(incorporate)h(user)e(interf)-11 b(aces,)324 b(encryption,)j(netw)-11 +b(ork)863 53244 y(protocols,)338 b(threads,)g(and)327 +b(almost)e(an)-17 b(ything)328 b(else.)488 b(In)326 b(contrast,)337 +b(porting)326 b(arbitrary)g(C)f(code)i(into)f(the)g(k)-11 +b(ernel)326 b(is)f(dif)-28 b(\002cult)326 b(and)863 54572 +y(usually)278 b(a)f(bad)h(idea.)863 58405 y Fj(2.3)1329 +b(Dri)-13 b(v)g(er)331 b(Memory)h(Pr)-24 b(otection)863 +61145 y Fn(Since)355 b(FUSD)g(dri)-28 b(v)-17 b(ers)354 +b(run)g(in)f(their)g(o)-28 b(wn)355 b(process)f(space,)374 +b(the)354 b(rest)f(of)g(the)h(system)g(is)e(protected)j(from)f(them.) +573 b(A)354 b(b)-22 b(uggy)355 b(or)863 62473 y(malicious)252 +b(FUSD)h(dri)-28 b(v)-17 b(er)-44 b(,)257 b(at)251 b(the)h(v)-17 +b(ery)253 b(w)-11 b(orst,)255 b(can)e(only)f(corrupt)g(itself.)334 +b(It')-61 b(s)250 b(not)h(possible)h(for)f(it)g(to)g(corrupt)h(the)g(k) +-11 b(ernel,)257 b(other)863 63801 y(FUSD)268 b(dri)-28 +b(v)-17 b(ers,)269 b(or)e(e)-28 b(v)-17 b(en)270 b(the)d(processes)h +(that)f(are)g(using)h(its)d(de)-28 b(vices.)342 b(In)267 +b(contrast,)i(a)e(b)-22 b(uggy)269 b(k)-11 b(ernel)268 +b(module)h(can)f(bring)f(do)-28 b(wn)863 65130 y(an)-17 +b(y)279 b(process)e(in)g(the)h(system,)e(or)h(the)g(entire)h(k)-11 +b(ernel)278 b(itself.)p 863 66078 20076 45 v 2070 66819 +a Fe(8)2457 67131 y Fd(http://www)-58 b(.uwsg.indiana.edu/h)l +(ypermail/linux/k)-9 b(ernel/0005.3/0061.html)25681 74071 +y Fn(6)p eop +%%Page: 7 10 +7 9 bop 863 2974 a Fj(2.4)1329 b(Gi)-13 b(ving)333 b(libraries)e +(language)h(independence)d(and)i(standard)g(noti\002cation)h +(interfaces)863 5714 y Fn(One)396 b(particularly)g(interesting)f +(application)i(of)e(FUSD)h(that)f(we')-55 b(v)-17 b(e)396 +b(found)h(v)-17 b(ery)396 b(useful)f(is)f(as)h(a)g(w)-11 +b(ay)396 b(to)f(let)g(re)-17 b(gular)396 b(user)-22 b(-)863 +7042 y(space)342 b(libraries)f(e)-17 b(xport)342 b(de)-28 +b(vice)343 b(\002le)f(APIs.)534 b(F)-17 b(or)342 b(e)-17 +b(xample,)359 b(imagine)343 b(you)f(had)g(a)f(library)g(which)h(f)-11 +b(actored)342 b(lar)-20 b(ge)342 b(composite)863 8370 +y(numbers.)596 b(T)-89 b(ypically)-72 b(,)384 b(it)360 +b(might)i(ha)-22 b(v)-17 b(e)362 b(a)g(C)f(interf)-11 +b(ace\227say)-72 b(,)383 b(a)361 b(function)h(called)g +Fo(int)665 b(*factorize\(int)h(bignum\))p Fn(.)863 9699 +y(W)-44 b(ith)408 b(FUSD,)h(it')-61 b(s)406 b(possible)j(to)f(create)h +(a)f(de)-28 b(vice)411 b(\002le)d(interf)-11 b(ace\227say)-72 +b(,)442 b(a)409 b(de)-28 b(vice)410 b(called)f Fo(/dev/factorize)i +Fn(to)d(which)863 11027 y(clients)277 b(can)h Fo(write\(2\))g +Fn(a)g(big)f(number)-44 b(,)278 b(then)g Fo(read\(2\))g +Fn(back)h(its)c(f)-11 b(actors.)2524 13020 y(This)279 +b(may)h(sound)g(strange,)g(b)-22 b(ut)280 b(de)-28 b(vice)281 +b(\002le)f(APIs)e(ha)-22 b(v)-17 b(e)281 b(at)e(least)g(three)h(adv)-28 +b(antages)282 b(o)-17 b(v)g(er)281 b(a)f(typical)g(library)f(API.)g +(First,)f(it)863 14348 y(becomes)253 b(much)f(more)f(language)i +(independent\227an)-17 b(y)256 b(language)d(that)e(can)g(mak)-11 +b(e)252 b(system)f(calls)f(can)i(access)f(the)g(f)-11 +b(actorization)863 15676 y(library)-72 b(.)739 b(Second,)444 +b(the)409 b(f)-11 b(actorization)410 b(code)h(is)d(running)i(in)f(a)g +(dif)-28 b(ferent)409 b(address)h(space;)476 b(if)408 +b(it)g(crashes,)442 b(it)408 b(w)-11 b(on')-20 b(t)409 +b(crash)g(or)863 17005 y(corrupt)364 b(the)g(caller)-61 +b(.)604 b(Third,)385 b(and)365 b(most)e(interestingly)-72 +b(,)385 b(it)363 b(is)g(possible)h(to)f(use)h Fo(select\(2\))h +Fn(to)e(w)-11 b(ait)364 b(for)f(the)h(f)-11 b(actorization)863 +18333 y(to)337 b(complete.)526 b Fo(select\(2\))338 b +Fn(w)-11 b(ould)338 b(mak)-11 b(e)339 b(it)d(easy)i(for)e(a)i(client)f +(to)g(f)-11 b(actor)337 b(a)h(lar)-20 b(ge)338 b(number)g(while)g +(remaining)g(responsi)-28 b(v)-17 b(e)863 19661 y(to)329 +b Fk(other)h Fn(e)-28 b(v)-17 b(ents)331 b(that)f(might)f(happen)j(in)d +(the)h(meantime.)502 b(In)329 b(other)g(w)-11 b(ords,)343 +b(FUSD)330 b(allo)-28 b(ws)329 b(normal)h(user)-22 b(-space)331 +b(libraries)d(to)863 20990 y(inte)-17 b(grate)278 b(seamlessly)g(with)e +(UNIX')-61 b(s)277 b(e)-17 b(xisting,)277 b(POSIX-standard)i(e)-28 +b(v)-17 b(ent)279 b(noti\002cation)g(interf)-11 b(ace:)344 +b Fo(select\(2\))p Fn(.)863 24743 y Fj(2.5)1329 b(De)-20 +b(v)-13 b(elopment)331 b(and)g(Deb)-27 b(ugging)332 b(Con)-53 +b(v)-13 b(enience)863 27483 y Fn(FUSD)286 b(processes)g(can)g(be)g(de) +-28 b(v)-17 b(eloped)289 b(and)e(deb)-22 b(ugged)288 +b(with)d(all)g(the)g(normal)h(user)-22 b(-space)286 b(tools.)368 +b(Buggy)287 b(dri)-28 b(v)-17 b(ers)285 b(w)-11 b(on')-20 +b(t)286 b(crash)863 28812 y(the)318 b(system,)327 b(b)-22 +b(ut)318 b(instead)g(dump)g(cores)g(that)g(can)g(be)g(analyzed.)467 +b(All)317 b(of)g(your)h(f)-11 b(a)-22 b(v)g(orite)318 +b(visual)f(deb)-22 b(uggers,)330 b(memory)318 b(bounds)863 +30140 y(check)-11 b(ers,)420 b(leak)390 b(detectors,)419 +b(pro\002lers,)f(and)391 b(other)f(tools)g(can)h(be)f(applied)i(to)e +(FUSD)g(dri)-28 b(v)-17 b(ers)391 b(as)e(the)-17 b(y)391 +b(w)-11 b(ould)391 b(to)f(an)-17 b(y)391 b(other)863 +31468 y(program.)863 35789 y Fm(3)1594 b(Installing)400 +b(FUSD)863 38928 y Fn(This)228 b(section)i(describes)f(the)g +(installation)f(procedure)j(for)d(FUSD.)h(It)f(assumes)g(a)h(good)h(w) +-11 b(orking)229 b(kno)-28 b(wledge)232 b(of)d(Linux)g(system)863 +40256 y(administration.)863 44010 y Fj(3.1)1329 b(Pr)-24 +b(er)g(equisites)863 46750 y Fn(Before)278 b(installing)f(FUSD,)h(mak) +-11 b(e)278 b(sure)f(you)h(ha)-22 b(v)-17 b(e)279 b(all)e(of)f(the)i +(follo)-28 b(wing)278 b(packages)i(installed)d(and)h(w)-11 +b(orking)278 b(correctly:)2524 49410 y Fg(\017)554 b +Fl(Linux)293 b(k)-11 b(er)-17 b(nel)295 b(2.4.0)f(or)f(later)p +Fn(.)391 b(FUSD)294 b(w)-11 b(as)292 b(de)-28 b(v)-17 +b(eloped)297 b(under)d(2.4.0)g(and)f(should)h(w)-11 b(ork)293 +b(with)g(an)-17 b(y)294 b(k)-11 b(ernel)294 b(in)e(the)i(2.4)3631 +50738 y(series.)2524 52777 y Fg(\017)554 b Fl(de)-17 +b(vfs)256 b(installed)f(and)h(running)-17 b(.)339 b Fn(FUSD)256 +b(dynamically)i(re)-17 b(gisters)255 b(de)-28 b(vices)257 +b(using)f(de)-28 b(vfs,)260 b(the)255 b(Linux)i(de)-28 +b(vice)258 b(\002lesystem)3631 54105 y(by)388 b(Richard)h(Gooch.)676 +b(F)-17 b(or)389 b(FUSD)f(to)g(w)-11 b(ork,)415 b(de)-28 +b(vfs)388 b(must)f(be)i(installed)e(and)i(running)g(on)f(your)h +(system.)674 b(F)-17 b(or)389 b(more)3631 55434 y(information)277 +b(about)i(de)-28 b(vfs)277 b(installation,)g(see)h(the)f(de)-28 +b(vfs)278 b(home)g(page)30782 55032 y Ff(9)31227 55434 +y Fn(.)3631 57117 y(Note)295 b(that)g(some)h(distrib)-22 +b(utions)294 b(mak)-11 b(e)297 b(installation)e(de)-28 +b(vfs)295 b(easier)-61 b(.)398 b(RedHat)296 b(7.1,)k(for)295 +b(e)-17 b(xample,)301 b(already)c(has)e(all)g(of)g(the)3631 +58445 y(necessary)f(daemons)h(and)f(con\002guration)i(changes)g(inte) +-17 b(grated.)393 b(de)-28 b(vfs)293 b(can)h(be)g(installed)f(simply)g +(by)h(recompiling)h(the)3631 59774 y(k)-11 b(ernel)277 +b(with)g(de)-28 b(vfs)278 b(support)g(enabled)h(and)f(recon\002guring)i +(LILO)e(to)e(pass)h Fo("devfs=mount")i Fn(to)e(the)h(k)-11 +b(ernel.)863 63527 y Fj(3.2)1329 b(Compiling)332 b(FUSD)f(as)h(a)h(K) +-33 b(er)-20 b(nel)331 b(Module)863 66267 y Fn(Before)312 +b(compiling)h(an)-17 b(ything,)322 b(tak)-11 b(e)312 +b(a)f(look)h(at)g(the)f(Mak)-11 b(e\002le)313 b(in)e(FUSD')-61 +b(s)312 b(home)h(directory)-72 b(.)446 b(Adjust)312 b(an)-17 +b(y)312 b(constants)g(that)g(are)863 67596 y(not)368 +b(correct.)616 b(In)367 b(particular)-44 b(,)390 b(mak)-11 +b(e)369 b(sure)e Fo(KERNEL)p 21778 67596 333 45 v 400 +w(HOME)h Fn(correctly)g(re\003ects)g(the)g(place)h(where)g(your)f(k)-11 +b(ernel)369 b(sources)f(are)863 68924 y(installed,)277 +b(if)f(the)-17 b(y)278 b(aren')-20 b(t)278 b(in)f(the)g(def)-11 +b(ault)278 b(location)g(of)f Fo(/usr/src/linux)p Fn(.)p +863 69696 20076 45 v 2070 70437 a Fe(9)2457 70750 y Fd(http://www)-58 +b(.atnf.csiro.au/)225 b(r)-16 b(gooch/linux/docs/de)-22 +b(vfs.html)25681 74071 y Fn(7)p eop +%%Page: 8 11 +8 10 bop 2524 2974 a Fn(Then,)350 b(type)335 b Fo(make)p +Fn(.)516 b(It)334 b(should)h(generate)i(a)d(directory)i(whose)f(name)h +(looks)f(something)h(lik)-11 b(e)334 b Fo(obj.i686-linux)p +Fn(,)351 b(or)863 4302 y(some)278 b(v)-28 b(ariation)278 +b(depending)i(on)e(your)g(architecture.)344 b(Inside)277 +b(of)g(that)g(directory)h(will)e(be)i(a)f(number)i(of)e(\002les,)f +(including:)2524 7180 y Fg(\017)554 b Fn(kfusd.o)277 +b(\226)g(The)h(FUSD)h(k)-11 b(ernel)277 b(module)2524 +9394 y Fg(\017)554 b Fn(libfusd.a)277 b(\226)g(The)h(C)f(library)g +(used)h(to)f(talk)g(to)g(the)g(k)-11 b(ernel)278 b(module)2524 +11608 y Fg(\017)554 b Fn(Example)278 b(programs)g(\226)f(link)-11 +b(ed)278 b(ag)-6 b(ainst)279 b(libfusd.a)2524 14486 y(Compilation)338 +b(of)f(the)g(k)-11 b(ernel)338 b(module)g(will)f(f)-11 +b(ail)336 b(if)g(the)h(dependencies)k(described)d(in)f(the)g(pre)-28 +b(vious)339 b(section)e(are)h(not)f(sat-)863 15815 y(is\002ed.)438 +b(The)310 b(module)g(must)f(be)g(compiled)h(ag)-6 b(ain)311 +b(Linux)e(k)-11 b(ernel)310 b(must)e(be)h(v2.4.0)h(or)f(later)-44 +b(,)315 b(and)310 b(the)f(k)-11 b(ernel)309 b(must)g(ha)-22 +b(v)-17 b(e)310 b(de)-28 b(vfs)863 17143 y(support)278 +b(enabled.)863 20976 y Fj(3.3)1329 b(T)-122 b(esting)332 +b(and)f(T)-98 b(r)-24 b(oubleshooting)863 23716 y Fn(Once)293 +b(e)-28 b(v)-17 b(erything)294 b(has)e(been)h(compiled,)k(gi)-28 +b(v)-17 b(e)293 b(it)d(a)i(try)f(to)g(see)h(if)e(it)h(actually)i(does)f +(something.)388 b(First,)293 b(use)f Fo(insmod)g Fn(to)g(insert)863 +25044 y(the)216 b(FUSD)g(k)-11 b(ernel)217 b(module,)229 +b(e.g.)323 b Fo(insmod)665 b(obj.i686-linux/kfusd.o)p +Fn(.)326 b(A)215 b(greeting)i(message)f(similar)f(to)g(\223)p +Fo(fusd:)863 26372 y(starting,)666 b(Revision:)1330 b(1.50)p +Fn(\224)328 b(should)f(appear)i(in)e(the)g(k)-11 b(ernel)327 +b(log)h(\(accessed)g(using)f(the)g Fo(dmesg)h Fn(command,)341 +b(or)863 27701 y(by)304 b(typing)h Fo(cat)665 b(/proc/kmsg)p +Fn(\).)423 b(Y)-122 b(ou)305 b(can)f(v)-17 b(erify)304 +b(the)g(module)h(has)f(been)h(inserted)f(by)g(typing)g +Fo(lsmod)p Fn(,)311 b(or)303 b(alternati)-28 b(v)-17 +b(ely)863 29029 y Fo(cat)665 b(/proc/modules)p Fn(.)2524 +31021 y(Once)323 b(the)f(module)i(has)e(been)h(inserted)f(successfully) +-72 b(,)334 b(trying)322 b(running)h(the)f Fo(helloworld)i +Fn(e)-17 b(xample)324 b(program.)479 b(When)863 32350 +y(run,)335 b(the)323 b(program)i(should)f(print)e(a)i(greeting)g +(message)g(similar)e(to)h Fo(/dev/hello-world)667 b(should)e(now)g +(exist)g(-)863 33678 y(calling)h(fusd)p 8899 33678 333 +45 v 399 w(run)p Fn(.)330 b(This)236 b(means)h(e)-28 +b(v)-17 b(erything)239 b(is)c(w)-11 b(orking;)251 b(the)237 +b(daemon)h(is)e(no)-28 b(w)237 b(block)-11 b(ed,)247 +b(w)-11 b(aiting)236 b(for)g(requests)g(to)h(the)863 +35006 y(ne)-28 b(w)308 b(de)-28 b(vice.)436 b(From)308 +b(another)g(shell,)314 b(type)308 b Fo(cat)665 b(/dev/hello-world)p +Fn(.)436 b(Y)-122 b(ou)308 b(should)g(see)g Fo(Hello,)665 +b(world!)434 b Fn(printed)863 36335 y(in)277 b(response.)344 +b(T)-39 b(ry)278 b(killing)f(the)g(test)f(program;)i(the)g +(corresponding)h(de)-28 b(vice)279 b(\002le)f(should)g(disappear)-61 +b(.)2524 38327 y(If)309 b(nothing)j(seems)f(to)f(be)i(w)-11 +b(orking,)320 b(try)310 b(looking)i(at)e(the)h(k)-11 +b(ernel)312 b(message)g(log)f(\(type)g Fo(dmesg)g Fn(or)f +Fo(cat)665 b(/proc/kmsg)p Fn(\))863 39656 y(to)317 b(see)h(if)e(there)i +(are)f(an)-17 b(y)319 b(errors.)463 b(If)316 b(nothing)j(seems)f(ob)-17 +b(viously)319 b(wrong,)328 b(try)317 b(turning)h(on)g(FUSD)g(k)-11 +b(ernel)318 b(module)h(deb)-22 b(ugging)863 40984 y(by)278 +b(de\002ning)h Fo(CONFIG)p 10202 40984 V 400 w(FUSD)p +13258 40984 V 399 w(DEBUG)f Fn(in)f(kfusd.c,)g(then)h(recompiling)g +(and)h(reinserting)e(the)g(module.)863 44817 y Fj(3.4)1329 +b(Installation)863 47557 y Fn(T)-89 b(yping)236 b Fo(make)665 +b(install)236 b Fn(will)d(cop)-11 b(y)236 b(the)e(FUSD)h(library)-72 +b(,)243 b(header)236 b(\002les,)242 b(and)236 b(man)f(pages)g(into)f +Fo(/usr/local)p Fn(.)331 b(The)235 b(FUSD)863 48885 y(k)-11 +b(ernel)276 b(module)h(is)e Fk(not)g Fn(installed)h(automatically)h +(because)h(of)d(v)-28 b(ariations)276 b(among)h(dif)-28 +b(ferent)276 b(Linux)g(distrib)-22 b(utions)275 b(in)g(ho)-28 +b(w)277 b(this)863 50213 y(is)219 b(accomplished.)327 +b(Y)-122 b(ou)221 b(may)g(w)-11 b(ant)221 b(to)f(arrange)h(to)f(ha)-22 +b(v)-17 b(e)222 b(the)e(module)i(start)d(automatically)i(on)g(boot)g +(by)g(\(for)e(e)-17 b(xample\))222 b(cop)-11 b(ying)863 +51542 y(it)276 b(into)h Fo(/lib/modules/your-kernel-version)p +Fn(,)283 b(and)278 b(adding)h(it)d(to)h Fo(/etc/modules.conf)p +Fn(.)863 55375 y Fj(3.5)1329 b(Making)332 b(FUSD)f(P)-13 +b(art)332 b(of)g(the)g(K)-33 b(er)-20 b(nel)332 b(Pr)-24 +b(oper)863 58114 y Fn(The)335 b(earlier)f(instructions,)347 +b(by)335 b(def)-11 b(ault,)348 b(create)335 b(a)f(FUSD)h(k)-11 +b(ernel)335 b(module.)515 b(If)333 b(desired,)348 b(it')-61 +b(s)332 b(also)i(v)-17 b(ery)335 b(easy)g(to)f(b)-22 +b(uild)334 b(FUSD)863 59443 y(right)277 b(into)g(the)g(k)-11 +b(ernel,)278 b(instead:)2247 62321 y(1.)554 b(Unpack)233 +b(the)f(2.4)g(k)-11 b(ernel)233 b(sources)f(and)h(cop)-11 +b(y)233 b(all)e(the)h(\002les)g(in)f(the)h Fo(include)g +Fn(and)h Fo(kfusd)f Fn(directories)g(into)g(your)g(k)-11 +b(ernel)3631 63649 y(source)262 b(tree,)i(under)e Fo(drivers/char)p +Fn(.)340 b(F)-17 b(or)262 b(e)-17 b(xample,)266 b(if)260 +b(FUSD)j(is)d(in)h(your)h(home)h(directory)-72 b(,)264 +b(and)f(your)f(k)-11 b(ernel)262 b(is)e(in)3631 64977 +y Fo(/usr/src/linux)p Fn(:)8944 67634 y Fo(cp)664 b(\230/fusd/kfusd/*)j +(\230/fusd/include/*)g(/usr/src/linux/drivers/char)2247 +70291 y Fn(2.)554 b(Apply)278 b(the)f(patch)h(found)h(in)e(FUSD')-61 +b(s)277 b Fo(patches)h Fn(directory)g(to)f(your)h(k)-11 +b(ernel)278 b(source)f(tree.)344 b(F)-17 b(or)277 b(e)-17 +b(xample:)25681 74071 y(8)p eop +%%Page: 9 12 +9 11 bop 8944 2974 a Fo(cd)664 b(/usr/src/linux)8944 +4302 y(patch)h(-p0)g(<)f(\230/fusd/patches/fusd-inkernel.patch)3631 +6753 y Fn(The)401 b(FUSD)h(in-k)-11 b(ernel)402 b(patch)g(doesn')-20 +b(t)401 b(actually)h(change)i(an)-17 b(y)402 b(k)-11 +b(ernel)402 b(sources)f(proper;)463 b(it)400 b(just)h(adds)g(FUSD)h(to) +f(the)3631 8082 y(k)-11 b(ernel)277 b(con\002guration)k(menu)d(and)g +(Mak)-11 b(e\002le.)2247 10214 y(3.)554 b(Using)266 b(your)i(k)-11 +b(ernel)267 b(con\002gurator)j(of)c(choice)j(\(e.g.)339 +b Fo(make)665 b(menuconfig)p Fn(\),)270 b(turn)c(on)i(the)f(FUSD)g +(options.)341 b(It)266 b(will)f(be)3631 11542 y(under)278 +b(the)f(\223Character)i(de)-28 b(vices\224)279 b(menu.)2247 +13674 y(4.)554 b(Build)277 b(and)h(install)e(the)i(k)-11 +b(ernel)278 b(as)f(usual.)863 18037 y Fm(4)1594 b(Basic)399 +b(De)-24 b(vice)398 b(Cr)-29 b(eation)863 21175 y Fn(Enough)280 +b(introduction\227it')-61 b(s)277 b(time)g(to)g(actually)h(create)g(a)f +(basic)h(de)-28 b(vice)279 b(dri)-28 b(v)-17 b(er)278 +b(using)f(FUSD!)2524 23168 y(This)304 b(follo)-28 b(wing)306 +b(sections)f(will)f(illustrate)g(v)-28 b(arious)305 b(techniques)i +(using)e(e)-17 b(xample)308 b(programs.)427 b(T)-89 b(o)305 +b(sa)-22 b(v)-17 b(e)306 b(space,)313 b(interesting)863 +24496 y(e)-17 b(xcerpts)418 b(are)e(sho)-28 b(wn)418 +b(instead)e(of)g(entire)h(programs.)761 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)453 b(the)416 b Fo(examples)i Fn(directory)f(of)f(the)g +(FUSD)h(distrib)-22 b(ution)863 25824 y(contains)360 +b(all)e(the)h(e)-17 b(xamples)361 b(in)d(their)h(entirety)-72 +b(.)588 b(The)-17 b(y)361 b(can)f(actually)f(be)h(compiled)g(and)g(run) +f(on)g(a)g(system)f(with)h(the)g(FUSD)863 27153 y(k)-11 +b(ernel)278 b(module)h(installed.)2524 29145 y(Where)362 +b(this)f(te)-17 b(xt)363 b(refers)e(to)h(e)-17 b(xample)364 +b(program)f(line)f(numbers,)384 b(it)361 b(refers)g(to)h(the)g(line)g +(numbers)h(printed)g(alongside)h(the)863 30474 y(e)-17 +b(xcerpts)279 b(in)e(the)g(manual\227not)i(the)f(line)f(numbers)h(of)f +(the)g(actual)h(programs)g(in)f(the)g Fo(examples)h Fn(directory)-72 +b(.)863 34269 y Fj(4.1)1329 b(Using)332 b Fc(fusd)p 10700 +34269 399 45 v 478 w(register)g Fj(to)h(cr)-24 b(eate)332 +b(a)g(new)f(de)-20 b(vice)863 37009 y Fn(W)-89 b(e)367 +b(sa)-17 b(w)366 b(an)h(e)-17 b(xample)368 b(of)e(a)g(simple)g(dri)-28 +b(v)-17 b(er)-44 b(,)388 b(hello)-28 b(w)-11 b(orld.c,)390 +b(in)365 b(Program)i(1)g(on)f(page)i(2.)610 b(Let')-61 +b(s)365 b(go)i(back)g(and)g(e)-17 b(xamine)369 b(that)863 +38337 y(program)278 b(no)-28 b(w)278 b(in)f(more)h(detail.)2524 +40330 y(The)228 b(FUSD)g(ball)g(starts)e(rolling)h(when)i(the)e +Fo(fusd)p 22085 40330 333 45 v 400 w(register)h Fn(function)h(is)d +(called,)238 b(as)227 b(sho)-28 b(wn)229 b(on)f(line)f(40.)328 +b(This)227 b(function)863 41658 y(tells)276 b(the)i(FUSD)g(k)-11 +b(ernel)278 b(module:)2524 44372 y Fg(\017)554 b Fo(char)664 +b(*name)p Fn(\227The)222 b(name)f(of)f(the)g(de)-28 b(vice)222 +b(being)f(created.)325 b(The)221 b(pre\002x)g(\(such)f(as)f +Fo(/dev/)p Fn(\))h(must)g(match)h(the)f(location)3631 +45700 y(where)349 b(de)-28 b(vfs)350 b(has)f(been)i(mounted.)561 +b(Names)350 b(containing)h(slashes)d(\(e.g.,)367 b Fo +(/dev/my-devices/dev1)p Fn(\))352 b(are)d(le)-17 b(g)-6 +b(al;)3631 47029 y(de)-28 b(vfs)277 b(creates)h(subdirectories)g +(automatically)-72 b(.)2524 49161 y Fg(\017)554 b Fo(mode)p +6353 49161 V 399 w(t)664 b(mode)p Fn(\227The)284 b(de)-28 +b(vice')-61 b(s)284 b(def)-11 b(ault)283 b(permissions.)358 +b(This)282 b(is)f(usually)i(speci\002ed)h(using)f(an)g(octal)f +(constant)i(with)e(a)3631 50489 y(leading)c(0\227)p Fo(0666)g +Fn(\(readable)h(and)f(writable)f(by)h(e)-28 b(v)-17 b(eryone\))280 +b(instead)d(of)g(the)h(incorrect)g(decimal)g(constant)g +Fo(666)p Fn(.)2524 52621 y Fg(\017)554 b Fo(void)664 +b(*device)p 11665 52621 V 400 w(info)p Fn(\227Pri)-28 +b(v)g(ate)292 b(data)g(that)e(should)h(be)g(passed)g(to)f(callback)i +(functions)f(for)f(this)g(de)-28 b(vice.)384 b(The)292 +b(use)3631 53949 y(of)276 b(this)h(\002eld)h(is)e(described)i(in)f +(Section)i(5.1.)2524 56081 y Fg(\017)554 b Fo(struct)665 +b(fusd)p 11002 56081 V 399 w(file)p 14057 56081 V 399 +w(operations)h(*fops)p Fn(\227A)286 b(structure)f(containing)j +(pointers)d(to)g(the)h(callback)h(functions)3631 57409 +y(that)277 b(should)h(be)f(called)i(by)e(FUSD)h(in)f(response)h(to)f +(certain)h(e)-28 b(v)-17 b(ents.)2524 60123 y(If)228 +b(de)-28 b(vice)232 b(re)-17 b(gistration)230 b(is)f(successful,)239 +b Fo(fusd)p 20591 60123 V 399 w(register)231 b Fn(returns)e(a)h +Fk(de)-17 b(vice)232 b(handle)p Fn(\227a)g(small)d(inte)-17 +b(ger)231 b Fg(\025)307 b Fb(0)p Fn(.)328 b(On)230 b(errors,)863 +61451 y(it)305 b(returns)h(-1)f(and)i(sets)e(the)h(global)h(v)-28 +b(ariable)308 b Fo(errno)e Fn(appropriately)-72 b(.)432 +b(In)305 b(reality)-72 b(,)313 b(the)306 b(de)-28 b(vice)308 +b(handle)g(you)f(get)f(is)f(a)h(plain)h(old)863 62780 +y(\002le)278 b(descriptor)-44 b(,)276 b(as)h(we')-11 +b(ll)277 b(see)g(in)g(Section)i(7.)2524 64772 y(Although)303 +b(Program)f(1)g(only)g(calls)f Fo(fusd)p 19296 64772 +V 399 w(register)i Fn(once,)308 b(it)301 b(can)h(be)g(called)h +(multiple)e(times)g(if)g(the)g(FUSD)i(dri)-28 b(v)-17 +b(er)302 b(is)863 66100 y(handling)279 b(more)f(than)g(one)g(de)-28 +b(vice)279 b(as)e(we')-11 b(ll)276 b(see)i(in)f(Program)h(4.)2524 +68093 y(There)375 b(is)f(intentional)i(similarity)d(between)j +Fo(fusd)p 23104 68093 V 400 w(register\(\))g Fn(and)f(the)g(k)-11 +b(ernel')-61 b(s)375 b(de)-28 b(vice)377 b(re)-17 b(gistration)374 +b(functions,)863 69421 y(such)265 b(as)f Fo(devfs)p 7728 +69421 V 400 w(register\(\))i Fn(and)f Fo(register)p 22208 +69421 V 400 w(chrdev\(\))p Fn(.)340 b(In)264 b(man)-17 +b(y)266 b(w)-11 b(ays,)267 b(FUSD')-61 b(s)265 b(interf)-11 +b(ace)265 b(is)e(meant)j(to)e(mirror)863 70750 y(the)278 +b(k)-11 b(ernel)278 b(interf)-11 b(ace)277 b(as)g(closely)h(as)f +(possible.)25681 74071 y(9)p eop +%%Page: 10 13 +10 12 bop 2524 2974 a Fn(The)358 b Fo(fusd)p 7324 2974 +333 45 v 400 w(file)p 10380 2974 V 399 w(operations)h +Fn(structure,)378 b(de\002ned)360 b(in)e Fo(fusd.h)p +Fn(,)379 b(contains)359 b(a)f(list)e(of)i(callbacks)h(that)f(are)g +(used)h(in)863 4302 y(response)325 b(to)e(dif)-28 b(ferent)324 +b(system)g(calls)f(e)-17 b(x)g(ecuted)327 b(on)e(a)e(\002le.)484 +b(It)322 b(is)h(similar)g(to)g(the)h(k)-11 b(ernel')-61 +b(s)324 b Fo(file)p 39605 4302 V 399 w(operations)h Fn(structure,)863 +5631 y(accepting)g(callbacks)f(for)e(system)g(calls)g(such)h(as)f +Fo(open\(\))p Fn(,)334 b Fo(close\(\))p Fn(,)g Fo(read\(\))p +Fn(,)g Fo(write\(\))p Fn(,)g(and)324 b Fo(ioctl\(\))p +Fn(.)480 b(F)-17 b(or)323 b(the)863 6959 y(most)243 b(part,)250 +b(the)244 b(prototypes)h(of)f(FUSD)g(\002le)g(operation)h(callbacks)h +(are)d(the)h(same)h(as)e(their)g(k)-11 b(ernel)245 b(cousins,)250 +b(with)244 b(one)g(important)863 8287 y(e)-17 b(xception.)338 +b(The)254 b(\002rst)d(ar)-20 b(gument)255 b(of)d(FUSD)i(callbacks)g(is) +e(al)-11 b(w)g(ays)253 b(a)g(pointer)g(to)f(a)h Fo(fusd)p +35757 8287 V 399 w(file)p 38812 8287 V 400 w(info)g Fn(structure;)260 +b(it)252 b(contains)863 9616 y(information)322 b(that)g(can)g(be)g +(used)g(to)f(identify)h(the)g(\002le.)476 b(This)321 +b(structure)g(is)g(used)h(instead)g(of)f(the)h(k)-11 +b(ernel')-61 b(s)321 b Fo(file)h Fn(and)g Fo(inode)863 +10944 y Fn(structures,)276 b(and)j(will)d(be)h(described)i(in)e(more)g +(detail)h(later)-61 b(.)2524 12936 y(In)247 b(lines)h(35\22638)i(of)e +(Program)h(1,)254 b(we)248 b(create)h(and)h(initialize)e(a)g +Fo(fusd)p 29219 12936 V 399 w(file)p 32274 12936 V 399 +w(operations)i Fn(structure.)333 b(A)248 b(GCC-speci\002c)863 +14265 y(C)240 b(e)-17 b(xtension)241 b(allo)-28 b(ws)240 +b(us)f(to)h(name)g(structure)g(\002elds)g(e)-17 b(xplicitly)240 +b(in)g(the)g(initializer)-61 b(.)330 b(This)239 b(style)h(may)g(look)g +(strange,)248 b(b)-22 b(ut)239 b(it)g(guards)863 15593 +y(ag)-6 b(ainst)302 b(errors)d(in)i(the)f(future)h(in)f(case)h(the)g +(order)g(of)f(\002elds)h(in)f(the)h(structure)g(e)-28 +b(v)-17 b(er)302 b(changes.)415 b(The)302 b(2.4)e(k)-11 +b(ernel)302 b(series)d(uses)i(the)863 16922 y(same)278 +b(trick.)2524 18914 y(After)401 b(calling)i Fo(fusd)p +11398 18914 V 399 w(register\(\))g Fn(on)g(line)f(40,)434 +b(the)402 b(e)-17 b(xample)405 b(program)e(calls)f Fo(fusd)p +39357 18914 V 399 w(run\(\))g Fn(on)h(line)f(44.)719 +b(This)863 20242 y(function)235 b(turns)f(control)g(o)-17 +b(v)g(er)235 b(to)f(the)g(FUSD)h(frame)-28 b(w)-11 b(ork.)330 +b(fusd)p 25909 20242 V 399 w(run)234 b(blocks)h(the)f(dri)-28 +b(v)-17 b(er)234 b(until)g(one)h(of)e(the)i(de)-28 b(vices)235 +b(it)e(re)-17 b(gistered)863 21571 y(needs)278 b(to)f(be)h(serviced.) +344 b(Then,)279 b(it)d(calls)h(the)g(appropriate)i(callback)g(and)f +(blocks)g(ag)-6 b(ain)279 b(until)e(the)g(ne)-17 b(xt)278 +b(e)-28 b(v)-17 b(ent.)2524 23563 y(No)-28 b(w)-72 b(,)455 +b(imagine)420 b(that)f(a)g(user)f(types)i Fo(cat)664 +b(/dev/hello-world)p Fn(.)772 b(What)419 b(happens?)771 +b(Recall)420 b(\002rst)e(what)i(the)f Fo(cat)863 24892 +y Fn(program)283 b(itself)d(does:)353 b(opens)283 b(a)f(\002le,)h +(reads)f(from)f(it)g(until)g(it)g(recei)-28 b(v)-17 b(es)283 +b(an)g(EOF)f(\(printing)f(whate)-28 b(v)-17 b(er)285 +b(it)280 b(reads)i(to)g(stdout\),)g(then)863 26220 y(closes)296 +b(it.)400 b Fo(cat)296 b Fn(w)-11 b(orks)296 b(the)g(same)h(w)-11 +b(ay)297 b(re)-17 b(g)-6 b(ardless)297 b(of)f(what)g(it')-61 +b(s)295 b(reading\227be)j(it)d(a)h(a)h(FUSD)g(de)-28 +b(vice,)302 b(a)297 b(re)-17 b(gular)297 b(\002le,)j(a)d(serial)863 +27548 y(port,)277 b(or)g(an)-17 b(ything)279 b(else.)343 +b(The)278 b Fo(strace)g Fn(program)g(is)e(a)i(great)f(w)-11 +b(ay)278 b(to)f(see)g(this)g(in)f(action;)i(see)g(Appendix)h(A)e(for)g +(details.)863 31381 y Fj(4.2)1329 b(The)331 b Fc(open)h +Fj(and)g Fc(close)g Fj(callbacks)863 34121 y Fn(The)298 +b(\002rst)d(tw)-11 b(o)297 b(callbacks)h(that)f(most)f(dri)-28 +b(v)-17 b(ers)297 b(typically)h(implement)f(are)g Fo(open)g +Fn(and)h Fo(close)p Fn(.)402 b(Each)298 b(of)f(these)g(tw)-11 +b(o)296 b(functions)863 35449 y(are)222 b(passed)h(just)e(one)i(ar)-20 +b(gument\227the)224 b Fo(fusd)p 18814 35449 V 399 w(file)p +21869 35449 V 400 w(info)e Fn(structure)g(that)f(describes)i(the)f +(instance)h(of)f(the)g(\002le)g(being)h(opened)863 36778 +y(or)277 b(closed.)344 b(Use)277 b(of)g(the)g(information)h(in)f(that)g +(structure)g(will)f(be)i(co)-17 b(v)g(ered)280 b(in)d(more)h(detail)f +(in)g(Section)h(5.)2524 38770 y(The)g(semantics)f(of)g(an)h +Fo(open)f Fn(callback')-61 b(s)279 b(return)e(v)-28 b(alue)278 +b(are)g(e)-17 b(xactly)279 b(the)e(same)h(as)e(inside)i(the)f(k)-11 +b(ernel:)2524 41648 y Fg(\017)554 b Fn(0)241 b(means)g(success,)249 +b(and)242 b(the)f(\002le)g(is)f(opened.)334 b(If)239 +b(the)j(\002le)f(is)f(allo)-28 b(wed)242 b(to)f(open,)249 +b(the)241 b(k)-11 b(ernel)242 b(returns)f(a)g(v)-28 b(alid)241 +b(\002le)h(descriptor)3631 42977 y(to)290 b(the)g(client.)383 +b(Using)291 b(that)f(descriptor)-44 b(,)293 b(other)e(callbacks)h(may)f +(be)g(called)g(for)f(that)g(\002le,)k(including)e(\(at)d(least\))h(a)g +Fo(close)3631 44305 y Fn(callback.)2524 46519 y Fg(\017)554 +b Fn(A)364 b(ne)-17 b(g)-6 b(ati)-28 b(v)-17 b(e)368 +b(number)e(indicates)f(a)g(f)-11 b(ailure,)386 b(and)366 +b(that)e(the)h(\002le)g(should)g(not)g(be)g(opened.)609 +b(Such)366 b(return)e(v)-28 b(alues)366 b(should)3631 +47847 y Fk(always)287 b Fn(be)h(the)g(speci\002ed)h(as)d(a)i(ne)-17 +b(g)-6 b(ati)-28 b(v)-17 b(e)290 b Fo(errno)e Fn(v)-28 +b(alue)289 b(such)e(as)g Fo(-EPERM)p Fn(,)h Fo(-EBUSY)p +Fn(,)f Fo(-ENODEV)p Fn(,)h Fo(-ENOMEM)p Fn(,)g(and)3631 +49176 y(so)416 b(on.)764 b(F)-17 b(or)417 b(e)-17 b(xample,)454 +b(if)416 b(the)i(callback)h(returns)d Fo(-EPERM)p Fn(,)i(the)f(caller') +-61 b(s)416 b Fo(open\(\))i Fn(will)e(return)h(-1,)452 +b(with)416 b Fo(errno)3631 50504 y Fn(set)367 b(to)g +Fo(EPERM)p Fn(.)h(A)f(complete)j(list)c(of)h(possible)h(return)g(v)-28 +b(alues)369 b(can)f(be)h(found)g(in)e(the)h(Linux)h(k)-11 +b(ernel)368 b(sources,)391 b(under)3631 51832 y Fo(include/asm/errno.h) +p Fn(.)2524 54710 y(If)267 b(an)j Fo(open)f Fn(callback)i(returns)d(0)h +(\(success\),)h(a)f(dri)-28 b(v)-17 b(er)270 b(is)e Fk(guar)-17 +b(anteed)272 b Fn(to)d(recei)-28 b(v)-17 b(e)271 b(e)-17 +b(xactly)270 b(one)g Fo(close)g Fn(callback)h(for)d(that)863 +56039 y(\002le)d(later)-61 b(.)339 b(By)265 b(the)g(same)g(tok)-11 +b(en,)268 b(the)d(close)g(callback)h Fk(will)e(not)h +Fn(be)g(called)g(if)f(the)h(open)h(f)-11 b(ails.)338 +b(Therefore,)268 b Fo(open)d Fn(callbacks)h(that)863 +57367 y(can)278 b(return)f(f)-11 b(ailure)277 b(must)g(be)h(sure)f(to)g +(deallocate)i(an)-17 b(y)278 b(resources)g(the)-17 b(y)278 +b(might)g(ha)-22 b(v)-17 b(e)279 b(allocated)f(before)g(returning)g(a)f +(f)-11 b(ailure.)2524 59360 y(Let')-61 b(s)347 b(return)i(to)f(our)g(e) +-17 b(xample)351 b(in)d(Program)h(1,)366 b(which)349 +b(creates)g(the)g Fo(/dev/hello-world)h Fn(de)-28 b(vice.)559 +b(If)347 b(a)h(user)h(types)863 60688 y Fo(cat)665 b(/dev/hello-world)p +Fn(,)250 b Fo(cat)241 b Fn(will)f(will)f(use)i(the)g +Fo(open\(2\))h Fn(system)f(call)f(to)h(open)h(the)f(\002le.)332 +b(FUSD)241 b(will)f(then)i(proxy)863 62016 y(that)298 +b(system)g(call)g(to)f(the)h(dri)-28 b(v)-17 b(er)299 +b(and)g(acti)-28 b(v)g(ate)300 b(the)e(callback)i(that)e(w)-11 +b(as)298 b(re)-17 b(gistered)298 b(as)g(the)g Fo(open)g +Fn(callback.)408 b(Recall)298 b(from)g(line)863 63345 +y(36)278 b(of)f(Program)h(1)f(that)g(we)h(re)-17 b(gistered)277 +b Fo(do)p 17888 63345 V 399 w(open)p 20943 63345 V 399 +w(or)p 22670 63345 V 399 w(close)p Fn(,)h(which)g(appears)g(on)g(line)f +(8.)2524 65337 y(In)348 b Fo(helloworld.c)p Fn(,)369 +b(the)350 b Fo(open)f Fn(callback)i(al)-11 b(w)g(ays)350 +b(returns)f(0,)367 b(or)349 b(success.)559 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)370 b(in)349 b(a)g(real)g(dri)-28 b(v)-17 +b(er)-44 b(,)368 b(something)863 66666 y(more)346 b(interesting)g(will) +f(probably)i(happen\227permissions)h(checks,)364 b(memory)347 +b(allocation)g(for)e(state-k)-11 b(eeping,)365 b(and)346 +b(so)g(forth.)863 67994 y(The)315 b(corresponding)i Fk(de)p +Fn(-allocation)f(of)e(those)h(resources)g(should)g(occur)g(in)f(the)h +Fo(close)f Fn(callback,)326 b(which)315 b(is)e(called)i(when)h(a)863 +69322 y(user)283 b(application)i(calls)e Fo(close)h Fn(on)g(their)f +(\002le)h(descriptor)-61 b(.)362 b Fo(close)284 b Fn(callbacks)h(are)e +(allo)-28 b(wed)285 b(to)e(return)h(error)e(v)-28 b(alues,)286 +b(b)-22 b(ut)284 b(this)863 70651 y(does)278 b(not)f(pre)-28 +b(v)-17 b(ent)280 b(the)d(\002le)g(from)g(actually)h(closing.)25405 +74071 y(10)p eop +%%Page: 11 14 +11 13 bop 863 2974 a Fj(4.3)1329 b(The)331 b Fc(read)h +Fj(callback)863 5714 y Fn(Returning)309 b(to)e(our)g +Fo(cat)665 b(/dev/hello-world)310 b Fn(e)-17 b(xample,)317 +b(what)307 b(happens)j(after)c(the)i Fo(open)g Fn(is)e(successful?)434 +b(Ne)-17 b(xt,)316 b Fo(cat)863 7042 y Fn(will)345 b(try)g(to)g(use)h +Fo(read\(2\))p Fn(,)364 b(which)346 b(will)f(get)h(proxied)h(by)f(FUSD) +h(to)e(the)h(function)h Fo(do)p 36325 7042 333 45 v 399 +w(read)f Fn(on)g(line)g(13.)549 b(This)346 b(function)863 +8370 y(tak)-11 b(es)278 b(some)f(additional)i(ar)-20 +b(guments)278 b(that)f(we)h(didn')-20 b(t)277 b(see)g(in)g(the)h(open)g +(and)g(close)g(callbacks:)2524 11225 y Fg(\017)554 b +Fo(struct)665 b(fusd)p 11002 11225 V 399 w(file)p 14057 +11225 V 399 w(info)g(*file)p Fn(\227The)294 b(\002rst)e(ar)-20 +b(gument)294 b(to)e(all)g(callbacks,)297 b(containing)e(information)e +(which)3631 12554 y(describes)277 b(the)h(\002le;)f(see)g(Section)i(5.) +2524 14756 y Fg(\017)554 b Fo(char)664 b(*user)p 10337 +14756 V 400 w(buffer)p Fn(\227The)370 b(b)-22 b(uf)-28 +b(fer)369 b(that)f(the)g(callback)j(should)e(use)f(to)h(write)e(data)i +(that)g(it)e(is)g(returning)i(to)g(the)3631 16085 y(user)-61 +b(.)2524 18287 y Fg(\017)554 b Fo(size)p 6353 18287 V +399 w(t)664 b(user)p 10736 18287 V 399 w(length)p Fn(\227The)294 +b(maximum)f(number)g(of)e(bytes)h(requested)h(by)g(the)f(user)-61 +b(.)386 b(The)293 b(dri)-28 b(v)-17 b(er)292 b(is)f(allo)-28 +b(wed)293 b(to)3631 19616 y(return)277 b(fe)-28 b(wer)277 +b(bytes,)g(b)-22 b(ut)278 b(should)g(ne)-28 b(v)-17 b(er)279 +b(write)d(more)i(then)g Fo(user)p 29807 19616 V 399 w(length)g +Fn(bytes)f(into)g Fo(user)p 41736 19616 V 399 w(buffer)p +Fn(.)2524 21818 y Fg(\017)554 b Fo(loff)p 6353 21818 +V 399 w(t)664 b(*offset)p Fn(\227A)250 b(pointer)f(to)f(an)h(inte)-17 +b(ger)249 b(which)h(represents)e(the)h(caller')-61 b(s)248 +b(of)-28 b(fset)247 b(into)i(the)g(\002le)f(\(i.e.,)253 +b(the)c(user')-61 b(s)3631 23146 y(\002le)305 b(pointer\).)429 +b(This)306 b(v)-28 b(alue)307 b(can)g(be)f(modi\002ed)i(by)e(the)g +(callback;)321 b(an)-17 b(y)307 b(change)h(will)d(be)h(propag)-6 +b(ated)309 b(back)e(to)f(the)g(user')-61 b(s)3631 24475 +y(\002le)277 b(pointer)h(inside)f(the)g(k)-11 b(ernel.)2524 +27330 y(The)278 b(semantics)f(of)g(the)g(return)h(v)-28 +b(alue)278 b(are)g(the)f(same)h(as)e(if)g(the)i(callback)h(were)e +(being)i(written)e(inside)g(the)g(k)-11 b(ernel)278 b(itself:)2524 +30185 y Fg(\017)554 b Fn(Positi)-28 b(v)-17 b(e)248 b(return)g(v)-28 +b(alues)249 b(indicate)g(success.)334 b(If)246 b(the)i(call)g(is)e +(successful,)254 b(and)249 b(the)f(dri)-28 b(v)-17 b(er)248 +b(has)g(copied)h(data)g(into)e Fo(buffer)p Fn(,)3631 +31513 y(the)416 b(return)g(v)-28 b(alue)417 b(indicates)g(ho)-28 +b(w)417 b(man)-17 b(y)417 b(bytes)f(were)h(copied.)761 +b(This)416 b(number)h(should)f(ne)-28 b(v)-17 b(er)418 +b(be)f(greater)f(than)h(the)3631 32842 y Fo(user)p 6353 +32842 V 399 w(length)278 b Fn(ar)-20 b(gument.)2524 35044 +y Fg(\017)554 b Fn(A)277 b(0)g(return)g(v)-28 b(alue)279 +b(indicates)f(EOF)f(has)h(been)g(reached)h(on)f(the)g(\002le.)2524 +37247 y Fg(\017)554 b Fn(As)278 b(in)i(the)f Fo(open)h +Fn(and)h Fo(close)f Fn(callbacks,)h(ne)-17 b(g)-6 b(ati)-28 +b(v)-17 b(e)283 b(v)-28 b(alues)281 b(\(such)e(as)g(-EPERM,)h(-EPIPE,)g +(or)f(-ENOMEM\))h(indicate)3631 38575 y(errors.)342 b(Such)278 +b(v)-28 b(alues)279 b(will)d(cause)i(the)g(user')-61 +b(s)276 b Fo(read\(\))i Fn(to)f(return)g(-1)g(with)f(errno)i(set)e +(appropriately)-72 b(.)2524 41430 y(The)332 b(\002rst)f(time)h(a)g +(read)h(is)e(done)i(on)f(a)g(de)-28 b(vice)334 b(\002le,)346 +b(the)332 b(user')-61 b(s)331 b(\002le)i(pointer)f(\()p +Fo(*offset)p Fn(\))g(is)f(0.)508 b(In)331 b(the)i(case)f(of)g(this)f +(\002rst)863 42759 y(read,)403 b(a)378 b(greeting)h(message)g(of)e +Fo(Hello,)665 b(world!)646 b Fn(is)377 b(copied)i(back)g(to)f(the)g +(user)-44 b(,)402 b(as)377 b(seen)i(on)f(line)g(24.)645 +b(The)379 b(user')-61 b(s)377 b(\002le)863 44087 y(pointer)279 +b(is)e(then)h(adv)-28 b(anced.)350 b(The)279 b(ne)-17 +b(xt)279 b(read)g(therefore)g(f)-11 b(ails)276 b(the)j(comparison)g(at) +f(line)g(20,)h(f)-11 b(alling)277 b(straight)h(through)h(to)f(return) +863 45415 y(0,)f(or)g(EOF)-89 b(.)2524 47408 y(In)369 +b(this)g(simple)g(program,)394 b(we)370 b(also)f(see)h(an)g(e)-17 +b(xample)372 b(of)e(an)g(error)f(return)h(on)g(line)f(22:)529 +b(if)369 b(the)h(user)f(tries)g(to)g(do)h(a)g(read)863 +48736 y(smaller)354 b(than)h(the)g(length)g(of)g(the)f(greeting)i +(message,)374 b(the)355 b(read)g(will)f(f)-11 b(ail)353 +b(with)h(-EINV)-149 b(AL.)354 b(\(In)g(an)h(actual)g(dri)-28 +b(v)-17 b(er)-44 b(,)374 b(it)354 b(w)-11 b(ould)863 +50065 y(normally)323 b(not)g(be)g(an)g(error)f(for)f(a)i(user)f(to)g +(pro)-17 b(vide)324 b(a)f(smaller)f(read)h(b)-22 b(uf)-28 +b(fer)322 b(than)h(the)g(size)f(of)g(the)h(a)-22 b(v)-28 +b(ailable)324 b(data.)480 b(The)323 b(right)863 51393 +y(w)-11 b(ay)246 b(for)f(dri)-28 b(v)-17 b(ers)246 b(to)f(handle)i +(this)d(situation)i(is)e(to)h(return)g(partial)g(data,)253 +b(then)246 b(mo)-17 b(v)g(e)247 b Fo(*offset)f Fn(forw)-11 +b(ard)246 b(so)f(that)g(the)h(remainder)863 52721 y(is)276 +b(returned)i(on)g(the)f(ne)-17 b(xt)279 b Fo(read\(\))p +Fn(.)344 b(W)-89 b(e)277 b(see)h(an)f(e)-17 b(xample)280 +b(of)d(this)f(in)h(Program)h(2.\))863 56549 y Fj(4.4)1329 +b(The)331 b Fc(write)i Fj(callback)863 59289 y Fn(Program)342 +b(1)g(illustrated)e(ho)-28 b(w)343 b(a)e(dri)-28 b(v)-17 +b(er)342 b(could)h(return)e(data)h Fk(to)f Fn(a)g(client)h(using)g(the) +f Fo(read)h Fn(callback.)537 b(As)341 b(you)h(might)g(e)-17 +b(xpect,)863 60617 y(there)344 b(is)f(a)g(corresponding)j +Fo(write)e Fn(callback)i(that)d(allo)-28 b(ws)344 b(the)g(dri)-28 +b(v)-17 b(er)344 b(to)f(recei)-28 b(v)-17 b(e)346 b(data)e +Fk(fr)-50 b(om)344 b Fn(a)f(client.)543 b Fo(write)344 +b Fn(tak)-11 b(es)344 b(four)863 61945 y(ar)-20 b(guments,)278 +b(similar)e(to)h(the)g Fo(read)h Fn(callback:)2524 65016 +y Fg(\017)554 b Fo(struct)665 b(fusd)p 11002 65016 V +399 w(file)p 14057 65016 V 399 w(info)g(*file)p Fn(\227The)294 +b(\002rst)e(ar)-20 b(gument)294 b(to)e(all)g(callbacks,)297 +b(containing)e(information)e(which)3631 66345 y(describes)277 +b(the)h(\002le;)f(see)g(Section)i(5.)2524 68547 y Fg(\017)554 +b Fo(const)665 b(char)f(*user)p 14322 68547 V 400 w(buffer)p +Fn(\227Pointer)279 b(to)e(data)g(being)i(written)e(by)g(the)h(client)f +(\(read-only\).)2524 70750 y Fg(\017)554 b Fo(size)p +6353 70750 V 399 w(t)664 b(user)p 10736 70750 V 399 w(length)p +Fn(\227The)279 b(number)g(of)e(bytes)g(pointed)i(to)e(by)g +Fo(user)p 34471 70750 V 400 w(buffer)p Fn(.)25405 74071 +y(11)p eop +%%Page: 12 15 +12 14 bop 2524 2974 a Fg(\017)554 b Fo(loff)p 6353 2974 +333 45 v 399 w(t)664 b(*offset)p Fn(\227A)250 b(pointer)f(to)f(an)h +(inte)-17 b(ger)249 b(which)h(represents)e(the)h(caller')-61 +b(s)248 b(of)-28 b(fset)247 b(into)i(the)g(\002le)f(\(i.e.,)253 +b(the)c(user')-61 b(s)3631 4302 y(\002le)305 b(pointer\).)429 +b(This)306 b(v)-28 b(alue)307 b(can)g(be)f(modi\002ed)i(by)e(the)g +(callback;)321 b(an)-17 b(y)307 b(change)h(will)d(be)h(propag)-6 +b(ated)309 b(back)e(to)f(the)g(user')-61 b(s)3631 5631 +y(\002le)277 b(pointer)h(inside)f(the)g(k)-11 b(ernel.)2524 +8730 y(The)278 b(semantics)f(of)g Fo(write)p Fn(')-61 +b(s)277 b(return)g(v)-28 b(alue)279 b(are)e(the)h(same)f(as)g(in)g(a)g +(k)-11 b(ernel)278 b(callback:)2524 11608 y Fg(\017)554 +b Fn(Positi)-28 b(v)-17 b(e)321 b(return)f(v)-28 b(alues)321 +b(indicate)h(success)e(and)h(indicate)h(ho)-28 b(w)321 +b(man)-17 b(y)322 b(bytes)e(of)g(the)g(user')-61 b(s)320 +b(b)-22 b(uf)-28 b(fer)320 b(were)h(successfully)3631 +12936 y(written)284 b(\(i.e.,)i(successfully)f(processed)h(by)g(the)f +(dri)-28 b(v)-17 b(er)286 b(in)e(some)i(w)-11 b(ay\).)367 +b(The)286 b(return)f(v)-28 b(alue)286 b(may)g(be)f(less)f(than)i(or)f +(equal)3631 14265 y(to)276 b(the)i Fo(user)p 9120 14265 +V 399 w(length)g Fn(ar)-20 b(gument,)278 b(b)-22 b(ut)278 +b(should)g(ne)-28 b(v)-17 b(er)279 b(be)e(greater)-61 +b(.)2524 16479 y Fg(\017)554 b Fn(0)277 b(should)h(only)g(be)f +(returned)h(in)f(response)h(to)f(a)h Fo(write)f Fn(of)g(length)h(0.) +2524 18693 y Fg(\017)554 b Fn(Ne)-17 b(g)-6 b(ati)-28 +b(v)-17 b(e)406 b(v)-28 b(alues)403 b(\(such)g(as)g(-EPERM,)g(-EPIPE,)g +(or)f(-ENOMEM\))h(indicate)h(errors.)719 b(Such)404 b(v)-28 +b(alues)404 b(will)e(cause)i(the)3631 20021 y(user')-61 +b(s)276 b Fo(write\(\))i Fn(to)f(return)g(-1)g(with)g(errno)g(set)g +(appropriately)-72 b(.)2524 22899 y(Program)408 b(2,)441 +b(echo.c,)h(is)407 b(an)h(e)-17 b(xample)410 b(implementation)g(of)e(a) +g(de)-28 b(vice)410 b(\()p Fo(/dev/echo)p Fn(\))e(that)g(uses)g(both)g +Fo(read\(\))h Fn(and)863 24227 y Fo(write\(\))d Fn(callbacks.)730 +b(A)405 b(client)g(that)h(tries)e(to)h Fo(read\(\))h +Fn(from)f(this)f(de)-28 b(vice)407 b(will)e(get)g(the)h(contents)g(of)f +(the)h(most)f(recent)863 25556 y Fo(write\(\))p Fn(.)344 +b(F)-17 b(or)278 b(e)-17 b(xample:)863 27935 y Fo(\045)665 +b(echo)f(Hello)h(there)g(>)g(/dev/echo)863 29264 y(\045)g(cat)f +(/dev/echo)863 30592 y(Hello)h(there)863 31920 y(\045)g(echo)f(Device)i +(drivers)f(are)g(fun)f(>)h(/dev/echo)863 33249 y(\045)g(cat)f +(/dev/echo)863 34577 y(Device)h(drivers)h(are)e(fun)2524 +37435 y Fn(The)260 b(implementation)i(of)d Fo(/dev/echo)i +Fn(k)-11 b(eeps)261 b(a)e(global)i(v)-28 b(ariable,)264 +b Fo(data)p Fn(,)g(which)c(serv)-17 b(es)260 b(as)g(a)f(cache)j(for)d +(the)h(data)g(most)863 38763 y(recently)255 b(written)e(to)g(the)h(dri) +-28 b(v)-17 b(er)254 b(by)g(a)f(client)h(program.)336 +b(The)255 b(dri)-28 b(v)-17 b(er)254 b(does)g(not)f(assume)h(the)g +(data)g(is)f(null-terminated,)258 b(so)c(it)e(also)863 +40092 y(k)-11 b(eeps)278 b(track)g(of)f(the)g(number)i(of)d(bytes)i(of) +f(data)h(a)-22 b(v)-28 b(ailable.)345 b(\(These)278 b(tw)-11 +b(o)277 b(v)-28 b(ariables)278 b(appear)h(on)e(lines)g(1\2262.\))2524 +42084 y(The)313 b(dri)-28 b(v)-17 b(er')-61 b(s)313 b +Fo(write)g Fn(callback)h(\002rst)e(frees)g(an)-17 b(y)314 +b(data)f(which)h(might)e(ha)-22 b(v)-17 b(e)315 b(been)f(allocated)g +(by)f(a)g(pre)-28 b(vious)314 b(call)e(to)h(write)863 +43413 y(\(lines)348 b(26\22629\).)558 b(Ne)-17 b(xt,)367 +b(on)349 b(line)f(33,)367 b(it)347 b(attempts)i(to)f(allocate)h(ne)-28 +b(w)350 b(memory)f(for)f(the)h(ne)-28 b(w)349 b(data)g(arri)-28 +b(ving.)558 b(If)347 b(the)h(allocation)863 44741 y(f)-11 +b(ails,)377 b Fo(-ENOMEM)360 b Fn(is)d(returned)j(to)e(the)h(client.) +588 b(If)357 b(the)i(allocation)h(is)d(successful,)379 +b(the)359 b(dri)-28 b(v)-17 b(er)359 b(copies)g(the)g(data)h(into)e +(its)f(local)863 46069 y(b)-22 b(uf)-28 b(fer)302 b(and)g(stores)e(its) +g(length)j(\(lines)d(37\22638\).)418 b(Finally)-72 b(,)308 +b(the)301 b(dri)-28 b(v)-17 b(er)303 b(tells)d(the)h(user)h(that)f(the) +h(entire)f(b)-22 b(uf)-28 b(fer)301 b(w)-11 b(as)302 +b(consumed)h(by)863 47398 y(returning)278 b(a)f(v)-28 +b(alue)279 b(equal)f(to)f(the)h(number)g(of)f(bytes)g(the)h(user)f +(tried)g(to)g(write)f(\()p Fo(user)p 34362 47398 V 399 +w(length)p Fn(\).)2524 49390 y(The)324 b Fo(read)f Fn(callback)i(has)e +(some)h(e)-17 b(xtra)324 b(features)f(that)g(we)h(did)f(not)g(see)h(in) +f(Program)h(1')-61 b(s)322 b Fo(read\(\))i Fn(callback.)483 +b(The)324 b(most)863 50719 y(important)387 b(is)e(that)h(it)g(allo)-28 +b(ws)386 b(the)h(dri)-28 b(v)-17 b(er)387 b(to)f(read)h(the)f(a)-22 +b(v)-28 b(ailable)388 b(data)f Fk(incr)-41 b(ementally)p +Fn(,)415 b(instead)387 b(of)f(requiring)h(that)f(the)h(\002rst)863 +52047 y Fo(read\(\))288 b Fn(e)-17 b(x)g(ecuted)291 b(by)d(the)g +(client)f(has)h(enough)h(space)g(for)d(all)h(the)h(data)g(the)g(dri)-28 +b(v)-17 b(er)288 b(has)f(a)-22 b(v)-28 b(ailable.)376 +b(In)287 b(other)h(w)-11 b(ords,)289 b(a)f(client)863 +53375 y(can)278 b(do)g(tw)-11 b(o)277 b(50-byte)i(reads,)e(and)h(e)-17 +b(xpect)279 b(the)f(same)f(ef)-28 b(fect)278 b(as)e(if)h(it)f(had)i +(done)h(a)e(single)g(100-byte)i(read.)2524 55368 y(This)334 +b(is)g(implemented)j(using)f Fo(*offset)p Fn(,)350 b(the)335 +b(user')-61 b(s)334 b(\002le)h(pointer)-61 b(.)518 b(If)334 +b(the)h(user)g(is)f(trying)h(to)g(read)h(past)e(the)i(amount)g(of)863 +56696 y(data)362 b(we)f(ha)-22 b(v)-17 b(e)362 b(a)-22 +b(v)-28 b(ailable,)384 b(the)361 b(dri)-28 b(v)-17 b(er)361 +b(returns)g(EOF)g(\(lines)f(8\2269\).)595 b(Normally)-72 +b(,)382 b(this)360 b(happens)j(after)d(the)i(client)f(has)g(\002nished) +863 58025 y(reading)g(data.)590 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)381 b(in)359 b(this)f(dri)-28 b(v)-17 b(er)-44 +b(,)380 b(it)358 b(might)i(happen)h(on)f(a)f(client')-61 +b(s)359 b(\002rst)f(read)i(if)e(nothing)i(has)f(been)i(written)e(to)g +(the)863 59353 y(dri)-28 b(v)-17 b(er)278 b(yet)f(or)g(if)f(the)i(most) +f(recent)h(write')-61 b(s)275 b(memory)k(allocation)f(f)-11 +b(ailed.)2524 61345 y(If)258 b(there)j(is)e(data)i(to)e(return,)264 +b(the)c(dri)-28 b(v)-17 b(er)261 b(computes)g(the)g(number)g(of)f +(bytes)g(that)g(should)h(be)g(copied)g(back)h(to)e(the)g(client\227the) +863 62674 y(minimum)e(of)f(the)h(number)g(of)f(bytes)h(the)g(user)f +(ask)-11 b(ed)258 b(for)-44 b(,)260 b(and)f(the)e(number)i(of)e(bytes)h +(of)f(data)h(that)f(this)g(client)g(hasn')-20 b(t)258 +b(seen)g(yet)863 64002 y(\(line)266 b(12\).)339 b(This)266 +b(data)g(is)f(copied)j(back)f(to)f(the)g(user')-61 b(s)265 +b(b)-22 b(uf)-28 b(fer)265 b(\(line)h(15\),)i(and)f(the)f(user')-61 +b(s)265 b(\002le)h(pointer)g(is)f(adv)-28 b(anced)269 +b(accordingly)863 65331 y(\(line)277 b(16\).)343 b(Finally)-72 +b(,)278 b(on)g(line)f(19,)g(the)h(client)f(is)f(told)h(ho)-28 +b(w)279 b(man)-17 b(y)278 b(bytes)g(were)f(copied)i(to)e(its)f(b)-22 +b(uf)-28 b(fer)-61 b(.)25405 74071 y(12)p eop +%%Page: 13 16 +13 15 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(2)d Fn(echo.c:)345 b(Using)277 b(both)h Fo(read)g Fn(and)g +Fo(write)f Fn(callbacks)p 863 3445 50191 45 v 365 4367 +a Fi(1)1661 b Fo(char)664 b(*data)i(=)e(NULL;)2524 5695 +y(int)g(data_length)i(=)f(0;)2524 8352 y(int)f(echo_read\(struct)j +(fusd_file_info)g(*file,)e(char)g(*user_buffer,)365 9680 +y Fi(5)10959 b Fo(size_t)665 b(user_length,)i(loff_t)e(*offset\))2524 +11009 y({)3852 12337 y(/*)f(if)h(the)g(user)g(has)f(read)h(past)g(the)g +(end)f(of)h(the)g(data,)g(return)g(EOF)g(*/)3852 13665 +y(if)f(\(*offset)i(>=)f(data_length\))5180 14994 y(return)h(0;)-133 +16322 y Fi(10)3852 17650 y Fo(/*)e(only)h(return)h(as)e(much)h(data)g +(as)f(we)h(have)g(*/)3852 18979 y(user_length)h(=)e(MIN\(user_length,)j +(data_length)g(-)d(*offset\);)3852 21636 y(/*)g(copy)h(data)g(to)g +(user)g(starting)g(from)g(the)g(first)g(byte)g(they)g(haven't)g(seen)g +(*/)-133 22964 y Fi(15)2989 b Fo(memcpy\(user_buffer,)667 +b(data)e(+)g(*offset,)g(user_length\);)3852 24292 y(*offset)g(+=)g +(user_length;)3852 26949 y(/*)f(tell)h(them)g(how)g(much)g(data)g(they) +g(got)f(*/)3852 28277 y(return)h(user_length;)-133 29606 +y Fi(20)1661 b Fo(})2524 32262 y(ssize_t)665 b(echo_write\(struct)i +(fusd_file_info)g(*file,)e(const)g(char)g(*user_buffer,)15143 +33591 y(size_t)g(user_length,)h(loff_t)g(*offset\))2524 +34919 y({)-133 36247 y Fi(25)2989 b Fo(/*)664 b(free)h(the)g(old)g +(data,)g(if)f(any)h(*/)3852 37576 y(if)f(\(data)i(!=)e(NULL\))h({)5180 +38904 y(free\(data\);)5180 40232 y(data)g(=)g(NULL;)5180 +41561 y(data_length)h(=)f(0;)-133 42889 y Fi(30)2989 +b Fo(})3852 45546 y(/*)664 b(allocate)i(space)f(for)g(new)g(data;)g +(return)g(error)g(if)f(that)h(fails)g(*/)3852 46874 y(if)f(\(\(data)i +(=)e(malloc\(user_length\)\))k(==)c(NULL\))5180 48203 +y(return)i(-ENOMEM;)-133 49531 y Fi(35)3852 50859 y Fo(/*)e(make)h(a)g +(copy)g(of)f(user's)h(data;)g(tell)g(the)g(user)g(we)f(copied)i +(everything)g(*/)3852 52188 y(memcpy\(data,)g(user_buffer,)h +(user_length\);)3852 53516 y(data_length)f(=)e(user_length;)3852 +54844 y(return)h(user_length;)-133 56173 y Fi(40)1661 +b Fo(})p 863 57667 V 863 60988 a Fj(4.5)1329 b(Unr)-24 +b(egistering)331 b(a)i(de)-20 b(vice)331 b(with)h Fc(fusd)p +22940 60988 399 45 v 479 w(unregister\(\))863 63728 y +Fn(All)e(de)-28 b(vices)331 b(re)-17 b(gistered)331 b(by)g(a)f(dri)-28 +b(v)-17 b(er)331 b(are)f(unre)-17 b(gistered)332 b(automatically)g +(when)f(the)g(program)g(e)-17 b(xits)330 b(\(or)g(crashes\).)502 +b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)863 65056 y(the)409 +b Fo(fusd)p 5346 65056 333 45 v 399 w(unregister\(\))h +Fn(function)g(can)f(be)g(used)g(to)g(unre)-17 b(gister)409 +b(a)f(de)-28 b(vice)411 b(without)e(terminating)g(the)g(entire)f(dri) +-28 b(v)-17 b(er)-61 b(.)863 66384 y Fo(fusd)p 3585 66384 +V 399 w(unregister)279 b Fn(tak)-11 b(es)277 b(one)h(ar)-20 +b(gument:)345 b(a)278 b(de)-28 b(vice)279 b(handle)g(\(i.e.,)c(the)j +(return)f(v)-28 b(alue)279 b(from)d Fo(fusd)p 41820 66384 +V 400 w(register\(\))p Fn(\).)2524 68377 y(A)217 b(de)-28 +b(vice)219 b(can)g(be)f(unre)-17 b(gistered)219 b(at)e(an)-17 +b(y)219 b(time.)323 b(An)-17 b(y)219 b(client)f(system)f(calls)g(that)h +(are)f(pending)j(when)f(a)e(de)-28 b(vice)220 b(is)c(unre)-17 +b(gistered)863 69705 y(will)276 b(return)h(immediately)i(with)e(an)g +(error)-61 b(.)343 b(In)277 b(this)f(case,)i Fo(errno)g +Fn(will)e(be)h(set)g(to)g Fo(-EPIPE)p Fn(.)25405 74071 +y(13)p eop +%%Page: 14 17 +14 16 bop 863 2974 a Fm(5)1594 b(Using)399 b(Inf)-40 +b(ormation)399 b(in)f Fa(fusd)p 21880 2974 479 45 v 576 +w(file)p 26280 2974 V 575 w(info)863 6112 y Fn(W)-89 +b(e)232 b(mentioned)i(in)d(the)g(pre)-28 b(vious)233 +b(sections)f(that)f(the)h(\002rst)e(ar)-20 b(gument)233 +b(to)e(e)-28 b(v)-17 b(ery)233 b(callback)h(is)c(a)i(pointer)f(to)h(a)f +Fo(fusd)p 45008 6112 333 45 v 399 w(file)p 48063 6112 +V 400 w(info)863 7440 y Fn(structure.)331 b(This)240 +b(structure)g(contains)i(information)f(that)f(can)i(be)f(useful)f(to)g +(dri)-28 b(v)-17 b(er)241 b(implementers)g(in)g(deciding)h(ho)-28 +b(w)241 b(to)g(respond)863 8769 y(to)277 b(a)g(system)g(call)g +(request.)2524 10761 y(The)h(\002elds)f(of)g Fo(fusd)p +11118 10761 V 399 w(file)p 14173 10761 V 399 w(info)h +Fn(structures)e(f)-11 b(all)277 b(into)g(se)-28 b(v)-17 +b(eral)278 b(cate)-17 b(gories:)2524 13639 y Fg(\017)554 +b Fk(Read-only)-61 b(.)345 b Fn(The)278 b(dri)-28 b(v)-17 +b(er)278 b(can)g(inspect)g(the)f(v)-28 b(alue,)279 b(b)-22 +b(ut)277 b(changing)j(it)c(will)g(ha)-22 b(v)-17 b(e)279 +b(no)f(ef)-28 b(fect.)4959 15853 y Fl(\226)554 b Fo(pid)p +8124 15853 V 399 w(t)664 b(pid)p Fn(:)344 b(The)278 b(process)f(ID)g +(of)g(the)g(process)g(making)i(the)f(request)4959 17624 +y Fl(\226)554 b Fo(uid)p 8124 17624 V 399 w(t)664 b(uid)p +Fn(:)344 b(The)278 b(user)f(ID)f(of)h(the)g(o)-28 b(wner)279 +b(of)e(the)g(process)h(making)g(the)g(request)4959 19396 +y Fl(\226)554 b Fo(gid)p 8124 19396 V 399 w(t)664 b(gid)p +Fn(:)344 b(The)278 b(group)g(ID)f(of)f(the)i(o)-28 b(wner)278 +b(of)f(the)g(process)h(making)g(the)g(request)2524 21610 +y Fg(\017)554 b Fk(Read-write)-17 b(.)332 b Fn(An)-17 +b(y)243 b(changes)h(to)d(the)h(v)-28 b(alue)243 b(will)e(be)h(propag)-6 +b(ated)245 b(back)e(to)e(the)h(k)-11 b(ernel)242 b(and)h(be)f(written)f +(to)g(the)h(appropriate)3631 22938 y(in-k)-11 b(ernel)277 +b(structure.)4959 25152 y Fl(\226)554 b Fo(unsigned)665 +b(int)g(flags)p Fn(:)482 b(A)345 b(cop)-11 b(y)348 b(of)d(the)i +Fo(f)p 26137 25152 V 398 w(flags)g Fn(\002eld)f(in)g(the)g(k)-11 +b(ernel')-61 b(s)347 b Fo(file)f Fn(structure.)549 b(The)347 +b(\003ags)6066 26480 y(are)277 b(an)h(or')-55 b(d-together)278 +b(set)e(of)h(the)g(k)-11 b(ernel')-61 b(s)278 b Fo(O)p +23913 26480 V 675 w Fn(series)e(of)h(\003ags:)344 b Fo(O)p +31990 26480 V 399 w(NONBLOCK)p Fn(,)278 b Fo(O)p 38920 +26480 V 398 w(APPEND)p Fn(,)g Fo(O)p 44521 26480 V 398 +w(SYNC)p Fn(,)g(etc.)4959 28251 y Fl(\226)554 b Fo(void)665 +b(*device)p 14101 28251 V 399 w(info)p Fn(:)409 b(The)311 +b(data)f(passed)g(to)g Fo(fusd)p 29144 28251 V 399 w(register)h +Fn(when)f(the)g(de)-28 b(vice)312 b(w)-11 b(as)309 b(re)-17 +b(gistered;)327 b(see)6066 29580 y(Section)278 b(5.1)g(for)e(details) +4959 31351 y Fl(\226)554 b Fo(void)665 b(*private)p 14765 +31351 V 400 w(data)p Fn(:)423 b(A)316 b(generic)i(per)-22 +b(-\002le-descriptor)318 b(pointer)f(usable)h(by)f(the)g(dri)-28 +b(v)-17 b(er)318 b(for)e(its)f(o)-28 b(wn)318 b(pur)-22 +b(-)6066 32679 y(poses,)383 b(such)363 b(as)f(to)g(k)-11 +b(eep)363 b(state)f(\(or)f(a)h(pointer)h(to)f(state\))f(that)h(should)h +(be)g(maintained)h(between)g(operations)f(on)6066 34007 +y(the)395 b(same)g(instance)h(of)e(an)i(open)g(\002le.)696 +b(It)394 b(is)g(guaranteed)j(to)e(be)g(NULL)h(when)g(the)f(\002le)g(is) +e(\002rst)h(opened.)699 b(See)6066 35336 y(Section)278 +b(5.2)g(for)e(more)i(details.)2524 37550 y Fg(\017)554 +b Fk(Hidden)299 b(\002elds.)406 b Fn(The)299 b(dri)-28 +b(v)-17 b(er)299 b(should)f(not)h(touch)g(these)f(\002elds)h(\(such)f +(as)f Fo(fd)p Fn(\).)406 b(The)-17 b(y)300 b(contain)f(state)f(used)g +(by)h(the)f(FUSD)3631 38878 y(library)276 b(to)h(generate)i(the)f +(reply)f(sent)g(to)g(the)h(k)-11 b(ernel.)2524 41756 +y Fl(Important)273 b(note:)342 b Fn(the)272 b(v)-28 b(alue)275 +b(of)d(the)h Fo(fusd)p 20262 41756 V 399 w(file)p 23317 +41756 V 399 w(info)g Fn(pointer)g(itself)e(has)i Fk(no)g(meaning)p +Fn(.)344 b(Repeated)275 b(requests)d(on)i(the)863 43085 +y(same)287 b(\002le)g(descriptor)f Fk(will)g(not)h Fn(generate)h +(callbacks)g(with)e(identical)h Fo(fusd)p 31000 43085 +V 400 w(file)p 34056 43085 V 399 w(info)f Fn(pointer)h(v)-28 +b(alues,)290 b(as)c(w)-11 b(ould)288 b(be)f(the)863 44413 +y(case)281 b(with)e(an)h(in-k)-11 b(ernel)281 b(dri)-28 +b(v)-17 b(er)-61 b(.)352 b(In)279 b(other)h(w)-11 b(ords,)280 +b(if)f(a)h(dri)-28 b(v)-17 b(er)280 b(needs)h(to)e(k)-11 +b(eep)282 b(state)d(in)g(between)j(successi)-28 b(v)-17 +b(e)282 b(system)d(calls)g(on)863 45741 y(a)333 b(user')-61 +b(s)331 b(\002le)i(descriptor)-44 b(,)345 b(it)332 b +Fk(must)g Fn(store)g(that)g(state)g(using)g(the)h Fo(private)p +30689 45741 V 400 w(data)f Fn(\002eld.)510 b(The)333 +b Fo(fusd)p 41540 45741 V 399 w(file)p 44595 45741 V +400 w(info)f Fn(pointer)863 47070 y(itself)276 b(is)g(ephemeral;)j(the) +e(data)h(to)f(which)h(it)e(points)i(is)e(persistent.)2524 +49062 y(Program)282 b(3)f(sho)-28 b(ws)282 b(an)g(e)-17 +b(xample)284 b(of)d(ho)-28 b(w)283 b(a)e(dri)-28 b(v)-17 +b(er)282 b(might)g(mak)-11 b(e)283 b(use)e(of)g(the)h(data)g(in)f(the)h +Fo(fusd)p 40577 49062 V 399 w(file)p 43632 49062 V 400 +w(info)f Fn(structure.)863 50390 y(Much)333 b(of)f(the)g(dri)-28 +b(v)-17 b(er)333 b(is)d(identical)j(to)f(hello)-28 b(w)-11 +b(orld.c.)509 b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)348 +b(instead)332 b(of)g(printing)g(a)g(static)f(greeting,)347 +b(this)331 b(ne)-28 b(w)333 b(program)863 51719 y(generates)273 +b(a)f(custom)g(message)h(each)g(time)e(the)h(de)-28 b(vice)273 +b(\002le)f(is)f(read,)i(as)e(seen)h(on)h(line)e(25.)342 +b(The)273 b(message)f(contains)h(the)f(PID)f(of)863 53047 +y(the)278 b(user)e(process)i(that)f(requested)i(the)e(read)h(\()p +Fo(file->pid)p Fn(\).)2524 55040 y(In)360 b(addition,)383 +b(Program)362 b(3')-61 b(s)360 b Fo(open)i Fn(callback)g(does)g(not)f +(return)g(0)g(\(success\))g(unconditionally)j(as)c(it)g(did)h(in)g +(Program)h(1.)863 56368 y(Instead,)339 b(it)326 b(checks)i(\(on)e(line) +h(7\))f(to)g(mak)-11 b(e)328 b(sure)e(the)h(UID)f(of)g(the)h(process)f +(trying)h(to)f(read)h(from)f(the)h(de)-28 b(vice)328 +b(\()p Fo(file->uid)p Fn(\))863 57696 y(matches)271 b(the)f(UID)g +(under)h(which)g(the)f(dri)-28 b(v)-17 b(er)270 b(itself)f(is)f +(running)k(\()p Fo(getuid\(\))p Fn(\).)341 b(If)268 b(the)-17 +b(y)271 b(don')-20 b(t)271 b(match,)h(-EPERM)e(is)f(returned.)863 +59025 y(In)354 b(other)g(w)-11 b(ords,)373 b(only)355 +b(the)f(user)g(who)h(ran)f(the)g(dri)-28 b(v)-17 b(er)355 +b(is)e(allo)-28 b(wed)355 b(to)f(read)h(from)e(the)i(de)-28 +b(vice)356 b(that)e(it)f(creates.)574 b(If)353 b(an)-17 +b(y)355 b(other)863 60353 y(user)-22 b(\227including)279 +b(root!\227tries)d(to)h(open)h(it,)e(a)h(\223Permission)h(denied\224)h +(error)e(will)f(be)i(generated.)863 64186 y Fj(5.1)1329 +b(Registration)333 b(of)f(Multiple)g(De)-20 b(vices,)332 +b(and)g(P)-13 b(assing)331 b(Data)h(to)h(Callbacks)863 +66926 y Fn(De)-28 b(vice)264 b(dri)-28 b(v)-17 b(ers)263 +b(frequently)g(e)-17 b(xpose)264 b(se)-28 b(v)-17 b(eral)264 +b(dif)-28 b(ferent)262 b(\223\003a)-22 b(v)g(ors\224)264 +b(of)e(a)g(de)-28 b(vice.)340 b(F)-17 b(or)263 b(e)-17 +b(xample,)267 b(a)c(single)f(magnetic)i(tape)f(dri)-28 +b(v)-17 b(e)863 68254 y(will)256 b(often)i(ha)-22 b(v)-17 +b(e)259 b(man)-17 b(y)259 b(dif)-28 b(ferent)257 b(de)-28 +b(vice)259 b(\002les)f(in)f Fo(/dev)p Fn(.)336 b(Each)259 +b(de)-28 b(vice)259 b(\002le)f(represents)f(a)g(dif)-28 +b(ferent)258 b(combination)h(of)e(options)863 69582 y(such)278 +b(as)f(re)-28 b(wind/no-re)g(wind,)279 b(or)e(compressed/uncompressed.) +347 b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)280 b(the)-17 +b(y)278 b(access)g(the)f(same)h(ph)-6 b(ysical)278 b(tape)g(dri)-28 +b(v)-17 b(e.)25405 74071 y(14)p eop +%%Page: 15 18 +15 17 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(3)d Fn(uid-\002lter)-61 b(.c:)344 b(Inspecting)278 +b(data)g(in)f Fo(fusd)p 22294 2940 333 45 v 399 w(file)p +25349 2940 V 399 w(info)h Fn(such)f(as)g(UID)g(and)h(PID)f(of)g(the)g +(calling)h(process)p 863 3445 50191 45 v 365 4400 a Fi(1)1661 +b Fo(int)664 b(do_open\(struct)j(fusd_file_info)g(*file\))2524 +5728 y({)3852 7057 y(/*)d(If)h(the)g(UID)f(of)h(the)g(process)g(trying) +g(to)g(do)f(the)h(read)g(doesn't)g(match)g(the)4516 8385 +y(*)f(UID)h(of)g(the)f(owner)h(of)g(the)g(driver,)g(return)g(-EPERM.) +1330 b(If)664 b(you)h(run)g(this)365 9714 y Fi(5)3653 +b Fo(*)664 b(driver)i(as)e(a)h(normal)g(user,)g(even)g(root)g(won't)g +(be)f(able)h(to)g(read)g(from)f(the)4516 11042 y(*)g(device)i(file)f +(created!)g(*/)3852 12370 y(if)f(\(file->uid)i(!=)f(getuid\(\)\))5180 +13699 y(return)h(-EPERM;)-133 16355 y Fi(10)2989 b Fo(return)665 +b(0;)2524 17684 y(})2524 20340 y(int)f(do_read\(struct)j +(fusd_file_info)g(*file,)e(char)g(*user_buffer,)10494 +21669 y(size_t)g(user_length,)h(loff_t)f(*offset\))-133 +22997 y Fi(15)1661 b Fo({)3852 24325 y(char)665 b(buf[128];)3852 +25654 y(int)g(len;)3852 28310 y(/*)f(The)h(first)g(read)g(to)g(the)f +(device)i(returns)f(a)f(greeting.)1330 b(The)665 b(second)g(read)-133 +29639 y Fi(20)3653 b Fo(*)664 b(returns)i(EOF.)f(*/)3852 +30967 y(if)f(\(*offset)i(!=)f(0\))5180 32296 y(return)h(0;)3852 +34952 y(/*)e(len)h(gets)g(set)g(to)f(the)h(number)g(of)g(characters)h +(written)f(to)g(buf)f(*/)-133 36281 y Fi(25)2989 b Fo(len)665 +b(=)f(sprintf\(buf,)i("Your)f(PID)g(is)g(\045d.)1328 +b(Have)665 b(a)g(nice)g(day.\\n",)g(file->pid\);)3852 +38937 y(/*)f(NEVER)i(return)f(more)g(data)g(than)f(the)h(user)g(asked)g +(for)g(*/)3852 40266 y(if)f(\(user_length)j(<)d(len\))5180 +41594 y(len)h(=)f(user_length;)-133 42922 y Fi(30)3852 +44251 y Fo(memcpy\(user_buffer,)j(buf,)e(len\);)3852 +45579 y(*offset)g(+=)g(len;)3852 46907 y(return)g(len;)2524 +48236 y(})p 863 49730 V 2524 53051 a Fn(T)-39 b(raditionally)-72 +b(,)252 b(the)246 b(de)-28 b(vice)247 b(\002le')-61 b(s)245 +b Fk(minor)h(number)g Fn(w)-11 b(as)245 b(used)h(to)f(communicate)j +(the)e(desired)g(options)f(with)g(de)-28 b(vice)248 b(dri)-28 +b(v)-17 b(ers.)863 54379 y(But,)367 b(since)350 b(de)-28 +b(vfs)350 b(dynamically)i(\(and)e(unpredictably\))i(generates)e(both)g +(major)g(and)g(minor)g(numbers)g(e)-28 b(v)-17 b(ery)351 +b(time)e(a)h(de)-28 b(vice)863 55708 y(is)298 b(re)-17 +b(gistered,)305 b(a)299 b(dif)-28 b(ferent)300 b(technique)h(w)-11 +b(as)299 b(de)-28 b(v)-17 b(eloped.)413 b(When)300 b(using)g(de)-28 +b(vfs,)305 b(dri)-28 b(v)-17 b(ers)299 b(are)g(allo)-28 +b(wed)301 b(to)e(associate)h(a)f(v)-28 b(alue)301 b(\(of)863 +57036 y(type)278 b Fo(void)665 b(*)p Fn(\))276 b(with)h(each)i(de)-28 +b(vice)279 b(the)-17 b(y)279 b(re)-17 b(gister)-61 b(.)343 +b(This)277 b(f)-11 b(acility)276 b(tak)-11 b(es)278 b(the)f(place)h(of) +f(the)h(minor)f(number)-61 b(.)2524 59029 y(The)302 b(de)-28 +b(vfs)302 b(solution)g(is)f(also)g(used)i(by)f(FUSD.)g(The)h +(mysterious)e(third)g(ar)-20 b(gument)304 b(to)d Fo(fusd)p +39277 59029 333 45 v 399 w(register)i Fn(that)f(we)f(men-)863 +60357 y(tioned)309 b(in)g(Section)g(4.1)g(is)e(an)i(arbitrary)f(piece)i +(of)e(data)h(that)f(can)i(be)f(passed)g(to)f(FUSD)h(when)h(a)e(de)-28 +b(vice)310 b(is)e(re)-17 b(gistered.)437 b(Later)-44 +b(,)863 61685 y(when)378 b(a)e(callback)j(is)c(acti)-28 +b(v)g(ated,)403 b(the)377 b(contents)g(of)g(that)f(ar)-20 +b(gument)378 b(are)f(a)-22 b(v)-28 b(ailable)378 b(in)e(the)h +Fo(device)p 41033 61685 V 399 w(info)g Fn(member)g(of)g(the)863 +63014 y Fo(fusd)p 3585 63014 V 399 w(file)p 6640 63014 +V 400 w(info)277 b Fn(structure.)2524 65006 y(Program)213 +b(4)f(sho)-28 b(ws)212 b(an)h(e)-17 b(xample)215 b(of)c(this)h +(technique,)227 b(inspired)212 b(by)h(Alessandro)g(Rubini')-61 +b(s)212 b(similar)f(de)-28 b(vfs)213 b(tutorial)e(published)863 +66335 y(in)321 b(Linux)h(Mag)-6 b(azine)9366 65933 y +Ff(10)10199 66335 y Fn(.)475 b(It)320 b(creates)h(a)g(number)i(of)d(de) +-28 b(vices)323 b(in)e(the)g Fo(/dev/drums)h Fn(directory)-72 +b(,)333 b(each)322 b(of)f(which)h(is)e(useful)h(for)863 +67663 y(generating)345 b(a)e(dif)-28 b(ferent)343 b(kind)g(of)f +(\223sound\224\227)p Fo(/dev/drums/bam)p Fn(,)364 b Fo(/dev/drums/boom) +p Fn(,)d(and)344 b(so)e(on.)541 b(Reading)344 b(from)p +863 68611 20076 45 v 1738 69352 a Fe(10)2457 69664 y +Fd(http://www)-58 b(.linux.it/k)-9 b(erneldocs/de)-22 +b(vfs/)25405 74071 y Fn(15)p eop +%%Page: 16 19 +16 18 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(4)d Fn(drums.c:)344 b(P)-17 b(assing)277 b(pri)-28 +b(v)g(ate)279 b(data)f(to)f Fo(fusd)p 23298 2940 333 +45 v 399 w(register)h Fn(and)g(retrie)-28 b(ving)278 +b(it)e(from)h Fo(device)p 43020 2940 V 400 w(info)p 863 +3445 50191 45 v 365 4400 a Fi(1)1661 b Fo(static)665 +b(char)g(*drums_strings[])i(=)d({"bam",)h("bum",)h("beat",)f("boom",) +23777 5728 y("bang",)h("crash",)f(NULL};)2524 8385 y(int)f +(drums_read\(struct)j(fusd_file_info)g(*file,)e(char)g(*user_buffer,) +365 9714 y Fi(5)11623 b Fo(size_t)665 b(user_length,)i(loff_t)e +(*offset\))2524 11042 y({)3852 12370 y(int)g(len;)3852 +13699 y(char)g(sound[128];)-133 16355 y Fi(10)2989 b +Fo(/*)664 b(file->device_info)k(is)c(what)h(we)g(passed)g(to)f +(fusd_register)j(when)e(we)4516 17684 y(*)f(registered)i(the)f(device)g +(*/)3852 19012 y(strcpy\(sound,)h(\(char)f(*\))g(file->device_info\);) +3852 20340 y(strcat\(sound,)h("\\n"\);)-133 22997 y Fi(15)2989 +b Fo(/*)664 b(1st)h(read)g(returns)g(the)g(sound;)g(2nd)g(returns)h +(EOF)e(*/)3852 24325 y(if)g(\(*offset)i(!=)f(0\))5180 +25654 y(return)h(0;)3852 28310 y(/*)e(NEVER)i(return)f(more)g(data)g +(than)f(the)h(user)g(asked)g(for)g(*/)-133 29639 y Fi(20)2989 +b Fo(len)665 b(=)f(MIN\(user_length,)j(strlen\(sound\)\);)3852 +30967 y(memcpy\(user_buffer,)g(sound,)f(len\);)3852 32296 +y(*offset)f(+=)g(len;)3852 33624 y(return)g(len;)2524 +34952 y(})-133 36281 y Fi(25)2524 37609 y Fo(int)f(main\(int)i(argc,)f +(char)g(*argv[]\))2524 38937 y({)3852 40266 y(int)g(i;)3852 +41594 y(char)g(buf[128];)-133 42922 y Fi(30)3852 44251 +y Fo(for)g(\(i)f(=)h(0;)f(drums_strings[i])j(!=)e(NULL;)g(i++\))g({) +5180 45579 y(sprintf\(buf,)i("/dev/drums/\045s",)g(drums_strings[i]\);) +5180 46907 y(if)e(\(fusd_register\(buf,)i(0666,)e(drums_strings[i],)j +(&drums_fops\))e(<)e(0\))6509 48236 y(fprintf\(stderr,)i("\045s)f +(register)h(failed:)f(\045m\\n",)g(drums_strings[i]\);)-133 +49564 y Fi(35)2989 b Fo(})3852 52221 y(fprintf\(stderr,)667 +b("calling)e(fusd_run...\\n"\);)3852 53549 y(fusd_run\(\);)3852 +54878 y(return)g(0;)-133 56206 y Fi(40)1661 b Fo(})p +863 57700 V 863 61021 a Fn(an)-17 b(y)279 b(of)e(these)g(de)-28 +b(vices)279 b(will)d(return)h(a)g(string)g(equal)h(to)f(the)g(de)-28 +b(vice')-61 b(s)279 b(name.)2524 63014 y(The)313 b(\002rst)f(thing)i +(to)f(notice)g(about)i Fo(drums.c)e Fn(is)f(that)h(it)f(re)-17 +b(gisters)312 b(more)i(than)f(one)h(FUSD)g(de)-28 b(vice.)453 +b(In)313 b(the)g(loop)g(starting)863 64342 y(in)407 b(line)g(31,)440 +b(it)406 b(calls)h Fo(fusd)p 12201 64342 333 45 v 399 +w(register\(\))h Fn(once)h(for)d(e)-28 b(v)-17 b(ery)409 +b(de)-28 b(vice)409 b(named)g(in)e Fo(drums)p 37877 64342 +V 399 w(strings)h Fn(on)g(line)f(1.)733 b(When)863 65670 +y Fo(fusd)p 3585 65670 V 399 w(run\(\))371 b Fn(is)e(called,)393 +b(it)369 b(automatically)j(w)-11 b(atches)371 b(e)-28 +b(v)-17 b(ery)372 b(de)-28 b(vice)372 b(the)e(dri)-28 +b(v)-17 b(er)370 b(re)-17 b(gistered,)394 b(and)371 b(acti)-28 +b(v)g(ates)371 b(the)f(callbacks)863 66999 y(associated)376 +b(with)f(each)i(de)-28 b(vice)377 b(as)e(needed.)639 +b(Although)377 b Fo(drums.c)f Fn(uses)f(the)g(same)h(set)e(of)h +(callbacks)h(for)f(e)-28 b(v)-17 b(ery)377 b(de)-28 b(vice)377 +b(it)863 68327 y(re)-17 b(gisters)387 b(\(as)f(can)i(be)g(seen)g(on)g +(line)f(33\),)414 b(each)389 b(de)-28 b(vice)389 b(could)g(ha)-22 +b(v)-17 b(e)389 b(dif)-28 b(ferent)387 b(callbacks)h(if)f(desired.)673 +b(\(Not)387 b(sho)-28 b(wn)389 b(is)d(the)863 69655 y(initialization) +278 b(of)e Fo(drums)p 11321 69655 V 400 w(fops)p Fn(,)h(which)h +(assigns)f Fo(drums)p 24708 69655 V 399 w(read)h Fn(to)f(be)g(the)h +Fo(read)f Fn(callback.\))25405 74071 y(16)p eop +%%Page: 17 20 +17 19 bop 2524 2974 a Fn(If)239 b Fo(drums)p 6887 2974 +333 45 v 400 w(read)i Fn(is)f(called)i(for)f(all)f(6)h(types)h(of)f +(drums,)248 b(ho)-28 b(w)242 b(does)g(it)e(kno)-28 b(w)242 +b(which)g(de)-28 b(vice)243 b(it')-61 b(s)240 b(supposed)j(to)e(be)g +(servicing)863 4302 y(when)220 b(it)e(gets)g(called?)326 +b(The)219 b(answer)g(is)f(in)g(the)h(third)f(ar)-20 b(gument)221 +b(of)d Fo(fusd)p 29223 4302 V 399 w(register\(\))p Fn(,)231 +b(which)220 b(we)f(were)g(pre)-28 b(viously)220 b(ignor)-22 +b(-)863 5631 y(ing.)371 b(Whate)-28 b(v)-17 b(er)288 +b(v)-28 b(alue)288 b(is)d(passed)i(to)f Fo(fusd)p 18255 +5631 V 399 w(register\(\))i Fn(will)d(be)i(passed)g(back)h(to)e(the)g +(callback)i(in)e(the)h Fo(device)p 48063 5631 V 400 w(info)863 +6959 y Fn(\002eld)267 b(of)e(the)h Fo(fusd)p 8624 6959 +V 399 w(file)p 11679 6959 V 400 w(info)g Fn(structure.)339 +b(The)267 b(name)f(of)g(the)g(drum)g(sound)h(is)e(passed)h(to)g +Fo(fusd)p 40460 6959 V 399 w(register)h Fn(on)f(line)g(33,)863 +8287 y(and)278 b(later)f(retrie)-28 b(v)-17 b(ed)279 +b(by)e(the)h(dri)-28 b(v)-17 b(er)278 b(on)f(line)g(12.)2524 +10280 y(Although)406 b(this)e(e)-17 b(xample)407 b(uses)e(a)g(string)f +(as)h(its)e Fo(device)p 26212 10280 V 400 w(info)p Fn(,)437 +b(the)405 b(pointer)h(can)g(be)f(used)h(for)e(an)-17 +b(ything\227a)408 b(mode)863 11608 y(number)-44 b(,)278 +b(a)f(pointer)h(to)f(a)g(con\002guration)j(structure,)d(and)h(so)f(on.) +863 15441 y Fj(5.2)1329 b(The)331 b(differ)-24 b(ence)332 +b(between)e Fc(device)p 22228 15441 399 45 v 479 w(info)i +Fj(and)f Fc(private)p 34279 15441 V 479 w(data)863 18181 +y Fn(As)310 b(we)g(mentioned)i(in)e(Section)h(5,)318 +b(the)310 b Fo(fusd)p 19319 18181 333 45 v 399 w(file)p +22374 18181 V 400 w(info)g Fn(structure)g(has)g(tw)-11 +b(o)310 b(seemingly)h(similar)d(\002elds,)319 b(both)310 +b(of)g(which)863 19509 y(can)433 b(be)f(used)h(by)f(dri)-28 +b(v)-17 b(ers)432 b(to)g(store)f(their)g(o)-28 b(wn)433 +b(data:)653 b Fo(device)p 27267 19509 V 400 w(info)432 +b Fn(and)h Fo(private)p 37433 19509 V 400 w(data)p Fn(.)807 +b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)472 b(there)433 b(is)d(an)863 +20837 y(important)278 b(dif)-28 b(ference)278 b(between)h(them:)2524 +23937 y Fg(\017)554 b Fo(private)p 8345 23937 V 399 w(data)315 +b Fn(is)e(stored)i Fk(per)f(\002le)h(descriptor)p Fn(.)456 +b(If)313 b(20)i(processes)g(open)h(a)e(FUSD)h(de)-28 +b(vice)317 b(\(or)-44 b(,)323 b(one)315 b(process)g(opens)3631 +25265 y(a)350 b(FUSD)i(de)-28 b(vice)353 b(20)e(times\),)368 +b(each)353 b(of)d(those)h(20)h(\002le)f(descriptors)f(will)g(ha)-22 +b(v)-17 b(e)353 b(their)d(o)-28 b(wn)352 b(cop)-11 b(y)352 +b(of)f Fo(private)p 48063 25265 V 400 w(data)3631 26594 +y Fn(associated)260 b(with)g(them.)338 b(This)259 b(\002eld)h(is)f +(therefore)h(useful)f(to)h(dri)-28 b(v)-17 b(ers)260 +b(that)f(need)i(to)f(dif)-28 b(ferentiate)260 b(multiple)g(requests)f +(to)h(a)3631 27922 y(single)303 b(de)-28 b(vice)306 b(that)e(might)g +(be)g(serviced)h(in)e(parallel.)423 b(\(Note)304 b(that)g(most)f(UNIX)h +(v)-28 b(ariants,)310 b(including)c(Linux,)311 b(do)304 +b(allo)-28 b(w)3631 29250 y(multiple)306 b(processes)h(to)f(share)h(a)f +(single)g(\002le)h(descriptor)-22 b(\227speci\002cally)-72 +b(,)316 b(if)305 b(a)h(process)h Fo(open)p Fn(s)f(a)h(\002le,)313 +b(then)307 b Fo(fork)p Fn(s.)431 b(In)3631 30579 y(this)276 +b(case,)h(processes)h(will)e(also)h(share)g(a)h(single)f(cop)-11 +b(y)278 b(of)f Fo(private)p 31175 30579 V 400 w(data)p +Fn(.\))3631 32350 y(The)331 b(\002rst)f(time)g(a)g(FUSD)i(dri)-28 +b(v)-17 b(er)331 b(sees)f Fo(private)p 23831 32350 V +400 w(data)h Fn(\(in)f(the)h Fo(open)f Fn(callback\),)346 +b(it)329 b(is)h(guaranteed)j(to)d(be)h(NULL.)3631 33678 +y(An)-17 b(y)278 b(changes)h(to)e(it)f(by)i(a)f(dri)-28 +b(v)-17 b(er)278 b(callback)h(will)d(only)i(af)-28 b(fect)278 +b(the)f(state)g(associated)h(with)f(that)g(single)g(\002le)h +(descriptor)-61 b(.)2524 35892 y Fg(\017)554 b Fo(device)p +7681 35892 V 399 w(info)339 b Fn(is)f(k)-11 b(ept)339 +b Fk(per)g(de)-17 b(vice)p Fn(.)530 b(That)340 b(is,)352 +b Fk(all)339 b Fn(clients)f(of)h(a)f(de)-28 b(vice)341 +b(share)e(a)g Fk(single)g Fn(cop)-11 b(y)340 b(of)e Fo(device)p +47786 35892 V 400 w(info)p Fn(.)3631 37220 y(Unlik)-11 +b(e)440 b Fo(private)p 11786 37220 V 399 w(data)p Fn(,)480 +b(which)441 b(is)d(al)-11 b(w)g(ays)440 b(initialized)f(to)g(NULL,)h +Fo(device)p 37228 37220 V 400 w(info)f Fn(is)g(al)-11 +b(w)g(ays)439 b(initialized)h(to)3631 38549 y(whate)-28 +b(v)-17 b(er)349 b(v)-28 b(alue)350 b(the)d(dri)-28 b(v)-17 +b(er)349 b(passed)f(to)f Fo(fusd)p 22582 38549 V 400 +w(register)h Fn(as)g(described)h(in)e(the)h(pre)-28 b(vious)349 +b(section.)555 b(If)346 b(a)i(callback)3631 39877 y(changes)251 +b(the)e(cop)-11 b(y)251 b(of)e Fo(device)p 16657 39877 +V 399 w(info)h Fn(in)f(the)g Fo(fusd)p 25329 39877 V +399 w(file)p 28384 39877 V 399 w(info)h Fn(structure,)k(this)248 +b(has)i(no)f(ef)-28 b(fect;)259 b Fo(device)p 48063 39877 +V 400 w(info)3631 41205 y Fn(can)278 b(only)g(be)f(set)g(at)g(re)-17 +b(gistration)277 b(time,)g(with)g Fo(fusd)p 24384 41205 +V 399 w(register)p Fn(.)2524 44305 y(In)381 b(short,)408 +b Fo(device)p 10776 44305 V 400 w(info)382 b Fn(is)f(used)i(to)f(dif) +-28 b(ferentiate)382 b Fk(de)-17 b(vices)p Fn(.)660 b +Fo(private)p 33575 44305 V 400 w(data)382 b Fn(is)f(used)i(to)f(dif)-28 +b(ferentiate)383 b Fk(user)-11 b(s)381 b(of)863 45633 +y(those)278 b(de)-17 b(vices)p Fn(.)2524 47626 y(Program)267 +b(5,)h(drums2.c,)g(illustrates)d(the)h(dif)-28 b(ference)268 +b(between)g Fo(device)p 31251 47626 V 399 w(info)f Fn(and)g +Fo(private)p 41085 47626 V 400 w(data)p Fn(.)340 b(Lik)-11 +b(e)266 b(the)h(origi-)863 48954 y(nal)295 b(drums.c,)k(it)294 +b(creates)h(a)g(b)-22 b(unch)297 b(of)d(de)-28 b(vices)297 +b(in)d Fo(/dev/drums/)p Fn(,)301 b(each)296 b(of)f(which)g +(\223plays\224)i(a)d(dif)-28 b(ferent)295 b(sound.)398 +b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)863 50283 y(it)263 +b(also)h(does)h(something)g(ne)-28 b(w:)338 b(k)-11 b(eeps)265 +b(track)f(of)g(ho)-28 b(w)265 b(man)-17 b(y)266 b(times)d(each)j(de)-28 +b(vice)266 b(has)e(been)i(opened.)341 b(Ev)-17 b(ery)266 +b(read)e(to)g(an)-17 b(y)266 b(drum)863 51611 y(gi)-28 +b(v)-17 b(es)279 b(you)h(the)e(name)h(of)f(its)f(sound)i(as)f(well)g +(as)g(your)h(unique)g(\223user)g(number\224.)348 b(And,)279 +b(instead)g(of)e(returning)i(just)e(a)i(single)f(line)863 +52939 y(\(as)f(drums.c)g(did\),)g(it)f(will)g(k)-11 b(eep)279 +b(generating)g(more)e(\223sound\224)j(e)-28 b(v)-17 b(ery)279 +b(time)d(a)i Fo(read\(\))f Fn(system)g(call)g(arri)-28 +b(v)-17 b(es.)2524 54932 y(The)278 b(trick)e(is)g(that)i(we)f(w)-11 +b(ant)278 b(to)f(k)-11 b(eep)278 b(users)f(separate)h(from)e(each)j +(other)-61 b(.)344 b(F)-17 b(or)278 b(e)-17 b(xample,)279 +b(user)e(one)h(might)f(type:)863 57311 y Fo(\045)665 +b(more)f(/dev/drums/bam)863 58640 y(You)h(are)g(user)f(1)h(to)f(hear)h +(a)g(drum)f(go)h('bam'!)863 59968 y(You)g(are)g(user)f(1)h(to)f(hear)h +(a)g(drum)f(go)h('bam'!)863 61296 y(You)g(are)g(user)f(1)h(to)f(hear)h +(a)g(drum)f(go)h('bam'!)863 62625 y(...)2524 65483 y +Fn(Meanwhile,)279 b(another)g(user)f(in)f(a)h(dif)-28 +b(ferent)278 b(shell)f(might)h(type)h(the)f(same)g(command)i(at)d(the)h +(same)h(time,)e(and)i(get)f(dif)-28 b(ferent)863 66811 +y(results:)25405 74071 y(17)p eop +%%Page: 18 21 +18 20 bop 863 3187 50191 89 v 863 4164 a Fl(Pr)-20 b(ogram)280 +b(5)d Fn(drums2.c:)344 b(Using)277 b(both)h Fo(device)p +20148 4164 333 45 v 400 w(info)f Fn(and)h Fo(private)p +30004 4164 V 400 w(data)p 863 4669 50191 45 v 365 5624 +a Fi(1)1661 b Fo(struct)665 b(drum_info)h({)3852 6953 +y(char)f(*name;)3852 8281 y(int)g(num_users;)2524 9609 +y(})f(drums[])h(=)g({)365 10938 y Fi(5)2989 b Fo({)664 +b("bam",)i(0)e(},)3852 12266 y({)g("bum",)i(0)e(},)3852 +13594 y(/*)g(...)h(*/)3852 14923 y({)f(NULL,)h(0)g(})2524 +16251 y(};)-133 17579 y Fi(10)2524 18908 y Fo(int)f(drums_open\(struct) +j(fusd_file_info)g(*file\))2524 20236 y({)3852 21564 +y(/*)d(file->device_info)k(is)c(what)h(we)g(passed)g(to)f +(fusd_register)j(when)e(we)4516 22893 y(*)f(registered)i(the)f(device.) +1330 b(It's)665 b(a)f(pointer)h(into)g(the)g("drums")g(struct.)h(*/) +-133 24221 y Fi(15)2989 b Fo(struct)665 b(drum_info)h(*d)e(=)h +(\(struct)g(drum_info)h(*\))f(file->device_info;)3852 +26878 y(/*)f(Store)i(this)e(user's)i(unique)f(user)g(number)g(in)g +(their)g(private_data)h(*/)3852 28206 y(file->private_data)h(=)e +(\(void)g(*\))f(++\(d->num_users\);)-133 30863 y Fi(20)2989 +b Fo(return)665 b(0;)g(/*)f(return)h(success)h(*/)2524 +32191 y(})2524 34848 y(int)e(drums_read\(struct)j(fusd_file_info)g +(*file,)e(char)g(*user_buffer,)12486 36176 y(size_t)g(user_length,)i +(loff_t)e(*offset\))-133 37505 y Fi(25)1661 b Fo({)3852 +38833 y(struct)665 b(drum_info)h(*d)e(=)h(\(struct)g(drum_info)h(*\))f +(file->device_info;)3852 40161 y(int)g(len;)3852 41490 +y(char)g(sound[128];)-133 44146 y Fi(30)2989 b Fo(sprintf\(sound,)667 +b("You)d(are)h(user)g(\045d)g(to)f(hear)h(a)f(drum)h(go)g +('\045s'!\\n",)9165 45475 y(\(int\))g(file->private_data,)j(d->name\);) +3852 48131 y(len)d(=)f(MIN\(user_length,)j(strlen\(sound\)\);)3852 +49460 y(memcpy\(user_buffer,)g(sound,)f(len\);)-133 50788 +y Fi(35)2989 b Fo(return)665 b(len;)2524 52116 y(})2524 +54773 y(int)f(main\(int)i(argc,)f(char)g(*argv[]\))2524 +56102 y({)-133 57430 y Fi(40)2989 b Fo(struct)665 b(drum_info)h(*d;) +3852 58758 y(char)f(buf[128];)3852 61415 y(for)g(\(d)f(=)h(drums;)g +(d->name)g(!=)g(NULL;)g(d++\))g({)5180 62743 y(sprintf\(buf,)i +("/dev/drums/\045s",)g(d->name\);)-133 64072 y Fi(45)4317 +b Fo(if)665 b(\(fusd_register\(buf,)i(0666,)e(d,)g(&drums_fops\))h(<)f +(0\))6509 65400 y(fprintf\(stderr,)h("\045s)f(register)h(failed:)f +(\045m\\n",)g(d->name\);)3852 66728 y(})3852 68057 y(/*)f(...)h(*/)p +863 69518 V 25405 74071 a Fn(18)p eop +%%Page: 19 22 +19 21 bop 863 3896 a Fo(\045)665 b(more)f(/dev/drums/bam)863 +5224 y(You)h(are)g(user)f(2)h(to)f(hear)h(a)g(drum)f(go)h('bam'!)863 +6553 y(You)g(are)g(user)f(2)h(to)f(hear)h(a)g(drum)f(go)h('bam'!)863 +7881 y(You)g(are)g(user)f(2)h(to)f(hear)h(a)g(drum)f(go)h('bam'!)863 +9209 y(...)2524 12068 y Fn(The)287 b(idea)f(is)f(that)i(no)f(matter)g +(ho)-28 b(w)287 b(long)g(those)g(tw)-11 b(o)286 b(users)f(go)i(on)g +(reading)g(their)f(de)-28 b(vices,)289 b(the)e(dri)-28 +b(v)-17 b(er)287 b(al)-11 b(w)g(ays)286 b(generates)i(a)863 +13396 y(message)278 b(that)f(is)f(speci\002c)j(to)e(that)g(user)-61 +b(.)343 b(The)278 b(tw)-11 b(o)277 b(users')f(data)i(are)g(not)f +(intermingled.)2524 15388 y(T)-89 b(o)313 b(implement)g(this,)320 +b(Program)313 b(5)g(introduces)g(a)f(ne)-28 b(w)314 b +Fo(drum)p 26788 15388 333 45 v 399 w(info)f Fn(structure)f(\(lines)f +(1-4\),)321 b(which)313 b(k)-11 b(eeps)313 b(track)g(of)f(both)863 +16717 y(the)421 b(drum')-61 b(s)420 b(name,)457 b(and)421 +b(the)g(number)h(of)e(time)g(each)i(drum)f(de)-28 b(vice)422 +b(has)e(been)i(opened.)776 b(An)420 b(instance)i(of)e(this)f +(structure,)863 18045 y Fo(drums)p Fn(,)393 b(is)369 +b(initialized)h(on)g(lines)f(4-8.)622 b(Note)370 b(that)g(the)g(call)f +(to)h Fo(fusd)p 29261 18045 V 399 w(register)h Fn(\(line)e(45\))h(no) +-28 b(w)371 b(passes)e(a)h(pointer)g(to)g(a)863 19373 +y Fo(drum)p 3585 19373 V 399 w(info)258 b Fn(structure.)336 +b(\(This)257 b Fo(drum)p 16634 19373 V 399 w(info)665 +b(*)257 b Fn(pointer)h(is)e(shared)i(by)g(e)-28 b(v)-17 +b(ery)259 b(instance)g(of)e(a)g(client)g(that)h(opens)g(a)f(particular) +863 20702 y(type)278 b(of)f(drum.\))2524 22694 y(Each)413 +b(time)g(a)f(drum)h(de)-28 b(vice)414 b(is)e(opened,)448 +b(its)411 b Fo(drum)p 23704 22694 V 400 w(info)h Fn(structure)g(is)g +(retrie)-28 b(v)-17 b(ed)414 b(from)e Fo(device)p 43458 +22694 V 399 w(info)h Fn(\(line)f(15\).)863 24023 y(Then,)266 +b(on)c(line)f(18,)k(the)c Fo(num)p 12287 24023 V 399 +w(users)h Fn(\002eld)g(is)e(incremented)k(and)e(the)f(ne)-28 +b(w)263 b(user)e(number)h(is)f(stored)g(in)g Fo(fusd)p +44270 24023 V 399 w(file)p 47325 24023 V 399 w(info)p +Fn(')-61 b(s)863 25351 y Fo(private)p 5577 25351 V 400 +w(data)308 b Fn(\002eld.)434 b(T)-89 b(o)308 b(reiterate)g(our)f +(earlier)g(point:)404 b Fo(device)p 28888 25351 V 400 +w(info)308 b Fk(contains)g(information)g(global)g(to)g(all)e(user)-11 +b(s)307 b(of)863 26679 y(a)277 b(de)-17 b(vice)-11 b(,)279 +b(while)f Fo(private)p 12436 26679 V 400 w(data)f Fk(has)g(information) +h(speci\002c)h(to)e(a)g(particular)g(user)g(of)g(the)h(de)-17 +b(vice)g(.)2524 28672 y Fn(It')-61 b(s)413 b(also)i(w)-11 +b(orthwhile)416 b(to)f(note)h(that)g(when)g(we)g(increment)g +Fo(num)p 29087 28672 V 399 w(users)g Fn(on)g(line)f(18,)450 +b(a)416 b(simple)f Fo(num)p 44918 28672 V 399 w(users++)h +Fn(is)863 30000 y(correct.)478 b(If)321 b(this)g(w)-11 +b(as)321 b(a)h(dri)-28 b(v)-17 b(er)323 b(inside)f(the)g(k)-11 +b(ernel,)334 b(we')-55 b(d)321 b(ha)-22 b(v)-17 b(e)324 +b(to)e(use)g(something)h(lik)-11 b(e)322 b Fo(atomic)p +40226 30000 V 399 w(inc\(\))h Fn(because)g(a)f(plain)863 +31329 y Fo(i++)301 b Fn(is)f(not)h(atomic.)415 b(Such)303 +b(a)e(non-atomic)h(statement)g(will)e(result)g(in)h(a)g(race)g +(condition)i(on)e(SMP)h(platforms,)k(if)300 b(an)h(interrupt)863 +32657 y(handler)328 b(also)e(touches)h Fo(num)p 12383 +32657 V 399 w(users)p Fn(,)339 b(or)326 b(in)g(some)h(future)f(Linux)h +(k)-11 b(ernel)327 b(that)g(is)e(preempti)-28 b(v)-17 +b(e.)493 b(Since)327 b(this)f(FUSD)h(dri)-28 b(v)-17 +b(er)327 b(is)863 33985 y(just)276 b(a)i(plain,)f(single-threaded)i +(user)-22 b(-space)278 b(application,)h(good)f(old)g +Fo(++)f Fn(still)e(w)-11 b(orks.)863 38385 y Fm(6)1594 +b(Writing)399 b Fa(ioctl)h Fm(Callbacks)863 41524 y Fn(The)302 +b(POSIX)f(API)g(pro)-17 b(vides)302 b(for)e(a)h(function)h(called)f +Fo(ioctl)p Fn(,)307 b(which)302 b(allo)-28 b(ws)301 b +(\223out-of-band\224)i(con\002guration)h(information)d(to)863 +42852 y(be)e(passed)g(to)f(a)g(de)-28 b(vice)301 b(dri)-28 +b(v)-17 b(er)299 b(through)g(a)g(\002le)f(descriptor)-61 +b(.)407 b(Using)299 b(FUSD,)g(you)g(can)g(write)f(a)g(de)-28 +b(vice)301 b(dri)-28 b(v)-17 b(er)299 b(with)f(a)g(callback)863 +44180 y(to)282 b(handle)i Fo(ioctl)f Fn(requests)f(from)g(clients.)358 +b(F)-17 b(or)283 b(the)g(most)f(part,)h(it')-61 b(s)280 +b(just)i(lik)-11 b(e)282 b(writing)g(a)g(callback)i(for)e +Fo(read)g Fn(or)g Fo(write)p Fn(,)i(as)863 45509 y(we')-55 +b(v)-17 b(e)264 b(seen)f(in)f(pre)-28 b(vious)264 b(sections.)339 +b(From)263 b(the)g(client')-61 b(s)262 b(point)h(of)f(vie)-28 +b(w)-72 b(,)267 b Fo(ioctl)c Fn(traditionally)g(tak)-11 +b(es)263 b(three)g(ar)-20 b(guments:)337 b(a)263 b(\002le)863 +46837 y(descriptor)-44 b(,)277 b(a)g(command)j(number)-44 +b(,)278 b(and)g(a)f(pointer)h(to)f(an)-17 b(y)278 b(additional)h(data)f +(that)f(might)g(be)h(required)g(for)f(the)g(command.)863 +50670 y Fj(6.1)1329 b(Using)332 b(macr)-24 b(os)331 b(to)i(generate)e +Fc(ioctl)h Fj(command)f(numbers)863 53410 y Fn(The)300 +b(Linux)h(header)g(\002le)e Fo(/usr/include/asm/ioctl.h)k +Fn(de\002nes)e(macros)f(that)f Fk(must)g Fn(be)h(used)g(to)f(create)h +(the)f Fo(ioctl)863 54738 y Fn(command)280 b(number)-61 +b(.)344 b(These)279 b(macros)e(tak)-11 b(e)278 b(v)-28 +b(arious)278 b(combinations)h(of)e(three)g(ar)-20 b(guments:)2524 +57838 y Fg(\017)554 b Fo(type)p Fn(\227an)431 b(8-bit)e(inte)-17 +b(ger)431 b(selected)g(to)f(be)g(speci\002c)h(to)f(the)g(de)-28 +b(vice)432 b(dri)-28 b(v)-17 b(er)-61 b(.)803 b Fo(type)430 +b Fn(should)h(be)f(chosen)h(so)f(as)g(not)3631 59166 +y(to)371 b(con\003ict)i(with)e(other)h(dri)-28 b(v)-17 +b(ers)372 b(that)f(might)h(be)g(\223listening\224)h(to)e(the)h(same)g +(\002le)f(descriptor)-61 b(.)627 b(\(Inside)371 b(the)h(k)-11 +b(ernel,)396 b(for)3631 60494 y(e)-17 b(xample,)292 b(the)c(TCP)h(and)f +(IP)g(stacks)g(use)f(distinct)h(numbers)g(since)h(an)f +Fo(ioctl)g Fn(sent)g(to)f(a)h(sock)-11 b(et)289 b(\002le)f(descriptor)g +(might)3631 61823 y(be)277 b(e)-17 b(xamined)280 b(by)e(both)g +(stacks.\))2524 64036 y Fg(\017)554 b Fo(number)p Fn(\227an)241 +b(8-bit)f(inte)-17 b(ger)241 b(\223command)h(number)-61 +b(.)-77 b(\224)333 b(W)-44 b(ithin)239 b(a)h(dri)-28 +b(v)-17 b(er)-44 b(,)248 b(distinct)239 b(numbers)i(should)g(be)g +(chosen)g(for)e(each)3631 65365 y(dif)-28 b(ferent)277 +b(kind)h(of)f Fo(ioctl)g Fn(command)j(that)d(the)g(dri)-28 +b(v)-17 b(er)278 b(services.)2524 67579 y Fg(\017)554 +b Fo(data)p 6353 67579 V 399 w(type)p Fn(\227The)292 +b(name)f(of)f(a)g(type)h(used)g(to)f(compute)i(ho)-28 +b(w)291 b(man)-17 b(y)292 b(bytes)f(are)f(e)-17 b(xchanged)295 +b(between)d(the)e(client)h(and)3631 68907 y(the)277 b(dri)-28 +b(v)-17 b(er)-61 b(.)344 b(This)277 b(ar)-20 b(gument)279 +b(is,)d(for)g(e)-17 b(xample,)279 b(the)f(name)g(of)f(a)g(structure.) +25405 74071 y(19)p eop +%%Page: 20 23 +20 22 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(6)d Fn(ioctl.h:)343 b(Using)278 b(the)p 14258 2940 +333 45 v 675 w Fo(IO)g Fn(macros)f(to)g(generate)i Fo(ioctl)f +Fn(command)h(numbers)p 863 3445 50191 45 v 365 4400 a +Fi(1)1661 b Fo(/*)664 b(definition)i(of)f(the)f(structure)i(exchanged)g +(between)f(client)g(and)g(server)g(*/)2524 5728 y(struct)g +(ioctl_data_t)h({)3852 7057 y(char)f(string1[60];)3852 +8385 y(char)g(string2[60];)365 9714 y Fi(5)1661 b Fo(};)2524 +12370 y(#define)665 b(IOCTL_APP_TYPE)i(71)d(/*)h(arbitrary)g(number)h +(unique)f(to)f(this)h(app)g(*/)2524 15027 y(#define)g(IOCTL_TEST2)h +(_IO\(IOCTL_APP_TYPE,)i(2\))c(/*)h(int)f(argument)i(*/)-133 +16355 y Fi(10)1661 b Fo(#define)665 b(IOCTL_TEST3)h +(_IOR\(IOCTL_APP_TYPE,)i(3,)c(struct)i(ioctl_data_t\))2524 +17684 y(#define)f(IOCTL_TEST4)h(_IOW\(IOCTL_APP_TYPE,)i(4,)c(struct)i +(ioctl_data_t\))2524 19012 y(#define)f(IOCTL_TEST5)h +(_IOWR\(IOCTL_APP_TYPE,)i(5,)d(struct)g(ioctl_data_t\))p +863 20524 V 2524 23606 a Fn(The)278 b(macros)f(used)h(to)f(generate)i +(command)g(numbers)g(are:)2524 26407 y Fg(\017)p 3697 +26407 333 45 v 952 w Fo(IO\(int)665 b(type,)g(int)g(number\))318 +b Fn(\226)f(used)h(for)e(a)h(simple)g(ioctl)f(that)h(sends)h(nothing)g +(b)-22 b(ut)317 b(the)g(type)h(and)g(number)-44 b(,)3631 +27736 y(and)278 b(recei)-28 b(v)-17 b(es)279 b(back)f(nothing)h(b)-22 +b(ut)277 b(an)h(\(inte)-17 b(ger\))277 b(retv)-28 b(al.)2524 +29830 y Fg(\017)p 3697 29830 V 952 w Fo(IOR\(int)665 +b(type,)h(int)e(number,)i(data)p 24020 29830 V 399 w(type\))401 +b Fn(\226)f(used)h(for)e(an)i(ioctl)f(that)g(reads)g(data)h +Fk(fr)-50 b(om)400 b Fn(the)h(de)-28 b(vice)3631 31159 +y(dri)g(v)-17 b(er)-61 b(.)344 b(The)278 b(dri)-28 b(v)-17 +b(er)278 b(will)e(be)h(allo)-28 b(wed)279 b(to)e(return)g +Fo(sizeof\(data)p 30165 31159 V 401 w(type\))g Fn(bytes)h(to)f(the)g +(user)-61 b(.)2524 33253 y Fg(\017)p 3697 33253 V 952 +w Fo(IOW\(int)665 b(type,)h(int)e(number,)i(data)p 24020 +33253 V 399 w(type\))241 b Fn(\226)f(similar)f(to)p 33189 +33253 V 638 w(IOR,)h(b)-22 b(ut)240 b(used)h(to)f(write)g(data)h +Fk(to)f Fn(the)g(dri)-28 b(v)-17 b(er)-61 b(.)2524 35348 +y Fg(\017)p 3697 35348 V 952 w Fo(IORW\(int)666 b(type,)f(int)f +(number,)i(data)p 24684 35348 V 399 w(type\))267 b Fn(\226)g(a)f +(combination)j(of)p 37237 35348 V 665 w Fo(IOR)e Fn(and)p +41759 35348 V 666 w Fo(IOW)p Fn(.)f(That)h(is,)h(data)f(is)3631 +36676 y(both)277 b(written)g(to)g(the)h(dri)-28 b(v)-17 +b(er)277 b(and)i(then)e(read)h(back)h(from)e(the)g(dri)-28 +b(v)-17 b(er)278 b(by)g(the)f(client.)2524 39478 y(Program)322 +b(6)f(is)f(an)h(e)-17 b(xample)324 b(header)f(\002le)e(sho)-28 +b(wing)322 b(the)g(use)f(of)g(these)g(macros.)476 b(In)321 +b(real)g(programs,)332 b(the)321 b(client)h(e)-17 b(x)g(ecuting)863 +40806 y(an)278 b(ioctl)f(and)h(the)f(dri)-28 b(v)-17 +b(er)278 b(that)f(services)h(it)e(must)g(share)i(the)f(same)h(header)h +(\002le.)863 44585 y Fj(6.2)1329 b(Example)332 b(client)g(calls)g(and)f +(dri)-13 b(v)g(er)331 b(callbacks)863 47325 y Fn(Program)268 +b(7)f(sho)-28 b(ws)268 b(a)f(client)g(program)h(that)f(e)-17 +b(x)g(ecutes)270 b Fo(ioctl)p Fn(s)d(using)g(the)h(ioctl)e(command)k +(numbers)e(de\002ned)h(in)e(Program)h(6.)863 48653 y(The)236 +b Fo(ioctl)p 6205 48653 V 399 w(data)p 9260 48653 V 400 +w(t)e Fn(is)g(application-speci\002c;)252 b(our)236 b(simple)e(test)h +(program)h(de\002nes)g(it)e(as)h(a)g(structure)g(containing)i(tw)-11 +b(o)235 b(arrays)863 49981 y(of)266 b(characters.)340 +b(The)267 b(\002rst)e Fo(ioctl)h Fn(call)g(\(line)g(10\))g(sends)g(the) +g(command)i Fo(IOCTL)p 32974 49981 V 400 w(TEST3)p Fn(,)g(which)f +(retrie)-28 b(v)-17 b(es)266 b(strings)f Fk(fr)-50 b(om)266 +b Fn(the)863 51310 y(dri)-28 b(v)-17 b(er)-61 b(.)344 +b(The)278 b(second)h Fo(ioctl)f Fn(uses)f(the)g(command)j +Fo(IOCTL)p 24809 51310 V 399 w(TEST4)e Fn(\(line)e(18\),)h(which)i +(sends)e(strings)f Fk(to)h Fn(the)g(dri)-28 b(v)-17 b(er)-61 +b(.)2524 53302 y(The)278 b(portion)f(of)g(the)h(FUSD)g(dri)-28 +b(v)-17 b(er)278 b(that)f(services)g(these)g(calls)g(is)f(sho)-28 +b(wn)279 b(in)e(Program)h(8.)2524 55295 y(The)337 b(ioctl)g(e)-17 +b(xample)339 b(header)g(\002le)e(and)h(test)e(programs)h(sho)-28 +b(wn)339 b(in)d(this)g(document)k(\(Programs)d(6,)351 +b(7,)h(and)338 b(8\))f(are)g(actually)863 56623 y(contained)f(in)d(a)g +(lar)-20 b(ger)-44 b(,)347 b(single)333 b(e)-17 b(xample)336 +b(program)e(included)h(in)e(the)h(FUSD)g(distrib)-22 +b(ution)333 b(called)h Fo(ioctl.c)p Fn(.)512 b(That)334 +b(source)863 57952 y(code)279 b(sho)-28 b(ws)277 b(other)h(v)-28 +b(ariations)278 b(on)f(calling)h(and)g(servicing)g Fo(ioctl)g +Fn(commands.)863 62298 y Fm(7)1594 b(Integrating)399 +b(FUSD)f(W)-29 b(ith)399 b(Y)-177 b(our)398 b(A)-40 b(pplication)400 +b(Using)f Fa(fusd)p 40051 62298 479 45 v 575 w(dispatch\(\))863 +65436 y Fn(The)228 b(e)-17 b(xample)229 b(applications)g(we')-55 +b(v)-17 b(e)228 b(seen)f(so)g(f)-11 b(ar)226 b(ha)-22 +b(v)-17 b(e)229 b(something)f(in)f(common:)320 b(after)227 +b(initialization)g(and)h(de)-28 b(vice)229 b(re)-17 b(gistration,)863 +66765 y(the)g(y)300 b(call)f Fo(fusd)p 7670 66765 333 +45 v 399 w(run\(\))p Fn(.)408 b(This)298 b(gi)-28 b(v)-17 +b(es)300 b(up)f(control)g(of)g(the)g(program')-61 b(s)299 +b(\003o)-28 b(w)-72 b(,)304 b(turning)c(it)d(o)-17 b(v)g(er)300 +b(to)f(the)g(FUSD)g(library)g(instead.)863 68093 y(This)234 +b(w)-11 b(ork)g(ed)236 b(\002ne)f(for)e(our)i(simple)f(e)-17 +b(xample)236 b(programs,)243 b(b)-22 b(ut)235 b(doesn')-20 +b(t)234 b(w)-11 b(ork)235 b(in)f(a)g(real)g(program)h(that)g(needs)g +(to)f(w)-11 b(ait)234 b(for)f(e)-28 b(v)-17 b(ents)863 +69421 y(other)316 b(than)h(FUSD)g(callbacks.)460 b(F)-17 +b(or)317 b(this)e(reason,)325 b(our)316 b(frame)-28 b(w)-11 +b(ork)317 b(pro)-17 b(vides)317 b(another)g(w)-11 b(ay)317 +b(to)f(acti)-28 b(v)g(ate)317 b(callbacks)g(that)f(does)863 +70750 y(not)278 b(require)f(the)h(dri)-28 b(v)-17 b(er)277 +b(to)g(gi)-28 b(v)-17 b(e)279 b(up)f(control)f(of)g(its)f +Fo(main\(\))p Fn(.)25405 74071 y(20)p eop +%%Page: 21 24 +21 23 bop 863 1955 50191 89 v 863 2932 a Fl(Pr)-20 b(ogram)280 +b(7)d Fn(ioctl-client.c:)344 b(A)276 b(program)j(that)e(mak)-11 +b(es)278 b Fo(ioctl)f Fn(requests)g(on)h(a)f(\002le)h(descriptor)p +863 3437 50191 45 v 365 4392 a Fi(1)4317 b Fo(int)665 +b(fd,)g(ret;)5180 5721 y(struct)h(ioctl_data_t)g(d;)5180 +8377 y(if)f(\(\(fd)g(=)f(open\("/dev/ioctltest",)k(O_RDWR\)\))e(<)e +(0\))h({)365 9706 y Fi(5)5646 b Fo(perror\("client:)666 +b(can't)g(open)e(ioctltest"\);)6509 11034 y(exit\(1\);)5180 +12363 y(})5180 15019 y(/*)h(test3:)g(make)g(sure)g(we)f(can)h(get)g +(data)g(FROM)g(a)f(driver)h(using)g(ioctl)g(*/)-133 16348 +y Fi(10)4317 b Fo(ret)665 b(=)f(ioctl\(fd,)i(IOCTL_TEST3,)g(&d\);)5180 +17676 y(printf\("ioctl)h(test3:)e(got)g(retval=\045d\\n",)h(ret\);)5180 +19004 y(printf\("ioctl)h(test3:)e(got)g(string1='\045s'\\n",)i +(d.string1\);)5180 20333 y(printf\("ioctl)g(test3:)e(got)g +(string2='\045s'\\n",)i(d.string2\);)-133 22989 y Fi(15)4317 +b Fo(/*)665 b(test4:)g(make)g(sure)g(we)f(can)h(send)g(data)g(TO)f(a)h +(driver)g(using)g(an)g(ioctl)g(*/)5180 24318 y(sprintf\(d.string1,)j +(TEST4_STRING1\);)5180 25646 y(sprintf\(d.string2,)g(TEST4_STRING2\);) +5180 26974 y(ret)d(=)f(ioctl\(fd,)i(IOCTL_TEST4,)g(&d\);)p +863 28486 V 863 31807 a Fj(7.1)1329 b(Using)332 b Fc(fusd)p +10700 31807 399 45 v 478 w(dispatch\(\))863 34547 y Fn(Recall)443 +b(from)g(Section)g(4.1)g(that)g Fo(fusd)p 17141 34547 +333 45 v 399 w(register)h Fn(returns)e(a)g Fk(\002le)h(descriptor)g +Fn(for)f(e)-28 b(v)-17 b(ery)444 b(de)-28 b(vice)445 +b(that)d(is)g(successfully)863 35875 y(re)-17 b(gistered.)357 +b(This)281 b(\002le)h(descriptor)f(can)i(be)f(used)g(to)f(acti)-28 +b(v)g(ate)283 b(de)-28 b(vice)284 b(callbacks)f(\223manually)-72 +b(,)-77 b(\224)284 b(without)e(passing)g(control)g(of)f(the)863 +37203 y(application)256 b(to)f Fo(fusd)p 9874 37203 V +399 w(run\(\))p Fn(.)336 b(Whene)-28 b(v)-17 b(er)257 +b(the)e(\002le)g(descriptor)f(becomes)j(readable)f(according)g(to)f +Fo(select\(2\))p Fn(,)260 b(it)253 b(should)863 38532 +y(be)258 b(passed)g(to)g Fo(fusd)p 9214 38532 V 399 w(dispatch\(\))p +Fn(,)k(which)d(in)e(turn)g(will)g(acti)-28 b(v)g(ate)259 +b(callbacks)g(in)e(the)h(same)g(w)-11 b(ay)258 b(that)f +Fo(fusd)p 44836 38532 V 400 w(run\(\))g Fn(does.)863 +39860 y(In)277 b(other)h(w)-11 b(ords,)276 b(an)i(application)h(can:) +2247 42738 y(1.)554 b(Sa)-22 b(v)-17 b(e)278 b(the)g(\002le)f +(descriptors)g(returned)h(by)g Fo(fusd)p 22546 42738 +V 399 w(register\(\))p Fn(;)2247 44952 y(2.)554 b(Add)263 +b(those)f(FUSD)h(\002le)g(descriptors)f(to)g(an)h Fo(fd)p +22108 44952 V 398 w(set)g Fn(that)f(is)f(passed)i(to)f +Fo(select)p Fn(,)k(along)d(with)f(an)-17 b(y)264 b(other)e(\002le)h +(descrip-)3631 46280 y(tors)276 b(that)h(might)g(be)h(interesting)f(to) +g(the)h(application;)g(and)2247 48494 y(3.)554 b(P)-17 +b(ass)277 b(e)-28 b(v)-17 b(ery)279 b(FUSD)f(\002le)f(descriptor)h +(that)f Fo(select)h Fn(indicates)g(is)e(readable)j(to)e +Fo(fusd)p 37363 48494 V 399 w(dispatch)p Fn(.)2524 51372 +y Fo(fusd)p 5246 51372 V 399 w(dispatch\(\))247 b Fn(returns)f(0)g(if)f +(at)g(least)h(one)h(callback)h(w)-11 b(as)246 b(successfully)g(acti)-28 +b(v)g(ated.)335 b(On)247 b(error)-44 b(,)251 b(-1)245 +b(is)g(returned)i(with)863 52701 y Fo(errno)261 b Fn(set)e +(appropriately)-72 b(.)340 b Fo(fusd)p 15100 52701 V +399 w(dispatch\(\))262 b Fn(will)d(ne)-28 b(v)-17 b(er)262 +b(block\227if)f(no)f(messages)h(are)g(a)-22 b(v)-28 b(ailable)262 +b(from)d(the)i(k)-11 b(ernel,)264 b(it)863 54029 y(will)276 +b(return)h(-1)g(with)g Fo(errno)h Fn(set)e(to)h Fo(EAGAIN)p +Fn(.)863 57862 y Fj(7.2)1329 b(Helper)332 b(Functions)e(f)-33 +b(or)332 b(Constructing)g(an)g Fc(fd)p 27226 57862 399 +45 v 478 w(set)863 60602 y Fn(The)305 b(FUSD)f(library)g(pro)-17 +b(vides)305 b(tw)-11 b(o)304 b(\(optional\))g(utility)f(functions)h +(that)g(can)g(mak)-11 b(e)305 b(it)e(easier)h(to)f(write)g +(applications)j(that)d(inte-)863 61930 y(grate)278 b(FUSD)g(into)f +(their)g(o)-28 b(wn)278 b Fo(select\(\))g Fn(loops.)344 +b(Speci\002cally:)2524 64808 y Fg(\017)554 b Fo(void)664 +b(fusd)p 9673 64808 333 45 v 400 w(fdset)p 13393 64808 +V 399 w(add\(fd)p 17776 64808 V 400 w(set)g(*set,)h(int)g(*max\))p +Fn(\227is)361 b(meant)h(to)e(help)i(construct)g(an)f +Fo(fd)p 46707 64808 V 399 w(set)g Fn(that)3631 66136 +y(will)347 b(be)i(passed)g(as)f(the)g(\223readable)j(fds\224)d(set)f +(to)h(select.)557 b(This)348 b(function)i(adds)e(the)h(\002le)g +(descriptors)f(of)g(all)f(pre)-28 b(viously)3631 67465 +y(re)-17 b(gistered)317 b(FUSD)g(de)-28 b(vices)318 b(to)e(the)h(fd)p +18882 67465 V 398 w(set)f Fo(set)p Fn(.)461 b(It)315 +b(assumes)i(that)f Fo(set)h Fn(has)f(already)i(been)g(initialized)e(by) +h(the)g(caller)-61 b(.)3631 68793 y(The)282 b(inte)-17 +b(ger)282 b Fo(max)f Fn(is)f(updated)k(to)d(re\003ect)h(the)f(lar)-20 +b(gest)281 b(\002le)h(descriptor)f(number)i(in)e(the)g(set.)355 +b Fo(max)282 b Fn(is)e(not)h(changed)j(if)d(the)3631 +70121 y(v)-28 b(alue)278 b(passed)g(to)f Fo(fusd)p 13365 +70121 V 399 w(fdset)p 17084 70121 V 400 w(add)g Fn(is)f(already)i(lar) +-20 b(ger)278 b(than)g(the)f(lar)-20 b(gest)277 b(FUSD)h(\002le)f +(descriptor)h(added)h(to)e(the)g(set.)25405 74071 y(21)p +eop +%%Page: 22 25 +22 24 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(8)d Fn(ioctl-serv)-17 b(er)-61 b(.c:)344 b(A)277 b(dri)-28 +b(v)-17 b(er)278 b(that)f(handles)h Fo(ioctl)g Fn(requests)p +863 3445 50191 45 v 365 4400 a Fi(1)1661 b Fo(/*)664 +b(This)h(function)h(is)e(run)h(by)f(the)h(driver)g(*/)2524 +5728 y(int)f(do_ioctl\(struct)j(fusd_file_info)g(*file,)e(int)g(cmd,)g +(void)f(*arg\))2524 7057 y({)3852 8385 y(struct)h(ioctl_data_t)h(*d;) +365 9714 y Fi(5)3852 11042 y Fo(if)e(\(_IOC_TYPE\(cmd\))j(!=)e +(IOCTL_APP_TYPE\))5180 12370 y(return)h(0;)3852 15027 +y(switch)f(\(cmd\))g({)-133 16355 y Fi(10)2989 b Fo(case)665 +b(IOCTL_TEST3:)h(/*)f(returns)g(data)g(to)f(the)h(client)g(*/)5180 +17684 y(d)g(=)f(arg;)5180 19012 y(strcpy\(d->string1,)k +(TEST3_STRING1\);)5180 20340 y(strcpy\(d->string2,)g(TEST3_STRING2\);) +5180 21669 y(return)e(0;)-133 22997 y Fi(15)4317 b Fo(break;)3852 +25654 y(case)665 b(IOCTL_TEST4:)h(/*)f(gets)g(data)f(from)h(the)g +(client)g(*/)5180 26982 y(d)g(=)f(arg;)5180 28310 y(printf\("ioctl)j +(server:)e(test4,)g(string1:)h(got)f('\045s'\\n",)g(d->string1\);)-133 +29639 y Fi(20)4317 b Fo(printf\("ioctl)667 b(server:)e(test4,)g +(string2:)h(got)f('\045s'\\n",)g(d->string2\);)5180 30967 +y(return)h(0;)5180 32296 y(break;)3852 33624 y(default:)5180 +34952 y(printf\("ioctl)h(server:)e(got)g(unknown)g(cmd,)g(sigh,)g(this) +g(is)g(broken\\n"\);)-133 36281 y Fi(25)4317 b Fo(return)666 +b(-EINVAL;)5180 37609 y(break;)3852 38937 y(})3852 41594 +y(return)f(0;)-133 42922 y Fi(30)1661 b Fo(})p 863 44417 +V 2524 47738 a Fg(\017)554 b Fo(void)664 b(fusd)p 9673 +47738 333 45 v 400 w(dispatch)p 15385 47738 V 400 w(fdset\(fd)p +21097 47738 V 399 w(set)h(*set\))p Fn(\227is)220 b(meant)h(to)f(be)g +(called)h(on)g(the)f Fo(fd)p 41899 47738 V 399 w(set)g +Fn(that)g(is)f Fk(r)-41 b(eturned)3631 49066 y Fn(by)357 +b(select.)583 b(It)356 b(assumes)h(that)g Fo(set)g Fn(contains)h(a)g +(set)e(\002le)h(descriptors)g(that)g Fo(select\(\))h +Fn(has)f(indicated)i(are)e(readable.)3631 50394 y Fo(fusd)p +6353 50394 V 399 w(dispatch)p 12064 50394 V 400 w(fdset\(\))409 +b Fn(calls)g Fo(fusd)p 22615 50394 V 399 w(dispatch)h +Fn(on)f(e)-28 b(v)-17 b(ery)411 b(descriptor)e(in)g Fo(set)g +Fn(that)g(is)e(a)i(v)-28 b(alid)410 b(FUSD)3631 51723 +y(descriptor)-61 b(.)343 b(Non-FUSD)279 b(descriptors)e(in)g +Fo(set)g Fn(are)h(ignored.)2524 54601 y(The)g(e)-17 b(xcerpt)279 +b(of)d Fo(drums3.c)i Fn(sho)-28 b(wn)279 b(in)e(Program)h(9)f +(demonstrates)h(the)f(use)h(of)f(these)g(helper)h(functions.)344 +b(This)277 b(program)863 55929 y(is)271 b(similar)g(to)h(the)g(earlier) +g(drums.c)g(e)-17 b(xample:)343 b(it)271 b(creates)i(a)f(number)h(of)f +(musical)h(instruments)e(such)i(as)f Fo(/dev/drums/bam)863 +57257 y Fn(and)469 b Fo(/dev/drums/boom)p Fn(.)919 b(Ho)-28 +b(we)g(v)-17 b(er)-44 b(,)518 b(in)468 b(addition)h(to)f(servicing)h +(its)e(musical)h(callbacks,)517 b(the)469 b(dri)-28 b(v)-17 +b(er)468 b(also)g(prints)g(a)863 58586 y(prompt)379 b(to)g(standard)g +(input)g(asking)g(ho)-28 b(w)380 b(\223loud\224)g(the)f(drums)f(should) +i(be.)648 b(Instead)379 b(of)f(turning)h(control)g(of)f +Fo(main\(\))h Fn(o)-17 b(v)g(er)863 59914 y(to)326 b +Fo(fusd)p 4772 59914 V 399 w(run\(\))h Fn(as)f(in)g(the)g(pre)-28 +b(vious)328 b(e)-17 b(xamples,)340 b Fo(drums3)327 b +Fn(uses)f Fo(select\(\))h Fn(to)f(simultaneously)i(w)-11 +b(atch)327 b(its)d(FUSD)k(\002le)863 61243 y(descriptors)277 +b(and)h(standard)g(input.)344 b(It)276 b(responds)i(to)f(input)h(from)e +(both)i(sources.)2524 63235 y(On)327 b(lines)f(2\2265,)341 +b(an)327 b Fo(fd)p 11662 63235 V 399 w(set)g Fn(and)h(its)e(associated) +i(\223max\224)h(v)-28 b(alue)328 b(are)g(initialized)f(to)g(contain)h +(stdin')-61 b(s)326 b(\002le)h(descriptor)-61 b(.)494 +b(On)863 64563 y(line)304 b(9,)310 b(we)304 b(use)g Fo(fusd)p +10062 64563 V 399 w(fdset)p 13781 64563 V 399 w(add)g +Fn(to)g(add)h(the)f(FUSD)g(\002le)g(descriptors)g(for)f(all)g(re)-17 +b(gistered)304 b(de)-28 b(vices.)425 b(\(Not)303 b(sho)-28 +b(wn)305 b(in)f(this)863 65892 y(e)-17 b(xcerpt)356 b(is)d(the)i(de)-28 +b(vice)356 b(re)-17 b(gistration,)373 b(which)355 b(is)e(the)i(same)f +(as)g(the)h(re)-17 b(gistration)354 b(code)i(we)e(sa)-17 +b(w)355 b(in)f Fo(drums.c)p Fn(.\))575 b(On)354 b(line)g(13)863 +67220 y(we)i(call)f(select,)375 b(which)356 b(blocks)g(until)f(one)i +(of)e(the)g(fd')-61 b(s)355 b(in)g(the)h(set)e(is)h(readable.)579 +b(On)356 b(lines)f(17)h(and)g(18,)375 b(we)356 b(check)h(to)e(see)h(if) +863 68548 y(standard)249 b(input)g(is)e(readable;)259 +b(if)247 b(so,)253 b(a)248 b(function)i(is)d(called)i(which)g(reads)f +(the)g(user')-61 b(s)248 b(response)g(from)g(standard)h(input)g(and)g +(prints)863 69877 y(a)256 b(ne)-28 b(w)257 b(prompt.)337 +b(Finally)-72 b(,)261 b(on)c(line)f(21,)k(we)c(call)g +Fo(fusd)p 22139 69877 V 400 w(dispatch)p 27851 69877 +V 400 w(fdset)p Fn(,)k(which)d(in)f(turn)g(will)f(acti)-28 +b(v)g(ate)258 b(the)e(callbacks)i(for)25405 74071 y(22)p +eop +%%Page: 23 26 +23 25 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(9)d Fn(drums3.c:)344 b(W)-89 b(aiting)278 b(for)e(both)i(FUSD)g(and)g +(non-FUSD)i(e)-28 b(v)-17 b(ents)278 b(in)f(a)g Fo(select)h +Fn(loop)p 863 3445 50191 45 v 365 4400 a Fi(1)2989 b +Fo(/*)664 b(initialize)i(the)f(set)g(*/)3852 5728 y(FD_ZERO\(&fds\);) +3852 8385 y(/*)f(add)h(stdin)g(to)g(the)f(set)h(*/)365 +9714 y Fi(5)2989 b Fo(FD_SET\(STDIN_FILENO,)668 b(&fds\);)3852 +11042 y(max)d(=)f(STDIN_FILENO;)3852 13699 y(/*)g(add)h(all)g(FUSD)g +(fds)f(to)h(the)g(set)f(*/)3852 15027 y(fusd_fdset_add\(&fds,)k +(&max\);)-133 16355 y Fi(10)3852 17684 y Fo(while)d(\(1\))g({)5180 +19012 y(tmp)g(=)f(fds;)5180 20340 y(if)h(\(select\(max+1,)h(&tmp,)g +(NULL,)f(NULL,)g(NULL\))g(<)f(0\))6509 21669 y(perror\("selecting"\);) +-133 22997 y Fi(15)4317 b Fo(else)665 b({)6509 24325 +y(/*)f(if)h(stdin)g(is)f(readable,)i(read)f(the)g(user's)g(response)g +(*/)6509 25654 y(if)f(\(FD_ISSET\(STDIN_FILENO,)k(&tmp\)\))7837 +26982 y(read_volume\(STDIN_FILENO\);)-133 29639 y Fi(20)5646 +b Fo(/*)664 b(call)h(any)g(FUSD)g(callbacks)g(that)g(have)g(messages)h +(waiting)f(*/)6509 30967 y(fusd_dispatch_fdset\(&tmp\);)5180 +32296 y(})3852 33624 y(})p 863 35118 V 863 38439 a Fn(de)-28 +b(vices)279 b(that)e(ha)-22 b(v)-17 b(e)279 b(pending)g(system)e(calls) +g(w)-11 b(aiting)277 b(to)g(be)h(serviced.)2524 40432 +y(It')-61 b(s)337 b(w)-11 b(orth)339 b(reiterating)g(that)g(dri)-28 +b(v)-17 b(ers)339 b(are)g(not)h(required)g(to)e(use)i(the)f(FUSD)h +(helper)f(functions)h Fo(fusd)p 43071 40432 333 45 v +399 w(fdset)p 46790 40432 V 400 w(add)f Fn(and)863 41760 +y Fo(fusd)p 3585 41760 V 399 w(dispatch)p 9296 41760 +V 400 w(fdset)p Fn(.)798 b(If)427 b(it')-61 b(s)427 b(more)i(con)-44 +b(v)-17 b(enient,)469 b(a)429 b(dri)-28 b(v)-17 b(er)429 +b(can)h(manually)g(sa)-22 b(v)-17 b(e)429 b(all)f(of)h(the)f(\002le)h +(descriptors)g(re-)863 43088 y(turned)282 b(by)h Fo(fusd)p +8083 43088 V 399 w(register)p Fn(,)g(construct)f(its)e(o)-28 +b(wn)283 b Fo(fd)p 23508 43088 V 399 w(set)p Fn(,)f(and)h(then)f(call)f +Fo(fusd)p 35060 43088 V 400 w(dispatch)h Fn(on)g(each)h(descriptor)f +(that)863 44417 y(is)415 b(readable.)760 b(This)415 b(method)i(is)d +(sometimes)i(required)g(for)f(inte)-17 b(gration)417 +b(with)e(other)h(frame)-28 b(w)-11 b(orks)416 b(that)f(w)-11 +b(ant)416 b(to)f(tak)-11 b(e)416 b(o)-17 b(v)g(er)863 +45745 y(your)425 b Fo(main\(\))p Fn(.)785 b(F)-17 b(or)424 +b(e)-17 b(xample,)463 b(the)425 b(GTK)f(user)g(interf)-11 +b(ace)425 b(frame)-28 b(w)-11 b(ork)30621 45343 y Ff(11)31876 +45745 y Fn(is)423 b(e)-28 b(v)-17 b(ent-dri)-28 b(v)-17 +b(en)428 b(and)d(requires)f(that)g(you)h(pass)863 47073 +y(control)371 b(of)g(your)g Fo(main)g Fn(to)f(it.)623 +b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)396 b(it)370 b(does)h(allo)-28 +b(w)371 b(you)h(to)f(gi)-28 b(v)-17 b(e)372 b(it)d(a)i(\002le)g +(descriptor)g(and)h(a)e(function)i(pointer)-44 b(,)394 +b(say-)863 48402 y(ing)385 b(\223Call)g(this)e(callback)j(when)g +Fo(select)f Fn(indicates)g(this)f(\002le)g(descriptor)h(has)g(become)h +(readable.)-77 b(\224)667 b(A)384 b(GTK)h(application)863 +49730 y(that)347 b(implements)g(FUSD)h(de)-28 b(vices)348 +b(can)g(w)-11 b(ork)347 b(by)g(gi)-28 b(ving)348 b(GTK)f(all)g(the)f +(FUSD)i(\002le)f(descriptors)g(indi)-28 b(vidually)-72 +b(,)365 b(and)348 b(calling)863 51059 y Fo(fusd)p 3585 +51059 V 399 w(dispatch\(\))279 b Fn(when)f(GTK)g(calls)f(the)g +(associated)h(callbacks.)863 55459 y Fm(8)1594 b(Implementing)399 +b(Blocking)g(System)f(Calls)863 58597 y Fn(All)359 b(of)h(the)g(e)-17 +b(xample)362 b(dri)-28 b(v)-17 b(ers)361 b(that)f(we')-55 +b(v)-17 b(e)361 b(seen)f(until)g(no)-28 b(w)361 b(ha)-22 +b(v)-17 b(e)362 b(had)f(an)f(important)g(feature)h(missing:)508 +b(the)-17 b(y)361 b(ne)-28 b(v)-17 b(er)362 b(had)f(to)863 +59925 y Fk(wait)330 b Fn(for)f(an)-17 b(ything.)504 b(So)331 +b(f)-11 b(ar)-44 b(,)342 b(a)330 b(dri)-28 b(v)-17 b(er')-61 +b(s)330 b(response)h(to)e(a)h(system)g(call)g(has)g(al)-11 +b(w)g(ays)331 b(been)g(immediately)g(a)-22 b(v)-28 b(ailable\227allo)g +(wing)863 61254 y(the)317 b(dri)-28 b(v)-17 b(er)318 +b(to)e(response)i(immediately)-72 b(.)464 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)329 b(real)316 b(de)-28 b(vices)319 b(are)e(often)g(not)g +(that)g(luck)-17 b(y:)424 b(the)-17 b(y)318 b(usually)g(ha)-22 +b(v)-17 b(e)318 b(to)f(w)-11 b(ait)317 b(for)863 62582 +y(something)302 b(to)e(happen)i(before)f(completing)h(a)f(client')-61 +b(s)299 b(system)h(call.)413 b(F)-17 b(or)301 b(e)-17 +b(xample,)308 b(a)300 b(dri)-28 b(v)-17 b(er)301 b(might)f(be)h(w)-11 +b(aiting)301 b(for)e(data)i(to)863 63910 y(arri)-28 b(v)-17 +b(e)278 b(from)f(the)g(serial)f(port)h(or)g(o)-17 b(v)g(er)279 +b(the)e(netw)-11 b(ork,)278 b(or)f(e)-28 b(v)-17 b(en)279 +b(w)-11 b(aiting)278 b(for)e(a)i(user)f(action.)2524 +65903 y(In)215 b(situations)h(lik)-11 b(e)216 b(this,)227 +b(a)216 b(basic)g(capability)h(most)f(de)-28 b(vice)218 +b(dri)-28 b(v)-17 b(ers)216 b(must)f(ha)-22 b(v)-17 b(e)218 +b(is)d(the)h(ability)g(to)g Fk(bloc)-22 b(k)217 b Fn(the)f(caller)-61 +b(.)323 b(Blocking)863 67231 y(operations)335 b(are)f(important)g +(because)i(the)-17 b(y)335 b(pro)-17 b(vide)336 b(a)e(simple)f(interf) +-11 b(ace)335 b(to)e(user)h(programs)g(that)g(does)h(\003o)-28 +b(w)335 b(control,)348 b(rather)863 68560 y(than)290 +b(something)h(more)f(e)-17 b(xpensi)-28 b(v)-17 b(e)293 +b(lik)-11 b(e)290 b(continuous)h(polling.)382 b(F)-17 +b(or)290 b(e)-17 b(xample,)294 b(user)c(programs)g(e)-17 +b(xpect)292 b(to)d(be)h(able)g(to)g(e)-17 b(x)g(ecute)p +863 69508 20076 45 v 1738 70248 a Fe(11)2457 70561 y +Fd(http://www)-58 b(.gtk.or)-16 b(g)25405 74071 y Fn(23)p +eop +%%Page: 24 27 +24 26 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(10)e Fn(console-read.c:)345 b(A)277 b(simple)g(blocking)i(system)e +(call)p 863 3445 50191 45 v 365 4400 a Fi(1)1661 b Fo(int)664 +b(do_read\(struct)j(fusd_file_info)g(*file,)e(char)g(*user_buffer,) +10494 5728 y(size_t)g(user_length,)h(loff_t)f(*offset\))2524 +7057 y({)3852 8385 y(char)g(buf[128];)365 9714 y Fi(5)3852 +11042 y Fo(if)f(\(*offset)i(>)e(0\))5180 12370 y(return)i(0;)3852 +15027 y(/*)e(print)i(a)e(prompt)h(*/)-133 16355 y Fi(10)2989 +b Fo(printf\("Got)666 b(a)e(read)h(from)g(pid)g(\045d.)1329 +b(What)665 b(do)f(we)h(say?\\n>)g(",)g(file->pid\);)3852 +17684 y(fflush\(stdout\);)3852 20340 y(/*)f(get)h(a)g(response)g(from)g +(the)g(console)g(*/)3852 21669 y(if)f(\(fgets\(buf,)j(sizeof\(buf\))f +(-)e(1,)h(stdin\))g(==)f(NULL\))-133 22997 y Fi(15)4317 +b Fo(return)666 b(0;)3852 25654 y(/*)e(compute)i(length)f(of)g(the)f +(response,)i(and)f(return)g(*/)3852 26982 y(user_length)h(=)e +(MIN\(user_length,)j(strlen\(buf\)\);)3852 28310 y +(memcpy\(user_buffer,)g(buf,)e(user_length\);)-133 29639 +y Fi(20)2989 b Fo(*offset)665 b(+=)g(user_length;)3852 +30967 y(return)g(user_length;)2524 32296 y(})p 863 33790 +V 863 37111 a Fn(a)388 b(statement)f(lik)-11 b(e)388 +b Fo(read\(fd,)665 b(buf,)g(sizeof\(buf\)\))p Fn(,)416 +b(and)389 b(e)-17 b(xpect)389 b(the)f(read)g(call)f(to)g(block)i +(\(stop)e(the)g(\003o)-28 b(w)389 b(of)e(the)863 38439 +y(calling)278 b(program\))g(until)f(data)g(is)g(a)-22 +b(v)-28 b(ailable.)345 b(This)277 b(is)f(much)i(simpler)f(and)h(more)f +(ef)-28 b(\002cient)279 b(than)f(polling)g(repeatedly)-72 +b(.)2524 40432 y(In)276 b(the)i(follo)-28 b(wing)278 +b(sections,)f(we')-11 b(ll)276 b(describe)i(ho)-28 b(w)279 +b(to)e(block)h(and)g(unblock)i(system)c(calls)h(for)g(de)-28 +b(vices)278 b(that)f(use)h(FUSD.)863 44265 y Fj(8.1)1329 +b(Blocking)332 b(the)g(caller)g(by)g(blocking)f(the)h(dri)-13 +b(v)g(er)863 47004 y Fn(The)326 b(easiest)e(\(b)-22 b(ut)324 +b(least)g(useful\))g(w)-11 b(ay)326 b(to)e(block)i(a)f(client')-61 +b(s)324 b(system)g(call)g(is)g(simply)g(to)h(block)g(the)g(dri)-28 +b(v)-17 b(er)-44 b(,)337 b(too.)486 b(F)-17 b(or)325 +b(e)-17 b(xample,)863 48333 y(consider)348 b(Program)g(10,)364 +b(which)348 b(implements)f(a)g(de)-28 b(vice)349 b(called)e +Fo(/dev/console-read)p Fn(.)555 b(Whene)-28 b(v)-17 b(er)350 +b(a)d(process)g(tries)e(to)863 49661 y(read)297 b(from)f(this)g(de)-28 +b(vice,)303 b(the)296 b(dri)-28 b(v)-17 b(er)297 b(prints)f(a)g(prompt) +h(to)f(standard)i(input,)j(asking)c(for)f(a)h(reply)-72 +b(.)401 b(\(The)297 b(prompt)g(appears)g(in)g(the)863 +50989 y(shell)286 b(the)h(dri)-28 b(v)-17 b(er)287 b(w)-11 +b(as)286 b(run)h(in,)h(not)f(the)g(shell)f(that')-61 +b(s)285 b(trying)i(to)f(read)h(from)f(the)h(de)-28 b(vice.\))373 +b(When)287 b(the)g(user)f(enters)h(a)f(line)h(of)f(te)-17 +b(xt,)863 52318 y(the)318 b(response)h(is)e(returned)i(to)e(the)i +(client)f(that)g(did)g(the)g(original)g Fo(read\(\))p +Fn(.)466 b(By)318 b(blocking)i(the)e(dri)-28 b(v)-17 +b(er)319 b(w)-11 b(aiting)318 b(for)g(the)g(reply)-72 +b(,)863 53646 y(the)278 b(client)f(that)g(issued)g(the)h(system)e(call) +i(is)e(block)-11 b(ed)279 b(as)e(well.)2524 55639 y(Blocking)341 +b(the)e(dri)-28 b(v)-17 b(er)340 b(this)e(w)-11 b(ay)340 +b(is)e(safe\227unlik)-11 b(e)341 b(programming)g(in)e(the)g(k)-11 +b(ernel)340 b(proper)-44 b(,)355 b(where)340 b(doing)g(something)h(lik) +-11 b(e)863 56967 y(this)372 b(w)-11 b(ould)374 b(block)f(the)g(entire) +g(system.)630 b(It')-61 b(s)371 b(also)h(easy)i(to)e(implement,)398 +b(as)372 b(seen)h(from)f(the)h(e)-17 b(xample)375 b(abo)-17 +b(v)g(e.)633 b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)399 b(it)863 +58295 y(mak)-11 b(es)284 b(the)f(dri)-28 b(v)-17 b(er)284 +b(unresponsi)-28 b(v)-17 b(e)286 b(to)c(system)h(call)g(requests)g +(that)g(might)g(be)h(coming)g(from)f(other)g(clients.)360 +b(If)282 b(another)j(process)863 59624 y(tries)310 b(to)g(do)i(an)-17 +b(ything)313 b(at)d(all)h(with)f(a)h(block)-11 b(ed)313 +b(dri)-28 b(v)-17 b(er')-61 b(s)311 b(de)-28 b(vice\227e)g(v)-17 +b(en)315 b(an)c Fo(open\(\))p Fn(\227it)g(will)f(block)i(until)f(the)g +(dri)-28 b(v)-17 b(er)311 b(w)-11 b(ak)g(es)863 60952 +y(up)303 b(ag)-6 b(ain.)421 b(This)302 b(limitation)g(mak)-11 +b(es)303 b(blocking)i(dri)-28 b(v)-17 b(ers)302 b(inappropriate)j(for)c +(an)-17 b(y)304 b(de)-28 b(vice)305 b(dri)-28 b(v)-17 +b(er)303 b(that)f(e)-17 b(xpects)304 b(to)f(service)f(more)863 +62280 y(than)278 b(one)g(client)g(at)f(a)g(time.)863 +66113 y Fj(8.2)1329 b(Blocking)332 b(the)g(caller)g(using)f +Fc(-FUSD)p 22235 66113 399 45 v 478 w(NOREPLY)p Fj(;)i(unblocking)d(it) +j(using)e Fc(fusd)p 43439 66113 V 479 w(return\(\))863 +68853 y Fn(If)314 b(a)i(de)-28 b(vice)317 b(dri)-28 b(v)-17 +b(er)316 b(e)-17 b(xpects)318 b(more)d(than)h(one)h(client)f(at)f(a)g +(time\227as)g(is)g(often)g(the)h(case\227a)h(slightly)e(dif)-28 +b(ferent)315 b(programming)863 70181 y(model)376 b(is)d(needed)k(for)d +(system)g(calls)g(that)g(can)i(potentially)f(block.)637 +b(Instead)374 b(of)h(blocking,)400 b(the)375 b(dri)-28 +b(v)-17 b(er)375 b(immediately)h(sends)25405 74071 y(24)p +eop +%%Page: 25 28 +25 27 bop 863 2974 a Fn(a)349 b(message)i(to)e(the)g(FUSD)h(frame)-28 +b(w)-11 b(ork)351 b(that)e(says,)367 b(in)349 b(essence,)368 +b(\223Don')-20 b(t)350 b(unblock)h(the)f(client)f(that)h(issued)f(this) +f(system)h(call,)863 4302 y(b)-22 b(ut)337 b(continue)i(sending)f +(additional)g(system)f(call)f(requests)h(that)g(might)g(be)g(coming)i +(from)d(other)h(clients.)-77 b(\224)522 b(Dri)-28 b(v)-17 +b(er)337 b(callbacks)863 5631 y(can)290 b(send)f(this)e(message)i(to)f +(FUSD)i(by)f(returning)g(the)f(special)h(v)-28 b(alue)290 +b Fo(-FUSD)p 31984 5631 333 45 v 399 w(NOREPLY)g Fn(instead)e(of)h(a)f +(normal)h(system)f(call)863 6959 y(return)277 b(v)-28 +b(alue.)2524 8951 y(Before)463 b(a)g(callback)h(blocks)g(the)f(caller)f +(by)i(returning)f Fo(-FUSD)p 28666 8951 V 399 w(NOREPLY)p +Fn(,)h(it)d(must)i(sa)-22 b(v)-17 b(e)463 b(the)g Fo(fusd)p +45008 8951 V 399 w(file)p 48063 8951 V 400 w(info)863 +10280 y Fn(pointer)402 b(that)f(w)-11 b(as)401 b(pro)-17 +b(vided)404 b(to)d(the)g(callback)i(as)e(its)f(\002rst)g(ar)-20 +b(gument.)718 b(Later)-44 b(,)432 b(when)402 b(an)g(e)-28 +b(v)-17 b(ent)403 b(occurs)f(which)g(allo)-28 b(ws)402 +b(the)863 11608 y(client')-61 b(s)275 b(block)-11 b(ed)277 +b(system)e(call)g(to)g(complete,)i(the)e(dri)-28 b(v)-17 +b(er)276 b(should)g(call)f Fo(fusd)p 31396 11608 V 399 +w(return\(\))p Fn(,)h(which)g(will)f(unblock)i(the)e(calling)863 +12936 y(process)j(and)g(complete)h(its)c(system)i(call.)344 +b Fo(fusd)p 20285 12936 V 399 w(return\(\))278 b Fn(tak)-11 +b(es)277 b(tw)-11 b(o)277 b(ar)-20 b(guments:)2524 15815 +y Fg(\017)554 b Fn(The)278 b Fo(fusd)p 8351 15815 V 399 +w(file)p 11406 15815 V 399 w(info)f Fn(pointer)h(that)f(the)h(callback) +h(sa)-22 b(v)-17 b(ed)278 b(earlier;)f(and)2524 18029 +y Fg(\017)554 b Fn(The)392 b(system)g(call')-61 b(s)391 +b(return)h(v)-28 b(alue)393 b(\(in)f(other)g(w)-11 b(ords,)420 +b(the)392 b(v)-28 b(alue)394 b(that)e(w)-11 b(ould)392 +b(ha)-22 b(v)-17 b(e)394 b(been)g(returned)e(by)h(the)f(callback)3631 +19357 y(function)331 b(had)f(it)f(not)i(returned)f Fo(-FUSD)p +19670 19357 V 400 w(NOREPLY)p Fn(\).)g(FUSD)h(itself)d +Fk(does)j(not)f Fn(e)-17 b(xamine)332 b(the)e(return)g(v)-28 +b(alue)332 b(passed)e(as)3631 20685 y(the)384 b(second)i(ar)-20 +b(gument)386 b(to)f Fo(fusd)p 17338 20685 V 399 w(return)p +Fn(;)438 b(it)384 b(simply)g(propag)-6 b(ates)387 b(that)e(v)-28 +b(alue)386 b(back)g(to)e(the)h(k)-11 b(ernel)385 b(as)f(the)h(return) +3631 22014 y(v)-28 b(alue)278 b(of)f(the)h(block)-11 +b(ed)279 b(system)e(call.)2524 24892 y(Dri)-28 b(v)-17 +b(ers)335 b(should)g(ne)-28 b(v)-17 b(er)337 b(call)e +Fo(fusd)p 16824 24892 V 399 w(return)h Fn(more)f(than)h(once)g(on)g(a)e +(single)h Fo(fusd)p 36719 24892 V 400 w(file)p 39775 +24892 V 399 w(info)g Fn(pointer)-61 b(.)517 b(Doing)336 +b(so)863 26220 y(will)276 b(ha)-22 b(v)-17 b(e)279 b(unde\002ned)i +(results,)275 b(similar)h(to)h(calling)h Fo(free\(\))g +Fn(twice)f(on)h(the)f(same)h(pointer)-61 b(.)2524 28213 +y(It)240 b(also)h(bears)h(repeating)h(that)f(a)g(callback)h(can)g(call) +e Fk(either)h Fn(call)f(fusd)p 29218 28213 V 399 w(return\(\))g(e)-17 +b(xplicitly)242 b Fk(or)g Fn(return)f(a)h(normal)g(return)f(v)-28 +b(alue)863 29541 y(\(i.e.,)276 b(not)h Fo(-FUSD)p 8215 +29541 V 400 w(NOREPLY)p Fn(\),)g(b)-22 b(ut)277 b(not)h(both.)2524 +31533 y Fo(-FUSD)p 5910 31533 V 399 w(NOREPLY)336 b Fn(and)h +Fo(fusd)p 15883 31533 V 399 w(return\(\))g Fn(mak)-11 +b(e)337 b(it)e(easy)h(for)f(a)h(dri)-28 b(v)-17 b(er)336 +b(to)g(block)h(a)f(process,)350 b(then)337 b(unblock)g(it)e(later)863 +32862 y(when)235 b(data)f(becomes)h(a)-22 b(v)-28 b(ailable.)331 +b(When)234 b(the)g(callback)h(returns)e Fo(-FUSD)p 29305 +32862 V 399 w(NOREPLY)p Fn(,)h(the)g(dri)-28 b(v)-17 +b(er)234 b(is)e(freed)i(up)g(to)f(w)-11 b(ait)233 b(for)f(other)863 +34190 y(e)-28 b(v)-17 b(ents,)283 b(e)-28 b(v)-17 b(en)283 +b(though)f(the)f(process)g(making)h(the)e(system)h(call)f(is)g(still)e +(block)-11 b(ed.)356 b(The)281 b(dri)-28 b(v)-17 b(er)281 +b(can)h(then)f(w)-11 b(ait)280 b(for)g(something)i(to)863 +35518 y(happen)299 b(that)e(unblocks)i(the)e(original)g(caller)-22 +b(\227for)296 b(e)-17 b(xample,)304 b(another)298 b(FUSD)f(e)-28 +b(v)-17 b(ent,)304 b(data)297 b(from)f(a)h(serial)f(port,)301 +b(or)c(data)g(from)863 36847 y(the)314 b(netw)-11 b(ork.)453 +b(\(Recall)314 b(from)f(Section)i(7)e(that)h(a)f(FUSD)i(dri)-28 +b(v)-17 b(er)314 b(can)g(simultaneously)h(w)-11 b(ait)313 +b(for)g(both)h(FUSD)g(and)h(non-FUSD)863 38175 y(e)-28 +b(v)-17 b(ents.\))2524 40168 y(FUSD)435 b(includes)g(an)g(e)-17 +b(xample)437 b(program,)474 b Fo(pager.c)p Fn(,)h(which)435 +b(demonstrates)g(these)g(techniques.)817 b(The)436 b(pager)f(dri)-28 +b(v)-17 b(er)863 41496 y(implements)301 b(a)f(simple)g(noti\002cation)i +(interf)-11 b(ace)301 b(which)g(lets)e(an)-17 b(y)301 +b(number)h(of)d(\223w)-11 b(aiters\224)301 b(w)-11 b(ait)300 +b(for)f(a)h(signal)g(from)g(a)g(\223noti\002er)-61 b(.)-77 +b(\224)863 42824 y(All)257 b(the)h(w)-11 b(aiters)258 +b(w)-11 b(ait)257 b(by)i(trying)f(to)f(read)i(from)e +Fo(/dev/pager/notify)p Fn(.)340 b(Those)259 b(reads)f(will)f(block)i +(until)e(a)h(noti\002er)h(writes)863 44153 y(the)377 +b(string)f Fo(page)h Fn(to)g Fo(/dev/pager/input)p Fn(.)644 +b(It')-61 b(s)375 b(easy)i(to)g(try)f(the)h(application)i(out\227run)e +(the)g(dri)-28 b(v)-17 b(er)-44 b(,)402 b(and)378 b(then)f(open)863 +45481 y(three)313 b(other)f(shells.)448 b(In)312 b(tw)-11 +b(o)312 b(of)g(them,)322 b(type)313 b Fo(cat)664 b(/dev/pager/notify)p +Fn(.)452 b(The)313 b(reads)f(will)g(block.)449 b(Then,)323 +b(in)312 b(the)g(third)863 46809 y(shell,)277 b(type)h +Fo(echo)664 b(page)h(>)g(/dev/pager/input)p Fn(\227the)280 +b(other)d(tw)-11 b(o)277 b(shells)g(should)h(become)h(unblock)-11 +b(ed.)2524 48802 y(Let')-61 b(s)276 b(tak)-11 b(e)278 +b(a)f(look)h(at)f(ho)-28 b(w)278 b(this)f(application)i(is)d +(implemented,)j(step)e(by)g(step.)863 52413 y Fl(8.2.1)1108 +b(K)-28 b(eeping)279 b(P)-22 b(er)-41 b(-Client)278 b(State)863 +55153 y Fn(The)351 b(\002rst)f(thing)h(to)f(notice)h(about)h +Fo(pager.c)f Fn(is)e(that)h(it)g(k)-11 b(eeps)351 b Fk(per)-22 +b(-client)351 b(state)p Fn(.)562 b(That)351 b(is,)367 +b(for)350 b(e)-28 b(v)-17 b(ery)352 b(\002le)f(descriptor)f(open)863 +56482 y(to)295 b(the)g(dri)-28 b(v)-17 b(er)-44 b(,)299 +b(a)c(structure)g(is)f(allocated)i(that)f(has)g(information)h(relating) +f(to)f(that)h(\002le)g(descriptor)-61 b(.)397 b(Pre)-28 +b(vious)296 b(dri)-28 b(v)-17 b(er)296 b(e)-17 b(xamples)863 +57810 y(were,)315 b(for)306 b(the)h(most)f(part,)314 +b Fk(r)-41 b(eactive)p Fn(\227the)-17 b(y)310 b(recei)-28 +b(v)-17 b(ed)309 b(requests,)314 b(and)308 b(immediately)h(generated)g +(responses.)433 b(Since)308 b(there)f(w)-11 b(as)863 +59138 y(ne)-28 b(v)-17 b(er)335 b(more)f(than)g(one)g(request)g +(outstanding,)348 b(there)334 b(w)-11 b(as)333 b(no)h(need)h(to)e(k)-11 +b(eep)334 b(a)f(list)f(of)h(them.)512 b(The)334 b(pager)g(application)h +(is)e(the)863 60467 y(\002rst)304 b(one)i(that)e(must)g(k)-11 +b(eep)307 b(track)e(of)f(an)h(arbitrary)g(number)h(of)e(requests)h +(that)f(might)h(be)h(outstanding)g(at)e(the)h(same)g(time.)426 +b(The)863 61795 y(\002rst)271 b(e)-17 b(xcerpt)274 b(of)e +Fo(pager.c)p Fn(,)h(which)g(appears)h(in)e(Program)h(11,)g(sho)-28 +b(ws)272 b(the)h(code)g(which)g(creates)g(this)e(per)-22 +b(-client)272 b(state.)342 b(Lines)863 63123 y(1\2266)240 +b(de\002ne)h(a)e(structure,)246 b Fo(pager)p 14218 63123 +V 400 w(client)p Fn(,)g(which)240 b(k)-11 b(eeps)240 +b(all)f(the)g(information)h(we)f(need)h(about)g(each)h(client)e +(attached)i(to)e(the)863 64452 y(dri)-28 b(v)-17 b(er)-61 +b(.)341 b(The)269 b Fo(open)f Fn(callback)i(for)d Fo(/dev/pager/notify) +p Fn(,)272 b(sho)-28 b(wn)269 b(on)f(lines)g(12\22631,)j(allocates)e +(memory)f(for)f(an)i(instance)863 65780 y(of)342 b(this)f(structure)g +(and)i(adds)g(it)e(to)g(a)h(link)-11 b(ed)343 b(list.)536 +b(\(If)340 b(the)i(memory)h(allocation)h(f)-11 b(ails,)356 +b(an)343 b(error)e(is)g(returned)h(to)g(the)g(client)g(on)863 +67108 y(line)300 b(18;)311 b(this)298 b(will)h(pre)-28 +b(v)-17 b(ent)301 b(the)f(\002le)g(from)f(opening.\))412 +b(Note)300 b(on)g(line)g(25)g(that)f(we)h(use)g(the)g +Fo(private)p 41394 67108 V 399 w(data)g Fn(\002eld)g(to)g(store)f(a)863 +68437 y(pointer)249 b(to)f(the)g(client)g(state;)257 +b(this)247 b(allo)-28 b(ws)249 b(the)f(structure)g(to)g(be)g(retrie)-28 +b(v)-17 b(ed)250 b(when)f(later)f(callbacks)h(on)g(this)e(\002le)h +(descriptor)g(arri)-28 b(v)-17 b(e.)863 69765 y(The)278 +b(memory)g(is)e(deallocated)k(when)f(the)e(\002le)g(is)g(closed;)g(we') +-11 b(ll)277 b(see)g(that)g(in)g(a)g(later)g(section.)25405 +74071 y(25)p eop +%%Page: 26 29 +26 28 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(11)e Fn(pager)-61 b(.c)278 b(\(P)-17 b(art)277 b(1\):)343 +b(Creating)278 b(state)f(for)f(e)-28 b(v)-17 b(ery)279 +b(client)f(using)f(the)h(dri)-28 b(v)-17 b(er)p 863 3445 +50191 45 v 365 4400 a Fi(1)1661 b Fo(/*)664 b(per-client)i(structure)g +(to)e(keep)h(track)g(of)g(who)g(has)f(an)h(open)g(FD)f(to)h(us)f(*/) +2524 5728 y(struct)h(pager_client)h({)3852 7057 y(int)f +(last_page_seen;)1995 b(/*)664 b(seq.)h(no.)g(of)f(last)h(page)g(this)g +(client)g(has)g(seen)g(*/)3852 8385 y(struct)g(fusd_file_info)i(*read;) +e(/*)g(outstanding)h(read)f(request,)g(if)g(any)f(*/)365 +9714 y Fi(5)2989 b Fo(struct)665 b(fusd_file_info)i(*polldiff;)f(/*)e +(outstanding)i(polldiff)g(request)f(*/)3852 11042 y(struct)g +(pager_client)h(*next;)1994 b(/*)665 b(to)f(construct)i(the)f(linked)g +(list)g(*/)2524 12370 y(};)2524 15027 y(struct)g(pager_client)h +(*client_list)g(=)f(NULL;)g(/*)f(list)h(of)g(clients)g(\(open)g(FDs\))g +(*/)-133 16355 y Fi(10)1661 b Fo(int)664 b(last_page)i(=)e(0;)h(/*)f +(seq.)h(no.)g(of)g(the)f(most)h(recent)g(page)g(to)g(arrive)g(*/)2524 +19012 y(/*)f(open)h(on)g(/dev/pager/notify:)i(create)e(state)g(for)g +(this)g(client)g(*/)2524 20340 y(static)g(int)g +(pager_notify_open\(struct)j(fusd_file_info)f(*file\))2524 +21669 y({)-133 22997 y Fi(15)2989 b Fo(/*)664 b(create)i(state)f(for)f +(this)h(client)h(*/)3852 24325 y(struct)f(pager_client)h(*c)f(=)f +(malloc\(sizeof\(struct)k(pager_client\)\);)3852 26982 +y(if)c(\(c)h(==)g(NULL\))5180 28310 y(return)h(-ENOBUFS;)-133 +29639 y Fi(20)3852 30967 y Fo(/*)e(initialize)i(fields)g(of)e(this)h +(client)g(state)g(*/)3852 32296 y(memset\(c,)h(0,)e(sizeof\(struct)j +(pager_client\)\);)3852 33624 y(c->last_page_seen)g(=)d(last_page;)-133 +36281 y Fi(25)2989 b Fo(/*)664 b(save)h(the)g(pointer)g(to)g(this)g +(state)g(so)f(it)h(gets)g(returned)g(to)g(us)g(later)g(*/)3852 +37609 y(file->private_data)i(=)e(c;)3852 40266 y(/*)f(add)h(this)g +(client)g(to)g(the)g(client)g(list)g(*/)3852 41594 y(c->next)g(=)g +(client_list;)-133 42922 y Fi(30)2989 b Fo(client_list)666 +b(=)e(c;)3852 45579 y(return)h(0;)2524 46907 y(})p 863 +48402 V 2524 51723 a Fn(Another)253 b(thing)g(to)g(notice)h(about)f +(the)g(open)i(callback)f(is)e(the)h(use)g(of)f(the)h +Fo(last)p 33489 51723 333 45 v 399 w(page)p 36544 51723 +V 399 w(seen)g Fn(v)-28 b(ariable.)337 b(The)253 b(dri)-28 +b(v)-17 b(er)254 b(gi)-28 b(v)-17 b(es)863 53051 y(a)301 +b(sequence)i(number)f(to)f(e)-28 b(v)-17 b(ery)302 b(page)g(it)e(recei) +-28 b(v)-17 b(es;)314 b Fo(last)p 23800 53051 V 399 w(page)p +26855 53051 V 399 w(seen)301 b Fn(stores)f(the)h(number)h(of)e(the)h +(most)g(recent)g(page)h(seen)863 54379 y(by)366 b(a)g(client.)608 +b(When)367 b(a)e(ne)-28 b(w)367 b(client)f(arri)-28 b(v)-17 +b(es)366 b(\(i.e.,)386 b(it)364 b(opens)j Fo(/dev/pager/notify)p +Fn(\),)390 b(its)364 b Fo(last)p 41511 54379 V 399 w(page)p +44566 54379 V 399 w(seen)i Fn(state)f(is)863 55708 y(set)311 +b(equal)h(to)f(the)g(page)h(that)f(has)h(most)e(recently)i(arri)-28 +b(v)-17 b(ed;)329 b(this)310 b(forces)h(a)g(ne)-28 b(w)312 +b(client)g(to)e(w)-11 b(ait)311 b(for)f(the)i Fk(ne)-22 +b(xt)311 b Fn(page,)321 b(rather)311 b(than)863 57036 +y(immediately)279 b(being)f(noti\002ed)h(of)d(a)i(page)g(that)f(has)h +(arri)-28 b(v)-17 b(ed)278 b(in)f(the)g(past.)863 60648 +y Fl(8.2.2)1108 b(Blocking)279 b(and)f(completing)h(r)-20 +b(eads)863 63387 y Fn(The)418 b(ne)-17 b(xt)419 b(part)e(of)g +Fo(pager.c)h Fn(is)e(sho)-28 b(wn)418 b(in)f(Program)h(12.)764 +b(The)418 b Fo(pager)p 31463 63387 V 400 w(notify)p 35847 +63387 V 399 w(read)g Fn(function)g(seen)g(on)f(line)h(1)f(is)863 +64716 y(re)-17 b(gistered)405 b(as)f(the)g Fo(read)h +Fn(callback)h(for)d(the)i Fo(/dev/pager/notify)i Fn(de)-28 +b(vice.)726 b(It)403 b(blocks)i(the)g(read)f(request)h(using)g(the)863 +66044 y(technique)278 b(we)e(described)h(earlier:)342 +b(it)275 b(stores)f(the)i Fo(fusd)p 23100 66044 V 399 +w(file)p 26155 66044 V 399 w(info)g Fn(pointer)g(in)g(that)f(client') +-61 b(s)275 b(state)g(structure,)h(and)g(returns)863 +67372 y Fo(-FUSD)p 4249 67372 V 400 w(NOREPLY)p Fn(.)309 +b(\(Note)h(that)f(the)h(pointer)g(to)f(the)g(client')-61 +b(s)309 b(state)g(structure)g(comes)h(from)f(the)h Fo(private)p +44555 67372 V 400 w(data)f Fn(\002eld)h(of)863 68701 +y Fo(fusd)p 3585 68701 V 399 w(file)p 6640 68701 V 400 +w(info)p Fn(,)277 b(where)h(the)f(open)i(callback)g(stored)e(it.\)) +25405 74071 y(26)p eop +%%Page: 27 30 +27 29 bop 863 3167 50191 89 v 863 4151 a Fl(Pr)-20 b(ogram)280 +b(12)e Fn(pager)-61 b(.c)278 b(\(P)-17 b(art)277 b(2\):)343 +b(Block)278 b(clients')f Fo(read)g Fn(requests,)g(and)i(later)d +(completing)j(the)f(block)-11 b(ed)279 b(reads)p 863 +4656 50191 45 v 365 5611 a Fi(1)1661 b Fo(ssize_t)665 +b(pager_notify_read\(struct)j(fusd_file_info)f(*file,)e(char)g +(*buffer,)19792 6940 y(size_t)g(len,)g(loff_t)h(*offset\))2524 +8268 y({)3852 9597 y(struct)f(pager_client)h(*c)f(=)f(\(struct)i +(pager_client)g(*\))f(file->private_data;)365 10925 y +Fi(5)3852 12253 y Fo(if)f(\(c)h(==)g(NULL)f(||)h(c->read)g(!=)g(NULL\)) +g({)5180 13582 y(fprintf\(stderr,)i("pager_read's)g(arguments)e(are)g +(confusd,)h(alas"\);)5180 14910 y(return)g(-EINVAL;)3852 +16238 y(})-133 17567 y Fi(10)3852 18895 y Fo(c->read)f(=)g(file;)3852 +20223 y(pager_notify_complete_read\(c\);)3852 21552 y(return)g +(-FUSD_NOREPLY;)2524 22880 y(})-133 24208 y Fi(15)2524 +25537 y Fo(void)f(pager_notify_complete_read\(struct)670 +b(pager_client)d(*c\))2524 26865 y({)3852 28193 y(/*)d(if)h(there)g(is) +g(no)f(outstanding)i(read,)f(do)g(nothing)g(*/)3852 29522 +y(if)f(\(c)h(==)g(NULL)f(||)h(c->read)g(==)g(NULL\))-133 +30850 y Fi(20)4317 b Fo(return;)3852 33507 y(/*)664 b(if)h(there)g(are) +g(no)f(outstanding)i(pages,)g(do)e(nothing)i(*/)3852 +34835 y(if)e(\(c->last_page_seen)k(>=)c(last_page\))5180 +36164 y(return;)-133 37492 y Fi(25)3852 38820 y Fo(/*)g(bring)i(this)e +(client)i(up)e(to)h(date)g(with)f(the)h(most)g(recent)g(page)g(*/)3852 +40149 y(c->last_page_seen)i(=)d(last_page;)3852 42805 +y(/*)g(and)h(notify)g(the)g(client)g(by)g(unblocking)h(the)f(read)f +(\(read)h(returns)h(0\))e(*/)-133 44134 y Fi(30)2989 +b Fo(fusd_return\(c->read,)668 b(0\);)3852 45462 y(c->read)d(=)g(NULL;) +2524 46790 y(})2524 49447 y(ssize_t)g(pager_input_write\(struct)j +(fusd_file_info)f(*file,)-133 50775 y Fi(35)18929 b Fo(const)665 +b(char)g(*buffer,)h(size_t)f(len,)g(loff_t)g(*offset\))2524 +52104 y({)3852 53432 y(struct)g(pager_client)h(*c;)3852 +56089 y(/*)e(...)h(*/)-133 57417 y Fi(40)3852 58746 y +Fo(CASE\("page"\))h({)5180 60074 y(last_page++;)5180 +62731 y(for)f(\(c)g(=)f(client_list;)i(c)f(!=)f(NULL;)h(c)f(=)h +(c->next\))g({)-133 64059 y Fi(45)5646 b Fo +(pager_notify_complete_polldiff\(c\);)6509 65387 y +(pager_notify_complete_read\(c\);)5180 66716 y(})3852 +68044 y(})p 863 69538 V 25405 74071 a Fn(27)p eop +%%Page: 28 31 +28 30 bop 2524 2974 a Fo(pager)p 5910 2974 333 45 v 399 +w(notify)p 10293 2974 V 400 w(complete)p 16005 2974 V +399 w(read)274 b Fk(unbloc)-22 b(ks)274 b Fn(pre)-28 +b(viously)274 b(block)-11 b(ed)275 b(reads.)342 b(This)273 +b(function)h(\002rst)e(checks)i(to)f(see)g(that)863 4302 +y(there)301 b(is,)306 b(in)300 b(f)-11 b(act,)306 b(a)301 +b(block)-11 b(ed)303 b(read)e(\(line)g(19\).)414 b(It)300 +b(then)h(checks)i(to)d(see)h(if)f(a)h(page)h(has)f(arri)-28 +b(v)-17 b(ed)302 b(that)e(the)h(client)g(hasn')-20 b(t)301 +b(seen)h(yet)863 5631 y(\(line)329 b(23\).)499 b(Finally)-72 +b(,)342 b(it)328 b(updates)j(the)e(client)g(state)g(and)h(unblocks)h +(the)e(block)-11 b(ed)331 b(read)f(by)g(calling)f Fo(fusd)p +42126 5631 V 399 w(return)p Fn(.)500 b(Note)330 b(the)863 +6959 y(second)258 b(ar)-20 b(gument)257 b(to)f Fo(fusd)p +12448 6959 V 399 w(return)h Fn(is)e(a)h(0;)263 b(as)255 +b(we)h(sa)-17 b(w)257 b(in)e(Section)j(4.3,)i(a)c(0)g(return)g(v)-28 +b(alue)257 b(to)f(a)g Fo(read)g Fn(system)g(call)g(means)863 +8287 y(EOF)-89 b(.)278 b(\(The)g(system)f(call)g(will)f(be)i(unblock) +-11 b(ed)280 b(re)-17 b(g)-6 b(ardless)278 b(of)f(the)g(return)g(v)-28 +b(alue.\))2524 10280 y Fo(pager)p 5910 10280 V 399 w(notify)p +10293 10280 V 400 w(complete)p 16005 10280 V 399 w(read)383 +b Fn(is)f(called)h(e)-28 b(v)-17 b(ery)385 b(time)d(a)h(ne)-28 +b(w)384 b(page)g(arri)-28 b(v)-17 b(es.)660 b(Ne)-28 +b(w)383 b(pages)h(are)e(processed)i(by)863 11608 y Fo(pager)p +4249 11608 V 400 w(input)p 7969 11608 V 399 w(write)301 +b Fn(\(line)f(34\),)306 b(which)301 b(is)f(the)g Fo(write)h +Fn(callback)i(for)c Fo(/dev/pager/input)p Fn(.)416 b(After)300 +b(recording)i(the)863 12936 y(f)-11 b(act)294 b(that)g(a)h(ne)-28 +b(w)295 b(page)h(has)e(arri)-28 b(v)-17 b(ed,)299 b(it)294 +b(calls)g Fo(pager)p 22092 12936 V 399 w(notify)p 26475 +12936 V 399 w(complete)p 32186 12936 V 400 w(read)h Fn(for)e(each)j +(client)f(that)f(has)g(an)h(open)h(\002le)863 14265 y(descriptor)-61 +b(.)377 b(This)288 b(will)f(complete)i(the)g(reads)f(of)g(an)-17 +b(y)289 b(clients)f(who)h(ha)-22 b(v)-17 b(e)290 b(not)e(yet)h(seen)g +(this)e(ne)-28 b(w)289 b(data,)i(and)e(ha)-22 b(v)-17 +b(e)290 b(no)f(ef)-28 b(fect)288 b(on)863 15593 y(clients)277 +b(that)g(don')-20 b(t)278 b(ha)-22 b(v)-17 b(e)279 b(outstanding)g +(reads.)2524 17586 y(There)433 b(is)f(another)i(interesting)f(point)h +(to)e(notice)i(about)g Fo(pager)p 28984 17586 V 399 w(notify)p +33367 17586 V 400 w(read)p Fn(.)811 b(On)433 b(line)f(12,)472 +b(after)433 b(it)f(stores)g(the)863 18914 y(block)-11 +b(ed)309 b(system)e(call')-61 b(s)306 b(pointer)-44 b(,)314 +b(b)-22 b(ut)307 b(before)g(we)g(return)g Fo(-FUSD)p +27135 18914 V 400 w(NOREPLY)p Fn(,)g(it)f(calls)g(the)h(completion)i +(function.)433 b(This)307 b(has)863 20242 y(the)357 b(ef)-28 +b(fect)358 b(of)e(returning)i(an)-17 b(y)358 b(data)g(that)f(might)g +(already)h(be)f(a)-22 b(v)-28 b(ailable)359 b(back)g(to)d(the)h(caller) +g(immediately)-72 b(.)584 b(If)356 b(that)h(happens,)863 +21571 y(we)282 b(will)f(end)i(up)f(calling)h Fo(fusd)p +13724 21571 V 399 w(return)g Fk(befor)-41 b(e)282 b Fn(we)h(return)e +Fo(-FUSD)p 29275 21571 V 400 w(NOREPLY)p Fn(.)h(This)g(probably)h +(seems)f(strange,)i(b)-22 b(ut)281 b(it')-61 b(s)863 +22899 y(le)-17 b(g)-6 b(al.)608 b(Recall)366 b(that)f(a)g(callback)i +(can)f(call)f(fusd)p 19839 22899 V 399 w(return\(\))f(e)-17 +b(xplicitly)366 b Fk(or)f Fn(return)g(a)g(normal)g(\(not)g +Fo(-FUSD)p 42694 22899 V 400 w(NOREPLY)p Fn(\))g(return)863 +24227 y(v)-28 b(alue,)279 b(b)-22 b(ut)277 b(not)g(both;)h(the)f(order) +h(doesn')-20 b(t)277 b(matter)-61 b(.)863 27839 y Fl(8.2.3)1108 +b(Using)277 b Fo(fusd)p 9889 27839 V 399 w(destroy\(\))i +Fl(to)e(clean)h(up)g(client)f(state)863 30579 y Fn(Finally)-72 +b(,)268 b(let')-61 b(s)264 b(tak)-11 b(e)266 b(a)f(look)h(at)f(one)i +(last)d(aspect)i(of)f(the)g(pager)i(program:)338 b(ho)-28 +b(w)266 b(it)e(cleans)i(up)g(the)g(per)-22 b(-client)265 +b(state)g(when)h(a)g(client)863 31907 y(lea)-22 b(v)-17 +b(es.)331 b(This)234 b(is)g(mostly)h(straightforw)-11 +b(ard,)243 b(with)235 b(one)h(e)-17 b(xception:)325 b(a)236 +b(client)f(may)h(ha)-22 b(v)-17 b(e)237 b(an)e(outstanding)i(read)f +(request)f(out)h(when)863 33235 y(a)309 b(close)g(request)g(comes)g +(in.)437 b(Normally)-72 b(,)317 b(a)309 b(client)f(can')-20 +b(t)309 b(mak)-11 b(e)310 b(another)g(system)e(call)h(request)g(while)f +(a)h(pre)-28 b(vious)310 b(system)e(call)863 34564 y(is)314 +b(still)f(block)-11 b(ed.)459 b(Ho)-28 b(we)g(v)-17 b(er)-44 +b(,)327 b(the)315 b Fo(close)h Fn(system)e(call)h(is)f(an)i(e)-17 +b(xception:)422 b(it)314 b(gets)g(called)i(when)h(a)e(client)g(dies)g +(\(for)f(e)-17 b(xample,)863 35892 y(if)367 b(it)g(recei)-28 +b(v)-17 b(es)369 b(an)g(interrupt)f(signal\).)615 b(If)367 +b(a)h Fo(close)g Fn(comes)h(in)e(while)i(another)g(system)e(call)h(is)f +(still)f(outstanding,)392 b(the)368 b(state)863 37220 +y(associated)263 b(with)e(the)h(outstanding)h(request)f(should)g(be)g +(freed)g(to)f(a)-22 b(v)g(oid)263 b(a)e(memory)i(leak.)339 +b(The)262 b Fo(fusd)p 41121 37220 V 399 w(destroy)g Fn(function)h(is) +863 38549 y(used)278 b(to)f(do)h(this,)e(seen)h(on)h(linen)g(12-14)g +(of)f(Program)h(13.)863 42382 y Fj(8.3)1329 b(Retrie)-20 +b(ving)332 b(a)h(block)-13 b(ed)330 b(system)h(call')-49 +b(s)333 b(ar)-13 b(guments)330 b(fr)-24 b(om)332 b(a)g +Fc(fusd)p 37031 42382 399 45 v 479 w(file)p 40698 42382 +V 478 w(info)g Fj(pointer)863 45121 y Fn(In)341 b(the)h(pre)-28 +b(vious)343 b(section,)358 b(we)342 b(sho)-28 b(wed)343 +b(ho)-28 b(w)342 b(the)g Fo(fusd)p 23678 45121 333 45 +v 399 w(return)g Fn(function)h(can)f(be)h(used)f(to)f(specify)h(the)g +(return)f(v)-28 b(alue)343 b(of)863 46450 y(a)305 b(system)g(call)g +(that)g(w)-11 b(as)305 b(pre)-28 b(viously)306 b(block)-11 +b(ed.)430 b(Ho)-28 b(we)g(v)-17 b(er)-44 b(,)314 b(man)-17 +b(y)306 b(system)f(calls)g(ha)-22 b(v)-17 b(e)306 b(side)f(ef)-28 +b(fects)305 b(in)g(addition)h(to)f(returning)863 47778 +y(a)316 b(v)-28 b(alue\227for)316 b(e)-17 b(xample,)327 +b(in)316 b(a)f Fo(read\(\))h Fn(request,)326 b(the)315 +b(data)h(being)h(returned)g(has)e(to)g(be)h(copied)i(into)d(the)h +(caller')-61 b(s)315 b(b)-22 b(uf)-28 b(fer)-61 b(.)458 +b(T)-89 b(o)863 49106 y(f)-11 b(acilitate)356 b(this,)376 +b(FUSD)357 b(pro)-17 b(vides)358 b(accessor)f(functions)h(that)e(let)g +(dri)-28 b(v)-17 b(ers)357 b(retrie)-28 b(v)-17 b(e)358 +b(the)f(ar)-20 b(guments)357 b(that)g(had)h(been)g(passed)f(to)863 +50435 y(its)311 b(callbacks)i(at)f(the)g(time)g(the)g(call)g(w)-11 +b(as)312 b(originally)g(issued.)448 b(F)-17 b(or)312 +b(e)-17 b(xample,)323 b(the)312 b Fo(fusd)p 35959 50435 +V 400 w(get)p 38351 50435 V 399 w(read)p 41406 50435 +V 399 w(buffer\(\))h Fn(function)863 51763 y(will)349 +b(return)h(a)g(pointer)h(to)f(the)g(data)h(b)-22 b(uf)-28 +b(fer)350 b(that)h(is)e(pro)-17 b(vided)352 b(with)e +Fo(read\(\))g Fn(callbacks.)564 b(Dri)-28 b(v)-17 b(ers)350 +b(can)h(use)g(these)f(accessor)863 53091 y(functions)278 +b(to)f(af)-28 b(fect)277 b(change)j(to)d(a)g(client)h +Fk(befor)-41 b(e)278 b Fn(calling)f Fo(fusd)p 26296 53091 +V 400 w(return\(\))p Fn(.)2524 55084 y(The)h(follo)-28 +b(wing)278 b(accessor)g(functions)f(are)h(a)-22 b(v)-28 +b(ailable,)278 b(all)f(of)g(which)h(tak)-11 b(e)278 b(a)f(single)g +Fo(fusd)p 37712 55084 V 400 w(file)p 40768 55084 V 399 +w(info)665 b(*)277 b Fn(ar)-20 b(gument:)2524 57962 y +Fg(\017)554 b Fo(int)664 b(char)h(*fusd)p 12994 57962 +V 400 w(get)p 15386 57962 V 399 w(read)p 18441 57962 +V 399 w(buffer)p Fn(\227The)358 b(destination)g(b)-22 +b(uf)-28 b(fer)357 b(for)f(data)h(that)g(a)f(dri)-28 +b(v)-17 b(er)358 b(is)d(returning)i(to)g(a)3631 59290 +y(process)277 b(doing)h(a)g Fo(read\(\))p Fn(.)2524 61504 +y Fg(\017)554 b Fo(const)665 b(char)f(*fusd)p 14322 61504 +V 400 w(get)p 16714 61504 V 399 w(write)p 20433 61504 +V 399 w(buffer)p Fn(\227The)324 b(source)f(b)-22 b(uf)-28 +b(fer)323 b(containing)h(data)f(sent)f(to)g(the)g(dri)-28 +b(v)-17 b(er)323 b(by)g(a)3631 62833 y(process)277 b(doing)h(a)g +Fo(write\(\))p Fn(.)2524 65047 y Fg(\017)554 b Fo(fusd)p +6353 65047 V 399 w(get)p 8744 65047 V 399 w(length)p +Fn(\227The)279 b(length)f(\(in)f(bytes\))g(of)f(the)i(b)-22 +b(uf)-28 b(fer)277 b(for)g(either)g(a)g Fo(read\(\))h +Fn(or)f(a)g Fo(write\(\))p Fn(.)2524 67261 y Fg(\017)554 +b Fo(loff)p 6353 67261 V 399 w(t)664 b(fusd)p 10736 67261 +V 399 w(get)p 13127 67261 V 399 w(offset)p Fn(\227The)255 +b(\002le)e(descriptor')-61 b(s)252 b(byte)h(of)-28 b(fset,)257 +b(typically)d(used)f(in)f Fo(read\(\))h Fn(and)h Fo(write\(\))3631 +68589 y Fn(callbacks.)25405 74071 y(28)p eop +%%Page: 29 32 +29 31 bop 863 1955 50191 89 v 863 2940 a Fl(Pr)-20 b(ogram)280 +b(13)e Fn(pager)-61 b(.c)278 b(\(P)-17 b(art)277 b(3\):)343 +b(Cleaning)279 b(up)f(when)g(a)f(client)h(lea)-22 b(v)-17 +b(es)p 863 3445 50191 45 v 365 4400 a Fi(1)1661 b Fo(/*)664 +b(close)h(on)g(/dev/pager/notify:)i(destroy)e(state)h(for)e(this)h +(client)g(*/)2524 5728 y(static)g(int)g(pager_notify_close\(struct)j +(fusd_file_info)f(*file\))2524 7057 y({)3852 8385 y(struct)e +(pager_client)h(*c;)365 9714 y Fi(5)3852 11042 y Fo(if)e(\(\(c)h(=)g +(\(struct)g(pager_client)h(*\))f(file->private_data\))i(!=)e(NULL\))g +({)5180 13699 y(/*)g(take)g(this)g(client)g(off)g(our)f(client)h(list)g +(*/)5180 15027 y(client_list_remove\(c\);)-133 16355 +y Fi(10)5180 17684 y Fo(/*)g(if)f(there)h(is)g(a)f(read)h(outstanding,) +h(free)f(the)g(state)g(*/)5180 19012 y(if)g(\(c->read)g(!=)g(NULL\))g +({)6509 20340 y(fusd_destroy\(c->read\);)6509 21669 y(c->read)g(=)f +(NULL;)-133 22997 y Fi(15)4317 b Fo(})5180 24325 y(/*)665 +b(destroy)g(any)g(outstanding)h(polldiffs)g(*/)5180 25654 +y(if)f(\(c->polldiff)h(!=)f(NULL\))g({)6509 26982 y +(fusd_destroy\(c->polldiff\);)6509 28310 y(c->polldiff)h(=)e(NULL;)-133 +29639 y Fi(20)4317 b Fo(})5180 32296 y(/*)665 b(get)g(rid)f(of)h(the)f +(struct)i(*/)5180 33624 y(free\(c\);)5180 34952 y(file->private_data)i +(=)c(NULL;)-133 36281 y Fi(25)2989 b Fo(})3852 37609 +y(return)665 b(0;)2524 38937 y(})p 863 40432 V 2524 43753 +a Fg(\017)554 b Fo(int)664 b(fusd)p 9009 43753 333 45 +v 399 w(get)p 11400 43753 V 400 w(ioctl)p 15120 43753 +V 399 w(request)p Fn(\227An)267 b(ioctl')-61 b(s)265 +b(request)h(\223command)j(number\224)f(\(i.e.,)e(the)h(\002rst)d(ar)-20 +b(gument)268 b(of)d(an)3631 45081 y(ioctl\).)2524 47295 +y Fg(\017)554 b Fo(int)664 b(fusd)p 9009 47295 V 399 +w(get)p 11400 47295 V 400 w(ioctl)p 15120 47295 V 399 +w(arg)p Fn(\227The)425 b(second)g(ar)-20 b(gument)425 +b(of)f(an)g(ioctl)f(for)g(non-data-bearing)k Fo(ioctl)d +Fn(requests)3631 48623 y(\(i.e.,)p 5972 48623 V 674 w +Fo(IO)277 b Fn(commands\).)2524 50837 y Fg(\017)554 b +Fo(void)664 b(*fusd)p 10337 50837 V 400 w(get)p 12729 +50837 V 399 w(ioctl)p 16448 50837 V 399 w(buffer)p Fn(\227The)438 +b(data)f(b)-22 b(uf)-28 b(fer)436 b(for)f(data-bearing)j +Fo(ioctl)f Fn(requests)f(\()p 45349 50837 V 398 w Fo(IOR)p +Fn(,)p 48452 50837 V 834 w Fo(IOW)p Fn(,)3631 52165 y(and)p +5572 52165 V 676 w Fo(IORW)278 b Fn(commands\).)2524 +54379 y Fg(\017)554 b Fo(int)664 b(fusd)p 9009 54379 +V 399 w(get)p 11400 54379 V 400 w(poll)p 14456 54379 +V 399 w(diff)p 17511 54379 V 399 w(cached)p 21894 54379 +V 399 w(state)p Fn(\227See)279 b(Section)g(9.)2524 57257 +y(W)-89 b(e)411 b(got)h(a)-17 b(w)-11 b(ay)412 b(without)g(using)f +(these)h(accessor)f(functions)h(in)f(our)g Fo(pager.c)h +Fn(e)-17 b(xample)414 b(because)f(the)e(pager)h(doesn')-20 +b(t)863 58586 y(actually)340 b(return)e(data\227it)h(just)e(blocks)i +(and)h(unblocks)g Fo(read)f Fn(calls.)526 b(Ho)-28 b(we)g(v)-17 +b(er)-44 b(,)356 b(the)339 b(FUSD)g(distrib)-22 b(ution)338 +b(contains)i(another)863 59914 y(e)-17 b(xample)280 b(program,)d +Fo(logring)p Fn(,)h(that)f(demonstrates)h(their)f(use.)2524 +61907 y Fo(logring)441 b Fn(mak)-11 b(es)442 b(it)e(easy)i(to)e(access) +i(the)f(most)g(recent)g(\(and)h(only)g(the)f(most)f(recent\))i(output)g +(from)e(a)h(process.)835 b(It)863 63235 y(w)-11 b(orks)433 +b(just)f(lik)-11 b(e)433 b Fo(tail)665 b(-f)433 b Fn(on)h(a)f(log)g +(\002le,)472 b(e)-17 b(xcept)435 b(that)e(the)h(storage)f(required)h +(ne)-28 b(v)-17 b(er)435 b(gro)-28 b(ws.)812 b(This)432 +b(can)i(be)g(useful)f(in)863 64563 y(embedded)345 b(systems)c(where)i +(there)f(isn')-20 b(t)340 b(enough)k(memory)f(or)e(disk)h(space)h(for)e +(k)-11 b(eeping)344 b(complete)f(log)f(\002les,)357 b(b)-22 +b(ut)342 b(the)g(most)863 65892 y(recent)278 b(deb)-22 +b(ugging)280 b(messages)e(are)f(sometimes)h(needed)h(\(e.g.,)e(after)f +(an)i(error)f(is)f(observ)-17 b(ed\).)2524 67884 y Fo(logring)257 +b Fn(uses)e(FUSD)j(to)d(implement)j(a)e(character)h(de)-28 +b(vice,)263 b Fo(/dev/logring)p Fn(,)e(that)c(acts)f(lik)-11 +b(e)256 b(a)g(named)i(pipe)f(that)f(has)863 69213 y(a)298 +b(\002nite,)304 b(circular)298 b(b)-22 b(uf)-28 b(fer)-61 +b(.)407 b(The)299 b(size)f(of)g(the)h(b)-22 b(uf)-28 +b(fer)298 b(is)f(gi)-28 b(v)-17 b(en)300 b(as)e(a)g(command-line)j(ar) +-20 b(gument.)408 b(As)298 b(more)g(data)h(is)e(written)h(into)25405 +74071 y(29)p eop +%%Page: 30 33 +30 32 bop 863 2974 a Fn(the)356 b(b)-22 b(uf)-28 b(fer)-44 +b(,)374 b(the)355 b(oldest)g(data)h(is)e(discarded.)579 +b(A)355 b(process)g(that)g(reads)h(from)e(the)i(logring)g(de)-28 +b(vice)357 b(will)d(\002rst)g(read)i(the)f(e)-17 b(xisting)863 +4302 y(b)-22 b(uf)-28 b(fer)-44 b(,)277 b(then)h(block)g(and)g(see)g +(ne)-28 b(w)278 b(data)g(as)f(it')-61 b(s)275 b(written,)i(similar)e +(to)i(monitoring)h(a)g(log)f(\002le)g(using)h Fo(tail)665 +b(-f)p Fn(.)2524 6295 y(Y)-122 b(ou)380 b(can)g(run)f(this)f(e)-17 +b(xample)381 b(program)f(by)g(typing)g Fo(logring)665 +b()p Fn(,)406 b(where)380 b Fo(logsize)g Fn(is)e(the)h(size)g +(of)g(the)863 7623 y(circular)337 b(b)-22 b(uf)-28 b(fer)337 +b(in)f(bytes.)523 b(Then,)353 b(type)337 b Fo(cat)665 +b(/dev/logring)338 b Fn(in)f(a)g(shell.)521 b(The)338 +b Fo(cat)f Fn(process)g(will)f(block,)352 b(w)-11 b(aiting)338 +b(for)863 8951 y(data.)403 b(From)297 b(another)h(shell,)j(write)296 +b(to)h(the)g(logring)g(\(e.g.,)k Fo(echo)665 b(Hi)f(there)h(>)g +(/dev/logring)p Fn(\).)403 b(The)298 b Fo(cat)f Fn(process)863 +10280 y(will)276 b(see)i(the)f(message)h(appear)-61 b(.)2524 +12272 y(\(This)343 b(e)-17 b(xample)347 b(program)f(is)d(based)j(on)f +Fk(emlo)-11 b(g)p Fn(,)362 b(a)344 b(\(real\))g(Linux)h(k)-11 +b(ernel)346 b(module)f(with)g(identical)g(functionality)-72 +b(.)547 b(If)343 b(you)863 13601 y(\002nd)278 b(logring)g(useful,)f(b) +-22 b(ut)277 b(w)-11 b(ant)278 b(to)f(use)g(it)f(on)i(a)f(system)g +(that)g(does)h(not)f(ha)-22 b(v)-17 b(e)279 b(FUSD,)f(check)h(out)f +(the)f(original)h(emlog)47280 13199 y Ff(12)48111 13601 +y Fn(.\))863 18001 y Fm(9)1594 b(Implementing)399 b Fa(select)p +Fm(able)i(De)-24 b(vices)863 21139 y Fn(One)376 b(important)g(feature)f +(that)g(almost)g(e)-28 b(v)-17 b(ery)377 b(de)-28 b(vice)377 +b(dri)-28 b(v)-17 b(er)376 b(in)f(a)g(system)g(should)h(ha)-22 +b(v)-17 b(e)376 b(is)e(support)i(for)e(the)i Fo(select\(2\))863 +22467 y Fn(system)423 b(call.)780 b Fo(select)424 b Fn(allo)-28 +b(ws)423 b(clients)g(to)g(assemble)g(a)g(set)g(of)f(\002le)h +(descriptors)g(and)h(ask)f(to)g(be)h(noti\002ed)g(when)g(one)g(of)863 +23796 y(them)287 b(becomes)i(readable)f(or)e(writable.)372 +b(This)287 b(simple)f(feature)h(is)f(decepti)-28 b(v)-17 +b(ely)290 b(po)-28 b(werful\227it)287 b(allo)-28 b(ws)286 +b(clients)h(to)f(w)-11 b(ait)287 b(for)e(an)-17 b(y)863 +25124 y(number)336 b(of)e(a)h(set)f(of)g(possible)g(e)-28 +b(v)-17 b(ents)336 b(to)f(occur)-61 b(.)516 b(This)335 +b(is)e(fundamentally)k(dif)-28 b(ferent)334 b(than)i(\(for)d(e)-17 +b(xample\))336 b(a)f(blocking)h(read,)863 26452 y(which)246 +b(only)g(unblocks)h(on)f(one)g(kind)g(of)e(e)-28 b(v)-17 +b(ent.)335 b(In)245 b(this)f(section,)252 b(we')-11 b(ll)244 +b(describe)i(ho)-28 b(w)246 b(FUSD)g(can)g(be)g(used)g(to)f(create)h(a) +f(de)-28 b(vice)863 27781 y(whose)278 b(state)f(can)h(be)g(queried)g +(by)g(a)f(client')-61 b(s)277 b(call)g(to)g Fo(select\(2\))p +Fn(.)2524 29773 y(This)367 b(section)g(is)g(limited)f(to)h(a)h +(discussion)f(what)h(a)f(FUSD)h(dri)-28 b(v)-17 b(er)368 +b(writer)f(needs)h(to)f(kno)-28 b(w)369 b(to)e(implement)h(a)g +(selectable)863 31102 y(de)-28 b(vice.)346 b(Details)276 +b(of)h(the)g(FUSD)i(implementation)g(required)f(to)f(support)g(this)g +(feature)g(are)h(described)g(in)f(Section)i(11.1)863 +34935 y Fj(9.1)1329 b(P)-27 b(oll)333 b(state)f(and)g(the)f +Fc(poll)p 17203 34935 399 45 v 479 w(diff)h Fj(callback)863 +37674 y Fn(FUSD')-61 b(s)329 b(implementation)i(of)d(selectable)i(de) +-28 b(vices)330 b(depends)h(on)e(the)g(concept)i(of)e +Fk(poll)f(state)p Fn(.)498 b(A)328 b(\002le)h(descriptor')-61 +b(s)329 b(poll)f(state)863 39003 y(is)436 b(a)i(bitmask)g(that)f +(describes)h(its)e(current)i(properties\227readable,)480 +b(writable,)d(or)437 b(e)-17 b(xception)440 b(raised.)824 +b(These)439 b(three)f(states)863 40331 y(correspond)279 +b(to)e Fo(select\(2\))p Fn(')-61 b(s)278 b(three)f Fo(fd)p +18072 40331 333 45 v 399 w(set)p Fn(s.)343 b(FUSD)278 +b(has)f(constants)h(used)g(to)f(describe)h(these)g(states:)2524 +43209 y Fg(\017)554 b Fo(FUSD)p 6353 43209 V 399 w(NOTIFY)p +10736 43209 V 399 w(INPUT)p Fn(\227Input)279 b(is)d(a)-22 +b(v)-28 b(ailable;)278 b(a)g(read)f(will)g(not)g(block.)2524 +45423 y Fg(\017)554 b Fo(FUSD)p 6353 45423 V 399 w(NOTIFY)p +10736 45423 V 399 w(OUTPUT)p Fn(\227Output)279 b(space)f(is)f(a)-22 +b(v)-28 b(ailable;)278 b(a)f(write)g(will)f(not)i(block.)2524 +47637 y Fg(\017)554 b Fo(FUSD)p 6353 47637 V 399 w(NOTIFY)p +10736 47637 V 399 w(EXCEPT)p Fn(\227An)279 b(e)-17 b(xception)280 +b(has)d(occurred.)2524 50515 y(These)c(constants)f(can)h(be)g(combined) +h(with)e(C')-61 b(s)271 b(bitwise-or)g(operator)-61 b(.)343 +b(F)-17 b(or)272 b(e)-17 b(xample,)275 b(a)d(descriptor)h(that)e(is)g +(both)i(readable)863 51843 y(and)370 b(writable)e(is)g(e)-17 +b(xpressed)370 b(as)e Fo(FUSD)p 16660 51843 V 400 w(NOTIFY)p +21044 51843 V 399 w(INPUT)665 b(|)g(FUSD)p 29413 51843 +V 399 w(NOTIFY)p 33796 51843 V 399 w(OUTPUT)p Fn(.)369 +b(0)g(means)h(a)e(\002le)h(descriptor)g(is)863 53172 +y(not)278 b(readable,)g(not)g(writable,)f(and)h(not)f(in)g(the)h(e)-17 +b(xception)280 b(set.)2524 55164 y(F)-17 b(or)263 b(a)g(FUSD)g(de)-28 +b(vice)265 b(to)e(be)g(selectable,)k(its)261 b(dri)-28 +b(v)-17 b(er)263 b(must)g(implement)h(a)e(callback)j(called)f +Fo(poll)p 40529 55164 V 399 w(diff)p Fn(.)339 b(This)262 +b(callback)j(is)863 56493 y(v)-17 b(ery)239 b(dif)-28 +b(ferent)237 b(than)i(the)f(others;)250 b(it)237 b(is)f(not)i(a)f +(\223direct)h(line\224)h(between)g(the)f(client)g(and)g(the)g(dri)-28 +b(v)-17 b(er)238 b(as)f(is)g(the)h(case)g(with)f(a)h(call)f(such)863 +57821 y(as)323 b Fo(ioctl)p Fn(.)480 b(A)323 b(dri)-28 +b(v)-17 b(er')-61 b(s)323 b(response)g(to)g Fo(poll)p +19068 57821 V 399 w(diff)g Fn(is)f Fk(not)h Fn(the)g(return)g(v)-28 +b(alue)324 b(seen)f(by)h(a)e(client')-61 b(s)323 b(call)g(to)f +Fo(select)p Fn(.)481 b(When)863 59149 y(a)388 b(client)g(tries)f(to)g +Fo(select)i Fn(on)f(a)g(set)f(of)h(\002le)g(descriptors,)415 +b(the)388 b(k)-11 b(ernel)389 b(collects)f(the)g(responses)g(from)g +(all)f(the)h(appropriate)863 60478 y(callbacks\227)p +Fo(poll)364 b Fn(for)c(\002le)h(descriptors)g(managed)j(by)e(k)-11 +b(ernel)362 b(dri)-28 b(v)-17 b(ers,)382 b(and)363 b +Fo(poll)p 35062 60478 V 399 w(diff)e Fn(callbacks)i(those)e(managed)j +(by)863 61806 y(FUSD)278 b(dri)-28 b(v)-17 b(ers\227and)279 +b(synthesizes)f(all)f(of)f(that)i(information)f(into)h(the)f(return)g +(v)-28 b(alue)279 b(seen)f(by)f(the)h(client.)2524 63799 +y(FUSD)360 b(k)-11 b(eeps)361 b(a)f(cache)i(of)e(the)g(poll)g(state)g +(it)f(has)h(most)f(recently)i(recei)-28 b(v)-17 b(ed)363 +b(from)c(each)j(FUSD)f(de)-28 b(vice)362 b(dri)-28 b(v)-17 +b(er)-44 b(,)380 b(initially)863 65127 y(assumed)241 +b(to)f(be)h(0.)331 b(This)239 b(state)h(is)f(returned)i(to)f(clients)g +(trying)g(to)g Fo(select\(\))h Fn(on)f(de)-28 b(vices)242 +b(managed)h(by)d(those)h(dri)-28 b(v)-17 b(ers.)331 b(Under)863 +66455 y(certain)322 b(conditions,)333 b(FUSD)322 b(sends)f(a)g(query)h +(to)f(the)g(dri)-28 b(v)-17 b(er)322 b(in)f(order)g(to)g(ensure)h(that) +f(the)g(k)-11 b(ernel')-61 b(s)321 b(poll)g(state)g(cache)i(is)d(up)h +(to)863 67784 y(date.)451 b(This)313 b(query)h(tak)-11 +b(es)313 b(the)g(form)f(of)h(a)g Fo(poll)p 20014 67784 +V 399 w(diff)g Fn(callback)i(acti)-28 b(v)g(ation,)323 +b(which)314 b(is)e(gi)-28 b(v)-17 b(en)315 b(a)e(single)f(ar)-20 +b(gument:)417 b(the)313 b(poll)p 863 68732 20076 45 v +1738 69472 a Fe(12)2457 69785 y Fd(http://www)-58 b(.circlemud.or)-16 +b(g/jelson/softw)-9 b(are/emlog)25405 74071 y Fn(30)p +eop +%%Page: 31 34 +31 33 bop 863 2974 a Fn(state)245 b(that)f(FUSD)i(currently)g(has)f +(cached.)335 b(The)245 b(dri)-28 b(v)-17 b(er)246 b(should)g(consult)f +(its)e(internal)j(data)f(structures)f(to)h(determine)h(the)f(actual,) +863 4302 y(current)278 b(poll)f(state)g(\(i.e.,)e(whether)k(or)e(not)g +(b)-22 b(uf)-28 b(fers)277 b(ha)-22 b(v)-17 b(e)279 b(readable)g +(data\).)343 b(Then:)2524 7180 y Fg(\017)554 b Fn(If)273 +b(the)i(FUSD)h(cache)g(is)e(incorrect)h(\(that)f(is,)g(the)h(current)g +(true)g(poll)f(state)h(is)e(dif)-28 b(ferent)275 b(than)g(FUSD')-61 +b(s)275 b(cached)i(state\),)e(the)3631 8509 y(current)i(poll)g(state)g +(should)h(be)g(returned)g(immediately)-72 b(.)2524 10723 +y Fg(\017)554 b Fn(If)398 b(the)i(FUSD)h(cache)h(is)d(up)h(to)g(date)h +(\(that)e(is,)429 b(it)399 b(matches)i(the)f(real)g(current)h(state\),) +429 b(the)400 b(callback)i(should)f(sa)-22 b(v)-17 b(e)401 +b(the)3631 12051 y Fo(fusd)p 6353 12051 333 45 v 399 +w(file)p 9408 12051 V 399 w(info)248 b Fn(pointer)h(and)g(return)f +Fo(-FUSD)p 24152 12051 V 400 w(NOREPLY)p Fn(.)g(Later)-44 +b(,)254 b(when)c(the)e(poll)g(state)g(changes,)256 b(the)248 +b(dri)-28 b(v)-17 b(er)249 b(can)3631 13379 y(call)277 +b Fo(fusd)p 8228 13379 V 399 w(return\(\))h Fn(to)f(update)i(FUSD')-61 +b(s)277 b(cache.)2524 16257 y(In)442 b(other)i(w)-11 +b(ords,)484 b(when)445 b(a)e(dri)-28 b(v)-17 b(er')-61 +b(s)443 b Fo(poll)p 20338 16257 V 400 w(diff)g Fn(callback)i(is)d(acti) +-28 b(v)g(ated,)487 b(the)443 b(k)-11 b(ernel)444 b(is)e(ef)-28 +b(fecti)g(v)-17 b(ely)446 b(saying)e(to)f(the)863 17586 +y(dri)-28 b(v)-17 b(er)-44 b(,)304 b(\223Here)298 b(is)f(what)i(I)e +(think)h(the)h(current)f(poll)g(state)f(of)h(this)f(\002le)h +(descriptor)h(is;)307 b(let)297 b(me)h(kno)-28 b(w)300 +b(when)f(that)f(state)g Fk(c)-17 b(hang)-11 b(es)p Fn(.)-77 +b(\224)863 18914 y(The)373 b(dri)-28 b(v)-17 b(er)373 +b(can)g(either)f(respond)h(immediately)g(\(if)e(the)h(k)-11 +b(ernel')-61 b(s)372 b(cache)i(is)d(already)i(kno)-28 +b(wn)374 b(to)e(be)h(out)f(of)f(date\),)396 b(or)372 +b(return)863 20242 y Fo(-FUSD)p 4249 20242 V 400 w(NOREPLY)278 +b Fn(if)f(no)i(update)g(is)e(immediately)i(necessary)-72 +b(.)347 b(Later)-44 b(,)278 b(when)h(the)f(poll)g(state)g(changes)i +(\(for)d(e)-17 b(xample,)280 b(if)d(ne)-28 b(w)863 21571 +y(data)285 b(arri)-28 b(v)-17 b(es)284 b(that)f(mak)-11 +b(es)285 b(a)f(de)-28 b(vice)285 b(readable\),)i(the)d(dri)-28 +b(v)-17 b(er)284 b(can)h(used)f(its)f(sa)-22 b(v)-17 +b(ed)285 b Fo(fusd)p 35352 21571 V 399 w(file)p 38407 +21571 V 399 w(info)f Fn(pointer)g(to)g(send)g(a)g(poll)863 +22899 y(state)277 b(update)i(to)e(the)g(k)-11 b(ernel.)2524 +24892 y(When)336 b(a)g(FUSD)h(dri)-28 b(v)-17 b(er)336 +b(sends)g(a)g(poll)f(state)h(update,)352 b(it)334 b(might)i(\(or)f +(might)h(not\))g(ha)-22 b(v)-17 b(e)337 b(the)f(ef)-28 +b(fect)336 b(of)g(w)-11 b(aking)337 b(up)f(a)g(client)863 +26220 y(that)322 b(w)-11 b(as)323 b(block)-11 b(ed)324 +b(in)e Fo(select\(2\))p Fn(.)480 b(On)322 b(the)h(same)g(note,)334 +b(it')-61 b(s)320 b(w)-11 b(orth)323 b(reiterating)f(that)g(a)h +Fo(-FUSD)p 40693 26220 V 399 w(NOREPLY)g Fn(response)g(to)863 +27548 y(a)282 b Fo(poll)p 4358 27548 V 399 w(diff)g Fn(callback)h +Fk(does)f(not)g Fn(necessarily)g(block)h(the)e(client\227other)i +(descriptors)e(in)g(the)h(client')-61 b(s)281 b Fo(select)h +Fn(set)f(might)863 28877 y(be)d(readable,)h(for)d(e)-17 +b(xample.)863 32710 y Fj(9.2)1329 b(Recei)-13 b(ving)332 +b(a)g Fc(poll)p 13969 32710 399 45 v 478 w(diff)g Fj(r)-24 +b(equest)331 b(when)g(the)h(pr)-24 b(e)k(vious)331 b(one)h(has)f(not)h +(been)f(r)-24 b(etur)k(ned)330 b(y)-13 b(et)863 35449 +y Fn(Calls)307 b(such)i(as)e Fo(read)h Fn(and)h Fo(write)g +Fn(are)f(synchronous)i(from)d(the)h(standpoint)h(of)f(an)g(indi)-28 +b(vidual)309 b(client\227a)g(request)f(is)f(made,)863 +36778 y(and)343 b(the)g(requester)g(blocks)g(until)f(a)g(reply)h(is)e +(recei)-28 b(v)-17 b(ed.)541 b(This)342 b(means)h(that)f(there)h(can') +-20 b(t)343 b(e)-28 b(v)-17 b(er)343 b(be)g(more)g(than)g(a)f(single)h +Fo(read)863 38106 y Fn(request)268 b(outstanding)h(for)d(a)h(single)h +(client)f(at)g(a)g(time.)340 b(\(The)268 b(dri)-28 b(v)-17 +b(er)268 b(as)e(a)i(whole)g(may)g(be)g(k)-11 b(eeping)269 +b(track)e(of)g(man)-17 b(y)269 b(outstanding)863 39434 +y Fo(read)278 b Fn(requests)f(in)g(parallel,)g(b)-22 +b(ut)277 b(no)h(tw)-11 b(o)277 b(of)g(them)g(will)g(be)g(from)g(the)g +(same)h(client)f(\002le)h(descriptor)-61 b(.\))2524 41427 +y(As)288 b(we)h(mentioned)i(in)e(the)g(pre)-28 b(vious)290 +b(section,)j(the)c Fo(poll)p 25515 41427 333 45 v 399 +w(diff)g Fn(callback)i(is)d(dif)-28 b(ferent)289 b(from)f(other)i +(callbacks.)380 b(It)288 b(is)g(not)863 42755 y(part)324 +b(of)g(a)h(synchronous)h(request/reply)f(sequence)i(that)d(causes)h +(the)g(client)f(to)h(block.)485 b(It)324 b(is)f(also)h(an)h(interf)-11 +b(ace)325 b(to)f(the)g Fk(k)-11 b(ernel)p Fn(,)863 44084 +y(not)254 b(directly)f(to)h(the)f(client.)336 b(So,)258 +b(it)252 b Fk(is)h Fn(possible)g(to)g(recei)-28 b(v)-17 +b(e)256 b(a)d Fo(poll)p 27386 44084 V 399 w(diff)h Fn(request)g(while)f +(there)h(is)e(already)j(one)f(outstanding.)863 45412 +y(This)273 b(happens)i(if)d(the)h(k)-11 b(ernel')-61 +b(s)273 b(poll)g(state)g(cache)i(changes,)h(causing)e(it)e(to)h(notify) +g(the)g(dri)-28 b(v)-17 b(er)274 b(that)f(it)f(has)h(a)g(ne)-28 +b(w)274 b(cached)i(v)-28 b(alue.)2524 47404 y(This)276 +b(is)h(easy)g(to)g(handle;)i(the)e(client)h(should)g(simply)2247 +50283 y(1.)554 b(Destro)-11 b(y)440 b(the)g(old)h(\(no)-28 +b(w)441 b(out-of-date\))f Fo(poll)p 22346 50283 V 399 +w(diff)h Fn(request)g(using)f(the)h Fo(fusd)p 36766 50283 +V 399 w(destroy)g Fn(function)g(we)g(sa)-17 b(w)440 b(in)3631 +51611 y(Section)278 b(8.2.3.)2247 53825 y(2.)554 b(Either)277 +b(respond)h(to)f(or)g(sa)-22 b(v)-17 b(e)278 b(the)f(ne)-28 +b(w)279 b Fo(poll)p 21381 53825 V 399 w(diff)e Fn(request,)h(e)-17 +b(xactly)279 b(as)d(described)j(in)e(the)g(pre)-28 b(vious)279 +b(section.)2524 56703 y(The)f(ne)-17 b(xt)278 b(section)g(will)e(sho) +-28 b(w)278 b(an)f(e)-17 b(xample)280 b(of)d(this)f(technique.)863 +60536 y Fj(9.3)1329 b(Adding)331 b Fc(select)h Fj(support)f(to)i +Fc(pager.c)863 63275 y Fn(Gi)-28 b(v)-17 b(en)223 b(the)f(e)-17 +b(xplanation)225 b(of)c Fo(poll)p 14554 63275 V 399 w(diff)h +Fn(in)g(the)g(pre)-28 b(vious)222 b(sections,)233 b(it)221 +b(might)g(seem)h(that)g(implementing)h(a)f(selectable)h(de)-28 +b(vice)863 64604 y(is)239 b(a)g(daunting)j(task.)330 +b(It')-61 b(s)238 b(actually)j(not)f(as)f(bad)i(as)e(it)g +(sounds\227the)i(e)-17 b(xample)242 b(code)f(may)f(well)f(be)i(shorter) +e(than)h(its)e(e)-17 b(xplanation!)2524 66596 y(Program)359 +b(14)g(sho)-28 b(ws)359 b(the)f(implementation)j(of)d +Fo(poll)p 24277 66596 V 399 w(diff)h Fn(in)f Fo(pager.c)p +Fn(,)379 b(which)360 b(mak)-11 b(es)359 b(its)e(noti\002cation)j +(interf)-11 b(ace)863 67925 y(\()p Fo(/dev/pager/notify)p +Fn(\))320 b(selectable.)468 b(It)317 b(is)h(decomposed)j(into)d(a)h +(\223top)g(half)61 b(\224)318 b(and)i(\223bottom)f(half)61 +b(\224)319 b(function,)329 b(e)-17 b(xactly)320 b(as)863 +69253 y(we)352 b(did)f(for)g(the)h(blocking)h Fo(read)f +Fn(implementation)h(in)e(Program)h(12.)567 b(First,)368 +b(on)352 b(lines)f(1\22620,)371 b(we)352 b(see)f(the)h(the)f(callback)j +(for)863 70581 y Fo(poll)p 3585 70581 V 399 w(diff)313 +b Fn(callback)h(itself.)447 b(It)311 b(is)g(virtually)h(identical)h(to) +f(the)g Fo(read)h Fn(callback)h(in)e(Program)h(12.)449 +b(The)313 b(main)f(dif)-28 b(ference)314 b(is)25405 74071 +y(31)p eop +%%Page: 32 35 +32 34 bop 863 4495 50191 89 v 863 5479 a Fl(Pr)-20 b(ogram)280 +b(14)e Fn(pager)-61 b(.c)278 b(\(P)-17 b(art)277 b(4\):)343 +b(Supporting)279 b Fo(select\(2\))g Fn(by)e(implementing)i(a)e +Fo(poll)p 36925 5479 333 45 v 400 w(diff)g Fn(callback)p +863 5985 50191 45 v 365 6940 a Fi(1)1661 b Fo(ssize_t)665 +b(pager_notify_polldiff\(struct)k(fusd_file_info)e(*file,)22449 +8268 y(unsigned)e(int)g(cached_state\))2524 9597 y({)3852 +10925 y(struct)g(pager_client)h(*c)f(=)f(\(struct)i(pager_client)g(*\)) +f(file->private_data;)365 12253 y Fi(5)3852 13582 y Fo(if)f(\(c)h(==)g +(NULL\))5180 14910 y(return)h(-EINVAL;)3852 17567 y(/*)e(if)h(we're)g +(already)g(holding)h(a)e(polldiff)i(request)f(that)g(we)g(haven't)-133 +18895 y Fi(10)3653 b Fo(*)664 b(replied)i(to)e(yet,)h(destroy)h(the)e +(old)h(one)g(and)g(hold)f(onto)h(only)g(the)g(new)4516 +20223 y(*)f(one)h(*/)3852 21552 y(if)f(\(c->polldiff)j(!=)d(NULL\))h({) +5180 22880 y(fusd_destroy\(c->polldiff\);)5180 24208 +y(c->polldiff)h(=)f(NULL;)-133 25537 y Fi(15)2989 b Fo(})3852 +28193 y(c->polldiff)666 b(=)e(file;)3852 29522 y +(pager_notify_complete_polldiff\(c\);)3852 30850 y(return)h +(-FUSD_NOREPLY;)-133 32178 y Fi(20)1661 b Fo(})2524 34835 +y(void)664 b(pager_notify_complete_polldiff\(struct)671 +b(pager_client)666 b(*c\))2524 36164 y({)3852 37492 y(int)f +(curr_state,)h(cached_state;)-133 38820 y Fi(25)3852 +40149 y Fo(/*)e(if)h(there)g(is)g(no)f(outstanding)i(polldiff,)g(do)f +(nothing)g(*/)3852 41477 y(if)f(\(c)h(==)g(NULL)f(||)h(c->polldiff)h +(==)f(NULL\))5180 42805 y(return;)-133 45462 y Fi(30)2989 +b Fo(/*)664 b(figure)i(out)e(the)h("current")h(state:)f(i.e.)g(whether) +g(or)g(not)g(the)f(pager)4516 46790 y(*)g(is)h(readable)h(for)e(this)h +(client)g(based)g(on)g(the)g(last)g(page)f(it)h(saw)g(*/)3852 +48119 y(if)f(\(c->last_page_seen)k(<)c(last_page\))5180 +49447 y(curr_state)i(=)f(FUSD_NOTIFY_INPUT;)i(/*)d(readable)i(*/)3852 +50775 y(else)-133 52104 y Fi(35)4317 b Fo(curr_state)666 +b(=)f(0;)f(/*)h(not)f(readable)i(or)e(writable)i(*/)3852 +54760 y(/*)e(cached_state)j(is)d(what)h(the)g(kernel)g(*thinks*)h(the)e +(state)h(is)g(*/)3852 56089 y(cached_state)h(=)f +(fusd_get_poll_diff_cached_state\(c->polldiff\);)-133 +58746 y Fi(40)2989 b Fo(/*)664 b(if)h(the)g(state)g(is)f(not)h(what)g +(the)g(kernel)g(thinks)g(it)g(is,)f(notify)i(the)5844 +60074 y(kernel)g(of)e(the)h(change)g(*/)3852 61402 y(if)f(\(curr_state) +j(!=)d(cached_state\))j({)5180 62731 y(fusd_return\(c->polldiff,)i +(curr_state\);)5180 64059 y(c->polldiff)d(=)f(NULL;)-133 +65387 y Fi(45)2989 b Fo(})2524 66716 y(})p 863 68210 +V 25405 74071 a Fn(32)p eop +%%Page: 33 36 +33 35 bop 863 2974 a Fn(that)317 b(it)e(\002rst)h(checks)i(\(on)f(line) +g(12\))f(to)h(see)g(if)e(a)i Fo(poll)p 22128 2974 333 +45 v 399 w(diff)g Fn(request)g(is)e(already)j(outstanding)h(when)f(a)e +(ne)-28 b(w)318 b(request)f(comes)863 4302 y(in.)343 +b(If)276 b(so,)h(the)g(out-of-date)h(request)g(is)e(destro)-11 +b(yed)278 b(using)g Fo(fusd)p 26176 4302 V 399 w(destroy)p +Fn(,)g(as)e(we)i(described)h(in)d(Section)j(9.2.)2524 +6295 y(The)322 b(bottom)g(half)g(is)e(sho)-28 b(wn)323 +b(on)f(lines)g(22-46.)478 b(First,)331 b(on)322 b(lines)f(32\22635,)335 +b(it)320 b(computes)j(the)f(current)g(poll)g(state\227if)f(a)g(page)863 +7623 y(has)349 b(arri)-28 b(v)-17 b(ed)351 b(that)e(the)h(client)f +(hasn')-20 b(t)349 b(seen)h(yet,)367 b(the)350 b(\002le)f(is)f +(readable;)387 b(otherwise,)367 b(it)349 b(isn')-20 b(t.)558 +b(Ne)-17 b(xt,)368 b(the)349 b(dri)-28 b(v)-17 b(er)350 +b(compares)h(the)863 8951 y(current)262 b(poll)f(state)h(with)f(the)g +(poll)h(state)f(that)g(the)h(k)-11 b(ernel)262 b(has)g(cached.)340 +b(If)261 b(the)g(k)-11 b(ernel')-61 b(s)262 b(cache)h(is)e(out)g(of)h +(date,)j(the)c(current)h(state)863 10280 y(is)276 b(returned)i(to)f +(the)h(k)-11 b(ernel.)344 b(Otherwise,)277 b(it)f(does)i(nothing.)2524 +12272 y(As)242 b(with)g(the)h Fo(read)f Fn(callback)j(we)e(sa)-17 +b(w)242 b(pre)-28 b(viously)-72 b(,)251 b(notice)244 +b(that)e Fo(pager)p 31445 12272 V 399 w(notify)p 35828 +12272 V 400 w(complete)p 41540 12272 V 400 w(polldiff)h +Fn(is)f(called)863 13601 y(in)277 b(tw)-11 b(o)277 b(dif)-28 +b(ferent)277 b(cases:)2247 16338 y(1.)554 b(It)418 b(is)h(called)i +(immediately)g(from)e(the)i Fo(pager)p 22631 16338 V +399 w(notify)p 27014 16338 V 400 w(polldiff)f Fn(callback)i(itself.)770 +b(This)420 b(causes)g(the)g(current)3631 17666 y(poll)309 +b(state)f(to)h(be)h(returned)g(to)f(the)g(k)-11 b(ernel)310 +b(immediately)h(when)f(the)g(request)f(arri)-28 b(v)-17 +b(es)310 b(if)e(the)h(dri)-28 b(v)-17 b(er)310 b(already)g(kno)-28 +b(ws)311 b(the)3631 18995 y(k)-11 b(ernel')-61 b(s)277 +b(state)g(needs)h(to)f(be)g(updated.)2247 21138 y(2.)554 +b(It)256 b(is)g(called)i(when)g(ne)-28 b(w)259 b(data)e(arri)-28 +b(v)-17 b(es)258 b(that)f(causes)h(the)f(poll)h(state)e(to)h(change.) +339 b(Refer)258 b(back)g(to)f(Program)h(12)g(on)g(page)h(27;)3631 +22467 y(in)253 b(the)h(callback)h(that)f(recei)-28 b(v)-17 +b(es)255 b(ne)-28 b(w)254 b(pages,)259 b(notice)c(on)f(line)f(45)h +(that)g(the)g Fo(poll)p 34999 22467 V 399 w(diff)g Fn(completion)h +(function)f(is)f(called)3631 23795 y(alongside)278 b(the)g +Fo(read)f Fn(completion)i(function.)2524 26533 y(W)-44 +b(ith)282 b(this)g Fo(poll)p 9580 26533 V 399 w(diff)h +Fn(implementation,)k(it)282 b(is)g(possible)h(for)f(a)h(client)g(to)g +(open)i Fo(/dev/pager/notify)p Fn(,)i(and)d(block)863 +27861 y(in)262 b(a)h Fo(select\(2\))g Fn(system)f(call.)339 +b(If)261 b(another)i(client)g(writes)e Fo(page)i Fn(to)f +Fo(/dev/pager/input)p Fn(,)267 b(the)c(\002rst)e(client')-61 +b(s)262 b Fo(select)863 29189 y Fn(will)276 b(unblock,)j(indicating)g +(the)e(\002le)h(has)f(become)i(readable.)2524 31182 y(F)-17 +b(or)258 b(additional)g(e)-17 b(xample)260 b(code,)j(tak)-11 +b(e)258 b(a)f(look)i(at)e(the)h Fo(logring)g Fn(e)-17 +b(xample)260 b(program)e(we)g(\002rst)e(mentioned)k(in)d(Section)i +(8.3.)863 32510 y(It)276 b(also)h(supports)g Fo(select)h +Fn(by)g(implementing)h(a)e(similar)f Fo(poll)p 26819 +32510 V 399 w(diff)i Fn(callback.)863 36879 y Fm(10)1594 +b(P)-32 b(erf)-40 b(ormance)398 b(of)g(User)-59 b(-Space)398 +b(De)-24 b(vices)863 40017 y Fn(This)278 b(section)h(hasn')-20 +b(t)279 b(been)h(written)e(yet.)348 b(I)277 b(ha)-22 +b(v)-17 b(e)281 b(some)d(pretty)h(graphs)g(and)h(whatnot,)f(b)-22 +b(ut)279 b(no)g(time)f(to)h(write)f(about)h(them)g(here)863 +41345 y(before)f(the)f(release.)863 45714 y Fm(11)1594 +b(FUSD)399 b(Implementation)f(Notes)863 48852 y Fn(In)349 +b(this)f(section,)367 b(we)349 b(describe)g(some)h(of)e(the)h(details)g +(of)f(ho)-28 b(w)350 b(FUSD)g(is)e(implemented.)560 b(It')-61 +b(s)347 b(not)i(necessary)h(to)f(understand)863 50180 +y(these)253 b(details)g(in)g(order)g(to)g(use)g(FUSD.)g(Ho)-28 +b(we)g(v)-17 b(er)-44 b(,)260 b(these)253 b(notes)g(can)h(be)g(useful)f +(for)f(people)i(who)g(are)f(trying)g(to)g(understand)i(the)863 +51509 y(FUSD)278 b(frame)-28 b(w)-11 b(ork)278 b(itself\227hack)-11 +b(ers,)277 b(deb)-22 b(uggers,)279 b(or)e(the)g(generally)i(curious.) +863 55310 y Fj(11.1)1329 b(The)332 b(situation)g(with)g +Fc(poll)p 18449 55310 399 45 v 479 w(diff)863 58050 y +Fn(In-k)-11 b(ernel)368 b(de)-28 b(vice)370 b(dri)-28 +b(v)-17 b(ers)369 b(support)f(select)g(by)g(implementing)i(a)e +(callback)i(called)e Fo(poll)p Fn(.)616 b(This)368 b(dri)-28 +b(v)-17 b(er')-61 b(s)368 b(callback)h(is)e(sup-)863 +59378 y(posed)435 b(to)f(do)h(tw)-11 b(o)434 b(things.)814 +b(First,)471 b(it)433 b(should)i(return)f(the)h(current)f(state)g(of)g +(a)g(\002le)g(descriptor)-22 b(\227a)435 b(combination)h(of)e(being)863 +60706 y(readable,)351 b(writable,)e(or)334 b(ha)-22 b(ving)336 +b(e)-17 b(xceptions.)519 b(Second,)351 b(it)334 b(should)h(pro)-17 +b(vide)337 b(a)e(pointer)g(to)f(one)i(of)e(the)h(dri)-28 +b(v)-17 b(er')-61 b(s)335 b(internal)g(w)-11 b(ait)863 +62035 y(queues)264 b(that)e(will)g(be)g(a)-17 b(w)-11 +b(ak)g(ened)266 b(whene)-28 b(v)-17 b(er)266 b(the)c(state)g(changes.) +341 b(The)263 b Fo(poll)f Fn(call)h(itself)d(should)k(ne)-28 +b(v)-17 b(er)264 b(block\227it)f(should)g(just)863 63363 +y(instantaneously)279 b(report)e(what)h(the)g Fk(curr)-41 +b(ent)277 b Fn(state)g(is.)2524 65356 y(FUSD')-61 b(s)368 +b(implementation)h(of)f(selectable)h(de)-28 b(vices)369 +b(is)e(dif)-28 b(ferent,)390 b(b)-22 b(ut)368 b(attempts)g(to)f +(maintain)i(three)f(properties)g(that)g(we)863 66684 +y(thought)279 b(to)e(be)g(most)g(important)h(from)e(the)i(point)f(of)g +(vie)-28 b(w)278 b(of)f(a)g(client)h(using)f Fo(select)p +Fn(.)344 b(Speci\002cally:)2247 69421 y(1.)554 b(The)267 +b Fo(select\(2\))h Fn(call)e(itself)f(should)i(ne)-28 +b(v)-17 b(er)269 b(become)g(block)-11 b(ed.)341 b(F)-17 +b(or)267 b(e)-17 b(xample,)271 b(if)266 b(one)h(\002le)g(descriptor)g +(in)f(its)f(set)h(isn')-20 b(t)3631 70750 y(readable,)278 +b(that)f(shouldn')-20 b(t)278 b(pre)-28 b(v)-17 b(ent)280 +b(it)c(from)g(reporting)i(other)g(\002le)f(descriptors)g(that)g(are.) +25405 74071 y(33)p eop +%%Page: 34 37 +34 36 bop 2247 2974 a Fn(2.)554 b(If)319 b Fo(select\(2\))i +Fn(indicates)g(a)g(\002le)f(descriptor)h(is)e(readable)j(\(or)e +(writable\),)330 b(a)321 b(read)g(\(or)e(write\))h(on)h(that)f(\002le)h +(descriptor)3631 4302 y(shouldn')-20 b(t)277 b(block.)2247 +6516 y(3.)554 b(Clients)331 b(should)i(be)g(allo)-28 +b(wed)334 b(to)e(seamlessly)g Fo(select)h Fn(on)g(an)-17 +b(y)333 b(set)f(of)g(\002le)g(descriptors,)346 b(e)-28 +b(v)-17 b(en)335 b(if)c(that)h(set)g(contains)h(a)3631 +7844 y(mix)277 b(of)g(both)g(FUSD)i(and)f(non-FUSD)h(de)-28 +b(vices.)2524 10723 y(The)349 b(FUSD)h(k)-11 b(ernel)350 +b(module)g(k)-11 b(eeps)350 b(a)f(cache)i(of)d(the)h(dri)-28 +b(v)-17 b(er')-61 b(s)349 b(most)f(recent)i(answer)f(for)g(each)h +(\002le)f(descriptor)-44 b(,)366 b(initially)863 12051 +y(assumed)278 b(to)f(be)h(0.)343 b(When)278 b(the)g(k)-11 +b(ernel)278 b(module')-61 b(s)278 b(internal)f Fo(poll)h +Fn(callback)h(is)d(acti)-28 b(v)g(ated,)279 b(it:)2247 +14929 y(1.)554 b(Dispatches)330 b(a)f Fk(non-)p Fn(blocking)j +Fo(poll)p 18591 14929 333 45 v 399 w(diff)e Fn(to)f(the)h(associated)g +(user)-22 b(-space)330 b(dri)-28 b(v)-17 b(er)-44 b(,)343 +b(asking)330 b(for)e(a)i(cache)h(update\227if)3631 16257 +y(and)278 b(only)g(if)e(there)h(isn')-20 b(t)276 b(already)j(an)e +(outstanding)i(poll)e(dif)-28 b(f)277 b(request)g(out)h(that)f(has)g +(the)h(same)f(v)-28 b(alue.)2247 18471 y(2.)554 b(Immediately)278 +b(returns)f(the)g(cached)j(v)-28 b(alue)278 b(to)f(the)h(k)-11 +b(ernel)2524 21349 y(In)285 b(addition,)k(the)d(cached)i(v)-28 +b(alue')-61 b(s)286 b(readable)i(bit)d(is)g(cleared)i(on)f(e)-28 +b(v)-17 b(ery)287 b(read;)k(the)286 b(writable)f(bit)g(is)g(cleared)i +(on)f(e)-28 b(v)-17 b(ery)288 b(write.)863 22678 y(This)248 +b(is)f(necessary)j(to)e(pre)-28 b(v)-17 b(ent)250 b(old)e(poll)g +(state\227which)i(says)d(\223de)-28 b(vice)251 b(is)c +(readable\224\227from)k(being)e(returned)g(out)g(of)e(the)i(cache)863 +24006 y(when)410 b(it)e(might)h(be)h(in)-44 b(v)-28 b(alid.)739 +b(FUSD)410 b(assumes)f(that)g(an)-17 b(y)410 b(read)g(to)f(a)g(de)-28 +b(vice)411 b(can)f(mak)-11 b(e)410 b(it)e(potentially)i(unreadable.)741 +b(This)863 25334 y(mechanism)279 b(is)d(what)i(causes)g(an)f(updated)j +(poll)d(dif)-28 b(f)276 b(to)h(be)h(sent)f(to)g(a)g(client)g(before)h +(the)g(pre)-28 b(vious)278 b(one)g(has)g(been)g(returned.)2524 +27327 y(\(this)d(section)j(isn')-20 b(t)276 b(\002nished)j(yet;)e(f)-11 +b(anc)-17 b(y)278 b(time)f(diagrams)h(coming)h(someday\))863 +31160 y Fj(11.2)1329 b(Restartable)332 b(System)f(Calls)863 +33900 y Fn(No)278 b(time)e(to)h(write)g(this)f(section)i(yet...)863 +38300 y Fm(A)1594 b(Using)399 b Fa(strace)863 41438 y +Fn(This)277 b(section)h(hasn')-20 b(t)277 b(been)i(written)d(yet.)344 +b(Contrib)-22 b(utions)278 b(are)f(welcome.)25405 74071 +y(34)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/doc/fusd.tex b/doc/fusd.tex new file mode 100644 index 0000000..63e5b7e --- /dev/null +++ b/doc/fusd.tex @@ -0,0 +1,2013 @@ +% +% +% FUSD - Framework for User-Space Devices +% Programming Manual & Tutorial +% +% Jeremy Elson, (c) 2001 Sensoria Corporation, 2003 UCLA +% Released under open-source, BSD license +% See LICENSE file for full license +% +% $Id: fusd.tex,v 1.63 2003/08/20 22:00:55 jelson Exp $ + +\documentclass{article} +\addtolength{\topmargin}{-.5in} % repairing LaTeX's huge margins... +\addtolength{\textheight}{1in} % more margin hacking +\addtolength{\textwidth}{1.5in} +\addtolength{\oddsidemargin}{-0.75in} +\addtolength{\evensidemargin}{-0.75in} + +\usepackage{graphicx,float,alltt,tabularx} +\usepackage{wrapfig,floatflt} +\usepackage{amsmath} +\usepackage{latexsym} +\usepackage{moreverb} +\usepackage{times} +\usepackage{html} +%\usepackage{draftcopy} + +%\setcounter{bottomnumber}{3} +%\renewcommand{\topfraction}{0} +%\renewcommand{\bottomfraction}{0.7} +%\renewcommand{\textfraction}{0} +%\renewcommand{\floatpagefraction}{2.0} + +\renewcommand{\topfraction}{1.0} +\renewcommand{\bottomfraction}{1.0} +\renewcommand{\textfraction}{0.0} +\renewcommand{\floatpagefraction}{0.9} + +\floatstyle{ruled} +\newfloat{Program}{tp}{lop} + + +\title{FUSD: +A Linux {\bf F}ramework for {\bf U}ser-{\bf S}pace {\bf D}evices} + +\author{Jeremy Elson\\ +jelson@circlemud.org\\ +http://www.circlemud.org/\tilde{}jelson/software/fusd} +\date{19 August 2003, Documentation for FUSD 1.10} + +\begin{document} + +%%%%%%%%%%%%%%%%%%%%%%%%% Title Page %%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{center} +\begin{latexonly}\vspace*{2in}\end{latexonly} +{\Huge FUSD:} \\ +\vspace{2\baselineskip} +{\huge A Linux {\bf F}ramework for {\bf U}ser-{\bf S}pace {\bf D}evices} + +\begin{latexonly}\vspace{2in}\end{latexonly} +\vspace{\baselineskip} + +\vfill + +{\large Jeremy Elson \\ +\begin{latexonly}\vspace{.5\baselineskip}\end{latexonly}} +\vspace{\baselineskip} +{\tt jelson@circlemud.org\\ +http://www.circlemud.org/jelson/software/fusd} + +\vspace{2\baselineskip} +19 August 2003\\ +Documentation for FUSD 1.10\\ + +\end{center} +\thispagestyle{empty} +\clearpage + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{latexonly} +\pagenumbering{roman} + +\tableofcontents +\bigskip +\listof{Program}{List of Example Programs} +\setlength{\parskip}{10pt} + +\clearpage +\end{latexonly} + +% This resets the page counter to 1 +\pagenumbering{arabic} +\addtolength{\parskip}{0.5\baselineskip} + +\section{Introduction} + +\subsection{What is FUSD?} + +FUSD (pronounced {\em fused}) is a Linux framework for proxying device +file callbacks into user-space, allowing device files to be +implemented by daemons instead of kernel code. Despite being +implemented in user-space, FUSD devices can look and act just like any +other file under /dev which is implemented by kernel callbacks. + +A user-space device driver can do many of the things that kernel +drivers can't, such as perform a long-running computation, block while +waiting for an event, or read files from the file system. Unlike +kernel drivers, a user-space device driver can {\em use other device +drivers}---that is, access the network, talk to a serial port, get +interactive input from the user, pop up GUI windows, or read from +disks. User-space drivers implemented using FUSD can be much easier +to debug; it is impossible for them to crash the machine, are easily +traceable using tools such as {\tt gdb}, and can be killed and +restarted without rebooting even if they become corrupted. FUSD +drivers don't have to be in C---Perl, Python, or any other language +that knows how to read from and write to a file descriptor can work +with FUSD. User-space drivers can be swapped out, whereas kernel +drivers lock physical memory. + +Of course, as with almost everything, there are trade-offs. +User-space drivers are slower than kernel drivers because they require +three times as many system calls, and additional memory copies (see +section~\ref{performance}). User-space drivers can not receive +interrupts, and do not have the full power to modify arbitrary kernel +data structures as kernel drivers do. Despite these limitations, we +have found user-space device drivers to be a powerful programming +paradigm with a wide variety of uses (see Section~\ref{use-cases}). + +FUSD is free software, distributed under a GPL-compatible license (the +``new'' BSD license, with the advertising clause removed). + +\subsection{How does FUSD work?} + +FUSD drivers are conceptually similar to kernel drivers: a set of +callback functions called in response to system calls made on file +descriptors by user programs. FUSD's C library provides a device +registration function, similar to the kernel's {\tt +devfs\_register\_chrdev()} function, to create new devices. {\tt +fusd\_register()} accepts the device name and a structure full of +pointers. Those pointers are callback functions which are called in +response to certain user system calls---for example, when a process +tries to open, close, read from, or write to the device file. The +callback functions should conform to the standard definitions of POSIX +system call behavior. In many ways, the user-space FUSD callback +functions are identical to their kernel counterparts. + +Perhaps the best way to show what FUSD does is by example. +Program~\ref{helloworld.c} is a simple FUSD device driver. When the +program is run, a device called {\tt /dev/hello-world} appears under +the {\tt /dev} directory. If that device is read (e.g., using {\tt +cat}), the read returns {\tt Hello, world!} followed by an EOF. +Finally, when the driver is stopped (e.g., by hitting Control-C), the +device file disappears. + +\begin{Program} +\listinginput[5]{1}{helloworld.c.example} +\caption{helloworld.c: A simple program using FUSD to + create {\tt /dev/hello-world}} +\label{helloworld.c} +\end{Program} + +On line 40 of the source, we use {\tt fusd\_register()} to create the +{\tt /dev/hello-world} device, passing pointers to callbacks for the +open(), close() and read() system calls. (Lines 36--39 use the GNU C +extension that allows initializer field naming; the 2.4 series of +Linux kernels use also that extension for the same purpose.) The +``Hello, World'' read() callback itself is virtually identical to what +a kernel driver for this device would look like. It can inspect and +modify the user's file pointer, copy data into the user-provided +buffer, control the system call return value (either positive, EOF, or +error), and so forth. + +The proxying of kernel system calls that makes this kind of program +possible is implemented by FUSD, using a combination of a kernel +module and cooperating user-space library. The kernel module +implements a character device, {\tt /dev/fusd}, which is used as a +control channel between the two. fusd\_register() uses this channel +to send a message to the FUSD kernel module, telling the name of the +device the user wants to register. The kernel module, in turn, +registers that device with the kernel proper using devfs. devfs and +the kernel don't know anything unusual is happening; it appears from +their point of view that the registered devices are simply being +implemented by the FUSD module. + +Later, when kernel makes a callback due to a system call (e.g.\ when +the character device file is opened or read), the FUSD kernel module's +callback blocks the calling process, marshals the arguments of the +callback into a message and sends it to user-space. Once there, the +library half of FUSD unmarshals it and calls whatever user-space +callback the FUSD driver passed to fusd\_register(). When that +user-space callback returns a value, the process happens in reverse: +the return value and its side-effects are marshaled by the library +and sent to the kernel. The FUSD kernel module unmarshals this +message, matches it up with a corresponding outstanding request, and +completes the system call. The calling process is completely unaware +of this trickery; it simply enters the kernel once, blocks, unblocks, +and returns from the system call---just as it would for any other +blocking call. + +One of the primary design goals of FUSD is {\em stability}. It should +not be possible for a FUSD driver to corrupt or crash the kernel, +either due to error or malice. Of course, a buggy driver itself may +corrupt itself (e.g., due to a buffer overrun). However, strict error +checking is implemented at the user-kernel boundary which should +prevent drivers from corrupting the kernel or any other user-space +process---including the errant driver's own clients, and other FUSD +drivers. + + +\subsection{What FUSD {\em Isn't}} + +FUSD looks similar to certain other Linux facilities that are already +available. It also skirts near a few of the kernel's hot-button +political issues. So, to avoid confusion, we present a list of +things that FUSD is {\em not}. + +\begin{itemize} + +\item {\bf A FUSD driver is not a kernel module.} Kernel modules +allow---well, modularity of kernel code. They let you insert and +remove kernel modules dynamically after the kernel boots. However, +once inserted, the kernel modules are actually part of the kernel +proper. They run in the kernel's address space, with all the same +privileges and restrictions that native kernel code does. A FUSD +device driver, in contrast, is more similar to a daemon---a program +that runs as a user-space process, with a process ID. + +\item {\bf FUSD is not, and doesn't replace, devfs.} When a FUSD +driver registers a FUSD device, it automatically creates a device file +in {\tt /dev}. However, FUSD is not a replacement for devfs---quite +the contrary, FUSD creates those device files by {\em using} devfs. +In a normal Linux system, only kernel modules proper---not user-space +programs---can register with devfs (see above). + +\item {\bf FUSD is not UDI.} UDI, the \htmladdnormallinkfoot{Uniform +Driver Interface}{http://www.projectudi.org}, aims to create a binary +API for drivers that is uniform across operating systems. It's true +that FUSD could conceivably be used for a similar purpose (inasmuch as +it defines a system call messaging structure). However, this was not +the goal of FUSD as much as an accidental side effect. We do not +advocate publishing drivers in binary-only form, even though FUSD does +make this possible in some cases. + +\item {\bf FUSD is not an attempt to turn Linux into a microkernel.} +We aren't trying to port existing drivers into user-space for a +variety of reasons (not the least of which is performance). We've +used FUSD as a tool to write new drivers that are much easier from +user-space than they would be in the kernel; see +Section~\ref{use-cases} for use cases. + + +\end{itemize} + + +\subsection{Related Work} + +FUSD is a new implementation, but certainly not a new idea---the +theory of its operation is the same as any microkernel operating +system. A microkernel (roughly speaking) is one that implements only +very basic resource protection and message passing in the kernel. +Implementation of device drivers, file systems, network stacks, and so +forth are relegated to userspace. Patrick Bridges maintains a list of +such \htmladdnormallinkfoot{microkernel operating systems}{http://www.cs.arizona.edu/people/bridges/os/microkernel.html}. + +Also related is the idea of a user-space filesystem, which has been +implemented in a number of contexts. Some examples include Klaus +Schauser's \htmladdnormallinkfoot{UFO +Project}{http://www.cs.ucsb.edu/projects/ufo/index.html} for Solaris, +and Jeremy Fitzhardinge's (no longer maintained) +\htmladdnormallinkfoot{UserFS}{http://www.goop.org/~jeremy/userfs/} +for Linux 1.x. The \htmladdnormallinkfoot{UFO +paper}{http://www.cs.ucsb.edu/projects/ufo/97-usenix-ufo.ps} is also +notable because it has a good survey of similar projects that +integrate user-space code with system calls. + +\subsection{Limitations and Future Work} + +In its current form, FUSD is useful and has proven to be quite +stable---we use it in production systems. However, it does have some +limitations that could benefit from the attention of developers. +Contributions to correct any of these deficiencies are welcomed! +(Many of these limitations will not make sense without having read the +rest of the documentation first.) + + +\begin{itemize} +\item Currently, FUSD only supports implementation of character +devices. Block devices and network devices are not supported yet. + +\item The kernel has 15 different callbacks in its {\tt +file\_operations} structure. The current version of FUSD does not +proxy some of the more obscure ones out to userspace. + +\item Currently, all system calls that FUSD understands are proxied +from the FUSD kernel module to userspace. Only the userspace library +knows which callbacks have actually been registered by the FUSD +driver. For example, the kernel may proxy a write() system call to +user-space even if the driver has not registered a write() callback +with fusd\_register(). + +fusd\_register() should, but currently does not, tell the kernel +module which callbacks it wants to receive, per-device. This will be +more efficient because it will prevent useless system calls for +unsupported operations. In addition, it will lead to more logical and +consistent behavior by allowing the kernel to use its default +implementations of certain functions such as writev(), instead of +being fooled into thinking the driver has an implementation of it in +cases where it doesn't. + +\item It should be possible to write a FUSD library in any language +that supports reads and writes on raw file descriptors. In the +future, it might be possible to write FUSD device drivers in a variety +of languages---Perl, Python, maybe even Java. However, the current +implementation has only a C library. + +\item It's possible for drivers that use FUSD to deadlock---for +example, if a driver tries to open itself. In this one case, FUSD +returns {\tt -EDEADLOCK}. However, deadlock protection should be +expanded to more general detection of cycles of arbitrary length. + +\item FUSD should provide a /proc interface that gives debugging and +status information, and allows parameter tuning. + +\item FUSD was written with efficiency in mind, but a number of +important optimizations have not yet been implemented. Specifically, +we'd like to try to reduce the number of memory copies by using a +buffer shared between user and kernel space to pass messages. + +\item FUSD currently requires devfs, which is used to dynamically +create device files under {\tt /dev} when a FUSD driver registers +itself. This is, perhaps, the most convenient and useful paradigm +for FUSD. However, some users have asked if it's possible to use FUSD +without devfs. This should be possible if FUSD drivers bind to device +major numbers instead of device file names. + +\end{itemize} + + + + +\subsection{Author Contact Information and Acknowledgments} + +The original version of FUSD was written by Jeremy Elson +\htmladdnormallink{(jelson@circlemud.org)}{mailto:jelson@circlemud.org} +and Lewis Girod at Sensoria Corporation. +Sensoria no longer maintains public releases of FUSD, but the same +authors have since forked the last public release and continue to +maintain FUSD from the University of California, Los Angeles. + +If you have bug reports, patches, suggestions, or any other comments, +please feel free to contact the authors. + +FUSD has two +\htmladdnormallinkfoot{SourceForge}{http://www.sourceforge.net}-host +mailing lists: a low-traffic list for announcements ({\tt fusd-announce}) +and a list for general discussion ({\tt fusd-devel}). Subscription +information for both lists is available at the +\htmladdnormallink{SourceForge's FUSD mailing list +page}{http://sourceforge.net/mail/?group_id=36326}. + +For the latest releases and information about FUSD, please see the +\htmladdnormallinkfoot{official FUSD home +page}{http://www.circlemud.org/jelson/software/fusd}. + + + +\subsection{Licensing Information} + +FUSD is free software, distributed under a GPL-compatible license (the +``new'' BSD license, with the advertising clause removed). The +license is enumerated in its entirety below. + +Copyright (c) 2001, Sensoria Corporation; (c) 2003 University of +California, Los Angeles. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +\begin{itemize} +\item Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +\item Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +\item Neither the names of Sensoria Corporation or UCLA, nor the +names of other contributors may be used to endorse or promote products +derived from this software without specific prior written permission. +\end{itemize} + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\section{Why use FUSD?} +\label{use-cases} + +One basic question about FUSD that one might ask is: what is it good +for? Why use it? In this section, we describe some of the situations +in which FUSD has been the solution for us. + +\subsection{Device Driver Layering} + +A problem that comes up frequently in modern operating systems is +contention for a single resource by multiple competing processes. In +UNIX, it's the job of a device driver to coordinate access to such +resources. By accepting requests from user processes and (for +example) queuing and serializing them, it becomes safe for processes +that know nothing about each other to make requests in parallel to the +same resource. Of course, kernel drivers do this job already, but +they typically operate on top of hardware directly. However, kernel +drivers can't easily be layered on top of {\em other device drivers}. + +For example, consider a device such as a modem that is connected to a +host via a serial port. Let's say we want to implement a device +driver that allows multiple users to dial the telephone (e.g., {\tt +echo 1-310-555-1212 > /dev/phone-dialer}). Such a driver should be +layered {\em on top of} the serial port driver---that is, it most +likely wants to write to {\tt /dev/ttyS0}, not directly to the UART +hardware itself. + +While it is possible to write to a logical file from within a kernel +device driver, it is both tricky and considered bad practice. In the +\htmladdnormallinkfoot{words of kernel hacker Dick Johnson} +{http://www.uwsg.indiana.edu/hypermail/linux/kernel/0005.3/0061.html}, +``You should never write a [kernel] module that requires reading or +writing to any logical device. The kernel is the thing that translates +physical I/O to logical I/O. Attempting to perform logical I/O in the +kernel is effectively going backwards.'' + +With FUSD, it's possible to layer device drivers because the driver is +a user-space process, not a kernel module. A FUSD implementation of +our hypothetical {\tt /dev/phone-dialer} can open {\tt /dev/ttyS0} +just as any other process would. + +Typically, such layering is accomplished by system daemons. For +example, the {\tt lpd} daemon manages printers at a high level. Since +it is a user-space process, it can access the physical printer devices +using kernel device drivers (for example, using printer or network +drivers). There a number of advantages to using FUSD instead: +\begin{itemize} +\item Using FUSD, a daemon/driver can create a standard device file +which is accessible by any program that knows how to use the POSIX +system call interface. Some trickery is possible using named +pipes and FIFOs, but quickly becomes difficult because of multiplexed +writes from multiple processes. +\item FUSD drivers receive the UID, GID, and process ID along with +every file operation, allowing the same sorts of security policies to +be implemented as would be possible with a real kernel driver. In +contrast, writes to a named pipe, UDP, and so forth are ``anonymous.'' +\end{itemize} + +\subsection{Use of User-Space Libraries} + +Since a FUSD driver is just a regular user-space program, it can +naturally use any of the enormous body of existing libraries that +exist for almost any task. FUSD drivers can easily incorporate user +interfaces, encryption, network protocols, threads, and almost +anything else. In contrast, porting arbitrary C code into the kernel +is difficult and usually a bad idea. + +\subsection{Driver Memory Protection} + +Since FUSD drivers run in their own process space, the rest of the +system is protected from them. A buggy or malicious FUSD driver, at +the very worst, can only corrupt itself. It's not possible for it to +corrupt the kernel, other FUSD drivers, or even the processes that are +using its devices. In contrast, a buggy kernel module can bring down +any process in the system, or the entire kernel itself. + +\subsection{Giving libraries language independence and standard +notification interfaces} + +One particularly interesting application of FUSD that we've found very +useful is as a way to let regular user-space libraries export device +file APIs. For example, imagine you had a library which factored +large composite numbers. Typically, it might have a C +interface---say, a function called {\tt int\ *factorize(int\ bignum)}. +With FUSD, it's possible to create a device file interface---say, a +device called {\tt /dev/factorize} to which clients can {\tt write(2)} +a big number, then {\tt read(2)} back its factors. + +This may sound strange, but device file APIs have at least three +advantages over a typical library API. First, it becomes much more +language independent---any language that can make system calls can +access the factorization library. Second, the factorization code is +running in a different address space; if it crashes, it won't crash or +corrupt the caller. Third, and most interestingly, it is possible to +use {\tt select(2)} to wait for the factorization to complete. {\tt +select(2)} would make it easy for a client to factor a large number +while remaining responsive to {\em other} events that might happen in +the meantime. In other words, FUSD allows normal user-space libraries +to integrate seamlessly with UNIX's existing, POSIX-standard event +notification interface: {\tt select(2)}. + +\subsection{Development and Debugging Convenience} + +FUSD processes can be developed and debugged with all the normal +user-space tools. Buggy drivers won't crash the system, but instead +dump cores that can be analyzed. All of your favorite visual +debuggers, memory bounds checkers, leak detectors, profilers, and +other tools can be applied to FUSD drivers as they would to any other +program. + +\section{Installing FUSD} + +This section describes the installation procedure for FUSD. It +assumes a good working knowledge of Linux system administration. + + +\subsection{Prerequisites} + +Before installing FUSD, make sure you have all of the following +packages installed and working correctly: + +\begin{itemize} +\item {\bf Linux kernel 2.4.0 or later}. FUSD was developed under +2.4.0 and should work with any kernel in the 2.4 series. + +\item {\bf devfs installed and running.} FUSD dynamically registers +devices using devfs, the Linux device filesystem by Richard Gooch. +For FUSD to work, devfs must be installed and running on your system. +For more information about devfs installation, see the +\htmladdnormallinkfoot{devfs home +page}{http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html}. + +Note that some distributions make installation devfs easier. RedHat +7.1, for example, already has all of the necessary daemons and +configuration changes integrated. devfs can be installed simply by +recompiling the kernel with devfs support enabled and reconfiguring +LILO to pass {\tt "devfs=mount"} to the kernel. +\end{itemize} + + +\subsection{Compiling FUSD as a Kernel Module} + +Before compiling anything, take a look at the Makefile in FUSD's home +directory. Adjust any constants that are not correct. In particular, +make sure {\tt KERNEL\_HOME} correctly reflects the place where your +kernel sources are installed, if they aren't in the default location +of {\tt /usr/src/linux}. + +Then, type {\tt make}. It should generate a directory whose name +looks something like {\tt obj.i686-linux}, or some variation depending +on your architecture. Inside of that directory will be a number of +files, including: +\begin{itemize} +\item kfusd.o -- The FUSD kernel module +\item libfusd.a -- The C library used to talk to the kernel module +\item Example programs -- linked against libfusd.a +\end{itemize} + +Compilation of the kernel module will fail if the dependencies +described in the previous section are not satisfied. The module must +be compiled again Linux kernel must be v2.4.0 or later, and the kernel +must have devfs support enabled. + + +\subsection{Testing and Troubleshooting} + +Once everything has been compiled, give it a try to see if it actually +does something. First, use {\tt insmod} to insert the FUSD kernel +module, e.g. {\tt insmod obj.i686-linux/kfusd.o}. A greeting message +similar to ``{\tt fusd: starting, Revision: 1.50}'' should appear in +the kernel log (accessed using the {\tt dmesg} command, or by typing +{\tt cat /proc/kmsg}). You can verify the module has been inserted by +typing {\tt lsmod}, or alternatively {\tt cat /proc/modules}. + +Once the module has been inserted successfully, trying running the +{\tt helloworld} example program. When run, the program should print +a greeting message similar to {\tt /dev/hello-world should now exist - +calling fusd\_run}. This means everything is working; the daemon is +now blocked, waiting for requests to the new device. From another +shell, type {\tt cat /dev/hello-world}. You should see {\tt Hello, +world!} printed in response. Try killing the test program; the +corresponding device file should disappear. + +If nothing seems to be working, try looking at the kernel message log +(type {\tt dmesg} or {\tt cat /proc/kmsg}) to see if there are any +errors. If nothing seems obviously wrong, try turning on FUSD kernel +module debugging by defining {\tt CONFIG\_FUSD\_DEBUG} in kfusd.c, +then recompiling and reinserting the module. + + +\subsection{Installation} + +Typing {\tt make install} will copy the FUSD library, header files, +and man pages into {\tt /usr/local}. The FUSD kernel module is {\em +not} installed automatically because of variations among different +Linux distributions in how this is accomplished. You may want to +arrange to have the module start automatically on boot by (for +example) copying it into {\tt /lib/modules/your-kernel-version}, and +adding it to {\tt /etc/modules.conf}. + + +\subsection{Making FUSD Part of the Kernel Proper} + +The earlier instructions, by default, create a FUSD kernel module. +If desired, it's also very easy to build FUSD right into the kernel, +instead: +\begin{enumerate} +\item Unpack the 2.4 kernel sources and copy all the files in the {\tt +include} and {\tt kfusd} directories into your kernel source tree, +under {\tt drivers/char}. For example, if FUSD is in +your home directory, and your kernel is in {\tt /usr/src/linux}: +\begin{verbatim} + cp ~/fusd/kfusd/* ~/fusd/include/* /usr/src/linux/drivers/char +\end{verbatim} + +\item Apply the patch found in FUSD's {\tt patches} directory to your +kernel source tree. For example: +\begin{verbatim} + cd /usr/src/linux + patch -p0 < ~/fusd/patches/fusd-inkernel.patch +\end{verbatim} +The FUSD in-kernel patch doesn't actually change any kernel sources +proper; it just adds FUSD to the kernel configuration menu and +Makefile. +\item Using your kernel configurator of choice (e.g. {\tt make +menuconfig}), turn on the FUSD options. It will be under the +``Character devices'' menu. +\item Build and install the kernel as usual. +\end{enumerate} + + +\section{Basic Device Creation} + +Enough introduction---it's time to actually create a basic device +driver using FUSD! + +This following sections will illustrate various techniques using +example programs. To save space, interesting excerpts are shown +instead of entire programs. However, the {\tt examples} directory +of the FUSD distribution contains all the examples in their +entirety. They can actually be compiled and run on a system with the +FUSD kernel module installed. + +Where this text refers to example program line numbers, it refers to +the line numbers printed alongside the excerpts in the manual---not +the line numbers of the actual programs in the {\tt examples} +directory. + + +\subsection{Using {\tt fusd\_register} to create a new device} +\label{using-fusd-register} + +We saw an example of a simple driver, helloworld.c, in +Program~\ref{helloworld.c} on page~\pageref{helloworld.c}. Let's go +back and examine that program now in more detail. + +The FUSD ball starts rolling when the {\tt fusd\_register} function is +called, as shown on line 40. This function tells the FUSD kernel +module: +\begin{itemize} +\item {\tt char *name}---The name of the device being created. The +prefix (such as {\tt /dev/}) must match the location where devfs has +been mounted. Names containing slashes (e.g., {\tt +/dev/my-devices/dev1}) are legal; devfs creates subdirectories +automatically. +\item {\tt mode\_t mode}---The device's default permissions. This is +usually specified using an octal constant with a leading 0---{\tt 0666} +(readable and writable by everyone) instead of the incorrect decimal +constant {\tt 666}. +\item {\tt void *device\_info}---Private data that should be passed to +callback functions for this device. The use of this field is +described in Section~\ref{device-info}. +\item {\tt struct fusd\_file\_operations *fops}---A structure containing +pointers to the callback functions that should be called by FUSD +in response to certain events. +\end{itemize} + +If device registration is successful, {\tt fusd\_register} returns a +{\em device handle}---a small integer $\ge0$. On errors, it returns +-1 and sets the global variable {\tt errno} appropriately. In +reality, the device handle you get is a plain old file descriptor, +as we'll see in Section~\ref{selecting}. + +Although Program~\ref{helloworld.c} only calls {\tt fusd\_register} +once, it can be called multiple times if the FUSD driver is handling +more than one device as we'll see in Program~\ref{drums.c}. + +There is intentional similarity between {\tt fusd\_register()} and the +kernel's device registration functions, such as {\tt +devfs\_register()} and {\tt register\_chrdev()}. In many ways, FUSD's +interface is meant to mirror the kernel interface as closely as +possible. + +The {\tt fusd\_file\_operations} structure, defined in {\tt fusd.h}, +contains a list of callbacks that are used in response to different +system calls executed on a file. It is similar to the kernel's {\tt +file\_operations} structure, accepting callbacks for system calls such +as {\tt open()}, {\tt close()}, {\tt read()}, {\tt write()}, and {\tt +ioctl()}. For the most part, the prototypes of FUSD file operation +callbacks are the same as their kernel cousins, with one important +exception. The first argument of FUSD callbacks is always a pointer +to a {\tt fusd\_file\_info} structure; it contains information that +can be used to identify the file. This structure is used instead of +the kernel's {\tt file} and {\tt inode} structures, and will be +described in more detail later. + +In lines 35--38 of Program~\ref{helloworld.c}, we create and +initialize a {\tt fusd\_file\_operations} structure. A GCC-specific C +extension allows us to name structure fields explicitly in the +initializer. This style may look strange, but it guards against +errors in the future in case the order of fields in the structure ever +changes. The 2.4 kernel series uses the same trick. + +After calling {\tt fusd\_register()} on line 40, the example program +calls {\tt fusd\_run()} on line 44. This function turns control over +to the FUSD framework. fusd\_run blocks the driver until one of the +devices it registered needs to be serviced. Then, it calls the +appropriate callback and blocks again until the next event. + +Now, imagine that a user types {\tt cat /dev/hello-world}. What +happens? Recall first what the {\tt cat} program itself does: opens a +file, reads from it until it receives an EOF (printing whatever it +reads to stdout), then closes it. {\tt cat} works the same way +regardless of what it's reading---be it a a FUSD device, a regular +file, a serial port, or anything else. The {\tt strace} program is a +great way to see this in action; see Appendix~\ref{strace} for +details. + +\subsection{The {\tt open} and {\tt close} callbacks} +\label{open-close} + +The first two callbacks that most drivers typically implement are {\tt +open} and {\tt close}. Each of these two functions are passed just +one argument---the {\tt fusd\_file\_info} structure that describes the +instance of the file being opened or closed. Use of the information +in that structure will be covered in more detail in +Section~\ref{fusd-file-info}. + +The semantics of an {\tt open} callback's return value are exactly the +same as inside the kernel: +\begin{itemize} +\item 0 means success, and the file is opened. If the file is allowed +to open, the kernel returns a valid file descriptor to the client. +Using that descriptor, other callbacks may be called for that file, +including (at least) a {\tt close} callback. + +\item A negative number indicates a failure, and that the file should +not be opened. Such return values should {\em always} be the +specified as a negative {\tt errno} value such as {\tt -EPERM}, {\tt +-EBUSY}, {\tt -ENODEV}, {\tt -ENOMEM}, and so on. For example, if the +callback returns {\tt -EPERM}, the caller's {\tt open()} will return +-1, with {\tt errno} set to {\tt EPERM}. A complete list of possible +return values can be found in the Linux kernel sources, under {\tt +include/asm/errno.h}. +\end{itemize} + +If an {\tt open} callback returns 0 (success), a driver is {\em +guaranteed} to receive exactly one {\tt close} callback for that file +later. By the same token, the close callback {\em will not} be called +if the open fails. Therefore, {\tt open} callbacks that can return +failure must be sure to deallocate any resources they might have +allocated before returning a failure. + +Let's return to our example in Program~\ref{helloworld.c}, which +creates the {\tt /dev/hello-world} device. If a user types {\tt cat +/dev/hello-world}, {\tt cat} will will use the {\tt open(2)} system +call to open the file. FUSD will then proxy that system call to the +driver and activate the callback that was registered as the {\tt open} +callback. Recall from line 36 of Program~\ref{helloworld.c} that we +registered {\tt do\_open\_or\_close}, which appears on line 8. + +In {\tt helloworld.c}, the {\tt open} callback always returns 0, or +success. However, in a real driver, something more interesting will +probably happen---permissions checks, memory allocation for +state-keeping, and so forth. The corresponding {\em de}-allocation of +those resources should occur in the {\tt close} callback, which is +called when a user application calls {\tt close} on their file +descriptor. {\tt close} callbacks are allowed to return error values, +but this does not prevent the file from actually closing. + + + +\subsection{The {\tt read} callback} +\label{read-callback} + +Returning to our {\tt cat /dev/hello-world} example, what happens +after the {\tt open} is successful? Next, {\tt cat} will try to use +{\tt read(2)}, which will get proxied by FUSD to the function {\tt +do\_read} on line 13. This function takes some additional arguments +that we didn't see in the open and close callbacks: +\begin{itemize} +\item {\tt struct fusd\_file\_info *file}---The first argument to all +callbacks, containing information which describes the file; see +Section~\ref{fusd-file-info}. +\item {\tt char *user\_buffer}---The buffer that the callback should use to +write data that it is returning to the user. +\item {\tt size\_t user\_length}---The maximum number of bytes +requested by the user. The driver is allowed to return fewer bytes, +but should never write more then {\tt user\_length} bytes into {\tt +user\_buffer}. +\item {\tt loff\_t *offset}---A pointer to an integer which represents +the caller's offset into the file (i.e., the user's file pointer). +This value can be modified by the callback; any change will be +propagated back to the user's file pointer inside the kernel. +\end{itemize} + +The semantics of the return value are the same as if the +callback were being written inside the kernel itself: +\begin{itemize} +\item Positive return values indicate success. If the call is +successful, and the driver has copied data into {\tt buffer}, the +return value indicates how many bytes were copied. This number should +never be greater than the {\tt user\_length} argument. +\item A 0 return value indicates EOF has been reached on the file. +\item As in the {\tt open} and {\tt close} callbacks, negative values +(such as -EPERM, -EPIPE, or -ENOMEM) indicate errors. Such values will +cause the user's {\tt read()} to return -1 with errno set +appropriately. +\end{itemize} + +The first time a read is done on a device file, the user's file +pointer ({\tt *offset}) is 0. In the case of this first read, a +greeting message of {\tt Hello, world!} is copied back to the user, as +seen on line 24. The user's file pointer is then advanced. The next +read therefore fails the comparison at line 20, falling straight +through to return 0, or EOF. + +In this simple program, we also see an example of an error return on +line 22: if the user tries to do a read smaller than the length of the +greeting message, the read will fail with -EINVAL. (In an actual +driver, it would normally not be an error for a user to provide a +smaller read buffer than the size of the available data. The right +way for drivers to handle this situation is to return partial data, +then move {\tt *offset} forward so that the remainder is returned on +the next {\tt read()}. We see an example of this in +Program~\ref{echo.c}.) + +\subsection{The {\tt write} callback} + +Program~\ref{helloworld.c} illustrated how a driver could return data +{\em to} a client using the {\tt read} callback. As you might expect, there +is a corresponding {\tt write} callback that allows the driver to +receive data {\em from} a client. {\tt write} takes four arguments, +similar to the {\tt read} callback: + +\begin{itemize} +\item {\tt struct fusd\_file\_info *file}---The first argument to all +callbacks, containing information which describes the file; see +Section~\ref{fusd-file-info}. +\item {\tt const char *user\_buffer}---Pointer to data being written +by the client (read-only). +\item {\tt size\_t user\_length}---The number of bytes pointed to by +{\tt user\_buffer}. +\item {\tt loff\_t *offset}---A pointer to an integer which represents +the caller's offset into the file (i.e., the user's file pointer). +This value can be modified by the callback; any change will be +propagated back to the user's file pointer inside the kernel. +\end{itemize} + +The semantics of {\tt write}'s return value are the same as in a +kernel callback: +\begin{itemize} +\item Positive return values indicate success and indicate how many +bytes of the user's buffer were successfully written (i.e., +successfully processed by the driver in some way). The return value +may be less than or equal to the {\tt user\_length} argument, but +should never be greater. +\item 0 should only be returned in response to a {\tt write} of length +0. +\item Negative values (such as -EPERM, -EPIPE, or -ENOMEM) indicate +errors. Such values will cause the user's {\tt write()} to return -1 +with errno set appropriately. +\end{itemize} + +Program~\ref{echo.c}, echo.c, is an example implementation of a device +({\tt /dev/echo}) that uses both {\tt read()} and {\tt write()} +callbacks. A client that tries to {\tt read()} from this device will +get the contents of the most recent {\tt write()}. For example:\\ +\begin{minipage}{\textwidth} +\vspace{\baselineskip} +\begin{verbatim} +% echo Hello there > /dev/echo +% cat /dev/echo +Hello there +% echo Device drivers are fun > /dev/echo +% cat /dev/echo +Device drivers are fun + +\end{verbatim} +\end{minipage} + +\begin{Program} +\listinginput[5]{1}{echo.c.example} +\caption{echo.c: Using both {\tt read} and {\tt write} callbacks} +\label{echo.c} +\end{Program} + +The implementation of {\tt /dev/echo} keeps a global variable, {\tt +data}, which serves as a cache for the data most recently written to +the driver by a client program. The driver does not assume the data +is null-terminated, so it also keeps track of the number of bytes of +data available. (These two variables appear on lines 1--2.) + +The driver's {\tt write} callback first frees any data which might +have been allocated by a previous call to write (lines 26--29). Next, +on line 33, it attempts to allocate new memory for the new data +arriving. If the allocation fails, {\tt -ENOMEM} is returned to the +client. If the allocation is successful, the driver copies the data +into its local buffer and stores its length (lines 37--38). Finally, +the driver tells the user that the entire buffer was consumed by +returning a value equal to the number of bytes the user tried to write +({\tt user\_length}). + +The {\tt read} callback has some extra features that we did not see in +Program~\ref{helloworld.c}'s {\tt read()} callback. The most +important is that it allows the driver to read the available data {\em +incrementally}, instead of requiring that the first {\tt read()} +executed by the client has enough space for all the data the driver +has available. In other words, a client can do two 50-byte reads, +and expect the same effect as if it had done a single 100-byte read. + +This is implemented using {\tt *offset}, the user's file pointer. If +the user is trying to read past the amount of data we have available, +the driver returns EOF (lines 8--9). Normally, this happens after the +client has finished reading data. However, in this driver, it might +happen on a client's first read if nothing has been written to the +driver yet or if the most recent write's memory allocation failed. + +If there is data to return, the driver computes the number of bytes +that should be copied back to the client---the minimum of the number +of bytes the user asked for, and the number of bytes of data that this +client hasn't seen yet (line 12). This data is copied back to the +user's buffer (line 15), and the user's file pointer is advanced +accordingly (line 16). Finally, on line 19, the client is told how +many bytes were copied to its buffer. + + +\subsection{Unregistering a device with {\tt fusd\_unregister()}} + +All devices registered by a driver are unregistered automatically when +the program exits (or crashes). However, the {\tt fusd\_unregister()} +function can be used to unregister a device without terminating the +entire driver. {\tt fusd\_unregister} takes one argument: a device +handle (i.e., the return value from {\tt fusd\_register()}). + +A device can be unregistered at any time. Any client system calls +that are pending when a device is unregistered will return immediately +with an error. In this case, {\tt errno} will be set to {\tt -EPIPE}. + + +\section{Using Information in {\tt fusd\_file\_info}} + +\label{fusd-file-info} + +We mentioned in the previous sections that the first argument to every +callback is a pointer to a {\tt fusd\_file\_info} structure. This +structure contains information that can be useful to driver +implementers in deciding how to respond to a system call request. + +The fields of {\tt fusd\_file\_info} structures fall into several +categories: +\begin{itemize} +\item {\em Read-only.} The driver can inspect the value, but changing +it will have no effect. +\begin{itemize} +\item {\tt pid\_t pid}: The process ID of the process making the +request +\item {\tt uid\_t uid}: The user ID of the owner of the process making +the request +\item {\tt gid\_t gid}: The group ID of the owner of the process making +the request +\end{itemize} +\item {\em Read-write.} Any changes to the value will be propagated +back to the kernel and be written to the appropriate in-kernel +structure. +\begin{itemize} +\item {\tt unsigned int flags}: A copy of the {\tt f\_flags} field in +the kernel's {\tt file} structure. The flags are an or'd-together set +of the kernel's {\tt O\_} series of flags: {\tt O\_NONBLOCK}, {\tt +O\_APPEND}, {\tt O\_SYNC}, etc. +\item {\tt void *device\_info}: The data passed to {\tt +fusd\_register} when the device was registered; see +Section~\ref{device-info} for details +\item {\tt void *private\_data}: A generic per-file-descriptor pointer +usable by the driver for its own purposes, such as to keep state (or a +pointer to state) that should be maintained between operations on the +same instance of an open file. It is guaranteed to be NULL when the +file is first opened. See Section~\ref{private-data} for more +details. +\end{itemize} +\item {\em Hidden fields.} The driver should not touch these fields +(such as {\tt fd}). They contain state used by the FUSD library to +generate the reply sent to the kernel. +\end{itemize} + +{\bf Important note:} the value of the {\tt fusd\_file\_info} pointer +itself has {\em no meaning}. Repeated requests on the same file +descriptor {\em will not} generate callbacks with identical {\tt +fusd\_file\_info} pointer values, as would be the case with an +in-kernel driver. In other words, if a driver needs to keep state in +between successive system calls on a user's file descriptor, it {\em +must} store that state using the {\tt private\_data} field. The {\tt +fusd\_file\_info} pointer itself is ephemeral; the data to which it +points is persistent. + +Program~\ref{uid-filter.c} shows an example of how a driver might make +use of the data in the {\tt fusd\_file\_info} structure. Much of the +driver is identical to helloworld.c. However, instead of printing a +static greeting, this new program generates a custom message each time +the device file is read, as seen on line 25. The message contains the +PID of the user process that requested the read ({\tt file->pid}). + +\begin{Program} +\listinginput[5]{1}{uid-filter.c.example} +\caption{uid-filter.c: Inspecting data in {\tt fusd\_file\_info} such +as UID and PID of the calling process} +\label{uid-filter.c} +\end{Program} + +In addition, Program~\ref{uid-filter.c}'s {\tt open} callback does not +return 0 (success) unconditionally as it did in +Program~\ref{helloworld.c}. Instead, it checks (on line 7) to make +sure the UID of the process trying to read from the device ({\tt +file->uid}) matches the UID under which the driver itself is running +({\tt getuid()}). If they don't match, -EPERM is returned. In other +words, only the user who ran the driver is allowed to read from the +device that it creates. If any other user---including root!---tries +to open it, a ``Permission denied'' error will be generated. + + +\subsection{Registration of Multiple Devices, and Passing Data to Callbacks} + +\label{device-info} + +Device drivers frequently expose several different ``flavors'' of a +device. For example, a single magnetic tape drive will often have +many different device files in {\tt /dev}. Each device file +represents a different combination of options such as +rewind/no-rewind, or compressed/uncompressed. However, they access +the same physical tape drive. + +Traditionally, the device file's {\em minor number} was used to +communicate the desired options with device drivers. But, since devfs +dynamically (and unpredictably) generates both major and minor numbers +every time a device is registered, a different technique was +developed. When using devfs, drivers are allowed to associate a value +(of type {\tt void *}) with each device they register. This facility +takes the place of the minor number. + +The devfs solution is also used by FUSD. The mysterious third +argument to {\tt fusd\_register} that we mentioned in +Section~\ref{using-fusd-register} is an arbitrary piece of data that +can be passed to FUSD when a device is registered. Later, when a +callback is activated, the contents of that argument are available in +the {\tt device\_info} member of the {\tt fusd\_file\_info} structure. + +Program~\ref{drums.c} shows an example of this technique, inspired by +Alessandro Rubini's similar devfs tutorial +\htmladdnormallinkfoot{published in Linux +Magazine}{http://www.linux.it/kerneldocs/devfs/}. It creates a number +of devices in the {\tt /dev/drums} directory, each of which is useful +for generating a different kind of ``sound''---{\tt /dev/drums/bam}, +{\tt /dev/drums/boom}, and so on. Reading from any of these devices +will return a string equal to the device's name. + +\begin{Program} +\listinginput[5]{1}{drums.c.example} +\caption{drums.c: Passing private data to {\tt fusd\_register} and +retrieving it from {\tt device\_info}} +\label{drums.c} +\end{Program} + +The first thing to notice about {\tt drums.c} is that it registers +more than one FUSD device. In the loop starting in line 31, it calls +{\tt fusd\_register()} once for every device named in {\tt +drums\_strings} on line 1. When {\tt fusd\_run()} is called, it +automatically watches every device the driver registered, and +activates the callbacks associated with each device as needed. +Although {\tt drums.c} uses the same set of callbacks for every device +it registers (as can be seen on line 33), each device could have +different callbacks if desired. (Not shown is the initialization of +{\tt drums\_fops}, which assigns {\tt drums\_read} to be the {\tt +read} callback.) + +If {\tt drums\_read} is called for all 6 types of drums, how does it +know which device it's supposed to be servicing when it gets called? +The answer is in the third argument of {\tt fusd\_register()}, which +we were previously ignoring. Whatever value is passed to {\tt +fusd\_register()} will be passed back to the callback in the {\tt +device\_info} field of the {\tt fusd\_file\_info} structure. The name +of the drum sound is passed to {\tt fusd\_register} on line 33, and +later retrieved by the driver on line 12. + +Although this example uses a string as its {\tt device\_info}, the +pointer can be used for anything---a mode number, a pointer to a +configuration structure, and so on. + + +\subsection{The difference between {\tt device\_info} and {\tt +private\_data}} + +\label{private-data} + +As we mentioned in Section~\ref{fusd-file-info}, the {\tt +fusd\_file\_info} structure has two seemingly similar fields, both of +which can be used by drivers to store their own data: {\tt +device\_info} and {\tt private\_data}. However, there is an important +difference between them: + +\begin{itemize} + +\item {\tt private\_data} is stored {\em per file descriptor}. If 20 +processes open a FUSD device (or, one process opens a FUSD device 20 +times), each of those 20 file descriptors will have their own copy of +{\tt private\_data} associated with them. This field is therefore +useful to drivers that need to differentiate multiple requests to a +single device that might be serviced in parallel. (Note that most +UNIX variants, including Linux, do allow multiple processes to share a +single file descriptor---specifically, if a process {\tt open}s a +file, then {\tt fork}s. In this case, processes will also share a +single copy of {\tt private\_data}.) + +The first time a FUSD driver sees {\tt private\_data} (in the {\tt +open} callback), it is guaranteed to be NULL. Any changes to it by a +driver callback will only affect the state associated with that single +file descriptor. + +\item {\tt device\_info} is kept {\em per device}. That is, {\em all} +clients of a device share a {\em single} copy of {\tt device\_info}. +Unlike {\tt private\_data}, which is always initialized to NULL, {\tt +device\_info} is always initialized to whatever value the driver +passed to {\tt fusd\_register} as described in the previous section. +If a callback changes the copy of {\tt device\_info} in the {\tt +fusd\_file\_info} structure, this has no effect; {\tt device\_info} +can only be set at registration time, with {\tt fusd\_register}. + +\end{itemize} + +In short, {\tt device\_info} is used to differentiate {\em devices}. +{\tt private\_data} is used to differentiate {\em users of those +devices}. + +Program~\ref{drums2.c}, drums2.c, illustrates the difference between +{\tt device\_info} and {\tt private\_data}. Like the original +drums.c, it creates a bunch of devices in {\tt /dev/drums/}, each of +which ``plays'' a different sound. However, it also does something +new: keeps track of how many times each device has been opened. Every +read to any drum gives you the name of its sound as well as your +unique ``user number''. And, instead of returning just a single line +(as drums.c did), it will keep generating more ``sound'' every time a +{\tt read()} system call arrives. + +\begin{Program} +\listinginput[5]{1}{drums2.c.example} +\caption{drums2.c: Using both {\tt device\_info} and {\tt private\_data}} +\label{drums2.c} +\end{Program} + +The trick is that we want to keep users separate from each other. For +example, user one might type:\\ +\begin{minipage}{\textwidth} +\vspace{\baselineskip} +\begin{verbatim} +% more /dev/drums/bam +You are user 1 to hear a drum go 'bam'! +You are user 1 to hear a drum go 'bam'! +You are user 1 to hear a drum go 'bam'! +... + +\end{verbatim} +\end{minipage} + +Meanwhile, another user in a different shell might type the same +command at the same time, and get different results:\\ +\begin{minipage}{\textwidth} +\vspace{\baselineskip} +\begin{verbatim} +% more /dev/drums/bam +You are user 2 to hear a drum go 'bam'! +You are user 2 to hear a drum go 'bam'! +You are user 2 to hear a drum go 'bam'! +... + +\end{verbatim} +\end{minipage} + +The idea is that no matter how long those two users go on reading +their devices, the driver always generates a message that is specific +to that user. The two users' data are not intermingled. + +To implement this, Program~\ref{drums2.c} introduces a new {\tt +drum\_info} structure (lines 1-4), which keeps track of both the +drum's name, and the number of time each drum device has been opened. +An instance of this structure, {\tt drums}, is initialized on lines +4-8. Note that the call to {\tt fusd\_register} (line 45) now passes +a pointer to a {\tt drum\_info} structure. (This {\tt drum\_info *} +pointer is shared by every instance of a client that opens a +particular type of drum.) + +Each time a drum device is opened, its {\tt drum\_info} structure is +retrieved from {\tt device\_info} (line 15). Then, on line 18, the +{\tt num\_users} field is incremented and the new user number is +stored in {\tt fusd\_file\_info}'s {\tt private\_data} field. To +reiterate our earlier point: {\em {\tt device\_info} contains +information global to all users of a device, while {\tt private\_data} +has information specific to a particular user of the device.} + +It's also worthwhile to note that when we increment {\tt num\_users} +on line 18, a simple {\tt num\_users++} is correct. If this was a +driver inside the kernel, we'd have to use something like {\tt +atomic\_inc()} because a plain {\tt i++} is not atomic. Such a +non-atomic statement will result in a race condition on SMP platforms, +if an interrupt handler also touches {\tt num\_users}, or in some +future Linux kernel that is preemptive. Since this FUSD driver is +just a plain, single-threaded user-space application, good old {\tt +++} still works. + + +\section{Writing {\tt ioctl} Callbacks} + +The POSIX API provides for a function called {\tt ioctl}, which allows +``out-of-band'' configuration information to be passed to a device +driver through a file descriptor. Using FUSD, you can write a device +driver with a callback to handle {\tt ioctl} requests from clients. +For the most part, it's just like writing a callback for {\tt read} or +{\tt write}, as we've seen in previous sections. From the client's +point of view, {\tt ioctl} traditionally takes three arguments: a file +descriptor, a command number, and a pointer to any additional data +that might be required for the command. + +\subsection{Using macros to generate {\tt ioctl} command numbers} + +The Linux header file {\tt /usr/include/asm/ioctl.h} defines macros +that {\em must} be used to create the {\tt ioctl} command number. +These macros take various combinations of three arguments: + +\begin{itemize} + +\item {\tt type}---an 8-bit integer selected to be specific to the +device driver. {\tt type} should be chosen so as not to conflict with +other drivers that might be ``listening'' to the same file descriptor. +(Inside the kernel, for example, the TCP and IP stacks use distinct +numbers since an {\tt ioctl} sent to a socket file descriptor might be +examined by both stacks.) + +\item {\tt number}---an 8-bit integer ``command number.'' Within a +driver, distinct numbers should be chosen for each different kind of +{\tt ioctl} command that the driver services. + +\item {\tt data\_type}---The name of a type used to compute how many +bytes are exchanged between the client and the driver. This argument +is, for example, the name of a structure. + +\end{itemize} + +The macros used to generate command numbers are: + +\begin{itemize} + +\item {\tt \_IO(int type, int number)} -- used for a simple ioctl that +sends nothing but the type and number, and receives back nothing but +an (integer) retval. + +\item {\tt \_IOR(int type, int number, data\_type)} -- used for an +ioctl that reads data {\em from} the device driver. The driver will +be allowed to return {\tt sizeof(data\_type)} bytes to the user. + +\item {\tt \_IOW(int type, int number, data\_type)} -- similar to +\_IOR, but used to write data {\em to} the driver. + +\item {\tt \_IORW(int type, int number, data\_type)} -- a combination +of {\tt \_IOR} and {\tt \_IOW}. That is, data is both written to the +driver and then read back from the driver by the client. +\end{itemize} + +\begin{Program} +\listinginput[5]{1}{ioctl.h.example} +\caption{ioctl.h: Using the {\tt \_IO} macros to generate {\tt ioctl} +command numbers} +\label{ioctl.h} +\end{Program} + +Program~\ref{ioctl.h} is an example header file showing the use of +these macros. In real programs, the client executing an ioctl and the +driver that services it must share the same header file. + +\subsection{Example client calls and driver callbacks} + +Program~\ref{ioctl-client.c} shows a client program that executes {\tt +ioctl}s using the ioctl command numbers defined in +Program~\ref{ioctl.h}. The {\tt ioctl\_data\_t} is +application-specific; our simple test program defines it as a +structure containing two arrays of characters. The first {\tt ioctl} +call (line 10) sends the command {\tt IOCTL\_TEST3}, which retrieves +strings {\em from} the driver. The second {\tt ioctl} uses the +command {\tt IOCTL\_TEST4} (line 18), which sends strings {\em to} the +driver. + +\begin{Program} +\listinginput[5]{1}{ioctl-client.c.example} +\caption{ioctl-client.c: A program that makes {\tt ioctl} requests on +a file descriptor} +\label{ioctl-client.c} +\end{Program} + +The portion of the FUSD driver that services these calls is shown in +Program~\ref{ioctl-server.c}. + +\begin{Program} +\listinginput[5]{1}{ioctl-server.c.example} +\caption{ioctl-server.c: A driver that handles {\tt ioctl} requests} +\label{ioctl-server.c} +\end{Program} + +The ioctl example header file and test programs shown in this document +(Programs~\ref{ioctl.h}, \ref{ioctl-client.c}, and +\ref{ioctl-server.c}) are actually contained in a larger, single +example program included in the FUSD distribution called {\tt +ioctl.c}. That source code shows other variations on calling and +servicing {\tt ioctl} commands. + + +\section{Integrating FUSD With Your Application Using {\tt fusd\_dispatch()}} +\label{selecting} + +The example applications we've seen so far have something in common: +after initialization and device registration, they call {\tt +fusd\_run()}. This gives up control of the program's flow, turning it +over to the FUSD library instead. This worked fine for our simple +example programs, but doesn't work in a real program that needs to +wait for events other than FUSD callbacks. For this reason, our +framework provides another way to activate callbacks that does not +require the driver to give up control of its {\tt main()}. + +\subsection{Using {\tt fusd\_dispatch()}} + +Recall from Section~\ref{using-fusd-register} that {\tt +fusd\_register} returns a {\em file descriptor} for every device that +is successfully registered. This file descriptor can be used to +activate device callbacks ``manually,'' without passing control of the +application to {\tt fusd\_run()}. Whenever the file descriptor +becomes readable according to {\tt select(2)}, it should be passed to +{\tt fusd\_dispatch()}, which in turn will activate callbacks in the +same way that {\tt fusd\_run()} does. In other words, an application +can: +\begin{enumerate} +\item Save the file descriptors returned by {\tt fusd\_register()}; +\item Add those FUSD file descriptors to an {\tt fd\_set} that is +passed to {\tt select}, along with any other file +descriptors that might be interesting to the application; and +\item Pass every FUSD file descriptor that {\tt select} indicates is +readable to {\tt fusd\_dispatch}. +\end{enumerate} + +{\tt fusd\_dispatch()} returns 0 if at least one callback was +successfully activated. On error, -1 is returned with {\tt errno} set +appropriately. {\tt fusd\_dispatch()} will never block---if no +messages are available from the kernel, it will return -1 with {\tt +errno} set to {\tt EAGAIN}. + +\subsection{Helper Functions for Constructing an {\tt fd\_set}} + +The FUSD library provides two (optional) utility functions that can +make it easier to write applications that integrate FUSD into their +own {\tt select()} loops. Specifically: +\begin{itemize} +\item {\tt void fusd\_fdset\_add(fd\_set *set, int *max)}---is meant +to help construct an {\tt fd\_set} that will be passed as the +``readable fds'' set to select. This function adds the file +descriptors of all previously registered FUSD devices to the fd\_set +{\tt set}. It assumes that {\tt set} has already been initialized by +the caller. The integer {\tt max} is updated to reflect the largest +file descriptor number in the set. {\tt max} is not changed if the +value passed to {\tt fusd\_fdset\_add} is already larger than the +largest FUSD file descriptor added to the set. + +\item {\tt void fusd\_dispatch\_fdset(fd\_set *set)}---is meant to be +called on the {\tt fd\_set} that is {\em returned} by select. It +assumes that {\tt set} contains a set file descriptors that {\tt +select()} has indicated are readable. {\tt fusd\_dispatch\_fdset()} +calls {\tt fusd\_dispatch} on every descriptor in {\tt set} that is a +valid FUSD descriptor. Non-FUSD descriptors in {\tt set} are +ignored. +\end{itemize} + + +\begin{Program} +\listinginput[5]{1}{drums3.c.example} +\caption{drums3.c: Waiting for both FUSD and non-FUSD events in a +{\tt select} loop} +\label{drums3.c} +\end{Program} + +The excerpt of {\tt drums3.c} shown in Program~\ref{drums3.c} +demonstrates the use of these helper functions. This program is +similar to the earlier drums.c example: it creates a number of musical +instruments such as {\tt /dev/drums/bam} and {\tt /dev/drums/boom}. +However, in addition to servicing its musical callbacks, the driver +also prints a prompt to standard input asking how ``loud'' the drums +should be. Instead of turning control of {\tt main()} over to {\tt +fusd\_run()} as in the previous examples, {\tt drums3} uses {\tt +select()} to simultaneously watch its FUSD file descriptors and standard +input. It responds to input from both sources. + +On lines 2--5, an {\tt fd\_set} and its associated ``max'' value are +initialized to contain stdin's file descriptor. On line 9, we use +{\tt fusd\_fdset\_add} to add the FUSD file descriptors for all +registered devices. (Not shown in this excerpt is the device +registration, which is the same as the registration code we saw in +{\tt drums.c}.) On line 13 we call select, which blocks until one of +the fd's in the set is readable. On lines 17 and 18, we check to see +if standard input is readable; if so, a function is called which reads +the user's response from standard input and prints a new prompt. +Finally, on line 21, we call {\tt fusd\_dispatch\_fdset}, which in +turn will activate the callbacks for devices that have pending system +calls waiting to be serviced. + +It's worth reiterating that drivers are not required to use the FUSD +helper functions {\tt fusd\_fdset\_add} and {\tt +fusd\_dispatch\_fdset}. If it's more convenient, a driver can +manually save all of the file descriptors returned by {\tt +fusd\_register}, construct its own {\tt fd\_set}, and then call {\tt +fusd\_dispatch} on each descriptor that is readable. This method is +sometimes required for integration with other frameworks that want to +take over your {\tt main()}. For example, the +\htmladdnormallinkfoot{GTK user interface +framework}{http://www.gtk.org} is event-driven and requires that you +pass control of your {\tt main} to it. However, it does allow you to +give it a file descriptor and a function pointer, saying ``Call this +callback when {\tt select} indicates this file descriptor has become +readable.'' A GTK application that implements FUSD devices can work +by giving GTK all the FUSD file descriptors individually, and calling +{\tt fusd\_dispatch()} when GTK calls the associated callbacks. + + + +\section{Implementing Blocking System Calls} + +All of the example drivers that we've seen until now have had an +important feature missing: they never had to {\em wait} for anything. +So far, a driver's response to a system call has always been +immediately available---allowing the driver to response immediately. +However, real devices are often not that lucky: they usually have to +wait for something to happen before completing a client's system call. +For example, a driver might be waiting for data to arrive from the +serial port or over the network, or even waiting for a user action. + +In situations like this, a basic capability most device drivers must +have is the ability to {\em block} the caller. Blocking operations +are important because they provide a simple interface to user programs +that does flow control, rather than something more expensive like +continuous polling. For example, user programs expect to be able to +execute a statement like {\tt read(fd, buf, sizeof(buf))}, and expect +the read call to block (stop the flow of the calling program) until +data is available. This is much simpler and more efficient than +polling repeatedly. + +In the following sections, we'll describe how to block and unblock +system calls for devices that use FUSD. + + +\subsection{Blocking the caller by blocking the driver} + +The easiest (but least useful) way to block a client's system call is +simply to block the driver, too. For example, consider +Program~\ref{console-read.c}, which implements a device called {\tt +/dev/console-read}. Whenever a process tries to read from this +device, the driver prints a prompt to standard input, asking for a +reply. (The prompt appears in the shell the driver was run in, not +the shell that's trying to read from the device.) When the user +enters a line of text, the response is returned to the client that did +the original {\tt read()}. By blocking the driver waiting for the +reply, the client that issued the system call is blocked as well. + +\begin{Program} +\listinginput[5]{1}{console-read.c.example} +\caption{console-read.c: A simple blocking system call} +\label{console-read.c} +\end{Program} + +Blocking the driver this way is safe---unlike programming in the +kernel proper, where doing something like this would block the entire +system. It's also easy to implement, as seen from the example above. +However, it makes the driver unresponsive to system call requests that +might be coming from other clients. If another process tries to do +anything at all with a blocked driver's device---even an {\tt +open()}---it will block until the driver wakes up again. This +limitation makes blocking drivers inappropriate for any device driver +that expects to service more than one client at a time. + + +\subsection{Blocking the caller using {\tt -FUSD\_NOREPLY}; +unblocking it using {\tt fusd\_return()}} +\label{fusd-noreply} + +If a device driver expects more than one client at a time---as is +often the case---a slightly different programming model is needed for +system calls that can potentially block. Instead of blocking, the +driver immediately sends a message to the FUSD framework that says, in +essence, ``Don't unblock the client that issued this system call, but +continue sending additional system call requests that might be coming +from other clients.'' Driver callbacks can send this message to FUSD +by returning the special value {\tt -FUSD\_NOREPLY} instead of a +normal system call return value. + +Before a callback blocks the caller by returning {\tt -FUSD\_NOREPLY}, +it must save the {\tt fusd\_file\_info} pointer that was provided to +the callback as its first argument. Later, when an event occurs which +allows the client's blocked system call to complete, the driver should +call {\tt fusd\_return()}, which will unblock the calling process and +complete its system call. {\tt fusd\_return()} takes two arguments: +\begin{itemize} +\item The {\tt fusd\_file\_info} pointer that the callback saved +earlier; and +\item The system call's return value (in other words, the value that +would have been returned by the callback function had it not returned +{\tt -FUSD\_NOREPLY}). FUSD itself {\em does not} examine the return +value passed as the second argument to {\tt fusd\_return}; it simply +propagates that value back to the kernel as the return value of the +blocked system call. +\end{itemize} + +Drivers should never call {\tt fusd\_return} more than once on a +single {\tt fusd\_file\_info} pointer. Doing so will have undefined +results, similar to calling {\tt free()} twice on the same pointer. + +It also bears repeating that a callback can call {\em either} call +fusd\_return() explicitly {\em or} return a normal return value (i.e., +not {\tt -FUSD\_NOREPLY}), but not both. + +{\tt -FUSD\_NOREPLY} and {\tt fusd\_return()} make it easy for a +driver to block a process, then unblock it later when data becomes +available. When the callback returns {\tt -FUSD\_NOREPLY}, the driver +is freed up to wait for other events, even though the process making +the system call is still blocked. The driver can then wait for +something to happen that unblocks the original caller---for example, +another FUSD event, data from a serial port, or data from the network. +(Recall from Section~\ref{selecting} that a FUSD driver can +simultaneously wait for both FUSD and non-FUSD events.) + +FUSD includes an example program, {\tt pager.c}, which demonstrates +these techniques. The pager driver implements a simple notification +interface which lets any number of ``waiters'' wait for a signal from +a ``notifier.'' All the waiters wait by trying to read from {\tt +/dev/pager/notify}. Those reads will block until a notifier writes +the string {\tt page} to {\tt /dev/pager/input}. It's easy to try +the application out---run the driver, and then open three other +shells. In two of them, type {\tt cat /dev/pager/notify}. The reads +will block. Then, in the third shell, type {\tt echo page > +/dev/pager/input}---the other two shells should become unblocked. + +Let's take a look at how this application is implemented, step by +step. + +\subsubsection{Keeping Per-Client State} + +The first thing to notice about {\tt pager.c} is that it keeps {\em +per-client state}. That is, for every file descriptor open to the +driver, a structure is allocated that has information relating to that +file descriptor. Previous driver examples were, for the most part, +{\em reactive}---they received requests, and immediately generated +responses. Since there was never more than one request outstanding, +there was no need to keep a list of them. The pager application is +the first one that must keep track of an arbitrary number of requests +that might be outstanding at the same time. The first excerpt of {\tt +pager.c}, which appears in Program~\ref{pager-open.c}, shows the code +which creates this per-client state. Lines 1--6 define a structure, +{\tt pager\_client}, which keeps all the information we need about +each client attached to the driver. The {\tt open} callback for {\tt +/dev/pager/notify}, shown on lines 12--31, allocates memory for an +instance of this structure and adds it to a linked list. (If the +memory allocation fails, an error is returned to the client on line +18; this will prevent the file from opening.) Note on line 25 that we +use the {\tt private\_data} field to store a pointer to the client +state; this allows the structure to be retrieved when later callbacks +on this file descriptor arrive. The memory is deallocated when the +file is closed; we'll see that in a later section. + +\begin{Program} +\listinginput[5]{1}{pager-open.c.example} +\caption{pager.c (Part 1): Creating state for every client using the +driver} +\label{pager-open.c} +\end{Program} + +Another thing to notice about the open callback is the use of the {\tt +last\_page\_seen} variable. The driver gives a sequence number to +every page it receives; {\tt last\_page\_seen} stores the number of +the most recent page seen by a client. When a new client arrives +(i.e., it opens {\tt /dev/pager/notify}), its {\tt last\_page\_seen} +state is set equal to the page that has most recently arrived; this +forces a new client to wait for the {\em next} page, rather than +immediately being notified of a page that has arrived in the past. + +\subsubsection{Blocking and completing reads} + +The next part of {\tt pager.c} is shown in Program~\ref{pager-read.c}. +The {\tt pager\_notify\_read} function seen on line 1 is registered as +the {\tt read} callback for the {\tt /dev/pager/notify} device. It +blocks the read request using the technique we described earlier: it +stores the {\tt fusd\_file\_info} pointer in that client's state +structure, and returns {\tt -FUSD\_NOREPLY}. (Note that the pointer +to the client's state structure comes from the {\tt private\_data} +field of {\tt fusd\_file\_info}, where the open callback stored it.) + +\begin{Program} +\listinginput[5]{1}{pager-read.c.example} +\caption{pager.c (Part 2): Block clients' {\tt read} requests, and later +completing the blocked reads} +\label{pager-read.c} +\end{Program} + + +{\tt pager\_notify\_complete\_read} {\em unblocks} previously blocked +reads. This function first checks to see that there is, in fact, a blocked +read (line 19). It then checks to see if a page has arrived that the +client hasn't seen yet (line 23). Finally, it updates the client +state and unblocks the blocked read by calling {\tt fusd\_return}. +Note the second argument to {\tt fusd\_return} is a 0; as we +saw in Section~\ref{read-callback}, a 0 return value to a {\tt read} +system call means EOF. (The system call will be unblocked regardless +of the return value.) + +{\tt pager\_notify\_complete\_read} is called every time a new page +arrives. New pages are processed by {\tt pager\_input\_write} (line +34), which is the {\tt write} callback for {\tt /dev/pager/input}. +After recording the fact that a new page has arrived, it calls {\tt +pager\_notify\_complete\_read} for each client that has an open file +descriptor. This will complete the reads of any clients who have not +yet seen this new data, and have no effect on clients that don't have +outstanding reads. + +There is another interesting point to notice about {\tt +pager\_notify\_read}. On line 12, after it stores the blocked system +call's pointer, but before we return {\tt -FUSD\_NOREPLY}, it calls +the completion function. This has the effect of returning any data +that might already be available back to the caller immediately. If +that happens, we will end up calling {\tt fusd\_return} {\em before} +we return {\tt -FUSD\_NOREPLY}. This probably seems strange, but it's +legal. Recall that a callback can call fusd\_return() explicitly {\em +or} return a normal (not {\tt -FUSD\_NOREPLY}) return value, but not +both; the order doesn't matter. + +\subsubsection{Using {\tt fusd\_destroy()} to clean up client state} +\label{fusd-destroy} + +Finally, let's take a look at one last aspect of the pager program: +how it cleans up the per-client state when a client leaves. This is +mostly straightforward, with one exception: a client may have an +outstanding read request out when a close request comes in. Normally, +a client can't make another system call request while a previous +system call is still blocked. However, the {\tt close} system call is +an exception: it gets called when a client dies (for example, if it +receives an interrupt signal). If a {\tt close} comes in while +another system call is still outstanding, the state associated with +the outstanding request should be freed to avoid a memory leak. The +{\tt fusd\_destroy} function is used to do this, seen on linen 12-14 +of Program~\ref{pager-close.c}. + +\begin{Program} +\listinginput[5]{1}{pager-close.c.example} +\caption{pager.c (Part 3): Cleaning up when a client leaves} +\label{pager-close.c} +\end{Program} + + +\subsection{Retrieving a blocked system call's arguments from a {\tt +fusd\_file\_info} pointer} + +\label{logring} + +In the previous section, we showed how the {\tt fusd\_return} function +can be used to specify the return value of a system call that was +previously blocked. However, many system calls have side effects in +addition to returning a value---for example, in a {\tt read()} +request, the data being returned has to be copied into the caller's +buffer. To facilitate this, FUSD provides accessor functions that let +drivers retrieve the arguments that had been passed to its callbacks +at the time the call was originally issued. For example, the {\tt +fusd\_get\_read\_buffer()} function will return a pointer to the data +buffer that is provided with {\tt read()} callbacks. Drivers can use +these accessor functions to affect change to a client {\em before} +calling {\tt fusd\_return()}. + +The following accessor functions are available, all of which take a +single {\tt fusd\_file\_info *} argument: +\begin{itemize} +\item {\tt int char *fusd\_get\_read\_buffer}---The destination buffer +for data that a driver is returning to a process doing a {\tt read()}. +\item {\tt const char *fusd\_get\_write\_buffer}---The source buffer +containing data sent to the driver by a process doing a {\tt write()}. +\item {\tt fusd\_get\_length}---The length (in bytes) of the buffer +for either a {\tt read()} or a {\tt write()}. +\item {\tt loff\_t fusd\_get\_offset}---The file descriptor's byte +offset, typically used in {\tt read()} and {\tt write()} callbacks. +\item {\tt int fusd\_get\_ioctl\_request}---An ioctl's request +``command number'' (i.e., the first argument of an ioctl). +\item {\tt int fusd\_get\_ioctl\_arg}---The second argument of an +ioctl for non-data-bearing {\tt ioctl} requests (i.e., {\tt \_IO} +commands). +\item {\tt void *fusd\_get\_ioctl\_buffer}---The data buffer for +data-bearing {\tt ioctl} requests ({\tt \_IOR}, {\tt \_IOW}, and +{\tt \_IORW} commands). +\item {\tt int fusd\_get\_poll\_diff\_cached\_state}---See +Section~\ref{selectable}. +\end{itemize} + +We got away without using these accessor functions in our {\tt +pager.c} example because the pager doesn't actually return data---it +just blocks and unblocks {\tt read} calls. However, the FUSD +distribution contains another example program, {\tt logring}, that +demonstrates their use. + +{\tt logring} makes it easy to access the most recent (and only the most +recent) output from a process. It works just like {\tt tail -f} on a +log file, except that the storage required never grows. This can be +useful in embedded systems where there isn't enough memory or disk +space for keeping complete log files, but the most recent debugging +messages are sometimes needed (e.g., after an error is observed). + +{\tt logring} uses FUSD to implement a character device, {\tt +/dev/logring}, that acts like a named pipe that has a finite, circular +buffer. The size of the buffer is given as a command-line argument. +As more data is written into the buffer, the oldest data is discarded. +A process that reads from the logring device will first read the +existing buffer, then block and see new data as it's written, similar +to monitoring a log file using {\tt tail -f}. + +You can run this example program by typing {\tt logring }, +where {\tt logsize} is the size of the circular buffer in bytes. +Then, type {\tt cat /dev/logring} in a shell. The {\tt cat} process +will block, waiting for data. From another shell, write to the +logring (e.g., {\tt echo Hi there > /dev/logring}). The {\tt cat} +process will see the message appear. + +(This example program is based on {\em emlog}, a (real) Linux kernel +module with identical functionality. If you find logring useful, but +want to use it on a system that does not have FUSD, check out the +original +\htmladdnormallinkfoot{emlog}{http://www.circlemud.org/jelson/software/emlog}.) + + + + + +\section{Implementing {\tt select}able Devices} +\label{selectable} + +One important feature that almost every device driver in a system +should have is support for the {\tt select(2)} system call. {\tt +select} allows clients to assemble a set of file descriptors and ask +to be notified when one of them becomes readable or writable. This +simple feature is deceptively powerful---it allows clients to wait for +any number of a set of possible events to occur. This is +fundamentally different than (for example) a blocking read, which only +unblocks on one kind of event. In this section, we'll describe how +FUSD can be used to create a device whose state can be queried by a +client's call to {\tt select(2)}. + +This section is limited to a discussion what a FUSD driver writer +needs to know to implement a selectable device. Details of the FUSD +implementation required to support this feature are described in +Section~\ref{poll-diff-implementation} + + +\subsection{Poll state and the {\tt poll\_diff} callback} + +FUSD's implementation of selectable devices depends on the concept of +{\em poll state}. A file descriptor's poll state is a bitmask that +describes its current properties---readable, writable, or exception +raised. These three states correspond to {\tt select(2)}'s three +{\tt fd\_set}s. FUSD has constants used to describe these states: +\begin{itemize} +\item {\tt FUSD\_NOTIFY\_INPUT}---Input is available; a read will not +block. +\item {\tt FUSD\_NOTIFY\_OUTPUT}---Output space is available; a write +will not block. +\item {\tt FUSD\_NOTIFY\_EXCEPT}---An exception has occurred. +\end{itemize} + +These constants can be combined with C's bitwise-or operator. For +example, a descriptor that is both readable and writable is expressed +as {\tt FUSD\_NOTIFY\_INPUT | FUSD\_NOTIFY\_OUTPUT}. 0 means a file +descriptor is not readable, not writable, and not in the exception +set. + +For a FUSD device to be selectable, its driver must implement a +callback called {\tt poll\_diff}. This callback is very different +than the others; it is not a ``direct line'' between the client and +the driver as is the case with a call such as {\tt ioctl}. A driver's +response to {\tt poll\_diff} is {\em not} the return value seen by a +client's call to {\tt select}. When a client tries to {\tt select} on +a set of file descriptors, the kernel collects the responses from all +the appropriate callbacks---{\tt poll} for file descriptors managed by +kernel drivers, and {\tt poll\_diff} callbacks those managed by FUSD +drivers---and synthesizes all of that information into the return +value seen by the client. + +FUSD keeps a cache of the poll state it has most recently received +from each FUSD device driver, initially assumed to be 0. This state +is returned to clients trying to {\tt select()} on devices managed by +those drivers. Under certain conditions, FUSD sends a query to the +driver in order to ensure that the kernel's poll state cache is up to +date. This query takes the form of a {\tt poll\_diff} callback +activation, which is given a single argument: the poll state that FUSD +currently has cached. The driver should consult its internal data +structures to determine the actual, current poll state (i.e., whether +or not buffers have readable data). Then: +\begin{itemize} +\item If the FUSD cache is incorrect (that is, the current true poll +state is different than FUSD's cached state), the current poll state +should be returned immediately. +\item If the FUSD cache is up to date (that is, it matches the real +current state), the callback should save the {\tt fusd\_file\_info} +pointer and return {\tt -FUSD\_NOREPLY}. Later, when the poll +state changes, the driver can call {\tt fusd\_return()} to update +FUSD's cache. +\end{itemize} + +In other words, when a driver's {\tt poll\_diff} callback is +activated, the kernel is effectively saying to the driver, ``Here is +what I think the current poll state of this file descriptor is; let me +know when that state {\em changes}.'' The driver can either respond +immediately (if the kernel's cache is already known to be out of +date), or return {\tt -FUSD\_NOREPLY} if no update is immediately +necessary. Later, when the poll state changes (for example, if new +data arrives that makes a device readable), the driver can used its +saved {\tt fusd\_file\_info} pointer to send a poll state update to +the kernel. + +When a FUSD driver sends a poll state update, it might (or might not) +have the effect of waking up a client that was blocked in {\tt +select(2)}. On the same note, it's worth reiterating that a {\tt +-FUSD\_NOREPLY} response to a {\tt poll\_diff} callback {\em does not} +necessarily block the client---other descriptors in the client's {\tt +select} set might be readable, for example. + +\subsection{Receiving a {\tt poll\_diff} request when the previous one +has not been returned yet} +\label{multiple-polldiffs} + +Calls such as {\tt read} and {\tt write} are synchronous from the +standpoint of an individual client---a request is made, and the +requester blocks until a reply is received. This means that there +can't ever be more than a single {\tt read} request outstanding for a +single client at a time. (The driver as a whole may be keeping track +of many outstanding {\tt read} requests in parallel, but no two of them will +be from the same client file descriptor.) + +As we mentioned in the previous section, the {\tt poll\_diff} callback +is different from other callbacks. It is not part of a synchronous +request/reply sequence that causes the client to block. It is also an +interface to the {\em kernel}, not directly to the client. So, it +{\em is} possible to receive a {\tt poll\_diff} request while there is +already one outstanding. This happens if the kernel's poll state +cache changes, causing it to notify the driver that it has a new +cached value. + +This is easy to handle; the client should simply +\begin{enumerate} +\item Destroy the old (now out-of-date) {\tt poll\_diff} request +using the {\tt fusd\_destroy} function we saw in +Section~\ref{fusd-destroy}. +\item Either respond to or save the new {\tt poll\_diff} request, +exactly as described in the previous section. +\end{enumerate} + +The next section will show an example of this technique. + + +\subsection{Adding {\tt select} support to {\tt pager.c}} + +Given the explanation of {\tt poll\_diff} in the previous sections, it +might seem that implementing a selectable device is a daunting task. +It's actually not as bad as it sounds---the example code may well be +shorter than its explanation! + +\begin{Program} +\listinginput[5]{1}{pager-polldiff.c.example} +\caption{pager.c (Part 4): Supporting {\tt select(2)} by implementing a +{\tt poll\_diff} callback} +\label{pager-polldiff.c} +\end{Program} + +Program~\ref{pager-polldiff.c} shows the implementation of {\tt +poll\_diff} in {\tt pager.c}, which makes its notification interface +({\tt /dev/pager/notify}) selectable. It is decomposed into a ``top +half'' and ``bottom half'' function, exactly as we did for the +blocking {\tt read} implementation in Program~\ref{pager-read.c}. +First, on lines 1--20, we see the the callback for {\tt poll\_diff} +callback itself. It is virtually identical to the {\tt read} callback +in Program~\ref{pager-read.c}. The main difference is that it first +checks (on line 12) to see if a {\tt poll\_diff} request is already +outstanding when a new request comes in. If so, the out-of-date +request is destroyed using {\tt fusd\_destroy}, as we described in +Section~\ref{multiple-polldiffs}. + +The bottom half is shown on lines 22-46. First, on lines 32--35, it +computes the current poll state---if a page has arrived that the +client hasn't seen yet, the file is readable; otherwise, it isn't. +Next, the driver compares the current poll state with the poll state +that the kernel has cached. If the kernel's cache is out of date, the +current state is returned to the kernel. Otherwise, it does nothing. + +As with the {\tt read} callback we saw previously, notice that {\tt +pager\_notify\_complete\_polldiff} is called in two different cases: +\begin{enumerate} +\item It is called immediately from the {\tt pager\_notify\_polldiff} +callback itself. This causes the current poll state to be returned to +the kernel immediately when the request arrives if the driver already +knows the kernel's state needs to be updated. +\item It is called when new data arrives that causes the poll state to +change. Refer back to Program~\ref{pager-read.c} on +page~\pageref{pager-read.c}; in the callback that receives new pages, +notice on line 45 that the {\tt poll\_diff} completion function is called +alongside the {\tt read} completion function. +\end{enumerate} + +With this {\tt poll\_diff} implementation, it is possible for a client +to open {\tt /dev/pager/notify}, and block in a {\tt select(2)} system +call. If another client writes {\tt page} to {\tt /dev/pager/input}, +the first client's {\tt select} will unblock, indicating the file has +become readable. + +For additional example code, take a look at the {\tt logring} example +program we first mentioned in Section~\ref{logring}. It also supports +{\tt select} by implementing a similar {\tt poll\_diff} callback. + +\section{Performance of User-Space Devices} +\label{performance} + +This section hasn't been written yet. I have some pretty graphs and +whatnot, but no time to write about them here before the release. + +\section{FUSD Implementation Notes} + +In this section, we describe some of the details of how FUSD is +implemented. It's not necessary to understand these details in order +to use FUSD. However, these notes can be useful for people who are +trying to understand the FUSD framework itself---hackers, debuggers, +or the generally curious. + +\subsection{The situation with {\tt poll\_diff}} +\label{poll-diff-implementation} + + +In-kernel device drivers support select by implementing a callback +called {\tt poll}. This driver's callback is supposed to do two +things. First, it should return the current state of a file +descriptor---a combination of being readable, writable, or having +exceptions. Second, it should provide a pointer to one of the +driver's internal wait queues that will be awakened whenever the state +changes. The {\tt poll} call itself should never block---it should +just instantaneously report what the {\em current} state is. + +FUSD's implementation of selectable devices is different, but attempts +to maintain three properties that we thought to be most important from +the point of view of a client using {\tt select}. Specifically: +\begin{enumerate} +\item The {\tt select(2)} call itself should never become blocked. +For example, if one file descriptor in its set isn't readable, that +shouldn't prevent it from reporting other file descriptors that are. +\item If {\tt select(2)} indicates a file descriptor is readable (or +writable), a read (or write) on that file descriptor shouldn't block. +\item Clients should be allowed to seamlessly {\tt select} on any set +of file descriptors, even if that set contains a mix of both FUSD and +non-FUSD devices. +\end{enumerate} + + +The FUSD kernel module keeps a cache of the driver's most recent +answer for each file descriptor, initially assumed to be 0. When the +kernel module's internal {\tt poll} callback is activated, it: +\begin{enumerate} +\item Dispatches a {\em non-}blocking {\tt poll\_diff} to the +associated user-space driver, asking for a cache update---if and only +if there isn't already an outstanding poll diff request out that has +the same value. +\item Immediately returns the cached value to the kernel +\end{enumerate} + +In addition, the cached value's readable bit is cleared on every read; +the writable bit is cleared on every write. This is necessary to +prevent old poll state---which says ``device is readable''---from +being returned out of the cache when it might be invalid. FUSD +assumes that any read to a device can make it potentially unreadable. +This mechanism is what causes an updated poll diff to be sent to a +client before the previous one has been returned. + +(this section isn't finished yet; fancy time diagrams coming someday) + +\subsection{Restartable System Calls} + +No time to write this section yet... + + +\appendix + +\section{Using {\tt strace}} +\label{strace} + +This section hasn't been written yet. Contributions are welcome. + +\end{document} + diff --git a/doc/html.sty b/doc/html.sty new file mode 100644 index 0000000..65bd03e --- /dev/null +++ b/doc/html.sty @@ -0,0 +1,1158 @@ +% +% $Id: html.sty,v 1.1 2001/05/12 00:38:48 cvs Exp $ +% LaTeX2HTML Version 99.2 : html.sty +% +% This file contains definitions of LaTeX commands which are +% processed in a special way by the translator. +% For example, there are commands for embedding external hypertext links, +% for cross-references between documents or for including raw HTML. +% This file includes the comments.sty file v2.0 by Victor Eijkhout +% In most cases these commands do nothing when processed by LaTeX. +% +% Place this file in a directory accessible to LaTeX (i.e., somewhere +% in the TEXINPUTS path.) +% +% NOTE: This file works with LaTeX 2.09 or (the newer) LaTeX2e. +% If you only have LaTeX 2.09, some complex LaTeX2HTML features +% like support for segmented documents are not available. + +% Changes: +% See the change log at end of file. + + +% Exit if the style file is already loaded +% (suggested by Lee Shombert +\ifx \htmlstyloaded\relax \endinput\else\let\htmlstyloaded\relax\fi +\makeatletter + +% allow for the hyperref package to be cleanly loaded +% either before or after this package, +% and ensure it is already loaded, when using pdf-TeX + +\ifx\undefined\hyperref + \ifx\pdfoutput\undefined \let\pdfunknown\relax + \let\html@new=\newcommand + \else + \ifx\pdfoutput\relax \let\pdfunknown\relax + \RequirePackage{hyperref}\let\html@new=\renewcommand + \else + \RequirePackage{hyperref}\let\html@new=\newcommand + \fi + \fi +\else + \let\html@new=\renewcommand +\fi + +\providecommand{\latextohtml}{\LaTeX2\texttt{HTML}} + +%%% LINKS TO EXTERNAL DOCUMENTS +% +% This can be used to provide links to arbitrary documents. +% The first argumment should be the text that is going to be +% highlighted and the second argument a URL. +% The hyperlink will appear as a hyperlink in the HTML +% document and as a footnote in the dvi or ps files. +% +\ifx\pdfunknown\relax + \html@new{\htmladdnormallinkfoot}[2]{#1\footnote{#2}} +\else + \def\htmladdnormallinkfoot#1#2{\footnote{\href{#2}{#1}}} +\fi + +% This is an alternative definition of the command above which +% will ignore the URL in the dvi or ps files. +\ifx\pdfunknown\relax + \html@new{\htmladdnormallink}[2]{#1} +\else + \def\htmladdnormallink#1#2{\href{#2}{#1}} +\fi + +% This command takes as argument a URL pointing to an image. +% The image will be embedded in the HTML document but will +% be ignored in the dvi and ps files. +% +\ifx\pdfunknown\relax + \html@new{\htmladdimg}[1]{} +\else + \def\htmladdimg#1{\hyperimage{#1}} +\fi + + +%%% CROSS-REFERENCES BETWEEN (LOCAL OR REMOTE) DOCUMENTS +% +% This can be used to refer to symbolic labels in other Latex +% documents that have already been processed by the translator. +% The arguments should be: +% #1 : the URL to the directory containing the external document +% #2 : the path to the labels.pl file of the external document. +% If the external document lives on a remote machine then labels.pl +% must be copied on the local machine. +% +%e.g. \externallabels{http://cbl.leeds.ac.uk/nikos/WWW/doc/tex2html/latex2html} +% {/usr/cblelca/nikos/tmp/labels.pl} +% The arguments are ignored in the dvi and ps files. +% +\newcommand{\externallabels}[2]{} + + +% This complements the \externallabels command above. The argument +% should be a label defined in another latex document and will be +% ignored in the dvi and ps files. +% +\newcommand{\externalref}[1]{} + + +% Suggested by Uffe Engberg (http://www.brics.dk/~engberg/) +% This allows the same effect for citations in external bibliographies. +% An \externallabels command must be given, locating a labels.pl file +% which defines the location and keys used in the external .html file. +% +\newcommand{\externalcite}{\nocite} + +% This allows a section-heading in the TOC or mini-TOC to be just +% a hyperlink to an external document. +% +% \htmladdTOClink[]{}{}{<URL>} +% where <section-level> is 'chapter' , 'section' , 'subsection' etc. +% and <path_to_labels> is the path to find a labels.pl file, +% so that external cross-referencing may work, as with \externallabels +% +%\ifx\pdfunknown\relax + \newcommand{\htmladdTOClink}[4][]{} +% +% can do something here, using the \pdfoutline primitive +%\else +% \def\htmladdTOClink#1#2#3#4{\pdfoutline user {/S /URI /URI #4} +% name{#2} count{#1}{#3}} +%\fi + + +%%% HTMLRULE +% This command adds a horizontal rule and is valid even within +% a figure caption. +% Here we introduce a stub for compatibility. +\newcommand{\htmlrule}{\protect\HTMLrule} +\newcommand{\HTMLrule}{\@ifstar\htmlrulestar\htmlrulestar} +\newcommand{\htmlrulestar}[1]{} + +%%% HTMLCLEAR +% This command puts in a <BR> tag, with CLEAR="ALL" +\newcommand{\htmlclear}{} + +% This command adds information within the <BODY> ... </BODY> tag +% +\newcommand{\bodytext}[1]{} +\newcommand{\htmlbody}{} + + +%%% HYPERREF +% Suggested by Eric M. Carol <eric@ca.utoronto.utcc.enfm> +% Similar to \ref but accepts conditional text. +% The first argument is HTML text which will become ``hyperized'' +% (underlined). +% The second and third arguments are text which will appear only in the paper +% version (DVI file), enclosing the fourth argument which is a reference to a label. +% +%e.g. \hyperref{using the tracer}{using the tracer (see Section}{)}{trace} +% where there is a corresponding \label{trace} +% +% avoid possible confict with hyperref package +\ifx\undefined\hyperref + \newcommand{\hyperrefhyper}[4]{#4}% + \def\next{\newcommand}% +\else + \let\hyperrefhyper\hyperref + \def\next{\renewcommand}% +\fi +\next{\hyperref}{\hyperrefi[]}\let\next=\relax + +\def\hyperrefi[#1]{{\def\next{#1}\def\tmp{}% + \ifx\next\tmp\aftergroup\hyperrefdef + \else\def\tmp{ref}\ifx\next\tmp\aftergroup\hyperrefref + \else\def\tmp{pageref}\ifx\next\tmp\aftergroup\hyperrefpageref + \else\def\tmp{page}\ifx\next\tmp\aftergroup\hyperrefpage + \else\def\tmp{noref}\ifx\next\tmp\aftergroup\hyperrefnoref + \else\def\tmp{no}\ifx\next\tmp\aftergroup\hyperrefno + \else\def\tmp{hyper}\ifx\next\tmp\aftergroup\hyperrefhyper + \else\def\tmp{html}\ifx\next\tmp\aftergroup\hyperrefhtml + \else\typeout{*** unknown option \next\space to hyperref ***}% + \fi\fi\fi\fi\fi\fi\fi\fi}} +\newcommand{\hyperrefdef}[4]{#2\ref{#4}#3} +\newcommand{\hyperrefpageref}[4]{#2\pageref{#4}#3} +\newcommand{\hyperrefnoref}[3]{#2} +\let\hyperrefref=\hyperrefdef +\let\hyperrefpage=\hyperrefpageref +\let\hyperrefno=\hyperrefnoref +\ifx\undefined\hyperrefhyper\newcommand{\hyperrefhyper}[4]{#4}\fi +\let\hyperrefhtml=\hyperrefdef + +%%% HYPERCITE --- added by RRM +% Suggested by Stephen Simpson <simpson@math.psu.edu> +% effects the same ideas as in \hyperref, but for citations. +% It does not allow an optional argument to the \cite, in LaTeX. +% +% \hypercite{<html-text>}{<LaTeX-text>}{<opt-text>}{<key>} +% +% uses the pre/post-texts in LaTeX, with a \cite{<key>} +% +% \hypercite[ext]{<html-text>}{<LaTeX-text>}{<key>} +% \hypercite[ext]{<html-text>}{<LaTeX-text>}[<prefix>]{<key>} +% +% uses the pre/post-texts in LaTeX, with a \nocite{<key>} +% the actual reference comes from an \externallabels file. +% +\newcommand{\hypercite}{\hypercitei[]} +\def\hypercitei[#1]{{\def\next{#1}\def\tmp{}% + \ifx\next\tmp\aftergroup\hypercitedef + \else\def\tmp{int}\ifx\next\tmp\aftergroup\hyperciteint + \else\def\tmp{cite}\ifx\next\tmp\aftergroup\hypercitecite + \else\def\tmp{ext}\ifx\next\tmp\aftergroup\hyperciteext + \else\def\tmp{nocite}\ifx\next\tmp\aftergroup\hypercitenocite + \else\def\tmp{no}\ifx\next\tmp\aftergroup\hyperciteno + \else\typeout{*** unknown option \next\space to hypercite ***}% + \fi\fi\fi\fi\fi\fi}} +\newcommand{\hypercitedef}[4]{#2{\def\tmp{#3}\def\emptyopt{}% + \ifx\tmp\emptyopt\cite{#4}\else\cite[#3]{#4}\fi}} +\newcommand{\hypercitenocite}[2]{#2\hypercitenocitex[]} +\def\hypercitenocitex[#1]#2{\nocite{#2}} +\let\hypercitecite=\hypercitedef +\let\hyperciteint=\hypercitedef +\let\hyperciteext=\hypercitenocite +\let\hyperciteno=\hypercitenocite + +%%% HTMLREF +% Reference in HTML version only. +% Mix between \htmladdnormallink and \hyperref. +% First arg is text for in both versions, second is label for use in HTML +% version. +\ifx\pdfunknown\relax + \html@new{\htmlref}[2]{#1} +\else + \def\htmlref#1#2{\hyperefhyper[#2]{#1}} +\fi + +%%% HTMLCITE +% Reference in HTML version only. +% Mix between \htmladdnormallink and \hypercite. +% First arg is text for both versions, second is citation for use in HTML +% version. +\newcommand{\htmlcite}[2]{#1} + + +%%% HTMLIMAGE +% This command can be used inside any environment that is converted +% into an inlined image (eg a "figure" environment) in order to change +% the way the image will be translated. The argument of \htmlimage +% is really a string of options separated by commas ie +% [scale=<scale factor>],[external],[thumbnail=<reduction factor> +% The scale option allows control over the size of the final image. +% The ``external'' option will cause the image not to be inlined +% (images are inlined by default). External images will be accessible +% via a hypertext link. +% The ``thumbnail'' option will cause a small inlined image to be +% placed in the caption. The size of the thumbnail depends on the +% reduction factor. The use of the ``thumbnail'' option implies +% the ``external'' option. +% +% Example: +% \htmlimage{scale=1.5,external,thumbnail=0.2} +% will cause a small thumbnail image 1/5th of the original size to be +% placed in the final document, pointing to an external image 1.5 +% times bigger than the original. +% +\newcommand{\htmlimage}[1]{} + + +% \htmlborder causes a border to be placed around an image or table +% when the image is placed within a <TABLE> cell. +\newcommand{\htmlborder}[1]{} + +% Put \begin{makeimage}, \end{makeimage} around LaTeX to ensure its +% translation into an image. +% This shields sensitive text from being translated. +\newenvironment{makeimage}{}{} + + +% A dummy environment that can be useful to alter the order +% in which commands are processed, in LaTeX2HTML +\newenvironment{tex2html_deferred}{}{} + + +%%% HTMLADDTONAVIGATION +% This command appends its argument to the buttons in the navigation +% panel. It is ignored by LaTeX. +% +% Example: +% \htmladdtonavigation{\htmladdnormallink +% {\htmladdimg{http://server/path/to/gif}} +% {http://server/path}} +\newcommand{\htmladdtonavigation}[1]{} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% based upon Eijkhout's comment.sty v2.0 +% with modifications to avoid conflicts with later versions +% of this package, should a user be requiring it. +% Ross Moore, 10 March 1999 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Comment.sty version 2.0, 19 June 1992 +% selectively in/exclude pieces of text: the user can define new +% comment versions, and each is controlled separately. +% This style can be used with plain TeX or LaTeX, and probably +% most other packages too. +% +% Examples of use in LaTeX and TeX follow \endinput +% +% Author +% Victor Eijkhout +% Department of Computer Science +% University Tennessee at Knoxville +% 104 Ayres Hall +% Knoxville, TN 37996 +% USA +% +% eijkhout@cs.utk.edu +% +% Usage: all text included in between +% \comment ... \endcomment +% or \begin{comment} ... \end{comment} +% is discarded. The closing command should appear on a line +% of its own. No starting spaces, nothing after it. +% This environment should work with arbitrary amounts +% of comment. +% +% Other 'comment' environments are defined by +% and are selected/deselected with +% \includecomment{versiona} +% \excludecoment{versionb} +% +% These environments are used as +% \versiona ... \endversiona +% or \begin{versiona} ... \end{versiona} +% with the closing command again on a line of its own. +% +% Basic approach: +% to comment something out, scoop up every line in verbatim mode +% as macro argument, then throw it away. +% For inclusions, both the opening and closing comands +% are defined as noop +% +% Changed \next to \html@next to prevent clashes with other sty files +% (mike@emn.fr) +% Changed \html@next to \htmlnext so the \makeatletter and +% \makeatother commands could be removed (they were causing other +% style files - changebar.sty - to crash) (nikos@cbl.leeds.ac.uk) +% Changed \htmlnext back to \html@next... + +\def\makeinnocent#1{\catcode`#1=12 } +\def\csarg#1#2{\expandafter#1\csname#2\endcsname} + +\def\ThrowAwayComment#1{\begingroup + \def\CurrentComment{#1}% + \let\do\makeinnocent \dospecials + \makeinnocent\^^L% and whatever other special cases +%%RRM +%% use \xhtmlComment for \xComment +%% use \html@next for \next + \endlinechar`\^^M \catcode`\^^M=12 \xhtmlComment} +{\catcode`\^^M=12 \endlinechar=-1 % + \gdef\xhtmlComment#1^^M{\def\test{#1}\edef\test{\meaning\test} + \csarg\ifx{PlainEnd\CurrentComment Test}\test + \let\html@next\endgroup + \else \csarg\ifx{LaLaEnd\CurrentComment Test}\test + \edef\html@next{\endgroup\noexpand\end{\CurrentComment}} + \else \csarg\ifx{LaInnEnd\CurrentComment Test}\test + \edef\html@next{\endgroup\noexpand\end{\CurrentComment}} + \else \let\html@next\xhtmlComment + \fi \fi \fi \html@next} +} + +%%\def\includecomment %%RRM +\def\htmlincludecomment + #1{\expandafter\def\csname#1\endcsname{}% + \expandafter\def\csname end#1\endcsname{}} +%%\def\excludecomment %%RRM +\def\htmlexcludecomment + #1{\expandafter\def\csname#1\endcsname{\ThrowAwayComment{#1}}% + {\escapechar=-1\relax + \edef\tmp{\string\\end#1}% + \csarg\xdef{PlainEnd#1Test}{\meaning\tmp}% + \edef\tmp{\string\\end\string\{#1\string\}}% + \csarg\xdef{LaLaEnd#1Test}{\meaning\tmp}% + \edef\tmp{\string\\end \string\{#1\string\}}% + \csarg\xdef{LaInnEnd#1Test}{\meaning\tmp}% + }} + +%%\excludecomment{comment} %%RRM +\htmlexcludecomment{comment} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% end Comment.sty +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\let\includecomment=\htmlincludecomment +\let\excludecomment=\htmlexcludecomment + +% +% Alternative code by Robin Fairbairns, 22 September 1997 +% revised to cope with % and unnested { }, by Ross Moore, 4 July 1998 +% further revised to cope with & and # in tables, 10 March 1999 +% +\def\raw@catcodes{\catcode`\%=12 \catcode`\{=12 \catcode`\}=12 + \catcode`\&=12 \catcode`\#=12 } +\newcommand\@gobbleenv{\bgroup\raw@catcodes + \let\reserved@a\@currenvir\@gobble@nv} +\bgroup + \def\expansionhead{\gdef\@gobble@nv@i##1} + \def\expansiontail{{\def\reserved@b{##1}\@gobble@nv@ii}} + \def\expansionheadii{\long\gdef\@gobble@nv##1\end} + \def\expansiontailii{{\@gobble@nv@i}} + \def\expansionmidii{##2} + \raw@catcodes\relax + \expandafter\expansionhead\expandafter}\expansiontail +\egroup +\long\gdef\@gobble@nv#1\end#2{\@gobble@nv@i} +%\long\def\@gobble@nv#1\end#2{\def\reserved@b{#2}% +\def\@gobble@nv@ii{% + \ifx\reserved@a\reserved@b + \edef\reserved@a{\egroup\noexpand\end{\reserved@a}}% + \expandafter\reserved@a + \else + \expandafter\@gobble@nv + \fi} + +\renewcommand{\htmlexcludecomment}[1]{% + \csname newenvironment\endcsname{#1}{\@gobbleenv}{}} +\newcommand{\htmlreexcludecomment}[1]{% + \csname renewenvironment\endcsname{#1}{\@gobbleenv}{}} + +%%% RAW HTML +% +% Enclose raw HTML between a \begin{rawhtml} and \end{rawhtml}. +% The html environment ignores its body +% +\htmlexcludecomment{rawhtml} + + +%%% HTML ONLY +% +% Enclose LaTeX constructs which will only appear in the +% HTML output and will be ignored by LaTeX with +% \begin{htmlonly} and \end{htmlonly} +% +\htmlexcludecomment{htmlonly} +% Shorter version +\newcommand{\html}[1]{} + +% for images.tex only +\htmlexcludecomment{imagesonly} + +%%% LaTeX ONLY +% Enclose LaTeX constructs which will only appear in the +% DVI output and will be ignored by latex2html with +%\begin{latexonly} and \end{latexonly} +% +\newenvironment{latexonly}{}{} +% Shorter version +\newcommand{\latex}[1]{#1} + + +%%% LaTeX or HTML +% Combination of \latex and \html. +% Say \latexhtml{this should be latex text}{this html text} +% +%\newcommand{\latexhtml}[2]{#1} +\long\def\latexhtml#1#2{#1} + + +%%% tracing the HTML conversions +% This alters the tracing-level within the processing +% performed by latex2html by adjusting $VERBOSITY +% (see latex2html.config for the appropriate values) +% +\newcommand{\htmltracing}[1]{} +\newcommand{\htmltracenv}[1]{} + + +%%% \strikeout for HTML only +% uses <STRIKE>...</STRIKE> tags on the argument +% LaTeX just gobbles it up. +\newcommand{\strikeout}[1]{} + +%%% \htmlurl and \url +% implement \url as the simplest thing, if not already defined +% let \htmlurl#1 be equivalent to it +% +\def\htmlurlx#1{\begin{small}\texttt{#1}\end{small}}% +\expandafter\ifx\csname url\endcsname\relax + \let\htmlurl=\htmlurlx \else \let\htmlurl=\url \fi + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% JCL - stop input here if LaTeX2e is not present +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\ifx\if@compatibility\undefined + %LaTeX209 + \makeatother\relax\expandafter\endinput +\fi +\if@compatibility + %LaTeX2e in LaTeX209 compatibility mode + \makeatother\relax\expandafter\endinput +\fi + +%\let\real@TeXlogo = \TeX +%\DeclareRobustCommand{\TeX}{\relax\real@TeXlogo} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Start providing LaTeX2e extension: +% This is currently: +% - additional optional argument for \htmladdimg +% - support for segmented documents +% + +\ProvidesPackage{html} + [1999/07/19 v1.38 hypertext commands for latex2html (nd, hws, rrm)] + +% +% Ensure that \includecomment and \excludecomment are bound +% to the version defined here. +% +\AtBeginDocument{% + \let\includecomment=\htmlincludecomment + \let\excludecomment=\htmlexcludecomment + \htmlreexcludecomment{comment}} + +%%% bind \htmlurl to \url if that is later loaded +% +\expandafter\ifx\csname url\endcsname\relax + \AtBeginDocument{\@ifundefined{url}{}{\let\htmlurl=\url}}\fi + +%%%%MG + +% This command takes as argument a URL pointing to an image. +% The image will be embedded in the HTML document but will +% be ignored in the dvi and ps files. The optional argument +% denotes additional HTML tags. +% +% Example: \htmladdimg[ALT="portrait" ALIGN=CENTER]{portrait.gif} +% +\ifx\pdfunknown\relax + \renewcommand{\htmladdimg}[2][]{} +\else + \renewcommand{\htmladdimg}[2][]{\hyperimage{#2}} +\fi + +%%% HTMLRULE for LaTeX2e +% This command adds a horizontal rule and is valid even within +% a figure caption. +% +% This command is best used with LaTeX2e and HTML 3.2 support. +% It is like \hrule, but allows for options via key--value pairs +% as follows: \htmlrule[key1=value1, key2=value2, ...] . +% Use \htmlrule* to suppress the <BR> tag. +% Eg. \htmlrule[left, 15, 5pt, "none", NOSHADE] produces +% <BR CLEAR="left"><HR NOSHADE SIZE="15">. +% Renew the necessary part. +\renewcommand{\htmlrulestar}[1][all]{} + +%%% HTMLCLEAR for LaTeX2e +% This command puts in a <BR> tag, with optional CLEAR="<attrib>" +% +\renewcommand{\htmlclear}[1][all]{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% renew some definitions to allow optional arguments +% +% The description of the options is missing, as yet. +% +\renewcommand{\latextohtml}{\textup{\LaTeX2\texttt{HTML}}} +\ifx\pdfunknown\relax + \renewcommand{\htmladdnormallinkfoot}[3][]{#2\footnote{#3}} + \renewcommand{\htmladdnormallink}[3][]{#2} +\else + \renewcommand{\htmladdnormallinkfoot}[1][]{\def\next{#1}% + \ifx\next\@empty\def\next{\htmladdnonamedlinkfoot}% + \else\def\next{\htmladdnamedlinkfoot{#1}}\fi \next} + \newcommand{\htmladdnonamedlinkfoot}[2]{% + #1\footnote{\href{#2}{#2}}} + \newcommand{\htmladdnamedlinkfoot}[3]{% + \hypertarget{#1}{#2}\footnote{\href{#3}{#3}}} + \renewcommand{\htmladdnormallink}[1][]{\def\next{#1}% + \ifx\next\@empty\def\next{\htmladdnonamedlink}% + \else\def\next{\htmladdnamedlink{#1}}\fi \next} + \newcommand{\htmladdnonamedlink}[2]{\href{#2}{#1}} + \newcommand{\htmladdnamedlink}[3]{% + \hypertarget{#1}{\hskip2bp}\href{#3}{#2}} +\fi + +\renewcommand{\htmlbody}[1][]{} +\renewcommand{\htmlborder}[2][]{} +\renewcommand{\externallabels}[3][]{} +\renewcommand{\externalref}[2][]{} +\renewcommand{\externalcite}[1][]{\nocite} +\renewcommand{\hyperref}[1][]{\hyperrefi[#1]} +\renewcommand{\hypercite}[1][]{\hypercitei[#1]} +\renewcommand{\hypercitenocite}[2]{#2\hypercitenocitex} +\renewcommand{\hypercitenocitex}[2][]{\nocite{#2}} +\let\hyperciteno=\hypercitenocite +\let\hyperciteext=\hypercitenocite + +\ifx\pdfunknown\relax + \renewcommand{\htmlimage}[2][]{} + \renewcommand{\htmlref}[2][]{#2{\def\tmp{#1}\ifx\tmp\@empty + \aftergroup\htmlrefdef\else\aftergroup\htmlrefext\fi}} + \newcommand{\htmlrefdef}[1]{} + \newcommand{\htmlrefext}[2][]{} + \renewcommand{\htmlcite}[2][]{#2{\def\tmp{#1}\ifx\tmp\@empty + \aftergroup\htmlcitedef\else\aftergroup\htmlciteext\fi}} + \newcommand{\htmlciteext}[2][]{} +\else + \renewcommand{\htmlimage}[2][]{\hyperimage{#2}} + \renewcommand{\htmlref}[1][]{\def\htmp@{#1}\ifx\htmp@\@empty + \def\htmp@{\htmlrefdef}\else\def\htmp@{\htmlrefext{#1}}\fi\htmp@} + \newcommand{\htmlrefdef}[2]{\hyperref[hyper][#2]{#1}} + \newcommand{\htmlrefext}[3]{% + \hypertarget{#1}{\hskip2bp}\hyperref[hyper][#3]{#2}} + \renewcommand{\htmlcite}[2][]{#2{\def\htmp@{#1}\ifx\htmp@\@empty + \aftergroup\htmlcitedef\else\aftergroup\htmlciteext\fi}} + \newcommand{\htmlciteext}[1][]{\cite} +\fi +\newcommand{\htmlcitedef}[1]{ \nocite{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% HTML HTMLset HTMLsetenv +% +% These commands do nothing in LaTeX, but can be used to place +% HTML tags or set Perl variables during the LaTeX2HTML processing; +% They are intended for expert use only. + +\newcommand{\HTMLcode}[2][]{} +\ifx\undefined\HTML\newcommand{\HTML}[2][]{}\else +\typeout{*** Warning: \string\HTML\space had an incompatible definition ***}% +\typeout{*** instead use \string\HTMLcode\space for raw HTML code ***}% +\fi +\newcommand{\HTMLset}[3][]{} +\newcommand{\HTMLsetenv}[3][]{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The following commands pertain to document segmentation, and +% were added by Herbert Swan <dprhws@edp.Arco.com> (with help from +% Michel Goossens <goossens@cern.ch>): +% +% +% This command inputs internal latex2html tables so that large +% documents can to partitioned into smaller (more manageable) +% segments. +% +\newcommand{\internal}[2][internals]{} + +% +% Define a dummy stub \htmlhead{}. This command causes latex2html +% to define the title of the start of a new segment. It is not +% normally placed in the user's document. Rather, it is passed to +% latex2html via a .ptr file written by \segment. +% +\newcommand{\htmlhead}[3][]{} + +% In the LaTeX2HTML version this will eliminate the title line +% generated by a \segment command, but retains the title string +% for use in other places. +% +\newcommand{\htmlnohead}{} + + +% In the LaTeX2HTML version this put a URL into a <BASE> tag +% within the <HEAD>...</HEAD> portion of a document. +% +\ifx\pdfunknown\relax + \newcommand{\htmlbase}[1]{} +\else + \let\htmlbase=\hyperbaseurl +\fi + + +% Include style information into the stylesheet; e.g. CSS +% +\newcommand{\htmlsetstyle}[3][]{} +\newcommand{\htmladdtostyle}[3][]{} + +% Define a style-class for information in a particular language +% +\newcommand{\htmllanguagestyle}[2][]{} + + +% +% The dummy command \endpreamble is needed by latex2html to +% mark the end of the preamble in document segments that do +% not contain a \begin{document} +% +\newcommand{\startdocument}{} + + +% \tableofchildlinks, \htmlinfo +% by Ross Moore --- extensions dated 27 September 1997 +% +% These do nothing in LaTeX but for LaTeX2HTML they mark +% where the table of child-links and info-page should be placed, +% when the user wants other than the default. +% \tableofchildlinks % put mini-TOC at this location +% \tableofchildlinks[off] % not on current page +% \tableofchildlinks[none] % not on current and subsequent pages +% \tableofchildlinks[on] % selectively on current page +% \tableofchildlinks[all] % on current and all subsequent pages +% \htmlinfo % put info-page at this location +% \htmlinfo[off] % no info-page in current document +% \htmlinfo[none] % no info-page in current document +% *-versions omit the preceding <BR> tag. +% +\newcommand{\tableofchildlinks}{% + \@ifstar\tableofchildlinksstar\tableofchildlinksstar} +\newcommand{\tableofchildlinksstar}[1][]{} + +\newcommand{\htmlinfo}{\@ifstar\htmlinfostar\htmlinfostar} +\newcommand{\htmlinfostar}[1][]{} + + +% This redefines \begin to allow for an optional argument +% which is used by LaTeX2HTML to specify `style-sheet' information + +\let\realLaTeX@begin=\begin +\renewcommand{\begin}[1][]{\realLaTeX@begin} + + +% +% Allocate a new set of section counters, which will get incremented +% for "*" forms of sectioning commands, and for a few miscellaneous +% commands. +% + +\@ifundefined{c@part}{\newcounter{part}}{}% +\newcounter{lpart} +\newcounter{lchapter}[part] +\@ifundefined{c@chapter}% + {\let\Hchapter\relax \newcounter{chapter}\let\thechapter\relax + \newcounter{lsection}[part]}% + {\let\Hchapter=\chapter \newcounter{lsection}[chapter]} +\newcounter{lsubsection}[section] +\newcounter{lsubsubsection}[subsection] +\newcounter{lparagraph}[subsubsection] +\newcounter{lsubparagraph}[paragraph] +%\newcounter{lequation} + +% +% Redefine "*" forms of sectioning commands to increment their +% respective counters. +% +\let\Hpart=\part +%\let\Hchapter=\chapter +\let\Hsection=\section +\let\Hsubsection=\subsection +\let\Hsubsubsection=\subsubsection +\let\Hparagraph=\paragraph +\let\Hsubparagraph=\subparagraph +\let\Hsubsubparagraph=\subsubparagraph + +\ifx\c@subparagraph\undefined + \newcounter{lsubsubparagraph}[lsubparagraph] +\else + \newcounter{lsubsubparagraph}[subparagraph] +\fi + +% +% The following definitions are specific to LaTeX2e: +% (They must be commented out for LaTeX 2.09) +% +\expandafter\ifx\csname part\endcsname\relax\else +\renewcommand{\part}{\@ifstar{\stepcounter{lpart}% + \bgroup\def\tmp{*}\H@part}{\bgroup\def\tmp{}\H@part}}\fi +\newcommand{\H@part}[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hpart\tmp} + +\ifx\Hchapter\relax\else + \def\chapter{\resetsections \@ifstar{\stepcounter{lchapter}% + \bgroup\def\tmp{*}\H@chapter}{\bgroup\def\tmp{}\H@chapter}}\fi +\newcommand{\H@chapter}[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hchapter\tmp} + +\renewcommand{\section}{\resetsubsections + \@ifstar{\stepcounter{lsection}\bgroup\def\tmp{*}% + \H@section}{\bgroup\def\tmp{}\H@section}} +\newcommand{\H@section}[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hsection\tmp} + +\renewcommand{\subsection}{\resetsubsubsections + \@ifstar{\stepcounter{lsubsection}\bgroup\def\tmp{*}% + \H@subsection}{\bgroup\def\tmp{}\H@subsection}} +\newcommand{\H@subsection}[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hsubsection\tmp} + +\renewcommand{\subsubsection}{\resetparagraphs + \@ifstar{\stepcounter{lsubsubsection}\bgroup\def\tmp{*}% + \H@subsubsection}{\bgroup\def\tmp{}\H@subsubsection}} +\newcommand{\H@subsubsection}[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hsubsubsection\tmp} + +\renewcommand{\paragraph}{\resetsubparagraphs + \@ifstar{\stepcounter{lparagraph}\bgroup\def\tmp{*}% + \H@paragraph}{\bgroup\def\tmp{}\H@paragraph}} +\newcommand\H@paragraph[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hparagraph\tmp} + +\ifx\Hsubparagraph\relax\else\@ifundefined{subparagraph}{}{% +\renewcommand{\subparagraph}{\resetsubsubparagraphs + \@ifstar{\stepcounter{lsubparagraph}\bgroup\def\tmp{*}% + \H@subparagraph}{\bgroup\def\tmp{}\H@subparagraph}}}\fi +\newcommand\H@subparagraph[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hsubparagraph\tmp} + +\ifx\Hsubsubparagraph\relax\else\@ifundefined{subsubparagraph}{}{% +\def\subsubparagraph{% + \@ifstar{\stepcounter{lsubsubparagraph}\bgroup\def\tmp{*}% + \H@subsubparagraph}{\bgroup\def\tmp{}\H@subsubparagraph}}}\fi +\newcommand\H@subsubparagraph[1][]{\def\tmp@a{#1}\check@align + \expandafter\egroup\expandafter\Hsubsubparagraph\tmp} + +\def\check@align{\def\empty{}\ifx\tmp@a\empty + \else\def\tmp@b{center}\ifx\tmp@a\tmp@b\let\tmp@a\empty + \else\def\tmp@b{left}\ifx\tmp@a\tmp@b\let\tmp@a\empty + \else\def\tmp@b{right}\ifx\tmp@a\tmp@b\let\tmp@a\empty + \else\expandafter\def\expandafter\tmp@a\expandafter{\expandafter[\tmp@a]}% + \fi\fi\fi \def\empty{}\ifx\tmp\empty\let\tmp=\tmp@a \else + \expandafter\def\expandafter\tmp\expandafter{\expandafter*\tmp@a}% + \fi\fi} +% +\def\resetsections{\setcounter{section}{0}\setcounter{lsection}{0}% + \reset@dependents{section}\resetsubsections } +\def\resetsubsections{\setcounter{subsection}{0}\setcounter{lsubsection}{0}% + \reset@dependents{subsection}\resetsubsubsections } +\def\resetsubsubsections{\setcounter{subsubsection}{0}\setcounter{lsubsubsection}{0}% + \reset@dependents{subsubsection}\resetparagraphs } +% +\def\resetparagraphs{\setcounter{lparagraph}{0}\setcounter{lparagraph}{0}% + \reset@dependents{paragraph}\resetsubparagraphs } +\def\resetsubparagraphs{\ifx\c@subparagraph\undefined\else + \setcounter{subparagraph}{0}\fi \setcounter{lsubparagraph}{0}% + \reset@dependents{subparagraph}\resetsubsubparagraphs } +\def\resetsubsubparagraphs{\ifx\c@subsubparagraph\undefined\else + \setcounter{subsubparagraph}{0}\fi \setcounter{lsubsubparagraph}{0}} +% +\def\reset@dependents#1{\begingroup\let \@elt \@stpelt + \csname cl@#1\endcsname\endgroup} +% +% +% Define a helper macro to dump a single \secounter command to a file. +% +\newcommand{\DumpPtr}[2]{% +\count255=\csname c@#1\endcsname\relax\def\dummy{dummy}\def\tmp{#2}% +\ifx\tmp\dummy\def\ctr{#1}\else + \def\ctr{#2}\advance\count255 by \csname c@#2\endcsname\relax\fi +\immediate\write\ptrfile{% +\noexpand\setcounter{\ctr}{\number\count255}}} +%\expandafter\noexpand\expandafter\setcounter\expandafter{\ctr}{\number\count255}}} + +% +% Define a helper macro to dump all counters to the file. +% The value for each counter will be the sum of the l-counter +% actual LaTeX section counter. +% Also dump an \htmlhead{section-command}{section title} command +% to the file. +% +\newwrite\ptrfile +\def\DumpCounters#1#2#3#4{% +\begingroup\let\protect=\noexpand +\immediate\openout\ptrfile = #1.ptr +\DumpPtr{part}{lpart}% +\ifx\Hchapter\relax\else\DumpPtr{chapter}{lchapter}\fi +\DumpPtr{section}{lsection}% +\DumpPtr{subsection}{lsubsection}% +\DumpPtr{subsubsection}{lsubsubsection}% +\DumpPtr{paragraph}{lparagraph}% +\DumpPtr{subparagraph}{lsubparagraph}% +\DumpPtr{equation}{dummy}% +\DumpPtr{footnote}{dummy}% +\def\tmp{#4}\ifx\tmp\@empty +\immediate\write\ptrfile{\noexpand\htmlhead{#2}{#3}}\else +\immediate\write\ptrfile{\noexpand\htmlhead[#4]{#2}{#3}}\fi +\dumpcitestatus \dumpcurrentcolor +\immediate\closeout\ptrfile +\endgroup } + + +%% interface to natbib.sty + +\def\dumpcitestatus{} +\def\loadcitestatus{\def\dumpcitestatus{% + \ifciteindex\immediate\write\ptrfile{\noexpand\citeindextrue}% + \else\immediate\write\ptrfile{\noexpand\citeindexfalse}\fi }% +} +\@ifpackageloaded{natbib}{\loadcitestatus}{% + \AtBeginDocument{\@ifpackageloaded{natbib}{\loadcitestatus}{}}} + + +%% interface to color.sty + +\def\dumpcurrentcolor{} +\def\loadsegmentcolors{% + \let\real@pagecolor=\pagecolor + \let\pagecolor\segmentpagecolor + \let\segmentcolor\color + \ifx\current@page@color\undefined \def\current@page@color{{}}\fi + \def\dumpcurrentcolor{\bgroup\def\@empty@{{}}% + \expandafter\def\expandafter\tmp\space####1@{\def\thiscol{####1}}% + \ifx\current@color\@empty@\def\thiscol{}\else + \expandafter\tmp\current@color @\fi + \immediate\write\ptrfile{\noexpand\segmentcolor{\thiscol}}% + \ifx\current@page@color\@empty@\def\thiscol{}\else + \expandafter\tmp\current@page@color @\fi + \immediate\write\ptrfile{\noexpand\segmentpagecolor{\thiscol}}% + \egroup}% + \global\let\loadsegmentcolors=\relax +} + +% These macros are needed within images.tex since this inputs +% the <segment>.ptr files for a segment, so that counters are +% colors are synchronised. +% +\newcommand{\segmentpagecolor}[1][]{% + \@ifpackageloaded{color}{\loadsegmentcolors\bgroup + \def\tmp{#1}\ifx\@empty\tmp\def\next{[]}\else\def\next{[#1]}\fi + \expandafter\segmentpagecolor@\next}% + {\@gobble}} +\def\segmentpagecolor@[#1]#2{\def\tmp{#1}\def\tmpB{#2}% + \ifx\tmpB\@empty\let\next=\egroup + \else + \let\realendgroup=\endgroup + \def\endgroup{\edef\next{\noexpand\realendgroup + \def\noexpand\current@page@color{\current@color}}\next}% + \ifx\tmp\@empty\real@pagecolor{#2}\def\model{}% + \else\real@pagecolor[#1]{#2}\def\model{[#1]}% + \fi + \edef\next{\egroup\def\noexpand\current@page@color{\current@page@color}% + \noexpand\real@pagecolor\model{#2}}% + \fi\next} +% +\newcommand{\segmentcolor}[2][named]{\@ifpackageloaded{color}% + {\loadsegmentcolors\segmentcolor[#1]{#2}}{}} + +\@ifpackageloaded{color}{\loadsegmentcolors}{\let\real@pagecolor=\@gobble + \AtBeginDocument{\@ifpackageloaded{color}{\loadsegmentcolors}{}}} + + +% Define the \segment[align]{file}{section-command}{section-title} command, +% and its helper macros. This command does four things: +% 1) Begins a new LaTeX section; +% 2) Writes a list of section counters to file.ptr, each +% of which represents the sum of the LaTeX section +% counters, and the l-counters, defined above; +% 3) Write an \htmlhead{section-title} command to file.ptr; +% 4) Inputs file.tex. + +\newcommand{\segment}{\@ifstar{\@@htmls}{\@@html}} +%\tracingall +\newcommand{\@endsegment}[1][]{} +\let\endsegment\@endsegment +\newcommand{\@@htmls}[1][]{\@@htmlsx{#1}} +\newcommand{\@@html}[1][]{\@@htmlx{#1}} +\def\@@htmlsx#1#2#3#4{\csname #3\endcsname* {#4}% + \DumpCounters{#2}{#3*}{#4}{#1}\input{#2}} +\def\@@htmlx#1#2#3#4{\csname #3\endcsname {#4}% + \DumpCounters{#2}{#3}{#4}{#1}\input{#2}} + +\makeatother +\endinput + + +% Modifications: +% +% (The listing of Initiales see Changes) + +% $Log: html.sty,v $ +% Revision 1.1 2001/05/12 00:38:48 cvs +% *** empty log message *** +% +% Revision 1.1 2000/03/22 05:04:32 jelson +% added parapin documentation +% +% Revision 1.38 1999/07/19 13:23:20 RRM +% -- compatibility with pdflatex and hyperref.sty +% citations are not complete yet, I think +% -- ensure that \thechapter remains undefined; some packages use it +% as a test for the type of documentclass being used. +% +% Revision 1.37 1999/03/12 07:02:38 RRM +% -- change macro name from \addTOCsection to \htmladdTOClink +% -- it has 3 + 1 optional argument, to allow a local path to a labels.pl +% file for the external document, for cross-references +% +% Revision 1.36 1999/03/10 05:46:00 RRM +% -- extended the code for compatibilty with comment.sty +% -- allow excluded environments to work within tables, +% with the excluded material spanning headers and several cells +% thanks Avinash Chopde for recognising the need for this. +% -- added LaTeX support (ignores it) for \htmladdTOCsection +% thanks to Steffen Klupsch and Uli Wortmann for this idea. +% +% Revision 1.35 1999/03/08 11:16:16 RRM +% html.sty for LaTeX2HTML V99.1 +% +% -- ensure that html.sty can be loaded *after* hyperref.sty +% -- support new command \htmlclear for <BR> in HTML, ignored by LaTeX +% -- ensure {part} and {chapter} counters are defined, even if not used +% +% Revision 1.34 1998/09/19 10:37:29 RRM +% -- fixed typo with \next{\hyperref}{....} +% +% Revision 1.33 1998/09/08 12:47:51 RRM +% -- changed macro-names for the \hyperref and \hypercite options +% allows easier compatibility with other packages +% +% Revision 1.32 1998/08/24 12:15:14 RRM +% -- new command \htmllanguagestyle to associate a style class +% with text declared as a particular language +% +% Revision 1.31 1998/07/07 14:15:41 RRM +% -- new commands \htmlsetstyle and \htmladdtostyle +% +% Revision 1.30 1998/07/04 02:42:22 RRM +% -- cope with catcodes of % { } in rawhtml/comment/htmlonly environments +% +% Revision 1.29 1998/06/23 13:33:23 RRM +% -- use \begin{small} with the default for URLs +% +% Revision 1.28 1998/06/21 09:38:39 RRM +% -- implement \htmlurl to agree with \url if already defined +% or loaded subsequently (LaTeX-2e only) +% -- get LaTeX to print the revision number when loading +% +% Revision 1.27 1998/06/20 15:13:10 RRM +% -- \TeX is already protected in recent versions of LaTeX +% so \DeclareRobust doesn't work --- causes looping +% -- \part and \subparagraph need not be defined in some styles +% +% Revision 1.26 1998/06/01 08:36:49 latex2html +% -- implement optional argument for \endsegment +% -- made the counter value output from \DumpPtr more robust +% +% Revision 1.25 1998/05/09 05:43:35 latex2html +% -- conditionals for avoiding undefined counters +% +% Revision 1.23 1998/02/26 10:32:24 latex2html +% -- use \providecommand for \latextohtml +% -- implemented \HTMLcode to do what \HTML did previously +% \HTML still works, unless already defined by another package +% -- fixed problems remaining with undefined \chapter +% -- defined \endsegment +% +% Revision 1.22 1997/12/05 11:38:18 RRM +% -- implemented an optional argument to \begin for style-sheet info. +% -- modified use of an optional argument with sectioning-commands +% +% Revision 1.21 1997/11/05 10:28:56 RRM +% -- replaced redefinition of \@htmlrule with \htmlrulestar +% +% Revision 1.20 1997/10/28 02:15:58 RRM +% -- altered the way some special html-macros are defined, so that +% star-variants are explicitly defined for LaTeX +% -- it is possible for these to occur within images.tex +% e.g. \htmlinfostar \htmlrulestar \tableofchildlinksstar +% +% Revision 1.19 1997/10/11 05:47:48 RRM +% -- allow the dummy {tex2html_nowrap} environment in LaTeX +% use it to make its contents be evaluated in environment order +% +% Revision 1.18 1997/10/04 06:56:50 RRM +% -- uses Robin Fairbairns' code for ignored environments, +% replacing the previous comment.sty stuff. +% -- extensions to the \tableofchildlinks command +% -- extensions to the \htmlinfo command +% +% Revision 1.17 1997/07/08 11:23:39 RRM +% include value of footnote counter in .ptr files for segments +% +% Revision 1.16 1997/07/03 08:56:34 RRM +% use \textup within the \latextohtml macro +% +% Revision 1.15 1997/06/15 10:24:58 RRM +% new command \htmltracenv as environment-ordered \htmltracing +% +% Revision 1.14 1997/06/06 10:30:37 RRM +% - new command: \htmlborder puts environment into a <TABLE> cell +% with a border of specified width, + other attributes. +% - new commands: \HTML for setting arbitrary HTML tags, with attributes +% \HTMLset for setting Perl variables, while processing +% \HTMLsetenv same as \HTMLset , but it gets processed +% as if it were an environment. +% - new command: \latextohtml --- to set the LaTeX2HTML name/logo +% - fixed some remaining problems with \segmentcolor & \segmentpagecolor +% +% Revision 1.13 1997/05/19 13:55:46 RRM +% alterations and extra options to \hypercite +% +% Revision 1.12 1997/05/09 12:28:39 RRM +% - Added the optional argument to \htmlhead, also in \DumpCounters +% - Implemented \HTMLset as a no-op in LaTeX. +% - Fixed a bug in accessing the page@color settings. +% +% Revision 1.11 1997/03/26 09:32:40 RRM +% - Implements LaTeX versions of \externalcite and \hypercite commands. +% Thanks to Uffe Engberg and Stephen Simpson for the suggestions. +% +% Revision 1.10 1997/03/06 07:37:58 RRM +% Added the \htmltracing command, for altering $VERBOSITY . +% +% Revision 1.9 1997/02/17 02:26:26 RRM +% - changes to counter handling (RRM) +% - shuffled around some definitions +% - changed \htmlrule of 209 mode +% +% Revision 1.8 1997/01/26 09:04:12 RRM +% RRM: added optional argument to sectioning commands +% \htmlbase sets the <BASE HREF=...> tag +% \htmlinfo and \htmlinfo* allow the document info to be positioned +% +% Revision 1.7 1997/01/03 12:15:44 L2HADMIN +% % - fixes to the color and natbib interfaces +% % - extended usage of \hyperref, via an optional argument. +% % - extended use comment environments to allow shifting expansions +% % e.g. within \multicolumn (`bug' reported by Luc De Coninck). +% % - allow optional argument to: \htmlimage, \htmlhead, +% % \htmladdimg, \htmladdnormallink, \htmladdnormallinkfoot +% % - added new commands: \htmlbody, \htmlnohead +% % - added new command: \tableofchildlinks +% +% Revision 1.6 1996/12/25 03:04:54 JCL +% added patches to segment feature from Martin Wilck +% +% Revision 1.5 1996/12/23 01:48:06 JCL +% o introduced the environment makeimage, which may be used to force +% LaTeX2HTML to generate an image from the contents. +% There's no magic, all what we have now is a defined empty environment +% which LaTeX2HTML will not recognize and thus pass it to images.tex. +% o provided \protect to the \htmlrule commands to allow for usage +% within captions. +% +% Revision 1.4 1996/12/21 19:59:22 JCL +% - shuffled some entries +% - added \latexhtml command +% +% Revision 1.3 1996/12/21 12:22:59 JCL +% removed duplicate \htmlrule, changed \htmlrule back not to create a \hrule +% to allow occurrence in caption +% +% Revision 1.2 1996/12/20 04:03:41 JCL +% changed occurrence of \makeatletter, \makeatother +% added new \htmlrule command both for the LaTeX2.09 and LaTeX2e +% sections +% +% +% jcl 30-SEP-96 +% - Stuck the commands commonly used by both LaTeX versions to the top, +% added a check which stops input or reads further if the document +% makes use of LaTeX2e. +% - Introduced rrm's \dumpcurrentcolor and \bodytext +% hws 31-JAN-96 - Added support for document segmentation +% hws 10-OCT-95 - Added \htmlrule command +% jz 22-APR-94 - Added support for htmlref +% nd - Created diff --git a/doc/make-examples.pl b/doc/make-examples.pl new file mode 100755 index 0000000..ea3d239 --- /dev/null +++ b/doc/make-examples.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w + + +foreach $path (@ARGV) { + $writing = 0; + + if (!open(IN, $path)) { + print "trying to open $path: $!\n"; + next; + } + + while ($line = <IN>) { + if ($line =~ /EXAMPLE (\w*) ([\w\-\.]*)/) { + $command = $1; + $filename = $2 . ".example"; + + if ($command eq 'START') { + if ($writing == 0) { + if (!open(OUT, ">>$filename")) { + print "trying to write to $filename: $!\n"; + } else { + print "$path: writing to $filename\n"; + $writing = 1; + } + } else { + print "$path: got $line while already writing!\n"; + } + } + + if ($command eq 'STOP') { + if ($writing == 1) { + close(OUT); + $writing = 0; + } else { + chomp($line); + die "$path line $.: got $line when not writing!\n"; + } + } + } else { + if ($writing && $line !~ /SKIPLINE/) { + print OUT $line; + } + } + } + if ($writing) { + close(OUT); + } + close(IN); +} + diff --git a/examples/console-read.c b/examples/console-read.c new file mode 100644 index 0000000..3d595e9 --- /dev/null +++ b/examples/console-read.c @@ -0,0 +1,99 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * console-read: This example demonstrates the easiest possible way to + * block a client system call: by blocking the driver itself. Not + * recommended for anything but the most trivial drivers -- if you + * need a template from which to start on a real driver, use pager.c + * instead. + * + * $Id: console-read.c,v 1.4 2003/07/11 22:29:38 cerpa Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "fusd.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +int do_open_or_close(struct fusd_file_info *file) +{ + return 0; /* attempts to open and close this file always succeed */ +} + +/* EXAMPLE START console-read.c */ +int do_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + char buf[128]; + + if (*offset > 0) + return 0; + + /* print a prompt */ + printf("Got a read from pid %d. What do we say?\n> ", file->pid); + fflush(stdout); + + /* get a response from the console */ + if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) + return 0; + + /* compute length of the response, and return */ + user_length = MIN(user_length, strlen(buf)); + memcpy(user_buffer, buf, user_length); + *offset += user_length; + return user_length; +} +/* EXAMPLE STOP */ + +int main(int argc, char *argv[]) +{ + struct fusd_file_operations fops = { + open: do_open_or_close, + read: do_read, + close: do_open_or_close }; + + if (fusd_register("/dev/console-read", "misc", "console-read", 0666, NULL, &fops) < 0) + perror("Unable to register device"); + else { + printf("/dev/console-read should now exist - calling fusd_run...\n"); + fusd_run(); + } + return 0; +} + diff --git a/examples/drums.c b/examples/drums.c new file mode 100644 index 0000000..cdf3139 --- /dev/null +++ b/examples/drums.c @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * drums.c: Example of how to pass data to a callback, inspired by + * Alessandro Rubini's similar example in his article for Linux + * Magazine (http://www.linux.it/kerneldocs/devfs/) + * + * This example creates a bunch of devices in the /dev/drums + * directory: /dev/drums/bam, /dev/drums/bum, etc. If you cat one of + * these devices, it returns a string that's the same as its name. + * + * $Id: drums.c,v 1.4 2003/07/11 22:29:38 cerpa Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "fusd.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + + +/* EXAMPLE START drums.c */ +static char *drums_strings[] = {"bam", "bum", "beat", "boom", + "bang", "crash", NULL}; + +int drums_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + int len; + char sound[128]; + + /* file->device_info is what we passed to fusd_register when we + * registered the device */ + strcpy(sound, (char *) file->device_info); + strcat(sound, "\n"); + + /* 1st read returns the sound; 2nd returns EOF */ + if (*offset != 0) + return 0; + + /* NEVER return more data than the user asked for */ + len = MIN(user_length, strlen(sound)); + memcpy(user_buffer, sound, len); + *offset += len; + return len; +} + +/* EXAMPLE STOP drums.c */ + + +int do_open_or_close(struct fusd_file_info *file) +{ + return 0; /* opens and closes always succeed */ +} + + +struct fusd_file_operations drums_fops = { + open: do_open_or_close, + read: drums_read, + close: do_open_or_close +}; + +/* EXAMPLE START drums.c */ +int main(int argc, char *argv[]) +{ + int i; + char buf[128]; + char devname[128]; + + for (i = 0; drums_strings[i] != NULL; i++) { + sprintf(buf, "/dev/drums/%s", drums_strings[i]); + sprintf(devname, "drum%s", drums_strings[i]); + if (fusd_register(buf, "drums", devname, 0666, drums_strings[i], &drums_fops) < 0) + fprintf(stderr, "%s register failed: %m\n", drums_strings[i]); + } + + fprintf(stderr, "calling fusd_run...\n"); + fusd_run(); + return 0; +} +/* EXAMPLE STOP drums.c */ diff --git a/examples/drums2.c b/examples/drums2.c new file mode 100644 index 0000000..62ccd46 --- /dev/null +++ b/examples/drums2.c @@ -0,0 +1,144 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * drums2.c: Another example of how to pass data to a callback, + * inspired by Alessandro Rubini's similar example in his article for + * Linux Magazine (http://www.linux.it/kerneldocs/devfs/) + * + * Like the original drums.c, this example creates a bunch of devices + * in the /dev/drums directory: /dev/drums/bam, /dev/drums/bum, etc. + * However, it also uses the private_data structure to keep per-file + * state, and return a string unique to each user of the device. + * + * Note, unlike the original drums.c, this driver does not use *offset + * to remember if this user has read before; cat /dev/drums/X will + * read infinitely + * + * $Id: drums2.c,v 1.6 2003/07/11 22:29:38 cerpa Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "fusd.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + + +/* EXAMPLE START drums2.c */ +struct drum_info { + char *name; + int num_users; +} drums[] = { + { "bam", 0 }, + { "bum", 0 }, + /* ... */ +/* EXAMPLE STOP */ + { "beat", 0 }, + { "boom", 0 }, + { "bang", 0 }, + { "crash", 0 }, +/* EXAMPLE START drums2.c */ + { NULL, 0 } +}; + +int drums_open(struct fusd_file_info *file) +{ + /* file->device_info is what we passed to fusd_register when we + * registered the device. It's a pointer into the "drums" struct. */ + struct drum_info *d = (struct drum_info *) file->device_info; + + /* Store this user's unique user number in their private_data */ + file->private_data = (void *) ++(d->num_users); + + return 0; /* return success */ +} + +int drums_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + struct drum_info *d = (struct drum_info *) file->device_info; + int len; + char sound[128]; + + sprintf(sound, "You are user %d to hear a drum go '%s'!\n", + (int) file->private_data, d->name); + + len = MIN(user_length, strlen(sound)); + memcpy(user_buffer, sound, len); + return len; +} +/* EXAMPLE STOP */ + + +int drums_close(struct fusd_file_info *file) +{ + return 0; /* closes always succeed */ +} + + +struct fusd_file_operations drums_fops = { + open: drums_open, + read: drums_read, + close: drums_close +}; + +/* EXAMPLE START drums2.c */ + +int main(int argc, char *argv[]) +{ + struct drum_info *d; + char buf[128]; + char devname[128]; + + for (d = drums; d->name != NULL; d++) { + sprintf(buf, "/dev/drums/%s", d->name); + sprintf(devname, "drum%s", d->name); + if (fusd_register(buf, "drums", devname, 0666, d, &drums_fops) < 0) + fprintf(stderr, "%s register failed: %m\n", d->name); + } + /* ... */ +/* EXAMPLE STOP */ + + fprintf(stderr, "calling fusd_run...\n"); + fusd_run(); + return 0; +} + + + diff --git a/examples/drums3.c b/examples/drums3.c new file mode 100644 index 0000000..3361d69 --- /dev/null +++ b/examples/drums3.c @@ -0,0 +1,200 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * drums3.c: This example shows how to wait for both FUSD and non-FUSD + * events at the same time. Instead of using fusd_run, we keep + * control of main() by using our own select loop. + * + * Like the original drums.c, this example creates a bunch of devices + * in the /dev/drums directory: /dev/drums/bam, /dev/drums/bum, etc. + * However, it also prints a prompt to the console, asking the user if + * how loud the drums should be. + * + * $Id: drums3.c,v 1.3 2003/07/11 22:29:38 cerpa Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> + +#include "fusd.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + + +static char *drums_strings[] = {"bam", "bum", "beat", "boom", + "bang", "crash", NULL}; + +int volume = 2; /* default volume is 2 */ + +int drums_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + int len; + char sound[128], *c; + + /* 1st read returns the sound; 2nd returns EOF */ + if (*offset != 0) + return 0; + + if (volume == 1) + strcpy(sound, "(you hear nothing)"); + else { + strcpy(sound, (char *) file->device_info); + + if (volume >= 3) + for (c = sound; *c; c++) + *c = toupper(*c); + + if (volume >= 4) + strcat(sound, "!!!!!"); + } + + strcat(sound, "\n"); + + /* NEVER return more data than the user asked for */ + len = MIN(user_length, strlen(sound)); + memcpy(user_buffer, sound, len); + *offset += len; + return len; +} + + +int do_open_or_close(struct fusd_file_info *file) +{ + return 0; /* opens and closes always succeed */ +} + + +struct fusd_file_operations drums_fops = { + open: do_open_or_close, + read: drums_read, + close: do_open_or_close +}; + + +void read_volume(int fd) +{ + char buf[100]; + int new_vol = 0, retval; + + if (fd < 0) + goto prompt; + + retval = read(fd, buf, sizeof(buf)-1); + + if (retval >= 0) { + buf[retval] = '\0'; + + if (*buf == 'q') { + printf("Goodbye...\n"); + exit(0); + } + + new_vol = atoi(buf); + } + + if (new_vol >= 1 && new_vol <= 4) { + volume = new_vol; + printf("Volume changed to %d\n", volume); + } else { + printf("Invalid volume!\n"); + } + + prompt: + printf("\nHow loud would you like the /dev/drums?\n"); + printf(" 1 - Inaudible\n"); + printf(" 2 - Quiet\n"); + printf(" 3 - Loud\n"); + printf(" 4 - Permanent ear damage!\n"); + printf(" q - Exit program\n"); + printf("Your choice? "); + fflush(stdout); +} + + + + +int main(int argc, char *argv[]) +{ + int i; + char buf[128]; + char devname[128]; + fd_set fds, tmp; + int max; + + for (i = 0; drums_strings[i] != NULL; i++) { + sprintf(buf, "/dev/drums/%s", drums_strings[i]); + sprintf(devname, "drum%s", drums_strings[i]); + if (fusd_register(buf, "drums", devname, 0666, drums_strings[i], &drums_fops) < 0) + fprintf(stderr, "%s register failed: %m\n", drums_strings[i]); + } + + /* print the initial prompt to the user */ + read_volume(-1); + +/* EXAMPLE START drums3.c */ + /* initialize the set */ + FD_ZERO(&fds); + + /* add stdin to the set */ + FD_SET(STDIN_FILENO, &fds); + max = STDIN_FILENO; + + /* add all FUSD fds to the set */ + fusd_fdset_add(&fds, &max); + + while (1) { + tmp = fds; + if (select(max+1, &tmp, NULL, NULL, NULL) < 0) + perror("selecting"); + else { + /* if stdin is readable, read the user's response */ + if (FD_ISSET(STDIN_FILENO, &tmp)) + read_volume(STDIN_FILENO); + + /* call any FUSD callbacks that have messages waiting */ + fusd_dispatch_fdset(&tmp); + } + } +/* EXAMPLE STOP drums3.c */ +} + + + diff --git a/examples/echo.c b/examples/echo.c new file mode 100644 index 0000000..b367b7c --- /dev/null +++ b/examples/echo.c @@ -0,0 +1,124 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * echo.c: Example of how to use both the 'read' and 'write' callbacks. + * + * This example creates a single device, /dev/echo. If you write + * something to /dev/echo (e.g., "echo HI THERE > /dev/echo"), it gets + * stored. Then, when you read (e.g. "cat /dev/echo"), you get back + * whatever you wrote most recently. + * + * $Id: echo.c,v 1.6 2003/07/11 22:29:38 cerpa Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "fusd.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +/* EXAMPLE START echo.c */ +char *data = NULL; +int data_length = 0; + +int echo_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + /* if the user has read past the end of the data, return EOF */ + if (*offset >= data_length) + return 0; + + /* only return as much data as we have */ + user_length = MIN(user_length, data_length - *offset); + + /* copy data to user starting from the first byte they haven't seen */ + memcpy(user_buffer, data + *offset, user_length); + *offset += user_length; + + /* tell them how much data they got */ + return user_length; +} + +ssize_t echo_write(struct fusd_file_info *file, const char *user_buffer, + size_t user_length, loff_t *offset) +{ + /* free the old data, if any */ + if (data != NULL) { + free(data); + data = NULL; + data_length = 0; + } + + /* allocate space for new data; return error if that fails */ + if ((data = malloc(user_length)) == NULL) + return -ENOMEM; + + /* make a copy of user's data; tell the user we copied everything */ + memcpy(data, user_buffer, user_length); + data_length = user_length; + return user_length; +} +/* EXAMPLE STOP */ + +int do_open_or_close(struct fusd_file_info *file) +{ + return 0; /* opens and closes always succeed */ +} + + +struct fusd_file_operations echo_fops = { + open: do_open_or_close, + read: echo_read, + write: echo_write, + close: do_open_or_close +}; + + +int main(int argc, char *argv[]) +{ + if (fusd_register("/dev/echo", "misc", "echo", 0666, NULL, &echo_fops) < 0) { + perror("register of /dev/echo failed"); + exit(1); + } + + fprintf(stderr, "calling fusd_run...\n"); + fusd_run(); + return 0; +} diff --git a/examples/helloworld b/examples/helloworld new file mode 100755 index 0000000000000000000000000000000000000000..9a29ada0ead5f846f66969fe498e2f9ac07eeeb3 GIT binary patch literal 27353 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 U%tVM{nTYWJsS+2n=nB*S4eWI#8~^|S literal 0 HcmV?d00001 diff --git a/examples/helloworld.c b/examples/helloworld.c new file mode 100644 index 0000000..9fcb07b --- /dev/null +++ b/examples/helloworld.c @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * hello-world: Simply creates a device called /dev/hello-world, which + * greets you when you try to get it. + * + * $Id: helloworld.c,v 1.11 2003/07/11 22:29:38 cerpa Exp $ + */ + +/* EXAMPLE START helloworld.c */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "fusd.h" + +#define GREETING "Hello, world!\n" + +int do_open_or_close(struct fusd_file_info *file) +{ + return 0; /* attempts to open and close this file always succeed */ +} + +ssize_t do_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + int retval = 0; + + /* The first read to the device returns a greeting. The second read + * returns EOF. */ + if (*offset == 0) { + if (user_length < strlen(GREETING)) + retval = -EINVAL; /* the user must supply a big enough buffer! */ + else { + memcpy(user_buffer, GREETING, strlen(GREETING)); /* greet user */ + retval = strlen(GREETING); /* retval = number of bytes returned */ + *offset += retval; /* advance user's file pointer */ + } + } + + return retval; +} + +int main(int argc, char *argv[]) +{ + struct fusd_file_operations fops = { + open: do_open_or_close, + read: do_read, + close: do_open_or_close }; + + if (fusd_register("/dev/hello-world", "test", "hello-world", 0666, NULL, &fops) < 0) + perror("Unable to register device"); + else { + printf("/dev/hello-world should now exist - calling fusd_run...\n"); + fusd_run(); + } + return 0; +} +/* EXAMPLE STOP helloworld.c */ diff --git a/examples/ioctl.c b/examples/ioctl.c new file mode 100644 index 0000000..fdadaf1 --- /dev/null +++ b/examples/ioctl.c @@ -0,0 +1,292 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * ioctl.c: Shows both the client side and server side of FUSD ioctl + * servicing. + * + * There's a lot of extra cruft in this example program (compared to + * the other examples, anyway), because this program is both an + * example and part of the regression test suite. + * + * $Id: ioctl.c,v 1.4 2003/07/11 22:29:39 cerpa Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/wait.h> + +#include "fusd.h" + +/* EXAMPLE START ioctl.h */ +/* definition of the structure exchanged between client and server */ +struct ioctl_data_t { + char string1[60]; + char string2[60]; +}; + +#define IOCTL_APP_TYPE 71 /* arbitrary number unique to this app */ + +#define IOCTL_TEST0 _IO(IOCTL_APP_TYPE, 0) /* no argument */ /* SKIPLINE */ +#define IOCTL_TEST1 _IO(IOCTL_APP_TYPE, 1) /* int argument */ /* SKIPLINE */ +#define IOCTL_TEST2 _IO(IOCTL_APP_TYPE, 2) /* int argument */ +#define IOCTL_TEST3 _IOR(IOCTL_APP_TYPE, 3, struct ioctl_data_t) +#define IOCTL_TEST4 _IOW(IOCTL_APP_TYPE, 4, struct ioctl_data_t) +#define IOCTL_TEST5 _IOWR(IOCTL_APP_TYPE, 5, struct ioctl_data_t) +/* EXAMPLE STOP ioctl.h */ +#define IOCTL_TEST_TERMINATE _IO(IOCTL_APP_TYPE, 6) + +#define TEST1_NUM 12345 +#define TEST3_STRING1 "This is test3 - string1" +#define TEST3_STRING2 "This is test3 - string2" +#define TEST4_STRING1 "This is test 4's string1" +#define TEST4_STRING2 "This is test 4's string2" +#define TEST5_STRING1_IN "If you're happy and you know it" +#define TEST5_STRING2_IN "clap your hands!" +#define TEST5_STRING1_OUT "IF YOU'RE HAPPY AND YOU KNOW IT" +#define TEST5_STRING2_OUT "CLAP YOUR HANDS!" + + +#define CHECK(condition) do { \ + if (!(condition)) { \ + printf("%s: TEST FAILED\n", __STRING(condition)); \ + errors++; \ + } \ +} while(0) + + +int zeroreturn(struct fusd_file_info *file) { return 0; } + +/* EXAMPLE START ioctl-server.c */ +/* This function is run by the driver */ +int do_ioctl(struct fusd_file_info *file, int cmd, void *arg) +{ + static int errors = 0; /* SKIPLINE */ + char *c; /* SKIPLINE */ + struct ioctl_data_t *d; + + if (_IOC_TYPE(cmd) != IOCTL_APP_TYPE) + return 0; + + switch (cmd) { +/* EXAMPLE STOP ioctl-server.c */ + case IOCTL_TEST0: + printf("ioctl server: got test0, returning 0\n"); + return 0; + break; + + case IOCTL_TEST1: + case IOCTL_TEST2: + printf("ioctl server: got test1/2, arg=%d, returning it\n", (int) arg); + return (int) arg; + break; + +/* EXAMPLE START ioctl-server.c */ + case IOCTL_TEST3: /* returns data to the client */ + d = arg; + printf("ioctl server: got test3 request (read-only)\n");/* SKIPLINE */ + printf("ioctl server: ...returning test strings for client to read\n"); /* SKIPLINE */ + strcpy(d->string1, TEST3_STRING1); + strcpy(d->string2, TEST3_STRING2); + return 0; + break; + + case IOCTL_TEST4: /* gets data from the client */ + d = arg; + printf("ioctl server: got test4 request (write-only)\n"); /* SKIPLINE */ + printf("ioctl server: ...got the following strings written by client:\n"); /* SKIPLINE */ + printf("ioctl server: test4, string1: got '%s'\n", d->string1); + printf("ioctl server: test4, string2: got '%s'\n", d->string2); + CHECK(!strcmp(d->string1, TEST4_STRING1));/* SKIPLINE */ + CHECK(!strcmp(d->string2, TEST4_STRING2)); /* SKIPLINE */ + return 0; + break; +/* EXAMPLE STOP ioctl-server.c */ + + case IOCTL_TEST5: + d = arg; + printf("ioctl server: got test5 request (read+write)\n"); + printf("ioctl server: test5, string1: got '%s'\n", d->string1); + printf("ioctl server: test5, string2: got '%s'\n", d->string2); + printf("ioctl server: capitalizing the strings and returning them\n"); + for (c = d->string1; *c; c++) + *c = toupper(*c); + for (c = d->string2; *c; c++) + *c = toupper(*c); + return 0; + break; + + case IOCTL_TEST_TERMINATE: + printf("ioctl server: got request to terminate, calling exit(%d)\n", + errors); + printf("ioctl server: note: client should see -EPIPE\n"); + exit(errors); + break; + +/* EXAMPLE START ioctl-server.c */ + default: + printf("ioctl server: got unknown cmd, sigh, this is broken\n"); + return -EINVAL; + break; + } + + return 0; +} +/* EXAMPLE STOP ioctl-server.c */ + +int main(int argc, char *argv[]) +{ + pid_t server_pid, retpid; + + if ((server_pid = fork()) < 0) { + perror("error creating server"); + exit(1); + } + + if (server_pid == 0) { + /* ioctl server */ + struct fusd_file_operations f = { open: zeroreturn, close: zeroreturn, + ioctl: do_ioctl}; + if (fusd_register("ioctltest", 0666, NULL, &f) < 0) + perror("registering ioctltest"); + printf("server starting\n"); + fusd_run(); + } else { + /* ioctl client */ +/* EXAMPLE START ioctl-client.c */ + int fd, ret; + struct ioctl_data_t d; +/* EXAMPLE STOP ioctl-client.c */ + int errors, status; + + errors = 0; + + sleep(1); +/* EXAMPLE START ioctl-client.c */ + + if ((fd = open("/dev/ioctltest", O_RDWR)) < 0) { + perror("client: can't open ioctltest"); + exit(1); + } + +/* EXAMPLE STOP ioctl-client.c */ + errors = 0; + + /* test0: simply issue a command and get a retval */ + ret = ioctl(fd, IOCTL_TEST0); + printf("ioctl test0: got %d (expecting 0)\n\n", ret); + CHECK(ret == 0); + + /* test1: issue a command with a simple (integer) argument */ + ret = ioctl(fd, IOCTL_TEST1, TEST1_NUM); + CHECK(ret == TEST1_NUM); + CHECK(errno == 0); + printf("ioctl test1: got %d, errno=%d (expecting %d, errno=0)\n\n", + ret, errno, TEST1_NUM); + + /* test2 again: make sure errno is set properly */ + ret = ioctl(fd, IOCTL_TEST2, -ELIBBAD); + CHECK(errno == ELIBBAD); + CHECK(ret == -1); + printf("ioctl test2: got %d, errno=%d (expecting -1, errno=%d)\n\n", + ret, errno, ELIBBAD); + + printf("ioctl test3: expecting retval 0, string This Is Test3\n"); +/* EXAMPLE START ioctl-client.c */ + /* test3: make sure we can get data FROM a driver using ioctl */ + ret = ioctl(fd, IOCTL_TEST3, &d); + CHECK(ret == 0); /* SKIPLINE */ + CHECK(!strcmp(d.string1, TEST3_STRING1)); /* SKIPLINE */ + CHECK(!strcmp(d.string2, TEST3_STRING2)); /* SKIPLINE */ + printf("ioctl test3: got retval=%d\n", ret); + printf("ioctl test3: got string1='%s'\n", d.string1); + printf("ioctl test3: got string2='%s'\n", d.string2); + printf("\n"); /* SKIPLINE */ + + /* test4: make sure we can send data TO a driver using an ioctl */ + printf("ioctl test4: server should see string 'This Is Test4'\n");/* SKIPLINE */ + sprintf(d.string1, TEST4_STRING1); + sprintf(d.string2, TEST4_STRING2); + ret = ioctl(fd, IOCTL_TEST4, &d); +/* EXAMPLE STOP ioctl-client.c */ + CHECK(ret == 0); + printf("\n"); + + /* test5: we send 2 strings to the ioctl server, they should come + * back in all caps */ + printf("ioctl test5: we send strings that should come back capitalized\n"); + sprintf(d.string1, TEST5_STRING1_IN); + sprintf(d.string2, TEST5_STRING2_IN); + printf("ioctl test5: sending string1='%s'\n", d.string1); + printf("ioctl test5: sending string2='%s'\n", d.string2); + ret = ioctl(fd, IOCTL_TEST5, &d); + CHECK(ret == 0); + CHECK(!strcmp(d.string1, TEST5_STRING1_OUT)); + CHECK(!strcmp(d.string2, TEST5_STRING2_OUT)); + printf("ioctl test5: got retval=%d\n", ret); + printf("ioctl test5: got back string1='%s'\n", d.string1); + printf("ioctl test5: got back string2='%s'\n", d.string2); + printf("\n"); + + /* now tell the server to terminate, we should get EPIPE */ + ret = ioctl(fd, IOCTL_TEST_TERMINATE); + CHECK(errno == EPIPE); + CHECK(ret == -1); + printf("ioctl termination test: got %d (errno=%d)\n", ret, errno); + printf("ioctl termination tets: expecting ret=-1, errno=%d\n\n", EPIPE); + + printf("ioctl client: waiting for server to terminate...\n"); + retpid = wait(&status); + CHECK(retpid == server_pid); + CHECK(WEXITSTATUS(status) == 0); + + printf("ioctl test done - %d errors\n", errors); + if (errors) { + printf("IOCTL REGRESSION TEST FAILED\n"); + exit(1); + } else { + printf("all tests passed\n"); + exit(0); + } + } + + return 0; +} diff --git a/examples/logring.c b/examples/logring.c new file mode 100644 index 0000000..31cafe3 --- /dev/null +++ b/examples/logring.c @@ -0,0 +1,455 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * logring.c: Implementation of a circular buffer log device + * + * logring makes it easy to access the most recent (and only the most + * recent) output from a process. It works just like "tail -f" on a + * log file, except that the storage required never grows. This can be + * useful in embedded systems where there isn't enough memory or disk + * space for keeping complete log files, but the most recent debugging + * messages are sometimes needed (e.g., after an error is observed). + * + * Logring uses FUSD to implement a character device, /dev/logring, + * that acts like a named pipe that has a finite, circular buffer. + * The size of the buffer is given as a command-line argument. As + * more data is written into the buffer, the oldest data is discarded. + * A process that reads from the logring device will first read the + * existing buffer, then block and see new data as it's written, + * similar to monitoring a log file using "tail -f". + * + * Non-blocking reads are supported; if a process needs to get the + * current contents of the log without blocking to wait for new data, + * it can set the O_NONBLOCK flag when it does the open(), or set it + * later using ioctl(). + * + * The select() interface is also supported; programs can select on + * /dev/logring to be notified when new data is available. + * + * Run this example program by typing "logring X", where X is the size + * of the circular buffer in bytes. Then, type "cat /dev/logring" in + * one shell. The cat process will block, waiting for data, similar + * to "tail -f". From another shell, write to the logring (e.g., + * "echo Hi there > /dev/logring".) The 'cat' process will see the + * message appear. + * + * Note: this example program is based on "emlog", a true Linux kernel + * module with identical functionality. If you find logring useful, + * but want to use it on a system that does not have FUSD, check out + * emlog at http://www.circlemud.org/~jelson/software/emlog. + * + * $Id: logring.c,v 1.8 2003/07/11 22:29:39 cerpa Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include <fusd.h> + + +/* per-client structure to keep track of who has an open FD to us */ +struct logring_client { + + /* used to store outstanding read and polldiff requests */ + struct fusd_file_info *read; + struct fusd_file_info *polldiff; + + /* to construct the linked list */ + struct logring_client *next; +}; + +/* list of currently open file descriptors */ +struct logring_client *client_list = NULL; + +char *logring_data = NULL; /* the data buffer used for the logring */ +int logring_size = 0; /* buffer space in the logring */ +int logring_writeindex = 0; /* write point in the logring array */ +int logring_readindex = 0; /* read point in the logring array */ +int logring_offset = 0; /* how far into the total stream is + * logring_read pointing? */ + +/* amount of data in the queue */ +#define LOGRING_QLEN (logring_writeindex >= logring_readindex ? \ + logring_writeindex - logring_readindex : \ + logring_size - logring_readindex + logring_writeindex) + +/* stream byte number of the last byte in the queue */ +#define LOGRING_FIRST_EMPTY_BYTE (logring_offset + LOGRING_QLEN) + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +/************************************************************************/ + +/* + * this function removes an element from a linked list. the + * pointer-manipulation insanity below is a trick that prevents the + * "element to be removed is the head of the list" from being a + * special case. + */ +void client_list_remove(struct logring_client *c) +{ + struct logring_client **ptr; + + if (c == NULL || client_list == NULL) + return; + + for (ptr = &client_list; *ptr != c; ptr = &((**ptr).next)) { + if (!*ptr) { + fprintf(stderr, "trying to remove a client that isn't in the list\n"); + return; + } + } + *ptr = c->next; +} + + +/* open on /dev/logring: create state for this client */ +static int logring_open(struct fusd_file_info *file) +{ + /* create state for this client */ + struct logring_client *c = malloc(sizeof(struct logring_client)); + + if (c == NULL) + return -ENOBUFS; + + /* initialize fields of this client state */ + memset(c, 0, sizeof(struct logring_client)); + + /* save the pointer to this state so it gets returned to us later */ + file->private_data = c; + + /* add this client to the client list */ + c->next = client_list; + client_list = c; + + return 0; +} + + +/* close on /dev/logring: destroy state for this client */ +static int logring_close(struct fusd_file_info *file) +{ + struct logring_client *c; + + if ((c = (struct logring_client *) file->private_data) != NULL) { + + /* take this client off our client list */ + client_list_remove(c); + + /* if there is a read outstanding, free the state */ + if (c->read != NULL) { + fusd_destroy(c->read); + c->read = NULL; + } + /* destroy any outstanding polldiffs */ + if (c->polldiff != NULL) { + fusd_destroy(c->polldiff); + c->polldiff = NULL; + } + + /* get rid of the struct */ + free(c); + file->private_data = NULL; + } + return 0; +} + + + +/* + * This function "completes" a read: that is, matches up a client who + * is requesting data with data that's waiting to be served. + * + * This function is called in two cases: + * + * 1- When a new read request comes in (it might be able to complete + * immediately, if there's data waiting that the client hasn't seen + * yet) + * + * 2- When new data comes in (the new data might be able to complete + * a read that had been previously blocked) + */ +void logring_complete_read(struct logring_client *c) +{ + loff_t *user_offset; + char *user_buffer; + size_t user_length; + int bytes_copied = 0, n, start_point, retval; + + + /* if there is no outstanding read, do nothing */ + if (c == NULL || c->read == NULL) + return; + + /* retrieve the read callback's arguments */ + user_offset = fusd_get_offset(c->read); + user_buffer = fusd_get_read_buffer(c->read); + user_length = fusd_get_length(c->read); + + /* is the client trying to read data that has scrolled off? */ + if (*user_offset < logring_offset) + *user_offset = logring_offset; + + /* is there new data this user hasn't seen yet, or are we at EOF? */ + /* If we have reached EOF: + * If this is a nonblocking read, return EAGAIN. + * else return without doing anything; keep the read blocked. + */ + if (*user_offset >= LOGRING_FIRST_EMPTY_BYTE) { + if (c->read->flags & O_NONBLOCK) { + retval = -EAGAIN; + goto done; + } else { + return; + } + } + + /* find the smaller of the total bytes we have available and what + * the user is asking for */ + user_length = MIN(user_length, LOGRING_FIRST_EMPTY_BYTE - *user_offset); + retval = user_length; + + /* figure out where to start copying data from, based on user's offset */ + start_point = + (logring_readindex + (*user_offset-logring_offset)) % logring_size; + + /* copy the (possibly noncontiguous) data into user's buffer) */ + while (user_length) { + n = MIN(user_length, logring_size - start_point); + memcpy(user_buffer + bytes_copied, logring_data + start_point, n); + bytes_copied += n; + user_length -= n; + start_point = (start_point + n) % logring_size; + } + + /* advance the user's file pointer */ + *user_offset += retval; + + done: + /* and complete the read system call */ + fusd_return(c->read, retval); + c->read = NULL; +} + + + +/* + * read on /dev/logring: store the fusd_file_info pointer. then call + * complete_read, which will immediately call fusd_return, if there is + * data already waiting. + * + * Note that this shows a trick we use commonly in FUSD drivers: you + * are allowed to call fusd_return() from within a callback as long as + * you return -FUSD_NOREPLY. In other words, a driver can EITHER + * return a real return value from its callback, OR call fusd_return + * explicitly, but not both. + */ +static ssize_t logring_read(struct fusd_file_info *file, char *buffer, + size_t len, loff_t *offset) +{ + struct logring_client *c = (struct logring_client *) file->private_data; + + if (c == NULL || c->read != NULL) { + fprintf(stderr, "logring_read's arguments are confusd, alas"); + return -EINVAL; + } + + c->read = file; + logring_complete_read(c); + return -FUSD_NOREPLY; +} + + +/* + * complete_polldiff: if a client has an outstanding 'polldiff' + * request, possibly return updated poll-state information to the + * kernel, if indeed the state has changed. + */ +void logring_complete_polldiff(struct logring_client *c) + +{ + int curr_state, cached_state; + + /* if there is no outstanding polldiff, do nothing */ + if (c == NULL || c->polldiff == NULL) + return; + + /* figure out the "current" state: i.e. whether or not the logring + * is readable for this client based on its current position in the + * stream. The logring is *always* writable. */ + if (*(fusd_get_offset(c->polldiff)) < LOGRING_FIRST_EMPTY_BYTE) + curr_state = FUSD_NOTIFY_INPUT | FUSD_NOTIFY_OUTPUT; /* read and write */ + else + curr_state = FUSD_NOTIFY_OUTPUT; /* writable only */ + + /* cached_state is what the kernel *thinks* the state is */ + cached_state = fusd_get_poll_diff_cached_state(c->polldiff); + + /* if the state is not what the kernel thinks it is, notify the + kernel of the change */ + if (curr_state != cached_state) { + fusd_return(c->polldiff, curr_state); + c->polldiff = NULL; + } +} + + +/* This function is only called on behalf of clients who are trying to + * use select(). The kernel keeps us up to date on what it thinks the + * current "poll state" is, i.e. readable and/or writable. The kernel + * calls this function every time its assumption about the current + * poll state changes. Every time the driver's notion of the state + * differs from what the kernel thinks it is, it should return the + * poll_diff request with the updated state. Note that a 2nd request + * may come from the kernel before the driver has returned the first + * one; if this happens, use fusd_destroy() to get rid of the older one. + */ +ssize_t logring_polldiff(struct fusd_file_info *file, unsigned int flags) +{ + struct logring_client *c = (struct logring_client *) file->private_data; + + if (c == NULL) + return -EIO; + + /* if we're already holding a polldiff request that we haven't + * replied to yet, destroy the old one and hold onto only the new + * one */ + if (c->polldiff != NULL) { + fusd_destroy(c->polldiff); + c->polldiff = NULL; + } + + c->polldiff = file; + logring_complete_polldiff(c); + return -FUSD_NOREPLY; +} + + +/* + * a write on /dev/logring: first, copy the data from the user into our + * data queue. Then, complete any reads and polldiffs that might be + * outstanding. + */ +ssize_t logring_write(struct fusd_file_info *file, const char *buffer, + size_t len, loff_t *offset) +{ + struct logring_client *c; + int overflow = 0, bytes_copied = 0, n, retval; + + /* if the message is longer than the buffer, just take the beginning + * of it, in hopes that the reader (if any) will have time to read + * before we wrap around and obliterate it */ + len = MIN(len, logring_size - 1); + retval = len; + + if (len + LOGRING_QLEN >= (logring_size-1)) { + overflow = 1; + + /* in case of overflow, figure out where the new buffer will + * begin. we start by figuring out where the current buffer ENDS: + * logring_offset + LOGRING_QLEN. we then advance the end-offset + * by the length of the current write, and work backwards to + * figure out what the oldest unoverwritten data will be (i.e., + * size of the buffer). was that all quite clear? :-) */ + logring_offset = logring_offset + LOGRING_QLEN + len - logring_size + 1; + } + + while (len) { + /* how many contiguous bytes are available from the write point to + * the end of the circular buffer? */ + n = MIN(len, logring_size - logring_writeindex); + memcpy(logring_data + logring_writeindex, buffer + bytes_copied, n); + bytes_copied += n; + len -= n; + logring_writeindex = (logring_writeindex + n) % logring_size; + } + + /* if there was an overflow (i.e., new data wrapped around and + * overwrote old data that had not yet been read), then, reset the + * read point to be whatever the oldest data is that we have. */ + if (overflow) + logring_readindex = (logring_writeindex + 1) % logring_size; + + /* now, complete any blocked reads and/or polldiffs */ + for (c = client_list; c != NULL; c = c->next) { + logring_complete_read(c); + logring_complete_polldiff(c); + } + + /* now tell the client how many bytes we acutally wrote */ + return retval; +} + + +int main(int argc, char *argv[]) +{ + char *name; + + /* size must be provided, and an optional logring name */ + if (argc != 2 && argc != 3) { + fprintf(stderr, "usage: %s <logring-size> [logring-name]\n", argv[0]); + exit(1); + } + + name = (argc == 3 ? argv[2] : "/dev/logring"); + + /* convert the arg to an int and alloc memory for the logring */ + if ((logring_size = atoi(argv[1])) <= 0) { + fprintf(stderr, "invalid logring size; it must be >0\n"); + exit(1); + } + + if ((logring_data = (char *) malloc(sizeof(char) * logring_size)) == NULL) { + fprintf(stderr, "couldn't allocate %d bytes!\n", logring_size); + exit(1); + } + + /* register the fusd device */ + fusd_simple_register(name, "misc", "logring", 0666, NULL, + open: logring_open, close: logring_close, + read: logring_read, write: logring_write, + poll_diff: logring_polldiff); + + printf("calling fusd_run; reads from /dev/logring will now block\n" + "until someone writes to /dev/logring...\n"); + fusd_run(); + + return 0; +} + diff --git a/examples/pager.c b/examples/pager.c new file mode 100644 index 0000000..6288e5a --- /dev/null +++ b/examples/pager.c @@ -0,0 +1,386 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * pagerd: simple daemon to accept page signals from underlying page + * devices, and redistribute those pages to applications. + * + * The application itself is not especially useful, but this example + * program has proved very valuable as a generic template for FUSD + * drivers that service multiple clients, and implement both blocking + * and selectable devices. This file is a good place to start for + * writing drivers. See logring.c for a more complex real-world + * application based on this template. + * + * How to use the pager: + * + * Interface for devices that generate pages: write "page" to + * /dev/pager/input + * + * Interface for programs waiting for pages: read from (or, select on + * and then read from) /dev/pager/notify. reads will unblock when a + * page arrives. Note that if more than one page arrives before you + * read, you'll only get the most recent one. In other words, you are + * guaranteed to get at least one page. + * + * Important: in order to guarantee that you do not miss any pages, + * you MUST NOT close the file descriptor in between reads/selects. + * If you close the FD and then reopen it, there will be a race (pages + * that arrive between the close and open will not be delivered). + * + * $Id: pager.c,v 1.9 2003/07/11 22:29:39 cerpa Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include <fusd.h> + + +/* EXAMPLE START pager-open.c */ +/* per-client structure to keep track of who has an open FD to us */ +struct pager_client { + int last_page_seen; /* seq. no. of last page this client has seen */ + struct fusd_file_info *read; /* outstanding read request, if any */ + struct fusd_file_info *polldiff; /* outstanding polldiff request */ + struct pager_client *next; /* to construct the linked list */ +}; + +struct pager_client *client_list = NULL; /* list of clients (open FDs) */ +int last_page = 0; /* seq. no. of the most recent page to arrive */ + +/* EXAMPLE STOP pager-open.c */ + +void pager_notify_complete_read(struct pager_client *c); +void pager_notify_complete_polldiff(struct pager_client *c); + + +/************************************************************************/ + +/* + * this function removes an element from a linked list. the + * pointer-manipulation insanity below is a trick that prevents the + * "element to be removed is the head of the list" from being a + * special case. + */ +void client_list_remove(struct pager_client *c) +{ + struct pager_client **ptr; + + if (c == NULL || client_list == NULL) + return; + + for (ptr = &client_list; *ptr != c; ptr = &((**ptr).next)) { + if (!*ptr) { + fprintf(stderr, "trying to remove a client that isn't in the list\n"); + return; + } + } + *ptr = c->next; +} + + +/* EXAMPLE START pager-open.c */ +/* open on /dev/pager/notify: create state for this client */ +static int pager_notify_open(struct fusd_file_info *file) +{ + /* create state for this client */ + struct pager_client *c = malloc(sizeof(struct pager_client)); + + if (c == NULL) + return -ENOBUFS; + + /* initialize fields of this client state */ + memset(c, 0, sizeof(struct pager_client)); + c->last_page_seen = last_page; + + /* save the pointer to this state so it gets returned to us later */ + file->private_data = c; + + /* add this client to the client list */ + c->next = client_list; + client_list = c; + + return 0; +} +/* EXAMPLE STOP pager-open.c */ + + +/* EXAMPLE START pager-close.c */ +/* close on /dev/pager/notify: destroy state for this client */ +static int pager_notify_close(struct fusd_file_info *file) +{ + struct pager_client *c; + + if ((c = (struct pager_client *) file->private_data) != NULL) { + + /* take this client off our client list */ + client_list_remove(c); + + /* if there is a read outstanding, free the state */ + if (c->read != NULL) { + fusd_destroy(c->read); + c->read = NULL; + } + /* destroy any outstanding polldiffs */ + if (c->polldiff != NULL) { + fusd_destroy(c->polldiff); + c->polldiff = NULL; + } + + /* get rid of the struct */ + free(c); + file->private_data = NULL; + } + return 0; +} +/* EXAMPLE STOP pager-close.c */ + + +/* + * read on /dev/pager/notify: store the fusd_file_info pointer. then call + * complete_read, which will immediately call fusd_return, if there is + * a page already waiting. + * + * Note that this shows a trick we use commonly in FUSD drivers: you + * are allowed to call fusd_return() from within a callback as long as + * you return -FUSD_NOREPLY. In other words, a driver can EITHER + * return a real return value from its callback, OR call fusd_return + * explicitly, but not both. + */ +/* EXAMPLE START pager-read.c */ +ssize_t pager_notify_read(struct fusd_file_info *file, char *buffer, + size_t len, loff_t *offset) +{ + struct pager_client *c = (struct pager_client *) file->private_data; + + if (c == NULL || c->read != NULL) { + fprintf(stderr, "pager_read's arguments are confusd, alas"); + return -EINVAL; + } + + c->read = file; + pager_notify_complete_read(c); + return -FUSD_NOREPLY; +} + +/* EXAMPLE STOP pager-read.c */ + +/* + * This function "completes" a read: that is, matches up a client who + * is requesting data with data that's waiting to be served. + * + * This function is called in two cases: + * + * 1- When a new read request comes in. The driver might be able to + * complete immediately, if a page arrived between the time the + * process opened the device and performed the read. This is the + * common case for clients that use select. hasn't seen yet - this + * is normal if ) + * + * 2- When a new page arrives, all readers are unblocked + */ +/* EXAMPLE START pager-read.c */ +void pager_notify_complete_read(struct pager_client *c) +{ + /* if there is no outstanding read, do nothing */ + if (c == NULL || c->read == NULL) + return; + + /* if there are no outstanding pages, do nothing */ + if (c->last_page_seen >= last_page) + return; + + /* bring this client up to date with the most recent page */ + c->last_page_seen = last_page; + + /* and notify the client by unblocking the read (read returns 0) */ + fusd_return(c->read, 0); + c->read = NULL; +} +/* EXAMPLE STOP pager-read.c */ + + +/* This function is only called on behalf of clients who are trying to + * use select(). The kernel keeps us up to date on what it thinks the + * current "poll state" is, i.e. readable and/or writable. The kernel + * calls this function every time its assumption about the current + * poll state changes. Every time the driver's notion of the state + * differs from what the kernel's cached value, it should return the + * poll_diff request with the updated state. Note that a 2nd request + * may come from the kernel before the driver has returned the first + * one; if this happens, use fusd_destroy() to get rid of the older one. + */ +/* EXAMPLE START pager-polldiff.c */ +ssize_t pager_notify_polldiff(struct fusd_file_info *file, + unsigned int cached_state) +{ + struct pager_client *c = (struct pager_client *) file->private_data; + + if (c == NULL) + return -EINVAL; + + /* if we're already holding a polldiff request that we haven't + * replied to yet, destroy the old one and hold onto only the new + * one */ + if (c->polldiff != NULL) { + fusd_destroy(c->polldiff); + c->polldiff = NULL; + } + + c->polldiff = file; + pager_notify_complete_polldiff(c); + return -FUSD_NOREPLY; +} + +/* EXAMPLE STOP pager-polldiff.c */ + + +/* + * complete_polldiff: if a client has an outstanding 'polldiff' + * request, possibly return updated poll-state information to the + * kernel, if indeed the state has changed. + */ +/* EXAMPLE START pager-polldiff.c */ +void pager_notify_complete_polldiff(struct pager_client *c) +{ + int curr_state, cached_state; + + /* if there is no outstanding polldiff, do nothing */ + if (c == NULL || c->polldiff == NULL) + return; + + /* figure out the "current" state: i.e. whether or not the pager + * is readable for this client based on the last page it saw */ + if (c->last_page_seen < last_page) + curr_state = FUSD_NOTIFY_INPUT; /* readable */ + else + curr_state = 0; /* not readable or writable */ + + /* cached_state is what the kernel *thinks* the state is */ + cached_state = fusd_get_poll_diff_cached_state(c->polldiff); + + /* if the state is not what the kernel thinks it is, notify the + kernel of the change */ + if (curr_state != cached_state) { + fusd_return(c->polldiff, curr_state); + c->polldiff = NULL; + } +} +/* EXAMPLE STOP pager-polldiff.c */ + + + +/* + * this handles a write on /dev/pager/input. this is called by one of + * the underlying page devices when a page arrives. if a device + * writes "page" to this interface, a page is queued for everyone + * using the notify interface. + */ +#define CASE(x) if ((found == 0) && !strcmp(tmp, x) && (found = 1)) +/* EXAMPLE START pager-read.c */ + +ssize_t pager_input_write(struct fusd_file_info *file, + const char *buffer, size_t len, loff_t *offset) +{ + struct pager_client *c; + + /* ... */ + /* EXAMPLE STOP pager-read.c */ + char tmp[1024]; + int found = 0; + + if (len > sizeof(tmp) - 1) + len = sizeof(tmp) - 1; + + strncpy(tmp, buffer, len); + tmp[len] = '\0'; + + /* strip trailing \n's */ + while (tmp[len-1] == '\n') + tmp[--len] = '\0'; + + /* EXAMPLE START pager-read.c */ + + CASE("page") { + last_page++; + + for (c = client_list; c != NULL; c = c->next) { + pager_notify_complete_polldiff(c); + pager_notify_complete_read(c); + } + } + /* EXAMPLE STOP pager-read.c */ + + /* other commands (if there ever are any) can go here */ + + if (!found) + return -EINVAL; + else + return len; +} +#undef CASE + + +static int fusd_success(struct fusd_file_info *file) +{ + return 0; +} + + +int main(int argc, char *argv[]) +{ + /* register the input device */ + fusd_simple_register("/dev/pager/input", "pager", "input", 0666, NULL, + open: fusd_success, close: fusd_success, + write: pager_input_write); + + /* register the notification device */ + fusd_simple_register("/dev/pager/notify", "pager", "notify", 0666, NULL, + open: pager_notify_open, + close: pager_notify_close, + read: pager_notify_read, + poll_diff: pager_notify_polldiff); + + printf("calling fusd_run; reads from /dev/pager/notify will now block\n" + "until someone writes 'page' to /dev/pager/input...\n"); + fusd_run(); + + return 0; +} + diff --git a/examples/uid-filter.c b/examples/uid-filter.c new file mode 100644 index 0000000..628688b --- /dev/null +++ b/examples/uid-filter.c @@ -0,0 +1,113 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD - The Framework for UserSpace Devices - Example program + * + * Jeremy Elson <jelson@circlemud.org> + * + * uid-filter. This program shows how you can use some of the + * meta-data provided in the fusd_file_info structure to affect your + * driver's behavior. + * + * In particular, this driver creates a device, /dev/my-pid, that can + * not be read by anyone other than the driver owner (not even root!). + * When you read from the device, it returns your PID to you. + * + * $Id: uid-filter.c,v 1.4 2003/07/11 22:29:39 cerpa Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "fusd.h" + + +int do_close(struct fusd_file_info *file) +{ + return 0; /* attempts to close the file always succeed */ +} + +/* EXAMPLE START uid-filter.c */ +int do_open(struct fusd_file_info *file) +{ + /* If the UID of the process trying to do the read doesn't match the + * UID of the owner of the driver, return -EPERM. If you run this + * driver as a normal user, even root won't be able to read from the + * device file created! */ + if (file->uid != getuid()) + return -EPERM; + + return 0; +} + +int do_read(struct fusd_file_info *file, char *user_buffer, + size_t user_length, loff_t *offset) +{ + char buf[128]; + int len; + + /* The first read to the device returns a greeting. The second read + * returns EOF. */ + if (*offset != 0) + return 0; + + /* len gets set to the number of characters written to buf */ + len = sprintf(buf, "Your PID is %d. Have a nice day.\n", file->pid); + + /* NEVER return more data than the user asked for */ + if (user_length < len) + len = user_length; + + memcpy(user_buffer, buf, len); + *offset += len; + return len; +} +/* EXAMPLE STOP uid-filter.c */ + + +int main(int argc, char *argv[]) +{ + struct fusd_file_operations fops = { + open: do_open, + read: do_read, + close: do_close }; + + if (fusd_register("/dev/my-pid", "misc", "my-pid", 0666, NULL, &fops) < 0) + perror("Unable to register device"); + else { + printf("/dev/my-pid should now exist - calling fusd_run...\n"); + fusd_run(); + } + return 0; +} diff --git a/include/fusd.h b/include/fusd.h new file mode 100755 index 0000000..a6f1ca0 --- /dev/null +++ b/include/fusd.h @@ -0,0 +1,285 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD: the Framework for User-Space Devices + * + * Public header function for user-space library. This is the API + * that user-space device drivers should write to. + */ + +#ifndef __FUSD_H__ +#define __FUSD_H__ + +#ifndef __KERNEL__ +#include <sys/types.h> + +__BEGIN_DECLS +#endif + + +#include "fusd_msg.h" + +/* FUSD_NOREPLY is a special error code. If a user-space driver + * implementing a system call returns -FUSD_NOREPLY (note it's + * negative!), the calling application will be blocked. When + * conditions enable a response to the system call (e.g. the read or + * write has completed), the user-space driver must call the + * fusd_return() function. */ +#define FUSD_NOREPLY 0x1000 + +/* FUSD defines several bitmasks for describing which channels of + * notification are being requested or signaled. These flags are + * used in the arguments and return value of the notify() callback. */ +#define FUSD_NOTIFY_INPUT 0x1 +#define FUSD_NOTIFY_OUTPUT 0x2 +#define FUSD_NOTIFY_EXCEPT 0x4 + + +#define FUSD_KOR_HACKED_VERSION + +struct fusd_file_info; /* forward decl */ + +typedef +struct fusd_file_operations { + int (*open) (struct fusd_file_info *file); + int (*close) (struct fusd_file_info *file); + ssize_t (*read) (struct fusd_file_info *file, char *buffer, size_t length, + loff_t *offset); + ssize_t (*write) (struct fusd_file_info *file, const char *buffer, + size_t length, loff_t *offset); + int (*ioctl) (struct fusd_file_info *file, int request, void *data); + int (*poll_diff) (struct fusd_file_info *file, unsigned int cached_state); + int (*unblock) (struct fusd_file_info *file); + int (*mmap) (struct fusd_file_info *file, int offset, size_t length, int flags, void** addr, size_t* out_length); +} fusd_file_operations_t; + + +/* state-keeping structure passed to device driver callbacks */ +typedef +struct fusd_file_info { + void *device_info; /* This is set by the library to + * whatever you passed to + * fusd_register. Changing this in a + * file_operations callback has no + * effect. */ + + void *private_data; /* File-specific data you can change + * in a file_operations callback. + * e.g., you can set this in an open() + * callback, then get it in a + * corresponding read() callback. */ + + unsigned int flags; /* Kept synced with file->f_flags */ + pid_t pid; /* PID of process making the request */ + uid_t uid; /* UID of process making the request */ + gid_t gid; /* GID of process making the request */ + + /* other info might be added later, e.g. state needed to complete + operations... */ + + /* request message associated with this call */ + int fd; + fusd_msg_t *fusd_msg; + +} fusd_file_info_t; + + + + +/*************************** Library Functions ****************************/ + +/* fusd_register: create a device file and register callbacks for it + * + * Arguments: + * + * name - the name of the device file, to be created wherever devfs + * is mounted (usually dev). example: pass "mydevice" will create + * /dev/mydevice. + * + * As a convenience, passing a string that starts with "/dev/" will + * automatically skip over that portion of the name. + * + * mode - the file protections to be given to the device + * + * device_info - you can provide arbitrary data that will later be + * passed back to your driver's callbacks in file->device_info. + * value has no effect on FUSD itself. + * + * fops - a table of callbacks to be called for this device; see + * structure above. + * + * Return value: + * On failure, -1 is returned and errno is set to indicate the error. + * + * On success, a valid file descriptor is returned which represents + * the control channel to your new device. You should never read + * from or write to that control channel directcly, but you can + * select on it to see when it needs attention (see fusd_run and + * fusd_dispatch). + */ + +int fusd_register(const char *name, const char* clazz, const char* devname, mode_t mode, void *device_info, + struct fusd_file_operations *fops); + + + +/* "simple" interface to fusd_register. */ +#define fusd_simple_register(name, clazz, devname, perms, arg, ops...) do { \ + struct fusd_file_operations f = { ops } ; \ + if (fusd_register(name, clazz, devname, perms, arg, &f) < 0) \ + perror("warning: fusd unavailable"); \ +} while(0) + +/* fusd_unregister: unregister a previously registered device + * + * Arguments: + * fd - the file descriptor previously returned to you by fusd_register. + * + * Return value: + * 0 on success. + * -1 on failure with errno set to indicate the failure. + */ +int fusd_unregister(int fd); + + +/* fusd_return: unblock a previously blocked system call + * + * Arguments: + * file - the file info struct that was previously blocked + * retval - the return value that would have been returned by the + * returning system call + * + * Return value: + * 0 on success. + * -1 on failure with errno set to indicate the failure + */ +int fusd_return(struct fusd_file_info *file, ssize_t retval); + + +/* + * fusd_destroy destroys all state associated with a fusd_file_info + * pointer. (It is implicitly called by fusd_return.) If a driver + * saves a fusd_file_info pointer by calling -FUSD_NOREPLY in order to + * block a read, but gets a "close" request on the file before the + * pointer is returned with fusd_return, it should be thrown away + * using fusd_destroy. + */ +void fusd_destroy(struct fusd_file_info *file); + + +/* fusd_dispatch: handles an event on a fusd file descriptor + * + * Arguments: + * fd - the file descriptor of the device that received an event + * + * Return value: + * None. + * + * Side effects: + * May (but may not) call a callback function originally passed to + * fusd_register. + * + * Prints an error to stderr in case of a dispatching error. + */ +void fusd_dispatch(int fd); + + +/* + * fusd_run: convenience function that handles dispatch for all + * fusd devices + * + * No return value; runs forever. + */ +void fusd_run(void); + + +/* + * fusd_fdset_add: given an FDSET and "max", add the currently valid + * FUSD fds to the set and update max accordingly. + */ +void fusd_fdset_add(fd_set *set, int *max); + + +/* + * fusd_dispatch_fdset: given an fd_set full of descriptors, call + * fusd_dispatch on every descriptor in the set which is a valid FUSD + * fd. + */ +void fusd_dispatch_fdset(fd_set *set); + + +/******************************************************************** + * + * Direct access API + * + * This API enables a driver implementation to store state about a + * blocked call more easily, extracting the call arguments directly + * with no need to store them separately. + * + ********************************************************************/ + +/* accessors */ +static inline int fusd_get_call_type(struct fusd_file_info *file) +{ return file->fusd_msg->subcmd; } + +static inline char * fusd_get_read_buffer(struct fusd_file_info *file) +{ return file->fusd_msg->data; } + +static inline const char * fusd_get_write_buffer(struct fusd_file_info *file) +{ return (const char *)file->fusd_msg->data; } + +static inline size_t fusd_get_length(struct fusd_file_info *file) +{ return (size_t)file->fusd_msg->datalen; } + +static inline loff_t *fusd_get_offset(struct fusd_file_info *file) +{ return &(file->fusd_msg->parm.fops_msg.offset); } + +static inline int fusd_get_ioctl_request(struct fusd_file_info *file) +{ return file->fusd_msg->parm.fops_msg.cmd; } + +static inline unsigned long fusd_get_ioctl_arg(struct fusd_file_info *file) +{ return file->fusd_msg->parm.fops_msg.arg.arg; } + +static inline void * fusd_get_ioctl_buffer(struct fusd_file_info *file) +{ return (void *)file->fusd_msg->data; } + +static inline int fusd_get_poll_diff_cached_state(struct fusd_file_info *file) +{ return file->fusd_msg->parm.fops_msg.cmd; } + +/* returns static string representing the flagset (e.g. RWE) */ +char *fusd_unparse_flags(int flags); + +#ifndef __KERNEL__ +__END_DECLS +#endif + +#endif /* __FUSD_H__ */ diff --git a/include/fusd_msg.h b/include/fusd_msg.h new file mode 100755 index 0000000..9a7ebd7 --- /dev/null +++ b/include/fusd_msg.h @@ -0,0 +1,151 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD: the Framework for User-Space Devices + * + * Defines the interface between the kernel module and userspace library. + * + */ + +#ifndef __FUSD_MSG_H__ +#define __FUSD_MSG_H__ + +/* filenames */ +#define DEFAULT_DEV_ROOT "/dev/" +#define FUSD_CONTROL_FILENAME "fusd/control" +#define FUSD_STATUS_FILENAME "fusd/status" + +#define FUSD_CONTROL_DEVNAME DEFAULT_DEV_ROOT FUSD_CONTROL_FILENAME +#define FUSD_STATUS_DEVNAME DEFAULT_DEV_ROOT FUSD_STATUS_FILENAME + +/* ioctl number to tell FUSD status device to return binary info */ +#define FUSD_STATUS_USE_BINARY _IO('F', 100) + +/* constants */ +#define FUSD_MAX_NAME_LENGTH 47 /* 47, to avoid expanding union size */ + + +/* commands */ +#define FUSD_REGISTER_DEVICE 0 /* device registration */ +#define FUSD_UNREGISTER_DEVICE 1 /* device unregistration */ + +/* these two must have successive numbers */ +#define FUSD_FOPS_CALL 2 /* synchronous round-trip call: request */ +#define FUSD_FOPS_REPLY (FUSD_FOPS_CALL + 1) + +/* these two must have successive numbers */ +#define FUSD_FOPS_NONBLOCK 4 /* call that does not block for a reply */ +#define FUSD_FOPS_NONBLOCK_REPLY (FUSD_FOPS_NONBLOCK + 1) + +#define FUSD_FOPS_CALL_DROPREPLY 6 /* call that doesn't want a reply */ + +/* subcommands */ +#define FUSD_OPEN 100 +#define FUSD_CLOSE 101 +#define FUSD_READ 102 +#define FUSD_WRITE 103 +#define FUSD_IOCTL 104 +#define FUSD_POLL_DIFF 105 +#define FUSD_UNBLOCK 106 +#define FUSD_MMAP 107 + +/* other constants */ +#define FUSD_MSG_MAGIC 0x7a6b93cd + +/* user->kernel: register a device */ +typedef struct { + char name[FUSD_MAX_NAME_LENGTH+1]; + char clazz[FUSD_MAX_NAME_LENGTH+1]; + char devname[FUSD_MAX_NAME_LENGTH+1]; + mode_t mode; + void *device_info; +} register_msg_t; + + +/* kernel->user: fops request message (common data) */ +typedef struct { + pid_t pid; + uid_t uid; + gid_t gid; + unsigned int flags; /* flags from file struct */ + void *device_info; /* device info */ + void *private_info; /* file info */ + + /* parameters and return values for various calls. should be a + * union but it just makes things too complex and doesn't save all + * that much memory anyway */ + ssize_t retval; + size_t length; + loff_t offset; + unsigned int cmd; /* ioctl cmd, poll_diff cached_state */ + + union { + unsigned long arg; /* ioctl */ + void *ptr_arg; + } arg; + + /* the following are cookies that have meaning internal to the kernel + * but must be returned, untouched, by userspace */ + void *fusd_file; + long transid; + int hint; +} fops_msg_t; + + +/* the message struct written to FUSD control channel */ +typedef struct { + int magic; + short int cmd; + short int subcmd; + + char *data; /* yes, it's slightly inefficient to push this useless + * pointer between user and kernel space, but it makes + * it much easier to have a pointer available in this + * structure that both the kernel and userlib can make + * their own use of. */ + int datalen; + union { + register_msg_t register_msg; /* device registration (U->K) */ + fops_msg_t fops_msg; /* U->K and K->U fops messages */ + } parm; +} fusd_msg_t; + + +/* structure read from FUSD binary status device */ +typedef struct { + char name[FUSD_MAX_NAME_LENGTH+1]; + int zombie; + pid_t pid; + int num_open; +} fusd_status_t; + +#endif /* __FUSD_MSG_H__ */ diff --git a/include/kfusd.h b/include/kfusd.h new file mode 100755 index 0000000..a3e8f05 --- /dev/null +++ b/include/kfusd.h @@ -0,0 +1,288 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD: the Framework for User-Space Devices + * + * Jeremy Elson <jelson@circlemud.org> + * Copyright (c) Sensoria Corporation 2001 + * + * Private header file used by the Linux Kernel Module + * + * $Id: kfusd.h,v 1.41 2003/07/11 22:29:39 cerpa Exp $ + */ + +#ifndef __KFUSD_H__ +#define __KFUSD_H__ + +#include "fusd_msg.h" + +/* magic numbers for structure checking; unique w.r.t + * /usr/src/linux/Documentation/magic-number.txt */ +#define FUSD_DEV_MAGIC 0x8b43a123 +#define FUSD_FILE_MAGIC 0x613aa8fe + +/* number of devices that can be created with fusd */ +#define MAX_FUSD_DEVICES 128 + +/* number of times each device can be opened simultaneously */ +#define MIN_FILEARRAY_SIZE 8 /* initialize allocation */ +#define MAX_FILEARRAY_SIZE 1024 /* maximum it can grow to */ + +/* maximum read/write size we're willing to service */ +#define MAX_RW_SIZE (1024*128) + + +/********************** Structure Definitions *******************************/ + +/* Container for a fusd msg */ +typedef struct fusd_msgC_s_t fusd_msgC_t; + +struct fusd_msgC_s_t { + fusd_msg_t fusd_msg; /* the message itself */ + fusd_msgC_t *next; /* pointer to next one in the list */ + + /* 1-bit flags */ + unsigned int peeked:1; /* has the first half of this been read? */ +}; + +struct fusd_transaction +{ + struct list_head list; + long transid; + int subcmd; + int pid; + int size; + fusd_msg_t* msg_in; +}; + +/* magical forward declarations to break the circular dependency */ +struct fusd_dev_t_s; +typedef struct fusd_dev_t_s fusd_dev_t; +struct CLASS; +struct class_device; + +/* state kept per opened file (i.e., an instance of a device) */ +typedef struct { + /* general state management */ + int magic; /* magic number for sanity checking */ + fusd_dev_t *fusd_dev; /* fusd device associated with this file */ + long fusd_dev_version; /* version number of fusd device */ + void *private_data; /* the user's private data (we ignore it) */ + struct file *file; /* kernel's file pointer for this file */ + int index; /* our index in our device's file array */ + struct semaphore file_sem; /* Semaphore for file structure */ + int cached_poll_state; /* Latest result from a poll diff req */ + int last_poll_sent; /* Last polldiff request we sent */ + + /* structures used for messaging */ + wait_queue_head_t file_wait; /* Wait on this for a user->kernel msg */ + wait_queue_head_t poll_wait; /* Given to kernel for poll() queue */ + struct list_head transactions; + struct semaphore transactions_sem; + +} fusd_file_t; + + +/* state kept per device registered under fusd */ +struct fusd_dev_t_s { + int magic; /* Magic number for sanity checking */ + long version; /* Instance number of this device */ + int zombie; /* Is the device dead? */ + pid_t pid; /* PID of device driver */ + struct task_struct* task; + + char *name; /* Name of the device under devfs (/dev) */ + char *class_name; + char *dev_name; + struct CLASS *clazz; + int owns_class; + struct class_device *class_device; + + void *private_data; /* User's private data */ + struct cdev* handle; + dev_t dev_id; +// devfs_handle_t handle; /* The devfs-provided handle */ + + fusd_file_t **files; /* Array of this device's open files */ + int array_size; /* Size of the array pointed to by 'files' */ + int num_files; /* Number of array entries that are valid */ + int open_in_progress; /* File is referencing this struct, + but not yet part of the file array */ + /* messaging */ + fusd_msgC_t *msg_head; /* linked list head for message queue */ + fusd_msgC_t *msg_tail; /* linked list tail for message queue */ + + /* synchronization */ + wait_queue_head_t dev_wait; /* Wait queue for kernel->user msgs */ + struct semaphore dev_sem; /* Sempahore for device structure */ + + /* pointer to allow a dev to be placed on a dev_list */ + struct list_head devlist; +}; + + +/**** Function Prototypes ****/ + +STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev); + +STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file); +STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file); + +STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg, + fusd_msg_t *fusd_msg, struct fusd_transaction** transaction); +STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg, + fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction); +STATIC void fusd_fops_call_done(fusd_file_t *fusd_file); + +STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev); + +STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction); +STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction); +STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction); +STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid); +STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid); + + + +/**** Utility functions & macros ****/ + +#ifdef CONFIG_FUSD_USE_WAKEUPSYNC +#define WAKE_UP_INTERRUPTIBLE_SYNC(x) wake_up_interruptible_sync(x) +#else +#define WAKE_UP_INTERRUPTIBLE_SYNC(x) wake_up_interruptible(x) +#endif /* CONFIG_FUSD_USE_WAKEUPSYNC */ + +#ifdef CONFIG_FUSD_DEBUG +static void rdebug_real(char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +#define RDEBUG(message_level, args...) do { \ + if (fusd_debug_level >= message_level) rdebug_real(args); \ +} while(0) +#else +#define RDEBUG(message_level, args...) +#endif /* CONFIG_FUSD_DEBUG */ + + +#define ZOMBIE(fusd_dev) ((fusd_dev)->zombie) + + +#define GET_FUSD_DEV(candidate, fusd_dev) do { \ + fusd_dev = candidate; \ + if (fusd_dev == NULL || fusd_dev->magic != FUSD_DEV_MAGIC) \ + goto invalid_dev; \ +} while (0) + +#define GET_FUSD_FILE_AND_DEV(candidate, fusd_file, fusd_dev) do { \ + fusd_file = candidate; \ + if (fusd_file == NULL || fusd_file->magic != FUSD_FILE_MAGIC) \ + goto invalid_file; \ + GET_FUSD_DEV(fusd_file->fusd_dev, fusd_dev); \ + if (fusd_dev->version != fusd_file->fusd_dev_version) \ + goto invalid_file; \ +} while (0) + + +#define LOCK_FUSD_DEV(fusd_dev) \ + do { down(&fusd_dev->dev_sem); \ + if (ZOMBIE(fusd_dev)) { up(&fusd_dev->dev_sem); goto zombie_dev; } \ + } while (0) + +/* rawlock does not do a zombie check */ +#define RAWLOCK_FUSD_DEV(fusd_dev) \ + do { down(&fusd_dev->dev_sem); } while (0) + +#define UNLOCK_FUSD_DEV(fusd_dev) \ + do { up(&fusd_dev->dev_sem); } while (0) + + +#define LOCK_FUSD_FILE(fusd_file) \ + do { down(&fusd_file->file_sem); \ + } while (0) + +#define UNLOCK_FUSD_FILE(fusd_file) \ + do { up(&fusd_file->file_sem); } while (0) + +#define FREE_FUSD_MSGC(fusd_msgc) do { \ + if ((fusd_msgc)->fusd_msg.data != NULL) VFREE(fusd_msgc->fusd_msg.data); \ + KFREE(fusd_msgc); \ +} while (0) + +#define NAME(fusd_dev) ((fusd_dev)->name == NULL ? \ + "<noname>" : (fusd_dev)->name) + +#ifdef CONFIG_FUSD_MEMDEBUG +static int fusd_mem_init(void); +static void fusd_mem_cleanup(void); +static void fusd_mem_add(void *ptr, int line, int size); +static void fusd_mem_del(void *ptr); +static void *fusd_kmalloc(size_t size, int type, int line); +static void fusd_kfree(void *ptr); +static void *fusd_vmalloc(size_t size, int line); +static void fusd_vfree(void *ptr); +# define KMALLOC(size, type) fusd_kmalloc(size, type, __LINE__) +# define KFREE(ptr) fusd_kfree(ptr) +# define VMALLOC(size) fusd_vmalloc(size, __LINE__) +# define VFREE(ptr) fusd_vfree(ptr) +#else /* no memory debugging */ +# define KMALLOC(size, type) kmalloc(size, type) +# define KFREE(ptr) kfree(ptr) +/*# define VMALLOC(size) vmalloc(size)*/ +# define VMALLOC(size) kmalloc(size, GFP_KERNEL) +# define VFREE(ptr) kfree(ptr) +#endif /* CONFIG_FUSD_MEMDEBUG */ + + + +/* Functions like this should be in the kernel, but they are not. Sigh. */ +#ifdef CONFIG_SMP + +DECLARE_MUTEX(atomic_ops); + +static __inline__ int atomic_inc_and_ret(int *i) +{ + int val; + + down(&atomic_ops); + val = (++(*i)); + up(&atomic_ops); + return val; +} +#else +static __inline__ int atomic_inc_and_ret(int *i) +{ + return (++(*i)); +} +#endif + + +#endif /* __KFUSD_H__ */ diff --git a/kfusd/Makefile b/kfusd/Makefile new file mode 100755 index 0000000..cf764b0 --- /dev/null +++ b/kfusd/Makefile @@ -0,0 +1,19 @@ +ifneq ($(KERNELRELEASE),) +obj-m := kfusd.o +else +KDIR ?= /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +default: + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) EXTRA_CFLAGS=-I$(PWD)/../include modules + +install: + $(INSTALL) -d -m 0755 /lib/modules/$(shell uname -r)/kernel/drivers/misc + $(INSTALL) -m 0755 kfusd.ko /lib/modules/$(shell uname -r)/kernel/drivers/misc + /sbin/depmod -a + +clean: + rm -f .kfusd* Modules.symvers \ + kfusd.ko kfusd.o kfusd.mod.o kfusd.mod.c built-in.o *~ + rm -rf .tmp_versions +endif diff --git a/kfusd/Module.symvers b/kfusd/Module.symvers new file mode 100644 index 0000000..e69de29 diff --git a/kfusd/kfusd.c b/kfusd/kfusd.c new file mode 100755 index 0000000..d736334 --- /dev/null +++ b/kfusd/kfusd.c @@ -0,0 +1,2943 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * FUSD: the Framework for User-Space Devices + * + * Linux Kernel Module + * + * Jeremy Elson <jelson@circlemud.org> + * Copyright (c) 2001, Sensoria Corporation + * Copyright (c) 2002-2003, Regents of the University of California + * + * $Id: kfusd.c,v 1.97 2003/07/11 22:29:39 cerpa Exp $ + */ + +/* + * Note on debugging messages: Unexpected errors (i.e., indicators of + * bugs in this kernel module) should always contain '!'. Expected + * conditions, even if exceptional (e.g., the device-driver-provider + * disappears while a file is waiting for a return from a system call) + * must NOT contain '!'. + */ + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#ifdef MODVERSIONS +#include <linux/modversions.h> +#endif + +//#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +//#include <linux/devfs_fs_kernel.h> +#include <linux/poll.h> +#include <linux/version.h> +#include <linux/major.h> +#include <linux/uio.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/highmem.h> + +#include <asm/atomic.h> +#include <asm/uaccess.h> +#include <asm/ioctl.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> + +#define STATIC + +/* Define this if you want to emit debug messages (adds ~8K) */ +#define CONFIG_FUSD_DEBUG + +/* Default debug level for FUSD messages. Has no effect unless + * CONFIG_FUSD_DEBUG is defined. */ +#ifndef CONFIG_FUSD_DEBUGLEVEL +#define CONFIG_FUSD_DEBUGLEVEL 2 +#endif + +/* Define this to check for memory leaks */ +/*#define CONFIG_FUSD_MEMDEBUG*/ + +/* Define this to use the faster wake_up_interruptible_sync instead of + * the normal wake_up_interruptible. Note: you can't do this unless + * you're bulding fusd as part of the kernel (not a module); or you've + * patched kernel/ksyms.s to add __wake_up_sync in addition to + * __wake_up. */ +/* #define CONFIG_FUSD_USE_WAKEUPSYNC */ + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,9) +# define vsnprintf(str, size, format, ap) vsprintf(str, format, ap) +# define snprintf(str, len, args...) sprintf(str, args) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) + +#define CLASS class_simple +#define class_create class_simple_create +#define class_destroy class_simple_destroy +#define CLASS_DEVICE_CREATE(a, b, c, d, e) class_simple_device_add(a, c, d, e) +#define class_device_destroy(a, b) class_simple_device_remove(b) + +#else + +#define CLASS class + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + +#define CLASS_DEVICE_CREATE(a, b, c, d, e) class_device_create(a, c, d, e) + +#else + +#define CLASS_DEVICE_CREATE(a, b, c, d, e) class_device_create(a, b, c, d, e) + +#endif + +#endif + +/**************************************************************************/ + +#include "fusd.h" +#include "fusd_msg.h" +#include "kfusd.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +# error "***FUSD doesn't work before Linux Kernel v2.4.0" +#endif + +STATIC struct cdev* fusd_control_device; +STATIC struct cdev* fusd_status_device; + +STATIC dev_t control_id; +STATIC dev_t status_id; + +static struct CLASS *fusd_class; + +static struct class_device *fusd_control_class_device; +static struct class_device *fusd_status_class_device; + +extern struct CLASS *sound_class; + +/* version number incremented for each registered device */ +STATIC int last_version = 1; + +/* version number incremented for each transaction to userspace */ +STATIC int last_transid = 1; + +/* wait queue that is awakened when new devices are registered */ +STATIC DECLARE_WAIT_QUEUE_HEAD(new_device_wait); + +/* the list of valid devices, and sem to protect it */ +LIST_HEAD(fusd_devlist_head); +DECLARE_MUTEX(fusd_devlist_sem); + +//#ifdef MODULE_LICENSE +MODULE_AUTHOR("Jeremy Elson <jelson@acm.org> (c)2001"); +MODULE_LICENSE("GPL"); +//#endif + +/***************************Debugging Support*****************************/ + +#ifdef CONFIG_FUSD_DEBUG + +STATIC int fusd_debug_level = CONFIG_FUSD_DEBUGLEVEL; +module_param(fusd_debug_level, int, S_IRUGO); + +#define BUFSIZE 1000 /* kernel's kmalloc pool has a 1012-sized bucket */ + +STATIC void rdebug_real(char *fmt, ...) +{ + va_list ap; + int len; + char *message; + + /* I'm kmallocing since you don't really want 1k on the stack. I've + * had stack overflow problems before; the kernel stack is quite + * small... */ + if ((message = KMALLOC(BUFSIZE, GFP_KERNEL)) == NULL) + return; + + va_start(ap, fmt); + len = vsnprintf(message, BUFSIZE-1, fmt, ap); + va_end(ap); + + if (len >= BUFSIZE) { + printk("WARNING: POSSIBLE KERNEL CORRUPTION; MESSAGE TOO LONG\n"); + } else { + printk("fusd: %.975s\n", message); /* note msgs are truncated at + * ~1000 chars to fit inside the 1024 printk + * limit imposed by the kernel */ + } + + KFREE(message); +} + +#endif /* CONFIG_FUSD_DEBUG */ + +/******************** Memory Debugging ************************************/ + +#ifdef CONFIG_FUSD_MEMDEBUG + +#define MAX_MEM_DEBUG 10000 + +DECLARE_MUTEX(fusd_memdebug_sem); + +typedef struct { + void *ptr; + int line; + int size; +} mem_debug_t; + +mem_debug_t *mem_debug; + +STATIC int fusd_mem_init(void) +{ + int i; + + mem_debug = kmalloc(sizeof(mem_debug_t) * MAX_MEM_DEBUG, GFP_KERNEL); + + if (mem_debug == NULL) { + RDEBUG(2, "argh - memdebug malloc failed!"); + return -ENOMEM; + } + + /* initialize */ + for (i = 0; i < MAX_MEM_DEBUG; i++) + mem_debug[i].ptr = NULL; + + RDEBUG(2, "FUSD memory debugger activated"); + return 0; +} + +STATIC void fusd_mem_cleanup(void) +{ + int i; + int count=0; + for (i = 0; i < MAX_MEM_DEBUG; i++) + if (mem_debug[i].ptr != NULL) { + RDEBUG(0, "memdebug: failed to free memory allocated at line %d (%d b)", + mem_debug[i].line, mem_debug[i].size); + count++; + } + if (!count) + RDEBUG(2, "congratulations - memory debugger is happy!"); + kfree(mem_debug); +} + +STATIC void fusd_mem_add(void *ptr, int line, int size) +{ + int i; + + if (ptr==NULL) + return; + + for (i = 0; i < MAX_MEM_DEBUG; i++) { + if (mem_debug[i].ptr == NULL) { + mem_debug[i].ptr = ptr; + mem_debug[i].line = line; + mem_debug[i].size = size; + return; + } + } + RDEBUG(1, "WARNING - memdebug out of space!!!!"); +} + +STATIC void fusd_mem_del(void *ptr) +{ + int i; + for (i = 0; i < MAX_MEM_DEBUG; i++) { + if (mem_debug[i].ptr == ptr) { + mem_debug[i].ptr = NULL; + return; + } + } + RDEBUG(2, "WARNING - memdebug is confused!!!!"); +} + + +STATIC void *fusd_kmalloc(size_t size, int type, int line) +{ + void *ptr = kmalloc(size, type); + down(&fusd_memdebug_sem); + fusd_mem_add(ptr, line, size); + up(&fusd_memdebug_sem); + return ptr; +} + +STATIC void fusd_kfree(void *ptr) +{ + down(&fusd_memdebug_sem); + fusd_mem_del(ptr); + kfree(ptr); + up(&fusd_memdebug_sem); +} + +STATIC void *fusd_vmalloc(size_t size, int line) +{ + void *ptr = vmalloc(size); + down(&fusd_memdebug_sem); + fusd_mem_add(ptr, line, size); + up(&fusd_memdebug_sem); + return ptr; +} + +STATIC void fusd_vfree(void *ptr) +{ + down(&fusd_memdebug_sem); + fusd_mem_del(ptr); + vfree(ptr); + up(&fusd_memdebug_sem); +} + +#endif /* CONFIG_FUSD_MEMDEBUG */ + + +/********************* FUSD Device List ***************************/ + + + +/*************************************************************************/ +/************** STATE MANAGEMENT AND BOOKKEEPING UTILITIES ***************/ +/*************************************************************************/ + +STATIC inline void init_fusd_msg(fusd_msg_t *fusd_msg) +{ + if (fusd_msg == NULL) + return; + + memset(fusd_msg, 0, sizeof(fusd_msg_t)); + fusd_msg->magic = FUSD_MSG_MAGIC; + fusd_msg->cmd = FUSD_FOPS_CALL; /* typical, but can be overwritten */ +} + +/* + * free a fusd_msg, and NULL out the pointer that points to that fusd_msg. + */ +STATIC inline void free_fusd_msg(fusd_msg_t **fusd_msg) +{ + if (fusd_msg == NULL || *fusd_msg == NULL) + return; + + if ((*fusd_msg)->data != NULL) { + VFREE((*fusd_msg)->data); + (*fusd_msg)->data = NULL; + } + KFREE(*fusd_msg); + *fusd_msg = NULL; +} + + +/* adjust the size of the 'files' array attached to the device to + * better match the number of files. In all cases, size must be at + * least MIN_ARRAY_SIZE. Subject to that constraint: if + * num_files==array_size, the size is doubled; if + * num_files<array_size/4, the size is halved. Array is kept as is if + * the malloc fails. Returns a pointer to the new file struct or NULL + * if there isn't one. */ +STATIC fusd_file_t **fusd_dev_adjsize(fusd_dev_t *fusd_dev) +{ + fusd_file_t **old_array; + int old_size; + + old_array = fusd_dev->files; + old_size = fusd_dev->array_size; + + /* compute the new size of the array */ + if (fusd_dev->array_size > 4*fusd_dev->num_files) + fusd_dev->array_size /= 2; + else if (fusd_dev->array_size == fusd_dev->num_files) + fusd_dev->array_size *= 2; + + /* respect the minimums and maximums (policy) */ + if (fusd_dev->array_size < MIN_FILEARRAY_SIZE) + fusd_dev->array_size = MIN_FILEARRAY_SIZE; + if (fusd_dev->array_size > MAX_FILEARRAY_SIZE) + fusd_dev->array_size = MAX_FILEARRAY_SIZE; + + /* make sure it's sane */ + if (fusd_dev->array_size < fusd_dev->num_files) { + RDEBUG(0, "fusd_dev_adjsize is royally screwed up!!!!!"); + return fusd_dev->files; + } + + /* create a new array. if successful, copy the contents of the old + * one. if not, revert back to the old. */ + fusd_dev->files = KMALLOC(fusd_dev->array_size * sizeof(fusd_file_t *), + GFP_KERNEL); + if (fusd_dev->files == NULL) { + RDEBUG(1, "malloc failed in fusd_dev_adjsize!"); + fusd_dev->files = old_array; + fusd_dev->array_size = old_size; + } else { + RDEBUG(10, "/dev/%s now has space for %d files (had %d)", NAME(fusd_dev), + fusd_dev->array_size, old_size); + memset(fusd_dev->files, 0, fusd_dev->array_size * sizeof(fusd_file_t *)); + memcpy(fusd_dev->files, old_array, + fusd_dev->num_files * sizeof(fusd_file_t *)); + KFREE(old_array); + } + + return fusd_dev->files; +} + + +/* + * DEVICE LOCK MUST BE HELD TO CALL THIS FUNCTION + * + * This function frees a device IF there is nothing left that is + * referencing it. + * + * Specifically, we do not free the device if: + * - The driver is still active (i.e. device is not a zombie) + * - There are still files with the device open + * - There is an open in progress, i.e. a client has verified that + * this is a valid device and is getting ready to add itself as an + * open file. + * + * If the device is safe to free, it is removed from the valid list + * (in verysafe mode only) and freed. + * + * Returns: 1 if the device was freed + * 0 if the device still exists (and can be unlocked) */ +STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev) +{ + fusd_msgC_t *ptr, *next; + + down(&fusd_devlist_sem); + + /* DON'T free the device under conditions listed above */ + if (!fusd_dev->zombie || fusd_dev->num_files || fusd_dev->open_in_progress) { + up(&fusd_devlist_sem); + return 0; + } + + /* OK - bombs away! This fusd_dev_t is on its way out the door! */ + + RDEBUG(8, "freeing state associated with /dev/%s", NAME(fusd_dev)); + + /* delete it off the list of valid devices, and unlock */ + list_del(&fusd_dev->devlist); + up(&fusd_devlist_sem); + + /* free any outgoing messages that the device might have waiting */ + for (ptr = fusd_dev->msg_head; ptr != NULL; ptr = next) { + next = ptr->next; + FREE_FUSD_MSGC(ptr); + } + + /* free the device's dev name */ + if (fusd_dev->dev_name != NULL) { + KFREE(fusd_dev->dev_name); + fusd_dev->dev_name = NULL; + } + + /* free the device's class name */ + if (fusd_dev->class_name != NULL) { + KFREE(fusd_dev->class_name); + fusd_dev->class_name = NULL; + } + + /* free the device's name */ + if (fusd_dev->name != NULL) { + KFREE(fusd_dev->name); + fusd_dev->name = NULL; + } + + + /* free the array used to store pointers to fusd_file_t's */ + if (fusd_dev->files != NULL) { + KFREE(fusd_dev->files); + fusd_dev->files = NULL; + } + + /* clear the structure and free it! */ + memset(fusd_dev, 0, sizeof(fusd_dev_t)); + KFREE(fusd_dev); + + /* notify fusd_status readers that there has been a change in the + * list of registered devices */ + atomic_inc_and_ret(&last_version); + wake_up_interruptible(&new_device_wait); + + //MOD_DEC_USE_COUNT; + return 1; +} + + +/* + * + * DO NOT CALL THIS FUNCTION UNLESS THE DEVICE IS ALREADY LOCKED + * + * zombify_device: called when the driver disappears. Indicates that + * the driver is no longer available to service requests. If there + * are no outstanding system calls waiting for the fusd_dev state, the + * device state itself is freed. + * + */ +STATIC void zombify_dev(fusd_dev_t *fusd_dev) +{ + int i; + + if (fusd_dev->zombie) { + RDEBUG(1, "zombify_device called on a zombie!!"); + return; + } + + fusd_dev->zombie = 1; + + RDEBUG(3, "/dev/%s turning into a zombie (%d open files)", NAME(fusd_dev), + fusd_dev->num_files); + + /* If there are files holding this device open, wake them up. */ + for (i = 0; i < fusd_dev->num_files; i++) { + wake_up_interruptible(&fusd_dev->files[i]->file_wait); + wake_up_interruptible(&fusd_dev->files[i]->poll_wait); + } +} + + + +/* utility function to find the index of a fusd_file in a fusd_dev. + * returns index if found, -1 if not found. ASSUMES WE HAVE A VALID + * fusd_dev. fusd_file may be NULL if we are searching for an empty + * slot. */ +STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) +{ + int i, num_files = fusd_dev->num_files; + fusd_file_t **files = fusd_dev->files; + + for (i = 0; i < num_files; i++) + if (files[i] == fusd_file) + return i; + + return -1; +} + + +/* + * DEVICE LOCK MUST BE HELD BEFORE THIS IS CALLED + * + * Returns 1 if the device was also freed. 0 if only the file was + * freed. If the device is freed, then do not try to unlock it! + * (Callers: Check the return value before unlocking!) + */ +STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) +{ + int i; + struct list_head *tmp, *it; + + /* find the index of the file in the device's file-list... */ + if ((i = find_fusd_file(fusd_dev, fusd_file)) < 0) + panic("corrupted fusd_dev: releasing a file that we think is closed"); + + /* ...and remove it (by putting the last entry into its place) */ + fusd_dev->files[i] = fusd_dev->files[--(fusd_dev->num_files)]; + + /* there might be an incoming message waiting for a restarted system + * call. free it -- after possibly forging a close (see + * fusd_forge_close). */ + + + list_for_each_safe(it, tmp, &fusd_file->transactions) + { + struct fusd_transaction* transaction = list_entry(it, struct fusd_transaction, list); + if(transaction->msg_in) + { + if (transaction->msg_in->subcmd == FUSD_OPEN && transaction->msg_in->parm.fops_msg.retval == 0) + fusd_forge_close(transaction->msg_in, fusd_dev); + free_fusd_msg(&transaction->msg_in); + } + KFREE(transaction); + } + + /* free state associated with this file */ + memset(fusd_file, 0, sizeof(fusd_file_t)); + KFREE(fusd_file); + + /* reduce the size of the file array if necessary */ + if (fusd_dev->array_size > MIN_FILEARRAY_SIZE && + fusd_dev->array_size > 4*fusd_dev->num_files) + fusd_dev_adjsize(fusd_dev); + + /* renumber the array */ + for (i = 0; i < fusd_dev->num_files; i++) + fusd_dev->files[i]->index = i; + + /* try to free the device -- this may have been its last file */ + return maybe_free_fusd_dev(fusd_dev); +} + + +/****************************************************************************/ +/********************** CLIENT CALLBACK FUNCTIONS ***************************/ +/****************************************************************************/ + + +/* todo + * fusd_restart_check: Called from the beginning of most system calls + * to see if we are restarting a system call. + * + * In the common case -- that this is NOT a restarted syscall -- we + * return 0. + * + * In the much less common case, we return ERESTARTSYS, and expect the + * caller to jump right to its fusd_fops_call() call. + * + * In the even LESS (hopefully very rare) case when one PID had an + * interrupted syscall, but a different PID is the next to do a system + * call on that file descriptor -- well, we lose. Clear state of that + * old syscall out and continue as usual. + */ +STATIC struct fusd_transaction* fusd_find_incomplete_transaction(fusd_file_t *fusd_file, int subcmd) +{ + struct fusd_transaction* transaction = fusd_find_transaction_by_pid(fusd_file, current->pid); + if(transaction == NULL) + return NULL; + + + if (transaction->subcmd != subcmd) + { + RDEBUG(2, "Incomplete transaction %ld thrown out, was expecting subcmd %d but received %d", + transaction->transid, transaction->subcmd, subcmd); + fusd_cleanup_transaction(fusd_file, transaction); + return NULL; + } + + RDEBUG(4, "pid %d restarting system call with transid %ld", current->pid, + transaction->transid); + return transaction; +} + + +STATIC int send_to_dev(fusd_dev_t *fusd_dev, fusd_msg_t *fusd_msg, int locked) +{ + fusd_msgC_t *fusd_msgC; + + /* allocate a container for the message */ + if ((fusd_msgC = KMALLOC(sizeof(fusd_msgC_t), GFP_KERNEL)) == NULL) + return -ENOMEM; + + memset(fusd_msgC, 0, sizeof(fusd_msgC_t)); + memcpy(&fusd_msgC->fusd_msg, fusd_msg, sizeof(fusd_msg_t)); + + if (!locked) + LOCK_FUSD_DEV(fusd_dev); + + /* put the message in the device's outgoing queue. */ + if (fusd_dev->msg_head == NULL) { + fusd_dev->msg_head = fusd_dev->msg_tail = fusd_msgC; + } else { + fusd_dev->msg_tail->next = fusd_msgC; + fusd_dev->msg_tail = fusd_msgC; + } + + if (!locked) + UNLOCK_FUSD_DEV(fusd_dev); + + /* wake up the driver, which now has a message waiting in its queue */ + WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_dev->dev_wait); + + return 0; + + zombie_dev: + KFREE(fusd_msgC); + return -EPIPE; +} + + +/* + * special case: if the driver sent back a successful "open", but + * there is no file that is actually open, we forge a "close" so that + * the driver can maintain balanced open/close pairs. We put calls to + * this in fusd_fops_reply, when the reply first comes in; and, + * free_fusd_file, when we throw away a reply that had been + * pending for a restart. + */ +STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev) +{ + RDEBUG(2, "/dev/%s tried to complete an open for transid %ld, " + "forging a close", NAME(fusd_dev), msg->parm.fops_msg.transid); + msg->cmd = FUSD_FOPS_CALL_DROPREPLY; + msg->subcmd = FUSD_CLOSE; + msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid); + send_to_dev(fusd_dev, msg, 1); +} + + + +/* + * fusd_fops_call_send: send a fusd_msg into userspace. + * + * NOTE - we are already holding the lock on fusd_file_arg when this + * function is called, but NOT the lock on the fusd_dev + */ +STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg, + fusd_msg_t *fusd_msg, struct fusd_transaction** transaction) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + + /* I check this just in case, shouldn't be necessary. */ + GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev); + + /* make sure message is sane */ + if ((fusd_msg->data == NULL) != (fusd_msg->datalen == 0)) { + RDEBUG(2, "fusd_fops_call: data pointer and datalen mismatch"); + return -EINVAL; + } + + /* fill the rest of the structure */ + fusd_msg->parm.fops_msg.pid = current->pid; + fusd_msg->parm.fops_msg.uid = current->uid; + fusd_msg->parm.fops_msg.gid = current->gid; + fusd_msg->parm.fops_msg.flags = fusd_file->file->f_flags; + fusd_msg->parm.fops_msg.offset = fusd_file->file->f_pos; + fusd_msg->parm.fops_msg.device_info = fusd_dev->private_data; + fusd_msg->parm.fops_msg.private_info = fusd_file->private_data; + fusd_msg->parm.fops_msg.fusd_file = fusd_file; + fusd_msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid); + + /* set up certain state depending on if we expect a reply */ + switch (fusd_msg->cmd) { + + case FUSD_FOPS_CALL: /* common case */ + fusd_msg->parm.fops_msg.hint = fusd_file->index; + + break; + + case FUSD_FOPS_CALL_DROPREPLY: + /* nothing needed */ + break; + + case FUSD_FOPS_NONBLOCK: + fusd_msg->parm.fops_msg.hint = fusd_file->index; + break; + + default: + RDEBUG(0, "whoa - fusd_fops_call_send got msg with unknown cmd!"); + break; + } + + if(transaction != NULL) + { + int retval; + retval = fusd_add_transaction(fusd_file, fusd_msg->parm.fops_msg.transid, fusd_msg->subcmd, + fusd_msg->parm.fops_msg.length, transaction); + if(retval < 0) + return retval; + } + + /* now add the message to the device's outgoing queue! */ + return send_to_dev(fusd_dev, fusd_msg, 0); + + + /* bizarre errors go straight here */ + invalid_dev: + invalid_file: + RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!"); + return -EPIPE; +} + + +/* + * fusd_fops_call_wait: wait for a driver to reply to a message + * + * NOTE - we are already holding the lock on fusd_file_arg when this + * function is called, but NOT the lock on the fusd_dev + */ +STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg, + fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + int retval; + + /* I check this just in case, shouldn't be necessary. */ + GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev); + + /* initialize first to tell callers there is no reply (yet) */ + if (fusd_msg_reply != NULL) + *fusd_msg_reply = NULL; + + /* + * Now, lock the device, check for an incoming message, and sleep if + * there is not a message already waiting for us. Note that we are + * unrolling the interruptible_sleep_on, as in the kernel's + * fs/pipe.c, to avoid race conditions between checking for the + * sleep condition and sleeping. + */ + LOCK_FUSD_DEV(fusd_dev); + while (transaction->msg_in == NULL) { + DECLARE_WAITQUEUE(wait, current); + + RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&fusd_file->file_wait, &wait); + UNLOCK_FUSD_DEV(fusd_dev); + UNLOCK_FUSD_FILE(fusd_file); + + schedule(); + remove_wait_queue(&fusd_file->file_wait, &wait); + current->state = TASK_RUNNING; + + /* + * If we woke up due to a signal -- and not due to a reply message + * coming in -- then we are in some trouble. The driver is already + * processing the request and might have changed some state that is + * hard to roll back. So, we'll tell the process to restart the + * system call, and come back to this point when the system call is + * restarted. We need to remember the PID to avoid confusion in + * case there is another process holding this file descriptor that + * is also trying to make a call. + */ + if (signal_pending(current)) { + RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS", + current->pid); + LOCK_FUSD_FILE(fusd_file); + return -ERESTARTSYS; + } + + LOCK_FUSD_FILE(fusd_file); + /* re-lock the device, so we can do our msg_in check again */ + LOCK_FUSD_DEV(fusd_dev); + } + UNLOCK_FUSD_DEV(fusd_dev); + + /* ok - at this point we are awake due to a message received. */ + + if (transaction->msg_in->cmd != FUSD_FOPS_REPLY || + transaction->msg_in->subcmd != transaction->subcmd || + transaction->msg_in->parm.fops_msg.transid != transaction->transid || + transaction->msg_in->parm.fops_msg.fusd_file != fusd_file) { + RDEBUG(2, "fusd_fops_call: invalid reply!"); + goto invalid_reply; + } + + /* copy metadata back from userspace */ + fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags; + fusd_file->private_data = transaction->msg_in->parm.fops_msg.private_info; + /* note, changes to device_info are NO LONGER honored here */ + + /* if everything's okay, return the return value. if caller is + * willing to take responsibility for freeing the message itself, we + * return the message too. */ + retval = transaction->msg_in->parm.fops_msg.retval; + if (fusd_msg_reply != NULL) { + /* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */ + *fusd_msg_reply = transaction->msg_in; + transaction->msg_in = NULL; + } else { + /* free the message ourselves */ + free_fusd_msg(&transaction->msg_in); + } + + /* success */ + fusd_cleanup_transaction(fusd_file, transaction); + return retval; + + invalid_reply: + fusd_cleanup_transaction(fusd_file, transaction); + return -EPIPE; + + /* bizarre errors go straight here */ + invalid_dev: + invalid_file: + RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!"); + return -EPIPE; + + zombie_dev: + RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply", + NAME(fusd_dev)); + return -EPIPE; +} + + +/* fusd client system call handlers should call this after they call + * fops_call, to destroy the message that was returned to them. */ +STATIC void fusd_transaction_done(struct fusd_transaction *transaction) +{ + transaction->transid = -1; + transaction->pid = 0; +} + + + +/********* Functions for opening a FUSD device *******************/ + + +/* + * The process of having a client open a FUSD device is surprisingly + * tricky -- perhaps the most complex piece of FUSD (or, a close + * second to poll_diffs). Race conditions are rampant here. + * + * The main problem is that there is a race between clients trying to + * open the FUSD device, and providers unregistering it (e.g., the + * driver dying). If the device-unregister callback starts, and is + * scheduled out after it locks the fusd device but before it + * unregisters the device with devfs, the open callback might be + * invoked in this interval. This means the client will down() on a + * semaphore that is about to be freed when the device is destroyed. + * + * The only way to fix this, as far as I can tell, is for device + * registration and unregistration to both share a global lock; the + * client checks its 'private_data' pointer to make sure it's on the + * list of valid devices. If so, it sets a flag (open_in_progress) + * which means "Don't free this device yet!". Then, it releases the + * global lock, grabs the device lock, and tries to add itself as a + * "file" to the device array. It is then safe to decrement + * open_in_progress, because being a member of the file array will + * guarantee that the device will zombify instead of being freed. + * + * Another gotcha: To avoid infinitely dining with philosophers, the + * global lock (fusd_devlist_sem) should always be acquired AFTER a + * fusd device is locked. The code path that frees devices acquires + * the device lock FIRST, so the code here must do the same. + * + * Because of the complexity of opening a file, I've broken it up into + * multiple sub-functions. + */ + + +/* + * fusd_dev_is_valid: If a fusd device is valid, returns 1, and will have + * set the "open_in_progress" flag on the device. + */ +int fusd_dev_is_valid(fusd_dev_t *fusd_dev) +{ + struct list_head *tmp; + int dev_found = 0; + + /* The first thing we must do is acquire the global lock on the + * device list, and make sure this device is valid; if so, mark it + * as being "in use". If we don't do this, there's a race: after we + * enter this function, the device may be unregistered. */ + down(&fusd_devlist_sem); + list_for_each(tmp, &fusd_devlist_head) { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + + if (d == fusd_dev && d->magic == FUSD_DEV_MAGIC && !ZOMBIE(d)) { + dev_found = 1; + break; + } + } + + /* A device will not be deallocated when this counter is >0 */ + if (dev_found) + fusd_dev->open_in_progress++; + + up(&fusd_devlist_sem); + + return dev_found; +} + + +int fusd_dev_add_file(struct file *file, fusd_dev_t *fusd_dev, fusd_file_t **fusd_file_ret) +{ + fusd_file_t *fusd_file; + int i; + + /* Make sure the device didn't become a zombie while we were waiting + * for the device lock */ + if (ZOMBIE(fusd_dev)) + return -ENOENT; + + /* this shouldn't happen. maybe i'm insane, but i check anyway. */ + for (i = 0; i < fusd_dev->num_files; i++) + if (fusd_dev->files[i]->file == file) { + RDEBUG(1, "warning: fusd_client_open got open for already-open file!?"); + return -EIO; + } + + /* You can't open your own file! Return -EDEADLOCK if someone tries to. + * + * XXX - TODO - FIXME - This should eventually be more general + * deadlock detection of arbitrary length cycles */ + if (current->pid == fusd_dev->pid) { + RDEBUG(3, "pid %d tried to open its own device (/dev/%s)", + fusd_dev->pid, NAME(fusd_dev)); + return -EDEADLOCK; + } + + /* make more space in the file array if we need it */ + if (fusd_dev->num_files == fusd_dev->array_size && + fusd_dev->array_size < MAX_FILEARRAY_SIZE) + fusd_dev_adjsize(fusd_dev); + + /* make sure we have room... adjsize may have failed */ + if (fusd_dev->num_files >= fusd_dev->array_size) { + RDEBUG(1, "/dev/%s out of state space for open files!", NAME(fusd_dev)); + return -ENOMEM; + } + + /* create state for this file */ + if ((fusd_file = KMALLOC(sizeof(fusd_file_t), GFP_KERNEL)) == NULL) { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + memset(fusd_file, 0, sizeof(fusd_file_t)); + init_waitqueue_head(&fusd_file->file_wait); + init_waitqueue_head(&fusd_file->poll_wait); + INIT_LIST_HEAD(&fusd_file->transactions); + init_MUTEX(&fusd_file->file_sem); + init_MUTEX(&fusd_file->transactions_sem); + fusd_file->last_poll_sent = -1; + fusd_file->magic = FUSD_FILE_MAGIC; + fusd_file->fusd_dev = fusd_dev; + fusd_file->fusd_dev_version = fusd_dev->version; + fusd_file->file = file; + + /* add this file to the list of files managed by the device */ + fusd_file->index = fusd_dev->num_files++; + fusd_dev->files[fusd_file->index] = fusd_file; + + /* store the pointer to this file with the kernel */ + file->private_data = fusd_file; + *fusd_file_ret = fusd_file; + + /* success! */ + return 0; +} + +STATIC struct fusd_dev_t_s* find_user_device(int dev_id) +{ + struct list_head* entry; + down(&fusd_devlist_sem); + list_for_each(entry, &fusd_devlist_head) + { + fusd_dev_t *d = list_entry(entry, fusd_dev_t, devlist); + if(d->dev_id == dev_id) + { + up(&fusd_devlist_sem); + return d; + } + } + up(&fusd_devlist_sem); + return NULL; +} + +/* + * A client has called open() has been called on a registered device. + * See comment higher up for detailed notes on this function. + */ +STATIC int fusd_client_open(struct inode *inode, struct file *file) +{ + int retval; + int device_freed = 0; + fusd_dev_t *fusd_dev = find_user_device(inode->i_rdev); + fusd_file_t *fusd_file; + fusd_msg_t fusd_msg; + struct fusd_transaction* transaction; + + /* If the device wasn't on our valid list, stop here. */ + if (!fusd_dev_is_valid(fusd_dev)) + return -ENOENT; + + /* fusd_dev->open_in_progress now set */ + + /* Lock the fusd device. Note, when we finally do acquire the lock, + * the device might be a zombie (driver disappeared). */ + RAWLOCK_FUSD_DEV(fusd_dev); + + RDEBUG(3, "got an open for /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + /* Try to add ourselves to the device's file list. If retval==0, we + are now part of the file array. */ + retval = fusd_dev_add_file(file, fusd_dev, &fusd_file); + + /* + * It is now safe to unset the open_in_progress flag. Either: + * 1) We are part of the file array, so dev won't be freed, or; + * 2) Something failed, so we are returning a failure now and no + * longer need the device. + * Note, open_in_progress must be protected by the global sem, not + * the device lock, due to the access of it in fusd_dev_is_valid(). + */ + down(&fusd_devlist_sem); + fusd_dev->open_in_progress--; + up(&fusd_devlist_sem); + + /* If adding ourselves to the device list failed, give up. Possibly + * free the device if it was a zombie and waiting for us to complete + * our open. */ + if (retval < 0) { + if (!maybe_free_fusd_dev(fusd_dev)) + UNLOCK_FUSD_DEV(fusd_dev); + return retval; + } + + /* send message to userspace and get retval */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_OPEN; + + /* send message to userspace and get the reply. Device can't be + * locked during that operation. */ + + UNLOCK_FUSD_DEV(fusd_dev); + retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); + + if (retval >= 0) + retval = fusd_fops_call_wait(fusd_file, NULL, transaction); + RAWLOCK_FUSD_DEV(fusd_dev); + + /* If the device zombified (while we were waiting to reacquire the + * lock)... consider that a failure */ + if (ZOMBIE(fusd_dev)) + retval = -ENOENT; + + /* if retval is negative, throw away state... the file open failed */ + if (retval < 0) { + RDEBUG(3, "...open failed for /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + device_freed = free_fusd_file(fusd_dev, fusd_file); + } + + /* Now unlock the device, if it still exists. (It may have been + * freed if the open failed, and we were the last outstanding + * request for it.) */ + if (!device_freed) + UNLOCK_FUSD_DEV(fusd_dev); + + return retval; +} + + +/* close() has been called on a registered device. like + * fusd_client_open, we must lock the entire device. */ +STATIC int fusd_client_release(struct inode *inode, struct file *file) +{ + int retval; + fusd_file_t *fusd_file; + fusd_dev_t *fusd_dev; + fusd_msg_t fusd_msg; + struct fusd_transaction* transaction; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got a close on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + /* Tell the driver that the file closed, if it still exists. */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_CLOSE; + retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); + RDEBUG(5, "fusd_client_release: send returned %d", retval); + if (retval >= 0) + retval = fusd_fops_call_wait(fusd_file, NULL, transaction); + + RDEBUG(5, "fusd_client_release: call_wait %d", retval); + /* delete the file off the device's file-list, and free it. note + * that device may be a zombie right now and may be freed when we + * come back from free_fusd_file. we only release the lock if the + * device still exists. */ + RAWLOCK_FUSD_DEV(fusd_dev); + if (!free_fusd_file(fusd_dev, fusd_file)) { + UNLOCK_FUSD_DEV(fusd_dev); + } + + return retval; + + invalid_dev: + invalid_file: + RDEBUG(1, "got a close on client file from pid %d, INVALID DEVICE!", + current->pid); + return -EPIPE; +} + + + +STATIC ssize_t fusd_client_read(struct file *file , char *buf, + size_t count, loff_t *offset) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + struct fusd_transaction* transaction; + fusd_msg_t fusd_msg, *reply = NULL; + int retval = -EPIPE; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got a read on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_READ); + if (transaction && transaction->size > count) + { + RDEBUG(3, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was greater than " + "the retry's size of %d bytes", transaction->transid, transaction->size, (int)count); + + fusd_cleanup_transaction(fusd_file, transaction); + transaction = NULL; + } + + if(transaction == NULL) + { + /* make sure we aren't trying to read too big of a buffer */ + if (count > MAX_RW_SIZE) + count = MAX_RW_SIZE; + + /* send the message */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_READ; + fusd_msg.parm.fops_msg.length = count; + + /* send message to userspace */ + if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) + goto done; + } + + /* and wait for the reply */ + /* todo: store and retrieve the transid from the interrupted messsage */ + retval = fusd_fops_call_wait(fusd_file, &reply, transaction); + + /* return immediately in case of error */ + if (retval < 0 || reply == NULL) + goto done; + + /* adjust the reval if the retval indicates a larger read than the + * data that was actually provided */ + if (reply->datalen != retval) { + RDEBUG(1, "warning: /dev/%s driver (pid %d) claimed it returned %d bytes " + "on read but actually returned %d", + NAME(fusd_dev), fusd_dev->pid, retval, reply->datalen); + retval = reply->datalen; + } + + /* adjust if the device driver gave us more data than the user asked for + * (bad! bad! why is the driver broken???) */ + if (retval > count) { + RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on read but " + "the user only asked for %d", + NAME(fusd_dev), fusd_dev->pid, retval, (int) count); + retval = count; + } + + /* copy the offset back from the message */ + *offset = reply->parm.fops_msg.offset; + + /* IFF return value indicates data present, copy it back */ + if (retval > 0) { + if (copy_to_user(buf, reply->data, retval)) { + retval = -EFAULT; + goto done; + } + } + + done: + /* clear the readable bit of our cached poll state */ + fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_INPUT); + + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + + invalid_file: + invalid_dev: + RDEBUG(3, "got a read on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; +} + +STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction) +{ + struct fusd_transaction* transaction = (struct fusd_transaction*) KMALLOC(sizeof(struct fusd_transaction), GFP_KERNEL); + if(transaction == NULL) + return -ENOMEM; + + transaction->msg_in = NULL; + transaction->transid = transid; + transaction->subcmd = subcmd; + transaction->pid = current->pid; + transaction->size = size; + + down(&fusd_file->transactions_sem); + list_add_tail(&transaction->list, &fusd_file->transactions); + up(&fusd_file->transactions_sem); + + if(out_transaction != NULL) + *out_transaction = transaction; + + return 0; +} + +STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction) +{ + free_fusd_msg(&transaction->msg_in); + fusd_remove_transaction(fusd_file, transaction); +} + +STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction) +{ + down(&fusd_file->transactions_sem); + list_del(&transaction->list); + up(&fusd_file->transactions_sem); + + KFREE(transaction); +} + +STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid) +{ + struct list_head* i; + down(&fusd_file->transactions_sem); + list_for_each(i, &fusd_file->transactions) + { + struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list); + if(transaction->transid == transid) + { + up(&fusd_file->transactions_sem); + return transaction; + } + } + up(&fusd_file->transactions_sem); + return NULL; +} + +STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid) +{ + struct list_head* i; + down(&fusd_file->transactions_sem); + list_for_each(i, &fusd_file->transactions) + { + struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list); + if(transaction->pid == pid) + { + up(&fusd_file->transactions_sem); + return transaction; + } + } + up(&fusd_file->transactions_sem); + return NULL; +} + +STATIC ssize_t fusd_client_write(struct file *file, + const char *buffer, + size_t length, + loff_t *offset) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + fusd_msg_t fusd_msg; + fusd_msg_t *reply = NULL; + int retval = -EPIPE; + struct fusd_transaction* transaction; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got a write on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_WRITE); + if (transaction && transaction->size == length) + { + RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was not equal to " + "the retry's size of %d bytes", transaction->transid, transaction->size, (int) length); + + fusd_cleanup_transaction(fusd_file, transaction); + transaction = NULL; + } + if(transaction == NULL) + { + if (length < 0) { + RDEBUG(2, "fusd_client_write: got invalid length %d", (int) length); + retval = -EINVAL; + goto done; + } + + if (length > MAX_RW_SIZE) + length = MAX_RW_SIZE; + + init_fusd_msg(&fusd_msg); + + /* sigh.. i guess zero length writes should be legal */ + if (length > 0) { + if ((fusd_msg.data = VMALLOC(length)) == NULL) { + retval = -ENOMEM; + goto done; + } + + if (copy_from_user(fusd_msg.data, buffer, length)) { + retval = -EFAULT; + goto done; + } + fusd_msg.datalen = length; + } + + fusd_msg.subcmd = FUSD_WRITE; + fusd_msg.parm.fops_msg.length = length; + + if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) + goto done; + } + /* todo: fix transid on restart */ + retval = fusd_fops_call_wait(fusd_file, &reply, transaction); + + if (retval < 0 || reply == NULL) + goto done; + + /* drivers should not write more bytes than they were asked to! */ + if (retval > length) { + RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on write; " + "the user only wanted %d", + NAME(fusd_dev), fusd_dev->pid, retval, (int) length); + retval = length; + } + + *offset = reply->parm.fops_msg.offset; + + /* all done! */ + + done: + /* clear the writable bit of our cached poll state */ + fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_OUTPUT); + + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + + invalid_file: + invalid_dev: + RDEBUG(3, "got a read on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; +} + + +STATIC int fusd_client_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + fusd_msg_t fusd_msg, *reply = NULL; + int retval = -EPIPE, dir, length; + struct fusd_transaction* transaction; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got an ioctl on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + dir = _IOC_DIR(cmd); + length = _IOC_SIZE(cmd); + + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_IOCTL); + // todo: Check to make sure the transaction is for the same IOCTL + + if(transaction == NULL) + { + /* if we're trying to read or write, make sure length is sane */ + if ((dir & (_IOC_WRITE | _IOC_READ)) && + (length <= 0 || length > MAX_RW_SIZE)) + { + RDEBUG(2, "client ioctl got crazy IOC_SIZE of %d", length); + retval = -EINVAL; + goto done; + } + + /* fill the struct */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_IOCTL; + fusd_msg.parm.fops_msg.cmd = cmd; + fusd_msg.parm.fops_msg.arg.arg = arg; + + /* get the data if user is trying to write to the driver */ + if (dir & _IOC_WRITE) { + if ((fusd_msg.data = VMALLOC(length)) == NULL) { + RDEBUG(2, "can't vmalloc for client ioctl!"); + retval = -ENOMEM; + goto done; + } + + if (copy_from_user(fusd_msg.data, (void *) arg, length)) { + retval = -EFAULT; + goto done; + } + fusd_msg.datalen = length; + } + + /* send request to the driver */ + if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) + goto done; + } + /* get the response */ + /* todo: fix transid on restart */ + if ((retval = fusd_fops_call_wait(fusd_file, &reply, transaction)) < 0 || reply == NULL) + goto done; + + /* if user is trying to read from the driver, copy data back */ + if (dir & _IOC_READ) { + if (reply->data == NULL || reply->datalen != length) { + RDEBUG(2, "client_ioctl read reply with screwy data (%d, %d)", + reply->datalen, length); + retval = -EIO; + goto done; + } + if (copy_to_user((void *)arg, reply->data, length)) { + retval = -EFAULT; + goto done; + } + } + + /* all done! */ + done: + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + + invalid_file: + invalid_dev: + RDEBUG(3, "got a read on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; +} +static void fusd_client_mm_open(struct vm_area_struct * vma); +static void fusd_client_mm_close(struct vm_area_struct * vma); +static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address, int* type); +static struct vm_operations_struct fusd_remap_vm_ops = +{ + open: fusd_client_mm_open, + close: fusd_client_mm_close, + nopage: fusd_client_nopage, +}; + +struct fusd_mmap_instance +{ + fusd_dev_t* fusd_dev; + fusd_file_t* fusd_file; + unsigned long addr; + int size; + atomic_t refcount; +}; + +static void fusd_client_mm_open(struct vm_area_struct * vma) +{ + struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; + atomic_inc(&mmap_instance->refcount); + +} + +static void fusd_client_mm_close(struct vm_area_struct * vma) +{ + struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; + if(atomic_dec_and_test(&mmap_instance->refcount)) + { + KFREE(mmap_instance); + } +} + +static int fusd_client_mmap(struct file *file, struct vm_area_struct * vma) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + struct fusd_transaction* transaction; + fusd_msg_t fusd_msg, *reply = NULL; + int retval = -EPIPE; + struct fusd_mmap_instance* mmap_instance; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got a mmap on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_MMAP); + + if(transaction == NULL) + { + /* send the message */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_MMAP; + fusd_msg.parm.fops_msg.offset = vma->vm_pgoff << PAGE_SHIFT; + fusd_msg.parm.fops_msg.flags = vma->vm_flags; + fusd_msg.parm.fops_msg.length = vma->vm_end - vma->vm_start; + + /* send message to userspace */ + if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) + goto done; + } + + /* and wait for the reply */ + /* todo: store and retrieve the transid from the interrupted messsage */ + retval = fusd_fops_call_wait(fusd_file, &reply, transaction); + + mmap_instance = + (struct fusd_mmap_instance*) KMALLOC(sizeof(struct fusd_mmap_instance), GFP_KERNEL); + // todo: free this thing at some point + + mmap_instance->fusd_dev = fusd_dev; + mmap_instance->fusd_file = fusd_file; + mmap_instance->addr = reply->parm.fops_msg.arg.arg; + mmap_instance->size = reply->parm.fops_msg.length; + atomic_set(&mmap_instance->refcount, 0); + + retval = reply->parm.fops_msg.retval; + + vma->vm_private_data = mmap_instance; + vma->vm_ops = &fusd_remap_vm_ops; + vma->vm_flags |= VM_RESERVED; + + fusd_client_mm_open(vma); + + done: + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + + invalid_file: + invalid_dev: + RDEBUG(3, "got a mmap on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; +} + +static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address, + int* type) +{ + struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; + unsigned long offset; + struct page *page = NOPAGE_SIGBUS; + int result; + offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + // todo: worry about size + if(offset > mmap_instance->size) + goto out; + + down_read(&mmap_instance->fusd_dev->task->mm->mmap_sem); + result = get_user_pages(mmap_instance->fusd_dev->task, mmap_instance->fusd_dev->task->mm, mmap_instance->addr + offset, 1, 1, 0, &page, NULL); + up_read(&mmap_instance->fusd_dev->task->mm->mmap_sem); + + + if(PageAnon(page)) + { + RDEBUG(2, "Cannot mmap anonymous pages. Be sure to allocate your shared buffer with MAP_SHARED | MAP_ANONYMOUS"); + return NOPAGE_SIGBUS; + } + + if(result > 0) + { + get_page(page); + if (type) + *type = VM_FAULT_MINOR; + } +out: + return page; + + +} + + +/* + * The design of poll for clients is a bit subtle. + * + * We don't want the select() call itself to block, so we keep a cache + * of the most recently known state supplied by the driver. The cache + * is initialized to 0 (meaning: nothing readable/writable). + * + * When a poll comes in, we do a non-blocking (!) dispatch of a + * command telling the driver "This is the state we have cached, reply + * to this call when the state changes.", and then immediately return + * the cached state. We tell the kernel's select to sleep on our + * poll_wait wait queue. + * + * When the driver replies, we update our cached info and wake up the + * wait queue. Waking up the wait queue will most likely immediately + * effect a poll again, in which case we will reply whatever we just + * cached from the driver. + * + */ +STATIC unsigned int fusd_client_poll(struct file *file, poll_table *wait) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + int kernel_bits = 0; + int send_poll = 0; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + LOCK_FUSD_DEV(fusd_dev); + + RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d", + NAME(fusd_dev), fusd_dev->pid, current->pid, + fusd_file->cached_poll_state); + + poll_wait(file, &fusd_file->poll_wait, wait); + + /* + * If our currently cached poll state is not the same as the + * most-recently-sent polldiff request, then, dispatch a new + * request. (We DO NOT wait for a reply, but just dispatch the + * request). + * + * Also, don't send a new polldiff if the most recent one resulted + * in an error. + */ + if (fusd_file->last_poll_sent != fusd_file->cached_poll_state && + fusd_file->cached_poll_state >= 0) { + RDEBUG(3, "sending polldiff request because lps=%d, cps=%d", + fusd_file->last_poll_sent, fusd_file->cached_poll_state); + send_poll = 1; + fusd_file->last_poll_sent = fusd_file->cached_poll_state; + } + + /* compute what to return for the state we had cached, converting to + * bits that have meaning to the kernel */ + if (fusd_file->cached_poll_state > 0) { + if (fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT) + kernel_bits |= POLLIN; + if (fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT) + kernel_bits |= POLLOUT; + if (fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT) + kernel_bits |= POLLPRI; + } + + /* Now that we've committed to sending the poll, etc., it should be + * safe to unlock the device */ + UNLOCK_FUSD_DEV(fusd_dev); + UNLOCK_FUSD_FILE(fusd_file); + + if (send_poll) { + fusd_msg_t fusd_msg; + + init_fusd_msg(&fusd_msg); + fusd_msg.cmd = FUSD_FOPS_NONBLOCK; + fusd_msg.subcmd = FUSD_POLL_DIFF; + fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state; + if (fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0) { + /* If poll dispatched failed, set back to -1 so we try again. + * Not a race (I think), since sending an *extra* polldiff never + * hurts anything. */ + fusd_file->last_poll_sent = -1; + } + } + return kernel_bits; + + zombie_dev: + /* might jump here from LOCK_FUSD_DEV */ + UNLOCK_FUSD_FILE(fusd_file); + invalid_dev: + invalid_file: + RDEBUG(3, "got a select on client file from pid %d, driver has disappeared", + current->pid); + return POLLPRI; +} + + + +STATIC struct file_operations fusd_client_fops = { + owner: THIS_MODULE, + open: fusd_client_open, + release: fusd_client_release, + read: fusd_client_read, + write: fusd_client_write, + ioctl: fusd_client_ioctl, + poll: fusd_client_poll, + mmap: fusd_client_mmap +}; + + +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + + +STATIC fusd_file_t *find_fusd_reply_file(fusd_dev_t *fusd_dev, fusd_msg_t *msg) +{ + /* first, try the hint */ + int i = msg->parm.fops_msg.hint; + if (i >= 0 && + i < fusd_dev->num_files && + fusd_dev->files[i] == msg->parm.fops_msg.fusd_file) + { + RDEBUG(15, "find_fusd_reply_file: hint worked"); + } else { + /* hint didn't work, fall back to a search of the whole array */ + i = find_fusd_file(fusd_dev, msg->parm.fops_msg.fusd_file); + RDEBUG(15, "find_fusd_reply_file: hint failed"); + } + + /* we couldn't find anyone waiting for this message! */ + if (i < 0) { + return NULL; + } else { + return fusd_dev->files[i]; + } +} + + +/* Process an incoming reply to a message dispatched by + * fusd_fops_call. Called by fusd_write when a driver writes to + * /dev/fusd. */ +STATIC int fusd_fops_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg) +{ + fusd_file_t *fusd_file; + struct fusd_transaction *transaction; + + /* figure out the index of the file we are replying to. usually + * very fast (uses a hint) */ + if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL) { + RDEBUG(2, "fusd_fops_reply: got a reply on /dev/%s with no connection", + NAME(fusd_dev)); + goto discard; + } + + /* make sure this is not an old reply going to an old instance that's gone */ + /* todo: kor fix this */ +/* + if (fusd_file->fusd_dev_version != fusd_dev->version || + msg->parm.fops_msg.transid != fusd_file->transid_outstanding) { + RDEBUG(2, "fusd_fops_reply: got an old message, discarding"); + goto discard; + }*/ + + transaction = fusd_find_transaction(fusd_file, msg->parm.fops_msg.transid); + if(transaction == NULL) + { + RDEBUG(2, "fusd_fops_reply: No transaction found with transid %ld", msg->parm.fops_msg.transid); + goto discard; + } + + RDEBUG(10, "fusd_fops_reply: /dev/%s completed transid %ld (retval %d)", + NAME(fusd_dev), msg->parm.fops_msg.transid, + (int) msg->parm.fops_msg.retval); + + transaction->msg_in = msg; + mb(); + + WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_file->file_wait); + + return 0; + + discard: + if (msg->subcmd == FUSD_OPEN && msg->parm.fops_msg.retval == 0) { + fusd_forge_close(msg, fusd_dev); + return 0; + } else { + return -EPIPE; + } +} + + +/* special function to process responses to POLL_DIFF */ +STATIC int fusd_polldiff_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg) +{ + fusd_file_t *fusd_file; + + /* figure out the index of the file we are replying to. usually + * very fast (uses a hint) */ + if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL) + return -EPIPE; + + /* record the poll state returned. convert all negative retvals to -1. */ + if ((fusd_file->cached_poll_state = msg->parm.fops_msg.retval) < 0) + fusd_file->cached_poll_state = -1; + + RDEBUG(3, "got updated poll state from /dev/%s driver: %d", NAME(fusd_dev), + fusd_file->cached_poll_state); + + /* since the client has returned the polldiff we sent, set + * last_poll_sent to -1, so that we'll send a polldiff request on + * the next select. */ + fusd_file->last_poll_sent = -1; + + /* wake up select's queue so that a new polldiff is generated */ + wake_up_interruptible(&fusd_file->poll_wait); + + return 0; +} + +STATIC int fusd_register_device(fusd_dev_t *fusd_dev, + register_msg_t register_msg) +{ + int error = 0; + struct list_head *tmp; + int dev_id; + + /* make sure args are valid */ + if (fusd_dev == NULL) { + RDEBUG(0, "fusd_register_device: bug in arguments!"); + return -EINVAL; + } + + /* user can only register one device per instance */ +// if (fusd_dev->handle != 0) +// return -EBUSY; + + register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0'; + + /* make sure that there isn't already a device by this name */ + down(&fusd_devlist_sem); + list_for_each(tmp, &fusd_devlist_head) { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + + + if (d && d->name && !d->zombie && !strcmp(d->name, register_msg.name)) { + error = -EEXIST; + break; + } + } + up(&fusd_devlist_sem); + + if (error) + return error; + + + /* allocate memory for the name, and copy */ + if ((fusd_dev->name = KMALLOC(strlen(register_msg.name)+1, GFP_KERNEL)) == NULL) { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + + strcpy(fusd_dev->name, register_msg.name); + + /* allocate memory for the class name, and copy */ + if ((fusd_dev->class_name = KMALLOC(strlen(register_msg.clazz)+1, GFP_KERNEL)) == NULL) { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + + strcpy(fusd_dev->class_name, register_msg.clazz); + + /* allocate memory for the class name, and copy */ + if ((fusd_dev->dev_name = KMALLOC(strlen(register_msg.devname)+1, GFP_KERNEL)) == NULL) { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + + strcpy(fusd_dev->dev_name, register_msg.devname); + + dev_id = 0; + + if((error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name)) < 0) + { + printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", error); + goto register_failed; + } + + fusd_dev->dev_id = dev_id; + + fusd_dev->handle = cdev_alloc(); + if(fusd_dev->handle == NULL) + { + printk(KERN_ERR "cdev_alloc() failed\n"); + error = -ENOMEM; + goto register_failed3; + } + + fusd_dev->handle->owner = THIS_MODULE; + fusd_dev->handle->ops = &fusd_client_fops; + + kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name); + + if((error = cdev_add(fusd_dev->handle, dev_id, 1)) < 0) + { + printk(KERN_ERR "cdev_add failed status: %d\n", error); + kobject_put(&fusd_dev->handle->kobj); + goto register_failed3; + } + + // Hack to add my class to the sound class + if(strcmp("sound", register_msg.clazz) == 0) + { + fusd_dev->clazz = sound_class; + fusd_dev->owns_class = 0; + } + else + { + fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name); + if(IS_ERR(fusd_dev->clazz)) + { + error = PTR_ERR(fusd_dev->clazz); + printk(KERN_ERR "class_create failed status: %d\n", error); + goto register_failed4; + } + fusd_dev->owns_class = 1; + } + + fusd_dev->class_device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name); + if(fusd_dev->class_device == NULL) + { + error = PTR_ERR(fusd_dev->class_device); + printk(KERN_ERR "class_device_create failed status: %d\n", error); + goto register_failed5; + } + + /* make sure the registration was successful */ + /* + if (fusd_dev->handle == 0) { + error = -EIO; + goto register_failed; + } + */ + + /* remember the user's private data so we can pass it back later */ + fusd_dev->private_data = register_msg.device_info; + + /* everything ok */ + fusd_dev->version = atomic_inc_and_ret(&last_version); + RDEBUG(3, "pid %d registered /dev/%s v%ld", fusd_dev->pid, NAME(fusd_dev), + fusd_dev->version); + wake_up_interruptible(&new_device_wait); + return 0; + +register_failed5: + class_destroy(fusd_dev->clazz); + fusd_dev->clazz = NULL; +register_failed4: + cdev_del(fusd_dev->handle); + fusd_dev->handle = NULL; +register_failed3: + + //register_failed2: + unregister_chrdev_region(dev_id, 1); +register_failed: + KFREE(fusd_dev->name); + fusd_dev->name = NULL; + return error; +} + + +/****************************************************************************/ +/******************** CONTROL CHANNEL CALLBACK FUNCTIONS ********************/ +/****************************************************************************/ + + +/* open() called on /dev/fusd itself */ +STATIC int fusd_open(struct inode *inode, struct file *file) +{ + fusd_dev_t *fusd_dev = NULL; + fusd_file_t **file_array = NULL; + + /* keep the module from being unloaded during initialization! */ + //MOD_INC_USE_COUNT; + + /* allocate memory for the device state */ + if ((fusd_dev = KMALLOC(sizeof(fusd_dev_t), GFP_KERNEL)) == NULL) + goto dev_malloc_failed; + memset(fusd_dev, 0, sizeof(fusd_dev_t)); + + if ((file_array = fusd_dev_adjsize(fusd_dev)) == NULL) + goto file_malloc_failed; + + init_waitqueue_head(&fusd_dev->dev_wait); + init_MUTEX(&fusd_dev->dev_sem); + fusd_dev->magic = FUSD_DEV_MAGIC; + fusd_dev->pid = current->pid; + fusd_dev->task = current; + file->private_data = fusd_dev; + + /* add to the list of valid devices */ + down(&fusd_devlist_sem); + list_add(&fusd_dev->devlist, &fusd_devlist_head); + up(&fusd_devlist_sem); + + RDEBUG(3, "pid %d opened /dev/fusd", fusd_dev->pid); + return 0; + + file_malloc_failed: + KFREE(fusd_dev); + dev_malloc_failed: + RDEBUG(1, "out of memory in fusd_open!"); + //MOD_DEC_USE_COUNT; + return -ENOMEM; +} + + +/* close() called on /dev/fusd itself. destroy the device that + * was registered by it, if any. */ +STATIC int fusd_release(struct inode *inode, struct file *file) +{ + fusd_dev_t *fusd_dev; + + GET_FUSD_DEV(file->private_data, fusd_dev); + LOCK_FUSD_DEV(fusd_dev); + + if (fusd_dev->pid != current->pid) { + RDEBUG(2, "yikes!: when releasing device, pid mismatch"); + } + + RDEBUG(3, "pid %d closing /dev/fusd", current->pid); + +#if 0 + /* This delay is needed to exercise the openrace.c race condition, + * i.e. testing to make sure that our open_in_progress stuff works */ + { + int target = jiffies + 10*HZ; + + RDEBUG(1, "starting to wait"); + while (jiffies < target) + schedule(); + RDEBUG(1, "stopping wait"); + } +#endif + + if(fusd_dev->handle) + { + class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id); + if(fusd_dev->owns_class) + { + class_destroy(fusd_dev->clazz); + } + cdev_del(fusd_dev->handle); + unregister_chrdev_region(fusd_dev->dev_id, 1); + } + + /* mark the driver as being gone */ + zombify_dev(fusd_dev); + + /* ...and possibly free it. (Release lock if it hasn't been freed) */ + if (!maybe_free_fusd_dev(fusd_dev)) + UNLOCK_FUSD_DEV(fusd_dev); + + /* notify fusd_status readers that there has been a change in the + * list of registered devices */ + atomic_inc_and_ret(&last_version); + wake_up_interruptible(&new_device_wait); + + return 0; + + zombie_dev: + invalid_dev: + RDEBUG(1, "invalid device found in fusd_release!!"); + return -ENODEV; +} + + +/* + * This function processes messages coming from userspace device drivers + * (i.e., writes to the /dev/fusd control channel.) + */ +STATIC ssize_t fusd_process_write(struct file *file, + const char *user_msg_buffer, size_t user_msg_len, + const char *user_data_buffer, size_t user_data_len) +{ + fusd_dev_t *fusd_dev; + fusd_msg_t *msg = NULL; + int retval = 0; + int yield = 0; + + GET_FUSD_DEV(file->private_data, fusd_dev); + LOCK_FUSD_DEV(fusd_dev); + + /* get the header from userspace (first make sure there's enough data) */ + if (user_msg_len != sizeof(fusd_msg_t)) { + RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)", + (int) user_msg_len, (int) sizeof(fusd_msg_t)); + retval = -EINVAL; + goto out_no_free; + } + if ((msg = KMALLOC(sizeof(fusd_msg_t), GFP_KERNEL)) == NULL) { + retval = -ENOMEM; + RDEBUG(1, "yikes! kernel can't allocate memory"); + goto out; + } + memset(msg, 0, sizeof(fusd_msg_t)); + + if (copy_from_user(msg, user_msg_buffer, sizeof(fusd_msg_t))) { + retval = -EFAULT; + goto out; + } + msg->data = NULL; /* pointers from userspace have no meaning */ + + /* check the magic number before acting on the message at all */ + if (msg->magic != FUSD_MSG_MAGIC) { + RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d", + current->pid); + retval = -EIO; + goto out; + } + + /* now get data portion of the message */ + if (user_data_len < 0 || user_data_len > MAX_RW_SIZE) { + RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len); + retval = -EINVAL; + goto out; + } + if (msg->datalen != user_data_len) { + RDEBUG(2, "msg->datalen(%d) != user_data_len(%d), sigh!", + msg->datalen, (int) user_data_len); + retval = -EINVAL; + goto out; + } + if (user_data_len > 0) { + if (user_data_buffer == NULL) { + RDEBUG(2, "msg->datalen and no data buffer, sigh!"); + retval = -EINVAL; + goto out; + } + if ((msg->data = VMALLOC(user_data_len)) == NULL) { + retval = -ENOMEM; + RDEBUG(1, "yikes! kernel can't allocate memory"); + goto out; + } + if (copy_from_user(msg->data, user_data_buffer, user_data_len)) { + retval = -EFAULT; + goto out; + } + } + + /* before device registration, the only command allowed is 'register'. */ + /* + if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) { + RDEBUG(2, "got a message other than 'register' on a new device!"); + retval = -EINVAL; + goto out; + } + */ + + /* now dispatch the command to the appropriate handler */ + switch (msg->cmd) { + case FUSD_REGISTER_DEVICE: + retval = fusd_register_device(fusd_dev, msg->parm.register_msg); + goto out; + break; + case FUSD_FOPS_REPLY: + /* if reply is successful, DO NOT free the message */ + if ((retval = fusd_fops_reply(fusd_dev, msg)) == 0) { + yield = 1; + goto out_no_free; + } + break; + case FUSD_FOPS_NONBLOCK_REPLY: + switch (msg->subcmd) { + case FUSD_POLL_DIFF: + retval = fusd_polldiff_reply(fusd_dev, msg); + break; + default: + RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd); + retval = -EINVAL; + } + break; + default: + RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd); + retval = -EINVAL; + goto out; + break; + } + + + out: + if (msg && msg->data) { + VFREE(msg->data); + msg->data = NULL; + } + if (msg != NULL) { + KFREE(msg); + msg = NULL; + } + + out_no_free: + + /* the functions we call indicate success by returning 0. we + * convert that into a success indication by changing the retval to + * the length of the write. */ + if (retval == 0) + retval = user_data_len + user_msg_len; + + UNLOCK_FUSD_DEV(fusd_dev); + + /* if we successfully completed someone's syscall, yield the + * processor to them immediately as a throughput optimization. we + * also hope that in the case of bulk data transfer, their next + * syscall will come in before we are scheduled again. */ + if (yield) { +#ifdef SCHED_YIELD + current->policy |= SCHED_YIELD; +#endif + schedule(); + } + + return retval; + + zombie_dev: + invalid_dev: + RDEBUG(1, "fusd_process_write: got invalid device!"); + return -EPIPE; +} + + +STATIC ssize_t fusd_write(struct file *file, + const char *buffer, + size_t length, + loff_t *offset) +{ + return fusd_process_write(file, buffer, length, NULL, 0); +} + + +STATIC ssize_t fusd_writev(struct file *file, + const struct iovec *iov, + unsigned long count, + loff_t *offset) +{ + if (count != 2) { + RDEBUG(2, "fusd_writev: got illegal iov count of %ld", count); + return -EINVAL; + } + + return fusd_process_write(file, + iov[0].iov_base, iov[0].iov_len, + iov[1].iov_base, iov[1].iov_len); +} + + +/* fusd_read: a process is reading on /dev/fusd. return any messages + * waiting to go from kernel to userspace. + * + * Important note: there are 2 possible read modes; + * 1) header-read mode; just the fusd_msg structure is returned. + * + * 2) data-read mode; the data portion of a call (NOT including the + * fusd_msg structure) is returned. + * + * The protocol this function expects the user-space library to follow + * is: + * 1) Userspace library reads header. + * 2) If fusd_msg->datalen == 0, goto step 4. + * 3) Userspace library reads data. + * 4) Message gets dequeued by the kernel. + * + * In other words, userspace first reads the header. Then, if and + * only if the header you read indicates that data follows, userspace + * follows with a read for that data. + * + * For the header read, the length requested MUST be the exact length + * sizeof(fusd_msg_t). The corresponding data read must request + * exactly the number of bytes in the data portion of the message. NO + * OTHER READ LENGTHS ARE ALLOWED - ALL OTHER READ LENGTHS WILL GET AN + * -EINVAL. This is done as a basic safety measure to make sure we're + * talking to a userspace library that understands our protocol, and + * to detect framing errors. + * + * (note: normally you'd have to worry about reentrancy in a function + * like this because the process can block on the userspace access and + * another might try to read. usually we would copy the message into + * a temp location to make sure two processes don't get the same + * message. however in this very specialized case, we're okay, + * because each instance of /dev/fusd has a completely independent + * message queue.) */ + + +/* do a "header" read: used by fusd_read */ +STATIC int fusd_read_header(char *user_buffer, size_t user_length, fusd_msg_t *msg) +{ + int len = sizeof(fusd_msg_t); + + if (user_length != len) { + RDEBUG(4, "bad length of %d sent to /dev/fusd for peek", (int) user_length); + return -EINVAL; + } + + if (copy_to_user(user_buffer, msg, len)) + return -EFAULT; + + return sizeof(fusd_msg_t); +} + + +/* do a "data" read: used by fusd_read */ +STATIC int fusd_read_data(char *user_buffer, size_t user_length, fusd_msg_t *msg) +{ + int len = msg->datalen; + + if (len == 0 || msg->data == NULL) { + RDEBUG(1, "fusd_read_data: no data to send!"); + return -EIO; + } + + /* make sure the user is requesting exactly the right amount (as a + sanity check) */ + if (user_length != len) { + RDEBUG(4, "bad read for %d bytes on /dev/fusd (need %d)", (int) user_length,len); + return -EINVAL; + } + + /* now copy to userspace */ + if (copy_to_user(user_buffer, msg->data, len)) + return -EFAULT; + + /* done! */ + return len; +} + + +STATIC ssize_t fusd_read(struct file *file, + char *user_buffer, /* The buffer to fill with data */ + size_t user_length, /* The length of the buffer */ + loff_t *offset) /* Our offset in the file */ +{ + fusd_dev_t *fusd_dev; + fusd_msgC_t *msg_out; + int retval, dequeue = 0; + + GET_FUSD_DEV(file->private_data, fusd_dev); + LOCK_FUSD_DEV(fusd_dev); + + RDEBUG(15, "driver pid %d (/dev/%s) entering fusd_read", current->pid, + NAME(fusd_dev)); + + /* if no messages are waiting, either block or return EAGAIN */ + while ((msg_out = fusd_dev->msg_head) == NULL) { + DECLARE_WAITQUEUE(wait, current); + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + /* + * sleep, waiting for a message to arrive. we are unrolling + * interruptible_sleep_on to avoid a race between unlocking the + * device and sleeping (what if a message arrives in that + * interval?) + */ + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&fusd_dev->dev_wait, &wait); + UNLOCK_FUSD_DEV(fusd_dev); + schedule(); + remove_wait_queue(&fusd_dev->dev_wait, &wait); + LOCK_FUSD_DEV(fusd_dev); + + /* we're back awake! --see if a signal woke us up */ + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + } + + /* is this a header read or data read? */ + if (!msg_out->peeked) { + /* this is a header read (first read) */ + retval = fusd_read_header(user_buffer, user_length, &msg_out->fusd_msg); + + /* is there data? if so, make sure next read gets data. if not, + * make sure message is dequeued now.*/ + if (msg_out->fusd_msg.datalen) { + msg_out->peeked = 1; + dequeue = 0; + } else { + dequeue = 1; + } + } else { + /* this is a data read (second read) */ + retval = fusd_read_data(user_buffer, user_length, &msg_out->fusd_msg); + dequeue = 1; /* message should be dequeued */ + } + + /* if this message is done, take it out of the outgoing queue */ + if (dequeue) { + if (fusd_dev->msg_tail == fusd_dev->msg_head) + fusd_dev->msg_tail = fusd_dev->msg_head = NULL; + else + fusd_dev->msg_head = msg_out->next; + FREE_FUSD_MSGC(msg_out); + } + + out: + UNLOCK_FUSD_DEV(fusd_dev); + return retval; + + zombie_dev: + invalid_dev: + RDEBUG(2, "got read on /dev/fusd for unknown device!"); + return -EPIPE; +} + + +/* a poll on /dev/fusd itself (the control channel) */ +STATIC unsigned int fusd_poll(struct file *file, poll_table *wait) +{ + fusd_dev_t *fusd_dev; + GET_FUSD_DEV(file->private_data, fusd_dev); + + poll_wait(file, &fusd_dev->dev_wait, wait); + + if (fusd_dev->msg_head != NULL) { + return POLLIN | POLLRDNORM; + } + + invalid_dev: + return 0; +} + + +STATIC struct file_operations fusd_fops = { + owner: THIS_MODULE, + open: fusd_open, + read: fusd_read, + write: fusd_write, + writev: fusd_writev, + release: fusd_release, + poll: fusd_poll, +}; + + + +/*************************************************************************/ + +typedef struct fusd_status_state { + int binary_status; + int need_new_status; + char *curr_status; + int curr_status_len; + int last_version_seen; +} fusd_statcontext_t; + +/* open() called on /dev/fusd/status */ +STATIC int fusd_status_open(struct inode *inode, struct file *file) +{ + int error = 0; + fusd_statcontext_t *fs; + + //MOD_INC_USE_COUNT; + + if ((fs = KMALLOC(sizeof(fusd_statcontext_t), GFP_KERNEL)) == NULL) { + RDEBUG(1, "yikes! kernel can't allocate memory"); + error = -ENOMEM; + goto out; + } + + memset(fs, 0, sizeof(fusd_statcontext_t)); + fs->need_new_status = 1; + file->private_data = (void *) fs; + + out: + //if (error) + // MOD_DEC_USE_COUNT; + return error; +} + +/* close on /dev/fusd_status */ +STATIC int fusd_status_release(struct inode *inode, struct file *file) +{ + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + + if (fs) { + if (fs->curr_status) + KFREE(fs->curr_status); + KFREE(fs); + } + + //MOD_DEC_USE_COUNT; + return 0; +} + + +/* ioctl() on /dev/fusd/status */ +STATIC int fusd_status_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + + if (!fs) + return -EIO; + + switch (cmd) { + case FUSD_STATUS_USE_BINARY: + fs->binary_status = 1; + return 0; + default: + return -EINVAL; + break; + } +} + + +/* + * maybe_expand_buffer: expand a buffer exponentially as it fills. We + * are given: + * + * - A reference to a pointer to a buffer (buf) + * - A reference to the buffer's current capacity (buf_size) + * - The current amount of buffer space used (len) + * - The amount of space we want to ensure is free in the buffer (space_needed) + * + * If there isn't at least space_needed difference between buf_size + * and len, the existing contents are moved into a larger buffer. + */ +STATIC int maybe_expand_buffer(char **buf, int *buf_size, int len, + int space_needed) +{ + if (*buf_size - len < space_needed) { + char *old_buf = *buf; + + *buf_size *= 2; + *buf = KMALLOC(*buf_size, GFP_KERNEL); + + if (*buf != NULL) + memmove(*buf, old_buf, len); + KFREE(old_buf); + if (*buf == NULL) { + RDEBUG(1, "out of memory!"); + return -1; + } + } + return 0; +} + + + +/* Build a text buffer containing current fusd status. */ +STATIC void fusd_status_build_text(fusd_statcontext_t *fs) +{ + int buf_size = 512; + char *buf = KMALLOC(buf_size, GFP_KERNEL); + int len = 0, total_clients = 0, total_files = 0; + struct list_head *tmp; + + if (buf == NULL) { + RDEBUG(1, "fusd_status_build: out of memory!"); + return; + } + + len += snprintf(buf + len, buf_size - len, + " PID Open Name\n" + "------ ---- -----------------\n"); + + down(&fusd_devlist_sem); + list_for_each(tmp, &fusd_devlist_head) { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + + if (!d) + continue; + + /* Possibly expand the buffer if we need more space */ + if (maybe_expand_buffer(&buf, &buf_size, len, FUSD_MAX_NAME_LENGTH+120) < 0) + goto out; + + len += snprintf(buf + len, buf_size - len, + "%6d %4d %s%s\n", d->pid, d->num_files, + d->zombie ? "<zombie>" : "", NAME(d)); + + total_files++; + total_clients += d->num_files; + } + + len += snprintf(buf + len, buf_size - len, + "\nFUSD $Revision: 1.97-kor-hacked-11 $ - %d devices used by %d clients\n", + total_files, total_clients); + + out: + fs->last_version_seen = last_version; + up(&fusd_devlist_sem); + + if (fs->curr_status) + KFREE(fs->curr_status); + + fs->curr_status = buf; + fs->curr_status_len = len; + fs->need_new_status = 0; +} + + +/* Build the binary version of status */ +STATIC void fusd_status_build_binary(fusd_statcontext_t *fs) +{ + int buf_size = 512; + char *buf = KMALLOC(buf_size, GFP_KERNEL); + int len = 0, i = 0; + struct list_head *tmp; + fusd_status_t *s; + + if (buf == NULL) { + RDEBUG(1, "out of memory!"); + return; + } + + down(&fusd_devlist_sem); + list_for_each(tmp, &fusd_devlist_head) { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + + if (!d) + continue; + + /* Possibly expand the buffer if we need more space */ + if (maybe_expand_buffer(&buf, &buf_size, len, sizeof(fusd_status_t)) < 0) + goto out; + + s = &((fusd_status_t *) buf)[i]; + + /* construct this status entry */ + memset(s, 0, sizeof(fusd_status_t)); + strncpy(s->name, NAME(d), FUSD_MAX_NAME_LENGTH); + s->zombie = d->zombie; + s->pid = d->pid; + s->num_open = d->num_files; + + i++; + len += sizeof(fusd_status_t); + } + + out: + fs->last_version_seen = last_version; + up(&fusd_devlist_sem); + + if (fs->curr_status) + KFREE(fs->curr_status); + + fs->curr_status = buf; + fs->curr_status_len = len; + fs->need_new_status = 0; +} + + + +STATIC ssize_t fusd_status_read(struct file *file, + char *user_buffer, /* The buffer to fill with data */ + size_t user_length, /* The length of the buffer */ + loff_t *offset) /* Our offset in the file */ +{ + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + + if (!fs) + return -EIO; + + /* create a new status page, if we aren't in the middle of one */ + if (fs->need_new_status) { + if (fs->binary_status) + fusd_status_build_binary(fs); + else + fusd_status_build_text(fs); + } + + /* return EOF if we're at the end */ + if (fs->curr_status == NULL || fs->curr_status_len == 0) { + fs->need_new_status = 1; + return 0; + } + + /* return only as much data as we have */ + if (fs->curr_status_len < user_length) + user_length = fs->curr_status_len; + if (copy_to_user(user_buffer, fs->curr_status, user_length)) + return -EFAULT; + + /* update fs, so we don't return the same data next time */ + fs->curr_status_len -= user_length; + if (fs->curr_status_len) + memmove(fs->curr_status, fs->curr_status + user_length, fs->curr_status_len); + else { + KFREE(fs->curr_status); + fs->curr_status = NULL; + } + + return user_length; +} + + +/* a poll on /dev/fusd itself (the control channel) */ +STATIC unsigned int fusd_status_poll(struct file *file, poll_table *wait) +{ + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + + poll_wait(file, &new_device_wait, wait); + + if (fs->last_version_seen < last_version) + return POLLIN | POLLRDNORM; + else + return 0; +} + + +STATIC struct file_operations fusd_status_fops = { + owner: THIS_MODULE, + open: fusd_status_open, + ioctl: fusd_status_ioctl, + read: fusd_status_read, + release: fusd_status_release, + poll: fusd_status_poll, +}; + + +/*************************************************************************/ + + +STATIC int init_fusd(void) +{ + int retval; + +#ifdef CONFIG_FUSD_MEMDEBUG + if ((retval = fusd_mem_init()) < 0) + return retval; +#endif + + + printk(KERN_INFO + "fusd: starting, $Revision: 1.97-kor-hacked-11 $, $Date: 2003/07/11 22:29:39 $"); +#ifdef CVSTAG + printk(", release %s", CVSTAG); +#endif +#ifdef CONFIG_FUSD_DEBUG + printk(", debuglevel=%d\n", fusd_debug_level); +#else + printk(", debugging messages disabled\n"); +#endif + + fusd_control_device = NULL; + fusd_status_device = NULL; + + fusd_class = class_create(THIS_MODULE, "fusd"); + if(IS_ERR(fusd_class)) + { + retval = PTR_ERR(fusd_class); + printk(KERN_ERR "class_create failed status: %d\n", retval); + goto fail0; + } + + control_id = 0; + + if((retval = alloc_chrdev_region(&control_id, 0, 1, FUSD_CONTROL_FILENAME)) < 0) + { + printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", retval); + goto fail1; + } + + fusd_control_device = cdev_alloc(); + if(fusd_control_device == NULL) + { + printk(KERN_ERR "cdev-alloc failed\n"); + retval = -ENOMEM; + goto fail3; + } + + fusd_control_device->owner = THIS_MODULE; + fusd_control_device->ops = &fusd_fops; + kobject_set_name(&fusd_control_device->kobj, FUSD_CONTROL_FILENAME); + + printk(KERN_ERR "cdev control id: %d\n", control_id); + if((retval = cdev_add(fusd_control_device, control_id, 1)) < 0) + { + printk(KERN_ERR "cdev_add failed status: %d\n", retval); + kobject_put(&fusd_control_device->kobj); + goto fail4; + } + + fusd_control_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, control_id, NULL, "control"); + if(fusd_control_class_device == NULL) + { + retval = PTR_ERR(fusd_control_class_device); + printk("class_device_create failed status: %d\n", retval); + goto fail5; + } + + status_id = 0; + + if((retval = alloc_chrdev_region(&status_id, 0, 1, FUSD_STATUS_FILENAME)) < 0) + { + printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", retval); + goto fail6; + } + + fusd_status_device = cdev_alloc(); + if(fusd_status_device == NULL) + { + retval = -ENOMEM; + goto fail8; + } + + fusd_status_device->owner = THIS_MODULE; + fusd_status_device->ops = &fusd_status_fops; + kobject_set_name(&fusd_status_device->kobj, FUSD_STATUS_FILENAME); + + if((retval = cdev_add(fusd_status_device, status_id, 1)) < 0) + { + printk(KERN_ERR "cdev_add failed status: %d\n", retval); + kobject_put(&fusd_status_device->kobj); + goto fail9; + } + + fusd_status_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, status_id, NULL, "status"); + if(fusd_status_class_device == NULL) + { + printk(KERN_ERR "class_device_create failed status: %d\n", retval); + retval = PTR_ERR(fusd_status_class_device); + goto fail10; + } + + RDEBUG(1, "registration successful"); + return 0; + +fail10: + cdev_del(fusd_status_device); +fail9: + kfree(fusd_status_device); +fail8: + + //fail7: + unregister_chrdev_region(status_id, 1); +fail6: + class_device_destroy(fusd_class, control_id); +fail5: + cdev_del(fusd_control_device); +fail4: + kfree(fusd_control_device); +fail3: + + //fail2: + unregister_chrdev_region(control_id, 1); + +fail1: + class_destroy(fusd_class); +fail0: + return retval; +} + +STATIC void cleanup_fusd(void) +{ + RDEBUG(1, "cleaning up"); + + class_device_destroy(fusd_class, status_id); + class_device_destroy(fusd_class, control_id); + + cdev_del(fusd_control_device); + cdev_del(fusd_status_device); + + class_destroy(fusd_class); + +#ifdef CONFIG_FUSD_MEMDEBUG + fusd_mem_cleanup(); +#endif +} + +module_init(init_fusd); +module_exit(cleanup_fusd); diff --git a/libfusd/Makefile b/libfusd/Makefile new file mode 100755 index 0000000..c53d8b9 --- /dev/null +++ b/libfusd/Makefile @@ -0,0 +1,30 @@ +SRC = libfusd.c +OBJ = libfusd.o +TARGETS = libfusd.a libfusd.so.0.0 + +default: $(TARGETS) + +install: $(TARGETS) + $(INSTALL) -d -m 0755 $(LIBDIR) + $(INSTALL) -m 0755 $(TARGETS) $(LIBDIR) + /sbin/ldconfig + $(INSTALL) -d -m 0755 $(INCDIR) + $(INSTALL) -m 0755 ../include/*.h $(INCDIR) + +clean: + rm -f *.o *.so *.so.* *.a *.d *.d.* gmon.out *~ + +$(TARGETS): + $(MAKE) target CFLAGS='-g -O2 $(SCF) $(GCF)' + +target: $(OBJ) + $(LD) $(OBJ) $(SOLDFLAGS) -o libfusd.so.0.0 $(SLF) + $(AR) -cr libfusd.a $(OBJ) + +%.d: %.c + $(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$ + +ifeq ($(MAKECMDGOALS),target) +include $(SRC:.c=.d) +endif + diff --git a/libfusd/libfusd.c b/libfusd/libfusd.c new file mode 100755 index 0000000..fc6da7b --- /dev/null +++ b/libfusd/libfusd.c @@ -0,0 +1,687 @@ +/* + * + * Copyright (c) 2003 The Regents of the University of California. All + * rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* + * fusd userspace library: functions that know how to properly talk + * to the fusd kernel module + * + * authors: jelson and girod + * + * $Id: libfusd.c,v 1.61 2003/07/11 22:29:39 cerpa Exp $ + */ + +char libfusd_c_id[] = "$Id: libfusd.c,v 1.61 2003/07/11 22:29:39 cerpa Exp $"; + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <time.h> + +#include "fusd.h" +#include "fusd_msg.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* maximum number of messages processed by a single call to fusd_dispatch */ +#define MAX_MESSAGES_PER_DISPATCH 40 + +/* used for fusd_run */ +static fd_set fusd_fds; + +/* default prefix of devices (often "/dev/") */ +char *dev_root = NULL; + +/* + * fusd_fops_set is an array that keeps track of the file operations + * struct for each fusd fd. + */ +static fusd_file_operations_t fusd_fops_set[FD_SETSIZE]; +fusd_file_operations_t null_fops = { NULL }; + +/* + * accessor macros + */ +#define FUSD_GET_FOPS(fd) \ + (fusd_fops_set + (fd)) + +#define FUSD_SET_FOPS(fd,fi) \ + (fusd_fops_set[(fd)]=(*fi)) + +#define FUSD_FD_VALID(fd) \ + (((fd)>=0) && \ + ((fd)<FD_SETSIZE) && \ + (memcmp(FUSD_GET_FOPS(fd), &null_fops, sizeof(fusd_file_operations_t)))) + + +/* + * fusd_init + * + * this is called automatically before the first + * register call + */ +void fusd_init() +{ + static int fusd_init_needed = 1; + + if (fusd_init_needed) { + int i; + + fusd_init_needed = 0; + + for (i = 0; i < FD_SETSIZE; i++) + FUSD_SET_FOPS(i, &null_fops); + FD_ZERO(&fusd_fds); + + dev_root = DEFAULT_DEV_ROOT; + } +} + + +int fusd_register(const char *name, const char* clazz, const char* devname, mode_t mode, void *device_info, + struct fusd_file_operations *fops) +{ + int fd = -1, retval = 0; + fusd_msg_t message; + + /* need initialization? */ + fusd_init(); + + /* make sure the name is valid and we have a valid set of fops... */ + if (name == NULL || fops == NULL) { + fprintf(stderr, "fusd_register: invalid name or fops argument\n"); + retval = -EINVAL; + goto done; + } + + /* + * convenience: if the first characters of the name you're trying + * to register are SKIP_PREFIX (usually "/dev/"), skip over them. + */ + if (dev_root != NULL && strlen(name) > strlen(dev_root) && + !strncmp(name, dev_root, strlen(dev_root))) { + name += strlen(dev_root); + } + + if (strlen(name) > FUSD_MAX_NAME_LENGTH) { + fprintf(stderr, "name '%s' too long, sorry :(", name); + retval = -EINVAL; + goto done; + } + + /* open the fusd control channel */ + if ((fd = open(FUSD_CONTROL_DEVNAME, O_RDWR | O_NONBLOCK)) < 0) { + + /* if the problem is that /dev/fusd does not exist, return the + * message "Package not installed", which is hopefully more + * illuminating than "no such file or directory" */ + if (errno == ENOENT) { + fprintf(stderr, "libfusd: %s does not exist; ensure FUSD's kernel module is installed\n", + FUSD_CONTROL_DEVNAME); + retval = -ENOPKG; + } else { + perror("libfusd: trying to open FUSD control channel"); + retval = -errno; + } + goto done; + } + + /* fd in use? */ + if (FUSD_FD_VALID(fd)) { + retval = -EBADF; + goto done; + } + + /* set up the message */ + memset(&message, 0, sizeof(message)); + message.magic = FUSD_MSG_MAGIC; + message.cmd = FUSD_REGISTER_DEVICE; + message.datalen = 0; + strcpy(message.parm.register_msg.name, name); + strcpy(message.parm.register_msg.clazz, clazz); + strcpy(message.parm.register_msg.devname, devname); + message.parm.register_msg.mode = mode; + message.parm.register_msg.device_info = device_info; + + /* make the request */ + if (write(fd, &message, sizeof(fusd_msg_t)) < 0) { + retval = -errno; + goto done; + } + + /* OK, store the new file state */ + FUSD_SET_FOPS(fd, fops); + FD_SET(fd, &fusd_fds); + + /* success! */ + done: + if (retval < 0) { + if (fd >= 0) + close(fd); + errno = -retval; + retval = -1; + } else { + errno = 0; + retval = fd; + } + + return retval; +} + + +int fusd_unregister(int fd) +{ + if (FUSD_FD_VALID(fd)) { + /* clear fd location */ + FUSD_SET_FOPS(fd, &null_fops); + FD_CLR(fd, &fusd_fds); + /* close */ + return close(fd); + } + + else { + errno = EBADF; + return -1; + } +} + + +/* + * fusd_run: a convenience function for automatically running a FUSD + * driver, for drivers that don't want to manually select on file + * descriptors and call fusd_dispatch. This function will + * automatically select on all devices the user has registered and + * call fusd_dispatch on any one that becomes readable. + */ +void fusd_run(void) +{ + fd_set tfds; + int status; + int maxfd; + int i; + + /* locate maxmimum fd in use */ + for (maxfd=0, i=0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, &fusd_fds)) { + maxfd = i; + } + } + maxfd++; + + + while (1) { + /* select */ + memmove(&tfds, &fusd_fds, sizeof(fd_set)); + status = select(maxfd, &tfds, NULL, NULL, NULL); + + /* error? */ + if (status < 0) { + perror("libfusd: fusd_run: error on select"); + continue; + } + + /* readable? */ + for (i = 0; i < maxfd; i++) + if (FD_ISSET(i, &tfds)) + fusd_dispatch(i); + } +} + + +/************************************************************************/ + + +/* reads a fusd kernel-to-userspace message from fd, and puts a + * fusd_msg into the memory pointed to by msg (we assume we are passed + * a buffer managed by the caller). if there is a data portion to the + * message (msg->datalen > 0), we allocate memory for it, set data to + * point to that memory. the returned data pointer must also be + * managed by the caller. */ +static int fusd_get_message(int fd, fusd_msg_t *msg) +{ + /* read the header part into the kernel */ + if (read(fd, msg, sizeof(fusd_msg_t)) < 0) { + if (errno != EAGAIN) + perror("error talking to FUSD control channel on header read"); + return -errno; + } + msg->data = NULL; /* pointers in kernelspace have no meaning */ + + if (msg->magic != FUSD_MSG_MAGIC) { + fprintf(stderr, "libfusd magic number failure\n"); + return -EINVAL; + } + + /* if there's a data part to the message, read it from the kernel. */ + if (msg->datalen) { + if ((msg->data = malloc(msg->datalen + 1)) == NULL) { + fprintf(stderr, "libfusd: can't allocate memory\n"); + return -ENOMEM; /* this is bad, we are now unsynced */ + } + + if (read(fd, msg->data, msg->datalen) < 0) { + perror("error talking to FUSD control channel on data read"); + free(msg->data); + msg->data = NULL; + return -EIO; + } + + /* For convenience, we now ensure that the byte *after* the buffer + * is set to 0. (Note we malloc'd one extra byte above.) */ + msg->data[msg->datalen] = '\0'; + } + + return 0; +} + + +/* + * fusd_fdset_add: given an FDSET and "max", add the currently valid + * FUSD fds to the set and update max accordingly. + */ +void fusd_fdset_add(fd_set *set, int *max) +{ + int i; + + for (i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, &fusd_fds)) { + FD_SET(i, set); + if (i > *max) { + *max = i; + } + } + } +} + + + +/* + * fusd_dispatch_fdset: given an fd_set full of descriptors, call + * fusd_dispatch on every descriptor in the set which is a valid FUSD + * fd. + */ +void fusd_dispatch_fdset(fd_set *set) +{ + int i; + + for (i = 0; i < FD_SETSIZE; i++) + if (FD_ISSET(i, set) && FD_ISSET(i, &fusd_fds)) + fusd_dispatch(i); +} + + +/* + * fusd_dispatch_one() -- read a single kernel-to-userspace message + * from fd, then call the appropriate userspace callback function, + * based on the message that was read. finally, return the result + * back to the kernel, IF the return value from the callback is not + * FUSD_NOREPLY. + * + * On success, returns 0. + * On failure, returns a negative number indicating the errno. + */ +static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops) +{ + fusd_file_info_t *file = NULL; + fusd_msg_t *msg = NULL; + int driver_retval = 0; /* returned to the FUSD driver */ + int user_retval = 0; /* returned to the user who made the syscall */ + + /* check for valid, look up ops */ + if (fops == NULL) { + fprintf(stderr, "fusd_dispatch: no fops provided!\n"); + driver_retval = -EBADF; + goto out_noreply; + } + + /* allocate memory for fusd_msg_t */ + if ((msg = malloc(sizeof(fusd_msg_t))) == NULL) { + driver_retval = -ENOMEM; + fprintf(stderr, "libfusd: can't allocate memory\n"); + goto out_noreply; + } + memset(msg, '\0', sizeof(fusd_msg_t)); + + /* read header and data, if it's there */ + if ((driver_retval = fusd_get_message(fd, msg)) < 0) + goto out_noreply; + + /* allocate file info struct */ + file = malloc(sizeof(fusd_file_info_t)); + if (NULL == file) { + fprintf(stderr, "libfusd: can't allocate memory\n"); + driver_retval = -ENOMEM; + goto out_noreply; + } + + /* fill the file info struct */ + memset(file, '\0', sizeof(fusd_file_info_t)); + file->fd = fd; + file->device_info = msg->parm.fops_msg.device_info; + file->private_data = msg->parm.fops_msg.private_info; + file->flags = msg->parm.fops_msg.flags; + file->pid = msg->parm.fops_msg.pid; + file->uid = msg->parm.fops_msg.uid; + file->gid = msg->parm.fops_msg.gid; + file->fusd_msg = msg; + + /* right now we only handle fops requests */ + if (msg->cmd != FUSD_FOPS_CALL && msg->cmd != FUSD_FOPS_NONBLOCK && + msg->cmd != FUSD_FOPS_CALL_DROPREPLY) { + fprintf(stderr, "libfusd: got unknown msg->cmd from kernel\n"); + user_retval = -EINVAL; + goto send_reply; + } + + /* dispatch on operation type */ + user_retval = -ENOSYS; + switch (msg->subcmd) { + case FUSD_OPEN: + if (fops && fops->open) + user_retval = fops->open(file); + break; + case FUSD_CLOSE: + if (fops && fops->close) + user_retval = fops->close(file); + break; + case FUSD_READ: + /* allocate a buffer and make the call */ + if (fops && fops->read) { + if ((msg->data = malloc(msg->parm.fops_msg.length)) == NULL) { + user_retval = -ENOMEM; + fprintf(stderr, "libfusd: can't allocate memory\n"); + } else { + msg->datalen = msg->parm.fops_msg.length; + user_retval = fops->read(file, msg->data, msg->datalen, + &msg->parm.fops_msg.offset); + } + } + break; + case FUSD_WRITE: + if (fops && fops->write) + user_retval = fops->write(file, msg->data, msg->datalen, + &msg->parm.fops_msg.offset); + break; + case FUSD_MMAP: + if (fops && fops->mmap) + { + user_retval = fops->mmap(file, msg->parm.fops_msg.offset, msg->parm.fops_msg.length, msg->parm.fops_msg.flags, + &msg->parm.fops_msg.arg.ptr_arg, &msg->parm.fops_msg.length); + } + break; + case FUSD_IOCTL: + if (fops && fops->ioctl) { + /* in the case of an ioctl read, allocate a buffer for the + * driver to write to, IF there isn't already a buffer. (there + * might already be a buffer if this is a read+write) */ + if ((_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ) && + msg->data == NULL) { + msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd); + if ((msg->data = malloc(msg->datalen)) == NULL) { + user_retval = -ENOMEM; + break; + } + } + if (msg->data != NULL) + user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd, msg->data); + else + user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd, + (void *) msg->parm.fops_msg.arg.ptr_arg); + } + break; + + case FUSD_POLL_DIFF: + /* This callback requests notification when an event occurs on a file, + * e.g. becoming readable or writable */ + if (fops && fops->poll_diff) + user_retval = fops->poll_diff(file, msg->parm.fops_msg.cmd); + break; + + case FUSD_UNBLOCK: + /* This callback is called when a system call is interrupted */ + if (fops && fops->unblock) + user_retval = fops->unblock(file); + break; + + default: + fprintf(stderr, "libfusd: Got unsupported operation\n"); + user_retval = -ENOSYS; + break; + } + + goto send_reply; + + + /* out_noreply is only used for handling errors */ + out_noreply: + if (msg->data != NULL) + free(msg->data); + if (msg != NULL) + free(msg); + goto done; + + /* send_reply is only used for success */ + send_reply: + if (-user_retval <= 0xff) { + /* 0xff is the maximum legal return value (?) - return val to user */ + driver_retval = fusd_return(file, user_retval); + } else { + /* if we got a FUSD_NOREPLY, don't free the msg structure */ + driver_retval = 0; + } + + /* this is common to both errors and success */ + done: + if (driver_retval < 0) { + errno = -driver_retval; + driver_retval = -1; + } + return driver_retval; +} + + +/* fusd_dispatch is now a wrapper around fusd_dispatch_one that calls + * it repeatedly, until it fails. this helps a lot with bulk data + * transfer since there is no intermediate select in between the + * reads. (the kernel module helps by running the user process in + * between). + * + * This function now prints an error to stderr in case of error, + * instead of returning a -1. + */ +void fusd_dispatch(int fd) +{ + int retval, num_dispatches = 0; + fusd_file_operations_t *fops = NULL; + + /* make sure we have a valid FD, and get its fops structure */ + if (!FUSD_FD_VALID(fd)) { + errno = EBADF; + retval = -1; + goto out; + } + fops = FUSD_GET_FOPS(fd); + + /* now keep dispatching until a dispatch returns an error */ + do { + retval = fusd_dispatch_one(fd, fops); + + if (retval >= 0) + num_dispatches++; + } while (retval >= 0 && num_dispatches <= MAX_MESSAGES_PER_DISPATCH); + + /* if we've dispatched at least one message successfully, and then + * stopped because of EAGAIN - do not report an error. this is the + * common case. */ + if (num_dispatches > 0 && errno == EAGAIN) { + retval = 0; + errno = 0; + } + + out: + if (retval < 0 && errno != EPIPE) + fprintf(stderr, "libfusd: fusd_dispatch error on fd %d: %m\n", fd); +} + + +/* + * fusd_destroy destroys all state associated with a fusd_file_info + * pointer. (It is implicitly called by fusd_return.) If a driver + * saves a fusd_file_info pointer by calling -FUSD_NOREPLY in order to + * block a read, but gets a "close" request on the file before the + * pointer is returned with fusd_return, it should be thrown away + * using fusd_destroy. + */ +void fusd_destroy(struct fusd_file_info *file) +{ + if (file == NULL) + return; + + if (file->fusd_msg->data != NULL) + free(file->fusd_msg->data); + free(file->fusd_msg); + free(file); +} + + +/* + * construct a user-to-kernel message in reply to a file function + * call. + * + * On success, returns 0. + * On failure, returns a negative number indicating the errno. + */ +int fusd_return(fusd_file_info_t *file, ssize_t retval) +{ + fusd_msg_t *msg = NULL; + int fd; + int driver_retval = 0; + struct iovec iov[2]; + + if (file == NULL) { + fprintf(stderr, "fusd_return: NULL file\n"); + return -EINVAL; + } + + fd = file->fd; + if (!FUSD_FD_VALID(fd)) { + fprintf(stderr, "fusd_return: badfd (fd %d)\n", fd); + return -EBADF; + } + + if ((msg = file->fusd_msg) == NULL) { + fprintf(stderr, "fusd_return: fusd_msg is gone\n"); + return -EINVAL; + } + + /* if this was a "DONTREPLY" message, just free the struct */ + if (msg->cmd == FUSD_FOPS_CALL_DROPREPLY) + goto free_memory; + + /* do we copy data back to kernel? how much? */ + switch(msg->subcmd) { + case FUSD_READ: + /* these operations can return data to userspace */ + if (retval > 0) { + msg->datalen = MIN(retval, msg->parm.fops_msg.length); + retval = msg->datalen; + } else { + msg->datalen = 0; + } + break; + case FUSD_IOCTL: + /* ioctl CAN (in read mode) return data to userspace */ + if ((retval == 0) && + (_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ)) + msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd); + else + msg->datalen = 0; + break; + default: + /* open, close, write, etc. do not return data */ + msg->datalen = 0; + break; + } + + /* fill the file info struct */ + msg->cmd++; /* change FOPS_CALL to FOPS_REPLY; NONBLOCK to NONBLOCK_REPLY */ + msg->parm.fops_msg.retval = retval; + msg->parm.fops_msg.device_info = file->device_info; + msg->parm.fops_msg.private_info = file->private_data; + msg->parm.fops_msg.flags = file->flags; + /* pid is NOT copied back. */ + + /* send message to kernel */ + if (msg->datalen && msg->data != NULL) { + iov[0].iov_base = msg; + iov[0].iov_len = sizeof(fusd_msg_t); + iov[1].iov_base = msg->data; + iov[1].iov_len = msg->datalen; + driver_retval = writev(fd, iov, 2); + } + else { + driver_retval = write(fd, msg, sizeof(fusd_msg_t)); + } + + free_memory: + fusd_destroy(file); + + if (driver_retval < 0) + return -errno; + else + return 0; +} + + +/* returns static string representing the flagset (e.g. RWE) */ +#define RING 5 +char *fusd_unparse_flags(int flags) +{ + static int i = 0; + static char ringbuf[RING][5]; + char *s = ringbuf[i]; + i = (i + 1) % RING; + + sprintf(s, "%c%c%c", + (flags & FUSD_NOTIFY_INPUT)?'R':'-', + (flags & FUSD_NOTIFY_OUTPUT)?'W':'-', + (flags & FUSD_NOTIFY_EXCEPT)?'E':'-'); + + return s; +} +#undef RING diff --git a/make.include b/make.include new file mode 100644 index 0000000..3e59554 --- /dev/null +++ b/make.include @@ -0,0 +1,149 @@ + +# auto-dependency generation makefile + + +#### Default values + +SRCEXTENSIONS := c C cpp +CC := gcc +CPP := g++ +LD := ld +AR := ar + +#### build object directory token + +CPU := $(shell uname -m) +OS := $(shell uname -s | tr '[A-Z]' '[a-z]') + +DEFAULT_ARCH := $(CPU)-$(OS) + +ifeq ($(strip $(ARCH)),) + ARCH := $(DEFAULT_ARCH) +endif + +OBJTOKEN := obj.$(ARCH) + +# +# Under most circumstances, paths are simple +# + +ifeq ($(POSTROOT),..) + MODPATH := . + OBJDIR := $(OBJTOKEN) +else + MODPATH := $(POSTROOT)/$(MODULENAME) + OBJDIR := $(MODPATH)/$(OBJTOKEN) +endif + + +# +# Directories +# + +MODLIBS := \ + -L$(OBJDIR) \ + $(foreach dir, $(MODULES), -L$(POSTROOT)/$(dir)/$(OBJTOKEN)) +MODINCLUDES := \ + -I$(MODPATH)/include \ + $(foreach dir, $(MODULES), -I$(POSTROOT)/$(dir)/include) +ALLTARGETS := \ + $(foreach targ, $(TARGETS), $(OBJDIR)/$(targ)) +VPATH := \ + $(MODPATH)/include \ + $(foreach dir, $(SRCDIRS), $(MODPATH)/$(dir)) \ + $(foreach dir, $(MODULES), $(POSTROOT)/$(dir)/include) + + +#### include paths + +LIBPATH := $(MODLIBS) +INCLUDEPATH += -I. -Iinclude $(MODINCLUDES) +KCFLAGS = -O2 \ + -Wall -Werror -Wstrict-prototypes \ + -fno-strict-aliasing -fomit-frame-pointer \ + -DMODULE -D__KERNEL__ + +CFLAGS := -fPIC -Wall -O2 -g +CCFLAGS := -Werror +CPPFLAGS := -ftemplate-depth-30 + +#### Architecture deps + +KERNEL_INCLUDE := $(KERNEL_HOME)/include +BINSTRIP := strip + +KCFLAGS += $(INCLUDEPATH) +CFLAGS += $(INCLUDEPATH) $(LIBPATH) + +CCFLAGS += $(CFLAGS) +CPPFLAGS += $(CFLAGS) + +# +# targets +# + +default: $(ALLTARGETS) + +#################################################### + + +# +# Dependency generation +# + + +# Get list of all source files +SOURCES := \ + $(notdir $(wildcard \ + $(foreach dir, $(SRCDIRS), \ + $(foreach ext, $(SRCEXTENSIONS), $(dir)/*.$(ext))))) + +# Convert all .c, .cpp, .C to .d +SRC_AND_DEPENDS := $(foreach ext, $(SRCEXTENSIONS),\ + $(patsubst %.$(ext),%.d,$(SOURCES))) + +DEPENDS := $(foreach file, $(filter %.d,$(SRC_AND_DEPENDS)), $(OBJDIR)/$(file)) + + + +BASE = $(subst /,\/,$*) +ODIR = $(subst /,\/,$(OBJDIR)) + +# This magic is from the 'make' manual (with mods by jelson) +$(OBJDIR)/%.d: %.c + @mkdir -p $(OBJDIR) + set -e; $(CC) -MM -I$(KERNEL_INCLUDE) $(CFLAGS) $< \ + | sed 's/\($(BASE)\)\.o[ :]*/$(ODIR)\/$(BASE).o $(ODIR)\/$(BASE).d : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +$(OBJDIR)/%.d: %.C + @mkdir -p $(OBJDIR) + set -e; $(CC) -MM $(CPPFLAGS) $< \ + | sed 's/\($(BASE)\)\.o[ :]*/$(ODIR)\/$(BASE).o $(ODIR)\/$(BASE).d : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +$(OBJDIR)/%.d: %.cpp + @mkdir -p $(OBJDIR) + set -e; $(CC) -MM $(CPPFLAGS) $< \ + | sed 's/\($(BASE)\)\.o[ :]*/$(ODIR)\/$(BASE).o $(ODIR)\/$(BASE).d : /g' > $@; \ + [ -s $@ ] || rm -f $@ + + +# +# Rules +# + +$(OBJDIR)/%.o: %.cpp + $(CPP) $(CPPFLAGS) $< -c -o $@ + +$(OBJDIR)/%.o: %.C + $(CPP) $(CPPFLAGS) $< -c -o $@ + +$(OBJDIR)/%.o: %.c + $(CC) $(CCFLAGS) $< -c -o $@ + +clean: + rm -f $(ALLTARGETS) $(OBJDIR)/*.[oa] $(OBJDIR)/*.so.* $(DEPENDS) + + +include $(DEPENDS)

    1uH{7G?b3{tG?luQ zW8phAR7rm(V{BCZn<)IwvO~xPYt6!OSvBLY4nPR2_!iK#kqzkqc`3TOszSOXGKN?; zaavVOGS)0`h1DkVFa}ZDD>qnX2vQnukHk8xJ$fD1RByE}_aD;t&5ub+mKcf+uI%yIDB(un(&Ty*_xj z`KkuaOGn?X^hRdZ4W_bg(C@!ia2qW^mN&lynz#_XXQfMVy2SD1a1Pt~7o^=^Roq2h z-5Ur;*Hr;s-{mdlL{wFVHV7@QyyV-33Ojz~v+5C6V9fA~=xA_M__DQ-Z63XOZ2hi+ zR|K-lJnfB00CBTicF7pin(-TiUQUYqXS6c|-s@!|(>wr)i1L zdved|7Q=#wrL00nNewlJU(RdMr=FSgoos*Nx&ZG4d)flu6pYg8OTFGv#_Lra{O_lq z6y6-5@G+PU9t6!{BaJ%e6h_gC6|ThEBGi&qQ~fHXP(M(ka?7VFA7bfoIh!5yU_jme z^zi=mz?-XwbYd^B`zs!#lPxJ^%s~$Zg05|jsAJ_d%ca2bC7WDl>-pS|=%egk@i5*)TaPA`O|PC8#7NuH8J7nQ zb6Kqg=ib)QUDgja8RRU6SC)?F-W4Slmh|2(dxWmxX;}84Bsf*goUAlWuO+J>FQsho zq8=z+JKVS?1P~Sxpudd2RX4SzNv|Bv*R~Vfs!IZK0E+v;_5~l3KDIl~jW~Gvf#?L= z#hm_@|eOgm7}o!yo!uDN3xw=Wi&auu)GNh*P{e?!qZZk-G|EZs*FS zx~K`m*F$;sqXtj+7$(_e8|GmjR1w@>b9Kv_mfLFLUEnYQQvtHDaq!AUJ(&Q7*WW^Ib5a^e}O;+CCJYxQ!&tHhrb*xyLe&ni|u%KB+ z01{RX%!@d5QOnXWdt~+{m{-qB=PpfU+W$tZTDIG zo?kaM{<*#wztg0m2*j&{3Tz`)Jfs96ZK`r$r7Qh3`-BKVrQt;hKBhiBn=g0Xm%5?v zjq9b$__1JN<*j5!e4=2|PTmQKK(Fzelzr}_++$={Pt8*(sa6-rWAE?fQ>$bAK56Zx zO}gd9sm4_d(UtRCMZ1r2rS-;C^L8)R^KR>6AbD)g@jhk0=6mZ# zf`n0@K;M?~WJOp)cp-t-XuW*b_QAB?qj@xE8O~R&Nu&`KPkI%XL~qNu+`#x_fZJr+%A1a*S`QLWjUG|J_7Y zP;G7#3TX_}V#rG79}&Xg*Sfpsz6+F1-c4MHpTA!7pedVL=qE-2i-I&5rquhL1Zm!Z zVX8Wlu2pCr+KOzbLKkr;W;m*)RWnLu$qKM31n>wt^gbo-J7(f01?-l1Rm$)|ycj$& z0>Te+4JY3;_1uesv@Sefs{Z))D;3_TA-oQhw*}{PO*|@?ty(+Nb=FTCu4SNZT)s;i zie@!uy(jGg{2*3KPCt`ij5*SThKlm)4r_@Fq z9ed&a6cq8K;YR~>x~2hvD052Y%X!&0rjMf&oNHz6LsW=pw?IdI*c5;c_(%UUsL2-p zF-S_J`5jC9)@BsOaPyj*`jr{2%wr>hxe31-IX7w4uQ)=Y)0h|>S`UFUH4DdsV!+ql z%13M_S(H{mVlC=lp(L|9Sw4;Ux0xN;p-Zyzq&mb&GOFqIguBVa6d+E zT=DgDu$j_07tkdF7(@>)XYu*6(vmy!ypUe=119)gVE=nzz?Cp4 zrt^)xw==lWcMm;LH$)imt2`L(?W;5IkH4PurC=gZBu45Yfr1^7?J3E9Ah>FAX8cLv zn5^TgzI<=$F4{zDd*k&41ETM6X6UWSg#Mj_j%q6eCMFgEr^k>a5X7*SY!A zd!w)O^gM|-iaY9G)X6~08vcK9tmcKoRO^RG$AbxnvjYtWux8>i?c`1&mx7r$U%fR7 z6|Lg=)4RWTy}Tju?`NhXnI!-I(<}3!Ylm@#Nq5B;gnIX3rM6hveMK%NRq~;ix+>2( zwJSuit3A05>|}K_cm3U2yg7kx-iuY-^jD7Y?LUfB^;$y1_dMO6+>TjDz=GmS+>PxTu;4>J+!7( z`@r7_B3Qf>dOsRPnOy7BAQORU2My{r&eh;K4wEE>^_UNc|M(++zYxz z8ojWCp46I_6ekDJ)1AV+sl7+&q~UP1EMbY)NXKZ@?SlXPsSW83VgW81cE+qP}nHaqOt zww;{x_j!K0=bZ8XpBLxFz2mMi_Fik(s#R5M&RKJQCbpN6S&gaLJ$zj;O**jK@(*Ra zu=yd8N|U7+c^UcgYETzUPQPM)lok!no;mcxp;M@n`|0I8xFA23<>KFeN&gqCx>ahC zbM%0-rC^{k*gGNMO+(Ae$d+kfm{B^RT_^OulMCz%N7_YAIb#rM7q;dZM~xlk+ZFB@ zmSGpl!zrUI-K69@vORIcNBv@lhv1{zO3NqpIo*a~)!_Tta|K?-4nEYP3<{bp;__%) zqHO33-J8+_W95s*MhG0Gw;pfxi*&=22B=h1hwXu7fFVQty#zEigY?_tZ zrjj1|Z9@<2C2V+zuDvtk@CJ*T%iW%-QElCf+$$;S;Ye18A!2QnsZEY%KCX}e7!in| z(o@chkZ`~JIH>10VY$b$p?am-oNi2E{<&sWamKncULvA&>8*mwg;W#1d~C%m)#ODE zFKF9v%ma<@aAZ^4ahDbg|Hv$Y(Bi@Um*Cch&WKblCBl zU%yeOXxyp3~#xT2PuE)ZBhAhq)_|^M~{tf1_LHo6f23QVc~Po zKF(s(g;qJ@7nIQX$wu3rU%o+U>y9(+2mZmIFHS;SyJ19V1$B#wt-kkeEFG9+3%ezo zqzk(>|MOMzhHAtEAY$IgS(Gi*4uGKh`dKwKiq-v&>8y`e;d_aHG!1^l+czb$3i z^TUGn*!{HT}Uw-_u(6)?t*Vw%v7Ms5p=26S*&QuUEXMMnxU-h1DE#H52 zX2=ya+)nBovF{U_tH&L+(V&!}o;3A-yP0yOjXW=p)O|J6X9{oA6aycZV+w!SmMzqQ z(ihd)D_I{Ef&WGfM!QLs_6t6|+Amm;;r{NUl+!P?fI~`=iu}p?6+&Z1**Nqfb9F4X zAo)%#ifyi+Cy-F8i?u+Gt}Fbd(Ec4RU0S3~*uqssqksHlLDv|6sHQ)Uo`r!bXr~;3 zKCZM_D(nV1#7S`8!bD|)XTCoVRJ1xI-#}Qf=V1Z7wp{3IX>KQTF-9!;*mEkTkHb>) zGHh}zQ1YwNAh%8rUK_{CNI?TXqU=r(0MST&L<fnsi?2e1i#B zB|+>3aX?k!yoR{Fx6~g-LAMaHI97Z*gbxxE0Cw}oH#ROJ2fw|+l{r&?y@UN-;aQEz z_sXjk0ldaeflv+?x1tn7&kyjJ{`A8!)x{y$@PA$-O$cWanpK&+fC}x+t;p%;@EbV+ zZ3u63+Ox<9YaX(YN!&$o;R-M({MZBTNhME_SIDJVU{-WVevW~FS1KU+Z8p7D^v)tHyF6X&R0opSI&!@UV4&x`V}3@ObI)#R}Rp)}H0ltlif zIvHZ_3xf{UopY_6<)5E7nVPtEr54M?ux_l)-xWihq_@20{;Wz8!!Do;>*-Zy2Dq%ZyAdgE-ks4QM|lMd=nI%RLq@cq%dQu7U?R9%1^M#H`BR; z6nJuRmu*NqF7cQ`G4WhC(kJ7c&V$`U&O2-NX5$JFz-h@0wmKxEWEN5UJ$voDNaDnv zg*v=nGB-KKd+c2H!3URebR)a(G`?VRE5t~a%)6`AIkGx-Y?0GbJOy!^r=<@`_-B8b z;m^VsMLFTiKUaV!^H|m+J0a7AEEOZwza(L(=1UT=0cbNW@}Zxl4w`aPVlnO# z(+b&?O9dHg?irowls~*PSSS_@4$M$kFG?1-j@jDNvKQ2>YzDD3h!A6Meh~ZGN}4vr zcDdc~k;;?BQBdg(BjwMVJZ2iDh8kH13+eymjJQRf+G794!jK8-ee1ST2jpMzS@lKl z4_oe_jcHdP&`xQYM|4W<_mZgC-^LPPqk2y=1z7gxKlV ze7!&l6SmbDs-{;m$^IE(WT6%n$7qnyd9?g{q6g+$Yu$8$QW?#9nv*#!H1GMHo4;G` z$^s8vt7Msrqsv!Fy5n zbV|k~WB+YcD4a5ro4ch&cXd{l)hm>H-@~gJrD-G%YNW1^<#$RmeHB@(zvLDVZ9C8e z@sX}OklGsCFvMbWmmSBt6Qop7!1k7!C#RcQ^aJAiiH43++5&MW=179lj#Y|WdEoaj z!Y|Ha7-$@Blv@0Qm$lTxUoca1F&+}7n?XndR8?`bBu!KU;H;$L3oE5kNO6_RosH-(UG*3l#GdZ6~86pG;x(kEv*q>8Cb zft`m{BMO0B3H=%&^UYf{J22H2bU~(F2(Bv=xOVf1MevB7`RdI893=>GpCLx38Yqm< z3&wx#cEVrv^o<`l%6k{qw}t>Kwq>J+5Tn#tIg9ItXtx{``*USdYNFcrG!AvRmeU=) z_KUe{A#FzL*HkNV)6(Xh+Vz}QtGR(CjH^(R%Psk5@aM{L9G~MkRyM!SVBehR)|IDQ zK)P}MgFpC%R*hP}d<2Q$c<}gl1nC?Q9W?|Mh7L6#Sh|Z?Iq@kzE&_(JXESeY0e50W z(8DwBV2?q9IB+WH z5-@#SoxMp?o@}zu0KRf$GjwA!tRgkvDvn|W_tWO8Q9x-MEb-L@Ql3P#fVkwnlC03h z_NIbihxBBCPW0U(uGJasSb|+ll1B+L2k_O8 zoXjpMM&ZhFg-cN{^6&Jw^@-vO!arV8PlFuI(W;4+)&LVY# zf7%CA{YNc;kiLayBN+id0mDsj2q$t7Ln0*G&03g|q2l5WQu0--)ij;tUG{9PS?o1b zURF}03L&!(bCUxZfm!MtwBLB|0$EEd#~~Tp`=;s`HHZ;v49dNlKLM3;S*gG>W^>IN z(GME1>4g{8AHd4*zn4anhlR%PzmrTkm@gX&kslV^Q3+jFtm{bD_d#-F)vbWJ}s!d)gjrkGsuH^C@1kN8P`*d=mw zgD+er37E=_sCp*I#rna6u#=3HL`-(LgY$&eRLv5+zRWmem$zY|vBo;INj(m^+@*PQ zdzI&6oY|{Z@1)(St?RCh_$5vKUncWUL&>4(R0`fo{#Xbk(|+tCxX(V&Zm+55P#9J=DV zp`)GYq{6N7R+rY$^n+i_$~#=tP4&3qM6p{evjX>Psrt0RgJ2+iu=X*)7Yt>2#Ms%~ zOY%iOVkNlGg{Zr33W5*{E$b$3)GoInIqq~oR}MODa&R+GVuD=l`L7!bAIVVHGlE*w zFG57%1&e4Hl0sxWG{JHv)Whbf^h0ApG1C>s69=J>tdYZ{iFSTG<-rZcmE`3butbzq z9&7Wtd}kXs6<_IyGvz;;j+Kf zYRV%1=9dBOiEYMO`ppkTox5CZa-?p`<{FnDe8-7q9)&Ljk8z%kiziNCj1VW1kxJCd zGAfk?#=%1N6?9Yw@-Ook)fh0&B>dL>KFxiLx{kkNIrLEnL984@VIl^~Cw|Ih_CD{P z2Qt9eUY+_nA&3yMRv`0^N(kV~r4^_M9Z`GBcXMqCwNUif6rg%mHSIb;iYp`K%mc2G zfVKH7mMy_$ao$ac>s zKKPA^(#haGkUlE2HN&YYXRaDW(fZ8Iy${A;J_?5Fm+o5LE}#cp>{b^Bi=)o@Y16cKM} zN_#RjF;!^DZULbe(Ya=|BK-xbzD!BPp&+;0fxWo-|D_54>QhTCJFQ65sR^5~zSTiJ z%N1DY20^ANQ-#|nozEZ2q@8HE?K1@-^~7^|OBGlsCB@E1>^BiFdD0N$pAeGpVc-(G z9|w96gy9-*;n?`ZP*$O7Sl*wP=#Xk8%L;1KSRr0t(ykQW;+iJ(t|Q-Sf!iKx_Pt$= z>EE;em$A#2ofqJH7Dz-?8=F_Gk{8I`%TGj$6l}=;BdB-I%p5zfyO;1jte479RT}j@ z<5fvgxJ2MfhDqW$##}3OE-k^+4;Sij zB-u9VU01K$|$CI>qPRy4@_ zzyrJR+3vS=ouEl#&Iekvrz4k`&@(yOu&wqqR3( zayDIQ=wt_cwtNOgx*i$-cR_Nv9p`8i@zeq#w34!^So+>N@2mREbu z5!RrL_BspQrTKq27i!^ddq*mru@Q>jwYieztQefhC=_UpfKz%6@dQ_rLrw!3k?z;P5h>K zX`NTpM))2~&=+8%AfHi6;Wr+a`zl@4%l^2%y^i-zs&B&#Wz}+$FDC`D&|2mH;T1Sb z^MfWe)g_0P>BzIVd%kI(58_Grz<~NnNYIdBQ9|(`lc4>^-(lf?NTfnRiSf@4A_Uwe*2pN zR5LH$R%ga3Z>kJIYXqbQY0r;wx1{V8u4j%!>8b{K(fr%Z_qLYub$}NYp;>zX{a>oq z{*aBElB+3mX%i?O$2T(-5J2Z)?xbbSF=+`-1ytzKf zq(xQr+Qbs7t+!94%2&zheo#ofc`Oy&BN~Oti#@3bz9?pCXtJGf1Amm--C}MVyGLKs z_a@}p-L?UvfUCIL`KpxutNF%s()e#++4j5k4!}}L(Rv2SChR1P?hmu{#s<$4Ua24plZ=)V z&lFm{H6!}CYOe4L$7Nf?+Qicy6w2L_QBW5BkV*Gi8E$V1Fpw>7y(x(Y|TD7291OG)`PWb;}x$3%Bq%PC`9Q`!< zD<`l6=&2<_v#vC)hJ8Vk+-WIB&wp%J1`rbA5=!Ix@e0NitE5F5@hyKC(H!6s{vrwpl}7fL{>H{8*_FOICI0(+ zfj}615xwB?H$;-bVOb7>Fi0f4>;y6=n{Tmkh4uI%5M7A7TgishdEWD@)BW;3b34Lb z1{zlB{sPEw2zdd+X8(%+!C-6mwQpYC;i6~2`EGC?SpUklEf7B5)VPh|`o$gP?tHh| zi!% z!LucdcriP=N0hf1B00mh96vch#+ntu;N@n* zk|ffWiCULW}lbSFHWB0frb+<*33U*%RabjRzs?XU`Qy%8AJQMr3FCVNAH2NA8lgv`w$! zi(u}gr(azG-1as2mc@$r|mI!HoU86rNEPK^6Zf;?aKTQbZ}3Ddw(XN>bq2R5MTwfT>D)%DsTL|0YRjsk)(I6Lwfd?^O3f|V zOf(bus)~y2YGZk%J*A$w%frN9IO(xI_#l{So?fg$#JZHn>D?~1Su(yPzWuUQc&H(* zMMI3<0)TF-8b-KF4_<)X4^CpEs=V4IlvaoHUNnO51;vW8f6fbZbqII4@csg7^Lglf z(tm1Eddn?sQlNp??qoXWq6{~+ncT>))peWK?WFV>mKZv5%`%43SH!w#`wEcS!bdE z!S^>}M3<$L!j%c7jeSvCuVS9;tfa6uR#jl2%oN9$59-Tt7PxS@eb$AuhUGeG$ny$D zzk*?DPX{Tt1yUaekC!Ckb*htL!bEwo!KrpMTE&BtC*`cnlay7WO`gC?tsf*o9a8CrE?t3|i zB__GDx#wFIS;2J!H^(*o2Y_cPWBuD1VDmA)2~%eo0P1;fPPQ6S-vZ#fxKyPWdY&0f zqeJw}H;QwD{Api7cd9e~H;B@Y?W0ux6Om~mx!PW~XinCk%2EmpyCp!*P|quwCjG~D zg{*_d>Q%DV@t1^;!#ANeAX#15Soqv0--bo;?)I@yDnZR_R6`5Jgl_jWY4OrlsOmI5 zXuiRAxOfG;_Py_xWF&)dx!T-7o43xbi{)%sWwHWy2-t7v*Y}a?WYg%!;K&?J-1=30 zfEWgSu{W*`!{WTC4(B0kvJxunE0v$m%;w>BUTl6JCi#N8Via<50wvaO zN4&C3_ggV2Z!=5R-k)!7@!pS#`eU)(`iw6}IRiF}n(y-mmt%xrY#E@>hrO*R3VS zhOr!s2HR`pon&t*9rp|Qzt_7MOE)!KvT|ptd)tMkcu z%xJ>hjq@7ojmAI>67x+&bG*{Oay*!3E6~{JokrGjUcr#a9TPA0kh)++UGyNYPp>cF zLuwGmOmH;yzfDaj5sQADUaRiHNki5Os}Ey&Obd_mI{6}vGB$Ki4q2LMc|zQodE;Am zf4{``eMx37a{Ye!8z+~-OEY*GCesZa2C?Q!MVi3zwZv*b(|I{}kQ#5{Mj$VG(ROqh zaCuQB2VDKz4DL1@ZWWIKR5jB1ccmDGvE&&q{X)aM zrolRahwhEbr5`j@xhEfCMOHk57|PX|{%Z8UM4QaB`etgPnrtNdh!w52n74eiYmmTkqWW|R9C3x66~4g1DHG-{fU)D ze@a9je6s06vl1UWz%w=#>e+c?NKmHPQ|%wPI(5`3!~)nsqUelw+-z5~-FGnklda;D zekzE+I{<7JKSde6Fca51;Nf}6@5CIQK>9m=a^={6il1^5j5T|t6!64F5e5ak98Aj# zfuy#5udIwCk7{$WW!8JAd3;N&R-jCoacDH_FN47?kJl>%p&>uaQ)q{23piQPje99e zbxm&oJ)vi7>^qGy0>3-8(h~DkcpikxF5g76N%MR-bZ?E3lXRrn3e&Gtn*3*q2nlt^ zF-s>)P5qZv_x!5NV9AWHS=i=2m8+G^RSJ7aM>D%t+=tMJ_cgQzVTMmuJ^}u`-Y%Q8 zfp%PAacz0$0G*6C9iG5+W&bJi1FV+RXeGJO$d}w3D%7%4-LeHep)!-40vh?1GIFWO z!L!?QS1pC|`UA=ZqY}-^TwPcH*X|9x((?OvY2y8iD!sfNuB>3ele2hyHj0&k6iBf4 zSXal3eC8D$nJG(*UsR)I+NMgy&9S3e7cfg@s+P=#oCxidZrwYf^&H%PRnouN&Z3z{ zk15m%ZG>4JeE@4P>oQ-5>IAO$4=$9Qf5qK1V6DXop|^n0``_DpSYZ$ZHJSK$V3mFz z3MLH^8b6P*il$teD$VP1UGNdlL}H@ZlP5*9pVkTV8bB@8XR{V|d=n-}^y^e`67lgk z0^V2nc;>es_;?uZ3`tWb^-=Q+>_5$A%znnbAa6eeA2XG4|0r8LJ8M*-#uc$*alLDG zj~_fKfq0fdhrNl-rFBnQ<}#uehT5HsBQ{i8Mk&7MR9)cs6EL@GcKs7z$nyOBkU^z1 zECu>Jl9jVlhnMChz3#ITxW@GIOEFZlZd!xcMR5qck**znuYXf(@1wDNW6QuAf@nQv zOy9Z8%kcKZnN#DQ66v0%o-!}1ekI1$dRS_{WnhHVqm;3V)_wk3QN4x5C<3Wz7idPN z-23s^;+nYg)RL(XCcU#<+!kuiWpM!tAX}JlnWUX{zJH++Poym`ZCvEsil>6)e+zd% zp)|Y6+ zF=C=!=wCIXj)_mU*|GvTp3aZrHSB9DN=xwkP;%C<4&4lHl#;H>P2 z>hsY0QJcY&Ug)`#{QNAnGtl)o_g%UHtI#{ea-!=!R?indIdDZRVHW6cnkvSDcz={# zj-^Tvycn?oTvi~RFP5f&dTgnsg6<1f!6AOCMQhqFs?68nPTrnq&S-XWq>;KS&8qiI zmH&r~a1ow(^sVby%W*PsvSzP@^ctduyM4pI2ssjM_(PED7O+z;zz_z;)qH)Htx-?- zyUNLT5UQFIsKwU{x4Ulon0y#WG#lX8a0`ZN_G=o=^C?NCwR&--`*Losb$tMVzQ*jX zL3vnD7MdS8Y8vgguFXRV=?Z>pQ&c5(WaYO*bY=^qTO%tOI<$T+JD zbUaXaaWS$LCFa)8C-G2z8@(L~grb!&r1CtZ(B1`Hin5 zmU}M5lWAK6E>%40S3)?5&Y)T4SahR|Gc5wLWgJ||{Mx|)T`EW<(bGD(Z&Rl*w;F}# zgh}MzGX*no!dUjHt8!@-7_L2ykQ_aLOpP^0(F)%b;^+LR9z3#hgF>Y1&~xKxBQhVmOPJ-10caw|Xkk8FNliB@}UA-DXf z!UJ}b@F_OC7I2~3FvNQZbN&nG%XnRVVX+wQ77nB#Ccerx%s8avHO+#bqUswg=| z3*0Y@J{ZE5A8L?M>+C=2$-XY2h7OF7@sW1`2nL4H5blYh_oDb&NeJ4Gtds9Z+$$7) zAuvuo6sn#eM@mZWhwit=knni2$s1QINxOIw6e~Accl>ut1t8fzlo8G$URD=aURW<= z%1^4euAx0M&7Qxx#1NYK`&Bo1?gx3IJm+n!hbM2iz@D7(=A9RXn|s8_gza8wK*Tk? zUpr^rU9jK2Q3oN)sstv}pLP5rA|`|xCNRZBib|C!*+}7T z{^rfXuY7k%3-R&daP<0Wu%QHjyRw|RWF5z{;~}2UXGm~Ia^A{t_w;?jyi}mT@(%7b z&15^$Zt=Tul5kPS`FO@~#L3gP3$HGj-lN76)g$E?|30VVqV=AnIs9GvVWXztykiCX zU*bB{D^ny=zY6bmafX(APH8LP5tr6yo`q-{rmW@AB{^K}U%rL*xjylHGuD49Ro6K$ z3sFS)Wk5NP$pe*(z$qLwnZ4{PNmjywCB6JRx2>O|H#%s&iGP}MJRKt9PWk$5D+2Dm z`B-6c?fK2X&w5&aIO;SIlJ*(qC1*acK zgF(jZ3{82!tkFENX1?S2dSxy5==&N|6Q7T}(W-m!Umle9{{7DL3l#>1a<@UW&c>f{v!A?4STi{|N1x(53 zTLh;zG?Z}4 z(}$~fs5lEB`~0iT`U|d&p=>wj09Zh$zm59+lv)f8o}5ix0irzF-I~O%VE<*=k>{8N z-z`K0d_exaV;Pg;DN+xtz1K-G75UAq)t!1#4li1`~-d^;Z%?sq4ote zL95SL+m-;%>jE|LF8^)lqG4|CQt>v{z=)n`Zeq;@xrRkFvJwCqFkHXMWvg)iDkg%(75Z@aGk1O506~yYf$?^>nrbFvawDi?-^Aigo2~!|cj^756%0;&s%25BN7lWhy((noe~*ENA>(pEOO~ z$#Aj0rUL6cprRe~;nt0X_T*snL4h4bf-3d}ED=&n(>Ys~^F`D6Jtk=S(Ec;yC*!EL^<_`7E&@}vvPTL{bA*Dv@Y z{x=eouIEOVaLo1CY;0nP+loKc0g=@bA`%uNVkJr*IwF!PzY{9%smQJ`_&gDqq+c5I z0UbN`Sq!1vOMB7X$mb;5!II`qXdzu`jS3 zWuELU-l)F3v*ptSz`Q~opLMPVE2H#~1&HhWv~gNAFU9al4GxUl3w$l_fL z^kYZ-Kq%bhGtkvw%@-viUoAyAsRF6~QX59i8x*+r9MrF;5VvKYhSK(1;l%IAUkNYg zhA;Ch8nS3vX7qREMlqT$6jbEdTY1Rp-m;({q%C9^vIhsTH;P3Uh^xxtDZ;4RS3-gq zBwDUJl<@*7cHD7rAvVaNBl&d&cL;j1u?)o>xT6q_ys^enRhY7<2#1Pm@6*O*>>n0- zD2DS#E@K(9$74qaV@Ta}^?Q6ntOzSDa;g$Hw-TPgl+qqye_j^8y=fCUgnxTe&U!+= z{_ss^iMCibe+CgVXYJ>EMpKh(8cGw!9Q+rcj&Ky@cFMC0i9soe)_}n*LP>&~JHaGc zs;F#`p)9Xh)IaXx@Z51WlQeHEfxQ2Lg&R%RxQENqkAw4;;ATXVnb#^@bSOP$F zS5#-})2ogd92UzWux~xy9SC{&T`gFl%Lc&nykj;Q~T z$Ihb@k0ViS3l*X$zgKYumy_~5;PpKD_I9*%VLMhHx3hld;4=91Xi+jcHbC*dws7Ki ze0)XWUYvOV>Sgdk0vQI5T>L7Xoi-2bN@;dM|E#W<RKvnkcvj;m$M@m{n6WP^(<{Jvu*T3rit(;YR} zkXWq-M91xD#VhpQwo*bS6Judu)d_NYqOruBue(Ar?r@ZD`Uf`T#V{r?*RHuY9i`Fr z3~}fmEJuCvY)eLU{&gNc3|B#&Rht)X$F*}fG^IX)IK8VQaZ+LWWiFe|t36N$|2H6h z{xjk)GmHg0@uxZsMY9m@l^H8tkp8AgJ`X=>-kv@`Pd^#wW0s~Fo$seL;kLSk|K9r> z6aa2d?z%6*C=EoYtp%Ak|-q9T(U zz{x-wZw%Qj_GrGD>Tg^uCvGYWRArFbrX2pC-VvsdB`NG`j_my6xgi#lGydtoQu9Qw z)I)@Bu#i4em|NzEa+2%ccWVNn|6hAke~C7j=SA}3F>b)>n0EGguncMx>TitbdX5*F zhpI3{nb-mKv#|3<<6So^kdjsm!MAfHd>=MYg`y~#a2UiG6e(1ExjxRS0Jc;@5z$sFZf=L!{q?3LH2C+{mJoDJ#;z^!Fzl)g z7+~Kf-J7b^jD>Kc;nxf^fsW!Fj|}V1lwF^K=2+{-_=e7MxO#~L={?Fm#`jP8&K}77 zyu@AAz`|Y8=xjjel8y*>a8sUF%r%U@FQwtu(UXv{`>tCXpeOS1XQzo%2VF=98m$n# z<6HR%8vivJ6}dLf_(XZOW<2E4zF?z?EjIoOY)7^+U26mJ{)W!qYTJK_hrXih(mY6b z62Wv!XeWjeietW;&Us#S+G5_roCri)G~=L>6J@Y$0gB>JViGSdZHR{l6|*`BQ08}J zWG!2_AkyBqJnK|Lju`7t@K5sh1UU=CvC3N_a`H0F@Rg61`3|?w^?DYc)X@zslZNI< z4B6Fz+b`1c{UvRGo|k16w55>dg7n}{{++yNQ9cy0<-A+qPV<5rN+a-!<2DL8-m27t zoxb8_+Nf&M5ZUoQp5S|l^gOM3Cy`7x33sVk^G&n8Ihc;!Ls?O%I9Ug>v`t@R6Ye=5 zFRjg=l6$#A3ghMy6d9<-N9xsPhz6AVPM1>JynA`VR)OQV#rYk&Q3Q3(x@`~8odAS!w&EA#TxnDrUJ)o1oF5e>u`<*Y*wS8aYw>tCj;Md?mZN!B}cLAgC!`j52np9rIPaiVE@UNrH4rt>|L)wQR zCP;k5-s$iCoj{iyw0Zg^q@7QiMZ;ol*X?J!1;t`}%u%!nNfr*HPy9mdq~|&LyUCuN z2@l`9aE5uS$2k}w8}cf1mv^DPw>;YM{(cg8MR~y!{fOg=olj(PtL4R7D*o&V6kiW0 zVXuY4-)=w0$-H7%ha}o3^K*_SHmIkrDmlG1$PKcKi5I=~bV*C=uKlR4ts;i@+e+Eg zj#JH4En*IbMtMc>*ok_42Re~1g=_H_bOw>*tbJso(xm^43)H))h%e2L4oO}(#slT+ z;kB|KKnBfC!1A{bfzPHzY>U{FVs|dh%WG8U8i|F9_*C2r56i_1OJ0a)=X~K#NIDxs z(iU##g+RgKMV3~SHR%T&b-k+1rb6bSSOPpIFW5FagWR9-k}u%zi?6V5!LQUW6zs7D z#Ym&PcuFpnk4}Ht39~kbK&}| z5A@Qvm!f(JaosEy#k{SBqSZh9)A7Qr|0Q2Ap&UToYS}O1$JUgnXo;=XSH+OJucsZ~ z(-H0)Ae^HoW#N+0zbnzWJ^tBsF^X;0|C0R}It45B9a0M9TqvF+(jJ^Ep7e7ld4-HV z(eSv?}AuFqK37^ z^&78+89-AnVwx;VzsN{awLI){$jJTJw+vM_heHnH^Zm%kKwuP z_8Wl{%|jkd(&yaTxVghsayst&s)fVk_95p5}gMQCk8yKrpUQNE<%VG&Ru>>984XtJ!_UPotfy|PKG%4;DHxAlG@wo-*U zsry&O<+1$2l4YGxRGzqhD^jI8;lD->uU3!`Q^sPk2&c+YM&kqjgq-;Srx0s?};|?R(!JL#V{<9(0*wSqsg9#9T+lJYZT1$&Yq09^W|96-75cpYcACn>~}}A{dSGI33=6 zdAz`0MB!F87fe+}6-nh?h|x;$gEl{4KKw7>!`^gU7in^^fv>Oi3gjIUdFC%~i1f;S zGRWsVU0w6@HvjEMCrhN3tnK#<96kz_4O{ryw05SCM#!t8lRa!0=Dph`>Dbcdzl z$}EJu7P_rQQAL_uqv>Xx$(CB^oaf`UNN-=%x&LJADO1rUwf}Dt|7&MGtEI98P|lnV2ZIB-MM$|Ysh0ov!1n#T98j`lMA z-Z@HQ^5w;)`u}B?|EY6~IlaY9!6F-|V}dBK`Lx^^jwV^X8DqcVgr8uh;&!uaMbV1s zRw?P(aD-^|+_?l4Ig?hCy7pb%u1%}A^&$+{+A_WeSa$t73a_ejn{eG+RaJHGRw0wVEvI4I!=&A=&Akp6?t2= z3;Dp~qw@9p`z?!{YVOl?zZke;J}vaUIPMZOt$B>ABst?p<%hSogYaX&&vA9}MYQwB z<;CcGahErQ!)CX)|Ht8dmKr|(`-oAWZ6Qu7qu4@b>J8ECv}_bx9n;6<@>AgXAIU>X z>h)t&5+g{PkJFwz+ZruUKOer~)r=L}YlRj_qEm&ciRhq1ehTDzjQwcRB+wCl%s=%UBu z7a8N1)79)v-j}usU0E1XZH`@DOWeL1_t(!APJyGn#LCOh=~iRUYM-Sw%B_=~URGQQ z1wz~^U*}4t#ym3k95tXal*$v;Q{uAdZxrD3#yv=ISuQf!&w_EOq70Cb0jRU@>Zcp= zq^W1isb@vU5+ClHLdb+!6Uu7l^cyLQHJusxotf4RsHoQG$7O5wv(Vt0_YrND8lN54 zc3#J(`?l6Ro*Pt$CYw(Z5ExXFq~A$z6BqmRI_S~|T`*;kiAxqr!^B8O`NXESp=i~4JfHA|foSwdSDk*xV?DJjLr;O5;h)_?t@}k?eTNz{NlLJy67~aZ{&BDjyuaA2ZbVb?jI>g&^9-gRnu<)3oho`#7CGX`lvWiIt? zdmZ41H}JlA%s&{vuAjp$;deK+5Y z1X`kayo}{eOWuIAUygQOpcV+q&b#syU&gpM2baGIt%RSJ7YMC7_oL<9T`6_NVtdd? zydc26>Iq$xRlqzpaa>wxuX{Ru<`dCkWK1CaR!W(Lk=amD1aN{ao)pcPl}4W#Z{f&} zrV4!@N|6Ls5d9?aBe>B$DDxu*!ca}O8D_UJ&K zgPpRYR+S@;OQomU7jA%66!+*$uC{cKW1@U#>OKZoqQHE|6|=TCvC;gUxPz>;(1>#4 z4qnno3V2dM_sl7Bl*O4=CNrmI#qumH67^;zA1XU+#T>#|z)(oJFkGD?=K5+u<3=>* z-y!F|cm8pbtQaMF<3wnkpJt=wQg=f@sLtySzn8@N2!;DzTl{@PVGhs zFs1qI%Vv8uv@`?1*t{%kH1K%OK21g&NJUhWHJHm)D^{-C1mv(TRRP++&6C!qNegBo@1}S6eD>{q1Oe7UtXg4{ z(YC3=(j4H^JG)$q-UZ7l)()y;IT3zdnuFZ)9IiGQ`} z7+MIfr(u|B^Tp^YD+R7hg36iu08jz)FPMFt=`TobjjKskuUbLLO42NH12ae3&l<7; z5+1V`I}63_9P%bWjJv5jFU9d(CBBLZEfr%wa|pg0tAopc*MI?@7A>r-=+s%t0B3N3 z(`K~gP+v`%qApJhb7PCfl(xVDY2Qit%OrvMojCRHS$C*gGR@&c12G|j&zT+QSWc6yv=JQS`7Z&?A+Zy_$!Ri5Dh7n8iiX15;82gOcz0>2 z{(Acv2XS8)k=BlJJ8T%>Ln#%*jPbk(yr0|pd8x{$%7Udz4-?uE&s1W$aP;{4!EEjb zJOK_^bcWX1*4|X={M7fOO5GU8oV1yv1~O6mbL{JbI-uE0LyCj7NH((}pR~}f_^Mg_ zlFpl05KcSg7QD0R3NpV5;7S8j5z48-N#>|!0t-w4dyL{m2jN2b*cvpg?I-*JvOSE%%*NCI-ifDUTE+iu1qxrF| zr;L2Aj*MmeDE})11PyB*6akF73%=Fg?~8cJb$RGum4t{trmThNaT=mT0@#vKgtqau zg$>lTq~o~aznVbVznZT9X|j^`L?UZY`#3gL6DE4g7!T94a1#wm5oc(K5jhPB=r^n; zLks{_^Y~#0@y|B-J4FJ1+z8I7{|gZ$f#U*Z>D2tq&&}Sb*IL>APeciL&=@lz1T8-i z)-2SM7b!<2kR`%K_S0{X)QVsZ#*pr|#js9*nxhhD-xEz{1$O)ktA?p!P1fSia^RGOLI}=t3Y~k&h_;{jd<7xRd41&$ z>)gpc_lY|EInR)YknnP|Z@DRwej@{-qUX_wHD3NqibT{nh_OW8a@jO|L;w{}z>Hd7 zD3>u2>vmBf@-082AmD$#-Cyau0=th|qzl3B@pID!0#ob9w*x?*j5*~@bpr5avU7<9|GWLH&`I?CA!q=O;#_=di@LK1h{>7&GY}40s?=UXgx2By zm;!GLWNezOrX_Sw{EKf{>0+U$J(a$y!X5|qx)0>huj_c$`WHIm-JAZznJAdRpPqV( zAcR}&zdT@$_ci2Pldkrl##)IeXtr}9t49K%Skoz1e?A?TrJ-{pE7(uZExHatyuhxU zG?W8K#7$`$MbFFfHKW_Qj3~Sxph>t=Q>$FIt2mE=TWKPn)Mm$9XUFP^CMlqMV7TYr z9ON!~nIzYqSqdCrICc2_Ow)`6H`l5e0AyGI6?I?fR;!};;6hDUCg?8ZCj%quhi}%@ z$I;Q&#GM)91k*ceRH=*Nc{_DQ_DnX`_r6P%D(}W38>Kk<)yh3D2!MpD1>t?LQ{njZ z7&f!byf@wZTnE=p4WprE)S)rYcNN|yYv5lF4Kp5&n^|FDN`0@$Rh(;}$*H|vC zYNFUcJLb74LID3?f|xu0wMgUPp=Y^Y3Jl^ucjbSmGzc)}SWdE%(EpMV85yMi*+n=k z2iCJ=O=9h4fatt>_tT7H_Or9{K@ky}V_>yB)^cZRbEy#13VANJ5aMw!V!)0@x_Hn) zObL%d#`T(2ADA>$Wo&g}?E_a@)>Ij+H4)znsxg_ObaANTPga-6s{VTu1?70MPlkB` zN`SuKXV$wVUJ>Q~&DnU>tbDbqp8cY}%J$%bl?8kt5H$1@zW{YwOhkDnRTQRTX_?fD ztYhLW#Vt7xH%#JmoJe9yk0?RXPW${J1>p2tAVxiKP&yBiIVUd>1r%w;-Ldmcj-eQ% z{CR&ahx=R78`!XcU&WD_ULC)l-S6spVp>(yrpxoV&>5%Q*ZaE-YwoW6jPMBtui^tW zT0SshTqI|dT@>A}2R`D&0(^Aq=@Yl-b2OmZgXCz?hutl1F{seN*d~Ki0}a`h;Y0~w zE+{$vcL}0xt z?pjOZq{QjSr#ti)yv@_*Vf3%tC9cVFwlJ@a#re*K6r8-Q z8EVfvrm()4pOF~1tI{hxy|sciy^o`!r>DP{lKg0~gD!pdG`^VW`fv6U3dvmF-5R?NAjgB;Xt=8-co`e7@tp7QSkeEo=gMp4tOc4~eTR0elAgqJb$-qB0z{Mht_C z>7ldXx5Q;uT*2KpINSh@Y9hMS>akABTw&R){noiPvtR9OG)8t}VUo$}A{qnb7J+?SFVs8tIXm;!14e)|p+w6~(iWQdT*;9baE zYk;xI=|-kgTRGlt(Ec^6*LsEZMSuhn>5vZ=YHZD8Ca}8%FYdPAPg z5ea=(l>k(fGtSkHj@q#fbUWpY5qA|EIE8dM`Iq+7*t8-^Y-RKAIRukX8L(E6+%02K zJsyZJZsQE!bRI2@El+M}h}-|{-<%qG+W&pcAK)AP(!9LhDee34jieR9>2*me@eogf zN*WXc1JV-5d(834<+Cu&%C9U6!(*kZWQIl-W9L7-&;oFulMbcq%N-O`Wbigpd?FeV z9W?V)mlm(T2tQb9Bk{F}pGgOg3tfS;jn=sitze^#gJxqy56j=6D^*4rbf4($3asL2 zo@r9WrdGGURztKq5DE#MT(9bZvEaum+ivMZT*Z(meW($h3A_5I{CP47RM(b;PZD0$ z_ThFOG#2%*q9TGj!3b>)8OL{(S;CV(0_QV;==6eb-NpM9UAxnc_x`*M$buLARUi}J z{re2>OMp)yzVO_2;0VrL!T*-x`#*On_;wY?eQ=r zki^{X9~nMThFNwpBPK^_F?-kvMp97hlNDoi@I!{O5h8hH2QqiWrU{XNX*;r~v>HMP zuSR|~k>1E)nJmic@vCnkIDt|M?n_@jLpYaj2~oX4%jG4(uCrOvigcVV!gfF$*Y6x& zQXPblF*|fjHqo#_HkVl;QPe)R2gBa)jmZ%|+2;1Mq862M+!W|)34lwn1$N;tbG~R*pz>IVedmTKF=7WB^rowd z;A(HB7#B##5}rpSn(r)wj=WJwG;Hvv`YCEL`aHd-^kTtERZT<}K5!e75CdpY_G#eY zVIieovh+A>wDUpJU?gDRw0eKuj^^+NDCYrriN>eOW4T>b4Gyj&&mWzsN_ss|af?Fh6W0wcQW1rt$vw`c#{8*cAZv9p&A8=cRwqKI z>STvPvH1*(T`1?*xfW8f-D=Da_%b*Pz|O!*a?a)q>+^2iVcB}ZC*{q+1pSSJO1fw2 z0GT!q!bQ&>ttj)z6CR{o^V{V#i~L1fyK#1iMw!de^m}dXRwTmf`?9xo1^F6crTMr@ z)Bx0aSNyQah3&Rgw+&w`Hyw*Qdc2*ZXEoR+>Pi z$^0$U*8@i==>-SRD}r}^{vJ3K2peOf6_C%3^iJfcDRzAryrs(oK-x(*UWdQtf6D zIa2)K<6x!|XWs=oa&ViruE3z#wOb+_Su|W^kOWg0y^2Xf`u}sseFSjZD^-G*t%O>x z)OPj#@MBBrmMQB7>RB(!8~g<7ezBDo7%=Q(3d8f^`3NyJMd|Lr@ngfi&TK;|UoX9o zeSjZGy+U&mFKH}ZR>v4Sbaoej$B5CpHe|7!Q)jjXnhE>wtYo7pfs;x@>;EZfps0Ll zM0%7t0yGTPDA*Ny)X}0O9lCJ?k@hT$O?(pZWNL6*phVhZ0lzG^EJb z@rVg^!#P6aCs5%7r_`ZNN77Bh3tZQStzKOo?&v&u*lh}G`d~n@Q&m|(dx4h+$gaG~@ z;Jo2lzD^rv#n{bb_3M+0b@%$`3!>w3C9FjWYpdvT_lhk36(_qW2aev5LZWla_$FS4 zl1fFK9;s#+_nmO_1q?crg(quu?{#ml4bD2>lpu)jn)vk66=08BxXQ#zLa=W^k62!) z0W@&-9LJN~J`K+a1?SPwC--$=fWSpLELM*|LWyl&MjZwpiK%^m(|+uGw3&vQxqPd( zC9#?l@;+1?=tcJdS0#Jj%ngn4=(egckA0Ha9~E$6DiZ9vXlbo3np1#G=awm}Y8?!ix2CL7z*thYjATy3tK3TP5Ndm@(xh zI>D%6 zG*esfe6WD9iA^=SpI%rCdN5U^0ixk zqpO2FS%324hT(!=fG`#^ng{c7t|a2(QH+1jUJbi!bEg3^*Jgo3xnNvw%t`C(;=br; zCNJ{FT<-8fzOY4kA-?=oE3+uR-H30aZw1OR-{^Y3=rBi~J^>9DLRS8CpR)t3JiIZ~=;fk2jYkrVEcH=pu2(Nl@- z4g}0#6~=4e+D`4cXSp>OrhNEnc=?U6LET+kBRxaj&JV!-vx`2Trs<8#Hcki+sT^+6zEP4mFo1xU9zXU$I>+{CfdU;F`)cdH=&dp)+ zIfp6p7G5HVL#lqIXZktgHV9qXH=9k@A+?khrU}=dfX2TU+6|bXxDXTik-r2;j(lx# z!27)BFRQsb{8puutBJIa?ms|$jb>D$&st4+`S@_<`Uy!c^A^4?_aiY_@C7Le=bA&) zox+J4GuNM$;@H6ps#wEg8K%2*Aorc*Smj+Zevvo8qnZqn7cs5)zv-FScL>Rig!R9% z1yD3Tj_Kg{)+8w!)ZcCpu7`4&%UQUb(_lTA)iWwyE!x8@f|;pTy%ntK)+>L*4Y^of zcoa|eLx%)leoQTMO}ztO_aR_gKxt(4R+0-hWuFDs9}j=tzO&J# z273$Gtf%BK?s~R!f|xOFEu7A@;}<}g1h}#DG>#KQ`vW%Zi66EmrSm)+tdb1zzlEu9 zp-=b@P_khSwfAe!%;htE6#9>=9TOK8M2AGR0>YEckiwcoXZnQ$+#6CnrDcX;mgL8p zJ+wZDU!ytHT2`azjEsO(Bsd^B&_XM?lJe4&m9TNOOM~XR>(UnXzsAU-Nch(n-^6}; zJdUU>bQ6^1i_1aoSN07SaTUx`dqenMUs|oNkgp^7+&4k}DNom`iJSWwNrQr_>?(m@ z#e(u`s$bX`pi}`sGq1dycUFYvVVm*-w-CufL|%xZ6x z;`HQk<&Kl0txQx~=k2o63hM|>@jL-OQ}>3ypj%cyaGo6%J@#vf7CKZKskPK7O+6W^ zC6Z+lDChH4YR1iZWfJ;!&X=19OZYdrp4ws~pEHY)D{572CFE|!opAhArtO85s3jI< z9Te+A5GYq=&BvxJUwd!o?_ddaEue?(hBm(?%!{S*0c6h57%=3lg|v9hkq=UK;`*_OC^GHwo)O z-8kw|dL1EcSR{;iTbby#C7XMth;4gFnZ041^UMa~kOYIbmmdhc^vekf=!!7p)!%kR z>au2U@02v)1`XvaB$B_0N`zKCKe(POH%MA92o`y`e*w(J8Ls~VKiDH@?Kt0h-q|0+ znjwf25~fOO0upZ~5@iiyK;%S#F@&8=DO&YC!d*iGOer1>OFg=!_jHkG%O%7AJaT>l zKK8uHSeny*(?o@zn>Xc=ovC5n>bbx89Xvd`go(AAZRUCU_s&jMIjHc9-ar2J%M`Z- zok#;G65Z|OIAF1}L1vRd83gN?65|F^EL;p|7>55O9qE4k<`OTo;tDn@S&Obe-)~vG z!ns-13V;aWBsg#sK~^>9BMqto+GfpZE`RumDw-xUE4tZYTq|d$XL;@s$uI&$zVa zP3+=NuPH?!Rbp<~;H6dq+L!Gn^eBf|lTO-}@A`(*Hp#zv*_GW!>+&wsMj=rG=V&b? z`-k~onViE&K3lKUh_N%)dp=0w^i^ej*h1NT(wl%p{sXbl(0l#Yp-XRYc6?XFk(%c( zz7dDgKVJoCyk&phV8ebbb+k@3O3*-M zZBoE{SocKm#&Tn-B^@WjkjA(Bauwg*`vy6uU^kbqw)LZR^}==D%XVlghxZV19yAt% zN&4SV`pM6&Io#|a&>#lit~#{Q(*lhT)jh~cyKZySZOK+_r3t^_)5T3-WOm3@J|Xr#+$^ zWD6?Hjar$F(I6OQ6 zS!IhvD(5Jd5%jO)kpwS-ge#^;YB#y!b35YEQY{$RhYK<%FvZ|q32u^{8It)EG@hv&Oc2pKXS=eQ?33Kkm$YLTx&_spNTIn&GSw0 z@r0};H)sWx_u<&=yoMeG$lrir3c0H~?C~enQczjvX;>!K|B$^>@hkxvgadR4 zMX9TB4@ew=CtSQB3`*-TXeYY+c3T>_5l7&@UD&6D{*!dc^Yn^5jK0@`lS$Nr5qAagVW^_O>aff#ybY&P}xs%(GI9I86qUwTK8CseET)tb!-0_SMUFsa2C9KxPkG|Jsy@J4*to$n+Oa zh5yM9spjr<%ToZy?D2by7P(Z-fP}?3V2tOL;Z~vn)!lNGNy6?~nJHEi^>GcpHE=Jk z>~fE?_zrbw?Aem^x67cQGXWj2E`J((g?zu~F|CW;@(f{U$@0R3j2qkOchgg4I(G-jY2*GRj+g9Tx zjOr z6)*30&xtFK9clt;O9O>8n7mT}MkNC8?E%Y7D$ta$xhnB8u+TsEg(^4((;)ZD@+9e? zWlpzd0Xs%W}M9egigYM?+{(pzO8wV-3> zI=@9+o3LzZ6^rppj}s;YPyXHocym3Dmo!4Fz_A)qEB4BLO;&)7TF$Z0j6}&hm# z6r95Uo!Mx3;@^XHll$Ky&Hrcii-#*b^KPQivtR*P#cbAUwg^c@Ydbg#*wr-VTZzBr6rPfpU>hhIR_PbHrZ0c$tXd zU^RiZU3V{^hW(?X=jCnJCBD=R`SaXz*&0Iw-S#^gz^Ew z5VC&)@_&gff-sL`?v3U5^#0I`M&CT>R%{<;p$am5fL5L0i35I8uBYYx^+kWE>T+LQ zDylZI`Yu>v{0vLA9e#C}b!edm@#$-f6Y{1UE}tTrGMf?H3lzRbU)AzSvZ&vQKJ>z9 zbkcoL3W}3j{9Q2#B-9Q}$H*cxM!n?;1*lf;vFNBY>A!*acM;A;*!El3lG@feSb6+$ z(ajYZiR{+7BM2bF8Pym>1)WmCtSkKMbhysFcJ3jYVB7pHs?!0U z(1qa#O6HI>K{)YuWTv!%TD%N9z^K|8K0rQd1oznu?@JI8FSy2YES}#|!O-Bppc(9c zh9Y1`XB-&PR%tyk5R2MExonlBPiV7>J@aC|&}B4TDTap-fa$R72+*jvSqlGpTjiv zLd!;}MIs1N6@LqsaEglOc5-Vb{-*hM5IRn{>wMx=tU0Ln^8Gt|55Pc{v1j~jx}_r;!sOp zI&w(fO@m;tQ87zpEY_I){A^f9%F8Kcw3z7EqYCl2El_W=HpEh&CNXA^n+nmv?y6o` zsGHK5-BzZ_#LGaOdPRhdAR6t?I{jO+y2REO*|>XAq% zBYNZLmGNte*y{GvMXgk&7Fk(^80qVN6ueX6y<^i_wot?q4TD#46p}doe?32V+y;y0 zB-nK4XRE<1$I2;Im-~6q;FJ}Ifs&(c|Q5p6H|4T$vMuIkh$A;8{CPOSHzt_%Vz1mcGT$US#OT63ZJ_EuSB; z*)s!LwqUwt0!^0S^Wy*@Q?B>7?oGqYuYc7ZYb|^hsVV~^joZ=7w`S@&^q=(0=+bw` zEhFp(yaH?BKqYaH5&%d*x4-iGG~d_B$WL_V?_RWmX!?J4Alp}^bp`&!$u{37S@5n> z@^Y=R{91p^bCGC?A_Xihm62}*l_w4?n-ERb@6b-0@4s*0jyXyP=Ye+THjAeK_z|e8 z*5i5t75>KQpY_vDD|HloHGkCUD9=Ez+W03r(qyP)PaJT2Gluda67|)d*sWRKq`WQ07}_i9pia^QwtbD*S-2Dz61^r-GQyWq1^&m<{+0VF ziV{vvz>K1K!G%ug2_UI#Lo~fC_Vem@1Xo>h%x~nTJe;u9W#{VEbZSyqlGX2$ljoP$ z$cavhCHaG9=8!^79Z(v5GyuX%0Dw8aZ3R^(5K=+%9z^B4b}&|7Vj`J#1sU7ZJlMeT#vqb8|JEnRb>)z9N9yzTln zmV?2EyTQW-_w}ESgNHFNrdBKjNfq|T+{!>I)_8h2)YVO>tMC*ywff&Aks-y~x(r;V zc-{UcwxO*t$kz86Q!5UZG%v%HUv8v2-D%kCK_<9!34eQT#4fN7D&+?Q8(C4443GR% z{PLs7i48EoPelGDANx2i3SUnDaH1`s% z;T7vyY33kkg7c#44-dRnTK}+Wx@Xo%?6fcRynGt7k~~315MPu&+1!0rGF1rVP^)N4 z>K;*&{Vldb1BlP#6})>c`eOq0K%GF7rd~N{X2;xIJ%lZm4|N0%=s|AVn}~o(u!9~o z_gZl4miTS*H=%JZRx`Nry6#NthXTEOab}e%>SX1}qM0i<2PId0ec_2{ylKX3?8L(< zl`_W4-FEZN_`(UYi6iWR{;N@dH~sDRKMu>3nOHP_ozGtlw+wp!Gcp<4w=`Q^b{G&rVYQ$M}fZJr>_8@i>)o`ok#n03g%370lscZ_HOXwVjszgbeD-L(dbOoIk5;cDNlziodK?A3OjREhaWIstH@U`LZZD~bXt$77h} zeZavL{(ezVp@&J%_eNw^ux2zVy%ZuXj(QXZ-M-eo*gjO?wD7x1STp-1{Pi+zON<&k z-mSJvs4&f@kblz)x&wtX-nAcrRz$f7MHZ994FQ+WE7k%oKJGa}gdrE)I$ioaNXLF- z!d}>^)j|cNH%13cz*+gG;M^0q#UgtiR|vntLCh&>q@8j`ACp}94HU3Gb?f22YkiPO z$^^X))m|hOClH+ec+=k?hYBb5b|^*-_X^VUaxQeVYRtFdtbi!xL~{F!ZHU&S8H#2c zN-F^J@L@-;F3JvRdz{|Jc`w<$<}9}`nGo;L3uvu$PebE)&orflESxgGf(PIdR~VBK zPK?9q$I|X@6UP-IND2 zj^`H|17<7pCv^fV%9-z>@^+=r!O)M9&lVLVK91fN`;m@I$9MIhWF5T^=8i_$hSZ^z zU&Uoo=vC$WdNOI#4-5A0GLQ3C&1}F$#J)zmWnRS^WI95sjnB#?qz9k`Cmm@vs$~HP z2>Y*}y?b_83Q0iy*S?Qkw;TiXL5!Enp zlWHlSoplx@~uGJ8xx5tu$uJ;91Cv5z3w6Dg(jZ@`ilv z-%{gh7G|o)i-tN6T8sDZpk%V0k?yZ!+)&0nX#gimPaiN8xiRWVbg@k+e$=jXMI|sm zp$R0BXju^VNx(dzr!F zet`e~@&8kYk)yoObI{S#(Xr6c0qDLCRu-23ai*hVq-S9Kx@Ki% z`1;VZFn{%Z05d}iduyxz`+onc`~P2hgvv+>!$4s| zeO+1yMASWdc_<8Wh=s(JWT{6x+-D8M^ zT@RNQ7P#N1ekGl2_N)LK#PAzS=I;XQVinowP-S{f_*~)C5lilVqp@%;#L=HRgvKg& z8hq|GSL1-NjS8P@_zAzo`v;*3^7TUpiz+a*9eyqa#2$FFAuGutWpp`HbMj%zLeopz zh`X)bt;oH|z0IA)dsa!=&@=U3QA(++3(cpUvj+t2GlhdTdCwZR4Iiaz>m2gcFZ456 zs)RDU-wtwC2LyRnbjWFJnUf7CdIY*1`uBvZjo`h-^>+|~jGD-n)j)><6;)q#ws}`P z)ii&PF8Yx^j@p=N*hipXnAD1=5d3S=4Ur3}wO!Ie9-C8~+y*w6Y{Z`nS5i1)*^b-M z5;iA^LRQ7D^svx=58u)m&9XtBzI*LHS#tkb?N@(xoW9F8Hy{%xc6zNJIM(?Y$%iBT z`kd!HD$X?6L9Z2U4(NZ!;wi31u@F>n9$kB7}ab ze}8U^`-7k~ob2WXgJ3kj#`k{q-``xuwuDl|L68Aa+!NQv+H|+1H{d*--lo-|o*r zhhq4gbCkasKT%B@r=);Y+~3QAk_e9qgffjtH564rgR{KyIk*JTC%?c>HOdR6Ov=vA z0#EjfWe#*wgW7F`HgZxkhi7-b<0Tkmgl;0)s=};}(M(5s1hxlW1bBOR0@Cpg>w1SBQ4eKn6JSaUqYd2=d z4zcy5>LiE0qs}ipxNF zD&;(UDm>YfC4-!u$L5CDOdo^teRV4)V68FZlYN|%;72yDU~NB$^KgrI#Van;FzIQdA{Z1zf;Wx+{3_u2A4*yF9l5cg zRnwCE+zQA!{?rmO8w@|Q%G-7sn_H_+5b{aP#H*b%pYX2Uqpa_MKzI;NQGoBg(z~QK(J7+t1YIL}g>#?{q{}j$XM-fJi`Z8Rrmn)mzGF zz8@K(bhu%1eo2TJa|*yF zTwql*pW2NlxUhCqFT7);;Xn?(>OG}WijP`6vE2b`KKf`!Pr$3Xf9ON3q;qd|3Js#? zK^syYHXKDhe$|I^I8KDSvDI!Z8Vy>Zgf@5JZJKIhpS9rAZOwCeGvt$P3mFY78NxIK zR{`PK#=~?GG*$JoZ-=?(=*)ctdj6eeC@}14R8Q9;esq+Fa*+%8x3TIdl;+f({MG(L zK-A>5^Zn$RU~e{|>roTnB~BW5N=!uc_uvi-(N=cFPV9<#@0;Tma6y2d!|&G{|?VRh!KrB3=O#h$c8Y*Y41dL#Y)2l8@ZC{aOhuaM-X}=EP!Hf+&*6M_anIooMLJh$)3L_uV-Wswbh! z06}0c*|*BGoImKLS7fdpRef$}JkA>|5i+N|CJhrvM{GHUrEmh34&b?RjLOQSrc;+w zwW&h`us4{>_%<`!%~~SUR#%uc0rJ|8LJ+@A`YbwBg2$UkUT6?y`=O=^7iP8|P1-s9j?hI{ScQh2Zu>6h`f#YA*Bfe#FDeBX zrqP6=O{iw!`)5>K#SF6FJ;uOWF8rua?v4Mx28OWQGT}{v(vHyQduoH zS#qzvxE_Q)t(M@ki`uLOy*_E;OjqB7zM8XG0D1z9ze8fK89XsK4?m9op{=@^e&ZeO z*|>MhXx#?hESb4Dno$TBtd;L4cg4P*!d~?mza^up>Xg^GO|OekglKwu{QUKu8TOnH zMLeZY^y6nZHc=3hC*JJTgo>5CnaLSw*Ss4y93Euju8s$t03>rP)LfkzVudWxe!_xwzL;n10+~WBb4qKe@yr4yf&sGIsC@}hA?F0CFc5i1_RWI&uj)2zo?EKwKNtzTeBi^BHpkZ5|dWEoB zJhaE9&)vpUJjsG+gF%y2;Y21}kc%Gm9Wq0w42TSeP<#4vg5N%520)FAU2eNE;O8%s z?*~U`S0{eU(J%p6k^TWo1yca`xZfWek53gTgXw5ytuOQJDYRjxA4tr}^?m7V(c1W! z2X)BPp1ieEhx3?-={qs|p%~_Erdr5{qh&4j;OS#XH;|0`Pi<`3+%!|x4bORGjvKmQ z^t0M)@PnbGEgR>WF87(tA%QJ{476$-3^i05E=xzKaJ0RxiHsaddl?3n;4ZIP5)?N> zwxdK)eVxFczCoLlwgQbGRO?>5R`;u6sLt}7Wc;-;c1)*LWSw(;j*Ff1Np;%A7?}M% zNR5n7Fq53Kgzys#u?gjK!F+hrmd3@4*^cIC#G=#NlsicA1tpcq6=Bnp`*V_GBymB- z+QJv;{qpv29%fl?Sf;)8E##Wyzk_>kb?BoNP-GwLYe8(u4cn~Bfwhj@Nm5eTw=UqCb z+Sb|0Ue%?qqH;?jm2N@Uc;;w#c^8NZ_brmJ%=|~)y{Xq4=%WZb>4oa`BX`RV)Z` z@pm>T`@Jy}UrwPKBt}&B{M!8&{kGJ>Xo6t8QCSx==&7F{5h`rDtL4EgjOc&nu{&u? zfLfMviIU{)NNJ#JdSLcpg*+k)BEPeMi}Tx(4V>Qj)5#Oqim}+l`V$p@j>bNUG5ZK# z-3ne8*<}dC$&lblN8q90$VcXqcIX9L-#*ZojkHxOt=_|)=Q1rz4OEp5Xeq3dF4ms# zc~&OYuDr^b6=Fk?lhF!v`cTs(vuv*C*#2OZYS+fChK98BQ9}0b@sW}_ePLcvj zj%TNb7O+I+3tI+2V@El48o)~-BdPl=(myNGOR94~P);42oe`&0hme=6r&Z@3gx5RJ z*w)%$x@tP6%|Xtijal}wYK?1;Fo7NCQPu^DFQmYa94MQ%Qd|~j%Uyq~TqNitrIunT z|Cn6SN?$9h%J7n-*YPjL^BcTP+!TqUxkW+#_|k?1y3 zCkEt z8iu5fmRK%rUfIc9u-I`Vb#U(=-r!2ow)4y{LCoRDq-B$)YUMelf|lpl>UD>db6~Xx z2+J|~NVgSZx0DJ2B5IB@uks0kaCQ&9m}afVE6DAzNNM-3*siQ%FzZ#Ypg;OIAGHdb3Oj1YG&a&A~mDb z+Ng%zGtnYl3p&EFS?sLA6?fKVhLNJBv(pnDY_@o{h*Zq^2+=}$P|%PMeacK8NbeIF zrIxPFDViEm(w2t_pCv@V4Fsu*S#`9(u~m;+)2AOXHr5$@KO2}i^ILIELU-X(9at`| zJ4ubex7)B7`ZoPsl@N@sr;DRVRKajv#KT4C3T8)?(;cQKmVxv1 zDQ=n=TOyDy-w#}N&lS5SRAHaoGvKB==)ntzMhQTMcWlheNUjNG$Wj)2P7^gYE!oz% z`c0Hc$6N2-4Yxu;s#HJ+j1|`l*T7{`fF|}v-1dLgf<7@42zPP7cvsxD6@hPp57e`a z^y9^M3{BDWD_4uti}(q6y+^q0TT=BSww7bZDiv#*O^L&5YwM72Mcpo#&L1Dx?^v~| z1iex+=Ft~Kd(7a{RYUn7t!*^W`Jj(+>*Q+Js!Uu^2@qAn`C-6B3i#L^am|8J6zi7# z=8sq88B67|z9-0HnD0DOoC(8ePZO?$eX-iISyjDpO;!o6R@spaob8A&?|)=d*iA1| zPv@oq-<*I8F=`Xdi+IB@VQxVL8Hvw(9Or>K3bJd%aH&Rq(u1jNwHW}ktnP7j9k&*A z7`Y~4SUI+liyS{(#NafW9*mIwNSYHCWC8m|HSMz^z*TN?)-g?~>7;L?^--X)VIYdED4DstSu?M+8tVGQ6C5ak zB&Co%)eGlh6>nn1YN{MH4{XGmO6dp!KwUrfBb>@EVlZYEDh;>NgZ@9*_s1wfnr>|n zE_PLQRTsK!+qP}nwr$(CZQHhO+jiA--_Lo@Idi^mz4OkGnO_rY<;q+Ukr9y*dtdw7 zJ0rFtlF5r*=)2VvfDc011xv}JNDzP0FCM&pU$WJw`z;*aesN?rgoQY*v_i9AT{!HW z>JwkiMiq*8^VTvjK!dqCU1!qy*@n2~3s)voFI++;6w~aLbPZ6&#v7nDzvPLeIVWHn z(5_i1-x~`oBR(5dXSFLc26xX+aZ&ytN|tAeW#9mlkRu?;Ylrf)C#4Ajoi;gqc(vi`6kj12VJ6vpmXNv6>(3#gSZDmry#y4!y zyk41tvl}p^qPI||6FIBzu>p-m6=5Ah@<*tAmm1kB`I2zr{ly#!E*ykEfOei#a)czx zVTI(4A%9?Rxp32%UdN4Ya+cUy-~aRiF|s)~$dDlT)yR2N&OxrVFSyDy6uNw{q}amg zgs`}gW!e|YZd|x3)f=b}9TD%JZ4ywqHI9G4&+kve8^rKbf_egcpKp`{BQb-)UbMW1 zhK5GDBlbc)Os5^kSBDGQ|<#J2~ogw;Me1+Dj+ zlgK=RdEl9WRt1YZd90G<_1?se;%#AJQJzE#Gykg_{(!bWzB8IWAIJb}(uM~|3)2{H zA_tLZ6g8M>b!q0Ggd$GBCw`_`R5?|`UsIq{E4*2}FrL4)O2%6j65jiRJiKJPDz$m$^8<}k)gCRA2 z(x>ct(m05@fd?Ml9dTa~raicUzzYio}Dy1_ydq*oMl1{LU0prrK6eldt~5k+qqsA~2a(3eCKu@ObG z{zC_AQw$*SJHx2%h)g_pJkPl}-HyZSh3(5&r1t}c4gh!W`18y@lB!o(^C#>Cg1zGy zrCpBWiC&qn5aW%&W!IcT(@&3|l-$vJbK`XJ;<6+@d5@WX;pjZKpBOLTHA%MH0d94c z)xY}nKz>9T1dw8>-aEC=4ARLL5t`gVjEYT7e+FkiYjEp8*Fi@v7vLL}gK)(23?sh8 z-I!-8TG2Q|pJA9U2*K1@BOE619bpj#o}26{a?^!N8FcaqtMJHH50o47YTme6ykhe|>rwA!18f!_ z&a%Wm)JiGaNylRxftcCku%8^bPFLU0vAzsNqD%@k_zEIRasgh!aYMXnRg2b3-^1T0 zs2}j0&nWmtnEkXm#asrsn4R~(a8h-V+m3RSz7Y= zHAS>{H9JAsw#u(?O6!@8v@=cG?%LirE0LVPM z5T$C;UFl>C+@)u!JbI5>I(BDVCtVNeXeVvoDpo*mc(127H0G%tLwCv{iNJzEpY#)f zyn$9xviY)EmC&lJWgNB9NW!h%4r-EnG&oIC%A^HOS$CSkfuEiLj1&nIw0eA|ZQF<^ zGTrqdnm=nAVWA4+9(Y5gfNio8<7%`qkxj=1XzJRvYwqK-$xr>aCC^}p67KShGMc`q zgS7q)(W^}Uj-_Ik6LgoZZc~yR7^F3}#NfE;V3u+n{}XqC?V+DPl%c_(7F1ypnu~>K zTn|C`n(fyKnU-waQ_wZ3vjrlPkd09191J2+>b{M7D|o^q zuIfhKn=(JTcJv+4?|rW7q3xa8fLwq=kRaz+qzxI_DyRZBziD%^+qAV}yT-B1UN=d8 zMx!B>TEN1OMSG0liDCeJkx+h)Y+t?0PAF080})NOjkljKUiO6aNp6(Z*`45A+;#$8 zeLO>3O`}2Gpvby<2k}9eagG-=s6r*ikAkMH7)u-}Og#IYMOy-gQwN`LaDZ2*q)d~LrJh59r) znw_O@3mOWrBk>tp!KXL-!SEkx2mr*Wx*G zCB9@3>In4COy7>nT_b@Y33Jg?lBp1bh&;((zNa-ad6D8A29&bHpjTF=Sh*K z$EA>Jt{Voj5;Y)m)*cXgmcQQURp5)p4IBkSnAMl*h>e-r{5m^W^{JC{I`H#ww`S}8_fK?WuxVjq3p?1vN2{W z%g`1u?YdIfgO_LtMt&cArV*@lxm;dN`&Q!PTfPhJ_>P|X)I>r0pQw5`C#`100^Y2{ z>qA2#b4j-qeT$OjGV7}(8qRd2D-9>AipFH@j+9YSB(O2MyhxzchN!xQyB)_O45Xsw z0^Dw58J)-AVab({psZvIILs)5W6_y@dYGW^m}QAESyh4VIpA!gr>iq z>u5#u5=x&<_Gd@W5hfDpWE7wj^m~3U+tDMDVYv>f3%I2N!WFP^i@M0J?=a2Ll4y?j z26iY7e3-a|EyUiJoD_@75${DYyVBGQLQBTJ*=-lB&B*IBlmt?r^p9#GD&gf9NZC&@ zK@9^RLweINUx)M~njj?f*9MFh}l6y#@D-*8*+zOP3MQ5iHPgyFx!+X3Wtg+vo%~A z3(k8IAYwyN&q$ve`;ClWW_=JeO};db-bo;%hHtis7dwcKRsE>T09RSW^W5D z`7|DgSc@_mD@n}2yaSfuXD!D=e??ddkS4&UjXx)d>~Gx_qfsnlyr)=&&QT4>Qn`-t z-G-l|>SDIcn4~(!t^_uj9rUB*$6Ji&W|)LsJ?W!QbHc6b zAi;HK4cI=|rDeT_$Bdb1NoR6ax7JM(-A|LXR1(*Q=3O7fe4j-R4@q`*TDYRj`Kc1t znVAz_g*g;1_;!8@9vKBZB%=D^)%Y1h-Mb2Pc*ywJVHWc8M+oCCFQtLL03qMn5cH)n z^MyVG3YWr1(K=EjBJtx9L5YXH0|7+}i6Op0n%}vM5o+;C!ULf}Kk_*K=)Mqi<$hW2 zKZ%ysh7phEtUFAI0ZH?@Ftc&i3lZnBKR&j33u9N8>8mzrJb2N%3JLF(^Yy)JhP8*% zQlTB^%bj=W7TA7wC2EaN5E%-2!|q_Rq%#kxRrxF%9~`2(aP^`;nZhsa@|s`O zUbzv9qf5x@WsYJ_K+`-N+IW-7Sm|avr6o&jtT=FsWKv#Y9Ve`AtHufHamv6MDgdwt zxn`b?EM7p1(4v@0z0Ek$s48zA%9W?YVs!Hl*E7>ZNmq*IxggAox)bG(T+eVmuSTeH z=ES;_n{S5C_A#vwVAGq+9aEp67WvqS^O5=LEXtMoQ~&_KVgK$0Fz7Thhep!&S$(fw z9|?(8$k_70x>~IhB*pigK_)!xap+$hF@qqPWj)6%>59Xh3+s$zye6Wdi_E?!$Yi8o0 zvoJnzJ5cgXh9*nWtSS8H9+=72&&aW{&>yb{(`n*t@GxgvlwfI&_az_wbtBC`O4?09 zzyd#-j=H**QPmN+6%%H4+-U7kPP+sdE1XgxU|=R~);;P}7~=5}d&=Bk@+EwaB&%?- zu)2MD=hIXp2`s~IdHl0lJ7^mU(IeQCoH;w(Q*IT?GOGj0YmjZv2eX=gkJeta;E3zT4BCUM5`#SY~pd0LMSj)rLLA@^_1ExW#*VPxSVrAtya@7PD-_M~u@$C@K zhDp!m5Iw)wT5j?nvk_{%Jhj+_#zv*<9)Ve>8=WIpWb^qd%St7K;!7+;j<%+?uOL9+ z2b^s7DkdwwMKbZt{59ESvqsMOj%an}o6_MO;T*fuLt_KL-aOz zpT9hR9Qc2jZF+UTwsfF2D3K-FxeH>`=)tvDfki5KI;Y)|yIs%@+%)1xMU>~}+79Yd z&&QrP{+_s_QfN5}Qv-ed(d{qbZh6kXYJgi42-hhDu zNwA6SPY?J3v^|2MM*}_L4o9k4aMBRRc|b@@vhFev+haCDypgk$;@BJ_WRidK%N|Qg zW;|X;>Z~f+clYgYq`(md+D?657vJawZE(&pN=FJl z{qQjf!V%X`(QXjl=X$WATY;QPwLjog&(wNljdfC^!TRQt9f3)U)Ul^d}7=1`9dZ&AlQ&@z&Y0(2QSy zs<-H``>HNirc#-K=*jJEoD~!LW@J;X;UC)F+4$-y7E)R_jggYlNF<9gpAUL_?`VBI zrTEp^o#v=O%Sf3o#(ULE7MKD{szN;2zC#v-)H8=6dx>*B~`F@mA} zkF+0gCxFCxCDK2|tA^Hzj2J`LeL{{11B~)a#@X1If2FU}Hj142l zRc*u?;3M5f0V$=+4-^6>h`OfFjJG9z$?UV;rctb{15{|Ud`a7kdEX1RN~NIU29dq( z3A{k_8AGV^Fi4%!A`U#rX8P&F4IOa2zh%WzJJ|H1rJnv{pIr>WkXYLldZi}1-^>?ATp*k8$!lGj)Wv7 zBk|%iUG$UVNmtGZY;J0M1y~K5IsEx+u6PdpIxKtu(_$YA{kjiZ;clMeQ4F zC&)#y3q(*3LJJJvOiTcD^&yPM+c3fQUgc0TE}gnx)82tz0PX!TK9?Lubw6KJ{fB37 z-ls9VDXc*~&`qukiB!WFuC{5j41Hv%sCLDf;4#BjxtYa_TIC|*PdAi+la4Qg5M3xL zGE29aN;E}tt~NE`@FW~Lu@be#>?q#e%6ZT4MUp(D9y#|I$!@hyzgFZzdC=hm7^Q-4 z3OB%|RS@}RsZBE1yRfH~*sf^=_v?->If%eLfpUzyL?brS=%bM5v|8?Pt+z%6a}t5$ zSuj4RcMEq7kKPl#D5ulUP~-J-#XvP)4kUt@k?H&{zWlVf3r`! zTdH)cpnkJ1KG0Q$FSdbuJ1`Qbh%4ny$rmm_aIREHnOJk_37%3ns438mmcoaEIhzf5;Jtw;ceUL;xSA? zqeaHZ&1S9|zE~7WoBnsAPf^mBcLiH~qXM)Qn`NdZCKnOiR9#A#YHdc+wVIBTkx2_U zr%AZ>%%v$#n`In2nUi-3&w3#gE>9>9g2$}rMznUb*MWsUTq3eD;I8!}rpy>^Jd2Rjf4LHJLaNh5 zmak_2R5XV&_PTA34tuQ)d`ZG|<)MY#XlK->&T!(^Z&^GoYWZaMQJ#ANJa}s)ojt^d-y5D-gy=nE|5#awHX+KOb4=M)DA(!2xQE=cig0Cr2!Y-sk z3fu~ih3@l5F{NX+*l*1SHjnZEtQo!{mJEzp)eX2{ZRH{^d2M=WVAIgclD?oZ{em09 z#!VUH3LWfS+(){q6T;rna3lXX!^WiIBw)Fpo1#?tqLon(b0Vg{Oo1`!_h_!5N`L=| zKJQ1CGlps$aFWx-Kcv;3jf@8$dRfUv`wF1-wLo$-f`5U@mxKPz1v|}_!~YTf?;@wF-sp%9t1ir&;v*t6THoYtb-bnD#&QL)dg zDgXmi!xvj*;xmGVTDI(4ILlAQt-aGMTnu`%EI4WUnjuVASPvoN@i=T}G@UET8^c5X}VcR0=Vu=Pq(vVU~BS$#0kRB-S(H#42$BU%b zBs0q;kf{d((-$Zl8>*G~5%lv)m7w5?=XK7~XU)6Jt-Iw-vO?PBlXx)GBIy*Q<(z+8 zAyWbp;w)KG319^IR||^g(hjbX3k)=nlhX-%nCC)nusDHCa+dKaWd5gNTcoXTB*@!$ zN&I9Ma^1fWH>WbK)(X~y6lm&m?m7>c#7S$H2B-!SQDq^e}CTU2wJw;Z-1QvIgqt|Ds~q-NuD(J zY$jYj3H@~dXPHN`d&r-(p@%SMZg7jxt}lbT!UqI|Miy>x${vZQ6PyXxIb16f0!hZr zs0JwrAOX2gBj_cRh#^=Aqc8Qse%bX&*2Uzg75<7n&dVeAMpA}G8K_98Cr>S*Cxzto z2AW7St5!nAz5l+lxT~xsmhiM+z`ziDF!HO;{XZw$Ks}fwDoqT`=5}@H^!5jn?K#Mw zoY!w`4j;|H?snWEO%A5O+qb{j67ukrHbpjBTW^Fe#I$Zms(@ zVP7>qQ?tREBm>bmF0z9d}evovVS&|S z{4+G;*--W|T|Oh?E{`ADyU^!KhdQg?xOEy3Wr+nWE|>_u0SX{#BQyR5p5fM4c%q!t z;|B?;VKGq&op>Q)YtuOiBzbDW`VI~Gk0R6h{a%8>n|IGghOWdpFweC7(O6l(o&$9` zMZ#VFXeTr(-qA|r$N>Xd(u#>O?-CKu5ZyafV#6ik+K&beT7jq}h9Y2mM)T8v22Nah z#0II@T^a}m;NPO5_T||>UTzBYf7P+ePG$DD)WpQ2y&G8i8BylSU9UL3Q6bW&Rka@) z4wwzv6%;~xBvlv{^qZEVN+VIaprAX?F(4C^$C0TO%gjhz2N|FC;b`-j!+Uh{9b1Ha zzk_kW#|J0oMrfM}H5ip|%Y|Ydy7^%7;0DYg-8UxBnEmj3q5aae*bs#;H&Cprpz=r0 zDim)4!h2YE={Qj||7j`rGgq#DM!3{kjxuQl;tbN-&{L~+8K*o|rtvGl`EUOQ?tDsw zCYgBsx_Bc%KjMqhYmRz2P3)Ya-(9C$?ZH)@sm_y(1-8j5C1)xKNgkn}&u8>YZ<7^6 z6KGr45-wssp_1|`G?t*~oA;Vt=&xK@#j+Z5#9ZM?;CixMohxD@!0wMQWi=DywVUUjC z|~jv|6ZiQ0XsGKoJLDW8WD;q09$RvV+HQX8+sL zwK7InUmjvbfyN(wh*)jA@67VQk*?;WXSjK?bIb^5L9=52yb#tASP+yA_`59zWdOcj zq~;pI+f+)-z;8(m54MAhW06-7^;0I%t5mLKPOfsU8#ODALm2eVfX?V}AZ=}g2{&Kr ziqY?HgdqhS0?UCT_rf{s$1)J#sE`xCGgcK#b&2Z%@zy^e0tt}Vi+ci)CKD2pv(#Hrt zuuPyjLec$f&99ImK!^AsLln-^{B(l?A@CyzYz@JLFGO(*Xbw༏Qpp3xpwxmwa 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