aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/aoe
diff options
context:
space:
mode:
authorEd Cashin <ecashin@coraid.com>2012-12-17 19:04:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-17 20:15:25 -0500
commitbbb44e30d07fdc111e34a5ec935b57521cea9499 (patch)
tree11dda6628c4d7719607891f287c12aa87f06855b /drivers/block/aoe
parentb91316f2b7bc0b1d128a9890a2a4895f7e1c74fc (diff)
aoe: improve handling of misbehaving network paths
An AoE target can have multiple network ports used for AoE, and in the aoe driver, those are tracked by the aoetgt struct. These changes allow the aoe driver to handle network paths, or aoetgts, that are not working well, compared to the others. Paths that do not get responses despite the retransmission of AoE commands are marked as "tainted", and non-tainted paths are preferred. Meanwhile, the aoe driver attempts to "probe" the tainted path in the background by issuing reads of LBA 0 that are padded out to full (possibly jumbo-frame) size. If the probes get responses, then the path is "redeemed", and its taint is removed. This mechanism has been shown to be helpful in transparently handling and recovering from real-world network "brown outs" in ways that the earlier "shoot the help-needing target in the head" mechanism could not. Signed-off-by: Ed Cashin <ecashin@coraid.com> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block/aoe')
-rw-r--r--drivers/block/aoe/aoe.h11
-rw-r--r--drivers/block/aoe/aoecmd.c377
-rw-r--r--drivers/block/aoe/aoedev.c1
3 files changed, 268 insertions, 121 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index bfd765cf0eb7..b6d2b16358be 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -91,6 +91,9 @@ enum {
91 RTTDSCALE = 3, 91 RTTDSCALE = 3,
92 RTTAVG_INIT = USEC_PER_SEC / 4 << RTTSCALE, 92 RTTAVG_INIT = USEC_PER_SEC / 4 << RTTSCALE,
93 RTTDEV_INIT = RTTAVG_INIT / 4, 93 RTTDEV_INIT = RTTAVG_INIT / 4,
94
95 HARD_SCORN_SECS = 10, /* try another remote port after this */
96 MAX_TAINT = 1000, /* cap on aoetgt taint */
94}; 97};
95 98
96struct buf { 99struct buf {
@@ -103,6 +106,10 @@ struct buf {
103 struct request *rq; 106 struct request *rq;
104}; 107};
105 108
109enum frame_flags {
110 FFL_PROBE = 1,
111};
112
106struct frame { 113struct frame {
107 struct list_head head; 114 struct list_head head;
108 u32 tag; 115 u32 tag;
@@ -118,6 +125,7 @@ struct frame {
118 struct bio_vec *bv; 125 struct bio_vec *bv;
119 ulong bcnt; 126 ulong bcnt;
120 ulong bv_off; 127 ulong bv_off;
128 char flags;
121}; 129};
122 130
123struct aoeif { 131struct aoeif {
@@ -138,8 +146,10 @@ struct aoetgt {
138 ushort next_cwnd; /* incr maxout after decrementing to zero */ 146 ushort next_cwnd; /* incr maxout after decrementing to zero */
139 ushort ssthresh; /* slow start threshold */ 147 ushort ssthresh; /* slow start threshold */
140 ulong falloc; /* number of allocated frames */ 148 ulong falloc; /* number of allocated frames */
149 int taint; /* how much we want to avoid this aoetgt */
141 int minbcnt; 150 int minbcnt;
142 int wpkts, rpkts; 151 int wpkts, rpkts;
152 char nout_probes;
143}; 153};
144 154
145struct aoedev { 155struct aoedev {
@@ -174,7 +184,6 @@ struct aoedev {
174 struct list_head rexmitq; /* deferred retransmissions */ 184 struct list_head rexmitq; /* deferred retransmissions */
175 struct aoetgt *targets[NTARGETS]; 185 struct aoetgt *targets[NTARGETS];
176 struct aoetgt **tgt; /* target in use when working */ 186 struct aoetgt **tgt; /* target in use when working */
177 struct aoetgt *htgt; /* target needing rexmit assistance */
178 ulong ntargets; 187 ulong ntargets;
179 ulong kicked; 188 ulong kicked;
180 char ident[512]; 189 char ident[512];
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 391dd8ee2009..000f7fb48841 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -22,6 +22,7 @@
22#define MAXIOC (8192) /* default meant to avoid most soft lockups */ 22#define MAXIOC (8192) /* default meant to avoid most soft lockups */
23 23
24static void ktcomplete(struct frame *, struct sk_buff *); 24static void ktcomplete(struct frame *, struct sk_buff *);
25static int count_targets(struct aoedev *d, int *untainted);
25 26
26static struct buf *nextbuf(struct aoedev *); 27static struct buf *nextbuf(struct aoedev *);
27 28
@@ -43,6 +44,8 @@ static struct {
43 spinlock_t lock; 44 spinlock_t lock;
44} iocq; 45} iocq;
45 46
47static struct page *empty_page;
48
46static struct sk_buff * 49static struct sk_buff *
47new_skb(ulong len) 50new_skb(ulong len)
48{ 51{
@@ -179,8 +182,10 @@ aoe_freetframe(struct frame *f)
179 182
180 t = f->t; 183 t = f->t;
181 f->buf = NULL; 184 f->buf = NULL;
185 f->lba = 0;
182 f->bv = NULL; 186 f->bv = NULL;
183 f->r_skb = NULL; 187 f->r_skb = NULL;
188 f->flags = 0;
184 list_add(&f->head, &t->ffree); 189 list_add(&f->head, &t->ffree);
185} 190}
186 191
@@ -234,20 +239,25 @@ newframe(struct aoedev *d)
234 struct frame *f; 239 struct frame *f;
235 struct aoetgt *t, **tt; 240 struct aoetgt *t, **tt;
236 int totout = 0; 241 int totout = 0;
242 int use_tainted;
243 int has_untainted;
237 244
238 if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ 245 if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */
239 printk(KERN_ERR "aoe: NULL TARGETS!\n"); 246 printk(KERN_ERR "aoe: NULL TARGETS!\n");
240 return NULL; 247 return NULL;
241 } 248 }
242 tt = d->tgt; /* last used target */ 249 tt = d->tgt; /* last used target */
243 for (;;) { 250 for (use_tainted = 0, has_untainted = 0;;) {
244 tt++; 251 tt++;
245 if (tt >= &d->targets[NTARGETS] || !*tt) 252 if (tt >= &d->targets[NTARGETS] || !*tt)
246 tt = d->targets; 253 tt = d->targets;
247 t = *tt; 254 t = *tt;
248 totout += t->nout; 255 if (!t->taint) {
256 has_untainted = 1;
257 totout += t->nout;
258 }
249 if (t->nout < t->maxout 259 if (t->nout < t->maxout
250 && t != d->htgt 260 && (use_tainted || !t->taint)
251 && t->ifp->nd) { 261 && t->ifp->nd) {
252 f = newtframe(d, t); 262 f = newtframe(d, t);
253 if (f) { 263 if (f) {
@@ -256,8 +266,12 @@ newframe(struct aoedev *d)
256 return f; 266 return f;
257 } 267 }
258 } 268 }
259 if (tt == d->tgt) /* we've looped and found nada */ 269 if (tt == d->tgt) { /* we've looped and found nada */
260 break; 270 if (!use_tainted && !has_untainted)
271 use_tainted = 1;
272 else
273 break;
274 }
261 } 275 }
262 if (totout == 0) { 276 if (totout == 0) {
263 d->kicked++; 277 d->kicked++;
@@ -294,21 +308,68 @@ fhash(struct frame *f)
294 list_add_tail(&f->head, &d->factive[n]); 308 list_add_tail(&f->head, &d->factive[n]);
295} 309}
296 310
311static void
312ata_rw_frameinit(struct frame *f)
313{
314 struct aoetgt *t;
315 struct aoe_hdr *h;
316 struct aoe_atahdr *ah;
317 struct sk_buff *skb;
318 char writebit, extbit;
319
320 skb = f->skb;
321 h = (struct aoe_hdr *) skb_mac_header(skb);
322 ah = (struct aoe_atahdr *) (h + 1);
323 skb_put(skb, sizeof(*h) + sizeof(*ah));
324 memset(h, 0, skb->len);
325
326 writebit = 0x10;
327 extbit = 0x4;
328
329 t = f->t;
330 f->tag = aoehdr_atainit(t->d, t, h);
331 fhash(f);
332 t->nout++;
333 f->waited = 0;
334 f->waited_total = 0;
335 if (f->buf)
336 f->lba = f->buf->sector;
337
338 /* set up ata header */
339 ah->scnt = f->bcnt >> 9;
340 put_lba(ah, f->lba);