Merge tag 'v2.7.0' into develop_qemu_2.7
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Mon, 12 Sep 2016 06:41:37 +0000 (15:41 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Mon, 12 Sep 2016 06:41:37 +0000 (15:41 +0900)
v2.7.0 release

Change-Id: Id5feb5a9404ab064f9ea3d0aa0d95eef17020fa3
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
72 files changed:
1  2 
.gitignore
Makefile
Makefile.objs
Makefile.target
accel.c
arch_init.c
audio/audio.c
audio/coreaudio.c
block.c
block/raw-win32.c
blockdev.c
configure
cpu-exec.c
cpus.c
exec.c
fsdev/9p-iov-marshal.c
fsdev/9p-marshal.c
fsdev/9p-marshal.h
fsdev/file-op-9p.h
fsdev/qemu-fsdev.c
fsdev/qemu-fsdev.h
hmp-commands.hx
hmp.c
hmp.h
hw/9pfs/9p-local-maru.c
hw/9pfs/9p-maru.c
hw/9pfs/9p-xattr.h
hw/9pfs/9p.h
hw/9pfs/cofile.c
hw/acpi/ich9.c
hw/acpi/piix4.c
hw/arm/Makefile.objs
hw/i386/pc.c
hw/i386/pc_piix.c
hw/input/pl050.c
hw/intc/apic_common.c
hw/pci/pci.c
hw/vigs/display.h
hw/vigs/vigs_device.c
hw/vigs/vigs_types.h
hw/vigs/winsys.h
hw/vigs/work_queue.h
hw/yagl/yagl_types.h
include/exec/hwaddr.h
include/qemu/error-report.h
include/qom/cpu.h
include/sysemu/arch_init.h
include/ui/console.h
main-loop.c
net/net.c
net/slirp.c
net/tap-win32.c
net/tap.c
qapi-schema.json
qemu-char.c
qemu-options.hx
qmp-commands.hx
slirp/tcp_subr.c
target-i386/translate.c
target-s390x/kvm.c
tcg/tcg.c
tizen/src/ecs/ecs_hds.c
tizen/src/emul_state.c
tizen/src/hw/pci/maru_tuner.c
ui/cocoa.m
ui/console.c
ui/spice-core.c
ui/spice-display.c
util/oslib-posix.c
util/oslib-win32.c
util/qemu-coroutine.c
vl.c

diff --cc .gitignore
  cscope.*
  tags
  TAGS
+ docker-src.*
  *~
 +tizen/emulator
 +tizen/src/build_info.h
 +tizen/src/skin/client/src/about.properties
 +tizen/src/skin/client/bin
 +tizen/src/skin/client/build
 +tizen/src/skin/client/emulator-skin.jar
 +tizen/src/skin/client/lib
 +tizen/src/skin/client/native_src/*.so
 +tizen/src/skin/client/native_src/*.dynlib
 +tizen/standalone-src/qt5_msgbox
 +tizen/standalone-src/qt5_msgbox.res
 +fsdev/virtfs-proxy-helper
 +.settings
 +.cproject
 +.project
 +check-hax
 +check-hax.exe
 +check-cam
 +check-cam.exe
 +check-gl
 +check-gl.exe
 +check-net
 +check-net.exe
diff --cc Makefile
Simple merge
diff --cc Makefile.objs
Simple merge
diff --cc Makefile.target
Simple merge
diff --cc accel.c
Simple merge
diff --cc arch_init.c
Simple merge
diff --cc audio/audio.c
Simple merge
@@@ -397,12 -376,7 +395,7 @@@ static inline UInt32 isPlaying (AudioDe
      return result;
  }
  
- static void coreaudio_atexit (void)
- {
-     isAtexit = 1;
- }
 -static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
 +static int coreaudio_lock (coreaudioVoice *core, const char *fn_name)
  {
      int err;
  
@@@ -541,18 -617,18 +534,18 @@@ static int coreaudio_init_voice (coreau
      return 0;
  }
  
 -static void coreaudio_fini_out (HWVoiceOut *hw)
 +static void coreaudio_fini_voice (coreaudioVoice *core, bool isInput)
  {
      OSStatus status;
 +    const char *typ = isInput ? "capture" : "playback";
      int err;
 -    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
  
-     if (!isAtexit) {
+     if (!audio_is_cleaning_up()) {
 -        /* stop playback */
 -        if (isPlaying(core->outputDeviceID)) {
 -            status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
 +        /* stop playback/capture */
 +        if (isPlaying(core->deviceID)) {
 +            status = AudioDeviceStop(core->deviceID, core->ioprocid);
              if (status != kAudioHardwareNoError) {
 -                coreaudio_logerr (status, "Could not stop playback\n");
 +                coreaudio_logerr (status, "Could not stop %s\n", typ);
              }
          }
  
@@@ -589,13 -665,13 +582,13 @@@ static int coreaudio_ctl_voice (coreaud
          break;
  
      case VOICE_DISABLE:
 -        /* stop playback */
 +        /* stop playback/capture */
-         if (!isAtexit) {
+         if (!audio_is_cleaning_up()) {
 -            if (isPlaying(core->outputDeviceID)) {
 -                status = AudioDeviceStop(core->outputDeviceID,
 +            if (isPlaying(core->deviceID)) {
 +                status = AudioDeviceStop(core->deviceID,
                                           core->ioprocid);
                  if (status != kAudioHardwareNoError) {
 -                    coreaudio_logerr (status, "Could not pause playback\n");
 +                    coreaudio_logerr (status, "Could not pause %s\n", typ);
                  }
              }
          }
diff --cc block.c
Simple merge
Simple merge
diff --cc blockdev.c
  static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
      QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
  
 +#ifdef CONFIG_MARU
 +#include "tizen/src/util/exported_strings.h"
 +#endif
 +
+ static int do_open_tray(const char *device, bool force, Error **errp);
  static const char *const if_name[IF_COUNT] = {
      [IF_NONE] = "none",
      [IF_IDE] = "ide",
diff --cc configure
+++ b/configure
@@@ -322,27 -321,9 +322,27 @@@ numa="
  tcmalloc="no"
  jemalloc="no"
  
 +yagl="no"
 +yagl_stats="no"
 +glx=""
 +vigs="no"
 +libtizenusb="no"
 +
 +# for TIZEN-maru
 +maru="no"
 +winver="0x501"
 +libav=""
 +libpng="no"
 +dxva2=""
 +vaapi=""
 +qt="no"
 +qtabi="5.0"
 +extension_path=""
 +#
 +
  # parse CC options first
  for opt do
-   optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+   optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
    case "$opt" in
    --cross-prefix=*) cross_prefix="$optarg"
    ;;
  ##########################################
  # X11 probe
  x11_cflags=
 -x11_libs=-lX11
 +x11_libs=
  if $pkg_config --exists "x11"; then
-     x11_cflags=`$pkg_config --cflags x11`
-     x11_libs=`$pkg_config --libs x11`
+     x11_cflags=$($pkg_config --cflags x11)
+     x11_libs=$($pkg_config --libs x11)
  fi
  
  ##########################################
@@@ -4692,188 -4570,6 +4726,178 @@@ if test "$libnfs" != "no" ; the
    fi
  fi
  
- # Disable zero malloc errors for official releases unless explicitly told to
- # enable/disable
- if test -z "$zero_malloc" ; then
-     if test "$z_version" = "50" ; then
-       zero_malloc="no"
-     else
-       zero_malloc="yes"
-     fi
- fi
 +########################################
 +# check if dxva2 is available.
 +
 +check_dxva2() {
 +
 +cat > $TMPC << EOF
 +#include <d3d9.h>
 +#include <dxva2api.h>
 +int main(void) {
 +#if !defined(IDirect3D9_CreateDevice) || \
 +    !defined(IDirect3DDeviceManager9_ResetDevice)
 +#error No DXVA2 support
 +#endif
 +    return 0;
 +}
 +EOF
 +if compile_prog "" "" ; then
 +    dxva2="yes"
 +else
 +    dxva2="no"
 +fi
 +
 +}
 +
 +if test "$dxva2" = "yes" ; then
 +      if test "$mingw32" = "yes" ; then
 +              check_dxva2
 +              if test "$dxva2" != "yes" ; then
 +                      feature_not_found "dxva2"
 +              fi
 +      else
 +              error_exit "DXVA2 is supported only on Windows"
 +      fi
 +else
 +      if test "$dxva2" != "no" ; then
 +              check_dxva2
 +      fi
 +fi
 +
 +########################################
 +# check if vaapi is available.
 +
 +check_vaapi() {
 +
 +if $pkg_config libva --exists; then
 +      libva_cflags=`$pkg_config --cflags libva`
 +      libva_libs=`$pkg_config --libs libva`
 +      vaapi="yes"
 +else
 +      vaapi="no"
 +fi
 +
 +if $pkg_config libva-x11 --exists; then
 +      libva_x11_cflags=`$pkg_config --cflags libva-x11`
 +      libva_x11_libs=`$pkg_config --libs libva-x11`
 +      libs_softmmu="$libva_libs $libva_x11_libs $libs_softmmu"
 +      vaapi="yes"
 +else
 +      vaapi="no"
 +fi
 +
 +}
 +
 +if test "$vaapi" = "yes" ; then
 +      if test "$linux" = "yes" ; then
 +              check_vaapi
 +              if test "$vaapi" != "yes" ; then
 +                      feature_not_found "vaapi"
 +              fi
 +      else
 +              error_exit "VAAPI is supported only on Linux"
 +      fi
 +else
 +      if test "$vaapi" != "no" ; then
 +              check_vaapi
 +      fi
 +fi
 +
 +########################################
 +# set WINVER
 +
 +if test "$mingw32" = "yes" ; then
 +  QEMU_CFLAGS="-DWINVER=$winver -D_WIN32_WINNT=$winver $QEMU_CFLAGS"
 +fi
 +
 +########################################
 +# check extension path
 +
 +if [ ! -d "$source_path/tizen/src/$extension_path" ] ; then
 +      error_exit "Extension path is not valid $source_path/tizen/src/$extension_path"
 +fi
 +
 +##########################################
 +# libav probe
 +
 +libavcodec_package="libavcodec"
 +libavcodec_version="54.35.0"
 +libavutil_package="libavutil"
 +libavutil_version="52.3.0"
 +libavformat_package="libavformat"
 +libavformat_version="54.20.3"
 +libavresample_package="libavresample"
 +libavresample_version="1.0.1"
 +libx264_package="x264"
 +libav_package="libav"
 +exists_libav="no"
 +exists_x264="no"
 +
 +check_libav() {
 +
 +      if ! $pkg_config --exists "$libavcodec_package >= $libavcodec_version" ; then
 +              return
 +      fi
 +      if ! $pkg_config --exists "$libavformat_package >= $libavformat_version" ; then
 +              return
 +      fi
 +      if ! $pkg_config --exists "$libavutil_package >= $libavutil_version" ; then
 +              return
 +      fi
 +      if ! $pkg_config --exists "$libavresample_package >= $libavresample_version" ; then
 +              return
 +      fi
 +      exists_libav="yes"
 +
 +      if $pkg_config --exists "$libx264_package" ; then
 +              exists_x264="yes"
 +      fi
 +}
 +
 +set_libav_config() {
 +      if [ "$libav" = "yes" ]; then
 +              if [ "$exists_libav" = "no" ]; then
 +                      feature_not_found "$libav_package"
 +              elif [ "$exists_x264" = "no" ]; then
 +                      feature_not_found "$libx264_package"
 +              fi
 +      fi
 +
 +      if [ "$exists_libav" = "yes" ] && [ "$exists_x264" = "yes" ]; then
 +              libav="yes"
 +              libav_cflags=`$pkg_config --cflags $libavcodec_package` #Header files are in same place.
 +              libav_libs=`$pkg_config --libs $libavcodec_package $libavformat_package $libavutil_package $libavresample_package $libx264_package`
 +      else
 +              libav="no"
 +      fi
 +}
 +
 +if [ "$libav" != "no" ]; then
 +      check_libav
 +      set_libav_config
 +fi
 +
 +##########################################
 +# libpng probe
 +
 +if test "$libpng" != "no"; then
 +    libpng_package="libpng"
 +
 +    if $pkg_config --exists "$libpng_package" ; then
 +        libpng_cflags=`$pkg_config --cflags $libpng_package`
 +        libpng_libs=`$pkg_config --libs $libpng_package`
 +        libs_softmmu="$libpng_libs $libs_softmmu"
 +        libpng="yes"
 +    else
 +        if test "$libpng" = "yes" ; then
 +            feature_not_found "libpng"
 +        fi
 +        libpng="no"
 +    fi
 +fi
 +
 +
  # Now we've finished running tests it's OK to add -Werror to the compiler flags
  if test "$werror" = "yes"; then
      QEMU_CFLAGS="-Werror $QEMU_CFLAGS"
@@@ -4919,15 -4615,9 +4943,15 @@@ if test "$softmmu" = yes ; the
      if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
        virtfs=yes
        tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
 +    elif test "$maru" = yes && test "$darwin" = yes ; then
 +      echo "Enable VirtFS on Darwin"
 +      virtfs=yes
 +    elif test "$maru" = yes && test "$mingw32" = yes ; then
 +      echo "Enable VirtFS on Windows"
 +      virtfs=yes
      else
        if test "$virtfs" = yes; then
-         error_exit "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel"
+         error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
        fi
        virtfs=no
      fi
diff --cc cpu-exec.c
@@@ -436,146 -618,11 +618,20 @@@ int cpu_exec(CPUState *cpu
                  break;
              }
  
-             next_tb = 0; /* force lookup of first TB */
 +#ifdef CONFIG_HAX
 +            if (hax_enabled() && !hax_vcpu_exec(cpu))
 +                longjmp(cpu->jmp_env, 1);
 +#endif
 +
+             cpu->tb_flushed = false; /* reset before first TB lookup */
              for(;;) {
-                 interrupt_request = cpu->interrupt_request;
-                 if (unlikely(interrupt_request)) {
-                     if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) {
-                         /* Mask out external interrupts for this step. */
-                         interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
-                     }
-                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
-                         cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
-                         cpu->exception_index = EXCP_DEBUG;
-                         cpu_loop_exit(cpu);
-                     }
-                     if (replay_mode == REPLAY_MODE_PLAY
-                         && !replay_has_interrupt()) {
-                         /* Do nothing */
-                     } else if (interrupt_request & CPU_INTERRUPT_HALT) {
-                         replay_interrupt();
-                         cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
-                         cpu->halted = 1;
-                         cpu->exception_index = EXCP_HLT;
-                         cpu_loop_exit(cpu);
-                     }
- #if defined(TARGET_I386)
-                     else if (interrupt_request & CPU_INTERRUPT_INIT) {
-                         replay_interrupt();
-                         cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
-                         do_cpu_init(x86_cpu);
-                         cpu->exception_index = EXCP_HALTED;
-                         cpu_loop_exit(cpu);
-                     }
- #else
-                     else if (interrupt_request & CPU_INTERRUPT_RESET) {
-                         replay_interrupt();
-                         cpu_reset(cpu);
-                         cpu_loop_exit(cpu);
-                     }
- #endif
-                     /* The target hook has 3 exit conditions:
-                        False when the interrupt isn't processed,
-                        True when it is, and we should restart on a new TB,
-                        and via longjmp via cpu_loop_exit.  */
-                     else {
-                         replay_interrupt();
-                         if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
-                             next_tb = 0;
-                         }
-                     }
-                     /* Don't use the cached interrupt_request value,
-                        do_interrupt may have updated the EXITTB flag. */
-                     if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
-                         cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
-                         /* ensure that no TB jump will be modified as
-                            the program flow was changed */
-                         next_tb = 0;
-                     }
-                 }
-                 if (unlikely(cpu->exit_request
-                              || replay_has_interrupt())) {
-                     cpu->exit_request = 0;
-                     cpu->exception_index = EXCP_INTERRUPT;
-                     cpu_loop_exit(cpu);
-                 }
-                 tb_lock();
-                 tb = tb_find_fast(cpu);
-                 /* Note: we do it here to avoid a gcc bug on Mac OS X when
-                    doing it in tb_find_slow */
-                 if (tcg_ctx.tb_ctx.tb_invalidated_flag) {
-                     /* as some TB could have been invalidated because
-                        of memory exceptions while generating the code, we
-                        must recompute the hash index here */
-                     next_tb = 0;
-                     tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
-                 }
-                 /* see if we can patch the calling TB. When the TB
-                    spans two pages, we cannot safely do a direct
-                    jump. */
-                 if (next_tb != 0 && tb->page_addr[1] == -1
-                     && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
-                     tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
-                                 next_tb & TB_EXIT_MASK, tb);
-                 }
-                 tb_unlock();
-                 if (likely(!cpu->exit_request)) {
-                     trace_exec_tb(tb, tb->pc);
-                     /* execute the generated code */
-                     cpu->current_tb = tb;
-                     next_tb = cpu_tb_exec(cpu, tb);
-                     cpu->current_tb = NULL;
-                     switch (next_tb & TB_EXIT_MASK) {
-                     case TB_EXIT_REQUESTED:
-                         /* Something asked us to stop executing
-                          * chained TBs; just continue round the main
-                          * loop. Whatever requested the exit will also
-                          * have set something else (eg exit_request or
-                          * interrupt_request) which we will handle
-                          * next time around the loop.  But we need to
-                          * ensure the tcg_exit_req read in generated code
-                          * comes before the next read of cpu->exit_request
-                          * or cpu->interrupt_request.
-                          */
-                         smp_rmb();
-                         next_tb = 0;
-                         break;
-                     case TB_EXIT_ICOUNT_EXPIRED:
-                     {
-                         /* Instruction counter expired.  */
-                         int insns_left = cpu->icount_decr.u32;
-                         if (cpu->icount_extra && insns_left >= 0) {
-                             /* Refill decrementer and continue execution.  */
-                             cpu->icount_extra += insns_left;
-                             insns_left = MIN(0xffff, cpu->icount_extra);
-                             cpu->icount_extra -= insns_left;
-                             cpu->icount_decr.u16.low = insns_left;
-                         } else {
-                             if (insns_left > 0) {
-                                 /* Execute remaining instructions.  */
-                                 tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
-                                 cpu_exec_nocache(cpu, insns_left, tb, false);
-                                 align_clocks(&sc, cpu);
-                             }
-                             cpu->exception_index = EXCP_INTERRUPT;
-                             next_tb = 0;
-                             cpu_loop_exit(cpu);
-                         }
-                         break;
-                     }
-                     default:
-                         break;
-                     }
-                 }
+                 cpu_handle_interrupt(cpu, &last_tb);
+                 tb = tb_find_fast(cpu, &last_tb, tb_exit);
+                 cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc);
 +#ifdef CONFIG_HAX
 +                if (hax_enabled() && hax_stop_emulation(cpu))
 +                    cpu_loop_exit(cpu);
 +#endif
                  /* Try to align the host and virtual clocks
                     if the guest is in advance */
                  align_clocks(&sc, cpu);
diff --cc cpus.c
--- 1/cpus.c
--- 2/cpus.c
+++ b/cpus.c
@@@ -33,8 -34,8 +34,9 @@@
  #include "exec/gdbstub.h"
  #include "sysemu/dma.h"
  #include "sysemu/kvm.h"
 +#include "sysemu/hax.h"
  #include "qmp-commands.h"
+ #include "exec/exec-all.h"
  
  #include "qemu/thread.h"
  #include "sysemu/cpus.h"
diff --cc exec.c
--- 1/exec.c
--- 2/exec.c
+++ b/exec.c
  
  #include "qemu/cutils.h"
  #include "cpu.h"
+ #include "exec/exec-all.h"
  #include "tcg.h"
- #include "hw/hw.h"
+ #include "hw/qdev-core.h"
  #if !defined(CONFIG_USER_ONLY)
  #include "hw/boards.h"
+ #include "hw/xen/xen.h"
  #endif
- #include "hw/qdev.h"
  #include "sysemu/kvm.h"
 +#include "sysemu/hax.h"
  #include "sysemu/sysemu.h"
- #include "hw/xen/xen.h"
  #include "qemu/timer.h"
  #include "qemu/config-file.h"
  #include "qemu/error-report.h"
Simple merge
Simple merge
@@@ -1,12 -1,6 +1,12 @@@
- #ifndef _QEMU_9P_MARSHAL_H
- #define _QEMU_9P_MARSHAL_H
+ #ifndef QEMU_9P_MARSHAL_H
+ #define QEMU_9P_MARSHAL_H
  
 +#ifdef CONFIG_MARU
 +#ifdef CONFIG_WIN32
 +#include "tizen/src/resources_win32.h"
 +#endif
 +#endif
 +
  typedef struct V9fsString
  {
      uint16_t size;
   * the COPYING file in the top-level directory.
   *
   */
- #ifndef _FILEOP_H
- #define _FILEOP_H
+ #ifndef FILE_OP_9P_H
+ #define FILE_OP_9P_H
  
 +#ifndef CONFIG_MARU
 +
  #include <dirent.h>
  #include <utime.h>
- #include <sys/uio.h>
  #include <sys/vfs.h>
  
 +#else /* if defiend CONFIG_MARU */
 +
 +#include <dirent.h>
 +#include <utime.h>
 +
 +#ifndef CONFIG_WIN32
 +#include <sys/uio.h>
 +#endif
 +
 +#ifdef CONFIG_LINUX
 +#include <sys/vfs.h>
 +#endif
 +
 +#ifdef CONFIG_DARWIN
 +#include <sys/param.h>
 +#include <sys/mount.h>
 +#endif
 +
 +#ifdef CONFIG_WIN32
 +#include "tizen/src/resources_win32.h"
 +#endif
 +
 +#endif /* CONFIG_MARU */
 +
  #define SM_LOCAL_MODE_BITS    0600
  #define SM_LOCAL_DIR_MODE_BITS    0700
  
Simple merge
Simple merge
diff --cc hmp-commands.hx
Simple merge
diff --cc hmp.c
Simple merge
diff --cc hmp.h
Simple merge
index c794b90,0000000..d2f4931
mode 100644,000000..100644
--- /dev/null
@@@ -1,1833 -1,0 +1,1834 @@@
-     return closedir(fs->dir);
 +/*
 + * Virtio 9p backend for Maru
 + * Based on hw/9pfs/virtio-9p-local.c:
 + *
 + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 + *
 + * Contact:
 + *  Sooyoung Ha <yoosah.ha@samsung.com>
 + *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#include "qemu/osdep.h"
 +#include "9p.h"
 +#include "fsdev/qemu-fsdev.h"   /* local_ops */
 +#ifndef CONFIG_WIN32
 +#include "9p-xattr.h"
 +#include <arpa/inet.h>
 +#include <pwd.h>
 +#include <grp.h>
 +#include <sys/socket.h>
 +#include <sys/un.h>
 +#include "qemu/xattr.h"
 +#endif
 +#include "qemu/cutils.h"
 +#include "qemu/error-report.h"
 +#include <libgen.h>
 +#ifdef CONFIG_LINUX
 +#include <linux/fs.h>
 +#endif
 +#ifdef CONFIG_LINUX_MAGIC_H
 +#include <linux/magic.h>
 +#endif
 +#ifndef CONFIG_WIN32
 +#include <sys/ioctl.h>
 +#endif
 +
 +#include "tizen/src/util/new_debug_ch.h"
 +DECLARE_DEBUG_CHANNEL(9pfs_local);
 +
 +#ifndef XFS_SUPER_MAGIC
 +#define XFS_SUPER_MAGIC  0x58465342
 +#endif
 +#ifndef EXT2_SUPER_MAGIC
 +#define EXT2_SUPER_MAGIC 0xEF53
 +#endif
 +#ifndef REISERFS_SUPER_MAGIC
 +#define REISERFS_SUPER_MAGIC 0x52654973
 +#endif
 +#ifndef BTRFS_SUPER_MAGIC
 +#define BTRFS_SUPER_MAGIC 0x9123683E
 +#endif
 +
 +#ifdef CONFIG_WIN32
 +#ifndef MSDOS_SUPER_MAGIC
 +#define MSDOS_SUPER_MAGIC 0x4d44
 +#endif
 +#ifndef NTFS_SUPER_MAGIC
 +#define NTFS_SUPER_MAGIC 0x5346544e
 +#endif
 +
 +uint64_t hostBytesPerSector = -1;
 +#endif
 +
 +#define VIRTFS_META_DIR ".virtfs_metadata"
 +
 +#ifndef AT_REMOVEDIR
 +#define AT_REMOVEDIR 0x200
 +#endif
 +
 +static char *local_mapped_attr_path(FsContext *ctx, const char *path)
 +{
 +    int dirlen;
 +    const char *name = strrchr(path, '/');
 +    if (name) {
 +        dirlen = name - path;
 +        ++name;
 +    } else {
 +        name = path;
 +        dirlen = 0;
 +    }
 +#ifndef CONFIG_WIN32
 +    return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root,
 +                           dirlen, path, VIRTFS_META_DIR, name);
 +#else
 +    char *buffer = g_strdup_printf("%s\\%.*s\\%s\\%s", ctx->fs_root,
 +                           dirlen, path, VIRTFS_META_DIR, name);
 +    while(buffer[strlen(buffer)-1] == '\\'){
 +        buffer[strlen(buffer)-1] = '\0';
 +    }
 +    return buffer;
 +#endif
 +}
 +
 +static FILE *local_fopen(const char *path, const char *mode)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int fd;
 +#ifndef CONFIG_WIN32
 +    int o_mode = 0;
 +#endif
 +    FILE *fp;
 +    int flags = O_NOFOLLOW;
 +    /*
 +     * only supports two modes
 +     */
 +    if (mode[0] == 'r') {
 +        flags |= O_RDONLY;
 +    } else if (mode[0] == 'w') {
 +        flags |= O_WRONLY | O_TRUNC | O_CREAT;
 +#ifndef CONFIG_WIN32
 +        o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
 +#endif
 +    } else {
 +        return NULL;
 +    }
 +#ifndef CONFIG_WIN32
 +    fd = open(path, flags, o_mode);
 +#else
 +    fd = open(path, flags | O_BINARY);
 +#endif
 +    if (fd == -1) {
 +        return NULL;
 +    }
 +    fp = fdopen(fd, mode);
 +    if (!fp) {
 +        close(fd);
 +    }
 +    return fp;
 +}
 +
 +#define ATTR_MAX 100
 +#ifndef CONFIG_WIN32
 +static void local_mapped_file_attr(FsContext *ctx, const char *path,
 +                                   struct stat *stbuf)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    FILE *fp;
 +    char buf[ATTR_MAX];
 +    char *attr_path;
 +
 +    attr_path = local_mapped_attr_path(ctx, path);
 +    fp = local_fopen(attr_path, "r");
 +    g_free(attr_path);
 +    if (!fp) {
 +        return;
 +    }
 +    memset(buf, 0, ATTR_MAX);
 +    while (fgets(buf, ATTR_MAX, fp)) {
 +        if (!strncmp(buf, "virtfs.uid", 10)) {
 +            stbuf->st_uid = atoi(buf+11);
 +        } else if (!strncmp(buf, "virtfs.gid", 10)) {
 +            stbuf->st_gid = atoi(buf+11);
 +        } else if (!strncmp(buf, "virtfs.mode", 11)) {
 +            stbuf->st_mode = atoi(buf+12);
 +        } else if (!strncmp(buf, "virtfs.rdev", 11)) {
 +            stbuf->st_rdev = atoi(buf+12);
 +        }
 +        memset(buf, 0, ATTR_MAX);
 +    }
 +    fclose(fp);
 +}
 +#endif
 +
 +static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    char *buffer;
 +    char *path = fs_path->data;
 +
 +    buffer = rpath(fs_ctx, path);
 +#ifndef CONFIG_WIN32
 +    err =  lstat(buffer, stbuf);
 +    if (err) {
 +        goto err_out;
 +    }
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        /* Actual credentials are part of extended attrs */
 +        uid_t tmp_uid;
 +        gid_t tmp_gid;
 +        mode_t tmp_mode;
 +        dev_t tmp_dev;
 +#ifdef CONFIG_LINUX
 +        if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
 +            stbuf->st_uid = le32_to_cpu(tmp_uid);
 +        }
 +        if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
 +            stbuf->st_gid = le32_to_cpu(tmp_gid);
 +        }
 +        if (getxattr(buffer, "user.virtfs.mode",
 +                    &tmp_mode, sizeof(mode_t)) > 0) {
 +            stbuf->st_mode = le32_to_cpu(tmp_mode);
 +        }
 +        if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
 +            stbuf->st_rdev = le64_to_cpu(tmp_dev);
 +        }
 +#else
 +        /*
 +         *  extra two parameters on Mac OS X.
 +         *  first one is position which specifies an offset within the extended attribute.
 +         *  i.e. extended attribute means "user.virtfs.uid". Currently, it is only used with
 +         *  resource fork attribute and all other extended attributes, it is reserved and should be zero.
 +         *  second one is options which specify option for retrieving extended attributes:
 +         *  (XATTR_NOFOLLOW, XATTR_SHOWCOMPRESSION)
 +         */
 +        if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0, 0) > 0) {
 +            stbuf->st_uid = le32_to_cpu(tmp_uid);
 +        }
 +        if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0, 0) > 0) {
 +            stbuf->st_gid = le32_to_cpu(tmp_gid);
 +        }
 +        if (getxattr(buffer, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0, 0) > 0) {
 +            stbuf->st_mode = le32_to_cpu(tmp_mode);
 +        }
 +        if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t), 0, 0) > 0) {
 +            stbuf->st_rdev = le64_to_cpu(tmp_dev);
 +        }
 +#endif
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        local_mapped_file_attr(fs_ctx, path, stbuf);
 +    }
 +
 +err_out:
 +#else
 +    const char * pathname = buffer;
 +    if (hostBytesPerSector == -1) {
 +        DWORD BytesPerSector;
 +        TCHAR tmpName[PATH_MAX] = {0};
 +
 +        strncpy(tmpName, pathname, 3 > PATH_MAX ? PATH_MAX : 3);
 +        tmpName[4 > PATH_MAX ? PATH_MAX : 4] = '\0';
 +        LPCTSTR RootPathName = (LPCTSTR)tmpName;
 +
 +        GetDiskFreeSpace(RootPathName, NULL, &BytesPerSector, NULL, NULL);
 +        hostBytesPerSector = BytesPerSector;
 +    }
 +    /* TODO
 +     * We should check how this works.
 +     */
 +    err = stat(pathname, stbuf);
 +
 +    /* Modify the permission to 777 except the directories. */
 +    stbuf->st_mode = stbuf->st_mode | 0777;
 +#endif
 +    g_free(buffer);
 +    return err;
 +}
 +
 +static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    char *attr_dir;
 +    char *tmp_path = g_strdup(path);
 +
 +#ifndef CONFIG_WIN32
 +    attr_dir = g_strdup_printf("%s/%s/%s",
 +             ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
 +
 +    err = mkdir(attr_dir, 0700);
 +#else
 +    attr_dir = g_strdup_printf("%s\\%s\\%s",
 +             ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
 +    err = mkdir(attr_dir);
 +#endif
 +    if (err < 0 && errno == EEXIST) {
 +        err = 0;
 +    }
 +    g_free(attr_dir);
 +    g_free(tmp_path);
 +    return err;
 +}
 +
 +static int local_set_mapped_file_attr(FsContext *ctx,
 +                                      const char *path, FsCred *credp)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    FILE *fp;
 +    int ret = 0;
 +    char buf[ATTR_MAX];
 +    char *attr_path;
 +    int uid = -1, gid = -1, mode = -1, rdev = -1;
 +
 +    attr_path = local_mapped_attr_path(ctx, path);
 +    fp = local_fopen(attr_path, "r");
 +    if (!fp) {
 +        goto create_map_file;
 +    }
 +    memset(buf, 0, ATTR_MAX);
 +    while (fgets(buf, ATTR_MAX, fp)) {
 +        if (!strncmp(buf, "virtfs.uid", 10)) {
 +            uid = atoi(buf+11);
 +        } else if (!strncmp(buf, "virtfs.gid", 10)) {
 +            gid = atoi(buf+11);
 +        } else if (!strncmp(buf, "virtfs.mode", 11)) {
 +            mode = atoi(buf+12);
 +        } else if (!strncmp(buf, "virtfs.rdev", 11)) {
 +            rdev = atoi(buf+12);
 +        }
 +        memset(buf, 0, ATTR_MAX);
 +    }
 +    fclose(fp);
 +    goto update_map_file;
 +
 +create_map_file:
 +    ret = local_create_mapped_attr_dir(ctx, path);
 +    if (ret < 0) {
 +        goto err_out;
 +    }
 +
 +update_map_file:
 +    fp = local_fopen(attr_path, "w");
 +    if (!fp) {
 +        ret = -1;
 +        goto err_out;
 +    }
 +
 +    if (credp->fc_uid != -1) {
 +        uid = credp->fc_uid;
 +    }
 +    if (credp->fc_gid != -1) {
 +        gid = credp->fc_gid;
 +    }
 +#ifndef CONFIG_WIN32
 +    if (credp->fc_mode != (mode_t)-1) {
 +        mode = credp->fc_mode;
 +    }
 +#else
 +    mode = credp->fc_mode;
 +#endif
 +    if (credp->fc_rdev != -1) {
 +        rdev = credp->fc_rdev;
 +    }
 +
 +
 +    if (uid != -1) {
 +        fprintf(fp, "virtfs.uid=%d\n", uid);
 +    }
 +    if (gid != -1) {
 +        fprintf(fp, "virtfs.gid=%d\n", gid);
 +    }
 +    if (mode != -1) {
 +        fprintf(fp, "virtfs.mode=%d\n", mode);
 +    }
 +    if (rdev != -1) {
 +        fprintf(fp, "virtfs.rdev=%d\n", rdev);
 +    }
 +    fclose(fp);
 +
 +err_out:
 +    g_free(attr_path);
 +    return ret;
 +}
 +
 +#ifndef CONFIG_WIN32
 +static int local_set_xattr(const char *path, FsCred *credp)
 +{
 +    int err;
 +
 +#ifdef CONFIG_LINUX
 +    if (credp->fc_uid != -1) {
 +        uint32_t tmp_uid = cpu_to_le32(credp->fc_uid);
 +        err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0);
 +        if (err) {
 +            return err;
 +        }
 +    }
 +    if (credp->fc_gid != -1) {
 +        uint32_t tmp_gid = cpu_to_le32(credp->fc_gid);
 +        err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0);
 +        if (err) {
 +            return err;
 +        }
 +    }
 +    if (credp->fc_mode != -1) {
 +        uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
 +        err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0);
 +        if (err) {
 +            return err;
 +        }
 +    }
 +    if (credp->fc_rdev != -1) {
 +        uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev);
 +        err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0);
 +        if (err) {
 +            return err;
 +        }
 +    }
 +#else
 +    /*
 +     * In case of setxattr on OS X, position parameter has been added.
 +     * Its purpose is the same as getxattr. Last parameter options is the same as flags on Linux.
 +     * XATTR_NOFOLLOW / XATTR_CREATE / XATTR_REPLACE
 +     */
 +    if (credp->fc_uid != -1) {
 +        err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
 +                 0, 0);
 +         if (err) {
 +             return err;
 +         }
 +     }
 +     if (credp->fc_gid != -1) {
 +         err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
 +                 0, 0);
 +         if (err) {
 +             return err;
 +         }
 +     }
 +     if (credp->fc_mode != (mode_t)-1) {
 +         err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
 +                 sizeof(mode_t), 0, 0);
 +         if (err) {
 +             return err;
 +         }
 +     }
 +     if (credp->fc_rdev != -1) {
 +         err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
 +                 sizeof(dev_t), 0, 0);
 +         if (err) {
 +             return err;
 +         }
 +     }
 +#endif
 +
 +    return 0;
 +}
 +#endif
 +
 +static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
 +                                         FsCred *credp)
 +{
 +#ifndef CONFIG_WIN32
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *buffer;
 +
 +    buffer = rpath(fs_ctx, path);
 +    if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
 +        /*
 +         * If we fail to change ownership and if we are
 +         * using security model none. Ignore the error
 +         */
 +        if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
 +            goto err;
 +        }
 +    }
 +
 +    if (chmod(buffer, credp->fc_mode & 07777) < 0) {
 +        goto err;
 +    }
 +
 +    g_free(buffer);
 +    return 0;
 +err:
 +    g_free(buffer);
 +    return -1;
 +#else //CONFIG_WIN32
 +    /* chown doesn't matter with the Windows environment. */
 +    return 0;
 +#endif
 +}
 +
 +static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
 +                              char *buf, size_t bufsz)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    ssize_t tsize = -1;
 +#ifndef CONFIG_WIN32
 +    char *buffer;
 +    char *path = fs_path->data;
 +
 +    if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
 +        (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
 +        int fd;
 +        buffer = rpath(fs_ctx, path);
 +        fd = open(buffer, O_RDONLY | O_NOFOLLOW);
 +        g_free(buffer);
 +        if (fd == -1) {
 +            return -1;
 +        }
 +        do {
 +            tsize = read(fd, (void *)buf, bufsz);
 +        } while (tsize == -1 && errno == EINTR);
 +        close(fd);
 +    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +               (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, path);
 +        tsize = readlink(buffer, buf, bufsz);
 +        g_free(buffer);
 +    }
 +#endif
 +    return tsize;
 +}
 +
 +static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    return close(fs->fd);
 +}
 +
 +static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
-     fs->dir = opendir(buffer);
++    return closedir(fs->dir.stream);
 +}
 +
 +static int local_open(FsContext *ctx, V9fsPath *fs_path,
 +                      int flags, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *buffer;
 +    char *path = fs_path->data;
 +
 +    buffer = rpath(ctx, path);
 +#ifdef CONFIG_WIN32
 +    flags |= O_BINARY;
 +#endif
 +    fs->fd = open(buffer, flags | O_NOFOLLOW);
 +    g_free(buffer);
 +    return fs->fd;
 +}
 +
 +static int local_opendir(FsContext *ctx,
 +                         V9fsPath *fs_path, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *buffer;
 +    char *path = fs_path->data;
 +
 +    buffer = rpath(ctx, path);
-     if (!fs->dir) {
++    fs->dir.stream = opendir(buffer);
 +    g_free(buffer);
-     rewinddir(fs->dir);
++    if (!fs->dir.stream) {
 +        return -1;
 +    }
 +    return 0;
 +}
 +
 +static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
-     return telldir(fs->dir);
++    rewinddir(fs->dir.stream);
 +}
 +
 +static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
- static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
-                            struct dirent *entry,
-                            struct dirent **result)
++    return telldir(fs->dir.stream);
 +}
 +
-     int ret;
++static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
-     ret = readdir_r(fs->dir, entry, result);
++    struct dirent *entry;
 +
 +again:
 +#ifndef CONFIG_WIN32
-         if (!ret && *result != NULL &&
-             !strcmp(entry->d_name, VIRTFS_META_DIR)) {
++    entry = readdir(fs->dir.stream);
++    if (!entry) {
++        return NULL;
++    }
++
 +    if (ctx->export_flags & V9FS_SM_MAPPED) {
 +        entry->d_type = DT_UNKNOWN;
 +    } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
-     ret = errno;
-     *result = readdir(fs->dir);
++        if (!strcmp(entry->d_name, VIRTFS_META_DIR)) {
 +            /* skp the meta data directory */
 +            goto again;
 +        }
 +        entry->d_type = DT_UNKNOWN;
 +    }
 +#else
-     return ret;
++    int ret = errno;
++    *result = readdir(fs->dir.stream);
 +    ret = (ret == errno ? 0 : errno);
 +    entry = *result;
 +    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        if (!ret && *result != NULL &&
 +                !strcmp(entry->d_name, VIRTFS_META_DIR)) {
 +            /* skp the meta data directory */
 +            goto again;
 +        }
 +    }
 +#endif
-     seekdir(fs->dir, off);
++    return entry;
 +}
 +
 +static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
-         fd = dirfd(fs->dir);
++    seekdir(fs->dir.stream, off);
 +}
 +
 +static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
 +                            const struct iovec *iov,
 +                            int iovcnt, off_t offset)
 +{
 +#ifdef CONFIG_PREADV
 +    return preadv(fs->fd, iov, iovcnt, offset);
 +#else
 +    int err = lseek(fs->fd, offset, SEEK_SET);
 +    if (err == -1) {
 +        return err;
 +    } else {
 +        return readv(fs->fd, iov, iovcnt);
 +    }
 +#endif
 +}
 +
 +static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
 +                             const struct iovec *iov,
 +                             int iovcnt, off_t offset)
 +{
 +    ssize_t ret;
 +
 +#ifdef CONFIG_PREADV
 +    ret = pwritev(fs->fd, iov, iovcnt, offset);
 +#else
 +    int err = lseek(fs->fd, offset, SEEK_SET);
 +    if (err == -1) {
 +        return err;
 +    } else {
 +        ret = writev(fs->fd, iov, iovcnt);
 +    }
 +#endif
 +#ifdef CONFIG_SYNC_FILE_RANGE
 +    if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
 +        /*
 +         * Initiate a writeback. This is not a data integrity sync.
 +         * We want to ensure that we don't leave dirty pages in the cache
 +         * after write when writeout=immediate is sepcified.
 +         */
 +        sync_file_range(fs->fd, offset, ret,
 +                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
 +    }
 +#endif
 +    return ret;
 +}
 +
 +static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +#ifndef CONFIG_WIN32
 +    char *buffer;
 +    int ret = -1;
 +    char *path = fs_path->data;
 +
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        buffer = rpath(fs_ctx, path);
 +        ret = local_set_xattr(buffer, credp);
 +        g_free(buffer);
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        return local_set_mapped_file_attr(fs_ctx, path, credp);
 +    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +               (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, path);
 +        ret = chmod(buffer, credp->fc_mode);
 +        g_free(buffer);
 +    }
 +    return ret;
 +#else
 +    return -1;
 +#endif
 +}
 +
 +static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
 +                       const char *name, FsCred *credp)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +#ifndef CONFIG_WIN32
 +    char *path;
 +    int err = -1;
 +    int serrno = 0;
 +    V9fsString fullname;
 +    char *buffer = NULL;
 +
 +    v9fs_string_init(&fullname);
 +    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
 +    path = fullname.data;
 +
 +    /* Determine the security model */
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        buffer = rpath(fs_ctx, path);
 +        err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
 +        if (err == -1) {
 +            goto out;
 +        }
 +        err = local_set_xattr(buffer, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +
 +        buffer = rpath(fs_ctx, path);
 +        err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
 +        if (err == -1) {
 +            goto out;
 +        }
 +        err = local_set_mapped_file_attr(fs_ctx, path, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +               (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, path);
 +        err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
 +        if (err == -1) {
 +            goto out;
 +        }
 +        err = local_post_create_passthrough(fs_ctx, path, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    }
 +    goto out;
 +
 +err_end:
 +    remove(buffer);
 +    errno = serrno;
 +out:
 +    g_free(buffer);
 +    v9fs_string_free(&fullname);
 +    return err;
 +#else
 +    return -1;
 +#endif
 +}
 +
 +static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
 +                       const char *name, FsCred *credp)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *path;
 +    int err = -1;
 +#ifndef CONFIG_WIN32
 +    int serrno = 0;
 +#endif
 +    V9fsString fullname;
 +    char *buffer = NULL;
 +
 +    v9fs_string_init(&fullname);
 +#ifndef CONFIG_WIN32
 +    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
 +#else
 +    v9fs_string_sprintf(&fullname, "%s\\%s", dir_path->data, name);
 +    while((fullname.data)[strlen(fullname.data)-1] == '\\'){
 +        (fullname.data)[strlen(fullname.data)-1] = '\0';
 +    }
 +#endif
 +    path = fullname.data;
 +
 +#ifndef CONFIG_WIN32
 +    /* Determine the security model */
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        buffer = rpath(fs_ctx, path);
 +        err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
 +        if (err == -1) {
 +            goto out;
 +        }
 +        credp->fc_mode = credp->fc_mode|S_IFDIR;
 +        err = local_set_xattr(buffer, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        buffer = rpath(fs_ctx, path);
 +        err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
 +        if (err == -1) {
 +            goto out;
 +        }
 +        credp->fc_mode = credp->fc_mode|S_IFDIR;
 +        err = local_set_mapped_file_attr(fs_ctx, path, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +               (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, path);
 +        err = mkdir(buffer, credp->fc_mode);
 +        if (err == -1) {
 +            goto out;
 +        }
 +        err = local_post_create_passthrough(fs_ctx, path, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    }
 +#else
 +    buffer = rpath(fs_ctx, path);
 +    err = mkdir(buffer);
 +#endif
 +    goto out;
 +
 +#ifndef CONFIG_WIN32
 +err_end:
 +    remove(buffer);
 +    errno = serrno;
 +#endif
 +out:
 +    g_free(buffer);
 +    v9fs_string_free(&fullname);
 +    return err;
 +}
 +
 +static int local_fstat(FsContext *fs_ctx, int fid_type,
 +                       V9fsFidOpenState *fs, struct stat *stbuf)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err, fd;
 +
 +    if (fid_type == P9_FID_DIR) {
 +#ifndef CONFIG_WIN32
-         fd = dirfd(fs->dir);
++        fd = dirfd(fs->dir.stream);
 +#else
 +        fd = fs->fd;
 +#endif
 +    } else {
 +        fd = fs->fd;
 +    }
 +
 +    err = fstat(fd, stbuf);
 +    if (err) {
 +        return err;
 +    }
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +#ifndef CONFIG_WIN32
 +        /* Actual credentials are part of extended attrs */
 +        uid_t tmp_uid;
 +        gid_t tmp_gid;
 +        mode_t tmp_mode;
 +        dev_t tmp_dev;
 +
 +#ifdef CONFIG_LINUX
 +        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
 +            stbuf->st_uid = le32_to_cpu(tmp_uid);
 +        }
 +        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
 +            stbuf->st_gid = le32_to_cpu(tmp_gid);
 +        }
 +        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
 +            stbuf->st_mode = le32_to_cpu(tmp_mode);
 +        }
 +        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
 +            stbuf->st_rdev = le64_to_cpu(tmp_dev);
 +        }
 +#else
 +        if (fgetxattr(fd, "user.virtfs.uid",
 +                      &tmp_uid, sizeof(uid_t), 0, 0) > 0) {
 +            stbuf->st_uid = le32_to_cpu(tmp_uid);
 +        }
 +        if (fgetxattr(fd, "user.virtfs.gid",
 +                      &tmp_gid, sizeof(gid_t), 0, 0) > 0) {
 +            stbuf->st_gid = le32_to_cpu(tmp_gid);
 +        }
 +        if (fgetxattr(fd, "user.virtfs.mode",
 +                      &tmp_mode, sizeof(mode_t), 0, 0) > 0) {
 +            stbuf->st_mode = le32_to_cpu(tmp_mode);
 +        }
 +        if (fgetxattr(fd, "user.virtfs.rdev",
 +                      &tmp_dev, sizeof(dev_t), 0, 0) > 0) {
 +                stbuf->st_rdev = le64_to_cpu(tmp_dev);
 +        }
 +#endif
 +#endif
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        errno = EOPNOTSUPP;
 +        return -1;
 +    }
 +    return err;
 +}
 +
 +static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
 +                       int flags, FsCred *credp, V9fsFidOpenState *fs)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *path;
 +    int fd = -1;
 +    int err = -1;
 +    int serrno = 0;
 +    V9fsString fullname;
 +    char *buffer = NULL;
 +
 +    /*
 +     * Mark all the open to not follow symlinks
 +     */
 +    flags |= O_NOFOLLOW;
 +
 +    v9fs_string_init(&fullname);
 +#ifndef CONFIG_WIN32
 +    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
 +#else
 +    v9fs_string_sprintf(&fullname, "%s\\%s", dir_path->data, name);
 +    flags |= O_BINARY;
 +#endif
 +    path = fullname.data;
 +
 +    /* Determine the security model */
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        buffer = rpath(fs_ctx, path);
 +        fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
 +        if (fd == -1) {
 +            err = fd;
 +            goto out;
 +        }
 +#ifndef CONFIG_WIN32
 +        credp->fc_mode = credp->fc_mode|S_IFREG;
 +        /* Set cleint credentials in xattr */
 +        err = local_set_xattr(buffer, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +#endif
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        buffer = rpath(fs_ctx, path);
 +        fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
 +        if (fd == -1) {
 +            err = fd;
 +            goto out;
 +        }
 +        credp->fc_mode = credp->fc_mode|S_IFREG;
 +        /* Set client credentials in .virtfs_metadata directory files */
 +        err = local_set_mapped_file_attr(fs_ctx, path, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +               (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, path);
 +        fd = open(buffer, flags, credp->fc_mode);
 +        if (fd == -1) {
 +            err = fd;
 +            goto out;
 +        }
 +        err = local_post_create_passthrough(fs_ctx, path, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    }
 +    err = fd;
 +    fs->fd = fd;
 +    goto out;
 +
 +err_end:
 +    close(fd);
 +    remove(buffer);
 +    errno = serrno;
 +out:
 +    g_free(buffer);
 +    v9fs_string_free(&fullname);
 +    return err;
 +}
 +
 +
 +static int local_symlink(FsContext *fs_ctx, const char *oldpath,
 +                         V9fsPath *dir_path, const char *name, FsCred *credp)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err = -1;
 +#ifndef CONFIG_WIN32
 +    int serrno = 0;
 +    char *newpath;
 +    V9fsString fullname;
 +    char *buffer = NULL;
 +
 +    v9fs_string_init(&fullname);
 +    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
 +    newpath = fullname.data;
 +
 +    /* Determine the security model */
 +    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        int fd;
 +        ssize_t oldpath_size, write_size;
 +        buffer = rpath(fs_ctx, newpath);
 +        fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
 +        if (fd == -1) {
 +            err = fd;
 +            goto out;
 +        }
 +        /* Write the oldpath (target) to the file. */
 +        oldpath_size = strlen(oldpath);
 +        do {
 +            write_size = write(fd, (void *)oldpath, oldpath_size);
 +        } while (write_size == -1 && errno == EINTR);
 +
 +        if (write_size != oldpath_size) {
 +            serrno = errno;
 +            close(fd);
 +            err = -1;
 +            goto err_end;
 +        }
 +        close(fd);
 +        /* Set cleint credentials in symlink's xattr */
 +        credp->fc_mode = credp->fc_mode|S_IFLNK;
 +        err = local_set_xattr(buffer, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        int fd;
 +        ssize_t oldpath_size, write_size;
 +        buffer = rpath(fs_ctx, newpath);
 +        fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
 +        if (fd == -1) {
 +            err = fd;
 +            goto out;
 +        }
 +        /* Write the oldpath (target) to the file. */
 +        oldpath_size = strlen(oldpath);
 +        do {
 +            write_size = write(fd, (void *)oldpath, oldpath_size);
 +        } while (write_size == -1 && errno == EINTR);
 +
 +        if (write_size != oldpath_size) {
 +            serrno = errno;
 +            close(fd);
 +            err = -1;
 +            goto err_end;
 +        }
 +        close(fd);
 +        /* Set cleint credentials in symlink's xattr */
 +        credp->fc_mode = credp->fc_mode|S_IFLNK;
 +        err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
 +        if (err == -1) {
 +            serrno = errno;
 +            goto err_end;
 +        }
 +    } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +               (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, newpath);
 +        err = symlink(oldpath, buffer);
 +        if (err) {
 +            goto out;
 +        }
 +        err = lchown(buffer, credp->fc_uid, credp->fc_gid);
 +        if (err == -1) {
 +            /*
 +             * If we fail to change ownership and if we are
 +             * using security model none. Ignore the error
 +             */
 +            if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
 +                serrno = errno;
 +                goto err_end;
 +            } else
 +                err = 0;
 +        }
 +    }
 +    goto out;
 +
 +err_end:
 +    remove(buffer);
 +    errno = serrno;
 +out:
 +    g_free(buffer);
 +    v9fs_string_free(&fullname);
 +#endif
 +    return err;
 +}
 +
 +static int local_link(FsContext *ctx, V9fsPath *oldpath,
 +                      V9fsPath *dirpath, const char *name)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +#ifndef CONFIG_WIN32
 +    int ret;
 +    V9fsString newpath;
 +    char *buffer, *buffer1;
 +
 +    v9fs_string_init(&newpath);
 +    v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
 +
 +    buffer = rpath(ctx, oldpath->data);
 +    buffer1 = rpath(ctx, newpath.data);
 +    ret = link(buffer, buffer1);
 +    g_free(buffer);
 +    g_free(buffer1);
 +
 +    /* now link the virtfs_metadata files */
 +    if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
 +        /* Link the .virtfs_metadata files. Create the metada directory */
 +        ret = local_create_mapped_attr_dir(ctx, newpath.data);
 +        if (ret < 0) {
 +            goto err_out;
 +        }
 +        buffer = local_mapped_attr_path(ctx, oldpath->data);
 +        buffer1 = local_mapped_attr_path(ctx, newpath.data);
 +        ret = link(buffer, buffer1);
 +        g_free(buffer);
 +        g_free(buffer1);
 +        if (ret < 0 && errno != ENOENT) {
 +            goto err_out;
 +        }
 +    }
 +err_out:
 +    v9fs_string_free(&newpath);
 +    return ret;
 +#else
 +    return -1;
 +#endif
 +}
 +
 +static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *buffer;
 +    int ret;
 +    char *path = fs_path->data;
 +
 +    buffer = rpath(ctx, path);
 +#ifndef CONFIG_WIN32
 +    ret = truncate(buffer, size);
 +#else
 +    int fd = open(buffer, O_RDWR | O_BINARY | O_NOFOLLOW);
 +    if(fd < 0) {
 +        ret = -1;
 +    } else {
 +        ret = ftruncate(fd, size);
 +        close(fd);
 +    }
 +#endif
 +    g_free(buffer);
 +    return ret;
 +}
 +
 +static int local_rename(FsContext *ctx, const char *oldpath,
 +                        const char *newpath)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    char *buffer, *buffer1;
 +
 +    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        err = local_create_mapped_attr_dir(ctx, newpath);
 +        if (err < 0) {
 +            return err;
 +        }
 +        /* rename the .virtfs_metadata files */
 +        buffer = local_mapped_attr_path(ctx, oldpath);
 +        buffer1 = local_mapped_attr_path(ctx, newpath);
 +        err = rename(buffer, buffer1);
 +        g_free(buffer);
 +        g_free(buffer1);
 +        if (err < 0 && errno != ENOENT) {
 +            return err;
 +        }
 +    }
 +
 +    buffer = rpath(ctx, oldpath);
 +    buffer1 = rpath(ctx, newpath);
 +#ifndef CONFIG_WIN32
 +    err = rename(buffer, buffer1);
 +    g_free(buffer);
 +    g_free(buffer1);
 +    return err;
 +#else
 +    if (!MoveFileEx((LPCTSTR)buffer,
 +                    (LPCTSTR)buffer1, MOVEFILE_REPLACE_EXISTING)){
 +        err = -(GetLastError());
 +        LOG_SEVERE("[%d][ >> %s] err: %d\n", __LINE__, __func__, err);
 +    } else {
 +        err = 0;
 +    }
 +    g_free(buffer);
 +    g_free(buffer1);
 +    return err;
 +#endif
 +}
 +
 +static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +#ifndef CONFIG_WIN32
 +    char *buffer;
 +    int ret = -1;
 +    char *path = fs_path->data;
 +
 +    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
 +        (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
 +        (fs_ctx->export_flags & V9FS_SM_NONE)) {
 +        buffer = rpath(fs_ctx, path);
 +        ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
 +        g_free(buffer);
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
 +        buffer = rpath(fs_ctx, path);
 +        ret = local_set_xattr(buffer, credp);
 +        g_free(buffer);
 +    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        return local_set_mapped_file_attr(fs_ctx, path, credp);
 +    }
 +    return ret;
 +#endif
 +    return -1;
 +}
 +
 +#ifdef CONFIG_WIN32
 +/* The function that change file last access and modification times for WIN32 */
 +static int win_utimes (const char *filename, const struct timeval tv[2])
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +
 +    FILETIME LastAccessTime, LastWriteTime;
 +
 +    ULARGE_INTEGER tmpTime;
 +
 +    ULONGLONG WindowsUnixTimeGap = 11644473600; // between 1601.01.01 and 1970.01.01
 +    ULONGLONG WindowsSecond = 10000000; // 1sec / 100nanosec
 +
 +    int res = 0;
 +
 +    HANDLE hFile = CreateFile(filename, FILE_WRITE_ATTRIBUTES,
 +                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
 +                            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
 +    if (hFile == INVALID_HANDLE_VALUE) {
 +        if (GetFileAttributes(filename) & FILE_ATTRIBUTE_DIRECTORY) {
 +            res = 0;
 +        }
 +        else {
 +            res = -1;
 +        }
 +    } else {
 +        if (!tv) { // case of NULL
 +            GetSystemTimeAsFileTime(&LastAccessTime);
 +            LastWriteTime = LastAccessTime;
 +        } else {
 +            tmpTime.QuadPart = UInt32x32To64(WindowsUnixTimeGap + tv[0].tv_sec, WindowsSecond)
 +                               + tv[0].tv_usec * 10;
 +            LastAccessTime.dwHighDateTime = tmpTime.HighPart;
 +            LastAccessTime.dwLowDateTime = tmpTime.LowPart;
 +
 +            tmpTime.QuadPart = UInt32x32To64(WindowsUnixTimeGap + tv[1].tv_sec, WindowsSecond)
 +                               + tv[1].tv_usec * 10;
 +            LastWriteTime.dwHighDateTime = tmpTime.HighPart;
 +            LastWriteTime.dwLowDateTime = tmpTime.LowPart;
 +        }
 +        if (!SetFileTime(hFile, NULL, &LastAccessTime, &LastWriteTime)) {
 +            res = -1;
 +        } else {
 +            res = 0;
 +        }
 +    }
 +
 +    if (hFile) {
 +        CloseHandle(hFile);
 +    }
 +    return res;
 +}
 +#endif
 +
 +static int local_utimensat(FsContext *s, V9fsPath *fs_path,
 +                           const struct timespec *buf)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *buffer;
 +    char *path = fs_path->data;
 +
 +    buffer = rpath(s, path);
 +#ifndef CONFIG_WIN32
 +    int ret;
 +    ret = qemu_utimens(buffer, buf);
 +    g_free(buffer);
 +    return ret;
 +#else
 +    const char * r_path = buffer;
 +    struct timeval tv[2], tv_now;
 +    struct stat st;
 +    int i;
 +
 +    /* happy if special cases */
 +    if (buf[0].tv_nsec == UTIME_OMIT && buf[1].tv_nsec == UTIME_OMIT) {
 +        return 0;
 +    }
 +    if (buf[0].tv_nsec == UTIME_NOW && buf[1].tv_nsec == UTIME_NOW) {
 +        return win_utimes(r_path, NULL);
 +    }
 +
 +    /* prepare for hard cases */
 +    if (buf[0].tv_nsec == UTIME_NOW || buf[1].tv_nsec == UTIME_NOW) {
 +        gettimeofday(&tv_now, NULL);
 +    }
 +    if (buf[0].tv_nsec == UTIME_OMIT || buf[1].tv_nsec == UTIME_OMIT) {
 +        stat(r_path, &st);
 +    }
 +
 +    for (i = 0; i < 2; i++) {
 +        if (buf[i].tv_nsec == UTIME_NOW) {
 +            tv[i].tv_sec = tv_now.tv_sec;
 +            tv[i].tv_usec = tv_now.tv_usec;
 +        } else if (buf[i].tv_nsec == UTIME_OMIT) {
 +            tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
 +            tv[i].tv_usec = 0;
 +        } else {
 +            tv[i].tv_sec = buf[i].tv_sec;
 +            tv[i].tv_usec = buf[i].tv_nsec / 1000;
 +        }
 +    }
 +
 +    return win_utimes(r_path, &tv[0]);
 +#endif
 +}
 +
 +static int local_remove(FsContext *ctx, const char *path)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    struct stat stbuf;
 +    char *buffer;
 +
 +    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        buffer = rpath(ctx, path);
 +#ifndef CONFIG_WIN32
 +        err =  lstat(buffer, &stbuf);
 +#else
 +        err = stat(buffer, &stbuf);
 +#endif
 +        g_free(buffer);
 +        if (err) {
 +            goto err_out;
 +        }
 +        /*
 +         * If directory remove .virtfs_metadata contained in the
 +         * directory
 +         */
 +        if (S_ISDIR(stbuf.st_mode)) {
 +#ifndef CONFIG_WIN32
 +            buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
 +                                     path, VIRTFS_META_DIR);
 +#else
 +            buffer = g_strdup_printf("%s\\%s\\%s", ctx->fs_root,
 +                                     path, VIRTFS_META_DIR);
 +#endif
 +            err = remove(buffer);
 +            g_free(buffer);
 +            if (err < 0 && errno != ENOENT) {
 +                /*
 +                 * We didn't had the .virtfs_metadata file. May be file created
 +                 * in non-mapped mode ?. Ignore ENOENT.
 +                 */
 +                goto err_out;
 +            }
 +        }
 +        /*
 +         * Now remove the name from parent directory
 +         * .virtfs_metadata directory
 +         */
 +        buffer = local_mapped_attr_path(ctx, path);
 +        err = remove(buffer);
 +        g_free(buffer);
 +        if (err < 0 && errno != ENOENT) {
 +            /*
 +             * We didn't had the .virtfs_metadata file. May be file created
 +             * in non-mapped mode ?. Ignore ENOENT.
 +             */
 +            goto err_out;
 +        }
 +    }
 +
 +    buffer = rpath(ctx, path);
 +    err = remove(buffer);
 +    g_free(buffer);
 +err_out:
 +    return err;
 +}
 +
 +static int local_fsync(FsContext *ctx, int fid_type,
 +                       V9fsFidOpenState *fs, int datasync)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int fd;
 +
 +    if (fid_type == P9_FID_DIR) {
 +#ifndef CONFIG_WIN32
-     .readdir_r = local_readdir_r,
++        fd = dirfd(fs->dir.stream);
 +#else
 +        fd = fs->fd;
 +#endif
 +    } else {
 +        fd = fs->fd;
 +    }
 +
 +#ifndef CONFIG_WIN32
 +    if (datasync) {
 +        return qemu_fdatasync(fd);
 +    } else {
 +        return fsync(fd);
 +    }
 +#else
 +    return _commit(fd);
 +#endif
 +}
 +
 +static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *buffer;
 +    char *path = fs_path->data;
 +
 +    buffer = rpath(s, path);
 +    LOG_TRACE("[%d][%s] statfs(%s)\n", __LINE__, __func__, buffer);
 +#ifndef CONFIG_WIN32
 +    int ret;
 +    ret = statfs(buffer, stbuf);
 +    g_free(buffer);
 +    return ret;
 +#else
 +    DWORD VolumeSerialNumber,
 +          MaximumComponentLength,
 +          FileSystemFlags;
 +
 +    DWORD SectorsPerCluster,
 +          BytesPerSector,
 +          NumberOfFreeClusters,
 +          TotalNumberOfClusters,
 +          BytesPerCluster;
 +
 +    ULARGE_INTEGER TotalNumberOfBytes,
 +                   TotalNumberOfFreeBytes,
 +                   FreeBytesAvailableToCaller;
 +
 +    TCHAR tmpName[PATH_MAX] = {0};
 +    TCHAR VolumeNameBuffer[PATH_MAX] = {0};
 +    TCHAR FileSystemNameBuffer[PATH_MAX] = {0};
 +
 +    strncpy(tmpName, buffer, 3 > PATH_MAX ? PATH_MAX : 3);
 +    tmpName[4 > PATH_MAX ? PATH_MAX : 4] = '\0';
 +    LPCTSTR RootPathName = (LPCTSTR)tmpName;
 +    g_free(buffer);
 +
 +    if (RootPathName == NULL) {
 +        LOG_SEVERE("[%d][%s] >> err = %d\n", __LINE__, __func__, GetLastError());
 +        stbuf = NULL;
 +        return -1;
 +    }
 +
 +    if (!GetVolumeInformation(RootPathName, (LPTSTR)&VolumeNameBuffer, PATH_MAX,
 +                        &VolumeSerialNumber, &MaximumComponentLength, &FileSystemFlags,
 +                        (LPTSTR)&FileSystemNameBuffer, PATH_MAX)) {
 +        LOG_SEVERE("[%d][%s] >> err = %d\n", __LINE__, __func__, GetLastError());
 +        return -1;
 +    }
 +
 +    if (!GetDiskFreeSpace(RootPathName, &SectorsPerCluster, &BytesPerSector,
 +                        &NumberOfFreeClusters, &TotalNumberOfClusters)) {
 +        SectorsPerCluster = 1;
 +        BytesPerSector = 1;
 +        NumberOfFreeClusters = 0;
 +        TotalNumberOfClusters = 0;
 +    }
 +
 +    BytesPerCluster = SectorsPerCluster * BytesPerSector;
 +    TotalNumberOfBytes.QuadPart = Int32x32To64(TotalNumberOfClusters, BytesPerCluster);
 +    TotalNumberOfFreeBytes.QuadPart = Int32x32To64(NumberOfFreeClusters, BytesPerCluster);
 +    FreeBytesAvailableToCaller=TotalNumberOfFreeBytes;
 +
 +    if (!strcmp(FileSystemNameBuffer, "NTFS")) {
 +        stbuf->f_type = NTFS_SUPER_MAGIC;
 +    }
 +    /* need to check more about other filesystems (ex CD) */
 +    else {
 +        stbuf->f_type = MSDOS_SUPER_MAGIC;
 +    }
 +    stbuf->f_bsize       = BytesPerSector;
 +    stbuf->f_blocks      = TotalNumberOfBytes.QuadPart / BytesPerSector;
 +    stbuf->f_bfree       = TotalNumberOfFreeBytes.QuadPart / BytesPerSector;
 +    stbuf->f_bavail      = FreeBytesAvailableToCaller.QuadPart / BytesPerSector;
 +    stbuf->f_files       = stbuf->f_blocks / SectorsPerCluster;
 +    stbuf->f_ffree       = stbuf->f_bfree / SectorsPerCluster;
 +    stbuf->f_fsid.val[0] = HIWORD(VolumeSerialNumber);
 +    stbuf->f_fsid.val[1] = LOWORD(VolumeSerialNumber);
 +    stbuf->f_namelen     = MaximumComponentLength;
 +    stbuf->f_spare[0]    = 0;
 +    stbuf->f_spare[1]    = 0;
 +    stbuf->f_spare[2]    = 0;
 +    stbuf->f_spare[3]    = 0;
 +    stbuf->f_spare[4]    = 0;
 +    stbuf->f_spare[5]    = 0;
 +
 +    return 0;
 +#endif
 +}
 +
 +static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
 +                               const char *name, void *value, size_t size)
 +{
 +#ifndef CONFIG_WIN32
 +    char *path = fs_path->data;
 +
 +    return v9fs_get_xattr(ctx, path, name, value, size);
 +#else
 +    /* xattr doesn't support on Windows */
 +    return -1;
 +#endif
 +}
 +
 +static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
 +                                void *value, size_t size)
 +{
 +#ifndef CONFIG_WIN32
 +    char *path = fs_path->data;
 +
 +    return v9fs_list_xattr(ctx, path, value, size);
 +#else
 +    /* xattr doesn't support on Windows */
 +    return -1;
 +#endif
 +}
 +
 +static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
 +                           void *value, size_t size, int flags)
 +{
 +#ifndef CONFIG_WIN32
 +    char *path = fs_path->data;
 +
 +    return v9fs_set_xattr(ctx, path, name, value, size, flags);
 +#else
 +    /* xattr doesn't support on Windows */
 +    return -1;
 +#endif
 +}
 +
 +static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
 +                              const char *name)
 +{
 +#ifndef CONFIG_WIN32
 +    char *path = fs_path->data;
 +
 +    return v9fs_remove_xattr(ctx, path, name);
 +#else
 +    /* xattr doesn't support on Windows */
 +    return -1;
 +#endif
 +}
 +
 +static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
 +                              const char *name, V9fsPath *target)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    if (dir_path) {
 +#ifndef CONFIG_WIN32
 +        v9fs_string_sprintf((V9fsString *)target, "%s/%s",
 +                            dir_path->data, name);
 +#else
 +        v9fs_string_sprintf((V9fsString *)target, "%s\\%s",
 +                            dir_path->data, name);
 +    while((target->data)[strlen(target->data)-1] == '\\'){
 +        (target->data)[strlen(target->data)-1] = '\0';
 +    }
 +#endif
 +    } else {
 +        v9fs_string_sprintf((V9fsString *)target, "%s", name);
 +    }
 +    /* Bump the size for including terminating NULL */
 +    target->size++;
 +    return 0;
 +}
 +
 +static int local_renameat(FsContext *ctx, V9fsPath *olddir,
 +                          const char *old_name, V9fsPath *newdir,
 +                          const char *new_name)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int ret;
 +    V9fsString old_full_name, new_full_name;
 +
 +    v9fs_string_init(&old_full_name);
 +    v9fs_string_init(&new_full_name);
 +
 +#ifndef CONFIG_WIN32
 +    v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
 +    v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
 +#else
 +    v9fs_string_sprintf(&old_full_name, "%s\\%s", olddir->data, old_name);
 +    v9fs_string_sprintf(&new_full_name, "%s\\%s", newdir->data, new_name);
 +#endif
 +
 +    ret = local_rename(ctx, old_full_name.data, new_full_name.data);
 +    v9fs_string_free(&old_full_name);
 +    v9fs_string_free(&new_full_name);
 +    return ret;
 +}
 +
 +static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
 +                          const char *name, int flags)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int ret;
 +    V9fsString fullname;
 +    char *buffer;
 +
 +    v9fs_string_init(&fullname);
 +
 +#ifndef CONFIG_WIN32
 +    v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
 +#else
 +    v9fs_string_sprintf(&fullname, "%s\\%s", dir->data, name);
 +    while(fullname.data[strlen(fullname.data)-1] == '\\'){
 +        fullname.data[strlen(fullname.data)-1] = '\0';
 +    }
 +#endif
 +    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +#ifdef CONFIG_VIRTFS_DARWIN
 +        if (flags == AT_REMOVEDIR) {
 +            /*
 +             * If directory remove .virtfs_metadata contained in the
 +             * directory
 +             */
 +#ifndef CONFIG_WIN32
 +            buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
 +                                     fullname.data, VIRTFS_META_DIR);
 +#else
 +            buffer = g_strdup_printf("%s\\%s\\%s", ctx->fs_root,
 +                                     fullname.data, VIRTFS_META_DIR);
 +#endif
 +            ret = remove(buffer);
 +            g_free(buffer);
 +            if (ret < 0 && errno != ENOENT) {
 +                /*
 +                 * We didn't had the .virtfs_metadata file. May be file created
 +                 * in non-mapped mode ?. Ignore ENOENT.
 +                 */
 +                goto err_out;
 +            }
 +        }
 +#endif
 +        /*
 +         * Now remove the name from parent directory
 +         * .virtfs_metadata directory.
 +         */
 +        buffer = local_mapped_attr_path(ctx, fullname.data);
 +        ret = remove(buffer);
 +        g_free(buffer);
 +        if (ret < 0 && errno != ENOENT) {
 +            /*
 +             * We didn't had the .virtfs_metadata file. May be file created
 +             * in non-mapped mode ?. Ignore ENOENT.
 +             */
 +            goto err_out;
 +        }
 +    }
 +    /* Remove the name finally */
 +    buffer = rpath(ctx, fullname.data);
 +#ifndef CONFIG_WIN32
 +    ret = remove(buffer);
 +#else
 +    if (flags == AT_REMOVEDIR) { // is dir
 +        ret = rmdir(buffer);
 +    } else { //is file
 +        ret = remove(buffer);
 +    }
 +#endif
 +    g_free(buffer);
 +
 +err_out:
 +    v9fs_string_free(&fullname);
 +    return ret;
 +}
 +
 +#ifdef FS_IOC_GETVERSION
 +static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
 +                                mode_t st_mode, uint64_t *st_gen)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +#ifndef CONFIG_WIN32
 +    int err;
 +
 +    V9fsFidOpenState fid_open;
 +
 +    /*
 +     * Do not try to open special files like device nodes, fifos etc
 +     * We can get fd for regular files and directories only
 +     */
 +    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
 +        errno = ENOTTY;
 +        return -1;
 +    }
 +    err = local_open(ctx, path, O_RDONLY, &fid_open);
 +    if (err < 0) {
 +        return err;
 +    }
 +    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
 +    local_close(ctx, &fid_open);
 +    return err;
 +#else
 +    errno = ENOTTY;
 +    return -1;
 +#endif
 +}
 +#endif
 +
 +static int local_init(FsContext *ctx)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err = 0;
 +#ifdef FS_IOC_GETVERSION
 +    struct statfs stbuf;
 +#endif
 +
 +#ifndef CONFIG_WIN32
 +    if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
 +        ctx->xops = passthrough_xattr_ops;
 +    } else if (ctx->export_flags & V9FS_SM_MAPPED) {
 +        ctx->xops = mapped_xattr_ops;
 +    } else if (ctx->export_flags & V9FS_SM_NONE) {
 +        ctx->xops = none_xattr_ops;
 +    } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 +        /*
 +         * xattr operation for mapped-file and passthrough
 +         * remain same.
 +         */
 +        ctx->xops = passthrough_xattr_ops;
 +    }
 +#else
 +    ctx->xops = NULL;
 +#endif
 +    ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
 +#ifdef FS_IOC_GETVERSION
 +    /*
 +     * use ioc_getversion only if the iocl is definied
 +     */
 +    err = statfs(ctx->fs_root, &stbuf);
 +    if (!err) {
 +        switch (stbuf.f_type) {
 +        case EXT2_SUPER_MAGIC:
 +        case BTRFS_SUPER_MAGIC:
 +        case REISERFS_SUPER_MAGIC:
 +        case XFS_SUPER_MAGIC:
 +            ctx->exops.get_st_gen = local_ioc_getversion;
 +            break;
 +        }
 +    }
 +#endif
 +    return err;
 +}
 +
 +static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
 +{
 +    LOG_TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    const char *sec_model = qemu_opt_get(opts, "security_model");
 +    const char *path = qemu_opt_get(opts, "path");
 +
 +    if (!sec_model) {
 +        error_report("Security model not specified, local fs needs security model");
 +        error_printf("valid options are:"
 +                     "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
 +        return -1;
 +    }
 +
 +    if (!strcmp(sec_model, "passthrough")) {
 +        fse->export_flags |= V9FS_SM_PASSTHROUGH;
 +    } else if (!strcmp(sec_model, "mapped") ||
 +               !strcmp(sec_model, "mapped-xattr")) {
 +        fse->export_flags |= V9FS_SM_MAPPED;
 +    } else if (!strcmp(sec_model, "none")) {
 +        fse->export_flags |= V9FS_SM_NONE;
 +    } else if (!strcmp(sec_model, "mapped-file")) {
 +        fse->export_flags |= V9FS_SM_MAPPED_FILE;
 +    } else {
 +        error_report("Invalid security model %s specified", sec_model);
 +        error_printf("valid options are:"
 +                     "\t[passthrough|mapped-xattr|mapped-file|none]\n");
 +        return -1;
 +    }
 +
 +    if (!path) {
 +        error_report("fsdev: No path specified");
 +        return -1;
 +    }
 +    fse->path = g_strdup(path);
 +
 +    return 0;
 +}
 +
 +FileOperations local_ops = {
 +    .parse_opts = local_parse_opts,
 +    .init  = local_init,
 +    .lstat = local_lstat,
 +    .readlink = local_readlink,
 +    .close = local_close,
 +    .closedir = local_closedir,
 +    .open = local_open,
 +    .opendir = local_opendir,
 +    .rewinddir = local_rewinddir,
 +    .telldir = local_telldir,
++    .readdir = local_readdir,
 +    .seekdir = local_seekdir,
 +    .preadv = local_preadv,
 +    .pwritev = local_pwritev,
 +    .chmod = local_chmod,
 +    .mknod = local_mknod,
 +    .mkdir = local_mkdir,
 +    .fstat = local_fstat,
 +    .open2 = local_open2,
 +    .symlink = local_symlink,
 +    .link = local_link,
 +    .truncate = local_truncate,
 +    .rename = local_rename,
 +    .chown = local_chown,
 +    .utimensat = local_utimensat,
 +    .remove = local_remove,
 +    .fsync = local_fsync,
 +    .statfs = local_statfs,
 +    .lgetxattr = local_lgetxattr,
 +    .llistxattr = local_llistxattr,
 +    .lsetxattr = local_lsetxattr,
 +    .lremovexattr = local_lremovexattr,
 +    .name_to_path = local_name_to_path,
 +    .renameat  = local_renameat,
 +    .unlinkat = local_unlinkat,
 +};
index 24eaa75,0000000..dcc0f2b
mode 100644,000000..100644
--- /dev/null
@@@ -1,3670 -1,0 +1,3675 @@@
-         if (f->fs.dir == NULL) {
 +/*
 + * Virtio 9p backend for Maru
 + * Based on hw/9pfs/virtio-9p.c:
 + *
 + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 + *
 + * Contact:
 + *  Sooyoung Ha <yoosah.ha@samsung.com>
 + *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#include "qemu/osdep.h"
 +#include "hw/virtio/virtio.h"
 +#include "hw/i386/pc.h"
 +#include "qapi/error.h"
 +#include "qemu/error-report.h"
 +#include "qemu/iov.h"
 +#include "qemu/sockets.h"
 +#include "virtio-9p.h"
 +#include "fsdev/qemu-fsdev.h"
 +#include "9p-xattr.h"
 +#include "coth.h"
 +#include "trace.h"
 +#include "migration/migration.h"
 +
 +#ifdef CONFIG_WIN32
 +#include "tizen/src/resources_win32.h"
 +
 +/* On windows, there's no mknod function. The device number is meaningless */
 +#define makedev(x,y) 0
 +#define major(x) 0
 +#define minor(x) 0
 +
 +/* Old MinGW's struct dirent doesn't support d_type member */
 +#define WIN32_D_TYPE 0
 +
 +extern uint64_t hostBytesPerSector;
 +#endif
 +
 +#ifdef CONFIG_DARWIN
 +#define O_DIRECT 040000 /* Direct disk access */
 +#define O_NOATIME 01000000 /* Do not set atime */
 +#endif
 +
 +#include "../../tizen/src/debug_ch.h"
 +MULTI_DEBUG_CHANNEL(tizen, 9pfs);
 +
 +int open_fd_hw;
 +int total_open_fd;
 +static int open_fd_rc;
 +
 +enum {
 +    Oread   = 0x00,
 +    Owrite  = 0x01,
 +    Ordwr   = 0x02,
 +    Oexec   = 0x03,
 +    Oexcl   = 0x04,
 +    Otrunc  = 0x10,
 +    Orexec  = 0x20,
 +    Orclose = 0x40,
 +    Oappend = 0x80,
 +};
 +
 +ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
 +{
 +    ssize_t ret;
 +    va_list ap;
 +
 +    va_start(ap, fmt);
 +    ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap);
 +    va_end(ap);
 +
 +    return ret;
 +}
 +
 +ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
 +{
 +    ssize_t ret;
 +    va_list ap;
 +
 +    va_start(ap, fmt);
 +    ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap);
 +    va_end(ap);
 +
 +    return ret;
 +}
 +
 +static void pdu_push_and_notify(V9fsPDU *pdu)
 +{
 +    virtio_9p_push_and_notify(pdu);
 +}
 +
 +static int omode_to_uflags(int8_t mode)
 +{
 +    int ret = 0;
 +
 +    switch (mode & 3) {
 +    case Oread:
 +        ret = O_RDONLY;
 +        break;
 +    case Ordwr:
 +        ret = O_RDWR;
 +        break;
 +    case Owrite:
 +        ret = O_WRONLY;
 +        break;
 +    case Oexec:
 +        ret = O_RDONLY;
 +        break;
 +    }
 +
 +    if (mode & Otrunc) {
 +        ret |= O_TRUNC;
 +    }
 +
 +    if (mode & Oappend) {
 +        ret |= O_APPEND;
 +    }
 +
 +    if (mode & Oexcl) {
 +        ret |= O_EXCL;
 +    }
 +
 +    return ret;
 +}
 +
 +struct dotl_openflag_map {
 +    int dotl_flag;
 +    int open_flag;
 +};
 +
 +static int dotl_to_open_flags(int flags)
 +{
 +    int i;
 +    /*
 +     * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
 +     * and P9_DOTL_NOACCESS
 +     */
 +    int oflags = flags & O_ACCMODE;
 +
 +    struct dotl_openflag_map dotl_oflag_map[] = {
 +        { P9_DOTL_CREATE, O_CREAT },
 +        { P9_DOTL_EXCL, O_EXCL },
 +        { P9_DOTL_NOCTTY , O_NOCTTY },
 +        { P9_DOTL_TRUNC, O_TRUNC },
 +        { P9_DOTL_APPEND, O_APPEND },
 +        { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
 +        { P9_DOTL_DSYNC, O_DSYNC },
 +        { P9_DOTL_FASYNC, FASYNC },
 +        { P9_DOTL_DIRECT, O_DIRECT },
 +        { P9_DOTL_LARGEFILE, O_LARGEFILE },
 +        { P9_DOTL_DIRECTORY, O_DIRECTORY },
 +        { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
 +        { P9_DOTL_NOATIME, O_NOATIME },
 +        { P9_DOTL_SYNC, O_SYNC },
 +    };
 +
 +    for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
 +        if (flags & dotl_oflag_map[i].dotl_flag) {
 +            oflags |= dotl_oflag_map[i].open_flag;
 +        }
 +    }
 +
 +    return oflags;
 +}
 +
 +void cred_init(FsCred *credp)
 +{
 +    credp->fc_uid = -1;
 +    credp->fc_gid = -1;
 +    credp->fc_mode = -1;
 +    credp->fc_rdev = -1;
 +}
 +
 +static int get_dotl_openflags(V9fsState *s, int oflags)
 +{
 +    int flags;
 +    /*
 +     * Filter the client open flags
 +     */
 +    flags = dotl_to_open_flags(oflags);
 +    flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
 +    /*
 +     * Ignore direct disk access hint until the server supports it.
 +     */
 +    flags &= ~O_DIRECT;
 +    return flags;
 +}
 +
 +void v9fs_path_init(V9fsPath *path)
 +{
 +    path->data = NULL;
 +    path->size = 0;
 +}
 +
 +void v9fs_path_free(V9fsPath *path)
 +{
 +    g_free(path->data);
 +    path->data = NULL;
 +    path->size = 0;
 +}
 +
 +void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
 +{
 +    v9fs_path_free(lhs);
 +    lhs->data = g_malloc(rhs->size);
 +    memcpy(lhs->data, rhs->data, rhs->size);
 +    lhs->size = rhs->size;
 +}
 +
 +int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
 +                      const char *name, V9fsPath *path)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    err = s->ops->name_to_path(&s->ctx, dirpath, name, path); // local_name_to_path
 +    if (err < 0) {
 +        err = -errno;
 +    }
 +    return err;
 +}
 +
 +/*
 + * Return TRUE if s1 is an ancestor of s2.
 + *
 + * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
 + * As a special case, We treat s1 as ancestor of s2 if they are same!
 + */
 +static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
 +{
 +    if (!strncmp(s1->data, s2->data, s1->size - 1)) {
 +#ifndef CONFIG_WIN32
 +        if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
 +#else
 +        if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '\\') {
 +#endif
 +            return 1;
 +        }
 +    }
 +    return 0;
 +}
 +
 +static size_t v9fs_string_size(V9fsString *str)
 +{
 +    return str->size;
 +}
 +
 +/*
 + * returns 0 if fid got re-opened, 1 if not, < 0 on error */
 +static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err = 1;
 +    if (f->fid_type == P9_FID_FILE) {
 +        if (f->fs.fd == -1) {
 +            do {
 +                err = v9fs_co_open(pdu, f, f->open_flags);
 +            } while (err == -EINTR && !pdu->cancelled);
 +        }
 +    } else if (f->fid_type == P9_FID_DIR) {
-         if (fidp->fs.dir != NULL) {
++        if (f->fs.dir.stream == NULL) {
 +            do {
 +                err = v9fs_co_opendir(pdu, f);
 +            } while (err == -EINTR && !pdu->cancelled);
 +        }
 +    }
 +    return err;
 +}
 +
 +static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    V9fsFidState *f;
 +    V9fsState *s = pdu->s;
 +
 +    for (f = s->fid_list; f; f = f->next) {
 +        BUG_ON(f->clunked);
 +        if (f->fid == fid) {
 +            /*
 +             * Update the fid ref upfront so that
 +             * we don't get reclaimed when we yield
 +             * in open later.
 +             */
 +            f->ref++;
 +            /*
 +             * check whether we need to reopen the
 +             * file. We might have closed the fd
 +             * while trying to free up some file
 +             * descriptors.
 +             */
 +            err = v9fs_reopen_fid(pdu, f);
 +            if (err < 0) {
 +                ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +                f->ref--;
 +                return NULL;
 +            }
 +            /*
 +             * Mark the fid as referenced so that the LRU
 +             * reclaim won't close the file descriptor
 +             */
 +            f->flags |= FID_REFERENCED;
 +            return f;
 +        }
 +    }
 +    return NULL;
 +}
 +
 +static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
 +{
 +    V9fsFidState *f;
 +
 +    for (f = s->fid_list; f; f = f->next) {
 +        /* If fid is already there return NULL */
 +        BUG_ON(f->clunked);
 +        if (f->fid == fid) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            return NULL;
 +        }
 +    }
 +    f = g_malloc0(sizeof(V9fsFidState));
 +    f->fid = fid;
 +    f->fid_type = P9_FID_NONE;
 +    f->ref = 1;
 +    /*
 +     * Mark the fid as referenced so that the LRU
 +     * reclaim won't close the file descriptor
 +     */
 +    f->flags |= FID_REFERENCED;
 +    f->next = s->fid_list;
 +    s->fid_list = f;
 +
 +    return f;
 +}
 +
 +#ifndef CONFIG_WIN32
 +static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int retval = 0;
 +
 +    if (fidp->fs.xattr.copied_len == -1) {
 +        /* getxattr/listxattr fid */
 +        goto free_value;
 +    }
 +    /*
 +     * if this is fid for setxattr. clunk should
 +     * result in setxattr localcall
 +     */
 +    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
 +        /* clunk after partial write */
 +        retval = -EINVAL;
 +        goto free_out;
 +    }
 +    if (fidp->fs.xattr.len) {
 +        retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
 +                                   fidp->fs.xattr.value,
 +                                   fidp->fs.xattr.len,
 +                                   fidp->fs.xattr.flags);
 +    } else {
 +        retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
 +    }
 +free_out:
 +    v9fs_string_free(&fidp->fs.xattr.name);
 +free_value:
 +    g_free(fidp->fs.xattr.value);
 +    return retval;
 +}
 +#endif
 +
 +static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int retval = 0;
 +
 +    if (fidp->fid_type == P9_FID_FILE) {
 +        /* If we reclaimed the fd no need to close */
 +        if (fidp->fs.fd != -1) {
 +            retval = v9fs_co_close(pdu, &fidp->fs);
 +        }
 +    } else if (fidp->fid_type == P9_FID_DIR) {
-             if (f->fs.dir != NULL) {
++        if (fidp->fs.dir.stream != NULL) {
 +            retval = v9fs_co_closedir(pdu, &fidp->fs);
 +        }
 +    } else if (fidp->fid_type == P9_FID_XATTR) {
 +#ifndef CONFIG_WIN32
 +        retval = v9fs_xattr_fid_clunk(pdu, fidp);
 +#else
 +      retval = -1;
 +#endif
 +    }
 +    v9fs_path_free(&fidp->path);
 +    g_free(fidp);
 +    return retval;
 +}
 +
 +static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
 +{
 +    BUG_ON(!fidp->ref);
 +    fidp->ref--;
 +    /*
 +     * Don't free the fid if it is in reclaim list
 +     */
 +    if (!fidp->ref && fidp->clunked) {
 +        if (fidp->fid == pdu->s->root_fid) {
 +            /*
 +             * if the clunked fid is root fid then we
 +             * have unmounted the fs on the client side.
 +             * delete the migration blocker. Ideally, this
 +             * should be hooked to transport close notification
 +             */
 +            if (pdu->s->migration_blocker) {
 +                migrate_del_blocker(pdu->s->migration_blocker);
 +                error_free(pdu->s->migration_blocker);
 +                pdu->s->migration_blocker = NULL;
 +            }
 +        }
 +        return free_fid(pdu, fidp);
 +    }
 +    return 0;
 +}
 +
 +static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
 +{
 +    V9fsFidState **fidpp, *fidp;
 +
 +    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
 +        if ((*fidpp)->fid == fid) {
 +            break;
 +        }
 +    }
 +    if (*fidpp == NULL) {
 +        return NULL;
 +    }
 +    fidp = *fidpp;
 +    *fidpp = fidp->next;
 +    fidp->clunked = 1;
 +    return fidp;
 +}
 +
 +void v9fs_reclaim_fd(V9fsPDU *pdu)
 +{
 +    int reclaim_count = 0;
 +    V9fsState *s = pdu->s;
 +    V9fsFidState *f, *reclaim_list = NULL;
 +
 +    for (f = s->fid_list; f; f = f->next) {
 +        /*
 +         * Unlink fids cannot be reclaimed. Check
 +         * for them and skip them. Also skip fids
 +         * currently being operated on.
 +         */
 +        if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
 +            continue;
 +        }
 +        /*
 +         * if it is a recently referenced fid
 +         * we leave the fid untouched and clear the
 +         * reference bit. We come back to it later
 +         * in the next iteration. (a simple LRU without
 +         * moving list elements around)
 +         */
 +        if (f->flags & FID_REFERENCED) {
 +            f->flags &= ~FID_REFERENCED;
 +            continue;
 +        }
 +        /*
 +         * Add fids to reclaim list.
 +         */
 +        if (f->fid_type == P9_FID_FILE) {
 +            if (f->fs.fd != -1) {
 +                /*
 +                 * Up the reference count so that
 +                 * a clunk request won't free this fid
 +                 */
 +                f->ref++;
 +                f->rclm_lst = reclaim_list;
 +                reclaim_list = f;
 +                f->fs_reclaim.fd = f->fs.fd;
 +                f->fs.fd = -1;
 +                reclaim_count++;
 +            }
 +        } else if (f->fid_type == P9_FID_DIR) {
-                 f->fs_reclaim.dir = f->fs.dir;
-                 f->fs.dir = NULL;
++            if (f->fs.dir.stream != NULL) {
 +                /*
 +                 * Up the reference count so that
 +                 * a clunk request won't free this fid
 +                 */
 +                f->ref++;
 +                f->rclm_lst = reclaim_list;
 +                reclaim_list = f;
-     struct dirent *dent, *result;
++                f->fs_reclaim.dir.stream = f->fs.dir.stream;
++                f->fs.dir.stream = NULL;
 +                reclaim_count++;
 +            }
 +        }
 +        if (reclaim_count >= open_fd_rc) {
 +            break;
 +        }
 +    }
 +    /*
 +     * Now close the fid in reclaim list. Free them if they
 +     * are already clunked.
 +     */
 +    while (reclaim_list) {
 +        f = reclaim_list;
 +        reclaim_list = f->rclm_lst;
 +        if (f->fid_type == P9_FID_FILE) {
 +            v9fs_co_close(pdu, &f->fs_reclaim);
 +        } else if (f->fid_type == P9_FID_DIR) {
 +            v9fs_co_closedir(pdu, &f->fs_reclaim);
 +        }
 +        f->rclm_lst = NULL;
 +        /*
 +         * Now drop the fid reference, free it
 +         * if clunked.
 +         */
 +        put_fid(pdu, f);
 +    }
 +}
 +
 +static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
 +{
 +    TRACE("[%d][ >> %s]\n", __LINE__, __func__);
 +    int err;
 +    V9fsState *s = pdu->s;
 +    V9fsFidState *fidp, head_fid;
 +
 +    head_fid.next = s->fid_list;
 +    for (fidp = s->fid_list; fidp; fidp = fidp->next) {
 +        if (fidp->path.size != path->size) {
 +            continue;
 +        }
 +        if (!memcmp(fidp->path.data, path->data, path->size)) {
 +            /* Mark the fid non reclaimable. */
 +            fidp->flags |= FID_NON_RECLAIMABLE;
 +
 +            /* reopen the file/dir if already closed */
 +            err = v9fs_reopen_fid(pdu, fidp);
 +            if (err < 0) {
 +                return -1;
 +            }
 +            /*
 +             * Go back to head of fid list because
 +             * the list could have got updated when
 +             * switched to the worker thread
 +             */
 +            if (err == 0) {
 +                fidp = &head_fid;
 +            }
 +        }
 +    }
 +    return 0;
 +}
 +
 +static void virtfs_reset(V9fsPDU *pdu)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsState *s = pdu->s;
 +    V9fsFidState *fidp = NULL;
 +
 +    /* Free all fids */
 +    while (s->fid_list) {
 +        fidp = s->fid_list;
 +        s->fid_list = fidp->next;
 +
 +        if (fidp->ref) {
 +            fidp->clunked = 1;
 +        } else {
 +            free_fid(pdu, fidp);
 +        }
 +    }
 +    if (fidp) {
 +        /* One or more unclunked fids found... */
 +        error_report("9pfs:%s: One or more uncluncked fids "
 +                     "found during reset", __func__);
 +    }
 +}
 +
 +#define P9_QID_TYPE_DIR         0x80
 +#define P9_QID_TYPE_SYMLINK     0x02
 +
 +#define P9_STAT_MODE_DIR        0x80000000
 +#define P9_STAT_MODE_APPEND     0x40000000
 +#define P9_STAT_MODE_EXCL       0x20000000
 +#define P9_STAT_MODE_MOUNT      0x10000000
 +#define P9_STAT_MODE_AUTH       0x08000000
 +#define P9_STAT_MODE_TMP        0x04000000
 +#define P9_STAT_MODE_SYMLINK    0x02000000
 +#define P9_STAT_MODE_LINK       0x01000000
 +#define P9_STAT_MODE_DEVICE     0x00800000
 +#define P9_STAT_MODE_NAMED_PIPE 0x00200000
 +#define P9_STAT_MODE_SOCKET     0x00100000
 +#define P9_STAT_MODE_SETUID     0x00080000
 +#define P9_STAT_MODE_SETGID     0x00040000
 +#define P9_STAT_MODE_SETVTX     0x00010000
 +
 +#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
 +                                P9_STAT_MODE_SYMLINK |      \
 +                                P9_STAT_MODE_LINK |         \
 +                                P9_STAT_MODE_DEVICE |       \
 +                                P9_STAT_MODE_NAMED_PIPE |   \
 +                                P9_STAT_MODE_SOCKET)
 +
 +/* This is the algorithm from ufs in spfs */
 +static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
 +{
 +    size_t size;
 +
 +    memset(&qidp->path, 0, sizeof(qidp->path));
 +    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
 +    memcpy(&qidp->path, &stbuf->st_ino, size);
 +    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
 +    qidp->type = 0;
 +    if (S_ISDIR(stbuf->st_mode)) {
 +        qidp->type |= P9_QID_TYPE_DIR;
 +    }
 +#ifndef CONFIG_WIN32
 +    if (S_ISLNK(stbuf->st_mode)) {
 +#else
 +    if (((stbuf->st_mode) & S_IFMT) == 0xA000) {
 +#endif
 +        qidp->type |= P9_QID_TYPE_SYMLINK;
 +    }
 +}
 +
 +static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
 +{
 +    TRACE("[%d][ >> %s]\n", __LINE__, __func__);
 +    struct stat stbuf;
 +    int err;
 +
 +    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
 +    if (err < 0) {
 +        return err;
 +    }
 +    stat_to_qid(&stbuf, qidp);
 +    return 0;
 +}
 +
 +V9fsPDU *pdu_alloc(V9fsState *s)
 +{
 +    V9fsPDU *pdu = NULL;
 +
 +    if (!QLIST_EMPTY(&s->free_list)) {
 +        pdu = QLIST_FIRST(&s->free_list);
 +        QLIST_REMOVE(pdu, next);
 +        QLIST_INSERT_HEAD(&s->active_list, pdu, next);
 +    }
 +    return pdu;
 +}
 +
 +void pdu_free(V9fsPDU *pdu)
 +{
 +    if (pdu) {
 +        V9fsState *s = pdu->s;
 +        /*
 +         * Cancelled pdu are added back to the freelist
 +         * by flush request .
 +         */
 +        if (!pdu->cancelled) {
 +            QLIST_REMOVE(pdu, next);
 +            QLIST_INSERT_HEAD(&s->free_list, pdu, next);
 +        }
 +    }
 +}
 +
 +/*
 + * We don't do error checking for pdu_marshal/unmarshal here
 + * because we always expect to have enough space to encode
 + * error details
 + */
 +static void pdu_complete(V9fsPDU *pdu, ssize_t len)
 +{
 +    int8_t id = pdu->id + 1; /* Response */
 +    V9fsState *s = pdu->s;
 +
 +    if (len < 0) {
 +        WARN("[%d][ >> %s]\n", __LINE__, __func__);
 +        int err = -len;
 +        len = 7;
 +
 +        if (s->proto_version != V9FS_PROTO_2000L) {
 +            V9fsString str;
 +
 +            str.data = strerror(err);
 +            str.size = strlen(str.data);
 +
 +            len += pdu_marshal(pdu, len, "s", &str);
 +            id = P9_RERROR;
 +        }
 +
 +        len += pdu_marshal(pdu, len, "d", err);
 +
 +        if (s->proto_version == V9FS_PROTO_2000L) {
 +            id = P9_RLERROR;
 +        }
 +        trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
 +    }
 +
 +    /* fill out the header */
 +    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
 +
 +    /* keep these in sync */
 +    pdu->size = len;
 +    pdu->id = id;
 +
 +    pdu_push_and_notify(pdu);
 +
 +    /* Now wakeup anybody waiting in flush for this request */
 +    qemu_co_queue_next(&pdu->complete);
 +
 +    pdu_free(pdu);
 +}
 +
 +#ifndef CONFIG_WIN32
 +static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
 +{
 +    mode_t ret;
 +
 +    ret = mode & 0777;
 +    if (mode & P9_STAT_MODE_DIR) {
 +        ret |= S_IFDIR;
 +    }
 +
 +    if (mode & P9_STAT_MODE_SYMLINK) {
 +        ret |= S_IFLNK;
 +    }
 +    if (mode & P9_STAT_MODE_SOCKET) {
 +        ret |= S_IFSOCK;
 +    }
 +    if (mode & P9_STAT_MODE_NAMED_PIPE) {
 +        ret |= S_IFIFO;
 +    }
 +    if (mode & P9_STAT_MODE_DEVICE) {
 +        if (extension->size && extension->data[0] == 'c') {
 +            ret |= S_IFCHR;
 +        } else {
 +            ret |= S_IFBLK;
 +        }
 +    }
 +
 +    if (!(ret&~0777)) {
 +        ret |= S_IFREG;
 +    }
 +
 +    if (mode & P9_STAT_MODE_SETUID) {
 +        ret |= S_ISUID;
 +    }
 +    if (mode & P9_STAT_MODE_SETGID) {
 +        ret |= S_ISGID;
 +    }
 +    if (mode & P9_STAT_MODE_SETVTX) {
 +        ret |= S_ISVTX;
 +    }
 +
 +    return ret;
 +}
 +#endif
 +
 +static int donttouch_stat(V9fsStat *stat)
 +{
 +    if (stat->type == -1 &&
 +        stat->dev == -1 &&
 +        stat->qid.type == -1 &&
 +        stat->qid.version == -1 &&
 +        stat->qid.path == -1 &&
 +        stat->mode == -1 &&
 +        stat->atime == -1 &&
 +        stat->mtime == -1 &&
 +        stat->length == -1 &&
 +        !stat->name.size &&
 +        !stat->uid.size &&
 +        !stat->gid.size &&
 +        !stat->muid.size &&
 +        stat->n_uid == -1 &&
 +        stat->n_gid == -1 &&
 +        stat->n_muid == -1) {
 +        return 1;
 +    }
 +
 +    return 0;
 +}
 +
 +static void v9fs_stat_init(V9fsStat *stat)
 +{
 +    v9fs_string_init(&stat->name);
 +    v9fs_string_init(&stat->uid);
 +    v9fs_string_init(&stat->gid);
 +    v9fs_string_init(&stat->muid);
 +    v9fs_string_init(&stat->extension);
 +}
 +
 +static void v9fs_stat_free(V9fsStat *stat)
 +{
 +    v9fs_string_free(&stat->name);
 +    v9fs_string_free(&stat->uid);
 +    v9fs_string_free(&stat->gid);
 +    v9fs_string_free(&stat->muid);
 +    v9fs_string_free(&stat->extension);
 +}
 +
 +static uint32_t stat_to_v9mode(const struct stat *stbuf)
 +{
 +    uint32_t mode;
 +
 +    mode = stbuf->st_mode & 0777;
 +#ifndef CONFIG_WIN32
 +    if (S_ISDIR(stbuf->st_mode)) {
 +        mode |= P9_STAT_MODE_DIR;
 +    }
 +
 +    if (S_ISLNK(stbuf->st_mode)) {
 +        mode |= P9_STAT_MODE_SYMLINK;
 +    }
 +
 +    if (S_ISSOCK(stbuf->st_mode)) {
 +        mode |= P9_STAT_MODE_SOCKET;
 +    }
 +
 +    if (S_ISFIFO(stbuf->st_mode)) {
 +        mode |= P9_STAT_MODE_NAMED_PIPE;
 +    }
 +
 +    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
 +        mode |= P9_STAT_MODE_DEVICE;
 +    }
 +
 +    if (stbuf->st_mode & S_ISUID) {
 +        mode |= P9_STAT_MODE_SETUID;
 +    }
 +
 +    if (stbuf->st_mode & S_ISGID) {
 +        mode |= P9_STAT_MODE_SETGID;
 +    }
 +
 +    if (stbuf->st_mode & S_ISVTX) {
 +        mode |= P9_STAT_MODE_SETVTX;
 +    }
 +
 +#endif
 +    return mode;
 +}
 +
 +static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
 +                            const struct stat *stbuf,
 +                            V9fsStat *v9stat)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    const char *str;
 +
 +    memset(v9stat, 0, sizeof(*v9stat));
 +
 +    stat_to_qid(stbuf, &v9stat->qid);
 +    v9stat->mode = stat_to_v9mode(stbuf);
 +    v9stat->atime = stbuf->st_atime;
 +    v9stat->mtime = stbuf->st_mtime;
 +    v9stat->length = stbuf->st_size;
 +
 +    v9fs_string_null(&v9stat->uid);
 +    v9fs_string_null(&v9stat->gid);
 +    v9fs_string_null(&v9stat->muid);
 +
 +    v9stat->n_uid = stbuf->st_uid;
 +    v9stat->n_gid = stbuf->st_gid;
 +    v9stat->n_muid = 0;
 +
 +    v9fs_string_null(&v9stat->extension);
 +
 +    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
 +        err = v9fs_co_readlink(pdu, name, &v9stat->extension);
 +        if (err < 0) {
 +            return err;
 +        }
 +    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
 +        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
 +                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
 +                major(stbuf->st_rdev), minor(stbuf->st_rdev));
 +    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
 +        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
 +                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
 +    }
 +
 +    str = strrchr(name->data, '/');
 +    if (str) {
 +        str += 1;
 +    } else {
 +        str = name->data;
 +    }
 +
 +    v9fs_string_sprintf(&v9stat->name, "%s", str);
 +
 +    v9stat->size = 61 +
 +        v9fs_string_size(&v9stat->name) +
 +        v9fs_string_size(&v9stat->uid) +
 +        v9fs_string_size(&v9stat->gid) +
 +        v9fs_string_size(&v9stat->muid) +
 +        v9fs_string_size(&v9stat->extension);
 +    return 0;
 +}
 +
 +#define P9_STATS_MODE          0x00000001ULL
 +#define P9_STATS_NLINK         0x00000002ULL
 +#define P9_STATS_UID           0x00000004ULL
 +#define P9_STATS_GID           0x00000008ULL
 +#define P9_STATS_RDEV          0x00000010ULL
 +#define P9_STATS_ATIME         0x00000020ULL
 +#define P9_STATS_MTIME         0x00000040ULL
 +#define P9_STATS_CTIME         0x00000080ULL
 +#define P9_STATS_INO           0x00000100ULL
 +#define P9_STATS_SIZE          0x00000200ULL
 +#define P9_STATS_BLOCKS        0x00000400ULL
 +
 +#define P9_STATS_BTIME         0x00000800ULL
 +#define P9_STATS_GEN           0x00001000ULL
 +#define P9_STATS_DATA_VERSION  0x00002000ULL
 +
 +#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
 +#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
 +
 +
 +static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
 +                                V9fsStatDotl *v9lstat)
 +{
 +    memset(v9lstat, 0, sizeof(*v9lstat));
 +
 +    v9lstat->st_mode = stbuf->st_mode;
 +    v9lstat->st_nlink = stbuf->st_nlink;
 +    v9lstat->st_uid = stbuf->st_uid;
 +    v9lstat->st_gid = stbuf->st_gid;
 +    v9lstat->st_rdev = stbuf->st_rdev;
 +    v9lstat->st_size = stbuf->st_size;
 +#ifndef CONFIG_WIN32
 +    v9lstat->st_blksize = stbuf->st_blksize;
 +    v9lstat->st_blocks = stbuf->st_blocks;
 +#else
 +    v9lstat->st_blksize = hostBytesPerSector;
 +    v9lstat->st_blocks = (uint64_t)(v9lstat->st_size / 512
 +                            + (v9lstat->st_size % 512 ? 1 : 0)); //round up
 +#endif
 +#ifdef CONFIG_LINUX
 +    v9lstat->st_atime_sec = stbuf->st_atime;
 +    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
 +    v9lstat->st_mtime_sec = stbuf->st_mtime;
 +    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
 +    v9lstat->st_ctime_sec = stbuf->st_ctime;
 +    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
 +#else // darwin
 +#ifndef CONFIG_WIN32
 +    v9lstat->st_atime_sec = stbuf->st_atimespec.tv_sec;
 +    v9lstat->st_atime_nsec = stbuf->st_atimespec.tv_nsec;
 +    v9lstat->st_mtime_sec = stbuf->st_mtimespec.tv_sec;
 +    v9lstat->st_mtime_nsec = stbuf->st_mtimespec.tv_nsec;
 +    v9lstat->st_ctime_sec = stbuf->st_ctimespec.tv_sec;
 +    v9lstat->st_ctime_nsec = stbuf->st_ctimespec.tv_nsec;
 +#else
 +    v9lstat->st_atime_sec = stbuf->st_atime;
 +    v9lstat->st_atime_nsec = 0;
 +    v9lstat->st_mtime_sec = stbuf->st_mtime;
 +    v9lstat->st_mtime_nsec = 0;
 +    v9lstat->st_ctime_sec = stbuf->st_ctime;
 +    v9lstat->st_ctime_nsec = 0;
 +#endif
 +#endif
 +
 +    /* Currently we only support BASIC fields in stat */
 +    v9lstat->st_result_mask = P9_STATS_BASIC;
 +
 +    stat_to_qid(stbuf, &v9lstat->qid);
 +}
 +
 +static void print_sg(struct iovec *sg, int cnt)
 +{
 +    int i;
 +
 +    printf("sg[%d]: {", cnt);
 +    for (i = 0; i < cnt; i++) {
 +        if (i) {
 +            printf(", ");
 +        }
 +        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
 +    }
 +    printf("}\n");
 +}
 +
 +/* Will call this only for path name based fid */
 +static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
 +{
 +    V9fsPath str;
 +    v9fs_path_init(&str);
 +    v9fs_path_copy(&str, dst);
 +    v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
 +    v9fs_path_free(&str);
 +    /* +1 to include terminating NULL */
 +    dst->size++;
 +}
 +
 +static inline bool is_ro_export(FsContext *ctx)
 +{
 +    return ctx->export_flags & V9FS_RDONLY;
 +}
 +
 +static void v9fs_version(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    ssize_t err;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +    V9fsString version;
 +    size_t offset = 7;
 +
 +    v9fs_string_init(&version);
 +    err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
 +    if (err < 0) {
 +        offset = err;
 +        goto out;
 +    }
 +    trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
 +
 +    virtfs_reset(pdu);
 +
 +    if (!strcmp(version.data, "9P2000.u")) {
 +        s->proto_version = V9FS_PROTO_2000U;
 +    } else if (!strcmp(version.data, "9P2000.L")) {
 +        s->proto_version = V9FS_PROTO_2000L;
 +    } else {
 +        v9fs_string_sprintf(&version, "unknown");
 +    }
 +
 +    err = pdu_marshal(pdu, offset, "ds", s->msize, &version);
 +    if (err < 0) {
 +        offset = err;
 +        goto out;
 +    }
 +    offset += err;
 +    trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
 +out:
 +    pdu_complete(pdu, offset);
 +    v9fs_string_free(&version);
 +}
 +
 +static void v9fs_attach(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +    int32_t fid, afid, n_uname;
 +    V9fsString uname, aname;
 +    V9fsFidState *fidp;
 +    size_t offset = 7;
 +    V9fsQID qid;
 +    ssize_t err;
 +
 +    v9fs_string_init(&uname);
 +    v9fs_string_init(&aname);
 +    err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
 +                        &afid, &uname, &aname, &n_uname);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
 +
 +    fidp = alloc_fid(s, fid);
 +    if (fidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    fidp->uid = n_uname;
 +#ifndef CONFIG_WIN32
 +    err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
 +#else
 +    err = v9fs_co_name_to_path(pdu, NULL, "\\", &fidp->path);
 +#endif
 +    if (err < 0) {
 +        err = -EINVAL;
 +        clunk_fid(s, fid);
 +        goto out;
 +    }
 +    err = fid_to_qid(pdu, fidp, &qid);
 +    if (err < 0) {
 +        err = -EINVAL;
 +        clunk_fid(s, fid);
 +        goto out;
 +    }
 +    err = pdu_marshal(pdu, offset, "Q", &qid);
 +    if (err < 0) {
 +        clunk_fid(s, fid);
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_attach_return(pdu->tag, pdu->id,
 +                             qid.type, qid.version, qid.path);
 +    /*
 +     * disable migration if we haven't done already.
 +     * attach could get called multiple times for the same export.
 +     */
 +    if (!s->migration_blocker) {
 +        s->root_fid = fid;
 +        error_setg(&s->migration_blocker,
 +                   "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
 +                   s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
 +        migrate_add_blocker(s->migration_blocker);
 +    }
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&uname);
 +    v9fs_string_free(&aname);
 +}
 +
 +static void v9fs_stat(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    V9fsStat v9stat;
 +    ssize_t err = 0;
 +    size_t offset = 7;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    err = pdu_unmarshal(pdu, offset, "d", &fid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_stat(pdu->tag, pdu->id, fid);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
 +    if (err < 0) {
 +        v9fs_stat_free(&v9stat);
 +        goto out;
 +    }
 +    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
 +                           v9stat.atime, v9stat.mtime, v9stat.length);
 +    err += offset;
 +    v9fs_stat_free(&v9stat);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static void v9fs_getattr(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    size_t offset = 7;
 +    ssize_t retval = 0;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    uint64_t request_mask;
 +    V9fsStatDotl v9stat_dotl;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
 +    if (retval < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        retval = -ENOENT;
 +        goto out_nofid;
 +    }
 +    /*
 +     * Currently we only support BASIC fields in stat, so there is no
 +     * need to look at request_mask.
 +     */
 +    retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
 +    if (retval < 0) {
 +        goto out;
 +    }
 +    stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
 +
 +    /*  fill st_gen if requested and supported by underlying fs */
 +    if (request_mask & P9_STATS_GEN) {
 +        retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
 +        switch (retval) {
 +        case 0:
 +            /* we have valid st_gen: update result mask */
 +            v9stat_dotl.st_result_mask |= P9_STATS_GEN;
 +            break;
 +        case -EINTR:
 +            /* request cancelled, e.g. by Tflush */
 +            goto out;
 +        default:
 +            /* failed to get st_gen: not fatal, ignore */
 +            break;
 +        }
 +    }
 +    retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
 +    if (retval < 0) {
 +        goto out;
 +    }
 +    retval += offset;
 +    trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
 +                              v9stat_dotl.st_mode, v9stat_dotl.st_uid,
 +                              v9stat_dotl.st_gid);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, retval);
 +}
 +
 +/* Attribute flags */
 +#define P9_ATTR_MODE       (1 << 0)
 +#define P9_ATTR_UID        (1 << 1)
 +#define P9_ATTR_GID        (1 << 2)
 +#define P9_ATTR_SIZE       (1 << 3)
 +#define P9_ATTR_ATIME      (1 << 4)
 +#define P9_ATTR_MTIME      (1 << 5)
 +#define P9_ATTR_CTIME      (1 << 6)
 +#define P9_ATTR_ATIME_SET  (1 << 7)
 +#define P9_ATTR_MTIME_SET  (1 << 8)
 +
 +#define P9_ATTR_MASK    127
 +
 +static void v9fs_setattr(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err = 0;
 +    int32_t fid;
 +    V9fsFidState *fidp;
 +    size_t offset = 7;
 +    V9fsIattr v9iattr;
 +    V9fsPDU *pdu = opaque;
 +
 +    err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    if (v9iattr.valid & P9_ATTR_MODE) {
 +#ifndef CONFIG_WIN32
 +        err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
 +#else
 +        err = -EPERM;
 +#endif
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) {
 +        struct timespec times[2];
 +        if (v9iattr.valid & P9_ATTR_ATIME) {
 +            if (v9iattr.valid & P9_ATTR_ATIME_SET) {
 +                times[0].tv_sec = v9iattr.atime_sec;
 +                times[0].tv_nsec = v9iattr.atime_nsec;
 +            } else {
 +                times[0].tv_nsec = UTIME_NOW;
 +            }
 +        } else {
 +            times[0].tv_nsec = UTIME_OMIT;
 +        }
 +        if (v9iattr.valid & P9_ATTR_MTIME) {
 +            if (v9iattr.valid & P9_ATTR_MTIME_SET) {
 +                times[1].tv_sec = v9iattr.mtime_sec;
 +                times[1].tv_nsec = v9iattr.mtime_nsec;
 +            } else {
 +                times[1].tv_nsec = UTIME_NOW;
 +            }
 +        } else {
 +            times[1].tv_nsec = UTIME_OMIT;
 +        }
 +        err = v9fs_co_utimensat(pdu, &fidp->path, times);
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    /*
 +     * If the only valid entry in iattr is ctime we can call
 +     * chown(-1,-1) to update the ctime of the file
 +     */
 +    if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) ||
 +        ((v9iattr.valid & P9_ATTR_CTIME)
 +         && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) {
 +        if (!(v9iattr.valid & P9_ATTR_UID)) {
 +            v9iattr.uid = -1;
 +        }
 +        if (!(v9iattr.valid & P9_ATTR_GID)) {
 +            v9iattr.gid = -1;
 +        }
 +#ifndef CONFIG_WIN32
 +        err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
 +                            v9iattr.gid);
 +#else
 +        err = -EPERM;
 +#endif
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    if (v9iattr.valid & (P9_ATTR_SIZE)) {
 +        err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    err = offset;
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
 +{
 +    int i;
 +    ssize_t err;
 +    size_t offset = 7;
 +
 +    err = pdu_marshal(pdu, offset, "w", nwnames);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        return err;
 +    }
 +    offset += err;
 +    for (i = 0; i < nwnames; i++) {
 +        err = pdu_marshal(pdu, offset, "Q", &qids[i]);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            return err;
 +        }
 +        offset += err;
 +    }
 +    return offset;
 +}
 +
 +static void v9fs_walk(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int name_idx;
 +    V9fsQID *qids = NULL;
 +    int i, err = 0;
 +    V9fsPath dpath, path;
 +    uint16_t nwnames;
 +    struct stat stbuf;
 +    size_t offset = 7;
 +    int32_t fid, newfid;
 +    V9fsString *wnames = NULL;
 +    V9fsFidState *fidp;
 +    V9fsFidState *newfidp = NULL;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        pdu_complete(pdu, err);
 +        return ;
 +    }
 +    offset += err;
 +
 +    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
 +
 +    if (nwnames && nwnames <= P9_MAXWELEM) {
 +        wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
 +        qids   = g_malloc0(sizeof(qids[0]) * nwnames);
 +        for (i = 0; i < nwnames; i++) {
 +            err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
 +            if (err < 0) {
 +                ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +                goto out_nofid;
 +            }
 +            offset += err;
 +        }
 +    } else if (nwnames > P9_MAXWELEM) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    v9fs_path_init(&dpath);
 +    v9fs_path_init(&path);
 +    /*
 +     * Both dpath and path initially poin to fidp.
 +     * Needed to handle request with nwnames == 0
 +     */
 +    v9fs_path_copy(&dpath, &fidp->path);
 +    v9fs_path_copy(&path, &fidp->path);
 +    for (name_idx = 0; name_idx < nwnames; name_idx++) {
 +        err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_lstat(pdu, &path, &stbuf);
 +        if (err < 0) {
 +            goto out;
 +        }
 +        stat_to_qid(&stbuf, &qids[name_idx]);
 +        v9fs_path_copy(&dpath, &path);
 +    }
 +    if (fid == newfid) {
 +        BUG_ON(fidp->fid_type != P9_FID_NONE);
 +        WARN("[%d][ >> %s]\n", __LINE__, __func__);
 +        v9fs_path_copy(&fidp->path, &path);
 +    } else {
 +        newfidp = alloc_fid(s, newfid);
 +        if (newfidp == NULL) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            err = -EINVAL;
 +            goto out;
 +        }
 +        newfidp->uid = fidp->uid;
 +        v9fs_path_copy(&newfidp->path, &path);
 +    }
 +    err = v9fs_walk_marshal(pdu, nwnames, qids);
 +    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
 +out:
 +    put_fid(pdu, fidp);
 +    if (newfidp) {
 +        put_fid(pdu, newfidp);
 +    }
 +    v9fs_path_free(&dpath);
 +    v9fs_path_free(&path);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    if (nwnames && nwnames <= P9_MAXWELEM) {
 +        for (name_idx = 0; name_idx < nwnames; name_idx++) {
 +            v9fs_string_free(&wnames[name_idx]);
 +        }
 +        g_free(wnames);
 +        g_free(qids);
 +    }
 +}
 +
 +static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
 +{
 +    struct statfs stbuf;
 +    int32_t iounit = 0;
 +    V9fsState *s = pdu->s;
 +
 +    /*
 +     * iounit should be multiples of f_bsize (host filesystem block size
 +     * and as well as less than (client msize - P9_IOHDRSZ))
 +     */
 +    if (!v9fs_co_statfs(pdu, path, &stbuf)) {
 +        iounit = stbuf.f_bsize;
 +        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
 +    }
 +    if (!iounit) {
 +        iounit = s->msize - P9_IOHDRSZ;
 +    }
 +    return iounit;
 +}
 +
 +static void v9fs_open(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int flags;
 +    int32_t fid;
 +    int32_t mode;
 +    V9fsQID qid;
 +    int iounit = 0;
 +    ssize_t err = 0;
 +    size_t offset = 7;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    if (s->proto_version == V9FS_PROTO_2000L) {
 +        err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
 +    } else {
 +        uint8_t modebyte;
 +        err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
 +        mode = modebyte;
 +    }
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    BUG_ON(fidp->fid_type != P9_FID_NONE);
 +
 +    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out;
 +    }
 +    stat_to_qid(&stbuf, &qid);
 +    if (S_ISDIR(stbuf.st_mode)) {
 +        err = v9fs_co_opendir(pdu, fidp);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        fidp->fid_type = P9_FID_DIR;
 +        err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err += offset;
 +    } else {
 +        if (s->proto_version == V9FS_PROTO_2000L) {
 +            flags = get_dotl_openflags(s, mode);
 +        } else {
 +            flags = omode_to_uflags(mode);
 +        }
 +        if (is_ro_export(&s->ctx)) {
 +            if (mode & O_WRONLY || mode & O_RDWR ||
 +                mode & O_APPEND || mode & O_TRUNC) {
 +                ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +                err = -EROFS;
 +                goto out;
 +            }
 +        }
 +        err = v9fs_co_open(pdu, fidp, flags);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        fidp->fid_type = P9_FID_FILE;
 +        fidp->open_flags = flags;
 +        if (flags & O_EXCL) {
 +            /*
 +             * We let the host file system do O_EXCL check
 +             * We should not reclaim such fd
 +             */
 +            fidp->flags |= FID_NON_RECLAIMABLE;
 +        }
 +        iounit = get_iounit(pdu, &fidp->path);
 +        err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err += offset;
 +    }
 +    trace_v9fs_open_return(pdu->tag, pdu->id,
 +                           qid.type, qid.version, qid.path, iounit);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static void v9fs_lcreate(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t dfid, flags, mode;
 +    gid_t gid;
 +    ssize_t err = 0;
 +    ssize_t offset = 7;
 +    V9fsString name;
 +    V9fsFidState *fidp;
 +    struct stat stbuf;
 +    V9fsQID qid;
 +    int32_t iounit;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
 +                        &name, &flags, &mode, &gid);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
 +
 +    fidp = get_fid(pdu, dfid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +
 +    flags = get_dotl_openflags(pdu->s, flags);
 +    err = v9fs_co_open2(pdu, fidp, &name, gid,
 +                        flags | O_CREAT, mode, &stbuf);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out;
 +    }
 +    fidp->fid_type = P9_FID_FILE;
 +    fidp->open_flags = flags;
 +    if (flags & O_EXCL) {
 +        /*
 +         * We let the host file system do O_EXCL check
 +         * We should not reclaim such fd
 +         */
 +        fidp->flags |= FID_NON_RECLAIMABLE;
 +    }
 +    iounit =  get_iounit(pdu, &fidp->path);
 +    stat_to_qid(&stbuf, &qid);
 +    err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
 +                              qid.type, qid.version, qid.path, iounit);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +
 +static void v9fs_fsync(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err;
 +    int32_t fid;
 +    int datasync;
 +    size_t offset = 7;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    err = v9fs_co_fsync(pdu, fidp, datasync);
 +    if (!err) {
 +        err = offset;
 +    }
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static void v9fs_clunk(void *opaque)
 +{
 +    int err;
 +    int32_t fid;
 +    size_t offset = 7;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    err = pdu_unmarshal(pdu, offset, "d", &fid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_clunk(pdu->tag, pdu->id, fid);
 +
 +    fidp = clunk_fid(s, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    /*
 +     * Bump the ref so that put_fid will
 +     * free the fid.
 +     */
 +    fidp->ref++;
 +    err = put_fid(pdu, fidp);
 +    if (!err) {
 +        err = offset;
 +    }
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +#ifndef CONFIG_WIN32
 +static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
 +                           uint64_t off, uint32_t max_count)
 +{
 +    ssize_t err;
 +    size_t offset = 7;
 +    int read_count;
 +    int64_t xattr_len;
 +    V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
 +    VirtQueueElement *elem = v->elems[pdu->idx];
 +
 +    xattr_len = fidp->fs.xattr.len;
 +    read_count = xattr_len - off;
 +    if (read_count > max_count) {
 +        read_count = max_count;
 +    } else if (read_count < 0) {
 +        /*
 +         * read beyond XATTR value
 +         */
 +        read_count = 0;
 +    }
 +    err = pdu_marshal(pdu, offset, "d", read_count);
 +    if (err < 0) {
 +        return err;
 +    }
 +    offset += err;
 +
 +    err = v9fs_pack(elem->in_sg, elem->in_num, offset,
 +                    ((char *)fidp->fs.xattr.value) + off,
 +                    read_count);
 +    if (err < 0) {
 +        return err;
 +    }
 +    offset += err;
 +    return offset;
 +}
 +#endif
 +
 +static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
 +                                     V9fsFidState *fidp, uint32_t max_count)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsPath path;
 +    V9fsStat v9stat;
 +    int len, err = 0;
 +    int32_t count = 0;
 +    struct stat stbuf;
 +    off_t saved_dir_pos;
-         err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
- #ifdef CONFIG_WIN32
-         dent = result;
- #endif
-         if (err || !result) {
++    struct dirent *dent;
 +
 +    /* save the directory position */
 +    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
 +    if (saved_dir_pos < 0) {
 +        return saved_dir_pos;
 +    }
 +
 +    dent = g_malloc(sizeof(struct dirent));
 +
 +    while (1) {
 +        v9fs_path_init(&path);
-     struct dirent *dent, *result;
++
++        v9fs_readdir_lock(&fidp->fs.dir);
++
++        err = v9fs_co_readdir(pdu, fidp, &dent);
++        if (err || !dent) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            break;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_lstat(pdu, &path, &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
 +        len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
++
++        v9fs_readdir_unlock(&fidp->fs.dir);
++
 +        if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
 +            /* Ran out of buffer. Set dir back to old position and return */
 +            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
 +            v9fs_stat_free(&v9stat);
 +            v9fs_path_free(&path);
 +            g_free(dent);
 +            return count;
 +        }
 +        count += len;
 +        v9fs_stat_free(&v9stat);
 +        v9fs_path_free(&path);
 +#ifdef CONFIG_LINUX
 +        saved_dir_pos = dent->d_off;
 +#else
 +        saved_dir_pos = v9fs_co_telldir(pdu, fidp);
 +#endif
 +    }
 +out:
 +    g_free(dent);
++
++    v9fs_readdir_unlock(&fidp->fs.dir);
++
 +    v9fs_path_free(&path);
 +    if (err < 0) {
 +        return err;
 +    }
 +    return count;
 +}
 +
 +/*
 + * Create a QEMUIOVector for a sub-region of PDU iovecs
 + *
 + * @qiov:       uninitialized QEMUIOVector
 + * @skip:       number of bytes to skip from beginning of PDU
 + * @size:       number of bytes to include
 + * @is_write:   true - write, false - read
 + *
 + * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
 + * with qemu_iovec_destroy().
 + */
 +static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
 +                                    size_t skip, size_t size,
 +                                    bool is_write)
 +{
 +    QEMUIOVector elem;
 +    struct iovec *iov;
 +    unsigned int niov;
 +
 +    virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write);
 +
 +    qemu_iovec_init_external(&elem, iov, niov);
 +    qemu_iovec_init(qiov, niov);
 +    qemu_iovec_concat(qiov, &elem, skip, size);
 +}
 +
 +static void v9fs_read(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    uint64_t off;
 +    ssize_t err = 0;
 +    int32_t count = 0;
 +    size_t offset = 7;
 +    uint32_t max_count;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +#ifndef CONFIG_WIN32
 +    V9fsState *s = pdu->s;
 +#endif
 +
 +    err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    if (fidp->fid_type == P9_FID_DIR) {
 +
 +        if (off == 0) {
 +            v9fs_co_rewinddir(pdu, fidp);
 +        }
 +        count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
 +        if (count < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            err = count;
 +            goto out;
 +        }
 +        err = pdu_marshal(pdu, offset, "d", count);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err += offset + count;
 +    } else if (fidp->fid_type == P9_FID_FILE) {
 +        QEMUIOVector qiov_full;
 +        QEMUIOVector qiov;
 +        int32_t len;
 +
 +        v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
 +        qemu_iovec_init(&qiov, qiov_full.niov);
 +        do {
 +            qemu_iovec_reset(&qiov);
 +            qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
 +            if (0) {
 +                print_sg(qiov.iov, qiov.niov);
 +            }
 +            /* Loop in case of EINTR */
 +            do {
 +                len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
 +                if (len >= 0) {
 +                    off   += len;
 +                    count += len;
 +                }
 +            } while (len == -EINTR && !pdu->cancelled);
 +            if (len < 0) {
 +                /* IO error return the error */
 +                ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +                err = len;
 +                goto out;
 +            }
 +        } while (count < max_count && len > 0);
 +        err = pdu_marshal(pdu, offset, "d", count);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err += offset + count;
 +        qemu_iovec_destroy(&qiov);
 +        qemu_iovec_destroy(&qiov_full);
 +#ifndef CONFIG_WIN32
 +    } else if (fidp->fid_type == P9_FID_XATTR) {
 +        err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
 +#endif
 +    } else {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -EINVAL;
 +    }
 +    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static size_t v9fs_readdir_data_size(V9fsString *name)
 +{
 +    /*
 +     * Size of each dirent on the wire: size of qid (13) + size of offset (8)
 +     * size of type (1) + size of name.size (2) + strlen(name.data)
 +     */
 +    return 24 + v9fs_string_size(name);
 +}
 +
 +static int v9fs_do_readdir(V9fsPDU *pdu,
 +                           V9fsFidState *fidp, int32_t max_count)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    size_t size;
 +    V9fsQID qid;
 +    V9fsString name;
 +    int len, err = 0;
 +    int32_t count = 0;
 +    off_t saved_dir_pos;
-         err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
- #ifdef CONFIG_WIN32
-         dent = result;
- #endif
-         if (err) {
-             ERR("[%d][ >> %s]\n", __LINE__, __func__);
-             break;
-         }
++    struct dirent *dent;
 +#ifndef CONFIG_LINUX
 +    uint64_t d_offset = 0;
 +#endif
 +
 +    /* save the directory position */
 +    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
 +    if (saved_dir_pos < 0) {
 +        return saved_dir_pos;
 +    }
 +
 +    dent = g_malloc(sizeof(struct dirent));
 +
 +    while (1) {
-         if (!result) {
-             TRACE("[%d][ >> %s] v9fs_co_readdir_r has no result.\n", __LINE__, __func__);
++        v9fs_readdir_lock(&fidp->fs.dir);
 +
++        err = v9fs_co_readdir(pdu, fidp, &dent);
++        if (err || !dent) {
++            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            break;
 +        }
-     if (!fidp->fs.dir) {
 +        v9fs_string_init(&name);
 +        v9fs_string_sprintf(&name, "%s", dent->d_name);
 +        if ((count + v9fs_readdir_data_size(&name)) > max_count) {
 +            /* Ran out of buffer. Set dir back to old position and return */
 +            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
 +            v9fs_string_free(&name);
 +            g_free(dent);
 +            return count;
 +        }
 +        /*
 +         * Fill up just the path field of qid because the client uses
 +         * only that. To fill the entire qid structure we will have
 +         * to stat each dirent found, which is expensive
 +         */
 +        size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
 +        memcpy(&qid.path, &dent->d_ino, size);
 +        /* Fill the other fields with dummy values */
 +        qid.type = 0;
 +        qid.version = 0;
 +
 +        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
 +#ifdef CONFIG_LINUX
 +        len = pdu_marshal(pdu, 11 + count, "Qqbs",
 +                          &qid, dent->d_off,
 +                          dent->d_type, &name);
 +#else
 +        d_offset = v9fs_co_telldir(pdu, fidp);
 +#ifndef CONFIG_WIN32
 +        len = pdu_marshal(pdu, 11 + count, "Qqbs",
 +                          &qid, d_offset,
 +                          dent->d_type, &name);
 +#else
 +        len = pdu_marshal(pdu, 11 + count, "Qqbs",
 +                          &qid, d_offset,
 +                          WIN32_D_TYPE, &name);
 +#endif
 +#endif
++
++        v9fs_readdir_unlock(&fidp->fs.dir);
++
 +        if (len < 0) {
 +            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
 +            v9fs_string_free(&name);
 +            g_free(dent);
 +            return len;
 +        }
 +        count += len;
 +        v9fs_string_free(&name);
 +#ifdef CONFIG_LINUX
 +        saved_dir_pos = dent->d_off;
 +#else
 +        saved_dir_pos = d_offset;
 +#endif
 +    }
 +    g_free(dent);
++
++    v9fs_readdir_unlock(&fidp->fs.dir);
++
 +    if (err < 0) {
 +        return err;
 +    }
 +    return count;
 +}
 +
 +static void v9fs_readdir(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    V9fsFidState *fidp;
 +    ssize_t retval = 0;
 +    size_t offset = 7;
 +    uint64_t initial_offset;
 +    int32_t count;
 +    uint32_t max_count;
 +    V9fsPDU *pdu = opaque;
 +
 +    retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
 +                           &initial_offset, &max_count);
 +    if (retval < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        retval = -EINVAL;
 +        goto out_nofid;
 +    }
-     co = qemu_coroutine_create(handler);
-     qemu_coroutine_enter(co, pdu);
++    if (!fidp->fs.dir.stream) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        retval = -EINVAL;
 +        goto out;
 +    }
 +    if (initial_offset == 0) {
 +        v9fs_co_rewinddir(pdu, fidp);
 +    } else {
 +        v9fs_co_seekdir(pdu, fidp, initial_offset);
 +    }
 +    count = v9fs_do_readdir(pdu, fidp, max_count);
 +    if (count < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        retval = count;
 +        goto out;
 +    }
 +    retval = pdu_marshal(pdu, offset, "d", count);
 +    if (retval < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out;
 +    }
 +    retval += count + offset;
 +    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, retval);
 +}
 +
 +#ifndef CONFIG_WIN32
 +static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
 +                            uint64_t off, uint32_t count,
 +                            struct iovec *sg, int cnt)
 +{
 +    int i, to_copy;
 +    ssize_t err = 0;
 +    int write_count;
 +    int64_t xattr_len;
 +    size_t offset = 7;
 +
 +
 +    xattr_len = fidp->fs.xattr.len;
 +    write_count = xattr_len - off;
 +    if (write_count > count) {
 +        write_count = count;
 +    } else if (write_count < 0) {
 +        /*
 +         * write beyond XATTR value len specified in
 +         * xattrcreate
 +         */
 +        err = -ENOSPC;
 +        goto out;
 +    }
 +    err = pdu_marshal(pdu, offset, "d", write_count);
 +    if (err < 0) {
 +        return err;
 +    }
 +    err += offset;
 +    fidp->fs.xattr.copied_len += write_count;
 +    /*
 +     * Now copy the content from sg list
 +     */
 +    for (i = 0; i < cnt; i++) {
 +        if (write_count > sg[i].iov_len) {
 +            to_copy = sg[i].iov_len;
 +        } else {
 +            to_copy = write_count;
 +        }
 +        memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
 +        /* updating vs->off since we are not using below */
 +        off += to_copy;
 +        write_count -= to_copy;
 +    }
 +out:
 +    return err;
 +}
 +#endif
 +
 +static void v9fs_write(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    ssize_t err;
 +    int32_t fid;
 +    uint64_t off;
 +    uint32_t count;
 +    int32_t len = 0;
 +    int32_t total = 0;
 +    size_t offset = 7;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +#ifndef CONFIG_WIN32
 +    V9fsState *s = pdu->s;
 +#endif
 +    QEMUIOVector qiov_full;
 +    QEMUIOVector qiov;
 +
 +    err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        pdu_complete(pdu, err);
 +        return;
 +    }
 +    offset += err;
 +    v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
 +    trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    if (fidp->fid_type == P9_FID_FILE) {
 +        if (fidp->fs.fd == -1) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            err = -EINVAL;
 +            goto out;
 +        }
 +    } else if (fidp->fid_type == P9_FID_XATTR) {
 +        /*
 +         * setxattr operation
 +         */
 +#ifndef CONFIG_WIN32
 +        err = v9fs_xattr_write(s, pdu, fidp, off, count,
 +                               qiov_full.iov, qiov_full.niov);
 +#endif
 +        goto out;
 +    } else {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -EINVAL;
 +        goto out;
 +    }
 +    qemu_iovec_init(&qiov, qiov_full.niov);
 +    do {
 +        qemu_iovec_reset(&qiov);
 +        qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total);
 +        if (0) {
 +            print_sg(qiov.iov, qiov.niov);
 +        }
 +        /* Loop in case of EINTR */
 +        do {
 +            len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
 +            if (len >= 0) {
 +                off   += len;
 +                total += len;
 +            }
 +        } while (len == -EINTR && !pdu->cancelled);
 +        if (len < 0) {
 +            /* IO error return the error */
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            err = len;
 +            goto out_qiov;
 +        }
 +    } while (total < count && len > 0);
 +
 +    offset = 7;
 +    err = pdu_marshal(pdu, offset, "d", total);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
 +out_qiov:
 +    qemu_iovec_destroy(&qiov);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    qemu_iovec_destroy(&qiov_full);
 +    pdu_complete(pdu, err);
 +}
 +
 +static void v9fs_create(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    int err = 0;
 +    size_t offset = 7;
 +    V9fsFidState *fidp;
 +    V9fsQID qid;
 +    int32_t perm;
 +    int8_t mode;
 +    V9fsPath path;
 +    struct stat stbuf;
 +    V9fsString name;
 +    V9fsString extension;
 +    int iounit;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_path_init(&path);
 +    v9fs_string_init(&name);
 +    v9fs_string_init(&extension);
 +    err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
 +                        &perm, &mode, &extension);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out_nofid;
 +    }
 +    trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    if (perm & P9_STAT_MODE_DIR) {
 +        err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
 +                            fidp->uid, -1, &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        v9fs_path_copy(&fidp->path, &path);
 +        err = v9fs_co_opendir(pdu, fidp);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        fidp->fid_type = P9_FID_DIR;
 +#ifndef CONFIG_WIN32
 +    } else if (perm & P9_STAT_MODE_SYMLINK) {
 +        err = v9fs_co_symlink(pdu, fidp, &name,
 +                              extension.data, -1 , &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        v9fs_path_copy(&fidp->path, &path);
 +    } else if (perm & P9_STAT_MODE_LINK) {
 +        int32_t ofid = atoi(extension.data);
 +        V9fsFidState *ofidp = get_fid(pdu, ofid);
 +        if (ofidp == NULL) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            err = -EINVAL;
 +            goto out;
 +        }
 +        err = v9fs_co_link(pdu, ofidp, fidp, &name);
 +        put_fid(pdu, ofidp);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            fidp->fid_type = P9_FID_NONE;
 +            goto out;
 +        }
 +        v9fs_path_copy(&fidp->path, &path);
 +        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            fidp->fid_type = P9_FID_NONE;
 +            goto out;
 +        }
 +    } else if (perm & P9_STAT_MODE_DEVICE) {
 +        char ctype;
 +        uint32_t major, minor;
 +        mode_t nmode = 0;
 +
 +        if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            err = -errno;
 +            goto out;
 +        }
 +
 +        switch (ctype) {
 +        case 'c':
 +            nmode = S_IFCHR;
 +            break;
 +        case 'b':
 +            nmode = S_IFBLK;
 +            break;
 +        default:
 +            err = -EIO;
 +            goto out;
 +        }
 +
 +        nmode |= perm & 0777;
 +        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
 +                            makedev(major, minor), nmode, &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        v9fs_path_copy(&fidp->path, &path);
 +    } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
 +        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
 +                            0, S_IFIFO | (perm & 0777), &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        v9fs_path_copy(&fidp->path, &path);
 +    } else if (perm & P9_STAT_MODE_SOCKET) {
 +        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
 +                            0, S_IFSOCK | (perm & 0777), &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        v9fs_path_copy(&fidp->path, &path);
 +#endif
 +    } else {
 +        err = v9fs_co_open2(pdu, fidp, &name, -1,
 +                            omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
 +        if (err < 0) {
 +            ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +            goto out;
 +        }
 +        fidp->fid_type = P9_FID_FILE;
 +        fidp->open_flags = omode_to_uflags(mode);
 +        if (fidp->open_flags & O_EXCL) {
 +            /*
 +             * We let the host file system do O_EXCL check
 +             * We should not reclaim such fd
 +             */
 +            fidp->flags |= FID_NON_RECLAIMABLE;
 +        }
 +    }
 +    iounit = get_iounit(pdu, &fidp->path);
 +    stat_to_qid(&stbuf, &qid);
 +    err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
 +    if (err < 0) {
 +        ERR("[%d][ >> %s]\n", __LINE__, __func__);
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_create_return(pdu->tag, pdu->id,
 +                             qid.type, qid.version, qid.path, iounit);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +   pdu_complete(pdu, err);
 +   v9fs_string_free(&name);
 +   v9fs_string_free(&extension);
 +   v9fs_path_free(&path);
 +}
 +
 +static void v9fs_symlink(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    V9fsString name;
 +    V9fsString symname;
 +    V9fsFidState *dfidp;
 +    V9fsQID qid;
 +    struct stat stbuf;
 +    int32_t dfid;
 +    int err = 0;
 +    gid_t gid;
 +    size_t offset = 7;
 +
 +    v9fs_string_init(&name);
 +    v9fs_string_init(&symname);
 +    err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
 +
 +    dfidp = get_fid(pdu, dfid);
 +    if (dfidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +#ifndef CONFIG_WIN32
 +    err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
 +#else
 +    err = -EPERM;
 +#endif
 +    if (err < 0) {
 +        goto out;
 +    }
 +    stat_to_qid(&stbuf, &qid);
 +    err =  pdu_marshal(pdu, offset, "Q", &qid);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_symlink_return(pdu->tag, pdu->id,
 +                              qid.type, qid.version, qid.path);
 +out:
 +    put_fid(pdu, dfidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +    v9fs_string_free(&symname);
 +}
 +
 +static void v9fs_flush(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    ssize_t err;
 +    int16_t tag;
 +    size_t offset = 7;
 +    V9fsPDU *cancel_pdu;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    err = pdu_unmarshal(pdu, offset, "w", &tag);
 +    if (err < 0) {
 +        pdu_complete(pdu, err);
 +        return;
 +    }
 +    trace_v9fs_flush(pdu->tag, pdu->id, tag);
 +
 +    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
 +        if (cancel_pdu->tag == tag) {
 +            break;
 +        }
 +    }
 +    if (cancel_pdu) {
 +        cancel_pdu->cancelled = 1;
 +        /*
 +         * Wait for pdu to complete.
 +         */
 +        qemu_co_queue_wait(&cancel_pdu->complete);
 +        cancel_pdu->cancelled = 0;
 +        pdu_free(cancel_pdu);
 +    }
 +    pdu_complete(pdu, 7);
 +}
 +
 +static void v9fs_link(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    int32_t dfid, oldfid;
 +    V9fsFidState *dfidp, *oldfidp;
 +    V9fsString name;
 +    size_t offset = 7;
 +    int err = 0;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
 +
 +    dfidp = get_fid(pdu, dfid);
 +    if (dfidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +
 +    oldfidp = get_fid(pdu, oldfid);
 +    if (oldfidp == NULL) {
 +        err = -ENOENT;
 +        goto out;
 +    }
 +    err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
 +    if (!err) {
 +        err = offset;
 +    }
 +out:
 +    put_fid(pdu, dfidp);
 +out_nofid:
 +    v9fs_string_free(&name);
 +    pdu_complete(pdu, err);
 +}
 +
 +/* Only works with path name based fid */
 +static void v9fs_remove(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    int err = 0;
 +    size_t offset = 7;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    err = pdu_unmarshal(pdu, offset, "d", &fid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_remove(pdu->tag, pdu->id, fid);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    /* if fs driver is not path based, return EOPNOTSUPP */
 +    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
 +        err = -EOPNOTSUPP;
 +        goto out_err;
 +    }
 +    /*
 +     * IF the file is unlinked, we cannot reopen
 +     * the file later. So don't reclaim fd
 +     */
 +    err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
 +    if (err < 0) {
 +        goto out_err;
 +    }
 +    err = v9fs_co_remove(pdu, &fidp->path);
 +    if (!err) {
 +        err = offset;
 +    }
 +out_err:
 +    /* For TREMOVE we need to clunk the fid even on failed remove */
 +    clunk_fid(pdu->s, fidp->fid);
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static void v9fs_unlinkat(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err = 0;
 +    V9fsString name;
 +    int32_t dfid, flags;
 +    size_t offset = 7;
 +    V9fsPath path;
 +    V9fsFidState *dfidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    dfidp = get_fid(pdu, dfid);
 +    if (dfidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    /*
 +     * IF the file is unlinked, we cannot reopen
 +     * the file later. So don't reclaim fd
 +     */
 +    v9fs_path_init(&path);
 +    err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
 +    if (err < 0) {
 +        goto out_err;
 +    }
 +    err = v9fs_mark_fids_unreclaim(pdu, &path);
 +    if (err < 0) {
 +        goto out_err;
 +    }
 +    err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
 +    if (!err) {
 +        err = offset;
 +    }
 +out_err:
 +    put_fid(pdu, dfidp);
 +    v9fs_path_free(&path);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +
 +/* Only works with path name based fid */
 +static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
 +                                int32_t newdirfid, V9fsString *name)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    char *end;
 +    int err = 0;
 +    V9fsPath new_path;
 +    V9fsFidState *tfidp;
 +    V9fsState *s = pdu->s;
 +    V9fsFidState *dirfidp = NULL;
 +    char *old_name, *new_name;
 +
 +    v9fs_path_init(&new_path);
 +    if (newdirfid != -1) {
 +        dirfidp = get_fid(pdu, newdirfid);
 +        if (dirfidp == NULL) {
 +            err = -ENOENT;
 +            goto out_nofid;
 +        }
 +        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
 +        v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
 +    } else {
 +        old_name = fidp->path.data;
 +        end = strrchr(old_name, '/');
 +        if (end) {
 +            end++;
 +        } else {
 +            end = old_name;
 +        }
 +        new_name = g_malloc0(end - old_name + name->size + 1);
 +        strncat(new_name, old_name, end - old_name);
 +        strncat(new_name + (end - old_name), name->data, name->size);
 +        v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
 +        g_free(new_name);
 +    }
 +    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    /*
 +     * Fixup fid's pointing to the old name to
 +     * start pointing to the new name
 +     */
 +    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
 +        if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
 +            /* replace the name */
 +            v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
 +        }
 +    }
 +out:
 +    if (dirfidp) {
 +        put_fid(pdu, dirfidp);
 +    }
 +    v9fs_path_free(&new_path);
 +out_nofid:
 +    return err;
 +}
 +
 +/* Only works with path name based fid */
 +static void v9fs_rename(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    ssize_t err = 0;
 +    size_t offset = 7;
 +    V9fsString name;
 +    int32_t newdirfid;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    BUG_ON(fidp->fid_type != P9_FID_NONE);
 +    /* if fs driver is not path based, return EOPNOTSUPP */
 +    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
 +        err = -EOPNOTSUPP;
 +        goto out;
 +    }
 +    v9fs_path_write_lock(s);
 +    err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
 +    v9fs_path_unlock(s);
 +    if (!err) {
 +        err = offset;
 +    }
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +
 +static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
 +                               V9fsString *old_name, V9fsPath *newdir,
 +                               V9fsString *new_name)
 +{
 +    V9fsFidState *tfidp;
 +    V9fsPath oldpath, newpath;
 +    V9fsState *s = pdu->s;
 +
 +
 +    v9fs_path_init(&oldpath);
 +    v9fs_path_init(&newpath);
 +    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
 +    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
 +
 +    /*
 +     * Fixup fid's pointing to the old name to
 +     * start pointing to the new name
 +     */
 +    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
 +        if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
 +            /* replace the name */
 +            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
 +        }
 +    }
 +    v9fs_path_free(&oldpath);
 +    v9fs_path_free(&newpath);
 +}
 +
 +static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
 +                                  V9fsString *old_name, int32_t newdirfid,
 +                                  V9fsString *new_name)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int err = 0;
 +    V9fsState *s = pdu->s;
 +    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
 +
 +    olddirfidp = get_fid(pdu, olddirfid);
 +    if (olddirfidp == NULL) {
 +        err = -ENOENT;
 +        goto out;
 +    }
 +    if (newdirfid != -1) {
 +        newdirfidp = get_fid(pdu, newdirfid);
 +        if (newdirfidp == NULL) {
 +            err = -ENOENT;
 +            goto out;
 +        }
 +    } else {
 +        newdirfidp = get_fid(pdu, olddirfid);
 +    }
 +
 +    err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
 +                           &newdirfidp->path, new_name);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
 +        /* Only for path based fid  we need to do the below fixup */
 +        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
 +                           &newdirfidp->path, new_name);
 +    }
 +out:
 +    if (olddirfidp) {
 +        put_fid(pdu, olddirfidp);
 +    }
 +    if (newdirfidp) {
 +        put_fid(pdu, newdirfidp);
 +    }
 +    return err;
 +}
 +
 +static void v9fs_renameat(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    ssize_t err = 0;
 +    size_t offset = 7;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +    int32_t olddirfid, newdirfid;
 +    V9fsString old_name, new_name;
 +
 +    v9fs_string_init(&old_name);
 +    v9fs_string_init(&new_name);
 +    err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
 +                        &old_name, &newdirfid, &new_name);
 +    if (err < 0) {
 +        goto out_err;
 +    }
 +
 +    v9fs_path_write_lock(s);
 +    err = v9fs_complete_renameat(pdu, olddirfid,
 +                                 &old_name, newdirfid, &new_name);
 +    v9fs_path_unlock(s);
 +    if (!err) {
 +        err = offset;
 +    }
 +
 +out_err:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&old_name);
 +    v9fs_string_free(&new_name);
 +}
 +
 +static void v9fs_wstat(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    int err = 0;
 +    int16_t unused;
 +    V9fsStat v9stat;
 +    size_t offset = 7;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_stat_init(&v9stat);
 +    err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_wstat(pdu->tag, pdu->id, fid,
 +                     v9stat.mode, v9stat.atime, v9stat.mtime);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    /* do we need to sync the file? */
 +    if (donttouch_stat(&v9stat)) {
 +        err = v9fs_co_fsync(pdu, fidp, 0);
 +        goto out;
 +    }
 +    if (v9stat.mode != -1) {
 +        uint32_t v9_mode;
 +        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
 +        if (err < 0) {
 +            goto out;
 +        }
 +        v9_mode = stat_to_v9mode(&stbuf);
 +        if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
 +            (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
 +            /* Attempting to change the type */
 +            err = -EIO;
 +            goto out;
 +        }
 +#ifndef CONFIG_WIN32
 +        err = v9fs_co_chmod(pdu, &fidp->path,
 +                            v9mode_to_mode(v9stat.mode,
 +                                           &v9stat.extension));
 +#else
 +        err = -EPERM;
 +#endif
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    if (v9stat.mtime != -1 || v9stat.atime != -1) {
 +        struct timespec times[2];
 +        if (v9stat.atime != -1) {
 +            times[0].tv_sec = v9stat.atime;
 +            times[0].tv_nsec = 0;
 +        } else {
 +            times[0].tv_nsec = UTIME_OMIT;
 +        }
 +        if (v9stat.mtime != -1) {
 +            times[1].tv_sec = v9stat.mtime;
 +            times[1].tv_nsec = 0;
 +        } else {
 +            times[1].tv_nsec = UTIME_OMIT;
 +        }
 +        err = v9fs_co_utimensat(pdu, &fidp->path, times);
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
 +#ifndef CONFIG_WIN32
 +        err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
 +#else
 +        err = -EPERM;
 +#endif
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    if (v9stat.name.size != 0) {
 +        err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    if (v9stat.length != -1) {
 +        err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
 +        if (err < 0) {
 +            goto out;
 +        }
 +    }
 +    err = offset;
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    v9fs_stat_free(&v9stat);
 +    pdu_complete(pdu, err);
 +}
 +
 +static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
 +{
 +    uint32_t f_type;
 +    uint32_t f_bsize;
 +    uint64_t f_blocks;
 +    uint64_t f_bfree;
 +    uint64_t f_bavail;
 +    uint64_t f_files;
 +    uint64_t f_ffree;
 +    uint64_t fsid_val;
 +    uint32_t f_namelen;
 +    size_t offset = 7;
 +    int32_t bsize_factor;
 +
 +    /*
 +     * compute bsize factor based on host file system block size
 +     * and client msize
 +     */
 +    bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
 +    if (!bsize_factor) {
 +        bsize_factor = 1;
 +    }
 +    f_type  = stbuf->f_type;
 +    f_bsize = stbuf->f_bsize;
 +    f_bsize *= bsize_factor;
 +    /*
 +     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
 +     * adjust(divide) the number of blocks, free blocks and available
 +     * blocks by bsize factor
 +     */
 +    f_blocks = stbuf->f_blocks/bsize_factor;
 +    f_bfree  = stbuf->f_bfree/bsize_factor;
 +    f_bavail = stbuf->f_bavail/bsize_factor;
 +    f_files  = stbuf->f_files;
 +    f_ffree  = stbuf->f_ffree;
 +#ifdef CONFIG_LINUX
 +    fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
 +               (unsigned long long)stbuf->f_fsid.__val[1] << 32;
 +    f_namelen = stbuf->f_namelen;
 +#else
 +    fsid_val = (unsigned int) stbuf->f_fsid.val[0] |
 +               (unsigned long long)stbuf->f_fsid.val[1] << 32;
 +    f_namelen = 255;
 +#endif
 +
 +    return pdu_marshal(pdu, offset, "ddqqqqqqd",
 +                       f_type, f_bsize, f_blocks, f_bfree,
 +                       f_bavail, f_files, f_ffree,
 +                       fsid_val, f_namelen);
 +}
 +
 +static void v9fs_statfs(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int32_t fid;
 +    ssize_t retval = 0;
 +    size_t offset = 7;
 +    V9fsFidState *fidp;
 +    struct statfs stbuf;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    retval = pdu_unmarshal(pdu, offset, "d", &fid);
 +    if (retval < 0) {
 +        goto out_nofid;
 +    }
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        retval = -ENOENT;
 +        goto out_nofid;
 +    }
 +    retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
 +    if (retval < 0) {
 +        goto out;
 +    }
 +    retval = v9fs_fill_statfs(s, pdu, &stbuf);
 +    if (retval < 0) {
 +        goto out;
 +    }
 +    retval += offset;
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, retval);
 +}
 +
 +static void v9fs_mknod(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +
 +    int mode;
 +    gid_t gid;
 +    int32_t fid;
 +    V9fsQID qid;
 +    int err = 0;
 +    int major, minor;
 +    size_t offset = 7;
 +    V9fsString name;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
 +                        &major, &minor, &gid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +#ifndef CONFIG_WIN32
 +    err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
 +                        makedev(major, minor), mode, &stbuf);
 +#else
 +    err = -EPERM;
 +#endif
 +    if (err < 0) {
 +        goto out;
 +    }
 +    stat_to_qid(&stbuf, &qid);
 +    err = pdu_marshal(pdu, offset, "Q", &qid);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_mknod_return(pdu->tag, pdu->id,
 +                            qid.type, qid.version, qid.path);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +
 +/*
 + * Implement posix byte range locking code
 + * Server side handling of locking code is very simple, because 9p server in
 + * QEMU can handle only one client. And most of the lock handling
 + * (like conflict, merging) etc is done by the VFS layer itself, so no need to
 + * do any thing in * qemu 9p server side lock code path.
 + * So when a TLOCK request comes, always return success
 + */
 +static void v9fs_lock(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    int8_t status;
 +    V9fsFlock flock;
 +    size_t offset = 7;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    int32_t fid, err = 0;
 +    V9fsPDU *pdu = opaque;
 +
 +    status = P9_LOCK_ERROR;
 +    v9fs_string_init(&flock.client_id);
 +    err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
 +                        &flock.flags, &flock.start, &flock.length,
 +                        &flock.proc_id, &flock.client_id);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_lock(pdu->tag, pdu->id, fid,
 +                    flock.type, flock.start, flock.length);
 +
 +
 +    /* We support only block flag now (that too ignored currently) */
 +    if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    err = v9fs_co_fstat(pdu, fidp, &stbuf);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    status = P9_LOCK_SUCCESS;
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    err = pdu_marshal(pdu, offset, "b", status);
 +    if (err > 0) {
 +        err += offset;
 +    }
 +    trace_v9fs_lock_return(pdu->tag, pdu->id, status);
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&flock.client_id);
 +}
 +
 +/*
 + * When a TGETLOCK request comes, always return success because all lock
 + * handling is done by client's VFS layer.
 + */
 +static void v9fs_getlock(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    size_t offset = 7;
 +    struct stat stbuf;
 +    V9fsFidState *fidp;
 +    V9fsGetlock glock;
 +    int32_t fid, err = 0;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_string_init(&glock.client_id);
 +    err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
 +                        &glock.start, &glock.length, &glock.proc_id,
 +                        &glock.client_id);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_getlock(pdu->tag, pdu->id, fid,
 +                       glock.type, glock.start, glock.length);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    err = v9fs_co_fstat(pdu, fidp, &stbuf);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    glock.type = P9_LOCK_TYPE_UNLCK;
 +    err = pdu_marshal(pdu, offset, "bqqds", glock.type,
 +                          glock.start, glock.length, glock.proc_id,
 +                          &glock.client_id);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
 +                              glock.length, glock.proc_id);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&glock.client_id);
 +}
 +
 +static void v9fs_mkdir(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    size_t offset = 7;
 +    int32_t fid;
 +    struct stat stbuf;
 +    V9fsQID qid;
 +    V9fsString name;
 +    V9fsFidState *fidp;
 +    gid_t gid;
 +    int mode;
 +    int err = 0;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
 +
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    stat_to_qid(&stbuf, &qid);
 +    err = pdu_marshal(pdu, offset, "Q", &qid);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
 +                            qid.type, qid.version, qid.path, err);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +
 +#ifndef CONFIG_WIN32
 +static void v9fs_xattrwalk(void *opaque)
 +{
 +    int64_t size;
 +    V9fsString name;
 +    ssize_t err = 0;
 +    size_t offset = 7;
 +    int32_t fid, newfid;
 +    V9fsFidState *file_fidp;
 +    V9fsFidState *xattr_fidp = NULL;
 +    V9fsPDU *pdu = opaque;
 +    V9fsState *s = pdu->s;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
 +
 +    file_fidp = get_fid(pdu, fid);
 +    if (file_fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +    xattr_fidp = alloc_fid(s, newfid);
 +    if (xattr_fidp == NULL) {
 +        err = -EINVAL;
 +        goto out;
 +    }
 +    v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
 +    if (name.data == NULL) {
 +        /*
 +         * listxattr request. Get the size first
 +         */
 +        size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
 +        if (size < 0) {
 +            err = size;
 +            clunk_fid(s, xattr_fidp->fid);
 +            goto out;
 +        }
 +        /*
 +         * Read the xattr value
 +         */
 +        xattr_fidp->fs.xattr.len = size;
 +        xattr_fidp->fid_type = P9_FID_XATTR;
 +        xattr_fidp->fs.xattr.copied_len = -1;
 +        if (size) {
 +            xattr_fidp->fs.xattr.value = g_malloc(size);
 +            err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
 +                                     xattr_fidp->fs.xattr.value,
 +                                     xattr_fidp->fs.xattr.len);
 +            if (err < 0) {
 +                clunk_fid(s, xattr_fidp->fid);
 +                goto out;
 +            }
 +        }
 +        err = pdu_marshal(pdu, offset, "q", size);
 +        if (err < 0) {
 +            goto out;
 +        }
 +        err += offset;
 +    } else {
 +        /*
 +         * specific xattr fid. We check for xattr
 +         * presence also collect the xattr size
 +         */
 +        size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
 +                                 &name, NULL, 0);
 +        if (size < 0) {
 +            err = size;
 +            clunk_fid(s, xattr_fidp->fid);
 +            goto out;
 +        }
 +        /*
 +         * Read the xattr value
 +         */
 +        xattr_fidp->fs.xattr.len = size;
 +        xattr_fidp->fid_type = P9_FID_XATTR;
 +        xattr_fidp->fs.xattr.copied_len = -1;
 +        if (size) {
 +            xattr_fidp->fs.xattr.value = g_malloc(size);
 +            err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
 +                                    &name, xattr_fidp->fs.xattr.value,
 +                                    xattr_fidp->fs.xattr.len);
 +            if (err < 0) {
 +                clunk_fid(s, xattr_fidp->fid);
 +                goto out;
 +            }
 +        }
 +        err = pdu_marshal(pdu, offset, "q", size);
 +        if (err < 0) {
 +            goto out;
 +        }
 +        err += offset;
 +    }
 +    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
 +out:
 +    put_fid(pdu, file_fidp);
 +    if (xattr_fidp) {
 +        put_fid(pdu, xattr_fidp);
 +    }
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +
 +static void v9fs_xattrcreate(void *opaque)
 +{
 +    int flags;
 +    int32_t fid;
 +    int64_t size;
 +    ssize_t err = 0;
 +    V9fsString name;
 +    size_t offset = 7;
 +    V9fsFidState *file_fidp;
 +    V9fsFidState *xattr_fidp;
 +    V9fsPDU *pdu = opaque;
 +
 +    v9fs_string_init(&name);
 +    err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
 +
 +    file_fidp = get_fid(pdu, fid);
 +    if (file_fidp == NULL) {
 +        err = -EINVAL;
 +        goto out_nofid;
 +    }
 +    /* Make the file fid point to xattr */
 +    xattr_fidp = file_fidp;
 +    xattr_fidp->fid_type = P9_FID_XATTR;
 +    xattr_fidp->fs.xattr.copied_len = 0;
 +    xattr_fidp->fs.xattr.len = size;
 +    xattr_fidp->fs.xattr.flags = flags;
 +    v9fs_string_init(&xattr_fidp->fs.xattr.name);
 +    v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
 +    xattr_fidp->fs.xattr.value = g_malloc(size);
 +    err = offset;
 +    put_fid(pdu, file_fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +    v9fs_string_free(&name);
 +}
 +#endif
 +
 +static void v9fs_readlink(void *opaque)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    size_t offset = 7;
 +    V9fsString target;
 +    int32_t fid;
 +    int err = 0;
 +    V9fsFidState *fidp;
 +
 +    err = pdu_unmarshal(pdu, offset, "d", &fid);
 +    if (err < 0) {
 +        goto out_nofid;
 +    }
 +    trace_v9fs_readlink(pdu->tag, pdu->id, fid);
 +    fidp = get_fid(pdu, fid);
 +    if (fidp == NULL) {
 +        err = -ENOENT;
 +        goto out_nofid;
 +    }
 +
 +    v9fs_string_init(&target);
 +    err = v9fs_co_readlink(pdu, &fidp->path, &target);
 +    if (err < 0) {
 +        goto out;
 +    }
 +    err = pdu_marshal(pdu, offset, "s", &target);
 +    if (err < 0) {
 +        v9fs_string_free(&target);
 +        goto out;
 +    }
 +    err += offset;
 +    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
 +    v9fs_string_free(&target);
 +out:
 +    put_fid(pdu, fidp);
 +out_nofid:
 +    pdu_complete(pdu, err);
 +}
 +
 +static CoroutineEntry *pdu_co_handlers[] = {
 +    [P9_TREADDIR] = v9fs_readdir,
 +    [P9_TSTATFS] = v9fs_statfs,
 +    [P9_TGETATTR] = v9fs_getattr,
 +    [P9_TSETATTR] = v9fs_setattr,
 +#ifndef CONFIG_WIN32
 +    [P9_TXATTRWALK] = v9fs_xattrwalk,
 +    [P9_TXATTRCREATE] = v9fs_xattrcreate,
 +#endif
 +    [P9_TMKNOD] = v9fs_mknod,
 +    [P9_TRENAME] = v9fs_rename,
 +    [P9_TLOCK] = v9fs_lock,
 +    [P9_TGETLOCK] = v9fs_getlock,
 +    [P9_TRENAMEAT] = v9fs_renameat,
 +    [P9_TREADLINK] = v9fs_readlink,
 +    [P9_TUNLINKAT] = v9fs_unlinkat,
 +    [P9_TMKDIR] = v9fs_mkdir,
 +    [P9_TVERSION] = v9fs_version,
 +    [P9_TLOPEN] = v9fs_open,
 +    [P9_TATTACH] = v9fs_attach,
 +    [P9_TSTAT] = v9fs_stat,
 +    [P9_TWALK] = v9fs_walk,
 +    [P9_TCLUNK] = v9fs_clunk,
 +    [P9_TFSYNC] = v9fs_fsync,
 +    [P9_TOPEN] = v9fs_open,
 +    [P9_TREAD] = v9fs_read,
 +#if 0
 +    [P9_TAUTH] = v9fs_auth,
 +#endif
 +    [P9_TFLUSH] = v9fs_flush,
 +    [P9_TLINK] = v9fs_link,
 +    [P9_TSYMLINK] = v9fs_symlink,
 +    [P9_TCREATE] = v9fs_create,
 +    [P9_TLCREATE] = v9fs_lcreate,
 +    [P9_TWRITE] = v9fs_write,
 +    [P9_TWSTAT] = v9fs_wstat,
 +    [P9_TREMOVE] = v9fs_remove,
 +};
 +
 +static void v9fs_op_not_supp(void *opaque)
 +{
 +    WARN("[%d][%s] >> This operation is not supported.\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    pdu_complete(pdu, -EOPNOTSUPP);
 +}
 +
 +static void v9fs_fs_ro(void *opaque)
 +{
 +    WARN("[%d][%s] >> This is the read-only operation.\n", __LINE__, __func__);
 +    V9fsPDU *pdu = opaque;
 +    pdu_complete(pdu, -EROFS);
 +}
 +
 +static inline bool is_read_only_op(V9fsPDU *pdu)
 +{
 +    switch (pdu->id) {
 +    case P9_TREADDIR:
 +    case P9_TSTATFS:
 +    case P9_TGETATTR:
 +    case P9_TXATTRWALK:
 +    case P9_TLOCK:
 +    case P9_TGETLOCK:
 +    case P9_TREADLINK:
 +    case P9_TVERSION:
 +    case P9_TLOPEN:
 +    case P9_TATTACH:
 +    case P9_TSTAT:
 +    case P9_TWALK:
 +    case P9_TCLUNK:
 +    case P9_TFSYNC:
 +    case P9_TOPEN:
 +    case P9_TREAD:
 +    case P9_TAUTH:
 +    case P9_TFLUSH:
 +        return 1;
 +    default:
 +        return 0;
 +    }
 +}
 +
 +void pdu_submit(V9fsPDU *pdu)
 +{
 +    Coroutine *co;
 +    CoroutineEntry *handler;
 +    V9fsState *s = pdu->s;
 +
 +    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
 +        (pdu_co_handlers[pdu->id] == NULL)) {
 +        handler = v9fs_op_not_supp;
 +    } else {
 +        handler = pdu_co_handlers[pdu->id];
 +    }
 +
 +    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
 +        handler = v9fs_fs_ro;
 +    }
++    co = qemu_coroutine_create(handler, pdu);
++    qemu_coroutine_enter(co);
 +}
 +
 +/* Returns 0 on success, 1 on failure. */
 +int v9fs_device_realize_common(V9fsState *s, Error **errp)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
 +    int i, len;
 +    struct stat stat;
 +    FsDriverEntry *fse;
 +    V9fsPath path;
 +    int rc = 1;
 +
 +    /* initialize pdu allocator */
 +    QLIST_INIT(&s->free_list);
 +    QLIST_INIT(&s->active_list);
 +    for (i = 0; i < (MAX_REQ - 1); i++) {
 +        QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next);
 +        v->pdus[i].s = s;
 +        v->pdus[i].idx = i;
 +    }
 +
 +    v9fs_path_init(&path);
 +
 +    fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
 +
 +    if (!fse) {
 +        /* We don't have a fsdev identified by fsdev_id */
 +        error_setg(errp, "9pfs device couldn't find fsdev with the "
 +                   "id = %s",
 +                   s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
 +        goto out;
 +    }
 +
 +    if (!s->fsconf.tag) {
 +        /* we haven't specified a mount_tag */
 +        error_setg(errp, "fsdev with id %s needs mount_tag arguments",
 +                   s->fsconf.fsdev_id);
 +        goto out;
 +    }
 +
 +    s->ctx.export_flags = fse->export_flags;
 +    s->ctx.fs_root = g_strdup(fse->path);
 +    s->ctx.exops.get_st_gen = NULL;
 +    len = strlen(s->fsconf.tag);
 +    if (len > MAX_TAG_LEN - 1) {
 +        error_setg(errp, "mount tag '%s' (%d bytes) is longer than "
 +                   "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
 +        goto out;
 +    }
 +
 +    s->tag = g_strdup(s->fsconf.tag);
 +    s->ctx.uid = -1;
 +
 +    s->ops = fse->ops;
 +
 +    s->fid_list = NULL;
 +    qemu_co_rwlock_init(&s->rename_lock);
 +
 +    if (s->ops->init(&s->ctx) < 0) {
 +        error_setg(errp, "9pfs Failed to initialize fs-driver with id:%s"
 +                   " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root);
 +        goto out;
 +    }
 +
 +    /*
 +     * Check details of export path, We need to use fs driver
 +     * call back to do that. Since we are in the init path, we don't
 +     * use co-routines here.
 +     */
 +#ifndef CONFIG_WIN32
 +    if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
 +#else
 +    if (s->ops->name_to_path(&s->ctx, NULL, "\\", &path) < 0) {
 +#endif
 +        error_setg(errp,
 +                   "error in converting name to path %s", strerror(errno));
 +        goto out;
 +    }
 +    if (s->ops->lstat(&s->ctx, &path, &stat)) {
 +        error_setg(errp, "share path %s does not exist", fse->path);
 +        goto out;
 +    } else if (!S_ISDIR(stat.st_mode)) {
 +        error_setg(errp, "share path %s is not a directory", fse->path);
 +        goto out;
 +    }
 +    v9fs_path_free(&path);
 +
 +    rc = 0;
 +out:
 +    if (rc) {
 +        g_free(s->ctx.fs_root);
 +        g_free(s->tag);
 +        v9fs_path_free(&path);
 +    }
 +    return rc;
 +}
 +
 +void v9fs_device_unrealize_common(V9fsState *s, Error **errp)
 +{
 +    TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
 +    g_free(s->ctx.fs_root);
 +    g_free(s->tag);
 +}
 +
 +static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
 +{
 +#ifndef CONFIG_WIN32
 +    struct rlimit rlim;
 +    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
 +        error_report("Failed to get the resource limit");
 +        exit(1);
 +    }
 +    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
 +    open_fd_rc = rlim.rlim_cur/2;
 +#else
 +    open_fd_hw = 3696; // 4096 - 400
 +    open_fd_rc = 2048; // 4096 / 2
 +#endif
 +}
Simple merge
diff --cc hw/9pfs/9p.h
@@@ -3,14 -3,7 +3,11 @@@
  
  #include <dirent.h>
  #include <utime.h>
 +
 +#if !defined(CONFIG_MARU) || !defined(CONFIG_WIN32)
  #include <sys/resource.h>
- #include <glib.h>
- #include "standard-headers/linux/virtio_9p.h"
- #include "hw/virtio/virtio.h"
 +#endif
 +
  #include "fsdev/file-op-9p.h"
  #include "fsdev/9p-iov-marshal.h"
  #include "qemu/thread.h"
Simple merge
diff --cc hw/acpi/ich9.c
Simple merge
diff --cc hw/acpi/piix4.c
  #include "hw/acpi/memory_hotplug.h"
  #include "hw/acpi/acpi_dev_interface.h"
  #include "hw/xen/xen.h"
+ #include "qom/cpu.h"
  
 +#include "sysemu/hax.h"
 +
 +#ifdef CONFIG_MARU
 +#include "tizen/src/hw/maru_pm.h"
 +#endif
 +
  //#define DEBUG
  
  #ifdef DEBUG
Simple merge
diff --cc hw/i386/pc.c
  #include "qapi/visitor.h"
  #include "qapi-visit.h"
  #include "qom/cpu.h"
+ #include "hw/nmi.h"
  
 +#include "sysemu/hax.h"
 +
  /* debug PC/ISA interrupts */
  //#define DEBUG_IRQ
  
Simple merge
Simple merge
Simple merge
diff --cc hw/pci/pci.c
Simple merge
index c6b5acf,0000000..c15a81d
mode 100644,000000..100644
--- /dev/null
@@@ -1,21 -1,0 +1,22 @@@
 +#ifndef _QEMU_DISPLAY_H
 +#define _QEMU_DISPLAY_H
 +
 +#include "qemu/osdep.h"
 +#include "qemu-common.h"
++#include "hw/qdev-core.h"
 +
 +#define TYPE_DISPLAYOBJECT "display"
 +
 +typedef struct {
 +    Object base;
 +    void *dpy;
 +} DisplayObject;
 +
 +#define DISPLAYOBJECT(obj) \
 +   OBJECT_CHECK(DisplayObject, obj, TYPE_DISPLAYOBJECT)
 +
 +DisplayObject *displayobject_create(bool *ambiguous);
 +
 +DisplayObject *displayobject_find(const char *id);
 +
 +#endif
index 7d0919a,0000000..3fd48a8
mode 100644,000000..100644
--- /dev/null
@@@ -1,631 -1,0 +1,633 @@@
-     if (display_type == DT_NONE || display_type == DT_NOGRAPHIC) {
 +/*
 + * vigs
 + *
 + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
 + *
 + * Contact:
 + * Stanislav Vorobiov <s.vorobiov@samsung.com>
 + * Jinhyung Jo <jinhyung.jo@samsung.com>
 + * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#include "vigs_log.h"
 +#include "vigs_onscreen_server.h"
 +#include "vigs_offscreen_server.h"
 +#include "vigs_backend.h"
 +#include "vigs_regs.h"
 +#include "vigs_fenceman.h"
 +#include "vigs_qt5.h"
 +#include "display.h"
 +#include "work_queue.h"
 +#include "winsys.h"
 +#include "hw/hw.h"
 +#include "hw/pci/pci.h"
 +#include "ui/console.h"
 +#include "qemu/main-loop.h"
 +#include "qemu/error-report.h"
 +#include "qapi/error.h"
 +#include "sysemu/sysemu.h"
 +
 +#define PCI_VENDOR_ID_VIGS 0x19B2
 +#define PCI_DEVICE_ID_VIGS 0x1011
 +
 +#define VIGS_IO_SIZE 0x1000
 +
 +#define VIGS_EXTRA_INVALIDATION (9)
 +
++bool nodisplay = false;
++
 +typedef struct VIGSState
 +{
 +    PCIDevice dev;
 +
 +    char *display;
 +    char *render_queue;
 +    char *backend;
 +    char *wsi;
 +    char *gl_version;
 +    MemoryRegion vram_bar;
 +    uint32_t vram_size;
 +
 +    MemoryRegion ram_bar;
 +    uint32_t ram_size;
 +
 +    MemoryRegion io_bar;
 +
 +    struct vigs_fenceman *fenceman;
 +
 +    QEMUBH *fence_ack_bh;
 +
 +    struct vigs_server *server;
 +
 +    /*
 +     * Our console.
 +     */
 +    QemuConsole *con;
 +    int invalidate_cnt;
 +
 +    uint32_t reg_con;
 +    uint32_t reg_int;
 +
 +    // for VBLANK emulation
 +    QEMUTimer *vblank_timer;
 +} VIGSState;
 +
 +#define TYPE_VIGS_DEVICE "vigs"
 +
 +static void vigs_update_irq(VIGSState *s)
 +{
 +    bool raise = false;
 +
 +    if ((s->reg_con & VIGS_REG_CON_VBLANK_ENABLE) &&
 +        (s->reg_int & VIGS_REG_INT_VBLANK_PENDING)) {
 +        raise = true;
 +    }
 +
 +    if (s->reg_int & VIGS_REG_INT_FENCE_ACK_PENDING) {
 +        raise = true;
 +    }
 +
 +    if (raise) {
 +        pci_set_irq(&s->dev, 1);
 +    } else {
 +        pci_set_irq(&s->dev, 0);
 +    }
 +}
 +
 +static void vigs_fence_ack_bh(void *opaque)
 +{
 +    VIGSState *s = opaque;
 +
 +    if (vigs_fenceman_pending(s->fenceman)) {
 +        s->reg_int |= VIGS_REG_INT_FENCE_ACK_PENDING;
 +    }
 +
 +    vigs_update_irq(s);
 +}
 +
 +static void vigs_hw_update(void *opaque)
 +{
 +    VIGSState *s = opaque;
 +    DisplaySurface *ds = qemu_console_surface(s->con);
 +
 +    if (!surface_data(ds)) {
 +        return;
 +    }
 +
 +    if (vigs_server_update_display(s->server, s->invalidate_cnt)) {
 +        /*
 +         * 'vigs_server_update_display' could have updated the surface,
 +         * so fetch it again.
 +         */
 +        ds = qemu_console_surface(s->con);
 +
 +        dpy_gfx_update(s->con, 0, 0, surface_width(ds), surface_height(ds));
 +    }
 +
 +    if (s->invalidate_cnt > 0) {
 +        s->invalidate_cnt--;
 +    }
 +
 +    if (s->reg_con & VIGS_REG_CON_VBLANK_ENABLE) {
 +        s->reg_int |= VIGS_REG_INT_VBLANK_PENDING;
 +        vigs_update_irq(s);
 +    }
 +}
 +
 +static void vigs_hw_display(void *opaque, console_ch_t *text)
 +{
 +    VIGSState *s = opaque;
 +    DisplaySurface *ds = qemu_console_surface(s->con);
 +    bool displayed;
 +
 +    if (!surface_data(ds)) {
 +        return;
 +    }
 +
 +    if (vigs_server_display(s->server, &displayed)) {
 +        /*
 +         * 'vigs_server_display' could have updated the surface,
 +         * so fetch it again.
 +         */
 +        ds = qemu_console_surface(s->con);
 +
 +        dpy_gfx_update(s->con, 0, 0, surface_width(ds), surface_height(ds));
 +    }
 +
 +    *text = displayed;
 +}
 +
 +static void vigs_hw_invalidate(void *opaque)
 +{
 +    VIGSState *s = opaque;
 +
 +    s->invalidate_cnt = 1 + VIGS_EXTRA_INVALIDATION;
 +}
 +
 +static void vigs_dpy_resize(void *user_data,
 +                            uint32_t width,
 +                            uint32_t height)
 +{
 +    VIGSState *s = user_data;
 +    DisplaySurface *ds = qemu_console_surface(s->con);
 +
 +    if ((width != surface_width(ds)) ||
 +        (height != surface_height(ds))) {
 +        qemu_console_resize(s->con, width, height);
 +    }
 +}
 +
 +static uint32_t vigs_dpy_get_stride(void *user_data)
 +{
 +    VIGSState *s = user_data;
 +    DisplaySurface *ds = qemu_console_surface(s->con);
 +
 +    return surface_stride(ds);
 +}
 +
 +static uint32_t vigs_dpy_get_bpp(void *user_data)
 +{
 +    VIGSState *s = user_data;
 +    DisplaySurface *ds = qemu_console_surface(s->con);
 +
 +    return surface_bytes_per_pixel(ds);
 +}
 +
 +static uint8_t *vigs_dpy_get_data(void *user_data)
 +{
 +    VIGSState *s = user_data;
 +    DisplaySurface *ds = qemu_console_surface(s->con);
 +
 +    return surface_data(ds);
 +}
 +
 +static void vigs_fence_ack(void *user_data,
 +                           uint32_t fence_seq)
 +{
 +    VIGSState *s = user_data;
 +
 +    vigs_fenceman_ack(s->fenceman, fence_seq);
 +
 +    qemu_bh_schedule(s->fence_ack_bh);
 +}
 +
 +static uint64_t vigs_io_read(void *opaque, hwaddr offset,
 +                             unsigned size)
 +{
 +    VIGSState *s = opaque;
 +
 +    switch (offset) {
 +    case VIGS_REG_CON:
 +        return s->reg_con;
 +    case VIGS_REG_INT:
 +        return s->reg_int;
 +    case VIGS_REG_FENCE_LOWER:
 +        return vigs_fenceman_get_lower(s->fenceman);
 +    case VIGS_REG_FENCE_UPPER:
 +        return vigs_fenceman_get_upper(s->fenceman);
 +    default:
 +        VIGS_LOG_CRITICAL("Bad register 0x%X read", (uint32_t)offset);
 +        break;
 +    }
 +
 +    return 0;
 +}
 +
 +static void vigs_io_write(void *opaque, hwaddr offset,
 +                          uint64_t value, unsigned size)
 +{
 +    VIGSState *s = opaque;
 +
 +    switch (offset) {
 +    case VIGS_REG_EXEC:
 +        vigs_server_dispatch(s->server, value);
 +        break;
 +    case VIGS_REG_CON:
 +        if (((s->reg_con & VIGS_REG_CON_VBLANK_ENABLE) == 0) &&
 +            (value & VIGS_REG_CON_VBLANK_ENABLE)) {
 +            VIGS_LOG_DEBUG("VBLANK On");
 +        } else if (((value & VIGS_REG_CON_VBLANK_ENABLE) == 0) &&
 +                   (s->reg_con & VIGS_REG_CON_VBLANK_ENABLE)) {
 +            VIGS_LOG_DEBUG("VBLANK Off");
 +        }
 +
 +        s->reg_con = value & VIGS_REG_CON_MASK;
 +
 +        vigs_update_irq(s);
 +        break;
 +    case VIGS_REG_INT:
 +        if (value & VIGS_REG_INT_VBLANK_PENDING) {
 +            value &= ~VIGS_REG_INT_VBLANK_PENDING;
 +        } else {
 +            value |= (s->reg_int & VIGS_REG_INT_VBLANK_PENDING);
 +        }
 +
 +        if (value & VIGS_REG_INT_FENCE_ACK_PENDING) {
 +            value &= ~VIGS_REG_INT_FENCE_ACK_PENDING;
 +        } else {
 +            value |= (s->reg_int & VIGS_REG_INT_FENCE_ACK_PENDING);
 +        }
 +
 +        s->reg_int = value & VIGS_REG_INT_MASK;
 +
 +        vigs_update_irq(s);
 +        break;
 +    default:
 +        VIGS_LOG_CRITICAL("Bad register 0x%X write", (uint32_t)offset);
 +        break;
 +    }
 +}
 +
 +static void vigs_register_capture_request_listener(void *listener,
 +                                                   void (*handler)(void *))
 +{
 +    return vigs_qt5_register_capture_request_listener(listener, handler);
 +}
 +
 +static void vigs_unregister_capture_request_listener(void *listener)
 +{
 +    return vigs_qt5_unregister_capture_request_listener(listener);
 +}
 +
 +static void vigs_process_captured(bool captured, void *pixels,
 +                                  uint32_t width, uint32_t height)
 +{
 +    return vigs_qt5_process_captured(captured, pixels, width, height);
 +}
 +
 +static struct GraphicHwOps vigs_hw_ops =
 +{
 +    .invalidate = vigs_hw_invalidate,
 +    .gfx_update = vigs_hw_update,
 +    /*
 +     * Hack. use 'graphic_hw_text_update' to do displaying, but
 +     * we have no choice, that's the only way to direct-to-window
 +     * rendering from Qt5.
 +     */
 +    .text_update = vigs_hw_display,
 +};
 +
 +static const MemoryRegionOps vigs_io_ops =
 +{
 +    .read = vigs_io_read,
 +    .write = vigs_io_write,
 +    .endianness = DEVICE_NATIVE_ENDIAN,
 +};
 +
 +static struct vigs_display_ops vigs_dpy_ops =
 +{
 +    .resize = vigs_dpy_resize,
 +    .get_stride = vigs_dpy_get_stride,
 +    .get_bpp = vigs_dpy_get_bpp,
 +    .get_data = vigs_dpy_get_data,
 +    .fence_ack = vigs_fence_ack,
 +};
 +
 +static struct vigs_capture_ops capture_ops =
 +{
 +    .register_listener = vigs_register_capture_request_listener,
 +    .unregister_listener = vigs_unregister_capture_request_listener,
 +    .process_captured = vigs_process_captured,
 +};
 +
 +static void vblank_update(void *opaque) {
 +    VIGSState *s = opaque;
 +    uint64_t last_update;
 +
 +    if (s->reg_con & VIGS_REG_CON_VBLANK_ENABLE) {
 +        s->reg_int |= VIGS_REG_INT_VBLANK_PENDING;
 +        vigs_update_irq(s);
 +    }
 +
 +    last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 +    timer_mod(s->vblank_timer, last_update + GUI_REFRESH_INTERVAL_DEFAULT);
 +}
 +
 +static void vigs_vblank_timer_init(VIGSState *s) {
 +        s->vblank_timer = timer_new_ms(QEMU_CLOCK_REALTIME, vblank_update, s);
 +        timer_mod(s->vblank_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
 +}
 +
 +static int vigs_device_init(PCIDevice *dev)
 +{
 +    VIGSState *s = DO_UPCAST(VIGSState, dev, dev);
 +    DisplayObject *dobj = NULL;
 +    WorkQueueObject *wqobj = NULL;
 +    WSIObject *wsiobj = NULL;
 +    struct vigs_backend *backend = NULL;
 +
 +    if (s->display) {
 +        dobj = displayobject_find(s->display);
 +
 +        if (!dobj) {
 +            error_report("display '%s' not found", s->display);
 +            return -1;
 +        }
 +    } else {
 +        bool ambiguous;
 +
 +        dobj = displayobject_create(&ambiguous);
 +
 +        if (ambiguous) {
 +            error_report("ambiguous display, set 'display' property");
 +            return -1;
 +        }
 +
 +        if (!dobj) {
 +            error_report("unable to create display");
 +            return -1;
 +        }
 +    }
 +
 +    if (s->render_queue) {
 +        wqobj = workqueueobject_find(s->render_queue);
 +
 +        if (!wqobj) {
 +            error_report("work queue '%s' not found", s->render_queue);
 +            return -1;
 +        }
 +    } else {
 +        bool ambiguous;
 +
 +        wqobj = workqueueobject_create(&ambiguous);
 +
 +        if (ambiguous) {
 +            error_report("ambiguous work queue, set 'render_queue' property");
 +            return -1;
 +        }
 +
 +        if (!wqobj) {
 +            error_report("unable to create work queue");
 +            return -1;
 +        }
 +    }
 +
 +    if (!s->backend) {
 +        error_report("'backend' property not set");
 +        return -1;
 +    }
 +
 +    if (strcmp(s->backend, "gl") && strcmp(s->backend, "sw")) {
 +        error_report("backend '%s' not found", s->backend);
 +        return -1;
 +    }
 +
 +    if (s->wsi) {
 +        Error *err = NULL;
 +
 +        wsiobj = WSIOBJECT(object_new(TYPE_WSIOBJECT));
 +
 +        object_property_add_child(container_get(object_get_root(), "/objects"),
 +                                  s->wsi, &wsiobj->base, &err);
 +
 +        object_unref(&wsiobj->base);
 +
 +        if (err) {
 +            error_report_err(err);
 +            return -1;
 +        }
 +    }
 +
 +    vigs_log_init();
 +
 +    if (s->vram_size < 16 * 1024 * 1024) {
 +        VIGS_LOG_WARN("\"vram_size\" is too small, defaulting to 16mb");
 +        s->vram_size = 16 * 1024 * 1024;
 +    }
 +
 +    if (s->ram_size < 1 * 1024 * 1024) {
 +        VIGS_LOG_WARN("\"ram_size\" is too small, defaulting to 1mb");
 +        s->ram_size = 1 * 1024 * 1024;
 +    }
 +
 +    pci_config_set_interrupt_pin(dev->config, 1);
 +
 +    memory_region_init_ram(&s->vram_bar, OBJECT(s),
 +                           TYPE_VIGS_DEVICE ".vram",
 +                           s->vram_size, &error_abort);
 +
 +    memory_region_init_ram(&s->ram_bar, OBJECT(s),
 +                           TYPE_VIGS_DEVICE ".ram",
 +                           s->ram_size, &error_abort);
 +
 +    memory_region_init_io(&s->io_bar, OBJECT(s),
 +                          &vigs_io_ops,
 +                          s,
 +                          TYPE_VIGS_DEVICE ".io",
 +                          VIGS_IO_SIZE);
 +
 +    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->vram_bar);
 +    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_bar);
 +    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_bar);
 +
 +    if (!strcmp(s->backend, "gl")) {
 +        backend = vigs_gl_backend_create(dobj->dpy, s->gl_version);
 +    } else if (!strcmp(s->backend, "sw")) {
 +        backend = vigs_sw_backend_create();
 +    }
 +
 +    if (!backend) {
 +        goto fail;
 +    }
 +
 +    s->fenceman = vigs_fenceman_create();
 +
 +    s->fence_ack_bh = qemu_bh_new(vigs_fence_ack_bh, s);
 +
 +    s->con = graphic_console_init(DEVICE(dev), 0, &vigs_hw_ops, s);
 +
 +    if (!s->con) {
 +        goto fail;
 +    }
 +
 +    if (vigs_qt5_onscreen_enabled()) {
 +        s->server = vigs_onscreen_server_create(memory_region_get_ram_ptr(&s->vram_bar),
 +                                                memory_region_get_ram_ptr(&s->ram_bar),
 +                                                &vigs_dpy_ops,
 +                                                &capture_ops,
 +                                                s,
 +                                                backend,
 +                                                wqobj->wq);
 +    } else {
 +        s->server = vigs_offscreen_server_create(memory_region_get_ram_ptr(&s->vram_bar),
 +                                                 memory_region_get_ram_ptr(&s->ram_bar),
 +                                                 &vigs_dpy_ops,
 +                                                 &capture_ops,
 +                                                 s,
 +                                                 backend,
 +                                                 wqobj->wq);
 +    }
 +
 +    if (!s->server) {
 +        goto fail;
 +    }
 +
 +    if (wsiobj) {
 +        wsiobj->wsi = &s->server->wsi;
 +        if (!strcmp(s->backend, "gl")) {
 +            wsiobj->gl_wsi = &s->server->wsi;
 +        }
 +    }
 +
 +    // XXX: VBLANK emulation
++    if (nodisplay) {
 +        VIGS_LOG_INFO("VIGS vblank emulation enabled");
 +        vigs_vblank_timer_init(s);
 +    }
 +
 +    VIGS_LOG_INFO("VIGS initialized");
 +
 +    VIGS_LOG_DEBUG("vram_size = %u", s->vram_size);
 +    VIGS_LOG_DEBUG("ram_size = %u", s->ram_size);
 +
 +    return 0;
 +
 +fail:
 +    if (backend) {
 +        backend->destroy(backend);
 +    }
 +
 +    if (s->fence_ack_bh) {
 +        qemu_bh_delete(s->fence_ack_bh);
 +    }
 +
 +    if (s->fenceman) {
 +        vigs_fenceman_destroy(s->fenceman);
 +    }
 +
 +    vigs_log_cleanup();
 +
 +    return -1;
 +}
 +
 +static void vigs_device_reset(DeviceState *d)
 +{
 +    VIGSState *s = container_of(d, VIGSState, dev.qdev);
 +
 +    vigs_server_reset(s->server);
 +
 +    vigs_fenceman_reset(s->fenceman);
 +
 +    pci_set_irq(&s->dev, 0);
 +
 +    s->reg_con = 0;
 +    s->reg_int = 0;
 +
 +    VIGS_LOG_INFO("VIGS reset");
 +}
 +
 +static void vigs_device_exit(PCIDevice *dev)
 +{
 +    VIGSState *s = DO_UPCAST(VIGSState, dev, dev);
 +
 +    s->server->destroy(s->server);
 +
 +    qemu_bh_delete(s->fence_ack_bh);
 +
 +    vigs_fenceman_destroy(s->fenceman);
 +
 +    VIGS_LOG_INFO("VIGS deinitialized");
 +
 +    vigs_log_cleanup();
 +}
 +
 +static Property vigs_properties[] = {
 +    DEFINE_PROP_STRING("display", VIGSState, display),
 +    DEFINE_PROP_STRING("render_queue", VIGSState, render_queue),
 +    DEFINE_PROP_STRING("backend", VIGSState, backend),
 +    DEFINE_PROP_STRING("wsi", VIGSState, wsi),
 +    DEFINE_PROP_STRING("gl_version", VIGSState, gl_version),
 +    DEFINE_PROP_UINT32("vram_size", VIGSState, vram_size,
 +                       32 * 1024 * 1024),
 +    DEFINE_PROP_UINT32("ram_size", VIGSState, ram_size,
 +                       1 * 1024 * 1024),
 +    DEFINE_PROP_END_OF_LIST(),
 +};
 +
 +static void vigs_class_init(ObjectClass *klass, void *data)
 +{
 +    DeviceClass *dc = DEVICE_CLASS(klass);
 +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 +
 +    k->init = vigs_device_init;
 +    k->exit = vigs_device_exit;
 +    k->vendor_id = PCI_VENDOR_ID_VIGS;
 +    k->device_id = PCI_DEVICE_ID_VIGS;
 +    k->class_id = PCI_CLASS_DISPLAY_VGA;
 +    dc->reset = vigs_device_reset;
 +    dc->props = vigs_properties;
 +    dc->desc = "VIGS device";
 +}
 +
 +static TypeInfo vigs_device_info =
 +{
 +    .name          = TYPE_VIGS_DEVICE,
 +    .parent        = TYPE_PCI_DEVICE,
 +    .instance_size = sizeof(VIGSState),
 +    .class_init    = vigs_class_init,
 +};
 +
 +static void vigs_register_types(void)
 +{
 +    type_register_static(&vigs_device_info);
 +}
 +
 +type_init(vigs_register_types)
index 9f9f8ab,0000000..d52e5b8
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,39 @@@
 +/*
 + * vigs
 + *
 + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
 + *
 + * Contact:
 + * Stanislav Vorobiov <s.vorobiov@samsung.com>
 + * Jinhyung Jo <jinhyung.jo@samsung.com>
 + * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#ifndef _QEMU_VIGS_TYPES_H
 +#define _QEMU_VIGS_TYPES_H
 +
 +#include "qemu/osdep.h"
 +#include "qemu-common.h"
++#include "qemu/thread.h"
++#include "hw/qdev-core.h"
 +#include "vigs_protocol.h"
 +
 +#endif
index 71fedb0,0000000..bc891e1
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,59 @@@
 +#ifndef _QEMU_WINSYS_H
 +#define _QEMU_WINSYS_H
 +
 +#include "qemu/osdep.h"
 +#include "qemu-common.h"
++#include "hw/qdev-core.h"
 +
 +typedef uint32_t winsys_id;
 +
 +struct winsys_surface
 +{
 +    uint32_t width;
 +    uint32_t height;
 +
 +    void (*acquire)(struct winsys_surface */*sfc*/);
 +    void (*release)(struct winsys_surface */*sfc*/);
 +
 +    void (*set_dirty)(struct winsys_surface */*sfc*/);
 +
 +    void (*draw_pixels)(struct winsys_surface */*sfc*/, uint8_t */*pixels*/);
 +
 +    void (*draw_pixels_scaled)(struct winsys_surface */*sfc*/,
 +                               uint8_t */*pixels*/,
 +                               uint32_t /*width*/,
 +                               uint32_t /*height*/);
 +};
 +
 +struct winsys_info
 +{
 +};
 +
 +struct winsys_interface
 +{
 +    struct winsys_info *ws_info;
 +
 +    /*
 +     * Acquires surface corresponding to winsys id. NULL if no such surface.
 +     */
 +    struct winsys_surface *(*acquire_surface)(struct winsys_interface */*wsi*/,
 +                                              winsys_id /*id*/);
 +
 +    void (*fence_ack)(struct winsys_interface */*wsi*/,
 +                      uint32_t /*fence_seq*/);
 +};
 +
 +#define TYPE_WSIOBJECT "wsi"
 +
 +typedef struct {
 +    Object base;
 +    struct winsys_interface *wsi;
 +    struct winsys_interface *gl_wsi;
 +} WSIObject;
 +
 +#define WSIOBJECT(obj) \
 +   OBJECT_CHECK(WSIObject, obj, TYPE_WSIOBJECT)
 +
 +WSIObject *wsiobject_find(const char *id);
 +
 +#endif
index 0a7592b,0000000..403d483
mode 100644,000000..100644
--- /dev/null
@@@ -1,61 -1,0 +1,62 @@@
 +#ifndef _QEMU_WORK_QUEUE_H
 +#define _QEMU_WORK_QUEUE_H
 +
 +#include "qemu/osdep.h"
 +#include "qemu-common.h"
 +#include "qemu/queue.h"
 +#include "qemu/thread.h"
 +#include "qapi/error.h"
++#include "hw/qdev-core.h"
 +
 +struct work_queue_item;
 +
 +typedef void (*work_queue_func)(struct work_queue_item */*wq_item*/);
 +
 +struct work_queue_item
 +{
 +    QTAILQ_ENTRY(work_queue_item) entry;
 +
 +    work_queue_func func;
 +};
 +
 +struct work_queue
 +{
 +    QemuThread thread;
 +    QemuMutex mutex;
 +    QemuCond add_cond;
 +    QemuCond wait_cond;
 +
 +    QTAILQ_HEAD(, work_queue_item) items;
 +
 +    int num_items;
 +
 +    bool destroying;
 +};
 +
 +void work_queue_item_init(struct work_queue_item *wq_item,
 +                          work_queue_func func);
 +
 +struct work_queue *work_queue_create(const char *name);
 +
 +void work_queue_add_item(struct work_queue *wq,
 +                         struct work_queue_item *wq_item);
 +
 +void work_queue_wait(struct work_queue *wq);
 +
 +void work_queue_destroy(struct work_queue *wq);
 +
 +#define TYPE_WORKQUEUEOBJECT "work_queue"
 +
 +typedef struct {
 +    Object base;
 +    struct work_queue *wq;
 +} WorkQueueObject;
 +
 +#define WORKQUEUEOBJECT(obj) \
 +   OBJECT_CHECK(WorkQueueObject, obj, TYPE_WORKQUEUEOBJECT)
 +
 +WorkQueueObject *workqueueobject_create(bool *ambiguous);
 +
 +WorkQueueObject *workqueueobject_find(const char *id);
 +
 +#endif
index 0ff6400,0000000..f7a76f8
mode 100644,000000..100644
--- /dev/null
@@@ -1,79 -1,0 +1,80 @@@
 +/*
 + * yagl
 + *
 + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
 + *
 + * Contact:
 + * Stanislav Vorobiov <s.vorobiov@samsung.com>
 + * Jinhyung Jo <jinhyung.jo@samsung.com>
 + * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#ifndef _QEMU_YAGL_TYPES_H
 +#define _QEMU_YAGL_TYPES_H
 +
 +#include "qemu/osdep.h"
 +#include "qemu-common.h"
++#include "cpu.h"
 +
 +typedef uint32_t yagl_pid;
 +typedef uint32_t yagl_tid;
 +typedef uint32_t yagl_func_id;
 +typedef uint32_t yagl_host_handle;
 +typedef uint32_t yagl_object_name;
 +typedef uint32_t yagl_winsys_id;
 +
 +struct yagl_transport;
 +
 +/*
 + * YaGL supported render types.
 + */
 +typedef enum
 +{
 +    yagl_render_type_offscreen = 1,
 +    yagl_render_type_onscreen = 2,
 +} yagl_render_type;
 +
 +/*
 + * YaGL supported API ids.
 + */
 +typedef enum
 +{
 +    yagl_api_id_egl = 1,
 +    yagl_api_id_gles = 2
 +} yagl_api_id;
 +
 +#define YAGL_NUM_APIS 2
 +
 +typedef enum
 +{
 +    /* OpenGL 2.1 or OpenGL >= 3.1 compatibility. */
 +    yagl_gl_2 = 0,
 +    /* OpenGL >= 3.1 core. */
 +    yagl_gl_3_1 = 1,
 +    /* OpenGL >= 3.1 core, GL_ARB_ES3_compatibility support. */
 +    yagl_gl_3_1_es3 = 2,
 +    /* OpenGL >= 3.2 core, no GL_ARB_ES3_compatibility support. */
 +    yagl_gl_3_2 = 3
 +} yagl_gl_version;
 +
 +typedef void (*yagl_api_func)(struct yagl_transport */*t*/);
 +
 +#endif
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc main-loop.c
Simple merge
diff --cc net/net.c
+++ b/net/net.c
@@@ -1391,31 -1428,6 +1428,31 @@@ static void net_vm_change_state_handler
      }
  }
  
-                                           NET_CLIENT_OPTIONS_KIND__MAX,
 +#if defined(CONFIG_MARU)
 +LinkInfo *qmp_get_link(const char *name, Error **errp)
 +{
 +    NetClientState *ncs[MAX_QUEUE_NUM];
 +    int queues, i;
 +    LinkInfo *info;
 +    info = g_malloc0(sizeof (struct LinkInfo));
 +
 +    queues = qemu_find_net_clients_except(name, ncs,
++                                          NET_CLIENT_DRIVER__MAX,
 +                                          MAX_QUEUE_NUM);
 +
 +    if (queues == 0) {
 +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 +                    "Device '%s' not found", name);
 +        return info;
 +    }
 +
 +    for (i = 0; i < queues; i++) {
 +        info->is_up = !(ncs[i]->link_down);
 +    }
 +    return info;
 +}
 +#endif
 +
  void net_cleanup(void)
  {
      NetClientState *nc;
diff --cc net/slirp.c
Simple merge
diff --cc net/tap-win32.c
Simple merge
diff --cc net/tap.c
+++ b/net/tap.c
@@@ -791,10 -748,11 +810,10 @@@ int net_init_tap(const Netdev *netdev, 
      const char *vhostfdname;
      char ifname[128];
  
-     assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-     tap = opts->u.tap.data;
+     assert(netdev->type == NET_CLIENT_DRIVER_TAP);
+     tap = &netdev->u.tap;
      queues = tap->has_queues ? tap->queues : 1;
      vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
 -
      /* QEMU vlans does not support multiqueue tap, in this case peer is set.
       * For -netdev, peer is always NULL. */
      if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
Simple merge
diff --cc qemu-char.c
Simple merge
diff --cc qemu-options.hx
@@@ -3687,43 -3684,11 +3719,18 @@@ DEF("trace", HAS_ARG, QEMU_OPTION_trace
  STEXI
  HXCOMM This line is not accurate, as some sub-options are backend-specific but
  HXCOMM HX does not support conditional compilation of text.
- @item -trace [events=@var{file}][,file=@var{file}]
+ @item -trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
  @findex -trace
- Specify tracing options.
- @table @option
- @item [enable=]@var{pattern}
- Immediately enable events matching @var{pattern}.
- The file must contain one event name (as listed in the @file{trace-events} file)
- per line; globbing patterns are accepted too.  This option is only
- available if QEMU has been compiled with the @var{simple}, @var{stderr}
- or @var{ftrace} tracing backend.  To specify multiple events or patterns,
- specify the @option{-trace} option multiple times.
- Use @code{-trace help} to print a list of names of trace points.
- @item events=@var{file}
- Immediately enable events listed in @var{file}.
- The file must contain one event name (as listed in the @file{trace-events} file)
- per line; globbing patterns are accepted too.  This option is only
- available if QEMU has been compiled with the @var{simple}, @var{stderr} or
- @var{ftrace} tracing backend.
- @item file=@var{file}
- Log output traces to @var{file}.
- This option is only available if QEMU has been compiled with
- the @var{simple} tracing backend.
- @end table
+ @include qemu-option-trace.texi
  ETEXI
  
 +DEF("enable-suspend", 0, QEMU_OPTION_enable_suspend, "", QEMU_ARCH_ALL)
 +STEXI
 +@item -enable-suspend
 +@findex -enable-suspend
 +Enable suspend power state. Default is disable.
 +ETEXI
 +
  HXCOMM Internal use
  DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL)
  DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL)
diff --cc qmp-commands.hx
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc tcg/tcg.c
Simple merge
index c6a86b3,0000000..614cc62
mode 100644,000000..100644
--- /dev/null
@@@ -1,403 -1,0 +1,404 @@@
 +/*
 + * Emulator Control Server - HDS
 + *
 + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
 + *
 + * Contact:
 + *  Chulho Song     <ch81.song@samsung.com>
 + *  Jinhyung Choi   <jinh0.choi@samsung.com>
 + *  Sangho Park     <sangho.p@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#include <string.h>
 +
 +#include "qemu/osdep.h"
 +#include "qemu-common.h"
++#include "qemu/thread.h"
 +#include "fsdev/qemu-fsdev.h"
 +
 +#include "emul_state.h"
 +#include "ecs_hds.h"
 +#include "util/hds.h"
 +#include "util/device_hotplug.h"
 +#include "debug_ch.h"
 +
 +MULTI_DEBUG_CHANNEL(qemu, hds);
 +
 +/* send # of available PCI slot */
 +static void ecs_hds_send_available_pci(char *cmd)
 +{
 +    int n_possible;
 +    int n_hidden;
 +    int n_available = 0;
 +    char slot_data[OUT_BUF_SIZE];
 +
 +    n_possible = hds_get_pci_available_slot_num();
 +    if (n_possible > 0) {
 +        n_hidden = hds_get_num_hidden_conn();
 +
 +        if (n_hidden > ECS_HDS_HIDDEN_RESERVED) {
 +            n_hidden = 0;
 +        } else {
 +            n_hidden = ECS_HDS_HIDDEN_RESERVED - n_hidden;
 +        }
 +
 +        n_available = n_possible - n_hidden;
 +        if (n_available < 0) {
 +            n_available = 0;
 +        }
 +    }
 +
 +    snprintf(slot_data, sizeof(slot_data), "%d", n_available);
 +    make_send_device_ntf(cmd, ECS_HDS_MSG_GROUP, ECS_HDS_ACTION_PCI, slot_data);
 +}
 +
 +static bool check_pci_slot(enum hds_level level)
 +{
 +    int n_possible;
 +    int n_hidden;
 +
 +    n_possible = hds_get_pci_available_slot_num();
 +    if (n_possible <= 0) {
 +        return false;
 +    }
 +
 +    g_assert(n_possible > 0);
 +
 +    if (level == hds_level_hidden) {
 +        return true;
 +    }
 +
 +    n_hidden = hds_get_num_hidden_conn();
 +
 +    if (n_hidden < ECS_HDS_HIDDEN_RESERVED) {
 +        n_hidden = ECS_HDS_HIDDEN_RESERVED - n_hidden;
 +
 +        n_possible = n_possible - n_hidden;
 +        if (n_possible <= 0) {
 +            return false;
 +        }
 +    }
 +
 +    return true;
 +}
 +
 +static void ecs_hds_do_status(char *cmd, type_group group)
 +{
 +    char *data = get_hds_lists();
 +    LOG_INFO("hds status: %s\n", data);
 +    make_send_device_ntf(cmd, group, ECS_HDS_ACTION_STATE, data);
 +
 +    ecs_hds_send_available_pci(cmd);
 +}
 +
 +static void ecs_hds_do_mount(char *cmd, type_group group, char *data)
 +{
 +    char token[] = "\n";
 +    char *host;
 +    char *level_token;
 +    char *hds_id;
 +    char *guest;
 +    int level = 0;
 +
 +    if (data == NULL) {
 +        LOG_WARNING("ecs_hds_do_mount data is empty.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_FAIL, NULL);
 +        return;
 +    }
 +
 +    host = strtok(data, token);
 +    if (host == NULL) {
 +        LOG_WARNING("ecs_hds_do_mount host token is empty.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_FAIL, NULL);
 +        return;
 +    } else if (hds_is_host_path_used((const char *)host)) {
 +        LOG_WARNING("host path '%s' is already taken.\n", host);
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_DUP_HOST_PATH, NULL);
 +        return;
 +    }
 +
 +    guest = strtok(NULL, token);
 +    if (guest == NULL) {
 +        LOG_WARNING("ecs_hds_do_mount guest token is empty.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_FAIL, NULL);
 +        return;
 +    } else if (hds_is_guest_path_used((const char *)guest)) {
 +        LOG_WARNING("guest path '%s' is already taken.\n", guest);
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_DUP_GUEST_PATH, NULL);
 +        return;
 +    }
 +
 +    level_token = strtok(NULL, token);
 +    if (level_token != NULL) {
 +        level = atoi(level_token);
 +    }
 +
 +    /* check available PCI slot num */
 +    if (!check_pci_slot(level)) {
 +        LOG_WARNING("No available pci slot.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_NO_SPACE, NULL);
 +        return;
 +    }
 +
 +    hds_id = new_hds_list(host, guest, level);
 +    if (hds_id != NULL) {
 +        LOG_INFO("do attach tag: %s, host: %s, guest: %s, level: %d\n", hds_id, host, guest, level);
 +        do_hotplug(ATTACH_HDS, hds_id, strlen(hds_id) + 1);
 +    } else {
 +        LOG_WARNING("ecs_hds_do_mount hds_id is empty.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_MOUNT_FAIL, NULL);
 +    }
 +}
 +
 +static void ecs_hds_do_umount(char *cmd, type_group group, type_action action, char *data)
 +{
 +    int level = 0;
 +    int len = 0;
 +    enum hds_level tag_level = 0;
 +    char token[] = "\n";
 +    char *tag;
 +    char *level_token;
 +    char *guest_path;
 +    char emuld_data[OUT_BUF_SIZE];
 +
 +    if (data == NULL) {
 +        LOG_WARNING("ecs_hds_do_umount data is empty.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_UMOUNT_FAIL, NULL);
 +        return;
 +    }
 +
 +    tag = strtok(data, token);
 +    if (tag == NULL) {
 +        LOG_WARNING("ecs_hds_do_umount tag token is empty.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_UMOUNT_FAIL, NULL);
 +        return;
 +    }
 +
 +    level_token = strtok(NULL, token);
 +    if (level_token != NULL) {
 +        level = atoi(level_token);
 +    }
 +
 +    LOG_INFO("try detach with is_hds_attached : %s, %d, level: %d\n",
 +            tag, is_hds_attached(tag), level);
 +
 +    if (!is_hds_attached(tag)) {
 +        LOG_WARNING("hds is not attached. do not try detach it.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_UMOUNT_FAIL, NULL);
 +        return;
 +    }
 +
 +    guest_path = get_guest_path_by_id(tag);
 +    if (guest_path == NULL) {
 +        LOG_WARNING("hds guest path is empty with tag %s.\n", tag);
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_UMOUNT_FAIL, NULL);
 +        return;
 +    }
 +
 +    tag_level = get_hds_level_by_id(tag);
 +
 +    if (tag_level > level) {
 +        LOG_WARNING("HDS Level is not enough to unmount.\n");
 +        make_send_device_ntf(cmd, group, ECS_HDS_ACT_UMOUNT_NOT_ENOUGH_LEVEL, NULL);
 +        return;
 +    }
 +
 +    len = snprintf(emuld_data, sizeof(emuld_data), "%s\n%s\n", data, guest_path);
 +    LOG_INFO("send emuld to umount.%s\n", emuld_data);
 +    send_msg_to_guest(cmd, group, action, emuld_data, len + 1);
 +}
 +
 +void msgproc_device_req_hds(ECS_Client *ccli, ECS__DeviceReq *msg, char * cmd)
 +{
 +    char *data = NULL;
 +    type_group group = (type_group) (msg->group & 0xff);
 +    type_action action = (type_action) (msg->action & 0xff);
 +
 +    if (msg->has_data && msg->data.len > 0) {
 +        data = (char *) g_malloc0(msg->data.len + 1);
 +        memcpy(data, msg->data.data, msg->data.len);
 +    }
 +
 +    LOG_INFO("hds group: %d, action : %d\n", group, action);
 +    if (group == MSG_GROUP_STATUS) {
 +        ecs_hds_do_status(cmd, group);
 +    } else if (group == ECS_HDS_MSG_GROUP && action == ECS_HDS_ACTION_MOUNT) {
 +        ecs_hds_do_mount(cmd, group, data);
 +    } else if (group == ECS_HDS_MSG_GROUP && action == ECS_HDS_ACTION_UMOUNT) {
 +        ecs_hds_do_umount(cmd, group, action, data);
 +    } else {
 +        LOG_WARNING("hds unknown command: group %d action %d\n", group, action);
 +    }
 +
 +    g_free(data);
 +}
 +
 +static void send_hds_mount_request(char *list)
 +{
 +    int len = 0;
 +    char token[] = ",";
 +    char emuld_data[OUT_BUF_SIZE];
 +    char *id;
 +    char *host;
 +    char *guest;
 +
 +    LOG_INFO("handling mount request: %s\n", list);
 +
 +    id = strtok(list, token);
 +    if (id == NULL) {
 +        LOG_WARNING("cannot send mount request because of id\n");
 +        return;
 +    }
 +
 +    host = strtok(NULL, token);
 +    if (host == NULL) {
 +        LOG_WARNING("cannot send mount request because of host\n");
 +        return;
 +    }
 +
 +    guest = strtok(NULL, token);
 +    if (guest == NULL) {
 +        LOG_WARNING("cannot send mount request because of guest\n");
 +        return;
 +    }
 +
 +    len = snprintf(emuld_data, sizeof(emuld_data), "%s\n%s\n", id, guest);
 +    send_msg_to_guest(MSG_TYPE_HDS, ECS_HDS_MSG_GROUP,
 +            ECS_HDS_ACTION_MOUNT, emuld_data, len + 1);
 +}
 +
 +static void *hds_mount_request_thread(void *args)
 +{
 +    char *list = (char *)args;
 +    char token[] = "\n";
 +    char *hds_list;
 +
 +    hds_list = strtok(list, token);
 +    if (hds_list == NULL) {
 +        LOG_INFO("no hds mount request\n");
 +        free(list);
 +        return NULL;
 +    }
 +
 +    send_hds_mount_request(hds_list);
 +
 +    while ((hds_list = strtok(NULL, token)) != NULL) {
 +        send_hds_mount_request(hds_list);
 +    }
 +
 +    free(list);
 +    return NULL;
 +}
 +
 +static void ecs_hds_do_get_list(void)
 +{
 +    char *list;
 +    QemuThread hds_thread_id;
 +
 +    list = get_hds_lists();
 +    if (strlen(list) == 0) {
 +        LOG_INFO("none of mount candidates available.\n");
 +        return;
 +    }
 +    qemu_thread_create(&hds_thread_id, "hds_mount", hds_mount_request_thread,
 +            (void *)list, QEMU_THREAD_DETACHED);
 +}
 +
 +void msgproc_injector_do_hds(char *cat, type_action action, const char *data)
 +{
 +    FsDriverEntry *entry;
 +    char msg[OUT_BUF_SIZE];
 +    char *host;
 +    char *guest;
 +    enum hds_level level;
 +
 +    LOG_INFO("hds status is %d, %s\n", action, data);
 +    switch (action) {
 +    case ECS_HDS_ACT_GET_LIST:
 +        ecs_hds_do_get_list();
 +        break;
 +    case ECS_HDS_ACT_ADD_LIST_FOR_DEFAULT:
 +        entry = get_fsdev_fsentry((char *)DEFAULT_STATIC_HDS_ID);
 +        if (entry == NULL) {
 +            LOG_WARNING("cannot find fsdev entry.\n");
 +            break;
 +        }
 +
 +        if (!add_hds_list(DEFAULT_STATIC_HDS_ID, entry->path, DEFAULT_HDS_GUEST_PATH, hds_level_normal)) {
 +            LOG_WARNING("cannot add into hds list.\n");
 +            break;
 +        }
 +
 +        set_hds_attached(DEFAULT_STATIC_HDS_ID, true);
 +        data = DEFAULT_STATIC_HDS_ID;
 +        /* pass-through */
 +
 +    case ECS_HDS_ACT_MOUNT_SUCCESS:
 +        if (data == NULL) {
 +            LOG_WARNING("error: hds data is null.\n");
 +            break;
 +        }
 +        host = get_host_path_by_id(data);
 +        if (host == NULL) {
 +            LOG_WARNING("get_host_path_by_id failed with %s\n", data);
 +            break;
 +        }
 +        guest = get_guest_path_by_id(data);
 +        if (guest == NULL) {
 +            LOG_WARNING("get_guest_path_by_id failed with %s\n", data);
 +            break;
 +        }
 +
 +        level = get_hds_level_by_id(data);
 +        snprintf(msg, sizeof(msg), "%s,%s,%s,%d,", data, host, guest, level);
 +        make_send_device_ntf(cat, ECS_HDS_MSG_GROUP, action, msg);
 +        break;
 +    case ECS_HDS_ACT_MOUNT_FAIL:
 +    case ECS_HDS_ACT_MOUNT_NOT_PERMITTED: /* not exist on the possible path */
 +    case ECS_HDS_ACT_MOUNT_NOT_VALID_PATH: /* not a vaild path */
 +        if (data == NULL) {
 +            LOG_WARNING("error: hds data is null.\n");
 +            break;
 +        }
 +        remove_hds_list((char *)data);
 +        do_hotplug(DETACH_HDS, (char *)data, strlen(data) + 1);
 +        make_send_device_ntf(cat, ECS_HDS_MSG_GROUP, action, (char *)data);
 +        break;
 +    case ECS_HDS_ACT_UMOUNT_SUCCESS:
 +        if (data == NULL) {
 +            LOG_WARNING("error: hds data is null.\n");
 +            break;
 +        }
 +        do_hotplug(DETACH_HDS, (char *)data, strlen(data) + 1);
 +        make_send_device_ntf(cat, ECS_HDS_MSG_GROUP, action, (char *)data);
 +        break;
 +    case ECS_HDS_ACT_UMOUNT_FAIL:
 +        if (data == NULL) {
 +            LOG_WARNING("error: hds data is null.\n");
 +            break;
 +        }
 +        make_send_device_ntf(cat, ECS_HDS_MSG_GROUP, action, (char *)data);
 +        break;
 +    default:
 +        LOG_WARNING("unknown action: %s.\n", action);
 +        break;
 +    }
 +}
index 43fdb50,0000000..8e6b7ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,770 -1,0 +1,770 @@@
-                                           NET_CLIENT_OPTIONS_KIND_NIC,
 +/*
 + * Emulator State Information
 + *
 + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
 + *
 + * Contact:
 + * SeokYeon Hwang <syeon.hwang@samsung.com>
 + * MunKyu Im <munkyu.im@samsung.com>
 + * GiWoong Kim <giwoong.kim@samsung.com>
 + * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
 + * HyunJun Son
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#include "emul_state.h"
 +
 +#include <libgen.h>
 +#include "emulator_common.h"
 +
 +#if defined(CONFIG_LINUX)
 +#include <X11/XKBlib.h>
 +extern bool kvm_allowed;
 +#elif defined(CONFIG_WIN32)
 +#include <windows.h>
 +extern bool hax_allowed;
 +#elif defined(CONFIG_DARWIN)
 +#include <fcntl.h>
 +extern bool hax_allowed;
 +#endif
 +
 +#include "qemu/osdep.h"
 +#include "ui/console.h"
 +#include "sysemu/sysemu.h"
 +#include "block/block_int.h"
 +#include "sysemu/block-backend.h"
 +#include "net/net.h"
 +#include "qmp-commands.h"
 +#ifdef CONFIG_VIRTFS
 +#include "fsdev/qemu-fsdev.h"
 +#endif
 +
 +#include "emulator.h"
 +#include "emulator_options.h"
 +#include "hw/virtio/maru_virtio_input.h"
 +#include "hw/virtio/maru_virtio_evdi.h"
 +#include "util/net_helper.h"
 +#include "util/new_debug_ch.h"
 +
 +DECLARE_DEBUG_CHANNEL(emul_state);
 +
 +#define MAXLEN  512
 +
 +static EmulatorConfigInfo _emul_info;
 +static EmulatorConfigState _emul_state;
 +
 +int get_max_touch_point(void)
 +{
 +    return virtio_touchscreen_get_max_touch_point();
 +}
 +
 +/* current emulator condition */
 +int get_emulator_condition(void)
 +{
 +    return _emul_state.emulator_condition;
 +}
 +
 +void set_emulator_condition(int state)
 +{
 +    if (state == BOOT_COMPLETED) {
 +        LOG_INFO("boot completed!\n");
 +        // TODO:
 +    } else if (state == RESET) {
 +        LOG_INFO("reset emulator!\n");
 +    }
 +
 +    _emul_state.emulator_condition = state;
 +}
 +
 +void set_emuld_connection(bool connected)
 +{
 +    _emul_state.emuld_connection = connected;
 +}
 +
 +bool get_emuld_connection(void)
 +{
 +    return _emul_state.emuld_connection;
 +}
 +
 +void set_sdb_connection(bool connected)
 +{
 +    _emul_state.sdb_connection = connected;
 +}
 +
 +bool get_sdb_connection(void)
 +{
 +    return _emul_state.sdb_connection;
 +}
 +
 +/* emualtor skin path */
 +const char* get_emul_skin_path(void)
 +{
 +    if (!_emul_info.skin_path) {
 +        _emul_info.skin_path = get_variable("skin_path");
 +    }
 +
 +    return _emul_info.skin_path;
 +}
 +
 +/* CPU virtualization */
 +bool get_emul_cpu_accel(void)
 +{
 +#ifdef CONFIG_LINUX
 +    return kvm_allowed;
 +#else
 +    return hax_allowed;
 +#endif
 +
 +    return false;
 +}
 +
 +//
 +// cleaned-up
 +//
 +
 +// launch_conf_path
 +// only set by emulator.c when start up
 +const char *launch_conf_file = NULL;
 +
 +// bin path
 +// only set by osutil-{OS}.c when start up
 +const char *bin_path = NULL;
 +
 +const char *get_bin_path(void)
 +{
 +    if (bin_path) {
 +        return bin_path;
 +    }
 +
 +    return "";
 +}
 +
 +// emulator kernel log file
 +static const char *kernel_log_redirect_file = NULL;
 +
 +const char *get_kernel_log_redirect_file(void)
 +{
 +    // TODO: kernel log path should be aquired from char device.
 +    if (kernel_log_redirect_file) {
 +        return kernel_log_redirect_file;
 +    }
 +
 +    const char *vms_path = get_variable("vms_path");
 +    const char *vm_name = get_variable("vm_name");
 +    if (!vms_path || !vm_name) {
 +        // we can not specify log path.
 +        // emulator may not be launched from emulator-manager.
 +        kernel_log_redirect_file = g_strdup("");
 +    }
 +    else {
 +        kernel_log_redirect_file =
 +            g_strdup_printf("%s/%s/logs/emulator.klog", vms_path, vm_name);
 +    }
 +
 +    return kernel_log_redirect_file;
 +}
 +
 +// emulator log file
 +static const char *log_redirect_file = NULL;
 +
 +#ifdef CONFIG_WIN32
 +// for checking Windows version
 +extern OSVERSIONINFO osvi;
 +#endif
 +
 +const char *get_log_redirect_file(void)
 +{
 +    int result = -1;
 +    char log_filename[PATH_MAX];
 +
 +    // should we compare stdout(fd/1) and stderr(fd/2) ??
 +#if defined(CONFIG_LINUX)
 +    result = readlink("/proc/self/fd/1", log_filename, PATH_MAX);
 +    if (result >= 0) {
 +        log_filename[result] = '\0';
 +    }
 +#elif defined(CONFIG_DARWIN)
 +    result = fcntl(STDOUT_FILENO, F_GETPATH, log_filename);
 +#elif defined(CONFIG_WIN32)
 +# if WINVER >= 0x600
 +    // works only vista or newer...
 +    if (osvi.dwMajorVersion >= 6) {
 +        char win32_log_filename_normalized[PATH_MAX];
 +        HANDLE handle_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
 +        DWORD ret = GetFinalPathNameByHandle(handle_stdout,
 +                win32_log_filename_normalized,
 +                PATH_MAX, FILE_NAME_NORMALIZED);
 +        // strip "\\?\"
 +        if (ret > 0) {
 +            g_stpcpy(log_filename, win32_log_filename_normalized + 4);
 +            result = 0;
 +        } else {
 +            result = -1;
 +        }
 +    }
 +# endif
 +#endif
 +    if (log_redirect_file) {
 +        g_free((void *)log_redirect_file);
 +    }
 +
 +    if (result >= 0) {
 +        log_redirect_file = g_strdup(log_filename);
 +    } else {
 +    // fail safe
 +        LOG_WARNING("Can not identify log redirection path, "
 +                "We should assume it !!!\n");
 +
 +        const char *vms_path = get_variable("vms_path");
 +        const char *vm_name = get_variable("vm_name");
 +        if (!vms_path || !vm_name) {
 +            // we can not specify log path.
 +            // emulator may not be launched from emulator-manager.
 +            log_redirect_file = g_strdup("");
 +        }
 +        else {
 +            log_redirect_file =
 +                g_strdup_printf("%s/%s/logs/emulator.log", vms_path, vm_name);
 +        }
 +    }
 +
 +    return log_redirect_file;
 +}
 +
 +// drive image file
 +static const char *drive_image_file = NULL;
 +
 +const char *get_drive_image_file(void)
 +{
 +    if (drive_image_file) {
 +        return drive_image_file;
 +    }
 +
 +    // we should parse from "drive" parameter.
 +    // so qemu_main() had to be called before.
 +    BlockBackend *bb = blk_by_name("drive");
 +    if (bb) {
 +        BlockDriverState *bs = blk_bs(bb);
 +        drive_image_file = g_strdup(bs->filename);
 +
 +        return drive_image_file;
 +    }
 +
 +    // called before device initialized
 +    // or very weired situation
 +    LOG_WARNING("Can not identify main drive image file !!!\n");
 +
 +    return "";
 +}
 +
 +const char *get_drive_image_ver(void)
 +{
 +    return get_variable("image_ver");
 +}
 +
 +// swap image file
 +static const char *swap_image_file = NULL;
 +
 +const char *get_swap_image_file(void)
 +{
 +    if (swap_image_file) {
 +        return swap_image_file;
 +    }
 +
 +    // we should parse from "swap" parameter.
 +    // so qemu_main() had to be called before.
 +    BlockBackend *bb = blk_by_name("swap");
 +    if (bb) {
 +        BlockDriverState *bs = blk_bs(bb);
 +        swap_image_file = g_strdup(bs->filename);
 +
 +        return swap_image_file;
 +    }
 +
 +    // called before device initialized
 +    // or very weired situation
 +    LOG_WARNING("Can not identify swap image file !!!\n");
 +
 +    return "";
 +}
 +
 +// kernel file
 +const char *get_kernel_file(void)
 +{
 +    return qemu_opt_get(qemu_get_machine_opts(), "kernel");
 +}
 +
 +// http proxy
 +static const char *http_proxy_addr = NULL;
 +
 +const char *get_http_proxy_addr(void)
 +{
 +    if (http_proxy_addr) {
 +        return http_proxy_addr;
 +    }
 +
 +    const char *kernel_cmdline =
 +        qemu_opt_get(qemu_get_machine_opts(), "append");
 +
 +    // kernel cmdline always contains proxy information
 +    char *buf = g_strstr_len(kernel_cmdline, -1, "http_proxy=");
 +    if (buf) {
 +        char **token = g_strsplit_set(buf, "= ", 3);
 +        if (token[0] && token[1] && g_strcmp0(token[1], "")) {
 +            http_proxy_addr = g_strdup(token[1]);
 +            g_strfreev(token);
 +
 +            LOG_INFO("HTTP proxy address: %s\n", http_proxy_addr);
 +
 +            return http_proxy_addr;
 +        }
 +        g_strfreev(token);
 +    }
 +
 +    http_proxy_addr = g_strdup("");
 +
 +    LOG_INFO("HTTP proxy address is not set.\n");
 +
 +    return http_proxy_addr;
 +}
 +
 +// vm_name
 +static const char *vm_name = NULL;
 +
 +const char *get_vm_name(void)
 +{
 +    if (vm_name) {
 +        return vm_name;
 +    }
 +
 +    // check variable
 +    const char *var_vm_name = get_variable("vm_name");
 +
 +    // check drive image name
 +    char *drive_file_vm_name = g_path_get_basename(get_drive_image_file());
 +
 +    // remove file extension
 +    char *last_dot = g_strrstr(drive_file_vm_name, ".");
 +    if (last_dot) {
 +        *last_dot = '\0';
 +    }
 +
 +    // if it has "emulimg-" prefix - it may be made by emulator-manager
 +    // we should remove it
 +    int start_index = 0;
 +    if (!strncmp("emulimg-", drive_file_vm_name, 8)) {
 +        start_index = 8;
 +    }
 +
 +    if (g_strcmp0(var_vm_name, drive_file_vm_name + start_index)) {
 +        // when drive_file_vm_name != var_vm_name
 +        // we should warn to users
 +        LOG_WARNING("vm_name and image_file_name is not matched\n");
 +    } else {
 +        // we choose drive_file_vm_name when var_vm_name is not provided
 +        // or they contain same name
 +    }
 +
 +    vm_name = g_strdup(drive_file_vm_name + start_index);
 +
 +    g_free(drive_file_vm_name);
 +
 +    LOG_INFO("VM name: %s\n", vm_name);
 +
 +    return vm_name;
 +}
 +
 +const char *get_profile_name(void)
 +{
 +    return get_variable("profile");
 +}
 +
 +const char *get_platform_version(void)
 +{
 +    return get_variable("platform_version");
 +}
 +
 +#ifdef CONFIG_VIRTFS
 +// host directory sharing path
 +const char* get_host_directory_sharing_path(void)
 +{
 +    FsDriverEntry *sharing_entry = get_fsdev_fsentry((char*)DEFAULT_STATIC_HDS_ID);
 +    const char *sharing_path = (sharing_entry != NULL ? sharing_entry->path : NULL);
 +
 +    return sharing_path;
 +}
 +#else
 +const char* get_host_directory_sharing_path(void)
 +{
 +    return NULL;
 +}
 +#endif
 +
 +// GPU virtualization
 +static bool gpu_accel_enabled;
 +
 +bool is_gpu_accel_enabled(void)
 +{
 +    static bool is_done;
 +    PciInfoList *info_list, *info;
 +    Error *err = NULL;
 +
 +    if (is_done) {
 +        return gpu_accel_enabled;
 +    }
 +
 +    info_list = qmp_query_pci(&err);
 +    if (err) {
 +        LOG_WARNING("PCI devices not supported\n");
 +        error_free(err);
 +        is_done = true;
 +        return false;
 +    }
 +
 +    for (info = info_list; info; info = info->next) {
 +        PciDeviceInfoList *dev;
 +
 +        for (dev = info->value->devices; dev; dev = dev->next) {
 +            /* TODO: use defines in the pci_regs.h
 +                     instead of the hard coding */
 +            if (dev->value->id->vendor == 0x19B1
 +                && dev->value->id->device == 0x1010) {
 +                gpu_accel_enabled = true;
 +            }
 +        }
 +    }
 +
 +    qapi_free_PciInfoList(info_list);
 +    is_done = true;
 +
 +    return gpu_accel_enabled;
 +}
 +
 +// ram size
 +uint64_t get_ram_size(void)
 +{
 +    return ram_size;
 +}
 +
 +// VM base port
 +// only set by net_helper.c when start up
 +int vm_base_port = -1;
 +
 +int get_vm_base_port(void)
 +{
 +    // should not be called before base port is prepared
 +    g_assert(vm_base_port != 0);
 +
 +    return vm_base_port;
 +}
 +
 +int get_vm_spice_port(void)
 +{
 +    // should not be called before base port is prepared
 +    g_assert(vm_base_port != 0);
 +
 +    return vm_base_port + SPICE_TCP_INDEX;
 +}
 +
 +int get_vm_device_serial_number(void)
 +{
 +    // should not be called before base port is prepared
 +    g_assert(vm_base_port != 0);
 +
 +    if (is_netclient_tap_attached()) {
 +        return (START_VM_BASE_PORT + SDB_TCP_INDEX);
 +    }
 +
 +    return vm_base_port + SDB_TCP_INDEX;
 +}
 +
 +// look-up PCI devices
 +bool is_pci_device_enabled(int device_id)
 +{
 +    bool is_enabled = false;
 +    PciInfoList *info_list, *info;
 +    Error *err = NULL;
 +
 +    info_list = qmp_query_pci(&err);
 +    if (err) {
 +        LOG_WARNING("PCI devices not supported\n");
 +        error_free(err);
 +        return false;
 +    }
 +
 +    for (info = info_list; info; info = info->next) {
 +        PciDeviceInfoList *dev;
 +        for (dev = info->value->devices; dev; dev = dev->next) {
 +            if (dev->value->id->device == device_id) {
 +                is_enabled = true;
 +                break;
 +            }
 +        }
 +    }
 +
 +    qapi_free_PciInfoList(info_list);
 +
 +    return is_enabled;
 +}
 +
 +// mouse input
 +bool is_mouse_enabled(void)
 +{
 +    /* TODO: If the maru mouse device is added,
 +     * the device id should to be changed for it.
 +    */
 +    return !is_pci_device_enabled(PCI_DEVICE_ID_VIRTIO_MARU_TOUCHSCREEN);
 +}
 +
 +// touchscreen input
 +bool is_touchscreen_enabled(void)
 +{
 +    return is_pci_device_enabled(PCI_DEVICE_ID_VIRTIO_MARU_TOUCHSCREEN);
 +}
 +
 +// tap attached
 +bool is_netclient_tap_attached(void)
 +{
 +    NetClientState *ncs[MAX_QUEUE_NUM];
 +    int queues, i;
 +
 +    queues = qemu_find_net_clients_except(NULL, ncs,
-         if (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_TAP &&
-                 (ncs[i]->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC ||
++                                          NET_CLIENT_DRIVER_NIC,
 +                                          MAX_QUEUE_NUM);
 +    for (i = 0; i < queues; ++i) {
-                  ncs[i]->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT)) {
++        if (ncs[i]->info->type == NET_CLIENT_DRIVER_TAP &&
++                (ncs[i]->peer->info->type == NET_CLIENT_DRIVER_NIC ||
 +                // for legacy -net option.
++                 ncs[i]->peer->info->type == NET_CLIENT_DRIVER_HUBPORT)) {
 +            return true;
 +        }
 +    }
 +
 +    return false;
 +}
 +
 +// vm_data_path
 +static const char *vm_data_path = NULL;
 +
 +const char* get_vm_data_path(void)
 +{
 +    if (vm_data_path) {
 +        return vm_data_path;
 +    }
 +
 +    // check drive image file path
 +    char *drive_image_path = g_path_get_dirname(get_drive_image_file());
 +
 +    // check launch conf file path
 +    char *conf_file_path = g_path_get_dirname(launch_conf_file);
 +
 +    if (g_strcmp0(drive_image_path, conf_file_path)) {
 +        // when drive_image_path != launch_conf_path
 +        // we should warn to users
 +        LOG_WARNING("drive_image_path and launch_conf_path is not matched\n");
 +    }
 +
 +    vm_data_path = drive_image_path;
 +
 +    g_free(conf_file_path);
 +
 +    LOG_INFO("VM data path: %s\n", vm_data_path);
 +
 +    return vm_data_path;
 +}
 +
 +const char *get_sdcard_image_path(void)
 +{
 +    const char *vm_data_path = get_vm_data_path();
 +#ifndef CONFIG_WIN32
 +    const gchar* sdcard_rel_path = g_strdup_printf("%s/../../sdcard/", vm_data_path);
 +#else
 +    const gchar* sdcard_rel_path = g_strdup_printf("%s\\..\\..\\sdcard\\", vm_data_path);
 +#endif
 +    char sdcard_abs_path[PATH_MAX + 1];
 +
 +    char *ptr = realpath(sdcard_rel_path, sdcard_abs_path);
 +    if (!ptr) {
 +        LOG_WARNING("Fail to get absolute path !!!\n");
 +        return sdcard_rel_path;
 +    }
 +#ifndef CONFIG_WIN32
 +    const char *sdcard_path = g_strdup_printf("%s/", sdcard_abs_path);
 +#else
 +    const char *sdcard_path;
 +    int path_length = strnlen(sdcard_abs_path, sizeof(sdcard_abs_path));
 +
 +    if (sdcard_abs_path[path_length - 1] != '\\') {
 +        sdcard_path = g_strdup_printf("%s\\", sdcard_abs_path);
 +    } else {
 +        sdcard_path = g_strdup(sdcard_abs_path);
 +    }
 +#endif
 +    g_free((void*)sdcard_rel_path);
 +
 +    LOG_INFO("SD card path: %s\n", sdcard_path);
 +    return sdcard_path;
 +}
 +
 +// guest IP
 +static const char *guest_ip = NULL;
 +
 +void set_guest_ip(const char *ip)
 +{
 +    if (guest_ip) {
 +        LOG_WARNING("Guest IP is aleady set !!!\n");
 +
 +        return;
 +    }
 +    guest_ip = g_strdup(ip);
 +}
 +
 +const char* get_guest_ip(void)
 +{
 +    if (!guest_ip) {
 +        LOG_WARNING("Guest IP is NULL !!!\n");
 +    }
 +
 +    return guest_ip;
 +}
 +
 +// host IP
 +static const char *host_ip = NULL;
 +
 +const char* get_host_ip(void)
 +{
 +    if (host_ip) {
 +        return host_ip;
 +    }
 +
 +    // try to get from conf
 +    const char *host_ip_var = get_variable("host_ip");
 +    if (host_ip_var) {
 +        host_ip = g_strdup(host_ip_var);
 +        return host_ip;
 +    }
 +
 +    // failsafe for legacy
 +    // try to parse from kernel commandline
 +    const char *kernel_cmdline =
 +        qemu_opt_get(qemu_get_machine_opts(), "append");
 +    char *buf = g_strstr_len(kernel_cmdline, -1, "host_ip=");
 +
 +    char **splitted;
 +    if (buf && (splitted = g_strsplit(buf, " ", 2))) {
 +        if (splitted[0]) {
 +            host_ip = g_strdup(splitted[0]);
 +        }
 +        g_strfreev(splitted);
 +
 +        return host_ip;
 +    }
 +
 +    g_assert(host_ip != NULL);
 +
 +    return NULL;
 +}
 +
 +// display resolution
 +// only set by vl.c when start up
 +int initial_resolution_width = -1;
 +int initial_resolution_height = -1;
 +
 +void set_initial_display_resolution(int width, int height)
 +{
 +    LOG_INFO("initial display resolution: %dx%d\n", width, height);
 +
 +    initial_resolution_width = width;
 +    initial_resolution_height = height;
 +}
 +
 +int get_display_resolution_width(void)
 +{
 +    return qemu_console_get_width(NULL, initial_resolution_width);
 +}
 +
 +int get_display_resolution_height(void)
 +{
 +    return qemu_console_get_height(NULL, initial_resolution_height);
 +}
 +
 +// guest default home
 +static const char *platform_default_home = NULL;
 +const char* get_platform_default_home(void)
 +{
 +    return platform_default_home;
 +}
 +
 +void set_platform_default_home(const char *path)
 +{
 +    if (!platform_default_home) {
 +        platform_default_home = g_strdup(path);
 +    } else {
 +        LOG_INFO("platform home path is already set : %s\n",
 +                platform_default_home);
 +    }
 +}
 +
 +static void emul_state_notify_exit(Notifier *notifier, void *data)
 +{
 +    g_free((void *)launch_conf_file);
 +    launch_conf_file = NULL;
 +
 +    g_free((void *)bin_path);
 +    bin_path = NULL;
 +
 +    g_free((void *)kernel_log_redirect_file);
 +    kernel_log_redirect_file = NULL;
 +
 +    g_free((void *)log_redirect_file);
 +    log_redirect_file = NULL;
 +
 +    g_free((void *)drive_image_file);
 +    drive_image_file = NULL;
 +
 +    g_free((void *)swap_image_file);
 +    swap_image_file = NULL;
 +
 +    g_free((void *)http_proxy_addr);
 +    http_proxy_addr = NULL;
 +
 +    g_free((void *)vm_name);
 +    vm_name = NULL;
 +
 +    g_free((void *)vm_data_path);
 +    vm_data_path = NULL;
 +
 +    g_free((void *)guest_ip);
 +    guest_ip = NULL;
 +
 +    g_free((void *)host_ip);
 +    host_ip = NULL;
 +
 +    g_free((void *)platform_default_home);
 +    platform_default_home = NULL;
 +}
 +
 +
 +static Notifier emul_state_exit = { .notify = emul_state_notify_exit };
 +
 +void init_emul_state(void)
 +{
 +    emulator_add_exit_notifier(&emul_state_exit);
 +}
index 8e28f87,0000000..ad2845c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1874 -1,0 +1,1873 @@@
- #include "exec/ram_addr.h"
 +/* * Maru virtual tuner device
 + *
 + * Copyright (C) 2011 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
 + *
 + * Contact:
 + * Byeongki Shin <bk0121.shin@samsung.com>
 + * Sangho Park <sangho.p@samsung.com>
 + * Ningjia Fan <ningjia.fan@samsung.com>
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 + * MA  02110-1301, USA.
 + *
 + * Contributors:
 + * - S-Core Co., Ltd
 + *
 + */
 +
 +#include <stdio.h>
 +#include <stddef.h>
 +#include <pthread.h>
 +
 +#include "qemu/osdep.h"
 +#include "exec/memory.h"
 +#include "exec/memory-internal.h"
-     s->vaddr = qemu_get_ram_ptr(NULL, (ram_addr_t)val);
 +#include "tizen/src/emulator.h"
 +#include "qemu/config-file.h"
 +#include "qemu/main-loop.h"
 +#include "qemu-common.h"
 +#include "hw/maru_device_ids.h"
 +#include "maru_tuner.h"
 +#include "ecs/ecs.h"
 +#include "util/new_debug_ch.h"
 +
 +DECLARE_DEBUG_CHANNEL(tuner);
 +
 +#define MARUTUNER_DEV_NAME      "maru-virtual-tuner"
 +#define MARUTUNER_TS_PACKETS    1024
 +//#define MARUTUNER_MEM_SIZE    (188 * MARUTUNER_TS_PACKETS)    /* size of a TS packet is 188 byte */
 +#define MARUTUNER_MEM_SIZE      0x2000
 +#define MARUTUNER_REG_SIZE      256
 +
 +
 +#define REPLAY_ON_EOF   0
 +
 +#define print_tuner_state(s) LOG_INFO("(%s:%d) tsfile:[%s] freq:%ld, mod:%x\n", \
 +                                  __func__, __LINE__, s->fe.ts_filename?s->fe.ts_filename:"null", s->fe.frequency, s->fe.modulation);
 +
 +#ifdef QTEST_TIZEN
 +#include <libgen.h>
 +
 +static int qtest_tuner_initfn(PCIDevice *dev);
 +static void qtest_tuner_02(MaruTunerState *s);
 +static void qtest_tuner_03(MaruTunerState *s);
 +static void qtest_tuner_04(MaruTunerState *s);
 +#endif
 +
 +static int g_tuners_num = 0;
 +
 +//TODO global tune info should be N-tuner based
 +static char ts_mapping_table_path[MAX_PATH_LEN] = {0};
 +//static char still_img_path[MAX_PATH_LEN] = {0};
 +static struct tune_info g_current_tune = {0, 0, MAX_MODULATION, -1, -1};
 +
 +static pthread_mutex_t g_tuners_lck = PTHREAD_MUTEX_INITIALIZER;
 +static QSIMPLEQ_HEAD(, MaruTunerState) g_tuners = QSIMPLEQ_HEAD_INITIALIZER(g_tuners);
 +
 +/* MaruTunerState handling utilities
 + * add_tuner_device, del_tuner_device , find_tuner_device
 + */
 +static void add_tuner_device(MaruTunerState* s)
 +{
 +    pthread_mutex_lock(&g_tuners_lck);
 +    QSIMPLEQ_INSERT_TAIL(&g_tuners, s, list);
 +    pthread_mutex_unlock(&g_tuners_lck);
 +}
 +
 +static void del_tuner_device(MaruTunerState* s)
 +{
 +    pthread_mutex_lock(&g_tuners_lck);
 +    QSIMPLEQ_REMOVE(&g_tuners, s, MaruTunerState, list);
 +    pthread_mutex_unlock(&g_tuners_lck);
 +}
 +
 +static MaruTunerState* find_tuner_device(int dev_num)
 +{
 +    // g_tuners_lck should be held before enter
 +    LOG_TRACE("(%s) %d\n", __func__, dev_num);
 +    MaruTunerState* s = NULL;
 +    if (QSIMPLEQ_EMPTY(&g_tuners))
 +        return NULL;
 +    QSIMPLEQ_FOREACH(s, &g_tuners, list) {
 +        if (s->id == dev_num)
 +            return s;
 +    }
 +    return NULL;
 +}
 +
 +
 +/* Should be called after acquiring tsdemux mutex */
 +static void dump_filter_list(MaruTunerState *s)
 +{
 +    struct pid_filter *filter;
 +    LOG_TRACE("(%s) :\n", __func__);
 +    QLIST_FOREACH(filter, &s->filters_head, entries) {
 +        LOG_TRACE("    pid = %d(0x%x), stream_idx = %d, enabled = %d\n",
 +                filter->pid, filter->pid, filter->stream_idx, filter->enabled);
 +    }
 +
 +    if (QLIST_EMPTY(&s->filters_head)) {
 +        LOG_TRACE("    filter list is empty\n", __func__);
 +    }
 +}
 +
 +
 +struct param_setting {
 +    const char *name;
 +    unsigned int value;
 +};
 +
 +#define MAX_ONAIR_LEN      10
 +#define MAX_MODULATION_LEN 10
 +#define MAX_CARRIER_LEN 128
 +static struct param_setting atsc_modulation_list[] = {
 +    { "QPSK",    QPSK   },
 +    { "PSK8",    PSK_8  },
 +    { "QAM32",   QAM_32 },
 +    { "QAM16",   QAM_16 },
 +    { "QAM128",  QAM_128},
 +    { "8VSB",    VSB_8  },
 +    { "16VSB",   VSB_16 },
 +    { "QAM64",   QAM_64 },
 +    { "QAM256",  QAM_256},
 +    { NULL,      -1 }
 +};
 +
 +static struct param_setting config_system_list[] = {
 +    { "ATSC", MARUTUNER_CONFIG_SYSTEM_ATSC },
 +    { "DVB",  MARUTUNER_CONFIG_SYSTEM_DVB  },
 +    { NULL, -1}
 +};
 +
 +static struct param_setting config_country_list[] = {
 +    { "KOR", MARUTUNER_CONFIG_COUNTRY_KOR },
 +    { "USA", MARUTUNER_CONFIG_COUNTRY_USA },
 +    { NULL, -1}
 +};
 +
 +static struct param_setting config_playmode_list[] = {
 +    { "ts", MARUTUNER_CONFIG_PLAYMODE_TS },
 +    { "still", MARUTUNER_CONFIG_PLAYMODE_STILL },
 +    { NULL, -1}
 +};
 +
 +static int get_config_value(struct param_setting *list, const char *str)
 +{
 +    while (list->name) {
 +        if (strcmp(list->name, str) == 0) {
 +            break;
 +        }
 +        list++;
 +    }
 +    return list->value;
 +}
 +
 +
 +#define CONFIG_TABLE_NR_COLUMN 7
 +#define CONFIG_TABLE_NR_COLUMN_DVB 12
 +static inline int get_table_entry_params_atsc(char *buf, unsigned int *streaming, char* carrier,
 +                                         unsigned int *freq, char *mod,
 +                                         char *path)
 +{
 +    int cnt;
 +    unsigned int ptc = 0;
 +    char onair[MAX_ONAIR_LEN] = {0};
 +    assert(buf);
 +    cnt = sscanf(buf, "%u %s %s %s %u %u %[^\n]", streaming, onair, carrier, mod, &ptc, freq, path);
 +    return cnt;
 +}
 +
 +static inline int get_table_entry_params_dvb(char *buf, unsigned int *streaming, char* carrier,
 +                                         unsigned int *freq, char *mod,
 +                                         char *path)
 +{
 +    int cnt;
 +    unsigned int sym_rate = 0;
 +    unsigned int cell_id = 0;
 +    unsigned int bit_error = 0;
 +    unsigned int sig_strength = 0;
 +    unsigned int sig_quality = 0;
 +    unsigned int ptc = 0;
 +    char onair[MAX_ONAIR_LEN] = {0};
 +    assert(buf);
 +    // The DVB specific params, which are from sym_rate to sig_quality, have no real operation now
 +    // Reserved for future use
 +    cnt = sscanf(buf, "%u %s %s %s %u %u %u %u %u %u %u %[^\n]", streaming, onair, carrier, mod, &ptc, freq,
 +                &sym_rate, &cell_id, &bit_error, &sig_strength, &sig_quality, path);
 +    return cnt;
 +}
 +
 +/*
 + * Table spec :
 + * <Antena> <OnAir> <PTC> <Frequency> <Modulation> <TS-file>
 + *
 + * returned argument :
 + * antena, frequency, modulation, file path
 + * none used : ptc, onair
 + */
 +//<Antena> <OnAir> <Carrier> <Modulation> <PTC> <Frequency> <TS-file>
 +static inline int get_table_entry_params(MaruTunerState *s, char *buf, unsigned int *streaming, char* carrier,
 +                                         unsigned int *freq, char *mod,
 +                                         char *path)
 +{
 +    int ret = 0;
 +    if (s->cfg.system == MARUTUNER_CONFIG_SYSTEM_ATSC) {
 +        ret = (CONFIG_TABLE_NR_COLUMN == get_table_entry_params_atsc(buf, streaming, carrier, freq, mod, path));
 +    } else if (s->cfg.system == MARUTUNER_CONFIG_SYSTEM_DVB) {
 +        ret = (CONFIG_TABLE_NR_COLUMN_DVB == get_table_entry_params_dvb(buf, streaming, carrier, freq, mod, path));
 +    } else {
 +        ret = 0;
 +    }
 +    return ret;
 +}
 +
 +// This marutuner_tune_atv function checks whether the number of columns is (CONFIG_TABLE_NR_COLUMN - 1),
 +// because the condition of ATV is existence of every parameters without only tsfile column.
 +// To sum up, in case of DTV must have CONFIG_TABLE_NR_COLUMN, and in case of ATV must have (CONFIG_TABLE_NR_COLUMN-1).
 +static inline int get_table_entry_params_atv(MaruTunerState *s, char *buf, unsigned int *streaming, char* carrier,
 +                                         unsigned int *freq, char *mod,
 +                                         char *path)
 +{
 +    int ret = 0;
 +    if (s->cfg.system == MARUTUNER_CONFIG_SYSTEM_ATSC) {
 +        ret = ((CONFIG_TABLE_NR_COLUMN - 1) == get_table_entry_params_atsc(buf, streaming, carrier, freq, mod, path));
 +    } else if (s->cfg.system == MARUTUNER_CONFIG_SYSTEM_DVB) {
 +        ret = ((CONFIG_TABLE_NR_COLUMN_DVB - 1) == get_table_entry_params_dvb(buf, streaming, carrier, freq, mod, path));
 +    } else {
 +        ret = 0;
 +    }
 +    return ret;
 +}
 +
 +/*
 + * simple table searching for atv
 + */
 +static void marutuner_tune_atv(MaruTunerState *s, unsigned int freq)
 +{
 +    char line_buf[MAX_PATH_LEN];       // is this enough?
 +    char tpath[MAX_PATH_LEN];
 +    char tmod_str[MAX_MODULATION_LEN];
 +    char carrier[MAX_CARRIER_LEN];
 +    size_t line_size = MAX_PATH_LEN;
 +
 +    s->fe.frequency = freq;
 +    s->fe_status = MARUTUNER_FE_TUNE_FAILED;
 +
 +    s->table = fopen(ts_mapping_table_path, "rb");
 +    if (!s->table) {
 +        LOG_SEVERE("(%s) table file open failed(%d)\n", __func__, errno);
 +        return;
 +    }
 +
 +    /* for win32 compatibility, we can't use getline */
 +    while ((fgets(line_buf, line_size, s->table)) != NULL) {
 +        unsigned int is_streaming = 0;
 +        unsigned int tfreq = 0;
 +        memset(tpath, 0x0, MAX_PATH_LEN);
 +        memset(tmod_str, 0x0, MAX_MODULATION_LEN);
 +        memset(carrier, 0x0, MAX_CARRIER_LEN);
 +
 +        if (!get_table_entry_params_atv(s, line_buf, &is_streaming, carrier, &tfreq, tmod_str, tpath)) {
 +            LOG_TRACE("(%s) invalid entry(%s). go to next entry.\n", __func__, line_buf);
 +            continue;
 +        }
 +
 +        /*
 +         * check frequency existence and no file
 +         * don't care modulation
 +         */
 +        if (s->fe.frequency == tfreq) {
 +            if (tpath[0] == '\0') {
 +                LOG_TRACE("(%s) frequency(%u) matched, atv channel\n", __func__, tfreq);
 +                s->fe_status = MARUTUNER_FE_HAS_ONLY_PARAM;
 +                break;
 +            } else {
 +                LOG_TRACE("(%s) frequency(%u) matched, but dtv channel\n", __func__, tfreq);
 +                break;
 +            }
 +        }
 +    }
 +
 +    if (s->table) {
 +        fclose(s->table);
 +        s->table = NULL;
 +    }
 +}
 +
 +/*
 + * TS mapping table parser
 + *
 + * return tuned status.
 + *        0 : failed. no entry or error
 + *        1 : failed. has only frequency and modulation, but no ts file
 + *        2 : success
 + */
 +static int get_mapped_ts_file(MaruTunerState *s, FILE *table, struct fe_param *fe)
 +{
 +    char line_buf[MAX_PATH_LEN];       // is this enough?
 +    char tmod_str[MAX_MODULATION_LEN];
 +    char tpath[MAX_PATH_LEN];
 +    char carrier[MAX_CARRIER_LEN];
 +
 +
 +    size_t line_size = MAX_PATH_LEN;
 +    int ret = MARUTUNER_FE_TUNE_FAILED;
 +
 +    /* for win32 compatibility, we can't use getline */
 +    while ((fgets(line_buf, line_size, table)) != NULL) {
 +        unsigned int is_streaming = 0;
 +        unsigned int tfreq = 0;
 +        fe_modulation_t tmod;
 +        memset(tpath, 0x0, MAX_PATH_LEN);
 +        memset(tmod_str, 0x0, MAX_MODULATION_LEN);
 +        memset(carrier, 0x0, MAX_CARRIER_LEN);
 +
 +        struct param_setting *mod_list = atsc_modulation_list;
 +        if (!get_table_entry_params(s, line_buf, &is_streaming, carrier, &tfreq, tmod_str, tpath)) {
 +            //LOG_TRACE("(%s) missing params(entry: %s). go to next entry.\n", __func__, line_buf);
 +            continue;
 +        }
 +        //LOG_TRACE("(%s) parsing success(freq=%u, mod=%s, path=%s)\n", __func__, tfreq, tmod_str, tpath);
 +
 +        /* get matched modulation value */
 +        while (mod_list->name) {
 +            if (strcmp(tmod_str, mod_list->name) == 0) {
 +                tmod = mod_list->value;
 +                goto modulation_converted;
 +            }
 +            mod_list++;
 +        }
 +        LOG_INFO("(%s) unsupported modulation. go to next entry\n", __func__);
 +        continue;
 +
 +modulation_converted:
 +        /* compare parameters */
 +        if ((fe->frequency == tfreq) && (fe->modulation == tmod)) {
 +            fe->ts_filename = strdup(tpath);
 +            if (!fe->ts_filename) {
 +                LOG_SEVERE("(%s) strdup error\n", __func__);
 +                goto out;
 +            }
 +
 +            LOG_INFO("(%s) frequency(%u) and modulation(%s) file(%s) matched\n",
 +                    __func__, tfreq, tmod_str, fe->ts_filename);
 +            /*
 +             * the 'b' mode of fopen is required by non-unix system
 +             */
 +            fe->tsfile = fopen(fe->ts_filename, "rb");
 +            if (!fe->tsfile) {
 +                LOG_SEVERE("(%s) ts file open failed\n", __func__);
 +                ret = MARUTUNER_FE_HAS_ONLY_PARAM;
 +                goto out;
 +            }
 +            fe->is_streaming = is_streaming;
 +            ret = MARUTUNER_FE_HAS_TS;
 +            goto out;
 +        }
 +    }
 +    LOG_TRACE("(%s) there is no matched list.\n", __func__);
 +
 +out:
 +    return ret;
 +}
 +
 +static int get_stream_idx_from_pid(MaruTunerState *s, int pid)
 +{
 +    AVStream *st;
 +    int i;
 +
 +    for (i = 0; i < s->fmt_ctx->nb_streams; i++) {
 +        st = s->fmt_ctx->streams[i];
 +        if (st->id == pid)
 +            return i;
 +    }
 +
 +    return -1;
 +}
 +
 +/* Should be called after acquiring tsdemux mutex */
 +static int add_pid_filter(MaruTunerState *s, int pid)
 +{
 +    struct pid_filter *filter;
 +
 +    LOG_TRACE("(%s)\n", __func__);
 +
 +    /* check that a filter already has this pid */
 +    QLIST_FOREACH(filter, &s->filters_head, entries) {
 +        if (filter->pid == pid) {
 +            LOG_TRACE("(%s) filter(pid = %d) already exists\n", __func__, pid);
 +            return 0;
 +        }
 +    }
 +
 +    /* new one */
 +    filter = calloc(1, sizeof(struct pid_filter));
 +    if (!filter) {
 +        LOG_SEVERE("(%s) not enough memory\n", __func__);
 +        return -1;
 +    }
 +
 +    filter->pid = pid;
 +    filter->stream_idx = -1; //stream_idx could be 0
 +    QLIST_INSERT_HEAD(&s->filters_head, filter, entries);
 +
 +    return 0;
 +}
 +
 +/* Should be called after acquiring tsdemux mutex
 + * return value:
 + *  -1 , if any error
 + *  otherwise, # of enabled filters
 + */
 +static int enable_filters_and_decoder(MaruTunerState *s)
 +{
 +    struct pid_filter *filter;
 +#ifndef QTEST_TIZEN
 +    AVStream *st;
 +#endif
 +    int idx;
 +    int ret = 0;
 +
 +    LOG_TRACE("(%s)\n", __func__);
 +
 +    QLIST_FOREACH(filter, &s->filters_head, entries) {
 +        if (filter->enabled == 0) {
 +            idx = get_stream_idx_from_pid(s, filter->pid);
 +            if (idx < 0) {
 +                LOG_TRACE("(%s) failed to get the matched stream idx(pid:%d)\n", __func__, filter->pid);
 +                continue;
 +            }
 +
 +#ifndef QTEST_TIZEN
 +            st = s->fmt_ctx->streams[idx];
 +            if (maru_tuner_dec_init_ctx(s->decoder_state, st) < 0) {
 +                /* TODO : unsupported format handling */
 +                LOG_SEVERE("(%s) Failed to initialize decoder context. pid(%d), stream idx(%d)\n",
 +                        __func__, filter->pid, filter->stream_idx);
 +                ret = -1;
 +                break;
 +            }
 +#endif
 +
 +            filter->stream_idx = idx;
 +            filter->enabled = 1;
 +            ret++;
 +            LOG_TRACE("(%s) pid(%d) matched stream idx = %d\n",
 +                    __func__, filter->pid, filter->stream_idx);
 +        }
 +    }
 +
 +    return ret;
 +}
 +
 +/* Should be called after acquiring tsdemux mutex */
 +static int init_avstream(MaruTunerState *s)
 +{
 +    /* open input file, and allocate format context */
 +    if (avformat_open_input(&s->fmt_ctx, s->fe.ts_filename, NULL, NULL) < 0) {
 +        LOG_SEVERE("(%s) avformat_open_input couldn't open ts file %s\n", __func__, s->fe.ts_filename);
 +        return -1;
 +    }
 +    LOG_INFO("init avstream :fmt_ctx: %p\n", s->fmt_ctx);
 +
 +    /* retrieve stream information */
 +    if (avformat_find_stream_info(s->fmt_ctx, NULL) < 0) {
 +        LOG_SEVERE("(%s) av_find_stream_info couldn't find stream information\n", __func__);
 +        goto error;
 +    }
 +
 +    LOG_TRACE("(%s) nb_programs = %d, nb_streams = %d\n",
 +            __func__, s->fmt_ctx->nb_programs, s->fmt_ctx->nb_streams);
 +
 +    return 0;
 +
 +error:
 +    avformat_close_input(&s->fmt_ctx);
 +    LOG_SEVERE("(%s) init failed. avstream closed\n", __func__);
 +    return -1;
 +}
 +
 +static void disable_filters_and_decoder(MaruTunerState *s)
 +{
 +    AVStream *st;
 +    struct pid_filter *filter, *next;
 +
 +    if (!s->fmt_ctx)
 +        return;
 +
 +    QLIST_FOREACH_SAFE(filter, &s->filters_head, entries, next) {
 +        if (filter->stream_idx == -1) {
 +            LOG_TRACE("(%s) filter(%p): pid(%d) is not enabled, enabled=%d\n",
 +                    __func__, filter, filter->pid, filter->enabled);
 +            continue;
 +        }
 +
 +        st = s->fmt_ctx->streams[filter->stream_idx];
 +        maru_tuner_dec_deinit_ctx(s->decoder_state, st);
 +        filter->enabled = 0;
 +        filter->stream_idx = -1;
 +        LOG_TRACE("(%s) disabled filter(%p): pid(%d), enabled(%d), stream_idx(%d)\n",
 +                __func__, filter, filter->pid, filter->enabled, filter->stream_idx);
 +    }
 +}
 +
 +/* Should be called after acquiring tsdemux mutex */
 +static void free_avstream(MaruTunerState *s, bool isfree)
 +{
 +    if (!s->fmt_ctx)
 +        return;
 +
 +    disable_filters_and_decoder(s);
 +
 +    LOG_TRACE("(%s) fmt_ctx: %p\n", __func__, s->fmt_ctx);
 +    avformat_close_input(&s->fmt_ctx);
 +    s->fe.is_streaming = false;
 +    /* don't need to assign null to fmt_ctx */
 +    //LOG_TRACE("(%s) after avformat close() :fmt_ctx: %p\n", __func__, s->fmt_ctx);
 +}
 +
 +static int switch_avstream(MaruTunerState *s)
 +{
 +    int ret;
 +
 +    free_avstream(s, false);
 +
 +    s->table = fopen(ts_mapping_table_path, "rb");
 +    if (!s->table) {
 +        LOG_SEVERE("(%s) table file open failed\n", __func__);
 +        return MARUTUNER_FE_TUNE_FAILED;
 +    }
 +    //TODO  mem leak here , before call get_mapped_ts_file
 +    // tsfile_name, tsfile (FILE*) should be closed.
 +    // at the same time, couldn't do that, because of section mutex
 +    ret = get_mapped_ts_file(s, s->table, &s->fe);
 +
 +    if (ret != MARUTUNER_FE_HAS_TS)
 +        goto close;
 +
 +    if (init_avstream(s) < 0) {
 +        LOG_SEVERE("(%s) failed to switch avstream\n", __func__);
 +        ret = MARUTUNER_FE_TUNE_FAILED;
 +        goto close;
 +    }
 +
 +    ret = enable_filters_and_decoder(s);
 +    if (ret < 0) {
 +        LOG_SEVERE("(%s) failed to enable fileter and decoder\n", __func__);
 +        ret = MARUTUNER_FE_TUNE_FAILED;
 +        free_avstream(s, false);
 +        goto close;
 +    } else if (ret == 0) {
 +        s->doing_filtering = 0;
 +    }
 +
 +close:
 +    if (s->table) {
 +        fclose (s->table);
 +        s->table = NULL;
 +    }
 +    return ret;
 +}
 +
 +#if 1
 +static void cleanup_filters(MaruTunerState *s)
 +{
 +    struct pid_filter *filter, *next;
 +    AVStream *st;
 +
 +    LOG_TRACE("(%s)\n", __func__);
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    QLIST_FOREACH_SAFE(filter, &s->filters_head, entries, next) {
 +        st = s->fmt_ctx->streams[filter->stream_idx];
 +        maru_tuner_dec_deinit_ctx(s->decoder_state, st);
 +        QLIST_REMOVE(filter, entries);
 +        free(filter);
 +    }
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +}
 +#endif
 +
 +/* Should be called after acquires section mutex */
 +static void marutuner_raise_intr(MaruTunerState *s, uint32_t irq)
 +{
 +    s->irq = irq;
 +    qemu_bh_schedule(s->qemu_bh);
 +}
 +
 +/* thread for section */
 +static void *marutuner_section_th(void *thread_param)
 +{
 +    MaruTunerState *s = (MaruTunerState *)thread_param;
 +#ifdef CONFIG_LINUX
 +    QemuThread thread;
 +#endif
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    LOG_INFO("section thread starting...\n");
 +#ifdef CONFIG_LINUX
 +    qemu_thread_get_self(&thread);
 +    LOG_TRACE("(%s) thread id : %x\n", __func__, thread.thread);
 +#endif
 +
 +    while (1) {
 +        //LOG_TRACE("(%s) waiting...\n", __func__);
 +        qemu_cond_wait(&s->section_th_cond, &s->section_mutex);
 +        //LOG_TRACE("(%s) woke up\n", __func__);
 +
 +        if (s->destroying == true) {
 +            LOG_TRACE("(%s) destroying...\n", __func__);
 +            s->hw_ptr_offset = 0;
 +#ifndef QTEST_TIZEN
 +            memset(s->vaddr, 0, MARUTUNER_MEM_SIZE);
 +#endif
 +            break;
 +        }
 +
 +        /* stop dma after the interrupt thread of kernel wakes up section thread */
 +        if (s->fe.is_streaming == false || s->doing_dma == 0) {
 +            s->hw_ptr_offset = 0;
 +            memset(s->vaddr, 0, MARUTUNER_MEM_SIZE);
 +            LOG_INFO("(%s) thread stopped\n", __func__);
 +            continue;
 +        }
 +
 +        /*
 +         * XXX : re-starting workaround
 +         * When gstreamer demux plugin works with frontend plugin independently or faster,
 +         * second time play already has previous frontend status like MARUTUNER_FE_HAS_TS.
 +         * So, this is processed as error, but it is no problem as demux send start cmd again.
 +         * Of course, we can handle to do not close ts file, this is not our goal.
 +         */
 +        if (s->doing_dma && !(s->fe.tsfile)) {
 +            LOG_TRACE("(%s) there is no opened ts file\n", __func__);
 +            marutuner_raise_intr(s, MARUTUNER_ERR_INT);
 +            continue;
 +        }
 +
 +        int read_cnt = 0;
 +        int total_cnt = 0;
 +        int todo = MARUTUNER_MEM_SIZE;
 +        while (todo > 0) {
 +            read_cnt = fread(s->vaddr + read_cnt, 1, todo, s->fe.tsfile);
 +            if (read_cnt < todo) {
 +                if (feof(s->fe.tsfile)) {
 +                    LOG_TRACE("(%s) End of TS file\n", __func__);
 +                    if (fseek(s->fe.tsfile, 0, SEEK_SET) < 0) {
 +                        LOG_TRACE("(%s) Failed to fseek\n", __func__);
 +                    }
 +                }
 +            }
 +            todo -= read_cnt;
 +            total_cnt += read_cnt;
 +            //LOG_TRACE("(%s) total_cnt = %d, todo = %d\n", __func__, total_cnt, todo);
 +        }
 +
 +        s->hw_ptr_offset = total_cnt;
 +        qemu_mutex_unlock(&s->section_mutex);
 +        usleep(5000); // temporary time
 +        qemu_mutex_lock(&s->section_mutex);
 +        marutuner_raise_intr(s, MARUTUNER_DMA_COMPLETE_INT);
 +    }
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +    LOG_TRACE("(%s) finished\n", __func__);
 +    return NULL;
 +}
 +
 +static void *marutuner_tsdemux_th(void *thread_param)
 +{
 +    MaruTunerState *s = (MaruTunerState *)thread_param;
 +    struct pid_filter *filter;
 +    AVStream *st;
 +    AVPacket pkt;
 +    int ret;
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +
 +    LOG_INFO("tsdemux thread starting...\n");
 +    av_init_packet(&pkt);
 +    pkt.data = NULL;
 +    pkt.size = 0;
 +
 +    while (1) {
 +        LOG_TRACE("(%s) waiting...\n", __func__);
 +        qemu_cond_wait(&s->tsdemux_th_cond, &s->tsdemux_mutex);
 +        qemu_mutex_unlock(&s->tsdemux_mutex);
 +        LOG_TRACE("(%s) woke up\n", __func__);
 +
 +        if (s->destroying == true) {
 +            LOG_TRACE("(%s) destroying...\n", __func__);
 +            break;
 +        }
 +
 +        while (1) {
 +            if (maru_tuner_dec_queue_is_full(s->decoder_state)) {
 +                /* we should find optimized sleep time */
 +                usleep(10000);
 +                continue;
 +            }
 +
 +            qemu_mutex_lock(&s->tsdemux_mutex);
 +            if (s->fe.is_streaming  == false || s->doing_filtering == 0) {
 +                LOG_TRACE("(%s) filtering stop\n", __func__);
 +                break;
 +            }
 +
 +
 +            ret = av_read_frame(s->fmt_ctx, &pkt);
 +            if (ret< 0) {
 +                if (ret == AVERROR(EAGAIN)) {
 +                    LOG_SEVERE("(%s) av_read_frame EAGAIN error\n", __func__);
 +                    break;
 +                }
 +
 +                if (ret == AVERROR_EOF) {
 +                    LOG_INFO("(%s) End of TS file\n", __func__);
 +#if REPLAY_ON_EOF
 +                    ret = avformat_seek_file(s->fmt_ctx, -1, INT64_MIN, 0, INT64_MAX, 0);
 +                    if (ret < 0) {
 +                        //FIXME: infinite loop??
 +                        LOG_SEVERE("(%s) failted to seek to start position\n");
 +                        break;
 +                    }
 +                    qemu_mutex_unlock(&s->tsdemux_mutex);
 +                    continue;
 +#endif
 +                }
 +                s->doing_filtering = 0;
 +                break;
 +            }
 +
 +            /*
 +             * filtering packet for PID
 +             */
 +            QLIST_FOREACH(filter, &s->filters_head, entries) {
 +                //LOG_TRACE("(%s:%d) start decode for filter->pid:%d filter->sid = %d pkt.streamidx:%d\n", __func__, __LINE__, filter->pid, filter->stream_idx, pkt.stream_index);
 +                if (filter->enabled == 1 && filter->stream_idx == pkt.stream_index) {
 +                    //LOG_TRACE("(%s:%d) start decode for filter->pid:%d\n", __func__, __LINE__, filter->pid);
 +                    st = s->fmt_ctx->streams[filter->stream_idx];
 +                    maru_tuner_dec_decode_pkt(s->decoder_state, st, &pkt);
 +                }
 +            }
 +
 +            qemu_mutex_unlock(&s->tsdemux_mutex);
 +        }
 +#if 0
 +        /* flush cached frames */
 +        pkt.data = NULL;
 +        pkt.size = 0;
 +        do {
 +            maru_tuner_dec_decode_pkt(&got_frame);
 +        } while (got_frame);
 +#endif
 +    }
 +
 +    LOG_INFO("(%s) finished\n", __func__);
 +
 +    return NULL;
 +}
 +
 +static void marutuner_threads_init(MaruTunerState *s)
 +{
 +    s->destroying = false;
 +    qemu_thread_create(&s->section_th, "marutuner_section_th", marutuner_section_th, (void *)s,
 +            QEMU_THREAD_JOINABLE);
 +    qemu_thread_create(&s->tsdemux_th, "marutuner_tsdemux_th", marutuner_tsdemux_th, (void *)s,
 +            QEMU_THREAD_JOINABLE);
 +}
 +
 +int marutuner_get_tuned_info(struct tune_info *info)
 +{
 +    assert(info != NULL);
 +    // TODO have to lock with some lock
 +    // otherwise, gettor will get imperfect data
 +
 +    info->is_tuned = g_current_tune.is_tuned;
 +    info->frequency = g_current_tune.frequency;
 +    info->modulation = g_current_tune.modulation;
 +    info->is_streaming = g_current_tune.is_streaming;
 +    info->system = g_current_tune.system;
 +    info->country = g_current_tune.country;
 +    info->playmode = g_current_tune.playmode;
 +    strcpy(info->map_table_path, ts_mapping_table_path);
 +
 +    return info->is_tuned? 0 : -1;
 +}
 +
 +static int marutuner_set_tuned_info(MaruTunerState *s, bool is_tuned)
 +{
 +    // TODO have to lock with some lock
 +    if (s->id != 0)
 +        return 0;
 +
 +    g_current_tune.is_tuned = is_tuned;
 +    g_current_tune.is_streaming= s->fe.is_streaming;
 +    g_current_tune.frequency = s->fe.frequency;
 +    g_current_tune.modulation = s->fe.modulation;
 +    g_current_tune.system = s->cfg.system;
 +    g_current_tune.country = s->cfg.country;
 +    g_current_tune.playmode = s->cfg.playmode;
 +
 +    qemu_bh_schedule(s->set_tune_info_bh);
 +    LOG_TRACE("(%s) set g_current_tune info freq:%lld, mod:%lld\n",
 +            __func__, g_current_tune.frequency, g_current_tune.modulation);
 +    return 0;
 +}
 +
 +int marutuner_toggle_stream(int devnum, struct tune_info *info, bool on)
 +{
 +    MaruTunerState *s = NULL;
 +    assert(info != NULL);
 +    assert(info->modulation < MAX_MODULATION);
 +    //TODO devnum should be get as parameters
 +    assert(devnum == 0);
 +    LOG_INFO("(%s) toggle : %s on current[stream on?:%s freq:%lld mod:%d]\n"
 +         , __func__, on? "on":"off"
 +         , info->is_streaming ? "on": "off"
 +         , info->frequency, info->modulation);
 +
 +    pthread_mutex_lock(&g_tuners_lck);
 +    s = find_tuner_device(devnum);
 +    if (s == NULL || s->destroying == true)
 +        goto out;
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    if (s->fe.frequency == info->frequency &&
 +            s->fe.modulation == info->modulation) {
 +        s->fe.is_streaming = on;
 +        marutuner_set_tuned_info(s, true);
 +    }
 +    if (s->doing_filtering == 1)
 +        qemu_cond_signal(&s->tsdemux_th_cond);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    if (s->doing_dma == 1)
 +        qemu_cond_signal(&s->section_th_cond);
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +out:
 +    pthread_mutex_unlock(&g_tuners_lck);
 +    return 0;
 +}
 +
 +int marutuner_switch_ts(int devnum, struct tune_info *info)
 +{
 +    MaruTunerState *s = NULL;
 +    LOG_TRACE("(%s) reload avstream \n",__func__);
 +
 +    assert(info != NULL);
 +    assert(info->modulation < MAX_MODULATION);
 +    //TODO devnum should be get as parameters
 +    assert(devnum == 0);
 +
 +    pthread_mutex_lock(&g_tuners_lck);
 +    s = find_tuner_device(devnum);
 +    if (s == NULL ||s->destroying == true)
 +        goto out;
 +
 +    //section thread , demux thread have to be stopped at some point
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    if (s->fe.frequency == info->frequency &&
 +            s->fe.modulation == info->modulation) {
 +        switch_avstream(s);
 +        marutuner_set_tuned_info(s, true);
 +    }
 +
 +    if (s->doing_filtering)
 +        qemu_cond_signal(&s->tsdemux_th_cond);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +
 +    //TODO  here any new command can come through mmio , will that be any probs??
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    qemu_cond_signal(&s->section_th_cond);
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +out:
 +    pthread_mutex_unlock(&g_tuners_lck);
 +    return 0;
 +}
 +
 +static int playmode_set_to_ts(MaruTunerState *s)
 +{
 +    int ret;
 +
 +    assert(!s->fmt_ctx);
 +    //print_tuner_state(s);
 +    LOG_TRACE("(%s) fe_status:%d, is_tuned:%d\n", __func__, s->fe_status, g_current_tune.is_tuned);
 +
 +    /* XXX : 'is_tuned' and 'fe_status' is the same thing? */
 +    if (s->fe_status != MARUTUNER_FE_HAS_TS) {
 +        return 0;
 +    }
 +
 +    if ((ret = init_avstream(s)) < 0) {
 +        LOG_SEVERE("(%s) failed to init_avstream\n", __func__);
 +        goto out;
 +    }
 +
 +    ret = enable_filters_and_decoder(s);
 +    if (ret < 0) {
 +        LOG_SEVERE("(%s) failed to enable fileter and decoder\n", __func__);
 +        free_avstream(s, false);
 +    } else if (ret > 0) {
 +        s->doing_filtering = 1;
 +        qemu_cond_signal(&s->tsdemux_th_cond);
 +    } // don't care ret == 0
 +
 +out:
 +    return ret;
 +}
 +
 +static int playmode_set_to_stillimg(MaruTunerState *s)
 +{
 +    //print_tuner_state(s);
 +
 +    free_avstream(s, false);
 +    s->fe.is_streaming = true; //section thread should not stop
 +    s->doing_filtering = 0; //tsdemux thread should stop
 +
 +    return 0;
 +}
 +
 +int marutuner_switch_playmode(int devnum, int playmode)
 +{
 +    MaruTunerState *s = NULL;
 +    int ret = 0;
 +
 +    pthread_mutex_lock(&g_tuners_lck);
 +    s = find_tuner_device(devnum);
 +    if (s == NULL ||s->destroying == true) {
 +        qemu_mutex_unlock(&s->tsdemux_mutex);
 +        return -1;
 +    }
 +
 +    assert(playmode == MARUTUNER_CONFIG_PLAYMODE_TS ||
 +           playmode == MARUTUNER_CONFIG_PLAYMODE_STILL);
 +    LOG_INFO("switching play mode %s -> %s\n",
 +         config_playmode_list[s->cfg.playmode].name,
 +         config_playmode_list[playmode].name);
 +
 +    /* if not changed, just ignore */
 +    if (s->cfg.playmode == playmode) {
 +        goto out;
 +    }
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    if (playmode == MARUTUNER_CONFIG_PLAYMODE_TS) {
 +        ret = playmode_set_to_ts(s);
 +    } else {
 +        ret = playmode_set_to_stillimg(s);
 +    }
 +    if (ret < 0) {
 +        LOG_INFO("playmode switching failed\n");
 +        qemu_mutex_unlock(&s->tsdemux_mutex);
 +        goto out;
 +    }
 +
 +    s->cfg.playmode = playmode;
 +    marutuner_set_tuned_info(s, g_current_tune.is_tuned);
 +    maru_tuner_dec_set_stillimage(s->decoder_state, playmode);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +
 +out:
 +    pthread_mutex_unlock(&g_tuners_lck);
 +    return ret;
 +}
 +
 +int marutuner_set_table_file(const char* path)
 +{//FIXME SAFE?
 +    strncpy(ts_mapping_table_path, path, MAX_PATH_LEN);
 +    LOG_TRACE("(%s) ts_mapping_table_path : %s\n", __func__, ts_mapping_table_path);
 +    return 0;
 +}
 +
 +static uint64_t marutuner_reg_read(void *opaque,
 +        hwaddr addr,
 +        unsigned size)
 +{
 +    uint32_t ret = 0;
 +    MaruTunerState *s = (MaruTunerState *)opaque;
 +
 +    switch (addr & 0xFF) {
 +    case MARUTUNER_FE_STATUS:
 +        //LOG_TRACE("(%s) MARUTUNER_FE_STATUS\n", __func__);
 +        ret = s->fe_status;
 +        break;
 +
 +    case MARUTUNER_FE_FREQ:
 +        LOG_TRACE("(%s) MARUTUNER_FE_FREQ\n", __func__);
 +        ret = s->fe.frequency;
 +        break;
 +
 +    case MARUTUNER_FE_MOD:
 +        LOG_TRACE("(%s) MARUTUNER_FE_MOD\n", __func__);
 +        ret = s->fe.modulation;
 +        break;
 +
 +    case MARUTUNER_FE_GET_SYSTEM:
 +        LOG_TRACE("(%s) MARUTUNER_FE_GET_SYSTEM\n", __func__);
 +        ret = s->cfg.system;
 +        break;
 +
 +    case MARUTUNER_FE_GET_ID:
 +        LOG_TRACE("(%s) MARUTUNER_FE_GET_ID\n", __func__);
 +        ret = s->id;
 +        break;
 +
 +    case MARUTUNER_START:
 +        //LOG_TRACE("(%s) MARUTUNER_START\n", __func__);
 +        ret = s->doing_dma;
 +        break;
 +
 +    case MARUTUNER_INT:
 +        //LOG_TRACE("(%s) MARUTUNER_INT\n");
 +        qemu_mutex_lock(&s->section_mutex);
 +        ret = s->irq;
 +        if (ret) {
 +            pci_set_irq(&s->dev, 0);
 +            s->irq = 0;
 +        }
 +        qemu_mutex_unlock(&s->section_mutex);
 +        break;
 +
 +    case MARUTUNER_HWPTR:
 +        ret = s->hw_ptr_offset;
 +        //LOG_TRACE("(%s) MARUTUNER_HWPTR, hw_ptr_offset = %d\n", __func__, s->hw_ptr_offset);
 +        break;
 +
 +    case MARUTUNER_ATV_GET_STATUS:
 +        //LOG_TRACE("(%s) MARUTUNER_ATV_GET_STATUS\n", __func__);
 +        ret = s->fe_status;
 +        break;
 +
 +    case MARUTUNER_FE_RESET:
 +    case MARUTUNER_FE_TUNE:
 +    case MARUTUNER_SETDMA:
 +        break;
 +
 +    default:
 +        LOG_SEVERE("(%s) invalid cmd. register addr = %d\n", __func__, (int)addr);
 +        break;
 +    }
 +
 +    return ret;
 +}
 +
 +static void marutuner_fe_reset(MaruTunerState *s)
 +{
 +    qemu_mutex_lock(&s->section_mutex);
 +    s->fe.frequency = 0;
 +    s->fe.modulation = MAX_MODULATION;
 +    s->fe_status = MARUTUNER_FE_TUNE_FAILED;
 +    if (s->fe.tsfile) {
 +        fclose(s->fe.tsfile);
 +        s->fe.tsfile = NULL;
 +    }
 +    s->doing_dma = 0;
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    //free_avstream(s, true);
 +    free_avstream(s, false);
 +    if (QLIST_EMPTY(&s->filters_head)) {
 +        s->doing_filtering = 0;
 +    }
 +    if (s->fe.ts_filename) {
 +        free(s->fe.ts_filename);
 +        s->fe.ts_filename = NULL;
 +    }
 +    dump_filter_list(s);
 +    marutuner_set_tuned_info(s, false);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +}
 +
 +static void marutuner_fe_freq(MaruTunerState *s, uint64_t val)
 +{
 +    s->fe.frequency = val;
 +}
 +
 +static void marutuner_fe_mod(MaruTunerState *s, uint64_t val)
 +{
 +    s->fe.modulation = val;
 +}
 +
 +static void marutuner_fe_tune(MaruTunerState *s)
 +{
 +    int ret;
 +
 +    /* because marutuner opens the table for each time, don't need sync with ECP */
 +    s->table = fopen(ts_mapping_table_path, "rb");
 +    if (!s->table) {
 +        s->fe_status = MARUTUNER_FE_TUNE_FAILED;
 +        LOG_TRACE("(%s) table file open failed\n", __func__);
 +        return;
 +    }
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    if (s->fe.tsfile) {
 +        fclose(s->fe.tsfile);
 +        s->fe.tsfile = NULL;
 +    }
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    s->doing_filtering = 0;
 +    free_avstream(s, false);
 +
 +    s->fe_status = get_mapped_ts_file(s, s->table, &s->fe);
 +    if (s->fe_status != MARUTUNER_FE_HAS_TS) {
 +        qemu_mutex_unlock(&s->tsdemux_mutex);
 +        goto out;
 +    }
 +
 +    /* libav and decoder init for each playmode */
 +    if (s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_TS) {
 +        if (maru_tuner_dec_set_stillimage(s->decoder_state, false) < 0) {
 +            LOG_SEVERE("(%s) stillimage setting failed(playmode:%s)\n",
 +                    __func__,
 +                    s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_TS ? "TS" : "STILL");
 +            qemu_mutex_unlock(&s->tsdemux_mutex);
 +            goto out;
 +        }
 +
 +        if (init_avstream(s) < 0) {
 +            LOG_SEVERE("(%s) failed to init avstream\n", __func__);
 +            s->fe_status = MARUTUNER_FE_TUNE_FAILED;
 +            qemu_mutex_unlock(&s->tsdemux_mutex);
 +            goto out;
 +        }
 +
 +        if ((ret = enable_filters_and_decoder(s)) < 0) {
 +            LOG_SEVERE("(%s) failed to enable fileter and decoder\n", __func__);
 +            s->fe_status = MARUTUNER_FE_TUNE_FAILED;
 +            free_avstream(s, false);
 +            qemu_mutex_unlock(&s->tsdemux_mutex);
 +            goto out;
 +        }
 +        if (ret > 0) {
 +            LOG_TRACE("(%s) wakeup tsdemux thread\n", __func__);
 +            s->doing_filtering = 1;
 +            qemu_cond_signal(&s->tsdemux_th_cond);
 +        }
 +    } else if (s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_STILL) {
 +        if (maru_tuner_dec_set_stillimage(s->decoder_state, true) < 0) {
 +            LOG_SEVERE("(%s) stillimage setting failed(playmode:%s)\n",
 +                    __func__,
 +                    s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_TS ? "TS" : "STILL");
 +            qemu_mutex_unlock(&s->tsdemux_mutex);
 +            goto out;
 +        }
 +    } else { //undefined playmode
 +        LOG_SEVERE("(%s) undefined playmode\n", __func__);
 +        qemu_mutex_unlock(&s->tsdemux_mutex);
 +        goto out;
 +    }
 +
 +    marutuner_set_tuned_info(s, true);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +
 +    /* if demux already started, threads should wakeup */
 +    qemu_mutex_lock(&s->section_mutex);
 +    if (s->doing_dma == 1) {
 +        LOG_TRACE("(%s) wakeup section thread\n", __func__);
 +        qemu_cond_signal(&s->section_th_cond);
 +    }
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +out:
 +    fclose(s->table);
 +    s->table = NULL;
 +}
 +
 +static void marutuner_setdma(MaruTunerState *s, uint64_t val)
 +{
 +    // XXX : is 'val' ok? should init memory_region_init?
++    s->vaddr = qemu_map_ram_ptr(NULL, (ram_addr_t)val);
 +    memset(s->vaddr, 0, MARUTUNER_MEM_SIZE);
 +}
 +
 +static int marutuner_start_section(MaruTunerState *s, uint64_t val)
 +{
 +    int ret = -1;
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    if (val != s->doing_dma) {
 +        LOG_TRACE("(%s) section %s\n", __func__, (val == 1 ? "START" : "STOP"));
 +    }
 +    s->doing_dma = val;
 +    if (s->doing_dma) {
 +        if (s->fe_status == MARUTUNER_FE_HAS_TS) {
 +            //LOG_TRACE("(%s) wakeup section thread\n", __func__);
 +#ifndef QTEST_TIZEN
 +            qemu_cond_signal(&s->section_th_cond);
 +#endif
 +            ret = 0;
 +        } else {
 +            LOG_TRACE("(%s) thread will be woken up when frontend locked\n", __func__);
 +        }
 +    }
 +    qemu_mutex_unlock(&s->section_mutex);
 +
 +    return ret;
 +}
 +
 +static int marutuner_start_pid_filter(MaruTunerState *s, uint64_t val)
 +{
 +    int ret = 0;
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    if (add_pid_filter(s, val) < 0) {
 +        qemu_mutex_unlock(&s->tsdemux_mutex);
 +        return -1;
 +    }
 +
 +    /* if the frontend is already tuned */
 +    if (s->fe_status == MARUTUNER_FE_HAS_TS) {
 +        LOG_TRACE("(%s) frontend already tuned. playmode:%s\n",
 +                __func__,
 +                s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_TS ? "TS" : "STILL");
 +        if (s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_TS) {
 +            /* decoder playmode is already set */
 +            if ((ret = enable_filters_and_decoder(s)) < 0) {
 +                qemu_mutex_unlock(&s->tsdemux_mutex);
 +                return ret;
 +            }
 +            if (ret > 0) {
 +                s->doing_filtering = 1;
 +                LOG_TRACE("(%s) wakeup ts demux thread\n", __func__);
 +#ifndef QTEST_TIZEN
 +                qemu_cond_signal(&s->tsdemux_th_cond);
 +#endif
 +            } else {
 +                LOG_TRACE("(%s) start filtering with pid:%d but there is no valid stream\n", __func__, val);
 +            }
 +        } else if (s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_STILL) {
 +            /* A new pid filtering adding don't need to wakeup tsdemux thread,
 +             * therefore, we ignore this filtering request.
 +             *
 +             * And because the playmode is already set when it is tuned,
 +             * don't need anything to do here.
 +             */
 +            ;
 +        } else { //undefined playmode
 +            LOG_SEVERE("(%s) undefined playmode\n", __func__);
 +            ret = -1;
 +        }
 +    } else {
 +        /*
 +         * If frontend is not tuned yet, we can't get any stream info
 +         * In this case, we only add a filter for the pid
 +         */
 +        LOG_TRACE("(%s) erontend does not tuned yet\n", __func__);
 +        ret = -1;
 +
 +        dump_filter_list(s);
 +    }
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +
 +    return ret;
 +}
 +
 +static void marutuner_stop_pid_filter(MaruTunerState *s, uint64_t val)
 +{
 +    struct pid_filter *filter, *next;
 +    AVStream *st;
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    QLIST_FOREACH_SAFE(filter, &s->filters_head, entries, next) {
 +        if (filter->pid == val) {
 +            LOG_TRACE("(%s) MARUTUNER_STOP_PID_FILTER: find matched filter(pid=%d, stream_idx=%d)\n",
 +                    __func__, filter->pid, filter->stream_idx);
 +            if (s->cfg.playmode == MARUTUNER_CONFIG_PLAYMODE_TS) {
 +                if (s->fmt_ctx && filter->stream_idx != -1) {
 +                    st = s->fmt_ctx->streams[filter->stream_idx];
 +                    maru_tuner_dec_deinit_ctx(s->decoder_state, st);
 +                }
 +            }
 +            QLIST_REMOVE(filter, entries);
 +            free(filter);
 +        }
 +    }
 +
 +    /*
 +     * we just stop the tsdemux thread here.
 +     * fmt_ctx is freed on frontend reset.
 +     */
 +    if (QLIST_EMPTY(&s->filters_head)) {
 +        s->doing_filtering = 0;
 +    }
 +    dump_filter_list(s);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +}
 +
 +static void marutuner_reg_write(void *opaque,
 +                            hwaddr addr,
 +                            uint64_t val,
 +                            unsigned size)
 +{
 +    MaruTunerState *s = (MaruTunerState *)opaque;
 +
 +    switch (addr & 0xFF) {
 +    case MARUTUNER_FE_RESET:
 +        LOG_TRACE("(%s) MARUTUNER_FE_RESET: val = %lld\n", __func__, val);
 +        marutuner_fe_reset(s);
 +        break;
 +
 +    case MARUTUNER_FE_FREQ:
 +        LOG_TRACE("(%s) MARUTUNER_FE_FREQ: val = %lld\n", __func__, val);
 +        marutuner_fe_freq(s, val);
 +        break;
 +
 +    case MARUTUNER_FE_MOD:
 +        LOG_TRACE("(%s) MARUTUNER_FE_MOD: val = %lld\n", __func__, val);
 +        marutuner_fe_mod(s, val);
 +        break;
 +
 +    case MARUTUNER_FE_TUNE:
 +        LOG_TRACE("(%s) MARUTUNER_FE_TUNE: val = %lld\n", __func__, val);
 +        marutuner_fe_tune(s);
 +        break;
 +
 +    case MARUTUNER_SETDMA:
 +        LOG_TRACE("(%s) MARUTUNER_SETDMA: val = %lld\n", __func__, val);
 +        marutuner_setdma(s, val);
 +        break;
 +
 +    case MARUTUNER_START:
 +        marutuner_start_section(s, val);
 +        break;
 +
 +    case MARUTUNER_START_PID_FILTER:
 +        LOG_TRACE("(%s) MARUTUNER_START_PID_FILTER: val = %lld\n", __func__, val);
 +        marutuner_start_pid_filter(s, val);
 +        break;
 +
 +    case MARUTUNER_STOP_PID_FILTER:
 +        LOG_TRACE("(%s) MARUTUNER_STOP_PID_FILTER: val = %lld\n", __func__, val);
 +        marutuner_stop_pid_filter(s, val);
 +        break;
 +
 +    case MARUTUNER_ATV_SET_TUNE:
 +        LOG_TRACE("(%s) MARUTUNER_ATV_SET_TUNE: val = %lld\n", __func__, val);
 +        marutuner_tune_atv(s, (unsigned int)val);
 +        break;
 +
 +    case MARUTUNER_FE_STATUS:
 +    case MARUTUNER_INT:
 +    case MARUTUNER_HWPTR:
 +    case MARUTUNER_FE_GET_SYSTEM:
 +        LOG_TRACE("(%s) ETC(0x%02llx): val = %lld\n", __func__, addr, val);
 +        break;
 +
 +    default:
 +        LOG_SEVERE("(%s) invalid cmd. register addr = %d\n", __func__, (int)addr);
 +        break;
 +    }
 +}
 +
 +static int set_tuner_info(MaruTunerState* s)
 +{
 +    if (!s->prop_table) {
 +        LOG_SEVERE("No table file path\n");
 +        return -1;
 +    }
 +
 +    strncpy(ts_mapping_table_path, s->prop_table, MAX_PATH_LEN);
 +
 +    if (s->prop_system)
 +        s->cfg.system = get_config_value(config_system_list, s->prop_system);
 +    else //default system
 +        s->cfg.system = MARUTUNER_CONFIG_SYSTEM_ATSC;
 +
 +    if (s->cfg.system == MARUTUNER_CONFIG_SYSTEM_ATSC) {
 +        if (s->prop_country == NULL) {
 +            LOG_SEVERE("invalid tuner configure: country has not specified even system is ATSC\n", __func__);
 +            return -1;
 +        }
 +        s->cfg.country = get_config_value(config_country_list, s->prop_country);
 +    } else {
 +        s->cfg.country = -1;
 +    }
 +
 +    if (s->prop_playmode)
 +        s->cfg.system = get_config_value(config_playmode_list, s->prop_playmode);
 +    else //default playmode
 +        s->cfg.playmode = MARUTUNER_CONFIG_PLAYMODE_STILL;
 +
 +    marutuner_set_tuned_info(s, false);
 +
 +    LOG_INFO("tuner configurations: sys:%s country:%s playmode:%s table:%s\n",
 +         config_system_list[s->cfg.system].name,
 +         (s->cfg.country != -1) ? config_country_list[s->cfg.country].name : "-",
 +         config_playmode_list[s->cfg.playmode].name,
 +         ts_mapping_table_path);
 +
 +    return 0;
 +}
 +
 +static const MemoryRegionOps marutuner_mmio_ops = {
 +    .read = marutuner_reg_read,
 +    .write = marutuner_reg_write,
 +    .endianness = DEVICE_LITTLE_ENDIAN,
 +};
 +
 +/*  for sake of no lock , copy to local variable.
 + *
 + * XXX : need not check initial status
 + * When the frontend is reset, the parameters initialized.
 + * And, finally, marutuner_get_tuned_info check this initialized modulation
 + */
 +#define TUNER_DATA_SIZE 4125
 +static void marutuner_deliver_tuned_info(void *opaque)
 +{
 +    char data[TUNER_DATA_SIZE];
 +    char cmd[10] = {0};
 +
 +    strcpy(cmd, "TUNER_DTV");
 +
 +    if (strlen(g_current_tune.map_table_path) < MAX_PATH_LEN) {
 +        sprintf(data, "%d:%d:%d:%d:%d:%d:%s",
 +                g_current_tune.is_streaming, g_current_tune.frequency,
 +                g_current_tune.modulation, g_current_tune.system,
 +                g_current_tune.country, g_current_tune. playmode,
 +                g_current_tune.map_table_path);
 +    }
 +
 +    make_send_device_ntf(cmd, MSG_GROUP_STATUS, 221, data);
 +}
 +
 +static void marutuner_irq(void *opaque)
 +{
 +        MaruTunerState *s = (MaruTunerState *)opaque;
 +
 +        qemu_mutex_lock(&s->section_mutex);
 +        if (s->irq) {
 +                pci_set_irq(&s->dev, 1);
 +        }
 +        qemu_mutex_unlock(&s->section_mutex);
 +}
 +
 +static void pci_create_marutuner_decoder(PCIBus *bus, MaruTunerState *s)
 +{
 +    PCIDevice *dev = NULL;
 +    MaruTunerDecoderState *decoder_state = NULL;
 +
 +    g_stillimg_dir = s->prop_stillimg;
 +    g_wsi_name = s->prop_wsi;
 +    dev = pci_create_simple(bus, -1, TUNER_DECODER_DEVICE_NAME);
 +    decoder_state = DO_UPCAST(MaruTunerDecoderState, dev, dev);
 +    s->decoder_state = decoder_state;
 +}
 +
 +static int marutuner_initfn(PCIDevice *dev)
 +{
 +    PCIBus *bus = PCI_BUS(dev->bus);
 +    MaruTunerState *s = DO_UPCAST(MaruTunerState, dev, dev);
 +    uint8_t *pci_conf = s->dev.config;
 +
 +    LOG_INFO("device initializing...\n");
 +
 +    pci_create_marutuner_decoder(bus, s);
 +
 +    pci_config_set_interrupt_pin(pci_conf, 2);
 +
 +    memory_region_init_io(&s->mmio, OBJECT(s), &marutuner_mmio_ops, s,
 +                            "marutuner-mmio", MARUTUNER_REG_SIZE);
 +
 +    //pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
 +    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
 +
 +    QLIST_INIT(&s->filters_head);
 +
 +    qemu_mutex_init(&s->section_mutex);
 +    qemu_cond_init(&s->section_th_cond);
 +
 +    qemu_mutex_init(&s->tsdemux_mutex);
 +    qemu_cond_init(&s->tsdemux_th_cond);
 +
 +    marutuner_threads_init(s);
 +
 +    s->destroying = false;
 +    s->qemu_bh = qemu_bh_new(marutuner_irq, s);
 +    s->set_tune_info_bh = qemu_bh_new(marutuner_deliver_tuned_info, s);
 +
 +    s->id = g_tuners_num++;
 +    /* register all libav formats and codecs */
 +    av_register_all();
 +
 +    if (set_tuner_info(s) < 0)
 +        goto error;
 +
 +    add_tuner_device(s);
 +    LOG_INFO("device initialized successfully\n");
 +
 +    return 0;
 +
 +error:
 +    qemu_bh_delete(s->qemu_bh);
 +    qemu_bh_delete(s->set_tune_info_bh);
 +    s->destroying = true;
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    qemu_cond_signal(&s->section_th_cond);
 +    qemu_mutex_unlock(&s->section_mutex);
 +    qemu_thread_join(&s->section_th);
 +    qemu_cond_destroy(&s->section_th_cond);
 +    qemu_mutex_destroy(&s->section_mutex);
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    qemu_cond_signal(&s->tsdemux_th_cond);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +    qemu_thread_join(&s->tsdemux_th);
 +    qemu_cond_destroy(&s->tsdemux_th_cond);
 +    qemu_mutex_destroy(&s->tsdemux_mutex);
 +
 +    LOG_INFO("device initialization failed\n");
 +
 +    return -1;
 +}
 +
 +static void marutuner_exitfn(PCIDevice *dev)
 +{
 +    MaruTunerState *s = DO_UPCAST(MaruTunerState, dev, dev);
 +
 +    cleanup_filters(s);
 +    qemu_bh_delete(s->qemu_bh);
 +    qemu_bh_delete(s->set_tune_info_bh);
 +    s->destroying = true;
 +
 +    qemu_mutex_lock(&s->section_mutex);
 +    qemu_cond_signal(&s->section_th_cond);
 +    qemu_mutex_unlock(&s->section_mutex);
 +    qemu_thread_join(&s->section_th);
 +    qemu_cond_destroy(&s->section_th_cond);
 +    qemu_mutex_destroy(&s->section_mutex);
 +
 +    qemu_mutex_lock(&s->tsdemux_mutex);
 +    qemu_cond_signal(&s->tsdemux_th_cond);
 +    qemu_mutex_unlock(&s->tsdemux_mutex);
 +    qemu_thread_join(&s->tsdemux_th);
 +    qemu_cond_destroy(&s->tsdemux_th_cond);
 +    qemu_mutex_destroy(&s->tsdemux_mutex);
 +
 +    del_tuner_device(s);
 +
 +    LOG_INFO("tuner device was released.\n");
 +}
 +
 +static Property maru_tuner_props[] = {
 +    DEFINE_PROP_STRING("system", MaruTunerState, prop_system),
 +    DEFINE_PROP_STRING("country", MaruTunerState, prop_country),
 +    DEFINE_PROP_STRING("playmode", MaruTunerState, prop_playmode),
 +    DEFINE_PROP_STRING("stillimg", MaruTunerState, prop_stillimg),
 +    DEFINE_PROP_STRING("table", MaruTunerState, prop_table),
 +    DEFINE_PROP_STRING("wsi", MaruTunerState, prop_wsi),
 +    DEFINE_PROP_END_OF_LIST(),
 +};
 +
 +static void marutuner_class_init(ObjectClass *klass, void *data)
 +{
 +    DeviceClass *dc = DEVICE_CLASS(klass);
 +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 +
 +#ifdef QTEST_TIZEN
 +    k->init = qtest_tuner_initfn;
 +#else
 +    k->init = marutuner_initfn;
 +#endif
 +    k->exit = marutuner_exitfn;
 +    k->vendor_id = PCI_VENDOR_ID_TIZEN;
 +    k->device_id = PCI_DEVICE_ID_VIRTUAL_TUNER;
 +    k->class_id = PCI_CLASS_OTHERS;
 +    dc->props = maru_tuner_props;
 +    dc->desc = "MARU virtual tuner device for Tizen emulator";
 +}
 +
 +static TypeInfo marutuner_info = {
 +    .name = MARUTUNER_DEV_NAME,
 +    .parent = TYPE_PCI_DEVICE,
 +    .instance_size = sizeof(MaruTunerState),
 +    .class_init = marutuner_class_init,
 +};
 +
 +static void tuner_register_types(void)
 +{
 +    type_register_static(&marutuner_info);
 +}
 +
 +type_init(tuner_register_types);
 +
 +
 +
 +/******************************************************************************
 +  functions for only unit test
 +******************************************************************************/
 +#ifdef QTEST_TIZEN
 +#define QTEST_DTV_FREQ1 57000000
 +#define QTEST_DTV_FREQ2 63000000
 +#define QTEST_DTV_FREQ3 69000000
 +#define QTEST_ATV_FREQ 79000000
 +#define QTEST_MOD VSB_8
 +
 +#define QTEST_DTV_VPID 0x11
 +#define QTEST_DTV_APID 0x14
 +
 +/**
 + * @test  UTC_TUNER_TEST02
 + * @sut   UTC_TUNER
 + * @brief Check frequency and modulation setting
 + * @flow  #02-01 set frequency and read the value by mmio command
 + *        #02-02 set modulation and read the value by mmio command
 + * @type  Right
 + * @input tuner context structure, frequency, modulation
 + */
 +static void qtest_tuner_02(MaruTunerState *s)
 +{
 +    /* flow #02-01 */
 +    marutuner_reg_write(s, MARUTUNER_FE_FREQ, QTEST_DTV_FREQ1, 4);
 +    LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST02] #02-01 : %s\n",
 +            marutuner_reg_read(s, MARUTUNER_FE_FREQ, 4) == QTEST_DTV_FREQ1 ? "SUCCESS" : "FAIL");
 +
 +    /* flow #02-02 */
 +    marutuner_reg_write(s, MARUTUNER_FE_MOD, QTEST_MOD, 4);
 +    LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST02] #02-02 : %s\n",
 +            marutuner_reg_read(s, MARUTUNER_FE_MOD, 4) == QTEST_MOD ? "SUCCESS" : "FAIL");
 +}
 +
 +/**
 + * @test  UTC_TUNER_TEST03
 + * @sut   UTC_TUNER
 + * @brief Check frequency and modulation setting
 + * @flow  #03-01 call get_mapped_ts_file with proper freq, mod and ts file
 + *        #03-02 call get_mapped_ts_file with proper freq and mod but nonexistant file
 + *        #03-03 call get_mapped_ts_file with improper freq and mod
 + *        #03-04 call marutuner_tune_atv with proper freq
 + * @type  Right
 + * @input tuner context structure
 + */
 +static void qtest_tuner_03(MaruTunerState *s)
 +{
 +    int ret;
 +
 +    /* flow #03-01 */
 +    s->table = fopen(ts_mapping_table_path, "rb");
 +    if (!s->table) {
 +        LOG_SEVERE("[QTEST][UTC_TUNER:%s] test error! tizen_tuner-test.cfg is required. test will be stopped\n", __func__);
 +        return;
 +    }
 +    s->fe.frequency = QTEST_DTV_FREQ1;
 +    s->fe.modulation = QTEST_MOD;
 +
 +    ret = get_mapped_ts_file(s, s->table, &s->fe);
 +    if (ret == MARUTUNER_FE_HAS_TS) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-01 : SUCCESS\n");
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-01 : FAIL\n");
 +    }
 +    fclose(s->table);
 +
 +    /* flow #03-02 */
 +    s->table = fopen(ts_mapping_table_path, "rb");
 +    if (!s->table) {
 +        LOG_SEVERE("[QTEST][UTC_TUNER:%s] test error! tizen_tuner-test.cfg is required. test will be stopped\n", __func__);
 +        return;
 +    }
 +    s->fe.frequency = QTEST_DTV_FREQ2;
 +    s->fe.modulation = QTEST_MOD;
 +
 +    ret = get_mapped_ts_file(s, s->table, &s->fe);
 +    if (ret == MARUTUNER_FE_HAS_ONLY_PARAM) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-02 : SUCCESS\n");
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-02 : FAIL\n");
 +    }
 +    fclose(s->table);
 +
 +    /* flow #03-03 */
 +    s->table = fopen(ts_mapping_table_path, "rb");
 +    if (!s->table) {
 +        LOG_SEVERE("[QTEST][UTC_TUNER:%s] test error! tizen_tuner-test.cfg is required. test will be stopped\n", __func__);
 +        return;
 +    }
 +    s->fe.frequency = QTEST_DTV_FREQ3;
 +    s->fe.modulation = QTEST_MOD;
 +
 +    ret = get_mapped_ts_file(s, s->table, &s->fe);
 +    if (ret == MARUTUNER_FE_TUNE_FAILED) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-03 : SUCCESS\n");
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-03 : FAIL\n");
 +    }
 +    fclose(s->table);
 +
 +    /* flow #03-04 */
 +    s->fe.frequency = QTEST_ATV_FREQ;
 +    marutuner_tune_atv(s, QTEST_ATV_FREQ);
 +    if (s->fe_status == MARUTUNER_FE_HAS_ONLY_PARAM) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-04 : SUCCESS\n");
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST03] #03-04 : FAIL\n");
 +    }
 +}
 +
 +/**
 + * @test  UTC_TUNER_TEST04
 + * @sut   UTC_TUNER
 + * @brief Test start section after a channel is tuned
 + * @flow  #04-01 call marutuner_start_section
 + * @type  Right
 + * @input tuner context structure
 + */
 +static void qtest_tuner_04(MaruTunerState *s)
 +{
 +    int ret;
 +
 +    s->fe_status = MARUTUNER_FE_HAS_TS;
 +
 +    ret = marutuner_start_section(s, 1);
 +    if (ret < 0) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST04] #04-01 : FAIL\n", __func__);
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST04] #04-01 : SUCCESS\n", __func__);
 +    }
 +}
 +
 +/**
 + * @test  UTC_TUNER_TEST05
 + * @sut   UTC_TUNER
 + * @brief Test start pid filtering for each playmode after a channel is tuned
 + * @flow  #05-01 call marutuner_start_pid_filter with STILL mode
 + *        #05-02 call marutuner_start_pid_filter with TS mode
 + * @type  Right
 + * @input tuner context structure
 + */
 +static void qtest_tuner_05(MaruTunerState *s)
 +{
 +    char tsfile_path[4096] = {0};
 +    char *cpath, *tpath, *bname;
 +    int ret = 0;
 +
 +    cpath = getenv("PWD");
 +    tpath = strdup(cpath);
 +    bname = basename(tpath);
 +    if (strcmp(bname, "qemu") != 0) {
 +        LOG_SEVERE("[QTEST][UTC_TUNER:%s] test error! test must be executed in the qemu directory\n", __func__);
 +    }
 +
 +    sprintf(tsfile_path, "%s/%s/tizen_tuner-test-ts.ts", cpath, "tests");
 +    //LOG_INFO("[QTEST][UTC_TUNER:%s] tsfile : %s\n", __func__, tsfile_path);
 +
 +    s->fe.ts_filename = strdup(tsfile_path);
 +    if (init_avstream(s) < 0) {
 +        LOG_SEVERE("[QTEST][UTC_TUNER:%s] test error! failed libav\n", __func__);
 +        return;
 +    }
 +
 +    s->fe_status = MARUTUNER_FE_HAS_TS;
 +    s->cfg.playmode = MARUTUNER_CONFIG_PLAYMODE_STILL;
 +    ret = marutuner_start_pid_filter(s, QTEST_DTV_VPID);
 +    if (ret < 0) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST05] #05-01 : FAIL\n", __func__);
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST05] #05-01 : SUCCESS\n", __func__);
 +    }
 +
 +    s->cfg.playmode = MARUTUNER_CONFIG_PLAYMODE_TS;
 +    marutuner_start_pid_filter(s, QTEST_DTV_VPID);
 +    if (ret < 0) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST05] #05-02 : FAIL\n", __func__);
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST05] #05-02 : SUCCESS\n", __func__);
 +    }
 +
 +    free(s->fe.ts_filename);
 +    free(tpath);
 +}
 +
 +static int qtest_tuner_initfn(PCIDevice *dev)
 +{
 +    MaruTunerState *s = NULL;
 +
 +    /* INIT TEST */
 +    LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST01] tuner initializing...\n");
 +    if (marutuner_initfn(dev) < 0) {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST01] failed to initialize tuner device.\n");
 +        return 0;
 +    } else {
 +        LOG_INFO("[QTEST][UTC_TUNER][UTC_TUNER_TEST01] tuner initialized\n");
 +    }
 +
 +    s = DO_UPCAST(MaruTunerState, dev, dev);
 +
 +    /* FUNCTION TESTS */
 +    qtest_tuner_02(s);
 +    qtest_tuner_03(s);
 +    qtest_tuner_04(s);
 +    qtest_tuner_05(s);
 +
 +    return 0;
 +}
 +#endif
 +
 +
 +/*#####################################################
 +#######################################################
 +#######DEBUGGING AND TESTING FUNCTIONS#################
 +######SHOULD BE REPLACE WITH ECS/ECP###################
 +#####################################################*/
 +
 +#include "monitor/monitor.h"
 +void tuner_info(Monitor *mon, const QDict *qdict)
 +{
 +    struct tune_info info;
 +
 +    marutuner_get_tuned_info(&info);
 +    monitor_printf(mon, "tuned:%d freq: %ld mod:%d is_stream:%s system:%d country:%d table:%s\n",
 +                   info.is_tuned, (long int)info.frequency, info.modulation, info.is_streaming?"on":"off", info.system, info.country, info.map_table_path);
 +}
 +
 +
 +void tuner_switch(Monitor *mon, const QDict *qdict)
 +{
 +    int ret = 0 ;
 +    struct tune_info info;
 +    const char *tsfile = qdict_get_try_str(qdict, "file");
 +
 +    marutuner_get_tuned_info(&info);
 +
 +    if (info.is_tuned != 1) {
 +        monitor_printf(mon, "not tuned yet\n");
 +        return ;
 +    }
 +    monitor_printf(mon, "current tune: freq: %ld mod:%d is_stream:%s\n",
 +                   (long int)info.frequency, info.modulation, info.is_streaming?"on":"off");
 +    if (tsfile)
 +    {
 +        monitor_printf (mon, "switch ts file to [%s]\n", tsfile);
 +        ret = marutuner_switch_ts(0, &info);
 +    } else {
 +        monitor_printf (mon, "toggle is_stream: %s -> %s\n"
 +                        , info.is_streaming?"on": "off"
 +                        , !info.is_streaming?"on": "off");
 +
 +        ret = marutuner_toggle_stream(0, &info, !info.is_streaming);
 +    }
 +
 +    monitor_printf (mon, "returned : %d\n", ret);
 +}
 +
diff --cc ui/cocoa.m
Simple merge
diff --cc ui/console.c
Simple merge
diff --cc ui/spice-core.c
Simple merge
@@@ -200,9 -196,8 +200,9 @@@ static void qemu_spice_create_one_updat
  
  static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
  {
 +#ifndef CONFIG_MARU
      static const int blksize = 32;
-     int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize;
+     int blocks = DIV_ROUND_UP(surface_width(ssd->ds), blksize);
      int dirty_top[blocks];
      int y, yoff1, yoff2, x, xoff, blk, bw;
      int bpp = surface_bytes_per_pixel(ssd->ds);
  #include <sys/sysctl.h>
  #endif
  
- #include <qemu/mmap-alloc.h>
+ #include "qemu/mmap-alloc.h"
  
 +#ifdef CONFIG_MARU
++#include "qemu/error-report.h"
 +#include "../../tizen/src/emulator_common.h"
 +#endif
 +
  int qemu_get_thread_id(void)
  {
  #if defined(__linux__)
Simple merge
Simple merge
diff --cc vl.c
--- 1/vl.c
--- 2/vl.c
+++ b/vl.c
@@@ -53,16 -52,7 +54,14 @@@ int main(int argc, char **argv
  #define main qemu_main
  #endif /* CONFIG_COCOA */
  
 +#ifdef CONFIG_MARU
 +#ifdef main
 +#undef main
 +#endif
 +int qemu_main(int argc, char **argv, char **envp);
 +#define main qemu_main
 +#endif
  
- #include <glib.h>
  #include "qemu/error-report.h"
  #include "qemu/sockets.h"
  #include "hw/hw.h"
@@@ -97,8 -88,8 +97,9 @@@
  #include "sysemu/dma.h"
  #include "audio/audio.h"
  #include "migration/migration.h"
+ #include "sysemu/cpus.h"
  #include "sysemu/kvm.h"
 +#include "sysemu/hax.h"
  #include "qapi/qmp/qjson.h"
  #include "qemu/option.h"
  #include "qemu/config-file.h"
@@@ -2126,6 -2053,15 +2087,22 @@@ static void select_vgahw(const char *p
      }
  }
  
+ typedef enum DisplayType {
+     DT_DEFAULT,
+     DT_CURSES,
+     DT_SDL,
+     DT_COCOA,
+     DT_GTK,
++#ifdef CONFIG_MARU
++    DT_MARU_REMOTE_SPICE,
++# ifdef CONFIG_QT
++    DT_MARU_QT_ONSCREEN,
++    DT_MARU_QT_OFFSCREEN,
++# endif
++#endif
+     DT_NONE,
+ } DisplayType;
  static DisplayType select_display(const char *p)
  {
      const char *opts;
@@@ -3045,11 -2914,20 +3010,28 @@@ static void set_memory_options(uint64_
      loc_pop(&loc);
  }
  
+ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
+ {
+     GlobalProperty *g;
+     g = g_malloc0(sizeof(*g));
+     g->driver   = qemu_opt_get(opts, "driver");
+     g->property = qemu_opt_get(opts, "property");
+     g->value    = qemu_opt_get(opts, "value");
+     g->user_provided = true;
+     g->errp = &error_fatal;
+     qdev_prop_register_global(g);
+     return 0;
+ }
 +#ifdef CONFIG_MARU
 +// W/A for preserve larger continuous heap for RAM.
 +extern void *preallocated_ram_ptr;
 +extern int preallocated_ram_size;
++// FIXME
++extern bool nodisplay;
 +#endif
++
  int main(int argc, char **argv, char **envp)
  {
      int i;
      FILE *vmstate_dump_file = NULL;
      Error *main_loop_err = NULL;
      Error *err = NULL;
+     bool list_data_dirs = false;
 +#ifdef CONFIG_YAGL
 +    static bool yagl_enabled = false;
 +#endif /* CONFIG_YAGL */
 +#ifdef CONFIG_VIGS
 +    static bool vigs_enabled = false;
 +    static char *vigs_backend = NULL;
 +#endif /* CONFIG_VIGS */
  
      qemu_init_cpu_loop();
      qemu_mutex_lock_iothread();
      current_machine->boot_order = boot_order;
      current_machine->cpu_model = cpu_model;
  
 +    configure_accelerator(current_machine);
 +
 +#if defined(CONFIG_MARU)
 +    if (is_maru_machine(machine_class)) {
 +        kernel_cmdline = qemu_opt_get(machine_opts, "append");
 +        // Returned variable points different address from input variable.
 +        kernel_cmdline = prepare_maru(kernel_cmdline);
 +        qemu_opt_set(qemu_get_machine_opts(), "append",
 +                kernel_cmdline, &error_abort);
 +
 +        current_machine->kernel_cmdline = (char *)kernel_cmdline;
++        if (display_type == DT_NONE) {
++            nodisplay = true;
++        }
 +    }
 +#endif
 +
      machine_class->init(current_machine);
  
      realtime_init();
          exit(1);
      }
  
 +    if (hax_enabled()) {
 +        hax_sync_vcpus();
 +    }
 +
      /* init USB devices */
-     if (usb_enabled()) {
+     if (machine_usb(current_machine)) {
          if (foreach_device_config(DEV_USB, usb_parse) < 0)
              exit(1);
      }
      case DT_GTK:
          gtk_display_init(ds, full_screen, grab_on_hover);
          break;
- #endif
 +#if defined(CONFIG_MARU)
 + #if defined(CONFIG_QT)
 +    case DT_MARU_QT_ONSCREEN:
 +    case DT_MARU_QT_OFFSCREEN:
 +        if (!is_maru_machine(machine_class)) {
 +            error_report("maru_qt can not work"
 +                    " without maru machine");
 +            exit(1);
 +        }
 +        maru_qt5_display_init(ds, full_screen);
 +        break;
 + #endif
 +#endif
      default:
          break;
      }
  
      os_setup_post();
  
 +#ifdef CONFIG_MARU
 +    enable_print_backtrace_at_normal_exit();
 +#endif
+     trace_init_vcpu_events();
      main_loop();
      replay_disable_events();