diff options
author | David Chinner <dgc@sgi.com> | 2007-05-24 01:27:03 -0400 |
---|---|---|
committer | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-05-29 04:15:17 -0400 |
commit | df3c7244264f1d12562413aa32d56be802486516 (patch) | |
tree | 99570b393dc5890fc1751c56aad3deffb0d1c95b /fs | |
parent | c420bc9f09a0926b708c3edb27eacba434a4f4ba (diff) |
[XFS] Write at EOF may not update filesize correctly.
The recent fix for preventing NULL files from being left around does not
update the file size corectly in all cases. The missing case is a write
extending the file that does not need to allocate a block.
In that case we used a read mapping of the extent which forced the use of
the read I/O completion handler instead of the write I/O completion
handle. Hence the file size was not updated on I/O completion.
SGI-PV: 965068
SGI-Modid: xfs-linux-melb:xfs-kern:28657a
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Nathan Scott <nscott@aconex.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 4475588e973a..7361861e3aac 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -701,7 +701,7 @@ xfs_is_delayed_page( | |||
701 | else if (buffer_delay(bh)) | 701 | else if (buffer_delay(bh)) |
702 | acceptable = (type == IOMAP_DELAY); | 702 | acceptable = (type == IOMAP_DELAY); |
703 | else if (buffer_dirty(bh) && buffer_mapped(bh)) | 703 | else if (buffer_dirty(bh) && buffer_mapped(bh)) |
704 | acceptable = (type == 0); | 704 | acceptable = (type == IOMAP_NEW); |
705 | else | 705 | else |
706 | break; | 706 | break; |
707 | } while ((bh = bh->b_this_page) != head); | 707 | } while ((bh = bh->b_this_page) != head); |
@@ -810,7 +810,7 @@ xfs_convert_page( | |||
810 | page_dirty--; | 810 | page_dirty--; |
811 | count++; | 811 | count++; |
812 | } else { | 812 | } else { |
813 | type = 0; | 813 | type = IOMAP_NEW; |
814 | if (buffer_mapped(bh) && all_bh && startio) { | 814 | if (buffer_mapped(bh) && all_bh && startio) { |
815 | lock_buffer(bh); | 815 | lock_buffer(bh); |
816 | xfs_add_to_ioend(inode, bh, offset, | 816 | xfs_add_to_ioend(inode, bh, offset, |
@@ -968,8 +968,8 @@ xfs_page_state_convert( | |||
968 | 968 | ||
969 | bh = head = page_buffers(page); | 969 | bh = head = page_buffers(page); |
970 | offset = page_offset(page); | 970 | offset = page_offset(page); |
971 | flags = -1; | 971 | flags = BMAPI_READ; |
972 | type = IOMAP_READ; | 972 | type = IOMAP_NEW; |
973 | 973 | ||
974 | /* TODO: cleanup count and page_dirty */ | 974 | /* TODO: cleanup count and page_dirty */ |
975 | 975 | ||
@@ -999,14 +999,14 @@ xfs_page_state_convert( | |||
999 | * | 999 | * |
1000 | * Third case, an unmapped buffer was found, and we are | 1000 | * Third case, an unmapped buffer was found, and we are |
1001 | * in a path where we need to write the whole page out. | 1001 | * in a path where we need to write the whole page out. |
1002 | */ | 1002 | */ |
1003 | if (buffer_unwritten(bh) || buffer_delay(bh) || | 1003 | if (buffer_unwritten(bh) || buffer_delay(bh) || |
1004 | ((buffer_uptodate(bh) || PageUptodate(page)) && | 1004 | ((buffer_uptodate(bh) || PageUptodate(page)) && |
1005 | !buffer_mapped(bh) && (unmapped || startio))) { | 1005 | !buffer_mapped(bh) && (unmapped || startio))) { |
1006 | /* | 1006 | /* |
1007 | * Make sure we don't use a read-only iomap | 1007 | * Make sure we don't use a read-only iomap |
1008 | */ | 1008 | */ |
1009 | if (flags == BMAPI_READ) | 1009 | if (flags == BMAPI_READ) |
1010 | iomap_valid = 0; | 1010 | iomap_valid = 0; |
1011 | 1011 | ||
1012 | if (buffer_unwritten(bh)) { | 1012 | if (buffer_unwritten(bh)) { |
@@ -1055,7 +1055,7 @@ xfs_page_state_convert( | |||
1055 | * That means it must already have extents allocated | 1055 | * That means it must already have extents allocated |
1056 | * underneath it. Map the extent by reading it. | 1056 | * underneath it. Map the extent by reading it. |
1057 | */ | 1057 | */ |
1058 | if (!iomap_valid || type != IOMAP_READ) { | 1058 | if (!iomap_valid || flags != BMAPI_READ) { |
1059 | flags = BMAPI_READ; | 1059 | flags = BMAPI_READ; |
1060 | size = xfs_probe_cluster(inode, page, bh, | 1060 | size = xfs_probe_cluster(inode, page, bh, |
1061 | head, 1); | 1061 | head, 1); |
@@ -1066,7 +1066,15 @@ xfs_page_state_convert( | |||
1066 | iomap_valid = xfs_iomap_valid(&iomap, offset); | 1066 | iomap_valid = xfs_iomap_valid(&iomap, offset); |
1067 | } | 1067 | } |
1068 | 1068 | ||
1069 | type = IOMAP_READ; | 1069 | /* |
1070 | * We set the type to IOMAP_NEW in case we are doing a | ||
1071 | * small write at EOF that is extending the file but | ||
1072 | * without needing an allocation. We need to update the | ||
1073 | * file size on I/O completion in this case so it is | ||
1074 | * the same case as having just allocated a new extent | ||
1075 | * that we are writing into for the first time. | ||
1076 | */ | ||
1077 | type = IOMAP_NEW; | ||
1070 | if (!test_and_set_bit(BH_Lock, &bh->b_state)) { | 1078 | if (!test_and_set_bit(BH_Lock, &bh->b_state)) { |
1071 | ASSERT(buffer_mapped(bh)); | 1079 | ASSERT(buffer_mapped(bh)); |
1072 | if (iomap_valid) | 1080 | if (iomap_valid) |