Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/aoe-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/aoe-2.6:
  [PATCH] aoe [3/3]: update version to 22
  [PATCH] aoe [2/3]: don't request ATA device ID on ATA error
  [PATCH] aoe [1/3]: support multiple AoE listeners
  [PATCH] aoe: do not stop retransmit timer when device goes down
  [PATCH] aoe [8/8]: update driver version number
  [PATCH] aoe [7/8]: update driver compatibility string
  [PATCH] aoe [6/8]: update device information on last close
  [PATCH] aoe [5/8]: allow network interface migration on packet retransmit
  [PATCH] aoe [4/8]: use less confusing driver name
  [PATCH] aoe [3/8]: increase allowed outstanding packets
  [PATCH] aoe [2/8]: support dynamic resizing of AoE devices
  [PATCH] aoe [1/8]: zero packet data after skb allocation
This commit is contained in:
Linus Torvalds 2006-03-25 09:20:39 -08:00
commit 3661f00e20
9 changed files with 238 additions and 120 deletions

View File

@ -27,6 +27,8 @@ rm -f $dir/discover
mknod -m 0200 $dir/discover c $MAJOR 3 mknod -m 0200 $dir/discover c $MAJOR 3
rm -f $dir/interfaces rm -f $dir/interfaces
mknod -m 0200 $dir/interfaces c $MAJOR 4 mknod -m 0200 $dir/interfaces c $MAJOR 4
rm -f $dir/revalidate
mknod -m 0200 $dir/revalidate c $MAJOR 5
export n_partitions export n_partitions
mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'` mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`

View File

@ -18,6 +18,7 @@
SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220" SUBSYSTEM="aoe", KERNEL="discover", NAME="etherd/%k", GROUP="disk", MODE="0220"
SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440" SUBSYSTEM="aoe", KERNEL="err", NAME="etherd/%k", GROUP="disk", MODE="0440"
SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220" SUBSYSTEM="aoe", KERNEL="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220"
SUBSYSTEM="aoe", KERNEL="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220"
# aoe block devices # aoe block devices
KERNEL="etherd*", NAME="%k", GROUP="disk" KERNEL="etherd*", NAME="%k", GROUP="disk"

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
#define VERSION "14" #define VERSION "22"
#define AOE_MAJOR 152 #define AOE_MAJOR 152
#define DEVICE_NAME "aoe" #define DEVICE_NAME "aoe"
@ -75,8 +75,9 @@ enum {
DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */ DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */
DEVFL_EXT = (1<<2), /* device accepts lba48 commands */ DEVFL_EXT = (1<<2), /* device accepts lba48 commands */
DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */ DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */
DEVFL_WC_UPDATE = (1<<4), /* this device needs to update write cache status */ DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */
DEVFL_WORKON = (1<<4), DEVFL_PAUSE = (1<<5),
DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
BUFFL_FAIL = 1, BUFFL_FAIL = 1,
}; };
@ -152,16 +153,17 @@ void aoechr_exit(void);
void aoechr_error(char *); void aoechr_error(char *);
void aoecmd_work(struct aoedev *d); void aoecmd_work(struct aoedev *d);
void aoecmd_cfg(ushort, unsigned char); void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
void aoecmd_ata_rsp(struct sk_buff *); void aoecmd_ata_rsp(struct sk_buff *);
void aoecmd_cfg_rsp(struct sk_buff *); void aoecmd_cfg_rsp(struct sk_buff *);
void aoecmd_sleepwork(void *vp);
int aoedev_init(void); int aoedev_init(void);
void aoedev_exit(void); void aoedev_exit(void);
struct aoedev *aoedev_by_aoeaddr(int maj, int min); struct aoedev *aoedev_by_aoeaddr(int maj, int min);
struct aoedev *aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt);
void aoedev_downdev(struct aoedev *d); void aoedev_downdev(struct aoedev *d);
struct aoedev *aoedev_set(ulong, unsigned char *, struct net_device *, ulong); int aoedev_isbusy(struct aoedev *d);
int aoedev_busy(void);
int aoenet_init(void); int aoenet_init(void);
void aoenet_exit(void); void aoenet_exit(void);

