qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 1/2] Dump: introduce a Filesystem in Userspace


From: Nan Li
Subject: [Qemu-devel] [PATCH 1/2] Dump: introduce a Filesystem in Userspace
Date: Sun, 8 May 2016 07:32:47 +0800

When running the command "dump-guest-memory", we usually need a large space
of storage to save the dumpfile into disk. It costs not only much time to
save a file in some of hard disks, but also costs limited storage in host.
In order to reduce the saving time and make it convenient for users to dump
the guest memory, we introduce a Filesystem in Userspace (FUSE) to save the
dump file in RAM. It is selectable in the configure file, adding a compiling
of package "fuse-devel". It doesn't change the way of dumping guest memory.

qemu_fuse_main(int argc, char *argv[]) is the API for qemu code to mount
this filesystem. And it only supports these operations just for dumping
guest memory.

static struct fuse_operations qemu_fuse_oper = {
        .getattr        = qemu_fuse_getattr,
        .fgetattr       = qemu_fuse_fgetattr,
        .readdir        = qemu_fuse_readdir,
        .create   = qemu_fuse_create,
        .open   = qemu_fuse_open,
        .read   = qemu_fuse_read,
        .write  = qemu_fuse_write,
        .unlink = qemu_fuse_unlink,
};

Signed-off-by: Nan Li <address@hidden>
---
 Makefile.target |   1 +
 configure       |  34 +++++
 fuse-mem.c      | 376 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fuse-mem.h      |   2 +
 4 files changed, 413 insertions(+)
 create mode 100644 fuse-mem.c
 create mode 100644 fuse-mem.h

diff --git a/Makefile.target b/Makefile.target
index 34ddb7e..7619ef8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -138,6 +138,7 @@ obj-$(CONFIG_KVM) += kvm-all.o
 obj-y += memory.o cputlb.o
 obj-y += memory_mapping.o
 obj-y += dump.o
+obj-$(CONFIG_FUSE) += fuse-mem.o
 obj-y += migration/ram.o migration/savevm.o
 LIBS := $(libs_softmmu) $(LIBS)
 
diff --git a/configure b/configure
index 5db29f0..0769caf 100755
--- a/configure
+++ b/configure
@@ -275,6 +275,7 @@ trace_backends="log"
 trace_file="trace"
 spice=""
 rbd=""
+fuse="yes"
 smartcard=""
 libusb=""
 usb_redir=""
@@ -1023,6 +1024,10 @@ for opt do
   ;;
   --enable-rbd) rbd="yes"
   ;;
+  --disable-fuse) fuse="no"
+  ;;
+  --enable-fuse) fuse="yes"
+  ;;
   --disable-xfsctl) xfs="no"
   ;;
   --enable-xfsctl) xfs="yes"
@@ -1349,6 +1354,7 @@ disabled with --disable-FEATURE, default is enabled if 
available:
   vhost-net       vhost-net acceleration support
   spice           spice
   rbd             rados block device (rbd)
+  fuse            the support of dumping guest memory via fuse
   libiscsi        iscsi support
   libnfs          nfs support
   smartcard       smartcard support (libcacard)
@@ -3139,6 +3145,28 @@ EOF
 fi
 
 ##########################################
+# fuse probe
+min_fuse_version=2.9.3
+if test "$fuse" != "no" ; then
+  if $pkg_config --atleast-version=$min_fuse_version fuse; then
+    fuse_cflags=`$pkg_config fuse --cflags`
+    fuse_libs=`$pkg_config fuse --libs`
+    QEMU_CFLAGS="$fuse_cflags $QEMU_CFLAGS"
+    libs_softmmu="$fuse_libs $libs_softmmu"
+    fuse=yes
+  else
+    if $pkg_config fuse; then
+      if test "$fuse" = "yes" ; then
+        error_exit "fuse >= $min_fuse_version required for --enable-fuse"
+      fi
+    else
+      feature_not_found "fuse" "Please install fuse devel pkgs: fuse-devel"
+    fi
+    fuse=no
+  fi
+fi
+
+##########################################
 # libssh2 probe
 min_libssh2_version=1.2.8
 if test "$libssh2" != "no" ; then
@@ -4815,6 +4843,7 @@ else
 echo "spice support     $spice"
 fi
 echo "rbd support       $rbd"
+echo "fuse support      $fuse"
 echo "xfsctl support    $xfs"
 echo "smartcard support $smartcard"
 echo "libusb            $libusb"
@@ -5293,6 +5322,11 @@ if test "$rbd" = "yes" ; then
   echo "RBD_CFLAGS=$rbd_cflags" >> $config_host_mak
   echo "RBD_LIBS=$rbd_libs" >> $config_host_mak
 fi
