xref: /illumos-gate/usr/src/lib/lib9p/common/lib9p.h (revision aa693e99)
1*aa693e99SJason King /*
2*aa693e99SJason King  * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
3*aa693e99SJason King  * All rights reserved
4*aa693e99SJason King  *
5*aa693e99SJason King  * Redistribution and use in source and binary forms, with or without
6*aa693e99SJason King  * modification, are permitted providing that the following conditions
7*aa693e99SJason King  * are met:
8*aa693e99SJason King  * 1. Redistributions of source code must retain the above copyright
9*aa693e99SJason King  *    notice, this list of conditions and the following disclaimer.
10*aa693e99SJason King  * 2. Redistributions in binary form must reproduce the above copyright
11*aa693e99SJason King  *    notice, this list of conditions and the following disclaimer in the
12*aa693e99SJason King  *    documentation and/or other materials provided with the distribution.
13*aa693e99SJason King  *
14*aa693e99SJason King  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*aa693e99SJason King  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16*aa693e99SJason King  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*aa693e99SJason King  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18*aa693e99SJason King  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*aa693e99SJason King  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*aa693e99SJason King  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*aa693e99SJason King  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22*aa693e99SJason King  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23*aa693e99SJason King  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24*aa693e99SJason King  * POSSIBILITY OF SUCH DAMAGE.
25*aa693e99SJason King  *
26*aa693e99SJason King  */
27*aa693e99SJason King 
28*aa693e99SJason King 
29*aa693e99SJason King #ifndef LIB9P_LIB9P_H
30*aa693e99SJason King #define LIB9P_LIB9P_H
31*aa693e99SJason King 
32*aa693e99SJason King #include <stdbool.h>
33*aa693e99SJason King #include <stdio.h>
34*aa693e99SJason King #include <sys/types.h>
35*aa693e99SJason King #include <sys/queue.h>
36*aa693e99SJason King #include <sys/uio.h>
37*aa693e99SJason King #include <pthread.h>
38*aa693e99SJason King 
39*aa693e99SJason King #if defined(__FreeBSD__)
40*aa693e99SJason King #include <sys/sbuf.h>
41*aa693e99SJason King #else
42*aa693e99SJason King #include "sbuf/sbuf.h"
43*aa693e99SJason King #endif
44*aa693e99SJason King 
45*aa693e99SJason King #include "fcall.h"
46*aa693e99SJason King #include "threadpool.h"
47*aa693e99SJason King #include "hashtable.h"
48*aa693e99SJason King 
49*aa693e99SJason King #define L9P_DEFAULT_MSIZE   8192
50*aa693e99SJason King #define L9P_MAX_IOV         128
51*aa693e99SJason King #define	L9P_NUMTHREADS      8
52*aa693e99SJason King 
53*aa693e99SJason King struct l9p_request;
54*aa693e99SJason King struct l9p_backend;
55*aa693e99SJason King struct l9p_fid;
56*aa693e99SJason King 
57*aa693e99SJason King /*
58*aa693e99SJason King  * Functions to implement underlying transport for lib9p.
59*aa693e99SJason King  *
60*aa693e99SJason King  * The transport is responsible for:
61*aa693e99SJason King  *
62*aa693e99SJason King  *   - allocating a response buffer (filling in the iovec and niov)
63*aa693e99SJason King  *     (gets req, pointer to base of iov array of size L9P_MAX_IOV,
64*aa693e99SJason King  *      pointer to niov, lt_aux)
65*aa693e99SJason King  *
66*aa693e99SJason King  *   - sending a response, when a request has a reply ready
67*aa693e99SJason King  *     (gets req, pointer to iov, niov, actual response length, lt_aux)
68*aa693e99SJason King  *
69*aa693e99SJason King  *   - dropping the response buffer, when a request has been
70*aa693e99SJason King  *     flushed or otherwise dropped without a response
71*aa693e99SJason King  *     (gets req, pointer to iov, niov, lt_aux)
72*aa693e99SJason King  *
73*aa693e99SJason King  * The transport is of course also responsible for feeding in
74*aa693e99SJason King  * request-buffers, but that happens by the transport calling
75*aa693e99SJason King  * l9p_connection_recv().
76*aa693e99SJason King  */
77*aa693e99SJason King struct l9p_transport {
78*aa693e99SJason King 	void *lt_aux;
79*aa693e99SJason King 	int (*lt_get_response_buffer)(struct l9p_request *, struct iovec *,
80*aa693e99SJason King 	    size_t *, void *);
81*aa693e99SJason King 	int (*lt_send_response)(struct l9p_request *, const struct iovec *,
82*aa693e99SJason King 	    size_t, size_t, void *);
83*aa693e99SJason King 	void (*lt_drop_response)(struct l9p_request *, const struct iovec *,
84*aa693e99SJason King 	    size_t, void *);
85*aa693e99SJason King };
86*aa693e99SJason King 
87*aa693e99SJason King enum l9p_pack_mode {
88*aa693e99SJason King 	L9P_PACK,
89*aa693e99SJason King 	L9P_UNPACK
90*aa693e99SJason King };
91*aa693e99SJason King 
92*aa693e99SJason King enum l9p_integer_type {
93*aa693e99SJason King 	L9P_BYTE = 1,
94*aa693e99SJason King 	L9P_WORD = 2,
95*aa693e99SJason King 	L9P_DWORD = 4,
96*aa693e99SJason King 	L9P_QWORD = 8
97*aa693e99SJason King };
98*aa693e99SJason King 
99*aa693e99SJason King enum l9p_version {
100*aa693e99SJason King 	L9P_INVALID_VERSION = 0,
101*aa693e99SJason King 	L9P_2000 = 1,
102*aa693e99SJason King 	L9P_2000U = 2,
103*aa693e99SJason King 	L9P_2000L = 3
104*aa693e99SJason King };
105*aa693e99SJason King 
106*aa693e99SJason King /*
107*aa693e99SJason King  * This structure is used for unpacking (decoding) incoming
108*aa693e99SJason King  * requests and packing (encoding) outgoing results.  It has its
109*aa693e99SJason King  * own copy of the iov array, with its own counters for working
110*aa693e99SJason King  * through that array, but it borrows the actual DATA from the
111*aa693e99SJason King  * original iov array associated with the original request (see
112*aa693e99SJason King  * below).
113*aa693e99SJason King  */
114*aa693e99SJason King struct l9p_message {
115*aa693e99SJason King 	enum l9p_pack_mode lm_mode;
116*aa693e99SJason King 	struct iovec lm_iov[L9P_MAX_IOV];
117*aa693e99SJason King 	size_t lm_niov;
118*aa693e99SJason King 	size_t lm_cursor_iov;
119*aa693e99SJason King 	size_t lm_cursor_offset;
120*aa693e99SJason King 	size_t lm_size;
121*aa693e99SJason King };
122*aa693e99SJason King 
123*aa693e99SJason King /*
124*aa693e99SJason King  * Data structure for a request/response pair (Tfoo/Rfoo).
125*aa693e99SJason King  *
126*aa693e99SJason King  * Note that the response is not formatted out into raw data
127*aa693e99SJason King  * (overwriting the request raw data) until we are really
128*aa693e99SJason King  * responding, with the exception of read operations Tread
129*aa693e99SJason King  * and Treaddir, which overlay their result-data into the
130*aa693e99SJason King  * iov array in the process of reading.
131*aa693e99SJason King  *
132*aa693e99SJason King  * We have room for two incoming fids, in case we are
133*aa693e99SJason King  * using 9P2000.L protocol.  Note that nothing that uses two
134*aa693e99SJason King  * fids also has an output fid (newfid), so we could have a
135*aa693e99SJason King  * union of lr_fid2 and lr_newfid, but keeping them separate
136*aa693e99SJason King  * is probably a bit less error-prone.  (If we want to shave
137*aa693e99SJason King  * memory requirements there are more places to look.)
138*aa693e99SJason King  *
139*aa693e99SJason King  * (The fid, fid2, and newfid fields should be removed via
140*aa693e99SJason King  * reorganization, as they are only used for smuggling data
141*aa693e99SJason King  * between request.c and the backend and should just be
142*aa693e99SJason King  * parameters to backend ops.)
143*aa693e99SJason King  */
144*aa693e99SJason King struct l9p_request {
145*aa693e99SJason King 	struct l9p_message lr_req_msg;	/* for unpacking the request */
146*aa693e99SJason King 	struct l9p_message lr_resp_msg;	/* for packing the response */
147*aa693e99SJason King 	union l9p_fcall lr_req;		/* the request, decoded/unpacked */
148*aa693e99SJason King 	union l9p_fcall lr_resp;	/* the response, not yet packed */
149*aa693e99SJason King 
150*aa693e99SJason King 	struct l9p_fid *lr_fid;
151*aa693e99SJason King 	struct l9p_fid *lr_fid2;
152*aa693e99SJason King 	struct l9p_fid *lr_newfid;
153*aa693e99SJason King 
154*aa693e99SJason King 	struct l9p_connection *lr_conn;	/* containing connection */
155*aa693e99SJason King 	void *lr_aux;			/* reserved for transport layer */
156*aa693e99SJason King 
157*aa693e99SJason King 	struct iovec lr_data_iov[L9P_MAX_IOV];	/* iovecs for req + resp */
158*aa693e99SJason King 	size_t lr_data_niov;			/* actual size of data_iov */
159*aa693e99SJason King 
160*aa693e99SJason King 	int lr_error;			/* result from l9p_dispatch_request */
161*aa693e99SJason King 
162*aa693e99SJason King 	/* proteced by threadpool mutex */
163*aa693e99SJason King 	enum l9p_workstate lr_workstate;	/* threadpool: work state */
164*aa693e99SJason King 	enum l9p_flushstate lr_flushstate;	/* flush state if flushee */
165*aa693e99SJason King 	struct l9p_worker *lr_worker;		/* threadpool: worker */
166*aa693e99SJason King 	STAILQ_ENTRY(l9p_request) lr_worklink;	/* reserved to threadpool */
167*aa693e99SJason King 
168*aa693e99SJason King 	/* protected by tag hash table lock */
169*aa693e99SJason King 	struct l9p_request_queue lr_flushq;	/* q of flushers */
170*aa693e99SJason King 	STAILQ_ENTRY(l9p_request) lr_flushlink;	/* link w/in flush queue */
171*aa693e99SJason King };
172*aa693e99SJason King 
173*aa693e99SJason King /* N.B.: these dirents are variable length and for .L only */
174*aa693e99SJason King struct l9p_dirent {
175*aa693e99SJason King 	struct l9p_qid qid;
176*aa693e99SJason King 	uint64_t offset;
177*aa693e99SJason King 	uint8_t type;
178*aa693e99SJason King 	char *name;
179*aa693e99SJason King };
180*aa693e99SJason King 
181*aa693e99SJason King /*
182*aa693e99SJason King  * The 9pfs protocol has the notion of a "session", which is
183*aa693e99SJason King  * traffic between any two "Tversion" requests.  All fids
184*aa693e99SJason King  * (lc_files, below) are specific to one particular session.
185*aa693e99SJason King  *
186*aa693e99SJason King  * We need a data structure per connection (client/server
187*aa693e99SJason King  * pair). This data structure lasts longer than these 9pfs
188*aa693e99SJason King  * sessions, but contains the request/response pairs and fids.
189*aa693e99SJason King  * Logically, the per-session data should be separate, but
190*aa693e99SJason King  * most of the time that would just require an extra
191*aa693e99SJason King  * indirection.  Instead, a new session simply clunks all
192*aa693e99SJason King  * fids, and otherwise keeps using this same connection.
193*aa693e99SJason King  */
194*aa693e99SJason King struct l9p_connection {
195*aa693e99SJason King 	struct l9p_server *lc_server;
196*aa693e99SJason King 	struct l9p_transport lc_lt;
197*aa693e99SJason King 	struct l9p_threadpool lc_tp;
198*aa693e99SJason King 	enum l9p_version lc_version;
199*aa693e99SJason King 	uint32_t lc_msize;
200*aa693e99SJason King 	uint32_t lc_max_io_size;
201*aa693e99SJason King 	struct ht lc_files;
202*aa693e99SJason King 	struct ht lc_requests;
203*aa693e99SJason King 	LIST_ENTRY(l9p_connection) lc_link;
204*aa693e99SJason King };
205*aa693e99SJason King 
206*aa693e99SJason King struct l9p_server {
207*aa693e99SJason King 	struct l9p_backend *ls_backend;
208*aa693e99SJason King 	enum l9p_version ls_max_version;
209*aa693e99SJason King 	LIST_HEAD(, l9p_connection) ls_conns;
210*aa693e99SJason King };
211*aa693e99SJason King 
212*aa693e99SJason King int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall,
213*aa693e99SJason King     enum l9p_version version);
214*aa693e99SJason King ssize_t l9p_pustat(struct l9p_message *msg, struct l9p_stat *s,
215*aa693e99SJason King     enum l9p_version version);
216*aa693e99SJason King uint16_t l9p_sizeof_stat(struct l9p_stat *stat, enum l9p_version version);
217*aa693e99SJason King int l9p_pack_stat(struct l9p_message *msg, struct l9p_request *req,
218*aa693e99SJason King     struct l9p_stat *s);
219*aa693e99SJason King ssize_t l9p_pudirent(struct l9p_message *msg, struct l9p_dirent *de);
220*aa693e99SJason King 
221*aa693e99SJason King int l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend);
222*aa693e99SJason King 
223*aa693e99SJason King int l9p_connection_init(struct l9p_server *server,
224*aa693e99SJason King     struct l9p_connection **connp);
225*aa693e99SJason King void l9p_connection_free(struct l9p_connection *conn);
226*aa693e99SJason King void l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
227*aa693e99SJason King     size_t niov, void *aux);
228*aa693e99SJason King void l9p_connection_close(struct l9p_connection *conn);
229*aa693e99SJason King struct l9p_fid *l9p_connection_alloc_fid(struct l9p_connection *conn,
230*aa693e99SJason King     uint32_t fid);
231*aa693e99SJason King void l9p_connection_remove_fid(struct l9p_connection *conn,
232*aa693e99SJason King     struct l9p_fid *fid);
233*aa693e99SJason King 
234*aa693e99SJason King int l9p_dispatch_request(struct l9p_request *req);
235*aa693e99SJason King void l9p_respond(struct l9p_request *req, bool drop, bool rmtag);
236*aa693e99SJason King 
237*aa693e99SJason King void l9p_init_msg(struct l9p_message *msg, struct l9p_request *req,
238*aa693e99SJason King     enum l9p_pack_mode mode);
239*aa693e99SJason King void l9p_seek_iov(const struct iovec *iov1, size_t niov1, struct iovec *iov2,
240*aa693e99SJason King     size_t *niov2, size_t seek);
241*aa693e99SJason King size_t l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length);
242*aa693e99SJason King void l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version,
243*aa693e99SJason King     struct sbuf *sb);
244*aa693e99SJason King void l9p_freefcall(union l9p_fcall *fcall);
245*aa693e99SJason King void l9p_freestat(struct l9p_stat *stat);
246*aa693e99SJason King 
247*aa693e99SJason King gid_t *l9p_getgrlist(const char *, gid_t, int *);
248*aa693e99SJason King 
249*aa693e99SJason King #endif  /* LIB9P_LIB9P_H */
250