Arnaldo, (or anybody else) I can get it working with the extra lock but not without... Comments inline and at the end. Help much appreciated! > Please leave the "extern" > Yep! > I guess we don't need this lock, but instead use bh_lock_sock, check if > there are users, look at ccid3_hc_tx_no_feedback_timer & ccid2_hc_tx_rto_expire > (I left a comment even having fixed the problem, duh will fix). I'm not sure what you mean by users here. Users of what? Can you explain > sk_reset_timer() please, so that we make sure we have a reference count > for the sock as its going to be on a timer > Will tidyup once get other problems sorted... > No need for the {}, just one statement Understand. Lazy when removing debugging... > sk_eat_skb() later? > It would be sk_eat_skb in dccp_write_xmit for two reasons: 1) sk_eat_skb alters receive queue. This is write 2) Existing xmit doesn't seem to do anything like this. To me it looks like the lower level does the kfree_skb... > > > + dp->dccps_xmit_lock = SPIN_LOCK_UNLOCKED; > > Not needed Understand - will remove Now I have attached two patches. acme1.diff is slightly tidied up version of original patch and works with normal testing and netem testing. acme2.diff is an attempt to get rid of spinlock and use sock_lock as I didn't think I needed bh_sock_lock as not receiving packets as that is seemed aimed at that (stopping the interrupt driver trashing receive queues...) If I do away with spinlocks as per acme2.diff I get this: Feb 21 14:37:56 localhost kernel: [17180168.280000] Debug: sleeping function called from invalid context at net/core/sock.c:1327 Feb 21 14:37:56 localhost kernel: [17180168.280000] in_atomic():1, irqs_disabled():0 Feb 21 14:37:56 localhost kernel: [17180168.280000] [show_trace+19/21] show_trace+0x13/0x15 Feb 21 14:37:56 localhost kernel: [17180168.280000] [dump_stack+22/26] dump_stack+0x16/0x1a Feb 21 14:37:56 localhost kernel: [17180168.280000] [__might_sleep+135/143] __might_sleep+0x87/0x8f Feb 21 14:37:56 localhost kernel: [17180168.280000] [lock_sock+26/158] lock_sock+0x1a/0x9e Feb 21 14:37:56 localhost kernel: [17180168.280000] [pg0+411554706/1070261248] dccp_write_xmit+0x25/0x264 [dccp] Feb 21 14:37:56 localhost kernel: [17180168.280000] [pg0+411555519/1070261248] dccp_write_xmit_timer+0xd/0x11 [dccp] Feb 21 14:37:56 localhost kernel: [17180168.280000] [run_timer_softirq+296/387] run_timer_softirq+0x128/0x183 Feb 21 14:37:56 localhost kernel: [17180168.280000] [__do_softirq+66/144] __do_softirq+0x42/0x90 Feb 21 14:37:56 localhost kernel: [17180168.280000] [do_softirq+42/47] do_softirq+0x2a/0x2f Feb 21 14:37:56 localhost kernel: [17180168.280000] [irq_exit+48/60] irq_exit+0x30/0x3c Feb 21 14:37:56 localhost kernel: [17180168.280000] [do_IRQ+72/84] do_IRQ+0x48/0x54 Feb 21 14:37:56 localhost kernel: [17180168.280000] [common_interrupt+26/32] common_interrupt+0x1a/0x20 Feb 21 14:37:56 localhost kernel: [17180168.280000] [cpu_idle+71/115] cpu_idle+0x47/0x73 Feb 21 14:37:56 localhost kernel: [17180168.280000] [_stext+55/60] rest_init+0x37/0x3c Feb 21 14:37:56 localhost kernel: [17180168.280000] [start_kernel+639/641] start_kernel+0x27f/0x281 Feb 21 14:37:56 localhost kernel: [17180168.280000] [L6+0/2] 0xc0100199 which seems to be that it doesn't like lock_sock being called from a timer as I read this. Can I not call lock_sock from a timer? When I substituted lock_sock/release_sock for bh_lock_sock/bh_release_sock in dccp_write_xmit (it doesn't call might_sleep) I lock my machine solid with no output... Feb 21 14:37:57 localhost kernel: [17180169.060000] scheduling while atomic: ttcp_acme/0x00000101/11660 Feb 21 14:37:57 localhost kernel: [17180169.060000] [show_trace+19/21] show_trace+0x13/0x15 Feb 21 14:37:57 localhost kernel: [17180169.060000] [dump_stack+22/26] dump_stack+0x16/0x1a Feb 21 14:37:57 localhost kernel: [17180169.060000] [schedule+67/1316] schedule+0x43/0x524 Feb 21 14:37:57 localhost kernel: [17180169.060000] [lock_sock+113/158] lock_sock+0x71/0x9e Feb 21 14:37:57 localhost kernel: [17180169.060000] [pg0+411554706/1070261248] dccp_write_xmit+0x25/0x264 [dccp] Feb 21 14:37:57 localhost kernel: [17180169.060000] [pg0+411555519/1070261248] dccp_write_xmit_timer+0xd/0x11 [dccp] Feb 21 14:37:57 localhost kernel: [17180169.060000] [run_timer_softirq+296/387] run_timer_softirq+0x128/0x183 Feb 21 14:37:57 localhost kernel: [17180169.060000] [__do_softirq+66/144] __do_softirq+0x42/0x90 Feb 21 14:37:57 localhost kernel: [17180169.060000] [do_softirq+42/47] do_softirq+0x2a/0x2f Feb 21 14:37:57 localhost kernel: [17180169.060000] [irq_exit+48/60] irq_exit+0x30/0x3c Feb 21 14:37:57 localhost kernel: [17180169.060000] [do_IRQ+72/84] do_IRQ+0x48/0x54 Feb 21 14:37:57 localhost kernel: [17180169.060000] [common_interrupt+26/32] common_interrupt+0x1a/0x20 Feb 21 14:37:57 localhost kernel: [17180169.060000] [do_gettimeofday+20/148] do_gettimeofday+0x14/0x94 Feb 21 14:37:57 localhost kernel: [17180169.060000] [pg0+411550955/1070261248] dccp_timestamp+0x11/0x42 [dccp] Feb 21 14:37:57 localhost kernel: [17180169.060000] [pg0+411872049/1070261248] ccid3_hc_tx_send_packet+0xeb/0x290 [dccp_ccid3] Feb 21 14:37:57 localhost kernel: [17180169.060000] [pg0+411554738/1070261248] dccp_write_xmit+0x45/0x264 [dccp] Feb 21 14:37:57 localhost kernel: [17180169.060000] [pg0+411558587/1070261248] dccp_sendmsg+0x11e/0x15f [dccp] Feb 21 14:37:57 localhost kernel: [17180169.060000] [inet_sendmsg+52/64] inet_sendmsg+0x34/0x40 Feb 21 14:37:57 localhost kernel: [17180169.060000] [do_sock_write+145/153] do_sock_write+0x91/0x99 Feb 21 14:37:57 localhost kernel: [17180169.060000] [sock_aio_write+85/99] sock_aio_write+0x55/0x63 Feb 21 14:37:57 localhost kernel: [17180169.060000] [do_sync_write+159/208] do_sync_write+0x9f/0xd0 Feb 21 14:37:57 localhost kernel: [17180169.060000] [vfs_write+180/327] vfs_write+0xb4/0x147 Feb 21 14:37:57 localhost kernel: [17180169.060000] [sys_write+58/97] sys_write+0x3a/0x61 Feb 21 14:37:57 localhost kernel: [17180169.060000] [syscall_call+7/11] syscall_call+0x7/0xb Here when I am transmitting a packet the timer fires because I go to get the time and it causes an issue..... acme2.diff doesn't work for me. I can't see how to get this working without a transmit lock which works perfectly for me. Are you able to tell me what I am doing wrong? I personally can't see what I am doing wrong - it is just that lock_sock isn't enough to prevent races which is why I need to put in a transmit lock... the issue is really the timer firing. TCP doesn't have the issue in quite this way as it uses ACK clocking in effect rather than being time based like CCID3. Comments/help really appreciated as I'm pulling my hair out and just want to use my extra lock.... Ian -- Ian McDonald http://wand.net.nz/~iam4 WAND Network Research Group Department of Computer Science University of Waikato New Zealand
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 088529f..4a2f845 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -411,6 +411,8 @@ struct dccp_ackvec; * @dccps_role - Role of this sock, one of %dccp_role * @dccps_ndp_count - number of Non Data Packets since last data packet * @dccps_hc_rx_ackvec - rx half connection ack vector + * @dccps_xmit_timer - timer for when CCID is not ready to send + * @dccps_xmit_lock - lock for transmitting */ struct dccp_sock { /* inet_connection_sock has to be the first member of dccp_sock */ @@ -443,6 +445,8 @@ struct dccp_sock { enum dccp_role dccps_role:2; __u8 dccps_hc_rx_insert_options:1; __u8 dccps_hc_tx_insert_options:1; + struct timer_list dccps_xmit_timer; + spinlock_t dccps_xmit_lock; }; static inline struct dccp_sock *dccp_sk(const struct sock *sk) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 93f26dd..ad38765 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -5,7 +5,7 @@ * * An implementation of the DCCP protocol * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> - * Copyright (c) 2005 Ian McDonald <iam4@xxxxxxxxxxxxxxxx> + * Copyright (c) 2005-6 Ian McDonald <imcdnzl@xxxxxxxxx> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as @@ -126,7 +126,7 @@ extern void dccp_send_delayed_ack(struct extern void dccp_send_sync(struct sock *sk, const u64 seq, const enum dccp_pkt_type pkt_type); -extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo); +extern void dccp_write_xmit(struct sock *sk, int block); extern void dccp_write_space(struct sock *sk); extern void dccp_init_xmit_timers(struct sock *sk); diff --git a/net/dccp/output.c b/net/dccp/output.c index efd7ffb..efadaaa 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -2,7 +2,8 @@ * net/dccp/output.c * * An implementation of the DCCP protocol - * Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> + * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> + * Copyright (c) 2006 Ian McDonald <imcdnzl@xxxxxxxxx> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -191,7 +192,7 @@ static int dccp_wait_for_ccid(struct soc while (1) { prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) + if (sk->sk_err) goto do_error; if (!*timeo) goto do_nonblock; @@ -207,9 +208,11 @@ static int dccp_wait_for_ccid(struct soc goto do_nonblock; sk->sk_write_pending++; + spin_unlock(&dp->dccps_xmit_lock); release_sock(sk); *timeo -= schedule_timeout(delay); lock_sock(sk); + spin_lock(&dp->dccps_xmit_lock); sk->sk_write_pending--; } out: @@ -227,37 +230,55 @@ do_interrupted: goto out; } -int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) -{ - const struct dccp_sock *dp = dccp_sk(sk); - int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb, - skb->len); +static void dccp_write_xmit_timer(unsigned long sk) { + dccp_write_xmit((struct sock *)sk,0); +} - if (err > 0) - err = dccp_wait_for_ccid(sk, skb, timeo); +void dccp_write_xmit(struct sock *sk, int block) +{ + struct dccp_sock *dp = dccp_sk(sk); + struct sk_buff *skb; + long timeo = 2000; /* FIXME imcdnzl - 2 second default */ - if (err == 0) { - struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); - const int len = skb->len; + spin_lock(&dp->dccps_xmit_lock); + + while ((skb = skb_peek(&sk->sk_write_queue))) { + int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb, + skb->len); + + if (err > 0) { + if (likely(!block)) { + mod_timer(&dp->dccps_xmit_timer, + msecs_to_jiffies(err)+jiffies); + goto xmit_out; + } else + err = dccp_wait_for_ccid(sk, skb, &timeo); + } - if (sk->sk_state == DCCP_PARTOPEN) { - /* See 8.1.5. Handshake Completion */ - inet_csk_schedule_ack(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, + skb_dequeue(&sk->sk_write_queue); + if (err == 0) { + struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); + const int len = skb->len; + + if (sk->sk_state == DCCP_PARTOPEN) { + /* See 8.1.5. Handshake Completion */ + inet_csk_schedule_ack(sk); + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); - dcb->dccpd_type = DCCP_PKT_DATAACK; - } else if (dccp_ack_pending(sk)) - dcb->dccpd_type = DCCP_PKT_DATAACK; - else - dcb->dccpd_type = DCCP_PKT_DATA; - - err = dccp_transmit_skb(sk, skb); - ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); - } else - kfree_skb(skb); - - return err; + dcb->dccpd_type = DCCP_PKT_DATAACK; + } else if (dccp_ack_pending(sk)) + dcb->dccpd_type = DCCP_PKT_DATAACK; + else + dcb->dccpd_type = DCCP_PKT_DATA; + + err = dccp_transmit_skb(sk, skb); + ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); + } else + kfree(skb); + } +xmit_out: + spin_unlock(&dp->dccps_xmit_lock); } int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb) @@ -396,6 +417,10 @@ static inline void dccp_connect_init(str dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); icsk->icsk_retransmits = 0; + init_timer(&dp->dccps_xmit_timer); + dp->dccps_xmit_timer.data = (unsigned long)sk; + dp->dccps_xmit_timer.function = dccp_write_xmit_timer; + dp->dccps_xmit_lock = SPIN_LOCK_UNLOCKED; } int dccp_connect(struct sock *sk) @@ -527,8 +552,10 @@ void dccp_send_close(struct sock *sk, co DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; if (active) { + dccp_write_xmit(sk, 1); dccp_skb_entail(sk, skb); dccp_transmit_skb(sk, skb_clone(skb, prio)); + /* FIXME do we need a retransmit timer here? */ } else dccp_transmit_skb(sk, skb); } diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 65b11ea..119ecc5 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -385,6 +385,7 @@ int dccp_sendmsg(struct kiocb *iocb, str lock_sock(sk); timeo = sock_sndtimeo(sk, noblock); + /* FIXME imcdnzl - we should be using timeo for memory allocation */ /* * We have to use sk_stream_wait_connect here to set sk_write_pending, @@ -407,19 +408,13 @@ int dccp_sendmsg(struct kiocb *iocb, str if (rc != 0) goto out_discard; - rc = dccp_write_xmit(sk, skb, &timeo); - /* - * XXX we don't use sk_write_queue, so just discard the packet. - * Current plan however is to _use_ sk_write_queue with - * an algorith similar to tcp_sendmsg, where the main difference - * is that in DCCP we have to respect packet boundaries, so - * no coalescing of skbs. - * - * This bug was _quickly_ found & fixed by just looking at an OSTRA - * generated callgraph 8) -acme - */ + skb_queue_tail(&sk->sk_write_queue, skb); + release_sock(sk); + dccp_write_xmit(sk,0); + goto out_end; out_release: release_sock(sk); +out_end: return rc ? : len; out_discard: kfree_skb(skb); @@ -591,6 +586,7 @@ static int dccp_close_state(struct sock void dccp_close(struct sock *sk, long timeout) { + struct dccp_sock *dp = dccp_sk(sk); struct sk_buff *skb; lock_sock(sk); @@ -606,6 +602,8 @@ void dccp_close(struct sock *sk, long ti goto adjudge_to_death; } + del_timer_sync(&dp->dccps_xmit_timer); + /* * We need to flush the recv. buffs. We do this only on the * descriptor close, not protocol-sourced closes, because the
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 088529f..3604d1d 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -411,6 +411,8 @@ struct dccp_ackvec; * @dccps_role - Role of this sock, one of %dccp_role * @dccps_ndp_count - number of Non Data Packets since last data packet * @dccps_hc_rx_ackvec - rx half connection ack vector + * @dccps_xmit_timer - timer for when CCID is not ready to send + * @dccps_xmit_lock - lock for transmitting */ struct dccp_sock { /* inet_connection_sock has to be the first member of dccp_sock */ @@ -443,6 +445,8 @@ struct dccp_sock { enum dccp_role dccps_role:2; __u8 dccps_hc_rx_insert_options:1; __u8 dccps_hc_tx_insert_options:1; + struct timer_list dccps_xmit_timer; +// spinlock_t dccps_xmit_lock; }; static inline struct dccp_sock *dccp_sk(const struct sock *sk) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 93f26dd..ad38765 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -5,7 +5,7 @@ * * An implementation of the DCCP protocol * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> - * Copyright (c) 2005 Ian McDonald <iam4@xxxxxxxxxxxxxxxx> + * Copyright (c) 2005-6 Ian McDonald <imcdnzl@xxxxxxxxx> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as @@ -126,7 +126,7 @@ extern void dccp_send_delayed_ack(struct extern void dccp_send_sync(struct sock *sk, const u64 seq, const enum dccp_pkt_type pkt_type); -extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo); +extern void dccp_write_xmit(struct sock *sk, int block); extern void dccp_write_space(struct sock *sk); extern void dccp_init_xmit_timers(struct sock *sk); diff --git a/net/dccp/output.c b/net/dccp/output.c index efd7ffb..f0e60af 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -2,7 +2,8 @@ * net/dccp/output.c * * An implementation of the DCCP protocol - * Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> + * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> + * Copyright (c) 2006 Ian McDonald <imcdnzl@xxxxxxxxx> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -191,7 +192,7 @@ static int dccp_wait_for_ccid(struct soc while (1) { prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) + if (sk->sk_err) goto do_error; if (!*timeo) goto do_nonblock; @@ -207,9 +208,12 @@ static int dccp_wait_for_ccid(struct soc goto do_nonblock; sk->sk_write_pending++; +// spin_unlock(&dp->dccps_xmit_lock); release_sock(sk); +/* not using bh_lock as comes through dccp_close which uses lock_sock */ *timeo -= schedule_timeout(delay); lock_sock(sk); +// spin_lock(&dp->dccps_xmit_lock); sk->sk_write_pending--; } out: @@ -227,37 +231,63 @@ do_interrupted: goto out; } -int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) +static void dccp_write_xmit_timer(unsigned long sk) { + dccp_write_xmit((struct sock *)sk,0); +} + +void dccp_write_xmit(struct sock *sk, int block) { - const struct dccp_sock *dp = dccp_sk(sk); - int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb, - skb->len); + struct dccp_sock *dp = dccp_sk(sk); + struct sk_buff *skb; + long timeo = 2000; /* FIXME imcdnzl - 2 second default */ - if (err > 0) - err = dccp_wait_for_ccid(sk, skb, timeo); +// spin_lock(&dp->dccps_xmit_lock); +// + if (!block) + lock_sock(sk); - if (err == 0) { - struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); - const int len = skb->len; + /* this is here because dccp_close locks the sock and + * we want to avoid deadlock */ + + while ((skb = skb_peek(&sk->sk_write_queue))) { + int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb, + skb->len); + + if (err > 0) { + if (likely(!block)) { + mod_timer(&dp->dccps_xmit_timer, + msecs_to_jiffies(err)+jiffies); + goto xmit_out; + } else + err = dccp_wait_for_ccid(sk, skb, &timeo); + } - if (sk->sk_state == DCCP_PARTOPEN) { - /* See 8.1.5. Handshake Completion */ - inet_csk_schedule_ack(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, + skb_dequeue(&sk->sk_write_queue); + if (err == 0) { + struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); + const int len = skb->len; + + if (sk->sk_state == DCCP_PARTOPEN) { + /* See 8.1.5. Handshake Completion */ + inet_csk_schedule_ack(sk); + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); - dcb->dccpd_type = DCCP_PKT_DATAACK; - } else if (dccp_ack_pending(sk)) - dcb->dccpd_type = DCCP_PKT_DATAACK; - else - dcb->dccpd_type = DCCP_PKT_DATA; - - err = dccp_transmit_skb(sk, skb); - ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); - } else - kfree_skb(skb); - - return err; + dcb->dccpd_type = DCCP_PKT_DATAACK; + } else if (dccp_ack_pending(sk)) + dcb->dccpd_type = DCCP_PKT_DATAACK; + else + dcb->dccpd_type = DCCP_PKT_DATA; + + err = dccp_transmit_skb(sk, skb); + ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); + } else + kfree(skb); + } +xmit_out: + if (!block) + release_sock(sk); +// spin_unlock(&dp->dccps_xmit_lock); } int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb) @@ -396,6 +426,10 @@ static inline void dccp_connect_init(str dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); icsk->icsk_retransmits = 0; + init_timer(&dp->dccps_xmit_timer); + dp->dccps_xmit_timer.data = (unsigned long)sk; + dp->dccps_xmit_timer.function = dccp_write_xmit_timer; +// dp->dccps_xmit_lock = SPIN_LOCK_UNLOCKED; } int dccp_connect(struct sock *sk) @@ -527,8 +561,10 @@ void dccp_send_close(struct sock *sk, co DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; if (active) { + dccp_write_xmit(sk, 1); dccp_skb_entail(sk, skb); dccp_transmit_skb(sk, skb_clone(skb, prio)); + /* FIXME do we need a retransmit timer here? */ } else dccp_transmit_skb(sk, skb); } diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 65b11ea..119ecc5 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -385,6 +385,7 @@ int dccp_sendmsg(struct kiocb *iocb, str lock_sock(sk); timeo = sock_sndtimeo(sk, noblock); + /* FIXME imcdnzl - we should be using timeo for memory allocation */ /* * We have to use sk_stream_wait_connect here to set sk_write_pending, @@ -407,19 +408,13 @@ int dccp_sendmsg(struct kiocb *iocb, str if (rc != 0) goto out_discard; - rc = dccp_write_xmit(sk, skb, &timeo); - /* - * XXX we don't use sk_write_queue, so just discard the packet. - * Current plan however is to _use_ sk_write_queue with - * an algorith similar to tcp_sendmsg, where the main difference - * is that in DCCP we have to respect packet boundaries, so - * no coalescing of skbs. - * - * This bug was _quickly_ found & fixed by just looking at an OSTRA - * generated callgraph 8) -acme - */ + skb_queue_tail(&sk->sk_write_queue, skb); + release_sock(sk); + dccp_write_xmit(sk,0); + goto out_end; out_release: release_sock(sk); +out_end: return rc ? : len; out_discard: kfree_skb(skb); @@ -591,6 +586,7 @@ static int dccp_close_state(struct sock void dccp_close(struct sock *sk, long timeout) { + struct dccp_sock *dp = dccp_sk(sk); struct sk_buff *skb; lock_sock(sk); @@ -606,6 +602,8 @@ void dccp_close(struct sock *sk, long ti goto adjudge_to_death; } + del_timer_sync(&dp->dccps_xmit_timer); + /* * We need to flush the recv. buffs. We do this only on the * descriptor close, not protocol-sourced closes, because the