aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorEd L. Cashin <ecashin@coraid.com>2006-09-20 14:36:49 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-10-18 15:53:50 -0400
commite407a7f6cd143b3ab4eb3d7e1cf882e96b710eb5 (patch)
treea180d2a6ae40b1fe6773c93a24a5c469948fd59d /drivers/block
parent2fdc0ea75b26e3009cfdf72e79901e4e16bb99bd (diff)
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>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/aoe/aoe.h7
-rw-r--r--drivers/block/aoe/aoecmd.c94
-rw-r--r--drivers/block/aoe/aoedev.c42
3 files changed, 69 insertions, 74 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 507c37799882..fa2d804b2665 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -107,11 +107,7 @@ struct frame {
107 ulong waited; 107 ulong waited;
108 struct buf *buf; 108 struct buf *buf;
109 char *bufaddr; 109 char *bufaddr;
110 int writedatalen; 110 struct sk_buff *skb;
111 int ndata;
112
113 /* largest possible */
114 unsigned char data[sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr)];
115}; 111};
116 112
117struct aoedev { 113struct aoedev {
@@ -157,6 +153,7 @@ void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
157void aoecmd_ata_rsp(struct sk_buff *); 153void aoecmd_ata_rsp(struct sk_buff *);
158void aoecmd_cfg_rsp(struct sk_buff *); 154void aoecmd_cfg_rsp(struct sk_buff *);
159void aoecmd_sleepwork(void *vp); 155void aoecmd_sleepwork(void *vp);
156struct sk_buff *new_skb(ulong);
160 157
161int aoedev_init(void); 158int aoedev_init(void);
162void aoedev_exit(void); 159void aoedev_exit(void);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index d1d8759eca85..1aeb2969987f 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -17,15 +17,14 @@
17#define MAXTIMER (HZ << 1) 17#define MAXTIMER (HZ << 1)
18#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */ 18#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */
19 19
20static struct sk_buff * 20struct sk_buff *
21new_skb(struct net_device *if_dev, ulong len) 21new_skb(ulong len)
22{ 22{
23 struct sk_buff *skb; 23 struct sk_buff *skb;
24 24
25 skb = alloc_skb(len, GFP_ATOMIC); 25 skb = alloc_skb(len, GFP_ATOMIC);
26 if (skb) { 26 if (skb) {
27 skb->nh.raw = skb->mac.raw = skb->data; 27 skb->nh.raw = skb->mac.raw = skb->data;
28 skb->dev = if_dev;
29 skb->protocol = __constant_htons(ETH_P_AOE); 28 skb->protocol = __constant_htons(ETH_P_AOE);
30 skb->priority = 0; 29 skb->priority = 0;
31 skb_put(skb, len); 30 skb_put(skb, len);
@@ -40,29 +39,6 @@ new_skb(struct net_device *if_dev, ulong len)
40 return skb; 39 return skb;
41} 40}
42 41
43static struct sk_buff *
44skb_prepare(struct aoedev *d, struct frame *f)
45{
46 struct sk_buff *skb;
47 char *p;
48
49 skb = new_skb(d->ifp, f->ndata + f->writedatalen);
50 if (!skb) {
51 printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n");
52 return NULL;
53 }
54
55 p = skb->mac.raw;
56 memcpy(p, f->data, f->ndata);
57
58 if (f->writedatalen) {
59 p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr);
60 memcpy(p, f->bufaddr, f->writedatalen);
61 }
62
63 return skb;
64}
65
66static struct frame * 42static struct frame *
67getframe(struct aoedev *d, int tag) 43getframe(struct aoedev *d, int tag)
68{ 44{
@@ -129,10 +105,11 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
129 bcnt = MAXATADATA; 105 bcnt = MAXATADATA;
130 106
131 /* initialize the headers & frame */ 107 /* initialize the headers & frame */
132 h = (struct aoe_hdr *) f->data; 108 skb = f->skb;
109 h = (struct aoe_hdr *) skb->mac.raw;
133 ah = (struct aoe_atahdr *) (h+1); 110 ah = (struct aoe_atahdr *) (h+1);
134 f->ndata = sizeof *h + sizeof *ah; 111 skb->len = sizeof *h + sizeof *ah;
135 memset(h, 0, f->ndata); 112 memset(h, 0, skb->len);
136 f->tag = aoehdr_atainit(d, h); 113 f->tag = aoehdr_atainit(d, h);
137 f->waited = 0; 114 f->waited = 0;
138 f->buf = buf; 115 f->buf = buf;
@@ -155,11 +132,13 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
155 } 132 }
156 133
157 if (bio_data_dir(buf->bio) == WRITE) { 134 if (bio_data_dir(buf->bio) == WRITE) {
135 skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
136 offset_in_page(f->bufaddr), bcnt);
158 ah->aflags |= AOEAFL_WRITE; 137 ah->aflags |= AOEAFL_WRITE;
159 f->writedatalen = bcnt;
160 } else { 138 } else {
139 skb_shinfo(skb)->nr_frags = 0;
140 skb->len = ETH_ZLEN;
161 writebit = 0; 141 writebit = 0;
162 f->writedatalen = 0;
163 } 142 }
164 143
165 ah->cmdstat = WIN_READ | writebit | extbit; 144 ah->cmdstat = WIN_READ | writebit | extbit;
@@ -179,15 +158,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
179 buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; 158 buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
180 } 159 }
181 160
182 skb = skb_prepare(d, f); 161 skb->dev = d->ifp;
183 if (skb) { 162 skb_get(skb);
184 skb->next = NULL; 163 skb->next = NULL;
185 if (d->sendq_hd) 164 if (d->sendq_hd)
186 d->sendq_tl->next = skb; 165 d->sendq_tl->next = skb;
187 else 166 else
188 d->sendq_hd = skb; 167 d->sendq_hd = skb;
189 d->sendq_tl = skb; 168 d->sendq_tl = skb;
190 }
191} 169}
192 170
193/* some callers cannot sleep, and they can call this function, 171/* some callers cannot sleep, and they can call this function,
@@ -209,11 +187,12 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
209 if (!is_aoe_netif(ifp)) 187 if (!is_aoe_netif(ifp))
210 continue; 188 continue;
211 189
212 skb = new_skb(ifp, sizeof *h + sizeof *ch); 190 skb = new_skb(sizeof *h + sizeof *ch);
213 if (skb == NULL) { 191 if (skb == NULL) {
214 printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n"); 192 printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
215 continue; 193 continue;
216 } 194 }
195 skb->dev = ifp;
217 if (sl_tail == NULL) 196 if (sl_tail == NULL)
218 sl_tail = skb; 197 sl_tail = skb;
219 h = (struct aoe_hdr *) skb->mac.raw; 198 h = (struct aoe_hdr *) skb->mac.raw;
@@ -283,21 +262,21 @@ rexmit(struct aoedev *d, struct frame *f)
283 d->aoemajor, d->aoeminor, f->tag, jiffies, n); 262 d->aoemajor, d->aoeminor, f->tag, jiffies, n);
284 aoechr_error(buf); 263 aoechr_error(buf);
285 264
286 h = (struct aoe_hdr *) f->data; 265 skb = f->skb;
266 h = (struct aoe_hdr *) skb->mac.raw;
287 f->tag = n; 267 f->tag = n;
288 h->tag = cpu_to_be32(n); 268 h->tag = cpu_to_be32(n);
289 memcpy(h->dst, d->addr, sizeof h->dst); 269 memcpy(h->dst, d->addr, sizeof h->dst);
290 memcpy(h->src, d->ifp->dev_addr, sizeof h->src); 270 memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
291 271
292 skb = skb_prepare(d, f); 272 skb->dev = d->ifp;
293 if (skb) { 273 skb_get(skb);
294 skb->next = NULL; 274 skb->next = NULL;
295 if (d->sendq_hd) 275 if (d->sendq_hd)
296 d->sendq_tl->next = skb; 276 d->sendq_tl->next = skb;
297 else 277 else
298 d->sendq_hd = skb; 278 d->sendq_hd = skb;
299 d->sendq_tl = skb; 279 d->sendq_tl = skb;
300 }
301} 280}
302 281
303static int 282static int
@@ -514,7 +493,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
514 calc_rttavg(d, tsince(f->tag)); 493 calc_rttavg(d, tsince(f->tag));
515 494
516 ahin = (struct aoe_atahdr *) (hin+1); 495 ahin = (struct aoe_atahdr *) (hin+1);
517 ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr)); 496 ahout = (struct aoe_atahdr *) (f->skb->mac.raw + sizeof(struct aoe_hdr));
518 buf = f->buf; 497 buf = f->buf;
519 498
520 if (ahout->cmdstat == WIN_IDENTIFY) 499 if (ahout->cmdstat == WIN_IDENTIFY)
@@ -620,20 +599,21 @@ aoecmd_ata_id(struct aoedev *d)
620 } 599 }
621 600
622 /* initialize the headers & frame */ 601 /* initialize the headers & frame */
623 h = (struct aoe_hdr *) f->data; 602 skb = f->skb;
603 h = (struct aoe_hdr *) skb->mac.raw;
624 ah = (struct aoe_atahdr *) (h+1); 604 ah = (struct aoe_atahdr *) (h+1);
625 f->ndata = sizeof *h + sizeof *ah; 605 skb->len = sizeof *h + sizeof *ah;
626 memset(h, 0, f->ndata); 606 memset(h, 0, skb->len);
627 f->tag = aoehdr_atainit(d, h); 607 f->tag = aoehdr_atainit(d, h);
628 f->waited = 0; 608 f->waited = 0;
629 f->writedatalen = 0;
630 609
631 /* set up ata header */ 610 /* set up ata header */
632 ah->scnt = 1; 611 ah->scnt = 1;
633 ah->cmdstat = WIN_IDENTIFY; 612 ah->cmdstat = WIN_IDENTIFY;
634 ah->lba3 = 0xa0; 613 ah->lba3 = 0xa0;
635 614
636 skb = skb_prepare(d, f); 615 skb->dev = d->ifp;
616 skb_get(skb);
637 617
638 d->rttavg = MAXTIMER; 618 d->rttavg = MAXTIMER;
639 d->timer.function = rexmit_timer; 619 d->timer.function = rexmit_timer;
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index c7e05ed82512..abf1d3c073e3 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -63,22 +63,32 @@ aoedev_newdev(ulong nframes)
63 struct frame *f, *e; 63 struct frame *f, *e;
64 64
65 d = kzalloc(sizeof *d, GFP_ATOMIC); 65 d = kzalloc(sizeof *d, GFP_ATOMIC);
66 if (d == NULL)
67 return NULL;
68 f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); 66 f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
69 if (f == NULL) { 67 switch (!d || !f) {
70 kfree(d); 68 case 0:
69 d->nframes = nframes;
70 d->frames = f;
71 e = f + nframes;
72 for (; f<e; f++) {
73 f->tag = FREETAG;
74 f->skb = new_skb(ETH_ZLEN);
75 if (!f->skb)
76 break;
77 }
78 if (f == e)
79 break;
80 while (f > d->frames) {
81 f--;
82 dev_kfree_skb(f->skb);
83 }
84 default:
85 if (f)
86 kfree(f);
87 if (d)
88 kfree(d);
71 return NULL; 89 return NULL;
72 } 90 }
73
74 INIT_WORK(&d->work, aoecmd_sleepwork, d); 91 INIT_WORK(&d->work, aoecmd_sleepwork, d);
75
76 d->nframes = nframes;
77 d->frames = f;
78 e = f + nframes;
79 for (; f<e; f++)
80 f->tag = FREETAG;
81
82 spin_lock_init(&d->lock); 92 spin_lock_init(&d->lock);
83 init_timer(&d->timer); 93 init_timer(&d->timer);
84 d->timer.data = (ulong) d; 94 d->timer.data = (ulong) d;
@@ -160,11 +170,19 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
160static void 170static void
161aoedev_freedev(struct aoedev *d) 171aoedev_freedev(struct aoedev *d)
162{ 172{
173 struct frame *f, *e;
174
163 if (d->gd) { 175 if (d->gd) {
164 aoedisk_rm_sysfs(d); 176 aoedisk_rm_sysfs(d);
165 del_gendisk(d->gd); 177 del_gendisk(d->gd);
166 put_disk(d->gd); 178 put_disk(d->gd);
167 } 179 }
180 f = d->frames;
181 e = f + d->nframes;
182 for (; f<e; f++) {
183 skb_shinfo(f->skb)->nr_frags = 0;
184 dev_kfree_skb(f->skb);
185 }
168 kfree(d->frames); 186 kfree(d->frames);
169 if (d->bufpool) 187 if (d->bufpool)
170 mempool_destroy(d->bufpool); 188 mempool_destroy(d->bufpool);