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
 | 
			
		||||
 */
 | 
			
		||||
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,34 @@ 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;
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
		 * 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)
 | 
			
		||||
			kfree(ctx);
 | 
			
		||||
		fd_install(ufd, file);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct fd f = fdget(ufd);
 | 
			
		||||
		if (!f.file)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue