On Sat, 2007-01-13 at 04:25 +0100, Nick Piggin wrote:
> 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.
> 
> Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>
> 
> Index: linux-2.6/mm/filemap.c
> ===================================================================
> --- linux-2.6.orig/mm/filemap.c
> +++ linux-2.6/mm/filemap.c
> @@ -1911,22 +1911,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);
> @@ -1935,10 +1922,9 @@ 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))
> +                     goto fs_write_aop_error;
> +

I don't think this is correct, see how status >= 0 is used a few lines
downwards. Perhaps something along the lines of an
is_positive_aop_return() to test on?

>               if (likely(copied > 0)) {
>                       if (!status)
>                               status = copied;
> @@ -1969,6 +1955,25 @@ generic_file_buffered_write(struct kiocb
>                       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 + bytes > inode->i_size)
> +                     vmtruncate(inode, inode->i_size);
> +             if (status == AOP_TRUNCATED_PAGE)
> +                     continue;
> +             else
> +                     break;
> +
>       } while (count);
>       *ppos = pos;


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

Reply via email to