* Re: [PATCH 11/13] mm/mlock: convert mlock code to use vma_flags_t
From: Lorenzo Stoakes @ 2026-07-02 15:47 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, tsbogend, maddy, mpe, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, l.stach, inki.dae, sw0312.kim,
kyungmin.park, krzk, peter.griffin, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, robin.clark, lumag, lyude, dakr,
tomi.valkeinen, hjc, heiko, andy.yan, thierry.reding, mperttunen,
jonathanh, kraxel, dmitry.osipenko, zack.rusin, matthew.brost,
thomas.hellstrom, oleksandr_andrushchenko, deller, bcrl, viro,
brauner, muchun.song, osalvador, david, ziy, baolin.wang, liam,
npache, ryan.roberts, dev.jain, baohua, hughd, vbabka, rppt,
surenb, mhocko, jannh, pfalcato, kees, perex, tiwai, linux-mips,
linux-kernel, linuxppc-dev, dri-devel, etnaviv, linux-arm-kernel,
linux-samsung-soc, intel-gfx, linux-arm-msm, freedreno, nouveau,
linux-rockchip, linux-tegra, virtualization, intel-xe, xen-devel,
linux-fbdev, linux-aio, linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <20260702132107.73727-1-lance.yang@linux.dev>
On Thu, Jul 02, 2026 at 09:21:07PM +0800, Lance Yang wrote:
>
> On Mon, Jun 29, 2026 at 08:25:34PM +0100, Lorenzo Stoakes wrote:
> >Replace use of the legacy vm_flags_t flags with vma_flags_t values
> >throughout the mlock logic.
> >
> >Additionally update comments to reflect the changes to be consistent.
> >
> >No functional change intended.
> >
> >Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> >---
>
> Nothing scary jumped out at me. Just one tiny nit below ;)
>
> [...]
> >@@ -466,24 +466,23 @@ static void mlock_vma_pages_range(struct vm_area_struct *vma,
> > */
> > static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma,
> > struct vm_area_struct **prev, unsigned long start,
> >- unsigned long end, vm_flags_t newflags)
> >+ unsigned long end, vma_flags_t *new_vma_flags)
> > {
> >- vma_flags_t new_vma_flags = legacy_to_vma_flags(newflags);
> > const vma_flags_t old_vma_flags = vma->flags;
> > struct mm_struct *mm = vma->vm_mm;
> > int nr_pages;
> > int ret = 0;
> >
> >- if (vma_flags_same_pair(&old_vma_flags, &new_vma_flags) ||
> >+ if (vma_flags_same_pair(&old_vma_flags, new_vma_flags) ||
> > vma_is_secretmem(vma) || !vma_supports_mlock(vma)) {
> > /*
> >- * Don't set VM_LOCKED or VM_LOCKONFAULT and don't count.
> >+ * Don't set VMA_LOCKED_BIT or VM_LOCKONFAULT and don't count.
>
> s/VM_LOCKONFAULT/VMA_LOCKONFAULT_BIT/
Ah yeah oops, will fix and respin! Good spot [and claude missed it ugh] :)
>
> Otherwise LGTM. Feel free to add:
>
> Reviewed-by: Lance Yang <lance.yang@linux.dev>
>
> > * For secretmem, don't allow the memory to be unlocked.
> > */
> > goto out;
> > }
> >
> >- vma = vma_modify_flags(vmi, *prev, vma, start, end, &new_vma_flags);
> >+ vma = vma_modify_flags(vmi, *prev, vma, start, end, new_vma_flags);
> > if (IS_ERR(vma)) {
> > ret = PTR_ERR(vma);
> > goto out;
> [...]
Thanks, Lorenzo
^ permalink raw reply
* Re: [PATCH 12/13] mm/mprotect: convert mprotect code to use vma_flags_t
From: Lorenzo Stoakes @ 2026-07-02 15:53 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, tsbogend, maddy, mpe, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, l.stach, inki.dae, sw0312.kim,
kyungmin.park, krzk, peter.griffin, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, robin.clark, lumag, lyude, dakr,
tomi.valkeinen, hjc, heiko, andy.yan, thierry.reding, mperttunen,
jonathanh, kraxel, dmitry.osipenko, zack.rusin, matthew.brost,
thomas.hellstrom, oleksandr_andrushchenko, deller, bcrl, viro,
brauner, muchun.song, osalvador, david, ziy, baolin.wang, liam,
npache, ryan.roberts, dev.jain, baohua, hughd, vbabka, rppt,
surenb, mhocko, jannh, pfalcato, kees, perex, tiwai, linux-mips,
linux-kernel, linuxppc-dev, dri-devel, etnaviv, linux-arm-kernel,
linux-samsung-soc, intel-gfx, linux-arm-msm, freedreno, nouveau,
linux-rockchip, linux-tegra, virtualization, intel-xe, xen-devel,
linux-fbdev, linux-aio, linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <20260701160917.91435-1-lance.yang@linux.dev>
On Thu, Jul 02, 2026 at 12:09:17AM +0800, Lance Yang wrote:
>
> On Mon, Jun 29, 2026 at 08:25:35PM +0100, Lorenzo Stoakes wrote:
> >Replace use of the legacy vm_flags_t flags with vma_flags_t values
> >throughout the mprotect logic.
> >
> >Note that we retain the legacy vm_flags_t bit shifting code in
> >do_mprotect_key(), deferring a vma_flags_t approach to this for the time
> >being.
> >
> >Additionally update comments to reflect the changes to be consistent.
> >
> >No functional change intended.
> >
> >Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> >---
> > mm/mprotect.c | 16 ++++++++--------
> > 1 file changed, 8 insertions(+), 8 deletions(-)
> >
> >diff --git a/mm/mprotect.c b/mm/mprotect.c
> >index 9cbf932b028c..c9504b2a2525 100644
> >--- a/mm/mprotect.c
> >+++ b/mm/mprotect.c
> >@@ -40,7 +40,7 @@
> >
> > static bool maybe_change_pte_writable(struct vm_area_struct *vma, pte_t pte)
> > {
> >- if (WARN_ON_ONCE(!(vma->vm_flags & VM_WRITE)))
> >+ if (WARN_ON_ONCE(!vma_test(vma, VMA_WRITE_BIT)))
> > return false;
> >
> > /* Don't touch entries that are not even readable. */
> >@@ -97,7 +97,7 @@ static bool can_change_shared_pte_writable(struct vm_area_struct *vma,
> > bool can_change_pte_writable(struct vm_area_struct *vma, unsigned long addr,
> > pte_t pte)
> > {
> >- if (!(vma->vm_flags & VM_SHARED))
> >+ if (!vma_test(vma, VMA_SHARED_BIT))
> > return can_change_private_pte_writable(vma, addr, pte);
> >
> > return can_change_shared_pte_writable(vma, pte);
> >@@ -194,7 +194,7 @@ static __always_inline void set_write_prot_commit_flush_ptes(struct vm_area_stru
> > {
> > bool set_write;
> >
> >- if (vma->vm_flags & VM_SHARED) {
> >+ if (vma_test(vma, VMA_SHARED_BIT)) {
> > set_write = can_change_shared_pte_writable(vma, ptent);
> > prot_commit_flush_ptes(vma, addr, ptep, oldpte, ptent, nr_ptes,
> > /* idx = */ 0, set_write, tlb);
> >@@ -811,8 +811,8 @@ mprotect_fixup(struct vma_iterator *vmi, struct mmu_gather *tlb,
> > vm_unacct_memory(nrpages);
> >
> > /*
> >- * Private VM_LOCKED VMA becoming writable: trigger COW to avoid major
> >- * fault on access.
> >+ * Private VMA_LOCKED_BIT VMA becoming writable: trigger COW to avoid
> >+ * major fault on access.
> > */
> > if (vma_flags_test(&new_vma_flags, VMA_WRITE_BIT) &&
> > vma_flags_test(&old_vma_flags, VMA_LOCKED_BIT) &&
> >@@ -886,7 +886,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
> > goto out;
> > start = vma->vm_start;
> > error = -EINVAL;
> >- if (!(vma->vm_flags & VM_GROWSDOWN))
> >+ if (!vma_test(vma, VMA_GROWSDOWN_BIT))
> > goto out;
> > } else {
> > if (vma->vm_start > start)
> >@@ -894,7 +894,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
> > if (unlikely(grows & PROT_GROWSUP)) {
> > end = vma->vm_end;
> > error = -EINVAL;
> >- if (!(vma->vm_flags & VM_GROWSUP))
> >+ if (!vma_test(vma, VMA_GROWSUP_BIT))
>
> IIUC, should this be
>
> if (!vma_test_single_mask(vma, VMA_GROWSUP))
>
> instead?
>
> #elif defined(CONFIG_PARISC)
> #define VM_GROWSUP INIT_VM_FLAG(GROWSUP)
> ...
> #ifndef VM_GROWSUP
> #define VM_GROWSUP VM_NONE
> ...
>
> VM_GROWSUP is only defined as GROWSUP on parisc and becomes VM_NONE
> elsewhere. But VMA_GROWSUP_BIT is the raw ARCH_1 bit, which is also used
> for other arch-specific VMA flags:
>
> DECLARE_VMA_BIT_ALIAS(SAO, ARCH_1), /* Strong Access Ordering (powerpc) */
> DECLARE_VMA_BIT_ALIAS(GROWSUP, ARCH_1), /* parisc */
> DECLARE_VMA_BIT_ALIAS(SPARC_ADI, ARCH_1), /* sparc64 */
> DECLARE_VMA_BIT_ALIAS(ARM64_BTI, ARCH_1), /* arm64 */
> DECLARE_VMA_BIT_ALIAS(ARCH_CLEAR, ARCH_1), /* sparc64, arm64 */
> DECLARE_VMA_BIT_ALIAS(MAPPED_COPY, ARCH_1), /* !CONFIG_MMU */
>
> Other vma_test() changes look fine to me: just fixed INIT_VM_FLAG()
> masks matching their VMA_*_BIT :)
Thanks you're right, will fix!
Again I swear I ran claude on all of this so it's failing me here :)
>
> Cheers, Lance
>
> > goto out;
> > }
> > }
> >@@ -918,7 +918,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
> > }
> >
> > /* Does the application expect PROT_READ to imply PROT_EXEC */
> >- if (rier && (vma->vm_flags & VM_MAYEXEC))
> >+ if (rier && vma_test(vma, VMA_MAYEXEC_BIT))
> > prot |= PROT_EXEC;
> >
> > /*
> >--
> >2.54.0
> >
> >
^ permalink raw reply
* Re: [PATCH 13/13] mm/mremap: convert mremap code to use vma_flags_t
From: Lorenzo Stoakes @ 2026-07-02 16:07 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, tsbogend, maddy, mpe, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, l.stach, inki.dae, sw0312.kim,
kyungmin.park, krzk, peter.griffin, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, robin.clark, lumag, lyude, dakr,
tomi.valkeinen, hjc, heiko, andy.yan, thierry.reding, mperttunen,
jonathanh, kraxel, dmitry.osipenko, zack.rusin, matthew.brost,
thomas.hellstrom, oleksandr_andrushchenko, deller, bcrl, viro,
brauner, muchun.song, osalvador, david, ziy, baolin.wang, liam,
npache, ryan.roberts, dev.jain, baohua, hughd, vbabka, rppt,
surenb, mhocko, jannh, pfalcato, kees, perex, tiwai, linux-mips,
linux-kernel, linuxppc-dev, dri-devel, etnaviv, linux-arm-kernel,
linux-samsung-soc, intel-gfx, linux-arm-msm, freedreno, nouveau,
linux-rockchip, linux-tegra, virtualization, intel-xe, xen-devel,
linux-fbdev, linux-aio, linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <20260702134947.25189-1-lance.yang@linux.dev>
On Thu, Jul 02, 2026 at 09:49:47PM +0800, Lance Yang wrote:
>
> On Mon, Jun 29, 2026 at 08:25:36PM +0100, Lorenzo Stoakes wrote:
> >Replace use of the legacy vm_flags_t flags with vma_flags_t values
> >throughout the mremap logic.
> >
> >Additionally update comments to reflect the changes to be consistent.
> >
> >No functional change intended.
> >
> >Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> >---
>
> The vm_flags_set() cases below spell out vma_start_write(), but the
> vm_flags_clear() cases don't?
Yep as I said elsewhere, implicitly taking the lock is terrible and me doing
this is completely on purpose to get rid of that :)
But I haven't been clear enough clearly, so I should put the argument as to why
that's ok in the commit message.
Will do so on respin.
>
> Thanks, Lance
>
> > mm/mremap.c | 38 ++++++++++++++++++++------------------
> > 1 file changed, 20 insertions(+), 18 deletions(-)
> >
> >diff --git a/mm/mremap.c b/mm/mremap.c
> >index 079a0ba0c4a7..0ea43302b7ed 100644
> >--- a/mm/mremap.c
> >+++ b/mm/mremap.c
> >@@ -68,7 +68,7 @@ struct vma_remap_struct {
> > bool populate_expand; /* mlock()'d expanded, must populate. */
> > enum mremap_type remap_type; /* expand, shrink, etc. */
> > bool mmap_locked; /* Is mm currently write-locked? */
> >- unsigned long charged; /* If VM_ACCOUNT, # pages to account. */
> >+ unsigned long charged; /* If VMA_ACCOUNT_BIT, # pgs to account */
> > bool vmi_needs_invalidate; /* Is the VMA iterator invalidated? */
> > };
> >
> >@@ -954,7 +954,7 @@ static unsigned long vrm_set_new_addr(struct vma_remap_struct *vrm)
> >
> > if (vrm->flags & MREMAP_FIXED)
> > map_flags |= MAP_FIXED;
> >- if (vma->vm_flags & VM_MAYSHARE)
> >+ if (vma_test(vma, VMA_MAYSHARE_BIT))
> > map_flags |= MAP_SHARED;
> >
> > res = get_unmapped_area(vma->vm_file, new_addr, vrm->new_len, pgoff,
> >@@ -976,7 +976,7 @@ static bool vrm_calc_charge(struct vma_remap_struct *vrm)
> > {
> > unsigned long charged;
> >
> >- if (!(vrm->vma->vm_flags & VM_ACCOUNT))
> >+ if (!vma_test(vrm->vma, VMA_ACCOUNT_BIT))
> > return true;
> >
> > /*
> >@@ -1003,7 +1003,7 @@ static bool vrm_calc_charge(struct vma_remap_struct *vrm)
> > */
> > static void vrm_uncharge(struct vma_remap_struct *vrm)
> > {
> >- if (!(vrm->vma->vm_flags & VM_ACCOUNT))
> >+ if (!vma_test(vrm->vma, VMA_ACCOUNT_BIT))
> > return;
> >
> > vm_unacct_memory(vrm->charged);
> >@@ -1023,7 +1023,7 @@ static void vrm_stat_account(struct vma_remap_struct *vrm,
> > struct vm_area_struct *vma = vrm->vma;
> >
> > vm_stat_account(mm, vma->vm_flags, pages);
> >- if (vma->vm_flags & VM_LOCKED)
> >+ if (vma_test(vma, VMA_LOCKED_BIT))
> > mm->locked_vm += pages;
> > }
> >
> >@@ -1167,7 +1167,7 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
> > * arose, in which case we _do_ wish to unmap the _new_ VMA, which means
> > * we actually _do_ want it be unaccounted.
> > */
> >- bool accountable_move = (vma->vm_flags & VM_ACCOUNT) &&
> >+ bool accountable_move = vma_test(vma, VMA_ACCOUNT_BIT) &&
> > !(vrm->flags & MREMAP_DONTUNMAP);
> >
> > /*
> >@@ -1186,7 +1186,7 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
> > * portions of the original VMA that remain.
> > */
> > if (accountable_move) {
> >- vm_flags_clear(vma, VM_ACCOUNT);
> >+ vma_clear_flags(vma, VMA_ACCOUNT_BIT);
This is called from move_vma() which holds the VMA write lock on vma.
> > /* We are about to split vma, so store the start/end. */
> > vm_start = vma->vm_start;
> > vm_end = vma->vm_end;
> >@@ -1211,8 +1211,8 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
> > * | |
> > * |-------------|
> > *
> >- * Having cleared VM_ACCOUNT from the whole VMA, after we unmap above
> >- * we'll end up with:
> >+ * Having cleared VMA_ACCOUNT_BIT from the whole VMA, after we unmap
> >+ * above we'll end up with:
> > *
> > * addr end
> > * | |
> >@@ -1232,13 +1232,15 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
> > if (vm_start < addr) {
> > struct vm_area_struct *prev = vma_prev(&vmi);
> >
> >- vm_flags_set(prev, VM_ACCOUNT); /* Acquires VMA lock. */
> >+ vma_start_write(prev);
> >+ vma_set_flags(prev, VMA_ACCOUNT_BIT);
> > }
> >
> > if (vm_end > end) {
> > struct vm_area_struct *next = vma_next(&vmi);
> >
> >- vm_flags_set(next, VM_ACCOUNT); /* Acquires VMA lock. */
> >+ vma_start_write(next);
> >+ vma_set_flags(next, VMA_ACCOUNT_BIT);
These need vma_start_write() as referencing other, unlocked VMAs.
> > }
> > }
> > }
> >@@ -1321,8 +1323,8 @@ static void dontunmap_complete(struct vma_remap_struct *vrm,
> > unsigned long old_start = vrm->vma->vm_start;
> > unsigned long old_end = vrm->vma->vm_end;
> >
> >- /* We always clear VM_LOCKED[ONFAULT] on the old VMA. */
> >- vm_flags_clear(vrm->vma, VM_LOCKED_MASK);
> >+ /* We always clear VMA_LOCKED[ONFAULT]_BIT on the old VMA. */
> >+ vma_clear_flags_mask(vrm->vma, VMA_LOCKED_MASK);
-
Same as above, called from move_vma() with VMA write lock held.
> >
> > /*
> > * anon_vma links of the old vma is no longer needed after its page
> >@@ -1758,14 +1760,14 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
> > * based on the original. There are no known use cases for this
> > * behavior. As a result, fail such attempts.
> > */
> >- if (!old_len && !(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) {
> >+ if (!old_len && !vma_test_any(vma, VMA_SHARED_BIT, VMA_MAYSHARE_BIT)) {
> > pr_warn_once("%s (%d): attempted to duplicate a private mapping with mremap. This is not supported.\n",
> > current->comm, current->pid);
> > return -EINVAL;
> > }
> >
> > if ((vrm->flags & MREMAP_DONTUNMAP) &&
> >- (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)))
> >+ vma_test_any(vma, VMA_DONTEXPAND_BIT, VMA_PFNMAP_BIT))
> > return -EINVAL;
> >
> > /*
> >@@ -1795,7 +1797,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
> > return 0;
> >
> > /* We are expanding and the VMA is mlock()'d so we need to populate. */
> >- if (vma->vm_flags & VM_LOCKED)
> >+ if (vma_test(vma, VMA_LOCKED_BIT))
> > vrm->populate_expand = true;
> >
> > /* Need to be careful about a growing mapping */
> >@@ -1803,10 +1805,10 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
> > if (pgoff + (new_len >> PAGE_SHIFT) < pgoff)
> > return -EINVAL;
> >
> >- if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
> >+ if (vma_test_any(vma, VMA_DONTEXPAND_BIT, VMA_PFNMAP_BIT))
> > return -EFAULT;
> >
> >- if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, vrm->delta))
> >+ if (!mlock_future_ok(mm, vma_test(vma, VMA_LOCKED_BIT), vrm->delta))
> > return -EAGAIN;
> >
> > if (!may_expand_vm(mm, &vma->flags, vrm->delta >> PAGE_SHIFT))
> >--
> >2.54.0
> >
> >
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH 13/13] mm/mremap: convert mremap code to use vma_flags_t
From: Lance Yang @ 2026-07-02 16:17 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: akpm, tsbogend, maddy, mpe, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, l.stach, inki.dae, sw0312.kim,
kyungmin.park, krzk, peter.griffin, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, robin.clark, lumag, lyude, dakr,
tomi.valkeinen, hjc, heiko, andy.yan, thierry.reding, mperttunen,
jonathanh, kraxel, dmitry.osipenko, zack.rusin, matthew.brost,
thomas.hellstrom, oleksandr_andrushchenko, deller, bcrl, viro,
brauner, muchun.song, osalvador, david, ziy, baolin.wang, liam,
npache, ryan.roberts, dev.jain, baohua, hughd, vbabka, rppt,
surenb, mhocko, jannh, pfalcato, kees, perex, tiwai, linux-mips,
linux-kernel, linuxppc-dev, dri-devel, etnaviv, linux-arm-kernel,
linux-samsung-soc, intel-gfx, linux-arm-msm, freedreno, nouveau,
linux-rockchip, linux-tegra, virtualization, intel-xe, xen-devel,
linux-fbdev, linux-aio, linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <akaJx8Zt8kazlrjq@lucifer>
On 2026/7/3 00:07, Lorenzo Stoakes wrote:
> On Thu, Jul 02, 2026 at 09:49:47PM +0800, Lance Yang wrote:
>>
>> On Mon, Jun 29, 2026 at 08:25:36PM +0100, Lorenzo Stoakes wrote:
>>> Replace use of the legacy vm_flags_t flags with vma_flags_t values
>>> throughout the mremap logic.
>>>
>>> Additionally update comments to reflect the changes to be consistent.
>>>
>>> No functional change intended.
>>>
>>> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
>>> ---
>>
>> The vm_flags_set() cases below spell out vma_start_write(), but the
>> vm_flags_clear() cases don't?
>
> Yep as I said elsewhere, implicitly taking the lock is terrible and me doing
> this is completely on purpose to get rid of that :)
>
> But I haven't been clear enough clearly, so I should put the argument as to why
> that's ok in the commit message.
>
> Will do so on respin.
Makes sense, thanks for spelling it out! A short changelog note
should clear it up for me :D
[...]
^ permalink raw reply
* Re: [PATCH 13/13] mm/mremap: convert mremap code to use vma_flags_t
From: Lorenzo Stoakes @ 2026-07-02 16:31 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, tsbogend, maddy, mpe, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, l.stach, inki.dae, sw0312.kim,
kyungmin.park, krzk, peter.griffin, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, robin.clark, lumag, lyude, dakr,
tomi.valkeinen, hjc, heiko, andy.yan, thierry.reding, mperttunen,
jonathanh, kraxel, dmitry.osipenko, zack.rusin, matthew.brost,
thomas.hellstrom, oleksandr_andrushchenko, deller, bcrl, viro,
brauner, muchun.song, osalvador, david, ziy, baolin.wang, liam,
npache, ryan.roberts, dev.jain, baohua, hughd, vbabka, rppt,
surenb, mhocko, jannh, pfalcato, kees, perex, tiwai, linux-mips,
linux-kernel, linuxppc-dev, dri-devel, etnaviv, linux-arm-kernel,
linux-samsung-soc, intel-gfx, linux-arm-msm, freedreno, nouveau,
linux-rockchip, linux-tegra, virtualization, intel-xe, xen-devel,
linux-fbdev, linux-aio, linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <2f36a2da-0686-485f-b4b9-ae699bef4fd4@linux.dev>
On Fri, Jul 03, 2026 at 12:17:29AM +0800, Lance Yang wrote:
>
>
> On 2026/7/3 00:07, Lorenzo Stoakes wrote:
> > On Thu, Jul 02, 2026 at 09:49:47PM +0800, Lance Yang wrote:
> > >
> > > On Mon, Jun 29, 2026 at 08:25:36PM +0100, Lorenzo Stoakes wrote:
> > > > Replace use of the legacy vm_flags_t flags with vma_flags_t values
> > > > throughout the mremap logic.
> > > >
> > > > Additionally update comments to reflect the changes to be consistent.
> > > >
> > > > No functional change intended.
> > > >
> > > > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> > > > ---
> > >
> > > The vm_flags_set() cases below spell out vma_start_write(), but the
> > > vm_flags_clear() cases don't?
> >
> > Yep as I said elsewhere, implicitly taking the lock is terrible and me doing
> > this is completely on purpose to get rid of that :)
> >
> > But I haven't been clear enough clearly, so I should put the argument as to why
> > that's ok in the commit message.
> >
> > Will do so on respin.
>
> Makes sense, thanks for spelling it out! A short changelog note
> should clear it up for me :D
Yeah absolutely, that's necessary and was an oversight on my part, will correct!
Thanks for your great review here, much appreciated! :)
>
> [...]
Cheers, Lorenzo
^ permalink raw reply
* RE: [PATCH v5 01/51] x86/apic: Provide helpers to set local APIC timer period in hz and khz
From: Michael Kelley @ 2026-07-02 17:47 UTC (permalink / raw)
To: Sean Christopherson, Jonathan Corbet, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, Kiryl Shutsemau, Rick Edgecombe, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Ajay Kaher,
Alexey Makhalov, Jan Kiszka, Andy Lutomirski, Peter Zijlstra,
Juergen Gross, Daniel Lezcano, John Stultz
Cc: Shuah Khan, H. Peter Anvin, Vitaly Kuznetsov,
Broadcom internal kernel review list, Boris Ostrovsky,
Stephen Boyd, linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
xen-devel@lists.xenproject.org, Tom Lendacky, Nikunj A Dadhania,
David Woodhouse, David Woodhouse, Michael Kelley, Thomas Gleixner
In-Reply-To: <20260701193212.749551-2-seanjc@google.com>
From: Sean Christopherson <seanjc@google.com> Sent: Wednesday, July 1, 2026 12:31 PM
>
> Add and use APIs to set the local APIC timer period instead of open coding
> the subtle HZ math in a all external callers, and make lapic_timer_period
Spurious word "a".
> local to apic.c. Provide APIs to specify the frequency in both hertz and
> kilohertz so that Hyper-V and VMware code aren't forced to lose precision.
>
> Opportunistically use mul_u64_u32_div() to harden against the possibility
> that the period in Khz is greater than 4294967, i.e. if the APIC timer runs
> at ~4.29 GHz. As pointed out by Sashiko, 4294968 * 1000 == 0x1_000002c0,
> and thus a Khz period of 4294968 would silently overflow the 32-bit
> unsigned integer used by most callers.
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
> arch/x86/include/asm/apic.h | 3 ++-
> arch/x86/kernel/apic/apic.c | 12 +++++++++++-
> arch/x86/kernel/cpu/mshyperv.c | 5 +----
> arch/x86/kernel/cpu/vmware.c | 4 +---
> arch/x86/kernel/jailhouse.c | 2 +-
> arch/x86/kernel/tsc.c | 2 +-
> arch/x86/kernel/tsc_msr.c | 2 +-
> 7 files changed, 18 insertions(+), 12 deletions(-)
>
> diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
> index 9cd493d467d4..cd84a94688a2 100644
> --- a/arch/x86/include/asm/apic.h
> +++ b/arch/x86/include/asm/apic.h
> @@ -63,7 +63,6 @@ extern int apic_verbosity;
> extern int local_apic_timer_c2_ok;
>
> extern bool apic_is_disabled;
> -extern unsigned int lapic_timer_period;
>
> extern enum apic_intr_mode_id apic_intr_mode;
> enum apic_intr_mode_id {
> @@ -138,6 +137,8 @@ void register_lapic_address(unsigned long address);
> extern void setup_boot_APIC_clock(void);
> extern void setup_secondary_APIC_clock(void);
> extern void lapic_update_tsc_freq(void);
> +extern void apic_set_timer_period_hz(u64 period_hz, const char *source);
> +extern void apic_set_timer_period_khz(u64 period_khz, const char *source);
>
> #ifdef CONFIG_X86_64
> static inline bool apic_force_enable(unsigned long addr)
> diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
> index aa1e19979aa8..8d3d930576fd 100644
> --- a/arch/x86/kernel/apic/apic.c
> +++ b/arch/x86/kernel/apic/apic.c
> @@ -176,7 +176,7 @@ static struct resource lapic_resource = {
> };
>
> /* Measured in ticks per HZ. */
> -unsigned int lapic_timer_period = 0;
> +static unsigned int lapic_timer_period;
>
> static void apic_pm_activate(void);
>
> @@ -796,6 +796,16 @@ bool __init apic_needs_pit(void)
> return lapic_timer_period == 0;
> }
>
> +void apic_set_timer_period_khz(u64 period_khz, const char *source)
> +{
> + lapic_timer_period = mul_u64_u32_div(period_khz, 1000, HZ);
> +}
> +
> +void apic_set_timer_period_hz(u64 period_hz, const char *source)
> +{
> + lapic_timer_period = div_u64(period_hz, HZ);
> +}
A string "source" argument is passed in, but not used. Is there an
envisioned future use? Also, this function doesn't output a pr_info()
message like the existing Hyper-V and VMware code does. I don't
know that the message is all that useful, though I do remember
one case where I was debugging some clock/timer issue when I
looked at it.
Michael
> +
> static int __init calibrate_APIC_clock(void)
> {
> struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
> diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
> index 185d4f677ec0..87beecec76f0 100644
> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
> @@ -646,10 +646,7 @@ static void __init ms_hyperv_init_platform(void)
> u64 hv_lapic_frequency;
>
> rdmsrq(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency);
> - hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ);
> - lapic_timer_period = hv_lapic_frequency;
> - pr_info("Hyper-V: LAPIC Timer Frequency: %#x\n",
> - lapic_timer_period);
> + apic_set_timer_period_hz(hv_lapic_frequency, "Hyper-V hypervisor");
> }
>
> register_nmi_handler(NMI_UNKNOWN, hv_nmi_unknown, NMI_FLAG_FIRST,
> diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
> index 34b73573b108..36f779dd311d 100644
> --- a/arch/x86/kernel/cpu/vmware.c
> +++ b/arch/x86/kernel/cpu/vmware.c
> @@ -424,9 +424,7 @@ static void __init vmware_platform_setup(void)
>
> #ifdef CONFIG_X86_LOCAL_APIC
> /* Skip lapic calibration since we know the bus frequency. */
> - lapic_timer_period = ecx / HZ;
> - pr_info("Host bus clock speed read from hypervisor : %u Hz\n",
> - ecx);
> + apic_set_timer_period_hz(ecx, "VMware hypervisor");
> #endif
> } else {
> pr_warn("Failed to get TSC freq from the hypervisor\n");
> diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c
> index f58ce9220e0f..f2d4ef89c085 100644
> --- a/arch/x86/kernel/jailhouse.c
> +++ b/arch/x86/kernel/jailhouse.c
> @@ -65,7 +65,7 @@ static void jailhouse_get_wallclock(struct timespec64 *now)
>
> static void __init jailhouse_timer_init(void)
> {
> - lapic_timer_period = setup_data.v1.apic_khz * (1000 / HZ);
> + apic_set_timer_period_khz(setup_data.v1.apic_khz, "Jailhouse hypervisor");
> }
>
> static unsigned long jailhouse_get_tsc(void)
> diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
> index ce10ae4b298b..f9ecc9256863 100644
> --- a/arch/x86/kernel/tsc.c
> +++ b/arch/x86/kernel/tsc.c
> @@ -717,7 +717,7 @@ unsigned long native_calibrate_tsc(void)
> * lapic_timer_period here to avoid having to calibrate the APIC
> * timer later.
> */
> - lapic_timer_period = crystal_khz * 1000 / HZ;
> + apic_set_timer_period_khz(crystal_khz, "CPUID 0x15/0x16");
> #endif
>
> return crystal_khz * ebx_numerator / eax_denominator;
> diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c
> index 48e6cc1cb017..7e990871e041 100644
> --- a/arch/x86/kernel/tsc_msr.c
> +++ b/arch/x86/kernel/tsc_msr.c
> @@ -211,7 +211,7 @@ unsigned long cpu_khz_from_msr(void)
> pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index);
>
> #ifdef CONFIG_X86_LOCAL_APIC
> - lapic_timer_period = (freq * 1000) / HZ;
> + apic_set_timer_period_khz(freq, "MSR_FSB_FREQ");
> #endif
>
> /*
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>
^ permalink raw reply
* RE: [PATCH v5 11/51] x86/tsc: Add dedicated hypervisor hooks for getting known TSC/CPU frequencies
From: Michael Kelley @ 2026-07-02 17:47 UTC (permalink / raw)
To: Sean Christopherson, Jonathan Corbet, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, Kiryl Shutsemau, Rick Edgecombe, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Ajay Kaher,
Alexey Makhalov, Jan Kiszka, Andy Lutomirski, Peter Zijlstra,
Juergen Gross, Daniel Lezcano, John Stultz
Cc: Shuah Khan, H. Peter Anvin, Vitaly Kuznetsov,
Broadcom internal kernel review list, Boris Ostrovsky,
Stephen Boyd, linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
xen-devel@lists.xenproject.org, Tom Lendacky, Nikunj A Dadhania,
David Woodhouse, David Woodhouse, Michael Kelley, Thomas Gleixner
In-Reply-To: <20260701193212.749551-12-seanjc@google.com>
From: Sean Christopherson <seanjc@google.com> Sent: Wednesday, July 1, 2026 12:32 PM
>
> Add dedicated hypervisor hooks for getting known TSC/CPU frequencies
> instead of overriding seemingly generic platform hooks, and explicitly
> priotize hypervisor-provided frequencies over native methods, but do NOT
s/priotize/prioritize/
> clobber the frequency obtained from trusted firmware. While shuffling the
> hooks around is arguably "six of one, half dozen of the other", scoping
> them to x86_hyper_init makes their purpose more obvious, and allows for
> explicitly defining the priority of sources (as is done here).
>
> As is already done when trusted firmware provides the TSC frequency, ignore
Word "ignore" is duplicated.
> ignore tsc_early_khz if the exact TSC frequency was obtained from the
> hypervisor, as attempting to refine the TSC frequency when running in a VM
> is all but guaranteed to cause problems sooner or later due to the
> calibration sources being emulated devices in the vast majority of setups.
>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
For the Hyper-V changes,
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
> ---
> .../admin-guide/kernel-parameters.txt | 3 +-
> arch/x86/include/asm/acrn.h | 5 ----
> arch/x86/include/asm/x86_init.h | 4 +++
> arch/x86/kernel/cpu/acrn.c | 10 +++++--
> arch/x86/kernel/cpu/mshyperv.c | 6 ++--
> arch/x86/kernel/cpu/vmware.c | 8 ++---
> arch/x86/kernel/jailhouse.c | 6 ++--
> arch/x86/kernel/kvmclock.c | 6 ++--
> arch/x86/kernel/tsc.c | 29 ++++++++++++++-----
> arch/x86/xen/time.c | 4 +--
> 10 files changed, 50 insertions(+), 31 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-
> guide/kernel-parameters.txt
> index 490e6aa72fc2..a387bb2c47e2 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -7948,7 +7948,8 @@ Kernel parameters
>
> Note, tsc_early_khz is ignored if the TSC frequency is
> provided by trusted firmware when running as an SNP or
> - TDX guest.
> + TDX guest, or when the hypervisor provides the exact
> + frequency via a paravirtual interface.
>
> tsx= [X86] Control Transactional Synchronization
> Extensions (TSX) feature in Intel processors that
> diff --git a/arch/x86/include/asm/acrn.h b/arch/x86/include/asm/acrn.h
> index db42b477c41d..a892179c61c6 100644
> --- a/arch/x86/include/asm/acrn.h
> +++ b/arch/x86/include/asm/acrn.h
> @@ -32,11 +32,6 @@ static inline u32 acrn_cpuid_base(void)
> return 0;
> }
>
> -static inline unsigned long acrn_get_tsc_khz(void)
> -{
> - return cpuid_eax(ACRN_CPUID_TIMING_INFO);
> -}
> -
> /*
> * Hypercalls for ACRN
> *
> diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
> index 953d3199408a..0c89bf40f507 100644
> --- a/arch/x86/include/asm/x86_init.h
> +++ b/arch/x86/include/asm/x86_init.h
> @@ -123,6 +123,8 @@ struct x86_init_pci {
> * @msi_ext_dest_id: MSI supports 15-bit APIC IDs
> * @init_mem_mapping: setup early mappings during init_mem_mapping()
> * @init_after_bootmem: guest init after boot allocator is finished
> + * @get_tsc_khz: get the TSC frequency (returns 0 if frequency is unknown)
> + * @get_cpu_khz: get the CPU frequency (returns 0 if frequency is unknown)
> */
> struct x86_hyper_init {
> void (*init_platform)(void);
> @@ -131,6 +133,8 @@ struct x86_hyper_init {
> bool (*msi_ext_dest_id)(void);
> void (*init_mem_mapping)(void);
> void (*init_after_bootmem)(void);
> + unsigned int (*get_tsc_khz)(void);
> + unsigned int (*get_cpu_khz)(void);
> };
>
> /**
> diff --git a/arch/x86/kernel/cpu/acrn.c b/arch/x86/kernel/cpu/acrn.c
> index dc119af83524..ad8f2da8003b 100644
> --- a/arch/x86/kernel/cpu/acrn.c
> +++ b/arch/x86/kernel/cpu/acrn.c
> @@ -24,13 +24,15 @@ static u32 __init acrn_detect(void)
> return acrn_cpuid_base();
> }
>
> +static unsigned int __init acrn_get_tsc_khz(void)
> +{
> + return cpuid_eax(ACRN_CPUID_TIMING_INFO);
> +}
> +
> static void __init acrn_init_platform(void)
> {
> /* Install system interrupt handler for ACRN hypervisor callback */
> sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_acrn_hv_callback);
> -
> - x86_platform.calibrate_tsc = acrn_get_tsc_khz;
> - x86_platform.calibrate_cpu = acrn_get_tsc_khz;
> }
>
> static bool acrn_x2apic_available(void)
> @@ -78,4 +80,6 @@ const __initconst struct hypervisor_x86 x86_hyper_acrn = {
> .type = X86_HYPER_ACRN,
> .init.init_platform = acrn_init_platform,
> .init.x2apic_available = acrn_x2apic_available,
> + .init.get_tsc_khz = acrn_get_tsc_khz,
> + .init.get_cpu_khz = acrn_get_tsc_khz,
> };
> diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
> index 87beecec76f0..f9bc1c2d8c93 100644
> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
> @@ -395,7 +395,7 @@ static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs)
> }
> #endif
>
> -static unsigned long hv_get_tsc_khz(void)
> +static unsigned int __init hv_get_tsc_khz(void)
> {
> unsigned long freq;
>
> @@ -573,8 +573,8 @@ static void __init ms_hyperv_init_platform(void)
>
> if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
> ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
> - x86_platform.calibrate_tsc = hv_get_tsc_khz;
> - x86_platform.calibrate_cpu = hv_get_tsc_khz;
> + x86_init.hyper.get_tsc_khz = hv_get_tsc_khz;
> + x86_init.hyper.get_cpu_khz = hv_get_tsc_khz;
> setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> }
>
> diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
> index 13b97265c535..3cb473cae462 100644
> --- a/arch/x86/kernel/cpu/vmware.c
> +++ b/arch/x86/kernel/cpu/vmware.c
> @@ -64,7 +64,7 @@ struct vmware_steal_time {
> u64 reserved[7];
> };
>
> -static unsigned long vmware_tsc_khz __ro_after_init;
> +static unsigned long vmware_tsc_khz __initdata;
> static u8 vmware_hypercall_mode __ro_after_init;
>
> unsigned long vmware_hypercall_slow(unsigned long cmd,
> @@ -137,7 +137,7 @@ static inline int __vmware_platform(void)
> return eax != UINT_MAX && ebx == VMWARE_HYPERVISOR_MAGIC;
> }
>
> -static unsigned long vmware_get_tsc_khz(void)
> +static unsigned int __init vmware_get_tsc_khz(void)
> {
> return vmware_tsc_khz;
> }
> @@ -419,8 +419,8 @@ static void __init vmware_platform_setup(void)
> }
>
> vmware_tsc_khz = tsc_khz;
> - x86_platform.calibrate_tsc = vmware_get_tsc_khz;
> - x86_platform.calibrate_cpu = vmware_get_tsc_khz;
> + x86_init.hyper.get_tsc_khz = vmware_get_tsc_khz;
> + x86_init.hyper.get_cpu_khz = vmware_get_tsc_khz;
>
> /* Skip lapic calibration since we know the bus frequency. */
> apic_set_timer_period_hz(ecx, "VMware hypervisor");
> diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c
> index f2d4ef89c085..e24c05ab4fae 100644
> --- a/arch/x86/kernel/jailhouse.c
> +++ b/arch/x86/kernel/jailhouse.c
> @@ -68,7 +68,7 @@ static void __init jailhouse_timer_init(void)
> apic_set_timer_period_khz(setup_data.v1.apic_khz, "Jailhouse hypervisor");
> }
>
> -static unsigned long jailhouse_get_tsc(void)
> +static unsigned int __init jailhouse_get_tsc(void)
> {
> return precalibrated_tsc_khz;
> }
> @@ -210,8 +210,6 @@ static void __init jailhouse_init_platform(void)
> x86_init.mpparse.parse_smp_cfg = jailhouse_parse_smp_config;
> x86_init.pci.arch_init = jailhouse_pci_arch_init;
>
> - x86_platform.calibrate_cpu = jailhouse_get_tsc;
> - x86_platform.calibrate_tsc = jailhouse_get_tsc;
> x86_platform.get_wallclock = jailhouse_get_wallclock;
> x86_platform.legacy.rtc = 0;
> x86_platform.legacy.warm_reset = 0;
> @@ -293,5 +291,7 @@ const struct hypervisor_x86 x86_hyper_jailhouse __refconst = {
> .detect = jailhouse_detect,
> .init.init_platform = jailhouse_init_platform,
> .init.x2apic_available = jailhouse_x2apic_available,
> + .init.get_tsc_khz = jailhouse_get_tsc,
> + .init.get_cpu_khz = jailhouse_get_tsc,
> .ignore_nopv = true,
> };
> diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
> index cb3d0ca1fa22..4f8299303a19 100644
> --- a/arch/x86/kernel/kvmclock.c
> +++ b/arch/x86/kernel/kvmclock.c
> @@ -136,7 +136,7 @@ static inline void kvm_sched_clock_init(bool stable)
> * poll of guests can be running and trouble each other. So we preset
> * lpj here
> */
> -static unsigned long kvm_get_tsc_khz(void)
> +static unsigned int __init kvm_get_tsc_khz(void)
> {
> setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> return pvclock_tsc_khz(this_cpu_pvti());
> @@ -343,8 +343,8 @@ void __init kvmclock_init(void)
> flags = pvclock_read_flags(&hv_clock_boot[0].pvti);
> kvm_sched_clock_init(flags & PVCLOCK_TSC_STABLE_BIT);
>
> - x86_platform.calibrate_tsc = kvm_get_tsc_khz;
> - x86_platform.calibrate_cpu = kvm_get_tsc_khz;
> + x86_init.hyper.get_tsc_khz = kvm_get_tsc_khz;
> + x86_init.hyper.get_cpu_khz = kvm_get_tsc_khz;
> x86_platform.get_wallclock = kvm_get_wallclock;
> x86_platform.set_wallclock = kvm_set_wallclock;
> #ifdef CONFIG_X86_LOCAL_APIC
> diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
> index 86384a83a5f6..1dca9464b41c 100644
> --- a/arch/x86/kernel/tsc.c
> +++ b/arch/x86/kernel/tsc.c
> @@ -1451,13 +1451,17 @@ static int __init init_tsc_clocksource(void)
> device_initcall(init_tsc_clocksource);
>
> static bool __init determine_cpu_tsc_frequencies(bool early,
> + unsigned int known_cpu_khz,
> unsigned int known_tsc_khz)
> {
> /* Make sure that cpu and tsc are not already calibrated */
> WARN_ON(cpu_khz || tsc_khz);
>
> if (early) {
> - cpu_khz = x86_platform.calibrate_cpu();
> + if (known_cpu_khz)
> + cpu_khz = known_cpu_khz;
> + else
> + cpu_khz = x86_platform.calibrate_cpu();
> if (known_tsc_khz)
> tsc_khz = known_tsc_khz;
> else
> @@ -1514,7 +1518,7 @@ static void __init tsc_enable_sched_clock(void)
>
> void __init tsc_early_init(void)
> {
> - unsigned int known_tsc_khz = 0;
> + unsigned int known_cpu_khz = 0, known_tsc_khz = 0;
>
> if (!boot_cpu_has(X86_FEATURE_TSC))
> return;
> @@ -1522,22 +1526,33 @@ void __init tsc_early_init(void)
> if (is_early_uv_system())
> return;
>
> + if (x86_init.hyper.get_cpu_khz)
> + known_cpu_khz = x86_init.hyper.get_cpu_khz();
> +
> if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC))
> known_tsc_khz = snp_secure_tsc_init();
> else if (boot_cpu_has(X86_FEATURE_TDX_GUEST))
> known_tsc_khz = tdx_tsc_init();
>
> + /*
> + * If the TSC frequency wasn't provided by trusted firmware, try to get
> + * it from the hypervisor (which is untrusted when running as a CoCo guest).
> + */
> + if (!known_tsc_khz && x86_init.hyper.get_tsc_khz)
> + known_tsc_khz = x86_init.hyper.get_tsc_khz();
> +
> /*
> * Ignore the user-provided TSC frequency if the exact frequency was
> - * obtained from trusted firmware, as the user-provided frequency is
> - * intended as a "starting point", not a known, guaranteed frequency.
> + * obtained from trusted firmware or the hypervisor, as the user-
> + * provided frequency is intended as a "starting point", not a known,
> + * guaranteed frequency.
> */
> if (!known_tsc_khz)
> known_tsc_khz = tsc_early_khz;
> else if (tsc_early_khz)
> - pr_err("Ignoring 'tsc_early_khz' in favor of trusted firmware.\n");
> + pr_err("Ignoring 'tsc_early_khz' in favor of firmware/hypervisor.\n");
>
> - if (!determine_cpu_tsc_frequencies(true, known_tsc_khz))
> + if (!determine_cpu_tsc_frequencies(true, known_cpu_khz, known_tsc_khz))
> return;
> tsc_enable_sched_clock();
> }
> @@ -1558,7 +1573,7 @@ void __init tsc_init(void)
>
> if (!tsc_khz) {
> /* We failed to determine frequencies earlier, try again */
> - if (!determine_cpu_tsc_frequencies(false, 0)) {
> + if (!determine_cpu_tsc_frequencies(false, 0, 0)) {
> mark_tsc_unstable("could not calculate TSC khz");
> setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
> return;
> diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
> index d62c14334b35..1adb44fdddb2 100644
> --- a/arch/x86/xen/time.c
> +++ b/arch/x86/xen/time.c
> @@ -38,7 +38,7 @@
> static u64 xen_sched_clock_offset __read_mostly;
>
> /* Get the TSC speed from Xen */
> -static unsigned long xen_tsc_khz(void)
> +static unsigned int __init xen_tsc_khz(void)
> {
> struct pvclock_vcpu_time_info *info =
> &HYPERVISOR_shared_info->vcpu_info[0].time;
> @@ -569,7 +569,7 @@ static void __init xen_init_time_common(void)
> static_call_update(pv_steal_clock, xen_steal_clock);
> paravirt_set_sched_clock(xen_sched_clock);
>
> - x86_platform.calibrate_tsc = xen_tsc_khz;
> + x86_init.hyper.get_tsc_khz = xen_tsc_khz;
> x86_platform.get_wallclock = xen_get_wallclock;
> }
>
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>
^ permalink raw reply
* RE: [PATCH v5 14/51] x86/tsc: Consolidate forcing of X86_FEATURE_TSC_KNOWN_FREQ for PV code
From: Michael Kelley @ 2026-07-02 17:47 UTC (permalink / raw)
To: Sean Christopherson, Jonathan Corbet, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, Kiryl Shutsemau, Rick Edgecombe, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Ajay Kaher,
Alexey Makhalov, Jan Kiszka, Andy Lutomirski, Peter Zijlstra,
Juergen Gross, Daniel Lezcano, John Stultz
Cc: Shuah Khan, H. Peter Anvin, Vitaly Kuznetsov,
Broadcom internal kernel review list, Boris Ostrovsky,
Stephen Boyd, linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
xen-devel@lists.xenproject.org, Tom Lendacky, Nikunj A Dadhania,
David Woodhouse, David Woodhouse, Michael Kelley, Thomas Gleixner
In-Reply-To: <20260701193212.749551-15-seanjc@google.com>
From: Sean Christopherson <seanjc@google.com> Sent: Wednesday, July 1, 2026 12:32 PM
>
> Now that all paravirt code that explicitly specifies the TSC frequency
> also sets X86_FEATURE_TSC_KNOWN_FREQ, replace all of the one-off code
> and simply set X86_FEATURE_TSC_KNOWN_FREQ if the TSC frequency is known.
>
> Do NOT force set TSC_KNOWN_FREQ if the "known" TSC frequency was provided
> by the user. Per commit bd35c77e32e4 ("x86/tsc: Add tsc_early_khz command
> line parameter"), one of the goals of the param is to allow the refined
> calibration work "to do meaningful error checking".
>
> No functional change intended.
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
For the Hyper-V changes,
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
> ---
> arch/x86/coco/sev/core.c | 1 -
> arch/x86/coco/tdx/tdx.c | 1 -
> arch/x86/kernel/cpu/acrn.c | 1 -
> arch/x86/kernel/cpu/mshyperv.c | 1 -
> arch/x86/kernel/cpu/vmware.c | 2 --
> arch/x86/kernel/jailhouse.c | 1 -
> arch/x86/kernel/kvmclock.c | 1 -
> arch/x86/kernel/tsc.c | 13 ++++++++++---
> arch/x86/xen/time.c | 1 -
> 9 files changed, 10 insertions(+), 12 deletions(-)
>
> diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
> index bc5ae9ef74da..72313b36b6f5 100644
> --- a/arch/x86/coco/sev/core.c
> +++ b/arch/x86/coco/sev/core.c
> @@ -2027,7 +2027,6 @@ unsigned int __init snp_secure_tsc_init(void)
>
> secrets = (__force struct snp_secrets_page *)mem;
>
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
>
> rdmsrq(MSR_AMD64_GUEST_TSC_FREQ, tsc_freq_mhz);
> diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
> index ae2d35f2ef33..94682aca188b 100644
> --- a/arch/x86/coco/tdx/tdx.c
> +++ b/arch/x86/coco/tdx/tdx.c
> @@ -1205,7 +1205,6 @@ unsigned int __init tdx_tsc_init(void)
>
> /* TSC is the only reliable clock in TDX guest */
> setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
>
> return info.crystal_khz * info.numerator / info.denominator;
> }
> diff --git a/arch/x86/kernel/cpu/acrn.c b/arch/x86/kernel/cpu/acrn.c
> index 3818f6ae0629..dc71a6fdd461 100644
> --- a/arch/x86/kernel/cpu/acrn.c
> +++ b/arch/x86/kernel/cpu/acrn.c
> @@ -40,7 +40,6 @@ static void __init acrn_init_platform(void)
> if (acrn_tsc_khz_cpuid) {
> x86_init.hyper.get_tsc_khz = acrn_get_tsc_khz;
> x86_init.hyper.get_cpu_khz = acrn_get_tsc_khz;
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> }
> }
>
> diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
> index f9bc1c2d8c93..e03c69a4db33 100644
> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
> @@ -575,7 +575,6 @@ static void __init ms_hyperv_init_platform(void)
> ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
> x86_init.hyper.get_tsc_khz = hv_get_tsc_khz;
> x86_init.hyper.get_cpu_khz = hv_get_tsc_khz;
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> }
>
> if (ms_hyperv.priv_high & HV_ISOLATION) {
> diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
> index 3cb473cae462..0a3bd90576d4 100644
> --- a/arch/x86/kernel/cpu/vmware.c
> +++ b/arch/x86/kernel/cpu/vmware.c
> @@ -390,8 +390,6 @@ static void __init vmware_set_capabilities(void)
> {
> setup_force_cpu_cap(X86_FEATURE_CONSTANT_TSC);
> setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
> - if (vmware_tsc_khz)
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMCALL)
> setup_force_cpu_cap(X86_FEATURE_VMCALL);
> else if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMMCALL)
> diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c
> index e24c05ab4fae..ff173052cdce 100644
> --- a/arch/x86/kernel/jailhouse.c
> +++ b/arch/x86/kernel/jailhouse.c
> @@ -255,7 +255,6 @@ static void __init jailhouse_init_platform(void)
> pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport);
>
> precalibrated_tsc_khz = setup_data.v1.tsc_khz;
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
>
> pci_probe = 0;
>
> diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
> index 4f8299303a19..35a879d33e9e 100644
> --- a/arch/x86/kernel/kvmclock.c
> +++ b/arch/x86/kernel/kvmclock.c
> @@ -138,7 +138,6 @@ static inline void kvm_sched_clock_init(bool stable)
> */
> static unsigned int __init kvm_get_tsc_khz(void)
> {
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> return pvclock_tsc_khz(this_cpu_pvti());
> }
>
> diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
> index 1dca9464b41c..676910292af7 100644
> --- a/arch/x86/kernel/tsc.c
> +++ b/arch/x86/kernel/tsc.c
> @@ -1541,11 +1541,18 @@ void __init tsc_early_init(void)
> if (!known_tsc_khz && x86_init.hyper.get_tsc_khz)
> known_tsc_khz = x86_init.hyper.get_tsc_khz();
>
> + /*
> + * Mark the TSC frequency as known if it was obtained from a hypervisor
> + * or trusted firmware.
> + */
> + if (known_tsc_khz)
> + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> +
> /*
> * Ignore the user-provided TSC frequency if the exact frequency was
> - * obtained from trusted firmware or the hypervisor, as the user-
> - * provided frequency is intended as a "starting point", not a known,
> - * guaranteed frequency.
> + * obtained from trusted firmware or the hypervisor, and don't mark the
> + * frequency as known, as the user-provided frequency is intended as a
> + * "starting point", not a known, guaranteed frequency
> */
> if (!known_tsc_khz)
> known_tsc_khz = tsc_early_khz;
> diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
> index 1adb44fdddb2..487ad838c441 100644
> --- a/arch/x86/xen/time.c
> +++ b/arch/x86/xen/time.c
> @@ -43,7 +43,6 @@ static unsigned int __init xen_tsc_khz(void)
> struct pvclock_vcpu_time_info *info =
> &HYPERVISOR_shared_info->vcpu_info[0].time;
>
> - setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
> return pvclock_tsc_khz(info);
> }
>
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>
^ permalink raw reply
* RE: [PATCH v5 36/51] x86/paravirt: Pass sched_clock save/restore helpers during registration
From: Michael Kelley @ 2026-07-02 17:48 UTC (permalink / raw)
To: Sean Christopherson, Jonathan Corbet, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, Kiryl Shutsemau, Rick Edgecombe, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Ajay Kaher,
Alexey Makhalov, Jan Kiszka, Andy Lutomirski, Peter Zijlstra,
Juergen Gross, Daniel Lezcano, John Stultz
Cc: Shuah Khan, H. Peter Anvin, Vitaly Kuznetsov,
Broadcom internal kernel review list, Boris Ostrovsky,
Stephen Boyd, linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
xen-devel@lists.xenproject.org, Tom Lendacky, Nikunj A Dadhania,
David Woodhouse, David Woodhouse, Michael Kelley, Thomas Gleixner
In-Reply-To: <20260701193212.749551-37-seanjc@google.com>
From: Sean Christopherson <seanjc@google.com> Sent: Wednesday, July 1, 2026 12:32 PM
>
> Pass in a PV clock's save/restore helpers when configuring sched_clock
> instead of relying on each PV clock to manually set the save/restore hooks.
> In addition to bringing sanity to the code, this will allow gracefully
> "rejecting" a PV sched_clock, e.g. when running as a CoCo guest that has
> access to a "secure" TSC.
>
> No functional change intended.
>
> Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
For the Hyper-V changes,
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
> ---
> arch/x86/include/asm/timer.h | 9 ++++++---
> arch/x86/kernel/cpu/vmware.c | 8 +++-----
> arch/x86/kernel/kvmclock.c | 6 +++---
> arch/x86/kernel/tsc.c | 5 ++++-
> arch/x86/xen/time.c | 5 ++---
> drivers/clocksource/hyperv_timer.c | 6 ++----
> 6 files changed, 20 insertions(+), 19 deletions(-)
>
> diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h
> index fe41d40a9ae6..e97cd1ae03d1 100644
> --- a/arch/x86/include/asm/timer.h
> +++ b/arch/x86/include/asm/timer.h
> @@ -14,11 +14,14 @@ extern int no_timer_check;
> extern bool using_native_sched_clock(void);
>
> #ifdef CONFIG_PARAVIRT
> -void __paravirt_set_sched_clock(u64 (*func)(void), bool stable);
> +void __paravirt_set_sched_clock(u64 (*func)(void), bool stable,
> + void (*save)(void), void (*restore)(void));
>
> -static inline void paravirt_set_sched_clock(u64 (*func)(void))
> +static inline void paravirt_set_sched_clock(u64 (*func)(void),
> + void (*save)(void),
> + void (*restore)(void))
> {
> - __paravirt_set_sched_clock(func, true);
> + __paravirt_set_sched_clock(func, true, save, restore);
> }
> #endif
>
> diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
> index 5c1ccaf4a25e..232255279a6e 100644
> --- a/arch/x86/kernel/cpu/vmware.c
> +++ b/arch/x86/kernel/cpu/vmware.c
> @@ -347,11 +347,9 @@ static void __init vmware_paravirt_ops_setup(void)
>
> vmware_cyc2ns_setup();
>
> - if (vmw_sched_clock) {
> - paravirt_set_sched_clock(vmware_sched_clock);
> - x86_platform.save_sched_clock_state = x86_init_noop;
> - x86_platform.restore_sched_clock_state = x86_init_noop;
> - }
> + if (vmw_sched_clock)
> + paravirt_set_sched_clock(vmware_sched_clock,
> + x86_init_noop, x86_init_noop);
>
> if (vmware_is_stealclock_available()) {
> has_steal_clock = true;
> diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
> index 07e875738c39..5b9955343199 100644
> --- a/arch/x86/kernel/kvmclock.c
> +++ b/arch/x86/kernel/kvmclock.c
> @@ -158,7 +158,9 @@ static void kvm_restore_sched_clock_state(void)
> static inline void kvm_sched_clock_init(bool stable)
> {
> kvm_sched_clock_offset = kvm_clock_read();
> - __paravirt_set_sched_clock(kvm_sched_clock_read, stable);
> + __paravirt_set_sched_clock(kvm_sched_clock_read, stable,
> + kvm_save_sched_clock_state,
> + kvm_restore_sched_clock_state);
>
> pr_info("kvm-clock: using sched offset of %llu cycles",
> kvm_sched_clock_offset);
> @@ -367,8 +369,6 @@ void __init kvmclock_init(bool prefer_tsc)
> #ifdef CONFIG_SMP
> x86_cpuinit.early_percpu_clock_init = kvm_setup_secondary_clock;
> #endif
> - x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
> - x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
> kvm_get_preset_lpj();
>
> /*
> diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
> index 7473dcab4775..83353d643150 100644
> --- a/arch/x86/kernel/tsc.c
> +++ b/arch/x86/kernel/tsc.c
> @@ -280,12 +280,15 @@ bool using_native_sched_clock(void)
> return static_call_query(pv_sched_clock) == native_sched_clock;
> }
>
> -void __paravirt_set_sched_clock(u64 (*func)(void), bool stable)
> +void __paravirt_set_sched_clock(u64 (*func)(void), bool stable,
> + void (*save)(void), void (*restore)(void))
> {
> if (!stable)
> clear_sched_clock_stable();
>
> static_call_update(pv_sched_clock, func);
> + x86_platform.save_sched_clock_state = save;
> + x86_platform.restore_sched_clock_state = restore;
> }
> #else
> u64 sched_clock_noinstr(void) __attribute__((alias("native_sched_clock")));
> diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
> index 477441752f40..8cd8bfaf1320 100644
> --- a/arch/x86/xen/time.c
> +++ b/arch/x86/xen/time.c
> @@ -566,13 +566,12 @@ static void __init xen_init_time_common(void)
> {
> xen_sched_clock_offset = xen_clocksource_read();
> static_call_update(pv_steal_clock, xen_steal_clock);
> - paravirt_set_sched_clock(xen_sched_clock);
> +
> /*
> * Xen has paravirtualized suspend/resume and so doesn't use the common
> * x86 sched_clock save/restore hooks.
> */
> - x86_platform.save_sched_clock_state = x86_init_noop;
> - x86_platform.restore_sched_clock_state = x86_init_noop;
> + paravirt_set_sched_clock(xen_sched_clock, x86_init_noop, x86_init_noop);
>
> x86_init.hyper.get_tsc_khz = xen_tsc_khz;
> x86_platform.get_wallclock = xen_get_wallclock;
> diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
> index 220668207d19..8ee7a9de0f4f 100644
> --- a/drivers/clocksource/hyperv_timer.c
> +++ b/drivers/clocksource/hyperv_timer.c
> @@ -570,10 +570,8 @@ static void hv_restore_sched_clock_state(void)
> static __always_inline void hv_setup_sched_clock(void *sched_clock)
> {
> /* We're on x86/x64 *and* using PV ops */
> - paravirt_set_sched_clock(sched_clock);
> -
> - x86_platform.save_sched_clock_state = hv_save_sched_clock_state;
> - x86_platform.restore_sched_clock_state = hv_restore_sched_clock_state;
> + paravirt_set_sched_clock(sched_clock, hv_save_sched_clock_state,
> + hv_restore_sched_clock_state);
> }
> #else /* !CONFIG_GENERIC_SCHED_CLOCK && !CONFIG_PARAVIRT */
> static __always_inline void hv_setup_sched_clock(void *sched_clock) {}
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>
^ permalink raw reply
* RE: [PATCH v5 47/51] x86/paravirt: Don't use a PV sched_clock in CoCo guests with trusted TSC
From: Michael Kelley @ 2026-07-02 17:48 UTC (permalink / raw)
To: Sean Christopherson, Jonathan Corbet, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, Kiryl Shutsemau, Rick Edgecombe, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Ajay Kaher,
Alexey Makhalov, Jan Kiszka, Andy Lutomirski, Peter Zijlstra,
Juergen Gross, Daniel Lezcano, John Stultz
Cc: Shuah Khan, H. Peter Anvin, Vitaly Kuznetsov,
Broadcom internal kernel review list, Boris Ostrovsky,
Stephen Boyd, linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
xen-devel@lists.xenproject.org, Tom Lendacky, Nikunj A Dadhania,
David Woodhouse, David Woodhouse, Michael Kelley, Thomas Gleixner
In-Reply-To: <20260701193212.749551-48-seanjc@google.com>
From: Sean Christopherson <seanjc@google.com> Sent: Wednesday, July 1, 2026 12:32 PM
>
> Silently ignore attempts to switch to a paravirt sched_clock when running
> as a CoCo guest with trusted TSC. In hand-wavy theory, a misbehaving
> hypervisor could attack the guest by manipulating the PV clock to affect
> guest scheduling in some weird and/or predictable way. More importantly,
> reading TSC on such platforms is faster than any PV clock, and sched_clock
> is all about speed.
>
> Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
> arch/x86/kernel/tsc.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
> index 012321fed5e5..a146fc7b5e74 100644
> --- a/arch/x86/kernel/tsc.c
> +++ b/arch/x86/kernel/tsc.c
> @@ -283,6 +283,15 @@ bool using_native_sched_clock(void)
> int __init __paravirt_set_sched_clock(u64 (*func)(void), bool stable,
> void (*save)(void), void (*restore)(void))
> {
> + /*
> + * Don't replace TSC with a PV clock when running as a CoCo guest and
> + * the TSC is secure/trusted; PV clocks are emulated by the hypervisor,
> + * which isn't in the guest's TCB.
> + */
> + if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC) ||
> + boot_cpu_has(X86_FEATURE_TDX_GUEST))
> + return -EPERM;
Do a pr_warn() in the error case? Your commit message says to
do the ignore silently, but I wonder if that's a good idea. At least
for Hyper-V, the error case shouldn't happen.
Michael
> +
> if (!stable)
> clear_sched_clock_stable();
>
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>
^ permalink raw reply
* Re: [PATCH v2 0/4] virtio_balloon: quiesce balloon work on device shutdown
From: Denis V. Lunev @ 2026-07-02 17:50 UTC (permalink / raw)
To: Denis V. Lunev, mst, david; +Cc: virtualization, linux-kernel
In-Reply-To: <20260624140846.2616797-1-den@openvz.org>
On 6/24/26 16:08, Denis V. Lunev wrote:
> This email originated from an IP that might not be authorized by the domain it was sent from.
> Do not click links or open attachments unless it is an email you expected to receive.
> Since commit 8bd2fa086a04 ("virtio: break and reset virtio devices on
> device_shutdown()") the virtio bus breaks and resets every virtio device
> during device_shutdown(), i.e. on reboot and kexec. virtio_balloon has no
> .shutdown of its own, so that generic path runs while the balloon's
> asynchronous work is still armed: the free page reporting worker, the
> inflate/deflate and stats workers, the OOM notifier and the free page
> shrinker.
>
> Once the device has been broken, virtqueue_add_inbuf() in
> virtballoon_free_page_report() returns -EIO and trips its WARN_ON_ONCE().
> On a kernel booted with panic_on_warn that turns an ordinary reboot into a
> fatal panic in the middle of device_shutdown(), so the machine never
> reaches the new kernel. The inflate/deflate and OOM paths do not warn but
> are no better off: they call wait_event(vb->acked, ...) and would block
> forever on a queue that can no longer complete.
>
> This was hit in the field as an intermittent failure of a virtualization
> cluster upgrade: guest storage nodes were rebooted via kexec into the new
> kernel, and the ones whose free page reporting happened to run during
> device_shutdown() panicked (the guests run with panic_on_warn) and never
> came back, stalling the rolling upgrade. The crash dump showed the WARN at
> virtio_balloon.c:216 in a page_reporting kworker, with all the balloon
> virtqueues already broken.
>
> Validated by churning balloon inflate/deflate from the host while
> kexec-rebooting the guest in a loop under panic_on_warn: the unpatched
> kernel reproduces the WARN within a couple of cycles, while the patched
> kernel survives many consecutive kexec cycles cleanly (12/12 in the final
> run, 0 WARNs). checkpatch is clean across the series.
>
> Changes in v2:
> - Add a virtio_device_shutdown() core helper and call it from the balloon
> .shutdown handler instead of open-coding break + synchronize_cbs + reset
> (David Hildenbrand).
> - New patch: make tell_host() warn and bail instead of hanging if a buffer
> add ever fails (David Hildenbrand); kept as a separate patch
> (Michael S. Tsirkin).
>
> v1: https://lore.kernel.org/all/20260622133715.3707707-1-den@openvz.org
>
> Denis V. Lunev (4):
> virtio: add virtio_device_shutdown() helper
> virtio_balloon: factor out virtballoon_quiesce()
> virtio_balloon: quiesce balloon work before device shutdown
> virtio_balloon: warn on failed buffer add in tell_host()
>
> drivers/virtio/virtio.c | 41 ++++++++++++++++++++++-----------
> drivers/virtio/virtio_balloon.c | 40 ++++++++++++++++++++++++--------
> include/linux/virtio.h | 1 +
> 3 files changed, 59 insertions(+), 23 deletions(-)
>
Hi, David!
Is this good to go in? I have not seen the confirmation that the
series is taken into your tree.
Thank you in advance,
Den
^ permalink raw reply
* [PATCH v3] drm/vblank: Don't arm vblank timer with invalid frame duration
From: Roman Ilin @ 2026-07-02 18:10 UTC (permalink / raw)
To: Thomas Zimmermann, Maarten Lankhorst, Maxime Ripard, David Airlie,
Simona Vetter
Cc: Louis Chauvet, Javier Martinez Canillas, Dmitry Osipenko,
dri-devel, virtualization, linux-kernel, Ville Syrjälä,
Thorsten Leemhuis, Peter Arnesen, Roman Ilin
In-Reply-To: <20260613224434.96501-1-me@romanilin.is>
When a CRTC's display mode carries a too small pixel clock,
drm_calc_timestamping_constants() computes a frame duration that
exceeds INT_MAX. drm_vblank_crtc.framedur_ns becomes negative.
drm_crtc_vblank_start_timer() then arms the vblank hrtimer with this
interval, after which vblank events are no longer delivered. Pending
page flips never complete and the display appears frozen.
This could be triggered on virtio-gpu guests that have dynamic resolution
enabled: when the SPICE agent or the X server resizes the output, it
submits a mode whose pixel clock is off by a factor of 1000, e.g.:
clock = 406 kHz, htotal = 3152, vtotal = 2148
framedur_ns = 3152 * 2148 * 1000000 / 406 = 16675852216 ns (~16.7 s)
16675852216 does not fit into an int and wraps to roughly -504000000.
ns_to_ktime() then yields a negative interval and the timer stops working.
Found by bisection, which pointed at commit a036f5fceedb ("drm/virtgpu:
Use vblank timer"). That commit merely made virtio-gpu use the vblank
timer and thereby exposed the pre-existing problem in the timer setup
added by commit 74afeb812850 ("drm/vblank: Add vblank timer").
To fix this, modify drm_calc_timestamping_constants() to use u64 for
calculations, check for INT_MAX overflows, and return an error code.
drm_crtc_vblank_start_timer() will then propagate the error, enabling
the driver to fall back to immediate vblank events. Valid modes are
unaffected, and the timer self-heals on the next mode with a sane clock.
Fixes: 74afeb812850 ("drm/vblank: Add vblank timer")
Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Roman Ilin <me@romanilin.is>
---
Changes in v3:
- Changed the WARN_ON_ONCE to drm_err_once
Notes:
drivers/gpu/drm/drm_vblank.c | 71 +++++++++++++++++++++++-------------
include/drm/drm_vblank.h | 4 +-
2 files changed, 48 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index f90fb2d13..629b9fcc7 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -631,42 +631,51 @@ EXPORT_SYMBOL(drm_crtc_vblank_waitqueue);
* drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from
* CRTC's true scanout timing, so they take things like panel scaling or
* other adjustments into account.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
*/
-void drm_calc_timestamping_constants(struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
+int drm_calc_timestamping_constants(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
unsigned int pipe = drm_crtc_index(crtc);
struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
- int linedur_ns = 0, framedur_ns = 0;
+ u64 linedur_ns, framedur_ns;
int dotclock = mode->crtc_clock;
+ unsigned int frame_size;
if (!drm_dev_has_vblank(dev))
- return;
+ return 0;
if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
- return;
+ return -EINVAL;
- /* Valid dotclock? */
- if (dotclock > 0) {
- int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
+ if (dotclock <= 0) {
+ drm_err(dev, "crtc %u: Can't calculate constants, dotclock = %d!\n",
+ crtc->base.id, dotclock);
+ goto error;
+ }
- /*
- * Convert scanline length in pixels and video
- * dot clock to line duration and frame duration
- * in nanoseconds:
- */
- linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
- framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
+ frame_size = (unsigned int)mode->crtc_htotal * (unsigned int)mode->crtc_vtotal;
- /*
- * Fields of interlaced scanout modes are only half a frame duration.
- */
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- framedur_ns /= 2;
- } else {
- drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n",
- crtc->base.id);
+ /*
+ * Convert scanline length in pixels and video dot clock to line duration
+ * and frame duration in nanoseconds.
+ */
+ linedur_ns = div_u64((u64)mode->crtc_htotal * 1000000, dotclock);
+ framedur_ns = div_u64((u64)frame_size * 1000000, dotclock);
+
+ /*
+ * Fields of interlaced scanout modes are only half a frame duration.
+ */
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ framedur_ns /= 2;
+
+ if (linedur_ns > INT_MAX || framedur_ns > INT_MAX) {
+ drm_dbg_kms(dev, "crtc %u: Can't calculate constants, mode clock too small!\n",
+ crtc->base.id);
+ goto error;
}
vblank->linedur_ns = linedur_ns;
@@ -678,7 +687,16 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
crtc->base.id, mode->crtc_htotal,
mode->crtc_vtotal, mode->crtc_vdisplay);
drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n",
- crtc->base.id, dotclock, framedur_ns, linedur_ns);
+ crtc->base.id, dotclock,
+ vblank->framedur_ns, vblank->linedur_ns);
+
+ return 0;
+
+error:
+ vblank->linedur_ns = 0;
+ vblank->framedur_ns = 0;
+ drm_mode_copy(&vblank->hwmode, mode);
+ return -EINVAL;
}
EXPORT_SYMBOL(drm_calc_timestamping_constants);
@@ -2221,6 +2239,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc)
struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer;
unsigned long flags;
+ int ret;
if (!vtimer->crtc) {
/*
@@ -2239,7 +2258,9 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc)
hrtimer_try_to_cancel(&vtimer->timer);
}
- drm_calc_timestamping_constants(crtc, &crtc->mode);
+ ret = drm_calc_timestamping_constants(crtc, &crtc->mode);
+ if (ret)
+ return ret;
spin_lock_irqsave(&vtimer->interval_lock, flags);
vtimer->interval = ns_to_ktime(vblank->framedur_ns);
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 2fcef9c0f..d99772dfa 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -311,8 +311,8 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc);
u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
void drm_crtc_vblank_restore(struct drm_crtc *crtc);
-void drm_calc_timestamping_constants(struct drm_crtc *crtc,
- const struct drm_display_mode *mode);
+int drm_calc_timestamping_constants(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode);
wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
u32 max_vblank_count);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v3] drm/vblank: Don't arm vblank timer with invalid frame duration
From: Roman Ilin @ 2026-07-02 18:23 UTC (permalink / raw)
To: Thomas Zimmermann, Maarten Lankhorst, Maxime Ripard, David Airlie,
Simona Vetter
Cc: Louis Chauvet, Javier Martinez Canillas, Dmitry Osipenko,
dri-devel, virtualization, linux-kernel, Ville Syrjälä,
Thorsten Leemhuis, Peter Arnesen
In-Reply-To: <20260702181027.98526-1-me@romanilin.is>
Apologies, I accidentally fired off send-email before saving my final
changelog notes. Please ignore the changelog and notes in the original
v3 email.
The actual changes in v3 are:
- Changed the WARN_ON_ONCE to drm_dbg_kms (to avoid user-triggerable
panics).
- Updated drm_calc_timestamping_constants with the goto error fallback
to clear the stale state.
Also, an automated review bot pointed out an AB-BA deadlock in
drm_crtc_vblank_start_timer(). But I am leaving this out of the patch to
keep the fixes orthogonal.
Sorry for the noise.
> On Jul 2, 2026, at 21:10, Roman Ilin <me@romanilin.is> wrote:
>
> When a CRTC's display mode carries a too small pixel clock,
> drm_calc_timestamping_constants() computes a frame duration that
> exceeds INT_MAX. drm_vblank_crtc.framedur_ns becomes negative.
> drm_crtc_vblank_start_timer() then arms the vblank hrtimer with this
> interval, after which vblank events are no longer delivered. Pending
> page flips never complete and the display appears frozen.
>
> This could be triggered on virtio-gpu guests that have dynamic resolution
> enabled: when the SPICE agent or the X server resizes the output, it
> submits a mode whose pixel clock is off by a factor of 1000, e.g.:
>
> clock = 406 kHz, htotal = 3152, vtotal = 2148
>
> framedur_ns = 3152 * 2148 * 1000000 / 406 = 16675852216 ns (~16.7 s)
>
> 16675852216 does not fit into an int and wraps to roughly -504000000.
> ns_to_ktime() then yields a negative interval and the timer stops working.
>
> Found by bisection, which pointed at commit a036f5fceedb ("drm/virtgpu:
> Use vblank timer"). That commit merely made virtio-gpu use the vblank
> timer and thereby exposed the pre-existing problem in the timer setup
> added by commit 74afeb812850 ("drm/vblank: Add vblank timer").
>
> To fix this, modify drm_calc_timestamping_constants() to use u64 for
> calculations, check for INT_MAX overflows, and return an error code.
> drm_crtc_vblank_start_timer() will then propagate the error, enabling
> the driver to fall back to immediate vblank events. Valid modes are
> unaffected, and the timer self-heals on the next mode with a sane clock.
>
> Fixes: 74afeb812850 ("drm/vblank: Add vblank timer")
> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
> Signed-off-by: Roman Ilin <me@romanilin.is>
> ---
> Changes in v3:
>
> - Changed the WARN_ON_ONCE to drm_err_once
>
> Notes:
>
>
>
> drivers/gpu/drm/drm_vblank.c | 71 +++++++++++++++++++++++-------------
> include/drm/drm_vblank.h | 4 +-
> 2 files changed, 48 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index f90fb2d13..629b9fcc7 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -631,42 +631,51 @@ EXPORT_SYMBOL(drm_crtc_vblank_waitqueue);
> * drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from
> * CRTC's true scanout timing, so they take things like panel scaling or
> * other adjustments into account.
> + *
> + * Returns:
> + * 0 on success, or a negative errno code otherwise.
> */
> -void drm_calc_timestamping_constants(struct drm_crtc *crtc,
> - const struct drm_display_mode *mode)
> +int drm_calc_timestamping_constants(struct drm_crtc *crtc,
> + const struct drm_display_mode *mode)
> {
> struct drm_device *dev = crtc->dev;
> unsigned int pipe = drm_crtc_index(crtc);
> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
> - int linedur_ns = 0, framedur_ns = 0;
> + u64 linedur_ns, framedur_ns;
> int dotclock = mode->crtc_clock;
> + unsigned int frame_size;
>
> if (!drm_dev_has_vblank(dev))
> - return;
> + return 0;
>
> if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
> - return;
> + return -EINVAL;
>
> - /* Valid dotclock? */
> - if (dotclock > 0) {
> - int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
> + if (dotclock <= 0) {
> + drm_err(dev, "crtc %u: Can't calculate constants, dotclock = %d!\n",
> + crtc->base.id, dotclock);
> + goto error;
> + }
>
> - /*
> - * Convert scanline length in pixels and video
> - * dot clock to line duration and frame duration
> - * in nanoseconds:
> - */
> - linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
> - framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
> + frame_size = (unsigned int)mode->crtc_htotal * (unsigned int)mode->crtc_vtotal;
>
> - /*
> - * Fields of interlaced scanout modes are only half a frame duration.
> - */
> - if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> - framedur_ns /= 2;
> - } else {
> - drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n",
> - crtc->base.id);
> + /*
> + * Convert scanline length in pixels and video dot clock to line duration
> + * and frame duration in nanoseconds.
> + */
> + linedur_ns = div_u64((u64)mode->crtc_htotal * 1000000, dotclock);
> + framedur_ns = div_u64((u64)frame_size * 1000000, dotclock);
> +
> + /*
> + * Fields of interlaced scanout modes are only half a frame duration.
> + */
> + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> + framedur_ns /= 2;
> +
> + if (linedur_ns > INT_MAX || framedur_ns > INT_MAX) {
> + drm_dbg_kms(dev, "crtc %u: Can't calculate constants, mode clock too small!\n",
> + crtc->base.id);
> + goto error;
> }
>
> vblank->linedur_ns = linedur_ns;
> @@ -678,7 +687,16 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
> crtc->base.id, mode->crtc_htotal,
> mode->crtc_vtotal, mode->crtc_vdisplay);
> drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n",
> - crtc->base.id, dotclock, framedur_ns, linedur_ns);
> + crtc->base.id, dotclock,
> + vblank->framedur_ns, vblank->linedur_ns);
> +
> + return 0;
> +
> +error:
> + vblank->linedur_ns = 0;
> + vblank->framedur_ns = 0;
> + drm_mode_copy(&vblank->hwmode, mode);
> + return -EINVAL;
> }
> EXPORT_SYMBOL(drm_calc_timestamping_constants);
>
> @@ -2221,6 +2239,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc)
> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
> struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer;
> unsigned long flags;
> + int ret;
>
> if (!vtimer->crtc) {
> /*
> @@ -2239,7 +2258,9 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc)
> hrtimer_try_to_cancel(&vtimer->timer);
> }
>
> - drm_calc_timestamping_constants(crtc, &crtc->mode);
> + ret = drm_calc_timestamping_constants(crtc, &crtc->mode);
> + if (ret)
> + return ret;
>
> spin_lock_irqsave(&vtimer->interval_lock, flags);
> vtimer->interval = ns_to_ktime(vblank->framedur_ns);
> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> index 2fcef9c0f..d99772dfa 100644
> --- a/include/drm/drm_vblank.h
> +++ b/include/drm/drm_vblank.h
> @@ -311,8 +311,8 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc);
> u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
> void drm_crtc_vblank_restore(struct drm_crtc *crtc);
>
> -void drm_calc_timestamping_constants(struct drm_crtc *crtc,
> - const struct drm_display_mode *mode);
> +int drm_calc_timestamping_constants(struct drm_crtc *crtc,
> + const struct drm_display_mode *mode);
> wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
> void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> u32 max_vblank_count);
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v2 0/4] virtio_balloon: quiesce balloon work on device shutdown
From: David Hildenbrand (Arm) @ 2026-07-02 19:30 UTC (permalink / raw)
To: Denis V. Lunev, Denis V. Lunev, mst; +Cc: virtualization, linux-kernel
In-Reply-To: <c18ed056-72f3-4eab-a370-c02b735e536e@virtuozzo.com>
On 7/2/26 19:50, Denis V. Lunev wrote:
> On 6/24/26 16:08, Denis V. Lunev wrote:
>> This email originated from an IP that might not be authorized by the domain it was sent from.
>> Do not click links or open attachments unless it is an email you expected to receive.
>> Since commit 8bd2fa086a04 ("virtio: break and reset virtio devices on
>> device_shutdown()") the virtio bus breaks and resets every virtio device
>> during device_shutdown(), i.e. on reboot and kexec. virtio_balloon has no
>> .shutdown of its own, so that generic path runs while the balloon's
>> asynchronous work is still armed: the free page reporting worker, the
>> inflate/deflate and stats workers, the OOM notifier and the free page
>> shrinker.
>>
>> Once the device has been broken, virtqueue_add_inbuf() in
>> virtballoon_free_page_report() returns -EIO and trips its WARN_ON_ONCE().
>> On a kernel booted with panic_on_warn that turns an ordinary reboot into a
>> fatal panic in the middle of device_shutdown(), so the machine never
>> reaches the new kernel. The inflate/deflate and OOM paths do not warn but
>> are no better off: they call wait_event(vb->acked, ...) and would block
>> forever on a queue that can no longer complete.
>>
>> This was hit in the field as an intermittent failure of a virtualization
>> cluster upgrade: guest storage nodes were rebooted via kexec into the new
>> kernel, and the ones whose free page reporting happened to run during
>> device_shutdown() panicked (the guests run with panic_on_warn) and never
>> came back, stalling the rolling upgrade. The crash dump showed the WARN at
>> virtio_balloon.c:216 in a page_reporting kworker, with all the balloon
>> virtqueues already broken.
>>
>> Validated by churning balloon inflate/deflate from the host while
>> kexec-rebooting the guest in a loop under panic_on_warn: the unpatched
>> kernel reproduces the WARN within a couple of cycles, while the patched
>> kernel survives many consecutive kexec cycles cleanly (12/12 in the final
>> run, 0 WARNs). checkpatch is clean across the series.
>>
>> Changes in v2:
>> - Add a virtio_device_shutdown() core helper and call it from the balloon
>> .shutdown handler instead of open-coding break + synchronize_cbs + reset
>> (David Hildenbrand).
>> - New patch: make tell_host() warn and bail instead of hanging if a buffer
>> add ever fails (David Hildenbrand); kept as a separate patch
>> (Michael S. Tsirkin).
>>
>> v1: https://lore.kernel.org/all/20260622133715.3707707-1-den@openvz.org
>>
>> Denis V. Lunev (4):
>> virtio: add virtio_device_shutdown() helper
>> virtio_balloon: factor out virtballoon_quiesce()
>> virtio_balloon: quiesce balloon work before device shutdown
>> virtio_balloon: warn on failed buffer add in tell_host()
>>
>> drivers/virtio/virtio.c | 41 ++++++++++++++++++++++-----------
>> drivers/virtio/virtio_balloon.c | 40 ++++++++++++++++++++++++--------
>> include/linux/virtio.h | 1 +
>> 3 files changed, 59 insertions(+), 23 deletions(-)
>>
> Hi, David!
Hi! :)
>
> Is this good to go in? I have not seen the confirmation that the
> series is taken into your tree.
I don't have a tree (yet), and once I have one it will likely be more mm focused :)
@MST, I think this is good to go!
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH net 1/2] vsock/virtio: collapse receive queue under memory pressure
From: Bobby Eshleman @ 2026-07-02 20:09 UTC (permalink / raw)
To: Stefano Garzarella
Cc: netdev, Jason Wang, Jakub Kicinski, Paolo Abeni,
Michael S. Tsirkin, kvm, virtualization, Xuan Zhuo, Eric Dumazet,
Simon Horman, linux-kernel, Stefan Hajnoczi, David S. Miller,
Eugenio Pérez, stable, Brien Oberstein
In-Reply-To: <akYl38_9Y4ydXuqE@sgarzare-redhat>
On Thu, Jul 02, 2026 at 10:56:04AM +0200, Stefano Garzarella wrote:
> On Wed, Jul 01, 2026 at 09:34:35AM -0700, Bobby Eshleman wrote:
> > On Fri, Jun 26, 2026 at 03:48:22PM +0200, Stefano Garzarella wrote:
>
> [...]
>
> > > +out:
> > > + if (new_skb)
> > > + __skb_queue_tail(&new_queue, new_skb);
> > > +
> > > + skb_queue_splice(&new_queue, &vvs->rx_queue);
> >
> > I think the new skbs will also need skb_set_owner_sk_safe(skb, sk)
> > when adding to rx_queue?
>
> IIRC we added it in the rx path, mainily for loopback to pass the ownership
> from the tx socket to the rx socket, but here we are already in the rx path,
> so the skb will never leave this socket.
>
Ah that's right, I stand corrected. There is no sender to leak in this
case.
> Maybe it's necessary for the eBPF path?
Looking through sockmap, I don't think it depends on skb->sk being
non-null either (it reassigns owner to the redirect socket anyway using
skb_set_owner_r()).
Sorry for the false alarm. LGTM.
Reviewed-by: Bobby Eshleman <bobbyeshleman@meta.com>
^ permalink raw reply
* Re: [PATCH v2 0/4] virtio_balloon: quiesce balloon work on device shutdown
From: Michael S. Tsirkin @ 2026-07-02 22:33 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Denis V. Lunev, Denis V. Lunev, virtualization, linux-kernel
In-Reply-To: <00ebb86d-f7b8-4ddc-a17c-c4700cab73a9@kernel.org>
On Thu, Jul 02, 2026 at 09:30:26PM +0200, David Hildenbrand (Arm) wrote:
> On 7/2/26 19:50, Denis V. Lunev wrote:
> > On 6/24/26 16:08, Denis V. Lunev wrote:
> >> This email originated from an IP that might not be authorized by the domain it was sent from.
> >> Do not click links or open attachments unless it is an email you expected to receive.
> >> Since commit 8bd2fa086a04 ("virtio: break and reset virtio devices on
> >> device_shutdown()") the virtio bus breaks and resets every virtio device
> >> during device_shutdown(), i.e. on reboot and kexec. virtio_balloon has no
> >> .shutdown of its own, so that generic path runs while the balloon's
> >> asynchronous work is still armed: the free page reporting worker, the
> >> inflate/deflate and stats workers, the OOM notifier and the free page
> >> shrinker.
> >>
> >> Once the device has been broken, virtqueue_add_inbuf() in
> >> virtballoon_free_page_report() returns -EIO and trips its WARN_ON_ONCE().
> >> On a kernel booted with panic_on_warn that turns an ordinary reboot into a
> >> fatal panic in the middle of device_shutdown(), so the machine never
> >> reaches the new kernel. The inflate/deflate and OOM paths do not warn but
> >> are no better off: they call wait_event(vb->acked, ...) and would block
> >> forever on a queue that can no longer complete.
> >>
> >> This was hit in the field as an intermittent failure of a virtualization
> >> cluster upgrade: guest storage nodes were rebooted via kexec into the new
> >> kernel, and the ones whose free page reporting happened to run during
> >> device_shutdown() panicked (the guests run with panic_on_warn) and never
> >> came back, stalling the rolling upgrade. The crash dump showed the WARN at
> >> virtio_balloon.c:216 in a page_reporting kworker, with all the balloon
> >> virtqueues already broken.
> >>
> >> Validated by churning balloon inflate/deflate from the host while
> >> kexec-rebooting the guest in a loop under panic_on_warn: the unpatched
> >> kernel reproduces the WARN within a couple of cycles, while the patched
> >> kernel survives many consecutive kexec cycles cleanly (12/12 in the final
> >> run, 0 WARNs). checkpatch is clean across the series.
> >>
> >> Changes in v2:
> >> - Add a virtio_device_shutdown() core helper and call it from the balloon
> >> .shutdown handler instead of open-coding break + synchronize_cbs + reset
> >> (David Hildenbrand).
> >> - New patch: make tell_host() warn and bail instead of hanging if a buffer
> >> add ever fails (David Hildenbrand); kept as a separate patch
> >> (Michael S. Tsirkin).
> >>
> >> v1: https://lore.kernel.org/all/20260622133715.3707707-1-den@openvz.org
> >>
> >> Denis V. Lunev (4):
> >> virtio: add virtio_device_shutdown() helper
> >> virtio_balloon: factor out virtballoon_quiesce()
> >> virtio_balloon: quiesce balloon work before device shutdown
> >> virtio_balloon: warn on failed buffer add in tell_host()
> >>
> >> drivers/virtio/virtio.c | 41 ++++++++++++++++++++++-----------
> >> drivers/virtio/virtio_balloon.c | 40 ++++++++++++++++++++++++--------
> >> include/linux/virtio.h | 1 +
> >> 3 files changed, 59 insertions(+), 23 deletions(-)
> >>
> > Hi, David!
>
> Hi! :)
>
> >
> > Is this good to go in? I have not seen the confirmation that the
> > series is taken into your tree.
>
> I don't have a tree (yet), and once I have one it will likely be more mm focused :)
>
> @MST, I think this is good to go!
>
> --
> Cheers,
>
> David
Indeed, it's just a bugfix and I'm trying to get features into qemu
now before their freeze. I'll work on linux end of next week.
^ permalink raw reply
* Re: [PATCH] drm/virtio: defer hotplug event from dequeue worker to avoid deadlock
From: Ryosuke Yasuoka @ 2026-07-03 5:58 UTC (permalink / raw)
To: Dmitry Osipenko, David Airlie, Gerd Hoffmann, Gurchetan Singh,
Chia-I Wu, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Simona Vetter, Dmitry Baryshkov, Javier Martinez Canillas
Cc: dri-devel, virtualization, linux-kernel
In-Reply-To: <1b56e514-17b5-4da1-9ebd-4534e3204ea4@collabora.com>
On 02/07/2026 14:26, Dmitry Osipenko wrote:
> On 7/1/26 12:23, Ryosuke Yasuoka wrote:
>>
>>
>> On 30/06/2026 16:46, Dmitry Osipenko wrote:
>>> Hi,
>>>
>>> On 6/30/26 12:16, Ryosuke Yasuoka wrote:
>>>> A probe-time deadlock can occur between the dequeue worker and
>>>> drm_client_register(). During probe, drm_client_register() holds
>>>> clientlist_mutex and calls the fbdev hotplug callback, which triggers an
>>>> atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs()
>>>> waiting for virtqueue space. The dequeue worker that would free that
>>>> space calls virtio_gpu_cmd_get_display_info_cb(), which invokes
>>>> drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting
>>>> to acquire the same clientlist_mutex. Since wake_up() is only called
>>>> after the resp_cb loop, the probe thread is never woken and both threads
>>>> deadlock.
>>>>
>>>> Fix this by deferring the hotplug notification from
>>>> virtio_gpu_cmd_get_display_info_cb() to a separate work item. The
>>>> display data (outputs[i].info) is still updated synchronously in the
>>>> callback, and the deferred work only triggers a re-probe notification to
>>>> DRM clients.
>>>>
>>>> Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client")
>>>> Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224
>>>> Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e
>>>> Signed-off-by: Ryosuke Yasuoka <ryasuoka@redhat.com>
>>>> ---
>>>> drivers/gpu/drm/virtio/virtgpu_drv.h | 3 +++
>>>> drivers/gpu/drm/virtio/virtgpu_kms.c | 3 +++
>>>> drivers/gpu/drm/virtio/virtgpu_vq.c | 12 ++++++++++--
>>>> 3 files changed, 16 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
>>>> index 7449907754a4..27ffa4697ae9 100644
>>>> --- a/drivers/gpu/drm/virtio/virtgpu_drv.h
>>>> +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
>>>> @@ -264,6 +264,8 @@ struct virtio_gpu_device {
>>>>
>>>> struct work_struct config_changed_work;
>>>>
>>>> + struct work_struct hotplug_work;
>>>> +
>>>> struct work_struct obj_free_work;
>>>> spinlock_t obj_free_lock;
>>>> struct list_head obj_free_list;
>>>> @@ -350,6 +352,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev,
>>>> uint32_t x, uint32_t y,
>>>> struct virtio_gpu_object_array *objs,
>>>> struct virtio_gpu_fence *fence);
>>>> +void virtio_gpu_hotplug_work_func(struct work_struct *work);
>>>> void virtio_gpu_panic_cmd_resource_flush(struct virtio_gpu_device *vgdev,
>>>> uint32_t resource_id,
>>>> uint32_t x, uint32_t y,
>>>> diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
>>>> index cfde9f573df6..cfb532ba43a4 100644
>>>> --- a/drivers/gpu/drm/virtio/virtgpu_kms.c
>>>> +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
>>>> @@ -154,6 +154,8 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
>>>> INIT_WORK(&vgdev->config_changed_work,
>>>> virtio_gpu_config_changed_work_func);
>>>>
>>>> + INIT_WORK(&vgdev->hotplug_work, virtio_gpu_hotplug_work_func);
>>>> +
>>>> INIT_WORK(&vgdev->obj_free_work,
>>>> virtio_gpu_array_put_free_work);
>>>> INIT_LIST_HEAD(&vgdev->obj_free_list);
>>>> @@ -293,6 +295,7 @@ void virtio_gpu_deinit(struct drm_device *dev)
>>>> flush_work(&vgdev->obj_free_work);
>>>> flush_work(&vgdev->ctrlq.dequeue_work);
>>>> flush_work(&vgdev->cursorq.dequeue_work);
>>>> + flush_work(&vgdev->hotplug_work);
>>>> flush_work(&vgdev->config_changed_work);
>>>> virtio_reset_device(vgdev->vdev);
>>>> vgdev->vdev->config->del_vqs(vgdev->vdev);
>>>> diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
>>>> index 67865810a2e7..084d98f5dc7b 100644
>>>> --- a/drivers/gpu/drm/virtio/virtgpu_vq.c
>>>> +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
>>>> @@ -816,6 +816,15 @@ virtio_gpu_cmd_resource_detach_backing(struct virtio_gpu_device *vgdev,
>>>> virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
>>>> }
>>>>
>>>> +void virtio_gpu_hotplug_work_func(struct work_struct *work)
>>>> +{
>>>> + struct virtio_gpu_device *vgdev =
>>>> + container_of(work, struct virtio_gpu_device, hotplug_work);
>>>> +
>>>> + if (!drm_helper_hpd_irq_event(vgdev->ddev))
>>>> + drm_kms_helper_hotplug_event(vgdev->ddev);
>>>> +}
>>>> +
>>>> static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
>>>> struct virtio_gpu_vbuffer *vbuf)
>>>> {
>>>> @@ -841,8 +850,7 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
>>>> spin_unlock(&vgdev->display_info_lock);
>>>> wake_up(&vgdev->resp_wq);
>>>>
>>>> - if (!drm_helper_hpd_irq_event(vgdev->ddev))
>>>> - drm_kms_helper_hotplug_event(vgdev->ddev);
>>>> + schedule_work(&vgdev->hotplug_work);
>>>> }
>>>>
>>>> static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
>>>
>>
>> Hi,
>> Thank you for your review.
>>
>>> Could you please move drm_kms_helper_hotplug_event() to virtio_gpu_init(), placing it after wait_event_timeout(display_info_pending)? This will avoid additional work_struct that otherwise needs to be cancelled in virtio_gpu_init() on the timeout.
>>
>> IIUC, moving the drm_kms_helper_hotplug_event() and _hpd_irq_event()
>> into virtio_gpu_init() after wait_event_timeout() would not prevent the
>> issue.
>>
>> Looking at the syzbot call traces[1][2], the deadlock occurs during
>> drm_client_setup(), which runs after virtio_gpu_init() has already
>> returned. The display_info_cb that triggers the deadlock is called from
>> the dequeue worker while drm_client_register() holds clientlist_mutex.
>>
>> Thread A:
>> virtio_gpu_probe()
>> -> virtio_gpu_init() // sends GET_DISPLAY_INFO and waits up to 5s
>
> You mean that the timeout happens and it's again syzkaller report for a
> broken host. A day ago I applied [1] that should fix this "bogus"
> syzkaller report.
>
> [1] https://patchwork.freedesktop.org/patch/735301/
Thank you for [1] and the clarificaiton. I agree that [1] addresses the
broken host scenario where virtio_gpu_init() times out and probe
continues with a pending display_info response. I think there is another
scenario causing the same deadlock reported by syzbot and my patch
addresses both cases.
The deadlock can also occur with the following scenario:
after virtio_gpu_init() completes successfully (wait_event_timeout
returns), if a config_changed event arrives before drm_client_setup()
completes, config_changed_work_func() sends a new GET_DISPLAY_INFO. Its
display_info_cb fires in the dequeue worker and blocks on
clientlist_mutex held by drm_client_register(). This is the same
deadlock path reported by syzbot.
Since [1] only prevents the timeout case, I believe the schedule_work()
approach is still needed to prevent display_info_cb from blocking on
clientlist_mutex in the dequeue worker context, regardless of the
trigger.
Best regards,
Ryosuke
^ permalink raw reply
* Re: [PATCH v3] drm/vblank: Don't arm vblank timer with invalid frame duration
From: Thomas Zimmermann @ 2026-07-03 7:26 UTC (permalink / raw)
To: Roman Ilin, Maarten Lankhorst, Maxime Ripard, David Airlie,
Simona Vetter
Cc: Louis Chauvet, Javier Martinez Canillas, Dmitry Osipenko,
dri-devel, virtualization, linux-kernel, Ville Syrjälä,
Thorsten Leemhuis, Peter Arnesen
In-Reply-To: <E697A2AE-5413-48AE-BFD6-3383819B388B@romanilin.is>
Hi
Am 02.07.26 um 20:23 schrieb Roman Ilin:
> Apologies, I accidentally fired off send-email before saving my final
> changelog notes. Please ignore the changelog and notes in the original
> v3 email.
>
> The actual changes in v3 are:
>
> - Changed the WARN_ON_ONCE to drm_dbg_kms (to avoid user-triggerable
> panics).
We want to know when this happens. And user space will only be able to
trigger this once, so there's no risk of spamming the kernel log.
So this is not really a problem. drm_WARN_ON_ONCE was ok for that. You
can also use a regular DRM print macro. But instead of drm_dbg_kms()
should use drm_err_once(). But please also output linedur_ns and
framedur_ns in the error. We want to know which of them is incorrect.
You can also add more information to the error message. See [1] for the
mode-formating macros.
[1]
https://elixir.bootlin.com/linux/v7.1.2/source/include/drm/drm_modes.h#L422
> - Updated drm_calc_timestamping_constants with the goto error fallback
> to clear the stale state.
>
> Also, an automated review bot pointed out an AB-BA deadlock in
> drm_crtc_vblank_start_timer(). But I am leaving this out of the patch to
> keep the fixes orthogonal.
>
> Sorry for the noise.
>
>> On Jul 2, 2026, at 21:10, Roman Ilin <me@romanilin.is> wrote:
>>
>> When a CRTC's display mode carries a too small pixel clock,
>> drm_calc_timestamping_constants() computes a frame duration that
>> exceeds INT_MAX. drm_vblank_crtc.framedur_ns becomes negative.
>> drm_crtc_vblank_start_timer() then arms the vblank hrtimer with this
>> interval, after which vblank events are no longer delivered. Pending
>> page flips never complete and the display appears frozen.
>>
>> This could be triggered on virtio-gpu guests that have dynamic resolution
>> enabled: when the SPICE agent or the X server resizes the output, it
>> submits a mode whose pixel clock is off by a factor of 1000, e.g.:
>>
>> clock = 406 kHz, htotal = 3152, vtotal = 2148
>>
>> framedur_ns = 3152 * 2148 * 1000000 / 406 = 16675852216 ns (~16.7 s)
>>
>> 16675852216 does not fit into an int and wraps to roughly -504000000.
>> ns_to_ktime() then yields a negative interval and the timer stops working.
>>
>> Found by bisection, which pointed at commit a036f5fceedb ("drm/virtgpu:
>> Use vblank timer"). That commit merely made virtio-gpu use the vblank
>> timer and thereby exposed the pre-existing problem in the timer setup
>> added by commit 74afeb812850 ("drm/vblank: Add vblank timer").
>>
>> To fix this, modify drm_calc_timestamping_constants() to use u64 for
>> calculations, check for INT_MAX overflows, and return an error code.
>> drm_crtc_vblank_start_timer() will then propagate the error, enabling
>> the driver to fall back to immediate vblank events. Valid modes are
>> unaffected, and the timer self-heals on the next mode with a sane clock.
>>
>> Fixes: 74afeb812850 ("drm/vblank: Add vblank timer")
>> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Signed-off-by: Roman Ilin <me@romanilin.is>
>> ---
>> Changes in v3:
>>
>> - Changed the WARN_ON_ONCE to drm_err_once
>>
>> Notes:
>>
>>
>>
>> drivers/gpu/drm/drm_vblank.c | 71 +++++++++++++++++++++++-------------
>> include/drm/drm_vblank.h | 4 +-
>> 2 files changed, 48 insertions(+), 27 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
>> index f90fb2d13..629b9fcc7 100644
>> --- a/drivers/gpu/drm/drm_vblank.c
>> +++ b/drivers/gpu/drm/drm_vblank.c
>> @@ -631,42 +631,51 @@ EXPORT_SYMBOL(drm_crtc_vblank_waitqueue);
>> * drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from
>> * CRTC's true scanout timing, so they take things like panel scaling or
>> * other adjustments into account.
>> + *
>> + * Returns:
>> + * 0 on success, or a negative errno code otherwise.
>> */
>> -void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>> - const struct drm_display_mode *mode)
>> +int drm_calc_timestamping_constants(struct drm_crtc *crtc,
>> + const struct drm_display_mode *mode)
>> {
>> struct drm_device *dev = crtc->dev;
>> unsigned int pipe = drm_crtc_index(crtc);
>> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
>> - int linedur_ns = 0, framedur_ns = 0;
>> + u64 linedur_ns, framedur_ns;
>> int dotclock = mode->crtc_clock;
>> + unsigned int frame_size;
>>
>> if (!drm_dev_has_vblank(dev))
>> - return;
>> + return 0;
>>
>> if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
>> - return;
>> + return -EINVAL;
>>
>> - /* Valid dotclock? */
>> - if (dotclock > 0) {
>> - int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
>> + if (dotclock <= 0) {
>> + drm_err(dev, "crtc %u: Can't calculate constants, dotclock = %d!\n",
Please turn this into drm_err_once() because this call can actually be
triggered repeatedly from userspace.
Best regards
Thomas
>> + crtc->base.id, dotclock);
>> + goto error;
>> + }
>>
>> - /*
>> - * Convert scanline length in pixels and video
>> - * dot clock to line duration and frame duration
>> - * in nanoseconds:
>> - */
>> - linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
>> - framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
>> + frame_size = (unsigned int)mode->crtc_htotal * (unsigned int)mode->crtc_vtotal;
>>
>> - /*
>> - * Fields of interlaced scanout modes are only half a frame duration.
>> - */
>> - if (mode->flags & DRM_MODE_FLAG_INTERLACE)
>> - framedur_ns /= 2;
>> - } else {
>> - drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n",
>> - crtc->base.id);
>> + /*
>> + * Convert scanline length in pixels and video dot clock to line duration
>> + * and frame duration in nanoseconds.
>> + */
>> + linedur_ns = div_u64((u64)mode->crtc_htotal * 1000000, dotclock);
>> + framedur_ns = div_u64((u64)frame_size * 1000000, dotclock);
>> +
>> + /*
>> + * Fields of interlaced scanout modes are only half a frame duration.
>> + */
>> + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
>> + framedur_ns /= 2;
>> +
>> + if (linedur_ns > INT_MAX || framedur_ns > INT_MAX) {
>> + drm_dbg_kms(dev, "crtc %u: Can't calculate constants, mode clock too small!\n",
>> + crtc->base.id);
>> + goto error;
>> }
>>
>> vblank->linedur_ns = linedur_ns;
>> @@ -678,7 +687,16 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>> crtc->base.id, mode->crtc_htotal,
>> mode->crtc_vtotal, mode->crtc_vdisplay);
>> drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n",
>> - crtc->base.id, dotclock, framedur_ns, linedur_ns);
>> + crtc->base.id, dotclock,
>> + vblank->framedur_ns, vblank->linedur_ns);
>> +
>> + return 0;
>> +
>> +error:
>> + vblank->linedur_ns = 0;
>> + vblank->framedur_ns = 0;
>> + drm_mode_copy(&vblank->hwmode, mode);
>> + return -EINVAL;
>> }
>> EXPORT_SYMBOL(drm_calc_timestamping_constants);
>>
>> @@ -2221,6 +2239,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc)
>> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
>> struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer;
>> unsigned long flags;
>> + int ret;
>>
>> if (!vtimer->crtc) {
>> /*
>> @@ -2239,7 +2258,9 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc)
>> hrtimer_try_to_cancel(&vtimer->timer);
>> }
>>
>> - drm_calc_timestamping_constants(crtc, &crtc->mode);
>> + ret = drm_calc_timestamping_constants(crtc, &crtc->mode);
>> + if (ret)
>> + return ret;
>>
>> spin_lock_irqsave(&vtimer->interval_lock, flags);
>> vtimer->interval = ns_to_ktime(vblank->framedur_ns);
>> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
>> index 2fcef9c0f..d99772dfa 100644
>> --- a/include/drm/drm_vblank.h
>> +++ b/include/drm/drm_vblank.h
>> @@ -311,8 +311,8 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc);
>> u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
>> void drm_crtc_vblank_restore(struct drm_crtc *crtc);
>>
>> -void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>> - const struct drm_display_mode *mode);
>> +int drm_calc_timestamping_constants(struct drm_crtc *crtc,
>> + const struct drm_display_mode *mode);
>> wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
>> void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
>> u32 max_vblank_count);
>> --
>> 2.54.0
>>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 01/13] mm: introduce vma_flags_can_grow() and vma_can_grow()
From: Zi Yan @ 2026-07-03 15:19 UTC (permalink / raw)
To: Lorenzo Stoakes, Andrew Morton
Cc: Thomas Bogendoerfer, Madhavan Srinivasan, Michael Ellerman,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Lucas Stach, Inki Dae, Seung-Woo Kim,
Kyungmin Park, Krzysztof Kozlowski, Peter Griffin, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Rob Clark,
Dmitry Baryshkov, Lyude Paul, Danilo Krummrich, Tomi Valkeinen,
Sandy Huang, Heiko Stübner, Andy Yan, Thierry Reding,
Mikko Perttunen, Jonathan Hunter, Gerd Hoffmann, Dmitry Osipenko,
Zack Rusin, Matthew Brost, Thomas Hellstrom,
Oleksandr Andrushchenko, Helge Deller, Benjamin LaHaise,
Alexander Viro, Christian Brauner, Muchun Song, Oscar Salvador,
David Hildenbrand, Baolin Wang, Liam R . Howlett, Nico Pache,
Ryan Roberts, Dev Jain, Barry Song, Lance Yang, Hugh Dickins,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Jann Horn, Pedro Falcato, Kees Cook, Jaroslav Kysela,
Takashi Iwai, linux-mips, linux-kernel, linuxppc-dev, dri-devel,
etnaviv, linux-arm-kernel, linux-samsung-soc, intel-gfx,
linux-arm-msm, freedreno, nouveau, linux-rockchip, linux-tegra,
virtualization, intel-xe, xen-devel, linux-fbdev, linux-aio,
linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <f2e8c32515d328db62279cc8bab8398ea278d74f.1782760670.git.ljs@kernel.org>
On Mon Jun 29, 2026 at 3:25 PM EDT, Lorenzo Stoakes wrote:
> These test whether the VMA has stack sematics, i.e. is able to grow upwards
> or downwards depending on the architecture.
>
> In order to account for arches which do not support upward-growing stacks,
> introduce VMA_GROWSUP whose definition depends on the architecture
> supporting it, and use vma_flags_test_single_mask() in vma_flags_can_grow()
> to account for this.
>
> Update the VMA userland tests to reflect the changes
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> ---
> include/linux/mm.h | 21 ++++++++++++++++++---
> tools/testing/vma/include/dup.h | 4 ++++
> 2 files changed, 22 insertions(+), 3 deletions(-)
>
Reviewed-by: Zi Yan <ziy@nvidia.com>
--
Best Regards,
Yan, Zi
^ permalink raw reply
* [PATCH] vdpa: alibaba: add missing MODULE_DEVICE_TABLE()
From: Pengpeng Hou @ 2026-07-04 15:27 UTC (permalink / raw)
To: Michael S. Tsirkin, Jason Wang, Xuan Zhuo, Eugenio Pérez
Cc: Pengpeng Hou, virtualization, linux-kernel
The driver has a match table for the pci bus wired into its driver
structure, but the table is not exported with MODULE_DEVICE_TABLE().
Add the missing MODULE_DEVICE_TABLE() entry so module alias information
is generated for automatic module loading.
This is a source-level fix. It does not claim dynamic hardware
reproduction; the evidence is the driver-owned match table, its use by
the driver registration structure, and the missing module alias
publication.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/vdpa/alibaba/eni_vdpa.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
index e476504db0c8..fd6fdba46094 100644
--- a/drivers/vdpa/alibaba/eni_vdpa.c
+++ b/drivers/vdpa/alibaba/eni_vdpa.c
@@ -545,6 +545,7 @@ static struct pci_device_id eni_pci_ids[] = {
VIRTIO_ID_NET) },
{ 0 },
};
+MODULE_DEVICE_TABLE(pci, eni_pci_ids);
static struct pci_driver eni_vdpa_driver = {
.name = "alibaba-eni-vdpa",
--
2.53.0
^ permalink raw reply related
* Re: [PATCH] vdpa: alibaba: add missing MODULE_DEVICE_TABLE()
From: Michael S. Tsirkin @ 2026-07-04 15:35 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Jason Wang, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel
In-Reply-To: <20260704152732.55338-1-pengpeng@iscas.ac.cn>
On Sat, Jul 04, 2026 at 11:27:32PM +0800, Pengpeng Hou wrote:
> The driver has a match table for the pci bus wired into its driver
> structure, but the table is not exported with MODULE_DEVICE_TABLE().
>
> Add the missing MODULE_DEVICE_TABLE() entry so module alias information
> is generated for automatic module loading.
>
> This is a source-level fix. It does not claim dynamic hardware
> reproduction; the evidence is the driver-owned match table, its use by
> the driver registration structure, and the missing module alias
> publication.
what does this paragraph mean?
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> ---
> drivers/vdpa/alibaba/eni_vdpa.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
> index e476504db0c8..fd6fdba46094 100644
> --- a/drivers/vdpa/alibaba/eni_vdpa.c
> +++ b/drivers/vdpa/alibaba/eni_vdpa.c
> @@ -545,6 +545,7 @@ static struct pci_device_id eni_pci_ids[] = {
> VIRTIO_ID_NET) },
> { 0 },
> };
> +MODULE_DEVICE_TABLE(pci, eni_pci_ids);
>
> static struct pci_driver eni_vdpa_driver = {
> .name = "alibaba-eni-vdpa",
> --
> 2.53.0
^ permalink raw reply
* [PATCH] vdpa: octeon_ep: add missing MODULE_DEVICE_TABLE()
From: Pengpeng Hou @ 2026-07-05 0:25 UTC (permalink / raw)
To: schalla, vattunuru, Michael S. Tsirkin, Jason Wang, Xuan Zhuo,
Eugenio Pérez
Cc: Pengpeng Hou, virtualization, linux-kernel
The driver has a match table for the pci bus wired into its driver
structure, but the table is not exported with MODULE_DEVICE_TABLE().
Add the missing MODULE_DEVICE_TABLE() entry so module alias information
is generated for automatic module loading.
This is a source-level fix. It does not claim dynamic hardware
reproduction; the evidence is the driver-owned match table, its use by
the driver registration structure, and the missing module alias
publication.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/vdpa/octeon_ep/octep_vdpa_main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/vdpa/octeon_ep/octep_vdpa_main.c b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
index 31a02e7fd7f2..9bedcd81a174 100644
--- a/drivers/vdpa/octeon_ep/octep_vdpa_main.c
+++ b/drivers/vdpa/octeon_ep/octep_vdpa_main.c
@@ -884,6 +884,7 @@ static struct pci_device_id octep_pci_vdpa_map[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_VDPA_DEVID_CN103K_VF) },
{ 0 },
};
+MODULE_DEVICE_TABLE(pci, octep_pci_vdpa_map);
static struct pci_driver octep_pci_vdpa = {
.name = OCTEP_VDPA_DRIVER_NAME,
--
2.53.0
^ permalink raw reply related
* [PATCH v2] virtio_balloon: disable indirect descriptors
From: Michael S. Tsirkin @ 2026-07-05 6:24 UTC (permalink / raw)
To: linux-kernel
Cc: David Hildenbrand (Arm), Jason Wang, Xuan Zhuo,
Eugenio Pérez, Andrew Morton, Alexander Duyck,
virtualization
The page reporting callback submits an sg list to the reporting
virtqueue. With VIRTIO_RING_F_INDIRECT_DESC negotiated and
total_sg > 1 (which it typically is), virtqueue_add reports it to the
host by allocating an indirect descriptor via kmalloc(GFP_KERNEL).
This is not pretty: the reporting worker isolates potentially hundreds
of MB of free pages from the buddy allocator (reported pages are at
least pageblock_order, and the sg can contain up to
PAGE_REPORTING_CAPACITY entries of varying orders). As the result,
very theoretically, the kmalloc might trigger OOM when we have in fact a
ton of free memory.
Clear VIRTIO_RING_F_INDIRECT_DESC, to avoid using indirect descriptors.
Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Assisted-by: Claude:claude-opus-4-6
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
I assume I'm the one merging this?
Changes in v2:
- Qualified OOM scenario as "very theoretically" (David Hildenbrand)
drivers/virtio/virtio_balloon.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 581ac799d974..69160da9cd5d 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -7,6 +7,7 @@
*/
#include <linux/virtio.h>
+#include <uapi/linux/virtio_ring.h>
#include <linux/virtio_balloon.h>
#include <linux/swap.h>
#include <linux/workqueue.h>
@@ -1165,6 +1166,11 @@ static int virtballoon_validate(struct virtio_device *vdev)
else if (!virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON))
__virtio_clear_bit(vdev, VIRTIO_BALLOON_F_REPORTING);
+ /*
+ * Disable indirect descriptors to avoid memory allocation in
+ * virtqueue_add during page reporting.
+ */
+ __virtio_clear_bit(vdev, VIRTIO_RING_F_INDIRECT_DESC);
__virtio_clear_bit(vdev, VIRTIO_F_ACCESS_PLATFORM);
return 0;
}
--
MST
^ permalink raw reply related
* [PATCH v3] mm: page_reporting: allow driver to set batch capacity
From: Michael S. Tsirkin @ 2026-07-05 6:25 UTC (permalink / raw)
To: linux-kernel
Cc: David Hildenbrand (Arm), Gregory Price, Zi Yan, Pankaj Gupta,
Jason Wang, Xuan Zhuo, Eugenio Pérez, Andrew Morton,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
Johannes Weiner, Alexander Duyck, virtualization, linux-mm
At the moment, if a virtio balloon device has a page reporting vq but
its size is < PAGE_REPORTING_CAPACITY (32), the balloon driver fails
probe.
But, there's no way for host to know this value, so it can easily
create a smaller vq and suddenly adding the reporting capability
to the device makes all of the driver fail. Not pretty.
Add a capacity field to page_reporting_dev_info so drivers can
control the maximum number of pages per report batch.
In virtio-balloon, set the capacity to the reporting virtqueue size,
letting page_reporting adapt to whatever the device provides.
Capacity need not be a power of two. Code previously called out
division by PAGE_REPORTING_CAPACITY as cheap since it was a power
of 2, but no performance difference was observed with non-power-of-2
values.
If capacity is 0 or exceeds PAGE_REPORTING_CAPACITY, it defaults
to PAGE_REPORTING_CAPACITY. The 0 check and the clamping is done in
page_reporting_register(), before the reporting work is scheduled,
so we never get division by 0.
Fixes: b0c504f15471 ("virtio-balloon: add support for providing free page reports to host")
Assisted-by: Claude:claude-opus-4-6
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Gregory Price <gourry@gourry.net>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Pankaj Gupta <pankaj.gupta@amd.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
Who's merging this? Me?
Changes in v3:
- Dropped stale "This value should always be a power of 2" comment
above PAGE_REPORTING_CAPACITY (David Hildenbrand, others)
Changes in v2:
- Added paragraph explaining capacity need not be a power of two
- Added paragraph documenting capacity=0 default and no div-by-zero
(Gregory Price)
- Improved struct field comment: "0 (default) means PAGE_REPORTING_CAPACITY"
drivers/virtio/virtio_balloon.c | 5 +----
include/linux/page_reporting.h | 4 +++-
mm/page_reporting.c | 24 ++++++++++++------------
3 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 088b3a0e6ce6..581ac799d974 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -1017,10 +1017,6 @@ static int virtballoon_probe(struct virtio_device *vdev)
unsigned int capacity;
capacity = virtqueue_get_vring_size(vb->reporting_vq);
- if (capacity < PAGE_REPORTING_CAPACITY) {
- err = -ENOSPC;
- goto out_unregister_oom;
- }
vb->pr_dev_info.order = PAGE_REPORTING_ORDER_UNSPECIFIED;
@@ -1041,6 +1037,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
vb->pr_dev_info.order = 5;
#endif
+ vb->pr_dev_info.capacity = capacity;
err = page_reporting_register(&vb->pr_dev_info);
if (err)
goto out_unregister_oom;
diff --git a/include/linux/page_reporting.h b/include/linux/page_reporting.h
index 9d4ca5c218a0..272b1274efdc 100644
--- a/include/linux/page_reporting.h
+++ b/include/linux/page_reporting.h
@@ -5,7 +5,6 @@
#include <linux/mmzone.h>
#include <linux/scatterlist.h>
-/* This value should always be a power of 2, see page_reporting_cycle() */
#define PAGE_REPORTING_CAPACITY 32
#define PAGE_REPORTING_ORDER_UNSPECIFIED -1
@@ -22,6 +21,9 @@ struct page_reporting_dev_info {
/* Minimal order of page reporting */
unsigned int order;
+
+ /* Max pages per report batch; 0 (default) means PAGE_REPORTING_CAPACITY */
+ unsigned int capacity;
};
/* Tear-down and bring-up for page reporting devices */
diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index 7418f2e500bb..942e84b6908a 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -173,11 +173,8 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
* any pages that may have already been present from the previous
* list processed. This should result in us reporting all pages on
* an idle system in about 30 seconds.
- *
- * The division here should be cheap since PAGE_REPORTING_CAPACITY
- * should always be a power of 2.
*/
- budget = DIV_ROUND_UP(area->nr_free, PAGE_REPORTING_CAPACITY * 16);
+ budget = DIV_ROUND_UP(area->nr_free, prdev->capacity * 16);
/* loop through free list adding unreported pages to sg list */
list_for_each_entry_safe(page, next, list, lru) {
@@ -222,10 +219,10 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
spin_unlock_irq(&zone->lock);
/* begin processing pages in local list */
- err = prdev->report(prdev, sgl, PAGE_REPORTING_CAPACITY);
+ err = prdev->report(prdev, sgl, prdev->capacity);
/* reset offset since the full list was reported */
- *offset = PAGE_REPORTING_CAPACITY;
+ *offset = prdev->capacity;
/* update budget to reflect call to report function */
budget--;
@@ -234,7 +231,7 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
spin_lock_irq(&zone->lock);
/* flush reported pages from the sg list */
- page_reporting_drain(prdev, sgl, PAGE_REPORTING_CAPACITY, !err);
+ page_reporting_drain(prdev, sgl, prdev->capacity, !err);
/*
* Reset next to first entry, the old next isn't valid
@@ -260,13 +257,13 @@ static int
page_reporting_process_zone(struct page_reporting_dev_info *prdev,
struct scatterlist *sgl, struct zone *zone)
{
- unsigned int order, mt, leftover, offset = PAGE_REPORTING_CAPACITY;
+ unsigned int order, mt, leftover, offset = prdev->capacity;
unsigned long watermark;
int err = 0;
/* Generate minimum watermark to be able to guarantee progress */
watermark = low_wmark_pages(zone) +
- (PAGE_REPORTING_CAPACITY << page_reporting_order);
+ (prdev->capacity << page_reporting_order);
/*
* Cancel request if insufficient free memory or if we failed
@@ -290,7 +287,7 @@ page_reporting_process_zone(struct page_reporting_dev_info *prdev,
}
/* report the leftover pages before going idle */
- leftover = PAGE_REPORTING_CAPACITY - offset;
+ leftover = prdev->capacity - offset;
if (leftover) {
sgl = &sgl[offset];
err = prdev->report(prdev, sgl, leftover);
@@ -322,11 +319,11 @@ static void page_reporting_process(struct work_struct *work)
atomic_set(&prdev->state, state);
/* allocate scatterlist to store pages being reported on */
- sgl = kmalloc_objs(*sgl, PAGE_REPORTING_CAPACITY);
+ sgl = kmalloc_objs(*sgl, prdev->capacity);
if (!sgl)
goto err_out;
- sg_init_table(sgl, PAGE_REPORTING_CAPACITY);
+ sg_init_table(sgl, prdev->capacity);
for_each_zone(zone) {
err = page_reporting_process_zone(prdev, sgl, zone);
@@ -377,6 +374,9 @@ int page_reporting_register(struct page_reporting_dev_info *prdev)
page_reporting_order = pageblock_order;
}
+ if (!prdev->capacity || prdev->capacity > PAGE_REPORTING_CAPACITY)
+ prdev->capacity = PAGE_REPORTING_CAPACITY;
+
/* initialize state and work structures */
atomic_set(&prdev->state, PAGE_REPORTING_IDLE);
INIT_DELAYED_WORK(&prdev->work, &page_reporting_process);
--
MST
^ permalink raw reply related
* Re: [PATCH v3] mm: page_reporting: allow driver to set batch capacity
From: Andrew Morton @ 2026-07-05 8:16 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: linux-kernel, David Hildenbrand (Arm), Gregory Price, Zi Yan,
Pankaj Gupta, Jason Wang, Xuan Zhuo, Eugenio Pérez,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
Johannes Weiner, Alexander Duyck, virtualization, linux-mm
In-Reply-To: <444c24cf39f3f3620fc90ef4695bd6b0979f4c4b.1783232420.git.mst@redhat.com>
On Sun, 5 Jul 2026 02:25:13 -0400 "Michael S. Tsirkin" <mst@redhat.com> wrote:
> At the moment, if a virtio balloon device has a page reporting vq but
> its size is < PAGE_REPORTING_CAPACITY (32), the balloon driver fails
> probe.
>
> But, there's no way for host to know this value, so it can easily
> create a smaller vq and suddenly adding the reporting capability
> to the device makes all of the driver fail. Not pretty.
>
> Add a capacity field to page_reporting_dev_info so drivers can
> control the maximum number of pages per report batch.
>
> In virtio-balloon, set the capacity to the reporting virtqueue size,
> letting page_reporting adapt to whatever the device provides.
>
> Capacity need not be a power of two. Code previously called out
> division by PAGE_REPORTING_CAPACITY as cheap since it was a power
> of 2, but no performance difference was observed with non-power-of-2
> values.
>
> If capacity is 0 or exceeds PAGE_REPORTING_CAPACITY, it defaults
> to PAGE_REPORTING_CAPACITY. The 0 check and the clamping is done in
> page_reporting_register(), before the reporting work is scheduled,
> so we never get division by 0.
Thanks. What's the priority here? Should we fix 7.2? Earlier?
It seems that Sashiko has found a pre-existing issue, a hard-to-hit
error path thing:
https://sashiko.dev/#/patchset/444c24cf39f3f3620fc90ef4695bd6b0979f4c4b.1783232420.git.mst@redhat.com
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox