diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 18:03:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 18:03:21 -0400 |
commit | a5adcfcad55d5f034b33f79f1a873229d1e77b24 (patch) | |
tree | e9548efcccb8f5ed3e120b0ca36ad04de116cdb7 | |
parent | 2b0a80b0d0bb0a3db74588279bf851b28c6c4705 (diff) | |
parent | 0df6f46995a9fc92a6b9e591428e77527dd9609a (diff) |
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o:
"A large number of bug fixes and cleanups.
One new feature to allow users to more easily find the jbd2 journal
thread for a particular ext4 file system"
* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (25 commits)
jbd2: jbd2_get_transaction does not need to return a value
jbd2: fix invalid descriptor block checksum
ext4: fix bigalloc cluster freeing when hole punching under load
ext4: add sysfs attr /sys/fs/ext4/<disk>/journal_task
ext4: Change debugging support help prefix from EXT4 to Ext4
ext4: fix compile error when using BUFFER_TRACE
jbd2: fix compile warning when using JBUFFER_TRACE
ext4: fix some error pointer dereferences
ext4: annotate more implicit fall throughs
ext4: annotate implicit fall throughs
ext4: don't update s_rev_level if not required
jbd2: fold jbd2_superblock_csum_{verify,set} into their callers
jbd2: fix race when writing superblock
ext4: fix crash during online resizing
ext4: disallow files with EXT4_JOURNAL_DATA_FL from EXT4_IOC_SWAP_BOOT
ext4: add mask of ext4 flags to swap
ext4: update quota information while swapping boot loader inode
ext4: cleanup pagecache before swap i_data
ext4: fix check of inode in swap_inode_boot_loader
ext4: unlock unused_pages timely when doing writeback
...
-rw-r--r-- | Documentation/ABI/testing/sysfs-fs-ext4 | 7 | ||||
-rw-r--r-- | fs/ext4/Kconfig | 2 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 9 | ||||
-rw-r--r-- | fs/ext4/extents.c | 29 | ||||
-rw-r--r-- | fs/ext4/hash.c | 2 | ||||
-rw-r--r-- | fs/ext4/indirect.c | 6 | ||||
-rw-r--r-- | fs/ext4/inode.c | 21 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 101 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 7 | ||||
-rw-r--r-- | fs/ext4/page-io.c | 4 | ||||
-rw-r--r-- | fs/ext4/resize.c | 3 | ||||
-rw-r--r-- | fs/ext4/super.c | 1 | ||||
-rw-r--r-- | fs/ext4/sysfs.c | 13 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 3 | ||||
-rw-r--r-- | fs/jbd2/checkpoint.c | 17 | ||||
-rw-r--r-- | fs/jbd2/commit.c | 6 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 90 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 83 |
18 files changed, 257 insertions, 147 deletions
diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4 index c631253cf85c..78604db56279 100644 --- a/Documentation/ABI/testing/sysfs-fs-ext4 +++ b/Documentation/ABI/testing/sysfs-fs-ext4 | |||
@@ -109,3 +109,10 @@ Description: | |||
109 | write operation (since a 4k random write might turn | 109 | write operation (since a 4k random write might turn |
110 | into a much larger write due to the zeroout | 110 | into a much larger write due to the zeroout |
111 | operation). | 111 | operation). |
112 | |||
113 | What: /sys/fs/ext4/<disk>/journal_task | ||
114 | Date: February 2019 | ||
115 | Contact: "Theodore Ts'o" <tytso@mit.edu> | ||
116 | Description: | ||
117 | This file is read-only and shows the pid of journal thread in | ||
118 | current pid-namespace or 0 if task is unreachable. | ||
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index 031e5a82d556..06f77ca7f36e 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig | |||
@@ -97,7 +97,7 @@ config EXT4_FS_SECURITY | |||
97 | extended attributes for file security labels, say N. | 97 | extended attributes for file security labels, say N. |
98 | 98 | ||
99 | config EXT4_DEBUG | 99 | config EXT4_DEBUG |
100 | bool "EXT4 debugging support" | 100 | bool "Ext4 debugging support" |
101 | depends on EXT4_FS | 101 | depends on EXT4_FS |
102 | help | 102 | help |
103 | Enables run-time debugging support for the ext4 filesystem. | 103 | Enables run-time debugging support for the ext4 filesystem. |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 5012ddb6daf9..82ffdacdc7fa 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -425,6 +425,9 @@ struct flex_groups { | |||
425 | /* Flags that are appropriate for non-directories/regular files. */ | 425 | /* Flags that are appropriate for non-directories/regular files. */ |
426 | #define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL) | 426 | #define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL) |
427 | 427 | ||
428 | /* The only flags that should be swapped */ | ||
429 | #define EXT4_FL_SHOULD_SWAP (EXT4_HUGE_FILE_FL | EXT4_EXTENTS_FL) | ||
430 | |||
428 | /* Mask out flags that are inappropriate for the given type of inode. */ | 431 | /* Mask out flags that are inappropriate for the given type of inode. */ |
429 | static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags) | 432 | static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags) |
430 | { | 433 | { |
@@ -1661,6 +1664,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) | |||
1661 | #define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ | 1664 | #define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ |
1662 | #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 | 1665 | #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 |
1663 | 1666 | ||
1667 | extern void ext4_update_dynamic_rev(struct super_block *sb); | ||
1668 | |||
1664 | #define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \ | 1669 | #define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \ |
1665 | static inline bool ext4_has_feature_##name(struct super_block *sb) \ | 1670 | static inline bool ext4_has_feature_##name(struct super_block *sb) \ |
1666 | { \ | 1671 | { \ |
@@ -1669,6 +1674,7 @@ static inline bool ext4_has_feature_##name(struct super_block *sb) \ | |||
1669 | } \ | 1674 | } \ |
1670 | static inline void ext4_set_feature_##name(struct super_block *sb) \ | 1675 | static inline void ext4_set_feature_##name(struct super_block *sb) \ |
1671 | { \ | 1676 | { \ |
1677 | ext4_update_dynamic_rev(sb); \ | ||
1672 | EXT4_SB(sb)->s_es->s_feature_compat |= \ | 1678 | EXT4_SB(sb)->s_es->s_feature_compat |= \ |
1673 | cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \ | 1679 | cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \ |
1674 | } \ | 1680 | } \ |
@@ -1686,6 +1692,7 @@ static inline bool ext4_has_feature_##name(struct super_block *sb) \ | |||
1686 | } \ | 1692 | } \ |
1687 | static inline void ext4_set_feature_##name(struct super_block *sb) \ | 1693 | static inline void ext4_set_feature_##name(struct super_block *sb) \ |
1688 | { \ | 1694 | { \ |
1695 | ext4_update_dynamic_rev(sb); \ | ||
1689 | EXT4_SB(sb)->s_es->s_feature_ro_compat |= \ | 1696 | EXT4_SB(sb)->s_es->s_feature_ro_compat |= \ |
1690 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \ | 1697 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \ |
1691 | } \ | 1698 | } \ |
@@ -1703,6 +1710,7 @@ static inline bool ext4_has_feature_##name(struct super_block *sb) \ | |||
1703 | } \ | 1710 | } \ |
1704 | static inline void ext4_set_feature_##name(struct super_block *sb) \ | 1711 | static inline void ext4_set_feature_##name(struct super_block *sb) \ |
1705 | { \ | 1712 | { \ |
1713 | ext4_update_dynamic_rev(sb); \ | ||
1706 | EXT4_SB(sb)->s_es->s_feature_incompat |= \ | 1714 | EXT4_SB(sb)->s_es->s_feature_incompat |= \ |
1707 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \ | 1715 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \ |
1708 | } \ | 1716 | } \ |
@@ -2666,7 +2674,6 @@ do { \ | |||
2666 | 2674 | ||
2667 | #endif | 2675 | #endif |
2668 | 2676 | ||
2669 | extern void ext4_update_dynamic_rev(struct super_block *sb); | ||
2670 | extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb, | 2677 | extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb, |
2671 | __u32 compat); | 2678 | __u32 compat); |
2672 | extern int ext4_update_rocompat_feature(handle_t *handle, | 2679 | extern int ext4_update_rocompat_feature(handle_t *handle, |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 79d986dbf5af..0f89f5190cd7 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -2956,14 +2956,17 @@ again: | |||
2956 | if (err < 0) | 2956 | if (err < 0) |
2957 | goto out; | 2957 | goto out; |
2958 | 2958 | ||
2959 | } else if (sbi->s_cluster_ratio > 1 && end >= ex_end) { | 2959 | } else if (sbi->s_cluster_ratio > 1 && end >= ex_end && |
2960 | partial.state == initial) { | ||
2960 | /* | 2961 | /* |
2961 | * If there's an extent to the right its first cluster | 2962 | * If we're punching, there's an extent to the right. |
2962 | * contains the immediate right boundary of the | 2963 | * If the partial cluster hasn't been set, set it to |
2963 | * truncated/punched region. Set partial_cluster to | 2964 | * that extent's first cluster and its state to nofree |
2964 | * its negative value so it won't be freed if shared | 2965 | * so it won't be freed should it contain blocks to be |
2965 | * with the current extent. The end < ee_block case | 2966 | * removed. If it's already set (tofree/nofree), we're |
2966 | * is handled in ext4_ext_rm_leaf(). | 2967 | * retrying and keep the original partial cluster info |
2968 | * so a cluster marked tofree as a result of earlier | ||
2969 | * extent removal is not lost. | ||
2967 | */ | 2970 | */ |
2968 | lblk = ex_end + 1; | 2971 | lblk = ex_end + 1; |
2969 | err = ext4_ext_search_right(inode, path, &lblk, &pblk, | 2972 | err = ext4_ext_search_right(inode, path, &lblk, &pblk, |
@@ -4048,18 +4051,8 @@ out: | |||
4048 | } else | 4051 | } else |
4049 | allocated = ret; | 4052 | allocated = ret; |
4050 | map->m_flags |= EXT4_MAP_NEW; | 4053 | map->m_flags |= EXT4_MAP_NEW; |
4051 | /* | 4054 | if (allocated > map->m_len) |
4052 | * if we allocated more blocks than requested | ||
4053 | * we need to make sure we unmap the extra block | ||
4054 | * allocated. The actual needed block will get | ||
4055 | * unmapped later when we find the buffer_head marked | ||
4056 | * new. | ||
4057 | */ | ||
4058 | if (allocated > map->m_len) { | ||
4059 | clean_bdev_aliases(inode->i_sb->s_bdev, newblock + map->m_len, | ||
4060 | allocated - map->m_len); | ||
4061 | allocated = map->m_len; | 4055 | allocated = map->m_len; |
4062 | } | ||
4063 | map->m_len = allocated; | 4056 | map->m_len = allocated; |
4064 | 4057 | ||
4065 | map_out: | 4058 | map_out: |
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index e22dcfab308b..46b24da33a28 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c | |||
@@ -231,6 +231,7 @@ int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) | |||
231 | break; | 231 | break; |
232 | case DX_HASH_HALF_MD4_UNSIGNED: | 232 | case DX_HASH_HALF_MD4_UNSIGNED: |
233 | str2hashbuf = str2hashbuf_unsigned; | 233 | str2hashbuf = str2hashbuf_unsigned; |
234 | /* fall through */ | ||
234 | case DX_HASH_HALF_MD4: | 235 | case DX_HASH_HALF_MD4: |
235 | p = name; | 236 | p = name; |
236 | while (len > 0) { | 237 | while (len > 0) { |
@@ -244,6 +245,7 @@ int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) | |||
244 | break; | 245 | break; |
245 | case DX_HASH_TEA_UNSIGNED: | 246 | case DX_HASH_TEA_UNSIGNED: |
246 | str2hashbuf = str2hashbuf_unsigned; | 247 | str2hashbuf = str2hashbuf_unsigned; |
248 | /* fall through */ | ||
247 | case DX_HASH_TEA: | 249 | case DX_HASH_TEA: |
248 | p = name; | 250 | p = name; |
249 | while (len > 0) { | 251 | while (len > 0) { |
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index bf7fa1507e81..c2225f0d31b5 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c | |||
@@ -1183,18 +1183,21 @@ do_indirects: | |||
1183 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); | 1183 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); |
1184 | i_data[EXT4_IND_BLOCK] = 0; | 1184 | i_data[EXT4_IND_BLOCK] = 0; |
1185 | } | 1185 | } |
1186 | /* fall through */ | ||
1186 | case EXT4_IND_BLOCK: | 1187 | case EXT4_IND_BLOCK: |
1187 | nr = i_data[EXT4_DIND_BLOCK]; | 1188 | nr = i_data[EXT4_DIND_BLOCK]; |
1188 | if (nr) { | 1189 | if (nr) { |
1189 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); | 1190 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); |
1190 | i_data[EXT4_DIND_BLOCK] = 0; | 1191 | i_data[EXT4_DIND_BLOCK] = 0; |
1191 | } | 1192 | } |
1193 | /* fall through */ | ||
1192 | case EXT4_DIND_BLOCK: | 1194 | case EXT4_DIND_BLOCK: |
1193 | nr = i_data[EXT4_TIND_BLOCK]; | 1195 | nr = i_data[EXT4_TIND_BLOCK]; |
1194 | if (nr) { | 1196 | if (nr) { |
1195 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); | 1197 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); |
1196 | i_data[EXT4_TIND_BLOCK] = 0; | 1198 | i_data[EXT4_TIND_BLOCK] = 0; |
1197 | } | 1199 | } |
1200 | /* fall through */ | ||
1198 | case EXT4_TIND_BLOCK: | 1201 | case EXT4_TIND_BLOCK: |
1199 | ; | 1202 | ; |
1200 | } | 1203 | } |
@@ -1433,6 +1436,7 @@ do_indirects: | |||
1433 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); | 1436 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); |
1434 | i_data[EXT4_IND_BLOCK] = 0; | 1437 | i_data[EXT4_IND_BLOCK] = 0; |
1435 | } | 1438 | } |
1439 | /* fall through */ | ||
1436 | case EXT4_IND_BLOCK: | 1440 | case EXT4_IND_BLOCK: |
1437 | if (++n >= n2) | 1441 | if (++n >= n2) |
1438 | return 0; | 1442 | return 0; |
@@ -1441,6 +1445,7 @@ do_indirects: | |||
1441 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); | 1445 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); |
1442 | i_data[EXT4_DIND_BLOCK] = 0; | 1446 | i_data[EXT4_DIND_BLOCK] = 0; |
1443 | } | 1447 | } |
1448 | /* fall through */ | ||
1444 | case EXT4_DIND_BLOCK: | 1449 | case EXT4_DIND_BLOCK: |
1445 | if (++n >= n2) | 1450 | if (++n >= n2) |
1446 | return 0; | 1451 | return 0; |
@@ -1449,6 +1454,7 @@ do_indirects: | |||
1449 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); | 1454 | ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); |
1450 | i_data[EXT4_TIND_BLOCK] = 0; | 1455 | i_data[EXT4_TIND_BLOCK] = 0; |
1451 | } | 1456 | } |
1457 | /* fall through */ | ||
1452 | case EXT4_TIND_BLOCK: | 1458 | case EXT4_TIND_BLOCK: |
1453 | ; | 1459 | ; |
1454 | } | 1460 | } |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 4356ef6d728e..b54b261ded36 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -391,7 +391,7 @@ void ext4_da_update_reserve_space(struct inode *inode, | |||
391 | * inode's preallocations. | 391 | * inode's preallocations. |
392 | */ | 392 | */ |
393 | if ((ei->i_reserved_data_blocks == 0) && | 393 | if ((ei->i_reserved_data_blocks == 0) && |
394 | (atomic_read(&inode->i_writecount) == 0)) | 394 | !inode_is_open_for_write(inode)) |
395 | ext4_discard_preallocations(inode); | 395 | ext4_discard_preallocations(inode); |
396 | } | 396 | } |
397 | 397 | ||
@@ -678,8 +678,6 @@ found: | |||
678 | if (flags & EXT4_GET_BLOCKS_ZERO && | 678 | if (flags & EXT4_GET_BLOCKS_ZERO && |
679 | map->m_flags & EXT4_MAP_MAPPED && | 679 | map->m_flags & EXT4_MAP_MAPPED && |
680 | map->m_flags & EXT4_MAP_NEW) { | 680 | map->m_flags & EXT4_MAP_NEW) { |
681 | clean_bdev_aliases(inode->i_sb->s_bdev, map->m_pblk, | ||
682 | map->m_len); | ||
683 | ret = ext4_issue_zeroout(inode, map->m_lblk, | 681 | ret = ext4_issue_zeroout(inode, map->m_lblk, |
684 | map->m_pblk, map->m_len); | 682 | map->m_pblk, map->m_len); |
685 | if (ret) { | 683 | if (ret) { |
@@ -1194,7 +1192,6 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, | |||
1194 | if (err) | 1192 | if (err) |
1195 | break; | 1193 | break; |
1196 | if (buffer_new(bh)) { | 1194 | if (buffer_new(bh)) { |
1197 | clean_bdev_bh_alias(bh); | ||
1198 | if (PageUptodate(page)) { | 1195 | if (PageUptodate(page)) { |
1199 | clear_buffer_new(bh); | 1196 | clear_buffer_new(bh); |
1200 | set_buffer_uptodate(bh); | 1197 | set_buffer_uptodate(bh); |
@@ -2489,10 +2486,6 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) | |||
2489 | } | 2486 | } |
2490 | 2487 | ||
2491 | BUG_ON(map->m_len == 0); | 2488 | BUG_ON(map->m_len == 0); |
2492 | if (map->m_flags & EXT4_MAP_NEW) { | ||
2493 | clean_bdev_aliases(inode->i_sb->s_bdev, map->m_pblk, | ||
2494 | map->m_len); | ||
2495 | } | ||
2496 | return 0; | 2489 | return 0; |
2497 | } | 2490 | } |
2498 | 2491 | ||
@@ -2835,12 +2828,12 @@ retry: | |||
2835 | goto unplug; | 2828 | goto unplug; |
2836 | } | 2829 | } |
2837 | ret = mpage_prepare_extent_to_map(&mpd); | 2830 | ret = mpage_prepare_extent_to_map(&mpd); |
2831 | /* Unlock pages we didn't use */ | ||
2832 | mpage_release_unused_pages(&mpd, false); | ||
2838 | /* Submit prepared bio */ | 2833 | /* Submit prepared bio */ |
2839 | ext4_io_submit(&mpd.io_submit); | 2834 | ext4_io_submit(&mpd.io_submit); |
2840 | ext4_put_io_end_defer(mpd.io_submit.io_end); | 2835 | ext4_put_io_end_defer(mpd.io_submit.io_end); |
2841 | mpd.io_submit.io_end = NULL; | 2836 | mpd.io_submit.io_end = NULL; |
2842 | /* Unlock pages we didn't use */ | ||
2843 | mpage_release_unused_pages(&mpd, false); | ||
2844 | if (ret < 0) | 2837 | if (ret < 0) |
2845 | goto unplug; | 2838 | goto unplug; |
2846 | 2839 | ||
@@ -2908,10 +2901,11 @@ retry: | |||
2908 | handle = NULL; | 2901 | handle = NULL; |
2909 | mpd.do_map = 0; | 2902 | mpd.do_map = 0; |
2910 | } | 2903 | } |
2911 | /* Submit prepared bio */ | ||
2912 | ext4_io_submit(&mpd.io_submit); | ||
2913 | /* Unlock pages we didn't use */ | 2904 | /* Unlock pages we didn't use */ |
2914 | mpage_release_unused_pages(&mpd, give_up_on_write); | 2905 | mpage_release_unused_pages(&mpd, give_up_on_write); |
2906 | /* Submit prepared bio */ | ||
2907 | ext4_io_submit(&mpd.io_submit); | ||
2908 | |||
2915 | /* | 2909 | /* |
2916 | * Drop our io_end reference we got from init. We have | 2910 | * Drop our io_end reference we got from init. We have |
2917 | * to be careful and use deferred io_end finishing if | 2911 | * to be careful and use deferred io_end finishing if |
@@ -5349,7 +5343,6 @@ static int ext4_do_update_inode(handle_t *handle, | |||
5349 | err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); | 5343 | err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); |
5350 | if (err) | 5344 | if (err) |
5351 | goto out_brelse; | 5345 | goto out_brelse; |
5352 | ext4_update_dynamic_rev(sb); | ||
5353 | ext4_set_feature_large_file(sb); | 5346 | ext4_set_feature_large_file(sb); |
5354 | ext4_handle_sync(handle); | 5347 | ext4_handle_sync(handle); |
5355 | err = ext4_handle_dirty_super(handle, sb); | 5348 | err = ext4_handle_dirty_super(handle, sb); |
@@ -6000,7 +5993,7 @@ int ext4_expand_extra_isize(struct inode *inode, | |||
6000 | 5993 | ||
6001 | ext4_write_lock_xattr(inode, &no_expand); | 5994 | ext4_write_lock_xattr(inode, &no_expand); |
6002 | 5995 | ||
6003 | BUFFER_TRACE(iloc.bh, "get_write_access"); | 5996 | BUFFER_TRACE(iloc->bh, "get_write_access"); |
6004 | error = ext4_journal_get_write_access(handle, iloc->bh); | 5997 | error = ext4_journal_get_write_access(handle, iloc->bh); |
6005 | if (error) { | 5998 | if (error) { |
6006 | brelse(iloc->bh); | 5999 | brelse(iloc->bh); |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index d26bcac291bb..3c4f8bb59f8a 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -63,18 +63,20 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2) | |||
63 | loff_t isize; | 63 | loff_t isize; |
64 | struct ext4_inode_info *ei1; | 64 | struct ext4_inode_info *ei1; |
65 | struct ext4_inode_info *ei2; | 65 | struct ext4_inode_info *ei2; |
66 | unsigned long tmp; | ||
66 | 67 | ||
67 | ei1 = EXT4_I(inode1); | 68 | ei1 = EXT4_I(inode1); |
68 | ei2 = EXT4_I(inode2); | 69 | ei2 = EXT4_I(inode2); |
69 | 70 | ||
70 | swap(inode1->i_version, inode2->i_version); | 71 | swap(inode1->i_version, inode2->i_version); |
71 | swap(inode1->i_blocks, inode2->i_blocks); | ||
72 | swap(inode1->i_bytes, inode2->i_bytes); | ||
73 | swap(inode1->i_atime, inode2->i_atime); | 72 | swap(inode1->i_atime, inode2->i_atime); |
74 | swap(inode1->i_mtime, inode2->i_mtime); | 73 | swap(inode1->i_mtime, inode2->i_mtime); |
75 | 74 | ||
76 | memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data)); | 75 | memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data)); |
77 | swap(ei1->i_flags, ei2->i_flags); | 76 | tmp = ei1->i_flags & EXT4_FL_SHOULD_SWAP; |
77 | ei1->i_flags = (ei2->i_flags & EXT4_FL_SHOULD_SWAP) | | ||
78 | (ei1->i_flags & ~EXT4_FL_SHOULD_SWAP); | ||
79 | ei2->i_flags = tmp | (ei2->i_flags & ~EXT4_FL_SHOULD_SWAP); | ||
78 | swap(ei1->i_disksize, ei2->i_disksize); | 80 | swap(ei1->i_disksize, ei2->i_disksize); |
79 | ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS); | 81 | ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS); |
80 | ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS); | 82 | ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS); |
@@ -115,28 +117,42 @@ static long swap_inode_boot_loader(struct super_block *sb, | |||
115 | int err; | 117 | int err; |
116 | struct inode *inode_bl; | 118 | struct inode *inode_bl; |
117 | struct ext4_inode_info *ei_bl; | 119 | struct ext4_inode_info *ei_bl; |
118 | 120 | qsize_t size, size_bl, diff; | |
119 | if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode) || | 121 | blkcnt_t blocks; |
120 | IS_SWAPFILE(inode) || IS_ENCRYPTED(inode) || | 122 | unsigned short bytes; |
121 | ext4_has_inline_data(inode)) | ||
122 | return -EINVAL; | ||
123 | |||
124 | if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) || | ||
125 | !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) | ||
126 | return -EPERM; | ||
127 | 123 | ||
128 | inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL); | 124 | inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL); |
129 | if (IS_ERR(inode_bl)) | 125 | if (IS_ERR(inode_bl)) |
130 | return PTR_ERR(inode_bl); | 126 | return PTR_ERR(inode_bl); |
131 | ei_bl = EXT4_I(inode_bl); | 127 | ei_bl = EXT4_I(inode_bl); |
132 | 128 | ||
133 | filemap_flush(inode->i_mapping); | ||
134 | filemap_flush(inode_bl->i_mapping); | ||
135 | |||
136 | /* Protect orig inodes against a truncate and make sure, | 129 | /* Protect orig inodes against a truncate and make sure, |
137 | * that only 1 swap_inode_boot_loader is running. */ | 130 | * that only 1 swap_inode_boot_loader is running. */ |
138 | lock_two_nondirectories(inode, inode_bl); | 131 | lock_two_nondirectories(inode, inode_bl); |
139 | 132 | ||
133 | if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode) || | ||
134 | IS_SWAPFILE(inode) || IS_ENCRYPTED(inode) || | ||
135 | (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) || | ||
136 | ext4_has_inline_data(inode)) { | ||
137 | err = -EINVAL; | ||
138 | goto journal_err_out; | ||
139 | } | ||
140 | |||
141 | if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) || | ||
142 | !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) { | ||
143 | err = -EPERM; | ||
144 | goto journal_err_out; | ||
145 | } | ||
146 | |||
147 | down_write(&EXT4_I(inode)->i_mmap_sem); | ||
148 | err = filemap_write_and_wait(inode->i_mapping); | ||
149 | if (err) | ||
150 | goto err_out; | ||
151 | |||
152 | err = filemap_write_and_wait(inode_bl->i_mapping); | ||
153 | if (err) | ||
154 | goto err_out; | ||
155 | |||
140 | /* Wait for all existing dio workers */ | 156 | /* Wait for all existing dio workers */ |
141 | inode_dio_wait(inode); | 157 | inode_dio_wait(inode); |
142 | inode_dio_wait(inode_bl); | 158 | inode_dio_wait(inode_bl); |
@@ -147,7 +163,7 @@ static long swap_inode_boot_loader(struct super_block *sb, | |||
147 | handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); | 163 | handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); |
148 | if (IS_ERR(handle)) { | 164 | if (IS_ERR(handle)) { |
149 | err = -EINVAL; | 165 | err = -EINVAL; |
150 | goto journal_err_out; | 166 | goto err_out; |
151 | } | 167 | } |
152 | 168 | ||
153 | /* Protect extent tree against block allocations via delalloc */ | 169 | /* Protect extent tree against block allocations via delalloc */ |
@@ -170,6 +186,13 @@ static long swap_inode_boot_loader(struct super_block *sb, | |||
170 | memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data)); | 186 | memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data)); |
171 | } | 187 | } |
172 | 188 | ||
189 | err = dquot_initialize(inode); | ||
190 | if (err) | ||
191 | goto err_out1; | ||
192 | |||
193 | size = (qsize_t)(inode->i_blocks) * (1 << 9) + inode->i_bytes; | ||
194 | size_bl = (qsize_t)(inode_bl->i_blocks) * (1 << 9) + inode_bl->i_bytes; | ||
195 | diff = size - size_bl; | ||
173 | swap_inode_data(inode, inode_bl); | 196 | swap_inode_data(inode, inode_bl); |
174 | 197 | ||
175 | inode->i_ctime = inode_bl->i_ctime = current_time(inode); | 198 | inode->i_ctime = inode_bl->i_ctime = current_time(inode); |
@@ -183,27 +206,51 @@ static long swap_inode_boot_loader(struct super_block *sb, | |||
183 | 206 | ||
184 | err = ext4_mark_inode_dirty(handle, inode); | 207 | err = ext4_mark_inode_dirty(handle, inode); |
185 | if (err < 0) { | 208 | if (err < 0) { |
209 | /* No need to update quota information. */ | ||
186 | ext4_warning(inode->i_sb, | 210 | ext4_warning(inode->i_sb, |
187 | "couldn't mark inode #%lu dirty (err %d)", | 211 | "couldn't mark inode #%lu dirty (err %d)", |
188 | inode->i_ino, err); | 212 | inode->i_ino, err); |
189 | /* Revert all changes: */ | 213 | /* Revert all changes: */ |
190 | swap_inode_data(inode, inode_bl); | 214 | swap_inode_data(inode, inode_bl); |
191 | ext4_mark_inode_dirty(handle, inode); | 215 | ext4_mark_inode_dirty(handle, inode); |
192 | } else { | 216 | goto err_out1; |
193 | err = ext4_mark_inode_dirty(handle, inode_bl); | 217 | } |
194 | if (err < 0) { | 218 | |
195 | ext4_warning(inode_bl->i_sb, | 219 | blocks = inode_bl->i_blocks; |
196 | "couldn't mark inode #%lu dirty (err %d)", | 220 | bytes = inode_bl->i_bytes; |
197 | inode_bl->i_ino, err); | 221 | inode_bl->i_blocks = inode->i_blocks; |
198 | /* Revert all changes: */ | 222 | inode_bl->i_bytes = inode->i_bytes; |
199 | swap_inode_data(inode, inode_bl); | 223 | err = ext4_mark_inode_dirty(handle, inode_bl); |
200 | ext4_mark_inode_dirty(handle, inode); | 224 | if (err < 0) { |
201 | ext4_mark_inode_dirty(handle, inode_bl); | 225 | /* No need to update quota information. */ |
202 | } | 226 | ext4_warning(inode_bl->i_sb, |
227 | "couldn't mark inode #%lu dirty (err %d)", | ||
228 | inode_bl->i_ino, err); | ||
229 | goto revert; | ||
230 | } | ||
231 | |||
232 | /* Bootloader inode should not be counted into quota information. */ | ||
233 | if (diff > 0) | ||
234 | dquot_free_space(inode, diff); | ||
235 | else | ||
236 | err = dquot_alloc_space(inode, -1 * diff); | ||
237 | |||
238 | if (err < 0) { | ||
239 | revert: | ||
240 | /* Revert all changes: */ | ||
241 | inode_bl->i_blocks = blocks; | ||
242 | inode_bl->i_bytes = bytes; | ||
243 | swap_inode_data(inode, inode_bl); | ||
244 | ext4_mark_inode_dirty(handle, inode); | ||
245 | ext4_mark_inode_dirty(handle, inode_bl); | ||
203 | } | 246 | } |
247 | |||
248 | err_out1: | ||
204 | ext4_journal_stop(handle); | 249 | ext4_journal_stop(handle); |
205 | ext4_double_up_write_data_sem(inode, inode_bl); | 250 | ext4_double_up_write_data_sem(inode, inode_bl); |
206 | 251 | ||
252 | err_out: | ||
253 | up_write(&EXT4_I(inode)->i_mmap_sem); | ||
207 | journal_err_out: | 254 | journal_err_out: |
208 | unlock_two_nondirectories(inode, inode_bl); | 255 | unlock_two_nondirectories(inode, inode_bl); |
209 | iput(inode_bl); | 256 | iput(inode_bl); |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index e2248083cdca..6fb76d408093 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4176,9 +4176,8 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac) | |||
4176 | isize = (i_size_read(ac->ac_inode) + ac->ac_sb->s_blocksize - 1) | 4176 | isize = (i_size_read(ac->ac_inode) + ac->ac_sb->s_blocksize - 1) |
4177 | >> bsbits; | 4177 | >> bsbits; |
4178 | 4178 | ||
4179 | if ((size == isize) && | 4179 | if ((size == isize) && !ext4_fs_is_busy(sbi) && |
4180 | !ext4_fs_is_busy(sbi) && | 4180 | !inode_is_open_for_write(ac->ac_inode)) { |
4181 | (atomic_read(&ac->ac_inode->i_writecount) == 0)) { | ||
4182 | ac->ac_flags |= EXT4_MB_HINT_NOPREALLOC; | 4181 | ac->ac_flags |= EXT4_MB_HINT_NOPREALLOC; |
4183 | return; | 4182 | return; |
4184 | } | 4183 | } |
@@ -4258,7 +4257,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac, | |||
4258 | (unsigned) ar->goal, ac->ac_flags, ac->ac_2order, | 4257 | (unsigned) ar->goal, ac->ac_flags, ac->ac_2order, |
4259 | (unsigned) ar->lleft, (unsigned) ar->pleft, | 4258 | (unsigned) ar->lleft, (unsigned) ar->pleft, |
4260 | (unsigned) ar->lright, (unsigned) ar->pright, | 4259 | (unsigned) ar->lright, (unsigned) ar->pright, |
4261 | atomic_read(&ar->inode->i_writecount) ? "" : "non-"); | 4260 | inode_is_open_for_write(ar->inode) ? "" : "non-"); |
4262 | return 0; | 4261 | return 0; |
4263 | 4262 | ||
4264 | } | 4263 | } |
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 6f5305e9a6ac..3e9298e6a705 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
@@ -468,10 +468,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
468 | ext4_io_submit(io); | 468 | ext4_io_submit(io); |
469 | continue; | 469 | continue; |
470 | } | 470 | } |
471 | if (buffer_new(bh)) { | 471 | if (buffer_new(bh)) |
472 | clear_buffer_new(bh); | 472 | clear_buffer_new(bh); |
473 | clean_bdev_bh_alias(bh); | ||
474 | } | ||
475 | set_buffer_async_write(bh); | 473 | set_buffer_async_write(bh); |
476 | nr_to_submit++; | 474 | nr_to_submit++; |
477 | } while ((bh = bh->b_this_page) != head); | 475 | } while ((bh = bh->b_this_page) != head); |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 48421de803b7..3d9b18505c0c 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -1960,7 +1960,8 @@ retry: | |||
1960 | le16_to_cpu(es->s_reserved_gdt_blocks); | 1960 | le16_to_cpu(es->s_reserved_gdt_blocks); |
1961 | n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb); | 1961 | n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb); |
1962 | n_blocks_count = (ext4_fsblk_t)n_group * | 1962 | n_blocks_count = (ext4_fsblk_t)n_group * |
1963 | EXT4_BLOCKS_PER_GROUP(sb); | 1963 | EXT4_BLOCKS_PER_GROUP(sb) + |
1964 | le32_to_cpu(es->s_first_data_block); | ||
1964 | n_group--; /* set to last group number */ | 1965 | n_group--; /* set to last group number */ |
1965 | } | 1966 | } |
1966 | 1967 | ||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 60da0a6e4d86..f5b828bf1299 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -2249,7 +2249,6 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
2249 | es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); | 2249 | es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); |
2250 | le16_add_cpu(&es->s_mnt_count, 1); | 2250 | le16_add_cpu(&es->s_mnt_count, 1); |
2251 | ext4_update_tstamp(es, s_mtime); | 2251 | ext4_update_tstamp(es, s_mtime); |
2252 | ext4_update_dynamic_rev(sb); | ||
2253 | if (sbi->s_journal) | 2252 | if (sbi->s_journal) |
2254 | ext4_set_feature_journal_needs_recovery(sb); | 2253 | ext4_set_feature_journal_needs_recovery(sb); |
2255 | 2254 | ||
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c index 5e4e78fc0b3a..616c075da062 100644 --- a/fs/ext4/sysfs.c +++ b/fs/ext4/sysfs.c | |||
@@ -30,6 +30,7 @@ typedef enum { | |||
30 | attr_feature, | 30 | attr_feature, |
31 | attr_pointer_ui, | 31 | attr_pointer_ui, |
32 | attr_pointer_atomic, | 32 | attr_pointer_atomic, |
33 | attr_journal_task, | ||
33 | } attr_id_t; | 34 | } attr_id_t; |
34 | 35 | ||
35 | typedef enum { | 36 | typedef enum { |
@@ -125,6 +126,14 @@ static ssize_t trigger_test_error(struct ext4_sb_info *sbi, | |||
125 | return count; | 126 | return count; |
126 | } | 127 | } |
127 | 128 | ||
129 | static ssize_t journal_task_show(struct ext4_sb_info *sbi, char *buf) | ||
130 | { | ||
131 | if (!sbi->s_journal) | ||
132 | return snprintf(buf, PAGE_SIZE, "<none>\n"); | ||
133 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
134 | task_pid_vnr(sbi->s_journal->j_task)); | ||
135 | } | ||
136 | |||
128 | #define EXT4_ATTR(_name,_mode,_id) \ | 137 | #define EXT4_ATTR(_name,_mode,_id) \ |
129 | static struct ext4_attr ext4_attr_##_name = { \ | 138 | static struct ext4_attr ext4_attr_##_name = { \ |
130 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | 139 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
@@ -188,6 +197,7 @@ EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst); | |||
188 | EXT4_RO_ATTR_ES_UI(errors_count, s_error_count); | 197 | EXT4_RO_ATTR_ES_UI(errors_count, s_error_count); |
189 | EXT4_ATTR(first_error_time, 0444, first_error_time); | 198 | EXT4_ATTR(first_error_time, 0444, first_error_time); |
190 | EXT4_ATTR(last_error_time, 0444, last_error_time); | 199 | EXT4_ATTR(last_error_time, 0444, last_error_time); |
200 | EXT4_ATTR(journal_task, 0444, journal_task); | ||
191 | 201 | ||
192 | static unsigned int old_bump_val = 128; | 202 | static unsigned int old_bump_val = 128; |
193 | EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val); | 203 | EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val); |
@@ -217,6 +227,7 @@ static struct attribute *ext4_attrs[] = { | |||
217 | ATTR_LIST(errors_count), | 227 | ATTR_LIST(errors_count), |
218 | ATTR_LIST(first_error_time), | 228 | ATTR_LIST(first_error_time), |
219 | ATTR_LIST(last_error_time), | 229 | ATTR_LIST(last_error_time), |
230 | ATTR_LIST(journal_task), | ||
220 | NULL, | 231 | NULL, |
221 | }; | 232 | }; |
222 | 233 | ||
@@ -304,6 +315,8 @@ static ssize_t ext4_attr_show(struct kobject *kobj, | |||
304 | return print_tstamp(buf, sbi->s_es, s_first_error_time); | 315 | return print_tstamp(buf, sbi->s_es, s_first_error_time); |
305 | case attr_last_error_time: | 316 | case attr_last_error_time: |
306 | return print_tstamp(buf, sbi->s_es, s_last_error_time); | 317 | return print_tstamp(buf, sbi->s_es, s_last_error_time); |
318 | case attr_journal_task: | ||
319 | return journal_task_show(sbi, buf); | ||
307 | } | 320 | } |
308 | 321 | ||
309 | return 0; | 322 | return 0; |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 86ed9c686249..dc82e7757f67 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -829,6 +829,7 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage) | |||
829 | bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); | 829 | bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); |
830 | if (IS_ERR(bh)) { | 830 | if (IS_ERR(bh)) { |
831 | ret = PTR_ERR(bh); | 831 | ret = PTR_ERR(bh); |
832 | bh = NULL; | ||
832 | goto out; | 833 | goto out; |
833 | } | 834 | } |
834 | 835 | ||
@@ -2903,6 +2904,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, | |||
2903 | if (error == -EIO) | 2904 | if (error == -EIO) |
2904 | EXT4_ERROR_INODE(inode, "block %llu read error", | 2905 | EXT4_ERROR_INODE(inode, "block %llu read error", |
2905 | EXT4_I(inode)->i_file_acl); | 2906 | EXT4_I(inode)->i_file_acl); |
2907 | bh = NULL; | ||
2906 | goto cleanup; | 2908 | goto cleanup; |
2907 | } | 2909 | } |
2908 | error = ext4_xattr_check_block(inode, bh); | 2910 | error = ext4_xattr_check_block(inode, bh); |
@@ -3059,6 +3061,7 @@ ext4_xattr_block_cache_find(struct inode *inode, | |||
3059 | if (IS_ERR(bh)) { | 3061 | if (IS_ERR(bh)) { |
3060 | if (PTR_ERR(bh) == -ENOMEM) | 3062 | if (PTR_ERR(bh) == -ENOMEM) |
3061 | return NULL; | 3063 | return NULL; |
3064 | bh = NULL; | ||
3062 | EXT4_ERROR_INODE(inode, "block %lu read error", | 3065 | EXT4_ERROR_INODE(inode, "block %lu read error", |
3063 | (unsigned long)ce->e_value); | 3066 | (unsigned long)ce->e_value); |
3064 | } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { | 3067 | } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { |
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 26f8d7e46462..02e0b79753e7 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -113,7 +113,7 @@ void __jbd2_log_wait_for_space(journal_t *journal) | |||
113 | nblocks = jbd2_space_needed(journal); | 113 | nblocks = jbd2_space_needed(journal); |
114 | while (jbd2_log_space_left(journal) < nblocks) { | 114 | while (jbd2_log_space_left(journal) < nblocks) { |
115 | write_unlock(&journal->j_state_lock); | 115 | write_unlock(&journal->j_state_lock); |
116 | mutex_lock(&journal->j_checkpoint_mutex); | 116 | mutex_lock_io(&journal->j_checkpoint_mutex); |
117 | 117 | ||
118 | /* | 118 | /* |
119 | * Test again, another process may have checkpointed while we | 119 | * Test again, another process may have checkpointed while we |
@@ -276,9 +276,22 @@ restart: | |||
276 | "JBD2: %s: Waiting for Godot: block %llu\n", | 276 | "JBD2: %s: Waiting for Godot: block %llu\n", |
277 | journal->j_devname, (unsigned long long) bh->b_blocknr); | 277 | journal->j_devname, (unsigned long long) bh->b_blocknr); |
278 | 278 | ||
279 | if (batch_count) | ||
280 | __flush_batch(journal, &batch_count); | ||
279 | jbd2_log_start_commit(journal, tid); | 281 | jbd2_log_start_commit(journal, tid); |
282 | /* | ||
283 | * jbd2_journal_commit_transaction() may want | ||
284 | * to take the checkpoint_mutex if JBD2_FLUSHED | ||
285 | * is set, jbd2_update_log_tail() called by | ||
286 | * jbd2_journal_commit_transaction() may also take | ||
287 | * checkpoint_mutex. So we need to temporarily | ||
288 | * drop it. | ||
289 | */ | ||
290 | mutex_unlock(&journal->j_checkpoint_mutex); | ||
280 | jbd2_log_wait_commit(journal, tid); | 291 | jbd2_log_wait_commit(journal, tid); |
281 | goto retry; | 292 | mutex_lock_io(&journal->j_checkpoint_mutex); |
293 | spin_lock(&journal->j_list_lock); | ||
294 | goto restart; | ||
282 | } | 295 | } |
283 | if (!buffer_dirty(bh)) { | 296 | if (!buffer_dirty(bh)) { |
284 | if (unlikely(buffer_write_io_error(bh)) && !result) | 297 | if (unlikely(buffer_write_io_error(bh)) && !result) |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 2eb55c3361a8..efd0ce9489ae 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -694,9 +694,11 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
694 | the last tag we set up. */ | 694 | the last tag we set up. */ |
695 | 695 | ||
696 | tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); | 696 | tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); |
697 | |||
698 | jbd2_descriptor_block_csum_set(journal, descriptor); | ||
699 | start_journal_io: | 697 | start_journal_io: |
698 | if (descriptor) | ||
699 | jbd2_descriptor_block_csum_set(journal, | ||
700 | descriptor); | ||
701 | |||
700 | for (i = 0; i < bufs; i++) { | 702 | for (i = 0; i < bufs; i++) { |
701 | struct buffer_head *bh = wbuf[i]; | 703 | struct buffer_head *bh = wbuf[i]; |
702 | /* | 704 | /* |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 8ef6b6daaa7a..382c030cc78b 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -142,22 +142,6 @@ static __be32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb) | |||
142 | return cpu_to_be32(csum); | 142 | return cpu_to_be32(csum); |
143 | } | 143 | } |
144 | 144 | ||
145 | static int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb) | ||
146 | { | ||
147 | if (!jbd2_journal_has_csum_v2or3(j)) | ||
148 | return 1; | ||
149 | |||
150 | return sb->s_checksum == jbd2_superblock_csum(j, sb); | ||
151 | } | ||
152 | |||
153 | static void jbd2_superblock_csum_set(journal_t *j, journal_superblock_t *sb) | ||
154 | { | ||
155 | if (!jbd2_journal_has_csum_v2or3(j)) | ||
156 | return; | ||
157 | |||
158 | sb->s_checksum = jbd2_superblock_csum(j, sb); | ||
159 | } | ||
160 | |||
161 | /* | 145 | /* |
162 | * Helper function used to manage commit timeouts | 146 | * Helper function used to manage commit timeouts |
163 | */ | 147 | */ |
@@ -1356,6 +1340,10 @@ static int journal_reset(journal_t *journal) | |||
1356 | return jbd2_journal_start_thread(journal); | 1340 | return jbd2_journal_start_thread(journal); |
1357 | } | 1341 | } |
1358 | 1342 | ||
1343 | /* | ||
1344 | * This function expects that the caller will have locked the journal | ||
1345 | * buffer head, and will return with it unlocked | ||
1346 | */ | ||
1359 | static int jbd2_write_superblock(journal_t *journal, int write_flags) | 1347 | static int jbd2_write_superblock(journal_t *journal, int write_flags) |
1360 | { | 1348 | { |
1361 | struct buffer_head *bh = journal->j_sb_buffer; | 1349 | struct buffer_head *bh = journal->j_sb_buffer; |
@@ -1365,7 +1353,6 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags) | |||
1365 | trace_jbd2_write_superblock(journal, write_flags); | 1353 | trace_jbd2_write_superblock(journal, write_flags); |
1366 | if (!(journal->j_flags & JBD2_BARRIER)) | 1354 | if (!(journal->j_flags & JBD2_BARRIER)) |
1367 | write_flags &= ~(REQ_FUA | REQ_PREFLUSH); | 1355 | write_flags &= ~(REQ_FUA | REQ_PREFLUSH); |
1368 | lock_buffer(bh); | ||
1369 | if (buffer_write_io_error(bh)) { | 1356 | if (buffer_write_io_error(bh)) { |
1370 | /* | 1357 | /* |
1371 | * Oh, dear. A previous attempt to write the journal | 1358 | * Oh, dear. A previous attempt to write the journal |
@@ -1381,7 +1368,8 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags) | |||
1381 | clear_buffer_write_io_error(bh); | 1368 | clear_buffer_write_io_error(bh); |
1382 | set_buffer_uptodate(bh); | 1369 | set_buffer_uptodate(bh); |
1383 | } | 1370 | } |
1384 | jbd2_superblock_csum_set(journal, sb); | 1371 | if (jbd2_journal_has_csum_v2or3(journal)) |
1372 | sb->s_checksum = jbd2_superblock_csum(journal, sb); | ||
1385 | get_bh(bh); | 1373 | get_bh(bh); |
1386 | bh->b_end_io = end_buffer_write_sync; | 1374 | bh->b_end_io = end_buffer_write_sync; |
1387 | ret = submit_bh(REQ_OP_WRITE, write_flags, bh); | 1375 | ret = submit_bh(REQ_OP_WRITE, write_flags, bh); |
@@ -1424,6 +1412,7 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, | |||
1424 | jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n", | 1412 | jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n", |
1425 | tail_block, tail_tid); | 1413 | tail_block, tail_tid); |
1426 | 1414 | ||
1415 | lock_buffer(journal->j_sb_buffer); | ||
1427 | sb->s_sequence = cpu_to_be32(tail_tid); | 1416 | sb->s_sequence = cpu_to_be32(tail_tid); |
1428 | sb->s_start = cpu_to_be32(tail_block); | 1417 | sb->s_start = cpu_to_be32(tail_block); |
1429 | 1418 | ||
@@ -1454,18 +1443,17 @@ static void jbd2_mark_journal_empty(journal_t *journal, int write_op) | |||
1454 | journal_superblock_t *sb = journal->j_superblock; | 1443 | journal_superblock_t *sb = journal->j_superblock; |
1455 | 1444 | ||
1456 | BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); | 1445 | BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); |
1457 | read_lock(&journal->j_state_lock); | 1446 | lock_buffer(journal->j_sb_buffer); |
1458 | /* Is it already empty? */ | 1447 | if (sb->s_start == 0) { /* Is it already empty? */ |
1459 | if (sb->s_start == 0) { | 1448 | unlock_buffer(journal->j_sb_buffer); |
1460 | read_unlock(&journal->j_state_lock); | ||
1461 | return; | 1449 | return; |
1462 | } | 1450 | } |
1451 | |||
1463 | jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n", | 1452 | jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n", |
1464 | journal->j_tail_sequence); | 1453 | journal->j_tail_sequence); |
1465 | 1454 | ||
1466 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); | 1455 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); |
1467 | sb->s_start = cpu_to_be32(0); | 1456 | sb->s_start = cpu_to_be32(0); |
1468 | read_unlock(&journal->j_state_lock); | ||
1469 | 1457 | ||
1470 | jbd2_write_superblock(journal, write_op); | 1458 | jbd2_write_superblock(journal, write_op); |
1471 | 1459 | ||
@@ -1488,9 +1476,8 @@ void jbd2_journal_update_sb_errno(journal_t *journal) | |||
1488 | journal_superblock_t *sb = journal->j_superblock; | 1476 | journal_superblock_t *sb = journal->j_superblock; |
1489 | int errcode; | 1477 | int errcode; |
1490 | 1478 | ||
1491 | read_lock(&journal->j_state_lock); | 1479 | lock_buffer(journal->j_sb_buffer); |
1492 | errcode = journal->j_errno; | 1480 | errcode = journal->j_errno; |
1493 | read_unlock(&journal->j_state_lock); | ||
1494 | if (errcode == -ESHUTDOWN) | 1481 | if (errcode == -ESHUTDOWN) |
1495 | errcode = 0; | 1482 | errcode = 0; |
1496 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", errcode); | 1483 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", errcode); |
@@ -1595,17 +1582,18 @@ static int journal_get_superblock(journal_t *journal) | |||
1595 | } | 1582 | } |
1596 | } | 1583 | } |
1597 | 1584 | ||
1598 | /* Check superblock checksum */ | 1585 | if (jbd2_journal_has_csum_v2or3(journal)) { |
1599 | if (!jbd2_superblock_csum_verify(journal, sb)) { | 1586 | /* Check superblock checksum */ |
1600 | printk(KERN_ERR "JBD2: journal checksum error\n"); | 1587 | if (sb->s_checksum != jbd2_superblock_csum(journal, sb)) { |
1601 | err = -EFSBADCRC; | 1588 | printk(KERN_ERR "JBD2: journal checksum error\n"); |
1602 | goto out; | 1589 | err = -EFSBADCRC; |
1603 | } | 1590 | goto out; |
1591 | } | ||
1604 | 1592 | ||
1605 | /* Precompute checksum seed for all metadata */ | 1593 | /* Precompute checksum seed for all metadata */ |
1606 | if (jbd2_journal_has_csum_v2or3(journal)) | ||
1607 | journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, | 1594 | journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, |
1608 | sizeof(sb->s_uuid)); | 1595 | sizeof(sb->s_uuid)); |
1596 | } | ||
1609 | 1597 | ||
1610 | set_buffer_verified(bh); | 1598 | set_buffer_verified(bh); |
1611 | 1599 | ||
@@ -1894,28 +1882,27 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | |||
1894 | 1882 | ||
1895 | sb = journal->j_superblock; | 1883 | sb = journal->j_superblock; |
1896 | 1884 | ||
1885 | /* Load the checksum driver if necessary */ | ||
1886 | if ((journal->j_chksum_driver == NULL) && | ||
1887 | INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V3)) { | ||
1888 | journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); | ||
1889 | if (IS_ERR(journal->j_chksum_driver)) { | ||
1890 | printk(KERN_ERR "JBD2: Cannot load crc32c driver.\n"); | ||
1891 | journal->j_chksum_driver = NULL; | ||
1892 | return 0; | ||
1893 | } | ||
1894 | /* Precompute checksum seed for all metadata */ | ||
1895 | journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, | ||
1896 | sizeof(sb->s_uuid)); | ||
1897 | } | ||
1898 | |||
1899 | lock_buffer(journal->j_sb_buffer); | ||
1900 | |||
1897 | /* If enabling v3 checksums, update superblock */ | 1901 | /* If enabling v3 checksums, update superblock */ |
1898 | if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V3)) { | 1902 | if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V3)) { |
1899 | sb->s_checksum_type = JBD2_CRC32C_CHKSUM; | 1903 | sb->s_checksum_type = JBD2_CRC32C_CHKSUM; |
1900 | sb->s_feature_compat &= | 1904 | sb->s_feature_compat &= |
1901 | ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); | 1905 | ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); |
1902 | |||
1903 | /* Load the checksum driver */ | ||
1904 | if (journal->j_chksum_driver == NULL) { | ||
1905 | journal->j_chksum_driver = crypto_alloc_shash("crc32c", | ||
1906 | 0, 0); | ||
1907 | if (IS_ERR(journal->j_chksum_driver)) { | ||
1908 | printk(KERN_ERR "JBD2: Cannot load crc32c " | ||
1909 | "driver.\n"); | ||
1910 | journal->j_chksum_driver = NULL; | ||
1911 | return 0; | ||
1912 | } | ||
1913 | |||
1914 | /* Precompute checksum seed for all metadata */ | ||
1915 | journal->j_csum_seed = jbd2_chksum(journal, ~0, | ||
1916 | sb->s_uuid, | ||
1917 | sizeof(sb->s_uuid)); | ||
1918 | } | ||
1919 | } | 1906 | } |
1920 | 1907 | ||
1921 | /* If enabling v1 checksums, downgrade superblock */ | 1908 | /* If enabling v1 checksums, downgrade superblock */ |
@@ -1927,6 +1914,7 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | |||
1927 | sb->s_feature_compat |= cpu_to_be32(compat); | 1914 | sb->s_feature_compat |= cpu_to_be32(compat); |
1928 | sb->s_feature_ro_compat |= cpu_to_be32(ro); | 1915 | sb->s_feature_ro_compat |= cpu_to_be32(ro); |
1929 | sb->s_feature_incompat |= cpu_to_be32(incompat); | 1916 | sb->s_feature_incompat |= cpu_to_be32(incompat); |
1917 | unlock_buffer(journal->j_sb_buffer); | ||
1930 | 1918 | ||
1931 | return 1; | 1919 | return 1; |
1932 | #undef COMPAT_FEATURE_ON | 1920 | #undef COMPAT_FEATURE_ON |
@@ -2067,7 +2055,7 @@ int jbd2_journal_wipe(journal_t *journal, int write) | |||
2067 | err = jbd2_journal_skip_recovery(journal); | 2055 | err = jbd2_journal_skip_recovery(journal); |
2068 | if (write) { | 2056 | if (write) { |
2069 | /* Lock to make assertions happy... */ | 2057 | /* Lock to make assertions happy... */ |
2070 | mutex_lock(&journal->j_checkpoint_mutex); | 2058 | mutex_lock_io(&journal->j_checkpoint_mutex); |
2071 | jbd2_mark_journal_empty(journal, REQ_SYNC | REQ_FUA); | 2059 | jbd2_mark_journal_empty(journal, REQ_SYNC | REQ_FUA); |
2072 | mutex_unlock(&journal->j_checkpoint_mutex); | 2060 | mutex_unlock(&journal->j_checkpoint_mutex); |
2073 | } | 2061 | } |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index cc35537232f2..f940d31c2adc 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -63,7 +63,7 @@ void jbd2_journal_free_transaction(transaction_t *transaction) | |||
63 | /* | 63 | /* |
64 | * jbd2_get_transaction: obtain a new transaction_t object. | 64 | * jbd2_get_transaction: obtain a new transaction_t object. |
65 | * | 65 | * |
66 | * Simply allocate and initialise a new transaction. Create it in | 66 | * Simply initialise a new transaction. Initialize it in |
67 | * RUNNING state and add it to the current journal (which should not | 67 | * RUNNING state and add it to the current journal (which should not |
68 | * have an existing running transaction: we only make a new transaction | 68 | * have an existing running transaction: we only make a new transaction |
69 | * once we have started to commit the old one). | 69 | * once we have started to commit the old one). |
@@ -75,8 +75,8 @@ void jbd2_journal_free_transaction(transaction_t *transaction) | |||
75 | * | 75 | * |
76 | */ | 76 | */ |
77 | 77 | ||
78 | static transaction_t * | 78 | static void jbd2_get_transaction(journal_t *journal, |
79 | jbd2_get_transaction(journal_t *journal, transaction_t *transaction) | 79 | transaction_t *transaction) |
80 | { | 80 | { |
81 | transaction->t_journal = journal; | 81 | transaction->t_journal = journal; |
82 | transaction->t_state = T_RUNNING; | 82 | transaction->t_state = T_RUNNING; |
@@ -100,8 +100,6 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction) | |||
100 | transaction->t_max_wait = 0; | 100 | transaction->t_max_wait = 0; |
101 | transaction->t_start = jiffies; | 101 | transaction->t_start = jiffies; |
102 | transaction->t_requested = 0; | 102 | transaction->t_requested = 0; |
103 | |||
104 | return transaction; | ||
105 | } | 103 | } |
106 | 104 | ||
107 | /* | 105 | /* |
@@ -1252,11 +1250,12 @@ int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh) | |||
1252 | struct journal_head *jh; | 1250 | struct journal_head *jh; |
1253 | char *committed_data = NULL; | 1251 | char *committed_data = NULL; |
1254 | 1252 | ||
1255 | JBUFFER_TRACE(jh, "entry"); | ||
1256 | if (jbd2_write_access_granted(handle, bh, true)) | 1253 | if (jbd2_write_access_granted(handle, bh, true)) |
1257 | return 0; | 1254 | return 0; |
1258 | 1255 | ||
1259 | jh = jbd2_journal_add_journal_head(bh); | 1256 | jh = jbd2_journal_add_journal_head(bh); |
1257 | JBUFFER_TRACE(jh, "entry"); | ||
1258 | |||
1260 | /* | 1259 | /* |
1261 | * Do this first --- it can drop the journal lock, so we want to | 1260 | * Do this first --- it can drop the journal lock, so we want to |
1262 | * make sure that obtaining the committed_data is done | 1261 | * make sure that obtaining the committed_data is done |
@@ -1367,15 +1366,17 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | |||
1367 | 1366 | ||
1368 | if (is_handle_aborted(handle)) | 1367 | if (is_handle_aborted(handle)) |
1369 | return -EROFS; | 1368 | return -EROFS; |
1370 | if (!buffer_jbd(bh)) { | 1369 | if (!buffer_jbd(bh)) |
1371 | ret = -EUCLEAN; | 1370 | return -EUCLEAN; |
1372 | goto out; | 1371 | |
1373 | } | ||
1374 | /* | 1372 | /* |
1375 | * We don't grab jh reference here since the buffer must be part | 1373 | * We don't grab jh reference here since the buffer must be part |
1376 | * of the running transaction. | 1374 | * of the running transaction. |
1377 | */ | 1375 | */ |
1378 | jh = bh2jh(bh); | 1376 | jh = bh2jh(bh); |
1377 | jbd_debug(5, "journal_head %p\n", jh); | ||
1378 | JBUFFER_TRACE(jh, "entry"); | ||
1379 | |||
1379 | /* | 1380 | /* |
1380 | * This and the following assertions are unreliable since we may see jh | 1381 | * This and the following assertions are unreliable since we may see jh |
1381 | * in inconsistent state unless we grab bh_state lock. But this is | 1382 | * in inconsistent state unless we grab bh_state lock. But this is |
@@ -1409,9 +1410,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | |||
1409 | } | 1410 | } |
1410 | 1411 | ||
1411 | journal = transaction->t_journal; | 1412 | journal = transaction->t_journal; |
1412 | jbd_debug(5, "journal_head %p\n", jh); | ||
1413 | JBUFFER_TRACE(jh, "entry"); | ||
1414 | |||
1415 | jbd_lock_bh_state(bh); | 1413 | jbd_lock_bh_state(bh); |
1416 | 1414 | ||
1417 | if (jh->b_modified == 0) { | 1415 | if (jh->b_modified == 0) { |
@@ -1597,9 +1595,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) | |||
1597 | __jbd2_journal_unfile_buffer(jh); | 1595 | __jbd2_journal_unfile_buffer(jh); |
1598 | if (!buffer_jbd(bh)) { | 1596 | if (!buffer_jbd(bh)) { |
1599 | spin_unlock(&journal->j_list_lock); | 1597 | spin_unlock(&journal->j_list_lock); |
1600 | jbd_unlock_bh_state(bh); | 1598 | goto not_jbd; |
1601 | __bforget(bh); | ||
1602 | goto drop; | ||
1603 | } | 1599 | } |
1604 | } | 1600 | } |
1605 | spin_unlock(&journal->j_list_lock); | 1601 | spin_unlock(&journal->j_list_lock); |
@@ -1609,14 +1605,21 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) | |||
1609 | /* However, if the buffer is still owned by a prior | 1605 | /* However, if the buffer is still owned by a prior |
1610 | * (committing) transaction, we can't drop it yet... */ | 1606 | * (committing) transaction, we can't drop it yet... */ |
1611 | JBUFFER_TRACE(jh, "belongs to older transaction"); | 1607 | JBUFFER_TRACE(jh, "belongs to older transaction"); |
1612 | /* ... but we CAN drop it from the new transaction if we | 1608 | /* ... but we CAN drop it from the new transaction through |
1613 | * have also modified it since the original commit. */ | 1609 | * marking the buffer as freed and set j_next_transaction to |
1610 | * the new transaction, so that not only the commit code | ||
1611 | * knows it should clear dirty bits when it is done with the | ||
1612 | * buffer, but also the buffer can be checkpointed only | ||
1613 | * after the new transaction commits. */ | ||
1614 | 1614 | ||
1615 | if (jh->b_next_transaction) { | 1615 | set_buffer_freed(bh); |
1616 | J_ASSERT(jh->b_next_transaction == transaction); | 1616 | |
1617 | if (!jh->b_next_transaction) { | ||
1617 | spin_lock(&journal->j_list_lock); | 1618 | spin_lock(&journal->j_list_lock); |
1618 | jh->b_next_transaction = NULL; | 1619 | jh->b_next_transaction = transaction; |
1619 | spin_unlock(&journal->j_list_lock); | 1620 | spin_unlock(&journal->j_list_lock); |
1621 | } else { | ||
1622 | J_ASSERT(jh->b_next_transaction == transaction); | ||
1620 | 1623 | ||
1621 | /* | 1624 | /* |
1622 | * only drop a reference if this transaction modified | 1625 | * only drop a reference if this transaction modified |
@@ -1625,9 +1628,40 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) | |||
1625 | if (was_modified) | 1628 | if (was_modified) |
1626 | drop_reserve = 1; | 1629 | drop_reserve = 1; |
1627 | } | 1630 | } |
1631 | } else { | ||
1632 | /* | ||
1633 | * Finally, if the buffer is not belongs to any | ||
1634 | * transaction, we can just drop it now if it has no | ||
1635 | * checkpoint. | ||
1636 | */ | ||
1637 | spin_lock(&journal->j_list_lock); | ||
1638 | if (!jh->b_cp_transaction) { | ||
1639 | JBUFFER_TRACE(jh, "belongs to none transaction"); | ||
1640 | spin_unlock(&journal->j_list_lock); | ||
1641 | goto not_jbd; | ||
1642 | } | ||
1643 | |||
1644 | /* | ||
1645 | * Otherwise, if the buffer has been written to disk, | ||
1646 | * it is safe to remove the checkpoint and drop it. | ||
1647 | */ | ||
1648 | if (!buffer_dirty(bh)) { | ||
1649 | __jbd2_journal_remove_checkpoint(jh); | ||
1650 | spin_unlock(&journal->j_list_lock); | ||
1651 | goto not_jbd; | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1655 | * The buffer is still not written to disk, we should | ||
1656 | * attach this buffer to current transaction so that the | ||
1657 | * buffer can be checkpointed only after the current | ||
1658 | * transaction commits. | ||
1659 | */ | ||
1660 | clear_buffer_dirty(bh); | ||
1661 | __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); | ||
1662 | spin_unlock(&journal->j_list_lock); | ||
1628 | } | 1663 | } |
1629 | 1664 | ||
1630 | not_jbd: | ||
1631 | jbd_unlock_bh_state(bh); | 1665 | jbd_unlock_bh_state(bh); |
1632 | __brelse(bh); | 1666 | __brelse(bh); |
1633 | drop: | 1667 | drop: |
@@ -1636,6 +1670,11 @@ drop: | |||
1636 | handle->h_buffer_credits++; | 1670 | handle->h_buffer_credits++; |
1637 | } | 1671 | } |
1638 | return err; | 1672 | return err; |
1673 | |||
1674 | not_jbd: | ||
1675 | jbd_unlock_bh_state(bh); | ||
1676 | __bforget(bh); | ||
1677 | goto drop; | ||
1639 | } | 1678 | } |
1640 | 1679 | ||
1641 | /** | 1680 | /** |