Skip to content

Commit d73ba77

Browse files
Rework streams allocation
According to our ivsetigation typical streams count opened by browser is about 15 - 25. We decide for better memory locality to preallocate 2 pages (8192 bytes, this is enough for 29 streams) and use it as a streams memory. If is memory is exceeded we allocate new 2 pages and use as a streams memory again. We use 8 bytes at the end of the memory which is used for streams as a pointer to the new page block.
1 parent b4a45a6 commit d73ba77

File tree

5 files changed

+139
-63
lines changed

5 files changed

+139
-63
lines changed

fw/http2.c

Lines changed: 120 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,28 +192,135 @@ tfw_h2_apply_new_settings(TfwH2Ctx *ctx)
192192
clear_bit(HTTP2_SETTINGS_NEED_TO_APPLY, ctx->settings_to_apply);
193193
}
194194

195-
int
196-
tfw_h2_init(void)
195+
#define TFW_H2_PAGE_ORDER 1
196+
#define TFW_H2_BOUNDARY(base) \
197+
(char *)base + PAGE_SIZE * (1 << TFW_H2_PAGE_ORDER);
198+
#define TFW_H2_NEXT_BLOCK(boundary) \
199+
(unsigned long *)(boundary - sizeof(unsigned long));
200+
201+
TfwH2Ctx *
202+
tfw_h2_context_alloc(void)
197203
{
198-
return tfw_h2_stream_cache_create();
204+
struct page *pg;
205+
206+
pg = alloc_pages(GFP_ATOMIC, TFW_H2_PAGE_ORDER);
207+
if (!pg)
208+
return NULL;
209+
return (TfwH2Ctx *)page_address(pg);
199210
}
200211

201212
void
202-
tfw_h2_cleanup(void)
213+
tfw_h2_context_free(TfwH2Ctx *ctx)
203214
{
204-
tfw_h2_stream_cache_destroy();
215+
free_pages((unsigned long)ctx, TFW_H2_PAGE_ORDER);
205216
}
206217

207-
TfwH2Ctx *
208-
tfw_h2_context_alloc(void)
218+
static inline void
219+
tfw_h2_context_init_stream_storage_impl(TfwH2Ctx *ctx, void *base,
220+
unsigned long *next_block)
209221
{
210-
return (TfwH2Ctx *)kzalloc(sizeof(TfwH2Ctx), GFP_ATOMIC);
222+
TfwStream *stream = (TfwStream *)base;
223+
224+
while ((char *)stream <= (char *)next_block - sizeof(TfwStream)) {
225+
stream->next = ctx->empty_list;
226+
ctx->empty_list = stream;
227+
stream++;
228+
}
229+
}
230+
231+
static inline int
232+
tfw_h2_conext_alloc_stream_storage_new_block(TfwH2Ctx *ctx)
233+
{
234+
char *boundary;
235+
unsigned long *next_block;
236+
unsigned long *new_block, *next_new_block;
237+
struct page *pg;
238+
239+
boundary = TFW_H2_BOUNDARY(ctx);
240+
next_block = TFW_H2_NEXT_BLOCK(boundary);
241+
242+
pg = alloc_pages(GFP_ATOMIC, TFW_H2_PAGE_ORDER);
243+
if (!unlikely(pg))
244+
return -ENOMEM;
245+
246+
new_block = (unsigned long *)page_address(pg);
247+
boundary = TFW_H2_BOUNDARY(new_block);
248+
next_new_block = TFW_H2_NEXT_BLOCK(boundary);
249+
250+
*next_new_block = *next_block;
251+
*next_block = (unsigned long)new_block;
252+
253+
tfw_h2_context_init_stream_storage_impl(ctx, new_block,
254+
next_new_block);
255+
256+
return 0;
257+
}
258+
259+
static inline void
260+
tfw_h2_context_clear_stream_storage(TfwH2Ctx *ctx)
261+
{
262+
char *boundary;
263+
unsigned long *next_block;
264+
265+
boundary = TFW_H2_BOUNDARY(ctx);
266+
next_block = TFW_H2_NEXT_BLOCK(boundary);
267+
268+
while (*next_block) {
269+
unsigned long to_free;
270+
271+
to_free = *next_block;
272+
boundary = TFW_H2_BOUNDARY(*next_block);
273+
next_block = TFW_H2_NEXT_BLOCK(boundary);
274+
free_pages(to_free, TFW_H2_PAGE_ORDER);
275+
}
276+
}
277+
278+
static inline void
279+
tfw_h2_context_init_stream_storage(TfwH2Ctx *ctx)
280+
{
281+
char *boundary;
282+
unsigned long *new_block;
283+
unsigned long *next_block;
284+
285+
boundary = TFW_H2_BOUNDARY(ctx);
286+
new_block = (unsigned long *)ctx + sizeof(TfwH2Ctx);
287+
next_block = TFW_H2_NEXT_BLOCK(boundary);
288+
289+
/*
290+
* Pointer to the next page block for empty streams, will be allocated,
291+
* if count of preallocated streams exceeded.
292+
*/
293+
*next_block = 0;
294+
tfw_h2_context_init_stream_storage_impl(ctx, new_block, next_block);
295+
}
296+
297+
#undef TFW_H2_NEXT_BLOCK
298+
#undef TFW_H2_BOUNDARY
299+
#undef TFW_H2_PAGE_ORDER
300+
301+
TfwStream *
302+
tfw_h2_conext_alloc_stream(TfwH2Ctx *ctx)
303+
{
304+
TfwStream *stream;
305+
306+
if (!ctx->empty_list) {
307+
if (tfw_h2_conext_alloc_stream_storage_new_block(ctx))
308+
return NULL;
309+
}
310+
311+
stream = ctx->empty_list;
312+
ctx->empty_list = ctx->empty_list->next;
313+
memset(stream, 0, sizeof(TfwStream));
314+
315+
return stream;
211316
}
212317

