Diff for /qemu/qemu-nbd.c between versions 1.1.1.6 and 1.1.1.7

version 1.1.1.6, 2018/04/24 18:56:11 version 1.1.1.7, 2018/04/24 19:17:15
Line 16 Line 16
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.   *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */   */
   
 #include <qemu-common.h>  #include "qemu-common.h"
 #include "block_int.h"  #include "block_int.h"
 #include "nbd.h"  #include "nbd.h"
   
Line 31 Line 31
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <signal.h>  #include <signal.h>
 #include <libgen.h>  #include <libgen.h>
   #include <pthread.h>
   
 #define SOCKET_PATH    "/var/lock/qemu-nbd-%s"  #define SOCKET_PATH    "/var/lock/qemu-nbd-%s"
   
 #define NBD_BUFFER_SIZE (1024*1024)  #define NBD_BUFFER_SIZE (1024*1024)
   
   static int sigterm_wfd;
 static int verbose;  static int verbose;
   static char *device;
   static char *srcpath;
   static char *sockpath;
   
 static void usage(const char *name)  static void usage(const char *name)
 {  {
Line 163  static int find_partition(BlockDriverSta Line 168  static int find_partition(BlockDriverSta
     return -1;      return -1;
 }  }
   
 static void show_parts(const char *device)  static void termsig_handler(int signum)
 {  {
     if (fork() == 0) {      static int sigterm_reported;
         int nbd;      if (!sigterm_reported) {
           sigterm_reported = (write(sigterm_wfd, "", 1) == 1);
       }
   }
   
         /* linux just needs an open() to trigger  static void *show_parts(void *arg)
          * the partition table update  {
          * but remember to load the module with max_part != 0 :      int nbd;
          *     modprobe nbd max_part=63  
          */      /* linux just needs an open() to trigger
         nbd = open(device, O_RDWR);       * the partition table update
         if (nbd != -1)       * but remember to load the module with max_part != 0 :
               close(nbd);       *     modprobe nbd max_part=63
         exit(0);       */
       nbd = open(device, O_RDWR);
       if (nbd != -1) {
           close(nbd);
     }      }
       return NULL;
   }
   
   static void *nbd_client_thread(void *arg)
   {
       int fd = *(int *)arg;
       off_t size;
       size_t blocksize;
       uint32_t nbdflags;
       int sock;
       int ret;
       pthread_t show_parts_thread;
   
       do {
           sock = unix_socket_outgoing(sockpath);
           if (sock == -1) {
               goto out;
           }
       } while (sock == -1);
   
       ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
                                   &size, &blocksize);
       if (ret == -1) {
           goto out;
       }
   
       ret = nbd_init(fd, sock, nbdflags, size, blocksize);
       if (ret == -1) {
           goto out;
       }
   
       /* update partition table */
       pthread_create(&show_parts_thread, NULL, show_parts, NULL);
   
       if (verbose) {
           fprintf(stderr, "NBD device %s is now connected to %s\n",
                   device, srcpath);
       } else {
           /* Close stderr so that the qemu-nbd process exits.  */
           dup2(STDOUT_FILENO, STDERR_FILENO);
       }
   
       ret = nbd_client(fd);
       if (ret) {
           goto out;
       }
       close(fd);
       kill(getpid(), SIGTERM);
       return (void *) EXIT_SUCCESS;
   
   out:
       kill(getpid(), SIGTERM);
       return (void *) EXIT_FAILURE;
 }  }
   
 int main(int argc, char **argv)  int main(int argc, char **argv)
