On Thursday 18 March 2010 04:50:56 Hugo Etchegoyen wrote:
> Charles,
>
> As I said in a previous mail, I was looking for means of speeding up
> yaffs shutdown during power fail, and that included disabling GC. Your
> last modification (the yaffs_gc_control parameter) addresses that issue.
>
> However, although setting this flag to zero will prevent entering GC, it
> will not abort a currently active GC. I had originally proposed to
> decrease the value of maxCopies in GarbageCollectBlock() to make it
> finer grained, but it looks faster and safer to just check your flag in
> each iteration of the copying loop:
>
> for (/* init already done */;
> retVal == YAFFS_OK &&
> dev->gcChunk < dev->param.nChunksPerBlock &&
> (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
> maxCopies > 0;
> dev->gcChunk++, oldChunk++) {
>
> if(dev->param.gcControl &&
> (dev->param.gcControl(dev) & 1) == 0)
> break;
>
> if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
>
> /* This page is in use and might need to be copied off */
> ...
Doing that should be fine. It should be OK to interrupt gc at any page. That's
pretty much what the maxCopy stuff is doing anyway.
I would tend to push the gcControl check into the for().
>
> As yaffs may now be shut down disabling GC, and depending on how much
> data is written with GC disabled (less than a block size in my case),
> maybe at initialization time there might be less free blocks than
> advisable. So I thought that it might be useful to catch up with delayed
> GCs at the end of yaffs_GutsInitialise(). Do you think this is
> necessary/advisable?
I don't think it is necessary.
> Would this code handle that correctly?
>
> /* Clean up any aborted checkpoint data */
> if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
> yaffs_InvalidateCheckpoint(dev);
>
> /* Honor any pending GCs */
> do {
> x = dev->nErasedBlocks;
> yaffs_CheckGarbageCollection(dev);
> } while ( dev->gcBlock > 0 || x < dev->nErasedBlocks );
>
There is no need to resume any gc per se. yaffs_CheckGarbageCollection()
already does iteration.
If you do it here then the checkpoint will be immediately invalidated which is
perhaps not a good idea. You might as well just leave this to be sorted out
on the first write.
> T(YAFFS_TRACE_TRACING,
> (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
>
> return YAFFS_OK;
>
> I also noticed that there is a possible source of delay when updating
> dirty directories, since once started it will iterate over a list of
> pending updates with the yaffs lock taken. I propose adding another
> flag, yaffs_udd_control ("udd" for Update Dirty Directories) and the
> corresponding callback (dev->uddControl). Then
> yaffs_UpdateDirtyDirectories() can check this flag in each iteration of
> the updating loop:
>
> while(!ylist_empty(&dev->dirtyDirectories)){
>
> if(dev->param.uddControl &&
> (dev->param.uddControl(dev) & 1) == 0)
> break;
>
> link = dev->dirtyDirectories.next;
> ylist_del_init(link);
> ...
That should be fine to do,
I'll be adding flags like these when I flesh out the background task with
background garbage collection etc.
> Please advise if these modifications are OK. I have attached the
> modified files (yaffs_guts.h, yaffs_guts.c and yaffs_fs.c). I have
> compiled and tried the module and it seems to work properly, including
> disabling GC and UDD, writing some data, then enabling them again and
> writing some more. I haven't yet simulated a power fail situation when
> one would abort an ongoing GC or UDD, then write some data, sync and
> unmount. I'll report back as soon as I can try that.
>
> Best regards,
> Hugo