View File

@ -22,7 +22,9 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
return snprintf(page, PAGE_SIZE, return snprintf(page, PAGE_SIZE,
"%s%s\n", "%s%s\n",
(d->flags & DEVFL_UP) ? "up" : "down", (d->flags & DEVFL_UP) ? "up" : "down",
(d->flags & DEVFL_CLOSEWAIT) ? ",closewait" : ""); (d->flags & DEVFL_PAUSE) ? ",paused" :
(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
/* I'd rather see nopen exported so we can ditch closewait */
} }
static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
{ {
@ -107,8 +109,7 @@ aoeblk_release(struct inode *inode, struct file *filp)
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) { if (--d->nopen == 0) {
d->flags &= ~DEVFL_CLOSEWAIT;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
aoecmd_cfg(d->aoemajor, d->aoeminor); aoecmd_cfg(d->aoemajor, d->aoeminor);
return 0; return 0;
@ -158,14 +159,14 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
} }
list_add_tail(&buf->bufs, &d->bufq); list_add_tail(&buf->bufs, &d->bufq);
aoecmd_work(d);
aoecmd_work(d);
sl = d->sendq_hd; sl = d->sendq_hd;
d->sendq_hd = d->sendq_tl = NULL; d->sendq_hd = d->sendq_tl = NULL;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
aoenet_xmit(sl); aoenet_xmit(sl);
return 0; return 0;
} }
@ -205,7 +206,7 @@ aoeblk_gdalloc(void *vp)
printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk " printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
"structure for %ld.%ld\n", d->aoemajor, d->aoeminor); "structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
d->flags &= ~DEVFL_WORKON; d->flags &= ~DEVFL_GDALLOC;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
return; return;
} }
@ -218,7 +219,7 @@ aoeblk_gdalloc(void *vp)
"for %ld.%ld\n", d->aoemajor, d->aoeminor); "for %ld.%ld\n", d->aoemajor, d->aoeminor);
put_disk(gd); put_disk(gd);
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
d->flags &= ~DEVFL_WORKON; d->flags &= ~DEVFL_GDALLOC;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
return; return;
} }
@ -235,18 +236,13 @@ aoeblk_gdalloc(void *vp)
gd->queue = &d->blkq; gd->queue = &d->blkq;
d->gd = gd; d->gd = gd;
d->flags &= ~DEVFL_WORKON; d->flags &= ~DEVFL_GDALLOC;
d->flags |= DEVFL_UP; d->flags |= DEVFL_UP;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
add_disk(gd); add_disk(gd);
aoedisk_add_sysfs(d); aoedisk_add_sysfs(d);
printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
"sectors\n", (unsigned long long)mac_addr(d->addr),
d->aoemajor, d->aoeminor,
d->fw_ver, (long long)d->ssize);
} }
void void

View File

