On Sat, 2 Sep 2000, Alexander Viro wrote:

> IOW, bug in question _does_ give the same kind of behaviour, but whether
> innd is hitting it or something different that happens to act like that...
> The only way to know is to try it.
> 
> I'll send rediffed patch in half an hour.

All right, it took longer than half an hour (RL sh*t in exactly wrong moment)
but here it is. Give it a try, folks.

diff -urN rc8-pre2/fs/ext2/inode.c rc8-pre2-truncate/fs/ext2/inode.c
--- rc8-pre2/fs/ext2/inode.c    Sat Sep  2 23:14:35 2000
+++ rc8-pre2-truncate/fs/ext2/inode.c   Sun Sep  3 00:03:57 2000
@@ -904,6 +904,7 @@
        int nr = 0;
        int n;
        long iblock;
+       unsigned blocksize, tail;
 
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
            S_ISLNK(inode->i_mode)))
@@ -913,8 +914,33 @@
 
        ext2_discard_prealloc(inode);
 
-       iblock = (inode->i_size + inode->i_sb->s_blocksize-1)
+       blocksize = inode->i_sb->s_blocksize;
+       iblock = (inode->i_size + blocksize-1)
                                        >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
+       tail = blocksize - (inode->i_size & (blocksize-1));
+
+       /*
+        * So truncate in the middle of a hole not on a block boundary will
+        * allocate a block. BFD. Everything is still consistent, so trying
+        * to be smart is not worth the trouble.
+        */
+       if (tail != blocksize) {
+               unsigned long index = inode->i_size >> PAGE_CACHE_SHIFT;
+               unsigned offset = (inode->i_size & (PAGE_CACHE_SIZE-1));
+               struct page *page = grab_cache_page(inode->i_mapping, index);
+               int err;
+               if (!page)
+                       return; /* -ENOMEM */
+               err = block_prepare_write(page, offset, offset+tail,
+                                                               ext2_get_block);
+               if (!err) {
+                       memset(page_address(page)+offset, 0, tail);
+                       flush_dcache_page(page);
+                       generic_commit_write(NULL, page, offset, offset+tail);
+               }
+               UnlockPage(page);
+               page_cache_release(page);
+       }
 
        n = ext2_block_to_path(inode, iblock, offsets);
        if (n == 0)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to