.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* SCTP kernel implementation |
---|
2 | 3 | * (C) Copyright Red Hat Inc. 2017 |
---|
3 | 4 | * |
---|
4 | 5 | * This file is part of the SCTP kernel implementation |
---|
5 | 6 | * |
---|
6 | 7 | * These functions manipulate sctp stream queue/scheduling. |
---|
7 | | - * |
---|
8 | | - * This SCTP implementation is free software; |
---|
9 | | - * you can redistribute it and/or modify it under the terms of |
---|
10 | | - * the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; either version 2, or (at your option) |
---|
12 | | - * any later version. |
---|
13 | | - * |
---|
14 | | - * This SCTP implementation is distributed in the hope that it |
---|
15 | | - * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
---|
16 | | - * ************************ |
---|
17 | | - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
---|
18 | | - * See the GNU General Public License for more details. |
---|
19 | | - * |
---|
20 | | - * You should have received a copy of the GNU General Public License |
---|
21 | | - * along with GNU CC; see the file COPYING. If not, see |
---|
22 | | - * <http://www.gnu.org/licenses/>. |
---|
23 | 8 | * |
---|
24 | 9 | * Please send any bug reports or fixes you make to the |
---|
25 | 10 | * email addresched(es): |
---|
.. | .. |
---|
40 | 25 | |
---|
41 | 26 | static void sctp_sched_prio_unsched_all(struct sctp_stream *stream); |
---|
42 | 27 | |
---|
| 28 | +static struct sctp_stream_priorities *sctp_sched_prio_head_get(struct sctp_stream_priorities *p) |
---|
| 29 | +{ |
---|
| 30 | + p->users++; |
---|
| 31 | + return p; |
---|
| 32 | +} |
---|
| 33 | + |
---|
| 34 | +static void sctp_sched_prio_head_put(struct sctp_stream_priorities *p) |
---|
| 35 | +{ |
---|
| 36 | + if (p && --p->users == 0) |
---|
| 37 | + kfree(p); |
---|
| 38 | +} |
---|
| 39 | + |
---|
43 | 40 | static struct sctp_stream_priorities *sctp_sched_prio_new_head( |
---|
44 | 41 | struct sctp_stream *stream, int prio, gfp_t gfp) |
---|
45 | 42 | { |
---|
.. | .. |
---|
53 | 50 | INIT_LIST_HEAD(&p->active); |
---|
54 | 51 | p->next = NULL; |
---|
55 | 52 | p->prio = prio; |
---|
| 53 | + p->users = 1; |
---|
56 | 54 | |
---|
57 | 55 | return p; |
---|
58 | 56 | } |
---|
.. | .. |
---|
68 | 66 | */ |
---|
69 | 67 | list_for_each_entry(p, &stream->prio_list, prio_sched) { |
---|
70 | 68 | if (p->prio == prio) |
---|
71 | | - return p; |
---|
| 69 | + return sctp_sched_prio_head_get(p); |
---|
72 | 70 | if (p->prio > prio) |
---|
73 | 71 | break; |
---|
74 | 72 | } |
---|
.. | .. |
---|
85 | 83 | */ |
---|
86 | 84 | break; |
---|
87 | 85 | if (p->prio == prio) |
---|
88 | | - return p; |
---|
| 86 | + return sctp_sched_prio_head_get(p); |
---|
89 | 87 | } |
---|
90 | 88 | |
---|
91 | 89 | /* If not even there, allocate a new one. */ |
---|
.. | .. |
---|
169 | 167 | struct sctp_stream_out_ext *soute = sout->ext; |
---|
170 | 168 | struct sctp_stream_priorities *prio_head, *old; |
---|
171 | 169 | bool reschedule = false; |
---|
172 | | - int i; |
---|
| 170 | + |
---|
| 171 | + old = soute->prio_head; |
---|
| 172 | + if (old && old->prio == prio) |
---|
| 173 | + return 0; |
---|
173 | 174 | |
---|
174 | 175 | prio_head = sctp_sched_prio_get_head(stream, prio, gfp); |
---|
175 | 176 | if (!prio_head) |
---|
176 | 177 | return -ENOMEM; |
---|
177 | 178 | |
---|
178 | 179 | reschedule = sctp_sched_prio_unsched(soute); |
---|
179 | | - old = soute->prio_head; |
---|
180 | 180 | soute->prio_head = prio_head; |
---|
181 | 181 | if (reschedule) |
---|
182 | 182 | sctp_sched_prio_sched(stream, soute); |
---|
183 | 183 | |
---|
184 | | - if (!old) |
---|
185 | | - /* Happens when we set the priority for the first time */ |
---|
186 | | - return 0; |
---|
187 | | - |
---|
188 | | - for (i = 0; i < stream->outcnt; i++) { |
---|
189 | | - soute = SCTP_SO(stream, i)->ext; |
---|
190 | | - if (soute && soute->prio_head == old) |
---|
191 | | - /* It's still in use, nothing else to do here. */ |
---|
192 | | - return 0; |
---|
193 | | - } |
---|
194 | | - |
---|
195 | | - /* No hits, we are good to free it. */ |
---|
196 | | - kfree(old); |
---|
197 | | - |
---|
| 184 | + sctp_sched_prio_head_put(old); |
---|
198 | 185 | return 0; |
---|
199 | 186 | } |
---|
200 | 187 | |
---|
.. | .. |
---|
217 | 204 | { |
---|
218 | 205 | INIT_LIST_HEAD(&SCTP_SO(stream, sid)->ext->prio_list); |
---|
219 | 206 | return sctp_sched_prio_set(stream, sid, 0, gfp); |
---|
| 207 | +} |
---|
| 208 | + |
---|
| 209 | +static void sctp_sched_prio_free_sid(struct sctp_stream *stream, __u16 sid) |
---|
| 210 | +{ |
---|
| 211 | + sctp_sched_prio_head_put(SCTP_SO(stream, sid)->ext->prio_head); |
---|
| 212 | + SCTP_SO(stream, sid)->ext->prio_head = NULL; |
---|
220 | 213 | } |
---|
221 | 214 | |
---|
222 | 215 | static void sctp_sched_prio_free(struct sctp_stream *stream) |
---|
.. | .. |
---|
338 | 331 | .get = sctp_sched_prio_get, |
---|
339 | 332 | .init = sctp_sched_prio_init, |
---|
340 | 333 | .init_sid = sctp_sched_prio_init_sid, |
---|
| 334 | + .free_sid = sctp_sched_prio_free_sid, |
---|
341 | 335 | .free = sctp_sched_prio_free, |
---|
342 | 336 | .enqueue = sctp_sched_prio_enqueue, |
---|
343 | 337 | .dequeue = sctp_sched_prio_dequeue, |
---|