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