29 #include <sys/types.h>
30 #include <sys/socket.h>
38 #include <netinet/in.h>
41 #define MY_NAME "nbd-tester-client"
130 g_warning(
"addtail found list tail has a next pointer");
137 g_warning(
"addtail found no list tail but a list head");
174 g_warning(
"addtail found list tail has a next pointer");
181 g_warning(
"addtail found no list tail but a list head");
193 uint64_t
size = 64*1024;
194 struct chunk * pchunk;
200 uint64_t towrite =
len;
213 if ((NULL == (buf = malloc(size))) || (NULL == (pchunk = calloc(1,
sizeof(
struct chunk))))) {
214 g_critical(
"Out of memory");
231 struct chunk * pchunk = NULL;
267 #define TEST_WRITE (1<<0)
268 #define TEST_FLUSH (1<<1)
272 if (x->tv_usec < y->tv_usec) {
273 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
274 y->tv_usec -= 1000000 * nsec;
278 if (x->tv_usec - y->tv_usec > 1000000) {
279 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
280 y->tv_usec += 1000000 * nsec;
284 result->tv_sec = x->tv_sec - y->tv_sec;
285 result->tv_usec = x->tv_usec - y->tv_usec;
287 return x->tv_sec < y->tv_sec;
293 return r.tv_sec * 1.0 + r.tv_usec/1000000.0;
301 if((res=read(f, buf, len)) <=0) {
319 if((res=write(f, buf, len)) <=0) {
332 #define READ_ALL_ERRCHK(f, buf, len, whereto, errmsg...) if((read_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); goto whereto; }
333 #define READ_ALL_ERR_RT(f, buf, len, whereto, rval, errmsg...) if((read_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); retval = rval; goto whereto; }
335 #define WRITE_ALL_ERRCHK(f, buf, len, whereto, errmsg...) if((write_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); goto whereto; }
336 #define WRITE_ALL_ERR_RT(f, buf, len, whereto, rval, errmsg...) if((write_all(f, buf, len))<=0) { snprintf(errstr, errstr_len, ##errmsg); retval = rval; goto whereto; }
340 struct hostent *host;
341 struct sockaddr_in addr;
350 if((sock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0) {
355 if(!(host=gethostbyname(hostname))) {
359 addr.sin_family=AF_INET;
360 addr.sin_port=htons(port);
361 addr.sin_addr.s_addr=*((
int *) host->h_addr);
362 if((connect(sock, (
struct sockaddr *)&addr,
sizeof(addr))<0)) {
379 READ_ALL_ERRCHK(sock, &tmp64,
sizeof(tmp64), err_open,
"Could not read cliserv_magic: %s", strerror(errno));
381 if(tmp64 != mymagic) {
390 READ_ALL_ERRCHK(sock, buf, 128, err_open,
"Could not read data: %s", strerror(errno));
394 READ_ALL_ERRCHK(sock, buf,
sizeof(uint16_t), err_open,
"Could not read reserved field: %s", strerror(errno));
396 WRITE_ALL_ERRCHK(sock, &tmp32,
sizeof(tmp32), err_open,
"Could not write reserved field: %s", strerror(errno));
399 WRITE_ALL_ERRCHK(sock, &tmp64,
sizeof(tmp64), err_open,
"Could not write magic: %s", strerror(errno));
402 WRITE_ALL_ERRCHK(sock, &tmp32,
sizeof(tmp32), err_open,
"Could not write option: %s", strerror(errno));
403 tmp32 = htonl((uint32_t)strlen(name));
404 WRITE_ALL_ERRCHK(sock, &tmp32,
sizeof(tmp32), err_open,
"Could not write name length: %s", strerror(errno));
405 WRITE_ALL_ERRCHK(sock, name, strlen(name), err_open,
"Could not write name:: %s", strerror(errno));
409 READ_ALL_ERRCHK(sock, &flags,
sizeof(uint16_t), err_open,
"Could not read flags: %s", strerror(errno));
410 flags = ntohs(flags);
411 *serverflags = flags;
412 READ_ALL_ERRCHK(sock, buf, 124, err_open,
"Could not read reserved zeroes: %s", strerror(errno));
430 memcpy(&(req.
handle), &(counter),
sizeof(counter));
434 if(write(sock, &req,
sizeof(req))<0) {
435 snprintf(
errstr,
errstr_len,
"Could not write to socket: %s", strerror(errno));
440 snprintf(
errstr,
errstr_len,
"Could not close socket: %s", strerror(errno));
445 g_critical(
"Your compiler is on crack!");
456 READ_ALL_ERR_RT(sock, &rep,
sizeof(rep), end, -1,
"Could not read reply header: %s", strerror(errno));
460 snprintf(
errstr,
errstr_len,
"Received package with incorrect reply_magic. Index of sent packages is %lld (0x%llX), received handle is %lld (0x%llX). Received magic 0x%lX, expected 0x%lX", (
long long int)curhandle, (
long long unsigned int)curhandle, (
long long int)*((u64*)rep.
handle), (
long long unsigned int)*((u64*)rep.
handle), (
long unsigned int)rep.
magic, (
long unsigned int)
NBD_REPLY_MAGIC);
465 snprintf(
errstr,
errstr_len,
"Received error from server: %ld (0x%lX). Handle is %lld (0x%llX).", (
long int)rep.
error, (
long unsigned int)rep.
error, (
long long int)(*((u64*)rep.
handle)), (
long long unsigned int)*((u64*)rep.
handle));
470 READ_ALL_ERR_RT(sock, &buf, datasize, end, -1,
"Could not read data: %s", strerror(errno));
477 char sock_is_open,
char close_sock,
int testflags) {
484 char buf[((1024*1024)+
sizeof(
struct nbd_request)/2)<<1];
490 g_warning(
"Could not open socket: %s",
errstr);
497 req.
len=htonl(1024*1024);
498 memcpy(&(req.
handle),&i,
sizeof(i));
500 WRITE_ALL_ERR_RT(sock, &req,
sizeof(req),
err, -1,
"Could not write request: %s", strerror(errno));
501 printf(
"%d: testing oversized request: %d: ", getpid(), ntohl(req.
len));
514 WRITE_ALL_ERR_RT(sock, &req,
sizeof(req),
err, -1,
"Could not write request: %s", strerror(errno));
515 printf(
"%d: testing oversized request: %d: ", getpid(), ntohl(req.
len));
519 printf(
"Received expected error\n");
527 req.
len = htonl(ntohl(req.
len) << 1);
528 WRITE_ALL_ERR_RT(sock, &req,
sizeof(req),
err, -1,
"Could not write request: %s", strerror(errno));
529 printf(
"%d: testing oversized request: %d: ", getpid(), ntohl(req.
len));
537 if((rep.
error && !got_err) || (!rep.
error && got_err)) {
538 printf(
"Received unexpected error\n");
546 char sock_is_open,
char close_sock,
int testflags) {
553 struct timeval start;
557 char speedchar[2] = {
'\0',
'\0' };
560 signed int do_write=TRUE;
561 pid_t mypid = getpid();
567 memset (writebuf,
'X', 1024);
571 g_warning(
"Could not open socket: %s",
errstr);
578 snprintf(
errstr,
errstr_len,
"Server did not supply flush capability flags");
584 if(gettimeofday(&start, NULL)<0) {
586 snprintf(
errstr,
errstr_len,
"Could not measure start time: %s", strerror(errno));
589 for(i=0;i+1024<=
size;i+=1024) {
591 int sendfua = (testflags &
TEST_FLUSH) && (((i>>10) & 15) == 3);
592 int sendflush = (testflags &
TEST_FLUSH) && (((i>>10) & 15) == 11);
596 memcpy(&(req.
handle),&i,
sizeof(i));
598 if (
write_all(sock, &req,
sizeof(req)) <0) {
602 if (testflags & TEST_WRITE) {
603 if (
write_all(sock, writebuf, 1024) <0) {
608 printf(
"%d: Requests(+): %d\r", (
int)mypid, ++requests);
610 long long int j = i ^ (1LL<<63);
612 memcpy(&(req.
handle),&j,
sizeof(j));
614 if (
write_all(sock, &req,
sizeof(req)) <0) {
618 printf(
"%d: Requests(+): %d\r", (
int)mypid, ++requests);
626 select(sock+1, &set, NULL, NULL, &tv);
627 if(FD_ISSET(sock, &set)) {
634 printf(
"%d: Requests(-): %d\r", (
int)mypid, --requests);
636 }
while FD_ISSET(sock, &set);
643 do_write=select(sock+1,NULL,&set,NULL,&tv);
644 if(!do_write) printf(
"Select finished\n");
657 select(sock+1, &set, NULL, NULL, &tv);
658 if(FD_ISSET(sock, &set)) {
662 printf(
"%d: Requests(-): %d\r", (
int)mypid, --requests);
666 if(gettimeofday(&stop, NULL)<0) {
668 snprintf(
errstr,
errstr_len,
"Could not measure end time: %s", strerror(errno));
685 g_message(
"%d: Throughput %s test (%s flushes) complete. Took %.3f seconds to complete, %.3f%sib/s", (
int)getpid(), (testflags & TEST_WRITE)?
"write":
"read", (testflags & TEST_FLUSH)?
"with":
"without", timespan, speed, speedchar);
700 static inline void makebuf(
char *buf, uint64_t seq, uint64_t blknum) {
701 uint64_t x = ((uint64_t)blknum) ^ (seq << 32) ^ (seq >> 32);
702 uint64_t* p = (uint64_t*)buf;
708 for (i = 0; i<512/
sizeof(uint64_t); i++) {
711 x+=0xFEEDA1ECDEADBEEFULL+i+(((uint64_t)i)<<56);
713 x = x ^ (x<<s) ^ (x>>(64-s)) ^ 0xAA55AA55AA55AA55ULL ^ seq;
717 static inline int checkbuf(
char *buf, uint64_t seq, uint64_t blknum) {
719 makebuf((
char *)cmp, seq, blknum);
720 return memcmp(cmp, buf, 512)?-1:0;
725 #ifdef DEBUG_COMMANDS
726 command=ntohl(command);
730 ctext=
"NBD_CMD_READ";
733 ctext=
"NBD_CMD_WRITE";
736 ctext=
"NBD_CMD_DISC";
739 ctext=
"NBD_CMD_FLUSH";
745 printf(
"%s: %s [%s] (0x%08x)\n",
759 for (i= 1 ; i<=5; i++)
760 handle ^= random() ^ (handle << 15);
761 }
while (g_hash_table_lookup(phash, &handle));
766 char sock_is_open,
char close_sock,
int testflags) {
771 struct timeval start;
775 char speedchar[2] = {
'\0',
'\0' };
780 char *blkhashname=NULL;
781 struct blkitem *blkhash = NULL;
784 uint64_t processed=0;
787 int readtransactionfile = 1;
789 struct rclist txqueue={NULL, NULL, 0};
790 struct rclist inflight={NULL, NULL, 0};
793 GHashTable *handlehash = g_hash_table_new(g_int64_hash, g_int64_equal);
798 g_warning(
"Could not open socket: %s",
errstr);
806 g_warning(
"Server flags do not support FLUSH and FUA - these may error");
809 blkhashname=strdup(
"/tmp/blkarray-XXXXXX");
810 if (!blkhashname || (-1 == (blkhashfd = mkstemp(blkhashname)))) {
811 g_warning(
"Could not open temp file: %s", strerror(errno));
817 if (-1 == (blkhashfd = open(blkhashname=strdup(tmpnam(NULL)),
819 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))) {
820 g_warning(
"Could not open temp file: %s", strerror(errno));
826 if (-1 == unlink(blkhashname)) {
827 g_warning(
"Could not unlink temp file: %s", strerror(errno));
832 if (-1 == lseek(blkhashfd, (off_t)((
size>>9)*
sizeof(
struct blkitem)), SEEK_SET)) {
833 g_warning(
"Could not llseek temp file: %s", strerror(errno));
838 if (-1 == write(blkhashfd,
"\0", 1)) {
839 g_warning(
"Could not write temp file: %s", strerror(errno));
844 if (NULL == (blkhash = mmap(NULL,
846 PROT_READ | PROT_WRITE,
850 g_warning(
"Could not mmap temp file: %s", strerror(errno));
857 g_warning(
"Could open log file: %s", strerror(errno));
862 if(gettimeofday(&start, NULL)<0) {
864 snprintf(
errstr,
errstr_len,
"Could not measure start time: %s", strerror(errno));
881 if (readtransactionfile)
882 FD_SET(logfd, &rset);
889 ret = select(1+((sock>logfd)?sock:logfd), &rset, &wset, NULL, &tv);
895 g_warning(
"Could not mmap temp file: %s",
errstr);
902 if (FD_ISSET(logfd, &rset)) {
909 "Could not read transaction log: %s",
911 magic = ntohl(magic);
914 if (NULL == (prc = calloc(1,
sizeof(
struct reqcontext)))) {
920 sizeof(magic)+(
char *)&(prc->
req),
923 "Could not read transaction log: %s",
932 readtransactionfile = 0;
942 sizeof(magic)+(
char *)(&rep),
945 "Could not read transaction log: %s",
950 snprintf(
errstr,
errstr_len,
"Transaction log file contained errored transaction");
965 if (FD_ISSET(sock, &wset))
967 if ((!(txqueue.
head) && !(txbuf.
head)) || blocked)
968 g_warning(
"Socket write FD set but we shouldn't have been interested");
971 if (!blocked && !(txbuf.
head) && (NULL != (prc = txqueue.
head)))
975 g_warning(
"Asked to write a request without a magic number");
979 command = ntohl(prc->
req.
type);
981 len = ntohl(prc->
req.
len);
996 uint64_t blknum = cfrom>>9;
999 (
long long int) cfrom, (
long long int)
size);
1002 if (blkhash[blknum].inflightw ||
1003 (blkhash[blknum].inflightr &&
1022 g_hash_table_insert(handlehash, prc->
req.
handle, prc);
1028 uint64_t blknum = from>>9;
1032 (
long long int) from, (
long long int)
size);
1046 uint64_t blknum = from>>9;
1049 (
long long int) from, (
long long int)
size);
1074 snprintf(
errstr,
errstr_len,
"Failed to write to socket buffer: %s", strerror(errno));
1081 if(FD_ISSET(sock, &rset)) {
1089 "Could not read from server socket: %s",
1105 memcpy(&handle,rep.
handle,8);
1106 prc = g_hash_table_lookup(handlehash, &handle);
1109 snprintf(
errstr,
errstr_len,
"Unrecognised handle in reply: 0x%llX", *(
long long unsigned int*)(rep.
handle));
1112 if (!g_hash_table_remove(handlehash, &handle)) {
1114 snprintf(
errstr,
errstr_len,
"Could not remove handle from hash: 0x%llX", *(
long long unsigned int*)(rep.
handle));
1125 command = ntohl(prc->
req.
type);
1127 len = ntohl(prc->
req.
len);
1132 uint64_t blknum = from>>9;
1136 (
long long int) from, (
long long int)
size);
1143 "Could not read data: %s",
1145 if (--(blkhash[blknum].inflightr) <0 ) {
1146 snprintf(
errstr,
errstr_len,
"Received a read reply for offset %llx when not in flight",
1147 (
long long int) from);
1151 if (
checkbuf(dbuf, blkhash[blknum].seq, blknum)) {
1153 snprintf(
errstr,
errstr_len,
"Bad reply data: I wanted blk %08x, seq %08x but I got (at a guess) blk %08x, seq %08x",
1154 (
unsigned int) blknum,
1155 blkhash[blknum].seq,
1156 ((uint32_t *)(dbuf))[0],
1157 ((uint32_t *)(dbuf))[1]
1169 uint64_t blknum = from>>9;
1170 if (--(blkhash[blknum].inflightw) <0 ) {
1171 snprintf(
errstr,
errstr_len,
"Received a write reply for offset %llx when not in flight",
1172 (
long long int) from);
1175 blkhash[blknum].
seq=(uint32_t)(prc->
seq);
1190 if (!(printer++ % 1000) || !(readtransactionfile || txqueue.
numitems || inflight.
numitems) )
1191 printf(
"%d: Seq %08lld Queued: %08d Inflight: %08d Done: %08lld\r",
1193 (
long long int) seq,
1196 (
long long int) processed);
1202 if (gettimeofday(&stop, NULL)<0) {
1204 snprintf(
errstr,
errstr_len,
"Could not measure end time: %s", strerror(errno));
1208 speed=xfer/timespan;
1221 g_message(
"%d: Integrity %s test complete. Took %.3f seconds to complete, %.3f%sib/s", (
int)getpid(), (testflags &
TEST_WRITE)?
"write":
"read", timespan, speed, speedchar);
1228 if (
size && blkhash)
1229 munmap(blkhash, (
size>>9)*
sizeof(
struct blkitem));
1231 if (blkhashfd != -1)
1243 g_hash_table_destroy(handlehash);
1249 static int nonopt=0;
1253 *hostname=g_strdup(opt);
1257 *p=(strtol(opt, NULL, 0));
1258 if(*p==LONG_MIN||*p==LONG_MAX) {
1259 g_critical(
"Could not parse port number: %s", strerror(errno));
1266 typedef int (*
testfunc)(gchar*, int,
char*, int, char, char, int);
1279 signal (SIGPIPE, SIG_IGN);
1282 g_message(
"%d: Not enough arguments", (
int)getpid());
1283 g_message(
"%d: Usage: %s <hostname> <port>", (
int)getpid(), argv[0]);
1284 g_message(
"%d: Or: %s <hostname> -N <exportname> [<port>]", (
int)getpid(), argv[0]);
1288 while((c=getopt(argc, argv,
"-N:t:owfil"))>=0) {
1294 name=g_strdup(optarg);
1320 while(optind < argc) {
1324 if(test(hostname, (
int)p, name, sock, FALSE, TRUE, testflags)<0) {
1325 g_warning(
"Could not run test: %s",
errstr);
void chunklist_addtail(struct chunklist *l, struct chunk *p)
#define READ_ALL_ERRCHK(f, buf, len, whereto, errmsg...)
double timeval_diff_to_double(struct timeval *x, struct timeval *y)
int throughput_test(gchar *hostname, int port, char *name, int sock, char sock_is_open, char close_sock, int testflags)
#define NBD_FLAG_SEND_FUA
static gchar * transactionlog
static gchar errstr[1024]
static void makebuf(char *buf, uint64_t seq, uint64_t blknum)
static void dumpcommand(char *text, uint32_t command)
void setmysockopt(int sock)
void handle_nonopt(char *opt, gchar **hostname, long int *p)
void chunklist_unlink(struct chunklist *l, struct chunk *p)
int setup_connection(gchar *hostname, int port, gchar *name, CONNECTION_TYPE ctype, int *serverflags)
#define NBD_FLAG_SEND_FLUSH
#define NBD_OPT_EXPORT_NAME
int read_packet_check_header(int sock, size_t datasize, long long int curhandle)
int main(int argc, char **argv)
void rclist_unlink(struct rclist *l, struct reqcontext *p)
int integrity_test(gchar *hostname, int port, char *name, int sock, char sock_is_open, char close_sock, int testflags)
static int read_all(int f, void *buf, size_t len)
void err(const char *s) G_GNUC_NORETURN
int oversize_test(gchar *hostname, int port, char *name, int sock, char sock_is_open, char close_sock, int testflags)
int(* testfunc)(gchar *, int, char *, int, char, char, int)
#define READ_ALL_ERR_RT(f, buf, len, whereto, rval, errmsg...)
#define NBD_CMD_MASK_COMMAND
int close_connection(int sock, CLOSE_TYPE type)
#define WRITE_ALL_ERR_RT(f, buf, len, whereto, rval, errmsg...)
int writebuffer(int fd, struct chunklist *l)
#define WRITE_ALL_ERRCHK(f, buf, len, whereto, errmsg...)
#define NBD_REQUEST_MAGIC
uint64_t getrandomhandle(GHashTable *phash)
void rclist_addtail(struct rclist *l, struct reqcontext *p)
static int checkbuf(char *buf, uint64_t seq, uint64_t blknum)
void addbuffer(struct chunklist *l, void *data, uint64_t len)
static int write_all(int f, void *buf, size_t len)
static const int errstr_len
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)