Changeset 998a78f in mainline
- Timestamp:
- 2011-08-14T07:07:30Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7be14db
- Parents:
- f3d4cd35
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/exfat/exfat_ops.c
rf3d4cd35 r998a78f 108 108 node->refcnt = 0; 109 109 node->dirty = false; 110 node->fragmented = true;110 node->fragmented = false; 111 111 node->lastc_cached_valid = false; 112 112 node->lastc_cached_value = 0; … … 118 118 static int exfat_node_sync(exfat_node_t *node) 119 119 { 120 /* TODO */ 120 121 return EOK; 121 122 } … … 364 365 } 365 366 367 static 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 407 static 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 } 366 450 367 451 … … 504 588 int exfat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags) 505 589 { 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 624 int 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 665 int 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 506 698 /* 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 521 730 } 522 731 523 732 int exfat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm) 524 733 { 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 778 error: 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 527 785 } 528 786 … … 650 908 exfat_cluster_t clst; 651 909 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); 653 911 if (rc != EOK) 654 912 return; … … 727 985 728 986 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); 730 988 if (rc != EOK) { 731 989 free(rootp); … … 1039 1297 size_t *wbytes, aoff64_t *nsize) 1040 1298 { 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; 1043 1382 } 1044 1383 … … 1046 1385 exfat_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size) 1047 1386 { 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 1051 1424 static int exfat_destroy(devmap_handle_t devmap_handle, fs_index_t index) 1052 1425 { 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; 1055 1445 } 1056 1446
Note:
See TracChangeset
for help on using the changeset viewer.