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