mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
Merge tag 'v4.9.147' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into odroidn2-4.9.y
This is the 4.9.147 stable release
This commit is contained in:
@@ -2919,6 +2919,9 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
goto process_bpf_exit;
|
||||
}
|
||||
|
||||
if (signal_pending(current))
|
||||
return -EAGAIN;
|
||||
|
||||
if (need_resched())
|
||||
cond_resched();
|
||||
|
||||
|
||||
@@ -75,6 +75,18 @@
|
||||
#define MAX_NODES 4
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The pending bit spinning loop count.
|
||||
* This heuristic is used to limit the number of lockword accesses
|
||||
* made by atomic_cond_read_relaxed when waiting for the lock to
|
||||
* transition out of the "== _Q_PENDING_VAL" state. We don't spin
|
||||
* indefinitely because there's no guarantee that we'll make forward
|
||||
* progress.
|
||||
*/
|
||||
#ifndef _Q_PENDING_LOOPS
|
||||
#define _Q_PENDING_LOOPS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Per-CPU queue node structures; we can never have more than 4 nested
|
||||
* contexts: task, softirq, hardirq, nmi.
|
||||
@@ -113,41 +125,18 @@ static inline __pure struct mcs_spinlock *decode_tail(u32 tail)
|
||||
|
||||
#define _Q_LOCKED_PENDING_MASK (_Q_LOCKED_MASK | _Q_PENDING_MASK)
|
||||
|
||||
/*
|
||||
* By using the whole 2nd least significant byte for the pending bit, we
|
||||
* can allow better optimization of the lock acquisition for the pending
|
||||
* bit holder.
|
||||
*
|
||||
* This internal structure is also used by the set_locked function which
|
||||
* is not restricted to _Q_PENDING_BITS == 8.
|
||||
*/
|
||||
struct __qspinlock {
|
||||
union {
|
||||
atomic_t val;
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
struct {
|
||||
u8 locked;
|
||||
u8 pending;
|
||||
};
|
||||
struct {
|
||||
u16 locked_pending;
|
||||
u16 tail;
|
||||
};
|
||||
#else
|
||||
struct {
|
||||
u16 tail;
|
||||
u16 locked_pending;
|
||||
};
|
||||
struct {
|
||||
u8 reserved[2];
|
||||
u8 pending;
|
||||
u8 locked;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
#if _Q_PENDING_BITS == 8
|
||||
/**
|
||||
* clear_pending - clear the pending bit.
|
||||
* @lock: Pointer to queued spinlock structure
|
||||
*
|
||||
* *,1,* -> *,0,*
|
||||
*/
|
||||
static __always_inline void clear_pending(struct qspinlock *lock)
|
||||
{
|
||||
WRITE_ONCE(lock->pending, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear_pending_set_locked - take ownership and clear the pending bit.
|
||||
* @lock: Pointer to queued spinlock structure
|
||||
@@ -158,9 +147,7 @@ struct __qspinlock {
|
||||
*/
|
||||
static __always_inline void clear_pending_set_locked(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
WRITE_ONCE(l->locked_pending, _Q_LOCKED_VAL);
|
||||
WRITE_ONCE(lock->locked_pending, _Q_LOCKED_VAL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -169,24 +156,33 @@ static __always_inline void clear_pending_set_locked(struct qspinlock *lock)
|
||||
* @tail : The new queue tail code word
|
||||
* Return: The previous queue tail code word
|
||||
*
|
||||
* xchg(lock, tail)
|
||||
* xchg(lock, tail), which heads an address dependency
|
||||
*
|
||||
* p,*,* -> n,*,* ; prev = xchg(lock, node)
|
||||
*/
|
||||
static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
/*
|
||||
* Use release semantics to make sure that the MCS node is properly
|
||||
* initialized before changing the tail code.
|
||||
*/
|
||||
return (u32)xchg_release(&l->tail,
|
||||
return (u32)xchg_release(&lock->tail,
|
||||
tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET;
|
||||
}
|
||||
|
||||
#else /* _Q_PENDING_BITS == 8 */
|
||||
|
||||
/**
|
||||
* clear_pending - clear the pending bit.
|
||||
* @lock: Pointer to queued spinlock structure
|
||||
*
|
||||
* *,1,* -> *,0,*
|
||||
*/
|
||||
static __always_inline void clear_pending(struct qspinlock *lock)
|
||||
{
|
||||
atomic_andnot(_Q_PENDING_VAL, &lock->val);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear_pending_set_locked - take ownership and clear the pending bit.
|
||||
* @lock: Pointer to queued spinlock structure
|
||||
@@ -228,6 +224,20 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
|
||||
}
|
||||
#endif /* _Q_PENDING_BITS == 8 */
|
||||
|
||||
/**
|
||||
* queued_fetch_set_pending_acquire - fetch the whole lock value and set pending
|
||||
* @lock : Pointer to queued spinlock structure
|
||||
* Return: The previous lock value
|
||||
*
|
||||
* *,*,* -> *,1,*
|
||||
*/
|
||||
#ifndef queued_fetch_set_pending_acquire
|
||||
static __always_inline u32 queued_fetch_set_pending_acquire(struct qspinlock *lock)
|
||||
{
|
||||
return atomic_fetch_or_acquire(_Q_PENDING_VAL, &lock->val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* set_locked - Set the lock bit and own the lock
|
||||
* @lock: Pointer to queued spinlock structure
|
||||
@@ -236,9 +246,7 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
|
||||
*/
|
||||
static __always_inline void set_locked(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
WRITE_ONCE(l->locked, _Q_LOCKED_VAL);
|
||||
WRITE_ONCE(lock->locked, _Q_LOCKED_VAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -410,7 +418,7 @@ EXPORT_SYMBOL(queued_spin_unlock_wait);
|
||||
void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
|
||||
{
|
||||
struct mcs_spinlock *prev, *next, *node;
|
||||
u32 new, old, tail;
|
||||
u32 old, tail;
|
||||
int idx;
|
||||
|
||||
BUILD_BUG_ON(CONFIG_NR_CPUS >= (1U << _Q_TAIL_CPU_BITS));
|
||||
@@ -422,65 +430,58 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
|
||||
return;
|
||||
|
||||
/*
|
||||
* wait for in-progress pending->locked hand-overs
|
||||
* Wait for in-progress pending->locked hand-overs with a bounded
|
||||
* number of spins so that we guarantee forward progress.
|
||||
*
|
||||
* 0,1,0 -> 0,0,1
|
||||
*/
|
||||
if (val == _Q_PENDING_VAL) {
|
||||
while ((val = atomic_read(&lock->val)) == _Q_PENDING_VAL)
|
||||
cpu_relax();
|
||||
int cnt = _Q_PENDING_LOOPS;
|
||||
val = smp_cond_load_acquire(&lock->val.counter,
|
||||
(VAL != _Q_PENDING_VAL) || !cnt--);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we observe any contention; queue.
|
||||
*/
|
||||
if (val & ~_Q_LOCKED_MASK)
|
||||
goto queue;
|
||||
|
||||
/*
|
||||
* trylock || pending
|
||||
*
|
||||
* 0,0,0 -> 0,0,1 ; trylock
|
||||
* 0,0,1 -> 0,1,1 ; pending
|
||||
*/
|
||||
for (;;) {
|
||||
/*
|
||||
* If we observe any contention; queue.
|
||||
*/
|
||||
if (val & ~_Q_LOCKED_MASK)
|
||||
goto queue;
|
||||
val = queued_fetch_set_pending_acquire(lock);
|
||||
|
||||
new = _Q_LOCKED_VAL;
|
||||
if (val == new)
|
||||
new |= _Q_PENDING_VAL;
|
||||
|
||||
/*
|
||||
* Acquire semantic is required here as the function may
|
||||
* return immediately if the lock was free.
|
||||
*/
|
||||
old = atomic_cmpxchg_acquire(&lock->val, val, new);
|
||||
if (old == val)
|
||||
break;
|
||||
|
||||
val = old;
|
||||
/*
|
||||
* If we observe any contention; undo and queue.
|
||||
*/
|
||||
if (unlikely(val & ~_Q_LOCKED_MASK)) {
|
||||
if (!(val & _Q_PENDING_MASK))
|
||||
clear_pending(lock);
|
||||
goto queue;
|
||||
}
|
||||
|
||||
/*
|
||||
* we won the trylock
|
||||
*/
|
||||
if (new == _Q_LOCKED_VAL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* we're pending, wait for the owner to go away.
|
||||
* We're pending, wait for the owner to go away.
|
||||
*
|
||||
* *,1,1 -> *,1,0
|
||||
* 0,1,1 -> 0,1,0
|
||||
*
|
||||
* this wait loop must be a load-acquire such that we match the
|
||||
* store-release that clears the locked bit and create lock
|
||||
* sequentiality; this is because not all clear_pending_set_locked()
|
||||
* implementations imply full barriers.
|
||||
* sequentiality; this is because not all
|
||||
* clear_pending_set_locked() implementations imply full
|
||||
* barriers.
|
||||
*/
|
||||
smp_cond_load_acquire(&lock->val.counter, !(VAL & _Q_LOCKED_MASK));
|
||||
if (val & _Q_LOCKED_MASK)
|
||||
smp_cond_load_acquire(&lock->val.counter, !(VAL & _Q_LOCKED_MASK));
|
||||
|
||||
/*
|
||||
* take ownership and clear the pending bit.
|
||||
*
|
||||
* *,1,0 -> *,0,1
|
||||
* 0,1,0 -> 0,0,1
|
||||
*/
|
||||
clear_pending_set_locked(lock);
|
||||
return;
|
||||
@@ -532,16 +533,15 @@ queue:
|
||||
*/
|
||||
if (old & _Q_TAIL_MASK) {
|
||||
prev = decode_tail(old);
|
||||
/*
|
||||
* The above xchg_tail() is also a load of @lock which generates,
|
||||
* through decode_tail(), a pointer.
|
||||
*
|
||||
* The address dependency matches the RELEASE of xchg_tail()
|
||||
* such that the access to @prev must happen after.
|
||||
*/
|
||||
smp_read_barrier_depends();
|
||||
|
||||
WRITE_ONCE(prev->next, node);
|
||||
/*
|
||||
* We must ensure that the stores to @node are observed before
|
||||
* the write to prev->next. The address dependency from
|
||||
* xchg_tail is not sufficient to ensure this because the read
|
||||
* component of xchg_tail is unordered with respect to the
|
||||
* initialisation of @node.
|
||||
*/
|
||||
smp_store_release(&prev->next, node);
|
||||
|
||||
pv_wait_node(node, prev);
|
||||
arch_mcs_spin_lock_contended(&node->locked);
|
||||
@@ -588,30 +588,27 @@ locked:
|
||||
* claim the lock:
|
||||
*
|
||||
* n,0,0 -> 0,0,1 : lock, uncontended
|
||||
* *,0,0 -> *,0,1 : lock, contended
|
||||
* *,*,0 -> *,*,1 : lock, contended
|
||||
*
|
||||
* If the queue head is the only one in the queue (lock value == tail),
|
||||
* clear the tail code and grab the lock. Otherwise, we only need
|
||||
* to grab the lock.
|
||||
* If the queue head is the only one in the queue (lock value == tail)
|
||||
* and nobody is pending, clear the tail code and grab the lock.
|
||||
* Otherwise, we only need to grab the lock.
|
||||
*/
|
||||
for (;;) {
|
||||
/* In the PV case we might already have _Q_LOCKED_VAL set */
|
||||
if ((val & _Q_TAIL_MASK) != tail) {
|
||||
set_locked(lock);
|
||||
break;
|
||||
}
|
||||
|
||||
/* In the PV case we might already have _Q_LOCKED_VAL set */
|
||||
if ((val & _Q_TAIL_MASK) == tail) {
|
||||
/*
|
||||
* The smp_cond_load_acquire() call above has provided the
|
||||
* necessary acquire semantics required for locking. At most
|
||||
* two iterations of this loop may be ran.
|
||||
* necessary acquire semantics required for locking.
|
||||
*/
|
||||
old = atomic_cmpxchg_relaxed(&lock->val, val, _Q_LOCKED_VAL);
|
||||
if (old == val)
|
||||
goto release; /* No contention */
|
||||
|
||||
val = old;
|
||||
goto release; /* No contention */
|
||||
}
|
||||
|
||||
/* Either somebody is queued behind us or _Q_PENDING_VAL is set */
|
||||
set_locked(lock);
|
||||
|
||||
/*
|
||||
* contended path; wait for next if not observed yet, release.
|
||||
*/
|
||||
|
||||
@@ -69,10 +69,8 @@ struct pv_node {
|
||||
#define queued_spin_trylock(l) pv_queued_spin_steal_lock(l)
|
||||
static inline bool pv_queued_spin_steal_lock(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
if (!(atomic_read(&lock->val) & _Q_LOCKED_PENDING_MASK) &&
|
||||
(cmpxchg(&l->locked, 0, _Q_LOCKED_VAL) == 0)) {
|
||||
(cmpxchg(&lock->locked, 0, _Q_LOCKED_VAL) == 0)) {
|
||||
qstat_inc(qstat_pv_lock_stealing, true);
|
||||
return true;
|
||||
}
|
||||
@@ -87,16 +85,7 @@ static inline bool pv_queued_spin_steal_lock(struct qspinlock *lock)
|
||||
#if _Q_PENDING_BITS == 8
|
||||
static __always_inline void set_pending(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
WRITE_ONCE(l->pending, 1);
|
||||
}
|
||||
|
||||
static __always_inline void clear_pending(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
WRITE_ONCE(l->pending, 0);
|
||||
WRITE_ONCE(lock->pending, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,10 +95,8 @@ static __always_inline void clear_pending(struct qspinlock *lock)
|
||||
*/
|
||||
static __always_inline int trylock_clear_pending(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
return !READ_ONCE(l->locked) &&
|
||||
(cmpxchg(&l->locked_pending, _Q_PENDING_VAL, _Q_LOCKED_VAL)
|
||||
return !READ_ONCE(lock->locked) &&
|
||||
(cmpxchg(&lock->locked_pending, _Q_PENDING_VAL, _Q_LOCKED_VAL)
|
||||
== _Q_PENDING_VAL);
|
||||
}
|
||||
#else /* _Q_PENDING_BITS == 8 */
|
||||
@@ -118,11 +105,6 @@ static __always_inline void set_pending(struct qspinlock *lock)
|
||||
atomic_or(_Q_PENDING_VAL, &lock->val);
|
||||
}
|
||||
|
||||
static __always_inline void clear_pending(struct qspinlock *lock)
|
||||
{
|
||||
atomic_andnot(_Q_PENDING_VAL, &lock->val);
|
||||
}
|
||||
|
||||
static __always_inline int trylock_clear_pending(struct qspinlock *lock)
|
||||
{
|
||||
int val = atomic_read(&lock->val);
|
||||
@@ -353,7 +335,6 @@ static void pv_wait_node(struct mcs_spinlock *node, struct mcs_spinlock *prev)
|
||||
static void pv_kick_node(struct qspinlock *lock, struct mcs_spinlock *node)
|
||||
{
|
||||
struct pv_node *pn = (struct pv_node *)node;
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
|
||||
/*
|
||||
* If the vCPU is indeed halted, advance its state to match that of
|
||||
@@ -372,7 +353,7 @@ static void pv_kick_node(struct qspinlock *lock, struct mcs_spinlock *node)
|
||||
* the hash table later on at unlock time, no atomic instruction is
|
||||
* needed.
|
||||
*/
|
||||
WRITE_ONCE(l->locked, _Q_SLOW_VAL);
|
||||
WRITE_ONCE(lock->locked, _Q_SLOW_VAL);
|
||||
(void)pv_hash(lock, pn);
|
||||
}
|
||||
|
||||
@@ -387,7 +368,6 @@ static u32
|
||||
pv_wait_head_or_lock(struct qspinlock *lock, struct mcs_spinlock *node)
|
||||
{
|
||||
struct pv_node *pn = (struct pv_node *)node;
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
struct qspinlock **lp = NULL;
|
||||
int waitcnt = 0;
|
||||
int loop;
|
||||
@@ -438,13 +418,13 @@ pv_wait_head_or_lock(struct qspinlock *lock, struct mcs_spinlock *node)
|
||||
*
|
||||
* Matches the smp_rmb() in __pv_queued_spin_unlock().
|
||||
*/
|
||||
if (xchg(&l->locked, _Q_SLOW_VAL) == 0) {
|
||||
if (xchg(&lock->locked, _Q_SLOW_VAL) == 0) {
|
||||
/*
|
||||
* The lock was free and now we own the lock.
|
||||
* Change the lock value back to _Q_LOCKED_VAL
|
||||
* and unhash the table.
|
||||
*/
|
||||
WRITE_ONCE(l->locked, _Q_LOCKED_VAL);
|
||||
WRITE_ONCE(lock->locked, _Q_LOCKED_VAL);
|
||||
WRITE_ONCE(*lp, NULL);
|
||||
goto gotlock;
|
||||
}
|
||||
@@ -452,7 +432,7 @@ pv_wait_head_or_lock(struct qspinlock *lock, struct mcs_spinlock *node)
|
||||
WRITE_ONCE(pn->state, vcpu_hashed);
|
||||
qstat_inc(qstat_pv_wait_head, true);
|
||||
qstat_inc(qstat_pv_wait_again, waitcnt);
|
||||
pv_wait(&l->locked, _Q_SLOW_VAL);
|
||||
pv_wait(&lock->locked, _Q_SLOW_VAL);
|
||||
|
||||
/*
|
||||
* Because of lock stealing, the queue head vCPU may not be
|
||||
@@ -477,7 +457,6 @@ gotlock:
|
||||
__visible void
|
||||
__pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
struct pv_node *node;
|
||||
|
||||
if (unlikely(locked != _Q_SLOW_VAL)) {
|
||||
@@ -506,7 +485,7 @@ __pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
|
||||
* Now that we have a reference to the (likely) blocked pv_node,
|
||||
* release the lock.
|
||||
*/
|
||||
smp_store_release(&l->locked, 0);
|
||||
smp_store_release(&lock->locked, 0);
|
||||
|
||||
/*
|
||||
* At this point the memory pointed at by lock can be freed/reused,
|
||||
@@ -532,7 +511,6 @@ __pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
|
||||
#ifndef __pv_queued_spin_unlock
|
||||
__visible void __pv_queued_spin_unlock(struct qspinlock *lock)
|
||||
{
|
||||
struct __qspinlock *l = (void *)lock;
|
||||
u8 locked;
|
||||
|
||||
/*
|
||||
@@ -540,7 +518,7 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
|
||||
* unhash. Otherwise it would be possible to have multiple @lock
|
||||
* entries, which would be BAD.
|
||||
*/
|
||||
locked = cmpxchg_release(&l->locked, _Q_LOCKED_VAL, 0);
|
||||
locked = cmpxchg_release(&lock->locked, _Q_LOCKED_VAL, 0);
|
||||
if (likely(locked == _Q_LOCKED_VAL))
|
||||
return;
|
||||
|
||||
|
||||
@@ -3116,7 +3116,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
|
||||
}
|
||||
|
||||
static int
|
||||
do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
|
||||
do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp,
|
||||
size_t min_ss_size)
|
||||
{
|
||||
stack_t oss;
|
||||
int error;
|
||||
@@ -3155,9 +3156,8 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
|
||||
ss_size = 0;
|
||||
ss_sp = NULL;
|
||||
} else {
|
||||
error = -ENOMEM;
|
||||
if (ss_size < MINSIGSTKSZ)
|
||||
goto out;
|
||||
if (unlikely(ss_size < min_ss_size))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
current->sas_ss_sp = (unsigned long) ss_sp;
|
||||
@@ -3180,12 +3180,14 @@ out:
|
||||
}
|
||||
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
|
||||
{
|
||||
return do_sigaltstack(uss, uoss, current_user_stack_pointer());
|
||||
return do_sigaltstack(uss, uoss, current_user_stack_pointer(),
|
||||
MINSIGSTKSZ);
|
||||
}
|
||||
|
||||
int restore_altstack(const stack_t __user *uss)
|
||||
{
|
||||
int err = do_sigaltstack(uss, NULL, current_user_stack_pointer());
|
||||
int err = do_sigaltstack(uss, NULL, current_user_stack_pointer(),
|
||||
MINSIGSTKSZ);
|
||||
/* squash all but EFAULT for now */
|
||||
return err == -EFAULT ? err : 0;
|
||||
}
|
||||
@@ -3226,7 +3228,8 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
|
||||
set_fs(KERNEL_DS);
|
||||
ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
|
||||
(stack_t __force __user *) &uoss,
|
||||
compat_user_stack_pointer());
|
||||
compat_user_stack_pointer(),
|
||||
COMPAT_MINSIGSTKSZ);
|
||||
set_fs(seg);
|
||||
if (ret >= 0 && uoss_ptr) {
|
||||
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) ||
|
||||
|
||||
@@ -399,7 +399,7 @@ static int __init init_timer_list_procfs(void)
|
||||
{
|
||||
struct proc_dir_entry *pe;
|
||||
|
||||
pe = proc_create("timer_list", 0444, NULL, &timer_list_fops);
|
||||
pe = proc_create("timer_list", 0400, NULL, &timer_list_fops);
|
||||
if (!pe)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
|
||||
@@ -4837,6 +4837,7 @@ void ftrace_destroy_filter_files(struct ftrace_ops *ops)
|
||||
if (ops->flags & FTRACE_OPS_FL_ENABLED)
|
||||
ftrace_shutdown(ops, 0);
|
||||
ops->flags |= FTRACE_OPS_FL_DELETED;
|
||||
ftrace_free_filter(ops);
|
||||
mutex_unlock(&ftrace_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -742,8 +742,10 @@ int set_trigger_filter(char *filter_str,
|
||||
|
||||
/* The filter is for the 'trigger' event, not the triggered event */
|
||||
ret = create_event_filter(file->event_call, filter_str, false, &filter);
|
||||
if (ret)
|
||||
goto out;
|
||||
/*
|
||||
* If create_event_filter() fails, filter still needs to be freed.
|
||||
* Which the calling code will do with data->filter.
|
||||
*/
|
||||
assign:
|
||||
tmp = rcu_access_pointer(data->filter);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user