Hi,

While trying to get affs working again, I noticed that the current
cont_prepare_write is hardly working, if you write to a file in steps of
1024, the bytes pointer is never updated resulting in an endless loop.
Below is a fixed version, that also removes the bogus tricks to the
bytes ptr. I also "fixed" the comment, any reason we have to be
insulting like this?
Anyway, does anyone see a problem with the fix before I send it to
Linus?

bye, Roman
Index: fs/buffer.c
===================================================================
RCS file: /dump/cvs/linux-2.4/fs/buffer.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 buffer.c
--- fs/buffer.c 2000/07/17 10:46:49     1.1.1.3
+++ fs/buffer.c 2000/07/24 11:45:54
@@ -1585,7 +1585,7 @@
 }
 
 /*
- * For moronic filesystems that do not allow holes in file.
+ * For filesystems that do not allow holes in file.
  * We may have to extend the file.
  */
 
@@ -1600,7 +1600,15 @@
        unsigned blocksize = inode->i_sb->s_blocksize;
        char *kaddr;
 
-       while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) {
+restart:
+       zerofrom = offset;
+       pgpos = *bytes;
+       if (page->index < (pgpos >> PAGE_CACHE_SHIFT))
+               goto skip_extend;
+
+       zerofrom = pgpos & ~PAGE_CACHE_MASK;
+       pgpos >>= PAGE_CACHE_SHIFT;
+       while (page->index > pgpos) {
                status = -ENOMEM;
                new_page = grab_cache_page(mapping, pgpos);
                if (!new_page)
@@ -1609,12 +1617,7 @@
                if (*bytes>>PAGE_CACHE_SHIFT != pgpos) {
                        UnlockPage(new_page);
                        page_cache_release(new_page);
-                       continue;
-               }
-               zerofrom = *bytes & ~PAGE_CACHE_MASK;
-               if (zerofrom & (blocksize-1)) {
-                       *bytes |= (blocksize-1);
-                       (*bytes)++;
+                       goto restart;
                }
                status = __block_prepare_write(inode, new_page, zerofrom,
                                                PAGE_CACHE_SIZE, get_block);
@@ -1626,35 +1629,26 @@
                kunmap(new_page);
                UnlockPage(new_page);
                page_cache_release(new_page);
+               zerofrom = 0;
+               *bytes = ++pgpos << PAGE_CACHE_SHIFT;
        }
 
-       if (page->index < pgpos) {
-               /* completely inside the area */
-               zerofrom = offset;
-       } else {
-               /* page covers the boundary, find the boundary offset */
-               zerofrom = *bytes & ~PAGE_CACHE_MASK;
-
-               /* if we will expand the thing last block will be filled */
-               if (to > zerofrom && (zerofrom & (blocksize-1))) {
-                       *bytes |= (blocksize-1);
-                       (*bytes)++;
-               }
+       pgpos <<= PAGE_CACHE_SHIFT;     
+       if (zerofrom < to)
+               *bytes = pgpos + to;
 
-               /* starting below the boundary? Nothing to zero out */
-               if (offset <= zerofrom)
-                       zerofrom = offset;
-       }
+skip_extend:
        status = __block_prepare_write(inode, page, zerofrom, to, get_block);
-       if (status)
-               goto out1;
-       kaddr = (char*)page_address(page);
-       if (zerofrom < offset) {
-               memset(kaddr+zerofrom, 0, offset-zerofrom);
-               __block_commit_write(inode, page, zerofrom, offset);
+       if (!status) {
+               if (zerofrom < offset) {
+                       kaddr = (char*)page_address(page);
+                       memset(kaddr+zerofrom, 0, offset-zerofrom);
+                       __block_commit_write(inode, page, zerofrom, offset);
+                       *bytes = pgpos + to;
+               }
+               return 0;
        }
-       return 0;
-out1:
+
        ClearPageUptodate(page);
        kunmap(page);
        return status;

Reply via email to