You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/12/04 07:04:30 UTC

[incubator-nuttx] 01/02: hosfs_rpmsg: merge hostfs_rpmsg to rpmsgfs

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 985cc4fc6d093fd8949856a0830c9d839f96e24b
Author: ligd <li...@xiaomi.com>
AuthorDate: Tue Nov 30 20:00:03 2021 +0800

    hosfs_rpmsg: merge hostfs_rpmsg to rpmsgfs
    
    Signed-off-by: ligd <li...@xiaomi.com>
---
 fs/Kconfig                                     |    1 +
 fs/Makefile                                    |    1 +
 fs/hostfs/Kconfig                              |   20 -
 fs/hostfs/Make.defs                            |    8 -
 fs/hostfs/hostfs_rpmsg.c                       |  775 -------------
 fs/hostfs/hostfs_rpmsg.h                       |  203 ----
 fs/hostfs/hostfs_rpmsg_server.c                |  883 --------------
 fs/mount/fs_gettype.c                          |    6 +
 fs/mount/fs_mount.c                            |    6 +
 fs/rpmsgfs/Kconfig                             |   12 +
 fs/{hostfs => rpmsgfs}/Make.defs               |   20 +-
 fs/rpmsgfs/rpmsgfs.c                           | 1456 ++++++++++++++++++++++++
 fs/rpmsgfs/rpmsgfs.h                           |  246 ++++
 fs/rpmsgfs/rpmsgfs_client.c                    |  819 +++++++++++++
 fs/rpmsgfs/rpmsgfs_server.c                    |  883 ++++++++++++++
 include/nuttx/fs/dirent.h                      |   14 +
 include/nuttx/fs/{hostfs_rpmsg.h => rpmsgfs.h} |   10 +-
 include/sys/statfs.h                           |    1 +
 18 files changed, 3454 insertions(+), 1910 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index 240f712..3bbda1f 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -134,3 +134,4 @@ source "fs/littlefs/Kconfig"
 source "fs/unionfs/Kconfig"
 source "fs/userfs/Kconfig"
 source "fs/hostfs/Kconfig"
+source "fs/rpmsgfs/Kconfig"
diff --git a/fs/Makefile b/fs/Makefile
index 90e1181..c09c0e3 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -56,6 +56,7 @@ include unionfs/Make.defs
 include userfs/Make.defs
 include hostfs/Make.defs
 include littlefs/Make.defs
+include rpmsgfs/Make.defs
 
 endif
 
diff --git a/fs/hostfs/Kconfig b/fs/hostfs/Kconfig
index 0395f66..6ef25b8 100644
--- a/fs/hostfs/Kconfig
+++ b/fs/hostfs/Kconfig
@@ -36,23 +36,3 @@ config FS_HOSTFS
 		option to enable the handling of the trap.
 		Theoretically, it can work for other environments as well.
 		E.g. a real hardware + JTAG + OpenOCD.
-
-config FS_HOSTFS_RPMSG
-	bool "Host File System Rpmsg"
-	default n
-	depends on FS_HOSTFS
-	depends on OPENAMP
-	---help---
-		Use Host file system to mount directories through rpmsg.
-		This is the driver that sending the message.
-
-		This effectively replaces the ordinary hostfs backend.
-		Right now, there is no way to enable both backends.
-
-config FS_HOSTFS_RPMSG_SERVER
-	bool "Host File System Rpmsg Server"
-	default n
-	depends on OPENAMP
-	---help---
-		Use Host file system to mount directories through rpmsg.
-		This is the driver that receiving the message.
diff --git a/fs/hostfs/Make.defs b/fs/hostfs/Make.defs
index 5dc6a24..a18589c 100644
--- a/fs/hostfs/Make.defs
+++ b/fs/hostfs/Make.defs
@@ -26,11 +26,3 @@ VPATH += :hostfs
 ifeq ($(CONFIG_FS_HOSTFS),y)
 CSRCS += hostfs.c
 endif
