All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <jakub.kicinski@netronome.com>
To: Yonghong Song <yhs@fb.com>
Cc: "alexei.starovoitov@gmail.com" <alexei.starovoitov@gmail.com>,
	"daniel@iogearbox.net" <daniel@iogearbox.net>,
	"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"oss-drivers@netronome.com" <oss-drivers@netronome.com>
Subject: Re: [RFC bpf-next v4 03/12] bpf: verifier: remove dead code
Date: Wed, 2 Jan 2019 10:31:35 -0800	[thread overview]
Message-ID: <20190102103135.48ca5120@cakuba.hsd1.ca.comcast.net> (raw)
In-Reply-To: <d3ec87a6-9049-ee3e-d8f0-e55e40ba1104@fb.com>

On Wed, 2 Jan 2019 05:25:49 +0000, Yonghong Song wrote:
> On 12/31/18 5:37 PM, Jakub Kicinski wrote:
> > Instead of overwriting dead code with jmp -1 instructions
> > remove it completely for root.  Adjust verifier state and
> > line info appropriately.
> > 
> > v2:
> >   - adjust func_info (Alexei);
> >   - make sure first instruction retains line info (Alexei).
> > v4: (Yonghong)
> >   - remove unnecessary if (!insn to remove) checks;
> >   - always keep last line info if first live instruction lacks one.
> > 
> > Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>

> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 30e2cd399b4a..2f786acb65ce 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -6233,6 +6233,141 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
> >   	return new_prog;
> >   }
> >   
> > +static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,
> > +					      u32 off, u32 cnt)
> > +{
> > +	int i, j;
> > +
> > +	/* find first prog starting at or after off (first to remove) */
> > +	for (i = 0; i < env->subprog_cnt; i++)
> > +		if (env->subprog_info[i].start >= off)
> > +			break;
> > +	/* find first prog starting at or after off + cnt (first to stay) */
> > +	for (j = i; j < env->subprog_cnt; j++)
> > +		if (env->subprog_info[j].start >= off + cnt)
> > +			break;
> > +	/* if j doesn't start exactly at off + cnt, we are just removing
> > +	 * the front of previous prog
> > +	 */
> > +	if (env->subprog_info[j].start != off + cnt)
> > +		j--;  
> 
> It is possible that j = env->subprog_cnt here.
> 
> Looks like the following case is not properly covered:
> for
>     func1:
>       insn1
>       insn2
>     func2:
>       insn3
>       insn4
> 
>    case (1): insn3 removed
>    case (2): insn3 and insn4 removed, func2 subprog_info should be remeoved.
> 
> Maybe a change like below will work to include handling of the last subprog:
> 
> -       if (env->subprog_info[j].start != off + cnt)
> +       if ((j == env->subprog_cnt && env->prog->len > off) ||
> +           (j < env->subprog_cnt && env->subprog_info[j].start != off + cnt))
>                  j--;

As I think Ed alluded to there is another "exit" subprog at the
env->subprog_cnt index.  So accessing env->subprog_info[env->subprog_cnt]
is correct (which is quite handy).  test_verifier: "dead code: tail of
main + two functions" should cover this.  Would that make sense?

> > +static int bpf_adj_linfo_after_remove(struct bpf_verifier_env *env, u32 off,
> > +				      u32 cnt)
> > +{
> > +	struct bpf_prog *prog = env->prog;
> > +	u32 i, l_off, l_cnt, nr_linfo;
> > +	struct bpf_line_info *linfo;
> > +
> > +	nr_linfo = prog->aux->nr_linfo;
> > +	if (!nr_linfo)
> > +		return 0;
> > +
> > +	linfo = prog->aux->linfo;
> > +
> > +	/* find first line info to remove, count lines to be removed */
> > +	for (i = 0; i < nr_linfo; i++)
> > +		if (linfo[i].insn_off >= off)
> > +			break;
> > +
> > +	l_off = i;
> > +	l_cnt = 0;
> > +	for (; i < nr_linfo; i++)
> > +		if (linfo[i].insn_off < off + cnt)
> > +			l_cnt++;
> > +		else
> > +			break;
> > +
> > +	/* first live insn doesn't match first live linfo, inherit */
> > +	if (prog->len != off && l_cnt &&
> > +	    (i == nr_linfo || linfo[i].insn_off != off + cnt)) {
> > +		l_cnt--;
> > +		linfo[--i].insn_off = off + cnt;  
> 
> The same here. The handling the last line_info seems not sufficient.
> It depends on whether all insns covered by last linfo have been removed 
> or not.
> 
> Maybe something like below?
> +       if (l_cnt &&
> +           ((i == nr_linfo && prog->len > off) ||
> +            (i < nr_linfo && linfo[i].insn_off != off + cnt))) {
>                  l_cnt--;
>                  linfo[--i].insn_off = off + cnt;
> 
> Please double check whether my suggested fix is correct or not.
> You may want to add test cases to cover these cases as well.

Hm..  We only need to "inherit" the linfo, if the first instruction
after removed region doesn't have linfo.  So if there are no
instructions after the removed regions (we remove tail, off ==
prog->len) we can't possibly need to inherit.  No?  

I think your code is correct (because if there is no code there can't
be any linfo after, either) but I'm not sure why it would be necessary.

  parent reply	other threads:[~2019-01-02 18:31 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-01  1:37 [RFC bpf-next v4 00/12] bpf: dead code elimination Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 01/12] bpf: change parameters of call/branch offset adjustment Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 02/12] bpf: verifier: hard wire branches to dead code Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 03/12] bpf: verifier: remove " Jakub Kicinski
2019-01-02  5:25   ` Yonghong Song
2019-01-02 12:23     ` Edward Cree
2019-01-02 18:31     ` Jakub Kicinski [this message]
2019-01-02 18:57       ` Yonghong Song
2019-01-02 19:14         ` Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 04/12] bpf: verifier: remove unconditional branches by 0 Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 05/12] selftests: bpf: add tests for dead code removal Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 06/12] bpf: verifier: record original instruction index Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 07/12] bpf: notify offload JITs about optimizations Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 08/12] nfp: bpf: don't use instruction number for jump target Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 09/12] nfp: bpf: split up the skip flag Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 10/12] nfp: bpf: save original program length Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 11/12] nfp: bpf: support optimizing dead branches Jakub Kicinski
2019-01-01  1:37 ` [RFC bpf-next v4 12/12] nfp: bpf: support removing dead code Jakub Kicinski

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=20190102103135.48ca5120@cakuba.hsd1.ca.comcast.net \
    --to=jakub.kicinski@netronome.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=daniel@iogearbox.net \
    --cc=netdev@vger.kernel.org \
    --cc=oss-drivers@netronome.com \
    --cc=yhs@fb.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.