source: mainline/uspace/lib/ext4/libext4_extent.c@ cb7056a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cb7056a was cb7056a, checked in by Frantisek Princ <frantisek.princ@…>, 14 years ago

comments on getters and setters used for extent structure

  • Property mode set to 100644
File size: 22.0 KB
RevLine 
[829d238]1/*
[f22d5ef0]2 * Copyright (c) 2012 Frantisek Princ
[829d238]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libext4
30 * @{
31 */
32
33/**
34 * @file libext4_extent.c
[c25e39b]35 * @brief Ext4 extent structures operations.
[829d238]36 */
37
[acd869e]38#include <byteorder.h>
[e2629b08]39#include <errno.h>
40#include <malloc.h>
41#include "libext4.h"
[829d238]42
[cb7056a]43/** Get logical number of the block covered extent.
44 *
45 * @param extent extent to load number from
46 * @return logical number of the first block covered by extent
47 */
[8958a26]48uint32_t ext4_extent_get_first_block(ext4_extent_t *extent)
49{
50 return uint32_t_le2host(extent->first_block);
51}
52
[cb7056a]53/** Set logical number of the first block covered by extent.
54 *
55 * @param extent extent to load number from
56 * @param iblock logical number of the first block covered by extent
57 */
58void ext4_extent_set_first_block(ext4_extent_t *extent, uint32_t iblock)
[343ccfd]59{
[cb7056a]60 extent->first_block = host2uint32_t_le(iblock);
[343ccfd]61}
62
[cb7056a]63/** Get number of blocks covered by extent.
64 *
65 * @param extent extent to load count from
66 * @return number of blocks covered by extent
67 */
[8958a26]68uint16_t ext4_extent_get_block_count(ext4_extent_t *extent)
69{
70 return uint16_t_le2host(extent->block_count);
71}
72
[cb7056a]73/** Set number of blocks covered by extent.
74 *
75 * @param extent extent to load count from
76 * @param count number of blocks covered by extent
77 */
78void ext4_extent_set_block_count(ext4_extent_t *extent, uint16_t count)
[343ccfd]79{
[cb7056a]80 extent->block_count = host2uint16_t_le(count);
[343ccfd]81}
82
[cb7056a]83/** Get physical number of the first block covered by extent.
84 *
85 * @param extent extent to load number
86 * @return physical number of the first block covered by extent
87 */
[8958a26]88uint64_t ext4_extent_get_start(ext4_extent_t *extent)
89{
90 return ((uint64_t)uint16_t_le2host(extent->start_hi)) << 32 |
91 ((uint64_t)uint32_t_le2host(extent->start_lo));
[343ccfd]92}
[8958a26]93
[cb7056a]94/** Set physical number of the first block covered by extent.
95 *
96 * @param extent extent to load number
97 * @param fblock physical number of the first block covered by extent
98 */
99void ext4_extent_set_start(ext4_extent_t *extent, uint64_t fblock)
[343ccfd]100{
[cb7056a]101 extent->start_lo = host2uint32_t_le((fblock << 32) >> 32);
102 extent->start_hi = host2uint16_t_le((uint16_t)(fblock >> 32));
[8958a26]103}
104
[cb7056a]105// TODO start comments here
106
[1a7756a]107uint32_t ext4_extent_index_get_first_block(ext4_extent_index_t *index)
108{
109 return uint32_t_le2host(index->first_block);
110}
111
[343ccfd]112void ext4_extent_index_set_first_block(ext4_extent_index_t *index,
113 uint32_t first)
114{
115 index->first_block = host2uint32_t_le(first);
116}
117
[1a7756a]118uint64_t ext4_extent_index_get_leaf(ext4_extent_index_t *index)
119{
120 return ((uint64_t)uint16_t_le2host(index->leaf_hi)) << 32 |
[343ccfd]121 ((uint64_t)uint32_t_le2host(index->leaf_lo));
122}
123
124void ext4_extent_index_set_leaf(ext4_extent_index_t *index, uint64_t leaf)
125{
126 index->leaf_lo = host2uint32_t_le((leaf << 32) >> 32);
127 index->leaf_hi = host2uint16_t_le((uint16_t)(leaf >> 32));
[1a7756a]128}
129
[acd869e]130uint16_t ext4_extent_header_get_magic(ext4_extent_header_t *header)
131{
132 return uint16_t_le2host(header->magic);
133}
134
[343ccfd]135void ext4_extent_header_set_magic(ext4_extent_header_t *header, uint16_t magic)
136{
137 header->magic = host2uint16_t_le(magic);
138}
139
[acd869e]140uint16_t ext4_extent_header_get_entries_count(ext4_extent_header_t *header)
141{
142 return uint16_t_le2host(header->entries_count);
143}
144
[343ccfd]145void ext4_extent_header_set_entries_count(ext4_extent_header_t *header,
146 uint16_t count)
147{
148 header->entries_count = host2uint16_t_le(count);
149}
150
[acd869e]151uint16_t ext4_extent_header_get_max_entries_count(ext4_extent_header_t *header)
152{
153 return uint16_t_le2host(header->max_entries_count);
154}
155
[343ccfd]156void ext4_extent_header_set_max_entries_count(ext4_extent_header_t *header,
157 uint16_t max_count)
158{
159 header->max_entries_count = host2uint16_t_le(max_count);
160}
161
[acd869e]162uint16_t ext4_extent_header_get_depth(ext4_extent_header_t *header)
163{
164 return uint16_t_le2host(header->depth);
165}
166
[343ccfd]167void ext4_extent_header_set_depth(ext4_extent_header_t *header, uint16_t depth)
168{
169 header->depth = host2uint16_t_le(depth);
170}
171
[acd869e]172uint32_t ext4_extent_header_get_generation(ext4_extent_header_t *header)
173{
174 return uint32_t_le2host(header->generation);
175}
[829d238]176
[343ccfd]177void ext4_extent_header_set_generation(ext4_extent_header_t *header,
178 uint32_t generation)
179{
180 header->generation = host2uint32_t_le(generation);
181}
182
[fffb061]183/**
184 * Binary search in extent index node
185 */
[47faec1]186static void ext4_extent_binsearch_idx(ext4_extent_header_t *header,
187 ext4_extent_index_t **index, uint32_t iblock)
188{
189 ext4_extent_index_t *r, *l, *m;
190
191 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
192
193 if (entries_count == 1) {
194 *index = EXT4_EXTENT_FIRST_INDEX(header);
195 return;
196 }
197
198 l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
199 r = l + entries_count - 1;
200
201 while (l <= r) {
202 m = l + (r - l) / 2;
203 uint32_t first_block = ext4_extent_index_get_first_block(m);
204 if (iblock < first_block) {
205 r = m - 1;
206 } else {
207 l = m + 1;
208 }
209 }
210
211 *index = l - 1;
212}
213
[fffb061]214/**
215 * Binary search in extent leaf node
216 */
[30ac3c3]217static void ext4_extent_binsearch(ext4_extent_header_t *header,
218 ext4_extent_t **extent, uint32_t iblock)
[a4419e7]219{
220 ext4_extent_t *r, *l, *m;
221
222 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
223
224 if (entries_count == 0) {
225 // this leaf is empty
[82cb6768]226// EXT4FS_DBG("EMPTY LEAF");
[47faec1]227 *extent = NULL;
228 return;
229 }
230
231 if (entries_count == 1) {
232 *extent = EXT4_EXTENT_FIRST(header);
[a4419e7]233 return;
234 }
235
236 l = EXT4_EXTENT_FIRST(header) + 1;
237 r = l + entries_count - 1;
[9104bb52]238
[0d4db0f]239 while (l < r) {
[a4419e7]240 m = l + (r - l) / 2;
[47faec1]241 uint32_t first_block = ext4_extent_get_first_block(m);
242 if (iblock < first_block) {
[a4419e7]243 r = m - 1;
244 } else {
245 l = m + 1;
246 }
247 }
248
[30ac3c3]249 *extent = l - 1;
[a4419e7]250}
251
[1ac1ab4]252// Reading routine without saving blocks to path - for saving memory during finding block
253int ext4_extent_find_block(ext4_inode_ref_t *inode_ref, uint32_t iblock, uint32_t *fblock)
[e2629b08]254{
[9104bb52]255 int rc;
[e2629b08]256
[b73530a]257 uint64_t inode_size = ext4_inode_get_size(
258 inode_ref->fs->superblock, inode_ref->inode);
259
260 uint32_t block_size = ext4_superblock_get_block_size(
261 inode_ref->fs->superblock);
262
263 uint32_t last_idx = (inode_size - 1) / block_size;
264
265 if (iblock > last_idx) {
266 *fblock = 0;
267 return EOK;
268 }
269
[1ac1ab4]270 block_t* block = NULL;
[e2629b08]271
[1ac1ab4]272 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode_ref->inode);
273 while (ext4_extent_header_get_depth(header) != 0) {
[e2629b08]274
[1ac1ab4]275 ext4_extent_index_t *index;
276 ext4_extent_binsearch_idx(header, &index, iblock);
[fffb061]277
[1ac1ab4]278 uint64_t child = ext4_extent_index_get_leaf(index);
[fffb061]279
[1ac1ab4]280 if (block != NULL) {
281 block_put(block);
282 }
[e2629b08]283
[1ac1ab4]284 rc = block_get(&block, inode_ref->fs->device, child, BLOCK_FLAGS_NONE);
[47faec1]285 if (rc != EOK) {
286 return rc;
287 }
[e2629b08]288
[1ac1ab4]289 header = (ext4_extent_header_t *)block->data;
[47faec1]290 }
[e2629b08]291
292
[0d4db0f]293 ext4_extent_t* extent = NULL;
[1ac1ab4]294 ext4_extent_binsearch(header, &extent, iblock);
[e2629b08]295
[1196df6]296 if (extent == NULL) {
297 *fblock = 0;
298 } else {
299 uint32_t phys_block;
300 phys_block = ext4_extent_get_start(extent) + iblock;
301 phys_block -= ext4_extent_get_first_block(extent);
[e2629b08]302
[1196df6]303 *fblock = phys_block;
304 }
[e2629b08]305
[1ac1ab4]306 if (block != NULL) {
307 block_put(block);
[fffb061]308 }
[9104bb52]309
[fffb061]310 return EOK;
[e2629b08]311}
312
[0d4db0f]313static int ext4_extent_find_extent(ext4_inode_ref_t *inode_ref,
314 uint32_t iblock, ext4_extent_path_t **ret_path)
315{
316 int rc;
317
318 ext4_extent_header_t *eh =
319 ext4_inode_get_extent_header(inode_ref->inode);
320
321 uint16_t depth = ext4_extent_header_get_depth(eh);
322
323 ext4_extent_path_t *tmp_path;
324
325 // Added 2 for possible tree growing
326 tmp_path = malloc(sizeof(ext4_extent_path_t) * (depth + 2));
327 if (tmp_path == NULL) {
328 return ENOMEM;
329 }
330
331 tmp_path[0].block = inode_ref->block;
332 tmp_path[0].header = eh;
333
334 uint16_t pos = 0;
335 while (ext4_extent_header_get_depth(eh) != 0) {
336
337 ext4_extent_binsearch_idx(tmp_path[pos].header, &tmp_path[pos].index, iblock);
338
339 tmp_path[pos].depth = depth;
340 tmp_path[pos].extent = NULL;
341
342 assert(tmp_path[pos].index != NULL);
343
344 uint64_t fblock = ext4_extent_index_get_leaf(tmp_path[pos].index);
345
346 block_t *block;
347 rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NONE);
348 if (rc != EOK) {
[6f413125]349 goto cleanup;
[0d4db0f]350 }
351
352 pos++;
353
354 eh = (ext4_extent_header_t *)block->data;
355 tmp_path[pos].block = block;
356 tmp_path[pos].header = eh;
357
358 }
359
360 tmp_path[pos].depth = 0;
361 tmp_path[pos].extent = NULL;
362 tmp_path[pos].index = NULL;
363
364 /* find extent */
365 ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent, iblock);
366
367 *ret_path = tmp_path;
368
369 return EOK;
[6f413125]370
371cleanup:
372 // Put loaded blocks
373 // From 1 -> 0 is a block with inode data
374 for (uint16_t i = 1; i < tmp_path->depth; ++i) {
375 if (tmp_path[i].block) {
376 block_put(tmp_path[i].block);
377 }
378 }
379
380 // Destroy temporary data structure
381 free(tmp_path);
382
383 return rc;
384
[0d4db0f]385}
386
[5b0a3946]387static int ext4_extent_release(ext4_inode_ref_t *inode_ref, ext4_extent_t* extent)
[0d4db0f]388{
389 int rc;
390
[5b0a3946]391 uint64_t start = ext4_extent_get_start(extent);
392 uint16_t block_count = ext4_extent_get_block_count(extent);
393
394 rc = ext4_balloc_free_blocks(inode_ref, start, block_count);
395 if (rc != EOK) {
396 EXT4FS_DBG("ERROR");
397 return rc;
398 }
399
400 return EOK;
401}
402
403// Recursive release
404static int ext4_extent_release_branch(ext4_inode_ref_t *inode_ref,
405 ext4_extent_index_t *index)
406{
407 int rc;
408
409 block_t* block;
410
411 uint32_t fblock = ext4_extent_index_get_leaf(index);
412
[82cb6768]413// EXT4FS_DBG("fblock = \%u", fblock);
[5b0a3946]414
415 rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NOREAD);
416 if (rc != EOK) {
417 EXT4FS_DBG("ERROR get_block");
418 return rc;
419 }
420
421 ext4_extent_header_t *header = block->data;
422
423 if (ext4_extent_header_get_depth(header)) {
424
425 ext4_extent_index_t *idx = EXT4_EXTENT_FIRST_INDEX(header);
426
427 for (uint32_t i = 0; i < ext4_extent_header_get_entries_count(header); ++i, ++idx) {
428 rc = ext4_extent_release_branch(inode_ref, idx);
429 if (rc != EOK) {
430 EXT4FS_DBG("error recursion");
431 return rc;
432 }
433 }
434 } else {
435 ext4_extent_t *ext = EXT4_EXTENT_FIRST(header);
436
437 for (uint32_t i = 0; i < ext4_extent_header_get_entries_count(header); ++i, ++ext) {
438 rc = ext4_extent_release(inode_ref, ext);
439 if (rc != EOK) {
440 EXT4FS_DBG("error recursion");
441 return rc;
442 }
443 }
444 }
445
446 rc = block_put(block);
447 if (rc != EOK) {
448 EXT4FS_DBG("ERROR put_block");
449 return rc;
450 }
451
452 ext4_balloc_free_block(inode_ref, fblock);
453
454 return EOK;
455}
456
[1196df6]457int ext4_extent_release_blocks_from(ext4_inode_ref_t *inode_ref,
458 uint32_t iblock_from)
[5b0a3946]459{
[6f413125]460 int rc = EOK;
[5b0a3946]461
[3e2952b]462 // Find the first extent to modify
[0d4db0f]463 ext4_extent_path_t *path;
[5b0a3946]464 rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);
[0d4db0f]465 if (rc != EOK) {
466 return rc;
467 }
468
[3e2952b]469 // Jump to last item of the path (extent)
[0d4db0f]470 ext4_extent_path_t *path_ptr = path;
471 while (path_ptr->depth != 0) {
472 path_ptr++;
473 }
474
475 assert(path_ptr->extent != NULL);
476
[3e2952b]477 // First extent maybe released partially
[5b0a3946]478 uint32_t first_fblock;
479 first_fblock = ext4_extent_get_start(path_ptr->extent) + iblock_from;
480 first_fblock -= ext4_extent_get_first_block(path_ptr->extent);
[0d4db0f]481
482 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
483
[5b0a3946]484 uint16_t delete_count = block_count - first_fblock +
485 ext4_extent_get_start(path_ptr->extent);
486
487 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
[3e2952b]488 if (rc != EOK) {
[6f413125]489 goto cleanup;
[3e2952b]490 }
[0d4db0f]491
[5b0a3946]492 block_count -= delete_count;
[0d4db0f]493 ext4_extent_set_block_count(path_ptr->extent, block_count);
494
[3e2952b]495 uint16_t entries = ext4_extent_header_get_entries_count(path_ptr->header);
496 ext4_extent_t *tmp_ext = path_ptr->extent + 1;
497 ext4_extent_t *stop_ext = EXT4_EXTENT_FIRST(path_ptr->header) + entries;
[5b0a3946]498
[3e2952b]499 // If first extent empty, release it
[0d4db0f]500 if (block_count == 0) {
501 entries--;
502 ext4_extent_header_set_entries_count(path_ptr->header, entries);
503 }
504
[3e2952b]505 // Release all successors of the first extent in the same node
506 while (tmp_ext < stop_ext) {
507 first_fblock = ext4_extent_get_start(tmp_ext);
508 delete_count = ext4_extent_get_block_count(tmp_ext);
[5b0a3946]509
[3e2952b]510 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
511 if (rc != EOK) {
[6f413125]512 goto cleanup;
[3e2952b]513 }
[5b0a3946]514
[3e2952b]515 entries--;
516 ext4_extent_header_set_entries_count(path_ptr->header, entries);
[5b0a3946]517
[3e2952b]518 tmp_ext++;
519 }
[5b0a3946]520
[3e2952b]521 // If leaf node is empty, the whole tree must be checked and the node will be released
522 bool check_tree = false;
[5b0a3946]523
[3e2952b]524 // Don't release root block (including inode data) !!!
525 if ((path_ptr != path) && (entries == 0)) {
526 rc = ext4_balloc_free_block(inode_ref, path_ptr->block->lba);
527 if (rc != EOK) {
[6f413125]528 goto cleanup;
[001307cf]529 }
[3e2952b]530 check_tree = true;
[5b0a3946]531 }
[001307cf]532
[3e2952b]533 // Jump to the parent
534 --path_ptr;
[5b0a3946]535
[3e2952b]536 // release all successors in all levels
537 while(path_ptr >= path) {
538 entries = ext4_extent_header_get_entries_count(path_ptr->header);
539 ext4_extent_index_t *index = path_ptr->index + 1;
540 ext4_extent_index_t *stop =
541 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
[001307cf]542
[3e2952b]543 if (check_tree) {
544 entries--;
545 ext4_extent_header_set_entries_count(path_ptr->header, entries);
[001307cf]546 }
[0d4db0f]547
[5b0a3946]548 while (index < stop) {
549 rc = ext4_extent_release_branch(inode_ref, index);
550 if (rc != EOK) {
[6f413125]551 goto cleanup;
[5b0a3946]552 }
553 ++index;
[3e2952b]554 --entries;
555 ext4_extent_header_set_entries_count(path_ptr->header, entries);
[5b0a3946]556 }
557
[3e2952b]558 path_ptr->block->dirty = true;
[5b0a3946]559
[3e2952b]560 if ((entries == 0) && (path_ptr != path)) {
561 rc = ext4_balloc_free_block(inode_ref, path_ptr->block->lba);
[5b0a3946]562 if (rc != EOK) {
[6f413125]563 goto cleanup;
[5b0a3946]564 }
[3e2952b]565 check_tree = true;
566 } else {
567 check_tree = false;
[5b0a3946]568 }
[3e2952b]569
570 --path_ptr;
[0d4db0f]571 }
572
[3e2952b]573
[6f413125]574cleanup:
[0d4db0f]575 // Put loaded blocks
576 // From 1 -> 0 is a block with inode data
[82cb6768]577 for (uint16_t i = 1; i <= path->depth; ++i) {
[0d4db0f]578 if (path[i].block) {
579 block_put(path[i].block);
580 }
581 }
582
583 // Destroy temporary data structure
584 free(path);
585
[6f413125]586 return rc;
[0d4db0f]587}
[1ac1ab4]588
[82cb6768]589static int ext4_extent_append_extent(ext4_inode_ref_t *inode_ref,
590 ext4_extent_path_t *path, ext4_extent_path_t **last_path_item,
591 uint32_t iblock)
592{
[7eb033ce]593 EXT4FS_DBG("");
[82cb6768]594 int rc;
595
596 ext4_extent_path_t *path_ptr = *last_path_item;
597
598 uint16_t entries = ext4_extent_header_get_entries_count(path_ptr->header);
599 uint16_t limit = ext4_extent_header_get_max_entries_count(path_ptr->header);
600
601 // Trivial way - no splitting
602 if (entries < limit) {
[7eb033ce]603 EXT4FS_DBG("adding extent entry");
604
[82cb6768]605 ext4_extent_header_set_entries_count(path_ptr->header, entries + 1);
606 path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header) + entries;
607 ext4_extent_set_block_count(path_ptr->extent, 0);
608 ext4_extent_set_first_block(path_ptr->extent, iblock);
609 ext4_extent_set_start(path_ptr->extent, 0);
610 path_ptr->block->dirty = true;
611
612 return EOK;
613 }
614
615 uint32_t block_size =
616 ext4_superblock_get_block_size(inode_ref->fs->superblock);
617
[7eb033ce]618 // Trivial tree - grow (extents were in root node)
[82cb6768]619 if (path_ptr == path) {
620
621 uint32_t new_fblock;
622 rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
623 if (rc != EOK) {
624 EXT4FS_DBG("error in block allocation");
625 return rc;
626 }
627
628 block_t *block;
629 rc = block_get(&block, inode_ref->fs->device,
630 new_fblock, BLOCK_FLAGS_NOREAD);
631 if (rc != EOK) {
632 EXT4FS_DBG("error in block_get");
633 return rc;
634 }
635
636 memset(block->data, 0, block_size);
637
638 // Move data from root to the new block
639 memcpy(block->data, inode_ref->inode->blocks,
640 EXT4_INODE_BLOCKS * sizeof(uint32_t));
641
642 path_ptr++;
643 path_ptr->block = block;
644 path_ptr->header = (ext4_extent_header_t *)block->data;
645 path_ptr->depth = ext4_extent_header_get_depth(path_ptr->header);
646 path_ptr->index = NULL;
647
648 uint16_t entries = ext4_extent_header_get_entries_count(path_ptr->header);
649 path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header) + entries;
650 ext4_extent_header_set_entries_count(path_ptr->header, entries + 1);
651 uint16_t limit = (block_size - sizeof(ext4_extent_header_t)) /
652 sizeof(ext4_extent_t);
653 ext4_extent_header_set_max_entries_count(path_ptr->header, limit);
654
655 // Modify root (in inode)
656 path->depth = 1;
657 path->extent = NULL;
658 path->index = EXT4_EXTENT_FIRST_INDEX(path->header);
659
660 ext4_extent_header_set_depth(path->header, path_ptr->depth + 1);
661 ext4_extent_header_set_entries_count(path->header, 1);
662
663 ext4_extent_index_set_first_block(path->index, 0);
664 ext4_extent_index_set_leaf(path->index, new_fblock);
665
666 path_ptr->block->dirty = true;
667 path->block->dirty = true;
668
669 *last_path_item = path_ptr;
670
671 return EOK;
672 }
673
[7eb033ce]674 assert(false);
675
[82cb6768]676 // start splitting
677 uint32_t fblock = 0;
678 while (path_ptr > path) {
679
[7eb033ce]680 // TODO
681
[82cb6768]682 rc = ext4_balloc_alloc_block(inode_ref, &fblock);
683 if (rc != EOK) {
684 return rc;
685 }
686
687 block_t *block;
688 rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NOREAD);
689 if (rc != EOK) {
690 ext4_balloc_free_block(inode_ref, fblock);
691 return rc;
692 }
693
694 // Init block
695 memset(block->data, 0, block_size);
696
697 // Not modified
698 block_put(path_ptr->block);
699 path_ptr->block = block;
700
701 path_ptr->header = block->data;
702
703 if (path_ptr->depth) {
704 path_ptr->index = EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
705 } else {
706 path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header);
707 }
[7eb033ce]708
709 path_ptr--;
710 }
711
712 // If splitting reached root node
713 if (path_ptr == path) {
714
715 uint32_t new_fblock;
716 rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
717 if (rc != EOK) {
718 EXT4FS_DBG("error in block allocation");
719 return rc;
720 }
721
722 block_t *block;
723 rc = block_get(&block, inode_ref->fs->device,
724 new_fblock, BLOCK_FLAGS_NOREAD);
725 if (rc != EOK) {
726 EXT4FS_DBG("error in block_get");
727 return rc;
728 }
729
730 memset(block->data, 0, block_size);
731
732 // Move data from root to the new block
733 memcpy(block->data, inode_ref->inode->blocks,
734 EXT4_INODE_BLOCKS * sizeof(uint32_t));
735
736 path_ptr++;
737 path_ptr->block = block;
738 path_ptr->header = (ext4_extent_header_t *)block->data;
739 path_ptr->depth = ext4_extent_header_get_depth(path_ptr->header);
740 path_ptr->index = NULL;
741
742 uint16_t entries = ext4_extent_header_get_entries_count(path_ptr->header);
743 path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header) + entries;
744 ext4_extent_header_set_entries_count(path_ptr->header, entries + 1);
745 uint16_t limit = (block_size - sizeof(ext4_extent_header_t)) /
746 sizeof(ext4_extent_t);
747 ext4_extent_header_set_max_entries_count(path_ptr->header, limit);
748
749 // Modify root (in inode)
750 path->depth = 1;
751 path->extent = NULL;
752 path->index = EXT4_EXTENT_FIRST_INDEX(path->header);
753
754 ext4_extent_header_set_depth(path->header, path_ptr->depth + 1);
755 ext4_extent_header_set_entries_count(path->header, 1);
756
757 ext4_extent_index_set_first_block(path->index, 0);
758 ext4_extent_index_set_leaf(path->index, new_fblock);
759
760 path_ptr->block->dirty = true;
761 path->block->dirty = true;
762
763 *last_path_item = path_ptr;
764
765 return EOK;
[82cb6768]766 }
767
768 return EOK;
769}
770
[ce6de59]771int ext4_extent_append_block(ext4_inode_ref_t *inode_ref,
772 uint32_t *iblock, uint32_t *fblock)
773{
[7eb033ce]774 EXT4FS_DBG("");
[6f413125]775 int rc = EOK;
[ce6de59]776
777 ext4_superblock_t *sb = inode_ref->fs->superblock;
778 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
779 uint32_t block_size = ext4_superblock_get_block_size(sb);
[b73530a]780
[82cb6768]781 // Calculate number of new logical block
[b73530a]782 uint32_t new_block_idx = 0;
783 if (inode_size > 0) {
784 if ((inode_size % block_size) != 0) {
785 inode_size += block_size - (inode_size % block_size);
786 }
787 new_block_idx = inode_size / block_size;
788 }
[ce6de59]789
[82cb6768]790 // Load the nearest leaf (with extent)
[ce6de59]791 ext4_extent_path_t *path;
792 rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
793 if (rc != EOK) {
794 return rc;
795 }
796
797 // Jump to last item of the path (extent)
798 ext4_extent_path_t *path_ptr = path;
799 while (path_ptr->depth != 0) {
800 path_ptr++;
801 }
802
[82cb6768]803 // Add new extent to the node
804 if (path_ptr->extent == NULL) {
805 goto append_extent;
806 }
[936132f]807
[82cb6768]808 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
809 uint16_t block_limit = (1 << 15);
[936132f]810
[b6d7b7c]811 uint32_t phys_block = 0;
[82cb6768]812 if (block_count < block_limit) {
[ce6de59]813
[82cb6768]814 if (block_count == 0) {
[ce6de59]815
[82cb6768]816 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
817 if (rc != EOK) {
[7eb033ce]818 goto finish;
[82cb6768]819 }
[ce6de59]820
[82cb6768]821 ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
822 ext4_extent_set_start(path_ptr->extent, phys_block);
823 ext4_extent_set_block_count(path_ptr->extent, 1);
[b73530a]824
[b6d7b7c]825 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
826 inode_ref->dirty = true;
827
[82cb6768]828 path_ptr->block->dirty = true;
[ce6de59]829
[6f413125]830 goto finish;
[82cb6768]831 } else {
[ce6de59]832
[82cb6768]833 phys_block = ext4_extent_get_start(path_ptr->extent);
834 phys_block += ext4_extent_get_block_count(path_ptr->extent);
[ce6de59]835
[82cb6768]836 bool free;
837 rc = ext4_balloc_try_alloc_block(inode_ref, phys_block, &free);
838 if (rc != EOK) {
[7eb033ce]839 goto finish;
[82cb6768]840 }
[ce6de59]841
[82cb6768]842 if (! free) {
843 // target is not free
844 goto append_extent;
845 }
[ce6de59]846
[b73530a]847
[82cb6768]848 ext4_extent_set_block_count(path_ptr->extent, block_count + 1);
[b73530a]849
[b6d7b7c]850 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
851 inode_ref->dirty = true;
852
[82cb6768]853 path_ptr->block->dirty = true;
[b73530a]854
[82cb6768]855 goto finish;
856 }
857 }
[b73530a]858
[82cb6768]859append_extent:
[ce6de59]860
[82cb6768]861 phys_block = 0;
862 // Allocate and insert insert new block
863 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
864 if (rc != EOK) {
865 EXT4FS_DBG("error in block allocation, rc = \%d", rc);
866 goto finish;
867 }
[b73530a]868
[82cb6768]869 rc = ext4_extent_append_extent(inode_ref, path, &path_ptr, new_block_idx);
870 if (rc != EOK) {
871 ext4_balloc_free_block(inode_ref, phys_block);
872 goto finish;
[ce6de59]873 }
874
[82cb6768]875 ext4_extent_set_block_count(path_ptr->extent, 1);
876 ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
877 ext4_extent_set_start(path_ptr->extent, phys_block);
878
[b6d7b7c]879 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
880 inode_ref->dirty = true;
881
[82cb6768]882 path_ptr->block->dirty = true;
[ce6de59]883
884finish:
[1196df6]885
886 *iblock = new_block_idx;
887 *fblock = phys_block;
888
[ce6de59]889 // Put loaded blocks
890 // From 1 -> 0 is a block with inode data
[82cb6768]891 for (uint16_t i = 1; i <= path->depth; ++i) {
[ce6de59]892 if (path[i].block) {
893 block_put(path[i].block);
894 }
895 }
896
897 // Destroy temporary data structure
898 free(path);
899
[6f413125]900 return rc;
[ce6de59]901}
902
[829d238]903/**
904 * @}
905 */
Note: See TracBrowser for help on using the repository browser.