xref: /freebsd/contrib/lib9p/request.c (revision 134e1779)
1*134e1779SJakub Wojciech Klama /*
2*134e1779SJakub Wojciech Klama  * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
3*134e1779SJakub Wojciech Klama  * All rights reserved
4*134e1779SJakub Wojciech Klama  *
5*134e1779SJakub Wojciech Klama  * Redistribution and use in source and binary forms, with or without
6*134e1779SJakub Wojciech Klama  * modification, are permitted providing that the following conditions
7*134e1779SJakub Wojciech Klama  * are met:
8*134e1779SJakub Wojciech Klama  * 1. Redistributions of source code must retain the above copyright
9*134e1779SJakub Wojciech Klama  *    notice, this list of conditions and the following disclaimer.
10*134e1779SJakub Wojciech Klama  * 2. Redistributions in binary form must reproduce the above copyright
11*134e1779SJakub Wojciech Klama  *    notice, this list of conditions and the following disclaimer in the
12*134e1779SJakub Wojciech Klama  *    documentation and/or other materials provided with the distribution.
13*134e1779SJakub Wojciech Klama  *
14*134e1779SJakub Wojciech Klama  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*134e1779SJakub Wojciech Klama  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16*134e1779SJakub Wojciech Klama  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*134e1779SJakub Wojciech Klama  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18*134e1779SJakub Wojciech Klama  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*134e1779SJakub Wojciech Klama  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*134e1779SJakub Wojciech Klama  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*134e1779SJakub Wojciech Klama  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22*134e1779SJakub Wojciech Klama  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23*134e1779SJakub Wojciech Klama  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24*134e1779SJakub Wojciech Klama  * POSSIBILITY OF SUCH DAMAGE.
25*134e1779SJakub Wojciech Klama  *
26*134e1779SJakub Wojciech Klama  */
27*134e1779SJakub Wojciech Klama 
28*134e1779SJakub Wojciech Klama #include <stdlib.h>
29*134e1779SJakub Wojciech Klama #include <string.h>
30*134e1779SJakub Wojciech Klama #include <assert.h>
31*134e1779SJakub Wojciech Klama #include <errno.h>
32*134e1779SJakub Wojciech Klama #include <sys/param.h>
33*134e1779SJakub Wojciech Klama #include <sys/uio.h>
34*134e1779SJakub Wojciech Klama #if defined(__FreeBSD__)
35*134e1779SJakub Wojciech Klama #include <sys/sbuf.h>
36*134e1779SJakub Wojciech Klama #else
37*134e1779SJakub Wojciech Klama #include "sbuf/sbuf.h"
38*134e1779SJakub Wojciech Klama #endif
39*134e1779SJakub Wojciech Klama #include "lib9p.h"
40*134e1779SJakub Wojciech Klama #include "lib9p_impl.h"
41*134e1779SJakub Wojciech Klama #include "fcall.h"
42*134e1779SJakub Wojciech Klama #include "fid.h"
43*134e1779SJakub Wojciech Klama #include "hashtable.h"
44*134e1779SJakub Wojciech Klama #include "log.h"
45*134e1779SJakub Wojciech Klama #include "linux_errno.h"
46*134e1779SJakub Wojciech Klama #include "backend/backend.h"
47*134e1779SJakub Wojciech Klama #include "threadpool.h"
48*134e1779SJakub Wojciech Klama 
49*134e1779SJakub Wojciech Klama #define N(x)    (sizeof(x) / sizeof(x[0]))
50*134e1779SJakub Wojciech Klama 
51*134e1779SJakub Wojciech Klama static int l9p_dispatch_tversion(struct l9p_request *req);
52*134e1779SJakub Wojciech Klama static int l9p_dispatch_tattach(struct l9p_request *req);
53*134e1779SJakub Wojciech Klama static int l9p_dispatch_tclunk(struct l9p_request *req);
54*134e1779SJakub Wojciech Klama static int l9p_dispatch_tcreate(struct l9p_request *req);
55*134e1779SJakub Wojciech Klama static int l9p_dispatch_topen(struct l9p_request *req);
56*134e1779SJakub Wojciech Klama static int l9p_dispatch_tread(struct l9p_request *req);
57*134e1779SJakub Wojciech Klama static int l9p_dispatch_tremove(struct l9p_request *req);
58*134e1779SJakub Wojciech Klama static int l9p_dispatch_tstat(struct l9p_request *req);
59*134e1779SJakub Wojciech Klama static int l9p_dispatch_twalk(struct l9p_request *req);
60*134e1779SJakub Wojciech Klama static int l9p_dispatch_twrite(struct l9p_request *req);
61*134e1779SJakub Wojciech Klama static int l9p_dispatch_twstat(struct l9p_request *req);
62*134e1779SJakub Wojciech Klama static int l9p_dispatch_tstatfs(struct l9p_request *req);
63*134e1779SJakub Wojciech Klama static int l9p_dispatch_tlopen(struct l9p_request *req);
64*134e1779SJakub Wojciech Klama static int l9p_dispatch_tlcreate(struct l9p_request *req);
65*134e1779SJakub Wojciech Klama static int l9p_dispatch_tsymlink(struct l9p_request *req);
66*134e1779SJakub Wojciech Klama static int l9p_dispatch_tmknod(struct l9p_request *req);
67*134e1779SJakub Wojciech Klama static int l9p_dispatch_trename(struct l9p_request *req);
68*134e1779SJakub Wojciech Klama static int l9p_dispatch_treadlink(struct l9p_request *req);
69*134e1779SJakub Wojciech Klama static int l9p_dispatch_tgetattr(struct l9p_request *req);
70*134e1779SJakub Wojciech Klama static int l9p_dispatch_tsetattr(struct l9p_request *req);
71*134e1779SJakub Wojciech Klama static int l9p_dispatch_txattrwalk(struct l9p_request *req);
72*134e1779SJakub Wojciech Klama static int l9p_dispatch_txattrcreate(struct l9p_request *req);
73*134e1779SJakub Wojciech Klama static int l9p_dispatch_treaddir(struct l9p_request *req);
74*134e1779SJakub Wojciech Klama static int l9p_dispatch_tfsync(struct l9p_request *req);
75*134e1779SJakub Wojciech Klama static int l9p_dispatch_tlock(struct l9p_request *req);
76*134e1779SJakub Wojciech Klama static int l9p_dispatch_tgetlock(struct l9p_request *req);
77*134e1779SJakub Wojciech Klama static int l9p_dispatch_tlink(struct l9p_request *req);
78*134e1779SJakub Wojciech Klama static int l9p_dispatch_tmkdir(struct l9p_request *req);
79*134e1779SJakub Wojciech Klama static int l9p_dispatch_trenameat(struct l9p_request *req);
80*134e1779SJakub Wojciech Klama static int l9p_dispatch_tunlinkat(struct l9p_request *req);
81*134e1779SJakub Wojciech Klama 
82*134e1779SJakub Wojciech Klama /*
83*134e1779SJakub Wojciech Klama  * Each Txxx handler has a "must run" flag.  If it is false,
84*134e1779SJakub Wojciech Klama  * we check for a flush request before calling the handler.
85*134e1779SJakub Wojciech Klama  * If a flush is already requested we can instantly fail the
86*134e1779SJakub Wojciech Klama  * request with EINTR.
87*134e1779SJakub Wojciech Klama  *
88*134e1779SJakub Wojciech Klama  * Tclunk and Tremove must run because they make their fids
89*134e1779SJakub Wojciech Klama  * become invalid.  Tversion and Tattach should never get
90*134e1779SJakub Wojciech Klama  * a flush request applied (it makes no sense as the connection
91*134e1779SJakub Wojciech Klama  * is not really running yet), so it should be harmless to
92*134e1779SJakub Wojciech Klama  * set them either way, but for now we have them as must-run.
93*134e1779SJakub Wojciech Klama  * Flushing a Tflush is not really allowed either so we keep
94*134e1779SJakub Wojciech Klama  * these as must-run too (although they run without being done
95*134e1779SJakub Wojciech Klama  * threaded anyway).
96*134e1779SJakub Wojciech Klama  */
97*134e1779SJakub Wojciech Klama struct l9p_handler {
98*134e1779SJakub Wojciech Klama 	enum l9p_ftype type;
99*134e1779SJakub Wojciech Klama 	int (*handler)(struct l9p_request *);
100*134e1779SJakub Wojciech Klama 	bool must_run;
101*134e1779SJakub Wojciech Klama };
102*134e1779SJakub Wojciech Klama 
103*134e1779SJakub Wojciech Klama static const struct l9p_handler l9p_handlers_no_version[] = {
104*134e1779SJakub Wojciech Klama 	{L9P_TVERSION, l9p_dispatch_tversion, true},
105*134e1779SJakub Wojciech Klama };
106*134e1779SJakub Wojciech Klama 
107*134e1779SJakub Wojciech Klama static const struct l9p_handler l9p_handlers_base[] = {
108*134e1779SJakub Wojciech Klama 	{L9P_TVERSION, l9p_dispatch_tversion, true},
109*134e1779SJakub Wojciech Klama 	{L9P_TATTACH, l9p_dispatch_tattach, true},
110*134e1779SJakub Wojciech Klama 	{L9P_TCLUNK, l9p_dispatch_tclunk, true},
111*134e1779SJakub Wojciech Klama 	{L9P_TFLUSH, l9p_threadpool_tflush, true},
112*134e1779SJakub Wojciech Klama 	{L9P_TCREATE, l9p_dispatch_tcreate, false},
113*134e1779SJakub Wojciech Klama 	{L9P_TOPEN, l9p_dispatch_topen, false},
114*134e1779SJakub Wojciech Klama 	{L9P_TREAD, l9p_dispatch_tread, false},
115*134e1779SJakub Wojciech Klama 	{L9P_TWRITE, l9p_dispatch_twrite, false},
116*134e1779SJakub Wojciech Klama 	{L9P_TREMOVE, l9p_dispatch_tremove, true},
117*134e1779SJakub Wojciech Klama 	{L9P_TSTAT, l9p_dispatch_tstat, false},
118*134e1779SJakub Wojciech Klama 	{L9P_TWALK, l9p_dispatch_twalk, false},
119*134e1779SJakub Wojciech Klama 	{L9P_TWSTAT, l9p_dispatch_twstat, false}
120*134e1779SJakub Wojciech Klama };
121*134e1779SJakub Wojciech Klama static const struct l9p_handler l9p_handlers_dotu[] = {
122*134e1779SJakub Wojciech Klama 	{L9P_TVERSION, l9p_dispatch_tversion, true},
123*134e1779SJakub Wojciech Klama 	{L9P_TATTACH, l9p_dispatch_tattach, true},
124*134e1779SJakub Wojciech Klama 	{L9P_TCLUNK, l9p_dispatch_tclunk, true},
125*134e1779SJakub Wojciech Klama 	{L9P_TFLUSH, l9p_threadpool_tflush, true},
126*134e1779SJakub Wojciech Klama 	{L9P_TCREATE, l9p_dispatch_tcreate, false},
127*134e1779SJakub Wojciech Klama 	{L9P_TOPEN, l9p_dispatch_topen, false},
128*134e1779SJakub Wojciech Klama 	{L9P_TREAD, l9p_dispatch_tread, false},
129*134e1779SJakub Wojciech Klama 	{L9P_TWRITE, l9p_dispatch_twrite, false},
130*134e1779SJakub Wojciech Klama 	{L9P_TREMOVE, l9p_dispatch_tremove, true},
131*134e1779SJakub Wojciech Klama 	{L9P_TSTAT, l9p_dispatch_tstat, false},
132*134e1779SJakub Wojciech Klama 	{L9P_TWALK, l9p_dispatch_twalk, false},
133*134e1779SJakub Wojciech Klama 	{L9P_TWSTAT, l9p_dispatch_twstat, false}
134*134e1779SJakub Wojciech Klama };
135*134e1779SJakub Wojciech Klama static const struct l9p_handler l9p_handlers_dotL[] = {
136*134e1779SJakub Wojciech Klama 	{L9P_TVERSION, l9p_dispatch_tversion, true},
137*134e1779SJakub Wojciech Klama 	{L9P_TATTACH, l9p_dispatch_tattach, true},
138*134e1779SJakub Wojciech Klama 	{L9P_TCLUNK, l9p_dispatch_tclunk, true},
139*134e1779SJakub Wojciech Klama 	{L9P_TFLUSH, l9p_threadpool_tflush, true},
140*134e1779SJakub Wojciech Klama 	{L9P_TCREATE, l9p_dispatch_tcreate, false},
141*134e1779SJakub Wojciech Klama 	{L9P_TOPEN, l9p_dispatch_topen, false},
142*134e1779SJakub Wojciech Klama 	{L9P_TREAD, l9p_dispatch_tread, false},
143*134e1779SJakub Wojciech Klama 	{L9P_TWRITE, l9p_dispatch_twrite, false},
144*134e1779SJakub Wojciech Klama 	{L9P_TREMOVE, l9p_dispatch_tremove, true},
145*134e1779SJakub Wojciech Klama 	{L9P_TSTAT, l9p_dispatch_tstat, false},
146*134e1779SJakub Wojciech Klama 	{L9P_TWALK, l9p_dispatch_twalk, false},
147*134e1779SJakub Wojciech Klama 	{L9P_TWSTAT, l9p_dispatch_twstat, false},
148*134e1779SJakub Wojciech Klama 	{L9P_TSTATFS, l9p_dispatch_tstatfs, false},
149*134e1779SJakub Wojciech Klama 	{L9P_TLOPEN, l9p_dispatch_tlopen, false},
150*134e1779SJakub Wojciech Klama 	{L9P_TLCREATE, l9p_dispatch_tlcreate, false},
151*134e1779SJakub Wojciech Klama 	{L9P_TSYMLINK, l9p_dispatch_tsymlink, false},
152*134e1779SJakub Wojciech Klama 	{L9P_TMKNOD, l9p_dispatch_tmknod, false},
153*134e1779SJakub Wojciech Klama 	{L9P_TRENAME, l9p_dispatch_trename, false},
154*134e1779SJakub Wojciech Klama 	{L9P_TREADLINK, l9p_dispatch_treadlink, false},
155*134e1779SJakub Wojciech Klama 	{L9P_TGETATTR, l9p_dispatch_tgetattr, false},
156*134e1779SJakub Wojciech Klama 	{L9P_TSETATTR, l9p_dispatch_tsetattr, false},
157*134e1779SJakub Wojciech Klama 	{L9P_TXATTRWALK, l9p_dispatch_txattrwalk, false},
158*134e1779SJakub Wojciech Klama 	{L9P_TXATTRCREATE, l9p_dispatch_txattrcreate, false},
159*134e1779SJakub Wojciech Klama 	{L9P_TREADDIR, l9p_dispatch_treaddir, false},
160*134e1779SJakub Wojciech Klama 	{L9P_TFSYNC, l9p_dispatch_tfsync, false},
161*134e1779SJakub Wojciech Klama 	{L9P_TLOCK, l9p_dispatch_tlock, true},
162*134e1779SJakub Wojciech Klama 	{L9P_TGETLOCK, l9p_dispatch_tgetlock, true},
163*134e1779SJakub Wojciech Klama 	{L9P_TLINK, l9p_dispatch_tlink, false},
164*134e1779SJakub Wojciech Klama 	{L9P_TMKDIR, l9p_dispatch_tmkdir, false},
165*134e1779SJakub Wojciech Klama 	{L9P_TRENAMEAT, l9p_dispatch_trenameat, false},
166*134e1779SJakub Wojciech Klama 	{L9P_TUNLINKAT, l9p_dispatch_tunlinkat, false},
167*134e1779SJakub Wojciech Klama };
168*134e1779SJakub Wojciech Klama 
169*134e1779SJakub Wojciech Klama /*
170*134e1779SJakub Wojciech Klama  * NB: version index 0 is reserved for new connections, and
171*134e1779SJakub Wojciech Klama  * is a protocol that handles only L9P_TVERSION.  Once we get a
172*134e1779SJakub Wojciech Klama  * valid version, we start a new session using its dispatch table.
173*134e1779SJakub Wojciech Klama  */
174*134e1779SJakub Wojciech Klama static const struct {
175*134e1779SJakub Wojciech Klama 	const char *name;
176*134e1779SJakub Wojciech Klama 	const struct l9p_handler *handlers;
177*134e1779SJakub Wojciech Klama 	int n_handlers;
178*134e1779SJakub Wojciech Klama } l9p_versions[] = {
179*134e1779SJakub Wojciech Klama 	{ "<none>", l9p_handlers_no_version, N(l9p_handlers_no_version) },
180*134e1779SJakub Wojciech Klama 	{ "9P2000", l9p_handlers_base, N(l9p_handlers_base) },
181*134e1779SJakub Wojciech Klama 	{ "9P2000.u", l9p_handlers_dotu, N(l9p_handlers_dotu), },
182*134e1779SJakub Wojciech Klama 	{ "9P2000.L", l9p_handlers_dotL, N(l9p_handlers_dotL), },
183*134e1779SJakub Wojciech Klama };
184*134e1779SJakub Wojciech Klama 
185*134e1779SJakub Wojciech Klama /*
186*134e1779SJakub Wojciech Klama  * Run the appropriate handler for this request.
187*134e1779SJakub Wojciech Klama  * It's our caller's responsibility to respond.
188*134e1779SJakub Wojciech Klama  */
189*134e1779SJakub Wojciech Klama int
l9p_dispatch_request(struct l9p_request * req)190*134e1779SJakub Wojciech Klama l9p_dispatch_request(struct l9p_request *req)
191*134e1779SJakub Wojciech Klama {
192*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn;
193*134e1779SJakub Wojciech Klama #if defined(L9P_DEBUG)
194*134e1779SJakub Wojciech Klama 	struct sbuf *sb;
195*134e1779SJakub Wojciech Klama #endif
196*134e1779SJakub Wojciech Klama 	size_t i, n;
197*134e1779SJakub Wojciech Klama 	const struct l9p_handler *handlers, *hp;
198*134e1779SJakub Wojciech Klama 	bool flush_requested;
199*134e1779SJakub Wojciech Klama 
200*134e1779SJakub Wojciech Klama 	conn = req->lr_conn;
201*134e1779SJakub Wojciech Klama 	flush_requested = req->lr_flushstate == L9P_FLUSH_REQUESTED_PRE_START;
202*134e1779SJakub Wojciech Klama 
203*134e1779SJakub Wojciech Klama 	handlers = l9p_versions[conn->lc_version].handlers;
204*134e1779SJakub Wojciech Klama 	n = (size_t)l9p_versions[conn->lc_version].n_handlers;
205*134e1779SJakub Wojciech Klama 	for (hp = handlers, i = 0; i < n; hp++, i++)
206*134e1779SJakub Wojciech Klama 		if (req->lr_req.hdr.type == hp->type)
207*134e1779SJakub Wojciech Klama 			goto found;
208*134e1779SJakub Wojciech Klama 	hp = NULL;
209*134e1779SJakub Wojciech Klama found:
210*134e1779SJakub Wojciech Klama 
211*134e1779SJakub Wojciech Klama #if defined(L9P_DEBUG)
212*134e1779SJakub Wojciech Klama 	sb = sbuf_new_auto();
213*134e1779SJakub Wojciech Klama 	if (flush_requested) {
214*134e1779SJakub Wojciech Klama 		sbuf_cat(sb, "FLUSH requested pre-dispatch");
215*134e1779SJakub Wojciech Klama 		if (hp != NULL && hp->must_run)
216*134e1779SJakub Wojciech Klama 			sbuf_cat(sb, ", but must run");
217*134e1779SJakub Wojciech Klama 		sbuf_cat(sb, ": ");
218*134e1779SJakub Wojciech Klama 	}
219*134e1779SJakub Wojciech Klama 	l9p_describe_fcall(&req->lr_req, conn->lc_version, sb);
220*134e1779SJakub Wojciech Klama 	sbuf_finish(sb);
221*134e1779SJakub Wojciech Klama 
222*134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
223*134e1779SJakub Wojciech Klama 	sbuf_delete(sb);
224*134e1779SJakub Wojciech Klama #endif
225*134e1779SJakub Wojciech Klama 
226*134e1779SJakub Wojciech Klama 	if (hp != NULL) {
227*134e1779SJakub Wojciech Klama 		if (!flush_requested || hp->must_run)
228*134e1779SJakub Wojciech Klama 			return (hp->handler(req));
229*134e1779SJakub Wojciech Klama 		return (EINTR);
230*134e1779SJakub Wojciech Klama 	}
231*134e1779SJakub Wojciech Klama 
232*134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_WARNING, "unknown request of type %d",
233*134e1779SJakub Wojciech Klama 	    req->lr_req.hdr.type);
234*134e1779SJakub Wojciech Klama 	return (ENOSYS);
235*134e1779SJakub Wojciech Klama }
236*134e1779SJakub Wojciech Klama 
237*134e1779SJakub Wojciech Klama /*
238*134e1779SJakub Wojciech Klama  * Translate BSD errno to 9P2000/9P2000.u errno.
239*134e1779SJakub Wojciech Klama  */
240*134e1779SJakub Wojciech Klama static inline int
e29p(int errnum)241*134e1779SJakub Wojciech Klama e29p(int errnum)
242*134e1779SJakub Wojciech Klama {
243*134e1779SJakub Wojciech Klama 	static int const table[] = {
244*134e1779SJakub Wojciech Klama 		[ENOTEMPTY] = EPERM,
245*134e1779SJakub Wojciech Klama 		[EDQUOT] = EPERM,
246*134e1779SJakub Wojciech Klama 		[ENOSYS] = EPERM,	/* ??? */
247*134e1779SJakub Wojciech Klama 	};
248*134e1779SJakub Wojciech Klama 
249*134e1779SJakub Wojciech Klama 	if ((size_t)errnum < N(table) && table[errnum] != 0)
250*134e1779SJakub Wojciech Klama 		return (table[errnum]);
251*134e1779SJakub Wojciech Klama 	if (errnum <= ERANGE)
252*134e1779SJakub Wojciech Klama 		return (errnum);
253*134e1779SJakub Wojciech Klama 	return (EIO);			/* ??? */
254*134e1779SJakub Wojciech Klama }
255*134e1779SJakub Wojciech Klama 
256*134e1779SJakub Wojciech Klama /*
257*134e1779SJakub Wojciech Klama  * Translate BSD errno to Linux errno.
258*134e1779SJakub Wojciech Klama  */
259*134e1779SJakub Wojciech Klama static inline int
e2linux(int errnum)260*134e1779SJakub Wojciech Klama e2linux(int errnum)
261*134e1779SJakub Wojciech Klama {
262*134e1779SJakub Wojciech Klama 	static int const table[] = {
263*134e1779SJakub Wojciech Klama 		[EDEADLK] = LINUX_EDEADLK,
264*134e1779SJakub Wojciech Klama 		[EAGAIN] = LINUX_EAGAIN,
265*134e1779SJakub Wojciech Klama 		[EINPROGRESS] = LINUX_EINPROGRESS,
266*134e1779SJakub Wojciech Klama 		[EALREADY] = LINUX_EALREADY,
267*134e1779SJakub Wojciech Klama 		[ENOTSOCK] = LINUX_ENOTSOCK,
268*134e1779SJakub Wojciech Klama 		[EDESTADDRREQ] = LINUX_EDESTADDRREQ,
269*134e1779SJakub Wojciech Klama 		[EMSGSIZE] = LINUX_EMSGSIZE,
270*134e1779SJakub Wojciech Klama 		[EPROTOTYPE] = LINUX_EPROTOTYPE,
271*134e1779SJakub Wojciech Klama 		[ENOPROTOOPT] = LINUX_ENOPROTOOPT,
272*134e1779SJakub Wojciech Klama 		[EPROTONOSUPPORT] = LINUX_EPROTONOSUPPORT,
273*134e1779SJakub Wojciech Klama 		[ESOCKTNOSUPPORT] = LINUX_ESOCKTNOSUPPORT,
274*134e1779SJakub Wojciech Klama 		[EOPNOTSUPP] = LINUX_EOPNOTSUPP,
275*134e1779SJakub Wojciech Klama 		[EPFNOSUPPORT] = LINUX_EPFNOSUPPORT,
276*134e1779SJakub Wojciech Klama 		[EAFNOSUPPORT] = LINUX_EAFNOSUPPORT,
277*134e1779SJakub Wojciech Klama 		[EADDRINUSE] = LINUX_EADDRINUSE,
278*134e1779SJakub Wojciech Klama 		[EADDRNOTAVAIL] = LINUX_EADDRNOTAVAIL,
279*134e1779SJakub Wojciech Klama 		[ENETDOWN] = LINUX_ENETDOWN,
280*134e1779SJakub Wojciech Klama 		[ENETUNREACH] = LINUX_ENETUNREACH,
281*134e1779SJakub Wojciech Klama 		[ENETRESET] = LINUX_ENETRESET,
282*134e1779SJakub Wojciech Klama 		[ECONNABORTED] = LINUX_ECONNABORTED,
283*134e1779SJakub Wojciech Klama 		[ECONNRESET] = LINUX_ECONNRESET,
284*134e1779SJakub Wojciech Klama 		[ENOBUFS] = LINUX_ENOBUFS,
285*134e1779SJakub Wojciech Klama 		[EISCONN] = LINUX_EISCONN,
286*134e1779SJakub Wojciech Klama 		[ENOTCONN] = LINUX_ENOTCONN,
287*134e1779SJakub Wojciech Klama 		[ESHUTDOWN] = LINUX_ESHUTDOWN,
288*134e1779SJakub Wojciech Klama 		[ETOOMANYREFS] = LINUX_ETOOMANYREFS,
289*134e1779SJakub Wojciech Klama 		[ETIMEDOUT] = LINUX_ETIMEDOUT,
290*134e1779SJakub Wojciech Klama 		[ECONNREFUSED] = LINUX_ECONNREFUSED,
291*134e1779SJakub Wojciech Klama 		[ELOOP] = LINUX_ELOOP,
292*134e1779SJakub Wojciech Klama 		[ENAMETOOLONG] = LINUX_ENAMETOOLONG,
293*134e1779SJakub Wojciech Klama 		[EHOSTDOWN] = LINUX_EHOSTDOWN,
294*134e1779SJakub Wojciech Klama 		[EHOSTUNREACH] = LINUX_EHOSTUNREACH,
295*134e1779SJakub Wojciech Klama 		[ENOTEMPTY] = LINUX_ENOTEMPTY,
296*134e1779SJakub Wojciech Klama 		[EPROCLIM] = LINUX_EAGAIN,
297*134e1779SJakub Wojciech Klama 		[EUSERS] = LINUX_EUSERS,
298*134e1779SJakub Wojciech Klama 		[EDQUOT] = LINUX_EDQUOT,
299*134e1779SJakub Wojciech Klama 		[ESTALE] = LINUX_ESTALE,
300*134e1779SJakub Wojciech Klama 		[EREMOTE] = LINUX_EREMOTE,
301*134e1779SJakub Wojciech Klama 		/* EBADRPC = unmappable? */
302*134e1779SJakub Wojciech Klama 		/* ERPCMISMATCH = unmappable? */
303*134e1779SJakub Wojciech Klama 		/* EPROGUNAVAIL = unmappable? */
304*134e1779SJakub Wojciech Klama 		/* EPROGMISMATCH = unmappable? */
305*134e1779SJakub Wojciech Klama 		/* EPROCUNAVAIL = unmappable? */
306*134e1779SJakub Wojciech Klama 		[ENOLCK] = LINUX_ENOLCK,
307*134e1779SJakub Wojciech Klama 		[ENOSYS] = LINUX_ENOSYS,
308*134e1779SJakub Wojciech Klama 		/* EFTYPE = unmappable? */
309*134e1779SJakub Wojciech Klama 		/* EAUTH = unmappable? */
310*134e1779SJakub Wojciech Klama 		/* ENEEDAUTH = unmappable? */
311*134e1779SJakub Wojciech Klama 		[EIDRM] = LINUX_EIDRM,
312*134e1779SJakub Wojciech Klama 		[ENOMSG] = LINUX_ENOMSG,
313*134e1779SJakub Wojciech Klama 		[EOVERFLOW] = LINUX_EOVERFLOW,
314*134e1779SJakub Wojciech Klama 		[ECANCELED] = LINUX_ECANCELED,
315*134e1779SJakub Wojciech Klama 		[EILSEQ] = LINUX_EILSEQ,
316*134e1779SJakub Wojciech Klama 		/* EDOOFUS = unmappable? */
317*134e1779SJakub Wojciech Klama 		[EBADMSG] = LINUX_EBADMSG,
318*134e1779SJakub Wojciech Klama 		[EMULTIHOP] = LINUX_EMULTIHOP,
319*134e1779SJakub Wojciech Klama 		[ENOLINK] = LINUX_ENOLINK,
320*134e1779SJakub Wojciech Klama 		[EPROTO] = LINUX_EPROTO,
321*134e1779SJakub Wojciech Klama 		/* ENOTCAPABLE = unmappable? */
322*134e1779SJakub Wojciech Klama #ifdef ECAPMODE
323*134e1779SJakub Wojciech Klama 		[ECAPMODE] = EPERM,
324*134e1779SJakub Wojciech Klama #endif
325*134e1779SJakub Wojciech Klama #ifdef ENOTRECOVERABLE
326*134e1779SJakub Wojciech Klama 		[ENOTRECOVERABLE] = LINUX_ENOTRECOVERABLE,
327*134e1779SJakub Wojciech Klama #endif
328*134e1779SJakub Wojciech Klama #ifdef EOWNERDEAD
329*134e1779SJakub Wojciech Klama 		[EOWNERDEAD] = LINUX_EOWNERDEAD,
330*134e1779SJakub Wojciech Klama #endif
331*134e1779SJakub Wojciech Klama 	};
332*134e1779SJakub Wojciech Klama 
333*134e1779SJakub Wojciech Klama 	/*
334*134e1779SJakub Wojciech Klama 	 * In case we want to return a raw Linux errno, allow negative
335*134e1779SJakub Wojciech Klama 	 * values a la Linux kernel internals.
336*134e1779SJakub Wojciech Klama 	 *
337*134e1779SJakub Wojciech Klama 	 * Values up to ERANGE are shared across systems (see
338*134e1779SJakub Wojciech Klama 	 * linux_errno.h), except for EAGAIN.
339*134e1779SJakub Wojciech Klama 	 */
340*134e1779SJakub Wojciech Klama 	if (errnum < 0)
341*134e1779SJakub Wojciech Klama 		return (-errnum);
342*134e1779SJakub Wojciech Klama 
343*134e1779SJakub Wojciech Klama 	if ((size_t)errnum < N(table) && table[errnum] != 0)
344*134e1779SJakub Wojciech Klama 		return (table[errnum]);
345*134e1779SJakub Wojciech Klama 
346*134e1779SJakub Wojciech Klama 	if (errnum <= ERANGE)
347*134e1779SJakub Wojciech Klama 		return (errnum);
348*134e1779SJakub Wojciech Klama 
349*134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_WARNING, "cannot map errno %d to anything reasonable",
350*134e1779SJakub Wojciech Klama 	    errnum);
351*134e1779SJakub Wojciech Klama 
352*134e1779SJakub Wojciech Klama 	return (LINUX_ENOTRECOVERABLE);	/* ??? */
353*134e1779SJakub Wojciech Klama }
354*134e1779SJakub Wojciech Klama 
355*134e1779SJakub Wojciech Klama /*
356*134e1779SJakub Wojciech Klama  * Send response to request, or possibly just drop request.
357*134e1779SJakub Wojciech Klama  * We also need to know whether to remove the request from
358*134e1779SJakub Wojciech Klama  * the tag hash table.
359*134e1779SJakub Wojciech Klama  */
360*134e1779SJakub Wojciech Klama void
l9p_respond(struct l9p_request * req,bool drop,bool rmtag)361*134e1779SJakub Wojciech Klama l9p_respond(struct l9p_request *req, bool drop, bool rmtag)
362*134e1779SJakub Wojciech Klama {
363*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
364*134e1779SJakub Wojciech Klama 	size_t iosize;
365*134e1779SJakub Wojciech Klama #if defined(L9P_DEBUG)
366*134e1779SJakub Wojciech Klama 	struct sbuf *sb;
367*134e1779SJakub Wojciech Klama 	const char *ftype;
368*134e1779SJakub Wojciech Klama #endif
369*134e1779SJakub Wojciech Klama 	int error;
370*134e1779SJakub Wojciech Klama 
371*134e1779SJakub Wojciech Klama 	req->lr_resp.hdr.tag = req->lr_req.hdr.tag;
372*134e1779SJakub Wojciech Klama 
373*134e1779SJakub Wojciech Klama 	error = req->lr_error;
374*134e1779SJakub Wojciech Klama 	if (error == 0)
375*134e1779SJakub Wojciech Klama 		req->lr_resp.hdr.type = req->lr_req.hdr.type + 1;
376*134e1779SJakub Wojciech Klama 	else {
377*134e1779SJakub Wojciech Klama 		if (conn->lc_version == L9P_2000L) {
378*134e1779SJakub Wojciech Klama 			req->lr_resp.hdr.type = L9P_RLERROR;
379*134e1779SJakub Wojciech Klama 			req->lr_resp.error.errnum = (uint32_t)e2linux(error);
380*134e1779SJakub Wojciech Klama 		} else {
381*134e1779SJakub Wojciech Klama 			req->lr_resp.hdr.type = L9P_RERROR;
382*134e1779SJakub Wojciech Klama 			req->lr_resp.error.ename = strerror(error);
383*134e1779SJakub Wojciech Klama 			req->lr_resp.error.errnum = (uint32_t)e29p(error);
384*134e1779SJakub Wojciech Klama 		}
385*134e1779SJakub Wojciech Klama 	}
386*134e1779SJakub Wojciech Klama 
387*134e1779SJakub Wojciech Klama #if defined(L9P_DEBUG)
388*134e1779SJakub Wojciech Klama 	sb = sbuf_new_auto();
389*134e1779SJakub Wojciech Klama 	l9p_describe_fcall(&req->lr_resp, conn->lc_version, sb);
390*134e1779SJakub Wojciech Klama 	sbuf_finish(sb);
391*134e1779SJakub Wojciech Klama 
392*134e1779SJakub Wojciech Klama 	switch (req->lr_flushstate) {
393*134e1779SJakub Wojciech Klama 	case L9P_FLUSH_NONE:
394*134e1779SJakub Wojciech Klama 		ftype = "";
395*134e1779SJakub Wojciech Klama 		break;
396*134e1779SJakub Wojciech Klama 	case L9P_FLUSH_REQUESTED_PRE_START:
397*134e1779SJakub Wojciech Klama 		ftype = "FLUSH requested pre-dispatch: ";
398*134e1779SJakub Wojciech Klama 		break;
399*134e1779SJakub Wojciech Klama 	case L9P_FLUSH_REQUESTED_POST_START:
400*134e1779SJakub Wojciech Klama 		ftype = "FLUSH requested while running: ";
401*134e1779SJakub Wojciech Klama 		break;
402*134e1779SJakub Wojciech Klama 	case L9P_FLUSH_TOOLATE:
403*134e1779SJakub Wojciech Klama 		ftype = "FLUSH requested too late: ";
404*134e1779SJakub Wojciech Klama 		break;
405*134e1779SJakub Wojciech Klama 	}
406*134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_DEBUG, "%s%s%s",
407*134e1779SJakub Wojciech Klama 	    drop ? "DROP: " : "", ftype, sbuf_data(sb));
408*134e1779SJakub Wojciech Klama 	sbuf_delete(sb);
409*134e1779SJakub Wojciech Klama #endif
410*134e1779SJakub Wojciech Klama 
411*134e1779SJakub Wojciech Klama 	error = drop ? 0 :
412*134e1779SJakub Wojciech Klama 	    l9p_pufcall(&req->lr_resp_msg, &req->lr_resp, conn->lc_version);
413*134e1779SJakub Wojciech Klama 	if (rmtag)
414*134e1779SJakub Wojciech Klama 		ht_remove(&conn->lc_requests, req->lr_req.hdr.tag);
415*134e1779SJakub Wojciech Klama 	if (error != 0) {
416*134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "cannot pack response");
417*134e1779SJakub Wojciech Klama 		drop = true;
418*134e1779SJakub Wojciech Klama 	}
419*134e1779SJakub Wojciech Klama 
420*134e1779SJakub Wojciech Klama 	if (drop) {
421*134e1779SJakub Wojciech Klama 		conn->lc_lt.lt_drop_response(req,
422*134e1779SJakub Wojciech Klama 		    req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
423*134e1779SJakub Wojciech Klama 		    conn->lc_lt.lt_aux);
424*134e1779SJakub Wojciech Klama 	} else {
425*134e1779SJakub Wojciech Klama 		iosize = req->lr_resp_msg.lm_size;
426*134e1779SJakub Wojciech Klama 
427*134e1779SJakub Wojciech Klama 		/*
428*134e1779SJakub Wojciech Klama 		 * Include I/O size in calculation for Rread and
429*134e1779SJakub Wojciech Klama 		 * Rreaddir responses.
430*134e1779SJakub Wojciech Klama 		 */
431*134e1779SJakub Wojciech Klama 		if (req->lr_resp.hdr.type == L9P_RREAD ||
432*134e1779SJakub Wojciech Klama 		    req->lr_resp.hdr.type == L9P_RREADDIR)
433*134e1779SJakub Wojciech Klama 			iosize += req->lr_resp.io.count;
434*134e1779SJakub Wojciech Klama 
435*134e1779SJakub Wojciech Klama 		conn->lc_lt.lt_send_response(req,
436*134e1779SJakub Wojciech Klama 		    req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
437*134e1779SJakub Wojciech Klama 		    iosize, conn->lc_lt.lt_aux);
438*134e1779SJakub Wojciech Klama 	}
439*134e1779SJakub Wojciech Klama 
440*134e1779SJakub Wojciech Klama 	l9p_freefcall(&req->lr_req);
441*134e1779SJakub Wojciech Klama 	l9p_freefcall(&req->lr_resp);
442*134e1779SJakub Wojciech Klama 
443*134e1779SJakub Wojciech Klama 	free(req);
444*134e1779SJakub Wojciech Klama }
445*134e1779SJakub Wojciech Klama 
446*134e1779SJakub Wojciech Klama /*
447*134e1779SJakub Wojciech Klama  * This allows a caller to iterate through the data in a
448*134e1779SJakub Wojciech Klama  * read or write request (creating the data if packing,
449*134e1779SJakub Wojciech Klama  * scanning through it if unpacking).  This is used for
450*134e1779SJakub Wojciech Klama  * writing readdir entries, so mode should be L9P_PACK
451*134e1779SJakub Wojciech Klama  * (but we allow L9P_UNPACK so that debug code can also scan
452*134e1779SJakub Wojciech Klama  * through the data later, if desired).
453*134e1779SJakub Wojciech Klama  *
454*134e1779SJakub Wojciech Klama  * This relies on the Tread op having positioned the request's
455*134e1779SJakub Wojciech Klama  * iov to the beginning of the data buffer (note the l9p_seek_iov
456*134e1779SJakub Wojciech Klama  * in l9p_dispatch_tread).
457*134e1779SJakub Wojciech Klama  */
458*134e1779SJakub Wojciech Klama void
l9p_init_msg(struct l9p_message * msg,struct l9p_request * req,enum l9p_pack_mode mode)459*134e1779SJakub Wojciech Klama l9p_init_msg(struct l9p_message *msg, struct l9p_request *req,
460*134e1779SJakub Wojciech Klama     enum l9p_pack_mode mode)
461*134e1779SJakub Wojciech Klama {
462*134e1779SJakub Wojciech Klama 
463*134e1779SJakub Wojciech Klama 	msg->lm_size = 0;
464*134e1779SJakub Wojciech Klama 	msg->lm_mode = mode;
465*134e1779SJakub Wojciech Klama 	msg->lm_cursor_iov = 0;
466*134e1779SJakub Wojciech Klama 	msg->lm_cursor_offset = 0;
467*134e1779SJakub Wojciech Klama 	msg->lm_niov = req->lr_data_niov;
468*134e1779SJakub Wojciech Klama 	memcpy(msg->lm_iov, req->lr_data_iov,
469*134e1779SJakub Wojciech Klama 	    sizeof (struct iovec) * req->lr_data_niov);
470*134e1779SJakub Wojciech Klama }
471*134e1779SJakub Wojciech Klama 
472*134e1779SJakub Wojciech Klama enum fid_lookup_flags {
473*134e1779SJakub Wojciech Klama 	F_REQUIRE_OPEN = 0x01,	/* require that the file be marked OPEN */
474*134e1779SJakub Wojciech Klama 	F_REQUIRE_DIR = 0x02,	/* require that the file be marked ISDIR */
475*134e1779SJakub Wojciech Klama 	F_REQUIRE_XATTR = 0x04,	/* require that the file be marked XATTR */
476*134e1779SJakub Wojciech Klama 	F_REQUIRE_AUTH = 0x08,	/* require that the fid be marked AUTH */
477*134e1779SJakub Wojciech Klama 	F_FORBID_OPEN = 0x10,	/* forbid that the file be marked OPEN */
478*134e1779SJakub Wojciech Klama 	F_FORBID_DIR = 0x20,	/* forbid that the file be marked ISDIR */
479*134e1779SJakub Wojciech Klama 	F_FORBID_XATTR = 0x40,	/* forbid that the file be marked XATTR */
480*134e1779SJakub Wojciech Klama 	F_ALLOW_AUTH = 0x80,	/* allow that the fid be marked AUTH */
481*134e1779SJakub Wojciech Klama };
482*134e1779SJakub Wojciech Klama 
483*134e1779SJakub Wojciech Klama /*
484*134e1779SJakub Wojciech Klama  * Look up a fid.  It must correspond to a valid file, else we return
485*134e1779SJakub Wojciech Klama  * the given errno (some "not a valid fid" calls must return EIO and
486*134e1779SJakub Wojciech Klama  * some must return EINVAL and qemu returns ENOENT in other cases and
487*134e1779SJakub Wojciech Klama  * so on, so we just provide a general "return this error number").
488*134e1779SJakub Wojciech Klama  *
489*134e1779SJakub Wojciech Klama  * Callers may also set constraints: fid must be (or not be) open,
490*134e1779SJakub Wojciech Klama  * must be (or not be) a directory, must be (or not be) an xattr.
491*134e1779SJakub Wojciech Klama  *
492*134e1779SJakub Wojciech Klama  * Only one op has a fid that *must* be an auth fid.  Most ops forbid
493*134e1779SJakub Wojciech Klama  * auth fids  So instead of FORBID we have ALLOW here and the default
494*134e1779SJakub Wojciech Klama  * is FORBID.
495*134e1779SJakub Wojciech Klama  */
496*134e1779SJakub Wojciech Klama static inline int
fid_lookup(struct l9p_connection * conn,uint32_t fid,int err,int flags,struct l9p_fid ** afile)497*134e1779SJakub Wojciech Klama fid_lookup(struct l9p_connection *conn, uint32_t fid, int err, int flags,
498*134e1779SJakub Wojciech Klama     struct l9p_fid **afile)
499*134e1779SJakub Wojciech Klama {
500*134e1779SJakub Wojciech Klama 	struct l9p_fid *file;
501*134e1779SJakub Wojciech Klama 
502*134e1779SJakub Wojciech Klama 	file = ht_find(&conn->lc_files, fid);
503*134e1779SJakub Wojciech Klama 	if (file == NULL)
504*134e1779SJakub Wojciech Klama 		return (err);
505*134e1779SJakub Wojciech Klama 
506*134e1779SJakub Wojciech Klama 	/*
507*134e1779SJakub Wojciech Klama 	 * As soon as we go multithreaded / async, this
508*134e1779SJakub Wojciech Klama 	 * assert has to become "return EINVAL" or "return err".
509*134e1779SJakub Wojciech Klama 	 *
510*134e1779SJakub Wojciech Klama 	 * We may also need a way to mark a fid as
511*134e1779SJakub Wojciech Klama 	 * "in async op" (valid for some purposes, but cannot be
512*134e1779SJakub Wojciech Klama 	 * used elsewhere until async op is completed or aborted).
513*134e1779SJakub Wojciech Klama 	 *
514*134e1779SJakub Wojciech Klama 	 * For now, this serves for bug-detecting.
515*134e1779SJakub Wojciech Klama 	 */
516*134e1779SJakub Wojciech Klama 	assert(l9p_fid_isvalid(file));
517*134e1779SJakub Wojciech Klama 
518*134e1779SJakub Wojciech Klama 	/*
519*134e1779SJakub Wojciech Klama 	 * Note that we're inline expanded and flags is constant,
520*134e1779SJakub Wojciech Klama 	 * so unnecessary tests just drop out entirely.
521*134e1779SJakub Wojciech Klama 	 */
522*134e1779SJakub Wojciech Klama 	if ((flags & F_REQUIRE_OPEN) && !l9p_fid_isopen(file))
523*134e1779SJakub Wojciech Klama 		return (EINVAL);
524*134e1779SJakub Wojciech Klama 	if ((flags & F_FORBID_OPEN) && l9p_fid_isopen(file))
525*134e1779SJakub Wojciech Klama 		return (EINVAL);
526*134e1779SJakub Wojciech Klama 	if ((flags & F_REQUIRE_DIR) && !l9p_fid_isdir(file))
527*134e1779SJakub Wojciech Klama 		return (ENOTDIR);
528*134e1779SJakub Wojciech Klama 	if ((flags & F_FORBID_DIR) && l9p_fid_isdir(file))
529*134e1779SJakub Wojciech Klama 		return (EISDIR);
530*134e1779SJakub Wojciech Klama 	if ((flags & F_REQUIRE_XATTR) && !l9p_fid_isxattr(file))
531*134e1779SJakub Wojciech Klama 		return (EINVAL);
532*134e1779SJakub Wojciech Klama 	if ((flags & F_FORBID_XATTR) && l9p_fid_isxattr(file))
533*134e1779SJakub Wojciech Klama 		return (EINVAL);
534*134e1779SJakub Wojciech Klama 	if (l9p_fid_isauth(file)) {
535*134e1779SJakub Wojciech Klama 		if ((flags & (F_REQUIRE_AUTH | F_ALLOW_AUTH)) == 0)
536*134e1779SJakub Wojciech Klama 			return (EINVAL);
537*134e1779SJakub Wojciech Klama 	} else if (flags & F_REQUIRE_AUTH)
538*134e1779SJakub Wojciech Klama 		return (EINVAL);
539*134e1779SJakub Wojciech Klama 	*afile = file;
540*134e1779SJakub Wojciech Klama 	return (0);
541*134e1779SJakub Wojciech Klama }
542*134e1779SJakub Wojciech Klama 
543*134e1779SJakub Wojciech Klama /*
544*134e1779SJakub Wojciech Klama  * Append variable-size stat object and adjust io count.
545*134e1779SJakub Wojciech Klama  * Returns 0 if the entire stat object was packed, -1 if not.
546*134e1779SJakub Wojciech Klama  * A fully packed object updates the request's io count.
547*134e1779SJakub Wojciech Klama  *
548*134e1779SJakub Wojciech Klama  * Caller must use their own private l9p_message object since
549*134e1779SJakub Wojciech Klama  * a partially packed object will leave the message object in
550*134e1779SJakub Wojciech Klama  * a useless state.
551*134e1779SJakub Wojciech Klama  *
552*134e1779SJakub Wojciech Klama  * Frees the stat object.
553*134e1779SJakub Wojciech Klama  */
554*134e1779SJakub Wojciech Klama int
l9p_pack_stat(struct l9p_message * msg,struct l9p_request * req,struct l9p_stat * st)555*134e1779SJakub Wojciech Klama l9p_pack_stat(struct l9p_message *msg, struct l9p_request *req,
556*134e1779SJakub Wojciech Klama     struct l9p_stat *st)
557*134e1779SJakub Wojciech Klama {
558*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
559*134e1779SJakub Wojciech Klama 	uint16_t size = l9p_sizeof_stat(st, conn->lc_version);
560*134e1779SJakub Wojciech Klama 	int ret = 0;
561*134e1779SJakub Wojciech Klama 
562*134e1779SJakub Wojciech Klama 	assert(msg->lm_mode == L9P_PACK);
563*134e1779SJakub Wojciech Klama 
564*134e1779SJakub Wojciech Klama 	if (req->lr_resp.io.count + size > req->lr_req.io.count ||
565*134e1779SJakub Wojciech Klama 	    l9p_pustat(msg, st, conn->lc_version) < 0)
566*134e1779SJakub Wojciech Klama 		ret = -1;
567*134e1779SJakub Wojciech Klama 	else
568*134e1779SJakub Wojciech Klama 		req->lr_resp.io.count += size;
569*134e1779SJakub Wojciech Klama 	l9p_freestat(st);
570*134e1779SJakub Wojciech Klama 	return (ret);
571*134e1779SJakub Wojciech Klama }
572*134e1779SJakub Wojciech Klama 
573*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tversion(struct l9p_request * req)574*134e1779SJakub Wojciech Klama l9p_dispatch_tversion(struct l9p_request *req)
575*134e1779SJakub Wojciech Klama {
576*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
577*134e1779SJakub Wojciech Klama 	struct l9p_server *server = conn->lc_server;
578*134e1779SJakub Wojciech Klama 	enum l9p_version remote_version = L9P_INVALID_VERSION;
579*134e1779SJakub Wojciech Klama 	size_t i;
580*134e1779SJakub Wojciech Klama 	const char *remote_version_name;
581*134e1779SJakub Wojciech Klama 
582*134e1779SJakub Wojciech Klama 	for (i = 0; i < N(l9p_versions); i++) {
583*134e1779SJakub Wojciech Klama 		if (strcmp(req->lr_req.version.version,
584*134e1779SJakub Wojciech Klama 		    l9p_versions[i].name) == 0) {
585*134e1779SJakub Wojciech Klama 			remote_version = (enum l9p_version)i;
586*134e1779SJakub Wojciech Klama 			break;
587*134e1779SJakub Wojciech Klama 		}
588*134e1779SJakub Wojciech Klama 	}
589*134e1779SJakub Wojciech Klama 
590*134e1779SJakub Wojciech Klama 	if (remote_version == L9P_INVALID_VERSION) {
591*134e1779SJakub Wojciech Klama 		L9P_LOG(L9P_ERROR, "unsupported remote version: %s",
592*134e1779SJakub Wojciech Klama 		    req->lr_req.version.version);
593*134e1779SJakub Wojciech Klama 		return (ENOSYS);
594*134e1779SJakub Wojciech Klama 	}
595*134e1779SJakub Wojciech Klama 
596*134e1779SJakub Wojciech Klama 	remote_version_name = l9p_versions[remote_version].name;
597*134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_INFO, "remote version: %s", remote_version_name);
598*134e1779SJakub Wojciech Klama 	L9P_LOG(L9P_INFO, "local version: %s",
599*134e1779SJakub Wojciech Klama 	    l9p_versions[server->ls_max_version].name);
600*134e1779SJakub Wojciech Klama 
601*134e1779SJakub Wojciech Klama 	conn->lc_version = MIN(remote_version, server->ls_max_version);
602*134e1779SJakub Wojciech Klama 	conn->lc_msize = MIN(req->lr_req.version.msize, conn->lc_msize);
603*134e1779SJakub Wojciech Klama 	conn->lc_max_io_size = conn->lc_msize - 24;
604*134e1779SJakub Wojciech Klama 	req->lr_resp.version.version = strdup(remote_version_name);
605*134e1779SJakub Wojciech Klama 	req->lr_resp.version.msize = conn->lc_msize;
606*134e1779SJakub Wojciech Klama 	return (0);
607*134e1779SJakub Wojciech Klama }
608*134e1779SJakub Wojciech Klama 
609*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tattach(struct l9p_request * req)610*134e1779SJakub Wojciech Klama l9p_dispatch_tattach(struct l9p_request *req)
611*134e1779SJakub Wojciech Klama {
612*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
613*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
614*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
615*134e1779SJakub Wojciech Klama 	int error;
616*134e1779SJakub Wojciech Klama 
617*134e1779SJakub Wojciech Klama 	/*
618*134e1779SJakub Wojciech Klama 	 * We still don't have Tauth yet, but let's code this part
619*134e1779SJakub Wojciech Klama 	 * anyway.
620*134e1779SJakub Wojciech Klama 	 *
621*134e1779SJakub Wojciech Klama 	 * Look up the auth fid first since if it fails we can just
622*134e1779SJakub Wojciech Klama 	 * return immediately.
623*134e1779SJakub Wojciech Klama 	 */
624*134e1779SJakub Wojciech Klama 	if (req->lr_req.tattach.afid != L9P_NOFID) {
625*134e1779SJakub Wojciech Klama 		error = fid_lookup(conn, req->lr_req.tattach.afid, EINVAL,
626*134e1779SJakub Wojciech Klama 		    F_REQUIRE_AUTH, &req->lr_fid2);
627*134e1779SJakub Wojciech Klama 		if (error)
628*134e1779SJakub Wojciech Klama 			return (error);
629*134e1779SJakub Wojciech Klama 	} else
630*134e1779SJakub Wojciech Klama 		req->lr_fid2 = NULL;
631*134e1779SJakub Wojciech Klama 
632*134e1779SJakub Wojciech Klama 	fid = l9p_connection_alloc_fid(conn, req->lr_req.hdr.fid);
633*134e1779SJakub Wojciech Klama 	if (fid == NULL)
634*134e1779SJakub Wojciech Klama 		return (EINVAL);
635*134e1779SJakub Wojciech Klama 
636*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
637*134e1779SJakub Wojciech Klama 
638*134e1779SJakub Wojciech Klama 	req->lr_fid = fid;
639*134e1779SJakub Wojciech Klama 
640*134e1779SJakub Wojciech Klama 	/* For backend convenience, set NONUNAME on 9P2000. */
641*134e1779SJakub Wojciech Klama 	if (conn->lc_version == L9P_2000)
642*134e1779SJakub Wojciech Klama 		req->lr_req.tattach.n_uname = L9P_NONUNAME;
643*134e1779SJakub Wojciech Klama 	error = be->attach(be->softc, req);
644*134e1779SJakub Wojciech Klama 
645*134e1779SJakub Wojciech Klama 	/*
646*134e1779SJakub Wojciech Klama 	 * On success, fid becomes valid; on failure, disconnect.
647*134e1779SJakub Wojciech Klama 	 * It certainly *should* be a directory here...
648*134e1779SJakub Wojciech Klama 	 */
649*134e1779SJakub Wojciech Klama 	if (error == 0) {
650*134e1779SJakub Wojciech Klama 		l9p_fid_setvalid(fid);
651*134e1779SJakub Wojciech Klama 		if (req->lr_resp.rattach.qid.type & L9P_QTDIR)
652*134e1779SJakub Wojciech Klama 			l9p_fid_setdir(fid);
653*134e1779SJakub Wojciech Klama 	} else
654*134e1779SJakub Wojciech Klama 		l9p_connection_remove_fid(conn, fid);
655*134e1779SJakub Wojciech Klama 	return (error);
656*134e1779SJakub Wojciech Klama }
657*134e1779SJakub Wojciech Klama 
658*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tclunk(struct l9p_request * req)659*134e1779SJakub Wojciech Klama l9p_dispatch_tclunk(struct l9p_request *req)
660*134e1779SJakub Wojciech Klama {
661*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
662*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
663*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
664*134e1779SJakub Wojciech Klama 	int error;
665*134e1779SJakub Wojciech Klama 
666*134e1779SJakub Wojciech Klama 	/* Note that clunk is the only way to dispose of an auth fid. */
667*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
668*134e1779SJakub Wojciech Klama 	    F_ALLOW_AUTH, &fid);
669*134e1779SJakub Wojciech Klama 	if (error)
670*134e1779SJakub Wojciech Klama 		return (error);
671*134e1779SJakub Wojciech Klama 
672*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
673*134e1779SJakub Wojciech Klama 	l9p_fid_unsetvalid(fid);
674*134e1779SJakub Wojciech Klama 
675*134e1779SJakub Wojciech Klama 	/*
676*134e1779SJakub Wojciech Klama 	 * If it's an xattr fid there must, by definition, be an
677*134e1779SJakub Wojciech Klama 	 * xattrclunk.  The xattrclunk function can only be NULL if
678*134e1779SJakub Wojciech Klama 	 * xattrwalk and xattrcreate are NULL or always return error.
679*134e1779SJakub Wojciech Klama 	 *
680*134e1779SJakub Wojciech Klama 	 * Q: do we want to allow async xattrclunk in case of very
681*134e1779SJakub Wojciech Klama 	 * large xattr create?  This will make things difficult,
682*134e1779SJakub Wojciech Klama 	 * so probably not.
683*134e1779SJakub Wojciech Klama 	 */
684*134e1779SJakub Wojciech Klama 	if (l9p_fid_isxattr(fid))
685*134e1779SJakub Wojciech Klama 		error = be->xattrclunk(be->softc, fid);
686*134e1779SJakub Wojciech Klama 	else
687*134e1779SJakub Wojciech Klama 		error = be->clunk(be->softc, fid);
688*134e1779SJakub Wojciech Klama 
689*134e1779SJakub Wojciech Klama 	/* fid is now gone regardless of any error return */
690*134e1779SJakub Wojciech Klama 	l9p_connection_remove_fid(conn, fid);
691*134e1779SJakub Wojciech Klama 	return (error);
692*134e1779SJakub Wojciech Klama }
693*134e1779SJakub Wojciech Klama 
694*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tcreate(struct l9p_request * req)695*134e1779SJakub Wojciech Klama l9p_dispatch_tcreate(struct l9p_request *req)
696*134e1779SJakub Wojciech Klama {
697*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
698*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
699*134e1779SJakub Wojciech Klama 	uint32_t dmperm;
700*134e1779SJakub Wojciech Klama 	int error;
701*134e1779SJakub Wojciech Klama 
702*134e1779SJakub Wojciech Klama 	/* Incoming fid must represent a directory that has not been opened. */
703*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
704*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
705*134e1779SJakub Wojciech Klama 	if (error)
706*134e1779SJakub Wojciech Klama 		return (error);
707*134e1779SJakub Wojciech Klama 
708*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
709*134e1779SJakub Wojciech Klama 	dmperm = req->lr_req.tcreate.perm;
710*134e1779SJakub Wojciech Klama #define MKDIR_OR_SIMILAR \
711*134e1779SJakub Wojciech Klama     (L9P_DMDIR | L9P_DMSYMLINK | L9P_DMNAMEDPIPE | L9P_DMSOCKET | L9P_DMDEVICE)
712*134e1779SJakub Wojciech Klama 
713*134e1779SJakub Wojciech Klama 	/*
714*134e1779SJakub Wojciech Klama 	 * TODO:
715*134e1779SJakub Wojciech Klama 	 *  - check new file name
716*134e1779SJakub Wojciech Klama 	 *  - break out different kinds of create (file vs mkdir etc)
717*134e1779SJakub Wojciech Klama 	 *  - add async file-create (leaves req->lr_fid in limbo)
718*134e1779SJakub Wojciech Klama 	 *
719*134e1779SJakub Wojciech Klama 	 * A successful file-create changes the fid into an open file.
720*134e1779SJakub Wojciech Klama 	 */
721*134e1779SJakub Wojciech Klama 	error = be->create(be->softc, req);
722*134e1779SJakub Wojciech Klama 	if (error == 0 && (dmperm & MKDIR_OR_SIMILAR) == 0) {
723*134e1779SJakub Wojciech Klama 		l9p_fid_unsetdir(req->lr_fid);
724*134e1779SJakub Wojciech Klama 		l9p_fid_setopen(req->lr_fid);
725*134e1779SJakub Wojciech Klama 	}
726*134e1779SJakub Wojciech Klama 
727*134e1779SJakub Wojciech Klama 	return (error);
728*134e1779SJakub Wojciech Klama }
729*134e1779SJakub Wojciech Klama 
730*134e1779SJakub Wojciech Klama static int
l9p_dispatch_topen(struct l9p_request * req)731*134e1779SJakub Wojciech Klama l9p_dispatch_topen(struct l9p_request *req)
732*134e1779SJakub Wojciech Klama {
733*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
734*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
735*134e1779SJakub Wojciech Klama 	int error;
736*134e1779SJakub Wojciech Klama 
737*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
738*134e1779SJakub Wojciech Klama 	    F_FORBID_OPEN | F_FORBID_XATTR, &req->lr_fid);
739*134e1779SJakub Wojciech Klama 	if (error)
740*134e1779SJakub Wojciech Klama 		return (error);
741*134e1779SJakub Wojciech Klama 
742*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
743*134e1779SJakub Wojciech Klama 
744*134e1779SJakub Wojciech Klama 	/*
745*134e1779SJakub Wojciech Klama 	 * TODO:
746*134e1779SJakub Wojciech Klama 	 *  - add async open (leaves req->lr_fid in limbo)
747*134e1779SJakub Wojciech Klama 	 */
748*134e1779SJakub Wojciech Klama 	error = be->open(be->softc, req);
749*134e1779SJakub Wojciech Klama 	if (error == 0)
750*134e1779SJakub Wojciech Klama 		l9p_fid_setopen(req->lr_fid);
751*134e1779SJakub Wojciech Klama 	return (error);
752*134e1779SJakub Wojciech Klama }
753*134e1779SJakub Wojciech Klama 
754*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tread(struct l9p_request * req)755*134e1779SJakub Wojciech Klama l9p_dispatch_tread(struct l9p_request *req)
756*134e1779SJakub Wojciech Klama {
757*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
758*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
759*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
760*134e1779SJakub Wojciech Klama 	int error;
761*134e1779SJakub Wojciech Klama 
762*134e1779SJakub Wojciech Klama 	/* Xattr fids are not open, so we need our own tests. */
763*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL, 0, &req->lr_fid);
764*134e1779SJakub Wojciech Klama 	if (error)
765*134e1779SJakub Wojciech Klama 		return (error);
766*134e1779SJakub Wojciech Klama 
767*134e1779SJakub Wojciech Klama 	/*
768*134e1779SJakub Wojciech Klama 	 * Adjust so that writing messages (packing data) starts
769*134e1779SJakub Wojciech Klama 	 * right after the count field in the response.
770*134e1779SJakub Wojciech Klama 	 *
771*134e1779SJakub Wojciech Klama 	 * size[4] + Rread[1] + tag[2] + count[4] = 11
772*134e1779SJakub Wojciech Klama 	 */
773*134e1779SJakub Wojciech Klama 	l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
774*134e1779SJakub Wojciech Klama 	    req->lr_data_iov, &req->lr_data_niov, 11);
775*134e1779SJakub Wojciech Klama 
776*134e1779SJakub Wojciech Klama 	/*
777*134e1779SJakub Wojciech Klama 	 * If it's an xattr fid there must, by definition, be an
778*134e1779SJakub Wojciech Klama 	 * xattrread.  The xattrread function can only be NULL if
779*134e1779SJakub Wojciech Klama 	 * xattrwalk and xattrcreate are NULL or always return error.
780*134e1779SJakub Wojciech Klama 	 *
781*134e1779SJakub Wojciech Klama 	 * TODO:
782*134e1779SJakub Wojciech Klama 	 *   separate out directory-read
783*134e1779SJakub Wojciech Klama 	 *   allow async read
784*134e1779SJakub Wojciech Klama 	 */
785*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
786*134e1779SJakub Wojciech Klama 	fid = req->lr_fid;
787*134e1779SJakub Wojciech Klama 	if (l9p_fid_isxattr(fid)) {
788*134e1779SJakub Wojciech Klama 		error = be->xattrread(be->softc, req);
789*134e1779SJakub Wojciech Klama 	} else if (l9p_fid_isopen(fid)) {
790*134e1779SJakub Wojciech Klama 		error = be->read(be->softc, req);
791*134e1779SJakub Wojciech Klama 	} else {
792*134e1779SJakub Wojciech Klama 		error = EINVAL;
793*134e1779SJakub Wojciech Klama 	}
794*134e1779SJakub Wojciech Klama 
795*134e1779SJakub Wojciech Klama 	return (error);
796*134e1779SJakub Wojciech Klama }
797*134e1779SJakub Wojciech Klama 
798*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tremove(struct l9p_request * req)799*134e1779SJakub Wojciech Klama l9p_dispatch_tremove(struct l9p_request *req)
800*134e1779SJakub Wojciech Klama {
801*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
802*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
803*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
804*134e1779SJakub Wojciech Klama 	int error;
805*134e1779SJakub Wojciech Klama 
806*134e1779SJakub Wojciech Klama 	/*
807*134e1779SJakub Wojciech Klama 	 * ?? Should we allow Tremove on auth fids? If so, do
808*134e1779SJakub Wojciech Klama 	 * we pretend it is just a Tclunk?
809*134e1779SJakub Wojciech Klama 	 */
810*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL, 0, &fid);
811*134e1779SJakub Wojciech Klama 	if (error)
812*134e1779SJakub Wojciech Klama 		return (error);
813*134e1779SJakub Wojciech Klama 
814*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
815*134e1779SJakub Wojciech Klama 	l9p_fid_unsetvalid(fid);
816*134e1779SJakub Wojciech Klama 
817*134e1779SJakub Wojciech Klama 	error = be->remove(be->softc, fid);
818*134e1779SJakub Wojciech Klama 	/* fid is now gone regardless of any error return */
819*134e1779SJakub Wojciech Klama 	l9p_connection_remove_fid(conn, fid);
820*134e1779SJakub Wojciech Klama 	return (error);
821*134e1779SJakub Wojciech Klama }
822*134e1779SJakub Wojciech Klama 
823*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tstat(struct l9p_request * req)824*134e1779SJakub Wojciech Klama l9p_dispatch_tstat(struct l9p_request *req)
825*134e1779SJakub Wojciech Klama {
826*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
827*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
828*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
829*134e1779SJakub Wojciech Klama 	int error;
830*134e1779SJakub Wojciech Klama 
831*134e1779SJakub Wojciech Klama 	/* Allow Tstat on auth fid?  Seems harmless enough... */
832*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
833*134e1779SJakub Wojciech Klama 	    F_ALLOW_AUTH, &fid);
834*134e1779SJakub Wojciech Klama 	if (error)
835*134e1779SJakub Wojciech Klama 		return (error);
836*134e1779SJakub Wojciech Klama 
837*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
838*134e1779SJakub Wojciech Klama 	req->lr_fid = fid;
839*134e1779SJakub Wojciech Klama 	error = be->stat(be->softc, req);
840*134e1779SJakub Wojciech Klama 
841*134e1779SJakub Wojciech Klama 	if (error == 0) {
842*134e1779SJakub Wojciech Klama 		if (l9p_fid_isauth(fid))
843*134e1779SJakub Wojciech Klama 			req->lr_resp.rstat.stat.qid.type |= L9P_QTAUTH;
844*134e1779SJakub Wojciech Klama 
845*134e1779SJakub Wojciech Klama 		/* should we check req->lr_resp.rstat.qid.type L9P_QTDIR bit? */
846*134e1779SJakub Wojciech Klama 		if (req->lr_resp.rstat.stat.qid.type &= L9P_QTDIR)
847*134e1779SJakub Wojciech Klama 			l9p_fid_setdir(fid);
848*134e1779SJakub Wojciech Klama 		else
849*134e1779SJakub Wojciech Klama 			l9p_fid_unsetdir(fid);
850*134e1779SJakub Wojciech Klama 	}
851*134e1779SJakub Wojciech Klama 
852*134e1779SJakub Wojciech Klama 	return (error);
853*134e1779SJakub Wojciech Klama }
854*134e1779SJakub Wojciech Klama 
855*134e1779SJakub Wojciech Klama static int
l9p_dispatch_twalk(struct l9p_request * req)856*134e1779SJakub Wojciech Klama l9p_dispatch_twalk(struct l9p_request *req)
857*134e1779SJakub Wojciech Klama {
858*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
859*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
860*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid, *newfid;
861*134e1779SJakub Wojciech Klama 	uint16_t n;
862*134e1779SJakub Wojciech Klama 	int error;
863*134e1779SJakub Wojciech Klama 
864*134e1779SJakub Wojciech Klama 	/* Can forbid XATTR, but cannot require DIR. */
865*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
866*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR, &fid);
867*134e1779SJakub Wojciech Klama 	if (error)
868*134e1779SJakub Wojciech Klama 		return (error);
869*134e1779SJakub Wojciech Klama 
870*134e1779SJakub Wojciech Klama 	if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) {
871*134e1779SJakub Wojciech Klama 		newfid = l9p_connection_alloc_fid(conn,
872*134e1779SJakub Wojciech Klama 		    req->lr_req.twalk.newfid);
873*134e1779SJakub Wojciech Klama 		if (newfid == NULL)
874*134e1779SJakub Wojciech Klama 			return (EINVAL);
875*134e1779SJakub Wojciech Klama 	} else
876*134e1779SJakub Wojciech Klama 		newfid = fid;
877*134e1779SJakub Wojciech Klama 
878*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
879*134e1779SJakub Wojciech Klama 	req->lr_fid = fid;
880*134e1779SJakub Wojciech Klama 	req->lr_newfid = newfid;
881*134e1779SJakub Wojciech Klama 	error = be->walk(be->softc, req);
882*134e1779SJakub Wojciech Klama 
883*134e1779SJakub Wojciech Klama 	/*
884*134e1779SJakub Wojciech Klama 	 * If newfid == fid, then fid itself has (potentially) changed,
885*134e1779SJakub Wojciech Klama 	 * but is still valid.  Otherwise set newfid valid on
886*134e1779SJakub Wojciech Klama 	 * success, and destroy it on error.
887*134e1779SJakub Wojciech Klama 	 */
888*134e1779SJakub Wojciech Klama 	if (newfid != fid) {
889*134e1779SJakub Wojciech Klama 		if (error == 0)
890*134e1779SJakub Wojciech Klama 			l9p_fid_setvalid(newfid);
891*134e1779SJakub Wojciech Klama 		else
892*134e1779SJakub Wojciech Klama 			l9p_connection_remove_fid(conn, newfid);
893*134e1779SJakub Wojciech Klama 	}
894*134e1779SJakub Wojciech Klama 
895*134e1779SJakub Wojciech Klama 	/*
896*134e1779SJakub Wojciech Klama 	 * If we walked any name elements, the last (n-1'th) qid
897*134e1779SJakub Wojciech Klama 	 * has the type (dir vs file) for the new fid.  Otherwise
898*134e1779SJakub Wojciech Klama 	 * the type of newfid is the same as fid.  Of course, if
899*134e1779SJakub Wojciech Klama 	 * n==0 and fid==newfid, fid is already set up correctly
900*134e1779SJakub Wojciech Klama 	 * as the whole thing was a big no-op, but it's safe to
901*134e1779SJakub Wojciech Klama 	 * copy its dir bit to itself.
902*134e1779SJakub Wojciech Klama 	 */
903*134e1779SJakub Wojciech Klama 	if (error == 0) {
904*134e1779SJakub Wojciech Klama 		n = req->lr_resp.rwalk.nwqid;
905*134e1779SJakub Wojciech Klama 		if (n > 0) {
906*134e1779SJakub Wojciech Klama 			if (req->lr_resp.rwalk.wqid[n - 1].type & L9P_QTDIR)
907*134e1779SJakub Wojciech Klama 				l9p_fid_setdir(newfid);
908*134e1779SJakub Wojciech Klama 		} else {
909*134e1779SJakub Wojciech Klama 			if (l9p_fid_isdir(fid))
910*134e1779SJakub Wojciech Klama 				l9p_fid_setdir(newfid);
911*134e1779SJakub Wojciech Klama 		}
912*134e1779SJakub Wojciech Klama 	}
913*134e1779SJakub Wojciech Klama 	return (error);
914*134e1779SJakub Wojciech Klama }
915*134e1779SJakub Wojciech Klama 
916*134e1779SJakub Wojciech Klama static int
l9p_dispatch_twrite(struct l9p_request * req)917*134e1779SJakub Wojciech Klama l9p_dispatch_twrite(struct l9p_request *req)
918*134e1779SJakub Wojciech Klama {
919*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
920*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
921*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
922*134e1779SJakub Wojciech Klama 	int error;
923*134e1779SJakub Wojciech Klama 
924*134e1779SJakub Wojciech Klama 	/* Cannot require open due to xattr write, but can forbid dir. */
925*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
926*134e1779SJakub Wojciech Klama 	    F_FORBID_DIR, &req->lr_fid);
927*134e1779SJakub Wojciech Klama 	if (error)
928*134e1779SJakub Wojciech Klama 		return (error);
929*134e1779SJakub Wojciech Klama 
930*134e1779SJakub Wojciech Klama 	/*
931*134e1779SJakub Wojciech Klama 	 * Adjust to point to the data to be written (a la
932*134e1779SJakub Wojciech Klama 	 * l9p_dispatch_tread, but we're pointing into the request
933*134e1779SJakub Wojciech Klama 	 * buffer rather than the response):
934*134e1779SJakub Wojciech Klama 	 *
935*134e1779SJakub Wojciech Klama 	 * size[4] + Twrite[1] + tag[2] + fid[4] + offset[8] + count[4] = 23
936*134e1779SJakub Wojciech Klama 	 */
937*134e1779SJakub Wojciech Klama 	l9p_seek_iov(req->lr_req_msg.lm_iov, req->lr_req_msg.lm_niov,
938*134e1779SJakub Wojciech Klama 	    req->lr_data_iov, &req->lr_data_niov, 23);
939*134e1779SJakub Wojciech Klama 
940*134e1779SJakub Wojciech Klama 	/*
941*134e1779SJakub Wojciech Klama 	 * Unlike read, write and xattrwrite are optional (for R/O fs).
942*134e1779SJakub Wojciech Klama 	 *
943*134e1779SJakub Wojciech Klama 	 * TODO:
944*134e1779SJakub Wojciech Klama 	 *   allow async write
945*134e1779SJakub Wojciech Klama 	 */
946*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
947*134e1779SJakub Wojciech Klama 	fid = req->lr_fid;
948*134e1779SJakub Wojciech Klama 	if (l9p_fid_isxattr(fid)) {
949*134e1779SJakub Wojciech Klama 		error = be->xattrwrite != NULL ?
950*134e1779SJakub Wojciech Klama 		    be->xattrwrite(be->softc, req) : ENOSYS;
951*134e1779SJakub Wojciech Klama 	} else if (l9p_fid_isopen(fid)) {
952*134e1779SJakub Wojciech Klama 		error = be->write != NULL ?
953*134e1779SJakub Wojciech Klama 		    be->write(be->softc, req) : ENOSYS;
954*134e1779SJakub Wojciech Klama 	} else {
955*134e1779SJakub Wojciech Klama 		error = EINVAL;
956*134e1779SJakub Wojciech Klama 	}
957*134e1779SJakub Wojciech Klama 
958*134e1779SJakub Wojciech Klama 	return (error);
959*134e1779SJakub Wojciech Klama }
960*134e1779SJakub Wojciech Klama 
961*134e1779SJakub Wojciech Klama static int
l9p_dispatch_twstat(struct l9p_request * req)962*134e1779SJakub Wojciech Klama l9p_dispatch_twstat(struct l9p_request *req)
963*134e1779SJakub Wojciech Klama {
964*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
965*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
966*134e1779SJakub Wojciech Klama 	int error;
967*134e1779SJakub Wojciech Klama 
968*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
969*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR, &req->lr_fid);
970*134e1779SJakub Wojciech Klama 	if (error)
971*134e1779SJakub Wojciech Klama 		return (error);
972*134e1779SJakub Wojciech Klama 
973*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
974*134e1779SJakub Wojciech Klama 	error = be->wstat != NULL ? be->wstat(be->softc, req) : ENOSYS;
975*134e1779SJakub Wojciech Klama 	return (error);
976*134e1779SJakub Wojciech Klama }
977*134e1779SJakub Wojciech Klama 
978*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tstatfs(struct l9p_request * req)979*134e1779SJakub Wojciech Klama l9p_dispatch_tstatfs(struct l9p_request *req)
980*134e1779SJakub Wojciech Klama {
981*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
982*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
983*134e1779SJakub Wojciech Klama 	int error;
984*134e1779SJakub Wojciech Klama 
985*134e1779SJakub Wojciech Klama 	/* Should we allow statfs on auth fids? */
986*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL, 0, &req->lr_fid);
987*134e1779SJakub Wojciech Klama 	if (error)
988*134e1779SJakub Wojciech Klama 		return (error);
989*134e1779SJakub Wojciech Klama 
990*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
991*134e1779SJakub Wojciech Klama 	error = be->statfs(be->softc, req);
992*134e1779SJakub Wojciech Klama 	return (error);
993*134e1779SJakub Wojciech Klama }
994*134e1779SJakub Wojciech Klama 
995*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tlopen(struct l9p_request * req)996*134e1779SJakub Wojciech Klama l9p_dispatch_tlopen(struct l9p_request *req)
997*134e1779SJakub Wojciech Klama {
998*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
999*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1000*134e1779SJakub Wojciech Klama 	int error;
1001*134e1779SJakub Wojciech Klama 
1002*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1003*134e1779SJakub Wojciech Klama 	    F_FORBID_OPEN | F_FORBID_XATTR, &req->lr_fid);
1004*134e1779SJakub Wojciech Klama 	if (error)
1005*134e1779SJakub Wojciech Klama 		return (error);
1006*134e1779SJakub Wojciech Klama 
1007*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1008*134e1779SJakub Wojciech Klama 
1009*134e1779SJakub Wojciech Klama 	/*
1010*134e1779SJakub Wojciech Klama 	 * TODO:
1011*134e1779SJakub Wojciech Klama 	 *  - add async open (leaves req->lr_fid in limbo)
1012*134e1779SJakub Wojciech Klama 	 */
1013*134e1779SJakub Wojciech Klama 	error = be->lopen != NULL ? be->lopen(be->softc, req) : ENOSYS;
1014*134e1779SJakub Wojciech Klama 	if (error == 0)
1015*134e1779SJakub Wojciech Klama 		l9p_fid_setopen(req->lr_fid);
1016*134e1779SJakub Wojciech Klama 	return (error);
1017*134e1779SJakub Wojciech Klama }
1018*134e1779SJakub Wojciech Klama 
1019*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tlcreate(struct l9p_request * req)1020*134e1779SJakub Wojciech Klama l9p_dispatch_tlcreate(struct l9p_request *req)
1021*134e1779SJakub Wojciech Klama {
1022*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1023*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1024*134e1779SJakub Wojciech Klama 	int error;
1025*134e1779SJakub Wojciech Klama 
1026*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1027*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1028*134e1779SJakub Wojciech Klama 	if (error)
1029*134e1779SJakub Wojciech Klama 		return (error);
1030*134e1779SJakub Wojciech Klama 
1031*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1032*134e1779SJakub Wojciech Klama 
1033*134e1779SJakub Wojciech Klama 	/*
1034*134e1779SJakub Wojciech Klama 	 * TODO:
1035*134e1779SJakub Wojciech Klama 	 *  - check new file name
1036*134e1779SJakub Wojciech Klama 	 *  - add async create (leaves req->lr_fid in limbo)
1037*134e1779SJakub Wojciech Klama 	 */
1038*134e1779SJakub Wojciech Klama 	error = be->lcreate != NULL ? be->lcreate(be->softc, req) : ENOSYS;
1039*134e1779SJakub Wojciech Klama 	if (error == 0) {
1040*134e1779SJakub Wojciech Klama 		l9p_fid_unsetdir(req->lr_fid);
1041*134e1779SJakub Wojciech Klama 		l9p_fid_setopen(req->lr_fid);
1042*134e1779SJakub Wojciech Klama 	}
1043*134e1779SJakub Wojciech Klama 	return (error);
1044*134e1779SJakub Wojciech Klama }
1045*134e1779SJakub Wojciech Klama 
1046*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tsymlink(struct l9p_request * req)1047*134e1779SJakub Wojciech Klama l9p_dispatch_tsymlink(struct l9p_request *req)
1048*134e1779SJakub Wojciech Klama {
1049*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1050*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1051*134e1779SJakub Wojciech Klama 	int error;
1052*134e1779SJakub Wojciech Klama 
1053*134e1779SJakub Wojciech Klama 	/* This doesn't affect the containing dir; maybe allow OPEN? */
1054*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1055*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1056*134e1779SJakub Wojciech Klama 	if (error)
1057*134e1779SJakub Wojciech Klama 		return (error);
1058*134e1779SJakub Wojciech Klama 
1059*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1060*134e1779SJakub Wojciech Klama 
1061*134e1779SJakub Wojciech Klama 	/*
1062*134e1779SJakub Wojciech Klama 	 * TODO:
1063*134e1779SJakub Wojciech Klama 	 *  - check new file name
1064*134e1779SJakub Wojciech Klama 	 */
1065*134e1779SJakub Wojciech Klama 	error = be->symlink != NULL ? be->symlink(be->softc, req) : ENOSYS;
1066*134e1779SJakub Wojciech Klama 	return (error);
1067*134e1779SJakub Wojciech Klama }
1068*134e1779SJakub Wojciech Klama 
1069*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tmknod(struct l9p_request * req)1070*134e1779SJakub Wojciech Klama l9p_dispatch_tmknod(struct l9p_request *req)
1071*134e1779SJakub Wojciech Klama {
1072*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1073*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1074*134e1779SJakub Wojciech Klama 	int error;
1075*134e1779SJakub Wojciech Klama 
1076*134e1779SJakub Wojciech Klama 	/* This doesn't affect the containing dir; maybe allow OPEN? */
1077*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1078*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1079*134e1779SJakub Wojciech Klama 	if (error)
1080*134e1779SJakub Wojciech Klama 		return (error);
1081*134e1779SJakub Wojciech Klama 
1082*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1083*134e1779SJakub Wojciech Klama 
1084*134e1779SJakub Wojciech Klama 	/*
1085*134e1779SJakub Wojciech Klama 	 * TODO:
1086*134e1779SJakub Wojciech Klama 	 *  - check new file name
1087*134e1779SJakub Wojciech Klama 	 */
1088*134e1779SJakub Wojciech Klama 	error = be->mknod != NULL ? be->mknod(be->softc, req) : ENOSYS;
1089*134e1779SJakub Wojciech Klama 	return (error);
1090*134e1779SJakub Wojciech Klama }
1091*134e1779SJakub Wojciech Klama 
1092*134e1779SJakub Wojciech Klama static int
l9p_dispatch_trename(struct l9p_request * req)1093*134e1779SJakub Wojciech Klama l9p_dispatch_trename(struct l9p_request *req)
1094*134e1779SJakub Wojciech Klama {
1095*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1096*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1097*134e1779SJakub Wojciech Klama 	int error;
1098*134e1779SJakub Wojciech Klama 
1099*134e1779SJakub Wojciech Klama 	/* Rename directory or file (including symlink etc). */
1100*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1101*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR, &req->lr_fid);
1102*134e1779SJakub Wojciech Klama 	if (error)
1103*134e1779SJakub Wojciech Klama 		return (error);
1104*134e1779SJakub Wojciech Klama 
1105*134e1779SJakub Wojciech Klama 	/* Doesn't affect new dir fid; maybe allow OPEN? */
1106*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.trename.dfid, ENOENT,
1107*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2);
1108*134e1779SJakub Wojciech Klama 	if (error)
1109*134e1779SJakub Wojciech Klama 		return (error);
1110*134e1779SJakub Wojciech Klama 
1111*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1112*134e1779SJakub Wojciech Klama 
1113*134e1779SJakub Wojciech Klama 	/*
1114*134e1779SJakub Wojciech Klama 	 * TODO:
1115*134e1779SJakub Wojciech Klama 	 *  - check new file name (trename.name)
1116*134e1779SJakub Wojciech Klama 	 */
1117*134e1779SJakub Wojciech Klama 	error = be->rename != NULL ? be->rename(be->softc, req) : ENOSYS;
1118*134e1779SJakub Wojciech Klama 	return (error);
1119*134e1779SJakub Wojciech Klama }
1120*134e1779SJakub Wojciech Klama 
1121*134e1779SJakub Wojciech Klama static int
l9p_dispatch_treadlink(struct l9p_request * req)1122*134e1779SJakub Wojciech Klama l9p_dispatch_treadlink(struct l9p_request *req)
1123*134e1779SJakub Wojciech Klama {
1124*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1125*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1126*134e1779SJakub Wojciech Klama 	int error;
1127*134e1779SJakub Wojciech Klama 
1128*134e1779SJakub Wojciech Klama 	/*
1129*134e1779SJakub Wojciech Klama 	 * The underlying readlink will fail unless it's a symlink,
1130*134e1779SJakub Wojciech Klama 	 * and the back end has to check, but we might as well forbid
1131*134e1779SJakub Wojciech Klama 	 * directories and open files here since it's cheap.
1132*134e1779SJakub Wojciech Klama 	 */
1133*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1134*134e1779SJakub Wojciech Klama 	    F_FORBID_DIR | F_FORBID_OPEN, &req->lr_fid);
1135*134e1779SJakub Wojciech Klama 	if (error)
1136*134e1779SJakub Wojciech Klama 		return (error);
1137*134e1779SJakub Wojciech Klama 
1138*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1139*134e1779SJakub Wojciech Klama 
1140*134e1779SJakub Wojciech Klama 	error = be->readlink != NULL ? be->readlink(be->softc, req) : ENOSYS;
1141*134e1779SJakub Wojciech Klama 	return (error);
1142*134e1779SJakub Wojciech Klama }
1143*134e1779SJakub Wojciech Klama 
1144*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tgetattr(struct l9p_request * req)1145*134e1779SJakub Wojciech Klama l9p_dispatch_tgetattr(struct l9p_request *req)
1146*134e1779SJakub Wojciech Klama {
1147*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1148*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1149*134e1779SJakub Wojciech Klama 	int error;
1150*134e1779SJakub Wojciech Klama 
1151*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1152*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR, &req->lr_fid);
1153*134e1779SJakub Wojciech Klama 	if (error)
1154*134e1779SJakub Wojciech Klama 		return (error);
1155*134e1779SJakub Wojciech Klama 
1156*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1157*134e1779SJakub Wojciech Klama 
1158*134e1779SJakub Wojciech Klama 	error = be->getattr != NULL ? be->getattr(be->softc, req) : ENOSYS;
1159*134e1779SJakub Wojciech Klama 	return (error);
1160*134e1779SJakub Wojciech Klama }
1161*134e1779SJakub Wojciech Klama 
1162*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tsetattr(struct l9p_request * req)1163*134e1779SJakub Wojciech Klama l9p_dispatch_tsetattr(struct l9p_request *req)
1164*134e1779SJakub Wojciech Klama {
1165*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1166*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1167*134e1779SJakub Wojciech Klama 	int error;
1168*134e1779SJakub Wojciech Klama 
1169*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1170*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR, &req->lr_fid);
1171*134e1779SJakub Wojciech Klama 	if (error)
1172*134e1779SJakub Wojciech Klama 		return (error);
1173*134e1779SJakub Wojciech Klama 
1174*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1175*134e1779SJakub Wojciech Klama 
1176*134e1779SJakub Wojciech Klama 	error = be->setattr != NULL ? be->setattr(be->softc, req) : ENOSYS;
1177*134e1779SJakub Wojciech Klama 	return (error);
1178*134e1779SJakub Wojciech Klama }
1179*134e1779SJakub Wojciech Klama 
1180*134e1779SJakub Wojciech Klama static int
l9p_dispatch_txattrwalk(struct l9p_request * req)1181*134e1779SJakub Wojciech Klama l9p_dispatch_txattrwalk(struct l9p_request *req)
1182*134e1779SJakub Wojciech Klama {
1183*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1184*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1185*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid, *newfid;
1186*134e1779SJakub Wojciech Klama 	int error;
1187*134e1779SJakub Wojciech Klama 
1188*134e1779SJakub Wojciech Klama 	/*
1189*134e1779SJakub Wojciech Klama 	 * Not sure if we care if file-or-dir is open or not.
1190*134e1779SJakub Wojciech Klama 	 * However, the fid argument should always be a file or
1191*134e1779SJakub Wojciech Klama 	 * dir and the newfid argument must be supplied, must
1192*134e1779SJakub Wojciech Klama 	 * be different, and always becomes a new xattr,
1193*134e1779SJakub Wojciech Klama 	 * so this is not very much like Twalk.
1194*134e1779SJakub Wojciech Klama 	 */
1195*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1196*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR, &fid);
1197*134e1779SJakub Wojciech Klama 	if (error)
1198*134e1779SJakub Wojciech Klama 		return (error);
1199*134e1779SJakub Wojciech Klama 
1200*134e1779SJakub Wojciech Klama 	newfid = l9p_connection_alloc_fid(conn, req->lr_req.txattrwalk.newfid);
1201*134e1779SJakub Wojciech Klama 	if (newfid == NULL)
1202*134e1779SJakub Wojciech Klama 		return (EINVAL);
1203*134e1779SJakub Wojciech Klama 
1204*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1205*134e1779SJakub Wojciech Klama 
1206*134e1779SJakub Wojciech Klama 	req->lr_fid = fid;
1207*134e1779SJakub Wojciech Klama 	req->lr_newfid = newfid;
1208*134e1779SJakub Wojciech Klama 	error = be->xattrwalk != NULL ? be->xattrwalk(be->softc, req) : ENOSYS;
1209*134e1779SJakub Wojciech Klama 
1210*134e1779SJakub Wojciech Klama 	/*
1211*134e1779SJakub Wojciech Klama 	 * Success/fail is similar to Twalk, except that we need
1212*134e1779SJakub Wojciech Klama 	 * to set the xattr type bit in the new fid.  It's also
1213*134e1779SJakub Wojciech Klama 	 * much simpler since newfid is always a new fid.
1214*134e1779SJakub Wojciech Klama 	 */
1215*134e1779SJakub Wojciech Klama 	if (error == 0) {
1216*134e1779SJakub Wojciech Klama 		l9p_fid_setvalid(newfid);
1217*134e1779SJakub Wojciech Klama 		l9p_fid_setxattr(newfid);
1218*134e1779SJakub Wojciech Klama 	} else {
1219*134e1779SJakub Wojciech Klama 		l9p_connection_remove_fid(conn, newfid);
1220*134e1779SJakub Wojciech Klama 	}
1221*134e1779SJakub Wojciech Klama 	return (error);
1222*134e1779SJakub Wojciech Klama }
1223*134e1779SJakub Wojciech Klama 
1224*134e1779SJakub Wojciech Klama static int
l9p_dispatch_txattrcreate(struct l9p_request * req)1225*134e1779SJakub Wojciech Klama l9p_dispatch_txattrcreate(struct l9p_request *req)
1226*134e1779SJakub Wojciech Klama {
1227*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1228*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1229*134e1779SJakub Wojciech Klama 	struct l9p_fid *fid;
1230*134e1779SJakub Wojciech Klama 	int error;
1231*134e1779SJakub Wojciech Klama 
1232*134e1779SJakub Wojciech Klama 	/*
1233*134e1779SJakub Wojciech Klama 	 * Forbid incoming open fid since it's going to become an
1234*134e1779SJakub Wojciech Klama 	 * xattr fid instead.  If it turns out we need to allow
1235*134e1779SJakub Wojciech Klama 	 * it, fs code will need to handle this.
1236*134e1779SJakub Wojciech Klama 	 *
1237*134e1779SJakub Wojciech Klama 	 * Curiously, qemu 9pfs uses ENOENT for a bad txattrwalk
1238*134e1779SJakub Wojciech Klama 	 * fid, but EINVAL for txattrcreate (so we do too).
1239*134e1779SJakub Wojciech Klama 	 */
1240*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, EINVAL,
1241*134e1779SJakub Wojciech Klama 	    F_FORBID_XATTR | F_FORBID_OPEN, &fid);
1242*134e1779SJakub Wojciech Klama 	if (error)
1243*134e1779SJakub Wojciech Klama 		return (error);
1244*134e1779SJakub Wojciech Klama 
1245*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1246*134e1779SJakub Wojciech Klama 
1247*134e1779SJakub Wojciech Klama 	req->lr_fid = fid;
1248*134e1779SJakub Wojciech Klama 	error = be->xattrcreate != NULL ? be->xattrcreate(be->softc, req) :
1249*134e1779SJakub Wojciech Klama 	    ENOSYS;
1250*134e1779SJakub Wojciech Klama 
1251*134e1779SJakub Wojciech Klama 	/*
1252*134e1779SJakub Wojciech Klama 	 * On success, fid has changed from a regular (file or dir)
1253*134e1779SJakub Wojciech Klama 	 * fid to an xattr fid.
1254*134e1779SJakub Wojciech Klama 	 */
1255*134e1779SJakub Wojciech Klama 	if (error == 0) {
1256*134e1779SJakub Wojciech Klama 		l9p_fid_unsetdir(fid);
1257*134e1779SJakub Wojciech Klama 		l9p_fid_setxattr(fid);
1258*134e1779SJakub Wojciech Klama 	}
1259*134e1779SJakub Wojciech Klama 	return (error);
1260*134e1779SJakub Wojciech Klama }
1261*134e1779SJakub Wojciech Klama 
1262*134e1779SJakub Wojciech Klama static int
l9p_dispatch_treaddir(struct l9p_request * req)1263*134e1779SJakub Wojciech Klama l9p_dispatch_treaddir(struct l9p_request *req)
1264*134e1779SJakub Wojciech Klama {
1265*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1266*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1267*134e1779SJakub Wojciech Klama 	int error;
1268*134e1779SJakub Wojciech Klama 
1269*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1270*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_REQUIRE_OPEN, &req->lr_fid);
1271*134e1779SJakub Wojciech Klama 	if (error)
1272*134e1779SJakub Wojciech Klama 		return (error);
1273*134e1779SJakub Wojciech Klama 
1274*134e1779SJakub Wojciech Klama 	/*
1275*134e1779SJakub Wojciech Klama 	 * Adjust so that writing messages (packing data) starts
1276*134e1779SJakub Wojciech Klama 	 * right after the count field in the response.
1277*134e1779SJakub Wojciech Klama 	 *
1278*134e1779SJakub Wojciech Klama 	 * size[4] + Rreaddir[1] + tag[2] + count[4] = 11
1279*134e1779SJakub Wojciech Klama 	 */
1280*134e1779SJakub Wojciech Klama 	l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
1281*134e1779SJakub Wojciech Klama 	    req->lr_data_iov, &req->lr_data_niov, 11);
1282*134e1779SJakub Wojciech Klama 
1283*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1284*134e1779SJakub Wojciech Klama 
1285*134e1779SJakub Wojciech Klama 	error = be->readdir != NULL ? be->readdir(be->softc, req) : ENOSYS;
1286*134e1779SJakub Wojciech Klama 	return (error);
1287*134e1779SJakub Wojciech Klama }
1288*134e1779SJakub Wojciech Klama 
1289*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tfsync(struct l9p_request * req)1290*134e1779SJakub Wojciech Klama l9p_dispatch_tfsync(struct l9p_request *req)
1291*134e1779SJakub Wojciech Klama {
1292*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1293*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1294*134e1779SJakub Wojciech Klama 	int error;
1295*134e1779SJakub Wojciech Klama 
1296*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1297*134e1779SJakub Wojciech Klama 	    F_REQUIRE_OPEN, &req->lr_fid);
1298*134e1779SJakub Wojciech Klama 	if (error)
1299*134e1779SJakub Wojciech Klama 		return (error);
1300*134e1779SJakub Wojciech Klama 
1301*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1302*134e1779SJakub Wojciech Klama 
1303*134e1779SJakub Wojciech Klama 	error = be->fsync != NULL ? be->fsync(be->softc, req) : ENOSYS;
1304*134e1779SJakub Wojciech Klama 	return (error);
1305*134e1779SJakub Wojciech Klama }
1306*134e1779SJakub Wojciech Klama 
1307*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tlock(struct l9p_request * req)1308*134e1779SJakub Wojciech Klama l9p_dispatch_tlock(struct l9p_request *req)
1309*134e1779SJakub Wojciech Klama {
1310*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1311*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1312*134e1779SJakub Wojciech Klama 	int error;
1313*134e1779SJakub Wojciech Klama 
1314*134e1779SJakub Wojciech Klama 	/* Forbid directories? */
1315*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1316*134e1779SJakub Wojciech Klama 	    F_REQUIRE_OPEN, &req->lr_fid);
1317*134e1779SJakub Wojciech Klama 	if (error)
1318*134e1779SJakub Wojciech Klama 		return (error);
1319*134e1779SJakub Wojciech Klama 
1320*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1321*134e1779SJakub Wojciech Klama 
1322*134e1779SJakub Wojciech Klama 	/*
1323*134e1779SJakub Wojciech Klama 	 * TODO: multiple client handling; perhaps async locking.
1324*134e1779SJakub Wojciech Klama 	 */
1325*134e1779SJakub Wojciech Klama 	error = be->lock != NULL ? be->lock(be->softc, req) : ENOSYS;
1326*134e1779SJakub Wojciech Klama 	return (error);
1327*134e1779SJakub Wojciech Klama }
1328*134e1779SJakub Wojciech Klama 
1329*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tgetlock(struct l9p_request * req)1330*134e1779SJakub Wojciech Klama l9p_dispatch_tgetlock(struct l9p_request *req)
1331*134e1779SJakub Wojciech Klama {
1332*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1333*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1334*134e1779SJakub Wojciech Klama 	int error;
1335*134e1779SJakub Wojciech Klama 
1336*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1337*134e1779SJakub Wojciech Klama 	    F_REQUIRE_OPEN, &req->lr_fid);
1338*134e1779SJakub Wojciech Klama 	if (error)
1339*134e1779SJakub Wojciech Klama 		return (error);
1340*134e1779SJakub Wojciech Klama 
1341*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1342*134e1779SJakub Wojciech Klama 
1343*134e1779SJakub Wojciech Klama 	/*
1344*134e1779SJakub Wojciech Klama 	 * TODO: multiple client handling; perhaps async locking.
1345*134e1779SJakub Wojciech Klama 	 */
1346*134e1779SJakub Wojciech Klama 	error = be->getlock != NULL ? be->getlock(be->softc, req) : ENOSYS;
1347*134e1779SJakub Wojciech Klama 	return (error);
1348*134e1779SJakub Wojciech Klama }
1349*134e1779SJakub Wojciech Klama 
1350*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tlink(struct l9p_request * req)1351*134e1779SJakub Wojciech Klama l9p_dispatch_tlink(struct l9p_request *req)
1352*134e1779SJakub Wojciech Klama {
1353*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1354*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1355*134e1779SJakub Wojciech Klama 	int error;
1356*134e1779SJakub Wojciech Klama 
1357*134e1779SJakub Wojciech Klama 	/*
1358*134e1779SJakub Wojciech Klama 	 * Note, dfid goes into fid2 in current scheme.
1359*134e1779SJakub Wojciech Klama 	 *
1360*134e1779SJakub Wojciech Klama 	 * Allow open dir?  Target dir fid is not modified...
1361*134e1779SJakub Wojciech Klama 	 */
1362*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.tlink.dfid, ENOENT,
1363*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2);
1364*134e1779SJakub Wojciech Klama 	if (error)
1365*134e1779SJakub Wojciech Klama 		return (error);
1366*134e1779SJakub Wojciech Klama 
1367*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1368*134e1779SJakub Wojciech Klama 	    F_FORBID_DIR | F_FORBID_XATTR, &req->lr_fid);
1369*134e1779SJakub Wojciech Klama 	if (error)
1370*134e1779SJakub Wojciech Klama 		return (error);
1371*134e1779SJakub Wojciech Klama 
1372*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1373*134e1779SJakub Wojciech Klama 
1374*134e1779SJakub Wojciech Klama 	error = be->link != NULL ? be->link(be->softc, req) : ENOSYS;
1375*134e1779SJakub Wojciech Klama 	return (error);
1376*134e1779SJakub Wojciech Klama }
1377*134e1779SJakub Wojciech Klama 
1378*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tmkdir(struct l9p_request * req)1379*134e1779SJakub Wojciech Klama l9p_dispatch_tmkdir(struct l9p_request *req)
1380*134e1779SJakub Wojciech Klama {
1381*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1382*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1383*134e1779SJakub Wojciech Klama 	int error;
1384*134e1779SJakub Wojciech Klama 
1385*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1386*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1387*134e1779SJakub Wojciech Klama 	if (error)
1388*134e1779SJakub Wojciech Klama 		return (error);
1389*134e1779SJakub Wojciech Klama 
1390*134e1779SJakub Wojciech Klama 	/* Slashes embedded in the name are not allowed */
1391*134e1779SJakub Wojciech Klama 	if (strchr(req->lr_req.tlcreate.name, '/') != NULL)
1392*134e1779SJakub Wojciech Klama 		return (EINVAL);
1393*134e1779SJakub Wojciech Klama 
1394*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1395*134e1779SJakub Wojciech Klama 	error = be->mkdir != NULL ? be->mkdir(be->softc, req) : ENOSYS;
1396*134e1779SJakub Wojciech Klama 	return (error);
1397*134e1779SJakub Wojciech Klama }
1398*134e1779SJakub Wojciech Klama 
1399*134e1779SJakub Wojciech Klama static int
l9p_dispatch_trenameat(struct l9p_request * req)1400*134e1779SJakub Wojciech Klama l9p_dispatch_trenameat(struct l9p_request *req)
1401*134e1779SJakub Wojciech Klama {
1402*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1403*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1404*134e1779SJakub Wojciech Klama 	int error;
1405*134e1779SJakub Wojciech Klama 
1406*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1407*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1408*134e1779SJakub Wojciech Klama 	if (error)
1409*134e1779SJakub Wojciech Klama 		return (error);
1410*134e1779SJakub Wojciech Klama 
1411*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.trenameat.newdirfid, ENOENT,
1412*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid2);
1413*134e1779SJakub Wojciech Klama 	if (error)
1414*134e1779SJakub Wojciech Klama 		return (error);
1415*134e1779SJakub Wojciech Klama 
1416*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1417*134e1779SJakub Wojciech Klama 
1418*134e1779SJakub Wojciech Klama 	/* TODO: check old and new names */
1419*134e1779SJakub Wojciech Klama 	error = be->renameat != NULL ? be->renameat(be->softc, req) : ENOSYS;
1420*134e1779SJakub Wojciech Klama 	return (error);
1421*134e1779SJakub Wojciech Klama }
1422*134e1779SJakub Wojciech Klama 
1423*134e1779SJakub Wojciech Klama static int
l9p_dispatch_tunlinkat(struct l9p_request * req)1424*134e1779SJakub Wojciech Klama l9p_dispatch_tunlinkat(struct l9p_request *req)
1425*134e1779SJakub Wojciech Klama {
1426*134e1779SJakub Wojciech Klama 	struct l9p_connection *conn = req->lr_conn;
1427*134e1779SJakub Wojciech Klama 	struct l9p_backend *be;
1428*134e1779SJakub Wojciech Klama 	int error;
1429*134e1779SJakub Wojciech Klama 
1430*134e1779SJakub Wojciech Klama 	error = fid_lookup(conn, req->lr_req.hdr.fid, ENOENT,
1431*134e1779SJakub Wojciech Klama 	    F_REQUIRE_DIR | F_FORBID_OPEN, &req->lr_fid);
1432*134e1779SJakub Wojciech Klama 	if (error)
1433*134e1779SJakub Wojciech Klama 		return (error);
1434*134e1779SJakub Wojciech Klama 
1435*134e1779SJakub Wojciech Klama 	be = conn->lc_server->ls_backend;
1436*134e1779SJakub Wojciech Klama 
1437*134e1779SJakub Wojciech Klama 	/* TODO: check dir-or-file name */
1438*134e1779SJakub Wojciech Klama 	error = be->unlinkat != NULL ? be->unlinkat(be->softc, req) : ENOSYS;
1439*134e1779SJakub Wojciech Klama 	return (error);
1440*134e1779SJakub Wojciech Klama }
1441