Compare commits
68 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b4cb2d9240 | ||
![]() |
1efb7bada6 | ||
![]() |
6bc2a4c0b9 | ||
![]() |
59de76c50c | ||
![]() |
209da655b3 | ||
![]() |
52b45e6b40 | ||
![]() |
d279eb7570 | ||
![]() |
c07df76ede | ||
![]() |
e19d005636 | ||
![]() |
d1e6e835c4 | ||
![]() |
e24efa9864 | ||
![]() |
3134d619ef | ||
![]() |
898f3f6c7e | ||
![]() |
5a1bc21088 | ||
![]() |
deb8f2c53b | ||
![]() |
1338d9e910 | ||
![]() |
47c05174b6 | ||
![]() |
191b3bc72c | ||
![]() |
770ca0d0e5 | ||
![]() |
6505588f25 | ||
![]() |
957707bcfc | ||
![]() |
3f01b77221 | ||
![]() |
0dbea7f8fe | ||
![]() |
091aacd16d | ||
![]() |
04b6637451 | ||
![]() |
7d2eda6cea | ||
![]() |
7e152ca4f2 | ||
![]() |
fe0125efbc | ||
![]() |
ebaaa6d671 | ||
![]() |
8cc8588744 | ||
![]() |
5da77ea39a | ||
![]() |
a744965c67 | ||
![]() |
d07659f694 | ||
![]() |
30562ed900 | ||
![]() |
93c0fa2e92 | ||
![]() |
8dc491fb89 | ||
![]() |
ea7cd64fc2 | ||
![]() |
35d3340708 | ||
![]() |
d47a44a204 | ||
![]() |
d6968d8242 | ||
![]() |
bf85e329a0 | ||
![]() |
edcaef532c | ||
![]() |
cb920e4e9d | ||
![]() |
91d85633b6 | ||
![]() |
7c516b85a6 | ||
![]() |
679fa6dbf8 | ||
![]() |
50708326ec | ||
![]() |
d907025d71 | ||
![]() |
e4d398a078 | ||
![]() |
8de0780125 | ||
![]() |
0fd16822ea | ||
![]() |
1e3c61b541 | ||
![]() |
a09e14b2d4 | ||
![]() |
a6710b6c32 | ||
![]() |
ed3995303f | ||
![]() |
f5de8fb12b | ||
![]() |
99a5f79a52 | ||
![]() |
356e1fd6a1 | ||
![]() |
67dcea207d | ||
![]() |
d3762162db | ||
![]() |
218c55fb63 | ||
![]() |
956a602475 | ||
![]() |
26a0a82f9d | ||
![]() |
76e0476113 | ||
![]() |
d9651a038c | ||
![]() |
fcd3d33498 | ||
![]() |
e3360a3a1b | ||
![]() |
1fefe1a669 |
10
.gitlab-ci.yml
Normal file
10
.gitlab-ci.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
image: "ruby:2.1"
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- apt-get update; apt-get install -y check libev-dev net-tools dpkg-dev
|
||||||
|
|
||||||
|
unit_test:
|
||||||
|
script:
|
||||||
|
- make clean
|
||||||
|
- make build
|
||||||
|
- make test
|
53
Makefile
53
Makefile
@@ -50,15 +50,11 @@ CC?=gcc
|
|||||||
|
|
||||||
LIBS=-lpthread
|
LIBS=-lpthread
|
||||||
INC=-I/usr/include/libev -Isrc/common -Isrc/server -Isrc/proxy
|
INC=-I/usr/include/libev -Isrc/common -Isrc/server -Isrc/proxy
|
||||||
COMPILE=$(CC) $(INC) -c $(CCFLAGS)
|
COMPILE=$(CC) -MMD $(INC) -c $(CCFLAGS)
|
||||||
SAVEDEP=$(CC) $(INC) -MM $(CCFLAGS)
|
|
||||||
LINK=$(CC) $(LLDFLAGS) -Isrc $(LIBS)
|
LINK=$(CC) $(LLDFLAGS) -Isrc $(LIBS)
|
||||||
|
|
||||||
LIB=build/
|
LIB=build/
|
||||||
|
|
||||||
EXISTING_OBJS := $(wildcard build/*.o)
|
|
||||||
-include $(EXISTING_OBJS:.o=.d)
|
|
||||||
|
|
||||||
COMMON_SRC := $(wildcard src/common/*.c)
|
COMMON_SRC := $(wildcard src/common/*.c)
|
||||||
SERVER_SRC := $(wildcard src/server/*.c)
|
SERVER_SRC := $(wildcard src/server/*.c)
|
||||||
PROXY_SRC := $(wildcard src/proxy/*.c)
|
PROXY_SRC := $(wildcard src/proxy/*.c)
|
||||||
@@ -71,12 +67,13 @@ SRCS := $(COMMON_SRC) $(SERVER_SRC) $(PROXY_SRC)
|
|||||||
OBJS := $(COMMON_OBJ) $(SERVER_OBJ) $(PROXY_OBJ)
|
OBJS := $(COMMON_OBJ) $(SERVER_OBJ) $(PROXY_OBJ)
|
||||||
|
|
||||||
|
|
||||||
all: build/flexnbd build/flexnbd-proxy doc
|
all: build doc
|
||||||
|
|
||||||
|
build: server proxy
|
||||||
|
|
||||||
build/%.o: %.c
|
build/%.o: %.c
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(COMPILE) $< -o $@
|
$(COMPILE) $< -o $@
|
||||||
$(SAVEDEP) $< > build/$*.d
|
|
||||||
|
|
||||||
objs: $(OBJS)
|
objs: $(OBJS)
|
||||||
|
|
||||||
@@ -87,41 +84,42 @@ build/flexnbd-proxy: $(COMMON_OBJ) $(PROXY_OBJ) build/proxy-main.o
|
|||||||
$(LINK) $^ -o $@
|
$(LINK) $^ -o $@
|
||||||
|
|
||||||
server: build/flexnbd
|
server: build/flexnbd
|
||||||
|
|
||||||
proxy: build/flexnbd-proxy
|
proxy: build/flexnbd-proxy
|
||||||
|
|
||||||
|
|
||||||
CHECK_SRC := $(wildcard tests/unit/*.c)
|
CHECK_SRC := $(wildcard tests/unit/*.c)
|
||||||
CHECK_OBJ := $(CHECK_SRC:tests/unit/%.c=build/tests/%.o)
|
CHECK_OBJ := $(CHECK_SRC:tests/unit/%.c=build/%.o)
|
||||||
# Why can't we reuse the build/%.o rule above? Not sure.
|
# Why can't we reuse the build/%.o rule above? Not sure.
|
||||||
build/tests/%.o: tests/unit/%.c
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(COMPILE) $< -o $@
|
|
||||||
$(SAVEDEP) $< > build/tests/$*.d
|
|
||||||
|
|
||||||
CHECK_BINS := $(CHECK_OBJ:build/tests/%.o=build/tests/%)
|
CHECK_BINS := $(CHECK_SRC:tests/unit/%.c=build/%)
|
||||||
build/tests/%: build/tests/%.o $(OBJS)
|
|
||||||
$(LINK) $^ -o $@ -lcheck
|
build/check_%: build/check_%.o
|
||||||
|
$(LINK) $^ -o $@ $(COMMON_OBJ) $(SERVER_OBJ) -lcheck
|
||||||
|
|
||||||
check_objs: $(CHECK_OBJ)
|
check_objs: $(CHECK_OBJ)
|
||||||
|
|
||||||
check_bins: $(CHECK_BINS)
|
check_bins: $(CHECK_BINS)
|
||||||
check: $(CHECK_BINS)
|
|
||||||
for bin in $^; do $$bin; done
|
check: $(OBJS) $(CHECK_BINS)
|
||||||
|
r=true ; for bin in $(CHECK_BINS); do $$bin || r=false; done ; $$r
|
||||||
|
|
||||||
|
acceptance: build
|
||||||
|
cd tests/acceptance && RUBYOPT='-I.' ruby nbd_scenarios -v
|
||||||
|
|
||||||
|
test: check acceptance
|
||||||
|
|
||||||
build/flexnbd.1: README.txt
|
build/flexnbd.1: README.txt
|
||||||
a2x --destination-dir build --format manpage $<
|
txt2man -t flexnbd -s 1 $< > $@
|
||||||
|
|
||||||
build/flexnbd-proxy.1: README.proxy.txt
|
build/flexnbd-proxy.1: README.proxy.txt
|
||||||
a2x --destination-dir build --format manpage $<
|
txt2man -t flexnbd-proxy -s 1 $< > $@
|
||||||
|
|
||||||
# If we don't pipe to file, gzip clobbers the original, causing make
|
# If we don't pipe to file, gzip clobbers the original, causing make
|
||||||
# to rebuild each time
|
# to rebuild each time
|
||||||
%.1.gz: %.1
|
%.1.gz: %.1
|
||||||
gzip -c -f $< > $@
|
gzip -c -f $< > $@
|
||||||
|
|
||||||
|
doc: build/flexnbd.1.gz build/flexnbd-proxy.1.gz
|
||||||
server-man: build/flexnbd.1.gz
|
|
||||||
proxy-man: build/flexnbd-proxy.1.gz
|
|
||||||
|
|
||||||
doc: server-man proxy-man
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
mkdir -p $(INSTALLDIR)
|
mkdir -p $(INSTALLDIR)
|
||||||
@@ -131,4 +129,7 @@ clean:
|
|||||||
rm -rf build/*
|
rm -rf build/*
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean objs check_objs all server proxy check_bins check server-man proxy-man doc
|
.PHONY: clean objs check_objs all server proxy check_bins check doc build test acceptance
|
||||||
|
|
||||||
|
# Include extra dependencies at the end, NOT before 'all'
|
||||||
|
-include $(wildcard build/*.d)
|
||||||
|
118
README.proxy.txt
118
README.proxy.txt
@@ -1,19 +1,14 @@
|
|||||||
FLEXNBD-PROXY(1)
|
|
||||||
================
|
|
||||||
:doctype: manpage
|
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
|
||||||
|
|
||||||
flexnbd-proxy - A simple NBD proxy
|
flexnbd-proxy - A simple NBD proxy
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
|
||||||
|
|
||||||
*flexnbd-proxy* ['OPTIONS']
|
flexnbd-proxy --addr ADDR [--port PORT] --conn-addr ADDR
|
||||||
|
--conn-port PORT [--bind ADDR] [--cache[=CACHE_BYTES]]
|
||||||
|
[--help] [--verbose] [--quiet]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
|
||||||
|
|
||||||
flexnbd-proxy is a simple NBD proxy server that implements resilient
|
flexnbd-proxy is a simple NBD proxy server that implements resilient
|
||||||
connection logic for the client. It connects to an upstream NBD server
|
connection logic for the client. It connects to an upstream NBD server
|
||||||
@@ -25,11 +20,6 @@ of view of the client) reconnects and retransmits the request, before
|
|||||||
returning the response to the client.
|
returning the response to the client.
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
-----
|
|
||||||
|
|
||||||
$ flexnbd-proxy --addr <ADDR> [ --port <PORT> ]
|
|
||||||
--conn-addr <ADDR> --conn-port <PORT>
|
|
||||||
[--bind <ADDR>] [--cache[=<CACHE_BYTES>]] [option]*
|
|
||||||
|
|
||||||
Proxy requests from an NBD client to an NBD server, resiliently. Only one
|
Proxy requests from an NBD client to an NBD server, resiliently. Only one
|
||||||
client can be connected at a time, and ACLs cannot be applied to the client, as they
|
client can be connected at a time, and ACLs cannot be applied to the client, as they
|
||||||
@@ -58,40 +48,39 @@ Only one request may be in-flight at a time under the current architecture; that
|
|||||||
doesn't seem to slow things down much relative to alternative options, but may
|
doesn't seem to slow things down much relative to alternative options, but may
|
||||||
be changed in the future if it becomes an issue.
|
be changed in the future if it becomes an issue.
|
||||||
|
|
||||||
Options
|
OPTIONS
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
*--addr, -l ADDR*:
|
--addr, -l ADDR
|
||||||
The address to listen on. If this begins with a '/', it is assumed to be
|
The address to listen on. If this begins with a '/', it is assumed to be
|
||||||
a UNIX domain socket to create. Otherwise, it should be an IPv4 or IPv6
|
a UNIX domain socket to create. Otherwise, it should be an IPv4 or IPv6
|
||||||
address.
|
address.
|
||||||
*--port, -p PORT*:
|
|
||||||
|
--port, -p PORT
|
||||||
The port to listen on, if --addr is not a UNIX socket.
|
The port to listen on, if --addr is not a UNIX socket.
|
||||||
|
|
||||||
*--conn-addr, -C ADDR*:
|
--conn-addr, -C ADDR
|
||||||
The address of the NBD server to connect to. Required.
|
The address of the NBD server to connect to. Required.
|
||||||
|
|
||||||
*--conn-port, -P PORT*:
|
--conn-port, -P PORT
|
||||||
The port of the NBD server to connect to. Required.
|
The port of the NBD server to connect to. Required.
|
||||||
|
|
||||||
*--cache, -c=CACHE_BYTES*:
|
--cache, -c=CACHE_BYTES
|
||||||
If given, the size in bytes of read cache to use. CACHE_BYTES
|
If given, the size in bytes of read cache to use. CACHE_BYTES
|
||||||
defaults to 4096.
|
defaults to 4096.
|
||||||
|
|
||||||
*--help, -h* :
|
--help, -h
|
||||||
Show command or global help.
|
Show command or global help.
|
||||||
|
|
||||||
*--verbose, -v* :
|
--verbose, -v
|
||||||
Output all available log information to STDERR.
|
Output all available log information to STDERR.
|
||||||
|
|
||||||
*--quiet, -q* :
|
--quiet, -q
|
||||||
Output as little log information as possible to STDERR.
|
Output as little log information as possible to STDERR.
|
||||||
|
|
||||||
|
|
||||||
LOGGING
|
LOGGING
|
||||||
-------
|
|
||||||
Log output is sent to STDERR. If --quiet is set, no output will be seen
|
Log output is sent to STDERR. If --quiet is set, no output will be
|
||||||
unless the program termintes abnormally. If neither --quiet nor
|
seen unless the program termintes abnormally. If neither --quiet nor
|
||||||
--verbose are set, no output will be seen unless something goes wrong
|
--verbose are set, no output will be seen unless something goes wrong
|
||||||
with a specific request. If --verbose is given, every available log
|
with a specific request. If --verbose is given, every available log
|
||||||
message will be seen (which, for a debug build, is many). It is not an
|
message will be seen (which, for a debug build, is many). It is not an
|
||||||
@@ -101,32 +90,31 @@ The log line format is:
|
|||||||
|
|
||||||
<TIMESTAMP>:<LEVEL>:<PID> <THREAD> <SOURCEFILE>:<SOURCELINE>: <MSG>
|
<TIMESTAMP>:<LEVEL>:<PID> <THREAD> <SOURCEFILE>:<SOURCELINE>: <MSG>
|
||||||
|
|
||||||
*TIMESTAMP*:
|
<TIMESTAMP>
|
||||||
Time the log entry was made. This is expressed in terms of monotonic ms
|
Time the log entry was made. This is expressed in terms of monotonic ms
|
||||||
|
|
||||||
*LEVEL*:
|
<LEVEL>
|
||||||
This will be one of 'D', 'I', 'W', 'E', 'F' in increasing order of
|
This will be one of 'D', 'I', 'W', 'E', 'F' in increasing order of
|
||||||
severity. If flexnbd is started with the --quiet flag, only 'F' will be
|
severity. If flexnbd is started with the --quiet flag, only 'F' will
|
||||||
seen. If it is started with the --verbose flag, any from 'I' upwards
|
be seen. If it is started with the --verbose flag, any from 'I'
|
||||||
will be seen. Only if you have a debug build and start it with
|
upwards will be seen. Only if you have a debug build and start it
|
||||||
--verbose will you see 'D' entries.
|
with --verbose will you see 'D' entries.
|
||||||
|
|
||||||
*PID*:
|
<PID>
|
||||||
This is the process ID.
|
This is the process ID.
|
||||||
|
|
||||||
*THREAD*:
|
<THREAD>
|
||||||
flexnbd-proxy is currently single-threaded, so this should be the same
|
flexnbd-proxy is currently single-threaded, so this should be the
|
||||||
for all lines. That may not be the case in the future.
|
same for all lines. That may not be the case in the future.
|
||||||
|
|
||||||
*SOURCEFILE:SOURCELINE*:
|
<SOURCEFILE:SOURCELINE>
|
||||||
Identifies where in the source code this log line can be found.
|
Identifies where in the source code this log line can be found.
|
||||||
|
|
||||||
*MSG*:
|
<MSG>
|
||||||
A short message describing what's happening, how it's being done, or
|
A short message describing what's happening, how it's being done, or
|
||||||
if you're very lucky *why* it's going on.
|
if you're very lucky why it's going on.
|
||||||
|
|
||||||
Proxying
|
EXAMPLES
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
The main point of the proxy mode is to allow clients that would otherwise break
|
The main point of the proxy mode is to allow clients that would otherwise break
|
||||||
when the NBD server goes away (during a migration, for instance) to see a
|
when the NBD server goes away (during a migration, for instance) to see a
|
||||||
@@ -160,7 +148,6 @@ The data in myfile has been moved between physical servers without the nbd
|
|||||||
client process having to be disturbed at all.
|
client process having to be disturbed at all.
|
||||||
|
|
||||||
READ CACHE
|
READ CACHE
|
||||||
----------
|
|
||||||
|
|
||||||
If the --cache option is given at the command line, either without an
|
If the --cache option is given at the command line, either without an
|
||||||
argument or with an argument greater than 0, flexnbd-proxy will use a
|
argument or with an argument greater than 0, flexnbd-proxy will use a
|
||||||
@@ -173,7 +160,7 @@ cache without making a request to the server.
|
|||||||
This pattern is designed to match sequential reads, such as those
|
This pattern is designed to match sequential reads, such as those
|
||||||
performed by a booting virtual machine.
|
performed by a booting virtual machine.
|
||||||
|
|
||||||
Note: If specifying a cache size, you *must* use this form:
|
Note: If specifying a cache size, you must use this form:
|
||||||
|
|
||||||
nbd-client$ flexnbd-proxy --cache=XXXX
|
nbd-client$ flexnbd-proxy --cache=XXXX
|
||||||
|
|
||||||
@@ -183,30 +170,37 @@ If no cache size is given, a size of 4096 bytes is assumed. Caching can
|
|||||||
be explicitly disabled by setting a size of 0.
|
be explicitly disabled by setting a size of 0.
|
||||||
|
|
||||||
BUGS
|
BUGS
|
||||||
----
|
|
||||||
|
|
||||||
Should be reported to nick@bytemark.co.uk.
|
Should be reported via GitHub.
|
||||||
|
|
||||||
|
* https://github.com/BytemarkHosting/flexnbd-c/issues
|
||||||
|
|
||||||
Current issues include:
|
Current issues include:
|
||||||
|
|
||||||
* Only old-style NBD negotiation is supported
|
* only old-style NBD negotiation is supported;
|
||||||
* Only one request may be in-flight at a time
|
* only one request may be in-flight at a time;
|
||||||
* All I/O is blocking, and signals terminate the process immediately
|
* all I/O is blocking, and signals terminate the process immediately;
|
||||||
* UNIX socket support is limited to the listen address
|
* UNIX socket support is limited to the listen address;
|
||||||
* FLUSH and TRIM commands, and the FUA flag, are not supported
|
* FLUSH and TRIM commands, and the FUA flag, are not supported;
|
||||||
* DISCONNECT requests do not get passed through to the NBD server
|
* DISCONNECT requests do not get passed through to the NBD server;
|
||||||
* No active timeout-retry of requests - we trust the kernel's idea of failure
|
* no active timeout-retry of requests - we trust the kernel's idea of
|
||||||
|
failure.
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
------
|
|
||||||
Written by Alex Young <alex@bytemark.co.uk>.
|
Originally written by Alex Young <alex@blackkettle.org>.
|
||||||
Original concept and core code by Matthew Bloch <matthew@bytemark.co.uk>.
|
Original concept and core code by Matthew Bloch <matthew@bytemark.co.uk>.
|
||||||
Proxy mode written by Nick Thomas <nick@bytemark.co.uk>
|
Proxy mode written by Nick Thomas <me@ur.gs>.
|
||||||
|
|
||||||
COPYING
|
The full commit history is available on GitHub.
|
||||||
-------
|
|
||||||
|
|
||||||
Copyright (c) 2012 Bytemark Hosting Ltd. Free use of this software is
|
SEE ALSO
|
||||||
granted under the terms of the GNU General Public License version 3 or
|
|
||||||
later.
|
flexnbd(1), nbd-client(8), xnbd-server(8), xnbd-client(8)
|
||||||
|
|
||||||
|
COPYRIGHT
|
||||||
|
|
||||||
|
Copyright (c) 2012-2016 Bytemark Hosting Ltd. Free use of this
|
||||||
|
software is granted under the terms of the GNU General Public License
|
||||||
|
version 3 or later.
|
||||||
|
|
||||||
|
319
README.txt
319
README.txt
@@ -1,17 +1,36 @@
|
|||||||
FLEXNBD(1)
|
|
||||||
==========
|
|
||||||
:doctype: manpage
|
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
|
||||||
flexnbd - A fast NBD server
|
flexnbd - A fast NBD server
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
|
||||||
*flexnbd* 'COMMAND' ['OPTIONS']
|
flexnbd MODE [ ARGS ]
|
||||||
|
|
||||||
|
flexnbd serve --addr ADDR --port PORT --file FILE [--sock SOCK]
|
||||||
|
[--default-deny] [--killswitch] [global_option]* [acl_entry]*
|
||||||
|
|
||||||
|
flexnbd listen --addr ADDR --port PORT --file FILE [--sock SOCK]
|
||||||
|
[--default-deny] [global_option]* [acl_entry]*
|
||||||
|
|
||||||
|
flexnbd mirror --addr ADDR --port PORT --sock SOCK [--unlink]
|
||||||
|
[--bind BIND_ADDR] [global_option]*
|
||||||
|
|
||||||
|
flexnbd acl --sock SOCK [acl_entry]+ [global_option]*
|
||||||
|
|
||||||
|
flexnbd break --sock SOCK [global_option]*
|
||||||
|
|
||||||
|
flexnbd status --sock SOCK [global_option]*
|
||||||
|
|
||||||
|
flexnbd read --addr ADDR --port PORT --from OFFSET --size SIZE
|
||||||
|
[--bind BIND_ADDR] [global_option]*
|
||||||
|
|
||||||
|
flexnbd write --addr ADDR --port PORT --from OFFSET --size SIZE
|
||||||
|
[--bind BIND_ADDR] [global_option]*
|
||||||
|
|
||||||
|
flexnbd help [mode] [global_option]*
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
|
||||||
Flexnbd is a fast NBD server which supports live migration. Live
|
Flexnbd is a fast NBD server which supports live migration. Live
|
||||||
migration is performed by writing the data to a new server. A failed
|
migration is performed by writing the data to a new server. A failed
|
||||||
migration will be invisible to any connected clients.
|
migration will be invisible to any connected clients.
|
||||||
@@ -19,57 +38,56 @@ migration will be invisible to any connected clients.
|
|||||||
Flexnbd tries quite hard to preserve sparsity of files it is serving,
|
Flexnbd tries quite hard to preserve sparsity of files it is serving,
|
||||||
even across migrations.
|
even across migrations.
|
||||||
|
|
||||||
COMMANDS
|
SERVE MODE
|
||||||
--------
|
|
||||||
|
Serve a file.
|
||||||
|
|
||||||
serve
|
|
||||||
~~~~~
|
|
||||||
$ flexnbd serve --addr <ADDR> --port <PORT> --file <FILE>
|
$ flexnbd serve --addr <ADDR> --port <PORT> --file <FILE>
|
||||||
[--sock <SOCK>] [--default-deny] [-k] [global option]* [acl entry]*
|
[--sock <SOCK>] [--default-deny] [-k] [global_option]*
|
||||||
|
[acl_entry]*
|
||||||
|
|
||||||
Serve a file. If any ACL entries are given (which should be IP
|
If any ACL entries are given (which should be IP
|
||||||
addresses), only those clients listed will be permitted to connect.
|
addresses), only those clients listed will be permitted to connect.
|
||||||
|
|
||||||
flexnbd will continue to serve until a SIGINT, SIGQUIT, or a successful
|
flexnbd will continue to serve until a SIGINT, SIGQUIT, or a successful
|
||||||
migration.
|
migration.
|
||||||
|
|
||||||
Options
|
OPTIONS
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
*--addr, -l ADDR*:
|
--addr, -l ADDR
|
||||||
The address to listen on. Required.
|
The address to listen on. Required.
|
||||||
|
|
||||||
*--port, -p PORT*:
|
--port, -p PORT
|
||||||
The port to listen on. Required.
|
The port to listen on. Required.
|
||||||
|
|
||||||
*--file, -f FILE*:
|
--file, -f FILE
|
||||||
The file to serve. Must already exist. Required.
|
The file to serve. Must already exist. Required.
|
||||||
|
|
||||||
*--sock, -s SOCK*:
|
--sock, -s SOCK
|
||||||
Path to a control socket to open. You will need this if you want to
|
Path to a control socket to open. You will need this if you want to
|
||||||
migrate, get the current status, or manipulate the access control
|
migrate, get the current status, or manipulate the access control
|
||||||
list.
|
list.
|
||||||
|
|
||||||
*--default-deny, -d*:
|
--default-deny, -d
|
||||||
How to interpret an empty ACL. If --default-deny is given, an
|
How to interpret an empty ACL. If --default-deny is given, an
|
||||||
empty ACL will let no clients connect. If it is not given, an
|
empty ACL will let no clients connect. If it is not given, an
|
||||||
empty ACL will let any client connect.
|
empty ACL will let any client connect.
|
||||||
|
|
||||||
*--killswitch, -k*:
|
--killswitch, -k
|
||||||
If set, we implement a 2-minute timeout on NBD requests and
|
If set, we implement a 2-minute timeout on NBD requests and
|
||||||
responses. If a request takes longer than that to complete,
|
responses. If a request takes longer than that to complete,
|
||||||
the client is disconnected. This is useful to keep broken
|
the client is disconnected. This is useful to keep broken
|
||||||
clients from breaking migrations, among other things.
|
clients from breaking migrations, among other things.
|
||||||
|
|
||||||
listen
|
LISTEN MODE
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
$ flexnbd listen --addr <ADDR> --port <PORT> --file <FILE>
|
|
||||||
[--sock <SOCK>] [--default-deny] [global option]* [acl entry]*
|
|
||||||
|
|
||||||
Listen for an inbound migration, and quit with a status of 0 on
|
Listen for an inbound migration, and quit with a status of 0 on
|
||||||
completion.
|
completion.
|
||||||
|
|
||||||
|
$ flexnbd listen --addr ADDR --port PORT --file FILE
|
||||||
|
[--sock SOCK] [--default-deny] [global_option]*
|
||||||
|
[acl_entry]*
|
||||||
|
|
||||||
flexnbd will wait for a successful migration, and then quit. The file
|
flexnbd will wait for a successful migration, and then quit. The file
|
||||||
to write the inbound migration data to must already exist before you
|
to write the inbound migration data to must already exist before you
|
||||||
run 'flexnbd listen'.
|
run 'flexnbd listen'.
|
||||||
@@ -81,25 +99,24 @@ to assume that a partial migration can be resumed because the
|
|||||||
destination has no knowledge of whether a client has made a write to
|
destination has no knowledge of whether a client has made a write to
|
||||||
the source in the interim.
|
the source in the interim.
|
||||||
|
|
||||||
If the migration fails for a reason which the `flexnbd listen` process
|
If the migration fails for a reason which the 'flexnbd listen' process
|
||||||
can't fix (say, a failed local write), it will exit with an error
|
can't fix (say, a failed local write), it will exit with an error
|
||||||
status. In this case, the sender will continually retry the migration
|
status. In this case, the sender will continually retry the migration
|
||||||
until it succeeds, and you will need to restart the `flexnbd listen`
|
until it succeeds, and you will need to restart the 'flexnbd listen'
|
||||||
process to allow that to happen.
|
process to allow that to happen.
|
||||||
|
|
||||||
Options
|
OPTIONS
|
||||||
^^^^^^^
|
|
||||||
As for 'serve'.
|
|
||||||
|
|
||||||
mirror
|
As for serve.
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
$ flexnbd mirror --addr <ADDR> --port <PORT> --sock SOCK
|
MIRROR MODE
|
||||||
[--unlink] [--bind <BIND-ADDR>] [global option]*
|
|
||||||
|
|
||||||
Start a migration from the server with control socket SOCK to the server
|
Start a migration from the server with control socket SOCK to the server
|
||||||
listening at ADDR:PORT.
|
listening at ADDR:PORT.
|
||||||
|
|
||||||
|
$ flexnbd mirror --addr ADDR --port PORT --sock SOCK [--unlink]
|
||||||
|
[--bind BIND_ADDR] [global_option]*
|
||||||
|
|
||||||
Migration can be a slow process. Rather than block the 'flexnbd mirror'
|
Migration can be a slow process. Rather than block the 'flexnbd mirror'
|
||||||
process until it completes, it will exit with a message of "Migration
|
process until it completes, it will exit with a message of "Migration
|
||||||
started" once it has confirmation that the local server was able to
|
started" once it has confirmation that the local server was able to
|
||||||
@@ -112,7 +129,7 @@ again. It is not safe to resume the migration from where it left off
|
|||||||
because the source can't see that the backing store behind the
|
because the source can't see that the backing store behind the
|
||||||
destination is intact, or even on the same machine.
|
destination is intact, or even on the same machine.
|
||||||
|
|
||||||
If the `--unlink` option is given, the local file will be deleted
|
If the --unlink option is given, the local file will be deleted
|
||||||
immediately before the mirror connection is terminated. This allows
|
immediately before the mirror connection is terminated. This allows
|
||||||
an otherwise-ambiguous situation to be resolved: if you don't unlink
|
an otherwise-ambiguous situation to be resolved: if you don't unlink
|
||||||
the file and the flexnbd process at either end is terminated, it's not
|
the file and the flexnbd process at either end is terminated, it's not
|
||||||
@@ -122,161 +139,150 @@ the data, there can be no ambiguity.
|
|||||||
|
|
||||||
Note: files smaller than 4096 bytes cannot be mirrored.
|
Note: files smaller than 4096 bytes cannot be mirrored.
|
||||||
|
|
||||||
Options
|
OPTIONS
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
*--addr, -l ADDR*:
|
--addr, -l ADDR
|
||||||
The address of the remote server to migrate to. Required.
|
The address of the remote server to migrate to. Required.
|
||||||
|
|
||||||
*--port, -p PORT*:
|
--port, -p PORT
|
||||||
The port of the remote server to migrate to. Required.
|
The port of the remote server to migrate to. Required.
|
||||||
|
|
||||||
*--sock, -s SOCK*:
|
--sock, -s SOCK
|
||||||
The control socket of the local server to migrate from. Required.
|
The control socket of the local server to migrate from. Required.
|
||||||
|
|
||||||
*--unlink, -u*:
|
--unlink, -u
|
||||||
Unlink the served file from the local filesystem after successfully
|
Unlink the served file from the local filesystem after
|
||||||
mirroring.
|
successfully mirroring.
|
||||||
|
|
||||||
*--bind, -b BIND-ADDR*:
|
--bind, -b BIND_ADDR
|
||||||
The local address to bind to. You may need this if the remote server
|
The local address to bind to. You may need this if the remote
|
||||||
is using an access control list.
|
server is using an access control list.
|
||||||
|
|
||||||
break
|
BREAK MODE
|
||||||
~~~~~
|
|
||||||
|
|
||||||
$ flexnbd mirror --sock SOCK [global option]*
|
|
||||||
|
|
||||||
Stop a running migration.
|
Stop a running migration.
|
||||||
|
|
||||||
Options
|
$ flexnbd break --sock SOCK [global_option]*
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
*--sock, -s SOCK*:
|
OPTIONS
|
||||||
The control socket of the local server whose emigration to stop.
|
|
||||||
|
--sock, -s SOCK
|
||||||
|
The control socket of the local server whose migration to stop.
|
||||||
Required.
|
Required.
|
||||||
|
|
||||||
|
ACL MODE
|
||||||
acl
|
|
||||||
~~~
|
|
||||||
|
|
||||||
$ flexnbd acl --sock <SOCK> [acl entry]+ [global option]*
|
|
||||||
|
|
||||||
Set the access control list of the server with the control socket SOCK
|
Set the access control list of the server with the control socket SOCK
|
||||||
to the given access control list entries.
|
to the given access control list entries.
|
||||||
|
|
||||||
|
$ flexnbd acl --sock SOCK [acl_entry]+ [global_option]*
|
||||||
|
|
||||||
ACL entries are given as IP addresses.
|
ACL entries are given as IP addresses.
|
||||||
|
|
||||||
Options
|
OPTIONS
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
*--sock, -s SOCK*:
|
--sock, -s SOCK
|
||||||
The control socket of the server whose ACL to replace.
|
The control socket of the server whose ACL to replace. Required
|
||||||
|
|
||||||
status
|
STATUS MODE
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
$ flexnbd status --sock <SOCK> [global option]*
|
|
||||||
|
|
||||||
Get the current status of the server with control socket SOCK.
|
Get the current status of the server with control socket SOCK.
|
||||||
|
|
||||||
|
$ flexnbd status --sock SOCK [global_option]*
|
||||||
|
|
||||||
The status will be printed to STDOUT. It is a space-separated list of
|
The status will be printed to STDOUT. It is a space-separated list of
|
||||||
key=value pairs. The space character will never appear in a key or
|
key=value pairs. The space character will never appear in a key or
|
||||||
value. Currently reported values are:
|
value. Currently reported values are:
|
||||||
|
|
||||||
*pid*:
|
pid
|
||||||
The process id of the server listening on SOCK.
|
The process id of the server listening on SOCK.
|
||||||
|
|
||||||
*is_mirroring*:
|
is_mirroring
|
||||||
'true' if this server is sending migration data, 'false' otherwise.
|
'true' if this server is sending migration data, 'false' otherwise.
|
||||||
|
|
||||||
*has_control*:
|
has_control
|
||||||
'false' if this server was started in 'listen' mode. 'true' otherwise.
|
'false' if this server was started in 'listen' mode. 'true' otherwise.
|
||||||
|
|
||||||
read
|
OPTIONS
|
||||||
~~~~
|
|
||||||
|
|
||||||
$ flexnbd read --addr <ADDR> --port <PORT> --from <OFFSET>
|
--sock, -s SOCK
|
||||||
--size <SIZE> [--bind BIND-ADDR] [global option]*
|
The control socket of the server of interest. Required.
|
||||||
|
|
||||||
|
READ MODE
|
||||||
|
|
||||||
Connect to the server at ADDR:PORT, and read SIZE bytes starting at
|
Connect to the server at ADDR:PORT, and read SIZE bytes starting at
|
||||||
OFFSET in a single NBD query. The returned data will be echoed to
|
OFFSET in a single NBD query.
|
||||||
STDOUT. In case of a remote ACL, set the local source address to
|
|
||||||
BIND-ADDR.
|
|
||||||
|
|
||||||
Options
|
$ flexnbd read --addr ADDR --port PORT --from OFFSET --size SIZE
|
||||||
^^^^^^^
|
[--bind BIND_ADDR] [global_option]*
|
||||||
|
|
||||||
*--addr, -l ADDR*:
|
The returned data will be echoed to STDOUT. In case of a remote ACL,
|
||||||
|
set the local source address to BIND_ADDR.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
|
||||||
|
--addr, -l ADDR
|
||||||
The address of the remote server. Required.
|
The address of the remote server. Required.
|
||||||
|
|
||||||
*--port, -p PORT*:
|
--port, -p PORT
|
||||||
The port of the remote server. Required.
|
The port of the remote server. Required.
|
||||||
|
|
||||||
*--from, -F OFFSET*:
|
--from, -F OFFSET
|
||||||
The byte offset to start reading from. Required. Maximum 2^62.
|
The byte offset to start reading from. Required. Maximum 2^62.
|
||||||
|
|
||||||
*--size, -S SIZE*:
|
--size, -S SIZE
|
||||||
The number of bytes to read. Required. Maximum 2^30.
|
The number of bytes to read. Required. Maximum 2^30.
|
||||||
|
|
||||||
*--bind, -b BIND-ADDR*:
|
--bind, -b BIND_ADDR
|
||||||
The local address to bind to. You may need this if the remote server
|
The local address to bind to. You may need this if the remote
|
||||||
is using an access control list.
|
server is using an access control list.
|
||||||
|
|
||||||
write
|
WRITE MODE
|
||||||
~~~~~
|
|
||||||
|
|
||||||
$ cat ... | flexnbd write --addr <ADDR> --port <PORT> --from <OFFSET>
|
|
||||||
--size <SIZE> [--bind BIND-ADDR] [global option]*
|
|
||||||
|
|
||||||
Connect to the server at ADDR:PORT, and write SIZE bytes from STDIN
|
Connect to the server at ADDR:PORT, and write SIZE bytes from STDIN
|
||||||
starting at OFFSET in a single NBD query. In case of a remote ACL, set
|
starting at OFFSET in a single NBD query.
|
||||||
the local source address to BIND-ADDR.
|
|
||||||
|
|
||||||
Options
|
$ cat ... | flexnbd write --addr ADDR --port PORT --from OFFSET
|
||||||
^^^^^^^
|
--size SIZE [--bind BIND_ADDR] [global_option]*
|
||||||
|
|
||||||
*--addr, -l ADDR*:
|
In case of a remote ACL, set the local source address to BIND_ADDR.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
|
||||||
|
--addr, -l ADDR
|
||||||
The address of the remote server. Required.
|
The address of the remote server. Required.
|
||||||
|
|
||||||
*--port, -p PORT*:
|
--port, -p PORT
|
||||||
The port of the remote server. Required.
|
The port of the remote server. Required.
|
||||||
|
|
||||||
*--from, -F OFFSET*:
|
--from, -F OFFSET
|
||||||
The byte offset to start writing from. Required. Maximum 2^62.
|
The byte offset to start writing from. Required. Maximum 2^62.
|
||||||
|
|
||||||
*--size, -S SIZE*:
|
--size, -S SIZE
|
||||||
The number of bytes to write. Required. Maximum 2^30.
|
The number of bytes to write. Required. Maximum 2^30.
|
||||||
|
|
||||||
*--bind, -b BIND-ADDR*:
|
--bind, -b BIND_ADDR
|
||||||
The local address to bind to. You may need this if the remote server
|
The local address to bind to. You may need this if the remote
|
||||||
is using an access control list.
|
server is using an access control list.
|
||||||
|
|
||||||
help
|
HELP MODE
|
||||||
~~~~
|
|
||||||
|
|
||||||
$ flexnbd help [command] [global option]*
|
$ flexnbd help [mode] [global_option]*
|
||||||
|
|
||||||
Without 'command', show the list of available commands. With 'command',
|
Without mode, show the list of available modes. With mode, show help for that mode.
|
||||||
show help for that command.
|
|
||||||
|
|
||||||
GLOBAL OPTIONS
|
GLOBAL OPTIONS
|
||||||
--------------
|
|
||||||
|
|
||||||
*--help, -h* :
|
--help, -h Show mode or global help.
|
||||||
Show command or global help.
|
|
||||||
|
|
||||||
*--verbose, -v* :
|
--verbose, -v Output all available log information to STDERR.
|
||||||
Output all available log information to STDERR.
|
|
||||||
|
|
||||||
*--quiet, -q* :
|
|
||||||
Output as little log information as possible to STDERR.
|
|
||||||
|
|
||||||
|
--quiet, -q Output as little log information as possible to STDERR.
|
||||||
|
|
||||||
LOGGING
|
LOGGING
|
||||||
-------
|
|
||||||
Log output is sent to STDERR. If --quiet is set, no output will be seen
|
Log output is sent to STDERR. If --quiet is set, no output will be
|
||||||
unless the program termintes abnormally. If neither --quiet nor
|
seen unless the program termintes abnormally. If neither --quiet nor
|
||||||
--verbose are set, no output will be seen unless something goes wrong
|
--verbose are set, no output will be seen unless something goes wrong
|
||||||
with a specific request. If --verbose is given, every available log
|
with a specific request. If --verbose is given, every available log
|
||||||
message will be seen (which, for a debug build, is many). It is not an
|
message will be seen (which, for a debug build, is many). It is not an
|
||||||
@@ -284,39 +290,38 @@ error to set both --verbose and --quiet. The last one wins.
|
|||||||
|
|
||||||
The log line format is:
|
The log line format is:
|
||||||
|
|
||||||
<TIMESTAMP>:<LEVEL>:<PID> <THREAD> <SOURCEFILE>:<SOURCELINE>: <MSG>
|
<TIMESTAMP>:<LEVEL>:<PID> <THREAD> <SOURCEFILE:SOURCELINE>: <MSG>
|
||||||
|
|
||||||
*TIMESTAMP*:
|
<TIMESTAMP>
|
||||||
Time the log entry was made. This is expressed in terms of monotonic ms.
|
Time the log entry was made. This is expressed in terms of monotonic
|
||||||
|
ms.
|
||||||
|
|
||||||
*LEVEL*:
|
<LEVEL>
|
||||||
This will be one of 'D', 'I', 'W', 'E', 'F' in increasing order of
|
This will be one of 'D', 'I', 'W', 'E', 'F' in increasing order of
|
||||||
severity. If flexnbd is started with the --quiet flag, only 'F' will be
|
severity. If flexnbd is started with the --quiet flag, only 'F'
|
||||||
seen. If it is started with the --verbose flag, any from 'I' upwards
|
will be seen. If it is started with the --verbose flag, any from 'I'
|
||||||
will be seen. Only if you have a debug build and start it with
|
upwards will be seen. Only if you have a debug build and start it
|
||||||
--verbose will you see 'D' entries.
|
with --verbose will you see 'D' entries.
|
||||||
|
|
||||||
*PID*:
|
<PID>
|
||||||
This is the process ID.
|
This is the process ID.
|
||||||
|
|
||||||
*THREAD*:
|
<THREAD>
|
||||||
There are several pthreads per flexnbd process: a main thread, a serve
|
There are several pthreads per flexnbd process: a main thread, a
|
||||||
thread, a thread per client, and possibly a pair of mirror threads and a
|
serve thread, a thread per client, and possibly a pair of mirror
|
||||||
control thread. This field identifies which thread was responsible for
|
threads and a control thread. This field identifies which thread was
|
||||||
the log line.
|
responsible for the log line.
|
||||||
|
|
||||||
*SOURCEFILE:SOURCELINE*:
|
<SOURCEFILE:SOURCELINE>
|
||||||
Identifies where in the source code this log line can be found.
|
Identifies where in the source code this log line can be found.
|
||||||
|
|
||||||
*MSG*:
|
<MSG>
|
||||||
A short message describing what's happening, how it's being done, or
|
A short message describing what's happening, how it's being done, or
|
||||||
if you're very lucky *why* it's going on.
|
if you're very lucky why it's going on.
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
--------
|
|
||||||
|
|
||||||
Serving a file
|
SERVING A FILE
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The simplest case is serving a file on the default nbd port:
|
The simplest case is serving a file on the default nbd port:
|
||||||
|
|
||||||
@@ -326,8 +331,7 @@ The simplest case is serving a file on the default nbd port:
|
|||||||
root:x:
|
root:x:
|
||||||
$
|
$
|
||||||
|
|
||||||
Reading server status
|
READING SERVER STATUS
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
In order to read a server's status, we need it to open a control socket.
|
In order to read a server's status, we need it to open a control socket.
|
||||||
|
|
||||||
@@ -340,8 +344,7 @@ In order to read a server's status, we need it to open a control socket.
|
|||||||
|
|
||||||
Note that the status output is newline-terminated.
|
Note that the status output is newline-terminated.
|
||||||
|
|
||||||
Migrating
|
MIGRATING
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
To migrate, we need to provide a destination file of the right size.
|
To migrate, we need to provide a destination file of the right size.
|
||||||
|
|
||||||
@@ -367,8 +370,8 @@ With this knowledge in hand, we can start the migration:
|
|||||||
$ flexnbd mirror --addr 127.0.0.1 --port 4779 \
|
$ flexnbd mirror --addr 127.0.0.1 --port 4779 \
|
||||||
--sock /tmp/flex-source.sock
|
--sock /tmp/flex-source.sock
|
||||||
Migration started
|
Migration started
|
||||||
[1] + 9648 done build/flexnbd serve --addr 0.0.0.0 --port 4778
|
[1] + 9648 done flexnbd serve --addr 0.0.0.0 --port 4778
|
||||||
[2] + 9651 done build/flexnbd listen --addr 0.0.0.0 --port 4779
|
[2] + 9651 done flexnbd listen --addr 0.0.0.0 --port 4779
|
||||||
$
|
$
|
||||||
|
|
||||||
Note that because the file is so small in this case, we see the source
|
Note that because the file is so small in this case, we see the source
|
||||||
@@ -376,21 +379,25 @@ server quit soon after we start the migration, and the destination
|
|||||||
exited at roughly the same time.
|
exited at roughly the same time.
|
||||||
|
|
||||||
BUGS
|
BUGS
|
||||||
----
|
|
||||||
|
|
||||||
Should be reported to alex@bytemark.co.uk.
|
Should be reported on GitHub at
|
||||||
|
|
||||||
|
* https://github.com/BytemarkHosting/flexnbd-c/issues
|
||||||
|
|
||||||
AUTHOR
|
AUTHOR
|
||||||
------
|
|
||||||
|
|
||||||
Written by Alex Young <alex@bytemark.co.uk>.
|
Originally written by Alex Young <alex@blackkettle.org>.
|
||||||
Original concept and core code by Matthew Bloch <matthew@bytemark.co.uk>.
|
Original concept and core code by Matthew Bloch <matthew@bytemark.co.uk>.
|
||||||
Some additions by Nick Thomas <nick@bytemark.co.uk>
|
Proxy mode written by Nick Thomas <me@ur.gs>.
|
||||||
|
|
||||||
COPYING
|
The full commit history is available on GitHub.
|
||||||
-------
|
|
||||||
|
|
||||||
Copyright (c) 2012 Bytemark Hosting Ltd. Free use of this software is
|
SEE ALSO
|
||||||
granted under the terms of the GNU General Public License version 3 or
|
|
||||||
later.
|
|
||||||
|
|
||||||
|
flexnbd-proxy(1), nbd-client(8), xnbd-server(8), xnbd-client(8)
|
||||||
|
|
||||||
|
COPYRIGHT
|
||||||
|
|
||||||
|
Copyright (c) 2012-2016 Bytemark Hosting Ltd. Free use of this
|
||||||
|
software is granted under the terms of the GNU General Public License
|
||||||
|
version 3 or later.
|
||||||
|
60
Rakefile
60
Rakefile
@@ -1,60 +0,0 @@
|
|||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
def make(*targets)
|
|
||||||
sh "make #{targets.map{|t| t.to_s}.join(" ")}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def maketask( opts )
|
|
||||||
case opts
|
|
||||||
when Symbol
|
|
||||||
maketask opts => opts
|
|
||||||
else
|
|
||||||
opts.each do |name, targets|
|
|
||||||
task( name ){make *[*targets]}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc "Build the binary and man page"
|
|
||||||
maketask :build => [:all, :doc]
|
|
||||||
|
|
||||||
desc "Build just the flexnbd binary"
|
|
||||||
maketask :flexnbd => [:server]
|
|
||||||
file "build/flexnbd" => :flexnbd
|
|
||||||
|
|
||||||
desc "Build just the flexnbd-proxy binary"
|
|
||||||
maketask :flexnbd_proxy => [:proxy]
|
|
||||||
file "build/flexnbd-proxy" => :flexnbd_proxy
|
|
||||||
|
|
||||||
desc "Build just the man page"
|
|
||||||
maketask :man => :doc
|
|
||||||
|
|
||||||
|
|
||||||
namespace "test" do
|
|
||||||
desc "Run all tests"
|
|
||||||
task 'run' => ["unit", "scenarios"]
|
|
||||||
|
|
||||||
desc "Build C tests"
|
|
||||||
maketask :build => :check_bins
|
|
||||||
|
|
||||||
desc "Run C tests"
|
|
||||||
maketask :unit => :check
|
|
||||||
|
|
||||||
desc "Run NBD test scenarios"
|
|
||||||
task 'scenarios' => ["build/flexnbd", "build/flexnbd-proxy"] do
|
|
||||||
sh "cd tests/acceptance && RUBYOPT='-I.' ruby nbd_scenarios -v"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc "Remove all build targets, binaries and temporary files"
|
|
||||||
maketask :clean
|
|
||||||
|
|
||||||
file "debian/changelog" do
|
|
||||||
FileUtils.mkdir_p "debian"
|
|
||||||
sh "hg log --style=changelog.template > debian/changelog"
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Generate the changelog"
|
|
||||||
task :changelog => "debian/changelog"
|
|
@@ -27,7 +27,7 @@ void nbd_r2h_request( struct nbd_request_raw *from, struct nbd_request * to )
|
|||||||
{
|
{
|
||||||
to->magic = htobe32( from->magic );
|
to->magic = htobe32( from->magic );
|
||||||
to->type = htobe32( from->type );
|
to->type = htobe32( from->type );
|
||||||
memcpy( to->handle, from->handle, 8 );
|
to->handle.w = from->handle.w;
|
||||||
to->from = htobe64( from->from );
|
to->from = htobe64( from->from );
|
||||||
to->len = htobe32( from->len );
|
to->len = htobe32( from->len );
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ void nbd_h2r_request( struct nbd_request * from, struct nbd_request_raw * to )
|
|||||||
{
|
{
|
||||||
to->magic = be32toh( from->magic );
|
to->magic = be32toh( from->magic );
|
||||||
to->type = be32toh( from->type );
|
to->type = be32toh( from->type );
|
||||||
memcpy( to->handle, from->handle, 8 );
|
to->handle.w = from->handle.w;
|
||||||
to->from = be64toh( from->from );
|
to->from = be64toh( from->from );
|
||||||
to->len = be32toh( from->len );
|
to->len = be32toh( from->len );
|
||||||
}
|
}
|
||||||
@@ -46,13 +46,13 @@ void nbd_r2h_reply( struct nbd_reply_raw * from, struct nbd_reply * to )
|
|||||||
{
|
{
|
||||||
to->magic = htobe32( from->magic );
|
to->magic = htobe32( from->magic );
|
||||||
to->error = htobe32( from->error );
|
to->error = htobe32( from->error );
|
||||||
memcpy( to->handle, from->handle, 8 );
|
to->handle.w = from->handle.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to )
|
void nbd_h2r_reply( struct nbd_reply * from, struct nbd_reply_raw * to )
|
||||||
{
|
{
|
||||||
to->magic = be32toh( from->magic );
|
to->magic = be32toh( from->magic );
|
||||||
to->error = be32toh( from->error );
|
to->error = be32toh( from->error );
|
||||||
memcpy( to->handle, from->handle, 8 );
|
to->handle.w = from->handle.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,11 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
typedef union nbd_handle_t {
|
||||||
|
uint8_t b[8];
|
||||||
|
uint64_t w;
|
||||||
|
} nbd_handle_t;
|
||||||
|
|
||||||
/* The _raw types are the types as they appear on the wire. Non-_raw
|
/* The _raw types are the types as they appear on the wire. Non-_raw
|
||||||
* types are in host-format.
|
* types are in host-format.
|
||||||
* Conversion functions are _r2h_ for converting raw to host, and _h2r_
|
* Conversion functions are _r2h_ for converting raw to host, and _h2r_
|
||||||
@@ -39,7 +44,7 @@ struct nbd_init_raw {
|
|||||||
struct nbd_request_raw {
|
struct nbd_request_raw {
|
||||||
__be32 magic;
|
__be32 magic;
|
||||||
__be32 type; /* == READ || == WRITE */
|
__be32 type; /* == READ || == WRITE */
|
||||||
char handle[8];
|
nbd_handle_t handle;
|
||||||
__be64 from;
|
__be64 from;
|
||||||
__be32 len;
|
__be32 len;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
@@ -47,7 +52,7 @@ struct nbd_request_raw {
|
|||||||
struct nbd_reply_raw {
|
struct nbd_reply_raw {
|
||||||
__be32 magic;
|
__be32 magic;
|
||||||
__be32 error; /* 0 = ok, else error */
|
__be32 error; /* 0 = ok, else error */
|
||||||
char handle[8]; /* handle you got from request */
|
nbd_handle_t handle; /* handle you got from request */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +67,7 @@ struct nbd_init {
|
|||||||
struct nbd_request {
|
struct nbd_request {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint32_t type; /* == READ || == WRITE || == DISCONNECT */
|
uint32_t type; /* == READ || == WRITE || == DISCONNECT */
|
||||||
char handle[8];
|
nbd_handle_t handle;
|
||||||
uint64_t from;
|
uint64_t from;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
@@ -70,7 +75,7 @@ struct nbd_request {
|
|||||||
struct nbd_reply {
|
struct nbd_reply {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint32_t error; /* 0 = ok, else error */
|
uint32_t error; /* 0 = ok, else error */
|
||||||
char handle[8]; /* handle you got from request */
|
nbd_handle_t handle; /* handle you got from request */
|
||||||
};
|
};
|
||||||
|
|
||||||
void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to );
|
void nbd_r2h_init( struct nbd_init_raw * from, struct nbd_init * to );
|
||||||
|
@@ -105,9 +105,7 @@ void fill_request(struct nbd_request *request, int type, uint64_t from, uint32_t
|
|||||||
{
|
{
|
||||||
request->magic = htobe32(REQUEST_MAGIC);
|
request->magic = htobe32(REQUEST_MAGIC);
|
||||||
request->type = htobe32(type);
|
request->type = htobe32(type);
|
||||||
uint32_t * randa = (uint32_t*)request->handle;
|
request->handle.w = (((uint64_t)rand()) << 32) | ((uint64_t)rand());
|
||||||
randa[0] = rand();
|
|
||||||
randa[1] = rand();
|
|
||||||
request->from = htobe64(from);
|
request->from = htobe64(from);
|
||||||
request->len = htobe32(len);
|
request->len = htobe32(len);
|
||||||
}
|
}
|
||||||
@@ -127,7 +125,7 @@ void read_reply(int fd, struct nbd_request *request, struct nbd_reply *reply)
|
|||||||
if (reply->error != 0) {
|
if (reply->error != 0) {
|
||||||
error("Server replied with error %d", reply->error);
|
error("Server replied with error %d", reply->error);
|
||||||
}
|
}
|
||||||
if (strncmp(request->handle, reply->handle, 8) != 0) {
|
if (request->handle.w != reply->handle.w) {
|
||||||
error("Did not reply with correct handle");
|
error("Did not reply with correct handle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -100,7 +100,7 @@ int sock_try_bind( int fd, const struct sockaddr* sa )
|
|||||||
{
|
{
|
||||||
int bind_result;
|
int bind_result;
|
||||||
char s_address[256];
|
char s_address[256];
|
||||||
int retry = 1;
|
int retry = 10;
|
||||||
|
|
||||||
sockaddr_address_string( sa, &s_address[0], 256 );
|
sockaddr_address_string( sa, &s_address[0], 256 );
|
||||||
|
|
||||||
@@ -126,8 +126,11 @@ int sock_try_bind( int fd, const struct sockaddr* sa )
|
|||||||
* will cope with it.
|
* will cope with it.
|
||||||
*/
|
*/
|
||||||
case EADDRNOTAVAIL:
|
case EADDRNOTAVAIL:
|
||||||
|
retry--;
|
||||||
|
if (retry) {
|
||||||
debug( "retrying" );
|
debug( "retrying" );
|
||||||
sleep( 1 );
|
sleep( 1 );
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
case EADDRINUSE:
|
case EADDRINUSE:
|
||||||
warn( "%s in use, giving up.", s_address );
|
warn( "%s in use, giving up.", s_address );
|
||||||
|
@@ -709,7 +709,7 @@ void proxy_session( struct proxier* proxy )
|
|||||||
state_started = monotonic_time_ms();
|
state_started = monotonic_time_ms();
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
"State transitition from %s to %s",
|
"State transition from %s to %s",
|
||||||
proxy_session_state_names[old_state],
|
proxy_session_state_names[old_state],
|
||||||
proxy_session_state_names[state]
|
proxy_session_state_names[state]
|
||||||
);
|
);
|
||||||
|
@@ -252,14 +252,14 @@ int client_read_request( struct client * client , struct nbd_request *out_reques
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd_write_reply( int fd, char *handle, int error )
|
int fd_write_reply( int fd, uint64_t handle, int error )
|
||||||
{
|
{
|
||||||
struct nbd_reply reply;
|
struct nbd_reply reply;
|
||||||
struct nbd_reply_raw reply_raw;
|
struct nbd_reply_raw reply_raw;
|
||||||
|
|
||||||
reply.magic = REPLY_MAGIC;
|
reply.magic = REPLY_MAGIC;
|
||||||
reply.error = error;
|
reply.error = error;
|
||||||
memcpy( reply.handle, handle, 8 );
|
reply.handle.w = handle;
|
||||||
|
|
||||||
nbd_h2r_reply( &reply, &reply_raw );
|
nbd_h2r_reply( &reply, &reply_raw );
|
||||||
debug( "Replying with handle=0x%08X, error=%"PRIu32, handle, error );
|
debug( "Replying with handle=0x%08X, error=%"PRIu32, handle, error );
|
||||||
@@ -291,7 +291,7 @@ int fd_write_reply( int fd, char *handle, int error )
|
|||||||
*/
|
*/
|
||||||
int client_write_reply( struct client * client, struct nbd_request *request, int error )
|
int client_write_reply( struct client * client, struct nbd_request *request, int error )
|
||||||
{
|
{
|
||||||
return fd_write_reply( client->socket, request->handle, error);
|
return fd_write_reply( client->socket, request->handle.w, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -412,7 +412,7 @@ int mirror_setup_next_xfer( struct mirror_ctrl *ctrl )
|
|||||||
struct nbd_request req = {
|
struct nbd_request req = {
|
||||||
.magic = REQUEST_MAGIC,
|
.magic = REQUEST_MAGIC,
|
||||||
.type = REQUEST_WRITE,
|
.type = REQUEST_WRITE,
|
||||||
.handle = ".MIRROR.",
|
.handle.b = ".MIRROR.",
|
||||||
.from = current,
|
.from = current,
|
||||||
.len = run
|
.len = run
|
||||||
};
|
};
|
||||||
@@ -568,7 +568,7 @@ static void mirror_read_cb( struct ev_loop *loop, ev_io *w, int revents )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( memcmp( ".MIRROR.", &rsp.handle[0], 8 ) != 0 ) {
|
if ( memcmp( ".MIRROR.", rsp.handle.b, 8 ) != 0 ) {
|
||||||
warn( "Bad handle returned from listener" );
|
warn( "Bad handle returned from listener" );
|
||||||
ev_break( loop, EVBREAK_ONE );
|
ev_break( loop, EVBREAK_ONE );
|
||||||
return;
|
return;
|
||||||
@@ -922,7 +922,7 @@ void* mirror_runner(void* serve_params_uncast)
|
|||||||
* for us ). But if we've failed and are going to retry on the next run, we
|
* for us ). But if we've failed and are going to retry on the next run, we
|
||||||
* must close this socket here to have any chance of it succeeding.
|
* must close this socket here to have any chance of it succeeding.
|
||||||
*/
|
*/
|
||||||
if ( !mirror->client < 0 ) {
|
if ( !(mirror->client < 0) ) {
|
||||||
sock_try_close( mirror->client );
|
sock_try_close( mirror->client );
|
||||||
mirror->client = -1;
|
mirror->client = -1;
|
||||||
}
|
}
|
||||||
|
@@ -255,7 +255,7 @@ int tryjoin_client_thread( struct client_tbl_entry *entry, int (*joinfunc)(pthre
|
|||||||
debug("nbd thread %016x exited (%s) with status %ld",
|
debug("nbd thread %016x exited (%s) with status %ld",
|
||||||
entry->thread,
|
entry->thread,
|
||||||
s_client_address,
|
s_client_address,
|
||||||
(uint64_t)status);
|
(uintptr_t)status);
|
||||||
client_destroy( entry->client );
|
client_destroy( entry->client );
|
||||||
entry->client = NULL;
|
entry->client = NULL;
|
||||||
entry->thread = 0;
|
entry->thread = 0;
|
||||||
|
@@ -32,7 +32,7 @@ module FlexNBD
|
|||||||
txt_lines.each do |line|
|
txt_lines.each do |line|
|
||||||
if line =~ /^#\s*define\s+([A-Z0-9_]+)\s+(\d+)\s*$/
|
if line =~ /^#\s*define\s+([A-Z0-9_]+)\s+(\d+)\s*$/
|
||||||
# Bodge until I can figure out what to do with #ifdefs
|
# Bodge until I can figure out what to do with #ifdefs
|
||||||
const_set($1, $2.to_i) unless constants.include?( $1 )
|
const_set($1, $2.to_i) unless const_defined?( $1 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -3,6 +3,10 @@ require 'flexnbd/fake_source'
|
|||||||
require 'flexnbd/fake_dest'
|
require 'flexnbd/fake_dest'
|
||||||
|
|
||||||
module ProxyTests
|
module ProxyTests
|
||||||
|
def b
|
||||||
|
"\xFF".b
|
||||||
|
end
|
||||||
|
|
||||||
def with_proxied_client( override_size = nil )
|
def with_proxied_client( override_size = nil )
|
||||||
@env.serve1 unless @server_up
|
@env.serve1 unless @server_up
|
||||||
@env.proxy2 unless @proxy_up
|
@env.proxy2 unless @proxy_up
|
||||||
@@ -51,7 +55,7 @@ module ProxyTests
|
|||||||
with_proxied_client do |client|
|
with_proxied_client do |client|
|
||||||
(0..3).each do |n|
|
(0..3).each do |n|
|
||||||
offset = n * 4096
|
offset = n * 4096
|
||||||
client.write(offset, "\xFF" * 4096)
|
client.write(offset, b * 4096)
|
||||||
rsp = client.read_response
|
rsp = client.read_response
|
||||||
|
|
||||||
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
||||||
@@ -60,7 +64,7 @@ module ProxyTests
|
|||||||
|
|
||||||
data = @env.file1.read(offset, 4096)
|
data = @env.file1.read(offset, 4096)
|
||||||
|
|
||||||
assert_equal( ( "\xFF" * 4096 ), data, "Data not written correctly (offset is #{n})" )
|
assert_equal( ( b * 4096 ), data, "Data not written correctly (offset is #{n})" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -107,7 +111,7 @@ module ProxyTests
|
|||||||
|
|
||||||
# The reply should be proxied back to the client.
|
# The reply should be proxied back to the client.
|
||||||
sc2.write_reply( req2[:handle] )
|
sc2.write_reply( req2[:handle] )
|
||||||
sc2.write_data( "\xFF" * 4096 )
|
sc2.write_data( b * 4096 )
|
||||||
|
|
||||||
# Check it to make sure it's correct
|
# Check it to make sure it's correct
|
||||||
rsp = timeout(15) { client.read_response }
|
rsp = timeout(15) { client.read_response }
|
||||||
@@ -116,7 +120,7 @@ module ProxyTests
|
|||||||
assert_equal req1[:handle], rsp[:handle]
|
assert_equal req1[:handle], rsp[:handle]
|
||||||
|
|
||||||
data = client.read_raw( 4096 )
|
data = client.read_raw( 4096 )
|
||||||
assert_equal( ("\xFF" * 4096), data, "Wrong data returned" )
|
assert_equal( (b * 4096), data, "Wrong data returned" )
|
||||||
|
|
||||||
sc2.close
|
sc2.close
|
||||||
server.close
|
server.close
|
||||||
@@ -131,7 +135,7 @@ module ProxyTests
|
|||||||
server, sc1 = maker.value
|
server, sc1 = maker.value
|
||||||
|
|
||||||
# Send the read request to the proxy
|
# Send the read request to the proxy
|
||||||
client.write( 0, ( "\xFF" * 4096 ) )
|
client.write( 0, ( b * 4096 ) )
|
||||||
|
|
||||||
# ensure we're given the read request
|
# ensure we're given the read request
|
||||||
req1 = sc1.read_request
|
req1 = sc1.read_request
|
||||||
@@ -140,7 +144,7 @@ module ProxyTests
|
|||||||
assert_equal 0, req1[:from]
|
assert_equal 0, req1[:from]
|
||||||
assert_equal 4096, req1[:len]
|
assert_equal 4096, req1[:len]
|
||||||
data1 = sc1.read_data( 4096 )
|
data1 = sc1.read_data( 4096 )
|
||||||
assert_equal( ( "\xFF" * 4096 ), data1, "Data not proxied successfully" )
|
assert_equal( ( b * 4096 ), data1, "Data not proxied successfully" )
|
||||||
|
|
||||||
# Kill the server again, now we're sure the read request has been sent once
|
# Kill the server again, now we're sure the read request has been sent once
|
||||||
sc1.close
|
sc1.close
|
||||||
|
@@ -115,6 +115,11 @@ class TestHappyPath < Test::Unit::TestCase
|
|||||||
|
|
||||||
|
|
||||||
def test_write_to_high_block
|
def test_write_to_high_block
|
||||||
|
#
|
||||||
|
# This test does not work on 32 bit platforms.
|
||||||
|
#
|
||||||
|
skip("Not relevant on 32-bit platforms") if ( ["a"].pack("p").size < 8 )
|
||||||
|
|
||||||
# Create a large file, then try to write to somewhere after the 2G boundary
|
# Create a large file, then try to write to somewhere after the 2G boundary
|
||||||
@env.truncate1 "4G"
|
@env.truncate1 "4G"
|
||||||
@env.serve1
|
@env.serve1
|
||||||
|
@@ -6,6 +6,7 @@ class TestServeMode < Test::Unit::TestCase
|
|||||||
|
|
||||||
def setup
|
def setup
|
||||||
super
|
super
|
||||||
|
@b = "\xFF".b
|
||||||
@env = Environment.new
|
@env = Environment.new
|
||||||
@env.writefile1( "0" )
|
@env.writefile1( "0" )
|
||||||
@env.serve1
|
@env.serve1
|
||||||
@@ -53,18 +54,18 @@ class TestServeMode < Test::Unit::TestCase
|
|||||||
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
||||||
assert_equal 0, rsp[:error]
|
assert_equal 0, rsp[:error]
|
||||||
|
|
||||||
client.write( 0, "\xFF" )
|
client.write( 0, @b )
|
||||||
rsp = client.read_response
|
rsp = client.read_response
|
||||||
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
||||||
assert_equal 0, rsp[:error]
|
assert_equal 0, rsp[:error]
|
||||||
|
|
||||||
client.write( 0, "\xFF\xFF" )
|
client.write( 0, @b * 2 )
|
||||||
rsp = client.read_response
|
rsp = client.read_response
|
||||||
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic]
|
||||||
assert_equal 0, rsp[:error]
|
assert_equal 0, rsp[:error]
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal "\xFF\xFF", @env.file1.read( 0, 2 )
|
assert_equal @b * 2, @env.file1.read( 0, 2 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@@ -59,7 +59,7 @@ END_TEST
|
|||||||
START_TEST(test_bit_ranges)
|
START_TEST(test_bit_ranges)
|
||||||
{
|
{
|
||||||
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)];
|
bitfield_word_t buffer[BIT_WORDS_FOR_SIZE(4160)];
|
||||||
uint64_t *longs = (unsigned long*) buffer;
|
uint64_t *longs = (uint64_t *) buffer;
|
||||||
uint64_t i;
|
uint64_t i;
|
||||||
|
|
||||||
memset(buffer, 0, 4160);
|
memset(buffer, 0, 4160);
|
||||||
@@ -67,9 +67,9 @@ START_TEST(test_bit_ranges)
|
|||||||
for (i=0; i<64; i++) {
|
for (i=0; i<64; i++) {
|
||||||
bit_set_range(buffer, i*64, i);
|
bit_set_range(buffer, i*64, i);
|
||||||
fail_unless(
|
fail_unless(
|
||||||
longs[i] == (1UL<<i)-1,
|
longs[i] == (1ULL<<i)-1,
|
||||||
"longs[%ld] = %lx SHOULD BE %lx",
|
"longs[%ld] = %lx SHOULD BE %lx",
|
||||||
i, longs[i], (1L<<i)-1
|
i, longs[i], (1ULL<<i)-1
|
||||||
);
|
);
|
||||||
|
|
||||||
fail_unless(longs[i+1] == 0, "bit_set_range overshot at i=%d", i);
|
fail_unless(longs[i+1] == 0, "bit_set_range overshot at i=%d", i);
|
||||||
|
@@ -66,9 +66,9 @@ START_TEST( test_receive_blocks_until_post )
|
|||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
Suite* acl_suite(void)
|
Suite* mbox_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("acl");
|
Suite *s = suite_create("mbox");
|
||||||
TCase *tc_create = tcase_create("create");
|
TCase *tc_create = tcase_create("create");
|
||||||
TCase *tc_post = tcase_create("post");
|
TCase *tc_post = tcase_create("post");
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ int main(void)
|
|||||||
log_level = 2;
|
log_level = 2;
|
||||||
#endif
|
#endif
|
||||||
int number_failed;
|
int number_failed;
|
||||||
Suite *s = acl_suite();
|
Suite *s = mbox_suite();
|
||||||
SRunner *sr = srunner_create(s);
|
SRunner *sr = srunner_create(s);
|
||||||
srunner_run_all(sr, CK_NORMAL);
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
log_level = 0;
|
log_level = 0;
|
||||||
|
@@ -88,14 +88,14 @@ START_TEST(test_request_handle)
|
|||||||
struct nbd_request_raw request_raw;
|
struct nbd_request_raw request_raw;
|
||||||
struct nbd_request request;
|
struct nbd_request request;
|
||||||
|
|
||||||
memcpy( request_raw.handle, "MYHANDLE", 8 );
|
memcpy( request_raw.handle.b, "MYHANDLE", 8 );
|
||||||
|
|
||||||
nbd_r2h_request( &request_raw, &request );
|
nbd_r2h_request( &request_raw, &request );
|
||||||
memset( request_raw.handle, 0, 8 );
|
request_raw.handle.w = 0;
|
||||||
nbd_h2r_request( &request, &request_raw );
|
nbd_h2r_request( &request, &request_raw );
|
||||||
|
|
||||||
fail_unless( memcmp( request.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
|
fail_unless( memcmp( request.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
|
||||||
fail_unless( memcmp( request_raw.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
|
fail_unless( memcmp( request_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -170,14 +170,14 @@ START_TEST(test_reply_handle)
|
|||||||
struct nbd_reply_raw reply_raw;
|
struct nbd_reply_raw reply_raw;
|
||||||
struct nbd_reply reply;
|
struct nbd_reply reply;
|
||||||
|
|
||||||
memcpy( reply_raw.handle, "MYHANDLE", 8 );
|
memcpy( reply_raw.handle.b, "MYHANDLE", 8 );
|
||||||
|
|
||||||
nbd_r2h_reply( &reply_raw, &reply );
|
nbd_r2h_reply( &reply_raw, &reply );
|
||||||
memset( reply_raw.handle, 0, 8 );
|
reply_raw.handle.w = 0;
|
||||||
nbd_h2r_reply( &reply, &reply_raw );
|
nbd_h2r_reply( &reply, &reply_raw );
|
||||||
|
|
||||||
fail_unless( memcmp( reply.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
|
fail_unless( memcmp( reply.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied." );
|
||||||
fail_unless( memcmp( reply_raw.handle, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
|
fail_unless( memcmp( reply_raw.handle.b, "MYHANDLE", 8 ) == 0, "The handle was not copied back." );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
@@ -188,14 +188,15 @@ START_TEST( test_convert_from )
|
|||||||
* nbd_request_raw */
|
* nbd_request_raw */
|
||||||
struct nbd_request_raw request_raw;
|
struct nbd_request_raw request_raw;
|
||||||
struct nbd_request request;
|
struct nbd_request request;
|
||||||
char readbuf[] = {0x80, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
memcpy( &request_raw.from, readbuf, 8 );
|
uint64_t target = 0x8000000000000000;
|
||||||
|
|
||||||
|
/* this is stored big-endian */
|
||||||
|
request_raw.from = htobe64(target);
|
||||||
|
|
||||||
|
/* We expect this to convert big-endian to the host format */
|
||||||
nbd_r2h_request( &request_raw, &request );
|
nbd_r2h_request( &request_raw, &request );
|
||||||
|
|
||||||
uint64_t target = 1;
|
|
||||||
target <<= 63;
|
|
||||||
fail_unless( target == request.from, "from was wrong" );
|
fail_unless( target == request.from, "from was wrong" );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
|
|
||||||
int fd_read_request( int, struct nbd_request_raw *);
|
int fd_read_request( int, struct nbd_request_raw *);
|
||||||
int fd_write_reply( int, char *, int );
|
int fd_write_reply( int, uint64_t, int );
|
||||||
|
|
||||||
int marker;
|
int marker;
|
||||||
|
|
||||||
@@ -46,8 +46,7 @@ void * responder( void *respond_uncast )
|
|||||||
struct respond * resp = (struct respond *) respond_uncast;
|
struct respond * resp = (struct respond *) respond_uncast;
|
||||||
int sock_fd = resp->sock_fds[1];
|
int sock_fd = resp->sock_fds[1];
|
||||||
struct nbd_request_raw request_raw;
|
struct nbd_request_raw request_raw;
|
||||||
char wrong_handle[] = "WHOOPSIE";
|
uint64_t wrong_handle = 0x80;
|
||||||
|
|
||||||
|
|
||||||
if( fd_read_request( sock_fd, &request_raw ) == -1){
|
if( fd_read_request( sock_fd, &request_raw ) == -1){
|
||||||
fprintf(stderr, "Problem with fd_read_request\n");
|
fprintf(stderr, "Problem with fd_read_request\n");
|
||||||
@@ -57,7 +56,7 @@ void * responder( void *respond_uncast )
|
|||||||
fd_write_reply( sock_fd, wrong_handle, 0 );
|
fd_write_reply( sock_fd, wrong_handle, 0 );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fd_write_reply( sock_fd, resp->received.handle, 0 );
|
fd_write_reply( sock_fd, resp->received.handle.w, 0 );
|
||||||
}
|
}
|
||||||
write( sock_fd, "12345678", 8 );
|
write( sock_fd, "12345678", 8 );
|
||||||
}
|
}
|
||||||
@@ -150,7 +149,7 @@ END_TEST
|
|||||||
|
|
||||||
Suite* readwrite_suite(void)
|
Suite* readwrite_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("acl");
|
Suite *s = suite_create("readwrite");
|
||||||
TCase *tc_transfer = tcase_create("entrust");
|
TCase *tc_transfer = tcase_create("entrust");
|
||||||
TCase *tc_disconnect = tcase_create("disconnect");
|
TCase *tc_disconnect = tcase_create("disconnect");
|
||||||
|
|
||||||
|
@@ -141,9 +141,9 @@ START_TEST( test_fatal_doesnt_call_handler )
|
|||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
Suite* error_suite(void)
|
Suite* util_suite(void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create("error");
|
Suite *s = suite_create("util");
|
||||||
TCase *tc_process = tcase_create("process");
|
TCase *tc_process = tcase_create("process");
|
||||||
TCase *tc_handler = tcase_create("handler");
|
TCase *tc_handler = tcase_create("handler");
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ Suite* error_suite(void)
|
|||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int number_failed;
|
int number_failed;
|
||||||
Suite *s = error_suite();
|
Suite *s = util_suite();
|
||||||
SRunner *sr = srunner_create(s);
|
SRunner *sr = srunner_create(s);
|
||||||
srunner_run_all(sr, CK_NORMAL);
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
number_failed = srunner_ntests_failed(sr);
|
number_failed = srunner_ntests_failed(sr);
|
||||||
|
Reference in New Issue
Block a user