Line 185  int main(int argc, char **argv) Line 249  int main(int argc, char **argv)
     BlockDriverState *bs;      BlockDriverState *bs;
     off_t dev_offset = 0;      off_t dev_offset = 0;
     off_t offset = 0;      off_t offset = 0;
     bool readonly = false;      uint32_t nbdflags = 0;
     bool disconnect = false;      bool disconnect = false;
     const char *bindto = "0.0.0.0";      const char *bindto = "0.0.0.0";
     int port = NBD_DEFAULT_PORT;      int port = NBD_DEFAULT_PORT;
     struct sockaddr_in addr;      struct sockaddr_in addr;
     socklen_t addr_len = sizeof(addr);      socklen_t addr_len = sizeof(addr);
     off_t fd_size;      off_t fd_size;
     char *device = NULL;  
     char *socket = NULL;  
     char sockpath[128];  
     const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";      const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
     struct option lopt[] = {      struct option lopt[] = {
         { "help", 0, NULL, 'h' },          { "help", 0, NULL, 'h' },
Line 230  int main(int argc, char **argv) Line 291  int main(int argc, char **argv)
     int nb_fds = 0;      int nb_fds = 0;
     int max_fd;      int max_fd;
     int persistent = 0;      int persistent = 0;
     uint32_t nbdflags;      pthread_t client_thread;
   
       /* The client thread uses SIGTERM to interrupt the server.  A signal
        * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
        */
       struct sigaction sa_sigterm;
       int sigterm_fd[2];
       if (qemu_pipe(sigterm_fd) == -1) {
           err(EXIT_FAILURE, "Error setting up communication pipe");
       }
   
       sigterm_wfd = sigterm_fd[1];
       memset(&sa_sigterm, 0, sizeof(sa_sigterm));
       sa_sigterm.sa_handler = termsig_handler;
       sigaction(SIGTERM, &sa_sigterm, NULL);
   
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {      while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {          switch (ch) {
Line 263  int main(int argc, char **argv) Line 338  int main(int argc, char **argv)
             }              }
             break;              break;
         case 'r':          case 'r':
             readonly = true;              nbdflags |= NBD_FLAG_READ_ONLY;
             flags &= ~BDRV_O_RDWR;              flags &= ~BDRV_O_RDWR;
             break;              break;
         case 'P':          case 'P':
Line 274  int main(int argc, char **argv) Line 349  int main(int argc, char **argv)
                 errx(EXIT_FAILURE, "Invalid partition %d", partition);                  errx(EXIT_FAILURE, "Invalid partition %d", partition);
             break;              break;
         case 'k':          case 'k':
             socket = optarg;              sockpath = optarg;
             if (socket[0] != '/')              if (sockpath[0] != '/')
                 errx(EXIT_FAILURE, "socket path must be absolute\n");                  errx(EXIT_FAILURE, "socket path must be absolute\n");
             break;              break;
         case 'd':          case 'd':
Line 333  int main(int argc, char **argv) Line 408  int main(int argc, char **argv)
         return 0;          return 0;
     }      }
   
     bdrv_init();      if (device && !verbose) {
           int stderr_fd[2];
     bs = bdrv_new("hda");  
   
     if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) {  
         errno = -ret;  
         err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);  
     }  
   
     fd_size = bs->total_sectors * 512;  
   
     if (partition != -1 &&  
         find_partition(bs, partition, &dev_offset, &fd_size))  
         err(EXIT_FAILURE, "Could not find partition %d", partition);  
   
     if (device) {  
         pid_t pid;          pid_t pid;
         int sock;          int ret;
   
         /* want to fail before daemonizing */          if (qemu_pipe(stderr_fd) == -1) {
         if (access(device, R_OK|W_OK) == -1) {              err(EXIT_FAILURE, "Error setting up communication pipe");
             err(EXIT_FAILURE, "Could not access '%s'", device);  
         }          }
   
         if (!verbose) {          /* Now daemonize, but keep a communication channel open to
             /* detach client and server */           * print errors and exit with the proper status code.
             if (qemu_daemon(0, 0) == -1) {           */
           pid = fork();
           if (pid == 0) {
               close(stderr_fd[0]);
               ret = qemu_daemon(0, 0);
   
               /* Temporarily redirect stderr to the parent's pipe...  */
               dup2(stderr_fd[1], STDERR_FILENO);
               if (ret == -1) {
                 err(EXIT_FAILURE, "Failed to daemonize");                  err(EXIT_FAILURE, "Failed to daemonize");
             }              }
         }  
   
         if (socket == NULL) {              /* ... close the descriptor we inherited and go on.  */
             snprintf(sockpath, sizeof(sockpath), SOCKET_PATH,              close(stderr_fd[1]);
                      basename(device));          } else {
             socket = sockpath;              bool errors = false;
         }              char *buf;
   
         pid = fork();              /* In the parent.  Print error messages from the child until
         if (pid < 0)               * it closes the pipe.
             return 1;               */
         if (pid != 0) {              close(stderr_fd[1]);
             off_t size;              buf = g_malloc(1024);
             size_t blocksize;              while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
                   errors = true;
             ret = 0;                  ret = qemu_write_full(STDERR_FILENO, buf, ret);
             bdrv_close(bs);                  if (ret == -1) {
                       exit(EXIT_FAILURE);
             do {  
                 sock = unix_socket_outgoing(socket);  
                 if (sock == -1) {  
                     if (errno != ENOENT && errno != ECONNREFUSED) {  
                         ret = 1;  
                         goto out;  
                     }  
                     sleep(1);   /* wait children */  
                 }                  }
             } while (sock == -1);  
   
             fd = open(device, O_RDWR);  
             if (fd == -1) {  
                 ret = 1;  
                 goto out;  
             }              }
   
             ret = nbd_receive_negotiate(sock, NULL, &nbdflags,  
                                         &size, &blocksize);  
             if (ret == -1) {              if (ret == -1) {
                 ret = 1;                  err(EXIT_FAILURE, "Cannot read from daemon");
                 goto out;  
             }              }
   
             ret = nbd_init(fd, sock, size, blocksize);              /* Usually the daemon should not print any message.
             if (ret == -1) {               * Exit with zero status in that case.
                 ret = 1;               */
                 goto out;              exit(errors);
             }          }
       }
   
             printf("NBD device %s is now connected to file %s\n",      if (device) {
                     device, argv[optind]);          /* Open before spawning new threads.  In the future, we may
            * drop privileges after opening.
            */
           fd = open(device, O_RDWR);
           if (fd == -1) {
               err(EXIT_FAILURE, "Failed to open %s", device);
           }
   
             /* update partition table */          if (sockpath == NULL) {
               sockpath = g_malloc(128);
               snprintf(sockpath, 128, SOCKET_PATH, basename(device));
           }
       }
   
             show_parts(device);      bdrv_init();
       atexit(bdrv_close_all);
   
             ret = nbd_client(fd);      bs = bdrv_new("hda");
             if (ret) {      srcpath = argv[optind];
                 ret = 1;      if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
             }          errno = -ret;
             close(fd);          err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
  out:      }
             kill(pid, SIGTERM);  
             unlink(socket);  
   
             return ret;      fd_size = bs->total_sectors * 512;
         }  
         /* children */      if (partition != -1 &&
           find_partition(bs, partition, &dev_offset, &fd_size)) {
           err(EXIT_FAILURE, "Could not find partition %d", partition);
     }      }
   
     sharing_fds = qemu_malloc((shared + 1) * sizeof(int));      sharing_fds = g_malloc((shared + 1) * sizeof(int));
   
     if (socket) {      if (sockpath) {
         sharing_fds[0] = unix_socket_incoming(socket);          sharing_fds[0] = unix_socket_incoming(sockpath);
     } else {      } else {
         sharing_fds[0] = tcp_socket_incoming(bindto, port);          sharing_fds[0] = tcp_socket_incoming(bindto, port);
     }      }
   
     if (sharing_fds[0] == -1)      if (sharing_fds[0] == -1)
         return 1;          return 1;
   
       if (device) {
           int ret;
   
           ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
           if (ret != 0) {
               errx(EXIT_FAILURE, "Failed to create client thread: %s",
                    strerror(ret));
           }
       } else {
           /* Shut up GCC warnings.  */
           memset(&client_thread, 0, sizeof(client_thread));
       }
   
     max_fd = sharing_fds[0];      max_fd = sharing_fds[0];
     nb_fds++;      nb_fds++;
   
     data = qemu_blockalign(bs, NBD_BUFFER_SIZE);      data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
     if (data == NULL)      if (data == NULL) {
         errx(EXIT_FAILURE, "Cannot allocate data buffer");          errx(EXIT_FAILURE, "Cannot allocate data buffer");
       }
   
     do {      do {
   
         FD_ZERO(&fds);          FD_ZERO(&fds);
           FD_SET(sigterm_fd[0], &fds);
         for (i = 0; i < nb_fds; i++)          for (i = 0; i < nb_fds; i++)
             FD_SET(sharing_fds[i], &fds);              FD_SET(sharing_fds[i], &fds);
   
         ret = select(max_fd + 1, &fds, NULL, NULL, NULL);          do {
         if (ret == -1)              ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
           } while (ret == -1 && errno == EINTR);
           if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) {
             break;              break;
           }
   
         if (FD_ISSET(sharing_fds[0], &fds))          if (FD_ISSET(sharing_fds[0], &fds))
             ret--;              ret--;
         for (i = 1; i < nb_fds && ret; i++) {          for (i = 1; i < nb_fds && ret; i++) {
             if (FD_ISSET(sharing_fds[i], &fds)) {              if (FD_ISSET(sharing_fds[i], &fds)) {
                 if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,                  if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
                     &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {                      &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) {
                     close(sharing_fds[i]);                      close(sharing_fds[i]);
                     nb_fds--;                      nb_fds--;
                     sharing_fds[i] = sharing_fds[nb_fds];                      sharing_fds[i] = sharing_fds[nb_fds];
Line 479  int main(int argc, char **argv) Line 558  int main(int argc, char **argv)
                                              (struct sockaddr *)&addr,                                               (struct sockaddr *)&addr,
                                              &addr_len);                                               &addr_len);
                 if (sharing_fds[nb_fds] != -1 &&                  if (sharing_fds[nb_fds] != -1 &&
                     nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) {                      nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
                         if (sharing_fds[nb_fds] > max_fd)                          if (sharing_fds[nb_fds] > max_fd)
                             max_fd = sharing_fds[nb_fds];                              max_fd = sharing_fds[nb_fds];
                         nb_fds++;                          nb_fds++;
Line 490  int main(int argc, char **argv) Line 569  int main(int argc, char **argv)
     qemu_vfree(data);      qemu_vfree(data);
   
     close(sharing_fds[0]);      close(sharing_fds[0]);
     bdrv_close(bs);      g_free(sharing_fds);
     qemu_free(sharing_fds);      if (sockpath) {
     if (socket)          unlink(sockpath);
         unlink(socket);      }
   
     return 0;      if (device) {
           void *ret;
           pthread_join(client_thread, &ret);
           exit(ret != NULL);
       } else {
           exit(EXIT_SUCCESS);
       }
 }  }

Removed from v.1.1.1.6  
changed lines
  Added in v.1.1.1.7


unix.superglobalmegacorp.com