Rewrite the lunabuild toolchain with enhanced feature (#60)
[lunaix-os.git] / lunaix-os / kernel / fs / ext2 / ext2.h
1 #ifndef __LUNAIX_EXT2_H
2 #define __LUNAIX_EXT2_H
3
4 #include <lunaix/fs/api.h>
5 #include <lunaix/types.h>
6 #include <lunaix/ds/llist.h>
7 #include <lunaix/ds/hashtable.h>
8 #include <lunaix/ds/lru.h>
9 #include <lunaix/ds/mutex.h>
10
11 #ifdef CONFIG_EXT2_DEBUG_MSG
12 #   include <lunaix/syslog.h>
13 #   define ext2_debug(fmt, ...)  kprintf_v("ext2", fmt, ##__VA_ARGS__)
14 #else
15 #   define ext2_debug(fmt, ...)
16 #endif
17
18 #define FEAT_COMPRESSION      0b00000001
19 #define FEAT_RESIZE_INO       0b00000010
20 #define FEAT_FILETYPE         0b00000100
21 #define FEAT_SPARSE_SB        0b00001000
22 #define FEAT_LARGE_FILE       0b00010000
23
24 #define IMODE_IFSOCK          0xC000
25 #define IMODE_IFLNK           0xA000
26 #define IMODE_IFREG           0x8000
27 #define IMODE_IFBLK           0x6000
28 #define IMODE_IFDIR           0x4000
29 #define IMODE_IFCHR           0x2000
30 #define IMODE_IFFIFO          0x1000
31
32 #define IMODE_URD             0x0100
33 #define IMODE_UWR             0x0080
34 #define IMODE_UEX             0x0040
35 #define IMODE_GRD             0x0020
36 #define IMODE_GWR             0x0010
37 #define IMODE_GEX             0x0008
38 #define IMODE_ORD             0x0004
39 #define IMODE_OWR             0x0002
40 #define IMODE_OEX             0x0001
41 #define IMODE_ACL_MASK        0x01ff
42
43 #define ext2_aligned                    compact align(4)
44 #define to_ext2ino_id(fsblock_id)       ((fsblock_id) + 1)
45 #define to_fsblock_id(ext2_ino)         ((ext2_ino) - 1)
46
47 extern bcache_zone_t gdesc_bcache_zone;
48
49 struct ext2b_super {
50     u32_t s_ino_cnt;
51     u32_t s_blk_cnt;
52     u32_t s_r_blk_cnt;
53     u32_t s_free_blk_cnt;
54     u32_t s_free_ino_cnt;
55     u32_t s_first_data_cnt;
56
57     u32_t s_log_blk_size;
58     u32_t s_log_frg_size;
59
60     u32_t s_blk_per_grp;
61     u32_t s_frg_per_grp;
62     u32_t s_ino_per_grp;
63
64     u32_t s_mtime;
65     u32_t s_wtime;
66     
67     u16_t s_mnt_cnt;
68     u16_t s_max_mnt_cnt;
69     u16_t s_magic;
70     u16_t s_state;
71     u16_t s_error;
72     u16_t s_minor_rev;
73
74     u32_t s_last_check;
75     u32_t s_checkinterval;
76     u32_t s_creator_os;
77     u32_t s_rev;
78     
79     u16_t s_def_resuid;
80     u16_t s_def_resgid;
81
82     // EXT2_DYNAMIC_REV
83
84     struct {
85         u32_t s_first_ino;
86         u16_t s_ino_size;
87         u16_t s_blkgrp_nr;
88         u32_t s_optional_feat;
89         u32_t s_required_feat;
90         u32_t s_ro_feat;
91         u8_t s_uuid[16];
92         u8_t s_volname[16];
93         u8_t s_last_mnt[64];
94         u32_t s_algo_bmp;
95     } compact;
96
97 } ext2_aligned;
98
99 struct ext2b_gdesc
100 {
101     u32_t bg_blk_map;
102     u32_t bg_ino_map;
103     u32_t bg_ino_tab;
104
105     u16_t bg_free_blk_cnt;
106     u16_t bg_free_ino_cnt;
107     u16_t bg_used_dir_cnt;
108     u16_t bg_pad;
109 } align(32) compact;
110
111 struct ext2b_inode
112 {
113     u16_t i_mode;
114     u16_t i_uid;
115     union {
116         u32_t i_size;
117         u32_t i_size_l32;
118     };
119
120     u32_t i_atime;
121     u32_t i_ctime;
122     u32_t i_mtime;
123     u32_t i_dtime;
124
125     u16_t i_gid;
126     u16_t i_lnk_cnt;
127
128     u32_t i_blocks;
129     u32_t i_flags;
130     u32_t i_osd1;
131
132     union {
133         struct 
134         {
135             u32_t directs[12];  // directum
136             union {
137                 struct {
138                     u32_t ind1;         // prima indirecta
139                     u32_t ind23[2];     // secunda et tertia indirecta
140                 } ext2_aligned;
141                 u32_t inds[3];
142             };
143         } ext2_aligned i_block;
144         u32_t i_block_arr[15];
145     };
146
147     u32_t i_gen;
148     u32_t i_file_acl;
149     union {
150         u32_t i_dir_acl;
151         u32_t i_size_h32;
152     };
153     u32_t i_faddr;
154
155     u8_t i_osd2[12];
156 } ext2_aligned;
157
158 struct ext2b_dirent 
159 {
160     u32_t inode;
161     u16_t rec_len;
162     u8_t name_len;
163     u8_t file_type;
164     char name[256];
165 } ext2_aligned;
166 #define EXT2_DRE(v_dnode) (fsapi_impl_data(v_dnode, struct ext2b_dirent))
167
168
169 #define GDESC_INO_SEL 0
170 #define GDESC_BLK_SEL 1
171
172 #define GDESC_FREE_LISTS                        \
173     union {                                     \
174         struct {                                \
175             struct llist_header free_grps_ino;  \
176             struct llist_header free_grps_blk;  \
177         };                                      \
178         struct llist_header free_list_sel[2];   \
179     }
180
181 #define check_gdesc_type_sel(sel)                               \
182     assert_msg(sel == GDESC_INO_SEL || sel == GDESC_BLK_SEL,    \
183                 "invalid type_sel");
184
185 struct ext2_sbinfo 
186 {
187     /**
188      * @brief 
189      * offset to inode table (in terms of blocks) within each block group.
190      * to account the difference of backup presence between rev 0/1
191      */
192     int ino_tab_len;
193
194     bool read_only;
195     unsigned int block_size;
196     unsigned int nr_gdesc_pb;
197     unsigned int nr_gdesc;
198     unsigned int all_feature;
199
200     struct device* bdev;
201     struct v_superblock* vsb;
202     
203     struct ext2b_super* raw;
204     bbuf_t* gdt_frag;
205     struct bcache gd_caches;
206     
207     bbuf_t buf;
208
209     struct {
210         struct llist_header gds;
211         GDESC_FREE_LISTS;
212     };
213
214     mutex_t lock;
215 };
216 #define EXT2_SB(vsb) (fsapi_impl_data(vsb, struct ext2_sbinfo))
217
218
219 struct ext2_bmp
220 {
221     bbuf_t raw;
222     u8_t* bmp;
223     unsigned int nr_bytes;
224     int next_free;
225 };
226
227 struct ext2_gdesc
228 {
229     struct llist_header groups;
230     GDESC_FREE_LISTS;
231
232     union {
233         struct {
234             struct ext2_bmp ino_bmp;
235             struct ext2_bmp blk_bmp;
236         };
237         struct ext2_bmp bmps[2];
238     };
239
240     unsigned int base;
241     unsigned int ino_base;
242
243     struct ext2b_gdesc* info;
244     struct ext2_sbinfo* sb;
245     bbuf_t buf;
246     bcobj_t cache_ref;
247
248     mutex_t lock;
249 };
250
251 /*
252     Indriection Block Translation Look-aside Buffer
253     
254     Provide a look-aside buffer for all last-level indirect block 
255     that is at least two indirection away.
256
257     For 4KiB block size:
258         16 sets, 256 ways, capacity 4096 blocks
259 */
260
261 struct ext2_btlb_entry
262 {
263     unsigned int tag;
264     bbuf_t block;
265 };
266
267 #define BTLB_SETS        16
268 struct ext2_btlb
269 {
270     struct ext2_btlb_entry buffer[BTLB_SETS];
271 };
272
273 struct ext2_fast_inode
274 {
275     struct ext2b_inode* ino;
276     bbuf_t buf;
277 };
278
279 struct ext2_inode
280 {
281     bbuf_t buf;                  // partial inotab that holds this inode
282     unsigned int inds_lgents;       // log2(# of block in an indirection level)
283     unsigned int ino_id;
284     size_t nr_fsblks;
285     size_t nr_indblks;
286     size_t isize;
287
288     struct ext2b_inode* ino;        // raw ext2 inode
289     struct ext2_btlb* btlb;         // block-TLB
290     struct ext2_gdesc* blk_grp;     // block group
291
292     union {
293         struct {
294             /*
295                 (future)
296                 dirent fragmentation degree, we will perform
297                 full reconstruction on dirent table when this goes too high.
298             */
299             unsigned int dir_fragdeg;
300         }; 
301     };
302
303     // prefetched block for 1st order of indirection
304     bbuf_t ind_ord1;
305     char* symlink;
306
307     // No lock required, it shares lock context with v_inode.
308 };
309 #define EXT2_INO(v_inode) (fsapi_impl_data(v_inode, struct ext2_inode))
310
311 struct ext2_dnode_sub
312 {
313     bbuf_t buf;
314     struct ext2b_dirent* dirent;
315 };
316
317 struct ext2_dnode
318 {
319     struct ext2_dnode_sub self;
320     struct ext2_dnode_sub prev;
321
322     // No lock required, it shares lock context with v_dnode.
323 };
324 #define EXT2_DNO(v_dnode) (fsapi_impl_data(v_dnode, struct ext2_dnode))
325
326
327 /**
328  * @brief General purpose iterator for ext2 objects
329  * 
330  */
331 struct ext2_iterator
332 {
333     struct v_inode* inode;
334     
335     union {
336         struct ext2b_dirent* dirent;
337         void* data;
338     };
339
340     union {
341         struct {
342             bool has_error:1;
343         };
344         unsigned int flags;
345     };
346
347     size_t pos;
348     unsigned int blksz;
349     size_t end_pos;
350     bbuf_t sel_buf;
351 };
352
353 struct ext2_file
354 {
355     struct ext2_iterator iter;
356 };
357 #define EXT2_FILE(v_file) (fsapi_impl_data(v_file, struct ext2_file))
358
359
360 #define MAX_INDS_DEPTH  4
361
362 struct walk_stack
363 {
364     unsigned int tables[MAX_INDS_DEPTH];
365     unsigned int indices[MAX_INDS_DEPTH];
366 };
367
368 struct walk_state
369 {
370     unsigned int* slot_ref;
371     bbuf_t table;
372     int indirections;
373     int level;
374
375     struct walk_stack stack;
376 };
377
378 static inline unsigned int
379 ext2_datablock(struct v_superblock* vsb, unsigned int id)
380 {
381     return EXT2_SB(vsb)->raw->s_first_data_cnt + id;
382 }
383
384 static inline bool
385 ext2_feature(struct v_superblock* vsb, unsigned int feat)
386 {
387     return !!(EXT2_SB(vsb)->all_feature & feat);
388 }
389
390 /* ************   Superblock   ************ */
391
392 static inline void
393 ext2sb_schedule_sync(struct ext2_sbinfo* sb)
394 {
395     fsblock_dirty(sb->buf);
396 }
397
398 static inline void must_inline
399 ext2sb_lock(struct ext2_sbinfo* sb)
400 {
401     mutex_lock(&sb->lock);
402 }
403
404 static inline void must_inline
405 ext2sb_unlock(struct ext2_sbinfo* sb)
406 {
407     mutex_unlock(&sb->lock);
408 }
409
410
411 /* ************   Inodes   ************ */
412
413 void
414 ext2ino_init(struct v_superblock* vsb, struct v_inode* inode);
415
416 int
417 ext2ino_get(struct v_superblock* vsb, 
418                unsigned int ino, struct ext2_inode** out);
419
420 int
421 ext2ino_get_fast(struct v_superblock* vsb, 
422                  unsigned int ino, struct ext2_fast_inode* fast_ino);
423
424 int
425 ext2ino_fill(struct v_inode* inode, ino_t ino_id);
426
427 int
428 ext2ino_make(struct v_superblock* vsb, unsigned int itype, 
429              struct ext2_inode* hint, struct v_inode** out);
430
431 void
432 ext2ino_update(struct v_inode* inode);
433
434 int
435 ext2ino_resizing(struct v_inode* inode, size_t new_size);
436
437 static inline void
438 ext2ino_linkto(struct ext2_inode* e_ino, struct ext2b_dirent* dirent)
439 {
440     dirent->inode = e_ino->ino_id;
441     e_ino->ino->i_lnk_cnt++;
442     fsblock_dirty(e_ino->buf);
443 }
444
445 static inline void
446 ext2ino_schedule_sync(struct ext2_inode* ino)
447 {
448     fsblock_dirty(ino->buf);
449 }
450
451
452 /* ************* Data blocks ************* */
453
454 #define DBIT_MODE_ISIZE 0
455 #define DBIT_MODE_BLOCK 1
456
457 void
458 ext2db_itbegin(struct ext2_iterator* iter, struct v_inode* inode, int mode);
459
460 void
461 ext2db_itend(struct ext2_iterator* iter);
462
463 bool
464 ext2db_itnext(struct ext2_iterator* iter);
465
466 int
467 ext2db_itffw(struct ext2_iterator* iter, int count);
468
469 void
470 ext2db_itreset(struct ext2_iterator* iter);
471
472
473 /**
474  * @brief Get the data block at given data pos associated with the
475  *        inode, return NULL if not present
476  * 
477  * @param inode 
478  * @param data_pos 
479  * @return bbuf_t 
480  */
481 bbuf_t
482 ext2db_get(struct v_inode* inode, unsigned int data_pos);
483
484 /**
485  * @brief Get the data block at given data pos associated with the
486  *        inode, allocate one if not present.
487  * 
488  * @param inode 
489  * @param data_pos 
490  * @param out 
491  * @return int 
492  */
493 int
494 ext2db_acquire(struct v_inode* inode, unsigned int data_pos, bbuf_t* out);
495
496 void
497 ext2db_free_pos(struct v_inode* inode, unsigned int block_pos);
498
499 /* ************* Walker ************* */
500
501 static inline void
502 ext2walk_init_state(struct walk_state* state)
503 {
504     *state = (struct walk_state) { };
505 }
506
507 static inline void
508 ext2walk_free_state(struct walk_state* state)
509 {
510     fsblock_put(state->table);
511 }
512
513 /* ************* Iterator ************* */
514
515 static inline bool
516 ext2_iterror(struct ext2_iterator* iter) {
517     return iter->has_error;
518 }
519
520 static inline bool
521 ext2_itcheckbuf(struct ext2_iterator* iter) {
522     return !(iter->has_error = blkbuf_errbuf(iter->sel_buf));
523 }
524
525 #define itstate_sel(iter, value)    \
526     (ext2_iterror(iter) ? EIO : (int)(value))
527
528
529 /* ************ Block Group ************ */
530
531 void
532 ext2gd_prepare_gdt(struct v_superblock* vsb);
533
534 void
535 ext2gd_release_gdt(struct v_superblock* vsb);
536
537 int
538 ext2gd_take_at(struct v_superblock* vsb, 
539                unsigned int index, struct ext2_gdesc** out);
540
541 static inline struct ext2_gdesc*
542 ext2gd_take(struct ext2_gdesc* gd) {
543     bcache_refonce(gd->cache_ref);
544
545     return gd;
546 }
547
548 static inline void
549 ext2gd_put(struct ext2_gdesc* gd) {
550     bcache_return(gd->cache_ref);
551 }
552
553 static inline void must_inline
554 ext2gd_lock(struct ext2_gdesc* gd)
555 {
556     mutex_lock(&gd->lock);
557 }
558
559 static inline void must_inline
560 ext2gd_unlock(struct ext2_gdesc* gd)
561 {
562     mutex_unlock(&gd->lock);
563 }
564
565
566 /* ************ Directory ************ */
567
568 int
569 ext2dr_lookup(struct v_inode* this, struct v_dnode* dnode);
570
571 int
572 ext2dr_read(struct v_file *file, struct dir_context *dctx);
573
574 void
575 ext2dr_itbegin(struct ext2_iterator* iter, struct v_inode* inode);
576
577 void
578 ext2dr_itend(struct ext2_iterator* iter);
579
580 static inline bool
581 ext2dr_itdrain(struct ext2_iterator* iter)
582 {
583     return iter->pos > iter->end_pos;
584 }
585
586 bool
587 ext2dr_itnext(struct ext2_iterator* iter);
588
589 int
590 ext2dr_itffw(struct ext2_iterator* iter, int count);
591
592 void
593 ext2dr_itreset(struct ext2_iterator* iter);
594
595 int
596 ext2dr_open(struct v_inode* this, struct v_file* file);
597
598 int
599 ext2dr_close(struct v_inode* this, struct v_file* file);
600
601 int
602 ext2dr_seek(struct v_file* file, size_t offset);
603
604 int
605 ext2dr_insert(struct v_inode* this, struct ext2b_dirent* dirent,
606               struct ext2_dnode** e_dno_out);
607
608 int
609 ext2dr_remove(struct ext2_dnode* e_dno);
610
611 int
612 ext2_rmdir(struct v_inode* parent, struct v_dnode* dnode);
613
614 int
615 ext2_mkdir(struct v_inode* parent, struct v_dnode* dnode);
616
617 int
618 ext2_rename(struct v_inode* from_inode, struct v_dnode* from_dnode,
619             struct v_dnode* to_dnode);
620
621 void
622 ext2dr_setup_dirent(struct ext2b_dirent* dirent, 
623                     struct v_inode* inode, struct hstr* name);
624
625
626 /* ************   Files   ************ */
627
628 int
629 ext2_open_inode(struct v_inode* this, struct v_file* file);
630
631 int
632 ext2_close_inode(struct v_file* file);
633
634 int
635 ext2_sync_inode(struct v_inode* inode);
636
637 int
638 ext2_file_sync(struct v_file* file);
639
640 int
641 ext2_inode_read(struct v_inode *inode, void *buffer, size_t len, size_t fpos);
642
643 int
644 ext2_inode_read_page(struct v_inode *inode, void *buffer, size_t fpos);
645
646 int
647 ext2_inode_write(struct v_inode *inode, void *buffer, size_t len, size_t fpos);
648
649 int
650 ext2_inode_write_page(struct v_inode *inode, void *buffer, size_t fpos);
651
652 int
653 ext2_seek_inode(struct v_file* file, size_t offset);
654
655 int
656 ext2_create(struct v_inode* this, struct v_dnode* dnode, unsigned int itype);
657
658 int
659 ext2_link(struct v_inode* this, struct v_dnode* new_name);
660
661 int
662 ext2_unlink(struct v_inode* this, struct v_dnode* name);
663
664 int
665 ext2_get_symlink(struct v_inode *this, const char **path_out);
666
667 int
668 ext2_set_symlink(struct v_inode *this, const char *target);
669
670 /* ***********   Allocations   *********** */
671
672 #define ALLOC_FAIL -1
673
674 static inline bool
675 valid_bmp_slot(int slot)
676 {
677     return slot != ALLOC_FAIL;
678 }
679
680 int
681 ext2gd_alloc_slot(struct ext2_gdesc* gd, int type_sel);
682
683 void
684 ext2gd_free_slot(struct ext2_gdesc* gd, int type_sel, int slot);
685
686 static inline int
687 ext2gd_alloc_inode(struct ext2_gdesc* gd) 
688 {
689     return ext2gd_alloc_slot(gd, GDESC_INO_SEL);
690 }
691
692 static inline int
693 ext2gd_alloc_block(struct ext2_gdesc* gd) 
694 {
695     return ext2gd_alloc_slot(gd, GDESC_BLK_SEL);
696 }
697
698 static inline void
699 ext2gd_free_inode(struct ext2_gdesc* gd, int slot) 
700 {
701     ext2gd_free_slot(gd, GDESC_INO_SEL, slot);
702 }
703
704 static inline void
705 ext2gd_free_block(struct ext2_gdesc* gd, int slot) 
706 {
707     ext2gd_free_slot(gd, GDESC_BLK_SEL, slot);
708 }
709
710 static inline void
711 ext2gd_schedule_sync(struct ext2_gdesc* gd)
712 {
713     fsblock_dirty(gd->buf);
714     fsblock_dirty(gd->ino_bmp.raw);
715     fsblock_dirty(gd->blk_bmp.raw);
716 }
717
718 /**
719  * @brief Allocate a free inode
720  * 
721  * @param vsb 
722  * @param hint locality hint
723  * @param out 
724  * @return int 
725  */
726 int
727 ext2ino_alloc(struct v_superblock* vsb, 
728                  struct ext2_inode* hint, struct ext2_inode** out);
729
730 /**
731  * @brief Allocate a free data block
732  * 
733  * @param inode inode where the data block goes, also used as locality hint
734  * @return bbuf_t 
735  */
736 int
737 ext2db_alloc(struct v_inode* inode, bbuf_t* out);
738
739 /**
740  * @brief free an inode
741  * 
742  * @param vsb 
743  * @param hint locality hint
744  * @param out 
745  * @return int 
746  */
747 int
748 ext2ino_free(struct v_inode* inode);
749
750 /**
751  * @brief Free a data block
752  * 
753  * @param inode inode where the data block goes, also used as locality hint
754  * @return bbuf_t 
755  */
756 int
757 ext2db_free(struct v_inode* inode, bbuf_t buf);
758
759 int
760 ext2ino_alloc_slot(struct v_superblock* vsb, struct ext2_gdesc** gd_out);
761
762 int
763 ext2db_alloc_slot(struct v_superblock* vsb, struct ext2_gdesc** gd_out);
764
765
766 /* ***********   Bitmap   *********** */
767
768 void
769 ext2bmp_init(struct ext2_bmp* e_bmp, bbuf_t bmp_buf, unsigned int nr_bits);
770
771 int
772 ext2bmp_alloc_nolock(struct ext2_bmp* e_bmp);
773
774 void
775 ext2bmp_free_nolock(struct ext2_bmp* e_bmp, unsigned int pos);
776
777 void
778 ext2bmp_discard_nolock(struct ext2_bmp* e_bmp);
779
780 static inline bool
781 ext2bmp_check_free(struct ext2_bmp* e_bmp)
782 {
783     assert(e_bmp->raw);
784
785     return valid_bmp_slot(e_bmp->next_free);
786 }
787
788 #endif /* __LUNAIX_EXT2_H */