213318
void
214-
tfw_h2_context_free(TfwH2Ctx *ctx)
319+
tfw_h2_conext_free_stream(TfwH2Ctx *ctx, TfwStream *stream)
215320
{
216-
kfree(ctx);
321+
BUG_ON(stream->xmit.resp || stream->xmit.skb_head);
322+
stream->next = ctx->empty_list;
323+
ctx->empty_list = stream;
217324
}
218325

219326
int
@@ -236,6 +343,7 @@ tfw_h2_context_init(TfwH2Ctx *ctx, TfwH2Conn *conn)
236343
INIT_LIST_HEAD(&idle_streams->list);
237344

238345
tfw_h2_init_stream_sched(&ctx->sched);
346+
tfw_h2_context_init_stream_storage(ctx);
239347

240348
lset->hdr_tbl_sz = rset->hdr_tbl_sz = HPACK_TABLE_DEF_SIZE;
241349
lset->push = rset->push = 1;
@@ -262,6 +370,7 @@ tfw_h2_context_clear(TfwH2Ctx *ctx)
262370
* postponed frames and connection closing initiated.
263371
*/
264372
ss_skb_queue_purge(&ctx->skb_head);
373+
tfw_h2_context_clear_stream_storage(ctx);
265374
tfw_hpack_clean(&ctx->hpack);
266375
}
267376

@@ -321,7 +430,7 @@ tfw_h2_conn_streams_cleanup(TfwH2Ctx *ctx)
321430
* No further actions regarding streams dependencies/prio
322431
* is required at this stage.
323432
*/
324-
tfw_h2_delete_stream(cur);
433+
tfw_h2_conext_free_stream(ctx, cur);
325434
--ctx->streams_num;
326435
}
327436
sched->streams = RB_ROOT;

