dffdf2ccc5
* 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>
1097 lines
39 KiB
Python
Executable File
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())
|