diff options
author | Wendy Cheng <wcheng@redhat.com> | 2007-08-24 09:15:01 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-10 03:55:51 -0400 |
commit | e9bd2b3bafd29bf75522546207f0bba0ec4515c2 (patch) | |
tree | fac6201981d94d827390ba23fe8fe6afc2fb0119 /fs | |
parent | c4f68a130fc1795e4a75ec5bdaf9e85d86c22419 (diff) |
[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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/inode.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 34f7bcdea1e9..013f00b90cc2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -244,6 +244,11 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) | |||
244 | return 0; | 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 | * gfs2_inode_refresh - Refresh the incore copy of the dinode | 253 | * gfs2_inode_refresh - Refresh the incore copy of the dinode |
249 | * @ip: The GFS2 inode | 254 | * @ip: The GFS2 inode |
@@ -688,7 +693,7 @@ out: | |||
688 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | 693 | static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
689 | const struct gfs2_inum_host *inum, unsigned int mode, | 694 | const struct gfs2_inum_host *inum, unsigned int mode, |
690 | unsigned int uid, unsigned int gid, | 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 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 698 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
694 | struct gfs2_dinode *di; | 699 | struct gfs2_dinode *di; |
@@ -743,13 +748,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
743 | di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); | 748 | di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); |
744 | di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); | 749 | di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); |
745 | memset(&di->di_reserved, 0, sizeof(di->di_reserved)); | 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 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | 757 | static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, |
751 | unsigned int mode, const struct gfs2_inum_host *inum, | 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 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 761 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
755 | unsigned int uid, gid; | 762 | unsigned int uid, gid; |
@@ -770,7 +777,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
770 | if (error) | 777 | if (error) |
771 | goto out_quota; | 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 | gfs2_quota_change(dip, +1, uid, gid); | 781 | gfs2_quota_change(dip, +1, uid, gid); |
775 | gfs2_trans_end(sdp); | 782 | gfs2_trans_end(sdp); |
776 | 783 | ||
@@ -909,6 +916,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
909 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; | 916 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; |
910 | int error; | 917 | int error; |
911 | u64 generation; | 918 | u64 generation; |
919 | struct buffer_head *bh=NULL; | ||
912 | 920 | ||
913 | if (!name->len || name->len > GFS2_FNAMESIZE) | 921 | if (!name->len || name->len > GFS2_FNAMESIZE) |
914 | return ERR_PTR(-ENAMETOOLONG); | 922 | return ERR_PTR(-ENAMETOOLONG); |
@@ -935,7 +943,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
935 | if (error) | 943 | if (error) |
936 | goto fail_gunlock; | 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 | if (error) | 947 | if (error) |
940 | goto fail_gunlock2; | 948 | goto fail_gunlock2; |
941 | 949 | ||
@@ -945,6 +953,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
945 | if (IS_ERR(inode)) | 953 | if (IS_ERR(inode)) |
946 | goto fail_gunlock2; | 954 | goto fail_gunlock2; |
947 | 955 | ||
956 | gfs2_inode_bh(GFS2_I(inode), bh); | ||
957 | |||
948 | error = gfs2_inode_refresh(GFS2_I(inode)); | 958 | error = gfs2_inode_refresh(GFS2_I(inode)); |
949 | if (error) | 959 | if (error) |
950 | goto fail_gunlock2; | 960 | goto fail_gunlock2; |