| /**************************************************************************** |
| * fs/smartfs/smartfs.h |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| #ifndef __FS_SMARTFS_SMARTFS_H |
| #define __FS_SMARTFS_SMARTFS_H |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/types.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| |
| #include <nuttx/mtd/mtd.h> |
| #include <nuttx/fs/smart.h> |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* SMART Definitions ********************************************************/ |
| |
| /* General SMART organization. The following example assumes 4 logical |
| * sectors per FLASH erase block. The actual relationship is determined by |
| * the FLASH geometry reported by the MTD driver. |
| * |
| * ERASE LOGICAL Sectors begin with a sector header. |
| * Sectors may be marked as "released," |
| * BLOCK SECTOR CONTENTS pending garbage collection |
| * n 4*n --+---------------+ |
| * Hdr |LLLLLLLLLLLLLLL| Logical sector number (2 bytes) |
| * |QQQQQQQQQQQQQQQ| Sequence number (2 bytes) |
| * |SSSSSSSSSSSSSSS| Status bits (1 byte) |
| * +---------------+ |
| * |TTTTTTTTTTTTTTT| Sector Type (dir or file) (1 byte) |
| * |NNNNNNNNNNNNNNN| Number of next logical sector in chain |
| * |UUUUUUUUUUUUUUU| Number of bytes used in this sector |
| * | | |
| * | (Sector Data) | |
| * | | |
| * 4*n+1 --+---------------+ |
| * Sector Hdr |LLLLLLLLLLLLLLL| Logical sector number (2 bytes) |
| * |QQQQQQQQQQQQQQQ| Sequence number (2 bytes) |
| * |SSSSSSSSSSSSSSS| Status bits (1 byte) |
| * +---------------+ |
| * FS Hdr |TTTTTTTTTTTTTTT| Sector Type (dir or file) (1 byte) |
| * |NNNNNNNNNNNNNNN| Number of next logical sector in chain |
| * |UUUUUUUUUUUUUUU| Number of bytes used in this sector |
| * | | |
| * | (Sector Data) | |
| * | | |
| * 4*n+2 --+---------------+ |
| * Sector Hdr |LLLLLLLLLLLLLLL| Logical sector number (2 bytes) |
| * |QQQQQQQQQQQQQQQ| Sequence number (2 bytes) |
| * |SSSSSSSSSSSSSSS| Status bits (1 byte) |
| * +---------------+ |
| * FS Hdr |TTTTTTTTTTTTTTT| Sector Type (dir or file) (1 byte) |
| * |NNNNNNNNNNNNNNN| Number of next logical sector in chain |
| * |UUUUUUUUUUUUUUU| Number of bytes used in this sector |
| * | | |
| * | (Sector Data) | |
| * | | |
| * 4*n+3 --+---------------+ |
| * Sector Hdr |LLLLLLLLLLLLLLL| Logical sector number (2 bytes) |
| * |QQQQQQQQQQQQQQQ| Sequence number (2 bytes) |
| * |SSSSSSSSSSSSSSS| Status bits (1 byte) |
| * +---------------+ |
| * FS Hdr |TTTTTTTTTTTTTTT| Sector Type (dir or file) (1 byte) |
| * |NNNNNNNNNNNNNNN| Number of next logical sector in chain |
| * |UUUUUUUUUUUUUUU| Number of bytes used in this sector |
| * | | |
| * | (Sector Data) | |
| * | | |
| * n+1 4*(n+1) --+---------------+ |
| * Sector Hdr |LLLLLLLLLLLLLLL| Logical sector number (2 bytes) |
| * |QQQQQQQQQQQQQQQ| Sequence number (2 bytes) |
| * |SSSSSSSSSSSSSSS| Status bits (1 byte) |
| * +---------------+ |
| * FS Hdr |TTTTTTTTTTTTTTT| Sector Type (dir or file) (1 byte) |
| * |NNNNNNNNNNNNNNN| Number of next logical sector in chain |
| * |UUUUUUUUUUUUUUU| Number of bytes used in this sector |
| * | | |
| * | | |
| * | | |
| * --+---------------+ |
| * |
| * General operation: |
| * Physical sectors are allocated and assigned a logical sector number |
| * and a starting sequence number of zero. |
| * |
| * SECTOR HEADER: |
| * The sector header (first 5 bytes) tracks the state of each sector and |
| * is used by the SMART MTD block driver. At the block level, there is |
| * no notion of sector chaining, only allocated sectors within erase |
| * blocks. |
| * |
| * FILE SYSTEM (FS) HEADER: |
| * The file system header (next 5 bytes) tracks file and directory entries |
| * and chains. |
| * |
| * SMART Limitations: |
| * 1. SMART currently depends on the underlying MTD block driver supporting |
| * single-byte programming operation. This is due to the method it |
| * uses for marking a sector as "released", committed, etc. |
| * 2. Garbage collection can occur when a new sector is allocated or when |
| * existing sector data is overwritten with new data. Thus, occasionally, |
| * file writing may take longer than other times. |
| * 3. The implementation currently does not track bad blocks on the device. |
| * 4. There is no true wear-leveling implemented yet, though provesion have |
| * been made to reserve logical sectors to allow it to be added using |
| * a "sector aging" tracking mechanism. |
| */ |
| |
| /* Values for SMART inode state. |
| * |
| * SMART_STATE_FILE - The inode is a valid usable, file |
| * INODE_STATE_DELETED - The inode has been deleted. |
| * Other values - The inode is bad and has an invalid state. |
| * |
| * Care is taken so that the VALID to DELETED transition only involves |
| * burning bits from the erased to non-erased state. |
| */ |
| |
| #define INODE_STATE_FILE (CONFIG_NXFFS_ERASEDSTATE ^ 0x22) |
| #define INODE_STATE_DELETED (CONFIG_NXFFS_ERASEDSTATE ^ 0xaa) |
| |
| /* Directory entry flag definitions */ |
| |
| #define SMARTFS_DIRENT_EMPTY 0x8000 /* Set to non-erase state when entry used */ |
| #define SMARTFS_DIRENT_ACTIVE 0x4000 /* Set to erase state when entry is active */ |
| #define SMARTFS_DIRENT_TYPE 0x2000 /* Indicates the type of entry (file/dir) */ |
| #define SMARTFS_DIRENT_DELETING 0x1000 /* Directory entry is being deleted */ |
| #define SMARTFS_DIRENT_RESERVED 0x0E00 /* Reserved bits */ |
| #define SMARTFS_DIRENT_MODE 0x01FF /* Mode the file was created with */ |
| |
| #define SMARTFS_DIRENT_TYPE_DIR 0x2000 |
| #define SMARTFS_DIRENT_TYPE_FILE 0x0000 |
| |
| /* Number of bytes in the SMART magic sequences */ |
| |
| #define SMART_MAGICSIZE 4 |
| |
| /* Underlying MTD Block driver access functions */ |
| |
| #define FS_BOPS(f) (f)->fs_blkdriver->u.i_bops |
| #define FS_IOCTL(f,c,a) (FS_BOPS(f)->ioctl ? FS_BOPS(f)->ioctl((f)->fs_blkdriver,c,a) : (-ENOSYS)) |
| |
| /* The logical sector number of the root directory. */ |
| |
| #define SMARTFS_ROOT_DIR_SECTOR 3 |
| |
| /* Defines the sector types */ |
| |
| #define SMARTFS_SECTOR_TYPE_DIR 1 |
| #define SMARTFS_SECTOR_TYPE_FILE 2 |
| |
| #ifndef CONFIG_SMARTFS_DIRDEPTH |
| # define CONFIG_SMARTFS_DIRDEPTH 8 |
| #endif |
| |
| /* Buffer flags (when CRC enabled) */ |
| |
| #define SMARTFS_BFLAG_DIRTY 0x01 /* Set if data changed in the sector */ |
| #define SMARTFS_BFLAG_NEWALLOC 0x02 /* Set if sector not written since alloc */ |
| |
| #define SMARTFS_ERASEDSTATE_16BIT (uint16_t) ((CONFIG_SMARTFS_ERASEDSTATE << 8) | \ |
| CONFIG_SMARTFS_ERASEDSTATE) |
| |
| /* Size of temporary buffer used when a file is zero extended by ftruncate() |
| * logic. |
| */ |
| |
| #define SMARTFS_TRUNCBUFFER_SIZE 512 |
| |
| #ifndef offsetof |
| # define offsetof(type, member) ((size_t)&(((FAR type *)0)->member)) |
| #endif |
| |
| #ifdef CONFIG_SMARTFS_ALIGNED_ACCESS |
| # define SMARTFS_NEXTSECTOR(h) (smartfs_rdle16(h->nextsector)) |
| # define SMARTFS_SET_NEXTSECTOR(h, v) smartfs_wrle16(h->nextsector, \ |
| (uint16_t)(v)) |
| |
| # define SMARTFS_USED(h) (smartfs_rdle16(h->used)) |
| # define SMARTFS_SET_USED(h, v) smartfs_wrle16(h->used, \ |
| (uint16_t)(v)) |
| |
| #else |
| # define SMARTFS_NEXTSECTOR(h) (*((FAR uint16_t *)h->nextsector)) |
| # define SMARTFS_SET_NEXTSECTOR(h, v) ((*((FAR uint16_t *)h->nextsector)) = \ |
| (uint16_t)(v)) |
| |
| # define SMARTFS_USED(h) (*((FAR uint16_t *)h->used)) |
| # define SMARTFS_SET_USED(h, v) ((*((FAR uint16_t *)h->used)) = \ |
| (uint16_t)(v)) |
| #endif |
| |
| #ifdef CONFIG_MTD_SMART_ENABLE_CRC |
| #define CONFIG_SMARTFS_USE_SECTOR_BUFFER |
| #endif |
| |
| /**************************************************************************** |
| * Public Types |
| ****************************************************************************/ |
| |
| /* This structure defines each packed block on the FLASH media */ |
| |
| /* This is an in-memory representation of the SMART inode as extracted from |
| * FLASH and with additional state information. |
| */ |
| |
| struct smartfs_entry_s |
| { |
| uint16_t firstsector; /* Sector number of the name */ |
| uint16_t dsector; /* Sector number of the directory entry */ |
| uint16_t doffset; /* Offset of the directory entry */ |
| uint16_t dfirst; /* 1st sector number of the directory entry */ |
| uint16_t flags; /* Flags, including mode */ |
| FAR char *name; /* inode name */ |
| uint32_t utc; /* Time stamp */ |
| uint32_t datlen; /* Length of inode data */ |
| }; |
| |
| /* This is an on-device representation of the SMART inode as it exists on |
| * the FLASH. |
| */ |
| |
| struct smartfs_entry_header_s |
| { |
| uint16_t flags; /* Flags, including permissions: |
| * 15: Empty entry |
| * 14: Active entry |
| * 12-0: Permissions bits */ |
| int16_t firstsector; /* Sector number of the name */ |
| uint32_t utc; /* Time stamp */ |
| char name[0]; /* inode name */ |
| }; |
| |
| /* This structure describes the smartfs header at the start of each |
| * sector. It manages the sector chain and used bytes in the sector. |
| */ |
| |
| #if defined(CONFIG_MTD_SMART_ENABLE_CRC) && defined(CONFIG_SMART_CRC_32) |
| struct smartfs_chain_header_s |
| { |
| uint8_t nextsector[4]; /* Next logical sector in the chain */ |
| uint8_t used[4]; /* Number of bytes used in this sector */ |
| uint8_t type; /* Type of sector entry (file or dir) */ |
| }; |
| #elif defined(CONFIG_MTD_SMART_ENABLE_CRC) && defined(CONFIG_SMART_CRC_16) |
| struct smartfs_chain_header_s |
| { |
| uint8_t type; /* Type of sector entry (file or dir) */ |
| uint8_t nextsector[2]; /* Next logical sector in the chain */ |
| uint8_t used[2]; /* Number of bytes used in this sector */ |
| }; |
| #else |
| struct smartfs_chain_header_s |
| { |
| uint8_t type; /* Type of sector entry (file or dir) */ |
| uint8_t nextsector[2]; /* Next logical sector in the chain */ |
| uint8_t used[2]; /* Number of bytes used in this sector */ |
| }; |
| #endif |
| |
| /* This structure describes the state of one open file. This structure |
| * is protected by the volume semaphore. |
| */ |
| |
| struct smartfs_ofile_s |
| { |
| FAR struct smartfs_ofile_s *fnext; /* Supports a singly linked list */ |
| #ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER |
| FAR uint8_t *buffer; /* Sector buffer to reduce writes */ |
| uint8_t bflags; /* Buffer flags */ |
| #endif |
| int16_t crefs; /* Reference count */ |
| mode_t oflags; /* Open mode */ |
| struct smartfs_entry_s entry; /* Describes the SMARTFS inode entry */ |
| size_t filepos; /* Current file position */ |
| uint16_t currsector; /* Current sector of filepos */ |
| uint16_t curroffset; /* Current offset in sector */ |
| uint16_t byteswritten; /* Count of bytes written to currsector |
| * that have not been recorded in the |
| * sector yet. We delay updating the |
| * used field until the file is closed, |
| * a seek, or more data is written that |
| * causes the sector to change. |
| */ |
| char path[1]; /* The full path to the file */ |
| }; |
| |
| /* This structure represents the overall mountpoint state. An instance of |
| * this structure is retained as inode private data on each mountpoint that |
| * is mounted with a smartfs filesystem. |
| */ |
| |
| struct smartfs_mountpt_s |
| { |
| #if defined(CONFIG_SMARTFS_MULTI_ROOT_DIRS) || defined(CONFIG_FS_PROCFS) |
| FAR struct smartfs_mountpt_s *fs_next; /* Pointer to next SMART filesystem */ |
| #endif |
| FAR struct inode *fs_blkdriver; /* Our underlying block device */ |
| FAR struct smartfs_ofile_s *fs_head; /* A singly-linked list of open files */ |
| bool fs_mounted; /* true: The file system is ready */ |
| struct smart_format_s fs_llformat; /* Low level device format info */ |
| FAR char *fs_rwbuffer; /* Read/Write working buffer */ |
| FAR char *fs_workbuffer; /* Working buffer */ |
| uint8_t fs_rootsector; /* Root directory sector num */ |
| }; |
| |
| /**************************************************************************** |
| * Public Data |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Public Functions Prototypes |
| ****************************************************************************/ |
| |
| /* Forward references for utility functions */ |
| |
| struct smartfs_mountpt_s; |
| |
| /* Utility functions */ |
| |
| int smartfs_mount(FAR struct smartfs_mountpt_s *fs, bool writeable); |
| |
| int smartfs_unmount(FAR struct smartfs_mountpt_s *fs); |
| |
| int smartfs_finddirentry(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_entry_s *direntry, FAR const char *relpath, |
| FAR uint16_t *parentdirsector, FAR const char **filename); |
| |
| int smartfs_createentry(FAR struct smartfs_mountpt_s *fs, |
| uint16_t parentdirsector, FAR const char *filename, |
| uint16_t type, |
| mode_t mode, FAR struct smartfs_entry_s *direntry, |
| uint16_t sectorno, FAR struct smartfs_ofile_s *sf); |
| |
| int smartfs_deleteentry(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_entry_s *entry); |
| |
| int smartfs_countdirentries(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_entry_s *entry); |
| |
| int smartfs_sync_internal(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_ofile_s *sf); |
| |
| off_t smartfs_seek_internal(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_ofile_s *sf, off_t offset, int whence); |
| |
| int smartfs_shrinkfile(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_ofile_s *sf, off_t length); |
| |
| int smartfs_extendfile(FAR struct smartfs_mountpt_s *fs, |
| FAR struct smartfs_ofile_s *sf, off_t length); |
| |
| uint16_t smartfs_rdle16(FAR const void *val); |
| |
| void smartfs_wrle16(FAR void *dest, uint16_t val); |
| |
| uint32_t smartfs_rdle32(FAR const void *val); |
| |
| void smartfs_wrle32(FAR uint8_t *dest, uint32_t val); |
| |
| #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) |
| FAR struct smartfs_mountpt_s *smartfs_get_first_mount(void); |
| #endif |
| |
| #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) |
| FAR struct smartfs_mountpt_s *smartfs_get_first_mount(void); |
| #endif |
| |
| struct file; /* Forward references */ |
| struct inode; |
| struct fs_dirent_s; |
| struct statfs; |
| struct stat; |
| |
| #endif /* __FS_SMARTFS_SMARTFS_H */ |