FIX: ea_size accounting is not correct after resizing. (2)
[lwext4.git] / lwext4 / ext4_fs.c
1 /*
2  * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
3  *
4  *
5  * HelenOS:
6  * Copyright (c) 2012 Martin Sucha
7  * Copyright (c) 2012 Frantisek Princ
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * - Redistributions of source code must retain the above copyright
15  *   notice, this list of conditions and the following disclaimer.
16  * - Redistributions in binary form must reproduce the above copyright
17  *   notice, this list of conditions and the following disclaimer in the
18  *   documentation and/or other materials provided with the distribution.
19  * - The name of the author may not be used to endorse or promote products
20  *   derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 /** @addtogroup lwext4
34  * @{
35  */
36 /**
37  * @file  ext4_fs.c
38  * @brief More complex filesystem functions.
39  */
40
41 #include "ext4_config.h"
42 #include "ext4_types.h"
43 #include "ext4_fs.h"
44 #include "ext4_errno.h"
45 #include "ext4_blockdev.h"
46 #include "ext4_super.h"
47 #include "ext4_debug.h"
48 #include "ext4_block_group.h"
49 #include "ext4_balloc.h"
50 #include "ext4_bitmap.h"
51 #include "ext4_inode.h"
52 #include "ext4_ialloc.h"
53 #include "ext4_extent.h"
54
55 #include <string.h>
56
57 int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
58 {
59         int r, i;
60         uint16_t tmp;
61         uint32_t bsize;
62         bool read_only = false;
63
64         ext4_assert(fs && bdev);
65
66         fs->bdev = bdev;
67
68         r = ext4_sb_read(fs->bdev, &fs->sb);
69         if (r != EOK)
70                 return r;
71
72         if (!ext4_sb_check(&fs->sb))
73                 return ENOTSUP;
74
75         bsize = ext4_sb_get_block_size(&fs->sb);
76         if (bsize > EXT4_MAX_BLOCK_SIZE)
77                 return ENXIO;
78
79         r = ext4_fs_check_features(fs, &read_only);
80         if (r != EOK)
81                 return r;
82
83         if (read_only)
84                 return ENOTSUP;
85
86         /* Compute limits for indirect block levels */
87         uint32_t blocks_id = bsize / sizeof(uint32_t);
88
89         fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
90         fs->inode_blocks_per_level[0] = 1;
91
92         for (i = 1; i < 4; i++) {
93                 fs->inode_blocks_per_level[i] =
94                     fs->inode_blocks_per_level[i - 1] * blocks_id;
95                 fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
96                                             fs->inode_blocks_per_level[i];
97         }
98
99         /*Validate FS*/
100         tmp = ext4_get16(&fs->sb, state);
101         if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
102                 ext4_dprintf(EXT4_DEBUG_FS, "last umount error\n");
103         }
104
105         /* Mark system as mounted */
106         ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
107         r = ext4_sb_write(fs->bdev, &fs->sb);
108         if (r != EOK)
109                 return r;
110
111         /*Update mount count*/
112         ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
113
114         return r;
115 }
116
117 int ext4_fs_fini(struct ext4_fs *fs)
118 {
119         ext4_assert(fs);
120
121         /*Set superblock state*/
122         ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
123
124         return ext4_sb_write(fs->bdev, &fs->sb);
125 }
126
127 static void ext4_fs_debug_features_incomp(uint32_t features_incompatible)
128 {
129
130         if (features_incompatible & EXT4_FEATURE_INCOMPAT_COMPRESSION) {
131                 ext4_dprintf(EXT4_DEBUG_FS, "compression\n");
132         }
133         if (features_incompatible & EXT4_FEATURE_INCOMPAT_FILETYPE) {
134                 ext4_dprintf(EXT4_DEBUG_FS, "filetype\n");
135         }
136         if (features_incompatible & EXT4_FEATURE_INCOMPAT_RECOVER) {
137                 ext4_dprintf(EXT4_DEBUG_FS, "recover\n");
138         }
139         if (features_incompatible & EXT4_FEATURE_INCOMPAT_JOURNAL_DEV) {
140                 ext4_dprintf(EXT4_DEBUG_FS, "journal_dev\n");
141         }
142         if (features_incompatible & EXT4_FEATURE_INCOMPAT_META_BG) {
143                 ext4_dprintf(EXT4_DEBUG_FS, "meta_bg\n");
144         }
145         if (features_incompatible & EXT4_FEATURE_INCOMPAT_EXTENTS) {
146                 ext4_dprintf(EXT4_DEBUG_FS, "extents\n");
147         }
148         if (features_incompatible & EXT4_FEATURE_INCOMPAT_64BIT) {
149                 ext4_dprintf(EXT4_DEBUG_FS, "64bit\n");
150         }
151         if (features_incompatible & EXT4_FEATURE_INCOMPAT_MMP) {
152                 ext4_dprintf(EXT4_DEBUG_FS, "mnp\n");
153         }
154         if (features_incompatible & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
155                 ext4_dprintf(EXT4_DEBUG_FS, "flex_bg\n");
156         }
157         if (features_incompatible & EXT4_FEATURE_INCOMPAT_EA_INODE) {
158                 ext4_dprintf(EXT4_DEBUG_FS, "ea_inode\n");
159         }
160         if (features_incompatible & EXT4_FEATURE_INCOMPAT_DIRDATA) {
161                 ext4_dprintf(EXT4_DEBUG_FS, "dirdata\n");
162         }
163         if (features_incompatible & EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM) {
164                 ext4_dprintf(EXT4_DEBUG_FS, "meta_csum\n");
165         }
166         if (features_incompatible & EXT4_FEATURE_INCOMPAT_LARGEDIR) {
167                 ext4_dprintf(EXT4_DEBUG_FS, "largedir\n");
168         }
169         if (features_incompatible & EXT4_FEATURE_INCOMPAT_INLINE_DATA) {
170                 ext4_dprintf(EXT4_DEBUG_FS, "inline_data\n");
171         }
172 }
173 static void ext4_fs_debug_features_comp(uint32_t features_compatible)
174 {
175         if (features_compatible & EXT4_FEATURE_COMPAT_DIR_PREALLOC) {
176                 ext4_dprintf(EXT4_DEBUG_FS, " dir_prealloc\n");
177         }
178         if (features_compatible & EXT4_FEATURE_COMPAT_IMAGIC_INODES) {
179                 ext4_dprintf(EXT4_DEBUG_FS, "imagic_inodes\n");
180         }
181         if (features_compatible & EXT4_FEATURE_COMPAT_HAS_JOURNAL) {
182                 ext4_dprintf(EXT4_DEBUG_FS, "has_journal\n");
183         }
184         if (features_compatible & EXT4_FEATURE_COMPAT_EXT_ATTR) {
185                 ext4_dprintf(EXT4_DEBUG_FS, "ext_attr\n");
186         }
187         if (features_compatible & EXT4_FEATURE_COMPAT_RESIZE_INODE) {
188                 ext4_dprintf(EXT4_DEBUG_FS, "resize_inode\n");
189         }
190         if (features_compatible & EXT4_FEATURE_COMPAT_DIR_INDEX) {
191                 ext4_dprintf(EXT4_DEBUG_FS, "dir_index\n");
192         }
193 }
194
195 static void ext4_fs_debug_features_ro(uint32_t features_ro)
196 {
197         if (features_ro & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) {
198                 ext4_dprintf(EXT4_DEBUG_FS, "sparse_super\n");
199         }
200         if (features_ro & EXT4_FEATURE_RO_COMPAT_LARGE_FILE) {
201                 ext4_dprintf(EXT4_DEBUG_FS, "large_file\n");
202         }
203         if (features_ro & EXT4_FEATURE_RO_COMPAT_BTREE_DIR) {
204                 ext4_dprintf(EXT4_DEBUG_FS, "btree_dir\n");
205         }
206         if (features_ro & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) {
207                 ext4_dprintf(EXT4_DEBUG_FS, "huge_file\n");
208         }
209         if (features_ro & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
210                 ext4_dprintf(EXT4_DEBUG_FS, "gtd_csum\n");
211         }
212         if (features_ro & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) {
213                 ext4_dprintf(EXT4_DEBUG_FS, "dir_nlink\n");
214         }
215         if (features_ro & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) {
216                 ext4_dprintf(EXT4_DEBUG_FS, "extra_isize\n");
217         }
218         if (features_ro & EXT4_FEATURE_RO_COMPAT_QUOTA) {
219                 ext4_dprintf(EXT4_DEBUG_FS, "quota\n");
220         }
221         if (features_ro & EXT4_FEATURE_RO_COMPAT_BIGALLOC) {
222                 ext4_dprintf(EXT4_DEBUG_FS, "bigalloc\n");
223         }
224         if (features_ro & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
225                 ext4_dprintf(EXT4_DEBUG_FS, "metadata_csum\n");
226         }
227 }
228
229 int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
230 {
231         ext4_assert(fs && read_only);
232         uint32_t v;
233         if (ext4_get32(&fs->sb, rev_level) == 0) {
234                 *read_only = false;
235                 return EOK;
236         }
237
238         ext4_dprintf(EXT4_DEBUG_FS, "\nSB features_incompatible:\n");
239         ext4_fs_debug_features_incomp(
240             ext4_get32(&fs->sb, features_incompatible));
241
242         ext4_dprintf(EXT4_DEBUG_FS, "\nSB features_compatible:\n");
243         ext4_fs_debug_features_comp(ext4_get32(&fs->sb, features_compatible));
244
245         ext4_dprintf(EXT4_DEBUG_FS, "\nSB features_read_only:\n");
246         ext4_fs_debug_features_ro(ext4_get32(&fs->sb, features_read_only));
247
248         /*Check features_incompatible*/
249         v = (ext4_get32(&fs->sb, features_incompatible) &
250              (~CONFIG_FEATURE_INCOMPAT_SUPP));
251         if (v) {
252                 ext4_dprintf(EXT4_DEBUG_FS, "SB features_incompatible: fail\n");
253                 ext4_fs_debug_features_incomp(v);
254                 return ENOTSUP;
255         }
256
257         /*Check features_read_only*/
258         v = (ext4_get32(&fs->sb, features_read_only) &
259              (~CONFIG_FEATURE_RO_COMPAT_SUPP));
260         if (v) {
261                 ext4_dprintf(
262                     EXT4_DEBUG_FS,
263                     "\nERROR sblock features_read_only . Unsupported:\n");
264                 ext4_fs_debug_features_incomp(v);
265
266                 *read_only = true;
267                 return EOK;
268         }
269         *read_only = false;
270
271         return EOK;
272 }
273
274 /**@brief Determine whether the block is inside the group.
275  * @param baddr   block address
276  * @param bgid    block group id
277  * @return Error code
278  */
279 static int ext4_block_in_group(struct ext4_sblock *s,
280                                uint32_t baddr,
281                                uint32_t bgid)
282 {
283         uint32_t actual_bgid;
284         actual_bgid = ext4_balloc_get_bgid_of_block(s, baddr);
285         if (actual_bgid == bgid)
286                 return 1;
287         return 0;
288 }
289
290 /**@brief   To avoid calling the atomic setbit hundreds or thousands of times, we only
291  *          need to use it within a single byte (to ensure we get endianness right).
292  *          We can use memset for the rest of the bitmap as there are no other users.
293  */
294 static void ext4_fs_mark_bitmap_end(int start_bit, int end_bit, void *bitmap)
295 {
296         int i;
297
298         if (start_bit >= end_bit)
299                 return;
300
301         for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
302                 ext4_bmap_bit_set(bitmap, i);
303
304         if (i < end_bit)
305                 memset((char *)bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
306 }
307
308 /**@brief Initialize block bitmap in block group.
309  * @param bg_ref Reference to block group
310  * @return Error code
311  */
312 static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
313 {
314         uint32_t i, bit, bit_max;
315         uint32_t group_blocks;
316         uint16_t inode_size = ext4_get16(&bg_ref->fs->sb, inode_size);
317         uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
318         uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
319         uint32_t bitmap_block_addr =
320             ext4_bg_get_block_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
321         uint32_t bitmap_inode_addr =
322             ext4_bg_get_inode_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
323         uint32_t inode_table_addr =
324             ext4_bg_get_inode_table_first_block(bg_ref->block_group,
325                                                 &bg_ref->fs->sb);
326         uint32_t first_group_addr =
327             ext4_balloc_get_block_of_bgid(&bg_ref->fs->sb, bg_ref->index);
328
329         uint32_t dsc_per_block =
330             ext4_sb_get_block_size(&bg_ref->fs->sb) /
331             ext4_sb_get_desc_size(&bg_ref->fs->sb);
332
333         bool flex_bg =
334                 ext4_sb_has_feature_incompatible(&bg_ref->fs->sb,
335                                                  EXT4_FEATURE_INCOMPAT_FLEX_BG);
336
337         uint32_t inode_table_bcnt = inodes_per_group * inode_size / block_size;
338
339         struct ext4_block block_bitmap;
340         int rc =
341             ext4_block_get(bg_ref->fs->bdev, &block_bitmap, bitmap_block_addr);
342         if (rc != EOK)
343                 return rc;
344
345         memset(block_bitmap.data, 0, block_size);
346
347         bit_max = ext4_sb_is_super_in_bg(&bg_ref->fs->sb, bg_ref->index);
348         if (!ext4_sb_has_feature_incompatible(&bg_ref->fs->sb,
349                                               EXT4_FEATURE_INCOMPAT_META_BG) ||
350                         bg_ref->index < ext4_sb_first_meta_bg(&bg_ref->fs->sb) *
351                         dsc_per_block) {
352                 if (bit_max) {
353                         bit_max += ext4_bg_num_gdb(&bg_ref->fs->sb,
354                                                    bg_ref->index);
355                         bit_max +=
356                                 ext4_get16(&bg_ref->fs->sb,
357                                            s_reserved_gdt_blocks);
358                 }
359         } else { /* For META_BG_BLOCK_GROUPS */
360                 bit_max += ext4_bg_num_gdb(&bg_ref->fs->sb,
361                                            bg_ref->index);
362         }
363         for (bit = 0; bit < bit_max; bit++)
364                 ext4_bmap_bit_set(block_bitmap.data, bit);
365
366         if (bg_ref->index == ext4_block_group_cnt(&bg_ref->fs->sb) - 1) {
367                 /*
368                  * Even though mke2fs always initialize first and last group
369                  * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
370                  * to make sure we calculate the right free blocks
371                  */
372                 group_blocks = (ext4_sb_get_blocks_cnt(&bg_ref->fs->sb) -
373                                 ext4_get32(&bg_ref->fs->sb, first_data_block) -
374                                 (ext4_get32(&bg_ref->fs->sb, blocks_per_group) *
375                                  (ext4_block_group_cnt(&bg_ref->fs->sb) - 1)));
376         } else {
377                 group_blocks = ext4_get32(&bg_ref->fs->sb, blocks_per_group);
378         }
379         if (!flex_bg ||
380             ext4_block_in_group(&bg_ref->fs->sb,
381                                 bitmap_block_addr, bg_ref->index))
382                 ext4_bmap_bit_set(block_bitmap.data,
383                                   bitmap_block_addr - first_group_addr);
384
385         if (!flex_bg ||
386             ext4_block_in_group(&bg_ref->fs->sb,
387                                 bitmap_inode_addr, bg_ref->index))
388                 ext4_bmap_bit_set(block_bitmap.data,
389                                   bitmap_inode_addr - first_group_addr);
390
391         for (i = inode_table_addr;
392                 i < inode_table_addr + inode_table_bcnt; i++) {
393                 if (!flex_bg ||
394                     ext4_block_in_group(&bg_ref->fs->sb,
395                                         i,
396                                         bg_ref->index))
397                         ext4_bmap_bit_set(block_bitmap.data,
398                                         i - first_group_addr);
399         }
400         /*
401          * Also if the number of blocks within the group is
402          * less than the blocksize * 8 ( which is the size
403          * of bitmap ), set rest of the block bitmap to 1
404          */
405         ext4_fs_mark_bitmap_end(group_blocks, block_size * 8, block_bitmap.data);
406         block_bitmap.dirty = true;
407
408         /* Save bitmap */
409         return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
410 }
411
412 /**@brief Initialize i-node bitmap in block group.
413  * @param bg_ref Reference to block group
414  * @return Error code
415  */
416 static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
417 {
418         /* Load bitmap */
419         uint32_t bitmap_block_addr =
420             ext4_bg_get_inode_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
421
422         struct ext4_block block_bitmap;
423         int rc =
424             ext4_block_get(bg_ref->fs->bdev, &block_bitmap, bitmap_block_addr);
425         if (rc != EOK)
426                 return rc;
427
428         /* Initialize all bitmap bits to zero */
429         uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
430         uint32_t inodes_per_group =
431             ext4_get32(&bg_ref->fs->sb, inodes_per_group);
432
433         memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8);
434
435         uint32_t start_bit = inodes_per_group;
436         uint32_t end_bit = block_size * 8;
437
438         uint32_t i;
439         for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
440                 ext4_bmap_bit_set(block_bitmap.data, i);
441
442         if (i < end_bit)
443                 memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3);
444
445         block_bitmap.dirty = true;
446
447         /* Save bitmap */
448         return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
449 }
450
451 /**@brief Initialize i-node table in block group.
452  * @param bg_ref Reference to block group
453  * @return Error code
454  */
455 static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
456 {
457         struct ext4_sblock *sb = &bg_ref->fs->sb;
458
459         uint32_t inode_size = ext4_get32(sb, inode_size);
460         uint32_t block_size = ext4_sb_get_block_size(sb);
461         uint32_t inodes_per_block = block_size / inode_size;
462         uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
463         uint32_t table_blocks = inodes_in_group / inodes_per_block;
464         uint32_t fblock;
465
466         if (inodes_in_group % inodes_per_block)
467                 table_blocks++;
468
469         /* Compute initialization bounds */
470         uint32_t first_block =
471             ext4_bg_get_inode_table_first_block(bg_ref->block_group, sb);
472
473         uint32_t last_block = first_block + table_blocks - 1;
474
475         /* Initialization of all itable blocks */
476         for (fblock = first_block; fblock <= last_block; ++fblock) {
477
478                 struct ext4_block block;
479                 int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock);
480                 if (rc != EOK)
481                         return rc;
482
483                 memset(block.data, 0, block_size);
484                 block.dirty = true;
485
486                 ext4_block_set(bg_ref->fs->bdev, &block);
487                 if (rc != EOK)
488                         return rc;
489         }
490
491         return EOK;
492 }
493
494 static uint64_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
495                                              uint32_t bgid,
496                                              uint32_t dsc_per_block)
497 {
498         uint32_t first_meta_bg, dsc_id;
499
500         int has_super = 0;
501
502         dsc_id = bgid / dsc_per_block;
503         first_meta_bg = ext4_sb_first_meta_bg(s);
504
505         if (!ext4_sb_has_feature_incompatible(s,
506                                               EXT4_FEATURE_INCOMPAT_META_BG) ||
507             dsc_id < first_meta_bg)
508                 return ext4_get32(s, first_data_block) + dsc_id + 1;
509
510         if (ext4_sb_is_super_in_bg(s, bgid))
511                 has_super = 1;
512
513         return (has_super + ext4_fs_first_bg_block_no(s, bgid));
514 }
515
516 int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
517                                 struct ext4_block_group_ref *ref)
518 {
519         /* Compute number of descriptors, that fits in one data block */
520         uint32_t dsc_per_block =
521             ext4_sb_get_block_size(&fs->sb) / ext4_sb_get_desc_size(&fs->sb);
522
523         /* Block group descriptor table starts at the next block after
524          * superblock */
525         uint64_t block_id =
526             ext4_fs_get_descriptor_block(&fs->sb, bgid, dsc_per_block);
527
528         uint32_t offset =
529             (bgid % dsc_per_block) * ext4_sb_get_desc_size(&fs->sb);
530
531         int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
532         if (rc != EOK)
533                 return rc;
534
535         ref->block_group = (void *)(ref->block.data + offset);
536         ref->fs = fs;
537         ref->index = bgid;
538         ref->dirty = false;
539
540         if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
541                 rc = ext4_fs_init_block_bitmap(ref);
542                 if (rc != EOK) {
543                         ext4_block_set(fs->bdev, &ref->block);
544                         return rc;
545                 }
546                 ext4_bg_clear_flag(ref->block_group,
547                                    EXT4_BLOCK_GROUP_BLOCK_UNINIT);
548
549                 ref->dirty = true;
550         }
551
552         if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_INODE_UNINIT)) {
553                 rc = ext4_fs_init_inode_bitmap(ref);
554                 if (rc != EOK) {
555                         ext4_block_set(ref->fs->bdev, &ref->block);
556                         return rc;
557                 }
558
559                 ext4_bg_clear_flag(ref->block_group,
560                                    EXT4_BLOCK_GROUP_INODE_UNINIT);
561
562                 if (!ext4_bg_has_flag(ref->block_group,
563                                       EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
564                         rc = ext4_fs_init_inode_table(ref);
565                         if (rc != EOK) {
566                                 ext4_block_set(fs->bdev, &ref->block);
567                                 return rc;
568                         }
569
570                         ext4_bg_set_flag(ref->block_group,
571                                          EXT4_BLOCK_GROUP_ITABLE_ZEROED);
572                 }
573
574                 ref->dirty = true;
575         }
576
577         return EOK;
578 }
579
580 /**@brief  Compute checksum of block group descriptor.
581  * @param sb   Superblock
582  * @param bgid Index of block group in the filesystem
583  * @param bg   Block group to compute checksum for
584  * @return Checksum value
585  */
586 static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
587                                     struct ext4_bgroup *bg)
588 {
589         /* If checksum not supported, 0 will be returned */
590         uint16_t crc = 0;
591
592         /* Compute the checksum only if the filesystem supports it */
593         if (ext4_sb_has_feature_read_only(sb,
594                                           EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
595                 uint8_t *base = (uint8_t *)bg;
596                 uint8_t *checksum = (uint8_t *)&bg->checksum;
597
598                 uint32_t offset = (uint32_t)(checksum - base);
599
600                 /* Convert block group index to little endian */
601                 uint32_t le_group = to_le32(bgid);
602
603                 /* Initialization */
604                 crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
605
606                 /* Include index of block group */
607                 crc =
608                     ext4_bg_crc16(crc, (uint8_t *)&le_group, sizeof(le_group));
609
610                 /* Compute crc from the first part (stop before checksum field)
611                  */
612                 crc = ext4_bg_crc16(crc, (uint8_t *)bg, offset);
613
614                 /* Skip checksum */
615                 offset += sizeof(bg->checksum);
616
617                 /* Checksum of the rest of block group descriptor */
618                 if ((ext4_sb_has_feature_incompatible(
619                         sb, EXT4_FEATURE_INCOMPAT_64BIT)) &&
620                     (offset < ext4_sb_get_desc_size(sb)))
621
622                         crc = ext4_bg_crc16(crc, ((uint8_t *)bg) + offset,
623                                             ext4_sb_get_desc_size(sb) - offset);
624         }
625         return crc;
626 }
627
628 int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
629 {
630         /* Check if reference modified */
631         if (ref->dirty) {
632                 /* Compute new checksum of block group */
633                 uint16_t checksum = ext4_fs_bg_checksum(
634                     &ref->fs->sb, ref->index, ref->block_group);
635
636                 ref->block_group->checksum = to_le16(checksum);
637
638                 /* Mark block dirty for writing changes to physical device */
639                 ref->block.dirty = true;
640         }
641
642         /* Put back block, that contains block group descriptor */
643         return ext4_block_set(ref->fs->bdev, &ref->block);
644 }
645
646 int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
647                           struct ext4_inode_ref *ref)
648 {
649         /* Compute number of i-nodes, that fits in one data block */
650         uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
651
652         /*
653          * Inode numbers are 1-based, but it is simpler to work with 0-based
654          * when computing indices
655          */
656         index -= 1;
657         uint32_t block_group = index / inodes_per_group;
658         uint32_t offset_in_group = index % inodes_per_group;
659
660         /* Load block group, where i-node is located */
661         struct ext4_block_group_ref bg_ref;
662
663         int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
664         if (rc != EOK) {
665                 return rc;
666         }
667
668         /* Load block address, where i-node table is located */
669         uint32_t inode_table_start =
670             ext4_bg_get_inode_table_first_block(bg_ref.block_group, &fs->sb);
671
672         /* Put back block group reference (not needed more) */
673         rc = ext4_fs_put_block_group_ref(&bg_ref);
674         if (rc != EOK) {
675                 return rc;
676         }
677
678         /* Compute position of i-node in the block group */
679         uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
680         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
681         uint32_t byte_offset_in_group = offset_in_group * inode_size;
682
683         /* Compute block address */
684         uint64_t block_id =
685             inode_table_start + (byte_offset_in_group / block_size);
686
687         rc = ext4_block_get(fs->bdev, &ref->block, block_id);
688         if (rc != EOK) {
689                 return rc;
690         }
691
692         /* Compute position of i-node in the data block */
693         uint32_t offset_in_block = byte_offset_in_group % block_size;
694         ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
695
696         /* We need to store the original value of index in the reference */
697         ref->index = index + 1;
698         ref->fs = fs;
699         ref->dirty = false;
700
701         return EOK;
702 }
703
704 int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
705 {
706         /* Check if reference modified */
707         if (ref->dirty) {
708                 /* Mark block dirty for writing changes to physical device */
709                 ref->block.dirty = true;
710         }
711
712         /* Put back block, that contains i-node */
713         return ext4_block_set(ref->fs->bdev, &ref->block);
714 }
715
716 void ext4_fs_inode_blocks_init(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref)
717 {
718         int i;
719         struct ext4_inode *inode = inode_ref->inode;
720
721         for (i = 0; i < EXT4_INODE_BLOCKS; i++)
722                 inode->blocks[i] = 0;
723
724 #if CONFIG_EXTENT_ENABLE
725         /* Initialize extents if needed */
726         if (ext4_sb_has_feature_incompatible(&fs->sb,
727                                 EXT4_FEATURE_INCOMPAT_EXTENTS)) {
728                 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
729
730                 /* Initialize extent root header */
731                 struct ext4_extent_header *header = ext4_inode_get_extent_header(inode);
732                 ext4_extent_header_set_depth(header, 0);
733                 ext4_extent_header_set_entries_count(header, 0);
734                 ext4_extent_header_set_generation(header, 0);
735                 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
736
737                 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
738                                 sizeof(struct ext4_extent_header)) /
739                         sizeof(struct ext4_extent);
740
741                 ext4_extent_header_set_max_entries_count(header, max_entries);
742         }
743 #endif
744 }
745
746 static uint32_t ext4_fs_correspond_inode_mode(int filetype)
747 {
748         switch (filetype) {
749         case EXT4_DIRENTRY_DIR:
750                 return EXT4_INODE_MODE_DIRECTORY;
751         case EXT4_DIRENTRY_REG_FILE:
752                 return EXT4_INODE_MODE_FILE;
753         case EXT4_DIRENTRY_SYMLINK:
754                 return EXT4_INODE_MODE_SOFTLINK;
755         default:
756                 /* FIXME: right now we only support 3 file type. */
757                 ext4_assert(0);
758         }
759         return 0;
760 }
761
762 int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
763                         int filetype)
764 {
765         /* Check if newly allocated i-node will be a directory */
766         bool is_dir;
767
768         is_dir = (filetype == EXT4_DIRENTRY_DIR);
769
770         /* Allocate inode by allocation algorithm */
771         uint32_t index;
772         int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
773         if (rc != EOK)
774                 return rc;
775
776         /* Load i-node from on-disk i-node table */
777         rc = ext4_fs_get_inode_ref(fs, index, inode_ref);
778         if (rc != EOK) {
779                 ext4_ialloc_free_inode(fs, index, is_dir);
780                 return rc;
781         }
782
783         /* Initialize i-node */
784         struct ext4_inode *inode = inode_ref->inode;
785
786         uint32_t mode;
787         if (is_dir) {
788                 /*
789                  * Default directory permissions to be compatible with other
790                  * systems
791                  * 0777 (octal) == rwxrwxrwx
792                  */
793
794                 mode = 0777;
795                 mode |= EXT4_INODE_MODE_DIRECTORY;
796         } else {
797                 /*
798                  * Default file permissions to be compatible with other systems
799                  * 0666 (octal) == rw-rw-rw-
800                  */
801
802                 mode = 0666;
803                 mode |= ext4_fs_correspond_inode_mode(filetype);
804         }
805         ext4_inode_set_mode(&fs->sb, inode, mode);
806
807         ext4_inode_set_links_count(inode, 0);
808         ext4_inode_set_uid(inode, 0);
809         ext4_inode_set_gid(inode, 0);
810         ext4_inode_set_size(inode, 0);
811         ext4_inode_set_access_time(inode, 0);
812         ext4_inode_set_change_inode_time(inode, 0);
813         ext4_inode_set_modification_time(inode, 0);
814         ext4_inode_set_deletion_time(inode, 0);
815         ext4_inode_set_blocks_count(&fs->sb, inode, 0);
816         ext4_inode_set_flags(inode, 0);
817         ext4_inode_set_generation(inode, 0);
818
819         /* Reset blocks array. For symbolic link inode, just
820          * fill in blocks with 0 */
821         if (ext4_inode_is_type(&fs->sb, inode, EXT4_INODE_MODE_SOFTLINK)) {
822                 for (int i = 0; i < EXT4_INODE_BLOCKS; i++)
823                         inode->blocks[i] = 0;
824
825         } else
826                 ext4_fs_inode_blocks_init(fs, inode_ref);
827
828         inode_ref->dirty = true;
829
830         return EOK;
831 }
832
833 int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
834 {
835         struct ext4_fs *fs = inode_ref->fs;
836         uint32_t offset;
837         uint32_t suboff;
838         int rc;
839 #if CONFIG_EXTENT_ENABLE
840         /* For extents must be data block destroyed by other way */
841         if ((ext4_sb_has_feature_incompatible(&fs->sb,
842                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
843             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
844                 /* Data structures are released during truncate operation... */
845                 goto finish;
846         }
847 #endif
848         /* Release all indirect (no data) blocks */
849
850         /* 1) Single indirect */
851         uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
852         if (fblock != 0) {
853                 int rc = ext4_balloc_free_block(inode_ref, fblock);
854                 if (rc != EOK)
855                         return rc;
856
857                 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
858         }
859
860         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
861         uint32_t count = block_size / sizeof(uint32_t);
862
863         struct ext4_block block;
864
865         /* 2) Double indirect */
866         fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
867         if (fblock != 0) {
868                 int rc = ext4_block_get(fs->bdev, &block, fblock);
869                 if (rc != EOK)
870                         return rc;
871
872                 uint32_t ind_block;
873                 for (offset = 0; offset < count; ++offset) {
874                         ind_block = to_le32(((uint32_t *)block.data)[offset]);
875
876                         if (ind_block == 0)
877                                 continue;
878                         rc = ext4_balloc_free_block(inode_ref, ind_block);
879                         if (rc != EOK) {
880                                 ext4_block_set(fs->bdev, &block);
881                                 return rc;
882                         }
883
884                 }
885
886                 ext4_block_set(fs->bdev, &block);
887                 rc = ext4_balloc_free_block(inode_ref, fblock);
888                 if (rc != EOK)
889                         return rc;
890
891                 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
892         }
893
894         /* 3) Tripple indirect */
895         struct ext4_block subblock;
896         fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
897         if (fblock == 0)
898                 goto finish;
899         rc = ext4_block_get(fs->bdev, &block, fblock);
900         if (rc != EOK)
901                 return rc;
902
903         uint32_t ind_block;
904         for (offset = 0; offset < count; ++offset) {
905                 ind_block = to_le32(((uint32_t *)block.data)[offset]);
906
907                 if (ind_block == 0)
908                         continue;
909                 rc = ext4_block_get(fs->bdev, &subblock,
910                                 ind_block);
911                 if (rc != EOK) {
912                         ext4_block_set(fs->bdev, &block);
913                         return rc;
914                 }
915
916                 uint32_t ind_subblk;
917                 for (suboff = 0; suboff < count; ++suboff) {
918                         ind_subblk = to_le32(((uint32_t *)subblock.data)[suboff]);
919
920                         if (ind_subblk == 0)
921                                 continue;
922                         rc = ext4_balloc_free_block(inode_ref, ind_subblk);
923                         if (rc != EOK) {
924                                 ext4_block_set(fs->bdev, &subblock);
925                                 ext4_block_set(fs->bdev, &block);
926                                 return rc;
927                         }
928
929                 }
930
931                 ext4_block_set(fs->bdev, &subblock);
932
933                 rc = ext4_balloc_free_block(inode_ref,
934                                 ind_block);
935                 if (rc != EOK) {
936                         ext4_block_set(fs->bdev, &block);
937                         return rc;
938                 }
939
940         }
941
942         ext4_block_set(fs->bdev, &block);
943         rc = ext4_balloc_free_block(inode_ref, fblock);
944         if (rc != EOK)
945                 return rc;
946
947         ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
948 finish:
949         /* Mark inode dirty for writing to the physical device */
950         inode_ref->dirty = true;
951
952         /* Free block with extended attributes if present */
953         uint32_t xattr_block =
954             ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
955         if (xattr_block) {
956                 int rc = ext4_balloc_free_block(inode_ref, xattr_block);
957                 if (rc != EOK)
958                         return rc;
959
960                 ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
961         }
962
963         /* Free inode by allocator */
964         if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
965                                EXT4_INODE_MODE_DIRECTORY))
966                 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
967         else
968                 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
969
970         return rc;
971 }
972
973 int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size)
974 {
975         struct ext4_sblock *sb = &inode_ref->fs->sb;
976         uint32_t i;
977
978         /* Check flags, if i-node can be truncated */
979         if (!ext4_inode_can_truncate(sb, inode_ref->inode))
980                 return EINVAL;
981
982         /* If sizes are equal, nothing has to be done. */
983         uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
984         if (old_size == new_size)
985                 return EOK;
986
987         /* It's not supported to make the larger file by truncate operation */
988         if (old_size < new_size)
989                 return EINVAL;
990
991         if (ext4_inode_is_type(sb, inode_ref->inode, EXT4_INODE_MODE_SOFTLINK)
992                         && old_size < sizeof(inode_ref->inode->blocks)
993                         && !ext4_inode_get_blocks_count(sb, inode_ref->inode)) {
994                 char *content = (char *)inode_ref->inode->blocks;
995                 memset(content + new_size, 0,
996                         sizeof(inode_ref->inode->blocks) - new_size);
997                 ext4_inode_set_size(inode_ref->inode, new_size);
998                 inode_ref->dirty = true;
999
1000                 return EOK;
1001         }
1002
1003         /* Compute how many blocks will be released */
1004         uint32_t block_size = ext4_sb_get_block_size(sb);
1005         uint32_t new_blocks_count = (new_size + block_size - 1) /
1006                                     block_size;
1007         uint32_t old_blocks_count = (old_size + block_size - 1) /
1008                                     block_size;
1009         uint32_t diff_blocks_count = old_blocks_count - new_blocks_count;
1010 #if CONFIG_EXTENT_ENABLE
1011         if ((ext4_sb_has_feature_incompatible(sb,
1012                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1013             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1014
1015                 /* Extents require special operation */
1016                 if (diff_blocks_count) {
1017                         int rc = ext4_extent_release_blocks_from(
1018                                         inode_ref,
1019                                         new_blocks_count);
1020                         if (rc != EOK)
1021                                 return rc;
1022
1023                 }
1024         } else
1025 #endif
1026         {
1027                 /* Release data blocks from the end of file */
1028
1029                 /* Starting from 1 because of logical blocks are numbered from 0
1030                  */
1031                 for (i = 0; i < diff_blocks_count; ++i) {
1032                         int rc = ext4_fs_release_inode_block(
1033                             inode_ref, new_blocks_count + i);
1034                         if (rc != EOK)
1035                                 return rc;
1036                 }
1037         }
1038
1039         /* Update i-node */
1040         ext4_inode_set_size(inode_ref->inode, new_size);
1041         inode_ref->dirty = true;
1042
1043         return EOK;
1044 }
1045
1046 int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
1047                                        uint64_t iblock, uint32_t *fblock)
1048 {
1049         struct ext4_fs *fs = inode_ref->fs;
1050
1051         /* For empty file is situation simple */
1052         if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
1053                 *fblock = 0;
1054                 return EOK;
1055         }
1056
1057         uint32_t current_block;
1058 #if CONFIG_EXTENT_ENABLE
1059         /* Handle i-node using extents */
1060         if ((ext4_sb_has_feature_incompatible(&fs->sb,
1061                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1062             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1063
1064                 int rc =
1065                     ext4_extent_find_block(inode_ref, iblock, &current_block);
1066                 if (rc != EOK)
1067                         return rc;
1068
1069                 *fblock = current_block;
1070                 return EOK;
1071         }
1072 #endif
1073
1074         struct ext4_inode *inode = inode_ref->inode;
1075
1076         /* Direct block are read directly from array in i-node structure */
1077         if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1078                 current_block =
1079                     ext4_inode_get_direct_block(inode, (uint32_t)iblock);
1080                 *fblock = current_block;
1081                 return EOK;
1082         }
1083
1084         /* Determine indirection level of the target block */
1085         unsigned int level = 0;
1086         unsigned int i;
1087         for (i = 1; i < 4; i++) {
1088                 if (iblock < fs->inode_block_limits[i]) {
1089                         level = i;
1090                         break;
1091                 }
1092         }
1093
1094         if (level == 0)
1095                 return EIO;
1096
1097         /* Compute offsets for the topmost level */
1098         uint64_t block_offset_in_level =
1099             iblock - fs->inode_block_limits[level - 1];
1100         current_block = ext4_inode_get_indirect_block(inode, level - 1);
1101         uint32_t offset_in_block =
1102             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1103
1104         /* Sparse file */
1105         if (current_block == 0) {
1106                 *fblock = 0;
1107                 return EOK;
1108         }
1109
1110         struct ext4_block block;
1111
1112         /*
1113          * Navigate through other levels, until we find the block number
1114          * or find null reference meaning we are dealing with sparse file
1115          */
1116         while (level > 0) {
1117                 /* Load indirect block */
1118                 int rc = ext4_block_get(fs->bdev, &block, current_block);
1119                 if (rc != EOK)
1120                         return rc;
1121
1122                 /* Read block address from indirect block */
1123                 current_block =
1124                     to_le32(((uint32_t *)block.data)[offset_in_block]);
1125
1126                 /* Put back indirect block untouched */
1127                 rc = ext4_block_set(fs->bdev, &block);
1128                 if (rc != EOK)
1129                         return rc;
1130
1131                 /* Check for sparse file */
1132                 if (current_block == 0) {
1133                         *fblock = 0;
1134                         return EOK;
1135                 }
1136
1137                 /* Jump to the next level */
1138                 level--;
1139
1140                 /* Termination condition - we have address of data block loaded
1141                  */
1142                 if (level == 0)
1143                         break;
1144
1145                 /* Visit the next level */
1146                 block_offset_in_level %= fs->inode_blocks_per_level[level];
1147                 offset_in_block = block_offset_in_level /
1148                                   fs->inode_blocks_per_level[level - 1];
1149         }
1150
1151         *fblock = current_block;
1152
1153         return EOK;
1154 }
1155
1156 int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
1157                                        uint64_t iblock, uint32_t fblock)
1158 {
1159         struct ext4_fs *fs = inode_ref->fs;
1160
1161 #if CONFIG_EXTENT_ENABLE
1162         /* Handle inode using extents */
1163         if ((ext4_sb_has_feature_incompatible(&fs->sb,
1164                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1165             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1166                 /* Not reachable */
1167                 return ENOTSUP;
1168         }
1169 #endif
1170
1171         /* Handle simple case when we are dealing with direct reference */
1172         if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1173                 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t)iblock,
1174                                             fblock);
1175                 inode_ref->dirty = true;
1176
1177                 return EOK;
1178         }
1179
1180         /* Determine the indirection level needed to get the desired block */
1181         unsigned int level = 0;
1182         unsigned int i;
1183         for (i = 1; i < 4; i++) {
1184                 if (iblock < fs->inode_block_limits[i]) {
1185                         level = i;
1186                         break;
1187                 }
1188         }
1189
1190         if (level == 0)
1191                 return EIO;
1192
1193         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
1194
1195         /* Compute offsets for the topmost level */
1196         uint64_t block_offset_in_level =
1197             iblock - fs->inode_block_limits[level - 1];
1198         uint32_t current_block =
1199             ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
1200         uint32_t offset_in_block =
1201             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1202
1203         uint32_t new_block_addr;
1204
1205         struct ext4_block block;
1206         struct ext4_block new_block;
1207
1208         /* Is needed to allocate indirect block on the i-node level */
1209         if (current_block == 0) {
1210                 /* Allocate new indirect block */
1211                 int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
1212                 if (rc != EOK)
1213                         return rc;
1214
1215                 /* Update i-node */
1216                 ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
1217                                               new_block_addr);
1218                 inode_ref->dirty = true;
1219
1220                 /* Load newly allocated block */
1221                 rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
1222                 if (rc != EOK) {
1223                         ext4_balloc_free_block(inode_ref, new_block_addr);
1224                         return rc;
1225                 }
1226
1227                 /* Initialize new block */
1228                 memset(new_block.data, 0, block_size);
1229                 new_block.dirty = true;
1230
1231                 /* Put back the allocated block */
1232                 rc = ext4_block_set(fs->bdev, &new_block);
1233                 if (rc != EOK)
1234                         return rc;
1235
1236                 current_block = new_block_addr;
1237         }
1238
1239         /*
1240          * Navigate through other levels, until we find the block number
1241          * or find null reference meaning we are dealing with sparse file
1242          */
1243         while (level > 0) {
1244                 int rc = ext4_block_get(fs->bdev, &block, current_block);
1245                 if (rc != EOK)
1246                         return rc;
1247
1248                 current_block =
1249                     to_le32(((uint32_t *)block.data)[offset_in_block]);
1250
1251                 if ((level > 1) && (current_block == 0)) {
1252                         /* Allocate new block */
1253                         rc =
1254                             ext4_balloc_alloc_block(inode_ref, &new_block_addr);
1255                         if (rc != EOK) {
1256                                 ext4_block_set(fs->bdev, &block);
1257                                 return rc;
1258                         }
1259
1260                         /* Load newly allocated block */
1261                         rc = ext4_block_get(fs->bdev, &new_block,
1262                                             new_block_addr);
1263
1264                         if (rc != EOK) {
1265                                 ext4_block_set(fs->bdev, &block);
1266                                 return rc;
1267                         }
1268
1269                         /* Initialize allocated block */
1270                         memset(new_block.data, 0, block_size);
1271                         new_block.dirty = true;
1272
1273                         rc = ext4_block_set(fs->bdev, &new_block);
1274                         if (rc != EOK) {
1275                                 ext4_block_set(fs->bdev, &block);
1276                                 return rc;
1277                         }
1278
1279                         /* Write block address to the parent */
1280                         ((uint32_t *)block.data)[offset_in_block] =
1281                             to_le32(new_block_addr);
1282                         block.dirty = true;
1283                         current_block = new_block_addr;
1284                 }
1285
1286                 /* Will be finished, write the fblock address */
1287                 if (level == 1) {
1288                         ((uint32_t *)block.data)[offset_in_block] =
1289                             to_le32(fblock);
1290                         block.dirty = true;
1291                 }
1292
1293                 rc = ext4_block_set(fs->bdev, &block);
1294                 if (rc != EOK)
1295                         return rc;
1296
1297                 level--;
1298
1299                 /*
1300                  * If we are on the last level, break here as
1301                  * there is no next level to visit
1302                  */
1303                 if (level == 0)
1304                         break;
1305
1306                 /* Visit the next level */
1307                 block_offset_in_level %= fs->inode_blocks_per_level[level];
1308                 offset_in_block = block_offset_in_level /
1309                                   fs->inode_blocks_per_level[level - 1];
1310         }
1311
1312         return EOK;
1313 }
1314
1315 int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
1316                                 uint32_t iblock)
1317 {
1318         uint32_t fblock;
1319
1320         struct ext4_fs *fs = inode_ref->fs;
1321
1322         /* Extents are handled otherwise = there is not support in this function
1323          */
1324         ext4_assert(!(
1325             ext4_sb_has_feature_incompatible(&fs->sb,
1326                                              EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1327             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
1328
1329         struct ext4_inode *inode = inode_ref->inode;
1330
1331         /* Handle simple case when we are dealing with direct reference */
1332         if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1333                 fblock = ext4_inode_get_direct_block(inode, iblock);
1334
1335                 /* Sparse file */
1336                 if (fblock == 0)
1337                         return EOK;
1338
1339                 ext4_inode_set_direct_block(inode, iblock, 0);
1340                 return ext4_balloc_free_block(inode_ref, fblock);
1341         }
1342
1343         /* Determine the indirection level needed to get the desired block */
1344         unsigned int level = 0;
1345         unsigned int i;
1346         for (i = 1; i < 4; i++) {
1347                 if (iblock < fs->inode_block_limits[i]) {
1348                         level = i;
1349                         break;
1350                 }
1351         }
1352
1353         if (level == 0)
1354                 return EIO;
1355
1356         /* Compute offsets for the topmost level */
1357         uint64_t block_offset_in_level =
1358             iblock - fs->inode_block_limits[level - 1];
1359         uint32_t current_block =
1360             ext4_inode_get_indirect_block(inode, level - 1);
1361         uint32_t offset_in_block =
1362             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1363
1364         /*
1365          * Navigate through other levels, until we find the block number
1366          * or find null reference meaning we are dealing with sparse file
1367          */
1368         struct ext4_block block;
1369
1370         while (level > 0) {
1371
1372                 /* Sparse check */
1373                 if (current_block == 0)
1374                         return EOK;
1375
1376                 int rc = ext4_block_get(fs->bdev, &block, current_block);
1377                 if (rc != EOK)
1378                         return rc;
1379
1380                 current_block =
1381                     to_le32(((uint32_t *)block.data)[offset_in_block]);
1382
1383                 /* Set zero if physical data block address found */
1384                 if (level == 1) {
1385                         ((uint32_t *)block.data)[offset_in_block] = to_le32(0);
1386                         block.dirty = true;
1387                 }
1388
1389                 rc = ext4_block_set(fs->bdev, &block);
1390                 if (rc != EOK)
1391                         return rc;
1392
1393                 level--;
1394
1395                 /*
1396                  * If we are on the last level, break here as
1397                  * there is no next level to visit
1398                  */
1399                 if (level == 0)
1400                         break;
1401
1402                 /* Visit the next level */
1403                 block_offset_in_level %= fs->inode_blocks_per_level[level];
1404                 offset_in_block = block_offset_in_level /
1405                                   fs->inode_blocks_per_level[level - 1];
1406         }
1407
1408         fblock = current_block;
1409         if (fblock == 0)
1410                 return EOK;
1411
1412         /* Physical block is not referenced, it can be released */
1413         return ext4_balloc_free_block(inode_ref, fblock);
1414 }
1415
1416 int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
1417                                uint32_t *fblock, uint32_t *iblock)
1418 {
1419 #if CONFIG_EXTENT_ENABLE
1420         /* Handle extents separately */
1421         if ((ext4_sb_has_feature_incompatible(&inode_ref->fs->sb,
1422                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1423             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1424                 return ext4_extent_append_block(inode_ref, iblock, fblock,
1425                                                 true);
1426         }
1427 #endif
1428         struct ext4_sblock *sb = &inode_ref->fs->sb;
1429
1430         /* Compute next block index and allocate data block */
1431         uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1432         uint32_t block_size = ext4_sb_get_block_size(sb);
1433
1434         /* Align size i-node size */
1435         if ((inode_size % block_size) != 0)
1436                 inode_size += block_size - (inode_size % block_size);
1437
1438         /* Logical blocks are numbered from 0 */
1439         uint32_t new_block_idx = inode_size / block_size;
1440
1441         /* Allocate new physical block */
1442         uint32_t phys_block;
1443         int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
1444         if (rc != EOK)
1445                 return rc;
1446
1447         /* Add physical block address to the i-node */
1448         rc = ext4_fs_set_inode_data_block_index(inode_ref, new_block_idx,
1449                                                 phys_block);
1450         if (rc != EOK) {
1451                 ext4_balloc_free_block(inode_ref, phys_block);
1452                 return rc;
1453         }
1454
1455         /* Update i-node */
1456         ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1457         inode_ref->dirty = true;
1458
1459         *fblock = phys_block;
1460         *iblock = new_block_idx;
1461
1462         return EOK;
1463 }
1464
1465 void ext4_fs_inode_links_count_inc(struct ext4_inode_ref *inode_ref)
1466 {
1467         uint16_t link;
1468
1469         link = ext4_inode_get_links_count(inode_ref->inode);
1470         link++;
1471         ext4_inode_set_links_count(inode_ref->inode, link);
1472
1473         bool is_dx =
1474             ext4_sb_has_feature_compatible(&inode_ref->fs->sb,
1475                                            EXT4_FEATURE_COMPAT_DIR_INDEX) &&
1476             ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_INDEX);
1477
1478         if (is_dx && link > 1) {
1479                 if (link >= EXT4_LINK_MAX || link == 2) {
1480                         ext4_inode_set_links_count(inode_ref->inode, 1);
1481
1482                         uint32_t v =
1483                             ext4_get32(&inode_ref->fs->sb, features_read_only);
1484                         v |= EXT4_FEATURE_RO_COMPAT_DIR_NLINK;
1485                         ext4_set32(&inode_ref->fs->sb, features_read_only, v);
1486                 }
1487         }
1488 }
1489
1490 void ext4_fs_inode_links_count_dec(struct ext4_inode_ref *inode_ref)
1491 {
1492         uint16_t links = ext4_inode_get_links_count(inode_ref->inode);
1493         if (!ext4_inode_is_type(&inode_ref->fs->sb, inode_ref->inode,
1494                                 EXT4_INODE_MODE_DIRECTORY)) {
1495                 if (links > 0)
1496                         ext4_inode_set_links_count(inode_ref->inode, links - 1);
1497                 return;
1498         }
1499
1500         if (links > 2)
1501                 ext4_inode_set_links_count(inode_ref->inode, links - 1);
1502 }
1503
1504 /**
1505  * @}
1506  */