创建,添加sdram
This commit is contained in:
commit
90c74bc31a
2944 files changed
+1430509
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-10-10 Bernard The first version of rewrite dfs
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "dfs.h"
|
||||
#include "dfs_file.h"
|
||||
#include "dfs_private.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_mnt.h"
|
||||
|
||||
#define DBG_TAG "DFS.dentry"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define DFS_DENTRY_HASH_NR 32
|
||||
struct dentry_hash_head
|
||||
{
|
||||
rt_list_t head[DFS_DENTRY_HASH_NR];
|
||||
};
|
||||
static struct dentry_hash_head hash_head;
|
||||
|
||||
static uint32_t _dentry_hash(struct dfs_mnt *mnt, const char *path)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
if (path)
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
val = ((val << 5) + val) + *path++;
|
||||
}
|
||||
}
|
||||
return (val ^ (unsigned long) mnt) & (DFS_DENTRY_HASH_NR - 1);
|
||||
}
|
||||
|
||||
static struct dfs_dentry *_dentry_create(struct dfs_mnt *mnt, char *path, rt_bool_t is_rela_path)
|
||||
{
|
||||
struct dfs_dentry *dentry = RT_NULL;
|
||||
|
||||
if (mnt == RT_NULL || path == RT_NULL)
|
||||
{
|
||||
return dentry;
|
||||
}
|
||||
|
||||
dentry = (struct dfs_dentry *)rt_calloc(1, sizeof(struct dfs_dentry));
|
||||
if (dentry)
|
||||
{
|
||||
char *dentry_path = path;
|
||||
if (!is_rela_path)
|
||||
{
|
||||
int mntpoint_len = strlen(mnt->fullpath);
|
||||
|
||||
if (rt_strncmp(mnt->fullpath, dentry_path, mntpoint_len) == 0)
|
||||
{
|
||||
dentry_path += mntpoint_len;
|
||||
}
|
||||
}
|
||||
|
||||
dentry->pathname = strlen(dentry_path) ? rt_strdup(dentry_path) : rt_strdup(path);
|
||||
dentry->mnt = dfs_mnt_ref(mnt);
|
||||
|
||||
rt_atomic_store(&(dentry->ref_count), 1);
|
||||
dentry->flags |= DENTRY_IS_ALLOCED;
|
||||
|
||||
LOG_I("create a dentry:%p for %s", dentry, fullpath);
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
struct dfs_dentry *dfs_dentry_create(struct dfs_mnt *mnt, char *fullpath)
|
||||
{
|
||||
return _dentry_create(mnt, fullpath, RT_FALSE);
|
||||
}
|
||||
|
||||
struct dfs_dentry *dfs_dentry_create_rela(struct dfs_mnt *mnt, char *rela_path)
|
||||
{
|
||||
return _dentry_create(mnt, rela_path, RT_TRUE);;
|
||||
}
|
||||
|
||||
struct dfs_dentry * dfs_dentry_ref(struct dfs_dentry *dentry)
|
||||
{
|
||||
if (dentry)
|
||||
{
|
||||
int ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
rt_atomic_add(&(dentry->ref_count), 1);
|
||||
if (dentry->vnode)
|
||||
{
|
||||
rt_atomic_add(&(dentry->vnode->ref_count), 1);
|
||||
}
|
||||
dfs_file_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
struct dfs_dentry *dfs_dentry_unref(struct dfs_dentry *dentry)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (dentry)
|
||||
{
|
||||
ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
if (dentry->flags & DENTRY_IS_ALLOCED)
|
||||
{
|
||||
rt_atomic_sub(&(dentry->ref_count), 1);
|
||||
}
|
||||
|
||||
if (rt_atomic_load(&(dentry->ref_count)) == 0)
|
||||
{
|
||||
DLOG(msg, "dentry", "dentry", DLOG_MSG, "free dentry, ref_count=0");
|
||||
if (dentry->flags & DENTRY_IS_ADDHASH)
|
||||
{
|
||||
rt_list_remove(&dentry->hashlist);
|
||||
}
|
||||
|
||||
/* release vnode */
|
||||
if (dentry->vnode)
|
||||
{
|
||||
dfs_vnode_unref(dentry->vnode);
|
||||
}
|
||||
|
||||
/* release mnt */
|
||||
DLOG(msg, "dentry", "mnt", DLOG_MSG, "dfs_mnt_unref(dentry->mnt)");
|
||||
if (dentry->mnt)
|
||||
{
|
||||
dfs_mnt_unref(dentry->mnt);
|
||||
}
|
||||
|
||||
dfs_file_unlock();
|
||||
|
||||
LOG_I("free a dentry: %p", dentry);
|
||||
rt_free(dentry->pathname);
|
||||
rt_free(dentry);
|
||||
dentry = RT_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dentry->vnode)
|
||||
{
|
||||
rt_atomic_sub(&(dentry->vnode->ref_count), 1);
|
||||
}
|
||||
dfs_file_unlock();
|
||||
DLOG(note, "dentry", "dentry ref_count=%d", rt_atomic_load(&(dentry->ref_count)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static struct dfs_dentry *_dentry_hash_lookup(struct dfs_mnt *mnt, const char *path)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct dfs_dentry *entry = RT_NULL;
|
||||
|
||||
ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
rt_list_for_each_entry(entry, &hash_head.head[_dentry_hash(mnt, path)], hashlist)
|
||||
{
|
||||
if (entry->mnt == mnt && !strcmp(entry->pathname, path))
|
||||
{
|
||||
dfs_dentry_ref(entry);
|
||||
dfs_file_unlock();
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
dfs_file_unlock();
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
void dfs_dentry_insert(struct dfs_dentry *dentry)
|
||||
{
|
||||
dfs_file_lock();
|
||||
rt_list_insert_after(&hash_head.head[_dentry_hash(dentry->mnt, dentry->pathname)], &dentry->hashlist);
|
||||
dentry->flags |= DENTRY_IS_ADDHASH;
|
||||
dfs_file_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* lookup a dentry, return this dentry and increase refcount if exist, otherwise return NULL
|
||||
*/
|
||||
struct dfs_dentry *dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint32_t flags)
|
||||
{
|
||||
struct dfs_dentry *dentry;
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
int mntpoint_len = strlen(mnt->fullpath);
|
||||
|
||||
if (rt_strncmp(mnt->fullpath, path, mntpoint_len) == 0)
|
||||
{
|
||||
path += mntpoint_len;
|
||||
if ((*path) == '\0')
|
||||
{
|
||||
/* root */
|
||||
path = "/";
|
||||
}
|
||||
}
|
||||
dfs_file_lock();
|
||||
dentry = _dentry_hash_lookup(mnt, path);
|
||||
if (!dentry)
|
||||
{
|
||||
if (mnt->fs_ops->lookup)
|
||||
{
|
||||
DLOG(activate, "dentry");
|
||||
/* not in hash table, create it */
|
||||
DLOG(msg, "dentry", "dentry", DLOG_MSG, "dfs_dentry_create_rela(mnt=%s, path=%s)", mnt->fullpath, path);
|
||||
dentry = dfs_dentry_create_rela(mnt, (char*)path);
|
||||
if (dentry)
|
||||
{
|
||||
DLOG(msg, "dentry", mnt->fs_ops->name, DLOG_MSG, "vnode=fs_ops->lookup(dentry)");
|
||||
|
||||
if (dfs_is_mounted(mnt) == 0)
|
||||
{
|
||||
vnode = mnt->fs_ops->lookup(dentry);
|
||||
}
|
||||
|
||||
if (vnode)
|
||||
{
|
||||
DLOG(msg, mnt->fs_ops->name, "dentry", DLOG_MSG_RET, "return vnode");
|
||||
dentry->vnode = vnode; /* the refcount of created vnode is 1. no need to reference */
|
||||
dfs_file_lock();
|
||||
rt_list_insert_after(&hash_head.head[_dentry_hash(mnt, path)], &dentry->hashlist);
|
||||
dentry->flags |= DENTRY_IS_ADDHASH;
|
||||
dfs_file_unlock();
|
||||
|
||||
if (dentry->flags & (DENTRY_IS_ALLOCED | DENTRY_IS_ADDHASH)
|
||||
&& !(dentry->flags & DENTRY_IS_OPENED))
|
||||
{
|
||||
rt_err_t ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
dentry->flags |= DENTRY_IS_OPENED;
|
||||
dfs_file_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG(msg, mnt->fs_ops->name, "dentry", DLOG_MSG_RET, "no dentry");
|
||||
|
||||
DLOG(msg, "dentry", "dentry", DLOG_MSG, "dfs_dentry_unref(dentry)");
|
||||
dfs_dentry_unref(dentry);
|
||||
dentry = RT_NULL;
|
||||
}
|
||||
}
|
||||
DLOG(deactivate, "dentry");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG(note, "dentry", "found dentry");
|
||||
}
|
||||
dfs_file_unlock();
|
||||
return dentry;
|
||||
}
|
||||
|
||||
char* dfs_dentry_full_path(struct dfs_dentry* dentry)
|
||||
{
|
||||
char *path = NULL;
|
||||
|
||||
if (dentry && dentry->mnt)
|
||||
{
|
||||
int mnt_len = strlen(dentry->mnt->fullpath);
|
||||
int path_len = strlen(dentry->pathname);
|
||||
|
||||
path = (char *) rt_malloc(mnt_len + path_len + 3);
|
||||
if (path)
|
||||
{
|
||||
if (dentry->pathname[0] == '/' || dentry->mnt->fullpath[mnt_len - 1] == '/')
|
||||
{
|
||||
rt_snprintf(path, mnt_len + path_len + 2, "%s%s", dentry->mnt->fullpath,
|
||||
dentry->pathname);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_snprintf(path, mnt_len + path_len + 2, "%s/%s", dentry->mnt->fullpath,
|
||||
dentry->pathname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
char* dfs_dentry_pathname(struct dfs_dentry* dentry)
|
||||
{
|
||||
char *pathname = RT_NULL;
|
||||
char *index = RT_NULL;
|
||||
|
||||
index = strrchr(dentry->pathname, '/');
|
||||
if (index)
|
||||
{
|
||||
int length = index - dentry->pathname;
|
||||
int path_length = strlen(dentry->mnt->fullpath) + length + 3;
|
||||
|
||||
pathname = (char*) rt_malloc(path_length);
|
||||
if (pathname)
|
||||
{
|
||||
if (dentry->pathname[0] == '/')
|
||||
{
|
||||
rt_snprintf(pathname, path_length - 1, "%s%.*s", dentry->mnt->fullpath,
|
||||
length, dentry->pathname);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_snprintf(pathname, path_length - 1, "%s/%.*s", dentry->mnt->fullpath,
|
||||
length, dentry->pathname);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pathname = rt_strdup(dentry->mnt->fullpath);
|
||||
}
|
||||
|
||||
return pathname;
|
||||
}
|
||||
|
||||
uint32_t dfs_dentry_full_path_crc32(struct dfs_dentry* dentry)
|
||||
{
|
||||
uint32_t crc32 = 0xFFFFFFFF;
|
||||
char *fullpath = dfs_dentry_full_path(dentry);
|
||||
if (fullpath)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while(fullpath[i] != '\0')
|
||||
{
|
||||
for (uint8_t b = 1; b; b <<= 1)
|
||||
{
|
||||
crc32 ^= (fullpath[i] & b) ? 1 : 0;
|
||||
crc32 = (crc32 & 1) ? crc32 >> 1 ^ 0xEDB88320 : crc32 >> 1;
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
rt_free(fullpath);
|
||||
}
|
||||
return crc32;
|
||||
}
|
||||
|
||||
int dfs_dentry_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(i = 0; i < DFS_DENTRY_HASH_NR; i++)
|
||||
{
|
||||
rt_list_init(&hash_head.head[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfs_dentry_dump(int argc, char** argv)
|
||||
{
|
||||
int index = 0;
|
||||
struct dfs_dentry *entry = RT_NULL;
|
||||
|
||||
dfs_lock();
|
||||
for (index = 0; index < DFS_DENTRY_HASH_NR; index ++)
|
||||
{
|
||||
rt_list_for_each_entry(entry, &hash_head.head[index], hashlist)
|
||||
{
|
||||
printf("dentry: %s%s @ %p, ref_count = %zd\n", entry->mnt->fullpath, entry->pathname, entry, (size_t)rt_atomic_load(&entry->ref_count));
|
||||
}
|
||||
}
|
||||
dfs_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(dfs_dentry_dump, dentry_dump, dump dentry in the system);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "dfs_file.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_mnt.h"
|
||||
|
||||
#define DBG_TAG "dfs.mmap"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
#if defined(RT_USING_SMART) && defined(ARCH_MM_MMU) && defined(RT_USING_PAGECACHE)
|
||||
|
||||
#include "dfs_pcache.h"
|
||||
|
||||
#include <lwp.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <lwp_user_mm.h>
|
||||
#include <mm_aspace.h>
|
||||
#include <mm_fault.h>
|
||||
#include <mm_flag.h>
|
||||
#include <mm_page.h>
|
||||
#include <mmu.h>
|
||||
#include <page.h>
|
||||
#include <tlb.h>
|
||||
|
||||
static rt_mem_obj_t dfs_get_mem_obj(struct dfs_file *file);
|
||||
static void *dfs_mem_obj_get_file(rt_mem_obj_t mem_obj);
|
||||
|
||||
static void *_do_mmap(struct rt_lwp *lwp, void *map_vaddr, size_t map_size, size_t attr,
|
||||
mm_flag_t flags, off_t pgoffset, void *data, rt_err_t *code)
|
||||
{
|
||||
int ret = 0;
|
||||
void *vaddr = map_vaddr;
|
||||
rt_mem_obj_t mem_obj = dfs_get_mem_obj(data);
|
||||
|
||||
ret = rt_aspace_map(lwp->aspace, &vaddr, map_size,
|
||||
attr, flags, mem_obj, pgoffset);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
vaddr = RT_NULL;
|
||||
LOG_E("failed to map %lx with size %lx with errno %d", map_vaddr,
|
||||
map_size, ret);
|
||||
}
|
||||
|
||||
if (code)
|
||||
{
|
||||
*code = ret;
|
||||
}
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static void *_map_data_to_uspace(struct dfs_mmap2_args *mmap2, void *data, rt_err_t *code)
|
||||
{
|
||||
size_t offset = 0;
|
||||
void *map_vaddr = mmap2->addr;
|
||||
size_t map_size = mmap2->length;
|
||||
struct rt_lwp *lwp = mmap2->lwp;
|
||||
rt_size_t k_attr;
|
||||
rt_size_t k_flags;
|
||||
|
||||
if (map_size)
|
||||
{
|
||||
offset = (size_t)map_vaddr & ARCH_PAGE_MASK;
|
||||
map_size += (offset + ARCH_PAGE_SIZE - 1);
|
||||
map_size &= ~ARCH_PAGE_MASK;
|
||||
map_vaddr = (void *)((size_t)map_vaddr & ~ARCH_PAGE_MASK);
|
||||
|
||||
k_flags = lwp_user_mm_flag_to_kernel(mmap2->flags);
|
||||
k_attr = lwp_user_mm_attr_to_kernel(mmap2->prot);
|
||||
|
||||
map_vaddr = _do_mmap(lwp, map_vaddr, map_size, k_attr, k_flags, mmap2->pgoffset, data, code);
|
||||
}
|
||||
|
||||
return map_vaddr;
|
||||
}
|
||||
|
||||
static void hint_free(rt_mm_va_hint_t hint)
|
||||
{
|
||||
}
|
||||
|
||||
static void on_page_fault(struct rt_varea *varea, struct rt_aspace_fault_msg *msg)
|
||||
{
|
||||
void *page;
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, varea);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
varea->start, varea->size, varea->offset, varea->attr, varea->flag);
|
||||
LOG_I("fault vaddr: %p", msg->fault_vaddr);
|
||||
|
||||
if (file->dentry)
|
||||
{
|
||||
LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
}
|
||||
|
||||
page = dfs_aspace_mmap(file, varea, msg->fault_vaddr);
|
||||
if (page)
|
||||
{
|
||||
msg->response.status = MM_FAULT_STATUS_OK_MAPPED;
|
||||
msg->response.size = ARCH_PAGE_SIZE;
|
||||
msg->response.vaddr = page;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p mmap failed at vaddr %p", __func__, varea, msg->fault_vaddr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
|
||||
}
|
||||
}
|
||||
|
||||
/* do pre open bushiness like inc a ref */
|
||||
static void on_varea_open(struct rt_varea *varea)
|
||||
{
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
varea->data = RT_NULL;
|
||||
rt_atomic_add(&(file->ref_count), 1);
|
||||
}
|
||||
|
||||
/* do post close bushiness like def a ref */
|
||||
static void on_varea_close(struct rt_varea *varea)
|
||||
{
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, varea);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
varea->start, varea->size, varea->offset, varea->attr, varea->flag);
|
||||
|
||||
if (file->dentry)
|
||||
{
|
||||
LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
}
|
||||
|
||||
dfs_aspace_unmap(file, varea);
|
||||
dfs_file_lock();
|
||||
if (rt_atomic_load(&(file->ref_count)) == 1)
|
||||
{
|
||||
dfs_file_close(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_atomic_sub(&(file->ref_count), 1);
|
||||
}
|
||||
dfs_file_unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_name(rt_varea_t varea)
|
||||
{
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
return (file && file->dentry) ? file->dentry->pathname : "file-mapper";
|
||||
}
|
||||
|
||||
void page_read(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
|
||||
{
|
||||
rt_ubase_t ret;
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, varea);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
varea->start, varea->size, varea->offset, varea->attr, varea->flag);
|
||||
|
||||
ret = dfs_aspace_mmap_read(file, varea, msg);
|
||||
if (ret > 0)
|
||||
{
|
||||
msg->response.status = MM_FAULT_STATUS_OK;
|
||||
if (ret < ARCH_PAGE_SIZE)
|
||||
{
|
||||
memset((char *)msg->buffer_vaddr + ret, 0, ARCH_PAGE_SIZE - ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
|
||||
}
|
||||
}
|
||||
|
||||
void page_write(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
|
||||
{
|
||||
rt_ubase_t ret;
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, varea);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
varea->start, varea->size, varea->offset, varea->attr, varea->flag);
|
||||
|
||||
ret = dfs_aspace_mmap_write(file, varea, msg);
|
||||
if (ret > 0)
|
||||
{
|
||||
msg->response.status = MM_FAULT_STATUS_OK;
|
||||
if (ret < ARCH_PAGE_SIZE)
|
||||
{
|
||||
memset((char *)msg->buffer_vaddr + ret, 0, ARCH_PAGE_SIZE - ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t unmap_pages(rt_varea_t varea, void *rm_start, void *rm_end)
|
||||
{
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p start: %p end: %p", __func__, varea, rm_start, rm_end);
|
||||
|
||||
RT_ASSERT(!((rt_ubase_t)rm_start & ARCH_PAGE_MASK));
|
||||
RT_ASSERT(!((rt_ubase_t)rm_end & ARCH_PAGE_MASK));
|
||||
while (rm_start != rm_end)
|
||||
{
|
||||
dfs_aspace_page_unmap(file, varea, rm_start);
|
||||
rm_start += ARCH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
|
||||
}
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t on_varea_shrink(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
|
||||
{
|
||||
char *varea_start = varea->start;
|
||||
void *rm_start;
|
||||
void *rm_end;
|
||||
|
||||
LOG_I("%s varea: %p", __func__, varea);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
varea->start, varea->size, varea->offset, varea->attr, varea->flag);
|
||||
LOG_I("new_vaddr: %p size: %p", new_vaddr, size);
|
||||
|
||||
if (varea_start == (char *)new_vaddr)
|
||||
{
|
||||
rm_start = varea_start + size;
|
||||
rm_end = varea_start + varea->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
rm_start = varea_start;
|
||||
rm_end = new_vaddr;
|
||||
}
|
||||
|
||||
return unmap_pages(varea, rm_start, rm_end);
|
||||
}
|
||||
|
||||
rt_err_t on_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, varea);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
varea->start, varea->size, varea->offset, varea->attr, varea->flag);
|
||||
LOG_I("new_vaddr: %p size: %p", new_vaddr, size);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t on_varea_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
|
||||
{
|
||||
rt_err_t rc;
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(existed->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, existed);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
existed->start, existed->size, existed->offset, existed->attr, existed->flag);
|
||||
LOG_I("unmap_start: %p unmap_len: %p", unmap_start, unmap_len);
|
||||
|
||||
if (file->dentry)
|
||||
{
|
||||
LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
}
|
||||
|
||||
rc = unmap_pages(existed, unmap_start, (char *)unmap_start + unmap_len);
|
||||
if (!rc)
|
||||
{
|
||||
rc = unmap_pages(existed, subset->start, (char *)subset->start + subset->size);
|
||||
if (!rc)
|
||||
on_varea_open(subset);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, existed, existed->start);
|
||||
}
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_err_t on_varea_merge(struct rt_varea *merge_to, struct rt_varea *merge_from)
|
||||
{
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(merge_from->mem_obj);
|
||||
|
||||
if (file)
|
||||
{
|
||||
LOG_I("%s varea: %p", __func__, merge_from);
|
||||
LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
|
||||
merge_from->start, merge_from->size, merge_from->offset, merge_from->attr, merge_from->flag);
|
||||
|
||||
if (file->dentry)
|
||||
{
|
||||
LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
}
|
||||
|
||||
dfs_aspace_unmap(file, merge_from);
|
||||
on_varea_close(merge_from);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s varea %p not a file, vaddr %p", __func__, merge_from, merge_from->start);
|
||||
}
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
void *on_varea_mremap(struct rt_varea *varea, rt_size_t new_size, int flags, void *new_address)
|
||||
{
|
||||
void *vaddr = RT_NULL;
|
||||
struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
|
||||
|
||||
#ifndef MREMAP_MAYMOVE
|
||||
#define MREMAP_MAYMOVE 1
|
||||
#endif
|
||||
|
||||
if (file && flags == MREMAP_MAYMOVE)
|
||||
{
|
||||
int ret;
|
||||
rt_mem_obj_t mem_obj = dfs_get_mem_obj(file);
|
||||
|
||||
vaddr = new_address ? new_address : varea->start;
|
||||
new_size = (new_size + ARCH_PAGE_SIZE - 1);
|
||||
new_size &= ~ARCH_PAGE_MASK;
|
||||
ret = rt_aspace_map(varea->aspace, &vaddr, new_size, varea->attr, varea->flag, mem_obj, varea->offset);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("failed to map %lx with size %lx with errno %d", vaddr, new_size, ret);
|
||||
vaddr = RT_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("old: %p size: %p new: %p size: %p", varea->start, varea->size, vaddr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static struct rt_mem_obj _mem_obj =
|
||||
{
|
||||
.hint_free = hint_free,
|
||||
.on_page_fault = on_page_fault,
|
||||
.on_varea_open = on_varea_open,
|
||||
.on_varea_close = on_varea_close,
|
||||
.get_name = get_name,
|
||||
|
||||
.page_read = page_read,
|
||||
.page_write = page_write,
|
||||
|
||||
.on_varea_shrink = on_varea_shrink,
|
||||
.on_varea_expand = on_varea_expand,
|
||||
.on_varea_split = on_varea_split,
|
||||
.on_varea_merge = on_varea_merge,
|
||||
|
||||
.on_varea_mremap = on_varea_mremap,
|
||||
};
|
||||
|
||||
struct dfs_mem_obj {
|
||||
struct rt_mem_obj mem_obj;
|
||||
void *file;
|
||||
};
|
||||
|
||||
static rt_mem_obj_t dfs_get_mem_obj(struct dfs_file *file)
|
||||
{
|
||||
rt_mem_obj_t mobj = file->mmap_context;
|
||||
if (!mobj)
|
||||
{
|
||||
struct dfs_mem_obj *dfs_mobj;
|
||||
dfs_file_lock();
|
||||
dfs_mobj = rt_malloc(sizeof(*dfs_mobj));
|
||||
if (dfs_mobj)
|
||||
{
|
||||
dfs_mobj->file = file;
|
||||
mobj = &dfs_mobj->mem_obj;
|
||||
memcpy(mobj, &_mem_obj, sizeof(*mobj));
|
||||
file->mmap_context = mobj;
|
||||
}
|
||||
dfs_file_unlock();
|
||||
}
|
||||
return mobj;
|
||||
}
|
||||
|
||||
static void *dfs_mem_obj_get_file(rt_mem_obj_t mem_obj)
|
||||
{
|
||||
struct dfs_mem_obj *dfs_mobj;
|
||||
dfs_mobj = rt_container_of(mem_obj, struct dfs_mem_obj, mem_obj);
|
||||
return dfs_mobj->file;
|
||||
}
|
||||
|
||||
int dfs_file_mmap(struct dfs_file *file, struct dfs_mmap2_args *mmap2)
|
||||
{
|
||||
rt_err_t ret = -EINVAL;
|
||||
void *map_vaddr;
|
||||
|
||||
LOG_I("mmap2 args addr: %p length: 0x%x prot: %d flags: 0x%x pgoffset: 0x%x",
|
||||
mmap2->addr, mmap2->length, mmap2->prot, mmap2->flags, mmap2->pgoffset);
|
||||
if (file && file->vnode)
|
||||
{
|
||||
if (file->vnode->aspace)
|
||||
{
|
||||
/* create a va area in user space (lwp) */
|
||||
map_vaddr = _map_data_to_uspace(mmap2, file, &ret);
|
||||
if (map_vaddr)
|
||||
{
|
||||
mmap2->ret = map_vaddr;
|
||||
LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("File mapping is not supported, file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int dfs_file_mmap(struct dfs_file *file, struct dfs_mmap2_args *mmap2)
|
||||
{
|
||||
LOG_E("File mapping support is not enabled, file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
|
||||
LOG_E("mmap2 args addr: %p length: 0x%x prot: %d flags: 0x%x pgoffset: 0x%x",
|
||||
mmap2->addr, mmap2->length, mmap2->prot, mmap2->flags, mmap2->pgoffset);
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2005-02-22 Bernard The first version.
|
||||
* 2010-06-30 Bernard Optimize for RT-Thread RTOS
|
||||
* 2011-03-12 Bernard fix the filesystem lookup issue.
|
||||
* 2017-11-30 Bernard fix the filesystem_operation_table issue.
|
||||
* 2017-12-05 Bernard fix the fs type search issue in mkfs.
|
||||
* 2023-05-05 Bernard change to dfs v2.0
|
||||
*/
|
||||
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include "dfs_private.h"
|
||||
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
#include "dfs_pcache.h"
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "DFS.fs"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct dfs_filesystem_type *file_systems = NULL;
|
||||
extern rt_list_t _mnt_list;
|
||||
|
||||
/**
|
||||
* @addtogroup FsApi
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
static struct dfs_filesystem_type **_find_filesystem(const char *name)
|
||||
{
|
||||
struct dfs_filesystem_type **type;
|
||||
for (type = &file_systems; *type; type = &(*type)->next)
|
||||
{
|
||||
if (strcmp((*type)->fs_ops->name, name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
struct dfs_filesystem_type *dfs_filesystems(void)
|
||||
{
|
||||
return file_systems;
|
||||
}
|
||||
|
||||
int dfs_register(struct dfs_filesystem_type *fs)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dfs_filesystem_type **type = _find_filesystem(fs->fs_ops->name);
|
||||
|
||||
LOG_D("register %s file system.", fs->fs_ops->name);
|
||||
|
||||
if (*type)
|
||||
{
|
||||
ret = -EBUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
*type = fs;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_unregister(struct dfs_filesystem_type *fs)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dfs_filesystem_type **type;
|
||||
|
||||
if (fs)
|
||||
{
|
||||
LOG_D("unregister %s file system.", fs->fs_ops->name);
|
||||
|
||||
for (type = &file_systems; *type; type = &(*type)->next)
|
||||
{
|
||||
if (strcmp((*type)->fs_ops->name, fs->fs_ops->name) == 0)
|
||||
{
|
||||
*type = (*type)->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*type) ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* parent(mount path)
|
||||
* mnt_parent <- - - - - - - +
|
||||
* | |
|
||||
* |- mnt_child <- - - - - -+ (1 refcount)
|
||||
* | |
|
||||
* |- parent - - + (1 refcount)
|
||||
*/
|
||||
int dfs_mount(const char *device_name,
|
||||
const char *path,
|
||||
const char *filesystemtype,
|
||||
unsigned long rwflag,
|
||||
const void *data)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
char *fullpath = RT_NULL;
|
||||
rt_device_t dev_id = RT_NULL;
|
||||
struct dfs_mnt *mnt_parent = RT_NULL, *mnt_child = RT_NULL;
|
||||
struct dfs_dentry *mntpoint_dentry = RT_NULL;
|
||||
struct dfs_filesystem_type *type = *_find_filesystem(filesystemtype);
|
||||
|
||||
if (type)
|
||||
{
|
||||
fullpath = dfs_normalize_path(RT_NULL, path);
|
||||
if (!fullpath)
|
||||
{
|
||||
rt_set_errno(EPERM);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(ENOENT);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (fullpath)
|
||||
{
|
||||
DLOG(note, "mnt", "mount %s(%s) on path: %s", device_name, filesystemtype, fullpath);
|
||||
|
||||
/* open specific device */
|
||||
if (device_name) dev_id = rt_device_find(device_name);
|
||||
|
||||
if (!(type->fs_ops->flags & FS_NEED_DEVICE) ||
|
||||
((type->fs_ops->flags & FS_NEED_DEVICE) && dev_id))
|
||||
{
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_lookup(%s)", fullpath);
|
||||
mnt_parent = dfs_mnt_lookup(fullpath);
|
||||
if ((!mnt_parent && (strcmp(fullpath, "/") == 0 || strcmp(fullpath, "/dev") == 0))
|
||||
|| (mnt_parent && strcmp(fullpath, "/") == 0 && strcmp(mnt_parent->fullpath, fullpath) != 0))
|
||||
{
|
||||
LOG_D("no mnt found @ mount point %s, should be root.", fullpath);
|
||||
DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "no mnt");
|
||||
|
||||
/* it's the root file system */
|
||||
/* the mount point dentry is the same as root dentry. */
|
||||
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_create(path)");
|
||||
mnt_parent = dfs_mnt_create(fullpath); /* mnt->ref_count should be 1. */
|
||||
if (mnt_parent)
|
||||
{
|
||||
DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "return mnt, ref_count=1");
|
||||
|
||||
mnt_parent->fs_ops = type->fs_ops;
|
||||
mnt_parent->dev_id = dev_id;
|
||||
if (mnt_parent->fs_ops->mount)
|
||||
{
|
||||
DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "fs_ops->mount(mnt_parent, rwflag, data)");
|
||||
ret = mnt_parent->fs_ops->mount(mnt_parent, rwflag, data);
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
DLOG(msg, type->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK, ret root_dentry");
|
||||
|
||||
mnt_child = mnt_parent;
|
||||
mnt_child->flags |= MNT_IS_MOUNTED;
|
||||
|
||||
DLOG(note_right, "mnt", "mount sucessfully");
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(, mnt_child)");
|
||||
dfs_mnt_insert(RT_NULL, mnt_child);
|
||||
|
||||
/* unref it, because the ref_count = 1 when create */
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_parent)");
|
||||
dfs_mnt_unref(mnt_parent);
|
||||
|
||||
/*
|
||||
* About root mnt:
|
||||
* There are two ref_count:
|
||||
* 1. the gobal root reference.
|
||||
* 1. the mnt->parent reference.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent)");
|
||||
dfs_mnt_destroy(mnt_parent);
|
||||
mnt_parent = RT_NULL;
|
||||
rt_set_errno(EPERM);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_W("no mount method on file system type: %s", type->fs_ops->name);
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent), no mount method");
|
||||
dfs_mnt_destroy(mnt_parent);
|
||||
mnt_parent = RT_NULL;
|
||||
rt_set_errno(EIO);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("create a mnt point failed.");
|
||||
rt_set_errno(ENOMEM);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else if (mnt_parent && (strcmp(mnt_parent->fullpath, fullpath) != 0))
|
||||
{
|
||||
DLOG(msg, "dfs", "dentry", DLOG_MSG, "mntpoint_dentry = dfs_dentry_lookup(mnt_parent, %s, 0)", fullpath);
|
||||
mntpoint_dentry = dfs_dentry_lookup(mnt_parent, fullpath, 0);
|
||||
if (mntpoint_dentry)
|
||||
{
|
||||
DLOG(msg, "dentry", "dfs", DLOG_MSG_RET, "dentry exist");
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_child = dfs_mnt_create(path)");
|
||||
mnt_child = dfs_mnt_create(fullpath);
|
||||
if (mnt_child)
|
||||
{
|
||||
LOG_D("create mnt point %p", mnt_child);
|
||||
|
||||
mnt_child->fs_ops = type->fs_ops;
|
||||
mnt_child->dev_id = dev_id;
|
||||
|
||||
if (mnt_child->fs_ops->mount)
|
||||
{
|
||||
DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "root_dentry = fs_ops->mount(mnt_child, rwflag, data)");
|
||||
ret = mnt_child->fs_ops->mount(mnt_child, rwflag, data);
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
mnt_child->flags |= MNT_IS_MOUNTED;
|
||||
|
||||
LOG_D("mount %s sucessfully", fullpath);
|
||||
DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK");
|
||||
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(mnt_parent, mnt_child)");
|
||||
dfs_mnt_insert(mnt_parent, mnt_child);
|
||||
|
||||
/* unref it, because the ref_count = 1 when create */
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_child)");
|
||||
dfs_mnt_unref(mnt_child);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
|
||||
DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount failed");
|
||||
dfs_mnt_destroy(mnt_child);
|
||||
rt_set_errno(EPERM);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_W("no mount method on file system type: %s", type->fs_ops->name);
|
||||
dfs_mnt_destroy(mnt_child);
|
||||
rt_set_errno(EIO);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("create a mnt point failed.");
|
||||
rt_set_errno(ENOMEM);
|
||||
ret = -1;
|
||||
}
|
||||
dfs_dentry_unref(mntpoint_dentry);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_W("no mount point (%s) in file system: %s", fullpath, mnt_parent->fullpath);
|
||||
rt_set_errno(ENOTDIR);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("mount point (%s) already mounted!", fullpath);
|
||||
rt_set_errno(EEXIST);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("No device found for this file system.");
|
||||
rt_set_errno(ENODEV);
|
||||
ret = -1;
|
||||
}
|
||||
rt_free(fullpath);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_umount(const char *specialfile, int flags)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
char *fullpath = RT_NULL;
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
fullpath = dfs_normalize_path(NULL, specialfile);
|
||||
if (fullpath)
|
||||
{
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
if (strcmp(mnt->fullpath, fullpath) == 0)
|
||||
{
|
||||
/* is the mount point */
|
||||
rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||
|
||||
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
|
||||
{
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
dfs_pcache_unmount(mnt);
|
||||
#endif
|
||||
/* destroy this mount point */
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt)");
|
||||
ret = dfs_mnt_destroy(mnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("the file system is busy!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("the path:%s is not a mountpoint!", fullpath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("no filesystem found.");
|
||||
}
|
||||
rt_free(fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(-ENOTDIR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* for compatibility */
|
||||
int dfs_unmount(const char *specialfile)
|
||||
{
|
||||
return dfs_umount(specialfile, 0);
|
||||
}
|
||||
|
||||
int dfs_is_mounted(struct dfs_mnt *mnt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mnt && !(mnt->flags & MNT_IS_MOUNTED))
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_mkfs(const char *fs_name, const char *device_name)
|
||||
{
|
||||
rt_device_t dev_id = NULL;
|
||||
struct dfs_filesystem_type *type;
|
||||
int ret = -RT_ERROR;
|
||||
|
||||
type = *_find_filesystem(fs_name);
|
||||
if (!type)
|
||||
{
|
||||
rt_kprintf("no file system: %s found!\n", fs_name);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type->fs_ops->flags & FS_NEED_DEVICE)
|
||||
{
|
||||
/* check device name, and it should not be NULL */
|
||||
if (device_name != NULL)
|
||||
dev_id = rt_device_find(device_name);
|
||||
|
||||
if (dev_id == NULL)
|
||||
{
|
||||
rt_set_errno(-ENODEV);
|
||||
rt_kprintf("Device (%s) was not found", device_name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dev_id = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (type->fs_ops->mkfs)
|
||||
{
|
||||
ret = type->fs_ops->mkfs(dev_id, type->fs_ops->name);
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
mnt = dfs_mnt_dev_lookup(dev_id);
|
||||
if (mnt)
|
||||
{
|
||||
dfs_pcache_unmount(mnt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_statfs(const char *path, struct statfs *buffer)
|
||||
{
|
||||
struct dfs_mnt *mnt;
|
||||
char *fullpath;
|
||||
int ret = -RT_ERROR;
|
||||
|
||||
fullpath = dfs_normalize_path(NULL, path);
|
||||
if (!fullpath)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
DLOG(msg, "dfs_file", "mnt", DLOG_MSG, "dfs_mnt_lookup(%s)", fullpath);
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
if (mnt->fs_ops->statfs)
|
||||
{
|
||||
if (dfs_is_mounted(mnt) == 0)
|
||||
{
|
||||
ret = mnt->fs_ops->statfs(mnt, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will return the mounted path for specified device.
|
||||
*
|
||||
* @param device the device object which is mounted.
|
||||
*
|
||||
* @return the mounted path or NULL if none device mounted.
|
||||
*/
|
||||
const char *dfs_filesystem_get_mounted_path(struct rt_device *device)
|
||||
{
|
||||
const char *path = NULL;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will fetch the partition table on specified buffer.
|
||||
*
|
||||
* @param part the returned partition structure.
|
||||
* @param buf the buffer contains partition table.
|
||||
* @param pindex the index of partition table to fetch.
|
||||
*
|
||||
* @return RT_EOK on successful or -RT_ERROR on failed.
|
||||
*/
|
||||
int dfs_filesystem_get_partition(struct dfs_partition *part,
|
||||
uint8_t *buf,
|
||||
uint32_t pindex)
|
||||
{
|
||||
#define DPT_ADDRESS 0x1be /* device partition offset in Boot Sector */
|
||||
#define DPT_ITEM_SIZE 16 /* partition item size */
|
||||
|
||||
uint8_t *dpt;
|
||||
uint8_t type;
|
||||
|
||||
RT_ASSERT(part != NULL);
|
||||
RT_ASSERT(buf != NULL);
|
||||
|
||||
dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;
|
||||
|
||||
/* check if it is a valid partition table */
|
||||
if ((*dpt != 0x80) && (*dpt != 0x00))
|
||||
return -EIO;
|
||||
|
||||
/* get partition type */
|
||||
type = *(dpt + 4);
|
||||
if (type == 0)
|
||||
return -EIO;
|
||||
|
||||
/* set partition information
|
||||
* size is the number of 512-Byte */
|
||||
part->type = type;
|
||||
part->offset = *(dpt + 8) | *(dpt + 9) << 8 | *(dpt + 10) << 16 | *(dpt + 11) << 24;
|
||||
part->size = *(dpt + 12) | *(dpt + 13) << 8 | *(dpt + 14) << 16 | *(dpt + 15) << 24;
|
||||
|
||||
rt_kprintf("found part[%d], begin: %ld, size: ",
|
||||
pindex, part->offset * 512);
|
||||
if ((part->size >> 11) == 0)
|
||||
rt_kprintf("%ld%s", part->size >> 1, "KB\n"); /* KB */
|
||||
else
|
||||
{
|
||||
unsigned int part_size;
|
||||
part_size = part->size >> 11; /* MB */
|
||||
if ((part_size >> 10) == 0)
|
||||
rt_kprintf("%d.%ld%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
|
||||
else
|
||||
rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* @} */
|
||||
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-05-05 Bernard Implement mnt in dfs v2.0
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "dfs.h"
|
||||
#include "dfs_mnt.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_private.h"
|
||||
|
||||
#define DBG_TAG "DFS.mnt"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct dfs_mnt *_root_mnt = RT_NULL;
|
||||
|
||||
/*
|
||||
* mnt tree structure
|
||||
*
|
||||
* mnt_root <----------------------------------------+
|
||||
* | (child) +----------+ |
|
||||
* v (sibling) v | |
|
||||
* mnt_child0 -> mnt_child1 | |
|
||||
* | (child) | |
|
||||
* v / (parent) | (root)
|
||||
* mnt_child10 ---/
|
||||
*
|
||||
*/
|
||||
|
||||
struct dfs_mnt *dfs_mnt_create(const char *path)
|
||||
{
|
||||
struct dfs_mnt *mnt = rt_calloc(1, sizeof(struct dfs_mnt));
|
||||
if (mnt)
|
||||
{
|
||||
LOG_I("create mnt at %s", path);
|
||||
|
||||
mnt->fullpath = rt_strdup(path);
|
||||
rt_list_init(&mnt->sibling);
|
||||
rt_list_init(&mnt->child);
|
||||
mnt->flags |= MNT_IS_ALLOCED;
|
||||
rt_atomic_store(&(mnt->ref_count), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(-ENOMEM);
|
||||
}
|
||||
|
||||
return mnt;
|
||||
}
|
||||
|
||||
int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child)
|
||||
{
|
||||
if (child)
|
||||
{
|
||||
if (mnt == RT_NULL)
|
||||
{
|
||||
/* insert into root */
|
||||
mnt = dfs_mnt_lookup(child->fullpath);
|
||||
if (mnt == RT_NULL || (strcmp(child->fullpath, "/") == 0))
|
||||
{
|
||||
/* it's root mnt */
|
||||
mnt = child;
|
||||
mnt->flags |= MNT_IS_LOCKED;
|
||||
|
||||
/* ref to gobal root */
|
||||
if (_root_mnt)
|
||||
{
|
||||
child = _root_mnt;
|
||||
rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
|
||||
rt_atomic_sub(&(_root_mnt->ref_count), 1);
|
||||
|
||||
_root_mnt = dfs_mnt_ref(mnt);
|
||||
mnt->parent = dfs_mnt_ref(mnt);
|
||||
mnt->flags |= MNT_IS_ADDLIST;
|
||||
|
||||
mkdir("/dev", 0777);
|
||||
}
|
||||
else
|
||||
{
|
||||
_root_mnt = dfs_mnt_ref(mnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
child->flags |= MNT_IS_ADDLIST;
|
||||
if (child != mnt)
|
||||
{
|
||||
/* not the root, insert into the child list */
|
||||
rt_list_insert_before(&mnt->child, &child->sibling);
|
||||
/* child ref self */
|
||||
dfs_mnt_ref(child);
|
||||
}
|
||||
/* parent ref parent */
|
||||
child->parent = dfs_mnt_ref(mnt);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* remove mnt from mnt_tree */
|
||||
int dfs_mnt_remove(struct dfs_mnt* mnt)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
|
||||
if (rt_list_isempty(&mnt->child))
|
||||
{
|
||||
rt_list_remove(&mnt->sibling);
|
||||
if (mnt->parent)
|
||||
{
|
||||
/* parent unref parent */
|
||||
rt_atomic_sub(&(mnt->parent->ref_count), 1);
|
||||
}
|
||||
|
||||
ret = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_W("remove a mnt point:%s with child.", mnt->fullpath);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dfs_mnt *_dfs_mnt_dev_lookup(struct dfs_mnt *mnt, rt_device_t dev_id)
|
||||
{
|
||||
struct dfs_mnt *ret = RT_NULL, *iter = RT_NULL;
|
||||
|
||||
rt_list_for_each_entry(iter, &mnt->child, sibling)
|
||||
{
|
||||
if (iter->dev_id == dev_id)
|
||||
{
|
||||
ret = iter;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = _dfs_mnt_dev_lookup(iter, dev_id);
|
||||
if (ret)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dfs_mnt *dfs_mnt_dev_lookup(rt_device_t dev_id)
|
||||
{
|
||||
struct dfs_mnt *mnt = _root_mnt;
|
||||
struct dfs_mnt *ret = RT_NULL;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
dfs_lock();
|
||||
|
||||
if (mnt->dev_id == dev_id)
|
||||
{
|
||||
dfs_unlock();
|
||||
return mnt;
|
||||
}
|
||||
|
||||
ret = _dfs_mnt_dev_lookup(mnt, dev_id);
|
||||
|
||||
dfs_unlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will return the file system mounted on specified path.
|
||||
*
|
||||
* @param path the specified path string.
|
||||
*
|
||||
* @return the found file system or NULL if no file system mounted on
|
||||
* specified path
|
||||
*/
|
||||
struct dfs_mnt *dfs_mnt_lookup(const char *fullpath)
|
||||
{
|
||||
struct dfs_mnt *mnt = _root_mnt;
|
||||
struct dfs_mnt *iter = RT_NULL;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
int mnt_len = rt_strlen(mnt->fullpath);
|
||||
|
||||
dfs_lock();
|
||||
if ((strncmp(mnt->fullpath, fullpath, mnt_len) == 0) &&
|
||||
(mnt_len == 1 || (fullpath[mnt_len] == '\0') || (fullpath[mnt_len] == '/')))
|
||||
{
|
||||
while (!rt_list_isempty(&mnt->child))
|
||||
{
|
||||
rt_list_for_each_entry(iter, &mnt->child, sibling)
|
||||
{
|
||||
mnt_len = rt_strlen(iter->fullpath);
|
||||
if ((strncmp(iter->fullpath, fullpath, mnt_len) == 0) &&
|
||||
((fullpath[mnt_len] == '\0') || (fullpath[mnt_len] == '/')))
|
||||
{
|
||||
mnt = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mnt != iter) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mnt = RT_NULL;
|
||||
}
|
||||
dfs_unlock();
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
LOG_D("mnt_lookup: %s path @ mount point %p", fullpath, mnt);
|
||||
DLOG(note, "mnt", "found mnt(%s)", mnt->fs_ops->name);
|
||||
}
|
||||
}
|
||||
|
||||
return mnt;
|
||||
}
|
||||
|
||||
struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt)
|
||||
{
|
||||
if (mnt)
|
||||
{
|
||||
rt_atomic_add(&(mnt->ref_count), 1);
|
||||
DLOG(note, "mnt", "mnt(%s),ref_count=%d", mnt->fs_ops->name, rt_atomic_load(&(mnt->ref_count)));
|
||||
}
|
||||
|
||||
return mnt;
|
||||
}
|
||||
|
||||
int dfs_mnt_unref(struct dfs_mnt* mnt)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
rt_atomic_sub(&(mnt->ref_count), 1);
|
||||
|
||||
if (rt_atomic_load(&(mnt->ref_count)) == 0)
|
||||
{
|
||||
dfs_lock();
|
||||
|
||||
if (mnt->flags & MNT_IS_UMOUNT)
|
||||
{
|
||||
mnt->fs_ops->umount(mnt);
|
||||
}
|
||||
|
||||
/* free full path */
|
||||
rt_free(mnt->fullpath);
|
||||
mnt->fullpath = RT_NULL;
|
||||
|
||||
/* destroy self and the ref_count should be 0 */
|
||||
DLOG(msg, "mnt", "mnt", DLOG_MSG, "free mnt(%s)", mnt->fs_ops->name);
|
||||
rt_free(mnt);
|
||||
|
||||
dfs_unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG(note, "mnt", "mnt(%s),ref_count=%d", mnt->fs_ops->name, rt_atomic_load(&(mnt->ref_count)));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_mnt_destroy(struct dfs_mnt* mnt)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
if (mnt->flags & MNT_IS_MOUNTED)
|
||||
{
|
||||
mnt->flags &= ~MNT_IS_MOUNTED;
|
||||
mnt->flags |= MNT_IS_UMOUNT;
|
||||
/* remote it from mnt list */
|
||||
if (mnt->flags & MNT_IS_ADDLIST)
|
||||
{
|
||||
dfs_mnt_remove(mnt);
|
||||
}
|
||||
}
|
||||
|
||||
dfs_mnt_unref(mnt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dfs_mnt* _dfs_mnt_foreach(struct dfs_mnt *mnt, struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter)
|
||||
{
|
||||
struct dfs_mnt *iter, *ret = NULL;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
ret = func(mnt, parameter);
|
||||
if (ret == RT_NULL)
|
||||
{
|
||||
if (!rt_list_isempty(&mnt->child))
|
||||
{
|
||||
/* for each in mount point list */
|
||||
rt_list_for_each_entry(iter, &mnt->child, sibling)
|
||||
{
|
||||
ret = _dfs_mnt_foreach(iter, func, parameter);
|
||||
if (ret != RT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = RT_NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dfs_mnt* _mnt_cmp_devid(struct dfs_mnt *mnt, void *device)
|
||||
{
|
||||
struct dfs_mnt *ret = RT_NULL;
|
||||
struct rt_device *dev = (struct rt_device*)device;
|
||||
|
||||
if (dev && mnt)
|
||||
{
|
||||
if (mnt->dev_id == dev)
|
||||
{
|
||||
ret = mnt;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will return the mounted path for specified device.
|
||||
*
|
||||
* @param device the device object which is mounted.
|
||||
*
|
||||
* @return the mounted path or NULL if none device mounted.
|
||||
*/
|
||||
const char *dfs_mnt_get_mounted_path(struct rt_device *device)
|
||||
{
|
||||
const char* path = RT_NULL;
|
||||
|
||||
if (_root_mnt)
|
||||
{
|
||||
struct dfs_mnt* mnt;
|
||||
|
||||
dfs_lock();
|
||||
mnt = _dfs_mnt_foreach(_root_mnt, _mnt_cmp_devid, device);
|
||||
dfs_unlock();
|
||||
|
||||
if (mnt) path = mnt->fullpath;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static struct dfs_mnt* _mnt_dump(struct dfs_mnt *mnt, void *parameter)
|
||||
{
|
||||
if (mnt)
|
||||
{
|
||||
if (mnt->dev_id)
|
||||
{
|
||||
rt_kprintf("%-10s %-6s %-10s %d\n",
|
||||
mnt->fs_ops->name, mnt->dev_id->parent.name, mnt->fullpath, rt_atomic_load(&(mnt->ref_count)));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-10s (NULL) %-10s %d\n",
|
||||
mnt->fs_ops->name, mnt->fullpath, rt_atomic_load(&(mnt->ref_count)));
|
||||
}
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static struct dfs_mnt* _mnt_cmp_path(struct dfs_mnt* mnt, void *parameter)
|
||||
{
|
||||
const char* fullpath = (const char*)parameter;
|
||||
struct dfs_mnt *ret = RT_NULL;
|
||||
|
||||
if (strncmp(mnt->fullpath, fullpath, rt_strlen(fullpath)) == 0)
|
||||
{
|
||||
ret = mnt;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath)
|
||||
{
|
||||
int ret = RT_FALSE;
|
||||
|
||||
if (mnt && fullpath)
|
||||
{
|
||||
struct dfs_mnt *m = RT_NULL;
|
||||
|
||||
dfs_lock();
|
||||
m = _dfs_mnt_foreach(mnt, _mnt_cmp_path, (void*)fullpath);
|
||||
dfs_unlock();
|
||||
|
||||
if (m)
|
||||
{
|
||||
ret = RT_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_mnt_list(struct dfs_mnt *mnt)
|
||||
{
|
||||
if (!mnt) mnt = _root_mnt;
|
||||
|
||||
/* lock file system */
|
||||
dfs_lock();
|
||||
_dfs_mnt_foreach(mnt, _mnt_dump, RT_NULL);
|
||||
/* unlock file system */
|
||||
dfs_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter)
|
||||
{
|
||||
/* lock file system */
|
||||
dfs_lock();
|
||||
_dfs_mnt_foreach(_root_mnt, func, parameter);
|
||||
/* unlock file system */
|
||||
dfs_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef DFS_PRIVATE_H__
|
||||
#define DFS_PRIVATE_H__
|
||||
|
||||
#include <dfs.h>
|
||||
|
||||
#define NO_WORKING_DIR "system does not support working directory\n"
|
||||
|
||||
extern char working_directory[];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <dfs_seq_file.h>
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#define DBG_TAG "DFS.seq"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
static void dfs_seq_overflow(struct dfs_seq_file *seq)
|
||||
{
|
||||
seq->count = seq->size;
|
||||
}
|
||||
|
||||
static void *dfs_seq_alloc(unsigned long size)
|
||||
{
|
||||
return rt_calloc(1, size);
|
||||
}
|
||||
|
||||
int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops)
|
||||
{
|
||||
struct dfs_seq_file *seq;
|
||||
|
||||
if (!ops)
|
||||
{
|
||||
LOG_E("dfs_seq_open: ops = null, pathname: %s\n", file->dentry->pathname);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (file->data)
|
||||
{
|
||||
LOG_W("dfs_seq_open: file->data != null\n");
|
||||
}
|
||||
|
||||
seq = rt_calloc(1, sizeof(struct dfs_seq_file));
|
||||
if (!seq)
|
||||
return -ENOMEM;
|
||||
|
||||
file->data = seq;
|
||||
|
||||
rt_mutex_init(&seq->lock, "dfs_seq", RT_IPC_FLAG_PRIO);
|
||||
|
||||
seq->ops = ops;
|
||||
seq->file = file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_seq_traverse(struct dfs_seq_file *seq, off_t offset)
|
||||
{
|
||||
off_t pos = 0;
|
||||
int error = 0;
|
||||
void *p;
|
||||
|
||||
seq->index = 0;
|
||||
seq->count = seq->from = 0;
|
||||
if (!offset)
|
||||
return 0;
|
||||
|
||||
if (!seq->buf)
|
||||
{
|
||||
seq->buf = dfs_seq_alloc(seq->size = PAGE_SIZE);
|
||||
if (!seq->buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
p = seq->ops->start(seq, &seq->index);
|
||||
while (p)
|
||||
{
|
||||
error = seq->ops->show(seq, p);
|
||||
if (error < 0)
|
||||
break;
|
||||
if (error)
|
||||
{
|
||||
error = 0;
|
||||
seq->count = 0;
|
||||
}
|
||||
if (dfs_seq_is_full(seq))
|
||||
goto Eoverflow;
|
||||
|
||||
p = seq->ops->next(seq, p, &seq->index);
|
||||
if (pos + seq->count > offset)
|
||||
{
|
||||
seq->from = offset - pos;
|
||||
seq->count -= seq->from;
|
||||
break;
|
||||
}
|
||||
pos += seq->count;
|
||||
seq->count = 0;
|
||||
if (pos == offset)
|
||||
break;
|
||||
}
|
||||
seq->ops->stop(seq, p);
|
||||
return error;
|
||||
|
||||
Eoverflow:
|
||||
seq->ops->stop(seq, p);
|
||||
rt_free(seq->buf);
|
||||
seq->count = 0;
|
||||
seq->buf = dfs_seq_alloc(seq->size <<= 1);
|
||||
return !seq->buf ? -ENOMEM : -EAGAIN;
|
||||
}
|
||||
|
||||
ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos)
|
||||
{
|
||||
struct dfs_seq_file *seq = file->data;
|
||||
size_t copied = 0;
|
||||
size_t n;
|
||||
void *p;
|
||||
int err = 0;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
rt_mutex_take(&seq->lock, RT_WAITING_FOREVER);
|
||||
|
||||
/*
|
||||
* if request is to read from zero offset, reset iterator to first
|
||||
* record as it might have been already advanced by previous requests
|
||||
*/
|
||||
if (*pos == 0)
|
||||
{
|
||||
seq->index = 0;
|
||||
seq->count = 0;
|
||||
}
|
||||
|
||||
/* Don't assume ki_pos is where we left it */
|
||||
if (*pos != seq->read_pos)
|
||||
{
|
||||
while ((err = dfs_seq_traverse(seq, *pos)) == -EAGAIN)
|
||||
;
|
||||
if (err)
|
||||
{
|
||||
/* With prejudice... */
|
||||
seq->read_pos = 0;
|
||||
seq->index = 0;
|
||||
seq->count = 0;
|
||||
goto Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
seq->read_pos = *pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* grab buffer if we didn't have one */
|
||||
if (!seq->buf)
|
||||
{
|
||||
seq->buf = dfs_seq_alloc(seq->size = PAGE_SIZE);
|
||||
if (!seq->buf)
|
||||
goto Enomem;
|
||||
}
|
||||
// something left in the buffer - copy it out first
|
||||
if (seq->count)
|
||||
{
|
||||
n = seq->count > size ? size : seq->count;
|
||||
rt_memcpy((char *)buf + copied, seq->buf + seq->from, n);
|
||||
size -= n;
|
||||
seq->count -= n;
|
||||
seq->from += n;
|
||||
copied += n;
|
||||
if (seq->count) // hadn't managed to copy everything
|
||||
goto Done;
|
||||
}
|
||||
// get a non-empty record in the buffer
|
||||
seq->from = 0;
|
||||
p = seq->ops->start(seq, &seq->index);
|
||||
while (p)
|
||||
{
|
||||
err = seq->ops->show(seq, p);
|
||||
if (err < 0) // hard error
|
||||
break;
|
||||
if (err) // ->show() says "skip it"
|
||||
seq->count = 0;
|
||||
if (!seq->count)
|
||||
{ // empty record
|
||||
p = seq->ops->next(seq, p, &seq->index);
|
||||
continue;
|
||||
}
|
||||
if (!dfs_seq_is_full(seq)) // got it
|
||||
goto Fill;
|
||||
// need a bigger buffer
|
||||
seq->ops->stop(seq, p);
|
||||
rt_free(seq->buf);
|
||||
seq->count = 0;
|
||||
seq->buf = dfs_seq_alloc(seq->size <<= 1);
|
||||
if (!seq->buf)
|
||||
goto Enomem;
|
||||
p = seq->ops->start(seq, &seq->index);
|
||||
}
|
||||
// EOF or an error
|
||||
seq->ops->stop(seq, p);
|
||||
seq->count = 0;
|
||||
goto Done;
|
||||
Fill:
|
||||
// one non-empty record is in the buffer; if they want more,
|
||||
// try to fit more in, but in any case we need to advance
|
||||
// the iterator once for every record shown.
|
||||
while (1)
|
||||
{
|
||||
size_t offs = seq->count;
|
||||
off_t pos = seq->index;
|
||||
|
||||
p = seq->ops->next(seq, p, &seq->index);
|
||||
if (pos == seq->index)
|
||||
{
|
||||
LOG_W(".next function %p did not update position index\n", seq->ops->next);
|
||||
seq->index++;
|
||||
}
|
||||
if (!p) // no next record for us
|
||||
break;
|
||||
if (seq->count >= size)
|
||||
break;
|
||||
err = seq->ops->show(seq, p);
|
||||
if (err > 0)
|
||||
{ // ->show() says "skip it"
|
||||
seq->count = offs;
|
||||
}
|
||||
else if (err || dfs_seq_is_full(seq))
|
||||
{
|
||||
seq->count = offs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
seq->ops->stop(seq, p);
|
||||
n = seq->count > size ? size : seq->count;
|
||||
rt_memcpy((char *)buf + copied, seq->buf, n);
|
||||
size -= n;
|
||||
copied += n;
|
||||
seq->count -= n;
|
||||
seq->from = n;
|
||||
Done:
|
||||
if (!copied)
|
||||
{
|
||||
copied = seq->count ? -EFAULT : err;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pos += copied;
|
||||
seq->read_pos += copied;
|
||||
}
|
||||
rt_mutex_release(&seq->lock);
|
||||
return copied;
|
||||
Enomem:
|
||||
err = -ENOMEM;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
|
||||
{
|
||||
struct dfs_seq_file *seq = file->data;
|
||||
off_t retval = -EINVAL;
|
||||
|
||||
rt_mutex_take(&seq->lock, RT_WAITING_FOREVER);
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
offset += file->fpos;
|
||||
case SEEK_SET:
|
||||
if (offset < 0)
|
||||
break;
|
||||
retval = offset;
|
||||
if (offset != seq->read_pos)
|
||||
{
|
||||
while ((retval = dfs_seq_traverse(seq, offset)) == -EAGAIN);
|
||||
if (retval)
|
||||
{
|
||||
/* with extreme prejudice... */
|
||||
retval = 0;
|
||||
seq->read_pos = 0;
|
||||
seq->index = 0;
|
||||
seq->count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
seq->read_pos = offset;
|
||||
retval = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rt_mutex_release(&seq->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int dfs_seq_release(struct dfs_file *file)
|
||||
{
|
||||
struct dfs_seq_file *seq = file->data;
|
||||
|
||||
if (seq)
|
||||
{
|
||||
rt_mutex_detach(&seq->lock);
|
||||
if (seq->buf)
|
||||
{
|
||||
rt_free(seq->buf);
|
||||
}
|
||||
rt_free(seq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfs_seq_vprintf(struct dfs_seq_file *seq, const char *f, va_list args)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (seq->count < seq->size)
|
||||
{
|
||||
len = vsnprintf(seq->buf + seq->count, seq->size - seq->count, f, args);
|
||||
if (seq->count + len < seq->size)
|
||||
{
|
||||
seq->count += len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dfs_seq_overflow(seq);
|
||||
}
|
||||
|
||||
void dfs_seq_printf(struct dfs_seq_file *seq, const char *f, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, f);
|
||||
dfs_seq_vprintf(seq, f, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* write char to buffer
|
||||
*/
|
||||
void dfs_seq_putc(struct dfs_seq_file *seq, char c)
|
||||
{
|
||||
if (seq->count < seq->size)
|
||||
{
|
||||
seq->buf[seq->count++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write string to buffer
|
||||
*/
|
||||
void dfs_seq_puts(struct dfs_seq_file *seq, const char *s)
|
||||
{
|
||||
int len = strlen(s);
|
||||
|
||||
if (seq->count + len >= seq->size)
|
||||
{
|
||||
dfs_seq_overflow(seq);
|
||||
return;
|
||||
}
|
||||
rt_memcpy(seq->buf + seq->count, s, len);
|
||||
seq->count += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* write arbitrary data to buffer
|
||||
*/
|
||||
int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len)
|
||||
{
|
||||
if (seq->count + len < seq->size)
|
||||
{
|
||||
rt_memcpy(seq->buf + seq->count, data, len);
|
||||
seq->count += len;
|
||||
return 0;
|
||||
}
|
||||
dfs_seq_overflow(seq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* write padding spaces to buffer
|
||||
*/
|
||||
void dfs_seq_pad(struct dfs_seq_file *seq, char c)
|
||||
{
|
||||
int size = seq->pad_until - seq->count;
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
if (size + seq->count > seq->size)
|
||||
{
|
||||
dfs_seq_overflow(seq);
|
||||
return;
|
||||
}
|
||||
rt_memset(seq->buf + seq->count, ' ', size);
|
||||
seq->count += size;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
dfs_seq_putc(seq, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-05-05 Bernard Implement vnode in dfs v2.0
|
||||
*/
|
||||
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
#include "dfs_pcache.h"
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "DFS.vnode"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops *fops)
|
||||
{
|
||||
if (vnode)
|
||||
{
|
||||
rt_memset(vnode, 0, sizeof(struct dfs_vnode));
|
||||
|
||||
vnode->type = type;
|
||||
rt_atomic_store(&(vnode->ref_count), 1);
|
||||
vnode->mnt = RT_NULL;
|
||||
vnode->fops = fops;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dfs_vnode *dfs_vnode_create(void)
|
||||
{
|
||||
struct dfs_vnode *vnode = rt_calloc(1, sizeof(struct dfs_vnode));
|
||||
if (!vnode)
|
||||
{
|
||||
LOG_E("create a vnode failed.");
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
rt_atomic_store(&(vnode->ref_count), 1);
|
||||
|
||||
LOG_I("create a vnode: %p", vnode);
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
int dfs_vnode_destroy(struct dfs_vnode* vnode)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (vnode)
|
||||
{
|
||||
ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
if (rt_atomic_load(&(vnode->ref_count)) == 1)
|
||||
{
|
||||
LOG_I("free a vnode: %p", vnode);
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
if (vnode->aspace)
|
||||
{
|
||||
dfs_aspace_destroy(vnode->aspace);
|
||||
}
|
||||
#endif
|
||||
if (vnode->mnt)
|
||||
{
|
||||
DLOG(msg, "vnode", vnode->mnt->fs_ops->name, DLOG_MSG, "fs_ops->free_vnode");
|
||||
vnode->mnt->fs_ops->free_vnode(vnode);
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG(msg, "vnode", "vnode", DLOG_MSG, "destroy vnode(mnt=NULL)");
|
||||
}
|
||||
|
||||
dfs_file_unlock();
|
||||
|
||||
rt_free(vnode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_file_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dfs_vnode *dfs_vnode_ref(struct dfs_vnode *vnode)
|
||||
{
|
||||
if (vnode)
|
||||
{
|
||||
rt_atomic_add(&(vnode->ref_count), 1);
|
||||
|
||||
DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
void dfs_vnode_unref(struct dfs_vnode *vnode)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (vnode)
|
||||
{
|
||||
ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
rt_atomic_sub(&(vnode->ref_count), 1);
|
||||
DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
if (vnode->aspace)
|
||||
{
|
||||
dfs_aspace_destroy(vnode->aspace);
|
||||
}
|
||||
#endif
|
||||
if (rt_atomic_load(&(vnode->ref_count)) == 0)
|
||||
{
|
||||
LOG_I("free a vnode: %p", vnode);
|
||||
DLOG(msg, "vnode", "vnode", DLOG_MSG, "free vnode, ref_count=0");
|
||||
|
||||
if (vnode->mnt)
|
||||
{
|
||||
DLOG(msg, "vnode", vnode->mnt->fs_ops->name, DLOG_MSG, "fs_ops->free_vnode");
|
||||
vnode->mnt->fs_ops->free_vnode(vnode);
|
||||
}
|
||||
|
||||
dfs_file_unlock();
|
||||
|
||||
rt_free(vnode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_file_unlock();
|
||||
DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
Reference in new issue
Block a user