Changeset 9a1d8ab in mainline for uspace/srv/fs/fat/fat_fat.c


Ignore:
Timestamp:
2010-07-28T15:27:13Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0b749a3, 482dde7, c0e1be7
Parents:
14f2100 (diff), dba4a23 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~jakub/helenos/fs.

This merge adds two important optimizations for appending files and doing
sequential I/O on them.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/fs/fat/fat_fat.c

    r14f2100 r9a1d8ab  
    4949#include <mem.h>
    5050
     51/*
     52 * Convenience macros for computing some frequently used values from the
     53 * primitive boot sector members.
     54 */
     55#define RDS(bs)         ((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
     56                        (((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
     57#define SSA(bs)         (RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
     58
     59#define CLBN2PBN(bs, cl, bn) \
     60        (SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
     61
    5162/**
    5263 * The fat_alloc_lock mutex protects all copies of the File Allocation Table
     
    7485{
    7586        block_t *b;
    76         unsigned bps;
    77         unsigned rscnt;         /* block address of the first FAT */
    7887        uint16_t clusters = 0;
    7988        fat_cluster_t clst = firstc;
    8089        int rc;
    81 
    82         bps = uint16_t_le2host(bs->bps);
    83         rscnt = uint16_t_le2host(bs->rscnt);
    8490
    8591        if (firstc == FAT_CLST_RES0) {
     
    99105                if (lastc)
    100106                        *lastc = clst;  /* remember the last cluster number */
    101                 fsec = (clst * sizeof(fat_cluster_t)) / bps;
    102                 fidx = clst % (bps / sizeof(fat_cluster_t));
     107                fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
     108                fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
    103109                /* read FAT1 */
    104                 rc = block_get(&b, dev_handle, rscnt + fsec, BLOCK_FLAGS_NONE);
     110                rc = block_get(&b, dev_handle, RSCNT(bs) + fsec,
     111                    BLOCK_FLAGS_NONE);
    105112                if (rc != EOK)
    106113                        return rc;
     
    125132 * @param block         Pointer to a block pointer for storing result.
    126133 * @param bs            Buffer holding the boot sector of the file system.
    127  * @param dev_handle    Device handle of the file system.
    128  * @param firstc        First cluster used by the file. Can be zero if the file
    129  *                      is empty.
     134 * @param nodep         FAT node.
    130135 * @param bn            Block number.
    131136 * @param flags         Flags passed to libblock.
     
    134139 */
    135140int
     141fat_block_get(block_t **block, struct fat_bs *bs, fat_node_t *nodep,
     142    aoff64_t bn, int flags)
     143{
     144        fat_cluster_t firstc = nodep->firstc;
     145        fat_cluster_t currc;
     146        aoff64_t relbn = bn;
     147        int rc;
     148
     149        if (!nodep->size)
     150                return ELIMIT;
     151
     152        if (nodep->firstc == FAT_CLST_ROOT)
     153                goto fall_through;
     154
     155        if (((((nodep->size - 1) / BPS(bs)) / SPC(bs)) == bn / SPC(bs)) &&
     156            nodep->lastc_cached_valid) {
     157                /*
     158                 * This is a request to read a block within the last cluster
     159                 * when fortunately we have the last cluster number cached.
     160                 */
     161                return block_get(block, nodep->idx->dev_handle,
     162                    CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
     163        }
     164
     165        if (nodep->currc_cached_valid && bn >= nodep->currc_cached_bn) {
     166                /*
     167                 * We can start with the cluster cached by the previous call to
     168                 * fat_block_get().
     169                 */
     170                firstc = nodep->currc_cached_value;
     171                relbn -= (nodep->currc_cached_bn / SPC(bs)) * SPC(bs);
     172        }
     173
     174fall_through:
     175        rc = _fat_block_get(block, bs, nodep->idx->dev_handle, firstc,
     176            &currc, relbn, flags);
     177        if (rc != EOK)
     178                return rc;
     179       
     180        /*
     181         * Update the "current" cluster cache.
     182         */
     183        nodep->currc_cached_valid = true;
     184        nodep->currc_cached_bn = bn;
     185        nodep->currc_cached_value = currc;
     186
     187        return rc;
     188}
     189
     190/** Read block from file located on a FAT file system.
     191 *
     192 * @param block         Pointer to a block pointer for storing result.
     193 * @param bs            Buffer holding the boot sector of the file system.
     194 * @param dev_handle    Device handle of the file system.
     195 * @param fcl           First cluster used by the file. Can be zero if the file
     196 *                      is empty.
     197 * @param clp           If not NULL, address where the cluster containing bn
     198 *                      will be stored.
     199 *                      stored
     200 * @param bn            Block number.
     201 * @param flags         Flags passed to libblock.
     202 *
     203 * @return              EOK on success or a negative error code.
     204 */
     205int
    136206_fat_block_get(block_t **block, fat_bs_t *bs, dev_handle_t dev_handle,
    137     fat_cluster_t firstc, aoff64_t bn, int flags)
    138 {
    139         unsigned bps;
    140         unsigned rscnt;         /* block address of the first FAT */
    141         unsigned rde;
    142         unsigned rds;           /* root directory size */
    143         unsigned sf;
    144         unsigned ssa;           /* size of the system area */
     207    fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
     208{
    145209        uint16_t clusters;
    146210        unsigned max_clusters;
    147         fat_cluster_t lastc;
     211        fat_cluster_t c;
    148212        int rc;
    149213
     
    151215         * This function can only operate on non-zero length files.
    152216         */
    153         if (firstc == FAT_CLST_RES0)
     217        if (fcl == FAT_CLST_RES0)
    154218                return ELIMIT;
    155219
    156         bps = uint16_t_le2host(bs->bps);
    157         rscnt = uint16_t_le2host(bs->rscnt);
    158         rde = uint16_t_le2host(bs->root_ent_max);
    159         sf = uint16_t_le2host(bs->sec_per_fat);
    160 
    161         rds = (sizeof(fat_dentry_t) * rde) / bps;
    162         rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
    163         ssa = rscnt + bs->fatcnt * sf + rds;
    164 
    165         if (firstc == FAT_CLST_ROOT) {
     220        if (fcl == FAT_CLST_ROOT) {
    166221                /* root directory special case */
    167                 assert(bn < rds);
    168                 rc = block_get(block, dev_handle, rscnt + bs->fatcnt * sf + bn,
    169                     flags);
     222                assert(bn < RDS(bs));
     223                rc = block_get(block, dev_handle,
     224                    RSCNT(bs) + FATCNT(bs) * SF(bs) + bn, flags);
    170225                return rc;
    171226        }
    172227
    173         max_clusters = bn / bs->spc;
    174         rc = fat_cluster_walk(bs, dev_handle, firstc, &lastc, &clusters,
    175             max_clusters);
     228        max_clusters = bn / SPC(bs);
     229        rc = fat_cluster_walk(bs, dev_handle, fcl, &c, &clusters, max_clusters);
    176230        if (rc != EOK)
    177231                return rc;
    178232        assert(clusters == max_clusters);
    179233
    180         rc = block_get(block, dev_handle,
    181             ssa + (lastc - FAT_CLST_FIRST) * bs->spc + bn % bs->spc, flags);
     234        rc = block_get(block, dev_handle, CLBN2PBN(bs, c, bn), flags);
     235
     236        if (clp)
     237                *clp = c;
    182238
    183239        return rc;
     
    198254int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
    199255{
    200         uint16_t bps;
    201         unsigned spc;
    202256        block_t *b;
    203257        aoff64_t o, boundary;
    204258        int rc;
    205259
    206         bps = uint16_t_le2host(bs->bps);
    207         spc = bs->spc;
    208        
    209         boundary = ROUND_UP(nodep->size, bps * spc);
     260        boundary = ROUND_UP(nodep->size, BPS(bs) * SPC(bs));
    210261
    211262        /* zero out already allocated space */
    212263        for (o = nodep->size; o < pos && o < boundary;
    213             o = ALIGN_DOWN(o + bps, bps)) {
    214                 int flags = (o % bps == 0) ?
     264            o = ALIGN_DOWN(o + BPS(bs), BPS(bs))) {
     265                int flags = (o % BPS(bs) == 0) ?
    215266                    BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
    216                 rc = fat_block_get(&b, bs, nodep, o / bps, flags);
    217                 if (rc != EOK)
    218                         return rc;
    219                 memset(b->data + o % bps, 0, bps - o % bps);
     267                rc = fat_block_get(&b, bs, nodep, o / BPS(bs), flags);
     268                if (rc != EOK)
     269                        return rc;
     270                memset(b->data + o % BPS(bs), 0, BPS(bs) - o % BPS(bs));
    220271                b->dirty = true;                /* need to sync node */
    221272                rc = block_put(b);
     
    228279       
    229280        /* zero out the initial part of the new cluster chain */
    230         for (o = boundary; o < pos; o += bps) {
     281        for (o = boundary; o < pos; o += BPS(bs)) {
    231282                rc = _fat_block_get(&b, bs, nodep->idx->dev_handle, mcl,
    232                     (o - boundary) / bps, BLOCK_FLAGS_NOREAD);
    233                 if (rc != EOK)
    234                         return rc;
    235                 memset(b->data, 0, min(bps, pos - o));
     283                    NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
     284                if (rc != EOK)
     285                        return rc;
     286                memset(b->data, 0, min(BPS(bs), pos - o));
    236287                b->dirty = true;                /* need to sync node */
    237288                rc = block_put(b);
     
    257308{
    258309        block_t *b;
    259         uint16_t bps;
    260         uint16_t rscnt;
    261         uint16_t sf;
    262310        fat_cluster_t *cp;
    263311        int rc;
    264312
    265         bps = uint16_t_le2host(bs->bps);
    266         rscnt = uint16_t_le2host(bs->rscnt);
    267         sf = uint16_t_le2host(bs->sec_per_fat);
    268 
    269         rc = block_get(&b, dev_handle, rscnt + sf * fatno +
    270             (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
     313        rc = block_get(&b, dev_handle, RSCNT(bs) + SF(bs) * fatno +
     314            (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
    271315        if (rc != EOK)
    272316                return rc;
    273         cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
     317        cp = (fat_cluster_t *)b->data +
     318            clst % (BPS(bs) / sizeof(fat_cluster_t));
    274319        *value = uint16_t_le2host(*cp);
    275320        rc = block_put(b);
     
    293338{
    294339        block_t *b;
    295         uint16_t bps;
    296         uint16_t rscnt;
    297         uint16_t sf;
    298340        fat_cluster_t *cp;
    299341        int rc;
    300342
    301         bps = uint16_t_le2host(bs->bps);
    302         rscnt = uint16_t_le2host(bs->rscnt);
    303         sf = uint16_t_le2host(bs->sec_per_fat);
    304 
    305         assert(fatno < bs->fatcnt);
    306         rc = block_get(&b, dev_handle, rscnt + sf * fatno +
    307             (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
     343        assert(fatno < FATCNT(bs));
     344        rc = block_get(&b, dev_handle, RSCNT(bs) + SF(bs) * fatno +
     345            (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
    308346        if (rc != EOK)
    309347                return rc;
    310         cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
     348        cp = (fat_cluster_t *)b->data +
     349            clst % (BPS(bs) / sizeof(fat_cluster_t));
    311350        *cp = host2uint16_t_le(value);
    312351        b->dirty = true;                /* need to sync block */
     
    364403    fat_cluster_t *mcl, fat_cluster_t *lcl)
    365404{
    366         uint16_t bps;
    367         uint16_t rscnt;
    368         uint16_t sf;
    369         uint32_t ts;
    370         unsigned rde;
    371         unsigned rds;
    372         unsigned ssa;
    373405        block_t *blk;
    374406        fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
     
    380412        if (!lifo)
    381413                return ENOMEM;
    382        
    383         bps = uint16_t_le2host(bs->bps);
    384         rscnt = uint16_t_le2host(bs->rscnt);
    385         sf = uint16_t_le2host(bs->sec_per_fat);
    386         rde = uint16_t_le2host(bs->root_ent_max);
    387         ts = (uint32_t) uint16_t_le2host(bs->totsec16);
    388         if (ts == 0)
    389                 ts = uint32_t_le2host(bs->totsec32);
    390 
    391         rds = (sizeof(fat_dentry_t) * rde) / bps;
    392         rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
    393         ssa = rscnt + bs->fatcnt * sf + rds;
    394414       
    395415        /*
     
    397417         */
    398418        fibril_mutex_lock(&fat_alloc_lock);
    399         for (b = 0, cl = 0; b < sf; b++) {
    400                 rc = block_get(&blk, dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
     419        for (b = 0, cl = 0; b < SF(bs); b++) {
     420                rc = block_get(&blk, dev_handle, RSCNT(bs) + b,
     421                    BLOCK_FLAGS_NONE);
    401422                if (rc != EOK)
    402423                        goto error;
    403                 for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
     424                for (c = 0; c < BPS(bs) / sizeof(fat_cluster_t); c++, cl++) {
    404425                        /*
    405426                         * Check if the cluster is physically there. This check
     
    408429                         * from the size of the file allocation table.
    409430                         */
    410                         if ((cl >= 2) && ((cl - 2) * bs->spc + ssa >= ts)) {
     431                        if ((cl >= 2) &&
     432                            ((cl - 2) * SPC(bs) + SSA(bs) >= TS(bs))) {
    411433                                rc = block_put(blk);
    412434                                if (rc != EOK)
     
    511533 * @param nodep         Node representing the file.
    512534 * @param mcl           First cluster of the cluster chain to append.
     535 * @param lcl           Last cluster of the cluster chain to append.
    513536 *
    514537 * @return              EOK on success or a negative error code.
    515538 */
    516 int fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl)
     539int
     540fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
     541    fat_cluster_t lcl)
    517542{
    518543        dev_handle_t dev_handle = nodep->idx->dev_handle;
    519         fat_cluster_t lcl;
     544        fat_cluster_t lastc;
    520545        uint16_t numc;
    521546        uint8_t fatno;
    522547        int rc;
    523548
    524         rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl, &numc,
    525             (uint16_t) -1);
    526         if (rc != EOK)
    527                 return rc;
    528 
    529         if (numc == 0) {
    530                 /* No clusters allocated to the node yet. */
    531                 nodep->firstc = mcl;
    532                 nodep->dirty = true;            /* need to sync node */
    533                 return EOK;
     549        if (nodep->lastc_cached_valid) {
     550                lastc = nodep->lastc_cached_value;
     551                nodep->lastc_cached_valid = false;
     552        } else {
     553                rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lastc,
     554                    &numc, (uint16_t) -1);
     555                if (rc != EOK)
     556                        return rc;
     557
     558                if (numc == 0) {
     559                        /* No clusters allocated to the node yet. */
     560                        nodep->firstc = mcl;
     561                        nodep->dirty = true;    /* need to sync node */
     562                        return EOK;
     563                }
    534564        }
    535565
    536566        for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
    537                 rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl,
     567                rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lastc,
    538568                    mcl);
    539569                if (rc != EOK)
    540570                        return rc;
    541571        }
     572
     573        nodep->lastc_cached_valid = true;
     574        nodep->lastc_cached_value = lcl;
    542575
    543576        return EOK;
     
    548581 * @param bs            Buffer holding the boot sector of the file system.
    549582 * @param nodep         FAT node where the chopping will take place.
    550  * @param lastc         Last cluster which will remain in the node. If this
     583 * @param lcl           Last cluster which will remain in the node. If this
    551584 *                      argument is FAT_CLST_RES0, then all clusters will
    552585 *                      be chopped off.
     
    554587 * @return              EOK on success or a negative return code.
    555588 */
    556 int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
    557 {
    558         int rc;
    559 
     589int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
     590{
     591        int rc;
    560592        dev_handle_t dev_handle = nodep->idx->dev_handle;
    561         if (lastc == FAT_CLST_RES0) {
     593
     594        /*
     595         * Invalidate cached cluster numbers.
     596         */
     597        nodep->lastc_cached_valid = false;
     598        if (nodep->currc_cached_value != lcl)
     599                nodep->currc_cached_valid = false;
     600
     601        if (lcl == FAT_CLST_RES0) {
    562602                /* The node will have zero size and no clusters allocated. */
    563603                rc = fat_free_clusters(bs, dev_handle, nodep->firstc);
     
    570610                unsigned fatno;
    571611
    572                 rc = fat_get_cluster(bs, dev_handle, FAT1, lastc, &nextc);
     612                rc = fat_get_cluster(bs, dev_handle, FAT1, lcl, &nextc);
    573613                if (rc != EOK)
    574614                        return rc;
     
    576616                /* Terminate the cluster chain in all copies of FAT. */
    577617                for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
    578                         rc = fat_set_cluster(bs, dev_handle, fatno, lastc,
     618                        rc = fat_set_cluster(bs, dev_handle, fatno, lcl,
    579619                            FAT_CLST_LAST1);
    580620                        if (rc != EOK)
     
    588628        }
    589629
     630        /*
     631         * Update and re-enable the last cluster cache.
     632         */
     633        nodep->lastc_cached_valid = true;
     634        nodep->lastc_cached_value = lcl;
     635
    590636        return EOK;
    591637}
     
    596642        int i;
    597643        block_t *b;
    598         unsigned bps;
    599         int rc;
    600 
    601         bps = uint16_t_le2host(bs->bps);
    602        
    603         for (i = 0; i < bs->spc; i++) {
    604                 rc = _fat_block_get(&b, bs, dev_handle, c, i,
     644        int rc;
     645
     646        for (i = 0; i < SPC(bs); i++) {
     647                rc = _fat_block_get(&b, bs, dev_handle, c, NULL, i,
    605648                    BLOCK_FLAGS_NOREAD);
    606649                if (rc != EOK)
    607650                        return rc;
    608                 memset(b->data, 0, bps);
     651                memset(b->data, 0, BPS(bs));
    609652                b->dirty = true;
    610653                rc = block_put(b);
Note: See TracChangeset for help on using the changeset viewer.