-
-ifeq ($(CONFIG_FS_HOSTFS_RPMSG),y)
-CSRCS += hostfs_rpmsg.c
-endif
-
-ifeq ($(CONFIG_FS_HOSTFS_RPMSG_SERVER),y)
-CSRCS += hostfs_rpmsg_server.c
-endif
diff --git a/fs/hostfs/hostfs_rpmsg.c b/fs/hostfs/hostfs_rpmsg.c
deleted file mode 100644
index 4e5be7d..0000000
--- a/fs/hostfs/hostfs_rpmsg.c
+++ /dev/null
@@ -1,775 +0,0 @@
-/****************************************************************************
- * fs/hostfs/hostfs_rpmsg.c
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/hostfs.h>
-#include <nuttx/fs/hostfs_rpmsg.h>
-#include <nuttx/rptun/openamp.h>
-#include <nuttx/semaphore.h>
-
-#include "hostfs_rpmsg.h"
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct hostfs_rpmsg_s
-{
-  struct rpmsg_endpoint ept;
-  FAR const char        *cpuname;
-};
-
-struct hostfs_rpmsg_cookie_s
-{
-  sem_t     sem;
-  int       result;
-  FAR void  *data;
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int hostfs_rpmsg_default_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_read_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_readdir_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_statfs_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_stat_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv);
-static void hostfs_rpmsg_device_created(struct rpmsg_device *rdev,
-                                        FAR void *priv_);
-static void hostfs_rpmsg_device_destroy(struct rpmsg_device *rdev,
-                                        FAR void *priv_);
-static int  hostfs_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
-                                FAR void *data, size_t len, uint32_t src,
-                                FAR void *priv);
-static int  hostfs_rpmsg_send_recv(uint32_t command, bool copy,
-                                   FAR struct hostfs_rpmsg_header_s *msg,
-                                   int len, FAR void *data);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-static struct hostfs_rpmsg_s g_hostfs_rpmsg;
-
-static const rpmsg_ept_cb g_hostfs_rpmsg_handler[] =
-{
-  [HOSTFS_RPMSG_OPEN]      = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_CLOSE]     = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_READ]      = hostfs_rpmsg_read_handler,
-  [HOSTFS_RPMSG_WRITE]     = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_LSEEK]     = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_IOCTL]     = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_SYNC]      = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_DUP]       = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_FSTAT]     = hostfs_rpmsg_stat_handler,
-  [HOSTFS_RPMSG_FTRUNCATE] = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_OPENDIR]   = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_READDIR]   = hostfs_rpmsg_readdir_handler,
-  [HOSTFS_RPMSG_REWINDDIR] = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_CLOSEDIR]  = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_STATFS]    = hostfs_rpmsg_statfs_handler,
-  [HOSTFS_RPMSG_UNLINK]    = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_MKDIR]     = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_RMDIR]     = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_RENAME]    = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_STAT]      = hostfs_rpmsg_stat_handler,
-  [HOSTFS_RPMSG_FCHSTAT]   = hostfs_rpmsg_default_handler,
-  [HOSTFS_RPMSG_CHSTAT]    = hostfs_rpmsg_default_handler,
-};
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-static int hostfs_rpmsg_default_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_header_s *header = data;
-  FAR struct hostfs_rpmsg_cookie_s *cookie =
-      (struct hostfs_rpmsg_cookie_s *)(uintptr_t)header->cookie;
-
-  cookie->result = header->result;
-  if (cookie->result >= 0 && cookie->data)
-    {
-      memcpy(cookie->data, data, len);
-    }
-
-  nxsem_post(&cookie->sem);
-
-  return 0;
-}
-
-static int hostfs_rpmsg_read_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_header_s *header = data;
-  FAR struct hostfs_rpmsg_cookie_s *cookie =
-      (struct hostfs_rpmsg_cookie_s *)(uintptr_t)header->cookie;
-  FAR struct hostfs_rpmsg_read_s *rsp = data;
-
-  cookie->result = header->result;
-  if (cookie->result > 0)
-    {
-      memcpy(cookie->data, rsp->buf, B2C(cookie->result));
-    }
-
-  nxsem_post(&cookie->sem);
-
-  return 0;
-}
-
-static int hostfs_rpmsg_readdir_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_header_s *header = data;
-  FAR struct hostfs_rpmsg_cookie_s *cookie =
-      (struct hostfs_rpmsg_cookie_s *)(uintptr_t)header->cookie;
-  FAR struct hostfs_rpmsg_readdir_s *rsp = data;
-  FAR struct dirent *entry = cookie->data;
-
-  cookie->result = header->result;
-  if (cookie->result >= 0)
-    {
-      nbstr2cstr(entry->d_name, rsp->name, NAME_MAX);
-      entry->d_name[NAME_MAX] = '\0';
-      entry->d_type = rsp->type;
-    }
-
-  nxsem_post(&cookie->sem);
-
-  return 0;
-}
-
-static int hostfs_rpmsg_statfs_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_header_s *header = data;
-  FAR struct hostfs_rpmsg_cookie_s *cookie =
-      (struct hostfs_rpmsg_cookie_s *)(uintptr_t)header->cookie;
-  FAR struct hostfs_rpmsg_statfs_s *rsp = data;
-  FAR struct statfs *buf = cookie->data;
-
-  cookie->result = header->result;
-  if (cookie->result >= 0)
-    {
-      buf->f_type    = rsp->buf.f_type;
-      buf->f_namelen = rsp->buf.f_namelen;
-      buf->f_bsize   = B2C(rsp->buf.f_bsize);
-      buf->f_blocks  = rsp->buf.f_blocks;
-      buf->f_bfree   = rsp->buf.f_bfree;
-      buf->f_bavail  = rsp->buf.f_bavail;
-      buf->f_files   = rsp->buf.f_files;
-      buf->f_ffree   = rsp->buf.f_ffree;
-    }
-
-  nxsem_post(&cookie->sem);
-
-  return 0;
-}
-
-static int hostfs_rpmsg_stat_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_header_s *header = data;
-  FAR struct hostfs_rpmsg_cookie_s *cookie =
-      (struct hostfs_rpmsg_cookie_s *)(uintptr_t)header->cookie;
-  FAR struct hostfs_rpmsg_stat_s *rsp = data;
-  FAR struct stat *buf = cookie->data;
-
-  cookie->result = header->result;
-  if (cookie->result >= 0)
-    {
-      buf->st_dev     = rsp->buf.st_dev;
-      buf->st_ino     = rsp->buf.st_ino;
-      buf->st_mode    = rsp->buf.st_mode;
-      buf->st_nlink   = rsp->buf.st_nlink;
-      buf->st_uid     = rsp->buf.st_uid;
-      buf->st_gid     = rsp->buf.st_gid;
-      buf->st_rdev    = rsp->buf.st_rdev;
-      buf->st_size    = B2C(rsp->buf.st_size);
-      buf->st_atime   = rsp->buf.st_atime;
-      buf->st_mtime   = rsp->buf.st_mtime;
-      buf->st_ctime   = rsp->buf.st_ctime;
-      buf->st_blksize = B2C(rsp->buf.st_blksize);
-      buf->st_blocks  = rsp->buf.st_blocks;
-    }
-
-  nxsem_post(&cookie->sem);
-
-  return 0;
-}
-
-static void hostfs_rpmsg_device_created(FAR struct rpmsg_device *rdev,
-                                        FAR void *priv_)
-{
-  FAR struct hostfs_rpmsg_s *priv = priv_;
-
-  if (strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0)
-    {
-      priv->ept.priv = priv;
-      rpmsg_create_ept(&priv->ept, rdev, HOSTFS_RPMSG_EPT_NAME,
-                       RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
-                       hostfs_rpmsg_ept_cb, NULL);
-    }
-}
-
-static void hostfs_rpmsg_device_destroy(FAR struct rpmsg_device *rdev,
-                                        FAR void *priv_)
-{
-  struct hostfs_rpmsg_s *priv = priv_;
-
-  if (strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0)
-    {
-      rpmsg_destroy_ept(&priv->ept);
-    }
-}
-
-static int hostfs_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
-                               FAR void *data, size_t len, uint32_t src,
-                               FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_header_s *header = data;
-  uint32_t command = header->command;
-
-  if (command < ARRAY_SIZE(g_hostfs_rpmsg_handler))
-    {
-      return g_hostfs_rpmsg_handler[command](ept, data, len, src, priv);
-    }
-
-  return -EINVAL;
-}
-
-static int hostfs_rpmsg_send_recv(uint32_t command, bool copy,
-                                  FAR struct hostfs_rpmsg_header_s *msg,
-                                  int len, FAR void *data)
-{
-  FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  FAR struct hostfs_rpmsg_cookie_s cookie;
-  int ret;
-
-  memset(&cookie, 0, sizeof(cookie));
-  nxsem_init(&cookie.sem, 0, 0);
-  nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE);
-
-  if (data)
-    {
-      cookie.data = data;
-    }
-  else if (copy)
-    {
-      cookie.data = msg;
-    }
-
-  msg->command = command;
-  msg->result  = -ENXIO;
-  msg->cookie  = (uintptr_t)&cookie;
-
-  if (copy)
-    {
-      ret = rpmsg_send(&priv->ept, msg, len);
-    }
-  else
-    {
-      ret = rpmsg_send_nocopy(&priv->ept, msg, len);
-    }
-
-  if (ret < 0)
-    {
-      goto fail;
-    }
-
-  ret = nxsem_wait_uninterruptible(&cookie.sem);
-  if (ret == 0)
-    {
-      ret = cookie.result;
-    }
-
-fail:
-  nxsem_destroy(&cookie.sem);
-  return ret;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-int host_open(FAR const char *pathname, int flags, int mode)
-{
-  FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  FAR struct hostfs_rpmsg_open_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(pathname) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  msg->flags = flags;
-  msg->mode  = mode;
-  cstr2bstr(msg->pathname, pathname);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_OPEN, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-}
-
-int host_close(int fd)
-{
-  struct hostfs_rpmsg_close_s msg =
-  {
-    .fd = fd,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_CLOSE, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-ssize_t host_read(int fd, FAR void *buf, size_t count)
-{
-  size_t read = 0;
-  int ret = 0;
-
-  while (read < count)
-    {
-      struct hostfs_rpmsg_read_s msg =
-      {
-        .fd    = fd,
-        .count = C2B(count - read),
-      };
-
-      ret = hostfs_rpmsg_send_recv(HOSTFS_RPMSG_READ, true,
-              (FAR struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), buf);
-      if (ret <= 0)
-        {
-          break;
-        }
-
-      read += B2C(ret);
-      buf  += B2C(ret);
-    }
-
-  return read ? read : ret;
-}
-
-ssize_t host_write(int fd, FAR const void *buf, size_t count)
-{
-  FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  size_t written = 0;
-  int ret = 0;
-
-  while (written < count)
-    {
-      FAR struct hostfs_rpmsg_write_s *msg;
-      uint32_t space;
-
-      msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-      if (!msg)
-        {
-          ret = -ENOMEM;
-          break;
-        }
-
-      space -= sizeof(*msg);
-      if (space > count - written)
-        {
-          space = count - written;
-        }
-
-      msg->fd    = fd;
-      msg->count = C2B(space);
-      memcpy(msg->buf, buf + written, space);
-
-      ret = hostfs_rpmsg_send_recv(HOSTFS_RPMSG_WRITE, false,
-                                   (FAR struct hostfs_rpmsg_header_s *)msg,
-                                   sizeof(*msg) + space, NULL);
-      if (ret <= 0)
-        {
-          break;
-        }
-
-      written += B2C(ret);
-    }
-
-  return written ? written : ret;
-}
-
-off_t host_lseek(int fd, off_t offset, int whence)
-{
-  struct hostfs_rpmsg_lseek_s msg =
-  {
-    .fd     = fd,
-    .offset = C2B(offset),
-    .whence = whence,
-  };
-
-  int ret;
-
-  ret = hostfs_rpmsg_send_recv(HOSTFS_RPMSG_LSEEK, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-
-  return ret < 0 ? ret : B2C(ret);
-}
-
-int host_ioctl(int fd, int request, unsigned long arg)
-{
-  struct hostfs_rpmsg_ioctl_s msg =
-  {
-    .fd      = fd,
-    .request = request,
-    .arg     = arg,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_IOCTL, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-void host_sync(int fd)
-{
-  struct hostfs_rpmsg_sync_s msg =
-  {
-    .fd = fd,
-  };
-
-  hostfs_rpmsg_send_recv(HOSTFS_RPMSG_SYNC, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-int host_dup(int fd)
-{
-  struct hostfs_rpmsg_dup_s msg =
-  {
-    .fd = fd,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_DUP, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-int host_fstat(int fd, struct stat *buf)
-{
-  struct hostfs_rpmsg_fstat_s msg =
-  {
-    .fd = fd,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_FSTAT, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), buf);
-}
-
-int host_ftruncate(int fd, off_t length)
-{
-  struct hostfs_rpmsg_ftruncate_s msg =
-  {
-    .fd     = fd,
-    .length = length,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_FTRUNCATE, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-FAR void *host_opendir(FAR const char *name)
-{
-  FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  FAR struct hostfs_rpmsg_opendir_s *msg;
-  uint32_t space;
-  size_t len;
-  int ret;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(name) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return NULL;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  cstr2bstr(msg->pathname, name);
-
-  ret = hostfs_rpmsg_send_recv(HOSTFS_RPMSG_OPENDIR, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-
-  return ret < 0 ? NULL : (FAR void *)((uintptr_t)ret);
-}
-
-int host_readdir(FAR void *dirp, FAR struct dirent *entry)
-{
-  struct hostfs_rpmsg_readdir_s msg =
-  {
-    .fd = (uintptr_t)dirp,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_READDIR, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), entry);
-}
-
-void host_rewinddir(FAR void *dirp)
-{
-  struct hostfs_rpmsg_rewinddir_s msg =
-  {
-    .fd = (uintptr_t)dirp,
-  };
-
-  hostfs_rpmsg_send_recv(HOSTFS_RPMSG_REWINDDIR, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-int host_closedir(FAR void *dirp)
-{
-  struct hostfs_rpmsg_closedir_s msg =
-  {
-    .fd = (uintptr_t)dirp,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_CLOSEDIR, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-int host_statfs(FAR const char *path, FAR struct statfs *buf)
-{
-  struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  struct hostfs_rpmsg_statfs_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(path) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  cstr2bstr(msg->pathname, path);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_STATFS, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, buf);
-}
-
-int host_unlink(FAR const char *pathname)
-{
-  struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  struct hostfs_rpmsg_unlink_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(pathname) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  cstr2bstr(msg->pathname, pathname);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_UNLINK, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-}
-
-int host_mkdir(FAR const char *pathname, mode_t mode)
-{
-  struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  struct hostfs_rpmsg_mkdir_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(pathname) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  msg->mode = mode;
-  cstr2bstr(msg->pathname, pathname);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_MKDIR, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-}
-
-int host_rmdir(FAR const char *pathname)
-{
-  struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  struct hostfs_rpmsg_rmdir_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(pathname) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  cstr2bstr(msg->pathname, pathname);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_RMDIR, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-}
-
-int host_rename(FAR const char *oldpath, FAR const char *newpath)
-{
-  struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  struct hostfs_rpmsg_rename_s *msg;
-  size_t len;
-  size_t oldlen;
-  uint32_t space;
-
-  len     = sizeof(*msg);
-  oldlen  = B2C((strlen(oldpath) + 1 + 0x7) & ~0x7);
-  len    += oldlen + B2C(strlen(newpath) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  cstr2bstr(msg->pathname, oldpath);
-  cstr2bstr(msg->pathname + oldlen, newpath);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_RENAME, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-}
-
-int host_stat(FAR const char *path, FAR struct stat *buf)
-{
-  FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  FAR struct hostfs_rpmsg_stat_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(path) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  cstr2bstr(msg->pathname, path);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_STAT, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, buf);
-}
-
-int host_fchstat(int fd, const struct stat *buf, int flags)
-{
-  struct hostfs_rpmsg_fchstat_s msg =
-  {
-    .flags = flags,
-    .buf = *buf,
-    .fd = fd,
-  };
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_FCHSTAT, true,
-          (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL);
-}
-
-int host_chstat(FAR const char *path, const FAR struct stat *buf, int flags)
-{
-  FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-  FAR struct hostfs_rpmsg_chstat_s *msg;
-  uint32_t space;
-  size_t len;
-
-  len  = sizeof(*msg);
-  len += B2C(strlen(path) + 1);
-
-  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
-  if (!msg)
-    {
-      return -ENOMEM;
-    }
-
-  DEBUGASSERT(len <= space);
-
-  msg->flags = flags;
-  memcpy(&msg->buf, buf, sizeof(*buf));
-  cstr2bstr(msg->pathname, path);
-
-  return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_CHSTAT, false,
-          (struct hostfs_rpmsg_header_s *)msg, len, NULL);
-}
-
-int hostfs_rpmsg_init(FAR const char *cpuname)
-{
-  struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg;
-
-  priv->cpuname = cpuname;
-
-  return rpmsg_register_callback(priv,
-                                 hostfs_rpmsg_device_created,
-                                 hostfs_rpmsg_device_destroy,
-                                 NULL);
-}
diff --git a/fs/hostfs/hostfs_rpmsg.h b/fs/hostfs/hostfs_rpmsg.h
deleted file mode 100644
index 9f11a1d..0000000
--- a/fs/hostfs/hostfs_rpmsg.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/****************************************************************************
- * fs/hostfs/hostfs_rpmsg.h
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-#ifndef __FS_HOSTFS_HOSTFS_RPMSG_H
-#define __FS_HOSTFS_HOSTFS_RPMSG_H
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <sys/stat.h>
-#include <sys/statfs.h>
-
-/****************************************************************************
- * Pre-processor definitions
- ****************************************************************************/
-
-#ifndef ARRAY_SIZE
-#  define ARRAY_SIZE(x)             (sizeof(x) / sizeof((x)[0]))
-#endif
-
-#define HOSTFS_RPMSG_EPT_NAME       "rpmsg-hostfs"
-
-#define HOSTFS_RPMSG_OPEN           1
-#define HOSTFS_RPMSG_CLOSE          2
-#define HOSTFS_RPMSG_READ           3
-#define HOSTFS_RPMSG_WRITE          4
-#define HOSTFS_RPMSG_LSEEK          5
-#define HOSTFS_RPMSG_IOCTL          6
-#define HOSTFS_RPMSG_SYNC           7
-#define HOSTFS_RPMSG_DUP            8
-#define HOSTFS_RPMSG_FSTAT          9
-#define HOSTFS_RPMSG_FTRUNCATE      10
-#define HOSTFS_RPMSG_OPENDIR        11
-#define HOSTFS_RPMSG_READDIR        12
-#define HOSTFS_RPMSG_REWINDDIR      13
-#define HOSTFS_RPMSG_CLOSEDIR       14
-#define HOSTFS_RPMSG_STATFS         15
-#define HOSTFS_RPMSG_UNLINK         16
-#define HOSTFS_RPMSG_MKDIR          17
-#define HOSTFS_RPMSG_RMDIR          18
-#define HOSTFS_RPMSG_RENAME         19
-#define HOSTFS_RPMSG_STAT           20
-#define HOSTFS_RPMSG_FCHSTAT        21
-#define HOSTFS_RPMSG_CHSTAT         22
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-begin_packed_struct struct hostfs_rpmsg_header_s
-{
-  uint32_t command;
-  int32_t  result;
-  uint64_t cookie;
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_open_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      flags;
-  int32_t                      mode;
-  char                         pathname[0];
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_close_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      fd;
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_read_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      fd;
-  uint32_t                     count;
-  char                         buf[0];
-} end_packed_struct;
-
-#define hostfs_rpmsg_write_s hostfs_rpmsg_read_s
-
-begin_packed_struct struct hostfs_rpmsg_lseek_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      fd;
-  int32_t                      whence;
-  int32_t                      offset;
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_ioctl_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      fd;
-  int32_t                      request;
-  int32_t                      arg;
-} end_packed_struct;
-
-#define hostfs_rpmsg_sync_s hostfs_rpmsg_close_s
-#define hostfs_rpmsg_dup_s  hostfs_rpmsg_close_s
-
-begin_packed_struct struct hostfs_rpmsg_fstat_s
-{
-  struct hostfs_rpmsg_header_s header;
-  union
-  {
-    struct stat                buf;
-    uint32_t                   reserved[16];
-  };
-
-  union
-  {
-    int32_t                    fd;
-    char                       pathname[0];
-  };
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_ftruncate_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      fd;
-  int32_t                      length;
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_opendir_s
-{
-  struct hostfs_rpmsg_header_s header;
-  char                         pathname[0];
-} end_packed_struct;
-
-begin_packed_struct struct hostfs_rpmsg_readdir_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      fd;
-  uint32_t                     type;
-  char                         name[0];
-} end_packed_struct;
-
-#define hostfs_rpmsg_rewinddir_s hostfs_rpmsg_close_s
-#define hostfs_rpmsg_closedir_s hostfs_rpmsg_close_s
-
-begin_packed_struct struct hostfs_rpmsg_statfs_s
-{
-  struct hostfs_rpmsg_header_s header;
-  union
-  {
-    struct statfs              buf;
-    uint32_t                   reserved[16];
-  };
-
-  char                         pathname[0];
-} end_packed_struct;
-
-#define hostfs_rpmsg_unlink_s hostfs_rpmsg_opendir_s
-
-begin_packed_struct struct hostfs_rpmsg_mkdir_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      mode;
-  uint32_t                     reserved;
-  char                         pathname[0];
-} end_packed_struct;
-
-#define hostfs_rpmsg_rmdir_s hostfs_rpmsg_opendir_s
-#define hostfs_rpmsg_rename_s hostfs_rpmsg_opendir_s
-#define hostfs_rpmsg_stat_s hostfs_rpmsg_fstat_s
-
-begin_packed_struct struct hostfs_rpmsg_fchstat_s
-{
-  struct hostfs_rpmsg_header_s header;
-  int32_t                      flags;
-  union
-  {
-    struct stat                buf;
-    uint32_t                   reserved[16];
-  };
-
-  union
-  {
-    int32_t                    fd;
-    char                       pathname[0];
-  };
-} end_packed_struct;
-
-#define hostfs_rpmsg_chstat_s hostfs_rpmsg_fchstat_s
-
-#endif /* __FS_HOSTFS_HOSTFS_RPMSG_H */
diff --git a/fs/hostfs/hostfs_rpmsg_server.c b/fs/hostfs/hostfs_rpmsg_server.c
deleted file mode 100644
index 9e8a68b..0000000
--- a/fs/hostfs/hostfs_rpmsg_server.c
+++ /dev/null
@@ -1,883 +0,0 @@
-/****************************************************************************
- * fs/hostfs/hostfs_rpmsg_server.c
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <dirent.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/fs/hostfs_rpmsg.h>
-#include <nuttx/rptun/openamp.h>
-
-#include "hostfs_rpmsg.h"
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct hostfs_rpmsg_server_s
-{
-  struct rpmsg_endpoint ept;
-  FAR struct file     **files;
-  FAR void            **dirs;
-  int                   file_rows;
-  int                   dir_nums;
-  sem_t                 sem;
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int hostfs_rpmsg_open_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_close_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_read_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_write_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_lseek_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_sync_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_dup_handler(FAR struct rpmsg_endpoint *ept,
-                                    FAR void *data, size_t len,
-                                    uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_fstat_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_ftruncate_handler(FAR struct rpmsg_endpoint *ept,
-                                          FAR void *data, size_t len,
-                                          uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_opendir_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_readdir_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_rewinddir_handler(FAR struct rpmsg_endpoint *ept,
-                                          FAR void *data, size_t len,
-                                          uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_closedir_handler(FAR struct rpmsg_endpoint *ept,
-                                         FAR void *data, size_t len,
-                                         uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_statfs_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_unlink_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_mkdir_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_rmdir_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_rename_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_stat_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_fchstat_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv);
-static int hostfs_rpmsg_chstat_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv);
-
-static void hostfs_rpmsg_ns_bind(FAR struct rpmsg_device *rdev,
-                                 FAR void *priv_, FAR const char *name,
-                                 uint32_t dest);
-static void hostfs_rpmsg_ns_unbind(FAR struct rpmsg_endpoint *ept);
-static int  hostfs_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
-                                FAR void *data, size_t len, uint32_t src,
-                                FAR void *priv);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-static const rpmsg_ept_cb g_hostfs_rpmsg_handler[] =
-{
-  [HOSTFS_RPMSG_OPEN]      = hostfs_rpmsg_open_handler,
-  [HOSTFS_RPMSG_CLOSE]     = hostfs_rpmsg_close_handler,
-  [HOSTFS_RPMSG_READ]      = hostfs_rpmsg_read_handler,
-  [HOSTFS_RPMSG_WRITE]     = hostfs_rpmsg_write_handler,
-  [HOSTFS_RPMSG_LSEEK]     = hostfs_rpmsg_lseek_handler,
-  [HOSTFS_RPMSG_IOCTL]     = hostfs_rpmsg_ioctl_handler,
-  [HOSTFS_RPMSG_SYNC]      = hostfs_rpmsg_sync_handler,
-  [HOSTFS_RPMSG_DUP]       = hostfs_rpmsg_dup_handler,
-  [HOSTFS_RPMSG_FSTAT]     = hostfs_rpmsg_fstat_handler,
-  [HOSTFS_RPMSG_FTRUNCATE] = hostfs_rpmsg_ftruncate_handler,
-  [HOSTFS_RPMSG_OPENDIR]   = hostfs_rpmsg_opendir_handler,
-  [HOSTFS_RPMSG_READDIR]   = hostfs_rpmsg_readdir_handler,
-  [HOSTFS_RPMSG_REWINDDIR] = hostfs_rpmsg_rewinddir_handler,
-  [HOSTFS_RPMSG_CLOSEDIR]  = hostfs_rpmsg_closedir_handler,
-  [HOSTFS_RPMSG_STATFS]    = hostfs_rpmsg_statfs_handler,
-  [HOSTFS_RPMSG_UNLINK]    = hostfs_rpmsg_unlink_handler,
-  [HOSTFS_RPMSG_MKDIR]     = hostfs_rpmsg_mkdir_handler,
-  [HOSTFS_RPMSG_RMDIR]     = hostfs_rpmsg_rmdir_handler,
-  [HOSTFS_RPMSG_RENAME]    = hostfs_rpmsg_rename_handler,
-  [HOSTFS_RPMSG_STAT]      = hostfs_rpmsg_stat_handler,
-  [HOSTFS_RPMSG_FCHSTAT]   = hostfs_rpmsg_fchstat_handler,
-  [HOSTFS_RPMSG_CHSTAT]    = hostfs_rpmsg_chstat_handler,
-};
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-static int hostfs_rpmsg_attach_file(FAR struct hostfs_rpmsg_server_s *priv,
-                                    FAR struct file *filep)
-{
-  FAR struct file **tmp;
-  int ret;
-  int i;
-  int j;
-
-  nxsem_wait(&priv->sem);
-
-  for (i = 0; i < priv->file_rows; i++)
-    {
-      for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++)
-        {
-          if (priv->files[i][j].f_inode == NULL)
-            {
-              memcpy(&priv->files[i][j], filep, sizeof(*filep));
-              ret = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j;
-              goto out;
-            }
-        }
-    }
-
-  tmp = kmm_realloc(priv->files, sizeof(FAR struct file *) * (i + 1));
-  DEBUGASSERT(tmp);
-  if (tmp == NULL)
-    {
-      ret = -ENFILE;
-      goto out;
-    }
-
-  tmp[i] = kmm_zalloc(sizeof(struct file) *
-                      CONFIG_NFILE_DESCRIPTORS_PER_BLOCK);
-  DEBUGASSERT(tmp[i]);
-  if (tmp[i] == NULL)
-    {
-      kmm_free(tmp);
-      ret = -ENFILE;
-      goto out;
-    }
-
-  priv->files = tmp;
-  priv->file_rows++;
-
-  memcpy(&priv->files[i][0], filep, sizeof(*filep));
-  ret = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK;
-
-out:
-  nxsem_post(&priv->sem);
-  return ret;
-}
-
-static int hostfs_rpmsg_detach_file(FAR struct hostfs_rpmsg_server_s *priv,
-                                    int fd, FAR struct file *filep)
-{
-  struct file *tfilep;
-
-  if (fd < 0 || fd >= priv->file_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK)
-    {
-      return -EBADF;
-    }
-
-  nxsem_wait(&priv->sem);
-  tfilep = &priv->files[fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]
-                       [fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK];
-  memcpy(filep, tfilep, sizeof(*filep));
-  memset(tfilep, 0, sizeof(*tfilep));
-  nxsem_post(&priv->sem);
-
-  return 0;
-}
-
-static FAR struct file *hostfs_rpmsg_get_file(
-                              FAR struct hostfs_rpmsg_server_s *priv,
-                              int fd)
-{
-  FAR struct file *filep;
-
-  if (fd < 0 || fd >= priv->file_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK)
-    {
-      return NULL;
-    }
-
-  nxsem_wait(&priv->sem);
-  filep = &priv->files[fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]
-                      [fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK];
-  nxsem_post(&priv->sem);
-
-  return filep;
-}
-
-static int hostfs_rpmsg_attach_dir(FAR struct hostfs_rpmsg_server_s *priv,
-                                   FAR void *dir)
-{
-  FAR void **tmp;
-  int i;
-
-  nxsem_wait(&priv->sem);
-  for (i = 1; i < priv->dir_nums; i++)
-    {
-      if (priv->dirs[i] == NULL)
-        {
-          priv->dirs[i] = dir;
-          nxsem_post(&priv->sem);
-          return i;
-        }
-    }
-
-  tmp = kmm_realloc(priv->dirs, sizeof(FAR void *) *
-                    (priv->dir_nums + CONFIG_NFILE_DESCRIPTORS_PER_BLOCK));
-  DEBUGASSERT(tmp);
-  if (tmp == NULL)
-    {
-      nxsem_post(&priv->sem);
-      return -ENOMEM;
-    }
-
-  priv->dirs = tmp;
-  priv->dir_nums += CONFIG_NFILE_DESCRIPTORS_PER_BLOCK;
-
-  priv->dirs[i] = dir;
-  nxsem_post(&priv->sem);
-  return i;
-}
-
-static void *hostfs_rpmsg_detach_dir(FAR struct hostfs_rpmsg_server_s *priv,
-                                    int fd)
-{
-  FAR void *dir = NULL;
-
-  if (fd >= 1 && fd < priv->dir_nums)
-    {
-      nxsem_wait(&priv->sem);
-      dir = priv->dirs[fd];
-      priv->dirs[fd] = NULL;
-      nxsem_post(&priv->sem);
-    }
-
-  return dir;
-}
-
-static FAR void *hostfs_rpmsg_get_dir(
-                              FAR struct hostfs_rpmsg_server_s *priv,
-                              int fd)
-{
-  FAR void *dir = NULL;
-
-  if (fd >= 1 && fd < priv->dir_nums)
-    {
-      nxsem_wait(&priv->sem);
-      dir = priv->dirs[fd];
-      nxsem_post(&priv->sem);
-    }
-
-  return dir;
-}
-
-static int hostfs_rpmsg_open_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_open_s *msg = data;
-  struct file file;
-  int ret;
-
-  ret = file_open(&file, msg->pathname, msg->flags, msg->mode);
-  if (ret >= 0)
-    {
-      ret = hostfs_rpmsg_attach_file(priv, &file);
-      if (ret < 0)
-        {
-          file_close(&file);
-        }
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_close_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_close_s *msg = data;
-  struct file file;
-  int ret;
-
-  ret = hostfs_rpmsg_detach_file(priv, msg->fd, &file);
-  if (ret >= 0)
-    {
-      ret = file_close(&file);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_read_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_read_s *msg = data;
-  FAR struct hostfs_rpmsg_read_s *rsp;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-  uint32_t space;
-
-  rsp = rpmsg_get_tx_payload_buffer(ept, &space, true);
-  if (!rsp)
-    {
-      return -ENOMEM;
-    }
-
-  *rsp = *msg;
-
-  space -= sizeof(*msg);
-  if (space > msg->count)
-    {
-      space = msg->count;
-    }
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_read(filep, rsp->buf, space);
-    }
-
-  rsp->header.result = ret;
-  return rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret) + sizeof(*rsp));
-}
-
-static int hostfs_rpmsg_write_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_write_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_write(filep, msg->buf, msg->count);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_lseek_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_lseek_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_seek(filep, msg->offset, msg->whence);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_ioctl_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_ioctl(filep, msg->request, msg->arg);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_sync_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_sync_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_fsync(filep);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_dup_handler(FAR struct rpmsg_endpoint *ept,
-                                    FAR void *data, size_t len,
-                                    uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_dup_s *msg = data;
-  FAR struct file *filep;
-  struct file newfile;
-  int ret = -ENOENT;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_dup2(filep, &newfile);
-      if (ret >= 0)
-        {
-          ret = hostfs_rpmsg_attach_file(priv, &newfile);
-          if (ret < 0)
-            {
-              file_close(&newfile);
-            }
-        }
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_fstat_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_fstat_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-  struct stat buf;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_fstat(filep, &buf);
-      if (ret >= 0)
-        {
-          msg->buf = buf;
-        }
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_ftruncate_handler(FAR struct rpmsg_endpoint *ept,
-                                          FAR void *data, size_t len,
-                                          uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_ftruncate_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      ret = file_truncate(filep, msg->length);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_opendir_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_opendir_s *msg = data;
-  FAR void *dir;
-  int ret = -ENOENT;
-
-  dir = opendir(msg->pathname);
-  if (dir)
-    {
-      ret = hostfs_rpmsg_attach_dir(priv, dir);
-      if (ret < 0)
-        {
-          closedir(dir);
-        }
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_readdir_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_readdir_s *msg = data;
-  FAR struct dirent *entry;
-  int ret = -ENOENT;
-  FAR void *dir;
-
-  dir = hostfs_rpmsg_get_dir(priv, msg->fd);
-  if (dir)
-    {
-      entry = readdir(dir);
-      if (entry)
-        {
-          msg->type = entry->d_type;
-          strcpy(msg->name, entry->d_name);
-          len += strlen(entry->d_name) + 1;
-          ret = 0;
-        }
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, len);
-}
-
-static int hostfs_rpmsg_rewinddir_handler(FAR struct rpmsg_endpoint *ept,
-                                          FAR void *data, size_t len,
-                                          uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_rewinddir_s *msg = data;
-  int ret = -ENOENT;
-  FAR void *dir;
-
-  dir = hostfs_rpmsg_get_dir(priv, msg->fd);
-  if (dir)
-    {
-      rewinddir(dir);
-      ret = 0;
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_closedir_handler(FAR struct rpmsg_endpoint *ept,
-                                         FAR void *data, size_t len,
-                                         uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_closedir_s *msg = data;
-  int ret = -ENOENT;
-  FAR void *dir;
-
-  dir = hostfs_rpmsg_detach_dir(priv, msg->fd);
-  if (dir)
-    {
-      ret = closedir(dir) ? -get_errno() : 0;
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_statfs_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_statfs_s *msg = data;
-  struct statfs buf;
-  int ret;
-
-  ret = statfs(msg->pathname, &buf);
-  if (ret)
-    {
-      ret = -get_errno();
-    }
-  else
-    {
-      msg->buf = buf;
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_unlink_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_unlink_s *msg = data;
-
-  msg->header.result = nx_unlink(msg->pathname);
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_mkdir_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_mkdir_s *msg = data;
-  int ret;
-
-  ret = mkdir(msg->pathname, msg->mode);
-  msg->header.result = ret ? -get_errno() : 0;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_rmdir_handler(FAR struct rpmsg_endpoint *ept,
-                                      FAR void *data, size_t len,
-                                      uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_rmdir_s *msg = data;
-  int ret;
-
-  ret = rmdir(msg->pathname);
-  msg->header.result = ret ? -get_errno() : 0;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_rename_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_rename_s *msg = data;
-  FAR char *newpath;
-  size_t oldlen;
-  int ret;
-
-  oldlen = (strlen(msg->pathname) + 1 + 0x7) & ~0x7;
-  newpath = msg->pathname + oldlen;
-
-  ret = rename(msg->pathname, newpath);
-  msg->header.result = ret ? -get_errno() : 0;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_stat_handler(FAR struct rpmsg_endpoint *ept,
-                                     FAR void *data, size_t len,
-                                     uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_stat_s *msg = data;
-  struct stat buf;
-  int ret;
-
-  ret = nx_stat(msg->pathname, &buf, 1);
-  if (ret >= 0)
-    {
-      msg->buf = buf;
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_fchstat_handler(FAR struct rpmsg_endpoint *ept,
-                                        FAR void *data, size_t len,
-                                        uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_fchstat_s *msg = data;
-  FAR struct file *filep;
-  int ret = -ENOENT;
-  struct stat buf;
-
-  filep = hostfs_rpmsg_get_file(priv, msg->fd);
-  if (filep != NULL)
-    {
-      buf = msg->buf;
-      ret = file_fchstat(filep, &buf, msg->flags);
-    }
-
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static int hostfs_rpmsg_chstat_handler(FAR struct rpmsg_endpoint *ept,
-                                       FAR void *data, size_t len,
-                                       uint32_t src, FAR void *priv)
-{
-  FAR struct hostfs_rpmsg_chstat_s *msg = data;
-  struct timespec times[2];
-  int ret = 0;
-
-  if (msg->flags & CH_STAT_MODE)
-    {
-      ret = chmod(msg->pathname, msg->buf.st_mode);
-      if (ret < 0)
-        {
-          ret = -get_errno();
-          goto out;
-        }
-    }
-
-  if (msg->flags & (CH_STAT_UID | CH_STAT_GID))
-    {
-      ret = chown(msg->pathname, msg->buf.st_uid, msg->buf.st_gid);
-      if (ret < 0)
-        {
-          ret = -get_errno();
-          goto out;
-        }
-    }
-
-  if (msg->flags & (CH_STAT_ATIME | CH_STAT_MTIME))
-    {
-      if (msg->flags & CH_STAT_ATIME)
-        {
-          times[0] = msg->buf.st_atim;
-        }
-      else
-        {
-          times[0].tv_nsec = UTIME_OMIT;
-        }
-
-      if (msg->flags & CH_STAT_MTIME)
-        {
-          times[1] = msg->buf.st_mtim;
-        }
-      else
-        {
-          times[1].tv_nsec = UTIME_OMIT;
-        }
-
-      ret = utimens(msg->pathname, times);
-      if (ret < 0)
-        {
-          ret = -get_errno();
-          goto out;
-        }
-    }
-
-out:
-  msg->header.result = ret;
-  return rpmsg_send(ept, msg, sizeof(*msg));
-}
-
-static void hostfs_rpmsg_ns_bind(FAR struct rpmsg_device *rdev,
-                                 FAR void *priv_, FAR const char *name,
-                                 uint32_t dest)
-{
-  FAR struct hostfs_rpmsg_server_s *priv;
-  int ret;
-
-  if (strcmp(name, HOSTFS_RPMSG_EPT_NAME))
-    {
-      return;
-    }
-
-  priv = kmm_zalloc(sizeof(*priv));
-  if (!priv)
-    {
-      return;
-    }
-
-  priv->ept.priv = priv;
-  nxsem_init(&priv->sem, 0, 1);
-
-  ret = rpmsg_create_ept(&priv->ept, rdev, HOSTFS_RPMSG_EPT_NAME,
-                         RPMSG_ADDR_ANY, dest,
-                         hostfs_rpmsg_ept_cb, hostfs_rpmsg_ns_unbind);
-  if (ret)
-    {
-      nxsem_destroy(&priv->sem);
-      kmm_free(priv);
-    }
-}
-
-static void hostfs_rpmsg_ns_unbind(FAR struct rpmsg_endpoint *ept)
-{
-  FAR struct hostfs_rpmsg_server_s *priv = ept->priv;
-  int i;
-  int j;
-
-  for (i = 0; i < priv->file_rows; i++)
-    {
-      for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++)
-        {
-          if (priv->files[i][j].f_inode)
-            {
-              file_close(&priv->files[i][j]);
-            }
-        }
-
-      kmm_free(priv->files[i]);
-    }
-
-  for (i = 0; i < priv->dir_nums; i++)
-    {
-      if (priv->dirs[i])
-        {
-          closedir(priv->dirs[i]);
-        }
-    }
-
-  rpmsg_destroy_ept(&priv->ept);
-  nxsem_destroy(&priv->sem);
-
-  kmm_free(priv->files);
-  kmm_free(priv->dirs);
-  kmm_free(priv);
-}
-
-static int hostfs_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
-                               FAR void *data, size_t len, uint32_t src,
-                               FAR void *priv)
-{
-  struct hostfs_rpmsg_header_s *header = data;
-  uint32_t command = header->command;
-
-  if (command < ARRAY_SIZE(g_hostfs_rpmsg_handler))
-    {
-      return g_hostfs_rpmsg_handler[command](ept, data, len, src, priv);
-    }
-
-  return -EINVAL;
-}
-
-int hostfs_rpmsg_server_init(void)
-{
-  return rpmsg_register_callback(NULL,
-                                 NULL,
-                                 NULL,
-                                 hostfs_rpmsg_ns_bind);
-}
diff --git a/fs/mount/fs_gettype.c b/fs/mount/fs_gettype.c
index 326ce47..b5894a6 100644
--- a/fs/mount/fs_gettype.c
+++ b/fs/mount/fs_gettype.c
@@ -135,6 +135,12 @@ FAR const char *fs_gettype(FAR struct statfs *statbuf)
         break;
 #endif
 
+#ifdef CONFIG_FS_RPMSGFS
+      case RPMSGFS_MAGIC:
+        fstype = "rpmsgfs";
+        break;
+#endif
+
 #ifdef CONFIG_FS_USERFS
       case USERFS_MAGIC:
         fstype = "userfs";
diff --git a/fs/mount/fs_mount.c b/fs/mount/fs_mount.c
index b0c7d2e..5450fcd 100644
--- a/fs/mount/fs_mount.c
+++ b/fs/mount/fs_mount.c
@@ -178,6 +178,9 @@ extern const struct mountpt_operations cromfs_operations;
 #ifdef CONFIG_FS_UNIONFS
 extern const struct mountpt_operations unionfs_operations;
 #endif
+#ifdef CONFIG_FS_RPMSGFS
+extern const struct mountpt_operations rpmsgfs_operations;
+#endif
 
 static const struct fsmap_t g_nonbdfsmap[] =
 {
@@ -208,6 +211,9 @@ static const struct fsmap_t g_nonbdfsmap[] =
 #ifdef CONFIG_FS_UNIONFS
     { "unionfs", &unionfs_operations },
 #endif
+#ifdef CONFIG_FS_RPMSGFS
+    { "rpmsgfs", &rpmsgfs_operations },
+#endif
     { NULL, NULL },
 };
 #endif /* NODFS_SUPPORT */
