linux/drivers/block/aoe/aoemain.c
Ed Cashin 896831f590 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>
2012-10-06 03:05:24 +09:00

116 lines
2.1 KiB
C

/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoemain.c
* Module initialization routines, discover timer
*/
#include <linux/hdreg.h>
#include <linux/blkdev.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include "aoe.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sam Hopkins <sah@coraid.com>");
MODULE_DESCRIPTION("AoE block/char driver for 2.6.2 and newer 2.6 kernels");
MODULE_VERSION(VERSION);
enum { TINIT, TRUN, TKILL };
static void
discover_timer(ulong vp)
{
static struct timer_list t;
static volatile ulong die;
static spinlock_t lock;
ulong flags;
enum { DTIMERTICK = HZ * 60 }; /* one minute */
switch (vp) {
case TINIT:
init_timer(&t);
spin_lock_init(&lock);
t.data = TRUN;
t.function = discover_timer;
die = 0;
case TRUN:
spin_lock_irqsave(&lock, flags);
if (!die) {
t.expires = jiffies + DTIMERTICK;
add_timer(&t);
}
spin_unlock_irqrestore(&lock, flags);
aoecmd_cfg(0xffff, 0xff);
return;
case TKILL:
spin_lock_irqsave(&lock, flags);
die = 1;
spin_unlock_irqrestore(&lock, flags);
del_timer_sync(&t);
default:
return;
}
}
static void
aoe_exit(void)
{
discover_timer(TKILL);
aoenet_exit();
unregister_blkdev(AOE_MAJOR, DEVICE_NAME);
aoecmd_exit();
aoechr_exit();
aoedev_exit();
aoeblk_exit(); /* free cache after de-allocating bufs */
}
static int __init
aoe_init(void)
{
int ret;
ret = aoedev_init();
if (ret)
return ret;
ret = aoechr_init();
if (ret)
goto chr_fail;
ret = aoeblk_init();
if (ret)
goto blk_fail;
ret = aoenet_init();
if (ret)
goto net_fail;
ret = aoecmd_init();
if (ret)
goto cmd_fail;
ret = register_blkdev(AOE_MAJOR, DEVICE_NAME);
if (ret < 0) {
printk(KERN_ERR "aoe: can't register major\n");
goto blkreg_fail;
}
printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION);
discover_timer(TINIT);
return 0;
blkreg_fail:
aoecmd_exit();
cmd_fail:
aoenet_exit();
net_fail:
aoeblk_exit();
blk_fail:
aoechr_exit();
chr_fail:
aoedev_exit();
printk(KERN_INFO "aoe: initialisation failure.\n");
return ret;
}
module_init(aoe_init);
module_exit(aoe_exit);