diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 126 |
1 files changed, 52 insertions, 74 deletions
diff --git a/net/socket.c b/net/socket.c index 769c386bd428..dae8c6b84a09 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -87,6 +87,7 @@ | |||
87 | #include <linux/wireless.h> | 87 | #include <linux/wireless.h> |
88 | #include <linux/nsproxy.h> | 88 | #include <linux/nsproxy.h> |
89 | #include <linux/magic.h> | 89 | #include <linux/magic.h> |
90 | #include <linux/slab.h> | ||
90 | 91 | ||
91 | #include <asm/uaccess.h> | 92 | #include <asm/uaccess.h> |
92 | #include <asm/unistd.h> | 93 | #include <asm/unistd.h> |
@@ -251,9 +252,14 @@ static struct inode *sock_alloc_inode(struct super_block *sb) | |||
251 | ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); | 252 | ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); |
252 | if (!ei) | 253 | if (!ei) |
253 | return NULL; | 254 | return NULL; |
254 | 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; | ||
255 | 262 | ||
256 | ei->socket.fasync_list = NULL; | ||
257 | ei->socket.state = SS_UNCONNECTED; | 263 | ei->socket.state = SS_UNCONNECTED; |
258 | ei->socket.flags = 0; | 264 | ei->socket.flags = 0; |
259 | ei->socket.ops = NULL; | 265 | ei->socket.ops = NULL; |
@@ -263,10 +269,21 @@ static struct inode *sock_alloc_inode(struct super_block *sb) | |||
263 | return &ei->vfs_inode; | 269 | return &ei->vfs_inode; |
264 | } | 270 | } |
265 | 271 | ||
272 | |||
273 | static 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 | |||
266 | static void sock_destroy_inode(struct inode *inode) | 280 | static void sock_destroy_inode(struct inode *inode) |
267 | { | 281 | { |
268 | kmem_cache_free(sock_inode_cachep, | 282 | struct socket_alloc *ei; |
269 | 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); | ||
270 | } | 287 | } |
271 | 288 | ||
272 | static void init_once(void *foo) | 289 | static void init_once(void *foo) |
@@ -512,7 +529,7 @@ void sock_release(struct socket *sock) | |||
512 | module_put(owner); | 529 | module_put(owner); |
513 | } | 530 | } |
514 | 531 | ||
515 | if (sock->fasync_list) | 532 | if (sock->wq->fasync_list) |
516 | printk(KERN_ERR "sock_release: fasync list not empty!\n"); | 533 | printk(KERN_ERR "sock_release: fasync list not empty!\n"); |
517 | 534 | ||
518 | percpu_sub(sockets_in_use, 1); | 535 | percpu_sub(sockets_in_use, 1); |
@@ -619,10 +636,9 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, | |||
619 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, | 636 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, |
620 | sizeof(tv), &tv); | 637 | sizeof(tv), &tv); |
621 | } else { | 638 | } else { |
622 | struct timespec ts; | 639 | skb_get_timestampns(skb, &ts[0]); |
623 | skb_get_timestampns(skb, &ts); | ||
624 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, | 640 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, |
625 | sizeof(ts), &ts); | 641 | sizeof(ts[0]), &ts[0]); |
626 | } | 642 | } |
627 | } | 643 | } |
628 | 644 | ||
@@ -655,13 +671,13 @@ inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff | |||
655 | sizeof(__u32), &skb->dropcount); | 671 | sizeof(__u32), &skb->dropcount); |
656 | } | 672 | } |
657 | 673 | ||
658 | void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, | 674 | void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, |
659 | struct sk_buff *skb) | 675 | struct sk_buff *skb) |
660 | { | 676 | { |
661 | sock_recv_timestamp(msg, sk, skb); | 677 | sock_recv_timestamp(msg, sk, skb); |
662 | sock_recv_drops(msg, sk, skb); | 678 | sock_recv_drops(msg, sk, skb); |
663 | } | 679 | } |
664 | EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops); | 680 | EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); |
665 | 681 | ||
666 | static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, | 682 | static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, |
667 | struct msghdr *msg, size_t size, int flags) | 683 | struct msghdr *msg, size_t size, int flags) |
@@ -1067,87 +1083,44 @@ static int sock_close(struct inode *inode, struct file *filp) | |||
1067 | * 1. fasync_list is modified only under process context socket lock | 1083 | * 1. fasync_list is modified only under process context socket lock |
1068 | * i.e. under semaphore. | 1084 | * i.e. under semaphore. |
1069 | * 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) |
1070 | * or under socket lock. | 1086 | * or under socket lock |
1071 | * 3. fasync_list can be used from softirq context, so that | ||
1072 | * modification under socket lock have to be enhanced with | ||
1073 | * write_lock_bh(&sk->sk_callback_lock). | ||
1074 | * --ANK (990710) | ||
1075 | */ | 1087 | */ |
1076 | 1088 | ||
1077 | static int sock_fasync(int fd, struct file *filp, int on) | 1089 | static int sock_fasync(int fd, struct file *filp, int on) |
1078 | { | 1090 | { |
1079 | struct fasync_struct *fa, *fna = NULL, **prev; | 1091 | struct socket *sock = filp->private_data; |
1080 | struct socket *sock; | 1092 | struct sock *sk = sock->sk; |
1081 | struct sock *sk; | ||
1082 | |||
1083 | if (on) { | ||
1084 | fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); | ||
1085 | if (fna == NULL) | ||
1086 | return -ENOMEM; | ||
1087 | } | ||
1088 | |||
1089 | sock = filp->private_data; | ||
1090 | 1093 | ||
1091 | sk = sock->sk; | 1094 | if (sk == NULL) |
1092 | if (sk == NULL) { | ||
1093 | kfree(fna); | ||
1094 | return -EINVAL; | 1095 | return -EINVAL; |
1095 | } | ||
1096 | 1096 | ||
1097 | lock_sock(sk); | 1097 | lock_sock(sk); |
1098 | 1098 | ||
1099 | spin_lock(&filp->f_lock); | 1099 | fasync_helper(fd, filp, on, &sock->wq->fasync_list); |
1100 | if (on) | ||
1101 | filp->f_flags |= FASYNC; | ||
1102 | else | ||
1103 | filp->f_flags &= ~FASYNC; | ||
1104 | spin_unlock(&filp->f_lock); | ||
1105 | 1100 | ||
1106 | prev = &(sock->fasync_list); | 1101 | if (!sock->wq->fasync_list) |
1107 | 1102 | sock_reset_flag(sk, SOCK_FASYNC); | |
1108 | for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev) | 1103 | else |
1109 | if (fa->fa_file == filp) | ||
1110 | break; | ||
1111 | |||
1112 | if (on) { | ||
1113 | if (fa != NULL) { | ||
1114 | write_lock_bh(&sk->sk_callback_lock); | ||
1115 | fa->fa_fd = fd; | ||
1116 | write_unlock_bh(&sk->sk_callback_lock); | ||
1117 | |||
1118 | kfree(fna); | ||
1119 | goto out; | ||
1120 | } | ||
1121 | fna->fa_file = filp; | ||
1122 | fna->fa_fd = fd; | ||
1123 | fna->magic = FASYNC_MAGIC; | ||
1124 | fna->fa_next = sock->fasync_list; | ||
1125 | write_lock_bh(&sk->sk_callback_lock); | ||
1126 | sock->fasync_list = fna; | ||
1127 | sock_set_flag(sk, SOCK_FASYNC); | 1104 | sock_set_flag(sk, SOCK_FASYNC); |
1128 | write_unlock_bh(&sk->sk_callback_lock); | ||
1129 | } else { | ||
1130 | if (fa != NULL) { | ||
1131 | write_lock_bh(&sk->sk_callback_lock); | ||
1132 | *prev = fa->fa_next; | ||
1133 | if (!sock->fasync_list) | ||
1134 | sock_reset_flag(sk, SOCK_FASYNC); | ||
1135 | write_unlock_bh(&sk->sk_callback_lock); | ||
1136 | kfree(fa); | ||
1137 | } | ||
1138 | } | ||
1139 | 1105 | ||
1140 | out: | 1106 | release_sock(sk); |
1141 | release_sock(sock->sk); | ||
1142 | return 0; | 1107 | return 0; |
1143 | } | 1108 | } |
1144 | 1109 | ||
1145 | /* 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 */ |
1146 | 1111 | ||
1147 | int sock_wake_async(struct socket *sock, int how, int band) | 1112 | int sock_wake_async(struct socket *sock, int how, int band) |
1148 | { | 1113 | { |
1149 | if (!sock || !sock->fasync_list) | 1114 | struct socket_wq *wq; |
1115 | |||
1116 | if (!sock) | ||
1150 | 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 | } | ||
1151 | switch (how) { | 1124 | switch (how) { |
1152 | case SOCK_WAKE_WAITD: | 1125 | case SOCK_WAKE_WAITD: |
1153 | if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) | 1126 | if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) |
@@ -1159,11 +1132,12 @@ int sock_wake_async(struct socket *sock, int how, int band) | |||
1159 | /* fall through */ | 1132 | /* fall through */ |
1160 | case SOCK_WAKE_IO: | 1133 | case SOCK_WAKE_IO: |
1161 | call_kill: | 1134 | call_kill: |
1162 | __kill_fasync(sock->fasync_list, SIGIO, band); | 1135 | kill_fasync(&wq->fasync_list, SIGIO, band); |
1163 | break; | 1136 | break; |
1164 | case SOCK_WAKE_URG: | 1137 | case SOCK_WAKE_URG: |
1165 | __kill_fasync(sock->fasync_list, SIGURG, band); | 1138 | kill_fasync(&wq->fasync_list, SIGURG, band); |
1166 | } | 1139 | } |
1140 | rcu_read_unlock(); | ||
1167 | return 0; | 1141 | return 0; |
1168 | } | 1142 | } |
1169 | 1143 | ||
@@ -2135,6 +2109,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | |||
2135 | break; | 2109 | break; |
2136 | ++datagrams; | 2110 | ++datagrams; |
2137 | 2111 | ||
2112 | /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ | ||
2113 | if (flags & MSG_WAITFORONE) | ||
2114 | flags |= MSG_DONTWAIT; | ||
2115 | |||
2138 | if (timeout) { | 2116 | if (timeout) { |
2139 | ktime_get_ts(timeout); | 2117 | ktime_get_ts(timeout); |
2140 | *timeout = timespec_sub(end_time, *timeout); | 2118 | *timeout = timespec_sub(end_time, *timeout); |