ext4_journal: handle EXT4_FINCOM_RECOVER flag properly.
[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_crc32c.h"
48 #include "ext4_debug.h"
49 #include "ext4_block_group.h"
50 #include "ext4_balloc.h"
51 #include "ext4_bitmap.h"
52 #include "ext4_inode.h"
53 #include "ext4_ialloc.h"
54 #include "ext4_extent.h"
55
56 #include <string.h>
57
58 int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
59 {
60         int r, i;
61         uint16_t tmp;
62         uint32_t bsize;
63         bool read_only = false;
64
65         ext4_assert(fs && bdev);
66
67         fs->bdev = bdev;
68
69         r = ext4_sb_read(fs->bdev, &fs->sb);
70         if (r != EOK)
71                 return r;
72
73         if (!ext4_sb_check(&fs->sb))
74                 return ENOTSUP;
75
76         bsize = ext4_sb_get_block_size(&fs->sb);
77         if (bsize > EXT4_MAX_BLOCK_SIZE)
78                 return ENXIO;
79
80         r = ext4_fs_check_features(fs, &read_only);
81         if (r != EOK)
82                 return r;
83
84         if (read_only)
85                 return ENOTSUP;
86
87         /* Compute limits for indirect block levels */
88         uint32_t blocks_id = bsize / sizeof(uint32_t);
89
90         fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
91         fs->inode_blocks_per_level[0] = 1;
92
93         for (i = 1; i < 4; i++) {
94                 fs->inode_blocks_per_level[i] =
95                     fs->inode_blocks_per_level[i - 1] * blocks_id;
96                 fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
97                                             fs->inode_blocks_per_level[i];
98         }
99
100         /*Validate FS*/
101         tmp = ext4_get16(&fs->sb, state);
102         if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS)
103                 ext4_dbg(DEBUG_FS, DBG_WARN
104                                 "last umount error: superblock fs_error flag\n");
105
106
107         /* Mark system as mounted */
108         ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
109         r = ext4_sb_write(fs->bdev, &fs->sb);
110         if (r != EOK)
111                 return r;
112
113         /*Update mount count*/
114         ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
115
116         return r;
117 }
118
119 int ext4_fs_fini(struct ext4_fs *fs)
120 {
121         ext4_assert(fs);
122
123         /*Set superblock state*/
124         ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
125
126         return ext4_sb_write(fs->bdev, &fs->sb);
127 }
128
129 static void ext4_fs_debug_features_inc(uint32_t features_incompatible)
130 {
131         if (features_incompatible & EXT4_FINCOM_COMPRESSION)
132                 ext4_dbg(DEBUG_FS, DBG_NONE "compression\n");
133         if (features_incompatible & EXT4_FINCOM_FILETYPE)
134                 ext4_dbg(DEBUG_FS, DBG_NONE "filetype\n");
135         if (features_incompatible & EXT4_FINCOM_RECOVER)
136                 ext4_dbg(DEBUG_FS, DBG_NONE "recover\n");
137         if (features_incompatible & EXT4_FINCOM_JOURNAL_DEV)
138                 ext4_dbg(DEBUG_FS, DBG_NONE "journal_dev\n");
139         if (features_incompatible & EXT4_FINCOM_META_BG)
140                 ext4_dbg(DEBUG_FS, DBG_NONE "meta_bg\n");
141         if (features_incompatible & EXT4_FINCOM_EXTENTS)
142                 ext4_dbg(DEBUG_FS, DBG_NONE "extents\n");
143         if (features_incompatible & EXT4_FINCOM_64BIT)
144                 ext4_dbg(DEBUG_FS, DBG_NONE "64bit\n");
145         if (features_incompatible & EXT4_FINCOM_MMP)
146                 ext4_dbg(DEBUG_FS, DBG_NONE "mnp\n");
147         if (features_incompatible & EXT4_FINCOM_FLEX_BG)
148                 ext4_dbg(DEBUG_FS, DBG_NONE "flex_bg\n");
149         if (features_incompatible & EXT4_FINCOM_EA_INODE)
150                 ext4_dbg(DEBUG_FS, DBG_NONE "ea_inode\n");
151         if (features_incompatible & EXT4_FINCOM_DIRDATA)
152                 ext4_dbg(DEBUG_FS, DBG_NONE "dirdata\n");
153         if (features_incompatible & EXT4_FINCOM_BG_USE_META_CSUM)
154                 ext4_dbg(DEBUG_FS, DBG_NONE "meta_csum\n");
155         if (features_incompatible & EXT4_FINCOM_LARGEDIR)
156                 ext4_dbg(DEBUG_FS, DBG_NONE "largedir\n");
157         if (features_incompatible & EXT4_FINCOM_INLINE_DATA)
158                 ext4_dbg(DEBUG_FS, DBG_NONE "inline_data\n");
159 }
160 static void ext4_fs_debug_features_comp(uint32_t features_compatible)
161 {
162         if (features_compatible & EXT4_FCOM_DIR_PREALLOC)
163                 ext4_dbg(DEBUG_FS, DBG_NONE "dir_prealloc\n");
164         if (features_compatible & EXT4_FCOM_IMAGIC_INODES)
165                 ext4_dbg(DEBUG_FS, DBG_NONE "imagic_inodes\n");
166         if (features_compatible & EXT4_FCOM_HAS_JOURNAL)
167                 ext4_dbg(DEBUG_FS, DBG_NONE "has_journal\n");
168         if (features_compatible & EXT4_FCOM_EXT_ATTR)
169                 ext4_dbg(DEBUG_FS, DBG_NONE "ext_attr\n");
170         if (features_compatible & EXT4_FCOM_RESIZE_INODE)
171                 ext4_dbg(DEBUG_FS, DBG_NONE "resize_inode\n");
172         if (features_compatible & EXT4_FCOM_DIR_INDEX)
173                 ext4_dbg(DEBUG_FS, DBG_NONE "dir_index\n");
174 }
175
176 static void ext4_fs_debug_features_ro(uint32_t features_ro)
177 {
178         if (features_ro & EXT4_FRO_COM_SPARSE_SUPER)
179                 ext4_dbg(DEBUG_FS, DBG_NONE "sparse_super\n");
180         if (features_ro & EXT4_FRO_COM_LARGE_FILE)
181                 ext4_dbg(DEBUG_FS, DBG_NONE "large_file\n");
182         if (features_ro & EXT4_FRO_COM_BTREE_DIR)
183                 ext4_dbg(DEBUG_FS, DBG_NONE "btree_dir\n");
184         if (features_ro & EXT4_FRO_COM_HUGE_FILE)
185                 ext4_dbg(DEBUG_FS, DBG_NONE "huge_file\n");
186         if (features_ro & EXT4_FRO_COM_GDT_CSUM)
187                 ext4_dbg(DEBUG_FS, DBG_NONE "gtd_csum\n");
188         if (features_ro & EXT4_FRO_COM_DIR_NLINK)
189                 ext4_dbg(DEBUG_FS, DBG_NONE "dir_nlink\n");
190         if (features_ro & EXT4_FRO_COM_EXTRA_ISIZE)
191                 ext4_dbg(DEBUG_FS, DBG_NONE "extra_isize\n");
192         if (features_ro & EXT4_FRO_COM_QUOTA)
193                 ext4_dbg(DEBUG_FS, DBG_NONE "quota\n");
194         if (features_ro & EXT4_FRO_COM_BIGALLOC)
195                 ext4_dbg(DEBUG_FS, DBG_NONE "bigalloc\n");
196         if (features_ro & EXT4_FRO_COM_METADATA_CSUM)
197                 ext4_dbg(DEBUG_FS, DBG_NONE "metadata_csum\n");
198 }
199
200 int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
201 {
202         ext4_assert(fs && read_only);
203         uint32_t v;
204         if (ext4_get32(&fs->sb, rev_level) == 0) {
205                 *read_only = false;
206                 return EOK;
207         }
208
209         ext4_dbg(DEBUG_FS, DBG_INFO "sblock features_incompatible:\n");
210         ext4_fs_debug_features_inc(ext4_get32(&fs->sb, features_incompatible));
211
212         ext4_dbg(DEBUG_FS, DBG_INFO "sblock features_compatible:\n");
213         ext4_fs_debug_features_comp(ext4_get32(&fs->sb, features_compatible));
214
215         ext4_dbg(DEBUG_FS, DBG_INFO "sblock features_read_only:\n");
216         ext4_fs_debug_features_ro(ext4_get32(&fs->sb, features_read_only));
217
218         /*Check features_incompatible*/
219         v = (ext4_get32(&fs->sb, features_incompatible) &
220              (~CONFIG_SUPPORTED_FINCOM));
221         if (v) {
222                 ext4_dbg(DEBUG_FS, DBG_ERROR
223                                 "sblock has unsupported features incompatible:\n");
224                 ext4_fs_debug_features_inc(v);
225                 return ENOTSUP;
226         }
227
228         /*Check features_read_only*/
229         v = ext4_get32(&fs->sb, features_read_only);
230         v &= ~CONFIG_SUPPORTED_FRO_COM;
231         if (v) {
232                 ext4_dbg(DEBUG_FS, DBG_WARN
233                         "sblock has unsupported features read only:\n");
234                 ext4_fs_debug_features_ro(v);
235                 *read_only = true;
236                 return EOK;
237         }
238         *read_only = false;
239
240         return EOK;
241 }
242
243 /**@brief Determine whether the block is inside the group.
244  * @param baddr   block address
245  * @param bgid    block group id
246  * @return Error code
247  */
248 static bool ext4_block_in_group(struct ext4_sblock *s, ext4_fsblk_t baddr,
249                                 uint32_t bgid)
250 {
251         uint32_t actual_bgid;
252         actual_bgid = ext4_balloc_get_bgid_of_block(s, baddr);
253         if (actual_bgid == bgid)
254                 return true;
255         return false;
256 }
257
258 /**@brief   To avoid calling the atomic setbit hundreds or thousands of times, we only
259  *          need to use it within a single byte (to ensure we get endianness right).
260  *          We can use memset for the rest of the bitmap as there are no other users.
261  */
262 static void ext4_fs_mark_bitmap_end(int start_bit, int end_bit, void *bitmap)
263 {
264         int i;
265
266         if (start_bit >= end_bit)
267                 return;
268
269         for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
270                 ext4_bmap_bit_set(bitmap, i);
271
272         if (i < end_bit)
273                 memset((char *)bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
274 }
275
276 /**@brief Initialize block bitmap in block group.
277  * @param bg_ref Reference to block group
278  * @return Error code
279  */
280 static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
281 {
282         struct ext4_sblock *sb = &bg_ref->fs->sb;
283         struct ext4_bgroup *bg = bg_ref->block_group;
284         int rc;
285
286         uint32_t i, bit, bit_max;
287         uint32_t group_blocks;
288         uint16_t inode_size = ext4_get16(sb, inode_size);
289         uint32_t block_size = ext4_sb_get_block_size(sb);
290         uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
291
292         ext4_fsblk_t bmp_blk = ext4_bg_get_block_bitmap(bg, sb);
293         ext4_fsblk_t bmp_inode = ext4_bg_get_inode_bitmap(bg, sb);
294         ext4_fsblk_t inode_table = ext4_bg_get_inode_table_first_block(bg, sb);
295         ext4_fsblk_t first_bg = ext4_balloc_get_block_of_bgid(sb, bg_ref->index);
296
297         uint32_t dsc_per_block =  block_size / ext4_sb_get_desc_size(sb);
298
299         bool flex_bg = ext4_sb_feature_incom(sb, EXT4_FINCOM_FLEX_BG);
300         bool meta_bg = ext4_sb_feature_incom(sb, EXT4_FINCOM_META_BG);
301
302         uint32_t inode_table_bcnt = inodes_per_group * inode_size / block_size;
303
304         struct ext4_block block_bitmap;
305         rc = ext4_block_get_noread(bg_ref->fs->bdev, &block_bitmap, bmp_blk);
306         if (rc != EOK)
307                 return rc;
308
309         memset(block_bitmap.data, 0, block_size);
310         bit_max = ext4_sb_is_super_in_bg(sb, bg_ref->index);
311
312         uint32_t count = ext4_sb_first_meta_bg(sb) * dsc_per_block;
313         if (!meta_bg || bg_ref->index < count) {
314                 if (bit_max) {
315                         bit_max += ext4_bg_num_gdb(sb, bg_ref->index);
316                         bit_max += ext4_get16(sb, s_reserved_gdt_blocks);
317                 }
318         } else { /* For META_BG_BLOCK_GROUPS */
319                 bit_max += ext4_bg_num_gdb(sb, bg_ref->index);
320         }
321         for (bit = 0; bit < bit_max; bit++)
322                 ext4_bmap_bit_set(block_bitmap.data, bit);
323
324         if (bg_ref->index == ext4_block_group_cnt(sb) - 1) {
325                 /*
326                  * Even though mke2fs always initialize first and last group
327                  * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
328                  * to make sure we calculate the right free blocks
329                  */
330
331                 group_blocks = ext4_sb_get_blocks_cnt(sb);
332                 group_blocks -= ext4_get32(sb, first_data_block);
333                 group_blocks -= ext4_get32(sb, blocks_per_group) *
334                                 (ext4_block_group_cnt(sb) - 1);
335         } else {
336                 group_blocks = ext4_get32(sb, blocks_per_group);
337         }
338
339         bool in_bg;
340         in_bg = ext4_block_in_group(sb, bmp_blk, bg_ref->index);
341         if (!flex_bg || in_bg)
342                 ext4_bmap_bit_set(block_bitmap.data, bmp_blk - first_bg);
343
344         in_bg = ext4_block_in_group(sb, bmp_inode, bg_ref->index);
345         if (!flex_bg || in_bg)
346                 ext4_bmap_bit_set(block_bitmap.data, bmp_inode - first_bg);
347
348         for (i = inode_table; i < inode_table + inode_table_bcnt; i++) {
349                 in_bg = ext4_block_in_group(sb, i, bg_ref->index);
350                 if (!flex_bg || in_bg)
351                         ext4_bmap_bit_set(block_bitmap.data, i - first_bg);
352         }
353         /*
354          * Also if the number of blocks within the group is
355          * less than the blocksize * 8 ( which is the size
356          * of bitmap ), set rest of the block bitmap to 1
357          */
358         ext4_fs_mark_bitmap_end(group_blocks, block_size * 8, block_bitmap.data);
359         ext4_bcache_set_dirty(block_bitmap.buf);
360
361         ext4_balloc_set_bitmap_csum(sb, bg_ref->block_group, block_bitmap.data);
362         bg_ref->dirty = true;
363
364         /* Save bitmap */
365         return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
366 }
367
368 /**@brief Initialize i-node bitmap in block group.
369  * @param bg_ref Reference to block group
370  * @return Error code
371  */
372 static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
373 {
374         int rc;
375         struct ext4_sblock *sb = &bg_ref->fs->sb;
376         struct ext4_bgroup *bg = bg_ref->block_group;
377
378         /* Load bitmap */
379         ext4_fsblk_t bitmap_block_addr = ext4_bg_get_inode_bitmap(bg, sb);
380
381         struct ext4_block b;
382         rc = ext4_block_get_noread(bg_ref->fs->bdev, &b, bitmap_block_addr);
383         if (rc != EOK)
384                 return rc;
385
386         /* Initialize all bitmap bits to zero */
387         uint32_t block_size = ext4_sb_get_block_size(sb);
388         uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
389
390         memset(b.data, 0, (inodes_per_group + 7) / 8);
391
392         uint32_t start_bit = inodes_per_group;
393         uint32_t end_bit = block_size * 8;
394
395         uint32_t i;
396         for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
397                 ext4_bmap_bit_set(b.data, i);
398
399         if (i < end_bit)
400                 memset(b.data + (i >> 3), 0xff, (end_bit - i) >> 3);
401
402         ext4_bcache_set_dirty(b.buf);
403
404         ext4_ialloc_set_bitmap_csum(sb, bg, b.data);
405         bg_ref->dirty = true;
406
407         /* Save bitmap */
408         return ext4_block_set(bg_ref->fs->bdev, &b);
409 }
410
411 /**@brief Initialize i-node table in block group.
412  * @param bg_ref Reference to block group
413  * @return Error code
414  */
415 static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
416 {
417         struct ext4_sblock *sb = &bg_ref->fs->sb;
418         struct ext4_bgroup *bg = bg_ref->block_group;
419
420         uint32_t inode_size = ext4_get32(sb, inode_size);
421         uint32_t block_size = ext4_sb_get_block_size(sb);
422         uint32_t inodes_per_block = block_size / inode_size;
423         uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
424         uint32_t table_blocks = inodes_in_group / inodes_per_block;
425         ext4_fsblk_t fblock;
426
427         if (inodes_in_group % inodes_per_block)
428                 table_blocks++;
429
430         /* Compute initialization bounds */
431         ext4_fsblk_t first_block = ext4_bg_get_inode_table_first_block(bg, sb);
432
433         ext4_fsblk_t last_block = first_block + table_blocks - 1;
434
435         /* Initialization of all itable blocks */
436         for (fblock = first_block; fblock <= last_block; ++fblock) {
437                 struct ext4_block b;
438                 int rc = ext4_block_get_noread(bg_ref->fs->bdev, &b, fblock);
439                 if (rc != EOK)
440                         return rc;
441
442                 memset(b.data, 0, block_size);
443                 ext4_bcache_set_dirty(b.buf);
444
445                 ext4_block_set(bg_ref->fs->bdev, &b);
446                 if (rc != EOK)
447                         return rc;
448         }
449
450         return EOK;
451 }
452
453 static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
454                                              uint32_t bgid,
455                                              uint32_t dsc_per_block)
456 {
457         uint32_t first_meta_bg, dsc_id;
458         int has_super = 0;
459         dsc_id = bgid / dsc_per_block;
460         first_meta_bg = ext4_sb_first_meta_bg(s);
461
462         bool meta_bg = ext4_sb_feature_incom(s, EXT4_FINCOM_META_BG);
463
464         if (!meta_bg || dsc_id < first_meta_bg)
465                 return ext4_get32(s, first_data_block) + dsc_id + 1;
466
467         if (ext4_sb_is_super_in_bg(s, bgid))
468                 has_super = 1;
469
470         return (has_super + ext4_fs_first_bg_block_no(s, bgid));
471 }
472
473 /**@brief  Compute checksum of block group descriptor.
474  * @param sb   Superblock
475  * @param bgid Index of block group in the filesystem
476  * @param bg   Block group to compute checksum for
477  * @return Checksum value
478  */
479 static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
480                                     struct ext4_bgroup *bg)
481 {
482         /* If checksum not supported, 0 will be returned */
483         uint16_t crc = 0;
484 #if CONFIG_META_CSUM_ENABLE
485         /* Compute the checksum only if the filesystem supports it */
486         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
487                 /* Use metadata_csum algorithm instead */
488                 uint32_t le32_bgid = to_le32(bgid);
489                 uint32_t orig_checksum, checksum;
490
491                 /* Preparation: temporarily set bg checksum to 0 */
492                 orig_checksum = bg->checksum;
493                 bg->checksum = 0;
494
495                 /* First calculate crc32 checksum against fs uuid */
496                 checksum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid,
497                                 sizeof(sb->uuid));
498                 /* Then calculate crc32 checksum against bgid */
499                 checksum = ext4_crc32c(checksum, &le32_bgid, sizeof(bgid));
500                 /* Finally calculate crc32 checksum against block_group_desc */
501                 checksum = ext4_crc32c(checksum, bg, ext4_sb_get_desc_size(sb));
502                 bg->checksum = orig_checksum;
503
504                 crc = checksum & 0xFFFF;
505                 return crc;
506         }
507 #endif
508         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_GDT_CSUM)) {
509                 uint8_t *base = (uint8_t *)bg;
510                 uint8_t *checksum = (uint8_t *)&bg->checksum;
511
512                 uint32_t offset = (uint32_t)(checksum - base);
513
514                 /* Convert block group index to little endian */
515                 uint32_t group = to_le32(bgid);
516
517                 /* Initialization */
518                 crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
519
520                 /* Include index of block group */
521                 crc = ext4_bg_crc16(crc, (uint8_t *)&group, sizeof(group));
522
523                 /* Compute crc from the first part (stop before checksum field)
524                  */
525                 crc = ext4_bg_crc16(crc, (uint8_t *)bg, offset);
526
527                 /* Skip checksum */
528                 offset += sizeof(bg->checksum);
529
530                 /* Checksum of the rest of block group descriptor */
531                 if ((ext4_sb_feature_incom(sb, EXT4_FINCOM_64BIT)) &&
532                     (offset < ext4_sb_get_desc_size(sb))) {
533
534                         const uint8_t *start = ((uint8_t *)bg) + offset;
535                         size_t len = ext4_sb_get_desc_size(sb) - offset;
536                         crc = ext4_bg_crc16(crc, start, len);
537                 }
538         }
539         return crc;
540 }
541
542 #if CONFIG_META_CSUM_ENABLE
543 static bool ext4_fs_verify_bg_csum(struct ext4_sblock *sb,
544                                    uint32_t bgid,
545                                    struct ext4_bgroup *bg)
546 {
547         if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
548                 return true;
549
550         return ext4_fs_bg_checksum(sb, bgid, bg) == to_le16(bg->checksum);
551 }
552 #else
553 #define ext4_fs_verify_bg_csum(...) true
554 #endif
555
556 int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
557                                 struct ext4_block_group_ref *ref)
558 {
559         /* Compute number of descriptors, that fits in one data block */
560         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
561         uint32_t dsc_cnt = block_size / ext4_sb_get_desc_size(&fs->sb);
562
563         /* Block group descriptor table starts at the next block after
564          * superblock */
565         uint64_t block_id = ext4_fs_get_descriptor_block(&fs->sb, bgid, dsc_cnt);
566
567         uint32_t offset = (bgid % dsc_cnt) * ext4_sb_get_desc_size(&fs->sb);
568
569         int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
570         if (rc != EOK)
571                 return rc;
572
573         ref->block_group = (void *)(ref->block.data + offset);
574         ref->fs = fs;
575         ref->index = bgid;
576         ref->dirty = false;
577         struct ext4_bgroup *bg = ref->block_group;
578
579         if (!ext4_fs_verify_bg_csum(&fs->sb, bgid, bg)) {
580                 ext4_dbg(DEBUG_FS,
581                          DBG_WARN "Block group descriptor checksum failed."
582                          "Block group index: %" PRIu32"\n",
583                          bgid);
584         }
585
586         if (ext4_bg_has_flag(bg, EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
587                 rc = ext4_fs_init_block_bitmap(ref);
588                 if (rc != EOK) {
589                         ext4_block_set(fs->bdev, &ref->block);
590                         return rc;
591                 }
592                 ext4_bg_clear_flag(bg, EXT4_BLOCK_GROUP_BLOCK_UNINIT);
593                 ref->dirty = true;
594         }
595
596         if (ext4_bg_has_flag(bg, EXT4_BLOCK_GROUP_INODE_UNINIT)) {
597                 rc = ext4_fs_init_inode_bitmap(ref);
598                 if (rc != EOK) {
599                         ext4_block_set(ref->fs->bdev, &ref->block);
600                         return rc;
601                 }
602
603                 ext4_bg_clear_flag(bg, EXT4_BLOCK_GROUP_INODE_UNINIT);
604
605                 if (!ext4_bg_has_flag(bg, EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
606                         rc = ext4_fs_init_inode_table(ref);
607                         if (rc != EOK) {
608                                 ext4_block_set(fs->bdev, &ref->block);
609                                 return rc;
610                         }
611
612                         ext4_bg_set_flag(bg, EXT4_BLOCK_GROUP_ITABLE_ZEROED);
613                 }
614
615                 ref->dirty = true;
616         }
617
618         return EOK;
619 }
620
621 int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
622 {
623         /* Check if reference modified */
624         if (ref->dirty) {
625                 /* Compute new checksum of block group */
626                 uint16_t cs;
627                 cs = ext4_fs_bg_checksum(&ref->fs->sb, ref->index,
628                                          ref->block_group);
629                 ref->block_group->checksum = to_le16(cs);
630
631                 /* Mark block dirty for writing changes to physical device */
632                 ext4_bcache_set_dirty(ref->block.buf);
633         }
634
635         /* Put back block, that contains block group descriptor */
636         return ext4_block_set(ref->fs->bdev, &ref->block);
637 }
638
639 #if CONFIG_META_CSUM_ENABLE
640 static uint32_t ext4_fs_inode_checksum(struct ext4_inode_ref *inode_ref)
641 {
642         uint32_t checksum = 0;
643         struct ext4_sblock *sb = &inode_ref->fs->sb;
644         uint16_t inode_size = ext4_get16(sb, inode_size);
645
646         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
647                 uint32_t orig_checksum;
648
649                 uint32_t ino_index = to_le32(inode_ref->index);
650                 uint32_t ino_gen =
651                         to_le32(ext4_inode_get_generation(inode_ref->inode));
652
653                 /* Preparation: temporarily set bg checksum to 0 */
654                 orig_checksum = ext4_inode_get_csum(sb, inode_ref->inode);
655                 ext4_inode_set_csum(sb, inode_ref->inode, 0);
656
657                 /* First calculate crc32 checksum against fs uuid */
658                 checksum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid,
659                                        sizeof(sb->uuid));
660                 /* Then calculate crc32 checksum against inode number
661                  * and inode generation */
662                 checksum = ext4_crc32c(checksum, &ino_index, sizeof(ino_index));
663                 checksum = ext4_crc32c(checksum, &ino_gen, sizeof(ino_gen));
664                 /* Finally calculate crc32 checksum against
665                  * the entire inode */
666                 checksum = ext4_crc32c(checksum, inode_ref->inode, inode_size);
667                 ext4_inode_set_csum(sb, inode_ref->inode, orig_checksum);
668
669                 /* If inode size is not large enough to hold the
670                  * upper 16bit of the checksum */
671                 if (inode_size == EXT4_GOOD_OLD_INODE_SIZE)
672                         checksum &= 0xFFFF;
673
674         }
675         return checksum;
676 }
677 #else
678 #define ext4_fs_inode_checksum(...) 0
679 #endif
680
681 static void ext4_fs_set_inode_checksum(struct ext4_inode_ref *inode_ref)
682 {
683         struct ext4_sblock *sb = &inode_ref->fs->sb;
684         if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
685                 return;
686
687         uint32_t csum = ext4_fs_inode_checksum(inode_ref);
688         ext4_inode_set_csum(sb, inode_ref->inode, csum);
689 }
690
691 #if CONFIG_META_CSUM_ENABLE
692 static bool ext4_fs_verify_inode_csum(struct ext4_inode_ref *inode_ref)
693 {
694         struct ext4_sblock *sb = &inode_ref->fs->sb;
695         if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
696                 return true;
697
698         return ext4_inode_get_csum(sb, inode_ref->inode) ==
699                 ext4_fs_inode_checksum(inode_ref);
700 }
701 #else
702 #define ext4_fs_verify_inode_csum(...) true
703 #endif
704
705 static int
706 __ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
707                         struct ext4_inode_ref *ref,
708                         bool initialized)
709 {
710         /* Compute number of i-nodes, that fits in one data block */
711         uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
712
713         /*
714          * Inode numbers are 1-based, but it is simpler to work with 0-based
715          * when computing indices
716          */
717         index -= 1;
718         uint32_t block_group = index / inodes_per_group;
719         uint32_t offset_in_group = index % inodes_per_group;
720
721         /* Load block group, where i-node is located */
722         struct ext4_block_group_ref bg_ref;
723
724         int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
725         if (rc != EOK) {
726                 return rc;
727         }
728
729         /* Load block address, where i-node table is located */
730         uint32_t inode_table_start =
731             ext4_bg_get_inode_table_first_block(bg_ref.block_group, &fs->sb);
732
733         /* Put back block group reference (not needed more) */
734         rc = ext4_fs_put_block_group_ref(&bg_ref);
735         if (rc != EOK) {
736                 return rc;
737         }
738
739         /* Compute position of i-node in the block group */
740         uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
741         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
742         uint32_t byte_offset_in_group = offset_in_group * inode_size;
743
744         /* Compute block address */
745         ext4_fsblk_t block_id =
746             inode_table_start + (byte_offset_in_group / block_size);
747
748         rc = ext4_block_get(fs->bdev, &ref->block, block_id);
749         if (rc != EOK) {
750                 return rc;
751         }
752
753         /* Compute position of i-node in the data block */
754         uint32_t offset_in_block = byte_offset_in_group % block_size;
755         ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
756
757         /* We need to store the original value of index in the reference */
758         ref->index = index + 1;
759         ref->fs = fs;
760         ref->dirty = false;
761
762         if (initialized && !ext4_fs_verify_inode_csum(ref)) {
763                 ext4_dbg(DEBUG_FS,
764                         DBG_WARN "Inode checksum failed."
765                         "Inode: %" PRIu32"\n",
766                         ref->index);
767         }
768
769         return EOK;
770 }
771
772 int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
773                           struct ext4_inode_ref *ref)
774 {
775         return __ext4_fs_get_inode_ref(fs, index, ref, true);
776 }
777
778 int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
779 {
780         /* Check if reference modified */
781         if (ref->dirty) {
782                 /* Mark block dirty for writing changes to physical device */
783                 ext4_fs_set_inode_checksum(ref);
784                 ext4_bcache_set_dirty(ref->block.buf);
785         }
786
787         /* Put back block, that contains i-node */
788         return ext4_block_set(ref->fs->bdev, &ref->block);
789 }
790
791 void ext4_fs_inode_blocks_init(struct ext4_fs *fs,
792                                struct ext4_inode_ref *inode_ref)
793 {
794         int i;
795         struct ext4_inode *inode = inode_ref->inode;
796
797         for (i = 0; i < EXT4_INODE_BLOCKS; i++)
798                 inode->blocks[i] = 0;
799
800         (void)fs;
801 #if CONFIG_EXTENT_ENABLE
802         /* Initialize extents if needed */
803         if (ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) {
804                 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
805
806                 /* Initialize extent root header */
807                 ext4_extent_tree_init(inode_ref);
808         }
809 #endif
810 }
811
812 uint32_t ext4_fs_correspond_inode_mode(int filetype)
813 {
814         switch (filetype) {
815         case EXT4_DE_DIR:
816                 return EXT4_INODE_MODE_DIRECTORY;
817         case EXT4_DE_REG_FILE:
818                 return EXT4_INODE_MODE_FILE;
819         case EXT4_DE_SYMLINK:
820                 return EXT4_INODE_MODE_SOFTLINK;
821         default:
822                 /* FIXME: right now we only support 3 file type. */
823                 ext4_assert(0);
824         }
825         return 0;
826 }
827
828 int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
829                         int filetype)
830 {
831         /* Check if newly allocated i-node will be a directory */
832         bool is_dir;
833         uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
834
835         is_dir = (filetype == EXT4_DE_DIR);
836
837         /* Allocate inode by allocation algorithm */
838         uint32_t index;
839         int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
840         if (rc != EOK)
841                 return rc;
842
843         /* Load i-node from on-disk i-node table */
844         rc = __ext4_fs_get_inode_ref(fs, index, inode_ref, false);
845         if (rc != EOK) {
846                 ext4_ialloc_free_inode(fs, index, is_dir);
847                 return rc;
848         }
849
850         /* Initialize i-node */
851         struct ext4_inode *inode = inode_ref->inode;
852
853         uint32_t mode;
854         if (is_dir) {
855                 /*
856                  * Default directory permissions to be compatible with other
857                  * systems
858                  * 0777 (octal) == rwxrwxrwx
859                  */
860
861                 mode = 0777;
862                 mode |= EXT4_INODE_MODE_DIRECTORY;
863         } else {
864                 /*
865                  * Default file permissions to be compatible with other systems
866                  * 0666 (octal) == rw-rw-rw-
867                  */
868
869                 mode = 0666;
870                 mode |= ext4_fs_correspond_inode_mode(filetype);
871         }
872         ext4_inode_set_mode(&fs->sb, inode, mode);
873
874         ext4_inode_set_links_cnt(inode, 0);
875         ext4_inode_set_uid(inode, 0);
876         ext4_inode_set_gid(inode, 0);
877         ext4_inode_set_size(inode, 0);
878         ext4_inode_set_access_time(inode, 0);
879         ext4_inode_set_change_inode_time(inode, 0);
880         ext4_inode_set_modif_time(inode, 0);
881         ext4_inode_set_del_time(inode, 0);
882         ext4_inode_set_blocks_count(&fs->sb, inode, 0);
883         ext4_inode_set_flags(inode, 0);
884         ext4_inode_set_generation(inode, 0);
885         if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
886                 uint16_t off = offsetof(struct ext4_inode, extra_isize);
887                 uint16_t size = sizeof(struct ext4_inode) - off;
888                 ext4_inode_set_extra_isize(inode, size);
889         }
890
891         /* Reset blocks array. For symbolic link inode, just
892          * fill in blocks with 0 */
893         if (ext4_inode_is_type(&fs->sb, inode, EXT4_INODE_MODE_SOFTLINK)) {
894                 for (int i = 0; i < EXT4_INODE_BLOCKS; i++)
895                         inode->blocks[i] = 0;
896
897         } else {
898                 ext4_fs_inode_blocks_init(fs, inode_ref);
899         }
900
901         inode_ref->dirty = true;
902
903         return EOK;
904 }
905
906 int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
907 {
908         struct ext4_fs *fs = inode_ref->fs;
909         uint32_t offset;
910         uint32_t suboff;
911         int rc;
912 #if CONFIG_EXTENT_ENABLE
913         /* For extents must be data block destroyed by other way */
914         if ((ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) &&
915             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
916                 /* Data structures are released during truncate operation... */
917                 goto finish;
918         }
919 #endif
920         /* Release all indirect (no data) blocks */
921
922         /* 1) Single indirect */
923         ext4_fsblk_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
924         if (fblock != 0) {
925                 int rc = ext4_balloc_free_block(inode_ref, fblock);
926                 if (rc != EOK)
927                         return rc;
928
929                 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
930         }
931
932         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
933         uint32_t count = block_size / sizeof(uint32_t);
934
935         struct ext4_block block;
936
937         /* 2) Double indirect */
938         fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
939         if (fblock != 0) {
940                 int rc = ext4_block_get(fs->bdev, &block, fblock);
941                 if (rc != EOK)
942                         return rc;
943
944                 ext4_fsblk_t ind_block;
945                 for (offset = 0; offset < count; ++offset) {
946                         ind_block = to_le32(((uint32_t *)block.data)[offset]);
947
948                         if (ind_block == 0)
949                                 continue;
950                         rc = ext4_balloc_free_block(inode_ref, ind_block);
951                         if (rc != EOK) {
952                                 ext4_block_set(fs->bdev, &block);
953                                 return rc;
954                         }
955
956                 }
957
958                 ext4_block_set(fs->bdev, &block);
959                 rc = ext4_balloc_free_block(inode_ref, fblock);
960                 if (rc != EOK)
961                         return rc;
962
963                 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
964         }
965
966         /* 3) Tripple indirect */
967         struct ext4_block subblock;
968         fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
969         if (fblock == 0)
970                 goto finish;
971         rc = ext4_block_get(fs->bdev, &block, fblock);
972         if (rc != EOK)
973                 return rc;
974
975         ext4_fsblk_t ind_block;
976         for (offset = 0; offset < count; ++offset) {
977                 ind_block = to_le32(((uint32_t *)block.data)[offset]);
978
979                 if (ind_block == 0)
980                         continue;
981                 rc = ext4_block_get(fs->bdev, &subblock,
982                                 ind_block);
983                 if (rc != EOK) {
984                         ext4_block_set(fs->bdev, &block);
985                         return rc;
986                 }
987
988                 ext4_fsblk_t ind_subblk;
989                 for (suboff = 0; suboff < count; ++suboff) {
990                         ind_subblk = to_le32(((uint32_t *)subblock.data)[suboff]);
991
992                         if (ind_subblk == 0)
993                                 continue;
994                         rc = ext4_balloc_free_block(inode_ref, ind_subblk);
995                         if (rc != EOK) {
996                                 ext4_block_set(fs->bdev, &subblock);
997                                 ext4_block_set(fs->bdev, &block);
998                                 return rc;
999                         }
1000
1001                 }
1002
1003                 ext4_block_set(fs->bdev, &subblock);
1004
1005                 rc = ext4_balloc_free_block(inode_ref,
1006                                 ind_block);
1007                 if (rc != EOK) {
1008                         ext4_block_set(fs->bdev, &block);
1009                         return rc;
1010                 }
1011
1012         }
1013
1014         ext4_block_set(fs->bdev, &block);
1015         rc = ext4_balloc_free_block(inode_ref, fblock);
1016         if (rc != EOK)
1017                 return rc;
1018
1019         ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
1020 finish:
1021         /* Mark inode dirty for writing to the physical device */
1022         inode_ref->dirty = true;
1023
1024         /* Free block with extended attributes if present */
1025         ext4_fsblk_t xattr_block =
1026             ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
1027         if (xattr_block) {
1028                 int rc = ext4_balloc_free_block(inode_ref, xattr_block);
1029                 if (rc != EOK)
1030                         return rc;
1031
1032                 ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
1033         }
1034
1035         /* Free inode by allocator */
1036         if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
1037                                EXT4_INODE_MODE_DIRECTORY))
1038                 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
1039         else
1040                 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
1041
1042         return rc;
1043 }
1044
1045
1046 /**@brief Release data block from i-node
1047  * @param inode_ref I-node to release block from
1048  * @param iblock    Logical block to be released
1049  * @return Error code
1050  */
1051 static int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
1052                                 uint32_t iblock)
1053 {
1054         ext4_fsblk_t fblock;
1055
1056         struct ext4_fs *fs = inode_ref->fs;
1057
1058         /* Extents are handled otherwise = there is not support in this function
1059          */
1060         ext4_assert(!(
1061             ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS) &&
1062             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
1063
1064         struct ext4_inode *inode = inode_ref->inode;
1065
1066         /* Handle simple case when we are dealing with direct reference */
1067         if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1068                 fblock = ext4_inode_get_direct_block(inode, iblock);
1069
1070                 /* Sparse file */
1071                 if (fblock == 0)
1072                         return EOK;
1073
1074                 ext4_inode_set_direct_block(inode, iblock, 0);
1075                 return ext4_balloc_free_block(inode_ref, fblock);
1076         }
1077
1078         /* Determine the indirection level needed to get the desired block */
1079         unsigned int level = 0;
1080         unsigned int i;
1081         for (i = 1; i < 4; i++) {
1082                 if (iblock < fs->inode_block_limits[i]) {
1083                         level = i;
1084                         break;
1085                 }
1086         }
1087
1088         if (level == 0)
1089                 return EIO;
1090
1091         /* Compute offsets for the topmost level */
1092         uint64_t block_offset_in_level =
1093             iblock - fs->inode_block_limits[level - 1];
1094         ext4_fsblk_t current_block =
1095             ext4_inode_get_indirect_block(inode, level - 1);
1096         uint32_t offset_in_block =
1097             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1098
1099         /*
1100          * Navigate through other levels, until we find the block number
1101          * or find null reference meaning we are dealing with sparse file
1102          */
1103         struct ext4_block block;
1104
1105         while (level > 0) {
1106
1107                 /* Sparse check */
1108                 if (current_block == 0)
1109                         return EOK;
1110
1111                 int rc = ext4_block_get(fs->bdev, &block, current_block);
1112                 if (rc != EOK)
1113                         return rc;
1114
1115                 current_block =
1116                     to_le32(((uint32_t *)block.data)[offset_in_block]);
1117
1118                 /* Set zero if physical data block address found */
1119                 if (level == 1) {
1120                         ((uint32_t *)block.data)[offset_in_block] = to_le32(0);
1121                         ext4_bcache_set_dirty(block.buf);
1122                 }
1123
1124                 rc = ext4_block_set(fs->bdev, &block);
1125                 if (rc != EOK)
1126                         return rc;
1127
1128                 level--;
1129
1130                 /*
1131                  * If we are on the last level, break here as
1132                  * there is no next level to visit
1133                  */
1134                 if (level == 0)
1135                         break;
1136
1137                 /* Visit the next level */
1138                 block_offset_in_level %= fs->inode_blocks_per_level[level];
1139                 offset_in_block = block_offset_in_level /
1140                                   fs->inode_blocks_per_level[level - 1];
1141         }
1142
1143         fblock = current_block;
1144         if (fblock == 0)
1145                 return EOK;
1146
1147         /* Physical block is not referenced, it can be released */
1148         return ext4_balloc_free_block(inode_ref, fblock);
1149 }
1150
1151 int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size)
1152 {
1153         struct ext4_sblock *sb = &inode_ref->fs->sb;
1154         uint32_t i;
1155         int r;
1156
1157         /* Check flags, if i-node can be truncated */
1158         if (!ext4_inode_can_truncate(sb, inode_ref->inode))
1159                 return EINVAL;
1160
1161         /* If sizes are equal, nothing has to be done. */
1162         uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
1163         if (old_size == new_size)
1164                 return EOK;
1165
1166         /* It's not supported to make the larger file by truncate operation */
1167         if (old_size < new_size)
1168                 return EINVAL;
1169
1170         bool v;
1171         v = ext4_inode_is_type(sb, inode_ref->inode, EXT4_INODE_MODE_SOFTLINK);
1172         if (v && old_size < sizeof(inode_ref->inode->blocks) &&
1173             !ext4_inode_get_blocks_count(sb, inode_ref->inode)) {
1174                 char *content = (char *)inode_ref->inode->blocks + new_size;
1175                 memset(content , 0, sizeof(inode_ref->inode->blocks) - new_size);
1176                 ext4_inode_set_size(inode_ref->inode, new_size);
1177                 inode_ref->dirty = true;
1178
1179                 return EOK;
1180         }
1181
1182         /* Compute how many blocks will be released */
1183         uint32_t block_size = ext4_sb_get_block_size(sb);
1184         uint32_t new_blocks_cnt = (new_size + block_size - 1) / block_size;
1185         uint32_t old_blocks_cnt = (old_size + block_size - 1) / block_size;
1186         uint32_t diff_blocks_cnt = old_blocks_cnt - new_blocks_cnt;
1187 #if CONFIG_EXTENT_ENABLE
1188         if ((ext4_sb_feature_incom(sb, EXT4_FINCOM_EXTENTS)) &&
1189             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1190
1191                 /* Extents require special operation */
1192                 if (diff_blocks_cnt) {
1193                         r = ext4_extent_remove_space(inode_ref, new_blocks_cnt,
1194                                                      EXT_MAX_BLOCKS);
1195                         if (r != EOK)
1196                                 return r;
1197
1198                 }
1199         } else
1200 #endif
1201         {
1202                 /* Release data blocks from the end of file */
1203
1204                 /* Starting from 1 because of logical blocks are numbered from 0
1205                  */
1206                 for (i = 0; i < diff_blocks_cnt; ++i) {
1207                         r = ext4_fs_release_inode_block(inode_ref,
1208                                                         new_blocks_cnt + i);
1209                         if (r != EOK)
1210                                 return r;
1211                 }
1212         }
1213
1214         /* Update i-node */
1215         ext4_inode_set_size(inode_ref->inode, new_size);
1216         inode_ref->dirty = true;
1217
1218         return EOK;
1219 }
1220
1221 /**@brief Compute 'goal' for inode index
1222  * @param inode_ref Reference to inode, to allocate block for
1223  * @return goal
1224  */
1225 ext4_fsblk_t ext4_fs_inode_to_goal_block(struct ext4_inode_ref *inode_ref)
1226 {
1227         uint32_t grp_inodes = ext4_get32(&inode_ref->fs->sb, inodes_per_group);
1228         return (inode_ref->index - 1) / grp_inodes;
1229 }
1230
1231 /**@brief Compute 'goal' for allocation algorithm (For blockmap).
1232  * @param inode_ref Reference to inode, to allocate block for
1233  * @param goal
1234  * @return error code
1235  */
1236 int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref,
1237                                ext4_fsblk_t *goal)
1238 {
1239         int r;
1240         struct ext4_sblock *sb = &inode_ref->fs->sb;
1241         *goal = 0;
1242
1243         uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1244         uint32_t block_size = ext4_sb_get_block_size(sb);
1245         uint32_t iblock_cnt = inode_size / block_size;
1246
1247         if (inode_size % block_size != 0)
1248                 iblock_cnt++;
1249
1250         /* If inode has some blocks, get last block address + 1 */
1251         if (iblock_cnt > 0) {
1252                 r = ext4_fs_get_inode_dblk_idx(inode_ref, iblock_cnt - 1,
1253                                                goal, false);
1254                 if (r != EOK)
1255                         return r;
1256
1257                 if (*goal != 0) {
1258                         (*goal)++;
1259                         return r;
1260                 }
1261
1262                 /* If goal == 0, sparse file -> continue */
1263         }
1264
1265         /* Identify block group of inode */
1266
1267         uint32_t inodes_per_bg = ext4_get32(sb, inodes_per_group);
1268         uint32_t block_group = (inode_ref->index - 1) / inodes_per_bg;
1269         block_size = ext4_sb_get_block_size(sb);
1270
1271         /* Load block group reference */
1272         struct ext4_block_group_ref bg_ref;
1273         r = ext4_fs_get_block_group_ref(inode_ref->fs, block_group, &bg_ref);
1274         if (r != EOK)
1275                 return r;
1276
1277         struct ext4_bgroup *bg = bg_ref.block_group;
1278
1279         /* Compute indexes */
1280         uint32_t bg_count = ext4_block_group_cnt(sb);
1281         ext4_fsblk_t itab_first_block = ext4_bg_get_inode_table_first_block(bg, sb);
1282         uint16_t itab_item_size = ext4_get16(sb, inode_size);
1283         uint32_t itab_bytes;
1284
1285         /* Check for last block group */
1286         if (block_group < bg_count - 1) {
1287                 itab_bytes = inodes_per_bg * itab_item_size;
1288         } else {
1289                 /* Last block group could be smaller */
1290                 uint32_t inodes_cnt = ext4_get32(sb, inodes_count);
1291
1292                 itab_bytes = (inodes_cnt - ((bg_count - 1) * inodes_per_bg));
1293                 itab_bytes *= itab_item_size;
1294         }
1295
1296         ext4_fsblk_t inode_table_blocks = itab_bytes / block_size;
1297
1298         if (itab_bytes % block_size)
1299                 inode_table_blocks++;
1300
1301         *goal = itab_first_block + inode_table_blocks;
1302
1303         return ext4_fs_put_block_group_ref(&bg_ref);
1304 }
1305
1306 static int ext4_fs_get_inode_dblk_idx_internal(struct ext4_inode_ref *inode_ref,
1307                                        uint64_t iblock, ext4_fsblk_t *fblock,
1308                                        bool extent_create,
1309                                        bool support_unwritten __unused)
1310 {
1311         struct ext4_fs *fs = inode_ref->fs;
1312
1313         /* For empty file is situation simple */
1314         if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
1315                 *fblock = 0;
1316                 return EOK;
1317         }
1318
1319         ext4_fsblk_t current_block;
1320
1321         (void)extent_create;
1322 #if CONFIG_EXTENT_ENABLE
1323         /* Handle i-node using extents */
1324         if ((ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) &&
1325             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1326
1327                 ext4_fsblk_t current_fsblk;
1328                 int rc = ext4_extent_get_blocks(inode_ref, iblock, 1,
1329                                 &current_fsblk, extent_create, NULL);
1330                 if (rc != EOK)
1331                         return rc;
1332
1333                 current_block = current_fsblk;
1334                 *fblock = current_block;
1335
1336                 ext4_assert(*fblock || support_unwritten);
1337                 return EOK;
1338         }
1339 #endif
1340
1341         struct ext4_inode *inode = inode_ref->inode;
1342
1343         /* Direct block are read directly from array in i-node structure */
1344         if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1345                 current_block =
1346                     ext4_inode_get_direct_block(inode, (uint32_t)iblock);
1347                 *fblock = current_block;
1348                 return EOK;
1349         }
1350
1351         /* Determine indirection level of the target block */
1352         unsigned int l = 0;
1353         unsigned int i;
1354         for (i = 1; i < 4; i++) {
1355                 if (iblock < fs->inode_block_limits[i]) {
1356                         l = i;
1357                         break;
1358                 }
1359         }
1360
1361         if (l == 0)
1362                 return EIO;
1363
1364         /* Compute offsets for the topmost level */
1365         uint64_t blk_off_in_lvl =  iblock - fs->inode_block_limits[l - 1];
1366         current_block = ext4_inode_get_indirect_block(inode, l - 1);
1367         uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
1368
1369         /* Sparse file */
1370         if (current_block == 0) {
1371                 *fblock = 0;
1372                 return EOK;
1373         }
1374
1375         struct ext4_block block;
1376
1377         /*
1378          * Navigate through other levels, until we find the block number
1379          * or find null reference meaning we are dealing with sparse file
1380          */
1381         while (l > 0) {
1382                 /* Load indirect block */
1383                 int rc = ext4_block_get(fs->bdev, &block, current_block);
1384                 if (rc != EOK)
1385                         return rc;
1386
1387                 /* Read block address from indirect block */
1388                 current_block =
1389                     to_le32(((uint32_t *)block.data)[off_in_blk]);
1390
1391                 /* Put back indirect block untouched */
1392                 rc = ext4_block_set(fs->bdev, &block);
1393                 if (rc != EOK)
1394                         return rc;
1395
1396                 /* Check for sparse file */
1397                 if (current_block == 0) {
1398                         *fblock = 0;
1399                         return EOK;
1400                 }
1401
1402                 /* Jump to the next level */
1403                 l--;
1404
1405                 /* Termination condition - we have address of data block loaded
1406                  */
1407                 if (l == 0)
1408                         break;
1409
1410                 /* Visit the next level */
1411                 blk_off_in_lvl %= fs->inode_blocks_per_level[l];
1412                 off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
1413         }
1414
1415         *fblock = current_block;
1416
1417         return EOK;
1418 }
1419
1420
1421 int ext4_fs_get_inode_dblk_idx(struct ext4_inode_ref *inode_ref,
1422                                uint64_t iblock, ext4_fsblk_t *fblock,
1423                                bool support_unwritten)
1424 {
1425         return ext4_fs_get_inode_dblk_idx_internal(inode_ref, iblock, fblock,
1426                                                    false, support_unwritten);
1427 }
1428
1429 int ext4_fs_init_inode_dblk_idx(struct ext4_inode_ref *inode_ref,
1430                                 uint64_t iblock, ext4_fsblk_t *fblock)
1431 {
1432         return ext4_fs_get_inode_dblk_idx_internal(inode_ref, iblock, fblock,
1433                                                    true, true);
1434 }
1435
1436 static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
1437                                        uint64_t iblock, ext4_fsblk_t fblock)
1438 {
1439         struct ext4_fs *fs = inode_ref->fs;
1440
1441 #if CONFIG_EXTENT_ENABLE
1442         /* Handle inode using extents */
1443         if ((ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) &&
1444             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1445                 /* Not reachable */
1446                 return ENOTSUP;
1447         }
1448 #endif
1449
1450         /* Handle simple case when we are dealing with direct reference */
1451         if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1452                 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t)iblock,
1453                                             (uint32_t)fblock);
1454                 inode_ref->dirty = true;
1455
1456                 return EOK;
1457         }
1458
1459         /* Determine the indirection level needed to get the desired block */
1460         unsigned int l = 0;
1461         unsigned int i;
1462         for (i = 1; i < 4; i++) {
1463                 if (iblock < fs->inode_block_limits[i]) {
1464                         l = i;
1465                         break;
1466                 }
1467         }
1468
1469         if (l == 0)
1470                 return EIO;
1471
1472         uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
1473
1474         /* Compute offsets for the topmost level */
1475         uint64_t blk_off_in_lvl =  iblock - fs->inode_block_limits[l - 1];
1476         ext4_fsblk_t current_block =
1477                         ext4_inode_get_indirect_block(inode_ref->inode, l - 1);
1478         uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
1479
1480         ext4_fsblk_t new_blk;
1481
1482         struct ext4_block block;
1483         struct ext4_block new_block;
1484
1485         /* Is needed to allocate indirect block on the i-node level */
1486         if (current_block == 0) {
1487                 /* Allocate new indirect block */
1488                 ext4_fsblk_t goal;
1489                 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
1490                 if (rc != EOK)
1491                         return rc;
1492
1493                 rc = ext4_balloc_alloc_block(inode_ref, goal, &new_blk);
1494                 if (rc != EOK)
1495                         return rc;
1496
1497                 /* Update i-node */
1498                 ext4_inode_set_indirect_block(inode_ref->inode, l - 1, new_blk);
1499                 inode_ref->dirty = true;
1500
1501                 /* Load newly allocated block */
1502                 rc = ext4_block_get_noread(fs->bdev, &new_block, new_blk);
1503                 if (rc != EOK) {
1504                         ext4_balloc_free_block(inode_ref, new_blk);
1505                         return rc;
1506                 }
1507
1508                 /* Initialize new block */
1509                 memset(new_block.data, 0, block_size);
1510                 ext4_bcache_set_dirty(new_block.buf);
1511
1512                 /* Put back the allocated block */
1513                 rc = ext4_block_set(fs->bdev, &new_block);
1514                 if (rc != EOK)
1515                         return rc;
1516
1517                 current_block = new_blk;
1518         }
1519
1520         /*
1521          * Navigate through other levels, until we find the block number
1522          * or find null reference meaning we are dealing with sparse file
1523          */
1524         while (l > 0) {
1525                 int rc = ext4_block_get(fs->bdev, &block, current_block);
1526                 if (rc != EOK)
1527                         return rc;
1528
1529                 current_block = to_le32(((uint32_t *)block.data)[off_in_blk]);
1530                 if ((l > 1) && (current_block == 0)) {
1531                         ext4_fsblk_t goal;
1532                         rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
1533                         if (rc != EOK) {
1534                                 ext4_block_set(fs->bdev, &block);
1535                                 return rc;
1536                         }
1537
1538                         /* Allocate new block */
1539                         rc =
1540                             ext4_balloc_alloc_block(inode_ref, goal, &new_blk);
1541                         if (rc != EOK) {
1542                                 ext4_block_set(fs->bdev, &block);
1543                                 return rc;
1544                         }
1545
1546                         /* Load newly allocated block */
1547                         rc = ext4_block_get_noread(fs->bdev, &new_block,
1548                                             new_blk);
1549
1550                         if (rc != EOK) {
1551                                 ext4_block_set(fs->bdev, &block);
1552                                 return rc;
1553                         }
1554
1555                         /* Initialize allocated block */
1556                         memset(new_block.data, 0, block_size);
1557                         ext4_bcache_set_dirty(new_block.buf);
1558
1559                         rc = ext4_block_set(fs->bdev, &new_block);
1560                         if (rc != EOK) {
1561                                 ext4_block_set(fs->bdev, &block);
1562                                 return rc;
1563                         }
1564
1565                         /* Write block address to the parent */
1566                         uint32_t * p = (uint32_t * )block.data;
1567                         p[off_in_blk] = to_le32((uint32_t)new_blk);
1568                         ext4_bcache_set_dirty(block.buf);
1569                         current_block = new_blk;
1570                 }
1571
1572                 /* Will be finished, write the fblock address */
1573                 if (l == 1) {
1574                         uint32_t * p = (uint32_t * )block.data;
1575                         p[off_in_blk] = to_le32((uint32_t)fblock);
1576                         ext4_bcache_set_dirty(block.buf);
1577                 }
1578
1579                 rc = ext4_block_set(fs->bdev, &block);
1580                 if (rc != EOK)
1581                         return rc;
1582
1583                 l--;
1584
1585                 /*
1586                  * If we are on the last level, break here as
1587                  * there is no next level to visit
1588                  */
1589                 if (l == 0)
1590                         break;
1591
1592                 /* Visit the next level */
1593                 blk_off_in_lvl %= fs->inode_blocks_per_level[l];
1594                 off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
1595         }
1596
1597         return EOK;
1598 }
1599
1600
1601 int ext4_fs_append_inode_dblk(struct ext4_inode_ref *inode_ref,
1602                               ext4_fsblk_t *fblock, uint32_t *iblock)
1603 {
1604 #if CONFIG_EXTENT_ENABLE
1605         /* Handle extents separately */
1606         if ((ext4_sb_feature_incom(&inode_ref->fs->sb, EXT4_FINCOM_EXTENTS)) &&
1607             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1608                 int rc;
1609                 ext4_fsblk_t current_fsblk;
1610                 struct ext4_sblock *sb = &inode_ref->fs->sb;
1611                 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1612                 uint32_t block_size = ext4_sb_get_block_size(sb);
1613                 *iblock = (inode_size + block_size - 1) / block_size;
1614
1615                 rc = ext4_extent_get_blocks(inode_ref, *iblock, 1,
1616                                                 &current_fsblk, true, NULL);
1617
1618                 *fblock = current_fsblk;
1619                 ext4_assert(*fblock);
1620
1621                 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1622                 inode_ref->dirty = true;
1623
1624
1625                 return rc;
1626         }
1627 #endif
1628         struct ext4_sblock *sb = &inode_ref->fs->sb;
1629
1630         /* Compute next block index and allocate data block */
1631         uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1632         uint32_t block_size = ext4_sb_get_block_size(sb);
1633
1634         /* Align size i-node size */
1635         if ((inode_size % block_size) != 0)
1636                 inode_size += block_size - (inode_size % block_size);
1637
1638         /* Logical blocks are numbered from 0 */
1639         uint32_t new_block_idx = inode_size / block_size;
1640
1641         /* Allocate new physical block */
1642         ext4_fsblk_t goal, phys_block;
1643         int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
1644         if (rc != EOK)
1645                 return rc;
1646
1647         rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
1648         if (rc != EOK)
1649                 return rc;
1650
1651         /* Add physical block address to the i-node */
1652         rc = ext4_fs_set_inode_data_block_index(inode_ref, new_block_idx,
1653                                                 phys_block);
1654         if (rc != EOK) {
1655                 ext4_balloc_free_block(inode_ref, phys_block);
1656                 return rc;
1657         }
1658
1659         /* Update i-node */
1660         ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1661         inode_ref->dirty = true;
1662
1663         *fblock = phys_block;
1664         *iblock = new_block_idx;
1665
1666         return EOK;
1667 }
1668
1669 void ext4_fs_inode_links_count_inc(struct ext4_inode_ref *inode_ref)
1670 {
1671         uint16_t link;
1672         bool is_dx;
1673         link = ext4_inode_get_links_cnt(inode_ref->inode);
1674         link++;
1675         ext4_inode_set_links_cnt(inode_ref->inode, link);
1676
1677         is_dx = ext4_sb_feature_com(&inode_ref->fs->sb, EXT4_FCOM_DIR_INDEX) &&
1678                 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_INDEX);
1679
1680         if (is_dx && link > 1) {
1681                 if (link >= EXT4_LINK_MAX || link == 2) {
1682                         ext4_inode_set_links_cnt(inode_ref->inode, 1);
1683
1684                         uint32_t v;
1685                         v = ext4_get32(&inode_ref->fs->sb, features_read_only);
1686                         v |= EXT4_FRO_COM_DIR_NLINK;
1687                         ext4_set32(&inode_ref->fs->sb, features_read_only, v);
1688                 }
1689         }
1690 }
1691
1692 void ext4_fs_inode_links_count_dec(struct ext4_inode_ref *inode_ref)
1693 {
1694         uint16_t links = ext4_inode_get_links_cnt(inode_ref->inode);
1695         if (!ext4_inode_is_type(&inode_ref->fs->sb, inode_ref->inode,
1696                                 EXT4_INODE_MODE_DIRECTORY)) {
1697                 if (links > 0)
1698                         ext4_inode_set_links_cnt(inode_ref->inode, links - 1);
1699                 return;
1700         }
1701
1702         if (links > 2)
1703                 ext4_inode_set_links_cnt(inode_ref->inode, links - 1);
1704 }
1705
1706 /**
1707  * @}
1708  */