aoe: zero copy write 1 of 2
Avoid memory copy on writes.
(This patch depends on fixes in patch 9 to follow.)
Although skb->len should not be set when working with linear skbuffs,
the skb->tail pointer maintained by skb_put/skb_trim is not relevant
to what happens when the skb_fill_page_desc function is called. This
issue was raised without comment in linux-kernel and netdev earlier
this month:
http://thread.gmane.org/gmane.linux.kernel/446474/
http://thread.gmane.org/gmane.linux.network/45444/
So until there is something analogous to skb_put that works for
zero-copy write skbuffs, we will do what the other callers of
skb_fill_page_desc are doing.
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>
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index c7e05ed8..abf1d3c 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -63,22 +63,32 @@
struct frame *f, *e;
d = kzalloc(sizeof *d, GFP_ATOMIC);
- if (d == NULL)
- return NULL;
f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
- if (f == NULL) {
- kfree(d);
+ switch (!d || !f) {
+ case 0:
+ d->nframes = nframes;
+ d->frames = f;
+ e = f + nframes;
+ for (; f<e; f++) {
+ f->tag = FREETAG;
+ f->skb = new_skb(ETH_ZLEN);
+ if (!f->skb)
+ break;
+ }
+ if (f == e)
+ break;
+ while (f > d->frames) {
+ f--;
+ dev_kfree_skb(f->skb);
+ }
+ default:
+ if (f)
+ kfree(f);
+ if (d)
+ kfree(d);
return NULL;
}
-
INIT_WORK(&d->work, aoecmd_sleepwork, d);
-
- d->nframes = nframes;
- d->frames = f;
- e = f + nframes;
- for (; f<e; f++)
- f->tag = FREETAG;
-
spin_lock_init(&d->lock);
init_timer(&d->timer);
d->timer.data = (ulong) d;
@@ -160,11 +170,19 @@
static void
aoedev_freedev(struct aoedev *d)
{
+ struct frame *f, *e;
+
if (d->gd) {
aoedisk_rm_sysfs(d);
del_gendisk(d->gd);
put_disk(d->gd);
}
+ f = d->frames;
+ e = f + d->nframes;
+ for (; f<e; f++) {
+ skb_shinfo(f->skb)->nr_frags = 0;
+ dev_kfree_skb(f->skb);
+ }
kfree(d->frames);
if (d->bufpool)
mempool_destroy(d->bufpool);