diff options
-rw-r--r-- | include/net/phonet/pep.h | 2 | ||||
-rw-r--r-- | net/phonet/pep.c | 38 | ||||
-rw-r--r-- | net/phonet/socket.c | 2 |
3 files changed, 23 insertions, 19 deletions
diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h index fcd793030e4d..4c61cdce4e5f 100644 --- a/include/net/phonet/pep.h +++ b/include/net/phonet/pep.h | |||
@@ -35,12 +35,12 @@ struct pep_sock { | |||
35 | struct sock *listener; | 35 | struct sock *listener; |
36 | struct sk_buff_head ctrlreq_queue; | 36 | struct sk_buff_head ctrlreq_queue; |
37 | #define PNPIPE_CTRLREQ_MAX 10 | 37 | #define PNPIPE_CTRLREQ_MAX 10 |
38 | atomic_t tx_credits; | ||
38 | int ifindex; | 39 | int ifindex; |
39 | u16 peer_type; /* peer type/subtype */ | 40 | u16 peer_type; /* peer type/subtype */ |
40 | u8 pipe_handle; | 41 | u8 pipe_handle; |
41 | 42 | ||
42 | u8 rx_credits; | 43 | u8 rx_credits; |
43 | u8 tx_credits; | ||
44 | u8 rx_fc; /* RX flow control */ | 44 | u8 rx_fc; /* RX flow control */ |
45 | u8 tx_fc; /* TX flow control */ | 45 | u8 tx_fc; /* TX flow control */ |
46 | u8 init_enable; /* auto-enable at creation */ | 46 | u8 init_enable; /* auto-enable at creation */ |
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index bc6d50f83249..bb3e67849b38 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -225,6 +225,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
225 | { | 225 | { |
226 | struct pep_sock *pn = pep_sk(sk); | 226 | struct pep_sock *pn = pep_sk(sk); |
227 | struct pnpipehdr *hdr = pnp_hdr(skb); | 227 | struct pnpipehdr *hdr = pnp_hdr(skb); |
228 | int wake = 0; | ||
228 | 229 | ||
229 | if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) | 230 | if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) |
230 | return -EINVAL; | 231 | return -EINVAL; |
@@ -241,16 +242,16 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
241 | case PN_LEGACY_FLOW_CONTROL: | 242 | case PN_LEGACY_FLOW_CONTROL: |
242 | switch (hdr->data[4]) { | 243 | switch (hdr->data[4]) { |
243 | case PEP_IND_BUSY: | 244 | case PEP_IND_BUSY: |
244 | pn->tx_credits = 0; | 245 | atomic_set(&pn->tx_credits, 0); |
245 | break; | 246 | break; |
246 | case PEP_IND_READY: | 247 | case PEP_IND_READY: |
247 | pn->tx_credits = 1; | 248 | atomic_set(&pn->tx_credits, wake = 1); |
248 | break; | 249 | break; |
249 | } | 250 | } |
250 | break; | 251 | break; |
251 | case PN_ONE_CREDIT_FLOW_CONTROL: | 252 | case PN_ONE_CREDIT_FLOW_CONTROL: |
252 | if (hdr->data[4] == PEP_IND_READY) | 253 | if (hdr->data[4] == PEP_IND_READY) |
253 | pn->tx_credits = 1; | 254 | atomic_set(&pn->tx_credits, wake = 1); |
254 | break; | 255 | break; |
255 | } | 256 | } |
256 | break; | 257 | break; |
@@ -258,10 +259,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
258 | case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: | 259 | case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: |
259 | if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) | 260 | if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) |
260 | break; | 261 | break; |
261 | if (pn->tx_credits + hdr->data[4] > 0xff) | 262 | atomic_add(wake = hdr->data[4], &pn->tx_credits); |
262 | pn->tx_credits = 0xff; | ||
263 | else | ||
264 | pn->tx_credits += hdr->data[4]; | ||
265 | break; | 263 | break; |
266 | 264 | ||
267 | default: | 265 | default: |
@@ -269,7 +267,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) | |||
269 | (unsigned)hdr->data[1]); | 267 | (unsigned)hdr->data[1]); |
270 | return -EOPNOTSUPP; | 268 | return -EOPNOTSUPP; |
271 | } | 269 | } |
272 | if (pn->tx_credits) | 270 | if (wake) |
273 | sk->sk_write_space(sk); | 271 | sk->sk_write_space(sk); |
274 | return 0; | 272 | return 0; |
275 | } | 273 | } |
@@ -343,7 +341,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
343 | } | 341 | } |
344 | /* fall through */ | 342 | /* fall through */ |
345 | case PNS_PEP_DISABLE_REQ: | 343 | case PNS_PEP_DISABLE_REQ: |
346 | pn->tx_credits = 0; | 344 | atomic_set(&pn->tx_credits, 0); |
347 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 345 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
348 | break; | 346 | break; |
349 | 347 | ||
@@ -390,7 +388,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
390 | /* fall through */ | 388 | /* fall through */ |
391 | case PNS_PIPE_ENABLED_IND: | 389 | case PNS_PIPE_ENABLED_IND: |
392 | if (!pn_flow_safe(pn->tx_fc)) { | 390 | if (!pn_flow_safe(pn->tx_fc)) { |
393 | pn->tx_credits = 1; | 391 | atomic_set(&pn->tx_credits, 1); |
394 | sk->sk_write_space(sk); | 392 | sk->sk_write_space(sk); |
395 | } | 393 | } |
396 | if (sk->sk_state == TCP_ESTABLISHED) | 394 | if (sk->sk_state == TCP_ESTABLISHED) |
@@ -504,8 +502,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) | |||
504 | newpn->pn_sk.resource = pn->pn_sk.resource; | 502 | newpn->pn_sk.resource = pn->pn_sk.resource; |
505 | skb_queue_head_init(&newpn->ctrlreq_queue); | 503 | skb_queue_head_init(&newpn->ctrlreq_queue); |
506 | newpn->pipe_handle = pipe_handle; | 504 | newpn->pipe_handle = pipe_handle; |
505 | atomic_set(&newpn->tx_credits, 0); | ||
507 | newpn->peer_type = peer_type; | 506 | newpn->peer_type = peer_type; |
508 | newpn->rx_credits = newpn->tx_credits = 0; | 507 | newpn->rx_credits = 0; |
509 | newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; | 508 | newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; |
510 | newpn->init_enable = enabled; | 509 | newpn->init_enable = enabled; |
511 | 510 | ||
@@ -821,14 +820,18 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | |||
821 | struct pep_sock *pn = pep_sk(sk); | 820 | struct pep_sock *pn = pep_sk(sk); |
822 | struct pnpipehdr *ph; | 821 | struct pnpipehdr *ph; |
823 | 822 | ||
823 | if (pn_flow_safe(pn->tx_fc) && | ||
824 | !atomic_add_unless(&pn->tx_credits, -1, 0)) { | ||
825 | kfree_skb(skb); | ||
826 | return -ENOBUFS; | ||
827 | } | ||
828 | |||
824 | skb_push(skb, 3); | 829 | skb_push(skb, 3); |
825 | skb_reset_transport_header(skb); | 830 | skb_reset_transport_header(skb); |
826 | ph = pnp_hdr(skb); | 831 | ph = pnp_hdr(skb); |
827 | ph->utid = 0; | 832 | ph->utid = 0; |
828 | ph->message_id = PNS_PIPE_DATA; | 833 | ph->message_id = PNS_PIPE_DATA; |
829 | ph->pipe_handle = pn->pipe_handle; | 834 | ph->pipe_handle = pn->pipe_handle; |
830 | if (pn_flow_safe(pn->tx_fc) && pn->tx_credits) | ||
831 | pn->tx_credits--; | ||
832 | 835 | ||
833 | return pn_skb_send(sk, skb, &pipe_srv); | 836 | return pn_skb_send(sk, skb, &pipe_srv); |
834 | } | 837 | } |
@@ -866,7 +869,7 @@ disabled: | |||
866 | BUG_ON(sk->sk_state != TCP_ESTABLISHED); | 869 | BUG_ON(sk->sk_state != TCP_ESTABLISHED); |
867 | 870 | ||
868 | /* Wait until flow control allows TX */ | 871 | /* Wait until flow control allows TX */ |
869 | done = pn->tx_credits > 0; | 872 | done = atomic_read(&pn->tx_credits); |
870 | while (!done) { | 873 | while (!done) { |
871 | DEFINE_WAIT(wait); | 874 | DEFINE_WAIT(wait); |
872 | 875 | ||
@@ -881,7 +884,7 @@ disabled: | |||
881 | 884 | ||
882 | prepare_to_wait(&sk->sk_socket->wait, &wait, | 885 | prepare_to_wait(&sk->sk_socket->wait, &wait, |
883 | TASK_INTERRUPTIBLE); | 886 | TASK_INTERRUPTIBLE); |
884 | done = sk_wait_event(sk, &timeo, pn->tx_credits > 0); | 887 | done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); |
885 | finish_wait(&sk->sk_socket->wait, &wait); | 888 | finish_wait(&sk->sk_socket->wait, &wait); |
886 | 889 | ||
887 | if (sk->sk_state != TCP_ESTABLISHED) | 890 | if (sk->sk_state != TCP_ESTABLISHED) |
@@ -895,7 +898,8 @@ disabled: | |||
895 | goto out; | 898 | goto out; |
896 | skb_reserve(skb, MAX_PHONET_HEADER + 3); | 899 | skb_reserve(skb, MAX_PHONET_HEADER + 3); |
897 | 900 | ||
898 | if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits) | 901 | if (sk->sk_state != TCP_ESTABLISHED || |
902 | !atomic_read(&pn->tx_credits)) | ||
899 | goto disabled; /* sock_alloc_send_skb might sleep */ | 903 | goto disabled; /* sock_alloc_send_skb might sleep */ |
900 | } | 904 | } |
901 | 905 | ||
@@ -917,7 +921,7 @@ int pep_writeable(struct sock *sk) | |||
917 | { | 921 | { |
918 | struct pep_sock *pn = pep_sk(sk); | 922 | struct pep_sock *pn = pep_sk(sk); |
919 | 923 | ||
920 | return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0; | 924 | return atomic_read(&pn->tx_credits); |
921 | } | 925 | } |
922 | 926 | ||
923 | int pep_write(struct sock *sk, struct sk_buff *skb) | 927 | int pep_write(struct sock *sk, struct sk_buff *skb) |
diff --git a/net/phonet/socket.c b/net/phonet/socket.c index c75aa5cdead5..ada2a35bf7a2 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c | |||
@@ -227,7 +227,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock, | |||
227 | if (!mask && sk->sk_state == TCP_CLOSE_WAIT) | 227 | if (!mask && sk->sk_state == TCP_CLOSE_WAIT) |
228 | return POLLHUP; | 228 | return POLLHUP; |
229 | 229 | ||
230 | if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits) | 230 | if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits)) |
231 | mask |= POLLOUT | POLLWRNORM | POLLWRBAND; | 231 | mask |= POLLOUT | POLLWRNORM | POLLWRBAND; |
232 | 232 | ||
233 | return mask; | 233 | return mask; |