From: Xin Long <lucien.xin@gmail.com>
To: Neil Horman <nhorman@tuxdriver.com>
Cc: network dev <netdev@vger.kernel.org>,
linux-sctp@vger.kernel.org, davem <davem@davemloft.net>,
Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Subject: Re: [PATCHv2 net] sctp: check and update stream->out_curr when allocating stream_out
Date: Fri, 30 Nov 2018 15:22:39 +0900 [thread overview]
Message-ID: <CADvbK_cJOBrSFumcEOtyKL0eBwYHFg__Ob37Z1H7Ty-sPow0dw@mail.gmail.com> (raw)
In-Reply-To: <20181129143855.GB14550@hmswarspite.think-freely.org>
On Thu, Nov 29, 2018 at 11:39 PM Neil Horman <nhorman@tuxdriver.com> wrote:
>
> On Thu, Nov 29, 2018 at 02:42:56PM +0800, Xin Long wrote:
> > Now when using stream reconfig to add out streams, stream->out
> > will get re-allocated, and all old streams' information will
> > be copied to the new ones and the old ones will be freed.
> >
> > So without stream->out_curr updated, next time when trying to
> > send from stream->out_curr stream, a panic would be caused.
> >
> > This patch is to check and update stream->out_curr when
> > allocating stream_out.
> >
> > v1->v2:
> > - define fa_index() to get elem index from stream->out_curr.
> >
> > Fixes: 5bbbbe32a431 ("sctp: introduce stream scheduler foundations")
> > Reported-by: Ying Xu <yinxu@redhat.com>
> > Reported-by: syzbot+e33a3a138267ca119c7d@syzkaller.appspotmail.com
> > Signed-off-by: Xin Long <lucien.xin@gmail.com>
> > ---
> > net/sctp/stream.c | 20 ++++++++++++++++++++
> > 1 file changed, 20 insertions(+)
> >
> > diff --git a/net/sctp/stream.c b/net/sctp/stream.c
> > index 3892e76..30e7809 100644
> > --- a/net/sctp/stream.c
> > +++ b/net/sctp/stream.c
> > @@ -84,6 +84,19 @@ static void fa_zero(struct flex_array *fa, size_t index, size_t count)
> > }
> > }
> >
> > +static size_t fa_index(struct flex_array *fa, void *elem, size_t count)
> > +{
> > + size_t index = 0;
> > +
> > + while (count--) {
> > + if (elem == flex_array_get(fa, index))
> > + break;
> > + index++;
> > + }
> > +
> > + return index;
> > +}
> > +
> > /* Migrates chunks from stream queues to new stream queues if needed,
> > * but not across associations. Also, removes those chunks to streams
> > * higher than the new max.
> > @@ -147,6 +160,13 @@ static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
> >
> > if (stream->out) {
> > fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt));
> > + if (stream->out_curr) {
> > + size_t index = fa_index(stream->out, stream->out_curr,
> > + stream->outcnt);
> > +
> > + BUG_ON(index == stream->outcnt);
> > + stream->out_curr = flex_array_get(out, index);
> > + }
> > fa_free(stream->out);
> > }
> >
> > --
> > 2.1.0
> >
> >
>
> This is the sort of thing I'm talking about. Its a little more code, but if you
> augment the flex_array api like this, you can preform a resize operation on your
> existing flex array, and you can avoid all the copying, and need to update
> pointers maintained outside the array. Note this code isn't tested at all, but
> its close to what I think should work.
>
>
> diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h
> index b94fa61b51fb..7fa1f27a91b5 100644
> --- a/include/linux/flex_array.h
> +++ b/include/linux/flex_array.h
> @@ -73,6 +73,8 @@ struct flex_array {
> struct flex_array *flex_array_alloc(int element_size, unsigned int total,
> gfp_t flags);
>
> +struct flex_array *flex_array_resize(struct flex_array *fa, unsigned int total, gfp_t flags);
> +
> /**
> * flex_array_prealloc() - Ensures that memory for the elements indexed in the
> * range defined by start and nr_elements has been allocated.
> diff --git a/lib/flex_array.c b/lib/flex_array.c
> index 2eed22fa507c..f8d54af3891b 100644
> --- a/lib/flex_array.c
> +++ b/lib/flex_array.c
> @@ -109,6 +109,7 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
> ret->total_nr_elements = total;
> ret->elems_per_part = elems_per_part;
> ret->reciprocal_elems = reciprocal_elems;
> + ret->elements_used = 0;
> if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO))
> memset(&ret->parts[0], FLEX_ARRAY_FREE,
> FLEX_ARRAY_BASE_BYTES_LEFT);
> @@ -116,6 +117,53 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
> }
> EXPORT_SYMBOL(flex_array_alloc);
>
> +static int flex_array_last_element_index(struct flex_array *fa)
> +{
> + struct flex_array_part *part;
> + int part_nr;
> + int i,j;
> +
> + if (elements_fit_in_base(fa)) {
> + part = (struct flex_array_part *)&fa->parts[0];
> + for (i = fa->elems_per_part; i >= 0; i--)
> + if (part->elements[i] != FLEX_ARRAY_FREE)
> + return i;
> + }
> +
> + i = fa->total_nr_elements;
> + for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) {
> + part = fa->parts[part_nr];
> + if (!part) {
> + i -= fa->elems_per_part;
> + continue;
> + }
> + for (j = fa->elems_per_part; j >= 0; j--, i--)
> + if (part->elements[j] != FLEX_ARRAY_FREE)
> + goto out;
> + }
> +out:
> + return i;
> +}
> +
> +struct flex_array *flex_array_resize(struct flex_array *fa, unsigned int total, gfp_t flags)
> +{
> + if (total >= fa->total_nr_elements) {
> + /* Grow case */
> + if (total > max_size)
> + return ERR_PTR(-ETOOBIG);
> + fa->total_nr_elements = total;
> + } else {
> + /* Shrink case */
> + /* Drop any pages we don't need*/
> + flex_array_shrink(fa);
> + if (flex_array_last_element_index(fa) >= total)
> + return ERR_PTR(-ESIZE);
> + fa->total_nr_elements = total;
> + }
> + return fa;
> +}
> +EXPORT_SYMBOL(flex_array_resize);
> +
> static int fa_element_to_part_nr(struct flex_array *fa,
> unsigned int element_nr)
> {
I have a question about how it checks one part is free in
flex_array_shrink():
part_is_free() is doing it by checking:
if (part->elements[all] == FLEX_ARRAY_FREE) ...
What if the data in the array that users put is FLEX_ARRAY_FREE,
it will be treated as free, but in fact it's still in use?
next prev parent reply other threads:[~2018-11-30 17:31 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-29 6:42 [PATCHv2 net] sctp: check and update stream->out_curr when allocating stream_out Xin Long
2018-11-29 12:49 ` Neil Horman
2018-11-29 14:31 ` Xin Long
2018-11-29 14:38 ` Neil Horman
2018-11-30 6:22 ` Xin Long [this message]
2018-11-30 12:20 ` Neil Horman
2018-11-30 13:48 ` Xin Long
2018-11-30 15:22 ` Neil Horman
2018-11-30 18:53 ` Xin Long
2018-11-30 19:35 ` Neil Horman
2018-11-30 19:40 ` Neil Horman
2019-01-29 12:05 ` Marcelo Ricardo Leitner
2019-01-29 18:58 ` Tuxdriver
2019-02-01 0:39 ` Marcelo Ricardo Leitner
2019-02-01 12:31 ` Neil Horman
2019-02-01 18:38 ` David Miller
2019-02-03 19:28 ` Xin Long
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CADvbK_cJOBrSFumcEOtyKL0eBwYHFg__Ob37Z1H7Ty-sPow0dw@mail.gmail.com \
--to=lucien.xin@gmail.com \
--cc=davem@davemloft.net \
--cc=linux-sctp@vger.kernel.org \
--cc=marcelo.leitner@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=nhorman@tuxdriver.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).