Commit 3fc9b032 authored by Ed Cashin's avatar Ed Cashin Committed by Linus Torvalds

aoe: commands in retransmit queue use new destination on failure

When one remote MAC address isn't working as a destination for AoE
commands, the frames used to track information associated with the AoE
commands are moved to a new aoetgt (defined by the tuple of {AoE major,
AoE minor, target MAC address}).

This patch makes sure that the frames on the queue for retransmits that
need to be done are updated to use the new destination, so that
retransmits will be sent through a working network path.

Without this change, packets on the retransmit queue will be needlessly
retransmitted to the unresponsive destination MAC, possibly causing
premature target failure before there's time for the retransmit timer to
run again, decide to retransmit again, and finally update the destination
to a working MAC address on the AoE target.
Signed-off-by: default avatarEd Cashin <ecashin@coraid.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5f0c9c48
...@@ -108,6 +108,7 @@ struct frame { ...@@ -108,6 +108,7 @@ struct frame {
struct timeval sent; /* high-res time packet was sent */ struct timeval sent; /* high-res time packet was sent */
u32 sent_jiffs; /* low-res jiffies-based sent time */ u32 sent_jiffs; /* low-res jiffies-based sent time */
ulong waited; ulong waited;
ulong waited_total;
struct aoetgt *t; /* parent target I belong to */ struct aoetgt *t; /* parent target I belong to */
sector_t lba; sector_t lba;
struct sk_buff *skb; /* command skb freed on module exit */ struct sk_buff *skb; /* command skb freed on module exit */
......
...@@ -352,6 +352,7 @@ aoecmd_ata_rw(struct aoedev *d) ...@@ -352,6 +352,7 @@ aoecmd_ata_rw(struct aoedev *d)
fhash(f); fhash(f);
t->nout++; t->nout++;
f->waited = 0; f->waited = 0;
f->waited_total = 0;
f->buf = buf; f->buf = buf;
f->bcnt = bcnt; f->bcnt = bcnt;
f->lba = buf->sector; f->lba = buf->sector;
...@@ -556,30 +557,20 @@ ejectif(struct aoetgt *t, struct aoeif *ifp) ...@@ -556,30 +557,20 @@ ejectif(struct aoetgt *t, struct aoeif *ifp)
dev_put(nd); dev_put(nd);
} }
static int static struct frame *
sthtith(struct aoedev *d) reassign_frame(struct list_head *pos)
{ {
struct frame *f, *nf; struct frame *f;
struct list_head *nx, *pos, *head; struct frame *nf;
struct sk_buff *skb; struct sk_buff *skb;
struct aoetgt *ht = d->htgt;
int i;
for (i = 0; i < NFACTIVE; i++) {
head = &d->factive[i];
list_for_each_safe(pos, nx, head) {
f = list_entry(pos, struct frame, head); f = list_entry(pos, struct frame, head);
if (f->t != ht) nf = newframe(f->t->d);
continue;
nf = newframe(d);
if (!nf) if (!nf)
return 0; return NULL;
/* remove frame from active list */
list_del(pos); list_del(pos);
/* reassign all pertinent bits to new outbound frame */
skb = nf->skb; skb = nf->skb;
nf->skb = f->skb; nf->skb = f->skb;
nf->buf = f->buf; nf->buf = f->buf;
...@@ -588,14 +579,47 @@ sthtith(struct aoedev *d) ...@@ -588,14 +579,47 @@ sthtith(struct aoedev *d)
nf->bv = f->bv; nf->bv = f->bv;
nf->bv_off = f->bv_off; nf->bv_off = f->bv_off;
nf->waited = 0; nf->waited = 0;
nf->sent_jiffs = f->sent_jiffs; nf->waited_total = f->waited_total;
nf->sent = f->sent;
f->skb = skb; f->skb = skb;
aoe_freetframe(f); aoe_freetframe(f);
ht->nout--; f->t->nout--;
nf->t->nout++; nf->t->nout++;
return nf;
}
static int
sthtith(struct aoedev *d)
{
struct frame *f, *nf;
struct list_head *nx, *pos, *head;
struct aoetgt *ht = d->htgt;
int i;
/* look through the active and pending retransmit frames */
for (i = 0; i < NFACTIVE; i++) {
head = &d->factive[i];
list_for_each_safe(pos, nx, head) {
f = list_entry(pos, struct frame, head);
if (f->t != ht)
continue;
nf = reassign_frame(pos);
if (!nf)
return 0;
resend(d, nf); resend(d, nf);
} }
} }
head = &d->rexmitq;
list_for_each_safe(pos, nx, head) {
f = list_entry(pos, struct frame, head);
if (f->t != ht)
continue;
nf = reassign_frame(pos);
if (!nf)
return 0;
resend(d, nf);
}
/* We've cleaned up the outstanding so take away his /* We've cleaned up the outstanding so take away his
* interfaces so he won't be used. We should remove him from * interfaces so he won't be used. We should remove him from
* the target array here, but cleaning up a target is * the target array here, but cleaning up a target is
...@@ -612,6 +636,7 @@ rexmit_deferred(struct aoedev *d) ...@@ -612,6 +636,7 @@ rexmit_deferred(struct aoedev *d)
struct aoetgt *t; struct aoetgt *t;
struct frame *f; struct frame *f;
struct list_head *pos, *nx, *head; struct list_head *pos, *nx, *head;
int since;
head = &d->rexmitq; head = &d->rexmitq;
list_for_each_safe(pos, nx, head) { list_for_each_safe(pos, nx, head) {
...@@ -621,6 +646,9 @@ rexmit_deferred(struct aoedev *d) ...@@ -621,6 +646,9 @@ rexmit_deferred(struct aoedev *d)
continue; continue;
list_del(pos); list_del(pos);
t->nout++; t->nout++;
since = tsince_hr(f);
f->waited += since;
f->waited_total += since;
resend(d, f); resend(d, f);
} }
} }
...@@ -637,6 +665,7 @@ rexmit_timer(ulong vp) ...@@ -637,6 +665,7 @@ rexmit_timer(ulong vp)
register long timeout; register long timeout;
ulong flags, n; ulong flags, n;
int i; int i;
int since;
d = (struct aoedev *) vp; d = (struct aoedev *) vp;
...@@ -669,7 +698,8 @@ rexmit_timer(ulong vp) ...@@ -669,7 +698,8 @@ rexmit_timer(ulong vp)
while (!list_empty(&flist)) { while (!list_empty(&flist)) {
pos = flist.next; pos = flist.next;
f = list_entry(pos, struct frame, head); f = list_entry(pos, struct frame, head);
n = f->waited += tsince_hr(f); since = tsince_hr(f);
n = f->waited_total + since;
n /= USEC_PER_SEC; n /= USEC_PER_SEC;
if (n > aoe_deadsecs) { if (n > aoe_deadsecs) {
/* Waited too long. Device failure. /* Waited too long. Device failure.
...@@ -1301,6 +1331,7 @@ aoecmd_ata_id(struct aoedev *d) ...@@ -1301,6 +1331,7 @@ aoecmd_ata_id(struct aoedev *d)
fhash(f); fhash(f);
t->nout++; t->nout++;
f->waited = 0; f->waited = 0;
f->waited_total = 0;
/* set up ata header */ /* set up ata header */
ah->scnt = 1; ah->scnt = 1;
......
...@@ -170,30 +170,40 @@ aoe_failip(struct aoedev *d) ...@@ -170,30 +170,40 @@ aoe_failip(struct aoedev *d)
aoe_end_request(d, rq, 0); aoe_end_request(d, rq, 0);
} }
static void
downdev_frame(struct list_head *pos)
{
struct frame *f;
f = list_entry(pos, struct frame, head);
list_del(pos);
if (f->buf) {
f->buf->nframesout--;
aoe_failbuf(f->t->d, f->buf);
}
aoe_freetframe(f);
}
void void
aoedev_downdev(struct aoedev *d) aoedev_downdev(struct aoedev *d)
{ {
struct aoetgt *t, **tt, **te; struct aoetgt *t, **tt, **te;
struct frame *f;
struct list_head *head, *pos, *nx; struct list_head *head, *pos, *nx;
struct request *rq; struct request *rq;
int i; int i;
d->flags &= ~DEVFL_UP; d->flags &= ~DEVFL_UP;
/* clean out active buffers */ /* clean out active and to-be-retransmitted buffers */
for (i = 0; i < NFACTIVE; i++) { for (i = 0; i < NFACTIVE; i++) {
head = &d->factive[i]; head = &d->factive[i];
list_for_each_safe(pos, nx, head) { list_for_each_safe(pos, nx, head)
f = list_entry(pos, struct frame, head); downdev_frame(pos);
list_del(pos);
if (f->buf) {
f->buf->nframesout--;
aoe_failbuf(d, f->buf);
}
aoe_freetframe(f);
}
} }
head = &d->rexmitq;
list_for_each_safe(pos, nx, head)
downdev_frame(pos);
/* reset window dressings */ /* reset window dressings */
tt = d->targets; tt = d->targets;
te = tt + NTARGETS; te = tt + NTARGETS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment