Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / new-tcp-zero-copy-2.4.21-rhel3.patch
1 diff -uNr linux-2.4.21-32.0.1.EL/include/linux/skbuff.h linux-2.4.21-32.0.1.EL-newzc/include/linux/skbuff.h
2 --- linux-2.4.21-32.0.1.EL/include/linux/skbuff.h       2005-06-02 05:51:57.000000000 +0300
3 +++ linux-2.4.21-32.0.1.EL-newzc/include/linux/skbuff.h 2006-10-23 23:54:31.000000000 +0300
4 @@ -116,6 +116,36 @@
5         __u16 size;
6  };
7  
8 +/* Zero Copy Callback Descriptor
9 + * This struct supports receiving notification when zero-copy network I/O has
10 + * completed.  The ZCCD can be embedded in a struct containing the state of a
11 + * zero-copy network send.  Every skbuff that references that send's pages also
12 + * keeps a reference on the ZCCD.  When they have all been disposed of, the
13 + * reference count on the ZCCD drops to zero and the callback is made, telling
14 + * the original caller that the pages may now be overwritten. */
15 +struct zccd 
16 +{
17 +       atomic_t         zccd_refcount;
18 +       void           (*zccd_callback)(struct zccd *); 
19 +};
20 +
21 +static inline void zccd_init (struct zccd *d, void (*callback)(struct zccd *))
22 +{
23 +       atomic_set (&d->zccd_refcount, 1);
24 +       d->zccd_callback = callback;
25 +}
26 +
27 +static inline void zccd_incref (struct zccd *d)        /* take a reference */
28 +{
29 +       atomic_inc (&d->zccd_refcount);
30 +}
31 +
32 +static inline void zccd_decref (struct zccd *d)        /* release a reference */
33 +{
34 +       if (atomic_dec_and_test (&d->zccd_refcount))
35 +               (d->zccd_callback)(d);
36 +}
37 +
38  /* This data is invariant across clones and lives at
39   * the end of the header data, ie. at skb->end.
40   */
41 @@ -123,6 +153,11 @@
42         atomic_t        dataref;
43         unsigned int    nr_frags;
44         struct sk_buff  *frag_list;
45 +       struct zccd     *zccd1;
46 +       struct zccd     *zccd2;
47 +       /* NB zero-copy data is normally whole pages.  We have 2 zccds in an
48 +        * skbuff so we don't unneccessarily split the packet where pages fall
49 +        * into the same packet. */
50         skb_frag_t      frags[MAX_SKB_FRAGS];
51  };
52  
53 @@ -1153,6 +1188,23 @@
54  #endif
55  }
56  
57 +/* This skbuf has dropped its pages: drop refs on any zero-copy callback
58 + * descriptors it has. */
59 +static inline void skb_complete_zccd (struct sk_buff *skb)
60 +{
61 +       struct skb_shared_info *info = skb_shinfo(skb);
62 +       
63 +       if (info->zccd1 != NULL) {
64 +               zccd_decref(info->zccd1);
65 +               info->zccd1 = NULL;
66 +       }
67 +
68 +       if (info->zccd2 != NULL) {
69 +               zccd_decref(info->zccd2);
70 +               info->zccd2 = NULL;
71 +       }
72 +}
73 +
74  #define skb_queue_walk(queue, skb) \
75                 for (skb = (queue)->next;                       \
76                      (skb != (struct sk_buff *)(queue));        \
77 diff -uNr linux-2.4.21-32.0.1.EL/include/net/tcp.h linux-2.4.21-32.0.1.EL-newzc/include/net/tcp.h
78 --- linux-2.4.21-32.0.1.EL/include/net/tcp.h    2005-06-02 05:51:51.000000000 +0300
79 +++ linux-2.4.21-32.0.1.EL-newzc/include/net/tcp.h      2006-10-23 23:54:37.000000000 +0300
80 @@ -636,6 +636,8 @@
81  
82  extern int                     tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size);
83  extern ssize_t                 tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags);
84 +extern ssize_t                 tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size,
85 +                                                 int flags, struct zccd *zccd);
86  
87  extern int                     tcp_ioctl(struct sock *sk, 
88                                           int cmd, 
89 diff -uNr linux-2.4.21-32.0.1.EL/net/core/skbuff.c linux-2.4.21-32.0.1.EL-newzc/net/core/skbuff.c
90 --- linux-2.4.21-32.0.1.EL/net/core/skbuff.c    2005-06-02 05:51:57.000000000 +0300
91 +++ linux-2.4.21-32.0.1.EL-newzc/net/core/skbuff.c      2006-10-23 23:44:10.000000000 +0300
92 @@ -210,6 +210,9 @@
93         atomic_set(&(skb_shinfo(skb)->dataref), 1);
94         skb_shinfo(skb)->nr_frags = 0;
95         skb_shinfo(skb)->frag_list = NULL;
96 +       skb_shinfo(skb)->zccd1 = NULL;          /* zero-copy completion callback */
97 +       skb_shinfo(skb)->zccd2 = NULL;          /* not required (yet) */
98 +
99         return skb;
100  
101  nodata:
102 @@ -280,6 +283,9 @@
103  {
104         if (!skb->cloned ||
105             atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) {
106 +               /* complete zero-copy callbacks (if any) */
107 +               skb_complete_zccd(skb);
108 +
109                 if (skb_shinfo(skb)->nr_frags) {
110                         int i;
111                         for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
112 @@ -550,6 +556,8 @@
113         atomic_set(&(skb_shinfo(skb)->dataref), 1);
114         skb_shinfo(skb)->nr_frags = 0;
115         skb_shinfo(skb)->frag_list = NULL;
116 +       skb_shinfo(skb)->zccd1 = NULL;          /* zero-copy completion callback */
117 +       skb_shinfo(skb)->zccd2 = NULL;          /* not required */
118  
119         /* We are no longer a clone, even if we were. */
120         skb->cloned = 0;
121 @@ -604,6 +612,18 @@
122                         get_page(skb_shinfo(n)->frags[i].page);
123                 }
124                 skb_shinfo(n)->nr_frags = i;
125 +
126 +               if (skb_shinfo(skb)->zccd1 != NULL) {
127 +                       BUG_TRAP(skb_shinfo(n)->zccd1 = NULL);
128 +                       skb_shinfo(n)->zccd1 = skb_shinfo(skb)->zccd1;
129 +                       zccd_incref(skb_shinfo(n)->zccd1);
130 +               }
131 +
132 +               if (skb_shinfo(skb)->zccd2 != NULL) {
133 +                       BUG_TRAP(skb_shinfo(n)->zccd2 = NULL);
134 +                       skb_shinfo(n)->zccd2 = skb_shinfo(skb)->zccd2;
135 +                       zccd_incref(skb_shinfo(n)->zccd2);
136 +               }
137         }
138  
139         if (skb_shinfo(skb)->frag_list) {
140 @@ -653,6 +673,13 @@
141         memcpy(data+nhead, skb->head, skb->tail-skb->head);
142         memcpy(data+size, skb->end, sizeof(struct skb_shared_info));
143  
144 +       /* zero-copy descriptors have been copied into the new shinfo - 
145 +        * account the new references */
146 +       if (skb_shinfo(skb)->zccd1 != NULL)
147 +          zccd_incref(skb_shinfo(skb)->zccd1);
148 +       if (skb_shinfo(skb)->zccd2 != NULL)
149 +          zccd_incref(skb_shinfo(skb)->zccd2);
150 +
151         for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
152                 get_page(skb_shinfo(skb)->frags[i].page);
153  
154 @@ -809,6 +836,9 @@
155                 offset = end;
156         }
157  
158 +       if (skb_shinfo(skb)->nr_frags == 0)     /* dropped all the pages */
159 +               skb_complete_zccd(skb);         /* drop zccd refs */
160 +       
161         if (offset < len) {
162                 skb->data_len -= skb->len - len;
163                 skb->len = len;
164 @@ -962,6 +992,9 @@
165         }
166         skb_shinfo(skb)->nr_frags = k;
167  
168 +       if (k == 0)                             /* dropped all the pages */
169 +               skb_complete_zccd(skb);         /* drop zccd refs */
170 +
171         skb->tail += delta;
172         skb->data_len -= delta;
173  
174 diff -uNr linux-2.4.21-32.0.1.EL/net/ipv4/tcp.c linux-2.4.21-32.0.1.EL-newzc/net/ipv4/tcp.c
175 --- linux-2.4.21-32.0.1.EL/net/ipv4/tcp.c       2005-06-02 05:51:51.000000000 +0300
176 +++ linux-2.4.21-32.0.1.EL-newzc/net/ipv4/tcp.c 2006-10-24 00:10:34.000000000 +0300
177 @@ -1015,7 +1015,7 @@
178         goto out;
179  }
180  
181 -ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags);
182 +ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags, struct zccd *zccd);
183  
184  static inline int
185  can_coalesce(struct sk_buff *skb, int i, struct page *page, int off)
186 @@ -1094,7 +1094,7 @@
187         return err;
188  }
189  
190 -ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags)
191 +ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags, struct zccd *zccd)
192  {
193         struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
194         int mss_now;
195 @@ -1147,6 +1147,17 @@
196                         copy = size;
197  
198                 i = skb_shinfo(skb)->nr_frags;
199 +
200 +               if (zccd != NULL &&             /* this is a zcc I/O */
201 +                   skb_shinfo(skb)->zccd1 != NULL && /* skb is part of a zcc I/O */
202 +                   skb_shinfo(skb)->zccd2 != NULL &&
203 +                   skb_shinfo(skb)->zccd1 != zccd && /* not the same one */
204 +                   skb_shinfo(skb)->zccd2 != zccd)
205 +               {
206 +                       tcp_mark_push (tp, skb);
207 +                       goto new_segment;
208 +               }
209 +
210                 if (can_coalesce(skb, i, page, offset)) {
211                         skb_shinfo(skb)->frags[i-1].size += copy;
212                 } else if (i < MAX_SKB_FRAGS) {
213 @@ -1157,6 +1168,18 @@
214                         goto new_segment;
215                 }
216  
217 +               if (zccd != NULL &&                   /* completion callback wanted */
218 +                   skb_shinfo(skb)->zccd1 != zccd && /* new to this skbuf */
219 +                   skb_shinfo(skb)->zccd2 != zccd) {
220 +                       if (skb_shinfo(skb)->zccd1 == NULL) {
221 +                               skb_shinfo(skb)->zccd1 = zccd;
222 +                       } else {
223 +                               BUG_TRAP (skb_shinfo(skb)->zccd2 == NULL);
224 +                               skb_shinfo(skb)->zccd2 = zccd;
225 +                       }
226 +                       zccd_incref(zccd);            /* new reference */
227 +               }
228 +
229                 skb->len += copy;
230                 skb->data_len += copy;
231                 skb->ip_summed = CHECKSUM_HW;
232 @@ -1209,7 +1232,8 @@
233         return tcp_error(sk, flags, err);
234  }
235  
236 -ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
237 +ssize_t tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, 
238 +                         size_t size, int flags, struct zccd *zccd)
239  {
240         struct kveclet let = { page, offset, size };
241         ssize_t res;
242 @@ -1224,12 +1248,18 @@
243  
244         lock_sock(sk);
245         TCP_CHECK_TIMER(sk);
246 -       res = do_tcp_sendpages(sk, &let, 0, size, flags);
247 +       res = do_tcp_sendpages(sk, &let, 0, size, flags, zccd);
248         TCP_CHECK_TIMER(sk);
249         release_sock(sk);
250         return res;
251  }
252  
253 +ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
254 +{
255 +      return tcp_sendpage_zccd(sock, page, offset, size, flags, NULL);
256 +}
257 +
258 +
259  static void tcp_kvec_write_worker(struct tcp_write_async_info *info)
260  {
261         struct sock *sk = info->sk;
262 @@ -1238,7 +1268,7 @@
263             !(sk->route_caps & TCP_ZC_CSUM_FLAGS))
264                 BUG();
265  
266 -       res = do_tcp_sendpages(sk, info->cur_let, info->offset, info->len - info->done, MSG_DONTWAIT);
267 +       res = do_tcp_sendpages(sk, info->cur_let, info->offset, info->len - info->done, MSG_DONTWAIT, NULL);
268         if (res > 0)
269                 info->done += res;
270  
271 diff -uNr linux-2.4.21-32.0.1.EL/net/ipv4/tcp_output.c linux-2.4.21-32.0.1.EL-newzc/net/ipv4/tcp_output.c
272 --- linux-2.4.21-32.0.1.EL/net/ipv4/tcp_output.c        2005-06-02 05:51:50.000000000 +0300
273 +++ linux-2.4.21-32.0.1.EL-newzc/net/ipv4/tcp_output.c  2006-10-23 23:44:10.000000000 +0300
274 @@ -363,6 +363,15 @@
275                 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
276                         skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i];
277  
278 +               /* Transfer zero-copy callback descriptors */
279 +               BUG_TRAP(skb_shinfo(skb1)->zccd1 == NULL);
280 +               skb_shinfo(skb1)->zccd1    = skb_shinfo(skb)->zccd1;
281 +               skb_shinfo(skb)->zccd1     = NULL;
282 +
283 +               BUG_TRAP(skb_shinfo(skb1)->zccd2 == NULL);
284 +               skb_shinfo(skb1)->zccd2    = skb_shinfo(skb)->zccd2;
285 +               skb_shinfo(skb)->zccd2     = NULL;
286 +
287                 skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags;
288                 skb_shinfo(skb)->nr_frags = 0;
289  
290 @@ -409,6 +418,30 @@
291                         pos += size;
292                 }
293                 skb_shinfo(skb1)->nr_frags = k;
294 +
295 +               if (k != 0) {                           
296 +                       /* skb1 has pages. Transfer or clone the zccds */
297 +
298 +                       if (skb_shinfo(skb)->zccd1 != NULL) {
299 +                               BUG_TRAP(skb_shinfo(skb1)->zccd1 == NULL);
300 +                               skb_shinfo(skb1)->zccd1 = skb_shinfo(skb)->zccd1;
301 +                     
302 +                               if (skb_shinfo(skb)->nr_frags == 0)
303 +                                       skb_shinfo(skb)->zccd1 = NULL;
304 +                               else
305 +                                       zccd_incref(skb_shinfo(skb)->zccd1);
306 +                       }
307 +
308 +                       if (skb_shinfo(skb)->zccd2 != NULL) {
309 +                               BUG_TRAP(skb_shinfo(skb1)->zccd2 == NULL);
310 +                               skb_shinfo(skb1)->zccd2 = skb_shinfo(skb)->zccd2;
311 +
312 +                               if (skb_shinfo(skb)->nr_frags == 0)
313 +                                       skb_shinfo(skb)->zccd2 = NULL;
314 +                               else
315 +                                       zccd_incref(skb_shinfo(skb)->zccd2);
316 +                       }
317 +               }
318         }
319  }
320  
321 --- linux-2.4.21-32.0.1.EL/net/netsyms.c        2005-06-02 05:51:50.000000000 +0300
322 +++ linux-2.4.21-32.0.1.EL-newzc/net/netsyms.c  2006-10-23 23:44:10.000000000 +0300
323 @@ -424,6 +424,7 @@
324  EXPORT_SYMBOL(ip_generic_getfrag);
325  
326  #endif
327 +EXPORT_SYMBOL(tcp_sendpage_zccd);
328  EXPORT_SYMBOL(tcp_read_sock);
329  
330  EXPORT_SYMBOL(netlink_set_err);