PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
dentry.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/fs/path.h>
4#include <kernel/fs/vnode.h>
5#include <kernel/sync/mutex.h>
6#include <kernel/sync/rcu.h>
8#include <kernel/utils/map.h>
9#include <kernel/utils/ref.h>
10
11#include <stdatomic.h>
12#include <stdint.h>
13#include <sys/fs.h>
14#include <sys/list.h>
15
16typedef struct dentry dentry_t;
17typedef struct dentry_ops dentry_ops_t;
18typedef struct vnode vnode_t;
19typedef struct superblock superblock_t;
20typedef struct dir_ctx dir_ctx_t;
21
22/**
23 * @brief Directory entry.
24 * @defgroup kernel_fs_dentry Dentry
25 * @ingroup kernel_fs
26 *
27 * A dentry represents the actual name in the filesystem hierarchy. It can be either positive, meaning it has an
28 * associated vnode, or negative, meaning it does not have an associated vnode.
29 *
30 * ## Mountpoints and Root Dentries
31 *
32 * The difference between a mountpoint dentry and a root dentry can be a bit confusing, so here is a quick
33 * explanation. When a filesystem is mounted the dentry that it gets mounted to becomes a mountpoint, any data that
34 * was there before becomes hidden and when we traverse to that dentry we "jump" to the root dentry of the
35 * mounted filesystem. The root dentry of the mounted filesystem is simply the root directory of that filesystem.
36 *
37 * This means that the mountpoint does not "become" the root of the mounted filesystem, it simply points to it.
38 *
39 * Finally, note that just because a dentry is a mountpoint does not mean that it can be traversed by the current
40 * process, a process can only traverse a mountpoint if it is visible in its namespace, if its not visible the
41 * dentry acts exactly like a normal dentry.
42 *
43 * @{
44 */
45
46/**
47 * @brief Dentry ID type.
48 */
50
51/**
52 * @brief Macro to check if a dentry is the root entry in its filesystem.
53 *
54 * A dentry is considered the root if its parent is itself.
55 *
56 * @param dentry The dentry to check.
57 * @return true if the dentry is the root, false otherwise.
58 */
59#define DENTRY_IS_ROOT(dentry) ((dentry)->parent == (dentry))
60
61/**
62 * @brief Check if a dentry is positive.
63 *
64 * @param dentry The dentry to check.
65 * @return true if the dentry is positive, false if it is negative.
66 */
67#define DENTRY_IS_POSITIVE(dentry) ((dentry)->vnode != NULL)
68
69/**
70 * @brief Check if the vnode associated with a dentry is a regular file.
71 *
72 * @param dentry The dentry to check.
73 * @return true if the dentry is a regular file, false otherwise or if the dentry is negative.
74 */
75#define DENTRY_IS_REGULAR(dentry) (DENTRY_IS_POSITIVE(dentry) && (dentry)->vnode->type == VREG)
76
77/**
78 * @brief Check if the vnode associated with a dentry is a directory.
79 *
80 * @param dentry The dentry to check.
81 * @return true if the dentry is a directory, false otherwise or if the dentry is negative.
82 */
83#define DENTRY_IS_DIR(dentry) (DENTRY_IS_POSITIVE(dentry) && (dentry)->vnode->type == VDIR)
84
85/**
86 * @brief Check if the vnode associated with a dentry is a symbolic link.
87 *
88 * @param dentry The dentry to check.
89 * @return true if the dentry is a symbolic link, false otherwise or if the dentry is negative.
90 */
91#define DENTRY_IS_SYMLINK(dentry) (DENTRY_IS_POSITIVE(dentry) && (dentry)->vnode->type == VSYMLINK)
92
93/**
94 * @brief Directory context used to iterate over directory entries.
95 */
96typedef struct dir_ctx
97{
98 /**
99 * @brief Emit function.
100 *
101 * Should be called on all entries inside a directory while iterating over it, until this function returns `false`.
102 *
103 * Will be implemented by the VFS not the filesystem.
104 *
105 * @param ctx The directory context.
106 * @param name The name of the entry.
107 * @param number The vnode number of the entry.
108 * @param type The vnode type of the entry.
109 * @return `true` to continue iterating, `false` to stop.
110 */
111 bool (*emit)(dir_ctx_t* ctx, const char* name, vtype_t type);
112 size_t pos; ///< The current position in the directory, can be used to skip entries.
113 void* data; ///< Private data that the filesystem can use to conveniently pass data.
114 size_t index; ///< An index that the filesystem can use for its own purposes.
115} dir_ctx_t;
116
117/**
118 * @brief Dentry operations structure.
119 * @struct dentry_ops_t
120 */
121typedef struct dentry_ops
122{
123 /**
124 * @brief Called when the dentry is looked up or retrieved from cache.
125 *
126 * Used for security by hiding files or directories based on filesystem defined logic.
127 *
128 * @return On success, `0`. On failure, `ERR` and `errno` is set.
129 */
130 uint64_t (*revalidate)(dentry_t* dentry);
131 /**
132 * @brief Iterate over the entries in a directory dentry.
133 *
134 * @param dentry The directory dentry to iterate over.
135 * @param ctx The directory context to use for iteration.
136 * @return On success, `0`. On failure, `ERR` and `errno` is set.
137 */
138 uint64_t (*iterate)(dentry_t* dentry, dir_ctx_t* ctx);
139 /**
140 * @brief Called when the dentry is being freed.
141 *
142 * @param dentry The dentry being cleaned up.
143 */
144 void (*cleanup)(dentry_t* dentry);
146
147/**
148 * @brief Directory entry structure.
149 * @struct dentry_t
150 *
151 * A dentry structure is protected by the mutex of its vnode. Note that since move and rename are not supported in favor
152 * of link and remove, the parent of a dentry will never change after creation which allows some optimizations.
153 */
154typedef struct dentry
155{
158 char name[MAX_NAME]; ///< The name of the dentry, immutable after creation.
159 vnode_t* vnode; ///< Will be `NULL` if the dentry is negative, once positive it will never be modified.
160 dentry_t* parent; ///< The parent dentry, will be itself if this is the root dentry, immutable after creation.
165 void* data;
166 struct dentry* next; ///< Next dentry in the dentry cache hash bucket.
167 _Atomic(uint64_t) mountCount; ///< Number of mounts targeting this dentry.
168 rcu_entry_t rcu; ///< RCU entry for deferred cleanup.
169 list_entry_t otherEntry; ///< Made available for use by any other subsystems for convenience.
170} dentry_t;
171
172/**
173 * @brief Create a new dentry.
174 *
175 * Will not add the dentry to its parent's list of children but it will appear in the dentry cache as a negative dentry
176 * until `dentry_make_positive()` is called making it positive. This is needed to solve some race conditions when
177 * creating new files. While the dentry is negative it is not possible to create another dentry of the same name in the
178 * same parent, and any lookup to the dentry will fail until it is made positive.
179 *
180 * There is no `dentry_free()` instead use `UNREF()`.
181 *
182 * @param superblock The superblock the dentry belongs to.
183 * @param parent The parent dentry, can be `NULL`.
184 * @param name The name of the dentry, can be `NULL` if `parent` is also `NULL`.
185 * @return On success, the new dentry. On failure, returns `NULL` and `errno` is set.
186 */
187dentry_t* dentry_new(superblock_t* superblock, dentry_t* parent, const char* name);
188
189/**
190 * @brief Remove a dentry from the dentry cache.
191 *
192 * @note Will not free the dentry, use `UNREF()` for that.
193 *
194 * @param dentry The dentry to remove.
195 */
196void dentry_remove(dentry_t* dentry);
197
198/**
199 * @brief Get a dentry from the dentry cache in an RCU read-side critical section without traversing mountpoints.
200 *
201 * Will only check the dentry cache and return a dentry if it exists there, will not call the filesystem's lookup
202 * function.
203 *
204 * @warning Will NOT return a reference to the dentry, the caller must ensure that this function is called in a RCU read
205 * critical section.
206 *
207 * @param parent The parent path.
208 * @param name The name of the dentry.
209 * @param length The length of the name.
210 * @return On success, the dentry, might be negative. On failure, returns `NULL` and `errno` is set.
211 */
212dentry_t* dentry_rcu_get(const dentry_t* parent, const char* name, size_t length);
213
214/**
215 * @brief Lookup a dentry for the given name without traversing mountpoints.
216 *
217 * If the dentry is not found in the dentry cache, the filesystem's lookup function will be called to try to find it.
218 *
219 * @param parent The parent dentry.
220 * @param name The name of the dentry.
221 * @param length The length of the name.
222 * @return On success, a reference to the dentry, might be negative. On failure, returns `NULL` and `errno` is set.
223 */
224dentry_t* dentry_lookup(dentry_t* parent, const char* name, size_t length);
225
226/**
227 * @brief Make a dentry positive by associating it with an vnode.
228 *
229 * This function is expected to be protected by the parent vnode's mutex.
230 *
231 * @param dentry The dentry to make positive, or `NULL` for no-op.
232 * @param vnode The vnode to associate with the dentry, or `NULL` for no-op.
233 */
234void dentry_make_positive(dentry_t* dentry, vnode_t* vnode);
235
236/**
237 * @brief The amount of special entries "." and ".." that `dentry_iterate_dots()` emits.
238 */
239#define DENTRY_DOTS_AMOUNT 2
240
241/**
242 * @brief Helper function to iterate over the special entries "." and "..".
243 *
244 * Intended to be used in filesystem iterate implementations.
245 *
246 * @param dentry The directory dentry to iterate over.
247 * @param ctx The directory context to use for iteration.
248 * @return `true` if the iteration should continue, `false` if it should stop.
249 */
250bool dentry_iterate_dots(dentry_t* dentry, dir_ctx_t* ctx);
251
252/**
253 * @brief Helper function for a basic iterate.
254 */
256
257/** @} */
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:134
uint64_t dentry_generic_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Helper function for a basic iterate.
Definition dentry.c:325
uint64_t dentry_id_t
Dentry ID type.
Definition dentry.h:49
dentry_t * dentry_lookup(dentry_t *parent, const char *name, size_t length)
Lookup a dentry for the given name without traversing mountpoints.
Definition dentry.c:229
void dentry_make_positive(dentry_t *dentry, vnode_t *vnode)
Make a dentry positive by associating it with an vnode.
Definition dentry.c:289
void dentry_remove(dentry_t *dentry)
Remove a dentry from the dentry cache.
Definition dentry.c:178
bool dentry_iterate_dots(dentry_t *dentry, dir_ctx_t *ctx)
Helper function to iterate over the special entries "." and "..".
Definition dentry.c:304
dentry_t * dentry_rcu_get(const dentry_t *parent, const char *name, size_t length)
Get a dentry from the dentry cache in an RCU read-side critical section without traversing mountpoint...
Definition dentry.c:188
vtype_t
Vnode type enum.
Definition fs.h:342
#define bool
Definition stdbool.h:5
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
Dentry operations structure.
Definition dentry.h:122
Directory entry structure.
Definition dentry.h:155
list_t children
Definition dentry.h:162
rcu_entry_t rcu
RCU entry for deferred cleanup.
Definition dentry.h:168
ref_t ref
Definition dentry.h:156
dentry_id_t id
Definition dentry.h:157
const dentry_ops_t * ops
Definition dentry.h:164
_Atomic(uint64_t) mountCount
Number of mounts targeting this dentry.
list_entry_t otherEntry
Made available for use by any other subsystems for convenience.
Definition dentry.h:169
dentry_t * parent
The parent dentry, will be itself if this is the root dentry, immutable after creation.
Definition dentry.h:160
void * data
Definition dentry.h:165
struct dentry * next
Next dentry in the dentry cache hash bucket.
Definition dentry.h:166
vnode_t * vnode
Will be NULL if the dentry is negative, once positive it will never be modified.
Definition dentry.h:159
superblock_t * superblock
Definition dentry.h:163
list_entry_t siblingEntry
Definition dentry.h:161
Directory context used to iterate over directory entries.
Definition dentry.h:97
size_t index
An index that the filesystem can use for its own purposes.
Definition dentry.h:114
void * data
Private data that the filesystem can use to conveniently pass data.
Definition dentry.h:113
size_t pos
The current position in the directory, can be used to skip entries.
Definition dentry.h:112
A entry in a doubly linked list.
Definition list.h:37
A doubly linked list.
Definition list.h:46
Intrusive RCU head structure.
Definition rcu.h:65
Reference counting structure.
Definition ref.h:52
Superblock structure.
Definition superblock.h:33
vnode structure.
Definition vnode.h:48