diff --git a/fs/rpmsgfs/Kconfig b/fs/rpmsgfs/Kconfig
new file mode 100644
index 0000000..30995a5
--- /dev/null
+++ b/fs/rpmsgfs/Kconfig
@@ -0,0 +1,12 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config FS_RPMSGFS
+	bool "RPMSG File System"
+	default n
+	depends on OPENAMP
+	---help---
+		Use rpmsg file system to mount remote directories to local.
+		This the method for user to use remote file like own core.
diff --git a/fs/hostfs/Make.defs b/fs/rpmsgfs/Make.defs
similarity index 76%
copy from fs/hostfs/Make.defs
copy to fs/rpmsgfs/Make.defs
index 5dc6a24..aea7bf0 100644
--- a/fs/hostfs/Make.defs
+++ b/fs/rpmsgfs/Make.defs
@@ -1,5 +1,5 @@
 ############################################################################
-# fs/hostfs/Make.defs
+# fs/rpmsgfs/Make.defs
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -18,19 +18,11 @@
 #
 ############################################################################
 
-# Include HOSTFS build support
+# Include RPSMGFS build support
 
-DEPPATH += --dep-path hostfs
-VPATH += :hostfs
+DEPPATH += --dep-path rpmsgfs
+VPATH += :rpmsgfs
 
-ifeq ($(CONFIG_FS_HOSTFS),y)
-CSRCS += hostfs.c
-endif
-
-ifeq ($(CONFIG_FS_HOSTFS_RPMSG),y)
-CSRCS += hostfs_rpmsg.c
-endif
-
-ifeq ($(CONFIG_FS_HOSTFS_RPMSG_SERVER),y)
-CSRCS += hostfs_rpmsg_server.c
+ifeq ($(CONFIG_FS_RPMSGFS),y)
+CSRCS += rpmsgfs.c rpmsgfs_client.c rpmsgfs_server.c
 endif
diff --git a/fs/rpmsgfs/rpmsgfs.c b/fs/rpmsgfs/rpmsgfs.c
new file mode 100644
index 0000000..e096be4
--- /dev/null
+++ b/fs/rpmsgfs/rpmsgfs.c
@@ -0,0 +1,1456 @@
+/****************************************************************************
+ * fs/rpmsgfs/rpmsgfs.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <debug.h>
+#include <limits.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/fs/dirent.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/fs/rpmsgfs.h>
+
+#include "rpmsgfs.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure describes the state of one open file.  This structure
+ * is protected by the volume semaphore.
+ */
+
+struct rpmsgfs_ofile_s
+{
+  struct rpmsgfs_ofile_s     *fnext;   /* Supports a singly linked list */
+  int16_t                    crefs;    /* Reference count */
+  mode_t                     oflags;   /* Open mode */
+  int                        fd;
+};
+
+/* This structure represents the overall mountpoint state.  An instance of
+ * this structure is retained as inode private data on each mountpoint that
+ * is mounted with a rpmsgfs filesystem.
+ */
+
+struct rpmsgfs_mountpt_s
+{
+  sem_t                      fs_sem;   /* Assure thread-safe access */
+  FAR struct rpmsgfs_ofile_s *fs_head; /* Singly-linked list of open files */
+  char                       fs_root[PATH_MAX];
+  void                       *handle;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int     rpmsgfs_open(FAR struct file *filep, FAR const char *relpath,
+                            int oflags, mode_t mode);
+static int     rpmsgfs_close(FAR struct file *filep);
+static ssize_t rpmsgfs_read(FAR struct file *filep, FAR char *buffer,
+                            size_t buflen);
+static ssize_t rpmsgfs_write(FAR struct file *filep, FAR const char *buffer,
+                             size_t buflen);
+static off_t   rpmsgfs_seek(FAR struct file *filep, off_t offset,
+                            int whence);
+static int     rpmsgfs_ioctl(FAR struct file *filep, int cmd,
+                             unsigned long arg);
+
+static int     rpmsgfs_sync(FAR struct file *filep);
+static int     rpmsgfs_dup(FAR const struct file *oldp,
+                           FAR struct file *newp);
+static int     rpmsgfs_fstat(FAR const struct file *filep,
+                             FAR struct stat *buf);
+static int     rpmsgfs_fchstat(FAR const struct file *filep,
+                               FAR const struct stat *buf, int flags);
+static int     rpmsgfs_ftruncate(FAR struct file *filep,
+                                 off_t length);
+
+static int     rpmsgfs_opendir(FAR struct inode *mountpt,
+                               FAR const char *relpath,
+                               FAR struct fs_dirent_s *dir);
+static int     rpmsgfs_closedir(FAR struct inode *mountpt,
+                                FAR struct fs_dirent_s *dir);
+static int     rpmsgfs_readdir(FAR struct inode *mountpt,
+                               FAR struct fs_dirent_s *dir);
+static int     rpmsgfs_rewinddir(FAR struct inode *mountpt,
+                                 FAR struct fs_dirent_s *dir);
+
+static int     rpmsgfs_bind(FAR struct inode *blkdriver,
+                            FAR const void *data, FAR void **handle);
+static int     rpmsgfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
+                              unsigned int flags);
+static int     rpmsgfs_statfs(FAR struct inode *mountpt,
+                              FAR struct statfs *buf);
+
+static int     rpmsgfs_unlink(FAR struct inode *mountpt,
+                              FAR const char *relpath);
+static int     rpmsgfs_mkdir(FAR struct inode *mountpt,
+                             FAR const char *relpath, mode_t mode);
+static int     rpmsgfs_rmdir(FAR struct inode *mountpt, const char *relpath);
+static int     rpmsgfs_rename(FAR struct inode *mountpt,
+                              FAR const char *oldrelpath,
+                              FAR const char *newrelpath);
+static int     rpmsgfs_stat(FAR struct inode *mountpt,
+                            FAR const char *relpath, FAR struct stat *buf);
+static int     rpmsgfs_chstat(FAR struct inode *mountpt,
+                              FAR const char *relpath,
+                              FAR const struct stat *buf, int flags);
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* See fs_mount.c -- this structure is explicitly externed there.
+ * We use the old-fashioned kind of initializers so that this will compile
+ * with any compiler.
+ */
+
+const struct mountpt_operations rpmsgfs_operations =
+{
+  rpmsgfs_open,          /* open */
+  rpmsgfs_close,         /* close */
+  rpmsgfs_read,          /* read */
+  rpmsgfs_write,         /* write */
+  rpmsgfs_seek,          /* seek */
+  rpmsgfs_ioctl,         /* ioctl */
+
+  rpmsgfs_sync,          /* sync */
+  rpmsgfs_dup,           /* dup */
+  rpmsgfs_fstat,         /* fstat */
+  rpmsgfs_fchstat,       /* fchstat */
+  rpmsgfs_ftruncate,     /* ftruncate */
+
+  rpmsgfs_opendir,       /* opendir */
+  rpmsgfs_closedir,      /* closedir */
+  rpmsgfs_readdir,       /* readdir */
+  rpmsgfs_rewinddir,     /* rewinddir */
+
+  rpmsgfs_bind,          /* bind */
+  rpmsgfs_unbind,        /* unbind */
+  rpmsgfs_statfs,        /* statfs */
+
+  rpmsgfs_unlink,        /* unlink */
+  rpmsgfs_mkdir,         /* mkdir */
+  rpmsgfs_rmdir,         /* rmdir */
+  rpmsgfs_rename,        /* rename */
+  rpmsgfs_stat,          /* stat */
+  rpmsgfs_chstat,        /* chstat */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rpmsgfs_semtake
+ ****************************************************************************/
+
+static int rpmsgfs_semtake(FAR struct rpmsgfs_mountpt_s *fs)
+{
+  return nxsem_wait_uninterruptible(&fs->fs_sem);
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_semgive
+ ****************************************************************************/
+
+static void rpmsgfs_semgive(FAR struct rpmsgfs_mountpt_s *fs)
+{
+  nxsem_post(&fs->fs_sem);
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_mkpath
+ *
+ * Description: Build absolute host path from relative NuttX path.
+ *
+ ****************************************************************************/
+
+static void rpmsgfs_mkpath(FAR struct rpmsgfs_mountpt_s  *fs,
+                           FAR const char *relpath,
+                           FAR char *path, int pathlen)
+{
+  int depth = 0;
+  int first;
+  int x;
+
+  /* Copy base host path to output */
+
+  strncpy(path, fs->fs_root, pathlen);
+
+  /* Be sure we aren't trying to use ".." to display outside of our
+   * mounted path.
+   */
+
+  x = 0;
+  while (relpath[x] == '/')
+    {
+      x++;
+    }
+
+  first = x;
+
+  while (relpath[x] != '\0')
+    {
+      /* Test for ".." occurrence */
+
+      if (strncmp(&relpath[x], "..", 2) == 0)
+        {
+          /* Reduce depth by 1 */
+
+          depth--;
+          x += 2;
+        }
+
+      else if (relpath[x] == '/' && relpath[x + 1] != '/' &&
+               relpath[x + 1] != '\0')
+        {
+          depth++;
+          x++;
+        }
+      else
+        {
+          x++;
+        }
+    }
+
+  if (depth >= 0)
+    {
+      strncat(path, &relpath[first], pathlen - strlen(path) - 1);
+    }
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_open
+ ****************************************************************************/
+
+static int rpmsgfs_open(FAR struct file *filep, FAR const char *relpath,
+                        int oflags, mode_t mode)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s  *hf;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT((filep->f_priv == NULL) && (filep->f_inode != NULL));
+
+  /* Get the mountpoint inode reference from the file structure and the
+   * mountpoint private data from the inode structure
+   */
+
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Allocate memory for the open file */
+
+  hf = (struct rpmsgfs_ofile_s *) kmm_malloc(sizeof *hf);
+  if (hf == NULL)
+    {
+      ret = -ENOMEM;
+      goto errout_with_semaphore;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Try to open the file in the host file system */
+
+  hf->fd = rpmsgfs_client_open(fs->handle, path, oflags, mode);
+  if (hf->fd < 0)
+    {
+      /* Error opening file */
+
+      ret = -EBADF;
+      goto errout_with_buffer;
+    }
+
+  /* In write/append mode, we need to set the file pointer to the end of the
+   * file.
+   */
+
+  if ((oflags & (O_APPEND | O_WRONLY)) == (O_APPEND | O_WRONLY))
+    {
+      ret = rpmsgfs_client_lseek(fs->handle, hf->fd, 0, SEEK_END);
+      if (ret >= 0)
+        {
+          filep->f_pos = ret;
+        }
+      else
+        {
+          goto errout_with_buffer;
+        }
+    }
+
+  /* Attach the private date to the struct file instance */
+
+  filep->f_priv = hf;
+
+  /* Then insert the new instance into the mountpoint structure.
+   * It needs to be there (1) to handle error conditions that effect
+   * all files, and (2) to inform the umount logic that we are busy
+   * (but a simple reference count could have done that).
+   */
+
+  hf->fnext = fs->fs_head;
+  hf->crefs = 1;
+  hf->oflags = oflags;
+  fs->fs_head = hf;
+
+  ret = OK;
+  goto errout_with_semaphore;
+
+errout_with_buffer:
+  kmm_free(hf);
+
+errout_with_semaphore:
+  rpmsgfs_semgive(fs);
+  if (ret == -EINVAL)
+    {
+      ret = -EIO;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_close
+ ****************************************************************************/
+
+static int rpmsgfs_close(FAR struct file *filep)
+{
+  FAR struct inode            *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s   *hf;
+  FAR struct rpmsgfs_ofile_s   *nextfile;
+  FAR struct rpmsgfs_ofile_s   *prevfile;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+  hf    = filep->f_priv;
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Check if we are the last one with a reference to the file and
+   * only close if we are.
+   */
+
+  if (hf->crefs > 1)
+    {
+      /* The file is opened more than once.  Just decrement the
+       * reference count and return.
+       */
+
+      hf->crefs--;
+      goto okout;
+    }
+
+  /* Remove ourselves from the linked list */
+
+  nextfile = fs->fs_head;
+  prevfile = nextfile;
+  while ((nextfile != hf) && (nextfile != NULL))
+    {
+      /* Save the previous file pointer too */
+
+      prevfile = nextfile;
+      nextfile = nextfile->fnext;
+    }
+
+  if (nextfile != NULL)
+    {
+      /* Test if we were the first entry */
+
+      if (nextfile == fs->fs_head)
+        {
+          /* Assign a new head */
+
+          fs->fs_head = nextfile->fnext;
+        }
+      else
+        {
+          /* Take ourselves out of the list */
+
+          prevfile->fnext = nextfile->fnext;
+        }
+    }
+
+  /* Close the host file */
+
+  rpmsgfs_client_close(fs->handle, hf->fd);
+
+  /* Now free the pointer */
+
+  filep->f_priv = NULL;
+  kmm_free(hf);
+
+okout:
+  rpmsgfs_semgive(fs);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_read
+ ****************************************************************************/
+
+static ssize_t rpmsgfs_read(FAR struct file *filep, FAR char *buffer,
+                            size_t buflen)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  ssize_t ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host to perform the read */
+
+  ret = rpmsgfs_client_read(fs->handle, hf->fd, buffer, buflen);
+  if (ret > 0)
+    {
+      filep->f_pos += ret;
+    }
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_write
+ ****************************************************************************/
+
+static ssize_t rpmsgfs_write(FAR struct file *filep, const char *buffer,
+                             size_t buflen)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  ssize_t ret;
+
+  /* Sanity checks.  I have seen the following assertion misfire if
+   * CONFIG_DEBUG_MM is enabled while re-directing output to a
+   * file.  In this case, the debug output can get generated while
+   * the file is being opened,  FAT data structures are being allocated,
+   * and things are generally in a perverse state.
+   */
+
+#ifdef CONFIG_DEBUG_MM
+  if (filep->f_priv == NULL || filep->f_inode == NULL)
+    {
+      return -ENXIO;
+    }
+#else
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+#endif
+
+  /* Recover our private data from the struct file instance */
+
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Test the permissions.  Only allow write if the file was opened with
+   * write flags.
+   */
+
+  if ((hf->oflags & O_WROK) == 0)
+    {
+      ret = -EACCES;
+      goto errout_with_semaphore;
+    }
+
+  /* Call the host to perform the write */
+
+  ret = rpmsgfs_client_write(fs->handle, hf->fd, buffer, buflen);
+  if (ret > 0)
+    {
+      filep->f_pos += ret;
+    }
+
+errout_with_semaphore:
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_seek
+ ****************************************************************************/
+
+static off_t rpmsgfs_seek(FAR struct file *filep, off_t offset, int whence)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  off_t ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call our internal routine to perform the seek */
+
+  ret = rpmsgfs_client_lseek(fs->handle, hf->fd, offset, whence);
+  if (ret >= 0)
+    {
+      filep->f_pos = ret;
+    }
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_ioctl
+ ****************************************************************************/
+
+static int rpmsgfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call our internal routine to perform the ioctl */
+
+  ret = rpmsgfs_client_ioctl(fs->handle, hf->fd, cmd, arg);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_sync
+ *
+ * Description: Synchronize the file state on disk to match internal, in-
+ *   memory state.
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_sync(FAR struct file *filep)
+{
+  FAR struct inode            *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s   *hf;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+  fs    = inode->i_private;
+
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  rpmsgfs_client_sync(fs->handle, hf->fd);
+
+  rpmsgfs_semgive(fs);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_dup
+ *
+ * Description: Duplicate open file data in the new file structure.
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_dup(FAR const struct file *oldp, FAR struct file *newp)
+{
+  FAR struct rpmsgfs_ofile_s *sf;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(oldp->f_priv != NULL &&
+              newp->f_priv == NULL &&
+              newp->f_inode != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  sf = oldp->f_priv;
+
+  DEBUGASSERT(sf != NULL);
+
+  /* Just increment the reference count on the ofile */
+
+  sf->crefs++;
+  newp->f_priv = (FAR void *)sf;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_fstat
+ *
+ * Description:
+ *   Obtain information about an open file associated with the file
+ *   descriptor 'fd', and will write it to the area pointed to by 'buf'.
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  int ret = OK;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep != NULL && buf != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+
+  fs    = inode->i_private;
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host to perform the read */
+
+  ret = rpmsgfs_client_fstat(fs->handle, hf->fd, buf);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_fchstat
+ *
+ * Description:
+ *   Change information about an open file associated with the file
+ *   descriptor 'fd'.
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_fchstat(FAR const struct file *filep,
+                           FAR const struct stat *buf, int flags)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  int ret = OK;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep != NULL && buf != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+
+  fs    = inode->i_private;
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host to perform the change */
+
+  ret = rpmsgfs_client_fchstat(fs->handle, hf->fd, buf, flags);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_ftruncate
+ *
+ * Description:
+ *   Set the length of the open, regular file associated with the file
+ *   structure 'filep' to 'length'.
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_ftruncate(FAR struct file *filep, off_t length)
+{
+  FAR struct inode *inode;
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR struct rpmsgfs_ofile_s *hf;
+  int ret = OK;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(filep != NULL);
+
+  /* Recover our private data from the struct file instance */
+
+  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+  hf    = filep->f_priv;
+  inode = filep->f_inode;
+
+  fs    = inode->i_private;
+  DEBUGASSERT(fs != NULL);
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host to perform the truncate */
+
+  ret = rpmsgfs_client_ftruncate(fs->handle, hf->fd, length);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_opendir
+ *
+ * Description: Open a directory for read access
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_opendir(FAR struct inode *mountpt,
+                           FAR const char *relpath,
+                           FAR struct fs_dirent_s *dir)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
+
+  /* Recover our private data from the inode instance */
+
+  fs = mountpt->i_private;
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Call the host's opendir function */
+
+  dir->u.rpmsgfs.fs_dir = rpmsgfs_client_opendir(fs->handle, path);
+  if (dir->u.rpmsgfs.fs_dir == NULL)
+    {
+      ret = -ENOENT;
+      goto errout_with_semaphore;
+    }
+
+  ret = OK;
+
+errout_with_semaphore:
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_closedir
+ *
+ * Description: Open a directory for read access
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_closedir(FAR struct inode *mountpt,
+                            FAR struct fs_dirent_s *dir)
+{
+  struct rpmsgfs_mountpt_s  *fs;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
+
+  /* Recover our private data from the inode instance */
+
+  fs = mountpt->i_private;
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host's closedir function */
+
+  rpmsgfs_client_closedir(fs->handle, dir->u.rpmsgfs.fs_dir);
+
+  rpmsgfs_semgive(fs);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_readdir
+ *
+ * Description: Read the next directory entry
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_readdir(FAR struct inode *mountpt,
+                           FAR struct fs_dirent_s *dir)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
+
+  /* Recover our private data from the inode instance */
+
+  fs = mountpt->i_private;
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host OS's readdir function */
+
+  ret = rpmsgfs_client_readdir(fs->handle,
+                               dir->u.rpmsgfs.fs_dir, &dir->fd_dir);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_rewindir
+ *
+ * Description: Reset directory read to the first entry
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_rewinddir(FAR struct inode *mountpt,
+                             FAR struct fs_dirent_s *dir)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
+
+  /* Recover our private data from the inode instance */
+
+  fs = mountpt->i_private;
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host and let it do all the work */
+
+  rpmsgfs_client_rewinddir(fs->handle, dir->u.rpmsgfs.fs_dir);
+
+  rpmsgfs_semgive(fs);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_bind
+ *
+ * Description: This implements a portion of the mount operation. This
+ *  function allocates and initializes the mountpoint private data and
+ *  binds the blockdriver inode to the filesystem private data.  The final
+ *  binding of the private data (containing the blockdriver) to the
+ *  mountpoint is performed by mount().
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_bind(FAR struct inode *blkdriver, FAR const void *data,
+                        FAR void **handle)
+{
+  FAR struct rpmsgfs_mountpt_s  *fs;
+  FAR const char *cpuname = NULL;
+  FAR char *options;
+  char *saveptr;
+  char *ptr;
+  int len;
+  int ret;
+
+  /* Validate the block driver is NULL */
+
+  if (blkdriver || !data)
+    {
+      return -ENODEV;
+    }
+
+  /* Create an instance of the mountpt state structure */
+
+  fs = (FAR struct rpmsgfs_mountpt_s *)
+    kmm_zalloc(sizeof(struct rpmsgfs_mountpt_s));
+
+  if (fs == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* The options we support are:
+   *  "fs=whatever,cpu=cpuname", remote dir
+   */
+
+  options = strdup(data);
+  if (!options)
+    {
+      kmm_free(fs);
+      return -ENOMEM;
+    }
+
+  ptr = strtok_r(options, ",", &saveptr);
+  while (ptr != NULL)
+    {
+      if ((strncmp(ptr, "fs=", 3) == 0))
+        {
+          strncpy(fs->fs_root, &ptr[3], sizeof(fs->fs_root));
+        }
+      else if ((strncmp(ptr, "cpu=", 4) == 0))
+        {
+          cpuname = &ptr[4];
+        }
+
+      ptr = strtok_r(NULL, ",", &saveptr);
+    }
+
+  ret = rpmsgfs_client_bind(&fs->handle, cpuname);
+  kmm_free(options);
+  if (ret < 0)
+    {
+      kmm_free(fs);
+      return ret;
+    }
+
+  /* If the global semaphore hasn't been initialized, then
+   * initialized it now.
+   */
+
+  /* Initialize the semaphore that controls access */
+
+  nxsem_init(&fs->fs_sem, 0, 1);
+
+  /* Initialize the allocated mountpt state structure.  The filesystem is
+   * responsible for one reference ont the blkdriver inode and does not
+   * have to addref() here (but does have to release in ubind().
+   */
+
+  fs->fs_head = NULL;
+
+  /* Now perform the mount.  */
+
+  len = strlen(fs->fs_root);
+  if (len > 1 && fs->fs_root[len - 1] == '/')
+    {
+      /* Remove trailing '/' */
+
+      fs->fs_root[len - 1] = '\0';
+    }
+
+  /* Append a '/' to the name now */
+
+  if (fs->fs_root[len - 1] != '/')
+    {
+      strcat(fs->fs_root, "/");
+    }
+
+  *handle = (FAR void *)fs;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_unbind
+ *
+ * Description: This implements the filesystem portion of the umount
+ *   operation.
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
+                          unsigned int flags)
+{
+  FAR struct rpmsgfs_mountpt_s *fs = (FAR struct rpmsgfs_mountpt_s *)handle;
+  int ret;
+
+  if (!fs)
+    {
+      return -EINVAL;
+    }
+
+  /* Check if there are sill any files opened on the filesystem. */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (fs->fs_head != NULL)
+    {
+      /* We cannot unmount now.. there are open files */
+
+      rpmsgfs_semgive(fs);
+
+      /* This implementation currently only supports unmounting if there are
+       * no open file references.
+       */
+
+      return (flags != 0) ? -ENOSYS : -EBUSY;
+    }
+
+  ret = rpmsgfs_client_unbind(fs->handle);
+  rpmsgfs_semgive(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  nxsem_destroy(&fs->fs_sem);
+  kmm_free(fs);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_statfs
+ *
+ * Description: Return filesystem statistics
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Call the host fs to perform the statfs */
+
+  memset(buf, 0, sizeof(struct statfs));
+  ret = rpmsgfs_client_statfs(fs->handle, fs->fs_root, buf);
+  buf->f_type = RPMSGFS_MAGIC;
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_unlink
+ *
+ * Description: Remove a file
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_unlink(FAR struct inode *mountpt, FAR const char *relpath)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Call the host fs to perform the unlink */
+
+  ret = rpmsgfs_client_unlink(fs->handle, path);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_mkdir
+ *
+ * Description: Create a directory
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath,
+                         mode_t mode)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Call the host FS to do the mkdir */
+
+  ret = rpmsgfs_client_mkdir(fs->handle, path, mode);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_rmdir
+ *
+ * Description: Remove a directory
+ *
+ ****************************************************************************/
+
+int rpmsgfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  /* Take the semaphore */
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Call the host FS to do the mkdir */
+
+  ret = rpmsgfs_client_rmdir(fs->handle, path);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_rename
+ *
+ * Description: Rename a file or directory
+ *
+ ****************************************************************************/
+
+int rpmsgfs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath,
+                   FAR const char *newrelpath)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char oldpath[PATH_MAX];
+  char newpath[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  strncpy(oldpath, fs->fs_root, sizeof(oldpath));
+  strncat(oldpath, oldrelpath, sizeof(oldpath)-strlen(oldpath)-1);
+  strncpy(newpath, fs->fs_root, sizeof(newpath));
+  strncat(newpath, newrelpath, sizeof(newpath)-strlen(newpath)-1);
+
+  /* Call the host FS to do the mkdir */
+
+  ret = rpmsgfs_client_rename(fs->handle, oldpath, newpath);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_stat
+ *
+ * Description: Return information about a file or directory
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
+                        FAR struct stat *buf)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Call the host FS to do the stat operation */
+
+  ret = rpmsgfs_client_stat(fs->handle, path, buf);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_chstat
+ *
+ * Description: Change information about a file or directory
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_chstat(FAR struct inode *mountpt, FAR const char *relpath,
+                          FAR const struct stat *buf, int flags)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  char path[PATH_MAX];
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = rpmsgfs_semtake(fs);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, sizeof(path));
+
+  /* Call the host FS to do the chstat operation */
+
+  ret = rpmsgfs_client_chstat(fs->handle, path, buf, flags);
+
+  rpmsgfs_semgive(fs);
+  return ret;
+}
diff --git a/fs/rpmsgfs/rpmsgfs.h b/fs/rpmsgfs/rpmsgfs.h
new file mode 100644
index 0000000..7f1014d
--- /dev/null
+++ b/fs/rpmsgfs/rpmsgfs.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+ * fs/rpmsgfs/rpmsgfs.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __FS_RPMSGFS_H
+#define __FS_RPMSGFS_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(x)         (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#define RPMSGFS_NAME_PREFIX     "rpmsgfs-"
+
+#define RPMSGFS_OPEN            1
+#define RPMSGFS_CLOSE           2
+#define RPMSGFS_READ            3
+#define RPMSGFS_WRITE           4
+#define RPMSGFS_LSEEK           5
+#define RPMSGFS_IOCTL           6
+#define RPMSGFS_SYNC            7
+#define RPMSGFS_DUP             8
+#define RPMSGFS_FSTAT           9
+#define RPMSGFS_FTRUNCATE       10
+#define RPMSGFS_OPENDIR         11
+#define RPMSGFS_READDIR         12
+#define RPMSGFS_REWINDDIR       13
+#define RPMSGFS_CLOSEDIR        14
+#define RPMSGFS_STATFS          15
+#define RPMSGFS_UNLINK          16
+#define RPMSGFS_MKDIR           17
+#define RPMSGFS_RMDIR           18
+#define RPMSGFS_RENAME          19
+#define RPMSGFS_STAT            20
+#define RPMSGFS_FCHSTAT         21
+#define RPMSGFS_CHSTAT          22
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+begin_packed_struct struct rpmsgfs_header_s
+{
+  uint32_t                command;
+  int32_t                 result;
+  uint64_t                cookie;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_open_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 flags;
+  int32_t                 mode;
+  char                    pathname[0];
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_close_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 fd;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_read_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 fd;
+  uint32_t                count;
+  char                    buf[0];
+} end_packed_struct;
+
+#define rpmsgfs_write_s rpmsgfs_read_s
+
+begin_packed_struct struct rpmsgfs_lseek_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 fd;
+  int32_t                 whence;
+  int32_t                 offset;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_ioctl_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 fd;
+  int32_t                 request;
+  int32_t                 arg;
+} end_packed_struct;
+
+#define rpmsgfs_sync_s rpmsgfs_close_s
+#define rpmsgfs_dup_s  rpmsgfs_close_s
+
+begin_packed_struct struct rpmsgfs_fstat_s
+{
+  struct rpmsgfs_header_s header;
+  union
+  {
+    struct stat           buf;
+    uint32_t              reserved[16];
+  };
+
+  union
+  {
+    int32_t               fd;
+    char                  pathname[0];
+  };
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_ftruncate_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 fd;
+  int32_t                 length;
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_opendir_s
+{
+  struct rpmsgfs_header_s header;
+  char                    pathname[0];
+} end_packed_struct;
+
+begin_packed_struct struct rpmsgfs_readdir_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 fd;
+  uint32_t                type;
+  char                    name[0];
+} end_packed_struct;
+
+#define rpmsgfs_rewinddir_s rpmsgfs_close_s
+#define rpmsgfs_closedir_s rpmsgfs_close_s
+
+begin_packed_struct struct rpmsgfs_statfs_s
+{
+  struct rpmsgfs_header_s header;
+  union
+  {
+    struct statfs         buf;
+    uint32_t              reserved[16];
+  };
+
+  char                    pathname[0];
+} end_packed_struct;
+
+#define rpmsgfs_unlink_s rpmsgfs_opendir_s
+
+begin_packed_struct struct rpmsgfs_mkdir_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 mode;
+  uint32_t                reserved;
+  char                    pathname[0];
+} end_packed_struct;
+
+#define rpmsgfs_rmdir_s rpmsgfs_opendir_s
+#define rpmsgfs_rename_s rpmsgfs_opendir_s
+#define rpmsgfs_stat_s rpmsgfs_fstat_s
+
+begin_packed_struct struct rpmsgfs_fchstat_s
+{
+  struct rpmsgfs_header_s header;
+  int32_t                 flags;
+  union
+  {
+    struct stat           buf;
+    uint32_t              reserved[16];
+  };
+
+  union
+  {
+    int32_t               fd;
+    char                  pathname[0];
+  };
+} end_packed_struct;
+
+#define rpmsgfs_chstat_s rpmsgfs_fchstat_s
+
+/****************************************************************************
+ * Internal function prototypes
+ ****************************************************************************/
+
+int       rpmsgfs_client_open(FAR void *handle,
+                              FAR const char *pathname, int flags, int mode);
+int       rpmsgfs_client_close(FAR void *handle, int fd);
+ssize_t   rpmsgfs_client_read(FAR void *handle, int fd,
+                              FAR void *buf, size_t count);
+ssize_t   rpmsgfs_client_write(FAR void *handle, int fd,
+                               FAR const void *buf, size_t count);
+off_t     rpmsgfs_client_lseek(FAR void *handle, int fd,
+                               off_t offset, int whence);
+int       rpmsgfs_client_ioctl(FAR void *handle, int fd,
+                               int request, unsigned long arg);
+void      rpmsgfs_client_sync(FAR void *handle, int fd);
+int       rpmsgfs_client_dup(FAR void *handle, int fd);
+int       rpmsgfs_client_fstat(FAR void *handle, int fd,
+                               FAR struct stat *buf);
+int       rpmsgfs_client_fchstat(FAR void *handle, int fd,
+                                 FAR const struct stat *buf, int flags);
+int       rpmsgfs_client_ftruncate(FAR void *handle, int fd, off_t length);
+FAR void *rpmsgfs_client_opendir(FAR void *handle, FAR const char *name);
+int       rpmsgfs_client_readdir(FAR void *handle, FAR void *dirp,
+                                 FAR struct dirent *entry);
+void      rpmsgfs_client_rewinddir(FAR void *handle, FAR void *dirp);
+int       rpmsgfs_client_bind(FAR void **handle, FAR const char *cpuname);
+int       rpmsgfs_client_unbind(FAR void *handle);
+int       rpmsgfs_client_closedir(FAR void *handle, FAR void *dirp);
+int       rpmsgfs_client_statfs(FAR void *handle, FAR const char *path,
+                                FAR struct statfs *buf);
+int       rpmsgfs_client_unlink(FAR void *handle, FAR const char *pathname);
+int       rpmsgfs_client_mkdir(FAR void *handle, FAR const char *pathname,
+                               mode_t mode);
+int       rpmsgfs_client_rmdir(FAR void *handle, FAR const char *pathname);
+int       rpmsgfs_client_rename(FAR void *handle, FAR const char *oldpath,
+                                FAR const char *newpath);
+int       rpmsgfs_client_stat(FAR void *handle, FAR const char *path,
+                              FAR struct stat *buf);
+int       rpmsgfs_client_chstat(FAR void *handle, FAR const char *path,
+                                FAR const struct stat *buf, int flags);
+
+#endif /* __FS_RPMSGFS_H */
diff --git a/fs/rpmsgfs/rpmsgfs_client.c b/fs/rpmsgfs/rpmsgfs_client.c
new file mode 100644
index 0000000..430a2f4
--- /dev/null
+++ b/fs/rpmsgfs/rpmsgfs_client.c
@@ -0,0 +1,819 @@
+/****************************************************************************
+ * fs/rpmsgfs/rpmsgfs_client.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/rpmsgfs.h>
+#include <nuttx/rptun/openamp.h>
+#include <nuttx/semaphore.h>
+
+#include "rpmsgfs.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rpmsgfs_s
+{
+  struct rpmsg_endpoint ept;
+  char                  cpuname[RPMSG_NAME_SIZE];
+};
+
+struct rpmsgfs_cookie_s
+{
+  sem_t     sem;
+  int       result;
+  FAR void  *data;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rpmsgfs_default_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv);
+static int rpmsgfs_read_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv);
+static int rpmsgfs_readdir_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgfs_statfs_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static void rpmsgfs_device_created(struct rpmsg_device *rdev,
+                                   FAR void *priv_);
+static void rpmsgfs_device_destroy(struct rpmsg_device *rdev,
+                                   FAR void *priv_);
+static int  rpmsgfs_ept_cb(FAR struct rpmsg_endpoint *ept,
+                           FAR void *data, size_t len, uint32_t src,
+                           FAR void *priv);
+static int rpmsgfs_send_recv(FAR struct rpmsgfs_s *priv,
+                             uint32_t command, bool copy,
+                             FAR struct rpmsgfs_header_s *msg,
+                             int len, FAR void *data);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const rpmsg_ept_cb g_rpmsgfs_handler[] =
+{
+  [RPMSGFS_OPEN]      = rpmsgfs_default_handler,
+  [RPMSGFS_CLOSE]     = rpmsgfs_default_handler,
+  [RPMSGFS_READ]      = rpmsgfs_read_handler,
+  [RPMSGFS_WRITE]     = rpmsgfs_default_handler,
+  [RPMSGFS_LSEEK]     = rpmsgfs_default_handler,
+  [RPMSGFS_IOCTL]     = rpmsgfs_default_handler,
+  [RPMSGFS_SYNC]      = rpmsgfs_default_handler,
+  [RPMSGFS_DUP]       = rpmsgfs_default_handler,
+  [RPMSGFS_FSTAT]     = rpmsgfs_stat_handler,
+  [RPMSGFS_FTRUNCATE] = rpmsgfs_default_handler,
+  [RPMSGFS_OPENDIR]   = rpmsgfs_default_handler,
+  [RPMSGFS_READDIR]   = rpmsgfs_readdir_handler,
+  [RPMSGFS_REWINDDIR] = rpmsgfs_default_handler,
+  [RPMSGFS_CLOSEDIR]  = rpmsgfs_default_handler,
+  [RPMSGFS_STATFS]    = rpmsgfs_statfs_handler,
+  [RPMSGFS_UNLINK]    = rpmsgfs_default_handler,
+  [RPMSGFS_MKDIR]     = rpmsgfs_default_handler,
+  [RPMSGFS_RMDIR]     = rpmsgfs_default_handler,
+  [RPMSGFS_RENAME]    = rpmsgfs_default_handler,
+  [RPMSGFS_STAT]      = rpmsgfs_stat_handler,
+  [RPMSGFS_FCHSTAT]   = rpmsgfs_default_handler,
+  [RPMSGFS_CHSTAT]    = rpmsgfs_default_handler,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int rpmsgfs_default_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  FAR struct rpmsgfs_cookie_s *cookie =
+      (struct rpmsgfs_cookie_s *)(uintptr_t)header->cookie;
+
+  cookie->result = header->result;
+  if (cookie->result >= 0 && cookie->data)
+    {
+      memcpy(cookie->data, data, len);
+    }
+
+  nxsem_post(&cookie->sem);
+
+  return 0;
+}
+
+static int rpmsgfs_read_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  FAR struct rpmsgfs_cookie_s *cookie =
+      (struct rpmsgfs_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgfs_read_s *rsp = data;
+
+  cookie->result = header->result;
+  if (cookie->result > 0)
+    {
+      memcpy(cookie->data, rsp->buf, B2C(cookie->result));
+    }
+
+  nxsem_post(&cookie->sem);
+
+  return 0;
+}
+
+static int rpmsgfs_readdir_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  FAR struct rpmsgfs_cookie_s *cookie =
+      (struct rpmsgfs_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgfs_readdir_s *rsp = data;
+  FAR struct dirent *entry = cookie->data;
+
+  cookie->result = header->result;
+  if (cookie->result >= 0)
+    {
+      nbstr2cstr(entry->d_name, rsp->name, NAME_MAX);
+      entry->d_name[NAME_MAX] = '\0';
+      entry->d_type = rsp->type;
+    }
+
+  nxsem_post(&cookie->sem);
+
+  return 0;
+}
+
+static int rpmsgfs_statfs_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  FAR struct rpmsgfs_cookie_s *cookie =
+      (struct rpmsgfs_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgfs_statfs_s *rsp = data;
+  FAR struct statfs *buf = cookie->data;
+
+  cookie->result = header->result;
+  if (cookie->result >= 0)
+    {
+      buf->f_type    = rsp->buf.f_type;
+      buf->f_namelen = rsp->buf.f_namelen;
+      buf->f_bsize   = B2C(rsp->buf.f_bsize);
+      buf->f_blocks  = rsp->buf.f_blocks;
+      buf->f_bfree   = rsp->buf.f_bfree;
+      buf->f_bavail  = rsp->buf.f_bavail;
+      buf->f_files   = rsp->buf.f_files;
+      buf->f_ffree   = rsp->buf.f_ffree;
+    }
+
+  nxsem_post(&cookie->sem);
+
+  return 0;
+}
+
+static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  FAR struct rpmsgfs_cookie_s *cookie =
+      (struct rpmsgfs_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgfs_stat_s *rsp = data;
+  FAR struct stat *buf = cookie->data;
+
+  cookie->result = header->result;
+  if (cookie->result >= 0)
+    {
+      buf->st_dev     = rsp->buf.st_dev;
+      buf->st_ino     = rsp->buf.st_ino;
+      buf->st_mode    = rsp->buf.st_mode;
+      buf->st_nlink   = rsp->buf.st_nlink;
+      buf->st_uid     = rsp->buf.st_uid;
+      buf->st_gid     = rsp->buf.st_gid;
+      buf->st_rdev    = rsp->buf.st_rdev;
+      buf->st_size    = B2C(rsp->buf.st_size);
+      buf->st_atime   = rsp->buf.st_atime;
+      buf->st_mtime   = rsp->buf.st_mtime;
+      buf->st_ctime   = rsp->buf.st_ctime;
+      buf->st_blksize = B2C(rsp->buf.st_blksize);
+      buf->st_blocks  = rsp->buf.st_blocks;
+    }
+
+  nxsem_post(&cookie->sem);
+
+  return 0;
+}
+
+static void rpmsgfs_device_created(FAR struct rpmsg_device *rdev,
+                                   FAR void *priv_)
+{
+  FAR struct rpmsgfs_s *priv = priv_;
+  char buf[RPMSG_NAME_SIZE];
+
+  if (strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0)
+    {
+      priv->ept.priv = priv;
+      snprintf(buf, sizeof(buf), "%s%p", RPMSGFS_NAME_PREFIX, priv);
+      rpmsg_create_ept(&priv->ept, rdev, buf,
+                       RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
+                       rpmsgfs_ept_cb, NULL);
+    }
+}
+
+static void rpmsgfs_device_destroy(FAR struct rpmsg_device *rdev,
+                                   FAR void *priv_)
+{
+  struct rpmsgfs_s *priv = priv_;
+
+  if (strcmp(priv->cpuname, rpmsg_get_cpuname(rdev)) == 0)
+    {
+      rpmsg_destroy_ept(&priv->ept);
+    }
+}
+
+static int rpmsgfs_ept_cb(FAR struct rpmsg_endpoint *ept,
+                          FAR void *data, size_t len, uint32_t src,
+                          FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  uint32_t command = header->command;
+
+  if (command < ARRAY_SIZE(g_rpmsgfs_handler))
+    {
+      return g_rpmsgfs_handler[command](ept, data, len, src, priv);
+    }
+
+  return -EINVAL;
+}
+
+static int rpmsgfs_send_recv(FAR struct rpmsgfs_s *priv,
+                             uint32_t command, bool copy,
+                             FAR struct rpmsgfs_header_s *msg,
+                             int len, FAR void *data)
+{
+  FAR struct rpmsgfs_cookie_s cookie;
+  int ret;
+
+  memset(&cookie, 0, sizeof(cookie));
+  nxsem_init(&cookie.sem, 0, 0);
+  nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE);
+
+  if (data)
+    {
+      cookie.data = data;
+    }
+  else if (copy)
+    {
+      cookie.data = msg;
+    }
+
+  msg->command = command;
+  msg->result  = -ENXIO;
+  msg->cookie  = (uintptr_t)&cookie;
+
+  if (copy)
+    {
+      ret = rpmsg_send(&priv->ept, msg, len);
+    }
+  else
+    {
+      ret = rpmsg_send_nocopy(&priv->ept, msg, len);
+    }
+
+  if (ret < 0)
+    {
+      goto fail;
+    }
+
+  ret = nxsem_wait_uninterruptible(&cookie.sem);
+  if (ret == 0)
+    {
+      ret = cookie.result;
+    }
+
+fail:
+  nxsem_destroy(&cookie.sem);
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int rpmsgfs_client_open(FAR void *handle, FAR const char *pathname,
+                        int flags, int mode)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_open_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(pathname) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  msg->flags = flags;
+  msg->mode  = mode;
+  cstr2bstr(msg->pathname, pathname);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_OPEN, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+int rpmsgfs_client_close(FAR void *handle, int fd)
+{
+  struct rpmsgfs_close_s msg =
+  {
+    .fd = fd,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_CLOSE, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+ssize_t rpmsgfs_client_read(FAR void *handle, int fd,
+                            FAR void *buf, size_t count)
+{
+  size_t read = 0;
+  int ret = 0;
+
+  while (read < count)
+    {
+      struct rpmsgfs_read_s msg =
+      {
+        .fd    = fd,
+        .count = C2B(count - read),
+      };
+
+      ret = rpmsgfs_send_recv(handle, RPMSGFS_READ, true,
+              (FAR struct rpmsgfs_header_s *)&msg, sizeof(msg), buf);
+      if (ret <= 0)
+        {
+          break;
+        }
+
+      read += B2C(ret);
+      buf  += B2C(ret);
+    }
+
+  return read ? read : ret;
+}
+
+ssize_t rpmsgfs_client_write(FAR void *handle, int fd,
+                             FAR const void *buf, size_t count)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  size_t written = 0;
+  int ret = 0;
+
+  while (written < count)
+    {
+      FAR struct rpmsgfs_write_s *msg;
+      uint32_t space;
+
+      msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+      if (!msg)
+        {
+          ret = -ENOMEM;
+          break;
+        }
+
+      space -= sizeof(*msg);
+      if (space > count - written)
+        {
+          space = count - written;
+        }
+
+      msg->fd    = fd;
+      msg->count = C2B(space);
+      memcpy(msg->buf, buf + written, space);
+
+      ret = rpmsgfs_send_recv(priv, RPMSGFS_WRITE, false,
+                                   (FAR struct rpmsgfs_header_s *)msg,
+                                   sizeof(*msg) + space, NULL);
+      if (ret <= 0)
+        {
+          break;
+        }
+
+      written += B2C(ret);
+    }
+
+  return written ? written : ret;
+}
+
+off_t rpmsgfs_client_lseek(FAR void *handle, int fd,
+                           off_t offset, int whence)
+{
+  struct rpmsgfs_lseek_s msg =
+  {
+    .fd     = fd,
+    .offset = C2B(offset),
+    .whence = whence,
+  };
+
+  int ret;
+
+  ret = rpmsgfs_send_recv(handle, RPMSGFS_LSEEK, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+
+  return ret < 0 ? ret : B2C(ret);
+}
+
+int rpmsgfs_client_ioctl(FAR void *handle, int fd,
+                         int request, unsigned long arg)
+{
+  struct rpmsgfs_ioctl_s msg =
+  {
+    .fd      = fd,
+    .request = request,
+    .arg     = arg,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_IOCTL, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+void rpmsgfs_client_sync(FAR void *handle, int fd)
+{
+  struct rpmsgfs_sync_s msg =
+  {
+    .fd = fd,
+  };
+
+  rpmsgfs_send_recv(handle, RPMSGFS_SYNC, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+int rpmsgfs_client_dup(FAR void *handle, int fd)
+{
+  struct rpmsgfs_dup_s msg =
+  {
+    .fd = fd,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_DUP, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+int rpmsgfs_client_fstat(FAR void *handle, int fd, struct stat *buf)
+{
+  struct rpmsgfs_fstat_s msg =
+  {
+    .fd = fd,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_FSTAT, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), buf);
+}
+
+int rpmsgfs_client_ftruncate(FAR void *handle, int fd, off_t length)
+{
+  struct rpmsgfs_ftruncate_s msg =
+  {
+    .fd     = fd,
+    .length = length,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_FTRUNCATE, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+FAR void *rpmsgfs_client_opendir(FAR void *handle, FAR const char *name)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_opendir_s *msg;
+  uint32_t space;
+  size_t len;
+  int ret;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(name) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return NULL;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  cstr2bstr(msg->pathname, name);
+
+  ret = rpmsgfs_send_recv(priv, RPMSGFS_OPENDIR, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+
+  return ret < 0 ? NULL : (FAR void *)((uintptr_t)ret);
+}
+
+int rpmsgfs_client_readdir(FAR void *handle, FAR void *dirp,
+                           FAR struct dirent *entry)
+{
+  struct rpmsgfs_readdir_s msg =
+  {
+    .fd = (uintptr_t)dirp,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_READDIR, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), entry);
+}
+
+void rpmsgfs_client_rewinddir(FAR void *handle, FAR void *dirp)
+{
+  struct rpmsgfs_rewinddir_s msg =
+  {
+    .fd = (uintptr_t)dirp,
+  };
+
+  rpmsgfs_send_recv(handle, RPMSGFS_REWINDDIR, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+int rpmsgfs_client_bind(FAR void **handle, FAR const char *cpuname)
+{
+  struct rpmsgfs_s *priv;
+  int ret;
+
+  if (!cpuname)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct rpmsgfs_s));
+  if (!priv)
+    {
+      return -ENOMEM;
+    }
+
+  strncpy(priv->cpuname, cpuname, RPMSG_NAME_SIZE);
+  ret = rpmsg_register_callback(priv,
+                                rpmsgfs_device_created,
+                                rpmsgfs_device_destroy,
+                                NULL);
+  if (ret < 0)
+    {
+      kmm_free(priv);
+      return ret;
+    }
+
+  *handle = priv;
+
+  return 0;
+}
+
+int rpmsgfs_client_unbind(FAR void *handle)
+{
+  struct rpmsgfs_s *priv = handle;
+
+  rpmsg_unregister_callback(priv,
+                            rpmsgfs_device_created,
+                            rpmsgfs_device_destroy,
+                            NULL);
+
+  kmm_free(priv);
+  return 0;
+}
+
+int rpmsgfs_client_closedir(FAR void *handle, FAR void *dirp)
+{
+  struct rpmsgfs_closedir_s msg =
+  {
+    .fd = (uintptr_t)dirp,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_CLOSEDIR, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+int rpmsgfs_client_statfs(FAR void *handle, FAR const char *path,
+                          FAR struct statfs *buf)
+{
+  struct rpmsgfs_s *priv = handle;
+  struct rpmsgfs_statfs_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(path) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  cstr2bstr(msg->pathname, path);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_STATFS, false,
+          (struct rpmsgfs_header_s *)msg, len, buf);
+}
+
+int rpmsgfs_client_unlink(FAR void *handle, FAR const char *pathname)
+{
+  struct rpmsgfs_s *priv = handle;
+  struct rpmsgfs_unlink_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(pathname) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  cstr2bstr(msg->pathname, pathname);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_UNLINK, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+int rpmsgfs_client_mkdir(FAR void *handle, FAR const char *pathname,
+                         mode_t mode)
+{
+  struct rpmsgfs_s *priv = handle;
+  struct rpmsgfs_mkdir_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(pathname) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  msg->mode = mode;
+  cstr2bstr(msg->pathname, pathname);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_MKDIR, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+int rpmsgfs_client_rmdir(FAR void *handle, FAR const char *pathname)
+{
+  struct rpmsgfs_s *priv = handle;
+  struct rpmsgfs_rmdir_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(pathname) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  cstr2bstr(msg->pathname, pathname);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_RMDIR, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+int rpmsgfs_client_rename(FAR void *handle, FAR const char *oldpath,
+                          FAR const char *newpath)
+{
+  struct rpmsgfs_s *priv = handle;
+  struct rpmsgfs_rename_s *msg;
+  size_t len;
+  size_t oldlen;
+  uint32_t space;
+
+  len     = sizeof(*msg);
+  oldlen  = B2C((strlen(oldpath) + 1 + 0x7) & ~0x7);
+  len    += oldlen + B2C(strlen(newpath) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  cstr2bstr(msg->pathname, oldpath);
+  cstr2bstr(msg->pathname + oldlen, newpath);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_RENAME, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+int rpmsgfs_client_stat(FAR void *handle, FAR const char *path,
+                        FAR struct stat *buf)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_stat_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(path) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  cstr2bstr(msg->pathname, path);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_STAT, false,
+          (struct rpmsgfs_header_s *)msg, len, buf);
+}
+
+int rpmsgfs_client_fchstat(FAR void *handle, int fd,
+                           const struct stat *buf, int flags)
+{
+  struct rpmsgfs_fchstat_s msg =
+  {
+    .flags = flags,
+    .buf = *buf,
+    .fd = fd,
+  };
+
+  return rpmsgfs_send_recv(handle, RPMSGFS_FCHSTAT, true,
+          (struct rpmsgfs_header_s *)&msg, sizeof(msg), NULL);
+}
+
+int rpmsgfs_client_chstat(FAR void *handle, FAR const char *path,
+                          const FAR struct stat *buf, int flags)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_chstat_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len  = sizeof(*msg);
+  len += B2C(strlen(path) + 1);
+
+  msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  msg->flags = flags;
+  memcpy(&msg->buf, buf, sizeof(*buf));
+  cstr2bstr(msg->pathname, path);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_CHSTAT, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
diff --git a/fs/rpmsgfs/rpmsgfs_server.c b/fs/rpmsgfs/rpmsgfs_server.c
new file mode 100644
index 0000000..9a7b27b
--- /dev/null
+++ b/fs/rpmsgfs/rpmsgfs_server.c
@@ -0,0 +1,883 @@
+/****************************************************************************
+ * fs/rpmsgfs/rpmsgfs_server.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/fs/rpmsgfs.h>
+#include <nuttx/rptun/openamp.h>
+
+#include "rpmsgfs.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rpmsgfs_server_s
+{
+  struct rpmsg_endpoint ept;
+  FAR struct file     **files;
+  FAR void            **dirs;
+  int                   file_rows;
+  int                   dir_nums;
+  sem_t                 sem;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rpmsgfs_open_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv);
+static int rpmsgfs_close_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_read_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv);
+static int rpmsgfs_write_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_lseek_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_sync_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv);
+static int rpmsgfs_dup_handler(FAR struct rpmsg_endpoint *ept,
+                               FAR void *data, size_t len,
+                               uint32_t src, FAR void *priv);
+static int rpmsgfs_fstat_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_ftruncate_handler(FAR struct rpmsg_endpoint *ept,
+                                     FAR void *data, size_t len,
+                                     uint32_t src, FAR void *priv);
+static int rpmsgfs_opendir_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv);
+static int rpmsgfs_readdir_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv);
+static int rpmsgfs_rewinddir_handler(FAR struct rpmsg_endpoint *ept,
+                                     FAR void *data, size_t len,
+                                     uint32_t src, FAR void *priv);
+static int rpmsgfs_closedir_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv);
+static int rpmsgfs_statfs_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgfs_unlink_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgfs_mkdir_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_rmdir_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+static int rpmsgfs_rename_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv);
+static int rpmsgfs_fchstat_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv);
+static int rpmsgfs_chstat_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv);
+
+static void rpmsgfs_ns_bind(FAR struct rpmsg_device *rdev,
+                            FAR void *priv_, FAR const char *name,
+                            uint32_t dest);
+static void rpmsgfs_ns_unbind(FAR struct rpmsg_endpoint *ept);
+static int  rpmsgfs_ept_cb(FAR struct rpmsg_endpoint *ept,
+                           FAR void *data, size_t len, uint32_t src,
+                           FAR void *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const rpmsg_ept_cb g_rpmsgfs_handler[] =
+{
+  [RPMSGFS_OPEN]      = rpmsgfs_open_handler,
+  [RPMSGFS_CLOSE]     = rpmsgfs_close_handler,
+  [RPMSGFS_READ]      = rpmsgfs_read_handler,
+  [RPMSGFS_WRITE]     = rpmsgfs_write_handler,
+  [RPMSGFS_LSEEK]     = rpmsgfs_lseek_handler,
+  [RPMSGFS_IOCTL]     = rpmsgfs_ioctl_handler,
+  [RPMSGFS_SYNC]      = rpmsgfs_sync_handler,
+  [RPMSGFS_DUP]       = rpmsgfs_dup_handler,
+  [RPMSGFS_FSTAT]     = rpmsgfs_fstat_handler,
+  [RPMSGFS_FTRUNCATE] = rpmsgfs_ftruncate_handler,
+  [RPMSGFS_OPENDIR]   = rpmsgfs_opendir_handler,
+  [RPMSGFS_READDIR]   = rpmsgfs_readdir_handler,
+  [RPMSGFS_REWINDDIR] = rpmsgfs_rewinddir_handler,
+  [RPMSGFS_CLOSEDIR]  = rpmsgfs_closedir_handler,
+  [RPMSGFS_STATFS]    = rpmsgfs_statfs_handler,
+  [RPMSGFS_UNLINK]    = rpmsgfs_unlink_handler,
+  [RPMSGFS_MKDIR]     = rpmsgfs_mkdir_handler,
+  [RPMSGFS_RMDIR]     = rpmsgfs_rmdir_handler,
+  [RPMSGFS_RENAME]    = rpmsgfs_rename_handler,
+  [RPMSGFS_STAT]      = rpmsgfs_stat_handler,
+  [RPMSGFS_FCHSTAT]   = rpmsgfs_fchstat_handler,
+  [RPMSGFS_CHSTAT]    = rpmsgfs_chstat_handler,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int rpmsgfs_attach_file(FAR struct rpmsgfs_server_s *priv,
+                               FAR struct file *filep)
+{
+  FAR struct file **tmp;
+  int ret;
+  int i;
+  int j;
+
+  nxsem_wait(&priv->sem);
+
+  for (i = 0; i < priv->file_rows; i++)
+    {
+      for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++)
+        {
+          if (priv->files[i][j].f_inode == NULL)
+            {
+              memcpy(&priv->files[i][j], filep, sizeof(*filep));
+              ret = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j;
+              goto out;
+            }
+        }
+    }
+
+  tmp = kmm_realloc(priv->files, sizeof(FAR struct file *) * (i + 1));
+  DEBUGASSERT(tmp);
+  if (tmp == NULL)
+    {
+      ret = -ENFILE;
+      goto out;
+    }
+
+  tmp[i] = kmm_zalloc(sizeof(struct file) *
+                      CONFIG_NFILE_DESCRIPTORS_PER_BLOCK);
+  DEBUGASSERT(tmp[i]);
+  if (tmp[i] == NULL)
+    {
+      kmm_free(tmp);
+      ret = -ENFILE;
+      goto out;
+    }
+
+  priv->files = tmp;
+  priv->file_rows++;
+
+  memcpy(&priv->files[i][0], filep, sizeof(*filep));
+  ret = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK;
+
+out:
+  nxsem_post(&priv->sem);
+  return ret;
+}
+
+static int rpmsgfs_detach_file(FAR struct rpmsgfs_server_s *priv,
+                               int fd, FAR struct file *filep)
+{
+  struct file *tfilep;
+
+  if (fd < 0 || fd >= priv->file_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK)
+    {
+      return -EBADF;
+    }
+
+  nxsem_wait(&priv->sem);
+  tfilep = &priv->files[fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]
+                       [fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK];
+  memcpy(filep, tfilep, sizeof(*filep));
+  memset(tfilep, 0, sizeof(*tfilep));
+  nxsem_post(&priv->sem);
+
+  return 0;
+}
+
+static FAR struct file *rpmsgfs_get_file(
+                              FAR struct rpmsgfs_server_s *priv,
+                              int fd)
+{
+  FAR struct file *filep;
+
+  if (fd < 0 || fd >= priv->file_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK)
+    {
+      return NULL;
+    }
+
+  nxsem_wait(&priv->sem);
+  filep = &priv->files[fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]
+                      [fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK];
+  nxsem_post(&priv->sem);
+
+  return filep;
+}
+
+static int rpmsgfs_attach_dir(FAR struct rpmsgfs_server_s *priv,
+                              FAR void *dir)
+{
+  FAR void **tmp;
+  int i;
+
+  nxsem_wait(&priv->sem);
+  for (i = 1; i < priv->dir_nums; i++)
+    {
+      if (priv->dirs[i] == NULL)
+        {
+          priv->dirs[i] = dir;
+          nxsem_post(&priv->sem);
+          return i;
+        }
+    }
+
+  tmp = kmm_realloc(priv->dirs, sizeof(FAR void *) *
+                    (priv->dir_nums + CONFIG_NFILE_DESCRIPTORS_PER_BLOCK));
+  DEBUGASSERT(tmp);
+  if (tmp == NULL)
+    {
+      nxsem_post(&priv->sem);
+      return -ENOMEM;
+    }
+
+  priv->dirs = tmp;
+  priv->dir_nums += CONFIG_NFILE_DESCRIPTORS_PER_BLOCK;
+
+  priv->dirs[i] = dir;
+  nxsem_post(&priv->sem);
+  return i;
+}
+
+static void *rpmsgfs_detach_dir(FAR struct rpmsgfs_server_s *priv,
+                                    int fd)
+{
+  FAR void *dir = NULL;
+
+  if (fd >= 1 && fd < priv->dir_nums)
+    {
+      nxsem_wait(&priv->sem);
+      dir = priv->dirs[fd];
+      priv->dirs[fd] = NULL;
+      nxsem_post(&priv->sem);
+    }
+
+  return dir;
+}
+
+static FAR void *rpmsgfs_get_dir(
+                              FAR struct rpmsgfs_server_s *priv,
+                              int fd)
+{
+  FAR void *dir = NULL;
+
+  if (fd >= 1 && fd < priv->dir_nums)
+    {
+      nxsem_wait(&priv->sem);
+      dir = priv->dirs[fd];
+      nxsem_post(&priv->sem);
+    }
+
+  return dir;
+}
+
+static int rpmsgfs_open_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_open_s *msg = data;
+  struct file file;
+  int ret;
+
+  ret = file_open(&file, msg->pathname, msg->flags, msg->mode);
+  if (ret >= 0)
+    {
+      ret = rpmsgfs_attach_file(priv, &file);
+      if (ret < 0)
+        {
+          file_close(&file);
+        }
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_close_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_close_s *msg = data;
+  struct file file;
+  int ret;
+
+  ret = rpmsgfs_detach_file(priv, msg->fd, &file);
+  if (ret >= 0)
+    {
+      ret = file_close(&file);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_read_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_read_s *msg = data;
+  FAR struct rpmsgfs_read_s *rsp;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+  uint32_t space;
+
+  rsp = rpmsg_get_tx_payload_buffer(ept, &space, true);
+  if (!rsp)
+    {
+      return -ENOMEM;
+    }
+
+  *rsp = *msg;
+
+  space -= sizeof(*msg);
+  if (space > msg->count)
+    {
+      space = msg->count;
+    }
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_read(filep, rsp->buf, space);
+    }
+
+  rsp->header.result = ret;
+  return rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret) + sizeof(*rsp));
+}
+
+static int rpmsgfs_write_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_write_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_write(filep, msg->buf, msg->count);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_lseek_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_lseek_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_seek(filep, msg->offset, msg->whence);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_ioctl_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_ioctl_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_ioctl(filep, msg->request, msg->arg);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_sync_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_sync_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_fsync(filep);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_dup_handler(FAR struct rpmsg_endpoint *ept,
+                               FAR void *data, size_t len,
+                               uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_dup_s *msg = data;
+  FAR struct file *filep;
+  struct file newfile;
+  int ret = -ENOENT;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_dup2(filep, &newfile);
+      if (ret >= 0)
+        {
+          ret = rpmsgfs_attach_file(priv, &newfile);
+          if (ret < 0)
+            {
+              file_close(&newfile);
+            }
+        }
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_fstat_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_fstat_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+  struct stat buf;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_fstat(filep, &buf);
+      if (ret >= 0)
+        {
+          msg->buf = buf;
+        }
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_ftruncate_handler(FAR struct rpmsg_endpoint *ept,
+                                     FAR void *data, size_t len,
+                                     uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_ftruncate_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      ret = file_truncate(filep, msg->length);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_opendir_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_opendir_s *msg = data;
+  FAR void *dir;
+  int ret = -ENOENT;
+
+  dir = opendir(msg->pathname);
+  if (dir)
+    {
+      ret = rpmsgfs_attach_dir(priv, dir);
+      if (ret < 0)
+        {
+          closedir(dir);
+        }
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_readdir_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_readdir_s *msg = data;
+  FAR struct dirent *entry;
+  int ret = -ENOENT;
+  FAR void *dir;
+
+  dir = rpmsgfs_get_dir(priv, msg->fd);
+  if (dir)
+    {
+      entry = readdir(dir);
+      if (entry)
+        {
+          msg->type = entry->d_type;
+          strcpy(msg->name, entry->d_name);
+          len += strlen(entry->d_name) + 1;
+          ret = 0;
+        }
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, len);
+}
+
+static int rpmsgfs_rewinddir_handler(FAR struct rpmsg_endpoint *ept,
+                                     FAR void *data, size_t len,
+                                     uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_rewinddir_s *msg = data;
+  int ret = -ENOENT;
+  FAR void *dir;
+
+  dir = rpmsgfs_get_dir(priv, msg->fd);
+  if (dir)
+    {
+      rewinddir(dir);
+      ret = 0;
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_closedir_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_closedir_s *msg = data;
+  int ret = -ENOENT;
+  FAR void *dir;
+
+  dir = rpmsgfs_detach_dir(priv, msg->fd);
+  if (dir)
+    {
+      ret = closedir(dir) ? -get_errno() : 0;
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_statfs_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_statfs_s *msg = data;
+  struct statfs buf;
+  int ret;
+
+  ret = statfs(msg->pathname, &buf);
+  if (ret)
+    {
+      ret = -get_errno();
+    }
+  else
+    {
+      msg->buf = buf;
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_unlink_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_unlink_s *msg = data;
+
+  msg->header.result = nx_unlink(msg->pathname);
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_mkdir_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_mkdir_s *msg = data;
+  int ret;
+
+  ret = mkdir(msg->pathname, msg->mode);
+  msg->header.result = ret ? -get_errno() : 0;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_rmdir_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_rmdir_s *msg = data;
+  int ret;
+
+  ret = rmdir(msg->pathname);
+  msg->header.result = ret ? -get_errno() : 0;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_rename_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_rename_s *msg = data;
+  FAR char *newpath;
+  size_t oldlen;
+  int ret;
+
+  oldlen = (strlen(msg->pathname) + 1 + 0x7) & ~0x7;
+  newpath = msg->pathname + oldlen;
+
+  ret = rename(msg->pathname, newpath);
+  msg->header.result = ret ? -get_errno() : 0;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_stat_s *msg = data;
+  struct stat buf;
+  int ret;
+
+  ret = nx_stat(msg->pathname, &buf, 1);
+  if (ret >= 0)
+    {
+      msg->buf = buf;
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_fchstat_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_fchstat_s *msg = data;
+  FAR struct file *filep;
+  int ret = -ENOENT;
+  struct stat buf;
+
+  filep = rpmsgfs_get_file(priv, msg->fd);
+  if (filep != NULL)
+    {
+      buf = msg->buf;
+      ret = file_fchstat(filep, &buf, msg->flags);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_chstat_handler(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_chstat_s *msg = data;
+  struct timespec times[2];
+  int ret = 0;
+
+  if (msg->flags & CH_STAT_MODE)
+    {
+      ret = chmod(msg->pathname, msg->buf.st_mode);
+      if (ret < 0)
+        {
+          ret = -get_errno();
+          goto out;
+        }
+    }
+
+  if (msg->flags & (CH_STAT_UID | CH_STAT_GID))
+    {
+      ret = chown(msg->pathname, msg->buf.st_uid, msg->buf.st_gid);
+      if (ret < 0)
+        {
+          ret = -get_errno();
+          goto out;
+        }
+    }
+
+  if (msg->flags & (CH_STAT_ATIME | CH_STAT_MTIME))
+    {
+      if (msg->flags & CH_STAT_ATIME)
+        {
+          times[0] = msg->buf.st_atim;
+        }
+      else
+        {
+          times[0].tv_nsec = UTIME_OMIT;
+        }
+
+      if (msg->flags & CH_STAT_MTIME)
+        {
+          times[1] = msg->buf.st_mtim;
+        }
+      else
+        {
+          times[1].tv_nsec = UTIME_OMIT;
+        }
+
+      ret = utimens(msg->pathname, times);
+      if (ret < 0)
+        {
+          ret = -get_errno();
+          goto out;
+        }
+    }
+
+out:
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static void rpmsgfs_ns_bind(FAR struct rpmsg_device *rdev,
+                            FAR void *priv_, FAR const char *name,
+                            uint32_t dest)
+{
+  FAR struct rpmsgfs_server_s *priv;
+  int ret;
+
+  if (strncmp(name, RPMSGFS_NAME_PREFIX, strlen(RPMSGFS_NAME_PREFIX)))
+    {
+      return;
+    }
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (!priv)
+    {
+      return;
+    }
+
+  priv->ept.priv = priv;
+  nxsem_init(&priv->sem, 0, 1);
+
+  ret = rpmsg_create_ept(&priv->ept, rdev, name,
+                         RPMSG_ADDR_ANY, dest,
+                         rpmsgfs_ept_cb, rpmsgfs_ns_unbind);
+  if (ret)
+    {
+      nxsem_destroy(&priv->sem);
+      kmm_free(priv);
+    }
+}
+
+static void rpmsgfs_ns_unbind(FAR struct rpmsg_endpoint *ept)
+{
+  FAR struct rpmsgfs_server_s *priv = ept->priv;
+  int i;
+  int j;
+
+  for (i = 0; i < priv->file_rows; i++)
+    {
+      for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++)
+        {
+          if (priv->files[i][j].f_inode)
+            {
+              file_close(&priv->files[i][j]);
+            }
+        }
+
+      kmm_free(priv->files[i]);
+    }
+
+  for (i = 0; i < priv->dir_nums; i++)
+    {
+      if (priv->dirs[i])
+        {
+          closedir(priv->dirs[i]);
+        }
+    }
+
+  rpmsg_destroy_ept(&priv->ept);
+  nxsem_destroy(&priv->sem);
+
+  kmm_free(priv->files);
+  kmm_free(priv->dirs);
+  kmm_free(priv);
+}
+
+static int rpmsgfs_ept_cb(FAR struct rpmsg_endpoint *ept,
+                          FAR void *data, size_t len, uint32_t src,
+                          FAR void *priv)
+{
+  struct rpmsgfs_header_s *header = data;
+  uint32_t command = header->command;
+
+  if (command < ARRAY_SIZE(g_rpmsgfs_handler))
+    {
+      return g_rpmsgfs_handler[command](ept, data, len, src, priv);
+    }
+
+  return -EINVAL;
+}
+
+int rpmsgfs_server_init(void)
+{
+  return rpmsg_register_callback(NULL,
+                                 NULL,
+                                 NULL,
+                                 rpmsgfs_ns_bind);
+}
diff --git a/include/nuttx/fs/dirent.h b/include/nuttx/fs/dirent.h
index a9a9675..0f19340 100644
--- a/include/nuttx/fs/dirent.h
+++ b/include/nuttx/fs/dirent.h
@@ -207,6 +207,17 @@ struct fs_hostfsdir_s
 };
 #endif
 
+#ifdef CONFIG_FS_RPMSGFS
+/* RPMSGFS provides mapping to directories on the host machine in the
+ * sim environment.
+ */
+
+struct fs_rpmsgfsdir_s
+{
+  FAR void *fs_dir;                           /* Opaque pointer to remote DIR */
+};
+#endif
+
 #endif /* CONFIG_DISABLE_MOUNTPOINT */
 
 struct fs_dirent_s
@@ -288,6 +299,9 @@ struct fs_dirent_s
 #ifdef CONFIG_FS_HOSTFS
       struct fs_hostfsdir_s  hostfs;
 #endif
+#ifdef CONFIG_FS_RPMSGFS
+      struct fs_rpmsgfsdir_s rpmsgfs;
+#endif
 #endif /* !CONFIG_DISABLE_MOUNTPOINT */
   } u;
 
diff --git a/include/nuttx/fs/hostfs_rpmsg.h b/include/nuttx/fs/rpmsgfs.h
similarity index 87%
rename from include/nuttx/fs/hostfs_rpmsg.h
rename to include/nuttx/fs/rpmsgfs.h
index 4154b8b..76de3de 100644
--- a/include/nuttx/fs/hostfs_rpmsg.h
+++ b/include/nuttx/fs/rpmsgfs.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * include/nuttx/fs/hostfs_rpmsg.h
+ * include/nuttx/fs/rpmsgfs.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -33,12 +33,8 @@ extern "C"
 #define EXTERN extern
 #endif
 
-#ifdef CONFIG_FS_HOSTFS_RPMSG
-int hostfs_rpmsg_init(FAR const char *cpu_name);
-#endif
-
-#ifdef CONFIG_FS_HOSTFS_RPMSG_SERVER
-int hostfs_rpmsg_server_init(void);
+#ifdef CONFIG_FS_RPMSGFS
+int rpmsgfs_server_init(void);
 #endif
 
 #undef EXTERN
diff --git a/include/sys/statfs.h b/include/sys/statfs.h
index 6cbd254..1bb9bed 100644
--- a/include/sys/statfs.h
+++ b/include/sys/statfs.h
@@ -93,6 +93,7 @@
 #define HOSTFS_MAGIC          0x54534f48
 #define USERFS_MAGIC          0x52455355
 #define CROMFS_MAGIC          0x4d4f5243
+#define RPMSGFS_MAGIC         0x54534f47
 
 #if defined(CONFIG_FS_LARGEFILE) && defined(CONFIG_HAVE_LONG_LONG)
 #  define statfs64            statfs