Re: [PATCH bpf-next 06/11] libbpf: add per-program log buffer setter and getter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Dec 05, 2021 at 12:32:29PM -0800, Andrii Nakryiko wrote:
>  
> +	ret = bpf_prog_load(prog->type, prog_name, license, insns, insns_cnt, &load_attr);
>  	if (ret >= 0) {
> -		if (log_buf && load_attr.log_level) {
> +		if (log_level && own_log_buf) {
>  			pr_debug("prog '%s': -- BEGIN PROG LOAD LOG --\n%s-- END PROG LOAD LOG --\n",
>  				 prog->name, log_buf);
>  		}
> @@ -6690,19 +6720,20 @@ static int bpf_object_load_prog_instance(struct bpf_object *obj, struct bpf_prog
>  		goto out;
>  	}
>  
> -	if (!log_buf || errno == ENOSPC) {
> -		log_buf_size = max((size_t)BPF_LOG_BUF_SIZE,
> -				   log_buf_size << 1);
> -		free(log_buf);
> +	if (log_level == 0) {
> +		log_level = 1;
>  		goto retry_load;
>  	}

I think the new log_level semantics makes sense,
but can we do it only in one layer?
The above piece of bpf_object_load_prog_instance() will change log_level,
but then bpf_prog_load_v0_6_0() will do it again
when log_buf != NULL.
The latter will not malloc log_buf, but the former will.
Though both change log_level.
Can we somehow unify this logic and only do log_level adjustment and log_buf
alloc in bpf_object_load_prog_instance() only ?

> +	/* on ENOSPC, increase log buffer size, unless custom log_buf is specified */
> +	if (own_log_buf && errno == ENOSPC && log_buf_size < UINT_MAX / 2)
> +		goto retry_load;

The kernel allows buf_size <= UINT_MAX >> 2.
Above condition will probably get to the same value, but it's not obvious.
Maybe make it exactly as kernel?

> -	if (log_buf && log_buf[0] != '\0') {
> +	if (own_log_buf && log_buf && log_buf[0] != '\0') {
>  		pr_warn("prog '%s': -- BEGIN PROG LOAD LOG --\n%s-- END PROG LOAD LOG --\n",
>  			prog->name, log_buf);
>  	}
> @@ -6712,7 +6743,8 @@ static int bpf_object_load_prog_instance(struct bpf_object *obj, struct bpf_prog
>  	}
>  
>  out:
> -	free(log_buf);
> +	if (own_log_buf)
> +		free(log_buf);

For lksel I'm thinking to pass allocated log_buf back.
lskel has no ability to printf from inside of it, so log_buf has to be passed back.
I wonder whether it would make sense for libbpf as well?
The own_log_buf flag can be kept in bpf_program and caller can
examine the log_buf instead of doing bpf_program__set_log_buf() below...

> +int bpf_program__set_log_buf(struct bpf_program *prog, char *log_buf, size_t log_size)
> +{
> +	if (log_size && !log_buf)
> +		return -EINVAL;
> +	if (prog->log_size > UINT_MAX)
> +		return -EINVAL;
> +	if (prog->obj->loaded)
> +		return -EBUSY;
> +
> +	prog->log_buf = log_buf;
> +	prog->log_size = log_size;
> +	return 0;
> +}

The problem with this helper is that the user would have to malloc
always even though the prog might load just fine.
But there is a chance of load failure even in production,
so the user would have to rely on libbpf printfs and override print func
or do prog_load without bpf_program__set_log_buf() and then do it again on error
or always do bpf_program__set_log_buf() with giant malloc.
All of these 3 options are not that great.
The 4th option is for libbpf to do a malloc in case of error and return it.
That's the most convenient:
err = ...prog_load(..)
if (err) // user will check what's in the log.
No need to override libbpf print, unconditionally allocated or do double load.



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux