romfs: cache romfs entry to improve access file speed

Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
This commit is contained in:
Jiuzhu Dong 2022-02-09 22:24:04 +08:00 committed by Xiang Xiao
parent bc43206920
commit f677a0d316
5 changed files with 301 additions and 8 deletions

View File

@ -11,4 +11,13 @@ config FS_ROMFS
Enable ROMFS filesystem support
if FS_ROMFS
config FS_ROMFS_CACHE_NODE
bool "Enable cache node of ROMFS file system"
default !DEFAULT_SMALL
---help---
All node will be cached to ram when file system
is mounted so that we can quick access entry of ROMFS
filesystem on emmc/sdcard.
endif

View File

@ -242,8 +242,7 @@ static int romfs_open(FAR struct file *filep, FAR const char *relpath,
/* Get the start of the file data */
ret = romfs_datastart(rm, nodeinfo.rn_offset,
&rf->rf_startoffset);
ret = romfs_datastart(rm, &nodeinfo, &rf->rf_startoffset);
if (ret < 0)
{
ferr("ERROR: Failed to locate start of file data: %d\n", ret);
@ -791,8 +790,13 @@ static int romfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
/* The entry is a directory */
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
dir->u.romfs.fr_firstnode = nodeinfo.rn_child;
dir->u.romfs.fr_currnode = nodeinfo.rn_child;
#else
dir->u.romfs.fr_firstoffset = nodeinfo.rn_offset;
dir->u.romfs.fr_curroffset = nodeinfo.rn_offset;
#endif
errout_with_semaphore:
romfs_semgive(rm);
@ -810,10 +814,12 @@ static int romfs_readdir(FAR struct inode *mountpt,
FAR struct fs_dirent_s *dir)
{
FAR struct romfs_mountpt_s *rm;
#ifndef CONFIG_FS_ROMFS_CACHE_NODE
uint32_t linkoffset;
uint32_t next;
uint32_t info;
uint32_t size;
#endif
uint32_t next;
int ret;
finfo("Entry\n");
@ -847,7 +853,11 @@ static int romfs_readdir(FAR struct inode *mountpt,
{
/* Have we reached the end of the directory */
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
if (!dir->u.romfs.fr_currnode || !(*dir->u.romfs.fr_currnode))
#else
if (!dir->u.romfs.fr_curroffset)
#endif
{
/* We signal the end of the directory by returning the
* special error -ENOENT
@ -858,6 +868,11 @@ static int romfs_readdir(FAR struct inode *mountpt,
goto errout_with_semaphore;
}
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
next = (*dir->u.romfs.fr_currnode)->rn_next;
strcpy(dir->fd_dir.d_name, (*dir->u.romfs.fr_currnode)->rn_name);
dir->u.romfs.fr_currnode++;
#else
/* Parse the directory entry */
ret = romfs_parsedirentry(rm, dir->u.romfs.fr_curroffset, &linkoffset,
@ -881,6 +896,7 @@ static int romfs_readdir(FAR struct inode *mountpt,
/* Set up the next directory entry offset */
dir->u.romfs.fr_curroffset = next & RFNEXT_OFFSETMASK;
#endif
/* Check the file type */
@ -940,7 +956,11 @@ static int romfs_rewinddir(FAR struct inode *mountpt,
ret = romfs_checkmount(rm);
if (ret == OK)
{
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
dir->u.romfs.fr_currnode = dir->u.romfs.fr_firstnode;
#else
dir->u.romfs.fr_curroffset = dir->u.romfs.fr_firstoffset;
#endif
}
romfs_semgive(rm);
@ -1114,6 +1134,9 @@ static int romfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
kmm_free(rm->rm_buffer);
}
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
romfs_freenode(rm->rm_root);
#endif
nxsem_destroy(&rm->rm_sem);
kmm_free(rm);
return OK;

View File

@ -120,18 +120,22 @@
/* 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 fat32 filesystem.
* is mounted with a romfs filesystem.
*/
struct romfs_file_s;
struct romfs_mountpt_s
{
FAR struct inode *rm_blkdriver; /* The block driver inode that hosts the FAT32 fs */
FAR struct inode *rm_blkdriver; /* The block driver inode that hosts the romfs */
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
FAR struct romfs_nodeinfo_s *rm_root; /* The node for root node */
#else
uint32_t rm_rootoffset; /* Saved offset to the first root directory entry */
#endif
bool rm_mounted; /* true: The file system is ready */
uint16_t rm_hwsectorsize; /* HW: Sector size reported by block driver */
sem_t rm_sem; /* Used to assume thread-safe access */
uint32_t rm_refs; /* The references for all files opened on this mountpoint */
uint32_t rm_rootoffset; /* Saved offset to the first root directory entry */
uint32_t rm_hwnsectors; /* HW: The number of sectors reported by the hardware */
uint32_t rm_volsize; /* Size of the ROMFS volume */
uint32_t rm_cachesector; /* Current sector in the rm_buffer */
@ -158,12 +162,14 @@ struct romfs_file_s
* walking a path
*/
#ifndef CONFIG_FS_ROMFS_CACHE_NODE
struct romfs_nodeinfo_s
{
uint32_t rn_offset; /* Offset of real file header */
uint32_t rn_next; /* Offset of the next file header+flags */
uint32_t rn_size; /* Size (if file) */
};
#endif
/****************************************************************************
* Public Data
@ -201,8 +207,12 @@ int romfs_parsedirentry(FAR struct romfs_mountpt_s *rm, uint32_t offset,
FAR uint32_t *pinfo, FAR uint32_t *psize);
int romfs_parsefilename(FAR struct romfs_mountpt_s *rm, uint32_t offset,
FAR char *pname);
int romfs_datastart(FAR struct romfs_mountpt_s *rm, uint32_t offset,
int romfs_datastart(FAR struct romfs_mountpt_s *rm,
FAR struct romfs_nodeinfo_s *nodeinfo,
FAR uint32_t *start);
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
void romfs_freenode(FAR struct romfs_nodeinfo_s *node);
#endif
#undef EXTERN
#if defined(__cplusplus)

View File

@ -48,6 +48,7 @@
#define LINK_NOT_FOLLOWED 0
#define LINK_FOLLOWED 1
#define NODEINFO_NINCR 4
/****************************************************************************
* Private Functions
@ -84,6 +85,7 @@ static uint32_t romfs_devread32(FAR struct romfs_mountpt_s *rm, int ndx)
*
****************************************************************************/
#ifndef CONFIG_FS_ROMFS_CACHE_NODE
static inline int romfs_checkentry(FAR struct romfs_mountpt_s *rm,
uint32_t offset,
FAR const char *entryname, int entrylen,
@ -150,6 +152,7 @@ static inline int romfs_checkentry(FAR struct romfs_mountpt_s *rm,
return -ENOENT;
}
#endif
/****************************************************************************
* Name: romfs_devcacheread
@ -260,6 +263,47 @@ static int romfs_followhardlinks(FAR struct romfs_mountpt_s *rm,
return -ELOOP;
}
/****************************************************************************
* Name: romfs_nodeinfo_search/romfs_nodeinfo_compare
*
* Description:
* Compare two names
*
****************************************************************************/
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
static int romfs_nodeinfo_search(FAR const void *a, FAR const void *b)
{
FAR struct romfs_nodeinfo_s *nodeinfo = *(FAR struct romfs_nodeinfo_s **)b;
FAR const char *name2 = nodeinfo->rn_name;
FAR const char *name1 = a;
size_t len = nodeinfo->rn_namesize;
int ret;
ret = strncmp(name1, name2, len);
if (!ret)
{
if (name1[len] == '/' || name1[len] == '\0')
{
return 0;
}
else
{
return 1;
}
}
return ret;
}
static int romfs_nodeinfo_compare(FAR const void *a, FAR const void *b)
{
FAR const char *name = (*(FAR struct romfs_nodeinfo_s **)a)->rn_name;
return romfs_nodeinfo_search(name, b);
}
#endif
/****************************************************************************
* Name: romfs_searchdir
*
@ -273,6 +317,18 @@ static inline int romfs_searchdir(FAR struct romfs_mountpt_s *rm,
FAR const char *entryname, int entrylen,
FAR struct romfs_nodeinfo_s *nodeinfo)
{
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
FAR struct romfs_nodeinfo_s **cnodeinfo;
cnodeinfo = bsearch(entryname, nodeinfo->rn_child, nodeinfo->rn_count,
sizeof(FAR struct romfs_nodeinfo_s *),
romfs_nodeinfo_search);
if (cnodeinfo)
{
memcpy(nodeinfo, *cnodeinfo, sizeof(*nodeinfo));
return OK;
}
#else
uint32_t offset;
uint32_t next;
int16_t ndx;
@ -320,12 +376,130 @@ static inline int romfs_searchdir(FAR struct romfs_mountpt_s *rm,
offset = next;
}
while (next != 0);
#endif
/* There is nothing in this directory with that name */
return -ENOENT;
}
/****************************************************************************
* Name: romfs_cachenode
*
* Description:
* Alloc all entry node at once when filesystem is mounted
*
****************************************************************************/
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
static int romfs_cachenode(FAR struct romfs_mountpt_s *rm,
uint32_t offset, uint32_t next,
uint32_t size, FAR const char *name,
FAR struct romfs_nodeinfo_s **pnodeinfo)
{
FAR struct romfs_nodeinfo_s **child;
FAR struct romfs_nodeinfo_s *nodeinfo;
char childname[NAME_MAX + 1];
uint32_t linkoffset;
uint32_t info;
uint8_t num = 0;
int ret;
nodeinfo = kmm_zalloc(sizeof(struct romfs_nodeinfo_s) + strlen(name));
if (nodeinfo == NULL)
{
return -ENOMEM;
}
*pnodeinfo = nodeinfo;
nodeinfo->rn_offset = offset;
nodeinfo->rn_next = next;
nodeinfo->rn_namesize = strlen(name);
strcpy(nodeinfo->rn_name, name);
if (!IS_DIRECTORY(next))
{
nodeinfo->rn_size = size;
return 0;
}
child = nodeinfo->rn_child;
do
{
/* Parse the directory entry at this offset (which may be re-directed
* to some other entry if HARLINKED).
*/
ret = romfs_parsedirentry(rm, offset, &linkoffset, &next, &info,
&size);
if (ret < 0)
{
return ret;
}
/* Now we are pointing to the real entry of interest. Is it a
* directory? Or a file?
*/
if (IS_DIRECTORY(next) || IS_FILE(next))
{
ret = romfs_parsefilename(rm, offset, childname);
if (ret < 0)
{
return ret;
}
if (strcmp(childname, ".") != 0 && strcmp(childname, "..") != 0)
{
if (child == NULL || nodeinfo->rn_count == num - 1)
{
FAR void *tmp;
tmp = kmm_realloc(nodeinfo->rn_child,
(num + NODEINFO_NINCR) *
sizeof(FAR struct romfs_nodeinfo_s *));
if (tmp == NULL)
{
return -ENOMEM;
}
nodeinfo->rn_child = tmp;
memset(nodeinfo->rn_child + num, 0, NODEINFO_NINCR *
sizeof(FAR struct romfs_nodeinfo_s *));
num += NODEINFO_NINCR;
}
child = &nodeinfo->rn_child[nodeinfo->rn_count++];
if (IS_DIRECTORY(next))
{
linkoffset = info;
}
ret = romfs_cachenode(rm, linkoffset, next, size,
childname, child);
if (ret < 0)
{
nodeinfo->rn_count--;
return ret;
}
}
}
next &= RFNEXT_OFFSETMASK;
offset = next;
}
while (next != 0);
if (nodeinfo->rn_count > 1)
{
qsort(nodeinfo->rn_child, nodeinfo->rn_count,
sizeof(FAR struct romfs_nodeinfo_s *),
romfs_nodeinfo_compare);
}
return 0;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -603,7 +777,18 @@ int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm)
/* The root directory entry begins right after the header */
name = (FAR const char *)&rm->rm_buffer[ROMFS_VHDR_VOLNAME];
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
ndx = romfs_cachenode(rm, ROMFS_ALIGNUP(ROMFS_VHDR_VOLNAME +
strlen(name) + 1),
RFNEXT_DIRECTORY, 0, "", &rm->rm_root);
if (ndx < 0)
{
romfs_freenode(rm->rm_root);
return ndx;
}
#else
rm->rm_rootoffset = ROMFS_ALIGNUP(ROMFS_VHDR_VOLNAME + strlen(name) + 1);
#endif
/* and return success */
@ -703,6 +888,33 @@ int romfs_checkmount(FAR struct romfs_mountpt_s *rm)
return -ENODEV;
}
/****************************************************************************
* Name: romfs_freenode
*
* Description:
* free all entry node at once when filesystem is unmounted
*
****************************************************************************/
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
void romfs_freenode(FAR struct romfs_nodeinfo_s *nodeinfo)
{
int i;
if (IS_DIRECTORY(nodeinfo->rn_next))
{
for (i = 0; i < nodeinfo->rn_count; i++)
{
romfs_freenode(nodeinfo->rn_child[i]);
}
kmm_free(nodeinfo->rn_child);
}
kmm_free(nodeinfo);
}
#endif
/****************************************************************************
* Name: romfs_finddirentry
*
@ -723,9 +935,13 @@ int romfs_finddirentry(FAR struct romfs_mountpt_s *rm,
/* Start with the first element after the root directory */
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
memcpy(nodeinfo, rm->rm_root, sizeof(*nodeinfo));
#else
nodeinfo->rn_offset = rm->rm_rootoffset;
nodeinfo->rn_next = RFNEXT_DIRECTORY;
nodeinfo->rn_size = 0;
#endif
/* The root directory is a special case */
@ -951,9 +1167,16 @@ int romfs_parsefilename(FAR struct romfs_mountpt_s *rm, uint32_t offset,
*
****************************************************************************/
int romfs_datastart(FAR struct romfs_mountpt_s *rm, uint32_t offset,
int romfs_datastart(FAR struct romfs_mountpt_s *rm,
FAR struct romfs_nodeinfo_s *nodeinfo,
FAR uint32_t *start)
{
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
*start = ROMFS_ALIGNUP(nodeinfo->rn_offset +
ROMFS_FHDR_NAME + nodeinfo->rn_namesize);
return OK;
#else
uint32_t offset = nodeinfo->rn_offset;
int16_t ndx;
/* Loop until the header size is obtained. */
@ -989,4 +1212,5 @@ int romfs_datastart(FAR struct romfs_mountpt_s *rm, uint32_t offset,
}
return -EINVAL; /* Won't get here */
#endif
}

View File

@ -76,6 +76,32 @@ struct fs_fatdir_s
#endif /* CONFIG_FS_FAT */
#ifdef CONFIG_FS_ROMFS
#ifdef CONFIG_FS_ROMFS_CACHE_NODE
/* This structure represents one entry node in the romfs file system */
struct romfs_nodeinfo_s
{
FAR struct romfs_nodeinfo_s **rn_child; /* The node array for link to lower level */
uint16_t rn_count; /* The count of node in rn_child level */
uint32_t rn_offset; /* The offset to real file header of the current entry */
uint32_t rn_next; /* The offset of the next file header+flags */
uint32_t rn_size; /* The size to the entry (if file) */
uint8_t rn_namesize; /* The length of name of the entry */
char rn_name[1]; /* The name to the entry */
};
/* For ROMFS, we need to return the node to the current and start node
* of the directory entry being read
*/
struct fs_romfsdir_s
{
FAR struct romfs_nodeinfo_s **fr_firstnode; /* The address of first node in the directory */
FAR struct romfs_nodeinfo_s **fr_currnode; /* The address of current node into the directory */
};
#else
/* For ROMFS, we need to return the offset to the current and start positions
* of the directory entry being read
*/
@ -85,6 +111,7 @@ struct fs_romfsdir_s
off_t fr_firstoffset; /* Offset to the first entry in the directory */
off_t fr_curroffset; /* Current offset into the directory contents */
};
#endif
#endif /* CONFIG_FS_ROMFS */
#ifdef CONFIG_FS_CROMFS