Ignore:
File:
1 edited

Legend:

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

    ra35b458 r5a6cc679  
    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.