Skip to content

bpf: BPF-driven proactive memcg reclaim - #8666

Open
kernel-patches-daemon-bpf-rc[bot] wants to merge 1 commit into
bpf-net_basefrom
series/1141976=>bpf-net
Open

bpf: BPF-driven proactive memcg reclaim#8666
kernel-patches-daemon-bpf-rc[bot] wants to merge 1 commit into
bpf-net_basefrom
series/1141976=>bpf-net

Conversation

@kernel-patches-daemon-bpf-rc

Copy link
Copy Markdown

Pull request for series with
subject: bpf: BPF-driven proactive memcg reclaim
version: 1
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=1141976

@kernel-patches-daemon-bpf-rc

Copy link
Copy Markdown
Author

Upstream branch: bfa3d89
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1141976
version: 1

Pull request is NOT updated. Failed to apply https://patchwork.kernel.org/project/netdevbpf/list/?series=1141976
error message:

Cmd('git') failed due to: exit code(128)
  cmdline: git am --3way
  stdout: 'Applying: mm/bpf: Add bpf_try_to_free_mem_cgroup_pages kfunc
Applying: bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement
Using index info to reconstruct a base tree...
M	include/linux/bpf.h
M	include/linux/cgroup.h
M	include/uapi/linux/bpf.h
M	kernel/bpf/btf.c
M	kernel/bpf/helpers.c
M	kernel/bpf/syscall.c
M	kernel/bpf/verifier.c
M	kernel/cgroup/cgroup.c
M	tools/testing/selftests/bpf/bpf_experimental.h
Falling back to patching base and 3-way merge...
Auto-merging include/linux/bpf.h
CONFLICT (content): Merge conflict in include/linux/bpf.h
Auto-merging include/linux/cgroup.h
Auto-merging include/uapi/linux/bpf.h
Auto-merging kernel/bpf/btf.c
Auto-merging kernel/bpf/helpers.c
Auto-merging kernel/bpf/syscall.c
CONFLICT (content): Merge conflict in kernel/bpf/syscall.c
Auto-merging kernel/bpf/verifier.c
CONFLICT (content): Merge conflict in kernel/bpf/verifier.c
Auto-merging kernel/cgroup/cgroup.c
Auto-merging tools/testing/selftests/bpf/bpf_experimental.h
Patch failed at 0002 bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement'
  stderr: 'error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"'

conflict:

diff --cc include/linux/bpf.h
index cd191c5fdb0a,d63ce8319869..000000000000
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@@ -488,6 -501,36 +497,39 @@@ static inline bool btf_record_has_field
  	return rec->field_mask & type;
  }
  
