MOS Source Code
Loading...
Searching...
No Matches
dentry_utils.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
9
10#include <mos_stdio.hpp>
11#include <mos_stdlib.hpp>
12#include <mos_string.hpp>
13
14using namespace mos::string_literals;
15
17{
18 MOS_ASSERT(dentry);
19 MOS_ASSERT(dentry->inode); // one cannot refcount a dentry without an inode
20 dentry->refcount++;
21 inode_ref(dentry->inode);
22 pr_dinfo2(dcache_ref, "dentry %p '%s' increased refcount to %zu", (void *) dentry, dentry_name(dentry).c_str(), dentry->refcount.load());
23 return dentry;
24}
25
27{
28 pr_dinfo2(dcache_ref, "dentry_ref_up_to(%p '%s', %p '%s')", (void *) dentry, dentry_name(dentry).c_str(), (void *) root, dentry_name(root).c_str());
29 for (dentry_t *cur = dentry; cur != root; cur = dentry_parent(*cur))
30 {
31 dentry_ref(cur);
32 if (cur->name.empty())
33 {
35 dentry_ref(cur);
36 }
37 }
38
39 dentry_ref(root); // it wasn't refcounted in the loop
40
41 pr_dinfo2(dcache_ref, "...done");
42 return dentry;
43}
44
52{
53 if (dentry == NULL)
54 return false;
55
56 if (dentry->refcount == 0)
57 {
58 mos_warn("dentry refcount is already 0");
59 return false;
60 }
61
62 dentry->refcount--;
63
64 if (dentry->inode)
65 {
66 if (inode_unref(dentry->inode))
67 {
68 pr_dinfo2(vfs, "inode %p has no more references, releasing", (void *) dentry->inode);
69 dentry->inode = NULL;
70 }
71 }
72
73 pr_dinfo2(dcache_ref, "dentry %p '%s' decreased refcount to %zu", (void *) dentry, dentry_name(dentry).c_str(), dentry->refcount.load());
74
75 if (dentry->name.empty() && dentry != root_dentry)
76 {
77 dentry_t *mountpoint = dentry_root_get_mountpoint(dentry);
78 if (!mountpoint)
79 goto done;
80 mountpoint->refcount--;
81 pr_dinfo2(dcache_ref, " mountpoint %p '%s' decreased mountpoint refcount to %zu", (void *) mountpoint, dentry_name(mountpoint).c_str(),
82 mountpoint->refcount.load());
83 }
84done:
85 return true;
86}
87
88void dentry_dump_refstat(const dentry_t *dentry, dump_refstat_receiver_t *receiver, void *receiver_data)
89{
90 if (dentry == NULL)
91 return;
92 static int depth = 0;
93
94 receiver(depth, dentry, false, receiver_data);
95
96 if (dentry->is_mountpoint)
97 {
98 dentry = dentry_get_mount(dentry)->root;
99 receiver(depth, dentry, true, receiver_data);
100 }
101
102 depth++;
103 tree_foreach_child(dentry_t, child, dentry)
104 {
105 dentry_dump_refstat(child, receiver, receiver_data);
106 }
107 depth--;
108}
109
111{
112 size_t expected_refcount = 0;
113
114 if (dentry != root_dentry)
115 {
116 if (dentry->is_mountpoint)
117 expected_refcount++; // the mountpoint itself
118
119 if (dentry->name.empty())
120 expected_refcount++; // the mounted root dentry
121 }
122 else
123 {
124 expected_refcount++; // the root dentry should only has one reference
125 }
126
127 tree_foreach_child(dentry_t, child, dentry)
128 {
129 expected_refcount += child->refcount;
130 }
131
132 if (dentry->refcount < expected_refcount)
133 {
134 mos_warn("dentry %p refcount %zu is less than expected refcount %zu", (void *) dentry, dentry->refcount.load(), expected_refcount);
135 tree_foreach_child(dentry_t, child, dentry)
136 {
137 pr_warn(" child %p '%s' has %zu references", (void *) child, dentry_name(child).c_str(), child->refcount.load());
138 }
139 mos_panic("don't know how to handle this");
140 }
141 else if (dentry->refcount - expected_refcount)
142 {
143 pr_dinfo2(dcache_ref, " dentry %p '%s' has %zu direct references", (void *) dentry, dentry_name(dentry).c_str(), dentry->refcount - expected_refcount);
144 }
145}
146
148{
149 MOS_ASSERT(dentry->refcount == 0);
150
151 const bool can_release = dentry->inode == NULL && list_is_empty(&tree_node(dentry)->children);
152 if (can_release)
153 {
154 list_remove(&dentry->tree_node);
155 delete dentry;
156 }
157}
158
160{
161 if (!dentry_unref_one_norelease(dentry))
162 return;
163
164 dentry_check_refstat(dentry);
165 dentry_unref(dentry_parent(*dentry));
166
167 if (dentry->refcount == 0)
168 dentry_try_release(dentry);
169}
170
171ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size)
172{
173 if (dentry == NULL)
174 return 0;
175
176 if (size < 2)
177 return -1;
178
179 if (dentry == root)
180 {
181 buf[0] = '/';
182 buf[1] = '\0';
183 return 1;
184 }
185
186 if (dentry->name.empty())
187 dentry = dentry_root_get_mountpoint(dentry);
188
189 auto path = dentry->name;
190
191 for (dentry_t *current = dentry_parent(*dentry); current != root; current = dentry_parent(*current))
192 {
193 if (current->name.empty())
195
196 if (current == NULL)
197 {
198 // root for other fs trees
199 path = ":/" + path;
200 if (path.size() + 1 > size)
201 return -1;
202
203 const size_t real_size = snprintf(buf, size, "%s", path.c_str());
204 return real_size;
205 }
206 else
207 {
208 path = current->name + "/" + path;
209 }
210 }
211
212 if (path.size() + 1 > size)
213 return -1;
214
215 const size_t real_size = snprintf(buf, size, "/%s", path.c_str());
216 return real_size;
217}
#define MOS_ASSERT(cond)
Definition assert.hpp:14
#define mos_warn(fmt,...)
Definition assert.hpp:23
bool empty() const
Definition string.hpp:235
void dentry_dump_refstat(const dentry_t *dentry, dump_refstat_receiver_t *receiver, void *receiver_data)
dentry_t * dentry_ref_up_to(dentry_t *dentry, dentry_t *root)
Increment the reference count of a dentry up to a given dentry.
void dump_refstat_receiver_t(int depth, const dentry_t *dentry, bool mountroot, void *data)
Definition dentry.hpp:78
void dentry_try_release(dentry_t *dentry)
ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size)
Get the path of a dentry.
should_inline dentry_t * dentry_parent(const dentry_t &dentry)
Definition dentry.hpp:67
dentry_t * dentry_ref(dentry_t *dentry)
Increment the reference count of a dentry.
void dentry_check_refstat(const dentry_t *dentry)
Check the reference count of a dentry.
void dentry_unref(dentry_t *dentry)
Decrement the reference count of a dentry.
__nodiscard bool dentry_unref_one_norelease(dentry_t *dentry)
Decrease the refcount of ONE SINGLE dentry, including (if it's a mountpoint) the mountpoint dentry.
MOSAPI bool list_is_empty(const list_node_t *head)
Definition list.cpp:21
#define list_remove(element)
Definition list.hpp:80
dentry_t * root_dentry
Definition vfs.cpp:35
void inode_ref(inode_t *inode)
Definition inode.cpp:66
bool inode_unref(inode_t *inode)
Definition inode.cpp:72
#define __nodiscard
Definition mos_global.h:35
int snprintf(char *__restrict str, size_t size, const char *__restrict format,...)
Definition mos_stdio.cpp:16
#define current
dentry_t * dentry_root_get_mountpoint(dentry_t *dentry)
Given a mounted root dentry, return the mountpoint dentry that points to it.
Definition mount.cpp:22
ptr< mount_t > dentry_get_mount(const dentry_t *dentry)
Definition mount.cpp:50
#define mos_panic(fmt,...)
Definition panic.hpp:51
#define NULL
Definition pb_syshdr.h:46
#define pr_warn(fmt,...)
Definition printk.hpp:38
#define pr_dinfo2(feat, fmt,...)
Definition printk.hpp:27
size_t size
Definition slab.cpp:34
mos::string name
bool is_mountpoint
atomic_t refcount
inode_t * inode
#define tree_node(element)
Definition tree.hpp:29
#define tree_foreach_child(t, v, h)
Definition tree.hpp:36
signed long ssize_t
Definition types.h:79
mos::string dentry_name(const dentry_t *dentry)