@ -13,6 +13,7 @@ enum {
MINOR_ERR = 2, MINOR_ERR = 2,
MINOR_DISCOVER, MINOR_DISCOVER,
MINOR_INTERFACES, MINOR_INTERFACES,
MINOR_REVALIDATE,
MSGSZ = 2048, MSGSZ = 2048,
NARGS = 10, NARGS = 10,
NMSG = 100, /* message backlog to retain */ NMSG = 100, /* message backlog to retain */
@ -41,6 +42,7 @@ static struct aoe_chardev chardevs[] = {
{ MINOR_ERR, "err" }, { MINOR_ERR, "err" },
{ MINOR_DISCOVER, "discover" }, { MINOR_DISCOVER, "discover" },
{ MINOR_INTERFACES, "interfaces" }, { MINOR_INTERFACES, "interfaces" },
{ MINOR_REVALIDATE, "revalidate" },
}; };
static int static int
@ -62,6 +64,39 @@ interfaces(const char __user *str, size_t size)
return 0; return 0;
} }
static int
revalidate(const char __user *str, size_t size)
{
int major, minor, n;
ulong flags;
struct aoedev *d;
char buf[16];
if (size >= sizeof buf)
return -EINVAL;
buf[sizeof buf - 1] = '\0';
if (copy_from_user(buf, str, size))
return -EFAULT;
/* should be e%d.%d format */
n = sscanf(buf, "e%d.%d", &major, &minor);
if (n != 2) {
printk(KERN_ERR "aoe: %s: invalid device specification\n",
__FUNCTION__);
return -EINVAL;
}
d = aoedev_by_aoeaddr(major, minor);
if (!d)
return -EINVAL;
spin_lock_irqsave(&d->lock, flags);
d->flags |= DEVFL_PAUSE;
spin_unlock_irqrestore(&d->lock, flags);
aoecmd_cfg(major, minor);
return 0;
}
void void
aoechr_error(char *msg) aoechr_error(char *msg)
{ {
@ -114,6 +149,8 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp
case MINOR_INTERFACES: case MINOR_INTERFACES:
ret = interfaces(buf, cnt); ret = interfaces(buf, cnt);
break; break;
case MINOR_REVALIDATE:
ret = revalidate(buf, cnt);
} }
if (ret == 0) if (ret == 0)
ret = cnt; ret = cnt;

View File

