[Devel] [PATCH hci-8.1 v2 6/6] dm/push_backup: add event file descriptor interface
no-reply at sashiko.virtuozzo.com
no-reply at sashiko.virtuozzo.com
Tue Nov 3 03:46:46 MSK 2026
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] dm-push-backup: push_backup_get_fd() installs fd before result is delivered
- [Low] dm-push-backup: event fd has no .poll method, so it cannot be multiplexed
--
commit 586e161f2dd08e2697bfd3552aef44d435e3d52e
Author: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
dm/push_backup: add event file descriptor interface
This adds a "push_backup_get_fd" target message that returns an anon inode
fd. The backup tool can read() the next range to back up and write() to
acknowledge it, without sleeping inside a dm message. 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
[ ... ]
> +static const struct file_operations pb_fops = {
> + .owner = THIS_MODULE,
> + .read = pb_fd_read,
> + .write = pb_fd_write,
> + .release = pb_fd_release,
> +};
[Severity: Low]
This isn't a bug, but pb_fops provides no .poll method, although
pb->waitq and pb_has_event() already exist and could back one.
Without .poll, poll() and select() report the fd as always ready, and
epoll_ctl() rejects it.
A consumer that wants to multiplex the fd must dedicate a thread to a
blocking read(), or retry read() on -EAGAIN with O_NONBLOCK. The UAPI
header documents the O_NONBLOCK -EAGAIN mode, but without .poll it is hard
to use.
Would it make sense to add .poll before the UAPI is finalized?
There is also no .llseek or stream_open(), so the fd is seekable even though
f_pos is meaningless. Should this be a stream-like file?
> +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: Medium]
Can this leak a file descriptor in the calling process?
anon_inode_getfd() calls fd_install() before the result is known to be
deliverable. After that, DMEMIT("%d", fd) only formats into the kernel
result buffer. It silently truncates if maxlen is too small, and
push_backup_get_fd() still returns 1.
If the DMEMIT output is truncated, or the dm ioctl core later fails to copy
the result out to userspace, the caller never learns the fd number:
pb_message()
push_backup_get_fd()
kref_get(&pb->ref);
anon_inode_getfd() <- fd_install() already done
DMEMIT("%d", fd); <- may truncate
return 1;
The caller cannot close that fd. The fd keeps its kref on struct push_backup
and a module reference, so the target memory and the module stay pinned until
the process exits.
Would it be better to reserve the fd with get_unused_fd_flags(), check that
the result fits, and call fd_install() last?
[ ... ]
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261103003246.712239-1-andrey.zhadchenko@virtuozzo.com?part=6
More information about the Devel
mailing list