diff --git a/TODO b/TODO index 1c5c29be674..1061679f52a 100644 --- a/TODO +++ b/TODO @@ -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/) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/configs/sim/userfs/defconfig b/configs/sim/userfs/defconfig index 64ae1a91220..91ee878ec2a 100644 --- a/configs/sim/userfs/defconfig +++ b/configs/sim/userfs/defconfig @@ -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 diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b976953331e..1881cf815b2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -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 diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 10e2408d09e..9d051d684d7 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -38,7 +38,6 @@ ****************************************************************************/ #include -#if defined(CONFIG_NET) && defined(CONFIG_NETDEV_LOOPBACK) #include #include @@ -63,6 +62,8 @@ # include #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 */ diff --git a/fs/userfs/Kconfig b/fs/userfs/Kconfig index 2e4507d3fac..4a13140b8b2 100644 --- a/fs/userfs/Kconfig +++ b/fs/userfs/Kconfig @@ -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 diff --git a/fs/userfs/fs_userfs.c b/fs/userfs/fs_userfs.c index 460898424ed..4514ce326e8 100644 --- a/fs/userfs/fs_userfs.c +++ b/fs/userfs/fs_userfs.c @@ -43,18 +43,20 @@ #include #include #include -#include #include #include #include #include #include -#include +#include #include #include #include +#include +#include + #include #include #include @@ -82,10 +84,9 @@ struct userfs_state_s /* Internal state */ - uint16_t instance; /* UserFS instance number */ struct socket psock; /* Client socket instance */ - struct sockaddr_un server; /* Server address */ - socklen_t addrlen; /* Size of server address */ + struct sockaddr_in server; /* Server address */ + sem_t exclsem; /* Exlusive access for request-response sequence */ /* I/O Buffer (actual size depends on USERFS_REQ_MAXSIZE and the configured * mxwrite). @@ -200,6 +201,7 @@ static int userfs_open(FAR struct file *filep, FAR const char *relpath, ssize_t nsent; ssize_t nrecvd; int pathlen; + int ret; finfo("Open '%s'\n", relpath); @@ -208,6 +210,23 @@ static int userfs_open(FAR struct file *filep, FAR const char *relpath, filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Check the path length */ + + DEBUGASSERT(relpath != NULL); + pathlen = strlen(relpath); + if (pathlen > priv->mxwrite) + { + return -E2BIG; + } + + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_open_request_s *)priv->iobuffer; @@ -215,21 +234,16 @@ static int userfs_open(FAR struct file *filep, FAR const char *relpath, req->oflags = oflags; req->mode = mode; - DEBUGASSERT(relpath != NULL); - pathlen = strlen(relpath); - if (pathlen > priv->mxwrite) - { - return -E2BIG; - } - strncpy(req->relpath, relpath, priv->mxwrite); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_OPEN_REQUEST_S(pathlen + 1), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -237,6 +251,8 @@ static int userfs_open(FAR struct file *filep, FAR const char *relpath, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -259,7 +275,6 @@ static int userfs_open(FAR struct file *filep, FAR const char *relpath, } filep->f_priv = resp->openinfo; - return resp->ret; } @@ -274,12 +289,21 @@ static int userfs_close(FAR struct file *filep) FAR struct userfs_close_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(filep != NULL && filep->f_inode != NULL && filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_close_request_s *)priv->iobuffer; @@ -288,10 +312,12 @@ static int userfs_close(FAR struct file *filep) nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_close_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -299,6 +325,8 @@ static int userfs_close(FAR struct file *filep) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -318,6 +346,11 @@ static int userfs_close(FAR struct file *filep) return -EIO; } + if (resp->ret >= 0) + { + filep->f_priv = NULL; + } + return resp->ret; } @@ -334,6 +367,7 @@ static ssize_t userfs_read(FAR struct file *filep, char *buffer, ssize_t nsent; ssize_t nrecvd; int respsize; + int ret; finfo("Read %d bytes from offset %d\n", buflen, filep->f_pos); @@ -342,6 +376,14 @@ static ssize_t userfs_read(FAR struct file *filep, char *buffer, filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_read_request_s *)priv->iobuffer; @@ -351,10 +393,12 @@ static ssize_t userfs_read(FAR struct file *filep, char *buffer, nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_read_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -362,6 +406,8 @@ static ssize_t userfs_read(FAR struct file *filep, char *buffer, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -412,6 +458,7 @@ static ssize_t userfs_write(FAR struct file *filep, FAR const char *buffer, FAR struct userfs_write_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; finfo("Write %d bytes to offset %d\n", buflen, filep->f_pos); @@ -428,6 +475,14 @@ static ssize_t userfs_write(FAR struct file *filep, FAR const char *buffer, return -E2BIG; /* No implememented yet */ } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_write_request_s *)priv->iobuffer; @@ -438,10 +493,12 @@ static ssize_t userfs_write(FAR struct file *filep, FAR const char *buffer, nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_WRITE_REQUEST_S(buflen), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -449,6 +506,8 @@ static ssize_t userfs_write(FAR struct file *filep, FAR const char *buffer, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -482,6 +541,7 @@ static off_t userfs_seek(FAR struct file *filep, off_t offset, int whence) FAR struct userfs_seek_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; finfo("Offset %lu bytes to whence=%d\n", (unsigned long)offset, whence); @@ -490,6 +550,14 @@ static off_t userfs_seek(FAR struct file *filep, off_t offset, int whence) filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_seek_request_s *)priv->iobuffer; @@ -500,10 +568,12 @@ static off_t userfs_seek(FAR struct file *filep, off_t offset, int whence) nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_seek_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -511,6 +581,8 @@ static off_t userfs_seek(FAR struct file *filep, off_t offset, int whence) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -544,6 +616,7 @@ static int userfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) FAR struct userfs_ioctl_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; finfo("cmd: %d arg: %08lx\n", cmd, arg); @@ -552,9 +625,17 @@ static int userfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ - req = (FAR struct userfs_ioctl_request_s *)priv->iobuffer; + req = (FAR struct userfs_ioctl_request_s *)priv->iobuffer; req->req = USERFS_REQ_IOCTL; req->openinfo = filep->f_priv; req->cmd = cmd; @@ -562,10 +643,12 @@ static int userfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_ioctl_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -573,6 +656,8 @@ static int userfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -606,12 +691,21 @@ static int userfs_sync(FAR struct file *filep) FAR struct userfs_sync_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(filep != NULL && filep->f_inode != NULL && filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_sync_request_s *)priv->iobuffer; @@ -620,10 +714,12 @@ static int userfs_sync(FAR struct file *filep) nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_sync_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -631,6 +727,8 @@ static int userfs_sync(FAR struct file *filep) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -668,6 +766,7 @@ static int userfs_dup(FAR const struct file *oldp, FAR struct file *newp) FAR struct userfs_dup_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; finfo("Dup %p->%p\n", oldp, newp); @@ -676,6 +775,14 @@ static int userfs_dup(FAR const struct file *oldp, FAR struct file *newp) oldp->f_inode->i_private != NULL); priv = oldp->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_dup_request_s *)priv->iobuffer; @@ -684,10 +791,12 @@ static int userfs_dup(FAR const struct file *oldp, FAR struct file *newp) nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_dup_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -695,6 +804,8 @@ static int userfs_dup(FAR const struct file *oldp, FAR struct file *newp) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -734,12 +845,21 @@ static int userfs_fstat(FAR const struct file *filep, FAR struct stat *buf) FAR struct userfs_fstat_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(filep != NULL && filep->f_inode != NULL && filep->f_inode->i_private != NULL); priv = filep->f_inode->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ req = (FAR struct userfs_fstat_request_s *)priv->iobuffer; @@ -748,10 +868,12 @@ static int userfs_fstat(FAR const struct file *filep, FAR struct stat *buf) nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_fstat_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -759,6 +881,8 @@ static int userfs_fstat(FAR const struct file *filep, FAR struct stat *buf) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -802,6 +926,7 @@ static int userfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, ssize_t nsent; ssize_t nrecvd; int pathlen; + int ret; finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL"); @@ -809,26 +934,38 @@ static int userfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, mountpt->i_private != NULL); priv = mountpt->i_private; - /* Construct and send the request to the server */ - - req = (FAR struct userfs_opendir_request_s *)priv->iobuffer; - req->req = USERFS_REQ_OPENDIR; + /* Check the path length */ DEBUGASSERT(relpath != NULL); - pathlen = strlen(relpath); + pathlen = strlen(relpath); if (pathlen > priv->mxwrite) { return -E2BIG; } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + /* Construct and send the request to the server */ + + req = (FAR struct userfs_opendir_request_s *)priv->iobuffer; + req->req = USERFS_REQ_OPENDIR; + strncpy(req->relpath, relpath, priv->mxwrite); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_OPENDIR_REQUEST_S(pathlen + 1), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -836,6 +973,8 @@ static int userfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -878,23 +1017,34 @@ static int userfs_closedir(FAR struct inode *mountpt, FAR struct userfs_closedir_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ - req = (FAR struct userfs_closedir_request_s *)priv->iobuffer; - req->req = USERFS_REQ_CLOSEDIR; - req->dir = dir->u.userfs.fs_dir; + req = (FAR struct userfs_closedir_request_s *)priv->iobuffer; + req->req = USERFS_REQ_CLOSEDIR; + req->dir = dir->u.userfs.fs_dir; nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_closedir_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -902,6 +1052,8 @@ static int userfs_closedir(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -939,23 +1091,34 @@ static int userfs_readdir(FAR struct inode *mountpt, FAR struct userfs_readdir_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ - req = (FAR struct userfs_readdir_request_s *)priv->iobuffer; - req->req = USERFS_REQ_READDIR; - req->dir = dir->u.userfs.fs_dir; + req = (FAR struct userfs_readdir_request_s *)priv->iobuffer; + req->req = USERFS_REQ_READDIR; + req->dir = dir->u.userfs.fs_dir; nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_readdir_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -963,6 +1126,8 @@ static int userfs_readdir(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1004,23 +1169,34 @@ static int userfs_rewinddir(FAR struct inode *mountpt, FAR struct userfs_rewinddir_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ - req = (FAR struct userfs_rewinddir_request_s *)priv->iobuffer; - req->req = USERFS_REQ_REWINDDIR; - req->dir = dir->u.userfs.fs_dir; + req = (FAR struct userfs_rewinddir_request_s *)priv->iobuffer; + req->req = USERFS_REQ_REWINDDIR; + req->dir = dir->u.userfs.fs_dir; nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_rewinddir_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1028,6 +1204,8 @@ static int userfs_rewinddir(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1066,14 +1244,12 @@ static int userfs_bind(FAR struct inode *blkdriver, FAR const void *data, { FAR struct userfs_state_s *priv; FAR const struct userfs_config_s *config; - struct sockaddr_un client; - socklen_t addrlen; + struct sockaddr_in client; unsigned int iolen; int ret; DEBUGASSERT(data != NULL && handle != NULL); config = (FAR const struct userfs_config_s *)data; - DEBUGASSERT(config->instance >= 0 && config->instance <= UINT16_MAX); /* Allocate an instance of the UserFS state structure */ @@ -1085,27 +1261,29 @@ static int userfs_bind(FAR struct inode *blkdriver, FAR const void *data, return -ENOMEM; } + /* Initialize the semaphore that assures mutually exclusive access through + * the entire request-response sequence. + */ + + sem_init(&priv->exclsem, 0, 1); + /* Copy the configuration data into the allocated structure. Why? First * we can't be certain of the life time of the memory underlying the config * reference. Also, in the KERNEL build, the config data will like in * process-specific memory and cannot be shared across processes. */ - priv->mxwrite = config->mxwrite; - priv->instance = config->instance; + priv->mxwrite = config->mxwrite; /* Preset the server address */ - priv->server.sun_family = AF_LOCAL; - snprintf(priv->server.sun_path, UNIX_PATH_MAX, USERFS_SERVER_FMT, - config->instance); - priv->server.sun_path[UNIX_PATH_MAX - 1] = '\0'; + priv->server.sin_family = AF_INET; + priv->server.sin_port = htons(config->portno); + priv->server.sin_addr.s_addr = HTONL(INADDR_LOOPBACK); - priv->addrlen = strlen(priv->server.sun_path) + sizeof(sa_family_t) + 1; + /* Create a LocalHost UDP client socket */ - /* Create a new Unix domain datagram server socket */ - - ret = psock_socket(PF_LOCAL, SOCK_DGRAM, 0, &priv->psock); + ret = psock_socket(PF_INET, SOCK_DGRAM, 0, &priv->psock); if (ret < 0) { printf("client: ERROR socket failure %d\n", ret); @@ -1116,13 +1294,12 @@ static int userfs_bind(FAR struct inode *blkdriver, FAR const void *data, /* Bind the socket to the client address */ - client.sun_family = AF_LOCAL; - snprintf(client.sun_path, UNIX_PATH_MAX, USERFS_CLIENT_FMT, - config->instance); - client.sun_path[UNIX_PATH_MAX - 1] = '\0'; + client.sin_family = AF_INET; + client.sin_port = 0; + client.sin_addr.s_addr = HTONL(INADDR_LOOPBACK); - addrlen = strlen(client.sun_path) + sizeof(sa_family_t) + 1; - ret = psock_bind(&priv->psock, (struct sockaddr*)&client, addrlen); + ret = psock_bind(&priv->psock, (struct sockaddr*)&client, + sizeof(struct sockaddr_in)); if (ret < 0) { ferr("ERROR: bind() failed: %d\n", ret); @@ -1160,20 +1337,31 @@ static int userfs_unbind(FAR void *handle, FAR struct inode **blkdriver, FAR struct userfs_destroy_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(priv != NULL); + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ - req = (FAR struct userfs_destroy_request_s *)priv->iobuffer; - req->req = USERFS_REQ_DESTROY; + req = (FAR struct userfs_destroy_request_s *)priv->iobuffer; + req->req = USERFS_REQ_DESTROY; nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_destroy_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1181,6 +1369,8 @@ static int userfs_unbind(FAR void *handle, FAR struct inode **blkdriver, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1229,22 +1419,33 @@ static int userfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf) FAR struct userfs_statfs_response_s *resp; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + /* Construct and send the request to the server */ - req = (FAR struct userfs_statfs_request_s *)priv->iobuffer; - req->req = USERFS_REQ_STATFS; + req = (FAR struct userfs_statfs_request_s *)priv->iobuffer; + req->req = USERFS_REQ_STATFS; nsent = psock_sendto(&priv->psock, priv->iobuffer, sizeof(struct userfs_statfs_request_s), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1252,13 +1453,15 @@ static int userfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf) nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); return (int)nrecvd; } - if (nrecvd != sizeof(struct userfs_unlink_response_s)) + if (nrecvd != sizeof(struct userfs_statfs_response_s)) { ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd); return -EIO; @@ -1295,15 +1498,13 @@ static int userfs_unlink(FAR struct inode *mountpt, ssize_t nsent; ssize_t nrecvd; int pathlen; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; - /* Construct and send the request to the server */ - - req = (FAR struct userfs_unlink_request_s *)priv->iobuffer; - req->req = USERFS_REQ_UNLINK; + /* Check the path length */ DEBUGASSERT(relpath != NULL); pathlen = strlen(relpath); @@ -1312,14 +1513,29 @@ static int userfs_unlink(FAR struct inode *mountpt, return -E2BIG; } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + /* Construct and send the request to the server */ + + req = (FAR struct userfs_unlink_request_s *)priv->iobuffer; + req->req = USERFS_REQ_UNLINK; + strncpy(req->relpath, relpath, priv->mxwrite); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_UNLINK_REQUEST_S(pathlen + 1), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1327,6 +1543,8 @@ static int userfs_unlink(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1366,32 +1584,45 @@ static int userfs_mkdir(FAR struct inode *mountpt, ssize_t nsent; ssize_t nrecvd; int pathlen; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; - /* Construct and send the request to the server */ - - req = (FAR struct userfs_mkdir_request_s *)priv->iobuffer; - req->req = USERFS_REQ_MKDIR; - req->mode = mode; + /* Check the path length */ DEBUGASSERT(relpath != NULL); - pathlen = strlen(relpath); + pathlen = strlen(relpath); if (pathlen > priv->mxwrite) { return -E2BIG; } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + /* Construct and send the request to the server */ + + req = (FAR struct userfs_mkdir_request_s *)priv->iobuffer; + req->req = USERFS_REQ_MKDIR; + req->mode = mode; + strncpy(req->relpath, relpath, priv->mxwrite); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_MKDIR_REQUEST_S(pathlen + 1), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1399,6 +1630,8 @@ static int userfs_mkdir(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1438,31 +1671,44 @@ static int userfs_rmdir(FAR struct inode *mountpt, ssize_t nsent; ssize_t nrecvd; int pathlen; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; - /* Construct and send the request to the server */ - - req = (FAR struct userfs_rmdir_request_s *)priv->iobuffer; - req->req = USERFS_REQ_RMDIR; + /* Check the path length */ DEBUGASSERT(relpath != NULL); - pathlen = strlen(relpath); + pathlen = strlen(relpath); if (pathlen > priv->mxwrite) { return -E2BIG; } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + /* Construct and send the request to the server */ + + req = (FAR struct userfs_rmdir_request_s *)priv->iobuffer; + req->req = USERFS_REQ_RMDIR; + strncpy(req->relpath, relpath, priv->mxwrite); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_RMDIR_REQUEST_S(pathlen + 1), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1470,6 +1716,8 @@ static int userfs_rmdir(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1511,35 +1759,48 @@ static int userfs_rename(FAR struct inode *mountpt, int newpathlen; ssize_t nsent; ssize_t nrecvd; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; - /* Construct and send the request to the server */ - - req = (FAR struct userfs_rename_request_s *)priv->iobuffer; - req->req = USERFS_REQ_RENAME; + /* Check the path lengths */ DEBUGASSERT(oldrelpath != NULL && newrelpath != NULL); - oldpathlen = strlen(oldrelpath) + 1; - newpathlen = strlen(newrelpath) + 1; + oldpathlen = strlen(oldrelpath) + 1; + newpathlen = strlen(newrelpath) + 1; if ((oldpathlen + newpathlen) > priv->mxwrite) { return -E2BIG; } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + /* Construct and send the request to the server */ + + req = (FAR struct userfs_rename_request_s *)priv->iobuffer; + req->req = USERFS_REQ_RENAME; req->newoffset = oldpathlen; + strncpy(req->oldrelpath, oldrelpath, oldpathlen); strncpy(&req->oldrelpath[oldpathlen], newrelpath, newpathlen); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_RENAME_REQUEST_S(oldpathlen, newpathlen), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1547,6 +1808,8 @@ static int userfs_rename(FAR struct inode *mountpt, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); @@ -1586,31 +1849,44 @@ static int userfs_stat(FAR struct inode *mountpt, FAR const char *relpath, ssize_t nsent; ssize_t nrecvd; int pathlen; + int ret; DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); priv = mountpt->i_private; - /* Construct and send the request to the server */ - - req = (FAR struct userfs_stat_request_s *)priv->iobuffer; - req->req = USERFS_REQ_STAT; + /* Check the path length */ DEBUGASSERT(relpath != NULL); - pathlen = strlen(relpath); + pathlen = strlen(relpath); if (pathlen > priv->mxwrite) { return -E2BIG; } + /* Get exclusive access */ + + ret = sem_wait(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + /* Construct and send the request to the server */ + + req = (FAR struct userfs_stat_request_s *)priv->iobuffer; + req->req = USERFS_REQ_STAT; + strncpy(req->relpath, relpath, priv->mxwrite); nsent = psock_sendto(&priv->psock, priv->iobuffer, SIZEOF_USERFS_STAT_REQUEST_S(pathlen + 1), 0, - (FAR struct sockaddr *)&priv->server, priv->addrlen); + (FAR struct sockaddr *)&priv->server, + sizeof(struct sockaddr_in)); if (nsent < 0) { ferr("ERROR: psock_sendto failed: %d\n", (int)nsent); + sem_post(&priv->exclsem); return (int)nsent; } @@ -1618,6 +1894,8 @@ static int userfs_stat(FAR struct inode *mountpt, FAR const char *relpath, nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv), 0, NULL, NULL); + sem_post(&priv->exclsem); + if (nrecvd < 0) { ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd); diff --git a/include/nuttx/fs/userfs.h b/include/nuttx/fs/userfs.h index 8eeef7d3bfb..413fe31bddb 100644 --- a/include/nuttx/fs/userfs.h +++ b/include/nuttx/fs/userfs.h @@ -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. diff --git a/libc/userfs/lib_userfs.c b/libc/userfs/lib_userfs.c index 8f80e94d967..63512055708 100644 --- a/libc/userfs/lib_userfs.c +++ b/libc/userfs/lib_userfs.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -52,20 +51,11 @@ #include #include +#include +#include + #include -/**************************************************************************** - * Pre-processor Definition - ****************************************************************************/ -/* There is a bug in the local socket recvfrom() logic as of this writing: - * The recvfrom logic for local datagram sockets returns the incorrect - * sender "from" address. Instead, it returns the receiver's "to" address. - * This means that returning a reply to the "from" address receiver sending - * a packet to itself. - */ - -#define LOCAL_RECVFROM_WAR 1 - /**************************************************************************** * Private Types ****************************************************************************/ @@ -74,8 +64,7 @@ struct userfs_info_s { FAR const struct userfs_operations_s *userops; /* File system callbacks */ FAR void *volinfo; /* Data that accompanies the user callbacks */ - struct sockaddr_un client; /* Client to send response back to */ - socklen_t addrlen; /* Length of the client address */ + struct sockaddr_in client; /* Client to send response back to */ int16_t sockfd; /* Server socket */ uint16_t iolen; /* Size of I/O buffer */ uint16_t mxwrite; /* The max size of a write data */ @@ -93,18 +82,18 @@ struct userfs_info_s * not generate unique instance numbers. */ -static sem_t g_userfs_exclsem = SEM_INITIALIZER(1); -static uint16_t g_userfs_next_instance; +static sem_t g_userfs_exclsem = SEM_INITIALIZER(1); +static uint8_t g_userfs_next_instance; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: userfs_instance + * Name: userfs_server_portno ****************************************************************************/ -static inline uint16_t userfs_instance(void) +static inline uint16_t userfs_server_portno(void) { int ret; @@ -118,7 +107,7 @@ static inline uint16_t userfs_instance(void) * happen if g_userfs_next_instance were to wrap around. */ - ret = g_userfs_next_instance++; + ret = USERFS_SERVER_PORTBASE | g_userfs_next_instance++; nxsem_post(&g_userfs_exclsem); } @@ -164,14 +153,16 @@ static inline int userfs_open_dispatch(FAR struct userfs_info_s *info, */ DEBUGASSERT(info->userops != NULL && info->userops->open != NULL); - resp.ret = info->userops->open(info->volinfo, req->relpath, req->oflags, - req->mode, &resp.openinfo); + resp.ret = info->userops->open(info->volinfo, req->relpath, req->oflags, + req->mode, &resp.openinfo); /* Send the response */ resp.resp = USERFS_RESP_OPEN; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_open_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_open_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); if (nsent < 0) { ret = -errno; @@ -201,13 +192,15 @@ static inline int userfs_close_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->close != NULL); - resp.ret = info->userops->close(info->volinfo, req->openinfo); + resp.ret = info->userops->close(info->volinfo, req->openinfo); /* Send the response */ resp.resp = USERFS_RESP_CLOSE; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_close_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_close_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -242,10 +235,11 @@ static inline int userfs_read_dispatch(FAR struct userfs_info_s *info, /* Send the response */ - resp->resp = USERFS_RESP_READ; - resplen = SIZEOF_USERFS_READ_RESPONSE_S(resp->nread); - nsent = sendto(info->sockfd, resp, resplen, 0, - (FAR struct sockaddr *)&info->client, info->addrlen); + resp->resp = USERFS_RESP_READ; + resplen = SIZEOF_USERFS_READ_RESPONSE_S(resp->nread); + nsent = sendto(info->sockfd, resp, resplen, 0, + (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -284,9 +278,11 @@ static inline int userfs_write_dispatch(FAR struct userfs_info_s *info, /* Send the response */ - resp.resp = USERFS_RESP_WRITE; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_write_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + resp.resp = USERFS_RESP_WRITE; + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_write_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -306,14 +302,16 @@ static inline int userfs_seek_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->seek != NULL); - resp.ret = info->userops->seek(info->volinfo, req->openinfo, req->offset, - req->whence); + resp.ret = info->userops->seek(info->volinfo, req->openinfo, req->offset, + req->whence); /* Send the response */ resp.resp = USERFS_RESP_SEEK; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_seek_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_seek_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -333,14 +331,16 @@ static inline int userfs_ioctl_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->ioctl != NULL); - resp.ret = info->userops->ioctl(info->volinfo, req->openinfo, req->cmd, - req->arg); + resp.ret = info->userops->ioctl(info->volinfo, req->openinfo, req->cmd, + req->arg); /* Send the response */ resp.resp = USERFS_RESP_IOCTL; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_ioctl_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_ioctl_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -360,13 +360,15 @@ static inline int userfs_sync_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->sync != NULL); - resp.ret = info->userops->sync(info->volinfo, req->openinfo); + resp.ret = info->userops->sync(info->volinfo, req->openinfo); /* Send the response */ resp.resp = USERFS_RESP_SYNC; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_sync_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_sync_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -386,13 +388,15 @@ static inline int userfs_dup_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->dup != NULL); - resp.ret = info->userops->dup(info->volinfo, req->openinfo, &resp.openinfo); + resp.ret = info->userops->dup(info->volinfo, req->openinfo, &resp.openinfo); /* Send the response */ resp.resp = USERFS_RESP_DUP; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_dup_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_dup_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -412,13 +416,15 @@ static inline int userfs_fstat_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->fstat != NULL); - resp.ret = info->userops->fstat(info->volinfo, req->openinfo, &resp.buf); + resp.ret = info->userops->fstat(info->volinfo, req->openinfo, &resp.buf); /* Send the response */ resp.resp = USERFS_RESP_FSTAT; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_fstat_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_fstat_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -452,13 +458,15 @@ static inline int userfs_opendir_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->opendir != NULL); - resp.ret = info->userops->opendir(info->volinfo, req->relpath, &resp.dir); + resp.ret = info->userops->opendir(info->volinfo, req->relpath, &resp.dir); /* Send the response */ resp.resp = USERFS_RESP_OPENDIR; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_opendir_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_opendir_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -478,13 +486,15 @@ static inline int userfs_closedir_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->closedir != NULL); - resp.ret = info->userops->closedir(info->volinfo, req->dir); + resp.ret = info->userops->closedir(info->volinfo, req->dir); /* Send the response */ resp.resp = USERFS_RESP_CLOSEDIR; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_open_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_closedir_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -504,13 +514,15 @@ static inline int userfs_readdir_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->readdir != NULL); - resp.ret = info->userops->readdir(info->volinfo, req->dir, &resp.entry); + resp.ret = info->userops->readdir(info->volinfo, req->dir, &resp.entry); /* Send the response */ resp.resp = USERFS_RESP_READDIR; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_readdir_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_readdir_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -530,13 +542,15 @@ static inline int userfs_rewinddir_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->rewinddir != NULL); - resp.ret = info->userops->rewinddir(info->volinfo, req->dir); + resp.ret = info->userops->rewinddir(info->volinfo, req->dir); /* Send the response */ resp.resp = USERFS_RESP_REWINDDIR; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_rewinddir_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_rewinddir_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -556,13 +570,15 @@ static inline int userfs_statfs_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->statfs != NULL); - resp.ret = info->userops->statfs(info->volinfo, &resp.buf); + resp.ret = info->userops->statfs(info->volinfo, &resp.buf); /* Send the response */ resp.resp = USERFS_RESP_STATFS; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_statfs_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_statfs_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -596,13 +612,15 @@ static inline int userfs_unlink_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->unlink != NULL); - resp.ret = info->userops->unlink(info->volinfo, req->relpath); + resp.ret = info->userops->unlink(info->volinfo, req->relpath); /* Send the response */ resp.resp = USERFS_RESP_UNLINK; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_unlink_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_unlink_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -636,13 +654,15 @@ static inline int userfs_mkdir_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->mkdir != NULL); - resp.ret = info->userops->mkdir(info->volinfo, req->relpath, req->mode); + resp.ret = info->userops->mkdir(info->volinfo, req->relpath, req->mode); /* Send the response */ resp.resp = USERFS_RESP_MKDIR; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_mkdir_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_mkdir_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -676,13 +696,15 @@ static inline int userfs_rmdir_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->rmdir != NULL); - resp.ret = info->userops->rmdir(info->volinfo, req->relpath); + resp.ret = info->userops->rmdir(info->volinfo, req->relpath); /* Send the response */ resp.resp = USERFS_RESP_RMDIR; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_rmdir_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_rmdir_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -729,14 +751,16 @@ static inline int userfs_rename_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->rename != NULL); - resp.ret = info->userops->rename(info->volinfo, req->oldrelpath, - newrelpath); + resp.ret = info->userops->rename(info->volinfo, req->oldrelpath, + newrelpath); /* Send the response */ resp.resp = USERFS_RESP_RENAME; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_rename_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_rename_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -770,13 +794,15 @@ static inline int userfs_stat_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->stat != NULL); - resp.ret = info->userops->stat(info->volinfo, req->relpath, &resp.buf); + resp.ret = info->userops->stat(info->volinfo, req->relpath, &resp.buf); /* Send the response */ resp.resp = USERFS_RESP_STAT; - nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_stat_response_s), - 0, (FAR struct sockaddr *)&info->client, info->addrlen); + nsent = sendto(info->sockfd, &resp, + sizeof(struct userfs_stat_response_s), + 0, (FAR struct sockaddr *)&info->client, + sizeof(struct sockaddr_in)); return nsent < 0 ? nsent : OK; } @@ -796,7 +822,7 @@ static inline int userfs_destroy_dispatch(FAR struct userfs_info_s *info, /* Dispatch the request */ DEBUGASSERT(info->userops != NULL && info->userops->destroy != NULL); - resp.ret = info->userops->destroy(info->volinfo); + resp.ret = info->userops->destroy(info->volinfo); /* Send the response */ @@ -804,7 +830,7 @@ static inline int userfs_destroy_dispatch(FAR struct userfs_info_s *info, nsent = sendto(info->sockfd, &resp, sizeof(struct userfs_destroy_response_s), 0, (FAR struct sockaddr *)&info->client, - info->addrlen); + sizeof(struct sockaddr_in)); if (nsent < 0) { int ret = -errno; @@ -836,13 +862,13 @@ static inline int userfs_destroy_dispatch(FAR struct userfs_info_s *info, * * 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. @@ -869,7 +895,7 @@ int userfs_run(FAR const char *mountpt, { FAR struct userfs_info_s *info; FAR struct userfs_config_s config; - struct sockaddr_un server; + struct sockaddr_in server; unsigned int iolen; socklen_t addrlen; ssize_t nread; @@ -878,7 +904,7 @@ int userfs_run(FAR const char *mountpt, DEBUGASSERT(mountpt != NULL && userops != NULL && mxwrite <= UINT16_MAX); DEBUGASSERT(mxwrite > 0 && mxwrite <= (UINT16_MAX - USERFS_REQ_MAXSIZE)); - /* Allocate a state structrue with an I/O buffer to receive UserFS requests */ + /* Allocate a state structure with an I/O buffer to receive UserFS requests */ iolen = USERFS_REQ_MAXSIZE + mxwrite; info = (FAR struct userfs_info_s *)zalloc(SIZEOF_USERFS_INFO_S(iolen)); @@ -900,7 +926,7 @@ int userfs_run(FAR const char *mountpt, */ config.mxwrite = mxwrite; - config.instance = userfs_instance(); + config.portno = userfs_server_portno(); /* Mounts the user file system at the provided mount point path. */ @@ -912,9 +938,9 @@ int userfs_run(FAR const char *mountpt, goto errout_with_info; } - /* Create a new Unix domain datagram server socket */ + /* Create a new LocalHost UDP server socket */ - info->sockfd = socket(PF_LOCAL, SOCK_DGRAM, 0); + info->sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (info->sockfd < 0) { ret = -get_errno(); @@ -922,15 +948,14 @@ int userfs_run(FAR const char *mountpt, goto errout_with_info; } - /* Bind the socket to a local server address */ + /* Bind the socket to a server port number */ - server.sun_family = AF_LOCAL; - snprintf(server.sun_path, UNIX_PATH_MAX, USERFS_SERVER_FMT, - config.instance); - server.sun_path[UNIX_PATH_MAX - 1] = '\0'; + server.sin_family = AF_INET; + server.sin_port = htons(config.portno); + server.sin_addr.s_addr = HTONL(INADDR_LOOPBACK); - addrlen = strlen(server.sun_path) + sizeof(sa_family_t) + 1; - ret = bind(info->sockfd, (struct sockaddr*)&server, addrlen); + ret = bind(info->sockfd, (struct sockaddr *)&server, + sizeof(struct sockaddr_in)); if (ret < 0) { ret = -get_errno(); @@ -938,19 +963,6 @@ int userfs_run(FAR const char *mountpt, goto errout_with_sockfd; } -#ifdef LOCAL_RECVFROM_WAR - /* Since this is a simple point-to-point communication with well known - * addresses at each endpoint, we can preset the client address. - */ - - info->client.sun_family = AF_LOCAL; - snprintf(info->client.sun_path, UNIX_PATH_MAX, USERFS_CLIENT_FMT, - config.instance); - info->client.sun_path[UNIX_PATH_MAX - 1] = '\0'; - - info->addrlen = strlen(info->client.sun_path) + sizeof(sa_family_t) + 1; -#endif - /* Receive file system requests on the POSIX message queue as long * as the mount persists. */ @@ -960,16 +972,10 @@ int userfs_run(FAR const char *mountpt, /* Receive the next file system request */ finfo("Receiving up %u bytes\n", info->iolen); -#ifdef LOCAL_RECVFROM_WAR - nread = recvfrom(info->sockfd, info->iobuffer, info->iolen, 0, - NULL, NULL); -#else - info->addrlen = 0; - nread = recvfrom(info->sockfd, info->iobuffer, info->iolen, 0, - (FAR struct sockaddr *)&info->client, - &info->addrlen); -#endif - + addrlen = sizeof(struct sockaddr_in); + nread = recvfrom(info->sockfd, info->iobuffer, info->iolen, 0, + (FAR struct sockaddr *)&info->client, + &addrlen); if (nread < 0) { ret = -get_errno(); @@ -977,10 +983,7 @@ int userfs_run(FAR const char *mountpt, goto errout_with_sockfd; } -#ifndef LOCAL_RECVFROM_WAR - DEBUGASSERT(info->addrlen >= sizeof(sa_family_t) && - info->addrlen <= sizeof(struct sockaddr_un)); -#endif + DEBUGASSERT(addrlen == sizeof(struct sockaddr_in)); /* Process the request according to its request ID */ @@ -1095,7 +1098,7 @@ int userfs_run(FAR const char *mountpt, } while (ret == OK); - /* Close the Unix domain socket */ + /* Close the LocalHost socket */ errout_with_sockfd: close(info->sockfd);