@ -8,6 +8,7 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/genhd.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "aoe.h" #include "aoe.h"
@ -28,6 +29,7 @@ new_skb(struct net_device *if_dev, ulong len)
skb->protocol = __constant_htons(ETH_P_AOE); skb->protocol = __constant_htons(ETH_P_AOE);
skb->priority = 0; skb->priority = 0;
skb_put(skb, len); skb_put(skb, len);
memset(skb->head, 0, len);
skb->next = skb->prev = NULL; skb->next = skb->prev = NULL;
/* tell the network layer not to perform IP checksums /* tell the network layer not to perform IP checksums
@ -188,12 +190,67 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
} }
} }
/* some callers cannot sleep, and they can call this function,
* transmitting the packets later, when interrupts are on
*/
static struct sk_buff *
aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
{
struct aoe_hdr *h;
struct aoe_cfghdr *ch;
struct sk_buff *skb, *sl, *sl_tail;
struct net_device *ifp;
sl = sl_tail = NULL;
read_lock(&dev_base_lock);
for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
continue;
skb = new_skb(ifp, sizeof *h + sizeof *ch);
if (skb == NULL) {
printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
continue;
}
if (sl_tail == NULL)
sl_tail = skb;
h = (struct aoe_hdr *) skb->mac.raw;
memset(h, 0, sizeof *h + sizeof *ch);
memset(h->dst, 0xff, sizeof h->dst);
memcpy(h->src, ifp->dev_addr, sizeof h->src);
h->type = __constant_cpu_to_be16(ETH_P_AOE);
h->verfl = AOE_HVER;
h->major = cpu_to_be16(aoemajor);
h->minor = aoeminor;
h->cmd = AOECMD_CFG;
skb->next = sl;
sl = skb;
}
read_unlock(&dev_base_lock);
if (tail != NULL)
*tail = sl_tail;
return sl;
}
/* enters with d->lock held */ /* enters with d->lock held */
void void
aoecmd_work(struct aoedev *d) aoecmd_work(struct aoedev *d)
{ {
struct frame *f; struct frame *f;
struct buf *buf; struct buf *buf;
if (d->flags & DEVFL_PAUSE) {
if (!aoedev_isbusy(d))
d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor,
d->aoeminor, &d->sendq_tl);
return;
}
loop: loop:
f = getframe(d, FREETAG); f = getframe(d, FREETAG);
if (f == NULL) if (f == NULL)
@ -229,6 +286,8 @@ rexmit(struct aoedev *d, struct frame *f)
h = (struct aoe_hdr *) f->data; h = (struct aoe_hdr *) f->data;
f->tag = n; f->tag = n;
h->tag = cpu_to_be32(n); h->tag = cpu_to_be32(n);
memcpy(h->dst, d->addr, sizeof h->dst);
memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
skb = skb_prepare(d, f); skb = skb_prepare(d, f);
if (skb) { if (skb) {
@ -272,7 +331,7 @@ rexmit_timer(ulong vp)
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
if (d->flags & DEVFL_TKILL) { if (d->flags & DEVFL_TKILL) {
tdie: spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
return; return;
} }
f = d->frames; f = d->frames;
@ -283,7 +342,7 @@ tdie: spin_unlock_irqrestore(&d->lock, flags);
n /= HZ; n /= HZ;
if (n > MAXWAIT) { /* waited too long. device failure. */ if (n > MAXWAIT) { /* waited too long. device failure. */
aoedev_downdev(d); aoedev_downdev(d);
goto tdie; break;
} }
rexmit(d, f); rexmit(d, f);
} }
@ -305,6 +364,37 @@ tdie: spin_unlock_irqrestore(&d->lock, flags);
aoenet_xmit(sl); aoenet_xmit(sl);
} }
/* this function performs work that has been deferred until sleeping is OK
*/
void
aoecmd_sleepwork(void *vp)
{
struct aoedev *d = (struct aoedev *) vp;
if (d->flags & DEVFL_GDALLOC)
aoeblk_gdalloc(d);
if (d->flags & DEVFL_NEWSIZE) {
struct block_device *bd;
unsigned long flags;
u64 ssize;
ssize = d->gd->capacity;
bd = bdget_disk(d->gd, 0);
if (bd) {
mutex_lock(&bd->bd_inode->i_mutex);
i_size_write(bd->bd_inode, (loff_t)ssize<<9);
mutex_unlock(&bd->bd_inode->i_mutex);
bdput(bd);
}
spin_lock_irqsave(&d->lock, flags);
d->flags |= DEVFL_UP;
d->flags &= ~DEVFL_NEWSIZE;
spin_unlock_irqrestore(&d->lock, flags);
}
}
static void static void
ataid_complete(struct aoedev *d, unsigned char *id) ataid_complete(struct aoedev *d, unsigned char *id)
{ {
@ -339,21 +429,29 @@ ataid_complete(struct aoedev *d, unsigned char *id)
d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
} }
if (d->ssize != ssize)
printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
"sectors\n", (unsigned long long)mac_addr(d->addr),
d->aoemajor, d->aoeminor,
d->fw_ver, (long long)ssize);
d->ssize = ssize; d->ssize = ssize;
d->geo.start = 0; d->geo.start = 0;
if (d->gd != NULL) { if (d->gd != NULL) {
d->gd->capacity = ssize; d->gd->capacity = ssize;
d->flags |= DEVFL_UP; d->flags |= DEVFL_NEWSIZE;
} else {
if (d->flags & DEVFL_GDALLOC) {
printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n",
__FUNCTION__,
"can't schedule work for",
d->aoemajor, d->aoeminor,
"it's already on! (This really shouldn't happen).\n");
return; return;
} }
if (d->flags & DEVFL_WORKON) { d->flags |= DEVFL_GDALLOC;
printk(KERN_INFO "aoe: ataid_complete: can't schedule work, it's already on! "
"(This really shouldn't happen).\n");
return;
} }
INIT_WORK(&d->work, aoeblk_gdalloc, d);
schedule_work(&d->work); schedule_work(&d->work);
d->flags |= DEVFL_WORKON;
} }
static void static void
@ -419,6 +517,8 @@ aoecmd_ata_rsp(struct sk_buff *skb)
ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr)); ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
buf = f->buf; buf = f->buf;
if (ahout->cmdstat == WIN_IDENTIFY)
d->flags &= ~DEVFL_PAUSE;
if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh " printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
"stat=%2.2Xh from e%ld.%ld\n", "stat=%2.2Xh from e%ld.%ld\n",
@ -451,7 +551,6 @@ aoecmd_ata_rsp(struct sk_buff *skb)
return; return;
} }
ataid_complete(d, (char *) (ahin+1)); ataid_complete(d, (char *) (ahin+1));
/* d->flags |= DEVFL_WC_UPDATE; */
break; break;
default: default:
printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized " printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
@ -484,51 +583,19 @@ aoecmd_ata_rsp(struct sk_buff *skb)
f->tag = FREETAG; f->tag = FREETAG;
aoecmd_work(d); aoecmd_work(d);
sl = d->sendq_hd; sl = d->sendq_hd;
d->sendq_hd = d->sendq_tl = NULL; d->sendq_hd = d->sendq_tl = NULL;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
aoenet_xmit(sl); aoenet_xmit(sl);
} }
void void
aoecmd_cfg(ushort aoemajor, unsigned char aoeminor) aoecmd_cfg(ushort aoemajor, unsigned char aoeminor)
{ {
struct aoe_hdr *h; struct sk_buff *sl;
struct aoe_cfghdr *ch;
struct sk_buff *skb, *sl;
struct net_device *ifp;
sl = NULL; sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);
read_lock(&dev_base_lock);
for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
continue;
skb = new_skb(ifp, sizeof *h + sizeof *ch);
if (skb == NULL) {
printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
continue;
}
h = (struct aoe_hdr *) skb->mac.raw;
memset(h, 0, sizeof *h + sizeof *ch);
memset(h->dst, 0xff, sizeof h->dst);
memcpy(h->src, ifp->dev_addr, sizeof h->src);
h->type = __constant_cpu_to_be16(ETH_P_AOE);
h->verfl = AOE_HVER;
h->major = cpu_to_be16(aoemajor);
h->minor = aoeminor;
h->cmd = AOECMD_CFG;
skb->next = sl;
sl = skb;
}
read_unlock(&dev_base_lock);
aoenet_xmit(sl); aoenet_xmit(sl);
} }
@ -561,9 +628,6 @@ aoecmd_ata_id(struct aoedev *d)
f->waited = 0; f->waited = 0;
f->writedatalen = 0; f->writedatalen = 0;
/* this message initializes the device, so we reset the rttavg */
d->rttavg = MAXTIMER;
/* set up ata header */ /* set up ata header */
ah->scnt = 1; ah->scnt = 1;
ah->cmdstat = WIN_IDENTIFY; ah->cmdstat = WIN_IDENTIFY;
@ -571,12 +635,8 @@ aoecmd_ata_id(struct aoedev *d)
skb = skb_prepare(d, f); skb = skb_prepare(d, f);
/* we now want to start the rexmit tracking */ d->rttavg = MAXTIMER;
d->flags &= ~DEVFL_TKILL;
d->timer.data = (ulong) d;
d->timer.function = rexmit_timer; d->timer.function = rexmit_timer;
d->timer.expires = jiffies + TIMERTICK;
add_timer(&d->timer);
return skb; return skb;
} }
@ -590,7 +650,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
ulong flags, sysminor, aoemajor; ulong flags, sysminor, aoemajor;
u16 bufcnt; u16 bufcnt;
struct sk_buff *sl; struct sk_buff *sl;
enum { MAXFRAMES = 8 }; enum { MAXFRAMES = 16 };
h = (struct aoe_hdr *) skb->mac.raw; h = (struct aoe_hdr *) skb->mac.raw;
ch = (struct aoe_cfghdr *) (h+1); ch = (struct aoe_cfghdr *) (h+1);
@ -618,23 +678,28 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
if (bufcnt > MAXFRAMES) /* keep it reasonable */ if (bufcnt > MAXFRAMES) /* keep it reasonable */
bufcnt = MAXFRAMES; bufcnt = MAXFRAMES;
d = aoedev_set(sysminor, h->src, skb->dev, bufcnt); d = aoedev_by_sysminor_m(sysminor, bufcnt);
if (d == NULL) { if (d == NULL) {
printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device set failure\n"); printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n");
return; return;
} }
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
if (d->flags & (DEVFL_UP | DEVFL_CLOSEWAIT)) { /* permit device to migrate mac and network interface */
d->ifp = skb->dev;
memcpy(d->addr, h->src, sizeof d->addr);
/* don't change users' perspective */
if (d->nopen && !(d->flags & DEVFL_PAUSE)) {
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
return; return;
} }
d->flags |= DEVFL_PAUSE; /* force pause */
d->fw_ver = be16_to_cpu(ch->fwver); d->fw_ver = be16_to_cpu(ch->fwver);
/* we get here only if the device is new */ /* check for already outstanding ataid */
sl = aoecmd_ata_id(d); sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);

View File

@ -12,6 +12,24 @@
static struct aoedev *devlist; static struct aoedev *devlist;
static spinlock_t devlist_lock; static spinlock_t devlist_lock;
int
aoedev_isbusy(struct aoedev *d)
{
struct frame *f, *e;
f = d->frames;
e = f + d->nframes;
do {
if (f->tag != FREETAG) {
printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n",
d->aoemajor, d->aoeminor);
return 1;
}
} while (++f < e);
return 0;
}
struct aoedev * struct aoedev *
aoedev_by_aoeaddr(int maj, int min) aoedev_by_aoeaddr(int maj, int min)
{ {
@ -28,6 +46,18 @@ aoedev_by_aoeaddr(int maj, int min)
return d; return d;
} }
static void
dummy_timer(ulong vp)
{
struct aoedev *d;
d = (struct aoedev *)vp;
if (d->flags & DEVFL_TKILL)
return;
d->timer.expires = jiffies + HZ;
add_timer(&d->timer);
}
/* called with devlist lock held */ /* called with devlist lock held */
static struct aoedev * static struct aoedev *
aoedev_newdev(ulong nframes) aoedev_newdev(ulong nframes)
@ -44,6 +74,8 @@ aoedev_newdev(ulong nframes)
return NULL; return NULL;
} }
INIT_WORK(&d->work, aoecmd_sleepwork, d);
d->nframes = nframes; d->nframes = nframes;
d->frames = f; d->frames = f;
e = f + nframes; e = f + nframes;
@ -52,6 +84,10 @@ aoedev_newdev(ulong nframes)
spin_lock_init(&d->lock); spin_lock_init(&d->lock);
init_timer(&d->timer); init_timer(&d->timer);
d->timer.data = (ulong) d;
d->timer.function = dummy_timer;
d->timer.expires = jiffies + HZ;
add_timer(&d->timer);
d->bufpool = NULL; /* defer to aoeblk_gdalloc */ d->bufpool = NULL; /* defer to aoeblk_gdalloc */
INIT_LIST_HEAD(&d->bufq); INIT_LIST_HEAD(&d->bufq);
d->next = devlist; d->next = devlist;
@ -67,9 +103,6 @@ aoedev_downdev(struct aoedev *d)
struct buf *buf; struct buf *buf;
struct bio *bio; struct bio *bio;
d->flags |= DEVFL_TKILL;
del_timer(&d->timer);
f = d->frames; f = d->frames;
e = f + d->nframes; e = f + d->nframes;
for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) {
@ -92,16 +125,15 @@ aoedev_downdev(struct aoedev *d)
bio_endio(bio, bio->bi_size, -EIO); bio_endio(bio, bio->bi_size, -EIO);
} }
if (d->nopen)
d->flags |= DEVFL_CLOSEWAIT;
if (d->gd) if (d->gd)
d->gd->capacity = 0; d->gd->capacity = 0;
d->flags &= ~DEVFL_UP; d->flags &= ~(DEVFL_UP | DEVFL_PAUSE);
} }
/* find it or malloc it */
struct aoedev * struct aoedev *
aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt) aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
{ {
struct aoedev *d; struct aoedev *d;
ulong flags; ulong flags;
@ -112,25 +144,19 @@ aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bu
if (d->sysminor == sysminor) if (d->sysminor == sysminor)
break; break;
if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) { if (d == NULL) {
d = aoedev_newdev(bufcnt);
if (d == NULL) {
spin_unlock_irqrestore(&devlist_lock, flags); spin_unlock_irqrestore(&devlist_lock, flags);
printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
return NULL; return NULL;
} /* if newdev, (d->flags & DEVFL_UP) == 0 for below */ }
spin_unlock_irqrestore(&devlist_lock, flags);
spin_lock_irqsave(&d->lock, flags);
d->ifp = ifp;
memcpy(d->addr, addr, sizeof d->addr);
if ((d->flags & DEVFL_UP) == 0) {
aoedev_downdev(d); /* flushes outstanding frames */
d->sysminor = sysminor; d->sysminor = sysminor;
d->aoemajor = AOEMAJOR(sysminor); d->aoemajor = AOEMAJOR(sysminor);
d->aoeminor = AOEMINOR(sysminor); d->aoeminor = AOEMINOR(sysminor);
} }
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&devlist_lock, flags);
return d; return d;
} }
@ -161,6 +187,7 @@ aoedev_exit(void)
spin_lock_irqsave(&d->lock, flags); spin_lock_irqsave(&d->lock, flags);
aoedev_downdev(d); aoedev_downdev(d);
d->flags |= DEVFL_TKILL;
spin_unlock_irqrestore(&d->lock, flags); spin_unlock_irqrestore(&d->lock, flags);
del_timer_sync(&d->timer); del_timer_sync(&d->timer);

