1516f6ad32380b23d9fec089a454d6d9ecace7f1
[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 <string.h>
54
55 int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
56 {
57     int r, i;
58     uint16_t tmp;
59     uint32_t bsize;
60     bool read_only = false;
61
62     ext4_assert(fs && bdev);
63
64     fs->bdev = bdev;
65
66     r = ext4_sb_read(fs->bdev, &fs->sb);
67     if(r != EOK)
68         return r;
69
70     if(!ext4_sb_check(&fs->sb))
71         return ENOTSUP;
72
73     bsize = ext4_sb_get_block_size(&fs->sb);
74     if (bsize > EXT4_MAX_BLOCK_SIZE)
75         return ENXIO;
76
77     r = ext4_fs_check_features(fs, &read_only);
78     if(r != EOK)
79         return r;
80
81     if(read_only)
82         return ENOTSUP;
83
84     /* Compute limits for indirect block levels */
85     uint32_t blocks_id = bsize / sizeof(uint32_t);
86
87     fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
88     fs->inode_blocks_per_level[0] = 1;
89
90     for (i = 1; i < 4; i++) {
91         fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] *
92                 blocks_id;
93         fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
94                 fs->inode_blocks_per_level[i];
95     }
96
97     /*Validate FS*/
98     tmp = ext4_get16(&fs->sb, state);
99     if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
100         ext4_dprintf(EXT4_DEBUG_FS,
101                 "Filesystem was not cleanly unmounted before \n");
102     }
103
104     /* Mark system as mounted */
105     ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
106     r = ext4_sb_write(fs->bdev, &fs->sb);
107     if (r != EOK)
108         return r;
109
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
118 int ext4_fs_fini(struct ext4_fs *fs)
119 {
120     ext4_assert(fs);
121
122     /*Set superblock state*/
123     ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
124
125     return ext4_sb_write(fs->bdev, &fs->sb);
126 }
127
128 int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
129 {
130     ext4_assert(fs && read_only);
131
132     if(ext4_get32(&fs->sb, rev_level) == 0){
133         *read_only = false;
134         return EOK;
135     }
136
137     /*Check features_incompatible*/
138     if ((ext4_get32(&fs->sb, features_incompatible) &
139             (~EXT4_FEATURE_INCOMPAT_SUPP)) )
140         return ENOTSUP;
141
142
143     /*Check features_read_only*/
144     if ((ext4_get32(&fs->sb, features_read_only) &
145             (~EXT4_FEATURE_RO_COMPAT_SUPP))){
146         *read_only = true;
147         return EOK;
148     }
149
150     *read_only = false;
151
152     return EOK;
153 }
154
155 uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr)
156 {
157     ext4_assert(baddr);
158     if(ext4_get32(s, first_data_block))
159         baddr--;
160
161     return  baddr % ext4_get32(s, blocks_per_group);
162 }
163
164
165
166 uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
167     uint32_t bgid)
168 {
169     if(ext4_get32(s, first_data_block))
170         index++;
171
172     return ext4_get32(s, blocks_per_group) * bgid + index;
173 }
174
175
176
177
178 static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
179 {
180     uint32_t i;
181     uint32_t bitmap_block_addr = ext4_bg_get_block_bitmap(
182             bg_ref->block_group, &bg_ref->fs->sb);
183
184     struct ext4_block block_bitmap;
185     int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
186             bitmap_block_addr);
187     if (rc != EOK)
188         return rc;
189
190
191     memset(block_bitmap.data, 0, ext4_sb_get_block_size(&bg_ref->fs->sb));
192
193     /* Determine first block and first data block in group */
194     uint32_t first_idx = 0;
195
196     uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
197             &bg_ref->fs->sb, bg_ref);
198     uint32_t first_data_idx = ext4_fs_baddr2_index_in_group(
199             &bg_ref->fs->sb, first_data);
200
201     /*Set bits from to first block to first data block - 1 to one (allocated)*/
202     /*TODO: Optimize it*/
203     for (i = first_idx; i < first_data_idx; ++i)
204         ext4_bmap_bit_set(block_bitmap.data, i);
205
206
207     block_bitmap.dirty = true;
208
209     /* Save bitmap */
210     return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
211 }
212
213 static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
214 {
215     /* Load bitmap */
216     uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
217             bg_ref->block_group, &bg_ref->fs->sb);
218
219     struct ext4_block block_bitmap;
220     int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
221             bitmap_block_addr);
222     if (rc != EOK)
223         return rc;
224
225     /* Initialize all bitmap bits to zero */
226     uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
227     uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
228
229     memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8);
230
231     uint32_t start_bit = inodes_per_group;
232     uint32_t end_bit = block_size * 8;
233
234     uint32_t i;
235     for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
236         ext4_bmap_bit_set(block_bitmap.data, i);
237
238     if (i < end_bit)
239         memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3);
240
241     block_bitmap.dirty = true;
242
243     /* Save bitmap */
244     return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
245 }
246
247 static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
248 {
249     struct ext4_sblock *sb = &bg_ref->fs->sb;
250
251     uint32_t inode_size           = ext4_get32(sb, inode_size);
252     uint32_t block_size           = ext4_sb_get_block_size(sb);
253     uint32_t inodes_per_block = block_size / inode_size;
254     uint32_t inodes_in_group  = ext4_inodes_in_group_cnt(sb, bg_ref->index);
255     uint32_t table_blocks = inodes_in_group / inodes_per_block;
256     uint32_t fblock;
257
258     if (inodes_in_group % inodes_per_block)
259         table_blocks++;
260
261     /* Compute initialization bounds */
262     uint32_t first_block = ext4_bg_get_inode_table_first_block(
263             bg_ref->block_group, sb);
264
265     uint32_t last_block = first_block + table_blocks - 1;
266
267     /* Initialization of all itable blocks */
268     for (fblock = first_block; fblock <= last_block; ++fblock) {
269
270         struct ext4_block block;
271         int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock);
272         if (rc != EOK)
273             return rc;
274
275         memset(block.data, 0, block_size);
276         block.dirty = true;
277
278         ext4_block_set(bg_ref->fs->bdev, &block);
279         if (rc != EOK)
280             return rc;
281     }
282
283     return EOK;
284 }
285
286
287 int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
288     struct ext4_block_group_ref *ref)
289 {
290     /* Compute number of descriptors, that fits in one data block */
291     uint32_t dsc_per_block = ext4_sb_get_block_size(&fs->sb) /
292             ext4_sb_get_desc_size(&fs->sb);
293
294     /* Block group descriptor table starts at the next block after superblock */
295     uint64_t block_id = ext4_get32(&fs->sb, first_data_block) + 1;
296
297     /* Find the block containing the descriptor we are looking for */
298     block_id += bgid / dsc_per_block;
299     uint32_t offset = (bgid % dsc_per_block) *
300             ext4_sb_get_desc_size(&fs->sb);
301
302
303     int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
304     if (rc != EOK)
305         return rc;
306
307     ref->block_group = (void *)(ref->block.data + offset);
308     ref->fs = fs;
309     ref->index = bgid;
310     ref->dirty = false;
311
312     if (ext4_bg_has_flag(ref->block_group,
313             EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
314         rc = ext4_fs_init_block_bitmap(ref);
315         if (rc != EOK) {
316             ext4_block_set(fs->bdev, &ref->block);
317             return rc;
318         }
319         ext4_bg_clear_flag(ref->block_group,
320             EXT4_BLOCK_GROUP_BLOCK_UNINIT);
321
322         ref->dirty = true;
323     }
324
325     if (ext4_bg_has_flag(ref->block_group,
326             EXT4_BLOCK_GROUP_INODE_UNINIT)) {
327         rc = ext4_fs_init_inode_bitmap(ref);
328         if (rc != EOK) {
329             ext4_block_set(ref->fs->bdev, &ref->block);
330             return rc;
331         }
332
333         ext4_bg_clear_flag(ref->block_group,
334             EXT4_BLOCK_GROUP_INODE_UNINIT);
335
336         if (!ext4_bg_has_flag(ref->block_group,
337                 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
338             rc = ext4_fs_init_inode_table(ref);
339             if (rc != EOK){
340                 ext4_block_set(fs->bdev, &ref->block);
341                 return rc;
342             }
343
344             ext4_bg_set_flag(ref->block_group,
345                 EXT4_BLOCK_GROUP_ITABLE_ZEROED);
346         }
347
348         ref->dirty = true;
349     }
350
351     return EOK;
352 }
353
354 static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
355     struct ext4_bgroup *bg)
356 {
357     /* If checksum not supported, 0 will be returned */
358     uint16_t crc = 0;
359
360     /* Compute the checksum only if the filesystem supports it */
361     if (ext4_sb_check_read_only(sb,
362             EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
363         void *base = bg;
364         void *checksum = &bg->checksum;
365
366         uint32_t offset = (uint32_t) (checksum - base);
367
368         /* Convert block group index to little endian */
369         uint32_t le_group = to_le32(bgid);
370
371         /* Initialization */
372         crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
373
374         /* Include index of block group */
375         crc = ext4_bg_crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
376
377         /* Compute crc from the first part (stop before checksum field) */
378         crc = ext4_bg_crc16(crc, (uint8_t *) bg, offset);
379
380         /* Skip checksum */
381         offset += sizeof(bg->checksum);
382
383         /* Checksum of the rest of block group descriptor */
384         if ((ext4_sb_check_feature_incompatible(sb,
385                 EXT4_FEATURE_INCOMPAT_64BIT)) &&
386                 (offset < ext4_sb_get_desc_size(sb)))
387
388             crc = ext4_bg_crc16(crc, ((uint8_t *) bg) + offset,
389                     ext4_sb_get_desc_size(sb) - offset);
390     }
391     return crc;
392 }
393
394 int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
395 {
396     /* Check if reference modified */
397     if (ref->dirty) {
398         /* Compute new checksum of block group */
399         uint16_t checksum =
400                 ext4_fs_bg_checksum(&ref->fs->sb, ref->index,
401                         ref->block_group);
402
403         ref->block_group->checksum = to_le16(checksum);
404
405         /* Mark block dirty for writing changes to physical device */
406         ref->block.dirty = true;
407     }
408
409     /* Put back block, that contains block group descriptor */
410     return ext4_block_set(ref->fs->bdev, &ref->block);
411 }
412
413 int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
414     struct ext4_inode_ref *ref)
415 {
416     /* Compute number of i-nodes, that fits in one data block */
417     uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
418
419     /*
420      * Inode numbers are 1-based, but it is simpler to work with 0-based
421      * when computing indices
422      */
423     index -= 1;
424     uint32_t block_group = index / inodes_per_group;
425     uint32_t offset_in_group = index % inodes_per_group;
426
427     /* Load block group, where i-node is located */
428     struct ext4_block_group_ref bg_ref;
429
430     int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
431     if (rc != EOK) {
432         return rc;
433     }
434
435     /* Load block address, where i-node table is located */
436     uint32_t inode_table_start =
437             ext4_bg_get_inode_table_first_block(bg_ref.block_group,
438                     &fs->sb);
439
440     /* Put back block group reference (not needed more) */
441     rc = ext4_fs_put_block_group_ref(&bg_ref);
442     if (rc != EOK) {
443         return rc;
444     }
445
446     /* Compute position of i-node in the block group */
447     uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
448     uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
449     uint32_t byte_offset_in_group = offset_in_group * inode_size;
450
451     /* Compute block address */
452     uint64_t block_id = inode_table_start +
453             (byte_offset_in_group / block_size);
454
455
456     rc = ext4_block_get(fs->bdev, &ref->block, block_id);
457     if (rc != EOK) {
458         return rc;
459     }
460
461     /* Compute position of i-node in the data block */
462     uint32_t offset_in_block = byte_offset_in_group % block_size;
463     ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
464
465     /* We need to store the original value of index in the reference */
466     ref->index = index + 1;
467     ref->fs = fs;
468     ref->dirty = false;
469
470     return EOK;
471 }
472
473 int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
474 {
475     /* Check if reference modified */
476     if (ref->dirty) {
477         /* Mark block dirty for writing changes to physical device */
478         ref->block.dirty = true;
479     }
480
481     /* Put back block, that contains i-node */
482     return  ext4_block_set(ref->fs->bdev, &ref->block);
483 }
484
485 int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
486     bool is_directory)
487 {
488     /* Check if newly allocated i-node will be a directory */
489     uint32_t i;
490     bool is_dir;
491
492     is_dir = is_directory;
493
494     /* Allocate inode by allocation algorithm */
495     uint32_t index;
496     int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
497     if (rc != EOK)
498         return rc;
499
500     /* Load i-node from on-disk i-node table */
501     rc = ext4_fs_get_inode_ref(fs, index, inode_ref);
502     if (rc != EOK) {
503         ext4_ialloc_free_inode(fs, index, is_dir);
504         return rc;
505     }
506
507     /* Initialize i-node */
508     struct ext4_inode *inode = inode_ref->inode;
509
510     uint16_t mode;
511     if (is_dir) {
512         /*
513          * Default directory permissions to be compatible with other systems
514          * 0777 (octal) == rwxrwxrwx
515          */
516
517         mode = 0777;
518         mode |= EXT4_INODE_MODE_DIRECTORY;
519         ext4_inode_set_mode(&fs->sb, inode, mode);
520         ext4_inode_set_links_count(inode, 1);  /* '.' entry */
521
522     } else {
523         /*
524          * Default file permissions to be compatible with other systems
525          * 0666 (octal) == rw-rw-rw-
526          */
527
528         mode = 0666;
529         mode |= EXT4_INODE_MODE_FILE;
530         ext4_inode_set_mode(&fs->sb, inode, mode);
531         ext4_inode_set_links_count(inode, 0);
532     }
533
534     ext4_inode_set_uid(inode, 0);
535     ext4_inode_set_gid(inode, 0);
536     ext4_inode_set_size(inode, 0);
537     ext4_inode_set_access_time(inode,           0);
538     ext4_inode_set_change_inode_time(inode, 0);
539     ext4_inode_set_modification_time(inode, 0);
540     ext4_inode_set_deletion_time(inode,         0);
541     ext4_inode_set_blocks_count(&fs->sb, inode, 0);
542     ext4_inode_set_flags(inode, 0);
543     ext4_inode_set_generation(inode, 0);
544
545     /* Reset blocks array */
546     for (i = 0; i < EXT4_INODE_BLOCKS; i++)
547         inode->blocks[i] = 0;
548
549 #if CONFIG_EXTENT_ENABLE
550     /* Initialize extents if needed */
551     if (ext4_sb_check_feature_incompatible(
552             &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
553         ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
554
555
556         /* Initialize extent root header */
557         ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
558         ext4_extent_header_set_depth(header, 0);
559         ext4_extent_header_set_entries_count(header, 0);
560         ext4_extent_header_set_generation(header, 0);
561         ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
562
563         uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
564                 sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
565
566         ext4_extent_header_set_max_entries_count(header, max_entries);
567     }
568 #endif
569
570     inode_ref->dirty = true;
571
572     return EOK;
573 }
574
575 int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
576 {
577     struct ext4_fs *fs = inode_ref->fs;
578     uint32_t offset;
579     uint32_t suboffset;
580 #if CONFIG_EXTENT_ENABLE
581     /* For extents must be data block destroyed by other way */
582     if ((ext4_sb_check_feature_incompatible(&fs->sb,
583             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
584             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
585         /* Data structures are released during truncate operation... */
586         goto finish;
587     }
588 #endif
589     /* Release all indirect (no data) blocks */
590
591     /* 1) Single indirect */
592     uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
593     if (fblock != 0) {
594         int rc = ext4_balloc_free_block(inode_ref, fblock);
595         if (rc != EOK)
596             return rc;
597
598         ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
599     }
600
601     uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
602     uint32_t count = block_size / sizeof(uint32_t);
603
604     struct      ext4_block  block;
605
606     /* 2) Double indirect */
607     fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
608     if (fblock != 0) {
609         int rc = ext4_block_get(fs->bdev, &block, fblock);
610         if (rc != EOK)
611             return rc;
612
613         uint32_t ind_block;
614         for (offset = 0; offset < count; ++offset) {
615             ind_block = to_le32(((uint32_t *) block.data)[offset]);
616
617             if (ind_block != 0) {
618                 rc = ext4_balloc_free_block(inode_ref, ind_block);
619                 if (rc != EOK) {
620                     ext4_block_set(fs->bdev, &block);
621                     return rc;
622                 }
623             }
624         }
625
626         ext4_block_set(fs->bdev, &block);
627         rc = ext4_balloc_free_block(inode_ref, fblock);
628         if (rc != EOK)
629             return rc;
630
631         ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
632     }
633
634     /* 3) Tripple indirect */
635     struct      ext4_block  subblock;
636     fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
637     if (fblock != 0) {
638         int rc = ext4_block_get(fs->bdev, &block, fblock);
639         if (rc != EOK)
640             return rc;
641
642         uint32_t ind_block;
643         for ( offset = 0; offset < count; ++offset) {
644             ind_block = to_le32(((uint32_t *) block.data)[offset]);
645
646             if (ind_block != 0) {
647                 rc = ext4_block_get(fs->bdev, &subblock, ind_block);
648                 if (rc != EOK) {
649                     ext4_block_set(fs->bdev, &block);
650                     return rc;
651                 }
652
653                 uint32_t ind_subblock;
654                 for (suboffset = 0; suboffset < count;
655                         ++suboffset) {
656                     ind_subblock = to_le32(((uint32_t *)
657                             subblock.data)[suboffset]);
658
659                     if (ind_subblock != 0) {
660                         rc = ext4_balloc_free_block(inode_ref, ind_subblock);
661                         if (rc != EOK) {
662                             ext4_block_set(fs->bdev, &subblock);
663                             ext4_block_set(fs->bdev, &block);
664                             return rc;
665                         }
666                     }
667                 }
668
669                 ext4_block_set(fs->bdev, &subblock);
670
671
672                 rc = ext4_balloc_free_block(inode_ref, ind_block);
673                 if (rc != EOK) {
674                     ext4_block_set(fs->bdev, &block);
675                     return rc;
676                 }
677             }
678         }
679
680         ext4_block_set(fs->bdev, &block);
681         rc = ext4_balloc_free_block(inode_ref, fblock);
682         if (rc != EOK)
683             return rc;
684
685         ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
686     }
687
688     finish:
689     /* Mark inode dirty for writing to the physical device */
690     inode_ref->dirty = true;
691
692     /* Free block with extended attributes if present */
693     uint32_t xattr_block = ext4_inode_get_file_acl(
694             inode_ref->inode, &fs->sb);
695     if (xattr_block) {
696         int rc = ext4_balloc_free_block(inode_ref, xattr_block);
697         if (rc != EOK)
698             return rc;
699
700         ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
701     }
702
703     /* Free inode by allocator */
704     int rc;
705     if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
706             EXT4_INODE_MODE_DIRECTORY))
707         rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
708     else
709         rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
710
711     return rc;
712 }
713
714 int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
715     uint64_t new_size)
716 {
717     struct ext4_sblock *sb = &inode_ref->fs->sb;
718     uint32_t i;
719
720     /* Check flags, if i-node can be truncated */
721     if (!ext4_inode_can_truncate(sb, inode_ref->inode))
722         return EINVAL;
723
724     /* If sizes are equal, nothing has to be done. */
725     uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
726     if (old_size == new_size)
727         return EOK;
728
729     /* It's not suppported to make the larger file by truncate operation */
730     if (old_size < new_size)
731         return EINVAL;
732
733     /* Compute how many blocks will be released */
734     uint64_t size_diff = old_size - new_size;
735     uint32_t block_size  = ext4_sb_get_block_size(sb);
736     uint32_t diff_blocks_count = size_diff / block_size;
737     if (size_diff % block_size != 0)
738         diff_blocks_count++;
739
740     uint32_t old_blocks_count = old_size / block_size;
741     if (old_size % block_size != 0)
742         old_blocks_count++;
743 #if CONFIG_EXTENT_ENABLE
744     if ((ext4_sb_check_feature_incompatible(sb,
745             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
746             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
747
748         /* Extents require special operation */
749         int rc = ext4_extent_release_blocks_from(inode_ref,
750                 old_blocks_count - diff_blocks_count);
751         if (rc != EOK)
752             return rc;
753
754     } else
755 #endif
756     {
757         /* Release data blocks from the end of file */
758
759         /* Starting from 1 because of logical blocks are numbered from 0 */
760         for (i = 1; i <= diff_blocks_count; ++i) {
761             int rc = ext4_fs_release_inode_block(inode_ref,
762                     old_blocks_count - i);
763             if (rc != EOK)
764                 return rc;
765         }
766     }
767
768     /* Update i-node */
769     ext4_inode_set_size(inode_ref->inode, new_size);
770     inode_ref->dirty = true;
771
772     return EOK;
773 }
774
775 int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
776     uint64_t iblock, uint32_t *fblock)
777 {
778     struct ext4_fs *fs = inode_ref->fs;
779
780     /* For empty file is situation simple */
781     if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
782         *fblock = 0;
783         return EOK;
784     }
785
786     uint32_t current_block;
787 #if CONFIG_EXTENT_ENABLE
788     /* Handle i-node using extents */
789     if ((ext4_sb_check_feature_incompatible(&fs->sb,
790             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
791             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
792
793
794         int rc = ext4_extent_find_block(inode_ref, iblock, &current_block);
795         if (rc != EOK)
796             return rc;
797
798         *fblock = current_block;
799         return EOK;
800     }
801 #endif
802
803     struct ext4_inode *inode = inode_ref->inode;
804
805     /* Direct block are read directly from array in i-node structure */
806     if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
807         current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);
808         *fblock = current_block;
809         return EOK;
810     }
811
812     /* Determine indirection level of the target block */
813     unsigned int level = 0;
814     unsigned int i;
815     for (i = 1; i < 4; i++) {
816         if (iblock < fs->inode_block_limits[i]) {
817             level = i;
818             break;
819         }
820     }
821
822     if (level == 0)
823         return EIO;
824
825     /* Compute offsets for the topmost level */
826     uint64_t block_offset_in_level =
827             iblock - fs->inode_block_limits[level - 1];
828     current_block = ext4_inode_get_indirect_block(inode, level - 1);
829     uint32_t offset_in_block =
830             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
831
832     /* Sparse file */
833     if (current_block == 0) {
834         *fblock = 0;
835         return EOK;
836     }
837
838     struct      ext4_block block;
839
840     /*
841      * Navigate through other levels, until we find the block number
842      * or find null reference meaning we are dealing with sparse file
843      */
844     while (level > 0) {
845         /* Load indirect block */
846         int rc = ext4_block_get(fs->bdev, &block, current_block);
847         if (rc != EOK)
848             return rc;
849
850         /* Read block address from indirect block */
851         current_block =
852                 to_le32(((uint32_t *) block.data)[offset_in_block]);
853
854         /* Put back indirect block untouched */
855         rc = ext4_block_set(fs->bdev, &block);
856         if (rc != EOK)
857             return rc;
858
859         /* Check for sparse file */
860         if (current_block == 0) {
861             *fblock = 0;
862             return EOK;
863         }
864
865         /* Jump to the next level */
866         level--;
867
868         /* Termination condition - we have address of data block loaded */
869         if (level == 0)
870             break;
871
872         /* Visit the next level */
873         block_offset_in_level %= fs->inode_blocks_per_level[level];
874         offset_in_block =
875                 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
876     }
877
878     *fblock = current_block;
879
880     return EOK;
881 }
882
883 int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
884     uint64_t iblock, uint32_t fblock)
885 {
886     struct ext4_fs *fs = inode_ref->fs;
887
888 #if CONFIG_EXTENT_ENABLE
889     /* Handle inode using extents */
890     if ((ext4_sb_check_feature_incompatible(&fs->sb,
891             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
892             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
893         /* Not reachable */
894         return ENOTSUP;
895     }
896 #endif
897
898     /* Handle simple case when we are dealing with direct reference */
899     if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
900         ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock,
901                 fblock);
902         inode_ref->dirty = true;
903
904         return EOK;
905     }
906
907     /* Determine the indirection level needed to get the desired block */
908     unsigned int level = 0;
909     unsigned int i;
910     for (i = 1; i < 4; i++) {
911         if (iblock < fs->inode_block_limits[i]) {
912             level = i;
913             break;
914         }
915     }
916
917     if (level == 0)
918         return EIO;
919
920     uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
921
922     /* Compute offsets for the topmost level */
923     uint64_t block_offset_in_level =
924             iblock - fs->inode_block_limits[level - 1];
925     uint32_t current_block =
926             ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
927     uint32_t offset_in_block =
928             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
929
930     uint32_t new_block_addr;
931
932     struct      ext4_block block;
933     struct      ext4_block new_block;
934
935     /* Is needed to allocate indirect block on the i-node level */
936     if (current_block == 0) {
937         /* Allocate new indirect block */
938         int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
939         if (rc != EOK)
940             return rc;
941
942         /* Update i-node */
943         ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
944             new_block_addr);
945         inode_ref->dirty = true;
946
947         /* Load newly allocated block */
948         rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
949         if (rc != EOK) {
950             ext4_balloc_free_block(inode_ref, new_block_addr);
951             return rc;
952         }
953
954         /* Initialize new block */
955         memset(new_block.data, 0, block_size);
956         new_block.dirty = true;
957
958         /* Put back the allocated block */
959         rc = ext4_block_set(fs->bdev, &new_block);
960         if (rc != EOK)
961             return rc;
962
963         current_block = new_block_addr;
964     }
965
966     /*
967      * Navigate through other levels, until we find the block number
968      * or find null reference meaning we are dealing with sparse file
969      */
970     while (level > 0) {
971         int rc = ext4_block_get(fs->bdev, &block, current_block);
972         if (rc != EOK)
973             return rc;
974
975         current_block =
976                 to_le32(((uint32_t *) block.data)[offset_in_block]);
977
978         if ((level > 1) && (current_block == 0)) {
979             /* Allocate new block */
980             rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
981             if (rc != EOK) {
982                 ext4_block_set(fs->bdev, &block);
983                 return rc;
984             }
985
986             /* Load newly allocated block */
987             rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
988
989             if (rc != EOK) {
990                 ext4_block_set(fs->bdev, &block);
991                 return rc;
992             }
993
994             /* Initialize allocated block */
995             memset(new_block.data, 0, block_size);
996             new_block.dirty = true;
997
998             rc = ext4_block_set(fs->bdev, &new_block);
999             if (rc != EOK) {
1000                 ext4_block_set(fs->bdev, &block);
1001                 return rc;
1002             }
1003
1004             /* Write block address to the parent */
1005             ((uint32_t *) block.data)[offset_in_block] =
1006                     to_le32(new_block_addr);
1007             block.dirty = true;
1008             current_block = new_block_addr;
1009         }
1010
1011         /* Will be finished, write the fblock address */
1012         if (level == 1) {
1013             ((uint32_t *) block.data)[offset_in_block] =
1014                     to_le32(fblock);
1015             block.dirty = true;
1016         }
1017
1018         rc = ext4_block_set(fs->bdev, &block);
1019         if (rc != EOK)
1020             return rc;
1021
1022         level--;
1023
1024         /*
1025          * If we are on the last level, break here as
1026          * there is no next level to visit
1027          */
1028         if (level == 0)
1029             break;
1030
1031         /* Visit the next level */
1032         block_offset_in_level %= fs->inode_blocks_per_level[level];
1033         offset_in_block =
1034                 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1035     }
1036
1037     return EOK;
1038 }
1039
1040 int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
1041     uint32_t iblock)
1042 {
1043     uint32_t fblock;
1044
1045     struct ext4_fs *fs = inode_ref->fs;
1046
1047     /* Extents are handled otherwise = there is not support in this function */
1048     ext4_assert(!(ext4_sb_check_feature_incompatible(&fs->sb,
1049             EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1050             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
1051
1052     struct ext4_inode *inode = inode_ref->inode;
1053
1054     /* Handle simple case when we are dealing with direct reference */
1055     if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1056         fblock = ext4_inode_get_direct_block(inode, iblock);
1057
1058         /* Sparse file */
1059         if (fblock == 0)
1060             return EOK;
1061
1062         ext4_inode_set_direct_block(inode, iblock, 0);
1063         return ext4_balloc_free_block(inode_ref, fblock);
1064     }
1065
1066     /* Determine the indirection level needed to get the desired block */
1067     unsigned int level = 0;
1068     unsigned int i;
1069     for (i = 1; i < 4; i++) {
1070         if (iblock < fs->inode_block_limits[i]) {
1071             level = i;
1072             break;
1073         }
1074     }
1075
1076     if (level == 0)
1077         return EIO;
1078
1079     /* Compute offsets for the topmost level */
1080     uint64_t block_offset_in_level =
1081             iblock - fs->inode_block_limits[level - 1];
1082     uint32_t current_block =
1083             ext4_inode_get_indirect_block(inode, level - 1);
1084     uint32_t offset_in_block =
1085             block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1086
1087     /*
1088      * Navigate through other levels, until we find the block number
1089      * or find null reference meaning we are dealing with sparse file
1090      */
1091     struct      ext4_block block;
1092
1093     while (level > 0) {
1094
1095         /* Sparse check */
1096         if (current_block == 0)
1097             return EOK;
1098
1099         int rc = ext4_block_get(fs->bdev, &block, current_block);
1100         if (rc != EOK)
1101             return rc;
1102
1103         current_block =
1104                 to_le32(((uint32_t *) block.data)[offset_in_block]);
1105
1106         /* Set zero if physical data block address found */
1107         if (level == 1) {
1108             ((uint32_t *) block.data)[offset_in_block] =
1109                     to_le32(0);
1110             block.dirty = true;
1111         }
1112
1113         rc = ext4_block_set(fs->bdev, &block);
1114         if (rc != EOK)
1115             return rc;
1116
1117         level--;
1118
1119         /*
1120          * If we are on the last level, break here as
1121          * there is no next level to visit
1122          */
1123         if (level == 0)
1124             break;
1125
1126         /* Visit the next level */
1127         block_offset_in_level %= fs->inode_blocks_per_level[level];
1128         offset_in_block =
1129                 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1130     }
1131
1132     fblock = current_block;
1133     if (fblock == 0)
1134         return EOK;
1135
1136     /* Physical block is not referenced, it can be released */
1137     return ext4_balloc_free_block(inode_ref, fblock);
1138 }
1139
1140
1141 int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
1142     uint32_t *fblock, uint32_t *iblock)
1143 {
1144 #if CONFIG_EXTENT_ENABLE
1145     /* Handle extents separately */
1146     if ((ext4_sb_check_feature_incompatible(&inode_ref->fs->sb,
1147             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1148             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
1149         return ext4_extent_append_block(inode_ref, iblock, fblock, true);
1150     }
1151 #endif
1152     struct ext4_sblock *sb = &inode_ref->fs->sb;
1153
1154     /* Compute next block index and allocate data block */
1155     uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1156     uint32_t block_size = ext4_sb_get_block_size(sb);
1157
1158     /* Align size i-node size */
1159     if ((inode_size % block_size) != 0)
1160         inode_size += block_size - (inode_size % block_size);
1161
1162     /* Logical blocks are numbered from 0 */
1163     uint32_t new_block_idx = inode_size / block_size;
1164
1165     /* Allocate new physical block */
1166     uint32_t phys_block;
1167     int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
1168     if (rc != EOK)
1169         return rc;
1170
1171     /* Add physical block address to the i-node */
1172     rc = ext4_fs_set_inode_data_block_index(inode_ref,
1173             new_block_idx, phys_block);
1174     if (rc != EOK) {
1175         ext4_balloc_free_block(inode_ref, phys_block);
1176         return rc;
1177     }
1178
1179     /* Update i-node */
1180     ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1181     inode_ref->dirty = true;
1182
1183     *fblock = phys_block;
1184     *iblock = new_block_idx;
1185
1186     return EOK;
1187 }
1188
1189 /**
1190  * @}
1191  */
1192