| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /*
- * 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);
|