From 9b9c987352138b70e4044116b00321f1c9c18dca Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 5 May 2011 23:31:44 +0000 Subject: Finish logic to update open writer after packing git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3568 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/fs/nxffs/nxffs_ioctl.c | 18 +- nuttx/fs/nxffs/nxffs_pack.c | 478 +++++++++++++++++++++++++++++++------------ nuttx/include/nuttx/ioctl.h | 3 + 3 files changed, 368 insertions(+), 131 deletions(-) diff --git a/nuttx/fs/nxffs/nxffs_ioctl.c b/nuttx/fs/nxffs/nxffs_ioctl.c index e24cf0564..a70dba87c 100644 --- a/nuttx/fs/nxffs/nxffs_ioctl.c +++ b/nuttx/fs/nxffs/nxffs_ioctl.c @@ -108,7 +108,7 @@ int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) goto errout; } - /* Only a reformat command is supported */ + /* Only a reformat and optimize commands are supported */ if (cmd == FIOC_REFORMAT) { @@ -126,12 +126,22 @@ int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* Re-format the volume -- all is lost */ ret = nxffs_reformat(volume); - goto errout_with_semaphore; } - /* No other commands supported */ + else if (cmd == FIOC_OPTIMIZE) + { + fvdbg("Optimize command\n"); + + /* Pack the volume */ + + ret = nxffs_pack(volume); + } + else + { + /* No other commands supported */ - ret = -ENOTTY; + ret = -ENOTTY; + } errout_with_semaphore: sem_post(&volume->exclsem); diff --git a/nuttx/fs/nxffs/nxffs_pack.c b/nuttx/fs/nxffs/nxffs_pack.c index d1dc185c6..2d5fc6358 100644 --- a/nuttx/fs/nxffs/nxffs_pack.c +++ b/nuttx/fs/nxffs/nxffs_pack.c @@ -726,26 +726,29 @@ static void nxffs_wrdathdr(FAR struct nxffs_volume_s *volume, uint16_t iooffset; uint32_t crc; - /* Get the offset in the block corresponding to the location of the data - * block header. NOTE: This must lie in the same block as we currently have - * buffered. - */ + if (pack->dest.blklen > 0) + { + /* Get the offset in the block corresponding to the location of the data + * block header. NOTE: This must lie in the same block as we currently have + * buffered. + */ - ioblock = nxffs_getblock(volume, pack->dest.blkoffset); - iooffset = nxffs_getoffset(volume, pack->dest.blkoffset, ioblock); - DEBUGASSERT(pack->dest.blkoffset && ioblock == pack->ioblock); + ioblock = nxffs_getblock(volume, pack->dest.blkoffset); + iooffset = nxffs_getoffset(volume, pack->dest.blkoffset, ioblock); + DEBUGASSERT(pack->dest.blkoffset && ioblock == pack->ioblock); - /* Write the data block header to memory */ + /* Write the data block header to memory */ - dathdr = (FAR struct nxffs_data_s *)&pack->iobuffer[iooffset]; - memcpy(dathdr->magic, g_datamagic, NXFFS_MAGICSIZE); - nxffs_wrle32(dathdr->crc, 0); - nxffs_wrle16(dathdr->datlen, pack->dest.blklen); + dathdr = (FAR struct nxffs_data_s *)&pack->iobuffer[iooffset]; + memcpy(dathdr->magic, g_datamagic, NXFFS_MAGICSIZE); + nxffs_wrle32(dathdr->crc, 0); + nxffs_wrle16(dathdr->datlen, pack->dest.blklen); - /* Update the entire data block CRC (including the header) */ + /* Update the entire data block CRC (including the header) */ - crc = crc32(&pack->iobuffer[iooffset], pack->dest.blklen + SIZEOF_NXFFS_DATA_HDR); - nxffs_wrle32(dathdr->crc, crc); + crc = crc32(&pack->iobuffer[iooffset], pack->dest.blklen + SIZEOF_NXFFS_DATA_HDR); + nxffs_wrle32(dathdr->crc, crc); + } /* Setup state to allocate the next data block */ @@ -754,6 +757,95 @@ static void nxffs_wrdathdr(FAR struct nxffs_volume_s *volume, pack->dest.blkpos = 0; } +/**************************************************************************** + * Name: nxffs_packtransfer + * + * Description: + * Transfer data from the source to the destination buffer. + * + * Input Parameters: + * volume - The volume to be packed + * pack - The volume packing state structure. + * + * Returned Values: + * None. + * + ****************************************************************************/ + +static void nxffs_packtransfer(FAR struct nxffs_volume_s *volume, + FAR struct nxffs_pack_s *pack) +{ + /* Determine how much data is available in the dest pack buffer */ + + uint16_t destlen = volume->geo.blocksize - pack->iooffset; + + /* Dermined how much data is available in the src data block */ + + uint16_t srclen = pack->src.blklen - pack->src.blkpos; + + /* Transfer the smaller of the two amounts data */ + + uint16_t xfrlen = MIN(srclen, destlen); + if (xfrlen > 0) + { + nxffs_ioseek(volume, pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blkpos); + memcpy(&pack->iobuffer[pack->iooffset], &volume->cache[volume->iooffset], xfrlen); + + /* Increment counts and offset for this data transfer */ + + pack->src.fpos += xfrlen; /* Source data offsets */ + pack->src.blkpos += xfrlen; + pack->dest.fpos += xfrlen; /* Destination data offsets */ + pack->dest.blkpos += xfrlen; + pack->dest.blklen += xfrlen; /* Destination data block size */ + pack->iooffset += xfrlen; /* Destination I/O block offset */ + volume->iooffset += xfrlen; /* Source I/O block offset */ + volume->froffset += xfrlen; /* Free FLASH offset */ + } +} + +/**************************************************************************** + * Name: nxffs_endsrcblock + * + * Description: + * The end of a source data block has been encountered. Locate the next + * source block and setup to continue the transfer. + * + * Input Parameters: + * volume - The volume to be packed + * pack - The volume packing state structure. + * + * Returned Values: + * Zero on success; Otherwise, a negated errno value is returned to + * indicate the nature of the failure. + * + ****************************************************************************/ + +static int nxffs_endsrcblock(FAR struct nxffs_volume_s *volume, + FAR struct nxffs_pack_s *pack) +{ + struct nxffs_blkentry_s blkentry; + off_t offset; + int ret; + + /* Yes.. find the next data block in the source input stream. */ + + offset = pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blklen; + ret = nxffs_nextblock(volume, offset, &blkentry); + if (ret < 0) + { + fdbg("Failed to find next data block: %d\n", -ret); + return ret; + } + + /* Set up the source stream */ + + pack->src.blkoffset = blkentry.hoffset; + pack->src.blklen = blkentry.datlen; + pack->src.blkpos = 0; + return OK; +} + /**************************************************************************** * Name: nxffs_packblock * @@ -801,9 +893,9 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, ret = nxffs_destsetup(volume, pack); if (ret < 0) { - /* -ENOSPC is a special return value which simply means that all of the - * has been used up to the end. We need to return OK in this case and - * resume at the next block. + /* -ENOSPC is a special return value which simply means that all of + * the FLASH has been used up to the end of the current. We need to + * return OK in this case and resume at the next block. */ if (ret == -ENOSPC) @@ -824,115 +916,91 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, for (;;) { - /* Determine how much data is available in the dest pack buffer */ - - uint16_t destlen = volume->geo.blocksize - pack->iooffset; - - /* Dermined how much data is available in the src data block */ + /* Transfer data from the source buffer to the destination buffer */ - uint16_t srclen = pack->src.blklen - pack->src.blkpos; + nxffs_packtransfer(volume, pack); - /* Transfer the smaller of the two amounts data */ - - uint16_t xfrlen = MIN(srclen, destlen); - if (xfrlen > 0) - { - nxffs_ioseek(volume, pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blkpos); - memcpy(&pack->iobuffer[pack->iooffset], &volume->cache[volume->iooffset], xfrlen); - - /* Increment counts and offset for this data transfer */ - - pack->src.fpos += xfrlen; /* Source data offsets */ - pack->src.blkpos += xfrlen; - pack->dest.fpos += xfrlen; /* Destination data offsets */ - pack->dest.blkpos += xfrlen; - pack->dest.blklen += xfrlen; /* Destination data block size */ - pack->iooffset += xfrlen; /* Destination I/O block offset */ - volume->iooffset += xfrlen; /* Source I/O block offset */ - volume->froffset += xfrlen; /* Free FLASH offset */ - } - - /* Now, either the (1) src block has been fully transferred, (2) all - * of the source data has been transferred, or (3) the the destination - * block is full, .. or all three. - * - * Check if all of the bytes in the source inode have been transferred. - */ + /* Now, either the (1) src block has been fully transferred, (2) all + * of the source data has been transferred, or (3) the the destination + * block is full, .. or all three. + * + * Check if all of the bytes in the source inode have been transferred. + */ - if (pack->src.fpos >= pack->src.entry.datlen) - { - /* Write the final destination data block header and inode - * headers. - */ + if (pack->src.fpos >= pack->src.entry.datlen) + { + /* Write the final destination data block header and inode + * headers. + */ - nxffs_wrdathdr(volume, pack); - nxffs_wrinodehdr(volume,pack); + nxffs_wrdathdr(volume, pack); + nxffs_wrinodehdr(volume, pack); - /* Find the next valid source inode */ + /* Find the next valid source inode */ - offset = pack->src.blkoffset + pack->src.blklen; - memset(&pack->src, 0, sizeof(struct nxffs_packstream_s)); + offset = pack->src.blkoffset + pack->src.blklen; + memset(&pack->src, 0, sizeof(struct nxffs_packstream_s)); - ret = nxffs_nextentry(volume, offset, &pack->src.entry); - if (ret < 0) - { - /* No more valid inode entries. Just return an end-of-flash error - * indication. - */ + ret = nxffs_nextentry(volume, offset, &pack->src.entry); + if (ret < 0) + { + /* No more valid inode entries. Just return an end-of-flash error + * indication. + */ - return -ENOSPC; - } + return -ENOSPC; + } - /* Setup the new source stream */ + /* Setup the new source stream */ - ret = nxffs_srcsetup(volume, pack, pack->src.entry.doffset); - if (ret < 0) - { - return ret; - } + ret = nxffs_srcsetup(volume, pack, pack->src.entry.doffset); + if (ret < 0) + { + return ret; + } - /* Setup the dest stream */ + /* Setup the dest stream */ - memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s)); - pack->dest.entry.name = pack->src.entry.name; - pack->dest.entry.utc = pack->src.entry.utc; - pack->dest.entry.datlen = pack->src.entry.datlen; - pack->src.entry.name = NULL; + memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s)); + pack->dest.entry.name = pack->src.entry.name; + pack->dest.entry.utc = pack->src.entry.utc; + pack->dest.entry.datlen = pack->src.entry.datlen; + pack->src.entry.name = NULL; - /* Is there sufficient space at the end of the I/O block to hold - * the inode header? - */ + /* Is there sufficient space at the end of the I/O block to hold + * the inode header? + */ - if (pack->iooffset + SIZEOF_NXFFS_INODE_HDR > volume->geo.blocksize) - { - /* No, just return success... we will handle this condition when - * this function is called on the next I/O block. - */ + if (pack->iooffset + SIZEOF_NXFFS_INODE_HDR > volume->geo.blocksize) + { + /* No, just return success... we will handle this condition when + * this function is called on the next I/O block. + */ - return OK; - } + return OK; + } - /* Configure the destination stream */ - - ret = nxffs_destsetup(volume, pack); - if (ret < 0) - { - /* -ENOSPC is a special return value which simply means that all of the - * has been used up to the end. We need to return OK in this case and - * resume at the next block. - */ + /* Configure the destination stream */ - if (ret == -ENOSPC) - { - return OK; - } - else - { - fdbg("Failed to configure the dest stream: %d\n", -ret); - return ret; - } - } - } + ret = nxffs_destsetup(volume, pack); + if (ret < 0) + { + /* -ENOSPC is a special return value which simply means that all of the + * has been used up to the end. We need to return OK in this case and + * resume at the next block. + */ + + if (ret == -ENOSPC) + { + return OK; + } + else + { + fdbg("Failed to configure the dest stream: %d\n", -ret); + return ret; + } + } + } /* Not at the end of the source data stream. Check if we are at the * end of the current source data block. @@ -940,23 +1008,11 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, else if (pack->src.blkpos >= pack->src.blklen) { - struct nxffs_blkentry_s blkentry; - - /* Yes.. find the next data block in the source input stream. */ - - offset = pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blklen; - ret = nxffs_nextblock(volume, offset, &blkentry); + ret = nxffs_endsrcblock(volume, pack); if (ret < 0) { - fdbg("Failed to find next data block: %d\n", -ret); return ret; } - - /* Set up the source stream */ - - pack->src.blkoffset = blkentry.hoffset; - pack->src.blklen = blkentry.datlen; - pack->src.blkpos = 0; } /* Check if the destination block is full */ @@ -973,6 +1029,70 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, return -ENOSYS; } +/**************************************************************************** + * Name: nxffs_setupwriter + * + * Description: + * Writing is performed at the end of the free FLASH region. When we + * finish packing the other inodes, we still need to pack the partially + * written file at the end of FLASH. This function performs the setup + * necessary to perform that packing phase. + * + * Input Parameters: + * volume - The volume to be packed + * pack - The volume packing state structure. + * + * Returned Values: + * If there is an active writer of the volume, its open file instance is + * returned. NULL is returned otherwise. + * + ****************************************************************************/ + +static FAR struct nxffs_wrfile_s * +nxffs_setupwriter(FAR struct nxffs_volume_s *volume, + FAR struct nxffs_pack_s *pack) +{ + FAR struct nxffs_wrfile_s *wrfile; + + /* Is there a writer? */ + + wrfile = nxffs_findwriter(volume); + if (wrfile) + { + /* Yes... It is the activity of this write that probably initiated + * this packing activity. The writer may have failed in one of several + * different stages: + * + * hoffset == 0: The write failed early before even FLASH for the inode + * header was set aside. + * noffset == 0: The write failed after the inode header was set aside, + * but before the inode name was written. + * doffset == 0: The write failed after writing the inode name, bue + * before any data blocks were written to FLASH. + * + * If no FLASH has been set aside for the write, then we don't need to + * do anything here. + */ + + if (wrfile->ofile.entry.hoffset > 0) + { + /* Initialize for the packing operation. */ + + memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s)); + pack->dest.entry.name = strdup(wrfile->ofile.entry.name); + pack->dest.entry.utc = wrfile->ofile.entry.utc; + pack->dest.entry.datlen = wrfile->ofile.entry.datlen; + + memset(&pack->src, 0, sizeof(struct nxffs_packstream_s)); + memcpy(&pack->src.entry, &wrfile->ofile.entry, sizeof(struct nxffs_entry_s)); + pack->src.entry.name = NULL; + return wrfile; + } + } + + return NULL; +} + /**************************************************************************** * Name: nxffs_packwriter * @@ -1000,8 +1120,112 @@ static inline int nxffs_packwriter(FAR struct nxffs_volume_s *volume, FAR struct nxffs_pack_s *pack, FAR struct nxffs_wrfile_s *wrfile) { -#warning "Missing logic" - return OK; + int ret; + + /* Are we currently processing a block from the source stream? */ + + if (pack->src.blkoffset == 0) + { + /* No.. setup the source stream */ + + ret = nxffs_srcsetup(volume, pack, pack->src.entry.doffset); + if (ret < 0) + { + fdbg("Failed to configure the src stream: %d\n", -ret); + return ret; + } + } + + /* We enter here on a new block every time, so we always have to setup + * the dest data stream. There should never be data block allocated at + * this point in time. + */ + + DEBUGASSERT(pack->dest.blkoffset == 0 && pack->dest.blkpos == 0); + + ret = nxffs_destsetup(volume, pack); + if (ret < 0) + { + /* -ENOSPC is a special return value which simply means that all of the + * has been used up to the end. We need to return OK in this case and + * resume at the next block. + */ + + if (ret == -ENOSPC) + { + return OK; + } + else + { + fdbg("Failed to configure the dest stream: %d\n", -ret); + return ret; + } + } + + /* Loop, transferring data from the source block to the destination pack + * buffer until either (1) the source stream is exhausted, (2) the destination + * block is full, or (3) an error occurs. + */ + + for (;;) + { + /* Transfer data from the source buffer to the destination buffer */ + + nxffs_packtransfer(volume, pack); + + /* Now, either the (1) src block has been fully transferred, (2) all + * of the source data has been transferred, or (3) the the destination + * block is full, .. or all three. + * + * Check if all of the bytes in the source inode have been transferred. + */ + + if (pack->src.fpos >= pack->src.entry.datlen) + { + /* Write the final destination data block header and inode + * headers. + */ + + nxffs_wrdathdr(volume, pack); + + /* Set the new offsets in the open file instance. */ + + wrfile->ofile.entry.hoffset = pack->dest.entry.hoffset; + wrfile->ofile.entry.noffset = pack->dest.entry.noffset; + wrfile->ofile.entry.doffset = pack->dest.entry.doffset; + + /* Return an end-of-flash error to indicate that all of the write + * data has been transferred. + */ + + return -ENOSPC; + } + + /* Not at the end of the source data stream. Check if we are at the + * end of the current source data block. + */ + + else if (pack->src.blkpos >= pack->src.blklen) + { + ret = nxffs_endsrcblock(volume, pack); + if (ret < 0) + { + return ret; + } + } + + /* Check if the destination block is full */ + + if (pack->iooffset >= volume->geo.blocksize) + { + /* Yes.. Write the destination data block header and return success */ + + nxffs_wrdathdr(volume, pack); + return OK; + } + } + + return -ENOSYS; } /**************************************************************************** @@ -1084,7 +1308,7 @@ int nxffs_pack(FAR struct nxffs_volume_s *volume) * the partially written file at the end of FLASH. */ - wrfile = nxffs_findwriter(volume); + wrfile = nxffs_setupwriter(volume, &pack); } /* Otherwise return OK.. meaning that there is nothing more we can @@ -1190,7 +1414,7 @@ int nxffs_pack(FAR struct nxffs_volume_s *volume) * and so will not be found by nxffs_packblock(). */ - wrfile = nxffs_findwriter(volume); + wrfile = nxffs_setupwriter(volume, &pack); } else { diff --git a/nuttx/include/nuttx/ioctl.h b/nuttx/include/nuttx/ioctl.h index 0c32004f8..30a8bd5f6 100644 --- a/nuttx/include/nuttx/ioctl.h +++ b/nuttx/include/nuttx/ioctl.h @@ -97,6 +97,9 @@ #define FIOC_REFORMAT _FIOC(0x0002) /* IN: None * OUT: None */ +#define FIOC_OPTIMIZE _FIOC(0x0003) /* IN: None + * OUT: None + */ /* NuttX file system ioctl definitions */ -- cgit v1.2.3