diff options
Diffstat (limited to 'fs/ocfs2/cluster/tcp.c')
-rw-r--r-- | fs/ocfs2/cluster/tcp.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index c6b90e670389..681691bc233a 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
@@ -108,7 +108,7 @@ static struct rb_root o2net_handler_tree = RB_ROOT; | |||
108 | static struct o2net_node o2net_nodes[O2NM_MAX_NODES]; | 108 | static struct o2net_node o2net_nodes[O2NM_MAX_NODES]; |
109 | 109 | ||
110 | /* XXX someday we'll need better accounting */ | 110 | /* XXX someday we'll need better accounting */ |
111 | static struct socket *o2net_listen_sock = NULL; | 111 | static struct socket *o2net_listen_sock; |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * listen work is only queued by the listening socket callbacks on the | 114 | * listen work is only queued by the listening socket callbacks on the |
@@ -1799,7 +1799,7 @@ int o2net_register_hb_callbacks(void) | |||
1799 | 1799 | ||
1800 | /* ------------------------------------------------------------ */ | 1800 | /* ------------------------------------------------------------ */ |
1801 | 1801 | ||
1802 | static int o2net_accept_one(struct socket *sock) | 1802 | static int o2net_accept_one(struct socket *sock, int *more) |
1803 | { | 1803 | { |
1804 | int ret, slen; | 1804 | int ret, slen; |
1805 | struct sockaddr_in sin; | 1805 | struct sockaddr_in sin; |
@@ -1810,6 +1810,7 @@ static int o2net_accept_one(struct socket *sock) | |||
1810 | struct o2net_node *nn; | 1810 | struct o2net_node *nn; |
1811 | 1811 | ||
1812 | BUG_ON(sock == NULL); | 1812 | BUG_ON(sock == NULL); |
1813 | *more = 0; | ||
1813 | ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, | 1814 | ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, |
1814 | sock->sk->sk_protocol, &new_sock); | 1815 | sock->sk->sk_protocol, &new_sock); |
1815 | if (ret) | 1816 | if (ret) |
@@ -1821,6 +1822,7 @@ static int o2net_accept_one(struct socket *sock) | |||
1821 | if (ret < 0) | 1822 | if (ret < 0) |
1822 | goto out; | 1823 | goto out; |
1823 | 1824 | ||
1825 | *more = 1; | ||
1824 | new_sock->sk->sk_allocation = GFP_ATOMIC; | 1826 | new_sock->sk->sk_allocation = GFP_ATOMIC; |
1825 | 1827 | ||
1826 | ret = o2net_set_nodelay(new_sock); | 1828 | ret = o2net_set_nodelay(new_sock); |
@@ -1919,11 +1921,36 @@ out: | |||
1919 | return ret; | 1921 | return ret; |
1920 | } | 1922 | } |
1921 | 1923 | ||
1924 | /* | ||
1925 | * This function is invoked in response to one or more | ||
1926 | * pending accepts at softIRQ level. We must drain the | ||
1927 | * entire que before returning. | ||
1928 | */ | ||
1929 | |||
1922 | static void o2net_accept_many(struct work_struct *work) | 1930 | static void o2net_accept_many(struct work_struct *work) |
1923 | { | 1931 | { |
1924 | struct socket *sock = o2net_listen_sock; | 1932 | struct socket *sock = o2net_listen_sock; |
1925 | while (o2net_accept_one(sock) == 0) | 1933 | int more; |
1934 | int err; | ||
1935 | |||
1936 | /* | ||
1937 | * It is critical to note that due to interrupt moderation | ||
1938 | * at the network driver level, we can't assume to get a | ||
1939 | * softIRQ for every single conn since tcp SYN packets | ||
1940 | * can arrive back-to-back, and therefore many pending | ||
1941 | * accepts may result in just 1 softIRQ. If we terminate | ||
1942 | * the o2net_accept_one() loop upon seeing an err, what happens | ||
1943 | * to the rest of the conns in the queue? If no new SYN | ||
1944 | * arrives for hours, no softIRQ will be delivered, | ||
1945 | * and the connections will just sit in the queue. | ||
1946 | */ | ||
1947 | |||
1948 | for (;;) { | ||
1949 | err = o2net_accept_one(sock, &more); | ||
1950 | if (!more) | ||
1951 | break; | ||
1926 | cond_resched(); | 1952 | cond_resched(); |
1953 | } | ||
1927 | } | 1954 | } |
1928 | 1955 | ||
1929 | static void o2net_listen_data_ready(struct sock *sk) | 1956 | static void o2net_listen_data_ready(struct sock *sk) |