kernel/filtermods.py
Patrick Talbert dffdf2ccc5 kernel-6.10.0-0.rc6.13.el10
* Tue Jul 02 2024 Patrick Talbert <ptalbert@redhat.com> [6.10.0-0.rc6.13.el10]
- scsi: libsas: Fix exp-attached device scan after probe failure scanned in again after probe failed (Xingui Yang)
- scsi: scsi_debug: Fix create target debugfs failure (Ming Lei)
- cxl: documentation: add missing files to cxl driver-api (Yao Xingtao)
- cxl/region: check interleave capability (Yao Xingtao)
- cxl/region: Avoid null pointer dereference in region lookup (Alison Schofield)
- cxl/mem: Fix no cxl_nvd during pmem region auto-assembling (Li Ming)
- btrfs: fix adding block group to a reclaim list and the unused list during reclaim (Naohiro Aota)
- syscalls: fix sys_fanotify_mark prototype (Arnd Bergmann)
- arm64: dts: rockchip: Add sound-dai-cells for RK3368 (Alex Bee)
- arm64: dts: rockchip: Fix the i2c address of es8316 on Cool Pi 4B (Andy Yan)
- arm64: dts: rockchip: fix PMIC interrupt pin on ROCK Pi E (FUKAUMI Naoki)
- arm64: dts: rockchip: make poweroff(8) work on Radxa ROCK 5A (FUKAUMI Naoki)
- Revert "arm64: dts: rockchip: remove redundant cd-gpios from rk3588 sdmmc nodes" (FUKAUMI Naoki)
- ARM: dts: rockchip: rk3066a: add #sound-dai-cells to hdmi node (Johan Jonker)
- arm64: dts: rockchip: Fix the value of `dlg,jack-det-rate` mismatch on rk3399-gru (Hsin-Te Yuan)
- arm64: dts: rockchip: set correct pwm0 pinctrl on rk3588-tiger (Heiko Stuebner)
- arm64: dts: rockchip: Rename LED related pinctrl nodes on rk3308-rock-pi-s (Jonas Karlman)
- arm64: dts: rockchip: Fix SD NAND and eMMC init on rk3308-rock-pi-s (Jonas Karlman)
- arm64: dts: rockchip: Fix rk3308 codec@ff560000 reset-names (Jonas Karlman)
- arm64: dts: rockchip: Fix the DCDC_REG2 minimum voltage on Quartz64 Model B (Dragan Simic)
- tee: optee: ffa: Fix missing-field-initializers warning (Mark-PK Tsai)
- drivers/soc/litex: drop obsolete dependency on COMPILE_TEST (Jean Delvare)
- reset: hisilicon: hi6220: add missing MODULE_DESCRIPTION() macro (Jeff Johnson)
- reset: gpio: Fix missing gpiolib dependency for GPIO reset controller (Mark Brown)
- MAINTAINERS: thead: update Maintainer (Jisheng Zhang)
- riscv: dts: starfive: Set EMMC vqmmc maximum voltage to 3.3V on JH7110 boards (Shengyu Qu)
- riscv: dts: canaan: Disable I/O devices unless used (Geert Uytterhoeven)
- riscv: dts: canaan: Clean up serial aliases (Geert Uytterhoeven)
- mtd: rawnand: rockchip: ensure NVDDR timings are rejected (Val Packett)
- mtd: rawnand: Bypass a couple of sanity checks during NAND identification (Miquel Raynal)
- mtd: rawnand: Fix the nand_read_data_op() early check (Miquel Raynal)
- mtd: rawnand: Ensure ECC configuration is propagated to upper layers (Miquel Raynal)
- netfs: Fix netfs_page_mkwrite() to flush conflicting data, not wait (David Howells)
- netfs: Fix netfs_page_mkwrite() to check folio->mapping is valid (David Howells)
- netfs: Delete some xarray-wangling functions that aren't used (David Howells)
- netfs: Fix early issue of write op on partial write to folio tail (David Howells)
- netfs: Fix io_uring based write-through (David Howells)
- vfs: generate FS_CREATE before FS_OPEN when ->atomic_open used. (NeilBrown)
- fsnotify: Do not generate events for O_PATH file descriptors (Jan Kara)
- fs: don't misleadingly warn during thaw operations (Christian Brauner)
- redhat: Add cgroup kselftests to kernel-selftests-internal (Waiman Long) [RHEL-43556]
- Revert "redhat/configs: Disable CONFIG_INFINIBAND_HFI1 and CONFIG_INFINIBAND_RDMAVT" (Kamal Heib)
- Remove new for GITLAB_TOKEN (Don Zickus)
- Set Fedora configs for 6.10 (Justin M. Forbes)
- Fedora: minor driver updates (Peter Robinson)
- v6.10-rc6-rt10 (Sebastian Andrzej Siewior)
- Linux 6.10-rc6 (Linus Torvalds)
- ata: ahci: Clean up sysfs file on error (Niklas Cassel)
- ata: libata-core: Fix double free on error (Niklas Cassel)
- ata,scsi: libata-core: Do not leak memory for ata_port struct members (Niklas Cassel)
- ata: libata-core: Fix null pointer dereference on error (Niklas Cassel)
- ata: libata-core: Add ATA_HORKAGE_NOLPM for all Crucial BX SSD1 models (Niklas Cassel)
- kbuild: scripts/gdb: bring the "abspath" back (Joel Granados)
- kbuild: Use $(obj)/%%.cc to fix host C++ module builds (Nicolas Schier)
- kbuild: rpm-pkg: fix build error with CONFIG_MODULES=n (Masahiro Yamada)
- kbuild: Fix build target deb-pkg: ln: failed to create hard link (Thayne Harbaugh)
- kbuild: doc: Update default INSTALL_MOD_DIR from extra to updates (Mark-PK Tsai)
- kbuild: Install dtb files as 0644 in Makefile.dtbinst (Dragan Simic)
- x86-32: fix cmpxchg8b_emu build error with clang (Linus Torvalds)
- counter: ti-eqep: enable clock at probe (David Lechner)
- iio: chemical: bme680: Fix sensor data read operation (Vasileios Amoiridis)
- iio: chemical: bme680: Fix overflows in compensate() functions (Vasileios Amoiridis)
- iio: chemical: bme680: Fix calibration data variable (Vasileios Amoiridis)
- iio: chemical: bme680: Fix pressure value output (Vasileios Amoiridis)
- iio: humidity: hdc3020: fix hysteresis representation (Dimitri Fedrau)
- iio: dac: fix ad9739a random config compile error (Ke Sun)
- iio: accel: fxls8962af: select IIO_BUFFER & IIO_KFIFO_BUF (Alexander Sverdlin)
- iio: adc: ad7266: Fix variable checking bug (Fernando Yang)
- iio: xilinx-ams: Don't include ams_ctrl_channels in scan_mask (Sean Anderson)
- staging: vchiq_debugfs: Fix build if CONFIG_DEBUG_FS is not set (Bernhard Rosenkränzer)
- staging: vc04_services: vchiq_arm: Fix initialisation check (Kieran Bingham)
- Revert "printk: Save console options for add_preferred_console_match()" (Greg Kroah-Hartman)
- Revert "printk: Don't try to parse DEVNAME:0.0 console options" (Greg Kroah-Hartman)
- Revert "printk: Flag register_console() if console is set on command line" (Greg Kroah-Hartman)
- Revert "serial: core: Add support for DEVNAME:0.0 style naming for kernel console" (Greg Kroah-Hartman)
- Revert "serial: core: Handle serial console options" (Greg Kroah-Hartman)
- Revert "serial: 8250: Add preferred console in serial8250_isa_init_ports()" (Greg Kroah-Hartman)
- Revert "Documentation: kernel-parameters: Add DEVNAME:0.0 format for serial ports" (Greg Kroah-Hartman)
- Revert "serial: 8250: Fix add preferred console for serial8250_isa_init_ports()" (Greg Kroah-Hartman)
- Revert "serial: core: Fix ifdef for serial base console functions" (Greg Kroah-Hartman)
- serial: bcm63xx-uart: fix tx after conversion to uart_port_tx_limited() (Jonas Gorski)
- serial: core: introduce uart_port_tx_limited_flags() (Jonas Gorski)
- Revert "serial: core: only stop transmit when HW fifo is empty" (Doug Brown)
- serial: imx: set receiver level before starting uart (Stefan Eichenberger)
- tty: mcf: MCF54418 has 10 UARTS (Jean-Michel Hautbois)
- serial: 8250_omap: Implementation of Errata i2310 (Udit Kumar)
- tty: serial: 8250: Fix port count mismatch with the device (Crescent Hsieh)
- usb: dwc3: core: Workaround for CSR read timeout (Jos Wang)
- Revert "usb: gadget: u_ether: Replace netif_stop_queue with netif_device_detach" (Ferry Toth)
- Revert "usb: gadget: u_ether: Re-attach netif device to mirror detachment" (Ferry Toth)
- usb: gadget: aspeed_udc: fix device address configuration (Jeremy Kerr)
- usb: dwc3: core: remove lock of otg mode during gadget suspend/resume to avoid deadlock (Meng Li)
- usb: typec: ucsi: glink: fix child node release in probe function (Javier Carrasco)
- usb: musb: da8xx: fix a resource leak in probe() (Dan Carpenter)
- usb: typec: ucsi_acpi: Add LG Gram quirk (Diogo Ivo)
- usb: ucsi: stm32: fix command completion handling (Fabrice Gasnier)
- usb: atm: cxacru: fix endpoint checking in cxacru_bind() (Nikita Zhandarovich)
- usb: gadget: printer: fix races against disable (Oliver Neukum)
- usb: gadget: printer: SS+ support (Oliver Neukum)
- cpu: Fix broken cmdline "nosmp" and "maxcpus=0" (Huacai Chen)
- cpu/hotplug: Fix dynstate assignment in __cpuhp_setup_state_cpuslocked() (Yuntao Wang)
- PCI/MSI: Fix UAF in msi_capability_init (Mostafa Saleh)
- irqchip/loongson-liointc: Set different ISRs for different cores (Huacai Chen)
- irqchip/loongson-eiointc: Use early_cpu_to_node() instead of cpu_to_node() (Huacai Chen)
- hrtimer: Prevent queuing of hrtimer without a function callback (Phil Chang)
- watchdog: add missing MODULE_DESCRIPTION() macros (Jeff Johnson)
- watchdog: lenovo_se10_wdt: add HAS_IOPORT dependency (Arnd Bergmann)
- redhat/configs: Remove obsolete x86 CPU mitigations config files (Waiman Long)
- redhat/configs: increase CONFIG_DEFAULT_MMAP_MIN_ADDR from 32K to 64K for aarch64 (Brian Masney)
- redhat/configs: Re-enable CONFIG_KEXEC for Fedora (Philipp Rudo)
- media: ipu-bridge: Add HIDs from out of tree IPU6 driver ipu-bridge copy (Hans de Goede)
- media: ipu-bridge: Sort ipu_supported_sensors[] array by ACPI HID (Hans de Goede)
- disable LR_WPAN for RHEL10 (Chris von Recklinghausen) [RHEL-40251]
- SUNRPC: Fix backchannel reply, again (Chuck Lever)
- xfs: honor init_xattrs in xfs_init_new_inode for !ATTR fs (Darrick J. Wong)
- xfs: fix direction in XFS_IOC_EXCHANGE_RANGE (Darrick J. Wong)
- xfs: allow unlinked symlinks and dirs with zero size (Darrick J. Wong)
- xfs: restrict when we try to align cow fork delalloc to cowextsz hints (Darrick J. Wong)
- xfs: fix freeing speculative preallocations for preallocated files (Christoph Hellwig)
- i2c: testunit: discard write requests while old command is running (Wolfram Sang)
- i2c: testunit: don't erase registers after STOP (Wolfram Sang)
- i2c: viai2c: turn common code into a proper module (Arnd Bergmann)
- platform/x86: add missing MODULE_DESCRIPTION() macros (Jeff Johnson)
- platform/x86/intel: add missing MODULE_DESCRIPTION() macros (Jeff Johnson)
- platform/x86/siemens: add missing MODULE_DESCRIPTION() macros (Jeff Johnson)
- platform/x86: lg-laptop: Use ACPI device handle when evaluating WMAB/WMBB (Armin Wolf)
- platform/x86: lg-laptop: Change ACPI device id (Armin Wolf)
- platform/x86: lg-laptop: Remove LGEX0815 hotkey handling (Armin Wolf)
- platform/x86: wireless-hotkey: Add support for LG Airplane Button (Armin Wolf)
- platform/mellanox: nvsw-sn2201: Add check for platform_device_add_resources (Chen Ni)
- mmc: sdhci: Do not lock spinlock around mmc_gpio_get_ro() (Adrian Hunter)
- mmc: sdhci: Do not invert write-protect twice (Adrian Hunter)
- Revert "mmc: moxart-mmc: Use sg_miter for PIO" (Linus Walleij)
- mmc: sdhci-brcmstb: check R1_STATUS for erase/trim/discard (Kamal Dasu)
- mmc: sdhci-pci-o2micro: Convert PCIBIOS_* return codes to errnos (Ilpo Järvinen)
- mmc: sdhci-pci: Convert PCIBIOS_* return codes to errnos (Ilpo Järvinen)
- riscv: stacktrace: convert arch_stack_walk() to noinstr (Andy Chiu)
- riscv: patch: Flush the icache right after patching to avoid illegal insns (Alexandre Ghiti)
- RISC-V: fix vector insn load/store width mask (Jesse Taube)
- tty: mxser: Remove __counted_by from mxser_board.ports[] (Nathan Chancellor)
- randomize_kstack: Remove non-functional per-arch entropy filtering (Kees Cook)
- string: kunit: add missing MODULE_DESCRIPTION() macros (Jeff Johnson)
- x86: stop playing stack games in profile_pc() (Linus Torvalds)
- Revert "nfsd: fix oops when reading pool_stats before server is started" (NeilBrown)
- nfsd: initialise nfsd_info.mutex early. (NeilBrown)
- bcachefs: Fix kmalloc bug in __snapshot_t_mut (Pei Li)
- bcachefs: Discard, invalidate workers are now per device (Kent Overstreet)
- bcachefs: Fix shift-out-of-bounds in bch2_blacklist_entries_gc (Pei Li)
- bcachefs: slab-use-after-free Read in bch2_sb_errors_from_cpu (Pei Li)
- bcachefs: Add missing bch2_journal_do_writes() call (Kent Overstreet)
- bcachefs: Fix null ptr deref in journal_pins_to_text() (Kent Overstreet)
- bcachefs: Add missing recalc_capacity() call (Kent Overstreet)
- bcachefs: Fix btree_trans list ordering (Kent Overstreet)
- bcachefs: Fix race between trans_put() and btree_transactions_read() (Kent Overstreet)
- closures: closure_get_not_zero(), closure_return_sync() (Kent Overstreet)
- bcachefs: Make btree_deadlock_to_text() clearer (Kent Overstreet)
- bcachefs: fix seqmutex_relock() (Kent Overstreet)
- bcachefs: Fix freeing of error pointers (Kent Overstreet)
- nvmet-fc: Remove __counted_by from nvmet_fc_tgt_queue.fod[] (Nathan Chancellor)
- nvmet: make 'tsas' attribute idempotent for RDMA (Hannes Reinecke)
- nvme: fixup comment for nvme RDMA Provider Type (Hannes Reinecke)
- nvme-apple: add missing MODULE_DESCRIPTION() (Jeff Johnson)
- nvmet: do not return 'reserved' for empty TSAS values (Hannes Reinecke)
- nvme: fix NVME_NS_DEAC may incorrectly identifying the disk as EXT_LBA. (Boyang Yu)
- MAINTAINERS: Update IOMMU tree location (Joerg Roedel)
- iommu/amd: Fix GT feature enablement again (Vasant Hegde)
- iommu/vt-d: Fix missed device TLB cache tag (Lu Baolu)
- iommu/amd: Invalidate cache before removing device from domain list (Vasant Hegde)
- gpiolib: cdev: Ignore reconfiguration without direction (Kent Gibson)
- gpiolib: cdev: Disallow reconfiguration without direction (uAPI v1) (Kent Gibson)
- gpio: graniterapids: Add missing raw_spinlock_init() (Aapo Vienamo)
- gpio: davinci: Validate the obtained number of IRQs (Aleksandr Mishin)
- gpio: pca953x: fix pca953x_irq_bus_sync_unlock race (Ian Ray)
- arm64: Clear the initial ID map correctly before remapping (Zenghui Yu)
- arm64: mm: Permit PTE SW bits to change in live mappings (Ryan Roberts)
- tools/power turbostat: Add local build_bug.h header for snapshot target (Patryk Wlazlyn)
- tools/power turbostat: Fix unc freq columns not showing with '-q' or '-l' (Adam Hawley)
- tools/power turbostat: option '-n' is ambiguous (David Arcari)
- Turn on USB_SERIAL_F81232 for Fedora (Justin M. Forbes)
- crypto: qat - fix linking errors when PCI_IOV is disabled (Xin Zeng)
- drm/drm_file: Fix pid refcounting race (Jann Horn)
- drm/i915/gt: Fix potential UAF by revoke of fence registers (Janusz Krzysztofik)
- drm/amdgpu: Don't show false warning for reg list (Lijo Lazar)
- drm/amdgpu: avoid using null object of framebuffer (Julia Zhang)
- drm/amd/display: Send DP_TOTAL_LTTPR_CNT during detection if LTTPR is present (Michael Strauss)
- drm/amdgpu: Fix pci state save during mode-1 reset (Lijo Lazar)
- drm/amdgpu/atomfirmware: fix parsing of vram_info (Alex Deucher)
- drm/amd/swsmu: add MALL init support workaround for smu_v14_0_1 (Li Ma)
- drm/nouveau/dispnv04: fix null pointer dereference in nv17_tv_get_ld_modes (Ma Ke)
- drm/nouveau/dispnv04: fix null pointer dereference in nv17_tv_get_hd_modes (Ma Ke)
- drm/panel: simple: Add missing display timing flags for KOE TX26D202VM0BWA (Liu Ying)
- drm/fbdev-dma: Only set smem_start is enable per module option (Thomas Zimmermann)
- cpufreq: intel_pstate: Use HWP to initialize ITMT if CPPC is missing (Rafael J. Wysocki)
- thermal: gov_step_wise: Go straight to instance->lower when mitigation is over (Rafael J. Wysocki)
- io_uring: signal SQPOLL task_work with TWA_SIGNAL_NO_IPI (Jens Axboe)
- io_uring: remove dead struct io_submit_state member (Jens Axboe)
- s390/boot: Do not adjust GOT entries for undef weak sym (Jens Remus)
- s390/sclp: Fix sclp_init() cleanup on failure (Heiko Carstens)
- s390/virtio_ccw: Fix config change notifications (Halil Pasic)
- s390/pci: Add missing virt_to_phys() for directed DIBV (Niklas Schnelle)
- kallsyms: rework symbol lookup return codes (Arnd Bergmann)
- linux/syscalls.h: add missing __user annotations (Arnd Bergmann)
- syscalls: mmap(): use unsigned offset type consistently (Arnd Bergmann)
- s390: remove native mmap2() syscall (Arnd Bergmann)
- hexagon: fix fadvise64_64 calling conventions (Arnd Bergmann)
- csky, hexagon: fix broken sys_sync_file_range (Arnd Bergmann)
- sh: rework sync_file_range ABI (Arnd Bergmann)
- powerpc: restore some missing spu syscalls (Arnd Bergmann)
- parisc: use generic sys_fanotify_mark implementation (Arnd Bergmann)
- parisc: use correct compat recv/recvfrom syscalls (Arnd Bergmann)
- sparc: fix compat recv/recvfrom syscalls (Arnd Bergmann)
- sparc: fix old compat_sys_select() (Arnd Bergmann)
- syscalls: fix compat_sys_io_pgetevents_time64 usage (Arnd Bergmann)
- ftruncate: pass a signed offset (Arnd Bergmann)
- btrfs: qgroup: fix quota root leak after quota disable failure (Filipe Manana)
- btrfs: scrub: handle RST lookup error correctly (Qu Wenruo)
- btrfs: zoned: fix initial free space detection (Naohiro Aota)
- btrfs: use NOFS context when getting inodes during logging and log replay (Filipe Manana)
- netfilter: nf_tables: fully validate NFT_DATA_VALUE on store to data registers (Pablo Neira Ayuso)
- netfilter: fix undefined reference to 'netfilter_lwtunnel_*' when CONFIG_SYSCTL=n (Jianguo Wu)
- net: mana: Fix possible double free in error handling path (Ma Ke)
- selftest: af_unix: Check SIOCATMARK after every send()/recv() in msg_oob.c. (Kuniyuki Iwashima)
- af_unix: Fix wrong ioctl(SIOCATMARK) when consumed OOB skb is at the head. (Kuniyuki Iwashima)
- selftest: af_unix: Check EPOLLPRI after every send()/recv() in msg_oob.c (Kuniyuki Iwashima)
- selftest: af_unix: Check SIGURG after every send() in msg_oob.c (Kuniyuki Iwashima)
- selftest: af_unix: Add SO_OOBINLINE test cases in msg_oob.c (Kuniyuki Iwashima)
- af_unix: Don't stop recv() at consumed ex-OOB skb. (Kuniyuki Iwashima)
- selftest: af_unix: Add non-TCP-compliant test cases in msg_oob.c. (Kuniyuki Iwashima)
- af_unix: Don't stop recv(MSG_DONTWAIT) if consumed OOB skb is at the head. (Kuniyuki Iwashima)
- af_unix: Stop recv(MSG_PEEK) at consumed OOB skb. (Kuniyuki Iwashima)
- selftest: af_unix: Add msg_oob.c. (Kuniyuki Iwashima)
- selftest: af_unix: Remove test_unix_oob.c. (Kuniyuki Iwashima)
- tracing/net_sched: NULL pointer dereference in perf_trace_qdisc_reset() (Yunseong Kim)
- net: usb: qmi_wwan: add Telit FN912 compositions (Daniele Palmas)
- tcp: fix tcp_rcv_fastopen_synack() to enter TCP_CA_Loss for failed TFO (Neal Cardwell)
- ionic: use dev_consume_skb_any outside of napi (Shannon Nelson)
- net: dsa: microchip: fix wrong register write when masking interrupt (Tristram Ha)
- Fix race for duplicate reqsk on identical SYN (luoxuanqiang)
- ibmvnic: Add tx check to prevent skb leak (Nick Child)
- xdp: Remove WARN() from __xdp_reg_mem_model() (Daniil Dulov)
- selftests/bpf: Add tests for may_goto with negative offset. (Alexei Starovoitov)
- bpf: Fix may_goto with negative offset. (Alexei Starovoitov)
- selftests/bpf: Add more ring buffer test coverage (Daniel Borkmann)
- bpf: Fix overrunning reservations in ringbuf (Daniel Borkmann)
- selftests/bpf: Tests with may_goto and jumps to the 1st insn (Alexei Starovoitov)
- bpf: Fix the corner case with may_goto and jump to the 1st insn. (Alexei Starovoitov)
- bpf: Update BPF LSM maintainer list (Matt Bobrowski)
- bpf: Fix remap of arena. (Alexei Starovoitov)
- selftests/bpf: Add a few tests to cover (Yonghong Song)
- bpf: Add missed var_off setting in coerce_subreg_to_size_sx() (Yonghong Song)
- bpf: Add missed var_off setting in set_sext32_default_val() (Yonghong Song)
- net: usb: ax88179_178a: improve link status logs (Jose Ignacio Tornos Martinez)
- octeontx2-pf: Fix coverity and klockwork issues in octeon PF driver (Ratheesh Kannoth)
- ice: Rebuild TC queues on VSI queue reconfiguration (Jan Sokolowski)
- dt-bindings: net: fman: remove ptp-timer from required list (Frank Li)
- net: dsa: microchip: monitor potential faults in half-duplex mode (Enguerrand de Ribaucourt)
- net: dsa: microchip: use collision based back pressure mode (Enguerrand de Ribaucourt)
- net: phy: micrel: add Microchip KSZ 9477 to the device table (Enguerrand de Ribaucourt)
- netlink: specs: Fix pse-set command attributes (Kory Maincent)
- ibmvnic: Free any outstanding tx skbs during scrq reset (Nick Child)
- Revert "batman-adv: prefer kfree_rcu() over call_rcu() with free-only callbacks" (Linus Lüssing)
- batman-adv: Don't accept TT entries for out-of-spec VIDs (Sven Eckelmann)
- can: mcp251xfd: fix infinite loop when xmit fails (Vitor Soares)
- can: kvaser_usb: fix return value for hif_usb_send_regout (Chen Ni)
- net: can: j1939: recover socket queue on CAN bus error during BAM transmission (Oleksij Rempel)
- net: can: j1939: Initialize unused data in j1939_send_one() (Shigeru Yoshida)
- net: can: j1939: enhanced error handling for tightly received RTS messages in xtp_rx_rts_session_new (Oleksij Rempel)
- vxlan: Pull inner IP header in vxlan_xmit_one(). (Guillaume Nault)
- mlxsw: spectrum_buffers: Fix memory corruptions on Spectrum-4 systems (Ido Schimmel)
- mlxsw: pci: Fix driver initialization with Spectrum-4 (Ido Schimmel)
- selftest: af_unix: Add Kconfig file. (Kuniyuki Iwashima)
- net: remove drivers@pensando.io from MAINTAINERS (Shannon Nelson)
- net: add softirq safety to netdev_rename_lock (Eric Dumazet)
- ionic: fix kernel panic due to multi-buffer handling (Taehee Yoo)
- net: pse-pd: Kconfig: Fix missing firmware loader config select (Kory Maincent)
- bonding: fix incorrect software timestamping report (Hangbin Liu)
- net: mvpp2: fill-in dev_port attribute (Aryan Srivastava)
- openvswitch: get related ct labels from its master if it is not confirmed (Xin Long)
- net: dsa: microchip: fix initial port flush problem (Tristram Ha)
- ASoC: rt5645: fix issue of random interrupt from push-button (Jack Yu)
- ASoC: amd: yc: Fix non-functional mic on ASUS M5602RA (Vyacheslav Frantsishko)
- ASoC: mediatek: mt8195: Add platform entry for ETDM1_OUT_BE dai link (Chen-Yu Tsai)
- ASoC: fsl-asoc-card: set priv->pdev before using it (Elinor Montmasson)
- ASoC: amd: acp: move chip->flag variable assignment (Vijendar Mukunda)
- ASoC: amd: acp: remove i2s configuration check in acp_i2s_probe() (Vijendar Mukunda)
- ASoC: amd: acp: add a null check for chip_pdev structure (Vijendar Mukunda)
- ASoC: Intel: soc-acpi: mtl: fix speaker no sound on Dell SKU 0C64 (Shuming Fan)
- ASoC: q6apm-lpass-dai: close graph on prepare errors (Srinivas Kandagatla)
- ASoC: cs35l56: Disconnect ASP1 TX sources when ASP1 DAI is hooked up (Richard Fitzgerald)
- ASoC: topology: Fix route memory corruption (Amadeusz Sławiński)
- ASoC: rt722-sdca-sdw: add debounce time for type detection (Jack Yu)
- ASoC: SOF: sof-audio: Skip unprepare for in-use widgets on error rollback (Peter Ujfalusi)
- ASoC: ti: davinci-mcasp: Set min period size using FIFO config (Jai Luthra)
- ALSA: dmaengine: Synchronize dma channel after drop() (Jai Luthra)
- ASoC: ti: omap-hdmi: Fix too long driver name (Primoz Fiser)
- ASoC: topology: Clean up route loading (Amadeusz Sławiński)
- ASoC: topology: Do not assign fields that are already set (Amadeusz Sławiński)
- ASoC: Intel: avs: Fix route override (Amadeusz Sławiński)
- ASoC: topology: Fix references to freed memory (Amadeusz Sławiński)
- bytcr_rt5640 : inverse jack detect for Archos 101 cesium (Thomas GENTY)
- ASoC: atmel: atmel-classd: Re-add dai_link->platform to fix card init (Andrei Simion)
- ASoC: mediatek: mt8183-da7219-max98357: Fix kcontrol name collision (Hsin-Te Yuan)
- ASoC: rockchip: i2s-tdm: Fix trcm mode by setting clock on right mclk (Alibek Omarov)
- ASoC: SOF: Intel: hda-dai: remove skip_tlv label (Bard Liao)
- ASoC: SOF: Intel: hda-dai: skip tlv for dspless mode (Bard Liao)
- ASoC: codecs: ES8326: Solve headphone detection issue (Zhang Yi)
- ASoC: cs42l43: Increase default type detect time and button delay (Maciej Strozek)
- ASoC: qcom: add missing MODULE_DESCRIPTION() macro (Jeff Johnson)
- ASoC: rt722-sdca-sdw: add silence detection register as volatile (Jack Yu)
- ASoC: fsl: add missing MODULE_DESCRIPTION() macro (Jeff Johnson)
- ASoC: mxs: add missing MODULE_DESCRIPTION() macro (Jeff Johnson)
- MAINTAINERS: copy linux-arm-msm for sound/qcom changes (Dmitry Baryshkov)
- ALSA: seq: Fix missing MSB in MIDI2 SPP conversion (Takashi Iwai)
- ALSA: hda/realtek: fix mute/micmute LEDs don't work for EliteBook 645/665 G11. (Dirk Su)
- ALSA: hda/realtek: Fix conflicting quirk for PCI SSID 17aa:3820 (Takashi Iwai)
- ALSA: dmaengine_pcm: terminate dmaengine before synchronize (Shengjiu Wang)
- ALSA: hda/relatek: Enable Mute LED on HP Laptop 15-gw0xxx (Aivaz Latypov)
- ALSA: PCM: Allow resume only for suspended streams (Takashi Iwai)
- ALSA: seq: Fix missing channel at encoding RPN/NRPN MIDI2 messages (Takashi Iwai)
- mm/memory: don't require head page for do_set_pmd() (Andrew Bresticker)
- mm/page_alloc: Separate THP PCP into movable and non-movable categories (yangge)
- nfs: drop the incorrect assertion in nfs_swap_rw() (Christoph Hellwig)
- mm/migrate: make migrate_pages_batch() stats consistent (Zi Yan)
- MAINTAINERS: TPM DEVICE DRIVER: update the W-tag (Jarkko Sakkinen)
- selftests/mm:fix test_prctl_fork_exec return failure (aigourensheng)
- mm: convert page type macros to enum (Stephen Brennan)
- ocfs2: fix DIO failure due to insufficient transaction credits (Jan Kara)
- kasan: fix bad call to unpoison_slab_object (Andrey Konovalov)
- mm: handle profiling for fake memory allocations during compaction (Suren Baghdasaryan)
- mm/slab: fix 'variable obj_exts set but not used' warning (Suren Baghdasaryan)
- /proc/pid/smaps: add mseal info for vma (Jeff Xu)
- mm: fix incorrect vbq reference in purge_fragmented_block (Zhaoyang Huang)
- redhat/scripts/filtermods.py: show all parent/child kmods in report (Jan Stancek)
- redhat/kernel.spec: capture filtermods.py return code (Jan Stancek)
- redhat/kernel.spec: fix run of mod-denylist (Jan Stancek)
- gitlab-ci: remove unused RHMAINTAINERS variable (Michael Hofmann)
- gitlab-ci: use environments for jobs that need access to push/gitlab secrets (Michael Hofmann)
- gitlab-ci: default to os-build for all maintenance jobs (Michael Hofmann)
- gitlab-ci: use the common git repo setup cki-gating as well (Michael Hofmann)
- gitlab-ci: help maintenance jobs to cope with missing private key (Michael Hofmann)
- gitlab-ci: use a common git repo setup for all maintenance jobs (Michael Hofmann)
- gitlab-ci: move repo setup script into script template holder (Michael Hofmann)
- gitlab-ci: move maintenance job DIST variable into common template (Michael Hofmann)
- gitlab-ci: move maintenance job rules into common template (Michael Hofmann)
- gitlab-ci: move maintenance job retry field into common template (Michael Hofmann)
- gitlab-ci: provide common non-secret schedule trigger variables (Michael Hofmann)
- gitlab-ci: rename .scheduled_setup to .git_setup (Michael Hofmann)
- gitlab-ci: move script snippets into separate template (Michael Hofmann)
- gitlab-ci: rename maintenance jobs (Michael Hofmann)
- gitlab-ci: introduce job template for maintenance jobs (Michael Hofmann)
- v6.10-rc5-rt9 (Sebastian Andrzej Siewior)
- perf: Update the perf series (Sebastian Andrzej Siewior)
- net: Update the BH series to v9. (Sebastian Andrzej Siewior)
- zram: Update the series. (Sebastian Andrzej Siewior)
- prinkt/nbcon: Add a scheduling point to nbcon_kthread_func(). (Sebastian Andrzej Siewior)
- v6.10-rc5-rt8 (Sebastian Andrzej Siewior)
- workqueue: Increase worker desc's length to 32 (Wenchao Hao)
- workqueue: Refactor worker ID formatting and make wq_worker_comm() use full ID string (Tejun Heo)
- Input: ads7846 - use spi_device_id table (Alexander Stein)
- Input: xpad - add support for ASUS ROG RAIKIRI PRO (Luke D. Jones)
- Input: ili210x - fix ili251x_read_touch_data() return value (John Keeping)
- Input: i8042 - add Ayaneo Kun to i8042 quirk table (Tobias Jakobi)
- Input: elantech - fix touchpad state on resume for Lenovo N24 (Jonathan Denose)
- pinctrl: rockchip: fix pinmux reset in rockchip_pmx_set (Huang-Huang Bao)
- pinctrl: rockchip: use dedicated pinctrl type for RK3328 (Huang-Huang Bao)
- pinctrl: rockchip: fix pinmux bits for RK3328 GPIO3-B pins (Huang-Huang Bao)
- pinctrl: rockchip: fix pinmux bits for RK3328 GPIO2-B pins (Huang-Huang Bao)
- pinctrl: fix deadlock in create_pinctrl() when handling -EPROBE_DEFER (Hagar Hemdan)
- pinctrl: bcm2835: Fix permissions of persist_gpio_outputs (Stefan Wahren)
- pinctrl: tps6594: add missing support for LP8764 PMIC (Thomas Richard)
- dt-bindings: pinctrl: qcom,pmic-gpio: drop pm8008 (Johan Hovold)
- pinctrl: qcom: spmi-gpio: drop broken pm8008 support (Johan Hovold)
- pinctrl: renesas: rzg2l: Use spin_{lock,unlock}_irq{save,restore} (Claudiu Beznea)
- Turn on KASAN_HW_TAGS for Fedora aarch64 debug kernels (Justin M. Forbes)
- Linux v6.10.0-0.rc6
Resolves: RHEL-29722

