Re: Still ext2-corruption in test8-pre5 (incl. OOPS)

From: Alexander Viro (aviro@redhat.com)
Date: Tue Sep 05 2000 - 20:31:17 EST


On Tue, 5 Sep 2000, Linus Torvalds wrote:

>
>
> On Tue, 5 Sep 2000, Alexander Viro wrote:
> >
> > WTF? <thinks> Erm... Linus, I suspect that we are losing the thing on the
> > very simple effect: readpage() gets buffer_heads, all right, but then
> > we lose the lock. That's your window for losing the buffer_head ring of
> > that page.
>
> Note that it's not even a small window: we get an up-to-date page, but
> readpage() can have happened hours, days, years before. The buffer-head
> ring _has_ been there at some earlier time, but there's nothing that
> guarantees that it still is there.
>
> Fixing this is not hard, happily. I'll do it. The only issue is whether to
> just copy one of the existing functions and make changes, or try to share
> code and have helper functions. The loop over the page doing the
> get_block() is certainly something that all of the functions for
> reading/writing need to do, and I suspect that I really should split
> things up a bit and share more code than we do now.
>
> If you WANT to do it, holler. I'm not glutton for punishment, but it
> doesn't look that bad.

Me neither, but IMO I have a cop-out:

--- buffer.c Tue Sep 5 21:23:41 2000
+++ buffer.c.new Tue Sep 5 21:28:53 2000
@@ -1724,12 +1724,24 @@
         return 0;
 }
 
+/*
+ * If it would be '74 that would go into libc...
+ */
+int mem_is_zero(char *p, unsigned len)
+{
+ while (len--)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
 int block_zero_page(struct address_space *mapping, loff_t from, unsigned length)
 {
         unsigned long index = from >> PAGE_CACHE_SHIFT;
         unsigned offset = from & (PAGE_CACHE_SIZE-1);
         struct inode *inode = (struct inode *)mapping->host;
         struct page *page;
+ char *kaddr;
         int err;
 
         if (!length)
@@ -1745,9 +1757,18 @@
         if (!Page_Uptodate(page))
                 goto unlock;
 
- memset((char *) kmap(page) + offset, 0, length);
+ kaddr = (char*)kmap(page);
+ err = 0;
+ if (mem_is_zero(kaddr+offset, length))
+ goto unmap;
+ err = mapping->a_ops->prepare_write(NULL, page, offset, offset+length);
+ if (err)
+ goto unmap;
+ memset(kaddr+offset, 0, length);
         flush_dcache_page(page);
         __block_commit_write(inode, page, offset, offset+length);
+ kunmap(page);
+unmap:
         kunmap(page);
         err = 0;
 

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



This archive was generated by hypermail 2b29 : Thu Sep 07 2000 - 21:00:24 EST