xref: /netbsd-src/lib/libpuffs/framebuf.c (revision 388550b026d49b7f7b7480b1113bf82bb8d6a480)
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, &notresp) == 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