framebuf.c revision 1.5 1 /* $NetBSD: framebuf.c,v 1.5 2007/05/11 16:22:38 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Finnish Cultural Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 #if !defined(lint)
33 __RCSID("$NetBSD: framebuf.c,v 1.5 2007/05/11 16:22:38 pooka Exp $");
34 #endif /* !lint */
35
36 #include <sys/types.h>
37 #include <sys/queue.h>
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <poll.h>
42 #include <puffs.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45
46 #include "puffs_priv.h"
47
48 struct puffs_framebuf {
49 struct puffs_cc *pcc; /* pcc to continue with */
50 /* OR */
51 puffs_framebuf_cb fcb; /* non-blocking callback */
52 void *fcb_arg; /* argument for previous */
53
54 uint8_t *buf; /* buffer base */
55 size_t len; /* total length */
56
57 size_t offset; /* cursor, telloff() */
58 size_t maxoff; /* maximum offset for data, tellsize() */
59
60 volatile int rv; /* errno value for pcc framebufs */
61
62 int istat;
63
64 TAILQ_ENTRY(puffs_framebuf) pfb_entries;
65 };
66 #define ISTAT_NODESTROY 0x01 /* indestructible by framebuf_destroy() */
67 #define ISTAT_INTERNAL 0x02 /* never leaves library */
68 #define ISTAT_NOREPLY 0x04 /* nuke after sending */
69
70 struct puffs_fctrl_io {
71 int io_fd;
72 int wrstat;
73
74 struct puffs_framebuf *cur_in;
75
76 TAILQ_HEAD(, puffs_framebuf) snd_qing; /* queueing to be sent */
77 TAILQ_HEAD(, puffs_framebuf) res_qing; /* q'ing for rescue */
78
79 LIST_ENTRY(puffs_fctrl_io) fio_entries;
80 };
81 #define EN_WRITE(fio) (fio->wrstat == 0 && !TAILQ_EMPTY(&fio->snd_qing))
82 #define RM_WRITE(fio) (fio->wrstat == 1 && TAILQ_EMPTY(&fio->snd_qing))
83
84 struct puffs_framectrl {
85 puffs_framebuf_readframe_fn rfb;
86 puffs_framebuf_writeframe_fn wfb;
87 puffs_framebuf_respcmp_fn cmpfb;
88
89 struct kevent *evs;
90 struct kevent *ch_evs;
91 size_t nevs;
92 int kq;
93
94 LIST_HEAD(, puffs_fctrl_io) fb_ios;
95 };
96
97 #define PUFBUF_INCRALLOC 65536 /* 64k ought to be enough for anyone */
98 #define PUFBUF_REMAIN(p) (p->len - p->offset)
99
100 static struct puffs_fctrl_io *
101 getfiobyfd(struct puffs_usermount *pu, int fd)
102 {
103 struct puffs_fctrl_io *fio;
104
105 LIST_FOREACH(fio, &pu->pu_framectrl->fb_ios, fio_entries)
106 if (fio->io_fd == fd)
107 return fio;
108 return NULL;
109 }
110
111 struct puffs_framebuf *
112 puffs_framebuf_make()
113 {
114 struct puffs_framebuf *pufbuf;
115
116 pufbuf = malloc(sizeof(struct puffs_framebuf));
117 if (pufbuf == NULL)
118 return NULL;
119 memset(pufbuf, 0, sizeof(struct puffs_framebuf));
120
121 pufbuf->buf = malloc(PUFBUF_INCRALLOC);
122 pufbuf->len = PUFBUF_INCRALLOC;
123 if (pufbuf->buf == NULL) {
124 free(pufbuf);
125 return NULL;
126 }
127
128 puffs_framebuf_recycle(pufbuf);
129 return pufbuf;
130 }
131
132 void
133 puffs_framebuf_destroy(struct puffs_framebuf *pufbuf)
134 {
135
136 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
137
138 free(pufbuf->buf);
139 free(pufbuf);
140 }
141
142 void
143 puffs_framebuf_recycle(struct puffs_framebuf *pufbuf)
144 {
145
146 assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
147
148 pufbuf->offset = 0;
149 pufbuf->maxoff = 0;
150 pufbuf->istat = 0;
151 }
152
153 static int
154 reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize)
155 {
156 size_t incr;
157 void *nd;
158
159 if (off <= pufbuf->len && pufbuf->len - off >= wantsize)
160 return 0;
161
162 for (incr = PUFBUF_INCRALLOC;
163 pufbuf->len + incr < off + wantsize;
164 incr += PUFBUF_INCRALLOC)
165 continue;
166
167 nd = realloc(pufbuf->buf, pufbuf->offset + incr);
168 if (nd == NULL)
169 return -1;
170
171 pufbuf->buf = nd;
172 pufbuf->len += incr;
173
174 return 0;
175 }
176
177 int
178 puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize)
179 {
180
181 return reservespace(pufbuf, pufbuf->offset, wantsize);
182 }
183
184 int
185 puffs_framebuf_putdata(struct puffs_framebuf *pufbuf,
186 const void *data, size_t dlen)
187 {
188
189 if (PUFBUF_REMAIN(pufbuf) < dlen)
190 if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1)
191 return -1;
192
193 memcpy(pufbuf->buf + pufbuf->offset, data, dlen);
194 pufbuf->offset += dlen;
195
196 if (pufbuf->offset > pufbuf->maxoff)
197 pufbuf->maxoff = pufbuf->offset;
198
199 return 0;
200 }
201
202 int
203 puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
204 const void *data, size_t dlen)
205 {
206
207 if (reservespace(pufbuf, offset, dlen) == -1)
208 return -1;
209
210 memcpy(pufbuf->buf + offset, data, dlen);
211
212 if (offset + dlen > pufbuf->maxoff)
213 pufbuf->maxoff = offset + dlen;
214
215 return 0;
216 }
217
218 int
219 puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen)
220 {
221
222 if (pufbuf->maxoff < pufbuf->offset + dlen) {
223 errno = ENOBUFS;
224 return -1;
225 }
226
227 memcpy(data, pufbuf->buf + pufbuf->offset, dlen);
228 pufbuf->offset += dlen;
229
230 return 0;
231 }
232
233 int
234 puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset,
235 void *data, size_t dlen)
236 {
237
238 if (pufbuf->maxoff < offset + dlen) {
239 errno = ENOBUFS;
240 return -1;
241 }
242
243 memcpy(data, pufbuf->buf + offset, dlen);
244 return 0;
245 }
246
247 size_t
248 puffs_framebuf_telloff(struct puffs_framebuf *pufbuf)
249 {
250
251 return pufbuf->offset;
252 }
253
254 size_t
255 puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf)
256 {
257
258 return pufbuf->maxoff;
259 }
260
261 size_t
262 puffs_framebuf_remaining(struct puffs_framebuf *pufbuf)
263 {
264
265 return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf);
266 }
267
268 int
269 puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff)
270 {
271
272 if (reservespace(pufbuf, newoff, 0) == -1)
273 return -1;
274
275 pufbuf->offset = newoff;
276 return 0;
277 }
278
279 int
280 puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff,
281 void **data, size_t *dlen)
282 {
283 size_t winlen;
284
285 #ifdef WINTESTING
286 winlen = MIN(*dlen, 32);
287 #else
288 winlen = *dlen;
289 #endif
290
291 if (reservespace(pufbuf, winoff, winlen) == -1)
292 return -1;
293
294 *data = pufbuf->buf + winoff;
295 if (pufbuf->maxoff < winoff + winlen)
296 pufbuf->maxoff = winoff + winlen;
297
298 return 0;
299 }
300
301 int
302 puffs_framebuf_enqueue_cc(struct puffs_cc *pcc, int fd,
303 struct puffs_framebuf *pufbuf)
304 {
305 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
306 struct puffs_fctrl_io *fio;
307
308 fio = getfiobyfd(pu, fd);
309 if (fio == NULL) {
310 errno = EINVAL;
311 return -1;
312 }
313
314 pufbuf->pcc = pcc;
315 pufbuf->fcb = NULL;
316 pufbuf->fcb_arg = NULL;
317
318 pufbuf->offset = 0;
319 pufbuf->istat |= ISTAT_NODESTROY;
320
321 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
322
323 puffs_cc_yield(pcc);
324 if (pufbuf->rv) {
325 errno = pufbuf->rv;
326 return -1;
327 }
328
329 return 0;
330 }
331
332 int
333 puffs_framebuf_enqueue_cb(struct puffs_usermount *pu, int fd,
334 struct puffs_framebuf *pufbuf, puffs_framebuf_cb fcb, void *arg)
335 {
336 struct puffs_fctrl_io *fio;
337
338 fio = getfiobyfd(pu, fd);
339 if (fio == NULL) {
340 errno = EINVAL;
341 return -1;
342 }
343
344 pufbuf->pcc = NULL;
345 pufbuf->fcb = fcb;
346 pufbuf->fcb_arg = arg;
347
348 pufbuf->offset = 0;
349 pufbuf->istat |= ISTAT_NODESTROY;
350
351 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
352
353 return 0;
354 }
355
356 int
357 puffs_framebuf_enqueue_justsend(struct puffs_usermount *pu, int fd,
358 struct puffs_framebuf *pufbuf, int reply)
359 {
360 struct puffs_fctrl_io *fio;
361
362 fio = getfiobyfd(pu, fd);
363 if (fio == NULL) {
364 errno = EINVAL;
365 return -1;
366 }
367
368 pufbuf->pcc = NULL;
369 pufbuf->fcb = NULL;
370 pufbuf->fcb_arg = NULL;
371
372 pufbuf->offset = 0;
373 pufbuf->istat |= ISTAT_NODESTROY;
374 if (!reply)
375 pufbuf->istat |= ISTAT_NOREPLY;
376
377 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries);
378
379 return 0;
380 }
381
382 static struct puffs_framebuf *
383 findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
384 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme)
385 {
386 struct puffs_framebuf *cand;
387
388 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries)
389 if (fctrl->cmpfb(pu, findme, cand))
390 break;
391
392 if (cand == NULL)
393 return NULL;
394
395 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries);
396 return cand;
397 }
398
399 static void
400 moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
401 {
402
403 assert(from->istat & ISTAT_INTERNAL);
404
405 /* migrate buffer */
406 free(to->buf);
407 to->buf = from->buf;
408 from->buf = NULL;
409
410 /* migrate buffer info */
411 to->len = from->len;
412 to->offset = from->offset;
413 to->maxoff = from->maxoff;
414 }
415
416 static int
417 handle_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
418 struct puffs_fctrl_io *fio, struct puffs_putreq *ppr)
419 {
420 struct puffs_framebuf *pufbuf, *appbuf;
421 int rv, complete;
422
423 for (;;) {
424 if ((pufbuf = fio->cur_in) == NULL) {
425 pufbuf = puffs_framebuf_make();
426 if (pufbuf == NULL)
427 return -1;
428 pufbuf->istat |= ISTAT_INTERNAL;
429 fio->cur_in = pufbuf;
430 }
431
432 complete = 0;
433 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete);
434
435 /* error */
436 if (rv) {
437 errno = rv;
438 return -1;
439 }
440
441 /* partial read, come back to fight another day */
442 if (complete == 0)
443 break;
444
445 /* else: full read, process */
446
447 appbuf = findbuf(pu, fctrl, fio, pufbuf);
448 if (appbuf == NULL) {
449 errno = ENOMSG;
450 return -1;
451 }
452
453 appbuf->istat &= ~ISTAT_NODESTROY;
454 moveinfo(pufbuf, appbuf);
455 if (appbuf->pcc) {
456 puffs_docc(appbuf->pcc, ppr);
457 } else if (appbuf->fcb) {
458 appbuf->fcb(pu, appbuf, appbuf->fcb_arg);
459 } else {
460 puffs_framebuf_destroy(appbuf);
461 }
462 puffs_framebuf_destroy(pufbuf);
463
464 /* hopeless romantics, here we go again */
465 fio->cur_in = NULL;
466 }
467
468 return rv;
469 }
470
471 static int
472 handle_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
473 struct puffs_fctrl_io *fio)
474 {
475 struct puffs_framebuf *pufbuf, *pufbuf_next;
476 int rv, complete;
477
478 for (pufbuf = TAILQ_FIRST(&fio->snd_qing);
479 pufbuf;
480 pufbuf = pufbuf_next) {
481 complete = 0;
482 pufbuf_next = TAILQ_NEXT(pufbuf, pfb_entries);
483 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
484
485 if (rv) {
486 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
487 pufbuf->rv = rv;
488 errno = rv;
489 return -1;
490 }
491
492 /* partial write */
493 if (complete == 0)
494 return 0;
495
496 /* else, complete write */
497 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
498
499 if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
500 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
501 pfb_entries);
502 } else {
503 pufbuf->istat &= ~ISTAT_NODESTROY;
504 puffs_framebuf_destroy(pufbuf);
505 }
506 }
507
508 return 0;
509 }
510
511 int
512 puffs_framebuf_addfd(struct puffs_usermount *pu, int fd)
513 {
514 struct puffs_framectrl *pfctrl = pu->pu_framectrl;
515 struct puffs_fctrl_io *fio;
516 struct kevent kev[2];
517 struct kevent *newevs;
518 int rv;
519
520 newevs = realloc(pfctrl->evs, (2*pfctrl->nevs+1)*sizeof(struct kevent));
521 if (newevs == NULL)
522 return -1;
523 pfctrl->evs = newevs;
524
525 newevs = realloc(pfctrl->ch_evs, pfctrl->nevs * sizeof(struct kevent));
526 if (newevs == NULL)
527 return -1;
528 pfctrl->ch_evs = newevs;
529
530 fio = malloc(sizeof(struct puffs_fctrl_io));
531 if (fio == NULL)
532 return -1;
533
534 EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, (intptr_t)fio);
535 EV_SET(&kev[1], fd, EVFILT_WRITE, EV_ADD|EV_DISABLE, 0,0,(intptr_t)fio);
536 rv = kevent(pfctrl->kq, kev, 2, NULL, 0, NULL);
537 if (rv == -1) {
538 free(fio);
539 return -1;
540 }
541
542 fio->io_fd = fd;
543 fio->cur_in = NULL;
544 fio->wrstat = 0;
545 TAILQ_INIT(&fio->snd_qing);
546 TAILQ_INIT(&fio->res_qing);
547
548 LIST_INSERT_HEAD(&pfctrl->fb_ios, fio, fio_entries);
549 pfctrl->nevs++;
550
551 return 0;
552 }
553
554 static int
555 removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio)
556 {
557 struct puffs_framectrl *pfctrl = pu->pu_framectrl;
558 struct puffs_framebuf *pufbuf;
559 struct kevent kev[2];
560
561 /* found, now remove */
562 EV_SET(&kev[0], fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
563 EV_SET(&kev[1], fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
564 (void) kevent(pfctrl->kq, kev, 2, NULL, 0, NULL);
565
566 LIST_REMOVE(fio, fio_entries);
567
568 /* free buffers */
569 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) {
570 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries);
571 puffs_framebuf_destroy(pufbuf);
572 }
573 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) {
574 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries);
575 puffs_framebuf_destroy(pufbuf);
576 }
577 if (fio->cur_in)
578 puffs_framebuf_destroy(fio->cur_in);
579 free(fio);
580
581 /* don't bother with realloc */
582 pfctrl->nevs--;
583
584 return 0;
585
586 }
587
588 int
589 puffs_framebuf_removefd(struct puffs_usermount *pu, int fd)
590 {
591 struct puffs_fctrl_io *fio;
592
593 fio = getfiobyfd(pu, fd);
594 if (fio == NULL) {
595 errno = ENXIO;
596 return -1;
597 }
598
599 return removefio(pu, fio);
600 }
601
602 int
603 puffs_framebuf_eventloop(struct puffs_usermount *pu, int *io_fds, size_t nfds,
604 puffs_framebuf_readframe_fn rfb, puffs_framebuf_writeframe_fn wfb,
605 puffs_framebuf_respcmp_fn cmpfb,
606 puffs_framebuf_loop_fn lfb)
607 {
608 struct puffs_getreq *pgr = NULL;
609 struct puffs_putreq *ppr = NULL;
610 struct puffs_framectrl *pfctrl = NULL;
611 struct puffs_fctrl_io *fio;
612 struct kevent kev;
613 struct kevent *curev;
614 size_t nchanges;
615 int puffsfd, sverrno;
616 int ndone;
617
618 assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
619
620 pgr = puffs_req_makeget(pu, puffs_getmaxreqlen(pu), 0);
621 if (pgr == NULL)
622 goto out;
623
624 ppr = puffs_req_makeput(pu);
625 if (ppr == NULL)
626 goto out;
627
628 pfctrl = malloc(sizeof(struct puffs_framectrl));
629 if (pfctrl == NULL)
630 goto out;
631 pfctrl->rfb = rfb;
632 pfctrl->wfb = wfb;
633 pfctrl->cmpfb = cmpfb;
634 pfctrl->evs = malloc(sizeof(struct kevent));
635 if (pfctrl->evs == NULL)
636 goto out;
637 pfctrl->ch_evs = NULL;
638 pfctrl->nevs = 1;
639 pfctrl->kq = kqueue();
640 if (pfctrl->kq == -1)
641 goto out;
642 LIST_INIT(&pfctrl->fb_ios);
643 pu->pu_framectrl = pfctrl;
644
645 for (; nfds--; io_fds++)
646 if (puffs_framebuf_addfd(pu, *io_fds) == -1)
647 goto out;
648
649 puffsfd = puffs_getselectable(pu);
650 EV_SET(&kev, puffsfd, EVFILT_READ, EV_ADD, 0, 0, 0);
651 if (kevent(pfctrl->kq, &kev, 1, NULL, 0, NULL) == -1)
652 goto out;
653
654 while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
655 if (lfb)
656 lfb(pu);
657
658 /*
659 * Build list of which to enable/disable in writecheck.
660 * Don't bother worrying about O(n) for now.
661 */
662 nchanges = 0;
663 LIST_FOREACH(fio, &pfctrl->fb_ios, fio_entries) {
664 /*
665 * Try to write out everything to avoid the
666 * need for enabling EVFILT_WRITE. The likely
667 * case is that we can fit everything into the
668 * socket buffer.
669 */
670 if (handle_output(pu, pfctrl, fio) == -1)
671 goto out;
672
673 assert((EN_WRITE(fio) && RM_WRITE(fio)) == 0);
674 if (EN_WRITE(fio)) {
675 EV_SET(&pfctrl->ch_evs[nchanges], fio->io_fd,
676 EVFILT_WRITE, EV_ENABLE, 0, 0,
677 (uintptr_t)fio);
678 fio->wrstat = 1; /* XXX: not before call */
679 nchanges++;
680 }
681 if (RM_WRITE(fio)) {
682 EV_SET(&pfctrl->ch_evs[nchanges], fio->io_fd,
683 EVFILT_WRITE, EV_DISABLE, 0, 0,
684 (uintptr_t)fio);
685 fio->wrstat = 0; /* XXX: not before call */
686 nchanges++;
687 }
688 }
689
690 ndone = kevent(pfctrl->kq, pfctrl->ch_evs, nchanges,
691 pfctrl->evs, pfctrl->nevs, NULL);
692 if (ndone == -1)
693 goto out;
694
695 /* XXX: handle errors */
696
697 /* iterate over the results */
698 for (curev = pfctrl->evs; ndone--; curev++) {
699 /* get & possibly dispatch events from kernel */
700 if (curev->ident == puffsfd) {
701 if (puffs_req_handle(pgr, ppr, 0) == -1)
702 goto out;
703 continue;
704 }
705
706 if (curev->filter == EVFILT_READ) {
707 if (handle_input(pu, pfctrl,
708 (void *)curev->udata, ppr) == -1)
709 goto out;
710 }
711
712 if (curev->filter == EVFILT_WRITE) {
713 if (handle_output(pu, pfctrl,
714 (void *)curev->udata) == -1)
715 goto out;
716 }
717 }
718
719 /* stuff all replies from both of the above into kernel */
720 if (puffs_req_putput(ppr) == -1)
721 goto out;
722 puffs_req_resetput(ppr);
723 }
724 errno = 0;
725
726 out:
727 /* store the real error for a while */
728 sverrno = errno;
729
730 if (pfctrl) {
731 while ((fio = LIST_FIRST(&pfctrl->fb_ios)) != NULL)
732 removefio(pu, fio);
733 pu->pu_framectrl = NULL;
734 free(pfctrl->evs);
735 close(pfctrl->kq); /* takes care of puffsfd */
736 free(pfctrl);
737 }
738
739 if (ppr)
740 puffs_req_destroyput(ppr);
741 if (pgr)
742 puffs_req_destroyget(pgr);
743
744 errno = sverrno;
745 if (errno)
746 return -1;
747 else
748 return 0;
749 }
750