fw/http2.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ typedef struct tfw_conn_t TfwConn;
8383
* from _HTTP2_SETTINGS_MAX are used to save what
8484
* settings we sent to the client;
8585
* @conn - pointer to h2 connection of this context;
86+
* @empty_list - pointer to the first empty stream;
8687
* @__off - offset to reinitialize processing context;
8788
* @skb_head - collected list of processed skbs containing HTTP/2
8889
* frames;
@@ -128,6 +129,7 @@ typedef struct tfw_h2_ctx_t {
128129
unsigned int new_settings[_HTTP2_SETTINGS_MAX - 1];
129130
DECLARE_BITMAP (settings_to_apply, 2 * _HTTP2_SETTINGS_MAX - 1);
130131
TfwH2Conn *conn;
132+
TfwStream *empty_list;
131133
char __off[0];
132134
struct sk_buff *skb_head;
133135
TfwStream *cur_stream;
@@ -142,8 +144,6 @@ typedef struct tfw_h2_ctx_t {
142144
unsigned char data_off;
143145
} TfwH2Ctx;
144146

145-
int tfw_h2_init(void);
146-
void tfw_h2_cleanup(void);
147147
TfwH2Ctx *tfw_h2_context_alloc(void);
148148
void tfw_h2_context_free(TfwH2Ctx *ctx);
149149
int tfw_h2_context_init(TfwH2Ctx *ctx, TfwH2Conn *conn);
@@ -168,5 +168,7 @@ void tfw_h2_req_unlink_and_close_stream(TfwHttpReq *req);
168168
int tfw_h2_stream_xmit_prepare_resp(TfwStream *stream);
169169
int tfw_h2_entail_stream_skb(struct sock *sk, TfwH2Ctx *ctx, TfwStream *stream,
170170
unsigned int *len, bool should_split);
171+
TfwStream * tfw_h2_conext_alloc_stream(TfwH2Ctx *ctx);
172+
void tfw_h2_conext_free_stream(TfwH2Ctx *ctx, TfwStream *stream);
171173

172174
#endif /* __HTTP2__ */

fw/http_stream.c

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,6 @@
3030

3131
#define HTTP2_DEF_WEIGHT 16
3232

33-
static struct kmem_cache *stream_cache;
34-
35-
int
36-
tfw_h2_stream_cache_create(void)
37-
{
38-
stream_cache = kmem_cache_create("tfw_stream_cache", sizeof(TfwStream),
39-
0, 0, NULL);
40-
if (!stream_cache)
41-
return -ENOMEM;
42-
43-
return 0;
44-
}
45-
46-
void
47-
tfw_h2_stream_cache_destroy(void)
48-
{
49-
kmem_cache_destroy(stream_cache);
50-
}
51-
52-
5333
static inline void
5434
tfw_h2_conn_reset_stream_on_close(TfwH2Ctx *ctx, TfwStream *stream)
5535
{
@@ -102,10 +82,10 @@ tfw_h2_init_stream(TfwStream *stream, unsigned int id, unsigned short weight,
10282
}
10383

10484
static TfwStream *
105-
tfw_h2_add_stream(TfwStreamSched *sched, unsigned int id, unsigned short weight,
106-
long int loc_wnd, long int rem_wnd)
85+
tfw_h2_add_stream(TfwH2Ctx *ctx, unsigned int id, unsigned short weight)
10786
{
10887
TfwStream *new_stream;
88+
TfwStreamSched *sched = &ctx->sched;
10989
struct rb_node **new = &sched->streams.rb_node;
11090
struct rb_node *parent = NULL;
11191

@@ -123,11 +103,12 @@ tfw_h2_add_stream(TfwStreamSched *sched, unsigned int id, unsigned short weight,
123103
}
124104
}
125105

126-
new_stream = kmem_cache_alloc(stream_cache, GFP_ATOMIC | __GFP_ZERO);
106+
new_stream = tfw_h2_conext_alloc_stream(ctx);
127107
if (unlikely(!new_stream))
128108
return NULL;
129109

130-
tfw_h2_init_stream(new_stream, id, weight, loc_wnd, rem_wnd);
110+
tfw_h2_init_stream(new_stream, id, weight, ctx->lsettings.wnd_sz,
111+
ctx->rsettings.wnd_sz);
131112

132113
rb_link_node(&new_stream->node, parent, new);
133114
rb_insert_color(&new_stream->node, &sched->streams);
@@ -225,9 +206,7 @@ tfw_h2_stream_create(TfwH2Ctx *ctx, unsigned int id)
225206
pri->exclusive, pri->stream_id, ctx, ctx->streams_num);
226207

227208
dep = tfw_h2_find_stream_dep(&ctx->sched, pri->stream_id);
228-
stream = tfw_h2_add_stream(&ctx->sched, id, pri->weight,
229-
ctx->lsettings.wnd_sz,
230-
ctx->rsettings.wnd_sz);
209+
stream = tfw_h2_add_stream(ctx, id, pri->weight);
231210
if (!stream)
232211
return NULL;
233212

@@ -245,7 +224,7 @@ tfw_h2_stream_clean(TfwH2Ctx *ctx, TfwStream *stream)
245224
tfw_h2_get_stream_state(stream), __h2_strm_st_n(stream),
246225
stream->weight, ctx, ctx->streams_num);
247226
tfw_h2_stop_stream(&ctx->sched, stream);
248-
tfw_h2_delete_stream(stream);
227+
tfw_h2_conext_free_stream(ctx, stream);
249228
--ctx->streams_num;
250229
}
251230

@@ -795,13 +774,6 @@ tfw_h2_find_stream(TfwStreamSched *sched, unsigned int id)
795774
return NULL;
796775
}
797776

