diff --git a/fs/nxffs/Make.defs b/fs/nxffs/Make.defs index 558fd6be6d..88c3d9cee9 100644 --- a/fs/nxffs/Make.defs +++ b/fs/nxffs/Make.defs @@ -35,9 +35,9 @@ ifeq ($(CONFIG_FS_NXFFS),y) ASRCS += -CSRCS += nxffs_block.c nxffs_blockstats.c nxffs_cache.c \ - nxffs_initialize.c nxffs_inode.c nxffs_open.c nxffs_reformat.c \ - nxffs_stat.c nxffs_unlink.c nxffs_util.c +CSRCS += nxffs_block.c nxffs_blockstats.c nxffs_cache.c nxffs_dirent.c \ + nxffs_initialize.c nxffs_inode.c nxffs_ioctl.c nxffs_open.c \ + nxffs_reformat.c nxffs_stat.c nxffs_unlink.c nxffs_util.c # Argument for dependency checking diff --git a/fs/nxffs/README.txt b/fs/nxffs/README.txt new file mode 100755 index 0000000000..a2577e1f8e --- /dev/null +++ b/fs/nxffs/README.txt @@ -0,0 +1,94 @@ +General NXFFS organization +========================== + +The following example assumes 4 logical blocks per FLASH erase block. The +actual relationship is determined by the FLASH geometry reported by the MTD +driver. + +ERASE LOGICAL Inodes begin with a inode header. inode may +BLOCK BLOCK CONTENTS be marked as "deleted," pending clean-up. + n 4*n --+--------------+ + |BBBBBBBBBBBBBB| Logic block header + |IIIIIIIIIIIIII| Inodes begin with a inode header + |DDDDDDDDDDDDDD| Data block containing inode data block + | (Inode Data) | + 4*n+1 --+--------------+ + |BBBBBBBBBBBBBB| Logic block header + |DDDDDDDDDDDDDD| Inodes may consist of multiple data blocks + | (Inode Data) | + |IIIIIIIIIIIIII| Next inode header + | | Possibly a few unused bytes at the end of a block + 4*n+2 --+--------------+ + |BBBBBBBBBBBBBB| Logic block header + |DDDDDDDDDDDDDD| + | (Inode Data) | + 4*n+3 --+--------------+ + |BBBBBBBBBBBBBB| Logic block header + |IIIIIIIIIIIIII| Next inode header + |DDDDDDDDDDDDDD| + | (Inode Data) | + n+1 4*(n+1) --+--------------+ + |BBBBBBBBBBBBBB| Logic block header + | | All FLASH is unused after the end of the final + | | inode. + --+--------------+ + +General operation +================= + + Inodes are written starting at the beginning of FLASH. As inodes are + deleted, they are marked as deleted but not removed. As new inodes are + written, allocations proceed to toward the end of the FLASH -- thus, + supporting wear leveling by using all FLASH blocks equally. + + When the FLASH becomes full (no more space at the end of the FLASH), a + clean-up operation must be performed: All inodes marked deleted are + finally removed and the remaining inodes are packed at the beginning of + the FLASH. Allocations then continue at the freed FLASH memory at the + end of the FLASH. + +Headers +======= + BLOCK HEADER: + The block header is used to determine if the block has every been + formatted and also indicates bad blocks which should never be used. + + INODE HEADER: + Each inode begins with an inode header that contains, among other things, + the name of the inode, the offset to the first data block, and the + length of the inode data. + + At present, the only kind of inode support is a file. So for now, the + term file and inode are interchangeable. + + INODE DATA HEADER: + Inode data is enclosed in a data header. For a given inode, there + is at most one inode data block per logical block. If the inode data + spans more than one logical block, then the inode data may be enclosed + in multiple data blocks, one per logical block. + +NXFFS Limitations +================= + +This implementation is very simple as, as a result, has several limitations +that you should be aware before opting to use NXFFS: + +1. Since the files are contiguous in FLASH and since allocations always + proceed toward the end of the FLASH, there can only be one file opened + for writing at a time. Multiple files may be opened for reading. + +2. Files may not be increased in size after they have been closed. The + O_APPEND open flag is not supported. + +3. Files are always written sequential. Seeking within a file opened for + writing will not work. + +4. There are no directories, however, '/' may be used within a file name + string providing some illusion of directories. + +5. Files may be opened for reading or for writing, but not both: The O_RDWR + open flag is not supported. + +6. The clean-up process occurs only during a write when the free FLASH + memory at the end of the FLASH is exhausted. Thus, occasionally, file + writing may take a long time. diff --git a/fs/nxffs/nxffs.h b/fs/nxffs/nxffs.h index 0912605525..4f903a072e 100644 --- a/fs/nxffs/nxffs.h +++ b/fs/nxffs/nxffs.h @@ -73,14 +73,14 @@ * n 4*n --+--------------+ * |BBBBBBBBBBBBBB| Logic block header * |IIIIIIIIIIIIII| Inodes begin with a inode header - * |DDDDDDDDDDDDD| Data block containing inode data block + * |DDDDDDDDDDDDDD| Data block containing inode data block * | (Inode Data) | * 4*n+1 --+--------------+ * |BBBBBBBBBBBBBB| Logic block header * |DDDDDDDDDDDDDD| Inodes may consist of multiple data blocks * | (Inode Data) | * |IIIIIIIIIIIIII| Next inode header - * | | Possibly a few unused bytes at the end of a block + * | | Possibly a few unused bytes at the end of a block * 4*n+2 --+--------------+ * |BBBBBBBBBBBBBB| Logic block header * |DDDDDDDDDDDDDD| @@ -141,7 +141,6 @@ * 6. The clean-up process occurs only during a write when the free FLASH * memory at the end of the FLASH is exhausted. Thus, occasionally, file * writing may take a long time. - * */ /* Values for logical block state. Basically, there are only two, perhaps @@ -703,7 +702,7 @@ extern int nxffs_rminode(FAR struct nxffs_volume_s *volume, FAR const char *name * - nxffs_open() and nxffs_close() are defined in nxffs_open.c * - nxffs_ioctl() is defined in nxffs_ioctl.c * - nxffs_opendir(), nxffs_readdir(), and nxffs_rewindir() are defined in - * nxffs_dir.c + * nxffs_dirent.c * - nxffs_stat() and nxffs_statfs() are defined in nxffs_stat.c * - nxffs_unlink() is defined nxffs_unlink.c * diff --git a/fs/nxffs/nxffs_dirent.c b/fs/nxffs/nxffs_dirent.c new file mode 100644 index 0000000000..bd53ffe0ce --- /dev/null +++ b/fs/nxffs/nxffs_dirent.c @@ -0,0 +1,222 @@ +/**************************************************************************** + * fs/nxffs/nxffs_dirent.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: Linux/Documentation/filesystems/romfs.txt + * + * 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 "nxffs.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxffs_opendir + * + * Description: + * Open a directory for read access + * + ****************************************************************************/ + +int nxffs_opendir(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct fs_dirent_s *dir) +{ + struct nxffs_volume_s *volume; + int ret; + + fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL"); + + /* Sanity checks */ + + DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); + + /* Recover the file system state from the NuttX inode instance */ + + volume = mountpt->i_private; + ret = sem_wait(&volume->exclsem); + if (ret != OK) + { + goto errout; + } + + /* The requested directory must be the volume-relative "root" directory */ + + if (relpath && relpath[0] != '\0') + { + ret = -ENOENT; + goto errout_with_semaphore; + } + + /* Set the offset to the offset to the first valid inode */ + + dir->u.nxffs.nx_offset = volume->inoffset; + ret = OK; + +errout_with_semaphore: + sem_post(&volume->exclsem); +errout: + return ret; +} + +/**************************************************************************** + * Name: nxffs_readdir + * + * Description: Read the next directory entry + * + ****************************************************************************/ + +int nxffs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) +{ + FAR struct nxffs_volume_s *volume; + FAR struct nxffs_entry_s entry; + off_t offset; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); + + /* Recover the file system state from the NuttX inode instance */ + + volume = mountpt->i_private; + ret = sem_wait(&volume->exclsem); + if (ret != OK) + { + goto errout; + } + + /* Read the next inode header from the offset */ + + offset = dir->u.nxffs.nx_offset; + ret = nxffs_nextentry(volume, offset, &entry); + + /* If the read was successful, then handle the reported inode. Note + * that when the last inode has been reported, the value -ENOENT will + * be returned.. which is correct for the readdir() method. + */ + + if (ret == OK) + { + /* Return the filename and file type */ + + fvdbg("Offset %d: \"%s\"\n", entry.hoffset, entry.name); + dir->fd_dir.d_type = DTYPE_FILE; + strncpy(dir->fd_dir.d_name, entry.name, NAME_MAX+1); + + /* Discard this entry and set the next offset using the rw data + * length as the offset increment. This is, of course, not accurate + * because it does not account for the data headers that enclose the + * data. But it is guaranteed to be less than or equal to the + * correct offset and, hence, better then searching byte-for-byte. + */ + + dir->u.nxffs.nx_offset = entry.doffset + entry.datlen; + nxffs_freeentry(&entry); + ret = OK; + } + + sem_post(&volume->exclsem); +errout: + return ret; +} + +/**************************************************************************** + * Name: nxffs_rewindir + * + * Description: + * Reset directory read to the first entry + * + ****************************************************************************/ + +int nxffs_rewinddir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) +{ + FAR struct nxffs_volume_s *volume; + int ret; + + fvdbg("Entry\n"); + + /* Sanity checks */ + + DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); + + /* Recover the file system state from the NuttX inode instance */ + + volume = mountpt->i_private; + ret = sem_wait(&volume->exclsem); + if (ret != OK) + { + goto errout; + } + + /* Reset the offset to the FLASH offset to the first valid inode */ + + dir->u.nxffs.nx_offset = volume->inoffset; + ret = OK; + + sem_post(&volume->exclsem); +errout: + return ret; +} diff --git a/fs/nxffs/nxffs_ioctl.c b/fs/nxffs/nxffs_ioctl.c new file mode 100644 index 0000000000..d5fe2ece83 --- /dev/null +++ b/fs/nxffs/nxffs_ioctl.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * fs/nxffs/nxffs_ioctl.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: Linux/Documentation/filesystems/romfs.txt + * + * 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 "nxffs.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxffs_ioctl + * + * Description: + * Standard mountpoint ioctl method. + * + ****************************************************************************/ + +int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct nxffs_volume_s *volume; + + fvdbg("cmd: %d arg: %08lx\n", cmd, arg); + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover the file system state from the open file */ + + volume = filep->f_inode->i_private; + DEBUGASSERT(volume != NULL); + + /* No ioctl commands yet supported */ + + return -ENOTTY; +} diff --git a/fs/nxffs/nxffs_open.c b/fs/nxffs/nxffs_open.c index a7caebca5f..88bfbf3ff6 100644 --- a/fs/nxffs/nxffs_open.c +++ b/fs/nxffs/nxffs_open.c @@ -289,6 +289,10 @@ static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume, /**************************************************************************** * Name: nxffs_freeofile + * + * Description: + * Free resources held by an open file. + * ****************************************************************************/ static inline void nxffs_freeofile(FAR struct nxffs_ofile_s *ofile) diff --git a/include/nuttx/dirent.h b/include/nuttx/dirent.h index 27835a4b27..82e0a55c3e 100644 --- a/include/nuttx/dirent.h +++ b/include/nuttx/dirent.h @@ -105,6 +105,17 @@ struct fs_binfsdir_s unsigned int fb_index; /* Index to the next named entry point */ }; #endif + +#ifdef CONFIG_FS_NXFFS +/* NXFFS is the tiny NuttX wear-leveling FLASH file system. The state value is + * the offset in FLASH memory to the next inode entry. + */ + +struct fs_nxffsdir_s +{ + off_t nx_offset; /* Offset to the next inode */ +}; +#endif #endif /* CONFIG_DISABLE_MOUNTPOINT */ struct fs_dirent_s @@ -153,7 +164,10 @@ struct fs_dirent_s #ifdef CONFIG_APPS_BINDIR struct fs_binfsdir_s binfs; #endif +#ifdef CONFIG_FS_NXFFS + struct fs_nxffsdir_s nxffs; #endif +#endif /* !CONFIG_DISABLE_MOUNTPOINT */ } u; /* In any event, this the actual struct dirent that is returned by readdir */