source: mainline/uspace/lib/ext4/src/filesystem.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was b7fd2a0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use errno_t in all uspace and kernel code.

Change type of every variable, parameter and return value that holds an
<errno.h> constant to either errno_t (the usual case), or sys_errno_t
(some places in kernel). This is for the purpose of self-documentation,
as well as for type-checking with a bit of type definition hackery.

Although this is a massive commit, it is a simple text replacement, and thus
is very easy to verify. Simply do the following:

`
git checkout <this commit's hash>
git reset HEAD
git add .
tools/srepl '\berrno_t\b' int
git add .
tools/srepl '\bsys_errno_t\b' sysarg_t
git reset
git diff
`

While this doesn't ensure that the replacements are correct, it does ensure
that the commit doesn't do anything except those replacements. Since errno_t
is typedef'd to int in the usual case (and sys_errno_t to sysarg_t), even if
incorrect, this commit cannot change behavior.

  • Property mode set to 100644
File size: 43.7 KB
RevLine 
[6c501f8]1/*
[d1538a1]2 * Copyright (c) 2011 Martin Sucha
[f22d5ef0]3 * Copyright (c) 2012 Frantisek Princ
[6c501f8]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libext4
31 * @{
[38542dc]32 */
[6c501f8]33/**
[4bfad34]34 * @file filesystem.c
[38542dc]35 * @brief More complex filesystem operations.
[6c501f8]36 */
37
[9b9d37bb]38#include <byteorder.h>
[6c501f8]39#include <errno.h>
[fcb0d76]40#include <mem.h>
[447201e]41#include <align.h>
[2b5d966]42#include <crypto.h>
[fcb0d76]43#include <ipc/vfs.h>
[4bfad34]44#include <libfs.h>
[fcb0d76]45#include <stdlib.h>
46#include "ext4/balloc.h"
47#include "ext4/bitmap.h"
48#include "ext4/block_group.h"
49#include "ext4/extent.h"
50#include "ext4/filesystem.h"
51#include "ext4/ialloc.h"
52#include "ext4/inode.h"
[4bfad34]53#include "ext4/ops.h"
[fcb0d76]54#include "ext4/superblock.h"
[6c501f8]55
[b7fd2a0]56static errno_t ext4_filesystem_check_features(ext4_filesystem_t *, bool *);
[4bfad34]57
[de5b708]58/** Initialize filesystem for opening.
59 *
60 * But do not mark mounted just yet.
[9fc72fb3]61 *
[38542dc]62 * @param fs Filesystem instance to be initialized
[395df52]63 * @param service_id Block device to open
[4bfad34]64 * @param cmode Cache mode
[38542dc]65 *
66 * @return Error code
67 *
[9fc72fb3]68 */
[b7fd2a0]69static errno_t ext4_filesystem_init(ext4_filesystem_t *fs, service_id_t service_id,
[de5b708]70 enum cache_mode cmode)
[6c501f8]71{
[b7fd2a0]72 errno_t rc;
[eb94d84]73 ext4_superblock_t *temp_superblock = NULL;
74
[01ab41b]75 fs->device = service_id;
[eb94d84]76
[06d85e5]77 /* Initialize block library (4096 is size of communication channel) */
[fc22069]78 rc = block_init(fs->device, 4096);
[38542dc]79 if (rc != EOK)
[eb94d84]80 goto err;
81
[06d85e5]82 /* Read superblock from device to memory */
[01ab41b]83 rc = ext4_superblock_read_direct(fs->device, &temp_superblock);
[eb94d84]84 if (rc != EOK)
85 goto err_1;
86
[06d85e5]87 /* Read block size from superblock and check */
[d9bbe45]88 uint32_t block_size = ext4_superblock_get_block_size(temp_superblock);
[01ab41b]89 if (block_size > EXT4_MAX_BLOCK_SIZE) {
[eb94d84]90 rc = ENOTSUP;
91 goto err_1;
[01ab41b]92 }
[eb94d84]93
[06d85e5]94 /* Initialize block caching by libblock */
[0b293a6]95 rc = block_cache_init(service_id, block_size, 0, cmode);
[eb94d84]96 if (rc != EOK)
97 goto err_1;
98
[06d85e5]99 /* Compute limits for indirect block levels */
[d9bbe45]100 uint32_t block_ids_per_block = block_size / sizeof(uint32_t);
[a9a0982]101 fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
102 fs->inode_blocks_per_level[0] = 1;
[38542dc]103 for (unsigned int i = 1; i < 4; i++) {
104 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] *
[a9a0982]105 block_ids_per_block;
[38542dc]106 fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
107 fs->inode_blocks_per_level[i];
[a9a0982]108 }
[eb94d84]109
[06d85e5]110 /* Return loaded superblock */
[01ab41b]111 fs->superblock = temp_superblock;
[eb94d84]112
[fb04cd90]113 uint16_t state = ext4_superblock_get_state(fs->superblock);
[eb94d84]114
[c3fe001]115 if (((state & EXT4_SUPERBLOCK_STATE_VALID_FS) !=
116 EXT4_SUPERBLOCK_STATE_VALID_FS) ||
117 ((state & EXT4_SUPERBLOCK_STATE_ERROR_FS) ==
118 EXT4_SUPERBLOCK_STATE_ERROR_FS)) {
[eb94d84]119 rc = ENOTSUP;
120 goto err_2;
[fb04cd90]121 }
[de5b708]122
[f066a87]123 rc = ext4_superblock_check_sanity(fs->superblock);
124 if (rc != EOK)
125 goto err_2;
[eb94d84]126
[4bfad34]127 /* Check flags */
128 bool read_only;
129 rc = ext4_filesystem_check_features(fs, &read_only);
130 if (rc != EOK)
131 goto err_2;
132
[de5b708]133 return EOK;
134err_2:
135 block_cache_fini(fs->device);
136err_1:
137 block_fini(fs->device);
138err:
139 if (temp_superblock)
140 ext4_superblock_release(temp_superblock);
141 return rc;
142}
143
144/** Finalize filesystem.
145 *
146 * @param fs Filesystem to be finalized
147 *
148 */
149static void ext4_filesystem_fini(ext4_filesystem_t *fs)
150{
151 /* Release memory space for superblock */
152 free(fs->superblock);
153
154 /* Finish work with block library */
155 block_cache_fini(fs->device);
156 block_fini(fs->device);
157}
158
[395df52]159/** Probe filesystem.
160 *
161 * @param service_id Block device to probe
162 *
[cde999a]163 * @return EOK or an error code.
[395df52]164 *
165 */
[b7fd2a0]166errno_t ext4_filesystem_probe(service_id_t service_id)
[395df52]167{
168 ext4_filesystem_t *fs = NULL;
[b7fd2a0]169 errno_t rc;
[395df52]170
171 fs = calloc(1, sizeof(ext4_filesystem_t));
172 if (fs == NULL)
173 return ENOMEM;
174
175 /* Initialize the file system for opening */
176 rc = ext4_filesystem_init(fs, service_id, CACHE_MODE_WT);
177 if (rc != EOK) {
178 free(fs);
179 return rc;
180 }
181
182 ext4_filesystem_fini(fs);
183 return EOK;
184}
185
[de5b708]186/** Open filesystem and read all needed data.
187 *
188 * @param fs Filesystem to be initialized
189 * @param inst Instance
190 * @param service_id Identifier if device with the filesystem
191 * @param cmode Cache mode
192 * @param size Output value - size of root node
193 *
194 * @return Error code
195 *
196 */
[b7fd2a0]197errno_t ext4_filesystem_open(ext4_instance_t *inst, service_id_t service_id,
[de5b708]198 enum cache_mode cmode, aoff64_t *size, ext4_filesystem_t **rfs)
199{
200 ext4_filesystem_t *fs = NULL;
201 fs_node_t *root_node = NULL;
[b7fd2a0]202 errno_t rc;
[de5b708]203
204 fs = calloc(1, sizeof(ext4_filesystem_t));
205 if (fs == NULL) {
206 rc = ENOMEM;
207 goto error;
208 }
209
210 inst->filesystem = fs;
211
212 /* Initialize the file system for opening */
213 rc = ext4_filesystem_init(fs, service_id, cmode);
214 if (rc != EOK)
215 goto error;
216
[4bfad34]217 /* Read root node */
[be39fc6]218 rc = ext4_node_get_core(&root_node, inst, EXT4_INODE_ROOT_INDEX);
[4bfad34]219 if (rc != EOK)
[de5b708]220 goto error;
[4bfad34]221
[06d85e5]222 /* Mark system as mounted */
[fb04cd90]223 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_ERROR_FS);
224 rc = ext4_superblock_write_direct(fs->device, fs->superblock);
[eb94d84]225 if (rc != EOK)
[de5b708]226 goto error;
[eb94d84]227
[4cdac68]228 uint16_t mnt_count = ext4_superblock_get_mount_count(fs->superblock);
229 ext4_superblock_set_mount_count(fs->superblock, mnt_count + 1);
[eb94d84]230
[be39fc6]231 ext4_node_t *enode = EXT4_NODE(root_node);
[de5b708]232
[4bfad34]233 *size = ext4_inode_get_size(fs->superblock, enode->inode_ref->inode);
[eb94d84]234
[be39fc6]235 ext4_node_put(root_node);
[de5b708]236 *rfs = fs;
[4bfad34]237 return EOK;
[de5b708]238error:
239 if (root_node != NULL)
240 ext4_node_put(root_node);
241
242 if (fs != NULL) {
243 ext4_filesystem_fini(fs);
244 free(fs);
245 }
246
[eb94d84]247 return rc;
[6c501f8]248}
249
[de5b708]250/** Close filesystem.
[9fc72fb3]251 *
[38542dc]252 * @param fs Filesystem to be destroyed
253 *
[cde999a]254 * @return EOK or an error code. On error the state of the file
[de5b708]255 * system is unchanged.
[38542dc]256 *
[9fc72fb3]257 */
[b7fd2a0]258errno_t ext4_filesystem_close(ext4_filesystem_t *fs)
[3711e7e]259{
[06d85e5]260 /* Write the superblock to the device */
[fb04cd90]261 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_VALID_FS);
[b7fd2a0]262 errno_t rc = ext4_superblock_write_direct(fs->device, fs->superblock);
[de5b708]263 if (rc != EOK)
264 return rc;
[2b5d966]265
[de5b708]266 ext4_filesystem_fini(fs);
267 return EOK;
[3711e7e]268}
269
[5b26747]270/** Check filesystem's features, if supported by this driver
[9fc72fb3]271 *
[5b26747]272 * Function can return EOK and set read_only flag. It mean's that
273 * there are some not-supported features, that can cause problems
274 * during some write operations.
275 *
[38542dc]276 * @param fs Filesystem to be checked
[4bfad34]277 * @param read_only Place to write flag saying whether filesystem
278 * should be mounted only for reading
[38542dc]279 *
280 * @return Error code
281 *
[9fc72fb3]282 */
[b7fd2a0]283static errno_t ext4_filesystem_check_features(ext4_filesystem_t *fs,
[4bfad34]284 bool *read_only)
[6c501f8]285{
[06d85e5]286 /* Feature flags are present only in higher revisions */
[9c0c0e1]287 if (ext4_superblock_get_rev_level(fs->superblock) == 0) {
[5b26747]288 *read_only = false;
[9c0c0e1]289 return EOK;
290 }
[38542dc]291
292 /*
293 * Check incompatible features - if filesystem has some,
[06d85e5]294 * volume can't be mounted
295 */
[9c0c0e1]296 uint32_t incompatible_features;
[38542dc]297 incompatible_features =
298 ext4_superblock_get_features_incompatible(fs->superblock);
[9c0c0e1]299 incompatible_features &= ~EXT4_FEATURE_INCOMPAT_SUPP;
[38542dc]300 if (incompatible_features > 0)
[9c0c0e1]301 return ENOTSUP;
[38542dc]302
303 /*
304 * Check read-only features, if filesystem has some,
[06d85e5]305 * volume can be mount only in read-only mode
306 */
[9c0c0e1]307 uint32_t compatible_read_only;
[38542dc]308 compatible_read_only =
309 ext4_superblock_get_features_read_only(fs->superblock);
[9c0c0e1]310 compatible_read_only &= ~EXT4_FEATURE_RO_COMPAT_SUPP;
311 if (compatible_read_only > 0) {
[5b26747]312 *read_only = true;
313 return EOK;
[9c0c0e1]314 }
[38542dc]315
[6c501f8]316 return EOK;
317}
318
[4cdac68]319
320/** Convert block address to relative index in block group.
321 *
[38542dc]322 * @param sb Superblock pointer
323 * @param block_addr Block number to convert
324 *
325 * @return Relative number of block
326 *
[4cdac68]327 */
328uint32_t ext4_filesystem_blockaddr2_index_in_group(ext4_superblock_t *sb,
[38542dc]329 uint32_t block_addr)
[4cdac68]330{
331 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
332 uint32_t first_block = ext4_superblock_get_first_data_block(sb);
[38542dc]333
[4cdac68]334 /* First block == 0 or 1 */
[38542dc]335 if (first_block == 0)
[4cdac68]336 return block_addr % blocks_per_group;
[38542dc]337 else
[4cdac68]338 return (block_addr - 1) % blocks_per_group;
339}
340
341
342/** Convert relative block address in group to absolute address.
343 *
[38542dc]344 * @param sb Superblock pointer
345 *
346 * @return Absolute block address
347 *
[4cdac68]348 */
349uint32_t ext4_filesystem_index_in_group2blockaddr(ext4_superblock_t *sb,
[38542dc]350 uint32_t index, uint32_t bgid)
[4cdac68]351{
352 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
[38542dc]353
354 if (ext4_superblock_get_first_data_block(sb) == 0)
[4cdac68]355 return bgid * blocks_per_group + index;
[38542dc]356 else
[4cdac68]357 return bgid * blocks_per_group + index + 1;
358}
359
[d76973c]360/** Convert the absolute block number to group number
361 *
362 * @param sb Pointer to the superblock
363 * @param b Absolute block number
364 *
365 * @return Group number
366 */
367uint32_t ext4_filesystem_blockaddr2group(ext4_superblock_t *sb, uint64_t b)
368{
369 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
[60c409c]370 uint32_t first_block = ext4_superblock_get_first_data_block(sb);
[d76973c]371
[60c409c]372 return (b - first_block) / blocks_per_group;
[d76973c]373}
374
[4cdac68]375/** Initialize block bitmap in block group.
[38542dc]376 *
377 * @param bg_ref Reference to block group
378 *
379 * @return Error code
380 *
[4cdac68]381 */
[b7fd2a0]382static errno_t ext4_filesystem_init_block_bitmap(ext4_block_group_ref_t *bg_ref)
[4cdac68]383{
[d76973c]384 uint64_t itb;
385 uint32_t sz;
386 uint32_t i;
387
[4cdac68]388 /* Load bitmap */
[d76973c]389 ext4_superblock_t *sb = bg_ref->fs->superblock;
390 uint64_t bitmap_block_addr = ext4_block_group_get_block_bitmap(
391 bg_ref->block_group, bg_ref->fs->superblock);
392 uint64_t bitmap_inode_addr = ext4_block_group_get_inode_bitmap(
[38542dc]393 bg_ref->block_group, bg_ref->fs->superblock);
394
[4cdac68]395 block_t *bitmap_block;
[b7fd2a0]396 errno_t rc = block_get(&bitmap_block, bg_ref->fs->device,
[38542dc]397 bitmap_block_addr, BLOCK_FLAGS_NOREAD);
398 if (rc != EOK)
[4cdac68]399 return rc;
[38542dc]400
[4cdac68]401 uint8_t *bitmap = bitmap_block->data;
[38542dc]402
[4cdac68]403 /* Initialize all bitmap bits to zero */
[d76973c]404 uint32_t block_size = ext4_superblock_get_block_size(sb);
[4cdac68]405 memset(bitmap, 0, block_size);
[38542dc]406
[d76973c]407 /* Determine the number of reserved blocks in the group */
408 uint32_t reserved_cnt = ext4_filesystem_bg_get_backup_blocks(bg_ref);
409
[4cdac68]410 /* Set bits from to first block to first data block - 1 to one (allocated) */
[d76973c]411 for (uint32_t block = 0; block < reserved_cnt; ++block)
[4cdac68]412 ext4_bitmap_set_bit(bitmap, block);
[d76973c]413
414 uint32_t bitmap_block_gid = ext4_filesystem_blockaddr2group(sb,
415 bitmap_block_addr);
416 if (bitmap_block_gid == bg_ref->index) {
417 ext4_bitmap_set_bit(bitmap,
418 ext4_filesystem_blockaddr2_index_in_group(sb, bitmap_block_addr));
419 }
420
421 uint32_t bitmap_inode_gid = ext4_filesystem_blockaddr2group(sb,
422 bitmap_inode_addr);
423 if (bitmap_inode_gid == bg_ref->index) {
424 ext4_bitmap_set_bit(bitmap,
425 ext4_filesystem_blockaddr2_index_in_group(sb, bitmap_inode_addr));
426 }
427
428 itb = ext4_block_group_get_inode_table_first_block(bg_ref->block_group,
429 sb);
430 sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
431
432 for (i = 0; i < sz; ++i, ++itb) {
433 uint32_t gid = ext4_filesystem_blockaddr2group(sb, itb);
434 if (gid == bg_ref->index) {
435 ext4_bitmap_set_bit(bitmap,
436 ext4_filesystem_blockaddr2_index_in_group(sb, itb));
437 }
438 }
439
[4cdac68]440 bitmap_block->dirty = true;
[38542dc]441
[4cdac68]442 /* Save bitmap */
[38542dc]443 return block_put(bitmap_block);
[4cdac68]444}
445
446/** Initialize i-node bitmap in block group.
[38542dc]447 *
448 * @param bg_ref Reference to block group
449 *
450 * @return Error code
451 *
[4cdac68]452 */
[b7fd2a0]453static errno_t ext4_filesystem_init_inode_bitmap(ext4_block_group_ref_t *bg_ref)
[4cdac68]454{
455 /* Load bitmap */
456 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
[38542dc]457 bg_ref->block_group, bg_ref->fs->superblock);
[4cdac68]458 block_t *bitmap_block;
[38542dc]459
[b7fd2a0]460 errno_t rc = block_get(&bitmap_block, bg_ref->fs->device,
[38542dc]461 bitmap_block_addr, BLOCK_FLAGS_NOREAD);
462 if (rc != EOK)
[4cdac68]463 return rc;
[38542dc]464
[4cdac68]465 uint8_t *bitmap = bitmap_block->data;
[38542dc]466
[4cdac68]467 /* Initialize all bitmap bits to zero */
468 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock);
469 uint32_t inodes_per_group =
[38542dc]470 ext4_superblock_get_inodes_per_group(bg_ref->fs->superblock);
[4cdac68]471 memset(bitmap, 0, (inodes_per_group + 7) / 8);
[38542dc]472
[4cdac68]473 uint32_t start_bit = inodes_per_group;
474 uint32_t end_bit = block_size * 8;
[38542dc]475
[4cdac68]476 uint32_t i;
[38542dc]477 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
[4cdac68]478 ext4_bitmap_set_bit(bitmap, i);
[38542dc]479
480 if (i < end_bit)
[4cdac68]481 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
[38542dc]482
[4cdac68]483 bitmap_block->dirty = true;
[38542dc]484
[4cdac68]485 /* Save bitmap */
[38542dc]486 return block_put(bitmap_block);
[4cdac68]487}
488
489/** Initialize i-node table in block group.
[38542dc]490 *
491 * @param bg_ref Reference to block group
492 *
493 * @return Error code
494 *
[fe61181]495 */
[b7fd2a0]496static errno_t ext4_filesystem_init_inode_table(ext4_block_group_ref_t *bg_ref)
[4cdac68]497{
498 ext4_superblock_t *sb = bg_ref->fs->superblock;
[38542dc]499
[4cdac68]500 uint32_t inode_size = ext4_superblock_get_inode_size(sb);
501 uint32_t block_size = ext4_superblock_get_block_size(sb);
502 uint32_t inodes_per_block = block_size / inode_size;
[38542dc]503
[4cdac68]504 uint32_t inodes_in_group =
[38542dc]505 ext4_superblock_get_inodes_in_group(sb, bg_ref->index);
506
[4cdac68]507 uint32_t table_blocks = inodes_in_group / inodes_per_block;
[38542dc]508
509 if (inodes_in_group % inodes_per_block)
[4cdac68]510 table_blocks++;
[38542dc]511
[4cdac68]512 /* Compute initialization bounds */
513 uint32_t first_block = ext4_block_group_get_inode_table_first_block(
[38542dc]514 bg_ref->block_group, sb);
515
[4cdac68]516 uint32_t last_block = first_block + table_blocks - 1;
[38542dc]517
[4cdac68]518 /* Initialization of all itable blocks */
519 for (uint32_t fblock = first_block; fblock <= last_block; ++fblock) {
520 block_t *block;
[b7fd2a0]521 errno_t rc = block_get(&block, bg_ref->fs->device, fblock,
[38542dc]522 BLOCK_FLAGS_NOREAD);
523 if (rc != EOK)
[4cdac68]524 return rc;
[38542dc]525
[4cdac68]526 memset(block->data, 0, block_size);
527 block->dirty = true;
[38542dc]528
[4cdac68]529 rc = block_put(block);
[38542dc]530 if (rc != EOK)
[4cdac68]531 return rc;
532 }
[38542dc]533
[4cdac68]534 return EOK;
535}
536
[5b26747]537/** Get reference to block group specified by index.
[9fc72fb3]538 *
[38542dc]539 * @param fs Filesystem to find block group on
540 * @param bgid Index of block group to load
541 * @param ref Output pointer for reference
542 *
543 * @return Error code
544 *
[9fc72fb3]545 */
[b7fd2a0]546errno_t ext4_filesystem_get_block_group_ref(ext4_filesystem_t *fs, uint32_t bgid,
[3711e7e]547 ext4_block_group_ref_t **ref)
[6c501f8]548{
[06d85e5]549 /* Allocate memory for new structure */
[38542dc]550 ext4_block_group_ref_t *newref =
551 malloc(sizeof(ext4_block_group_ref_t));
552 if (newref == NULL)
[3711e7e]553 return ENOMEM;
[38542dc]554
[06d85e5]555 /* Compute number of descriptors, that fits in one data block */
[38542dc]556 uint32_t descriptors_per_block =
557 ext4_superblock_get_block_size(fs->superblock) /
558 ext4_superblock_get_desc_size(fs->superblock);
559
[06d85e5]560 /* Block group descriptor table starts at the next block after superblock */
[38542dc]561 aoff64_t block_id =
562 ext4_superblock_get_first_data_block(fs->superblock) + 1;
563
[06d85e5]564 /* Find the block containing the descriptor we are looking for */
[3711e7e]565 block_id += bgid / descriptors_per_block;
[38542dc]566 uint32_t offset = (bgid % descriptors_per_block) *
567 ext4_superblock_get_desc_size(fs->superblock);
568
[06d85e5]569 /* Load block with descriptors */
[b7fd2a0]570 errno_t rc = block_get(&newref->block, fs->device, block_id, 0);
[3711e7e]571 if (rc != EOK) {
572 free(newref);
573 return rc;
574 }
[38542dc]575
[7f29575]576 /* Initialize in-memory representation */
[3711e7e]577 newref->block_group = newref->block->data + offset;
[1ac1ab4]578 newref->fs = fs;
579 newref->index = bgid;
[12b4a7f]580 newref->dirty = false;
[38542dc]581
[3711e7e]582 *ref = newref;
[38542dc]583
[4cdac68]584 if (ext4_block_group_has_flag(newref->block_group,
[38542dc]585 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
[4cdac68]586 rc = ext4_filesystem_init_block_bitmap(newref);
587 if (rc != EOK) {
588 block_put(newref->block);
589 free(newref);
590 return rc;
591 }
[38542dc]592
[4cdac68]593 ext4_block_group_clear_flag(newref->block_group,
[38542dc]594 EXT4_BLOCK_GROUP_BLOCK_UNINIT);
595
[4cdac68]596 newref->dirty = true;
597 }
[38542dc]598
[4cdac68]599 if (ext4_block_group_has_flag(newref->block_group,
[38542dc]600 EXT4_BLOCK_GROUP_INODE_UNINIT)) {
[4cdac68]601 rc = ext4_filesystem_init_inode_bitmap(newref);
602 if (rc != EOK) {
603 block_put(newref->block);
604 free(newref);
605 return rc;
606 }
[38542dc]607
[4cdac68]608 ext4_block_group_clear_flag(newref->block_group,
[38542dc]609 EXT4_BLOCK_GROUP_INODE_UNINIT);
610
611 if (!ext4_block_group_has_flag(newref->block_group,
612 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
[4cdac68]613 rc = ext4_filesystem_init_inode_table(newref);
[38542dc]614 if (rc != EOK)
[4cdac68]615 return rc;
[38542dc]616
[4cdac68]617 ext4_block_group_set_flag(newref->block_group,
[38542dc]618 EXT4_BLOCK_GROUP_ITABLE_ZEROED);
[4cdac68]619 }
[38542dc]620
[4cdac68]621 newref->dirty = true;
622 }
[38542dc]623
[3711e7e]624 return EOK;
[6c501f8]625}
626
[81a7858]627/** Compute checksum of block group descriptor.
[9fc72fb3]628 *
[38542dc]629 * @param sb Superblock
630 * @param bgid Index of block group in the filesystem
631 * @param bg Block group to compute checksum for
632 *
633 * @return Checksum value
634 *
[9fc72fb3]635 */
[1ac1ab4]636static uint16_t ext4_filesystem_bg_checksum(ext4_superblock_t *sb, uint32_t bgid,
[38542dc]637 ext4_block_group_t *bg)
[1ac1ab4]638{
[06d85e5]639 /* If checksum not supported, 0 will be returned */
[1ac1ab4]640 uint16_t crc = 0;
[2b5d966]641
[06d85e5]642 /* Compute the checksum only if the filesystem supports it */
[38542dc]643 if (ext4_superblock_has_feature_read_only(sb,
644 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
[1ac1ab4]645 void *base = bg;
646 void *checksum = &bg->checksum;
[38542dc]647
648 uint32_t offset = (uint32_t) (checksum - base);
649
[06d85e5]650 /* Convert block group index to little endian */
[1ac1ab4]651 uint32_t le_group = host2uint32_t_le(bgid);
[38542dc]652
[06d85e5]653 /* Initialization */
[2b5d966]654 crc = crc16_ibm(~0, sb->uuid, sizeof(sb->uuid));
[38542dc]655
[06d85e5]656 /* Include index of block group */
[2b5d966]657 crc = crc16_ibm(crc, (uint8_t *) &le_group, sizeof(le_group));
[38542dc]658
[06d85e5]659 /* Compute crc from the first part (stop before checksum field) */
[2b5d966]660 crc = crc16_ibm(crc, (uint8_t *) bg, offset);
[38542dc]661
[06d85e5]662 /* Skip checksum */
[81a7858]663 offset += sizeof(bg->checksum);
[38542dc]664
[06d85e5]665 /* Checksum of the rest of block group descriptor */
[38542dc]666 if ((ext4_superblock_has_feature_incompatible(sb,
667 EXT4_FEATURE_INCOMPAT_64BIT)) &&
668 (offset < ext4_superblock_get_desc_size(sb)))
[2b5d966]669 crc = crc16_ibm(crc, ((uint8_t *) bg) + offset,
[38542dc]670 ext4_superblock_get_desc_size(sb) - offset);
[1ac1ab4]671 }
[38542dc]672
[1ac1ab4]673 return crc;
674}
675
[d76973c]676/** Get the size of the block group's inode table
677 *
678 * @param sb Pointer to the superblock
679 * @param bg_ref Pointer to the block group reference
680 *
681 * @return Size of the inode table in blocks.
682 */
683uint32_t ext4_filesystem_bg_get_itable_size(ext4_superblock_t *sb,
684 ext4_block_group_ref_t *bg_ref)
685{
686 uint32_t itable_size;
687 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
688 uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
689 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
690 uint32_t block_size = ext4_superblock_get_block_size(sb);
691
692 if (bg_ref->index < block_group_count - 1) {
693 itable_size = inodes_per_group * inode_table_item_size;
694 } else {
695 /* Last block group could be smaller */
696 uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
697 itable_size =
698 (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
699 inode_table_item_size;
700 }
701
702 return ROUND_UP(itable_size, block_size) / block_size;
703}
704
[447201e]705/* Check if n is a power of p */
706static bool is_power_of(uint32_t n, unsigned p)
707{
708 if (p == 1 && n != p)
709 return false;
710
711 while (n != p) {
712 if (n < p)
713 return false;
714 else if ((n % p) != 0)
715 return false;
716
717 n /= p;
718 }
719
720 return true;
721}
722
723/** Get the number of blocks used by superblock + gdt + reserved gdt backups
724 *
725 * @param bg Pointer to block group
726 *
727 * @return Number of blocks
728 */
[d76973c]729uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg)
[447201e]730{
731 uint32_t const idx = bg->index;
732 uint32_t r = 0;
733 bool has_backups = false;
734 ext4_superblock_t *sb = bg->fs->superblock;
735
736 /* First step: determine if the block group contains the backups */
737
738 if (idx <= 1)
739 has_backups = true;
740 else {
741 if (ext4_superblock_has_feature_compatible(sb,
742 EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
743 uint32_t g1, g2;
744
745 ext4_superblock_get_backup_groups_sparse2(sb,
746 &g1, &g2);
747
748 if (idx == g1 || idx == g2)
749 has_backups = true;
750 } else if (!ext4_superblock_has_feature_read_only(sb,
751 EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
752 /* Very old fs were all block groups have
753 * superblock and block descriptors backups.
754 */
755 has_backups = true;
756 } else {
757 if ((idx & 1) && (is_power_of(idx, 3) ||
758 is_power_of(idx, 5) || is_power_of(idx, 7)))
759 has_backups = true;
760 }
761 }
762
763 if (has_backups) {
764 uint32_t bg_count;
765 uint32_t bg_desc_sz;
766 uint32_t gdt_table; /* Size of the GDT in blocks */
767 uint32_t block_size = ext4_superblock_get_block_size(sb);
768
769 /* Now we know that this block group has backups,
770 * we have to compute how many blocks are reserved
771 * for them
772 */
773
774 if (idx == 0 && block_size == 1024) {
775 /* Special case for first group were the boot block
776 * resides
777 */
778 r++;
779 }
780
781 /* This accounts for the superblock */
782 r++;
783
784 /* Add the number of blocks used for the GDT */
785 bg_count = ext4_superblock_get_block_group_count(sb);
786 bg_desc_sz = ext4_superblock_get_desc_size(sb);
787 gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
788 block_size;
789
790 r += gdt_table;
791
792 /* And now the number of reserved GDT blocks */
793 r += ext4_superblock_get_reserved_gdt_blocks(sb);
794 }
795
796 return r;
797}
798
[5b26747]799/** Put reference to block group.
[9fc72fb3]800 *
[c1fd281]801 * @param ref Pointer for reference to be put back
[38542dc]802 *
803 * @return Error code
804 *
[9fc72fb3]805 */
[b7fd2a0]806errno_t ext4_filesystem_put_block_group_ref(ext4_block_group_ref_t *ref)
[829d238]807{
[06d85e5]808 /* Check if reference modified */
[12b4a7f]809 if (ref->dirty) {
[06d85e5]810 /* Compute new checksum of block group */
[38542dc]811 uint16_t checksum =
812 ext4_filesystem_bg_checksum(ref->fs->superblock, ref->index,
813 ref->block_group);
[5b0a3946]814 ext4_block_group_set_checksum(ref->block_group, checksum);
[38542dc]815
[06d85e5]816 /* Mark block dirty for writing changes to physical device */
[12b4a7f]817 ref->block->dirty = true;
818 }
[38542dc]819
[06d85e5]820 /* Put back block, that contains block group descriptor */
[b7fd2a0]821 errno_t rc = block_put(ref->block);
[829d238]822 free(ref);
[38542dc]823
[829d238]824 return rc;
825}
826
[5b26747]827/** Get reference to i-node specified by index.
[9fc72fb3]828 *
[38542dc]829 * @param fs Filesystem to find i-node on
830 * @param index Index of i-node to load
831 * @oaram ref Output pointer for reference
832 *
833 * @return Error code
834 *
[9fc72fb3]835 */
[b7fd2a0]836errno_t ext4_filesystem_get_inode_ref(ext4_filesystem_t *fs, uint32_t index,
[3711e7e]837 ext4_inode_ref_t **ref)
838{
[06d85e5]839 /* Allocate memory for new structure */
[38542dc]840 ext4_inode_ref_t *newref =
841 malloc(sizeof(ext4_inode_ref_t));
842 if (newref == NULL)
[3711e7e]843 return ENOMEM;
[38542dc]844
[06d85e5]845 /* Compute number of i-nodes, that fits in one data block */
[d9bbe45]846 uint32_t inodes_per_group =
[38542dc]847 ext4_superblock_get_inodes_per_group(fs->superblock);
848
849 /*
850 * Inode numbers are 1-based, but it is simpler to work with 0-based
[3711e7e]851 * when computing indices
852 */
853 index -= 1;
[d9bbe45]854 uint32_t block_group = index / inodes_per_group;
855 uint32_t offset_in_group = index % inodes_per_group;
[38542dc]856
[06d85e5]857 /* Load block group, where i-node is located */
[d9bbe45]858 ext4_block_group_ref_t *bg_ref;
[b7fd2a0]859 errno_t rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
[3711e7e]860 if (rc != EOK) {
861 free(newref);
862 return rc;
863 }
[38542dc]864
[06d85e5]865 /* Load block address, where i-node table is located */
[38542dc]866 uint32_t inode_table_start =
867 ext4_block_group_get_inode_table_first_block(bg_ref->block_group,
868 fs->superblock);
869
[06d85e5]870 /* Put back block group reference (not needed more) */
[829d238]871 rc = ext4_filesystem_put_block_group_ref(bg_ref);
872 if (rc != EOK) {
873 free(newref);
874 return rc;
875 }
[38542dc]876
[06d85e5]877 /* Compute position of i-node in the block group */
[d9bbe45]878 uint16_t inode_size = ext4_superblock_get_inode_size(fs->superblock);
879 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
880 uint32_t byte_offset_in_group = offset_in_group * inode_size;
[38542dc]881
[06d85e5]882 /* Compute block address */
[d9bbe45]883 aoff64_t block_id = inode_table_start + (byte_offset_in_group / block_size);
[3711e7e]884 rc = block_get(&newref->block, fs->device, block_id, 0);
885 if (rc != EOK) {
886 free(newref);
887 return rc;
888 }
[38542dc]889
[06d85e5]890 /* Compute position of i-node in the data block */
[d9bbe45]891 uint32_t offset_in_block = byte_offset_in_group % block_size;
[3711e7e]892 newref->inode = newref->block->data + offset_in_block;
[38542dc]893
[06d85e5]894 /* We need to store the original value of index in the reference */
[1ac1ab4]895 newref->index = index + 1;
896 newref->fs = fs;
[052e82d]897 newref->dirty = false;
[38542dc]898
[3711e7e]899 *ref = newref;
[38542dc]900
[9b9d37bb]901 return EOK;
902}
903
[81a7858]904/** Put reference to i-node.
[9fc72fb3]905 *
[38542dc]906 * @param ref Pointer for reference to be put back
907 *
908 * @return Error code
909 *
[9fc72fb3]910 */
[b7fd2a0]911errno_t ext4_filesystem_put_inode_ref(ext4_inode_ref_t *ref)
[9b9d37bb]912{
[06d85e5]913 /* Check if reference modified */
[052e82d]914 if (ref->dirty) {
[06d85e5]915 /* Mark block dirty for writing changes to physical device */
[052e82d]916 ref->block->dirty = true;
917 }
[38542dc]918
[06d85e5]919 /* Put back block, that contains i-node */
[b7fd2a0]920 errno_t rc = block_put(ref->block);
[9b9d37bb]921 free(ref);
[38542dc]922
[9b9d37bb]923 return rc;
924}
925
[81a7858]926/** Allocate new i-node in the filesystem.
[9fc72fb3]927 *
[38542dc]928 * @param fs Filesystem to allocated i-node on
929 * @param inode_ref Output pointer to return reference to allocated i-node
930 * @param flags Flags to be set for newly created i-node
931 *
932 * @return Error code
933 *
[9fc72fb3]934 */
[b7fd2a0]935errno_t ext4_filesystem_alloc_inode(ext4_filesystem_t *fs,
[38542dc]936 ext4_inode_ref_t **inode_ref, int flags)
[2d2c6ce]937{
[06d85e5]938 /* Check if newly allocated i-node will be a directory */
[304faab]939 bool is_dir = false;
[38542dc]940 if (flags & L_DIRECTORY)
[304faab]941 is_dir = true;
[38542dc]942
[06d85e5]943 /* Allocate inode by allocation algorithm */
[304faab]944 uint32_t index;
[b7fd2a0]945 errno_t rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
[38542dc]946 if (rc != EOK)
[304faab]947 return rc;
[38542dc]948
[06d85e5]949 /* Load i-node from on-disk i-node table */
[304faab]950 rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref);
951 if (rc != EOK) {
952 ext4_ialloc_free_inode(fs, index, is_dir);
953 return rc;
954 }
[38542dc]955
[06d85e5]956 /* Initialize i-node */
[304faab]957 ext4_inode_t *inode = (*inode_ref)->inode;
[38542dc]958
[8847142]959 uint16_t mode;
[304faab]960 if (is_dir) {
[8847142]961 /*
962 * Default directory permissions to be compatible with other systems
963 * 0777 (octal) == rwxrwxrwx
964 */
[38542dc]965
[8847142]966 mode = 0777;
967 mode |= EXT4_INODE_MODE_DIRECTORY;
968 ext4_inode_set_mode(fs->superblock, inode, mode);
[38542dc]969 ext4_inode_set_links_count(inode, 1); /* '.' entry */
[2d2c6ce]970 } else {
[8847142]971 /*
972 * Default file permissions to be compatible with other systems
973 * 0666 (octal) == rw-rw-rw-
974 */
[38542dc]975
[8847142]976 mode = 0666;
977 mode |= EXT4_INODE_MODE_FILE;
978 ext4_inode_set_mode(fs->superblock, inode, mode);
[2d2c6ce]979 ext4_inode_set_links_count(inode, 0);
980 }
[38542dc]981
[2d2c6ce]982 ext4_inode_set_uid(inode, 0);
983 ext4_inode_set_gid(inode, 0);
984 ext4_inode_set_size(inode, 0);
985 ext4_inode_set_access_time(inode, 0);
986 ext4_inode_set_change_inode_time(inode, 0);
987 ext4_inode_set_modification_time(inode, 0);
988 ext4_inode_set_deletion_time(inode, 0);
989 ext4_inode_set_blocks_count(fs->superblock, inode, 0);
990 ext4_inode_set_flags(inode, 0);
991 ext4_inode_set_generation(inode, 0);
[38542dc]992
[06d85e5]993 /* Reset blocks array */
[38542dc]994 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++)
[2d2c6ce]995 inode->blocks[i] = 0;
[38542dc]996
[06d85e5]997 /* Initialize extents if needed */
[936132f]998 if (ext4_superblock_has_feature_incompatible(
[38542dc]999 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
[936132f]1000 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
[38542dc]1001
[06d85e5]1002 /* Initialize extent root header */
[936132f]1003 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
1004 ext4_extent_header_set_depth(header, 0);
1005 ext4_extent_header_set_entries_count(header, 0);
1006 ext4_extent_header_set_generation(header, 0);
1007 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
[38542dc]1008
1009 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
1010 sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
1011
[936132f]1012 ext4_extent_header_set_max_entries_count(header, max_entries);
1013 }
[38542dc]1014
[304faab]1015 (*inode_ref)->dirty = true;
[38542dc]1016
[2d2c6ce]1017 return EOK;
1018}
1019
[81a7858]1020/** Release i-node and mark it as free.
[9fc72fb3]1021 *
[38542dc]1022 * @param inode_ref I-node to be released
1023 *
1024 * @return Error code
1025 *
[9fc72fb3]1026 */
[b7fd2a0]1027errno_t ext4_filesystem_free_inode(ext4_inode_ref_t *inode_ref)
[3d4fd2c]1028{
[3e2952b]1029 ext4_filesystem_t *fs = inode_ref->fs;
[38542dc]1030
[06d85e5]1031 /* For extents must be data block destroyed by other way */
[38542dc]1032 if ((ext4_superblock_has_feature_incompatible(fs->superblock,
1033 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1034 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
[06d85e5]1035 /* Data structures are released during truncate operation... */
[3e2952b]1036 goto finish;
1037 }
[38542dc]1038
[06d85e5]1039 /* Release all indirect (no data) blocks */
[38542dc]1040
[06d85e5]1041 /* 1) Single indirect */
[d9bbe45]1042 uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
[3d4fd2c]1043 if (fblock != 0) {
[b7fd2a0]1044 errno_t rc = ext4_balloc_free_block(inode_ref, fblock);
[38542dc]1045 if (rc != EOK)
[ca3d77a]1046 return rc;
[38542dc]1047
[3d4fd2c]1048 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
1049 }
[38542dc]1050
[3d4fd2c]1051 block_t *block;
1052 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
1053 uint32_t count = block_size / sizeof(uint32_t);
[38542dc]1054
[06d85e5]1055 /* 2) Double indirect */
[3d4fd2c]1056 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
1057 if (fblock != 0) {
[b7fd2a0]1058 errno_t rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
[38542dc]1059 if (rc != EOK)
[e63ce679]1060 return rc;
[38542dc]1061
[3d4fd2c]1062 uint32_t ind_block;
1063 for (uint32_t offset = 0; offset < count; ++offset) {
[38542dc]1064 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]);
1065
[3d4fd2c]1066 if (ind_block != 0) {
[1ac1ab4]1067 rc = ext4_balloc_free_block(inode_ref, ind_block);
[3d4fd2c]1068 if (rc != EOK) {
[e63ce679]1069 block_put(block);
1070 return rc;
[3d4fd2c]1071 }
1072 }
1073 }
[38542dc]1074
[532f53d]1075 rc = block_put(block);
1076 if (rc != EOK)
1077 return rc;
1078
[1ac1ab4]1079 rc = ext4_balloc_free_block(inode_ref, fblock);
[38542dc]1080 if (rc != EOK)
[e63ce679]1081 return rc;
[38542dc]1082
[3d4fd2c]1083 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
1084 }
[38542dc]1085
[06d85e5]1086 /* 3) Tripple indirect */
[3d4fd2c]1087 block_t *subblock;
1088 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
1089 if (fblock != 0) {
[b7fd2a0]1090 errno_t rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
[38542dc]1091 if (rc != EOK)
[e63ce679]1092 return rc;
[38542dc]1093
[3d4fd2c]1094 uint32_t ind_block;
1095 for (uint32_t offset = 0; offset < count; ++offset) {
[38542dc]1096 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]);
1097
[3d4fd2c]1098 if (ind_block != 0) {
[38542dc]1099 rc = block_get(&subblock, fs->device, ind_block,
1100 BLOCK_FLAGS_NONE);
[3d4fd2c]1101 if (rc != EOK) {
[e63ce679]1102 block_put(block);
1103 return rc;
[3d4fd2c]1104 }
[38542dc]1105
[3d4fd2c]1106 uint32_t ind_subblock;
[38542dc]1107 for (uint32_t suboffset = 0; suboffset < count;
1108 ++suboffset) {
1109 ind_subblock = uint32_t_le2host(((uint32_t *)
1110 subblock->data)[suboffset]);
1111
[3d4fd2c]1112 if (ind_subblock != 0) {
[1ac1ab4]1113 rc = ext4_balloc_free_block(inode_ref, ind_subblock);
[3d4fd2c]1114 if (rc != EOK) {
[e63ce679]1115 block_put(subblock);
1116 block_put(block);
1117 return rc;
[3d4fd2c]1118 }
1119 }
1120 }
[38542dc]1121
[532f53d]1122 rc = block_put(subblock);
[f5c03a8]1123 if (rc != EOK) {
1124 block_put(block);
[532f53d]1125 return rc;
[f5c03a8]1126 }
[3d4fd2c]1127 }
[38542dc]1128
[1ac1ab4]1129 rc = ext4_balloc_free_block(inode_ref, ind_block);
[3d4fd2c]1130 if (rc != EOK) {
[e63ce679]1131 block_put(block);
1132 return rc;
[3d4fd2c]1133 }
1134 }
[38542dc]1135
[532f53d]1136 rc = block_put(block);
1137 if (rc != EOK)
1138 return rc;
1139
[1ac1ab4]1140 rc = ext4_balloc_free_block(inode_ref, fblock);
[38542dc]1141 if (rc != EOK)
[e63ce679]1142 return rc;
[38542dc]1143
[3d4fd2c]1144 ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
1145 }
[38542dc]1146
[3e2952b]1147finish:
[06d85e5]1148 /* Mark inode dirty for writing to the physical device */
[e5f8762]1149 inode_ref->dirty = true;
[38542dc]1150
[0b293a6]1151 /* Free block with extended attributes if present */
1152 uint32_t xattr_block = ext4_inode_get_file_acl(
[38542dc]1153 inode_ref->inode, fs->superblock);
[0b293a6]1154 if (xattr_block) {
[b7fd2a0]1155 errno_t rc = ext4_balloc_free_block(inode_ref, xattr_block);
[38542dc]1156 if (rc != EOK)
[0b293a6]1157 return rc;
[38542dc]1158
[0b293a6]1159 ext4_inode_set_file_acl(inode_ref->inode, fs->superblock, 0);
1160 }
[38542dc]1161
[06d85e5]1162 /* Free inode by allocator */
[b7fd2a0]1163 errno_t rc;
[304faab]1164 if (ext4_inode_is_type(fs->superblock, inode_ref->inode,
[38542dc]1165 EXT4_INODE_MODE_DIRECTORY))
[304faab]1166 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
[38542dc]1167 else
[304faab]1168 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
[38542dc]1169
1170 return rc;
[3d4fd2c]1171}
1172
[81a7858]1173/** Truncate i-node data blocks.
[9fc72fb3]1174 *
[38542dc]1175 * @param inode_ref I-node to be truncated
1176 * @param new_size New size of inode (must be < current size)
1177 *
1178 * @return Error code
1179 *
[9fc72fb3]1180 */
[b7fd2a0]1181errno_t ext4_filesystem_truncate_inode(ext4_inode_ref_t *inode_ref,
[38542dc]1182 aoff64_t new_size)
[3d4fd2c]1183{
[1ac1ab4]1184 ext4_superblock_t *sb = inode_ref->fs->superblock;
[38542dc]1185
[06d85e5]1186 /* Check flags, if i-node can be truncated */
[38542dc]1187 if (!ext4_inode_can_truncate(sb, inode_ref->inode))
[3d4fd2c]1188 return EINVAL;
[38542dc]1189
[06d85e5]1190 /* If sizes are equal, nothing has to be done. */
[1ac1ab4]1191 aoff64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
[38542dc]1192 if (old_size == new_size)
[3d4fd2c]1193 return EOK;
[38542dc]1194
[06d85e5]1195 /* It's not suppported to make the larger file by truncate operation */
[38542dc]1196 if (old_size < new_size)
[3d4fd2c]1197 return EINVAL;
[38542dc]1198
[06d85e5]1199 /* Compute how many blocks will be released */
[d9bbe45]1200 aoff64_t size_diff = old_size - new_size;
[1ac1ab4]1201 uint32_t block_size = ext4_superblock_get_block_size(sb);
[ca3d77a]1202 uint32_t diff_blocks_count = size_diff / block_size;
[38542dc]1203 if (size_diff % block_size != 0)
[ca3d77a]1204 diff_blocks_count++;
[38542dc]1205
[ca3d77a]1206 uint32_t old_blocks_count = old_size / block_size;
[38542dc]1207 if (old_size % block_size != 0)
[ca3d77a]1208 old_blocks_count++;
[38542dc]1209
1210 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock,
1211 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1212 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
[06d85e5]1213 /* Extents require special operation */
[b7fd2a0]1214 errno_t rc = ext4_extent_release_blocks_from(inode_ref,
[38542dc]1215 old_blocks_count - diff_blocks_count);
1216 if (rc != EOK)
[ca3d77a]1217 return rc;
[5b0a3946]1218 } else {
[06d85e5]1219 /* Release data blocks from the end of file */
[38542dc]1220
[06d85e5]1221 /* Starting from 1 because of logical blocks are numbered from 0 */
[5b0a3946]1222 for (uint32_t i = 1; i <= diff_blocks_count; ++i) {
[b7fd2a0]1223 errno_t rc = ext4_filesystem_release_inode_block(inode_ref,
[38542dc]1224 old_blocks_count - i);
1225 if (rc != EOK)
[5b0a3946]1226 return rc;
1227 }
[3d4fd2c]1228 }
[38542dc]1229
[06d85e5]1230 /* Update i-node */
[3d4fd2c]1231 ext4_inode_set_size(inode_ref->inode, new_size);
1232 inode_ref->dirty = true;
[38542dc]1233
[3d4fd2c]1234 return EOK;
1235}
1236
[81a7858]1237/** Get physical block address by logical index of the block.
[9fc72fb3]1238 *
[38542dc]1239 * @param inode_ref I-node to read block address from
1240 * @param iblock Logical index of block
1241 * @param fblock Output pointer for return physical block address
1242 *
1243 * @return Error code
1244 *
[9fc72fb3]1245 */
[b7fd2a0]1246errno_t ext4_filesystem_get_inode_data_block_index(ext4_inode_ref_t *inode_ref,
[38542dc]1247 aoff64_t iblock, uint32_t *fblock)
[9b9d37bb]1248{
[1ac1ab4]1249 ext4_filesystem_t *fs = inode_ref->fs;
[38542dc]1250
[06d85e5]1251 /* For empty file is situation simple */
[b73530a]1252 if (ext4_inode_get_size(fs->superblock, inode_ref->inode) == 0) {
1253 *fblock = 0;
1254 return EOK;
1255 }
[38542dc]1256
[9b9d37bb]1257 uint32_t current_block;
[38542dc]1258
[06d85e5]1259 /* Handle i-node using extents */
[38542dc]1260 if ((ext4_superblock_has_feature_incompatible(fs->superblock,
1261 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1262 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
[b7fd2a0]1263 errno_t rc = ext4_extent_find_block(inode_ref, iblock, &current_block);
[38542dc]1264 if (rc != EOK)
[9104bb5]1265 return rc;
[38542dc]1266
[acd869e]1267 *fblock = current_block;
1268 return EOK;
1269 }
[38542dc]1270
[9104bb5]1271 ext4_inode_t *inode = inode_ref->inode;
[38542dc]1272
[06d85e5]1273 /* Direct block are read directly from array in i-node structure */
[e68c834]1274 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
[38542dc]1275 current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);
[9b9d37bb]1276 *fblock = current_block;
1277 return EOK;
1278 }
[38542dc]1279
[06d85e5]1280 /* Determine indirection level of the target block */
[38542dc]1281 unsigned int level = 0;
1282 for (unsigned int i = 1; i < 4; i++) {
[a9a0982]1283 if (iblock < fs->inode_block_limits[i]) {
[9b9d37bb]1284 level = i;
1285 break;
1286 }
1287 }
[38542dc]1288
1289 if (level == 0)
[9b9d37bb]1290 return EIO;
[38542dc]1291
[06d85e5]1292 /* Compute offsets for the topmost level */
[38542dc]1293 aoff64_t block_offset_in_level =
1294 iblock - fs->inode_block_limits[level - 1];
1295 current_block = ext4_inode_get_indirect_block(inode, level - 1);
1296 uint32_t offset_in_block =
1297 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1298
[06d85e5]1299 /* Sparse file */
[6088193]1300 if (current_block == 0) {
1301 *fblock = 0;
1302 return EOK;
1303 }
[38542dc]1304
[d9bbe45]1305 block_t *block;
[38542dc]1306
1307 /*
1308 * Navigate through other levels, until we find the block number
[9b9d37bb]1309 * or find null reference meaning we are dealing with sparse file
1310 */
1311 while (level > 0) {
[06d85e5]1312 /* Load indirect block */
[b7fd2a0]1313 errno_t rc = block_get(&block, fs->device, current_block, 0);
[38542dc]1314 if (rc != EOK)
[9b9d37bb]1315 return rc;
[38542dc]1316
[06d85e5]1317 /* Read block address from indirect block */
[38542dc]1318 current_block =
1319 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]);
1320
[06d85e5]1321 /* Put back indirect block untouched */
[9b9d37bb]1322 rc = block_put(block);
[38542dc]1323 if (rc != EOK)
[9b9d37bb]1324 return rc;
[38542dc]1325
[06d85e5]1326 /* Check for sparse file */
[9b9d37bb]1327 if (current_block == 0) {
1328 *fblock = 0;
1329 return EOK;
1330 }
[38542dc]1331
[06d85e5]1332 /* Jump to the next level */
[38542dc]1333 level--;
1334
[06d85e5]1335 /* Termination condition - we have address of data block loaded */
[38542dc]1336 if (level == 0)
[9b9d37bb]1337 break;
[38542dc]1338
[06d85e5]1339 /* Visit the next level */
[a9a0982]1340 block_offset_in_level %= fs->inode_blocks_per_level[level];
[38542dc]1341 offset_in_block =
1342 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
[9b9d37bb]1343 }
[38542dc]1344
[9b9d37bb]1345 *fblock = current_block;
[38542dc]1346
[3711e7e]1347 return EOK;
1348}
[6c501f8]1349
[8060341a]1350/** Set physical block address for the block logical address into the i-node.
[9fc72fb3]1351 *
[38542dc]1352 * @param inode_ref I-node to set block address to
1353 * @param iblock Logical index of block
1354 * @param fblock Physical block address
1355 *
1356 * @return Error code
1357 *
[9fc72fb3]1358 */
[b7fd2a0]1359errno_t ext4_filesystem_set_inode_data_block_index(ext4_inode_ref_t *inode_ref,
[38542dc]1360 aoff64_t iblock, uint32_t fblock)
[35f48f2]1361{
[1ac1ab4]1362 ext4_filesystem_t *fs = inode_ref->fs;
[38542dc]1363
[06d85e5]1364 /* Handle inode using extents */
[38542dc]1365 if ((ext4_superblock_has_feature_compatible(fs->superblock,
1366 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1367 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
1368 /* Not reachable */
[35f48f2]1369 return ENOTSUP;
1370 }
[38542dc]1371
[06d85e5]1372 /* Handle simple case when we are dealing with direct reference */
[35f48f2]1373 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
[38542dc]1374 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock);
[1e65444]1375 inode_ref->dirty = true;
[38542dc]1376
[35f48f2]1377 return EOK;
1378 }
[38542dc]1379
[06d85e5]1380 /* Determine the indirection level needed to get the desired block */
[38542dc]1381 unsigned int level = 0;
1382 for (unsigned int i = 1; i < 4; i++) {
[1e65444]1383 if (iblock < fs->inode_block_limits[i]) {
1384 level = i;
1385 break;
1386 }
1387 }
[38542dc]1388
1389 if (level == 0)
[1e65444]1390 return EIO;
[38542dc]1391
[d9bbe45]1392 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
[38542dc]1393
[06d85e5]1394 /* Compute offsets for the topmost level */
[38542dc]1395 aoff64_t block_offset_in_level =
1396 iblock - fs->inode_block_limits[level - 1];
1397 uint32_t current_block =
1398 ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
1399 uint32_t offset_in_block =
1400 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1401
[d9bbe45]1402 uint32_t new_block_addr;
[38542dc]1403 block_t *block;
1404 block_t *new_block;
1405
[06d85e5]1406 /* Is needed to allocate indirect block on the i-node level */
[1e65444]1407 if (current_block == 0) {
[06d85e5]1408 /* Allocate new indirect block */
[b7fd2a0]1409 errno_t rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
[38542dc]1410 if (rc != EOK)
[e63ce679]1411 return rc;
[38542dc]1412
[06d85e5]1413 /* Update i-node */
[38542dc]1414 ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
1415 new_block_addr);
[1e65444]1416 inode_ref->dirty = true;
[38542dc]1417
[06d85e5]1418 /* Load newly allocated block */
[38542dc]1419 rc = block_get(&new_block, fs->device, new_block_addr,
1420 BLOCK_FLAGS_NOREAD);
[1e65444]1421 if (rc != EOK) {
[1ac1ab4]1422 ext4_balloc_free_block(inode_ref, new_block_addr);
[e63ce679]1423 return rc;
[1e65444]1424 }
[38542dc]1425
[06d85e5]1426 /* Initialize new block */
[1e65444]1427 memset(new_block->data, 0, block_size);
1428 new_block->dirty = true;
[38542dc]1429
[06d85e5]1430 /* Put back the allocated block */
[1e65444]1431 rc = block_put(new_block);
[38542dc]1432 if (rc != EOK)
[e63ce679]1433 return rc;
[38542dc]1434
[1e65444]1435 current_block = new_block_addr;
1436 }
[38542dc]1437
1438 /*
1439 * Navigate through other levels, until we find the block number
[1e65444]1440 * or find null reference meaning we are dealing with sparse file
1441 */
1442 while (level > 0) {
[b7fd2a0]1443 errno_t rc = block_get(&block, fs->device, current_block, 0);
[38542dc]1444 if (rc != EOK)
[1e65444]1445 return rc;
[38542dc]1446
1447 current_block =
1448 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]);
1449
[b12ca16]1450 if ((level > 1) && (current_block == 0)) {
[06d85e5]1451 /* Allocate new block */
[1ac1ab4]1452 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
[b12ca16]1453 if (rc != EOK) {
[e63ce679]1454 block_put(block);
1455 return rc;
[b12ca16]1456 }
[38542dc]1457
[06d85e5]1458 /* Load newly allocated block */
[38542dc]1459 rc = block_get(&new_block, fs->device, new_block_addr,
1460 BLOCK_FLAGS_NOREAD);
[b12ca16]1461 if (rc != EOK) {
[e63ce679]1462 block_put(block);
1463 return rc;
[b12ca16]1464 }
[38542dc]1465
[06d85e5]1466 /* Initialize allocated block */
[b12ca16]1467 memset(new_block->data, 0, block_size);
1468 new_block->dirty = true;
[38542dc]1469
[b12ca16]1470 rc = block_put(new_block);
1471 if (rc != EOK) {
[e63ce679]1472 block_put(block);
1473 return rc;
[b12ca16]1474 }
[38542dc]1475
[06d85e5]1476 /* Write block address to the parent */
[38542dc]1477 ((uint32_t *) block->data)[offset_in_block] =
1478 host2uint32_t_le(new_block_addr);
[b12ca16]1479 block->dirty = true;
1480 current_block = new_block_addr;
1481 }
[38542dc]1482
[06d85e5]1483 /* Will be finished, write the fblock address */
[b12ca16]1484 if (level == 1) {
[38542dc]1485 ((uint32_t *) block->data)[offset_in_block] =
1486 host2uint32_t_le(fblock);
[b12ca16]1487 block->dirty = true;
[1e65444]1488 }
[38542dc]1489
[1e65444]1490 rc = block_put(block);
[38542dc]1491 if (rc != EOK)
[1e65444]1492 return rc;
[38542dc]1493
1494 level--;
1495
1496 /*
1497 * If we are on the last level, break here as
[1e65444]1498 * there is no next level to visit
1499 */
[38542dc]1500 if (level == 0)
[1e65444]1501 break;
[38542dc]1502
[1e65444]1503 /* Visit the next level */
1504 block_offset_in_level %= fs->inode_blocks_per_level[level];
[38542dc]1505 offset_in_block =
1506 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
[1e65444]1507 }
[38542dc]1508
[35f48f2]1509 return EOK;
1510}
1511
[8060341a]1512/** Release data block from i-node
[9fc72fb3]1513 *
[38542dc]1514 * @param inode_ref I-node to release block from
1515 * @param iblock Logical block to be released
1516 *
1517 * @return Error code
1518 *
[9fc72fb3]1519 */
[b7fd2a0]1520errno_t ext4_filesystem_release_inode_block(ext4_inode_ref_t *inode_ref,
[38542dc]1521 uint32_t iblock)
[d5a78e28]1522{
[fffb061]1523 uint32_t fblock;
[38542dc]1524
[1ac1ab4]1525 ext4_filesystem_t *fs = inode_ref->fs;
[38542dc]1526
1527 /* Extents are handled otherwise = there is not support in this function */
1528 assert(!(ext4_superblock_has_feature_incompatible(fs->superblock,
1529 EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1530 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
1531
[d9bbe45]1532 ext4_inode_t *inode = inode_ref->inode;
[38542dc]1533
[06d85e5]1534 /* Handle simple case when we are dealing with direct reference */
[052e82d]1535 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
[12b4a7f]1536 fblock = ext4_inode_get_direct_block(inode, iblock);
[38542dc]1537
[06d85e5]1538 /* Sparse file */
[38542dc]1539 if (fblock == 0)
[052e82d]1540 return EOK;
[38542dc]1541
[052e82d]1542 ext4_inode_set_direct_block(inode, iblock, 0);
[1ac1ab4]1543 return ext4_balloc_free_block(inode_ref, fblock);
[12b4a7f]1544 }
[38542dc]1545
[06d85e5]1546 /* Determine the indirection level needed to get the desired block */
[38542dc]1547 unsigned int level = 0;
1548 for (unsigned int i = 1; i < 4; i++) {
[12b4a7f]1549 if (iblock < fs->inode_block_limits[i]) {
1550 level = i;
1551 break;
[052e82d]1552 }
[12b4a7f]1553 }
[38542dc]1554
1555 if (level == 0)
[12b4a7f]1556 return EIO;
[38542dc]1557
[06d85e5]1558 /* Compute offsets for the topmost level */
[38542dc]1559 aoff64_t block_offset_in_level =
1560 iblock - fs->inode_block_limits[level - 1];
1561 uint32_t current_block =
1562 ext4_inode_get_indirect_block(inode, level - 1);
1563 uint32_t offset_in_block =
1564 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1565
1566 /*
1567 * Navigate through other levels, until we find the block number
[12b4a7f]1568 * or find null reference meaning we are dealing with sparse file
1569 */
[d9bbe45]1570 block_t *block;
[12b4a7f]1571 while (level > 0) {
[041ab64]1572
1573 /* Sparse check */
1574 if (current_block == 0)
1575 return EOK;
1576
[b7fd2a0]1577 errno_t rc = block_get(&block, fs->device, current_block, 0);
[38542dc]1578 if (rc != EOK)
[12b4a7f]1579 return rc;
[38542dc]1580
1581 current_block =
1582 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]);
1583
[06d85e5]1584 /* Set zero if physical data block address found */
[12b4a7f]1585 if (level == 1) {
[38542dc]1586 ((uint32_t *) block->data)[offset_in_block] =
1587 host2uint32_t_le(0);
[12b4a7f]1588 block->dirty = true;
[052e82d]1589 }
[38542dc]1590
[12b4a7f]1591 rc = block_put(block);
[38542dc]1592 if (rc != EOK)
[12b4a7f]1593 return rc;
[38542dc]1594
1595 level--;
1596
1597 /*
1598 * If we are on the last level, break here as
[12b4a7f]1599 * there is no next level to visit
1600 */
[38542dc]1601 if (level == 0)
[12b4a7f]1602 break;
[38542dc]1603
[12b4a7f]1604 /* Visit the next level */
1605 block_offset_in_level %= fs->inode_blocks_per_level[level];
[38542dc]1606 offset_in_block =
1607 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
[12b4a7f]1608 }
[38542dc]1609
[12b4a7f]1610 fblock = current_block;
[38542dc]1611 if (fblock == 0)
[12b4a7f]1612 return EOK;
[38542dc]1613
[06d85e5]1614 /* Physical block is not referenced, it can be released */
[1ac1ab4]1615 return ext4_balloc_free_block(inode_ref, fblock);
[d5a78e28]1616}
1617
[81a7858]1618/** Append following logical block to the i-node.
[9fc72fb3]1619 *
[38542dc]1620 * @param inode_ref I-node to append block to
1621 * @param fblock Output physical block address of newly allocated block
1622 * @param iblock Output logical number of newly allocated block
1623 *
1624 * @return Error code
1625 *
[9fc72fb3]1626 */
[b7fd2a0]1627errno_t ext4_filesystem_append_inode_block(ext4_inode_ref_t *inode_ref,
[38542dc]1628 uint32_t *fblock, uint32_t *iblock)
[5b16912]1629{
[06d85e5]1630 /* Handle extents separately */
[38542dc]1631 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock,
1632 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1633 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)))
[d510ac01]1634 return ext4_extent_append_block(inode_ref, iblock, fblock, true);
[38542dc]1635
[5b16912]1636 ext4_superblock_t *sb = inode_ref->fs->superblock;
[38542dc]1637
[06d85e5]1638 /* Compute next block index and allocate data block */
[5b16912]1639 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1640 uint32_t block_size = ext4_superblock_get_block_size(sb);
[38542dc]1641
[06d85e5]1642 /* Align size i-node size */
[38542dc]1643 if ((inode_size % block_size) != 0)
[81a7858]1644 inode_size += block_size - (inode_size % block_size);
[38542dc]1645
[06d85e5]1646 /* Logical blocks are numbered from 0 */
[5b16912]1647 uint32_t new_block_idx = inode_size / block_size;
[38542dc]1648
[06d85e5]1649 /* Allocate new physical block */
[5b16912]1650 uint32_t phys_block;
[b7fd2a0]1651 errno_t rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
[38542dc]1652 if (rc != EOK)
[5b16912]1653 return rc;
[38542dc]1654
[06d85e5]1655 /* Add physical block address to the i-node */
[38542dc]1656 rc = ext4_filesystem_set_inode_data_block_index(inode_ref,
1657 new_block_idx, phys_block);
[5b16912]1658 if (rc != EOK) {
1659 ext4_balloc_free_block(inode_ref, phys_block);
1660 return rc;
1661 }
[38542dc]1662
[06d85e5]1663 /* Update i-node */
[5b16912]1664 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1665 inode_ref->dirty = true;
[38542dc]1666
[5b16912]1667 *fblock = phys_block;
1668 *iblock = new_block_idx;
[38542dc]1669
[5b16912]1670 return EOK;
1671}
1672
[6c501f8]1673/**
1674 * @}
[38542dc]1675 */
Note: See TracBrowser for help on using the repository browser.