Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 844cf763 authored by Jon Paul Maloy's avatar Jon Paul Maloy Committed by David S. Miller
Browse files

tipc: make macro tipc_wait_for_cond() smp safe



The macro tipc_wait_for_cond() is embedding the macro sk_wait_event()
to fulfil its task. The latter, in turn, is evaluating the stated
condition outside the socket lock context. This is problematic if
the condition is accessing non-trivial data structures which may be
altered by incoming interrupts, as is the case with the cong_links()
linked list, used by socket to keep track of the current set of
congested links. We sometimes see crashes when this list is accessed
by a condition function at the same time as a SOCK_WAKEUP interrupt
is removing an element from the list.

We fix this by expanding selected parts of sk_wait_event() into the
outer macro, while ensuring that all evaluations of a given condition
are performed under socket lock protection.

Fixes: commit 365ad353 ("tipc: reduce risk of user starvation during link congestion")
Reviewed-by: default avatarParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com>
Signed-off-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ad990dbe
Loading
Loading
Loading
Loading
+19 −19
Original line number Diff line number Diff line
@@ -362,22 +362,22 @@ static int tipc_sk_sock_err(struct socket *sock, long *timeout)
	return 0;
}

#define tipc_wait_for_cond(sock_, timeout_, condition_)			\
#define tipc_wait_for_cond(sock_, timeo_, condition_)			       \
({                                                                             \
	int rc_ = 0;							\
	int done_ = 0;							\
	struct sock *sk_;						       \
	int rc_;							       \
									       \
	while (!(condition_) && !done_) {				\
		struct sock *sk_ = sock->sk;				\
	while ((rc_ = !(condition_))) {					       \
		DEFINE_WAIT_FUNC(wait_, woken_wake_function);	               \
									\
		rc_ = tipc_sk_sock_err(sock_, timeout_);		\
		sk_ = (sock_)->sk;					       \
		rc_ = tipc_sk_sock_err((sock_), timeo_);		       \
		if (rc_)						       \
			break;						       \
		prepare_to_wait(sk_sleep(sk_), &wait_,			\
				TASK_INTERRUPTIBLE);			\
		done_ = sk_wait_event(sk_, timeout_,			\
				      (condition_), &wait_);		\
		prepare_to_wait(sk_sleep(sk_), &wait_, TASK_INTERRUPTIBLE);    \
		release_sock(sk_);					       \
		*(timeo_) = wait_woken(&wait_, TASK_INTERRUPTIBLE, *(timeo_)); \
		sched_annotate_sleep();				               \
		lock_sock(sk_);						       \
		remove_wait_queue(sk_sleep(sk_), &wait_);		       \
	}								       \
	rc_;								       \