You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/01/15 18:56:11 UTC
[04/14] incubator-mynewt-larva git commit: Relocate libs/fs -> fs/fs
libs/nffs -> fs/nffs.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/cf40853d/libs/nffs/src/nffs_restore.c
----------------------------------------------------------------------
diff --git a/libs/nffs/src/nffs_restore.c b/libs/nffs/src/nffs_restore.c
deleted file mode 100644
index b94b5fb..0000000
--- a/libs/nffs/src/nffs_restore.c
+++ /dev/null
@@ -1,1034 +0,0 @@
-/**
- * Copyright (c) 2015 Runtime Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include "hal/hal_flash.h"
-#include "os/os_mempool.h"
-#include "os/os_malloc.h"
-#include "nffs/nffs.h"
-#include "nffs_priv.h"
-
-/**
- * The size of the largest data block encountered during detection. This is
- * used to ensure that the maximum block data size is not set lower than the
- * size of an existing block.
- */
-static uint16_t nffs_restore_largest_block_data_len;
-
-/**
- * Checks that each block a chain of data blocks was properly restored.
- *
- * @param last_block_entry The entry corresponding to the last block in
- * the chain.
- *
- * @return 0 if the block chain is OK;
- * FS_ECORRUPT if corruption is detected;
- * nonzero on other error.
- */
-static int
-nffs_restore_validate_block_chain(struct nffs_hash_entry *last_block_entry)
-{
- struct nffs_disk_block disk_block;
- struct nffs_hash_entry *cur;
- struct nffs_block block;
- uint32_t area_offset;
- uint8_t area_idx;
- int rc;
-
- cur = last_block_entry;
-
- while (cur != NULL) {
- nffs_flash_loc_expand(cur->nhe_flash_loc, &area_idx, &area_offset);
-
- rc = nffs_block_read_disk(area_idx, area_offset, &disk_block);
- if (rc != 0) {
- return rc;
- }
-
- rc = nffs_block_from_hash_entry(&block, cur);
- if (rc != 0) {
- return rc;
- }
-
- cur = block.nb_prev;
- }
-
- return 0;
-}
-
-static void
-u32toa(char *dst, uint32_t val)
-{
- uint8_t tmp;
- int idx = 0;
- int i;
- int print = 0;
-
- for (i = 0; i < 8; i++) {
- tmp = val >> 28;
- if (tmp || i == 7) {
- print = 1;
- }
- if (tmp < 10) {
- tmp += '0';
- } else {
- tmp += 'a' - 10;
- }
- if (print) {
- dst[idx++] = tmp;
- }
- val <<= 4;
- }
- dst[idx++] = '\0';
-}
-
-/**
- * If the specified inode entry is a dummy directory, this function moves
- * all its children to the lost+found directory.
- *
- * @param inode_entry The parent inode to test and empty.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_migrate_orphan_children(struct nffs_inode_entry *inode_entry)
-{
- struct nffs_inode_entry *lost_found_sub;
- struct nffs_inode_entry *child_entry;
- char buf[32];
- int rc;
-
- if (!nffs_hash_id_is_dir(inode_entry->nie_hash_entry.nhe_id)) {
- /* Not a directory. */
- return 0;
- }
-
- if (inode_entry->nie_refcnt != 0) {
- /* Not a dummy. */
- return 0;
- }
-
- if (SLIST_EMPTY(&inode_entry->nie_child_list)) {
- /* No children to migrate. */
- return 0;
- }
-
- /* Create a directory in lost+found to hold the dummy directory's
- * contents.
- */
- strcpy(buf, "/lost+found/");
- u32toa(&buf[strlen(buf)], inode_entry->nie_hash_entry.nhe_id);
-
- rc = nffs_path_new_dir(buf, &lost_found_sub);
- if (rc != 0 && rc != FS_EEXIST) {
- return rc;
- }
-
- /* Move each child into the new subdirectory. */
- while ((child_entry = SLIST_FIRST(&inode_entry->nie_child_list)) != NULL) {
- rc = nffs_inode_rename(child_entry, lost_found_sub, NULL);
- if (rc != 0) {
- return rc;
- }
- }
-
- return 0;
-}
-
-static int
-nffs_restore_should_sweep_inode_entry(struct nffs_inode_entry *inode_entry,
- int *out_should_sweep)
-{
- struct nffs_inode inode;
- int rc;
-
- /* Determine if the inode is a dummy. Dummy inodes have a reference count
- * of 0. If it is a dummy, increment its reference count back to 1 so that
- * it can be properly deleted. The presence of a dummy inode during the
- * final sweep step indicates file system corruption. If the inode is a
- * directory, all its children should have been migrated to the /lost+found
- * directory prior to this.
- */
- if (inode_entry->nie_refcnt == 0) {
- *out_should_sweep = 1;
- inode_entry->nie_refcnt++;
- return 0;
- }
-
- /* Determine if the inode has been deleted. If an inode has no parent (and
- * it isn't the root directory), it has been deleted from the disk and
- * should be swept from the RAM representation.
- */
- if (inode_entry->nie_hash_entry.nhe_id != NFFS_ID_ROOT_DIR) {
- rc = nffs_inode_from_entry(&inode, inode_entry);
- if (rc != 0) {
- *out_should_sweep = 0;
- return rc;
- }
-
- if (inode.ni_parent == NULL) {
- *out_should_sweep = 1;
- return 0;
- }
- }
-
- /* If this is a file inode, verify that all of its constituent blocks are
- * present.
- */
- if (nffs_hash_id_is_file(inode_entry->nie_hash_entry.nhe_id)) {
- rc = nffs_restore_validate_block_chain(
- inode_entry->nie_last_block_entry);
- if (rc == FS_ECORRUPT) {
- *out_should_sweep = 1;
- return 0;
- } else if (rc != 0) {
- *out_should_sweep = 0;
- return rc;
- }
- }
-
- /* This is a valid inode; don't sweep it. */
- *out_should_sweep = 0;
- return 0;
-}
-
-static void
-nffs_restore_inode_from_dummy_entry(struct nffs_inode *out_inode,
- struct nffs_inode_entry *inode_entry)
-{
- memset(out_inode, 0, sizeof *out_inode);
- out_inode->ni_inode_entry = inode_entry;
-}
-
-/**
- * Performs a sweep of the RAM representation at the end of a successful
- * restore. The sweep phase performs the following actions of each inode in
- * the file system:
- * 1. If the inode is a dummy directory, its children are migrated to the
- * lost+found directory.
- * 2. Else if the inode is a dummy file, it is fully deleted from RAM.
- * 3. Else, a CRC check is performed on each of the inode's constituent
- * blocks. If corruption is detected, the inode is fully deleted from
- * RAM.
- *
- * @return 0 on success; nonzero on failure.
- */
-int
-nffs_restore_sweep(void)
-{
- struct nffs_inode_entry *inode_entry;
- struct nffs_hash_entry *entry;
- struct nffs_hash_entry *next;
- struct nffs_hash_list *list;
- struct nffs_inode inode;
- int del;
- int rc;
- int i;
-
- /* Iterate through every object in the hash table, deleting all inodes that
- * should be removed.
- */
- for (i = 0; i < NFFS_HASH_SIZE; i++) {
- list = nffs_hash + i;
-
- entry = SLIST_FIRST(list);
- while (entry != NULL) {
- next = SLIST_NEXT(entry, nhe_next);
- if (nffs_hash_id_is_inode(entry->nhe_id)) {
- inode_entry = (struct nffs_inode_entry *)entry;
-
- /* If this is a dummy inode directory, the file system is
- * corrupted. Move the directory's children inodes to the
- * lost+found directory.
- */
- rc = nffs_restore_migrate_orphan_children(inode_entry);
- if (rc != 0) {
- return rc;
- }
-
- /* Determine if this inode needs to be deleted. */
- rc = nffs_restore_should_sweep_inode_entry(inode_entry, &del);
- if (rc != 0) {
- return rc;
- }
-
- if (del) {
- if (inode_entry->nie_hash_entry.nhe_flash_loc ==
- NFFS_FLASH_LOC_NONE) {
-
- nffs_restore_inode_from_dummy_entry(&inode,
- inode_entry);
- } else {
- rc = nffs_inode_from_entry(&inode, inode_entry);
- if (rc != 0) {
- return rc;
- }
- }
-
- /* Remove the inode and all its children from RAM. */
- rc = nffs_inode_unlink_from_ram(&inode, &next);
- if (rc != 0) {
- return rc;
- }
- next = SLIST_FIRST(list);
- }
- }
-
- entry = next;
- }
- }
-
- return 0;
-}
-
-/**
- * Creates a dummy inode and inserts it into the hash table. A dummy inode is
- * a temporary placeholder for a real inode that has not been restored yet.
- * These are necessary so that the inter-object links can be maintained until
- * the absent inode is eventually restored. Dummy inodes are identified by a
- * reference count of 0.
- *
- * @param id The ID of the dummy inode to create.
- * @param out_inode_entry On success, the dummy inode gets written here.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_dummy_inode(uint32_t id,
- struct nffs_inode_entry **out_inode_entry)
-{
- struct nffs_inode_entry *inode_entry;
-
- inode_entry = nffs_inode_entry_alloc();
- if (inode_entry == NULL) {
- return FS_ENOMEM;
- }
- inode_entry->nie_hash_entry.nhe_id = id;
- inode_entry->nie_hash_entry.nhe_flash_loc = NFFS_FLASH_LOC_NONE;
- inode_entry->nie_refcnt = 0;
-
- nffs_hash_insert(&inode_entry->nie_hash_entry);
-
- *out_inode_entry = inode_entry;
-
- return 0;
-}
-
-/**
- * Determines if an already-restored inode should be replaced by another inode
- * just read from flash. This function should only be called if both inodes
- * share the same ID. The existing inode gets replaced if:
- * o It is a dummy inode.
- * o Its sequence number is less than that of the new inode.
- *
- * @param old_inode_entry The already-restored inode to test.
- * @param disk_inode The inode just read from flash.
- * @param out_should_replace On success, 0=don't replace; 1=do replace.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_inode_gets_replaced(struct nffs_inode_entry *old_inode_entry,
- const struct nffs_disk_inode *disk_inode,
- int *out_should_replace)
-{
- struct nffs_inode old_inode;
- int rc;
-
- assert(old_inode_entry->nie_hash_entry.nhe_id == disk_inode->ndi_id);
-
- if (old_inode_entry->nie_refcnt == 0) {
- *out_should_replace = 1;
- return 0;
- }
-
- rc = nffs_inode_from_entry(&old_inode, old_inode_entry);
- if (rc != 0) {
- *out_should_replace = 0;
- return rc;
- }
-
- if (old_inode.ni_seq < disk_inode->ndi_seq) {
- *out_should_replace = 1;
- return 0;
- }
-
- if (old_inode.ni_seq == disk_inode->ndi_seq) {
- /* This is a duplicate of a previously-read inode. This should never
- * happen.
- */
- *out_should_replace = 0;
- return FS_ECORRUPT;
- }
-
- *out_should_replace = 0;
- return 0;
-}
-
-/**
- * Determines if the specified inode should be added to the RAM representation
- * and adds it if appropriate.
- *
- * @param disk_inode The inode just read from flash.
- * @param area_idx The index of the area containing the inode.
- * @param area_offset The offset within the area of the inode.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_inode(const struct nffs_disk_inode *disk_inode, uint8_t area_idx,
- uint32_t area_offset)
-{
- struct nffs_inode_entry *inode_entry;
- struct nffs_inode_entry *parent;
- struct nffs_inode inode;
- int new_inode;
- int do_add;
- int rc;
-
- new_inode = 0;
-
- /* Check the inode's CRC. If the inode is corrupt, discard it. */
- rc = nffs_crc_disk_inode_validate(disk_inode, area_idx, area_offset);
- if (rc != 0) {
- goto err;
- }
-
- inode_entry = nffs_hash_find_inode(disk_inode->ndi_id);
- if (inode_entry != NULL) {
- rc = nffs_restore_inode_gets_replaced(inode_entry, disk_inode,
- &do_add);
- if (rc != 0) {
- goto err;
- }
-
- if (do_add) {
- if (inode_entry->nie_hash_entry.nhe_flash_loc !=
- NFFS_FLASH_LOC_NONE) {
-
- rc = nffs_inode_from_entry(&inode, inode_entry);
- if (rc != 0) {
- return rc;
- }
- if (inode.ni_parent != NULL) {
- nffs_inode_remove_child(&inode);
- }
- }
-
- inode_entry->nie_hash_entry.nhe_flash_loc =
- nffs_flash_loc(area_idx, area_offset);
- }
- } else {
- inode_entry = nffs_inode_entry_alloc();
- if (inode_entry == NULL) {
- rc = FS_ENOMEM;
- goto err;
- }
- new_inode = 1;
- do_add = 1;
-
- inode_entry->nie_hash_entry.nhe_id = disk_inode->ndi_id;
- inode_entry->nie_hash_entry.nhe_flash_loc =
- nffs_flash_loc(area_idx, area_offset);
-
- nffs_hash_insert(&inode_entry->nie_hash_entry);
- }
-
- if (do_add) {
- inode_entry->nie_refcnt = 1;
-
- if (disk_inode->ndi_parent_id != NFFS_ID_NONE) {
- parent = nffs_hash_find_inode(disk_inode->ndi_parent_id);
- if (parent == NULL) {
- rc = nffs_restore_dummy_inode(disk_inode->ndi_parent_id,
- &parent);
- if (rc != 0) {
- goto err;
- }
- }
-
- rc = nffs_inode_add_child(parent, inode_entry);
- if (rc != 0) {
- goto err;
- }
- }
-
-
- if (inode_entry->nie_hash_entry.nhe_id == NFFS_ID_ROOT_DIR) {
- nffs_root_dir = inode_entry;
- }
- }
-
- if (nffs_hash_id_is_file(inode_entry->nie_hash_entry.nhe_id)) {
- if (inode_entry->nie_hash_entry.nhe_id >= nffs_hash_next_file_id) {
- nffs_hash_next_file_id = inode_entry->nie_hash_entry.nhe_id + 1;
- }
- } else {
- if (inode_entry->nie_hash_entry.nhe_id >= nffs_hash_next_dir_id) {
- nffs_hash_next_dir_id = inode_entry->nie_hash_entry.nhe_id + 1;
- }
- }
-
- return 0;
-
-err:
- if (new_inode) {
- nffs_inode_entry_free(inode_entry);
- }
- return rc;
-}
-
-/**
- * Indicates whether the specified data block is superseded by the just-read
- * disk data block. A data block supersedes another if its ID is equal and its
- * sequence number is greater than that of the other block.
- *
- * @param out_should_replace On success, 0 or 1 gets written here, to
- * indicate whether replacement should occur.
- * @param old_block The data block which has already been read and
- * converted to its RAM representation. This
- * is the block that may be superseded.
- * @param disk_block The disk data block that was just read from
- * flash. This is the block which may
- * supersede the other.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_block_gets_replaced(const struct nffs_block *old_block,
- const struct nffs_disk_block *disk_block,
- int *out_should_replace)
-{
- assert(old_block->nb_hash_entry->nhe_id == disk_block->ndb_id);
-
- if (old_block->nb_seq < disk_block->ndb_seq) {
- *out_should_replace = 1;
- return 0;
- }
-
- if (old_block->nb_seq == disk_block->ndb_seq) {
- /* This is a duplicate of an previously-read inode. This should never
- * happen.
- */
- return FS_ECORRUPT;
- }
-
- *out_should_replace = 0;
- return 0;
-}
-
-/**
- * Populates the nffs RAM state with the memory representation of the specified
- * disk data block.
- *
- * @param disk_block The source disk block to insert.
- * @param area_idx The ID of the area containing the block.
- * @param area_offset The area_offset within the area of the block.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_block(const struct nffs_disk_block *disk_block, uint8_t area_idx,
- uint32_t area_offset)
-{
- struct nffs_inode_entry *inode_entry;
- struct nffs_hash_entry *entry;
- struct nffs_block block;
- int do_replace;
- int new_block;
- int rc;
-
- new_block = 0;
-
- /* Check the block's CRC. If the block is corrupt, discard it. If this
- * block would have superseded another, the old block becomes current.
- */
- rc = nffs_crc_disk_block_validate(disk_block, area_idx, area_offset);
- if (rc != 0) {
- goto err;
- }
-
- entry = nffs_hash_find_block(disk_block->ndb_id);
- if (entry != NULL) {
- rc = nffs_block_from_hash_entry_no_ptrs(&block, entry);
- if (rc != 0) {
- goto err;
- }
-
- rc = nffs_restore_block_gets_replaced(&block, disk_block, &do_replace);
- if (rc != 0) {
- goto err;
- }
-
- if (!do_replace) {
- /* The new block is superseded by the old; nothing to do. */
- return 0;
- }
-
- nffs_block_delete_from_ram(entry);
- }
-
- entry = nffs_block_entry_alloc();
- if (entry == NULL) {
- rc = FS_ENOMEM;
- goto err;
- }
- new_block = 1;
- entry->nhe_id = disk_block->ndb_id;
- entry->nhe_flash_loc = nffs_flash_loc(area_idx, area_offset);
-
- /* The block is ready to be inserted into the hash. */
-
- inode_entry = nffs_hash_find_inode(disk_block->ndb_inode_id);
- if (inode_entry == NULL) {
- rc = nffs_restore_dummy_inode(disk_block->ndb_inode_id, &inode_entry);
- if (rc != 0) {
- goto err;
- }
- }
-
- if (inode_entry->nie_last_block_entry == NULL ||
- inode_entry->nie_last_block_entry->nhe_id == disk_block->ndb_prev_id) {
-
- inode_entry->nie_last_block_entry = entry;
- }
-
- nffs_hash_insert(entry);
-
- if (disk_block->ndb_id >= nffs_hash_next_block_id) {
- nffs_hash_next_block_id = disk_block->ndb_id + 1;
- }
-
- /* Make sure the maximum block data size is not set lower than the size of
- * an existing block.
- */
- if (disk_block->ndb_data_len > nffs_restore_largest_block_data_len) {
- nffs_restore_largest_block_data_len = disk_block->ndb_data_len;
- }
-
- return 0;
-
-err:
- if (new_block) {
- nffs_block_entry_free(entry);
- }
- return rc;
-}
-
-/**
- * Populates the nffs RAM state with the memory representation of the specified
- * disk object.
- *
- * @param disk_object The source disk object to convert.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_object(const struct nffs_disk_object *disk_object)
-{
- int rc;
-
- switch (disk_object->ndo_type) {
- case NFFS_OBJECT_TYPE_INODE:
- rc = nffs_restore_inode(&disk_object->ndo_disk_inode,
- disk_object->ndo_area_idx,
- disk_object->ndo_offset);
- break;
-
- case NFFS_OBJECT_TYPE_BLOCK:
- rc = nffs_restore_block(&disk_object->ndo_disk_block,
- disk_object->ndo_area_idx,
- disk_object->ndo_offset);
- break;
-
- default:
- assert(0);
- rc = FS_EINVAL;
- break;
- }
-
- return rc;
-}
-
-/**
- * Reads a single disk object from flash.
- *
- * @param area_idx The area to read the object from.
- * @param area_offset The offset within the area to read from.
- * @param out_disk_object On success, the restored object gets written
- * here.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_disk_object(int area_idx, uint32_t area_offset,
- struct nffs_disk_object *out_disk_object)
-{
- uint32_t magic;
- int rc;
-
- rc = nffs_flash_read(area_idx, area_offset, &magic, sizeof magic);
- if (rc != 0) {
- return rc;
- }
-
- switch (magic) {
- case NFFS_INODE_MAGIC:
- out_disk_object->ndo_type = NFFS_OBJECT_TYPE_INODE;
- rc = nffs_inode_read_disk(area_idx, area_offset,
- &out_disk_object->ndo_disk_inode);
- break;
-
- case NFFS_BLOCK_MAGIC:
- out_disk_object->ndo_type = NFFS_OBJECT_TYPE_BLOCK;
- rc = nffs_block_read_disk(area_idx, area_offset,
- &out_disk_object->ndo_disk_block);
- break;
-
- case 0xffffffff:
- rc = FS_EEMPTY;
- break;
-
- default:
- rc = FS_ECORRUPT;
- break;
- }
-
- if (rc != 0) {
- return rc;
- }
-
- out_disk_object->ndo_area_idx = area_idx;
- out_disk_object->ndo_offset = area_offset;
-
- return 0;
-}
-
-/**
- * Calculates the disk space occupied by the specified disk object.
- *
- * @param disk_object
- */
-static int
-nffs_restore_disk_object_size(const struct nffs_disk_object *disk_object)
-{
- switch (disk_object->ndo_type) {
- case NFFS_OBJECT_TYPE_INODE:
- return sizeof disk_object->ndo_disk_inode +
- disk_object->ndo_disk_inode.ndi_filename_len;
-
- case NFFS_OBJECT_TYPE_BLOCK:
- return sizeof disk_object->ndo_disk_block +
- disk_object->ndo_disk_block.ndb_data_len;
-
- default:
- assert(0);
- return 1;
- }
-}
-
-/**
- * Reads the specified area from disk and loads its contents into the RAM
- * representation.
- *
- * @param area_idx The index of the area to read.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_area_contents(int area_idx)
-{
- struct nffs_disk_object disk_object;
- struct nffs_area *area;
- int rc;
-
- area = nffs_areas + area_idx;
-
- area->na_cur = sizeof (struct nffs_disk_area);
- while (1) {
- rc = nffs_restore_disk_object(area_idx, area->na_cur, &disk_object);
- switch (rc) {
- case 0:
- /* Valid object; restore it into the RAM representation. */
- nffs_restore_object(&disk_object);
- area->na_cur += nffs_restore_disk_object_size(&disk_object);
- break;
-
- case FS_ECORRUPT:
- /* Invalid object; keep scanning for a valid magic number. */
- area->na_cur++;
- break;
-
- case FS_EEMPTY:
- case FS_ERANGE:
- /* End of disk encountered; area fully restored. */
- return 0;
-
- default:
- return rc;
- }
- }
-}
-
-/**
- * Reads and parses one area header. This function does not read the area's
- * contents.
- *
- * @param out_is_scratch On success, 0 or 1 gets written here,
- * indicating whether the area is a scratch
- * area.
- * @param area_offset The flash offset of the start of the area.
- *
- * @return 0 on success;
- * nonzero on failure.
- */
-static int
-nffs_restore_detect_one_area(uint8_t flash_id, uint32_t area_offset,
- struct nffs_disk_area *out_disk_area)
-{
- int rc;
-
- rc = hal_flash_read(flash_id, area_offset, out_disk_area,
- sizeof *out_disk_area);
- if (rc != 0) {
- return FS_HW_ERROR;
- }
-
- if (!nffs_area_magic_is_set(out_disk_area)) {
- return FS_ECORRUPT;
- }
-
- return 0;
-}
-
-/**
- * Repairs the effects of a corrupt scratch area. Scratch area corruption can
- * occur when the system resets while a garbage collection cycle is in
- * progress.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_restore_corrupt_scratch(void)
-{
- struct nffs_inode_entry *inode_entry;
- struct nffs_hash_entry *entry;
- struct nffs_hash_entry *next;
- uint32_t area_offset;
- uint16_t good_idx;
- uint16_t bad_idx;
- uint8_t area_idx;
- int rc;
- int i;
-
- /* Search for a pair of areas with identical IDs. If found, these areas
- * represent the source and destination areas of a garbage collection
- * cycle. The shorter of the two areas was the destination area. Since
- * the garbage collection cycle did not finish, the source area contains a
- * more complete set of objects than the destination area.
- *
- * good_idx = index of source area.
- * bad_idx = index of destination area; this will be turned into the
- * scratch area.
- */
- rc = nffs_area_find_corrupt_scratch(&good_idx, &bad_idx);
- if (rc != 0) {
- return rc;
- }
-
- /* Invalidate all objects resident in the bad area. */
- for (i = 0; i < NFFS_HASH_SIZE; i++) {
- entry = SLIST_FIRST(&nffs_hash[i]);
- while (entry != NULL) {
- next = SLIST_NEXT(entry, nhe_next);
-
- nffs_flash_loc_expand(entry->nhe_flash_loc,
- &area_idx, &area_offset);
- if (area_idx == bad_idx) {
- if (nffs_hash_id_is_block(entry->nhe_id)) {
- rc = nffs_block_delete_from_ram(entry);
- if (rc != 0) {
- return rc;
- }
- } else {
- inode_entry = (struct nffs_inode_entry *)entry;
- inode_entry->nie_refcnt = 0;
- }
- }
-
- entry = next;
- }
- }
-
- /* Now that the objects in the scratch area have been invalidated, reload
- * everything from the good area.
- */
- rc = nffs_restore_area_contents(good_idx);
- if (rc != 0) {
- return rc;
- }
-
- /* Convert the bad area into a scratch area. */
- rc = nffs_format_area(bad_idx, 1);
- if (rc != 0) {
- return rc;
- }
- nffs_scratch_area_idx = bad_idx;
-
- return 0;
-}
-
-/**
- * Searches for a valid nffs file system among the specified areas. This
- * function succeeds if a file system is detected among any subset of the
- * supplied areas. If the area set does not contain a valid file system,
- * a new one can be created via a call to nffs_format().
- *
- * @param area_descs The area set to search. This array must be
- * terminated with a 0-length area.
- *
- * @return 0 on success;
- * FS_ECORRUPT if no valid file system was detected;
- * other nonzero on error.
- */
-int
-nffs_restore_full(const struct nffs_area_desc *area_descs)
-{
- struct nffs_disk_area disk_area;
- int cur_area_idx;
- int use_area;
- int rc;
- int i;
-
- /* Start from a clean state. */
- rc = nffs_misc_reset();
- if (rc) {
- return rc;
- }
- nffs_restore_largest_block_data_len = 0;
-
- /* Read each area from flash. */
- for (i = 0; area_descs[i].nad_length != 0; i++) {
- if (i > NFFS_MAX_AREAS) {
- rc = FS_EINVAL;
- goto err;
- }
-
- rc = nffs_restore_detect_one_area(area_descs[i].nad_flash_id,
- area_descs[i].nad_offset,
- &disk_area);
- switch (rc) {
- case 0:
- use_area = 1;
- break;
-
- case FS_ECORRUPT:
- use_area = 0;
- break;
-
- default:
- goto err;
- }
-
- if (use_area) {
- if (disk_area.nda_id == NFFS_AREA_ID_NONE &&
- nffs_scratch_area_idx != NFFS_AREA_ID_NONE) {
-
- /* Don't allow more than one scratch area. */
- use_area = 0;
- }
- }
-
- if (use_area) {
- /* Populate RAM with a representation of this area. */
- cur_area_idx = nffs_num_areas;
-
- rc = nffs_misc_set_num_areas(nffs_num_areas + 1);
- if (rc != 0) {
- goto err;
- }
-
- nffs_areas[cur_area_idx].na_offset = area_descs[i].nad_offset;
- nffs_areas[cur_area_idx].na_length = area_descs[i].nad_length;
- nffs_areas[cur_area_idx].na_flash_id = area_descs[i].nad_flash_id;
- nffs_areas[cur_area_idx].na_gc_seq = disk_area.nda_gc_seq;
- nffs_areas[cur_area_idx].na_id = disk_area.nda_id;
-
- if (disk_area.nda_id == NFFS_AREA_ID_NONE) {
- nffs_areas[cur_area_idx].na_cur = NFFS_AREA_OFFSET_ID;
- nffs_scratch_area_idx = cur_area_idx;
- } else {
- nffs_areas[cur_area_idx].na_cur =
- sizeof (struct nffs_disk_area);
- nffs_restore_area_contents(cur_area_idx);
- }
- }
- }
-
- /* All areas have been restored from flash. */
-
- if (nffs_scratch_area_idx == NFFS_AREA_ID_NONE) {
- /* No scratch area. The system may have been rebooted in the middle of
- * a garbage collection cycle. Look for a candidate scratch area.
- */
- rc = nffs_restore_corrupt_scratch();
- if (rc != 0) {
- if (rc == FS_ENOENT) {
- rc = FS_ECORRUPT;
- }
- goto err;
- }
- }
-
- /* Ensure this file system contains a valid scratch area. */
- rc = nffs_misc_validate_scratch();
- if (rc != 0) {
- goto err;
- }
-
- /* Make sure the file system contains a valid root directory. */
- rc = nffs_misc_validate_root_dir();
- if (rc != 0) {
- goto err;
- }
-
- /* Ensure there is a "/lost+found" directory. */
- rc = nffs_misc_create_lost_found_dir();
- if (rc != 0) {
- goto err;
- }
-
- /* Delete from RAM any objects that were invalidated when subsequent areas
- * were restored.
- */
- nffs_restore_sweep();
-
- /* Set the maximum data block size according to the size of the smallest
- * area.
- */
- rc = nffs_misc_set_max_block_data_len(nffs_restore_largest_block_data_len);
- if (rc != 0) {
- goto err;
- }
-
- return 0;
-
-err:
- nffs_misc_reset();
- return rc;
-}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/cf40853d/libs/nffs/src/nffs_write.c
----------------------------------------------------------------------
diff --git a/libs/nffs/src/nffs_write.c b/libs/nffs/src/nffs_write.c
deleted file mode 100644
index 3d5325b..0000000
--- a/libs/nffs/src/nffs_write.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/**
- * Copyright (c) 2015 Runtime Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include "testutil/testutil.h"
-#include "nffs/nffs.h"
-#include "nffs_priv.h"
-#include "crc16.h"
-
-static int
-nffs_write_fill_crc16_overwrite(struct nffs_disk_block *disk_block,
- uint8_t src_area_idx, uint32_t src_area_offset,
- uint16_t left_copy_len, uint16_t right_copy_len,
- const void *new_data, uint16_t new_data_len)
-{
- uint16_t block_off;
- uint16_t crc16;
- int rc;
-
- block_off = 0;
-
- crc16 = nffs_crc_disk_block_hdr(disk_block);
- block_off += sizeof *disk_block;
-
- /* Copy data from the start of the old block, in case the new data starts
- * at a non-zero offset.
- */
- if (left_copy_len > 0) {
- rc = nffs_crc_flash(crc16, src_area_idx, src_area_offset + block_off,
- left_copy_len, &crc16);
- if (rc != 0) {
- return rc;
- }
- block_off += left_copy_len;
- }
-
- /* Write the new data into the data block. This may extend the block's
- * length beyond its old value.
- */
- crc16 = crc16_ccitt(crc16, new_data, new_data_len);
- block_off += new_data_len;
-
- /* Copy data from the end of the old block, in case the new data doesn't
- * extend to the end of the block.
- */
- if (right_copy_len > 0) {
- rc = nffs_crc_flash(crc16, src_area_idx, src_area_offset + block_off,
- right_copy_len, &crc16);
- if (rc != 0) {
- return rc;
- }
- block_off += right_copy_len;
- }
-
- assert(block_off == sizeof *disk_block + disk_block->ndb_data_len);
-
- disk_block->ndb_crc16 = crc16;
-
- return 0;
-}
-
-/**
- * Overwrites an existing data block. The resulting block has the same ID as
- * the old one, but it supersedes it with a greater sequence number.
- *
- * @param entry The data block to overwrite.
- * @param left_copy_len The number of bytes of existing data to retain
- * before the new data begins.
- * @param new_data The new data to write to the block.
- * @param new_data_len The number of new bytes to write to the block.
- * If this value plus left_copy_len is less
- * than the existing block's data length,
- * previous data at the end of the block is
- * retained.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_write_over_block(struct nffs_hash_entry *entry, uint16_t left_copy_len,
- const void *new_data, uint16_t new_data_len)
-{
- struct nffs_disk_block disk_block;
- struct nffs_block block;
- uint32_t src_area_offset;
- uint32_t dst_area_offset;
- uint16_t right_copy_len;
- uint16_t block_off;
- uint8_t src_area_idx;
- uint8_t dst_area_idx;
- int rc;
-
- rc = nffs_block_from_hash_entry(&block, entry);
- if (rc != 0) {
- return rc;
- }
-
- assert(left_copy_len <= block.nb_data_len);
-
- /* Determine how much old data at the end of the block needs to be
- * retained. If the new data doesn't extend to the end of the block, the
- * the rest of the block retains its old contents.
- */
- if (left_copy_len + new_data_len > block.nb_data_len) {
- right_copy_len = 0;
- } else {
- right_copy_len = block.nb_data_len - left_copy_len - new_data_len;
- }
-
- block.nb_seq++;
- block.nb_data_len = left_copy_len + new_data_len + right_copy_len;
- nffs_block_to_disk(&block, &disk_block);
-
- nffs_flash_loc_expand(entry->nhe_flash_loc,
- &src_area_idx, &src_area_offset);
-
- rc = nffs_write_fill_crc16_overwrite(&disk_block,
- src_area_idx, src_area_offset,
- left_copy_len, right_copy_len,
- new_data, new_data_len);
- if (rc != 0) {
- return rc;
- }
-
- rc = nffs_misc_reserve_space(sizeof disk_block + disk_block.ndb_data_len,
- &dst_area_idx, &dst_area_offset);
- if (rc != 0) {
- return rc;
- }
-
- block_off = 0;
-
- /* Write the block header. */
- rc = nffs_flash_write(dst_area_idx, dst_area_offset + block_off,
- &disk_block, sizeof disk_block);
- if (rc != 0) {
- return rc;
- }
- block_off += sizeof disk_block;
-
- /* Copy data from the start of the old block, in case the new data starts
- * at a non-zero offset.
- */
- if (left_copy_len > 0) {
- rc = nffs_flash_copy(src_area_idx, src_area_offset + block_off,
- dst_area_idx, dst_area_offset + block_off,
- left_copy_len);
- if (rc != 0) {
- return rc;
- }
- block_off += left_copy_len;
- }
-
- /* Write the new data into the data block. This may extend the block's
- * length beyond its old value.
- */
- rc = nffs_flash_write(dst_area_idx, dst_area_offset + block_off,
- new_data, new_data_len);
- if (rc != 0) {
- return rc;
- }
- block_off += new_data_len;
-
- /* Copy data from the end of the old block, in case the new data doesn't
- * extend to the end of the block.
- */
- if (right_copy_len > 0) {
- rc = nffs_flash_copy(src_area_idx, src_area_offset + block_off,
- dst_area_idx, dst_area_offset + block_off,
- right_copy_len);
- if (rc != 0) {
- return rc;
- }
- block_off += right_copy_len;
- }
-
- assert(block_off == sizeof disk_block + block.nb_data_len);
-
- entry->nhe_flash_loc = nffs_flash_loc(dst_area_idx, dst_area_offset);
-
- ASSERT_IF_TEST(nffs_crc_disk_block_validate(&disk_block, dst_area_idx,
- dst_area_offset) == 0);
-
- return 0;
-}
-
-/**
- * Appends a new block to an inode block chain.
- *
- * @param inode_entry The inode to append a block to.
- * @param data The contents of the new block.
- * @param len The number of bytes of data to write.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_write_append(struct nffs_cache_inode *cache_inode, const void *data,
- uint16_t len)
-{
- struct nffs_inode_entry *inode_entry;
- struct nffs_hash_entry *entry;
- struct nffs_disk_block disk_block;
- uint32_t area_offset;
- uint8_t area_idx;
- int rc;
-
- entry = nffs_block_entry_alloc();
- if (entry == NULL) {
- return FS_ENOMEM;
- }
-
- inode_entry = cache_inode->nci_inode.ni_inode_entry;
-
- disk_block.ndb_magic = NFFS_BLOCK_MAGIC;
- disk_block.ndb_id = nffs_hash_next_block_id++;
- disk_block.ndb_seq = 0;
- disk_block.ndb_inode_id = inode_entry->nie_hash_entry.nhe_id;
- if (inode_entry->nie_last_block_entry == NULL) {
- disk_block.ndb_prev_id = NFFS_ID_NONE;
- } else {
- disk_block.ndb_prev_id = inode_entry->nie_last_block_entry->nhe_id;
- }
- disk_block.ndb_data_len = len;
- nffs_crc_disk_block_fill(&disk_block, data);
-
- rc = nffs_block_write_disk(&disk_block, data, &area_idx, &area_offset);
- if (rc != 0) {
- return rc;
- }
-
- entry->nhe_id = disk_block.ndb_id;
- entry->nhe_flash_loc = nffs_flash_loc(area_idx, area_offset);
- nffs_hash_insert(entry);
-
- inode_entry->nie_last_block_entry = entry;
-
- /* Update cached inode with the new file size. */
- cache_inode->nci_file_size += len;
-
- /* Add appended block to the cache. */
- nffs_cache_seek(cache_inode, cache_inode->nci_file_size - 1, NULL);
-
- return 0;
-}
-
-/**
- * Performs a single write operation. The data written must be no greater
- * than the maximum block data length. If old data gets overwritten, then
- * the existing data blocks are superseded as necessary.
- *
- * @param write_info Describes the write operation being perfomred.
- * @param inode_entry The file inode to write to.
- * @param data The new data to write.
- * @param data_len The number of bytes of new data to write.
- *
- * @return 0 on success; nonzero on failure.
- */
-static int
-nffs_write_chunk(struct nffs_cache_inode *cache_inode, uint32_t file_offset,
- const void *data, uint16_t data_len)
-{
- struct nffs_cache_block *cache_block;
- uint32_t append_len;
- uint32_t data_offset;
- uint32_t block_end;
- uint32_t dst_off;
- uint16_t chunk_off;
- uint16_t chunk_sz;
- int rc;
-
- assert(data_len <= nffs_block_max_data_sz);
-
- /** Handle the simple append case first. */
- if (file_offset == cache_inode->nci_file_size) {
- rc = nffs_write_append(cache_inode, data, data_len);
- return rc;
- }
-
- /** This is not an append; i.e., old data is getting overwritten. */
-
- dst_off = file_offset + data_len;
- data_offset = data_len;
- cache_block = NULL;
-
- if (dst_off > cache_inode->nci_file_size) {
- append_len = dst_off - cache_inode->nci_file_size;
- } else {
- append_len = 0;
- }
-
- do {
- if (cache_block == NULL) {
- rc = nffs_cache_seek(cache_inode, dst_off - 1, &cache_block);
- if (rc != 0) {
- return rc;
- }
- }
-
- if (cache_block->ncb_file_offset < file_offset) {
- chunk_off = file_offset - cache_block->ncb_file_offset;
- } else {
- chunk_off = 0;
- }
-
- chunk_sz = cache_block->ncb_block.nb_data_len - chunk_off;
- block_end = cache_block->ncb_file_offset +
- cache_block->ncb_block.nb_data_len;
- if (block_end != dst_off) {
- chunk_sz += (int)(dst_off - block_end);
- }
-
- data_offset = cache_block->ncb_file_offset + chunk_off - file_offset;
- rc = nffs_write_over_block(cache_block->ncb_block.nb_hash_entry,
- chunk_off, data + data_offset, chunk_sz);
- if (rc != 0) {
- return rc;
- }
-
- dst_off -= chunk_sz;
- cache_block = TAILQ_PREV(cache_block, nffs_cache_block_list, ncb_link);
- } while (data_offset > 0);
-
- cache_inode->nci_file_size += append_len;
- return 0;
-}
-
-/**
- * Writes a chunk of contiguous data to a file.
- *
- * @param file The file to write to.
- * @param data The data to write.
- * @param len The length of data to write.
- *
- * @return 0 on success; nonzero on failure.
- */
-int
-nffs_write_to_file(struct nffs_file *file, const void *data, int len)
-{
- struct nffs_cache_inode *cache_inode;
- const uint8_t *data_ptr;
- uint16_t chunk_size;
- int rc;
-
- if (!(file->nf_access_flags & FS_ACCESS_WRITE)) {
- return FS_EACCESS;
- }
-
- if (len == 0) {
- return 0;
- }
-
- rc = nffs_cache_inode_ensure(&cache_inode, file->nf_inode_entry);
- if (rc != 0) {
- return rc;
- }
-
- /* The append flag forces all writes to the end of the file, regardless of
- * seek position.
- */
- if (file->nf_access_flags & FS_ACCESS_APPEND) {
- file->nf_offset = cache_inode->nci_file_size;
- }
-
- /* Write data as a sequence of blocks. */
- data_ptr = data;
- while (len > 0) {
- if (len > nffs_block_max_data_sz) {
- chunk_size = nffs_block_max_data_sz;
- } else {
- chunk_size = len;
- }
-
- rc = nffs_write_chunk(cache_inode, file->nf_offset, data_ptr,
- chunk_size);
- if (rc != 0) {
- return rc;
- }
-
- len -= chunk_size;
- data_ptr += chunk_size;
- file->nf_offset += chunk_size;
- }
-
- return 0;
-}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/cf40853d/libs/nffs/src/test/arch/cortex_m4/nffs_test.c
----------------------------------------------------------------------
diff --git a/libs/nffs/src/test/arch/cortex_m4/nffs_test.c b/libs/nffs/src/test/arch/cortex_m4/nffs_test.c
deleted file mode 100644
index f15447d..0000000
--- a/libs/nffs/src/test/arch/cortex_m4/nffs_test.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2015 Runtime Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "nffs/nffs_test.h"
-
-int
-nffs_test_all(void)
-{
- return 0;
-}