initial commit

This commit is contained in:
longpanda
2020-04-05 00:07:50 +08:00
parent 2090c6fa97
commit 05a1b863a6
487 changed files with 114253 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
The patches in the contrib directory enable features
that either don't work completely, aren't well tested, or
are of limited general use. They can be applied by
using patch in the vblade source directory as follows:
forfeit:~/vblade-12 # patch -p1 <contrib/jumbo.diff
patching file aoe.c
patching file fns.h
patching file freebsd.c
patching file linux.c
forfeit:~/vblade-12 #

View File

@@ -0,0 +1,37 @@
#!/bin/sh
set -eu
SERVICEFILE="/lib/systemd/system/vblade@.service"
WANTDIR="$1/vblade.service.wants"
CONFIG_DIR=/etc/vblade.conf.d/
if [ -d "$CONFIG_DIR" ] ; then
mkdir -p "$WANTDIR"
cd "$CONFIG_DIR"
for CONFIG in *.conf ; do
[ -f "$CONFIG" ] || continue
INSTANCE="$(systemd-escape "${CONFIG%%.conf}")"
LINK="$WANTDIR/vblade@$INSTANCE.service"
sh -n "$CONFIG_DIR$CONFIG" 2>/dev/null || continue
shelf=
slot=
netif=
filename=
options=
. "$CONFIG_DIR$CONFIG"
[ "$netif" ] || continue
[ "$shelf" ] || continue
[ "$slot" ] || continue
[ "$filename" ] || continue
ln -s "$SERVICEFILE" "$LINK"
done
fi
exit 0

View File

@@ -0,0 +1,107 @@
= VBLADE-PERSISTENCE(5)
== NAME
vblade-persistence - description of the vblade persistence
== DESCRIPTION
vblade-persistence uses the files in `/etc/vblade.conf.d/` to manage
exports. File names must end in `.conf`. The "instance" name is the
file name without `.conf`.
The file format is a POSIX shell fragment.
The following variables *must* be defined: `netif`, `shelf`, `slot`,
and `filename`. See vblade(8) for their meaning. Incomplete
configuration files are ignored, so are files that are not a valid
shell syntax.
Additionally, the following variables may be defined:
* `options`
Any options as provided by vblade(7).
* `ionice`
Use these to define an I/O scheduling class and level for that export.
The value must be understood by ionice(1).
== EXAMPLE
----
shelf=14
slot=2
netif=ens3
filename=/dev/mapper/export
options='-r -m 11:22:33:44:55:66,22:33:44:55:66:77 -o 8'
ionice='--class best-effort --classdata 7'
----
== USAGE
=== On systems using systemd
Install `vblade-generator` in `/lib/systemd/system-generators/`, and
both `vblade.service` and `vblade@.service` in `/lib/systemd/system/`.
Enable the vblade service, reload systemd. Additional units for each
export should appear, named `vblade@<instance>.service`.
=== On systems using SysV init
Individual instances may be controlled by providing their name as
a second option, e.g.
----
/etc/init.d/vblade status demo
----
Two different init scripts are available:
==== `vblade.init.lsb-daemon`
Uses LSB functions and daemon(1) program to control the instance.
Pros: daemon(1) is a very fine tool for this, providing also respawning
and output redirection.
==== `vblade.init.daemon`
As above, but without using LSB functions.
Pros: Should be fairly portable, no thrills.
==== Template
The template for these scripts is `vblade.init.in`, the actual
templating is done using tpage(1p), see `vblade.init.generate`.
Support for using Debian's start-stop-daemon has been prepared but
requires pid file supprt in vblade to be usable.
== BUGS
On SysV init systems, the configuration files are always sourced as
shell scripts. On systemd systems, the configuration file is just
a key/value store without shell expansion.
It's a wise idea to run `sh -n` against a configuration file after any
modification for basic format validation.
== SEE ALSO
daemon: <http://www.libslack.org/daemon/>
tpage(1p)
vblade(8)
== AUTHOR
Christoph Biedl <sourceforge.bnwi@manchmal.in-ulm.de>

View File

@@ -0,0 +1,191 @@
#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="vblade export"
NAME=vblade
VBLADE="/usr/sbin/$NAME"
DAEMON=/usr/bin/daemon
IONICE=/usr/bin/ionice
PIDDIR="/var/run/vblade/"
[ -x "$VBLADE" ] || exit 0
[ -x "$DAEMON" ] || exit 0
mkdir -p "$PIDDIR"
# Emulation of LSB functions
VERBOSE=1
log_daemon_msg () {
printf '%s ' "$@"
}
log_end_msg () {
local CODE="$1"
if [ "$CODE" -eq 0 ] ; then
echo '.'
else
echo 'failed!'
fi
}
# Start a vblade instance
#
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
do_start () {
local INSTANCE="$1"
local CONFIG="$2"
sh -n "$CONFIG" 2>/dev/null || return 2
shelf=
slot=
filename=
netif=
options=
ionice=
. "$CONFIG"
[ "$netif" ] || return 2
[ "$shelf" ] || return 2
[ "$slot" ] || return 2
[ "$filename" ] || return 2
if [ "$ionice" ] ; then
if [ -x "$IONICE" ] ; then
ionice="$IONICE $ionice"
else
ionice=
fi
fi
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
&& return 1
$ionice "$DAEMON" \
--respawn \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
--output daemon.notice \
--stdout daemon.notice \
--stderr daemon.err -- \
$VBLADE $options $shelf $slot $netif $filename || return 2
}
# Stop a vblade instance
#
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
do_stop () {
local INSTANCE="$1"
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" || return 1
"$DAEMON" \
--stop \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
--stop || return 2
# Wait until the process is gone
for i in $(seq 1 10) ; do
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" || return 0
done
return 2
}
EXIT=0
do_action () {
local CONFIG="$1"
INSTANCE="$(basename "${CONFIG%%.conf}")"
case "$ACTION" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$INSTANCE"
do_start "$INSTANCE" "$CONFIG"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$INSTANCE"
do_stop "$INSTANCE"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
if "$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR"
then
echo "$DESC instance $INSTANCE is running"
else
echo "$DESC instance $INSTANCE is not running"
EXIT=1
fi
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$INSTANCE"
do_stop "$INSTANCE"
case "$?" in
0|1)
do_start "$INSTANCE" "$CONFIG"
case "$?" in
0) log_end_msg 0 ;;
*)
# Old process is still running or
# failed to start
log_end_msg 1 ;;
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: /etc/init.d/vblade {start|stop|status|restart|force-reload} [<export> ...]" >&2
exit 3
;;
esac
}
ACTION="$1"
shift
if [ "$1" ] ; then
while [ "$1" ] ; do
CONFIG="/etc/vblade.conf.d/$1.conf"
if [ -f "$CONFIG" ] ; then
do_action "$CONFIG"
fi
shift
done
else
for CONFIG in /etc/vblade.conf.d/*.conf ; do
if [ -f "$CONFIG" ] ; then
do_action "$CONFIG"
fi
done
fi
exit $EXIT

View File

@@ -0,0 +1,24 @@
#!/bin/sh
set -e
TEMPDIR="$(mktemp --directory --tmpdir "vblade.init.generate.$$.XXXXX")"
trap "cd / ; rm -rf \"$TEMPDIR\"" EXIT
run () {
local OUTPUT="$1"
echo "I: Processing $OUTPUT"
TEMP="$TEMPDIR/$OUTPUT"
shift
tpage "$@" vblade.init.in>"$TEMP"
sh -n "$TEMP"
if [ -f "$OUTPUT" ] && cmp -s "$TEMP" "$OUTPUT" ; then
echo "I: $OUTPUT is fresh"
else
cp "$TEMP" "$OUTPUT"
fi
}
# run 'vblade.init.debian' --define lsb=1 --define control=ssd
run 'vblade.init.lsb-daemon' --define lsb=1 --define control=daemon
run 'vblade.init.daemon' --define lsb= --define control=daemon

View File

@@ -0,0 +1,245 @@
#!/bin/sh
[% IF lsb -%]
### BEGIN INIT INFO
# Provides: vblade
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: vblade exports
# Description: Manage all vlbade exports defined in
# /etc/vblade.conf.d/
### END INIT INFO
[% END -%]
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="vblade export"
NAME=vblade
VBLADE="/usr/sbin/$NAME"
[% IF control == 'ssd' -%]
[% PERL -%]die ('control=ssd cannot be used as long as vblade as no pidfile support');[% END -%]
[% ELSIF control == 'daemon' -%]
DAEMON=/usr/bin/daemon
[% END -%]
IONICE=/usr/bin/ionice
PIDDIR="/var/run/vblade/"
[ -x "$VBLADE" ] || exit 0
[% IF control == 'daemon' -%]
[ -x "$DAEMON" ] || exit 0
[% END -%]
mkdir -p "$PIDDIR"
[% IF lsb -%]
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB functions
. /lib/lsb/init-functions
[% ELSE -%]
# Emulation of LSB functions
VERBOSE=1
log_daemon_msg () {
printf '%s ' "$@"
}
log_end_msg () {
local CODE="$1"
if [ "$CODE" -eq 0 ] ; then
echo '.'
else
echo 'failed!'
fi
}
[% END -%]
# Start a vblade instance
#
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
do_start () {
local INSTANCE="$1"
local CONFIG="$2"
sh -n "$CONFIG" 2>/dev/null || return 2
shelf=
slot=
filename=
netif=
options=
ionice=
. "$CONFIG"
[ "$netif" ] || return 2
[ "$shelf" ] || return 2
[ "$slot" ] || return 2
[ "$filename" ] || return 2
if [ "$ionice" ] ; then
if [ -x "$IONICE" ] ; then
ionice="$IONICE $ionice"
else
ionice=
fi
fi
[% IF control == 'ssd' -%]
local PIDFILE="$PIDDIR/$INSTANCE.pid"
start-stop-daemon --start --quiet \
--pidfile "$PIDFILE" --exec "$VBLADE" --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet \
--pidfile "$PIDFILE" \
--exec $ionice "$VBLADE" -- \
$shelf $slot $netif $filename $options \
|| return 2
[% ELSIF control == 'daemon' -%]
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
&& return 1
$ionice "$DAEMON" \
--respawn \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
--output daemon.notice \
--stdout daemon.notice \
--stderr daemon.err -- \
$VBLADE $options $shelf $slot $netif $filename || return 2
[% END -%]
}
# Stop a vblade instance
#
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
do_stop () {
local INSTANCE="$1"
[% IF control == 'ssd' -%]
local PIDFILE="$PIDDIR/$INSTANCE.pid"
start-stop-daemon --stop --quiet \
--retry=TERM/30/KILL/5 --pidfile "$PIDFILE" --name "$NAME"
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f "$PIDFILE"
return "$RETVAL"
[% ELSIF control == 'daemon' -%]
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" || return 1
"$DAEMON" \
--stop \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
--stop || return 2
# Wait until the process is gone
for i in $(seq 1 10) ; do
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" || return 0
done
return 2
[% END -%]
}
EXIT=0
do_action () {
local CONFIG="$1"
INSTANCE="$(basename "${CONFIG%%.conf}")"
case "$ACTION" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$INSTANCE"
do_start "$INSTANCE" "$CONFIG"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$INSTANCE"
do_stop "$INSTANCE"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
[% IF lsb -%]
status_of_proc -p "$PIDDIR/$INSTANCE.pid" "$VBLADE" "vblade instance $INSTANCE" || EXIT=$?
[% ELSE -%]
if "$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR"
then
echo "$DESC instance $INSTANCE is running"
else
echo "$DESC instance $INSTANCE is not running"
EXIT=1
fi
[% END -%]
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$INSTANCE"
do_stop "$INSTANCE"
case "$?" in
0|1)
do_start "$INSTANCE" "$CONFIG"
case "$?" in
0) log_end_msg 0 ;;
*)
# Old process is still running or
# failed to start
log_end_msg 1 ;;
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: /etc/init.d/vblade {start|stop|status|restart|force-reload} [<export> ...]" >&2
exit 3
;;
esac
}
ACTION="$1"
shift
if [ "$1" ] ; then
while [ "$1" ] ; do
CONFIG="/etc/vblade.conf.d/$1.conf"
if [ -f "$CONFIG" ] ; then
do_action "$CONFIG"
fi
shift
done
else
for CONFIG in /etc/vblade.conf.d/*.conf ; do
if [ -f "$CONFIG" ] ; then
do_action "$CONFIG"
fi
done
fi
exit $EXIT

View File

@@ -0,0 +1,185 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: vblade
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: vblade exports
# Description: Manage all vlbade exports defined in
# /etc/vblade.conf.d/
### END INIT INFO
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="vblade export"
NAME=vblade
VBLADE="/usr/sbin/$NAME"
DAEMON=/usr/bin/daemon
IONICE=/usr/bin/ionice
PIDDIR="/var/run/vblade/"
[ -x "$VBLADE" ] || exit 0
[ -x "$DAEMON" ] || exit 0
mkdir -p "$PIDDIR"
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB functions
. /lib/lsb/init-functions
# Start a vblade instance
#
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
do_start () {
local INSTANCE="$1"
local CONFIG="$2"
sh -n "$CONFIG" 2>/dev/null || return 2
shelf=
slot=
filename=
netif=
options=
ionice=
. "$CONFIG"
[ "$netif" ] || return 2
[ "$shelf" ] || return 2
[ "$slot" ] || return 2
[ "$filename" ] || return 2
if [ "$ionice" ] ; then
if [ -x "$IONICE" ] ; then
ionice="$IONICE $ionice"
else
ionice=
fi
fi
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
&& return 1
$ionice "$DAEMON" \
--respawn \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
--output daemon.notice \
--stdout daemon.notice \
--stderr daemon.err -- \
$VBLADE $options $shelf $slot $netif $filename || return 2
}
# Stop a vblade instance
#
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
do_stop () {
local INSTANCE="$1"
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" || return 1
"$DAEMON" \
--stop \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" \
--stop || return 2
# Wait until the process is gone
for i in $(seq 1 10) ; do
"$DAEMON" \
--running \
--name "$INSTANCE" \
--pidfiles "$PIDDIR" || return 0
done
return 2
}
EXIT=0
do_action () {
local CONFIG="$1"
INSTANCE="$(basename "${CONFIG%%.conf}")"
case "$ACTION" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$INSTANCE"
do_start "$INSTANCE" "$CONFIG"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$INSTANCE"
do_stop "$INSTANCE"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc -p "$PIDDIR/$INSTANCE.pid" "$VBLADE" "vblade instance $INSTANCE" || EXIT=$?
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$INSTANCE"
do_stop "$INSTANCE"
case "$?" in
0|1)
do_start "$INSTANCE" "$CONFIG"
case "$?" in
0) log_end_msg 0 ;;
*)
# Old process is still running or
# failed to start
log_end_msg 1 ;;
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: /etc/init.d/vblade {start|stop|status|restart|force-reload} [<export> ...]" >&2
exit 3
;;
esac
}
ACTION="$1"
shift
if [ "$1" ] ; then
while [ "$1" ] ; do
CONFIG="/etc/vblade.conf.d/$1.conf"
if [ -f "$CONFIG" ] ; then
do_action "$CONFIG"
fi
shift
done
else
for CONFIG in /etc/vblade.conf.d/*.conf ; do
if [ -f "$CONFIG" ] ; then
do_action "$CONFIG"
fi
done
fi
exit $EXIT

View File

@@ -0,0 +1,13 @@
[Unit]
Description=vblade exports
Documentation=man:vblade-persistence(5)
Documentation=man:vblade(8)
[Service]
Type=oneshot
ExecStart=/bin/true
ExecReload=/bin/true
RemainAfterExit=on
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,18 @@
[Unit]
Description=vblade instance %I
SourcePath=/etc/vblade.conf.d/%I.conf
Documentation=man:vblade(8)
PartOf=vblade.service
After=rc-local.service
[Service]
Type=simple
Environment="ionice=-c2 -n7"
EnvironmentFile=/etc/vblade.conf.d/%I.conf
ExecStart=/usr/bin/ionice $ionice /usr/sbin/vblade $shelf $slot $netif $filename $options
SyslogIdentifier=vblade
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,31 @@
This proof-of-concept patch modifies vblade to access the underlying block
device using POSIX asynchronous IO (AIO) rather than using normal blocking
read() and write(). AIO allows vblade to receive and queue several several ATA
read/write commands at once, returning the response to the client
asynchronously as each IO operation completes. It should be most beneficial
for devices which experience very non-sequential IO. An AIO-enabled vblade is
also a good starting point if you want to generalise vblade to export multiple
devices without the complexity and overhead of a multithreaded approach.
The patch implements AIO support for both Linux and FreeBSD, but I have not
tested the FreeBSD support and would therefore be especially interested to
hear success/failure reports for compiling and running AIO vblade on FreeBSD.
A SIGIO handler which writes a single byte to a pipe is used to notify the
main poll() loop that AIO operations have completed and are ready to return to
the client. Running oprofile on a box with a heavily loaded loopback
vblade-aio suggests that it spends an inordinate amount of time in the signal
handler. Some method of poll()ing directly on the AIO events at the same time
as the socket fd could cut this overhead out completely.
More generally, experimenting on Linux with standard O_DIRECT vblade and
O_DIRECT vblade-aio on a loopback interface with MTU 9000 suggests that the
performance difference on a single RAID1-backed block device is fairly small:
swamped by the performance of the network and the underlying block device.
However, the POSIX AIO in glibc librt is emulated in userspace threads rather
than using the kernel AIO api. A kernel-backed POSIX AIO implementation should
perform better, especially for multiple access to a single block device.
I would be delighted to hear any feedback and experiences from people running
vblade together with this patch.
Chris Webb <chris@arachsys.com>, 2008-04-21.

View File

@@ -0,0 +1,538 @@
diff -uprN vblade-17.orig/aoe.c vblade-17/aoe.c
--- vblade-17.orig/aoe.c 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/aoe.c 2008-06-09 11:05:23.000000000 -0400
@@ -8,6 +8,9 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
+#include <errno.h>
+#include <aio.h>
+#include <poll.h>
#include "dat.h"
#include "fns.h"
@@ -22,6 +25,11 @@ char config[Nconfig];
int nconfig = 0;
int maxscnt = 2;
char *ifname;
+int queuepipe[2];
+int pktlen[Nplaces], pending[Nplaces];
+Ata *pkt[Nplaces];
+Ataregs regs[Nplaces];
+struct aiocb aiocb[Nplaces];
void
aoead(int fd) // advertise the virtual blade
@@ -78,32 +86,52 @@ getlba(uchar *p)
}
int
-aoeata(Ata *p, int pktlen) // do ATA reqeust
+aoeata(int place) // do ATA reqeust
{
- Ataregs r;
- int len = 60;
int n;
+ int len = 60; // minimum ethernet packet size
- r.lba = getlba(p->lba);
- r.sectors = p->sectors;
- r.feature = p->err;
- r.cmd = p->cmd;
- if (atacmd(&r, (uchar *)(p+1), maxscnt*512, pktlen - sizeof(*p)) < 0) {
- p->h.flags |= Error;
- p->h.error = BadArg;
+ regs[place].lba = getlba(pkt[place]->lba);
+ regs[place].sectors = pkt[place]->sectors;
+ regs[place].feature = pkt[place]->err;
+ regs[place].cmd = pkt[place]->cmd;
+ n = atacmd(regs + place, (uchar *)(pkt[place] + 1), maxscnt*512,
+ pktlen[place] - sizeof(Ata), aiocb + place);
+ if (n < 0) {
+ pkt[place]->h.flags |= Error;
+ pkt[place]->h.error = BadArg;
return len;
+ } else if (n > 0) {
+ pending[place] = 1;
+ return 0;
+ }
+ if (!(pkt[place]->aflag & Write) && (n = pkt[place]->sectors)) {
+ n -= regs[place].sectors;
+ len = sizeof (Ata) + (n*512);
}
- if (!(p->aflag & Write))
- if ((n = p->sectors)) {
- n -= r.sectors;
+ pkt[place]->sectors = regs[place].sectors;
+ pkt[place]->err = regs[place].err;
+ pkt[place]->cmd = regs[place].status;
+ return len;
+}
+
+int aoeatacomplete(int place, int pktlen)
+{
+ int n;
+ int len = 60; // minimum ethernet packet size
+ atacmdcomplete(regs + place, aiocb + place);
+ if (!(pkt[place]->aflag & Write) && (n = pkt[place]->sectors)) {
+ n -= regs[place].sectors;
len = sizeof (Ata) + (n*512);
}
- p->sectors = r.sectors;
- p->err = r.err;
- p->cmd = r.status;
+ pkt[place]->sectors = regs[place].sectors;
+ pkt[place]->err = regs[place].err;
+ pkt[place]->cmd = regs[place].status;
+ pending[place] = 0;
return len;
}
+
#define QCMD(x) ((x)->vercmd & 0xf)
// yes, this makes unnecessary copies.
@@ -156,8 +184,9 @@ confcmd(Conf *p, int payload) // process
}
void
-doaoe(Aoehdr *p, int n)
+doaoe(int place)
{
+ Aoehdr *p = (Aoehdr *) pkt[place];
int len;
enum { // config query header size
CHDR_SIZ = sizeof(Conf) - sizeof(((Conf *)0)->data),
@@ -165,14 +194,16 @@ doaoe(Aoehdr *p, int n)
switch (p->cmd) {
case ATAcmd:
- if (n < sizeof(Ata))
+ if (pktlen[place] < sizeof(Ata))
+ return;
+ len = aoeata(place);
+ if (len == 0)
return;
- len = aoeata((Ata*)p, n);
break;
case Config:
- if (n < CHDR_SIZ)
+ if (pktlen[place] < CHDR_SIZ)
return;
- len = confcmd((Conf *)p, n - CHDR_SIZ);
+ len = confcmd((Conf *)p, pktlen[place] - CHDR_SIZ);
if (len == 0)
return;
break;
@@ -193,25 +224,129 @@ doaoe(Aoehdr *p, int n)
}
void
+doaoecomplete(int place)
+{
+ Aoehdr *p = (Aoehdr *) pkt[place];
+ int len = aoeatacomplete(place, pktlen[place]);
+ memmove(p->dst, p->src, 6);
+ memmove(p->src, mac, 6);
+ p->maj = htons(shelf);
+ p->min = slot;
+ p->flags |= Resp;
+ if (putpkt(sfd, (uchar *) p, len) == -1) {
+ perror("write to network");
+ exit(1);
+ }
+
+}
+
+// allocate the buffer so that the ata data area
+// is page aligned for o_direct on linux
+
+void *
+bufalloc(void **buf, long len)
+{
+ long psize;
+ unsigned long n;
+
+ psize = sysconf(_SC_PAGESIZE);
+ if (psize == -1) {
+ perror("sysconf");
+ exit(EXIT_FAILURE);
+ }
+ n = len/psize + 3;
+ *buf = malloc(psize * n);
+ if (!*buf) {
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+ n = (unsigned long) *buf;
+ n += psize * 2;
+ n &= ~(psize - 1);
+ return (void *) (n - sizeof (Ata));
+}
+
+void
+sigio(int signo)
+{
+ const char dummy = 0;
+ write(queuepipe[1], &dummy, 1);
+}
+
+void
aoe(void)
{
Aoehdr *p;
- uchar *buf;
- int n, sh;
+ char dummy;
+ int n, place, sh;
enum { bufsz = 1<<16, };
-
- buf = malloc(bufsz);
+ sigset_t mask, oldmask;
+ struct sigaction sigact;
+ struct pollfd pollfds[2];
+ void *freeme[Nplaces];
+
+ for (n = 0; n < Nplaces; n++) {
+ pkt[n] = bufalloc(freeme + n, bufsz);
+ pending[n] = 0;
+ }
aoead(sfd);
+ pipe(queuepipe);
+ fcntl(queuepipe[0], F_SETFL, O_NONBLOCK);
+ fcntl(queuepipe[1], F_SETFL, O_NONBLOCK);
+
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigact.sa_sigaction = (void *) sigio;
+ sigaction(SIGIO, &sigact, NULL);
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGIO);
+ sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+ pollfds[0].fd = queuepipe[0];
+ pollfds[1].fd = sfd;
+ pollfds[0].events = pollfds[1].events = POLLIN;
+
for (;;) {
- n = getpkt(sfd, buf, bufsz);
- if (n < 0) {
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ n = poll(pollfds, 2, 1000);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ if (n < 0 && errno != EINTR) {
+ perror("poll");
+ continue;
+ } else if (n == 0 || pollfds[0].revents & POLLIN) {
+ while(read(queuepipe[0], &dummy, 1) > 0);
+ for (place = 0; place < Nplaces; place++) {
+ if (!pending[place])
+ continue;
+ if (aio_error(aiocb + place) == EINPROGRESS)
+ continue;
+ doaoecomplete(place);
+ pollfds[1].events = POLLIN;
+ }
+ }
+
+ if ((pollfds[1].revents & POLLIN) == 0)
+ continue;
+
+ for (place = 0; pending[place] && place < Nplaces; place++);
+ if (place >= Nplaces) {
+ pollfds[1].events = 0;
+ continue;
+ }
+
+ pktlen[place] = getpkt(sfd, (uchar *) pkt[place], bufsz);
+ if (pktlen[place] < 0) {
+ if (errno == EINTR)
+ continue;
perror("read network");
exit(1);
}
- if (n < sizeof(Aoehdr))
+ if (pktlen[place] < sizeof(Aoehdr))
continue;
- p = (Aoehdr *) buf;
+ p = (Aoehdr *) pkt[place];
if (ntohs(p->type) != 0x88a2)
continue;
if (p->flags & Resp)
@@ -223,9 +358,10 @@ aoe(void)
continue;
if (nmasks && !maskok(p->src))
continue;
- doaoe(p, n);
+ doaoe(place);
}
- free(buf);
+ for (place = 0; place < Nplaces; place++)
+ free(freeme[place]);
}
void
@@ -317,7 +453,7 @@ main(int argc, char **argv)
}
if (s.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
omode = O_RDWR;
- bfd = open(argv[3], omode);
+ bfd = opendisk(argv[3], omode);
if (bfd == -1) {
perror("open");
exit(1);
diff -uprN vblade-17.orig/ata.c vblade-17/ata.c
--- vblade-17.orig/ata.c 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/ata.c 2008-06-09 11:05:23.000000000 -0400
@@ -3,6 +3,8 @@
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
+#include <errno.h>
+#include <aio.h>
#include "dat.h"
#include "fns.h"
@@ -98,7 +100,7 @@ atainit(void)
* check for that.
*/
int
-atacmd(Ataregs *p, uchar *dp, int ndp, int payload) // do the ata cmd
+atacmd(Ataregs *p, uchar *dp, int ndp, int payload, struct aiocb *aiocb) // do the ata cmd
{
vlong lba;
ushort *ip;
@@ -155,14 +157,29 @@ atacmd(Ataregs *p, uchar *dp, int ndp, i
return 0;
}
if (p->cmd == 0x20 || p->cmd == 0x24)
- n = getsec(bfd, dp, lba, p->sectors);
+ n = getsec(bfd, dp, lba, p->sectors, aiocb);
else {
// packet should be big enough to contain the data
if (payload < 512 * p->sectors)
return -1;
- n = putsec(bfd, dp, lba, p->sectors);
+ n = putsec(bfd, dp, lba, p->sectors, aiocb);
}
- n /= 512;
+ if (n < 0) {
+ p->err = ABRT;
+ p->status = ERR|DRDY;
+ p->lba += n;
+ p->sectors -= n;
+ return 0;
+ }
+ return 1; // callback expected
+}
+
+
+int
+atacmdcomplete(Ataregs *p, struct aiocb *aiocb) // complete the ata cmd
+{
+ int n;
+ n = aio_return(aiocb) / 512;
if (n != p->sectors) {
p->err = ABRT;
p->status = ERR;
@@ -173,4 +190,3 @@ atacmd(Ataregs *p, uchar *dp, int ndp, i
p->sectors -= n;
return 0;
}
-
diff -uprN vblade-17.orig/dat.h vblade-17/dat.h
--- vblade-17.orig/dat.h 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/dat.h 2008-06-09 11:05:23.000000000 -0400
@@ -111,6 +111,8 @@ enum {
Nconfig = 1024,
Bufcount = 16,
+
+ Nplaces = 32,
};
int shelf, slot;
diff -uprN vblade-17.orig/fns.h vblade-17/fns.h
--- vblade-17.orig/fns.h 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/fns.h 2008-06-09 11:07:21.000000000 -0400
@@ -15,7 +15,8 @@ int maskok(uchar *);
// ata.c
void atainit(void);
-int atacmd(Ataregs *, uchar *, int, int);
+int atacmd(Ataregs *, uchar *, int, int, struct aiocb *);
+int atacmdcomplete(Ataregs *, struct aiocb *);
// bpf.c
@@ -26,8 +27,9 @@ void free_bpf_program(void *);
int dial(char *);
int getea(int, char *, uchar *);
-int putsec(int, uchar *, vlong, int);
-int getsec(int, uchar *, vlong, int);
+int opendisk(const char *, int);
+int putsec(int, uchar *, vlong, int, struct aiocb *);
+int getsec(int, uchar *, vlong, int, struct aiocb *);
int putpkt(int, uchar *, int);
int getpkt(int, uchar *, int);
vlong getsize(int);
diff -uprN vblade-17.orig/freebsd.c vblade-17/freebsd.c
--- vblade-17.orig/freebsd.c 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/freebsd.c 2008-06-09 11:05:23.000000000 -0400
@@ -209,19 +209,40 @@ getea(int s, char *eth, uchar *ea)
return(0);
}
-
int
-getsec(int fd, uchar *place, vlong lba, int nsec)
+opendisk(const char *disk, int omode)
{
- return pread(fd, place, nsec * 512, lba * 512);
+ return open(disk, omode);
}
int
-putsec(int fd, uchar *place, vlong lba, int nsec)
-{
- return pwrite(fd, place, nsec * 512, lba * 512);
+getsec(int fd, uchar *place, vlong lba, int nsec, struct aiocb *aiocb)
+{
+ bzero((char *) aiocb, sizeof(struct aiocb));
+ aiocb->aio_fildes = fd;
+ aiocb->aio_buf = place;
+ aiocb->aio_nbytes = nsec * 512;
+ aiocb->aio_offset = lba * 512;
+ aiocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb->aio_sigevent.sigev_signo = SIGIO;
+ aiocb->aio_sigevent.sigev_value.sival_ptr = aiocb;
+ return aio_read(aiocb);
}
+int
+putsec(int fd, uchar *place, vlong lba, int nsec, struct aiocb *aiocb)
+{
+ bzero((char *) aiocb, sizeof(struct aiocb));
+ aiocb->aio_fildes = fd;
+ aiocb->aio_buf = place;
+ aiocb->aio_nbytes = nsec * 512;
+ aiocb->aio_offset = lba * 512;
+ aiocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb->aio_sigevent.sigev_signo = SIGIO;
+ aiocb->aio_sigevent.sigev_value.sival_ptr = aiocb;
+ return aio_write(aiocb);
+}
+
static int pktn = 0;
static uchar *pktbp = NULL;
diff -uprN vblade-17.orig/linux.c vblade-17/linux.c
--- vblade-17.orig/linux.c 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/linux.c 2008-06-09 11:05:23.000000000 -0400
@@ -1,5 +1,6 @@
// linux.c: low level access routines for Linux
#include "config.h"
+#define _GNU_SOURCE
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
@@ -22,6 +23,9 @@
#include <netinet/in.h>
#include <linux/fs.h>
#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <aio.h>
#include "dat.h"
#include "fns.h"
@@ -29,8 +33,6 @@
int getindx(int, char *);
int getea(int, char *, uchar *);
-
-
int
dial(char *eth) // get us a raw connection to an interface
{
@@ -84,7 +86,7 @@ getea(int s, char *name, uchar *ea)
struct ifreq xx;
int n;
- strcpy(xx.ifr_name, name);
+ strcpy(xx.ifr_name, name);
n = ioctl(s, SIOCGIFHWADDR, &xx);
if (n == -1) {
perror("Can't get hw addr");
@@ -110,17 +112,37 @@ getmtu(int s, char *name)
}
int
-getsec(int fd, uchar *place, vlong lba, int nsec)
+opendisk(const char *disk, int omode)
+{
+ return open(disk, omode|O_DIRECT);
+}
+
+int
+getsec(int fd, uchar *place, vlong lba, int nsec, struct aiocb *aiocb)
{
- lseek(fd, lba * 512, 0);
- return read(fd, place, nsec * 512);
+ bzero((char *) aiocb, sizeof(struct aiocb));
+ aiocb->aio_fildes = fd;
+ aiocb->aio_buf = place;
+ aiocb->aio_nbytes = nsec * 512;
+ aiocb->aio_offset = lba * 512;
+ aiocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb->aio_sigevent.sigev_signo = SIGIO;
+ aiocb->aio_sigevent.sigev_value.sival_ptr = aiocb;
+ return aio_read(aiocb);
}
int
-putsec(int fd, uchar *place, vlong lba, int nsec)
+putsec(int fd, uchar *place, vlong lba, int nsec, struct aiocb *aiocb)
{
- lseek(fd, lba * 512, 0);
- return write(fd, place, nsec * 512);
+ bzero((char *) aiocb, sizeof(struct aiocb));
+ aiocb->aio_fildes = fd;
+ aiocb->aio_buf = place;
+ aiocb->aio_nbytes = nsec * 512;
+ aiocb->aio_offset = lba * 512;
+ aiocb->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocb->aio_sigevent.sigev_signo = SIGIO;
+ aiocb->aio_sigevent.sigev_value.sival_ptr = aiocb;
+ return aio_write(aiocb);
}
int
diff -uprN vblade-17.orig/linux.h vblade-17/linux.h
--- vblade-17.orig/linux.h 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/linux.h 2008-06-09 11:05:23.000000000 -0400
@@ -6,6 +6,6 @@ typedef long long vlong;
int dial(char *);
int getindx(int, char *);
int getea(int, char *, uchar *);
-int getsec(int, uchar *, vlong, int);
-int putsec(int, uchar *, vlong, int);
+int getsec(int, uchar *, vlong, int, struct aiocb *);
+int putsec(int, uchar *, vlong, int, struct aiocb *);
vlong getsize(int);
diff -uprN vblade-17.orig/makefile vblade-17/makefile
--- vblade-17.orig/makefile 2008-06-09 10:53:07.000000000 -0400
+++ vblade-17/makefile 2008-06-09 11:05:23.000000000 -0400
@@ -13,7 +13,7 @@ CFLAGS += -Wall -g -O2
CC = gcc
vblade: $O
- ${CC} -o vblade $O
+ ${CC} -lrt -o vblade $O
aoe.o : aoe.c config.h dat.h fns.h makefile
${CC} ${CFLAGS} -c $<