Signed-off-by: Patrick Talbert <ptalbert@redhat.com>
2024-07-02 18:03:45 +02:00

1097 lines
39 KiB
Python
Executable File

#!/usr/bin/env python3
"""
filter kmods into groups for packaging, see filtermods.adoc
"""
import argparse
import os
import re
import subprocess
import sys
import yaml
import unittest
from logging import getLogger, DEBUG, INFO, WARN, ERROR, CRITICAL, NOTSET, FileHandler, StreamHandler, Formatter, Logger
from typing import Optional
log = getLogger('filtermods')
def get_td(filename):
script_dir = os.path.dirname(os.path.realpath(__file__))
return os.path.join(script_dir, 'filtermods-testdata', filename)
def run_command(cmd, cwddir=None):
p = subprocess.Popen(cmd, cwd=cwddir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = p.communicate()
out_str = out.decode('utf-8')
err_str = err.decode('utf-8')
return p.returncode, out_str, err_str
def safe_run_command(cmd, cwddir=None):
log.info('%s', cmd)
retcode, out, err = run_command(cmd, cwddir)
if retcode != 0:
log.warning('Command failed: %s, ret_code: %d', cmd, retcode)
log.warning(out)
log.warning(err)
raise Exception(err)
log.info(' ^^[OK]')
return retcode, out, err
def setup_logging(log_filename, stdout_log_level):
log_format = '%(asctime)s %(levelname)7.7s %(funcName)20.20s:%(lineno)4s %(message)s'
log = getLogger('filtermods')
log.setLevel(DEBUG)
handler = StreamHandler(sys.stdout)
formatter = Formatter(log_format, '%H:%M:%S')
handler.setFormatter(formatter)
handler.setLevel(stdout_log_level)
log.addHandler(handler)
log.debug('stdout logging on')
if log_filename:
file_handler = FileHandler(log_filename, 'w')
file_handler.setFormatter(formatter)
file_handler.setLevel(DEBUG)
log.addHandler(file_handler)
log.info('file logging on: %s', log_filename)
return log
def canon_modname(kmod_pathname: str) -> str:
name = os.path.basename(kmod_pathname)
if name.endswith('.xz'):
name = name[:-3]
return name
class HierarchyObject:
def __init__(self):
self.depends_on = set()
def get_topo_order(obj_list: list[HierarchyObject], func_get_linked_objs=lambda x: x.depends_on) -> list[HierarchyObject]:
topo_order = []
objs_to_sort = set(obj_list)
objs_sorted = set()
while len(objs_to_sort) > 0:
no_deps = set()
for obj in objs_to_sort:
linked = func_get_linked_objs(obj)
if not linked:
no_deps.add(obj)
else:
all_deps_sorted = True
for dep in linked:
if dep not in objs_sorted:
all_deps_sorted = False
break
if all_deps_sorted:
no_deps.add(obj)
for obj in no_deps:
topo_order.append(obj)
objs_sorted.add(obj)
objs_to_sort.remove(obj)
return topo_order
class KMod(HierarchyObject):
def __init__(self, kmod_pathname: str) -> None:
super(KMod, self).__init__()
self.name: str = canon_modname(kmod_pathname)
self.kmod_pathname: str = kmod_pathname
self.is_dependency_for: set[KMod] = set()
self.assigned_to_pkg: Optional[KModPackage] = None
self.preferred_pkg: Optional[KModPackage] = None
self.rule_specifity: int = 0
self.allowed_list: Optional[set[KModPackage]] = None
self.err = 0
def __str__(self):
depends_on = ''
for kmod in self.depends_on:
depends_on = depends_on + ' ' + kmod.name
return '%s {%s}' % (self.name, depends_on)
class KModList():
def __init__(self) -> None:
self.name_to_kmod_map: dict[str, KMod] = {}
self.topo_order: Optional[list[KMod]] = None
def get(self, kmod_pathname, create_if_missing=False):
kmod_name = canon_modname(kmod_pathname)
if kmod_name in self.name_to_kmod_map:
return self.name_to_kmod_map[kmod_name]
if not create_if_missing:
return None
kmod = KMod(kmod_pathname)
# log.debug('Adding kmod %s (%s) to list', kmod.name, kmod.kmod_pathname)
if kmod.kmod_pathname != kmod_pathname:
raise Exception('Already have %s, but path changed? %s', kmod_name, kmod_pathname)
if not kmod.name:
raise Exception('Each kmod needs a name')
self.name_to_kmod_map[kmod_name] = kmod
return kmod
def process_depmod_line(self, line):
tmp = line.split(':')
if len(tmp) != 2:
raise Exception('Depmod line has unexpected format: %s', line)
kmod_pathname = tmp[0].strip()
dependencies_pathnames = tmp[1].strip()
kmod = self.get(kmod_pathname, create_if_missing=True)
if dependencies_pathnames:
for dep_pathname in dependencies_pathnames.split(' '):
dep_kmod = self.get(dep_pathname, create_if_missing=True)
kmod.depends_on.add(dep_kmod)
dep_kmod.is_dependency_for.add(kmod)
def load_depmod_file(self, filepath):
with open(filepath) as f:
lines = f.readlines()
for line in lines:
if not line or line.startswith('#'):
continue
self.process_depmod_line(line)
log.info('depmod %s loaded, number of kmods: %s', filepath, len(self.name_to_kmod_map))
def dump(self):
for kmod in self.name_to_kmod_map.values():
print(kmod)
def get_topo_order(self):
if self.topo_order is None:
self.topo_order = get_topo_order(self.name_to_kmod_map.values())
# TODO: what if we add something after?
return self.topo_order
def get_alphabetical_order(self):
kmods = list(self.name_to_kmod_map.values())
kmods.sort(key=lambda k: k.kmod_pathname)
return kmods
def load_kmods_from_dir(self, topdir):
ret = []
for root, dirs, files in os.walk(topdir):
for filename in files:
if filename.endswith('.xz'):
filename = filename[:-3]
if filename.endswith('.ko'):
kmod_pathname = os.path.join(root, filename)
ret.append(kmod_pathname)
return ret
def check_depmod_has_all_kmods(self, dirpath):
ret = self.load_kmods_from_dir(dirpath)
for kmod_pathname in ret:
kmod = self.get(kmod_pathname)
if not kmod:
raise Exception('Could not find kmod %s in depmod', kmod_pathname)
log.debug('OK: all (%s) kmods from %s are known', len(ret), dirpath)
class KModPackage(HierarchyObject):
def _get_depends_on(pkg):
return pkg.depends_on
def _get_deps_for(pkg):
return pkg.is_dependency_for
def __init__(self, name: str, depends_on=[]) -> None:
self.name: str = name
self.depends_on: set[KModPackage] = set(depends_on)
self.is_dependency_for: set[KModPackage] = set()
for pkg in self.depends_on:
pkg.is_dependency_for.add(self)
self.all_depends_on_list: list[KModPackage] = self._get_all_linked(KModPackage._get_depends_on)
self.all_depends_on: set[KModPackage] = set(self.all_depends_on_list)
self.all_deps_for: Optional[set[KModPackage]] = None
self.default = False
log.debug('KModPackage created %s, depends_on: %s', name, [pkg.name for pkg in depends_on])
def __repr__(self):
return self.name
def get_all_deps_for(self):
if self.all_deps_for is None:
self.all_deps_for = set(self._get_all_linked(KModPackage._get_deps_for))
return self.all_deps_for
def _get_all_linked(self, func_get_links):
ret = []
explore = func_get_links(self)
while len(explore) > 0:
new_explore = set()
for pkg in explore:
if pkg not in ret:
ret.append(pkg)
for dep in func_get_links(pkg):
new_explore.add(dep)
explore = new_explore
return ret
class KModPackageList(HierarchyObject):
def __init__(self) -> None:
self.name_to_obj: dict[str, KModPackage] = {}
self.kmod_pkg_list: list[KModPackage] = []
self.rules: list[tuple[str, str, str]] = []
def get(self, pkgname):
if pkgname in self.name_to_obj:
return self.name_to_obj[pkgname]
return None
def add_kmod_pkg(self, pkg):
self.name_to_obj[pkg.name] = pkg
self.kmod_pkg_list.append(pkg)
def __iter__(self):
return iter(self.kmod_pkg_list)
def get_kmods_matching_re(kmod_list: KModList, param_re: str) -> list[KMod]:
ret = []
# first subdir can be anything - this is because during build everything
# goes to kernel, but subpackages can move it (e.g. to extra)
param_re = '[^/]+/' + param_re
pattern = re.compile(param_re)
for kmod in kmod_list.get_topo_order():
m = pattern.match(kmod.kmod_pathname)
if m:
ret.append(kmod)
return ret
def walk_kmod_chain(kmod, myfunc):
visited = set()
def visit_kmod(kmod, parent_kmod, func_to_call):
func_to_call(kmod, parent_kmod)
visited.add(kmod)
for dep in kmod.depends_on:
if dep not in visited:
visit_kmod(dep, kmod, func_to_call)
visit_kmod(kmod, None, myfunc)
return visited
# is pkg a parent to any pkg from "alist"
def is_pkg_parent_to_any(pkg: KModPackage, alist: set[KModPackage]) -> bool:
if pkg in alist:
return True
for some_pkg in alist:
if some_pkg in pkg.all_depends_on:
return True
return False
# is pkg a child to any pkg from "alist"
def is_pkg_child_to_any(pkg: KModPackage, alist: set[KModPackage]) -> bool:
if pkg in alist:
return True
for some_pkg in alist:
if pkg in some_pkg.all_depends_on:
return True
return False
def update_allowed(kmod: KMod, visited: set[KMod], update_linked: bool = False) -> int:
num_updated = 0
init = False
to_remove = set()
if kmod in visited:
return num_updated
visited.add(kmod)
# if we have nothing, try to initialise based on parents and children
if kmod.allowed_list is None:
init_allowed_list: set[KModPackage] = set()
# init from children
for kmod_dep in kmod.depends_on:
if kmod_dep.allowed_list:
init_allowed_list.update(kmod_dep.allowed_list)
init = True
if init:
# also add any pkgs that pkgs from list could depend on
deps_for = set()
for pkg in init_allowed_list:
deps_for.update(pkg.get_all_deps_for())
init_allowed_list.update(deps_for)
# init from parents
if not init:
for kmod_par in kmod.is_dependency_for:
if kmod_par.allowed_list:
init_allowed_list.update(kmod_par.allowed_list)
# also add any pkgs that depend on pkgs from list
for pkg in kmod_par.allowed_list:
init_allowed_list.update(pkg.all_depends_on)
init = True
if init:
kmod.allowed_list = init_allowed_list
log.debug('%s: init to %s', kmod.name, [x.name for x in kmod.allowed_list])
kmod_allowed_list = kmod.allowed_list or set()
# log.debug('%s: update to %s', kmod.name, [x.name for x in kmod_allowed_list])
# each allowed is parent to at least one child allowed [for _all_ children]
for pkg in kmod_allowed_list:
for kmod_dep in kmod.depends_on:
if kmod_dep.allowed_list is None or kmod_dep.err:
continue
if not is_pkg_parent_to_any(pkg, kmod_dep.allowed_list):
to_remove.add(pkg)
log.debug('%s: remove %s from allowed, child: %s [%s]',
kmod.name, [pkg.name], kmod_dep.name, [x.name for x in kmod_dep.allowed_list])
# each allowed is child to at least one parent allowed [for _all_ parents]
for pkg in kmod_allowed_list:
for kmod_par in kmod.is_dependency_for:
if kmod_par.allowed_list is None or kmod_par.err:
continue
if not is_pkg_child_to_any(pkg, kmod_par.allowed_list):
to_remove.add(pkg)
log.debug('%s: remove %s from allowed, parent: %s %s',
kmod.name, [pkg.name], kmod_par.name, [x.name for x in kmod_par.allowed_list])
for pkg in to_remove:
kmod_allowed_list.remove(pkg)
num_updated = num_updated + 1
if len(kmod_allowed_list) == 0:
log.error('%s: cleared entire allow list', kmod.name)
kmod.err = 1
if init or to_remove or update_linked:
if to_remove:
log.debug('%s: updated to %s', kmod.name, [x.name for x in kmod_allowed_list])
for kmod_dep in kmod.depends_on:
num_updated = num_updated + update_allowed(kmod_dep, visited)
for kmod_dep in kmod.is_dependency_for:
num_updated = num_updated + update_allowed(kmod_dep, visited)
return num_updated
def apply_initial_labels(pkg_list: KModPackageList, kmod_list: KModList, treat_default_as_wants=False):
log.debug('')
for cur_rule in ['needs', 'wants', 'default']:
for package_name, rule_type, rule in pkg_list.rules:
pkg_obj = pkg_list.get(package_name)
if not pkg_obj:
log.error('no package with name %s', package_name)
if cur_rule != rule_type:
continue
if rule_type == 'default' and treat_default_as_wants:
rule_type = 'wants'
if 'needs' == rule_type:
# kmod_matching is already in topo_order
kmod_matching = get_kmods_matching_re(kmod_list, rule)
for kmod in kmod_matching:
if kmod.assigned_to_pkg and kmod.assigned_to_pkg != pkg_obj:
log.error('%s: can not be required by 2 pkgs %s %s', kmod.name, kmod.assigned_to_pkg, pkg_obj.name)
else:
kmod.assigned_to_pkg = pkg_obj
kmod.allowed_list = set([pkg_obj])
kmod.rule_specifity = len(kmod_matching)
log.debug('%s: needed by %s', kmod.name, [pkg_obj.name])
if 'wants' == rule_type:
# kmod_matching is already in topo_order
kmod_matching = get_kmods_matching_re(kmod_list, rule)
for kmod in kmod_matching:
if kmod.allowed_list is None:
kmod.allowed_list = set(pkg_obj.all_depends_on)
kmod.allowed_list.add(pkg_obj)
kmod.preferred_pkg = pkg_obj
kmod.rule_specifity = len(kmod_matching)
log.debug('%s: wanted by %s, init allowed to %s', kmod.name, [pkg_obj.name], [pkg.name for pkg in kmod.allowed_list])
else:
if kmod.assigned_to_pkg:
log.debug('%s: ignoring wants by %s, already assigned to %s', kmod.name, pkg_obj.name, kmod.assigned_to_pkg.name)
else:
# rule specifity may not be good idea, so just log it
# e.g. .*test.* may not be more specific than arch/x86/.*
log.debug('already have wants for %s %s, new rule: %s', kmod.name, kmod.preferred_pkg, rule)
if 'default' == rule_type:
pkg_obj.default = True
def settle(kmod_list: KModList) -> None:
kmod_topo_order = list(kmod_list.get_topo_order())
for i in range(0, 25):
log.debug('settle start %s', i)
ret = 0
for kmod in kmod_topo_order:
visited: set[KMod] = set()
ret = ret + update_allowed(kmod, visited)
log.debug('settle %s updated nodes: %s', i, ret)
if ret == 0:
break
kmod_topo_order.reverse()
# phase 1 - propagate initial labels
def propagate_labels_1(pkg_list: KModPackageList, kmod_list: KModList):
log.info('')
settle(kmod_list)
def pick_closest_to_preffered(preferred_pkg: KModPackage, allowed_set: set[KModPackage]):
for child in preferred_pkg.all_depends_on_list:
if child in allowed_set:
return child
return None
# phase 2 - if some kmods allow more than one pkg, pick wanted package
def propagate_labels_2(pkg_list: KModPackageList, kmod_list: KModList):
log.info('')
ret = 0
for kmod in kmod_list.get_topo_order():
update_linked = False
if kmod.allowed_list is None and kmod.preferred_pkg:
log.error('%s: has no allowed list but has preferred_pkg %s', kmod.name, kmod.preferred_pkg.name)
kmod.err = 1
if kmod.allowed_list and kmod.preferred_pkg:
chosen_pkg = None
if kmod.preferred_pkg in kmod.allowed_list:
chosen_pkg = kmod.preferred_pkg
else:
chosen_pkg = pick_closest_to_preffered(kmod.preferred_pkg, kmod.allowed_list)
if chosen_pkg is not None:
kmod.allowed_list = set([chosen_pkg])
log.debug('%s: making to prefer %s (preffered is %s), allowed: %s', kmod.name, chosen_pkg.name,
kmod.preferred_pkg.name, [pkg.name for pkg in kmod.allowed_list])
update_linked = True
visited: set[KMod] = set()
ret = ret + update_allowed(kmod, visited, update_linked)
log.debug('updated nodes: %s', ret)
settle(kmod_list)
# Is this the best pick? ¯\_(ツ)_/¯
def pick_topmost_allowed(allowed_set: set[KModPackage]) -> KModPackage:
topmost = next(iter(allowed_set))
for pkg in allowed_set:
if len(pkg.all_depends_on) > len(topmost.all_depends_on):
topmost = pkg
return topmost
# phase 3 - assign everything else that remained
def propagate_labels_3(pkg_list: KModPackageList, kmod_list: KModList):
log.info('')
ret = 0
kmod_topo_order = list(kmod_list.get_topo_order())
# do reverse topo order to cover children faster
kmod_topo_order.reverse()
default_pkg = None
default_name = ''
for pkg_obj in pkg_list:
if pkg_obj.default:
if default_pkg:
log.error('Already have default pkg: %s / %s', default_pkg.name, pkg_obj.name)
else:
default_pkg = pkg_obj
default_name = default_pkg.name
for kmod in kmod_topo_order:
update_linked = False
chosen_pkg = None
if kmod.allowed_list is None:
if default_pkg:
chosen_pkg = default_pkg
else:
log.error('%s not assigned and there is no default', kmod.name)
elif len(kmod.allowed_list) > 1:
if default_pkg:
if default_pkg in kmod.allowed_list:
chosen_pkg = default_pkg
else:
chosen_pkg = pick_closest_to_preffered(default_pkg, kmod.allowed_list)
if chosen_pkg:
log.debug('closest is %s', chosen_pkg.name)
if not chosen_pkg:
# multiple pkgs are allowed, but none is preferred or default
chosen_pkg = pick_topmost_allowed(kmod.allowed_list)
log.debug('topmost is %s', chosen_pkg.name)
if chosen_pkg:
kmod.allowed_list = set([chosen_pkg])
log.debug('%s: making to prefer %s (default: %s)', kmod.name, [chosen_pkg.name], default_name)
update_linked = True
visited: set[KMod] = set()
ret = ret + update_allowed(kmod, visited, update_linked)
log.debug('updated nodes: %s', ret)
settle(kmod_list)
def load_config(config_pathname: str, kmod_list: KModList, variants=[]):
kmod_pkg_list = KModPackageList()
with open(config_pathname, 'r') as file:
yobj = yaml.safe_load(file)
for pkg_dict in yobj['packages']:
pkg_name = pkg_dict['name']
depends_on = pkg_dict.get('depends-on', [])
if_variant_in = pkg_dict.get('if_variant_in')
if if_variant_in is not None:
if not (set(variants) & set(if_variant_in)):
log.debug('Skipping %s for variants %s', pkg_name, variants)
continue
pkg_dep_list = []
for pkg_dep_name in depends_on:
pkg_dep = kmod_pkg_list.get(pkg_dep_name)
pkg_dep_list.append(pkg_dep)
pkg_obj = kmod_pkg_list.get(pkg_name)
if not pkg_obj:
pkg_obj = KModPackage(pkg_name, pkg_dep_list)
kmod_pkg_list.add_kmod_pkg(pkg_obj)
else:
log.error('package %s already exists?', pkg_name)
rules_list = yobj.get('rules', [])
for rule_dict in rules_list:
if_variant_in = rule_dict.get('if_variant_in')
exact_pkg = rule_dict.get('exact_pkg')
for key, value in rule_dict.items():
if key in ['if_variant_in', 'exact_pkg']:
continue
if if_variant_in is not None:
if not (set(variants) & set(if_variant_in)):
continue
rule = key
package_name = value
if not kmod_pkg_list.get(package_name):
raise Exception('Unknown package ' + package_name)
rule_type = 'wants'
if exact_pkg is True:
rule_type = 'needs'
elif key == 'default':
rule_type = 'default'
rule = '.*'
log.debug('found rule: %s', (package_name, rule_type, rule))
kmod_pkg_list.rules.append((package_name, rule_type, rule))
log.info('loaded config, rules: %s', len(kmod_pkg_list.rules))
return kmod_pkg_list
def make_pictures(pkg_list: KModPackageList, kmod_list: KModList, filename: str, print_allowed=True):
f = open(filename + '.dot', 'w')
f.write('digraph {\n')
f.write('node [style=filled fillcolor="#f8f8f8"]\n')
f.write(' subgraph kmods {\n')
f.write(' "Legend" [shape=note label="kmod name\\n{desired package}\\nresulting package(s)"]\n')
for kmod in kmod_list.get_topo_order():
pkg_name = ''
attr = ''
if kmod.assigned_to_pkg:
attr = 'fillcolor="#eddad5" color="#b22800"'
pkg_name = kmod.assigned_to_pkg.name + "!"
if kmod.preferred_pkg:
attr = 'fillcolor="#ddddf5" color="#b268fe"'
pkg_name = kmod.preferred_pkg.name + "?"
allowed = ''
if kmod.allowed_list and print_allowed:
allowed = '=' + ' '.join([pkg.name for pkg in kmod.allowed_list])
f.write(' "%s" [label="%s\\n%s\\n%s" shape=box %s] \n' % (kmod.name, kmod.name, pkg_name, allowed, attr))
for kmod in kmod_list.get_topo_order():
for kmod_dep in kmod.depends_on:
f.write(' "%s" -> "%s";\n' % (kmod.name, kmod_dep.name))
f.write(' }\n')
f.write(' subgraph packages {\n')
for pkg in pkg_list:
desc = ''
if pkg.default:
desc = '/default'
f.write(' "%s" [label="%s\\n%s"] \n' % (pkg.name, pkg.name, desc))
for pkg_dep in pkg.depends_on:
f.write(' "%s" -> "%s";\n' % (pkg.name, pkg_dep.name))
f.write(' }\n')
f.write('}\n')
f.close()
# safe_run_command('dot -Tpng -Gdpi=150 %s.dot > %s.png' % (filename, filename))
safe_run_command('dot -Tsvg %s.dot > %s.svg' % (filename, filename))
def sort_kmods(depmod_pathname: str, config_str: str, variants=[], do_pictures=''):
log.info('%s %s', depmod_pathname, config_str)
kmod_list = KModList()
kmod_list.load_depmod_file(depmod_pathname)
pkg_list = load_config(config_str, kmod_list, variants)
basename = os.path.splitext(config_str)[0]
apply_initial_labels(pkg_list, kmod_list)
if '0' in do_pictures:
make_pictures(pkg_list, kmod_list, basename + "_0", print_allowed=False)
try:
propagate_labels_1(pkg_list, kmod_list)
if '1' in do_pictures:
make_pictures(pkg_list, kmod_list, basename + "_1")
propagate_labels_2(pkg_list, kmod_list)
propagate_labels_3(pkg_list, kmod_list)
finally:
if 'f' in do_pictures:
make_pictures(pkg_list, kmod_list, basename + "_f")
return pkg_list, kmod_list
def abbrev_list_for_report(alist: list[KMod]) -> str:
tmp_str = []
for kmod in alist:
if kmod.allowed_list:
tmp_str.append('%s(%s)' % (kmod.name, ' '.join([x.name for x in kmod.allowed_list])))
ret = ', '.join(tmp_str)
return ret
def print_report(pkg_list: KModPackageList, kmod_list: KModList):
log.info('*'*26 + ' REPORT ' + '*'*26)
kmods_err = 0
kmods_moved = 0
kmods_good = 0
for kmod in kmod_list.get_topo_order():
if not kmod.allowed_list:
log.error('%s: not assigned to any package! Please check the full log for details', kmod.name)
kmods_err = kmods_err + 1
continue
if len(kmod.allowed_list) > 1:
log.error('%s: assigned to more than one package! Please check the full log for details', kmod.name)
kmods_err = kmods_err + 1
continue
if not kmod.preferred_pkg:
# config doesn't care where it ended up
kmods_good = kmods_good + 1
continue
if kmod.preferred_pkg in kmod.allowed_list:
# it ended up where it needs to be
kmods_good = kmods_good + 1
continue
bad_parent_list = []
for kmod_parent in kmod.is_dependency_for:
if not is_pkg_child_to_any(kmod.preferred_pkg, kmod_parent.allowed_list):
bad_parent_list.append(kmod_parent)
bad_child_list = []
for kmod_child in kmod.depends_on:
if not is_pkg_parent_to_any(kmod.preferred_pkg, kmod_child.allowed_list):
bad_child_list.append(kmod_parent)
log.info('%s: wanted by %s but ended up in %s', kmod.name, [kmod.preferred_pkg.name], [pkg.name for pkg in kmod.allowed_list])
if bad_parent_list:
log.info('\thas conflicting parent: %s', abbrev_list_for_report(bad_parent_list))
if bad_child_list:
log.info('\thas conflicting children: %s', abbrev_list_for_report(bad_child_list))
kmods_moved = kmods_moved + 1
log.info('No. of kmod(s) assigned to preferred package: %s', kmods_good)
log.info('No. of kmod(s) moved to a related package: %s', kmods_moved)
log.info('No. of kmod(s) which could not be assigned: %s', kmods_err)
log.info('*'*60)
return kmods_err
def write_modules_lists(path_prefix: str, pkg_list: KModPackageList, kmod_list: KModList):
kmod_list_alphabetical = sorted(kmod_list.get_topo_order(), key=lambda x: x.kmod_pathname)
for pkg in pkg_list:
output_path = os.path.join(path_prefix, pkg.name + '.list')
i = 0
with open(output_path, "w") as file:
for kmod in kmod_list_alphabetical:
if kmod.allowed_list and pkg in kmod.allowed_list:
file.write(kmod.kmod_pathname)
file.write('\n')
i = i + 1
log.info('Module list %s created with %s kmods', output_path, i)
class FiltermodTests(unittest.TestCase):
do_pictures = ''
def setUp(self):
self.pkg_list = None
self.kmod_list = None
def _is_kmod_pkg(self, kmodname, pkgnames):
self.assertIsNotNone(self.pkg_list)
self.assertIsNotNone(self.kmod_list)
if type(pkgnames) is str:
pkgnames = [pkgnames]
expected_pkgs = []
for pkgname in pkgnames:
pkg = self.pkg_list.get(pkgname)
self.assertIsNotNone(pkg)
expected_pkgs.append(pkg)
kmod = self.kmod_list.get(kmodname)
self.assertIsNotNone(kmod)
if expected_pkgs:
self.assertTrue(len(kmod.allowed_list) == 1)
self.assertIn(next(iter(kmod.allowed_list)), expected_pkgs)
else:
self.assertEqual(kmod.allowed_list, set())
def test1a(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test1.dep'), get_td('test1.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._is_kmod_pkg('kmod1', 'modules-core')
self._is_kmod_pkg('kmod2', 'modules-core')
self._is_kmod_pkg('kmod3', 'modules')
self._is_kmod_pkg('kmod4', 'modules')
def test1b(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test1.dep'), get_td('test1.yaml'),
do_pictures=FiltermodTests.do_pictures,
variants=['rt'])
self.assertIsNotNone(self.pkg_list.get('rt-kvm'))
self._is_kmod_pkg('kmod1', 'modules-core')
self._is_kmod_pkg('kmod2', 'modules-core')
self._is_kmod_pkg('kmod3', 'modules')
self._is_kmod_pkg('kmod4', 'rt-kvm')
def test2(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test2.dep'), get_td('test2.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._is_kmod_pkg('kmod1', 'modules-extra')
self._is_kmod_pkg('kmod2', 'modules')
self._is_kmod_pkg('kmod3', 'modules-core')
self._is_kmod_pkg('kmod4', 'modules-core')
self._is_kmod_pkg('kmod5', 'modules-core')
self._is_kmod_pkg('kmod6', 'modules-extra')
self._is_kmod_pkg('kmod8', 'modules')
def test3(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test3.dep'), get_td('test3.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._is_kmod_pkg('kmod2', ['modules-core', 'modules'])
self._is_kmod_pkg('kmod4', ['modules-core', 'modules-extra'])
self._is_kmod_pkg('kmod5', 'modules-core')
self._is_kmod_pkg('kmod6', 'modules-core')
def test4(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test4.dep'), get_td('test4.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._is_kmod_pkg('kmod0', 'modules')
self._is_kmod_pkg('kmod1', 'modules')
self._is_kmod_pkg('kmod2', 'modules')
self._is_kmod_pkg('kmod3', 'modules')
self._is_kmod_pkg('kmod4', 'modules')
self._is_kmod_pkg('kmod5', 'modules')
self._is_kmod_pkg('kmod6', 'modules')
self._is_kmod_pkg('kmod7', 'modules-partner2')
self._is_kmod_pkg('kmod8', 'modules-partner')
self._is_kmod_pkg('kmod9', 'modules-partner')
def _check_preffered_pkg(self, kmodname, pkgname):
kmod = self.kmod_list.get(kmodname)
self.assertIsNotNone(kmod)
self.assertEqual(kmod.preferred_pkg.name, pkgname)
def test5(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test5.dep'), get_td('test5.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._check_preffered_pkg('kmod2', 'modules')
self._check_preffered_pkg('kmod3', 'modules-partner')
self._check_preffered_pkg('kmod4', 'modules-partner')
def test6(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test6.dep'), get_td('test6.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._is_kmod_pkg('kmod2', 'modules-core')
self._is_kmod_pkg('kmod3', 'modules')
self._is_kmod_pkg('kmod4', 'modules')
self._is_kmod_pkg('kmod1', [])
def test7(self):
self.pkg_list, self.kmod_list = sort_kmods(get_td('test7.dep'), get_td('test7.yaml'),
do_pictures=FiltermodTests.do_pictures)
self._is_kmod_pkg('kmod1', 'modules-core')
self._is_kmod_pkg('kmod2', 'modules-core')
self._is_kmod_pkg('kmod3', 'modules-other')
self._is_kmod_pkg('kmod4', 'modules')
def do_rpm_mapping_test(config_pathname, kmod_rpms):
kmod_dict = {}
def get_kmods_matching_re(pkgname, param_re):
matched = []
param_re = '^kernel/' + param_re
pattern = re.compile(param_re)
for kmod_pathname, kmod_rec in kmod_dict.items():
m = pattern.match(kmod_pathname)
if m:
matched.append(kmod_pathname)
return matched
for kmod_rpm in kmod_rpms.split():
filename = os.path.basename(kmod_rpm)
m = re.match(r'.*-modules-([^-]+)', filename)
if not m:
raise Exception('Unrecognized rpm ' + kmod_rpm + ', expected a kernel-modules* rpm')
pkgname = 'modules-' + m.group(1)
m = re.match(r'modules-([0-9.]+)', pkgname)
if m:
pkgname = 'modules'
tmpdir = os.path.join('tmp.filtermods', filename, pkgname)
if not os.path.exists(tmpdir):
log.info('creating tmp dir %s', tmpdir)
os.makedirs(tmpdir)
safe_run_command('rpm2cpio %s | cpio -id' % (os.path.abspath(kmod_rpm)), cwddir=tmpdir)
else:
log.info('using cached content of tmp dir: %s', tmpdir)
for path, subdirs, files in os.walk(tmpdir):
for name in files:
ret = re.match(r'.*/'+pkgname+'/lib/modules/[^/]+/[^/]+/(.*)', os.path.join(path, name))
if not ret:
continue
kmod_pathname = 'kernel/' + ret.group(1)
if not kmod_pathname.endswith('.xz') and not kmod_pathname.endswith('.ko'):
continue
if kmod_pathname in kmod_dict:
if pkgname not in kmod_dict[kmod_pathname]['target_pkgs']:
kmod_dict[kmod_pathname]['target_pkgs'].append(pkgname)
else:
kmod_dict[kmod_pathname] = {}
kmod_dict[kmod_pathname]['target_pkgs'] = [pkgname]
kmod_dict[kmod_pathname]['pkg'] = None
kmod_dict[kmod_pathname]['matched'] = False
kmod_pkg_list = load_config(config_pathname, None)
for package_name, rule_type, rule in kmod_pkg_list.rules:
kmod_names = get_kmods_matching_re(package_name, rule)
for kmod_pathname in kmod_names:
kmod_rec = kmod_dict[kmod_pathname]
if not kmod_rec['matched']:
kmod_rec['matched'] = True
kmod_rec['pkg'] = package_name
for kmod_pathname, kmod_rec in kmod_dict.items():
if kmod_rec['pkg'] not in kmod_rec['target_pkgs']:
log.warning('kmod %s wanted by config in %s, in tree it is: %s', kmod_pathname, [kmod_rec['pkg']], kmod_rec['target_pkgs'])
elif len(kmod_rec['target_pkgs']) > 1:
# if set(kmod_rec['target_pkgs']) != set(['modules', 'modules-core']):
log.warning('kmod %s multiple matches in tree: %s/%s', kmod_pathname, [kmod_rec['pkg']], kmod_rec['target_pkgs'])
def cmd_sort(options):
do_pictures = ''
if options.graphviz:
do_pictures = '0f'
pkg_list, kmod_list = sort_kmods(options.depmod, options.config,
options.variants, do_pictures)
ret = print_report(pkg_list, kmod_list)
if options.output:
write_modules_lists(options.output, pkg_list, kmod_list)
return ret
def cmd_print_rule_map(options):
kmod_list = KModList()
kmod_list.load_depmod_file(options.depmod)
pkg_list = load_config(options.config, kmod_list, options.variants)
apply_initial_labels(pkg_list, kmod_list, treat_default_as_wants=True)
for kmod in kmod_list.get_alphabetical_order():
print('%-20s %s' % (kmod.preferred_pkg, kmod.kmod_pathname))
def cmd_selftest(options):
if options.graphviz:
FiltermodTests.do_pictures = '0f'
for arg in ['selftest', '-g', '--graphviz']:
if arg in sys.argv:
sys.argv.remove(arg)
unittest.main()
sys.exit(0)
def cmd_cmp2rpm(options):
do_rpm_mapping_test(options.config, options.kmod_rpms)
def main():
global log
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', dest='verbose',
help='be more verbose', action='count', default=4)
parser.add_argument('-q', '--quiet', dest='quiet',
help='be more quiet', action='count', default=0)
parser.add_argument('-l', '--log-filename', dest='log_filename',
help='log filename', default='filtermods.log')
subparsers = parser.add_subparsers(dest='cmd')
def add_graphviz_arg(p):
p.add_argument('-g', '--graphviz', dest='graphviz',
help='generate graphviz visualizations',
action='store_true', default=False)
def add_config_arg(p):
p.add_argument('-c', '--config', dest='config', required=True,
help='path to yaml config with rules')
def add_depmod_arg(p):
p.add_argument('-d', '--depmod', dest='depmod', required=True,
help='path to modules.dep file')
def add_output_arg(p):
p.add_argument('-o', '--output', dest='output', default=None,
help='output $module_name.list files to directory specified by this parameter')
def add_variants_arg(p):
p.add_argument('-r', '--variants', dest='variants', action='append', default=[],
help='variants to enable in config')
def add_kmod_rpms_arg(p):
p.add_argument('-k', '--kmod-rpms', dest='kmod_rpms', required=True,
help='compare content of specified rpm(s) against yaml config rules')
parser_sort = subparsers.add_parser('sort', help='assign kmods specified by modules.dep using rules from yaml config')
add_config_arg(parser_sort)
add_depmod_arg(parser_sort)
add_output_arg(parser_sort)
add_variants_arg(parser_sort)
add_graphviz_arg(parser_sort)
parser_rule_map = subparsers.add_parser('rulemap', help='print how yaml config maps to kmods')
add_config_arg(parser_rule_map)
add_depmod_arg(parser_rule_map)
add_variants_arg(parser_rule_map)
parser_test = subparsers.add_parser('selftest', help='runs a self-test')
add_graphviz_arg(parser_test)
parser_cmp2rpm = subparsers.add_parser('cmp2rpm', help='compare ruleset against RPM(s)')
add_config_arg(parser_cmp2rpm)
add_kmod_rpms_arg(parser_cmp2rpm)
options = parser.parse_args()
if options.cmd == "selftest":
options.verbose = options.verbose - 2
options.verbose = max(options.verbose - options.quiet, 0)
levels = [NOTSET, CRITICAL, ERROR, WARN, INFO, DEBUG]
stdout_log_level = levels[min(options.verbose, len(levels) - 1)]
log = setup_logging(options.log_filename, stdout_log_level)
ret = 0
if options.cmd == "sort":
ret = cmd_sort(options)
elif options.cmd == "rulemap":
cmd_print_rule_map(options)
elif options.cmd == "selftest":
cmd_selftest(options)
elif options.cmd == "cmp2rpm":
cmd_cmp2rpm(options)
else:
parser.print_help()
return ret
if __name__ == '__main__':
# import profile
# profile.run('main()', sort=1)
sys.exit(main())