Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset f5af635 in mainline for uspace/srv/fs/fat/fat_ops.c


Ignore:
Timestamp:
2009-10-01T11:53:17Z (11 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
master
Children:
d57e08f
Parents:
bbf88db (diff), 8810c63 (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 FAT server error handling improvements and some fixes.

File:
1 edited

Legend:

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

    rbbf88db rf5af635  
    6565static LIST_INITIALIZE(ffn_head);
    6666
    67 static void fat_node_initialize(fat_node_t *node)
    68 {
    69         fibril_mutex_initialize(&node->lock);
    70         node->bp = NULL;
    71         node->idx = NULL;
    72         node->type = 0;
    73         link_initialize(&node->ffn_link);
    74         node->size = 0;
    75         node->lnkcnt = 0;
    76         node->refcnt = 0;
    77         node->dirty = false;
    78 }
    79 
    80 static int fat_node_sync(fat_node_t *node)
    81 {
    82         block_t *b;
    83         fat_bs_t *bs;
    84         fat_dentry_t *d;
    85         uint16_t bps;
    86         unsigned dps;
    87         int rc;
    88        
    89         assert(node->dirty);
    90 
    91         bs = block_bb_get(node->idx->dev_handle);
    92         bps = uint16_t_le2host(bs->bps);
    93         dps = bps / sizeof(fat_dentry_t);
    94        
    95         /* Read the block that contains the dentry of interest. */
    96         rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
    97             (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
    98         if (rc != EOK)
    99                 return rc;
    100 
    101         d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
    102 
    103         d->firstc = host2uint16_t_le(node->firstc);
    104         if (node->type == FAT_FILE) {
    105                 d->size = host2uint32_t_le(node->size);
    106         } else if (node->type == FAT_DIRECTORY) {
    107                 d->attr = FAT_ATTR_SUBDIR;
    108         }
    109        
    110         /* TODO: update other fields? (e.g time fields) */
    111        
    112         b->dirty = true;                /* need to sync block */
    113         rc = block_put(b);
    114         return rc;
    115 }
    116 
    117 static fat_node_t *fat_node_get_new(void)
    118 {
    119         fs_node_t *fn;
    120         fat_node_t *nodep;
    121         int rc;
    122 
    123         fibril_mutex_lock(&ffn_mutex);
    124         if (!list_empty(&ffn_head)) {
    125                 /* Try to use a cached free node structure. */
    126                 fat_idx_t *idxp_tmp;
    127                 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
    128                 if (!fibril_mutex_trylock(&nodep->lock))
    129                         goto skip_cache;
    130                 idxp_tmp = nodep->idx;
    131                 if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
    132                         fibril_mutex_unlock(&nodep->lock);
    133                         goto skip_cache;
    134                 }
    135                 list_remove(&nodep->ffn_link);
    136                 fibril_mutex_unlock(&ffn_mutex);
    137                 if (nodep->dirty) {
    138                         rc = fat_node_sync(nodep);
    139                         assert(rc == EOK);
    140                 }
    141                 idxp_tmp->nodep = NULL;
    142                 fibril_mutex_unlock(&nodep->lock);
    143                 fibril_mutex_unlock(&idxp_tmp->lock);
    144                 fn = FS_NODE(nodep);
    145         } else {
    146 skip_cache:
    147                 /* Try to allocate a new node structure. */
    148                 fibril_mutex_unlock(&ffn_mutex);
    149                 fn = (fs_node_t *)malloc(sizeof(fs_node_t));
    150                 if (!fn)
    151                         return NULL;
    152                 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
    153                 if (!nodep) {
    154                         free(fn);
    155                         return NULL;
    156                 }
    157         }
    158         fat_node_initialize(nodep);
    159         fs_node_initialize(fn);
    160         fn->data = nodep;
    161         nodep->bp = fn;
    162        
    163         return nodep;
    164 }
    165 
    166 /** Internal version of fat_node_get().
    167  *
    168  * @param idxp          Locked index structure.
    169  */
    170 static fat_node_t *fat_node_get_core(fat_idx_t *idxp)
    171 {
    172         block_t *b;
    173         fat_bs_t *bs;
    174         fat_dentry_t *d;
    175         fat_node_t *nodep = NULL;
    176         unsigned bps;
    177         unsigned spc;
    178         unsigned dps;
    179         int rc;
    180 
    181         if (idxp->nodep) {
    182                 /*
    183                  * We are lucky.
    184                  * The node is already instantiated in memory.
    185                  */
    186                 fibril_mutex_lock(&idxp->nodep->lock);
    187                 if (!idxp->nodep->refcnt++)
    188                         list_remove(&idxp->nodep->ffn_link);
    189                 fibril_mutex_unlock(&idxp->nodep->lock);
    190                 return idxp->nodep;
    191         }
    192 
    193         /*
    194          * We must instantiate the node from the file system.
    195          */
    196        
    197         assert(idxp->pfc);
    198 
    199         nodep = fat_node_get_new();
    200         if (!nodep)
    201                 return NULL;
    202 
    203         bs = block_bb_get(idxp->dev_handle);
    204         bps = uint16_t_le2host(bs->bps);
    205         spc = bs->spc;
    206         dps = bps / sizeof(fat_dentry_t);
    207 
    208         /* Read the block that contains the dentry of interest. */
    209         rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
    210             (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
    211         assert(rc == EOK);
    212 
    213         d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
    214         if (d->attr & FAT_ATTR_SUBDIR) {
    215                 /*
    216                  * The only directory which does not have this bit set is the
    217                  * root directory itself. The root directory node is handled
    218                  * and initialized elsewhere.
    219                  */
    220                 nodep->type = FAT_DIRECTORY;
    221                 /*
    222                  * Unfortunately, the 'size' field of the FAT dentry is not
    223                  * defined for the directory entry type. We must determine the
    224                  * size of the directory by walking the FAT.
    225                  */
    226                 uint16_t clusters;
    227                 rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
    228                     uint16_t_le2host(d->firstc));
    229                 assert(rc == EOK);
    230                 nodep->size = bps * spc * clusters;
    231         } else {
    232                 nodep->type = FAT_FILE;
    233                 nodep->size = uint32_t_le2host(d->size);
    234         }
    235         nodep->firstc = uint16_t_le2host(d->firstc);
    236         nodep->lnkcnt = 1;
    237         nodep->refcnt = 1;
    238 
    239         rc = block_put(b);
    240         assert(rc == EOK);
    241 
    242         /* Link the idx structure with the node structure. */
    243         nodep->idx = idxp;
    244         idxp->nodep = nodep;
    245 
    246         return nodep;
    247 }
    248 
    24967/*
    25068 * Forward declarations of FAT libfs operations.
     
    26785
    26886/*
     87 * Helper functions.
     88 */
     89static void fat_node_initialize(fat_node_t *node)
     90{
     91        fibril_mutex_initialize(&node->lock);
     92        node->bp = NULL;
     93        node->idx = NULL;
     94        node->type = 0;
     95        link_initialize(&node->ffn_link);
     96        node->size = 0;
     97        node->lnkcnt = 0;
     98        node->refcnt = 0;
     99        node->dirty = false;
     100}
     101
     102static int fat_node_sync(fat_node_t *node)
     103{
     104        block_t *b;
     105        fat_bs_t *bs;
     106        fat_dentry_t *d;
     107        uint16_t bps;
     108        unsigned dps;
     109        int rc;
     110       
     111        assert(node->dirty);
     112
     113        bs = block_bb_get(node->idx->dev_handle);
     114        bps = uint16_t_le2host(bs->bps);
     115        dps = bps / sizeof(fat_dentry_t);
     116       
     117        /* Read the block that contains the dentry of interest. */
     118        rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
     119            (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
     120        if (rc != EOK)
     121                return rc;
     122
     123        d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
     124
     125        d->firstc = host2uint16_t_le(node->firstc);
     126        if (node->type == FAT_FILE) {
     127                d->size = host2uint32_t_le(node->size);
     128        } else if (node->type == FAT_DIRECTORY) {
     129                d->attr = FAT_ATTR_SUBDIR;
     130        }
     131       
     132        /* TODO: update other fields? (e.g time fields) */
     133       
     134        b->dirty = true;                /* need to sync block */
     135        rc = block_put(b);
     136        return rc;
     137}
     138
     139static int fat_node_get_new(fat_node_t **nodepp)
     140{
     141        fs_node_t *fn;
     142        fat_node_t *nodep;
     143        int rc;
     144
     145        fibril_mutex_lock(&ffn_mutex);
     146        if (!list_empty(&ffn_head)) {
     147                /* Try to use a cached free node structure. */
     148                fat_idx_t *idxp_tmp;
     149                nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
     150                if (!fibril_mutex_trylock(&nodep->lock))
     151                        goto skip_cache;
     152                idxp_tmp = nodep->idx;
     153                if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
     154                        fibril_mutex_unlock(&nodep->lock);
     155                        goto skip_cache;
     156                }
     157                list_remove(&nodep->ffn_link);
     158                fibril_mutex_unlock(&ffn_mutex);
     159                if (nodep->dirty) {
     160                        rc = fat_node_sync(nodep);
     161                        if (rc != EOK) {
     162                                idxp_tmp->nodep = NULL;
     163                                fibril_mutex_unlock(&nodep->lock);
     164                                fibril_mutex_unlock(&idxp_tmp->lock);
     165                                free(nodep->bp);
     166                                free(nodep);
     167                                return rc;
     168                        }
     169                }
     170                idxp_tmp->nodep = NULL;
     171                fibril_mutex_unlock(&nodep->lock);
     172                fibril_mutex_unlock(&idxp_tmp->lock);
     173                fn = FS_NODE(nodep);
     174        } else {
     175skip_cache:
     176                /* Try to allocate a new node structure. */
     177                fibril_mutex_unlock(&ffn_mutex);
     178                fn = (fs_node_t *)malloc(sizeof(fs_node_t));
     179                if (!fn)
     180                        return ENOMEM;
     181                nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
     182                if (!nodep) {
     183                        free(fn);
     184                        return ENOMEM;
     185                }
     186        }
     187        fat_node_initialize(nodep);
     188        fs_node_initialize(fn);
     189        fn->data = nodep;
     190        nodep->bp = fn;
     191       
     192        *nodepp = nodep;
     193        return EOK;
     194}
     195
     196/** Internal version of fat_node_get().
     197 *
     198 * @param idxp          Locked index structure.
     199 */
     200static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
     201{
     202        block_t *b;
     203        fat_bs_t *bs;
     204        fat_dentry_t *d;
     205        fat_node_t *nodep = NULL;
     206        unsigned bps;
     207        unsigned spc;
     208        unsigned dps;
     209        int rc;
     210
     211        if (idxp->nodep) {
     212                /*
     213                 * We are lucky.
     214                 * The node is already instantiated in memory.
     215                 */
     216                fibril_mutex_lock(&idxp->nodep->lock);
     217                if (!idxp->nodep->refcnt++) {
     218                        fibril_mutex_lock(&ffn_mutex);
     219                        list_remove(&idxp->nodep->ffn_link);
     220                        fibril_mutex_unlock(&ffn_mutex);
     221                }
     222                fibril_mutex_unlock(&idxp->nodep->lock);
     223                *nodepp = idxp->nodep;
     224                return EOK;
     225        }
     226
     227        /*
     228         * We must instantiate the node from the file system.
     229         */
     230       
     231        assert(idxp->pfc);
     232
     233        rc = fat_node_get_new(&nodep);
     234        if (rc != EOK)
     235                return rc;
     236
     237        bs = block_bb_get(idxp->dev_handle);
     238        bps = uint16_t_le2host(bs->bps);
     239        spc = bs->spc;
     240        dps = bps / sizeof(fat_dentry_t);
     241
     242        /* Read the block that contains the dentry of interest. */
     243        rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
     244            (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
     245        if (rc != EOK) {
     246                (void) fat_node_put(FS_NODE(nodep));
     247                return rc;
     248        }
     249
     250        d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
     251        if (d->attr & FAT_ATTR_SUBDIR) {
     252                /*
     253                 * The only directory which does not have this bit set is the
     254                 * root directory itself. The root directory node is handled
     255                 * and initialized elsewhere.
     256                 */
     257                nodep->type = FAT_DIRECTORY;
     258                /*
     259                 * Unfortunately, the 'size' field of the FAT dentry is not
     260                 * defined for the directory entry type. We must determine the
     261                 * size of the directory by walking the FAT.
     262                 */
     263                uint16_t clusters;
     264                rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
     265                    uint16_t_le2host(d->firstc));
     266                if (rc != EOK) {
     267                        (void) fat_node_put(FS_NODE(nodep));
     268                        return rc;
     269                }
     270                nodep->size = bps * spc * clusters;
     271        } else {
     272                nodep->type = FAT_FILE;
     273                nodep->size = uint32_t_le2host(d->size);
     274        }
     275        nodep->firstc = uint16_t_le2host(d->firstc);
     276        nodep->lnkcnt = 1;
     277        nodep->refcnt = 1;
     278
     279        rc = block_put(b);
     280        if (rc != EOK) {
     281                (void) fat_node_put(FS_NODE(nodep));
     282                return rc;
     283        }
     284
     285        /* Link the idx structure with the node structure. */
     286        nodep->idx = idxp;
     287        idxp->nodep = nodep;
     288
     289        *nodepp = nodep;
     290        return EOK;
     291}
     292
     293/*
    269294 * FAT libfs operations.
    270295 */
     
    306331                                continue;
    307332                        case FAT_DENTRY_LAST:
     333                                /* miss */
    308334                                rc = block_put(b);
    309                                 /* expect EOK as b was not dirty */
    310                                 assert(rc == EOK);     
    311335                                fibril_mutex_unlock(&parentp->idx->lock);
    312336                                *rfn = NULL;
    313                                 return EOK;
     337                                return rc;
    314338                        default:
    315339                        case FAT_DENTRY_VALID:
     
    336360                                         */
    337361                                        rc = block_put(b);
    338                                         /* expect EOK as b was not dirty */
    339                                         assert(rc == EOK);     
    340                                         return ENOMEM;
     362                                        return (rc == EOK) ? ENOMEM : rc;
    341363                                }
    342                                 nodep = fat_node_get_core(idx);
     364                                rc = fat_node_get_core(&nodep, idx);
     365                                assert(rc == EOK);
    343366                                fibril_mutex_unlock(&idx->lock);
    344                                 rc = block_put(b);
    345                                 /* expect EOK as b was not dirty */
    346                                 assert(rc == EOK);
     367                                (void) block_put(b);
    347368                                *rfn = FS_NODE(nodep);
    348369                                return EOK;
     
    350371                }
    351372                rc = block_put(b);
    352                 assert(rc == EOK);      /* expect EOK as b was not dirty */
     373                if (rc != EOK) {
     374                        fibril_mutex_unlock(&parentp->idx->lock);
     375                        return rc;
     376                }
    353377        }
    354378
     
    363387        fat_node_t *nodep;
    364388        fat_idx_t *idxp;
     389        int rc;
    365390
    366391        idxp = fat_idx_get_by_index(dev_handle, index);
     
    370395        }
    371396        /* idxp->lock held */
    372         nodep = fat_node_get_core(idxp);
     397        rc = fat_node_get_core(&nodep, idxp);
    373398        fibril_mutex_unlock(&idxp->lock);
    374         *rfn = FS_NODE(nodep);
    375         return EOK;
     399        if (rc == EOK)
     400                *rfn = FS_NODE(nodep);
     401        return rc;
    376402}
    377403
     
    429455        }
    430456
    431         nodep = fat_node_get_new();
    432         if (!nodep) {
     457        rc = fat_node_get_new(&nodep);
     458        if (rc != EOK) {
    433459                (void) fat_free_clusters(bs, dev_handle, mcl);
    434                 return ENOMEM;  /* FIXME: determine the true error code */
    435         }
    436         idxp = fat_idx_get_new(dev_handle);
    437         if (!idxp) {
     460                return rc;
     461        }
     462        rc = fat_idx_get_new(&idxp, dev_handle);
     463        if (rc != EOK) {
    438464                (void) fat_free_clusters(bs, dev_handle, mcl); 
    439465                (void) fat_node_put(FS_NODE(nodep));
    440                 return ENOMEM;  /* FIXME: determine the true error code */
     466                return rc;
    441467        }
    442468        /* idxp->lock held */
     
    782808                        case FAT_DENTRY_LAST:
    783809                                rc = block_put(b);
    784                                 /* expect EOK as b was not dirty */
    785                                 assert(rc == EOK);
    786810                                fibril_mutex_unlock(&nodep->idx->lock);
    787811                                *has_children = false;
    788                                 return EOK;
     812                                return rc;
    789813                        default:
    790814                        case FAT_DENTRY_VALID:
    791815                                rc = block_put(b);
    792                                 /* expect EOK as b was not dirty */
    793                                 assert(rc == EOK);
    794816                                fibril_mutex_unlock(&nodep->idx->lock);
    795817                                *has_children = true;
    796                                 return EOK;
     818                                return rc;
    797819                        }
    798820                }
    799821                rc = block_put(b);
    800                 assert(rc == EOK);      /* expect EOK as b was not dirty */
     822                if (rc != EOK) {
     823                        fibril_mutex_unlock(&nodep->idx->lock);
     824                        return rc;     
     825                }
    801826        }
    802827
Note: See TracChangeset for help on using the changeset viewer.