From: no-reply@sashiko.virtuozzo.com
To: Alexander Ivanov <alexander.ivanov@virtuozzo.com>, den@virtuozzo.com
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 07:54:23 +0000 [thread overview]
Message-ID: <010701a11a8199aa-30d1f207-f777-46d2-803b-193c675da792-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261008073837.510678-6-alexander.ivanov@virtuozzo.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] dm-ploop: lost wakeup in ploop_allocator() can hang ploop_postsuspend() in wait_event()
- [Medium] dm-ploop: ploop_reload_metadata() uses GFP_KERNEL allocs with no NOIO scope
- [Medium] dm-ploop: postsuspend wait_event on prealloc can hang on allocator lost wakeup
- [Low] dm-ploop: ploop_reload_metadata() restore path leaves m_Sig/m_Type/m_Sectors modified
--
commit 17ae791b0a37f669147d370ddae2ae7351e7b6de
Author: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
dm-ploop: reload metadata on resume
This patch makes ploop_preresume() re-read the top delta header, the BAT
of every delta and the delta file sizes, and rebuild the BAT tree and
holes_bitmap. It moves preallocation from ploop_ctr() to ploop_preresume(),
makes ploop_postsuspend() wait for pending preallocation, and takes
ctl_rwsem in ploop_llseek_hole().
Link: https://virtuozzo.atlassian.net/browse/VSTOR-148171
> diff --git a/drivers/md/dm-ploop-bat.c b/drivers/md/dm-ploop-bat.c
> --- a/drivers/md/dm-ploop-bat.c
> +++ b/drivers/md/dm-ploop-bat.c
[ ... ]
> +int ploop_reload_metadata(struct ploop *ploop)
> +{
> + struct rb_root old_bat_entries = ploop->bat_entries;
> + void *old_holes_bitmap = ploop->holes_bitmap;
> + u32 old_nr_bat_entries = ploop->nr_bat_entries;
> + u32 old_hb_nr = ploop->hb_nr;
[ ... ]
> + old_deltas = kmemdup(ploop->deltas,
> + sizeof(*old_deltas) * ploop->nr_deltas,
> + GFP_KERNEL);
> + page = alloc_page(GFP_KERNEL);
[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?
[ ... ]
> + ploop->bat_entries = RB_ROOT;
> + ploop->holes_bitmap = NULL;
> +
> + /* Image is already checked for being in use in ploop_ctr() */
> + ret = ploop_setup_metadata(ploop, page, false);
> + if (ret)
> + goto restore;
[ ... ]
> +restore:
> + ploop_free_md_pages_tree(&ploop->bat_entries);
> + kvfree(ploop->holes_bitmap);
> + ploop->bat_entries = old_bat_entries;
> + ploop->holes_bitmap = old_holes_bitmap;
> + ploop->nr_bat_entries = old_nr_bat_entries;
> + ploop->hb_nr = old_hb_nr;
[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?
> diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c
> --- a/drivers/md/dm-ploop-map.c
> +++ b/drivers/md/dm-ploop-map.c
> @@ -1245,6 +1245,12 @@ static int ploop_no_pending_prealloc(struct ploop *ploop)
> return ret;
> }
>
> +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?
[ ... ]
> diff --git a/drivers/md/dm-ploop-target.c b/drivers/md/dm-ploop-target.c
> --- a/drivers/md/dm-ploop-target.c
> +++ b/drivers/md/dm-ploop-target.c
[ ... ]
> static void ploop_postsuspend(struct dm_target *ti)
> {
> + struct ploop *ploop = ti->private;
> +
> + /*
> + * Let the next resumed ploop (maybe of reloaded table)
> + * see final size of the top delta.
> + */
> + ploop_wait_prealloc(ploop);
> ploop_set_suspended(ti, true);
> }
[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?
[ ... ]
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261008073837.510678-1-alexander.ivanov@virtuozzo.com?part=5
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-10-08 7:55 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 [this message]
2026-10-08 11:46 ` Alexander Ivanov
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=010701a11a8199aa-30d1f207-f777-46d2-803b-193c675da792-000000@eu-central-1.amazonses.com \
--to=no-reply@sashiko.virtuozzo.com \
--cc=alexander.ivanov@virtuozzo.com \
--cc=den@virtuozzo.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox