Merge branch 'linus' into locking/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
这个提交包含在:
@@ -476,7 +476,7 @@ static u32 prog_fd_array_sys_lookup_elem(void *ptr)
|
||||
}
|
||||
|
||||
/* decrement refcnt of all bpf_progs that are stored in this map */
|
||||
void bpf_fd_array_map_clear(struct bpf_map *map)
|
||||
static void bpf_fd_array_map_clear(struct bpf_map *map)
|
||||
{
|
||||
struct bpf_array *array = container_of(map, struct bpf_array, map);
|
||||
int i;
|
||||
@@ -495,6 +495,7 @@ const struct bpf_map_ops prog_array_map_ops = {
|
||||
.map_fd_get_ptr = prog_fd_array_get_ptr,
|
||||
.map_fd_put_ptr = prog_fd_array_put_ptr,
|
||||
.map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem,
|
||||
.map_release_uref = bpf_fd_array_map_clear,
|
||||
};
|
||||
|
||||
static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file,
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include <net/tcp.h>
|
||||
#include <linux/ptr_ring.h>
|
||||
#include <net/inet_common.h>
|
||||
#include <linux/sched/signal.h>
|
||||
|
||||
#define SOCK_CREATE_FLAG_MASK \
|
||||
(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)
|
||||
@@ -325,6 +326,9 @@ retry:
|
||||
if (ret > 0) {
|
||||
if (apply)
|
||||
apply_bytes -= ret;
|
||||
|
||||
sg->offset += ret;
|
||||
sg->length -= ret;
|
||||
size -= ret;
|
||||
offset += ret;
|
||||
if (uncharge)
|
||||
@@ -332,8 +336,6 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
sg->length = size;
|
||||
sg->offset = offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -391,7 +393,8 @@ static void return_mem_sg(struct sock *sk, int bytes, struct sk_msg_buff *md)
|
||||
} while (i != md->sg_end);
|
||||
}
|
||||
|
||||
static void free_bytes_sg(struct sock *sk, int bytes, struct sk_msg_buff *md)
|
||||
static void free_bytes_sg(struct sock *sk, int bytes,
|
||||
struct sk_msg_buff *md, bool charge)
|
||||
{
|
||||
struct scatterlist *sg = md->sg_data;
|
||||
int i = md->sg_start, free;
|
||||
@@ -401,11 +404,13 @@ static void free_bytes_sg(struct sock *sk, int bytes, struct sk_msg_buff *md)
|
||||
if (bytes < free) {
|
||||
sg[i].length -= bytes;
|
||||
sg[i].offset += bytes;
|
||||
sk_mem_uncharge(sk, bytes);
|
||||
if (charge)
|
||||
sk_mem_uncharge(sk, bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
sk_mem_uncharge(sk, sg[i].length);
|
||||
if (charge)
|
||||
sk_mem_uncharge(sk, sg[i].length);
|
||||
put_page(sg_page(&sg[i]));
|
||||
bytes -= sg[i].length;
|
||||
sg[i].length = 0;
|
||||
@@ -416,6 +421,7 @@ static void free_bytes_sg(struct sock *sk, int bytes, struct sk_msg_buff *md)
|
||||
if (i == MAX_SKB_FRAGS)
|
||||
i = 0;
|
||||
}
|
||||
md->sg_start = i;
|
||||
}
|
||||
|
||||
static int free_sg(struct sock *sk, int start, struct sk_msg_buff *md)
|
||||
@@ -523,8 +529,6 @@ static int bpf_tcp_ingress(struct sock *sk, int apply_bytes,
|
||||
i = md->sg_start;
|
||||
|
||||
do {
|
||||
r->sg_data[i] = md->sg_data[i];
|
||||
|
||||
size = (apply && apply_bytes < md->sg_data[i].length) ?
|
||||
apply_bytes : md->sg_data[i].length;
|
||||
|
||||
@@ -535,6 +539,7 @@ static int bpf_tcp_ingress(struct sock *sk, int apply_bytes,
|
||||
}
|
||||
|
||||
sk_mem_charge(sk, size);
|
||||
r->sg_data[i] = md->sg_data[i];
|
||||
r->sg_data[i].length = size;
|
||||
md->sg_data[i].length -= size;
|
||||
md->sg_data[i].offset += size;
|
||||
@@ -575,10 +580,10 @@ static int bpf_tcp_sendmsg_do_redirect(struct sock *sk, int send,
|
||||
struct sk_msg_buff *md,
|
||||
int flags)
|
||||
{
|
||||
bool ingress = !!(md->flags & BPF_F_INGRESS);
|
||||
struct smap_psock *psock;
|
||||
struct scatterlist *sg;
|
||||
int i, err, free = 0;
|
||||
bool ingress = !!(md->flags & BPF_F_INGRESS);
|
||||
int err = 0;
|
||||
|
||||
sg = md->sg_data;
|
||||
|
||||
@@ -606,16 +611,8 @@ static int bpf_tcp_sendmsg_do_redirect(struct sock *sk, int send,
|
||||
out_rcu:
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
i = md->sg_start;
|
||||
while (sg[i].length) {
|
||||
free += sg[i].length;
|
||||
put_page(sg_page(&sg[i]));
|
||||
sg[i].length = 0;
|
||||
i++;
|
||||
if (i == MAX_SKB_FRAGS)
|
||||
i = 0;
|
||||
}
|
||||
return free;
|
||||
free_bytes_sg(NULL, send, md, false);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void bpf_md_init(struct smap_psock *psock)
|
||||
@@ -700,19 +697,26 @@ more_data:
|
||||
err = bpf_tcp_sendmsg_do_redirect(redir, send, m, flags);
|
||||
lock_sock(sk);
|
||||
|
||||
if (unlikely(err < 0)) {
|
||||
free_start_sg(sk, m);
|
||||
psock->sg_size = 0;
|
||||
if (!cork)
|
||||
*copied -= send;
|
||||
} else {
|
||||
psock->sg_size -= send;
|
||||
}
|
||||
|
||||
if (cork) {
|
||||
free_start_sg(sk, m);
|
||||
psock->sg_size = 0;
|
||||
kfree(m);
|
||||
m = NULL;
|
||||
err = 0;
|
||||
}
|
||||
if (unlikely(err))
|
||||
*copied -= err;
|
||||
else
|
||||
psock->sg_size -= send;
|
||||
break;
|
||||
case __SK_DROP:
|
||||
default:
|
||||
free_bytes_sg(sk, send, m);
|
||||
free_bytes_sg(sk, send, m, true);
|
||||
apply_bytes_dec(psock, send);
|
||||
*copied -= send;
|
||||
psock->sg_size -= send;
|
||||
@@ -732,6 +736,26 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bpf_wait_data(struct sock *sk,
|
||||
struct smap_psock *psk, int flags,
|
||||
long timeo, int *err)
|
||||
{
|
||||
int rc;
|
||||
|
||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||
rc = sk_wait_event(sk, &timeo,
|
||||
!list_empty(&psk->ingress) ||
|
||||
!skb_queue_empty(&sk->sk_receive_queue),
|
||||
&wait);
|
||||
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
int nonblock, int flags, int *addr_len)
|
||||
{
|
||||
@@ -755,6 +779,7 @@ static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
||||
|
||||
lock_sock(sk);
|
||||
bytes_ready:
|
||||
while (copied != len) {
|
||||
struct scatterlist *sg;
|
||||
struct sk_msg_buff *md;
|
||||
@@ -809,6 +834,28 @@ static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
if (!copied) {
|
||||
long timeo;
|
||||
int data;
|
||||
int err = 0;
|
||||
|
||||
timeo = sock_rcvtimeo(sk, nonblock);
|
||||
data = bpf_wait_data(sk, psock, flags, timeo, &err);
|
||||
|
||||
if (data) {
|
||||
if (!skb_queue_empty(&sk->sk_receive_queue)) {
|
||||
release_sock(sk);
|
||||
smap_release_sock(psock, sk);
|
||||
copied = tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
|
||||
return copied;
|
||||
}
|
||||
goto bytes_ready;
|
||||
}
|
||||
|
||||
if (err)
|
||||
copied = err;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
smap_release_sock(psock, sk);
|
||||
return copied;
|
||||
@@ -1831,7 +1878,7 @@ static int sock_map_update_elem(struct bpf_map *map,
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sock_map_release(struct bpf_map *map, struct file *map_file)
|
||||
static void sock_map_release(struct bpf_map *map)
|
||||
{
|
||||
struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
|
||||
struct bpf_prog *orig;
|
||||
@@ -1855,7 +1902,7 @@ const struct bpf_map_ops sock_map_ops = {
|
||||
.map_get_next_key = sock_map_get_next_key,
|
||||
.map_update_elem = sock_map_update_elem,
|
||||
.map_delete_elem = sock_map_delete_elem,
|
||||
.map_release = sock_map_release,
|
||||
.map_release_uref = sock_map_release,
|
||||
};
|
||||
|
||||
BPF_CALL_4(bpf_sock_map_update, struct bpf_sock_ops_kern *, bpf_sock,
|
||||
|
@@ -257,8 +257,8 @@ static void bpf_map_free_deferred(struct work_struct *work)
|
||||
static void bpf_map_put_uref(struct bpf_map *map)
|
||||
{
|
||||
if (atomic_dec_and_test(&map->usercnt)) {
|
||||
if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
|
||||
bpf_fd_array_map_clear(map);
|
||||
if (map->ops->map_release_uref)
|
||||
map->ops->map_release_uref(map);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -491,7 +491,7 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
|
||||
if (!uprobe)
|
||||
return NULL;
|
||||
|
||||
uprobe->inode = igrab(inode);
|
||||
uprobe->inode = inode;
|
||||
uprobe->offset = offset;
|
||||
init_rwsem(&uprobe->register_rwsem);
|
||||
init_rwsem(&uprobe->consumer_rwsem);
|
||||
@@ -502,7 +502,6 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
|
||||
if (cur_uprobe) {
|
||||
kfree(uprobe);
|
||||
uprobe = cur_uprobe;
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
return uprobe;
|
||||
@@ -701,7 +700,6 @@ static void delete_uprobe(struct uprobe *uprobe)
|
||||
rb_erase(&uprobe->rb_node, &uprobes_tree);
|
||||
spin_unlock(&uprobes_treelock);
|
||||
RB_CLEAR_NODE(&uprobe->rb_node); /* for uprobe_is_active() */
|
||||
iput(uprobe->inode);
|
||||
put_uprobe(uprobe);
|
||||
}
|
||||
|
||||
@@ -873,7 +871,8 @@ static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *u
|
||||
* tuple). Creation refcount stops uprobe_unregister from freeing the
|
||||
* @uprobe even before the register operation is complete. Creation
|
||||
* refcount is released when the last @uc for the @uprobe
|
||||
* unregisters.
|
||||
* unregisters. Caller of uprobe_register() is required to keep @inode
|
||||
* (and the containing mount) referenced.
|
||||
*
|
||||
* Return errno if it cannot successully install probes
|
||||
* else return 0 (success)
|
||||
|
@@ -1472,7 +1472,8 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
|
||||
{
|
||||
struct module_sect_attr *sattr =
|
||||
container_of(mattr, struct module_sect_attr, mattr);
|
||||
return sprintf(buf, "0x%pK\n", (void *)sattr->address);
|
||||
return sprintf(buf, "0x%px\n", kptr_restrict < 2 ?
|
||||
(void *)sattr->address : NULL);
|
||||
}
|
||||
|
||||
static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
|
||||
|
@@ -704,24 +704,6 @@ static const struct bin_table bin_net_netfilter_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct bin_table bin_net_irda_table[] = {
|
||||
{ CTL_INT, NET_IRDA_DISCOVERY, "discovery" },
|
||||
{ CTL_STR, NET_IRDA_DEVNAME, "devname" },
|
||||
{ CTL_INT, NET_IRDA_DEBUG, "debug" },
|
||||
{ CTL_INT, NET_IRDA_FAST_POLL, "fast_poll_increase" },
|
||||
{ CTL_INT, NET_IRDA_DISCOVERY_SLOTS, "discovery_slots" },
|
||||
{ CTL_INT, NET_IRDA_DISCOVERY_TIMEOUT, "discovery_timeout" },
|
||||
{ CTL_INT, NET_IRDA_SLOT_TIMEOUT, "slot_timeout" },
|
||||
{ CTL_INT, NET_IRDA_MAX_BAUD_RATE, "max_baud_rate" },
|
||||
{ CTL_INT, NET_IRDA_MIN_TX_TURN_TIME, "min_tx_turn_time" },
|
||||
{ CTL_INT, NET_IRDA_MAX_TX_DATA_SIZE, "max_tx_data_size" },
|
||||
{ CTL_INT, NET_IRDA_MAX_TX_WINDOW, "max_tx_window" },
|
||||
{ CTL_INT, NET_IRDA_MAX_NOREPLY_TIME, "max_noreply_time" },
|
||||
{ CTL_INT, NET_IRDA_WARN_NOREPLY_TIME, "warn_noreply_time" },
|
||||
{ CTL_INT, NET_IRDA_LAP_KEEPALIVE_TIME, "lap_keepalive_time" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct bin_table bin_net_table[] = {
|
||||
{ CTL_DIR, NET_CORE, "core", bin_net_core_table },
|
||||
/* NET_ETHER not used */
|
||||
@@ -743,7 +725,7 @@ static const struct bin_table bin_net_table[] = {
|
||||
{ CTL_DIR, NET_LLC, "llc", bin_net_llc_table },
|
||||
{ CTL_DIR, NET_NETFILTER, "netfilter", bin_net_netfilter_table },
|
||||
/* NET_DCCP "dccp" no longer used */
|
||||
{ CTL_DIR, NET_IRDA, "irda", bin_net_irda_table },
|
||||
/* NET_IRDA "irda" no longer used */
|
||||
{ CTL_INT, 2089, "nf_conntrack_max" },
|
||||
{}
|
||||
};
|
||||
|
@@ -90,6 +90,11 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
|
||||
.clockid = CLOCK_REALTIME,
|
||||
.get_time = &ktime_get_real,
|
||||
},
|
||||
{
|
||||
.index = HRTIMER_BASE_BOOTTIME,
|
||||
.clockid = CLOCK_BOOTTIME,
|
||||
.get_time = &ktime_get_boottime,
|
||||
},
|
||||
{
|
||||
.index = HRTIMER_BASE_TAI,
|
||||
.clockid = CLOCK_TAI,
|
||||
@@ -105,6 +110,11 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
|
||||
.clockid = CLOCK_REALTIME,
|
||||
.get_time = &ktime_get_real,
|
||||
},
|
||||
{
|
||||
.index = HRTIMER_BASE_BOOTTIME_SOFT,
|
||||
.clockid = CLOCK_BOOTTIME,
|
||||
.get_time = &ktime_get_boottime,
|
||||
},
|
||||
{
|
||||
.index = HRTIMER_BASE_TAI_SOFT,
|
||||
.clockid = CLOCK_TAI,
|
||||
@@ -119,7 +129,7 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
|
||||
|
||||
[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME,
|
||||
[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC,
|
||||
[CLOCK_BOOTTIME] = HRTIMER_BASE_MONOTONIC,
|
||||
[CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME,
|
||||
[CLOCK_TAI] = HRTIMER_BASE_TAI,
|
||||
};
|
||||
|
||||
@@ -571,12 +581,14 @@ __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_
|
||||
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
|
||||
{
|
||||
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
|
||||
ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
|
||||
ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
|
||||
|
||||
ktime_t now = ktime_get_update_offsets_now(&base->clock_was_set_seq,
|
||||
offs_real, offs_tai);
|
||||
offs_real, offs_boot, offs_tai);
|
||||
|
||||
base->clock_base[HRTIMER_BASE_REALTIME_SOFT].offset = *offs_real;
|
||||
base->clock_base[HRTIMER_BASE_BOOTTIME_SOFT].offset = *offs_boot;
|
||||
base->clock_base[HRTIMER_BASE_TAI_SOFT].offset = *offs_tai;
|
||||
|
||||
return now;
|
||||
|
@@ -83,8 +83,6 @@ int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp)
|
||||
case CLOCK_BOOTTIME:
|
||||
get_monotonic_boottime64(tp);
|
||||
break;
|
||||
case CLOCK_MONOTONIC_ACTIVE:
|
||||
ktime_get_active_ts64(tp);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -252,16 +252,15 @@ static int posix_get_coarse_res(const clockid_t which_clock, struct timespec64 *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp)
|
||||
static int posix_get_boottime(const clockid_t which_clock, struct timespec64 *tp)
|
||||
{
|
||||
timekeeping_clocktai64(tp);
|
||||
get_monotonic_boottime64(tp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int posix_get_monotonic_active(clockid_t which_clock,
|
||||
struct timespec64 *tp)
|
||||
static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp)
|
||||
{
|
||||
ktime_get_active_ts64(tp);
|
||||
timekeeping_clocktai64(tp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1317,9 +1316,19 @@ static const struct k_clock clock_tai = {
|
||||
.timer_arm = common_hrtimer_arm,
|
||||
};
|
||||
|
||||
static const struct k_clock clock_monotonic_active = {
|
||||
static const struct k_clock clock_boottime = {
|
||||
.clock_getres = posix_get_hrtimer_res,
|
||||
.clock_get = posix_get_monotonic_active,
|
||||
.clock_get = posix_get_boottime,
|
||||
.nsleep = common_nsleep,
|
||||
.timer_create = common_timer_create,
|
||||
.timer_set = common_timer_set,
|
||||
.timer_get = common_timer_get,
|
||||
.timer_del = common_timer_del,
|
||||
.timer_rearm = common_hrtimer_rearm,
|
||||
.timer_forward = common_hrtimer_forward,
|
||||
.timer_remaining = common_hrtimer_remaining,
|
||||
.timer_try_to_cancel = common_hrtimer_try_to_cancel,
|
||||
.timer_arm = common_hrtimer_arm,
|
||||
};
|
||||
|
||||
static const struct k_clock * const posix_clocks[] = {
|
||||
@@ -1330,11 +1339,10 @@ static const struct k_clock * const posix_clocks[] = {
|
||||
[CLOCK_MONOTONIC_RAW] = &clock_monotonic_raw,
|
||||
[CLOCK_REALTIME_COARSE] = &clock_realtime_coarse,
|
||||
[CLOCK_MONOTONIC_COARSE] = &clock_monotonic_coarse,
|
||||
[CLOCK_BOOTTIME] = &clock_monotonic,
|
||||
[CLOCK_BOOTTIME] = &clock_boottime,
|
||||
[CLOCK_REALTIME_ALARM] = &alarm_clock,
|
||||
[CLOCK_BOOTTIME_ALARM] = &alarm_clock,
|
||||
[CLOCK_TAI] = &clock_tai,
|
||||
[CLOCK_MONOTONIC_ACTIVE] = &clock_monotonic_active,
|
||||
};
|
||||
|
||||
static const struct k_clock *clockid_to_kclock(const clockid_t id)
|
||||
|
@@ -419,19 +419,6 @@ void tick_suspend_local(void)
|
||||
clockevents_shutdown(td->evtdev);
|
||||
}
|
||||
|
||||
static void tick_forward_next_period(void)
|
||||
{
|
||||
ktime_t delta, now = ktime_get();
|
||||
u64 n;
|
||||
|
||||
delta = ktime_sub(now, tick_next_period);
|
||||
n = ktime_divns(delta, tick_period);
|
||||
tick_next_period += n * tick_period;
|
||||
if (tick_next_period < now)
|
||||
tick_next_period += tick_period;
|
||||
tick_sched_forward_next_period();
|
||||
}
|
||||
|
||||
/**
|
||||
* tick_resume_local - Resume the local tick device
|
||||
*
|
||||
@@ -444,8 +431,6 @@ void tick_resume_local(void)
|
||||
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
|
||||
bool broadcast = tick_resume_check_broadcast();
|
||||
|
||||
tick_forward_next_period();
|
||||
|
||||
clockevents_tick_resume(td->evtdev);
|
||||
if (!broadcast) {
|
||||
if (td->mode == TICKDEV_MODE_PERIODIC)
|
||||
|
@@ -141,12 +141,6 @@ static inline void tick_check_oneshot_broadcast_this_cpu(void) { }
|
||||
static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); }
|
||||
#endif /* !(BROADCAST && ONESHOT) */
|
||||
|
||||
#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
|
||||
extern void tick_sched_forward_next_period(void);
|
||||
#else
|
||||
static inline void tick_sched_forward_next_period(void) { }
|
||||
#endif
|
||||
|
||||
/* NO_HZ_FULL internal */
|
||||
#ifdef CONFIG_NO_HZ_FULL
|
||||
extern void tick_nohz_init(void);
|
||||
|
@@ -51,15 +51,6 @@ struct tick_sched *tick_get_tick_sched(int cpu)
|
||||
*/
|
||||
static ktime_t last_jiffies_update;
|
||||
|
||||
/*
|
||||
* Called after resume. Make sure that jiffies are not fast forwarded due to
|
||||
* clock monotonic being forwarded by the suspended time.
|
||||
*/
|
||||
void tick_sched_forward_next_period(void)
|
||||
{
|
||||
last_jiffies_update = tick_next_period;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with interrupts disabled !
|
||||
*/
|
||||
@@ -804,12 +795,12 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
|
||||
return;
|
||||
}
|
||||
|
||||
hrtimer_set_expires(&ts->sched_timer, tick);
|
||||
|
||||
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
|
||||
hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED);
|
||||
else
|
||||
if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
|
||||
hrtimer_start(&ts->sched_timer, tick, HRTIMER_MODE_ABS_PINNED);
|
||||
} else {
|
||||
hrtimer_set_expires(&ts->sched_timer, tick);
|
||||
tick_program_event(tick, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void tick_nohz_retain_tick(struct tick_sched *ts)
|
||||
|
@@ -138,12 +138,7 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
|
||||
|
||||
static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
|
||||
{
|
||||
/* Update both bases so mono and raw stay coupled. */
|
||||
tk->tkr_mono.base += delta;
|
||||
tk->tkr_raw.base += delta;
|
||||
|
||||
/* Accumulate time spent in suspend */
|
||||
tk->time_suspended += delta;
|
||||
tk->offs_boot = ktime_add(tk->offs_boot, delta);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -473,6 +468,36 @@ u64 ktime_get_raw_fast_ns(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns);
|
||||
|
||||
/**
|
||||
* ktime_get_boot_fast_ns - NMI safe and fast access to boot clock.
|
||||
*
|
||||
* To keep it NMI safe since we're accessing from tracing, we're not using a
|
||||
* separate timekeeper with updates to monotonic clock and boot offset
|
||||
* protected with seqlocks. This has the following minor side effects:
|
||||
*
|
||||
* (1) Its possible that a timestamp be taken after the boot offset is updated
|
||||
* but before the timekeeper is updated. If this happens, the new boot offset
|
||||
* is added to the old timekeeping making the clock appear to update slightly
|
||||
* earlier:
|
||||
* CPU 0 CPU 1
|
||||
* timekeeping_inject_sleeptime64()
|
||||
* __timekeeping_inject_sleeptime(tk, delta);
|
||||
* timestamp();
|
||||
* timekeeping_update(tk, TK_CLEAR_NTP...);
|
||||
*
|
||||
* (2) On 32-bit systems, the 64-bit boot offset (tk->offs_boot) may be
|
||||
* partially updated. Since the tk->offs_boot update is a rare event, this
|
||||
* should be a rare occurrence which postprocessing should be able to handle.
|
||||
*/
|
||||
u64 notrace ktime_get_boot_fast_ns(void)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
|
||||
return (ktime_get_mono_fast_ns() + ktime_to_ns(tk->offs_boot));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
|
||||
|
||||
|
||||
/*
|
||||
* See comment for __ktime_get_fast_ns() vs. timestamp ordering
|
||||
*/
|
||||
@@ -764,6 +789,7 @@ EXPORT_SYMBOL_GPL(ktime_get_resolution_ns);
|
||||
|
||||
static ktime_t *offsets[TK_OFFS_MAX] = {
|
||||
[TK_OFFS_REAL] = &tk_core.timekeeper.offs_real,
|
||||
[TK_OFFS_BOOT] = &tk_core.timekeeper.offs_boot,
|
||||
[TK_OFFS_TAI] = &tk_core.timekeeper.offs_tai,
|
||||
};
|
||||
|
||||
@@ -860,39 +886,6 @@ void ktime_get_ts64(struct timespec64 *ts)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ktime_get_ts64);
|
||||
|
||||
/**
|
||||
* ktime_get_active_ts64 - Get the active non-suspended monotonic clock
|
||||
* @ts: pointer to timespec variable
|
||||
*
|
||||
* The function calculates the monotonic clock from the realtime clock and
|
||||
* the wall_to_monotonic offset, subtracts the accumulated suspend time and
|
||||
* stores the result in normalized timespec64 format in the variable
|
||||
* pointed to by @ts.
|
||||
*/
|
||||
void ktime_get_active_ts64(struct timespec64 *ts)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
struct timespec64 tomono, tsusp;
|
||||
u64 nsec, nssusp;
|
||||
unsigned int seq;
|
||||
|
||||
WARN_ON(timekeeping_suspended);
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
ts->tv_sec = tk->xtime_sec;
|
||||
nsec = timekeeping_get_ns(&tk->tkr_mono);
|
||||
tomono = tk->wall_to_monotonic;
|
||||
nssusp = tk->time_suspended;
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
ts->tv_sec += tomono.tv_sec;
|
||||
ts->tv_nsec = 0;
|
||||
timespec64_add_ns(ts, nsec + tomono.tv_nsec);
|
||||
tsusp = ns_to_timespec64(nssusp);
|
||||
*ts = timespec64_sub(*ts, tsusp);
|
||||
}
|
||||
|
||||
/**
|
||||
* ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
|
||||
*
|
||||
@@ -1593,6 +1586,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
|
||||
return;
|
||||
}
|
||||
tk_xtime_add(tk, delta);
|
||||
tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *delta));
|
||||
tk_update_sleep_time(tk, timespec64_to_ktime(*delta));
|
||||
tk_debug_account_sleep_time(delta);
|
||||
}
|
||||
@@ -2125,7 +2119,7 @@ out:
|
||||
void getboottime64(struct timespec64 *ts)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
ktime_t t = ktime_sub(tk->offs_real, tk->time_suspended);
|
||||
ktime_t t = ktime_sub(tk->offs_real, tk->offs_boot);
|
||||
|
||||
*ts = ktime_to_timespec64(t);
|
||||
}
|
||||
@@ -2188,6 +2182,7 @@ void do_timer(unsigned long ticks)
|
||||
* ktime_get_update_offsets_now - hrtimer helper
|
||||
* @cwsseq: pointer to check and store the clock was set sequence number
|
||||
* @offs_real: pointer to storage for monotonic -> realtime offset
|
||||
* @offs_boot: pointer to storage for monotonic -> boottime offset
|
||||
* @offs_tai: pointer to storage for monotonic -> clock tai offset
|
||||
*
|
||||
* Returns current monotonic time and updates the offsets if the
|
||||
@@ -2197,7 +2192,7 @@ void do_timer(unsigned long ticks)
|
||||
* Called from hrtimer_interrupt() or retrigger_next_event()
|
||||
*/
|
||||
ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
|
||||
ktime_t *offs_tai)
|
||||
ktime_t *offs_boot, ktime_t *offs_tai)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
unsigned int seq;
|
||||
@@ -2214,6 +2209,7 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
|
||||
if (*cwsseq != tk->clock_was_set_seq) {
|
||||
*cwsseq = tk->clock_was_set_seq;
|
||||
*offs_real = tk->offs_real;
|
||||
*offs_boot = tk->offs_boot;
|
||||
*offs_tai = tk->offs_tai;
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq,
|
||||
ktime_t *offs_real,
|
||||
ktime_t *offs_boot,
|
||||
ktime_t *offs_tai);
|
||||
|
||||
extern int timekeeping_valid_for_hres(void);
|
||||
|
@@ -1165,7 +1165,7 @@ static struct {
|
||||
{ trace_clock, "perf", 1 },
|
||||
{ ktime_get_mono_fast_ns, "mono", 1 },
|
||||
{ ktime_get_raw_fast_ns, "mono_raw", 1 },
|
||||
{ ktime_get_mono_fast_ns, "boot", 1 },
|
||||
{ ktime_get_boot_fast_ns, "boot", 1 },
|
||||
ARCH_TRACE_CLOCKS
|
||||
};
|
||||
|
||||
|
@@ -2466,6 +2466,7 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
|
||||
else if (strcmp(modifier, "usecs") == 0)
|
||||
*flags |= HIST_FIELD_FL_TIMESTAMP_USECS;
|
||||
else {
|
||||
hist_err("Invalid field modifier: ", modifier);
|
||||
field = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
@@ -2481,6 +2482,7 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
|
||||
else {
|
||||
field = trace_find_event_field(file->event_call, field_name);
|
||||
if (!field || !field->size) {
|
||||
hist_err("Couldn't find field: ", field_name);
|
||||
field = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
@@ -4913,6 +4915,16 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
|
||||
seq_printf(m, "%s", field_name);
|
||||
} else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP)
|
||||
seq_puts(m, "common_timestamp");
|
||||
|
||||
if (hist_field->flags) {
|
||||
if (!(hist_field->flags & HIST_FIELD_FL_VAR_REF) &&
|
||||
!(hist_field->flags & HIST_FIELD_FL_EXPR)) {
|
||||
const char *flags = get_hist_field_flags(hist_field);
|
||||
|
||||
if (flags)
|
||||
seq_printf(m, ".%s", flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int event_hist_trigger_print(struct seq_file *m,
|
||||
|
@@ -55,6 +55,7 @@ struct trace_uprobe {
|
||||
struct list_head list;
|
||||
struct trace_uprobe_filter filter;
|
||||
struct uprobe_consumer consumer;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
char *filename;
|
||||
unsigned long offset;
|
||||
@@ -289,7 +290,7 @@ static void free_trace_uprobe(struct trace_uprobe *tu)
|
||||
for (i = 0; i < tu->tp.nr_args; i++)
|
||||
traceprobe_free_probe_arg(&tu->tp.args[i]);
|
||||
|
||||
iput(tu->inode);
|
||||
path_put(&tu->path);
|
||||
kfree(tu->tp.call.class->system);
|
||||
kfree(tu->tp.call.name);
|
||||
kfree(tu->filename);
|
||||
@@ -363,7 +364,6 @@ end:
|
||||
static int create_trace_uprobe(int argc, char **argv)
|
||||
{
|
||||
struct trace_uprobe *tu;
|
||||
struct inode *inode;
|
||||
char *arg, *event, *group, *filename;
|
||||
char buf[MAX_EVENT_NAME_LEN];
|
||||
struct path path;
|
||||
@@ -371,7 +371,6 @@ static int create_trace_uprobe(int argc, char **argv)
|
||||
bool is_delete, is_return;
|
||||
int i, ret;
|
||||
|
||||
inode = NULL;
|
||||
ret = 0;
|
||||
is_delete = false;
|
||||
is_return = false;
|
||||
@@ -437,21 +436,16 @@ static int create_trace_uprobe(int argc, char **argv)
|
||||
}
|
||||
/* Find the last occurrence, in case the path contains ':' too. */
|
||||
arg = strrchr(argv[1], ':');
|
||||
if (!arg) {
|
||||
ret = -EINVAL;
|
||||
goto fail_address_parse;
|
||||
}
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
*arg++ = '\0';
|
||||
filename = argv[1];
|
||||
ret = kern_path(filename, LOOKUP_FOLLOW, &path);
|
||||
if (ret)
|
||||
goto fail_address_parse;
|
||||
return ret;
|
||||
|
||||
inode = igrab(d_real_inode(path.dentry));
|
||||
path_put(&path);
|
||||
|
||||
if (!inode || !S_ISREG(inode->i_mode)) {
|
||||
if (!d_is_reg(path.dentry)) {
|
||||
ret = -EINVAL;
|
||||
goto fail_address_parse;
|
||||
}
|
||||
@@ -490,7 +484,7 @@ static int create_trace_uprobe(int argc, char **argv)
|
||||
goto fail_address_parse;
|
||||
}
|
||||
tu->offset = offset;
|
||||
tu->inode = inode;
|
||||
tu->path = path;
|
||||
tu->filename = kstrdup(filename, GFP_KERNEL);
|
||||
|
||||
if (!tu->filename) {
|
||||
@@ -558,7 +552,7 @@ error:
|
||||
return ret;
|
||||
|
||||
fail_address_parse:
|
||||
iput(inode);
|
||||
path_put(&path);
|
||||
|
||||
pr_info("Failed to parse address or file.\n");
|
||||
|
||||
@@ -922,6 +916,7 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
|
||||
goto err_flags;
|
||||
|
||||
tu->consumer.filter = filter;
|
||||
tu->inode = d_real_inode(tu->path.dentry);
|
||||
ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
|
||||
if (ret)
|
||||
goto err_buffer;
|
||||
@@ -967,6 +962,7 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
|
||||
WARN_ON(!uprobe_filter_is_empty(&tu->filter));
|
||||
|
||||
uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
|
||||
tu->inode = NULL;
|
||||
tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
|
||||
|
||||
uprobe_buffer_disable();
|
||||
@@ -1337,7 +1333,6 @@ struct trace_event_call *
|
||||
create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
|
||||
{
|
||||
struct trace_uprobe *tu;
|
||||
struct inode *inode;
|
||||
struct path path;
|
||||
int ret;
|
||||
|
||||
@@ -1345,11 +1340,8 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
inode = igrab(d_inode(path.dentry));
|
||||
path_put(&path);
|
||||
|
||||
if (!inode || !S_ISREG(inode->i_mode)) {
|
||||
iput(inode);
|
||||
if (!d_is_reg(path.dentry)) {
|
||||
path_put(&path);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
@@ -1364,11 +1356,12 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
|
||||
if (IS_ERR(tu)) {
|
||||
pr_info("Failed to allocate trace_uprobe.(%d)\n",
|
||||
(int)PTR_ERR(tu));
|
||||
path_put(&path);
|
||||
return ERR_CAST(tu);
|
||||
}
|
||||
|
||||
tu->offset = offs;
|
||||
tu->inode = inode;
|
||||
tu->path = path;
|
||||
tu->filename = kstrdup(name, GFP_KERNEL);
|
||||
init_trace_event_call(tu, &tu->tp.call);
|
||||
|
||||
|
@@ -207,7 +207,7 @@ static int tracepoint_add_func(struct tracepoint *tp,
|
||||
lockdep_is_held(&tracepoints_mutex));
|
||||
old = func_add(&tp_funcs, func, prio);
|
||||
if (IS_ERR(old)) {
|
||||
WARN_ON_ONCE(1);
|
||||
WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM);
|
||||
return PTR_ERR(old);
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ static int tracepoint_remove_func(struct tracepoint *tp,
|
||||
lockdep_is_held(&tracepoints_mutex));
|
||||
old = func_remove(&tp_funcs, func);
|
||||
if (IS_ERR(old)) {
|
||||
WARN_ON_ONCE(1);
|
||||
WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM);
|
||||
return PTR_ERR(old);
|
||||
}
|
||||
|
||||
|
在新工单中引用
屏蔽一个用户