This comment converts the underlying IPC used by the UserFS from Unix domain local sockets to UDP LocalHost loopback sockets. The problem with the local sockets is that they do require operations on the top level psuedo-file system inode tree. That tree must be locked during certain traversals such as enumerate mountpoints or enumerating directory entries.

This conversion is unfortunate in the sense that Unix local domain sockets are relatively lightweight.  LocalHost UDP sockets are much heavier weight since they rely on the full UDP stack.  If anyone is up for a complete redesign, then using some shared memory and a POSIX message queue would be lightweight again.

This commit also fixes several bugs that were not testable before the inode tree deadlock.  I cannot say that the logic is 100% stable but it does not have basic functionality.

Squashed commit of the following:

    fs/userfs:  Order locking so that access to the shared I/O buffer is also locked.
    fs/userfs:  Converts to use LocalHost UDP loopback for IPC.
This commit is contained in:
Gregory Nutt
2017-11-05 12:25:58 -06:00
parent 2fc5237854
commit 7deb24484c
8 changed files with 535 additions and 310 deletions
+1 -31
View File
@@ -23,7 +23,7 @@ nuttx/:
(4) USB (drivers/usbdev, drivers/usbhost)
(0) Other drivers (drivers/)
(12) Libraries (libc/, libm/)
(11) File system/Generic drivers (fs/, drivers/)
(10) File system/Generic drivers (fs/, drivers/)
(9) Graphics Subsystem (graphics/)
(3) Build system / Toolchains
(3) Linux/Cywgin simulation (arch/sim)
@@ -1963,36 +1963,6 @@ o File system / Generic drivers (fs/, drivers/)
ignored by readder() logic. This the file does not
appear in the 'ls'.
Title: DEADLOCKS WITH USERFS
Description: UserFS support has been added to NuttX. However, the current
version is not very usable due to problems with deadlocks. These
deadlocks occur because: (1) logic on the NSH thread locks the
inode tree to prevent modification while travering file system
entities, but (2) Logic in the UserFS daemon also needs to lock
the inode tree. This leads to the deadlock because the logic on
the NSH thread cannot unlock the inode tree until the traversal
completes but the logic on the UserFS daemon thread is blocked
waiting to lock the inodes.
This can be seen with the NSH mount command which locks the
inode tree while traversing all of the mountpoints and also
with a simple directory listing with the 'ls' command which
locks the inode tree while the directory entries are enumerated.
The simplest solution would be change the IPC so that it does
not interact with the inode tree. The simplest IPC change
would be to swith the underlying IPC from Unix domain local
sockets to LocalHost loopback sockets. This would add
overhead of supporting a UDP stack in all configurations.
Another option would be to use shared memory or, perhaps
better, shared memory with a message queue.
Support UserFS is currently marked EXPERIMENTAL to prevent
accidentlly enabling the feature.
Status: Open
Priority: Since this is a new feature, the priority must be low (unless,
of course, someone is in dire need of the feature).
o Graphics Subsystem (graphics/)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+5 -1
View File
@@ -1,7 +1,7 @@
# CONFIG_NET_ETHERNET is not set
# CONFIG_NET_IPv4 is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_DISABLE_DATE is not set
# CONFIG_NSH_NETINIT is not set
CONFIG_ARCH_BOARD_SIM=y
CONFIG_ARCH_BOARD="sim"
CONFIG_ARCH_SIM=y
@@ -31,7 +31,10 @@ CONFIG_IDLETHREAD_STACKSIZE=4096
CONFIG_LIBC_EXECFUNCS=y
CONFIG_MAX_TASKS=64
CONFIG_NET_LOCAL=y
CONFIG_NET_LOOPBACK=y
CONFIG_NET_UDP=y
CONFIG_NET=y
CONFIG_NETDEVICES=y
CONFIG_NFILE_DESCRIPTORS=32
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_ARCHROMFS=y
@@ -46,6 +49,7 @@ CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=2048
CONFIG_PTHREAD_STACK_DEFAULT=8192
CONFIG_READLINE_TABCOMPLETION=y
CONFIG_SCHED_HAVE_PARENT=y
CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_ONEXIT=y
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
-20
View File
@@ -14,26 +14,6 @@ config NETDEV_LOOPBACK
Add support for the local network loopback device, lo.
if NETDEV_LOOPBACK
choice
prompt "Work queue"
default LOOPBACK_LPWORK if SCHED_LPWORK
default LOOPBACK_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
depends on SCHED_WORKQUEUE
---help---
Work queue support is required to use the loopback driver. If the
low priority work queue is available, then it should be used by the
loopback driver.
config LOOPBACK_HPWORK
bool "High priority"
depends on SCHED_HPWORK
config LOOPBACK_LPWORK
bool "Low priority"
depends on SCHED_LPWORK
endchoice # Work queue
endif # NETDEV_LOOPBACK
config NETDEV_TELNET
+5 -12
View File
@@ -38,7 +38,6 @@
****************************************************************************/
#include <nuttx/config.h>
#if defined(CONFIG_NET) && defined(CONFIG_NETDEV_LOOPBACK)
#include <stdint.h>
#include <stdbool.h>
@@ -63,6 +62,8 @@
# include <nuttx/net/pkt.h>
#endif
#ifdef CONFIG_NETDEV_LOOPBACK
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -71,14 +72,6 @@
#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Worker thread support is required (CONFIG_SCHED_WORKQUEUE)
#else
# if defined(CONFIG_LOOPBACK_HPWORK)
# define LPBKWORK HPWORK
# elif defined(CONFIG_LOOPBACK_LPWORK)
# define LPBKWORK LPWORK
# else
# error Neither CONFIG_LOOPBACK_HPWORK nor CONFIG_LOOPBACK_LPWORK defined
# endif
#endif
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
@@ -283,7 +276,7 @@ static void lo_poll_expiry(int argc, wdparm_t arg, ...)
/* Schedule to perform the interrupt processing on the worker thread. */
work_queue(LPBKWORK, &priv->lo_work, lo_poll_work, priv, 0);
work_queue(LPWORK, &priv->lo_work, lo_poll_work, priv, 0);
}
/****************************************************************************
@@ -429,7 +422,7 @@ static int lo_txavail(FAR struct net_driver_s *dev)
{
/* Schedule to serialize the poll on the worker thread. */
work_queue(LPBKWORK, &priv->lo_work, lo_txavail_work, priv, 0);
work_queue(LPWORK, &priv->lo_work, lo_txavail_work, priv, 0);
}
return OK;
@@ -558,4 +551,4 @@ int localhost_initialize(void)
return lo_ifup(&priv->lo_dev);
}
#endif /* CONFIG_NET && CONFIG_NETDEV_LOOPBACK */
#endif /* CONFIG_NETDEV_LOOPBACK */
+1 -1
View File
@@ -6,7 +6,7 @@
config FS_USERFS
bool "User file system"
default n
depends on NET_LOCAL && EXPERIMENTAL
depends on NET_IPv4 && NET_UDP && NETDEV_LOOPBACK
---help---
Enable support for user file system. See include/nuttx/fs/userfs.h
+376 -98
View File
File diff suppressed because it is too large Load Diff
+16 -19
View File
@@ -55,10 +55,9 @@
* 1. The UserFS OS support will be instantiated when the UserFS is mounted
* based upon the configuration passed in the optional data of the
* mount command.
* 2. The UserFS instance N will be configured to communicate on a Unix
* domain local socket with address: /dev/userfsN where N is the same
* value as was when file system was created. The Unix domain socket
* handles both client to server requests and server-to-client responses.
* 2. The UserFS server port number will be configured to communicate on a
* LocalHost UDP socket with the server portof 0x83nn where nn is the
* value that was provided when file system was created.
* 3. The UserFs will receive system file system requests and forward them
* on the the MqUfsReqN to the user-space file system server
* (userfs_run()). These requests may be accompanied by additional data in
@@ -66,12 +65,12 @@
* created. This buffer would hold, for example, the data to be
* written that would accompany a write request.
* 4. The user-space logic of userfs_run() listens at the other end of the
* Unix domain socket. It will receive the requests and forward them
* LocalHost socket. It will receive the requests and forward them
* to the user file system implementation via the methods of struct
* userfs_operations_s
* 5. Responses generated by the struct userfs_operations_s method will be
* returned to UserFS via the Unix domain socket.
* 6. The UserFS kernel thread will listen on the Unix local domain socket
* returned to UserFS via the LocalHost socket.
* 6. The UserFS kernel thread will listen on the LocalHost socket
* and will receive the user file system responses and forward them to
* the kernel-space file system client.
*/
@@ -104,19 +103,17 @@
* Input: This function receives an pointer to a read-only instance of
* struct userfs_config_s that contains information needed to
* configure the UserFS instance.
* Output: On success the UserFS N instance is created. N is non-negative
* Output: On success the UserFS nn instance is created. nn is non-negative
* and will be provided as the IOCTL return value on success. On
* failure, ioctl() will return -1 with the errno variable set to
* indicate the cause of the failure.
*/
/* Format statements that should be used in creating Unix domain addresses */
/* This is the base value of the server port number. The actual range is
* 0x8300 through 0x83ff.
*/
#define USERFS_SERVER_FMT "/dev/userver%u"
#define USERFS_SERVER_MAXLEN (18)
#define USERFS_CLIENT_FMT "/dev/uclient%u"
#define USERFS_CLIENT_MAXLEN (18)
#define USERFS_SERVER_PORTBASE 0x8300
/* It looks like the maximum size of a request is 16 bytes. We will allow a
* little more for the maximum size of a request structure.
@@ -194,7 +191,7 @@ enum userfs_resp_e
struct userfs_config_s
{
size_t mxwrite; /* The max size of a write data */
int instance; /* Instance number used to create unique naming */
uint16_t portno; /* The server port number (host order) */
};
/* This structure identifies the user-space file system operations. */
@@ -561,13 +558,13 @@ int userfs_register(void);
*
* 1. It configures and creates the UserFS file system and
* 2. Mounts the user file system at the provide mount point path.
* 2. Receives file system requests on the Unix doamin local socket with
* address /dev/userfsN where N is the same as above,
* 2. Receives file system requests on the LocalHost socket with
* server port 0x83nn where nn is the same as above,
* 3. Received file system requests are marshaled and dispatch to the
* user file system via callbacks to the operations provided by
* "userops", and
* 3. Returns file system responses generated by the callbacks via the
* same Unix domain local socket.
* 3. Returns file system responses generated by the callbacks to the
* LocalHost client socket.
*
* NOTE: This is a user function that is implemented as part of the
* NuttX C library and is intended to be called by appliation logic.
+131 -128
View File
File diff suppressed because it is too large Load Diff