romfs: cache romfs entry to improve access file speed
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
This commit is contained in:
parent
bc43206920
commit
f677a0d316
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user