Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ext4/src/extent.c

    r5a6cc679 ra35b458  
    295295        ext4_extent_index_t *l;
    296296        ext4_extent_index_t *m;
    297        
     297
    298298        uint16_t entries_count =
    299299            ext4_extent_header_get_entries_count(header);
    300        
     300
    301301        /* Initialize bounds */
    302302        l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
    303303        r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
    304        
     304
    305305        /* Do binary search */
    306306        while (l <= r) {
    307307                m = l + (r - l) / 2;
    308308                uint32_t first_block = ext4_extent_index_get_first_block(m);
    309                
     309
    310310                if (iblock < first_block)
    311311                        r = m - 1;
     
    313313                        l = m + 1;
    314314        }
    315        
     315
    316316        /* Set output value */
    317317        *index = l - 1;
     
    332332        ext4_extent_t *l;
    333333        ext4_extent_t *m;
    334        
     334
    335335        uint16_t entries_count =
    336336            ext4_extent_header_get_entries_count(header);
    337        
     337
    338338        if (entries_count == 0) {
    339339                /* this leaf is empty */
     
    341341                return;
    342342        }
    343        
     343
    344344        /* Initialize bounds */
    345345        l = EXT4_EXTENT_FIRST(header) + 1;
    346346        r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
    347        
     347
    348348        /* Do binary search */
    349349        while (l <= r) {
    350350                m = l + (r - l) / 2;
    351351                uint32_t first_block = ext4_extent_get_first_block(m);
    352                
     352
    353353                if (iblock < first_block)
    354354                        r = m - 1;
     
    356356                        l = m + 1;
    357357        }
    358        
     358
    359359        /* Set output value */
    360360        *extent = l - 1;
     
    379379        uint64_t inode_size =
    380380            ext4_inode_get_size(inode_ref->fs->superblock, inode_ref->inode);
    381        
     381
    382382        uint32_t block_size =
    383383            ext4_superblock_get_block_size(inode_ref->fs->superblock);
    384        
     384
    385385        uint32_t last_idx = (inode_size - 1) / block_size;
    386        
     386
    387387        /* Check if requested iblock is not over size of i-node */
    388388        if (iblock > last_idx) {
     
    390390                return EOK;
    391391        }
    392        
     392
    393393        block_t *block = NULL;
    394        
     394
    395395        /* Walk through extent tree */
    396396        ext4_extent_header_t *header =
    397397            ext4_inode_get_extent_header(inode_ref->inode);
    398        
     398
    399399        while (ext4_extent_header_get_depth(header) != 0) {
    400400                /* Search index in node */
    401401                ext4_extent_index_t *index;
    402402                ext4_extent_binsearch_idx(header, &index, iblock);
    403                
     403
    404404                /* Load child node and set values for the next iteration */
    405405                uint64_t child = ext4_extent_index_get_leaf(index);
    406                
     406
    407407                if (block != NULL) {
    408408                        rc = block_put(block);
     
    410410                                return rc;
    411411                }
    412                
     412
    413413                rc = block_get(&block, inode_ref->fs->device, child,
    414414                    BLOCK_FLAGS_NONE);
    415415                if (rc != EOK)
    416416                        return rc;
    417                
     417
    418418                header = (ext4_extent_header_t *)block->data;
    419419        }
    420        
     420
    421421        /* Search extent in the leaf block */
    422422        ext4_extent_t* extent = NULL;
    423423        ext4_extent_binsearch(header, &extent, iblock);
    424        
     424
    425425        /* Prevent empty leaf */
    426426        if (extent == NULL) {
     
    431431                uint32_t first = ext4_extent_get_first_block(extent);
    432432                phys_block = ext4_extent_get_start(extent) + iblock - first;
    433                
     433
    434434                *fblock = phys_block;
    435435        }
    436        
     436
    437437        /* Cleanup */
    438438        if (block != NULL)
    439439                rc = block_put(block);
    440        
     440
    441441        return rc;
    442442}
     
    459459        ext4_extent_header_t *eh =
    460460            ext4_inode_get_extent_header(inode_ref->inode);
    461        
     461
    462462        uint16_t depth = ext4_extent_header_get_depth(eh);
    463        
     463
    464464        ext4_extent_path_t *tmp_path;
    465        
     465
    466466        /* Added 2 for possible tree growing */
    467467        tmp_path = malloc(sizeof(ext4_extent_path_t) * (depth + 2));
    468468        if (tmp_path == NULL)
    469469                return ENOMEM;
    470        
     470
    471471        /* Initialize structure for algorithm start */
    472472        tmp_path[0].block = inode_ref->block;
    473473        tmp_path[0].header = eh;
    474        
     474
    475475        /* Walk through the extent tree */
    476476        uint16_t pos = 0;
     
    480480                ext4_extent_binsearch_idx(tmp_path[pos].header,
    481481                    &tmp_path[pos].index, iblock);
    482                
     482
    483483                tmp_path[pos].depth = depth;
    484484                tmp_path[pos].extent = NULL;
    485                
     485
    486486                assert(tmp_path[pos].index != NULL);
    487                
     487
    488488                /* Load information for the next iteration */
    489489                uint64_t fblock = ext4_extent_index_get_leaf(tmp_path[pos].index);
    490                
     490
    491491                block_t *block;
    492492                rc = block_get(&block, inode_ref->fs->device, fblock,
     
    494494                if (rc != EOK)
    495495                        goto cleanup;
    496                
     496
    497497                pos++;
    498                
     498
    499499                eh = (ext4_extent_header_t *)block->data;
    500500                tmp_path[pos].block = block;
    501501                tmp_path[pos].header = eh;
    502502        }
    503        
     503
    504504        tmp_path[pos].depth = 0;
    505505        tmp_path[pos].extent = NULL;
    506506        tmp_path[pos].index = NULL;
    507        
     507
    508508        /* Find extent in the leaf node */
    509509        ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent, iblock);
    510510        *ret_path = tmp_path;
    511        
     511
    512512        return EOK;
    513        
     513
    514514cleanup:
    515515        ;
     
    528528                }
    529529        }
    530        
     530
    531531        /* Destroy temporary data structure */
    532532        free(tmp_path);
    533        
     533
    534534        return rc;
    535535}
     
    549549        uint64_t start = ext4_extent_get_start(extent);
    550550        uint16_t block_count = ext4_extent_get_block_count(extent);
    551        
     551
    552552        return ext4_balloc_free_blocks(inode_ref, start, block_count);
    553553}
     
    569569{
    570570        uint32_t fblock = ext4_extent_index_get_leaf(index);
    571        
     571
    572572        block_t* block;
    573573        errno_t rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NONE);
    574574        if (rc != EOK)
    575575                return rc;
    576        
     576
    577577        ext4_extent_header_t *header = block->data;
    578        
     578
    579579        if (ext4_extent_header_get_depth(header)) {
    580580                /* The node is non-leaf, do recursion */
    581581                ext4_extent_index_t *idx = EXT4_EXTENT_FIRST_INDEX(header);
    582                
     582
    583583                /* Release all subbranches */
    584584                for (uint32_t i = 0;
     
    592592                /* Leaf node reached */
    593593                ext4_extent_t *ext = EXT4_EXTENT_FIRST(header);
    594                
     594
    595595                /* Release all extents and stop recursion */
    596596                for (uint32_t i = 0;
     
    602602                }
    603603        }
    604        
     604
    605605        /* Release data block where the node was stored */
    606        
     606
    607607        rc = block_put(block);
    608608        if (rc != EOK)
    609609                return rc;
    610        
     610
    611611        return ext4_balloc_free_block(inode_ref, fblock);
    612612}
     
    626626        if (rc != EOK)
    627627                return rc;
    628        
     628
    629629        /* Jump to last item of the path (extent) */
    630630        ext4_extent_path_t *path_ptr = path;
    631631        while (path_ptr->depth != 0)
    632632                path_ptr++;
    633        
     633
    634634        assert(path_ptr->extent != NULL);
    635        
     635
    636636        /* First extent maybe released partially */
    637637        uint32_t first_iblock =
     
    639639        uint32_t first_fblock =
    640640            ext4_extent_get_start(path_ptr->extent) + iblock_from - first_iblock;
    641        
     641
    642642        uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
    643        
     643
    644644        uint16_t delete_count = block_count -
    645645            (ext4_extent_get_start(path_ptr->extent) - first_fblock);
    646        
     646
    647647        /* Release all blocks */
    648648        rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
    649649        if (rc != EOK)
    650650                goto cleanup;
    651        
     651
    652652        /* Correct counter */
    653653        block_count -= delete_count;
    654654        ext4_extent_set_block_count(path_ptr->extent, block_count);
    655        
     655
    656656        /* Initialize the following loop */
    657657        uint16_t entries =
     
    659659        ext4_extent_t *tmp_ext = path_ptr->extent + 1;
    660660        ext4_extent_t *stop_ext = EXT4_EXTENT_FIRST(path_ptr->header) + entries;
    661        
     661
    662662        /* If first extent empty, release it */
    663663        if (block_count == 0)
    664664                entries--;
    665        
     665
    666666        /* Release all successors of the first extent in the same node */
    667667        while (tmp_ext < stop_ext) {
    668668                first_fblock = ext4_extent_get_start(tmp_ext);
    669669                delete_count = ext4_extent_get_block_count(tmp_ext);
    670                
     670
    671671                rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
    672672                if (rc != EOK)
    673673                        goto cleanup;
    674                
     674
    675675                entries--;
    676676                tmp_ext++;
    677677        }
    678        
     678
    679679        ext4_extent_header_set_entries_count(path_ptr->header, entries);
    680680        path_ptr->block->dirty = true;
    681        
     681
    682682        /* If leaf node is empty, parent entry must be modified */
    683683        bool remove_parent_record = false;
    684        
     684
    685685        /* Don't release root block (including inode data) !!! */
    686686        if ((path_ptr != path) && (entries == 0)) {
     
    688688                if (rc != EOK)
    689689                        goto cleanup;
    690                
     690
    691691                remove_parent_record = true;
    692692        }
    693        
     693
    694694        /* Jump to the parent */
    695695        --path_ptr;
    696        
     696
    697697        /* Release all successors in all tree levels */
    698698        while (path_ptr >= path) {
     
    701701                ext4_extent_index_t *stop =
    702702                    EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
    703                
     703
    704704                /* Correct entries count because of changes in the previous iteration */
    705705                if (remove_parent_record)
    706706                        entries--;
    707                
     707
    708708                /* Iterate over all entries and release the whole subtrees */
    709709                while (index < stop) {
     
    711711                        if (rc != EOK)
    712712                                goto cleanup;
    713                        
     713
    714714                        ++index;
    715715                        --entries;
    716716                }
    717                
     717
    718718                ext4_extent_header_set_entries_count(path_ptr->header, entries);
    719719                path_ptr->block->dirty = true;
    720                
     720
    721721                /* Free the node if it is empty */
    722722                if ((entries == 0) && (path_ptr != path)) {
     
    724724                        if (rc != EOK)
    725725                                goto cleanup;
    726                        
     726
    727727                        /* Mark parent to be checked */
    728728                        remove_parent_record = true;
    729729                } else
    730730                        remove_parent_record = false;
    731                
     731
    732732                --path_ptr;
    733733        }
    734        
     734
    735735cleanup:
    736736        ;
     
    749749                }
    750750        }
    751        
     751
    752752        /* Destroy temporary data structure */
    753753        free(path);
    754        
     754
    755755        return rc;
    756756}
     
    771771{
    772772        ext4_extent_path_t *path_ptr = path + path->depth;
    773        
     773
    774774        uint32_t block_size =
    775775            ext4_superblock_get_block_size(inode_ref->fs->superblock);
    776        
     776
    777777        /* Start splitting */
    778778        while (path_ptr > path) {
     
    781781                uint16_t limit =
    782782                    ext4_extent_header_get_max_entries_count(path_ptr->header);
    783                
     783
    784784                if (entries == limit) {
    785785                        /* Full node - allocate block for new one */
     
    788788                        if (rc != EOK)
    789789                                return rc;
    790                        
     790
    791791                        block_t *block;
    792792                        rc = block_get(&block, inode_ref->fs->device, fblock,
     
    796796                                return rc;
    797797                        }
    798                        
     798
    799799                        /* Put back not modified old block */
    800800                        rc = block_put(path_ptr->block);
     
    804804                                return rc;
    805805                        }
    806                        
     806
    807807                        /* Initialize newly allocated block and remember it */
    808808                        memset(block->data, 0, block_size);
    809809                        path_ptr->block = block;
    810                        
     810
    811811                        /* Update pointers in extent path structure */
    812812                        path_ptr->header = block->data;
     
    823823                                    sizeof(ext4_extent_t);
    824824                        }
    825                        
     825
    826826                        /* Initialize on-disk structure (header) */
    827827                        ext4_extent_header_set_entries_count(path_ptr->header, 1);
     
    830830                        ext4_extent_header_set_depth(path_ptr->header, path_ptr->depth);
    831831                        ext4_extent_header_set_generation(path_ptr->header, 0);
    832                        
     832
    833833                        path_ptr->block->dirty = true;
    834                        
     834
    835835                        /* Jump to the preceeding item */
    836836                        path_ptr--;
     
    845845                                ext4_extent_set_first_block(path_ptr->extent, iblock);
    846846                        }
    847                        
     847
    848848                        ext4_extent_header_set_entries_count(path_ptr->header, entries + 1);
    849849                        path_ptr->block->dirty = true;
    850                        
     850
    851851                        /* No more splitting needed */
    852852                        return EOK;
    853853                }
    854854        }
    855        
     855
    856856        assert(path_ptr == path);
    857        
     857
    858858        /* Should be the root split too? */
    859        
     859
    860860        uint16_t entries = ext4_extent_header_get_entries_count(path->header);
    861861        uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
    862        
     862
    863863        if (entries == limit) {
    864864                uint32_t new_fblock;
     
    866866                if (rc != EOK)
    867867                        return rc;
    868                
     868
    869869                block_t *block;
    870870                rc = block_get(&block, inode_ref->fs->device, new_fblock,
     
    872872                if (rc != EOK)
    873873                        return rc;
    874                
     874
    875875                /* Initialize newly allocated block */
    876876                memset(block->data, 0, block_size);
    877                
     877
    878878                /* Move data from root to the new block */
    879879                memcpy(block->data, inode_ref->inode->blocks,
    880880                    EXT4_INODE_BLOCKS * sizeof(uint32_t));
    881                
     881
    882882                /* Data block is initialized */
    883                
     883
    884884                block_t *root_block = path->block;
    885885                uint16_t root_depth = path->depth;
    886886                ext4_extent_header_t *root_header = path->header;
    887                
     887
    888888                /* Make space for tree growing */
    889889                ext4_extent_path_t *new_root = path;
    890890                ext4_extent_path_t *old_root = path + 1;
    891                
     891
    892892                size_t nbytes = sizeof(ext4_extent_path_t) * (path->depth + 1);
    893893                memmove(old_root, new_root, nbytes);
    894894                memset(new_root, 0, sizeof(ext4_extent_path_t));
    895                
     895
    896896                /* Update old root structure */
    897897                old_root->block = block;
    898898                old_root->header = (ext4_extent_header_t *)block->data;
    899                
     899
    900900                /* Add new entry and update limit for entries */
    901901                if (old_root->depth) {
     
    913913                        old_root->index = NULL;
    914914                }
    915                
     915
    916916                ext4_extent_header_set_entries_count(old_root->header, entries + 1);
    917917                ext4_extent_header_set_max_entries_count(old_root->header, limit);
    918                
     918
    919919                old_root->block->dirty = true;
    920                
     920
    921921                /* Re-initialize new root metadata */
    922922                new_root->depth = root_depth + 1;
     
    925925                new_root->extent = NULL;
    926926                new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
    927                
     927
    928928                ext4_extent_header_set_depth(new_root->header, new_root->depth);
    929                
     929
    930930                /* Create new entry in root */
    931931                ext4_extent_header_set_entries_count(new_root->header, 1);
    932932                ext4_extent_index_set_first_block(new_root->index, 0);
    933933                ext4_extent_index_set_leaf(new_root->index, new_fblock);
    934                
     934
    935935                new_root->block->dirty = true;
    936936        } else {
     
    943943                        ext4_extent_set_first_block(path->extent, iblock);
    944944                }
    945                
     945
    946946                ext4_extent_header_set_entries_count(path->header, entries + 1);
    947947                path->block->dirty = true;
    948948        }
    949        
     949
    950950        return EOK;
    951951}
     
    970970        uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
    971971        uint32_t block_size = ext4_superblock_get_block_size(sb);
    972        
     972
    973973        /* Calculate number of new logical block */
    974974        uint32_t new_block_idx = 0;
     
    976976                if ((inode_size % block_size) != 0)
    977977                        inode_size += block_size - (inode_size % block_size);
    978                
     978
    979979                new_block_idx = inode_size / block_size;
    980980        }
    981        
     981
    982982        /* Load the nearest leaf (with extent) */
    983983        ext4_extent_path_t *path;
     
    985985        if (rc != EOK)
    986986                return rc;
    987        
     987
    988988        /* Jump to last item of the path (extent) */
    989989        ext4_extent_path_t *path_ptr = path;
    990990        while (path_ptr->depth != 0)
    991991                path_ptr++;
    992        
     992
    993993        /* Add new extent to the node if not present */
    994994        if (path_ptr->extent == NULL)
    995995                goto append_extent;
    996        
     996
    997997        uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
    998998        uint16_t block_limit = (1 << 15);
    999        
     999
    10001000        uint32_t phys_block = 0;
    10011001        if (block_count < block_limit) {
     
    10061006                        if (rc != EOK)
    10071007                                goto finish;
    1008                        
     1008
    10091009                        /* Initialize extent */
    10101010                        ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
    10111011                        ext4_extent_set_start(path_ptr->extent, phys_block);
    10121012                        ext4_extent_set_block_count(path_ptr->extent, 1);
    1013                        
     1013
    10141014                        /* Update i-node */
    10151015                        if (update_size) {
     
    10171017                                inode_ref->dirty = true;
    10181018                        }
    1019                        
     1019
    10201020                        path_ptr->block->dirty = true;
    1021                        
     1021
    10221022                        goto finish;
    10231023                } else {
     
    10251025                        phys_block = ext4_extent_get_start(path_ptr->extent);
    10261026                        phys_block += ext4_extent_get_block_count(path_ptr->extent);
    1027                        
     1027
    10281028                        /* Check if the following block is free for allocation */
    10291029                        bool free;
     
    10311031                        if (rc != EOK)
    10321032                                goto finish;
    1033                        
     1033
    10341034                        if (!free) {
    10351035                                /* Target is not free, new block must be appended to new extent */
    10361036                                goto append_extent;
    10371037                        }
    1038                        
     1038
    10391039                        /* Update extent */
    10401040                        ext4_extent_set_block_count(path_ptr->extent, block_count + 1);
    1041                        
     1041
    10421042                        /* Update i-node */
    10431043                        if (update_size) {
     
    10451045                                inode_ref->dirty = true;
    10461046                        }
    1047                        
     1047
    10481048                        path_ptr->block->dirty = true;
    1049                        
     1049
    10501050                        goto finish;
    10511051                }
    10521052        }
    1053        
    1054        
     1053
     1054
    10551055append_extent:
    10561056        /* Append new extent to the tree */
    10571057        phys_block = 0;
    1058        
     1058
    10591059        /* Allocate new data block */
    10601060        rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
    10611061        if (rc != EOK)
    10621062                goto finish;
    1063        
     1063
    10641064        /* Append extent for new block (includes tree splitting if needed) */
    10651065        rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
     
    10681068                goto finish;
    10691069        }
    1070        
     1070
    10711071        uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
    10721072        path_ptr = path + tree_depth;
    1073        
     1073
    10741074        /* Initialize newly created extent */
    10751075        ext4_extent_set_block_count(path_ptr->extent, 1);
    10761076        ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
    10771077        ext4_extent_set_start(path_ptr->extent, phys_block);
    1078        
     1078
    10791079        /* Update i-node */
    10801080        if (update_size) {
     
    10821082                inode_ref->dirty = true;
    10831083        }
    1084        
     1084
    10851085        path_ptr->block->dirty = true;
    1086        
     1086
    10871087finish:
    10881088        ;
     
    10931093        *iblock = new_block_idx;
    10941094        *fblock = phys_block;
    1095        
     1095
    10961096        /*
    10971097         * Put loaded blocks
     
    11051105                }
    11061106        }
    1107        
     1107
    11081108        /* Destroy temporary data structure */
    11091109        free(path);
    1110        
     1110
    11111111        return rc;
    11121112}
Note: See TracChangeset for help on using the changeset viewer.