798-
void
799-
tfw_h2_delete_stream(TfwStream *stream)
800-
{
801-
BUG_ON(stream->xmit.resp || stream->xmit.skb_head);
802-
kmem_cache_free(stream_cache, stream);
803-
}
804-
805777
int
806778
tfw_h2_stream_init_for_xmit(TfwHttpResp *resp, TfwStreamXmitState state,
807779
unsigned long h_len, unsigned long b_len)
@@ -840,7 +812,7 @@ tfw_h2_stream_init_for_xmit(TfwHttpResp *resp, TfwStreamXmitState state,
840812
int
841813
tfw_h2_stream_init_t_len_for_xmit(TfwHttpResp *resp, unsigned long t_len)
842814
{
843-
TfwH2Ctx *ctx = tfw_h2_context_unsafe(resp->req->conn);
815+
TfwH2Ctx *ctx = tfw_h2_context(resp->req->conn);
844816
TfwStream *stream;
845817

846818
spin_lock(&ctx->lock);

fw/http_stream.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ typedef enum {
179179
* @msg - message that is currently being processed;
180180
* @parser - the state of message processing;
181181
* @queue - queue of half-closed or closed streams or NULL;
182+
* @next - pointer to the next free stream, if this stream is in
183+
* empty list;
182184
* @xmit - last http2 response info, used in `xmit` callbacks;
183185
*/
184186
struct tfw_http_stream_t {
@@ -196,13 +198,12 @@ struct tfw_http_stream_t {
196198
TfwMsg *msg;
197199
TfwHttpParser parser;
198200
TfwStreamQueue *queue;
201+
TfwStream *next;
199202
TfwHttpXmit xmit;
200203
};
201204

202205
typedef struct tfw_h2_ctx_t TfwH2Ctx;
203206

204-
int tfw_h2_stream_cache_create(void);
205-
void tfw_h2_stream_cache_destroy(void);
206207
TfwStream *tfw_h2_stream_create(TfwH2Ctx *ctx, unsigned int id);
207208
void tfw_h2_stream_remove_idle(TfwH2Ctx *ctx, TfwStream *stream);
208209
void tfw_h2_stream_clean(TfwH2Ctx *ctx, TfwStream *stream);
@@ -212,7 +213,6 @@ TfwStreamFsmRes tfw_h2_stream_fsm(TfwH2Ctx *ctx, TfwStream *stream,
212213
unsigned char type, unsigned char flags,
213214
bool send, TfwH2Err *err);
214215
TfwStream *tfw_h2_find_stream(TfwStreamSched *sched, unsigned int id);
215-
void tfw_h2_delete_stream(TfwStream *stream);
216216
int tfw_h2_stream_init_for_xmit(TfwHttpResp *resp, TfwStreamXmitState state,
217217
unsigned long h_len, unsigned long b_len);
218218
int tfw_h2_stream_init_t_len_for_xmit(TfwHttpResp *resp, unsigned long t_len);

fw/tls.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -961,18 +961,20 @@ static inline int
961961
tfw_tls_over(TlsCtx *tls, int state)
962962
{
963963
int sk_proto = ((SsProto *)tls->sk->sk_user_data)->type;
964-
TfwH2Conn *conn = (TfwH2Conn*)tls->sk->sk_user_data;
965964

966965
if (state == TTLS_HS_CB_FINISHED_NEW
967966
|| state == TTLS_HS_CB_FINISHED_RESUMED)
968967
TFW_INC_STAT_BH(serv.tls_hs_successful);
969968

970969
if (TFW_FSM_TYPE(sk_proto) == TFW_FSM_H2) {
970+
TfwH2Conn *conn = (TfwH2Conn*)tls->sk->sk_user_data;
971971
int r;
972972

973973
conn->h2 = tfw_h2_context_alloc();
974-
if (!conn->h2)
974+
if (!conn->h2) {
975+
T_ERR("cannot allocate http2 connection context");
975976
return -ENOMEM;
977+
}
976978
r = tfw_h2_context_init(conn->h2, conn);
977979
if (r) {
978980
T_ERR("cannot establish a new h2 connection\n");
@@ -1244,26 +1246,17 @@ tfw_tls_init(void)
12441246
ttls_cli_id, tfw_tls_alpn_match,
12451247
tfw_ja5t_limit_conn, tfw_ja5t_limit_rec);
12461248

1247-
if ((r = tfw_h2_init()))
1248-
goto err_h2;
1249-
12501249
tfw_connection_hooks_register(&tls_conn_hooks, TFW_FSM_HTTPS);
12511250
tfw_connection_hooks_register(&tls_conn_hooks, TFW_FSM_H2);
12521251
tfw_mod_register(&tfw_tls_mod);
12531252

12541253
return 0;
1255-
1256-
err_h2:
1257-
tfw_tls_do_cleanup();
1258-
1259-
return r;
12601254
}
12611255

12621256
void
12631257
tfw_tls_exit(void)
12641258
{
12651259
tfw_mod_unregister(&tfw_tls_mod);
12661260
tfw_connection_hooks_unregister(TFW_FSM_HTTPS);
1267-
tfw_h2_cleanup();
12681261
tfw_tls_do_cleanup();
12691262
}

0 commit comments

Comments
 (0)