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