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