aboutsummaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-04-14 05:55:35 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-21 19:19:29 -0400
commit989a2979205dd34269382b357e6d4b4b6956b889 (patch)
tree2f504e9f4d8d418dd8fb2d042b076c1318232360 /net/socket.c
parente5700aff144fbbba46be40049f0c55fb57283777 (diff)
fasync: RCU and fine grained locking
kill_fasync() uses a central rwlock, candidate for RCU conversion, to avoid cache line ping pongs on SMP. fasync_remove_entry() and fasync_add_entry() can disable IRQS on a short section instead during whole list scan. Use a spinlock per fasync_struct to synchronize kill_fasync_rcu() and fasync_{remove|add}_entry(). This spinlock is IRQ safe, so sock_fasync() doesnt need its own implementation and can use fasync_helper(), to reduce code size and complexity. We can remove __kill_fasync() direct use in net/socket.c, and rename it to kill_fasync_rcu(). Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c73
1 files changed, 11 insertions, 62 deletions
diff --git a/net/socket.c b/net/socket.c
index 35bc198bbf68..9822081eab38 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1067,78 +1067,27 @@ static int sock_close(struct inode *inode, struct file *filp)
1067 * 1. fasync_list is modified only under process context socket lock 1067 * 1. fasync_list is modified only under process context socket lock
1068 * i.e. under semaphore. 1068 * i.e. under semaphore.
1069 * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) 1069 * 2. fasync_list is used under read_lock(&sk->sk_callback_lock)
1070 * or under socket lock. 1070 * 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 */ 1071 */
1076 1072
1077static int sock_fasync(int fd, struct file *filp, int on) 1073static int sock_fasync(int fd, struct file *filp, int on)
1078{ 1074{
1079 struct fasync_struct *fa, *fna = NULL, **prev; 1075 struct socket *sock = filp->private_data;
1080 struct socket *sock; 1076 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 1077
1091 sk = sock->sk; 1078 if (sk == NULL)
1092 if (sk == NULL) {
1093 kfree(fna);
1094 return -EINVAL; 1079 return -EINVAL;
1095 }
1096 1080
1097 lock_sock(sk); 1081 lock_sock(sk);
1098 1082
1099 spin_lock(&filp->f_lock); 1083 fasync_helper(fd, filp, on, &sock->fasync_list);
1100 if (on)
1101 filp->f_flags |= FASYNC;
1102 else
1103 filp->f_flags &= ~FASYNC;
1104 spin_unlock(&filp->f_lock);
1105
1106 prev = &(sock->fasync_list);
1107 1084
1108 for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev) 1085 if (!sock->fasync_list)
1109 if (fa->fa_file == filp) 1086 sock_reset_flag(sk, SOCK_FASYNC);
1110 break; 1087 else
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); 1088 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 1089
1140out: 1090 release_sock(sk);
1141 release_sock(sock->sk);
1142 return 0; 1091 return 0;
1143} 1092}
1144 1093
@@ -1159,10 +1108,10 @@ int sock_wake_async(struct socket *sock, int how, int band)
1159 /* fall through */ 1108 /* fall through */
1160 case SOCK_WAKE_IO: 1109 case SOCK_WAKE_IO:
1161call_kill: 1110call_kill:
1162 __kill_fasync(sock->fasync_list, SIGIO, band); 1111 kill_fasync(&sock->fasync_list, SIGIO, band);
1163 break; 1112 break;
1164 case SOCK_WAKE_URG: 1113 case SOCK_WAKE_URG:
1165 __kill_fasync(sock->fasync_list, SIGURG, band); 1114 kill_fasync(&sock->fasync_list, SIGURG, band);
1166 } 1115 }
1167 return 0; 1116 return 0;
1168} 1117}