RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
dfs_dentry.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-10-10 Bernard The first version of rewrite dfs
9 */
10#include <rtthread.h>
11
12#include "dfs.h"
13#include "dfs_file.h"
14#include "dfs_private.h"
15#include "dfs_dentry.h"
16#include "dfs_mnt.h"
17
18#define DBG_TAG "DFS.dentry"
19#define DBG_LVL DBG_WARNING
20#include <rtdbg.h>
21
22#define DFS_DENTRY_HASH_NR 32
23struct dentry_hash_head
24{
26};
27static struct dentry_hash_head hash_head;
28
29static uint32_t _dentry_hash(struct dfs_mnt *mnt, const char *path)
30{
31 uint32_t val = 0;
32
33 if (path)
34 {
35 while (*path)
36 {
37 val = ((val << 5) + val) + *path++;
38 }
39 }
40 return (val ^ (unsigned long) mnt) & (DFS_DENTRY_HASH_NR - 1);
41}
42
43static struct dfs_dentry *_dentry_create(struct dfs_mnt *mnt, char *path, rt_bool_t is_rela_path)
44{
45 struct dfs_dentry *dentry = RT_NULL;
46
47 if (mnt == RT_NULL || path == RT_NULL)
48 {
49 return dentry;
50 }
51
52 dentry = (struct dfs_dentry *)rt_calloc(1, sizeof(struct dfs_dentry));
53 if (dentry)
54 {
55 char *dentry_path = path;
56 if (!is_rela_path)
57 {
58 int mntpoint_len = strlen(mnt->fullpath);
59
60 if (rt_strncmp(mnt->fullpath, dentry_path, mntpoint_len) == 0)
61 {
62 dentry_path += mntpoint_len;
63 }
64 }
65
66 dentry->pathname = strlen(dentry_path) ? rt_strdup(dentry_path) : rt_strdup(path);
67 dentry->mnt = dfs_mnt_ref(mnt);
68
69 rt_atomic_store(&(dentry->ref_count), 1);
70 dentry->flags |= DENTRY_IS_ALLOCED;
71
72 LOG_I("create a dentry:%p for %s", dentry, fullpath);
73 }
74
75 return dentry;
76}
77
78struct dfs_dentry *dfs_dentry_create(struct dfs_mnt *mnt, char *fullpath)
79{
80 return _dentry_create(mnt, fullpath, RT_FALSE);
81}
82
83struct dfs_dentry *dfs_dentry_create_rela(struct dfs_mnt *mnt, char *rela_path)
84{
85 return _dentry_create(mnt, rela_path, RT_TRUE);;
86}
87
88struct dfs_dentry * dfs_dentry_ref(struct dfs_dentry *dentry)
89{
90 if (dentry)
91 {
92 int ret = dfs_file_lock();
93 if (ret == RT_EOK)
94 {
95 rt_atomic_add(&(dentry->ref_count), 1);
96 if (dentry->vnode)
97 {
98 rt_atomic_add(&(dentry->vnode->ref_count), 1);
99 }
101 }
102 }
103
104 return dentry;
105}
106
108{
109 rt_err_t ret = RT_EOK;
110
111 if (dentry)
112 {
113 ret = dfs_file_lock();
114 if (ret == RT_EOK)
115 {
116 if (dentry->flags & DENTRY_IS_ALLOCED)
117 {
118 rt_atomic_sub(&(dentry->ref_count), 1);
119 }
120
121 if (rt_atomic_load(&(dentry->ref_count)) == 0)
122 {
123 DLOG(msg, "dentry", "dentry", DLOG_MSG, "free dentry, ref_count=0");
124 if (dentry->flags & DENTRY_IS_ADDHASH)
125 {
126 rt_list_remove(&dentry->hashlist);
127 }
128
129 /* release vnode */
130 if (dentry->vnode)
131 {
132 dfs_vnode_unref(dentry->vnode);
133 }
134
135 /* release mnt */
136 DLOG(msg, "dentry", "mnt", DLOG_MSG, "dfs_mnt_unref(dentry->mnt)");
137 if (dentry->mnt)
138 {
139 dfs_mnt_unref(dentry->mnt);
140 }
141
143
144 LOG_I("free a dentry: %p", dentry);
145 rt_free(dentry->pathname);
146 rt_free(dentry);
147 dentry = RT_NULL;
148 }
149 else
150 {
151 if (dentry->vnode)
152 {
153 rt_atomic_sub(&(dentry->vnode->ref_count), 1);
154 }
156 DLOG(note, "dentry", "dentry ref_count=%d", rt_atomic_load(&(dentry->ref_count)));
157 }
158 }
159 }
160
161 return dentry;
162}
163
164static struct dfs_dentry *_dentry_hash_lookup(struct dfs_mnt *mnt, const char *path)
165{
166 rt_err_t ret = RT_EOK;
167 struct dfs_dentry *entry = RT_NULL;
168
169 ret = dfs_file_lock();
170 if (ret == RT_EOK)
171 {
172 rt_list_for_each_entry(entry, &hash_head.head[_dentry_hash(mnt, path)], hashlist)
173 {
174 if (entry->mnt == mnt && !strcmp(entry->pathname, path))
175 {
176 dfs_dentry_ref(entry);
178 return entry;
179 }
180 }
181
183 }
184
185 return RT_NULL;
186}
187
188void dfs_dentry_insert(struct dfs_dentry *dentry)
189{
191 rt_list_insert_after(&hash_head.head[_dentry_hash(dentry->mnt, dentry->pathname)], &dentry->hashlist);
192 dentry->flags |= DENTRY_IS_ADDHASH;
194}
195
196/*
197 * lookup a dentry, return this dentry and increase refcount if exist, otherwise return NULL
198 */
199struct dfs_dentry *dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint32_t flags)
200{
201 struct dfs_dentry *dentry;
202 struct dfs_vnode *vnode = RT_NULL;
203 int mntpoint_len = strlen(mnt->fullpath);
204
205 if (rt_strncmp(mnt->fullpath, path, mntpoint_len) == 0)
206 {
207 path += mntpoint_len;
208 if ((*path) == '\0')
209 {
210 /* root */
211 path = "/";
212 }
213 }
215 dentry = _dentry_hash_lookup(mnt, path);
216 if (!dentry)
217 {
218 if (mnt->fs_ops->lookup)
219 {
220 DLOG(activate, "dentry");
221 /* not in hash table, create it */
222 DLOG(msg, "dentry", "dentry", DLOG_MSG, "dfs_dentry_create_rela(mnt=%s, path=%s)", mnt->fullpath, path);
223 dentry = dfs_dentry_create_rela(mnt, (char*)path);
224 if (dentry)
225 {
226 DLOG(msg, "dentry", mnt->fs_ops->name, DLOG_MSG, "vnode=fs_ops->lookup(dentry)");
227
228 if (dfs_is_mounted(mnt) == 0)
229 {
230 vnode = mnt->fs_ops->lookup(dentry);
231 }
232
233 if (vnode)
234 {
235 DLOG(msg, mnt->fs_ops->name, "dentry", DLOG_MSG_RET, "return vnode");
236 dentry->vnode = vnode; /* the refcount of created vnode is 1. no need to reference */
238 rt_list_insert_after(&hash_head.head[_dentry_hash(mnt, path)], &dentry->hashlist);
239 dentry->flags |= DENTRY_IS_ADDHASH;
241
243 && !(dentry->flags & DENTRY_IS_OPENED))
244 {
245 rt_err_t ret = dfs_file_lock();
246 if (ret == RT_EOK)
247 {
248 dentry->flags |= DENTRY_IS_OPENED;
250 }
251 }
252 }
253 else
254 {
255 DLOG(msg, mnt->fs_ops->name, "dentry", DLOG_MSG_RET, "no dentry");
256
257 DLOG(msg, "dentry", "dentry", DLOG_MSG, "dfs_dentry_unref(dentry)");
258 dfs_dentry_unref(dentry);
259 dentry = RT_NULL;
260 }
261 }
262 DLOG(deactivate, "dentry");
263 }
264 }
265 else
266 {
267 DLOG(note, "dentry", "found dentry");
268 }
270 return dentry;
271}
272
273char* dfs_dentry_full_path(struct dfs_dentry* dentry)
274{
275 char *path = NULL;
276
277 if (dentry && dentry->mnt)
278 {
279 int mnt_len = strlen(dentry->mnt->fullpath);
280 int path_len = strlen(dentry->pathname);
281
282 path = (char *) rt_malloc(mnt_len + path_len + 3);
283 if (path)
284 {
285 if (dentry->pathname[0] == '/' || dentry->mnt->fullpath[mnt_len - 1] == '/')
286 {
287 rt_snprintf(path, mnt_len + path_len + 2, "%s%s", dentry->mnt->fullpath,
288 dentry->pathname);
289 }
290 else
291 {
292 rt_snprintf(path, mnt_len + path_len + 2, "%s/%s", dentry->mnt->fullpath,
293 dentry->pathname);
294 }
295 }
296 }
297
298 return path;
299}
300
301char* dfs_dentry_pathname(struct dfs_dentry* dentry)
302{
303 char *pathname = RT_NULL;
304 char *index = RT_NULL;
305
306 index = strrchr(dentry->pathname, '/');
307 if (index)
308 {
309 int length = index - dentry->pathname;
310 int path_length = strlen(dentry->mnt->fullpath) + length + 3;
311
312 pathname = (char*) rt_malloc(path_length);
313 if (pathname)
314 {
315 if (dentry->pathname[0] == '/')
316 {
317 rt_snprintf(pathname, path_length - 1, "%s%.*s", dentry->mnt->fullpath,
318 length, dentry->pathname);
319 }
320 else
321 {
322 rt_snprintf(pathname, path_length - 1, "%s/%.*s", dentry->mnt->fullpath,
323 length, dentry->pathname);
324 }
325 }
326 }
327 else
328 {
329 pathname = rt_strdup(dentry->mnt->fullpath);
330 }
331
332 return pathname;
333}
334
336{
337 uint32_t crc32 = 0xFFFFFFFF;
338 char *fullpath = dfs_dentry_full_path(dentry);
339 if (fullpath)
340 {
341 int i = 0;
342
343 while(fullpath[i] != '\0')
344 {
345 for (uint8_t b = 1; b; b <<= 1)
346 {
347 crc32 ^= (fullpath[i] & b) ? 1 : 0;
348 crc32 = (crc32 & 1) ? crc32 >> 1 ^ 0xEDB88320 : crc32 >> 1;
349 }
350 i ++;
351 }
352 rt_free(fullpath);
353 }
354 return crc32;
355}
356
358{
359 int i = 0;
360
361 for(i = 0; i < DFS_DENTRY_HASH_NR; i++)
362 {
363 rt_list_init(&hash_head.head[i]);
364 }
365
366 return 0;
367}
368
369int dfs_dentry_dump(int argc, char** argv)
370{
371 int index = 0;
372 struct dfs_dentry *entry = RT_NULL;
373
374 dfs_lock();
375 for (index = 0; index < DFS_DENTRY_HASH_NR; index ++)
376 {
377 rt_list_for_each_entry(entry, &hash_head.head[index], hashlist)
378 {
379 printf("dentry: %s%s @ %p, ref_count = %zd\n", entry->mnt->fullpath, entry->pathname, entry, (size_t)rt_atomic_load(&entry->ref_count));
380 }
381 }
382 dfs_unlock();
383
384 return 0;
385}
386MSH_CMD_EXPORT_ALIAS(dfs_dentry_dump, dentry_dump, dump dentry in the system);
rt_err_t dfs_lock(void)
定义 dfs.c:120
void dfs_unlock(void)
定义 dfs.c:137
struct dfs_dentry * dfs_dentry_create(struct dfs_mnt *mnt, char *fullpath)
struct dfs_dentry * dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint32_t flags)
int dfs_dentry_init(void)
#define DFS_DENTRY_HASH_NR
struct dfs_dentry * dfs_dentry_unref(struct dfs_dentry *dentry)
uint32_t dfs_dentry_full_path_crc32(struct dfs_dentry *dentry)
char * dfs_dentry_full_path(struct dfs_dentry *dentry)
void dfs_dentry_insert(struct dfs_dentry *dentry)
struct dfs_dentry * dfs_dentry_create_rela(struct dfs_mnt *mnt, char *rela_path)
char * dfs_dentry_pathname(struct dfs_dentry *dentry)
int dfs_dentry_dump(int argc, char **argv)
struct dfs_dentry * dfs_dentry_ref(struct dfs_dentry *dentry)
#define DENTRY_IS_OPENED
#define DENTRY_IS_ADDHASH
#define DENTRY_IS_ALLOCED
int dfs_is_mounted(struct dfs_mnt *mnt)
int dfs_mnt_unref(struct dfs_mnt *mnt)
struct dfs_mnt * dfs_mnt_ref(struct dfs_mnt *mnt)
void dfs_vnode_unref(struct dfs_vnode *vnode)
void dfs_file_unlock(void)
定义 dfs.c:164
rt_err_t dfs_file_lock(void)
定义 dfs.c:147
rt_inline void rt_list_remove(rt_list_t *n)
remove node from list.
rt_weak void * rt_calloc(rt_size_t count, rt_size_t size)
This function will contiguously allocate enough space for count objects that are size bytes of memory...
rt_inline void rt_list_init(rt_list_t *l)
initialize a list
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
insert a node after a list
#define rt_list_for_each_entry(pos, head, member)
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
rt_weak void * rt_malloc(rt_size_t size)
Allocate a block of memory with a minimum of 'size' bytes.
#define MSH_CMD_EXPORT_ALIAS(...)
#define rt_atomic_sub(ptr, v)
#define rt_atomic_add(ptr, v)
#define rt_atomic_store(ptr, v)
#define rt_atomic_load(ptr)
#define DLOG(...)
定义 rtdbg.h:53
#define LOG_I(...)
int rt_bool_t
rt_base_t rt_err_t
#define RT_TRUE
struct rt_list_node rt_list_t
#define RT_FALSE
#define RT_NULL
rt_atomic_t ref_count
rt_list_t hashlist
struct dfs_mnt * mnt
struct dfs_vnode * vnode
struct dfs_vnode *(* lookup)(struct dfs_dentry *dentry)
const char * name
char * fullpath
const struct dfs_filesystem_ops * fs_ops
struct dfs_mnt * mnt
rt_atomic_t ref_count