diff options
author | Bob Peterson <rpeterso@redhat.com> | 2010-09-30 10:34:00 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2010-09-30 12:23:03 -0400 |
commit | 46290341cd649c2bfb69e5067c1804c0395c83a1 (patch) | |
tree | 1ef4a9c1d158ec182645d4be4cb3357a52a4404d /fs/gfs2 | |
parent | feb47ca9314666d920855b8a235032dea2b2caa4 (diff) |
GFS2 fatal: filesystem consistency error on rename
This patch fixes a GFS2 problem whereby the first rename after a
mount can result in a file system consistency error being flagged
improperly and cause the file system to withdraw. The problem is
that the rename code tries to run the rgrp list with function
gfs2_blk2rgrpd before the rgrp list is guaranteed to be read in
from disk. The patch makes the rename function hold the rindex
glock (as the gfs2_unlink code does today) which reads in the rgrp
list if need be. There were a total of three places in the rename
code that improperly referenced the rgrp list without the rindex
glock and this patch fixes all three.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/ops_inode.c | 8 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 22 | ||||
-rw-r--r-- | fs/gfs2/rgrp.h | 8 |
3 files changed, 24 insertions, 14 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index fba00171d915..0534510200d5 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -736,7 +736,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
736 | struct gfs2_inode *ip = GFS2_I(odentry->d_inode); | 736 | struct gfs2_inode *ip = GFS2_I(odentry->d_inode); |
737 | struct gfs2_inode *nip = NULL; | 737 | struct gfs2_inode *nip = NULL; |
738 | struct gfs2_sbd *sdp = GFS2_SB(odir); | 738 | struct gfs2_sbd *sdp = GFS2_SB(odir); |
739 | struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }; | 739 | struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh; |
740 | struct gfs2_rgrpd *nrgd; | 740 | struct gfs2_rgrpd *nrgd; |
741 | unsigned int num_gh; | 741 | unsigned int num_gh; |
742 | int dir_rename = 0; | 742 | int dir_rename = 0; |
@@ -750,6 +750,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
750 | return 0; | 750 | return 0; |
751 | } | 751 | } |
752 | 752 | ||
753 | error = gfs2_rindex_hold(sdp, &ri_gh); | ||
754 | if (error) | ||
755 | return error; | ||
753 | 756 | ||
754 | if (odip != ndip) { | 757 | if (odip != ndip) { |
755 | error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, | 758 | error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, |
@@ -879,7 +882,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
879 | 882 | ||
880 | al->al_requested = sdp->sd_max_dirres; | 883 | al->al_requested = sdp->sd_max_dirres; |
881 | 884 | ||
882 | error = gfs2_inplace_reserve(ndip); | 885 | error = gfs2_inplace_reserve_ri(ndip); |
883 | if (error) | 886 | if (error) |
884 | goto out_gunlock_q; | 887 | goto out_gunlock_q; |
885 | 888 | ||
@@ -961,6 +964,7 @@ out_gunlock_r: | |||
961 | if (r_gh.gh_gl) | 964 | if (r_gh.gh_gl) |
962 | gfs2_glock_dq_uninit(&r_gh); | 965 | gfs2_glock_dq_uninit(&r_gh); |
963 | out: | 966 | out: |
967 | gfs2_glock_dq_uninit(&ri_gh); | ||
964 | return error; | 968 | return error; |
965 | } | 969 | } |
966 | 970 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index f9ddcf401753..fb67f593f408 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -1200,7 +1200,8 @@ out: | |||
1200 | * Returns: errno | 1200 | * Returns: errno |
1201 | */ | 1201 | */ |
1202 | 1202 | ||
1203 | int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) | 1203 | int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, |
1204 | char *file, unsigned int line) | ||
1204 | { | 1205 | { |
1205 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1206 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1206 | struct gfs2_alloc *al = ip->i_alloc; | 1207 | struct gfs2_alloc *al = ip->i_alloc; |
@@ -1211,12 +1212,15 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) | |||
1211 | return -EINVAL; | 1212 | return -EINVAL; |
1212 | 1213 | ||
1213 | try_again: | 1214 | try_again: |
1214 | /* We need to hold the rindex unless the inode we're using is | 1215 | if (hold_rindex) { |
1215 | the rindex itself, in which case it's already held. */ | 1216 | /* We need to hold the rindex unless the inode we're using is |
1216 | if (ip != GFS2_I(sdp->sd_rindex)) | 1217 | the rindex itself, in which case it's already held. */ |
1217 | error = gfs2_rindex_hold(sdp, &al->al_ri_gh); | 1218 | if (ip != GFS2_I(sdp->sd_rindex)) |
1218 | else if (!sdp->sd_rgrps) /* We may not have the rindex read in, so: */ | 1219 | error = gfs2_rindex_hold(sdp, &al->al_ri_gh); |
1219 | error = gfs2_ri_update_special(ip); | 1220 | else if (!sdp->sd_rgrps) /* We may not have the rindex read |
1221 | in, so: */ | ||
1222 | error = gfs2_ri_update_special(ip); | ||
1223 | } | ||
1220 | 1224 | ||
1221 | if (error) | 1225 | if (error) |
1222 | return error; | 1226 | return error; |
@@ -1227,7 +1231,7 @@ try_again: | |||
1227 | try to free it, and try the allocation again. */ | 1231 | try to free it, and try the allocation again. */ |
1228 | error = get_local_rgrp(ip, &unlinked, &last_unlinked); | 1232 | error = get_local_rgrp(ip, &unlinked, &last_unlinked); |
1229 | if (error) { | 1233 | if (error) { |
1230 | if (ip != GFS2_I(sdp->sd_rindex)) | 1234 | if (hold_rindex && ip != GFS2_I(sdp->sd_rindex)) |
1231 | gfs2_glock_dq_uninit(&al->al_ri_gh); | 1235 | gfs2_glock_dq_uninit(&al->al_ri_gh); |
1232 | if (error != -EAGAIN) | 1236 | if (error != -EAGAIN) |
1233 | return error; | 1237 | return error; |
@@ -1269,7 +1273,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip) | |||
1269 | al->al_rgd = NULL; | 1273 | al->al_rgd = NULL; |
1270 | if (al->al_rgd_gh.gh_gl) | 1274 | if (al->al_rgd_gh.gh_gl) |
1271 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1275 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1272 | if (ip != GFS2_I(sdp->sd_rindex)) | 1276 | if (ip != GFS2_I(sdp->sd_rindex) && al->al_ri_gh.gh_gl) |
1273 | gfs2_glock_dq_uninit(&al->al_ri_gh); | 1277 | gfs2_glock_dq_uninit(&al->al_ri_gh); |
1274 | } | 1278 | } |
1275 | 1279 | ||
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index f07119d89557..0e35c0466f9a 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
@@ -39,10 +39,12 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip) | |||
39 | ip->i_alloc = NULL; | 39 | ip->i_alloc = NULL; |
40 | } | 40 | } |
41 | 41 | ||
42 | extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, | 42 | extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, |
43 | unsigned int line); | 43 | char *file, unsigned int line); |
44 | #define gfs2_inplace_reserve(ip) \ | 44 | #define gfs2_inplace_reserve(ip) \ |
45 | gfs2_inplace_reserve_i((ip), __FILE__, __LINE__) | 45 | gfs2_inplace_reserve_i((ip), 1, __FILE__, __LINE__) |
46 | #define gfs2_inplace_reserve_ri(ip) \ | ||
47 | gfs2_inplace_reserve_i((ip), 0, __FILE__, __LINE__) | ||
46 | 48 | ||
47 | extern void gfs2_inplace_release(struct gfs2_inode *ip); | 49 | extern void gfs2_inplace_release(struct gfs2_inode *ip); |
48 | 50 | ||