Compare commits

..

12 commits

6 changed files with 1171 additions and 49 deletions

View file

@ -1,52 +1,68 @@
### build_kernel ### build-kernel
This playbook is used to automatically build a kernel with an ACS overrides patch applied. Useful to isolate PCI-e devices to their own IOMMU group for VFIO passthrough. This playbook is used to automatically build a kernel with an ACS overrides patch applied as well as Valve's fsync patches.
See this page for kernel configuration details: https://copr.fedorainfracloud.org/coprs/jlay/kernel-acspatch/ The ACS patch is useful to isolate PCI-e devices to their own IOMMU group for VFIO passthrough.
### Example usage The fsync patches improve Proton performance.
See this page for ACS kernel configuration details: https://copr.fedorainfracloud.org/coprs/jlay/kernel-acspatch/
### Requirements
- Inventory with one host
- `hosts-local` provided as a sample inventory for localhost
- This host must be running Fedora (builds use mock)
### Usage
#### Notes
Target Fedora version is controlled by the variable `fedora_version` in [./playbook.yml](./playbook.yml)
Patch to apply is determined by the `patch_file` variable, stored in [./payload/](./payload)
Patches for many different kernel versions provided, the highest version available should be current/working. Patch versions only change when `diffs` change.
#### Output:
``` ```
jlay@workstation:~/git/ansible/build_kernel$ ansible-playbook -i hosts playbook.yml $ ansible-playbook -i buildserver playbook.yml -b --ask-become-pass
BECOME password:
PLAY [buildservers] ****************************************************************************************************************************************** PLAY [buildservers] *******************************************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************************************************
ok: [delta.jlay.io] ok: [buildserver]
TASK [Ensure libselinux-python is installed] ****************************************************************************************************************************************** TASK [Ensure fedpkg is installed] *****************************************************************************************************************************
ok: [delta.jlay.io] changed: [buildserver]
TASK [Ensure fedpkg is installed] ****************************************************************************************************************************************** TASK [Find old mock chroots] **********************************************************************************************************************************
ok: [delta.jlay.io] ok: [buildserver]
TASK [Find old mock chroots] ****************************************************************************************************************************************** TASK [Clean old mock chroots] *********************************************************************************************************************************
ok: [delta.jlay.io]
TASK [Clean old mock chroots] ****************************************************************************************************************************************** TASK [Clean old build dir] ************************************************************************************************************************************
ok: [buildserver]
TASK [Clean old build dir] ****************************************************************************************************************************************** TASK [Clone f32 kernel to /tmp/f32_kernel] ********************************************************************************************************************
changed: [delta.jlay.io] changed: [buildserver]
TASK [Clone f29 kernel to /tmp/f29_kernel] ****************************************************************************************************************************************** TASK [Copy patch to build dir] ********************************************************************************************************************************
changed: [delta.jlay.io] changed: [buildserver]
TASK [Copy patch to build dir] ****************************************************************************************************************************************** TASK [Copy newpatch.sh on master branch, for 5.6 on f31] ******************************************************************************************************
changed: [delta.jlay.io] changed: [buildserver]
TASK [Apply patch and build kernel (logs in /tmp/f29_kernel/results_kernel/*)] ****************************************************************************************************************************************** TASK [Apply patch and build kernel (logs in /tmp/f32_kernel/results_kernel/*)] ********************************************************************************
changed: [delta.jlay.io] => (item=./scripts/newpatch.sh acso-4.18.patch) changed: [buildserver] => (item=./scripts/newpatch.sh acso-5.4.6.patch)
changed: [delta.jlay.io] => (item=/usr/bin/sed -i -e 's/%define buildid .*$/%define buildid .acspatch/' kernel.spec) changed: [buildserver] => (item=/usr/bin/sed -i -e 's/%define buildid .*$/%define buildid .acspatch/' kernel.spec)
changed: [delta.jlay.io] => (item=/usr/bin/make release) changed: [buildserver] => (item=/usr/bin/make release)
changed: [delta.jlay.io] => (item=fedpkg mockbuild) changed: [buildserver] => (item=fedpkg mockbuild)
TASK [Find RPMs in /tmp/f29_kernel/results_kernel/*/*/*.rpm] ****************************************************************************************************************************************** TASK [Find RPMs in /tmp/f32_kernel/results_kernel/*/*/*.rpm] **************************************************************************************************
ok: [delta.jlay.io] ok: [buildserver]
TASK [Copy RPMs to /tmp/ (local)] ****************************************************************************************************************************************** TASK [Copy RPMs to /tmp/ (local)] *****************************************************************************************************************************
ok: [delta.jlay.io] => (item={'uid': 0, 'woth': False, 'mtime': 1545900251.552329, 'inode': 1086935, 'isgid': False, 'size': 104419185, 'roth': True, 'isuid': False, 'isreg': True, 'pw_name': 'root', 'gid': 135, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'mock', 'path': '/tmp/f29_kernel/results_kernel/4.19.12/302.acspatch.fc29/kernel-4.19.12-302.acspatch.fc29.src.rpm', 'xusr': False, 'atime': 1545932715.7957838, 'isdir': False, 'ctime': 1545926304.4206192, 'isblk': False, 'xgrp': False, 'dev': 41, 'wgrp': False, 'isfifo': False, 'mode': '0644', 'islnk': False})
[...] [...]
PLAY RECAP ****************************************************************************************************************************************** PLAY RECAP ****************************************************************************************************************************************************
delta.jlay.io : ok=8 changed=4 unreachable=0 failed=0 buildserver : ok=10 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
jlay@workstation:~/git/ansible/build_kernel$
``` ```

View file

@ -1,4 +1,5 @@
[defaults] [defaults]
nocows = True
command_warnings = False command_warnings = False
retry_files_enabled = False retry_files_enabled = False
#strategy_plugins = ./mitogen-0.2.7/ansible_mitogen/plugins/strategy #strategy_plugins = ./mitogen-0.2.7/ansible_mitogen/plugins/strategy

View file

@ -3,3 +3,4 @@ localhost
[buildservers:vars] [buildservers:vars]
ansible_connection=local ansible_connection=local
ansible_python_interpreter=/usr/bin/python3

187
payload/acso-5.4.6.patch Normal file
View file

@ -0,0 +1,187 @@
From: Josh Lay <me@jlay.io>
Date: Fri, 12 Oct 2018 11:17:23 -0600
Subject: [PATCH] pci: Enable overrides for missing ACS capabilities (4.18)
This an updated version of Alex Williamson's patch from:
https://lkml.org/lkml/2013/5/30/513
To build on Fedora 28 kernels 4.18.x
Original commit message follows:
---
PCIe ACS (Access Control Services) is the PCIe 2.0+ feature that
allows us to control whether transactions are allowed to be redirected
in various subnodes of a PCIe topology. For instance, if two
endpoints are below a root port or downsteam switch port, the
downstream port may optionally redirect transactions between the
devices, bypassing upstream devices. The same can happen internally
on multifunction devices. The transaction may never be visible to the
upstream devices.
One upstream device that we particularly care about is the IOMMU. If
a redirection occurs in the topology below the IOMMU, then the IOMMU
cannot provide isolation between devices. This is why the PCIe spec
encourages topologies to include ACS support. Without it, we have to
assume peer-to-peer DMA within a hierarchy can bypass IOMMU isolation.
Unfortunately, far too many topologies do not support ACS to make this
a steadfast requirement. Even the latest chipsets from Intel are only
sporadically supporting ACS. We have trouble getting interconnect
vendors to include the PCIe spec required PCIe capability, let alone
suggested features.
Therefore, we need to add some flexibility. The pcie_acs_override=
boot option lets users opt-in specific devices or sets of devices to
assume ACS support. The "downstream" option assumes full ACS support
on root ports and downstream switch ports. The "multifunction"
option assumes the subset of ACS features available on multifunction
endpoints and upstream switch ports are supported. The "id:nnnn:nnnn"
option enables ACS support on devices matching the provided vendor
and device IDs, allowing more strategic ACS overrides. These options
may be combined in any order. A maximum of 16 id specific overrides
are available. It's suggested to use the most limited set of options
necessary to avoid completely disabling ACS across the topology.
Note to hardware vendors, we have facilities to permanently quirk
specific devices which enforce isolation but not provide an ACS
capability. Please contact me to have your devices added and save
your customers the hassle of this boot option.
Signed-off-by: Mark Weiman <mark.weiman@markzz.com>
---
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index efc7aa7a0670..b5258db83441 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3028,6 +3028,15 @@
nomsi [MSI] If the PCI_MSI kernel config parameter is
enabled, this kernel boot option can be used to
disable the use of MSI interrupts system-wide.
+ pcie_acs_override =
+ [PCIE] Override missing PCIe ACS support for:
+ downstream
+ All downstream ports - full ACS capabilities
+ multfunction
+ All multifunction devices - multifunction ACS subset
+ id:nnnn:nnnn
+ Specfic device - full ACS capabilities
+ Specified as vid:did (vendor/device ID) in hex
noioapicquirk [APIC] Disable all boot interrupt quirks.
Safety option to keep boot IRQs enabled. This
should never be necessary.
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index f439de848658..6431f60a56f4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3481,6 +3481,106 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
}
+static bool acs_on_downstream;
+static bool acs_on_multifunction;
+
+#define NUM_ACS_IDS 16
+struct acs_on_id {
+ unsigned short vendor;
+ unsigned short device;
+};
+static struct acs_on_id acs_on_ids[NUM_ACS_IDS];
+static u8 max_acs_id;
+
+static __init int pcie_acs_override_setup(char *p)
+{
+ if (!p)
+ return -EINVAL;
+
+ while (*p) {
+ if (!strncmp(p, "downstream", 10))
+ acs_on_downstream = true;
+ if (!strncmp(p, "multifunction", 13))
+ acs_on_multifunction = true;
+ if (!strncmp(p, "id:", 3)) {
+ char opt[5];
+ int ret;
+ long val;
+
+ if (max_acs_id >= NUM_ACS_IDS - 1) {
+ pr_warn("Out of PCIe ACS override slots (%d)\n",
+ NUM_ACS_IDS);
+ goto next;
+ }
+
+ p += 3;
+ snprintf(opt, 5, "%s", p);
+ ret = kstrtol(opt, 16, &val);
+ if (ret) {
+ pr_warn("PCIe ACS ID parse error %d\n", ret);
+ goto next;
+ }
+ acs_on_ids[max_acs_id].vendor = val;
+
+ p += strcspn(p, ":");
+ if (*p != ':') {
+ pr_warn("PCIe ACS invalid ID\n");
+ goto next;
+ }
+
+ p++;
+ snprintf(opt, 5, "%s", p);
+ ret = kstrtol(opt, 16, &val);
+ if (ret) {
+ pr_warn("PCIe ACS ID parse error %d\n", ret);
+ goto next;
+ }
+ acs_on_ids[max_acs_id].device = val;
+ max_acs_id++;
+ }
+next:
+ p += strcspn(p, ",");
+ if (*p == ',')
+ p++;
+ }
+
+ if (acs_on_downstream || acs_on_multifunction || max_acs_id)
+ pr_warn("Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n");
+
+ return 0;
+}
+early_param("pcie_acs_override", pcie_acs_override_setup);
+
+static int pcie_acs_overrides(struct pci_dev *dev, u16 acs_flags)
+{
+ int i;
+
+ /* Never override ACS for legacy devices or devices with ACS caps */
+ if (!pci_is_pcie(dev) ||
+ pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS))
+ return -ENOTTY;
+
+ for (i = 0; i < max_acs_id; i++)
+ if (acs_on_ids[i].vendor == dev->vendor &&
+ acs_on_ids[i].device == dev->device)
+ return 1;
+
+ switch (pci_pcie_type(dev)) {
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ case PCI_EXP_TYPE_ROOT_PORT:
+ if (acs_on_downstream)
+ return 1;
+ break;
+ case PCI_EXP_TYPE_ENDPOINT:
+ case PCI_EXP_TYPE_UPSTREAM:
+ case PCI_EXP_TYPE_LEG_END:
+ case PCI_EXP_TYPE_RC_END:
+ if (acs_on_multifunction && dev->multifunction)
+ return 1;
+ }
+
+ return -ENOTTY;
+}
/*
* Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
* The device will throw a Link Down error on AER-capable systems and
@@ -4660,4 +4760,5 @@
{ PCI_VENDOR_ID_AMPERE, 0xE00A, pci_quirk_xgene_acs },
{ PCI_VENDOR_ID_AMPERE, 0xE00B, pci_quirk_xgene_acs },
{ PCI_VENDOR_ID_AMPERE, 0xE00C, pci_quirk_xgene_acs },
+ { PCI_ANY_ID, PCI_ANY_ID, pcie_acs_overrides },
{ PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },

909
payload/fsync-5.6.patch Normal file
View file

@ -0,0 +1,909 @@
From f7f49141a5dbe9c99d78196b58c44307fb2e6be3 Mon Sep 17 00:00:00 2001
From: Tk-Glitch <ti3nou@gmail.com>
Date: Mon, 20 Apr 2020 14:09:11 +0200
Subject: Import Fsync v3 patchset - Squashed from https://gitlab.collabora.com/tonyk/linux/-/commits/futex-proton-v3
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
index a89eb0accd5e2ee527be1e3e11b1117ff5bf94b4..580001e89c6caed57dd8b3cb491d65dce846caff 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -21,6 +21,7 @@
#define FUTEX_WAKE_BITSET 10
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12
+#define FUTEX_WAIT_MULTIPLE 13
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
@@ -40,6 +41,8 @@
FUTEX_PRIVATE_FLAG)
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \
FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAIT_MULTIPLE_PRIVATE (FUTEX_WAIT_MULTIPLE | \
+ FUTEX_PRIVATE_FLAG)
/*
* Support for robust futexes: the kernel cleans up held futexes at
@@ -150,4 +153,21 @@ struct robust_list_head {
(((op & 0xf) << 28) | ((cmp & 0xf) << 24) \
| ((oparg & 0xfff) << 12) | (cmparg & 0xfff))
+/*
+ * Maximum number of multiple futexes to wait for
+ */
+#define FUTEX_MULTIPLE_MAX_COUNT 128
+
+/**
+ * struct futex_wait_block - Block of futexes to be waited for
+ * @uaddr: User address of the futex
+ * @val: Futex value expected by userspace
+ * @bitset: Bitset for the optional bitmasked wakeup
+ */
+struct futex_wait_block {
+ __u32 __user *uaddr;
+ __u32 val;
+ __u32 bitset;
+};
+
#endif /* _UAPI_LINUX_FUTEX_H */
diff --git a/kernel/futex.c b/kernel/futex.c
index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a92e676ba 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -215,6 +215,8 @@ struct futex_pi_state {
* @rt_waiter: rt_waiter storage for use with requeue_pi
* @requeue_pi_key: the requeue_pi target futex key
* @bitset: bitset for the optional bitmasked wakeup
+ * @uaddr: userspace address of futex
+ * @uval: expected futex's value
*
* We use this hashed waitqueue, instead of a normal wait_queue_entry_t, so
* we can wake only the relevant ones (hashed queues may be shared).
@@ -237,6 +239,8 @@ struct futex_q {
struct rt_mutex_waiter *rt_waiter;
union futex_key *requeue_pi_key;
u32 bitset;
+ u32 __user *uaddr;
+ u32 uval;
} __randomize_layout;
static const struct futex_q futex_q_init = {
@@ -2420,6 +2424,29 @@ static int unqueue_me(struct futex_q *q)
return ret;
}
+/**
+ * unqueue_multiple() - Remove several futexes from their futex_hash_bucket
+ * @q: The list of futexes to unqueue
+ * @count: Number of futexes in the list
+ *
+ * Helper to unqueue a list of futexes. This can't fail.
+ *
+ * Return:
+ * - >=0 - Index of the last futex that was awoken;
+ * - -1 - If no futex was awoken
+ */
+static int unqueue_multiple(struct futex_q *q, int count)
+{
+ int ret = -1;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (!unqueue_me(&q[i]))
+ ret = i;
+ }
+ return ret;
+}
+
/*
* PI futexes can not be requeued and must remove themself from the
* hash bucket. The hash bucket lock (i.e. lock_ptr) is held on entry
@@ -2783,6 +2810,211 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
return ret;
}
+/**
+ * futex_wait_multiple_setup() - Prepare to wait and enqueue multiple futexes
+ * @qs: The corresponding futex list
+ * @count: The size of the lists
+ * @flags: Futex flags (FLAGS_SHARED, etc.)
+ * @awaken: Index of the last awoken futex
+ *
+ * Prepare multiple futexes in a single step and enqueue them. This may fail if
+ * the futex list is invalid or if any futex was already awoken. On success the
+ * task is ready to interruptible sleep.
+ *
+ * Return:
+ * - 1 - One of the futexes was awaken by another thread
+ * - 0 - Success
+ * - <0 - -EFAULT, -EWOULDBLOCK or -EINVAL
+ */
+static int futex_wait_multiple_setup(struct futex_q *qs, int count,
+ unsigned int flags, int *awaken)
+{
+ struct futex_hash_bucket *hb;
+ int ret, i;
+ u32 uval;
+
+ /*
+ * Enqueuing multiple futexes is tricky, because we need to
+ * enqueue each futex in the list before dealing with the next
+ * one to avoid deadlocking on the hash bucket. But, before
+ * enqueuing, we need to make sure that current->state is
+ * TASK_INTERRUPTIBLE, so we don't absorb any awake events, which
+ * cannot be done before the get_futex_key of the next key,
+ * because it calls get_user_pages, which can sleep. Thus, we
+ * fetch the list of futexes keys in two steps, by first pinning
+ * all the memory keys in the futex key, and only then we read
+ * each key and queue the corresponding futex.
+ */
+retry:
+ for (i = 0; i < count; i++) {
+ qs[i].key = FUTEX_KEY_INIT;
+ ret = get_futex_key(qs[i].uaddr, flags & FLAGS_SHARED,
+ &qs[i].key, FUTEX_READ);
+ if (unlikely(ret)) {
+ for (--i; i >= 0; i--)
+ put_futex_key(&qs[i].key);
+ return ret;
+ }
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ for (i = 0; i < count; i++) {
+ struct futex_q *q = &qs[i];
+
+ hb = queue_lock(q);
+
+ ret = get_futex_value_locked(&uval, q->uaddr);
+ if (ret) {
+ /*
+ * We need to try to handle the fault, which
+ * cannot be done without sleep, so we need to
+ * undo all the work already done, to make sure
+ * we don't miss any wake ups. Therefore, clean
+ * up, handle the fault and retry from the
+ * beginning.
+ */
+ queue_unlock(hb);
+
+ /*
+ * Keys 0..(i-1) are implicitly put
+ * on unqueue_multiple.
+ */
+ put_futex_key(&q->key);
+
+ *awaken = unqueue_multiple(qs, i);
+
+ __set_current_state(TASK_RUNNING);
+
+ /*
+ * On a real fault, prioritize the error even if
+ * some other futex was awoken. Userspace gave
+ * us a bad address, -EFAULT them.
+ */
+ ret = get_user(uval, q->uaddr);
+ if (ret)
+ return ret;
+
+ /*
+ * Even if the page fault was handled, If
+ * something was already awaken, we can safely
+ * give up and succeed to give a hint for userspace to
+ * acquire the right futex faster.
+ */
+ if (*awaken >= 0)
+ return 1;
+
+ goto retry;
+ }
+
+ if (uval != q->uval) {
+ queue_unlock(hb);
+
+ put_futex_key(&qs[i].key);
+
+ /*
+ * If something was already awaken, we can
+ * safely ignore the error and succeed.
+ */
+ *awaken = unqueue_multiple(qs, i);
+ __set_current_state(TASK_RUNNING);
+ if (*awaken >= 0)
+ return 1;
+
+ return -EWOULDBLOCK;
+ }
+
+ /*
+ * The bucket lock can't be held while dealing with the
+ * next futex. Queue each futex at this moment so hb can
+ * be unlocked.
+ */
+ queue_me(&qs[i], hb);
+ }
+ return 0;
+}
+
+/**
+ * futex_wait_multiple() - Prepare to wait on and enqueue several futexes
+ * @qs: The list of futexes to wait on
+ * @op: Operation code from futex's syscall
+ * @count: The number of objects
+ * @abs_time: Timeout before giving up and returning to userspace
+ *
+ * Entry point for the FUTEX_WAIT_MULTIPLE futex operation, this function
+ * sleeps on a group of futexes and returns on the first futex that
+ * triggered, or after the timeout has elapsed.
+ *
+ * Return:
+ * - >=0 - Hint to the futex that was awoken
+ * - <0 - On error
+ */
+static int futex_wait_multiple(struct futex_q *qs, int op,
+ u32 count, ktime_t *abs_time)
+{
+ struct hrtimer_sleeper timeout, *to;
+ int ret, flags = 0, hint = 0;
+ unsigned int i;
+
+ if (!(op & FUTEX_PRIVATE_FLAG))
+ flags |= FLAGS_SHARED;
+
+ if (op & FUTEX_CLOCK_REALTIME)
+ flags |= FLAGS_CLOCKRT;
+
+ to = futex_setup_timer(abs_time, &timeout, flags, 0);
+ while (1) {
+ ret = futex_wait_multiple_setup(qs, count, flags, &hint);
+ if (ret) {
+ if (ret > 0) {
+ /* A futex was awaken during setup */
+ ret = hint;
+ }
+ break;
+ }
+
+ if (to)
+ hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS);
+
+ /*
+ * Avoid sleeping if another thread already tried to
+ * wake us.
+ */
+ for (i = 0; i < count; i++) {
+ if (plist_node_empty(&qs[i].list))
+ break;
+ }
+
+ if (i == count && (!to || to->task))
+ freezable_schedule();
+
+ ret = unqueue_multiple(qs, count);
+
+ __set_current_state(TASK_RUNNING);
+
+ if (ret >= 0)
+ break;
+ if (to && !to->task) {
+ ret = -ETIMEDOUT;
+ break;
+ } else if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ /*
+ * The final case is a spurious wakeup, for
+ * which just retry.
+ */
+ }
+
+ if (to) {
+ hrtimer_cancel(&to->timer);
+ destroy_hrtimer_on_stack(&to->timer);
+ }
+
+ return ret;
+}
+
static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
ktime_t *abs_time, u32 bitset)
{
@@ -3907,6 +4139,43 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
return -ENOSYS;
}
+/**
+ * futex_read_wait_block - Read an array of futex_wait_block from userspace
+ * @uaddr: Userspace address of the block
+ * @count: Number of blocks to be read
+ *
+ * This function creates and allocate an array of futex_q (we zero it to
+ * initialize the fields) and then, for each futex_wait_block element from
+ * userspace, fill a futex_q element with proper values.
+ */
+inline struct futex_q *futex_read_wait_block(u32 __user *uaddr, u32 count)
+{
+ unsigned int i;
+ struct futex_q *qs;
+ struct futex_wait_block fwb;
+ struct futex_wait_block __user *entry =
+ (struct futex_wait_block __user *)uaddr;
+
+ if (!count || count > FUTEX_MULTIPLE_MAX_COUNT)
+ return ERR_PTR(-EINVAL);
+
+ qs = kcalloc(count, sizeof(*qs), GFP_KERNEL);
+ if (!qs)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < count; i++) {
+ if (copy_from_user(&fwb, &entry[i], sizeof(fwb))) {
+ kfree(qs);
+ return ERR_PTR(-EFAULT);
+ }
+
+ qs[i].uaddr = fwb.uaddr;
+ qs[i].uval = fwb.val;
+ qs[i].bitset = fwb.bitset;
+ }
+
+ return qs;
+}
SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
struct __kernel_timespec __user *, utime, u32 __user *, uaddr2,
@@ -3919,7 +4188,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET ||
- cmd == FUTEX_WAIT_REQUEUE_PI)) {
+ cmd == FUTEX_WAIT_REQUEUE_PI ||
+ cmd == FUTEX_WAIT_MULTIPLE)) {
if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
return -EFAULT;
if (get_timespec64(&ts, utime))
@@ -3940,6 +4210,25 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
val2 = (u32) (unsigned long) utime;
+ if (cmd == FUTEX_WAIT_MULTIPLE) {
+ int ret;
+ struct futex_q *qs;
+
+#ifdef CONFIG_X86_X32
+ if (unlikely(in_x32_syscall()))
+ return -ENOSYS;
+#endif
+ qs = futex_read_wait_block(uaddr, val);
+
+ if (IS_ERR(qs))
+ return PTR_ERR(qs);
+
+ ret = futex_wait_multiple(qs, op, val, tp);
+ kfree(qs);
+
+ return ret;
+ }
+
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
@@ -4102,6 +4391,57 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
#endif /* CONFIG_COMPAT */
#ifdef CONFIG_COMPAT_32BIT_TIME
+/**
+ * struct compat_futex_wait_block - Block of futexes to be waited for
+ * @uaddr: User address of the futex (compatible pointer)
+ * @val: Futex value expected by userspace
+ * @bitset: Bitset for the optional bitmasked wakeup
+ */
+struct compat_futex_wait_block {
+ compat_uptr_t uaddr;
+ __u32 val;
+ __u32 bitset;
+};
+
+/**
+ * compat_futex_read_wait_block - Read an array of futex_wait_block from
+ * userspace
+ * @uaddr: Userspace address of the block
+ * @count: Number of blocks to be read
+ *
+ * This function does the same as futex_read_wait_block(), except that it
+ * converts the pointer to the futex from the compat version to the regular one.
+ */
+inline struct futex_q *compat_futex_read_wait_block(u32 __user *uaddr,
+ u32 count)
+{
+ unsigned int i;
+ struct futex_q *qs;
+ struct compat_futex_wait_block fwb;
+ struct compat_futex_wait_block __user *entry =
+ (struct compat_futex_wait_block __user *)uaddr;
+
+ if (!count || count > FUTEX_MULTIPLE_MAX_COUNT)
+ return ERR_PTR(-EINVAL);
+
+ qs = kcalloc(count, sizeof(*qs), GFP_KERNEL);
+ if (!qs)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < count; i++) {
+ if (copy_from_user(&fwb, &entry[i], sizeof(fwb))) {
+ kfree(qs);
+ return ERR_PTR(-EFAULT);
+ }
+
+ qs[i].uaddr = compat_ptr(fwb.uaddr);
+ qs[i].uval = fwb.val;
+ qs[i].bitset = fwb.bitset;
+ }
+
+ return qs;
+}
+
SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
u32, val3)
@@ -4113,7 +4453,8 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET ||
- cmd == FUTEX_WAIT_REQUEUE_PI)) {
+ cmd == FUTEX_WAIT_REQUEUE_PI ||
+ cmd == FUTEX_WAIT_MULTIPLE)) {
if (get_old_timespec32(&ts, utime))
return -EFAULT;
if (!timespec64_valid(&ts))
@@ -4128,6 +4469,19 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
val2 = (int) (unsigned long) utime;
+ if (cmd == FUTEX_WAIT_MULTIPLE) {
+ int ret;
+ struct futex_q *qs = compat_futex_read_wait_block(uaddr, val);
+
+ if (IS_ERR(qs))
+ return PTR_ERR(qs);
+
+ ret = futex_wait_multiple(qs, op, val, tp);
+ kfree(qs);
+
+ return ret;
+ }
+
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
#endif /* CONFIG_COMPAT_32BIT_TIME */
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
index ee55e6d389a3f053194435342c4e471dc7cf8786..2a63e1c2cfb6407a5988233217cff2e52787bc66 100644
--- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c
+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
@@ -11,6 +11,7 @@
*
* HISTORY
* 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
+ * 2019-Dec-13: Add WAIT_MULTIPLE test by Krisman <krisman@collabora.com>
*
*****************************************************************************/
@@ -41,6 +42,8 @@ int main(int argc, char *argv[])
{
futex_t f1 = FUTEX_INITIALIZER;
struct timespec to;
+ time_t secs;
+ struct futex_wait_block fwb = {&f1, f1, 0};
int res, ret = RET_PASS;
int c;
@@ -65,7 +68,7 @@ int main(int argc, char *argv[])
}
ksft_print_header();
- ksft_set_plan(1);
+ ksft_set_plan(2);
ksft_print_msg("%s: Block on a futex and wait for timeout\n",
basename(argv[0]));
ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns);
@@ -79,8 +82,39 @@ int main(int argc, char *argv[])
if (!res || errno != ETIMEDOUT) {
fail("futex_wait returned %d\n", ret < 0 ? errno : ret);
ret = RET_FAIL;
+ } else
+ ksft_test_result_pass("futex_wait timeout succeeds\n");
+
+ info("Calling futex_wait_multiple on f1: %u @ %p\n", f1, &f1);
+
+ /* Setup absolute time */
+ ret = clock_gettime(CLOCK_REALTIME, &to);
+ secs = (to.tv_nsec + timeout_ns) / 1000000000;
+ to.tv_nsec = ((int64_t)to.tv_nsec + timeout_ns) % 1000000000;
+ to.tv_sec += secs;
+ info("to.tv_sec = %ld\n", to.tv_sec);
+ info("to.tv_nsec = %ld\n", to.tv_nsec);
+
+ res = futex_wait_multiple(&fwb, 1, &to,
+ FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME);
+
+#ifdef __ILP32__
+ if (res == -1 && errno == ENOSYS) {
+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
+ } else {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
}
+#else
+ if (!res || errno != ETIMEDOUT) {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
+ } else
+ ksft_test_result_pass("futex_wait_multiple timeout succeeds\n");
+#endif /* __ILP32__ */
- print_result(TEST_NAME, ret);
+ ksft_print_cnts();
return ret;
}
diff --git a/tools/testing/selftests/futex/include/futextest.h b/tools/testing/selftests/futex/include/futextest.h
index ddbcfc9b7bac4aebb5bac2f249e26ecfd948aa84..bb103bef4557012ef9a389ca74c868e4476a8a31 100644
--- a/tools/testing/selftests/futex/include/futextest.h
+++ b/tools/testing/selftests/futex/include/futextest.h
@@ -38,6 +38,14 @@ typedef volatile u_int32_t futex_t;
#ifndef FUTEX_CMP_REQUEUE_PI
#define FUTEX_CMP_REQUEUE_PI 12
#endif
+#ifndef FUTEX_WAIT_MULTIPLE
+#define FUTEX_WAIT_MULTIPLE 13
+struct futex_wait_block {
+ futex_t *uaddr;
+ futex_t val;
+ __u32 bitset;
+};
+#endif
#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
FUTEX_PRIVATE_FLAG)
@@ -80,6 +88,20 @@ futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
}
+/**
+ * futex_wait_multiple() - block on several futexes with optional timeout
+ * @fwb: wait block user space address
+ * @count: number of entities at fwb
+ * @timeout: absolute timeout
+ */
+static inline int
+futex_wait_multiple(struct futex_wait_block *fwb, int count,
+ struct timespec *timeout, int opflags)
+{
+ return futex(fwb, FUTEX_WAIT_MULTIPLE, count, timeout, NULL, 0,
+ opflags);
+}
+
/**
* futex_wake() - wake one or more tasks blocked on uaddr
* @nr_wake: wake up to this many tasks
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
index 0ae390ff816449c88d0bb655a26eb014382c2b4f..bcbac042992d447e0bc9ef5fefe94e875de310f2 100644
--- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
@@ -12,6 +12,7 @@
*
* HISTORY
* 2009-Nov-14: Initial version by Gowrishankar <gowrishankar.m@in.ibm.com>
+ * 2019-Dec-13: Add WAIT_MULTIPLE test by Krisman <krisman@collabora.com>
*
*****************************************************************************/
@@ -40,6 +41,7 @@ int main(int argc, char *argv[])
{
struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns};
futex_t f1 = FUTEX_INITIALIZER;
+ struct futex_wait_block fwb = {&f1, f1+1, 0};
int res, ret = RET_PASS;
int c;
@@ -61,7 +63,7 @@ int main(int argc, char *argv[])
}
ksft_print_header();
- ksft_set_plan(1);
+ ksft_set_plan(2);
ksft_print_msg("%s: Test the unexpected futex value in FUTEX_WAIT\n",
basename(argv[0]));
@@ -71,8 +73,30 @@ int main(int argc, char *argv[])
fail("futex_wait returned: %d %s\n",
res ? errno : res, res ? strerror(errno) : "");
ret = RET_FAIL;
+ } else
+ ksft_test_result_pass("futex_wait wouldblock succeeds\n");
+
+ info("Calling futex_wait_multiple on f1: %u @ %p with val=%u\n",
+ f1, &f1, f1+1);
+ res = futex_wait_multiple(&fwb, 1, NULL, FUTEX_PRIVATE_FLAG);
+
+#ifdef __ILP32__
+ if (res != -1 || errno != ENOSYS) {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
+ } else {
+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
+ }
+#else
+ if (!res || errno != EWOULDBLOCK) {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
}
+ ksft_test_result_pass("futex_wait_multiple wouldblock succeeds\n");
+#endif /* __ILP32__ */
- print_result(TEST_NAME, ret);
+ ksft_print_cnts();
return ret;
}
diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore
index a09f570619023750f558c84004aff166b4337d72..4660128a545edb04a17cc6bd9760931c1386122f 100644
--- a/tools/testing/selftests/futex/functional/.gitignore
+++ b/tools/testing/selftests/futex/functional/.gitignore
@@ -5,3 +5,4 @@ futex_wait_private_mapped_file
futex_wait_timeout
futex_wait_uninitialized_heap
futex_wait_wouldblock
+futex_wait_multiple
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
index 30996306cabcfe89a47977643e529b122893bb7e..75f9fface11fa3c90c1bdb9a49b3ea51291afd58 100644
--- a/tools/testing/selftests/futex/functional/Makefile
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -14,7 +14,8 @@ TEST_GEN_FILES := \
futex_requeue_pi_signal_restart \
futex_requeue_pi_mismatched_ops \
futex_wait_uninitialized_heap \
- futex_wait_private_mapped_file
+ futex_wait_private_mapped_file \
+ futex_wait_multiple
TEST_PROGS := run.sh
diff --git a/tools/testing/selftests/futex/functional/futex_wait_multiple.c b/tools/testing/selftests/futex/functional/futex_wait_multiple.c
new file mode 100644
index 0000000000000000000000000000000000000000..b48422e79f42edba1653bb0bd2a4c4fd98d2d48d
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_multiple.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/******************************************************************************
+ *
+ * Copyright © Collabora, Ltd., 2019
+ *
+ * DESCRIPTION
+ * Test basic semantics of FUTEX_WAIT_MULTIPLE
+ *
+ * AUTHOR
+ * Gabriel Krisman Bertazi <krisman@collabora.com>
+ *
+ * HISTORY
+ * 2019-Dec-13: Initial version by Krisman <krisman@collabora.com>
+ *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include "futextest.h"
+#include "logging.h"
+
+#define TEST_NAME "futex-wait-multiple"
+#define timeout_ns 100000
+#define MAX_COUNT 128
+#define WAKE_WAIT_US 3000000
+
+int ret = RET_PASS;
+char *progname;
+futex_t f[MAX_COUNT] = {0};
+struct futex_wait_block fwb[MAX_COUNT];
+
+void usage(char *prog)
+{
+ printf("Usage: %s\n", prog);
+ printf(" -c Use color\n");
+ printf(" -h Display this help message\n");
+ printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
+ VQUIET, VCRITICAL, VINFO);
+}
+
+void test_count_overflow(void)
+{
+ futex_t f = FUTEX_INITIALIZER;
+ struct futex_wait_block fwb[MAX_COUNT+1];
+ int res, i;
+
+ ksft_print_msg("%s: Test a too big number of futexes\n", progname);
+
+ for (i = 0; i < MAX_COUNT+1; i++) {
+ fwb[i].uaddr = &f;
+ fwb[i].val = f;
+ fwb[i].bitset = 0;
+ }
+
+ res = futex_wait_multiple(fwb, MAX_COUNT+1, NULL, FUTEX_PRIVATE_FLAG);
+
+#ifdef __ILP32__
+ if (res != -1 || errno != ENOSYS) {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
+ } else {
+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
+ }
+#else
+ if (res != -1 || errno != EINVAL) {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
+ } else {
+ ksft_test_result_pass("futex_wait_multiple count overflow succeed\n");
+ }
+
+#endif /* __ILP32__ */
+}
+
+void *waiterfn(void *arg)
+{
+ int res;
+
+ res = futex_wait_multiple(fwb, MAX_COUNT, NULL, FUTEX_PRIVATE_FLAG);
+
+#ifdef __ILP32__
+ if (res != -1 || errno != ENOSYS) {
+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
+ res < 0 ? errno : res);
+ ret = RET_FAIL;
+ } else {
+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
+ }
+#else
+ if (res < 0)
+ ksft_print_msg("waiter failed %d\n", res);
+
+ info("futex_wait_multiple: Got hint futex %d was freed\n", res);
+#endif /* __ILP32__ */
+
+ return NULL;
+}
+
+void test_fwb_wakeup(void)
+{
+ int res, i;
+ pthread_t waiter;
+
+ ksft_print_msg("%s: Test wake up in a list of futex\n", progname);
+
+ for (i = 0; i < MAX_COUNT; i++) {
+ fwb[i].uaddr = &f[i];
+ fwb[i].val = f[i];
+ fwb[i].bitset = 0xffffffff;
+ }
+
+ res = pthread_create(&waiter, NULL, waiterfn, NULL);
+ if (res) {
+ ksft_test_result_fail("Creating waiting thread failed");
+ ksft_exit_fail();
+ }
+
+ usleep(WAKE_WAIT_US);
+ res = futex_wake(&(f[MAX_COUNT-1]), 1, FUTEX_PRIVATE_FLAG);
+ if (res != 1) {
+ ksft_test_result_fail("Failed to wake thread res=%d\n", res);
+ ksft_exit_fail();
+ }
+
+ pthread_join(waiter, NULL);
+ ksft_test_result_pass("%s succeed\n", __func__);
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "cht:v:")) != -1) {
+ switch (c) {
+ case 'c':
+ log_color(1);
+ break;
+ case 'h':
+ usage(basename(argv[0]));
+ exit(0);
+ case 'v':
+ log_verbosity(atoi(optarg));
+ break;
+ default:
+ usage(basename(argv[0]));
+ exit(1);
+ }
+ }
+
+ progname = basename(argv[0]);
+
+ ksft_print_header();
+ ksft_set_plan(2);
+
+ test_count_overflow();
+
+#ifdef __ILP32__
+ // if it's a 32x binary, there's no futex to wakeup
+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
+#else
+ test_fwb_wakeup();
+#endif /* __ILP32__ */
+
+ ksft_print_cnts();
+ return ret;
+}
diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
index 1acb6ace1680e8f3d6b3ee2dc528c19ddfdb018e..a8be94f28ff78b4879d2d19bca5d9b0fcb26c1f8 100755
--- a/tools/testing/selftests/futex/functional/run.sh
+++ b/tools/testing/selftests/futex/functional/run.sh
@@ -73,3 +73,6 @@ echo
echo
./futex_wait_uninitialized_heap $COLOR
./futex_wait_private_mapped_file $COLOR
+
+echo
+./futex_wait_multiple $COLOR
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
index 580001e89c6caed57dd8b3cb491d65dce846caff..a3e760886b8e7e74285fdcf2caaaa6f66ad16675 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -21,7 +21,7 @@
#define FUTEX_WAKE_BITSET 10
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12
-#define FUTEX_WAIT_MULTIPLE 13
+#define FUTEX_WAIT_MULTIPLE 31
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
diff --git a/kernel/futex.c b/kernel/futex.c
index 58cf9eb2b851b4858e29b5ef4114a29a92e676ba..e0bb628a5e1988dcc9ae5442a4259edc229d578d 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -4198,7 +4198,7 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
return -EINVAL;
t = timespec64_to_ktime(ts);
- if (cmd == FUTEX_WAIT)
+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE)
t = ktime_add_safe(ktime_get(), t);
tp = &t;
}
@@ -4399,6 +4399,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
*/
struct compat_futex_wait_block {
compat_uptr_t uaddr;
+ __u32 pad;
__u32 val;
__u32 bitset;
};
@@ -4461,7 +4462,7 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
return -EINVAL;
t = timespec64_to_ktime(ts);
- if (cmd == FUTEX_WAIT)
+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE)
t = ktime_add_safe(ktime_get(), t);
tp = &t;
}

