From: no-reply@sashiko.virtuozzo.com
To: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>,
alexander.ivanov@virtuozzo.com
Cc: devel@openvz.org
Subject: Re: [Devel] [PATCH hci-8.1 5/5] dm/push_backup: add event file descriptor interface
Date: Mon, 2 Nov 2026 23:51:46 +0000 [thread overview]
Message-ID: <010701a19ead1814-f91bb2ed-49ad-43c2-a9ba-0af34cc638ef-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261102233849.613155-6-andrey.zhadchenko@virtuozzo.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] dm-push-backup: fd write races pb_destroy() and uses freed pbio_pool in resubmit_pbios()
- [Low] dm-push-backup: push_backup_get_fd() installs fd before result is delivered
- [Low] dm-push-backup: event fd has no .poll handler, so it cannot be polled
--
commit 013b902b0f480dc76bc700b18a002953deb80967
Author: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
dm/push_backup: add event file descriptor interface
This patch adds an anon-inode file descriptor interface to dm-push-backup.
The fd is obtained with a new push_backup_get_fd target message. Userspace
then uses read() to get the next cluster range to back up and write() to
acknowledge it. A kref on struct push_backup is tied to the number of open
fds.
Link: https://virtuozzo.atlassian.net/browse/VSTOR-152912
> diff --git a/drivers/md/dm-push-backup.c b/drivers/md/dm-push-backup.c
> --- a/drivers/md/dm-push-backup.c
> +++ b/drivers/md/dm-push-backup.c
[ ... ]
> @@ -534,6 +591,73 @@ static int push_backup_write(struct push_backup *pb,
> return 0;
> }
>
> +static ssize_t pb_fd_write(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + struct push_backup *pb = file->private_data;
> + struct push_backup_range range;
> + int ret;
> +
> + if (count != sizeof(range))
> + return -EINVAL;
> + if (copy_from_user(&range, buf, sizeof(range)))
> + return -EFAULT;
> +
> + ret = push_backup_write(pb, range.clu, range.nr);
> + return ret ? : sizeof(range);
> +}
[Severity: High]
Can this race with pb_destroy() and use freed memory?
Before this patch, push_backup_write() was reachable only through
pb_message(), which runs under dm_get_live_table() and ctl_rwsem, so it
could not overlap the target destructor. Now pb_fd_write() calls it with
neither.
The dead check in push_backup_write() is made under pb->lock, but
resubmit_pbios() runs after the lock is dropped:
push_backup_write()
spin_unlock_irq(&pb->lock);
...
if (!list_empty(&pbio_list))
resubmit_pbios(pb, &pbio_list);
resubmit_pbios()
list_del_init(&pbio->list);
dm_requeue_original_rq(pbio->rq);
mempool_free(pbio, pb->pbio_pool);
If pb_destroy() runs on another CPU after the writer has unlinked the
pbios and dropped the lock, it can proceed as follows:
pb_destroy()
spin_lock_irq(&pb->lock);
pb->dead = true;
...
spin_unlock_irq(&pb->lock);
...
destroy_workqueue(pb->wq);
kvfree(pb->pending_htable);
mempool_destroy(pb->pbio_pool);
...
pb_put(pb);
The writer would then call mempool_free() on a pbio_pool that
mempool_destroy() has already freed. WARN_ON_ONCE(pb->nr_delayed) in
pb_destroy() would not fire in this case, because the writer has already
decremented nr_delayed.
The new kref keeps only the struct push_backup allocation alive. It does not
keep pbio_pool, pending_htable, wq or origin_dev alive. pb_destroy() does
not wait for fd readers or writers that have already passed the dead check.
The fd can also be inherited or passed to a process other than the one that
opened it. Also, __dm_destroy() suspends the device without draining
postponed requests, so pending pbios can exist when dtr runs.
Is there something that serializes pb_fd_write() against pb_destroy(), for
example draining in-flight fd operations before freeing the sub-resources?
> +static int pb_fd_release(struct inode *inode, struct file *file)
> +{
> + pb_put(file->private_data);
> + return 0;
> +}
> +
> +static const struct file_operations pb_fops = {
> + .owner = THIS_MODULE,
> + .read = pb_fd_read,
> + .write = pb_fd_write,
> + .release = pb_fd_release,
> +};
[Severity: Low]
The interface is described as an event file descriptor, but pb_fops has no
.poll callback.
Can a backup tool multiplex this fd with its other I/O? As written, it can
only block in read() or busy-poll with O_NONBLOCK and get -EAGAIN.
pb_has_event() and pb->waitq already exist and look like a natural basis
for a poll handler. Would it make sense to add .poll before the UAPI is
fixed? Adding it later is harder because read() does not consume anything
and returns 0 to mean "finished".
> +static int push_backup_get_fd(struct push_backup *pb,
> + char *result, unsigned int maxlen)
> +{
> + unsigned int sz = 0;
> + int fd;
> +
> + kref_get(&pb->ref);
> + fd = anon_inode_getfd("[push_backup]", &pb_fops, pb,
> + O_RDWR | O_CLOEXEC);
> + if (fd < 0) {
> + pb_put(pb);
> + return fd;
> + }
> +
> + DMEMIT("%d", fd);
> + return 1;
> +}
[Severity: Low]
Can this leak the fd when the result is not delivered?
anon_inode_getfd() does fd_install() irrevocably. DMEMIT() never reports
truncation, so push_backup_get_fd() returns 1 even if the result buffer is
too small and the fd number is truncated or omitted. The same applies if the
dm-ioctl copy-out fails afterwards.
In those cases the caller never learns the fd number, and the open fd
continues to hold a pb kref and a module reference through pb_fops.owner
until the process exits.
Would it be better to check maxlen before creating the fd, or to use
get_unused_fd_flags() and call fd_install() only after the result has been
formatted?
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261102233849.613155-1-andrey.zhadchenko@virtuozzo.com?part=5
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
prev parent reply other threads:[~2026-11-02 23:53 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 23:38 [Devel] [PATCH 0/5] dm/push_backup: event fd interface and fixes Andrey Zhadchenko
2026-11-02 23:38 ` [Devel] [PATCH hci-8.1 1/5] drivers/md/push_backup: correct initialization Andrey Zhadchenko
2026-11-02 23:46 ` no-reply
2026-11-02 23:38 ` [Devel] [PATCH hci-8.1 2/5] drivers/md/push_backup: clear pb->alive under pb->lock Andrey Zhadchenko
2026-11-02 23:47 ` no-reply
2026-11-02 23:38 ` [Devel] [PATCH hci-8.1 3/5] drivers/md/push_backup: do not re-arm deadline timer in push_backup_write() Andrey Zhadchenko
2026-11-02 23:48 ` no-reply
2026-11-02 23:38 ` [Devel] [PATCH hci-8.1 4/5] drivers/md/push_backup: fix mod_timer() usage Andrey Zhadchenko
2026-11-02 23:47 ` no-reply
2026-11-02 23:38 ` [Devel] [PATCH hci-8.1 5/5] dm/push_backup: add event file descriptor interface Andrey Zhadchenko
2026-11-02 23:51 ` no-reply [this message]
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=010701a19ead1814-f91bb2ed-49ad-43c2-a9ba-0af34cc638ef-000000@eu-central-1.amazonses.com \
--to=no-reply@sashiko.virtuozzo.com \
--cc=alexander.ivanov@virtuozzo.com \
--cc=andrey.zhadchenko@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 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.