Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 84705
b: refs/heads/master
c: 9bb237b
h: refs/heads/master
i:
  84703: a4cee3c
v: v3
  • Loading branch information
Ed L. Cashin authored and Linus Torvalds committed Feb 8, 2008
1 parent 59e4cc1 commit 6f195b3
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 42 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 262bf54144ebcb78cd0d057d2705dc5fb7bba7ac
refs/heads/master: 9bb237b6a670fa7a6af3adc65231b1f6fda44510
5 changes: 5 additions & 0 deletions trunk/drivers/block/aoe/aoe.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ enum {
MIN_BUFS = 16,
NTARGETS = 8,
NAOEIFS = 8,
NSKBPOOLMAX = 128,

TIMERTICK = HZ / 10,
MINTIMER = HZ >> 2,
Expand Down Expand Up @@ -138,6 +139,7 @@ struct aoetgt {
u16 useme;
ulong lastwadj; /* last window adjustment */
int wpkts, rpkts;
int dataref;
};

struct aoedev {
Expand All @@ -159,6 +161,9 @@ struct aoedev {
spinlock_t lock;
struct sk_buff *sendq_hd; /* packets needing to be sent, list head */
struct sk_buff *sendq_tl;
struct sk_buff *skbpool_hd;
struct sk_buff *skbpool_tl;
int nskbpool;
mempool_t *bufpool; /* for deadlock-free Buf allocation */
struct list_head bufq; /* queue of bios to work on */
struct buf *inprocess; /* the one we're currently working on */
Expand Down
117 changes: 83 additions & 34 deletions trunk/drivers/block/aoe/aoecmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,45 +106,104 @@ ifrotate(struct aoetgt *t)
}
}

static void
skb_pool_put(struct aoedev *d, struct sk_buff *skb)
{
if (!d->skbpool_hd)
d->skbpool_hd = skb;
else
d->skbpool_tl->next = skb;
d->skbpool_tl = skb;
}

static struct sk_buff *
skb_pool_get(struct aoedev *d)
{
struct sk_buff *skb;

skb = d->skbpool_hd;
if (skb && atomic_read(&skb_shinfo(skb)->dataref) == 1) {
d->skbpool_hd = skb->next;
skb->next = NULL;
return skb;
}
if (d->nskbpool < NSKBPOOLMAX
&& (skb = new_skb(ETH_ZLEN))) {
d->nskbpool++;
return skb;
}
return NULL;
}

/* freeframe is where we do our load balancing so it's a little hairy. */
static struct frame *
freeframe(struct aoedev *d)
{
struct frame *f, *e;
struct frame *f, *e, *rf;
struct aoetgt **t;
ulong n;
struct sk_buff *skb;

if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */
printk(KERN_ERR "aoe: NULL TARGETS!\n");
return NULL;
}
t = d->targets;
do {
if (t != d->htgt
&& (*t)->ifp->nd
&& (*t)->nout < (*t)->maxout) {
n = (*t)->nframes;
t = d->tgt;
t++;
if (t >= &d->targets[NTARGETS] || !*t)
t = d->targets;
for (;;) {
if ((*t)->nout < (*t)->maxout
&& t != d->htgt
&& (*t)->ifp->nd) {
rf = NULL;
f = (*t)->frames;
e = f + n;
e = f + (*t)->nframes;
for (; f < e; f++) {
if (f->tag != FREETAG)
continue;
if (atomic_read(&skb_shinfo(f->skb)->dataref)
skb = f->skb;
if (!skb
&& !(f->skb = skb = new_skb(ETH_ZLEN)))
continue;
if (atomic_read(&skb_shinfo(skb)->dataref)
!= 1) {
n--;
if (!rf)
rf = f;
continue;
}
skb_shinfo(f->skb)->nr_frags = 0;
f->skb->data_len = 0;
skb_trim(f->skb, 0);
gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0;
skb_trim(skb, 0);
d->tgt = t;
ifrotate(*t);
return f;
}
if (n == 0) /* slow polling network card */
/* Work can be done, but the network layer is
holding our precious packets. Try to grab
one from the pool. */
f = rf;
if (f == NULL) { /* more paranoia */
printk(KERN_ERR
"aoe: freeframe: %s.\n",
"unexpected null rf");
d->flags |= DEVFL_KICKME;
return NULL;
}
skb = skb_pool_get(d);
if (skb) {
skb_pool_put(d, f->skb);
f->skb = skb;
goto gotone;
}
(*t)->dataref++;
if ((*t)->nout == 0)
d->flags |= DEVFL_KICKME;
}
if (t == d->tgt) /* we've looped and found nada */
break;
t++;
} while (t < &d->targets[NTARGETS] && *t);
if (t >= &d->targets[NTARGETS] || !*t)
t = d->targets;
}
return NULL;
}

Expand Down Expand Up @@ -894,33 +953,23 @@ addtgt(struct aoedev *d, char *addr, ulong nframes)
return NULL;

t = kcalloc(1, sizeof *t, GFP_ATOMIC);
if (!t)
return NULL;
f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
if (!t || !f)
goto bail;
if (!f) {
kfree(t);
return NULL;
}

t->nframes = nframes;
t->frames = f;
e = f + nframes;
for (; f < e; f++) {
for (; f < e; f++)
f->tag = FREETAG;
f->skb = new_skb(ETH_ZLEN);
if (!f->skb)
break;
}
if (f != e) {
while (f > t->frames) {
f--;
dev_kfree_skb(f->skb);
}
goto bail;
}
memcpy(t->addr, addr, sizeof t->addr);
t->ifp = t->ifs;
t->maxout = t->nframes;
return *tt = t;
bail:
kfree(t);
kfree(f);
return NULL;
}

void
Expand Down
52 changes: 45 additions & 7 deletions trunk/drivers/block/aoe/aoedev.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
#include <linux/hdreg.h>
#include <linux/blkdev.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include "aoe.h"

static void dummy_timer(ulong);
static void aoedev_freedev(struct aoedev *);
static void freetgt(struct aoetgt *t);
static void freetgt(struct aoedev *d, struct aoetgt *t);
static void skbpoolfree(struct aoedev *d);

static struct aoedev *devlist;
static spinlock_t devlist_lock;
Expand Down Expand Up @@ -125,9 +127,10 @@ aoedev_freedev(struct aoedev *d)
t = d->targets;
e = t + NTARGETS;
for (; t < e && *t; t++)
freetgt(*t);
freetgt(d, *t);
if (d->bufpool)
mempool_destroy(d->bufpool);
skbpoolfree(d);
kfree(d);
}

