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