From 17719647db4aa70b2e280856a1596c1937333fff Mon Sep 17 00:00:00 2001 From: yoe Date: Thu, 30 Mar 2006 20:11:21 +0000 Subject: [PATCH] r153: Add support for persistent connections (reconnecting if the connection drops for some unknown reason) --- nbd-client.c | 208 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 129 insertions(+), 79 deletions(-) diff --git a/nbd-client.c b/nbd-client.c index 8330906..ffda42c 100644 --- a/nbd-client.c +++ b/nbd-client.c @@ -37,8 +37,7 @@ #define MY_NAME "nbd_client" #include "cliserv.h" -int opennet(char *name, int port) -{ +int opennet(char *name, int port) { int sock; struct sockaddr_in xaddrin; int xaddrinlen = sizeof(xaddrin); @@ -61,77 +60,9 @@ int opennet(char *name, int port) return sock; } -int main(int argc, char *argv[]) -{ - int port, sock, nbd; +u64 negotiate(int sock, int blocksize) { u64 magic, size64; - unsigned long size; char buf[256] = "\0\0\0\0\0\0\0\0\0"; - int blocksize=1024; - char *hostname; - int swap=0; - - logging(); - - if (argc < 3) { - errmsg: - fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION); - fprintf(stderr, "Usage: nbd-client [bs=blocksize] host port nbd_device [-swap]\n"); - fprintf(stderr, "Or : nbd-client -d nbd_device\n"); - fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n"); - fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */ - fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n"); - fprintf(stderr, "blocksizes other than 1024 without patches\n"); - return 1; - } - - ++argv; --argc; /* skip programname */ - - if (strcmp(argv[0], "-d")==0) { - nbd = open(argv[1], O_RDWR); - if (nbd < 0) - err("Can not open NBD: %m"); - printf("Disconnecting: que, "); - if (ioctl(nbd, NBD_CLEAR_QUE)< 0) - err("Ioctl failed: %m\n"); - printf("disconnect, "); -#ifdef NBD_DISCONNECT - if (ioctl(nbd, NBD_DISCONNECT)<0) - err("Ioctl failed: %m\n"); - printf("sock, "); -#else - fprintf(stderr, "Can't disconnect: I was not compiled with disconnect support!\n" ); - exit(1); -#endif - if (ioctl(nbd, NBD_CLEAR_SOCK)<0) - err("Ioctl failed: %m\n"); - printf("done\n"); - return 0; - } - - if (strncmp(argv[0], "bs=", 3)==0) { - blocksize=atoi(argv[0]+3); - ++argv; --argc; /* skip blocksize */ - } - - if (argc==0) goto errmsg; - hostname=argv[0]; - ++argv; --argc; /* skip hostname */ - - if (argc==0) goto errmsg; - port = atoi(argv[0]); - ++argv; --argc; /* skip port */ - - if (argc==0) goto errmsg; - sock = opennet(hostname, port); - nbd = open(argv[0], O_RDWR); - if (nbd < 0) - err("Can not open NBD: %m"); - ++argv; --argc; /* skip device */ - - if (argc>1) goto errmsg; - if (argc!=0) swap=1; - argv=NULL; argc=0; /* don't use it later suddenly */ printf("Negotiation: "); if (read(sock, buf, 8) < 0) @@ -170,6 +101,12 @@ int main(int argc, char *argv[]) err("Failed/4: %m\n"); printf("\n"); + return size64; +} + +void setsizes(int nbd, u64 size64, int blocksize) { + unsigned long size; + #ifdef NBD_SET_SIZE_BLOCKS if (size64/blocksize > (~0UL >> 1)) err("Device too large.\n"); @@ -180,7 +117,7 @@ int main(int argc, char *argv[]) size = (unsigned long)(size64/blocksize); if ((er = ioctl(nbd, NBD_SET_SIZE_BLOCKS, size)) < 0) err("Ioctl/1.1b failed: %m\n"); -fprintf(stderr, "bs=%d, sz=%lu\n", blocksize, size); + fprintf(stderr, "bs=%d, sz=%lu\n", blocksize, size); } #else if (size64 > (~0UL >> 1)) { @@ -188,13 +125,16 @@ fprintf(stderr, "bs=%d, sz=%lu\n", blocksize, size); } else { size = (unsigned long)size64; if (ioctl(nbd, NBD_SET_SIZE, size) < 0) - err("Ioctl/1 failed: %m\n"); + err("Ioctl NBD_SET_SIZE failed: %m\n"); } #endif ioctl(nbd, NBD_CLEAR_SOCK); +} + +void finish_sock(int sock, int nbd, int swap) { if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) - err("Ioctl/2 failed: %m\n"); + err("Ioctl NBD_SET_SOCK failed: %m\n"); #ifndef SO_SWAPPING if (swap) @@ -204,17 +144,127 @@ fprintf(stderr, "bs=%d, sz=%lu\n", blocksize, size); if (setsockopt(sock, SOL_SOCKET, SO_SWAPPING, &one, sizeof(int)) < 0) err("Could not enable swapping: %m"); #endif +} + +int main(int argc, char *argv[]) { + int port, sock, nbd; + int blocksize=1024; + char *hostname; + int swap=0; + int cont=0; + u64 size64; + + logging(); + + if (argc < 3) { + errmsg: + fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION); + fprintf(stderr, "Usage: nbd-client [bs=blocksize] host port nbd_device [-swap] [-persist]\n"); + fprintf(stderr, "Or : nbd-client -d nbd_device\n"); + fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n"); + fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */ + fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n"); + fprintf(stderr, "blocksizes other than 1024 without patches\n"); + return 1; + } + + ++argv; --argc; /* skip programname */ + + if (strcmp(argv[0], "-d")==0) { + nbd = open(argv[1], O_RDWR); + if (nbd < 0) + err("Can not open NBD: %m"); + printf("Disconnecting: que, "); + if (ioctl(nbd, NBD_CLEAR_QUE)< 0) + err("Ioctl failed: %m\n"); + printf("disconnect, "); +#ifdef NBD_DISCONNECT + if (ioctl(nbd, NBD_DISCONNECT)<0) + err("Ioctl failed: %m\n"); + printf("sock, "); +#else + fprintf(stderr, "Can't disconnect: I was not compiled with disconnect support!\n" ); + exit(1); +#endif + if (ioctl(nbd, NBD_CLEAR_SOCK)<0) + err("Ioctl failed: %m\n"); + printf("done\n"); + return 0; + } + if (strncmp(argv[0], "bs=", 3)==0) { + blocksize=atoi(argv[0]+3); + ++argv; --argc; /* skip blocksize */ + } + + if (argc==0) goto errmsg; + hostname=argv[0]; + ++argv; --argc; /* skip hostname */ + + if (argc==0) goto errmsg; + port = atoi(argv[0]); + ++argv; --argc; /* skip port */ + + if (argc==0) goto errmsg; + sock = opennet(hostname, port); + nbd = open(argv[0], O_RDWR); + if (nbd < 0) + err("Can not open NBD: %m"); + ++argv; --argc; /* skip device */ + + if (argc>2) goto errmsg; + if (argc!=0) { + if(strncmp(argv[0], "-swap", 5)==0) { + swap=1; + ++argv;--argc; + } + } + if (argc!=0) { + if(strncmp(argv[0], "-persist", 8)==0) { + cont=1; + ++argv;--argc; + } + } + argv=NULL; argc=0; /* don't use it later suddenly */ + + size64 = negotiate(sock, blocksize); + setsizes(nbd, size64, blocksize); + finish_sock(sock, nbd, swap); + /* Go daemon */ chdir("/"); if (fork()) exit(0); - - if (ioctl(nbd, NBD_DO_IT) < 0) - fprintf(stderr, "Kernel call returned: %m"); - else - fprintf(stderr, "Kernel call returned."); + + do { + if (ioctl(nbd, NBD_DO_IT) < 0) { + fprintf(stderr, "Kernel call returned: %m"); + if(errno==EBADR) { + /* The user probably did 'nbd-client -d' on us. + * quit */ + cont=0; + } else { + if(cont) { + fprintf(stderr, " Reconnecting\n"); + close(sock); close(nbd); + sock = opennet(hostname, port); + nbd = open(argv[0], O_RDWR); + if(size64!=negotiate(sock,blocksize)) { + err("Size of the device changed. Bye"); + } + setsizes(nbd, size64, blocksize); + finish_sock(sock,nbd,swap); + } + } + } else { + /* We're on 2.4. It's not clearly defined what exactly + * happened at this point. Probably best to quit, now + */ + fprintf(stderr, "Kernel call returned."); + cont=0; + } + } while(cont); printf("Closing: que, "); ioctl(nbd, NBD_CLEAR_QUE); printf("sock, "); -- 1.7.10.4