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