diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:17:52 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:17:52 +0000 |
commit | 3afb00d3f86d3d924f88b56fa8285d4e9db85852 (patch) | |
tree | 95a985d3019522cea546b7d8df621369bc44fc6c /fs/signalfd.c | |
parent | Adding debian version 6.9.12-1. (diff) | |
download | linux-3afb00d3f86d3d924f88b56fa8285d4e9db85852.tar.xz linux-3afb00d3f86d3d924f88b56fa8285d4e9db85852.zip |
Merging upstream version 6.10.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fs/signalfd.c')
-rw-r--r-- | fs/signalfd.c | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/fs/signalfd.c b/fs/signalfd.c index e20d1484c6..ec7b2da247 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -68,8 +68,7 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait) /* * Copied from copy_siginfo_to_user() in kernel/signal.c */ -static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, - kernel_siginfo_t const *kinfo) +static int signalfd_copyinfo(struct iov_iter *to, kernel_siginfo_t const *kinfo) { struct signalfd_siginfo new; @@ -146,10 +145,10 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, break; } - if (copy_to_user(uinfo, &new, sizeof(struct signalfd_siginfo))) + if (!copy_to_iter_full(&new, sizeof(struct signalfd_siginfo), to)) return -EFAULT; - return sizeof(*uinfo); + return sizeof(struct signalfd_siginfo); } static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info, @@ -199,28 +198,27 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info * error code. The "count" parameter must be at least the size of a * "struct signalfd_siginfo". */ -static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) +static ssize_t signalfd_read_iter(struct kiocb *iocb, struct iov_iter *to) { + struct file *file = iocb->ki_filp; struct signalfd_ctx *ctx = file->private_data; - struct signalfd_siginfo __user *siginfo; - int nonblock = file->f_flags & O_NONBLOCK; + size_t count = iov_iter_count(to); ssize_t ret, total = 0; kernel_siginfo_t info; + bool nonblock; count /= sizeof(struct signalfd_siginfo); if (!count) return -EINVAL; - siginfo = (struct signalfd_siginfo __user *) buf; + nonblock = file->f_flags & O_NONBLOCK || iocb->ki_flags & IOCB_NOWAIT; do { ret = signalfd_dequeue(ctx, &info, nonblock); if (unlikely(ret <= 0)) break; - ret = signalfd_copyinfo(siginfo, &info); + ret = signalfd_copyinfo(to, &info); if (ret < 0) break; - siginfo++; total += ret; nonblock = 1; } while (--count); @@ -246,7 +244,7 @@ static const struct file_operations signalfd_fops = { #endif .release = signalfd_release, .poll = signalfd_poll, - .read = signalfd_read, + .read_iter = signalfd_read_iter, .llseek = noop_llseek, }; @@ -265,20 +263,30 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags) signotset(mask); if (ufd == -1) { + struct file *file; + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; ctx->sigmask = *mask; - /* - * When we call this, the initialization must be complete, since - * anon_inode_getfd() will install the fd. - */ - ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx, - O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK))); - if (ufd < 0) + ufd = get_unused_fd_flags(flags & O_CLOEXEC); + if (ufd < 0) { + kfree(ctx); + return ufd; + } + + file = anon_inode_getfile("[signalfd]", &signalfd_fops, ctx, + O_RDWR | (flags & O_NONBLOCK)); + if (IS_ERR(file)) { + put_unused_fd(ufd); kfree(ctx); + return PTR_ERR(file); + } + file->f_mode |= FMODE_NOWAIT; + + fd_install(ufd, file); } else { struct fd f = fdget(ufd); if (!f.file) |