[patch 06/41] mm: trim more holes

2007-05-25 Thread npiggin

If prepare_write fails with AOP_TRUNCATED_PAGE, or if commit_write fails, then
we may have failed the write operation despite prepare_write having
instantiated blocks past i_size. Fix this, and consolidate the trimming into
one place.

Cc: Linux Memory Management <[EMAIL PROTECTED]>
Cc: Linux Filesystems 
Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>

 mm/filemap.c |   80 +--
 1 file changed, 40 insertions(+), 40 deletions(-)

Index: linux-2.6/mm/filemap.c
===
--- linux-2.6.orig/mm/filemap.c
+++ linux-2.6/mm/filemap.c
@@ -1969,22 +1969,9 @@ generic_file_buffered_write(struct kiocb
}
 
status = a_ops->prepare_write(file, page, offset, offset+bytes);
-   if (unlikely(status)) {
-   loff_t isize = i_size_read(inode);
+   if (unlikely(status))
+   goto fs_write_aop_error;
 
-   if (status != AOP_TRUNCATED_PAGE)
-   unlock_page(page);
-   page_cache_release(page);
-   if (status == AOP_TRUNCATED_PAGE)
-   continue;
-   /*
-* prepare_write() may have instantiated a few blocks
-* outside i_size.  Trim these off again.
-*/
-   if (pos + bytes > isize)
-   vmtruncate(inode, isize);
-   break;
-   }
if (likely(nr_segs == 1))
copied = filemap_copy_from_user(page, offset,
buf, bytes);
@@ -1993,40 +1980,53 @@ generic_file_buffered_write(struct kiocb
cur_iov, iov_offset, bytes);
flush_dcache_page(page);
status = a_ops->commit_write(file, page, offset, offset+bytes);
-   if (status == AOP_TRUNCATED_PAGE) {
-   page_cache_release(page);
-   continue;
+   if (unlikely(status < 0 || status == AOP_TRUNCATED_PAGE))
+   goto fs_write_aop_error;
+   if (unlikely(copied != bytes)) {
+   status = -EFAULT;
+   goto fs_write_aop_error;
}
-   if (likely(copied > 0)) {
-   if (!status)
-   status = copied;
+   if (unlikely(status > 0)) /* filesystem did partial write */
+   copied = status;
 
-   if (status >= 0) {
-   written += status;
-   count -= status;
-   pos += status;
-   buf += status;
-   if (unlikely(nr_segs > 1)) {
-   filemap_set_next_iovec(&cur_iov,
-   &iov_offset, status);
-   if (count)
-   buf = cur_iov->iov_base +
-   iov_offset;
-   } else {
-   iov_offset += status;
-   }
+   if (likely(copied > 0)) {
+   written += copied;
+   count -= copied;
+   pos += copied;
+   buf += copied;
+   if (unlikely(nr_segs > 1)) {
+   filemap_set_next_iovec(&cur_iov,
+   &iov_offset, copied);
+   if (count)
+   buf = cur_iov->iov_base + iov_offset;
+   } else {
+   iov_offset += copied;
}
}
-   if (unlikely(copied != bytes))
-   if (status >= 0)
-   status = -EFAULT;
unlock_page(page);
mark_page_accessed(page);
page_cache_release(page);
-   if (status < 0)
-   break;
balance_dirty_pages_ratelimited(mapping);
cond_resched();
+   continue;
+
+fs_write_aop_error:
+   if (status != AOP_TRUNCATED_PAGE)
+   unlock_page(page);
+   page_cache_release(page);
+
+   /*
+* prepare_write() may have instantiated a few blocks
+* outside i_size.  Trim these off again. Don't need
+* i_size_read because we hold i_mutex.
+*/
+   if (pos 

[patch 06/41] mm: trim more holes

2007-05-14 Thread npiggin

If prepare_write fails with AOP_TRUNCATED_PAGE, or if commit_write fails, then
we may have failed the write operation despite prepare_write having
instantiated blocks past i_size. Fix this, and consolidate the trimming into
one place.

Cc: Linux Memory Management <[EMAIL PROTECTED]>
Cc: Linux Filesystems 
Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>

 mm/filemap.c |   80 +--
 1 file changed, 40 insertions(+), 40 deletions(-)

Index: linux-2.6/mm/filemap.c
===
--- linux-2.6.orig/mm/filemap.c
+++ linux-2.6/mm/filemap.c
@@ -1957,22 +1957,9 @@ generic_file_buffered_write(struct kiocb
}
 
status = a_ops->prepare_write(file, page, offset, offset+bytes);
-   if (unlikely(status)) {
-   loff_t isize = i_size_read(inode);
+   if (unlikely(status))
+   goto fs_write_aop_error;
 
-   if (status != AOP_TRUNCATED_PAGE)
-   unlock_page(page);
-   page_cache_release(page);
-   if (status == AOP_TRUNCATED_PAGE)
-   continue;
-   /*
-* prepare_write() may have instantiated a few blocks
-* outside i_size.  Trim these off again.
-*/
-   if (pos + bytes > isize)
-   vmtruncate(inode, isize);
-   break;
-   }
if (likely(nr_segs == 1))
copied = filemap_copy_from_user(page, offset,
buf, bytes);
@@ -1981,40 +1968,53 @@ generic_file_buffered_write(struct kiocb
cur_iov, iov_offset, bytes);
flush_dcache_page(page);
status = a_ops->commit_write(file, page, offset, offset+bytes);
-   if (status == AOP_TRUNCATED_PAGE) {
-   page_cache_release(page);
-   continue;
+   if (unlikely(status < 0 || status == AOP_TRUNCATED_PAGE))
+   goto fs_write_aop_error;
+   if (unlikely(copied != bytes)) {
+   status = -EFAULT;
+   goto fs_write_aop_error;
}
-   if (likely(copied > 0)) {
-   if (!status)
-   status = copied;
+   if (unlikely(status > 0)) /* filesystem did partial write */
+   copied = status;
 
-   if (status >= 0) {
-   written += status;
-   count -= status;
-   pos += status;
-   buf += status;
-   if (unlikely(nr_segs > 1)) {
-   filemap_set_next_iovec(&cur_iov,
-   &iov_offset, status);
-   if (count)
-   buf = cur_iov->iov_base +
-   iov_offset;
-   } else {
-   iov_offset += status;
-   }
+   if (likely(copied > 0)) {
+   written += copied;
+   count -= copied;
+   pos += copied;
+   buf += copied;
+   if (unlikely(nr_segs > 1)) {
+   filemap_set_next_iovec(&cur_iov,
+   &iov_offset, copied);
+   if (count)
+   buf = cur_iov->iov_base + iov_offset;
+   } else {
+   iov_offset += copied;
}
}
-   if (unlikely(copied != bytes))
-   if (status >= 0)
-   status = -EFAULT;
unlock_page(page);
mark_page_accessed(page);
page_cache_release(page);
-   if (status < 0)
-   break;
balance_dirty_pages_ratelimited(mapping);
cond_resched();
+   continue;
+
+fs_write_aop_error:
+   if (status != AOP_TRUNCATED_PAGE)
+   unlock_page(page);
+   page_cache_release(page);
+
+   /*
+* prepare_write() may have instantiated a few blocks
+* outside i_size.  Trim these off again. Don't need
+* i_size_read because we hold i_mutex.
+*/
+   if (pos