diff options
Diffstat (limited to 'net/socket.c')
| -rw-r--r-- | net/socket.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/net/socket.c b/net/socket.c index ac2219f90d5d..937d0fcf74bc 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -240,17 +240,19 @@ static struct kmem_cache *sock_inode_cachep __read_mostly; | |||
| 240 | static struct inode *sock_alloc_inode(struct super_block *sb) | 240 | static struct inode *sock_alloc_inode(struct super_block *sb) |
| 241 | { | 241 | { |
| 242 | struct socket_alloc *ei; | 242 | struct socket_alloc *ei; |
| 243 | struct socket_wq *wq; | ||
| 243 | 244 | ||
| 244 | ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); | 245 | ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); |
| 245 | if (!ei) | 246 | if (!ei) |
| 246 | return NULL; | 247 | return NULL; |
| 247 | ei->socket.wq = kmalloc(sizeof(struct socket_wq), GFP_KERNEL); | 248 | wq = kmalloc(sizeof(*wq), GFP_KERNEL); |
| 248 | if (!ei->socket.wq) { | 249 | if (!wq) { |
| 249 | kmem_cache_free(sock_inode_cachep, ei); | 250 | kmem_cache_free(sock_inode_cachep, ei); |
| 250 | return NULL; | 251 | return NULL; |
| 251 | } | 252 | } |
| 252 | init_waitqueue_head(&ei->socket.wq->wait); | 253 | init_waitqueue_head(&wq->wait); |
| 253 | ei->socket.wq->fasync_list = NULL; | 254 | wq->fasync_list = NULL; |
| 255 | RCU_INIT_POINTER(ei->socket.wq, wq); | ||
| 254 | 256 | ||
| 255 | ei->socket.state = SS_UNCONNECTED; | 257 | ei->socket.state = SS_UNCONNECTED; |
| 256 | ei->socket.flags = 0; | 258 | ei->socket.flags = 0; |
| @@ -273,9 +275,11 @@ static void wq_free_rcu(struct rcu_head *head) | |||
| 273 | static void sock_destroy_inode(struct inode *inode) | 275 | static void sock_destroy_inode(struct inode *inode) |
| 274 | { | 276 | { |
| 275 | struct socket_alloc *ei; | 277 | struct socket_alloc *ei; |
| 278 | struct socket_wq *wq; | ||
| 276 | 279 | ||
| 277 | ei = container_of(inode, struct socket_alloc, vfs_inode); | 280 | ei = container_of(inode, struct socket_alloc, vfs_inode); |
| 278 | call_rcu(&ei->socket.wq->rcu, wq_free_rcu); | 281 | wq = rcu_dereference_protected(ei->socket.wq, 1); |
| 282 | call_rcu(&wq->rcu, wq_free_rcu); | ||
| 279 | kmem_cache_free(sock_inode_cachep, ei); | 283 | kmem_cache_free(sock_inode_cachep, ei); |
| 280 | } | 284 | } |
| 281 | 285 | ||
| @@ -524,7 +528,7 @@ void sock_release(struct socket *sock) | |||
| 524 | module_put(owner); | 528 | module_put(owner); |
| 525 | } | 529 | } |
| 526 | 530 | ||
| 527 | if (sock->wq->fasync_list) | 531 | if (rcu_dereference_protected(sock->wq, 1)->fasync_list) |
| 528 | printk(KERN_ERR "sock_release: fasync list not empty!\n"); | 532 | printk(KERN_ERR "sock_release: fasync list not empty!\n"); |
| 529 | 533 | ||
| 530 | percpu_sub(sockets_in_use, 1); | 534 | percpu_sub(sockets_in_use, 1); |
| @@ -1108,15 +1112,16 @@ static int sock_fasync(int fd, struct file *filp, int on) | |||
| 1108 | { | 1112 | { |
| 1109 | struct socket *sock = filp->private_data; | 1113 | struct socket *sock = filp->private_data; |
| 1110 | struct sock *sk = sock->sk; | 1114 | struct sock *sk = sock->sk; |
| 1115 | struct socket_wq *wq; | ||
| 1111 | 1116 | ||
| 1112 | if (sk == NULL) | 1117 | if (sk == NULL) |
| 1113 | return -EINVAL; | 1118 | return -EINVAL; |
| 1114 | 1119 | ||
| 1115 | lock_sock(sk); | 1120 | lock_sock(sk); |
| 1121 | wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk)); | ||
| 1122 | fasync_helper(fd, filp, on, &wq->fasync_list); | ||
| 1116 | 1123 | ||
| 1117 | fasync_helper(fd, filp, on, &sock->wq->fasync_list); | 1124 | if (!wq->fasync_list) |
| 1118 | |||
| 1119 | if (!sock->wq->fasync_list) | ||
| 1120 | sock_reset_flag(sk, SOCK_FASYNC); | 1125 | sock_reset_flag(sk, SOCK_FASYNC); |
| 1121 | else | 1126 | else |
| 1122 | sock_set_flag(sk, SOCK_FASYNC); | 1127 | sock_set_flag(sk, SOCK_FASYNC); |
| @@ -2643,7 +2648,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd, | |||
| 2643 | 2648 | ||
| 2644 | old_fs = get_fs(); | 2649 | old_fs = get_fs(); |
| 2645 | set_fs(KERNEL_DS); | 2650 | set_fs(KERNEL_DS); |
| 2646 | err = dev_ioctl(net, cmd, &kifr); | 2651 | err = dev_ioctl(net, cmd, |
| 2652 | (struct ifreq __user __force *) &kifr); | ||
| 2647 | set_fs(old_fs); | 2653 | set_fs(old_fs); |
| 2648 | 2654 | ||
| 2649 | return err; | 2655 | return err; |
| @@ -2752,7 +2758,7 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd, | |||
| 2752 | 2758 | ||
| 2753 | old_fs = get_fs(); | 2759 | old_fs = get_fs(); |
| 2754 | set_fs(KERNEL_DS); | 2760 | set_fs(KERNEL_DS); |
| 2755 | err = dev_ioctl(net, cmd, (void __user *)&ifr); | 2761 | err = dev_ioctl(net, cmd, (void __user __force *)&ifr); |
| 2756 | set_fs(old_fs); | 2762 | set_fs(old_fs); |
| 2757 | 2763 | ||
| 2758 | if (cmd == SIOCGIFMAP && !err) { | 2764 | if (cmd == SIOCGIFMAP && !err) { |
| @@ -2857,7 +2863,8 @@ static int routing_ioctl(struct net *net, struct socket *sock, | |||
| 2857 | ret |= __get_user(rtdev, &(ur4->rt_dev)); | 2863 | ret |= __get_user(rtdev, &(ur4->rt_dev)); |
| 2858 | if (rtdev) { | 2864 | if (rtdev) { |
| 2859 | ret |= copy_from_user(devname, compat_ptr(rtdev), 15); | 2865 | ret |= copy_from_user(devname, compat_ptr(rtdev), 15); |
| 2860 | r4.rt_dev = devname; devname[15] = 0; | 2866 | r4.rt_dev = (char __user __force *)devname; |
| 2867 | devname[15] = 0; | ||
| 2861 | } else | 2868 | } else |
| 2862 | r4.rt_dev = NULL; | 2869 | r4.rt_dev = NULL; |
| 2863 | 2870 | ||
