diff --git a/fs/romfs/Kconfig b/fs/romfs/Kconfig index 427cf3bf85..ff0566ce82 100644 --- a/fs/romfs/Kconfig +++ b/fs/romfs/Kconfig @@ -27,4 +27,11 @@ config FS_ROMFS_CACHE_FILE_NSECTORS ---help--- The number of file cache sector +config FS_ROMFS_WRITEABLE + bool "Enable write extended feature in romfs" + default n + depends on FS_ROMFS_CACHE_NODE + ---help--- + Enable write extended feature in romfs + endif diff --git a/fs/romfs/fs_romfs.c b/fs/romfs/fs_romfs.c index 463852b379..25f6f6deda 100644 --- a/fs/romfs/fs_romfs.c +++ b/fs/romfs/fs_romfs.c @@ -1128,7 +1128,7 @@ static int romfs_bind(FAR struct inode *blkdriver, FAR const void *data, * the ROMF header */ - ret = romfs_fsconfigure(rm); + ret = romfs_fsconfigure(rm, data); if (ret < 0) { ferr("ERROR: romfs_fsconfigure failed: %d\n", ret); @@ -1238,6 +1238,9 @@ static int romfs_unbind(FAR void *handle, FAR struct inode **blkdriver, #ifdef CONFIG_FS_ROMFS_CACHE_NODE romfs_freenode(rm->rm_root); +#endif +#ifdef CONFIG_FS_ROMFS_WRITEABLE + romfs_free_sparelist(&rm->rm_sparelist); #endif nxrmutex_destroy(&rm->rm_lock); fs_heap_free(rm); @@ -1296,8 +1299,8 @@ static int romfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf) /* Everything else follows in units of sectors */ buf->f_blocks = SEC_NSECTORS(rm, rm->rm_volsize + SEC_NDXMASK(rm)); - buf->f_bfree = 0; - buf->f_bavail = 0; + buf->f_bfree = rm->rm_hwnsectors - buf->f_blocks; + buf->f_bavail = buf->f_bfree; buf->f_namelen = NAME_MAX; errout_with_lock: diff --git a/fs/romfs/fs_romfs.h b/fs/romfs/fs_romfs.h index f0af14fcc5..b066d0adf2 100644 --- a/fs/romfs/fs_romfs.h +++ b/fs/romfs/fs_romfs.h @@ -26,6 +26,7 @@ ****************************************************************************/ #include +#include #include #include @@ -116,6 +117,20 @@ * Public Types ****************************************************************************/ +#ifdef CONFIG_FS_ROMFS_WRITEABLE +/* This structure represents the spare list. An instance of this + * structure is retained as file header and file data size on each mountpoint + * that is mounted with a romfs filesystem. + */ + +struct romfs_sparenode_s +{ + struct list_node node; + uint32_t start; + uint32_t end; +}; +#endif + /* 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 romfs filesystem. @@ -139,6 +154,9 @@ struct romfs_mountpt_s uint32_t rm_cachesector; /* Current sector in the rm_buffer */ FAR uint8_t *rm_xipbase; /* Base address of directly accessible media */ FAR uint8_t *rm_buffer; /* Device sector buffer, allocated if rm_xipbase==0 */ +#ifdef CONFIG_FS_ROMFS_WRITEABLE + struct list_node rm_sparelist; /* The list of spare space */ +#endif }; /* This structure represents on open file under the mountpoint. An instance @@ -194,7 +212,7 @@ int romfs_hwread(FAR struct romfs_mountpt_s *rm, FAR uint8_t *buffer, int romfs_filecacheread(FAR struct romfs_mountpt_s *rm, FAR struct romfs_file_s *rf, uint32_t sector); int romfs_hwconfigure(FAR struct romfs_mountpt_s *rm); -int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm); +int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm, FAR const void *data); int romfs_fileconfigure(FAR struct romfs_mountpt_s *rm, FAR struct romfs_file_s *rf); int romfs_checkmount(FAR struct romfs_mountpt_s *rm); @@ -212,6 +230,9 @@ int romfs_datastart(FAR struct romfs_mountpt_s *rm, #ifdef CONFIG_FS_ROMFS_CACHE_NODE void romfs_freenode(FAR struct romfs_nodeinfo_s *node); #endif +#ifdef CONFIG_FS_ROMFS_WRITEABLE +void romfs_free_sparelist(FAR struct list_node *list); +#endif #undef EXTERN #if defined(__cplusplus) diff --git a/fs/romfs/fs_romfsutil.c b/fs/romfs/fs_romfsutil.c index 84310ec04f..16dd0d1045 100644 --- a/fs/romfs/fs_romfsutil.c +++ b/fs/romfs/fs_romfsutil.c @@ -395,6 +395,127 @@ static inline int romfs_searchdir(FAR struct romfs_mountpt_s *rm, return -ENOENT; } +#ifdef CONFIG_FS_ROMFS_WRITEABLE +/**************************************************************************** + * Name: romfs_alloc_sparenode + * + * Description: + * Allocate the spare node + * + ****************************************************************************/ + +static FAR struct romfs_sparenode_s * +romfs_alloc_sparenode(uint32_t start, uint32_t end) +{ + FAR struct romfs_sparenode_s *node; + node = kmm_malloc(sizeof(struct romfs_sparenode_s)); + if (node == NULL) + { + ferr("romfs_alloc_sparenode: no memory\n"); + return NULL; + } + + node->start = start; + node->end = end; + return node; +} + +/**************************************************************************** + * Name: romfs_init_sparelist + * + * Description: + * Init the sparelist + * + ****************************************************************************/ + +static int romfs_init_sparelist(FAR struct romfs_mountpt_s *rm, bool rw) +{ + FAR struct romfs_sparenode_s *node; + + list_initialize(&rm->rm_sparelist); + if (!rw) + { + return 0; + } + + node = romfs_alloc_sparenode(0, rm->rm_hwsectorsize * + rm->rm_hwnsectors); + if (node == NULL) + { + return -ENOMEM; + } + + list_add_head(&rm->rm_sparelist, &node->node); + rm->rm_volsize = 0; + return 0; +} + +/**************************************************************************** + * Name: romfs_alloc_spareregion + * + * Description: + * Allocate the spare region + * + ****************************************************************************/ + +static int romfs_alloc_spareregion(FAR struct list_node *list, + uint32_t start, uint32_t end) +{ + FAR struct romfs_sparenode_s *node; + + list_for_every_entry(list, node, struct romfs_sparenode_s, node) + { + /* Find the node that start ~ end + * is in node->start ~ node->end + */ + + if (start == node->start && end == node->end) + { + /* Delete the node */ + + list_delete(&node->node); + kmm_free(node); + return 0; + } + else if (start == node->start) + { + /* Update the node */ + + node->start = end; + return 0; + } + else if (end == node->end) + { + /* Update the node */ + + node->end = start; + return 0; + } + else if (start > node->start && end < node->end) + { + /* Split the node */ + + FAR struct romfs_sparenode_s *new; + new = romfs_alloc_sparenode(end, node->end); + if (new == NULL) + { + return -ENOMEM; + } + + node->end = start; + list_add_after(&node->node, &new->node); + return 0; + } + } + + /* Not found */ + + ferr("No space for start %" PRIu32 ", end %" PRIu32 "\n", start, + end); + return -ENOENT; +} +#endif + /**************************************************************************** * Name: romfs_cachenode * @@ -431,6 +552,26 @@ static int romfs_cachenode(FAR struct romfs_mountpt_s *rm, nodeinfo->rn_next = next; nodeinfo->rn_namesize = nsize; strlcpy(nodeinfo->rn_name, name, nsize + 1); + +#ifdef CONFIG_FS_ROMFS_WRITEABLE + if (!list_is_empty(&rm->rm_sparelist)) + { + uint32_t totalsize = ROMFS_ALIGNUP(ROMFS_FHDR_NAME + nsize + 1); + if (offset == origoffset) + { + totalsize += size; + } + + rm->rm_volsize += totalsize; + ret = romfs_alloc_spareregion(&rm->rm_sparelist, offset, + offset + totalsize); + if (ret < 0) + { + return ret; + } + } +#endif + if (!IS_DIRECTORY(next) || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { @@ -686,6 +827,27 @@ int romfs_hwconfigure(FAR struct romfs_mountpt_s *rm) return OK; } +/**************************************************************************** + * Name: romfs_free_sparelist + * + * Description: + * Free the sparelist + * + ****************************************************************************/ +#ifdef CONFIG_FS_ROMFS_WRITEABLE +void romfs_free_sparelist(FAR struct list_node *list) +{ + FAR struct romfs_sparenode_s *node; + FAR struct romfs_sparenode_s *tmp; + + list_for_every_entry_safe(list, node, tmp, struct romfs_sparenode_s, node) + { + list_delete(&node->node); + kmm_free(node); + } +} +#endif + /**************************************************************************** * Name: romfs_fsconfigure * @@ -697,20 +859,20 @@ int romfs_hwconfigure(FAR struct romfs_mountpt_s *rm) * ****************************************************************************/ -int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm) +int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm, FAR const void *data) { FAR const char *name; - int16_t ndx; + int ret; uint32_t rootoffset; /* Then get information about the ROMFS filesystem on the devices managed * by this block driver. Read sector zero which contains the volume header. */ - ndx = romfs_devcacheread(rm, 0); - if (ndx < 0) + ret = romfs_devcacheread(rm, 0); + if (ret < 0) { - return ndx; + return ret; } /* Verify the magic number at that identifies this as a ROMFS filesystem */ @@ -722,19 +884,30 @@ int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm) /* Then extract the values we need from the header and return success */ - rm->rm_volsize = romfs_devread32(rm, ROMFS_VHDR_SIZE); + rm->rm_volsize = romfs_devread32(rm, ROMFS_VHDR_SIZE); /* The root directory entry begins right after the header */ - name = (FAR const char *)&rm->rm_buffer[ROMFS_VHDR_VOLNAME]; - rootoffset = ROMFS_ALIGNUP(ROMFS_VHDR_VOLNAME + strlen(name) + 1); -#ifdef CONFIG_FS_ROMFS_CACHE_NODE - ndx = romfs_cachenode(rm, 0, rootoffset, RFNEXT_DIRECTORY, - 0, "", &rm->rm_root); - if (ndx < 0) + name = (FAR const char *)&rm->rm_buffer[ROMFS_VHDR_VOLNAME]; + rootoffset = ROMFS_ALIGNUP(ROMFS_VHDR_VOLNAME + strlen(name) + 1); +#ifdef CONFIG_FS_ROMFS_WRITEABLE + ret = romfs_init_sparelist(rm, data && strstr(data, "rw")); + if (ret < 0) { + return ret; + } +#endif + +#ifdef CONFIG_FS_ROMFS_CACHE_NODE + ret = romfs_cachenode(rm, 0, rootoffset, RFNEXT_DIRECTORY, + 0, "", &rm->rm_root); + if (ret < 0) + { +# ifdef CONFIG_FS_ROMFS_WRITEABLE + romfs_free_sparelist(&rm->rm_sparelist); +# endif romfs_freenode(rm->rm_root); - return ndx; + return ret; } #else rm->rm_rootoffset = rootoffset; @@ -742,7 +915,7 @@ int romfs_fsconfigure(FAR struct romfs_mountpt_s *rm) /* and return success */ - rm->rm_mounted = true; + rm->rm_mounted = true; return OK; }