summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/arm/msgqueue.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2026-09-14 22:12:34 -1000
committerTejun Heo <tj@kernel.org>2026-09-15 06:57:20 -1000
commita9e3760b0838299649c0d57cca44daaf40ba3c33 (patch)
tree95807ff0e511c05602ef34808cfc660303309057 /drivers/scsi/arm/msgqueue.c
downloadlinux-stable-a9e3760b0838299649c0d57cca44daaf40ba3c33.tar.gz
linux-stable-a9e3760b0838299649c0d57cca44daaf40ba3c33.zip
sched_ext: Maintain an online cid mask in the scheduler arenagrafted
Schedulers on the default cid mapping treat [0, nr_online_cids) as the online set and restart on hotplug. Schedulers that install their own mapping with scx_bpf_cid_override() have no way to learn which cids are online: the count no longer identifies members and the CPU-form cpumask is unusable from cid programs. This is an obvious hole in the cid API. Add scx_bpf_online_cmask(), a kernel-maintained cmask in the scheduler's arena, allocated alongside the per-CPU scratch masks and populated after the cid mapping is finalized and before ops.init(), for child schedulers too. The pointer stays valid through ops.exit() with no reference to take. It is the arena offset as a void pointer, the same form struct_ops arena arguments arrive in. The verifier types the void return as a scalar for the program's arena cast. The mask follows the SCX hotplug notifications: seeded from cpu_active_mask and updated before ops.cid_online/offline() runs, so it lags cpu_online_mask only inside a hotplug transition. Updates walk the scheduler list under the lock that also serializes unlinking. Reads are live, not atomic snapshots. Root initialization excludes hotplug. v2: Reworded the getter kerneldoc (Andrea Righi). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
Diffstat (limited to 'drivers/scsi/arm/msgqueue.c')
-rw-r--r--drivers/scsi/arm/msgqueue.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c
new file mode 100644
index 000000000..581158313
--- /dev/null
+++ b/drivers/scsi/arm/msgqueue.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/drivers/acorn/scsi/msgqueue.c
+ *
+ * Copyright (C) 1997-1998 Russell King
+ *
+ * message queue handling
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+
+#include "msgqueue.h"
+
+/*
+ * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
+ * Purpose : Allocate a message queue entry
+ * Params : msgq - message queue to claim entry for
+ * Returns : message queue entry or NULL.
+ */
+static struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
+{
+ struct msgqueue_entry *mq;
+
+ if ((mq = msgq->free) != NULL)
+ msgq->free = mq->next;
+
+ return mq;
+}
+
+/*
+ * Function: void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
+ * Purpose : free a message queue entry
+ * Params : msgq - message queue to free entry from
+ * mq - message queue entry to free
+ */
+static void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
+{
+ if (mq) {
+ mq->next = msgq->free;
+ msgq->free = mq;
+ }
+}
+
+/*
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
+ * Purpose : initialise a message queue
+ * Params : msgq - queue to initialise
+ */
+void msgqueue_initialise(MsgQueue_t *msgq)
+{
+ int i;
+
+ msgq->qe = NULL;
+ msgq->free = &msgq->entries[0];
+
+ for (i = 0; i < NR_MESSAGES; i++)
+ msgq->entries[i].next = &msgq->entries[i + 1];
+
+ msgq->entries[NR_MESSAGES - 1].next = NULL;
+}
+
+
+/*
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
+ * Purpose : free a queue
+ * Params : msgq - queue to free
+ */
+void msgqueue_free(MsgQueue_t *msgq)
+{
+}
+
+/*
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
+ * Purpose : calculate the total length of all messages on the message queue
+ * Params : msgq - queue to examine
+ * Returns : number of bytes of messages in queue
+ */
+int msgqueue_msglength(MsgQueue_t *msgq)
+{
+ struct msgqueue_entry *mq = msgq->qe;
+ int length = 0;
+
+ for (mq = msgq->qe; mq; mq = mq->next)
+ length += mq->msg.length;
+
+ return length;
+}
+
+/*
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message
+ * Params : msgq - queue to obtain message from
+ * : msgno - message number
+ * Returns : pointer to message string, or NULL
+ */
+struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+{
+ struct msgqueue_entry *mq;
+
+ for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--);
+
+ return mq ? &mq->msg : NULL;
+}
+
+/*
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+ * Purpose : add a message onto a message queue
+ * Params : msgq - queue to add message on
+ * length - length of message
+ * ... - message bytes
+ * Returns : != 0 if successful
+ */
+int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+{
+ struct msgqueue_entry *mq = mqe_alloc(msgq);
+ va_list ap;
+
+ if (mq) {
+ struct msgqueue_entry **mqp;
+ int i;
+
+ va_start(ap, length);
+ for (i = 0; i < length; i++)
+ mq->msg.msg[i] = va_arg(ap, unsigned int);
+ va_end(ap);
+
+ mq->msg.length = length;
+ mq->msg.fifo = 0;
+ mq->next = NULL;
+
+ mqp = &msgq->qe;
+ while (*mqp)
+ mqp = &(*mqp)->next;
+
+ *mqp = mq;
+ }
+
+ return mq != NULL;
+}
+
+/*
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
+ * Purpose : flush all messages from message queue
+ * Params : msgq - queue to flush
+ */
+void msgqueue_flush(MsgQueue_t *msgq)
+{
+ struct msgqueue_entry *mq, *mqnext;
+
+ for (mq = msgq->qe; mq; mq = mqnext) {
+ mqnext = mq->next;
+ mqe_free(msgq, mq);
+ }
+ msgq->qe = NULL;
+}
+
+EXPORT_SYMBOL(msgqueue_initialise);
+EXPORT_SYMBOL(msgqueue_free);
+EXPORT_SYMBOL(msgqueue_msglength);
+EXPORT_SYMBOL(msgqueue_getmsg);
+EXPORT_SYMBOL(msgqueue_addmsg);
+EXPORT_SYMBOL(msgqueue_flush);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI message queue handling");
+MODULE_LICENSE("GPL");