diff options
Diffstat (limited to 'fs/ext3/inode.c')
| -rw-r--r-- | fs/ext3/inode.c | 113 |
1 files changed, 74 insertions, 39 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 6ae4ecf3ce40..507d8689b111 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
| @@ -1767,44 +1767,47 @@ static int ext3_journalled_set_page_dirty(struct page *page) | |||
| 1767 | } | 1767 | } |
| 1768 | 1768 | ||
| 1769 | static const struct address_space_operations ext3_ordered_aops = { | 1769 | static const struct address_space_operations ext3_ordered_aops = { |
| 1770 | .readpage = ext3_readpage, | 1770 | .readpage = ext3_readpage, |
| 1771 | .readpages = ext3_readpages, | 1771 | .readpages = ext3_readpages, |
| 1772 | .writepage = ext3_ordered_writepage, | 1772 | .writepage = ext3_ordered_writepage, |
| 1773 | .sync_page = block_sync_page, | 1773 | .sync_page = block_sync_page, |
| 1774 | .write_begin = ext3_write_begin, | 1774 | .write_begin = ext3_write_begin, |
| 1775 | .write_end = ext3_ordered_write_end, | 1775 | .write_end = ext3_ordered_write_end, |
| 1776 | .bmap = ext3_bmap, | 1776 | .bmap = ext3_bmap, |
| 1777 | .invalidatepage = ext3_invalidatepage, | 1777 | .invalidatepage = ext3_invalidatepage, |
| 1778 | .releasepage = ext3_releasepage, | 1778 | .releasepage = ext3_releasepage, |
| 1779 | .direct_IO = ext3_direct_IO, | 1779 | .direct_IO = ext3_direct_IO, |
| 1780 | .migratepage = buffer_migrate_page, | 1780 | .migratepage = buffer_migrate_page, |
| 1781 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 1781 | }; | 1782 | }; |
| 1782 | 1783 | ||
| 1783 | static const struct address_space_operations ext3_writeback_aops = { | 1784 | static const struct address_space_operations ext3_writeback_aops = { |
| 1784 | .readpage = ext3_readpage, | 1785 | .readpage = ext3_readpage, |
| 1785 | .readpages = ext3_readpages, | 1786 | .readpages = ext3_readpages, |
| 1786 | .writepage = ext3_writeback_writepage, | 1787 | .writepage = ext3_writeback_writepage, |
| 1787 | .sync_page = block_sync_page, | 1788 | .sync_page = block_sync_page, |
| 1788 | .write_begin = ext3_write_begin, | 1789 | .write_begin = ext3_write_begin, |
| 1789 | .write_end = ext3_writeback_write_end, | 1790 | .write_end = ext3_writeback_write_end, |
| 1790 | .bmap = ext3_bmap, | 1791 | .bmap = ext3_bmap, |
| 1791 | .invalidatepage = ext3_invalidatepage, | 1792 | .invalidatepage = ext3_invalidatepage, |
| 1792 | .releasepage = ext3_releasepage, | 1793 | .releasepage = ext3_releasepage, |
| 1793 | .direct_IO = ext3_direct_IO, | 1794 | .direct_IO = ext3_direct_IO, |
| 1794 | .migratepage = buffer_migrate_page, | 1795 | .migratepage = buffer_migrate_page, |
| 1796 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 1795 | }; | 1797 | }; |
| 1796 | 1798 | ||
| 1797 | static const struct address_space_operations ext3_journalled_aops = { | 1799 | static const struct address_space_operations ext3_journalled_aops = { |
| 1798 | .readpage = ext3_readpage, | 1800 | .readpage = ext3_readpage, |
| 1799 | .readpages = ext3_readpages, | 1801 | .readpages = ext3_readpages, |
| 1800 | .writepage = ext3_journalled_writepage, | 1802 | .writepage = ext3_journalled_writepage, |
| 1801 | .sync_page = block_sync_page, | 1803 | .sync_page = block_sync_page, |
| 1802 | .write_begin = ext3_write_begin, | 1804 | .write_begin = ext3_write_begin, |
| 1803 | .write_end = ext3_journalled_write_end, | 1805 | .write_end = ext3_journalled_write_end, |
| 1804 | .set_page_dirty = ext3_journalled_set_page_dirty, | 1806 | .set_page_dirty = ext3_journalled_set_page_dirty, |
| 1805 | .bmap = ext3_bmap, | 1807 | .bmap = ext3_bmap, |
| 1806 | .invalidatepage = ext3_invalidatepage, | 1808 | .invalidatepage = ext3_invalidatepage, |
| 1807 | .releasepage = ext3_releasepage, | 1809 | .releasepage = ext3_releasepage, |
| 1810 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 1808 | }; | 1811 | }; |
| 1809 | 1812 | ||
| 1810 | void ext3_set_aops(struct inode *inode) | 1813 | void ext3_set_aops(struct inode *inode) |
| @@ -2127,7 +2130,21 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, | |||
| 2127 | 2130 | ||
| 2128 | if (this_bh) { | 2131 | if (this_bh) { |
| 2129 | BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); | 2132 | BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); |
| 2130 | ext3_journal_dirty_metadata(handle, this_bh); | 2133 | |
| 2134 | /* | ||
| 2135 | * The buffer head should have an attached journal head at this | ||
| 2136 | * point. However, if the data is corrupted and an indirect | ||
| 2137 | * block pointed to itself, it would have been detached when | ||
| 2138 | * the block was cleared. Check for this instead of OOPSing. | ||
| 2139 | */ | ||
| 2140 | if (bh2jh(this_bh)) | ||
| 2141 | ext3_journal_dirty_metadata(handle, this_bh); | ||
| 2142 | else | ||
| 2143 | ext3_error(inode->i_sb, "ext3_free_data", | ||
| 2144 | "circular indirect block detected, " | ||
| 2145 | "inode=%lu, block=%llu", | ||
| 2146 | inode->i_ino, | ||
| 2147 | (unsigned long long)this_bh->b_blocknr); | ||
| 2131 | } | 2148 | } |
| 2132 | } | 2149 | } |
| 2133 | 2150 | ||
| @@ -2253,6 +2270,19 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
| 2253 | } | 2270 | } |
| 2254 | } | 2271 | } |
| 2255 | 2272 | ||
| 2273 | int ext3_can_truncate(struct inode *inode) | ||
| 2274 | { | ||
| 2275 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
| 2276 | return 0; | ||
| 2277 | if (S_ISREG(inode->i_mode)) | ||
| 2278 | return 1; | ||
| 2279 | if (S_ISDIR(inode->i_mode)) | ||
| 2280 | return 1; | ||
| 2281 | if (S_ISLNK(inode->i_mode)) | ||
| 2282 | return !ext3_inode_is_fast_symlink(inode); | ||
| 2283 | return 0; | ||
| 2284 | } | ||
| 2285 | |||
| 2256 | /* | 2286 | /* |
| 2257 | * ext3_truncate() | 2287 | * ext3_truncate() |
| 2258 | * | 2288 | * |
| @@ -2297,12 +2327,7 @@ void ext3_truncate(struct inode *inode) | |||
| 2297 | unsigned blocksize = inode->i_sb->s_blocksize; | 2327 | unsigned blocksize = inode->i_sb->s_blocksize; |
| 2298 | struct page *page; | 2328 | struct page *page; |
| 2299 | 2329 | ||
| 2300 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 2330 | if (!ext3_can_truncate(inode)) |
| 2301 | S_ISLNK(inode->i_mode))) | ||
| 2302 | return; | ||
| 2303 | if (ext3_inode_is_fast_symlink(inode)) | ||
| 2304 | return; | ||
| 2305 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
| 2306 | return; | 2331 | return; |
| 2307 | 2332 | ||
| 2308 | /* | 2333 | /* |
| @@ -2513,6 +2538,16 @@ static int __ext3_get_inode_loc(struct inode *inode, | |||
| 2513 | } | 2538 | } |
| 2514 | if (!buffer_uptodate(bh)) { | 2539 | if (!buffer_uptodate(bh)) { |
| 2515 | lock_buffer(bh); | 2540 | lock_buffer(bh); |
| 2541 | |||
| 2542 | /* | ||
| 2543 | * If the buffer has the write error flag, we have failed | ||
| 2544 | * to write out another inode in the same block. In this | ||
| 2545 | * case, we don't have to read the block because we may | ||
| 2546 | * read the old inode data successfully. | ||
| 2547 | */ | ||
| 2548 | if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) | ||
| 2549 | set_buffer_uptodate(bh); | ||
| 2550 | |||
| 2516 | if (buffer_uptodate(bh)) { | 2551 | if (buffer_uptodate(bh)) { |
| 2517 | /* someone brought it uptodate while we waited */ | 2552 | /* someone brought it uptodate while we waited */ |
| 2518 | unlock_buffer(bh); | 2553 | unlock_buffer(bh); |
