Re: [Yaffs] Kenrel 2.6.28-rc8 removes prepare_write/commit_w…

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Charles Manning
Date:  
To: yaffs
CC: Marcel Ziswiler, yaffs
Subject: Re: [Yaffs] Kenrel 2.6.28-rc8 removes prepare_write/commit_write...
Hi

I also have a version of a fix in the pipe which is pretty similar. I'm still
setting up something to test it though.


Does what you've set up work?

One thing I've been looking at addressing is that write_begin should really to
the -ENOSPC check, but this code does not.

My patch (**WORK IN PROGRESS**) looks like:

--- ref/yaffs2/yaffs_fs.c    2009-01-19 10:50:37.000000000 +1300
+++ dev/yaffs2/yaffs_fs.c    2009-01-19 17:11:30.000000000 +1300
@@ -91,6 +91,13 @@
 #define WRITE_SIZE(mtd) (mtd)->oobblock
 #endif


+#if(LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
+#define YAFFS_USE_WRITE_BEGIN_END 1
+#else
+#define YAFFS_USE_WRITE_BEGIN_END 0
+#endif
+
+
#include <asm/uaccess.h>

#include "yportenv.h"
@@ -150,6 +157,8 @@

 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
                 loff_t * pos);
+static ssize_t yaffs_hold_space(struct file *f);
+static void yaffs_release_space(struct file *f);


 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
 static int yaffs_file_flush(struct file *file, fl_owner_t id);
@@ -218,10 +227,22 @@
 #else
 static int yaffs_writepage(struct page *page);
 #endif
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END != 0)
+static int yaffs_write_begin(struct file *filp, struct address_space 
*mapping,
+                             loff_t pos, unsigned len, unsigned flags,
+                          struct page **pagep, void **fsdata);
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+               loff_t pos, unsigned len, unsigned copied,
+               struct page *pg, void *fsdadata);
+#else
 static int yaffs_prepare_write(struct file *f, struct page *pg,
                    unsigned offset, unsigned to);
 static int yaffs_commit_write(struct file *f, struct page *pg, unsigned 
offset,
                   unsigned to);
+                                                                                                
+#endif


 static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
               int buflen);
@@ -234,8 +255,13 @@
 static struct address_space_operations yaffs_file_address_operations = {
     .readpage = yaffs_readpage,
     .writepage = yaffs_writepage,
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+    .write_begin = yaffs_write_begin,
+    .write_end = yaffs_write_end,
+#else
     .prepare_write = yaffs_prepare_write,
     .commit_write = yaffs_commit_write,
+#endif
 };


 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
@@ -249,6 +275,7 @@
     .fsync = yaffs_sync_object,
     .splice_read = generic_file_splice_read,
     .splice_write = generic_file_splice_write,
+    .llseek = generic_file_llseek,
 };


 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
@@ -701,6 +728,63 @@
     return (nWritten == nBytes) ? 0 : -ENOSPC;
 }


