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