diff --git a/configs/sim/nxffs/defconfig b/configs/sim/nxffs/defconfig index acedc357da..2fa2297c19 100644 --- a/configs/sim/nxffs/defconfig +++ b/configs/sim/nxffs/defconfig @@ -355,6 +355,7 @@ CONFIG_NSH_NETMASK=(255<<24|255<<16|255<<8|0) # Various FS, NXFFS, RAMMTD and other settings needed for # apps/examples/nxffs # +CONFIG_LIB_RAND_ORDER=3 CONFIG_FS_NXFFS=y CONFIG_NXFFS_ERASEDSTATE=0xff CONFIG_NXFSS_PREALLOCATED=y diff --git a/fs/nxffs/nxffs.h b/fs/nxffs/nxffs.h index 48311f3ec6..51c7d7a3d6 100644 --- a/fs/nxffs/nxffs.h +++ b/fs/nxffs/nxffs.h @@ -239,6 +239,15 @@ struct nxffs_entry_s uint32_t datlen; /* Length of inode data */ }; +/* This structure describes int in-memory representation of the data block */ + +struct nxffs_blkentry_s +{ + off_t hoffset; /* Offset to the block data header */ + uint16_t datlen; /* Length of data following the header */ + uint16_t foffset; /* Offset to start of data */ +}; + /* This structure describes the state of one open file. This structure * is protected by the volume semaphore. */ @@ -285,6 +294,7 @@ struct nxffs_volume_s off_t cblock; /* Starting block number in cache */ FAR struct nxffs_ofile_s *ofiles; /* A singly-linked list of open files */ FAR uint8_t *cache; /* Allocated erase block */ + FAR uint8_t *pack; /* Extra I/O block buffer to support packing */ }; /* This structure describes the state of the blocks on the NXFFS volume */ @@ -769,13 +779,34 @@ extern FAR struct nxffs_ofile_s *nxffs_findofile(FAR struct nxffs_volume_s *volu * volume->froffset - Updated offset to the first free FLASH block after * the reserved memory. * - * * Defined in nxffs_write.c * ****************************************************************************/ extern int nxffs_wrreserve(FAR struct nxffs_volume_s *volume, size_t size); +/**************************************************************************** + * Name: nxffs_nextblock + * + * Description: + * Search for the next valid data block starting at the provided + * FLASH offset. + * + * Input Parameters: + * volume - Describes the NXFFS volume. + * datlen - A memory location to return the data block length. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno is returned + * that indicates the nature of the failure. + * + * Defined in nxffs_read.c + * + ****************************************************************************/ + +extern int nxffs_nextblock(FAR struct nxffs_volume_s *volume, off_t offset, + FAR struct nxffs_blkentry_s *blkentry); + /**************************************************************************** * Name: nxffs_wrverify * @@ -814,6 +845,8 @@ extern int nxffs_wrreserve(FAR struct nxffs_volume_s *volume, size_t size); * position. * volume->froffset - Updated offset to the first free FLASH block. * + * Defined in nxffs_write.c + * ****************************************************************************/ extern int nxffs_wrverify(FAR struct nxffs_volume_s *volume, size_t size); diff --git a/fs/nxffs/nxffs_initialize.c b/fs/nxffs/nxffs_initialize.c index adf1f76f79..2d1f61e4cf 100644 --- a/fs/nxffs/nxffs_initialize.c +++ b/fs/nxffs/nxffs_initialize.c @@ -207,6 +207,19 @@ int nxffs_initialize(FAR struct mtd_dev_s *mtd) goto errout_with_volume; } + /* Pre-allocate one additional I/O block buffer to support filesystem + * packing. This buffer is not needed often, but is best to have pre- + * allocated and in-place. + */ + + volume->pack = (FAR uint8_t *)kmalloc(volume->geo.blocksize); + if (!volume->pack) + { + fdbg("Failed to allocate an I/O block buffer\n"); + ret = -ENOMEM; + goto errout_with_cache; + } + /* Get the number of R/W blocks per erase block and the total number o * R/W blocks */ @@ -221,7 +234,7 @@ int nxffs_initialize(FAR struct mtd_dev_s *mtd) if (ret < 0) { fdbg("Failed to collect block statistics: %d\n", -ret); - goto errout_with_iobuffer; + goto errout_with_buffer; } /* If the proportion of good blocks is low or the proportion of unformatted @@ -237,7 +250,7 @@ int nxffs_initialize(FAR struct mtd_dev_s *mtd) if (ret < 0) { fdbg("Failed to reformat the volume: %d\n", -ret); - goto errout_with_iobuffer; + goto errout_with_buffer; } /* Get statistics on the re-formatted volume */ @@ -247,7 +260,7 @@ int nxffs_initialize(FAR struct mtd_dev_s *mtd) if (ret < 0) { fdbg("Failed to collect block statistics: %d\n", -ret); - goto errout_with_iobuffer; + goto errout_with_buffer; } #endif } @@ -261,7 +274,9 @@ int nxffs_initialize(FAR struct mtd_dev_s *mtd) } fdbg("Failed to calculate file system limits: %d\n", -ret); -errout_with_iobuffer: +errout_with_buffer: + kfree(volume->pack); +errout_with_cache: kfree(volume->cache); errout_with_volume: kfree(volume); diff --git a/fs/nxffs/nxffs_pack.c b/fs/nxffs/nxffs_pack.c index 476c5972be..b44a157366 100644 --- a/fs/nxffs/nxffs_pack.c +++ b/fs/nxffs/nxffs_pack.c @@ -41,7 +41,10 @@ #include +#include #include +#include +#include #include "nxffs.h" @@ -52,6 +55,24 @@ /**************************************************************************** * Public Types ****************************************************************************/ +/* This structure supports access to one inode data stream */ + +struct nxffs_packstream_s +{ + struct nxffs_entry_s entry; /* Described the inode header */ + off_t fpos; /* Current file position */ + off_t blkoffset; /* Offset to the current data block */ + uint16_t blklen; /* Size of this block */ + uint16_t blkpos; /* Position in block corresponding to fpos */ +}; + +/* The structure supports the overall packing operation */ + +struct nxffs_pack_s +{ + struct nxffs_packstream_s src; /* Describes the src stream */ + struct nxffs_packstream_s dest; /* Describes the destination stream */ +}; /**************************************************************************** * Public Variables @@ -61,6 +82,140 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nxffs_startblock + * + * Description: + * Find the position in FLASH memory where we should begin packing. That + * position is the place where there is a gap between the last and the next + * valid inode. + * + * Input Parameters: + * volume - The volume to be packed. + * + * Returned Values: + * Zero on success; Otherwise, a negated errno value is returned to + * indicate the nature of the failure. + * + ****************************************************************************/ + +static int nxffs_startblock(FAR struct nxffs_volume_s *volume, + FAR struct nxffs_pack_s *pack) +{ + struct nxffs_blkentry_s blkentry; + off_t wasted; + off_t offset; + off_t nbytes; + int ret; + + memset(pack, 0, sizeof(struct nxffs_pack_s)); + + /* Find the FLASH offset to the first valid block */ + + volume->ioblock = 0; + ret = nxffs_validblock(volume, &volume->ioblock); + if (ret < 0) + { + /* No valid blocks? */ + + return nxffs_reformat(volume); + } + + volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR; + offset = nxffs_iotell(volume); + + /* Loop until we find a gap of unused FLASH large enough to warrant the + * compression. + */ + + for(;;) + { + /* Get the offset to the first valid inode entry */ + + ret = nxffs_nextentry(volume, offset, &pack->src.entry); + if (ret < 0) + { + /* No valid entries -- reformat the flash */ + + return nxffs_reformat(volume); + } + + /* Is there wasted space between the offset where the we could have + * valid data and the offset to the beginning of the first valid + * inode header? NOTE: The threshold check is not accurate, there + * may or may not be intervening block headers making the separation + * seem larger than it is. + */ + + DEBUGASSERT(pack->src.entry.hoffset >= offset); + wasted = pack->src.entry.hoffset - offset; + if (wasted > CONFIG_NXFFS_PACKTHRESHOLD) + { + /* This is where we must begin packing */ + + memcpy(&pack->dest.entry, &pack->src.entry, sizeof(struct nxffs_entry_s)); + + pack->dest.entry.hoffset = offset; + pack->src.entry.name = NULL; + return OK; + } + + /* Free the allocated memory in the entry */ + + nxffs_freeentry(&pack->src.entry); + + /* Update the offset to the first byte at the end of the last data + * block. + */ + + nbytes = 0; + offset = pack->src.entry.doffset; + + while (nbytes < pack->src.entry.datlen) + { + /* Read the next data block header */ + + ret = nxffs_nextblock(volume, offset, &blkentry); + if (ret < 0) + { + fdbg("Failed to find next data block: %d\n", -ret); + return ret; + } + + /* Get the number of blocks and pointer to where the next + * data block might lie. + */ + + nbytes += blkentry.datlen; + offset = blkentry.hoffset + SIZEOF_NXFFS_DATA_HDR + blkentry.datlen; + } + + /* Make sure there is space at this location for an inode header */ + + nxffs_ioseek(volume, offset); + if (volume->iooffset + SIZEOF_NXFFS_INODE_HDR > volume->geo.blocksize) + { + /* Find the next valid block */ + + volume->ioblock++; + ret = nxffs_validblock(volume, &volume->ioblock); + if (ret < 0) + { + /* No valid blocks? Then there is nothing we can do */ + + return -ENOSPC; + } + + volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR; + offset = nxffs_iotell(volume); + } + } + + /* We won't get here */ + + return -ENOSYS; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -83,6 +238,29 @@ int nxffs_pack(FAR struct nxffs_volume_s *volume) { + struct nxffs_pack_s pack; + int ret; + + /* Get the offset to the first valid inode entry */ + + ret = nxffs_startblock(volume, &pack); + if (ret < 0) + { + fdbg("Failed to find a start block: %d\n", -ret); + return ret; + } + + /* A special case is where the entire FLASH needs to be reformatted. In + * this case, the source and destination offsets will both be zero. + */ + + if (pack.src.entry.hoffset == 0 && pack.dest.entry.hoffset == 0) + { + return OK; + } + + /* Otherwise, begin pack at this src/dest block combination */ + # warning "Missing logic" return -ENOSYS; } diff --git a/fs/nxffs/nxffs_read.c b/fs/nxffs/nxffs_read.c index bb400e232e..30fcd09aae 100644 --- a/fs/nxffs/nxffs_read.c +++ b/fs/nxffs/nxffs_read.c @@ -61,13 +61,6 @@ * Public Types ****************************************************************************/ -struct nxffs_blkentry_s -{ - off_t hoffset; /* Offset to the block data header */ - uint16_t datlen; /* Length of data following the header */ - uint16_t foffset; /* Offset to start of data */ -}; - /**************************************************************************** * Public Variables ****************************************************************************/ @@ -145,127 +138,6 @@ static int nxffs_rdblkhdr(FAR struct nxffs_volume_s *volume, off_t offset, return OK; } -/**************************************************************************** - * Name: nxffs_nextblock - * - * Description: - * Search for the next valid data block starting at the provided - * FLASH offset. - * - * Input Parameters: - * volume - Describes the NXFFS volume. - * datlen - A memory location to return the data block length. - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno is returned - * that indicates the nature of the failure. - * - ****************************************************************************/ - -int nxffs_nextblock(FAR struct nxffs_volume_s *volume, off_t offset, - FAR struct nxffs_blkentry_s *blkentry) -{ - int nmagic; - int ch; - int nerased; - int ret; - - /* Seek to the first FLASH offset provided by the caller. */ - - nxffs_ioseek(volume, offset); - - /* Skip the block header */ - - if (volume->iooffset < SIZEOF_NXFFS_BLOCK_HDR) - { - volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR; - } - - /* Then begin searching */ - - nerased = 0; - nmagic = 0; - - for (;;) - { - /* Read the next character */ - - ch = nxffs_getc(volume); - if (ch < 0) - { - fvdbg("nxffs_getc failed: %d\n", -ch); - return ch; - } - - /* Check for another erased byte */ - - else if (ch == CONFIG_NXFFS_ERASEDSTATE) - { - /* If we have encountered NXFFS_NERASED number of consecutive - * erased bytes, then presume we have reached the end of valid - * data. - */ - - if (++nerased >= NXFFS_NERASED) - { - fvdbg("No entry found\n"); - return -ENOENT; - } - } - else - { - nerased = 0; - - /* Check for the magic sequence indicating the start of an NXFFS - * data block or start of the next inode. There is the possibility - * of this magic sequnce occurring in FLASH data. However, the - * data block CRC should distinguish between real NXFFS data blocks - * headers and such false alarms. - */ - - if (ch != g_datamagic[nmagic]) - { - nmagic = 0; - } - else if (nmagic < NXFFS_MAGICSIZE - 1) - { - nmagic++; - } - - /* We have found the magic sequence in the FLASH data that may - * indicate the beginning of an NXFFS data block. - */ - - else - { - /* The offset to the header must be 4 bytes before the current - * FLASH seek location. - */ - - blkentry->hoffset = nxffs_iotell(volume) - 4; - - /* Read the block header and verify the block at that address */ - - ret = nxffs_rdblkhdr(volume, blkentry->hoffset, &blkentry->datlen); - if (ret == OK) - { - fvdbg("Found a valid data block, offset: %d datlen: %d\n", - blkentry->hoffset, blkentry->datlen); - return OK; - } - - /* False alarm.. keep looking */ - - nmagic = 0; - } - } - } - - /* We won't get here, but to keep some compilers happy: */ - - return -ENOENT; -} - /**************************************************************************** * Name: nxffs_rdseek * @@ -444,3 +316,125 @@ errout: return (ssize_t)ret; } +/**************************************************************************** + * Name: nxffs_nextblock + * + * Description: + * Search for the next valid data block starting at the provided + * FLASH offset. + * + * Input Parameters: + * volume - Describes the NXFFS volume. + * datlen - A memory location to return the data block length. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno is returned + * that indicates the nature of the failure. + * + ****************************************************************************/ + +int nxffs_nextblock(FAR struct nxffs_volume_s *volume, off_t offset, + FAR struct nxffs_blkentry_s *blkentry) +{ + int nmagic; + int ch; + int nerased; + int ret; + + /* Seek to the first FLASH offset provided by the caller. */ + + nxffs_ioseek(volume, offset); + + /* Skip the block header */ + + if (volume->iooffset < SIZEOF_NXFFS_BLOCK_HDR) + { + volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR; + } + + /* Then begin searching */ + + nerased = 0; + nmagic = 0; + + for (;;) + { + /* Read the next character */ + + ch = nxffs_getc(volume); + if (ch < 0) + { + fvdbg("nxffs_getc failed: %d\n", -ch); + return ch; + } + + /* Check for another erased byte */ + + else if (ch == CONFIG_NXFFS_ERASEDSTATE) + { + /* If we have encountered NXFFS_NERASED number of consecutive + * erased bytes, then presume we have reached the end of valid + * data. + */ + + if (++nerased >= NXFFS_NERASED) + { + fvdbg("No entry found\n"); + return -ENOENT; + } + } + else + { + nerased = 0; + + /* Check for the magic sequence indicating the start of an NXFFS + * data block or start of the next inode. There is the possibility + * of this magic sequnce occurring in FLASH data. However, the + * data block CRC should distinguish between real NXFFS data blocks + * headers and such false alarms. + */ + + if (ch != g_datamagic[nmagic]) + { + nmagic = 0; + } + else if (nmagic < NXFFS_MAGICSIZE - 1) + { + nmagic++; + } + + /* We have found the magic sequence in the FLASH data that may + * indicate the beginning of an NXFFS data block. + */ + + else + { + /* The offset to the header must be 4 bytes before the current + * FLASH seek location. + */ + + blkentry->hoffset = nxffs_iotell(volume) - 4; + + /* Read the block header and verify the block at that address */ + + ret = nxffs_rdblkhdr(volume, blkentry->hoffset, &blkentry->datlen); + if (ret == OK) + { + fvdbg("Found a valid data block, offset: %d datlen: %d\n", + blkentry->hoffset, blkentry->datlen); + return OK; + } + + /* False alarm.. keep looking */ + + nmagic = 0; + } + } + } + + /* We won't get here, but to keep some compilers happy: */ + + return -ENOENT; +} + + diff --git a/include/nuttx/nxffs.h b/include/nuttx/nxffs.h index bfe7460e8c..90f1d76c6e 100644 --- a/include/nuttx/nxffs.h +++ b/include/nuttx/nxffs.h @@ -59,6 +59,10 @@ # error "CONFIG_NXFFS_ERASEDSTATE must be either 0x00 or 0xff" #endif +#ifndef CONFIG_NXFFS_PACKTHRESHOLD +# define CONFIG_NXFFS_PACKTHRESHOLD 32 +#endif + /* At present, only a single pre-allocated NXFFS volume is supported. This * is because here can be only a single NXFFS volume mounted at any time. * This has to do with the fact that we bind to an MTD driver (instead of a diff --git a/lib/stdlib/lib_rand.c b/lib/stdlib/lib_rand.c index 3f3b33d5fc..537bc1aaee 100644 --- a/lib/stdlib/lib_rand.c +++ b/lib/stdlib/lib_rand.c @@ -1,7 +1,7 @@ /************************************************************ * lib/stdlib/lib_rand.c * - * Copyright (C) 2007,l 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,8 +48,8 @@ * Definitions ************************************************************/ -#ifndef RND_ORDER -#define RND_ORDER 1 +#ifndef CONFIG_LIB_RAND_ORDER +#define CONFIG_LIB_RAND_ORDER 1 #endif /* Values needed by the random number generator */ @@ -64,9 +64,9 @@ #define RND3_CONSTK3 616087 #define RND3_CONSTP 997783 -#if RND_ORDER == 1 +#if CONFIG_LIB_RAND_ORDER == 1 # define RND_CONSTP RND1_CONSTP -#elif RND_ORDER == 2 +#elif CONFIG_LIB_RAND_ORDER == 2 # define RND_CONSTP RND2_CONSTP #else # define RND_CONSTP RND3_CONSTP @@ -82,9 +82,9 @@ static unsigned int nrand(unsigned int nLimit); static double_t frand1(void); -#if (RND_ORDER > 1) +#if (CONFIG_LIB_RAND_ORDER > 1) static double_t frand2(void); -#if (RND_ORDER > 2) +#if (CONFIG_LIB_RAND_ORDER > 2) static double_t frand3(void); #endif #endif @@ -106,37 +106,17 @@ static double_t frand3(void); ************************************************************/ static unsigned long g_nRandInt1; -#if (RND_ORDER > 1) +#if (CONFIG_LIB_RAND_ORDER > 1) static unsigned long g_nRandInt2; -#if (RND_ORDER > 2) +#if (CONFIG_LIB_RAND_ORDER > 2) static unsigned long g_nRandInt3; #endif #endif /************************************************************ - * Function: srand, rand + * Private Functions ************************************************************/ - -void srand(unsigned int seed) -{ - g_nRandInt1 = seed; -#if (RND_ORDER > 1) - g_nRandInt2 = seed; - (void)frand1(); -#if (RND_ORDER > 2) - g_nRandInt3 = seed; - (void)frand2(); -#endif -#endif - -} /* end srand */ - -int rand(void) -{ - return (int)nrand(32768); - -} /* end rand */ - + static unsigned int nrand(unsigned int nLimit) { unsigned long nResult; @@ -146,9 +126,9 @@ static unsigned int nrand(unsigned int nLimit) do { /* Get a random integer in the requested range */ -#if (RND_ORDER == 1) +#if (CONFIG_LIB_RAND_ORDER == 1) fRatio = frand1(); -#elif (RND_ORDER == 2) +#elif (CONFIG_LIB_RAND_ORDER == 2) fRatio = frand2(); #else fRatio = frand3(); @@ -176,7 +156,7 @@ static double_t frand1(void) } /* end frand */ -#if (RND_ORDER > 1) +#if (CONFIG_LIB_RAND_ORDER > 1) static double_t frand2(void) { unsigned long nRandInt; @@ -192,8 +172,8 @@ static double_t frand2(void) } /* end frand */ -#if (RND_ORDER > 2) -static double_t frand(void) +#if (CONFIG_LIB_RAND_ORDER > 2) +static double_t frand3(void) { unsigned long nRandInt; @@ -210,3 +190,31 @@ static double_t frand(void) } /* end frand */ #endif #endif + +/************************************************************ + * Public Functions + ************************************************************/ +/************************************************************ + * Function: srand, rand + ************************************************************/ + +void srand(unsigned int seed) +{ + g_nRandInt1 = seed; +#if (CONFIG_LIB_RAND_ORDER > 1) + g_nRandInt2 = seed; + (void)frand1(); +#if (CONFIG_LIB_RAND_ORDER > 2) + g_nRandInt3 = seed; + (void)frand2(); +#endif +#endif + +} /* end srand */ + +int rand(void) +{ + return (int)nrand(32768); + +} /* end rand */ +