Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 220943
b: refs/heads/master
c: b1fcf55
h: refs/heads/master
i:
  220941: 998f924
  220939: 6cf6fd2
  220935: de793e2
  220927: 97e2b04
v: v3
  • Loading branch information
Gerrit Renker authored and David S. Miller committed Oct 28, 2010
1 parent a3b4f0a commit 60e6af4
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: dc841e30eaea9f9f83c9ab1ee0b3ef9e5c95ce8a
refs/heads/master: b1fcf55eea541af9efa5d39f5a0d1aec8ceca55d
5 changes: 3 additions & 2 deletions trunk/net/dccp/dccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,9 @@ extern void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
extern void dccp_send_sync(struct sock *sk, const u64 seq,
const enum dccp_pkt_type pkt_type);

extern void dccp_write_xmit(struct sock *sk, int block);
extern void dccp_write_space(struct sock *sk);
extern void dccp_write_xmit(struct sock *sk);
extern void dccp_write_space(struct sock *sk);
extern void dccp_flush_write_queue(struct sock *sk, long *time_budget);

extern void dccp_init_xmit_timers(struct sock *sk);
static inline void dccp_clear_xmit_timers(struct sock *sk)
Expand Down
115 changes: 65 additions & 50 deletions trunk/net/dccp/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,49 +209,29 @@ void dccp_write_space(struct sock *sk)
}

/**
* dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
* dccp_wait_for_ccid - Await CCID send permission
* @sk: socket to wait for
* @skb: current skb to pass on for waiting
* @delay: sleep timeout in milliseconds (> 0)
* This function is called by default when the socket is closed, and
* when a non-zero linger time is set on the socket. For consistency
* @delay: timeout in jiffies
* This is used by CCIDs which need to delay the send time in process context.
*/
static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay)
static int dccp_wait_for_ccid(struct sock *sk, unsigned long delay)
{
struct dccp_sock *dp = dccp_sk(sk);
DEFINE_WAIT(wait);
unsigned long jiffdelay;
int rc;

do {
dccp_pr_debug("delayed send by %d msec\n", delay);
jiffdelay = msecs_to_jiffies(delay);

prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
long remaining;

sk->sk_write_pending++;
release_sock(sk);
schedule_timeout(jiffdelay);
lock_sock(sk);
sk->sk_write_pending--;
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
sk->sk_write_pending++;
release_sock(sk);

if (sk->sk_err)
goto do_error;
if (signal_pending(current))
goto do_interrupted;
remaining = schedule_timeout(delay);

rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
} while ((delay = rc) > 0);
out:
lock_sock(sk);
sk->sk_write_pending--;
finish_wait(sk_sleep(sk), &wait);
return rc;

do_error:
rc = -EPIPE;
goto out;
do_interrupted:
rc = -EINTR;
goto out;

if (signal_pending(current) || sk->sk_err)
return -1;
return remaining;
}

/**
Expand Down Expand Up @@ -305,7 +285,53 @@ static void dccp_xmit_packet(struct sock *sk)
ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len);
}

void dccp_write_xmit(struct sock *sk, int block)
/**
* dccp_flush_write_queue - Drain queue at end of connection
* Since dccp_sendmsg queues packets without waiting for them to be sent, it may
* happen that the TX queue is not empty at the end of a connection. We give the
* HC-sender CCID a grace period of up to @time_budget jiffies. If this function
* returns with a non-empty write queue, it will be purged later.
*/
void dccp_flush_write_queue(struct sock *sk, long *time_budget)
{
struct dccp_sock *dp = dccp_sk(sk);
struct sk_buff *skb;
long delay, rc;

while (*time_budget > 0 && (skb = skb_peek(&sk->sk_write_queue))) {
rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);

switch (ccid_packet_dequeue_eval(rc)) {
case CCID_PACKET_WILL_DEQUEUE_LATER:
/*
* If the CCID determines when to send, the next sending
* time is unknown or the CCID may not even send again
* (e.g. remote host crashes or lost Ack packets).
*/
DCCP_WARN("CCID did not manage to send all packets\n");
return;
case CCID_PACKET_DELAY:
delay = msecs_to_jiffies(rc);
if (delay > *time_budget)
return;
rc = dccp_wait_for_ccid(sk, delay);
if (rc < 0)
return;
*time_budget -= (delay - rc);
/* check again if we can send now */
break;
case CCID_PACKET_SEND_AT_ONCE:
dccp_xmit_packet(sk);
break;
case CCID_PACKET_ERR:
skb_dequeue(&sk->sk_write_queue);
kfree_skb(skb);
dccp_pr_debug("packet discarded due to err=%ld\n", rc);
}
}
}

void dccp_write_xmit(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct sk_buff *skb;
Expand All @@ -317,19 +343,9 @@ void dccp_write_xmit(struct sock *sk, int block)
case CCID_PACKET_WILL_DEQUEUE_LATER:
return;
case CCID_PACKET_DELAY:
if (!block) {
sk_reset_timer(sk, &dp->dccps_xmit_timer,
msecs_to_jiffies(rc)+jiffies);
return;
}
rc = dccp_wait_for_ccid(sk, skb, rc);
if (rc && rc != -EINTR) {
DCCP_BUG("err=%d after dccp_wait_for_ccid", rc);
skb_dequeue(&sk->sk_write_queue);
kfree_skb(skb);
break;
}
/* fall through */
sk_reset_timer(sk, &dp->dccps_xmit_timer,
jiffies + msecs_to_jiffies(rc));
return;
case CCID_PACKET_SEND_AT_ONCE:
dccp_xmit_packet(sk);
break;
Expand Down Expand Up @@ -648,7 +664,6 @@ void dccp_send_close(struct sock *sk, const int active)
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSE;

if (active) {
dccp_write_xmit(sk, 1);
dccp_skb_entail(sk, skb);
dccp_transmit_skb(sk, skb_clone(skb, prio));
/*
Expand Down
21 changes: 20 additions & 1 deletion trunk/net/dccp/proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,13 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
goto out_discard;

skb_queue_tail(&sk->sk_write_queue, skb);
dccp_write_xmit(sk,0);
/*
* The xmit_timer is set if the TX CCID is rate-based and will expire
* when congestion control permits to release further packets into the
* network. Window-based CCIDs do not use this timer.
*/
if (!timer_pending(&dp->dccps_xmit_timer))
dccp_write_xmit(sk);
out_release:
release_sock(sk);
return rc ? : len;
Expand Down Expand Up @@ -951,9 +957,22 @@ void dccp_close(struct sock *sk, long timeout)
/* Check zero linger _after_ checking for unread data. */
sk->sk_prot->disconnect(sk, 0);
} else if (sk->sk_state != DCCP_CLOSED) {
/*
* Normal connection termination. May need to wait if there are
* still packets in the TX queue that are delayed by the CCID.
*/
dccp_flush_write_queue(sk, &timeout);
dccp_terminate_connection(sk);
}

/*
* Flush write queue. This may be necessary in several cases:
* - we have been closed by the peer but still have application data;
* - abortive termination (unread data or zero linger time),
* - normal termination but queue could not be flushed within time limit
*/
__skb_queue_purge(&sk->sk_write_queue);

sk_stream_wait_close(sk, timeout);

adjudge_to_death:
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/dccp/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ static void dccp_write_xmitlet(unsigned long data)
if (sock_owned_by_user(sk))
sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1);
else
dccp_write_xmit(sk, 0);
dccp_write_xmit(sk);
bh_unlock_sock(sk);
}

Expand Down

0 comments on commit 60e6af4

Please sign in to comment.