fix dependency check logic cause config always disabled
[lunaix-os.git] / lunaix-os / kernel / fs / ext2 / mount.c
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>
6
7 #include "ext2.h"
8
9 LOG_MODULE("EXT2")
10
11 #define EXT2_COMPRESSION    0x0001
12 #define EXT2_FILETYPE       0x0002
13 #define EXT2_JOURNAL        0x0004
14 #define EXT2_METABG         0x0008
15
16 #define EXT2_SPARSESB       0x0001
17 #define EXT2_LARGEFLE       0x0002
18 #define EXT2_BTREEDIR       0x0004
19
20 #define EXT2_SUPER_MAGIC            0xef53
21 #define EXT2_BASE_BLKSZ             1024
22 #define EXT2_PRIME_SB_OFF           EXT2_BASE_BLKSZ
23
24 // current support for incompatible features
25 #define EXT2_IMPL_REQFEAT           (EXT2_FILETYPE)
26
27 // current support for readonly feature
28 #define EXT2_IMPL_ROFEAT            (EXT2_SPARSESB)
29
30 #define EXT2_ROOT_INO               to_ext2ino_id(1)
31
32 #define check_compat_mnt(feat) \
33         (!((feat) & ~EXT2_IMPL_REQFEAT))
34
35 #define check_compat_mnt_ro_fallback(feat) \
36         (((feat) & ~EXT2_IMPL_ROFEAT))
37
38 static size_t
39 ext2_rd_capacity(struct v_superblock* vsb)
40 {
41     struct ext2_sbinfo* sb = fsapi_impl_data(vsb, struct ext2_sbinfo);
42     return sb->raw->s_blk_cnt * fsapi_block_size(vsb);
43 }
44
45 static void
46 __vsb_release(struct v_superblock* vsb)
47 {
48     ext2gd_release_gdt(vsb);
49     vfree(vsb->data);
50 }
51
52 static size_t
53 ext2_rd_usage(struct v_superblock* vsb)
54 {
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);
58 }
59
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
65 };
66
67 static inline unsigned int
68 __translate_feature(struct ext2b_super* sb)
69 {
70     unsigned int feature = 0;
71     unsigned int req, opt, ro;
72
73     req = sb->s_required_feat;
74     opt = sb->s_optional_feat;
75     ro  = sb->s_ro_feat;
76
77     if ((req & EXT2_COMPRESSION)) {
78         feature |= FEAT_COMPRESSION;
79     }
80
81     if ((req & EXT2_FILETYPE)) {
82         feature |= FEAT_FILETYPE;
83     }
84
85     if ((ro & EXT2_SPARSESB)) {
86         feature |= FEAT_SPARSE_SB;
87     }
88
89     if ((ro & EXT2_LARGEFLE)) {
90         feature |= FEAT_LARGE_FILE;
91     }
92
93     return feature;
94 }
95
96 static bool
97 __check_mount(struct v_superblock* vsb, struct ext2b_super* sb)
98 {
99     unsigned int req, opt, ro;
100
101     req = sb->s_required_feat;
102     opt = sb->s_optional_feat;
103     ro  = sb->s_ro_feat;
104     
105     if (sb->s_magic != EXT2_SUPER_MAGIC) {
106         ERROR("invalid magic: 0x%x", sb->s_magic);
107         return false;
108     }
109
110     if (!check_compat_mnt(req)) 
111     {
112         ERROR("unsupported feature: 0x%x, mount refused", req);
113         return false;
114     }
115
116     if (check_compat_mnt_ro_fallback(ro)) 
117     {
118         WARN("unsupported feature: 0x%x, mounted as readonly", ro);
119         fsapi_set_readonly_mount(vsb);
120     }
121
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);
126     }
127 #endif
128
129     return true;
130 }
131
132 static int 
133 ext2_mount(struct v_superblock* vsb, struct v_dnode* mnt)
134 {
135     struct device* bdev;
136     struct ext2_sbinfo* ext2sb;
137     struct ext2b_super* rawsb;
138     struct v_inode* root_inode;
139     bbuf_t buf;
140     size_t block_size;
141     int errno = 0;
142     unsigned int req_feat;
143
144     bdev = fsapi_blockdev(vsb);
145     ext2sb = vzalloc(sizeof(*ext2sb));
146     rawsb = vzalloc(sizeof(*rawsb));
147
148     errno = bdev->ops.read(bdev, rawsb, EXT2_PRIME_SB_OFF, sizeof(*rawsb));
149     if (errno < 0) {
150         goto failed;
151     }
152
153     block_size = EXT2_BASE_BLKSZ << rawsb->s_log_blk_size;
154     fsapi_begin_vsb_setup(vsb, block_size);
155     
156     if (!__check_mount(vsb, rawsb)) {
157         goto unsupported;
158     }
159
160     if (block_size > PAGE_SIZE) {
161         ERROR("block size must not greater than page size");
162         errno = EINVAL;
163         goto failed;
164     }
165
166     ext2sb->bdev = bdev;
167     ext2sb->block_size = block_size;
168     ext2sb->vsb = vsb;
169     ext2sb->read_only = fsapi_readonly_mount(vsb);
170     ext2sb->raw = rawsb;
171     ext2sb->all_feature = __translate_feature(rawsb);
172
173     mutex_init(&ext2sb->lock);
174
175     fsapi_set_vsb_ops(vsb, &vsb_ops);
176     fsapi_complete_vsb_setup(vsb, ext2sb);
177
178     ext2gd_prepare_gdt(vsb);
179
180     root_inode = vfs_i_alloc(vsb);
181     ext2ino_fill(root_inode, EXT2_ROOT_INO);
182     vfs_assign_inode(mnt, root_inode);
183
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);
188     }
189     else {
190         ext2sb->raw = offset(blkbuf_data(buf), EXT2_BASE_BLKSZ);
191     }
192
193     ext2sb->raw->s_mnt_cnt++;
194     ext2sb->raw->s_mtime = clock_unixtime();
195
196     ext2sb->buf = buf;
197     vfree(rawsb);
198     return 0;
199
200 unsupported:
201     errno = ENOTSUP;
202
203 failed:
204     vfree(ext2sb);
205     vfree(rawsb);
206     fsapi_reset_vsb(vsb);
207     return errno;
208 }
209
210 static int 
211 ext2_umount(struct v_superblock* vsb)
212 {
213     // sync all dirty buffers
214     if (!blkbuf_syncall(vsb->blks, false)) {
215         return EAGAIN;
216     }
217
218     ext2gd_release_gdt(vsb);
219
220     blkbuf_release(vsb->blks);
221     return 0;
222 }
223
224 static void
225 ext2_init()
226 {
227     struct filesystem* fs;
228     fs = fsapi_fs_declare("ext2", 0);
229
230     fsapi_fs_set_mntops(fs, ext2_mount, ext2_umount);
231     fsapi_fs_finalise(fs);
232
233     gdesc_bcache_zone = bcache_create_zone("ext2_gdesc");
234 }
235 EXPORT_FILE_SYSTEM(ext2fs, ext2_init);