Commit e9bd2b3bafd29bf75522546207f0bba0ec4515c2
Committed by
Steven Whitehouse
1 parent
c4f68a130f
[GFS2] fix inode meta data corruption
Fix a nasty inode meta data corruption issue by keeping the buffer head in icache array. This buffer needs to stay in memory until journal flush occurs Otherwise, gfs2_meta_inode_buffer could do a disk read before the inode hits disk. It ends up with meta data corruptions. The buffer will be released as part of the existing journal flush logic. Signed-off-by: S. Wendy Cheng <wcheng@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Showing 1 changed file with 15 additions and 5 deletions Side-by-side Diff
fs/gfs2/inode.c
... | ... | @@ -244,6 +244,11 @@ |
244 | 244 | return 0; |
245 | 245 | } |
246 | 246 | |
247 | +static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh) | |
248 | +{ | |
249 | + ip->i_cache[0] = bh; | |
250 | +} | |
251 | + | |
247 | 252 | /** |
248 | 253 | * gfs2_inode_refresh - Refresh the incore copy of the dinode |
249 | 254 | * @ip: The GFS2 inode |
... | ... | @@ -688,7 +693,7 @@ |
688 | 693 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
689 | 694 | const struct gfs2_inum_host *inum, unsigned int mode, |
690 | 695 | unsigned int uid, unsigned int gid, |
691 | - const u64 *generation, dev_t dev) | |
696 | + const u64 *generation, dev_t dev, struct buffer_head **bhp) | |
692 | 697 | { |
693 | 698 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
694 | 699 | struct gfs2_dinode *di; |
695 | 700 | |
696 | 701 | |
... | ... | @@ -743,13 +748,15 @@ |
743 | 748 | di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); |
744 | 749 | di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); |
745 | 750 | memset(&di->di_reserved, 0, sizeof(di->di_reserved)); |
751 | + | |
752 | + set_buffer_uptodate(dibh); | |
746 | 753 | |
747 | - brelse(dibh); | |
754 | + *bhp = dibh; | |
748 | 755 | } |
749 | 756 | |
750 | 757 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
751 | 758 | unsigned int mode, const struct gfs2_inum_host *inum, |
752 | - const u64 *generation, dev_t dev) | |
759 | + const u64 *generation, dev_t dev, struct buffer_head **bhp) | |
753 | 760 | { |
754 | 761 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
755 | 762 | unsigned int uid, gid; |
... | ... | @@ -770,7 +777,7 @@ |
770 | 777 | if (error) |
771 | 778 | goto out_quota; |
772 | 779 | |
773 | - init_dinode(dip, gl, inum, mode, uid, gid, generation, dev); | |
780 | + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); | |
774 | 781 | gfs2_quota_change(dip, +1, uid, gid); |
775 | 782 | gfs2_trans_end(sdp); |
776 | 783 | |
... | ... | @@ -909,6 +916,7 @@ |
909 | 916 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; |
910 | 917 | int error; |
911 | 918 | u64 generation; |
919 | + struct buffer_head *bh=NULL; | |
912 | 920 | |
913 | 921 | if (!name->len || name->len > GFS2_FNAMESIZE) |
914 | 922 | return ERR_PTR(-ENAMETOOLONG); |
... | ... | @@ -935,7 +943,7 @@ |
935 | 943 | if (error) |
936 | 944 | goto fail_gunlock; |
937 | 945 | |
938 | - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev); | |
946 | + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); | |
939 | 947 | if (error) |
940 | 948 | goto fail_gunlock2; |
941 | 949 | |
... | ... | @@ -944,6 +952,8 @@ |
944 | 952 | inum.no_formal_ino); |
945 | 953 | if (IS_ERR(inode)) |
946 | 954 | goto fail_gunlock2; |
955 | + | |
956 | + gfs2_inode_bh(GFS2_I(inode), bh); | |
947 | 957 | |
948 | 958 | error = gfs2_inode_refresh(GFS2_I(inode)); |
949 | 959 | if (error) |