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