mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	signalfd: convert to ->read_iter()
Rather than use the older style ->read() hook, use ->read_iter() so that signalfd can support both O_NONBLOCK and IOCB_NOWAIT for non-blocking read attempts. Split the fd setup into two parts, so that signalfd can mark the file mode with FMODE_NOWAIT before installing it into the process table. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									40f45fe8eb
								
							
						
					
					
						commit
						fbe38120eb
					
				
					 1 changed files with 28 additions and 16 deletions
				
			
		| 
						 | 
					@ -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
 | 
					 * Copied from copy_siginfo_to_user() in kernel/signal.c
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
 | 
					static int signalfd_copyinfo(struct iov_iter *to, kernel_siginfo_t const *kinfo)
 | 
				
			||||||
			     kernel_siginfo_t const *kinfo)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct signalfd_siginfo new;
 | 
						struct signalfd_siginfo new;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,10 +145,10 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
 | 
				
			||||||
		break;
 | 
							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 -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sizeof(*uinfo);
 | 
						return sizeof(struct signalfd_siginfo);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info,
 | 
					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
 | 
					 * error code. The "count" parameter must be at least the size of a
 | 
				
			||||||
 * "struct signalfd_siginfo".
 | 
					 * "struct signalfd_siginfo".
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
 | 
					static ssize_t signalfd_read_iter(struct kiocb *iocb, struct iov_iter *to)
 | 
				
			||||||
			     loff_t *ppos)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct file *file = iocb->ki_filp;
 | 
				
			||||||
	struct signalfd_ctx *ctx = file->private_data;
 | 
						struct signalfd_ctx *ctx = file->private_data;
 | 
				
			||||||
	struct signalfd_siginfo __user *siginfo;
 | 
						size_t count = iov_iter_count(to);
 | 
				
			||||||
	int nonblock = file->f_flags & O_NONBLOCK;
 | 
					 | 
				
			||||||
	ssize_t ret, total = 0;
 | 
						ssize_t ret, total = 0;
 | 
				
			||||||
	kernel_siginfo_t info;
 | 
						kernel_siginfo_t info;
 | 
				
			||||||
 | 
						bool nonblock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	count /= sizeof(struct signalfd_siginfo);
 | 
						count /= sizeof(struct signalfd_siginfo);
 | 
				
			||||||
	if (!count)
 | 
						if (!count)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	siginfo = (struct signalfd_siginfo __user *) buf;
 | 
						nonblock = file->f_flags & O_NONBLOCK || iocb->ki_flags & IOCB_NOWAIT;
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		ret = signalfd_dequeue(ctx, &info, nonblock);
 | 
							ret = signalfd_dequeue(ctx, &info, nonblock);
 | 
				
			||||||
		if (unlikely(ret <= 0))
 | 
							if (unlikely(ret <= 0))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		ret = signalfd_copyinfo(siginfo, &info);
 | 
							ret = signalfd_copyinfo(to, &info);
 | 
				
			||||||
		if (ret < 0)
 | 
							if (ret < 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		siginfo++;
 | 
					 | 
				
			||||||
		total += ret;
 | 
							total += ret;
 | 
				
			||||||
		nonblock = 1;
 | 
							nonblock = 1;
 | 
				
			||||||
	} while (--count);
 | 
						} while (--count);
 | 
				
			||||||
| 
						 | 
					@ -246,7 +244,7 @@ static const struct file_operations signalfd_fops = {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	.release	= signalfd_release,
 | 
						.release	= signalfd_release,
 | 
				
			||||||
	.poll		= signalfd_poll,
 | 
						.poll		= signalfd_poll,
 | 
				
			||||||
	.read		= signalfd_read,
 | 
						.read_iter	= signalfd_read_iter,
 | 
				
			||||||
	.llseek		= noop_llseek,
 | 
						.llseek		= noop_llseek,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,20 +263,34 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags)
 | 
				
			||||||
	signotset(mask);
 | 
						signotset(mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ufd == -1) {
 | 
						if (ufd == -1) {
 | 
				
			||||||
 | 
							struct file *file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
 | 
							ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
 | 
				
			||||||
		if (!ctx)
 | 
							if (!ctx)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx->sigmask = *mask;
 | 
							ctx->sigmask = *mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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 ufd;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							file->f_mode |= FMODE_NOWAIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * When we call this, the initialization must be complete, since
 | 
							 * When we call this, the initialization must be complete, since
 | 
				
			||||||
		 * anon_inode_getfd() will install the fd.
 | 
							 * anon_inode_getfd() will install the fd.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx,
 | 
							fd_install(ufd, file);
 | 
				
			||||||
				       O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK)));
 | 
					 | 
				
			||||||
		if (ufd < 0)
 | 
					 | 
				
			||||||
			kfree(ctx);
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		struct fd f = fdget(ufd);
 | 
							struct fd f = fdget(ufd);
 | 
				
			||||||
		if (!f.file)
 | 
							if (!f.file)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue