diff options
Diffstat (limited to 'arch/x86/net/bpf_jit_comp.c')
| -rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 18 | 
1 files changed, 14 insertions, 4 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index b725154182cc..263c8453815e 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1027,7 +1027,17 @@ emit_cond_jmp:		/* convert BPF opcode to x86 */  			break;  		case BPF_JMP | BPF_JA: -			jmp_offset = addrs[i + insn->off] - addrs[i]; +			if (insn->off == -1) +				/* -1 jmp instructions will always jump +				 * backwards two bytes. Explicitly handling +				 * this case avoids wasting too many passes +				 * when there are long sequences of replaced +				 * dead code. +				 */ +				jmp_offset = -2; +			else +				jmp_offset = addrs[i + insn->off] - addrs[i]; +  			if (!jmp_offset)  				/* optimize out nop jumps */  				break; @@ -1226,6 +1236,7 @@ skip_init_addrs:  	for (pass = 0; pass < 20 || image; pass++) {  		proglen = do_jit(prog, addrs, image, oldproglen, &ctx);  		if (proglen <= 0) { +out_image:  			image = NULL;  			if (header)  				bpf_jit_binary_free(header); @@ -1236,8 +1247,7 @@ skip_init_addrs:  			if (proglen != oldproglen) {  				pr_err("bpf_jit: proglen=%d != oldproglen=%d\n",  				       proglen, oldproglen); -				prog = orig_prog; -				goto out_addrs; +				goto out_image;  			}  			break;  		} @@ -1273,7 +1283,7 @@ skip_init_addrs:  		prog = orig_prog;  	} -	if (!prog->is_func || extra_pass) { +	if (!image || !prog->is_func || extra_pass) {  out_addrs:  		kfree(addrs);  		kfree(jit_data);  |