Merge tag 'v5.8-rc7' into perf/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -3746,7 +3746,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
|
||||
return false;
|
||||
|
||||
t = btf_type_skip_modifiers(btf, t->type, NULL);
|
||||
if (!btf_type_is_int(t)) {
|
||||
if (!btf_type_is_small_int(t)) {
|
||||
bpf_log(log,
|
||||
"ret type %s not allowed for fmod_ret\n",
|
||||
btf_kind_str[BTF_INFO_KIND(t->info)]);
|
||||
@@ -3768,7 +3768,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
|
||||
/* skip modifiers */
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
if (btf_type_is_int(t) || btf_type_is_enum(t))
|
||||
if (btf_type_is_small_int(t) || btf_type_is_enum(t))
|
||||
/* accessing a scalar */
|
||||
return true;
|
||||
if (!btf_type_is_ptr(t)) {
|
||||
|
@@ -19,18 +19,21 @@ struct bpf_netns_link {
|
||||
* with netns_bpf_mutex held.
|
||||
*/
|
||||
struct net *net;
|
||||
struct list_head node; /* node in list of links attached to net */
|
||||
};
|
||||
|
||||
/* Protects updates to netns_bpf */
|
||||
DEFINE_MUTEX(netns_bpf_mutex);
|
||||
|
||||
/* Must be called with netns_bpf_mutex held. */
|
||||
static void __net_exit bpf_netns_link_auto_detach(struct bpf_link *link)
|
||||
static void netns_bpf_run_array_detach(struct net *net,
|
||||
enum netns_bpf_attach_type type)
|
||||
{
|
||||
struct bpf_netns_link *net_link =
|
||||
container_of(link, struct bpf_netns_link, link);
|
||||
struct bpf_prog_array *run_array;
|
||||
|
||||
net_link->net = NULL;
|
||||
run_array = rcu_replace_pointer(net->bpf.run_array[type], NULL,
|
||||
lockdep_is_held(&netns_bpf_mutex));
|
||||
bpf_prog_array_free(run_array);
|
||||
}
|
||||
|
||||
static void bpf_netns_link_release(struct bpf_link *link)
|
||||
@@ -40,22 +43,18 @@ static void bpf_netns_link_release(struct bpf_link *link)
|
||||
enum netns_bpf_attach_type type = net_link->netns_type;
|
||||
struct net *net;
|
||||
|
||||
/* Link auto-detached by dying netns. */
|
||||
if (!net_link->net)
|
||||
return;
|
||||
|
||||
mutex_lock(&netns_bpf_mutex);
|
||||
|
||||
/* Recheck after potential sleep. We can race with cleanup_net
|
||||
* here, but if we see a non-NULL struct net pointer pre_exit
|
||||
* has not happened yet and will block on netns_bpf_mutex.
|
||||
/* We can race with cleanup_net, but if we see a non-NULL
|
||||
* struct net pointer, pre_exit has not run yet and wait for
|
||||
* netns_bpf_mutex.
|
||||
*/
|
||||
net = net_link->net;
|
||||
if (!net)
|
||||
goto out_unlock;
|
||||
|
||||
net->bpf.links[type] = NULL;
|
||||
RCU_INIT_POINTER(net->bpf.progs[type], NULL);
|
||||
netns_bpf_run_array_detach(net, type);
|
||||
list_del(&net_link->node);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&netns_bpf_mutex);
|
||||
@@ -76,6 +75,7 @@ static int bpf_netns_link_update_prog(struct bpf_link *link,
|
||||
struct bpf_netns_link *net_link =
|
||||
container_of(link, struct bpf_netns_link, link);
|
||||
enum netns_bpf_attach_type type = net_link->netns_type;
|
||||
struct bpf_prog_array *run_array;
|
||||
struct net *net;
|
||||
int ret = 0;
|
||||
|
||||
@@ -93,8 +93,11 @@ static int bpf_netns_link_update_prog(struct bpf_link *link,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
run_array = rcu_dereference_protected(net->bpf.run_array[type],
|
||||
lockdep_is_held(&netns_bpf_mutex));
|
||||
WRITE_ONCE(run_array->items[0].prog, new_prog);
|
||||
|
||||
old_prog = xchg(&link->prog, new_prog);
|
||||
rcu_assign_pointer(net->bpf.progs[type], new_prog);
|
||||
bpf_prog_put(old_prog);
|
||||
|
||||
out_unlock:
|
||||
@@ -142,14 +145,38 @@ static const struct bpf_link_ops bpf_netns_link_ops = {
|
||||
.show_fdinfo = bpf_netns_link_show_fdinfo,
|
||||
};
|
||||
|
||||
/* Must be called with netns_bpf_mutex held. */
|
||||
static int __netns_bpf_prog_query(const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr,
|
||||
struct net *net,
|
||||
enum netns_bpf_attach_type type)
|
||||
{
|
||||
__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
|
||||
struct bpf_prog_array *run_array;
|
||||
u32 prog_cnt = 0, flags = 0;
|
||||
|
||||
run_array = rcu_dereference_protected(net->bpf.run_array[type],
|
||||
lockdep_is_held(&netns_bpf_mutex));
|
||||
if (run_array)
|
||||
prog_cnt = bpf_prog_array_length(run_array);
|
||||
|
||||
if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(&uattr->query.prog_cnt, &prog_cnt, sizeof(prog_cnt)))
|
||||
return -EFAULT;
|
||||
if (!attr->query.prog_cnt || !prog_ids || !prog_cnt)
|
||||
return 0;
|
||||
|
||||
return bpf_prog_array_copy_to_user(run_array, prog_ids,
|
||||
attr->query.prog_cnt);
|
||||
}
|
||||
|
||||
int netns_bpf_prog_query(const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
|
||||
u32 prog_id, prog_cnt = 0, flags = 0;
|
||||
enum netns_bpf_attach_type type;
|
||||
struct bpf_prog *attached;
|
||||
struct net *net;
|
||||
int ret;
|
||||
|
||||
if (attr->query.query_flags)
|
||||
return -EINVAL;
|
||||
@@ -162,36 +189,25 @@ int netns_bpf_prog_query(const union bpf_attr *attr,
|
||||
if (IS_ERR(net))
|
||||
return PTR_ERR(net);
|
||||
|
||||
rcu_read_lock();
|
||||
attached = rcu_dereference(net->bpf.progs[type]);
|
||||
if (attached) {
|
||||
prog_cnt = 1;
|
||||
prog_id = attached->aux->id;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
mutex_lock(&netns_bpf_mutex);
|
||||
ret = __netns_bpf_prog_query(attr, uattr, net, type);
|
||||
mutex_unlock(&netns_bpf_mutex);
|
||||
|
||||
put_net(net);
|
||||
|
||||
if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(&uattr->query.prog_cnt, &prog_cnt, sizeof(prog_cnt)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!attr->query.prog_cnt || !prog_ids || !prog_cnt)
|
||||
return 0;
|
||||
|
||||
if (copy_to_user(prog_ids, &prog_id, sizeof(u32)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_prog_array *run_array;
|
||||
enum netns_bpf_attach_type type;
|
||||
struct bpf_prog *attached;
|
||||
struct net *net;
|
||||
int ret;
|
||||
|
||||
if (attr->target_fd || attr->attach_flags || attr->replace_bpf_fd)
|
||||
return -EINVAL;
|
||||
|
||||
type = to_netns_bpf_attach_type(attr->attach_type);
|
||||
if (type < 0)
|
||||
return -EINVAL;
|
||||
@@ -200,19 +216,47 @@ int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
|
||||
mutex_lock(&netns_bpf_mutex);
|
||||
|
||||
/* Attaching prog directly is not compatible with links */
|
||||
if (net->bpf.links[type]) {
|
||||
if (!list_empty(&net->bpf.links[type])) {
|
||||
ret = -EEXIST;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NETNS_BPF_FLOW_DISSECTOR:
|
||||
ret = flow_dissector_bpf_prog_attach(net, prog);
|
||||
ret = flow_dissector_bpf_prog_attach_check(net, prog);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
attached = net->bpf.progs[type];
|
||||
if (attached == prog) {
|
||||
/* The same program cannot be attached twice */
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
run_array = rcu_dereference_protected(net->bpf.run_array[type],
|
||||
lockdep_is_held(&netns_bpf_mutex));
|
||||
if (run_array) {
|
||||
WRITE_ONCE(run_array->items[0].prog, prog);
|
||||
} else {
|
||||
run_array = bpf_prog_array_alloc(1, GFP_KERNEL);
|
||||
if (!run_array) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
run_array->items[0].prog = prog;
|
||||
rcu_assign_pointer(net->bpf.run_array[type], run_array);
|
||||
}
|
||||
|
||||
net->bpf.progs[type] = prog;
|
||||
if (attached)
|
||||
bpf_prog_put(attached);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&netns_bpf_mutex);
|
||||
|
||||
@@ -221,63 +265,74 @@ out_unlock:
|
||||
|
||||
/* Must be called with netns_bpf_mutex held. */
|
||||
static int __netns_bpf_prog_detach(struct net *net,
|
||||
enum netns_bpf_attach_type type)
|
||||
enum netns_bpf_attach_type type,
|
||||
struct bpf_prog *old)
|
||||
{
|
||||
struct bpf_prog *attached;
|
||||
|
||||
/* Progs attached via links cannot be detached */
|
||||
if (net->bpf.links[type])
|
||||
if (!list_empty(&net->bpf.links[type]))
|
||||
return -EINVAL;
|
||||
|
||||
attached = rcu_dereference_protected(net->bpf.progs[type],
|
||||
lockdep_is_held(&netns_bpf_mutex));
|
||||
if (!attached)
|
||||
attached = net->bpf.progs[type];
|
||||
if (!attached || attached != old)
|
||||
return -ENOENT;
|
||||
RCU_INIT_POINTER(net->bpf.progs[type], NULL);
|
||||
netns_bpf_run_array_detach(net, type);
|
||||
net->bpf.progs[type] = NULL;
|
||||
bpf_prog_put(attached);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netns_bpf_prog_detach(const union bpf_attr *attr)
|
||||
int netns_bpf_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype)
|
||||
{
|
||||
enum netns_bpf_attach_type type;
|
||||
struct bpf_prog *prog;
|
||||
int ret;
|
||||
|
||||
if (attr->target_fd)
|
||||
return -EINVAL;
|
||||
|
||||
type = to_netns_bpf_attach_type(attr->attach_type);
|
||||
if (type < 0)
|
||||
return -EINVAL;
|
||||
|
||||
prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
|
||||
if (IS_ERR(prog))
|
||||
return PTR_ERR(prog);
|
||||
|
||||
mutex_lock(&netns_bpf_mutex);
|
||||
ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type);
|
||||
ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type, prog);
|
||||
mutex_unlock(&netns_bpf_mutex);
|
||||
|
||||
bpf_prog_put(prog);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int netns_bpf_link_attach(struct net *net, struct bpf_link *link,
|
||||
enum netns_bpf_attach_type type)
|
||||
{
|
||||
struct bpf_prog *prog;
|
||||
struct bpf_netns_link *net_link =
|
||||
container_of(link, struct bpf_netns_link, link);
|
||||
struct bpf_prog_array *run_array;
|
||||
int err;
|
||||
|
||||
mutex_lock(&netns_bpf_mutex);
|
||||
|
||||
/* Allow attaching only one prog or link for now */
|
||||
if (net->bpf.links[type]) {
|
||||
if (!list_empty(&net->bpf.links[type])) {
|
||||
err = -E2BIG;
|
||||
goto out_unlock;
|
||||
}
|
||||
/* Links are not compatible with attaching prog directly */
|
||||
prog = rcu_dereference_protected(net->bpf.progs[type],
|
||||
lockdep_is_held(&netns_bpf_mutex));
|
||||
if (prog) {
|
||||
if (net->bpf.progs[type]) {
|
||||
err = -EEXIST;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NETNS_BPF_FLOW_DISSECTOR:
|
||||
err = flow_dissector_bpf_prog_attach(net, link->prog);
|
||||
err = flow_dissector_bpf_prog_attach_check(net, link->prog);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
@@ -286,7 +341,15 @@ static int netns_bpf_link_attach(struct net *net, struct bpf_link *link,
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
net->bpf.links[type] = link;
|
||||
run_array = bpf_prog_array_alloc(1, GFP_KERNEL);
|
||||
if (!run_array) {
|
||||
err = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
run_array->items[0].prog = link->prog;
|
||||
rcu_assign_pointer(net->bpf.run_array[type], run_array);
|
||||
|
||||
list_add_tail(&net_link->node, &net->bpf.links[type]);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&netns_bpf_mutex);
|
||||
@@ -345,23 +408,34 @@ out_put_net:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __net_init netns_bpf_pernet_init(struct net *net)
|
||||
{
|
||||
int type;
|
||||
|
||||
for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++)
|
||||
INIT_LIST_HEAD(&net->bpf.links[type]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __net_exit netns_bpf_pernet_pre_exit(struct net *net)
|
||||
{
|
||||
enum netns_bpf_attach_type type;
|
||||
struct bpf_link *link;
|
||||
struct bpf_netns_link *net_link;
|
||||
|
||||
mutex_lock(&netns_bpf_mutex);
|
||||
for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) {
|
||||
link = net->bpf.links[type];
|
||||
if (link)
|
||||
bpf_netns_link_auto_detach(link);
|
||||
else
|
||||
__netns_bpf_prog_detach(net, type);
|
||||
netns_bpf_run_array_detach(net, type);
|
||||
list_for_each_entry(net_link, &net->bpf.links[type], node)
|
||||
net_link->net = NULL; /* auto-detach link */
|
||||
if (net->bpf.progs[type])
|
||||
bpf_prog_put(net->bpf.progs[type]);
|
||||
}
|
||||
mutex_unlock(&netns_bpf_mutex);
|
||||
}
|
||||
|
||||
static struct pernet_operations netns_bpf_pernet_ops __net_initdata = {
|
||||
.init = netns_bpf_pernet_init,
|
||||
.pre_exit = netns_bpf_pernet_pre_exit,
|
||||
};
|
||||
|
||||
|
@@ -20,11 +20,14 @@ static struct reuseport_array *reuseport_array(struct bpf_map *map)
|
||||
/* The caller must hold the reuseport_lock */
|
||||
void bpf_sk_reuseport_detach(struct sock *sk)
|
||||
{
|
||||
struct sock __rcu **socks;
|
||||
uintptr_t sk_user_data;
|
||||
|
||||
write_lock_bh(&sk->sk_callback_lock);
|
||||
socks = sk->sk_user_data;
|
||||
if (socks) {
|
||||
sk_user_data = (uintptr_t)sk->sk_user_data;
|
||||
if (sk_user_data & SK_USER_DATA_BPF) {
|
||||
struct sock __rcu **socks;
|
||||
|
||||
socks = (void *)(sk_user_data & SK_USER_DATA_PTRMASK);
|
||||
WRITE_ONCE(sk->sk_user_data, NULL);
|
||||
/*
|
||||
* Do not move this NULL assignment outside of
|
||||
@@ -252,6 +255,7 @@ int bpf_fd_reuseport_array_update_elem(struct bpf_map *map, void *key,
|
||||
struct sock *free_osk = NULL, *osk, *nsk;
|
||||
struct sock_reuseport *reuse;
|
||||
u32 index = *(u32 *)key;
|
||||
uintptr_t sk_user_data;
|
||||
struct socket *socket;
|
||||
int err, fd;
|
||||
|
||||
@@ -305,7 +309,9 @@ int bpf_fd_reuseport_array_update_elem(struct bpf_map *map, void *key,
|
||||
if (err)
|
||||
goto put_file_unlock;
|
||||
|
||||
WRITE_ONCE(nsk->sk_user_data, &array->ptrs[index]);
|
||||
sk_user_data = (uintptr_t)&array->ptrs[index] | SK_USER_DATA_NOCOPY |
|
||||
SK_USER_DATA_BPF;
|
||||
WRITE_ONCE(nsk->sk_user_data, (void *)sk_user_data);
|
||||
rcu_assign_pointer(array->ptrs[index], nsk);
|
||||
free_osk = osk;
|
||||
err = 0;
|
||||
|
@@ -132,15 +132,6 @@ static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node)
|
||||
{
|
||||
struct bpf_ringbuf *rb;
|
||||
|
||||
if (!data_sz || !PAGE_ALIGNED(data_sz))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/* on 32-bit arch, it's impossible to overflow record's hdr->pgoff */
|
||||
if (data_sz > RINGBUF_MAX_DATA_SZ)
|
||||
return ERR_PTR(-E2BIG);
|
||||
#endif
|
||||
|
||||
rb = bpf_ringbuf_area_alloc(data_sz, numa_node);
|
||||
if (!rb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@@ -166,9 +157,16 @@ static struct bpf_map *ringbuf_map_alloc(union bpf_attr *attr)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (attr->key_size || attr->value_size ||
|
||||
attr->max_entries == 0 || !PAGE_ALIGNED(attr->max_entries))
|
||||
!is_power_of_2(attr->max_entries) ||
|
||||
!PAGE_ALIGNED(attr->max_entries))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/* on 32-bit arch, it's impossible to overflow record's hdr->pgoff */
|
||||
if (attr->max_entries > RINGBUF_MAX_DATA_SZ)
|
||||
return ERR_PTR(-E2BIG);
|
||||
#endif
|
||||
|
||||
rb_map = kzalloc(sizeof(*rb_map), GFP_USER);
|
||||
if (!rb_map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@@ -2121,7 +2121,7 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
|
||||
!bpf_capable())
|
||||
return -EPERM;
|
||||
|
||||
if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN))
|
||||
if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (is_perfmon_prog_type(type) && !perfmon_capable())
|
||||
return -EPERM;
|
||||
@@ -2893,13 +2893,11 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
||||
switch (ptype) {
|
||||
case BPF_PROG_TYPE_SK_MSG:
|
||||
case BPF_PROG_TYPE_SK_SKB:
|
||||
return sock_map_get_from_fd(attr, NULL);
|
||||
return sock_map_prog_detach(attr, ptype);
|
||||
case BPF_PROG_TYPE_LIRC_MODE2:
|
||||
return lirc_prog_detach(attr);
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
return netns_bpf_prog_detach(attr);
|
||||
return netns_bpf_prog_detach(attr, ptype);
|
||||
case BPF_PROG_TYPE_CGROUP_DEVICE:
|
||||
case BPF_PROG_TYPE_CGROUP_SKB:
|
||||
case BPF_PROG_TYPE_CGROUP_SOCK:
|
||||
@@ -3139,7 +3137,8 @@ static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
|
||||
static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
|
||||
const struct cred *f_cred)
|
||||
{
|
||||
const struct bpf_map *map;
|
||||
struct bpf_insn *insns;
|
||||
@@ -3165,7 +3164,7 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
|
||||
code == (BPF_JMP | BPF_CALL_ARGS)) {
|
||||
if (code == (BPF_JMP | BPF_CALL_ARGS))
|
||||
insns[i].code = BPF_JMP | BPF_CALL;
|
||||
if (!bpf_dump_raw_ok())
|
||||
if (!bpf_dump_raw_ok(f_cred))
|
||||
insns[i].imm = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -3221,7 +3220,8 @@ static int set_info_rec_size(struct bpf_prog_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
||||
static int bpf_prog_get_info_by_fd(struct file *file,
|
||||
struct bpf_prog *prog,
|
||||
const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
@@ -3290,11 +3290,11 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
||||
struct bpf_insn *insns_sanitized;
|
||||
bool fault;
|
||||
|
||||
if (prog->blinded && !bpf_dump_raw_ok()) {
|
||||
if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
|
||||
info.xlated_prog_insns = 0;
|
||||
goto done;
|
||||
}
|
||||
insns_sanitized = bpf_insn_prepare_dump(prog);
|
||||
insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
|
||||
if (!insns_sanitized)
|
||||
return -ENOMEM;
|
||||
uinsns = u64_to_user_ptr(info.xlated_prog_insns);
|
||||
@@ -3328,7 +3328,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
||||
}
|
||||
|
||||
if (info.jited_prog_len && ulen) {
|
||||
if (bpf_dump_raw_ok()) {
|
||||
if (bpf_dump_raw_ok(file->f_cred)) {
|
||||
uinsns = u64_to_user_ptr(info.jited_prog_insns);
|
||||
ulen = min_t(u32, info.jited_prog_len, ulen);
|
||||
|
||||
@@ -3363,7 +3363,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
||||
ulen = info.nr_jited_ksyms;
|
||||
info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
|
||||
if (ulen) {
|
||||
if (bpf_dump_raw_ok()) {
|
||||
if (bpf_dump_raw_ok(file->f_cred)) {
|
||||
unsigned long ksym_addr;
|
||||
u64 __user *user_ksyms;
|
||||
u32 i;
|
||||
@@ -3394,7 +3394,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
||||
ulen = info.nr_jited_func_lens;
|
||||
info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
|
||||
if (ulen) {
|
||||
if (bpf_dump_raw_ok()) {
|
||||
if (bpf_dump_raw_ok(file->f_cred)) {
|
||||
u32 __user *user_lens;
|
||||
u32 func_len, i;
|
||||
|
||||
@@ -3451,7 +3451,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
|
||||
else
|
||||
info.nr_jited_line_info = 0;
|
||||
if (info.nr_jited_line_info && ulen) {
|
||||
if (bpf_dump_raw_ok()) {
|
||||
if (bpf_dump_raw_ok(file->f_cred)) {
|
||||
__u64 __user *user_linfo;
|
||||
u32 i;
|
||||
|
||||
@@ -3497,7 +3497,8 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_map_get_info_by_fd(struct bpf_map *map,
|
||||
static int bpf_map_get_info_by_fd(struct file *file,
|
||||
struct bpf_map *map,
|
||||
const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
@@ -3540,7 +3541,8 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_btf_get_info_by_fd(struct btf *btf,
|
||||
static int bpf_btf_get_info_by_fd(struct file *file,
|
||||
struct btf *btf,
|
||||
const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
@@ -3555,7 +3557,8 @@ static int bpf_btf_get_info_by_fd(struct btf *btf,
|
||||
return btf_get_info_by_fd(btf, attr, uattr);
|
||||
}
|
||||
|
||||
static int bpf_link_get_info_by_fd(struct bpf_link *link,
|
||||
static int bpf_link_get_info_by_fd(struct file *file,
|
||||
struct bpf_link *link,
|
||||
const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr)
|
||||
{
|
||||
@@ -3608,15 +3611,15 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
|
||||
return -EBADFD;
|
||||
|
||||
if (f.file->f_op == &bpf_prog_fops)
|
||||
err = bpf_prog_get_info_by_fd(f.file->private_data, attr,
|
||||
err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
|
||||
uattr);
|
||||
else if (f.file->f_op == &bpf_map_fops)
|
||||
err = bpf_map_get_info_by_fd(f.file->private_data, attr,
|
||||
err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
|
||||
uattr);
|
||||
else if (f.file->f_op == &btf_fops)
|
||||
err = bpf_btf_get_info_by_fd(f.file->private_data, attr, uattr);
|
||||
err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
|
||||
else if (f.file->f_op == &bpf_link_fops)
|
||||
err = bpf_link_get_info_by_fd(f.file->private_data,
|
||||
err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
|
||||
attr, uattr);
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
@@ -399,8 +399,7 @@ static bool reg_type_not_null(enum bpf_reg_type type)
|
||||
return type == PTR_TO_SOCKET ||
|
||||
type == PTR_TO_TCP_SOCK ||
|
||||
type == PTR_TO_MAP_VALUE ||
|
||||
type == PTR_TO_SOCK_COMMON ||
|
||||
type == PTR_TO_BTF_ID;
|
||||
type == PTR_TO_SOCK_COMMON;
|
||||
}
|
||||
|
||||
static bool reg_type_may_be_null(enum bpf_reg_type type)
|
||||
@@ -9801,7 +9800,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
|
||||
int i, j, subprog_start, subprog_end = 0, len, subprog;
|
||||
struct bpf_insn *insn;
|
||||
void *old_bpf_func;
|
||||
int err;
|
||||
int err, num_exentries;
|
||||
|
||||
if (env->subprog_cnt <= 1)
|
||||
return 0;
|
||||
@@ -9876,6 +9875,14 @@ static int jit_subprogs(struct bpf_verifier_env *env)
|
||||
func[i]->aux->nr_linfo = prog->aux->nr_linfo;
|
||||
func[i]->aux->jited_linfo = prog->aux->jited_linfo;
|
||||
func[i]->aux->linfo_idx = env->subprog_info[i].linfo_idx;
|
||||
num_exentries = 0;
|
||||
insn = func[i]->insnsi;
|
||||
for (j = 0; j < func[i]->len; j++, insn++) {
|
||||
if (BPF_CLASS(insn->code) == BPF_LDX &&
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEM)
|
||||
num_exentries++;
|
||||
}
|
||||
func[i]->aux->num_exentries = num_exentries;
|
||||
func[i] = bpf_int_jit_compile(func[i]);
|
||||
if (!func[i]->jited) {
|
||||
err = -ENOTSUPP;
|
||||
|
@@ -6439,18 +6439,8 @@ void cgroup_sk_alloc_disable(void)
|
||||
|
||||
void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
|
||||
{
|
||||
if (cgroup_sk_alloc_disabled)
|
||||
return;
|
||||
|
||||
/* Socket clone path */
|
||||
if (skcd->val) {
|
||||
/*
|
||||
* We might be cloning a socket which is left in an empty
|
||||
* cgroup and the cgroup might have already been rmdir'd.
|
||||
* Don't use cgroup_get_live().
|
||||
*/
|
||||
cgroup_get(sock_cgroup_ptr(skcd));
|
||||
cgroup_bpf_get(sock_cgroup_ptr(skcd));
|
||||
if (cgroup_sk_alloc_disabled) {
|
||||
skcd->no_refcnt = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6475,10 +6465,27 @@ void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void cgroup_sk_clone(struct sock_cgroup_data *skcd)
|
||||
{
|
||||
if (skcd->val) {
|
||||
if (skcd->no_refcnt)
|
||||
return;
|
||||
/*
|
||||
* We might be cloning a socket which is left in an empty
|
||||
* cgroup and the cgroup might have already been rmdir'd.
|
||||
* Don't use cgroup_get_live().
|
||||
*/
|
||||
cgroup_get(sock_cgroup_ptr(skcd));
|
||||
cgroup_bpf_get(sock_cgroup_ptr(skcd));
|
||||
}
|
||||
}
|
||||
|
||||
void cgroup_sk_free(struct sock_cgroup_data *skcd)
|
||||
{
|
||||
struct cgroup *cgrp = sock_cgroup_ptr(skcd);
|
||||
|
||||
if (skcd->no_refcnt)
|
||||
return;
|
||||
cgroup_bpf_put(cgrp);
|
||||
cgroup_put(cgrp);
|
||||
}
|
||||
|
@@ -792,6 +792,19 @@ static void gdb_cmd_query(struct kgdb_state *ks)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_ARCH_KGDB_QXFER_PKT
|
||||
case 'S':
|
||||
if (!strncmp(remcom_in_buffer, "qSupported:", 11))
|
||||
strcpy(remcom_out_buffer, kgdb_arch_gdb_stub_feature);
|
||||
break;
|
||||
case 'X':
|
||||
if (!strncmp(remcom_in_buffer, "qXfer:", 6))
|
||||
kgdb_arch_handle_qxfer_pkt(remcom_in_buffer,
|
||||
remcom_out_buffer);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -70,7 +70,7 @@ gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
|
||||
bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
|
||||
{
|
||||
return phys_to_dma_direct(dev, phys) + size - 1 <=
|
||||
min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit);
|
||||
@@ -539,3 +539,9 @@ size_t dma_direct_max_mapping_size(struct device *dev)
|
||||
return swiotlb_max_mapping_size(dev);
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
bool dma_direct_need_sync(struct device *dev, dma_addr_t dma_addr)
|
||||
{
|
||||
return !dev_is_dma_coherent(dev) ||
|
||||
is_swiotlb_buffer(dma_to_phys(dev, dma_addr));
|
||||
}
|
||||
|
@@ -397,6 +397,16 @@ size_t dma_max_mapping_size(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_max_mapping_size);
|
||||
|
||||
bool dma_need_sync(struct device *dev, dma_addr_t dma_addr)
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
||||
if (dma_is_direct(ops))
|
||||
return dma_direct_need_sync(dev, dma_addr);
|
||||
return ops->sync_single_for_cpu || ops->sync_single_for_device;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_need_sync);
|
||||
|
||||
unsigned long dma_get_merge_boundary(struct device *dev)
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
@@ -6,7 +6,6 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dma-direct.h>
|
||||
#include <linux/dma-noncoherent.h>
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/set_memory.h>
|
||||
@@ -69,12 +68,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
|
||||
|
||||
do {
|
||||
pool_size = 1 << (PAGE_SHIFT + order);
|
||||
|
||||
if (dev_get_cma_area(NULL))
|
||||
page = dma_alloc_from_contiguous(NULL, 1 << order,
|
||||
order, false);
|
||||
else
|
||||
page = alloc_pages(gfp, order);
|
||||
page = alloc_pages(gfp, order);
|
||||
} while (!page && order-- > 0);
|
||||
if (!page)
|
||||
goto out;
|
||||
@@ -118,8 +112,7 @@ remove_mapping:
|
||||
dma_common_free_remap(addr, pool_size);
|
||||
#endif
|
||||
free_page: __maybe_unused
|
||||
if (!dma_release_from_contiguous(NULL, page, 1 << order))
|
||||
__free_pages(page, order);
|
||||
__free_pages(page, order);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -203,7 +196,7 @@ static int __init dma_atomic_pool_init(void)
|
||||
}
|
||||
postcore_initcall(dma_atomic_pool_init);
|
||||
|
||||
static inline struct gen_pool *dev_to_pool(struct device *dev)
|
||||
static inline struct gen_pool *dma_guess_pool_from_device(struct device *dev)
|
||||
{
|
||||
u64 phys_mask;
|
||||
gfp_t gfp;
|
||||
@@ -217,47 +210,79 @@ static inline struct gen_pool *dev_to_pool(struct device *dev)
|
||||
return atomic_pool_kernel;
|
||||
}
|
||||
|
||||
static bool dma_in_atomic_pool(struct device *dev, void *start, size_t size)
|
||||
static inline struct gen_pool *dma_get_safer_pool(struct gen_pool *bad_pool)
|
||||
{
|
||||
struct gen_pool *pool = dev_to_pool(dev);
|
||||
if (bad_pool == atomic_pool_kernel)
|
||||
return atomic_pool_dma32 ? : atomic_pool_dma;
|
||||
|
||||
if (unlikely(!pool))
|
||||
return false;
|
||||
return gen_pool_has_addr(pool, (unsigned long)start, size);
|
||||
if (bad_pool == atomic_pool_dma32)
|
||||
return atomic_pool_dma;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct gen_pool *dma_guess_pool(struct device *dev,
|
||||
struct gen_pool *bad_pool)
|
||||
{
|
||||
if (bad_pool)
|
||||
return dma_get_safer_pool(bad_pool);
|
||||
|
||||
return dma_guess_pool_from_device(dev);
|
||||
}
|
||||
|
||||
void *dma_alloc_from_pool(struct device *dev, size_t size,
|
||||
struct page **ret_page, gfp_t flags)
|
||||
{
|
||||
struct gen_pool *pool = dev_to_pool(dev);
|
||||
unsigned long val;
|
||||
struct gen_pool *pool = NULL;
|
||||
unsigned long val = 0;
|
||||
void *ptr = NULL;
|
||||
phys_addr_t phys;
|
||||
|
||||
if (!pool) {
|
||||
WARN(1, "%pGg atomic pool not initialised!\n", &flags);
|
||||
return NULL;
|
||||
while (1) {
|
||||
pool = dma_guess_pool(dev, pool);
|
||||
if (!pool) {
|
||||
WARN(1, "Failed to get suitable pool for %s\n",
|
||||
dev_name(dev));
|
||||
break;
|
||||
}
|
||||
|
||||
val = gen_pool_alloc(pool, size);
|
||||
if (!val)
|
||||
continue;
|
||||
|
||||
phys = gen_pool_virt_to_phys(pool, val);
|
||||
if (dma_coherent_ok(dev, phys, size))
|
||||
break;
|
||||
|
||||
gen_pool_free(pool, val, size);
|
||||
val = 0;
|
||||
}
|
||||
|
||||
val = gen_pool_alloc(pool, size);
|
||||
if (val) {
|
||||
phys_addr_t phys = gen_pool_virt_to_phys(pool, val);
|
||||
|
||||
if (val) {
|
||||
*ret_page = pfn_to_page(__phys_to_pfn(phys));
|
||||
ptr = (void *)val;
|
||||
memset(ptr, 0, size);
|
||||
|
||||
if (gen_pool_avail(pool) < atomic_pool_size)
|
||||
schedule_work(&atomic_pool_work);
|
||||
}
|
||||
if (gen_pool_avail(pool) < atomic_pool_size)
|
||||
schedule_work(&atomic_pool_work);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool dma_free_from_pool(struct device *dev, void *start, size_t size)
|
||||
{
|
||||
struct gen_pool *pool = dev_to_pool(dev);
|
||||
struct gen_pool *pool = NULL;
|
||||
|
||||
if (!dma_in_atomic_pool(dev, start, size))
|
||||
return false;
|
||||
gen_pool_free(pool, (unsigned long)start, size);
|
||||
return true;
|
||||
while (1) {
|
||||
pool = dma_guess_pool(dev, pool);
|
||||
if (!pool)
|
||||
return false;
|
||||
|
||||
if (gen_pool_has_addr(pool, (unsigned long)start, size)) {
|
||||
gen_pool_free(pool, (unsigned long)start, size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2199,7 +2199,7 @@ static void handle_swbp(struct pt_regs *regs)
|
||||
if (!uprobe) {
|
||||
if (is_swbp > 0) {
|
||||
/* No matching uprobe; signal SIGTRAP. */
|
||||
send_sig(SIGTRAP, current, 0);
|
||||
force_sig(SIGTRAP);
|
||||
} else {
|
||||
/*
|
||||
* Either we raced with uprobe_unregister() or we can't
|
||||
|
@@ -1977,7 +1977,7 @@ static __latent_entropy struct task_struct *copy_process(
|
||||
* to stop root fork bombs.
|
||||
*/
|
||||
retval = -EAGAIN;
|
||||
if (nr_threads >= max_threads)
|
||||
if (data_race(nr_threads >= max_threads))
|
||||
goto bad_fork_cleanup_count;
|
||||
|
||||
delayacct_tsk_init(p); /* Must remain after dup_task_struct() */
|
||||
|
@@ -195,9 +195,9 @@ void irq_set_thread_affinity(struct irq_desc *desc)
|
||||
set_bit(IRQTF_AFFINITY, &action->thread_flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
static void irq_validate_effective_affinity(struct irq_data *data)
|
||||
{
|
||||
#ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
const struct cpumask *m = irq_data_get_effective_affinity_mask(data);
|
||||
struct irq_chip *chip = irq_data_get_irq_chip(data);
|
||||
|
||||
@@ -205,9 +205,19 @@ static void irq_validate_effective_affinity(struct irq_data *data)
|
||||
return;
|
||||
pr_warn_once("irq_chip %s did not update eff. affinity mask of irq %u\n",
|
||||
chip->name, data->irq);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void irq_init_effective_affinity(struct irq_data *data,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
cpumask_copy(irq_data_get_effective_affinity_mask(data), mask);
|
||||
}
|
||||
#else
|
||||
static inline void irq_validate_effective_affinity(struct irq_data *data) { }
|
||||
static inline void irq_init_effective_affinity(struct irq_data *data,
|
||||
const struct cpumask *mask) { }
|
||||
#endif
|
||||
|
||||
int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
||||
bool force)
|
||||
{
|
||||
@@ -304,6 +314,26 @@ static int irq_try_set_affinity(struct irq_data *data,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool irq_set_affinity_deactivated(struct irq_data *data,
|
||||
const struct cpumask *mask, bool force)
|
||||
{
|
||||
struct irq_desc *desc = irq_data_to_desc(data);
|
||||
|
||||
/*
|
||||
* If the interrupt is not yet activated, just store the affinity
|
||||
* mask and do not call the chip driver at all. On activation the
|
||||
* driver has to make sure anyway that the interrupt is in a
|
||||
* useable state so startup works.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) || irqd_is_activated(data))
|
||||
return false;
|
||||
|
||||
cpumask_copy(desc->irq_common_data.affinity, mask);
|
||||
irq_init_effective_affinity(data, mask);
|
||||
irqd_set(data, IRQD_AFFINITY_SET);
|
||||
return true;
|
||||
}
|
||||
|
||||
int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
|
||||
bool force)
|
||||
{
|
||||
@@ -314,6 +344,9 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
|
||||
if (!chip || !chip->irq_set_affinity)
|
||||
return -EINVAL;
|
||||
|
||||
if (irq_set_affinity_deactivated(data, mask, force))
|
||||
return 0;
|
||||
|
||||
if (irq_can_move_pcntxt(data) && !irqd_is_setaffinity_pending(data)) {
|
||||
ret = irq_try_set_affinity(data, mask, force);
|
||||
} else {
|
||||
|
@@ -678,19 +678,20 @@ static inline int kallsyms_for_perf(void)
|
||||
* Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to
|
||||
* block even that).
|
||||
*/
|
||||
int kallsyms_show_value(void)
|
||||
bool kallsyms_show_value(const struct cred *cred)
|
||||
{
|
||||
switch (kptr_restrict) {
|
||||
case 0:
|
||||
if (kallsyms_for_perf())
|
||||
return 1;
|
||||
return true;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
if (has_capability_noaudit(current, CAP_SYSLOG))
|
||||
return 1;
|
||||
if (security_capable(cred, &init_user_ns, CAP_SYSLOG,
|
||||
CAP_OPT_NOAUDIT) == 0)
|
||||
return true;
|
||||
/* fallthrough */
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,7 +708,11 @@ static int kallsyms_open(struct inode *inode, struct file *file)
|
||||
return -ENOMEM;
|
||||
reset_iter(iter, 0);
|
||||
|
||||
iter->show_value = kallsyms_show_value();
|
||||
/*
|
||||
* Instead of checking this on every s_show() call, cache
|
||||
* the result here at open time.
|
||||
*/
|
||||
iter->show_value = kallsyms_show_value(file->f_cred);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -2505,7 +2505,7 @@ static void report_probe(struct seq_file *pi, struct kprobe *p,
|
||||
else
|
||||
kprobe_type = "k";
|
||||
|
||||
if (!kallsyms_show_value())
|
||||
if (!kallsyms_show_value(pi->file->f_cred))
|
||||
addr = NULL;
|
||||
|
||||
if (sym)
|
||||
@@ -2597,7 +2597,7 @@ static int kprobe_blacklist_seq_show(struct seq_file *m, void *v)
|
||||
* If /proc/kallsyms is not showing kernel address, we won't
|
||||
* show them here either.
|
||||
*/
|
||||
if (!kallsyms_show_value())
|
||||
if (!kallsyms_show_value(m->file->f_cred))
|
||||
seq_printf(m, "0x%px-0x%px\t%ps\n", NULL, NULL,
|
||||
(void *)ent->start_addr);
|
||||
else
|
||||
|
@@ -1510,8 +1510,7 @@ static inline bool sect_empty(const Elf_Shdr *sect)
|
||||
}
|
||||
|
||||
struct module_sect_attr {
|
||||
struct module_attribute mattr;
|
||||
char *name;
|
||||
struct bin_attribute battr;
|
||||
unsigned long address;
|
||||
};
|
||||
|
||||
@@ -1521,13 +1520,18 @@ struct module_sect_attrs {
|
||||
struct module_sect_attr attrs[];
|
||||
};
|
||||
|
||||
static ssize_t module_sect_show(struct module_attribute *mattr,
|
||||
struct module_kobject *mk, char *buf)
|
||||
static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
|
||||
struct bin_attribute *battr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
struct module_sect_attr *sattr =
|
||||
container_of(mattr, struct module_sect_attr, mattr);
|
||||
return sprintf(buf, "0x%px\n", kptr_restrict < 2 ?
|
||||
(void *)sattr->address : NULL);
|
||||
container_of(battr, struct module_sect_attr, battr);
|
||||
|
||||
if (pos != 0)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "0x%px\n",
|
||||
kallsyms_show_value(file->f_cred) ? (void *)sattr->address : NULL);
|
||||
}
|
||||
|
||||
static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
|
||||
@@ -1535,7 +1539,7 @@ static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
|
||||
unsigned int section;
|
||||
|
||||
for (section = 0; section < sect_attrs->nsections; section++)
|
||||
kfree(sect_attrs->attrs[section].name);
|
||||
kfree(sect_attrs->attrs[section].battr.attr.name);
|
||||
kfree(sect_attrs);
|
||||
}
|
||||
|
||||
@@ -1544,42 +1548,41 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
|
||||
unsigned int nloaded = 0, i, size[2];
|
||||
struct module_sect_attrs *sect_attrs;
|
||||
struct module_sect_attr *sattr;
|
||||
struct attribute **gattr;
|
||||
struct bin_attribute **gattr;
|
||||
|
||||
/* Count loaded sections and allocate structures */
|
||||
for (i = 0; i < info->hdr->e_shnum; i++)
|
||||
if (!sect_empty(&info->sechdrs[i]))
|
||||
nloaded++;
|
||||
size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
|
||||
sizeof(sect_attrs->grp.attrs[0]));
|
||||
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
|
||||
sizeof(sect_attrs->grp.bin_attrs[0]));
|
||||
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
|
||||
sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
|
||||
if (sect_attrs == NULL)
|
||||
return;
|
||||
|
||||
/* Setup section attributes. */
|
||||
sect_attrs->grp.name = "sections";
|
||||
sect_attrs->grp.attrs = (void *)sect_attrs + size[0];
|
||||
sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
|
||||
|
||||
sect_attrs->nsections = 0;
|
||||
sattr = §_attrs->attrs[0];
|
||||
gattr = §_attrs->grp.attrs[0];
|
||||
gattr = §_attrs->grp.bin_attrs[0];
|
||||
for (i = 0; i < info->hdr->e_shnum; i++) {
|
||||
Elf_Shdr *sec = &info->sechdrs[i];
|
||||
if (sect_empty(sec))
|
||||
continue;
|
||||
sysfs_bin_attr_init(&sattr->battr);
|
||||
sattr->address = sec->sh_addr;
|
||||
sattr->name = kstrdup(info->secstrings + sec->sh_name,
|
||||
GFP_KERNEL);
|
||||
if (sattr->name == NULL)
|
||||
sattr->battr.attr.name =
|
||||
kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
|
||||
if (sattr->battr.attr.name == NULL)
|
||||
goto out;
|
||||
sect_attrs->nsections++;
|
||||
sysfs_attr_init(&sattr->mattr.attr);
|
||||
sattr->mattr.show = module_sect_show;
|
||||
sattr->mattr.store = NULL;
|
||||
sattr->mattr.attr.name = sattr->name;
|
||||
sattr->mattr.attr.mode = S_IRUSR;
|
||||
*(gattr++) = &(sattr++)->mattr.attr;
|
||||
sattr->battr.read = module_sect_read;
|
||||
sattr->battr.size = 3 /* "0x", "\n" */ + (BITS_PER_LONG / 4);
|
||||
sattr->battr.attr.mode = 0400;
|
||||
*(gattr++) = &(sattr++)->battr;
|
||||
}
|
||||
*gattr = NULL;
|
||||
|
||||
@@ -1669,7 +1672,7 @@ static void add_notes_attrs(struct module *mod, const struct load_info *info)
|
||||
continue;
|
||||
if (info->sechdrs[i].sh_type == SHT_NOTE) {
|
||||
sysfs_bin_attr_init(nattr);
|
||||
nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
|
||||
nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
|
||||
nattr->attr.mode = S_IRUGO;
|
||||
nattr->size = info->sechdrs[i].sh_size;
|
||||
nattr->private = (void *) info->sechdrs[i].sh_addr;
|
||||
@@ -2785,7 +2788,7 @@ void * __weak module_alloc(unsigned long size)
|
||||
{
|
||||
return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
|
||||
GFP_KERNEL, PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS,
|
||||
NUMA_NO_NODE, __func__);
|
||||
NUMA_NO_NODE, __builtin_return_address(0));
|
||||
}
|
||||
|
||||
bool __weak module_init_section(const char *name)
|
||||
@@ -4379,7 +4382,7 @@ static int modules_open(struct inode *inode, struct file *file)
|
||||
|
||||
if (!err) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = kallsyms_show_value() ? NULL : (void *)8ul;
|
||||
m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@@ -335,7 +335,7 @@ static void padata_reorder(struct parallel_data *pd)
|
||||
*
|
||||
* Ensure reorder queue is read after pd->lock is dropped so we see
|
||||
* new objects from another task in padata_do_serial. Pairs with
|
||||
* smp_mb__after_atomic in padata_do_serial.
|
||||
* smp_mb in padata_do_serial.
|
||||
*/
|
||||
smp_mb();
|
||||
|
||||
@@ -418,7 +418,7 @@ void padata_do_serial(struct padata_priv *padata)
|
||||
* with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
|
||||
* in padata_reorder.
|
||||
*/
|
||||
smp_mb__after_atomic();
|
||||
smp_mb();
|
||||
|
||||
padata_reorder(pd);
|
||||
}
|
||||
|
@@ -723,7 +723,7 @@ kfree_perf_init(void)
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
|
||||
pr_alert("kfree object size=%lu\n", kfree_mult * sizeof(struct kfree_obj));
|
||||
pr_alert("kfree object size=%zu\n", kfree_mult * sizeof(struct kfree_obj));
|
||||
|
||||
kfree_reader_tasks = kcalloc(kfree_nrealthreads, sizeof(kfree_reader_tasks[0]),
|
||||
GFP_KERNEL);
|
||||
|
@@ -1311,9 +1311,6 @@ static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
|
||||
|
||||
void activate_task(struct rq *rq, struct task_struct *p, int flags)
|
||||
{
|
||||
if (task_contributes_to_load(p))
|
||||
rq->nr_uninterruptible--;
|
||||
|
||||
enqueue_task(rq, p, flags);
|
||||
|
||||
p->on_rq = TASK_ON_RQ_QUEUED;
|
||||
@@ -1323,9 +1320,6 @@ void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
|
||||
{
|
||||
p->on_rq = (flags & DEQUEUE_SLEEP) ? 0 : TASK_ON_RQ_MIGRATING;
|
||||
|
||||
if (task_contributes_to_load(p))
|
||||
rq->nr_uninterruptible++;
|
||||
|
||||
dequeue_task(rq, p, flags);
|
||||
}
|
||||
|
||||
@@ -2236,10 +2230,10 @@ ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags,
|
||||
|
||||
lockdep_assert_held(&rq->lock);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (p->sched_contributes_to_load)
|
||||
rq->nr_uninterruptible--;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (wake_flags & WF_MIGRATED)
|
||||
en_flags |= ENQUEUE_MIGRATED;
|
||||
#endif
|
||||
@@ -2583,7 +2577,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
|
||||
* A similar smb_rmb() lives in try_invoke_on_locked_down_task().
|
||||
*/
|
||||
smp_rmb();
|
||||
if (p->on_rq && ttwu_remote(p, wake_flags))
|
||||
if (READ_ONCE(p->on_rq) && ttwu_remote(p, wake_flags))
|
||||
goto unlock;
|
||||
|
||||
if (p->in_iowait) {
|
||||
@@ -2592,9 +2586,6 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
p->sched_contributes_to_load = !!task_contributes_to_load(p);
|
||||
p->state = TASK_WAKING;
|
||||
|
||||
/*
|
||||
* Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
|
||||
* possible to, falsely, observe p->on_cpu == 0.
|
||||
@@ -2613,8 +2604,20 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
|
||||
*
|
||||
* Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
|
||||
* __schedule(). See the comment for smp_mb__after_spinlock().
|
||||
*
|
||||
* Form a control-dep-acquire with p->on_rq == 0 above, to ensure
|
||||
* schedule()'s deactivate_task() has 'happened' and p will no longer
|
||||
* care about it's own p->state. See the comment in __schedule().
|
||||
*/
|
||||
smp_rmb();
|
||||
smp_acquire__after_ctrl_dep();
|
||||
|
||||
/*
|
||||
* We're doing the wakeup (@success == 1), they did a dequeue (p->on_rq
|
||||
* == 0), which means we need to do an enqueue, change p->state to
|
||||
* TASK_WAKING such that we can unlock p->pi_lock before doing the
|
||||
* enqueue, such as ttwu_queue_wakelist().
|
||||
*/
|
||||
p->state = TASK_WAKING;
|
||||
|
||||
/*
|
||||
* If the owning (remote) CPU is still in the middle of schedule() with
|
||||
@@ -2962,6 +2965,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
|
||||
* Silence PROVE_RCU.
|
||||
*/
|
||||
raw_spin_lock_irqsave(&p->pi_lock, flags);
|
||||
rseq_migrate(p);
|
||||
/*
|
||||
* We're setting the CPU for the first time, we don't migrate,
|
||||
* so use __set_task_cpu().
|
||||
@@ -3026,6 +3030,7 @@ void wake_up_new_task(struct task_struct *p)
|
||||
* as we're not fully set-up yet.
|
||||
*/
|
||||
p->recent_used_cpu = task_cpu(p);
|
||||
rseq_migrate(p);
|
||||
__set_task_cpu(p, select_task_rq(p, task_cpu(p), SD_BALANCE_FORK, 0));
|
||||
#endif
|
||||
rq = __task_rq_lock(p, &rf);
|
||||
@@ -4097,6 +4102,7 @@ static void __sched notrace __schedule(bool preempt)
|
||||
{
|
||||
struct task_struct *prev, *next;
|
||||
unsigned long *switch_count;
|
||||
unsigned long prev_state;
|
||||
struct rq_flags rf;
|
||||
struct rq *rq;
|
||||
int cpu;
|
||||
@@ -4116,9 +4122,16 @@ static void __sched notrace __schedule(bool preempt)
|
||||
/*
|
||||
* Make sure that signal_pending_state()->signal_pending() below
|
||||
* can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
|
||||
* done by the caller to avoid the race with signal_wake_up().
|
||||
* done by the caller to avoid the race with signal_wake_up():
|
||||
*
|
||||
* The membarrier system call requires a full memory barrier
|
||||
* __set_current_state(@state) signal_wake_up()
|
||||
* schedule() set_tsk_thread_flag(p, TIF_SIGPENDING)
|
||||
* wake_up_state(p, state)
|
||||
* LOCK rq->lock LOCK p->pi_state
|
||||
* smp_mb__after_spinlock() smp_mb__after_spinlock()
|
||||
* if (signal_pending_state()) if (p->state & @state)
|
||||
*
|
||||
* Also, the membarrier system call requires a full memory barrier
|
||||
* after coming from user-space, before storing to rq->curr.
|
||||
*/
|
||||
rq_lock(rq, &rf);
|
||||
@@ -4129,10 +4142,38 @@ static void __sched notrace __schedule(bool preempt)
|
||||
update_rq_clock(rq);
|
||||
|
||||
switch_count = &prev->nivcsw;
|
||||
if (!preempt && prev->state) {
|
||||
if (signal_pending_state(prev->state, prev)) {
|
||||
|
||||
/*
|
||||
* We must load prev->state once (task_struct::state is volatile), such
|
||||
* that:
|
||||
*
|
||||
* - we form a control dependency vs deactivate_task() below.
|
||||
* - ptrace_{,un}freeze_traced() can change ->state underneath us.
|
||||
*/
|
||||
prev_state = prev->state;
|
||||
if (!preempt && prev_state) {
|
||||
if (signal_pending_state(prev_state, prev)) {
|
||||
prev->state = TASK_RUNNING;
|
||||
} else {
|
||||
prev->sched_contributes_to_load =
|
||||
(prev_state & TASK_UNINTERRUPTIBLE) &&
|
||||
!(prev_state & TASK_NOLOAD) &&
|
||||
!(prev->flags & PF_FROZEN);
|
||||
|
||||
if (prev->sched_contributes_to_load)
|
||||
rq->nr_uninterruptible++;
|
||||
|
||||
/*
|
||||
* __schedule() ttwu()
|
||||
* prev_state = prev->state; if (p->on_rq && ...)
|
||||
* if (prev_state) goto out;
|
||||
* p->on_rq = 0; smp_acquire__after_ctrl_dep();
|
||||
* p->state = TASK_WAKING
|
||||
*
|
||||
* Where __schedule() and ttwu() have matching control dependencies.
|
||||
*
|
||||
* After this, schedule() must not care about p->state any more.
|
||||
*/
|
||||
deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);
|
||||
|
||||
if (prev->in_iowait) {
|
||||
@@ -4444,6 +4485,7 @@ asmlinkage __visible void __sched preempt_schedule_irq(void)
|
||||
int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,
|
||||
void *key)
|
||||
{
|
||||
WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC);
|
||||
return try_to_wake_up(curr->private, mode, wake_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(default_wake_function);
|
||||
|
@@ -4039,7 +4039,11 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq)
|
||||
return;
|
||||
}
|
||||
|
||||
rq->misfit_task_load = task_h_load(p);
|
||||
/*
|
||||
* Make sure that misfit_task_load will not be null even if
|
||||
* task_h_load() returns 0.
|
||||
*/
|
||||
rq->misfit_task_load = max_t(unsigned long, task_h_load(p), 1);
|
||||
}
|
||||
|
||||
#else /* CONFIG_SMP */
|
||||
@@ -7638,7 +7642,14 @@ static int detach_tasks(struct lb_env *env)
|
||||
|
||||
switch (env->migration_type) {
|
||||
case migrate_load:
|
||||
load = task_h_load(p);
|
||||
/*
|
||||
* Depending of the number of CPUs and tasks and the
|
||||
* cgroup hierarchy, task_h_load() can return a null
|
||||
* value. Make sure that env->imbalance decreases
|
||||
* otherwise detach_tasks() will stop only after
|
||||
* detaching up to loop_max tasks.
|
||||
*/
|
||||
load = max_t(unsigned long, task_h_load(p), 1);
|
||||
|
||||
if (sched_feat(LB_MIN) &&
|
||||
load < 16 && !env->sd->nr_balance_failed)
|
||||
|
@@ -2529,9 +2529,6 @@ bool get_signal(struct ksignal *ksig)
|
||||
struct signal_struct *signal = current->signal;
|
||||
int signr;
|
||||
|
||||
if (unlikely(current->task_works))
|
||||
task_work_run();
|
||||
|
||||
if (unlikely(uprobe_deny_signal()))
|
||||
return false;
|
||||
|
||||
@@ -2544,6 +2541,13 @@ bool get_signal(struct ksignal *ksig)
|
||||
|
||||
relock:
|
||||
spin_lock_irq(&sighand->siglock);
|
||||
current->jobctl &= ~JOBCTL_TASK_WORK;
|
||||
if (unlikely(current->task_works)) {
|
||||
spin_unlock_irq(&sighand->siglock);
|
||||
task_work_run();
|
||||
goto relock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Every stopped thread goes here after wakeup. Check to see if
|
||||
* we should notify the parent, prepare_signal(SIGCONT) encodes
|
||||
|
@@ -25,9 +25,10 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */
|
||||
* 0 if succeeds or -ESRCH.
|
||||
*/
|
||||
int
|
||||
task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
|
||||
task_work_add(struct task_struct *task, struct callback_head *work, int notify)
|
||||
{
|
||||
struct callback_head *head;
|
||||
unsigned long flags;
|
||||
|
||||
do {
|
||||
head = READ_ONCE(task->task_works);
|
||||
@@ -36,8 +37,19 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
|
||||
work->next = head;
|
||||
} while (cmpxchg(&task->task_works, head, work) != head);
|
||||
|
||||
if (notify)
|
||||
switch (notify) {
|
||||
case TWA_RESUME:
|
||||
set_notify_resume(task);
|
||||
break;
|
||||
case TWA_SIGNAL:
|
||||
if (lock_task_sighand(task, &flags)) {
|
||||
task->jobctl |= JOBCTL_TASK_WORK;
|
||||
signal_wake_up(task, 0);
|
||||
unlock_task_sighand(task, &flags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -521,8 +521,8 @@ static int calc_wheel_index(unsigned long expires, unsigned long clk)
|
||||
* Force expire obscene large timeouts to expire at the
|
||||
* capacity limit of the wheel.
|
||||
*/
|
||||
if (expires >= WHEEL_TIMEOUT_CUTOFF)
|
||||
expires = WHEEL_TIMEOUT_MAX;
|
||||
if (delta >= WHEEL_TIMEOUT_CUTOFF)
|
||||
expires = clk + WHEEL_TIMEOUT_MAX;
|
||||
|
||||
idx = calc_index(expires, LVL_DEPTH - 1);
|
||||
}
|
||||
@@ -584,7 +584,15 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
|
||||
* Set the next expiry time and kick the CPU so it can reevaluate the
|
||||
* wheel:
|
||||
*/
|
||||
base->next_expiry = timer->expires;
|
||||
if (time_before(timer->expires, base->clk)) {
|
||||
/*
|
||||
* Prevent from forward_timer_base() moving the base->clk
|
||||
* backward
|
||||
*/
|
||||
base->next_expiry = base->clk;
|
||||
} else {
|
||||
base->next_expiry = timer->expires;
|
||||
}
|
||||
wake_up_nohz_cpu(base->cpu);
|
||||
}
|
||||
|
||||
@@ -896,10 +904,13 @@ static inline void forward_timer_base(struct timer_base *base)
|
||||
* If the next expiry value is > jiffies, then we fast forward to
|
||||
* jiffies otherwise we forward to the next expiry value.
|
||||
*/
|
||||
if (time_after(base->next_expiry, jnow))
|
||||
if (time_after(base->next_expiry, jnow)) {
|
||||
base->clk = jnow;
|
||||
else
|
||||
} else {
|
||||
if (WARN_ON_ONCE(time_before(base->next_expiry, base->clk)))
|
||||
return;
|
||||
base->clk = base->next_expiry;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user