+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_begin(struct file *filp, struct address_space 
*mapping,
+                             loff_t pos, unsigned len, unsigned flags,
+                          struct page **pagep, void **fsdata)
+
+{
+    struct page *pg = NULL;
+        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+        /* uint32_t page_start = index << PAGE_CACHE_SHIFT; */
+        int ret = 0;
+        int space_held = 0;
+        
+                
+    T(YAFFS_TRACE_OS, (KERN_DEBUG "start yaffs_write_begin\n"));
+    /* Get a page */
+    pg = __grab_cache_page(mapping,index);
+    if(!pg){
+        ret =  -ENOMEM;
+        goto out;
+    }
+    /* Get fs space */
+    space_held = yaffs_hold_space(filp);
+    
+    if(!space_held){
+        ret = -ENOSPC;
+        goto out;
+    }
+        
+    /* Update page if required */
+    
+    if (!Page_Uptodate(pg))
+        ret = yaffs_readpage_nolock(filp, pg);
+    
+    if(ret)
+        goto out;
+
+    /* Happy path return */
+    T(YAFFS_TRACE_OS, (KERN_DEBUG "end yaffs_write_begin - ok\n"));
+        
+    *pagep = pg;    
+    return 0;
+        
+out:
+    T(YAFFS_TRACE_OS, (KERN_DEBUG "end yaffs_write_begin fail 
returning %d\n",ret));
+    if(space_held){
+        yaffs_release_space(filp);
+    }
+    if(pg) {
+        unlock_page(pg);
+        page_cache_release(pg);
+    }
+    return ret;
+}
+
+#else
+
 static int yaffs_prepare_write(struct file *f, struct page *pg,
                    unsigned offset, unsigned to)
 {
@@ -708,10 +792,55 @@
     T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n"));
     if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
         return yaffs_readpage_nolock(f, pg);
-
     return 0;


 }
+#endif
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+               loff_t pos, unsigned len, unsigned copied,
+               struct page *pg, void *fsdadata)
+{
+    int ret = 0;
+    void *addr, *kva;
+        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+        uint32_t page_start = index << PAGE_CACHE_SHIFT;
+        uint32_t offset_into_page = pos - page_start; 
+
+
+    int nBytes = len;
+    int nWritten;
+    
+    kva=kmap(pg);
+    addr = kva + offset_into_page;
+
+    T(YAFFS_TRACE_OS,
+      (KERN_DEBUG "yaffs_write_end addr %x pos %x nBytes %d\n", (unsigned) addr,
+       (int)pos, nBytes));
+
+    nWritten = yaffs_file_write(filp, addr, nBytes, &pos);
+
+    if (nWritten != nBytes) {
+        T(YAFFS_TRACE_OS,
+          (KERN_DEBUG
+           "yaffs_write_end not same size nWritten %d  nBytes %d\n",
+           nWritten, nBytes));
+        SetPageError(pg);
+        ClearPageUptodate(pg);
+    } else {
+        SetPageUptodate(pg);
+    }
+
+    kunmap(pg);
+
+    
+    yaffs_release_space(filp);
+    unlock_page(pg);
+    page_cache_release(pg);
+    return ret;
+}
+#else


 static int yaffs_commit_write(struct file *f, struct page *pg, unsigned 
offset,
                   unsigned to)
@@ -724,11 +853,13 @@
     int nWritten;


     unsigned spos = pos;
-    unsigned saddr = (unsigned)addr;
+    unsigned saddr;

    
     kva=kmap(pg);
     addr = kva + offset;


+    saddr = (unsigned) addr;
+
     T(YAFFS_TRACE_OS,
       (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
        spos, nBytes));
@@ -755,6 +886,8 @@
     return nWritten == nBytes ? 0 : nWritten;


}
+#endif
+

 static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * 
obj)
 {
@@ -954,6 +1087,48 @@
     return nWritten == 0 ? -ENOSPC : nWritten;
 }


