1 #ifndef __LUNAIX_EXT2_H
2 #define __LUNAIX_EXT2_H
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>
11 #ifdef CONFIG_EXT2_DEBUG_MSG
12 # include <lunaix/syslog.h>
13 # define ext2_debug(fmt, ...) kprintf_v("ext2", fmt, ##__VA_ARGS__)
15 # define ext2_debug(fmt, ...)
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
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
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
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)
47 extern bcache_zone_t gdesc_bcache_zone;
55 u32_t s_first_data_cnt;
75 u32_t s_checkinterval;
88 u32_t s_optional_feat;
89 u32_t s_required_feat;
105 u16_t bg_free_blk_cnt;
106 u16_t bg_free_ino_cnt;
107 u16_t bg_used_dir_cnt;
135 u32_t directs[12]; // directum
138 u32_t ind1; // prima indirecta
139 u32_t ind23[2]; // secunda et tertia indirecta
143 } ext2_aligned i_block;
144 u32_t i_block_arr[15];
166 #define EXT2_DRE(v_dnode) (fsapi_impl_data(v_dnode, struct ext2b_dirent))
169 #define GDESC_INO_SEL 0
170 #define GDESC_BLK_SEL 1
172 #define GDESC_FREE_LISTS \
175 struct llist_header free_grps_ino; \
176 struct llist_header free_grps_blk; \
178 struct llist_header free_list_sel[2]; \
181 #define check_gdesc_type_sel(sel) \
182 assert_msg(sel == GDESC_INO_SEL || sel == GDESC_BLK_SEL, \
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
195 unsigned int block_size;
196 unsigned int nr_gdesc_pb;
197 unsigned int nr_gdesc;
198 unsigned int all_feature;
201 struct v_superblock* vsb;
203 struct ext2b_super* raw;
205 struct bcache gd_caches;
210 struct llist_header gds;
216 #define EXT2_SB(vsb) (fsapi_impl_data(vsb, struct ext2_sbinfo))
223 unsigned int nr_bytes;
229 struct llist_header groups;
234 struct ext2_bmp ino_bmp;
235 struct ext2_bmp blk_bmp;
237 struct ext2_bmp bmps[2];
241 unsigned int ino_base;
243 struct ext2b_gdesc* info;
244 struct ext2_sbinfo* sb;
252 Indriection Block Translation Look-aside Buffer
254 Provide a look-aside buffer for all last-level indirect block
255 that is at least two indirection away.
258 16 sets, 256 ways, capacity 4096 blocks
261 struct ext2_btlb_entry
270 struct ext2_btlb_entry buffer[BTLB_SETS];
273 struct ext2_fast_inode
275 struct ext2b_inode* ino;
281 bbuf_t buf; // partial inotab that holds this inode
282 unsigned int inds_lgents; // log2(# of block in an indirection level)
288 struct ext2b_inode* ino; // raw ext2 inode
289 struct ext2_btlb* btlb; // block-TLB
290 struct ext2_gdesc* blk_grp; // block group
296 dirent fragmentation degree, we will perform
297 full reconstruction on dirent table when this goes too high.
299 unsigned int dir_fragdeg;
303 // prefetched block for 1st order of indirection
307 // No lock required, it shares lock context with v_inode.
309 #define EXT2_INO(v_inode) (fsapi_impl_data(v_inode, struct ext2_inode))
311 struct ext2_dnode_sub
314 struct ext2b_dirent* dirent;
319 struct ext2_dnode_sub self;
320 struct ext2_dnode_sub prev;
322 // No lock required, it shares lock context with v_dnode.
324 #define EXT2_DNO(v_dnode) (fsapi_impl_data(v_dnode, struct ext2_dnode))
328 * @brief General purpose iterator for ext2 objects
333 struct v_inode* inode;
336 struct ext2b_dirent* dirent;
355 struct ext2_iterator iter;
357 #define EXT2_FILE(v_file) (fsapi_impl_data(v_file, struct ext2_file))
360 #define MAX_INDS_DEPTH 4
364 unsigned int tables[MAX_INDS_DEPTH];
365 unsigned int indices[MAX_INDS_DEPTH];
370 unsigned int* slot_ref;
375 struct walk_stack stack;
378 static inline unsigned int
379 ext2_datablock(struct v_superblock* vsb, unsigned int id)
381 return EXT2_SB(vsb)->raw->s_first_data_cnt + id;
385 ext2_feature(struct v_superblock* vsb, unsigned int feat)
387 return !!(EXT2_SB(vsb)->all_feature & feat);
390 /* ************ Superblock ************ */
393 ext2sb_schedule_sync(struct ext2_sbinfo* sb)
395 fsblock_dirty(sb->buf);
398 static inline void must_inline
399 ext2sb_lock(struct ext2_sbinfo* sb)
401 mutex_lock(&sb->lock);
404 static inline void must_inline
405 ext2sb_unlock(struct ext2_sbinfo* sb)
407 mutex_unlock(&sb->lock);
411 /* ************ Inodes ************ */
414 ext2ino_init(struct v_superblock* vsb, struct v_inode* inode);
417 ext2ino_get(struct v_superblock* vsb,
418 unsigned int ino, struct ext2_inode** out);
421 ext2ino_get_fast(struct v_superblock* vsb,
422 unsigned int ino, struct ext2_fast_inode* fast_ino);
425 ext2ino_fill(struct v_inode* inode, ino_t ino_id);
428 ext2ino_make(struct v_superblock* vsb, unsigned int itype,
429 struct ext2_inode* hint, struct v_inode** out);
432 ext2ino_update(struct v_inode* inode);
435 ext2ino_resizing(struct v_inode* inode, size_t new_size);
438 ext2ino_linkto(struct ext2_inode* e_ino, struct ext2b_dirent* dirent)
440 dirent->inode = e_ino->ino_id;
441 e_ino->ino->i_lnk_cnt++;
442 fsblock_dirty(e_ino->buf);
446 ext2ino_schedule_sync(struct ext2_inode* ino)
448 fsblock_dirty(ino->buf);
452 /* ************* Data blocks ************* */
454 #define DBIT_MODE_ISIZE 0
455 #define DBIT_MODE_BLOCK 1
458 ext2db_itbegin(struct ext2_iterator* iter, struct v_inode* inode, int mode);
461 ext2db_itend(struct ext2_iterator* iter);
464 ext2db_itnext(struct ext2_iterator* iter);
467 ext2db_itffw(struct ext2_iterator* iter, int count);
470 ext2db_itreset(struct ext2_iterator* iter);
474 * @brief Get the data block at given data pos associated with the
475 * inode, return NULL if not present
482 ext2db_get(struct v_inode* inode, unsigned int data_pos);
485 * @brief Get the data block at given data pos associated with the
486 * inode, allocate one if not present.
494 ext2db_acquire(struct v_inode* inode, unsigned int data_pos, bbuf_t* out);
497 ext2db_free_pos(struct v_inode* inode, unsigned int block_pos);
499 /* ************* Walker ************* */
502 ext2walk_init_state(struct walk_state* state)
504 *state = (struct walk_state) { };
508 ext2walk_free_state(struct walk_state* state)
510 fsblock_put(state->table);
513 /* ************* Iterator ************* */
516 ext2_iterror(struct ext2_iterator* iter) {
517 return iter->has_error;
521 ext2_itcheckbuf(struct ext2_iterator* iter) {
522 return !(iter->has_error = blkbuf_errbuf(iter->sel_buf));
525 #define itstate_sel(iter, value) \
526 (ext2_iterror(iter) ? EIO : (int)(value))
529 /* ************ Block Group ************ */
532 ext2gd_prepare_gdt(struct v_superblock* vsb);
535 ext2gd_release_gdt(struct v_superblock* vsb);
538 ext2gd_take_at(struct v_superblock* vsb,
539 unsigned int index, struct ext2_gdesc** out);
541 static inline struct ext2_gdesc*
542 ext2gd_take(struct ext2_gdesc* gd) {
543 bcache_refonce(gd->cache_ref);
549 ext2gd_put(struct ext2_gdesc* gd) {
550 bcache_return(gd->cache_ref);
553 static inline void must_inline
554 ext2gd_lock(struct ext2_gdesc* gd)
556 mutex_lock(&gd->lock);
559 static inline void must_inline
560 ext2gd_unlock(struct ext2_gdesc* gd)
562 mutex_unlock(&gd->lock);
566 /* ************ Directory ************ */
569 ext2dr_lookup(struct v_inode* this, struct v_dnode* dnode);
572 ext2dr_read(struct v_file *file, struct dir_context *dctx);
575 ext2dr_itbegin(struct ext2_iterator* iter, struct v_inode* inode);
578 ext2dr_itend(struct ext2_iterator* iter);
581 ext2dr_itdrain(struct ext2_iterator* iter)
583 return iter->pos > iter->end_pos;
587 ext2dr_itnext(struct ext2_iterator* iter);
590 ext2dr_itffw(struct ext2_iterator* iter, int count);
593 ext2dr_itreset(struct ext2_iterator* iter);
596 ext2dr_open(struct v_inode* this, struct v_file* file);
599 ext2dr_close(struct v_inode* this, struct v_file* file);
602 ext2dr_seek(struct v_file* file, size_t offset);
605 ext2dr_insert(struct v_inode* this, struct ext2b_dirent* dirent,
606 struct ext2_dnode** e_dno_out);
609 ext2dr_remove(struct ext2_dnode* e_dno);
612 ext2_rmdir(struct v_inode* parent, struct v_dnode* dnode);
615 ext2_mkdir(struct v_inode* parent, struct v_dnode* dnode);
618 ext2_rename(struct v_inode* from_inode, struct v_dnode* from_dnode,
619 struct v_dnode* to_dnode);
622 ext2dr_setup_dirent(struct ext2b_dirent* dirent,
623 struct v_inode* inode, struct hstr* name);
626 /* ************ Files ************ */
629 ext2_open_inode(struct v_inode* this, struct v_file* file);
632 ext2_close_inode(struct v_file* file);
635 ext2_sync_inode(struct v_inode* inode);
638 ext2_file_sync(struct v_file* file);
641 ext2_inode_read(struct v_inode *inode, void *buffer, size_t len, size_t fpos);
644 ext2_inode_read_page(struct v_inode *inode, void *buffer, size_t fpos);
647 ext2_inode_write(struct v_inode *inode, void *buffer, size_t len, size_t fpos);
650 ext2_inode_write_page(struct v_inode *inode, void *buffer, size_t fpos);
653 ext2_seek_inode(struct v_file* file, size_t offset);
656 ext2_create(struct v_inode* this, struct v_dnode* dnode, unsigned int itype);
659 ext2_link(struct v_inode* this, struct v_dnode* new_name);
662 ext2_unlink(struct v_inode* this, struct v_dnode* name);
665 ext2_get_symlink(struct v_inode *this, const char **path_out);
668 ext2_set_symlink(struct v_inode *this, const char *target);
670 /* *********** Allocations *********** */
672 #define ALLOC_FAIL -1
675 valid_bmp_slot(int slot)
677 return slot != ALLOC_FAIL;
681 ext2gd_alloc_slot(struct ext2_gdesc* gd, int type_sel);
684 ext2gd_free_slot(struct ext2_gdesc* gd, int type_sel, int slot);
687 ext2gd_alloc_inode(struct ext2_gdesc* gd)
689 return ext2gd_alloc_slot(gd, GDESC_INO_SEL);
693 ext2gd_alloc_block(struct ext2_gdesc* gd)
695 return ext2gd_alloc_slot(gd, GDESC_BLK_SEL);
699 ext2gd_free_inode(struct ext2_gdesc* gd, int slot)
701 ext2gd_free_slot(gd, GDESC_INO_SEL, slot);
705 ext2gd_free_block(struct ext2_gdesc* gd, int slot)
707 ext2gd_free_slot(gd, GDESC_BLK_SEL, slot);
711 ext2gd_schedule_sync(struct ext2_gdesc* gd)
713 fsblock_dirty(gd->buf);
714 fsblock_dirty(gd->ino_bmp.raw);
715 fsblock_dirty(gd->blk_bmp.raw);
719 * @brief Allocate a free inode
722 * @param hint locality hint
727 ext2ino_alloc(struct v_superblock* vsb,
728 struct ext2_inode* hint, struct ext2_inode** out);
731 * @brief Allocate a free data block
733 * @param inode inode where the data block goes, also used as locality hint
737 ext2db_alloc(struct v_inode* inode, bbuf_t* out);
740 * @brief free an inode
743 * @param hint locality hint
748 ext2ino_free(struct v_inode* inode);
751 * @brief Free a data block
753 * @param inode inode where the data block goes, also used as locality hint
757 ext2db_free(struct v_inode* inode, bbuf_t buf);
760 ext2ino_alloc_slot(struct v_superblock* vsb, struct ext2_gdesc** gd_out);
763 ext2db_alloc_slot(struct v_superblock* vsb, struct ext2_gdesc** gd_out);
766 /* *********** Bitmap *********** */
769 ext2bmp_init(struct ext2_bmp* e_bmp, bbuf_t bmp_buf, unsigned int nr_bits);
772 ext2bmp_alloc_nolock(struct ext2_bmp* e_bmp);
775 ext2bmp_free_nolock(struct ext2_bmp* e_bmp, unsigned int pos);
778 ext2bmp_discard_nolock(struct ext2_bmp* e_bmp);
781 ext2bmp_check_free(struct ext2_bmp* e_bmp)
785 return valid_bmp_slot(e_bmp->next_free);
788 #endif /* __LUNAIX_EXT2_H */