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

Changeset 998a78f in mainline


Ignore:
Timestamp:
2011-08-14T07:07:30Z (9 years ago)
Author:
Oleg Romanenko <romanenko.oleg@…>
Branches:
master
Children:
7be14db
Parents:
f3d4cd35
Message:

exFAT: functions for managing nodes (expand, shrink, write, truncate,
destroy)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/fs/exfat/exfat_ops.c

    rf3d4cd35 r998a78f  
    108108        node->refcnt = 0;
    109109        node->dirty = false;
    110         node->fragmented = true;
     110        node->fragmented = false;
    111111        node->lastc_cached_valid = false;
    112112        node->lastc_cached_value = 0;
     
    118118static int exfat_node_sync(exfat_node_t *node)
    119119{
     120        /* TODO */
    120121        return EOK;
    121122}
     
    364365}
    365366
     367static int exfat_node_expand(devmap_handle_t devmap_handle, exfat_node_t *nodep, exfat_cluster_t clusters)
     368{
     369        exfat_bs_t *bs;
     370        int rc;
     371        bs = block_bb_get(devmap_handle);
     372
     373        if (nodep->fragmented) {
     374                /* TODO */
     375                rc = bitmap_append_clusters(bs, nodep, clusters);
     376                if (rc != ENOSPC)
     377                        return rc;
     378                if (rc == ENOSPC) {
     379                        nodep->fragmented = true;
     380                        nodep->dirty = true;            /* need to sync node */
     381                        rc = bitmap_replicate_clusters(bs, nodep);
     382                        if (rc != EOK)
     383                                return rc;
     384                }
     385        }
     386
     387        /* If we cant linear expand the node, we should use FAT instead */
     388        exfat_cluster_t mcl, lcl;
     389
     390        /* create an independent chain of nclsts clusters in all FATs */
     391        rc = exfat_alloc_clusters(bs, devmap_handle, clusters, &mcl, &lcl);
     392        if (rc != EOK)
     393                return rc;
     394        /*
     395         * Append the cluster chain starting in mcl to the end of the
     396         * node's cluster chain.
     397         */
     398        rc = exfat_append_clusters(bs, nodep, mcl, lcl);
     399        if (rc != EOK) {
     400                (void) exfat_free_clusters(bs, devmap_handle, mcl);
     401                return rc;
     402        }
     403
     404        return EOK;
     405}
     406
     407static int exfat_node_shrink(devmap_handle_t devmap_handle, exfat_node_t *nodep, aoff64_t size)
     408{
     409        exfat_bs_t *bs;
     410        int rc;
     411        bs = block_bb_get(devmap_handle);
     412
     413        if (nodep->fragmented) {
     414                /* TODO */
     415                exfat_cluster_t clsts, prev_clsts, new_clsts;
     416                prev_clsts = ROUND_UP(nodep->size, BPC(bs)) / BPC(bs);
     417                new_clsts =  ROUND_UP(size, BPC(bs)) / BPC(bs);
     418
     419                assert(new_clsts < prev_clsts);
     420
     421                clsts = prev_clsts - new_clsts;
     422               
     423                rc = bitmap_free_clusters(bs, nodep, clsts);
     424                if (rc != EOK)
     425                        return rc;
     426        } else {
     427                /*
     428                 * The node will be shrunk, clusters will be deallocated.
     429                 */
     430                if (size == 0) {
     431                        rc = exfat_chop_clusters(bs, nodep, 0);
     432                        if (rc != EOK)
     433                                return rc;
     434                } else {
     435                        exfat_cluster_t lastc;
     436                        rc = exfat_cluster_walk(bs, devmap_handle, nodep->firstc,
     437                            &lastc, NULL, (size - 1) / BPC(bs));
     438                        if (rc != EOK)
     439                                return rc;
     440                        rc = exfat_chop_clusters(bs, nodep, lastc);
     441                        if (rc != EOK)
     442                                return rc;
     443                }
     444        }
     445
     446        nodep->size = size;
     447        nodep->dirty = true;            /* need to sync node */
     448        return EOK;
     449}
    366450
    367451
     
    504588int exfat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
    505589{
     590        exfat_idx_t *idxp;
     591        exfat_node_t *nodep;
     592        int rc;
     593
     594        rc = exfat_node_get_new(&nodep);
     595        if (rc != EOK)
     596                return rc;
     597
     598        rc = exfat_idx_get_new(&idxp, devmap_handle);
     599        if (rc != EOK) {
     600                (void) exfat_node_put(FS_NODE(nodep));
     601                return rc;
     602        }
     603
     604        if (flags & L_DIRECTORY)
     605                nodep->type = EXFAT_DIRECTORY;
     606        else
     607                nodep->type = EXFAT_FILE;
     608
     609        nodep->firstc = 0;
     610        nodep->size = 0;
     611        nodep->fragmented = false;
     612        nodep->lnkcnt = 0;      /* not linked anywhere */
     613        nodep->refcnt = 1;
     614        nodep->dirty = true;
     615
     616        nodep->idx = idxp;
     617        idxp->nodep = nodep;
     618
     619        fibril_mutex_unlock(&idxp->lock);
     620        *rfn = FS_NODE(nodep);
     621        return EOK;
     622}
     623
     624int exfat_destroy_node(fs_node_t *fn)
     625{
     626        exfat_node_t *nodep = EXFAT_NODE(fn);
     627        exfat_bs_t *bs;
     628        bool has_children;
     629        int rc;
     630
     631        /*
     632         * The node is not reachable from the file system. This means that the
     633         * link count should be zero and that the index structure cannot be
     634         * found in the position hash. Obviously, we don't need to lock the node
     635         * nor its index structure.
     636         */
     637        assert(nodep->lnkcnt == 0);
     638
     639        /*
     640         * The node may not have any children.
     641         */
     642        rc = exfat_has_children(&has_children, fn);
     643        if (rc != EOK)
     644                return rc;
     645        assert(!has_children);
     646
     647        bs = block_bb_get(nodep->idx->devmap_handle);
     648        if (nodep->firstc != 0) {
     649                assert(nodep->size);
     650                /* Free all clusters allocated to the node. */
     651                if (nodep->fragmented)
     652                        rc = exfat_free_clusters(bs, nodep->idx->devmap_handle,
     653                                nodep->firstc);
     654                else
     655                        rc = bitmap_free_clusters(bs, nodep,
     656                            ROUND_UP(nodep->size, BPC(bs)) / BPC(bs));
     657        }
     658
     659        exfat_idx_destroy(nodep->idx);
     660        free(nodep->bp);
     661        free(nodep);
     662        return rc;
     663}
     664
     665int exfat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
     666{
     667        exfat_node_t *parentp = EXFAT_NODE(pfn);
     668        exfat_node_t *childp = EXFAT_NODE(cfn);
     669        exfat_directory_t di;
     670        int rc;
     671
     672        fibril_mutex_lock(&childp->lock);
     673        if (childp->lnkcnt == 1) {
     674                /*
     675                 * On FAT, we don't support multiple hard links.
     676                 */
     677                fibril_mutex_unlock(&childp->lock);
     678                return EMLINK;
     679        }
     680        assert(childp->lnkcnt == 0);
     681        fibril_mutex_unlock(&childp->lock);
     682
     683        if (!exfat_valid_name(name))
     684                return ENOTSUP;
     685
     686        fibril_mutex_lock(&parentp->idx->lock);
     687        rc = exfat_directory_open(parentp, &di);
     688        if (rc != EOK)
     689                return rc;
     690
     691        /*
     692         * At this point we only establish the link between the parent and the
     693         * child.  The dentry, except of the name and the extension, will remain
     694         * uninitialized until the corresponding node is synced. Thus the valid
     695         * dentry data is kept in the child node structure.
     696         */
     697
    506698        /* TODO */
    507         *rfn = NULL;
    508         return EOK;
    509 }
    510 
    511 int exfat_destroy_node(fs_node_t *fn)
    512 {
    513         /* TODO */
    514         return EOK;
    515 }
    516 
    517 int exfat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
    518 {
    519         /* TODO */
    520         return EOK;
     699        rc = exfat_directory_write_file(&di, name);
     700        if (rc!=EOK)
     701                return rc;
     702        rc = exfat_directory_close(&di);
     703        if (rc!=EOK)
     704                return rc;
     705
     706        fibril_mutex_unlock(&parentp->idx->lock);
     707        if (rc != EOK)
     708                return rc;
     709
     710        fibril_mutex_lock(&childp->idx->lock);
     711
     712
     713        childp->idx->pfc = parentp->firstc;
     714        childp->idx->parent_fragmented = parentp->fragmented;
     715        childp->idx->pdi = di.pos;      /* di.pos holds absolute position of SFN entry */
     716        fibril_mutex_unlock(&childp->idx->lock);
     717
     718        fibril_mutex_lock(&childp->lock);
     719        childp->lnkcnt = 1;
     720        childp->dirty = true;           /* need to sync node */
     721        fibril_mutex_unlock(&childp->lock);
     722
     723        /*
     724         * Hash in the index structure into the position hash.
     725         */
     726        exfat_idx_hashin(childp->idx);
     727
     728        return EOK;
     729
    521730}
    522731
    523732int exfat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
    524733{
    525         /* TODO */
    526         return EOK;
     734        exfat_node_t *parentp = EXFAT_NODE(pfn);
     735        exfat_node_t *childp = EXFAT_NODE(cfn);
     736        bool has_children;
     737        int rc;
     738
     739        if (!parentp)
     740                return EBUSY;
     741
     742        rc = exfat_has_children(&has_children, cfn);
     743        if (rc != EOK)
     744                return rc;
     745        if (has_children)
     746                return ENOTEMPTY;
     747
     748        fibril_mutex_lock(&parentp->lock);
     749        fibril_mutex_lock(&childp->lock);
     750        assert(childp->lnkcnt == 1);
     751        fibril_mutex_lock(&childp->idx->lock);
     752       
     753        exfat_directory_t di;
     754        rc = exfat_directory_open(parentp,&di);
     755        if (rc != EOK)
     756                goto error;
     757        rc = exfat_directory_erase_file(&di, childp->idx->pdi);
     758        if (rc != EOK)
     759                goto error;
     760        rc = exfat_directory_close(&di);
     761        if (rc != EOK)
     762                goto error;
     763
     764        /* remove the index structure from the position hash */
     765        exfat_idx_hashout(childp->idx);
     766        /* clear position information */
     767        childp->idx->pfc = 0;
     768        childp->idx->pdi = 0;
     769        fibril_mutex_unlock(&childp->idx->lock);
     770        childp->lnkcnt = 0;
     771        childp->refcnt++;       /* keep the node in memory until destroyed */
     772        childp->dirty = true;
     773        fibril_mutex_unlock(&childp->lock);
     774        fibril_mutex_unlock(&parentp->lock);
     775
     776        return EOK;
     777
     778error:
     779        (void) exfat_directory_close(&di);
     780        fibril_mutex_unlock(&childp->idx->lock);
     781        fibril_mutex_unlock(&childp->lock);
     782        fibril_mutex_unlock(&parentp->lock);
     783        return rc;
     784
    527785}
    528786
     
    650908        exfat_cluster_t clst;
    651909        for (i=0; i<6; i++) {
    652                 rc = fat_get_cluster(bs, devmap_handle, i, &clst);
     910                rc = exfat_get_cluster(bs, devmap_handle, i, &clst);
    653911                if (rc != EOK)
    654912                        return;
     
    727985
    728986        uint32_t clusters;
    729         rc = fat_clusters_get(&clusters, bs, devmap_handle, rootp->firstc);
     987        rc = exfat_clusters_get(&clusters, bs, devmap_handle, rootp->firstc);
    730988        if (rc != EOK) {
    731989                free(rootp);
     
    10391297    size_t *wbytes, aoff64_t *nsize)
    10401298{
    1041         /* TODO */
    1042         return EOK;
     1299        fs_node_t *fn;
     1300        exfat_node_t *nodep;
     1301        exfat_bs_t *bs;
     1302        size_t bytes;
     1303        block_t *b;
     1304        aoff64_t boundary;
     1305        int flags = BLOCK_FLAGS_NONE;
     1306        int rc;
     1307
     1308        rc = exfat_node_get(&fn, devmap_handle, index);
     1309        if (rc != EOK)
     1310                return rc;
     1311        if (!fn)
     1312                return ENOENT;
     1313        nodep = EXFAT_NODE(fn);
     1314
     1315        ipc_callid_t callid;
     1316        size_t len;
     1317        if (!async_data_write_receive(&callid, &len)) {
     1318                (void) exfat_node_put(fn);
     1319                async_answer_0(callid, EINVAL);
     1320                return EINVAL;
     1321        }
     1322
     1323        bs = block_bb_get(devmap_handle);
     1324
     1325        /*
     1326         * In all scenarios, we will attempt to write out only one block worth
     1327         * of data at maximum. There might be some more efficient approaches,
     1328         * but this one greatly simplifies fat_write(). Note that we can afford
     1329         * to do this because the client must be ready to handle the return
     1330         * value signalizing a smaller number of bytes written.
     1331         */
     1332        bytes = min(len, BPS(bs) - pos % BPS(bs));
     1333        if (bytes == BPS(bs))
     1334                flags |= BLOCK_FLAGS_NOREAD;
     1335
     1336        boundary = ROUND_UP(nodep->size, BPC(bs));
     1337
     1338        if (pos >= boundary) {
     1339                unsigned nclsts;
     1340                nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
     1341                rc = exfat_node_expand(devmap_handle, nodep, nclsts);
     1342                if (rc != EOK) {
     1343                        /* could not expand node */
     1344                        (void) exfat_node_put(fn);
     1345                        async_answer_0(callid, rc);
     1346                        return rc;
     1347                }
     1348        }
     1349
     1350        if (pos + bytes > nodep->size) {
     1351                nodep->size = pos + bytes;
     1352                nodep->dirty = true;    /* need to sync node */
     1353        }
     1354
     1355        /*
     1356         * This is the easier case - we are either overwriting already
     1357         * existing contents or writing behind the EOF, but still within
     1358         * the limits of the last cluster. The node size may grow to the
     1359         * next block size boundary.
     1360         */
     1361        rc = exfat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
     1362        if (rc != EOK) {
     1363                (void) exfat_node_put(fn);
     1364                async_answer_0(callid, rc);
     1365                return rc;
     1366        }
     1367
     1368        (void) async_data_write_finalize(callid,
     1369                b->data + pos % BPS(bs), bytes);
     1370        b->dirty = true;                /* need to sync block */
     1371        rc = block_put(b);
     1372        if (rc != EOK) {
     1373                (void) exfat_node_put(fn);
     1374                return rc;
     1375        }
     1376
     1377
     1378        *wbytes = bytes;
     1379        *nsize = nodep->size;
     1380        rc = exfat_node_put(fn);
     1381        return rc;
    10431382}
    10441383
     
    10461385exfat_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
    10471386{
    1048         /* TODO */
    1049         return EOK;
    1050 }
     1387        fs_node_t *fn;
     1388        exfat_node_t *nodep;
     1389        exfat_bs_t *bs;
     1390        int rc;
     1391
     1392        rc = exfat_node_get(&fn, devmap_handle, index);
     1393        if (rc != EOK)
     1394                return rc;
     1395        if (!fn)
     1396                return ENOENT;
     1397        nodep = EXFAT_NODE(fn);
     1398
     1399        bs = block_bb_get(devmap_handle);
     1400
     1401        if (nodep->size == size) {
     1402                rc = EOK;
     1403        } else if (nodep->size < size) {
     1404                /*
     1405                 * The standard says we have the freedom to grow the node.
     1406                 * For now, we simply return an error.
     1407                 */
     1408                rc = EINVAL;
     1409        } else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
     1410                /*
     1411                 * The node will be shrunk, but no clusters will be deallocated.
     1412                 */
     1413                nodep->size = size;
     1414                nodep->dirty = true;            /* need to sync node */
     1415                rc = EOK;
     1416        } else {
     1417                rc = exfat_node_shrink(devmap_handle, nodep, size);
     1418        }
     1419
     1420        (void) exfat_node_put(fn);
     1421        return rc;
     1422}
     1423
    10511424static int exfat_destroy(devmap_handle_t devmap_handle, fs_index_t index)
    10521425{
    1053         /* TODO */
    1054         return EOK;
     1426        fs_node_t *fn;
     1427        exfat_node_t *nodep;
     1428        int rc;
     1429
     1430        rc = exfat_node_get(&fn, devmap_handle, index);
     1431        if (rc != EOK)
     1432                return rc;
     1433        if (!fn)
     1434                return ENOENT;
     1435
     1436        nodep = EXFAT_NODE(fn);
     1437        /*
     1438         * We should have exactly two references. One for the above
     1439         * call to fat_node_get() and one from fat_unlink().
     1440         */
     1441        assert(nodep->refcnt == 2);
     1442
     1443        rc = exfat_destroy_node(fn);
     1444        return rc;
    10551445}
    10561446
Note: See TracChangeset for help on using the changeset viewer.