Changeset View
Changeset View
Standalone View
Standalone View
contrib/lib9p/lib9p.h
- This file was added.
/* | |||||
* Copyright 2016 Jakub Klama <jceel@FreeBSD.org> | |||||
* All rights reserved | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted providing that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||||
* POSSIBILITY OF SUCH DAMAGE. | |||||
* | |||||
*/ | |||||
#ifndef LIB9P_LIB9P_H | |||||
#define LIB9P_LIB9P_H | |||||
#include <stdbool.h> | |||||
#include <stdio.h> | |||||
#include <sys/types.h> | |||||
#include <sys/queue.h> | |||||
#include <sys/uio.h> | |||||
#include <pthread.h> | |||||
#if defined(__FreeBSD__) | |||||
#include <sys/sbuf.h> | |||||
#else | |||||
#include "sbuf/sbuf.h" | |||||
#endif | |||||
#include "fcall.h" | |||||
#include "threadpool.h" | |||||
#include "hashtable.h" | |||||
#define L9P_DEFAULT_MSIZE 8192 | |||||
#define L9P_MAX_IOV 128 | |||||
#define L9P_NUMTHREADS 8 | |||||
struct l9p_request; | |||||
struct l9p_backend; | |||||
struct l9p_fid; | |||||
/* | |||||
* Functions to implement underlying transport for lib9p. | |||||
* | |||||
* The transport is responsible for: | |||||
* | |||||
* - allocating a response buffer (filling in the iovec and niov) | |||||
* (gets req, pointer to base of iov array of size L9P_MAX_IOV, | |||||
* pointer to niov, lt_aux) | |||||
* | |||||
* - sending a response, when a request has a reply ready | |||||
* (gets req, pointer to iov, niov, actual response length, lt_aux) | |||||
* | |||||
* - dropping the response buffer, when a request has been | |||||
* flushed or otherwise dropped without a response | |||||
* (gets req, pointer to iov, niov, lt_aux) | |||||
* | |||||
* The transport is of course also responsible for feeding in | |||||
* request-buffers, but that happens by the transport calling | |||||
* l9p_connection_recv(). | |||||
*/ | |||||
struct l9p_transport { | |||||
void *lt_aux; | |||||
int (*lt_get_response_buffer)(struct l9p_request *, struct iovec *, | |||||
size_t *, void *); | |||||
int (*lt_send_response)(struct l9p_request *, const struct iovec *, | |||||
size_t, size_t, void *); | |||||
void (*lt_drop_response)(struct l9p_request *, const struct iovec *, | |||||
size_t, void *); | |||||
}; | |||||
enum l9p_pack_mode { | |||||
L9P_PACK, | |||||
L9P_UNPACK | |||||
}; | |||||
enum l9p_integer_type { | |||||
L9P_BYTE = 1, | |||||
L9P_WORD = 2, | |||||
L9P_DWORD = 4, | |||||
L9P_QWORD = 8 | |||||
}; | |||||
enum l9p_version { | |||||
L9P_INVALID_VERSION = 0, | |||||
L9P_2000 = 1, | |||||
L9P_2000U = 2, | |||||
L9P_2000L = 3 | |||||
}; | |||||
/* | |||||
* This structure is used for unpacking (decoding) incoming | |||||
* requests and packing (encoding) outgoing results. It has its | |||||
* own copy of the iov array, with its own counters for working | |||||
* through that array, but it borrows the actual DATA from the | |||||
* original iov array associated with the original request (see | |||||
* below). | |||||
*/ | |||||
struct l9p_message { | |||||
enum l9p_pack_mode lm_mode; | |||||
struct iovec lm_iov[L9P_MAX_IOV]; | |||||
size_t lm_niov; | |||||
size_t lm_cursor_iov; | |||||
size_t lm_cursor_offset; | |||||
size_t lm_size; | |||||
}; | |||||
/* | |||||
* Data structure for a request/response pair (Tfoo/Rfoo). | |||||
* | |||||
* Note that the response is not formatted out into raw data | |||||
* (overwriting the request raw data) until we are really | |||||
* responding, with the exception of read operations Tread | |||||
* and Treaddir, which overlay their result-data into the | |||||
* iov array in the process of reading. | |||||
* | |||||
* We have room for two incoming fids, in case we are | |||||
* using 9P2000.L protocol. Note that nothing that uses two | |||||
* fids also has an output fid (newfid), so we could have a | |||||
* union of lr_fid2 and lr_newfid, but keeping them separate | |||||
* is probably a bit less error-prone. (If we want to shave | |||||
* memory requirements there are more places to look.) | |||||
* | |||||
* (The fid, fid2, and newfid fields should be removed via | |||||
* reorganization, as they are only used for smuggling data | |||||
* between request.c and the backend and should just be | |||||
* parameters to backend ops.) | |||||
*/ | |||||
struct l9p_request { | |||||
struct l9p_message lr_req_msg; /* for unpacking the request */ | |||||
struct l9p_message lr_resp_msg; /* for packing the response */ | |||||
union l9p_fcall lr_req; /* the request, decoded/unpacked */ | |||||
union l9p_fcall lr_resp; /* the response, not yet packed */ | |||||
struct l9p_fid *lr_fid; | |||||
struct l9p_fid *lr_fid2; | |||||
struct l9p_fid *lr_newfid; | |||||
struct l9p_connection *lr_conn; /* containing connection */ | |||||
void *lr_aux; /* reserved for transport layer */ | |||||
struct iovec lr_data_iov[L9P_MAX_IOV]; /* iovecs for req + resp */ | |||||
size_t lr_data_niov; /* actual size of data_iov */ | |||||
int lr_error; /* result from l9p_dispatch_request */ | |||||
/* proteced by threadpool mutex */ | |||||
enum l9p_workstate lr_workstate; /* threadpool: work state */ | |||||
enum l9p_flushstate lr_flushstate; /* flush state if flushee */ | |||||
struct l9p_worker *lr_worker; /* threadpool: worker */ | |||||
STAILQ_ENTRY(l9p_request) lr_worklink; /* reserved to threadpool */ | |||||
/* protected by tag hash table lock */ | |||||
struct l9p_request_queue lr_flushq; /* q of flushers */ | |||||
STAILQ_ENTRY(l9p_request) lr_flushlink; /* link w/in flush queue */ | |||||
}; | |||||
/* N.B.: these dirents are variable length and for .L only */ | |||||
struct l9p_dirent { | |||||
struct l9p_qid qid; | |||||
uint64_t offset; | |||||
uint8_t type; | |||||
char *name; | |||||
}; | |||||
/* | |||||
* The 9pfs protocol has the notion of a "session", which is | |||||
* traffic between any two "Tversion" requests. All fids | |||||
* (lc_files, below) are specific to one particular session. | |||||
* | |||||
* We need a data structure per connection (client/server | |||||
* pair). This data structure lasts longer than these 9pfs | |||||
* sessions, but contains the request/response pairs and fids. | |||||
* Logically, the per-session data should be separate, but | |||||
* most of the time that would just require an extra | |||||
* indirection. Instead, a new session simply clunks all | |||||
* fids, and otherwise keeps using this same connection. | |||||
*/ | |||||
struct l9p_connection { | |||||
struct l9p_server *lc_server; | |||||
struct l9p_transport lc_lt; | |||||
struct l9p_threadpool lc_tp; | |||||
enum l9p_version lc_version; | |||||
uint32_t lc_msize; | |||||
uint32_t lc_max_io_size; | |||||
struct ht lc_files; | |||||
struct ht lc_requests; | |||||
LIST_ENTRY(l9p_connection) lc_link; | |||||
}; | |||||
struct l9p_server { | |||||
struct l9p_backend *ls_backend; | |||||
enum l9p_version ls_max_version; | |||||
LIST_HEAD(, l9p_connection) ls_conns; | |||||
}; | |||||
int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall, | |||||
enum l9p_version version); | |||||
ssize_t l9p_pustat(struct l9p_message *msg, struct l9p_stat *s, | |||||
enum l9p_version version); | |||||
uint16_t l9p_sizeof_stat(struct l9p_stat *stat, enum l9p_version version); | |||||
int l9p_pack_stat(struct l9p_message *msg, struct l9p_request *req, | |||||
struct l9p_stat *s); | |||||
ssize_t l9p_pudirent(struct l9p_message *msg, struct l9p_dirent *de); | |||||
int l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend); | |||||
int l9p_connection_init(struct l9p_server *server, | |||||
struct l9p_connection **connp); | |||||
void l9p_connection_free(struct l9p_connection *conn); | |||||
void l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov, | |||||
size_t niov, void *aux); | |||||
void l9p_connection_close(struct l9p_connection *conn); | |||||
struct l9p_fid *l9p_connection_alloc_fid(struct l9p_connection *conn, | |||||
uint32_t fid); | |||||
void l9p_connection_remove_fid(struct l9p_connection *conn, | |||||
struct l9p_fid *fid); | |||||
int l9p_dispatch_request(struct l9p_request *req); | |||||
void l9p_respond(struct l9p_request *req, bool drop, bool rmtag); | |||||
void l9p_init_msg(struct l9p_message *msg, struct l9p_request *req, | |||||
enum l9p_pack_mode mode); | |||||
void l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2, | |||||
size_t *niov2, size_t seek); | |||||
size_t l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length); | |||||
void l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version, | |||||
struct sbuf *sb); | |||||
void l9p_freefcall(union l9p_fcall *fcall); | |||||
void l9p_freestat(struct l9p_stat *stat); | |||||
gid_t *l9p_getgrlist(const char *, gid_t, int *); | |||||
#endif /* LIB9P_LIB9P_H */ |