diff options
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 977e715f0bf2..0f09526aa7d9 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1291,7 +1291,8 @@ out: | |||
1291 | * on error we return an unlocked page and the error value | 1291 | * on error we return an unlocked page and the error value |
1292 | * on success we return a locked page and 0 | 1292 | * on success we return a locked page and 0 |
1293 | */ | 1293 | */ |
1294 | static int prepare_uptodate_page(struct page *page, u64 pos, | 1294 | static int prepare_uptodate_page(struct inode *inode, |
1295 | struct page *page, u64 pos, | ||
1295 | bool force_uptodate) | 1296 | bool force_uptodate) |
1296 | { | 1297 | { |
1297 | int ret = 0; | 1298 | int ret = 0; |
@@ -1306,6 +1307,10 @@ static int prepare_uptodate_page(struct page *page, u64 pos, | |||
1306 | unlock_page(page); | 1307 | unlock_page(page); |
1307 | return -EIO; | 1308 | return -EIO; |
1308 | } | 1309 | } |
1310 | if (page->mapping != inode->i_mapping) { | ||
1311 | unlock_page(page); | ||
1312 | return -EAGAIN; | ||
1313 | } | ||
1309 | } | 1314 | } |
1310 | return 0; | 1315 | return 0; |
1311 | } | 1316 | } |
@@ -1324,6 +1329,7 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages, | |||
1324 | int faili; | 1329 | int faili; |
1325 | 1330 | ||
1326 | for (i = 0; i < num_pages; i++) { | 1331 | for (i = 0; i < num_pages; i++) { |
1332 | again: | ||
1327 | pages[i] = find_or_create_page(inode->i_mapping, index + i, | 1333 | pages[i] = find_or_create_page(inode->i_mapping, index + i, |
1328 | mask | __GFP_WRITE); | 1334 | mask | __GFP_WRITE); |
1329 | if (!pages[i]) { | 1335 | if (!pages[i]) { |
@@ -1333,13 +1339,17 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages, | |||
1333 | } | 1339 | } |
1334 | 1340 | ||
1335 | if (i == 0) | 1341 | if (i == 0) |
1336 | err = prepare_uptodate_page(pages[i], pos, | 1342 | err = prepare_uptodate_page(inode, pages[i], pos, |
1337 | force_uptodate); | 1343 | force_uptodate); |
1338 | if (i == num_pages - 1) | 1344 | if (!err && i == num_pages - 1) |
1339 | err = prepare_uptodate_page(pages[i], | 1345 | err = prepare_uptodate_page(inode, pages[i], |
1340 | pos + write_bytes, false); | 1346 | pos + write_bytes, false); |
1341 | if (err) { | 1347 | if (err) { |
1342 | page_cache_release(pages[i]); | 1348 | page_cache_release(pages[i]); |
1349 | if (err == -EAGAIN) { | ||
1350 | err = 0; | ||
1351 | goto again; | ||
1352 | } | ||
1343 | faili = i - 1; | 1353 | faili = i - 1; |
1344 | goto fail; | 1354 | goto fail; |
1345 | } | 1355 | } |
@@ -1882,8 +1892,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
1882 | struct btrfs_log_ctx ctx; | 1892 | struct btrfs_log_ctx ctx; |
1883 | int ret = 0; | 1893 | int ret = 0; |
1884 | bool full_sync = 0; | 1894 | bool full_sync = 0; |
1885 | const u64 len = end - start + 1; | 1895 | u64 len; |
1886 | 1896 | ||
1897 | /* | ||
1898 | * The range length can be represented by u64, we have to do the typecasts | ||
1899 | * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync() | ||
1900 | */ | ||
1901 | len = (u64)end - (u64)start + 1; | ||
1887 | trace_btrfs_sync_file(file, datasync); | 1902 | trace_btrfs_sync_file(file, datasync); |
1888 | 1903 | ||
1889 | /* | 1904 | /* |
@@ -2071,8 +2086,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
2071 | } | 2086 | } |
2072 | } | 2087 | } |
2073 | if (!full_sync) { | 2088 | if (!full_sync) { |
2074 | ret = btrfs_wait_ordered_range(inode, start, | 2089 | ret = btrfs_wait_ordered_range(inode, start, len); |
2075 | end - start + 1); | ||
2076 | if (ret) { | 2090 | if (ret) { |
2077 | btrfs_end_transaction(trans, root); | 2091 | btrfs_end_transaction(trans, root); |
2078 | goto out; | 2092 | goto out; |