| .. | .. |
|---|
| 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, |
|---|