++<<<<<<< HEAD
++=======
+ static inline bool btf_field_is_nmi_safe(enum btf_field_type type)
+ {
+ 	switch (type) {
+ 	case BPF_SPIN_LOCK:
+ 	case BPF_RES_SPIN_LOCK:
+ 	case BPF_TIMER:
+ 	case BPF_WORKQUEUE:
+ 	case BPF_TASK_WORK:
+ 	case BPF_KPTR_UNREF:
+ 	case BPF_REFCOUNT:
+ 	case BPF_THREAD_WQ:
+ 		return true;
+ 	default:
+ 		return false;
+ 	}
+ }
+ 
+ static inline bool btf_record_has_nmi_unsafe_fields(const struct btf_record *rec)
+ {
+ 	int i;
+ 
+ 	if (IS_ERR_OR_NULL(rec))
+ 		return false;
+ 	for (i = 0; i < rec->cnt; i++) {
+ 		if (!btf_field_is_nmi_safe(rec->fields[i].type))
+ 			return true;
+ 	}
+ 	return false;
+ }
+ 
++>>>>>>> bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement
  static inline void bpf_obj_init(const struct btf_record *rec, void *obj)
  {
  	int i;
@@@ -2595,6 -2737,8 +2639,11 @@@ bool btf_record_equal(const struct btf_
  void bpf_obj_free_timer(const struct btf_record *rec, void *obj);
  void bpf_obj_free_workqueue(const struct btf_record *rec, void *obj);
  void bpf_obj_free_task_work(const struct btf_record *rec, void *obj);
++<<<<<<< HEAD
++=======
+ void bpf_obj_free_thread_wq(const struct btf_record *rec, void *obj);
+ void bpf_obj_cancel_fields(struct bpf_map *map, void *obj);
++>>>>>>> bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement
  void bpf_obj_free_fields(const struct btf_record *rec, void *obj);
  void __bpf_obj_drop_impl(void *p, const struct btf_record *rec, bool percpu);
  
diff --cc kernel/bpf/syscall.c
index 630d530782fe,dea14823bacd..000000000000
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@@ -807,6 -809,18 +809,21 @@@ void bpf_obj_free_task_work(const struc
  	bpf_task_work_cancel_and_free(obj + rec->task_work_off);
  }
  
++<<<<<<< HEAD
++=======
+ void bpf_obj_free_thread_wq(const struct btf_record *rec, void *obj)
+ {
+ 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_THREAD_WQ)))
+ 		return;
+ 	bpf_thread_wq_cancel_and_free(obj + rec->thread_wq_off);
+ }
+ 
+ void bpf_obj_cancel_fields(struct bpf_map *map, void *obj)
+ {
+ 	bpf_map_free_internal_structs(map, obj);
+ }
+ 
++>>>>>>> bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement
  void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
  {
  	const struct btf_field *fields;
@@@ -1293,7 -1311,9 +1313,8 @@@ static int map_check_btf(struct bpf_ma
  			case BPF_TIMER:
  			case BPF_WORKQUEUE:
  			case BPF_TASK_WORK:
+ 			case BPF_THREAD_WQ:
  				if (map->map_type != BPF_MAP_TYPE_HASH &&
 -				    map->map_type != BPF_MAP_TYPE_RHASH &&
  				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
  				    map->map_type != BPF_MAP_TYPE_ARRAY) {
  					ret = -EOPNOTSUPP;
diff --cc kernel/bpf/verifier.c
index 7fb88e1cd7c4,4d713bb767e0..000000000000
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@@ -1830,32 -1858,37 +1833,64 @@@ static void __mark_dynptr_reg(struct bp
  	reg->dynptr.first_slot = first_slot;
  }
  
++<<<<<<< HEAD
++=======
+ /*
+  * Refine the return type of the bpf_map_lookup_elem() for special map types:
+  * map-in-map, xskmap, sockmap and sockhash.
+  */
+ static void refine_map_lookup_value(struct bpf_reg_state *reg)
+ {
+ 	enum bpf_type_flag maybe_null = reg->type & PTR_MAYBE_NULL;
+ 	const struct bpf_map *map = reg->map_ptr;
+ 
+ 	if (map->inner_map_meta) {
+ 		reg->type = CONST_PTR_TO_MAP | maybe_null;
+ 		reg->map_ptr = map->inner_map_meta;
+ 		/* transfer reg's id which is unique for every map_lookup_elem
+ 		 * as UID of the inner map.
+ 		 */
+ 		if (btf_record_has_field(map->inner_map_meta->record,
+ 					 BPF_TIMER |
+ 					 BPF_WORKQUEUE |
+ 					 BPF_TASK_WORK |
+ 					 BPF_THREAD_WQ))
+ 			reg->map_uid = reg->id;
+ 	} else if (map->map_type == BPF_MAP_TYPE_XSKMAP) {
+ 		reg->type = PTR_TO_XDP_SOCK | maybe_null;
+ 	} else if (map->map_type == BPF_MAP_TYPE_SOCKMAP ||
+ 		   map->map_type == BPF_MAP_TYPE_SOCKHASH) {
+ 		reg->type = PTR_TO_SOCKET | maybe_null;
+ 	}
+ }
+ 
++>>>>>>> bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement
  static void mark_ptr_not_null_reg(struct bpf_reg_state *reg)
  {
 +	if (base_type(reg->type) == PTR_TO_MAP_VALUE) {
 +		const struct bpf_map *map = reg->map_ptr;
 +
 +		if (map->inner_map_meta) {
 +			reg->type = CONST_PTR_TO_MAP;
 +			reg->map_ptr = map->inner_map_meta;
 +			/* transfer reg's id which is unique for every map_lookup_elem
 +			 * as UID of the inner map.
 +			 */
 +			if (btf_record_has_field(map->inner_map_meta->record,
 +						 BPF_TIMER | BPF_WORKQUEUE | BPF_TASK_WORK)) {
 +				reg->map_uid = reg->id;
 +			}
 +		} else if (map->map_type == BPF_MAP_TYPE_XSKMAP) {
 +			reg->type = PTR_TO_XDP_SOCK;
 +		} else if (map->map_type == BPF_MAP_TYPE_SOCKMAP ||
 +			   map->map_type == BPF_MAP_TYPE_SOCKHASH) {
 +			reg->type = PTR_TO_SOCKET;
 +		} else {
 +			reg->type = PTR_TO_MAP_VALUE;
 +		}
 +		return;
 +	}
 +
  	reg->type &= ~PTR_MAYBE_NULL;
  }
  
@@@ -11394,82 -11445,117 +11442,134 @@@ get_kfunc_ptr_arg_type(struct bpf_verif
  	 * type to our caller. When a set of conditions hold in the BTF type of
  	 * arguments, we resolve it to a known kfunc_ptr_arg_type.
  	 */
++<<<<<<< HEAD
 +	if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno))
 +		return KF_ARG_PTR_TO_CTX;
 +
 +	if (is_kfunc_arg_nullable(meta->btf, &args[argno]) && bpf_register_is_null(reg) &&
 +	    !arg_mem_size)
 +		return KF_ARG_PTR_TO_NULL;
 +
 +	if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_ALLOC_BTF_ID;
 +
 +	if (is_kfunc_arg_refcounted_kptr(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_REFCOUNTED_KPTR;
 +
 +	if (is_kfunc_arg_dynptr(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_DYNPTR;
 +
 +	if (is_kfunc_arg_iter(meta, argno, &args[argno]))
 +		return KF_ARG_PTR_TO_ITER;
 +
 +	if (is_kfunc_arg_list_head(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_LIST_HEAD;
 +
 +	if (is_kfunc_arg_list_node(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_LIST_NODE;
 +
 +	if (is_kfunc_arg_rbtree_root(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_RB_ROOT;
 +
 +	if (is_kfunc_arg_rbtree_node(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_RB_NODE;
 +
 +	if (is_kfunc_arg_const_str(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_CONST_STR;
 +
 +	if (is_kfunc_arg_map(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_MAP;
 +
 +	if (is_kfunc_arg_wq(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_WORKQUEUE;
 +
 +	if (is_kfunc_arg_timer(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_TIMER;
 +
 +	if (is_kfunc_arg_task_work(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_TASK_WORK;
 +
 +	if (is_kfunc_arg_irq_flag(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_IRQ_FLAG;
 +
 +	if (is_kfunc_arg_res_spin_lock(meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_RES_SPIN_LOCK;
 +
 +	if ((base_type(reg->type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(reg->type)])) {
 +		if (!btf_type_is_struct(ref_t)) {
 +			verbose(env, "kernel function %s args#%d pointer type %s %s is not supported\n",
 +				meta->func_name, argno, btf_type_str(ref_t), ref_tname);
++=======
+ 	if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
+ 	    meta->func_id == special_kfunc_list[KF_bpf_session_is_return] ||
+ 	    meta->func_id == special_kfunc_list[KF_bpf_session_cookie])
+ 		arg_type = KF_ARG_PTR_TO_CTX;
+ 	else if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), arg))
+ 		arg_type = KF_ARG_PTR_TO_CTX;
+ 	else if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_ALLOC_BTF_ID;
+ 	else if (is_kfunc_arg_refcounted_kptr(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_REFCOUNTED_KPTR;
+ 	else if (is_kfunc_arg_dynptr(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_DYNPTR;
+ 	else if (is_kfunc_arg_iter(meta, arg, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_ITER;
+ 	else if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_LIST_HEAD;
+ 	else if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_LIST_NODE;
+ 	else if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_RB_ROOT;
+ 	else if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_RB_NODE;
+ 	else if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_CONST_STR;
+ 	else if (is_kfunc_arg_const_map(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_CONST_MAP_PTR;
+ 	else if (is_kfunc_arg_map(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_BTF_ID;
+ 	else if (is_kfunc_arg_wq(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_WORKQUEUE;
+ 	else if (is_kfunc_arg_timer(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_TIMER;
+ 	else if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_TASK_WORK;
+ 	else if (is_kfunc_arg_thread_wq(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_THREAD_WQ;
+ 	else if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_IRQ_FLAG;
+ 	else if (is_kfunc_arg_res_spin_lock(meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_RES_SPIN_LOCK;
+ 	else if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
+ 		arg_type = KF_ARG_PTR_TO_CALLBACK;
+ 	else if (arg + 1 < nargs &&
+ 		 (is_kfunc_arg_mem_size(meta->btf, &args[arg + 1]) ||
+ 		  is_kfunc_arg_const_mem_size(meta->btf, &args[arg + 1]))) {
+ 		if (!btf_type_is_void(ref_t) && !btf_type_is_scalar(ref_t) &&
+ 		    !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0)) {
+ 			verbose(env, "%s pointer type %s %s must point to void, scalar, or struct with scalar\n",
+ 				reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
++>>>>>>> bpf: add bpf_thread_wq kthread-backed workqueue with cgroup placement
  			return -EINVAL;
  		}
 -		arg_type = KF_ARG_PTR_TO_MEM;
 -	} else if (btf_type_is_struct(ref_t))
 -		/* A pointer to a struct without a size argument is classified as KF_ARG_PTR_TO_BTF_ID */
 -		arg_type = KF_ARG_PTR_TO_BTF_ID;
 -	else {
 -		/*
 -		 * Otherwise this is a fixed-size memory buffer supported by
 -		 * check_helper_mem_access(): a pointer to a scalar or a struct of
 -		 * scalars. The access size is derived from the pointed-to BTF type.
 -		 */
 -		if (!btf_type_is_scalar(ref_t) &&
 -		    !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0)) {
 -			verbose(env, "%s pointer type %s %s must point to scalar, or struct with scalar\n",
 -				reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
 -			return -EINVAL;
 -		}
 -		arg_type = KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
 +		return KF_ARG_PTR_TO_BTF_ID;
  	}
  
 -	if (is_kfunc_arg_nullable(meta->btf, &args[arg]))
 -		arg_type |= PTR_MAYBE_NULL;
 -
 -	return arg_type;
 -}
 -
 -static int gen_kfunc_arg_proto(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
 -			       struct bpf_func_proto *proto)
 -{
 -	const struct btf *btf = meta->btf;
 -	const struct btf_param *args;
 -	u32 i, nargs;
 -	int arg_type;
 +	if (is_kfunc_arg_callback(env, meta->btf, &args[argno]))
 +		return KF_ARG_PTR_TO_CALLBACK;
  
 -	args = (const struct btf_param *)(meta->func_proto + 1);
 -	nargs = btf_type_vlen(meta->func_proto);
 -	if (nargs > MAX_BPF_FUNC_ARGS) {
 -		verbose(env, "Function %s has %d > %d args\n", meta->func_name,
 -			nargs, MAX_BPF_FUNC_ARGS);
 +	/* This is the catch all argument type of register types supported by
 +	 * check_helper_mem_access. However, we only allow when argument type is
 +	 * pointer to scalar, or struct composed (recursively) of scalars. When
 +	 * arg_mem_size is true, the pointer can be void *.
 +	 */
 +	if (!btf_type_is_scalar(ref_t) && !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0) &&
 +	    (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
 +		verbose(env, "arg#%d pointer type %s %s must point to %sscalar, or struct with scalar\n",
 +			argno, btf_type_str(ref_t), ref_tname, arg_mem_size ? "void, " : "");
  		return -EINVAL;
  	}
 -	if (nargs > MAX_BPF_FUNC_REG_ARGS && !bpf_jit_supports_stack_args()) {
 -		verbose(env, "JIT does not support kfunc %s() with %d args\n",
 -			meta->func_name, nargs);
 -		return -ENOTSUPP;
 -	}
 -
 -	for (i = 0; i < nargs; i++) {
 -		if (is_kfunc_arg_prog_aux(btf, &args[i]) ||
 -		    is_kfunc_arg_ignore(btf, &args[i]) ||
 -		    is_kfunc_arg_implicit(meta, i))
 -			continue;
 -
 -		arg_type = get_kfunc_arg_type(env, meta, args, i, nargs);
 -		if (arg_type < 0)
 -			return arg_type;
 -
 -		proto->arg_type[i] = arg_type;
 -	}
 -
 -	return 0;
 +	return arg_mem_size ? KF_ARG_PTR_TO_MEM_SIZE : KF_ARG_PTR_TO_MEM;
  }
  
  static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants