mirror of
https://github.com/apache/nuttx.git
synced 2026-09-20 04:47:58 +08:00
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:
@@ -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/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+16
-19
@@ -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
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user