+if test "$fuse" = "yes" ; then
+  echo "CONFIG_FUSE=y" >> $config_host_mak
+  echo "FUSE_CFLAGS=$fuse_cflags" >> $config_host_mak
+  echo "FUSE_LIBS=$fuse_libs" >> $config_host_mak
+fi
 
 echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
 if test "$coroutine_pool" = "yes" ; then
diff --git a/fuse-mem.c b/fuse-mem.c
new file mode 100644
index 0000000..3365ddb
--- /dev/null
+++ b/fuse-mem.c
@@ -0,0 +1,376 @@
+/*
+
+  gcc -Wall myfuse.c -lfuse -D_FILE_OFFSET_BITS=64 -o myfuse
+*/
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "fuse-mem.h"
+
+//static const char *qemu_str = "Hello World!\n";
+//static const char *qemu_path = "/etc/qemu";
+
+#define PAGE_SIZE      (0x100000)
+#define FILE_BUFFER_PAGE       (PAGE_SIZE - sizeof(struct file_buffer))
+
+struct file_buffer {
+       struct file_buffer *next;
+       size_t used;
+       size_t size;
+       /* Data points here */
+       unsigned char data[0];
+};
+
+struct file_bufhead {
+       //spinlock_t lock;
+       struct file_buffer *head;       
+       struct file_buffer *tail;
+       //struct file_buffer *current;  
+       size_t filesize;
+       //off_t offset;
+       //char *offset_ptr;
+};
+
+struct fuse_file {
+       char path[128];
+       struct fuse_file_info fileinfo;
+       struct file_bufhead file;
+       struct fuse_file *next;
+};
+
+struct fuse_file_root {
+       struct fuse_file *head;
+       struct fuse_file *tail;
+};
+
+struct fuse_file_root root;
+
+#if 0
+void dumpfile(struct fuse_file *fuse_file_ptr)
+{
+       struct file_buffer *file_buffer_ptr;
+       int i;
+       printf("DUMPFILE:\n");
+       for (file_buffer_ptr = fuse_file_ptr->file.head; file_buffer_ptr != 
NULL; file_buffer_ptr = file_buffer_ptr->next) {
+               for (i = 0; i < file_buffer_ptr->used; i++) {
+                       printf("Address:0x%x:  0x%x\n", 
&file_buffer_ptr->data[i], file_buffer_ptr->data[i]);
+               }
+       }
+}
+#endif
+
+static int qemu_fuse_getattr(const char *path, struct stat *stbuf)
+{
+       struct fuse_file *fuse_file_ptr;
+       fuse_file_ptr = root.head;
+       
+       memset(stbuf, 0, sizeof(struct stat));
+       if (strcmp(path, "/") == 0) {
+               stbuf->st_mode = S_IFDIR | 0777;
+               stbuf->st_nlink = 2;
+       } else {
+               while(fuse_file_ptr != NULL) {
+                       if (strcmp(fuse_file_ptr->path, path) == 0) {
+                               stbuf->st_mode = S_IFREG | 0666;
+                               stbuf->st_nlink = 1;
+                               stbuf->st_size = fuse_file_ptr->file.filesize;
+                               return 0;
+                       }
+                       else
+                               fuse_file_ptr = fuse_file_ptr->next;
+               }
+               return -ENOENT;
+       }
+
+       return 0;
+}
+/*
+static int qemu_fuse_getattr(const char *path, struct stat *stbuf)
+{
+       int res;
+
+       res = lstat(path, stbuf);
+       if (res == -1)
+               return -errno;
+
+       return 0;
+}
+*/
+static int qemu_fuse_fgetattr(const char *path, struct stat *stbuf,
+                       struct fuse_file_info *fi)
+{
+       struct fuse_file *fuse_file_ptr;
+       fuse_file_ptr = root.head;
+       
+       memset(stbuf, 0, sizeof(struct stat));
+
+       while(fuse_file_ptr != NULL) {
+               if (fuse_file_ptr->fileinfo.fh == fi->fh) {
+                       stbuf->st_mode = S_IFREG | 0666;
+                       stbuf->st_nlink = 1;
+                       stbuf->st_size = fuse_file_ptr->file.filesize;
+                       return 0;
+               }
+               else
+                       fuse_file_ptr = fuse_file_ptr->next;
+       }
+       return -ENOENT;
+
+       return 0;
+}
+
+static int qemu_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t 
filler,
+                        off_t offset, struct fuse_file_info *fi)
+{
+
+       return 0;
+}
+
+static int qemu_fuse_create(const char *path, mode_t mode, struct 
fuse_file_info *fi)
+{
+       struct fuse_file *fuse_file_ptr;
+
+       fuse_file_ptr = (struct fuse_file *)malloc(sizeof(struct fuse_file));
+       if (fuse_file_ptr) {
+               memcpy(&fuse_file_ptr->fileinfo, fi, sizeof(struct 
fuse_file_info));
+               memset(&fuse_file_ptr->file, 0, sizeof(fuse_file_ptr->file));
+               fuse_file_ptr->next = NULL;
+               if (root.head == NULL) {
+                       root.head = fuse_file_ptr;
+                       fi->fh = 1;
+               } else {
+                       root.tail->next = fuse_file_ptr;
+                       fi->fh = root.tail->fileinfo.fh + 1;
+               }
+               root.tail = fuse_file_ptr;
+               fuse_file_ptr->fileinfo.fh = fi->fh;
+               strcpy(fuse_file_ptr->path, path);
+       } else {
+               return -ENOMEM;
+       }
+       
+       return 0;
+}
+
+static int qemu_fuse_open(const char *path, struct fuse_file_info *fi)
+{
+       struct fuse_file *fuse_file_ptr;
+
+       fuse_file_ptr = root.head;
+
+       while(fuse_file_ptr != NULL) {
+               if (strcmp(fuse_file_ptr->path, path) == 0) {
+                       fi->fh = fuse_file_ptr->fileinfo.fh;
+                       memcpy(&fuse_file_ptr->fileinfo, fi, sizeof(struct 
fuse_file_info));
+                       return 0;
+               }
+               else
+                       fuse_file_ptr = fuse_file_ptr->next;
+       }
+
+       return -ENOENT;
+}
+
+static int qemu_fuse_read(const char *path, char *buf, size_t size, off_t 
offset,
+                     struct fuse_file_info *fi)
+{
+//printf("herbert:read:size=%u, offset=%u\n", size, offset);
+
+       struct fuse_file *fuse_file_ptr;
+       struct file_buffer *file_buffer_ptr;
+
+       fuse_file_ptr = root.head;
+       long n, count;
+       int item, index;
+       int i = 0, j = 0;
+
+       while(fuse_file_ptr != NULL) {
+               if (fuse_file_ptr->fileinfo.fh == fi->fh) {
+                       if ((fuse_file_ptr->file.filesize <= offset) || 
(fuse_file_ptr->file.filesize == 0))
+                               return 0;
+                       if (size + offset > fuse_file_ptr->file.filesize)
+                               size = fuse_file_ptr->file.filesize - offset;
+                       n = size;
+                       
+                       item = offset / FILE_BUFFER_PAGE;
+                       index = offset % FILE_BUFFER_PAGE;
+                       
+                       for (file_buffer_ptr = fuse_file_ptr->file.head; 
file_buffer_ptr != NULL; file_buffer_ptr = file_buffer_ptr->next) {
+                               if ( i == item )
+                                       break;
+                               i++;
+                       }
+
+                       j = index;
+                       while (file_buffer_ptr != NULL && n > 0) {      
+                               if ( n > ((long)file_buffer_ptr->used - j) )
+                                       count = ((long)file_buffer_ptr->used - 
j);
+                               else
+                                       count = n;
+                               
+                               memcpy(buf + size -n, 
&file_buffer_ptr->data[j], count);
+                               n -= count;
+                               j = 0;
+                               if (n > 0)
+                                       file_buffer_ptr = file_buffer_ptr->next;
+                       }
+//dumpfile(fuse_file_ptr);                     
+                       return size;
+               }
+               else {
+                       fuse_file_ptr = fuse_file_ptr->next;
+               }
+       }
+
+       return -EBADF;
+}
+
+static int qemu_fuse_write(const char *path, const char *buf, size_t size,
+                    off_t offset, struct fuse_file_info *fi)
+{
+//printf("herbert:write:size=%u, offset=%u\n", size, offset);
+
+       struct fuse_file *fuse_file_ptr;
+       struct file_buffer *file_buffer_ptr;
+
+       long n, count;
+       int item, index;
+       int i = 0, j = 0;
+       
+       fuse_file_ptr = root.head;
+
+       while(fuse_file_ptr != NULL) {
+               if (fuse_file_ptr->fileinfo.fh == fi->fh) {
+                       n = size;
+                       
+                       item = offset / FILE_BUFFER_PAGE;
+                       index = offset % FILE_BUFFER_PAGE;
+
+                       for (file_buffer_ptr = fuse_file_ptr->file.head; 
file_buffer_ptr != NULL; file_buffer_ptr = file_buffer_ptr->next) {
+                               if ( i == item )
+                                       break;
+                               i++;
+                       }
+
+                       j = index;
+
+                       while (file_buffer_ptr != NULL && n > 0) {      
+                               if ( n > file_buffer_ptr->size - j )
+                                       count = file_buffer_ptr->size- j;
+                               else
+                                       count = n;
+                               
+                               memcpy(&file_buffer_ptr->data[j], buf + size 
-n, count);
+                               if ((count + j - (long)file_buffer_ptr->used) > 
0) {
+                                       fuse_file_ptr->file.filesize += (count 
+ j - (long)file_buffer_ptr->used);
+                                       file_buffer_ptr->used = count + j; 
+                               }
+                               n -= count;
+                               j = 0;
+                               
+                               if (n > 0)
+                                       file_buffer_ptr = file_buffer_ptr->next;
+                       }
+
+                       while (n > 0) {
+                               file_buffer_ptr = (struct file_buffer 
*)malloc(PAGE_SIZE);
+                               if (file_buffer_ptr) {
+                                       file_buffer_ptr->next = NULL;
+                                       file_buffer_ptr->size = 
FILE_BUFFER_PAGE;
+                                       if ( n > file_buffer_ptr->size )
+                                               count = file_buffer_ptr->size;
+                                       else
+                                               count = n;
+                                       
+                                       memcpy(file_buffer_ptr->data, buf + 
size -n, count);
+                                       
+                                       file_buffer_ptr->used = count;
+                                       
+                                       if (fuse_file_ptr->file.head == NULL) {
+                                               fuse_file_ptr->file.head = 
file_buffer_ptr;
+                                       } else {
+                                               fuse_file_ptr->file.tail->next 
= file_buffer_ptr;
+                                       }
+                                       fuse_file_ptr->file.tail = 
file_buffer_ptr;
+                                       fuse_file_ptr->file.filesize += count;
+                                       
+                                       n -= count;
+                                       
+                                       if (n > 0)
+                                               file_buffer_ptr = 
file_buffer_ptr->next;
+                               } else {
+                                       return -ENOMEM;
+                               }       
+                       }
+//dumpfile(fuse_file_ptr);
+                       return size;
+                       
+               }
+               else {
+                       fuse_file_ptr = fuse_file_ptr->next;
+               }
+       }
+       
+       return -EBADF;
+}
+
+static int qemu_fuse_unlink(const char *path)
+{
+       struct fuse_file *fuse_file_ptr, *p;
+       struct file_buffer *file_buffer_ptr, *q;
+       
+       fuse_file_ptr = root.head;
+
+       while(fuse_file_ptr != NULL) {
+               if (strcmp(fuse_file_ptr->path, path) == 0) {
+
+                       file_buffer_ptr = fuse_file_ptr->file.head;
+                       q = fuse_file_ptr->file.head;
+                       while (file_buffer_ptr != NULL) {
+                               q = q->next;
+                               free(file_buffer_ptr);
+                               file_buffer_ptr = q;
+                       }
+
+                       if (fuse_file_ptr == root.head) {
+                               root.head = fuse_file_ptr->next;
+                       } else {
+                               for (p = root.head; p->next != fuse_file_ptr; p 
= p->next);
+                               p->next = fuse_file_ptr->next;
+                       }
+                       
+                       free(fuse_file_ptr);
+
+                       return 0;
+               }
+               else
+                       fuse_file_ptr = fuse_file_ptr->next;
+       }
+       
+       return -EACCES;
+}
+
+static struct fuse_operations qemu_fuse_oper = {
+       .getattr        = qemu_fuse_getattr,
+       .fgetattr       = qemu_fuse_fgetattr,
+       .readdir        = qemu_fuse_readdir,
+       .create   = qemu_fuse_create,
+       .open   = qemu_fuse_open,
+       .read   = qemu_fuse_read,
+       .write  = qemu_fuse_write,
+       .unlink = qemu_fuse_unlink,
+};
+
+extern int qemu_fuse_main(int argc, char *argv[])
+{
+       return fuse_main(argc, argv, &qemu_fuse_oper, NULL);
+}
+
+
+
diff --git a/fuse-mem.h b/fuse-mem.h
new file mode 100644
index 0000000..1a40168
--- /dev/null
+++ b/fuse-mem.h
@@ -0,0 +1,2 @@
+extern int qemu_fuse_main(int argc, char *argv[]);
+
-- 
1.8.4.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]