Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sctp: convert to genradix

This also makes sctp_stream_alloc_(out|in) saner, in that they no longer
allocate new flex_arrays/genradixes, they just preallocate more
elements.

This code does however have a suspicious lack of locking.

Link: http://lkml.kernel.org/r/20181217131929.11727-7-kent.overstreet@gmail.com
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Cc: Vlad Yasevich <vyasevich@gmail.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Eric Paris <eparis@parisplace.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Paul Moore <paul@paul-moore.com>
Cc: Pravin B Shelar <pshelar@ovn.org>
Cc: Shaohua Li <shli@kernel.org>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kent Overstreet and committed by
Linus Torvalds
2075e50c 94f8f3b0

+28 -114
+8 -7
include/net/sctp/structs.h
··· 48 48 #define __sctp_structs_h__ 49 49 50 50 #include <linux/ktime.h> 51 + #include <linux/generic-radix-tree.h> 51 52 #include <linux/rhashtable-types.h> 52 53 #include <linux/socket.h> /* linux/in.h needs this!! */ 53 54 #include <linux/in.h> /* We get struct sockaddr_in. */ ··· 58 57 #include <linux/atomic.h> /* This gets us atomic counters. */ 59 58 #include <linux/skbuff.h> /* We need sk_buff_head. */ 60 59 #include <linux/workqueue.h> /* We need tq_struct. */ 61 - #include <linux/flex_array.h> /* We need flex_array. */ 62 60 #include <linux/sctp.h> /* We need sctp* header structs. */ 63 61 #include <net/sctp/auth.h> /* We need auth specific structs */ 64 62 #include <net/ip.h> /* For inet_skb_parm */ ··· 1449 1449 }; 1450 1450 1451 1451 struct sctp_stream { 1452 - struct flex_array *out; 1453 - struct flex_array *in; 1452 + GENRADIX(struct sctp_stream_out) out; 1453 + GENRADIX(struct sctp_stream_in) in; 1454 + 1454 1455 __u16 outcnt; 1455 1456 __u16 incnt; 1456 1457 /* Current stream being sent, if any */ ··· 1474 1473 }; 1475 1474 1476 1475 static inline struct sctp_stream_out *sctp_stream_out( 1477 - const struct sctp_stream *stream, 1476 + struct sctp_stream *stream, 1478 1477 __u16 sid) 1479 1478 { 1480 - return flex_array_get(stream->out, sid); 1479 + return genradix_ptr(&stream->out, sid); 1481 1480 } 1482 1481 1483 1482 static inline struct sctp_stream_in *sctp_stream_in( 1484 - const struct sctp_stream *stream, 1483 + struct sctp_stream *stream, 1485 1484 __u16 sid) 1486 1485 { 1487 - return flex_array_get(stream->in, sid); 1486 + return genradix_ptr(&stream->in, sid); 1488 1487 } 1489 1488 1490 1489 #define SCTP_SO(s, i) sctp_stream_out((s), (i))
+19 -106
net/sctp/stream.c
··· 37 37 #include <net/sctp/sm.h> 38 38 #include <net/sctp/stream_sched.h> 39 39 40 - static struct flex_array *fa_alloc(size_t elem_size, size_t elem_count, 41 - gfp_t gfp) 42 - { 43 - struct flex_array *result; 44 - int err; 45 - 46 - result = flex_array_alloc(elem_size, elem_count, gfp); 47 - if (result) { 48 - err = flex_array_prealloc(result, 0, elem_count, gfp); 49 - if (err) { 50 - flex_array_free(result); 51 - result = NULL; 52 - } 53 - } 54 - 55 - return result; 56 - } 57 - 58 - static void fa_free(struct flex_array *fa) 59 - { 60 - if (fa) 61 - flex_array_free(fa); 62 - } 63 - 64 - static void fa_copy(struct flex_array *fa, struct flex_array *from, 65 - size_t index, size_t count) 66 - { 67 - void *elem; 68 - 69 - while (count--) { 70 - elem = flex_array_get(from, index); 71 - flex_array_put(fa, index, elem, 0); 72 - index++; 73 - } 74 - } 75 - 76 - static void fa_zero(struct flex_array *fa, size_t index, size_t count) 77 - { 78 - void *elem; 79 - 80 - while (count--) { 81 - elem = flex_array_get(fa, index); 82 - memset(elem, 0, fa->element_size); 83 - index++; 84 - } 85 - } 86 - 87 - static size_t fa_index(struct flex_array *fa, void *elem, size_t count) 88 - { 89 - size_t index = 0; 90 - 91 - while (count--) { 92 - if (elem == flex_array_get(fa, index)) 93 - break; 94 - index++; 95 - } 96 - 97 - return index; 98 - } 99 - 100 40 /* Migrates chunks from stream queues to new stream queues if needed, 101 41 * but not across associations. Also, removes those chunks to streams 102 42 * higher than the new max. ··· 93 153 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, 94 154 gfp_t gfp) 95 155 { 96 - struct flex_array *out; 97 - size_t elem_size = sizeof(struct sctp_stream_out); 156 + int ret; 98 157 99 - out = fa_alloc(elem_size, outcnt, gfp); 100 - if (!out) 101 - return -ENOMEM; 158 + if (outcnt <= stream->outcnt) 159 + return 0; 102 160 103 - if (stream->out) { 104 - fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt)); 105 - if (stream->out_curr) { 106 - size_t index = fa_index(stream->out, stream->out_curr, 107 - stream->outcnt); 161 + ret = genradix_prealloc(&stream->out, outcnt, gfp); 162 + if (ret) 163 + return ret; 108 164 109 - BUG_ON(index == stream->outcnt); 110 - stream->out_curr = flex_array_get(out, index); 111 - } 112 - fa_free(stream->out); 113 - } 114 - 115 - if (outcnt > stream->outcnt) 116 - fa_zero(out, stream->outcnt, (outcnt - stream->outcnt)); 117 - 118 - stream->out = out; 119 - 165 + stream->outcnt = outcnt; 120 166 return 0; 121 167 } 122 168 123 169 static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt, 124 170 gfp_t gfp) 125 171 { 126 - struct flex_array *in; 127 - size_t elem_size = sizeof(struct sctp_stream_in); 172 + int ret; 128 173 129 - in = fa_alloc(elem_size, incnt, gfp); 130 - if (!in) 131 - return -ENOMEM; 174 + if (incnt <= stream->incnt) 175 + return 0; 132 176 133 - if (stream->in) { 134 - fa_copy(in, stream->in, 0, min(incnt, stream->incnt)); 135 - fa_free(stream->in); 136 - } 177 + ret = genradix_prealloc(&stream->in, incnt, gfp); 178 + if (ret) 179 + return ret; 137 180 138 - if (incnt > stream->incnt) 139 - fa_zero(in, stream->incnt, (incnt - stream->incnt)); 140 - 141 - stream->in = in; 142 - 181 + stream->incnt = incnt; 143 182 return 0; 144 183 } 145 184 ··· 145 226 if (ret) 146 227 goto out; 147 228 148 - stream->outcnt = outcnt; 149 229 for (i = 0; i < stream->outcnt; i++) 150 230 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; 151 231 ··· 156 238 ret = sctp_stream_alloc_in(stream, incnt, gfp); 157 239 if (ret) { 158 240 sched->free(stream); 159 - fa_free(stream->out); 160 - stream->out = NULL; 241 + genradix_free(&stream->out); 161 242 stream->outcnt = 0; 162 243 goto out; 163 244 } 164 - 165 - stream->incnt = incnt; 166 245 167 246 out: 168 247 return ret; ··· 185 270 sched->free(stream); 186 271 for (i = 0; i < stream->outcnt; i++) 187 272 kfree(SCTP_SO(stream, i)->ext); 188 - fa_free(stream->out); 189 - fa_free(stream->in); 273 + genradix_free(&stream->out); 274 + genradix_free(&stream->in); 190 275 } 191 276 192 277 void sctp_stream_clear(struct sctp_stream *stream) ··· 217 302 218 303 sched->sched_all(stream); 219 304 220 - new->out = NULL; 221 - new->in = NULL; 305 + new->out.tree.root = NULL; 306 + new->in.tree.root = NULL; 222 307 new->outcnt = 0; 223 308 new->incnt = 0; 224 309 } ··· 469 554 asoc->strreset_chunk = NULL; 470 555 goto out; 471 556 } 472 - 473 - stream->outcnt = outcnt; 474 557 475 558 asoc->strreset_outstanding = !!out + !!in; 476 559
+1 -1
net/sctp/stream_interleave.c
··· 101 101 102 102 static bool sctp_validate_data(struct sctp_chunk *chunk) 103 103 { 104 - const struct sctp_stream *stream; 104 + struct sctp_stream *stream; 105 105 __u16 sid, ssn; 106 106 107 107 if (chunk->chunk_hdr->type != SCTP_CID_DATA)