aboutsummaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c123
1 files changed, 48 insertions, 75 deletions
diff --git a/net/socket.c b/net/socket.c
index 5e8d0af3c0e7..f9f7d0872cac 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -252,9 +252,14 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
252 ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); 252 ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
253 if (!ei) 253 if (!ei)
254 return NULL; 254 return NULL;
255 init_waitqueue_head(&ei->socket.wait); 255 ei->socket.wq = kmalloc(sizeof(struct socket_wq), GFP_KERNEL);
256 if (!ei->socket.wq) {
257 kmem_cache_free(sock_inode_cachep, ei);
258 return NULL;
259 }
260 init_waitqueue_head(&ei->socket.wq->wait);
261 ei->socket.wq->fasync_list = NULL;
256 262
257 ei->socket.fasync_list = NULL;
258 ei->socket.state = SS_UNCONNECTED; 263 ei->socket.state = SS_UNCONNECTED;
259 ei->socket.flags = 0; 264 ei->socket.flags = 0;
260 ei->socket.ops = NULL; 265 ei->socket.ops = NULL;
@@ -264,10 +269,21 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
264 return &ei->vfs_inode; 269 return &ei->vfs_inode;
265} 270}
266 271
272
273static void wq_free_rcu(struct rcu_head *head)
274{
275 struct socket_wq *wq = container_of(head, struct socket_wq, rcu);
276
277 kfree(wq);
278}
279
267static void sock_destroy_inode(struct inode *inode) 280static void sock_destroy_inode(struct inode *inode)
268{ 281{
269 kmem_cache_free(sock_inode_cachep, 282 struct socket_alloc *ei;
270 container_of(inode, struct socket_alloc, vfs_inode)); 283
284 ei = container_of(inode, struct socket_alloc, vfs_inode);
285 call_rcu(&ei->socket.wq->rcu, wq_free_rcu);
286 kmem_cache_free(sock_inode_cachep, ei);
271} 287}
272 288
273static void init_once(void *foo) 289static void init_once(void *foo)
@@ -513,7 +529,7 @@ void sock_release(struct socket *sock)
513 module_put(owner); 529 module_put(owner);
514 } 530 }
515 531
516 if (sock->fasync_list) 532 if (sock->wq->fasync_list)
517 printk(KERN_ERR "sock_release: fasync list not empty!\n"); 533 printk(KERN_ERR "sock_release: fasync list not empty!\n");
518 534
519 percpu_sub(sockets_in_use, 1); 535 percpu_sub(sockets_in_use, 1);
@@ -620,10 +636,9 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
620 put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, 636 put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
621 sizeof(tv), &tv); 637 sizeof(tv), &tv);
622 } else { 638 } else {
623 struct timespec ts; 639 skb_get_timestampns(skb, &ts[0]);
624 skb_get_timestampns(skb, &ts);
625 put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, 640 put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
626 sizeof(ts), &ts); 641 sizeof(ts[0]), &ts[0]);
627 } 642 }
628 } 643 }
629 644
@@ -656,13 +671,13 @@ inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff
656 sizeof(__u32), &skb->dropcount); 671 sizeof(__u32), &skb->dropcount);
657} 672}
658 673
659void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, 674void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
660 struct sk_buff *skb) 675 struct sk_buff *skb)
661{ 676{
662 sock_recv_timestamp(msg, sk, skb); 677 sock_recv_timestamp(msg, sk, skb);
663 sock_recv_drops(msg, sk, skb); 678 sock_recv_drops(msg, sk, skb);
664} 679}
665EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops); 680EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops);
666 681
667static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, 682static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
668 struct msghdr *msg, size_t size, int flags) 683 struct msghdr *msg, size_t size, int flags)
@@ -1068,87 +1083,44 @@ static int sock_close(struct inode *inode, struct file *filp)
1068 * 1. fasync_list is modified only under process context socket lock 1083 * 1. fasync_list is modified only under process context socket lock
1069 * i.e. under semaphore. 1084 * i.e. under semaphore.
1070 * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) 1085 * 2. fasync_list is used under read_lock(&sk->sk_callback_lock)
1071 * or under socket lock. 1086 * or under socket lock
1072 * 3. fasync_list can be used from softirq context, so that
1073 * modification under socket lock have to be enhanced with
1074 * write_lock_bh(&sk->sk_callback_lock).
1075 * --ANK (990710)
1076 */ 1087 */
1077 1088
1078static int sock_fasync(int fd, struct file *filp, int on) 1089static int sock_fasync(int fd, struct file *filp, int on)
1079{ 1090{
1080 struct fasync_struct *fa, *fna = NULL, **prev; 1091 struct socket *sock = filp->private_data;
1081 struct socket *sock; 1092 struct sock *sk = sock->sk;
1082 struct sock *sk;
1083
1084 if (on) {
1085 fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
1086 if (fna == NULL)
1087 return -ENOMEM;
1088 }
1089
1090 sock = filp->private_data;
1091 1093
1092 sk = sock->sk; 1094 if (sk == NULL)
1093 if (sk == NULL) {
1094 kfree(fna);
1095 return -EINVAL; 1095 return -EINVAL;
1096 }
1097 1096
1098 lock_sock(sk); 1097 lock_sock(sk);
1099 1098
1100 spin_lock(&filp->f_lock); 1099 fasync_helper(fd, filp, on, &sock->wq->fasync_list);
1101 if (on)
1102 filp->f_flags |= FASYNC;
1103 else
1104 filp->f_flags &= ~FASYNC;
1105 spin_unlock(&filp->f_lock);
1106 1100
1107 prev = &(sock->fasync_list); 1101 if (!sock->wq->fasync_list)
1108 1102 sock_reset_flag(sk, SOCK_FASYNC);
1109 for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev) 1103 else
1110 if (fa->fa_file == filp)
1111 break;
1112
1113 if (on) {
1114 if (fa != NULL) {
1115 write_lock_bh(&sk->sk_callback_lock);
1116 fa->fa_fd = fd;
1117 write_unlock_bh(&sk->sk_callback_lock);
1118
1119 kfree(fna);
1120 goto out;
1121 }
1122 fna->fa_file = filp;
1123 fna->fa_fd = fd;
1124 fna->magic = FASYNC_MAGIC;
1125 fna->fa_next = sock->fasync_list;
1126 write_lock_bh(&sk->sk_callback_lock);
1127 sock->fasync_list = fna;
1128 sock_set_flag(sk, SOCK_FASYNC); 1104 sock_set_flag(sk, SOCK_FASYNC);
1129 write_unlock_bh(&sk->sk_callback_lock);
1130 } else {
1131 if (fa != NULL) {
1132 write_lock_bh(&sk->sk_callback_lock);
1133 *prev = fa->fa_next;
1134 if (!sock->fasync_list)
1135 sock_reset_flag(sk, SOCK_FASYNC);
1136 write_unlock_bh(&sk->sk_callback_lock);
1137 kfree(fa);
1138 }
1139 }
1140 1105
1141out: 1106 release_sock(sk);
1142 release_sock(sock->sk);
1143 return 0; 1107 return 0;
1144} 1108}
1145 1109
1146/* This function may be called only under socket lock or callback_lock */ 1110/* This function may be called only under socket lock or callback_lock or rcu_lock */
1147 1111
1148int sock_wake_async(struct socket *sock, int how, int band) 1112int sock_wake_async(struct socket *sock, int how, int band)
1149{ 1113{
1150 if (!sock || !sock->fasync_list) 1114 struct socket_wq *wq;
1115
1116 if (!sock)
1151 return -1; 1117 return -1;
1118 rcu_read_lock();
1119 wq = rcu_dereference(sock->wq);
1120 if (!wq || !wq->fasync_list) {
1121 rcu_read_unlock();
1122 return -1;
1123 }
1152 switch (how) { 1124 switch (how) {
1153 case SOCK_WAKE_WAITD: 1125 case SOCK_WAKE_WAITD:
1154 if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) 1126 if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
@@ -1160,11 +1132,12 @@ int sock_wake_async(struct socket *sock, int how, int band)
1160 /* fall through */ 1132 /* fall through */
1161 case SOCK_WAKE_IO: 1133 case SOCK_WAKE_IO:
1162call_kill: 1134call_kill:
1163 __kill_fasync(sock->fasync_list, SIGIO, band); 1135 kill_fasync(&wq->fasync_list, SIGIO, band);
1164 break; 1136 break;
1165 case SOCK_WAKE_URG: 1137 case SOCK_WAKE_URG:
1166 __kill_fasync(sock->fasync_list, SIGURG, band); 1138 kill_fasync(&wq->fasync_list, SIGURG, band);
1167 } 1139 }
1140 rcu_read_unlock();
1168 return 0; 1141 return 0;
1169} 1142}
1170 1143
@@ -2642,7 +2615,7 @@ static int bond_ioctl(struct net *net, unsigned int cmd,
2642 return dev_ioctl(net, cmd, uifr); 2615 return dev_ioctl(net, cmd, uifr);
2643 default: 2616 default:
2644 return -EINVAL; 2617 return -EINVAL;
2645 }; 2618 }
2646} 2619}
2647 2620
2648static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, 2621static int siocdevprivate_ioctl(struct net *net, unsigned int cmd,