Hi, Now in the -nmw git tree. Thanks,
Steve. On Thu, 2009-06-25 at 15:09 -0500, Benjamin Marzinski wrote: > GFS2 wasn't syncing its statfs info on grows. This causes a problem > when you grow the filesystem on multiple nodes. GFS2 would calculate > the new space based on the resource groups (which are always current), > and then assume that the filesystem had grown the from the existing > statfs size. If you grew the filesystem on two different nodes in a > short time, the second node wouldn't see the statfs size change from the > first node, and would assume that it was grown by a larger amount than > it was. When all these changes were synced out, the total fileystem > size would be incorrect (the first grow would be counted twice). > > This patch syncs makes GFS2 read in the statfs changes from disk before > a grow, and write them out after the grow, while the master statfs inode > is locked. > > Signed-off-by: Benjamin Marzinski <[email protected]> > --- > fs/gfs2/aops.c | 39 +++++++++++++++++++++++++++++++++++++++ > fs/gfs2/super.c | 39 +++++++++++++++++++++++++-------------- > fs/gfs2/super.h | 4 ++++ > 3 files changed, 68 insertions(+), 14 deletions(-) > > Index: kernel-upstream/fs/gfs2/aops.c > =================================================================== > --- kernel-upstream.orig/fs/gfs2/aops.c > +++ kernel-upstream/fs/gfs2/aops.c > @@ -624,6 +624,7 @@ static int gfs2_write_begin(struct file > { > struct gfs2_inode *ip = GFS2_I(mapping->host); > struct gfs2_sbd *sdp = GFS2_SB(mapping->host); > + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); > unsigned int data_blocks = 0, ind_blocks = 0, rblocks; > int alloc_required; > int error = 0; > @@ -637,6 +638,14 @@ static int gfs2_write_begin(struct file > error = gfs2_glock_nq(&ip->i_gh); > if (unlikely(error)) > goto out_uninit; > + if (&ip->i_inode == sdp->sd_rindex) { > + error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, > + GL_NOCACHE, &m_ip->i_gh); > + if (unlikely(error)) { > + gfs2_glock_dq(&ip->i_gh); > + goto out_uninit; > + } > + } > > error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); > if (error) > @@ -667,6 +676,8 @@ static int gfs2_write_begin(struct file > rblocks += data_blocks ? data_blocks : 1; > if (ind_blocks || data_blocks) > rblocks += RES_STATFS + RES_QUOTA; > + if (&ip->i_inode == sdp->sd_rindex) > + rblocks += 2 * RES_STATFS; > > error = gfs2_trans_begin(sdp, rblocks, > PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); > @@ -712,6 +723,10 @@ out_alloc_put: > gfs2_alloc_put(ip); > } > out_unlock: > + if (&ip->i_inode == sdp->sd_rindex) { > + gfs2_glock_dq(&m_ip->i_gh); > + gfs2_holder_uninit(&m_ip->i_gh); > + } > gfs2_glock_dq(&ip->i_gh); > out_uninit: > gfs2_holder_uninit(&ip->i_gh); > @@ -725,14 +740,21 @@ out_uninit: > static void adjust_fs_space(struct inode *inode) > { > struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; > + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); > + struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); > struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; > struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; > + struct buffer_head *m_bh, *l_bh; > u64 fs_total, new_free; > > /* Total up the file system space, according to the latest rindex. */ > fs_total = gfs2_ri_total(sdp); > + if (gfs2_meta_inode_buffer(m_ip, &m_bh) != 0) > + return; > > spin_lock(&sdp->sd_statfs_spin); > + gfs2_statfs_change_in(m_sc, m_bh->b_data + > + sizeof(struct gfs2_dinode)); > if (fs_total > (m_sc->sc_total + l_sc->sc_total)) > new_free = fs_total - (m_sc->sc_total + l_sc->sc_total); > else > @@ -741,6 +763,13 @@ static void adjust_fs_space(struct inode > fs_warn(sdp, "File system extended by %llu blocks.\n", > (unsigned long long)new_free); > gfs2_statfs_change(sdp, new_free, new_free, 0); > + > + if (gfs2_meta_inode_buffer(l_ip, &l_bh) != 0) > + goto out; > + update_statfs(sdp, m_bh, l_bh); > + brelse(l_bh); > +out: > + brelse(m_bh); > } > > /** > @@ -763,6 +792,7 @@ static int gfs2_stuffed_write_end(struct > { > struct gfs2_inode *ip = GFS2_I(inode); > struct gfs2_sbd *sdp = GFS2_SB(inode); > + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); > u64 to = pos + copied; > void *kaddr; > unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); > @@ -794,6 +824,10 @@ static int gfs2_stuffed_write_end(struct > > brelse(dibh); > gfs2_trans_end(sdp); > + if (inode == sdp->sd_rindex) { > + gfs2_glock_dq(&m_ip->i_gh); > + gfs2_holder_uninit(&m_ip->i_gh); > + } > gfs2_glock_dq(&ip->i_gh); > gfs2_holder_uninit(&ip->i_gh); > return copied; > @@ -823,6 +857,7 @@ static int gfs2_write_end(struct file *f > struct inode *inode = page->mapping->host; > struct gfs2_inode *ip = GFS2_I(inode); > struct gfs2_sbd *sdp = GFS2_SB(inode); > + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); > struct buffer_head *dibh; > struct gfs2_alloc *al = ip->i_alloc; > unsigned int from = pos & (PAGE_CACHE_SIZE - 1); > @@ -865,6 +900,10 @@ failed: > gfs2_quota_unlock(ip); > gfs2_alloc_put(ip); > } > + if (inode == sdp->sd_rindex) { > + gfs2_glock_dq(&m_ip->i_gh); > + gfs2_holder_uninit(&m_ip->i_gh); > + } > gfs2_glock_dq(&ip->i_gh); > gfs2_holder_uninit(&ip->i_gh); > return ret; > Index: kernel-upstream/fs/gfs2/super.c > =================================================================== > --- kernel-upstream.orig/fs/gfs2/super.c > +++ kernel-upstream/fs/gfs2/super.c > @@ -353,7 +353,7 @@ fail: > return error; > } > > -static void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const > void *buf) > +void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void > *buf) > { > const struct gfs2_statfs_change *str = buf; > > @@ -441,6 +441,29 @@ void gfs2_statfs_change(struct gfs2_sbd > brelse(l_bh); > } > > +void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, > + struct buffer_head *l_bh) > +{ > + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); > + struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); > + struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; > + struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; > + > + gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); > + > + spin_lock(&sdp->sd_statfs_spin); > + m_sc->sc_total += l_sc->sc_total; > + m_sc->sc_free += l_sc->sc_free; > + m_sc->sc_dinodes += l_sc->sc_dinodes; > + memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); > + memset(l_bh->b_data + sizeof(struct gfs2_dinode), > + 0, sizeof(struct gfs2_statfs_change)); > + spin_unlock(&sdp->sd_statfs_spin); > + > + gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); > + gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); > +} > + > int gfs2_statfs_sync(struct gfs2_sbd *sdp) > { > struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); > @@ -477,19 +500,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sd > if (error) > goto out_bh2; > > - gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); > - > - spin_lock(&sdp->sd_statfs_spin); > - m_sc->sc_total += l_sc->sc_total; > - m_sc->sc_free += l_sc->sc_free; > - m_sc->sc_dinodes += l_sc->sc_dinodes; > - memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); > - memset(l_bh->b_data + sizeof(struct gfs2_dinode), > - 0, sizeof(struct gfs2_statfs_change)); > - spin_unlock(&sdp->sd_statfs_spin); > - > - gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); > - gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); > + update_statfs(sdp, m_bh, l_bh); > > gfs2_trans_end(sdp); > > Index: kernel-upstream/fs/gfs2/super.h > =================================================================== > --- kernel-upstream.orig/fs/gfs2/super.h > +++ kernel-upstream/fs/gfs2/super.h > @@ -40,6 +40,10 @@ extern int gfs2_make_fs_rw(struct gfs2_s > extern int gfs2_statfs_init(struct gfs2_sbd *sdp); > extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, > s64 dinodes); > +extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, > + const void *buf); > +extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, > + struct buffer_head *l_bh); > extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); > > extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); >
