]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bpf: notify offload JITs about optimizations
authorJakub Kicinski <jakub.kicinski@netronome.com>
Wed, 23 Jan 2019 06:45:24 +0000 (22:45 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 24 Jan 2019 01:35:32 +0000 (17:35 -0800)
Let offload JITs know when instructions are replaced and optimized
out, so they can update their state appropriately.  The optimizations
are best effort, if JIT returns an error from any callback verifier
will stop notifying it as state may now be out of sync, but the
verifier continues making progress.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf.h
include/linux/bpf_verifier.h
kernel/bpf/offload.c
kernel/bpf/verifier.c

index e734f163bd0b9ae05c199fde7bd4e3dc1bfed542..3851529062ecb46f984715b5271234ee017b2829 100644 (file)
@@ -268,9 +268,15 @@ struct bpf_verifier_ops {
 };
 
 struct bpf_prog_offload_ops {
+       /* verifier basic callbacks */
        int (*insn_hook)(struct bpf_verifier_env *env,
                         int insn_idx, int prev_insn_idx);
        int (*finalize)(struct bpf_verifier_env *env);
+       /* verifier optimization callbacks (called after .finalize) */
+       int (*replace_insn)(struct bpf_verifier_env *env, u32 off,
+                           struct bpf_insn *insn);
+       int (*remove_insns)(struct bpf_verifier_env *env, u32 off, u32 cnt);
+       /* program management callbacks */
        int (*prepare)(struct bpf_prog *prog);
        int (*translate)(struct bpf_prog *prog);
        void (*destroy)(struct bpf_prog *prog);
@@ -283,6 +289,7 @@ struct bpf_prog_offload {
        void                    *dev_priv;
        struct list_head        offloads;
        bool                    dev_state;
+       bool                    opt_failed;
        void                    *jited_image;
        u32                     jited_len;
 };
index f3ae00ee5516e9d176f6f4c8a9faba8a01731952..0620e418dde5d48161d659c291839a0e93f93621 100644 (file)
@@ -266,5 +266,10 @@ int bpf_prog_offload_verifier_prep(struct bpf_prog *prog);
 int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env,
                                 int insn_idx, int prev_insn_idx);
 int bpf_prog_offload_finalize(struct bpf_verifier_env *env);
+void
+bpf_prog_offload_replace_insn(struct bpf_verifier_env *env, u32 off,
+                             struct bpf_insn *insn);
+void
+bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt);
 
 #endif /* _LINUX_BPF_VERIFIER_H */
index 54cf2b9c44a4570e8007848d1b530d367aefe64f..39dba8c9033128d75817307accd7b8d277637fc6 100644 (file)
@@ -173,6 +173,41 @@ int bpf_prog_offload_finalize(struct bpf_verifier_env *env)
        return ret;
 }
 
+void
+bpf_prog_offload_replace_insn(struct bpf_verifier_env *env, u32 off,
+                             struct bpf_insn *insn)
+{
+       const struct bpf_prog_offload_ops *ops;
+       struct bpf_prog_offload *offload;
+       int ret = -EOPNOTSUPP;
+
+       down_read(&bpf_devs_lock);
+       offload = env->prog->aux->offload;
+       if (offload) {
+               ops = offload->offdev->ops;
+               if (!offload->opt_failed && ops->replace_insn)
+                       ret = ops->replace_insn(env, off, insn);
+               offload->opt_failed |= ret;
+       }
+       up_read(&bpf_devs_lock);
+}
+
+void
+bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
+{
+       struct bpf_prog_offload *offload;
+       int ret = -EOPNOTSUPP;
+
+       down_read(&bpf_devs_lock);
+       offload = env->prog->aux->offload;
+       if (offload) {
+               if (!offload->opt_failed && offload->offdev->ops->remove_insns)
+                       ret = offload->offdev->ops->remove_insns(env, off, cnt);
+               offload->opt_failed |= ret;
+       }
+       up_read(&bpf_devs_lock);
+}
+
 static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
 {
        struct bpf_prog_offload *offload = prog->aux->offload;
index f2c49b4235df8d6bdb08ece70e27484cc501f055..8cfe39ef770f4c5447f62f6d691bfbd3eb6a3feb 100644 (file)
@@ -6558,6 +6558,9 @@ static int verifier_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
        unsigned int orig_prog_len = env->prog->len;
        int err;
 
+       if (bpf_prog_is_dev_bound(env->prog->aux))
+               bpf_prog_offload_remove_insns(env, off, cnt);
+
        err = bpf_remove_insns(env->prog, off, cnt);
        if (err)
                return err;
@@ -6632,6 +6635,9 @@ static void opt_hard_wire_dead_code_branches(struct bpf_verifier_env *env)
                else
                        continue;
 
+               if (bpf_prog_is_dev_bound(env->prog->aux))
+                       bpf_prog_offload_replace_insn(env, i, &ja);
+
                memcpy(insn, &ja, sizeof(ja));
        }
 }