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(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