mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
gfs2: Stop using rhashtable_walk_peek
Function rhashtable_walk_peek is problematic because there is no guarantee that the glock previously returned still exists; when that key is deleted, rhashtable_walk_peek can end up returning a different key, which will cause an inconsistent glock dump. Fix this by keeping track of the current glock in the seq file iterator functions instead. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
parent
450b1f6f56
commit
3fd5d3ad35
@ -1923,28 +1923,37 @@ void gfs2_glock_exit(void)
|
|||||||
|
|
||||||
static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
|
static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
|
||||||
{
|
{
|
||||||
if (n == 0)
|
struct gfs2_glock *gl = gi->gl;
|
||||||
gi->gl = rhashtable_walk_peek(&gi->hti);
|
|
||||||
else {
|
if (gl) {
|
||||||
gi->gl = rhashtable_walk_next(&gi->hti);
|
if (n == 0)
|
||||||
n--;
|
return;
|
||||||
|
if (!lockref_put_not_zero(&gl->gl_lockref))
|
||||||
|
gfs2_glock_queue_put(gl);
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (IS_ERR_OR_NULL(gi->gl)) {
|
gl = rhashtable_walk_next(&gi->hti);
|
||||||
if (!gi->gl)
|
if (IS_ERR_OR_NULL(gl)) {
|
||||||
return;
|
if (gl == ERR_PTR(-EAGAIN)) {
|
||||||
if (PTR_ERR(gi->gl) != -EAGAIN) {
|
n = 1;
|
||||||
gi->gl = NULL;
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
n = 0;
|
gl = NULL;
|
||||||
} else if (gi->sdp == gi->gl->gl_name.ln_sbd &&
|
break;
|
||||||
!__lockref_is_dead(&gi->gl->gl_lockref)) {
|
}
|
||||||
if (!n--)
|
if (gl->gl_name.ln_sbd != gi->sdp)
|
||||||
break;
|
continue;
|
||||||
|
if (n <= 1) {
|
||||||
|
if (!lockref_get_not_dead(&gl->gl_lockref))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (__lockref_is_dead(&gl->gl_lockref))
|
||||||
|
continue;
|
||||||
|
n--;
|
||||||
}
|
}
|
||||||
gi->gl = rhashtable_walk_next(&gi->hti);
|
|
||||||
}
|
}
|
||||||
|
gi->gl = gl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
|
static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
@ -1988,7 +1997,6 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr)
|
|||||||
{
|
{
|
||||||
struct gfs2_glock_iter *gi = seq->private;
|
struct gfs2_glock_iter *gi = seq->private;
|
||||||
|
|
||||||
gi->gl = NULL;
|
|
||||||
rhashtable_walk_stop(&gi->hti);
|
rhashtable_walk_stop(&gi->hti);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2076,7 +2084,8 @@ static int gfs2_glocks_release(struct inode *inode, struct file *file)
|
|||||||
struct seq_file *seq = file->private_data;
|
struct seq_file *seq = file->private_data;
|
||||||
struct gfs2_glock_iter *gi = seq->private;
|
struct gfs2_glock_iter *gi = seq->private;
|
||||||
|
|
||||||
gi->gl = NULL;
|
if (gi->gl)
|
||||||
|
gfs2_glock_put(gi->gl);
|
||||||
rhashtable_walk_exit(&gi->hti);
|
rhashtable_walk_exit(&gi->hti);
|
||||||
return seq_release_private(inode, file);
|
return seq_release_private(inode, file);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user