diff options
author | Theodore Ts'o <tytso@mit.edu> | 2017-02-04 23:04:00 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-12 00:41:46 -0500 |
commit | 0b37d0c0c6b35317bfc3aee8cdf94f853d594e5f (patch) | |
tree | 5624710ad17e61535ed48e2fffa85eb4e007a72c /fs | |
parent | 68ca0fdac41fa801e1e6c2f99e27a9c24e494532 (diff) |
ext4: fix inline data error paths
commit eb5efbcb762aee4b454b04f7115f73ccbcf8f0ef upstream.
The write_end() function must always unlock the page and drop its ref
count, even on an error.
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/inline.c | 9 | ||||
-rw-r--r-- | fs/ext4/inode.c | 20 |
2 files changed, 23 insertions, 6 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 028329721bbe..37b521ed39df 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -933,8 +933,15 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, | |||
933 | struct page *page) | 933 | struct page *page) |
934 | { | 934 | { |
935 | int i_size_changed = 0; | 935 | int i_size_changed = 0; |
936 | int ret; | ||
936 | 937 | ||
937 | copied = ext4_write_inline_data_end(inode, pos, len, copied, page); | 938 | ret = ext4_write_inline_data_end(inode, pos, len, copied, page); |
939 | if (ret < 0) { | ||
940 | unlock_page(page); | ||
941 | put_page(page); | ||
942 | return ret; | ||
943 | } | ||
944 | copied = ret; | ||
938 | 945 | ||
939 | /* | 946 | /* |
940 | * No need to use i_size_read() here, the i_size | 947 | * No need to use i_size_read() here, the i_size |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a48b17cc0cd1..1d4f5faa04b5 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1324,8 +1324,11 @@ static int ext4_write_end(struct file *file, | |||
1324 | if (ext4_has_inline_data(inode)) { | 1324 | if (ext4_has_inline_data(inode)) { |
1325 | ret = ext4_write_inline_data_end(inode, pos, len, | 1325 | ret = ext4_write_inline_data_end(inode, pos, len, |
1326 | copied, page); | 1326 | copied, page); |
1327 | if (ret < 0) | 1327 | if (ret < 0) { |
1328 | unlock_page(page); | ||
1329 | put_page(page); | ||
1328 | goto errout; | 1330 | goto errout; |
1331 | } | ||
1329 | copied = ret; | 1332 | copied = ret; |
1330 | } else | 1333 | } else |
1331 | copied = block_write_end(file, mapping, pos, | 1334 | copied = block_write_end(file, mapping, pos, |
@@ -1427,10 +1430,16 @@ static int ext4_journalled_write_end(struct file *file, | |||
1427 | 1430 | ||
1428 | BUG_ON(!ext4_handle_valid(handle)); | 1431 | BUG_ON(!ext4_handle_valid(handle)); |
1429 | 1432 | ||
1430 | if (ext4_has_inline_data(inode)) | 1433 | if (ext4_has_inline_data(inode)) { |
1431 | copied = ext4_write_inline_data_end(inode, pos, len, | 1434 | ret = ext4_write_inline_data_end(inode, pos, len, |
1432 | copied, page); | 1435 | copied, page); |
1433 | else if (unlikely(copied < len) && !PageUptodate(page)) { | 1436 | if (ret < 0) { |
1437 | unlock_page(page); | ||
1438 | put_page(page); | ||
1439 | goto errout; | ||
1440 | } | ||
1441 | copied = ret; | ||
1442 | } else if (unlikely(copied < len) && !PageUptodate(page)) { | ||
1434 | copied = 0; | 1443 | copied = 0; |
1435 | ext4_journalled_zero_new_buffers(handle, page, from, to); | 1444 | ext4_journalled_zero_new_buffers(handle, page, from, to); |
1436 | } else { | 1445 | } else { |
@@ -1465,6 +1474,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1465 | */ | 1474 | */ |
1466 | ext4_orphan_add(handle, inode); | 1475 | ext4_orphan_add(handle, inode); |
1467 | 1476 | ||
1477 | errout: | ||
1468 | ret2 = ext4_journal_stop(handle); | 1478 | ret2 = ext4_journal_stop(handle); |
1469 | if (!ret) | 1479 | if (!ret) |
1470 | ret = ret2; | 1480 | ret = ret2; |