2 * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
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.
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.
34 #include <sys/types.h>
35 #include <sys/queue.h>
39 #if defined(__FreeBSD__)
42 #include "sbuf/sbuf.h"
46 #include "threadpool.h"
47 #include "hashtable.h"
49 #define L9P_DEFAULT_MSIZE 8192
50 #define L9P_MAX_IOV 128
51 #define L9P_NUMTHREADS 8
58 * Functions to implement underlying transport for lib9p.
60 * The transport is responsible for:
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)
66 * - sending a response, when a request has a reply ready
67 * (gets req, pointer to iov, niov, actual response length, lt_aux)
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)
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().
77 struct l9p_transport {
79 int (*lt_get_response_buffer)(struct l9p_request *, struct iovec *,
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 *,
92 enum l9p_integer_type {
100 L9P_INVALID_VERSION = 0,
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
115 enum l9p_pack_mode lm_mode;
116 struct iovec lm_iov[L9P_MAX_IOV];
118 size_t lm_cursor_iov;
119 size_t lm_cursor_offset;
124 * Data structure for a request/response pair (Tfoo/Rfoo).
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.
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.)
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.)
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 */
150 struct l9p_fid *lr_fid;
151 struct l9p_fid *lr_fid2;
152 struct l9p_fid *lr_newfid;
154 struct l9p_connection *lr_conn; /* containing connection */
155 void *lr_aux; /* reserved for transport layer */
157 struct iovec lr_data_iov[L9P_MAX_IOV]; /* iovecs for req + resp */
158 size_t lr_data_niov; /* actual size of data_iov */
160 int lr_error; /* result from l9p_dispatch_request */
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 */
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 */
173 /* N.B.: these dirents are variable length and for .L only */
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.
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.
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;
200 uint32_t lc_max_io_size;
202 struct ht lc_requests;
203 LIST_ENTRY(l9p_connection) lc_link;
207 struct l9p_backend *ls_backend;
208 enum l9p_version ls_max_version;
209 LIST_HEAD(, l9p_connection) ls_conns;
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,
219 ssize_t l9p_pudirent(struct l9p_message *msg, struct l9p_dirent *de);
221 int l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend);
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,
231 void l9p_connection_remove_fid(struct l9p_connection *conn,
232 struct l9p_fid *fid);
234 int l9p_dispatch_request(struct l9p_request *req);
235 void l9p_respond(struct l9p_request *req, bool drop, bool rmtag);
237 void l9p_init_msg(struct l9p_message *msg, struct l9p_request *req,
238 enum l9p_pack_mode mode);
239 void l9p_seek_iov(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,
244 void l9p_freefcall(union l9p_fcall *fcall);
245 void l9p_freestat(struct l9p_stat *stat);
247 gid_t *l9p_getgrlist(const char *, gid_t, int *);
249 #endif /* LIB9P_LIB9P_H */