On Tue, Sep 01, 2026, Sean Christopherson wrote:
> On Tue, Sep 01, 2026, Fuad Tabba wrote:
> > > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> > > index 803c7cdbbe0f6..fe02c47c85fb5 100644
> > > --- a/virt/kvm/guest_memfd.c
> > > +++ b/virt/kvm/guest_memfd.c
> > > @@ -538,8 +538,46 @@ static int kvm_gmem_mas_preallocate(struct ma_state
> > > *mas, u64 attributes,
> > > return mas_preallocate(mas, xa_mk_value(attributes), GFP_KERNEL);
> > > }
> > >
> > > +static bool kvm_gmem_has_outstanding_references(struct inode *inode,
> > > + pgoff_t start, size_t
> > > nr_pages,
> > > + pgoff_t *err_index)
> > > +{
> > > + struct address_space *mapping = inode->i_mapping;
> > > + pgoff_t last = start + nr_pages - 1;
> > > + bool has_outstanding = false;
> > > + struct folio_batch fbatch;
> > > + pgoff_t next;
> > > + int i;
> > > +
> > > + folio_batch_init(&fbatch);
> > > +
> > > + next = start;
> > > + while (has_outstanding && filemap_get_folios(mapping, &next,
> > > last, &fbatch)) {
> >
> > has_outstanding starts as false, so the loop never runs and the function
> > always returns false. The outstanding-reference check is dead at this
> > patch, so a to-private conversion would not be rejected even when a page
> > still has an outstanding reference.
> >
> > It's fixed later in "KVM: guest_memfd: Handle lru_add fbatch refcounts
> > during conversion safety check", which changes the condition to
> > !has_outstanding. I think that fix belongs in this patch, so the check
> > works when it is introduced and the series bisects cleanly.
Wait, why are there even separate patches for this? For all intents and
purposes,
"Ensure pages are not in use before conversion" introduces a bug and then the
bug
is fixed by "Handle lru_add fbatch refcounts during conversion safety check".
Just don't introduce the bug.
I also recommend splitting the export of lru_cache_drain_for_folio() to its own
patch so that it can be more easily Acked by mm/ folks. If we want to squash it
with the KVM change, then that's trivial to do when applying.
> Why even bother with has_outstanding? Avoiding it requires copy+pasting
> folio_batch_release(), but it's less code and IMO the end result is a lot
> easier
> to follow:
>
> struct address_space *mapping = inode->i_mapping;
> pgoff_t last = start + nr_pages - 1;
> struct folio_batch fbatch;
> pgoff_t next;
> int i;
>
> folio_batch_init(&fbatch);
>
> next = start;
> while (filemap_get_folios(mapping, &next, last, &fbatch)) {
> for (i = 0; i < folio_batch_count(&fbatch); ++i) {
> struct folio *folio = fbatch.folios[i];
>
> /*
> * Outstanding references are anything other than those
> * from the page cache, plus 1 temporary reference held
> * by filemap_get_folios() in the folio batch.
> */
> if (folio_ref_count(folio) != folio_nr_pages(folio) +
> 1) {
> *err_index = max(start, folio->index);
> folio_batch_release(&fbatch);
> return true;
> }
> }
>
> folio_batch_release(&fbatch);
> cond_resched();
> }
>
> return false;
>
> and then we end up with:
>
> enum lru_cache_drained drained = LRU_CACHE_NOT_DRAINED;
> struct address_space *mapping = inode->i_mapping;
> pgoff_t last = start + nr_pages - 1;
> struct folio_batch fbatch;
> pgoff_t next;
> int i;
>
> folio_batch_init(&fbatch);
>
> next = start;
> while (filemap_get_folios(mapping, &next, last, &fbatch)) {
> for (i = 0; i < folio_batch_count(&fbatch); ++i) {
> struct folio *folio = fbatch.folios[i];
>
> if (__folio_has_outstanding_references(folio,
> &drained)) {
> *err_index = max(start, folio->index);
> folio_batch_release(&fbatch);
> return true;
> }
> }
>
> folio_batch_release(&fbatch);
> cond_resched();
> }
>
> return false;