diff options
author | Ed L. Cashin <ecashin@coraid.com> | 2006-09-20 14:36:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-10-18 15:53:50 -0400 |
commit | 4f51dc5e9ae195d2e8c22e5f574e004c2f6518a4 (patch) | |
tree | 852ab0b29d19f1ac9a4f7e7eeba6510c0ee7bca1 /drivers/block/aoe/aoecmd.c | |
parent | dced3a053dd5415a7321e1ae153c96dea644da4e (diff) |
aoe: zero copy write 2 of 2
Avoid memory copy on writes.
(This patch follows patch 4.)
Signed-off-by: "Ed L. Cashin" <ecashin@coraid.com>
Acked-by: Alan Cox <alan@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/block/aoe/aoecmd.c')
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 82 |
1 files changed, 62 insertions, 20 deletions
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index c0bdc1fe21f0..9ebc98ade3c5 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -120,7 +120,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
120 | h = (struct aoe_hdr *) skb->mac.raw; | 120 | h = (struct aoe_hdr *) skb->mac.raw; |
121 | ah = (struct aoe_atahdr *) (h+1); | 121 | ah = (struct aoe_atahdr *) (h+1); |
122 | skb->len = sizeof *h + sizeof *ah; | 122 | skb->len = sizeof *h + sizeof *ah; |
123 | memset(h, 0, skb->len); | 123 | memset(h, 0, ETH_ZLEN); |
124 | f->tag = aoehdr_atainit(d, h); | 124 | f->tag = aoehdr_atainit(d, h); |
125 | f->waited = 0; | 125 | f->waited = 0; |
126 | f->buf = buf; | 126 | f->buf = buf; |
@@ -143,8 +143,9 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
143 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), | 143 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), |
144 | offset_in_page(f->bufaddr), bcnt); | 144 | offset_in_page(f->bufaddr), bcnt); |
145 | ah->aflags |= AOEAFL_WRITE; | 145 | ah->aflags |= AOEAFL_WRITE; |
146 | skb->len += bcnt; | ||
147 | skb->data_len = bcnt; | ||
146 | } else { | 148 | } else { |
147 | skb_shinfo(skb)->nr_frags = 0; | ||
148 | skb->len = ETH_ZLEN; | 149 | skb->len = ETH_ZLEN; |
149 | writebit = 0; | 150 | writebit = 0; |
150 | } | 151 | } |
@@ -167,8 +168,9 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
167 | } | 168 | } |
168 | 169 | ||
169 | skb->dev = d->ifp; | 170 | skb->dev = d->ifp; |
170 | skb_get(skb); | 171 | skb = skb_clone(skb, GFP_ATOMIC); |
171 | skb->next = NULL; | 172 | if (skb == NULL) |
173 | return; | ||
172 | if (d->sendq_hd) | 174 | if (d->sendq_hd) |
173 | d->sendq_tl->next = skb; | 175 | d->sendq_tl->next = skb; |
174 | else | 176 | else |
@@ -224,6 +226,29 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) | |||
224 | return sl; | 226 | return sl; |
225 | } | 227 | } |
226 | 228 | ||
229 | static struct frame * | ||
230 | freeframe(struct aoedev *d) | ||
231 | { | ||
232 | struct frame *f, *e; | ||
233 | int n = 0; | ||
234 | |||
235 | f = d->frames; | ||
236 | e = f + d->nframes; | ||
237 | for (; f<e; f++) { | ||
238 | if (f->tag != FREETAG) | ||
239 | continue; | ||
240 | if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { | ||
241 | skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; | ||
242 | return f; | ||
243 | } | ||
244 | n++; | ||
245 | } | ||
246 | if (n == d->nframes) /* wait for network layer */ | ||
247 | d->flags |= DEVFL_KICKME; | ||
248 | |||
249 | return NULL; | ||
250 | } | ||
251 | |||
227 | /* enters with d->lock held */ | 252 | /* enters with d->lock held */ |
228 | void | 253 | void |
229 | aoecmd_work(struct aoedev *d) | 254 | aoecmd_work(struct aoedev *d) |
@@ -239,7 +264,7 @@ aoecmd_work(struct aoedev *d) | |||
239 | } | 264 | } |
240 | 265 | ||
241 | loop: | 266 | loop: |
242 | f = getframe(d, FREETAG); | 267 | f = freeframe(d); |
243 | if (f == NULL) | 268 | if (f == NULL) |
244 | return; | 269 | return; |
245 | if (d->inprocess == NULL) { | 270 | if (d->inprocess == NULL) { |
@@ -282,20 +307,25 @@ rexmit(struct aoedev *d, struct frame *f) | |||
282 | n = DEFAULTBCNT / 512; | 307 | n = DEFAULTBCNT / 512; |
283 | if (ah->scnt > n) { | 308 | if (ah->scnt > n) { |
284 | ah->scnt = n; | 309 | ah->scnt = n; |
285 | if (ah->aflags & AOEAFL_WRITE) | 310 | if (ah->aflags & AOEAFL_WRITE) { |
286 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), | 311 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), |
287 | offset_in_page(f->bufaddr), DEFAULTBCNT); | 312 | offset_in_page(f->bufaddr), DEFAULTBCNT); |
313 | skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT; | ||
314 | skb->data_len = DEFAULTBCNT; | ||
315 | } | ||
288 | if (++d->lostjumbo > (d->nframes << 1)) | 316 | if (++d->lostjumbo > (d->nframes << 1)) |
289 | if (d->maxbcnt != DEFAULTBCNT) { | 317 | if (d->maxbcnt != DEFAULTBCNT) { |
290 | iprintk("too many lost jumbo - using 1KB frames.\n"); | 318 | iprintk("e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n", |
319 | d->aoemajor, d->aoeminor, d->ifp->name); | ||
291 | d->maxbcnt = DEFAULTBCNT; | 320 | d->maxbcnt = DEFAULTBCNT; |
292 | d->flags |= DEVFL_MAXBCNT; | 321 | d->flags |= DEVFL_MAXBCNT; |
293 | } | 322 | } |
294 | } | 323 | } |
295 | 324 | ||
296 | skb->dev = d->ifp; | 325 | skb->dev = d->ifp; |
297 | skb_get(skb); | 326 | skb = skb_clone(skb, GFP_ATOMIC); |
298 | skb->next = NULL; | 327 | if (skb == NULL) |
328 | return; | ||
299 | if (d->sendq_hd) | 329 | if (d->sendq_hd) |
300 | d->sendq_tl->next = skb; | 330 | d->sendq_tl->next = skb; |
301 | else | 331 | else |
@@ -350,6 +380,10 @@ rexmit_timer(ulong vp) | |||
350 | rexmit(d, f); | 380 | rexmit(d, f); |
351 | } | 381 | } |
352 | } | 382 | } |
383 | if (d->flags & DEVFL_KICKME) { | ||
384 | d->flags &= ~DEVFL_KICKME; | ||
385 | aoecmd_work(d); | ||
386 | } | ||
353 | 387 | ||
354 | sl = d->sendq_hd; | 388 | sl = d->sendq_hd; |
355 | d->sendq_hd = d->sendq_tl = NULL; | 389 | d->sendq_hd = d->sendq_tl = NULL; |
@@ -552,23 +586,27 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
552 | case WIN_WRITE: | 586 | case WIN_WRITE: |
553 | case WIN_WRITE_EXT: | 587 | case WIN_WRITE_EXT: |
554 | if (f->bcnt -= n) { | 588 | if (f->bcnt -= n) { |
589 | skb = f->skb; | ||
555 | f->bufaddr += n; | 590 | f->bufaddr += n; |
556 | put_lba(ahout, f->lba += ahout->scnt); | 591 | put_lba(ahout, f->lba += ahout->scnt); |
557 | n = f->bcnt; | 592 | n = f->bcnt; |
558 | if (n > DEFAULTBCNT) | 593 | if (n > DEFAULTBCNT) |
559 | n = DEFAULTBCNT; | 594 | n = DEFAULTBCNT; |
560 | ahout->scnt = n >> 9; | 595 | ahout->scnt = n >> 9; |
561 | if (ahout->aflags & AOEAFL_WRITE) | 596 | if (ahout->aflags & AOEAFL_WRITE) { |
562 | skb_fill_page_desc(f->skb, 0, | 597 | skb_fill_page_desc(skb, 0, |
563 | virt_to_page(f->bufaddr), | 598 | virt_to_page(f->bufaddr), |
564 | offset_in_page(f->bufaddr), n); | 599 | offset_in_page(f->bufaddr), n); |
600 | skb->len = sizeof *hout + sizeof *ahout + n; | ||
601 | skb->data_len = n; | ||
602 | } | ||
565 | f->tag = newtag(d); | 603 | f->tag = newtag(d); |
566 | hout->tag = cpu_to_be32(f->tag); | 604 | hout->tag = cpu_to_be32(f->tag); |
567 | skb->dev = d->ifp; | 605 | skb->dev = d->ifp; |
568 | skb_get(f->skb); | 606 | skb = skb_clone(skb, GFP_ATOMIC); |
569 | f->skb->next = NULL; | ||
570 | spin_unlock_irqrestore(&d->lock, flags); | 607 | spin_unlock_irqrestore(&d->lock, flags); |
571 | aoenet_xmit(f->skb); | 608 | if (skb) |
609 | aoenet_xmit(skb); | ||
572 | return; | 610 | return; |
573 | } | 611 | } |
574 | if (n > DEFAULTBCNT) | 612 | if (n > DEFAULTBCNT) |
@@ -642,7 +680,7 @@ aoecmd_ata_id(struct aoedev *d) | |||
642 | struct frame *f; | 680 | struct frame *f; |
643 | struct sk_buff *skb; | 681 | struct sk_buff *skb; |
644 | 682 | ||
645 | f = getframe(d, FREETAG); | 683 | f = freeframe(d); |
646 | if (f == NULL) { | 684 | if (f == NULL) { |
647 | eprintk("can't get a frame. This shouldn't happen.\n"); | 685 | eprintk("can't get a frame. This shouldn't happen.\n"); |
648 | return NULL; | 686 | return NULL; |
@@ -652,8 +690,8 @@ aoecmd_ata_id(struct aoedev *d) | |||
652 | skb = f->skb; | 690 | skb = f->skb; |
653 | h = (struct aoe_hdr *) skb->mac.raw; | 691 | h = (struct aoe_hdr *) skb->mac.raw; |
654 | ah = (struct aoe_atahdr *) (h+1); | 692 | ah = (struct aoe_atahdr *) (h+1); |
655 | skb->len = sizeof *h + sizeof *ah; | 693 | skb->len = ETH_ZLEN; |
656 | memset(h, 0, skb->len); | 694 | memset(h, 0, ETH_ZLEN); |
657 | f->tag = aoehdr_atainit(d, h); | 695 | f->tag = aoehdr_atainit(d, h); |
658 | f->waited = 0; | 696 | f->waited = 0; |
659 | 697 | ||
@@ -663,12 +701,11 @@ aoecmd_ata_id(struct aoedev *d) | |||
663 | ah->lba3 = 0xa0; | 701 | ah->lba3 = 0xa0; |
664 | 702 | ||
665 | skb->dev = d->ifp; | 703 | skb->dev = d->ifp; |
666 | skb_get(skb); | ||
667 | 704 | ||
668 | d->rttavg = MAXTIMER; | 705 | d->rttavg = MAXTIMER; |
669 | d->timer.function = rexmit_timer; | 706 | d->timer.function = rexmit_timer; |
670 | 707 | ||
671 | return skb; | 708 | return skb_clone(skb, GFP_ATOMIC); |
672 | } | 709 | } |
673 | 710 | ||
674 | void | 711 | void |
@@ -724,7 +761,12 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
724 | n /= 512; | 761 | n /= 512; |
725 | if (n > ch->scnt) | 762 | if (n > ch->scnt) |
726 | n = ch->scnt; | 763 | n = ch->scnt; |
727 | d->maxbcnt = n ? n * 512 : DEFAULTBCNT; | 764 | n = n ? n * 512 : DEFAULTBCNT; |
765 | if (n != d->maxbcnt) { | ||
766 | iprintk("e%ld.%ld: setting %d byte data frames on %s\n", | ||
767 | d->aoemajor, d->aoeminor, n, d->ifp->name); | ||
768 | d->maxbcnt = n; | ||
769 | } | ||
728 | } | 770 | } |
729 | 771 | ||
730 | /* don't change users' perspective */ | 772 | /* don't change users' perspective */ |