diff options
author | Bob Peterson <rpeterso@redhat.com> | 2010-04-14 11:58:16 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2010-04-14 11:48:05 -0400 |
commit | 1a0eae8848cde6e0734360f6456496c995ee1e23 (patch) | |
tree | 536f944468ef5bc6f47ec09325422adbc5a3907a /fs/gfs2 | |
parent | 602c89d2e3e8652f94a697c9a919be739b9bcdd5 (diff) |
GFS2: glock livelock
This patch fixes a couple gfs2 problems with the reclaiming of
unlinked dinodes. First, there were a couple of livelocks where
everything would come to a halt waiting for a glock that was
seemingly held by a process that no longer existed. In fact, the
process did exist, it just had the wrong pid number in the holder
information. Second, there was a lock ordering problem between
inode locking and glock locking. Third, glock/inode contention
could sometimes cause inodes to be improperly marked invalid by
iget_failed.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/dir.c | 2 | ||||
-rw-r--r-- | fs/gfs2/export.c | 2 | ||||
-rw-r--r-- | fs/gfs2/glock.c | 3 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 101 | ||||
-rw-r--r-- | fs/gfs2/inode.h | 5 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 2 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 58 |
7 files changed, 144 insertions, 29 deletions
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 25fddc100f18..8295c5b5d4a9 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -1475,7 +1475,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) | |||
1475 | inode = gfs2_inode_lookup(dir->i_sb, | 1475 | inode = gfs2_inode_lookup(dir->i_sb, |
1476 | be16_to_cpu(dent->de_type), | 1476 | be16_to_cpu(dent->de_type), |
1477 | be64_to_cpu(dent->de_inum.no_addr), | 1477 | be64_to_cpu(dent->de_inum.no_addr), |
1478 | be64_to_cpu(dent->de_inum.no_formal_ino), 0); | 1478 | be64_to_cpu(dent->de_inum.no_formal_ino)); |
1479 | brelse(bh); | 1479 | brelse(bh); |
1480 | return inode; | 1480 | return inode; |
1481 | } | 1481 | } |
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index d15876e9aa26..d81bc7e90e98 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c | |||
@@ -169,7 +169,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, | |||
169 | if (error) | 169 | if (error) |
170 | goto fail; | 170 | goto fail; |
171 | 171 | ||
172 | inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0, 0); | 172 | inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0); |
173 | if (IS_ERR(inode)) { | 173 | if (IS_ERR(inode)) { |
174 | error = PTR_ERR(inode); | 174 | error = PTR_ERR(inode); |
175 | goto fail; | 175 | goto fail; |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 454d4b4eb36b..ddcdbf493536 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -855,6 +855,9 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder * | |||
855 | gh->gh_flags = flags; | 855 | gh->gh_flags = flags; |
856 | gh->gh_iflags = 0; | 856 | gh->gh_iflags = 0; |
857 | gh->gh_ip = (unsigned long)__builtin_return_address(0); | 857 | gh->gh_ip = (unsigned long)__builtin_return_address(0); |
858 | if (gh->gh_owner_pid) | ||
859 | put_pid(gh->gh_owner_pid); | ||
860 | gh->gh_owner_pid = get_pid(task_pid(current)); | ||
858 | } | 861 | } |
859 | 862 | ||
860 | /** | 863 | /** |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index b1bf2694fb2b..51d8061fa07a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -158,7 +158,6 @@ void gfs2_set_iop(struct inode *inode) | |||
158 | * @sb: The super block | 158 | * @sb: The super block |
159 | * @no_addr: The inode number | 159 | * @no_addr: The inode number |
160 | * @type: The type of the inode | 160 | * @type: The type of the inode |
161 | * @skip_freeing: set this not return an inode if it is currently being freed. | ||
162 | * | 161 | * |
163 | * Returns: A VFS inode, or an error | 162 | * Returns: A VFS inode, or an error |
164 | */ | 163 | */ |
@@ -166,17 +165,14 @@ void gfs2_set_iop(struct inode *inode) | |||
166 | struct inode *gfs2_inode_lookup(struct super_block *sb, | 165 | struct inode *gfs2_inode_lookup(struct super_block *sb, |
167 | unsigned int type, | 166 | unsigned int type, |
168 | u64 no_addr, | 167 | u64 no_addr, |
169 | u64 no_formal_ino, int skip_freeing) | 168 | u64 no_formal_ino) |
170 | { | 169 | { |
171 | struct inode *inode; | 170 | struct inode *inode; |
172 | struct gfs2_inode *ip; | 171 | struct gfs2_inode *ip; |
173 | struct gfs2_glock *io_gl; | 172 | struct gfs2_glock *io_gl; |
174 | int error; | 173 | int error; |
175 | 174 | ||
176 | if (skip_freeing) | 175 | inode = gfs2_iget(sb, no_addr); |
177 | inode = gfs2_iget_skip(sb, no_addr); | ||
178 | else | ||
179 | inode = gfs2_iget(sb, no_addr); | ||
180 | ip = GFS2_I(inode); | 176 | ip = GFS2_I(inode); |
181 | 177 | ||
182 | if (!inode) | 178 | if (!inode) |
@@ -234,13 +230,100 @@ fail_glock: | |||
234 | fail_iopen: | 230 | fail_iopen: |
235 | gfs2_glock_put(io_gl); | 231 | gfs2_glock_put(io_gl); |
236 | fail_put: | 232 | fail_put: |
237 | ip->i_gl->gl_object = NULL; | 233 | if (inode->i_state & I_NEW) |
234 | ip->i_gl->gl_object = NULL; | ||
238 | gfs2_glock_put(ip->i_gl); | 235 | gfs2_glock_put(ip->i_gl); |
239 | fail: | 236 | fail: |
240 | iget_failed(inode); | 237 | if (inode->i_state & I_NEW) |
238 | iget_failed(inode); | ||
239 | else | ||
240 | iput(inode); | ||
241 | return ERR_PTR(error); | 241 | return ERR_PTR(error); |
242 | } | 242 | } |
243 | 243 | ||
244 | /** | ||
245 | * gfs2_unlinked_inode_lookup - Lookup an unlinked inode for reclamation | ||
246 | * @sb: The super block | ||
247 | * no_addr: The inode number | ||
248 | * @@inode: A pointer to the inode found, if any | ||
249 | * | ||
250 | * Returns: 0 and *inode if no errors occurred. If an error occurs, | ||
251 | * the resulting *inode may or may not be NULL. | ||
252 | */ | ||
253 | |||
254 | int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr, | ||
255 | struct inode **inode) | ||
256 | { | ||
257 | struct gfs2_sbd *sdp; | ||
258 | struct gfs2_inode *ip; | ||
259 | struct gfs2_glock *io_gl; | ||
260 | int error; | ||
261 | struct gfs2_holder gh; | ||
262 | |||
263 | *inode = gfs2_iget_skip(sb, no_addr); | ||
264 | |||
265 | if (!(*inode)) | ||
266 | return -ENOBUFS; | ||
267 | |||
268 | if (!((*inode)->i_state & I_NEW)) | ||
269 | return -ENOBUFS; | ||
270 | |||
271 | ip = GFS2_I(*inode); | ||
272 | sdp = GFS2_SB(*inode); | ||
273 | ip->i_no_formal_ino = -1; | ||
274 | |||
275 | error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); | ||
276 | if (unlikely(error)) | ||
277 | goto fail; | ||
278 | ip->i_gl->gl_object = ip; | ||
279 | |||
280 | error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); | ||
281 | if (unlikely(error)) | ||
282 | goto fail_put; | ||
283 | |||
284 | set_bit(GIF_INVALID, &ip->i_flags); | ||
285 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, LM_FLAG_TRY | GL_EXACT, | ||
286 | &ip->i_iopen_gh); | ||
287 | if (unlikely(error)) { | ||
288 | if (error == GLR_TRYFAILED) | ||
289 | error = 0; | ||
290 | goto fail_iopen; | ||
291 | } | ||
292 | ip->i_iopen_gh.gh_gl->gl_object = ip; | ||
293 | gfs2_glock_put(io_gl); | ||
294 | |||
295 | (*inode)->i_mode = DT2IF(DT_UNKNOWN); | ||
296 | |||
297 | /* | ||
298 | * We must read the inode in order to work out its type in | ||
299 | * this case. Note that this doesn't happen often as we normally | ||
300 | * know the type beforehand. This code path only occurs during | ||
301 | * unlinked inode recovery (where it is safe to do this glock, | ||
302 | * which is not true in the general case). | ||
303 | */ | ||
304 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY, | ||
305 | &gh); | ||
306 | if (unlikely(error)) { | ||
307 | if (error == GLR_TRYFAILED) | ||
308 | error = 0; | ||
309 | goto fail_glock; | ||
310 | } | ||
311 | /* Inode is now uptodate */ | ||
312 | gfs2_glock_dq_uninit(&gh); | ||
313 | gfs2_set_iop(*inode); | ||
314 | |||
315 | return 0; | ||
316 | fail_glock: | ||
317 | gfs2_glock_dq(&ip->i_iopen_gh); | ||
318 | fail_iopen: | ||
319 | gfs2_glock_put(io_gl); | ||
320 | fail_put: | ||
321 | ip->i_gl->gl_object = NULL; | ||
322 | gfs2_glock_put(ip->i_gl); | ||
323 | fail: | ||
324 | return error; | ||
325 | } | ||
326 | |||
244 | static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) | 327 | static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) |
245 | { | 328 | { |
246 | const struct gfs2_dinode *str = buf; | 329 | const struct gfs2_dinode *str = buf; |
@@ -862,7 +945,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
862 | goto fail_gunlock2; | 945 | goto fail_gunlock2; |
863 | 946 | ||
864 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, | 947 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, |
865 | inum.no_formal_ino, 0); | 948 | inum.no_formal_ino); |
866 | if (IS_ERR(inode)) | 949 | if (IS_ERR(inode)) |
867 | goto fail_gunlock2; | 950 | goto fail_gunlock2; |
868 | 951 | ||
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index c341aaf67adb..e161461d4c57 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h | |||
@@ -83,8 +83,9 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip, | |||
83 | 83 | ||
84 | extern void gfs2_set_iop(struct inode *inode); | 84 | extern void gfs2_set_iop(struct inode *inode); |
85 | extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, | 85 | extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, |
86 | u64 no_addr, u64 no_formal_ino, | 86 | u64 no_addr, u64 no_formal_ino); |
87 | int skip_freeing); | 87 | extern int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr, |
88 | struct inode **inode); | ||
88 | extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); | 89 | extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); |
89 | 90 | ||
90 | extern int gfs2_inode_refresh(struct gfs2_inode *ip); | 91 | extern int gfs2_inode_refresh(struct gfs2_inode *ip); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c1309ed1c496..dc35f3470271 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -487,7 +487,7 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, | |||
487 | struct dentry *dentry; | 487 | struct dentry *dentry; |
488 | struct inode *inode; | 488 | struct inode *inode; |
489 | 489 | ||
490 | inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0); | 490 | inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0); |
491 | if (IS_ERR(inode)) { | 491 | if (IS_ERR(inode)) { |
492 | fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); | 492 | fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); |
493 | return PTR_ERR(inode); | 493 | return PTR_ERR(inode); |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 503b842f3ba2..37391550284f 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -948,18 +948,20 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) | |||
948 | * try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes | 948 | * try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes |
949 | * @rgd: The rgrp | 949 | * @rgd: The rgrp |
950 | * | 950 | * |
951 | * Returns: The inode, if one has been found | 951 | * Returns: 0 if no error |
952 | * The inode, if one has been found, in inode. | ||
952 | */ | 953 | */ |
953 | 954 | ||
954 | static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, | 955 | static int try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, |
955 | u64 skip) | 956 | u64 skip, struct inode **inode) |
956 | { | 957 | { |
957 | struct inode *inode; | ||
958 | u32 goal = 0, block; | 958 | u32 goal = 0, block; |
959 | u64 no_addr; | 959 | u64 no_addr; |
960 | struct gfs2_sbd *sdp = rgd->rd_sbd; | 960 | struct gfs2_sbd *sdp = rgd->rd_sbd; |
961 | unsigned int n; | 961 | unsigned int n; |
962 | int error = 0; | ||
962 | 963 | ||
964 | *inode = NULL; | ||
963 | for(;;) { | 965 | for(;;) { |
964 | if (goal >= rgd->rd_data) | 966 | if (goal >= rgd->rd_data) |
965 | break; | 967 | break; |
@@ -979,14 +981,14 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, | |||
979 | if (no_addr == skip) | 981 | if (no_addr == skip) |
980 | continue; | 982 | continue; |
981 | *last_unlinked = no_addr; | 983 | *last_unlinked = no_addr; |
982 | inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, | 984 | error = gfs2_unlinked_inode_lookup(rgd->rd_sbd->sd_vfs, |
983 | no_addr, -1, 1); | 985 | no_addr, inode); |
984 | if (!IS_ERR(inode)) | 986 | if (*inode || error) |
985 | return inode; | 987 | return error; |
986 | } | 988 | } |
987 | 989 | ||
988 | rgd->rd_flags &= ~GFS2_RDF_CHECK; | 990 | rgd->rd_flags &= ~GFS2_RDF_CHECK; |
989 | return NULL; | 991 | return 0; |
990 | } | 992 | } |
991 | 993 | ||
992 | /** | 994 | /** |
@@ -1096,12 +1098,27 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1096 | case 0: | 1098 | case 0: |
1097 | if (try_rgrp_fit(rgd, al)) | 1099 | if (try_rgrp_fit(rgd, al)) |
1098 | goto out; | 1100 | goto out; |
1099 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1101 | /* If the rg came in already locked, there's no |
1100 | inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); | 1102 | way we can recover from a failed try_rgrp_unlink |
1103 | because that would require an iput which can only | ||
1104 | happen after the rgrp is unlocked. */ | ||
1105 | if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK) | ||
1106 | error = try_rgrp_unlink(rgd, last_unlinked, | ||
1107 | ip->i_no_addr, &inode); | ||
1101 | if (!rg_locked) | 1108 | if (!rg_locked) |
1102 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1109 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1103 | if (inode) | 1110 | if (inode) { |
1111 | if (error) { | ||
1112 | if (inode->i_state & I_NEW) | ||
1113 | iget_failed(inode); | ||
1114 | else | ||
1115 | iput(inode); | ||
1116 | return ERR_PTR(error); | ||
1117 | } | ||
1104 | return inode; | 1118 | return inode; |
1119 | } | ||
1120 | if (error) | ||
1121 | return ERR_PTR(error); | ||
1105 | /* fall through */ | 1122 | /* fall through */ |
1106 | case GLR_TRYFAILED: | 1123 | case GLR_TRYFAILED: |
1107 | rgd = recent_rgrp_next(rgd); | 1124 | rgd = recent_rgrp_next(rgd); |
@@ -1130,12 +1147,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1130 | case 0: | 1147 | case 0: |
1131 | if (try_rgrp_fit(rgd, al)) | 1148 | if (try_rgrp_fit(rgd, al)) |
1132 | goto out; | 1149 | goto out; |
1133 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1150 | if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK) |
1134 | inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); | 1151 | error = try_rgrp_unlink(rgd, last_unlinked, |
1152 | ip->i_no_addr, &inode); | ||
1135 | if (!rg_locked) | 1153 | if (!rg_locked) |
1136 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1154 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1137 | if (inode) | 1155 | if (inode) { |
1156 | if (error) { | ||
1157 | if (inode->i_state & I_NEW) | ||
1158 | iget_failed(inode); | ||
1159 | else | ||
1160 | iput(inode); | ||
1161 | return ERR_PTR(error); | ||
1162 | } | ||
1138 | return inode; | 1163 | return inode; |
1164 | } | ||
1165 | if (error) | ||
1166 | return ERR_PTR(error); | ||
1139 | break; | 1167 | break; |
1140 | 1168 | ||
1141 | case GLR_TRYFAILED: | 1169 | case GLR_TRYFAILED: |