diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-16 12:38:14 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-16 12:38:14 -0500 |
| commit | e6a2562fe27f0a42243ca5a0aec5408c9a1d42a5 (patch) | |
| tree | 6c043311ed655b1bc1b029a1c0c3425ef831ae4f | |
| parent | 32e2524a529c1fd8e377738d6cdc2268ffd171ce (diff) | |
| parent | c26b5aa8ef0d46035060fded475e6ab957b9f69f (diff) | |
Merge tag 'gfs2-4.20.fixes3' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2
Pull bfs2 fixes from Andreas Gruenbacher:
"Fix two bugs leading to leaked buffer head references:
- gfs2: Put bitmap buffers in put_super
- gfs2: Fix iomap buffer head reference counting bug
And one bug leading to significant slow-downs when deleting large
files:
- gfs2: Fix metadata read-ahead during truncate (2)"
* tag 'gfs2-4.20.fixes3' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
gfs2: Fix iomap buffer head reference counting bug
gfs2: Fix metadata read-ahead during truncate (2)
gfs2: Put bitmap buffers in put_super
| -rw-r--r-- | fs/gfs2/bmap.c | 54 | ||||
| -rw-r--r-- | fs/gfs2/rgrp.c | 3 |
2 files changed, 29 insertions, 28 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index a683d9b27d76..9a4a15d646eb 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
| @@ -826,7 +826,7 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, | |||
| 826 | ret = gfs2_meta_inode_buffer(ip, &dibh); | 826 | ret = gfs2_meta_inode_buffer(ip, &dibh); |
| 827 | if (ret) | 827 | if (ret) |
| 828 | goto unlock; | 828 | goto unlock; |
| 829 | iomap->private = dibh; | 829 | mp->mp_bh[0] = dibh; |
| 830 | 830 | ||
| 831 | if (gfs2_is_stuffed(ip)) { | 831 | if (gfs2_is_stuffed(ip)) { |
| 832 | if (flags & IOMAP_WRITE) { | 832 | if (flags & IOMAP_WRITE) { |
| @@ -863,9 +863,6 @@ unstuff: | |||
| 863 | len = lblock_stop - lblock + 1; | 863 | len = lblock_stop - lblock + 1; |
| 864 | iomap->length = len << inode->i_blkbits; | 864 | iomap->length = len << inode->i_blkbits; |
| 865 | 865 | ||
| 866 | get_bh(dibh); | ||
| 867 | mp->mp_bh[0] = dibh; | ||
| 868 | |||
| 869 | height = ip->i_height; | 866 | height = ip->i_height; |
| 870 | while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height]) | 867 | while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height]) |
| 871 | height++; | 868 | height++; |
| @@ -898,8 +895,6 @@ out: | |||
| 898 | iomap->bdev = inode->i_sb->s_bdev; | 895 | iomap->bdev = inode->i_sb->s_bdev; |
| 899 | unlock: | 896 | unlock: |
| 900 | up_read(&ip->i_rw_mutex); | 897 | up_read(&ip->i_rw_mutex); |
| 901 | if (ret && dibh) | ||
| 902 | brelse(dibh); | ||
| 903 | return ret; | 898 | return ret; |
| 904 | 899 | ||
| 905 | do_alloc: | 900 | do_alloc: |
| @@ -980,9 +975,9 @@ static void gfs2_iomap_journaled_page_done(struct inode *inode, loff_t pos, | |||
| 980 | 975 | ||
| 981 | static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, | 976 | static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, |
| 982 | loff_t length, unsigned flags, | 977 | loff_t length, unsigned flags, |
| 983 | struct iomap *iomap) | 978 | struct iomap *iomap, |
| 979 | struct metapath *mp) | ||
| 984 | { | 980 | { |
| 985 | struct metapath mp = { .mp_aheight = 1, }; | ||
| 986 | struct gfs2_inode *ip = GFS2_I(inode); | 981 | struct gfs2_inode *ip = GFS2_I(inode); |
| 987 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 982 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
| 988 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; | 983 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; |
| @@ -996,9 +991,9 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, | |||
| 996 | unstuff = gfs2_is_stuffed(ip) && | 991 | unstuff = gfs2_is_stuffed(ip) && |
| 997 | pos + length > gfs2_max_stuffed_size(ip); | 992 | pos + length > gfs2_max_stuffed_size(ip); |
| 998 | 993 | ||
| 999 | ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); | 994 | ret = gfs2_iomap_get(inode, pos, length, flags, iomap, mp); |
| 1000 | if (ret) | 995 | if (ret) |
| 1001 | goto out_release; | 996 | goto out_unlock; |
| 1002 | 997 | ||
| 1003 | alloc_required = unstuff || iomap->type == IOMAP_HOLE; | 998 | alloc_required = unstuff || iomap->type == IOMAP_HOLE; |
| 1004 | 999 | ||
| @@ -1013,7 +1008,7 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, | |||
| 1013 | 1008 | ||
| 1014 | ret = gfs2_quota_lock_check(ip, &ap); | 1009 | ret = gfs2_quota_lock_check(ip, &ap); |
| 1015 | if (ret) | 1010 | if (ret) |
| 1016 | goto out_release; | 1011 | goto out_unlock; |
| 1017 | 1012 | ||
| 1018 | ret = gfs2_inplace_reserve(ip, &ap); | 1013 | ret = gfs2_inplace_reserve(ip, &ap); |
| 1019 | if (ret) | 1014 | if (ret) |
| @@ -1038,17 +1033,15 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, | |||
| 1038 | ret = gfs2_unstuff_dinode(ip, NULL); | 1033 | ret = gfs2_unstuff_dinode(ip, NULL); |
| 1039 | if (ret) | 1034 | if (ret) |
| 1040 | goto out_trans_end; | 1035 | goto out_trans_end; |
| 1041 | release_metapath(&mp); | 1036 | release_metapath(mp); |
| 1042 | brelse(iomap->private); | ||
| 1043 | iomap->private = NULL; | ||
| 1044 | ret = gfs2_iomap_get(inode, iomap->offset, iomap->length, | 1037 | ret = gfs2_iomap_get(inode, iomap->offset, iomap->length, |
| 1045 | flags, iomap, &mp); | 1038 | flags, iomap, mp); |
| 1046 | if (ret) | 1039 | if (ret) |
| 1047 | goto out_trans_end; | 1040 | goto out_trans_end; |
| 1048 | } | 1041 | } |
| 1049 | 1042 | ||
| 1050 | if (iomap->type == IOMAP_HOLE) { | 1043 | if (iomap->type == IOMAP_HOLE) { |
| 1051 | ret = gfs2_iomap_alloc(inode, iomap, flags, &mp); | 1044 | ret = gfs2_iomap_alloc(inode, iomap, flags, mp); |
| 1052 | if (ret) { | 1045 | if (ret) { |
| 1053 | gfs2_trans_end(sdp); | 1046 | gfs2_trans_end(sdp); |
| 1054 | gfs2_inplace_release(ip); | 1047 | gfs2_inplace_release(ip); |
| @@ -1056,7 +1049,6 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, | |||
| 1056 | goto out_qunlock; | 1049 | goto out_qunlock; |
| 1057 | } | 1050 | } |
| 1058 | } | 1051 | } |
| 1059 | release_metapath(&mp); | ||
| 1060 | if (!gfs2_is_stuffed(ip) && gfs2_is_jdata(ip)) | 1052 | if (!gfs2_is_stuffed(ip) && gfs2_is_jdata(ip)) |
| 1061 | iomap->page_done = gfs2_iomap_journaled_page_done; | 1053 | iomap->page_done = gfs2_iomap_journaled_page_done; |
| 1062 | return 0; | 1054 | return 0; |
| @@ -1069,10 +1061,7 @@ out_trans_fail: | |||
| 1069 | out_qunlock: | 1061 | out_qunlock: |
| 1070 | if (alloc_required) | 1062 | if (alloc_required) |
| 1071 | gfs2_quota_unlock(ip); | 1063 | gfs2_quota_unlock(ip); |
| 1072 | out_release: | 1064 | out_unlock: |
| 1073 | if (iomap->private) | ||
| 1074 | brelse(iomap->private); | ||
| 1075 | release_metapath(&mp); | ||
| 1076 | gfs2_write_unlock(inode); | 1065 | gfs2_write_unlock(inode); |
| 1077 | return ret; | 1066 | return ret; |
| 1078 | } | 1067 | } |
| @@ -1088,10 +1077,10 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, | |||
| 1088 | 1077 | ||
| 1089 | trace_gfs2_iomap_start(ip, pos, length, flags); | 1078 | trace_gfs2_iomap_start(ip, pos, length, flags); |
| 1090 | if ((flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)) { | 1079 | if ((flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)) { |
| 1091 | ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap); | 1080 | ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); |
| 1092 | } else { | 1081 | } else { |
| 1093 | ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); | 1082 | ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); |
| 1094 | release_metapath(&mp); | 1083 | |
| 1095 | /* | 1084 | /* |
| 1096 | * Silently fall back to buffered I/O for stuffed files or if | 1085 | * Silently fall back to buffered I/O for stuffed files or if |
| 1097 | * we've hot a hole (see gfs2_file_direct_write). | 1086 | * we've hot a hole (see gfs2_file_direct_write). |
| @@ -1100,6 +1089,11 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, | |||
| 1100 | iomap->type != IOMAP_MAPPED) | 1089 | iomap->type != IOMAP_MAPPED) |
| 1101 | ret = -ENOTBLK; | 1090 | ret = -ENOTBLK; |
| 1102 | } | 1091 | } |
| 1092 | if (!ret) { | ||
| 1093 | get_bh(mp.mp_bh[0]); | ||
| 1094 | iomap->private = mp.mp_bh[0]; | ||
| 1095 | } | ||
| 1096 | release_metapath(&mp); | ||
| 1103 | trace_gfs2_iomap_end(ip, iomap, ret); | 1097 | trace_gfs2_iomap_end(ip, iomap, ret); |
| 1104 | return ret; | 1098 | return ret; |
| 1105 | } | 1099 | } |
| @@ -1908,10 +1902,16 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length) | |||
| 1908 | if (ret < 0) | 1902 | if (ret < 0) |
| 1909 | goto out; | 1903 | goto out; |
| 1910 | 1904 | ||
| 1911 | /* issue read-ahead on metadata */ | 1905 | /* On the first pass, issue read-ahead on metadata. */ |
| 1912 | if (mp.mp_aheight > 1) { | 1906 | if (mp.mp_aheight > 1 && strip_h == ip->i_height - 1) { |
| 1913 | for (; ret > 1; ret--) { | 1907 | unsigned int height = mp.mp_aheight - 1; |
| 1914 | metapointer_range(&mp, mp.mp_aheight - ret, | 1908 | |
| 1909 | /* No read-ahead for data blocks. */ | ||
| 1910 | if (mp.mp_aheight - 1 == strip_h) | ||
| 1911 | height--; | ||
| 1912 | |||
| 1913 | for (; height >= mp.mp_aheight - ret; height--) { | ||
| 1914 | metapointer_range(&mp, height, | ||
| 1915 | start_list, start_aligned, | 1915 | start_list, start_aligned, |
| 1916 | end_list, end_aligned, | 1916 | end_list, end_aligned, |
| 1917 | &start, &end); | 1917 | &start, &end); |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index ffe3032b1043..b08a530433ad 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
| @@ -733,6 +733,7 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) | |||
| 733 | 733 | ||
| 734 | if (gl) { | 734 | if (gl) { |
| 735 | glock_clear_object(gl, rgd); | 735 | glock_clear_object(gl, rgd); |
| 736 | gfs2_rgrp_brelse(rgd); | ||
| 736 | gfs2_glock_put(gl); | 737 | gfs2_glock_put(gl); |
| 737 | } | 738 | } |
| 738 | 739 | ||
| @@ -1174,7 +1175,7 @@ static u32 count_unlinked(struct gfs2_rgrpd *rgd) | |||
| 1174 | * @rgd: the struct gfs2_rgrpd describing the RG to read in | 1175 | * @rgd: the struct gfs2_rgrpd describing the RG to read in |
| 1175 | * | 1176 | * |
| 1176 | * Read in all of a Resource Group's header and bitmap blocks. | 1177 | * Read in all of a Resource Group's header and bitmap blocks. |
| 1177 | * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps. | 1178 | * Caller must eventually call gfs2_rgrp_brelse() to free the bitmaps. |
| 1178 | * | 1179 | * |
| 1179 | * Returns: errno | 1180 | * Returns: errno |
| 1180 | */ | 1181 | */ |
