summaryrefslogtreecommitdiffstats
path: root/drivers/block/aoe/aoedev.c
diff options
context:
space:
mode:
authorEd Cashin2012-10-05 02:16:21 +0200
committerLinus Torvalds2012-10-05 20:05:24 +0200
commit896831f5909e2733c13c9cb13a1a215f10c3eaa8 (patch)
tree9541075df9b3703b7ea8853de619fa98c4be1456 /drivers/block/aoe/aoedev.c
parentaoe: for performance support larger packet payloads (diff)
downloadkernel-qcow2-linux-896831f5909e2733c13c9cb13a1a215f10c3eaa8.tar.gz
kernel-qcow2-linux-896831f5909e2733c13c9cb13a1a215f10c3eaa8.tar.xz
kernel-qcow2-linux-896831f5909e2733c13c9cb13a1a215f10c3eaa8.zip
aoe: kernel thread handles I/O completions for simple locking
Make the frames the aoe driver uses to track the relationship between bios and packets more flexible and detached, so that they can be passed to an "aoe_ktio" thread for completion of I/O. The frames are handled much like skbs, with a capped amount of preallocation so that real-world use cases are likely to run smoothly and degenerate gracefully even under memory pressure. Decoupling I/O completion from the receive path and serializing it in a process makes it easier to think about the correctness of the locking in the driver, especially in the case of a remote MAC address becoming unusable. [dan.carpenter@oracle.com: cleanup an allocation a bit] Signed-off-by: Ed Cashin <ecashin@coraid.com> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block/aoe/aoedev.c')
-rw-r--r--drivers/block/aoe/aoedev.c84
1 files changed, 50 insertions, 34 deletions
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index b2d1fd354eac..40bae1a1ff1e 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -48,47 +48,60 @@ dummy_timer(ulong vp)
}
void
-aoedev_downdev(struct aoedev *d)
+aoe_failbuf(struct aoedev *d, struct buf *buf)
{
- struct aoetgt **t, **te;
- struct frame *f, *e;
- struct buf *buf;
struct bio *bio;
- t = d->targets;
- te = t + NTARGETS;
- for (; t < te && *t; t++) {
- f = (*t)->frames;
- e = f + (*t)->nframes;
- for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) {
- if (f->tag == FREETAG || f->buf == NULL)
- continue;
- buf = f->buf;
- bio = buf->bio;
- if (--buf->nframesout == 0
- && buf != d->inprocess) {
- mempool_free(buf, d->bufpool);
- bio_endio(bio, -EIO);
- }
- }
- (*t)->maxout = (*t)->nframes;
- (*t)->nout = 0;
- }
- buf = d->inprocess;
- if (buf) {
+ if (buf == NULL)
+ return;
+ buf->flags |= BUFFL_FAIL;
+ if (buf->nframesout == 0) {
+ if (buf == d->inprocess) /* ensure we only process this once */
+ d->inprocess = NULL;
bio = buf->bio;
mempool_free(buf, d->bufpool);
bio_endio(bio, -EIO);
}
+}
+
+void
+aoedev_downdev(struct aoedev *d)
+{
+ struct aoetgt *t, **tt, **te;
+ struct frame *f;
+ struct list_head *head, *pos, *nx;
+ int i;
+
+ /* clean out active buffers on all targets */
+ tt = d->targets;
+ te = tt + NTARGETS;
+ for (; tt < te && (t = *tt); tt++) {
+ for (i = 0; i < NFACTIVE; i++) {
+ head = &t->factive[i];
+ list_for_each_safe(pos, nx, head) {
+ list_del(pos);
+ f = list_entry(pos, struct frame, head);
+ if (f->buf) {
+ f->buf->nframesout--;
+ aoe_failbuf(d, f->buf);
+ }
+ aoe_freetframe(f);
+ }
+ }
+ t->maxout = t->nframes;
+ t->nout = 0;
+ }
+
+ /* clean out the in-process buffer (if any) */
+ aoe_failbuf(d, d->inprocess);
d->inprocess = NULL;
d->htgt = NULL;
+ /* clean out all pending I/O */
while (!list_empty(&d->bufq)) {
- buf = container_of(d->bufq.next, struct buf, bufs);
+ struct buf *buf = container_of(d->bufq.next, struct buf, bufs);
list_del(d->bufq.next);
- bio = buf->bio;
- mempool_free(buf, d->bufpool);
- bio_endio(bio, -EIO);
+ aoe_failbuf(d, buf);
}
if (d->gd)
@@ -242,13 +255,16 @@ aoedev_by_sysminor_m(ulong sysminor)
static void
freetgt(struct aoedev *d, struct aoetgt *t)
{
- struct frame *f, *e;
+ struct frame *f;
+ struct list_head *pos, *nx, *head;
- f = t->frames;
- e = f + t->nframes;
- for (; f < e; f++)
+ head = &t->ffree;
+ list_for_each_safe(pos, nx, head) {
+ list_del(pos);
+ f = list_entry(pos, struct frame, head);
skbfree(f->skb);
- kfree(t->frames);
+ kfree(f);
+ }
kfree(t);
}