xref: /minix3/lib/libpuffs/requests.c (revision ba736c796854b82e29da17267614db0a449419db)
1*84d9c625SLionel Sambuc /*	$NetBSD: requests.c,v 1.24 2013/01/23 20:22:34 riastradh Exp $	*/
2*84d9c625SLionel Sambuc 
3*84d9c625SLionel Sambuc /*
4*84d9c625SLionel Sambuc  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
5*84d9c625SLionel Sambuc  *
6*84d9c625SLionel Sambuc  * Development of this software was supported by the
7*84d9c625SLionel Sambuc  * Research Foundation of Helsinki University of Technology
8*84d9c625SLionel Sambuc  *
9*84d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
10*84d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions
11*84d9c625SLionel Sambuc  * are met:
12*84d9c625SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
13*84d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
14*84d9c625SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
15*84d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
16*84d9c625SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
17*84d9c625SLionel Sambuc  *
18*84d9c625SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19*84d9c625SLionel Sambuc  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20*84d9c625SLionel Sambuc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21*84d9c625SLionel Sambuc  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*84d9c625SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*84d9c625SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24*84d9c625SLionel Sambuc  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*84d9c625SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*84d9c625SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*84d9c625SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*84d9c625SLionel Sambuc  * SUCH DAMAGE.
29*84d9c625SLionel Sambuc  */
30*84d9c625SLionel Sambuc 
31*84d9c625SLionel Sambuc #include <sys/cdefs.h>
32*84d9c625SLionel Sambuc #if !defined(lint)
33*84d9c625SLionel Sambuc __RCSID("$NetBSD: requests.c,v 1.24 2013/01/23 20:22:34 riastradh Exp $");
34*84d9c625SLionel Sambuc #endif /* !lint */
35*84d9c625SLionel Sambuc 
36*84d9c625SLionel Sambuc #include <sys/types.h>
37*84d9c625SLionel Sambuc #include <sys/ioctl.h>
38*84d9c625SLionel Sambuc #include <sys/queue.h>
39*84d9c625SLionel Sambuc #include <sys/socket.h>
40*84d9c625SLionel Sambuc 
41*84d9c625SLionel Sambuc #include <dev/putter/putter.h>
42*84d9c625SLionel Sambuc 
43*84d9c625SLionel Sambuc #include <assert.h>
44*84d9c625SLionel Sambuc #include <errno.h>
45*84d9c625SLionel Sambuc #include <puffs.h>
46*84d9c625SLionel Sambuc #include <stdio.h>
47*84d9c625SLionel Sambuc #include <stdlib.h>
48*84d9c625SLionel Sambuc #include <unistd.h>
49*84d9c625SLionel Sambuc 
50*84d9c625SLionel Sambuc #include "puffs_priv.h"
51*84d9c625SLionel Sambuc 
52*84d9c625SLionel Sambuc /*
53*84d9c625SLionel Sambuc  * Read a frame from the upstream provider.  First read the frame
54*84d9c625SLionel Sambuc  * length and after this read the actual contents.  Yes, optimize
55*84d9c625SLionel Sambuc  * me some day.
56*84d9c625SLionel Sambuc  */
57*84d9c625SLionel Sambuc /*ARGSUSED*/
58*84d9c625SLionel Sambuc int
puffs__fsframe_read(struct puffs_usermount * pu,struct puffs_framebuf * pb,int fd,int * done)59*84d9c625SLionel Sambuc puffs__fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
60*84d9c625SLionel Sambuc 	int fd, int *done)
61*84d9c625SLionel Sambuc {
62*84d9c625SLionel Sambuc 	struct putter_hdr phdr;
63*84d9c625SLionel Sambuc 	void *win;
64*84d9c625SLionel Sambuc 	size_t howmuch, winlen, curoff;
65*84d9c625SLionel Sambuc 	ssize_t n;
66*84d9c625SLionel Sambuc 	int lenstate;
67*84d9c625SLionel Sambuc 
68*84d9c625SLionel Sambuc 	/* How much to read? */
69*84d9c625SLionel Sambuc  the_next_level:
70*84d9c625SLionel Sambuc 	curoff = puffs_framebuf_telloff(pb);
71*84d9c625SLionel Sambuc 	if (curoff < sizeof(struct putter_hdr)) {
72*84d9c625SLionel Sambuc 		howmuch = sizeof(struct putter_hdr) - curoff;
73*84d9c625SLionel Sambuc 		lenstate = 1;
74*84d9c625SLionel Sambuc 	} else {
75*84d9c625SLionel Sambuc 		puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
76*84d9c625SLionel Sambuc 		/*LINTED*/
77*84d9c625SLionel Sambuc 		howmuch = phdr.pth_framelen - curoff;
78*84d9c625SLionel Sambuc 		lenstate = 0;
79*84d9c625SLionel Sambuc 	}
80*84d9c625SLionel Sambuc 
81*84d9c625SLionel Sambuc 	if (puffs_framebuf_reserve_space(pb, howmuch) == -1)
82*84d9c625SLionel Sambuc 		return errno;
83*84d9c625SLionel Sambuc 
84*84d9c625SLionel Sambuc 	/* Read contents */
85*84d9c625SLionel Sambuc 	while (howmuch) {
86*84d9c625SLionel Sambuc 		winlen = howmuch;
87*84d9c625SLionel Sambuc 		curoff = puffs_framebuf_telloff(pb);
88*84d9c625SLionel Sambuc 		if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
89*84d9c625SLionel Sambuc 			return errno;
90*84d9c625SLionel Sambuc 		n = read(fd, win, winlen);
91*84d9c625SLionel Sambuc 		switch (n) {
92*84d9c625SLionel Sambuc 		case 0:
93*84d9c625SLionel Sambuc 			return ECONNRESET;
94*84d9c625SLionel Sambuc 		case -1:
95*84d9c625SLionel Sambuc 			if (errno == EAGAIN)
96*84d9c625SLionel Sambuc 				return 0;
97*84d9c625SLionel Sambuc 			return errno;
98*84d9c625SLionel Sambuc 		default:
99*84d9c625SLionel Sambuc 			howmuch -= n;
100*84d9c625SLionel Sambuc 			puffs_framebuf_seekset(pb, curoff + n);
101*84d9c625SLionel Sambuc 			break;
102*84d9c625SLionel Sambuc 		}
103*84d9c625SLionel Sambuc 	}
104*84d9c625SLionel Sambuc 
105*84d9c625SLionel Sambuc 	if (lenstate)
106*84d9c625SLionel Sambuc 		goto the_next_level;
107*84d9c625SLionel Sambuc 
108*84d9c625SLionel Sambuc 	puffs_framebuf_seekset(pb, 0);
109*84d9c625SLionel Sambuc 	*done = 1;
110*84d9c625SLionel Sambuc 	return 0;
111*84d9c625SLionel Sambuc }
112*84d9c625SLionel Sambuc 
113*84d9c625SLionel Sambuc /*
114*84d9c625SLionel Sambuc  * Write a frame upstream
115*84d9c625SLionel Sambuc  */
116*84d9c625SLionel Sambuc /*ARGSUSED*/
117*84d9c625SLionel Sambuc int
puffs__fsframe_write(struct puffs_usermount * pu,struct puffs_framebuf * pb,int fd,int * done)118*84d9c625SLionel Sambuc puffs__fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
119*84d9c625SLionel Sambuc 	int fd, int *done)
120*84d9c625SLionel Sambuc {
121*84d9c625SLionel Sambuc 	void *win;
122*84d9c625SLionel Sambuc 	uint64_t flen;
123*84d9c625SLionel Sambuc 	size_t winlen, howmuch, curoff;
124*84d9c625SLionel Sambuc 	ssize_t n;
125*84d9c625SLionel Sambuc 	int rv;
126*84d9c625SLionel Sambuc 
127*84d9c625SLionel Sambuc 	/*
128*84d9c625SLionel Sambuc 	 * Finalize it if we haven't written anything yet (or we're still
129*84d9c625SLionel Sambuc 	 * attempting to write the first byte)
130*84d9c625SLionel Sambuc 	 *
131*84d9c625SLionel Sambuc 	 * XXX: this shouldn't be here
132*84d9c625SLionel Sambuc 	 */
133*84d9c625SLionel Sambuc 	if (puffs_framebuf_telloff(pb) == 0) {
134*84d9c625SLionel Sambuc 		struct puffs_req *preq;
135*84d9c625SLionel Sambuc 
136*84d9c625SLionel Sambuc 		winlen = sizeof(struct puffs_req);
137*84d9c625SLionel Sambuc 		rv = puffs_framebuf_getwindow(pb, 0, (void *)&preq, &winlen);
138*84d9c625SLionel Sambuc 		if (rv == -1)
139*84d9c625SLionel Sambuc 			return errno;
140*84d9c625SLionel Sambuc 		preq->preq_pth.pth_framelen = flen = preq->preq_buflen;
141*84d9c625SLionel Sambuc 	} else {
142*84d9c625SLionel Sambuc 		struct putter_hdr phdr;
143*84d9c625SLionel Sambuc 
144*84d9c625SLionel Sambuc 		puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
145*84d9c625SLionel Sambuc 		flen = phdr.pth_framelen;
146*84d9c625SLionel Sambuc 	}
147*84d9c625SLionel Sambuc 
148*84d9c625SLionel Sambuc 	/*
149*84d9c625SLionel Sambuc 	 * Then write it.  Chances are if we are talking to the kernel it'll
150*84d9c625SLionel Sambuc 	 * just shlosh in all at once, but if we're e.g. talking to the
151*84d9c625SLionel Sambuc 	 * network it might take a few tries.
152*84d9c625SLionel Sambuc 	 */
153*84d9c625SLionel Sambuc 	/*LINTED*/
154*84d9c625SLionel Sambuc 	howmuch = flen - puffs_framebuf_telloff(pb);
155*84d9c625SLionel Sambuc 
156*84d9c625SLionel Sambuc 	while (howmuch) {
157*84d9c625SLionel Sambuc 		winlen = howmuch;
158*84d9c625SLionel Sambuc 		curoff = puffs_framebuf_telloff(pb);
159*84d9c625SLionel Sambuc 		if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
160*84d9c625SLionel Sambuc 			return errno;
161*84d9c625SLionel Sambuc 
162*84d9c625SLionel Sambuc 		/*
163*84d9c625SLionel Sambuc 		 * XXX: we know from the framebuf implementation that we
164*84d9c625SLionel Sambuc 		 * will always managed to map the entire window.  But if
165*84d9c625SLionel Sambuc 		 * that changes, this will catch it.  Then we can do stuff
166*84d9c625SLionel Sambuc 		 * iov stuff instead.
167*84d9c625SLionel Sambuc 		 */
168*84d9c625SLionel Sambuc 		assert(winlen == howmuch);
169*84d9c625SLionel Sambuc 
170*84d9c625SLionel Sambuc 		/* XXX: want NOSIGNAL if writing to a pipe */
171*84d9c625SLionel Sambuc #if 0
172*84d9c625SLionel Sambuc 		n = send(fd, win, winlen, MSG_NOSIGNAL);
173*84d9c625SLionel Sambuc #else
174*84d9c625SLionel Sambuc 		n = write(fd, win, winlen);
175*84d9c625SLionel Sambuc #endif
176*84d9c625SLionel Sambuc 		switch (n) {
177*84d9c625SLionel Sambuc 		case 0:
178*84d9c625SLionel Sambuc 			return ECONNRESET;
179*84d9c625SLionel Sambuc 		case -1:
180*84d9c625SLionel Sambuc 			if (errno == EAGAIN)
181*84d9c625SLionel Sambuc 				return 0;
182*84d9c625SLionel Sambuc 			return errno;
183*84d9c625SLionel Sambuc 		default:
184*84d9c625SLionel Sambuc 			howmuch -= n;
185*84d9c625SLionel Sambuc 			puffs_framebuf_seekset(pb, curoff + n);
186*84d9c625SLionel Sambuc 			break;
187*84d9c625SLionel Sambuc 		}
188*84d9c625SLionel Sambuc 	}
189*84d9c625SLionel Sambuc 
190*84d9c625SLionel Sambuc 	*done = 1;
191*84d9c625SLionel Sambuc 	return 0;
192*84d9c625SLionel Sambuc }
193*84d9c625SLionel Sambuc 
194*84d9c625SLionel Sambuc /*
195*84d9c625SLionel Sambuc  * Compare if "pb1" is a response to a previously sent frame pb2.
196*84d9c625SLionel Sambuc  * More often than not "pb1" is not a response to anything but
197*84d9c625SLionel Sambuc  * rather a fresh request from the kernel.
198*84d9c625SLionel Sambuc  */
199*84d9c625SLionel Sambuc /*ARGSUSED*/
200*84d9c625SLionel Sambuc int
puffs__fsframe_cmp(struct puffs_usermount * pu,struct puffs_framebuf * pb1,struct puffs_framebuf * pb2,int * notresp)201*84d9c625SLionel Sambuc puffs__fsframe_cmp(struct puffs_usermount *pu,
202*84d9c625SLionel Sambuc 	struct puffs_framebuf *pb1, struct puffs_framebuf *pb2, int *notresp)
203*84d9c625SLionel Sambuc {
204*84d9c625SLionel Sambuc 	struct puffs_req *preq1, *preq2;
205*84d9c625SLionel Sambuc 	size_t winlen;
206*84d9c625SLionel Sambuc 	int rv;
207*84d9c625SLionel Sambuc 
208*84d9c625SLionel Sambuc 	/* map incoming preq */
209*84d9c625SLionel Sambuc 	winlen = sizeof(struct puffs_req);
210*84d9c625SLionel Sambuc 	rv = puffs_framebuf_getwindow(pb1, 0, (void *)&preq1, &winlen);
211*84d9c625SLionel Sambuc 	assert(rv == 0); /* frames are always at least puffs_req in size */
212*84d9c625SLionel Sambuc 	assert(winlen == sizeof(struct puffs_req));
213*84d9c625SLionel Sambuc 
214*84d9c625SLionel Sambuc 	/*
215*84d9c625SLionel Sambuc 	 * Check if this is not a response in this slot.  That's the
216*84d9c625SLionel Sambuc 	 * likely case.
217*84d9c625SLionel Sambuc 	 */
218*84d9c625SLionel Sambuc 	if ((preq1->preq_opclass & PUFFSOPFLAG_ISRESPONSE) == 0) {
219*84d9c625SLionel Sambuc 		*notresp = 1;
220*84d9c625SLionel Sambuc 		return 0;
221*84d9c625SLionel Sambuc 	}
222*84d9c625SLionel Sambuc 
223*84d9c625SLionel Sambuc 	/* map second preq */
224*84d9c625SLionel Sambuc 	winlen = sizeof(struct puffs_req);
225*84d9c625SLionel Sambuc 	rv = puffs_framebuf_getwindow(pb2, 0, (void *)&preq2, &winlen);
226*84d9c625SLionel Sambuc 	assert(rv == 0); /* frames are always at least puffs_req in size */
227*84d9c625SLionel Sambuc 	assert(winlen == sizeof(struct puffs_req));
228*84d9c625SLionel Sambuc 
229*84d9c625SLionel Sambuc 	/* then compare: resid equal? */
230*84d9c625SLionel Sambuc 	return preq1->preq_id != preq2->preq_id;
231*84d9c625SLionel Sambuc }
232*84d9c625SLionel Sambuc 
233*84d9c625SLionel Sambuc void
puffs__fsframe_gotframe(struct puffs_usermount * pu,struct puffs_framebuf * pb)234*84d9c625SLionel Sambuc puffs__fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
235*84d9c625SLionel Sambuc {
236*84d9c625SLionel Sambuc 
237*84d9c625SLionel Sambuc 	puffs_framebuf_seekset(pb, 0);
238*84d9c625SLionel Sambuc 	puffs__ml_dispatch(pu, pb);
239*84d9c625SLionel Sambuc }
240