View file

@ -1,21 +1,23 @@
--- ---
- hosts: buildservers - hosts: buildservers
become: true
vars: vars:
fedora_version: f30 fedora_version: f32
patch_file: acso-5.0.5.patch # This patch has been the same since 4.18, renamed to appear more relevant patch_files:
- acso-5.4.6.patch # This patch has been modified to work on 5.6+
- fsync-5.6.patch
run_epoch: "{{ ansible_date_time.epoch }}" run_epoch: "{{ ansible_date_time.epoch }}"
build_dir: /tmp/{{ fedora_version }}_kernel build_dir: /tmp/{{ fedora_version }}_kernel
tasks: tasks:
- name: Ensure libselinux-python is installed # - name: Ensure libselinux-python is installed - no longer required on f31+?
dnf: # dnf:
name: libselinux-python # name: libselinux-python
state: present # state: present
become: true # become: true
- name: Ensure fedpkg is installed - name: Ensure fedpkg is installed
dnf: dnf:
name: fedpkg name: fedpkg
state: present state: present
become: true
- name: Find old mock chroots - name: Find old mock chroots
find: find:
paths: /var/lib/mock/ paths: /var/lib/mock/
@ -28,26 +30,32 @@
path: "{{ item.path }}" path: "{{ item.path }}"
state: absent state: absent
with_items: "{{ chroots_to_delete.files }}" with_items: "{{ chroots_to_delete.files }}"
become: true
- name: Clean old build dir - name: Clean old build dir
file: file:
path: "{{ build_dir }}" path: "{{ build_dir }}"
state: absent state: absent
become: true
- name: Clone {{ fedora_version }} kernel to {{ build_dir }} - name: Clone {{ fedora_version }} kernel to {{ build_dir }}
shell: fedpkg clone -a -b {{ fedora_version }} kernel {{ build_dir }} shell: fedpkg clone -a -b {{ fedora_version }} kernel {{ build_dir }}
- name: Copy patch to build dir - name: Copy patch to build dir
copy: copy:
src: payload/{{ patch_file }} src: "payload/{{ item }}"
dest: "{{ build_dir }}" dest: "{{ build_dir }}"
- name: Apply patch and build kernel (logs in {{ build_dir }}/results_kernel/*) with_items: "{{ patch_files }}"
- name: Copy newpatch.sh on master branch, for 5.6 on f31
copy:
src: files/newpatch.sh
mode: 0775
dest: "{{ build_dir }}/scripts/"
when: (fedora_version in ['master', 'f32'])
- name: Apply patches
command: "./scripts/newpatch.sh {{ item }} chdir={{ build_dir }}"
with_items: "{{ patch_files }}"
- name: Build kernel (logs in {{ build_dir }}/results_kernel/*)
command: "{{ item }} chdir={{ build_dir }}" command: "{{ item }} chdir={{ build_dir }}"
with_items: with_items:
- ./scripts/newpatch.sh {{ patch_file }} - /usr/bin/sed -i -e 's/%define buildid .*$/%define buildid .acsfsync/' kernel.spec
- /usr/bin/sed -i -e 's/%define buildid .*$/%define buildid .acspatch/' kernel.spec
- /usr/bin/make release - /usr/bin/make release
- fedpkg mockbuild - fedpkg mockbuild
become: true
- name: Find RPMs in {{ build_dir }}/results_kernel/*/*/*.rpm - name: Find RPMs in {{ build_dir }}/results_kernel/*/*/*.rpm
find: find:
paths: "{{ build_dir }}/results_kernel/" paths: "{{ build_dir }}/results_kernel/"