+/* Space holding and freeing is done to ensure we have space available for 
write_begin/end */
+/* For now we just assume few parallel writes and check against a small 
number. */
+/* Todo: need to do this with a counter to handle parallel reads better */
+
+static ssize_t yaffs_hold_space(struct file *f)
+{
+    yaffs_Object *obj;
+    yaffs_Device *dev;
+    
+    int nFreeChunks;
+
+    
+    obj = yaffs_DentryToObject(f->f_dentry);
+
+    dev = obj->myDev;
+
+    yaffs_GrossLock(dev);
+
+    nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
+    
+    yaffs_GrossUnlock(dev);
+
+    return (nFreeChunks > 20) ? 1 : 0;
+}
+
+static void yaffs_release_space(struct file *f)
+{
+    yaffs_Object *obj;
+    yaffs_Device *dev;
+    
+    
+    obj = yaffs_DentryToObject(f->f_dentry);
+
+    dev = obj->myDev;
+
+    yaffs_GrossLock(dev);
+
+    
+    yaffs_GrossUnlock(dev);
+
+}
+
 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
 {
     yaffs_Object *obj;





On Tuesday 20 January 2009 10:40:54 Marcel Ziswiler wrote:
> Peter Barada <peterb <at> logicpd.com> writes:
> > Does anyone have a patch to get the latest CVS YAFFS to work with
> > 2.6.28-rc8?
>
> Sure, how about something like that?
>
> diff -Naur yaffs2.orig/yaffs_fs.c yaffs2/yaffs_fs.c
> --- yaffs2.orig/yaffs_fs.c    2009-01-18 22:50:37.000000000 +0100
> +++ yaffs2/yaffs_fs.c    2009-01-19 22:17:52.000000000 +0100
> @@ -218,10 +218,19 @@
>  #else
>  static int yaffs_writepage(struct page *page);
>  #endif
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +static int yaffs_write_begin(struct file *f, struct address_space
> *mapping, +                 loff_t pos, unsigned len, unsigned flags,
> +                 struct page **pagep, void **fsdata);
> +static int yaffs_write_end(struct file *f, struct address_space *mapping,
> +               loff_t pos, unsigned len, unsigned copied,
> +               struct page *pg, void *fsdata);
> +#else
>  static int yaffs_prepare_write(struct file *f, struct page *pg,
>                     unsigned offset, unsigned to);
>  static int yaffs_commit_write(struct file *f, struct page *pg, unsigned
> offset, unsigned to);
> +#endif

>
>  static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
>                int buflen);
> @@ -234,8 +243,13 @@
>  static struct address_space_operations yaffs_file_address_operations = {
>      .readpage = yaffs_readpage,
>      .writepage = yaffs_writepage,
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +    .write_begin = yaffs_write_begin,
> +    .write_end = yaffs_write_end,
> +#else
>      .prepare_write = yaffs_prepare_write,
>      .commit_write = yaffs_commit_write,
> +#endif
>  };

>
>  #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
> @@ -701,32 +715,67 @@
>      return (nWritten == nBytes) ? 0 : -ENOSPC;
>  }

>
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +static int yaffs_write_begin(struct file *f, struct address_space
> *mapping, +                 loff_t pos, unsigned len, unsigned flags,
> +                 struct page **pagep, void **fsdata)
> +{
> +    struct page *pg;
> +    pgoff_t index = pos >> PAGE_CACHE_SHIFT;
> +    uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
> +    uint32_t to = offset + len;
> +#else
>  static int yaffs_prepare_write(struct file *f, struct page *pg,
>                     unsigned offset, unsigned to)
>  {
> +#endif
> +    int ret = 0;

>
>      T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n"));
> -    if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
> -        return yaffs_readpage_nolock(f, pg);
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +    pg = __grab_cache_page(mapping, index);
> +    if (!pg)
> +        return -ENOMEM;
> +    *pagep = pg;
> +#endif

>
> -    return 0;
> +    if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) {
> +        ret = yaffs_readpage_nolock(f, pg);
> +    }
> +
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +    if (ret) {
> +        unlock_page(pg);
> +        page_cache_release(pg);
> +    }
> +#endif

>
> +    return ret;
>  }

>
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +static int yaffs_write_end(struct file *f, struct address_space *mapping,
> +               loff_t pos, unsigned len, unsigned copied,
> +               struct page *pg, void *fsdata)
> +{
> +    unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
> +    unsigned to = offset + copied;
> +#else
>  static int yaffs_commit_write(struct file *f, struct page *pg, unsigned
> offset, unsigned to)
>  {
> -
> +#endif
>      void *addr, *kva;
> -
> +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27))
>      loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
> +#endif
>      int nBytes = to - offset;
>      int nWritten;

>
>      unsigned spos = pos;
>      unsigned saddr = (unsigned)addr;

>
> -    kva=kmap(pg);
> +    kva = kmap(pg);
>      addr = kva + offset;

>
>      T(YAFFS_TRACE_OS,
> @@ -752,8 +801,12 @@
>        (KERN_DEBUG "yaffs_commit_write returning %d\n",
>         nWritten == nBytes ? 0 : nWritten));

>
> -    return nWritten == nBytes ? 0 : nWritten;
> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
> +    unlock_page(pg);
> +    page_cache_release(pg);
> +#endif

>
> +    return nWritten == nBytes ? 0 : nWritten;
>  }

>
> static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *
> obj)
>
>
>
> _______________________________________________
> yaffs mailing list
>
> http://lists.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs