1 #include <lunaix/fs/api.h>
2 #include <lunaix/block.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/mm/page.h>
5 #include <lunaix/syslog.h>
11 #define EXT2_COMPRESSION 0x0001
12 #define EXT2_FILETYPE 0x0002
13 #define EXT2_JOURNAL 0x0004
14 #define EXT2_METABG 0x0008
16 #define EXT2_SPARSESB 0x0001
17 #define EXT2_LARGEFLE 0x0002
18 #define EXT2_BTREEDIR 0x0004
20 #define EXT2_SUPER_MAGIC 0xef53
21 #define EXT2_BASE_BLKSZ 1024
22 #define EXT2_PRIME_SB_OFF EXT2_BASE_BLKSZ
24 // current support for incompatible features
25 #define EXT2_IMPL_REQFEAT (EXT2_FILETYPE)
27 // current support for readonly feature
28 #define EXT2_IMPL_ROFEAT (EXT2_SPARSESB)
30 #define EXT2_ROOT_INO to_ext2ino_id(1)
32 #define check_compat_mnt(feat) \
33 (!((feat) & ~EXT2_IMPL_REQFEAT))
35 #define check_compat_mnt_ro_fallback(feat) \
36 (((feat) & ~EXT2_IMPL_ROFEAT))
39 ext2_rd_capacity(struct v_superblock* vsb)
41 struct ext2_sbinfo* sb = fsapi_impl_data(vsb, struct ext2_sbinfo);
42 return sb->raw->s_blk_cnt * fsapi_block_size(vsb);
46 __vsb_release(struct v_superblock* vsb)
48 ext2gd_release_gdt(vsb);
53 ext2_rd_usage(struct v_superblock* vsb)
55 struct ext2_sbinfo* sb = fsapi_impl_data(vsb, struct ext2_sbinfo);
56 size_t used = sb->raw->s_free_blk_cnt - sb->raw->s_blk_cnt;
57 return used * fsapi_block_size(vsb);
60 struct fsapi_vsb_ops vsb_ops = {
61 .read_capacity = ext2_rd_capacity,
62 .read_usage = ext2_rd_usage,
63 .init_inode = ext2ino_init,
64 .release = __vsb_release
67 static inline unsigned int
68 __translate_feature(struct ext2b_super* sb)
70 unsigned int feature = 0;
71 unsigned int req, opt, ro;
73 req = sb->s_required_feat;
74 opt = sb->s_optional_feat;
77 if ((req & EXT2_COMPRESSION)) {
78 feature |= FEAT_COMPRESSION;
81 if ((req & EXT2_FILETYPE)) {
82 feature |= FEAT_FILETYPE;
85 if ((ro & EXT2_SPARSESB)) {
86 feature |= FEAT_SPARSE_SB;
89 if ((ro & EXT2_LARGEFLE)) {
90 feature |= FEAT_LARGE_FILE;
97 __check_mount(struct v_superblock* vsb, struct ext2b_super* sb)
99 unsigned int req, opt, ro;
101 req = sb->s_required_feat;
102 opt = sb->s_optional_feat;
105 if (sb->s_magic != EXT2_SUPER_MAGIC) {
106 ERROR("invalid magic: 0x%x", sb->s_magic);
110 if (!check_compat_mnt(req))
112 ERROR("unsupported feature: 0x%x, mount refused", req);
116 if (check_compat_mnt_ro_fallback(ro))
118 WARN("unsupported feature: 0x%x, mounted as readonly", ro);
119 fsapi_set_readonly_mount(vsb);
122 #ifndef CONFIG_ARCH_BITS_64
123 if ((ro & EXT2_LARGEFLE)) {
124 WARN("large file not supported on 32bits machine");
125 fsapi_set_readonly_mount(vsb);
133 ext2_mount(struct v_superblock* vsb, struct v_dnode* mnt)
136 struct ext2_sbinfo* ext2sb;
137 struct ext2b_super* rawsb;
138 struct v_inode* root_inode;
142 unsigned int req_feat;
144 bdev = fsapi_blockdev(vsb);
145 ext2sb = vzalloc(sizeof(*ext2sb));
146 rawsb = vzalloc(sizeof(*rawsb));
148 errno = bdev->ops.read(bdev, rawsb, EXT2_PRIME_SB_OFF, sizeof(*rawsb));
153 block_size = EXT2_BASE_BLKSZ << rawsb->s_log_blk_size;
154 fsapi_begin_vsb_setup(vsb, block_size);
156 if (!__check_mount(vsb, rawsb)) {
160 if (block_size > PAGE_SIZE) {
161 ERROR("block size must not greater than page size");
167 ext2sb->block_size = block_size;
169 ext2sb->read_only = fsapi_readonly_mount(vsb);
171 ext2sb->all_feature = __translate_feature(rawsb);
173 mutex_init(&ext2sb->lock);
175 fsapi_set_vsb_ops(vsb, &vsb_ops);
176 fsapi_complete_vsb_setup(vsb, ext2sb);
178 ext2gd_prepare_gdt(vsb);
180 root_inode = vfs_i_alloc(vsb);
181 ext2ino_fill(root_inode, EXT2_ROOT_INO);
182 vfs_assign_inode(mnt, root_inode);
184 // replace the superblock raw buffer with bcache managed one
185 buf = fsblock_get(vsb, ext2_datablock(vsb, 0));
186 if (block_size == EXT2_BASE_BLKSZ) {
187 ext2sb->raw = blkbuf_data(buf);
190 ext2sb->raw = offset(blkbuf_data(buf), EXT2_BASE_BLKSZ);
193 ext2sb->raw->s_mnt_cnt++;
194 ext2sb->raw->s_mtime = clock_unixtime();
206 fsapi_reset_vsb(vsb);
211 ext2_umount(struct v_superblock* vsb)
213 // sync all dirty buffers
214 if (!blkbuf_syncall(vsb->blks, false)) {
218 ext2gd_release_gdt(vsb);
220 blkbuf_release(vsb->blks);
227 struct filesystem* fs;
228 fs = fsapi_fs_declare("ext2", 0);
230 fsapi_fs_set_mntops(fs, ext2_mount, ext2_umount);
231 fsapi_fs_finalise(fs);
233 gdesc_bcache_zone = bcache_create_zone("ext2_gdesc");
235 EXPORT_FILE_SYSTEM(ext2fs, ext2_init);