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