FAILED: patch "[PATCH] gfs2: Fix iomap buffer head reference counting bug" failed to apply to 4.19-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.19-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
c26b5aa8ef0d46035060fded475e6ab957b9f69fMon Sep 17 00:00:00 2001
From: Andreas Gruenbacher <[email protected]>
Date: Sun, 11 Nov 2018 11:15:21 +0000
Subject: [PATCH] gfs2: Fix iomap buffer head reference counting bug
GFS2 passes the inode buffer head (dibh) from gfs2_iomap_begin to gfs2_iomap_end in iomap->private. It sets that private pointer in gfs2_iomap_get. Users of gfs2_iomap_get other than gfs2_iomap_begin would have to release iomap->private, but this isn't done correctly, leading to a leak of buffer head references.
To fix this, move the code for setting iomap->private from gfs2_iomap_get to gfs2_iomap_begin.
fs/gfs2/bmap.c +17 -23
@@ -826,7 +826,7 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, ret =gfs2_meta_inode_buffer (ip, &dibh);if (ret) goto unlock; - iomap->private = dibh; + mp->mp_bh[0 ] = dibh;if (gfs2_is_stuffed (ip)) {if (flags &IOMAP_WRITE ) {
@@ -863,9 +863,6 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, len = lblock_stop - lblock +1 ; iomap->length = len << inode->i_blkbits; -get_bh (dibh); - mp->mp_bh[0 ] = dibh; - height = ip->i_height;while ((lblock +1 ) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height]) height++;
@@ -898,8 +895,6 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, iomap->bdev = inode->i_sb->s_bdev; unlock:up_read (&ip->i_rw_mutex); -if (ret && dibh) -brelse (dibh);return ret; do_alloc:
@@ -980,9 +975,9 @@ static void gfs2_iomap_journaled_page_done(struct inode *inode, loff_t pos,static int gfs2_iomap_begin_write (struct inode *inode,loff_t pos,loff_t length,unsigned flags, -struct iomap *iomap) +struct iomap *iomap, +struct metapath *mp) { -struct metapath mp = { .mp_aheight =1 , };struct gfs2_inode *ip =GFS2_I (inode);struct gfs2_sbd *sdp =GFS2_SB (inode);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, unstuff =gfs2_is_stuffed (ip) && pos + length >gfs2_max_stuffed_size (ip); - ret =gfs2_iomap_get (inode, pos, length, flags, iomap, &mp); + ret =gfs2_iomap_get (inode, pos, length, flags, iomap, mp);if (ret) - goto out_release; + goto out_unlock; alloc_required = unstuff || iomap->type ==IOMAP_HOLE ;
@@ -1013,7 +1008,7 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, ret =gfs2_quota_lock_check (ip, &ap);if (ret) - goto out_release; + goto out_unlock; ret =gfs2_inplace_reserve (ip, &ap);if (ret)
@@ -1038,17 +1033,15 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, ret =gfs2_unstuff_dinode (ip,NULL );if (ret) goto out_trans_end; -release_metapath (&mp); -brelse (iomap->private); - iomap->private =NULL ; +release_metapath (mp); ret =gfs2_iomap_get (inode, iomap->offset, iomap->length, - flags, iomap, &mp); + flags, iomap, mp);if (ret) goto out_trans_end; }if (iomap->type ==IOMAP_HOLE ) { - ret =gfs2_iomap_alloc (inode, iomap, flags, &mp); + ret =gfs2_iomap_alloc (inode, iomap, flags, mp);if (ret) {gfs2_trans_end (sdp);gfs2_inplace_release (ip);
@@ -1056,7 +1049,6 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, goto out_qunlock; } } -release_metapath (&mp);if (gfs2_is_jdata (ip)) iomap->page_done = gfs2_iomap_journaled_page_done;return 0 ;
@@ -1069,10 +1061,7 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, out_qunlock:if (alloc_required)gfs2_quota_unlock (ip); -out_release: -if (iomap->private) -brelse (iomap->private); -release_metapath (&mp); +out_unlock:gfs2_write_unlock (inode);return ret; }
@@ -1088,10 +1077,10 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,trace_gfs2_iomap_start (ip, pos, length, flags);if ((flags &IOMAP_WRITE ) && !(flags &IOMAP_DIRECT )) { - ret =gfs2_iomap_begin_write (inode, pos, length, flags, iomap); + ret =gfs2_iomap_begin_write (inode, pos, length, flags, iomap, &mp); }else { ret =gfs2_iomap_get (inode, pos, length, flags, iomap, &mp); -release_metapath (&mp); +/* * Silently fall back to buffered I/O for stuffed files or if * 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, iomap->type != IOMAP_MAPPED) ret = -ENOTBLK ; } +if (!ret) { +get_bh (mp.mp_bh[0 ]); + iomap->private = mp.mp_bh[0 ]; + } +release_metapath (&mp);trace_gfs2_iomap_end (ip, iomap, ret);return ret; }