Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24 /fs/affs/file.c

Filename:/fs/affs/file.c
Lines Added:59
Lines Deleted:42
Also changed in: (Previous) 2.6.24-rc8  2.6.24-rc7  2.6.24-rc6  2.6.24-rc5  2.6.24-rc4  2.6.24-rc3 
(Following) 2.6.25-git14  2.6.25-git15  2.6.25-git16  2.6.25-git17  2.6.25-git18  2.6.25-git19 

Location
[  2.6.24
  [  fs
    [  affs
       o  file.c

Patch

diff --git a/fs/affs/file.c b/fs/affs/file.c
index c314a35..6e0c939 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -395,25 +395,33 @@ static int affs_writepage(struct page *page, struct writeback_control *wbc)
 {
    return block_write_full_page(page, affs_get_block, wbc);
 }
+
 static int affs_readpage(struct file *file, struct page *page)
 {
    return block_read_full_page(page, affs_get_block);
 }
-static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+
+static int affs_write_begin(struct file *file, struct address_space *mapping,
+         loff_t pos, unsigned len, unsigned flags,
+         struct page **pagep, void **fsdata)
 {
-   return cont_prepare_write(page, from, to, affs_get_block,
-      &AFFS_I(page->mapping->host)->mmu_private);
+   *pagep = NULL;
+   return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+            affs_get_block,
+            &AFFS_I(mapping->host)->mmu_private);
 }
+
 static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 {
    return generic_block_bmap(mapping,block,affs_get_block);
 }
+
 const struct address_space_operations affs_aops = {
    .readpage = affs_readpage,
    .writepage = affs_writepage,
    .sync_page = block_sync_page,
-   .prepare_write = affs_prepare_write,
-   .commit_write = generic_commit_write,
+   .write_begin = affs_write_begin,
+   .write_end = generic_write_end,
    .bmap = _affs_bmap
 };
 
@@ -603,54 +611,65 @@ affs_readpage_ofs(struct file *file, struct page *page)
    return err;
 }
 
-static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
+static int affs_write_begin_ofs(struct file *file, struct address_space *mapping,
+            loff_t pos, unsigned len, unsigned flags,
+            struct page **pagep, void **fsdata)
 {
-   struct inode *inode = page->mapping->host;
-   u32 size, offset;
-   u32 tmp;
+   struct inode *inode = mapping->host;
+   struct page *page;
+   pgoff_t index;
    int err = 0;
 
-   pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
-   offset = page->index << PAGE_CACHE_SHIFT;
-   if (offset + from > AFFS_I(inode)->mmu_private) {
-      err = affs_extent_file_ofs(inode, offset + from);
+   pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len);
+   if (pos > AFFS_I(inode)->mmu_private) {
+      /* XXX: this probably leaves a too-big i_size in case of
+       * failure. Should really be updating i_size at write_end time
+       */
+      err = affs_extent_file_ofs(inode, pos);
       if (err)
          return err;
    }
-   size = inode->i_size;
+
+   index = pos >> PAGE_CACHE_SHIFT;
+   page = __grab_cache_page(mapping, index);
+   if (!page)
+      return -ENOMEM;
+   *pagep = page;
 
    if (PageUptodate(page))
       return 0;
 
-   if (from) {
-      err = affs_do_readpage_ofs(file, page, 0, from);
-      if (err)
-         return err;
-   }
-   if (to < PAGE_CACHE_SIZE) {
-      zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0);
-      if (size > offset + to) {
-         if (size < offset + PAGE_CACHE_SIZE)
-            tmp = size & ~PAGE_CACHE_MASK;
-         else
-            tmp = PAGE_CACHE_SIZE;
-         err = affs_do_readpage_ofs(file, page, to, tmp);
-      }
+   /* XXX: inefficient but safe in the face of short writes */
+   err = affs_do_readpage_ofs(file, page, 0, PAGE_CACHE_SIZE);
+   if (err) {
+      unlock_page(page);
+      page_cache_release(page);
    }
    return err;
 }
 
-static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
+static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
+            loff_t pos, unsigned len, unsigned copied,
+            struct page *page, void *fsdata)
 {
-   struct inode *inode = page->mapping->host;
+   struct inode *inode = mapping->host;
    struct super_block *sb = inode->i_sb;
    struct buffer_head *bh, *prev_bh;
    char *data;
    u32 bidx, boff, bsize;
+   unsigned from, to;
    u32 tmp;
    int written;
 
-   pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+   from = pos & (PAGE_CACHE_SIZE - 1);
+   to = pos + len;
+   /*
+    * XXX: not sure if this can handle short copies (len < copied), but
+    * we don't have to, because the page should always be uptodate here,
+    * due to write_begin.
+    */
+
+   pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len);
    bsize = AFFS_SB(sb)->s_data_blksize;
    data = page_address(page);
 
@@ -748,6 +767,9 @@ done:
    if (tmp > inode->i_size)
       inode->i_size = AFFS_I(inode)->mmu_private = tmp;
 
+   unlock_page(page);
+   page_cache_release(page);
+
    return written;
 
 out:
@@ -761,8 +783,8 @@ const struct address_space_operations affs_aops_ofs = {
    .readpage = affs_readpage_ofs,
    //.writepage = affs_writepage_ofs,
    //.sync_page = affs_sync_page_ofs,
-   .prepare_write = affs_prepare_write_ofs,
-   .commit_write = affs_commit_write_ofs
+   .write_begin = affs_write_begin_ofs,
+   .write_end = affs_write_end_ofs
 };
 
 /* Free any preallocated blocks. */
@@ -805,18 +827,13 @@ affs_truncate(struct inode *inode)
    if (inode->i_size > AFFS_I(inode)->mmu_private) {
       struct address_space *mapping = inode->i_mapping;
       struct page *page;
-      u32 size = inode->i_size - 1;
+      void *fsdata;
+      u32 size = inode->i_size;
       int res;
 
-      page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
-      if (!page)
-         return;
-      size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
-      res = mapping->a_ops->prepare_write(NULL, page, size, size);
+      res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
       if (!res)
-         res = mapping->a_ops->commit_write(NULL, page, size, size);
-      unlock_page(page);
-      page_cache_release(page);
+         res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
       mark_inode_dirty(inode);
       return;
    } else if (inode->i_size == AFFS_I(inode)->mmu_private)


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.