Phonet: use atomic for packet TX window
GPRS TX flow control won't need to lock the underlying socket anymore. Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
57c81fffc8
commit
be677730a0
@@ -35,12 +35,12 @@ struct pep_sock {
|
|||||||
struct sock *listener;
|
struct sock *listener;
|
||||||
struct sk_buff_head ctrlreq_queue;
|
struct sk_buff_head ctrlreq_queue;
|
||||||
#define PNPIPE_CTRLREQ_MAX 10
|
#define PNPIPE_CTRLREQ_MAX 10
|
||||||
|
atomic_t tx_credits;
|
||||||
int ifindex;
|
int ifindex;
|
||||||
u16 peer_type; /* peer type/subtype */
|
u16 peer_type; /* peer type/subtype */
|
||||||
u8 pipe_handle;
|
u8 pipe_handle;
|
||||||
|
|
||||||
u8 rx_credits;
|
u8 rx_credits;
|
||||||
u8 tx_credits;
|
|
||||||
u8 rx_fc; /* RX flow control */
|
u8 rx_fc; /* RX flow control */
|
||||||
u8 tx_fc; /* TX flow control */
|
u8 tx_fc; /* TX flow control */
|
||||||
u8 init_enable; /* auto-enable at creation */
|
u8 init_enable; /* auto-enable at creation */
|
||||||
|
@@ -225,6 +225,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
|
|||||||
{
|
{
|
||||||
struct pep_sock *pn = pep_sk(sk);
|
struct pep_sock *pn = pep_sk(sk);
|
||||||
struct pnpipehdr *hdr = pnp_hdr(skb);
|
struct pnpipehdr *hdr = pnp_hdr(skb);
|
||||||
|
int wake = 0;
|
||||||
|
|
||||||
if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
|
if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -241,16 +242,16 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
|
|||||||
case PN_LEGACY_FLOW_CONTROL:
|
case PN_LEGACY_FLOW_CONTROL:
|
||||||
switch (hdr->data[4]) {
|
switch (hdr->data[4]) {
|
||||||
case PEP_IND_BUSY:
|
case PEP_IND_BUSY:
|
||||||
pn->tx_credits = 0;
|
atomic_set(&pn->tx_credits, 0);
|
||||||
break;
|
break;
|
||||||
case PEP_IND_READY:
|
case PEP_IND_READY:
|
||||||
pn->tx_credits = 1;
|
atomic_set(&pn->tx_credits, wake = 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PN_ONE_CREDIT_FLOW_CONTROL:
|
case PN_ONE_CREDIT_FLOW_CONTROL:
|
||||||
if (hdr->data[4] == PEP_IND_READY)
|
if (hdr->data[4] == PEP_IND_READY)
|
||||||
pn->tx_credits = 1;
|
atomic_set(&pn->tx_credits, wake = 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -258,10 +259,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
|
|||||||
case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
|
case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
|
||||||
if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
|
if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
|
||||||
break;
|
break;
|
||||||
if (pn->tx_credits + hdr->data[4] > 0xff)
|
atomic_add(wake = hdr->data[4], &pn->tx_credits);
|
||||||
pn->tx_credits = 0xff;
|
|
||||||
else
|
|
||||||
pn->tx_credits += hdr->data[4];
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -269,7 +267,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
|
|||||||
(unsigned)hdr->data[1]);
|
(unsigned)hdr->data[1]);
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
if (pn->tx_credits)
|
if (wake)
|
||||||
sk->sk_write_space(sk);
|
sk->sk_write_space(sk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -343,7 +341,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case PNS_PEP_DISABLE_REQ:
|
case PNS_PEP_DISABLE_REQ:
|
||||||
pn->tx_credits = 0;
|
atomic_set(&pn->tx_credits, 0);
|
||||||
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
|
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -390,7 +388,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
|
|||||||
/* fall through */
|
/* fall through */
|
||||||
case PNS_PIPE_ENABLED_IND:
|
case PNS_PIPE_ENABLED_IND:
|
||||||
if (!pn_flow_safe(pn->tx_fc)) {
|
if (!pn_flow_safe(pn->tx_fc)) {
|
||||||
pn->tx_credits = 1;
|
atomic_set(&pn->tx_credits, 1);
|
||||||
sk->sk_write_space(sk);
|
sk->sk_write_space(sk);
|
||||||
}
|
}
|
||||||
if (sk->sk_state == TCP_ESTABLISHED)
|
if (sk->sk_state == TCP_ESTABLISHED)
|
||||||
@@ -504,8 +502,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
|
|||||||
newpn->pn_sk.resource = pn->pn_sk.resource;
|
newpn->pn_sk.resource = pn->pn_sk.resource;
|
||||||
skb_queue_head_init(&newpn->ctrlreq_queue);
|
skb_queue_head_init(&newpn->ctrlreq_queue);
|
||||||
newpn->pipe_handle = pipe_handle;
|
newpn->pipe_handle = pipe_handle;
|
||||||
|
atomic_set(&newpn->tx_credits, 0);
|
||||||
newpn->peer_type = peer_type;
|
newpn->peer_type = peer_type;
|
||||||
newpn->rx_credits = newpn->tx_credits = 0;
|
newpn->rx_credits = 0;
|
||||||
newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
|
newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
|
||||||
newpn->init_enable = enabled;
|
newpn->init_enable = enabled;
|
||||||
|
|
||||||
@@ -821,14 +820,18 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
|
|||||||
struct pep_sock *pn = pep_sk(sk);
|
struct pep_sock *pn = pep_sk(sk);
|
||||||
struct pnpipehdr *ph;
|
struct pnpipehdr *ph;
|
||||||
|
|
||||||
|
if (pn_flow_safe(pn->tx_fc) &&
|
||||||
|
!atomic_add_unless(&pn->tx_credits, -1, 0)) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
|
||||||
skb_push(skb, 3);
|
skb_push(skb, 3);
|
||||||
skb_reset_transport_header(skb);
|
skb_reset_transport_header(skb);
|
||||||
ph = pnp_hdr(skb);
|
ph = pnp_hdr(skb);
|
||||||
ph->utid = 0;
|
ph->utid = 0;
|
||||||
ph->message_id = PNS_PIPE_DATA;
|
ph->message_id = PNS_PIPE_DATA;
|
||||||
ph->pipe_handle = pn->pipe_handle;
|
ph->pipe_handle = pn->pipe_handle;
|
||||||
if (pn_flow_safe(pn->tx_fc) && pn->tx_credits)
|
|
||||||
pn->tx_credits--;
|
|
||||||
|
|
||||||
return pn_skb_send(sk, skb, &pipe_srv);
|
return pn_skb_send(sk, skb, &pipe_srv);
|
||||||
}
|
}
|
||||||
@@ -866,7 +869,7 @@ disabled:
|
|||||||
BUG_ON(sk->sk_state != TCP_ESTABLISHED);
|
BUG_ON(sk->sk_state != TCP_ESTABLISHED);
|
||||||
|
|
||||||
/* Wait until flow control allows TX */
|
/* Wait until flow control allows TX */
|
||||||
done = pn->tx_credits > 0;
|
done = atomic_read(&pn->tx_credits);
|
||||||
while (!done) {
|
while (!done) {
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
|
|
||||||
@@ -881,7 +884,7 @@ disabled:
|
|||||||
|
|
||||||
prepare_to_wait(&sk->sk_socket->wait, &wait,
|
prepare_to_wait(&sk->sk_socket->wait, &wait,
|
||||||
TASK_INTERRUPTIBLE);
|
TASK_INTERRUPTIBLE);
|
||||||
done = sk_wait_event(sk, &timeo, pn->tx_credits > 0);
|
done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits));
|
||||||
finish_wait(&sk->sk_socket->wait, &wait);
|
finish_wait(&sk->sk_socket->wait, &wait);
|
||||||
|
|
||||||
if (sk->sk_state != TCP_ESTABLISHED)
|
if (sk->sk_state != TCP_ESTABLISHED)
|
||||||
@@ -895,7 +898,8 @@ disabled:
|
|||||||
goto out;
|
goto out;
|
||||||
skb_reserve(skb, MAX_PHONET_HEADER + 3);
|
skb_reserve(skb, MAX_PHONET_HEADER + 3);
|
||||||
|
|
||||||
if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits)
|
if (sk->sk_state != TCP_ESTABLISHED ||
|
||||||
|
!atomic_read(&pn->tx_credits))
|
||||||
goto disabled; /* sock_alloc_send_skb might sleep */
|
goto disabled; /* sock_alloc_send_skb might sleep */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -917,7 +921,7 @@ int pep_writeable(struct sock *sk)
|
|||||||
{
|
{
|
||||||
struct pep_sock *pn = pep_sk(sk);
|
struct pep_sock *pn = pep_sk(sk);
|
||||||
|
|
||||||
return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0;
|
return atomic_read(&pn->tx_credits);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pep_write(struct sock *sk, struct sk_buff *skb)
|
int pep_write(struct sock *sk, struct sk_buff *skb)
|
||||||
|
@@ -227,7 +227,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
|
|||||||
if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
|
if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
|
||||||
return POLLHUP;
|
return POLLHUP;
|
||||||
|
|
||||||
if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits)
|
if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits))
|
||||||
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
|
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
|
||||||
|
|
||||||
return mask;
|
return mask;
|
||||||
|
Reference in New Issue
Block a user