diff -urN 2.4.18pre1/fs/buffer.c err/fs/buffer.c --- 2.4.18pre1/fs/buffer.c Fri Dec 21 20:06:42 2001 +++ err/fs/buffer.c Tue Jan 8 00:55:05 2002 @@ -1512,6 +1512,7 @@ int err, i; unsigned long block; struct buffer_head *bh, *head; + int need_unlock; if (!PageLocked(page)) BUG(); @@ -1567,8 +1568,34 @@ return 0; out: + /* + * ENOSPC, or some other error. We may already have added some + * blocks to the file, so we need to write these out to avoid + * exposing stale data. + */ ClearPageUptodate(page); - UnlockPage(page); + bh = head; + need_unlock = 1; + /* Recovery: lock and submit the mapped buffers */ + do { + if (buffer_mapped(bh)) { + lock_buffer(bh); + set_buffer_async_io(bh); + need_unlock = 0; + } + bh = bh->b_this_page; + } while (bh != head); + do { + struct buffer_head *next = bh->b_this_page; + if (buffer_mapped(bh)) { + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + submit_bh(WRITE, bh); + } + bh = next; + } while (bh != head); + if (need_unlock) + UnlockPage(page); return err; } @@ -1599,6 +1626,7 @@ continue; if (block_start >= to) break; + clear_bit(BH_New, &bh->b_state); if (!buffer_mapped(bh)) { err = get_block(inode, block, bh, 1); if (err) @@ -1633,12 +1661,34 @@ */ while(wait_bh > wait) { wait_on_buffer(*--wait_bh); - err = -EIO; if (!buffer_uptodate(*wait_bh)) - goto out; + return -EIO; } return 0; out: + /* + * Zero out any newly allocated blocks to avoid exposing stale + * data. If BH_New is set, we know that the block was newly + * allocated in the above loop. + */ + bh = head; + block_start = 0; + do { + block_end = block_start+blocksize; + if (block_end <= from) + continue; + if (block_start >= to) + break; + if (buffer_new(bh)) { + if (buffer_uptodate(bh)) + printk(KERN_ERR "%s: zeroing uptodate buffer!\n", __FUNCTION__); + memset(kaddr+block_start, 0, bh->b_size); + set_bit(BH_Uptodate, &bh->b_state); + mark_buffer_dirty(bh); + } + block_start = block_end; + bh = bh->b_this_page; + } while (bh != head); return err; } diff -urN 2.4.18pre1/mm/filemap.c err/mm/filemap.c --- 2.4.18pre1/mm/filemap.c Sat Jan 5 06:17:43 2002 +++ err/mm/filemap.c Tue Jan 8 00:54:47 2002 @@ -3004,7 +3004,7 @@ kaddr = kmap(page); status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes); if (status) - goto unlock; + goto sync_failure; page_fault = __copy_from_user(kaddr+offset, buf, bytes); flush_dcache_page(page); status = mapping->a_ops->commit_write(file, page, offset, offset+bytes); @@ -3029,6 +3029,7 @@ if (status < 0) break; } while (count); +done: *ppos = pos; if (cached_page) @@ -3050,6 +3051,18 @@ fail_write: status = -EFAULT; goto unlock; + +sync_failure: + /* + * If blocksize < pagesize, prepare_write() may have instantiated a + * few blocks outside i_size. Trim these off again. + */ + kunmap(page); + UnlockPage(page); + page_cache_release(page); + if (pos + bytes > inode->i_size) + vmtruncate(inode, inode->i_size); + goto done; o_direct: written = generic_file_direct_IO(WRITE, file, (char *) buf, count, pos);