All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
From: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
To: den@openvz.org
Cc: devel@openvz.org
Subject: Re: [Devel] [PATCH hci-8.1 v2 5/6] dm-ploop: reload metadata on resume
Date: Thu, 8 Oct 2026 13:46:43 +0200	[thread overview]
Message-ID: <2e7b895e-ef7e-4069-bba9-a7d039d6d357@virtuozzo.com> (raw)
In-Reply-To: <20261008073837.510678-6-alexander.ivanov@virtuozzo.com>

> [Severity: Medium]
> Can these GFP_KERNEL allocations deadlock under memory pressure?
>
> ploop_preresume() runs in the DM ioctl task while the device is still
> suspended, and no memalloc_noio scope is set on that path.  Direct reclaim
> with __GFP_IO and __GFP_FS could write back dirty pages of a filesystem
> mounted on this ploop device.  Those bios are held until resume completes,
> but the resume is the task waiting in the allocation.
>
> The same applies to the other allocations reached from here:
>
> ploop_reload_metadata()
>    ploop_setup_metadata()
>      ploop_setup_holes_bitmap()
>        ploop->holes_bitmap = kvmalloc(size, GFP_KERNEL);
>
> and to ploop_prealloc_md_pages().  The ploop kthreads avoid this by running
> with PF_MEMALLOC_NOIO (PLOOP_PFLAGS in dm-ploop-map.c), but the ioctl task
> has no such protection.
>
> Would it make sense to wrap ploop_reload_metadata() in
> memalloc_noio_save()/memalloc_noio_restore(), or to use GFP_NOIO?
Wrapped ploop_reload_metadata() in ploop_preresume() with 
memalloc_noio_save()/restore() rather than switching to GFP_NOIO, so 
nested allocations (holes_bitmap, md pages, backing fs reads) are 
covered as well. The same applies to ploop_truncate_unused_tail() in 
ploop_postsuspend() in the next patch, fixed there too.

> [Severity: Low]
> The commit message says "On error the old metadata is kept and resume
> fails."  Is that fully true here?
>
> ploop_setup_metadata() overwrites these fields before its later checks
> ('custom FirstBlockOffset', 'Too short BAT', ploop_setup_holes_bitmap()
> returning -ENOMEM):
>
> 	memcpy(ploop->m_Sig, m_hdr->m_Sig, sizeof(ploop->m_Sig));
> 	ploop->m_Type = le32_to_cpu(m_hdr->m_Type);
> 	ploop->m_Sectors = le32_to_cpu(m_hdr->m_Sectors);
>
> The restore label puts back bat_entries, holes_bitmap, nr_bat_entries,
> hb_nr and deltas[], but not m_Sig, m_Type or m_Sectors.  The same applies
> when ploop_prealloc_md_pages() or ploop_read_delta() fails.
>
> m_Sig and m_Sectors are validated, so in practice only m_Type could differ,
> and only if userspace rewrote the header.  ploop_delta_check_header()
> compares against these fields, so a later delta check could then use a value
> that does not match the retained old BAT.
>
> Should these three fields be saved and restored along with the others?
Fixed.

>> +void ploop_wait_prealloc(struct ploop *ploop)
>> +{
>> +	wait_event(ploop->dispatcher_wq_prealloc,
>> +		   ploop_no_pending_prealloc(ploop));
>> +}
> [Severity: Medium]
> Can this wait hang forever on a lost wakeup in the allocator?
>
> This is an unbounded, uninterruptible wait whose only waker is the
> wake_up() in ploop_allocator() after a preallocation completes.  In
> ploop_allocator(), prealloc_size is tested locklessly before the task state
> is set:
>
> 	if (ploop->prealloc_size) {
> 		...
> 	}
> 	if (kthread_should_stop()) {...}
> 	set_current_state(TASK_INTERRUPTIBLE);
> 	schedule();
>
> Consider this interleaving:
>
>    allocator: reads prealloc_size == 0, not yet in set_current_state()
>    requester: ploop_req_prealloc() sets prealloc_size under bat_lock
>    requester: wake_up_process(ploop->kt_allocator->task)  /* TASK_RUNNING */
>    allocator: set_current_state(TASK_INTERRUPTIBLE); schedule();
>
> The wakeup is a no-op and the allocator sleeps with prealloc_size != 0.
> ploop_req_prealloc() returns early when the requested size is already
> covered, so later IO would not re-kick it, and suspend has quiesced IO
> anyway.  ploop_no_pending_prealloc() then never becomes true.
>
> The race in the allocator predates this patch.  Before it, a lost wakeup
> only delayed preallocation until the next request.  Now it can hang
> ploop_postsuspend().  The new ploop_should_prealloc() call in
> ploop_preresume() also adds a new place to trigger it.
>
> Could the allocator re-check prealloc_size after set_current_state(), or
> could the wait be made bounded or killable?
Fixed in a separate patch "dm-ploop: fix lost wakeup in ploop_allocator()".

