Files
omarchy-pkgs/pkgbuilds/linux-omarchy-muqss/0110-muqss-0.31.patch
T

17204 lines
505 KiB
Diff

diff --git a/arch/m68k/coldfire/pci.c b/arch/m68k/coldfire/pci.c
--- a/arch/m68k/coldfire/pci.c
+++ b/arch/m68k/coldfire/pci.c
@@ -226,7 +226,7 @@ static int __init mcf_pci_init(void)
/* Turn of PCI reset, and wait for devices to settle */
mcf_write32(0, PCIGSCR);
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(200));
+ schedule_msec_hrtimeout(200);
pci_add_resource(&bridge->windows, &ioport_resource);
diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c
--- a/arch/powerpc/platforms/powernv/vas-window.c
+++ b/arch/powerpc/platforms/powernv/vas-window.c
@@ -1185,7 +1185,7 @@ static void poll_window_credits(struct pnv_vas_window *window)
if (creds < window->vas_win.wcreds_max) {
val = 0;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout(10);
count++;
/*
* Process can not close send window until all credits are
@@ -1218,7 +1218,7 @@ static void poll_window_busy_state(struct pnv_vas_window *window)
if (busy) {
val = 0;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout(10);
count++;
/*
* Takes around few milliseconds to process all pending
diff --git a/block/Makefile b/block/Makefile
--- a/block/Makefile
+++ b/block/Makefile
@@ -14,6 +14,7 @@ obj-y := bdev.o fops.o bio.o elevator.o blk-core.o blk-sysfs.o \
disk-events.o blk-ia-ranges.o early-lookup.o
obj-$(CONFIG_BLK_ERROR_INJECTION) += error-injection.o
+obj-$(CONFIG_MUQSS_IOTIME) += blk-iotime.o
obj-$(CONFIG_BLK_DEV_BSG_COMMON) += bsg.o
obj-$(CONFIG_BLK_DEV_BSGLIB) += bsg-lib.o
obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o
diff --git a/block/bio.c b/block/bio.c
--- a/block/bio.c
+++ b/block/bio.c
@@ -19,6 +19,7 @@
#include <linux/blk-crypto.h>
#include <linux/xarray.h>
#include <linux/kmemleak.h>
+#include <linux/muqss_iotime.h>
#include <trace/events/block.h>
#include "blk.h"
@@ -185,6 +186,8 @@ void bio_uninit(struct bio *bio)
bio->bi_blkg = NULL;
}
#endif
+ muqss_iotime_put_owner(bio);
+
if (bio_integrity(bio))
bio_integrity_free(bio);
@@ -234,13 +237,18 @@ void bio_init(struct bio *bio, struct block_device *bdev, struct bio_vec *table,
bio->bi_private = NULL;
#ifdef CONFIG_BLK_CGROUP
bio->bi_blkg = NULL;
- bio->issue_time_ns = 0;
if (bdev)
bio_associate_blkg(bio);
#ifdef CONFIG_BLK_CGROUP_IOCOST
bio->bi_iocost_cost = 0;
#endif
#endif
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_MUQSS_IOTIME)
+ bio->issue_time_ns = 0;
+#endif
+#ifdef CONFIG_MUQSS_IOTIME
+ bio->bi_muqss_owner = NULL;
+#endif
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
bio->bi_crypt_context = NULL;
#endif
@@ -868,6 +876,7 @@ static int __bio_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp)
bio_set_flag(bio, BIO_REMAPPED);
bio_clone_blkg_association(bio, bio_src);
}
+ muqss_iotime_clone_owner(bio, bio_src);
if (bio_crypt_clone(bio, bio_src, gfp) < 0)
return -ENOMEM;
@@ -1865,6 +1874,7 @@ void bio_endio(struct bio *bio)
bio->bi_blkg = NULL;
}
#endif
+ muqss_iotime_put_owner(bio);
if (bio->bi_end_io)
bio->bi_end_io(bio);
diff --git a/block/blk-iotime.c b/block/blk-iotime.c
new file mode 100644
--- /dev/null
+++ b/block/blk-iotime.c
@@ -0,0 +1,753 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * I/O aware scheduling support for MuQSS.
+ *
+ * The CPU scheduler can see how much CPU a task uses but nothing of what it
+ * costs the storage device. This attaches an rq_qos policy that attributes
+ * block device time back to the task that caused the I/O, so that cost is
+ * visible to the scheduler.
+ *
+ * Two different quantities are recorded and deliberately kept apart:
+ *
+ * Latency is what a waiting task experiences, measured per bio from
+ * bio->issue_time_ns, which is stamped in blk_mq_submit_bio() before merging
+ * and request allocation. It therefore includes plug, merge and queue wait as
+ * well as service.
+ *
+ * Occupancy is what the task cost everybody else, measured per request from
+ * rq->io_start_time_ns at dispatch to rq->muqss_done_ns at completion. This is
+ * the quantity the scheduler charges for.
+ *
+ * Attribution has two halves. Reads and synchronous writes are submitted by
+ * the originating task, so the owner is simply current. Writeback is not: the
+ * dirtier is recorded on the folio when it is dirtied and recovered when the
+ * flusher thread submits the I/O. See the owner table below.
+ *
+ * The owner table earns its keep a second time over. A kworker running a work
+ * item declares itself to be acting for whoever queued that work, which both
+ * attributes the I/O the work item issues and lets the CPU time it costs be
+ * charged back as kern_debt_ns. See muqss_kerntime_begin().
+ *
+ * The occupancy is charged one for one against the deadline, with nothing to
+ * tune it by: the accounting below and the scheduling it feeds are one
+ * feature, and only CONFIG_MUQSS_IOTIME=n removes either. See
+ * consume_iotime_penalty() in kernel/sched/MuQSS.c and
+ * MuQSS-iotime-design.md.
+ */
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/sched/task.h>
+#include <linux/slab.h>
+#include <linux/workqueue_types.h>
+#include <linux/muqss_iotime.h>
+
+#include "blk.h"
+#include "blk-mq.h"
+#include "blk-mq-debugfs.h"
+#include "blk-rq-qos.h"
+#include "blk-stat.h"
+
+struct blk_iotime {
+ struct rq_qos rqos;
+
+ /* Unattributed device busy time, see comment above. */
+ atomic64_t occupancy_ns;
+ atomic64_t requests;
+
+ /*
+ * Bios that completed with no owner recorded. Counted so the size of
+ * the attribution gap stays visible rather than silently skewing the
+ * per task numbers.
+ */
+ atomic64_t unattributed;
+
+ /* Requests disowned because a merge brought in another task's bio. */
+ atomic64_t mixed;
+
+ /*
+ * Requests that reached completion with no captured timestamp, and so
+ * could not be measured at all. See muqss_iotime_done().
+ */
+ atomic64_t unstamped;
+
+ /* Bios that completed with an owner but no submit timestamp. */
+ atomic64_t nostamp_bio;
+};
+
+static inline struct blk_iotime *BLK_IOTIME(struct rq_qos *rqos)
+{
+ return container_of(rqos, struct blk_iotime, rqos);
+}
+
+/*
+ * Owner table.
+ *
+ * Reads are attributable at submit time because the submitting task is the
+ * originating one. Writeback is not: the folio is dirtied by one task and
+ * written out much later by a flusher thread. The dirtier is therefore
+ * recorded on the folio itself, in spare page->flags bits, as an index into
+ * this table.
+ *
+ * Only MUQSS_IOWNER_WIDTH bits are available, so the table is small and the
+ * index carries no generation. Slot 0 is reserved to mean "no owner". A slot
+ * is held from the task's first dirty until it exits, and the table holds a
+ * reference for that whole period, so a resolved pointer is always a live
+ * task_struct.
+ *
+ * Slots are released on exit and never stolen from a live task, so a resolved
+ * index is never charged to the wrong task. The cost of that choice is that
+ * beyond IOWNER_SLOTS concurrent dirtiers, further tasks get no slot and their
+ * writeback goes unattributed; iowner_exhausted counts it.
+ *
+ * Writeback still in flight for a task that has exited resolves to nothing,
+ * which is correct: there is no longer anybody to charge.
+ */
+#define IOWNER_SLOTS (1U << MUQSS_IOWNER_SHIFT)
+
+static struct task_struct *iowner_table[IOWNER_SLOTS];
+/* Work can be queued with a raw runqueue lock held (for example by PSI). */
+static DEFINE_RAW_SPINLOCK(iowner_lock);
+
+static atomic64_t iowner_exhausted;
+
+static atomic64_t iowner_proxied;
+
+/* Work items charged back to a task, and the CPU time they cost. */
+static atomic64_t kernwork_charged;
+static atomic64_t kernwork_ns;
+
+/*
+ * Slot for @tsk, allocating one on first use.
+ *
+ * @tsk is not necessarily current: an io-wq worker allocates on behalf of the
+ * task that queued the request it is running, so that pages it dirties are
+ * tagged with the real owner. The caller holds a reference to @tsk.
+ */
+static unsigned int iotime_task_slot(struct task_struct *tsk)
+{
+ unsigned int slot, scan;
+ unsigned long flags;
+
+ if (!MUQSS_IOWNER_WIDTH)
+ return 0;
+
+ slot = READ_ONCE(tsk->io_owner_slot);
+ if (slot)
+ return slot;
+
+ if (tsk->flags & (PF_KTHREAD | PF_EXITING))
+ return 0;
+
+ raw_spin_lock_irqsave(&iowner_lock, flags);
+
+ /*
+ * Recheck PF_EXITING under the lock. It is set well before
+ * muqss_iotime_release_slot() runs, and that also takes this lock, so
+ * a task seen here as not exiting either has not reached exit or will
+ * release the slot we are about to hand it. Without the recheck a slot
+ * claimed for a remote task racing through exit would never be freed.
+ */
+ if (tsk->flags & PF_EXITING)
+ goto out;
+
+ /* Raced with another dirty on the same task. */
+ if (tsk->io_owner_slot) {
+ slot = tsk->io_owner_slot;
+ goto out;
+ }
+
+ /* Prefer a free slot. */
+ for (scan = 1; scan < IOWNER_SLOTS; scan++) {
+ if (!iowner_table[scan]) {
+ slot = scan;
+ goto claim;
+ }
+ }
+
+ /*
+ * Table full of live dirtiers. Leave this task unattributed rather
+ * than evicting somebody still using their slot: a stolen slot would
+ * silently charge one task's writeback to another, which is worse
+ * than not charging it at all.
+ */
+ atomic64_inc(&iowner_exhausted);
+ slot = 0;
+ goto out;
+
+claim:
+ iowner_table[slot] = get_task_struct(tsk);
+ WRITE_ONCE(tsk->io_owner_slot, slot);
+out:
+ raw_spin_unlock_irqrestore(&iowner_lock, flags);
+ return slot;
+}
+
+unsigned int muqss_iotime_owner_slot(void)
+{
+ struct task_struct *tsk = current;
+ struct task_struct *owner;
+
+ /*
+ * A thread running inside a proxy window dirties pages on behalf of
+ * the task that window belongs to, so tag them with that task. Doing
+ * otherwise would both misattribute the writeback and, for io-wq
+ * workers, let a churn of short lived workers consume the whole slot
+ * table.
+ *
+ * An io-wq worker outside a window has nobody to speak for and must
+ * not claim a slot of its own. A kworker outside a window needs no
+ * such test: iotime_task_slot() refuses PF_KTHREAD outright.
+ */
+ owner = READ_ONCE(tsk->io_owner_override);
+ if (owner)
+ tsk = owner;
+ else if (tsk->flags & PF_IO_WORKER)
+ return 0;
+
+ return iotime_task_slot(tsk);
+}
+
+struct task_struct *muqss_iotime_proxy_begin(struct task_struct *owner)
+{
+ struct task_struct *prev = current->io_owner_override;
+
+ WRITE_ONCE(current->io_owner_override, owner);
+ return prev;
+}
+
+void muqss_iotime_proxy_end(struct task_struct *prev)
+{
+ WRITE_ONCE(current->io_owner_override, prev);
+}
+
+void muqss_work_set_owner(struct work_struct *work)
+{
+ /* Interrupt work does not belong to the task it interrupted. */
+ work->muqss_owner_slot = in_task() ? muqss_iotime_owner_slot() : 0;
+}
+
+void muqss_kerntime_begin(struct muqss_kern_window *w, unsigned int slot)
+{
+ w->prev = NULL;
+ w->start = 0;
+
+ /*
+ * Resolving the slot is what costs here, so it gates everything else.
+ * Work queued by kernel threads on their own account carries slot 0
+ * and leaves this function having done one branch, which matters:
+ * timers, readahead, RCU and any amount of driver housekeeping run
+ * through work items that belong to nobody.
+ */
+ w->owner = muqss_iotime_owner_task(slot);
+ if (!w->owner)
+ return;
+
+ w->prev = muqss_iotime_proxy_begin(w->owner);
+ w->start = muqss_task_runtime_live();
+}
+
+void muqss_kerntime_end(struct muqss_kern_window *w)
+{
+ s64 ns;
+
+ if (!w->owner)
+ return;
+
+ ns = muqss_task_runtime_live() - w->start;
+ muqss_iotime_proxy_end(w->prev);
+
+ /*
+ * Runtime rather than elapsed time, so a worker preempted for a whole
+ * scheduling round does not hand the bill for it to the task it is
+ * working for. Negative or absurd deltas are possible if the two ends
+ * of the window landed either side of a clock warp, and are dropped
+ * rather than clamped: there is no sensible value to substitute.
+ */
+ if (ns > 0) {
+ atomic64_add(ns, &w->owner->kern_time_ns);
+ atomic64_add(ns, &w->owner->kern_debt_ns);
+ atomic64_inc(&kernwork_charged);
+ atomic64_add(ns, &kernwork_ns);
+ }
+
+ put_task_struct(w->owner);
+ w->owner = NULL;
+}
+
+struct task_struct *muqss_iotime_owner_task(unsigned int slot)
+{
+ struct task_struct *tsk = NULL;
+ unsigned long flags;
+
+ if (!slot || slot >= IOWNER_SLOTS)
+ return NULL;
+
+ raw_spin_lock_irqsave(&iowner_lock, flags);
+ if (iowner_table[slot])
+ tsk = get_task_struct(iowner_table[slot]);
+ raw_spin_unlock_irqrestore(&iowner_lock, flags);
+
+ return tsk;
+}
+
+void muqss_iotime_release_slot(struct task_struct *p)
+{
+ unsigned int slot = READ_ONCE(p->io_owner_slot);
+ unsigned long flags;
+
+ if (!slot)
+ return;
+
+ raw_spin_lock_irqsave(&iowner_lock, flags);
+ if (iowner_table[slot] == p) {
+ iowner_table[slot] = NULL;
+ WRITE_ONCE(p->io_owner_slot, 0);
+ raw_spin_unlock_irqrestore(&iowner_lock, flags);
+ put_task_struct(p);
+ return;
+ }
+ WRITE_ONCE(p->io_owner_slot, 0);
+ raw_spin_unlock_irqrestore(&iowner_lock, flags);
+}
+
+void muqss_iotime_dirty_folio(struct folio *folio)
+{
+ unsigned int slot = muqss_iotime_owner_slot();
+
+ folio_set_io_owner(folio, slot);
+}
+
+void muqss_iotime_task_init(struct task_struct *p)
+{
+ atomic64_set(&p->io_latency_ns, 0);
+ atomic64_set(&p->io_count, 0);
+ atomic64_set(&p->io_occupancy_ns, 0);
+ atomic64_set(&p->io_debt_ns, 0);
+ atomic64_set(&p->kern_time_ns, 0);
+ atomic64_set(&p->kern_debt_ns, 0);
+ p->io_owner_slot = 0;
+ p->io_owner_override = NULL;
+}
+
+void muqss_iotime_set_owner(struct bio *bio)
+{
+ struct task_struct *tsk = current;
+
+ if (bio->bi_muqss_owner)
+ return;
+
+ /*
+ * Not in task context: current is whatever this interrupted, which
+ * has nothing to do with the I/O. Bios submitted from softirq or hard
+ * IRQ, such as a filesystem completing one write by starting another,
+ * would otherwise be charged to a bystander.
+ */
+ if (!in_task())
+ return;
+
+ /*
+ * Passthrough requests are not issued on any task's behalf. Neither
+ * is the flush machinery's own empty bio, but REQ_PREFLUSH is also set
+ * on an ordinary write that wants a cache flush ahead of it, and that
+ * write is somebody's. Test for the payload rather than the flag.
+ */
+ if (blk_op_is_passthrough(bio->bi_opf))
+ return;
+ if ((bio->bi_opf & REQ_PREFLUSH) && !bio_has_data(bio))
+ return;
+
+ if (tsk->flags & (PF_KTHREAD | PF_IO_WORKER)) {
+ struct task_struct *owner;
+ struct folio *folio;
+
+ /*
+ * io_uring punted this submission to an io-wq worker, which
+ * published the task that queued the request. Charge that
+ * task: the worker is an anonymous thread that exists only to
+ * run somebody else's I/O.
+ *
+ * Writeback that happens to be issued from inside the same
+ * window is charged here too, which is a small misattribution
+ * within one application rather than a loss.
+ */
+ owner = READ_ONCE(tsk->io_owner_override);
+ if (owner) {
+ atomic64_inc(&iowner_proxied);
+ bio->bi_muqss_owner = get_task_struct(owner);
+ return;
+ }
+
+ /*
+ * Writeback. current is a flusher thread rather than the task
+ * that dirtied the data, so recover the owner from the folio,
+ * where it was recorded at dirty time.
+ *
+ * The first page decides for the whole bio. A writeback bio
+ * normally covers one file's pages dirtied by one task, and
+ * reading every page to take a vote would put a loop on the
+ * submit path for a heuristic that does not need it.
+ *
+ * Cloned bios are skipped: their bi_io_vec belongs to the
+ * parent, and muqss_iotime_clone_owner() has already carried
+ * the owner across.
+ */
+ if (op_is_write(bio->bi_opf) && bio->bi_vcnt &&
+ !bio_flagged(bio, BIO_CLONED)) {
+ folio = page_folio(bio->bi_io_vec[0].bv_page);
+ bio->bi_muqss_owner =
+ muqss_iotime_owner_task(folio_io_owner(folio));
+ return;
+ }
+
+ /*
+ * An io_uring SQPOLL thread submits for whoever shares its
+ * ring, and the request does not record which task that was;
+ * with IORING_SETUP_ATTACH_WQ it need not be a single one.
+ * The thread is a long lived schedulable task in its own
+ * right though, so charge it directly rather than lose the
+ * time: the device cost is real, and the sq thread is the
+ * entity the scheduler can actually act on.
+ *
+ * Kernel threads proper get nothing.
+ */
+ if (tsk->flags & PF_IO_WORKER)
+ bio->bi_muqss_owner = get_task_struct(tsk);
+ return;
+ }
+
+ bio->bi_muqss_owner = get_task_struct(tsk);
+}
+
+void muqss_iotime_put_owner(struct bio *bio)
+{
+ if (bio->bi_muqss_owner) {
+ put_task_struct(bio->bi_muqss_owner);
+ bio->bi_muqss_owner = NULL;
+ }
+}
+
+void muqss_iotime_clone_owner(struct bio *bio, struct bio *bio_src)
+{
+ muqss_iotime_put_owner(bio);
+
+ if (bio_src->bi_muqss_owner)
+ bio->bi_muqss_owner = get_task_struct(bio_src->bi_muqss_owner);
+}
+
+/*
+ * Per bio completion. The owner reference is not dropped here: bio_endio()
+ * and bio_uninit() release it alongside the blkg reference, which keeps the
+ * lifetime rules identical to the ones the block layer already follows.
+ */
+static void muqss_iotime_done_bio(struct rq_qos *rqos, struct bio *bio)
+{
+ struct blk_iotime *bit = BLK_IOTIME(rqos);
+ struct task_struct *tsk = bio->bi_muqss_owner;
+ u64 now;
+
+ if (!tsk) {
+ atomic64_inc(&bit->unattributed);
+ return;
+ }
+ if (!bio->issue_time_ns) {
+ atomic64_inc(&bit->nostamp_bio);
+ return;
+ }
+
+ now = blk_time_get_ns();
+ if (now <= bio->issue_time_ns)
+ return;
+
+ atomic64_add(now - bio->issue_time_ns, &tsk->io_latency_ns);
+ atomic64_inc(&tsk->io_count);
+}
+
+/*
+ * A request is being built from its first bio. Take our own reference for the
+ * request: the bio's reference is released by bio_endio() during
+ * blk_update_request(), which runs before rq_qos_done(), so borrowing it would
+ * leave a dangling pointer at completion.
+ */
+static void muqss_iotime_track(struct rq_qos *rqos, struct request *rq,
+ struct bio *bio)
+{
+ if (bio->bi_muqss_owner)
+ rq->muqss_owner = get_task_struct(bio->bi_muqss_owner);
+}
+
+/*
+ * A further bio is merging into an existing request. Occupancy is measured
+ * per request and cannot be split between owners, so a request that ends up
+ * serving more than one task is disowned rather than charged to whichever
+ * task happened to be first.
+ */
+static void muqss_iotime_merge(struct rq_qos *rqos, struct request *rq,
+ struct bio *bio)
+{
+ if (!rq->muqss_owner || rq->muqss_owner == bio->bi_muqss_owner)
+ return;
+
+ put_task_struct(rq->muqss_owner);
+ rq->muqss_owner = NULL;
+ atomic64_inc(&BLK_IOTIME(rqos)->mixed);
+}
+
+/*
+ * Two whole requests are being merged: next's bios are about to be appended to
+ * rq and next freed. The rq_qos ->merge hook does not cover this, it only sees
+ * a bio being merged into a request, so without this the survivor keeps its own
+ * owner and is charged for both requests' device time.
+ *
+ * Called from attempt_merge() rather than being an rq_qos op because the
+ * framework has no request-to-request callback to hang it on.
+ */
+void muqss_iotime_merge_requests(struct request *rq, struct request *next)
+{
+ struct rq_qos *rqos;
+
+ if (!rq->muqss_owner || rq->muqss_owner == next->muqss_owner)
+ return;
+
+ put_task_struct(rq->muqss_owner);
+ rq->muqss_owner = NULL;
+
+ rqos = rq_qos_id(rq->q, RQ_QOS_MUQSS_IOTIME);
+ if (rqos)
+ atomic64_inc(&BLK_IOTIME(rqos)->mixed);
+}
+
+/* Per request completion. This is where device occupancy is attributed. */
+static void muqss_iotime_done(struct rq_qos *rqos, struct request *rq)
+{
+ struct blk_iotime *bit = BLK_IOTIME(rqos);
+ struct task_struct *tsk = rq->muqss_owner;
+ u64 now, occupancy;
+
+ if (!(rq->rq_flags & RQF_STATS) || !rq->io_start_time_ns)
+ goto out;
+
+ /*
+ * Use the timestamp captured when the request completed, not one
+ * taken here: rq_qos_done() runs after blk_update_request() has
+ * completed every bio, so measuring now would fold the completion
+ * path into what is supposed to be device service time. That bias is
+ * roughly constant per request, which would quietly turn part of the
+ * charge into a per-I/O-count charge and penalise small random I/O.
+ *
+ * Consuming the stamp also makes this idempotent. rq_qos_done() runs
+ * twice for a request with an end_io handler that frees it: once from
+ * __blk_mq_end_request() and again from blk_mq_free_request(). Every
+ * policy has to tolerate that. Clearing muqss_owner alone stopped the
+ * task being charged twice but left the device totals below counting
+ * the same request on both passes.
+ *
+ * A request that never went through blk_mq_end_request() has no stamp
+ * and is not measured. Timing it here instead would report the
+ * completion path as device time, which is the bias this exists to
+ * avoid; unstamped counts them so the loss stays visible.
+ */
+ now = rq->muqss_done_ns;
+ if (!now) {
+ atomic64_inc(&bit->unstamped);
+ goto out;
+ }
+ rq->muqss_done_ns = 0;
+
+ if (now <= rq->io_start_time_ns)
+ goto out;
+
+ occupancy = now - rq->io_start_time_ns;
+ atomic64_add(occupancy, &bit->occupancy_ns);
+ atomic64_inc(&bit->requests);
+
+ if (tsk) {
+ atomic64_add(occupancy, &tsk->io_occupancy_ns);
+ atomic64_add(occupancy, &tsk->io_debt_ns);
+ }
+out:
+ if (tsk) {
+ put_task_struct(tsk);
+ rq->muqss_owner = NULL;
+ }
+}
+
+static void muqss_iotime_exit(struct rq_qos *rqos)
+{
+ struct blk_iotime *bit = BLK_IOTIME(rqos);
+
+ /*
+ * QUEUE_FLAG_BIO_ISSUE_TIME is deliberately left set. blk-iolatency
+ * uses the same flag, and the queue is being torn down here anyway.
+ */
+ blk_stat_disable_accounting(rqos->disk->queue);
+ kfree(bit);
+}
+
+#ifdef CONFIG_BLK_DEBUG_FS
+static int muqss_iotime_occupancy_show(void *data, struct seq_file *m)
+{
+ struct rq_qos *rqos = data;
+
+ seq_printf(m, "%llu\n",
+ (u64)atomic64_read(&BLK_IOTIME(rqos)->occupancy_ns));
+ return 0;
+}
+
+static int muqss_iotime_requests_show(void *data, struct seq_file *m)
+{
+ struct rq_qos *rqos = data;
+
+ seq_printf(m, "%llu\n",
+ (u64)atomic64_read(&BLK_IOTIME(rqos)->requests));
+ return 0;
+}
+
+static int muqss_iotime_unattributed_show(void *data, struct seq_file *m)
+{
+ struct rq_qos *rqos = data;
+
+ seq_printf(m, "%llu\n",
+ (u64)atomic64_read(&BLK_IOTIME(rqos)->unattributed));
+ return 0;
+}
+
+static int muqss_iotime_mixed_show(void *data, struct seq_file *m)
+{
+ struct rq_qos *rqos = data;
+
+ seq_printf(m, "%llu\n", (u64)atomic64_read(&BLK_IOTIME(rqos)->mixed));
+ return 0;
+}
+
+static int muqss_iotime_unstamped_show(void *data, struct seq_file *m)
+{
+ struct rq_qos *rqos = data;
+
+ seq_printf(m, "%llu\n",
+ (u64)atomic64_read(&BLK_IOTIME(rqos)->unstamped));
+ return 0;
+}
+
+static int muqss_iotime_nostamp_bio_show(void *data, struct seq_file *m)
+{
+ struct rq_qos *rqos = data;
+
+ seq_printf(m, "%llu\n",
+ (u64)atomic64_read(&BLK_IOTIME(rqos)->nostamp_bio));
+ return 0;
+}
+
+static int muqss_iotime_exhausted_show(void *data, struct seq_file *m)
+{
+ seq_printf(m, "%llu\n", (u64)atomic64_read(&iowner_exhausted));
+ return 0;
+}
+
+static int muqss_iotime_proxied_show(void *data, struct seq_file *m)
+{
+ seq_printf(m, "%llu\n", (u64)atomic64_read(&iowner_proxied));
+ return 0;
+}
+
+static int muqss_iotime_owner_width_show(void *data, struct seq_file *m)
+{
+ seq_printf(m, "%u\n", MUQSS_IOWNER_WIDTH);
+ return 0;
+}
+
+static int muqss_iotime_kernwork_show(void *data, struct seq_file *m)
+{
+ seq_printf(m, "%llu\n", (u64)atomic64_read(&kernwork_charged));
+ return 0;
+}
+
+static int muqss_iotime_kernwork_ns_show(void *data, struct seq_file *m)
+{
+ seq_printf(m, "%llu\n", (u64)atomic64_read(&kernwork_ns));
+ return 0;
+}
+
+static const struct blk_mq_debugfs_attr muqss_iotime_debugfs_attrs[] = {
+ {"occupancy_ns", 0400, muqss_iotime_occupancy_show},
+ {"requests", 0400, muqss_iotime_requests_show},
+ {"unattributed", 0400, muqss_iotime_unattributed_show},
+ {"mixed", 0400, muqss_iotime_mixed_show},
+ {"unstamped", 0400, muqss_iotime_unstamped_show},
+ {"nostamp_bio", 0400, muqss_iotime_nostamp_bio_show},
+ {"owner_slots_exhausted", 0400, muqss_iotime_exhausted_show},
+ {"proxied", 0400, muqss_iotime_proxied_show},
+ {"owner_tag_bits", 0400, muqss_iotime_owner_width_show},
+ {"kernwork", 0400, muqss_iotime_kernwork_show},
+ {"kernwork_ns", 0400, muqss_iotime_kernwork_ns_show},
+ {},
+};
+#endif
+
+static const struct rq_qos_ops muqss_iotime_ops = {
+ .track = muqss_iotime_track,
+ .merge = muqss_iotime_merge,
+ .done = muqss_iotime_done,
+ .done_bio = muqss_iotime_done_bio,
+ .exit = muqss_iotime_exit,
+#ifdef CONFIG_BLK_DEBUG_FS
+ .debugfs_attrs = muqss_iotime_debugfs_attrs,
+#endif
+};
+
+void muqss_iotime_enable(struct gendisk *disk)
+{
+ struct request_queue *q = disk->queue;
+ unsigned int memflags;
+ struct blk_iotime *bit;
+ int ret;
+
+ if (!queue_is_mq(q))
+ return;
+
+ /*
+ * Only attach to queues backed by real hardware.
+ *
+ * A stacking driver that uses blk-mq -- loop is the common one --
+ * serves its requests by doing I/O to another block device, which runs
+ * this policy too. Accounting both charges the task twice for one
+ * trip to the disk, and with the deadline charge live that is a real
+ * distortion rather than a cosmetic one.
+ *
+ * Drivers for physical devices pass their parent through
+ * device_add_disk(): nvme passes ctrl->device, sd its scsi_device,
+ * virtio_blk its virtio device. Virtual ones call add_disk(), which
+ * is device_add_disk(NULL, ...) -- loop, brd, zram, nbd. So the
+ * absence of a parent is a serviceable test for "not a device whose
+ * busy time means anything".
+ *
+ * Bio based stacking drivers (dm, md) never reach here at all, having
+ * failed queue_is_mq() above.
+ */
+ if (!disk_to_dev(disk)->parent)
+ return;
+
+ bit = kzalloc_obj(*bit);
+ if (!bit)
+ return;
+
+ mutex_lock(&q->rq_qos_mutex);
+ ret = rq_qos_add(&bit->rqos, disk, RQ_QOS_MUQSS_IOTIME,
+ &muqss_iotime_ops);
+ mutex_unlock(&q->rq_qos_mutex);
+ if (ret) {
+ kfree(bit);
+ return;
+ }
+
+ /* Needed for rq->io_start_time_ns to be stamped at dispatch. */
+ blk_stat_enable_accounting(q);
+ /* Needed for bio->issue_time_ns to be stamped at submit. */
+ blk_queue_flag_set(QUEUE_FLAG_BIO_ISSUE_TIME, q);
+
+ memflags = blk_debugfs_lock(q);
+ blk_mq_debugfs_register_rq_qos(q);
+ blk_debugfs_unlock(q, memflags);
+}
diff --git a/block/blk-merge.c b/block/blk-merge.c
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -12,6 +12,8 @@
#include <trace/events/block.h>
+#include <linux/muqss_iotime.h>
+
#include "blk.h"
#include "blk-mq-sched.h"
#include "blk-rq-qos.h"
@@ -848,6 +850,7 @@ static struct request *attempt_merge(struct request_queue *q,
* 'next' is going away, so update stats accordingly
*/
blk_account_io_merge_request(next);
+ muqss_iotime_merge_requests(req, next);
trace_block_rq_merge(next);
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c
--- a/block/blk-mq-debugfs.c
+++ b/block/blk-mq-debugfs.c
@@ -757,6 +757,8 @@ static const char *rq_qos_id_to_name(enum rq_qos_id id)
return "latency";
case RQ_QOS_COST:
return "cost";
+ case RQ_QOS_MUQSS_IOTIME:
+ return "iotime";
}
return "unknown";
}
diff --git a/block/blk-mq.c b/block/blk-mq.c
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -41,6 +41,7 @@
#include "blk-stat.h"
#include "blk-mq-sched.h"
#include "blk-rq-qos.h"
+#include <linux/muqss_iotime.h>
static DEFINE_PER_CPU(struct llist_head, blk_cpu_done);
static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd);
@@ -398,12 +399,48 @@ static inline void blk_mq_rq_time_init(struct request *rq, u64 alloc_time_ns)
#endif
}
+/*
+ * Record the completion timestamp for MuQSS I/O accounting.
+ *
+ * rq_qos_done() is reached only after blk_update_request() has run bio_endio()
+ * on every bio of the request, so a timestamp taken inside the policy is later
+ * than the request actually finished, and lands after the per bio latency
+ * stamp. Occupancy then measures longer than the end to end latency it is
+ * supposed to be a subset of.
+ *
+ * Does not overwrite: the first caller to record a stamp is the earliest and
+ * therefore the most accurate one.
+ */
+static inline void blk_mq_set_iotime_done(struct request *rq, u64 now)
+{
+#ifdef CONFIG_MUQSS_IOTIME
+ if (!rq->muqss_done_ns)
+ rq->muqss_done_ns = now;
+#endif
+}
+
+/*
+ * Take the completion stamp before bio completion. Costs an extra timestamp
+ * on the completion path, which cannot be avoided by reusing the one taken
+ * for blk-stat: that one is deliberately read after blk_update_request() and
+ * moving it would change accounting shared with everybody else.
+ */
+static inline void blk_mq_capture_iotime_done(struct request *rq)
+{
+#ifdef CONFIG_MUQSS_IOTIME
+ if (blk_mq_need_time_stamp(rq))
+ rq->muqss_done_ns = blk_time_get_ns();
+#endif
+}
+
static inline void blk_mq_bio_issue_init(struct request_queue *q,
struct bio *bio)
{
-#ifdef CONFIG_BLK_CGROUP
- if (test_bit(QUEUE_FLAG_BIO_ISSUE_TIME, &q->queue_flags))
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_MUQSS_IOTIME)
+ if (test_bit(QUEUE_FLAG_BIO_ISSUE_TIME, &q->queue_flags)) {
bio->issue_time_ns = blk_time_get_ns();
+ muqss_iotime_set_owner(bio);
+ }
#endif
}
@@ -435,6 +472,10 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data,
rq->part = NULL;
rq->io_start_time_ns = 0;
+#ifdef CONFIG_MUQSS_IOTIME
+ rq->muqss_owner = NULL;
+ rq->muqss_done_ns = 0;
+#endif
rq->stats_sectors = 0;
rq->nr_phys_segments = 0;
rq->nr_integrity_segments = 0;
@@ -1127,8 +1168,12 @@ static inline void __blk_mq_end_request_acct(struct request *rq, u64 now)
inline void __blk_mq_end_request(struct request *rq, blk_status_t error)
{
- if (blk_mq_need_time_stamp(rq))
- __blk_mq_end_request_acct(rq, blk_time_get_ns());
+ if (blk_mq_need_time_stamp(rq)) {
+ u64 now = blk_time_get_ns();
+
+ blk_mq_set_iotime_done(rq, now);
+ __blk_mq_end_request_acct(rq, now);
+ }
blk_mq_finish_request(rq);
@@ -1144,6 +1189,7 @@ EXPORT_SYMBOL(__blk_mq_end_request);
void blk_mq_end_request(struct request *rq, blk_status_t error)
{
+ blk_mq_capture_iotime_done(rq);
if (blk_update_request(rq, error, blk_rq_bytes(rq)))
BUG();
__blk_mq_end_request(rq, error);
@@ -1178,8 +1224,10 @@ void blk_mq_end_request_batch(struct io_comp_batch *iob)
prefetch(rq->rq_next);
blk_complete_request(rq);
- if (iob->need_ts)
+ if (iob->need_ts) {
+ blk_mq_set_iotime_done(rq, now);
__blk_mq_end_request_acct(rq, now);
+ }
blk_mq_finish_request(rq);
diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h
--- a/block/blk-rq-qos.h
+++ b/block/blk-rq-qos.h
@@ -17,6 +17,7 @@ enum rq_qos_id {
RQ_QOS_WBT,
RQ_QOS_LATENCY,
RQ_QOS_COST,
+ RQ_QOS_MUQSS_IOTIME,
};
struct rq_wait {
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -20,6 +20,7 @@
#include "blk-cgroup.h"
#include "blk-throttle.h"
#include "error-injection.h"
+#include <linux/muqss_iotime.h>
struct queue_sysfs_entry {
struct attribute attr;
@@ -993,6 +994,7 @@ int blk_register_queue(struct gendisk *disk)
blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q);
wbt_init_enable_default(disk);
+ muqss_iotime_enable(disk);
/* Now everything is ready and send out KOBJ_ADD uevent */
kobject_uevent(&disk->queue_kobj, KOBJ_ADD);
diff --git a/drivers/accessibility/speakup/speakup_acntpc.c b/drivers/accessibility/speakup/speakup_acntpc.c
--- a/drivers/accessibility/speakup/speakup_acntpc.c
+++ b/drivers/accessibility/speakup/speakup_acntpc.c
@@ -207,7 +207,7 @@ static void do_catch_up(struct spk_synth *synth)
full_time_val = full_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (synth_full()) {
- schedule_timeout(msecs_to_jiffies(full_time_val));
+ schedule_msec_hrtimeout(full_time_val);
continue;
}
set_current_state(TASK_RUNNING);
@@ -235,7 +235,7 @@ static void do_catch_up(struct spk_synth *synth)
jiffy_delta_val = jiffy_delta->u.n.value;
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
}
diff --git a/drivers/accessibility/speakup/speakup_apollo.c b/drivers/accessibility/speakup/speakup_apollo.c
--- a/drivers/accessibility/speakup/speakup_apollo.c
+++ b/drivers/accessibility/speakup/speakup_apollo.c
@@ -178,7 +178,7 @@ static void do_catch_up(struct spk_synth *synth)
if (!synth->io_ops->synth_out(synth, ch)) {
synth->io_ops->tiocmset(synth, 0, UART_MCR_RTS);
synth->io_ops->tiocmset(synth, UART_MCR_RTS, 0);
- schedule_timeout(msecs_to_jiffies(full_time_val));
+ schedule_msec_hrtimeout(full_time_val);
continue;
}
if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
@@ -188,11 +188,9 @@ static void do_catch_up(struct spk_synth *synth)
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (synth->io_ops->synth_out(synth, synth->procspeech))
- schedule_timeout(msecs_to_jiffies
- (delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
else
- schedule_timeout(msecs_to_jiffies
- (full_time_val));
+ schedule_msec_hrtimeout(full_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/accessibility/speakup/speakup_decext.c b/drivers/accessibility/speakup/speakup_decext.c
--- a/drivers/accessibility/speakup/speakup_decext.c
+++ b/drivers/accessibility/speakup/speakup_decext.c
@@ -189,7 +189,7 @@ static void do_catch_up(struct spk_synth *synth)
if (ch == '\n')
ch = 0x0D;
if (synth_full() || !synth->io_ops->synth_out(synth, ch)) {
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
continue;
}
set_current_state(TASK_RUNNING);
@@ -213,8 +213,7 @@ static void do_catch_up(struct spk_synth *synth)
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock,
flags);
- schedule_timeout(msecs_to_jiffies
- (delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
}
diff --git a/drivers/accessibility/speakup/speakup_decpc.c b/drivers/accessibility/speakup/speakup_decpc.c
--- a/drivers/accessibility/speakup/speakup_decpc.c
+++ b/drivers/accessibility/speakup/speakup_decpc.c
@@ -409,7 +409,7 @@ static void do_catch_up(struct spk_synth *synth)
if (ch == '\n')
ch = 0x0D;
if (dt_sendchar(ch)) {
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
continue;
}
set_current_state(TASK_RUNNING);
@@ -432,8 +432,7 @@ static void do_catch_up(struct spk_synth *synth)
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock,
flags);
- schedule_timeout(msecs_to_jiffies
- (delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
}
diff --git a/drivers/accessibility/speakup/speakup_dectlk.c b/drivers/accessibility/speakup/speakup_dectlk.c
--- a/drivers/accessibility/speakup/speakup_dectlk.c
+++ b/drivers/accessibility/speakup/speakup_dectlk.c
@@ -265,7 +265,7 @@ static void do_catch_up(struct spk_synth *synth)
if (ch == '\n')
ch = 0x0D;
if (synth_full_val || !synth->io_ops->synth_out(synth, ch)) {
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
continue;
}
set_current_state(TASK_RUNNING);
@@ -289,8 +289,7 @@ static void do_catch_up(struct spk_synth *synth)
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock,
flags);
- schedule_timeout(msecs_to_jiffies
- (delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
}
diff --git a/drivers/accessibility/speakup/speakup_dtlk.c b/drivers/accessibility/speakup/speakup_dtlk.c
--- a/drivers/accessibility/speakup/speakup_dtlk.c
+++ b/drivers/accessibility/speakup/speakup_dtlk.c
@@ -221,7 +221,7 @@ static void do_catch_up(struct spk_synth *synth)
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (synth_full()) {
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
continue;
}
set_current_state(TASK_RUNNING);
@@ -237,7 +237,7 @@ static void do_catch_up(struct spk_synth *synth)
delay_time_val = delay_time->u.n.value;
jiffy_delta_val = jiffy_delta->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
}
diff --git a/drivers/accessibility/speakup/speakup_keypc.c b/drivers/accessibility/speakup/speakup_keypc.c
--- a/drivers/accessibility/speakup/speakup_keypc.c
+++ b/drivers/accessibility/speakup/speakup_keypc.c
@@ -208,7 +208,7 @@ static void do_catch_up(struct spk_synth *synth)
full_time_val = full_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (synth_full()) {
- schedule_timeout(msecs_to_jiffies(full_time_val));
+ schedule_msec_hrtimeout(full_time_val);
continue;
}
set_current_state(TASK_RUNNING);
@@ -241,7 +241,7 @@ static void do_catch_up(struct spk_synth *synth)
jiffy_delta_val = jiffy_delta->u.n.value;
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- schedule_timeout(msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
}
diff --git a/drivers/accessibility/speakup/synth.c b/drivers/accessibility/speakup/synth.c
--- a/drivers/accessibility/speakup/synth.c
+++ b/drivers/accessibility/speakup/synth.c
@@ -98,7 +98,7 @@ static void _spk_do_catch_up(struct spk_synth *synth, int unicode)
else
ret = synth->io_ops->synth_out(synth, ch);
if (!ret) {
- schedule_timeout(msecs_to_jiffies(full_time_val));
+ schedule_msec_hrtimeout(full_time_val);
continue;
}
if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
@@ -108,11 +108,9 @@ static void _spk_do_catch_up(struct spk_synth *synth, int unicode)
full_time_val = full_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (synth->io_ops->synth_out(synth, synth->procspeech))
- schedule_timeout(
- msecs_to_jiffies(delay_time_val));
+ schedule_msec_hrtimeout(delay_time_val);
else
- schedule_timeout(
- msecs_to_jiffies(full_time_val));
+ schedule_msec_hrtimeout(full_time_val);
jiff_max = jiffies + jiffy_delta_val;
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/auxdisplay/hd44780_common.c b/drivers/auxdisplay/hd44780_common.c
--- a/drivers/auxdisplay/hd44780_common.c
+++ b/drivers/auxdisplay/hd44780_common.c
@@ -34,7 +34,7 @@
/* sleeps that many milliseconds with a reschedule */
static void long_sleep(int ms)
{
- schedule_timeout_interruptible(msecs_to_jiffies(ms));
+ schedule_msec_hrtimeout_interruptible(ms);
}
int hd44780_common_print(struct charlcd *lcd, int c)
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -330,7 +330,7 @@ static inline void swim_motor(struct swim __iomem *base,
if (swim_readbit(base, MOTOR_ON))
break;
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_min_hrtimeout();
}
} else if (action == OFF) {
swim_action(base, MOTOR_OFF);
@@ -349,7 +349,7 @@ static inline void swim_eject(struct swim __iomem *base)
if (!swim_readbit(base, DISK_IN))
break;
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_min_hrtimeout();
}
swim_select(base, RELAX);
}
@@ -373,7 +373,7 @@ static inline int swim_step(struct swim __iomem *base)
for (wait = 0; wait < HZ; wait++) {
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_min_hrtimeout();
swim_select(base, RELAX);
if (!swim_readbit(base, STEP))
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -3804,7 +3804,7 @@ static void cleanup_smi_msgs(struct ipmi_smi *intf)
/* Current message first, to preserve order */
while (intf->curr_msg && !list_empty(&intf->waiting_rcv_msgs)) {
/* Wait for the message to clear out. */
- schedule_timeout(1);
+ schedule_min_hrtimeout();
}
/* No need for locks, the interface is down. */
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -1282,7 +1282,7 @@ static void shutdown_ssif(void *send_info)
/* make sure the driver is not looking for flags any more. */
while (ssif_info->ssif_state != SSIF_IDLE)
- schedule_timeout(1);
+ schedule_min_hrtimeout();
ssif_info->stopping = true;
timer_delete_sync(&ssif_info->watch_timer);
diff --git a/drivers/comedi/drivers/ni_mio_common.c b/drivers/comedi/drivers/ni_mio_common.c
--- a/drivers/comedi/drivers/ni_mio_common.c
+++ b/drivers/comedi/drivers/ni_mio_common.c
@@ -4762,7 +4762,7 @@ static int cs5529_wait_for_idle(struct comedi_device *dev)
if ((status & NI67XX_CAL_STATUS_BUSY) == 0)
break;
set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout(1))
+ if (schedule_min_hrtimeout())
return -EIO;
}
if (i == timeout) {
diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c
--- a/drivers/crypto/ccp/tee-dev.c
+++ b/drivers/crypto/ccp/tee-dev.c
@@ -270,7 +270,7 @@ static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
/* Wait if ring buffer is full or TEE is processing data */
mutex_unlock(&tee->rb_mgr.mutex);
- schedule_timeout_interruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_interruptible(10);
mutex_lock(&tee->rb_mgr.mutex);
} while (--nloop);
diff --git a/drivers/gpib/nec7210/nec7210.c b/drivers/gpib/nec7210/nec7210.c
--- a/drivers/gpib/nec7210/nec7210.c
+++ b/drivers/gpib/nec7210/nec7210.c
@@ -317,7 +317,7 @@ int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv)
if (i == timeout) {
for (i = 0; i < HZ; i++) {
set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout(1))
+ if (schedule_min_hrtimeout())
return -ERESTARTSYS;
adsr_bits = read_byte(priv, ADSR);
if (adsr_bits & HR_NATN)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
@@ -215,7 +215,7 @@ static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv,
DRM_ERROR("SVGA device lockup.\n");
break;
}
- schedule_timeout(1);
+ schedule_min_hrtimeout();
if (interruptible && signal_pending(current)) {
ret = -ERESTARTSYS;
break;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -200,7 +200,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
break;
}
if (lazy)
- schedule_timeout(1);
+ schedule_min_hrtimeout();
else if ((++count & 0x0F) == 0) {
/**
* FIXME: Use schedule_hr_timeout here for
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -332,7 +332,7 @@ static int adt7470_update_thread(void *p)
if (kthread_should_stop())
break;
- schedule_timeout_interruptible(msecs_to_jiffies(data->auto_update_interval));
+ schedule_msec_hrtimeout_interruptible(data->auto_update_interval);
}
return 0;
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -221,7 +221,7 @@ static ssize_t power1_average_show(struct device *dev,
prev_ptsc[cu] = data->cpu_sw_pwr_ptsc[cu];
}
- leftover = schedule_timeout_interruptible(msecs_to_jiffies(data->power_period));
+ leftover = schedule_msec_hrtimeout_interruptible(data->power_period);
if (leftover)
return 0;
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -827,9 +827,8 @@ static ssize_t aem_show_power(struct device *dev,
time = ktime_get_ns();
before = data->energy[attr->index];
- leftover = schedule_timeout_interruptible(
- msecs_to_jiffies(data->power_period[attr->index])
- );
+ leftover = schedule_msec_hrtimeout_interruptible(
+ data->power_period[attr->index]);
if (leftover) {
mutex_unlock(&data->lock);
return 0;
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -274,11 +274,7 @@ static void tsl2563_wait_adc(struct tsl2563_chip *chip)
default:
delay = 402;
}
- /*
- * TODO: Make sure that we wait at least required delay but why we
- * have to extend it one tick more?
- */
- schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2);
+ schedule_msec_hrtimeout_interruptible(delay + 1);
}
static int tsl2563_adjust_gainlevel(struct tsl2563_chip *chip, u16 adc)
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -1846,8 +1846,7 @@ static void bch_btree_gc(struct cache_set *c)
cond_resched();
if (ret == -EAGAIN)
- schedule_timeout_interruptible(
- msecs_to_jiffies(btree_gc_sleep_ms(c)));
+ schedule_msec_hrtimeout_interruptible(btree_gc_sleep_ms(c));
else if (ret)
pr_warn("gc failed!\n");
} while (ret && !test_bit(CACHE_SET_IO_DISABLE, &c->flags));
diff --git a/drivers/media/i2c/bt866.c b/drivers/media/i2c/bt866.c
--- a/drivers/media/i2c/bt866.c
+++ b/drivers/media/i2c/bt866.c
@@ -65,7 +65,7 @@ static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
err++;
v4l_warn(client, "error #%d writing to 0x%02x\n",
err, subaddr);
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
}
if (err == 3) {
v4l_warn(client, "giving up\n");
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -698,7 +698,7 @@ static int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf,
*/
for (i = 0; i < 20; ++i) {
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(50));
+ schedule_msec_hrtimeout(50);
ret = i2c_master_send(ir->tx_c, buf, 1);
if (ret == 1)
break;
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -170,7 +170,7 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
break;
dev_warn(&client->dev, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
dev, addr);
- schedule_timeout_interruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_interruptible(10);
}
if (err == 3) {
dev_warn(&client->dev, "resetting chip, sound will go off.\n");
@@ -211,7 +211,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
break;
dev_warn(&client->dev, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
dev, addr);
- schedule_timeout_interruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_interruptible(10);
}
if (err == 3) {
dev_warn(&client->dev, "resetting chip, sound will go off.\n");
diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c
--- a/drivers/media/i2c/saa7110.c
+++ b/drivers/media/i2c/saa7110.c
@@ -184,7 +184,7 @@ static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
saa7110_write_block(sd, initseq, sizeof(initseq));
saa7110_selmux(sd, decoder->input);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(250));
+ schedule_msec_hrtimeout(250);
finish_wait(&decoder->wq, &wait);
status = saa7110_read(sd);
if (status & 0x40) {
@@ -219,7 +219,7 @@ static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
/*saa7110_write(sd,0x2E,0x9A);*/
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(250));
+ schedule_msec_hrtimeout(250);
finish_wait(&decoder->wq, &wait);
status = saa7110_read(sd);
diff --git a/drivers/media/pci/cx18/cx18-gpio.c b/drivers/media/pci/cx18/cx18-gpio.c
--- a/drivers/media/pci/cx18/cx18-gpio.c
+++ b/drivers/media/pci/cx18/cx18-gpio.c
@@ -81,11 +81,11 @@ static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi,
/* Assert */
gpio_update(cx, mask, ~active_lo);
- schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs));
+ schedule_msec_hrtimeout_uninterruptible(assert_msecs);
/* Deassert */
gpio_update(cx, mask, ~active_hi);
- schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs));
+ schedule_msec_hrtimeout_uninterruptible(recovery_msecs);
}
/*
diff --git a/drivers/media/pci/hws/hws_pci.c b/drivers/media/pci/hws/hws_pci.c
--- a/drivers/media/pci/hws/hws_pci.c
+++ b/drivers/media/pci/hws/hws_pci.c
@@ -215,7 +215,7 @@ static int main_ks_thread_handle(void *data)
/* If we're suspending, don't touch hardware; just sleep/freeze. */
if (READ_ONCE(pdx->suspended)) {
try_to_freeze();
- schedule_timeout_interruptible(msecs_to_jiffies(1000));
+ schedule_msec_hrtimeout_interruptible(1000);
continue;
}
@@ -225,7 +225,7 @@ static int main_ks_thread_handle(void *data)
try_to_freeze(); /* cooperate with freezer each loop */
/* Sleep 1s or until signaled to wake/stop */
- schedule_timeout_interruptible(msecs_to_jiffies(1000));
+ schedule_msec_hrtimeout_interruptible(1000);
}
dev_dbg(&pdx->pdev->dev, "%s: exiting\n", __func__);
diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c
--- a/drivers/media/pci/ivtv/ivtv-gpio.c
+++ b/drivers/media/pci/ivtv/ivtv-gpio.c
@@ -105,7 +105,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
curout = (curout & ~0xF) | 1;
write_reg(curout, IVTV_REG_GPIO_OUT);
/* We could use something else for smaller time */
- schedule_timeout_interruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_interruptible(1);
curout |= 2;
write_reg(curout, IVTV_REG_GPIO_OUT);
curdir &= ~0x80;
@@ -125,11 +125,11 @@ int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
curout = read_reg(IVTV_REG_GPIO_OUT);
curout &= ~(1 << itv->card->xceive_pin);
write_reg(curout, IVTV_REG_GPIO_OUT);
- schedule_timeout_interruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_interruptible(1);
curout |= 1 << itv->card->xceive_pin;
write_reg(curout, IVTV_REG_GPIO_OUT);
- schedule_timeout_interruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_interruptible(1);
return 0;
}
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -1141,7 +1141,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std)
TASK_UNINTERRUPTIBLE);
if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100)
break;
- schedule_timeout(msecs_to_jiffies(25));
+ schedule_msec_hrtimeout(25);
}
finish_wait(&itv->vsync_waitq, &wait);
mutex_lock(&itv->serialize_lock);
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
--- a/drivers/media/pci/ivtv/ivtv-streams.c
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -835,7 +835,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
time_before(jiffies,
then + msecs_to_jiffies(2000))) {
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout(10);
}
/* To convert jiffies to ms, we must multiply by 1000
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
--- a/drivers/media/pci/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -474,7 +474,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
case FBIO_WAITFORVSYNC:
prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
- if (!schedule_timeout(msecs_to_jiffies(50)))
+ if (!schedule_msec_hrtimeout(50))
rc = -ETIMEDOUT;
finish_wait(&itv->vsync_waitq, &wait);
return rc;
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
--- a/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -307,8 +307,7 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
set_current_state(TASK_INTERRUPTIBLE);
schedule();
} else {
- schedule_timeout_interruptible
- (msecs_to_jiffies(timeout));
+ schedule_msec_hrtimeout_interruptible(timeout);
}
}
return dev->thread.scan1 != dev->thread.scan2;
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -366,7 +366,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
retval = -ENODATA;
break;
}
- if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+ if (schedule_msec_hrtimeout_interruptible(10)) {
retval = -ERESTARTSYS;
break;
}
diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c
--- a/drivers/media/radio/radio-tea5777.c
+++ b/drivers/media/radio/radio-tea5777.c
@@ -235,7 +235,7 @@ static int radio_tea5777_update_read_reg(struct radio_tea5777 *tea, int wait)
}
if (wait) {
- if (schedule_timeout_interruptible(msecs_to_jiffies(wait)))
+ if (schedule_msec_hrtimeout_interruptible(wait))
return -ERESTARTSYS;
}
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -401,7 +401,7 @@ int snd_tea575x_s_hw_freq_seek(struct file *file, struct snd_tea575x *tea,
for (;;) {
if (time_after(jiffies, timeout))
break;
- if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+ if (schedule_msec_hrtimeout_interruptible(10)) {
/* some signal arrived, stop search */
tea->val &= ~TEA575X_BIT_SEARCH;
snd_tea575x_set_freq(tea);
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
--- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
@@ -297,7 +297,7 @@ static int rotation_thread_function(void *data)
__s32 vflip, hflip;
set_current_state(TASK_INTERRUPTIBLE);
- while (!schedule_timeout(msecs_to_jiffies(100))) {
+ while (!schedule_msec_hrtimeout(100)) {
if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
break;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -253,7 +253,7 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
break;
/* yield to other processes */
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_min_hrtimeout();
}
return UCB_ADC_DAT(val);
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -1464,7 +1464,7 @@ int mei_me_polling_thread(void *_dev)
MEI_POLLING_TIMEOUT_IDLE);
}
- schedule_timeout_interruptible(msecs_to_jiffies(polling_timeout));
+ schedule_msec_hrtimeout_interruptible(polling_timeout);
}
return 0;
diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c
--- a/drivers/misc/sgi-xp/xpc_channel.c
+++ b/drivers/misc/sgi-xp/xpc_channel.c
@@ -834,7 +834,7 @@ xpc_allocate_msg_wait(struct xpc_channel *ch)
atomic_inc(&ch->n_on_msg_allocate_wq);
prepare_to_wait(&ch->msg_allocate_wq, &wait, TASK_INTERRUPTIBLE);
- ret = schedule_timeout(1);
+ ret = schedule_min_hrtimeout();
finish_wait(&ch->msg_allocate_wq, &wait);
atomic_dec(&ch->n_on_msg_allocate_wq);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -308,7 +308,7 @@ static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff)
} else {
/* the PCAN-USB needs time to init */
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT));
+ schedule_msec_hrtimeout(PCAN_USB_STARTUP_TIMEOUT);
}
return err;
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
--- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
@@ -1090,7 +1090,7 @@ static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs)
struct napi_struct *napi, *n;
int ret;
- schedule_timeout_uninterruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_uninterruptible(100);
if (wait_for_pending_requests(oct))
dev_err(&oct->pci_dev->dev, "There were pending requests\n");
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -758,7 +758,7 @@ static int liquidio_watchdog(void *param)
while (!kthread_should_stop()) {
/* sleep for a couple of seconds so that we don't hog the CPU */
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(2000));
+ schedule_msec_hrtimeout(2000);
mask_of_crashed_or_stuck_cores =
(u16)octeon_read_csr64(oct, CN23XX_SLI_SCRATCH2);
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -3514,7 +3514,7 @@ static void lan78xx_terminate_urbs(struct lan78xx_net *dev)
/* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq) ||
!skb_queue_empty(&dev->txq)) {
- schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
+ schedule_msec_hrtimeout(UNLINK_TIMEOUT_MS);
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions", temp);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -791,7 +791,7 @@ static void wait_skb_queue_empty(struct sk_buff_head *q)
spin_lock_irqsave(&q->lock, flags);
while (!skb_queue_empty(q)) {
spin_unlock_irqrestore(&q->lock, flags);
- schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
+ schedule_msec_hrtimeout(UNLINK_TIMEOUT_MS);
set_current_state(TASK_UNINTERRUPTIBLE);
spin_lock_irqsave(&q->lock, flags);
}
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -799,7 +799,7 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
* doesn't seem to have as many firmware restart cycles...
*
* As a test, we're sticking in a 1/100s delay here */
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_uninterruptible(10);
return 0;
@@ -1250,7 +1250,7 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv)
IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
i = 5000;
do {
- schedule_timeout_uninterruptible(msecs_to_jiffies(40));
+ schedule_msec_hrtimeout_uninterruptible(40);
/* Todo... wait for sync command ... */
read_register(priv->net_dev, IPW_REG_INTA, &inta);
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -202,7 +202,7 @@ int parport_wait_peripheral(struct parport *port,
/* parport_wait_event didn't time out, but the
* peripheral wasn't actually ready either.
* Wait for another 10ms. */
- schedule_timeout_interruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_interruptible(10);
}
}
diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c
--- a/drivers/parport/ieee1284_ops.c
+++ b/drivers/parport/ieee1284_ops.c
@@ -520,7 +520,7 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port,
/* Yield the port for a while. */
if (dev->port->irq != PARPORT_IRQ_NONE) {
parport_release (dev);
- schedule_timeout_interruptible(msecs_to_jiffies(40));
+ schedule_msec_hrtimeout_interruptible(40);
parport_claim_or_block (dev);
}
else
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -177,8 +177,7 @@ static int change_mode(struct parport *p, int m)
if (time_after_eq(jiffies, expire))
/* The FIFO is stuck. */
return -EBUSY;
- schedule_timeout_interruptible(
- msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_interruptible(10);
if (signal_pending(current))
break;
}
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -806,7 +806,7 @@ static int ips_adjust(void *data)
ips_gpu_lower(ips);
sleep:
- schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD));
+ schedule_msec_hrtimeout_interruptible(IPS_ADJUST_PERIOD);
} while (!kthread_should_stop());
dev_dbg(ips->dev, "ips-adjust thread stopped\n");
@@ -984,7 +984,7 @@ static int ips_monitor(void *data)
seqno_timestamp = get_jiffies_64();
old_cpu_power = thm_readl(THM_CEC);
- schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+ schedule_msec_hrtimeout_interruptible(IPS_SAMPLE_PERIOD);
/* Collect an initial average */
for (i = 0; i < IPS_SAMPLE_COUNT; i++) {
@@ -1011,7 +1011,7 @@ static int ips_monitor(void *data)
mchp_samples[i] = mchp;
}
- schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+ schedule_msec_hrtimeout_interruptible(IPS_SAMPLE_PERIOD);
if (kthread_should_stop())
break;
}
@@ -1038,7 +1038,7 @@ static int ips_monitor(void *data)
* us to reduce the sample frequency if the CPU and GPU are idle.
*/
old_cpu_power = thm_readl(THM_CEC);
- schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+ schedule_msec_hrtimeout_interruptible(IPS_SAMPLE_PERIOD);
last_sample_period = IPS_SAMPLE_PERIOD;
timer_setup(&ips->timer, monitor_timeout, TIMER_DEFERRABLE);
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -114,7 +114,7 @@ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm)
/* Wait until confirmation of stopping */
do {
rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
- schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_uninterruptible(1);
} while (--retries && !(rtc_ctrl & WM8350_RTC_STS));
if (!retries) {
@@ -197,7 +197,7 @@ static int wm8350_rtc_stop_alarm(struct wm8350 *wm8350)
/* Wait until confirmation of stopping */
do {
rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
- schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_uninterruptible(1);
} while (retries-- && !(rtc_ctrl & WM8350_RTC_ALMSTS));
if (!(rtc_ctrl & WM8350_RTC_ALMSTS))
@@ -220,7 +220,7 @@ static int wm8350_rtc_start_alarm(struct wm8350 *wm8350)
/* Wait until confirmation */
do {
rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
- schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_uninterruptible(1);
} while (retries-- && rtc_ctrl & WM8350_RTC_ALMSTS);
if (rtc_ctrl & WM8350_RTC_ALMSTS)
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -68,7 +68,7 @@ static int sdias_sclp_send(struct sclp_req *req)
/* not initiated, wait some time and retry */
set_current_state(TASK_INTERRUPTIBLE);
TRACE("add request failed: rc = %i\n",rc);
- schedule_timeout(msecs_to_jiffies(500));
+ schedule_msec_hrtimeout(500);
continue;
}
/* initiated, wait for completion of service call */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -611,7 +611,7 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
if (time_after(jiffies, timeout))
break;
/* 1ms sleep is enough in most cases */
- schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_uninterruptible(1);
} while (!ready);
beiscsi_log(phba, KERN_ERR,
diff --git a/drivers/scsi/esas2r/esas2r_flash.c b/drivers/scsi/esas2r/esas2r_flash.c
--- a/drivers/scsi/esas2r/esas2r_flash.c
+++ b/drivers/scsi/esas2r/esas2r_flash.c
@@ -965,7 +965,7 @@ static bool esas2r_flash_access(struct esas2r_adapter *a, u32 function)
break;
}
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
/*
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
--- a/drivers/scsi/esas2r/esas2r_init.c
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -994,7 +994,7 @@ bool esas2r_check_adapter(struct esas2r_adapter *a)
break;
}
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
if ((jiffies_to_msecs(jiffies) - starttime) > 180000) {
esas2r_hdebug("FW ready TMO");
@@ -1017,7 +1017,7 @@ bool esas2r_check_adapter(struct esas2r_adapter *a)
break;
}
- schedule_timeout_interruptible(msecs_to_jiffies(50));
+ schedule_msec_hrtimeout_interruptible(50);
if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
esas2r_hdebug("timeout waiting for interface down");
@@ -1106,7 +1106,7 @@ bool esas2r_check_adapter(struct esas2r_adapter *a)
break;
}
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
esas2r_hdebug(
@@ -1356,7 +1356,7 @@ bool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll)
atomic_dec(&a->disable_cnt);
while (test_bit(AF_DISC_PENDING, &a->flags)) {
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
/*
* Determine the need for a timer tick based on the
@@ -1512,7 +1512,7 @@ static void esas2r_power_down_notify_firmware(struct esas2r_adapter *a)
break;
}
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
if ((jiffies_to_msecs(jiffies) - starttime) > 30000) {
esas2r_hdebug("Timeout waiting for power down");
@@ -1557,7 +1557,7 @@ void esas2r_power_down(struct esas2r_adapter *a)
break;
}
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
esas2r_hdebug(
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -1247,7 +1247,7 @@ void esas2r_wait_request(struct esas2r_adapter *a, struct esas2r_request *rq)
if (rq->req_stat != RS_STARTED)
break;
- schedule_timeout_interruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_interruptible(100);
if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
esas2r_hdebug("request TMO");
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -258,7 +258,7 @@ int fnic_fw_reset_handler(struct fnic *fnic)
/* wait for io cmpl */
while (atomic_read(&fnic->in_flight))
- schedule_timeout(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout(1);
spin_lock_irqsave(&fnic->wq_copy_lock[0], flags);
@@ -1634,7 +1634,7 @@ static void fnic_cleanup_io(struct fnic *fnic, int exclude_id)
io_count,
atomic64_read(&fnic->fnic_stats.io_stats.active_ios));
- schedule_timeout(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout(100);
}
}
@@ -1912,7 +1912,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id)
atomic_dec(&fnic->in_flight);
while ((io_count = fnic_count_ioreqs(fnic, port_id)))
- schedule_timeout(msecs_to_jiffies(1000));
+ schedule_msec_hrtimeout(1000);
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
"rport: 0x%x remaining portid-io-count: %d ",
@@ -2510,7 +2510,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
ret = iter_data.ret;
goto clean_pending_aborts_end;
}
- schedule_timeout(msecs_to_jiffies(2 * fnic->config.ed_tov));
+ schedule_msec_hrtimeout(2 * fnic->config.ed_tov);
/* walk again to check, if IOs are still pending in fw */
if (fnic_is_abts_pending(fnic, lr_sc))
@@ -2811,7 +2811,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
}
FNIC_SCSI_DBG(KERN_ERR, fnic,
"Cannot clean up all IOs for the LUN\n");
- schedule_timeout(msecs_to_jiffies(1000));
+ schedule_msec_hrtimeout(1000);
count++;
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -5920,7 +5920,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport)
return FAILED;
if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
return SUCCESS;
- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+ schedule_msec_hrtimeout_uninterruptible(500);
rdata = rport->dd_data;
if (!rdata)
return FAILED;
@@ -5962,7 +5962,7 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id,
tgt_id, lun_id, context);
later = secs_to_jiffies(2 * vport->cfg_devloss_tmo) + jiffies;
while (time_after(later, jiffies) && cnt) {
- schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+ schedule_msec_hrtimeout_uninterruptible(20);
cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context);
}
if (cnt) {
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -1552,7 +1552,7 @@ static int qla4_82xx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
(val == PHAN_INITIALIZE_ACK))
return 0;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(500));
+ schedule_msec_hrtimeout(500);
} while (--retries);
diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c
--- a/drivers/scsi/snic/snic_scsi.c
+++ b/drivers/scsi/snic/snic_scsi.c
@@ -1863,7 +1863,7 @@ snic_dr_clean_pending_req(struct snic *snic, struct scsi_cmnd *lr_sc)
}
}
- schedule_timeout(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout(100);
/* Walk through all the cmds and check abts status. */
if (snic_is_abts_pending(snic, lr_sc))
@@ -2321,7 +2321,7 @@ snic_reset(struct Scsi_Host *shost, struct scsi_cmnd *sc)
/* Wait for all the IOs that are entered in Qcmd */
while (atomic_read(&snic->ios_inflight))
- schedule_timeout(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout(1);
ret = snic_issue_hba_reset(snic, sc);
if (ret) {
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -923,7 +923,7 @@ static int usblp_wwait(struct usblp *usblp, int nonblock)
if (rc <= 0)
break;
- if (schedule_timeout(msecs_to_jiffies(1500)) == 0) {
+ if (schedule_msec_hrtimeout(1500) == 0) {
if (usblp->flags & LP_ABORT) {
err = usblp_check_status(usblp, err);
if (err == 1) { /* Paper out */
diff --git a/drivers/video/fbdev/omap/hwa742.c b/drivers/video/fbdev/omap/hwa742.c
--- a/drivers/video/fbdev/omap/hwa742.c
+++ b/drivers/video/fbdev/omap/hwa742.c
@@ -926,7 +926,7 @@ static void hwa742_resume(void)
if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7))
break;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(5));
+ schedule_msec_hrtimeout(5);
}
hwa742_set_update_mode(hwa742.update_mode_before_suspend);
}
diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c
--- a/drivers/video/fbdev/pxafb.c
+++ b/drivers/video/fbdev/pxafb.c
@@ -1272,7 +1272,7 @@ static int pxafb_smart_thread(void *arg)
mutex_unlock(&fbi->ctrlr_lock);
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(30));
+ schedule_msec_hrtimeout(30);
}
pr_debug("%s(): task ending\n", __func__);
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -28,7 +28,7 @@ static inline void get_lock_elapsed_time(struct f2fs_time_stat *ts)
{
ts->total_time = ktime_get();
#ifdef CONFIG_64BIT
- ts->running_time = current->se.sum_exec_runtime;
+ ts->running_time = tsk_seruntime(current);
#endif
#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
ts->runnable_time = current->sched_info.run_delay;
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -110,7 +110,7 @@ static int jffs2_garbage_collect_thread(void *_c)
* This forces the GCD to slow the hell down. Pulling an
* inode in with read_inode() is much preferable to having
* the GC thread get there first. */
- schedule_timeout_interruptible(msecs_to_jiffies(50));
+ schedule_msec_hrtimeout_interruptible(50);
if (kthread_should_stop()) {
jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
diff --git a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -513,7 +513,7 @@ static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns,
seq_puts(m, "0 0 0\n");
else
seq_printf(m, "%llu %llu %lu\n",
- (unsigned long long)task->se.sum_exec_runtime,
+ (unsigned long long)tsk_seruntime(task),
(unsigned long long)task->sched_info.run_delay,
task->sched_info.pcount);
@@ -521,6 +521,108 @@ static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns,
}
#endif
+#ifdef CONFIG_MUQSS_IOTIME
+/*
+ * Provides /proc/PID/iotime
+ *
+ * Block device time consumed on this task's behalf, in nanoseconds.
+ *
+ * io_latency_ns is end to end per bio and so includes queue wait: it is what
+ * this task waited for. io_occupancy_ns is device service time per request:
+ * it is what this task cost everybody else, and is what scheduling charges
+ * are based on. io_debt_ns is occupancy not yet charged to the deadline.
+ * See block/blk-iotime.c.
+ *
+ * kern_time_ns is CPU time rather than device time: kernel work done for this
+ * task in another thread's context, which today means kworkers running work
+ * items it queued. kern_debt_ns is the part of it not yet charged. Work the
+ * task asks for in its own context is not counted here, because that already
+ * comes out of its own timeslice.
+ *
+ * Access is restricted exactly as /proc/PID/io is, and for the same reason:
+ * these counters say when a task used the device and for how long, which is
+ * enough to infer a good deal about what it is doing. The exec_update_lock
+ * keeps the permission check and the read on the same side of an exec, so
+ * credentials cannot change between the two.
+ *
+ * Also as /proc/PID/io: the tgid file sums the thread group and the tid file
+ * reports one thread. Charging is per thread, since each has its own deadline,
+ * but a multithreaded writer's total is only meaningful summed.
+ */
+struct iotime_acct {
+ u64 latency_ns;
+ u64 count;
+ u64 occupancy_ns;
+ u64 debt_ns;
+ u64 kern_time_ns;
+ u64 kern_debt_ns;
+};
+
+static void iotime_add(struct iotime_acct *acct, struct task_struct *task)
+{
+ acct->latency_ns += atomic64_read(&task->io_latency_ns);
+ acct->count += atomic64_read(&task->io_count);
+ acct->occupancy_ns += atomic64_read(&task->io_occupancy_ns);
+ acct->debt_ns += atomic64_read(&task->io_debt_ns);
+ acct->kern_time_ns += atomic64_read(&task->kern_time_ns);
+ acct->kern_debt_ns += atomic64_read(&task->kern_debt_ns);
+}
+
+static int do_iotime_accounting(struct task_struct *task, struct seq_file *m,
+ int whole)
+{
+ struct iotime_acct acct = { };
+ int result;
+
+ result = down_read_killable(&task->signal->exec_update_lock);
+ if (result)
+ return result;
+
+ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
+ result = -EACCES;
+ goto out_unlock;
+ }
+
+ if (whole) {
+ struct task_struct *t;
+
+ rcu_read_lock();
+ for_each_thread(task, t)
+ iotime_add(&acct, t);
+ rcu_read_unlock();
+ } else {
+ iotime_add(&acct, task);
+ }
+
+ seq_printf(m,
+ "io_latency_ns %llu\n"
+ "io_count %llu\n"
+ "io_occupancy_ns %llu\n"
+ "io_debt_ns %llu\n"
+ "kern_time_ns %llu\n"
+ "kern_debt_ns %llu\n",
+ acct.latency_ns, acct.count, acct.occupancy_ns,
+ acct.debt_ns, acct.kern_time_ns, acct.kern_debt_ns);
+
+out_unlock:
+ up_read(&task->signal->exec_update_lock);
+ return result;
+}
+
+static int proc_tgid_iotime(struct seq_file *m, struct pid_namespace *ns,
+ struct pid *pid, struct task_struct *task)
+{
+ return do_iotime_accounting(task, m, 1);
+}
+
+static int proc_tid_iotime(struct seq_file *m, struct pid_namespace *ns,
+ struct pid *pid, struct task_struct *task)
+{
+ return do_iotime_accounting(task, m, 0);
+}
+
+#endif
+
#ifdef CONFIG_LATENCYTOP
static int lstats_show_proc(struct seq_file *m, void *v)
{
@@ -3336,6 +3438,9 @@ static const struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_SCHED_INFO
ONE("schedstat", S_IRUGO, proc_pid_schedstat),
#endif
+#ifdef CONFIG_MUQSS_IOTIME
+ ONE("iotime", S_IRUSR, proc_tgid_iotime),
+#endif
#ifdef CONFIG_LATENCYTOP
REG("latency", S_IRUGO, proc_lstats_operations),
#endif
@@ -3691,6 +3796,9 @@ static const struct pid_entry tid_base_stuff[] = {
#ifdef CONFIG_SCHED_INFO
ONE("schedstat", S_IRUGO, proc_pid_schedstat),
#endif
+#ifdef CONFIG_MUQSS_IOTIME
+ ONE("iotime", S_IRUSR, proc_tid_iotime),
+#endif
#ifdef CONFIG_LATENCYTOP
REG("latency", S_IRUGO, proc_lstats_operations),
#endif
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -714,7 +714,7 @@ xfsaild(
spin_unlock(&ailp->ail_lock);
if (tout)
- schedule_timeout(msecs_to_jiffies(tout));
+ schedule_msec_hrtimeout(tout);
__set_current_state(TASK_RUNNING);
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -137,6 +137,23 @@ struct request {
/* Time that I/O was submitted to the device. */
u64 io_start_time_ns;
+#ifdef CONFIG_MUQSS_IOTIME
+ /*
+ * Task this request is being served for, holding a reference. Set
+ * once from the first bio and cleared if a merge brings in a bio
+ * belonging to somebody else, since occupancy cannot be split
+ * between owners at completion time.
+ */
+ struct task_struct *muqss_owner;
+ /*
+ * Completion time, captured where the block layer already takes it.
+ * rq_qos_done() runs after blk_update_request() has completed every
+ * bio, so a timestamp taken there would include the completion path
+ * and overstate device service time.
+ */
+ u64 muqss_done_ns;
+#endif
+
#ifdef CONFIG_BLK_WBT
unsigned short wbt_flags;
#endif
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -252,13 +252,25 @@ struct bio {
* on release of the bio.
*/
struct blkcg_gq *bi_blkg;
- /* Time that this bio was issued. */
- u64 issue_time_ns;
#ifdef CONFIG_BLK_CGROUP_IOCOST
u64 bi_iocost_cost;
#endif
#endif
+ /*
+ * Time that this bio was issued. Wanted by blkcg accounting and by
+ * MuQSS I/O aware scheduling, which must work on kernels built
+ * without any block cgroup support.
+ */
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_MUQSS_IOTIME)
+ u64 issue_time_ns;
+#endif
+
+#ifdef CONFIG_MUQSS_IOTIME
+ /* Task this I/O is being done for. Holds a reference. */
+ struct task_struct *bi_muqss_owner;
+#endif
+
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
struct bio_crypt_ctx *bi_crypt_context;
#endif
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -91,6 +91,7 @@ static inline bool try_to_freeze(void) { return false; }
static inline void set_freezable(void) {}
+#define pm_freezing (false)
#endif /* !CONFIG_FREEZER */
#endif /* FREEZER_H_INCLUDED */
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -29,6 +29,8 @@ static inline bool ioprio_valid(unsigned short ioprio)
*/
static inline int task_nice_ioprio(struct task_struct *task)
{
+ if (iso_task(task))
+ return 0;
return (task_nice(task) + 20) / 5;
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2460,6 +2460,61 @@ static inline bool folio_use_access_time(struct folio *folio)
}
#endif /* CONFIG_NUMA_BALANCING */
+#if MUQSS_IOWNER_WIDTH
+/*
+ * MuQSS I/O owner tag: an index into the owner table in block/blk-iotime.c,
+ * recorded when a folio is dirtied so that the writeback issued for it later
+ * by a flusher thread can still be charged to the task responsible. Zero
+ * means no owner.
+ *
+ * The tag itself is lossy by design: which of two racing dirtiers wins the
+ * field does not matter, and a wrong answer costs one misattributed
+ * writeback. The *word* is not ours to be lossy with, though. Other fields in
+ * folio->flags are updated by atomic bit operations from contexts that do not
+ * hold the folio lock -- PG_waiters is set by lock waiters, and losing it
+ * skips the wakeup on unlock -- so a plain read-modify-write store here would
+ * discard concurrent updates to unrelated bits. Update the field the way
+ * folio_xchg_last_cpupid() does, with a cmpxchg loop that touches only our
+ * own bits.
+ */
+static inline unsigned int folio_io_owner(const struct folio *folio)
+{
+ return (READ_ONCE(folio->flags.f) >> MUQSS_IOWNER_PGSHIFT) &
+ MUQSS_IOWNER_MASK;
+}
+
+static inline void folio_set_io_owner(struct folio *folio, unsigned int slot)
+{
+ unsigned long old_flags, flags;
+
+ old_flags = READ_ONCE(folio->flags.f);
+ do {
+ flags = old_flags;
+ flags &= ~(MUQSS_IOWNER_MASK << MUQSS_IOWNER_PGSHIFT);
+ flags |= ((unsigned long)slot & MUQSS_IOWNER_MASK) <<
+ MUQSS_IOWNER_PGSHIFT;
+ } while (unlikely(!try_cmpxchg(&folio->flags.f, &old_flags, flags)));
+}
+
+static inline void page_io_owner_reset(struct page *page)
+{
+ page->flags.f &= ~(MUQSS_IOWNER_MASK << MUQSS_IOWNER_PGSHIFT);
+}
+#else
+static inline unsigned int folio_io_owner(const struct folio *folio)
+{
+ return 0;
+}
+
+static inline void folio_set_io_owner(struct folio *folio, unsigned int slot)
+{
+}
+
+static inline void page_io_owner_reset(struct page *page)
+{
+}
+#endif /* MUQSS_IOWNER_WIDTH */
+
#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
/*
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1240,6 +1240,7 @@ static inline bool zone_is_empty(const struct zone *zone)
#define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH)
#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH)
#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH)
+#define MUQSS_IOWNER_PGOFF (LRU_REFS_PGOFF - MUQSS_IOWNER_WIDTH)
/*
* Define the bit shifts to access each section. For non-existent
@@ -1251,6 +1252,7 @@ static inline bool zone_is_empty(const struct zone *zone)
#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0))
#define LAST_CPUPID_PGSHIFT (LAST_CPUPID_PGOFF * (LAST_CPUPID_WIDTH != 0))
#define KASAN_TAG_PGSHIFT (KASAN_TAG_PGOFF * (KASAN_TAG_WIDTH != 0))
+#define MUQSS_IOWNER_PGSHIFT (MUQSS_IOWNER_PGOFF * (MUQSS_IOWNER_WIDTH != 0))
/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */
#ifdef NODE_NOT_IN_PAGE_FLAGS
@@ -1269,6 +1271,7 @@ static inline bool zone_is_empty(const struct zone *zone)
#define NODES_MASK ((1UL << NODES_WIDTH) - 1)
#define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1)
#define LAST_CPUPID_MASK ((1UL << LAST_CPUPID_SHIFT) - 1)
+#define MUQSS_IOWNER_MASK ((1UL << MUQSS_IOWNER_WIDTH) - 1)
#define KASAN_TAG_MASK ((1UL << KASAN_TAG_WIDTH) - 1)
#define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1)
diff --git a/include/linux/muqss.h b/include/linux/muqss.h
new file mode 100644
--- /dev/null
+++ b/include/linux/muqss.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Scheduler-neutral accessors for task fields that MuQSS keeps somewhere
+ * other than the mainline scheduling entities.
+ *
+ * Kept out of <linux/sched.h> so that enabling MuQSS costs that header only
+ * the task_struct members themselves. Include this after task_struct is
+ * defined; <linux/sched.h> already does so on your behalf.
+ */
+#ifndef _LINUX_MUQSS_H
+#define _LINUX_MUQSS_H
+
+#ifdef CONFIG_SCHED_MUQSS
+
+/* MuQSS accounts runtime and RT timeouts directly on the task. */
+#define tsk_seruntime(t) ((t)->sched_time)
+#define tsk_rttimeout(t) ((t)->rt_timeout)
+
+/*
+ * The rtmutex PI chain sorts equal-priority waiters by SCHED_DEADLINE
+ * deadline. MuQSS implements no deadline class, and that tie-break is only
+ * consulted when dl_prio(prio) holds - i.e. prio < MAX_DL_PRIO, which is 0 -
+ * so it is unreachable here. Report 0 rather than carry a dl entity.
+ */
+#define tsk_dl_deadline(t) (0)
+
+/* No deadline class: no budget to overrun and no bandwidth to migrate. */
+#define tsk_dl_overrun(t) (0)
+#define tsk_dl_bw(t) (0)
+
+static inline bool iso_task(struct task_struct *p)
+{
+ return (p->policy == SCHED_ISO);
+}
+
+#else /* CONFIG_SCHED_MUQSS */
+
+#define tsk_seruntime(t) ((t)->se.sum_exec_runtime)
+#define tsk_rttimeout(t) ((t)->rt.timeout)
+#define tsk_dl_deadline(t) ((t)->dl.deadline)
+#define tsk_dl_overrun(t) ((t)->dl.dl_overrun)
+#define tsk_dl_bw(t) ((t)->dl.dl_bw)
+
+static inline bool iso_task(struct task_struct *p)
+{
+ return false;
+}
+
+#endif /* CONFIG_SCHED_MUQSS */
+
+#endif /* _LINUX_MUQSS_H */
diff --git a/include/linux/muqss_iotime.h b/include/linux/muqss_iotime.h
new file mode 100644
--- /dev/null
+++ b/include/linux/muqss_iotime.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * I/O aware scheduling support for MuQSS.
+ *
+ * Attributes block device time back to the task that caused the I/O, so the
+ * CPU scheduler can see what a task costs the storage device rather than only
+ * what it costs the CPU.
+ *
+ * The attributed time is charged against the task's virtual deadline one for
+ * one, a nanosecond of deadline for each nanosecond of device time, so that
+ * I/O and CPU cost a task the same.
+ *
+ * The same attribution carries CPU time as well as device time. A kworker
+ * running a work item declares itself to be acting for whoever queued that
+ * work, so the time it spends is charged back to them rather than lost to a
+ * kernel thread. That half is charged one for one: a nanosecond of CPU time
+ * costs the same wherever the kernel chose to spend it, and work a task does
+ * in its own context already costs it exactly that.
+ *
+ * See MuQSS-iotime-design.md.
+ */
+#ifndef _LINUX_MUQSS_IOTIME_H
+#define _LINUX_MUQSS_IOTIME_H
+
+#include <linux/types.h>
+
+struct bio;
+struct folio;
+struct request;
+struct gendisk;
+struct task_struct;
+struct work_struct;
+
+#ifdef CONFIG_MUQSS_IOTIME
+
+/*
+ * A window during which current is running on behalf of another task, opened
+ * by a kworker around one work item. Lives on the stack of the thread doing
+ * the work; see muqss_kerntime_begin().
+ */
+struct muqss_kern_window {
+ struct task_struct *owner; /* who to charge, NULL for nobody */
+ struct task_struct *prev; /* override to restore on close */
+ u64 start; /* current's runtime when opened */
+};
+
+/*
+ * Tag @bio with the task that caused it. Called from the block layer submit
+ * path, where current is the originating task for reads, readahead and
+ * synchronous writes alike. Takes a reference that is dropped by
+ * muqss_iotime_put_owner().
+ */
+void muqss_iotime_set_owner(struct bio *bio);
+
+/*
+ * Drop the owner reference taken above. Idempotent, so it can be called from
+ * every site that releases bio state without tracking which ran first.
+ */
+void muqss_iotime_put_owner(struct bio *bio);
+
+/*
+ * Propagate ownership from @bio_src to @bio. Stacked drivers (md, dm, loop)
+ * resubmit clones from their own threads, where current is a kernel thread
+ * rather than the originating task, so without this attribution is lost on
+ * every RAID and LUKS setup.
+ */
+void muqss_iotime_clone_owner(struct bio *bio, struct bio *bio_src);
+
+/* Attach the accounting policy to a newly registered queue. */
+void muqss_iotime_enable(struct gendisk *disk);
+
+/* Zero a new task's counters so nothing is inherited across fork. */
+void muqss_iotime_task_init(struct task_struct *p);
+
+/*
+ * Owner table, used to attribute writeback. A dirtying task is given a slot,
+ * whose index is small enough to store in spare page->flags bits; writeback
+ * issued later by a flusher thread reads the index back off the folio and
+ * resolves it to the task that dirtied it.
+ */
+
+/* Slot for current, allocating one on first use. 0 if none is available. */
+unsigned int muqss_iotime_owner_slot(void);
+
+/* Resolve a slot to its task, taking a reference. NULL if the slot is stale. */
+struct task_struct *muqss_iotime_owner_task(unsigned int slot);
+
+/* Give up a task's slot. Called from exit. */
+void muqss_iotime_release_slot(struct task_struct *p);
+
+/* Record current as the dirtier of @folio, if it can be attributed. */
+void muqss_iotime_dirty_folio(struct folio *folio);
+
+/*
+ * Declare that current is about to do I/O on behalf of @owner, and undo it.
+ * Used by io_uring's io-wq workers, which issue requests that another task
+ * queued. Returns the previous value, to be handed back to _proxy_end().
+ *
+ * The caller must keep a reference to @owner across the window.
+ */
+struct task_struct *muqss_iotime_proxy_begin(struct task_struct *owner);
+void muqss_iotime_proxy_end(struct task_struct *prev);
+
+/*
+ * Two requests are being merged into one. Disowns @rq if @next belongs to a
+ * different task, so the survivor is not charged for both.
+ */
+void muqss_iotime_merge_requests(struct request *rq, struct request *next);
+
+/*
+ * Record who queued @work, so the kworker that eventually runs it can be
+ * charged to them. Called from the queueing task's own context, which rules
+ * out the deferred re-entries into __queue_work() made by the delayed work
+ * timer and the rcu_work callback: those run in interrupt and softirq
+ * context, where current is whoever was unlucky enough to be interrupted.
+ */
+void muqss_work_set_owner(struct work_struct *work);
+
+/*
+ * Open and close a window in which current is running work on behalf of the
+ * task in @slot. The CPU time current consumes across the window is charged
+ * to that task, and any I/O the work issues is attributed to it too.
+ *
+ * Cheap when there is nobody to charge, which is the common case: an unowned
+ * slot costs one comparison and reads no clocks.
+ */
+void muqss_kerntime_begin(struct muqss_kern_window *w, unsigned int slot);
+void muqss_kerntime_end(struct muqss_kern_window *w);
+
+/*
+ * The CPU time current has consumed so far, including the part not yet banked
+ * into ->sched_time. Implemented by the scheduler; see MuQSS.c.
+ */
+u64 muqss_task_runtime_live(void);
+
+#else /* !CONFIG_MUQSS_IOTIME */
+
+struct muqss_kern_window { };
+
+static inline void muqss_iotime_set_owner(struct bio *bio) { }
+static inline void muqss_iotime_put_owner(struct bio *bio) { }
+static inline void muqss_iotime_clone_owner(struct bio *bio,
+ struct bio *bio_src) { }
+static inline void muqss_iotime_enable(struct gendisk *disk) { }
+static inline void muqss_iotime_task_init(struct task_struct *p) { }
+static inline unsigned int muqss_iotime_owner_slot(void) { return 0; }
+static inline struct task_struct *muqss_iotime_owner_task(unsigned int slot)
+{
+ return NULL;
+}
+static inline void muqss_iotime_release_slot(struct task_struct *p) { }
+static inline void muqss_iotime_dirty_folio(struct folio *folio) { }
+static inline struct task_struct *
+muqss_iotime_proxy_begin(struct task_struct *owner)
+{
+ return NULL;
+}
+static inline void muqss_iotime_proxy_end(struct task_struct *prev) { }
+static inline void muqss_iotime_merge_requests(struct request *rq,
+ struct request *next) { }
+static inline void muqss_work_set_owner(struct work_struct *work) { }
+static inline void muqss_kerntime_begin(struct muqss_kern_window *w,
+ unsigned int slot) { }
+static inline void muqss_kerntime_end(struct muqss_kern_window *w) { }
+
+#endif /* CONFIG_MUQSS_IOTIME */
+
+#endif /* _LINUX_MUQSS_IOTIME_H */
diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h
--- a/include/linux/page-flags-layout.h
+++ b/include/linux/page-flags-layout.h
@@ -113,9 +113,39 @@
ZONES_WIDTH - LRU_GEN_WIDTH - SECTIONS_WIDTH - \
NODES_WIDTH - KASAN_TAG_WIDTH - LAST_CPUPID_WIDTH)
+/*
+ * MuQSS I/O aware scheduling stores an index into its owner table here, so
+ * that a page dirtied now can be charged to the task that dirtied it when it
+ * is written back later by a flusher thread.
+ *
+ * These bits are affordable because MuQSS excludes NUMA balancing, which is
+ * the only user of LAST_CPUPID: with CONFIG_NUMA_BALANCING off,
+ * LAST_CPUPID_SHIFT is 0 and its share of page->flags is unclaimed.
+ *
+ * Taken last so nothing else has to shrink. __LRU_REFS_WIDTH rather than
+ * LRU_REFS_WIDTH is used below because the latter is a min() expression and
+ * so cannot be evaluated by the preprocessor; the two are equal whenever
+ * there is room for MGLRU's full allocation, which is the only case in which
+ * anything is left over for us anyway.
+ */
+#ifdef CONFIG_MUQSS_IOTIME
+#define MUQSS_IOWNER_SHIFT 8
+#else
+#define MUQSS_IOWNER_SHIFT 0
+#endif
+
+#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \
+ KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH + __LRU_REFS_WIDTH + \
+ MUQSS_IOWNER_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS
+#define MUQSS_IOWNER_WIDTH MUQSS_IOWNER_SHIFT
+#else
+#define MUQSS_IOWNER_WIDTH 0
+#endif
+
#define NR_NON_PAGEFLAG_BITS (SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH + \
LAST_CPUPID_SHIFT + KASAN_TAG_WIDTH + \
- LRU_GEN_WIDTH + LRU_REFS_WIDTH)
+ LRU_GEN_WIDTH + LRU_REFS_WIDTH + \
+ MUQSS_IOWNER_WIDTH)
#define NR_UNUSED_PAGEFLAG_BITS (BITS_PER_LONG - \
(NR_NON_PAGEFLAG_BITS + NR_PAGEFLAGS))
diff --git a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -44,6 +44,9 @@
#include <linux/restart_block.h>
#include <linux/rseq_types.h>
#include <linux/seqlock_types.h>
+#ifdef CONFIG_SCHED_MUQSS
+#include <linux/skip_list.h>
+#endif
#include <linux/kcsan.h>
#include <linux/rv.h>
#include <linux/uidgid_types.h>
@@ -334,6 +337,12 @@ extern long schedule_timeout_interruptible(long timeout);
extern long schedule_timeout_killable(long timeout);
extern long schedule_timeout_uninterruptible(long timeout);
extern long schedule_timeout_idle(long timeout);
+
+extern long schedule_msec_hrtimeout(long timeout);
+extern long schedule_min_hrtimeout(void);
+extern long schedule_msec_hrtimeout_interruptible(long timeout);
+extern long schedule_msec_hrtimeout_uninterruptible(long timeout);
+
asmlinkage void schedule(void);
extern void schedule_preempt_disabled(void);
asmlinkage void preempt_schedule_irq(void);
@@ -877,6 +886,79 @@ struct task_struct {
int normal_prio;
unsigned int rt_priority;
+#ifdef CONFIG_SCHED_MUQSS
+ int time_slice;
+ u64 deadline;
+ skiplist_node node; /* Skip list node */
+ u64 last_ran;
+ u64 sched_time; /* sched_clock time spent running */
+#ifdef CONFIG_SMT_NICE
+ int smt_bias; /* Policy/nice level bias across smt siblings */
+#endif
+#ifdef CONFIG_HOTPLUG_CPU
+ bool zerobound; /* Bound to CPU0 for hotplug */
+#endif
+ unsigned long rt_timeout;
+ /* Unbanked cpu time */
+ unsigned long utime_ns, stime_ns;
+#ifdef CONFIG_MUQSS_IOTIME
+ /*
+ * Block device time consumed on this task's behalf. Updated from
+ * I/O completion, which may be any CPU, so these are atomic. Read
+ * via /proc/<pid>/iotime. Not inherited across fork. Bytes are not
+ * counted here, task_io_accounting already has them.
+ *
+ * io_latency_ns is end to end per bio, so it includes queue wait and
+ * is what a waiting task experiences. io_occupancy_ns is device
+ * service time per request, which is what this task cost everybody
+ * else, and is the only one of the two fit to charge for.
+ *
+ * io_debt_ns is occupancy not yet charged to the deadline. The
+ * scheduler consumes and zeroes it; see consume_iotime_penalty().
+ */
+ atomic64_t io_latency_ns;
+ atomic64_t io_count;
+ atomic64_t io_occupancy_ns;
+ atomic64_t io_debt_ns;
+
+ /*
+ * CPU time burnt in some other thread's context on this task's
+ * behalf, currently kworkers running work items it queued. Unlike the
+ * I/O counters above this is CPU time, which the task would have been
+ * charged against its own time_slice had the kernel done the work
+ * synchronously instead of handing it to a worker.
+ *
+ * kern_time_ns is cumulative and only for reporting. kern_debt_ns is
+ * the part not yet charged to the deadline; the scheduler consumes
+ * and zeroes it, see consume_kerntime_penalty().
+ */
+ atomic64_t kern_time_ns;
+ atomic64_t kern_debt_ns;
+
+ /*
+ * Index of this task's slot in the I/O owner table, stamped into
+ * page->flags when it dirties a folio so writeback can be charged
+ * back to it. 0 means no slot; allocated lazily on first dirty and
+ * released on exit.
+ */
+ unsigned int io_owner_slot;
+
+ /*
+ * The task this one is currently working on behalf of, or NULL.
+ * io_uring's io-wq workers publish the task that queued the request
+ * here for the duration of the issue, so a submission punted to a
+ * worker is still charged to the task that asked for it. kworkers do
+ * the same around each work item, which additionally attributes any
+ * I/O the work item submits, and any pages it dirties, to the task
+ * that queued the work rather than losing them to a kernel thread.
+ *
+ * Only ever written by the task itself and only read while it is
+ * running, so it needs no locking. The publisher holds a reference
+ * to the pointee for the whole window.
+ */
+ struct task_struct *io_owner_override;
+#endif
+#else /* CONFIG_SCHED_MUQSS */
struct sched_entity se;
struct sched_rt_entity rt;
struct sched_dl_entity dl;
@@ -885,6 +967,7 @@ struct task_struct {
struct sched_ext_entity scx;
#endif
const struct sched_class *sched_class;
+#endif /* CONFIG_SCHED_MUQSS */
#ifdef CONFIG_SCHED_CORE
struct rb_node core_node;
@@ -1677,6 +1760,8 @@ struct task_struct {
randomized_struct_fields_end
} __attribute__ ((aligned (64)));
+#include <linux/muqss.h>
+
#ifdef CONFIG_SCHED_PROXY_EXEC
DECLARE_STATIC_KEY_TRUE(__sched_proxy_exec);
static inline bool sched_proxy_exec(void)
@@ -2293,7 +2378,12 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
static inline bool task_is_runnable(struct task_struct *p)
{
+#ifdef CONFIG_SCHED_MUQSS
+ /* MuQSS has no delayed dequeue: queued means runnable. */
+ return p->on_rq;
+#else
return p->on_rq && !p->se.sched_delayed;
+#endif
}
extern bool sched_task_on_rq(struct task_struct *p);
diff --git a/include/linux/sched/deadline.h b/include/linux/sched/deadline.h
--- a/include/linux/sched/deadline.h
+++ b/include/linux/sched/deadline.h
@@ -30,6 +30,24 @@ static inline bool dl_time_before(u64 a, u64 b)
}
struct root_domain;
+#ifdef CONFIG_SCHED_MUQSS
+/*
+ * MuQSS implements no deadline scheduling class, so there is never any DL
+ * bandwidth to account for or migrate between root domains.
+ */
+static inline void dl_add_task_root_domain(struct task_struct *p) { }
+static inline void dl_clear_root_domain(struct root_domain *rd) { }
+static inline void dl_clear_root_domain_cpu(int cpu) { }
+static inline bool dl_task_needs_bw_move(struct task_struct *p,
+ const struct cpumask *new_mask)
+{
+ return false;
+}
+static inline bool dl_bw_visited(int cpu, u64 cookie)
+{
+ return false;
+}
+#else /* CONFIG_SCHED_MUQSS */
extern void dl_add_task_root_domain(struct task_struct *p);
extern void dl_clear_root_domain(struct root_domain *rd);
extern void dl_clear_root_domain_cpu(int cpu);
@@ -43,19 +61,23 @@ extern void dl_clear_root_domain_cpu(int cpu);
extern bool dl_task_needs_bw_move(struct task_struct *p,
const struct cpumask *new_mask);
-extern u64 dl_cookie;
extern bool dl_bw_visited(int cpu, u64 cookie);
+#endif /* CONFIG_SCHED_MUQSS */
+
+extern u64 dl_cookie;
static inline bool dl_server(struct sched_dl_entity *dl_se)
{
return dl_se->dl_server;
}
+#ifndef CONFIG_SCHED_MUQSS
static inline struct task_struct *dl_task_of(struct sched_dl_entity *dl_se)
{
BUG_ON(dl_server(dl_se));
return container_of(dl_se, struct task_struct, dl);
}
+#endif
/*
* Regarding the deadline, a task with implicit deadline has a relative
diff --git a/include/linux/sched/nohz.h b/include/linux/sched/nohz.h
--- a/include/linux/sched/nohz.h
+++ b/include/linux/sched/nohz.h
@@ -13,7 +13,7 @@ extern int get_nohz_timer_target(void);
static inline void nohz_balance_enter_idle(int cpu) { }
#endif
-#ifdef CONFIG_NO_HZ_COMMON
+#if defined(CONFIG_NO_HZ_COMMON) && !defined(CONFIG_SCHED_MUQSS)
void calc_load_nohz_start(void);
void calc_load_nohz_remote(struct rq *rq);
void calc_load_nohz_stop(void);
diff --git a/include/linux/sched/prio.h b/include/linux/sched/prio.h
--- a/include/linux/sched/prio.h
+++ b/include/linux/sched/prio.h
@@ -16,6 +16,21 @@
#define MAX_RT_PRIO 100
#define MAX_DL_PRIO 0
+#ifdef CONFIG_SCHED_MUQSS
+/*
+ * MuQSS ranks its non-RT policies immediately below the RT range, and has no
+ * deadline class. SCHED_IDLEPRIO is an alias for the SCHED_IDLE policy value.
+ */
+#define ISO_PRIO (MAX_RT_PRIO)
+#define NORMAL_PRIO (MAX_RT_PRIO + 1)
+#define IDLE_PRIO (MAX_RT_PRIO + 2)
+#define PRIO_LIMIT ((IDLE_PRIO) + 1)
+
+#define SCHED_IDLEPRIO SCHED_IDLE
+#define SCHED_MAX (SCHED_IDLEPRIO)
+#define SCHED_RANGE(policy) ((policy) <= SCHED_MAX)
+#endif /* CONFIG_SCHED_MUQSS */
+
#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH)
#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)
diff --git a/include/linux/skip_list.h b/include/linux/skip_list.h
new file mode 100644
--- /dev/null
+++ b/include/linux/skip_list.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SKIP_LISTS_H
+#define _LINUX_SKIP_LISTS_H
+
+/*
+ * Four levels is enough: randomLevel() returns 0..3, and insert only
+ * grows the list one level at a time, so next/prev[4..] were unused.
+ */
+#define SKIPLIST_MAXLEVEL 4
+
+typedef u64 keyType;
+
+typedef struct nodeStructure skiplist_node;
+
+struct nodeStructure {
+ keyType key;
+ skiplist_node *next[SKIPLIST_MAXLEVEL];
+ skiplist_node *prev[SKIPLIST_MAXLEVEL];
+};
+
+typedef struct listStructure {
+ int entries;
+ int level; /* Maximum level of the list
+ (1 more than the number of levels in the list) */
+ u64 best_key; /* Earliest queued key; lockless hint for EDT */
+ skiplist_node *header; /* pointer to header */
+} skiplist;
+
+void skiplist_init(skiplist_node *slnode);
+void skiplist_cache_init(void);
+skiplist *new_skiplist(skiplist_node *slnode);
+void skiplist_free(skiplist *l);
+void free_skiplist(skiplist *l);
+void skiplist_node_init(skiplist_node *node);
+void skiplist_insert(skiplist *l, skiplist_node *node, keyType key, unsigned int randseed);
+bool skiplist_delete(skiplist *l, skiplist_node *node);
+
+static inline bool skiplist_node_empty(skiplist_node *node) {
+ return (!node->next[0]);
+}
+#endif /* _LINUX_SKIP_LISTS_H */
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -288,6 +288,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, (_key), 0); \
INIT_LIST_HEAD(&(_work)->entry); \
(_work)->func = (_func); \
+ muqss_work_init_owner(_work); \
} while (0)
#else
#define __INIT_WORK_KEY(_work, _func, _onstack, _key) \
@@ -296,6 +297,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
INIT_LIST_HEAD(&(_work)->entry); \
(_work)->func = (_func); \
+ muqss_work_init_owner(_work); \
} while (0)
#endif
diff --git a/include/linux/workqueue_types.h b/include/linux/workqueue_types.h
--- a/include/linux/workqueue_types.h
+++ b/include/linux/workqueue_types.h
@@ -17,9 +17,51 @@ struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
+#ifdef CONFIG_MUQSS_IOTIME
+ /*
+ * Index in the I/O owner table of the task that queued this work, so
+ * the CPU time the kworker spends running it can be charged back to
+ * whoever asked for it. 0 means nobody to charge, which is the case
+ * for the great deal of work queued by kernel threads on their own
+ * account.
+ *
+ * A slot index rather than a task pointer deliberately: work items
+ * are cancelled and disabled through half a dozen paths that clear
+ * the pending bit without ever running the work, and none of them
+ * would drop a reference taken here. A stale slot simply resolves to
+ * NULL and the work is charged to nobody.
+ */
+ unsigned int muqss_owner_slot;
+#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
+#ifdef CONFIG_MUQSS_IOTIME
+static inline unsigned int muqss_work_owner(struct work_struct *work)
+{
+ return work->muqss_owner_slot;
+}
+
+/*
+ * Every queueing path stamps the owner, so this only matters for a work item
+ * initialised on memory that was never zeroed and then reaching execution by
+ * some path that does not. It is here so that such a path, if one exists,
+ * charges nobody rather than charging whichever unlucky task holds the slot
+ * the garbage happens to name.
+ */
+static inline void muqss_work_init_owner(struct work_struct *work)
+{
+ work->muqss_owner_slot = 0;
+}
+#else
+static inline unsigned int muqss_work_owner(struct work_struct *work)
+{
+ return 0;
+}
+
+static inline void muqss_work_init_owner(struct work_struct *work) { }
+#endif
+
#endif /* _LINUX_WORKQUEUE_TYPES_H */
diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h
--- a/include/uapi/linux/sched.h
+++ b/include/uapi/linux/sched.h
@@ -125,7 +125,7 @@ struct clone_args {
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_BATCH 3
-/* SCHED_ISO: reserved but not implemented yet */
+#define SCHED_ISO 4 /* Implemented on MuQSS only */
#define SCHED_IDLE 5
#define SCHED_DEADLINE 6
#define SCHED_EXT 7
diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -218,6 +218,8 @@ config THREAD_INFO_IN_TASK
menu "General setup"
+source "kernel/Kconfig.MuQSS"
+
config BROKEN
bool
help
@@ -887,6 +889,7 @@ menu "Scheduler features"
config UCLAMP_TASK
bool "Enable utilization clamping for RT/FAIR tasks"
depends on CPU_FREQ_GOV_SCHEDUTIL
+ depends on !SCHED_MUQSS
help
This feature enables the scheduler to track the clamped utilization
of each CPU based on RUNNABLE tasks scheduled on that CPU.
@@ -935,6 +938,8 @@ config UCLAMP_BUCKETS_COUNT
config SCHED_PROXY_EXEC
bool "Proxy Execution"
+ # MuQSS has no sched_class donor/proxy plumbing
+ depends on !SCHED_MUQSS
# Avoid some build failures w/ PREEMPT_RT until it can be fixed
depends on !PREEMPT_RT
# Need to investigate how to inform sched_ext of split contexts
@@ -1012,6 +1017,7 @@ config ARCH_WANT_NUMA_VARIABLE_LOCALITY
config NUMA_BALANCING
bool "Memory placement aware NUMA scheduler"
+ depends on !SCHED_MUQSS
depends on ARCH_SUPPORTS_NUMA_BALANCING
depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY
depends on SMP && NUMA_MIGRATION && !PREEMPT_RT
@@ -1026,6 +1032,8 @@ config SCHED_CACHE
bool "Cache aware load balance"
default y
depends on SMP
+ # Cache aware load balancing lives in CFS, which MuQSS replaces
+ depends on !SCHED_MUQSS
help
When enabled, the scheduler will attempt to aggregate tasks from
the same process onto a single Last Level Cache (LLC) domain when
@@ -1148,7 +1156,7 @@ menuconfig CGROUP_SCHED
bandwidth allocation to such task groups. It uses cgroups to group
tasks.
-if CGROUP_SCHED
+if CGROUP_SCHED && !SCHED_MUQSS
config GROUP_SCHED_WEIGHT
def_bool n
@@ -1210,7 +1218,7 @@ config EXT_SUB_SCHED
config SCHED_MM_CID
def_bool y
- depends on SMP && RSEQ
+ depends on SMP && RSEQ && !SCHED_MUQSS
config UCLAMP_TASK_GROUP
bool "Utilization clamping per group of tasks"
@@ -1337,6 +1345,7 @@ config CGROUP_DEVICE
config CGROUP_CPUACCT
bool "Simple CPU accounting controller"
+ depends on !SCHED_MUQSS
help
Provides a simple controller for monitoring the
total CPU consumed by the tasks in a cgroup.
@@ -1482,6 +1491,7 @@ config CHECKPOINT_RESTORE
config SCHED_AUTOGROUP
bool "Automatic process group scheduling"
+ depends on !SCHED_MUQSS
select CGROUPS
select CGROUP_SCHED
select FAIR_GROUP_SCHED
@@ -2005,6 +2015,7 @@ config RSEQ
config RSEQ_SLICE_EXTENSION
bool "Enable rseq-based time slice extension mechanism"
depends on RSEQ && HIGH_RES_TIMERS && GENERIC_ENTRY && HAVE_GENERIC_TIF_BITS
+ depends on !SCHED_MUQSS
help
Allows userspace to request a limited time slice extension when
returning from an interrupt to user space via the RSEQ shared
diff --git a/init/init_task.c b/init/init_task.c
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -111,9 +111,17 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.stack = init_stack,
.usage = REFCOUNT_INIT(2),
.flags = PF_KTHREAD,
+#ifdef CONFIG_SCHED_MUQSS
+ .prio = NORMAL_PRIO,
+ .static_prio = MAX_PRIO - 20,
+ .normal_prio = NORMAL_PRIO,
+ .deadline = 0,
+ .time_slice = 1000000,
+#else
.prio = MAX_PRIO - 20,
.static_prio = MAX_PRIO - 20,
.normal_prio = MAX_PRIO - 20,
+#endif
.policy = SCHED_NORMAL,
.cpus_ptr = &init_task.cpus_mask,
.user_cpus_ptr = NULL,
@@ -126,6 +134,7 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.restart_block = {
.fn = do_no_restart_syscall,
},
+#ifndef CONFIG_SCHED_MUQSS
.se = {
.group_node = LIST_HEAD_INIT(init_task.se.group_node),
},
@@ -133,6 +142,7 @@ struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.run_list = LIST_HEAD_INIT(init_task.rt.run_list),
.time_slice = RR_TIMESLICE,
},
+#endif
.tasks = LIST_HEAD_INIT(init_task.tasks),
#ifdef CONFIG_SMP
.pushable_tasks = PLIST_NODE_INIT(init_task.pushable_tasks, MAX_PRIO),
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -56,6 +56,7 @@
#include <linux/task_work.h>
#include <linux/io_uring.h>
#include <linux/io_uring/cmd.h>
+#include <linux/muqss_iotime.h>
#include <linux/audit.h>
#include <linux/security.h>
#include <linux/jump_label.h>
@@ -1531,7 +1532,19 @@ void io_wq_submit_work(struct io_wq_work *work)
}
do {
+ struct task_struct *prev;
+
+ /*
+ * Anything this issue submits to the block layer is being done
+ * on behalf of the task that queued the request, not this
+ * worker. Publish it so the I/O is charged to the right task;
+ * req->tctx pins it for the duration.
+ */
+ prev = muqss_iotime_proxy_begin(req->tctx ? req->tctx->task :
+ NULL);
ret = io_issue_sqe(req, issue_flags);
+ muqss_iotime_proxy_end(prev);
+
if (ret != -EAGAIN)
break;
diff --git a/kernel/Kconfig.MuQSS b/kernel/Kconfig.MuQSS
new file mode 100644
--- /dev/null
+++ b/kernel/Kconfig.MuQSS
@@ -0,0 +1,220 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# MuQSS - The Multiple Queue Skiplist Scheduler by Con Kolivas.
+#
+# Everything MuQSS needs from Kconfig lives in this file, including the
+# negative dependencies that disable mainline scheduler features MuQSS
+# replaces or does not implement. Kconfig merges properties from repeated
+# "config" blocks, so those features are gated here rather than by editing
+# each mainline Kconfig in place. The only change required outside this file
+# is a single source line in init/Kconfig.
+
+config SCHED_MUQSS
+ bool "MuQSS cpu scheduler"
+ # Architectures the port is built and tested on. Widening this needs
+ # arch review: <linux/sched/prio.h> gains a NORMAL_PRIO definition,
+ # which collides with the private one in
+ # arch/powerpc/platforms/cell/spufs/sched.c.
+ depends on X86 || ARM64
+ select HIGH_RES_TIMERS
+ default y
+ help
+ The Multiple Queue Skiplist Scheduler for excellent interactivity and
+ responsiveness on the desktop and highly scalable deterministic
+ low latency on any hardware.
+
+ Say Y here.
+
+config SMT_NICE
+ bool "SMT (Hyperthreading) aware nice priority and policy support"
+ depends on SCHED_MUQSS && SCHED_SMT
+ default y
+ help
+ Enabling Hyperthreading on Intel CPUs decreases the effectiveness
+ of the use of 'nice' levels and different scheduling policies
+ (e.g. realtime) due to sharing of CPU power between hyperthreads.
+ SMT nice support makes each logical CPU aware of what is running on
+ its hyperthread siblings, maintaining appropriate distribution of
+ CPU according to nice levels and scheduling policies at the expense
+ of slightly increased overhead.
+
+ If unsure say Y here.
+
+choice
+ depends on SMP
+ prompt "CPU scheduler runqueue sharing"
+ default RQ_MC if SCHED_MUQSS
+ default RQ_NONE
+
+config RQ_NONE
+ bool "No sharing"
+ help
+ This is the default behaviour where the CPU scheduler has one runqueue
+ per CPU, whether it is a physical or logical CPU (hyperthread).
+
+ This can still be enabled runtime with the boot parameter
+ rqshare=none
+
+ If unsure, say N.
+
+config RQ_SMT
+ bool "SMT (hyperthread) siblings"
+ depends on SCHED_SMT && SCHED_MUQSS
+
+ help
+ With this option enabled, the CPU scheduler will have one runqueue
+ shared by SMT (hyperthread) siblings. As these logical cores share
+ one physical core, sharing the runqueue resource can lead to decreased
+ overhead, lower latency and higher throughput.
+
+ This can still be enabled runtime with the boot parameter
+ rqshare=smt
+
+ If unsure, say N.
+
+config RQ_MC
+ bool "Multicore siblings"
+ depends on SCHED_MC && SCHED_MUQSS
+ help
+ With this option enabled, the CPU scheduler will have one runqueue
+ shared by multicore siblings in addition to any SMT siblings.
+ As these physical cores share caches, sharing the runqueue resource
+ will lead to lower latency, but its effects on overhead and throughput
+ are less predictable. As a general rule, 6 or fewer cores will likely
+ benefit from this, while larger CPUs will only derive a latency
+ benefit. If your workloads are primarily single threaded, this will
+ possibly worsen throughput. If you are only concerned about latency
+ then enable this regardless of how many cores you have.
+
+ This can still be enabled runtime with the boot parameter
+ rqshare=mc
+
+ If unsure, say Y.
+
+config RQ_MC_LLC
+ bool "Multicore siblings (LLC)"
+ depends on SCHED_MC && SCHED_MUQSS
+ help
+ With this option enabled, the CPU scheduler will behave similarly as
+ with "Multicore siblings".
+ This option takes LLC cache into account when scheduling tasks.
+ Option may benefit CPUs with multiple LLC caches, such as Ryzen
+ and Xeon CPUs.
+
+ This can still be enabled runtime with the boot parameter
+ rqshare=llc
+
+ If unsure, say N.
+
+config RQ_SMP
+ bool "Symmetric Multi-Processing"
+ depends on SMP && SCHED_MUQSS
+ help
+ With this option enabled, the CPU scheduler will have one runqueue
+ shared by all physical CPUs unless they are on separate NUMA nodes.
+ As physical CPUs usually do not share resources, sharing the runqueue
+ will normally worsen throughput but improve latency. If you only
+ care about latency enable this.
+
+ This can still be enabled runtime with the boot parameter
+ rqshare=smp
+
+ If unsure, say N.
+
+config RQ_ALL
+ bool "NUMA"
+ depends on SMP && SCHED_MUQSS
+ help
+ With this option enabled, the CPU scheduler will have one runqueue
+ regardless of the architecture configuration, including across NUMA
+ nodes. This can substantially decrease throughput in NUMA
+ configurations, but light NUMA designs will not be dramatically
+ affected. This option should only be chosen if latency is the prime
+ concern.
+
+ This can still be enabled runtime with the boot parameter
+ rqshare=all
+
+ If unsure, say N.
+endchoice
+
+config SHARERQ
+ int
+ default 0 if RQ_NONE
+ default 1 if RQ_SMT
+ default 2 if RQ_MC
+ default 3 if RQ_MC_LLC
+ default 4 if RQ_SMP
+ default 5 if RQ_ALL
+
+config MUQSS_IOTIME
+ bool "I/O aware CPU scheduling support"
+ depends on SCHED_MUQSS && BLOCK
+ default y
+ help
+ Ordinarily the CPU scheduler can see how much CPU a task uses, but it
+ is blind to how much block device time that task consumes. A task
+ that keeps a disk busy on everyone else's behalf looks identical to
+ one that is merely idle, so it keeps full CPU priority while other
+ tasks wait behind its I/O.
+
+ This option attaches the scheduler to the block layer so that the
+ time a device spends servicing each request is attributed back to the
+ task that asked for it, and accumulates that as a per task I/O time
+ figure. It is exported per task through /proc/<pid>/iotime and per
+ device through debugfs.
+
+ That figure is charged against the task's virtual deadline, demoting a
+ task in proportion to the device time it consumed. This stops a task
+ that keeps a disk busy on everybody else's behalf from retaining full
+ CPU priority for free, while leaving tasks that merely wait on I/O as
+ responsive as they are now.
+
+ The charge is one nanosecond of deadline per nanosecond of device
+ time, so I/O and CPU cost a task equally. That rate is what the
+ feature means rather than a setting within it, so there is nothing to
+ tune it by.
+
+ The same machinery charges a task for kernel work done in another
+ thread's context on its behalf, which today means kworkers running
+ work items it queued. Kernel work a task asks for in its own context
+ needs no such help, since it already comes out of that task's own
+ timeslice; what escapes the scheduler is the work handed to somebody
+ else, and forcing IRQ threading moves more work into that blind spot.
+ That is charged one for one, since a nanosecond of CPU time costs the
+ same wherever the kernel chose to spend it. It is reported alongside
+ the I/O figures.
+
+ Doing this costs a timestamp and an owner reference on every block
+ request, and an accounting update on every completion. On very fast
+ devices, or under heavy small random I/O, that overhead is measurable
+ and may reduce peak I/O throughput. Say N if you are tuning purely
+ for storage benchmarks.
+
+ When disabled this is compiled out entirely and costs nothing.
+
+ If unsure, say Y.
+
+#
+# Mainline features MuQSS replaces or does not implement are gated with
+# "depends on !SCHED_MUQSS" at their point of definition. Kconfig scopes a
+# "depends on" to the properties declared in the same config block, so a
+# dependency cannot be attached to a symbol from here; each gate has to live
+# beside the definition it constrains. They are:
+#
+# init/Kconfig UCLAMP_TASK
+# SCHED_PROXY_EXEC
+# NUMA_BALANCING
+# SCHED_CACHE
+# SCHED_MM_CID
+# CGROUP_CPUACCT
+# SCHED_AUTOGROUP
+# RSEQ_SLICE_EXTENSION
+# if CGROUP_SCHED (group scheduling
+# block: FAIR_GROUP_SCHED,
+# CFS_BANDWIDTH, RT_GROUP_SCHED,
+# GROUP_SCHED_*, EXT_GROUP_SCHED)
+# kernel/Kconfig.preempt PREEMPT_RT
+# SCHED_CORE
+# SCHED_CLASS_EXT
+# kernel/trace/rv/monitors/deadline/Kconfig RV_MON_DEADLINE
diff --git a/kernel/Kconfig.hz b/kernel/Kconfig.hz
--- a/kernel/Kconfig.hz
+++ b/kernel/Kconfig.hz
@@ -3,9 +3,29 @@
# Timer Interrupt Frequency Configuration
#
+#
+# Silent symbols keep CONFIG_HZ_* available to the rest of the tree and to
+# inherited .configs, but they are not choice members. The promptable
+# *_NODEF names are what olddefconfig can stick on; renaming every rate
+# (including 100) means a saved "# CONFIG_HZ_100 is not set" cannot pin the
+# choice away from the MuQSS default.
+#
+config HZ_100
+ bool
+
+config HZ_250
+ bool
+
+config HZ_300
+ bool
+
+config HZ_1000
+ bool
+
choice
prompt "Timer frequency"
- default HZ_250
+ default HZ_100_NODEF if SCHED_MUQSS
+ default HZ_250_NODEF if !SCHED_MUQSS
help
Allows the configuration of the timer frequency. It is customary
to have the timer interrupt run at 1000 Hz but 100 Hz may be more
@@ -17,31 +37,45 @@ choice
per second.
- config HZ_100
+ config HZ_100_NODEF
bool "100 HZ"
+ select HZ_100
help
+ 100 Hz is a suitable choice in combination with MuQSS which does
+ not rely on ticks for rescheduling interrupts, and is not Hz limited
+ for timeouts and sleeps from both the kernel and userspace.
+ This allows us to benefit from the lower overhead and higher
+ throughput of fewer timer ticks.
+
+ Non-MuQSS kernels:
100 Hz is a typical choice for servers, SMP and NUMA systems
with lots of processors that may show reduced performance if
too many timer interrupts are occurring.
- config HZ_250
+ config HZ_250_NODEF
bool "250 HZ"
+ select HZ_250
help
250 Hz is a good compromise choice allowing server performance
while also showing good interactive responsiveness even
on SMP and NUMA systems. If you are going to be using NTSC video
or multimedia, select 300Hz instead.
- config HZ_300
+ 250 Hz is the default choice for the mainline scheduler but not
+ advantageous in combination with MuQSS.
+
+ config HZ_300_NODEF
bool "300 HZ"
+ select HZ_300
help
300 Hz is a good compromise choice allowing server performance
while also showing good interactive responsiveness even
on SMP and NUMA systems and exactly dividing by both PAL and
NTSC frame rates for video and multimedia work.
- config HZ_1000
+ config HZ_1000_NODEF
bool "1000 HZ"
+ select HZ_1000
help
1000 Hz is the preferred choice for desktop systems and other
systems requiring fast interactive responses to events.
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
--- a/kernel/Kconfig.preempt
+++ b/kernel/Kconfig.preempt
@@ -14,15 +14,35 @@ config PREEMPT_BUILD
config ARCH_HAS_PREEMPT_LAZY
bool
+#
+# Silent symbols keep CONFIG_PREEMPT{,_NONE,_VOLUNTARY,_LAZY} available to
+# the rest of the tree and to inherited .configs, but they are not choice
+# members. The promptable *_NODEF names are what olddefconfig can stick on;
+# renaming every model (including PREEMPT) means a saved
+# "# CONFIG_PREEMPT is not set" or CONFIG_PREEMPT_{NONE,VOLUNTARY,LAZY}=y
+# cannot pin the choice away from full preempt.
+#
+config PREEMPT_NONE
+ bool
+
+config PREEMPT_VOLUNTARY
+ bool
+
+config PREEMPT
+ bool
+
+config PREEMPT_LAZY
+ bool
+
choice
prompt "Preemption Model"
- default PREEMPT_LAZY if ARCH_HAS_PREEMPT_LAZY
- default PREEMPT_NONE
+ default PREEMPT_NODEF
-config PREEMPT_NONE
+config PREEMPT_NONE_NODEF
bool "No Forced Preemption (Server)"
depends on !PREEMPT_RT
depends on ARCH_NO_PREEMPT
+ select PREEMPT_NONE
select PREEMPT_NONE_BUILD if !PREEMPT_DYNAMIC
help
This is the traditional Linux preemption model, geared towards
@@ -35,11 +55,12 @@ config PREEMPT_NONE
raw processing power of the kernel, irrespective of scheduling
latencies.
-config PREEMPT_VOLUNTARY
- bool "Voluntary Kernel Preemption (Desktop)"
+config PREEMPT_VOLUNTARY_NODEF
+ bool "Voluntary Kernel Preemption (Nothing)"
depends on !ARCH_HAS_PREEMPT_LAZY
depends on !ARCH_NO_PREEMPT
depends on !PREEMPT_RT
+ select PREEMPT_VOLUNTARY
select PREEMPT_VOLUNTARY_BUILD if !PREEMPT_DYNAMIC
help
This option reduces the latency of the kernel by adding more
@@ -54,11 +75,13 @@ config PREEMPT_VOLUNTARY
applications to run more 'smoothly' even when the system is
under load.
- Select this if you are building a kernel for a desktop system.
+ Select this for no system in particular (choose Preemptible
+ instead on a desktop if you know what's good for you).
-config PREEMPT
+config PREEMPT_NODEF
bool "Preemptible Kernel (Low-Latency Desktop)"
depends on !ARCH_NO_PREEMPT
+ select PREEMPT
select PREEMPT_BUILD if !PREEMPT_DYNAMIC
help
This option reduces the latency of the kernel by making
@@ -75,10 +98,11 @@ config PREEMPT
embedded system with latency requirements in the milliseconds
range.
-config PREEMPT_LAZY
+config PREEMPT_LAZY_NODEF
bool "Scheduler controlled preemption model"
depends on !ARCH_NO_PREEMPT
depends on ARCH_HAS_PREEMPT_LAZY
+ select PREEMPT_LAZY
select PREEMPT_BUILD if !PREEMPT_DYNAMIC
help
This option provides a scheduler driven preemption model that
@@ -87,11 +111,17 @@ config PREEMPT_LAZY
reduce lock holder preemption and recover some of the performance
gains seen from using Voluntary preemption.
+ It trades the latency that makes a desktop feel responsive for
+ throughput, so choose Preemptible instead unless you are building
+ for a throughput oriented system.
+
endchoice
config PREEMPT_RT
bool "Fully Preemptible Kernel (Real-Time)"
depends on EXPERT && ARCH_SUPPORTS_RT && !COMPILE_TEST
+ # MuQSS does not implement the PREEMPT_RT scheduler/locking contract
+ depends on !SCHED_MUQSS
select PREEMPTION
help
This option turns the kernel into a real-time kernel by replacing
@@ -150,7 +180,7 @@ config PREEMPT_DYNAMIC
config SCHED_CORE
bool "Core Scheduling for SMT"
- depends on SCHED_SMT
+ depends on SCHED_SMT && !SCHED_MUQSS
help
This option permits Core Scheduling, a means of coordinated task
selection across SMT siblings. When enabled -- see
@@ -168,7 +198,7 @@ config SCHED_CORE
config SCHED_CLASS_EXT
bool "Extensible Scheduling Class"
- depends on BPF_SYSCALL && BPF_JIT && DEBUG_INFO_BTF
+ depends on BPF_SYSCALL && BPF_JIT && DEBUG_INFO_BTF && !SCHED_MUQSS
select GENERIC_ALLOCATOR
select STACKTRACE if STACKTRACE_SUPPORT
help
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3083,7 +3083,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
*/
cs->nr_migrate_dl_tasks++;
if (dl_task_needs_bw_move(task, cs->effective_cpus))
- cs->sum_migrate_dl_bw += task->dl.dl_bw;
+ cs->sum_migrate_dl_bw += tsk_dl_bw(task);
}
}
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -170,7 +170,7 @@ int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
*/
t1 = tsk->sched_info.pcount;
t2 = tsk->sched_info.run_delay;
- t3 = tsk->se.sum_exec_runtime;
+ t3 = tsk_seruntime(tsk);
d->cpu_count += t1;
diff --git a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -34,6 +34,7 @@
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/kthread.h>
+#include <linux/muqss_iotime.h>
#include <linux/mempolicy.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
@@ -207,7 +208,7 @@ static void __exit_signal(struct release_task_post *post, struct task_struct *ts
sig->inblock += task_io_get_inblock(tsk);
sig->oublock += task_io_get_oublock(tsk);
task_io_accounting_add(&sig->ioac, &tsk->ioac);
- sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
+ sig->sum_sched_runtime += tsk_seruntime(tsk);
sig->nr_threads--;
__unhash_process(post, tsk, group_dead);
write_sequnlock(&sig->stats_lock);
@@ -298,8 +299,8 @@ void release_task(struct task_struct *p)
proc_flush_pid(thread_pid);
put_pid(thread_pid);
exit_cred_namespaces(p);
- add_device_randomness(&p->se.sum_exec_runtime,
- sizeof(p->se.sum_exec_runtime));
+ add_device_randomness(&tsk_seruntime(p),
+ sizeof(tsk_seruntime(p)));
free_pids(post.pids);
release_thread(p);
/*
@@ -1037,6 +1038,9 @@ void __noreturn do_exit(long code)
if (tsk->io_context)
exit_io_context(tsk);
+ /* Give up the I/O owner table slot used to attribute writeback. */
+ muqss_iotime_release_slot(tsk);
+
if (tsk->splice_pipe)
free_pipe_info(tsk->splice_pipe);
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -372,7 +372,7 @@ waiter_update_prio(struct rt_mutex_waiter *waiter, struct task_struct *task)
lockdep_assert(RB_EMPTY_NODE(&waiter->tree.entry));
waiter->tree.prio = __waiter_prio(task);
- waiter->tree.deadline = task->dl.deadline;
+ waiter->tree.deadline = tsk_dl_deadline(task);
}
/*
@@ -393,7 +393,7 @@ waiter_clone_prio(struct rt_mutex_waiter *waiter, struct task_struct *task)
* Only use with rt_waiter_node_{less,equal}()
*/
#define task_to_waiter_node(p) \
- &(struct rt_waiter_node){ .prio = __waiter_prio(p), .deadline = (p)->dl.deadline }
+ &(struct rt_waiter_node){ .prio = __waiter_prio(p), .deadline = tsk_dl_deadline(p) }
#define task_to_waiter(p) \
&(struct rt_mutex_waiter){ .tree = *task_to_waiter_node(p) }
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -23,12 +23,14 @@ ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
# I turn this off for IA-64 only. Andreas Schwab says it's also needed on m68k
# to get a correct value for the wait-channel (WCHAN in ps). --davidm
CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
+CFLAGS_MuQSS.o := $(PROFILING) -fno-omit-frame-pointer
endif
# Branch profiling isn't noinstr-safe
ifdef CONFIG_TRACE_BRANCH_PROFILING
CFLAGS_build_policy.o += -DDISABLE_BRANCH_PROFILING
CFLAGS_build_utility.o += -DDISABLE_BRANCH_PROFILING
+CFLAGS_build_muqss.o += -DDISABLE_BRANCH_PROFILING
endif
#
# Build efficiency:
@@ -36,7 +38,12 @@ endif
# These compilation units have roughly the same size and complexity - so their
# build parallelizes well and finishes roughly at once:
#
+ifdef CONFIG_SCHED_MUQSS
+obj-y += MuQSS.o
+obj-y += build_muqss.o
+else
obj-y += core.o
obj-y += fair.o
obj-y += build_policy.o
obj-y += build_utility.o
+endif
diff --git a/kernel/sched/MuQSS.c b/kernel/sched/MuQSS.c
new file mode 100644
--- /dev/null
+++ b/kernel/sched/MuQSS.c
@@ -0,0 +1,10795 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kernel/sched/MuQSS.c, was kernel/sched.c
+ *
+ * Kernel scheduler and related syscalls
+ *
+ * Copyright (C) 1991-2002 Linus Torvalds
+ *
+ * 1996-12-23 Modified by Dave Grothe to fix bugs in semaphores and
+ * make semaphores SMP safe
+ * 1998-11-19 Implemented schedule_timeout() and related stuff
+ * by Andrea Arcangeli
+ * 2002-01-04 New ultra-scalable O(1) scheduler by Ingo Molnar:
+ * hybrid priority-list and round-robin design with
+ * an array-switch method of distributing timeslices
+ * and per-CPU runqueues. Cleanups and useful suggestions
+ * by Davide Libenzi, preemptible kernel bits by Robert Love.
+ * 2003-09-03 Interactivity tuning by Con Kolivas.
+ * 2004-04-02 Scheduler domains code by Nick Piggin
+ * 2007-04-15 Work begun on replacing all interactivity tuning with a
+ * fair scheduling design by Con Kolivas.
+ * 2007-05-05 Load balancing (smp-nice) and other improvements
+ * by Peter Williams
+ * 2007-05-06 Interactivity improvements to CFS by Mike Galbraith
+ * 2007-07-01 Group scheduling enhancements by Srivatsa Vaddagiri
+ * 2007-11-29 RT balancing improvements by Steven Rostedt, Gregory Haskins,
+ * Thomas Gleixner, Mike Kravetz
+ * 2009-08-13 Brainfuck deadline scheduling policy by Con Kolivas deletes
+ * a whole lot of those previous things.
+ * 2016-10-01 Multiple Queue Skiplist Scheduler scalable evolution of BFS
+ * scheduler by Con Kolivas.
+ * 2019-08-31 LLC bits by Eduards Bezverhijs
+ */
+/* Out-of-line migrate_{disable,enable} for modules; see linux/sched.h. */
+#define INSTANTIATE_EXPORTED_MIGRATE_DISABLE
+#include <linux/sched/isolation.h>
+#include <linux/sched/loadavg.h>
+
+#include <linux/binfmts.h>
+#include <linux/blkdev.h>
+#include <linux/compat.h>
+#include <linux/context_tracking.h>
+#include <linux/cpuset.h>
+#include <linux/delayacct.h>
+#include <linux/init_task.h>
+#include <linux/kcov.h>
+#include <linux/kprobes.h>
+#include <linux/mmu_context.h>
+#include <linux/module.h>
+#include <linux/nmi.h>
+#include <linux/prefetch.h>
+#include <linux/profile.h>
+#include <linux/rcupdate_wait.h>
+#include <linux/sched.h>
+#include <linux/scs.h>
+#include <linux/security.h>
+#include <linux/skip_list.h>
+#include <linux/syscalls.h>
+#include <linux/tick.h>
+#include <linux/wait_bit.h>
+#include <linux/completion.h>
+#include <linux/hrtimer_rearm.h>
+#include <linux/livepatch_sched.h>
+#include <linux/muqss_iotime.h>
+#include <linux/smp.h>
+
+#include <asm/irq_regs.h>
+#include <asm/switch_to.h>
+#include <asm/tlb.h>
+
+#include "../workqueue_internal.h"
+#include "../../io_uring/io-wq.h"
+#include "../smpboot.h"
+
+#define CREATE_TRACE_POINTS
+#include <linux/sched/rseq_api.h>
+#include <trace/events/sched.h>
+#include <trace/events/ipi.h>
+#undef CREATE_TRACE_POINTS
+
+#include "MuQSS.h"
+#include "smp.h"
+
+/* Modules probe these; core.c exports the same set under CFS. */
+EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_send_cpu);
+EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_send_cpumask);
+EXPORT_TRACEPOINT_SYMBOL(sched_set_state_tp);
+
+#define rt_prio(prio) unlikely((prio) < MAX_RT_PRIO)
+#define rt_task(p) rt_prio((p)->prio)
+#define batch_task(p) (unlikely((p)->policy == SCHED_BATCH))
+#define is_rt_policy(policy) ((policy) == SCHED_FIFO || \
+ (policy) == SCHED_RR)
+#define has_rt_policy(p) unlikely(is_rt_policy((p)->policy))
+
+#define is_idle_policy(policy) ((policy) == SCHED_IDLEPRIO)
+#define idleprio_task(p) unlikely(is_idle_policy((p)->policy))
+#define task_running_idle(p) unlikely((p)->prio == IDLE_PRIO)
+
+#define is_iso_policy(policy) ((policy) == SCHED_ISO)
+#define iso_task(p) unlikely(is_iso_policy((p)->policy))
+#define task_running_iso(p) unlikely((p)->prio == ISO_PRIO)
+
+#define rq_idle(rq) ((rq)->rq_prio == PRIO_LIMIT)
+
+#define ISO_PERIOD (5 * HZ)
+
+/*
+ * 'User priority' is the nice value converted to something we
+ * can work with better when scaling various scheduler parameters,
+ * it's a [ 0 ... 39 ] range.
+ */
+#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
+#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
+#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
+#define STOP_PRIO (MAX_RT_PRIO - 1)
+
+/*
+ * Some helpers for converting to/from various scales. Use shifts to get
+ * approximate multiples of ten for less overhead. These are internal scales
+ * only - niffies themselves are real nanoseconds, so anything converting the
+ * tick into niffies must use TICK_NSEC rather than the approximations here.
+ */
+#define APPROX_NS_PS (1073741824) /* Approximate ns per second */
+#define JIFFY_NS (APPROX_NS_PS / HZ)
+#define NS_TO_JIFFIES(TIME) ((TIME) / JIFFY_NS)
+#define HALF_JIFFY_NS (APPROX_NS_PS / HZ / 2)
+/*
+ * time_slice is banked in NS_TO_US() of real nanoseconds, so half a tick in
+ * those units has to come from TICK_NSEC, not from the approximate scale.
+ */
+#define HALF_JIFFY_US (NS_TO_US(TICK_NSEC) / 2)
+#define MS_TO_NS(TIME) ((TIME) << 20)
+#define MS_TO_US(TIME) ((TIME) << 10)
+#define NS_TO_MS(TIME) ((TIME) >> 20)
+#define NS_TO_US(TIME) ((TIME) >> 10)
+#define US_TO_NS(TIME) ((TIME) << 10)
+#define TICK_APPROX_NS ((APPROX_NS_PS+HZ/2)/HZ)
+
+#define RESCHED_US (100) /* Reschedule if less than this many μs left */
+
+static void print_scheduler_version(void)
+{
+ printk(KERN_INFO "MuQSS CPU scheduler v0.31 by Con Kolivas.\n");
+}
+
+/*
+ * This is the time all tasks within the same priority round robin.
+ * Value is in ms and set to a minimum of 6ms.
+ * Tunable via /proc interface.
+ */
+int rr_interval __read_mostly = 6;
+
+/*
+ * Tunable to choose whether to prioritise latency or throughput, simple
+ * binary yes or no
+ */
+int sched_interactive __read_mostly = 1;
+
+/*
+ * sched_iso_cpu - sysctl which determines the cpu percentage SCHED_ISO tasks
+ * are allowed to run five seconds as real time tasks. This is the total over
+ * all online cpus.
+ */
+int sched_iso_cpu __read_mostly = 70;
+
+/*
+ * sched_yield_type - Choose what sort of yield sched_yield will perform.
+ * 0: No yield.
+ * 1: Yield only to better priority/deadline tasks. (default)
+ * 2: Expire timeslice and recalculate deadline.
+ */
+int sched_yield_type __read_mostly = 1;
+
+/*
+ * The relative length of deadline for each priority(nice) level.
+ */
+static int prio_ratios[NICE_WIDTH] __read_mostly;
+
+
+/*
+ * The quota handed out to tasks of all priority levels when refilling their
+ * time_slice.
+ */
+static inline int timeslice(void)
+{
+ return MS_TO_US(rr_interval);
+}
+
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
+
+#ifdef CONFIG_SMP
+
+/* Define RQ share levels */
+#define RQSHARE_NONE 0
+#define RQSHARE_SMT 1
+#define RQSHARE_MC 2
+#define RQSHARE_MC_LLC 3
+#define RQSHARE_SMP 4
+#define RQSHARE_ALL 5
+
+/* Define locality levels */
+#define LOCALITY_SAME 0
+#define LOCALITY_SMT 1
+#define LOCALITY_MC_LLC 2
+#define LOCALITY_MC 3
+#define LOCALITY_SMP 4
+#define LOCALITY_DISTANT 5
+
+/*
+ * This determines what level of runqueue sharing will be done and is
+ * configurable at boot time with the bootparam rqshare =
+ */
+static int rqshare __read_mostly = CONFIG_SHARERQ; /* Default RQSHARE_MC */
+
+static int __init set_rqshare(char *str)
+{
+ if (!strncmp(str, "none", 4)) {
+ rqshare = RQSHARE_NONE;
+ return 1;
+ }
+ if (!strncmp(str, "smt", 3)) {
+ rqshare = RQSHARE_SMT;
+ return 1;
+ }
+ if (!strncmp(str, "mc", 2)) {
+ rqshare = RQSHARE_MC;
+ return 1;
+ }
+ if (!strncmp(str, "llc", 3)) {
+ rqshare = RQSHARE_MC_LLC;
+ return 1;
+ }
+ if (!strncmp(str, "smp", 3)) {
+ rqshare = RQSHARE_SMP;
+ return 1;
+ }
+ if (!strncmp(str, "all", 3)) {
+ rqshare = RQSHARE_ALL;
+ return 1;
+ }
+ return 0;
+}
+__setup("rqshare=", set_rqshare);
+
+/*
+ * Total number of runqueues. Equals number of CPUs when there is no runqueue
+ * sharing but is usually less with SMT/MC sharing of runqueues.
+ */
+static int total_runqueues __read_mostly = 1;
+
+static cpumask_t cpu_idle_map ____cacheline_aligned_in_smp;
+
+/*
+ * For asym packing, by default the lower numbered cpu has higher priority.
+ */
+int __weak arch_asym_cpu_priority(int cpu)
+{
+ return -cpu;
+}
+
+#else
+struct rq *uprq;
+#endif /* CONFIG_SMP */
+
+/*
+ * sched_smt_active() is unconditionally available now that cpu_smt_mask() is
+ * cpumask_of(cpu) for !CONFIG_SCHED_SMT, so the key must always be defined.
+ */
+DEFINE_STATIC_KEY_FALSE(sched_smt_present);
+EXPORT_SYMBOL_GPL(sched_smt_present);
+
+#include "stats.h"
+
+/*
+ * All common locking functions performed on rq->lock. rq->clock is local to
+ * the CPU accessing it so it can be modified just with interrupts disabled
+ * when we're not updating niffies.
+ * Looking up task_rq must be done under rq->lock to be safe.
+ */
+
+/*
+ * RQ-clock updating methods:
+ */
+
+#ifdef HAVE_SCHED_AVG_IRQ
+static void update_irq_load_avg(struct rq *rq, long delta);
+#else
+static inline void update_irq_load_avg(struct rq *rq, long delta) {}
+#endif
+
+/* Use CONFIG_PARAVIRT as this will avoid more #ifdef in arch code. */
+#ifdef CONFIG_PARAVIRT
+struct static_key paravirt_steal_rq_enabled;
+#endif
+
+static void update_rq_clock_task(struct rq *rq, s64 delta)
+{
+/*
+ * In theory, the compile should just see 0 here, and optimize out the call
+ * to sched_rt_avg_update. But I don't trust it...
+ */
+ s64 __maybe_unused steal = 0, irq_delta = 0;
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+ irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time;
+
+ /*
+ * Since irq_time is only updated on {soft,}irq_exit, we might run into
+ * this case when a previous update_rq_clock() happened inside a
+ * {soft,}irq region.
+ *
+ * When this happens, we stop ->clock_task and only update the
+ * prev_irq_time stamp to account for the part that fit, so that a next
+ * update will consume the rest. This ensures ->clock_task is
+ * monotonic.
+ *
+ * It does however cause some slight miss-attribution of {soft,}irq
+ * time, a more accurate solution would be to update the irq_time using
+ * the current rq->clock timestamp, except that would require using
+ * atomic ops.
+ */
+ if (irq_delta > delta)
+ irq_delta = delta;
+
+ rq->prev_irq_time += irq_delta;
+ delta -= irq_delta;
+#endif
+#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
+ if (static_key_false((&paravirt_steal_rq_enabled))) {
+ steal = paravirt_steal_clock(cpu_of(rq));
+ steal -= rq->prev_steal_time_rq;
+
+ if (unlikely(steal > delta))
+ steal = delta;
+
+ rq->prev_steal_time_rq += steal;
+ delta -= steal;
+ }
+#endif
+ rq->clock_task += delta;
+
+#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
+ if (irq_delta + steal)
+ update_irq_load_avg(rq, irq_delta + steal);
+#endif
+}
+
+static inline void update_rq_clock(struct rq *rq)
+{
+ s64 delta = sched_clock_cpu(cpu_of(rq)) - rq->clock;
+
+ if (unlikely(delta < 0))
+ return;
+ rq->clock += delta;
+ update_rq_clock_task(rq, delta);
+}
+
+/*
+ * Niffies are a globally increasing nanosecond counter. They're only used by
+ * update_load_avg and time_slice_expired, however deadlines are based on them
+ * across CPUs. Update them whenever we will call one of those functions, and
+ * synchronise them across CPUs whenever we hold both runqueue locks.
+ *
+ * Niffies are the highest of two absolute values that each advance at real
+ * time: this runqueue's clock, and a tick line advanced by whole jiffies so
+ * that we keep counting if the rq clock stalls. Because both are absolute,
+ * time contributed by the tick line, or imported by synchronise_niffies(), is
+ * never counted again when the rq clock catches up - niffies simply stall
+ * until it does. Accumulating the maximum of the two *deltas* instead keeps
+ * every overshoot for good and drifts upwards without bound.
+ */
+static inline void update_clocks(struct rq *rq)
+{
+ long jdiff;
+
+ update_rq_clock(rq);
+ jdiff = jiffies - rq->last_jiffy;
+ if (jdiff > 0) {
+ rq->last_jiffy += jdiff;
+ rq->jiffy_niffies += (u64)jdiff * TICK_NSEC;
+ }
+ if (rq->niffies < rq->jiffy_niffies)
+ rq->niffies = rq->jiffy_niffies;
+ if (rq->niffies < rq->clock)
+ rq->niffies = rq->clock;
+}
+
+/*
+ * Any time we have two runqueues locked we use that as an opportunity to
+ * synchronise niffies to the highest value as idle ticks may have artificially
+ * kept niffies low on one CPU and the truth can only be later.
+ */
+static inline void synchronise_niffies(struct rq *rq1, struct rq *rq2)
+{
+ if (rq1->niffies > rq2->niffies)
+ rq2->niffies = rq1->niffies;
+ else
+ rq1->niffies = rq2->niffies;
+}
+
+/*
+ * double_rq_lock - safely lock two runqueues
+ *
+ * Note this does not disable interrupts like task_rq_lock,
+ * you need to do so manually before calling.
+ */
+
+/* For when we know rq1 != rq2 */
+static inline void __double_rq_lock(struct rq *rq1, struct rq *rq2)
+ __acquires(rq1->lock)
+ __acquires(rq2->lock)
+{
+ if (rq1 < rq2) {
+ raw_spin_lock(rq1->lock);
+ raw_spin_lock_nested(rq2->lock, SINGLE_DEPTH_NESTING);
+ } else {
+ raw_spin_lock(rq2->lock);
+ raw_spin_lock_nested(rq1->lock, SINGLE_DEPTH_NESTING);
+ }
+}
+
+static inline void double_rq_lock(struct rq *rq1, struct rq *rq2)
+ __acquires(rq1->lock)
+ __acquires(rq2->lock)
+{
+ BUG_ON(!irqs_disabled());
+ if (rq1->lock == rq2->lock) {
+ raw_spin_lock(rq1->lock);
+ __acquire(rq2->lock); /* Fake it out ;) */
+ } else
+ __double_rq_lock(rq1, rq2);
+ synchronise_niffies(rq1, rq2);
+}
+
+/*
+ * double_rq_unlock - safely unlock two runqueues
+ *
+ * Note this does not restore interrupts like task_rq_unlock,
+ * you need to do so manually after calling.
+ */
+static inline void double_rq_unlock(struct rq *rq1, struct rq *rq2)
+ __releases(rq1->lock)
+ __releases(rq2->lock)
+{
+ raw_spin_unlock(rq1->lock);
+ if (rq1->lock != rq2->lock)
+ raw_spin_unlock(rq2->lock);
+ else
+ __release(rq2->lock);
+}
+
+static inline void lock_all_rqs(void)
+{
+ int cpu;
+
+ preempt_disable();
+ for_each_possible_cpu(cpu) {
+ struct rq *rq = cpu_rq(cpu);
+
+ do_raw_spin_lock(rq->lock);
+ }
+}
+
+static inline void unlock_all_rqs(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct rq *rq = cpu_rq(cpu);
+
+ do_raw_spin_unlock(rq->lock);
+ }
+ preempt_enable();
+}
+
+/* Specially nest trylock an rq */
+static inline bool trylock_rq(struct rq *this_rq, struct rq *rq)
+{
+ if (unlikely(!do_raw_spin_trylock(rq->lock)))
+ return false;
+ spin_acquire(&rq->lock->dep_map, SINGLE_DEPTH_NESTING, 1, _RET_IP_);
+ synchronise_niffies(this_rq, rq);
+ return true;
+}
+
+/* Unlock a specially nested trylocked rq */
+static inline void unlock_rq(struct rq *rq)
+{
+ spin_release(&rq->lock->dep_map, _RET_IP_);
+ do_raw_spin_unlock(rq->lock);
+}
+
+/*
+ * cmpxchg based fetch_or, macro so it works for different integer types
+ */
+#define fetch_or(ptr, mask) \
+ ({ \
+ typeof(ptr) _ptr = (ptr); \
+ typeof(mask) _mask = (mask); \
+ typeof(*_ptr) _old, _val = *_ptr; \
+ \
+ for (;;) { \
+ _old = cmpxchg(_ptr, _val, _val | _mask); \
+ if (_old == _val) \
+ break; \
+ _val = _old; \
+ } \
+ _old; \
+})
+
+#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG)
+/*
+ * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG,
+ * this avoids any races wrt polling state changes and thereby avoids
+ * spurious IPIs.
+ */
+static bool set_nr_and_not_polling(struct task_struct *p)
+{
+ struct thread_info *ti = task_thread_info(p);
+ return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG);
+}
+
+/*
+ * Atomically set TIF_NEED_RESCHED if TIF_POLLING_NRFLAG is set.
+ *
+ * If this returns true, then the idle task promises to call
+ * sched_ttwu_pending() and reschedule soon.
+ */
+static bool set_nr_if_polling(struct task_struct *p)
+{
+ struct thread_info *ti = task_thread_info(p);
+ typeof(ti->flags) old, val = READ_ONCE(ti->flags);
+
+ for (;;) {
+ if (!(val & _TIF_POLLING_NRFLAG))
+ return false;
+ if (val & _TIF_NEED_RESCHED)
+ return true;
+ old = cmpxchg(&ti->flags, val, val | _TIF_NEED_RESCHED);
+ if (old == val)
+ break;
+ val = old;
+ }
+ return true;
+}
+
+#else
+static bool set_nr_and_not_polling(struct task_struct *p)
+{
+ set_tsk_need_resched(p);
+ return true;
+}
+
+#ifdef CONFIG_SMP
+static bool set_nr_if_polling(struct task_struct *p)
+{
+ return false;
+}
+#endif
+#endif
+
+static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task)
+{
+ struct wake_q_node *node = &task->wake_q;
+
+ /*
+ * Atomically grab the task, if ->wake_q is !nil already it means
+ * it's already queued (either by us or someone else) and will get the
+ * wakeup due to that.
+ *
+ * In order to ensure that a pending wakeup will observe our pending
+ * state, even in the failed case, an explicit smp_mb() must be used.
+ */
+ smp_mb__before_atomic();
+ if (unlikely(cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL)))
+ return false;
+
+ /*
+ * The head is context local, there can be no concurrency.
+ */
+ *head->lastp = node;
+ head->lastp = &node->next;
+ return true;
+}
+
+/**
+ * wake_q_add() - queue a wakeup for 'later' waking.
+ * @head: the wake_q_head to add @task to
+ * @task: the task to queue for 'later' wakeup
+ *
+ * Queue a task for later wakeup, most likely by the wake_up_q() call in the
+ * same context, _HOWEVER_ this is not guaranteed, the wakeup can come
+ * instantly.
+ *
+ * This function must be used as-if it were wake_up_process(); IOW the task
+ * must be ready to be woken at this location.
+ */
+void wake_q_add(struct wake_q_head *head, struct task_struct *task)
+{
+ if (__wake_q_add(head, task))
+ get_task_struct(task);
+}
+
+/**
+ * wake_q_add_safe() - safely queue a wakeup for 'later' waking.
+ * @head: the wake_q_head to add @task to
+ * @task: the task to queue for 'later' wakeup
+ *
+ * Queue a task for later wakeup, most likely by the wake_up_q() call in the
+ * same context, _HOWEVER_ this is not guaranteed, the wakeup can come
+ * instantly.
+ *
+ * This function must be used as-if it were wake_up_process(); IOW the task
+ * must be ready to be woken at this location.
+ *
+ * This function is essentially a task-safe equivalent to wake_q_add(). Callers
+ * that already hold reference to @task can call the 'safe' version and trust
+ * wake_q to do the right thing depending whether or not the @task is already
+ * queued for wakeup.
+ */
+void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task)
+{
+ if (!__wake_q_add(head, task))
+ put_task_struct(task);
+}
+
+void wake_up_q(struct wake_q_head *head)
+{
+ struct wake_q_node *node = head->first;
+
+ while (node != WAKE_Q_TAIL) {
+ struct task_struct *task;
+
+ task = container_of(node, struct task_struct, wake_q);
+ BUG_ON(!task);
+ /* Task can safely be re-inserted now */
+ node = node->next;
+ task->wake_q.next = NULL;
+
+ /*
+ * wake_up_process() executes a full barrier, which pairs with
+ * the queueing in wake_q_add() so as not to miss wakeups.
+ */
+ wake_up_process(task);
+ put_task_struct(task);
+ }
+}
+
+static inline void smp_sched_reschedule(int cpu)
+{
+ if (likely(cpu_online(cpu)))
+ smp_send_reschedule(cpu);
+}
+
+/*
+ * resched_task - mark a task 'to be rescheduled now'.
+ *
+ * On UP this means the setting of the need_resched flag, on SMP it
+ * might also involve a cross-CPU call to trigger the scheduler on
+ * the target CPU.
+ */
+#ifdef CONFIG_PREEMPT_DYNAMIC
+static DEFINE_STATIC_KEY_FALSE(sk_dynamic_preempt_lazy);
+static __always_inline bool dynamic_preempt_lazy(void)
+{
+ return static_branch_unlikely(&sk_dynamic_preempt_lazy);
+}
+#else
+static __always_inline bool dynamic_preempt_lazy(void)
+{
+ return IS_ENABLED(CONFIG_PREEMPT_LAZY);
+}
+#endif
+
+static void resched_task(struct task_struct *p)
+{
+ int cpu;
+#ifdef CONFIG_LOCKDEP
+ /* Kernel threads call this when creating workqueues while still
+ * inactive from __kthread_bind_mask, holding only the pi_lock */
+ if (!(p->flags & PF_KTHREAD)) {
+ struct rq *rq = task_rq(p);
+
+ lockdep_assert_held(rq->lock);
+ }
+#endif
+ if (test_tsk_need_resched(p))
+ return;
+
+ cpu = task_cpu(p);
+ if (cpu == smp_processor_id()) {
+ set_tsk_need_resched(p);
+ set_preempt_need_resched();
+ return;
+ }
+
+ if (set_nr_and_not_polling(p))
+ smp_sched_reschedule(cpu);
+ else
+ trace_sched_wake_idle_without_ipi(cpu);
+}
+
+/*
+ * A task that is not running or queued will not have a node set.
+ * A task that is queued but not running will have a node set.
+ * A task that is currently running will have ->on_cpu set but no node set.
+ */
+static inline bool task_queued(struct task_struct *p)
+{
+ return !skiplist_node_empty(&p->node);
+}
+
+static void enqueue_task(struct rq *rq, struct task_struct *p, int flags);
+static inline void resched_if_idle(struct rq *rq);
+
+static inline bool deadline_before(u64 deadline, u64 time)
+{
+ return (deadline < time);
+}
+
+/*
+ * Deadline is "now" in niffies + (offset by priority). Setting the deadline
+ * is the key to everything. It distributes cpu fairly amongst tasks of the
+ * same nice value, it proportions cpu according to nice level, it means the
+ * task that last woke up the longest ago has the earliest deadline, thus
+ * ensuring that interactive tasks get low latency on wake up. The CPU
+ * proportion works out to the square of the virtual deadline difference, so
+ * this equation will give nice 19 3% CPU compared to nice 0.
+ */
+static inline u64 prio_deadline_diff(int user_prio)
+{
+ return (prio_ratios[user_prio] * rr_interval * (MS_TO_NS(1) / 128));
+}
+
+static inline u64 task_deadline_diff(struct task_struct *p)
+{
+ return prio_deadline_diff(TASK_USER_PRIO(p));
+}
+
+static inline u64 static_deadline_diff(int static_prio)
+{
+ return prio_deadline_diff(USER_PRIO(static_prio));
+}
+
+static inline int longest_deadline_diff(void)
+{
+ return prio_deadline_diff(39);
+}
+
+static inline int ms_longest_deadline_diff(void)
+{
+ return NS_TO_MS(longest_deadline_diff());
+}
+
+#ifdef CONFIG_MUQSS_IOTIME
+/*
+ * Scale an I/O time penalty by nice level, exactly as prio_deadline_diff()
+ * scales rr_interval. A deadline is virtual time, already stretched by
+ * prio_ratios[] before it means anything; adding raw nanoseconds of device
+ * time to it mixes two different currencies. Passing the penalty through the
+ * same ratio makes it commensurate with the deadline it is added to, so a
+ * given amount of I/O costs a task the same share of its own allotment
+ * whatever its nice level, and a niced down task is pushed back further in
+ * absolute terms than a niced up one for the same device time.
+ *
+ * The multiply is 64 bit, as it is in prio_deadline_diff(). Wrapping it would
+ * need a penalty over U64_MAX / prio_ratios[39], which is some forty days of
+ * device occupancy charged to one task between two scheduling events, so it
+ * is not a case worth writing code for.
+ */
+static inline u64 prio_penalty_diff(int user_prio, u64 penalty)
+{
+ return penalty * prio_ratios[user_prio] / 128;
+}
+
+/*
+ * Idleprio tasks are charged at the highest nice level whatever nice value
+ * they happen to carry. SCHED_IDLEPRIO is a class beneath the whole nice
+ * range rather than a position within it, and a task there has said it should
+ * run only when nothing else wants the CPU. Scaling by its own nice would let
+ * an idleprio task sitting at nice -20 be charged the lightest rate of all
+ * for keeping the disk busy, which is backwards. Their deadlines already sort
+ * below everything else in enqueue_task(); this keeps what they are charged
+ * for I/O consistent with that.
+ */
+static inline u64 task_penalty_diff(struct task_struct *p, u64 penalty)
+{
+ if (idleprio_task(p))
+ return prio_penalty_diff(39, penalty);
+
+ return prio_penalty_diff(TASK_USER_PRIO(p), penalty);
+}
+#endif
+
+#ifdef CONFIG_MUQSS_IOTIME
+/*
+ * Take the block device time accumulated on this task's behalf since it was
+ * last charged, and convert it to an amount of virtual deadline to push the
+ * task back by. The debt is consumed as it is read, so each nanosecond of
+ * device time demotes the task exactly once no matter which caller gets to it
+ * first. The charge is added to the deadline, so it is a demotion, not a
+ * boost: a task that keeps a device busy for everybody else stops getting
+ * full CPU priority for free.
+ *
+ * Charged one for one, a nanosecond of deadline for each nanosecond of device
+ * time consumed. That rate says device time and CPU time cost a task the
+ * same, which is the premise of the feature rather than a setting within it,
+ * so there is nothing to weight one against the other with.
+ *
+ * The charge is then scaled by nice through task_penalty_diff(), the same way
+ * rr_interval is, so that it is in the same virtual currency as the deadline
+ * it is added to. One for one is therefore one for one in deadline terms
+ * rather than in raw nanoseconds: at nice 0 the ratio is prio_ratios[20] /
+ * 128, about 6.7, exactly as an ordinary nice 0 timeslice is worth 6.7
+ * rr_intervals of deadline.
+ *
+ * There is no ceiling. A task that keeps a device busy can be demoted
+ * arbitrarily far behind, past the deadline of the lowest nice level. See
+ * MuQSS-iotime-design.md.
+ *
+ * This has to be consumed from both time_slice_expired() and enqueue_task().
+ * Expiry alone misses the streaming reader, which blocks before exhausting its
+ * slice and so never refreshes its deadline. Enqueue alone is not enough
+ * either: time_slice_expired() assigns the deadline absolutely, resetting the
+ * task to an uncharged baseline, and two of its callers (sched_yield() and
+ * yield_to()) have no enqueue behind them to reapply the charge.
+ */
+static inline u64 consume_iotime_penalty(struct task_struct *p)
+{
+ u64 debt = atomic64_xchg(&p->io_debt_ns, 0);
+
+ if (!debt)
+ return 0;
+
+ return task_penalty_diff(p, debt);
+}
+
+/*
+ * The same for CPU time spent in another thread's context on this task's
+ * behalf, which today means kworkers running work items it queued.
+ *
+ * Charged one for one, as device time is. A nanosecond of CPU time is a
+ * nanosecond of CPU time wherever it was spent, and the whole premise
+ * here is that the thread it was spent in should not decide whether it counts.
+ * Work a task asks for in its own context is already charged at exactly that
+ * rate: update_cpu_clock_switch() and update_cpu_clock_tick() deduct it from
+ * ->time_slice with no regard for which mode it was spent in, so a task that
+ * burns its whole quantum inside a syscall is demoted as surely as one that
+ * spun in userspace. Charging deferred work at anything other than parity
+ * would say that where the kernel chose to do the work changes what it cost,
+ * which is the bug this exists to fix. Forcing IRQ threading, as -ck does,
+ * only moves more work into that blind spot.
+ *
+ * It is still scaled by nice through task_penalty_diff(), like every other
+ * addition to a deadline, so that it is in the same virtual currency as the
+ * deadline it lands on.
+ *
+ * As with iotime there is no ceiling. The runaway this invites is a different
+ * shape to the I/O case and worth naming, because here CPU consumption is
+ * being punished with CPU demotion: a demoted task need not stop generating
+ * the work, so it can be starved while kworkers keep charging it. It is
+ * bounded in practice because the debt a task can accrue is bounded by the
+ * work it queued, and a task demoted enough to stop running stops queueing
+ * more.
+ *
+ * Kept as a separate counter from io_debt_ns rather than folded into it,
+ * because the two are quantities of very different size: work item runtimes
+ * are microseconds where device occupancy is milliseconds, and sharing an
+ * accumulator would let one vanish into the rounding of the other. Separate
+ * also keeps them separable in /proc/<pid>/iotime when the question is why a
+ * task was demoted.
+ */
+static inline u64 consume_kerntime_penalty(struct task_struct *p)
+{
+ u64 debt = atomic64_xchg(&p->kern_debt_ns, 0);
+
+ if (!debt)
+ return 0;
+
+ return task_penalty_diff(p, debt);
+}
+#else
+static inline u64 consume_iotime_penalty(struct task_struct *p)
+{
+ return 0;
+}
+
+static inline u64 consume_kerntime_penalty(struct task_struct *p)
+{
+ return 0;
+}
+#endif
+
+/*
+ * Everything charged against a task's deadline that did not come out of its
+ * own time_slice.
+ */
+static inline u64 consume_task_penalty(struct task_struct *p)
+{
+ return consume_iotime_penalty(p) + consume_kerntime_penalty(p);
+}
+
+static inline bool rq_local(struct rq *rq);
+
+#ifndef SCHED_CAPACITY_SCALE
+#define SCHED_CAPACITY_SCALE 1024
+#endif
+
+static inline int rq_load(struct rq *rq)
+{
+ return rq->nr_running;
+}
+
+/*
+ * Update the load average for feeding into cpu frequency governors. Use a
+ * rough estimate of a rolling average with ~ time constant of 32ms.
+ * 80/128 ~ 0.63. * 80 / 32768 / 128 == * 5 / 262144
+ * Make sure a call to update_clocks has been made before calling this to get
+ * an updated rq->niffies.
+ */
+static void update_load_avg(struct rq *rq, unsigned int flags)
+{
+ long us_interval, load;
+
+ us_interval = NS_TO_US(rq->niffies - rq->load_update);
+ if (unlikely(us_interval <= 0))
+ return;
+
+ load = rq->load_avg - (rq->load_avg * us_interval * 5 / 262144);
+ if (unlikely(load < 0))
+ load = 0;
+ load += rq_load(rq) * SCHED_CAPACITY_SCALE * us_interval * 5 / 262144;
+ rq->load_avg = load;
+
+ rq->load_update = rq->niffies;
+ update_irq_load_avg(rq, 0);
+ if (likely(rq_local(rq)))
+ cpufreq_trigger(rq, flags);
+}
+
+#ifdef HAVE_SCHED_AVG_IRQ
+/*
+ * IRQ variant of update_load_avg below. delta is actually time in nanoseconds
+ * here so we scale curload to how long it's been since the last update.
+ */
+static void update_irq_load_avg(struct rq *rq, long delta)
+{
+ long us_interval, load;
+
+ us_interval = NS_TO_US(rq->niffies - rq->irq_load_update);
+ if (unlikely(us_interval <= 0))
+ return;
+
+ load = rq->irq_load_avg - (rq->irq_load_avg * us_interval * 5 / 262144);
+ if (unlikely(load < 0))
+ load = 0;
+ load += NS_TO_US(delta) * SCHED_CAPACITY_SCALE * 5 / 262144;
+ rq->irq_load_avg = load;
+
+ rq->irq_load_update = rq->niffies;
+}
+#endif
+
+static inline void update_best_key(struct rq *rq)
+{
+ WRITE_ONCE(rq->sl->best_key, rq->node->next[0]->key);
+}
+
+/*
+ * Removing from the runqueue. Enter with rq locked. Deleting a task
+ * from the skip list is done via the stored node reference in the task struct
+ * and does not require a full look up. Thus it occurs in O(k) time where k
+ * is the "level" of the list the task was stored at - usually 0, max 3.
+ */
+static void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
+{
+ /*
+ * Everything below is accounting for @p having been on @rq, so none of
+ * it may happen if it was not: a task whose node is unlinked is on no
+ * runqueue at all and skiplist_delete() has left the list untouched.
+ *
+ * nr_running in particular is unsigned, so a single spurious decrement
+ * wraps it to ~0 and the runqueue never looks empty again. That wedges
+ * sched_cpu_wait_empty(), whose only exit is nr_running <= 1, and a CPU
+ * offline then hangs forever with the dying CPU idle. psi_dequeue()
+ * would likewise clear state that is counted somewhere else. Leaving
+ * best_key alone is right for the same reason - the list did not
+ * change.
+ *
+ * skiplist_delete() has already warned; this only keeps a lost race in
+ * the caller from becoming permanent corruption of the runqueue.
+ */
+ if (unlikely(!skiplist_delete(rq->sl, &p->node)))
+ return;
+
+ update_best_key(rq);
+ update_clocks(rq);
+
+ if (!(flags & DEQUEUE_SAVE)) {
+ sched_info_dequeue(rq, p);
+ /* Pass full flags: DEQUEUE_SLEEP vs migration clear all state. */
+ psi_dequeue(p, flags);
+ }
+ rq->nr_running--;
+ if (rt_task(p))
+ rq->rt_nr_running--;
+ update_load_avg(rq, flags);
+}
+
+#ifdef CONFIG_PREEMPT_RCU
+static bool rcu_read_critical(struct task_struct *p)
+{
+ return p->rcu_read_unlock_special.b.blocked;
+}
+#else /* CONFIG_PREEMPT_RCU */
+#define rcu_read_critical(p) (false)
+#endif /* CONFIG_PREEMPT_RCU */
+
+/*
+ * To determine if it's safe for a task of SCHED_IDLEPRIO to actually run as
+ * an idle task, we ensure none of the following conditions are met.
+ */
+static bool idleprio_suitable(struct task_struct *p)
+{
+ return (!(p->sched_contributes_to_load) && !(p->flags & (PF_EXITING)) &&
+ !signal_pending(p) && !rcu_read_critical(p) && !freezing(p));
+}
+
+/*
+ * To determine if a task of SCHED_ISO can run in pseudo-realtime, we check
+ * that the iso_refractory flag is not set.
+ */
+static inline bool isoprio_suitable(struct rq *rq)
+{
+ return !rq->iso_refractory;
+}
+
+static inline void inc_nr_running(struct rq *rq)
+{
+ rq->nr_running++;
+ if (trace_sched_update_nr_running_tp_enabled()) {
+ call_trace_sched_update_nr_running(rq, 1);
+ }
+}
+
+static inline void dec_nr_running(struct rq *rq)
+{
+ rq->nr_running--;
+ if (trace_sched_update_nr_running_tp_enabled()) {
+ call_trace_sched_update_nr_running(rq, -1);
+ }
+}
+
+/*
+ * A running task is off the skiplist, so its share of rt_nr_running is not
+ * maintained by the enqueue/dequeue pair; __schedule() hands that slot over on
+ * every switch instead. When a *running* task's priority crosses the rt
+ * boundary neither happens, so fix the count up here.
+ */
+static inline void rt_running_reprio(struct rq *rq, int oldprio, int newprio)
+{
+ if (!rt_prio(newprio) == !rt_prio(oldprio))
+ return;
+
+ if (rt_prio(newprio))
+ rq->rt_nr_running++;
+ else
+ rq->rt_nr_running--;
+}
+
+/*
+ * Adding to the runqueue. Enter with rq locked.
+ */
+static void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
+{
+ unsigned int randseed, cflags = 0;
+ u64 sl_id, penalty;
+
+ if (!rt_task(p)) {
+ /* Check it hasn't gotten rt from PI */
+ if ((idleprio_task(p) && idleprio_suitable(p)) ||
+ (iso_task(p) && isoprio_suitable(rq)))
+ p->prio = p->normal_prio;
+ else
+ p->prio = NORMAL_PRIO;
+ } else
+ rq->rt_nr_running++;
+ /*
+ * The sl_id key passed to the skiplist generates a sorted list.
+ * Realtime and sched iso tasks run FIFO so they only need be sorted
+ * according to priority. The skiplist will put tasks of the same
+ * key inserted later in FIFO order. Tasks of sched normal, batch
+ * and idleprio are sorted according to their deadlines. Idleprio
+ * tasks are offset by an impossibly large deadline value ensuring
+ * they get sorted into last positions, but still according to their
+ * own deadlines. This creates a "landscape" of skiplists running
+ * from priority 0 realtime in first place to the lowest priority
+ * idleprio tasks last. Skiplist insertion is an O(log n) process.
+ */
+ /*
+ * Charge for device time and kernel work consumed since this task was
+ * last queued. Consumed unconditionally so debt cannot accumulate
+ * while a task is realtime, but only applied below, since realtime and
+ * iso tasks sort by priority rather than by deadline and so are never
+ * demoted.
+ */
+ penalty = consume_task_penalty(p);
+
+ if (p->prio <= ISO_PRIO) {
+ sl_id = p->prio;
+ } else {
+ p->deadline += penalty;
+ sl_id = p->deadline;
+ if (idleprio_task(p)) {
+ if (p->prio == IDLE_PRIO)
+ sl_id |= 0xF000000000000000;
+ else
+ sl_id += longest_deadline_diff();
+ }
+ }
+ /*
+ * Some architectures don't have better than microsecond resolution
+ * so mask out ~microseconds as the random seed for skiplist insertion.
+ */
+ update_clocks(rq);
+ if (!(flags & ENQUEUE_RESTORE)) {
+ sched_info_enqueue(rq, p);
+ /* Full flags so ENQUEUE_MIGRATED is visible to psi_enqueue(). */
+ psi_enqueue(p, flags);
+ }
+
+ randseed = (rq->niffies >> 10) & 0xFFFFFFFF;
+ skiplist_insert(rq->sl, &p->node, sl_id, randseed);
+ update_best_key(rq);
+ if (p->in_iowait)
+ cflags |= SCHED_CPUFREQ_IOWAIT;
+ inc_nr_running(rq);
+ update_load_avg(rq, cflags);
+}
+
+/*
+ * Returns the relative length of deadline all compared to the shortest
+ * deadline which is that of nice -20.
+ */
+static inline int task_prio_ratio(struct task_struct *p)
+{
+ return prio_ratios[TASK_USER_PRIO(p)];
+}
+
+/*
+ * task_timeslice - all tasks of all priorities get the exact same timeslice
+ * length. CPU distribution is handled by giving different deadlines to
+ * tasks of different priorities. Use 128 as the base value for fast shifts.
+ */
+static inline int task_timeslice(struct task_struct *p)
+{
+ return (rr_interval * task_prio_ratio(p) / 128);
+}
+
+#ifdef CONFIG_SMP
+/* Entered with rq locked */
+static inline void resched_if_idle(struct rq *rq)
+{
+ if (rq_idle(rq))
+ resched_task(rq->curr);
+}
+
+static inline bool rq_local(struct rq *rq)
+{
+ return (rq->cpu == smp_processor_id());
+}
+#ifdef CONFIG_SMT_NICE
+static const cpumask_t *thread_cpumask(int cpu);
+
+/* Find the best real time priority running on any SMT siblings of cpu and if
+ * none are running, the static priority of the best deadline task running.
+ * The lookups to the other runqueues is done lockless as the occasional wrong
+ * value would be harmless. */
+static int best_smt_bias(struct rq *this_rq)
+{
+ int other_cpu, best_bias = 0;
+
+ for_each_cpu(other_cpu, &this_rq->thread_mask) {
+ struct rq *rq = cpu_rq(other_cpu);
+
+ if (rq_idle(rq))
+ continue;
+ if (unlikely(!rq->online))
+ continue;
+ if (!rq->rq_mm)
+ continue;
+ if (likely(rq->rq_smt_bias > best_bias))
+ best_bias = rq->rq_smt_bias;
+ }
+ return best_bias;
+}
+
+static int task_prio_bias(struct task_struct *p)
+{
+ if (rt_task(p))
+ return 1 << 30;
+ else if (task_running_iso(p))
+ return 1 << 29;
+ else if (task_running_idle(p))
+ return 0;
+ return MAX_PRIO - p->static_prio;
+}
+
+static DEFINE_STATIC_KEY_FALSE(smt_nice_enabled);
+
+/* We've already decided p can run on CPU, now test if it shouldn't for SMT
+ * nice reasons. */
+static bool smt_should_schedule(struct task_struct *p, struct rq *this_rq)
+{
+ int best_bias, task_bias;
+
+ if (!idleprio_suitable(p))
+ return true;
+ best_bias = best_smt_bias(this_rq);
+ /* The smt siblings are all idle or running IDLEPRIO */
+ if (best_bias < 1)
+ return true;
+ task_bias = task_prio_bias(p);
+ if (task_bias < 1)
+ return false;
+ if (task_bias >= best_bias)
+ return true;
+ /* Dither 25% cpu of normal tasks regardless of nice difference */
+ if (best_bias % 4 == 1)
+ return true;
+ /* Sorry, you lose */
+ return false;
+}
+
+static inline bool smt_schedule(struct task_struct *p, struct rq *this_rq)
+{
+ if (!static_branch_unlikely(&smt_nice_enabled))
+ return true;
+ /* Kernel threads and RT tasks always run */
+ if (unlikely(!p->mm) || rt_task(p))
+ return true;
+ return smt_should_schedule(p, this_rq);
+}
+#else /* CONFIG_SMT_NICE */
+#define smt_schedule(p, this_rq) (true)
+#endif /* CONFIG_SMT_NICE */
+
+static inline void atomic_set_cpu(int cpu, cpumask_t *cpumask)
+{
+ set_bit(cpu, (volatile unsigned long *)cpumask);
+}
+
+/*
+ * The cpu_idle_map stores a bitmap of all the CPUs currently idle to
+ * allow easy lookup of whether any suitable idle CPUs are available.
+ * It's cheaper to maintain a binary yes/no if there are any idle CPUs on the
+ * idle_cpus variable than to do a full bitmask check when we are busy. The
+ * bits are set atomically but read locklessly as occasional false positive /
+ * negative is harmless.
+ */
+static inline void set_cpuidle_map(int cpu)
+{
+ /*
+ * Only an active CPU may advertise itself as a wakeup target.
+ * select_best_cpu() returns resched_best_idle()'s pick directly,
+ * and that pick comes straight out of this map without consulting
+ * is_cpu_allowed(), so a CPU on its way down (online but no longer
+ * active) would keep re-arming itself here every time it idled and
+ * collect fresh wakeups that sched_cpu_wait_empty() has to chase.
+ * set_rq_offline() clears the map; this keeps it clear.
+ */
+ if (likely(cpu_active(cpu)))
+ atomic_set_cpu(cpu, &cpu_idle_map);
+}
+
+static inline void atomic_clear_cpu(int cpu, cpumask_t *cpumask)
+{
+ clear_bit(cpu, (volatile unsigned long *)cpumask);
+}
+
+static inline void clear_cpuidle_map(int cpu)
+{
+ atomic_clear_cpu(cpu, &cpu_idle_map);
+}
+
+static bool suitable_idle_cpus(struct task_struct *p)
+{
+ return (cpumask_intersects(p->cpus_ptr, &cpu_idle_map));
+}
+
+/*
+ * Resched current on rq. We don't know if rq is local to this CPU nor if it
+ * is locked so we do not use an intermediate variable for the task to avoid
+ * having it dereferenced.
+ */
+static void resched_curr(struct rq *rq)
+{
+ int cpu;
+
+ if (test_tsk_need_resched(rq->curr))
+ return;
+
+ rq->preempt = rq->curr;
+ cpu = rq->cpu;
+
+ /* We're doing this without holding the rq lock if it's not task_rq */
+
+ if (cpu == smp_processor_id()) {
+ set_tsk_need_resched(rq->curr);
+ set_preempt_need_resched();
+ return;
+ }
+
+ if (set_nr_and_not_polling(rq->curr))
+ smp_sched_reschedule(cpu);
+ else
+ trace_sched_wake_idle_without_ipi(cpu);
+}
+
+#define CPUIDLE_NO_SIBLING (1)
+#define CPUIDLE_DIFF_THREAD (2)
+#define CPUIDLE_DIFF_CORE_LLC (4)
+#define CPUIDLE_DIFF_CORE (8)
+#define CPUIDLE_CACHE_BUSY (16)
+#define CPUIDLE_DIFF_CPU (32)
+#define CPUIDLE_THREAD_BUSY (64)
+#define CPUIDLE_DIFF_NODE (128)
+
+/*
+ * The best idle CPU is chosen according to the CPUIDLE ranking above where the
+ * lowest value would give the most suitable CPU to schedule p onto next. The
+ * order works out to be the following:
+ *
+ * Same thread, idle or busy cache, idle or busy threads
+ * Other core, same cache, idle or busy cache, idle threads.
+ * Same node, other CPU, idle cache, idle threads.
+ * Same node, other CPU, busy cache, idle threads.
+ * Other core, same cache, busy threads.
+ * Same node, other CPU, busy threads.
+ * Other node, other CPU, idle cache, idle threads.
+ * Other node, other CPU, busy cache, idle threads.
+ * Other node, other CPU, busy threads.
+ *
+ * CPUIDLE_NO_SIBLING is the least significant rank so it only separates cores
+ * that are otherwise equal, preferring a core with an idle SMT sibling over one
+ * with no siblings at all. On hybrid CPUs that indirectly prefers P cores over
+ * E cores, since only the former have siblings. A core whose sibling is busy
+ * still ranks below a core with no siblings as it only offers half a core.
+ * This does not treat CPUs with a single offline sibling as idle for
+ * simplicity.
+ */
+static int best_mask_cpu(int best_cpu, struct rq *rq, cpumask_t *tmpmask)
+{
+ int best_ranking = CPUIDLE_DIFF_NODE | CPUIDLE_THREAD_BUSY |
+ CPUIDLE_DIFF_CPU | CPUIDLE_CACHE_BUSY | CPUIDLE_DIFF_CORE |
+ CPUIDLE_DIFF_CORE_LLC | CPUIDLE_DIFF_THREAD | CPUIDLE_NO_SIBLING;
+ unsigned long best_idle_jiffy = 0;
+ int cpu_tmp;
+
+ if (cpumask_test_cpu(best_cpu, tmpmask))
+ goto out;
+
+ for_each_cpu(cpu_tmp, tmpmask) {
+ int ranking, locality;
+ struct rq *tmp_rq;
+
+ ranking = 0;
+ tmp_rq = cpu_rq(cpu_tmp);
+
+ locality = rq->cpu_locality[cpu_tmp];
+#ifdef CONFIG_NUMA
+ if (locality > LOCALITY_SMP)
+ ranking |= CPUIDLE_DIFF_NODE;
+ else
+#endif
+ if (locality > LOCALITY_MC)
+ ranking |= CPUIDLE_DIFF_CPU;
+#ifdef CONFIG_SCHED_MC
+ else if (locality == LOCALITY_MC_LLC)
+ ranking |= CPUIDLE_DIFF_CORE_LLC;
+ else if (locality == LOCALITY_MC)
+ ranking |= CPUIDLE_DIFF_CORE;
+ if (!(tmp_rq->cache_idle(tmp_rq)))
+ ranking |= CPUIDLE_CACHE_BUSY;
+#endif
+#ifdef CONFIG_SCHED_SMT
+ if (locality == LOCALITY_SMT)
+ ranking |= CPUIDLE_DIFF_THREAD;
+ if (!tmp_rq->has_smt_sibling)
+ ranking |= CPUIDLE_NO_SIBLING;
+ else if (!cpumask_subset(&tmp_rq->thread_mask, &cpu_idle_map))
+ ranking |= CPUIDLE_THREAD_BUSY;
+#endif
+ /* Also look for the most recently idled CPU as it will likely
+ * be still at a higher CPU frequency */
+ if (ranking < best_ranking ||
+ (ranking == best_ranking && tmp_rq->idle_jiffy > best_idle_jiffy)) {
+ best_cpu = cpu_tmp;
+ best_ranking = ranking;
+ best_idle_jiffy = tmp_rq->idle_jiffy;
+ }
+ }
+out:
+ return best_cpu;
+}
+
+bool cpus_share_cache(int this_cpu, int that_cpu)
+{
+ struct rq *this_rq = cpu_rq(this_cpu);
+
+ return (this_rq->cpu_locality[that_cpu] < LOCALITY_SMP);
+}
+
+/* As per resched_curr but only will resched idle task */
+static inline void resched_idle(struct rq *rq)
+{
+ if (test_tsk_need_resched(rq->idle))
+ return;
+
+ rq->preempt = rq->idle;
+
+ if (rq_local(rq)) {
+ set_tsk_need_resched(rq->idle);
+ set_preempt_need_resched();
+ return;
+ }
+
+ /*
+ * Atomically set NEED_RESCHED and only IPI if the idle task is not
+ * polling — same protocol as resched_curr / wake_up_idle_cpu.
+ */
+ if (set_nr_and_not_polling(rq->idle))
+ smp_sched_reschedule(rq->cpu);
+ else
+ trace_sched_wake_idle_without_ipi(rq->cpu);
+}
+
+DEFINE_PER_CPU(cpumask_t, idlemask);
+
+static struct rq *resched_best_idle(struct task_struct *p, int cpu)
+{
+ cpumask_t *tmpmask = &(per_cpu(idlemask, cpu));
+ struct rq *rq;
+ int best_cpu;
+
+ cpumask_and(tmpmask, p->cpus_ptr, &cpu_idle_map);
+ best_cpu = best_mask_cpu(cpu, task_rq(p), tmpmask);
+ rq = cpu_rq(best_cpu);
+ if (!smt_schedule(p, rq))
+ return NULL;
+ rq->preempt = p;
+ resched_idle(rq);
+ return rq;
+}
+
+static inline void resched_suitable_idle(struct task_struct *p)
+{
+ if (suitable_idle_cpus(p))
+ resched_best_idle(p, task_cpu(p));
+}
+
+static inline struct rq *rq_order(struct rq *rq, int cpu)
+{
+ return rq->rq_order[cpu];
+}
+#else /* CONFIG_SMP */
+static inline void set_cpuidle_map(int cpu)
+{
+}
+
+static inline void clear_cpuidle_map(int cpu)
+{
+}
+
+static inline bool suitable_idle_cpus(struct task_struct *p)
+{
+ return uprq->curr == uprq->idle;
+}
+
+static inline void resched_suitable_idle(struct task_struct *p)
+{
+}
+
+static inline void resched_curr(struct rq *rq)
+{
+ resched_task(rq->curr);
+}
+
+static inline void resched_if_idle(struct rq *rq)
+{
+}
+
+static inline bool rq_local(struct rq *rq)
+{
+ return true;
+}
+
+static inline struct rq *rq_order(struct rq *rq, int cpu)
+{
+ return rq;
+}
+
+static inline bool smt_schedule(struct task_struct *p, struct rq *rq)
+{
+ return true;
+}
+
+/* One CPU shares its cache with itself. */
+bool cpus_share_cache(int this_cpu, int that_cpu)
+{
+ return true;
+}
+#endif /* CONFIG_SMP */
+
+static inline int normal_prio(struct task_struct *p)
+{
+ if (has_rt_policy(p))
+ return MAX_RT_PRIO - 1 - p->rt_priority;
+ if (idleprio_task(p))
+ return IDLE_PRIO;
+ if (iso_task(p))
+ return ISO_PRIO;
+ return NORMAL_PRIO;
+}
+
+/*
+ * Calculate the current priority, i.e. the priority
+ * taken into account by the scheduler. This value might
+ * be boosted by RT tasks as it will be RT if the task got
+ * RT-boosted. If not then it returns p->normal_prio.
+ */
+static int effective_prio(struct task_struct *p)
+{
+ p->normal_prio = normal_prio(p);
+ /*
+ * If we are RT tasks or we were boosted to RT priority,
+ * keep the priority unchanged. Otherwise, update priority
+ * to the normal priority:
+ */
+ if (!rt_prio(p->prio))
+ return p->normal_prio;
+ return p->prio;
+}
+
+/*
+ * activate_task - move a task to the runqueue. Enter with rq locked.
+ */
+static void activate_task(struct rq *rq, struct task_struct *p, int flags)
+{
+ resched_if_idle(rq);
+
+ /* Sleep profiling (SLEEP_PROFILING) was removed upstream. */
+
+ p->prio = effective_prio(p);
+ enqueue_task(rq, p, flags);
+ p->on_rq = TASK_ON_RQ_QUEUED;
+}
+
+/*
+ * deactivate_task - If it's running, it's not on the runqueue and we can just
+ * decrement the nr_running. Enter with rq locked.
+ */
+static inline void deactivate_task(struct task_struct *p, struct rq *rq)
+{
+ p->on_rq = 0;
+ sched_info_dequeue(rq, p);
+ /* deactivate_task is always DEQUEUE_SLEEP in muqss */
+ psi_dequeue(p, DEQUEUE_SLEEP);
+}
+
+/*
+ * PSI counts the state a task is in per CPU, indexed by task_cpu(), so
+ * whenever task_cpu() changes for a task that still carries state, that state
+ * has to be moved with it. That is TSK_RUNNING for a task being taken to
+ * another runqueue, and TSK_IOWAIT for one that is still asleep. Whoever
+ * clears them next does so against task_cpu(p), and if that is no longer the
+ * CPU they were counted on the per-CPU counter underflows.
+ *
+ * TSK_ONCPU is deliberately not moved. It belongs to psi_sched_switch(), and
+ * a task whose CPU is being changed here is by definition not on one.
+ */
+#ifdef CONFIG_PSI
+static inline unsigned int psi_migrate_begin(struct task_struct *p)
+{
+ unsigned int migrate = p->psi_flags & ~TSK_ONCPU;
+
+ if (migrate)
+ psi_task_change(p, migrate, 0);
+ return migrate;
+}
+
+static inline void psi_migrate_end(struct task_struct *p, unsigned int migrate)
+{
+ if (migrate)
+ psi_task_change(p, 0, migrate);
+}
+#else /* !CONFIG_PSI */
+static inline unsigned int psi_migrate_begin(struct task_struct *p)
+{
+ return 0;
+}
+
+static inline void psi_migrate_end(struct task_struct *p, unsigned int migrate)
+{
+}
+#endif /* CONFIG_PSI */
+
+#ifdef CONFIG_SMP
+void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
+{
+ unsigned int migrate;
+ struct rq *rq;
+
+ if (task_cpu(p) == new_cpu)
+ return;
+
+ /* Do NOT call set_task_cpu on a currently queued task as we will not
+ * be reliably holding the rq lock after changing CPU. */
+ BUG_ON(task_queued(p));
+ rq = task_rq(p);
+
+#ifdef CONFIG_LOCKDEP
+ /*
+ * The caller should hold either p->pi_lock or rq->lock, when changing
+ * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
+ *
+ * Furthermore, all task_rq users should acquire both locks, see
+ * task_rq_lock().
+ */
+ WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
+ lockdep_is_held(rq->lock)));
+#endif
+
+ trace_sched_migrate_task(p, new_cpu);
+ rseq_sched_set_ids_changed(p);
+ perf_event_task_migrate(p);
+
+ /*
+ * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be
+ * successfully executed on another CPU. We must ensure that updates of
+ * per-task data have been completed by this moment.
+ */
+ smp_wmb();
+
+ p->wake_cpu = new_cpu;
+
+ if (task_running(rq, p)) {
+ /*
+ * We should only be calling this on a running task if we're
+ * holding rq lock.
+ */
+ lockdep_assert_held(rq->lock);
+
+ /*
+ * We can't change the task_thread_info CPU on a running task
+ * as p will still be protected by the rq lock of the CPU it
+ * is still running on so we only set the wake_cpu for it to be
+ * lazily updated once off the CPU.
+ */
+ return;
+ }
+
+ migrate = psi_migrate_begin(p);
+ WRITE_ONCE(task_thread_info(p)->cpu, new_cpu);
+ psi_migrate_end(p, migrate);
+ /* We're no longer protecting p after this point since we're holding
+ * the wrong runqueue lock. */
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * Move a task off the runqueue and take it to a cpu for it will
+ * become the running task.
+ */
+static inline void take_task(struct rq *rq, int cpu, struct task_struct *p)
+{
+ struct rq *p_rq = task_rq(p);
+
+ dequeue_task(p_rq, p, DEQUEUE_SAVE);
+ if (p_rq != rq) {
+ sched_info_dequeue(p_rq, p);
+ sched_info_enqueue(rq, p);
+ }
+ /*
+ * DEQUEUE_SAVE left TSK_RUNNING in place, and set_task_cpu() moves it
+ * to @cpu along with the task.
+ */
+ set_task_cpu(p, cpu);
+}
+
+/*
+ * Returns a descheduling task to the runqueue unless it is being
+ * deactivated.
+ */
+static inline void return_task(struct task_struct *p, struct rq *rq,
+ int cpu, bool deactivate)
+{
+ if (deactivate)
+ deactivate_task(p, rq);
+ else {
+#ifdef CONFIG_SMP
+ /*
+ * set_task_cpu was called on the running task that doesn't
+ * want to deactivate so it has to be enqueued to a different
+ * CPU and we need its lock. Tag it to be moved with as the
+ * lock is dropped in finish_lock_switch.
+ */
+ if (unlikely(p->wake_cpu != cpu))
+ WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
+ else
+#endif
+ enqueue_task(rq, p, ENQUEUE_RESTORE);
+ }
+}
+
+/* Enter with rq lock held. We know p is on the local cpu */
+static inline void __set_tsk_resched(struct task_struct *p)
+{
+ set_tsk_need_resched(p);
+ set_preempt_need_resched();
+}
+
+/**
+ * task_curr - is this task currently executing on a CPU?
+ * @p: the task in question.
+ *
+ * Return: 1 if the task is currently executing. 0 otherwise.
+ */
+inline int task_curr(const struct task_struct *p)
+{
+ return cpu_curr(task_cpu(p)) == p;
+}
+
+static __always_inline
+int __task_state_match(struct task_struct *p, unsigned int state)
+{
+ if (READ_ONCE(p->__state) & state)
+ return 1;
+
+ if (READ_ONCE(p->saved_state) & state)
+ return -1;
+
+ return 0;
+}
+
+static __always_inline
+int task_state_match(struct task_struct *p, unsigned int state)
+{
+ int match;
+
+ /*
+ * Serialize against current_save_and_set_rtlock_wait_state(),
+ * current_restore_rtlock_saved_state(), and __refrigerator().
+ */
+ raw_spin_lock_irq(&p->pi_lock);
+ match = __task_state_match(p, state);
+ raw_spin_unlock_irq(&p->pi_lock);
+
+ return match;
+}
+
+/*
+ * wait_task_inactive - wait for a thread to unschedule.
+ *
+ * Wait for the thread to block in any of the states set in @match_state.
+ * If it changes, i.e. @p might have woken up, then return zero. When we
+ * succeed in waiting for @p to be off its CPU, we return a positive number
+ * (its total switch count). If a second call a short while later returns
+ * the same number, the caller can be sure that @p has remained unscheduled
+ * the whole time.
+ *
+ * The caller must ensure that the task *will* unschedule sometime soon,
+ * else this function might spin for a *long* time. This function can't
+ * be called with interrupts off, or it may introduce deadlock with
+ * smp_call_function() if an IPI is sent by the same process we are
+ * waiting to become inactive.
+ */
+unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state)
+{
+ int running, queued, match;
+ struct rq_flags rf;
+ unsigned long ncsw;
+ struct rq *rq;
+
+ for (;;) {
+ rq = task_rq(p);
+
+ /*
+ * If the task is actively running on another CPU
+ * still, just relax and busy-wait without holding
+ * any locks.
+ *
+ * NOTE! Since we don't hold any locks, it's not
+ * even sure that "rq" stays as the right runqueue!
+ * But we don't care, since this will return false
+ * if the runqueue has changed and p is actually now
+ * running somewhere else!
+ */
+ while (task_running(rq, p)) {
+ if (!task_state_match(p, match_state))
+ return 0;
+ cpu_relax();
+ }
+
+ /*
+ * Ok, time to look more closely! We need the rq
+ * lock now, to be *sure*. If we're wrong, we'll
+ * just go back and repeat.
+ */
+ rq = task_rq_lock(p, &rf);
+ trace_sched_wait_task(p);
+ running = task_running(rq, p);
+ queued = task_on_rq_queued(p);
+ ncsw = 0;
+ if ((match = __task_state_match(p, match_state))) {
+ /*
+ * When matching on p->saved_state, consider this task
+ * still queued so it will wait.
+ */
+ if (match < 0)
+ queued = 1;
+ ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
+ }
+ task_rq_unlock(rq, p, &rf);
+
+ /*
+ * If it changed from the expected state, bail out now.
+ */
+ if (unlikely(!ncsw))
+ break;
+
+ /*
+ * Was it really running after all now that we
+ * checked with the proper locks actually held?
+ *
+ * Oops. Go back and try again..
+ */
+ if (unlikely(running)) {
+ cpu_relax();
+ continue;
+ }
+
+ /*
+ * It's not enough that it's not actively running,
+ * it must be off the runqueue _entirely_, and not
+ * preempted!
+ *
+ * So if it was still runnable (but just not actively
+ * running right now), it's preempted, and we should
+ * yield - it could be a while.
+ */
+ if (unlikely(queued)) {
+ ktime_t to = NSEC_PER_SEC / HZ;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&to, HRTIMER_MODE_REL);
+ continue;
+ }
+
+ /*
+ * Ahh, all good. It wasn't running, and it wasn't
+ * runnable, which means that it will never become
+ * running in the future either. We're all done!
+ */
+ break;
+ }
+
+ return ncsw;
+}
+
+/***
+ * kick_process - kick a running thread to enter/exit the kernel
+ * @p: the to-be-kicked thread
+ *
+ * Cause a process which is running on another CPU to enter
+ * kernel-mode, without any delay. (to get signals handled.)
+ *
+ * NOTE: this function doesn't have to take the runqueue lock,
+ * because all it wants to ensure is that the remote task enters
+ * the kernel. If the IPI races and the task has been migrated
+ * to another CPU then no harm is done and the purpose has been
+ * achieved as well.
+ */
+#ifdef CONFIG_SMP
+void kick_process(struct task_struct *p)
+{
+ int cpu;
+
+ preempt_disable();
+ cpu = task_cpu(p);
+ if ((cpu != smp_processor_id()) && task_curr(p))
+ smp_sched_reschedule(cpu);
+ preempt_enable();
+}
+#else /* !CONFIG_SMP */
+/* @p can only be running on the CPU we are already running on. */
+void kick_process(struct task_struct *p)
+{
+}
+#endif /* CONFIG_SMP */
+EXPORT_SYMBOL_GPL(kick_process);
+
+/*
+ * RT tasks preempt purely on priority. SCHED_NORMAL tasks preempt on the
+ * basis of earlier deadlines. SCHED_IDLEPRIO don't preempt anything else or
+ * between themselves, they cooperatively multitask. An idle rq scores as
+ * prio PRIO_LIMIT so it is always preempted.
+ */
+static inline bool
+can_preempt(struct task_struct *p, int prio, u64 deadline)
+{
+ /* Better static priority RT task or better policy preemption */
+ if (p->prio < prio)
+ return true;
+ if (p->prio > prio)
+ return false;
+ if (p->policy == SCHED_BATCH)
+ return false;
+ /* SCHED_NORMAL and ISO will preempt based on deadline */
+ if (!deadline_before(p->deadline, deadline))
+ return false;
+ return true;
+}
+
+#ifdef CONFIG_SMP
+
+/*
+ * Per-CPU kthreads are allowed to run on !active && online CPUs, see
+ * __set_cpus_allowed_ptr().
+ */
+static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
+{
+ if (!cpumask_test_cpu(cpu, p->cpus_ptr))
+ return false;
+
+ /* migrate_disable() must be allowed to finish on an online CPU. */
+ if (is_migration_disabled(p))
+ return cpu_online(cpu);
+
+ if (!(p->flags & PF_KTHREAD))
+ return cpu_active(cpu);
+
+ /* KTHREAD_IS_PER_CPU is always allowed. */
+ if (kthread_is_per_cpu(p))
+ return cpu_online(cpu);
+
+ /* Regular kernel threads don't get to stay during offline. */
+ if (cpu_dying(cpu))
+ return false;
+
+ /* But are allowed during online. */
+ return cpu_online(cpu);
+}
+
+/*
+ * Check to see if p can run on cpu, and if not, whether there are any online
+ * CPUs it can run on instead. This only happens with the hotplug threads that
+ * bring up the CPUs.
+ */
+static inline bool sched_other_cpu(struct task_struct *p, int cpu)
+{
+ if (unlikely(is_migration_disabled(p) && task_cpu(p) != cpu))
+ return true;
+ /*
+ * Defer to the single placement predicate: userspace is refused a
+ * deactivated CPU, a regular kthread is refused a dying one, while
+ * per-CPU kthreads and a migrate_disable() pin on this CPU still
+ * may run there.
+ */
+ if (likely(cpumask_test_cpu(cpu, p->cpus_ptr)))
+ return !is_cpu_allowed(p, cpu);
+ if (p->nr_cpus_allowed == 1) {
+ cpumask_t valid_mask;
+
+ /*
+ * Nowhere left to send it, so it may as well run here. The mask
+ * has to be the same one valid_task_cpu() uses to pick the
+ * destination, or the two disagree and the task is placed on a
+ * CPU that then refuses to run it.
+ *
+ * That is what a regular kthread affine to a single dying CPU
+ * hits: the CPU is still online, so intersecting with
+ * cpu_online_mask alone leaves it non-empty and this escape
+ * hatch never fires, while is_cpu_allowed() has already refused
+ * the dying CPU itself. It ends up runnable with no CPU willing
+ * to pick it. bind_zero() would free it by overriding the
+ * affinity, but that only runs from sched_cpu_wait_empty(),
+ * several hotplug states later - and anything the CPU going
+ * down waits for in between, such as blk_mq_hctx_notify_offline()
+ * waiting on a threaded completion interrupt, deadlocks against
+ * it.
+ */
+ cpumask_and(&valid_mask, p->cpus_ptr, cpu_online_mask);
+ if (!kthread_is_per_cpu(p))
+ cpumask_andnot(&valid_mask, &valid_mask, cpu_dying_mask);
+ if (unlikely(cpumask_empty(&valid_mask)))
+ return false;
+ }
+ return true;
+}
+
+static inline bool needs_other_cpu(struct task_struct *p, int cpu)
+{
+ if (unlikely(is_migration_disabled(p)))
+ return task_cpu(p) != cpu;
+ return !is_cpu_allowed(p, cpu);
+}
+
+/*
+ * Pin p->cpus_ptr to this CPU so EDT / select_best_cpu cannot steal a
+ * preempted migrate_disable() task. Called under rq->lock on prev.
+ */
+static void migrate_disable_switch(struct rq *rq, struct task_struct *p)
+{
+ if (likely(!p->migration_disabled))
+ return;
+ if (p->cpus_ptr != &p->cpus_mask)
+ return;
+ p->cpus_ptr = cpumask_of(cpu_of(rq));
+}
+
+#define cpu_online_map (*(cpumask_t *)cpu_online_mask)
+
+static void try_preempt(struct task_struct *p, struct rq *this_rq)
+{
+ int i, this_entries = rq_load(this_rq);
+ cpumask_t tmp;
+
+ /*
+ * An idle CPU first: waking one costs less than bouncing a task
+ * that is already running, and it is what keeps work spread out.
+ * Only if none is available do we consider preemption, and the
+ * loop below starts at cpu_order[0] - this_rq - so @p still gets
+ * to preempt its own dest before any remote runqueue.
+ */
+ if (suitable_idle_cpus(p) && resched_best_idle(p, task_cpu(p)))
+ return;
+
+ /* IDLEPRIO tasks never preempt anything but idle */
+ if (p->policy == SCHED_IDLEPRIO)
+ return;
+
+ cpumask_and(&tmp, &cpu_online_map, p->cpus_ptr);
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ struct rq *rq = this_rq->cpu_order[i];
+
+ if (!cpumask_test_cpu(rq->cpu, &tmp))
+ continue;
+
+ if (!sched_interactive && rq != this_rq && rq_load(rq) <= this_entries)
+ continue;
+ if (smt_schedule(p, rq) && can_preempt(p, rq->rq_prio, rq->rq_deadline)) {
+ /* We set rq->preempting lockless, it's a hint only */
+ rq->preempting = p;
+ resched_curr(rq);
+ return;
+ }
+ }
+}
+
+static int __set_cpus_allowed_ptr(struct task_struct *p,
+ const struct cpumask *new_mask,
+ u32 flags);
+#else /* CONFIG_SMP */
+static inline bool needs_other_cpu(struct task_struct *p, int cpu)
+{
+ return false;
+}
+
+static void try_preempt(struct task_struct *p, struct rq *this_rq)
+{
+ if (p->policy == SCHED_IDLEPRIO)
+ return;
+ if (can_preempt(p, uprq->rq_prio, uprq->rq_deadline))
+ resched_curr(uprq);
+}
+
+static inline int __set_cpus_allowed_ptr(struct task_struct *p,
+ const struct cpumask *new_mask,
+ u32 __always_unused flags)
+{
+ return set_cpus_allowed_ptr(p, new_mask);
+}
+#endif /* CONFIG_SMP */
+
+static void
+ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
+{
+ struct rq *rq;
+
+ if (!schedstat_enabled())
+ return;
+
+ rq = this_rq();
+
+#ifdef CONFIG_SMP
+ if (cpu == rq->cpu) {
+ __schedstat_inc(rq->ttwu_local);
+ } else {
+ struct sched_domain *sd;
+
+ rcu_read_lock();
+ for_each_domain(rq->cpu, sd) {
+ if (cpumask_test_cpu(cpu, sched_domain_span(sd))) {
+ __schedstat_inc(sd->ttwu_wake_remote);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ }
+
+#endif /* CONFIG_SMP */
+
+ __schedstat_inc(rq->ttwu_count);
+}
+
+/*
+ * Mark the task runnable and perform wakeup-preemption.
+ */
+static void ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
+{
+ /*
+ * WF_SYNC means the waker will leave the CPU shortly. Prefer an
+ * idle CPU and do not preempt the waker itself — it will pick the
+ * wakee up on the next schedule(). A remote dest still needs
+ * kicking, or the wakee sits until dest's next tick (or forever
+ * on a nohz_full hog).
+ */
+ if ((wake_flags & WF_SYNC) && rq == this_rq())
+ resched_suitable_idle(p);
+ else
+ try_preempt(p, rq);
+ WRITE_ONCE(p->__state, TASK_RUNNING);
+ trace_sched_wakeup(p);
+}
+
+static void
+ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags)
+{
+ int en_flags = ENQUEUE_WAKEUP;
+
+ lockdep_assert_held(rq->lock);
+
+ if (p->sched_contributes_to_load)
+ rq->nr_uninterruptible--;
+
+#ifdef CONFIG_SMP
+ if (wake_flags & WF_MIGRATED)
+ en_flags |= ENQUEUE_MIGRATED;
+ else
+#endif
+ if (p->in_iowait) {
+ delayacct_blkio_end(p);
+ atomic_dec(&task_rq(p)->nr_iowait);
+ }
+
+ activate_task(rq, p, en_flags);
+ ttwu_do_wakeup(rq, p, wake_flags);
+}
+
+/*
+ * Consider @p being inside a wait loop:
+ *
+ * for (;;) {
+ * set_current_state(TASK_UNINTERRUPTIBLE);
+ *
+ * if (CONDITION)
+ * break;
+ *
+ * schedule();
+ * }
+ * __set_current_state(TASK_RUNNING);
+ *
+ * between set_current_state() and schedule(). In this case @p is still
+ * runnable, so all that needs doing is change p->__state back to TASK_RUNNING in
+ * an atomic manner.
+ *
+ * By taking task_rq(p)->lock we serialize against schedule(), if @p->on_rq
+ * then schedule() must still happen and p->__state can be changed to
+ * TASK_RUNNING. Otherwise we lost the race, schedule() has happened, and we
+ * need to do a full wakeup with enqueue.
+ *
+ * Returns: %true when the wakeup is done,
+ * %false otherwise.
+ */
+static int ttwu_runnable(struct task_struct *p, int wake_flags)
+{
+ struct rq *rq;
+ int ret = 0;
+
+ rq = __task_rq_lock(p, NULL);
+ if (likely(task_on_rq_queued(p))) {
+ ttwu_do_wakeup(rq, p, wake_flags);
+ ret = 1;
+ }
+ __task_rq_unlock(rq, p, NULL);
+
+ return ret;
+}
+
+#ifdef CONFIG_SMP
+void sched_ttwu_pending(void *arg)
+{
+ struct llist_node *llist = arg;
+ struct rq *rq = this_rq();
+ struct task_struct *p, *t;
+ struct rq_flags rf;
+
+ if (!llist)
+ return;
+
+ /*
+ * rq::ttwu_pending racy indication of out-standing wakeups.
+ * Races such that false-negatives are possible, since they
+ * are shorter lived that false-positives would be.
+ */
+ WRITE_ONCE(rq->ttwu_pending, 0);
+
+ rq_lock_irqsave(rq, &rf);
+
+ llist_for_each_entry_safe(p, t, llist, wake_entry.llist) {
+ if (WARN_ON_ONCE(p->on_cpu))
+ smp_cond_load_acquire(&p->on_cpu, !VAL);
+
+ if (WARN_ON_ONCE(task_cpu(p) != cpu_of(rq)))
+ set_task_cpu(p, cpu_of(rq));
+
+ ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0);
+ }
+
+ rq_unlock_irqrestore(rq, &rf);
+}
+
+/*
+ * Called from smp.c: report whether the caller still needs to send the IPI,
+ * having woken a polling idle task in passing.
+ */
+bool call_function_single_prep_ipi(int cpu)
+{
+ if (set_nr_if_polling(cpu_rq(cpu)->idle)) {
+ trace_sched_wake_idle_without_ipi(cpu);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Queue a task on the target CPUs wake_list and wake the CPU via IPI if
+ * necessary. The wakee CPU on receipt of the IPI will queue the task
+ * via sched_ttwu_wakeup() for activation so the wakee incurs the cost
+ * of the wakeup instead of the waker.
+ */
+static void __ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
+{
+ struct rq *rq = cpu_rq(cpu);
+
+ /*
+ * Carry WF_MIGRATED across to the CPU that will do the enqueue. Losing
+ * it there makes ttwu_do_activate() treat an already migrated wakeup
+ * as a local one, decrementing rq->nr_iowait a second time and telling
+ * PSI to clear an iowait that psi_ttwu_dequeue() has already dropped.
+ */
+ p->sched_remote_wakeup = !!(wake_flags & WF_MIGRATED);
+
+ WRITE_ONCE(rq->ttwu_pending, 1);
+ __smp_call_single_queue(cpu, &p->wake_entry.llist);
+}
+
+void wake_up_if_idle(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ struct rq_flags rf;
+
+ rcu_read_lock();
+
+ if (!is_idle_task(rcu_dereference(rq->curr)))
+ goto out;
+
+ /*
+ * Match mainline: always go through resched_curr so TIF_NEED_RESCHED
+ * is set before any IPI. Sending a reschedule IPI alone does nothing
+ * useful — scheduler_ipi() only folds an already-set need_resched.
+ */
+ rq_lock_irqsave(rq, &rf);
+ if (is_idle_task(rq->curr))
+ resched_curr(rq);
+ rq_unlock_irqrestore(rq, &rf);
+
+out:
+ rcu_read_unlock();
+}
+
+static inline bool ttwu_queue_cond(int cpu, int wake_flags)
+{
+ /*
+ * Do not complicate things with the async wake_list while the CPU is
+ * in hotplug state.
+ */
+ if (!cpu_active(cpu))
+ return false;
+
+ /*
+ * If the CPU does not share cache, then queue the task on the
+ * remote rqs wakelist to avoid accessing remote data.
+ */
+ if (!cpus_share_cache(smp_processor_id(), cpu))
+ return true;
+
+ /*
+ * If the task is descheduling and the only running task on the
+ * CPU then use the wakelist to offload the task activation to
+ * the soon-to-be-idle CPU as the current CPU is likely busy.
+ * nr_running is checked to avoid unnecessary task stacking.
+ */
+ if ((wake_flags & WF_ON_CPU) && cpu_rq(cpu)->nr_running <= 1)
+ return true;
+
+ return false;
+}
+
+static bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
+{
+ /* CFS would require sched_feat(TTWU_QUEUE) here but that is
+ * fixed enabled */
+ if (ttwu_queue_cond(cpu, wake_flags)) {
+ if (WARN_ON_ONCE(cpu == smp_processor_id()))
+ return false;
+
+ sched_clock_cpu(cpu); /* Sync clocks across CPUs */
+ __ttwu_queue_wakelist(p, cpu, wake_flags);
+ return true;
+ }
+
+ return false;
+}
+
+static int valid_task_cpu(struct task_struct *p)
+{
+ cpumask_t valid_mask;
+
+ if (unlikely(is_migration_disabled(p)))
+ return task_cpu(p);
+
+ /*
+ * Kthreads may be bound to a CPU that is not yet online (per-CPU
+ * hotplug threads created during smp_init). Placement for running
+ * must still pick an online CPU — sched_other_cpu() allows them to
+ * be selected despite the affinity mismatch until their CPU is up.
+ * Userspace tasks are restricted to the active mask as usual.
+ */
+ if (p->flags & PF_KTHREAD) {
+ cpumask_and(&valid_mask, p->cpus_ptr, cpu_online_mask);
+ /*
+ * Only KTHREAD_IS_PER_CPU gets to stay on a CPU that is on
+ * its way down, so do not hand a regular kthread back the
+ * CPU bind_zero() just moved it off. Mirrors is_cpu_allowed().
+ */
+ if (!kthread_is_per_cpu(p))
+ cpumask_andnot(&valid_mask, &valid_mask, cpu_dying_mask);
+ } else
+ cpumask_and(&valid_mask, p->cpus_ptr, cpu_active_mask);
+
+ if (unlikely(!cpumask_weight(&valid_mask))) {
+ if ((p->flags & PF_KTHREAD) && num_online_cpus())
+ return cpumask_any(cpu_online_mask);
+ /* Defer console access while holding the task's PI lock. */
+ printk_deferred(KERN_WARNING "SCHED: No cpumask for %s/%d weight %d\n",
+ p->comm, p->pid, cpumask_weight(p->cpus_ptr));
+ return cpumask_any(p->cpus_ptr);
+ }
+ return cpumask_any(&valid_mask);
+}
+
+/*
+ * For a task that's just being woken up we have a valuable balancing
+ * opportunity so choose the nearest cache most lightly loaded runqueue.
+ * Entered with rq locked and returns with the chosen runqueue locked.
+ */
+static inline int select_best_cpu(struct task_struct *p)
+{
+ unsigned int idlest = ~0U;
+ struct rq *rq = NULL;
+ int i;
+
+ if (suitable_idle_cpus(p)) {
+ int cpu = task_cpu(p);
+
+ if (unlikely(needs_other_cpu(p, cpu)))
+ cpu = valid_task_cpu(p);
+ rq = resched_best_idle(p, cpu);
+ if (likely(rq))
+ return rq->cpu;
+ }
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ struct rq *other_rq = task_rq(p)->cpu_order[i];
+ int entries;
+
+ if (!other_rq->online)
+ continue;
+ if (needs_other_cpu(p, other_rq->cpu))
+ continue;
+ entries = rq_load(other_rq);
+ if (entries >= idlest)
+ continue;
+ idlest = entries;
+ rq = other_rq;
+ }
+ if (unlikely(!rq)) {
+ /*
+ * The walk found nowhere to put @p. Its affinity may contain
+ * only offline CPUs (hotplug kthreads bound before their CPU
+ * is up), or the walk may simply not have reached an allowed
+ * one: cpu_order[] is built once at boot, so once any CPU is
+ * offline the num_online_cpus() bound above stops short of its
+ * tail and never examines what is there.
+ *
+ * Staying put is only an answer if this CPU is one @p is
+ * allowed to run on. Otherwise defer to valid_task_cpu(),
+ * which intersects the mask directly and so does not depend on
+ * that ordering at all. Never place a wakeup on a CPU the task
+ * is not allowed on, whether because it is offline or because
+ * it is not in the mask; a blocked task keeps a stale
+ * task_cpu() across an affinity change, so the latter is the
+ * common case here.
+ */
+ if (unlikely(needs_other_cpu(p, task_cpu(p))))
+ return valid_task_cpu(p);
+ return task_cpu(p);
+ }
+ return rq->cpu;
+}
+#else /* CONFIG_SMP */
+
+static inline bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags)
+{
+ return false;
+}
+
+static int valid_task_cpu(struct task_struct *p)
+{
+ return 0;
+}
+
+static inline int select_best_cpu(struct task_struct *p)
+{
+ return 0;
+}
+
+static struct rq *resched_best_idle(struct task_struct *p, int cpu)
+{
+ return NULL;
+}
+#endif /* CONFIG_SMP */
+
+static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags)
+{
+ struct rq *rq = cpu_rq(cpu);
+
+ if (ttwu_queue_wakelist(p, cpu, wake_flags))
+ return;
+
+ rq_lock(rq);
+ update_rq_clock(rq);
+ ttwu_do_activate(rq, p, wake_flags);
+ rq_unlock(rq);
+}
+
+/*
+ * Consider @state matched against @p, taking p->saved_state into account.
+ *
+ * The caller holds p::pi_lock if p != current or has preemption disabled
+ * when p == current.
+ *
+ * The rules of saved_state:
+ *
+ * The related locking code always holds p::pi_lock when updating
+ * p::saved_state, which means the code is fully serialized in both cases.
+ *
+ * For PREEMPT_RT, the lock wait and lock wakeups happen via TASK_RTLOCK_WAIT.
+ * No other bits set. This allows to distinguish all wakeup scenarios.
+ *
+ * For FREEZER, the wakeup happens via TASK_FROZEN. No other bits set. This
+ * allows us to prevent early wakeup of tasks before they can be run on
+ * asymmetric ISA architectures (eg ARMv9).
+ */
+static __always_inline
+bool ttwu_state_match(struct task_struct *p, unsigned int state, int *success)
+{
+ int match;
+
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)) {
+ WARN_ON_ONCE((state & TASK_RTLOCK_WAIT) &&
+ state != TASK_RTLOCK_WAIT);
+ }
+
+ *success = !!(match = __task_state_match(p, state));
+
+ /*
+ * Saved state preserves the task state across blocking on
+ * an RT lock or TASK_FREEZABLE tasks. If the state matches,
+ * set p::saved_state to TASK_RUNNING, but do not wake the task
+ * because it waits for a lock wakeup or __thaw_task(). Also
+ * indicate success because from the regular waker's point of
+ * view this has succeeded.
+ *
+ * After acquiring the lock the task will restore p::__state
+ * from p::saved_state which ensures that the regular
+ * wakeup is not lost. The restore will also set
+ * p::saved_state to TASK_RUNNING so any further tests will
+ * not result in false positives vs. @success
+ */
+ if (match < 0)
+ p->saved_state = TASK_RUNNING;
+
+ return match > 0;
+}
+
+/***
+ * try_to_wake_up - wake up a thread
+ * @p: the thread to be awakened
+ * @state: the mask of task states that can be woken
+ * @wake_flags: wake modifier flags (WF_*)
+ *
+ * Put it on the run-queue if it's not already there. The "current"
+ * thread is always on the run-queue (except when the actual
+ * re-schedule is in progress), and as such you're allowed to do
+ * the simpler "current->__state = TASK_RUNNING" to mark yourself
+ * runnable without the overhead of this.
+ *
+ * Return: %true if @p was woken up, %false if it was already running.
+ * or @state didn't match @p's state.
+ */
+int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
+{
+ unsigned long flags;
+ int cpu, success = 0;
+
+ preempt_disable();
+ if (p == current) {
+ /*
+ * We're waking current, this means 'p->on_rq' and 'task_cpu(p)
+ * == smp_processor_id()'. Together this means we can special
+ * case the whole 'p->on_rq && ttwu_runnable()' case below
+ * without taking any locks.
+ *
+ * In particular:
+ * - we rely on Program-Order guarantees for all the ordering,
+ * - we're serialized against set_special_state() by virtue of
+ * it disabling IRQs (this allows not taking ->pi_lock).
+ */
+ if (!ttwu_state_match(p, state, &success))
+ goto out;
+
+ trace_sched_waking(p);
+ p->__state = TASK_RUNNING;
+ trace_sched_wakeup(p);
+ goto out;
+ }
+
+ /*
+ * If we are going to wake up a thread waiting for CONDITION we
+ * need to ensure that CONDITION=1 done by the caller can not be
+ * reordered with p->__state check below. This pairs with smp_store_mb()
+ * in set_current_state() that the waiting thread does.
+ */
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
+ smp_mb__after_spinlock();
+ if (!ttwu_state_match(p, state, &success))
+ goto unlock;
+
+ trace_sched_waking(p);
+
+ /*
+ * Ensure we load p->on_rq _after_ p->__state, otherwise it would
+ * be possible to, falsely, observe p->on_rq == 0 and get stuck
+ * in smp_cond_load_acquire() below.
+ *
+ * sched_ttwu_pending() try_to_wake_up()
+ * STORE p->on_rq = 1 LOAD p->__state
+ * UNLOCK rq->lock
+ *
+ * __schedule() (switch to task 'p')
+ * LOCK rq->lock smp_rmb();
+ * smp_mb__after_spinlock();
+ * UNLOCK rq->lock
+ *
+ * [task p]
+ * STORE p->__state = UNINTERRUPTIBLE LOAD p->on_rq
+ *
+ * Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
+ * __schedule(). See the comment for smp_mb__after_spinlock().
+ */
+ smp_rmb();
+ if (READ_ONCE(p->on_rq) && ttwu_runnable(p, wake_flags))
+ goto unlock;
+
+#ifdef CONFIG_SMP
+ /*
+ * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
+ * possible to, falsely, observe p->on_cpu == 0.
+ *
+ * One must be running (->on_cpu == 1) in order to remove oneself
+ * from the runqueue.
+ *
+ * __schedule() (switch to task 'p') try_to_wake_up()
+ * STORE p->on_cpu = 1 LOAD p->on_rq
+ * UNLOCK rq->lock
+ *
+ * __schedule() (put 'p' to sleep)
+ * LOCK rq->lock smp_rmb();
+ * smp_mb__after_spinlock();
+ * STORE p->on_rq = 0 LOAD p->on_cpu
+ *
+ * Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
+ * __schedule(). See the comment for smp_mb__after_spinlock().
+ *
+ * Form a control-dep-acquire with p->on_rq == 0 above, to ensure
+ * schedule()'s deactivate_task() has 'happened' and p will no longer
+ * care about it's own p->__state. See the comment in __schedule().
+ */
+ smp_acquire__after_ctrl_dep();
+
+ /*
+ * We're doing the wakeup (@success == 1), they did a dequeue (p->on_rq
+ * == 0), which means we need to do an enqueue, change p->__state to
+ * TASK_WAKING such that we can unlock p->pi_lock before doing the
+ * enqueue, such as ttwu_queue_wakelist().
+ */
+ p->__state = TASK_WAKING;
+
+ /*
+ * If the owning (remote) CPU is still in the middle of schedule() with
+ * this task as prev, considering queueing p on the remote CPUs wake_list
+ * which potentially sends an IPI instead of spinning on p->on_cpu to
+ * let the waker make forward progress. This is safe because IRQs are
+ * disabled and the IPI will deliver after on_cpu is cleared.
+ *
+ * Ensure we load task_cpu(p) after p->on_cpu:
+ *
+ * set_task_cpu(p, cpu);
+ * STORE task_cpu(p) = @cpu
+ * __schedule() (switch to task 'p')
+ * LOCK rq->lock
+ * smp_mb__after_spin_lock() smp_cond_load_acquire(&p->on_cpu)
+ * STORE p->on_cpu = 1 LOAD task_cpu(p)
+ *
+ * to ensure we observe the correct CPU on which the task is currently
+ * scheduling.
+ */
+ if (smp_load_acquire(&p->on_cpu) &&
+ ttwu_queue_wakelist(p, task_cpu(p), wake_flags | WF_ON_CPU))
+ goto unlock;
+
+ /*
+ * If the owning (remote) CPU is still in the middle of schedule() with
+ * this task as prev, wait until it's done referencing the task.
+ *
+ * Pairs with the smp_store_release() in finish_task().
+ *
+ * This ensures that tasks getting woken will be fully ordered against
+ * their previous state and preserve Program Order.
+ */
+ smp_cond_load_acquire(&p->on_cpu, !VAL);
+
+ cpu = select_best_cpu(p);
+ if (task_cpu(p) != cpu) {
+ if (p->in_iowait) {
+ delayacct_blkio_end(p);
+ atomic_dec(&task_rq(p)->nr_iowait);
+ }
+
+ wake_flags |= WF_MIGRATED;
+ psi_ttwu_dequeue(p);
+ set_task_cpu(p, cpu);
+ }
+
+#else
+ cpu = task_cpu(p);
+#endif /* CONFIG_SMP */
+
+ ttwu_queue(p, cpu, wake_flags);
+unlock:
+ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+out:
+ if (success)
+ ttwu_stat(p, task_cpu(p), wake_flags);
+ preempt_enable();
+
+ return success;
+}
+
+static bool __task_needs_rq_lock(struct task_struct *p)
+{
+ unsigned int state = READ_ONCE(p->__state);
+
+ /*
+ * Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
+ * the task is blocked. Make sure to check @state since ttwu() can drop
+ * locks at the end, see ttwu_queue_wakelist().
+ */
+ if (state == TASK_RUNNING || state == TASK_WAKING)
+ return true;
+
+ /*
+ * Ensure we load p->on_rq after p->__state, otherwise it would be
+ * possible to, falsely, observe p->on_rq == 0.
+ *
+ * See try_to_wake_up() for a longer comment.
+ */
+ smp_rmb();
+ if (p->on_rq)
+ return true;
+
+ /*
+ * Ensure the task has finished __schedule() and will not be referenced
+ * anymore. Again, see try_to_wake_up() for a longer comment.
+ */
+ smp_rmb();
+ smp_cond_load_acquire(&p->on_cpu, !VAL);
+
+ return false;
+}
+
+/**
+ * task_call_func - Invoke a function on task in fixed state
+ * @p: Process for which the function is to be invoked, can be @current.
+ * @func: Function to invoke.
+ * @arg: Argument to function.
+ *
+ * Fix the task in it's current state by avoiding wakeups and or rq operations
+ * and call @func(@arg) on it. This function can use task_is_runnable() and
+ * task_curr() to work out what the state is, if required. Given that @func
+ * can be invoked with a runqueue lock held, it had better be quite
+ * lightweight.
+ *
+ * Returns:
+ * Whatever @func returns
+ */
+int task_call_func(struct task_struct *p, task_call_f func, void *arg)
+{
+ struct rq_flags rf;
+ int ret;
+
+ raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
+
+ if (__task_needs_rq_lock(p)) {
+ struct rq *rq = __task_rq_lock(p, &rf);
+
+ /*
+ * At this point the task is pinned; either:
+ * - blocked and we're holding off wakeups (pi->lock)
+ * - woken, and we're holding off enqueue (rq->lock)
+ * - queued, and we're holding off schedule (rq->lock)
+ * - running, and we're holding off de-schedule (rq->lock)
+ *
+ * The called function (@func) can use: task_curr(), p->on_rq and
+ * p->__state to differentiate between these states.
+ */
+ ret = func(p, arg);
+
+ __task_rq_unlock(rq, p, &rf);
+ } else {
+ ret = func(p, arg);
+ }
+
+ raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags);
+ return ret;
+}
+
+/**
+ * wake_up_process - Wake up a specific process
+ * @p: The process to be woken up.
+ *
+ * Attempt to wake up the nominated process and move it to the set of runnable
+ * processes.
+ *
+ * Return: 1 if the process was woken up, 0 if it was already running.
+ *
+ * This function executes a full memory barrier before accessing the task state.
+ */
+int wake_up_process(struct task_struct *p)
+{
+ return try_to_wake_up(p, TASK_NORMAL, 0);
+}
+EXPORT_SYMBOL(wake_up_process);
+
+int wake_up_state(struct task_struct *p, unsigned int state)
+{
+ return try_to_wake_up(p, state, 0);
+}
+
+static void time_slice_expired(struct task_struct *p, struct rq *rq);
+
+/*
+ * Perform scheduler related setup for a newly forked process p.
+ * p is forked by current.
+ */
+int sched_fork(u64 __maybe_unused clone_flags, struct task_struct *p)
+{
+ unsigned long flags;
+
+#ifdef CONFIG_PREEMPT_NOTIFIERS
+ INIT_HLIST_HEAD(&p->preempt_notifiers);
+#endif
+
+#ifdef CONFIG_COMPACTION
+ p->capture_control = NULL;
+#endif
+
+#ifdef CONFIG_SMP
+ p->wake_entry.u_flags = CSD_TYPE_TTWU;
+#endif
+ /* A new task starts with no I/O history of its own. */
+ muqss_iotime_task_init(p);
+
+ /*
+ * We mark the process as NEW here. This guarantees that
+ * nobody will actually run it, and a signal or other external
+ * event cannot wake it up and insert it on the runqueue either.
+ */
+ p->__state = TASK_NEW;
+
+ /*
+ * The process state is set to the same value of the process executing
+ * do_fork() code. That is running. This guarantees that nobody will
+ * actually run it, and a signal or other external event cannot wake
+ * it up and insert it on the runqueue either.
+ */
+
+ /* Should be reset in fork.c but done here for ease of MuQSS patching */
+ p->on_cpu =
+ p->on_rq =
+ p->utime =
+ p->stime =
+ p->sched_time =
+ p->stime_ns =
+ p->utime_ns = 0;
+ skiplist_node_init(&p->node);
+
+ /*
+ * Revert to default priority/policy on fork if requested.
+ */
+ if (unlikely(p->sched_reset_on_fork)) {
+ if (p->policy == SCHED_FIFO || p->policy == SCHED_RR || p-> policy == SCHED_ISO) {
+ /*
+ * __setscheduler() zeroes timer_slack_ns for rt tasks,
+ * so restore it when demoting back to SCHED_NORMAL,
+ * otherwise the child inherits zero slack forever.
+ */
+ if (has_rt_policy(p))
+ p->timer_slack_ns = p->default_timer_slack_ns;
+ p->policy = SCHED_NORMAL;
+ p->normal_prio = normal_prio(p);
+ }
+
+ if (PRIO_TO_NICE(p->static_prio) < 0) {
+ p->static_prio = NICE_TO_PRIO(0);
+ p->normal_prio = p->static_prio;
+ }
+
+ /*
+ * We don't need the reset flag anymore after the fork. It has
+ * fulfilled its duty:
+ */
+ p->sched_reset_on_fork = 0;
+ }
+
+ /*
+ * Silence PROVE_RCU.
+ */
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
+ rseq_sched_set_ids_changed(p);
+ set_task_cpu(p, smp_processor_id());
+ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+
+#ifdef CONFIG_SCHED_INFO
+ if (unlikely(sched_info_on()))
+ memset(&p->sched_info, 0, sizeof(p->sched_info));
+#endif
+ init_task_preempt_count(p);
+
+ return 0;
+}
+
+void sched_post_fork(struct task_struct *p)
+{
+}
+
+#ifdef CONFIG_SCHEDSTATS
+
+DEFINE_STATIC_KEY_FALSE(sched_schedstats);
+static bool __initdata __sched_schedstats = false;
+
+static void set_schedstats(bool enabled)
+{
+ if (enabled)
+ static_branch_enable(&sched_schedstats);
+ else
+ static_branch_disable(&sched_schedstats);
+}
+
+void force_schedstat_enabled(void)
+{
+ if (!schedstat_enabled()) {
+ pr_info("kernel profiling enabled schedstats, disable via kernel.sched_schedstats.\n");
+ static_branch_enable(&sched_schedstats);
+ }
+}
+
+static int __init setup_schedstats(char *str)
+{
+ int ret = 0;
+ if (!str)
+ goto out;
+
+ /*
+ * This code is called before jump labels have been set up, so we can't
+ * change the static branch directly just yet. Instead set a temporary
+ * variable so init_schedstats() can do it later.
+ */
+ if (!strcmp(str, "enable")) {
+ __sched_schedstats = true;
+ ret = 1;
+ } else if (!strcmp(str, "disable")) {
+ __sched_schedstats = false;
+ ret = 1;
+ }
+out:
+ if (!ret)
+ pr_warn("Unable to parse schedstats=\n");
+
+ return ret;
+}
+__setup("schedstats=", setup_schedstats);
+
+static void __init init_schedstats(void)
+{
+ set_schedstats(__sched_schedstats);
+}
+
+#ifdef CONFIG_SYSCTL
+static int sysctl_schedstats(const struct ctl_table *table, int write, void *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table t;
+ int err;
+ int state = static_branch_likely(&sched_schedstats);
+
+ if (write && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ t = *table;
+ t.data = &state;
+ err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
+ if (err < 0)
+ return err;
+ if (write)
+ set_schedstats(state);
+ return err;
+}
+#endif /* CONFIG_SYSCTL */
+#else /* !CONFIG_SCHEDSTATS */
+static inline void init_schedstats(void) {}
+#endif /* CONFIG_SCHEDSTATS */
+
+#ifdef CONFIG_SYSCTL
+/*
+ * MuQSS tunables used to live in kernel/sysctl.c. Mainline moved scheduler
+ * sysctls next to their implementation via register_sysctl_init(), so register
+ * ours the same way. CFS/rt/fair knobs are not present under MuQSS.
+ */
+static const struct ctl_table muqss_sysctls[] = {
+ {
+ .procname = "rr_interval",
+ .data = &rr_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ONE,
+ .extra2 = SYSCTL_ONE_THOUSAND,
+ },
+ {
+ .procname = "interactive",
+ .data = &sched_interactive,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
+ {
+ .procname = "iso_cpu",
+ .data = &sched_iso_cpu,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE_HUNDRED,
+ },
+ {
+ .procname = "yield_type",
+ .data = &sched_yield_type,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_TWO,
+ },
+#ifdef CONFIG_SCHEDSTATS
+ {
+ .procname = "sched_schedstats",
+ .data = NULL,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = sysctl_schedstats,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
+#endif
+};
+
+static int __init muqss_sysctl_init(void)
+{
+ register_sysctl_init("kernel", muqss_sysctls);
+ return 0;
+}
+late_initcall(muqss_sysctl_init);
+#endif /* CONFIG_SYSCTL */
+
+static void update_cpu_clock_switch(struct rq *rq, struct task_struct *p);
+
+static void account_task_cpu(struct rq *rq, struct task_struct *p)
+{
+ update_clocks(rq);
+ /* This isn't really a context switch but accounting is the same */
+ update_cpu_clock_switch(rq, p);
+ p->last_ran = rq->niffies;
+}
+
+bool sched_smp_initialized __read_mostly;
+
+/*
+ * High-resolution timeslice expiry (MuQSS counterpart of mainline hrtick).
+ *
+ * Reprogramming a oneshot clockevent from set_rq_task() on every context
+ * switch under the rq lock races with the tick/timer softirq path on SMP
+ * and starves TIMER_SOFTIRQ (RCU "timer wakeup didn't happen"). Mirror
+ * mainline: HARD + LAZY_REARM setup, needs_rearm 5us threshold, and defer
+ * the actual start/cancel until hrexpiry_schedule_exit() after the pick.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+
+enum {
+ HREXPIRE_SCHED_NONE = 0,
+ HREXPIRE_SCHED_DEFER = BIT(1),
+ HREXPIRE_SCHED_START = BIT(2),
+ HREXPIRE_SCHED_REARM_HRTIMER = BIT(3),
+};
+
+static inline int hrexpiry_enabled(struct rq *rq)
+{
+ /*
+ * 5.12 used hrtimer_is_hres_active(); 7.1 exposes the same idea as
+ * hrtimer_resolution != LOW_RES_NSEC once highres has switched on.
+ */
+ return hrtimer_resolution != LOW_RES_NSEC;
+}
+
+static inline bool hrexpiry_needs_rearm(struct hrtimer *timer, ktime_t expires)
+{
+ /*
+ * Queued is false when not started or the callback is running. If
+ * already queued, only reprogram when the expiry moves substantially.
+ */
+ return !hrtimer_is_queued(timer) ||
+ abs(expires - hrtimer_get_expires(timer)) > 5000;
+}
+
+static void hrexpiry_cond_restart(struct rq *rq)
+{
+ struct hrtimer *timer = &rq->hrexpiry_timer;
+ ktime_t time = rq->hrexpiry_time;
+
+ if (hrexpiry_needs_rearm(timer, time))
+ hrtimer_start(timer, time, HRTIMER_MODE_ABS_PINNED_HARD);
+}
+
+/*
+ * Remote start IPI — wake_up_new_task may shorten a parent on another CPU.
+ * Runs hardirq/IPI context; take the rq lock like mainline __hrtick_start.
+ */
+static void __hrexpiry_start(void *arg)
+{
+ struct rq *rq = arg;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(rq->lock, flags);
+ hrexpiry_cond_restart(rq);
+ raw_spin_unlock_irqrestore(rq->lock, flags);
+}
+
+static inline void hrexpiry_clear(struct rq *rq)
+{
+ if (!hrexpiry_enabled(rq))
+ return;
+
+ /*
+ * Inside __schedule() only drop a pending deferred start; the actual
+ * cancel happens once in hrexpiry_schedule_exit().
+ */
+ if (rq->hrexpiry_sched) {
+ rq->hrexpiry_sched &= ~HREXPIRE_SCHED_START;
+ return;
+ }
+
+ hrtimer_try_to_cancel(&rq->hrexpiry_timer);
+}
+
+/*
+ * High-resolution time_slice expiry.
+ * Runs from hardirq context with interrupts disabled.
+ */
+static enum hrtimer_restart hrexpiry(struct hrtimer *timer)
+{
+ struct rq *rq = container_of(timer, struct rq, hrexpiry_timer);
+ struct task_struct *p;
+
+ /* This can happen during CPU hotplug / resume */
+ if (unlikely(cpu_of(rq) != smp_processor_id()))
+ goto out;
+
+ /*
+ * Local CPU only; no rq lock. Force a reschedule when the slice
+ * expires — __schedule() will pick the next deadline task.
+ */
+ p = rq->curr;
+ p->time_slice = 0;
+ __set_tsk_resched(p);
+out:
+ return HRTIMER_NORESTART;
+}
+
+/*
+ * Called with irqs disabled under the rq lock (set_rq_task / fork path).
+ * May target a remote rq — then arm via CSD like mainline hrtick_start.
+ */
+static void hrexpiry_start(struct rq *rq, u64 delay)
+{
+ s64 delta;
+
+ if (!hrexpiry_enabled(rq))
+ return;
+
+ /* Slices < 10us are not useful and can DoS the timer subsystem. */
+ delta = max_t(s64, delay, 10000LL);
+
+ /*
+ * Mid-schedule: note the delay and let hrexpiry_schedule_exit()
+ * program the clockevent once.
+ */
+ if (rq->hrexpiry_sched) {
+ rq->hrexpiry_sched |= HREXPIRE_SCHED_START;
+ rq->hrexpiry_delay = delta;
+ return;
+ }
+
+ rq->hrexpiry_time = ktime_add_ns(ktime_get(), delta);
+ if (!hrexpiry_needs_rearm(&rq->hrexpiry_timer, rq->hrexpiry_time))
+ return;
+
+ if (rq == this_rq())
+ hrtimer_start(&rq->hrexpiry_timer, rq->hrexpiry_time,
+ HRTIMER_MODE_ABS_PINNED_HARD);
+ else
+ smp_call_function_single_async(cpu_of(rq), &rq->hrexpiry_csd);
+}
+
+static inline void hrexpiry_schedule_enter(struct rq *rq)
+{
+ rq->hrexpiry_sched = HREXPIRE_SCHED_DEFER;
+ if (hrtimer_test_and_clear_rearm_deferred())
+ rq->hrexpiry_sched |= HREXPIRE_SCHED_REARM_HRTIMER;
+}
+
+static inline void hrexpiry_schedule_exit(struct rq *rq)
+{
+ if (rq->hrexpiry_sched & HREXPIRE_SCHED_START) {
+ rq->hrexpiry_time = ktime_add_ns(ktime_get(), rq->hrexpiry_delay);
+ hrexpiry_cond_restart(rq);
+ } else if (rq->curr == rq->idle || rq->curr->policy == SCHED_FIFO) {
+ /*
+ * No slice timer needed. Local CPU, IRQs off: the HARD
+ * callback cannot be running, so cancel is safe.
+ */
+ if (hrtimer_is_queued(&rq->hrexpiry_timer))
+ hrtimer_cancel(&rq->hrexpiry_timer);
+ }
+
+ if (rq->hrexpiry_sched & HREXPIRE_SCHED_REARM_HRTIMER)
+ __hrtimer_rearm_deferred();
+
+ rq->hrexpiry_sched = HREXPIRE_SCHED_NONE;
+}
+
+static void init_rq_hrexpiry(struct rq *rq)
+{
+ INIT_CSD(&rq->hrexpiry_csd, __hrexpiry_start, rq);
+ rq->hrexpiry_sched = HREXPIRE_SCHED_NONE;
+ hrtimer_setup(&rq->hrexpiry_timer, hrexpiry, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_HARD | HRTIMER_MODE_LAZY_REARM);
+}
+
+#else /* !CONFIG_HIGH_RES_TIMERS */
+
+static inline int hrexpiry_enabled(struct rq *rq)
+{
+ return 0;
+}
+static inline void hrexpiry_clear(struct rq *rq) { }
+static inline void hrexpiry_start(struct rq *rq, u64 delay) { }
+static inline void hrexpiry_schedule_enter(struct rq *rq) { }
+static inline void hrexpiry_schedule_exit(struct rq *rq) { }
+static inline void init_rq_hrexpiry(struct rq *rq) { }
+
+#endif /* CONFIG_HIGH_RES_TIMERS */
+
+static inline int rq_dither(struct rq *rq)
+{
+ if (!hrexpiry_enabled(rq))
+ return HALF_JIFFY_US;
+ return 0;
+}
+
+/*
+ * wake_up_new_task - wake up a newly created task for the first time.
+ *
+ * This function will do some initial scheduler statistics housekeeping
+ * that must be done for every newly created context, then puts the task
+ * on the runqueue and wakes it.
+ */
+void wake_up_new_task(struct task_struct *p)
+{
+ struct task_struct *parent, *rq_curr;
+ struct rq *rq, *new_rq;
+ unsigned long flags;
+
+ parent = p->parent;
+
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
+ p->__state = TASK_RUNNING;
+ /* Task_rq can't change yet on a new task */
+ new_rq = rq = task_rq(p);
+ if (unlikely(needs_other_cpu(p, task_cpu(p)))) {
+ set_task_cpu(p, valid_task_cpu(p));
+ new_rq = task_rq(p);
+ }
+
+ double_rq_lock(rq, new_rq);
+ rq_curr = rq->curr;
+
+ /*
+ * Make sure we do not leak PI boosting priority to the child.
+ */
+ p->prio = rq_curr->normal_prio;
+
+ trace_sched_wakeup_new(p);
+
+ /*
+ * Share the timeslice between parent and child, thus the
+ * total amount of pending timeslices in the system doesn't change,
+ * resulting in more scheduling fairness. If it's negative, it won't
+ * matter since that's the same as being 0. rq->rq_deadline is only
+ * modified within schedule() so it is always equal to
+ * current->deadline.
+ */
+ account_task_cpu(rq, rq_curr);
+ p->last_ran = rq_curr->last_ran;
+ if (likely(rq_curr->policy != SCHED_FIFO)) {
+ rq_curr->time_slice /= 2;
+ if (rq_curr->time_slice < RESCHED_US) {
+ /*
+ * Forking task has run out of timeslice. Reschedule it and
+ * start its child with a new time slice and deadline. The
+ * child will end up running first because its deadline will
+ * be slightly earlier.
+ */
+ __set_tsk_resched(rq_curr);
+ time_slice_expired(p, new_rq);
+ if (suitable_idle_cpus(p))
+ resched_best_idle(p, task_cpu(p));
+ else if (unlikely(rq != new_rq))
+ try_preempt(p, new_rq);
+ } else {
+ p->time_slice = rq_curr->time_slice;
+ if (rq_curr == parent && rq == new_rq && !suitable_idle_cpus(p)) {
+ /*
+ * The VM isn't cloned, so we're in a good position to
+ * do child-runs-first in anticipation of an exec. This
+ * usually avoids a lot of COW overhead.
+ */
+ __set_tsk_resched(rq_curr);
+ } else {
+ /*
+ * Adjust the hrexpiry since rq_curr will keep
+ * running and its timeslice has been shortened.
+ */
+ hrexpiry_start(rq, US_TO_NS(rq_curr->time_slice));
+ try_preempt(p, new_rq);
+ }
+ }
+ } else {
+ time_slice_expired(p, new_rq);
+ try_preempt(p, new_rq);
+ }
+ activate_task(new_rq, p, 0);
+ double_rq_unlock(rq, new_rq);
+ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+}
+
+#ifdef CONFIG_PREEMPT_NOTIFIERS
+
+static DEFINE_STATIC_KEY_FALSE(preempt_notifier_key);
+
+void preempt_notifier_inc(void)
+{
+ static_branch_inc(&preempt_notifier_key);
+}
+EXPORT_SYMBOL_GPL(preempt_notifier_inc);
+
+void preempt_notifier_dec(void)
+{
+ static_branch_dec(&preempt_notifier_key);
+}
+EXPORT_SYMBOL_GPL(preempt_notifier_dec);
+
+/**
+ * preempt_notifier_register - tell me when current is being preempted & rescheduled
+ * @notifier: notifier struct to register
+ */
+void preempt_notifier_register(struct preempt_notifier *notifier)
+{
+ if (!static_branch_unlikely(&preempt_notifier_key))
+ WARN(1, "registering preempt_notifier while notifiers disabled\n");
+
+ hlist_add_head(&notifier->link, &current->preempt_notifiers);
+}
+EXPORT_SYMBOL_GPL(preempt_notifier_register);
+
+/**
+ * preempt_notifier_unregister - no longer interested in preemption notifications
+ * @notifier: notifier struct to unregister
+ *
+ * This is *not* safe to call from within a preemption notifier.
+ */
+void preempt_notifier_unregister(struct preempt_notifier *notifier)
+{
+ hlist_del(&notifier->link);
+}
+EXPORT_SYMBOL_GPL(preempt_notifier_unregister);
+
+static void __fire_sched_in_preempt_notifiers(struct task_struct *curr)
+{
+ struct preempt_notifier *notifier;
+
+ hlist_for_each_entry(notifier, &curr->preempt_notifiers, link)
+ notifier->ops->sched_in(notifier, raw_smp_processor_id());
+}
+
+static __always_inline void fire_sched_in_preempt_notifiers(struct task_struct *curr)
+{
+ if (static_branch_unlikely(&preempt_notifier_key))
+ __fire_sched_in_preempt_notifiers(curr);
+}
+
+static void
+__fire_sched_out_preempt_notifiers(struct task_struct *curr,
+ struct task_struct *next)
+{
+ struct preempt_notifier *notifier;
+
+ hlist_for_each_entry(notifier, &curr->preempt_notifiers, link)
+ notifier->ops->sched_out(notifier, next);
+}
+
+static __always_inline void
+fire_sched_out_preempt_notifiers(struct task_struct *curr,
+ struct task_struct *next)
+{
+ if (static_branch_unlikely(&preempt_notifier_key))
+ __fire_sched_out_preempt_notifiers(curr, next);
+}
+
+#else /* !CONFIG_PREEMPT_NOTIFIERS */
+
+static inline void fire_sched_in_preempt_notifiers(struct task_struct *curr)
+{
+}
+
+static inline void
+fire_sched_out_preempt_notifiers(struct task_struct *curr,
+ struct task_struct *next)
+{
+}
+
+#endif /* CONFIG_PREEMPT_NOTIFIERS */
+
+static inline void prepare_task(struct task_struct *next)
+{
+ /*
+ * Claim the task as running, we do this before switching to it
+ * such that any running task will have this set.
+ *
+ * See the ttwu() WF_ON_CPU case and its ordering comment.
+ */
+ WRITE_ONCE(next->on_cpu, 1);
+}
+
+static inline void finish_task(struct task_struct *prev)
+{
+ /*
+ * This must be the very last reference to @prev from this CPU. After
+ * p->on_cpu is cleared, the task can be moved to a different CPU. We
+ * must ensure this doesn't happen until the switch is completely
+ * finished.
+ *
+ * In particular, the load of prev->__state in finish_task_switch() must
+ * happen before this.
+ *
+ * Pairs with the smp_cond_load_acquire() in try_to_wake_up() and
+ * __task_needs_rq_lock().
+ */
+ smp_store_release(&prev->on_cpu, 0);
+}
+
+static inline void
+prepare_lock_switch(struct rq *rq, struct task_struct *next)
+{
+ /*
+ * Since the runqueue lock will be released by the next
+ * task (which is an invalid locking op but in the case
+ * of the scheduler it's an obvious special-case), so we
+ * do an early lockdep release here:
+ */
+ spin_release(&rq->lock->dep_map, _THIS_IP_);
+#ifdef CONFIG_DEBUG_SPINLOCK
+ /* this is a valid case when another task releases the spinlock */
+ rq->lock->owner = next;
+#endif
+}
+
+static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
+{
+ /*
+ * If we are tracking spinlock dependencies then we have to
+ * fix up the runqueue lock - which gets 'carried over' from
+ * prev into current:
+ */
+ spin_acquire(&rq->lock->dep_map, 0, 0, _THIS_IP_);
+
+#ifdef CONFIG_SMP
+ /*
+ * If prev was marked as migrating to another CPU in return_task, drop
+ * the local runqueue lock but leave interrupts disabled and grab the
+ * remote lock we're migrating it to before enabling them.
+ */
+ if (unlikely(task_on_rq_migrating(prev))) {
+ unsigned int migrate;
+
+ /*
+ * Program/cancel hrexpiry on this CPU before dropping its
+ * rq lock; after the unlock `rq` may become the remote one.
+ */
+ hrexpiry_schedule_exit(rq);
+ sched_info_dequeue(rq, prev);
+ /*
+ * We move the ownership of prev to the new cpu now. Note that
+ * this does not lock ttwu out: pointing task_cpu() at wake_cpu
+ * below sends a concurrent ttwu_runnable() to the *new*
+ * runqueue's lock rather than the one dropped here, and
+ * __task_rq_lock() does not spin on task_on_rq_migrating() the
+ * way mainline's does. See the re-check before enqueueing.
+ *
+ * This bypasses set_task_cpu(), so any PSI state prev is still
+ * counted for has to be moved by hand, exactly as that does.
+ * psi_sched_switch() saw prev off the CPU as a sleep, since it
+ * is no longer queued, so a task in iowait is carrying
+ * TSK_IOWAIT here and enqueue_task() below would clear it on
+ * the new CPU that never counted it.
+ */
+ migrate = psi_migrate_begin(prev);
+ task_thread_info(prev)->cpu = prev->wake_cpu;
+ psi_migrate_end(prev, migrate);
+ raw_spin_unlock(rq->lock);
+
+ raw_spin_lock(&prev->pi_lock);
+ rq = __task_rq_lock(prev, NULL);
+ /*
+ * Complete the handover only while it is still ours to
+ * complete. ttwu() reaches prev here despite the comment
+ * above: ttwu_runnable() only accepts TASK_ON_RQ_QUEUED, so a
+ * wakeup that finds prev still TASK_ON_RQ_MIGRATING falls
+ * through it and enqueues prev itself. Once it has, prev can be
+ * picked and run on another CPU, and take_task() empties its
+ * skiplist node again.
+ *
+ * task_queued() only asks whether that node is linked, so at
+ * that point it reads "prev still needs enqueueing" when it
+ * means "prev is running elsewhere", and puts a task that is on
+ * a CPU back on a runqueue for a second CPU to pick up. One
+ * task then runs on two CPUs off one stack, which shows up
+ * downstream as skiplist corruption, PSI counting the task
+ * twice, and a scribbled kernel stack.
+ *
+ * on_rq is what actually tracks the handover - return_task()
+ * set TASK_ON_RQ_MIGRATING and whoever takes prev over clears
+ * it - and pi_lock, held here and taken by ttwu() before it
+ * does anything, serialises the two.
+ */
+ if (likely(task_on_rq_migrating(prev))) {
+ enqueue_task(rq, prev, 0);
+ prev->on_rq = TASK_ON_RQ_QUEUED;
+ /* Wake up the CPU if it's not already running */
+ resched_if_idle(rq);
+ }
+ raw_spin_unlock(&prev->pi_lock);
+ raw_spin_unlock_irq(rq->lock);
+ return;
+ }
+#endif
+ hrexpiry_schedule_exit(rq);
+ raw_spin_unlock_irq(rq->lock);
+}
+
+#ifndef prepare_arch_switch
+# define prepare_arch_switch(next) do { } while (0)
+#endif
+#ifndef finish_arch_switch
+# define finish_arch_switch(prev) do { } while (0)
+#endif
+#ifndef finish_arch_post_lock_switch
+# define finish_arch_post_lock_switch() do { } while (0)
+#endif
+
+static inline void kmap_local_sched_out(void)
+{
+#ifdef CONFIG_KMAP_LOCAL
+ if (unlikely(current->kmap_ctrl.idx))
+ __kmap_local_sched_out();
+#endif
+}
+
+static inline void kmap_local_sched_in(void)
+{
+#ifdef CONFIG_KMAP_LOCAL
+ if (unlikely(current->kmap_ctrl.idx))
+ __kmap_local_sched_in();
+#endif
+}
+
+/**
+ * prepare_task_switch - prepare to switch tasks
+ * @rq: the runqueue preparing to switch
+ * @next: the task we are going to switch to.
+ *
+ * This is called with the rq lock held and interrupts off. It must
+ * be paired with a subsequent finish_task_switch after the context
+ * switch.
+ *
+ * prepare_task_switch sets up locking and calls architecture specific
+ * hooks.
+ */
+static inline void
+prepare_task_switch(struct rq *rq, struct task_struct *prev,
+ struct task_struct *next)
+{
+ kcov_prepare_switch(prev);
+ sched_info_switch(rq, prev, next);
+ perf_event_task_sched_out(prev, next);
+ /*
+ * rseq_preempt(prev) became rseq_sched_switch_event(next): rseq is now
+ * told about the task being scheduled *in*.
+ */
+ rseq_sched_switch_event(next);
+ fire_sched_out_preempt_notifiers(prev, next);
+ kmap_local_sched_out();
+ prepare_task(next);
+ prepare_arch_switch(next);
+}
+
+/**
+ * finish_task_switch - clean up after a task-switch
+ * @rq: runqueue associated with task-switch
+ * @prev: the thread we just switched away from.
+ *
+ * finish_task_switch must be called after the context switch, paired
+ * with a prepare_task_switch call before the context switch.
+ * finish_task_switch will reconcile locking set up by prepare_task_switch,
+ * and do any other architecture-specific cleanup actions.
+ *
+ * Note that we may have delayed dropping an mm in context_switch(). If
+ * so, we finish that here outside of the runqueue lock. (Doing it
+ * with the lock held can cause deadlocks; see schedule() for
+ * details.)
+ *
+ * The context switch have flipped the stack from under us and restored the
+ * local variables which were saved when this task called schedule() in the
+ * past. prev == current is still correct but we need to recalculate this_rq
+ * because prev may have moved to another CPU.
+ */
+static void finish_task_switch(struct task_struct *prev)
+ __releases(rq->lock)
+{
+ struct rq *rq = this_rq();
+ struct mm_struct *mm = rq->prev_mm;
+ long prev_state;
+
+ /*
+ * The previous task will have left us with a preempt_count of 2
+ * because it left us after:
+ *
+ * schedule()
+ * preempt_disable(); // 1
+ * __schedule()
+ * raw_spin_lock_irq(rq->lock) // 2
+ *
+ * Also, see FORK_PREEMPT_COUNT.
+ */
+ if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
+ "corrupted preempt_count: %s/%d/0x%x\n",
+ current->comm, current->pid, preempt_count()))
+ preempt_count_set(FORK_PREEMPT_COUNT);
+
+ rq->prev_mm = NULL;
+
+ /*
+ * A task struct has one reference for the use as "current".
+ * If a task dies, then it sets TASK_DEAD in tsk->__state and calls
+ * schedule one last time. The schedule call will never return, and
+ * the scheduled task must drop that reference.
+ *
+ * We must observe prev->__state before clearing prev->on_cpu (in
+ * finish_task), otherwise a concurrent wakeup can get prev
+ * running on another CPU and we could rave with its RUNNING -> DEAD
+ * transition, resulting in a double drop.
+ */
+ prev_state = prev->__state;
+ vtime_task_switch(prev);
+ perf_event_task_sched_in(prev, current);
+ finish_task(prev);
+ finish_lock_switch(rq, prev);
+ finish_arch_post_lock_switch();
+ kcov_finish_switch(current);
+ /*
+ * kmap_local_sched_out() is invoked with rq::lock held and
+ * interrupts disabled. There is no requirement for that, but the
+ * sched out code does not have an interrupt enabled section.
+ * Restoring the maps on sched in does not require interrupts being
+ * disabled either.
+ */
+ kmap_local_sched_in();
+
+ /*
+ * Any cached block-layer timestamp (plug->cur_ktime) is stale now,
+ * invalidate it.
+ */
+ blk_plug_invalidate_ts();
+
+ fire_sched_in_preempt_notifiers(current);
+ /*
+ * When switching through a kernel thread, the loop in
+ * membarrier_{private,global}_expedited() may have observed that
+ * kernel thread and not issued an IPI. It is therefore possible to
+ * schedule between user->kernel->user threads without passing though
+ * switch_mm(). Membarrier requires a barrier after storing to
+ * rq->curr, before returning to userspace, so provide them here:
+ *
+ * - a full memory barrier for {PRIVATE,GLOBAL}_EXPEDITED, implicitly
+ * provided by mmdrop_lazy_tlb(),
+ * - a sync_core for SYNC_CORE.
+ */
+ if (mm) {
+ membarrier_mm_sync_core_before_usermode(mm);
+ mmdrop_lazy_tlb_sched(mm);
+ }
+ if (unlikely(prev_state == TASK_DEAD)) {
+ /*
+ * Remove function-return probe instances associated with this
+ * task and put them back on the free list.
+ */
+ kprobe_flush_task(prev);
+
+ /*
+ * Unlink from css_set after the final switch so rmdir can
+ * complete. Must precede put_task_struct_rcu_user().
+ */
+ cgroup_task_dead(prev);
+
+ /* Task is done with its stack. */
+ put_task_stack(prev);
+
+ put_task_struct_rcu_user(prev);
+ }
+}
+
+/**
+ * schedule_tail - first thing a freshly forked thread must call.
+ * @prev: the thread we just switched away from.
+ */
+asmlinkage __visible void schedule_tail(struct task_struct *prev)
+{
+ /*
+ * New tasks start with FORK_PREEMPT_COUNT, see there and
+ * finish_task_switch() for details.
+ *
+ * finish_task_switch() will drop rq->lock() and lower preempt_count
+ * and the preempt_enable() will end up enabling preemption (on
+ * PREEMPT_COUNT kernels).
+ */
+
+ finish_task_switch(prev);
+ preempt_enable();
+
+ if (current->set_child_tid)
+ put_user(task_pid_vnr(current), current->set_child_tid);
+
+ calculate_sigpending();
+}
+
+/*
+ * context_switch - switch to the new MM and the new thread's register state.
+ */
+static __always_inline void
+context_switch(struct rq *rq, struct task_struct *prev,
+ struct task_struct *next)
+{
+ prepare_task_switch(rq, prev, next);
+
+ /*
+ * For paravirt, this is coupled with an exit in switch_to to
+ * combine the page table reload and the switch backend into
+ * one hypercall.
+ */
+ arch_start_context_switch(prev);
+
+ /*
+ * kernel -> kernel lazy + transfer active
+ * user -> kernel lazy + mmgrab_lazy_tlb() active
+ *
+ * kernel -> user switch + mmdrop_lazy_tlb() active
+ * user -> user switch
+ */
+ if (!next->mm) { // to kernel
+ enter_lazy_tlb(prev->active_mm, next);
+
+ next->active_mm = prev->active_mm;
+ if (prev->mm) // from user
+ mmgrab_lazy_tlb(prev->active_mm);
+ else
+ prev->active_mm = NULL;
+ } else { // to user
+ membarrier_switch_mm(rq, prev->active_mm, next->mm);
+ /*
+ * sys_membarrier() requires an smp_mb() between setting
+ * rq->curr / membarrier_switch_mm() and returning to userspace.
+ *
+ * The below provides this either through switch_mm(), or in
+ * case 'prev->active_mm == next->mm' through
+ * finish_task_switch()'s mmdrop_lazy_tlb().
+ */
+ switch_mm_irqs_off(prev->active_mm, next->mm, next);
+ lru_gen_use_mm(next->mm);
+
+ if (!prev->mm) { // from kernel
+ /* will mmdrop_lazy_tlb() in finish_task_switch(). */
+ rq->prev_mm = prev->active_mm;
+ prev->active_mm = NULL;
+ }
+ }
+ prepare_lock_switch(rq, next);
+
+ /* Here we just switch the register state and the stack. */
+ switch_to(prev, next, prev);
+ barrier();
+
+ finish_task_switch(prev);
+}
+
+/*
+ * nr_running, nr_uninterruptible and nr_context_switches:
+ *
+ * externally visible scheduler statistics: current number of runnable
+ * threads, total number of context switches performed since bootup.
+ */
+unsigned int nr_running(void)
+{
+ unsigned long i, sum = 0;
+
+ for_each_online_cpu(i)
+ sum += cpu_rq(i)->nr_running;
+
+ return sum;
+}
+
+static unsigned long nr_uninterruptible(void)
+{
+ unsigned long i, sum = 0;
+
+ for_each_online_cpu(i)
+ sum += cpu_rq(i)->nr_uninterruptible;
+
+ return sum;
+}
+
+/*
+ * Check if only the current task is running on the CPU.
+ *
+ * Caution: this function does not check that the caller has disabled
+ * preemption, thus the result might have a time-of-check-to-time-of-use
+ * race. The caller is responsible to use it correctly, for example:
+ *
+ * - from a non-preemptible section (of course)
+ *
+ * - from a thread that is bound to a single CPU
+ *
+ * - in a loop with very short iterations (e.g. a polling loop)
+ */
+bool single_task_running(void)
+{
+ if (rq_load(raw_rq()) == 1)
+ return true;
+ else
+ return false;
+}
+EXPORT_SYMBOL(single_task_running);
+
+unsigned long long nr_context_switches(void)
+{
+ int cpu;
+ unsigned long long sum = 0;
+
+ for_each_possible_cpu(cpu)
+ sum += cpu_rq(cpu)->nr_switches;
+
+ return sum;
+}
+
+/*
+ * Consumers of these two interfaces, like for example the cpufreq menu
+ * governor are using nonsensical data. Boosting frequency for a CPU that has
+ * IO-wait which might not even end up running the task when it does become
+ * runnable.
+ */
+
+unsigned int nr_iowait_cpu(int cpu)
+{
+ return atomic_read(&cpu_rq(cpu)->nr_iowait);
+}
+
+/*
+ * IO-wait accounting, and how it's mostly bollocks (on SMP).
+ *
+ * The idea behind IO-wait account is to account the idle time that we could
+ * have spend running if it were not for IO. That is, if we were to improve the
+ * storage performance, we'd have a proportional reduction in IO-wait time.
+ *
+ * This all works nicely on UP, where, when a task blocks on IO, we account
+ * idle time as IO-wait, because if the storage were faster, it could've been
+ * running and we'd not be idle.
+ *
+ * This has been extended to SMP, by doing the same for each CPU. This however
+ * is broken.
+ *
+ * Imagine for instance the case where two tasks block on one CPU, only the one
+ * CPU will have IO-wait accounted, while the other has regular idle. Even
+ * though, if the storage were faster, both could've ran at the same time,
+ * utilising both CPUs.
+ *
+ * This means, that when looking globally, the current IO-wait accounting on
+ * SMP is a lower bound, by reason of under accounting.
+ *
+ * Worse, since the numbers are provided per CPU, they are sometimes
+ * interpreted per CPU, and that is nonsensical. A blocked task isn't strictly
+ * associated with any one particular CPU, it can wake to another CPU than it
+ * blocked on. This means the per CPU IO-wait number is meaningless.
+ *
+ * Task CPU affinities can make all that even more 'interesting'.
+ */
+
+unsigned int nr_iowait(void)
+{
+ unsigned long cpu, sum = 0;
+
+ for_each_possible_cpu(cpu)
+ sum += nr_iowait_cpu(cpu);
+
+ return sum;
+}
+
+static unsigned long nr_active(void)
+{
+ return nr_running() + nr_uninterruptible();
+}
+
+/* Variables and functions for calc_load */
+static unsigned long calc_load_update;
+unsigned long avenrun[3];
+EXPORT_SYMBOL(avenrun);
+
+/**
+ * get_avenrun - get the load average array
+ * @loads: pointer to dest load array
+ * @offset: offset to add
+ * @shift: shift count to shift the result left
+ *
+ * These values are estimates at best, so no need for locking.
+ */
+void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
+{
+ loads[0] = (avenrun[0] + offset) << shift;
+ loads[1] = (avenrun[1] + offset) << shift;
+ loads[2] = (avenrun[2] + offset) << shift;
+}
+
+/*
+ * calc_load - update the avenrun load estimates every LOAD_FREQ seconds.
+ */
+void calc_global_load(void)
+{
+ long active;
+
+ if (time_before(jiffies, READ_ONCE(calc_load_update)))
+ return;
+ active = nr_active() * FIXED_1;
+
+ avenrun[0] = calc_load(avenrun[0], EXP_1, active);
+ avenrun[1] = calc_load(avenrun[1], EXP_5, active);
+ avenrun[2] = calc_load(avenrun[2], EXP_15, active);
+
+ calc_load_update = jiffies + LOAD_FREQ;
+}
+
+/**
+ * fixed_power_int - compute: x^n, in O(log n) time
+ *
+ * @x: base of the power
+ * @frac_bits: fractional bits of @x
+ * @n: power to raise @x to.
+ *
+ * By exploiting the relation between the definition of the natural power
+ * function: x^n := x*x*...*x (x multiplied by itself for n times), and
+ * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i,
+ * (where: n_i \elem {0, 1}, the binary vector representing n),
+ * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is
+ * of course trivially computable in O(log_2 n), the length of our binary
+ * vector.
+ */
+static unsigned long
+fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
+{
+ unsigned long result = 1UL << frac_bits;
+
+ if (n) {
+ for (;;) {
+ if (n & 1) {
+ result *= x;
+ result += 1UL << (frac_bits - 1);
+ result >>= frac_bits;
+ }
+ n >>= 1;
+ if (!n)
+ break;
+ x *= x;
+ x += 1UL << (frac_bits - 1);
+ x >>= frac_bits;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * a1 = a0 * e + a * (1 - e)
+ *
+ * a2 = a1 * e + a * (1 - e)
+ * = (a0 * e + a * (1 - e)) * e + a * (1 - e)
+ * = a0 * e^2 + a * (1 - e) * (1 + e)
+ *
+ * a3 = a2 * e + a * (1 - e)
+ * = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e)
+ * = a0 * e^3 + a * (1 - e) * (1 + e + e^2)
+ *
+ * ...
+ *
+ * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1]
+ * = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e)
+ * = a0 * e^n + a * (1 - e^n)
+ *
+ * [1] application of the geometric series:
+ *
+ * n 1 - x^(n+1)
+ * S_n := \Sum x^i = -------------
+ * i=0 1 - x
+ */
+unsigned long
+calc_load_n(unsigned long load, unsigned long exp,
+ unsigned long active, unsigned int n)
+{
+ return calc_load(load, fixed_power_int(exp, FSHIFT, n), active);
+}
+
+DEFINE_PER_CPU(struct kernel_stat, kstat);
+DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat) = {
+#ifdef CONFIG_NO_HZ_COMMON
+ .idle_sleeptime_seq = SEQCNT_ZERO(kernel_cpustat.idle_sleeptime_seq)
+#endif
+};
+
+EXPORT_PER_CPU_SYMBOL(kstat);
+EXPORT_PER_CPU_SYMBOL(kernel_cpustat);
+
+#ifdef CONFIG_PARAVIRT
+static inline u64 steal_ticks(u64 steal)
+{
+ if (unlikely(steal > NSEC_PER_SEC))
+ return div_u64(steal, TICK_NSEC);
+
+ return __iter_div_u64_rem(steal, TICK_NSEC, &steal);
+}
+#endif
+
+#ifndef nsecs_to_cputime
+# define nsecs_to_cputime(__nsecs) nsecs_to_jiffies(__nsecs)
+#endif
+
+/*
+ * On each tick, add the number of nanoseconds to the unbanked variables and
+ * once one tick's worth has accumulated, account it allowing for accurate
+ * sub-tick accounting and totals. Use the TICK_APPROX_NS to match the way we
+ * deduct nanoseconds.
+ */
+static void pc_idle_time(struct rq *rq, struct task_struct *idle, unsigned long ns)
+{
+ u64 *cpustat = kcpustat_this_cpu->cpustat;
+ unsigned long ticks;
+
+ if (atomic_read(&rq->nr_iowait) > 0) {
+ rq->iowait_ns += ns;
+ if (rq->iowait_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->iowait_ns);
+ cpustat[CPUTIME_IOWAIT] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->iowait_ns %= JIFFY_NS;
+ }
+ } else {
+ rq->idle_ns += ns;
+ if (rq->idle_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->idle_ns);
+ cpustat[CPUTIME_IDLE] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->idle_ns %= JIFFY_NS;
+ }
+ }
+ acct_update_integrals(idle);
+}
+
+static void pc_system_time(struct rq *rq, struct task_struct *p,
+ int hardirq_offset, unsigned long ns)
+{
+ u64 *cpustat = kcpustat_this_cpu->cpustat;
+ unsigned long ticks;
+
+ p->stime_ns += ns;
+ if (p->stime_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(p->stime_ns);
+ p->stime_ns %= JIFFY_NS;
+ p->stime += (__force u64)TICK_APPROX_NS * ticks;
+ account_group_system_time(p, TICK_APPROX_NS * ticks);
+ }
+ p->sched_time += ns;
+ account_group_exec_runtime(p, ns);
+
+ if (hardirq_count() - hardirq_offset) {
+ rq->irq_ns += ns;
+ if (rq->irq_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->irq_ns);
+ cpustat[CPUTIME_IRQ] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->irq_ns %= JIFFY_NS;
+ }
+ } else if (in_serving_softirq() || this_cpu_ksoftirqd() == p) {
+ /*
+ * ksoftirqd time does not get accounted in cpu_softirq_time, so
+ * it has to be handled separately here. Naming it explicitly
+ * also catches it between batches, where it has reenabled bh
+ * and in_serving_softirq() no longer holds - which is where the
+ * context switch that lands us here happens.
+ */
+ rq->softirq_ns += ns;
+ if (rq->softirq_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->softirq_ns);
+ cpustat[CPUTIME_SOFTIRQ] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->softirq_ns %= JIFFY_NS;
+ }
+ } else {
+ rq->system_ns += ns;
+ if (rq->system_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->system_ns);
+ cpustat[CPUTIME_SYSTEM] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->system_ns %= JIFFY_NS;
+ }
+ }
+ acct_update_integrals(p);
+}
+
+static void pc_user_time(struct rq *rq, struct task_struct *p, unsigned long ns)
+{
+ u64 *cpustat = kcpustat_this_cpu->cpustat;
+ unsigned long ticks;
+
+ p->utime_ns += ns;
+ if (p->utime_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(p->utime_ns);
+ p->utime_ns %= JIFFY_NS;
+ p->utime += (__force u64)TICK_APPROX_NS * ticks;
+ account_group_user_time(p, TICK_APPROX_NS * ticks);
+ }
+ p->sched_time += ns;
+ account_group_exec_runtime(p, ns);
+
+ if (task_nice(p) > 0 || idleprio_task(p)) {
+ rq->nice_ns += ns;
+ if (rq->nice_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->nice_ns);
+ cpustat[CPUTIME_NICE] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->nice_ns %= JIFFY_NS;
+ }
+ } else {
+ rq->user_ns += ns;
+ if (rq->user_ns >= JIFFY_NS) {
+ ticks = NS_TO_JIFFIES(rq->user_ns);
+ cpustat[CPUTIME_USER] += (__force u64)TICK_APPROX_NS * ticks;
+ rq->user_ns %= JIFFY_NS;
+ }
+ }
+ acct_update_integrals(p);
+}
+
+/*
+ * This is called on clock ticks.
+ * Bank in p->sched_time the ns elapsed since the last tick or switch.
+ * CPU scheduler quota accounting is also performed here in microseconds.
+ */
+static void update_cpu_clock_tick(struct rq *rq, struct task_struct *p)
+{
+ s64 account_ns = rq->niffies - p->last_ran;
+ struct task_struct *idle = rq->idle;
+
+ /* Accurate tick timekeeping */
+ if (user_mode(get_irq_regs()))
+ pc_user_time(rq, p, account_ns);
+ else if (p != idle || (irq_count() != HARDIRQ_OFFSET)) {
+ pc_system_time(rq, p, HARDIRQ_OFFSET, account_ns);
+ } else
+ pc_idle_time(rq, idle, account_ns);
+
+ /* time_slice accounting is done in usecs to avoid overflow on 32bit */
+ if (p->policy != SCHED_FIFO && p != idle)
+ p->time_slice -= NS_TO_US(account_ns);
+
+ p->last_ran = rq->niffies;
+}
+
+/*
+ * This is called on context switches.
+ * Bank in p->sched_time the ns elapsed since the last tick or switch.
+ * CPU scheduler quota accounting is also performed here in microseconds.
+ */
+static void update_cpu_clock_switch(struct rq *rq, struct task_struct *p)
+{
+ s64 account_ns = rq->niffies - p->last_ran;
+ struct task_struct *idle = rq->idle;
+
+ /*
+ * Accurate subtick timekeeping. There is no interrupt frame to sample
+ * here the way update_cpu_clock_tick() samples one: the entry code has
+ * already restored the previous value by the time irqentry_exit()
+ * reaches preempt_schedule_irq(), and a task that called schedule()
+ * itself never had a frame at all. What can be said for certain is that
+ * a task which never executes user code cannot have spent this interval
+ * in userspace, so charge all of those as system time. Without this the
+ * whole of every kernel thread's runtime that lands between two ticks
+ * is booked as user time, which is how irq threads, kworkers and
+ * ksoftirqd end up carrying utime they cannot possibly have accrued.
+ *
+ * A user task that blocks in a syscall genuinely does split its
+ * interval between the two modes, and knowing where it crossed over
+ * needs timestamped user/kernel transitions - vtime - that MuQSS
+ * deliberately does not take. Those keep the historical assumption.
+ */
+ if (p == idle)
+ pc_idle_time(rq, idle, account_ns);
+ else if (is_user_task(p))
+ pc_user_time(rq, p, account_ns);
+ else
+ pc_system_time(rq, p, 0, account_ns);
+
+ /* time_slice accounting is done in usecs to avoid overflow on 32bit */
+ if (p->policy != SCHED_FIFO && p != idle)
+ p->time_slice -= NS_TO_US(account_ns);
+}
+
+#ifdef CONFIG_MUQSS_IOTIME
+/*
+ * The CPU time current has consumed so far, for measuring how long a stretch
+ * of work took the thread doing it.
+ *
+ * ->sched_time alone is not enough. It is banked at ticks and at context
+ * switches, and a kworker's switches happen at the ends of a whole batch of
+ * work items, so the delta across any one of them is usually a flat zero. The
+ * unbanked remainder has to be added in, and that means reading a clock:
+ * sched_clock_cpu() rather than rq->niffies, which is only refreshed under
+ * the rq lock and would be stale by up to a tick here.
+ *
+ * niffies is monotonised forward of the raw clock, so last_ran can be ahead
+ * of what we read and the remainder can come out negative. Drop it in that
+ * case; it is bounded by the skew between the two and the banked figure is
+ * still right.
+ *
+ * Interrupts are off across the read so the tick cannot land between taking
+ * ->sched_time and taking ->last_ran and have the interval counted in both.
+ * That also pins us to this CPU, which is what makes the subtraction a
+ * same-clock one.
+ */
+u64 muqss_task_runtime_live(void)
+{
+ struct task_struct *p = current;
+ unsigned long flags;
+ s64 remainder;
+ u64 ns, ran;
+
+ local_irq_save(flags);
+ ns = p->sched_time;
+ ran = p->last_ran;
+ remainder = sched_clock_cpu(smp_processor_id()) - ran;
+ local_irq_restore(flags);
+
+ if (likely(remainder > 0))
+ ns += remainder;
+
+ return ns;
+}
+#endif
+
+/*
+ * Return any ns on the sched_clock that have not yet been accounted in
+ * @p in case that task is currently running.
+ *
+ * Called with task_rq_lock(p) held.
+ */
+static inline u64 do_task_delta_exec(struct task_struct *p, struct rq *rq)
+{
+ u64 ns = 0;
+
+ /*
+ * Must be ->curr _and_ ->on_rq. If dequeued, we would
+ * project cycles that may never be accounted to this
+ * thread, breaking clock_gettime().
+ */
+ if (p == rq->curr && task_on_rq_queued(p)) {
+ update_clocks(rq);
+ ns = rq->niffies - p->last_ran;
+ }
+
+ return ns;
+}
+
+/*
+ * Return accounted runtime for the task.
+ * Return separately the current's pending runtime that have not been
+ * accounted yet.
+ */
+unsigned long long task_sched_runtime(struct task_struct *p)
+{
+ struct rq_flags rf;
+ struct rq *rq;
+ u64 ns;
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+ /*
+ * 64-bit doesn't need locks to atomically read a 64-bit value.
+ * So we have a optimisation chance when the task's delta_exec is 0.
+ * Reading ->on_cpu is racy, but this is ok.
+ *
+ * If we race with it leaving CPU, we'll take a lock. So we're correct.
+ * If we race with it entering CPU, unaccounted time is 0. This is
+ * indistinguishable from the read occurring a few cycles earlier.
+ * If we see ->on_cpu without ->on_rq, the task is leaving, and has
+ * been accounted, so we're correct here as well.
+ */
+ if (!p->on_cpu || !task_on_rq_queued(p))
+ return tsk_seruntime(p);
+#endif
+
+ rq = task_rq_lock(p, &rf);
+ ns = p->sched_time + do_task_delta_exec(p, rq);
+ task_rq_unlock(rq, p, &rf);
+
+ return ns;
+}
+
+/*
+ * Functions to test for when SCHED_ISO tasks have used their allocated
+ * quota as real time scheduling and convert them back to SCHED_NORMAL. All
+ * data is modified only by the local runqueue during sched_tick with
+ * interrupts disabled.
+ */
+
+/*
+ * Test if SCHED_ISO tasks have run longer than their alloted period as RT
+ * tasks and set the refractory flag if necessary. There is 10% hysteresis
+ * for unsetting the flag. 115/128 is ~90/100 as a fast shift instead of a
+ * slow division.
+ */
+static inline void iso_tick(struct rq *rq)
+{
+ rq->iso_ticks = rq->iso_ticks * (ISO_PERIOD - 1) / ISO_PERIOD;
+ rq->iso_ticks += 100;
+ if (rq->iso_ticks > ISO_PERIOD * sched_iso_cpu) {
+ rq->iso_refractory = true;
+ if (unlikely(rq->iso_ticks > ISO_PERIOD * 100))
+ rq->iso_ticks = ISO_PERIOD * 100;
+ }
+}
+
+/* No SCHED_ISO task was running so decrease rq->iso_ticks */
+static inline void no_iso_tick(struct rq *rq, int ticks)
+{
+ if (rq->iso_ticks > 0 || rq->iso_refractory) {
+ rq->iso_ticks = rq->iso_ticks * (ISO_PERIOD - ticks) / ISO_PERIOD;
+ if (rq->iso_ticks < ISO_PERIOD * (sched_iso_cpu * 115 / 128)) {
+ rq->iso_refractory = false;
+ if (unlikely(rq->iso_ticks < 0))
+ rq->iso_ticks = 0;
+ }
+ }
+}
+
+/* This manages tasks that have run out of timeslice during a sched_tick */
+static void task_running_tick(struct rq *rq)
+{
+ struct task_struct *p = rq->curr;
+
+ /*
+ * If a SCHED_ISO task is running we increment the iso_ticks. In
+ * order to prevent SCHED_ISO tasks from causing starvation in the
+ * presence of true RT tasks we account those as iso_ticks as well.
+ */
+ if (rt_task(p) || task_running_iso(p))
+ iso_tick(rq);
+ else
+ no_iso_tick(rq, 1);
+
+ /* SCHED_FIFO tasks never run out of timeslice. */
+ if (p->policy == SCHED_FIFO)
+ return;
+
+ if (iso_task(p)) {
+ if (task_running_iso(p)) {
+ if (rq->iso_refractory) {
+ /*
+ * SCHED_ISO task is running as RT and limit
+ * has been hit. Force it to reschedule as
+ * SCHED_NORMAL by zeroing its time_slice
+ */
+ p->time_slice = 0;
+ }
+ } else if (!rq->iso_refractory) {
+ /* Can now run again ISO. Reschedule to pick up prio */
+ goto out_resched;
+ }
+ }
+
+ /*
+ * Tasks that were scheduled in the first half of a tick are not
+ * allowed to run into the 2nd half of the next tick if they will
+ * run out of time slice in the interim. Otherwise, if they have
+ * less than RESCHED_US μs of time slice left they will be rescheduled.
+ * Dither is used as a backup for when hrexpiry is disabled or high res
+ * timers not configured in.
+ */
+ if (p->time_slice - rq->dither >= RESCHED_US)
+ return;
+out_resched:
+ rq_lock(rq);
+ __set_tsk_resched(p);
+ rq_unlock(rq);
+}
+
+static inline void task_tick(struct rq *rq)
+{
+ if (!rq_idle(rq))
+ task_running_tick(rq);
+ else if (rq->last_jiffy > rq->last_scheduler_tick)
+ no_iso_tick(rq, rq->last_jiffy - rq->last_scheduler_tick);
+}
+
+#ifdef CONFIG_NO_HZ_FULL
+/*
+ * We can stop the timer tick any time highres timers are active since
+ * we rely entirely on highres timeouts for task expiry rescheduling.
+ */
+static void sched_stop_tick(struct rq *rq, int cpu)
+{
+ if (!hrexpiry_enabled(rq))
+ return;
+ if (!tick_nohz_full_enabled())
+ return;
+ if (!tick_nohz_full_cpu(cpu))
+ return;
+ tick_nohz_dep_clear_cpu(cpu, TICK_DEP_BIT_SCHED);
+}
+
+static inline void sched_start_tick(struct rq *rq, int cpu)
+{
+ tick_nohz_dep_set_cpu(cpu, TICK_DEP_BIT_SCHED);
+}
+
+struct tick_work {
+ int cpu;
+ atomic_t state;
+ struct delayed_work work;
+};
+/* Values for ->state, see diagram below. */
+#define TICK_SCHED_REMOTE_OFFLINE 0
+#define TICK_SCHED_REMOTE_OFFLINING 1
+#define TICK_SCHED_REMOTE_RUNNING 2
+
+/*
+ * State diagram for ->state:
+ *
+ *
+ * TICK_SCHED_REMOTE_OFFLINE
+ * | ^
+ * | |
+ * | | sched_tick_remote()
+ * | |
+ * | |
+ * +--TICK_SCHED_REMOTE_OFFLINING
+ * | ^
+ * | |
+ * sched_tick_start() | | sched_tick_stop()
+ * | |
+ * V |
+ * TICK_SCHED_REMOTE_RUNNING
+ *
+ *
+ * Other transitions get WARN_ON_ONCE(), except that sched_tick_remote()
+ * and sched_tick_start() are happy to leave the state in RUNNING.
+ */
+
+static struct tick_work __percpu *tick_work_cpu;
+
+static void sched_tick_remote(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct tick_work *twork = container_of(dwork, struct tick_work, work);
+ int cpu = twork->cpu;
+ struct rq *rq = cpu_rq(cpu);
+ struct task_struct *curr;
+ u64 delta;
+ int os;
+
+ /*
+ * Handle the tick only if it appears the remote CPU is running in full
+ * dynticks mode. The check is racy by nature, but missing a tick or
+ * having one too much is no big deal because the scheduler tick updates
+ * statistics and checks timeslices in a time-independent way, regardless
+ * of when exactly it is running.
+ */
+ if (!tick_nohz_tick_stopped_cpu(cpu))
+ goto out_requeue;
+
+ rq_lock_irq(rq);
+ if (cpu_is_offline(cpu))
+ goto out_unlock;
+
+ curr = rq->curr;
+ update_rq_clock(rq);
+
+ if (!is_idle_task(curr)) {
+ /*
+ * Make sure the next tick runs within a reasonable
+ * amount of time.
+ */
+ delta = rq_clock_task(rq) - curr->last_ran;
+ WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 3);
+ }
+ /*
+ * task_tick() takes the rq lock itself when it needs to force a
+ * reschedule so we must drop it here, keeping interrupts disabled
+ * to match the context it is called in from sched_tick().
+ */
+ rq_unlock(rq);
+ task_tick(rq);
+ local_irq_enable();
+ goto out_requeue;
+
+out_unlock:
+ rq_unlock_irq(rq, NULL);
+
+out_requeue:
+
+ /*
+ * Run the remote tick once per second (1Hz). This arbitrary
+ * frequency is large enough to avoid overload but short enough
+ * to keep scheduler internal stats reasonably up to date. But
+ * first update state to reflect hotplug activity if required.
+ */
+ os = atomic_fetch_add_unless(&twork->state, -1, TICK_SCHED_REMOTE_RUNNING);
+ WARN_ON_ONCE(os == TICK_SCHED_REMOTE_OFFLINE);
+ if (os == TICK_SCHED_REMOTE_RUNNING)
+ queue_delayed_work(system_unbound_wq, dwork, HZ);
+}
+
+static void sched_tick_start(int cpu)
+{
+ struct tick_work *twork;
+ int os;
+
+ if (housekeeping_cpu(cpu, HK_TYPE_TICK))
+ return;
+
+ WARN_ON_ONCE(!tick_work_cpu);
+
+ twork = per_cpu_ptr(tick_work_cpu, cpu);
+ os = atomic_xchg(&twork->state, TICK_SCHED_REMOTE_RUNNING);
+ WARN_ON_ONCE(os == TICK_SCHED_REMOTE_RUNNING);
+ if (os == TICK_SCHED_REMOTE_OFFLINE) {
+ twork->cpu = cpu;
+ INIT_DELAYED_WORK(&twork->work, sched_tick_remote);
+ queue_delayed_work(system_unbound_wq, &twork->work, HZ);
+ }
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void sched_tick_stop(int cpu)
+{
+ struct tick_work *twork;
+ int os;
+
+ if (housekeeping_cpu(cpu, HK_TYPE_TICK))
+ return;
+
+ WARN_ON_ONCE(!tick_work_cpu);
+
+ twork = per_cpu_ptr(tick_work_cpu, cpu);
+ /* There cannot be competing actions, but don't rely on stop-machine. */
+ os = atomic_xchg(&twork->state, TICK_SCHED_REMOTE_OFFLINING);
+ WARN_ON_ONCE(os != TICK_SCHED_REMOTE_RUNNING);
+ /* Don't cancel, as this would mess up the state machine. */
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+int __init sched_tick_offload_init(void)
+{
+ tick_work_cpu = alloc_percpu(struct tick_work);
+ BUG_ON(!tick_work_cpu);
+ return 0;
+}
+
+#else /* !CONFIG_NO_HZ_FULL */
+static inline void sched_stop_tick(struct rq *rq, int cpu) {}
+static inline void sched_start_tick(struct rq *rq, int cpu) {}
+static inline void sched_tick_start(int cpu) { }
+static inline void sched_tick_stop(int cpu) { }
+#endif
+
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void sched_tick(void)
+{
+ int cpu __maybe_unused = smp_processor_id();
+ struct rq *rq = cpu_rq(cpu);
+
+ arch_scale_freq_tick();
+ sched_clock_tick();
+ update_clocks(rq);
+ update_load_avg(rq, 0);
+ update_cpu_clock_tick(rq, rq->curr);
+ task_tick(rq);
+ rq->last_scheduler_tick = rq->last_jiffy;
+ rq->last_tick = rq->clock;
+ perf_event_task_tick();
+ sched_stop_tick(rq, cpu);
+}
+
+#if defined(CONFIG_PREEMPTION) && (defined(CONFIG_DEBUG_PREEMPT) || \
+ defined(CONFIG_TRACE_PREEMPT_TOGGLE))
+/*
+ * If the value passed in is equal to the current preempt count
+ * then we just disabled preemption. Start timing the latency.
+ */
+static inline void preempt_latency_start(int val)
+{
+ if (preempt_count() == val) {
+ unsigned long ip = get_lock_parent_ip();
+#ifdef CONFIG_DEBUG_PREEMPT
+ current->preempt_disable_ip = ip;
+#endif
+ trace_preempt_off(CALLER_ADDR0, ip);
+ }
+}
+
+void preempt_count_add(int val)
+{
+#ifdef CONFIG_DEBUG_PREEMPT
+ /*
+ * Underflow?
+ */
+ if (DEBUG_LOCKS_WARN_ON((preempt_count() < 0)))
+ return;
+#endif
+ __preempt_count_add(val);
+#ifdef CONFIG_DEBUG_PREEMPT
+ /*
+ * Spinlock count overflowing soon?
+ */
+ DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
+ PREEMPT_MASK - 10);
+#endif
+ preempt_latency_start(val);
+}
+EXPORT_SYMBOL(preempt_count_add);
+NOKPROBE_SYMBOL(preempt_count_add);
+
+/*
+ * If the value passed in equals to the current preempt count
+ * then we just enabled preemption. Stop timing the latency.
+ */
+static inline void preempt_latency_stop(int val)
+{
+ if (preempt_count() == val)
+ trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip());
+}
+
+void preempt_count_sub(int val)
+{
+#ifdef CONFIG_DEBUG_PREEMPT
+ /*
+ * Underflow?
+ */
+ if (DEBUG_LOCKS_WARN_ON(val > preempt_count()))
+ return;
+ /*
+ * Is the spinlock portion underflowing?
+ */
+ if (DEBUG_LOCKS_WARN_ON((val < PREEMPT_MASK) &&
+ !(preempt_count() & PREEMPT_MASK)))
+ return;
+#endif
+
+ preempt_latency_stop(val);
+ __preempt_count_sub(val);
+}
+EXPORT_SYMBOL(preempt_count_sub);
+NOKPROBE_SYMBOL(preempt_count_sub);
+
+#else
+static inline void preempt_latency_start(int val) { }
+static inline void preempt_latency_stop(int val) { }
+#endif
+
+static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
+{
+#ifdef CONFIG_DEBUG_PREEMPT
+ return p->preempt_disable_ip;
+#else
+ return 0;
+#endif
+}
+
+/*
+ * The time_slice is only refilled when it is empty and that is when we set a
+ * new deadline. Make sure update_clocks has been called recently to update
+ * rq->niffies.
+ */
+static void time_slice_expired(struct task_struct *p, struct rq *rq)
+{
+ p->time_slice = timeslice();
+ /*
+ * This assignment is absolute, so the charge has to be folded in here
+ * rather than left to enqueue_task(), or expiry would reset the task
+ * to an uncharged baseline.
+ */
+ p->deadline = rq->niffies + task_deadline_diff(p) +
+ consume_task_penalty(p);
+#ifdef CONFIG_SMT_NICE
+ if (!p->mm)
+ p->smt_bias = 0;
+ else if (rt_task(p))
+ p->smt_bias = 1 << 30;
+ else if (task_running_iso(p))
+ p->smt_bias = 1 << 29;
+ else if (idleprio_task(p)) {
+ if (task_running_idle(p))
+ p->smt_bias = 0;
+ else
+ p->smt_bias = 1;
+ } else if (--p->smt_bias < 1)
+ p->smt_bias = MAX_PRIO - p->static_prio;
+#endif
+}
+
+/*
+ * Timeslices below RESCHED_US are considered as good as expired as there's no
+ * point rescheduling when there's so little time left. SCHED_BATCH tasks
+ * have been flagged be not latency sensitive and likely to be fully CPU
+ * bound so every time they're rescheduled they have their time_slice
+ * refilled, but get a new later deadline to have little effect on
+ * SCHED_NORMAL tasks.
+
+ */
+static inline void check_deadline(struct task_struct *p, struct rq *rq)
+{
+ if (p->time_slice < RESCHED_US || batch_task(p))
+ time_slice_expired(p, rq);
+}
+
+/*
+ * Task selection with skiplists is a simple matter of picking off the first
+ * task in the sorted list, an O(1) operation. The lookup is amortised O(1)
+ * being bound to the number of processors.
+ *
+ * Runqueues are selectively locked based on their unlocked data and then
+ * unlocked if not needed. At most 3 locks will be held at any time and are
+ * released as soon as they're no longer needed. All balancing between CPUs
+ * is thus done here in an extremely simple first come best fit manner.
+ *
+ * This iterates over runqueues in cache locality order. In interactive mode
+ * it iterates over all CPUs and finds the task with the best key/deadline.
+ * In non-interactive mode it will only take a task if it's from the current
+ * runqueue or a runqueue with more tasks than the current one with a better
+ * key/deadline.
+ */
+#ifdef CONFIG_SMP
+static inline struct task_struct
+*earliest_deadline_task(struct rq *rq, int cpu, struct task_struct *idle)
+{
+ struct rq *locked = NULL, *chosen = NULL;
+ struct task_struct *edt = idle;
+ int i, best_entries = 0;
+ u64 best_key = ~0ULL;
+
+ for (i = 0; i < total_runqueues; i++) {
+ skiplist *sl = rq->sl_order[i];
+ struct rq *other_rq = NULL;
+ skiplist_node *next;
+ int entries;
+
+ entries = READ_ONCE(sl->entries);
+ /*
+ * Check for queued entres lockless first. The local runqueue
+ * is locked so entries will always be accurate.
+ */
+ if (!sched_interactive) {
+ /*
+ * Don't reschedule balance across nodes unless the CPU
+ * is idle. Non-interactive needs the rq: cpu is read
+ * before the entries filter.
+ */
+ other_rq = rq_order(rq, i);
+ if (edt != idle && rq->cpu_locality[other_rq->cpu] > LOCALITY_SMP)
+ break;
+ if (entries <= best_entries)
+ continue;
+ } else if (!entries)
+ continue;
+
+ /* if (i) implies other_rq != rq */
+ if (i) {
+ /* Check for best id queued lockless first */
+ if (READ_ONCE(sl->best_key) >= best_key)
+ continue;
+
+ other_rq = rq_order(rq, i);
+ if (unlikely(!trylock_rq(rq, other_rq)))
+ continue;
+
+ /* Need to reevaluate entries after locking */
+ entries = sl->entries;
+ if (unlikely(!entries)) {
+ unlock_rq(other_rq);
+ continue;
+ }
+ }
+
+ next = sl->header;
+ /*
+ * In interactive mode we check beyond the best entry on other
+ * runqueues if we can't get the best for smt or affinity
+ * reasons.
+ */
+ while ((next = next->next[0]) != sl->header) {
+ struct task_struct *p;
+ u64 key = next->key;
+
+ /* Reevaluate key after locking */
+ if (key >= best_key)
+ break;
+
+ p = container_of(next, struct task_struct, node);
+ if (!smt_schedule(p, rq)) {
+ if (i && !sched_interactive)
+ break;
+ continue;
+ }
+
+ if (sched_other_cpu(p, cpu)) {
+ if (sched_interactive || !i)
+ continue;
+ break;
+ }
+ /* Make sure affinity is ok */
+ if (i) {
+ /* From this point on p is the best so far */
+ if (locked)
+ unlock_rq(locked);
+ chosen = locked = other_rq;
+ }
+ best_entries = entries;
+ best_key = key;
+ edt = p;
+ break;
+ }
+ /* rq->preempting is a hint only as the state may have changed
+ * since it was set with the resched call but if we have met
+ * the condition we can break out here. */
+ if (edt == rq->preempting)
+ break;
+ if (i && other_rq != chosen)
+ unlock_rq(other_rq);
+ }
+
+ if (likely(edt != idle))
+ take_task(rq, cpu, edt);
+
+ if (locked)
+ unlock_rq(locked);
+
+ rq->preempting = NULL;
+
+ return edt;
+}
+#else /* CONFIG_SMP */
+static inline struct task_struct
+*earliest_deadline_task(struct rq *rq, int cpu, struct task_struct *idle)
+{
+ struct task_struct *edt;
+
+ if (unlikely(!rq->sl->entries))
+ return idle;
+ edt = container_of(rq->node->next[0], struct task_struct, node);
+ take_task(rq, cpu, edt);
+ return edt;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * Print scheduling while atomic bug:
+ */
+static noinline void __schedule_bug(struct task_struct *prev)
+{
+ /* Save this before calling printk(), since that will clobber it */
+ unsigned long preempt_disable_ip = get_preempt_disable_ip(current);
+
+ if (oops_in_progress)
+ return;
+
+ printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n",
+ prev->comm, prev->pid, preempt_count());
+
+ debug_show_held_locks(prev);
+ print_modules();
+ if (irqs_disabled())
+ print_irqtrace_events(prev);
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
+ && in_atomic_preempt_off()) {
+ pr_err("Preemption disabled at:");
+ print_ip_sym(KERN_ERR, preempt_disable_ip);
+ }
+ dump_stack();
+ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
+}
+
+/*
+ * Various schedule()-time debugging checks and statistics:
+ */
+static inline void schedule_debug(struct task_struct *prev, bool preempt)
+{
+#ifdef CONFIG_SCHED_STACK_END_CHECK
+ if (task_stack_end_corrupted(prev))
+ panic("corrupted stack end detected inside scheduler\n");
+
+ if (task_scs_end_corrupted(prev))
+ panic("corrupted shadow stack detected inside scheduler\n");
+#endif
+
+#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
+ if (!preempt && prev->__state && prev->non_block_count) {
+ printk(KERN_ERR "BUG: scheduling in a non-blocking section: %s/%d/%i\n",
+ prev->comm, prev->pid, prev->non_block_count);
+ dump_stack();
+ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
+ }
+#endif
+
+ if (unlikely(in_atomic_preempt_off())) {
+ __schedule_bug(prev);
+ preempt_count_set(PREEMPT_DISABLED);
+ }
+ rcu_sleep_check();
+ SCHED_WARN_ON(ct_state() == CT_STATE_USER);
+
+ profile_hit(SCHED_PROFILING, __builtin_return_address(0));
+
+ schedstat_inc(this_rq()->sched_count);
+}
+
+/*
+ * The currently running task's information is all stored in rq local data
+ * which is only modified by the local CPU.
+ */
+static inline void set_rq_task(struct rq *rq, struct task_struct *p)
+{
+ if (p == rq->idle || p->policy == SCHED_FIFO)
+ hrexpiry_clear(rq);
+ else
+ hrexpiry_start(rq, US_TO_NS(p->time_slice));
+ if (rq->clock - rq->last_tick > HALF_JIFFY_NS)
+ rq->dither = 0;
+ else
+ rq->dither = rq_dither(rq);
+
+ rq->rq_deadline = p->deadline;
+ rq->rq_prio = p->prio;
+#ifdef CONFIG_SMT_NICE
+ rq->rq_mm = p->mm;
+ rq->rq_smt_bias = p->smt_bias;
+#endif
+}
+
+#ifdef CONFIG_SMT_NICE
+static void check_no_siblings(struct rq __maybe_unused *this_rq) {}
+static void wake_no_siblings(struct rq __maybe_unused *this_rq) {}
+static void (*check_siblings)(struct rq *this_rq) = &check_no_siblings;
+static void (*wake_siblings)(struct rq *this_rq) = &wake_no_siblings;
+
+/* Iterate over smt siblings when we've scheduled a process on cpu and decide
+ * whether they should continue running or be descheduled. */
+static void check_smt_siblings(struct rq *this_rq)
+{
+ int other_cpu;
+
+ for_each_cpu(other_cpu, &this_rq->thread_mask) {
+ struct task_struct *p;
+ struct rq *rq;
+
+ rq = cpu_rq(other_cpu);
+ if (rq_idle(rq))
+ continue;
+ p = rq->curr;
+ if (!smt_schedule(p, this_rq))
+ resched_curr(rq);
+ }
+}
+
+static void wake_smt_siblings(struct rq *this_rq)
+{
+ int other_cpu;
+
+ for_each_cpu(other_cpu, &this_rq->thread_mask) {
+ struct rq *rq;
+
+ rq = cpu_rq(other_cpu);
+ if (rq_idle(rq))
+ resched_idle(rq);
+ }
+}
+#else
+static void check_siblings(struct rq __maybe_unused *this_rq) {}
+static void wake_siblings(struct rq __maybe_unused *this_rq) {}
+#endif
+
+/*
+ * schedule() is the main scheduler function.
+ *
+ * The main means of driving the scheduler and thus entering this function are:
+ *
+ * 1. Explicit blocking: mutex, semaphore, waitqueue, etc.
+ *
+ * 2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return
+ * paths. For example, see arch/x86/entry_64.S.
+ *
+ * To drive preemption between tasks, the scheduler sets the flag in timer
+ * interrupt handler sched_tick().
+ *
+ * 3. Wakeups don't really cause entry into schedule(). They add a
+ * task to the run-queue and that's it.
+ *
+ * Now, if the new task added to the run-queue preempts the current
+ * task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
+ * called on the nearest possible occasion:
+ *
+ * - If the kernel is preemptible (CONFIG_PREEMPTION=y):
+ *
+ * - in syscall or exception context, at the next outmost
+ * preempt_enable(). (this might be as soon as the wake_up()'s
+ * spin_unlock()!)
+ *
+ * - in IRQ context, return from interrupt-handler to
+ * preemptible context
+ *
+ * - If the kernel is not preemptible (CONFIG_PREEMPTION is not set)
+ * then at the next:
+ *
+ * - cond_resched() call
+ * - explicit schedule() call
+ * - return from syscall or exception to user-space
+ * - return from interrupt-handler to user-space
+ *
+ * WARNING: must be called with preemption disabled!
+ */
+#define SM_IDLE (-1)
+#define SM_NONE 0
+#define SM_PREEMPT 1
+#define SM_RTLOCK_WAIT 2
+
+static void __sched notrace __schedule(int sched_mode)
+{
+ struct task_struct *prev, *next, *idle;
+ unsigned long *switch_count;
+ unsigned long prev_state;
+ bool deactivate = false;
+ struct rq *rq;
+ u64 niffies;
+ int cpu;
+ /*
+ * On PREEMPT_RT, SM_RTLOCK_WAIT is noted as a preemption by
+ * schedule_debug() and RCU. Task-state changes still treat
+ * only SM_PREEMPT as preemption so a sleeping lock wait can
+ * deactivate.
+ */
+ bool preempt = sched_mode > SM_NONE;
+
+ cpu = smp_processor_id();
+ rq = cpu_rq(cpu);
+ prev = rq->curr;
+ idle = rq->idle;
+
+ schedule_debug(prev, preempt);
+
+ klp_sched_try_switch(prev);
+
+ local_irq_disable();
+ rcu_note_context_switch(preempt);
+
+ /*
+ * Make sure that signal_pending_state()->signal_pending() below
+ * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
+ * done by the caller to avoid the race with signal_wake_up():
+ *
+ * __set_current_state(@state) signal_wake_up()
+ * schedule() set_tsk_thread_flag(p, TIF_SIGPENDING)
+ * wake_up_state(p, state)
+ * LOCK rq->lock LOCK p->pi_state
+ * smp_mb__after_spinlock() smp_mb__after_spinlock()
+ * if (signal_pending_state()) if (p->__state & @state)
+ *
+ * Also, the membarrier system call requires a full memory barrier
+ * after coming from user-space, before storing to rq->curr.
+ */
+ rq_lock(rq);
+ smp_mb__after_spinlock();
+#ifdef CONFIG_SMP
+ if (rq->preempt) {
+ /*
+ * Make sure resched_curr hasn't triggered a preemption
+ * locklessly on a task that has since scheduled away. Spurious
+ * wakeup of idle is okay though.
+ */
+ if (unlikely(sched_mode == SM_PREEMPT && prev != idle &&
+ !test_tsk_need_resched(prev))) {
+ rq->preempt = NULL;
+ clear_preempt_need_resched();
+ rq_unlock_irq(rq, NULL);
+ return;
+ }
+ rq->preempt = NULL;
+ }
+ migrate_disable_switch(rq, prev);
+#endif
+
+ /*
+ * Defer hrexpiry start/cancel until we leave __schedule so we do not
+ * thrash the oneshot clockevent under the rq lock (mainline hrtick).
+ */
+ hrexpiry_schedule_enter(rq);
+
+ switch_count = &prev->nivcsw;
+
+ /* Task state changes only consider SM_PREEMPT as preemption */
+ preempt = sched_mode == SM_PREEMPT;
+
+ /*
+ * We must load prev->__state once (task_struct::state is volatile), such
+ * that:
+ *
+ * - we form a control dependency vs deactivate_task() below.
+ * - ptrace_{,un}freeze_traced() can change ->state underneath us.
+ */
+ prev_state = prev->__state;
+ if (!preempt && prev_state) {
+ if (signal_pending_state(prev_state, prev)) {
+ prev->__state = TASK_RUNNING;
+ } else {
+ prev->sched_contributes_to_load =
+ (prev_state & TASK_UNINTERRUPTIBLE) &&
+ !(prev_state & TASK_NOLOAD) &&
+ !(prev_state & TASK_FROZEN);
+
+ if (prev->sched_contributes_to_load)
+ rq->nr_uninterruptible++;
+
+ /*
+ * __schedule() ttwu()
+ * prev_state = prev->__state; if (p->on_rq && ...)
+ * if (prev_state) goto out;
+ * p->on_rq = 0; smp_acquire__after_ctrl_dep();
+ * p->__state = TASK_WAKING
+ *
+ * Where __schedule() and ttwu() have matching control dependencies.
+ *
+ * After this, schedule() must not care about p->__state any more.
+ */
+ deactivate = true;
+
+ if (prev->in_iowait) {
+ atomic_inc(&rq->nr_iowait);
+ delayacct_blkio_start();
+ }
+ }
+ switch_count = &prev->nvcsw;
+ }
+
+ /*
+ * Store the niffy value here for use by the next task's last_ran
+ * below to avoid losing niffies due to update_clocks being called
+ * again after this point.
+ */
+ update_clocks(rq);
+ niffies = rq->niffies;
+ update_cpu_clock_switch(rq, prev);
+
+ clear_tsk_need_resched(prev);
+ clear_preempt_need_resched();
+
+ if (idle != prev) {
+ check_deadline(prev, rq);
+ return_task(prev, rq, cpu, deactivate);
+ }
+
+ next = earliest_deadline_task(rq, cpu, idle);
+ if (likely(next->prio != PRIO_LIMIT))
+ clear_cpuidle_map(cpu);
+ else {
+#ifdef CONFIG_SMP
+ if (prev != idle)
+ rq->idle_jiffy = jiffies;
+#endif
+ set_cpuidle_map(cpu);
+ update_load_avg(rq, 0);
+ }
+
+ set_rq_task(rq, next);
+ next->last_ran = niffies;
+
+ if (likely(prev != next)) {
+ /*
+ * Don't reschedule an idle task or deactivated tasks
+ */
+ if (prev == idle)
+ inc_nr_running(rq);
+ else if (!deactivate)
+ resched_suitable_idle(prev);
+ /*
+ * The task on the CPU is not on the skiplist, so it holds a
+ * count of its own on top of the queued ones. nr_running only
+ * changes when that slot is created or destroyed - i.e. on the
+ * idle transitions above and below - but rt_nr_running also
+ * depends on *which* task holds it, so hand it over on every
+ * switch. Leaving that to the idle transitions leaked a count
+ * on every rt -> non-rt switch and underflowed on the reverse.
+ */
+ if (prev != idle && rt_task(prev))
+ rq->rt_nr_running--;
+ if (next != idle && rt_task(next))
+ rq->rt_nr_running++;
+ if (unlikely(next == idle)) {
+ dec_nr_running(rq);
+ wake_siblings(rq);
+ } else
+ check_siblings(rq);
+ rq->nr_switches++;
+ /*
+ * RCU users of rcu_dereference(rq->curr) may not see
+ * changes to task_struct made by pick_next_task().
+ */
+ RCU_INIT_POINTER(rq->curr, next);
+ /*
+ * The membarrier system call requires each architecture
+ * to have a full memory barrier after updating
+ * rq->curr, before returning to user-space.
+ *
+ * Here are the schemes providing that barrier on the
+ * various architectures:
+ * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC.
+ * switch_mm() rely on membarrier_arch_switch_mm() on PowerPC.
+ * - finish_lock_switch() for weakly-ordered
+ * architectures where spin_unlock is a full barrier,
+ * - switch_to() for arm64 (weakly-ordered, spin_unlock
+ * is a RELEASE barrier),
+ */
+ ++*switch_count;
+
+ psi_sched_switch(prev, next, !task_on_rq_queued(prev));
+
+ trace_sched_switch(preempt, prev, next, prev->__state);
+ context_switch(rq, prev, next); /* unlocks the rq via finish_lock_switch */
+ } else {
+ check_siblings(rq);
+ hrexpiry_schedule_exit(rq);
+ rq_unlock(rq);
+ local_irq_enable();
+ }
+}
+
+void __noreturn do_task_dead(void)
+{
+ /* Causes final put_task_struct in finish_task_switch(). */
+ set_special_state(TASK_DEAD);
+
+ /* Tell freezer to ignore us: */
+ current->flags |= PF_NOFREEZE;
+ __schedule(SM_NONE);
+ BUG();
+
+ /* Avoid "noreturn function does return" - but don't continue if BUG() is a NOP: */
+ for (;;)
+ cpu_relax();
+}
+
+static inline void sched_submit_work(struct task_struct *tsk)
+{
+ unsigned int task_flags;
+
+ if (!tsk->__state)
+ return;
+
+ task_flags = tsk->flags;
+ /*
+ * If a worker went to sleep, notify and ask workqueue whether
+ * it wants to wake up a task to maintain concurrency.
+ * As this function is called inside the schedule() context,
+ * we disable preemption to avoid it calling schedule() again
+ * in the possible wakeup of a kworker and because wq_worker_sleeping()
+ * requires it.
+ */
+ if (task_flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
+ preempt_disable();
+ if (task_flags & PF_WQ_WORKER)
+ wq_worker_sleeping(tsk);
+ else
+ io_wq_worker_sleeping(tsk);
+ preempt_enable_no_resched();
+ }
+
+ if (tsk->pi_blocked_on)
+ return;
+
+ /*
+ * If we are going to sleep and we have plugged IO queued,
+ * make sure to submit it to avoid deadlocks.
+ */
+ blk_flush_plug(tsk->plug, true);
+}
+
+static inline void sched_update_worker(struct task_struct *tsk)
+{
+ if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
+ if (tsk->flags & PF_WQ_WORKER)
+ wq_worker_running(tsk);
+ else
+ io_wq_worker_running(tsk);
+ }
+}
+
+static __always_inline void __schedule_loop(int sched_mode)
+{
+ do {
+ preempt_disable();
+ __schedule(sched_mode);
+ sched_preempt_enable_no_resched();
+ } while (need_resched());
+}
+
+asmlinkage __visible void __sched schedule(void)
+{
+ struct task_struct *tsk = current;
+
+#ifdef CONFIG_RT_MUTEXES
+ lockdep_assert(!tsk->sched_rt_mutex);
+#endif
+ sched_submit_work(tsk);
+ __schedule_loop(SM_NONE);
+ sched_update_worker(tsk);
+}
+
+EXPORT_SYMBOL(schedule);
+
+/*
+ * synchronize_rcu_tasks() makes sure that no task is stuck in preempted
+ * state (have scheduled out non-voluntarily) by making sure that all
+ * tasks have either left the run queue or have gone into user space.
+ * As idle tasks do not do either, they must not ever be preempted
+ * (schedule out non-voluntarily).
+ *
+ * schedule_idle() is similar to schedule_preempt_disable() except that it
+ * never enables preemption because it does not call sched_submit_work().
+ */
+void __sched schedule_idle(void)
+{
+ /*
+ * As this skips calling sched_submit_work(), which the idle task does
+ * regardless because that function is a nop when the task is in a
+ * TASK_RUNNING state, make sure this isn't used someplace that the
+ * current task can be in any other state. Note, idle is always in the
+ * TASK_RUNNING state.
+ */
+ WARN_ON_ONCE(current->__state);
+ do {
+ __schedule(SM_IDLE);
+ } while (need_resched());
+}
+
+#if defined(CONFIG_CONTEXT_TRACKING) && !defined(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK)
+asmlinkage __visible void __sched schedule_user(void)
+{
+ /*
+ * If we come here after a random call to set_need_resched(),
+ * or we have been woken up remotely but the IPI has not yet arrived,
+ * we haven't yet exited the RCU idle mode. Do it here manually until
+ * we find a better solution.
+ *
+ * NB: There are buggy callers of this function. Ideally we
+ * should warn if prev_state != IN_USER, but that will trigger
+ * too frequently to make sense yet.
+ */
+ enum ctx_state prev_state = exception_enter();
+ schedule();
+ exception_exit(prev_state);
+}
+#endif
+
+/**
+ * schedule_preempt_disabled - called with preemption disabled
+ *
+ * Returns with preemption disabled. Note: preempt_count must be 1
+ */
+void __sched schedule_preempt_disabled(void)
+{
+ sched_preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+}
+
+#ifdef CONFIG_PREEMPT_RT
+void __sched notrace schedule_rtlock(void)
+{
+ __schedule_loop(SM_RTLOCK_WAIT);
+}
+NOKPROBE_SYMBOL(schedule_rtlock);
+#endif
+
+static void __sched notrace preempt_schedule_common(void)
+{
+ do {
+ /*
+ * Because the function tracer can trace preempt_count_sub()
+ * and it also uses preempt_enable/disable_notrace(), if
+ * NEED_RESCHED is set, the preempt_enable_notrace() called
+ * by the function tracer will call this function again and
+ * cause infinite recursion.
+ *
+ * Preemption must be disabled here before the function
+ * tracer can trace. Break up preempt_disable() into two
+ * calls. One to disable preemption without fear of being
+ * traced. The other to still record the preemption latency,
+ * which can also be traced by the function tracer.
+ */
+ preempt_disable_notrace();
+ preempt_latency_start(1);
+ __schedule(SM_PREEMPT);
+ preempt_latency_stop(1);
+ preempt_enable_no_resched_notrace();
+
+ /*
+ * Check again in case we missed a preemption opportunity
+ * between schedule and now.
+ */
+ } while (need_resched());
+}
+
+#ifdef CONFIG_PREEMPTION
+/*
+ * This is the entry point to schedule() from in-kernel preemption
+ * off of preempt_enable.
+ */
+asmlinkage __visible void __sched notrace preempt_schedule(void)
+{
+ /*
+ * If there is a non-zero preempt_count or interrupts are disabled,
+ * we do not want to preempt the current task. Just return..
+ */
+ if (likely(!preemptible()))
+ return;
+
+ preempt_schedule_common();
+}
+NOKPROBE_SYMBOL(preempt_schedule);
+EXPORT_SYMBOL(preempt_schedule);
+
+#ifdef CONFIG_PREEMPT_DYNAMIC
+# ifdef CONFIG_HAVE_PREEMPT_DYNAMIC_CALL
+# ifndef preempt_schedule_dynamic_enabled
+# define preempt_schedule_dynamic_enabled preempt_schedule
+# define preempt_schedule_dynamic_disabled NULL
+# endif
+DEFINE_STATIC_CALL(preempt_schedule, preempt_schedule_dynamic_enabled);
+EXPORT_STATIC_CALL_TRAMP(preempt_schedule);
+# elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
+static DEFINE_STATIC_KEY_TRUE(sk_dynamic_preempt_schedule);
+void __sched notrace dynamic_preempt_schedule(void)
+{
+ if (!static_branch_unlikely(&sk_dynamic_preempt_schedule))
+ return;
+ preempt_schedule();
+}
+NOKPROBE_SYMBOL(dynamic_preempt_schedule);
+EXPORT_SYMBOL(dynamic_preempt_schedule);
+# endif
+#endif
+
+
+/**
+ * preempt_schedule_notrace - preempt_schedule called by tracing
+ *
+ * The tracing infrastructure uses preempt_enable_notrace to prevent
+ * recursion and tracing preempt enabling caused by the tracing
+ * infrastructure itself. But as tracing can happen in areas coming
+ * from userspace or just about to enter userspace, a preempt enable
+ * can occur before user_exit() is called. This will cause the scheduler
+ * to be called when the system is still in usermode.
+ *
+ * To prevent this, the preempt_enable_notrace will use this function
+ * instead of preempt_schedule() to exit user context if needed before
+ * calling the scheduler.
+ */
+asmlinkage __visible void __sched notrace preempt_schedule_notrace(void)
+{
+ enum ctx_state prev_ctx;
+
+ if (likely(!preemptible()))
+ return;
+
+ do {
+ /*
+ * Because the function tracer can trace preempt_count_sub()
+ * and it also uses preempt_enable/disable_notrace(), if
+ * NEED_RESCHED is set, the preempt_enable_notrace() called
+ * by the function tracer will call this function again and
+ * cause infinite recursion.
+ *
+ * Preemption must be disabled here before the function
+ * tracer can trace. Break up preempt_disable() into two
+ * calls. One to disable preemption without fear of being
+ * traced. The other to still record the preemption latency,
+ * which can also be traced by the function tracer.
+ */
+ preempt_disable_notrace();
+ preempt_latency_start(1);
+ /*
+ * Needs preempt disabled in case user_exit() is traced
+ * and the tracer calls preempt_enable_notrace() causing
+ * an infinite recursion.
+ */
+ prev_ctx = exception_enter();
+ __schedule(SM_PREEMPT);
+ exception_exit(prev_ctx);
+
+ preempt_latency_stop(1);
+ preempt_enable_no_resched_notrace();
+ } while (need_resched());
+}
+EXPORT_SYMBOL_GPL(preempt_schedule_notrace);
+
+#ifdef CONFIG_PREEMPT_DYNAMIC
+# if defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL)
+# ifndef preempt_schedule_notrace_dynamic_enabled
+# define preempt_schedule_notrace_dynamic_enabled preempt_schedule_notrace
+# define preempt_schedule_notrace_dynamic_disabled NULL
+# endif
+DEFINE_STATIC_CALL(preempt_schedule_notrace, preempt_schedule_notrace_dynamic_enabled);
+EXPORT_STATIC_CALL_TRAMP(preempt_schedule_notrace);
+# elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
+static DEFINE_STATIC_KEY_TRUE(sk_dynamic_preempt_schedule_notrace);
+void __sched notrace dynamic_preempt_schedule_notrace(void)
+{
+ if (!static_branch_unlikely(&sk_dynamic_preempt_schedule_notrace))
+ return;
+ preempt_schedule_notrace();
+}
+NOKPROBE_SYMBOL(dynamic_preempt_schedule_notrace);
+EXPORT_SYMBOL(dynamic_preempt_schedule_notrace);
+# endif
+#endif
+
+#endif /* CONFIG_PREEMPTION */
+
+#ifdef CONFIG_PREEMPT_DYNAMIC
+/*
+ * These aliases sit beside __cond_resched() in core.c, which MuQSS.c defines
+ * much further down; declare them here so sched_dynamic_update() can see them.
+ */
+# ifdef CONFIG_HAVE_PREEMPT_DYNAMIC_CALL
+# define cond_resched_dynamic_enabled __cond_resched
+# define cond_resched_dynamic_disabled ((void *)&__static_call_return0)
+# define might_resched_dynamic_enabled __cond_resched
+# define might_resched_dynamic_disabled ((void *)&__static_call_return0)
+# endif
+#endif
+
+#ifdef CONFIG_PREEMPT_DYNAMIC
+
+# ifdef CONFIG_GENERIC_IRQ_ENTRY
+# include <linux/irq-entry-common.h>
+# endif
+
+/*
+ * SC:cond_resched
+ * SC:might_resched
+ * SC:preempt_schedule
+ * SC:preempt_schedule_notrace
+ * SC:irqentry_exit_cond_resched
+ *
+ *
+ * NONE:
+ * cond_resched <- __cond_resched
+ * might_resched <- RET0
+ * preempt_schedule <- NOP
+ * preempt_schedule_notrace <- NOP
+ * irqentry_exit_cond_resched <- NOP
+ * dynamic_preempt_lazy <- false
+ *
+ * VOLUNTARY:
+ * cond_resched <- __cond_resched
+ * might_resched <- __cond_resched
+ * preempt_schedule <- NOP
+ * preempt_schedule_notrace <- NOP
+ * irqentry_exit_cond_resched <- NOP
+ * dynamic_preempt_lazy <- false
+ *
+ * FULL:
+ * cond_resched <- RET0
+ * might_resched <- RET0
+ * preempt_schedule <- preempt_schedule
+ * preempt_schedule_notrace <- preempt_schedule_notrace
+ * irqentry_exit_cond_resched <- irqentry_exit_cond_resched
+ * dynamic_preempt_lazy <- false
+ *
+ * LAZY:
+ * cond_resched <- RET0
+ * might_resched <- RET0
+ * preempt_schedule <- preempt_schedule
+ * preempt_schedule_notrace <- preempt_schedule_notrace
+ * irqentry_exit_cond_resched <- irqentry_exit_cond_resched
+ * dynamic_preempt_lazy <- true
+ */
+
+enum {
+ preempt_dynamic_undefined = -1,
+ preempt_dynamic_none,
+ preempt_dynamic_voluntary,
+ preempt_dynamic_full,
+ preempt_dynamic_lazy,
+};
+
+int preempt_dynamic_mode = preempt_dynamic_undefined;
+
+int sched_dynamic_mode(const char *str)
+{
+# if !(defined(CONFIG_PREEMPT_RT) || defined(CONFIG_ARCH_HAS_PREEMPT_LAZY))
+ if (!strcmp(str, "none"))
+ return preempt_dynamic_none;
+
+ if (!strcmp(str, "voluntary"))
+ return preempt_dynamic_voluntary;
+# endif
+
+ if (!strcmp(str, "full"))
+ return preempt_dynamic_full;
+
+# ifdef CONFIG_ARCH_HAS_PREEMPT_LAZY
+ if (!strcmp(str, "lazy"))
+ return preempt_dynamic_lazy;
+# endif
+
+ return -EINVAL;
+}
+
+# define preempt_dynamic_key_enable(f) static_key_enable(&sk_dynamic_##f.key)
+# define preempt_dynamic_key_disable(f) static_key_disable(&sk_dynamic_##f.key)
+
+# if defined(CONFIG_HAVE_PREEMPT_DYNAMIC_CALL)
+# define preempt_dynamic_enable(f) static_call_update(f, f##_dynamic_enabled)
+# define preempt_dynamic_disable(f) static_call_update(f, f##_dynamic_disabled)
+# elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
+# define preempt_dynamic_enable(f) preempt_dynamic_key_enable(f)
+# define preempt_dynamic_disable(f) preempt_dynamic_key_disable(f)
+# else
+# error "Unsupported PREEMPT_DYNAMIC mechanism"
+# endif
+
+static DEFINE_MUTEX(sched_dynamic_mutex);
+
+static void __sched_dynamic_update(int mode)
+{
+ /*
+ * Avoid {NONE,VOLUNTARY} -> FULL transitions from ever ending up in
+ * the ZERO state, which is invalid.
+ */
+ preempt_dynamic_enable(cond_resched);
+ preempt_dynamic_enable(might_resched);
+ preempt_dynamic_enable(preempt_schedule);
+ preempt_dynamic_enable(preempt_schedule_notrace);
+ preempt_dynamic_enable(irqentry_exit_cond_resched);
+ preempt_dynamic_key_disable(preempt_lazy);
+
+ switch (mode) {
+ case preempt_dynamic_none:
+ preempt_dynamic_enable(cond_resched);
+ preempt_dynamic_disable(might_resched);
+ preempt_dynamic_disable(preempt_schedule);
+ preempt_dynamic_disable(preempt_schedule_notrace);
+ preempt_dynamic_disable(irqentry_exit_cond_resched);
+ preempt_dynamic_key_disable(preempt_lazy);
+ if (mode != preempt_dynamic_mode)
+ pr_info("Dynamic Preempt: none\n");
+ break;
+
+ case preempt_dynamic_voluntary:
+ preempt_dynamic_enable(cond_resched);
+ preempt_dynamic_enable(might_resched);
+ preempt_dynamic_disable(preempt_schedule);
+ preempt_dynamic_disable(preempt_schedule_notrace);
+ preempt_dynamic_disable(irqentry_exit_cond_resched);
+ preempt_dynamic_key_disable(preempt_lazy);
+ if (mode != preempt_dynamic_mode)
+ pr_info("Dynamic Preempt: voluntary\n");
+ break;
+
+ case preempt_dynamic_full:
+ preempt_dynamic_disable(cond_resched);
+ preempt_dynamic_disable(might_resched);
+ preempt_dynamic_enable(preempt_schedule);
+ preempt_dynamic_enable(preempt_schedule_notrace);
+ preempt_dynamic_enable(irqentry_exit_cond_resched);
+ preempt_dynamic_key_disable(preempt_lazy);
+ if (mode != preempt_dynamic_mode)
+ pr_info("Dynamic Preempt: full\n");
+ break;
+
+ case preempt_dynamic_lazy:
+ preempt_dynamic_disable(cond_resched);
+ preempt_dynamic_disable(might_resched);
+ preempt_dynamic_enable(preempt_schedule);
+ preempt_dynamic_enable(preempt_schedule_notrace);
+ preempt_dynamic_enable(irqentry_exit_cond_resched);
+ preempt_dynamic_key_enable(preempt_lazy);
+ if (mode != preempt_dynamic_mode)
+ pr_info("Dynamic Preempt: lazy\n");
+ break;
+ }
+
+ WRITE_ONCE(preempt_dynamic_mode, mode);
+}
+
+void sched_dynamic_update(int mode)
+{
+ mutex_lock(&sched_dynamic_mutex);
+ __sched_dynamic_update(mode);
+ mutex_unlock(&sched_dynamic_mutex);
+}
+
+static int __init setup_preempt_mode(char *str)
+{
+ int mode = sched_dynamic_mode(str);
+ if (mode < 0) {
+ pr_warn("Dynamic Preempt: unsupported mode: %s\n", str);
+ return 0;
+ }
+
+ sched_dynamic_update(mode);
+ return 1;
+}
+__setup("preempt=", setup_preempt_mode);
+
+static void __init preempt_dynamic_init(void)
+{
+ if (preempt_dynamic_mode == preempt_dynamic_undefined) {
+ if (IS_ENABLED(CONFIG_PREEMPT_NONE)) {
+ sched_dynamic_update(preempt_dynamic_none);
+ } else if (IS_ENABLED(CONFIG_PREEMPT_VOLUNTARY)) {
+ sched_dynamic_update(preempt_dynamic_voluntary);
+ } else if (IS_ENABLED(CONFIG_PREEMPT_LAZY)) {
+ sched_dynamic_update(preempt_dynamic_lazy);
+ } else {
+ /* Default static call setting, nothing to do */
+ WARN_ON_ONCE(!IS_ENABLED(CONFIG_PREEMPT));
+ preempt_dynamic_mode = preempt_dynamic_full;
+ pr_info("Dynamic Preempt: full\n");
+ }
+ }
+}
+
+# define PREEMPT_MODEL_ACCESSOR(mode) \
+ bool preempt_model_##mode(void) \
+ { \
+ int mode = READ_ONCE(preempt_dynamic_mode); \
+ WARN_ON_ONCE(mode == preempt_dynamic_undefined); \
+ return mode == preempt_dynamic_##mode; \
+ } \
+ EXPORT_SYMBOL_GPL(preempt_model_##mode)
+
+PREEMPT_MODEL_ACCESSOR(none);
+PREEMPT_MODEL_ACCESSOR(voluntary);
+PREEMPT_MODEL_ACCESSOR(full);
+PREEMPT_MODEL_ACCESSOR(lazy);
+
+#else /* !CONFIG_PREEMPT_DYNAMIC: */
+
+#define preempt_dynamic_mode -1
+
+static inline void preempt_dynamic_init(void) { }
+
+#endif /* CONFIG_PREEMPT_DYNAMIC */
+
+const char *preempt_modes[] = {
+ "none", "voluntary", "full", "lazy", NULL,
+};
+/*
+ * This is the entry point to schedule() from kernel preemption
+ * off of irq context.
+ * Note, that this is called and return with irqs disabled. This will
+ * protect us against recursive calling from irq.
+ */
+asmlinkage __visible void __sched preempt_schedule_irq(void)
+{
+ enum ctx_state prev_state;
+
+ /* Catch callers which need to be fixed */
+ BUG_ON(preempt_count() || !irqs_disabled());
+
+ prev_state = exception_enter();
+
+ do {
+ preempt_disable();
+ local_irq_enable();
+ __schedule(SM_PREEMPT);
+ local_irq_disable();
+ sched_preempt_enable_no_resched();
+ } while (need_resched());
+
+ exception_exit(prev_state);
+}
+
+int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,
+ void *key)
+{
+ WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC);
+ return try_to_wake_up(curr->private, mode, wake_flags);
+}
+EXPORT_SYMBOL(default_wake_function);
+
+#ifdef CONFIG_RT_MUTEXES
+
+static inline int __rt_effective_prio(struct task_struct *pi_task, int prio)
+{
+ if (pi_task)
+ prio = min(prio, pi_task->prio);
+
+ return prio;
+}
+
+static inline int rt_effective_prio(struct task_struct *p, int prio)
+{
+ struct task_struct *pi_task = rt_mutex_get_top_task(p);
+
+ return __rt_effective_prio(pi_task, prio);
+}
+
+/*
+ * rt_mutex_setprio - set the current priority of a task
+ * @p: task to boost
+ * @pi_task: donor task
+ *
+ * This function changes the 'effective' priority of a task. It does
+ * not touch ->normal_prio like __setscheduler().
+ *
+ * Used by the rt_mutex code to implement priority inheritance
+ * logic. Call site only calls if the priority of the task changed.
+ */
+void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
+{
+ int prio, oldprio;
+ struct rq *rq;
+
+ /* XXX used to be waiter->prio, not waiter->task->prio */
+ prio = __rt_effective_prio(pi_task, p->normal_prio);
+
+ /*
+ * If nothing changed; bail early.
+ */
+ if (p->pi_top_task == pi_task && prio == p->prio)
+ return;
+
+ rq = __task_rq_lock(p, NULL);
+ update_rq_clock(rq);
+ /*
+ * Set under pi_lock && rq->lock, such that the value can be used under
+ * either lock.
+ *
+ * Note that there is loads of tricky to make this pointer cache work
+ * right. rt_mutex_slowunlock()+rt_mutex_postunlock() work together to
+ * ensure a task is de-boosted (pi_task is set to NULL) before the
+ * task is allowed to run again (and can exit). This ensures the pointer
+ * points to a blocked task -- which guarantees the task is present.
+ */
+ p->pi_top_task = pi_task;
+
+ /*
+ * For FIFO/RR we only need to set prio, if that matches we're done.
+ */
+ if (prio == p->prio)
+ goto out_unlock;
+
+ /*
+ * Idle task boosting is a nono in general. There is one
+ * exception, when PREEMPT_RT and NOHZ is active:
+ *
+ * The idle task calls get_next_timer_interrupt() and holds
+ * the timer wheel base->lock on the CPU and another CPU wants
+ * to access the timer (probably to cancel it). We can safely
+ * ignore the boosting request, as the idle CPU runs this code
+ * with interrupts disabled and will complete the lock
+ * protected section without being interrupted. So there is no
+ * real need to boost.
+ */
+ if (unlikely(p == rq->idle)) {
+ WARN_ON(p != rq->curr);
+ WARN_ON(p->pi_blocked_on);
+ goto out_unlock;
+ }
+
+ trace_sched_pi_setprio(p, pi_task);
+ oldprio = p->prio;
+ p->prio = prio;
+ if (task_running(rq, p)){
+ rt_running_reprio(rq, oldprio, prio);
+ if (prio > oldprio)
+ resched_task(p);
+ } else if (task_queued(p)) {
+ dequeue_task(rq, p, DEQUEUE_SAVE);
+ enqueue_task(rq, p, ENQUEUE_RESTORE);
+ if (prio < oldprio)
+ try_preempt(p, rq);
+ }
+out_unlock:
+ /* Avoid rq from going away on us: */
+ preempt_disable();
+ __task_rq_unlock(rq, p, NULL);
+
+ preempt_enable();
+}
+#else
+static inline int rt_effective_prio(struct task_struct *p, int prio)
+{
+ return prio;
+}
+#endif
+
+/*
+ * Adjust the deadline for when the priority is to change, before it's
+ * changed.
+ */
+static inline void adjust_deadline(struct task_struct *p, int new_prio)
+{
+ p->deadline += static_deadline_diff(new_prio) - task_deadline_diff(p);
+}
+
+void set_user_nice(struct task_struct *p, long nice)
+{
+ int new_static, old_static;
+ struct rq_flags rf;
+ struct rq *rq;
+
+ if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
+ return;
+ new_static = NICE_TO_PRIO(nice);
+ /*
+ * We have to be careful, if called from sys_setpriority(),
+ * the task might be in the middle of scheduling on another CPU.
+ */
+ rq = task_rq_lock(p, &rf);
+ update_rq_clock(rq);
+
+ /*
+ * The RT priorities are set via sched_setscheduler(), but we still
+ * allow the 'normal' nice value to be set - but as expected
+ * it won't have any effect on scheduling until the task is
+ * not SCHED_NORMAL/SCHED_BATCH:
+ */
+ if (has_rt_policy(p)) {
+ p->static_prio = new_static;
+ goto out_unlock;
+ }
+
+ adjust_deadline(p, new_static);
+ old_static = p->static_prio;
+ p->static_prio = new_static;
+ p->prio = effective_prio(p);
+
+ if (task_queued(p)) {
+ dequeue_task(rq, p, DEQUEUE_SAVE);
+ enqueue_task(rq, p, ENQUEUE_RESTORE);
+ if (new_static < old_static)
+ try_preempt(p, rq);
+ } else if (task_running(rq, p)) {
+ set_rq_task(rq, p);
+ if (old_static < new_static)
+ resched_task(p);
+ }
+out_unlock:
+ task_rq_unlock(rq, p, &rf);
+}
+EXPORT_SYMBOL(set_user_nice);
+
+/*
+ * can_nice - check if a task can reduce its nice value
+ * @p: task
+ * @nice: nice value
+ */
+int can_nice(const struct task_struct *p, const int nice)
+{
+ /* Convert nice value [19,-20] to rlimit style value [1,40] */
+ int nice_rlim = nice_to_rlimit(nice);
+
+ return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
+ capable(CAP_SYS_NICE));
+}
+
+#ifdef __ARCH_WANT_SYS_NICE
+
+/*
+ * sys_nice - change the priority of the current process.
+ * @increment: priority increment
+ *
+ * sys_setpriority is a more generic, but much slower function that
+ * does similar things.
+ */
+SYSCALL_DEFINE1(nice, int, increment)
+{
+ long nice, retval;
+
+ /*
+ * Setpriority might change our priority at the same moment.
+ * We don't have to worry. Conceptually one call occurs first
+ * and we have a single winner.
+ */
+
+ increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH);
+ nice = task_nice(current) + increment;
+
+ nice = clamp_val(nice, MIN_NICE, MAX_NICE);
+ if (increment < 0 && !can_nice(current, nice))
+ return -EPERM;
+
+ retval = security_task_setnice(current, nice);
+ if (retval)
+ return retval;
+
+ set_user_nice(current, nice);
+ return 0;
+}
+
+#endif
+
+/**
+ * task_prio - return the priority value of a given task.
+ * @p: the task in question.
+ *
+ * Return: The priority value as seen by users in /proc.
+ *
+ * sched policy return value kernel prio user prio/nice
+ *
+ * normal, batch, [1 ... 41] 101 0/[-20 ... 19]
+ * idle [42 ... 81] 102 0/[-20 ... 19]
+ * iso [0 ... 41] 100 0/[-20 ... 19]
+ * fifo, rr [-2 ... -100] [98 ... 0] [1 ... 99]
+ */
+int task_prio(const struct task_struct *p)
+{
+ int delta, prio = p->prio - MAX_RT_PRIO;
+
+ /* rt tasks and iso tasks */
+ if (prio <= 0)
+ goto out;
+
+ /* Convert to ms to avoid overflows */
+ delta = NS_TO_MS(p->deadline - task_rq(p)->niffies);
+ if (unlikely(delta < 0))
+ delta = 0;
+ delta = delta * 40 / ms_longest_deadline_diff();
+ if (delta <= 80)
+ prio += delta;
+ if (idleprio_task(p))
+ prio += 40;
+out:
+ return prio;
+}
+
+#ifdef CONFIG_SMP
+static inline bool rt_rq_is_runnable(struct rq *rt_rq)
+{
+ return rt_rq->rt_nr_running;
+}
+
+/*
+ * This function computes an effective utilization for the given CPU, to be
+ * used for frequency selection given the linear relation: f = u * f_max.
+ *
+ * The scheduler tracks the following metrics:
+ *
+ * cpu_util_{cfs,rt,dl,irq}()
+ * cpu_bw_dl()
+ *
+ * Where the cfs,rt and dl util numbers are tracked with the same metric and
+ * synchronized windows and are thus directly comparable.
+ *
+ * The cfs,rt,dl utilization are the running times measured with rq->clock_task
+ * which excludes things like IRQ and steal-time. These latter are then accrued
+ * in the irq utilization.
+ *
+ * The DL bandwidth number otoh is not a measured metric but a value computed
+ * based on the task model parameters and gives the minimal utilization
+ * required to meet deadlines.
+ */
+unsigned long effective_cpu_util(int cpu, unsigned long util_cfs,
+ unsigned long *min, unsigned long *max)
+{
+ unsigned long util, irq, scale;
+ struct rq *rq = cpu_rq(cpu);
+
+ scale = arch_scale_cpu_capacity(cpu);
+
+ /*
+ * Early check to see if IRQ/steal time saturates the CPU, can be
+ * because of inaccuracies in how we track these.
+ */
+ irq = cpu_util_irq(rq);
+ if (unlikely(irq >= scale)) {
+ if (min)
+ *min = scale;
+ if (max)
+ *max = scale;
+ return scale;
+ }
+
+ /*
+ * MuQSS has no utilisation clamping and no deadline bandwidth, so the
+ * usable range is simply the whole capacity. A runnable realtime task
+ * asks for the maximum.
+ */
+ if (min)
+ *min = rt_rq_is_runnable(rq) ? scale : 0;
+ if (max)
+ *max = scale;
+
+ util = util_cfs + cpu_util_rt(rq);
+ util = scale_irq_capacity(util, irq, scale);
+
+ return min_t(unsigned long, scale, util);
+}
+
+/*
+ * Available idle CPU capacity, used by the energy model. MuQSS does not
+ * implement energy aware scheduling, but the interface is still called.
+ */
+unsigned long sched_cpu_util(int cpu)
+{
+ unsigned long min, max;
+
+ return effective_cpu_util(cpu, cpu_util_cfs(cpu_rq(cpu)), &min, &max);
+}
+#endif /* CONFIG_SMP */
+
+/**
+ * idle_cpu - is a given CPU idle currently?
+ * @cpu: the processor in question.
+ *
+ * Return: 1 if the CPU is currently idle. 0 otherwise.
+ */
+int idle_cpu(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+
+ if (rq->curr != rq->idle)
+ return 0;
+
+ if (rq->nr_running)
+ return 0;
+
+#ifdef CONFIG_SMP
+ if (rq->ttwu_pending)
+ return 0;
+#endif
+
+ return 1;
+}
+
+/**
+ * available_idle_cpu - is a given CPU idle for enqueuing work.
+ * @cpu: the CPU in question.
+ *
+ * Return: 1 if the CPU is currently idle. 0 otherwise.
+ */
+bool available_idle_cpu(int cpu)
+{
+ if (!idle_cpu(cpu))
+ return 0;
+
+ if (vcpu_is_preempted(cpu))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * idle_task - return the idle task for a given CPU.
+ * @cpu: the processor in question.
+ *
+ * Return: The idle task for the CPU @cpu.
+ */
+struct task_struct *idle_task(int cpu)
+{
+ return cpu_rq(cpu)->idle;
+}
+
+/**
+ * find_process_by_pid - find a process with a matching PID value.
+ * @pid: the pid in question.
+ *
+ * The task of @pid, if found. %NULL otherwise.
+ */
+static inline struct task_struct *find_process_by_pid(pid_t pid)
+{
+ return pid ? find_task_by_vpid(pid) : current;
+}
+
+/* Actually do priority change: must hold rq lock. */
+static void __setscheduler(struct task_struct *p, struct rq *rq, int policy,
+ int prio, const struct sched_attr *attr,
+ bool keep_boost)
+{
+ int oldrtprio, oldprio;
+
+ /*
+ * If params can't change scheduling class changes aren't allowed
+ * either.
+ */
+ if (attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)
+ return;
+
+ p->policy = policy;
+ oldrtprio = p->rt_priority;
+ p->rt_priority = prio;
+
+ /* rt-policy tasks do not have a timerslack */
+ if (has_rt_policy(p)) {
+ p->timer_slack_ns = 0;
+ } else if (p->timer_slack_ns == 0) {
+ /* when switching back to non-rt policy, restore timerslack */
+ p->timer_slack_ns = p->default_timer_slack_ns;
+ }
+
+ p->normal_prio = normal_prio(p);
+ oldprio = p->prio;
+ /*
+ * Keep a potential priority boosting if called from
+ * sched_setscheduler().
+ */
+ p->prio = normal_prio(p);
+ if (keep_boost)
+ p->prio = rt_effective_prio(p, p->prio);
+
+ if (task_running(rq, p)) {
+ rt_running_reprio(rq, oldprio, p->prio);
+ set_rq_task(rq, p);
+ resched_task(p);
+ } else if (task_queued(p)) {
+ dequeue_task(rq, p, DEQUEUE_SAVE);
+ enqueue_task(rq, p, ENQUEUE_RESTORE);
+ if (p->prio < oldprio || p->rt_priority > oldrtprio)
+ try_preempt(p, rq);
+ }
+}
+
+/*
+ * Check the target process has a UID that matches the current process's
+ */
+static bool check_same_owner(struct task_struct *p)
+{
+ const struct cred *cred = current_cred(), *pcred;
+ bool match;
+
+ rcu_read_lock();
+ pcred = __task_cred(p);
+ match = (uid_eq(cred->euid, pcred->euid) ||
+ uid_eq(cred->euid, pcred->uid));
+ rcu_read_unlock();
+ return match;
+}
+
+static int __sched_setscheduler(struct task_struct *p,
+ const struct sched_attr *attr,
+ bool user, bool pi)
+{
+ int retval, policy = attr->sched_policy, oldpolicy = -1, priority = attr->sched_priority;
+ unsigned long rlim_rtprio = 0;
+ struct rq_flags rf;
+ int reset_on_fork;
+ struct rq *rq;
+
+ /* The pi code expects interrupts enabled */
+ BUG_ON(pi && in_interrupt());
+
+ if (is_rt_policy(policy) && !capable(CAP_SYS_NICE)) {
+ unsigned long lflags;
+
+ if (!lock_task_sighand(p, &lflags))
+ return -ESRCH;
+ rlim_rtprio = task_rlimit(p, RLIMIT_RTPRIO);
+ unlock_task_sighand(p, &lflags);
+ if (rlim_rtprio)
+ goto recheck;
+ /*
+ * If the caller requested an RT policy without having the
+ * necessary rights, we downgrade the policy to SCHED_ISO.
+ * We also set the parameter to zero to pass the checks.
+ */
+ policy = SCHED_ISO;
+ priority = 0;
+ }
+recheck:
+ /* Double check policy once rq lock held */
+ if (policy < 0) {
+ reset_on_fork = p->sched_reset_on_fork;
+ policy = oldpolicy = p->policy;
+ } else {
+ reset_on_fork = !!(policy & SCHED_RESET_ON_FORK);
+ policy &= ~SCHED_RESET_ON_FORK;
+
+ if (!SCHED_RANGE(policy))
+ return -EINVAL;
+ }
+
+ if (attr->sched_flags & ~(SCHED_FLAG_ALL | SCHED_FLAG_SUGOV))
+ return -EINVAL;
+
+ /*
+ * Valid priorities for SCHED_FIFO and SCHED_RR are
+ * 1..MAX_RT_PRIO-1, valid priority for SCHED_NORMAL and
+ * SCHED_BATCH is 0.
+ */
+ if (priority > MAX_RT_PRIO-1)
+ return -EINVAL;
+ if (is_rt_policy(policy) != (priority != 0))
+ return -EINVAL;
+
+ /*
+ * Allow unprivileged RT tasks to decrease priority:
+ */
+ if (user && !capable(CAP_SYS_NICE)) {
+ if (is_rt_policy(policy)) {
+ unsigned long rlim_rtprio =
+ task_rlimit(p, RLIMIT_RTPRIO);
+
+ /* Can't set/change the rt policy */
+ if (policy != p->policy && !rlim_rtprio)
+ return -EPERM;
+
+ /* Can't increase priority */
+ if (priority > p->rt_priority &&
+ priority > rlim_rtprio)
+ return -EPERM;
+ } else {
+ switch (p->policy) {
+ /*
+ * Can only downgrade policies but not back to
+ * SCHED_NORMAL
+ */
+ case SCHED_ISO:
+ if (policy == SCHED_ISO)
+ goto out;
+ if (policy != SCHED_NORMAL)
+ return -EPERM;
+ break;
+ case SCHED_BATCH:
+ if (policy == SCHED_BATCH)
+ goto out;
+ if (policy != SCHED_IDLEPRIO)
+ return -EPERM;
+ break;
+ case SCHED_IDLEPRIO:
+ if (policy == SCHED_IDLEPRIO)
+ goto out;
+ return -EPERM;
+ default:
+ break;
+ }
+ }
+
+ /* Can't change other user's priorities */
+ if (!check_same_owner(p))
+ return -EPERM;
+
+ /* Normal users shall not reset the sched_reset_on_fork flag: */
+ if (p->sched_reset_on_fork && !reset_on_fork)
+ return -EPERM;
+ }
+
+ if (user) {
+ retval = security_task_setscheduler(p);
+ if (retval)
+ return retval;
+ }
+
+ if (pi)
+ cpuset_lock();
+
+ /*
+ * Make sure no PI-waiters arrive (or leave) while we are
+ * changing the priority of the task:
+ *
+ * To be able to change p->policy safely, the runqueue lock must be
+ * held.
+ */
+ rq = task_rq_lock(p, &rf);
+ update_rq_clock(rq);
+
+ /*
+ * Changing the policy of the stop threads its a very bad idea:
+ */
+ if (p == rq->stop) {
+ retval = -EINVAL;
+ goto unlock;
+ }
+
+ /*
+ * If not changing anything there's no need to proceed further,
+ * but store a possible modification of reset_on_fork.
+ */
+ if (unlikely(policy == p->policy && (!is_rt_policy(policy) ||
+ priority == p->rt_priority))) {
+ p->sched_reset_on_fork = reset_on_fork;
+ retval = 0;
+ goto unlock;
+ }
+
+ /* Re-check policy now with rq lock held */
+ if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) {
+ policy = oldpolicy = -1;
+ task_rq_unlock(rq, p, &rf);
+ if (pi)
+ cpuset_unlock();
+ goto recheck;
+ }
+ p->sched_reset_on_fork = reset_on_fork;
+
+ __setscheduler(p, rq, policy, priority, attr, pi);
+
+ /* Avoid rq from going away on us: */
+ preempt_disable();
+ task_rq_unlock(rq, p, &rf);
+
+ if (pi) {
+ cpuset_unlock();
+ rt_mutex_adjust_pi(p);
+ }
+ preempt_enable();
+out:
+ return 0;
+
+unlock:
+ task_rq_unlock(rq, p, &rf);
+ if (pi)
+ cpuset_unlock();
+ return retval;
+}
+
+static int _sched_setscheduler(struct task_struct *p, int policy,
+ const struct sched_param *param, bool check)
+{
+ struct sched_attr attr = {
+ .sched_policy = policy,
+ .sched_priority = param->sched_priority,
+ .sched_nice = PRIO_TO_NICE(p->static_prio),
+ };
+
+ return __sched_setscheduler(p, &attr, check, true);
+}
+/**
+ * sched_setscheduler - change the scheduling policy and/or RT priority of a thread.
+ * @p: the task in question.
+ * @policy: new policy.
+ * @param: structure containing the new RT priority.
+ *
+ * Use sched_set_fifo(), read its comment.
+ *
+ * Return: 0 on success. An error code otherwise.
+ *
+ * NOTE that the task may be already dead.
+ */
+int sched_setscheduler(struct task_struct *p, int policy,
+ const struct sched_param *param)
+{
+ return _sched_setscheduler(p, policy, param, true);
+}
+
+
+int sched_setattr(struct task_struct *p, const struct sched_attr *attr)
+{
+ return __sched_setscheduler(p, attr, true, true);
+}
+
+int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr)
+{
+ return __sched_setscheduler(p, attr, false, true);
+}
+
+/**
+ * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace.
+ * @p: the task in question.
+ * @policy: new policy.
+ * @param: structure containing the new RT priority.
+ *
+ * Just like sched_setscheduler, only don't bother checking if the
+ * current context has permission. For example, this is needed in
+ * stop_machine(): we create temporary high priority worker threads,
+ * but our caller might not have that capability.
+ *
+ * Return: 0 on success. An error code otherwise.
+ */
+int sched_setscheduler_nocheck(struct task_struct *p, int policy,
+ const struct sched_param *param)
+{
+ return _sched_setscheduler(p, policy, param, false);
+}
+
+/*
+ * SCHED_FIFO is a broken scheduler model; that is, it is fundamentally
+ * incapable of resource management, which is the one thing an OS really should
+ * be doing.
+ *
+ * This is of course the reason it is limited to privileged users only.
+ *
+ * Worse still; it is fundamentally impossible to compose static priority
+ * workloads. You cannot take two correctly working static prio workloads
+ * and smash them together and still expect them to work.
+ *
+ * For this reason 'all' FIFO tasks the kernel creates are basically at:
+ *
+ * MAX_RT_PRIO / 2
+ *
+ * The administrator _MUST_ configure the system, the kernel simply doesn't
+ * know enough information to make a sensible choice.
+ */
+void sched_set_fifo(struct task_struct *p)
+{
+ struct sched_param sp = { .sched_priority = MAX_RT_PRIO / 2 };
+ WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0);
+}
+EXPORT_SYMBOL_GPL(sched_set_fifo);
+
+/*
+ * For when you don't much care about FIFO, but want to be above SCHED_NORMAL.
+ */
+void sched_set_fifo_low(struct task_struct *p)
+{
+ struct sched_param sp = { .sched_priority = 1 };
+ WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0);
+}
+EXPORT_SYMBOL_GPL(sched_set_fifo_low);
+
+void sched_set_normal(struct task_struct *p, int nice)
+{
+ struct sched_attr attr = {
+ .sched_policy = SCHED_NORMAL,
+ .sched_nice = nice,
+ };
+ WARN_ON_ONCE(sched_setattr_nocheck(p, &attr) != 0);
+}
+EXPORT_SYMBOL_GPL(sched_set_normal);
+
+static int
+do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
+{
+ struct sched_param lparam;
+ struct task_struct *p;
+ int retval;
+
+ if (!param || pid < 0)
+ return -EINVAL;
+ if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
+ return -EFAULT;
+
+ rcu_read_lock();
+ retval = -ESRCH;
+ p = find_process_by_pid(pid);
+ if (likely(p))
+ get_task_struct(p);
+ rcu_read_unlock();
+
+ if (likely(p)) {
+ retval = sched_setscheduler(p, policy, &lparam);
+ put_task_struct(p);
+ }
+
+ return retval;
+}
+
+/*
+ * Mimics kernel/events/core.c perf_copy_attr().
+ */
+static int sched_copy_attr(struct sched_attr __user *uattr,
+ struct sched_attr *attr)
+{
+ u32 size;
+ int ret;
+
+ /* Zero the full structure, so that a short copy will be nice: */
+ memset(attr, 0, sizeof(*attr));
+
+ ret = get_user(size, &uattr->size);
+ if (ret)
+ return ret;
+
+ /* ABI compatibility quirk: */
+ if (!size)
+ size = SCHED_ATTR_SIZE_VER0;
+
+ if (size < SCHED_ATTR_SIZE_VER0 || size > PAGE_SIZE)
+ goto err_size;
+
+ ret = copy_struct_from_user(attr, sizeof(*attr), uattr, size);
+ if (ret) {
+ if (ret == -E2BIG)
+ goto err_size;
+ return ret;
+ }
+
+ /*
+ * XXX: Do we want to be lenient like existing syscalls; or do we want
+ * to be strict and return an error on out-of-bounds values?
+ */
+ attr->sched_nice = clamp(attr->sched_nice, -20, 19);
+
+ /* sched/core.c uses zero here but we already know ret is zero */
+ return 0;
+
+err_size:
+ put_user(sizeof(*attr), &uattr->size);
+ return -E2BIG;
+}
+
+/*
+ * sched_setparam() passes in -1 for its policy, to let the functions
+ * it calls know not to change it.
+ */
+#define SETPARAM_POLICY -1
+
+/**
+ * sys_sched_setscheduler - set/change the scheduler policy and RT priority
+ * @pid: the pid in question.
+ * @policy: new policy.
+ * @param: structure containing the new RT priority.
+ *
+ * Return: 0 on success. An error code otherwise.
+ */
+SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param)
+{
+ if (policy < 0)
+ return -EINVAL;
+
+ return do_sched_setscheduler(pid, policy, param);
+}
+
+/**
+ * sys_sched_setparam - set/change the RT priority of a thread
+ * @pid: the pid in question.
+ * @param: structure containing the new RT priority.
+ *
+ * Return: 0 on success. An error code otherwise.
+ */
+SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
+{
+ return do_sched_setscheduler(pid, SETPARAM_POLICY, param);
+}
+
+/**
+ * sys_sched_setattr - same as above, but with extended sched_attr
+ * @pid: the pid in question.
+ * @uattr: structure containing the extended parameters.
+ */
+SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
+ unsigned int, flags)
+{
+ struct sched_attr attr;
+ struct task_struct *p;
+ int retval;
+
+ if (!uattr || pid < 0 || flags)
+ return -EINVAL;
+
+ retval = sched_copy_attr(uattr, &attr);
+ if (retval)
+ return retval;
+
+ if ((int)attr.sched_policy < 0)
+ return -EINVAL;
+ if (attr.sched_flags & SCHED_FLAG_KEEP_POLICY)
+ attr.sched_policy = SETPARAM_POLICY;
+
+ rcu_read_lock();
+ retval = -ESRCH;
+ p = find_process_by_pid(pid);
+ if (likely(p))
+ get_task_struct(p);
+ rcu_read_unlock();
+
+ if (likely(p)) {
+ retval = sched_setattr(p, &attr);
+ put_task_struct(p);
+ }
+
+ return retval;
+}
+
+/**
+ * sys_sched_getscheduler - get the policy (scheduling class) of a thread
+ * @pid: the pid in question.
+ *
+ * Return: On success, the policy of the thread. Otherwise, a negative error
+ * code.
+ */
+SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
+{
+ struct task_struct *p;
+ int retval = -EINVAL;
+
+ if (pid < 0)
+ goto out_nounlock;
+
+ retval = -ESRCH;
+ rcu_read_lock();
+ p = find_process_by_pid(pid);
+ if (p) {
+ retval = security_task_getscheduler(p);
+ if (!retval)
+ retval = p->policy;
+ }
+ rcu_read_unlock();
+
+out_nounlock:
+ return retval;
+}
+
+/**
+ * sys_sched_getscheduler - get the RT priority of a thread
+ * @pid: the pid in question.
+ * @param: structure containing the RT priority.
+ *
+ * Return: On success, 0 and the RT priority is in @param. Otherwise, an error
+ * code.
+ */
+SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)
+{
+ struct sched_param lp = { .sched_priority = 0 };
+ struct task_struct *p;
+ int retval = -EINVAL;
+
+ if (!param || pid < 0)
+ goto out_nounlock;
+
+ rcu_read_lock();
+ p = find_process_by_pid(pid);
+ retval = -ESRCH;
+ if (!p)
+ goto out_unlock;
+
+ retval = security_task_getscheduler(p);
+ if (retval)
+ goto out_unlock;
+
+ if (has_rt_policy(p))
+ lp.sched_priority = p->rt_priority;
+ rcu_read_unlock();
+
+ /*
+ * This one might sleep, we cannot do it with a spinlock held ...
+ */
+ retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0;
+
+out_nounlock:
+ return retval;
+
+out_unlock:
+ rcu_read_unlock();
+ return retval;
+}
+
+/*
+ * Copy the kernel size attribute structure (which might be larger
+ * than what user-space knows about) to user-space.
+ *
+ * Note that all cases are valid: user-space buffer can be larger or
+ * smaller than the kernel-space buffer. The usual case is that both
+ * have the same size.
+ */
+static int
+sched_attr_copy_to_user(struct sched_attr __user *uattr,
+ struct sched_attr *kattr,
+ unsigned int usize)
+{
+ unsigned int ksize = sizeof(*kattr);
+
+ if (!access_ok(uattr, usize))
+ return -EFAULT;
+
+ /*
+ * sched_getattr() ABI forwards and backwards compatibility:
+ *
+ * If usize == ksize then we just copy everything to user-space and all is good.
+ *
+ * If usize < ksize then we only copy as much as user-space has space for,
+ * this keeps ABI compatibility as well. We skip the rest.
+ *
+ * If usize > ksize then user-space is using a newer version of the ABI,
+ * which part the kernel doesn't know about. Just ignore it - tooling can
+ * detect the kernel's knowledge of attributes from the attr->size value
+ * which is set to ksize in this case.
+ */
+ kattr->size = min(usize, ksize);
+
+ if (copy_to_user(uattr, kattr, kattr->size))
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
+ * sys_sched_getattr - similar to sched_getparam, but with sched_attr
+ * @pid: the pid in question.
+ * @uattr: structure containing the extended parameters.
+ * @usize: sizeof(attr) for fwd/bwd comp.
+ * @flags: for future extension.
+ */
+SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
+ unsigned int, usize, unsigned int, flags)
+{
+ struct sched_attr kattr = { };
+ struct task_struct *p;
+ int retval;
+
+ if (!uattr || pid < 0 || usize > PAGE_SIZE ||
+ usize < SCHED_ATTR_SIZE_VER0 || flags)
+ return -EINVAL;
+
+ rcu_read_lock();
+ p = find_process_by_pid(pid);
+ retval = -ESRCH;
+ if (!p)
+ goto out_unlock;
+
+ retval = security_task_getscheduler(p);
+ if (retval)
+ goto out_unlock;
+
+ kattr.sched_policy = p->policy;
+ if (rt_task(p))
+ kattr.sched_priority = p->rt_priority;
+ else
+ kattr.sched_nice = task_nice(p);
+
+ rcu_read_unlock();
+
+ return sched_attr_copy_to_user(uattr, &kattr, usize);
+
+out_unlock:
+ rcu_read_unlock();
+ return retval;
+}
+
+long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
+{
+ cpumask_var_t cpus_allowed, new_mask;
+ struct task_struct *p;
+ int retval;
+
+ rcu_read_lock();
+
+ p = find_process_by_pid(pid);
+ if (!p) {
+ rcu_read_unlock();
+ return -ESRCH;
+ }
+
+ /* Prevent p going away */
+ get_task_struct(p);
+ rcu_read_unlock();
+
+ if (p->flags & PF_NO_SETAFFINITY) {
+ retval = -EINVAL;
+ goto out_put_task;
+ }
+ if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
+ retval = -ENOMEM;
+ goto out_put_task;
+ }
+ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
+ retval = -ENOMEM;
+ goto out_free_cpus_allowed;
+ }
+ retval = -EPERM;
+ if (!check_same_owner(p)) {
+ rcu_read_lock();
+ if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) {
+ rcu_read_unlock();
+ goto out_unlock;
+ }
+ rcu_read_unlock();
+ }
+
+ retval = security_task_setscheduler(p);
+ if (retval)
+ goto out_unlock;
+
+ cpuset_cpus_allowed(p, cpus_allowed);
+ cpumask_and(new_mask, in_mask, cpus_allowed);
+again:
+ retval = __set_cpus_allowed_ptr(p, new_mask, SCA_CHECK | SCA_USER);
+
+ if (!retval) {
+ cpuset_cpus_allowed(p, cpus_allowed);
+ if (!cpumask_subset(new_mask, cpus_allowed)) {
+ /*
+ * We must have raced with a concurrent cpuset
+ * update. Just reset the cpus_allowed to the
+ * cpuset's cpus_allowed
+ */
+ cpumask_copy(new_mask, cpus_allowed);
+ goto again;
+ }
+ }
+out_unlock:
+ free_cpumask_var(new_mask);
+out_free_cpus_allowed:
+ free_cpumask_var(cpus_allowed);
+out_put_task:
+ put_task_struct(p);
+ return retval;
+}
+
+static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len,
+ cpumask_t *new_mask)
+{
+ if (len < cpumask_size())
+ cpumask_clear(new_mask);
+ else if (len > cpumask_size())
+ len = cpumask_size();
+
+ return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0;
+}
+
+
+/**
+ * sys_sched_setaffinity - set the CPU affinity of a process
+ * @pid: pid of the process
+ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
+ * @user_mask_ptr: user-space pointer to the new CPU mask
+ *
+ * Return: 0 on success. An error code otherwise.
+ */
+SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
+ unsigned long __user *, user_mask_ptr)
+{
+ cpumask_var_t new_mask;
+ int retval;
+
+ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ retval = get_user_cpu_mask(user_mask_ptr, len, new_mask);
+ if (retval == 0)
+ retval = sched_setaffinity(pid, new_mask);
+ free_cpumask_var(new_mask);
+ return retval;
+}
+
+long sched_getaffinity(pid_t pid, cpumask_t *mask)
+{
+ struct task_struct *p;
+ unsigned long flags;
+ int retval;
+
+ cpus_read_lock();
+ rcu_read_lock();
+
+ retval = -ESRCH;
+ p = find_process_by_pid(pid);
+ if (!p)
+ goto out_unlock;
+
+ retval = security_task_getscheduler(p);
+ if (retval)
+ goto out_unlock;
+
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
+ cpumask_and(mask, &p->cpus_mask, cpu_active_mask);
+ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+
+out_unlock:
+ rcu_read_unlock();
+ cpus_read_unlock();
+
+ return retval;
+}
+
+/**
+ * sys_sched_getaffinity - get the CPU affinity of a process
+ * @pid: pid of the process
+ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
+ * @user_mask_ptr: user-space pointer to hold the current CPU mask
+ *
+ * Return: 0 on success. An error code otherwise.
+ */
+SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
+ unsigned long __user *, user_mask_ptr)
+{
+ int ret;
+ cpumask_var_t mask;
+
+ if ((len * BITS_PER_BYTE) < nr_cpu_ids)
+ return -EINVAL;
+ if (len & (sizeof(unsigned long)-1))
+ return -EINVAL;
+
+ if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ ret = sched_getaffinity(pid, mask);
+ if (ret == 0) {
+ unsigned int retlen = min(len, cpumask_size());
+
+ if (copy_to_user(user_mask_ptr, mask, retlen))
+ ret = -EFAULT;
+ else
+ ret = retlen;
+ }
+ free_cpumask_var(mask);
+
+ return ret;
+}
+
+static void do_sched_yield(void)
+{
+ struct rq_flags rf;
+ struct rq *rq;
+
+ if (!sched_yield_type)
+ return;
+
+ rq = this_rq_lock_irq(&rf);
+
+ if (sched_yield_type > 1)
+ time_slice_expired(current, rq);
+ schedstat_inc(rq->yld_count);
+
+ preempt_disable();
+ rq_unlock_irq(rq, &rf);
+ sched_preempt_enable_no_resched();
+
+ schedule();
+}
+
+/**
+ * sys_sched_yield - yield the current processor to other threads.
+ *
+ * This function yields the current CPU to other tasks. If there are no
+ * other threads running on this CPU then this function will return.
+ *
+ * Return: 0.
+ */
+SYSCALL_DEFINE0(sched_yield)
+{
+ do_sched_yield();
+ return 0;
+}
+
+#if !defined(CONFIG_PREEMPTION) || defined(CONFIG_PREEMPT_DYNAMIC)
+int __sched __cond_resched(void)
+{
+ if (should_resched(0)) {
+ preempt_schedule_common();
+ return 1;
+ }
+#ifndef CONFIG_PREEMPT_RCU
+ rcu_all_qs();
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(__cond_resched);
+#endif
+
+#ifdef CONFIG_PREEMPT_DYNAMIC
+# ifdef CONFIG_HAVE_PREEMPT_DYNAMIC_CALL
+DEFINE_STATIC_CALL_RET0(cond_resched, __cond_resched);
+EXPORT_STATIC_CALL_TRAMP(cond_resched);
+
+DEFINE_STATIC_CALL_RET0(might_resched, __cond_resched);
+EXPORT_STATIC_CALL_TRAMP(might_resched);
+# elif defined(CONFIG_HAVE_PREEMPT_DYNAMIC_KEY)
+static DEFINE_STATIC_KEY_FALSE(sk_dynamic_cond_resched);
+int __sched dynamic_cond_resched(void)
+{
+ if (!static_branch_unlikely(&sk_dynamic_cond_resched))
+ return 0;
+ return __cond_resched();
+}
+EXPORT_SYMBOL(dynamic_cond_resched);
+
+static DEFINE_STATIC_KEY_FALSE(sk_dynamic_might_resched);
+int __sched dynamic_might_resched(void)
+{
+ if (!static_branch_unlikely(&sk_dynamic_might_resched))
+ return 0;
+ return __cond_resched();
+}
+EXPORT_SYMBOL(dynamic_might_resched);
+# endif
+#endif /* CONFIG_PREEMPT_DYNAMIC */
+
+/*
+ * __cond_resched_lock() - if a reschedule is pending, drop the given lock,
+ * call schedule, and on return reacquire the lock.
+ *
+ * This works OK both with and without CONFIG_PREEMPTION. We do strange low-level
+ * operations here to prevent schedule() from being called twice (once via
+ * spin_unlock(), once by hand).
+ */
+int __cond_resched_lock(spinlock_t *lock)
+{
+ int resched = should_resched(PREEMPT_LOCK_OFFSET);
+ int ret = 0;
+
+ lockdep_assert_held(lock);
+
+ if (spin_needbreak(lock) || resched) {
+ spin_unlock(lock);
+ if (resched)
+ preempt_schedule_common();
+ else
+ cpu_relax();
+ ret = 1;
+ spin_lock(lock);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(__cond_resched_lock);
+
+int __cond_resched_rwlock_read(rwlock_t *lock)
+{
+ int resched = should_resched(PREEMPT_LOCK_OFFSET);
+ int ret = 0;
+
+ lockdep_assert_held_read(lock);
+
+ if (rwlock_needbreak(lock) || resched) {
+ read_unlock(lock);
+ if (resched)
+ preempt_schedule_common();
+ else
+ cpu_relax();
+ ret = 1;
+ read_lock(lock);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(__cond_resched_rwlock_read);
+
+int __cond_resched_rwlock_write(rwlock_t *lock)
+{
+ int resched = should_resched(PREEMPT_LOCK_OFFSET);
+ int ret = 0;
+
+ lockdep_assert_held_write(lock);
+
+ if (rwlock_needbreak(lock) || resched) {
+ write_unlock(lock);
+ if (resched)
+ preempt_schedule_common();
+ else
+ cpu_relax();
+ ret = 1;
+ write_lock(lock);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(__cond_resched_rwlock_write);
+
+/**
+ * yield - yield the current processor to other threads.
+ *
+ * Do not ever use this function, there's a 99% chance you're doing it wrong.
+ *
+ * The scheduler is at all times free to pick the calling task as the most
+ * eligible task to run, if removing the yield() call from your code breaks
+ * it, it's already broken.
+ *
+ * Typical broken usage is:
+ *
+ * while (!event)
+ * yield();
+ *
+ * where one assumes that yield() will let 'the other' process run that will
+ * make event true. If the current task is a SCHED_FIFO task that will never
+ * happen. Never use yield() as a progress guarantee!!
+ *
+ * If you want to use yield() to wait for something, use wait_event().
+ * If you want to use yield() to be 'nice' for others, use cond_resched().
+ * If you still want to use yield(), do not!
+ */
+void __sched yield(void)
+{
+ set_current_state(TASK_RUNNING);
+ do_sched_yield();
+}
+EXPORT_SYMBOL(yield);
+
+/**
+ * yield_to - yield the current processor to another thread in
+ * your thread group, or accelerate that thread toward the
+ * processor it's on.
+ * @p: target task
+ * @preempt: whether task preemption is allowed or not
+ *
+ * It's the caller's job to ensure that the target task struct
+ * can't go away on us before we can do any checks.
+ *
+ * Return:
+ * true (>0) if we indeed boosted the target task.
+ * false (0) if we failed to boost the target.
+ * -ESRCH if there's no task to yield to.
+ */
+int __sched yield_to(struct task_struct *p, bool preempt)
+{
+ struct task_struct *rq_p;
+ struct rq *rq, *p_rq;
+ unsigned long flags;
+ int yielded = 0;
+
+ local_irq_save(flags);
+ rq = this_rq();
+
+again:
+ p_rq = task_rq(p);
+ /*
+ * If we're the only runnable task on the rq and target rq also
+ * has only one task, there's absolutely no point in yielding.
+ */
+ if (task_running(p_rq, p) || p->__state) {
+ yielded = -ESRCH;
+ goto out_irq;
+ }
+
+ double_rq_lock(rq, p_rq);
+ if (unlikely(task_rq(p) != p_rq)) {
+ double_rq_unlock(rq, p_rq);
+ goto again;
+ }
+
+ yielded = 1;
+ schedstat_inc(rq->yld_count);
+ rq_p = rq->curr;
+ if (p->deadline > rq_p->deadline)
+ p->deadline = rq_p->deadline;
+ p->time_slice += rq_p->time_slice;
+ if (p->time_slice > timeslice())
+ p->time_slice = timeslice();
+ time_slice_expired(rq_p, rq);
+ if (preempt && rq != p_rq)
+ resched_task(p_rq->curr);
+ double_rq_unlock(rq, p_rq);
+out_irq:
+ local_irq_restore(flags);
+
+ if (yielded > 0)
+ schedule();
+ return yielded;
+}
+EXPORT_SYMBOL_GPL(yield_to);
+
+int io_schedule_prepare(void)
+{
+ int old_iowait = current->in_iowait;
+
+ current->in_iowait = 1;
+ blk_flush_plug(current->plug, true);
+
+ return old_iowait;
+}
+
+void io_schedule_finish(int token)
+{
+ current->in_iowait = token;
+}
+
+/*
+ * This task is about to go to sleep on IO. Increment rq->nr_iowait so
+ * that process accounting knows that this is a task in IO wait state.
+ *
+ * But don't do that if it is a deliberate, throttling IO wait (this task
+ * has set its backing_dev_info: the queue against which it should throttle)
+ */
+
+long __sched io_schedule_timeout(long timeout)
+{
+ int token;
+ long ret;
+
+ token = io_schedule_prepare();
+ ret = schedule_timeout(timeout);
+ io_schedule_finish(token);
+
+ return ret;
+}
+EXPORT_SYMBOL(io_schedule_timeout);
+
+void __sched io_schedule(void)
+{
+ int token;
+
+ token = io_schedule_prepare();
+ schedule();
+ io_schedule_finish(token);
+}
+EXPORT_SYMBOL(io_schedule);
+
+/**
+ * sys_sched_get_priority_max - return maximum RT priority.
+ * @policy: scheduling class.
+ *
+ * Return: On success, this syscall returns the maximum
+ * rt_priority that can be used by a given scheduling class.
+ * On failure, a negative error code is returned.
+ */
+SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
+{
+ int ret = -EINVAL;
+
+ switch (policy) {
+ case SCHED_FIFO:
+ case SCHED_RR:
+ ret = MAX_RT_PRIO-1;
+ break;
+ case SCHED_NORMAL:
+ case SCHED_BATCH:
+ case SCHED_ISO:
+ case SCHED_IDLEPRIO:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+/**
+ * sys_sched_get_priority_min - return minimum RT priority.
+ * @policy: scheduling class.
+ *
+ * Return: On success, this syscall returns the minimum
+ * rt_priority that can be used by a given scheduling class.
+ * On failure, a negative error code is returned.
+ */
+SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
+{
+ int ret = -EINVAL;
+
+ switch (policy) {
+ case SCHED_FIFO:
+ case SCHED_RR:
+ ret = 1;
+ break;
+ case SCHED_NORMAL:
+ case SCHED_BATCH:
+ case SCHED_ISO:
+ case SCHED_IDLEPRIO:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int sched_rr_get_interval(pid_t pid, struct timespec64 *t)
+{
+ struct task_struct *p;
+ unsigned int time_slice;
+ struct rq_flags rf;
+ struct rq *rq;
+ int retval;
+
+ if (pid < 0)
+ return -EINVAL;
+
+ retval = -ESRCH;
+ rcu_read_lock();
+ p = find_process_by_pid(pid);
+ if (!p)
+ goto out_unlock;
+
+ retval = security_task_getscheduler(p);
+ if (retval)
+ goto out_unlock;
+
+ rq = task_rq_lock(p, &rf);
+ time_slice = p->policy == SCHED_FIFO ? 0 : MS_TO_NS(task_timeslice(p));
+ task_rq_unlock(rq, p, &rf);
+
+ rcu_read_unlock();
+ *t = ns_to_timespec64(time_slice);
+ return 0;
+
+out_unlock:
+ rcu_read_unlock();
+ return retval;
+}
+
+/**
+ * sys_sched_rr_get_interval - return the default timeslice of a process.
+ * @pid: pid of the process.
+ * @interval: userspace pointer to the timeslice value.
+ *
+ * this syscall writes the default timeslice value of a given process
+ * into the user-space timespec buffer. A value of '0' means infinity.
+ *
+ * Return: On success, 0 and the timeslice is in @interval. Otherwise,
+ * an error code.
+ */
+SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
+ struct __kernel_timespec __user *, interval)
+{
+ struct timespec64 t;
+ int retval = sched_rr_get_interval(pid, &t);
+
+ if (retval == 0)
+ retval = put_timespec64(&t, interval);
+
+ return retval;
+}
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
+SYSCALL_DEFINE2(sched_rr_get_interval_time32, pid_t, pid,
+ struct old_timespec32 __user *, interval)
+{
+ struct timespec64 t;
+ int retval = sched_rr_get_interval(pid, &t);
+
+ if (retval == 0)
+ retval = put_old_timespec32(&t, interval);
+ return retval;
+}
+#endif
+
+void sched_show_task(struct task_struct *p)
+{
+ unsigned long free = 0;
+ int ppid;
+
+ if (!try_get_task_stack(p))
+ return;
+
+ printk(KERN_INFO "%-15.15s %c", p->comm, task_state_to_char(p));
+
+ if (p->__state == TASK_RUNNING)
+ printk(KERN_CONT " running task ");
+#ifdef CONFIG_DEBUG_STACK_USAGE
+ free = stack_not_used(p);
+#endif
+ ppid = 0;
+ rcu_read_lock();
+ if (pid_alive(p))
+ ppid = task_pid_nr(rcu_dereference(p->real_parent));
+ rcu_read_unlock();
+ pr_cont(" stack:%5lu pid:%5d ppid:%6d flags:0x%08lx\n",
+ free, task_pid_nr(p), ppid,
+ (unsigned long)task_thread_info(p)->flags);
+
+ print_worker_info(KERN_INFO, p);
+ print_stop_info(KERN_INFO, p);
+ show_stack(p, NULL, KERN_INFO);
+ put_task_stack(p);
+}
+EXPORT_SYMBOL_GPL(sched_show_task);
+
+static inline bool
+state_filter_match(unsigned long state_filter, struct task_struct *p)
+{
+ /* no filter, everything matches */
+ if (!state_filter)
+ return true;
+
+ /* filter, but doesn't match */
+ if (!(p->__state & state_filter))
+ return false;
+
+ /*
+ * When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows
+ * TASK_KILLABLE).
+ */
+ if (state_filter == TASK_UNINTERRUPTIBLE && p->__state == TASK_IDLE)
+ return false;
+
+ return true;
+}
+
+void show_state_filter(unsigned int state_filter)
+{
+ struct task_struct *g, *p;
+
+ rcu_read_lock();
+ for_each_process_thread(g, p) {
+ /*
+ * reset the NMI-timeout, listing all files on a slow
+ * console might take a lot of time:
+ * Also, reset softlockup watchdogs on all CPUs, because
+ * another CPU might be blocked waiting for us to process
+ * an IPI.
+ */
+ touch_nmi_watchdog();
+ touch_all_softlockup_watchdogs();
+ if (state_filter_match(state_filter, p))
+ sched_show_task(p);
+ }
+
+ rcu_read_unlock();
+ /*
+ * Only show locks if all tasks are dumped:
+ */
+ if (!state_filter)
+ debug_show_all_locks();
+}
+
+void dump_cpu_task(int cpu)
+{
+ pr_info("Task dump for CPU %d:\n", cpu);
+ sched_show_task(cpu_curr(cpu));
+}
+
+#ifdef CONFIG_SMP
+void set_cpus_allowed_common(struct task_struct *p, struct affinity_context *ctx)
+{
+ if (ctx->flags & (SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE)) {
+ p->cpus_ptr = ctx->new_mask;
+ return;
+ }
+
+ cpumask_copy(&p->cpus_mask, ctx->new_mask);
+ p->nr_cpus_allowed = cpumask_weight(ctx->new_mask);
+}
+
+void
+__do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx)
+{
+ struct rq *rq = task_rq(p);
+
+ lockdep_assert_held(&p->pi_lock);
+
+ /*
+ * Keep cpus_mask and nr_cpus_allowed in lockstep. sched_other_cpu()
+ * relies on nr_cpus_allowed == 1 to allow hotplug kthreads bound to
+ * offline CPUs to still be picked on an online runqueue.
+ */
+ set_cpus_allowed_common(p, ctx);
+
+ if (task_queued(p)) {
+ /*
+ * Because __kthread_bind() calls this on blocked tasks without
+ * holding rq->lock.
+ */
+ lockdep_assert_held(rq->lock);
+ }
+}
+
+static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,
+ struct task_struct *p, int new_cpu);
+
+/*
+ * Calling do_set_cpus_allowed from outside the scheduler code should not be
+ * called on a running or queued task. We should be holding pi_lock.
+ */
+void do_set_cpus_allowed(struct task_struct *p, struct affinity_context *ctx)
+{
+ __do_set_cpus_allowed(p, ctx);
+
+ /*
+ * A mask forced by cpuset or kthread_bind is a change of what the
+ * task wants, so an override bind_zero() had to make must not be
+ * restored over the top of it later. What was saved is left in place
+ * rather than freed, which here would be under pi_lock.
+ */
+ if (ctx->flags & SCA_USER)
+ p->zerobound = false;
+
+ if (needs_other_cpu(p, task_cpu(p))) {
+ struct rq *rq;
+
+ rq = __task_rq_lock(p, NULL);
+ /*
+ * A blocked task is on no runqueue, so task_cpu() only says
+ * which rq lock protects it and which CPU PSI counts its state
+ * on. It is left exactly as it is.
+ *
+ * Moving it would leave the TSK_IOWAIT it is carrying counted
+ * on the CPU it came from, and the wakeup would then clear it
+ * on a CPU that never counted it and underflow that counter.
+ * Nor may the destination be recorded in wake_cpu: that is not
+ * a hint, it is the bit that arms the lazy migration handshake.
+ * return_task() reads wake_cpu != task_cpu() as "set_task_cpu()
+ * moved this running task, hand it over in
+ * finish_lock_switch()", so stamping it here arms a migration
+ * no one arranged. Widening the mask again before the task
+ * wakes is enough to leave it armed, since ttwu only calls
+ * set_task_cpu() - the one place that resyncs wake_cpu - when
+ * it picks a different CPU, and a wakeup back onto task_cpu()
+ * therefore keeps the stale value until the next deschedule
+ * migrates the task out from under the switch.
+ *
+ * Nothing needs either. select_best_cpu() honours the new mask
+ * when the task wakes and set_task_cpu() takes the PSI state
+ * with it, which is why affine_move_task() leaves a blocked
+ * task alone here as well.
+ */
+ if (task_running(rq, p)) {
+ /*
+ * A running task is not on any skiplist, so
+ * set_task_cpu() only tags wake_cpu for it; resched_task()
+ * gets it off the CPU so finish_lock_switch() can
+ * complete the move.
+ */
+ set_task_cpu(p, valid_task_cpu(p));
+ resched_task(p);
+ } else if (task_queued(p)) {
+ /*
+ * A queued task's skiplist node is linked into this
+ * rq's list, so its CPU must not be rewritten
+ * underneath it: task_rq(p) would then name a runqueue
+ * the node is not in, and the next dequeue_task() would
+ * try to unlink it from there and trip
+ * skiplist_delete()'s "m < 0" while leaving the node
+ * linked in the list it really is on. Unlink it first,
+ * exactly as every other migration of a queued task
+ * does.
+ */
+ rq = move_queued_task(rq, NULL, p, valid_task_cpu(p));
+ }
+ __task_rq_unlock(rq, p, NULL);
+ }
+}
+
+/* migrate_disable()/migrate_enable() are inline in <linux/sched.h> now. */
+#endif
+
+/**
+ * init_idle - set up an idle thread for a given CPU
+ * @idle: task in question
+ * @cpu: cpu the idle task belongs to
+ *
+ * NOTE: this function does not set the idle thread's NEED_RESCHED
+ * flag, to make booting more robust.
+ */
+void init_idle(struct task_struct *idle, int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&idle->pi_lock, flags);
+ raw_spin_lock(rq->lock);
+ idle->last_ran = rq->niffies;
+ time_slice_expired(idle, rq);
+ idle->__state = TASK_RUNNING;
+ /* Setting prio to illegal value shouldn't matter when never queued */
+ idle->prio = PRIO_LIMIT;
+ idle->flags |= PF_IDLE;
+
+ scs_task_reset(idle);
+ kasan_unpoison_task_stack(idle);
+
+#ifdef CONFIG_SMP
+ /*
+ * It's possible that init_idle() gets called multiple times on a task,
+ * in that case do_set_cpus_allowed() will not do the right thing.
+ *
+ * And since this is boot we can forgo the serialisation.
+ */
+ {
+ struct affinity_context ac = { .new_mask = cpumask_of(cpu) };
+
+ set_cpus_allowed_common(idle, &ac);
+ }
+#ifdef CONFIG_SMT_NICE
+ idle->smt_bias = 0;
+#endif
+#endif
+ set_rq_task(rq, idle);
+
+ /* Silence PROVE_RCU */
+ rcu_read_lock();
+ set_task_cpu(idle, cpu);
+ rcu_read_unlock();
+
+ rq->idle = idle;
+ rcu_assign_pointer(rq->curr, idle);
+ idle->on_rq = TASK_ON_RQ_QUEUED;
+ raw_spin_unlock(rq->lock);
+ raw_spin_unlock_irqrestore(&idle->pi_lock, flags);
+
+ /* Set the preempt count _outside_ the spinlocks! */
+ init_idle_preempt_count(idle, cpu);
+
+ ftrace_graph_init_idle_task(idle, cpu);
+ vtime_init_idle(idle, cpu);
+#ifdef CONFIG_SMP
+ sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu);
+#endif
+}
+
+int cpuset_cpumask_can_shrink(const struct cpumask __maybe_unused *cur,
+ const struct cpumask __maybe_unused *trial)
+{
+ return 1;
+}
+
+int task_can_attach(struct task_struct *p)
+{
+ int ret = 0;
+
+ /*
+ * Kthreads which disallow setaffinity shouldn't be moved
+ * to a new cpuset; we don't want to change their CPU
+ * affinity and isolating such threads by their set of
+ * allowed nodes is unnecessary. Thus, cpusets are not
+ * applicable for such threads. This prevents checking for
+ * success of set_cpus_allowed_ptr() on all attached tasks
+ * before cpus_mask may be changed.
+ */
+ if (p->flags & PF_NO_SETAFFINITY)
+ ret = -EINVAL;
+
+ return ret;
+}
+
+void resched_cpu(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ struct rq_flags rf;
+
+ rq_lock_irqsave(rq, &rf);
+ if (cpu_online(cpu) || cpu == smp_processor_id())
+ resched_curr(rq);
+ rq_unlock_irqrestore(rq, &rf);
+}
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_NO_HZ_COMMON
+void nohz_balance_enter_idle(int cpu) {}
+
+/*
+ * In the semi idle case, use the nearest busy CPU for migrating timers
+ * from an idle CPU. This is good for power-savings.
+ *
+ * We don't do similar optimization for completely idle system, as
+ * selecting an idle CPU will add more delays to the timers than intended
+ * (as that CPU's timer base may not be uptodate wrt jiffies etc).
+ */
+int get_nohz_timer_target(void)
+{
+ int i, cpu = smp_processor_id(), default_cpu = -1;
+ struct sched_domain *sd;
+
+ if (housekeeping_cpu(cpu, HK_TYPE_TIMER)) {
+ if (!idle_cpu(cpu))
+ return cpu;
+ default_cpu = cpu;
+ }
+
+ rcu_read_lock();
+ for_each_domain(cpu, sd) {
+ for_each_cpu_and(i, sched_domain_span(sd),
+ housekeeping_cpumask(HK_TYPE_TIMER)) {
+ if (cpu == i)
+ continue;
+
+ if (!idle_cpu(i)) {
+ cpu = i;
+ goto unlock;
+ }
+ }
+ }
+
+ if (default_cpu == -1)
+ default_cpu = housekeeping_any_cpu(HK_TYPE_TIMER);
+ cpu = default_cpu;
+unlock:
+ rcu_read_unlock();
+ return cpu;
+}
+
+/*
+ * When add_timer_on() enqueues a timer into the timer wheel of an
+ * idle CPU then this timer might expire before the next timer event
+ * which is scheduled to wake up that CPU. In case of a completely
+ * idle system the next event might even be infinite time into the
+ * future. wake_up_idle_cpu() ensures that the CPU is woken up and
+ * leaves the inner idle loop so the newly added timer is taken into
+ * account when the CPU goes back to idle and evaluates the timer
+ * wheel for the next timer event.
+ */
+static void wake_up_idle_cpu(int cpu)
+{
+ if (cpu == smp_processor_id())
+ return;
+
+ if (set_nr_and_not_polling(cpu_rq(cpu)->idle))
+ smp_sched_reschedule(cpu);
+ else
+ trace_sched_wake_idle_without_ipi(cpu);
+}
+
+static bool wake_up_full_nohz_cpu(int cpu)
+{
+ /*
+ * We just need the target to call irq_exit() and re-evaluate
+ * the next tick. The nohz full kick at least implies that.
+ * If needed we can still optimize that later with an
+ * empty IRQ.
+ */
+ if (cpu_is_offline(cpu))
+ return true; /* Don't try to wake offline CPUs. */
+ if (tick_nohz_full_cpu(cpu)) {
+ if (cpu != smp_processor_id() ||
+ tick_nohz_tick_stopped())
+ tick_nohz_full_kick_cpu(cpu);
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Wake up the specified CPU. If the CPU is going offline, it is the
+ * caller's responsibility to deal with the lost wakeup, for example,
+ * by hooking into the CPU_DEAD notifier like timers and hrtimers do.
+ */
+void wake_up_nohz_cpu(int cpu)
+{
+ if (!wake_up_full_nohz_cpu(cpu))
+ wake_up_idle_cpu(cpu);
+}
+#endif /* CONFIG_NO_HZ_COMMON */
+
+/*
+ * This is how migration works:
+ *
+ * 1) we invoke migration_cpu_stop() on the target CPU using
+ * stop_one_cpu().
+ * 2) stopper starts to run (implicitly forcing the migrated thread
+ * off the CPU)
+ * 3) it checks whether the migrated task is still in the wrong runqueue.
+ * 4) if it's in the wrong runqueue then the migration thread removes
+ * it and puts it into the right queue.
+ * 5) stopper completes and stop_one_cpu() returns and the migration
+ * is done.
+ */
+
+/*
+ * move_queued_task - move a queued task to new rq.
+ *
+ * Returns (locked) new rq. Old rq's lock is released. Running tasks
+ * are not on the skiplist, so callers must use task_queued().
+ */
+static struct rq *move_queued_task(struct rq *rq,
+ struct rq_flags __always_unused *rf,
+ struct task_struct *p, int new_cpu)
+{
+ lockdep_assert_held(rq->lock);
+
+ dequeue_task(rq, p, 0);
+ set_task_cpu(p, new_cpu);
+ rq_unlock(rq);
+
+ rq = cpu_rq(new_cpu);
+
+ rq_lock(rq);
+ WARN_ON_ONCE(task_cpu(p) != new_cpu);
+ enqueue_task(rq, p, ENQUEUE_MIGRATED);
+ try_preempt(p, rq);
+
+ return rq;
+}
+
+struct set_affinity_pending;
+
+struct migration_arg {
+ struct task_struct *task;
+ int dest_cpu;
+ struct set_affinity_pending *pending;
+};
+
+/*
+ * @refs: number of wait_for_completion()
+ * @stop_pending: is @stop_work in use
+ */
+struct set_affinity_pending {
+ refcount_t refs;
+ unsigned int stop_pending;
+ struct completion done;
+ struct cpu_stop_work stop_work;
+ struct migration_arg arg;
+};
+
+static struct rq *__migrate_task(struct rq *rq, struct rq_flags *rf,
+ struct task_struct *p, int dest_cpu)
+{
+ /* Affinity changed (again). */
+ if (!is_cpu_allowed(p, dest_cpu))
+ return rq;
+
+ return move_queued_task(rq, rf, p, dest_cpu);
+}
+
+static int migration_cpu_stop(void *data)
+{
+ struct migration_arg *arg = data;
+ struct set_affinity_pending *pending = arg->pending;
+ struct task_struct *p = arg->task;
+ struct rq *rq = this_rq();
+ bool complete = false;
+ struct rq_flags rf;
+
+ /*
+ * The original target CPU might have gone down and we might
+ * be on another CPU but it doesn't matter.
+ */
+ local_irq_save(rf.flags);
+ /*
+ * Flush pending wakeups so we do not miss enforcing cpus_ptr,
+ * see set_cpus_allowed_ptr()'s TASK_WAKING test.
+ */
+ flush_smp_call_function_queue();
+
+ raw_spin_lock(&p->pi_lock);
+ rq_lock(rq);
+
+ /*
+ * If we were passed a pending, then ->stop_pending was set, thus
+ * p->migration_pending must have remained stable.
+ */
+ WARN_ON_ONCE(pending && pending != p->migration_pending);
+
+ /*
+ * If task_rq(p) != rq, it cannot be migrated here, because we're
+ * holding rq->lock. If p is not queued it cannot get enqueued
+ * because we're holding p->pi_lock.
+ */
+ if (task_rq(p) == rq) {
+ if (is_migration_disabled(p))
+ goto out;
+
+ if (pending) {
+ p->migration_pending = NULL;
+ complete = true;
+
+ if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask))
+ goto out;
+ }
+
+ /*
+ * Mainline updates the rq clock before __migrate_task() here.
+ * MuQSS has no need to: dequeue_task() and enqueue_task() each
+ * call update_clocks() on the runqueue they touch, so niffies,
+ * which deadlines are based on, is current on both sides of
+ * the migration. Adding one here would only be redundant.
+ */
+ if (task_queued(p))
+ rq = __migrate_task(rq, &rf, p, arg->dest_cpu);
+ else
+ p->wake_cpu = arg->dest_cpu;
+ } else if (pending) {
+ /*
+ * The task moved before the stopper got to run. We're
+ * holding ->pi_lock, so the allowed mask is stable - if
+ * it got somewhere allowed, we're done.
+ */
+ if (cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
+ p->migration_pending = NULL;
+ complete = true;
+ goto out;
+ }
+
+ /*
+ * When migrate_enable() hits a rq mis-match we can't
+ * reliably determine is_migration_disabled() and so
+ * have to chase after it.
+ */
+ WARN_ON_ONCE(!pending->stop_pending);
+ preempt_disable();
+ rq_unlock(rq);
+ raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags);
+ stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop,
+ &pending->arg, &pending->stop_work);
+ preempt_enable();
+ return 0;
+ }
+out:
+ if (pending)
+ pending->stop_pending = false;
+ rq_unlock(rq);
+ raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags);
+
+ if (complete)
+ complete_all(&pending->done);
+
+ return 0;
+}
+
+/*
+ * When given a valid mask, __set_cpus_allowed_ptr() must block until
+ * the designated task is enqueued on an allowed CPU. A running task
+ * is kicked off with the CPU stopper. A migrate_disable() region on
+ * the target delays that move until the outermost migrate_enable();
+ * concurrent waiters share one set_affinity_pending.
+ */
+static int affine_move_task(struct rq *rq, struct task_struct *p,
+ struct rq_flags *rf, int dest_cpu, unsigned int flags)
+{
+ struct set_affinity_pending my_pending = { }, *pending = NULL;
+ bool stop_pending, complete = false;
+
+ /* Can the task run on the task's current CPU? If so, we're done */
+ if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask)) {
+ /*
+ * If there are pending waiters, but no pending stop_work,
+ * then complete now.
+ */
+ pending = p->migration_pending;
+ if (pending && !pending->stop_pending) {
+ p->migration_pending = NULL;
+ complete = true;
+ }
+
+ task_rq_unlock(rq, p, rf);
+
+ if (complete)
+ complete_all(&pending->done);
+
+ return 0;
+ }
+
+ if (!(flags & SCA_MIGRATE_ENABLE)) {
+ /* serialized by p->pi_lock */
+ if (!p->migration_pending) {
+ refcount_set(&my_pending.refs, 1);
+ init_completion(&my_pending.done);
+ my_pending.arg = (struct migration_arg) {
+ .task = p,
+ .dest_cpu = dest_cpu,
+ .pending = &my_pending,
+ };
+
+ p->migration_pending = &my_pending;
+ } else {
+ pending = p->migration_pending;
+ refcount_inc(&pending->refs);
+ /*
+ * Affinity has changed, but we've already installed a
+ * pending. migration_cpu_stop() *must* see this, else
+ * we risk completing despite a task on a disallowed
+ * CPU. Serialized by p->pi_lock.
+ */
+ pending->arg.dest_cpu = dest_cpu;
+ }
+ }
+ pending = p->migration_pending;
+ /*
+ * !MIGRATE_ENABLE installs a pending if there wasn't one.
+ * MIGRATE_ENABLE only gets here because the current CPU no
+ * longer matches, so a concurrent set_cpus_allowed_ptr()
+ * should still be pending completion.
+ */
+ if (WARN_ON_ONCE(!pending)) {
+ task_rq_unlock(rq, p, rf);
+ return -EINVAL;
+ }
+
+ if (task_running(rq, p) || READ_ONCE(p->__state) == TASK_WAKING) {
+ /*
+ * MIGRATE_ENABLE gets here because 'p == current'. For
+ * anything else we cannot do is_migration_disabled();
+ * punt and have the stopper handle it race-free.
+ */
+ stop_pending = pending->stop_pending;
+ if (!stop_pending)
+ pending->stop_pending = true;
+
+ preempt_disable();
+ task_rq_unlock(rq, p, rf);
+ if (!stop_pending) {
+ stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
+ &pending->arg, &pending->stop_work);
+ }
+ preempt_enable();
+
+ if (flags & SCA_MIGRATE_ENABLE)
+ return 0;
+ } else {
+ if (!is_migration_disabled(p)) {
+ if (task_queued(p))
+ rq = move_queued_task(rq, rf, p, dest_cpu);
+
+ if (!pending->stop_pending) {
+ p->migration_pending = NULL;
+ complete = true;
+ }
+ }
+ task_rq_unlock(rq, p, rf);
+
+ if (complete)
+ complete_all(&pending->done);
+ }
+
+ wait_for_completion(&pending->done);
+
+ if (refcount_dec_and_test(&pending->refs))
+ wake_up_var(&pending->refs); /* No UaF, just an address */
+
+ /*
+ * Block the original owner of &pending until all subsequent
+ * callers have seen the completion and decremented the refcount
+ */
+ wait_var_event(&my_pending.refs, !refcount_read(&my_pending.refs));
+
+ WARN_ON_ONCE(my_pending.stop_pending);
+
+ return 0;
+}
+
+/*
+ * Record @new_mask as the affinity userspace asked for, handing back the
+ * allocation it displaced for the caller to free once the locks are
+ * dropped. An explicit request also supersedes any override bind_zero()
+ * had to force, since this mask is the one that is wanted now.
+ */
+static cpumask_t *set_user_cpus_ptr(struct task_struct *p,
+ const struct cpumask *new_mask,
+ cpumask_t *user_mask)
+{
+ lockdep_assert_held(&p->pi_lock);
+
+ if (user_mask) {
+ cpumask_copy(user_mask, new_mask);
+ swap(p->user_cpus_ptr, user_mask);
+ }
+ p->zerobound = false;
+
+ return user_mask;
+}
+
+/*
+ * Change a given task's CPU affinity. Migrate the thread to a
+ * proper CPU and schedule it away if the CPU it's executing on
+ * is removed from the allowed bitmask.
+ *
+ * NOTE: the caller must have a valid reference to the task, the
+ * task must not exit() & deallocate itself prematurely. The
+ * call is not atomic; no spinlocks may be held.
+ */
+static int __set_cpus_allowed_ptr(struct task_struct *p,
+ const struct cpumask *new_mask,
+ u32 flags)
+{
+ const struct cpumask *cpu_valid_mask = cpu_active_mask;
+ cpumask_t *user_mask = NULL;
+ unsigned int dest_cpu;
+ struct rq_flags rf;
+ struct rq *rq;
+ int ret = 0;
+
+ /*
+ * user_cpus_ptr keeps what userspace asked for so that
+ * relax_compatible_cpus_allowed_ptr() and unbind_zero() have
+ * something to put back. Only sched_setaffinity() passes SCA_USER
+ * and it is always sleepable, so make room before taking any lock;
+ * failing here only costs the task that restore, not the syscall.
+ */
+ if (flags & SCA_USER)
+ user_mask = kmalloc(cpumask_size(), GFP_KERNEL);
+
+ rq = task_rq_lock(p, &rf);
+ update_rq_clock(rq);
+
+ if ((p->flags & PF_KTHREAD) || is_migration_disabled(p)) {
+ /*
+ * Kernel threads are allowed on online && !active CPUs.
+ * migrate_disabled() tasks must not fail the dest pick
+ * on SCA_MIGRATE_ENABLE or we skip set_cpus_allowed_common()
+ * and never reset p->cpus_ptr.
+ */
+ cpu_valid_mask = cpu_online_mask;
+ }
+
+ /*
+ * Must re-check here, to close a race against __kthread_bind(),
+ * sched_setaffinity() is not guaranteed to observe the flag.
+ */
+ if ((flags & SCA_CHECK) && (p->flags & PF_NO_SETAFFINITY)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!(flags & SCA_MIGRATE_ENABLE)) {
+ if (cpumask_equal(&p->cpus_mask, new_mask)) {
+ /*
+ * Nothing to change, but asking for exactly the mask
+ * bind_zero() forced is still userspace choosing it,
+ * and takes over from the restore. An internal caller
+ * changing nothing must not cost the task that.
+ */
+ if (flags & SCA_USER)
+ user_mask = set_user_cpus_ptr(p, new_mask,
+ user_mask);
+ goto out;
+ }
+
+ if (WARN_ON_ONCE(p == current &&
+ is_migration_disabled(p) &&
+ !cpumask_test_cpu(task_cpu(p), new_mask))) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ /*
+ * Picking a ~random cpu helps in cases where we are changing affinity
+ * for groups of tasks (ie. cpuset), so that load balancing is not
+ * immediately required to distribute the tasks within their new mask.
+ */
+ dest_cpu = cpumask_any_and_distribute(cpu_valid_mask, new_mask);
+ if (dest_cpu >= nr_cpu_ids) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ {
+ struct affinity_context ac = {
+ .new_mask = new_mask,
+ .flags = flags,
+ };
+
+ __do_set_cpus_allowed(p, &ac);
+ }
+
+ /*
+ * migrate_enable() only reinstates cpus_mask, so it is not a change
+ * of what the task wants and must not disturb what is saved.
+ */
+ if (!(flags & SCA_MIGRATE_ENABLE))
+ user_mask = set_user_cpus_ptr(p, new_mask, user_mask);
+
+ if (p->flags & PF_KTHREAD) {
+ /*
+ * For kernel threads that do indeed end up on online &&
+ * !active we want to ensure they are strict per-CPU threads.
+ */
+ WARN_ON(cpumask_intersects(new_mask, cpu_online_mask) &&
+ !cpumask_intersects(new_mask, cpu_active_mask) &&
+ p->nr_cpus_allowed != 1);
+ }
+
+ ret = affine_move_task(rq, p, &rf, dest_cpu, flags);
+ kfree(user_mask);
+
+ return ret;
+
+out:
+ task_rq_unlock(rq, p, &rf);
+ kfree(user_mask);
+
+ return ret;
+}
+
+int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
+{
+ return __set_cpus_allowed_ptr(p, new_mask, 0);
+}
+EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Skip affinity rewrite for tasks whose mask is managed elsewhere: the
+ * hotplug/stopper threads, idle, and kthreads that forbid setaffinity
+ * (including KTHREAD_IS_PER_CPU, rebound on unpark).
+ */
+static bool bind_zero_skip_affinity(struct task_struct *p, struct rq *rq)
+{
+ return p == current || is_idle_task(p) || p == rq->stop ||
+ (p->flags & PF_NO_SETAFFINITY) || kthread_is_per_cpu(p);
+}
+
+/*
+ * Move @p off @src_cpu under pi+rq lock, and only override its affinity
+ * if losing @src_cpu would leave it with no active CPU at all.
+ *
+ * Like mainline, the common case does not touch cpus_mask: an offline or
+ * deactivated CPU is already refused by is_cpu_allowed(), sched_other_cpu(),
+ * needs_other_cpu() and valid_task_cpu(), so the mask needs no editing and
+ * the task keeps the affinity userspace asked for across a hotplug cycle.
+ * Narrowing here would be permanent, as unbind_zero() only restores tasks
+ * that were forced.
+ *
+ * The desperate case still has to put the task somewhere: substitute an
+ * active fallback (usually CPU0) for @src_cpu and record that with
+ * zerobound, stashing the mask being replaced in user_cpus_ptr so
+ * unbind_zero() can put back exactly what userspace asked for once
+ * @src_cpu returns.
+ *
+ * migrate_disable() tasks keep their pin (cpus_ptr) and are left for
+ * wait_empty to wait out; only cpus_mask is updated so migrate_enable()
+ * will affine_move them.
+ */
+static int bind_zero_one(struct task_struct *p, int src_cpu)
+{
+ cpumask_t *user_mask, new_mask;
+ struct rq_flags rf;
+ struct rq *rq;
+ int dest, bound = 0;
+
+ /*
+ * The override below cannot allocate under the runqueue lock, so
+ * speculatively provide it room for the old mask here. Almost every
+ * task takes the fast path and hands this straight back.
+ */
+ user_mask = kmalloc(cpumask_size(), GFP_ATOMIC);
+
+ rq = task_rq_lock(p, &rf);
+
+ if (!bind_zero_skip_affinity(p, rq) &&
+ cpumask_test_cpu(src_cpu, &p->cpus_mask)) {
+ cpumask_copy(&new_mask, &p->cpus_mask);
+ cpumask_clear_cpu(src_cpu, &new_mask);
+ if (!cpumask_intersects(&new_mask, cpu_active_mask)) {
+ dest = cpumask_any(cpu_active_mask);
+ if (dest >= nr_cpu_ids)
+ dest = cpumask_any(cpu_online_mask);
+ if (dest < nr_cpu_ids) {
+ struct affinity_context ac = {
+ .new_mask = &new_mask
+ };
+
+ /*
+ * Only the first override saves; a second one
+ * would only be replacing an already forced
+ * mask with another. What is being displaced
+ * is what has to come back, so it takes over
+ * any mask sched_setaffinity() left here -
+ * reusing its allocation - rather than let a
+ * request cpusets have since narrowed be
+ * restored wider than the cpuset allows.
+ */
+ if (!p->zerobound) {
+ if (p->user_cpus_ptr) {
+ cpumask_copy(p->user_cpus_ptr,
+ &p->cpus_mask);
+ } else if (user_mask) {
+ cpumask_copy(user_mask,
+ &p->cpus_mask);
+ p->user_cpus_ptr = user_mask;
+ user_mask = NULL;
+ }
+ }
+ cpumask_set_cpu(dest, &new_mask);
+ p->zerobound = true;
+ __do_set_cpus_allowed(p, &ac);
+ bound = 1;
+ }
+ }
+ }
+
+ if (task_cpu(p) == src_cpu && p != current &&
+ !is_idle_task(p) && p != rq->stop &&
+ !is_migration_disabled(p)) {
+ dest = valid_task_cpu(p);
+ if (dest != src_cpu) {
+ /*
+ * Only a queued task has to be moved. A blocked one is
+ * on no runqueue, so it does not hold @src_cpu up, and
+ * its destination must not be stamped into wake_cpu:
+ * that arms return_task()'s migration handshake, which
+ * would then fire on a task nobody is migrating. Its
+ * wakeup picks an allowed CPU by itself.
+ */
+ if (task_queued(p))
+ rq = move_queued_task(rq, &rf, p, dest);
+ }
+ }
+
+ task_rq_unlock(rq, p, &rf);
+ kfree(user_mask);
+ return bound;
+}
+
+/*
+ * Called from sched_cpu_wait_empty() (sleepable) on the outgoing CPU.
+ * Walk every task and move anyone still queued here. Affinity is only
+ * overridden for the few tasks @src_cpu leaving would otherwise strand,
+ * so on a normal offline this reports nothing.
+ */
+static void bind_zero(int src_cpu)
+{
+ struct task_struct *g, *p;
+ int bound = 0;
+
+ if (src_cpu == 0)
+ return;
+
+ rcu_read_lock();
+ for_each_process_thread(g, p) {
+ if (task_cpu(p) != src_cpu &&
+ !cpumask_test_cpu(src_cpu, p->cpus_ptr) &&
+ !cpumask_test_cpu(src_cpu, &p->cpus_mask))
+ continue;
+ bound += bind_zero_one(p, src_cpu);
+ }
+ rcu_read_unlock();
+
+ if (bound) {
+ printk(KERN_INFO "MuQSS overrode affinity for %d processes left with no active cpu by offlining cpu %d\n",
+ bound, src_cpu);
+ }
+}
+
+/*
+ * Undo the affinity override bind_zero() had to force onto tasks that
+ * @src_cpu leaving would have stranded. Hold pi+rq so cpus_mask /
+ * nr_cpus_allowed stay in lockstep. Unbound kthreads are eligible — only
+ * per-CPU / PF_NO_SETAFFINITY threads were skipped on the way out.
+ *
+ * Restoring the saved mask can take the CPU the task is on right now away
+ * from it, so kick it off exactly like do_set_cpus_allowed() does.
+ */
+static void unbind_zero(int src_cpu)
+{
+ int restored = 0, unbound = 0;
+ struct task_struct *g, *p;
+
+ if (src_cpu == 0)
+ return;
+
+ rcu_read_lock();
+ for_each_process_thread(g, p) {
+ struct rq_flags rf;
+ struct rq *rq;
+
+ if (!p->zerobound)
+ continue;
+
+ rq = task_rq_lock(p, &rf);
+ if (!p->zerobound) {
+ task_rq_unlock(rq, p, &rf);
+ continue;
+ }
+
+ if (likely(p->user_cpus_ptr)) {
+ /*
+ * Wait for one of the CPUs the task actually wanted,
+ * or restoring would strand it all over again. The
+ * saved mask stays put once copied back: it is still
+ * what the task wants, and what a later override or
+ * relax_compatible_cpus_allowed_ptr() restores.
+ */
+ if (cpumask_test_cpu(src_cpu, p->user_cpus_ptr)) {
+ struct affinity_context ac = {
+ .new_mask = p->user_cpus_ptr
+ };
+
+ __do_set_cpus_allowed(p, &ac);
+ p->zerobound = false;
+ restored++;
+ }
+ } else if (!cpumask_test_cpu(src_cpu, &p->cpus_mask)) {
+ /*
+ * bind_zero() had no room to save the old mask, so
+ * hand @src_cpu back and stop there rather than
+ * accumulate every CPU that ever comes online.
+ */
+ cpumask_set_cpu(src_cpu, &p->cpus_mask);
+ p->nr_cpus_allowed = cpumask_weight(&p->cpus_mask);
+ p->zerobound = false;
+ unbound++;
+ }
+
+ if (!p->zerobound && needs_other_cpu(p, task_cpu(p))) {
+ int dest = valid_task_cpu(p);
+
+ /*
+ * As in bind_zero_one(), a blocked task is left alone
+ * rather than having @dest stamped into its wake_cpu,
+ * which would arm return_task()'s migration handshake
+ * for a migration that is not happening.
+ */
+ if (task_queued(p))
+ rq = move_queued_task(rq, &rf, p, dest);
+ else if (task_running(rq, p)) {
+ set_task_cpu(p, dest);
+ resched_task(p);
+ }
+ }
+
+ task_rq_unlock(rq, p, &rf);
+ }
+ rcu_read_unlock();
+
+ if (restored) {
+ printk(KERN_INFO "MuQSS restored the original affinity of %d processes by onlining cpu %d\n",
+ restored, src_cpu);
+ }
+ if (unbound) {
+ printk(KERN_INFO "MuQSS added affinity for %d processes to cpu %d\n",
+ unbound, src_cpu);
+ }
+}
+
+/*
+ * idle_task_exit() is an empty inline in <linux/sched/hotplug.h> now; the
+ * outgoing CPU switches back to init_mm from sched_cpu_wait_empty() instead.
+ */
+#else /* CONFIG_HOTPLUG_CPU */
+static void unbind_zero(int src_cpu) {}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+void sched_set_stop_task(int cpu, struct task_struct *stop)
+{
+ struct sched_param stop_param = { .sched_priority = STOP_PRIO };
+ struct sched_param start_param = { .sched_priority = 0 };
+ struct task_struct *old_stop = cpu_rq(cpu)->stop;
+
+ if (stop) {
+ /*
+ * Make it appear like a SCHED_FIFO task, its something
+ * userspace knows about and won't get confused about.
+ *
+ * Also, it will make PI more or less work without too
+ * much confusion -- but then, stop work should not
+ * rely on PI working anyway.
+ */
+ sched_setscheduler_nocheck(stop, SCHED_FIFO, &stop_param);
+ }
+
+ cpu_rq(cpu)->stop = stop;
+
+ if (old_stop) {
+ /*
+ * Reset it back to a normal scheduling policy so that
+ * it can die in pieces.
+ */
+ sched_setscheduler_nocheck(old_stop, SCHED_NORMAL, &start_param);
+ }
+}
+
+#if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL)
+
+static struct ctl_table sd_ctl_dir[] = {
+ {
+ .procname = "sched_domain",
+ .mode = 0555,
+ },
+ {}
+};
+
+static struct ctl_table sd_ctl_root[] = {
+ {
+ .procname = "kernel",
+ .mode = 0555,
+ .child = sd_ctl_dir,
+ },
+ {}
+};
+
+static struct ctl_table *sd_alloc_ctl_entry(int n)
+{
+ struct ctl_table *entry =
+ kcalloc(n, sizeof(struct ctl_table), GFP_KERNEL);
+
+ return entry;
+}
+
+static void sd_free_ctl_entry(struct ctl_table **tablep)
+{
+ struct ctl_table *entry;
+
+ /*
+ * In the intermediate directories, both the child directory and
+ * procname are dynamically allocated and could fail but the mode
+ * will always be set. In the lowest directory the names are
+ * static strings and all have proc handlers.
+ */
+ for (entry = *tablep; entry->mode; entry++) {
+ if (entry->child)
+ sd_free_ctl_entry(&entry->child);
+ if (entry->proc_handler == NULL)
+ kfree(entry->procname);
+ }
+
+ kfree(*tablep);
+ *tablep = NULL;
+}
+
+static void
+set_table_entry(struct ctl_table *entry,
+ const char *procname, void *data, int maxlen,
+ umode_t mode, proc_handler *proc_handler)
+{
+ entry->procname = procname;
+ entry->data = data;
+ entry->maxlen = maxlen;
+ entry->mode = mode;
+ entry->proc_handler = proc_handler;
+}
+
+static struct ctl_table *
+sd_alloc_ctl_domain_table(struct sched_domain *sd)
+{
+ struct ctl_table *table = sd_alloc_ctl_entry(9);
+
+ if (table == NULL)
+ return NULL;
+
+ set_table_entry(&table[0], "min_interval", &sd->min_interval, sizeof(long), 0644, proc_doulongvec_minmax);
+ set_table_entry(&table[1], "max_interval", &sd->max_interval, sizeof(long), 0644, proc_doulongvec_minmax);
+ set_table_entry(&table[2], "busy_factor", &sd->busy_factor, sizeof(int), 0644, proc_dointvec_minmax);
+ set_table_entry(&table[3], "imbalance_pct", &sd->imbalance_pct, sizeof(int), 0644, proc_dointvec_minmax);
+ set_table_entry(&table[4], "cache_nice_tries", &sd->cache_nice_tries, sizeof(int), 0644, proc_dointvec_minmax);
+ set_table_entry(&table[5], "flags", &sd->flags, sizeof(int), 0644, proc_dointvec_minmax);
+ set_table_entry(&table[6], "max_newidle_lb_cost", &sd->max_newidle_lb_cost, sizeof(long), 0644, proc_doulongvec_minmax);
+ set_table_entry(&table[7], "name", sd->name, CORENAME_MAX_SIZE, 0444, proc_dostring);
+ /* &table[8] is terminator */
+
+ return table;
+}
+
+static struct ctl_table *sd_alloc_ctl_cpu_table(int cpu)
+{
+ struct ctl_table *entry, *table;
+ struct sched_domain *sd;
+ int domain_num = 0, i;
+ char buf[32];
+
+ for_each_domain(cpu, sd)
+ domain_num++;
+ entry = table = sd_alloc_ctl_entry(domain_num + 1);
+ if (table == NULL)
+ return NULL;
+
+ i = 0;
+ for_each_domain(cpu, sd) {
+ snprintf(buf, 32, "domain%d", i);
+ entry->procname = kstrdup(buf, GFP_KERNEL);
+ entry->mode = 0555;
+ entry->child = sd_alloc_ctl_domain_table(sd);
+ entry++;
+ i++;
+ }
+ return table;
+}
+
+static cpumask_var_t sd_sysctl_cpus;
+static struct ctl_table_header *sd_sysctl_header;
+
+void register_sched_domain_sysctl(void)
+{
+ static struct ctl_table *cpu_entries;
+ static struct ctl_table **cpu_idx;
+ char buf[32];
+ int i;
+
+ if (!cpu_entries) {
+ cpu_entries = sd_alloc_ctl_entry(num_possible_cpus() + 1);
+ if (!cpu_entries)
+ return;
+
+ WARN_ON(sd_ctl_dir[0].child);
+ sd_ctl_dir[0].child = cpu_entries;
+ }
+
+ if (!cpu_idx) {
+ struct ctl_table *e = cpu_entries;
+
+ cpu_idx = kcalloc(nr_cpu_ids, sizeof(struct ctl_table*), GFP_KERNEL);
+ if (!cpu_idx)
+ return;
+
+ /* deal with sparse possible map */
+ for_each_possible_cpu(i) {
+ cpu_idx[i] = e;
+ e++;
+ }
+ }
+
+ if (!cpumask_available(sd_sysctl_cpus)) {
+ if (!alloc_cpumask_var(&sd_sysctl_cpus, GFP_KERNEL))
+ return;
+
+ /* init to possible to not have holes in @cpu_entries */
+ cpumask_copy(sd_sysctl_cpus, cpu_possible_mask);
+ }
+
+ for_each_cpu(i, sd_sysctl_cpus) {
+ struct ctl_table *e = cpu_idx[i];
+
+ if (e->child)
+ sd_free_ctl_entry(&e->child);
+
+ if (!e->procname) {
+ snprintf(buf, 32, "cpu%d", i);
+ e->procname = kstrdup(buf, GFP_KERNEL);
+ }
+ e->mode = 0555;
+ e->child = sd_alloc_ctl_cpu_table(i);
+
+ __cpumask_clear_cpu(i, sd_sysctl_cpus);
+ }
+
+ WARN_ON(sd_sysctl_header);
+ sd_sysctl_header = register_sysctl_table(sd_ctl_root);
+}
+
+void dirty_sched_domain_sysctl(int cpu)
+{
+ if (cpumask_available(sd_sysctl_cpus))
+ __cpumask_set_cpu(cpu, sd_sysctl_cpus);
+}
+
+/* may be called multiple times per register */
+void unregister_sched_domain_sysctl(void)
+{
+ unregister_sysctl_table(sd_sysctl_header);
+ sd_sysctl_header = NULL;
+}
+#endif /* CONFIG_SYSCTL */
+
+void set_rq_online(struct rq *rq)
+{
+ if (!rq->online) {
+ cpumask_set_cpu(cpu_of(rq), rq->rd->online);
+ rq->online = true;
+ }
+}
+
+void set_rq_offline(struct rq *rq)
+{
+ if (rq->online) {
+ int cpu = cpu_of(rq);
+
+ cpumask_clear_cpu(cpu, rq->rd->online);
+ rq->online = false;
+ clear_cpuidle_map(cpu);
+ }
+}
+
+/*
+ * used to mark begin/end of suspend/resume:
+ */
+static int num_cpus_frozen;
+
+/*
+ * Update cpusets according to cpu_active mask. If cpusets are
+ * disabled, cpuset_update_active_cpus() becomes a simple wrapper
+ * around partition_sched_domains().
+ *
+ * If we come here as part of a suspend/resume, don't touch cpusets because we
+ * want to restore it back to its original state upon resume anyway.
+ */
+static void cpuset_cpu_active(void)
+{
+ if (cpuhp_tasks_frozen) {
+ /*
+ * num_cpus_frozen tracks how many CPUs are involved in suspend
+ * resume sequence. As long as this is not the last online
+ * operation in the resume sequence, just build a single sched
+ * domain, ignoring cpusets.
+ */
+ partition_sched_domains(1, NULL, NULL);
+ if (--num_cpus_frozen)
+ return;
+ /*
+ * This is the last CPU online operation. So fall through and
+ * restore the original sched domains by considering the
+ * cpuset configurations.
+ */
+ cpuset_force_rebuild();
+ }
+
+ cpuset_update_active_cpus();
+}
+
+static int cpuset_cpu_inactive(unsigned int cpu)
+{
+ if (!cpuhp_tasks_frozen) {
+ cpuset_update_active_cpus();
+ } else {
+ num_cpus_frozen++;
+ partition_sched_domains(1, NULL, NULL);
+ }
+ return 0;
+}
+
+int sched_cpu_activate(unsigned int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ struct rq_flags rf;
+
+ /*
+ * When going up, increment the number of cores with SMT present.
+ * cpu_smt_mask() is cpumask_of(cpu) when !CONFIG_SCHED_SMT, so this
+ * never fires there.
+ */
+ if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
+ static_branch_inc_cpuslocked(&sched_smt_present);
+
+ set_cpu_active(cpu, true);
+
+ if (sched_smp_initialized) {
+ sched_domains_numa_masks_set(cpu);
+ cpuset_cpu_active();
+ }
+
+ /*
+ * Put the rq online, if not already. This happens:
+ *
+ * 1) In the early boot process, because we build the real domains
+ * after all CPUs have been brought up.
+ *
+ * 2) At runtime, if cpuset_cpu_active() fails to rebuild the
+ * domains.
+ */
+ rq_lock_irqsave(rq, &rf);
+ if (rq->rd) {
+ BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
+ set_rq_online(rq);
+ }
+ rq_unlock_irqrestore(rq, &rf);
+ /*
+ * unbind_zero() takes each task's pi+rq lock; do not nest that
+ * under this CPU's rq lock.
+ */
+ unbind_zero(cpu);
+
+ return 0;
+}
+
+int sched_cpu_deactivate(unsigned int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ struct rq_flags rf;
+ int ret;
+
+ set_cpu_active(cpu, false);
+ /*
+ * We've cleared cpu_active_mask, wait for all preempt-disabled and RCU
+ * users of this state to go away such that all new such users will
+ * observe it.
+ *
+ * Do sync before park smpboot threads to take care the rcu boost case.
+ */
+ synchronize_rcu();
+
+ sched_domains_free_llc_id(cpu);
+
+ rq_lock_irqsave(rq, &rf);
+ if (rq->rd) {
+ update_rq_clock(rq);
+ BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
+ set_rq_offline(rq);
+ }
+ rq_unlock_irqrestore(rq, &rf);
+
+ /*
+ * When going down, decrement the number of cores with SMT present.
+ */
+ if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
+ static_branch_dec_cpuslocked(&sched_smt_present);
+
+ if (!sched_smp_initialized)
+ return 0;
+
+ ret = cpuset_cpu_inactive(cpu);
+ if (ret) {
+ set_cpu_active(cpu, true);
+ return ret;
+ }
+ sched_domains_numa_masks_clear(cpu);
+ return 0;
+}
+
+int sched_cpu_starting(unsigned int cpu)
+{
+ sched_tick_start(cpu);
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Invoked on the outgoing CPU in context of the CPU hotplug thread after
+ * ensuring that there are no user space tasks left on the CPU.
+ *
+ * If there is a lazy mm in use on the hotplug thread, drop it and switch to
+ * init_mm. finish_cpu() on the control CPU drops the init_mm reference and
+ * WARNs if we left anything else behind. 5.12 did this from idle_task_exit();
+ * mainline now does it here from sched_cpu_wait_empty().
+ */
+static void __sched_force_init_mm(void)
+{
+ struct mm_struct *mm = current->active_mm;
+
+ if (mm == &init_mm)
+ return;
+
+ mmgrab_lazy_tlb(&init_mm);
+ current->active_mm = &init_mm;
+ switch_mm_irqs_off(mm, &init_mm, current);
+ finish_arch_post_lock_switch();
+ mmdrop_lazy_tlb(mm);
+}
+
+static void sched_force_init_mm(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ __sched_force_init_mm();
+ local_irq_restore(flags);
+}
+
+static void dump_rq_tasks(struct rq *rq, const char *loglvl)
+{
+ struct task_struct *g, *p;
+ int cpu = cpu_of(rq);
+
+ lockdep_assert_rq_held(rq);
+
+ printk("%sCPU%d tasks (nr_running=%u nr_pinned=%u):\n",
+ loglvl, cpu, rq->nr_running, rq->nr_pinned);
+ rcu_read_lock();
+ for_each_process_thread(g, p) {
+ if (task_cpu(p) != cpu)
+ continue;
+ printk("%s\tpid: %d, name: %s, queued: %d, on_rq: %d\n",
+ loglvl, p->pid, p->comm, task_queued(p), p->on_rq);
+ }
+ rcu_read_unlock();
+}
+
+/*
+ * Invoked on the outgoing CPU after per-CPU kthreads have been parked.
+ * bind_zero() takes affinity off this CPU and moves anyone still queued
+ * here. Then wait until only this hotplug thread remains and every
+ * migrate_disable() pin has dropped, so finish_cpu() cannot see a user mm.
+ */
+int sched_cpu_wait_empty(unsigned int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+
+ WARN_ON_ONCE(cpu != smp_processor_id());
+
+ for (;;) {
+ bind_zero(cpu);
+ if (READ_ONCE(rq->nr_running) <= 1 && !READ_ONCE(rq->nr_pinned))
+ break;
+ schedule_timeout_uninterruptible(1);
+ }
+
+ sched_force_init_mm();
+ return 0;
+}
+
+int sched_cpu_dying(unsigned int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ struct rq_flags rf;
+
+ /* Handle pending wakeups; tasks were already moved in wait_empty. */
+ sched_tick_stop(cpu);
+
+ rq_lock_irqsave(rq, &rf);
+ if (rq->rd) {
+ BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
+ set_rq_offline(rq);
+ }
+ if (rq->nr_running > 1 || rq->nr_pinned) {
+ WARN(true, "Dying CPU not properly vacated!");
+ dump_rq_tasks(rq, KERN_WARNING);
+ }
+ rq_unlock_irqrestore(rq, &rf);
+
+ sched_start_tick(rq, cpu);
+ hrexpiry_clear(rq);
+ /*
+ * Belt-and-suspenders: wait_empty already switched to init_mm,
+ * but a preempting migrate_disable() task could have left a
+ * lazy user mm on current. Drop it again now that this is the
+ * last thing to run before idle takes over.
+ */
+ local_irq_disable();
+ __sched_force_init_mm();
+ local_irq_enable();
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SCHED_SMT) || defined(CONFIG_SCHED_MC)
+/*
+ * Cheaper version of the below functions in case support for SMT and MC is
+ * compiled in but CPUs have no siblings.
+ */
+static bool sole_cpu_idle(struct rq *rq)
+{
+ return rq_idle(rq);
+}
+#endif
+#ifdef CONFIG_SCHED_SMT
+static const cpumask_t *thread_cpumask(int cpu)
+{
+ return topology_sibling_cpumask(cpu);
+}
+#endif
+#ifdef CONFIG_SCHED_MC
+static const cpumask_t *core_cpumask(int cpu)
+{
+ return topology_core_cpumask(cpu);
+}
+/* All this CPU's shared cache siblings are idle */
+static bool cache_cpu_idle(struct rq *rq)
+{
+ return cpumask_subset(&rq->core_mask, &cpu_idle_map);
+}
+/* MC siblings CPU mask which share the same LLC */
+static const cpumask_t *llc_core_cpumask(int cpu)
+{
+#ifdef CONFIG_X86
+ return per_cpu(cpu_llc_shared_map, cpu);
+#else
+ return topology_core_cpumask(cpu);
+#endif
+}
+#endif
+
+enum sched_domain_level {
+ SD_LV_NONE = 0,
+ SD_LV_SIBLING,
+ SD_LV_MC,
+ SD_LV_BOOK,
+ SD_LV_CPU,
+ SD_LV_NODE,
+ SD_LV_ALLNODES,
+ SD_LV_MAX
+};
+
+#ifdef CONFIG_SMT_NICE
+/*
+ * Recorded by select_leaders() and consumed by sched_init_smp() once the
+ * runqueue locks have been dropped. See the comment where it is set.
+ */
+static bool __initdata smt_nice_needed;
+#endif
+
+/*
+ * Set up the relative cache distance of each online cpu from each
+ * other in a simple array for quick lookup. Locality is determined
+ * by the closest sched_domain that CPUs are separated by. CPUs with
+ * shared cache in SMT and MC are treated as local. Separate CPUs
+ * (within the same package or physically) within the same node are
+ * treated as not local. CPUs not even in the same domain (different
+ * nodes) are treated as very distant.
+ *
+ * Called with interrupts disabled and every runqueue lock held, so nothing
+ * here may sleep or wait on another CPU.
+ */
+static void __init select_leaders(void)
+{
+ struct rq *rq, *other_rq, *leader;
+ struct sched_domain *sd;
+ int cpu, other_cpu;
+#ifdef CONFIG_SCHED_SMT
+ bool smt_threads = false;
+#endif
+
+ for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+ rq = cpu_rq(cpu);
+ leader = NULL;
+ /* First check if this cpu is in the same node */
+ for_each_domain(cpu, sd) {
+ if (sd->level > SD_LV_MC)
+ continue;
+ if (rqshare != RQSHARE_ALL)
+ leader = NULL;
+ /* Set locality to local node if not already found lower */
+ for_each_cpu(other_cpu, sched_domain_span(sd)) {
+ if (rqshare >= RQSHARE_SMP) {
+ other_rq = cpu_rq(other_cpu);
+
+ /* Set the smp_leader to the first CPU */
+ if (!leader)
+ leader = rq;
+ if (!other_rq->smp_leader)
+ other_rq->smp_leader = leader;
+ }
+ if (rq->cpu_locality[other_cpu] > LOCALITY_SMP)
+ rq->cpu_locality[other_cpu] = LOCALITY_SMP;
+ }
+ }
+
+ /*
+ * Each runqueue has its own function in case it doesn't have
+ * siblings of its own allowing mixed topologies.
+ */
+#ifdef CONFIG_SCHED_MC
+ leader = NULL;
+ if (cpumask_weight(core_cpumask(cpu)) > 1) {
+ cpumask_copy(&rq->core_mask, llc_core_cpumask(cpu));
+ cpumask_clear_cpu(cpu, &rq->core_mask);
+ for_each_cpu(other_cpu, core_cpumask(cpu)) {
+ if (rqshare == RQSHARE_MC ||
+ (rqshare == RQSHARE_MC_LLC && cpumask_test_cpu(other_cpu, llc_core_cpumask(cpu)))) {
+ other_rq = cpu_rq(other_cpu);
+
+ /* Set the mc_leader to the first CPU */
+ if (!leader)
+ leader = rq;
+ if (!other_rq->mc_leader)
+ other_rq->mc_leader = leader;
+ }
+ if (rq->cpu_locality[other_cpu] > LOCALITY_MC) {
+ /* this is to get LLC into play even in case LLC sharing is not used */
+ if (cpumask_test_cpu(other_cpu, llc_core_cpumask(cpu)))
+ rq->cpu_locality[other_cpu] = LOCALITY_MC_LLC;
+ else
+ rq->cpu_locality[other_cpu] = LOCALITY_MC;
+ }
+ }
+ rq->cache_idle = cache_cpu_idle;
+ }
+#endif
+#ifdef CONFIG_SCHED_SMT
+ leader = NULL;
+ if (cpumask_weight(thread_cpumask(cpu)) > 1) {
+ cpumask_copy(&rq->thread_mask, thread_cpumask(cpu));
+ cpumask_clear_cpu(cpu, &rq->thread_mask);
+ for_each_cpu(other_cpu, thread_cpumask(cpu)) {
+ if (rqshare == RQSHARE_SMT) {
+ other_rq = cpu_rq(other_cpu);
+
+ /* Set the smt_leader to the first CPU */
+ if (!leader)
+ leader = rq;
+ if (!other_rq->smt_leader)
+ other_rq->smt_leader = leader;
+ }
+ if (rq->cpu_locality[other_cpu] > LOCALITY_SMT)
+ rq->cpu_locality[other_cpu] = LOCALITY_SMT;
+ }
+ rq->has_smt_sibling = true;
+ smt_threads = true;
+ }
+#endif
+ }
+
+#ifdef CONFIG_SMT_NICE
+ /*
+ * Only record it here; sched_init_smp() turns SMT nice on once it has
+ * dropped the runqueue locks and re-enabled interrupts.
+ *
+ * static_branch_enable() must not be called from this context. It
+ * takes cpus_read_lock() and jump_label_mutex, either of which can
+ * sleep - and scheduling from here would try to take a runqueue lock
+ * this CPU already holds - and it then patches the jump site with
+ * text_poke_bp(), which waits for every other CPU to answer a sync
+ * IPI. Any CPU spinning on one of the runqueue locks held here has
+ * interrupts disabled and can never answer, so the wait never ends and
+ * the machine is gone with nothing on the console.
+ */
+ smt_nice_needed = smt_threads;
+#endif
+
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ for_each_online_cpu(other_cpu) {
+ printk(KERN_DEBUG "MuQSS locality CPU %d to %d: %d\n", cpu, other_cpu, rq->cpu_locality[other_cpu]);
+ }
+ }
+}
+
+/*
+ * Fold @rq into @leader while all runqueue locks are already held by
+ * lock_all_rqs(). Secondary CPUs may already have tasks queued by the time
+ * sched_init_smp() runs (hotplug kthreads, RCU, early kworkers), so the
+ * skiplist must be drained onto the leader before its storage is freed.
+ *
+ * Lock handoff: rq_lock() is a plain raw_spin_lock(rq->lock) with no re-check,
+ * so a CPU that had already read the follower's lock pointer would acquire the
+ * old lock after we drop it and then walk the leader's skiplist without the
+ * leader's lock. share_rqs() therefore runs from stop_machine(), where no
+ * other CPU can be inside or waiting on any rq lock, which is what makes
+ * repointing rq->lock and freeing the old one safe.
+ */
+static void __init share_and_free_rq(struct rq *leader, struct rq *rq)
+{
+ raw_spinlock_t *old_lock = rq->lock;
+ skiplist_node *old_node = rq->node;
+ skiplist *old_sl = rq->sl;
+
+ /*
+ * Move every queued task onto the leader skiplist. nr_running is
+ * accounted against the rq the task belongs to (task_rq(p), which is
+ * unchanged here) rather than the rq owning the skiplist, so hand the
+ * counts straight back or the follower underflows on the next dequeue
+ * and the leader keeps a phantom entry forever.
+ */
+ while (rq->sl->entries > 0) {
+ struct task_struct *p = container_of(rq->node->next[0],
+ struct task_struct, node);
+
+ dequeue_task(rq, p, DEQUEUE_SAVE);
+ enqueue_task(leader, p, ENQUEUE_RESTORE);
+ leader->nr_running--;
+ rq->nr_running++;
+ if (rt_task(p)) {
+ leader->rt_nr_running--;
+ rq->rt_nr_running++;
+ }
+ }
+
+ /*
+ * A non-idle curr is not on the skiplist but still accounts for one
+ * nr_running. Leave that count on @rq; only the shared skiplist and
+ * lock are merged.
+ */
+ WARN_ON_ONCE(rq->sl->entries != 0);
+
+ /* Point the follower at the leader's skiplist and lock. */
+ rq->node = leader->node;
+ rq->sl = leader->sl;
+ rq->lock = leader->lock;
+ rq->is_leader = false;
+
+ /*
+ * Drop the follower's private lock, taken by lock_all_rqs(). Only the
+ * leader lock remains held for @rq, and nothing can be waiting on the
+ * old one, so free it.
+ */
+ do_raw_spin_unlock(old_lock);
+
+ kfree(old_node);
+ skiplist_free(old_sl);
+ kfree(old_lock);
+}
+
+/*
+ * Called with every runqueue lock held via lock_all_rqs() and IRQs off.
+ * Must not take locks again. After this, only leader rqs own a unique lock;
+ * unlock_all_rqs() is replaced by unlock_leader_rqs().
+ */
+static void __init share_rqs(void)
+{
+ struct rq *rq, *leader;
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ leader = rq->smp_leader;
+
+ if (leader && rq != leader) {
+ printk(KERN_INFO "MuQSS sharing SMP runqueue from CPU %d to CPU %d\n",
+ leader->cpu, rq->cpu);
+ share_and_free_rq(leader, rq);
+ }
+ }
+
+#ifdef CONFIG_SCHED_MC
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ leader = rq->mc_leader;
+
+ if (leader && rq != leader) {
+ printk(KERN_INFO "MuQSS sharing MC runqueue from CPU %d to CPU %d\n",
+ leader->cpu, rq->cpu);
+ share_and_free_rq(leader, rq);
+ }
+ }
+#endif /* CONFIG_SCHED_MC */
+
+#ifdef CONFIG_SCHED_SMT
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ leader = rq->smt_leader;
+
+ if (leader && rq != leader) {
+ printk(KERN_INFO "MuQSS sharing SMT runqueue from CPU %d to CPU %d\n",
+ leader->cpu, rq->cpu);
+ share_and_free_rq(leader, rq);
+ }
+ }
+#endif /* CONFIG_SCHED_SMT */
+}
+
+/* Unlock each unique runqueue lock once after share_rqs(). */
+static inline void unlock_leader_rqs(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct rq *rq = cpu_rq(cpu);
+
+ if (rq->is_leader)
+ do_raw_spin_unlock(rq->lock);
+ }
+ preempt_enable();
+}
+
+/*
+ * Fold the runqueues from stop_machine() context. Every other CPU is parked
+ * in the stopper with interrupts disabled, so none of them is inside an rq
+ * lock or spinning on one while share_and_free_rq() repoints a follower's
+ * rq->lock at its leader and frees the old lock. Any single CPU can run this.
+ */
+static int __init share_rqs_stopper(void *unused)
+{
+ lock_all_rqs();
+ share_rqs();
+ unlock_leader_rqs();
+
+ return 0;
+}
+
+static void __init set_rq_order(struct rq *rq, int idx, struct rq *other)
+{
+ rq->rq_order[idx] = other;
+ rq->sl_order[idx] = other->sl;
+}
+
+static void __init setup_rq_orders(void)
+{
+ int *selected_cpus, *ordered_cpus;
+ struct rq *rq, *other_rq;
+ int cpu, other_cpu, i;
+
+ selected_cpus = kmalloc(sizeof(int) * NR_CPUS, GFP_ATOMIC);
+ ordered_cpus = kmalloc(sizeof(int) * NR_CPUS, GFP_ATOMIC);
+
+ total_runqueues = 0;
+ for_each_online_cpu(cpu) {
+ int locality, total_rqs = 0, total_cpus = 0;
+
+ rq = cpu_rq(cpu);
+ if (rq->is_leader)
+ total_runqueues++;
+
+ for (locality = LOCALITY_SAME; locality <= LOCALITY_DISTANT; locality++) {
+ int selected_cpu_cnt, selected_cpu_idx, test_cpu_idx, cpu_idx, best_locality, test_cpu;
+ int ordered_cpus_idx;
+
+ ordered_cpus_idx = -1;
+ selected_cpu_cnt = 0;
+
+ for_each_online_cpu(test_cpu) {
+ if (cpu < num_online_cpus() / 2)
+ other_cpu = cpu + test_cpu;
+ else
+ other_cpu = cpu - test_cpu;
+ if (other_cpu < 0)
+ other_cpu += num_online_cpus();
+ else
+ other_cpu %= num_online_cpus();
+ /* gather CPUs of the same locality */
+ if (rq->cpu_locality[other_cpu] == locality) {
+ selected_cpus[selected_cpu_cnt] = other_cpu;
+ selected_cpu_cnt++;
+ }
+ }
+
+ /* reserve first CPU as starting point */
+ if (selected_cpu_cnt > 0) {
+ ordered_cpus_idx++;
+ ordered_cpus[ordered_cpus_idx] = selected_cpus[ordered_cpus_idx];
+ selected_cpus[ordered_cpus_idx] = -1;
+ }
+
+ /* take each CPU and sort it within the same locality based on each inter-CPU localities */
+ for (test_cpu_idx = 1; test_cpu_idx < selected_cpu_cnt; test_cpu_idx++) {
+ /* starting point with worst locality and current CPU */
+ best_locality = LOCALITY_DISTANT;
+ selected_cpu_idx = test_cpu_idx;
+
+ /* try to find the best locality within group */
+ for (cpu_idx = 1; cpu_idx < selected_cpu_cnt; cpu_idx++) {
+ /* if CPU has not been used and locality is better */
+ if (selected_cpus[cpu_idx] > -1) {
+ other_rq = cpu_rq(ordered_cpus[ordered_cpus_idx]);
+ if (best_locality > other_rq->cpu_locality[selected_cpus[cpu_idx]]) {
+ /* assign best locality and best CPU idx in array */
+ best_locality = other_rq->cpu_locality[selected_cpus[cpu_idx]];
+ selected_cpu_idx = cpu_idx;
+ }
+ }
+ }
+
+ /* add our next best CPU to ordered list */
+ ordered_cpus_idx++;
+ ordered_cpus[ordered_cpus_idx] = selected_cpus[selected_cpu_idx];
+ /* mark this CPU as used */
+ selected_cpus[selected_cpu_idx] = -1;
+ }
+
+ /* set up RQ and CPU orders */
+ for (test_cpu = 0; test_cpu <= ordered_cpus_idx; test_cpu++) {
+ other_rq = cpu_rq(ordered_cpus[test_cpu]);
+ /* set up cpu orders */
+ rq->cpu_order[total_cpus++] = other_rq;
+ if (other_rq->is_leader) {
+ /* set up RQ orders */
+ set_rq_order(rq, total_rqs++, other_rq);
+ }
+ }
+ }
+ }
+
+ kfree(selected_cpus);
+ kfree(ordered_cpus);
+
+#ifdef CONFIG_X86
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ for (i = 0; i < total_runqueues; i++) {
+ printk(KERN_DEBUG "MuQSS CPU %d llc %d RQ order %d RQ %d llc %d\n", cpu, per_cpu_llc_id(cpu), i,
+ rq->rq_order[i]->cpu, per_cpu_llc_id(rq->rq_order[i]->cpu));
+ }
+ }
+
+ for_each_online_cpu(cpu) {
+ rq = cpu_rq(cpu);
+ for (i = 0; i < num_online_cpus(); i++) {
+ printk(KERN_DEBUG "MuQSS CPU %d llc %d CPU order %d RQ %d llc %d\n", cpu, per_cpu_llc_id(cpu), i,
+ rq->cpu_order[i]->cpu, per_cpu_llc_id(rq->cpu_order[i]->cpu));
+ }
+ }
+#endif
+}
+
+void __init sched_init_smp(void)
+{
+ sched_init_numa(NUMA_NO_NODE);
+
+ /*
+ * There's no userspace yet to cause hotplug operations; hence all the
+ * cpu masks are stable and all blatant races in the below code cannot
+ * happen.
+ */
+ mutex_lock(&sched_domains_mutex);
+ sched_init_domains(cpu_active_mask);
+ mutex_unlock(&sched_domains_mutex);
+
+ /* Move init over to a non-isolated CPU */
+ if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_TYPE_DOMAIN)) < 0)
+ BUG();
+
+ /*
+ * Take the sleeping lock before disabling interrupts - the 5.12 order
+ * trips "sleeping function called from invalid context" under
+ * CONFIG_DEBUG_ATOMIC_SLEEP. select_leaders() walks the domain tree,
+ * which is what the mutex is for.
+ */
+ mutex_lock(&sched_domains_mutex);
+ local_irq_disable();
+ lock_all_rqs();
+
+ printk(KERN_INFO "MuQSS possible/present/online CPUs: %d/%d/%d\n",
+ num_possible_cpus(), num_present_cpus(), num_online_cpus());
+
+ select_leaders();
+
+ unlock_all_rqs();
+ local_irq_enable();
+ mutex_unlock(&sched_domains_mutex);
+
+#ifdef CONFIG_SMT_NICE
+ /*
+ * Safe to patch the jump site only now that the runqueue locks are
+ * dropped and interrupts are back on; see select_leaders(). Until
+ * this point smt_schedule() just returns true and check_siblings()/
+ * wake_siblings() are the no-op variants, which is correct behaviour,
+ * merely without SMT nice.
+ */
+ if (smt_nice_needed) {
+ check_siblings = &check_smt_siblings;
+ wake_siblings = &wake_smt_siblings;
+ static_branch_enable(&smt_nice_enabled);
+ }
+#endif
+
+ /*
+ * Only now fold the runqueues together, and do it from stop_machine():
+ * 7.1 has the secondary CPUs running by this point, so a follower's rq
+ * lock can be held - or waited on - by another CPU exactly while it is
+ * handed over to the leader and freed. Quiescing everybody closes that
+ * window without putting a re-check in the rq_lock() fast path. Note
+ * stop_machine() takes cpus_read_lock(), so it must not nest inside
+ * sched_domains_mutex.
+ */
+ stop_machine(share_rqs_stopper, NULL, cpumask_of(raw_smp_processor_id()));
+
+ setup_rq_orders();
+
+ switch (rqshare) {
+ case RQSHARE_ALL:
+ /* This should only ever read 1 */
+ printk(KERN_INFO "MuQSS runqueue share type ALL total runqueues: %d\n",
+ total_runqueues);
+ break;
+ case RQSHARE_SMP:
+ printk(KERN_INFO "MuQSS runqueue share type SMP total runqueues: %d\n",
+ total_runqueues);
+ break;
+ case RQSHARE_MC:
+ printk(KERN_INFO "MuQSS runqueue share type MC total runqueues: %d\n",
+ total_runqueues);
+ break;
+ case RQSHARE_MC_LLC:
+ printk(KERN_INFO "MuQSS runqueue share type LLC total runqueues: %d\n",
+ total_runqueues);
+ break;
+ case RQSHARE_SMT:
+ printk(KERN_INFO "MuQSS runqueue share type SMT total runqueues: %d\n",
+ total_runqueues);
+ break;
+ case RQSHARE_NONE:
+ printk(KERN_INFO "MuQSS runqueue share type NONE total runqueues: %d\n",
+ total_runqueues);
+ break;
+ }
+
+ sched_smp_initialized = true;
+}
+#else /* !CONFIG_SMP */
+void __init sched_init_smp(void)
+{
+ sched_smp_initialized = true;
+}
+
+/*
+ * 7.1 dropped the !CONFIG_SMP inline stubs these used to have in
+ * <linux/sched.h>, so the scheduler has to provide them on UP too. There is
+ * only ever cpu 0 to run on, so affinity is either trivially satisfied or
+ * impossible.
+ */
+int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
+{
+ if (!cpumask_test_cpu(0, new_mask))
+ return -EINVAL;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
+
+void set_cpus_allowed_force(struct task_struct *p, const struct cpumask *new_mask)
+{
+ cpumask_copy(&p->cpus_mask, new_mask);
+ p->nr_cpus_allowed = cpumask_weight(new_mask);
+}
+
+#ifdef CONFIG_NO_HZ_COMMON
+void nohz_balance_enter_idle(int cpu) {}
+
+/*
+ * The only CPU is the one already running this, so it is by definition not
+ * idle and needs no kick.
+ */
+void wake_up_nohz_cpu(int cpu)
+{
+}
+#endif /* CONFIG_NO_HZ_COMMON */
+
+/*
+ * topology.c is not built on UP, but <linux/sched/topology.h> declares this
+ * unconditionally and amd-pstate calls it. There are no sched domains to
+ * update.
+ */
+void sched_update_asym_prefer_cpu(int cpu, int old_prio, int new_prio)
+{
+}
+#endif /* CONFIG_SMP */
+
+int in_sched_functions(unsigned long addr)
+{
+ return in_lock_functions(addr) ||
+ (addr >= (unsigned long)__sched_text_start
+ && addr < (unsigned long)__sched_text_end);
+}
+
+#ifdef CONFIG_CGROUP_SCHED
+/*
+ * Default CFS bandwidth period (100ms). Used only for accept-and-ignore
+ * readback of cpu.max / cfs_period_us — MuQSS does not enforce quotas.
+ */
+#define MUQSS_CGROUP_PERIOD_DFL_US 100000ULL
+
+/* task group related information */
+struct task_group {
+ struct cgroup_subsys_state css;
+
+ struct rcu_head rcu;
+ struct list_head list;
+
+ struct task_group *parent;
+ struct list_head siblings;
+ struct list_head children;
+
+ /*
+ * cpu controller knobs stored for ABI/readback only. Writes are
+ * validated then ignored for scheduling — MuQSS has no group fairness
+ * or bandwidth enforcement. Keeps systemd/docker/podman happy.
+ */
+ unsigned long weight; /* cgroup weight [CGROUP_WEIGHT_MIN, MAX] */
+ s64 idle;
+ u64 period_us;
+ s64 quota_us; /* -1 == unlimited ("max") */
+ u64 burst_us;
+};
+
+/*
+ * Default task group.
+ * Every task in system belongs to this group at bootup.
+ */
+struct task_group root_task_group;
+LIST_HEAD(task_groups);
+
+/* Cacheline aligned slab cache for task_group */
+static struct kmem_cache *task_group_cache __read_mostly;
+
+static void init_tg_cgroup_defaults(struct task_group *tg)
+{
+ tg->weight = CGROUP_WEIGHT_DFL;
+ tg->idle = 0;
+ tg->period_us = MUQSS_CGROUP_PERIOD_DFL_US;
+ tg->quota_us = -1;
+ tg->burst_us = 0;
+}
+#endif /* CONFIG_CGROUP_SCHED */
+
+void __init sched_init(void)
+{
+#ifdef CONFIG_SMP
+ int cpu_ids;
+#endif
+ int i;
+ struct rq *rq;
+
+ wait_bit_init();
+
+ prio_ratios[0] = 128;
+ for (i = 1 ; i < NICE_WIDTH ; i++)
+ prio_ratios[i] = prio_ratios[i - 1] * 11 / 10;
+
+ skiplist_node_init(&init_task.node);
+
+#ifdef CONFIG_SMP
+ init_defrootdomain();
+ cpumask_clear(&cpu_idle_map);
+#else
+ uprq = &per_cpu(runqueues, 0);
+#endif
+
+#ifdef CONFIG_CGROUP_SCHED
+ task_group_cache = KMEM_CACHE(task_group, 0);
+
+ list_add(&root_task_group.list, &task_groups);
+ INIT_LIST_HEAD(&root_task_group.children);
+ INIT_LIST_HEAD(&root_task_group.siblings);
+ init_tg_cgroup_defaults(&root_task_group);
+#endif /* CONFIG_CGROUP_SCHED */
+ skiplist_cache_init();
+ for_each_possible_cpu(i) {
+ rq = cpu_rq(i);
+ rq->node = kmalloc(sizeof(skiplist_node), GFP_ATOMIC);
+ skiplist_init(rq->node);
+ rq->sl = new_skiplist(rq->node);
+ rq->lock = kmalloc(sizeof(raw_spinlock_t), GFP_ATOMIC);
+ raw_spin_lock_init(rq->lock);
+ rq->nr_running = 0;
+ rq->nr_uninterruptible = 0;
+ rq->nr_switches = 0;
+ rq->clock = rq->niffies = rq->jiffy_niffies = 0;
+ rq->last_jiffy = jiffies;
+ rq->user_ns = rq->nice_ns = rq->softirq_ns = rq->system_ns =
+ rq->iowait_ns = rq->idle_ns = 0;
+ rq->dither = 0;
+ set_rq_task(rq, &init_task);
+ rq->iso_ticks = 0;
+ rq->iso_refractory = false;
+#ifdef CONFIG_SMP
+ rq->is_leader = true;
+ rq->smp_leader = NULL;
+#ifdef CONFIG_SCHED_MC
+ rq->mc_leader = NULL;
+#endif
+#ifdef CONFIG_SCHED_SMT
+ rq->smt_leader = NULL;
+#endif
+ rq->sd = NULL;
+ rq->rd = NULL;
+ rq->online = false;
+ rq->cpu = i;
+ rq_attach_root(rq, &def_root_domain);
+#endif /* CONFIG_SMP */
+ init_rq_hrexpiry(rq);
+ atomic_set(&rq->nr_iowait, 0);
+ }
+
+#ifdef CONFIG_SMP
+ cpu_ids = i;
+ /*
+ * Set the base locality for cpu cache distance calculation to
+ * "distant" (3). Make sure the distance from a CPU to itself is 0.
+ */
+ for_each_possible_cpu(i) {
+ int j;
+
+ rq = cpu_rq(i);
+#ifdef CONFIG_SCHED_MC
+ rq->cache_idle = sole_cpu_idle;
+#endif
+ rq->cpu_locality = kmalloc(cpu_ids * sizeof(int *), GFP_ATOMIC);
+ for_each_possible_cpu(j) {
+ if (i == j)
+ rq->cpu_locality[j] = LOCALITY_SAME;
+ else
+ rq->cpu_locality[j] = LOCALITY_DISTANT;
+ }
+ /* sl_order is O(possible_cpus²) pointers, same as rq_order. */
+ rq->rq_order = kmalloc(cpu_ids * sizeof(struct rq *), GFP_ATOMIC);
+ rq->sl_order = kmalloc(cpu_ids * sizeof(skiplist *), GFP_ATOMIC);
+ rq->cpu_order = kmalloc(cpu_ids * sizeof(struct rq *), GFP_ATOMIC);
+ set_rq_order(rq, 0, rq);
+ rq->cpu_order[0] = rq;
+ for (j = 1; j < cpu_ids; j++) {
+ set_rq_order(rq, j, cpu_rq(j));
+ rq->cpu_order[j] = cpu_rq(j);
+ }
+ }
+#endif
+
+ /*
+ * The boot idle thread does lazy MMU switching as well:
+ */
+ mmgrab_lazy_tlb(&init_mm);
+ enter_lazy_tlb(&init_mm, current);
+
+ /*
+ * Make us the idle thread. Technically, schedule() should not be
+ * called from this thread, however somewhere below it might be,
+ * but because we are the idle thread, we just pick up running again
+ * when this runqueue becomes "idle".
+ */
+ init_idle(current, smp_processor_id());
+
+#ifdef CONFIG_SMP
+ idle_thread_set_boot_cpu();
+#endif /* SMP */
+
+ init_schedstats();
+
+ psi_init();
+
+ preempt_dynamic_init();
+
+ print_scheduler_version();
+}
+
+#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
+static inline int preempt_count_equals(int preempt_offset)
+{
+ int nested = preempt_count() + rcu_preempt_depth();
+
+ return (nested == preempt_offset);
+}
+
+void __might_sleep(const char *file, int line)
+{
+ unsigned int state = get_current_state();
+ /*
+ * Blocking primitives will set (and therefore destroy) current->__state,
+ * since we will exit with TASK_RUNNING make sure we enter with it,
+ * otherwise we will destroy state.
+ */
+ WARN_ONCE(state != TASK_RUNNING && current->task_state_change,
+ "do not call blocking ops when !TASK_RUNNING; "
+ "state=%x set at [<%p>] %pS\n", state,
+ (void *)current->task_state_change,
+ (void *)current->task_state_change);
+
+ __might_resched(file, line, 0);
+}
+EXPORT_SYMBOL(__might_sleep);
+
+void __cant_migrate(const char *file, int line)
+{
+ static unsigned long prev_jiffy;
+
+ if (irqs_disabled())
+ return;
+
+ if (is_migration_disabled(current))
+ return;
+
+ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
+ return;
+
+ if (preempt_count() > 0)
+ return;
+
+ if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
+ return;
+ prev_jiffy = jiffies;
+
+ pr_err("BUG: assuming non migratable context at %s:%d\n", file, line);
+ pr_err("in_atomic(): %d, irqs_disabled(): %d, migration_disabled() %u pid: %d, name: %s\n",
+ in_atomic(), irqs_disabled(), is_migration_disabled(current),
+ current->pid, current->comm);
+
+ debug_show_held_locks(current);
+ dump_stack();
+ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
+}
+EXPORT_SYMBOL_GPL(__cant_migrate);
+
+void __cant_sleep(const char *file, int line, int preempt_offset)
+{
+ static unsigned long prev_jiffy;
+
+ if (irqs_disabled())
+ return;
+
+ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
+ return;
+
+ if (preempt_count() > preempt_offset)
+ return;
+
+ if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
+ return;
+ prev_jiffy = jiffies;
+
+ printk(KERN_ERR "BUG: assuming atomic context at %s:%d\n", file, line);
+ printk(KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n",
+ in_atomic(), irqs_disabled(),
+ current->pid, current->comm);
+
+ debug_show_held_locks(current);
+ dump_stack();
+ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
+}
+EXPORT_SYMBOL_GPL(__cant_sleep);
+
+void __might_resched(const char *file, int line, unsigned int offsets)
+{
+ /* Ratelimiting timestamp: */
+ static unsigned long prev_jiffy;
+
+ unsigned long preempt_disable_ip;
+
+ /* WARN_ON_ONCE() by default, no rate limit required: */
+ rcu_sleep_check();
+
+ if ((preempt_count_equals(offsets) && !irqs_disabled() &&
+ !is_idle_task(current) && !current->non_block_count) ||
+ system_state == SYSTEM_BOOTING || system_state > SYSTEM_RUNNING ||
+ oops_in_progress)
+ return;
+
+ if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
+ return;
+ prev_jiffy = jiffies;
+
+ /* Save this before calling printk(), since that will clobber it: */
+ preempt_disable_ip = get_preempt_disable_ip(current);
+
+ printk(KERN_ERR
+ "BUG: sleeping function called from invalid context at %s:%d\n",
+ file, line);
+ printk(KERN_ERR
+ "in_atomic(): %d, irqs_disabled(): %d, non_block: %d, pid: %d, name: %s\n",
+ in_atomic(), irqs_disabled(), current->non_block_count,
+ current->pid, current->comm);
+
+ if (task_stack_end_corrupted(current))
+ printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
+
+ debug_show_held_locks(current);
+ if (irqs_disabled())
+ print_irqtrace_events(current);
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
+ && !preempt_count_equals(offsets)) {
+ pr_err("Preemption disabled at:");
+ print_ip_sym(KERN_ERR, preempt_disable_ip);
+ }
+ dump_stack();
+ add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
+}
+EXPORT_SYMBOL(__might_resched);
+#endif
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static inline void normalise_rt_tasks(void)
+{
+ struct sched_attr attr = {};
+ struct task_struct *g, *p;
+ struct rq_flags rf;
+ struct rq *rq;
+
+ read_lock(&tasklist_lock);
+ for_each_process_thread(g, p) {
+ /*
+ * Only normalize user tasks:
+ */
+ if (p->flags & PF_KTHREAD)
+ continue;
+
+ if (!rt_task(p) && !iso_task(p))
+ continue;
+
+ rq = task_rq_lock(p, &rf);
+ __setscheduler(p, rq, SCHED_NORMAL, 0, &attr, false);
+ task_rq_unlock(rq, p, &rf);
+ }
+ read_unlock(&tasklist_lock);
+}
+
+void normalize_rt_tasks(void)
+{
+ normalise_rt_tasks();
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+#if defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB)
+/*
+ * These functions are only useful for the IA64 MCA handling, or kdb.
+ *
+ * They can only be called when the whole system has been
+ * stopped - every CPU needs to be quiescent, and no scheduling
+ * activity can take place. Using them for anything else would
+ * be a serious bug, and as a result, they aren't even visible
+ * under any other configuration.
+ */
+
+/**
+ * curr_task - return the current task for a given CPU.
+ * @cpu: the processor in question.
+ *
+ * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
+ *
+ * Return: The current task for @cpu.
+ */
+struct task_struct *curr_task(int cpu)
+{
+ return cpu_curr(cpu);
+}
+
+#endif /* defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) */
+
+#ifdef CONFIG_IA64
+/**
+ * ia64_set_curr_task - set the current task for a given CPU.
+ * @cpu: the processor in question.
+ * @p: the task pointer to set.
+ *
+ * Description: This function must only be used when non-maskable interrupts
+ * are serviced on a separate stack. It allows the architecture to switch the
+ * notion of the current task on a CPU in a non-blocking manner. This function
+ * must be called with all CPU's synchronised, and interrupts disabled, the
+ * and caller must save the original value of the current task (see
+ * curr_task() above) and restore that value before reenabling interrupts and
+ * re-starting the system.
+ *
+ * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
+ */
+void ia64_set_curr_task(int cpu, struct task_struct *p)
+{
+ cpu_curr(cpu) = p;
+}
+
+#endif
+
+#ifdef CONFIG_SCHED_DEBUG
+__read_mostly bool sched_debug_enabled;
+
+void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
+ struct seq_file *m)
+{
+ seq_printf(m, "%s (%d, #threads: %d)\n", p->comm, task_pid_nr_ns(p, ns),
+ get_nr_threads(p));
+}
+
+void proc_sched_set_task(struct task_struct *p)
+{}
+#endif
+
+#ifdef CONFIG_CGROUP_SCHED
+static void sched_free_group(struct task_group *tg)
+{
+ kmem_cache_free(task_group_cache, tg);
+}
+
+/* allocate runqueue etc for a new task group */
+struct task_group *sched_create_group(struct task_group *parent)
+{
+ struct task_group *tg;
+
+ tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO);
+ if (!tg)
+ return ERR_PTR(-ENOMEM);
+
+ init_tg_cgroup_defaults(tg);
+ return tg;
+}
+
+void sched_online_group(struct task_group *tg, struct task_group *parent)
+{
+}
+
+/* rcu callback to free various structures associated with a task group */
+static void sched_free_group_rcu(struct rcu_head *rhp)
+{
+ /* Now it should be safe to free those cfs_rqs */
+ sched_free_group(container_of(rhp, struct task_group, rcu));
+}
+
+void sched_destroy_group(struct task_group *tg)
+{
+ /* Wait for possible concurrent references to cfs_rqs complete */
+ call_rcu(&tg->rcu, sched_free_group_rcu);
+}
+
+void sched_release_group(struct task_group *tg)
+{
+}
+
+static inline struct task_group *css_tg(struct cgroup_subsys_state *css)
+{
+ return css ? container_of(css, struct task_group, css) : NULL;
+}
+
+static struct cgroup_subsys_state *
+cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
+{
+ struct task_group *parent = css_tg(parent_css);
+ struct task_group *tg;
+
+ if (!parent) {
+ /* This is early initialization for the top cgroup */
+ return &root_task_group.css;
+ }
+
+ tg = sched_create_group(parent);
+ if (IS_ERR(tg))
+ return ERR_PTR(-ENOMEM);
+ return &tg->css;
+}
+
+/* Expose task group only after completing cgroup initialization */
+static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
+{
+ struct task_group *tg = css_tg(css);
+ struct task_group *parent = css_tg(css->parent);
+
+ if (parent)
+ sched_online_group(tg, parent);
+ return 0;
+}
+
+static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
+{
+ struct task_group *tg = css_tg(css);
+
+ sched_release_group(tg);
+}
+
+static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
+{
+ struct task_group *tg = css_tg(css);
+
+ /*
+ * Relies on the RCU grace period between css_released() and this.
+ */
+ sched_free_group(tg);
+}
+
+static void cpu_cgroup_fork(struct task_struct *task)
+{
+}
+
+static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
+{
+ return 0;
+}
+
+static void cpu_cgroup_attach(struct cgroup_taskset *tset)
+{
+}
+
+/*
+ * Accept-and-ignore cpu controller files.
+ *
+ * Mainline wires these to CFS shares/bandwidth. MuQSS has neither, but
+ * container runtimes and systemd write CPUWeight=/CPUQuota=/--cpus and
+ * fail if the files are missing. Validate ranges, store for readback,
+ * and leave scheduling unaffected.
+ *
+ * nice↔weight table matches CFS (sched_prio_to_weight) so weight.nice
+ * round-trips to the same values userspace expects.
+ */
+static const int muqss_prio_to_weight[40] = {
+ /* -20 */ 88761, 71755, 56483, 46273, 36291,
+ /* -15 */ 29154, 23254, 18705, 14949, 11916,
+ /* -10 */ 9548, 7620, 6100, 4904, 3906,
+ /* -5 */ 3121, 2501, 1991, 1586, 1277,
+ /* 0 */ 1024, 820, 655, 526, 423,
+ /* 5 */ 335, 272, 215, 172, 137,
+ /* 10 */ 110, 87, 70, 56, 45,
+ /* 15 */ 36, 29, 23, 18, 15,
+};
+
+static unsigned long muqss_weight_from_cgroup(unsigned long cgrp_weight)
+{
+ return DIV_ROUND_CLOSEST_ULL(cgrp_weight * 1024, CGROUP_WEIGHT_DFL);
+}
+
+static unsigned long muqss_weight_to_cgroup(unsigned long weight)
+{
+ return clamp_t(unsigned long,
+ DIV_ROUND_CLOSEST_ULL(weight * CGROUP_WEIGHT_DFL, 1024),
+ CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX);
+}
+
+static u64 cpu_weight_read_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return css_tg(css)->weight;
+}
+
+static int cpu_weight_write_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft, u64 cgrp_weight)
+{
+ if (cgrp_weight < CGROUP_WEIGHT_MIN || cgrp_weight > CGROUP_WEIGHT_MAX)
+ return -ERANGE;
+
+ css_tg(css)->weight = cgrp_weight;
+ return 0;
+}
+
+static s64 cpu_weight_nice_read_s64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ unsigned long weight = muqss_weight_from_cgroup(css_tg(css)->weight);
+ int last_delta = INT_MAX;
+ int prio, delta;
+
+ for (prio = 0; prio < ARRAY_SIZE(muqss_prio_to_weight); prio++) {
+ delta = abs(muqss_prio_to_weight[prio] - (int)weight);
+ if (delta >= last_delta)
+ break;
+ last_delta = delta;
+ }
+
+ return PRIO_TO_NICE(prio - 1 + MAX_RT_PRIO);
+}
+
+static int cpu_weight_nice_write_s64(struct cgroup_subsys_state *css,
+ struct cftype *cft, s64 nice)
+{
+ int idx;
+
+ if (nice < MIN_NICE || nice > MAX_NICE)
+ return -ERANGE;
+
+ idx = NICE_TO_PRIO(nice) - MAX_RT_PRIO;
+ idx = array_index_nospec(idx, ARRAY_SIZE(muqss_prio_to_weight));
+ css_tg(css)->weight =
+ muqss_weight_to_cgroup(muqss_prio_to_weight[idx]);
+ return 0;
+}
+
+static s64 cpu_idle_read_s64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return css_tg(css)->idle;
+}
+
+static int cpu_idle_write_s64(struct cgroup_subsys_state *css,
+ struct cftype *cft, s64 idle)
+{
+ if (idle != 0 && idle != 1)
+ return -EINVAL;
+
+ css_tg(css)->idle = idle;
+ return 0;
+}
+
+static void cpu_period_quota_print(struct seq_file *sf, long period, long quota)
+{
+ if (quota < 0)
+ seq_puts(sf, "max");
+ else
+ seq_printf(sf, "%ld", quota);
+
+ seq_printf(sf, " %ld\n", period);
+}
+
+static int cpu_period_quota_parse(char *buf, u64 *period_us_p, u64 *quota_us_p)
+{
+ char tok[21]; /* U64_MAX */
+
+ if (sscanf(buf, "%20s %llu", tok, period_us_p) < 1)
+ return -EINVAL;
+
+ if (sscanf(tok, "%llu", quota_us_p) < 1) {
+ if (!strcmp(tok, "max"))
+ *quota_us_p = U64_MAX;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cpu_max_show(struct seq_file *sf, void *v)
+{
+ struct task_group *tg = css_tg(seq_css(sf));
+ s64 quota = tg->quota_us;
+
+ cpu_period_quota_print(sf, tg->period_us, quota);
+ return 0;
+}
+
+static ssize_t cpu_max_write(struct kernfs_open_file *of,
+ char *buf, size_t nbytes, loff_t off)
+{
+ struct task_group *tg = css_tg(of_css(of));
+ u64 period_us = tg->period_us, quota_us;
+ int ret;
+
+ ret = cpu_period_quota_parse(buf, &period_us, &quota_us);
+ if (ret)
+ return ret;
+
+ if (!period_us || period_us > USEC_PER_SEC)
+ return -EINVAL;
+
+ tg->period_us = period_us;
+ tg->quota_us = (quota_us == U64_MAX) ? -1 : (s64)quota_us;
+ return nbytes;
+}
+
+static u64 cpu_burst_read_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return css_tg(css)->burst_us;
+}
+
+static int cpu_burst_write_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft, u64 burst_us)
+{
+ struct task_group *tg = css_tg(css);
+
+ /* Burst must not exceed a finite quota when one is set. */
+ if (tg->quota_us >= 0 && burst_us > (u64)tg->quota_us)
+ return -EINVAL;
+
+ tg->burst_us = burst_us;
+ return 0;
+}
+
+/* Legacy v1 interfaces */
+static u64 cpu_shares_read_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return muqss_weight_from_cgroup(css_tg(css)->weight);
+}
+
+static int cpu_shares_write_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft, u64 share)
+{
+ if (share < 2 || share > 262144)
+ return -ERANGE;
+
+ css_tg(css)->weight = muqss_weight_to_cgroup(share);
+ return 0;
+}
+
+static u64 cpu_period_read_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return css_tg(css)->period_us;
+}
+
+static int cpu_period_write_u64(struct cgroup_subsys_state *css,
+ struct cftype *cft, u64 period_us)
+{
+ if (!period_us || period_us > USEC_PER_SEC)
+ return -EINVAL;
+
+ css_tg(css)->period_us = period_us;
+ return 0;
+}
+
+static s64 cpu_quota_read_s64(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return css_tg(css)->quota_us;
+}
+
+static int cpu_quota_write_s64(struct cgroup_subsys_state *css,
+ struct cftype *cft, s64 quota_us)
+{
+ if (quota_us < -1 || quota_us > (s64)USEC_PER_SEC * 1024)
+ return -EINVAL;
+
+ css_tg(css)->quota_us = quota_us;
+ return 0;
+}
+
+static struct cftype cpu_legacy_files[] = {
+ {
+ .name = "shares",
+ .read_u64 = cpu_shares_read_u64,
+ .write_u64 = cpu_shares_write_u64,
+ },
+ {
+ .name = "idle",
+ .read_s64 = cpu_idle_read_s64,
+ .write_s64 = cpu_idle_write_s64,
+ },
+ {
+ .name = "cfs_period_us",
+ .read_u64 = cpu_period_read_u64,
+ .write_u64 = cpu_period_write_u64,
+ },
+ {
+ .name = "cfs_quota_us",
+ .read_s64 = cpu_quota_read_s64,
+ .write_s64 = cpu_quota_write_s64,
+ },
+ {
+ .name = "cfs_burst_us",
+ .read_u64 = cpu_burst_read_u64,
+ .write_u64 = cpu_burst_write_u64,
+ },
+ { } /* Terminate */
+};
+
+static struct cftype cpu_files[] = {
+ {
+ .name = "weight",
+ .flags = CFTYPE_NOT_ON_ROOT,
+ .read_u64 = cpu_weight_read_u64,
+ .write_u64 = cpu_weight_write_u64,
+ },
+ {
+ .name = "weight.nice",
+ .flags = CFTYPE_NOT_ON_ROOT,
+ .read_s64 = cpu_weight_nice_read_s64,
+ .write_s64 = cpu_weight_nice_write_s64,
+ },
+ {
+ .name = "idle",
+ .flags = CFTYPE_NOT_ON_ROOT,
+ .read_s64 = cpu_idle_read_s64,
+ .write_s64 = cpu_idle_write_s64,
+ },
+ {
+ .name = "max",
+ .flags = CFTYPE_NOT_ON_ROOT,
+ .seq_show = cpu_max_show,
+ .write = cpu_max_write,
+ },
+ {
+ .name = "max.burst",
+ .flags = CFTYPE_NOT_ON_ROOT,
+ .read_u64 = cpu_burst_read_u64,
+ .write_u64 = cpu_burst_write_u64,
+ },
+ { } /* terminate */
+};
+
+static int cpu_extra_stat_show(struct seq_file *sf,
+ struct cgroup_subsys_state *css)
+{
+ return 0;
+}
+
+struct cgroup_subsys cpu_cgrp_subsys = {
+ .css_alloc = cpu_cgroup_css_alloc,
+ .css_online = cpu_cgroup_css_online,
+ .css_released = cpu_cgroup_css_released,
+ .css_free = cpu_cgroup_css_free,
+ .css_extra_stat_show = cpu_extra_stat_show,
+ .fork = cpu_cgroup_fork,
+ .can_attach = cpu_cgroup_can_attach,
+ .attach = cpu_cgroup_attach,
+ .legacy_cftypes = cpu_legacy_files,
+ .dfl_cftypes = cpu_files,
+ .early_init = true,
+ .threaded = true,
+};
+#endif /* CONFIG_CGROUP_SCHED */
+
+void call_trace_sched_update_nr_running(struct rq *rq, int count)
+{
+ trace_sched_update_nr_running_tp(rq, count);
+}
+
+/* CFS Compat */
+#ifdef CONFIG_RCU_TORTURE_TEST
+int sysctl_sched_rt_runtime;
+#endif
+
+/*
+ * Compatibility layer for core.c interfaces added after 5.12.
+ *
+ * These are all consumed by code outside the scheduler. Where the feature
+ * behind them does not exist under MuQSS (deadline bandwidth, sched_ext,
+ * mm_cid, the CFS runqueue debugfs) the implementation is deliberately inert
+ * rather than absent, so mainline callers need no #ifdef.
+ */
+
+/*
+ * Tracepoint helpers behind set_current_state()/set_need_resched(). Callers
+ * MUST guard these with a tracepoint_enabled() check, which is why they use
+ * the unguarded trace_call__<tp>() form.
+ */
+void __trace_set_current_state(int state_value)
+{
+ trace_call__sched_set_state_tp(current, state_value);
+}
+EXPORT_SYMBOL(__trace_set_current_state);
+
+void __trace_set_need_resched(struct task_struct *curr, int tif)
+{
+ trace_call__sched_set_need_resched_tp(curr, smp_processor_id(), tif);
+}
+EXPORT_SYMBOL_GPL(__trace_set_need_resched);
+
+unsigned long long nr_context_switches_cpu(int cpu)
+{
+ return cpu_rq(cpu)->nr_switches;
+}
+
+/*
+ * External (non-sched/) callers cannot see task_on_rq_queued(); wrap it.
+ * Used by tick-sched nohz full path among others.
+ */
+bool sched_task_on_rq(struct task_struct *p)
+{
+ return task_on_rq_queued(p);
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long ip = 0;
+ unsigned int state;
+
+ if (!p || p == current)
+ return 0;
+
+ /* Only get wchan if task is blocked and we can keep it that way. */
+ raw_spin_lock_irq(&p->pi_lock);
+ state = READ_ONCE(p->__state);
+ smp_rmb(); /* see try_to_wake_up() */
+ if (state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq)
+ ip = __get_wchan(p);
+ raw_spin_unlock_irq(&p->pi_lock);
+
+ return ip;
+}
+
+/*
+ * Fork path. MuQSS does no cgroup bandwidth accounting and has no sched_ext
+ * to cancel, so these only need to exist.
+ */
+int sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs)
+{
+ return 0;
+}
+
+void sched_cancel_fork(struct task_struct *p)
+{
+}
+
+/*
+ * rt_mutex helpers. MuQSS has no proxy execution; pre/post still run the
+ * worker submit/update pair so blocking on an rt_mutex flushes plugged IO.
+ * rt_mutex_schedule() must not re-enter schedule() or submit_work runs twice.
+ */
+#ifdef CONFIG_RT_MUTEXES
+#define fetch_and_set(x, v) ({ int _x = (x); (x) = (v); _x; })
+#endif
+
+void rt_mutex_pre_schedule(void)
+{
+#ifdef CONFIG_RT_MUTEXES
+ lockdep_assert(!fetch_and_set(current->sched_rt_mutex, 1));
+#endif
+ sched_submit_work(current);
+}
+
+/* Futex callers cannot have worker state or plugged IO to submit. */
+void rt_mutex_futex_pre_schedule(void)
+{
+ lockdep_assert(!(current->flags & (PF_WQ_WORKER | PF_IO_WORKER)));
+ lockdep_assert(!current->plug);
+#ifdef CONFIG_RT_MUTEXES
+ lockdep_assert(!fetch_and_set(current->sched_rt_mutex, 1));
+#endif
+}
+
+void rt_mutex_schedule(void)
+{
+#ifdef CONFIG_RT_MUTEXES
+ lockdep_assert(current->sched_rt_mutex);
+#endif
+ __schedule_loop(SM_NONE);
+}
+
+void rt_mutex_post_schedule(void)
+{
+ sched_update_worker(current);
+#ifdef CONFIG_RT_MUTEXES
+ lockdep_assert(fetch_and_set(current->sched_rt_mutex, 0));
+#endif
+}
+
+void rt_mutex_futex_post_schedule(void)
+{
+#ifdef CONFIG_RT_MUTEXES
+ lockdep_assert(fetch_and_set(current->sched_rt_mutex, 0));
+#endif
+}
+
+int dl_task_check_affinity(struct task_struct *p __always_unused,
+ const struct cpumask *mask __always_unused)
+{
+ /* MuQSS has no deadline bandwidth admission. */
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+/* Callers must hold p->pi_lock across the read and its use. */
+static const struct cpumask *task_user_cpus(struct task_struct *p)
+{
+ lockdep_assert_held(&p->pi_lock);
+
+ if (!p->user_cpus_ptr)
+ return cpu_possible_mask;
+ return p->user_cpus_ptr;
+}
+
+/*
+ * Copy out the intersection of the task's user-requested mask and @mask.
+ * pi_lock keeps user_cpus_ptr alive for the copy: everything that frees it
+ * clears the pointer under task_rq_lock(), which nests pi_lock, and only
+ * frees once that has been dropped.
+ */
+static bool user_cpus_and(struct task_struct *p, struct cpumask *dst,
+ const struct cpumask *mask)
+{
+ unsigned long flags;
+ bool ret;
+
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
+ ret = cpumask_and(dst, task_user_cpus(p), mask);
+ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+
+ return ret;
+}
+
+/*
+ * Intersect the task's user-requested mask with @subset_mask and apply it.
+ * Empty intersection leaves affinity unchanged.
+ */
+static int restrict_cpus_allowed_ptr(struct task_struct *p,
+ struct cpumask *new_mask,
+ const struct cpumask *subset_mask)
+{
+ if (!user_cpus_and(p, new_mask, subset_mask))
+ return -EINVAL;
+
+ return __set_cpus_allowed_ptr(p, new_mask, 0);
+}
+#endif
+
+/*
+ * Restrict @p to CPUs it can actually run on (task_cpu_possible_mask()).
+ * ARM64 32-bit execve uses this when 64-bit-only CPUs exist.
+ */
+void force_compatible_cpus_allowed_ptr(struct task_struct *p)
+{
+ const struct cpumask *override_mask = task_cpu_possible_mask(p);
+#ifdef CONFIG_SMP
+ cpumask_var_t new_mask;
+
+ alloc_cpumask_var(&new_mask, GFP_KERNEL);
+
+ /*
+ * __migrate_task() can fail silently if the dest CPU is offlined
+ * concurrently, so hold the hotplug lock across the move.
+ */
+ cpus_read_lock();
+ if (!cpumask_available(new_mask))
+ goto out_set_mask;
+
+ if (!restrict_cpus_allowed_ptr(p, new_mask, override_mask))
+ goto out_free_mask;
+
+ cpuset_cpus_allowed(p, new_mask);
+ override_mask = new_mask;
+
+out_set_mask:
+ if (printk_ratelimit()) {
+ printk_deferred("Overriding affinity for process %d (%s) to CPUs %*pbl\n",
+ task_pid_nr(p), p->comm,
+ cpumask_pr_args(override_mask));
+ }
+
+ WARN_ON(set_cpus_allowed_ptr(p, override_mask));
+out_free_mask:
+ cpus_read_unlock();
+ free_cpumask_var(new_mask);
+#else
+ WARN_ON(set_cpus_allowed_ptr(p, override_mask));
+#endif
+}
+
+/*
+ * Restore the affinity previously restricted by
+ * force_compatible_cpus_allowed_ptr(). Caller serialises the pair.
+ */
+void relax_compatible_cpus_allowed_ptr(struct task_struct *p)
+{
+#ifdef CONFIG_SMP
+ cpumask_var_t cpus_allowed, new_mask;
+ int ret = -ENOMEM;
+
+ if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL))
+ goto warn;
+ if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
+ goto out_free_cpus_allowed;
+
+ cpuset_cpus_allowed(p, cpus_allowed);
+ user_cpus_and(p, new_mask, cpus_allowed);
+ ret = __set_cpus_allowed_ptr(p, new_mask, SCA_CHECK);
+
+ free_cpumask_var(new_mask);
+out_free_cpus_allowed:
+ free_cpumask_var(cpus_allowed);
+warn:
+ WARN_ON_ONCE(ret);
+#else
+ WARN_ON(set_cpus_allowed_ptr(p, cpu_possible_mask));
+#endif
+}
+
+const char *preempt_model_str(void)
+{
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
+ return "PREEMPT_RT";
+ if (preempt_model_full())
+ return "PREEMPT";
+ if (preempt_model_voluntary())
+ return "VOLUNTARY";
+ return "NONE";
+}
+
+#ifdef CONFIG_SMP
+bool cpus_equal_capacity(int this_cpu, int that_cpu)
+{
+ if (!sched_asym_cpucap_active())
+ return true;
+
+ if (this_cpu == that_cpu)
+ return true;
+
+ return arch_scale_cpu_capacity(this_cpu) == arch_scale_cpu_capacity(that_cpu);
+}
+
+void set_cpus_allowed_force(struct task_struct *p, const struct cpumask *new_mask)
+{
+ struct affinity_context ac = {
+ .new_mask = new_mask,
+ .user_mask = NULL,
+ .flags = SCA_USER,
+ };
+
+ do_set_cpus_allowed(p, &ac);
+}
+
+void ___migrate_enable(void)
+{
+ __set_cpus_allowed_ptr(current, &current->cpus_mask,
+ SCA_MIGRATE_ENABLE);
+}
+#else /* !CONFIG_SMP */
+/*
+ * Nothing ever repoints cpus_ptr away from cpus_mask on UP, so
+ * __migrate_enable() never reaches here - it just has to link.
+ */
+void ___migrate_enable(void)
+{
+}
+#endif /* CONFIG_SMP */
+EXPORT_SYMBOL_GPL(___migrate_enable);
+
+/*
+ * user_cpus_ptr records the affinity a task asked for so that it can be
+ * restored after a temporary restriction: sched_setaffinity() stores it, and
+ * bind_zero() stores the mask it displaces from a task that would otherwise
+ * have been stranded by a CPU going down. Either way the child inherits both
+ * the restriction (zerobound, copied by dup_task_struct()) and the mask that
+ * has to be put back for it.
+ */
+int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
+ int node)
+{
+ cpumask_t *user_mask;
+ unsigned long flags;
+
+ dst->user_cpus_ptr = NULL;
+
+ /*
+ * Racing here is harmless: losing it just means the child forgoes a
+ * restore it would have got for free, and taking the pi_lock on every
+ * fork to close it is not worth that.
+ */
+ if (data_race(!src->user_cpus_ptr))
+ return 0;
+
+ user_mask = kmalloc_node(cpumask_size(), GFP_KERNEL, node);
+ if (!user_mask)
+ return -ENOMEM;
+
+ raw_spin_lock_irqsave(&src->pi_lock, flags);
+ if (src->user_cpus_ptr) {
+ swap(dst->user_cpus_ptr, user_mask);
+ cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
+ }
+ raw_spin_unlock_irqrestore(&src->pi_lock, flags);
+
+ kfree(user_mask);
+
+ return 0;
+}
+
+void release_user_cpus_ptr(struct task_struct *p)
+{
+ kfree(p->user_cpus_ptr);
+ p->user_cpus_ptr = NULL;
+}
+
+/*
+ * Modules cannot see the runqueues layout, so export out-of-line wrappers
+ * (INSTANTIATE_EXPORTED_MIGRATE_DISABLE makes the inlines become externs).
+ */
+void migrate_disable(void)
+{
+ __migrate_disable();
+}
+EXPORT_SYMBOL_GPL(migrate_disable);
+
+void migrate_enable(void)
+{
+ __migrate_enable();
+}
+EXPORT_SYMBOL_GPL(migrate_enable);
+
+/*
+ * MuQSS picks the CPU for a task at schedule() time rather than at exec, so
+ * there is nothing useful to do here.
+ */
+void sched_exec(void)
+{
+}
+
+/*
+ * Deadline bandwidth accounting. There is no deadline class, so no bandwidth
+ * is ever reserved and cpuset has nothing to move between root domains.
+ */
+u64 dl_cookie;
+
+int dl_bw_alloc(int cpu, u64 dl_bw)
+{
+ return 0;
+}
+
+void dl_bw_free(int cpu, u64 dl_bw)
+{
+}
+
+void sched_set_fifo_secondary(struct task_struct *p)
+{
+ struct sched_param sp = { .sched_priority = MAX_RT_PRIO / 2 - 1 };
+
+ WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0);
+}
+EXPORT_SYMBOL_GPL(sched_set_fifo_secondary);
+
+/*
+ * Scheduler debugfs. debug.c is CFS/EEVDF runqueue introspection and is not
+ * built under MuQSS; /proc/<pid>/sched reports nothing.
+ */
+bool sched_debug_verbose;
+
+#ifdef CONFIG_SMP
+/* Only topology.c calls these, and it is not built on UP. */
+void update_sched_domain_debugfs(void)
+{
+}
+
+void dirty_sched_domain_sysctl(int cpu)
+{
+}
+#endif /* CONFIG_SMP */
+
+void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
+ struct seq_file *m)
+{
+}
+
+void proc_sched_set_task(struct task_struct *p)
+{
+}
diff --git a/kernel/sched/MuQSS.h b/kernel/sched/MuQSS.h
new file mode 100644
--- /dev/null
+++ b/kernel/sched/MuQSS.h
@@ -0,0 +1,1254 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef MUQSS_SCHED_H
+#define MUQSS_SCHED_H
+
+#include <linux/sched/clock.h>
+#include <linux/sched/cpufreq.h>
+#include <linux/sched/cputime.h>
+#include <linux/sched/deadline.h>
+#include <linux/sched/debug.h>
+#include <linux/sched/hotplug.h>
+#include <linux/sched/init.h>
+#include <linux/sched/isolation.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/nohz.h>
+#include <linux/sched/signal.h>
+#include <linux/sched/smt.h>
+#include <linux/sched/stat.h>
+#include <linux/sched/task.h>
+#include <linux/sched/task_stack.h>
+#include <linux/sched/topology.h>
+#include <linux/sched/wake_q.h>
+
+#include <uapi/linux/sched/types.h>
+
+#include <linux/cgroup.h>
+#include <linux/cpufreq.h>
+#include <linux/cpuidle.h>
+#include <linux/cpuset.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/energy_model.h>
+#include <linux/freezer.h>
+#include <linux/kernel_stat.h>
+#include <linux/kthread.h>
+#include <linux/membarrier.h>
+#include <linux/livepatch.h>
+#include <linux/proc_fs.h>
+#include <linux/psi.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/skip_list.h>
+#include <linux/smp.h>
+#include <linux/stop_machine.h>
+#include <linux/suspend.h>
+#include <linux/swait.h>
+#include <linux/syscalls.h>
+#include <linux/tick.h>
+#include <linux/tsacct_kern.h>
+#include <linux/u64_stats_sync.h>
+
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#endif
+
+/*
+ * cpupri.h is deliberately not included: MuQSS has no RT class priority
+ * bitmap, root_domain keeps an opaque pointer instead, and pulling the header
+ * in would clash with the no-op cpupri_init()/cpupri_cleanup() below.
+ */
+
+#include <trace/events/sched.h>
+
+#ifdef CONFIG_SCHED_DEBUG
+# define SCHED_WARN_ON(x) WARN_ONCE(x, #x)
+#else
+# define SCHED_WARN_ON(x) ((void)(x))
+#endif
+
+/* Wake flags. The first three directly map to some SD flag value */
+#define WF_EXEC 0x02 /* Wakeup after exec; maps to SD_BALANCE_EXEC */
+#define WF_FORK 0x04 /* Wakeup after fork; maps to SD_BALANCE_FORK */
+#define WF_TTWU 0x08 /* Wakeup; maps to SD_BALANCE_WAKE */
+
+#define WF_SYNC 0x10 /* Waker goes to sleep after wakeup */
+#define WF_MIGRATED 0x20 /* Internal use, task got migrated */
+#define WF_CURRENT_CPU 0x40 /* Prefer to move the wakee to the current CPU. */
+#define WF_ON_CPU 0x80 /* Wakee is on_cpu */
+
+#ifdef CONFIG_SMP
+static_assert(WF_EXEC == SD_BALANCE_EXEC);
+static_assert(WF_FORK == SD_BALANCE_FORK);
+static_assert(WF_TTWU == SD_BALANCE_WAKE);
+#endif
+
+/* task_struct::on_rq states: */
+#define TASK_ON_RQ_QUEUED 1
+#define TASK_ON_RQ_MIGRATING 2
+
+extern void call_trace_sched_update_nr_running(struct rq *rq, int count);
+
+struct rq;
+
+#ifdef CONFIG_SMP
+
+static inline bool sched_asym_prefer(int a, int b)
+{
+ return arch_asym_cpu_priority(a) > arch_asym_cpu_priority(b);
+}
+
+struct perf_domain {
+ struct em_perf_domain *em_pd;
+ struct perf_domain *next;
+ struct rcu_head rcu;
+};
+
+/* Scheduling group status flags */
+#define SG_OVERLOAD 0x1 /* More than one runnable task on a CPU. */
+#define SG_OVERUTILIZED 0x2 /* One or more CPUs are over-utilized. */
+
+/*
+ * We add the notion of a root-domain which will be used to define per-domain
+ * variables. Each exclusive cpuset essentially defines an island domain by
+ * fully partitioning the member cpus from any other cpuset. Whenever a new
+ * exclusive cpuset is created, we also create and attach a new root-domain
+ * object.
+ *
+ */
+struct root_domain {
+ atomic_t refcount;
+ atomic_t rto_count;
+ struct rcu_head rcu;
+ cpumask_var_t span;
+ cpumask_var_t online;
+
+ /*
+ * Indicate pullable load on at least one CPU, e.g:
+ * - More than one runnable task
+ * - Running task is misfit
+ */
+ int overload;
+
+ /* Indicate one or more cpus over-utilized (tipping point) */
+ int overutilized;
+
+ /*
+ * The bit corresponding to a CPU gets set here if such CPU has more
+ * than one runnable -deadline task (as it is below for RT tasks).
+ */
+ cpumask_var_t dlo_mask;
+ atomic_t dlo_count;
+
+ /* Replace unused CFS structures with void */
+ //struct dl_bw dl_bw;
+ //struct cpudl cpudl;
+ void *dl_bw;
+ void *cpudl;
+ u64 visit_cookie;
+
+ /*
+ * The "RT overload" flag: it gets set if a CPU has more than
+ * one runnable RT task.
+ */
+ cpumask_var_t rto_mask;
+ //struct cpupri cpupri;
+ void *cpupri;
+
+ unsigned long max_cpu_capacity;
+
+ /*
+ * NULL-terminated list of performance domains intersecting with the
+ * CPUs of the rd. Protected by RCU.
+ */
+ struct perf_domain *pd;
+};
+
+extern void init_defrootdomain(void);
+extern int sched_init_domains(const struct cpumask *cpu_map);
+extern void rq_attach_root(struct rq *rq, struct root_domain *rd);
+
+static inline void cpupri_cleanup(void __maybe_unused *cpupri)
+{
+}
+
+static inline void cpudl_cleanup(void __maybe_unused *cpudl)
+{
+}
+
+static inline void init_dl_bw(void __maybe_unused *dl_bw)
+{
+}
+
+static inline int cpudl_init(void __maybe_unused *dl_bw)
+{
+ return 0;
+}
+
+static inline int cpupri_init(void __maybe_unused *cpupri)
+{
+ return 0;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * This is the main, per-CPU runqueue data structure.
+ * This data should only be modified by the local cpu.
+ */
+struct rq {
+ raw_spinlock_t *lock;
+ raw_spinlock_t *orig_lock;
+
+ struct task_struct __rcu *curr;
+ struct task_struct *idle;
+ struct task_struct *stop;
+ struct mm_struct *prev_mm;
+
+ unsigned int nr_running;
+ /*
+ * This is part of a global counter where only the total sum
+ * over all CPUs matters. A task can increase this counter on
+ * one CPU and if it got migrated afterwards it may decrease
+ * it on another CPU. Always updated under the runqueue lock:
+ */
+ unsigned long nr_uninterruptible;
+#ifdef CONFIG_SMP
+ unsigned int ttwu_pending;
+#endif
+ /*
+ * migrate_disable() nesting count. Mainline's migrate_disable() and
+ * __migrate_enable() are inline in <linux/sched.h> and reach this via
+ * the RQ_nr_pinned offset generated from rq-offsets.c, so the member
+ * is required whether or not MuQSS itself consults it.
+ */
+ unsigned int nr_pinned;
+ u64 nr_switches;
+
+ /*
+ * Isolated curr snapshot for lockless peeks. Own cacheline so
+ * last_jiffy / niffies (and remote synchronise_niffies()) do not
+ * invalidate it. Under SMT_NICE this is four fields; without it,
+ * deadline + prio only. Do not pull nr_running, online, or sl in.
+ */
+ u64 rq_deadline ____cacheline_aligned;
+ int rq_prio;
+#ifdef CONFIG_SMT_NICE
+ struct mm_struct *rq_mm;
+ int rq_smt_bias; /* Policy/nice level bias across smt siblings */
+#endif
+ u8 __rq_snap_pad[0] ____cacheline_aligned;
+
+ unsigned long last_scheduler_tick; /* Last jiffy this RQ ticked */
+ unsigned long last_jiffy; /* Last jiffy this RQ updated rq clock */
+ u64 niffies; /* Last time this RQ updated rq clock */
+ u64 jiffy_niffies; /* Niffies as counted by the tick alone */
+
+ u64 load_update; /* When we last updated load */
+ unsigned long load_avg; /* Rolling load average */
+#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
+ u64 irq_load_update; /* When we last updated IRQ load */
+ unsigned long irq_load_avg; /* Rolling IRQ load average */
+#endif
+ /* Accurate timekeeping data */
+ unsigned long user_ns, nice_ns, irq_ns, softirq_ns, system_ns,
+ iowait_ns, idle_ns;
+ atomic_t nr_iowait;
+
+#ifdef CONFIG_MEMBARRIER
+ int membarrier_state;
+#endif
+
+ /*
+ * MuQSS runs no deadline server. topology.c unconditionally tests
+ * rq->fair_server.dl_server when attaching a root domain, so carry a
+ * one-byte flag that is never set rather than #ifdef that code out.
+ * __dl_server_attach_root() below is a no-op taking void *, so the
+ * member's type does not have to match sched_dl_entity.
+ */
+ struct {
+ bool dl_server;
+ } fair_server;
+
+ skiplist_node *node;
+ skiplist *sl;
+#ifdef CONFIG_SMP
+ struct task_struct *preempt; /* Preempt triggered on this task */
+ struct task_struct *preempting; /* Hint only, what task is preempting */
+
+ int cpu; /* cpu of this runqueue */
+ bool online;
+
+ struct root_domain *rd;
+ struct sched_domain *sd;
+
+ unsigned long cpu_capacity_orig;
+
+ int *cpu_locality; /* CPU relative cache distance */
+ struct rq **rq_order; /* Shared RQs ordered by relative cache distance */
+ skiplist **sl_order; /* Leaders' skiplists, parallel to rq_order */
+ struct rq **cpu_order; /* RQs of discrete CPUs ordered by distance */
+
+ bool is_leader;
+ struct rq *smp_leader; /* First physical CPU per node */
+#ifdef CONFIG_SCHED_THERMAL_PRESSURE
+ struct sched_avg avg_thermal;
+#endif /* CONFIG_SCHED_THERMAL_PRESSURE */
+#ifdef CONFIG_SCHED_SMT
+ struct rq *smt_leader; /* First logical CPU in SMT siblings */
+ cpumask_t thread_mask;
+ bool has_smt_sibling; /* This CPU has SMT siblings at all */
+#endif /* CONFIG_SCHED_SMT */
+#ifdef CONFIG_SCHED_MC
+ struct rq *mc_leader; /* First logical CPU in MC siblings */
+ cpumask_t core_mask;
+ bool (*cache_idle)(struct rq *rq);
+ /* See if all cache siblings are idle */
+#endif /* CONFIG_SCHED_MC */
+ /* last busy→idle, wakeup idle pick */
+ unsigned long idle_jiffy;
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+ u64 prev_irq_time;
+ u64 psi_irq_time;
+#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
+#ifdef CONFIG_PARAVIRT
+ u64 prev_steal_time;
+#endif /* CONFIG_PARAVIRT */
+#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
+ u64 prev_steal_time_rq;
+#endif /* CONFIG_PARAVIRT_TIME_ACCOUNTING */
+
+ u64 clock, last_tick;
+ /* Ensure that all clocks are in the same cache line */
+ u64 clock_task ____cacheline_aligned;
+ int dither;
+
+ int iso_ticks;
+ bool iso_refractory;
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+ struct hrtimer hrexpiry_timer;
+ /*
+ * Deferred start/cancel around __schedule() — same scheme as mainline
+ * hrtick. Reprogramming the oneshot clockevent from set_rq_task() on
+ * every context switch under the rq lock starves TIMER_SOFTIRQ on SMP.
+ */
+ call_single_data_t hrexpiry_csd;
+ unsigned int hrexpiry_sched;
+ s64 hrexpiry_delay;
+ ktime_t hrexpiry_time;
+#endif
+
+ int rt_nr_running; /* Number real time tasks running */
+#ifdef CONFIG_SCHEDSTATS
+
+ /* latency stats */
+ struct sched_info rq_sched_info;
+ unsigned long long rq_cpu_time;
+ /* could above be rq->cfs_rq.exec_clock + rq->rt_rq.rt_runtime ? */
+
+ /* sys_sched_yield() stats */
+ unsigned int yld_count;
+
+ /* schedule() stats */
+ unsigned int sched_switch;
+ unsigned int sched_count;
+ unsigned int sched_goidle;
+
+ /* try_to_wake_up() stats */
+ unsigned int ttwu_count;
+ unsigned int ttwu_local;
+#endif /* CONFIG_SCHEDSTATS */
+
+#ifdef CONFIG_CPU_IDLE
+ /* Must be inspected within a rcu lock section */
+ struct cpuidle_state *idle_state;
+#endif
+};
+
+static inline u64 __rq_clock_broken(struct rq *rq)
+{
+ return READ_ONCE(rq->clock);
+}
+
+static inline u64 rq_clock(struct rq *rq)
+{
+ lockdep_assert_held(rq->lock);
+
+ return rq->clock;
+}
+
+static inline u64 rq_clock_task(struct rq *rq)
+{
+ lockdep_assert_held(rq->lock);
+
+ return rq->clock_task;
+}
+
+/**
+ * By default the decay is the default pelt decay period.
+ * The decay shift can change the decay period in
+ * multiples of 32.
+ * Decay shift Decay period(ms)
+ * 0 32
+ * 1 64
+ * 2 128
+ * 3 256
+ * 4 512
+ */
+extern int sched_thermal_decay_shift;
+
+static inline u64 rq_clock_thermal(struct rq *rq)
+{
+ return rq_clock_task(rq) >> sched_thermal_decay_shift;
+}
+
+struct rq_flags {
+ unsigned long flags;
+};
+
+#ifdef CONFIG_SMP
+struct rq *cpu_rq(int cpu);
+#endif
+
+#ifndef CONFIG_SMP
+extern struct rq *uprq;
+#define cpu_rq(cpu) (uprq)
+#define this_rq() (uprq)
+#define raw_rq() (uprq)
+#define task_rq(p) (uprq)
+#define cpu_curr(cpu) ((uprq)->curr)
+#else /* CONFIG_SMP */
+DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
+#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
+#define this_rq() this_cpu_ptr(&runqueues)
+#define task_rq(p) cpu_rq(task_cpu(p))
+#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
+#define raw_rq() raw_cpu_ptr(&runqueues)
+#endif /* CONFIG_SMP */
+
+static inline int task_current(struct rq *rq, struct task_struct *p)
+{
+ return rq->curr == p;
+}
+
+static inline int task_running(struct rq *rq, struct task_struct *p)
+{
+#ifdef CONFIG_SMP
+ return p->on_cpu;
+#else
+ return task_current(rq, p);
+#endif
+}
+
+/*
+ * Mainline name used by stats.h / psi.c / RT helpers. Equivalent to
+ * task_running() under SMP; always uses p->on_cpu so the @rq argument is
+ * unused (kept for API compatibility with mainline call sites).
+ */
+static inline int task_on_cpu(struct rq *rq, struct task_struct *p)
+{
+#ifdef CONFIG_SMP
+ return p->on_cpu;
+#else
+ return task_current(rq, p);
+#endif
+}
+
+static inline int task_on_rq_queued(struct task_struct *p)
+{
+ return p->on_rq == TASK_ON_RQ_QUEUED;
+}
+
+static inline int task_on_rq_migrating(struct task_struct *p)
+{
+ return READ_ONCE(p->on_rq) == TASK_ON_RQ_MIGRATING;
+}
+
+static inline void lockdep_assert_rq_held(struct rq *rq)
+{
+ lockdep_assert_held(rq->lock);
+}
+
+static inline void rq_lock(struct rq *rq)
+ __acquires(rq->lock)
+{
+ raw_spin_lock(rq->lock);
+}
+
+static inline void rq_unlock(struct rq *rq)
+ __releases(rq->lock)
+{
+ raw_spin_unlock(rq->lock);
+}
+
+static inline void rq_lock_irq(struct rq *rq)
+ __acquires(rq->lock)
+{
+ raw_spin_lock_irq(rq->lock);
+}
+
+static inline void rq_unlock_irq(struct rq *rq, struct rq_flags __always_unused *rf)
+ __releases(rq->lock)
+{
+ raw_spin_unlock_irq(rq->lock);
+}
+
+static inline void rq_lock_irqsave(struct rq *rq, struct rq_flags *rf)
+ __acquires(rq->lock)
+{
+ raw_spin_lock_irqsave(rq->lock, rf->flags);
+}
+
+static inline void rq_unlock_irqrestore(struct rq *rq, struct rq_flags *rf)
+ __releases(rq->lock)
+{
+ raw_spin_unlock_irqrestore(rq->lock, rf->flags);
+}
+
+static inline struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
+ __acquires(p->pi_lock)
+ __acquires(rq->lock)
+{
+ struct rq *rq;
+
+ while (42) {
+ raw_spin_lock_irqsave(&p->pi_lock, rf->flags);
+ rq = task_rq(p);
+ raw_spin_lock(rq->lock);
+ if (likely(rq == task_rq(p)))
+ break;
+ raw_spin_unlock(rq->lock);
+ raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
+ }
+ return rq;
+}
+
+static inline void task_rq_unlock(struct rq *rq, struct task_struct *p, struct rq_flags *rf)
+ __releases(rq->lock)
+ __releases(p->pi_lock)
+{
+ rq_unlock(rq);
+ raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
+}
+
+static inline struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags __always_unused *rf)
+ __acquires(rq->lock)
+{
+ struct rq *rq;
+
+ lockdep_assert_held(&p->pi_lock);
+
+ while (42) {
+ rq = task_rq(p);
+ raw_spin_lock(rq->lock);
+ if (likely(rq == task_rq(p)))
+ break;
+ raw_spin_unlock(rq->lock);
+ }
+ return rq;
+}
+
+/*
+ * Match mainline's 3-arg signature (stats.h / psi paths pass @p). MuQSS does
+ * not pin the lock cookie, so @p and @rf are unused beyond API compatibility.
+ */
+static inline void __task_rq_unlock(struct rq *rq,
+ struct task_struct __always_unused *p,
+ struct rq_flags __always_unused *rf)
+{
+ rq_unlock(rq);
+}
+
+/*
+ * scoped_guard / guard(rq_lock_irq) used by psi_cgroup_restart() and similar.
+ * MuQSS rq_lock_irq takes only the rq (no pin cookie).
+ */
+DEFINE_LOCK_GUARD_1(rq_lock_irq, struct rq,
+ rq_lock_irq(_T->lock),
+ rq_unlock_irq(_T->lock, &_T->rf),
+ struct rq_flags rf)
+
+DEFINE_LOCK_GUARD_1(rq_lock_irqsave, struct rq,
+ rq_lock_irqsave(_T->lock, &_T->rf),
+ rq_unlock_irqrestore(_T->lock, &_T->rf),
+ struct rq_flags rf)
+
+static inline struct rq *
+this_rq_lock_irq(struct rq_flags *rf)
+ __acquires(rq->lock)
+{
+ struct rq *rq;
+
+ local_irq_disable();
+ rq = this_rq();
+ rq_lock(rq);
+ return rq;
+}
+
+/*
+ * {de,en}queue flags: Most not used on MuQSS.
+ *
+ * DEQUEUE_SLEEP - task is no longer runnable
+ * ENQUEUE_WAKEUP - task just became runnable
+ *
+ * SAVE/RESTORE - an otherwise spurious dequeue/enqueue, done to ensure tasks
+ * are in a known state which allows modification. Such pairs
+ * should preserve as much state as possible.
+ *
+ * MOVE - paired with SAVE/RESTORE, explicitly does not preserve the location
+ * in the runqueue.
+ *
+ * ENQUEUE_HEAD - place at front of runqueue (tail if not specified)
+ * ENQUEUE_REPLENISH - CBS (replenish runtime and postpone deadline)
+ * ENQUEUE_MIGRATED - the task was migrated during wakeup
+ *
+ */
+
+#define DEQUEUE_SLEEP 0x01
+#define DEQUEUE_SAVE 0x02 /* matches ENQUEUE_RESTORE */
+
+#define ENQUEUE_WAKEUP 0x01
+#define ENQUEUE_RESTORE 0x02
+
+#ifdef CONFIG_SMP
+#define ENQUEUE_MIGRATED 0x40
+#else
+#define ENQUEUE_MIGRATED 0x00
+#endif
+
+#ifdef CONFIG_NUMA
+enum numa_topology_type {
+ NUMA_DIRECT,
+ NUMA_GLUELESS_MESH,
+ NUMA_BACKPLANE,
+};
+extern enum numa_topology_type sched_numa_topology_type;
+extern int sched_max_numa_distance;
+extern bool find_numa_distance(int distance);
+extern void sched_init_numa(int offline_node);
+extern void sched_domains_numa_masks_set(unsigned int cpu);
+extern void sched_domains_numa_masks_clear(unsigned int cpu);
+extern int sched_numa_find_closest(const struct cpumask *cpus, int cpu);
+#else
+static inline void sched_init_numa(int offline_node) { }
+static inline void sched_domains_numa_masks_set(unsigned int cpu) { }
+static inline void sched_domains_numa_masks_clear(unsigned int cpu) { }
+static inline int sched_numa_find_closest(const struct cpumask *cpus, int cpu)
+{
+ return nr_cpu_ids;
+}
+#endif
+
+extern struct mutex sched_domains_mutex;
+extern struct static_key_false sched_schedstats;
+
+#define rcu_dereference_sched_domain(p) \
+ rcu_dereference_all_check((p), lockdep_is_held(&sched_domains_mutex))
+
+struct affinity_context {
+ const struct cpumask *new_mask;
+ struct cpumask *user_mask;
+ unsigned int flags;
+};
+
+#define MDF_PUSH 0x01
+
+static inline bool is_migration_disabled(struct task_struct *p)
+{
+ return p->migration_disabled;
+}
+
+#define SCA_CHECK 0x01
+#define SCA_MIGRATE_DISABLE 0x02
+#define SCA_MIGRATE_ENABLE 0x04
+#define SCA_USER 0x08
+
+#ifdef CONFIG_SMP
+
+/*
+ * The domain tree (rq->sd) is protected by RCU's quiescent state transition.
+ * See destroy_sched_domains: call_rcu for details.
+ *
+ * The domain tree of any CPU may only be accessed from within
+ * preempt-disabled sections.
+ */
+#define for_each_domain(cpu, __sd) \
+ for (__sd = rcu_dereference_sched_domain(cpu_rq(cpu)->sd); \
+ __sd; __sd = __sd->parent)
+
+/**
+ * highest_flag_domain - Return highest sched_domain containing flag.
+ * @cpu: The cpu whose highest level of sched domain is to
+ * be returned.
+ * @flag: The flag to check for the highest sched_domain
+ * for the given cpu.
+ *
+ * Returns the highest sched_domain of a cpu which contains the given flag.
+ */
+static inline struct sched_domain *highest_flag_domain(int cpu, int flag)
+{
+ struct sched_domain *sd, *hsd = NULL;
+
+ for_each_domain(cpu, sd) {
+ if (!(sd->flags & flag))
+ break;
+ hsd = sd;
+ }
+
+ return hsd;
+}
+
+static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
+{
+ struct sched_domain *sd;
+
+ for_each_domain(cpu, sd) {
+ if (sd->flags & flag)
+ break;
+ }
+
+ return sd;
+}
+
+DECLARE_PER_CPU(struct sched_domain __rcu *, sd_llc);
+DECLARE_PER_CPU(int, sd_llc_size);
+DECLARE_PER_CPU(int, sd_llc_id);
+DECLARE_PER_CPU(int, sd_share_id);
+DECLARE_PER_CPU(struct sched_domain_shared __rcu *, sd_llc_shared);
+DECLARE_PER_CPU(struct sched_domain_shared __rcu *, sd_balance_shared);
+DECLARE_PER_CPU(struct sched_domain __rcu *, sd_numa);
+DECLARE_PER_CPU(struct sched_domain __rcu *, sd_asym_packing);
+DECLARE_PER_CPU(struct sched_domain __rcu *, sd_asym_cpucapacity);
+
+void sched_domains_free_llc_id(int cpu);
+
+extern struct static_key_false sched_asym_cpucapacity;
+extern struct static_key_false sched_cluster_active;
+
+static __always_inline bool sched_asym_cpucap_active(void)
+{
+ return static_branch_unlikely(&sched_asym_cpucapacity);
+}
+
+struct sched_group_capacity {
+ atomic_t ref;
+ /*
+ * CPU capacity of this group, SCHED_CAPACITY_SCALE being max capacity
+ * for a single CPU.
+ */
+ unsigned long capacity;
+ unsigned long min_capacity; /* Min per-CPU capacity in group */
+ unsigned long max_capacity; /* Max per-CPU capacity in group */
+ unsigned long next_update;
+ int imbalance; /* XXX unrelated to capacity but shared group state */
+
+ int id;
+
+ unsigned long cpumask[]; /* Balance mask */
+};
+
+struct sched_group {
+ struct sched_group *next; /* Must be a circular list */
+ atomic_t ref;
+
+ unsigned int group_weight;
+ unsigned int cores;
+ struct sched_group_capacity *sgc;
+ int asym_prefer_cpu; /* CPU of highest priority in group */
+ int flags;
+
+ /*
+ * The CPUs this group covers.
+ *
+ * NOTE: this field is variable length. (Allocated dynamically
+ * by attaching extra space to the end of the structure,
+ * depending on how many CPUs the kernel has booted up with)
+ */
+ unsigned long cpumask[];
+};
+
+static inline struct cpumask *sched_group_span(struct sched_group *sg)
+{
+ return to_cpumask(sg->cpumask);
+}
+
+/*
+ * See build_balance_mask().
+ */
+static inline struct cpumask *group_balance_mask(struct sched_group *sg)
+{
+ return to_cpumask(sg->sgc->cpumask);
+}
+
+extern int group_balance_cpu(struct sched_group *sg);
+extern void update_sched_domain_debugfs(void);
+extern void dirty_sched_domain_sysctl(int cpu);
+extern void sched_update_numa(int cpu, bool online);
+extern void sched_get_rd(struct root_domain *rd);
+extern void sched_put_rd(struct root_domain *rd);
+extern bool sched_debug_verbose;
+
+/**
+ * group_first_cpu - Returns the first cpu in the cpumask of a sched_group.
+ * @group: The group whose first cpu is to be returned.
+ */
+static inline unsigned int group_first_cpu(struct sched_group *group)
+{
+ return cpumask_first(sched_group_span(group));
+}
+
+
+/*
+ * register_sched_domain_sysctl()/unregister_sched_domain_sysctl() were
+ * replaced upstream by update_sched_domain_debugfs(), declared above with
+ * dirty_sched_domain_sysctl(). flush_smp_call_function_from_idle() likewise
+ * became flush_smp_call_function_queue(), declared in smp.h.
+ */
+
+extern void set_cpus_allowed_common(struct task_struct *p, struct affinity_context *ctx);
+
+extern void set_rq_online (struct rq *rq);
+extern void set_rq_offline(struct rq *rq);
+extern bool sched_smp_initialized;
+
+static inline void update_group_capacity(struct sched_domain *sd, int cpu)
+{
+}
+
+static inline void trigger_load_balance(struct rq *rq)
+{
+}
+
+#else /* CONFIG_SMP */
+
+static inline void flush_smp_call_function_from_idle(void) { }
+
+/*
+ * UP has no sched domains and MuQSS's rq has no ->sd, but stats.c walks the
+ * domain list unconditionally. Hand it an empty list.
+ */
+#define for_each_domain(cpu, __sd) \
+ for (__sd = NULL; __sd; __sd = __sd->parent)
+
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_CPU_IDLE
+static inline void idle_set_state(struct rq *rq,
+ struct cpuidle_state *idle_state)
+{
+ rq->idle_state = idle_state;
+}
+
+static inline struct cpuidle_state *idle_get_state(struct rq *rq)
+{
+ SCHED_WARN_ON(!rcu_read_lock_held());
+ return rq->idle_state;
+}
+#else
+static inline void idle_set_state(struct rq *rq,
+ struct cpuidle_state *idle_state)
+{
+}
+
+static inline struct cpuidle_state *idle_get_state(struct rq *rq)
+{
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_SCHED_DEBUG
+extern bool sched_debug_enabled;
+#endif
+
+extern void schedule_idle(void);
+
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+struct irqtime {
+ u64 total;
+ u64 tick_delta;
+ u64 irq_start_time;
+ struct u64_stats_sync sync;
+};
+
+DECLARE_PER_CPU(struct irqtime, cpu_irqtime);
+
+/*
+ * Returns the irqtime minus the softirq time computed by ksoftirqd.
+ * Otherwise ksoftirqd's sum_exec_runtime is substracted its own runtime
+ * and never move forward.
+ */
+static inline u64 irq_time_read(int cpu)
+{
+ struct irqtime *irqtime = &per_cpu(cpu_irqtime, cpu);
+ unsigned int seq;
+ u64 total;
+
+ do {
+ seq = __u64_stats_fetch_begin(&irqtime->sync);
+ total = irqtime->total;
+ } while (__u64_stats_fetch_retry(&irqtime->sync, seq));
+
+ return total;
+}
+#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
+
+static inline bool sched_stop_runnable(struct rq *rq)
+{
+ return rq->stop && task_on_rq_queued(rq->stop);
+}
+
+#ifdef CONFIG_SMP
+static inline int cpu_of(struct rq *rq)
+{
+ return rq->cpu;
+}
+#else /* CONFIG_SMP */
+static inline int cpu_of(struct rq *rq)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CPU_FREQ
+DECLARE_PER_CPU(struct update_util_data *, cpufreq_update_util_data);
+
+static inline void cpufreq_trigger(struct rq *rq, unsigned int flags)
+{
+ struct update_util_data *data;
+
+ data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
+ cpu_of(rq)));
+
+ if (data)
+ data->func(data, rq->niffies, flags);
+}
+#else
+static inline void cpufreq_trigger(struct rq *rq, unsigned int flag)
+{
+}
+#endif /* CONFIG_CPU_FREQ */
+
+static __always_inline
+unsigned int uclamp_rq_util_with(struct rq __maybe_unused *rq, unsigned int util,
+ struct task_struct __maybe_unused *p)
+{
+ return util;
+}
+
+static inline bool uclamp_is_used(void)
+{
+ return false;
+}
+
+#ifndef arch_scale_freq_tick
+static __always_inline
+void arch_scale_freq_tick(void)
+{
+}
+#endif
+
+#ifdef arch_scale_freq_capacity
+#ifndef arch_scale_freq_invariant
+#define arch_scale_freq_invariant() (true)
+#endif
+#else /* arch_scale_freq_capacity */
+#define arch_scale_freq_invariant() (false)
+#endif
+
+/*
+ * read_sum_exec_runtime() lives in cputime.c and now goes through
+ * tsk_seruntime(), so MuQSS needs no copy of it here.
+ */
+
+#ifndef arch_scale_freq_capacity
+/**
+ * arch_scale_freq_capacity - get the frequency scale factor of a given CPU.
+ * @cpu: the CPU in question.
+ *
+ * Return: the frequency scale factor normalized against SCHED_CAPACITY_SCALE, i.e.
+ *
+ * f_curr
+ * ------ * SCHED_CAPACITY_SCALE
+ * f_max
+ */
+static __always_inline
+unsigned long arch_scale_freq_capacity(int cpu)
+{
+ return SCHED_CAPACITY_SCALE;
+}
+#endif
+
+#ifdef CONFIG_NO_HZ_FULL
+extern bool sched_can_stop_tick(struct rq *rq);
+extern int __init sched_tick_offload_init(void);
+
+/*
+ * Tick may be needed by tasks in the runqueue depending on their policy and
+ * requirements. If tick is needed, lets send the target an IPI to kick it out of
+ * nohz mode if necessary.
+ */
+static inline void sched_update_tick_dependency(struct rq *rq)
+{
+ int cpu = cpu_of(rq);
+
+ if (!tick_nohz_full_cpu(cpu))
+ return;
+
+ if (sched_can_stop_tick(rq))
+ tick_nohz_dep_clear_cpu(cpu, TICK_DEP_BIT_SCHED);
+ else
+ tick_nohz_dep_set_cpu(cpu, TICK_DEP_BIT_SCHED);
+}
+#else
+static inline int sched_tick_offload_init(void) { return 0; }
+static inline void sched_update_tick_dependency(struct rq *rq) { }
+#endif
+
+#define SCHED_FLAG_SUGOV 0x10000000
+
+#ifdef CONFIG_SMP
+/*
+ * enum cpu_util_type and its FREQUENCY_UTIL/ENERGY_UTIL members were removed
+ * upstream; effective_cpu_util() now reports a utilisation figure plus the
+ * usable capacity range. MuQSS supplies it from MuQSS.c.
+ */
+unsigned long effective_cpu_util(int cpu, unsigned long util_cfs,
+ unsigned long *min, unsigned long *max);
+
+static inline unsigned long cpu_bw_dl(struct rq *rq)
+{
+ return 0;
+}
+
+static inline unsigned long cpu_util_dl(struct rq *rq)
+{
+ return 0;
+}
+
+static inline unsigned long cpu_util_cfs(struct rq *rq)
+{
+ unsigned long ret = READ_ONCE(rq->load_avg);
+
+ if (ret > SCHED_CAPACITY_SCALE)
+ ret = SCHED_CAPACITY_SCALE;
+ return ret;
+}
+
+static inline unsigned long cpu_util_rt(struct rq *rq)
+{
+ unsigned long ret = READ_ONCE(rq->rt_nr_running);
+
+ if (ret > SCHED_CAPACITY_SCALE)
+ ret = SCHED_CAPACITY_SCALE;
+ return ret;
+}
+
+#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
+static inline unsigned long cpu_util_irq(struct rq *rq)
+{
+ unsigned long ret = READ_ONCE(rq->irq_load_avg);
+
+ if (ret > SCHED_CAPACITY_SCALE)
+ ret = SCHED_CAPACITY_SCALE;
+ return ret;
+}
+
+static inline
+unsigned long scale_irq_capacity(unsigned long util, unsigned long irq, unsigned long max)
+{
+ util *= (max - irq);
+ util /= max;
+
+ return util;
+
+}
+#else /* CONFIG_HAVE_SCHED_AVG_IRQ */
+static inline unsigned long cpu_util_irq(struct rq *rq)
+{
+ return 0;
+}
+
+static inline
+unsigned long scale_irq_capacity(unsigned long util, unsigned long irq, unsigned long max)
+{
+ return util;
+}
+#endif /* CONFIG_HAVE_SCHED_AVG_IRQ */
+#endif /* CONFIG_SMP */
+
+#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
+#define perf_domain_span(pd) (to_cpumask(((pd)->em_pd->cpus)))
+
+DECLARE_STATIC_KEY_FALSE(sched_energy_present);
+
+static inline bool sched_energy_enabled(void)
+{
+ return static_branch_unlikely(&sched_energy_present);
+}
+
+#else /* ! (CONFIG_ENERGY_MODEL && CONFIG_CPU_FREQ_GOV_SCHEDUTIL) */
+
+#define perf_domain_span(pd) NULL
+static inline bool sched_energy_enabled(void) { return false; }
+
+#endif /* CONFIG_ENERGY_MODEL && CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
+
+#ifdef CONFIG_MEMBARRIER
+/*
+ * The scheduler provides memory barriers required by membarrier between:
+ * - prior user-space memory accesses and store to rq->membarrier_state,
+ * - store to rq->membarrier_state and following user-space memory accesses.
+ * In the same way it provides those guarantees around store to rq->curr.
+ */
+static inline void membarrier_switch_mm(struct rq *rq,
+ struct mm_struct *prev_mm,
+ struct mm_struct *next_mm)
+{
+ int membarrier_state;
+
+ if (prev_mm == next_mm)
+ return;
+
+ membarrier_state = atomic_read(&next_mm->membarrier_state);
+ if (READ_ONCE(rq->membarrier_state) == membarrier_state)
+ return;
+
+ WRITE_ONCE(rq->membarrier_state, membarrier_state);
+}
+#else
+static inline void membarrier_switch_mm(struct rq *rq,
+ struct mm_struct *prev_mm,
+ struct mm_struct *next_mm)
+{
+}
+#endif
+
+#ifdef CONFIG_SMP
+static inline bool is_per_cpu_kthread(struct task_struct *p)
+{
+ if (!(p->flags & PF_KTHREAD))
+ return false;
+
+ if (p->nr_cpus_allowed != 1)
+ return false;
+
+ return true;
+}
+#endif
+
+void swake_up_all_locked(struct swait_queue_head *q);
+void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
+
+/* pelt.h compat CONFIG_SCHED_THERMAL_PRESSURE impossible with MUQSS */
+static inline int
+update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity)
+{
+ return 0;
+}
+
+static inline u64 thermal_load_avg(struct rq *rq)
+{
+ return 0;
+}
+
+#ifdef CONFIG_RCU_TORTURE_TEST
+extern int sysctl_sched_rt_runtime;
+#endif
+
+/*
+ * Asymmetric CPU capacity bits, used by topology.c. MuQSS does not do
+ * capacity-aware placement, but the domain build code still maintains the
+ * list.
+ */
+struct asym_cap_data {
+ struct list_head link;
+ struct rcu_head rcu;
+ unsigned long capacity;
+ unsigned long cpus[];
+};
+
+extern struct list_head asym_cap_list;
+
+#define cpu_capacity_span(asym_data) to_cpumask((asym_data)->cpus)
+
+/*
+ * Stubs for mainline scheduler machinery MuQSS does not implement. These are
+ * referenced by the support files retained in build_muqss.c.
+ */
+
+/* No deadline server: topology.c attaches none. See rq->fair_server. */
+static inline void __dl_server_attach_root(void *dl_se, struct rq *rq)
+{
+}
+
+/* sched_ext is mutually exclusive with MuQSS; schedutil still asks. */
+static inline u32 scx_cpuperf_target(s32 cpu)
+{
+ return 0;
+}
+
+static inline bool scx_switched_all(void)
+{
+ return false;
+}
+
+/* No nohz idle balancing: MuQSS balances implicitly at task selection. */
+static inline void nohz_run_idle_balance(int cpu)
+{
+}
+
+/* No utilisation clamping, and no CFS utilisation to boost or clamp. */
+static inline bool uclamp_rq_is_capped(struct rq *rq)
+{
+ return false;
+}
+
+static inline unsigned long cpu_util_cfs_boost(int cpu)
+{
+ return 0;
+}
+
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+DECLARE_STATIC_KEY_FALSE(sched_clock_irqtime);
+
+static inline int irqtime_enabled(void)
+{
+ return static_branch_likely(&sched_clock_irqtime);
+}
+#else
+static inline int irqtime_enabled(void)
+{
+ return 0;
+}
+#endif
+
+extern unsigned long sugov_effective_cpu_perf(int cpu, unsigned long actual,
+ unsigned long min,
+ unsigned long max);
+
+extern int try_to_wake_up(struct task_struct *p, unsigned int state,
+ int wake_flags);
+
+asmlinkage void schedule_user(void);
+extern void resched_cpu(int cpu);
+extern bool available_idle_cpu(int cpu);
+extern void do_set_cpus_allowed(struct task_struct *p,
+ struct affinity_context *ctx);
+extern void __do_set_cpus_allowed(struct task_struct *p,
+ struct affinity_context *ctx);
+
+#ifdef CONFIG_PREEMPT_DYNAMIC
+extern int sched_dynamic_mode(const char *str);
+extern void sched_dynamic_update(int mode);
+#endif
+
+#ifdef CONFIG_CGROUP_SCHED
+extern struct task_group *sched_create_group(struct task_group *parent);
+extern void sched_online_group(struct task_group *tg,
+ struct task_group *parent);
+extern void sched_destroy_group(struct task_group *tg);
+extern void sched_release_group(struct task_group *tg);
+#endif
+
+#endif /* MUQSS_SCHED_H */
diff --git a/kernel/sched/build_muqss.c b/kernel/sched/build_muqss.c
new file mode 100644
--- /dev/null
+++ b/kernel/sched/build_muqss.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * The scheduler support files MuQSS retains from mainline, built in a single
+ * compilation unit for the same build-efficiency reasons as build_policy.c
+ * and build_utility.c.
+ *
+ * MuQSS replaces core.c, fair.c, rt.c, deadline.c, syscalls.c and stop_task.c
+ * outright, so neither of the mainline aggregates can be used as-is. The
+ * files gathered here are the subset of build_utility.c and build_policy.c
+ * that survives, and they are #included rather than built individually
+ * because several of them (clock.c, completion.c, psi.c) carry no includes of
+ * their own and only compile as part of an aggregate.
+ *
+ * Deliberately absent, and why:
+ *
+ * fair.c rt.c deadline.c ext.c stop_task.c policy replaced by MuQSS
+ * cpudeadline.c cpupri.c pelt.c supporting data for those classes
+ * syscalls.c MuQSS implements the syscalls
+ * core_sched.c SCHED_CORE gated off
+ * debug.c CFS/EEVDF runqueue introspection
+ * loadavg.c MuQSS keeps its own load average
+ * autogroup.c cpuacct.c gated off in Kconfig.MuQSS
+ */
+
+/* Headers: */
+#include <linux/sched/clock.h>
+#include <linux/sched/cputime.h>
+#include <linux/sched/debug.h>
+#include <linux/sched/hotplug.h>
+#include <linux/sched/isolation.h>
+#include <linux/sched/loadavg.h>
+#include <linux/sched/nohz.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/posix-timers.h>
+#include <linux/sched/rseq_api.h>
+#include <linux/sched/rt.h>
+#include <linux/sched/task_stack.h>
+
+#include <linux/cpufreq.h>
+#include <linux/cpuidle.h>
+#include <linux/cpumask_api.h>
+#include <linux/cpuset.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/energy_model.h>
+#include <linux/hashtable_api.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/kobject_api.h>
+#include <linux/livepatch.h>
+#include <linux/membarrier.h>
+#include <linux/memblock.h>
+#include <linux/mempolicy.h>
+#include <linux/nmi.h>
+#include <linux/nospec.h>
+#include <linux/percpu-rwsem.h>
+#include <linux/pm.h>
+#include <linux/proc_fs.h>
+#include <linux/psi.h>
+#include <linux/ptrace_api.h>
+#include <linux/rhashtable.h>
+#include <linux/sched_clock.h>
+#include <linux/security.h>
+#include <linux/seq_buf.h>
+#include <linux/seqlock_api.h>
+#include <linux/slab.h>
+#include <linux/spinlock_api.h>
+#include <linux/suspend.h>
+#include <linux/swait_api.h>
+#include <linux/sysrq.h>
+#include <linux/timex.h>
+#include <linux/tsacct_kern.h>
+#include <linux/utsname.h>
+#include <linux/vtime.h>
+#include <linux/wait_api.h>
+#include <linux/workqueue_api.h>
+
+#include <uapi/linux/prctl.h>
+#include <uapi/linux/sched/types.h>
+
+#include <asm/switch_to.h>
+
+#include <trace/events/power.h>
+
+#include "sched.h"
+#include "stats.h"
+
+/* psi.c needs wq_worker_last_func(); mainline gets this via sched.h. */
+#include "../workqueue_internal.h"
+
+/* Source code modules: */
+
+#include "clock.c"
+
+#ifdef CONFIG_CPU_FREQ
+# include "cpufreq.c"
+#endif
+
+#ifdef CONFIG_CPU_FREQ_GOV_SCHEDUTIL
+# include "cpufreq_schedutil.c"
+#endif
+
+#ifdef CONFIG_SCHEDSTATS
+# include "stats.c"
+#endif
+
+#include "completion.c"
+#include "swait.c"
+#include "wait_bit.c"
+#include "wait.c"
+
+#include "cputime.c"
+#include "idle.c"
+
+#ifdef CONFIG_SMP
+# include "topology.c"
+#endif
+
+#ifdef CONFIG_PSI
+# include "psi.c"
+#endif
+
+#ifdef CONFIG_MEMBARRIER
+# include "membarrier.c"
+#endif
+
+#ifdef CONFIG_CPU_ISOLATION
+# include "isolation.c"
+#endif
+
+#include "skip_list.c"
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -305,7 +305,7 @@ static inline u64 account_other_time(u64 max)
#ifdef CONFIG_64BIT
static inline u64 read_sum_exec_runtime(struct task_struct *t)
{
- return t->se.sum_exec_runtime;
+ return tsk_seruntime(t);
}
#else /* !CONFIG_64BIT: */
static u64 read_sum_exec_runtime(struct task_struct *t)
@@ -315,7 +315,7 @@ static u64 read_sum_exec_runtime(struct task_struct *t)
struct rq *rq;
rq = task_rq_lock(t, &rf);
- ns = t->se.sum_exec_runtime;
+ ns = tsk_seruntime(t);
task_rq_unlock(rq, t, &rf);
return ns;
@@ -689,6 +689,19 @@ void account_process_tick(struct task_struct *p, int user_tick)
{
u64 cputime, steal;
+ /*
+ * MuQSS accounts this tick itself, from sched_tick() ->
+ * update_cpu_clock_tick(), which update_process_times() calls a few
+ * lines after calling us. Its accounting is in real nanoseconds rather
+ * than whole ticks, and it is the same p->utime/p->stime and the same
+ * kcpustat[] fields we would be adding to here, so running both counts
+ * every busy tick twice. That is invisible in per-task figures, since
+ * cputime_adjust() rescales utime/stime to sched_time, but it doubles
+ * the busy buckets of /proc/stat. Leave it all to MuQSS.
+ */
+ if (IS_ENABLED(CONFIG_SCHED_MUQSS))
+ return;
+
if (vtime_accounting_enabled_this_cpu())
return;
@@ -811,7 +824,7 @@ void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev,
void task_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
{
struct task_cputime cputime = {
- .sum_exec_runtime = p->se.sum_exec_runtime,
+ .sum_exec_runtime = tsk_seruntime(p),
};
if (task_cputime(p, &cputime.utime, &cputime.stime))
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -454,6 +454,7 @@ void cpu_startup_entry(enum cpuhp_state state)
do_idle();
}
+#ifndef CONFIG_SCHED_MUQSS
/*
* idle-task scheduling class.
*/
@@ -591,3 +592,4 @@ DEFINE_SCHED_CLASS(idle) = {
.switching_to = switching_to_idle,
.update_curr = update_curr_idle,
};
+#endif /* CONFIG_SCHED_MUQSS */
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -5,6 +5,10 @@
#ifndef _KERNEL_SCHED_SCHED_H
#define _KERNEL_SCHED_SCHED_H
+#ifdef CONFIG_SCHED_MUQSS
+#include "MuQSS.h"
+#else /* CONFIG_SCHED_MUQSS */
+
#include <linux/prandom.h>
#include <linux/sched/affinity.h>
#include <linux/sched/autogroup.h>
@@ -4216,4 +4220,6 @@ DEFINE_CLASS_IS_UNCONDITIONAL(sched_change)
#include "ext/ext.h"
+#endif /* CONFIG_SCHED_MUQSS */
+
#endif /* _KERNEL_SCHED_SCHED_H */
diff --git a/kernel/sched/skip_list.c b/kernel/sched/skip_list.c
new file mode 100644
--- /dev/null
+++ b/kernel/sched/skip_list.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ Copyright (C) 2011,2016 Con Kolivas.
+
+ Code based on example originally by William Pugh.
+
+Skip Lists are a probabilistic alternative to balanced trees, as
+described in the June 1990 issue of CACM and were invented by
+William Pugh in 1987.
+
+A couple of comments about this implementation:
+The routine randomLevel has been hard-coded to generate random
+levels using p=0.25. It can be easily changed.
+
+The insertion routine has been implemented so as to use the
+dirty hack described in the CACM paper: if a random level is
+generated that is more than the current maximum level, the
+current maximum level plus one is used instead.
+
+Levels start at zero and go up to MaxLevel (which is equal to
+MaxNumberOfLevels-1).
+
+The routines defined in this file are:
+
+init: defines slnode
+
+new_skiplist: returns a new, empty list
+
+randomLevel: Returns a random level based on a u64 random seed passed to it.
+In MuQSS, the "niffy" time is used for this purpose.
+
+insert(l, node, key): inserts node into l ordered by key. This operation
+occurs in O(log n) time.
+
+delnode(slnode, l, node): deletes the node from l. This operation occurs
+in O(k) time where k is the number of levels of the node in question
+(max 4). The original delete function occurred in O(log n) time and
+involved a search.
+
+MuQSS Notes: In this implementation of skiplists, there are bidirectional
+next/prev pointers. The node is embedded in task_struct; the task is
+recovered with container_of(). The key here is chosen by the scheduler
+so as to sort tasks according to the priority list requirements. The
+scheduler lookup occurs in O(1) time because it is always the first
+item in the level 0 linked list. Since the task struct embeds the node,
+it can also remove it much faster than the original implementation with
+the aid of prev<->next pointer manipulation and no searching.
+
+*/
+
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/skip_list.h>
+
+static struct kmem_cache *skiplist_cache __read_mostly;
+
+#define MaxNumberOfLevels SKIPLIST_MAXLEVEL
+#define MaxLevel (MaxNumberOfLevels - 1)
+
+void skiplist_init(skiplist_node *slnode)
+{
+ int i;
+
+ slnode->key = 0xFFFFFFFFFFFFFFFF;
+ for (i = 0; i < MaxNumberOfLevels; i++)
+ slnode->next[i] = slnode->prev[i] = slnode;
+}
+
+void __init skiplist_cache_init(void)
+{
+ skiplist_cache = kmem_cache_create("skiplist", sizeof(skiplist),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ BUG_ON(!skiplist_cache);
+}
+
+skiplist *new_skiplist(skiplist_node *slnode)
+{
+ skiplist *l = kmem_cache_zalloc(skiplist_cache, GFP_ATOMIC);
+
+ BUG_ON(!l);
+ l->header = slnode;
+ l->best_key = ~0ULL;
+ return l;
+}
+
+void skiplist_free(skiplist *l)
+{
+ kmem_cache_free(skiplist_cache, l);
+}
+
+void free_skiplist(skiplist *l)
+{
+ skiplist_node *p, *q;
+
+ p = l->header;
+ do {
+ q = p->next[0];
+ p->next[0]->prev[0] = q->prev[0];
+ skiplist_node_init(p);
+ p = q;
+ } while (p != l->header);
+ skiplist_free(l);
+}
+
+void skiplist_node_init(skiplist_node *node)
+{
+ memset(node, 0, sizeof(skiplist_node));
+}
+
+static inline unsigned int randomLevel(const long unsigned int randseed)
+{
+ /*
+ * Two bits per extra level (p = 0.25). Search 2*MaxLevel+1 bits
+ * so the result stays in 0..MaxLevel; this matches the old
+ * 8-slot arrays whose random height never exceeded 3.
+ */
+ return find_first_bit(&randseed, MaxLevel * 2 + 1) / 2;
+}
+
+void skiplist_insert(skiplist *l, skiplist_node *node, keyType key, unsigned int randseed)
+{
+ skiplist_node *update[MaxNumberOfLevels];
+ skiplist_node *p, *q;
+ int k = l->level;
+
+ p = l->header;
+ do {
+ while (q = p->next[k], q->key <= key)
+ p = q;
+ update[k] = p;
+ } while (--k >= 0);
+
+ WRITE_ONCE(l->entries, l->entries + 1);
+ k = randomLevel(randseed);
+ if (k > l->level) {
+ k = ++l->level;
+ update[k] = l->header;
+ }
+
+ node->key = key;
+ do {
+ p = update[k];
+ node->next[k] = p->next[k];
+ p->next[k] = node;
+ node->prev[k] = p;
+ node->next[k]->prev[k] = node;
+ } while (--k >= 0);
+}
+
+/*
+ * Unlink @node from @l. Returns true if it was linked and has been removed,
+ * false if it was not on any list and nothing was changed - the caller's own
+ * accounting has to be skipped along with the removal in that case.
+ */
+bool skiplist_delete(skiplist *l, skiplist_node *node)
+{
+ int k, m;
+
+ /*
+ * Insert fills levels contiguously from 0 up and removal zeroes the
+ * whole node, so a NULL next[] marks the top of this node and stands
+ * in for the level count the node used to carry.
+ */
+ for (k = 0; k < MaxNumberOfLevels && node->next[k]; k++) {
+ node->prev[k]->next[k] = node->next[k];
+ node->next[k]->prev[k] = node->prev[k];
+ }
+ m = k - 1;
+ /*
+ * A node that was never queued has no levels linked at all. Leave
+ * before decrementing entries, which would otherwise go negative and
+ * make the emptiness tests in earliest_deadline_task() pass on an
+ * empty list, handing the caller the header as if it were a task.
+ */
+ if (WARN_ON_ONCE(m < 0))
+ return false;
+ skiplist_node_init(node);
+ if (m == l->level) {
+ while (l->header->next[m] == l->header && l->header->prev[m] == l->header && m > 0)
+ m--;
+ l->level = m;
+ }
+ WRITE_ONCE(l->entries, l->entries - 1);
+
+ return true;
+}
diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h
--- a/kernel/sched/stats.h
+++ b/kernel/sched/stats.h
@@ -89,6 +89,8 @@ static inline void rq_sched_info_depart (struct rq *rq, unsigned long long delt
#endif /* CONFIG_SCHEDSTATS */
+#ifndef CONFIG_SCHED_MUQSS
+/* Only reachable from fair.c, debug.c and core.c, none of which MuQSS builds. */
static inline struct sched_statistics *
__schedstats_from_se(struct sched_entity *se)
{
@@ -98,6 +100,7 @@ __schedstats_from_se(struct sched_entity *se)
#endif
return &task_of(se)->stats;
}
+#endif /* CONFIG_SCHED_MUQSS */
#ifdef CONFIG_PSI
void psi_task_change(struct task_struct *task, int clear, int set);
@@ -135,6 +138,23 @@ static inline void psi_enqueue(struct task_struct *p, int flags)
if (task_on_cpu(task_rq(p), p))
return;
+#ifdef CONFIG_SCHED_MUQSS
+ /*
+ * MuQSS has no delayed-dequeue (no task_struct::se), so a migration
+ * always moves a runnable task and a non-migration is a wakeup.
+ */
+ if (flags & ENQUEUE_MIGRATED) {
+ set = TSK_RUNNING;
+ if (p->in_memstall)
+ set |= TSK_MEMSTALL | TSK_MEMSTALL_RUNNING;
+ } else {
+ if (p->in_iowait)
+ clear |= TSK_IOWAIT;
+ set = TSK_RUNNING;
+ if (p->in_memstall)
+ set |= TSK_MEMSTALL_RUNNING;
+ }
+#else
if (p->se.sched_delayed) {
/* CPU migration of "sleeping" task */
WARN_ON_ONCE(!(flags & ENQUEUE_MIGRATED));
@@ -155,6 +175,7 @@ static inline void psi_enqueue(struct task_struct *p, int flags)
if (p->in_memstall)
set |= TSK_MEMSTALL_RUNNING;
}
+#endif /* CONFIG_SCHED_MUQSS */
psi_task_change(p, clear, set);
}
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -103,18 +103,36 @@ config NO_HZ_COMMON
bool
select TICK_ONESHOT
+#
+# Silent symbols keep CONFIG_NO_HZ_* / CONFIG_HZ_PERIODIC available to the
+# rest of the tree. The promptable *_NODEF names are what olddefconfig can
+# stick on; renaming every choice member (including idle) means a saved
+# "# CONFIG_NO_HZ_IDLE is not set" cannot pin the choice onto full dynticks.
+#
+config HZ_PERIODIC
+ bool
+
+config NO_HZ_IDLE
+ bool
+
+config NO_HZ_FULL
+ bool
+
choice
prompt "Timer tick handling"
- default NO_HZ_IDLE if NO_HZ
+ default NO_HZ_IDLE_NODEF if NO_HZ
+ default NO_HZ_IDLE_NODEF
-config HZ_PERIODIC
+config HZ_PERIODIC_NODEF
bool "Periodic timer ticks (constant rate, no dynticks)"
+ select HZ_PERIODIC
help
This option keeps the tick running periodically at a constant
rate, even when the CPU doesn't need it.
-config NO_HZ_IDLE
+config NO_HZ_IDLE_NODEF
bool "Idle dynticks system (tickless idle)"
+ select NO_HZ_IDLE
select NO_HZ_COMMON
help
This option enables a tickless idle system: timer interrupts
@@ -123,8 +141,9 @@ config NO_HZ_IDLE
Most of the time you want to say Y here.
-config NO_HZ_FULL
+config NO_HZ_FULL_NODEF
bool "Full dynticks system (tickless)"
+ select NO_HZ_FULL
# NO_HZ_COMMON dependency
# We need at least one periodic CPU for timekeeping
depends on SMP
@@ -150,6 +169,8 @@ config NO_HZ_FULL
By default, without passing the nohz_full parameter, this behaves just
like NO_HZ_IDLE.
+ Not recommended for desktops, laptops, or mobile devices.
+
If you're a distro say Y.
endchoice
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -194,8 +194,8 @@ int clockevents_tick_resume(struct clock_event_device *dev)
#ifdef CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST
-/* Limit min_delta to a jiffy */
-#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ)
+/* Limit min_delta to the configurable hrtimer granularity */
+#define MIN_DELTA_LIMIT (hrtimer_granularity_us * NSEC_PER_USEC)
/**
* clockevents_increase_min_delta - raise minimum delta of a clock event device
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -223,7 +223,7 @@ static void task_sample_cputime(struct task_struct *p, u64 *samples)
u64 stime, utime;
task_cputime(p, &utime, &stime);
- store_samples(samples, stime, utime, p->se.sum_exec_runtime);
+ store_samples(samples, stime, utime, tsk_seruntime(p));
}
static void proc_sample_cputime_atomic(struct task_cputime_atomic *at,
@@ -905,10 +905,12 @@ static void collect_posix_cputimers(struct posix_cputimers *pct, u64 *samples,
static inline void check_dl_overrun(struct task_struct *tsk)
{
+#ifndef CONFIG_SCHED_MUQSS
if (tsk->dl.dl_overrun) {
tsk->dl.dl_overrun = 0;
send_signal_locked(SIGXCPU, SEND_SIG_PRIV, tsk, PIDTYPE_TGID);
}
+#endif
}
static bool check_rlimit(u64 time, u64 limit, int signo, bool rt, bool hard)
@@ -952,7 +954,7 @@ static void check_thread_timers(struct task_struct *tsk,
soft = task_rlimit(tsk, RLIMIT_RTTIME);
if (soft != RLIM_INFINITY) {
/* Task RT timeout is accounted in jiffies. RTTIME is usec */
- unsigned long rttime = tsk->rt.timeout * (USEC_PER_SEC / HZ);
+ unsigned long rttime = tsk_rttimeout(tsk) * (USEC_PER_SEC / HZ);
unsigned long hard = task_rlimit_max(tsk, RLIMIT_RTTIME);
/* At the hard limit, send SIGKILL. No further action. */
@@ -1183,7 +1185,7 @@ static inline bool fastpath_timer_check(struct task_struct *tsk)
return true;
}
- if (dl_task(tsk) && tsk->dl.dl_overrun)
+ if (dl_task(tsk) && tsk_dl_overrun(tsk))
return true;
return false;
diff --git a/kernel/time/sleep_timeout.c b/kernel/time/sleep_timeout.c
--- a/kernel/time/sleep_timeout.c
+++ b/kernel/time/sleep_timeout.c
@@ -4,13 +4,57 @@
*/
#include <linux/delay.h>
+#include <linux/freezer.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/sched/signal.h>
#include <linux/sched/debug.h>
+#include <linux/sysctl.h>
#include "tick-internal.h"
+/*
+ * Granularity, in microseconds, below which a high resolution timeout is not
+ * worth arming. Also caps how far clockevents_increase_min_delta() is allowed
+ * to raise a clock event device's minimum delta.
+ */
+int __read_mostly hrtimer_granularity_us = 100;
+
+/* The timeout, in microseconds, used by schedule_min_hrtimeout(). */
+int __read_mostly hrtimeout_min_us = 500;
+
+#ifdef CONFIG_SYSCTL
+static const int hrtimeout_us_max = 10000;
+
+static const struct ctl_table hrtimeout_sysctl[] = {
+ {
+ .procname = "hrtimer_granularity_us",
+ .data = &hrtimer_granularity_us,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ONE,
+ .extra2 = (void *)&hrtimeout_us_max,
+ },
+ {
+ .procname = "hrtimeout_min_us",
+ .data = &hrtimeout_min_us,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ONE,
+ .extra2 = (void *)&hrtimeout_us_max,
+ },
+};
+
+static int __init hrtimeout_sysctl_init(void)
+{
+ register_sysctl("kernel", hrtimeout_sysctl);
+ return 0;
+}
+device_initcall(hrtimeout_sysctl_init);
+#endif /* CONFIG_SYSCTL */
+
/*
* Since schedule_timeout()'s timer is defined on the stack, it must store
* the target task on the stack as well.
@@ -279,10 +323,164 @@ int __sched schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode)
}
EXPORT_SYMBOL_GPL(schedule_hrtimeout);
+#ifdef CONFIG_HIGH_RES_TIMERS
+/*
+ * As per schedule_hrtimeout but takes a millisecond value and returns how
+ * many milliseconds are left.
+ */
+long __sched schedule_msec_hrtimeout(long timeout)
+{
+ struct hrtimer_sleeper t;
+ int delta, jiffs;
+ ktime_t expires;
+
+ if (!timeout) {
+ __set_current_state(TASK_RUNNING);
+ return 0;
+ }
+
+ jiffs = msecs_to_jiffies(timeout);
+ /*
+ * If regular timer resolution is adequate or hrtimer resolution is not
+ * (yet) better than Hz, as would occur during startup, use regular
+ * timers. Freezing gets the same treatment as some drivers still do not
+ * correctly use freezable timeouts.
+ */
+ if (jiffs > 4 || hrtimer_resolution >= NSEC_PER_SEC / HZ || pm_freezing)
+ return schedule_timeout(jiffs);
+
+ /* The jiffs > 4 test above bounds timeout well under one second. */
+ delta = (timeout % 1000) * NSEC_PER_MSEC;
+ expires = ktime_set(0, delta);
+
+ hrtimer_setup_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ /*
+ * No slack is given here. The whole point of taking the high resolution
+ * path is that the timeout is too short for the tick to resolve, and a
+ * slack of delta would push the expiry out to twice the request.
+ */
+ hrtimer_set_expires(&t.timer, expires);
+
+ hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_REL);
+
+ if (likely(t.task))
+ schedule();
+
+ hrtimer_cancel(&t.timer);
+ destroy_hrtimer_on_stack(&t.timer);
+
+ __set_current_state(TASK_RUNNING);
+
+ expires = hrtimer_expires_remaining(&t.timer);
+ timeout = ktime_to_ms(expires);
+ return timeout < 0 ? 0 : timeout;
+}
+
+EXPORT_SYMBOL(schedule_msec_hrtimeout);
+
+/*
+ * As per schedule_msec_hrtimeout but takes a microsecond value and returns
+ * how many microseconds are left.
+ */
+static long __sched schedule_usec_hrtimeout(long timeout)
+{
+ struct hrtimer_sleeper t;
+ ktime_t expires;
+ int delta;
+
+ if (!timeout) {
+ __set_current_state(TASK_RUNNING);
+ return 0;
+ }
+
+ if (hrtimer_resolution >= NSEC_PER_SEC / HZ)
+ return schedule_timeout(usecs_to_jiffies(timeout));
+
+ if (timeout < hrtimer_granularity_us)
+ timeout = hrtimer_granularity_us;
+ delta = (timeout % USEC_PER_SEC) * NSEC_PER_USEC;
+ expires = ktime_set(0, delta);
+
+ hrtimer_setup_sleeper_on_stack(&t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ /* No slack is given here, as per schedule_msec_hrtimeout(). */
+ hrtimer_set_expires(&t.timer, expires);
+
+ hrtimer_sleeper_start_expires(&t, HRTIMER_MODE_REL);
+
+ if (likely(t.task))
+ schedule();
+
+ hrtimer_cancel(&t.timer);
+ destroy_hrtimer_on_stack(&t.timer);
+
+ __set_current_state(TASK_RUNNING);
+
+ expires = hrtimer_expires_remaining(&t.timer);
+ timeout = ktime_to_us(expires);
+ return timeout < 0 ? 0 : timeout;
+}
+
+long __sched schedule_min_hrtimeout(void)
+{
+ return usecs_to_jiffies(schedule_usec_hrtimeout(hrtimeout_min_us));
+}
+
+EXPORT_SYMBOL(schedule_min_hrtimeout);
+
+long __sched schedule_msec_hrtimeout_interruptible(long timeout)
+{
+ __set_current_state(TASK_INTERRUPTIBLE);
+ return schedule_msec_hrtimeout(timeout);
+}
+EXPORT_SYMBOL(schedule_msec_hrtimeout_interruptible);
+
+long __sched schedule_msec_hrtimeout_uninterruptible(long timeout)
+{
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ return schedule_msec_hrtimeout(timeout);
+}
+EXPORT_SYMBOL(schedule_msec_hrtimeout_uninterruptible);
+
+#else /* !CONFIG_HIGH_RES_TIMERS */
+
+/*
+ * Without high resolution timers there is nothing better than the regular
+ * jiffy based timeouts to fall back on.
+ */
+long __sched schedule_msec_hrtimeout(long timeout)
+{
+ return schedule_timeout(msecs_to_jiffies(timeout));
+}
+EXPORT_SYMBOL(schedule_msec_hrtimeout);
+
+long __sched schedule_min_hrtimeout(void)
+{
+ return schedule_timeout(1);
+}
+EXPORT_SYMBOL(schedule_min_hrtimeout);
+
+long __sched schedule_msec_hrtimeout_interruptible(long timeout)
+{
+ return schedule_timeout_interruptible(msecs_to_jiffies(timeout));
+}
+EXPORT_SYMBOL(schedule_msec_hrtimeout_interruptible);
+
+long __sched schedule_msec_hrtimeout_uninterruptible(long timeout)
+{
+ return schedule_timeout_uninterruptible(msecs_to_jiffies(timeout));
+}
+EXPORT_SYMBOL(schedule_msec_hrtimeout_uninterruptible);
+
+#endif /* CONFIG_HIGH_RES_TIMERS */
+
/**
* msleep - sleep safely even with waitqueue interruptions
* @msecs: Requested sleep duration in milliseconds
*
+ * Sleeps shorter than five ticks are handed to a high resolution timer instead,
+ * where that has better resolution than the tick, so the slack described below
+ * only applies to the jiffy based path.
+ *
* msleep() uses jiffy based timeouts for the sleep duration. Because of the
* design of the timer wheel, the maximum additional percentage delay (slack) is
* 12.5%. This is only valid for timers which will end up in level 1 or a higher
@@ -312,7 +510,19 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout);
*/
void msleep(unsigned int msecs)
{
- unsigned long timeout = msecs_to_jiffies(msecs);
+ int jiffs = msecs_to_jiffies(msecs);
+ unsigned long timeout;
+
+ /*
+ * Use high resolution timers where the resolution of tick based
+ * timers is inadequate.
+ */
+ if (jiffs < 5 && hrtimer_resolution < NSEC_PER_SEC / HZ && !pm_freezing) {
+ while (msecs)
+ msecs = schedule_msec_hrtimeout_uninterruptible(msecs);
+ return;
+ }
+ timeout = jiffs;
while (timeout)
timeout = schedule_timeout_uninterruptible(timeout);
@@ -333,7 +543,15 @@ EXPORT_SYMBOL(msleep);
*/
unsigned long msleep_interruptible(unsigned int msecs)
{
- unsigned long timeout = msecs_to_jiffies(msecs);
+ int jiffs = msecs_to_jiffies(msecs);
+ unsigned long timeout;
+
+ if (jiffs < 5 && hrtimer_resolution < NSEC_PER_SEC / HZ && !pm_freezing) {
+ while (msecs && !signal_pending(current))
+ msecs = schedule_msec_hrtimeout_interruptible(msecs);
+ return msecs;
+ }
+ timeout = jiffs;
while (timeout && !signal_pending(current))
timeout = schedule_timeout_interruptible(timeout);
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -13,6 +13,9 @@ struct timer_events {
u64 global;
};
+/* Defined in sleep_timeout.c, tunable via sysctl */
+extern int hrtimer_granularity_us;
+
#ifdef CONFIG_GENERIC_CLOCKEVENTS
# define TICK_DO_TIMER_NONE -1
diff --git a/kernel/trace/rv/monitors/deadline/Kconfig b/kernel/trace/rv/monitors/deadline/Kconfig
--- a/kernel/trace/rv/monitors/deadline/Kconfig
+++ b/kernel/trace/rv/monitors/deadline/Kconfig
@@ -1,5 +1,5 @@
config RV_MON_DEADLINE
- depends on RV
+ depends on RV && !SCHED_MUQSS
bool "deadline monitor"
help
Collection of monitors to check the deadline scheduler and server
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -56,6 +56,7 @@
#include <linux/kvm_para.h>
#include <linux/delay.h>
#include <linux/irq_work.h>
+#include <linux/muqss_iotime.h>
#include "workqueue_internal.h"
@@ -1438,7 +1439,7 @@ void wq_worker_running(struct task_struct *task)
* CPU intensive auto-detection cares about how long a work item hogged
* CPU without sleeping. Reset the starting timestamp on wakeup.
*/
- worker->current_at = worker->task->se.sum_exec_runtime;
+ worker->current_at = tsk_seruntime(worker->task);
WRITE_ONCE(worker->sleeping, 0);
}
@@ -1523,7 +1524,7 @@ void wq_worker_tick(struct task_struct *task)
* We probably want to make this prettier in the future.
*/
if ((worker->flags & WORKER_NOT_RUNNING) || READ_ONCE(worker->sleeping) ||
- worker->task->se.sum_exec_runtime - worker->current_at <
+ tsk_seruntime(worker->task) - worker->current_at <
wq_cpu_intensive_thresh_us * NSEC_PER_USEC)
return;
@@ -2449,6 +2450,7 @@ bool queue_work_on(int cpu, struct workqueue_struct *wq,
if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)) &&
!clear_pending_if_disabled(work)) {
+ muqss_work_set_owner(work);
__queue_work(cpu, wq, work);
ret = true;
}
@@ -2530,6 +2532,7 @@ bool queue_work_node(int node, struct workqueue_struct *wq,
!clear_pending_if_disabled(work)) {
int cpu = select_numa_node_cpu(node);
+ muqss_work_set_owner(work);
__queue_work(cpu, wq, work);
ret = true;
}
@@ -2617,6 +2620,7 @@ bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)) &&
!clear_pending_if_disabled(work)) {
+ muqss_work_set_owner(work);
__queue_delayed_work(cpu, wq, dwork, delay);
ret = true;
}
@@ -2652,8 +2656,10 @@ bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
ret = work_grab_pending(&dwork->work, WORK_CANCEL_DELAYED, &irq_flags);
- if (!clear_pending_if_disabled(&dwork->work))
+ if (!clear_pending_if_disabled(&dwork->work)) {
+ muqss_work_set_owner(&dwork->work);
__queue_delayed_work(cpu, wq, dwork, delay);
+ }
local_irq_restore(irq_flags);
return ret;
@@ -2690,6 +2696,7 @@ bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork)
*/
if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)) &&
!WARN_ON_ONCE(clear_pending_if_disabled(work))) {
+ muqss_work_set_owner(work);
rwork->wq = wq;
call_rcu_hurry(&rwork->rcu, rcu_work_rcufn);
return true;
@@ -3223,7 +3230,9 @@ __acquires(&pool->lock)
{
struct pool_workqueue *pwq = get_work_pwq(work);
struct worker_pool *pool = worker->pool;
+ struct muqss_kern_window kern_window;
unsigned long work_data;
+ unsigned int muqss_owner;
int lockdep_start_depth, rcu_start_depth;
bool bh_draining = pool->flags & POOL_BH_DRAINING;
#ifdef CONFIG_LOCKDEP
@@ -3249,11 +3258,23 @@ __acquires(&pool->lock)
worker->current_func = work->func;
worker->current_pwq = pwq;
if (worker->task)
- worker->current_at = worker->task->se.sum_exec_runtime;
+ worker->current_at = tsk_seruntime(worker->task);
worker->current_start = jiffies;
work_data = *work_data_bits(work);
worker->current_color = get_work_color(work_data);
+ /*
+ * Read while PENDING still holds this work item for us. Once it is
+ * cleared below another CPU may requeue the same item and restamp it
+ * with a different owner, and the one we are about to run belongs to
+ * whoever queued it, not to them.
+ *
+ * A BH pool runs work in softirq context on top of whichever task was
+ * interrupted, so worker->task is NULL and there is no worker runtime
+ * to measure. Charge nobody there.
+ */
+ muqss_owner = worker->task ? muqss_work_owner(work) : 0;
+
/*
* Record wq name for cmdline and debug reporting, may get
* overridden through set_worker_desc().
@@ -3318,6 +3339,13 @@ __acquires(&pool->lock)
* workqueues), so hiding them isn't a problem.
*/
lockdep_invariant_state(true);
+ /*
+ * Everything from here to muqss_kerntime_end() is done on the queueing
+ * task's account: the CPU time it costs this worker is charged back to
+ * it, and so is any I/O the work item submits or any page it dirties,
+ * which would otherwise be lost to a kernel thread.
+ */
+ muqss_kerntime_begin(&kern_window, muqss_owner);
trace_workqueue_execute_start(work);
worker->current_func(work);
/*
@@ -3325,6 +3353,7 @@ __acquires(&pool->lock)
* point will only record its address.
*/
trace_workqueue_execute_end(work, worker->current_func);
+ muqss_kerntime_end(&kern_window);
lock_map_release(&lockdep_map);
if (!bh_draining)
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -969,7 +969,7 @@ static void khugepaged_alloc_sleep(void)
add_wait_queue(&khugepaged_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
- schedule_timeout(msecs_to_jiffies(khugepaged_alloc_sleep_millisecs));
+ schedule_msec_hrtimeout(khugepaged_alloc_sleep_millisecs);
remove_wait_queue(&khugepaged_wait, &wait);
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -38,6 +38,7 @@
#include <linux/sched/rt.h>
#include <linux/sched/signal.h>
#include <linux/mm_inline.h>
+#include <linux/muqss_iotime.h>
#include <linux/shmem_fs.h>
#include <trace/events/writeback.h>
@@ -2636,6 +2637,12 @@ static void folio_account_dirtied(struct folio *folio,
current->nr_dirtied += nr;
__this_cpu_add(bdp_ratelimits, nr);
+ /*
+ * Record who dirtied this so the writeback issued for it later
+ * by a flusher thread can still be charged to them.
+ */
+ muqss_iotime_dirty_folio(folio);
+
mem_cgroup_track_foreign_dirty(folio, wb);
}
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1401,6 +1401,7 @@ static __always_inline bool __free_pages_prepare(struct page *page,
}
page_cpupid_reset_last(page);
+ page_io_owner_reset(page);
page->flags.f &= ~PAGE_FLAGS_CHECK_AT_PREP;
page->private = 0;
reset_page_owner(page, order);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -1992,7 +1992,7 @@ static ssize_t pktgen_thread_write(struct file *file,
mutex_lock(&pktgen_thread_lock);
t->control |= T_REMDEVALL;
mutex_unlock(&pktgen_thread_lock);
- schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */
+ schedule_msec_hrtimeout_interruptible(125); /* Propagate thread->control */
ret = count;
sprintf(pg_result, "OK: rem_device_all");
goto out;
@@ -2064,7 +2064,7 @@ static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname)
mutex_unlock(&pktgen_thread_lock);
pr_debug("%s: waiting for %s to disappear....\n",
__func__, ifname);
- schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
+ schedule_msec_hrtimeout_interruptible(msec_per_try);
mutex_lock(&pktgen_thread_lock);
if (++i >= max_tries) {
@@ -3321,7 +3321,7 @@ static void pktgen_run_all_threads(struct pktgen_net *pn)
pktgen_handle_all_threads(pn, T_RUN);
/* Propagate thread->control */
- schedule_timeout_interruptible(msecs_to_jiffies(125));
+ schedule_msec_hrtimeout_interruptible(125);
pktgen_wait_all_threads_run(pn);
}
@@ -3333,7 +3333,7 @@ static void pktgen_reset_all_threads(struct pktgen_net *pn)
pktgen_handle_all_threads(pn, T_REMDEVALL);
/* Propagate thread->control */
- schedule_timeout_interruptible(msecs_to_jiffies(125));
+ schedule_msec_hrtimeout_interruptible(125);
pktgen_wait_all_threads_run(pn);
}
diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c
--- a/sound/hda/core/controller.c
+++ b/sound/hda/core/controller.c
@@ -340,7 +340,7 @@ static int snd_hdac_bus_get_response_rirb(struct hdac_bus *bus,
break;
#define LOOP_COUNT_MAX 3000
if (!bus->polling_mode) {
- schedule_timeout(msecs_to_jiffies(2));
+ schedule_msec_hrtimeout(2);
} else if (bus->needs_damn_long_delay ||
loopcounter > LOOP_COUNT_MAX) {
if (loopcounter > LOOP_COUNT_MAX && !warned) {
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -490,7 +490,7 @@ static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
& ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
- schedule_timeout_interruptible(msecs_to_jiffies(333));
+ schedule_msec_hrtimeout_interruptible(333);
return 0;
}
dev_warn(chip->card->dev, LOGNAME ": ADC calibration failed\n");
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1999,7 +1999,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
outw(0, io + GPIO_DATA);
outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
- schedule_timeout_uninterruptible(msecs_to_jiffies(delay1));
+ schedule_msec_hrtimeout_uninterruptible(delay1);
outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
udelay(5);
@@ -2007,7 +2007,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
outw(~0, io + GPIO_MASK);
- schedule_timeout_uninterruptible(msecs_to_jiffies(delay2));
+ schedule_msec_hrtimeout_uninterruptible(delay2);
if (! snd_m3_try_read_vendor(chip))
break;
@@ -2054,7 +2054,7 @@ static int snd_m3_mixer(struct snd_m3 *chip)
/* seems ac97 PCM needs initialization.. hack hack.. */
snd_ac97_write(chip->ac97, AC97_PCM, 0x8000 | (15 << 8) | 15);
- schedule_timeout_uninterruptible(msecs_to_jiffies(100));
+ schedule_msec_hrtimeout_uninterruptible(100);
snd_ac97_write(chip->ac97, AC97_PCM, 0);
#ifndef CONFIG_SND_MAESTRO3_INPUT
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -742,7 +742,7 @@ static void snd_ymfpci_irq_wait(struct snd_ymfpci *chip)
init_waitqueue_entry(&wait, current);
add_wait_queue(&chip->interrupt_sleep, &wait);
atomic_inc(&chip->interrupt_sleep_count);
- schedule_timeout_uninterruptible(msecs_to_jiffies(50));
+ schedule_msec_hrtimeout_uninterruptible(50);
remove_wait_queue(&chip->interrupt_sleep, &wait);
}
}
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -417,7 +417,7 @@ static void onebit_depop_mute_stage(struct snd_soc_component *component, int ena
hp_zc = snd_soc_component_read(component, RT5631_INT_ST_IRQ_CTRL_2);
snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
if (enable) {
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_uninterruptible(10);
/* config one-bit depop parameter */
rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x307f);
snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
@@ -529,7 +529,7 @@ static void depop_seq_mute_stage(struct snd_soc_component *component, int enable
hp_zc = snd_soc_component_read(component, RT5631_INT_ST_IRQ_CTRL_2);
snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
if (enable) {
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_uninterruptible(10);
/* config depop sequence parameter */
rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x302f);
@@ -1496,8 +1496,7 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
"change PLL in master mode\n");
snd_soc_component_write(component, RT5631_PLL_CTRL,
codec_master_pll_div[i].reg_val);
- schedule_timeout_uninterruptible(
- msecs_to_jiffies(20));
+ schedule_msec_hrtimeout_uninterruptible(20);
snd_soc_component_update_bits(component,
RT5631_GLOBAL_CLK_CTRL,
RT5631_SYSCLK_SOUR_SEL_MASK |
@@ -1515,8 +1514,7 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
"change PLL in slave mode\n");
snd_soc_component_write(component, RT5631_PLL_CTRL,
codec_slave_pll_div[i].reg_val);
- schedule_timeout_uninterruptible(
- msecs_to_jiffies(20));
+ schedule_msec_hrtimeout_uninterruptible(20);
snd_soc_component_update_bits(component,
RT5631_GLOBAL_CLK_CTRL,
RT5631_SYSCLK_SOUR_SEL_MASK |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -234,11 +234,9 @@ static void wm8350_pga_work(struct work_struct *work)
out2->ramp == WM8350_RAMP_UP) {
/* delay is longer over 0dB as increases are larger */
if (i >= WM8350_OUTn_0dB)
- schedule_timeout_interruptible(msecs_to_jiffies
- (2));
+ schedule_msec_hrtimeout_interruptible(2);
else
- schedule_timeout_interruptible(msecs_to_jiffies
- (1));
+ schedule_msec_hrtimeout_interruptible(1);
} else
udelay(50); /* doesn't matter if we delay longer */
}
@@ -1122,9 +1120,7 @@ static int wm8350_set_bias_level(struct snd_soc_component *component,
(platform->dis_out4 << 6));
/* wait for discharge */
- schedule_timeout_interruptible(msecs_to_jiffies
- (platform->
- cap_discharge_msecs));
+ schedule_msec_hrtimeout_interruptible(platform->cap_discharge_msecs);
/* enable antipop */
wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
@@ -1138,9 +1134,7 @@ static int wm8350_set_bias_level(struct snd_soc_component *component,
WM8350_VBUFEN);
/* wait for vmid */
- schedule_timeout_interruptible(msecs_to_jiffies
- (platform->
- vmid_charge_msecs));
+ schedule_msec_hrtimeout_interruptible(platform->vmid_charge_msecs);
/* turn on vmid 300k */
pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
@@ -1189,9 +1183,7 @@ static int wm8350_set_bias_level(struct snd_soc_component *component,
wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
/* wait */
- schedule_timeout_interruptible(msecs_to_jiffies
- (platform->
- vmid_discharge_msecs));
+ schedule_msec_hrtimeout_interruptible(platform->vmid_discharge_msecs);
wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
(platform->vmid_s_curve << 8) |
@@ -1207,8 +1199,7 @@ static int wm8350_set_bias_level(struct snd_soc_component *component,
pm1 | WM8350_OUTPUT_DRAIN_EN);
/* wait */
- schedule_timeout_interruptible(msecs_to_jiffies
- (platform->drain_msecs));
+ schedule_msec_hrtimeout_interruptible(platform->drain_msecs);
pm1 &= ~WM8350_BIASEN;
wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -1057,7 +1057,7 @@ static int wm8900_set_bias_level(struct snd_soc_component *component,
WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
/* Allow capacitors to charge */
- schedule_timeout_interruptible(msecs_to_jiffies(400));
+ schedule_msec_hrtimeout_interruptible(400);
/* Enable bias */
snd_soc_component_write(component, WM8900_REG_POWER1,
@@ -1091,7 +1091,7 @@ static int wm8900_set_bias_level(struct snd_soc_component *component,
/* Discharge caps */
snd_soc_component_write(component, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA);
- schedule_timeout_interruptible(msecs_to_jiffies(500));
+ schedule_msec_hrtimeout_interruptible(500);
/* Remove clamp */
snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
@@ -1105,7 +1105,7 @@ static int wm8900_set_bias_level(struct snd_soc_component *component,
/* Need to let things settle before stopping the clock
* to ensure that restart works, see "Stopping the
* master clock" in the datasheet. */
- schedule_timeout_interruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_interruptible(1);
snd_soc_component_write(component, WM8900_REG_POWER2,
WM8900_REG_POWER2_SYSCLK_ENA);
break;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -199,7 +199,7 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
/* Gracefully shut down the voice interface. */
snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, 0x0200);
- schedule_timeout_interruptible(msecs_to_jiffies(1));
+ schedule_msec_hrtimeout_interruptible(1);
snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x1000, 0x1000);
@@ -864,7 +864,7 @@ static int wm9713_set_pll(struct snd_soc_component *component,
wm9713->pll_in = freq_in;
/* wait 10ms AC97 link frames for the link to stabilise */
- schedule_timeout_interruptible(msecs_to_jiffies(10));
+ schedule_msec_hrtimeout_interruptible(10);
return 0;
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -166,7 +166,7 @@ static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
static void dapm_pop_wait(void)
{
if (pop_time)
- schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
+ schedule_msec_hrtimeout_uninterruptible(pop_time);
}
__printf(2, 3)
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
--- a/sound/usb/line6/pcm.c
+++ b/sound/usb/line6/pcm.c
@@ -127,7 +127,7 @@ static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
if (!alive)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_min_hrtimeout();
} while (--timeout > 0);
if (alive)
dev_err(line6pcm->line6->ifcdev,
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -101,9 +101,19 @@ LIBOPCODES_LIBS := $(shell \
HAVE_DISASM_STYLED := $(shell echo '$(pound)include <dis-asm.h>' | \
$(HOSTCC) -E -xc - 2>/dev/null | grep -q disassembler_style && echo y)
+#
+# Linking -lopcodes can succeed when the shared library is present without
+# development headers. That is common on Gentoo without sys-libs/binutils-libs
+# (bfd.h lives under /usr/lib64/binutils/<tuple>/<ver>/include, not
+# /usr/include). Do not enable DISAS unless the headers actually compile.
+#
+HAVE_DISAS_HEADERS := $(shell printf "$(pound)include <bfd.h>\n$(pound)include <dis-asm.h>\nint main(void) { return 0; }\n" | \
+ $(HOSTCC) $(HOSTCFLAGS) -DPACKAGE='"objtool"' -xc - -c -o /dev/null 2>/dev/null && echo y)
+
BUILD_DISAS := n
ifneq ($(LIBOPCODES_LIBS),)
+ifeq ($(HAVE_DISAS_HEADERS),y)
BUILD_DISAS := y
OBJTOOL_CFLAGS += -DDISAS -DPACKAGE='"objtool"'
OBJTOOL_LDFLAGS += $(LIBOPCODES_LIBS)
@@ -111,6 +121,7 @@ ifeq ($(HAVE_DISASM_STYLED),y)
OBJTOOL_CFLAGS += -DDISASM_INIT_STYLED
endif
endif
+endif
export BUILD_DISAS