075cc017fe33966b0e5b704d4e8b0116f761fd91
[lunaix-os.git] / lunaix-os / includes / lunaix / fs.h
1 #ifndef __LUNAIX_VFS_H
2 #define __LUNAIX_VFS_H
3
4 #include <lunaix/clock.h>
5 #include <lunaix/device.h>
6 #include <lunaix/ds/btrie.h>
7 #include <lunaix/ds/hashtable.h>
8 #include <lunaix/ds/hstr.h>
9 #include <lunaix/ds/llist.h>
10 #include <lunaix/ds/lru.h>
11 #include <lunaix/ds/mutex.h>
12 #include <lunaix/process.h>
13 #include <lunaix/status.h>
14 #include <stdatomic.h>
15
16 #define VFS_NAME_MAXLEN 128
17 #define VFS_MAX_FD 32
18
19 #define VFS_IFDIR 0x1
20 #define VFS_IFFILE 0x2
21 #define VFS_IFSEQDEV 0x4
22 #define VFS_IFVOLDEV 0x8
23 #define VFS_IFSYMLINK 0x16
24
25 #define VFS_WALK_MKPARENT 0x1
26 #define VFS_WALK_FSRELATIVE 0x2
27 #define VFS_WALK_PARENT 0x4
28 #define VFS_WALK_NOFOLLOW 0x8
29
30 #define VFS_HASHTABLE_BITS 10
31 #define VFS_HASHTABLE_SIZE (1 << VFS_HASHTABLE_BITS)
32 #define VFS_HASH_MASK (VFS_HASHTABLE_SIZE - 1)
33 #define VFS_HASHBITS (32 - VFS_HASHTABLE_BITS)
34
35 #define VFS_PATH_DELIM '/'
36
37 #define FSTYPE_ROFS 0x1
38
39 #define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
40 #define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
41
42 #define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
43
44 #define VFS_VALID_CHAR(chr)                                                    \
45     (('A' <= (chr) && (chr) <= 'Z') || ('a' <= (chr) && (chr) <= 'z') ||       \
46      ('0' <= (chr) && (chr) <= '9') || (chr) == '.' || (chr) == '_' ||         \
47      (chr) == '-' || (chr) == ':')
48
49 #define unlock_inode(inode) mutex_unlock(&inode->lock)
50 #define lock_inode(inode)                                                      \
51     ({                                                                         \
52         mutex_lock(&inode->lock);                                              \
53         lru_use_one(inode_lru, &inode->lru);                                   \
54     })
55
56 #define unlock_dnode(dnode) mutex_unlock(&dnode->lock)
57 #define lock_dnode(dnode)                                                      \
58     ({                                                                         \
59         mutex_lock(&dnode->lock);                                              \
60         lru_use_one(dnode_lru, &dnode->lru);                                   \
61     })
62
63 typedef uint32_t inode_t;
64
65 struct v_dnode;
66 struct v_inode;
67 struct v_superblock;
68 struct v_file;
69 struct v_file_ops;
70 struct v_inode_ops;
71 struct v_fd;
72 struct pcache;
73 struct v_xattr_entry;
74
75 extern struct v_file_ops default_file_ops;
76 extern struct v_inode_ops default_inode_ops;
77
78 extern struct hstr vfs_ddot;
79 extern struct hstr vfs_dot;
80 extern struct v_dnode* vfs_sysroot;
81
82 struct filesystem
83 {
84     struct hlist_node fs_list;
85     struct hstr fs_name;
86     uint32_t types;
87     int fs_id;
88     int (*mount)(struct v_superblock* vsb, struct v_dnode* mount_point);
89     int (*unmount)(struct v_superblock* vsb);
90 };
91
92 struct v_superblock
93 {
94     struct llist_header sb_list;
95     struct device* dev;
96     struct v_dnode* root;
97     struct filesystem* fs;
98     uint32_t iobuf_size;
99     struct hbucket* i_cache;
100     void* data;
101     struct
102     {
103         uint32_t (*read_capacity)(struct v_superblock* vsb);
104         uint32_t (*read_usage)(struct v_superblock* vsb);
105         void (*init_inode)(struct v_superblock* vsb, struct v_inode* inode);
106     } ops;
107 };
108
109 struct dir_context
110 {
111     int index;
112     void* cb_data;
113     void (*read_complete_callback)(struct dir_context* dctx,
114                                    const char* name,
115                                    const int len,
116                                    const int dtype);
117 };
118
119 struct v_file_ops
120 {
121     int (*write)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
122     int (*read)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
123
124     // for operatiosn {write|read}_page, following are true:
125     //  + `len` always equals to PG_SIZE
126     //  + `fpos` always PG_SIZE aligned.
127     // These additional operations allow underlying fs to use more specialized
128     // and optimized code.
129
130     int (*write_page)(struct v_inode* inode, void* pg, size_t len, size_t fpos);
131     int (*read_page)(struct v_inode* inode, void* pg, size_t len, size_t fpos);
132
133     int (*readdir)(struct v_file* file, struct dir_context* dctx);
134     int (*seek)(struct v_inode* inode, size_t offset); // optional
135     int (*close)(struct v_file* file);
136     int (*sync)(struct v_file* file);
137 };
138
139 struct v_inode_ops
140 {
141     int (*create)(struct v_inode* this, struct v_dnode* dnode);
142     int (*open)(struct v_inode* this, struct v_file* file);
143     int (*sync)(struct v_inode* this);
144     int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
145     int (*rmdir)(struct v_inode* this, struct v_dnode* dir);
146     int (*unlink)(struct v_inode* this);
147     int (*link)(struct v_inode* this, struct v_dnode* new_name);
148     int (*read_symlink)(struct v_inode* this, const char** path_out);
149     int (*set_symlink)(struct v_inode* this, const char* target);
150     int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
151     int (*rename)(struct v_inode* from_inode,
152                   struct v_dnode* from_dnode,
153                   struct v_dnode* to_dnode);
154     int (*getxattr)(struct v_inode* this,
155                     struct v_xattr_entry* entry); // optional
156     int (*setxattr)(struct v_inode* this,
157                     struct v_xattr_entry* entry); // optional
158     int (*delxattr)(struct v_inode* this,
159                     struct v_xattr_entry* entry); // optional
160 };
161
162 struct v_xattr_entry
163 {
164     struct llist_header entries;
165     struct hstr name;
166     const void* value;
167     size_t len;
168 };
169
170 struct v_file
171 {
172     struct v_inode* inode;
173     struct v_dnode* dnode;
174     struct llist_header* f_list;
175     uint32_t f_pos;
176     atomic_ulong ref_count;
177     struct v_file_ops* ops; // for caching
178 };
179
180 struct v_fd
181 {
182     struct v_file* file;
183     int flags;
184 };
185
186 //  [v_inode::aka_nodes]
187 //  how do we invalidate corresponding v_dnodes given the v_inode?
188 /*
189     Consider taskfs, which is Lunaix's speak of Linux's procfs, that allow
190     info of every process being accessible via file system. Each process's
191     creation will result a creation of a directory under the root of task fs
192     with it's pid as name. But that dir must delete when process is killed, and
193     such deletion does not mediated by vfs itself, so there is a need of cache
194     syncing.
195     And this is also the case of all ramfs where argumentation to file tree is
196     performed by third party.
197 */
198
199 struct v_inode
200 {
201     inode_t id;
202     mutex_t lock;
203     uint32_t itype;
204     time_t ctime;
205     time_t mtime;
206     time_t atime;
207     lba_t lb_addr;
208     uint32_t open_count;
209     uint32_t link_count;
210     uint32_t lb_usage;
211     uint32_t fsize;
212     void* data; // 允许底层FS绑定他的一些专有数据
213     struct llist_header aka_dnodes;
214     struct llist_header xattrs;
215     struct v_superblock* sb;
216     struct hlist_node hash_list;
217     struct lru_node lru;
218     struct pcache* pg_cache;
219     struct v_inode_ops* ops;
220     struct v_file_ops* default_fops;
221 };
222
223 struct v_mount
224 {
225     mutex_t lock;
226     struct llist_header list;
227     struct llist_header submnts;
228     struct llist_header sibmnts;
229     struct v_mount* parent;
230     struct v_dnode* mnt_point;
231     struct v_superblock* super_block;
232     uint32_t busy_counter;
233     int flags;
234 };
235
236 struct v_dnode
237 {
238     mutex_t lock; // sync the path walking
239     struct lru_node lru;
240     struct hstr name;
241     struct v_inode* inode;
242     struct v_dnode* parent;
243     struct hlist_node hash_list;
244     struct llist_header aka_list;
245     struct llist_header children;
246     struct llist_header siblings;
247     struct v_superblock* super_block;
248     struct v_mount* mnt;
249     atomic_ulong ref_count;
250
251     void* data;
252 };
253
254 struct v_fdtable
255 {
256     struct v_fd* fds[VFS_MAX_FD];
257 };
258
259 struct pcache
260 {
261     struct v_inode* master;
262     struct btrie tree;
263     struct llist_header pages;
264     struct llist_header dirty;
265     uint32_t n_dirty;
266     uint32_t n_pages;
267 };
268
269 struct pcache_pg
270 {
271     struct llist_header pg_list;
272     struct llist_header dirty_list;
273     struct lru_node lru;
274     struct pcache* holder;
275     void* pg;
276     uint32_t flags;
277     uint32_t fpos;
278     uint32_t len;
279 };
280
281 void
282 fsm_init();
283
284 void
285 fsm_register_all();
286
287 struct filesystem*
288 fsm_new_fs(char* name, size_t name_len);
289
290 void
291 fsm_register(struct filesystem* fs);
292
293 struct filesystem*
294 fsm_get(const char* fs_name);
295
296 void
297 vfs_init();
298
299 void
300 vfs_export_attributes();
301
302 struct v_dnode*
303 vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str);
304
305 void
306 vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode);
307
308 void
309 vfs_dcache_rehash(struct v_dnode* new_parent, struct v_dnode* dnode);
310
311 void
312 vfs_dcache_remove(struct v_dnode* dnode);
313
314 int
315 vfs_walk(struct v_dnode* start,
316          const char* path,
317          struct v_dnode** dentry,
318          struct hstr* component,
319          int walk_options);
320
321 int
322 vfs_walk_proc(const char* path,
323               struct v_dnode** dentry,
324               struct hstr* component,
325               int options);
326
327 int
328 vfs_mount(const char* target,
329           const char* fs_name,
330           struct device* device,
331           int options);
332
333 int
334 vfs_unmount(const char* target);
335
336 int
337 vfs_mount_at(const char* fs_name,
338              struct device* device,
339              struct v_dnode* mnt_point,
340              int options);
341
342 int
343 vfs_unmount_at(struct v_dnode* mnt_point);
344
345 int
346 vfs_mkdir(const char* path, struct v_dnode** dentry);
347
348 int
349 vfs_open(struct v_dnode* dnode, struct v_file** file);
350
351 int
352 vfs_pclose(struct v_file* file, pid_t pid);
353
354 int
355 vfs_close(struct v_file* file);
356
357 void
358 vfs_free_fd(struct v_fd* fd);
359
360 int
361 vfs_fsync(struct v_file* file);
362
363 void
364 vfs_assign_inode(struct v_dnode* assign_to, struct v_inode* inode);
365
366 struct v_superblock*
367 vfs_sb_alloc();
368
369 void
370 vfs_sb_free(struct v_superblock* sb);
371
372 struct v_dnode*
373 vfs_d_alloc();
374
375 void
376 vfs_d_free(struct v_dnode* dnode);
377
378 struct v_inode*
379 vfs_i_find(struct v_superblock* sb, uint32_t i_id);
380
381 void
382 vfs_i_addhash(struct v_inode* inode);
383
384 struct v_inode*
385 vfs_i_alloc(struct v_superblock* sb);
386
387 void
388 vfs_i_free(struct v_inode* inode);
389
390 int
391 vfs_dup_fd(struct v_fd* old, struct v_fd** new);
392
393 int
394 vfs_getfd(int fd, struct v_fd** fd_s);
395
396 int
397 vfs_get_dtype(int itype);
398
399 void
400 vfs_ref_dnode(struct v_dnode* dnode);
401
402 void
403 vfs_unref_dnode(struct v_dnode* dnode);
404
405 int
406 vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth);
407
408 void
409 pcache_init(struct pcache* pcache);
410
411 void
412 pcache_release_page(struct pcache* pcache, struct pcache_pg* page);
413
414 struct pcache_pg*
415 pcache_new_page(struct pcache* pcache, uint32_t index);
416
417 void
418 pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg);
419
420 int
421 pcache_get_page(struct pcache* pcache,
422                 uint32_t index,
423                 uint32_t* offset,
424                 struct pcache_pg** page);
425
426 int
427 pcache_write(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos);
428
429 int
430 pcache_read(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos);
431
432 void
433 pcache_release(struct pcache* pcache);
434
435 int
436 pcache_commit(struct v_inode* inode, struct pcache_pg* page);
437
438 void
439 pcache_commit_all(struct v_inode* inode);
440
441 void
442 pcache_invalidate(struct pcache* pcache, struct pcache_pg* page);
443
444 /**
445  * @brief 将挂载点标记为繁忙
446  *
447  * @param mnt
448  */
449 void
450 mnt_mkbusy(struct v_mount* mnt);
451
452 /**
453  * @brief 将挂载点标记为清闲
454  *
455  * @param mnt
456  */
457 void
458 mnt_chillax(struct v_mount* mnt);
459
460 int
461 vfs_mount_root(const char* fs_name, struct device* device);
462
463 struct v_mount*
464 vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point);
465
466 int
467 vfs_check_writable(struct v_dnode* dnode);
468
469 int
470 default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
471
472 int
473 default_file_write(struct v_inode* inode,
474                    void* buffer,
475                    size_t len,
476                    size_t fpos);
477
478 int
479 default_file_readdir(struct v_file* file, struct dir_context* dctx);
480
481 int
482 default_inode_dirlookup(struct v_inode* this, struct v_dnode* dnode);
483
484 int
485 default_inode_rename(struct v_inode* from_inode,
486                      struct v_dnode* from_dnode,
487                      struct v_dnode* to_dnode);
488
489 int
490 default_file_close(struct v_file* file);
491
492 int
493 default_file_seek(struct v_inode* inode, size_t offset);
494
495 int
496 default_inode_open(struct v_inode* this, struct v_file* file);
497
498 int
499 default_inode_rmdir(struct v_inode* this, struct v_dnode* dir);
500
501 int
502 default_inode_mkdir(struct v_inode* this, struct v_dnode* dir);
503
504 struct v_xattr_entry*
505 xattr_new(struct hstr* name);
506
507 struct v_xattr_entry*
508 xattr_getcache(struct v_inode* inode, struct hstr* name);
509
510 void
511 xattr_addcache(struct v_inode* inode, struct v_xattr_entry* xattr);
512
513 #endif /* __LUNAIX_VFS_H */