> [Severity: Medium]
> Can ploop_postsuspend() block here indefinitely?
>
> If the allocator loses the wakeup described above, ploop_wait_prealloc()
> never returns and dmsetup suspend hangs in D state.  This is a new
> dependency of the suspend path on the allocator making progress.
>
> The follow-up patch "dm-ploop: truncate unused tail of top delta on
> suspend" does not touch ploop_allocator() or ploop_wait_prealloc().  It
> makes ploop_postsuspend() call ploop_wait_prealloc() under
> down_write(&ctl_rwsem), so in the final series state the hang would also
> block every other ctl_rwsem user (message, status, ploop_llseek_hole()).
>
> Would it be possible to fix the allocator wakeup, or to avoid waiting while
> holding ctl_rwsem for write?
The lost wakeup in ploop_allocator() is fixed earlier in this series by
"dm-ploop: fix lost wakeup in ploop_allocator()". Also this patch
switches the allocator to wake_up() for dispatcher_wq_prealloc, since
ploop_wait_prealloc() uses uninterruptible wait_event().

ploop_preallocate_cluster() always clears prealloc_size and
prealloc_in_progress, including the error path, and the allocator never
takes ctl_rwsem, so the wait is bounded by the fallocate itself.

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  parent reply	other threads:[~2026-10-08 11:48 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-08  7:38 [Devel] [PATCH hci-8.1 v2 0/6] truncate unused tail of images on suspend Alexander Ivanov
2026-10-08  7:38 ` [Devel] [PATCH hci-8.1 v2 1/6] dm-qcow2: add qcow2_md_page_read_sync() helper Alexander Ivanov
2026-10-08  7:43   ` no-reply
2026-10-08  7:38 ` [Devel] [PATCH hci-8.1 v2 2/6] dm-qcow2: truncate unused tail of image on suspend Alexander Ivanov
2026-10-08  7:44   ` no-reply
2026-10-08  9:50   ` Alexander Ivanov
2026-10-08  7:38 ` [Devel] [PATCH hci-8.1 v2 3/6] dm-ploop: set delta is_raw before applying its mappings Alexander Ivanov
2026-10-08  7:46   ` no-reply
2026-10-08 10:42   ` Alexander Ivanov
2026-10-08  7:38 ` [Devel] [PATCH hci-8.1 v2 4/6] dm-ploop: factor out ploop_read_delta() from ploop_add_delta() Alexander Ivanov
2026-10-08  7:46   ` no-reply
2026-10-08  7:38 ` [Devel] [PATCH hci-8.1 v2 5/6] dm-ploop: reload metadata on resume Alexander Ivanov
2026-10-08  7:54   ` no-reply
2026-10-08 11:46   ` Alexander Ivanov [this message]
2026-10-08  7:38 ` [Devel] [PATCH hci-8.1 v2 6/6] dm-ploop: truncate unused tail of top delta on suspend Alexander Ivanov
2026-10-08  7:52   ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2e7b895e-ef7e-4069-bba9-a7d039d6d357@virtuozzo.com \
    --to=alexander.ivanov@virtuozzo.com \
    --cc=den@openvz.org \
    --cc=devel@openvz.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.