Commit 1d9dff94f7 for frr
commit 1d9dff94f7b6801ce3f2b3f8fa0e7d9dae5d12b8
Author: Mark Stapp <mjs@cisco.com>
Date: Thu Oct 29 14:40:32 2026 -0400
lib: disable task scheduling from event lib show commands
There are several show commands in lib/event that need to
hold the event-loop mutex while producing output. The vty
lib code cannot try to schedule a task - a background write
of buffered data for example - during those commands. We add
a special api that avoids task scheduling, and use that around
the lib/event show commands' loops.
Signed-off-by: Mark Stapp <mjs@cisco.com>
diff --git a/lib/event.c b/lib/event.c
index 1ad0f3048b..53025cb44b 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -315,6 +315,11 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
tmp.funcname = "TOTAL";
tmp.types = filter;
+ /* Defer background write scheduling from the vty - we're holding that lock
+ * here.
+ */
+ vty_defer_scheduling(vty, true);
+
frr_with_mutex (&masters_mtx) {
for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
const char *name = m->name ? m->name : "main";
@@ -349,6 +354,9 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
}
}
+ /* Resume background write scheduling from the vty */
+ vty_defer_scheduling(vty, false);
+
vty_out(vty, "\n");
vty_out(vty, "Total Event statistics\n");
vty_out(vty, "-------------------------\n");
@@ -600,6 +608,11 @@ DEFUN_NOSH (show_event_poll,
struct listnode *node;
struct event_loop *m;
+ /* Defer background write scheduling from the vty - we're holding that lock
+ * here.
+ */
+ vty_defer_scheduling(vty, true);
+
frr_with_mutex (&masters_mtx) {
for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
pthread_mutex_lock(&m->mtx);
@@ -608,6 +621,9 @@ DEFUN_NOSH (show_event_poll,
}
}
+ /* Resume background write scheduling from the vty */
+ vty_defer_scheduling(vty, false);
+
return CMD_SUCCESS;
}
@@ -663,6 +679,11 @@ DEFPY_NOSH (show_event_timers,
struct listnode *node;
struct event_loop *m;
+ /* Defer background write scheduling from the vty - we're holding that lock
+ * here.
+ */
+ vty_defer_scheduling(vty, true);
+
frr_with_mutex (&masters_mtx) {
for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
pthread_mutex_lock(&m->mtx);
@@ -671,6 +692,9 @@ DEFPY_NOSH (show_event_timers,
}
}
+ /* Resume background write scheduling from the vty */
+ vty_defer_scheduling(vty, false);
+
return CMD_SUCCESS;
}
diff --git a/lib/vty.c b/lib/vty.c
index 35e48590fb..4bd2440f44 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2208,7 +2208,11 @@ static int vtysh_flush(struct vty *vty)
switch (ret) {
case BUFFER_PENDING:
- vty_event(VTYSH_WRITE, vty);
+ /* Some callers may be holding the scheduling mutex; defer
+ * for them.
+ */
+ if (!vty->avoid_sched)
+ vty_event(VTYSH_WRITE, vty);
break;
case BUFFER_ERROR:
flog_err(EC_LIB_SOCKET, "%s: write error to fd %d, closing",
@@ -2976,6 +2980,15 @@ static void vty_event(enum vty_event event, struct vty *vty)
}
}
+/* Defer scheduling tasks, used when the caller will be holding the
+ * scheduling mutex and must avoid deadlock. These callers are inside
+ * the scheduling library, so far.
+ */
+void vty_defer_scheduling(struct vty *vty, bool defer_p)
+{
+ vty->avoid_sched = defer_p;
+}
+
DEFUN_NOSH (config_who,
config_who_cmd,
"who",
diff --git a/lib/vty.h b/lib/vty.h
index 63afd092e4..6f5cdb677c 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -238,6 +238,14 @@ struct vty {
*/
size_t vty_buf_threshold;
size_t vty_buf_size_accum;
+
+ /* During output, it's possible for a vty to schedule a task to
+ * continue flushing buffered output. Some specialized callers
+ * in the library code may be holding the event-loop mutex while
+ * they produce output: in those paths, we defer task-scheduling
+ * to avoid deadlocks
+ */
+ bool avoid_sched;
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
@@ -438,6 +446,12 @@ static inline bool vty_is_closed(const struct vty *vty)
*/
extern void vty_resume_response(struct vty *vty, int ret);
+/* Defer scheduling tasks, used when the caller will be holding the
+ * scheduling mutex and must avoid deadlock. These callers are inside
+ * the scheduling library, so far.
+ */
+void vty_defer_scheduling(struct vty *vty, bool defer_p);
+
/* --------------------------------------------------- */
/* Callbacks for Mgmtd front-end CLI vty modifications */
/* --------------------------------------------------- */