diff --git a/fs/dirent/fs_readdir.c b/fs/dirent/fs_readdir.c index f7cc4a69e6..b9dcd3cf1a 100644 --- a/fs/dirent/fs_readdir.c +++ b/fs/dirent/fs_readdir.c @@ -1,7 +1,8 @@ /**************************************************************************** * fs/dirent/fs_readdir.c * - * Copyright (C) 2007-2009, 2011, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2017-2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -64,9 +65,9 @@ static inline int readpseudodir(struct fs_dirent_s *idir) if (!idir->u.pseudo.fd_next) { - /* End of file and error conditions are not distinguishable - * with readdir. Here we return -ENOENT to signal the end - * of the directory. + /* End of file and error conditions are not distinguishable with + * readdir. Here we return -ENOENT to signal the end of the + * directory. */ return -ENOENT; @@ -74,17 +75,17 @@ static inline int readpseudodir(struct fs_dirent_s *idir) /* Copy the inode name into the dirent structure */ - strncpy(idir->fd_dir.d_name, idir->u.pseudo.fd_next->i_name, NAME_MAX+1); + strncpy(idir->fd_dir.d_name, idir->u.pseudo.fd_next->i_name, + NAME_MAX + 1); - /* If the node has file operations, we will say that it is - * a file. - */ + /* If the node has file operations, we will say that it is a file. */ idir->fd_dir.d_type = 0; if (idir->u.pseudo.fd_next->u.i_ops) { #ifndef CONFIG_DISABLE_MOUNTPOINT - if (INODE_IS_BLOCK(idir->u.pseudo.fd_next)) + if (INODE_IS_BLOCK(idir->u.pseudo.fd_next) || + INODE_IS_MTD(idir->u.pseudo.fd_next)) { idir->fd_dir.d_type |= DTYPE_BLK; } @@ -249,4 +250,3 @@ errout: set_errno(ret); return NULL; } - diff --git a/fs/driver/Make.defs b/fs/driver/Make.defs index 33013d0f6a..e8fb165881 100644 --- a/fs/driver/Make.defs +++ b/fs/driver/Make.defs @@ -48,6 +48,7 @@ CSRCS += fs_blockpartition.c ifeq ($(CONFIG_MTD),y) CSRCS += fs_registermtddriver.c fs_unregistermtddriver.c fs_findmtddriver.c +CSRCS += fs_mtdproxy.c endif ifneq ($(CONFIG_DISABLE_PSEUDOFS_OPERATIONS),y) diff --git a/fs/driver/driver.h b/fs/driver/driver.h index 5731c35e25..fc409129c4 100644 --- a/fs/driver/driver.h +++ b/fs/driver/driver.h @@ -122,6 +122,40 @@ int find_blockdriver(FAR const char *pathname, int mountflags, int block_proxy(FAR const char *blkdev, int oflags); #endif +/**************************************************************************** + * Name: mtd_proxy + * + * Description: + * Create a temporary block driver using drivers/mtd/ftl to mediate block + * oriented accessed to the mtd driver. + * + * Input Parameters: + * mtddev - The path to the mtd driver + * mountflags - if MS_RDONLY is not set, then driver must support write + * operations (see include/sys/mount.h) + * ppinode - address of the location to return the inode reference + * + * Returned Value: + * If zero, non-zero inode pointer is returned on success. This + * is the inode pointer of the nameless block driver that mediates + * accesses to the mtd driver. + * + * Errors that may be returned: + * + * ENOMEM - Failed to create a temporay path name. + * + * Plus: + * + * - Errors reported from ftl_initialize() + * - Errors reported from open() or unlink() + * + ****************************************************************************/ + +#ifdef CONFIG_MTD +int mtd_proxy(FAR const char *mtddev, int mountflags, + FAR struct inode **ppinode); +#endif + /**************************************************************************** * Name: find_mtddriver * diff --git a/fs/driver/fs_blockproxy.c b/fs/driver/fs_blockproxy.c index 1cb47d08f9..1a8e246744 100644 --- a/fs/driver/fs_blockproxy.c +++ b/fs/driver/fs_blockproxy.c @@ -121,7 +121,7 @@ static FAR char *unique_chardev(void) /* Construct the full device number */ devno &= 0xffffff; - snprintf(devbuf, 16, "/dev/tmp%06lx", (unsigned long)devno); + snprintf(devbuf, 16, "/dev/tmpc%06lx", (unsigned long)devno); /* Make sure that file name is not in use */ diff --git a/fs/driver/fs_mtdproxy.c b/fs/driver/fs_mtdproxy.c new file mode 100644 index 0000000000..01109b8221 --- /dev/null +++ b/fs/driver/fs_mtdproxy.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * fs/driver/fs_mtdproxy.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "driver/driver.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint32_t g_devno; +static sem_t g_devno_sem = SEM_INITIALIZER(1); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unique_blkdev + * + * Description: + * Create a unique temporary device name in the /dev/ directory of the + * pseudo-file system. We cannot use mktemp for this because it will + * attempt to open() the file. + * + * Input Parameters: + * None + * + * Returned Value: + * The allocated path to the device. This must be released by the caller + * to prevent memory links. NULL will be returned only the case where + * we fail to allocate memory. + * + ****************************************************************************/ + +static FAR char *unique_blkdev(void) +{ + struct stat statbuf; + char devbuf[16]; + uint32_t devno; + int ret; + + /* Loop until we get a unique device name */ + + for (; ; ) + { + /* Get the semaphore protecting the path number */ + + do + { + ret = nxsem_wait(&g_devno_sem); + + /* The only case that an error should occur here is if the wait + * was awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR); + } + while (ret == -EINTR); + + /* Get the next device number and release the semaphore */ + + devno = ++g_devno; + nxsem_post(&g_devno_sem); + + /* Construct the full device number */ + + devno &= 0xffffff; + snprintf(devbuf, 16, "/dev/tmpb%06lx", (unsigned long)devno); + + /* Make sure that file name is not in use */ + + ret = stat(devbuf, &statbuf); + if (ret < 0) + { + DEBUGASSERT(errno == ENOENT); + return strdup(devbuf); + } + + /* It is in use, try again */ + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mtd_proxy + * + * Description: + * Create a temporary block driver using drivers/mtd/ftl to mediate block + * oriented accessed to the mtd driver. + * + * Input Parameters: + * mtddev - The path to the mtd driver + * mountflags - if MS_RDONLY is not set, then driver must support write + * operations (see include/sys/mount.h) + * ppinode - address of the location to return the inode reference + * + * Returned Value: + * If zero, non-zero inode pointer is returned on success. This + * is the inode pointer of the nameless block driver that mediates + * accesses to the mtd driver. + * + * Errors that may be returned: + * + * ENOMEM - Failed to create a temporay path name. + * + * Plus: + * + * - Errors reported from ftl_initialize() + * - Errors reported from open() or unlink() + * + ****************************************************************************/ + +int mtd_proxy(FAR const char *mtddev, int mountflags, + FAR struct inode **ppinode) +{ + FAR struct inode *mtd; + FAR char *blkdev; + int ret; + + /* Create a unique temporary file name for the block device */ + + blkdev = unique_blkdev(); + if (blkdev == NULL) + { + ferr("ERROR: Failed to create temporary device name\n"); + return -ENOMEM; + } + + /* Wrap the mtd driver with an instance of the ftl driver */ + + ret = find_mtddriver(mtddev, &mtd); + if (ret < 0) + { + ferr("ERROR: Failed to find %s mtd driver\n", mtddev); + goto out_with_blkdev; + } + + ret = ftl_initialize_by_path(blkdev, mtd->u.i_mtd); + inode_release(mtd); + if (ret < 0) + { + ferr("ERROR: ftl_initialize_by_path(%s, %s) failed: %d\n", + mtddev, blkdev, ret); + goto out_with_blkdev; + } + + /* Open the newly created block driver */ + + ret = open_blockdriver(blkdev, mountflags, ppinode); + if (ret < 0) + { + ferr("ERROR: Failed to open %s: %d\n", blkdev, ret); + goto out_with_fltdev; + } + + /* Unlink and free the block device name. The driver instance will persist, + * provided that CONFIG_DISABLE_PSEUDOFS_OPERATIONS=y (otherwise, we have + * a problem here!) + */ + +out_with_fltdev: + unlink(blkdev); +out_with_blkdev: + kmm_free(blkdev); + return ret; +} + diff --git a/fs/driver/fs_openblockdriver.c b/fs/driver/fs_openblockdriver.c index e88d05d752..19f0afec5e 100644 --- a/fs/driver/fs_openblockdriver.c +++ b/fs/driver/fs_openblockdriver.c @@ -84,8 +84,7 @@ int open_blockdriver(FAR const char *pathname, int mountflags, #ifdef CONFIG_DEBUG_FEATURES if (!ppinode) { - ret = -EINVAL; - goto errout; + return -EINVAL; } #endif @@ -96,8 +95,14 @@ int open_blockdriver(FAR const char *pathname, int mountflags, ret = find_blockdriver(pathname, mountflags, &inode); if (ret < 0) { +#ifdef CONFIG_MTD + /* Not block device, mtd device? let's try it. */ + + return mtd_proxy(pathname, mountflags, ppinode); +#else ferr("ERROR: Failed to file %s block driver\n", pathname); - goto errout; + return ret; +#endif } /* Open the block driver. Note that no mutually exclusive access @@ -111,15 +116,11 @@ int open_blockdriver(FAR const char *pathname, int mountflags, if (ret < 0) { ferr("ERROR: %s driver open failed\n", pathname); - goto errout_with_inode; + inode_release(inode); + return ret; } } *ppinode = inode; return OK; - -errout_with_inode: - inode_release(inode); -errout: - return ret; } diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index f3f3cff863..9f61b21d61 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -157,7 +157,7 @@ int nx_vopen(FAR const char *path, int oflags, va_list ap) * NOTE: This will recurse to open the character driver proxy. */ - if (INODE_IS_BLOCK(inode)) + if (INODE_IS_BLOCK(inode) || INODE_IS_MTD(inode)) { /* Release the inode reference */ diff --git a/fs/vfs/fs_poll.c b/fs/vfs/fs_poll.c index 9a7ba6d1a4..a1b9e89f04 100644 --- a/fs/vfs/fs_poll.c +++ b/fs/vfs/fs_poll.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/vfs/fs_poll.c * - * Copyright (C) 2008-2009, 2012-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009, 2012-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -108,7 +108,7 @@ static int poll_fdsetup(int fd, FAR struct pollfd *fds, bool setup) /* Perform the socket ioctl */ #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 - if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) + if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) { return net_poll(fd, fds, setup); } @@ -352,7 +352,8 @@ int file_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) * reading and writing." */ - if (INODE_IS_MOUNTPT(inode) || INODE_IS_BLOCK(inode)) + if (INODE_IS_MOUNTPT(inode) || INODE_IS_BLOCK(inode) || + INODE_IS_MTD(inode)) { if (setup) { diff --git a/fs/vfs/fs_stat.c b/fs/vfs/fs_stat.c index caf703c7db..869f7ceec0 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -296,6 +296,15 @@ int inode_stat(FAR struct inode *inode, FAR struct stat *buf) } else #endif +#if defined(CONFIG_MTD) + if (INODE_IS_MTD(inode)) + { + buf->st_mode = S_IFMTD; + buf->st_mode |= S_IROTH | S_IRGRP | S_IRUSR; + buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; + } + else +#endif #ifdef CONFIG_PSEUDOFS_SOFTLINKS /* Handle softlinks differently. Just call stat() recursively on the * target of the softlink. diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 23313d9786..fe22dcce01 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -386,7 +386,7 @@ union inode_ops_u #ifndef CONFIG_DISABLE_MQUEUE FAR struct mqueue_inode_s *i_mqueue; /* POSIX message queue */ #endif -#ifndef CONFIGMTD +#ifdef CONFIG_MTD FAR struct mtd_dev_s *i_mtd; /* MTD device driver */ #endif #ifdef CONFIG_PSEUDOFS_SOFTLINKS