1 /*
2 * Copyright (c) 2006-2025 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-05-05 Bernard Implement vnode in dfs v2.0
9 */
10
11 #include <dfs_file.h>
12 #include <dfs_mnt.h>
13 #ifdef RT_USING_PAGECACHE
14 #include "dfs_pcache.h"
15 #endif
16
17 #define DBG_TAG "DFS.vnode"
18 #define DBG_LVL DBG_WARNING
19 #include <rtdbg.h>
20
21 /**
22 * @brief Initialize a virtual node (vnode) structure
23 *
24 * @param[in,out] vnode Pointer to the vnode to be initialized
25 * @param[in] type Type of the vnode
26 * @param[in] fops Pointer to file operations structure
27 *
28 * @return int Always returns 0 indicating success
29 */
dfs_vnode_init(struct dfs_vnode * vnode,int type,const struct dfs_file_ops * fops)30 int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops *fops)
31 {
32 if (vnode)
33 {
34 rt_memset(vnode, 0, sizeof(struct dfs_vnode));
35
36 vnode->type = type;
37 rt_atomic_store(&(vnode->ref_count), 1);
38 vnode->mnt = RT_NULL;
39 vnode->fops = fops;
40 }
41
42 return 0;
43 }
44
45 /**
46 * @brief Create and initialize a new virtual node (vnode)
47 *
48 * @return struct dfs_vnode* Pointer to the newly created vnode, or NULL if creation failed
49 */
dfs_vnode_create(void)50 struct dfs_vnode *dfs_vnode_create(void)
51 {
52 struct dfs_vnode *vnode = rt_calloc(1, sizeof(struct dfs_vnode));
53 if (!vnode)
54 {
55 LOG_E("create a vnode failed.");
56 return RT_NULL;
57 }
58
59 rt_atomic_store(&(vnode->ref_count), 1);
60
61 LOG_I("create a vnode: %p", vnode);
62
63 return vnode;
64 }
65
66 /**
67 * @brief Destroy a virtual node (vnode) and free its resources
68 *
69 * @param[in] vnode Pointer to the vnode to be destroyed
70 *
71 * @return int Always returns 0. Note that this does not guarantee success, as errors may occur internally.
72 */
dfs_vnode_destroy(struct dfs_vnode * vnode)73 int dfs_vnode_destroy(struct dfs_vnode* vnode)
74 {
75 rt_err_t ret = RT_EOK;
76
77 if (vnode)
78 {
79 ret = dfs_file_lock();
80 if (ret == RT_EOK)
81 {
82 if (rt_atomic_load(&(vnode->ref_count)) == 1)
83 {
84 LOG_I("free a vnode: %p", vnode);
85 #ifdef RT_USING_PAGECACHE
86 if (vnode->aspace)
87 {
88 dfs_aspace_destroy(vnode->aspace);
89 }
90 #endif
91 if (vnode->mnt)
92 {
93 DLOG(msg, "vnode", vnode->mnt->fs_ops->name, DLOG_MSG, "fs_ops->free_vnode");
94 vnode->mnt->fs_ops->free_vnode(vnode);
95 }
96 else
97 {
98 DLOG(msg, "vnode", "vnode", DLOG_MSG, "destroy vnode(mnt=NULL)");
99 }
100
101 dfs_file_unlock();
102
103 rt_free(vnode);
104 }
105 else
106 {
107 dfs_file_unlock();
108 }
109 }
110 }
111
112 return 0;
113 }
114
115 /**
116 * @brief Increase reference count of a virtual node (vnode)
117 *
118 * @param[in,out] vnode Pointer to the vnode to be referenced
119 *
120 * @return struct dfs_vnode* The same vnode pointer that was passed in
121 */
dfs_vnode_ref(struct dfs_vnode * vnode)122 struct dfs_vnode *dfs_vnode_ref(struct dfs_vnode *vnode)
123 {
124 if (vnode)
125 {
126 rt_atomic_add(&(vnode->ref_count), 1);
127
128 DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
129 }
130
131 return vnode;
132 }
133
134 /**
135 * @brief Decrease reference count of a virtual node (vnode) and potentially free it
136 *
137 * @param[in,out] vnode Pointer to the vnode to be unreferenced
138 */
dfs_vnode_unref(struct dfs_vnode * vnode)139 void dfs_vnode_unref(struct dfs_vnode *vnode)
140 {
141 rt_err_t ret = RT_EOK;
142
143 if (vnode)
144 {
145 ret = dfs_file_lock();
146 if (ret == RT_EOK)
147 {
148 rt_atomic_sub(&(vnode->ref_count), 1);
149 DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
150 #ifdef RT_USING_PAGECACHE
151 if (vnode->aspace)
152 {
153 dfs_aspace_destroy(vnode->aspace);
154 }
155 #endif
156 if (rt_atomic_load(&(vnode->ref_count)) == 0)
157 {
158 LOG_I("free a vnode: %p", vnode);
159 DLOG(msg, "vnode", "vnode", DLOG_MSG, "free vnode, ref_count=0");
160
161 if (vnode->mnt)
162 {
163 DLOG(msg, "vnode", vnode->mnt->fs_ops->name, DLOG_MSG, "fs_ops->free_vnode");
164 vnode->mnt->fs_ops->free_vnode(vnode);
165 }
166
167 dfs_file_unlock();
168
169 rt_free(vnode);
170 }
171 else
172 {
173 dfs_file_unlock();
174 DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
175 }
176 }
177 }
178
179 return;
180 }
181