[Yaffs] [PATCH RFC YAFFS] fix writepage when extending a fil…

Top Page
Attachments:
Message as email
+ (text/plain)
+ fix-writepage-when-extending.diff (text/plain)
Delete this message
Reply to this message
Author: Luc Van Oostenryck
Date:  
CC: Charles Manning, yaffs
Old-Topics: Re: [Yaffs] data loss under heavy pressure on Yaffs2 GC --> fix
New-Topics: [Yaffs] [PATCH YAFFS2 CVS] fix writepage when extending a file but ...
Subject: [Yaffs] [PATCH RFC YAFFS] fix writepage when extending a file
wrote:
>>Luc Van Oostenryck wrote:
>
>
> <snip>
>
>>Yes, there seems to be something missing.
>>
>>The others fs use something like a mix of calling vmtruncate() and/or
>>something like the code below,
>>either in setattr() or XXX_truncate() (to add in inode_operations and
>>called by vmtruncate if present)
>>
>>    page = grab_cache_page(inode->i_mapping, inode->i_size >>
>>PAGE_CACHE_SHIFT) // or attrs->ia_size  >> PAGE_CACHE_SHIFT
>>    // if needed, fill with zeroes the partial page
>>    // there is already a/some function to do this
>>    flush_dcache_page(page);
>>    unlock_page(page);
>>    page_cache_release(page);

>>
>
>
> Forget about this for the moment.
> vmtruncate() is called via inode_settattr() which is done at the and of
> yaffs_setattr()
> And vmtruncate()can call a method "truncate" if implemented
> This method doesn't seems to be needed for the way we actually do the
> truncation/resizing.
>
>
>>I will need to investigate much further.
>>
>
>
> I hadn't enough time yesterday, but there is something that I don't
> understand: in yaffs_setattr() -> yaffs_SetAttributes() ->
> yaffs_ResizeFile(), how the object filesize is changed if newSize >
> oldFileSize ?
>>From what I understand, it this never changed.


OK, I found it.
It is changed by the yaffs_writepage() called by vmtruncate(),
but there is a bug there when we are extending the file.

The problem was detected whe traces in yaffs_writepage() reported the following:
    yaffs_writepage at 0001d000, size 000001d8
    writepag0: obj = 0e1d8, ino = 0e1d8
                     ^^^^^
    Chunk -1 not found zero instead
    writepag1: obj = 1d1d8, ino = 0e1d8
                     ^^^^^


I need to check if there is not similar corner case, but the attached patch
seems to indeed solve the problems, at least the test is runnig well now.

> Apart this, I think that in the case of a resizing down, the object header
> can be updated several times: once in yaffs_ResizeFile and once in
> yaffs_SetAttributes.
>



Luc
--- a/fs/yaffs2/yaffs_fs.c    Tue Aug 2 20:43:50 2005
+++ b/fs/yaffs2/yaffs_fs.c    Thu Aug  4 23:28:08 2005
@@ -479,64 +479,76 @@
 }


// writepage inspired by/stolen from smbfs
//

 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
 #else
 static int yaffs_writepage(struct page *page)
 #endif
 {
     struct address_space *mapping = page->mapping;
+    loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
     struct inode *inode;
     unsigned long end_index;
     char *buffer;
     yaffs_Object *obj;
     int nWritten = 0;
     unsigned nBytes;


     if (!mapping)
         BUG();
     inode = mapping->host;
     if (!inode)
         BUG();


+    if (offset > inode->i_size)
+    {
+        T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_writepage at %08x, inode size = %08x!!!\n", (unsigned)(page->index << PAGE_CACHE_SHIFT), (unsigned) inode->i_size));
+        T(YAFFS_TRACE_OS,(KERN_DEBUG"                -> don't care!!\n"));
+        return 0;
+    }
+
     end_index = inode->i_size >> PAGE_CACHE_SHIFT;


     /* easy case */
     if (page->index < end_index)
     {
         nBytes = PAGE_CACHE_SIZE;
     }
     else
     {
         nBytes = inode->i_size & (PAGE_CACHE_SIZE-1);
     }
     //  What's happening here?
     ///* OK, are we completely out? */
     //if (page->index >= end_index+1 || !offset)
     //    return -EIO;


     get_page(page);



     buffer = kmap(page);


     obj = yaffs_InodeToObject(inode);
     yaffs_GrossLock(obj->myDev);


+    T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_writepage at %08x, size %08x\n", (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
+    T(YAFFS_TRACE_OS,(KERN_DEBUG"writepag0: obj = %05x, ino = %05x\n", (int) obj->variant.fileVariant.fileSize, (int) inode->i_size));


     nWritten = yaffs_WriteDataToFile(obj,buffer,page->index << PAGE_CACHE_SHIFT,nBytes,0);


+    T(YAFFS_TRACE_OS,(KERN_DEBUG"writepag1: obj = %05x, ino = %05x\n", (int) obj->variant.fileVariant.fileSize, (int) inode->i_size));
+
     yaffs_GrossUnlock(obj->myDev);

    
     kunmap(page);
     SetPageUptodate(page);
     UnlockPage(page);
     put_page(page);


     return (nWritten == nBytes) ? 0  : -ENOSPC;
 }