lkml.org 
[lkml]   [2004]   [May]   [17]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
DateMon, 17 May 2004 00:46:26 -0700
FromAndrew Morton <>
SubjectRe: 1352 NUL bytes at the end of a page? (was Re: Assertion `s && s->tree' failed: The saga continues.)
Andrew Morton <akpm@osdl.org> wrote:
>
>  If an application does mmap(MAP_SHARED) of, say, a 2048 byte file and then
>  extends it:
> 
>  	p = mmap(..., fd, ...);
>  	ftructate(fd, 4096);
>  	p[3000] = 1;
> 
>  A racing block_write_full_page() could fail to notice the extended i_size
>  and would decide to zap those 2048 bytes anyway.

This should plug it.

diff -puN mm/memory.c~ftruncate-vs-block_write_full_page mm/memory.c
--- 25/mm/memory.c~ftruncate-vs-block_write_full_page	2004-05-17 00:33:07.060231368 -0700
+++ 25-akpm/mm/memory.c	2004-05-17 00:41:00.924193096 -0700
@@ -1208,6 +1208,8 @@ int vmtruncate(struct inode * inode, lof
 {
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long limit;
+	loff_t i_size;
+	struct page *page;
 
 	if (inode->i_size < offset)
 		goto do_expand;
@@ -1222,8 +1224,22 @@ do_expand:
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	i_size_write(inode, offset);
 
+	/*
+	 * If there is a pagecache page at the current i_size we need to lock
+	 * it while modifying i_size to synchronise against
+	 * block_write_full_page()'s sampling of i_size.  Otherwise
+	 * block_write_full_page may decide to memset part of this page after
+	 * the application extended the file size.
+	 */
+	i_size = inode->i_size;	/* don't need i_size_read() due to i_sem */
+	page = NULL;
+	if (i_size & (PAGE_CACHE_SIZE - 1))
+		page = find_lock_page(inode->i_mapping,
+				i_size >> PAGE_CACHE_SHIFT);
+	i_size_write(inode, offset);
+	if (page)
+		unlock_page(page);
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate)
 		inode->i_op->truncate(inode);
_

The same could happen with a pwrite() in place of ftruncate:

	fd = open("2048-byte-file");
	p = mmap(..., MAP_SHARED, fd, ...);
	pwrite(fd, buf, 1, 4096);
	p[3000] = 1;

But I doubt that bk does extending writes() against a file which is
concurrently being modified via MAP_SHARED.
-
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/

\
 
 \ /
  Last update: 2005-03-22 13:03    [from the cache]
©2003-2008