diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-01-02 12:57:34 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-01-02 12:57:34 -0500 |
| commit | 5439ca6b8ff8cf8d758c19eb28b617a5912904ee (patch) | |
| tree | 676f9e0b25074d2d8c5ab29df30c962b3cb7311e /fs | |
| parent | a7a88b23737095e6c18a20c5d4eef9e25ec5b829 (diff) | |
| parent | 0e9a9a1ad619e7e987815d20262d36a2f95717ca (diff) | |
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 bug fixes from Ted Ts'o:
"Various bug fixes for ext4. Perhaps the most serious bug fixed is one
which could cause file system corruptions when performing file punch
operations."
* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: avoid hang when mounting non-journal filesystems with orphan list
ext4: lock i_mutex when truncating orphan inodes
ext4: do not try to write superblock on ro remount w/o journal
ext4: include journal blocks in df overhead calcs
ext4: remove unaligned AIO warning printk
ext4: fix an incorrect comment about i_mutex
ext4: fix deadlock in journal_unmap_buffer()
ext4: split off ext4_journalled_invalidatepage()
jbd2: fix assertion failure in jbd2_journal_flush()
ext4: check dioread_nolock on remount
ext4: fix extent tree corruption caused by hole punch
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ext4/extents.c | 22 | ||||
| -rw-r--r-- | fs/ext4/file.c | 8 | ||||
| -rw-r--r-- | fs/ext4/fsync.c | 2 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 99 | ||||
| -rw-r--r-- | fs/ext4/namei.c | 3 | ||||
| -rw-r--r-- | fs/ext4/super.c | 30 | ||||
| -rw-r--r-- | fs/jbd2/transaction.c | 30 |
7 files changed, 138 insertions, 56 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 26af22832a84..5ae1674ec12f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -2226,13 +2226,14 @@ errout: | |||
| 2226 | * removes index from the index block. | 2226 | * removes index from the index block. |
| 2227 | */ | 2227 | */ |
| 2228 | static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | 2228 | static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, |
| 2229 | struct ext4_ext_path *path) | 2229 | struct ext4_ext_path *path, int depth) |
| 2230 | { | 2230 | { |
| 2231 | int err; | 2231 | int err; |
| 2232 | ext4_fsblk_t leaf; | 2232 | ext4_fsblk_t leaf; |
| 2233 | 2233 | ||
| 2234 | /* free index block */ | 2234 | /* free index block */ |
| 2235 | path--; | 2235 | depth--; |
| 2236 | path = path + depth; | ||
| 2236 | leaf = ext4_idx_pblock(path->p_idx); | 2237 | leaf = ext4_idx_pblock(path->p_idx); |
| 2237 | if (unlikely(path->p_hdr->eh_entries == 0)) { | 2238 | if (unlikely(path->p_hdr->eh_entries == 0)) { |
| 2238 | EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0"); | 2239 | EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0"); |
| @@ -2257,6 +2258,19 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | |||
| 2257 | 2258 | ||
| 2258 | ext4_free_blocks(handle, inode, NULL, leaf, 1, | 2259 | ext4_free_blocks(handle, inode, NULL, leaf, 1, |
| 2259 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); | 2260 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); |
| 2261 | |||
| 2262 | while (--depth >= 0) { | ||
| 2263 | if (path->p_idx != EXT_FIRST_INDEX(path->p_hdr)) | ||
| 2264 | break; | ||
| 2265 | path--; | ||
| 2266 | err = ext4_ext_get_access(handle, inode, path); | ||
| 2267 | if (err) | ||
| 2268 | break; | ||
| 2269 | path->p_idx->ei_block = (path+1)->p_idx->ei_block; | ||
| 2270 | err = ext4_ext_dirty(handle, inode, path); | ||
| 2271 | if (err) | ||
| 2272 | break; | ||
| 2273 | } | ||
| 2260 | return err; | 2274 | return err; |
| 2261 | } | 2275 | } |
| 2262 | 2276 | ||
| @@ -2599,7 +2613,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
| 2599 | /* if this leaf is free, then we should | 2613 | /* if this leaf is free, then we should |
| 2600 | * remove it from index block above */ | 2614 | * remove it from index block above */ |
| 2601 | if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) | 2615 | if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) |
| 2602 | err = ext4_ext_rm_idx(handle, inode, path + depth); | 2616 | err = ext4_ext_rm_idx(handle, inode, path, depth); |
| 2603 | 2617 | ||
| 2604 | out: | 2618 | out: |
| 2605 | return err; | 2619 | return err; |
| @@ -2802,7 +2816,7 @@ again: | |||
| 2802 | /* index is empty, remove it; | 2816 | /* index is empty, remove it; |
| 2803 | * handle must be already prepared by the | 2817 | * handle must be already prepared by the |
| 2804 | * truncatei_leaf() */ | 2818 | * truncatei_leaf() */ |
| 2805 | err = ext4_ext_rm_idx(handle, inode, path + i); | 2819 | err = ext4_ext_rm_idx(handle, inode, path, i); |
| 2806 | } | 2820 | } |
| 2807 | /* root level has p_bh == NULL, brelse() eats this */ | 2821 | /* root level has p_bh == NULL, brelse() eats this */ |
| 2808 | brelse(path[i].p_bh); | 2822 | brelse(path[i].p_bh); |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index d07c27ca594a..405565a62277 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
| @@ -108,14 +108,6 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 108 | 108 | ||
| 109 | /* Unaligned direct AIO must be serialized; see comment above */ | 109 | /* Unaligned direct AIO must be serialized; see comment above */ |
| 110 | if (unaligned_aio) { | 110 | if (unaligned_aio) { |
| 111 | static unsigned long unaligned_warn_time; | ||
| 112 | |||
| 113 | /* Warn about this once per day */ | ||
| 114 | if (printk_timed_ratelimit(&unaligned_warn_time, 60*60*24*HZ)) | ||
| 115 | ext4_msg(inode->i_sb, KERN_WARNING, | ||
| 116 | "Unaligned AIO/DIO on inode %ld by %s; " | ||
| 117 | "performance will be poor.", | ||
| 118 | inode->i_ino, current->comm); | ||
| 119 | mutex_lock(ext4_aio_mutex(inode)); | 111 | mutex_lock(ext4_aio_mutex(inode)); |
| 120 | ext4_unwritten_wait(inode); | 112 | ext4_unwritten_wait(inode); |
| 121 | } | 113 | } |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index dfbc1fe96674..3278e64e57b6 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
| @@ -109,8 +109,6 @@ static int __sync_inode(struct inode *inode, int datasync) | |||
| 109 | * | 109 | * |
| 110 | * What we do is just kick off a commit and wait on it. This will snapshot the | 110 | * What we do is just kick off a commit and wait on it. This will snapshot the |
| 111 | * inode to disk. | 111 | * inode to disk. |
| 112 | * | ||
| 113 | * i_mutex lock is held when entering and exiting this function | ||
| 114 | */ | 112 | */ |
| 115 | 113 | ||
| 116 | int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | 114 | int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index cb1c1ab2720b..cbfe13bf5b2a 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -2880,8 +2880,6 @@ static void ext4_invalidatepage_free_endio(struct page *page, unsigned long offs | |||
| 2880 | 2880 | ||
| 2881 | static void ext4_invalidatepage(struct page *page, unsigned long offset) | 2881 | static void ext4_invalidatepage(struct page *page, unsigned long offset) |
| 2882 | { | 2882 | { |
| 2883 | journal_t *journal = EXT4_JOURNAL(page->mapping->host); | ||
| 2884 | |||
| 2885 | trace_ext4_invalidatepage(page, offset); | 2883 | trace_ext4_invalidatepage(page, offset); |
| 2886 | 2884 | ||
| 2887 | /* | 2885 | /* |
| @@ -2889,16 +2887,34 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset) | |||
| 2889 | */ | 2887 | */ |
| 2890 | if (ext4_should_dioread_nolock(page->mapping->host)) | 2888 | if (ext4_should_dioread_nolock(page->mapping->host)) |
| 2891 | ext4_invalidatepage_free_endio(page, offset); | 2889 | ext4_invalidatepage_free_endio(page, offset); |
| 2890 | |||
| 2891 | /* No journalling happens on data buffers when this function is used */ | ||
| 2892 | WARN_ON(page_has_buffers(page) && buffer_jbd(page_buffers(page))); | ||
| 2893 | |||
| 2894 | block_invalidatepage(page, offset); | ||
| 2895 | } | ||
| 2896 | |||
| 2897 | static int __ext4_journalled_invalidatepage(struct page *page, | ||
| 2898 | unsigned long offset) | ||
| 2899 | { | ||
| 2900 | journal_t *journal = EXT4_JOURNAL(page->mapping->host); | ||
| 2901 | |||
| 2902 | trace_ext4_journalled_invalidatepage(page, offset); | ||
| 2903 | |||
| 2892 | /* | 2904 | /* |
| 2893 | * If it's a full truncate we just forget about the pending dirtying | 2905 | * If it's a full truncate we just forget about the pending dirtying |
| 2894 | */ | 2906 | */ |
| 2895 | if (offset == 0) | 2907 | if (offset == 0) |
| 2896 | ClearPageChecked(page); | 2908 | ClearPageChecked(page); |
| 2897 | 2909 | ||
| 2898 | if (journal) | 2910 | return jbd2_journal_invalidatepage(journal, page, offset); |
| 2899 | jbd2_journal_invalidatepage(journal, page, offset); | 2911 | } |
| 2900 | else | 2912 | |
| 2901 | block_invalidatepage(page, offset); | 2913 | /* Wrapper for aops... */ |
| 2914 | static void ext4_journalled_invalidatepage(struct page *page, | ||
| 2915 | unsigned long offset) | ||
| 2916 | { | ||
| 2917 | WARN_ON(__ext4_journalled_invalidatepage(page, offset) < 0); | ||
| 2902 | } | 2918 | } |
| 2903 | 2919 | ||
| 2904 | static int ext4_releasepage(struct page *page, gfp_t wait) | 2920 | static int ext4_releasepage(struct page *page, gfp_t wait) |
| @@ -3264,7 +3280,7 @@ static const struct address_space_operations ext4_journalled_aops = { | |||
| 3264 | .write_end = ext4_journalled_write_end, | 3280 | .write_end = ext4_journalled_write_end, |
| 3265 | .set_page_dirty = ext4_journalled_set_page_dirty, | 3281 | .set_page_dirty = ext4_journalled_set_page_dirty, |
| 3266 | .bmap = ext4_bmap, | 3282 | .bmap = ext4_bmap, |
| 3267 | .invalidatepage = ext4_invalidatepage, | 3283 | .invalidatepage = ext4_journalled_invalidatepage, |
| 3268 | .releasepage = ext4_releasepage, | 3284 | .releasepage = ext4_releasepage, |
| 3269 | .direct_IO = ext4_direct_IO, | 3285 | .direct_IO = ext4_direct_IO, |
| 3270 | .is_partially_uptodate = block_is_partially_uptodate, | 3286 | .is_partially_uptodate = block_is_partially_uptodate, |
| @@ -4305,6 +4321,47 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 4305 | } | 4321 | } |
| 4306 | 4322 | ||
| 4307 | /* | 4323 | /* |
| 4324 | * In data=journal mode ext4_journalled_invalidatepage() may fail to invalidate | ||
| 4325 | * buffers that are attached to a page stradding i_size and are undergoing | ||
| 4326 | * commit. In that case we have to wait for commit to finish and try again. | ||
| 4327 | */ | ||
| 4328 | static void ext4_wait_for_tail_page_commit(struct inode *inode) | ||
| 4329 | { | ||
| 4330 | struct page *page; | ||
| 4331 | unsigned offset; | ||
| 4332 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; | ||
| 4333 | tid_t commit_tid = 0; | ||
