diff options
Diffstat (limited to 'fs/signalfd.c')
| -rw-r--r-- | fs/signalfd.c | 76 | 
1 files changed, 70 insertions, 6 deletions
diff --git a/fs/signalfd.c b/fs/signalfd.c index 492465b451d..424b7b65321 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -29,6 +29,23 @@  #include <linux/anon_inodes.h>  #include <linux/signalfd.h>  #include <linux/syscalls.h> +#include <linux/proc_fs.h> +#include <linux/compat.h> + +void signalfd_cleanup(struct sighand_struct *sighand) +{ +	wait_queue_head_t *wqh = &sighand->signalfd_wqh; +	/* +	 * The lockless check can race with remove_wait_queue() in progress, +	 * but in this case its caller should run under rcu_read_lock() and +	 * sighand_cachep is SLAB_DESTROY_BY_RCU, we can safely return. +	 */ +	if (likely(!waitqueue_active(wqh))) +		return; + +	/* wait_queue_t->func(POLLFREE) should do remove_wait_queue() */ +	wake_up_poll(wqh, POLLHUP | POLLFREE); +}  struct signalfd_ctx {  	sigset_t sigmask; @@ -212,7 +229,24 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,  	return total ? total: ret;  } +#ifdef CONFIG_PROC_FS +static int signalfd_show_fdinfo(struct seq_file *m, struct file *f) +{ +	struct signalfd_ctx *ctx = f->private_data; +	sigset_t sigmask; + +	sigmask = ctx->sigmask; +	signotset(&sigmask); +	render_sigset_t(m, "sigmask:\t", &sigmask); + +	return 0; +} +#endif +  static const struct file_operations signalfd_fops = { +#ifdef CONFIG_PROC_FS +	.show_fdinfo	= signalfd_show_fdinfo, +#endif  	.release	= signalfd_release,  	.poll		= signalfd_poll,  	.read		= signalfd_read, @@ -254,12 +288,12 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,  		if (ufd < 0)  			kfree(ctx);  	} else { -		struct file *file = fget(ufd); -		if (!file) +		struct fd f = fdget(ufd); +		if (!f.file)  			return -EBADF; -		ctx = file->private_data; -		if (file->f_op != &signalfd_fops) { -			fput(file); +		ctx = f.file->private_data; +		if (f.file->f_op != &signalfd_fops) { +			fdput(f);  			return -EINVAL;  		}  		spin_lock_irq(¤t->sighand->siglock); @@ -267,7 +301,7 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,  		spin_unlock_irq(¤t->sighand->siglock);  		wake_up(¤t->sighand->signalfd_wqh); -		fput(file); +		fdput(f);  	}  	return ufd; @@ -278,3 +312,33 @@ SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask,  {  	return sys_signalfd4(ufd, user_mask, sizemask, 0);  } + +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd, +		     const compat_sigset_t __user *,sigmask, +		     compat_size_t, sigsetsize, +		     int, flags) +{ +	compat_sigset_t ss32; +	sigset_t tmp; +	sigset_t __user *ksigmask; + +	if (sigsetsize != sizeof(compat_sigset_t)) +		return -EINVAL; +	if (copy_from_user(&ss32, sigmask, sizeof(ss32))) +		return -EFAULT; +	sigset_from_compat(&tmp, &ss32); +	ksigmask = compat_alloc_user_space(sizeof(sigset_t)); +	if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t))) +		return -EFAULT; + +	return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags); +} + +COMPAT_SYSCALL_DEFINE3(signalfd, int, ufd, +		     const compat_sigset_t __user *,sigmask, +		     compat_size_t, sigsetsize) +{ +	return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0); +} +#endif  | 
