1 .\" $NetBSD: puffs_framebuf.3,v 1.27 2009/11/22 18:40:26 mbalmer Exp $
3 .\" Copyright (c) 2007 Antti Kantee. All rights reserved.
5 .\" Redistribution and use in source and binary forms, with or without
6 .\" modification, are permitted provided that the following conditions
8 .\" 1. Redistributions of source code must retain the above copyright
9 .\" notice, this list of conditions and the following disclaimer.
10 .\" 2. Redistributions in binary form must reproduce the above copyright
11 .\" notice, this list of conditions and the following disclaimer in the
12 .\" documentation and/or other materials provided with the distribution.
14 .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 .Nd buffering and event handling for networked file systems
36 .Ft struct puffs_framebuf *
37 .Fn puffs_framebuf_make
39 .Fn puffs_framebuf_destroy "struct puffs_framebuf *pufbuf"
41 .Fn puffs_framebuf_recycle "struct puffs_framebuf *pufbuf"
43 .Fn puffs_framebuf_reserve_space "struct puffs_framebuf *pufbuf" "size_t space"
45 .Fo puffs_framebuf_putdata
46 .Fa "struct puffs_framebuf *pufbuf" "const void *data" "size_t dlen"
49 .Fo puffs_framebuf_putdata_atoff
50 .Fa "struct puffs_framebuf *pufbuf" "size_t offset" "const void *data"
54 .Fo puffs_framebuf_getdata
55 .Fa "struct puffs_framebuf *pufbuf" "void *data" "size_t dlen"
58 .Fo puffs_framebuf_getdata_atoff
59 .Fa "struct puffs_framebuf *pufbuf" "size_t offset"
60 .Fa "void *data" "size_t dlen"
63 .Fn puffs_framebuf_telloff "struct puffs_framebuf *pufbuf"
65 .Fn puffs_framebuf_tellsize "struct puffs_framebuf *pufbuf"
67 .Fn puffs_framebuf_remaining "struct puffs_framebuf *pufbuf"
69 .Fn puffs_framebuf_seekset "struct puffs_framebuf *pufbuf" "size_t offset"
71 .Fo puffs_framebuf_getwindow
72 .Fa "struct puffs_framebuf *pufbuf" "size_t offset"
73 .Fa "void **winp" "size_t *winlen"
76 .Fo puffs_framev_enqueue_cc
77 .Fa "struct puffs_cc *pcc" "int fd" "struct puffs_framebuf *pufbuf" "int flags"
81 .Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
82 .Fa "void *arg" "int flags"
86 .Fo puffs_framev_enqueue_cb
87 .Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
88 .Fa "puffs_framebuf_cb fcb" "void *fcb_arg" "int flags"
91 .Fo puffs_framev_enqueue_justsend
92 .Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
93 .Fa "int waitreply" "int flags"
96 .Fo puffs_framev_enqueue_directsend
97 .Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
101 .Fo puffs_framev_enqueue_directreceive
102 .Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
106 .Fo puffs_framev_framebuf_ccpromote
107 .Fa "struct puffs_framebuf *pufbuf" "struct puffs_cc *pcc"
110 .Fn puffs_framev_enqueue_waitevent "struct puffs_cc *pcc" "int fd" "int *what"
112 .Fo puffs_framev_readframe_fn
113 .Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pufbuf"
114 .Fa "int fd" "int *done"
117 .Fo puffs_framev_writeframe_fn
118 .Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pufbuf"
119 .Fa "int fd" "int *done"
122 .Fo puffs_framev_cmpframe_fn
123 .Fa "struct puffs_usermount *pu"
124 .Fa "struct puffs_framebuf *cmp1" "struct puffs_framebuf *cmp2" "int *notresp"
127 .Fo puffs_framev_gotframe_fn
128 .Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pufbuf"
131 .Fo puffs_framev_fdnotify_fn
132 .Fa "struct puffs_usermount *pu" "int fd" "int what"
135 .Fo puffs_framev_init
136 .Fa "struct puffs_usermount *pu"
137 .Fa "puffs_framev_readframe_fn rfb" "puffs_framev_writeframe_fn wfb"
138 .Fa "puffs_framev_cmpframe_fn cmpfb" "puffs_framev_gotframe_fn gotfb"
139 .Fa "puffs_framev_fdnotify_fn fdnotfn"
142 .Fn puffs_framev_addfd "struct puffs_usermount *pu" "int fd" "int what"
144 .Fn puffs_framev_enablefd "struct puffs_usermount *pu" "int fd" "int what"
146 .Fn puffs_framev_disablefd "struct puffs_usermount *pu" "int fd" "int what"
148 .Fn puffs_framev_removefd "struct puffs_usermount *pu" "int fd" "int error"
150 .Fo puffs_framev_unmountonclose
151 .Fa "struct puffs_usermount *pu" "int fd" "int what"
156 routines provide buffering and an event loop structured around the
158 It operates on top of the puffs continuation framework,
160 and multiplexes execution automatically to an instance whenever
163 The file system is entered in three different ways:
164 .Bl -bullet -offset indent
166 An event arrives from the kernel and the
168 callbacks are called to start processing the event.
170 A file system which has sent out a request receives a response.
171 Execution is resumed from the place where the file system yielded.
173 A request from a peer arrives.
174 A request is an incoming PDU which is not a response to any outstanding
179 is used by defining various callbacks and providing I/O descriptors,
180 which are then monitored for activity by the library.
181 A descriptor, when present, can be either enabled or disabled for
183 If a descriptor is not enabled for a certain direction, the callbacks
184 will not be called even if there were activity on the descriptor.
185 For example, even if a network socket has been added and there is
186 input data in the socket buffer, the read callback will be called
187 only if the socket has been enabled for reading.
189 File descriptors are treated like sockets: they have two sides, a read
190 side and a write side.
191 The framework determines that one side of the descriptor has been
192 closed if the supplied I/O callbacks return an error or if the I/O
193 multiplexing call says a side has been closed.
194 It is still possible, from the framework perspective, to write to a
195 file descriptor whose read side is closed.
196 However, it is not possible to wait for a response on such a file
198 Conversely, it is possible to read responses from a descriptor whose
199 write side is closed.
200 It should be stressed that the implementation underlying the file
201 descriptor might not support this.
203 The following callbacks can be defined, cf.
204 .Fn puffs_framev_init ,
205 and all are optional.
206 None of them should block, because this would cause the entire file server
208 One option is to make the descriptors non-blocking before adding them.
209 .Bl -tag -width "xfdnotfnx"
211 Read a frame from the file descriptor onto the specified buffer.
213 Write a frame from the specified buffer into the file descriptor.
215 Identify if a buffer is the response to the specified buffer.
217 Called iff no outstanding request matches the incoming frame.
218 In other words, this is called when we receive a request from a peer.
220 Receive notifications about a change-of-state in a file descriptor's
224 Better descriptions for each callback are given below.
228 provide automatic memory management of buffers for the file servers.
229 They provide a cursor to the current buffer offset.
230 Reading or writing data through the normal routines will advance that cursor.
231 Additionally, the buffer size is provided to the user.
232 It represents the maximum offset where data was written.
234 Generally the write functions will fail if the cannot allocate enough
235 memory to satisfy the buffer length requirements.
236 Read functions will fail if the amount of data written to the buffer
237 is not large enough to satisfy the read.
239 .It Fn puffs_framebuf_make
241 Return the address of the buffer or
243 in case no memory was available.
244 .It Fn puffs_framebuf_destroy pufbuf
245 Free memory used by buffer.
246 .It Fn puffs_framebuf_recycle pufbuf
247 Reset offsets so that buffer can be reused.
248 Does not free memory or reallocate memory.
249 .It Fn puffs_framebuf_reserve_space pufbuf space
250 Make sure that the buffer has
252 bytes of available memory starting from the current offset.
253 This is not strictly necessary, but can be used for optimizations
254 where it is known in advance how much memory will be required.
255 .It Fn puffs_framebuf_putdata pufbuf data dlen
258 amount of data from the address
261 Moves the offset cursor forward
264 .It Fn puffs_framebuf_putdata_atoff pufbuf offset data dlen
266 .Fn puffs_framebuf_putdata ,
267 except writes data at buffer offset
269 It is legal to write past the current end of the buffer.
270 Does NOT modify the current offset cursor.
271 .It Fn puffs_framebuf_getdata pufbuf data dlen
274 bytes of data from the buffer into
276 Advances the offset cursor.
277 .It Fn puffs_framebuf_getdata_atoff pufbuf offset data dlen
278 Read data from buffer position
280 Does NOT modify the offset cursor.
281 .It Fn puffs_framebuf_telloff pufbuf
282 Return the offset into the buffer.
283 .It Fn puffs_framebuf_tellsize pufbuf
284 Return the maximum offset where data has been written, i.e. buffer size.
285 .It Fn puffs_framebuf_remaining pufbuf
286 Distance from current offset to the end of the buffer, i.e. size-offset.
287 .It Fn puffs_framebuf_seekset pufbuf offset
288 Set the offset cursor to the position
290 This does NOT modify the buffer size, but reserves at least
291 enough memory memory for a write to
293 and will fail if memory cannot be allocated.
294 .It Fn puffs_framebuf_getwindow pufbuf offset winp winlen
295 Get a direct memory window into the buffer starting from
297 The maximum mapped window size will be
299 bytes, but this routine might return a smaller window and the caller
300 should always check the actual mapped size after the call.
301 The window is returned in
303 This function not modify the buffer offset, but it DOES set the buffer
307 in case that value is greater than the current size.
308 The window is valid until the next until the next
310 call operating on the buffer in question.
311 .It Fn puffs_framev_enqueue_cc pcc fd pufbuf flags
314 to outgoing queue of descriptor
316 and yield with the continuation
318 Execution is resumed once a response is received.
319 Returns 0 if the buffer was successfully enqueued (not necessarily
320 delivered) and non-zero to signal a non-recoverable error.
322 Usually the buffer is placed at the end of the output queue.
326 .Dv PUFFS_FBQUEUE_URGENT ,
328 is placed in the front of the queue to be sent immediately after
329 the current PDU (if any) has been sent.
330 .It Fn puffs_framev_enqueue_cb pu fd pufbuf fcb fcb_arg flags
333 for outgoing data and immediately return.
334 Once a response arrives, the callback
336 will be called with the argument
338 The callback function
340 is responsible for freeing the buffer.
341 Returns 0 if the buffer was successfully enqueued (not necessarily
342 delivered) and non-zero to signal a non-recoverable error.
345 .Fn puffs_framev_enqueue_cc
348 .It Fn puffs_framev_cb pu pufbuf arg error
350 Called when a response to a specific request arrives from the server.
353 is non-zero, the framework was unable to obtain a response and the
354 function should not examine the contents of
356 only do resource cleanup.
358 .It Fn puffs_framev_enqueue_justsend pu fd pufbuf waitreply flags
361 for outgoing traffic and immediately return.
364 can be used to control if the buffer is to be freed immediately after
365 sending of if a response is expected and the buffer should be freed
366 only after the response arrives (receiving an unexpected message from
367 the server is treated as an error).
368 Returns 0 if the buffer was successfully enqueued (not necessarily
369 delivered) and non-zero to signal a non-recoverable error.
372 .Fn puffs_framev_enqueue_cc
375 .It Fn puffs_framev_enqueue_directsend pcc fd pufbuf flags
377 .Fn puffs_framev_enqueue_justsend
378 with the exception that the call yields until the frame has been sent.
380 .Fn puffs_framev_enqueue_cc ,
381 the routine does not wait for input, but returns immediately after
385 .Fn puffs_framev_enqueue_cc
388 .It Fn puffs_framev_enqueue_directreceive pcc fd pufbuf flags
391 This routine yields until a complete frame has been read into
392 the buffer by the readframe routine.
395 .Fn puffs_framev_enqueue_cc
398 .It Fn puffs_framev_framebuf_ccpromote pufbuf pcc
399 Promote the framebuffer
402 .Fn puffs_framev_enqueue_cb
404 .Fn puffs_framev_enqueue_justsend
407 and yield until the result arrives.
408 The response from the file server for
410 must not yet have arrived.
412 .Fn puffs_framev_enqueue_justsend ,
413 the call must be expecting a response.
414 .It Fn puffs_framev_enqueue_waitevent pcc fd what
415 Waits for an event in
417 to happen on file descriptor
419 The events which happened are returned back in
421 The possible events are
422 .Dv PUFFS_FBIO_READ ,
423 .Dv PUFFS_FBIO_WRITE ,
425 .Dv PUFFS_FBIO_ERROR ,
426 specifying read, write and error conditions, respectively.
427 Error is always checked.
429 This call does not depend on if the events were previously enabled on
430 the file descriptor - the specified events are always checked
433 There is currently no other way to cancel or timeout a call except by
434 removing the file descriptor in question.
435 This may change in the future.
436 .It Fn puffs_framev_readframe_fn pu pufbuf fd done
438 Read at most one frame from file descriptor
442 If a complete frame is read, the value pointed to by
445 This function should return 0 on success (even if a complete frame was not
446 yet read) and a non-zero
448 to signal a fatal error.
449 In case a fatal error is returned, the read side of the file descriptor
451 This routine will be called with the same buffer argument until a
452 complete frame has been read.
454 .It Fn puffs_framev_writeframe_fn pu pufbuf fd done
455 Write the frame contained in
457 to the file descriptor
459 In case the entire frame is successfully written,
462 This function should return 0 on success (even if a complete frame was not
463 yet written) and a non-zero
465 to signal a fatal error.
466 In case a fatal error is returned, the write side of the file descriptor
468 This routine will be called with the same buffer argument until the
469 complete frame has been written.
472 It is a good idea to make sure that this function can handle a possible
474 caused by a closed connection.
475 For example, the file server can opt to trap
477 or, if writing to a socket, call
483 .It Fn puffs_framev_cmpframe_fn pu pufbuf_cmp1 pufbuf_cmp2 notresp
484 Compare the file system internal request tags in
488 Should return 0 if the tags are equal, 1 if first buffer's tag is
489 greater than the second and \-1 if it is smaller.
490 The definitions "greater" and "smaller" are used transparently by
491 the library, e.g. like
493 If it can be determined from
495 that it is not a response to any outstanding request,
497 should be set to non-zero.
500 to skip the test of the buffer against the rest of the outstanding
503 .It Fn puffs_framev_gotframe_fn pu pufbuf
504 Called when no outstanding request matches an incoming frame.
507 is transferred to the called function and must be destroyed once
510 .It Fn puffs_framev_fdnotify_fn pu fd what
511 Is called when the read or write side of the file descriptor
514 It is called once for each side, the bitmask parameter
516 specified what is currently closed:
520 for read and write, respectively.
521 .It Fn puffs_framev_init pu rfb wfb cmpfb gotfb fdnotfn
522 Initializes the given callbacks to the system.
523 They will be used when
526 The framework provides the routines
527 .Fn puffs_framev_removeonclose
529 .Fn puffs_framev_unmountonclose ,
530 which can be given as
532 The first one removes the file descriptor once both sides are closed
533 while the second one unmounts the file system and exits the mainloop.
534 .It Fn puffs_framev_addfd pu fd what
537 to be handled by the framework.
538 It is legal to add a file descriptor either before calling
540 or at time when running.
543 controls enabling of input and output events and can be a bitwise
547 .Dv PUFFS_FBIO_WRITE .
548 If not specified, the descriptor will be in a disabled state.
549 .It Fn puffs_framev_enablefd pu fd error
550 Enable events of type
554 .It Fn puffs_framev_disablefd pu fd error
555 Disable events of type
559 .It Fn puffs_framev_removefd pu fd error
560 Remove file descriptor
562 from the list of descriptors handled by the framework.
563 Removing a file descriptor causes all operations blocked either on
564 output or input to be released with the error value
566 In case 0 is supplied as this parameter,
572 explicitly remove each fd it has added.
573 A good place to do this is
574 .Fn puffs_framev_fdnotify_fn
576 .Fn puffs_node_reclaim ,
577 depending a little on the structure of the file system.
578 .It Fn puffs_framev_unmountonclose pu fd what
579 This is library provided convenience routine for
580 .Fn puffs_framev_fdnotify_fn .
581 It unmounts the file system when both the read and write side are
583 It is useful for file systems such as
585 which depend on a single connection.
595 .Pa src/usr.sbin/puffs/mount_psshfs
597 .Pa src/usr.sbin/puffs/mount_9p
598 for the respective usage examples.
600 These functions generally return \-1 to signal error and set
602 to indicate the type of error.
610 .%I Helsinki University of Technology
611 .%R Tech Report TKK-TKO-B157
612 .%T Using puffs for Implementing Client-Server Distributed File Systems
617 .%J Proceedings of AsiaBSDCon 2008
619 .%T Send and Receive of File System Protocols: Userspace Approach With puffs