Re: ramdisk corruption problems - was: RE: pivot_root and initrd kern el panic woes

From: Andrew Morton (akpm@zip.com.au)
Date: Sun Dec 30 2001 - 02:08:18 EST


As you pointed out offline, the -ac kernels fixed the problem using
*both* approaches. Here's a 2.4.18-pre1 version. generic_file_write()
is getting rather icky.

Please let me know if this looks like the way to proceed, and I'll
find a way to actually test the thing.

--- linux-2.4.18-pre1/fs/buffer.c Fri Dec 21 11:19:14 2001
+++ linux-akpm/fs/buffer.c Sat Dec 29 22:46:21 2001
@@ -1639,6 +1639,17 @@ static int __block_prepare_write(struct
         }
         return 0;
 out:
+ bh = head;
+ block_start = 0;
+ do {
+ if (buffer_new(bh) && !buffer_uptodate(bh)) {
+ memset(kaddr+block_start, 0, bh->b_size);
+ set_bit(BH_Uptodate, &bh->b_state);
+ mark_buffer_dirty(bh);
+ }
+ block_start += bh->b_size;
+ bh = bh->b_this_page;
+ } while (bh != head);
         return err;
 }
 
--- linux-2.4.18-pre1/mm/filemap.c Wed Dec 26 11:47:41 2001
+++ linux-akpm/mm/filemap.c Sat Dec 29 23:04:29 2001
@@ -2856,6 +2856,7 @@ generic_file_write(struct file *file,con
         ssize_t written;
         long status = 0;
         int err;
+ int prepare_write_failed = 0;
         unsigned bytes;
 
         if ((ssize_t) count < 0)
@@ -3003,8 +3004,10 @@ generic_file_write(struct file *file,con
 
                 kaddr = kmap(page);
                 status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes);
- if (status)
+ if (status) {
+ prepare_write_failed = 1;
                         goto unlock;
+ }
                 page_fault = __copy_from_user(kaddr+offset, buf, bytes);
                 flush_dcache_page(page);
                 status = mapping->a_ops->commit_write(file, page, offset, offset+bytes);
@@ -3026,8 +3029,18 @@ unlock:
                 UnlockPage(page);
                 page_cache_release(page);
 
- if (status < 0)
+ if (status < 0) {
+ if (prepare_write_failed) {
+ /*
+ * If blocksize < pagesize, prepare_write() may have
+ * instantiated a few blocks outside i_size. Trim
+ * these off again.
+ */
+ if (pos + bytes > inode->i_size)
+ vmtruncate(inode, inode->i_size);
+ }
                         break;
+ }
         } while (count);
         *ppos = pos;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Dec 31 2001 - 21:00:22 EST