View File

@ -11,7 +11,7 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>"); MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
MODULE_DESCRIPTION("AoE block/char driver for 2.6.[0-9]+"); MODULE_DESCRIPTION("AoE block/char driver for 2.6.2 and newer 2.6 kernels");
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
enum { TINIT, TRUN, TKILL }; enum { TINIT, TRUN, TKILL };
@ -89,7 +89,7 @@ aoe_init(void)
} }
printk(KERN_INFO printk(KERN_INFO
"aoe: aoe_init: AoE v2.6-%s initialised.\n", "aoe: aoe_init: AoE v%s initialised.\n",
VERSION); VERSION);
discover_timer(TINIT); discover_timer(TINIT);
return 0; return 0;

View File

@ -92,18 +92,6 @@ mac_addr(char addr[6])
return __be64_to_cpu(n); return __be64_to_cpu(n);
} }
static struct sk_buff *
skb_check(struct sk_buff *skb)
{
if (skb_is_nonlinear(skb))
if ((skb = skb_share_check(skb, GFP_ATOMIC)))
if (skb_linearize(skb, GFP_ATOMIC) < 0) {
dev_kfree_skb(skb);
return NULL;
}
return skb;
}
void void
aoenet_xmit(struct sk_buff *sl) aoenet_xmit(struct sk_buff *sl)
{ {
@ -125,14 +113,14 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
struct aoe_hdr *h; struct aoe_hdr *h;
u32 n; u32 n;
skb = skb_check(skb); skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb) if (skb == NULL)
return 0; return 0;
if (skb_is_nonlinear(skb))
if (skb_linearize(skb, GFP_ATOMIC) < 0)
goto exit;
if (!is_aoe_netif(ifp)) if (!is_aoe_netif(ifp))
goto exit; goto exit;
//skb->len += ETH_HLEN; /* (1) */
skb_push(skb, ETH_HLEN); /* (1) */ skb_push(skb, ETH_HLEN); /* (1) */
h = (struct aoe_hdr *) skb->mac.raw; h = (struct aoe_hdr *) skb->mac.raw;