1*388550b0Srillig /* $NetBSD: framebuf.c,v 1.37 2022/04/19 20:32:17 rillig Exp $ */
2b223c403Spooka
3b223c403Spooka /*
4b223c403Spooka * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5b223c403Spooka *
6b223c403Spooka * Development of this software was supported by the
7b223c403Spooka * Finnish Cultural Foundation.
8b223c403Spooka *
9b223c403Spooka * Redistribution and use in source and binary forms, with or without
10b223c403Spooka * modification, are permitted provided that the following conditions
11b223c403Spooka * are met:
12b223c403Spooka * 1. Redistributions of source code must retain the above copyright
13b223c403Spooka * notice, this list of conditions and the following disclaimer.
14b223c403Spooka * 2. Redistributions in binary form must reproduce the above copyright
15b223c403Spooka * notice, this list of conditions and the following disclaimer in the
16b223c403Spooka * documentation and/or other materials provided with the distribution.
17b223c403Spooka *
18b223c403Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19b223c403Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20b223c403Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21b223c403Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b223c403Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b223c403Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24b223c403Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b223c403Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b223c403Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b223c403Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b223c403Spooka * SUCH DAMAGE.
29b223c403Spooka */
30b223c403Spooka
31343e8df3Spooka /*
32343e8df3Spooka * The event portion of this code is a twisty maze of pointers,
33343e8df3Spooka * flags, yields and continues. Sincere aplogies.
34343e8df3Spooka */
35343e8df3Spooka
36b223c403Spooka #include <sys/cdefs.h>
37b223c403Spooka #if !defined(lint)
38*388550b0Srillig __RCSID("$NetBSD: framebuf.c,v 1.37 2022/04/19 20:32:17 rillig Exp $");
39b223c403Spooka #endif /* !lint */
40b223c403Spooka
41b223c403Spooka #include <sys/types.h>
42b223c403Spooka #include <sys/queue.h>
43b223c403Spooka
44b223c403Spooka #include <assert.h>
45b223c403Spooka #include <errno.h>
46b223c403Spooka #include <poll.h>
47b223c403Spooka #include <puffs.h>
4861113f40Spooka #include <stdio.h>
49b223c403Spooka #include <stdlib.h>
502b8177d9Spooka #include <unistd.h>
51b223c403Spooka
52b223c403Spooka #include "puffs_priv.h"
53b223c403Spooka
54b223c403Spooka struct puffs_framebuf {
55b223c403Spooka struct puffs_cc *pcc; /* pcc to continue with */
56b223c403Spooka /* OR */
57291fe845Spooka puffs_framev_cb fcb; /* non-blocking callback */
58b223c403Spooka void *fcb_arg; /* argument for previous */
59b223c403Spooka
60b223c403Spooka uint8_t *buf; /* buffer base */
61b223c403Spooka size_t len; /* total length */
62b223c403Spooka
63b223c403Spooka size_t offset; /* cursor, telloff() */
64b223c403Spooka size_t maxoff; /* maximum offset for data, tellsize() */
65b223c403Spooka
66291fe845Spooka volatile int rv; /* errno value */
67b223c403Spooka
68b223c403Spooka int istat;
69b223c403Spooka
70b223c403Spooka TAILQ_ENTRY(puffs_framebuf) pfb_entries;
71b223c403Spooka };
72b223c403Spooka #define ISTAT_NODESTROY 0x01 /* indestructible by framebuf_destroy() */
73b223c403Spooka #define ISTAT_INTERNAL 0x02 /* never leaves library */
74b223c403Spooka #define ISTAT_NOREPLY 0x04 /* nuke after sending */
758c9c68dbSpooka #define ISTAT_DIRECT 0x08 /* receive directly, no moveinfo */
76b223c403Spooka
77866bcfbbSpooka #define ISTAT_ONQUEUE ISTAT_NODESTROY /* alias */
78866bcfbbSpooka
79cc2ad436Spooka #define PUFBUF_INCRALLOC 4096
80b223c403Spooka #define PUFBUF_REMAIN(p) (p->len - p->offset)
81b223c403Spooka
82343e8df3Spooka /* for poll/kqueue */
83343e8df3Spooka struct puffs_fbevent {
84343e8df3Spooka struct puffs_cc *pcc;
85343e8df3Spooka int what;
86343e8df3Spooka volatile int rv;
87343e8df3Spooka
88343e8df3Spooka LIST_ENTRY(puffs_fbevent) pfe_entries;
89343e8df3Spooka };
90343e8df3Spooka
912b8177d9Spooka static struct puffs_fctrl_io *
getfiobyfd(struct puffs_usermount * pu,int fd)922b8177d9Spooka getfiobyfd(struct puffs_usermount *pu, int fd)
932b8177d9Spooka {
942b8177d9Spooka struct puffs_fctrl_io *fio;
952b8177d9Spooka
9661113f40Spooka LIST_FOREACH(fio, &pu->pu_ios, fio_entries)
972b8177d9Spooka if (fio->io_fd == fd)
982b8177d9Spooka return fio;
992b8177d9Spooka return NULL;
1002b8177d9Spooka }
1012b8177d9Spooka
102b223c403Spooka struct puffs_framebuf *
puffs_framebuf_make(void)1039e66e6d7Sabs puffs_framebuf_make(void)
104b223c403Spooka {
105b223c403Spooka struct puffs_framebuf *pufbuf;
106b223c403Spooka
107b223c403Spooka pufbuf = malloc(sizeof(struct puffs_framebuf));
108b223c403Spooka if (pufbuf == NULL)
109b223c403Spooka return NULL;
110b223c403Spooka memset(pufbuf, 0, sizeof(struct puffs_framebuf));
111b223c403Spooka
112b223c403Spooka pufbuf->buf = malloc(PUFBUF_INCRALLOC);
113b223c403Spooka if (pufbuf->buf == NULL) {
114b223c403Spooka free(pufbuf);
115b223c403Spooka return NULL;
116b223c403Spooka }
117cc2ad436Spooka pufbuf->len = PUFBUF_INCRALLOC;
118b223c403Spooka
119b223c403Spooka puffs_framebuf_recycle(pufbuf);
120b223c403Spooka return pufbuf;
121b223c403Spooka }
122b223c403Spooka
123b223c403Spooka void
puffs_framebuf_destroy(struct puffs_framebuf * pufbuf)124b223c403Spooka puffs_framebuf_destroy(struct puffs_framebuf *pufbuf)
125b223c403Spooka {
126b223c403Spooka
127b223c403Spooka assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
128b223c403Spooka
129b223c403Spooka free(pufbuf->buf);
130b223c403Spooka free(pufbuf);
131b223c403Spooka }
132b223c403Spooka
133b223c403Spooka void
puffs_framebuf_recycle(struct puffs_framebuf * pufbuf)134b223c403Spooka puffs_framebuf_recycle(struct puffs_framebuf *pufbuf)
135b223c403Spooka {
136b223c403Spooka
137b223c403Spooka assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
138b223c403Spooka
139b223c403Spooka pufbuf->offset = 0;
140b223c403Spooka pufbuf->maxoff = 0;
141b223c403Spooka pufbuf->istat = 0;
142b223c403Spooka }
143b223c403Spooka
144b223c403Spooka static int
reservespace(struct puffs_framebuf * pufbuf,size_t off,size_t wantsize)145b223c403Spooka reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize)
146b223c403Spooka {
147b223c403Spooka size_t incr;
148b223c403Spooka void *nd;
149b223c403Spooka
150b223c403Spooka if (off <= pufbuf->len && pufbuf->len - off >= wantsize)
151b223c403Spooka return 0;
152b223c403Spooka
153b223c403Spooka for (incr = PUFBUF_INCRALLOC;
154b223c403Spooka pufbuf->len + incr < off + wantsize;
155b223c403Spooka incr += PUFBUF_INCRALLOC)
156b223c403Spooka continue;
157b223c403Spooka
1582049bce7Spooka nd = realloc(pufbuf->buf, pufbuf->len + incr);
159b223c403Spooka if (nd == NULL)
160b223c403Spooka return -1;
161b223c403Spooka
162b223c403Spooka pufbuf->buf = nd;
163b223c403Spooka pufbuf->len += incr;
164b223c403Spooka
165b223c403Spooka return 0;
166b223c403Spooka }
167b223c403Spooka
168b223c403Spooka int
puffs_framebuf_dup(struct puffs_framebuf * pb,struct puffs_framebuf ** pbp)16961113f40Spooka puffs_framebuf_dup(struct puffs_framebuf *pb, struct puffs_framebuf **pbp)
17061113f40Spooka {
17161113f40Spooka struct puffs_framebuf *newpb;
17261113f40Spooka
17361113f40Spooka newpb = puffs_framebuf_make();
17461113f40Spooka if (newpb == NULL) {
17561113f40Spooka errno = ENOMEM;
17661113f40Spooka return -1;
17761113f40Spooka }
17861113f40Spooka memcpy(newpb, pb, sizeof(struct puffs_framebuf));
17961113f40Spooka
18061113f40Spooka newpb->buf = NULL;
18161113f40Spooka newpb->len = 0;
18261113f40Spooka if (reservespace(newpb, 0, pb->maxoff) == -1) {
18361113f40Spooka puffs_framebuf_destroy(newpb);
18461113f40Spooka return -1;
18561113f40Spooka }
18661113f40Spooka
18761113f40Spooka memcpy(newpb->buf, pb->buf, pb->maxoff);
18861113f40Spooka newpb->istat = 0;
18961113f40Spooka *pbp = newpb;
19061113f40Spooka
19161113f40Spooka return 0;
19261113f40Spooka }
19361113f40Spooka
19461113f40Spooka int
puffs_framebuf_reserve_space(struct puffs_framebuf * pufbuf,size_t wantsize)195b223c403Spooka puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
196b223c403Spooka {
197b223c403Spooka
198b223c403Spooka return reservespace(pufbuf, pufbuf->offset, wantsize);
199b223c403Spooka }
200b223c403Spooka
201b223c403Spooka int
puffs_framebuf_putdata(struct puffs_framebuf * pufbuf,const void * data,size_t dlen)202b223c403Spooka puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
203b223c403Spooka const void *data, size_t dlen)
204b223c403Spooka {
205b223c403Spooka
206b223c403Spooka if (PUFBUF_REMAIN(pufbuf) < dlen)
207b223c403Spooka if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
208b223c403Spooka return -1;
209b223c403Spooka
210b223c403Spooka memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
211b223c403Spooka pufbuf->offset += dlen;
212b223c403Spooka
213b223c403Spooka if (pufbuf->offset > pufbuf->maxoff)
214b223c403Spooka pufbuf->maxoff = pufbuf->offset;
215b223c403Spooka
216b223c403Spooka return 0;
217b223c403Spooka }
218b223c403Spooka
219b223c403Spooka int
puffs_framebuf_putdata_atoff(struct puffs_framebuf * pufbuf,size_t offset,const void * data,size_t dlen)220b223c403Spooka puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
221b223c403Spooka const void *data, size_t dlen)
222b223c403Spooka {
223b223c403Spooka
224b223c403Spooka if (reservespace(pufbuf, offset, dlen) == -1)
225b223c403Spooka return -1;
226b223c403Spooka
227b223c403Spooka memcpy(pufbuf->buf + offset, data, dlen);
228b223c403Spooka
229b223c403Spooka if (offset + dlen > pufbuf->maxoff)
230b223c403Spooka pufbuf->maxoff = offset + dlen;
231b223c403Spooka
232b223c403Spooka return 0;
233b223c403Spooka }
234b223c403Spooka
235b223c403Spooka int
puffs_framebuf_getdata(struct puffs_framebuf * pufbuf,void * data,size_t dlen)236b223c403Spooka puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
237b223c403Spooka {
238b223c403Spooka
239b223c403Spooka if (pufbuf->maxoff < pufbuf->offset + dlen) {
240b223c403Spooka errno = ENOBUFS;
241b223c403Spooka return -1;
242b223c403Spooka }
243b223c403Spooka
244b223c403Spooka memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
245b223c403Spooka pufbuf->offset += dlen;
246b223c403Spooka
247b223c403Spooka return 0;
248b223c403Spooka }
249b223c403Spooka
250b223c403Spooka int
puffs_framebuf_getdata_atoff(struct puffs_framebuf * pufbuf,size_t offset,void * data,size_t dlen)251b223c403Spooka puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
252b223c403Spooka void *data, size_t dlen)
253b223c403Spooka {
254b223c403Spooka
255b223c403Spooka if (pufbuf->maxoff < offset + dlen) {
256b223c403Spooka errno = ENOBUFS;
257b223c403Spooka return -1;
258b223c403Spooka }
259b223c403Spooka
260b223c403Spooka memcpy(data, pufbuf->buf + offset, dlen);
261b223c403Spooka return 0;
262b223c403Spooka }
263b223c403Spooka
264b223c403Spooka size_t
puffs_framebuf_telloff(struct puffs_framebuf * pufbuf)265b223c403Spooka puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
266b223c403Spooka {
267b223c403Spooka
268b223c403Spooka return pufbuf->offset;
269b223c403Spooka }
270b223c403Spooka
271b223c403Spooka size_t
puffs_framebuf_tellsize(struct puffs_framebuf * pufbuf)272b223c403Spooka puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
273b223c403Spooka {
274b223c403Spooka
275b223c403Spooka return pufbuf->maxoff;
276b223c403Spooka }
277b223c403Spooka
2784226bd8bSpooka size_t
puffs_framebuf_remaining(struct puffs_framebuf * pufbuf)2794226bd8bSpooka puffs_framebuf_remaining(struct puffs_framebuf *pufbuf)
2804226bd8bSpooka {
2814226bd8bSpooka
2824226bd8bSpooka return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf);
2834226bd8bSpooka }
2844226bd8bSpooka
285b223c403Spooka int
puffs_framebuf_seekset(struct puffs_framebuf * pufbuf,size_t newoff)286b223c403Spooka puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
287b223c403Spooka {
288b223c403Spooka
289b223c403Spooka if (reservespace(pufbuf, newoff, 0) == -1)
290b223c403Spooka return -1;
291b223c403Spooka
292b223c403Spooka pufbuf->offset = newoff;
293b223c403Spooka return 0;
294b223c403Spooka }
295b223c403Spooka
296b223c403Spooka int
puffs_framebuf_getwindow(struct puffs_framebuf * pufbuf,size_t winoff,void ** data,size_t * dlen)297b223c403Spooka puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
298b223c403Spooka void **data, size_t *dlen)
299b223c403Spooka {
300b223c403Spooka size_t winlen;
301b223c403Spooka
302b223c403Spooka #ifdef WINTESTING
303b223c403Spooka winlen = MIN(*dlen, 32);
304b223c403Spooka #else
305b223c403Spooka winlen = *dlen;
306b223c403Spooka #endif
307b223c403Spooka
308b223c403Spooka if (reservespace(pufbuf, winoff, winlen) == -1)
309b223c403Spooka return -1;
310b223c403Spooka
311b223c403Spooka *data = pufbuf->buf + winoff;
312b223c403Spooka if (pufbuf->maxoff < winoff + winlen)
313b223c403Spooka pufbuf->maxoff = winoff + winlen;
314b223c403Spooka
315b223c403Spooka return 0;
316b223c403Spooka }
317b223c403Spooka
31861113f40Spooka void *
puffs__framebuf_getdataptr(struct puffs_framebuf * pufbuf)31961113f40Spooka puffs__framebuf_getdataptr(struct puffs_framebuf *pufbuf)
32061113f40Spooka {
32161113f40Spooka
32261113f40Spooka return pufbuf->buf;
32361113f40Spooka }
32461113f40Spooka
325291fe845Spooka static void
errnotify(struct puffs_usermount * pu,struct puffs_framebuf * pufbuf,int error)326b017aa60Spooka errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error)
327291fe845Spooka {
328291fe845Spooka
329291fe845Spooka pufbuf->rv = error;
330291fe845Spooka if (pufbuf->pcc) {
331d1d05d65Spooka puffs__goto(pufbuf->pcc);
332291fe845Spooka } else if (pufbuf->fcb) {
333291fe845Spooka pufbuf->istat &= ~ISTAT_NODESTROY;
334b017aa60Spooka pufbuf->fcb(pu, pufbuf, pufbuf->fcb_arg, error);
335291fe845Spooka } else {
336291fe845Spooka pufbuf->istat &= ~ISTAT_NODESTROY;
337291fe845Spooka puffs_framebuf_destroy(pufbuf);
338291fe845Spooka }
339291fe845Spooka }
340291fe845Spooka
341291fe845Spooka #define GETFIO(fd) \
342291fe845Spooka do { \
343291fe845Spooka fio = getfiobyfd(pu, fd); \
344291fe845Spooka if (fio == NULL) { \
345291fe845Spooka errno = EINVAL; \
346291fe845Spooka return -1; \
347291fe845Spooka } \
348291fe845Spooka if (fio->stat & FIO_WRGONE) { \
349291fe845Spooka errno = ESHUTDOWN; \
350291fe845Spooka return -1; \
351291fe845Spooka } \
352*388550b0Srillig } while (0)
353291fe845Spooka
354b223c403Spooka int
puffs_framev_enqueue_cc(struct puffs_cc * pcc,int fd,struct puffs_framebuf * pufbuf,int flags)355291fe845Spooka puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd,
3568c9c68dbSpooka struct puffs_framebuf *pufbuf, int flags)
357b223c403Spooka {
35808c7b613Spooka struct puffs_usermount *pu = pcc->pcc_pu;
3592b8177d9Spooka struct puffs_fctrl_io *fio;
3602b8177d9Spooka
361291fe845Spooka /*
362be5ed87cSpooka * Technically we shouldn't allow this if RDGONE, but it's
363291fe845Spooka * difficult to trap write close without allowing writes.
364291fe845Spooka * And besides, there's probably a disconnect sequence in
365291fe845Spooka * the protocol, so unexpectedly getting a closed fd is
366291fe845Spooka * most likely an error condition.
367291fe845Spooka */
368291fe845Spooka GETFIO(fd);
369b223c403Spooka
370b223c403Spooka pufbuf->pcc = pcc;
371b223c403Spooka pufbuf->fcb = NULL;
372b223c403Spooka pufbuf->fcb_arg = NULL;
373b223c403Spooka
374b223c403Spooka pufbuf->offset = 0;
375b223c403Spooka pufbuf->istat |= ISTAT_NODESTROY;
376b223c403Spooka
3778c9c68dbSpooka if (flags & PUFFS_FBQUEUE_URGENT)
3788c9c68dbSpooka TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
3798c9c68dbSpooka else
3802b8177d9Spooka TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
381b223c403Spooka
382b223c403Spooka puffs_cc_yield(pcc);
383b223c403Spooka if (pufbuf->rv) {
384291fe845Spooka pufbuf->istat &= ~ISTAT_NODESTROY;
385b223c403Spooka errno = pufbuf->rv;
386b223c403Spooka return -1;
387b223c403Spooka }
388b223c403Spooka
389b223c403Spooka return 0;
390b223c403Spooka }
391b223c403Spooka
3922b8177d9Spooka int
puffs_framev_enqueue_cb(struct puffs_usermount * pu,int fd,struct puffs_framebuf * pufbuf,puffs_framev_cb fcb,void * arg,int flags)393291fe845Spooka puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd,
3948c9c68dbSpooka struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg,
3958c9c68dbSpooka int flags)
396b223c403Spooka {
3972b8177d9Spooka struct puffs_fctrl_io *fio;
3982b8177d9Spooka
399291fe845Spooka /* see enqueue_cc */
400291fe845Spooka GETFIO(fd);
401b223c403Spooka
402b223c403Spooka pufbuf->pcc = NULL;
403b223c403Spooka pufbuf->fcb = fcb;
404b223c403Spooka pufbuf->fcb_arg = arg;
405b223c403Spooka
406b223c403Spooka pufbuf->offset = 0;
407b223c403Spooka pufbuf->istat |= ISTAT_NODESTROY;
408b223c403Spooka
4098c9c68dbSpooka if (flags & PUFFS_FBQUEUE_URGENT)
4108c9c68dbSpooka TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
4118c9c68dbSpooka else
4122b8177d9Spooka TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
4132b8177d9Spooka
4142b8177d9Spooka return 0;
415b223c403Spooka }
416b223c403Spooka
4172b8177d9Spooka int
puffs_framev_enqueue_justsend(struct puffs_usermount * pu,int fd,struct puffs_framebuf * pufbuf,int reply,int flags)418291fe845Spooka puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd,
4198c9c68dbSpooka struct puffs_framebuf *pufbuf, int reply, int flags)
420b223c403Spooka {
4212b8177d9Spooka struct puffs_fctrl_io *fio;
4222b8177d9Spooka
423be5ed87cSpooka assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
424be5ed87cSpooka
425291fe845Spooka GETFIO(fd);
426b223c403Spooka
427b223c403Spooka pufbuf->pcc = NULL;
428b223c403Spooka pufbuf->fcb = NULL;
429b223c403Spooka pufbuf->fcb_arg = NULL;
430b223c403Spooka
431b223c403Spooka pufbuf->offset = 0;
432b223c403Spooka pufbuf->istat |= ISTAT_NODESTROY;
433b223c403Spooka if (!reply)
434b223c403Spooka pufbuf->istat |= ISTAT_NOREPLY;
435b223c403Spooka
4368c9c68dbSpooka if (flags & PUFFS_FBQUEUE_URGENT)
4378c9c68dbSpooka TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries);
4388c9c68dbSpooka else
4392b8177d9Spooka TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
4402b8177d9Spooka
4412b8177d9Spooka return 0;
442b223c403Spooka }
443b223c403Spooka
4448c9c68dbSpooka /* ARGSUSED */
4458c9c68dbSpooka int
puffs_framev_enqueue_directreceive(struct puffs_cc * pcc,int fd,struct puffs_framebuf * pufbuf,int flags)4468c9c68dbSpooka puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd,
4478c9c68dbSpooka struct puffs_framebuf *pufbuf, int flags /* used in the future */)
4488c9c68dbSpooka {
44908c7b613Spooka struct puffs_usermount *pu = pcc->pcc_pu;
4508c9c68dbSpooka struct puffs_fctrl_io *fio;
4518c9c68dbSpooka
452be5ed87cSpooka assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
453be5ed87cSpooka
4548c9c68dbSpooka fio = getfiobyfd(pu, fd);
4558c9c68dbSpooka if (fio == NULL) {
4568c9c68dbSpooka errno = EINVAL;
4578c9c68dbSpooka return -1;
4588c9c68dbSpooka }
4598c9c68dbSpooka
4608c9c68dbSpooka /* XXX: should have cur_in queue */
4618c9c68dbSpooka assert(fio->cur_in == NULL);
4628c9c68dbSpooka fio->cur_in = pufbuf;
4638c9c68dbSpooka
4648c9c68dbSpooka pufbuf->pcc = pcc;
4658c9c68dbSpooka pufbuf->fcb = NULL;
4668c9c68dbSpooka pufbuf->fcb_arg = NULL;
4678c9c68dbSpooka
4688c9c68dbSpooka pufbuf->offset = 0;
4698c9c68dbSpooka pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
4708c9c68dbSpooka
4718c9c68dbSpooka puffs_cc_yield(pcc);
4728c9c68dbSpooka pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */
4738c9c68dbSpooka if (pufbuf->rv) {
4748c9c68dbSpooka errno = pufbuf->rv;
4758c9c68dbSpooka return -1;
4768c9c68dbSpooka }
4778c9c68dbSpooka
4788c9c68dbSpooka return 0;
4798c9c68dbSpooka }
4808c9c68dbSpooka
4818c9c68dbSpooka int
puffs_framev_enqueue_directsend(struct puffs_cc * pcc,int fd,struct puffs_framebuf * pufbuf,int flags)4828c9c68dbSpooka puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd,
4838c9c68dbSpooka struct puffs_framebuf *pufbuf, int flags)
4848c9c68dbSpooka {
48508c7b613Spooka struct puffs_usermount *pu = pcc->pcc_pu;
4868c9c68dbSpooka struct puffs_fctrl_io *fio;
4878c9c68dbSpooka
488be5ed87cSpooka assert((pufbuf->istat & ISTAT_INTERNAL) == 0);
489be5ed87cSpooka
4908c9c68dbSpooka if (flags & PUFFS_FBQUEUE_URGENT)
4918c9c68dbSpooka abort(); /* EOPNOTSUPP for now */
4928c9c68dbSpooka
4938c9c68dbSpooka GETFIO(fd);
4948c9c68dbSpooka
4958c9c68dbSpooka pufbuf->pcc = pcc;
4968c9c68dbSpooka pufbuf->fcb = NULL;
4978c9c68dbSpooka pufbuf->fcb_arg = NULL;
4988c9c68dbSpooka
4998c9c68dbSpooka pufbuf->offset = 0;
5008c9c68dbSpooka pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT;
5018c9c68dbSpooka
5028c9c68dbSpooka TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
5038c9c68dbSpooka
5048c9c68dbSpooka puffs_cc_yield(pcc);
5058c9c68dbSpooka if (pufbuf->rv) {
5068c9c68dbSpooka pufbuf->istat &= ~ISTAT_NODESTROY;
5078c9c68dbSpooka errno = pufbuf->rv;
5088c9c68dbSpooka return -1;
5098c9c68dbSpooka }
5108c9c68dbSpooka
5118c9c68dbSpooka return 0;
5128c9c68dbSpooka }
5138c9c68dbSpooka
514866bcfbbSpooka int
puffs_framev_framebuf_ccpromote(struct puffs_framebuf * pufbuf,struct puffs_cc * pcc)515866bcfbbSpooka puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf,
516866bcfbbSpooka struct puffs_cc *pcc)
517866bcfbbSpooka {
518866bcfbbSpooka
519866bcfbbSpooka if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) {
520866bcfbbSpooka errno = EBUSY;
521866bcfbbSpooka return -1;
522866bcfbbSpooka }
523866bcfbbSpooka
524866bcfbbSpooka pufbuf->pcc = pcc;
525866bcfbbSpooka pufbuf->fcb = NULL;
526866bcfbbSpooka pufbuf->fcb_arg = NULL;
527866bcfbbSpooka pufbuf->istat &= ~ISTAT_NOREPLY;
528866bcfbbSpooka
529866bcfbbSpooka puffs_cc_yield(pcc);
530866bcfbbSpooka
531866bcfbbSpooka return 0;
532866bcfbbSpooka }
533866bcfbbSpooka
534343e8df3Spooka int
puffs_framev_enqueue_waitevent(struct puffs_cc * pcc,int fd,int * what)535343e8df3Spooka puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
536343e8df3Spooka {
53708c7b613Spooka struct puffs_usermount *pu = pcc->pcc_pu;
538343e8df3Spooka struct puffs_fctrl_io *fio;
539343e8df3Spooka struct puffs_fbevent feb;
540343e8df3Spooka struct kevent kev;
541343e8df3Spooka int rv, svwhat;
542343e8df3Spooka
543343e8df3Spooka svwhat = *what;
544343e8df3Spooka
545343e8df3Spooka if (*what == 0) {
546343e8df3Spooka errno = EINVAL;
547343e8df3Spooka return -1;
548343e8df3Spooka }
549343e8df3Spooka
550343e8df3Spooka fio = getfiobyfd(pu, fd);
551343e8df3Spooka if (fio == NULL) {
552343e8df3Spooka errno = EINVAL;
553343e8df3Spooka return -1;
554343e8df3Spooka }
555343e8df3Spooka
556343e8df3Spooka feb.pcc = pcc;
557343e8df3Spooka feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR);
558343e8df3Spooka
559343e8df3Spooka if (*what & PUFFS_FBIO_READ)
560343e8df3Spooka if ((fio->stat & FIO_ENABLE_R) == 0)
56165fe3242Schristos EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, fio);
562343e8df3Spooka
563dade3157Sriastradh if (kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL) == -1)
564dade3157Sriastradh return -1;
565343e8df3Spooka
566343e8df3Spooka if (*what & PUFFS_FBIO_READ)
567343e8df3Spooka fio->rwait++;
568343e8df3Spooka if (*what & PUFFS_FBIO_WRITE)
569343e8df3Spooka fio->wwait++;
570343e8df3Spooka
571343e8df3Spooka LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries);
572343e8df3Spooka puffs_cc_yield(pcc);
573343e8df3Spooka
574343e8df3Spooka assert(svwhat == *what);
575343e8df3Spooka
576343e8df3Spooka if (*what & PUFFS_FBIO_READ) {
577343e8df3Spooka fio->rwait--;
578343e8df3Spooka if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) {
57965fe3242Schristos EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 0, 0, fio);
580343e8df3Spooka rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
581343e8df3Spooka #if 0
582343e8df3Spooka if (rv != 0)
583343e8df3Spooka /* XXXXX oh dear */;
584343e8df3Spooka #endif
585343e8df3Spooka }
586343e8df3Spooka }
587343e8df3Spooka if (*what & PUFFS_FBIO_WRITE)
588343e8df3Spooka fio->wwait--;
589343e8df3Spooka
590e30ed213Spooka if (feb.rv == 0) {
591343e8df3Spooka *what = feb.what;
592e30ed213Spooka rv = 0;
593e30ed213Spooka } else {
594e30ed213Spooka *what = PUFFS_FBIO_ERROR;
595e30ed213Spooka errno = feb.rv;
596e30ed213Spooka rv = -1;
597e30ed213Spooka }
598343e8df3Spooka
599e30ed213Spooka return rv;
600343e8df3Spooka }
601343e8df3Spooka
602343e8df3Spooka void
puffs__framev_notify(struct puffs_fctrl_io * fio,int what)603d1d05d65Spooka puffs__framev_notify(struct puffs_fctrl_io *fio, int what)
604343e8df3Spooka {
605343e8df3Spooka struct puffs_fbevent *fbevp;
606343e8df3Spooka
607343e8df3Spooka restart:
608343e8df3Spooka LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) {
609343e8df3Spooka if (fbevp->what & what) {
610343e8df3Spooka fbevp->what = what;
611343e8df3Spooka fbevp->rv = 0;
612343e8df3Spooka LIST_REMOVE(fbevp, pfe_entries);
613343e8df3Spooka puffs_cc_continue(fbevp->pcc);
614343e8df3Spooka goto restart;
615343e8df3Spooka }
616343e8df3Spooka }
617343e8df3Spooka }
618343e8df3Spooka
619b223c403Spooka static struct puffs_framebuf *
findbuf(struct puffs_usermount * pu,struct puffs_framectrl * fctrl,struct puffs_fctrl_io * fio,struct puffs_framebuf * findme)620b223c403Spooka findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
6212b8177d9Spooka struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
622b223c403Spooka {
623b223c403Spooka struct puffs_framebuf *cand;
62456b35d3bSpooka int notresp = 0;
625b223c403Spooka
6262b8177d9Spooka TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
62756b35d3bSpooka if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp)
628b223c403Spooka break;
629b223c403Spooka
63056b35d3bSpooka assert(!(notresp && cand == NULL));
63156b35d3bSpooka if (notresp || cand == NULL)
632b223c403Spooka return NULL;
633b223c403Spooka
6342b8177d9Spooka TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
635b223c403Spooka return cand;
636b223c403Spooka }
637b223c403Spooka
63861113f40Spooka void
puffs__framebuf_moveinfo(struct puffs_framebuf * from,struct puffs_framebuf * to)63961113f40Spooka puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
640b223c403Spooka {
641b223c403Spooka
642b223c403Spooka assert(from->istat & ISTAT_INTERNAL);
643b223c403Spooka
644b223c403Spooka /* migrate buffer */
645b223c403Spooka free(to->buf);
646b223c403Spooka to->buf = from->buf;
647b223c403Spooka
648b223c403Spooka /* migrate buffer info */
649b223c403Spooka to->len = from->len;
650b223c403Spooka to->offset = from->offset;
651b223c403Spooka to->maxoff = from->maxoff;
65261113f40Spooka
65361113f40Spooka from->buf = NULL;
65461113f40Spooka from->len = 0;
655b223c403Spooka }
656b223c403Spooka
657291fe845Spooka void
puffs__framev_input(struct puffs_usermount * pu,struct puffs_framectrl * fctrl,struct puffs_fctrl_io * fio)658d1d05d65Spooka puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
65961113f40Spooka struct puffs_fctrl_io *fio)
660b223c403Spooka {
661b223c403Spooka struct puffs_framebuf *pufbuf, *appbuf;
662b223c403Spooka int rv, complete;
663b223c403Spooka
6648c9c68dbSpooka while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) {
6652b8177d9Spooka if ((pufbuf = fio->cur_in) == NULL) {
666b223c403Spooka pufbuf = puffs_framebuf_make();
667b223c403Spooka if (pufbuf == NULL)
668291fe845Spooka return;
669b223c403Spooka pufbuf->istat |= ISTAT_INTERNAL;
6702b8177d9Spooka fio->cur_in = pufbuf;
671b223c403Spooka }
672b223c403Spooka
673b223c403Spooka complete = 0;
6742b8177d9Spooka rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
675b223c403Spooka
676b223c403Spooka /* error */
677b223c403Spooka if (rv) {
678d1d05d65Spooka puffs__framev_readclose(pu, fio, rv);
679343e8df3Spooka fio->cur_in = NULL;
680291fe845Spooka return;
681b223c403Spooka }
682b223c403Spooka
683b223c403Spooka /* partial read, come back to fight another day */
684b223c403Spooka if (complete == 0)
685b223c403Spooka break;
686b223c403Spooka
687b223c403Spooka /* else: full read, process */
68861113f40Spooka fio->cur_in = NULL;
6898c9c68dbSpooka if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
6902b8177d9Spooka appbuf = findbuf(pu, fctrl, fio, pufbuf);
691291fe845Spooka
692dc9a9106Spooka /*
693dc9a9106Spooka * No request for this frame? If fs implements
694dc9a9106Spooka * gotfb, give frame to that. Otherwise drop it.
695dc9a9106Spooka */
696b223c403Spooka if (appbuf == NULL) {
697be5ed87cSpooka if (fctrl->gotfb) {
698be5ed87cSpooka pufbuf->istat &= ~ISTAT_INTERNAL;
699dc9a9106Spooka fctrl->gotfb(pu, pufbuf);
700be5ed87cSpooka } else {
701dc9a9106Spooka puffs_framebuf_destroy(pufbuf);
702be5ed87cSpooka }
703dc9a9106Spooka continue;
704b223c403Spooka }
705b223c403Spooka
70661113f40Spooka puffs__framebuf_moveinfo(pufbuf, appbuf);
7078c9c68dbSpooka puffs_framebuf_destroy(pufbuf);
7088c9c68dbSpooka } else {
7098c9c68dbSpooka appbuf = pufbuf;
7108c9c68dbSpooka }
7118c9c68dbSpooka appbuf->istat &= ~ISTAT_NODESTROY;
7128c9c68dbSpooka
713b223c403Spooka if (appbuf->pcc) {
714d1d05d65Spooka puffs__cc_cont(appbuf->pcc);
715b223c403Spooka } else if (appbuf->fcb) {
716c1f0cc68Spooka appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
717b223c403Spooka } else {
718b223c403Spooka puffs_framebuf_destroy(appbuf);
719b223c403Spooka }
720b223c403Spooka
721b223c403Spooka /* hopeless romantics, here we go again */
722b223c403Spooka }
723b223c403Spooka }
724b223c403Spooka
725e94b19cfSpooka int
puffs__framev_output(struct puffs_usermount * pu,struct puffs_framectrl * fctrl,struct puffs_fctrl_io * fio)726d1d05d65Spooka puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
72761113f40Spooka struct puffs_fctrl_io *fio)
728b223c403Spooka {
729e2dc8334Spooka struct puffs_framebuf *pufbuf;
7308c9c68dbSpooka int rv, complete, done;
731b223c403Spooka
732291fe845Spooka if (fio->stat & FIO_DEAD)
733291fe845Spooka return 0;
734291fe845Spooka
7358c9c68dbSpooka for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0;
7368c9c68dbSpooka pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W;
737e2dc8334Spooka pufbuf = TAILQ_FIRST(&fio->snd_qing)) {
738b223c403Spooka complete = 0;
7392b8177d9Spooka rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
740b223c403Spooka
741b223c403Spooka if (rv) {
742d1d05d65Spooka puffs__framev_writeclose(pu, fio, rv);
7438c9c68dbSpooka done = 1;
744291fe845Spooka break;
745b223c403Spooka }
746b223c403Spooka
747b223c403Spooka /* partial write */
748b223c403Spooka if (complete == 0)
7498c9c68dbSpooka return done;
750b223c403Spooka
751b223c403Spooka /* else, complete write */
7522b8177d9Spooka TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
753b223c403Spooka
754291fe845Spooka /* can't wait for result if we can't read */
755291fe845Spooka if (fio->stat & FIO_RDGONE) {
756b017aa60Spooka errnotify(pu, pufbuf, ENXIO);
7578c9c68dbSpooka done = 1;
7588c9c68dbSpooka } else if ((pufbuf->istat & ISTAT_DIRECT)) {
7598c9c68dbSpooka pufbuf->istat &= ~ISTAT_NODESTROY;
7608c9c68dbSpooka done = 1;
761d1d05d65Spooka puffs__cc_cont(pufbuf->pcc);
762291fe845Spooka } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
7632b8177d9Spooka TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
764b223c403Spooka pfb_entries);
765b223c403Spooka } else {
766b223c403Spooka pufbuf->istat &= ~ISTAT_NODESTROY;
767b223c403Spooka puffs_framebuf_destroy(pufbuf);
768b223c403Spooka }
769291fe845Spooka
770291fe845Spooka /* omstart! */
771b223c403Spooka }
772b223c403Spooka
7738c9c68dbSpooka return done;
774b223c403Spooka }
775b223c403Spooka
776b223c403Spooka int
puffs__framev_addfd_ctrl(struct puffs_usermount * pu,int fd,int what,struct puffs_framectrl * pfctrl)77761113f40Spooka puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what,
77861113f40Spooka struct puffs_framectrl *pfctrl)
7792b8177d9Spooka {
7802b8177d9Spooka struct puffs_fctrl_io *fio;
7818c9c68dbSpooka struct kevent kev[2];
782b95be6c6Spooka size_t nevs;
7838c9c68dbSpooka int rv, readenable;
7842b8177d9Spooka
785b95be6c6Spooka nevs = pu->pu_nevs+2;
7868221e07eSnia if (reallocarr(&pu->pu_evs, nevs, sizeof(struct kevent)) != 0) {
7878221e07eSnia errno = ENOMEM;
7882b8177d9Spooka return -1;
7898221e07eSnia }
7902b8177d9Spooka
7912b8177d9Spooka fio = malloc(sizeof(struct puffs_fctrl_io));
7922b8177d9Spooka if (fio == NULL)
7932b8177d9Spooka return -1;
794343e8df3Spooka memset(fio, 0, sizeof(struct puffs_fctrl_io));
7952b8177d9Spooka fio->io_fd = fd;
7962b8177d9Spooka fio->cur_in = NULL;
79761113f40Spooka fio->fctrl = pfctrl;
7982b8177d9Spooka TAILQ_INIT(&fio->snd_qing);
7992b8177d9Spooka TAILQ_INIT(&fio->res_qing);
800343e8df3Spooka LIST_INIT(&fio->ev_qing);
8012b8177d9Spooka
8028c9c68dbSpooka readenable = 0;
8038c9c68dbSpooka if ((what & PUFFS_FBIO_READ) == 0)
8048c9c68dbSpooka readenable = EV_DISABLE;
8058c9c68dbSpooka
8068c9c68dbSpooka if (pu->pu_state & PU_INLOOP) {
807518a4ef5Schristos struct stat st;
808518a4ef5Schristos size_t nf = 0;
809518a4ef5Schristos
810518a4ef5Schristos if (fstat(fd, &st) == -1)
811518a4ef5Schristos goto out;
81265fe3242Schristos EV_SET(&kev[nf], fd, EVFILT_READ, EV_ADD|readenable, 0, 0, fio);
813518a4ef5Schristos nf++;
814518a4ef5Schristos if (S_ISSOCK(st.st_mode)) {
815518a4ef5Schristos EV_SET(&kev[nf], fd, EVFILT_WRITE,
81665fe3242Schristos EV_ADD|EV_DISABLE, 0, 0, fio);
817518a4ef5Schristos nf++;
8188c9c68dbSpooka }
819518a4ef5Schristos rv = kevent(pu->pu_kq, kev, nf, NULL, 0, NULL);
820518a4ef5Schristos if (rv == -1)
821518a4ef5Schristos goto out;
8228c9c68dbSpooka }
8238c9c68dbSpooka if (what & PUFFS_FBIO_READ)
8248c9c68dbSpooka fio->stat |= FIO_ENABLE_R;
8258c9c68dbSpooka if (what & PUFFS_FBIO_WRITE)
8268c9c68dbSpooka fio->stat |= FIO_ENABLE_W;
8278c9c68dbSpooka
82861113f40Spooka LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries);
829b95be6c6Spooka pu->pu_nevs = nevs;
8302b8177d9Spooka
8312b8177d9Spooka return 0;
832518a4ef5Schristos out:
833518a4ef5Schristos free(fio);
834518a4ef5Schristos return -1;
8352b8177d9Spooka }
8362b8177d9Spooka
83761113f40Spooka int
puffs_framev_addfd(struct puffs_usermount * pu,int fd,int what)83861113f40Spooka puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what)
83961113f40Spooka {
84061113f40Spooka
84161113f40Spooka return puffs__framev_addfd_ctrl(pu, fd, what,
84261113f40Spooka &pu->pu_framectrl[PU_FRAMECTRL_USER]);
84361113f40Spooka }
84461113f40Spooka
8458c9c68dbSpooka /*
8468c9c68dbSpooka * XXX: the following en/disable should be coalesced and executed
847343e8df3Spooka * only during the actual kevent call. So feel free to fix if
8488c9c68dbSpooka * threatened by mindblowing boredom.
8498c9c68dbSpooka */
8508c9c68dbSpooka
8518c9c68dbSpooka int
puffs_framev_enablefd(struct puffs_usermount * pu,int fd,int what)8528c9c68dbSpooka puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what)
8538c9c68dbSpooka {
8548c9c68dbSpooka struct kevent kev;
8558c9c68dbSpooka struct puffs_fctrl_io *fio;
856343e8df3Spooka int rv = 0;
8578c9c68dbSpooka
8588c9c68dbSpooka assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
8598c9c68dbSpooka
8608c9c68dbSpooka fio = getfiobyfd(pu, fd);
8618c9c68dbSpooka if (fio == NULL) {
8628c9c68dbSpooka errno = ENXIO;
8638c9c68dbSpooka return -1;
8648c9c68dbSpooka }
8658c9c68dbSpooka
8668c9c68dbSpooka /* write is enabled in the event loop if there is output */
867343e8df3Spooka if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
86865fe3242Schristos EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, fio);
8698c9c68dbSpooka rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
870343e8df3Spooka }
8718c9c68dbSpooka
8728c9c68dbSpooka if (rv == 0) {
8738c9c68dbSpooka if (what & PUFFS_FBIO_READ)
8748c9c68dbSpooka fio->stat |= FIO_ENABLE_R;
8758c9c68dbSpooka if (what & PUFFS_FBIO_WRITE)
8768c9c68dbSpooka fio->stat |= FIO_ENABLE_W;
8778c9c68dbSpooka }
8788c9c68dbSpooka
8798c9c68dbSpooka return rv;
8808c9c68dbSpooka }
8818c9c68dbSpooka
8828c9c68dbSpooka int
puffs_framev_disablefd(struct puffs_usermount * pu,int fd,int what)8838c9c68dbSpooka puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
8848c9c68dbSpooka {
8858c9c68dbSpooka struct kevent kev[2];
8868c9c68dbSpooka struct puffs_fctrl_io *fio;
8878c9c68dbSpooka size_t i;
8888c9c68dbSpooka int rv;
8898c9c68dbSpooka
8908c9c68dbSpooka assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0);
8918c9c68dbSpooka
8928c9c68dbSpooka fio = getfiobyfd(pu, fd);
8938c9c68dbSpooka if (fio == NULL) {
8948c9c68dbSpooka errno = ENXIO;
8958c9c68dbSpooka return -1;
8968c9c68dbSpooka }
8978c9c68dbSpooka
8988c9c68dbSpooka i = 0;
899343e8df3Spooka if (what & PUFFS_FBIO_READ && fio->rwait == 0) {
90065fe3242Schristos EV_SET(&kev[0], fd, EVFILT_READ, EV_DISABLE, 0, 0, fio);
9018c9c68dbSpooka i++;
9028c9c68dbSpooka }
903343e8df3Spooka if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) {
90465fe3242Schristos EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DISABLE, 0, 0, fio);
9058c9c68dbSpooka i++;
9068c9c68dbSpooka }
907343e8df3Spooka if (i)
9088c9c68dbSpooka rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL);
909343e8df3Spooka else
910343e8df3Spooka rv = 0;
9118c9c68dbSpooka
9128c9c68dbSpooka if (rv == 0) {
9138c9c68dbSpooka if (what & PUFFS_FBIO_READ)
9148c9c68dbSpooka fio->stat &= ~FIO_ENABLE_R;
9158c9c68dbSpooka if (what & PUFFS_FBIO_WRITE)
9168c9c68dbSpooka fio->stat &= ~FIO_ENABLE_W;
9178c9c68dbSpooka }
9188c9c68dbSpooka
9198c9c68dbSpooka return rv;
9208c9c68dbSpooka }
9218c9c68dbSpooka
922291fe845Spooka void
puffs__framev_readclose(struct puffs_usermount * pu,struct puffs_fctrl_io * fio,int error)923d1d05d65Spooka puffs__framev_readclose(struct puffs_usermount *pu,
924291fe845Spooka struct puffs_fctrl_io *fio, int error)
9252b8177d9Spooka {
9262b8177d9Spooka struct puffs_framebuf *pufbuf;
927291fe845Spooka struct kevent kev;
928291fe845Spooka int notflag;
9292b8177d9Spooka
930291fe845Spooka if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD)
931291fe845Spooka return;
932291fe845Spooka fio->stat |= FIO_RDGONE;
933291fe845Spooka
934291fe845Spooka if (fio->cur_in) {
9358c9c68dbSpooka if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) {
936291fe845Spooka puffs_framebuf_destroy(fio->cur_in);
937291fe845Spooka fio->cur_in = NULL;
9388c9c68dbSpooka } else {
939b017aa60Spooka errnotify(pu, fio->cur_in, error);
9408c9c68dbSpooka }
941e94b19cfSpooka }
9422b8177d9Spooka
9432b8177d9Spooka while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
9442b8177d9Spooka TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
945b017aa60Spooka errnotify(pu, pufbuf, error);
9462b8177d9Spooka }
947291fe845Spooka
948291fe845Spooka EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
949291fe845Spooka (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
950291fe845Spooka
9518c9c68dbSpooka notflag = PUFFS_FBIO_READ;
952291fe845Spooka if (fio->stat & FIO_WRGONE)
9538c9c68dbSpooka notflag |= PUFFS_FBIO_WRITE;
954291fe845Spooka
95561113f40Spooka if (fio->fctrl->fdnotfn)
95661113f40Spooka fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
957291fe845Spooka }
958291fe845Spooka
959291fe845Spooka void
puffs__framev_writeclose(struct puffs_usermount * pu,struct puffs_fctrl_io * fio,int error)960d1d05d65Spooka puffs__framev_writeclose(struct puffs_usermount *pu,
961291fe845Spooka struct puffs_fctrl_io *fio, int error)
962291fe845Spooka {
963291fe845Spooka struct puffs_framebuf *pufbuf;
964291fe845Spooka struct kevent kev;
965291fe845Spooka int notflag;
966291fe845Spooka
967291fe845Spooka if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD)
968291fe845Spooka return;
969291fe845Spooka fio->stat |= FIO_WRGONE;
970291fe845Spooka
971291fe845Spooka while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
972291fe845Spooka TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
973b017aa60Spooka errnotify(pu, pufbuf, error);
974291fe845Spooka }
975291fe845Spooka
976291fe845Spooka EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
977291fe845Spooka (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL);
978291fe845Spooka
9798c9c68dbSpooka notflag = PUFFS_FBIO_WRITE;
980291fe845Spooka if (fio->stat & FIO_RDGONE)
9818c9c68dbSpooka notflag |= PUFFS_FBIO_READ;
982291fe845Spooka
98361113f40Spooka if (fio->fctrl->fdnotfn)
98461113f40Spooka fio->fctrl->fdnotfn(pu, fio->io_fd, notflag);
985291fe845Spooka }
986291fe845Spooka
987291fe845Spooka static int
removefio(struct puffs_usermount * pu,struct puffs_fctrl_io * fio,int error)988291fe845Spooka removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
989291fe845Spooka {
990343e8df3Spooka struct puffs_fbevent *fbevp;
991291fe845Spooka
992291fe845Spooka LIST_REMOVE(fio, fio_entries);
993291fe845Spooka if (pu->pu_state & PU_INLOOP) {
994d1d05d65Spooka puffs__framev_readclose(pu, fio, error);
995d1d05d65Spooka puffs__framev_writeclose(pu, fio, error);
996291fe845Spooka }
9972b8177d9Spooka
998343e8df3Spooka while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
999343e8df3Spooka fbevp->rv = error;
1000343e8df3Spooka LIST_REMOVE(fbevp, pfe_entries);
1001d1d05d65Spooka puffs__goto(fbevp->pcc);
1002343e8df3Spooka }
1003343e8df3Spooka
10042b8177d9Spooka /* don't bother with realloc */
1005b95be6c6Spooka pu->pu_nevs -= 2;
10062b8177d9Spooka
1007291fe845Spooka /* don't free us yet, might have some references in event arrays */
1008291fe845Spooka fio->stat |= FIO_DEAD;
100961113f40Spooka LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries);
1010291fe845Spooka
10112b8177d9Spooka return 0;
10122b8177d9Spooka
10132b8177d9Spooka }
10142b8177d9Spooka
10152b8177d9Spooka int
puffs_framev_removefd(struct puffs_usermount * pu,int fd,int error)1016291fe845Spooka puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error)
10172b8177d9Spooka {
10182b8177d9Spooka struct puffs_fctrl_io *fio;
10192b8177d9Spooka
10202b8177d9Spooka fio = getfiobyfd(pu, fd);
10212b8177d9Spooka if (fio == NULL) {
10222b8177d9Spooka errno = ENXIO;
10232b8177d9Spooka return -1;
10242b8177d9Spooka }
10252b8177d9Spooka
10268be39bc3Spooka return removefio(pu, fio, error ? error : ECONNRESET);
10272b8177d9Spooka }
10282b8177d9Spooka
10291119cb90Spooka void
puffs_framev_removeonclose(struct puffs_usermount * pu,int fd,int what)10301119cb90Spooka puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what)
1031291fe845Spooka {
1032291fe845Spooka
10333541e44cSpooka if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
10348be39bc3Spooka (void) puffs_framev_removefd(pu, fd, ECONNRESET);
1035291fe845Spooka }
1036291fe845Spooka
1037291fe845Spooka void
puffs_framev_unmountonclose(struct puffs_usermount * pu,int fd,int what)1038291fe845Spooka puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what)
1039291fe845Spooka {
1040291fe845Spooka
1041291fe845Spooka /* XXX & X: unmount is non-sensible */
10421119cb90Spooka puffs_framev_removeonclose(pu, fd, what);
10433541e44cSpooka if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE))
1044291fe845Spooka PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED);
1045291fe845Spooka }
1046291fe845Spooka
1047291fe845Spooka void
puffs_framev_init(struct puffs_usermount * pu,puffs_framev_readframe_fn rfb,puffs_framev_writeframe_fn wfb,puffs_framev_cmpframe_fn cmpfb,puffs_framev_gotframe_fn gotfb,puffs_framev_fdnotify_fn fdnotfn)1048291fe845Spooka puffs_framev_init(struct puffs_usermount *pu,
1049291fe845Spooka puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb,
1050dc9a9106Spooka puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb,
1051dc9a9106Spooka puffs_framev_fdnotify_fn fdnotfn)
1052b223c403Spooka {
1053e94b19cfSpooka struct puffs_framectrl *pfctrl;
1054b223c403Spooka
105561113f40Spooka pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER];
1056b223c403Spooka pfctrl->rfb = rfb;
1057b223c403Spooka pfctrl->wfb = wfb;
1058b223c403Spooka pfctrl->cmpfb = cmpfb;
1059dc9a9106Spooka pfctrl->gotfb = gotfb;
1060291fe845Spooka pfctrl->fdnotfn = fdnotfn;
10612b8177d9Spooka }
10622b8177d9Spooka
1063e94b19cfSpooka void
puffs__framev_exit(struct puffs_usermount * pu)1064d1d05d65Spooka puffs__framev_exit(struct puffs_usermount *pu)
1065e94b19cfSpooka {
1066e94b19cfSpooka struct puffs_fctrl_io *fio;
1067b223c403Spooka
106861113f40Spooka while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL)
1069291fe845Spooka removefio(pu, fio, ENXIO);
107061113f40Spooka free(pu->pu_evs);
1071b223c403Spooka
1072e94b19cfSpooka /* closing pu->pu_kq takes care of puffsfd */
1073b223c403Spooka }
1074