Expand Down Expand Up @@ -176,6 +179,43 @@ aoedev_flush(const char __user *str, size_t cnt)
return 0;
}

/* I'm not really sure that this is a realistic problem, but if the
network driver goes gonzo let's just leak memory after complaining. */
static void
skbfree(struct sk_buff *skb)
{
enum { Sms = 100, Tms = 3*1000};
int i = Tms / Sms;

if (skb == NULL)
return;
while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0)
msleep(Sms);
if (i <= 0) {
printk(KERN_ERR
"aoe: %s holds ref: %s\n",
skb->dev ? skb->dev->name : "netif",
"cannot free skb -- memory leaked.");
return;
}
skb_shinfo(skb)->nr_frags = skb->data_len = 0;
skb_trim(skb, 0);
dev_kfree_skb(skb);
}

static void
skbpoolfree(struct aoedev *d)
{
struct sk_buff *skb;

while ((skb = d->skbpool_hd)) {
d->skbpool_hd = skb->next;
skb->next = NULL;
skbfree(skb);
}
d->skbpool_tl = NULL;
}

/* find it or malloc it */
struct aoedev *
aoedev_by_sysminor_m(ulong sysminor)
Expand Down Expand Up @@ -215,16 +255,14 @@ aoedev_by_sysminor_m(ulong sysminor)
}

static void
freetgt(struct aoetgt *t)
freetgt(struct aoedev *d, struct aoetgt *t)
{
struct frame *f, *e;

f = t->frames;
e = f + t->nframes;
for (; f < e; f++) {
skb_shinfo(f->skb)->nr_frags = 0;
dev_kfree_skb(f->skb);
}
for (; f < e; f++)
skbfree(f->skb);
kfree(t->frames);
kfree(t);
}
Expand Down

0 comments on commit 6f195b3

Please sign in to comment.