diff options
author | Ed Cashin <ecashin@coraid.com> | 2012-10-04 20:16:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 14:05:25 -0400 |
commit | 3f0f0133747368fe0fcf3908f788b53591bff4e0 (patch) | |
tree | 05e8f202fff8f7b848fee76a297c8a7ebbd101f6 /drivers | |
parent | eb086ec59667df5b07d58176e21a5f523ead1d66 (diff) |
aoe: use packets that work with the smallest-MTU local interface
Users with several network interfaces dedicated to AoE generally do not
configure them to support different-sized AoE data payloads on purpose.
For a given AoE target, there will be a set of local network interfaces
that can reach it. Using only the payload that will fit in the
smallest-sized MTU of all those local interfaces greatly simplifies the
driver, especially in failure scenarios.
Signed-off-by: Ed Cashin <ecashin@coraid.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/aoe/aoe.h | 7 | ||||
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 151 |
2 files changed, 87 insertions, 71 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index d0087de1780e..ffded64dcbeb 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h | |||
@@ -125,9 +125,8 @@ struct frame { | |||
125 | 125 | ||
126 | struct aoeif { | 126 | struct aoeif { |
127 | struct net_device *nd; | 127 | struct net_device *nd; |
128 | unsigned char lost; | 128 | ulong lost; |
129 | unsigned char lostjumbo; | 129 | int bcnt; |
130 | ushort maxbcnt; | ||
131 | }; | 130 | }; |
132 | 131 | ||
133 | struct aoetgt { | 132 | struct aoetgt { |
@@ -144,6 +143,7 @@ struct aoetgt { | |||
144 | u16 useme; | 143 | u16 useme; |
145 | ulong falloc; | 144 | ulong falloc; |
146 | ulong lastwadj; /* last window adjustment */ | 145 | ulong lastwadj; /* last window adjustment */ |
146 | int minbcnt; | ||
147 | int wpkts, rpkts; | 147 | int wpkts, rpkts; |
148 | }; | 148 | }; |
149 | 149 | ||
@@ -172,6 +172,7 @@ struct aoedev { | |||
172 | struct bio *nxbio; | 172 | struct bio *nxbio; |
173 | struct request *rq; | 173 | struct request *rq; |
174 | } ip; | 174 | } ip; |
175 | ulong maxbcnt; | ||
175 | struct aoetgt *targets[NTARGETS]; | 176 | struct aoetgt *targets[NTARGETS]; |
176 | struct aoetgt **tgt; /* target in use when working */ | 177 | struct aoetgt **tgt; /* target in use when working */ |
177 | struct aoetgt *htgt; /* target needing rexmit assistance */ | 178 | struct aoetgt *htgt; /* target needing rexmit assistance */ |
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index a1c5e8aa08c0..bbab40c8d67c 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -119,16 +119,18 @@ put_lba(struct aoe_atahdr *ah, sector_t lba) | |||
119 | ah->lba5 = lba >>= 8; | 119 | ah->lba5 = lba >>= 8; |
120 | } | 120 | } |
121 | 121 | ||
122 | static void | 122 | static struct aoeif * |
123 | ifrotate(struct aoetgt *t) | 123 | ifrotate(struct aoetgt *t) |
124 | { | 124 | { |
125 | t->ifp++; | 125 | struct aoeif *ifp; |
126 | if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL) | 126 | |
127 | t->ifp = t->ifs; | 127 | ifp = t->ifp; |
128 | if (t->ifp->nd == NULL) { | 128 | ifp++; |
129 | printk(KERN_INFO "aoe: no interface to rotate to\n"); | 129 | if (ifp >= &t->ifs[NAOEIFS] || ifp->nd == NULL) |
130 | BUG(); | 130 | ifp = t->ifs; |
131 | } | 131 | if (ifp->nd == NULL) |
132 | return NULL; | ||
133 | return t->ifp = ifp; | ||
132 | } | 134 | } |
133 | 135 | ||
134 | static void | 136 | static void |
@@ -232,8 +234,8 @@ newframe(struct aoedev *d) | |||
232 | && t->ifp->nd) { | 234 | && t->ifp->nd) { |
233 | f = newtframe(d, t); | 235 | f = newtframe(d, t); |
234 | if (f) { | 236 | if (f) { |
235 | d->tgt = tt; | ||
236 | ifrotate(t); | 237 | ifrotate(t); |
238 | d->tgt = tt; | ||
237 | return f; | 239 | return f; |
238 | } | 240 | } |
239 | } | 241 | } |
@@ -300,7 +302,7 @@ aoecmd_ata_rw(struct aoedev *d) | |||
300 | return 0; | 302 | return 0; |
301 | t = *d->tgt; | 303 | t = *d->tgt; |
302 | bv = buf->bv; | 304 | bv = buf->bv; |
303 | bcnt = t->ifp->maxbcnt; | 305 | bcnt = d->maxbcnt; |
304 | if (bcnt == 0) | 306 | if (bcnt == 0) |
305 | bcnt = DEFAULTBCNT; | 307 | bcnt = DEFAULTBCNT; |
306 | if (bcnt > buf->resid) | 308 | if (bcnt > buf->resid) |
@@ -431,9 +433,14 @@ resend(struct aoedev *d, struct frame *f) | |||
431 | u32 n; | 433 | u32 n; |
432 | 434 | ||
433 | t = f->t; | 435 | t = f->t; |
434 | ifrotate(t); | ||
435 | n = newtag(t); | 436 | n = newtag(t); |
436 | skb = f->skb; | 437 | skb = f->skb; |
438 | if (ifrotate(t) == NULL) { | ||
439 | /* probably can't happen, but set it up to fail anyway */ | ||
440 | pr_info("aoe: resend: no interfaces to rotate to.\n"); | ||
441 | ktcomplete(f, NULL); | ||
442 | return; | ||
443 | } | ||
437 | h = (struct aoe_hdr *) skb_mac_header(skb); | 444 | h = (struct aoe_hdr *) skb_mac_header(skb); |
438 | ah = (struct aoe_atahdr *) (h+1); | 445 | ah = (struct aoe_atahdr *) (h+1); |
439 | 446 | ||
@@ -483,21 +490,6 @@ getif(struct aoetgt *t, struct net_device *nd) | |||
483 | return NULL; | 490 | return NULL; |
484 | } | 491 | } |
485 | 492 | ||
486 | static struct aoeif * | ||
487 | addif(struct aoetgt *t, struct net_device *nd) | ||
488 | { | ||
489 | struct aoeif *p; | ||
490 | |||
491 | p = getif(t, NULL); | ||
492 | if (!p) | ||
493 | return NULL; | ||
494 | p->nd = nd; | ||
495 | p->maxbcnt = DEFAULTBCNT; | ||
496 | p->lost = 0; | ||
497 | p->lostjumbo = 0; | ||
498 | return p; | ||
499 | } | ||
500 | |||
501 | static void | 493 | static void |
502 | ejectif(struct aoetgt *t, struct aoeif *ifp) | 494 | ejectif(struct aoetgt *t, struct aoeif *ifp) |
503 | { | 495 | { |
@@ -546,7 +538,11 @@ sthtith(struct aoedev *d) | |||
546 | resend(d, nf); | 538 | resend(d, nf); |
547 | } | 539 | } |
548 | } | 540 | } |
549 | /* he's clean, he's useless. take away his interfaces */ | 541 | /* We've cleaned up the outstanding so take away his |
542 | * interfaces so he won't be used. We should remove him from | ||
543 | * the target array here, but cleaning up a target is | ||
544 | * involved. PUNT! | ||
545 | */ | ||
550 | memset(ht->ifs, 0, sizeof ht->ifs); | 546 | memset(ht->ifs, 0, sizeof ht->ifs); |
551 | d->htgt = NULL; | 547 | d->htgt = NULL; |
552 | return 1; | 548 | return 1; |
@@ -1015,11 +1011,8 @@ noskb: if (buf) | |||
1015 | case ATA_CMD_PIO_WRITE_EXT: | 1011 | case ATA_CMD_PIO_WRITE_EXT: |
1016 | spin_lock_irq(&d->lock); | 1012 | spin_lock_irq(&d->lock); |
1017 | ifp = getif(t, skb->dev); | 1013 | ifp = getif(t, skb->dev); |
1018 | if (ifp) { | 1014 | if (ifp) |
1019 | ifp->lost = 0; | 1015 | ifp->lost = 0; |
1020 | if (n > DEFAULTBCNT) | ||
1021 | ifp->lostjumbo = 0; | ||
1022 | } | ||
1023 | if (d->htgt == t) /* I'll help myself, thank you. */ | 1016 | if (d->htgt == t) /* I'll help myself, thank you. */ |
1024 | d->htgt = NULL; | 1017 | d->htgt = NULL; |
1025 | spin_unlock_irq(&d->lock); | 1018 | spin_unlock_irq(&d->lock); |
@@ -1292,6 +1285,56 @@ addtgt(struct aoedev *d, char *addr, ulong nframes) | |||
1292 | return *tt = t; | 1285 | return *tt = t; |
1293 | } | 1286 | } |
1294 | 1287 | ||
1288 | static void | ||
1289 | setdbcnt(struct aoedev *d) | ||
1290 | { | ||
1291 | struct aoetgt **t, **e; | ||
1292 | int bcnt = 0; | ||
1293 | |||
1294 | t = d->targets; | ||
1295 | e = t + NTARGETS; | ||
1296 | for (; t < e && *t; t++) | ||
1297 | if (bcnt == 0 || bcnt > (*t)->minbcnt) | ||
1298 | bcnt = (*t)->minbcnt; | ||
1299 | if (bcnt != d->maxbcnt) { | ||
1300 | d->maxbcnt = bcnt; | ||
1301 | pr_info("aoe: e%ld.%d: setting %d byte data frames\n", | ||
1302 | d->aoemajor, d->aoeminor, bcnt); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | static void | ||
1307 | setifbcnt(struct aoetgt *t, struct net_device *nd, int bcnt) | ||
1308 | { | ||
1309 | struct aoedev *d; | ||
1310 | struct aoeif *p, *e; | ||
1311 | int minbcnt; | ||
1312 | |||
1313 | d = t->d; | ||
1314 | minbcnt = bcnt; | ||
1315 | p = t->ifs; | ||
1316 | e = p + NAOEIFS; | ||
1317 | for (; p < e; p++) { | ||
1318 | if (p->nd == NULL) | ||
1319 | break; /* end of the valid interfaces */ | ||
1320 | if (p->nd == nd) { | ||
1321 | p->bcnt = bcnt; /* we're updating */ | ||
1322 | nd = NULL; | ||
1323 | } else if (minbcnt > p->bcnt) | ||
1324 | minbcnt = p->bcnt; /* find the min interface */ | ||
1325 | } | ||
1326 | if (nd) { | ||
1327 | if (p == e) { | ||
1328 | pr_err("aoe: device setifbcnt failure; too many interfaces.\n"); | ||
1329 | return; | ||
1330 | } | ||
1331 | p->nd = nd; | ||
1332 | p->bcnt = bcnt; | ||
1333 | } | ||
1334 | t->minbcnt = minbcnt; | ||
1335 | setdbcnt(d); | ||
1336 | } | ||
1337 | |||
1295 | void | 1338 | void |
1296 | aoecmd_cfg_rsp(struct sk_buff *skb) | 1339 | aoecmd_cfg_rsp(struct sk_buff *skb) |
1297 | { | 1340 | { |
@@ -1299,7 +1342,6 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
1299 | struct aoe_hdr *h; | 1342 | struct aoe_hdr *h; |
1300 | struct aoe_cfghdr *ch; | 1343 | struct aoe_cfghdr *ch; |
1301 | struct aoetgt *t; | 1344 | struct aoetgt *t; |
1302 | struct aoeif *ifp; | ||
1303 | ulong flags, sysminor, aoemajor; | 1345 | ulong flags, sysminor, aoemajor; |
1304 | struct sk_buff *sl; | 1346 | struct sk_buff *sl; |
1305 | struct sk_buff_head queue; | 1347 | struct sk_buff_head queue; |
@@ -1345,32 +1387,13 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
1345 | if (!t) | 1387 | if (!t) |
1346 | goto bail; | 1388 | goto bail; |
1347 | } | 1389 | } |
1348 | ifp = getif(t, skb->dev); | 1390 | n = skb->dev->mtu; |
1349 | if (!ifp) { | 1391 | n -= sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); |
1350 | ifp = addif(t, skb->dev); | 1392 | n /= 512; |
1351 | if (!ifp) { | 1393 | if (n > ch->scnt) |
1352 | printk(KERN_INFO | 1394 | n = ch->scnt; |
1353 | "aoe: device addif failure; " | 1395 | n = n ? n * 512 : DEFAULTBCNT; |
1354 | "too many interfaces?\n"); | 1396 | setifbcnt(t, skb->dev, n); |
1355 | goto bail; | ||
1356 | } | ||
1357 | } | ||
1358 | if (ifp->maxbcnt) { | ||
1359 | n = ifp->nd->mtu; | ||
1360 | n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); | ||
1361 | n /= 512; | ||
1362 | if (n > ch->scnt) | ||
1363 | n = ch->scnt; | ||
1364 | n = n ? n * 512 : DEFAULTBCNT; | ||
1365 | if (n != ifp->maxbcnt) { | ||
1366 | printk(KERN_INFO | ||
1367 | "aoe: e%ld.%d: setting %d%s%s:%pm\n", | ||
1368 | d->aoemajor, d->aoeminor, n, | ||
1369 | " byte data frames on ", ifp->nd->name, | ||
1370 | t->addr); | ||
1371 | ifp->maxbcnt = n; | ||
1372 | } | ||
1373 | } | ||
1374 | 1397 | ||
1375 | /* don't change users' perspective */ | 1398 | /* don't change users' perspective */ |
1376 | if (d->nopen == 0) { | 1399 | if (d->nopen == 0) { |
@@ -1391,22 +1414,14 @@ void | |||
1391 | aoecmd_cleanslate(struct aoedev *d) | 1414 | aoecmd_cleanslate(struct aoedev *d) |
1392 | { | 1415 | { |
1393 | struct aoetgt **t, **te; | 1416 | struct aoetgt **t, **te; |
1394 | struct aoeif *p, *e; | ||
1395 | 1417 | ||
1396 | d->mintimer = MINTIMER; | 1418 | d->mintimer = MINTIMER; |
1419 | d->maxbcnt = 0; | ||
1397 | 1420 | ||
1398 | t = d->targets; | 1421 | t = d->targets; |
1399 | te = t + NTARGETS; | 1422 | te = t + NTARGETS; |
1400 | for (; t < te && *t; t++) { | 1423 | for (; t < te && *t; t++) |
1401 | (*t)->maxout = (*t)->nframes; | 1424 | (*t)->maxout = (*t)->nframes; |
1402 | p = (*t)->ifs; | ||
1403 | e = p + NAOEIFS; | ||
1404 | for (; p < e; p++) { | ||
1405 | p->lostjumbo = 0; | ||
1406 | p->lost = 0; | ||
1407 | p->maxbcnt = DEFAULTBCNT; | ||
1408 | } | ||
1409 | } | ||
1410 | } | 1425 | } |
1411 | 1426 | ||
1412 | void | 1427 | void |