]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/lib9p/connection.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / contrib / lib9p / connection.c
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 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <sys/queue.h>
33 #include "lib9p.h"
34 #include "lib9p_impl.h"
35 #include "fid.h"
36 #include "hashtable.h"
37 #include "log.h"
38 #include "threadpool.h"
39 #include "backend/backend.h"
40
41 int
42 l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend)
43 {
44         struct l9p_server *server;
45
46         server = l9p_calloc(1, sizeof (*server));
47         server->ls_max_version = L9P_2000L;
48         server->ls_backend = backend;
49         LIST_INIT(&server->ls_conns);
50
51         *serverp = server;
52         return (0);
53 }
54
55 int
56 l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn)
57 {
58         struct l9p_connection *newconn;
59
60         assert(server != NULL);
61         assert(conn != NULL);
62
63         newconn = calloc(1, sizeof (*newconn));
64         if (newconn == NULL)
65                 return (-1);
66         newconn->lc_server = server;
67         newconn->lc_msize = L9P_DEFAULT_MSIZE;
68         if (l9p_threadpool_init(&newconn->lc_tp, L9P_NUMTHREADS)) {
69                 free(newconn);
70                 return (-1);
71         }
72         ht_init(&newconn->lc_files, 100);
73         ht_init(&newconn->lc_requests, 100);
74         LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link);
75         *conn = newconn;
76
77         return (0);
78 }
79
80 void
81 l9p_connection_free(struct l9p_connection *conn)
82 {
83
84         LIST_REMOVE(conn, lc_link);
85         free(conn);
86 }
87
88 void
89 l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
90     const size_t niov, void *aux)
91 {
92         struct l9p_request *req;
93         int error;
94
95         req = l9p_calloc(1, sizeof (struct l9p_request));
96         req->lr_aux = aux;
97         req->lr_conn = conn;
98
99         req->lr_req_msg.lm_mode = L9P_UNPACK;
100         req->lr_req_msg.lm_niov = niov;
101         memcpy(req->lr_req_msg.lm_iov, iov, sizeof (struct iovec) * niov);
102
103         req->lr_resp_msg.lm_mode = L9P_PACK;
104
105         if (l9p_pufcall(&req->lr_req_msg, &req->lr_req, conn->lc_version) != 0) {
106                 L9P_LOG(L9P_WARNING, "cannot unpack received message");
107                 l9p_freefcall(&req->lr_req);
108                 free(req);
109                 return;
110         }
111
112         if (ht_add(&conn->lc_requests, req->lr_req.hdr.tag, req)) {
113                 L9P_LOG(L9P_WARNING, "client reusing outstanding tag %d",
114                     req->lr_req.hdr.tag);
115                 l9p_freefcall(&req->lr_req);
116                 free(req);
117                 return;
118         }
119
120         error = conn->lc_lt.lt_get_response_buffer(req,
121             req->lr_resp_msg.lm_iov,
122             &req->lr_resp_msg.lm_niov,
123             conn->lc_lt.lt_aux);
124         if (error) {
125                 L9P_LOG(L9P_WARNING, "cannot obtain buffers for response");
126                 ht_remove(&conn->lc_requests, req->lr_req.hdr.tag);
127                 l9p_freefcall(&req->lr_req);
128                 free(req);
129                 return;
130         }
131
132         /*
133          * NB: it's up to l9p_threadpool_run to decide whether
134          * to queue the work or to run it immediately and wait
135          * (it must do the latter for Tflush requests).
136          */
137         l9p_threadpool_run(&conn->lc_tp, req);
138 }
139
140 void
141 l9p_connection_close(struct l9p_connection *conn)
142 {
143         struct ht_iter iter;
144         struct l9p_fid *fid;
145         struct l9p_request *req;
146
147         L9P_LOG(L9P_DEBUG, "waiting for thread pool to shut down");
148         l9p_threadpool_shutdown(&conn->lc_tp);
149
150         /* Drain pending requests (if any) */
151         L9P_LOG(L9P_DEBUG, "draining pending requests");
152         ht_iter(&conn->lc_requests, &iter);
153         while ((req = ht_next(&iter)) != NULL) {
154 #ifdef notyet
155                 /* XXX would be good to know if there is anyone listening */
156                 if (anyone listening) {
157                         /* XXX crude - ops like Tclunk should succeed */
158                         req->lr_error = EINTR;
159                         l9p_respond(req, false, false);
160                 } else
161 #endif
162                 l9p_respond(req, true, false);  /* use no-answer path */
163                 ht_remove_at_iter(&iter);
164         }
165
166         /* Close opened files (if any) */
167         L9P_LOG(L9P_DEBUG, "closing opened files");
168         ht_iter(&conn->lc_files, &iter);
169         while ((fid = ht_next(&iter)) != NULL) {
170                 conn->lc_server->ls_backend->freefid(
171                     conn->lc_server->ls_backend->softc, fid);
172                 free(fid);
173                 ht_remove_at_iter(&iter);
174         }
175
176         ht_destroy(&conn->lc_requests);
177         ht_destroy(&conn->lc_files);
178 }
179
180 struct l9p_fid *
181 l9p_connection_alloc_fid(struct l9p_connection *conn, uint32_t fid)
182 {
183         struct l9p_fid *file;
184
185         file = l9p_calloc(1, sizeof (struct l9p_fid));
186         file->lo_fid = fid;
187         /*
188          * Note that the new fid is not marked valid yet.
189          * The insert here will fail if the fid number is
190          * in use, otherwise we have an invalid fid in the
191          * table (as desired).
192          */
193
194         if (ht_add(&conn->lc_files, fid, file) != 0) {
195                 free(file);
196                 return (NULL);
197         }
198
199         return (file);
200 }
201
202 void
203 l9p_connection_remove_fid(struct l9p_connection *conn, struct l9p_fid *fid)
204 {
205         struct l9p_backend *be;
206
207         /* fid should be marked invalid by this point */
208         assert(!l9p_fid_isvalid(fid));
209
210         be = conn->lc_server->ls_backend;
211         be->freefid(be->softc, fid);
212
213         ht_remove(&conn->lc_files, fid->lo_fid);
214         free(fid);
215 }