]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
gfs2: Use rhashtable walk interface in glock_hash_walk
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 11 Feb 2017 11:26:45 +0000 (19:26 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 14 Feb 2017 03:17:05 +0000 (22:17 -0500)
The function glock_hash_walk walks the rhashtable by hand.  This
is broken because if it catches the hash table in the middle of
a rehash, then it will miss entries.

This patch replaces the manual walk by using the rhashtable walk
interface.

Fixes: 88ffbf3e037e ("GFS2: Use resizable hash table for glocks")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
fs/gfs2/glock.c

index 94f50cac91c617b03025d4d596d8d9d65d2c185b..70e94170af85eb67e553d5fb3ce76e7c343bb384 100644 (file)
@@ -1420,26 +1420,32 @@ static struct shrinker glock_shrinker = {
  * @sdp: the filesystem
  * @bucket: the bucket
  *
+ * Note that the function can be called multiple times on the same
+ * object.  So the user must ensure that the function can cope with
+ * that.
  */
 
 static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp)
 {
        struct gfs2_glock *gl;
-       struct rhash_head *pos;
-       const struct bucket_table *tbl;
-       int i;
+       struct rhashtable_iter iter;
 
-       rcu_read_lock();
-       tbl = rht_dereference_rcu(gl_hash_table.tbl, &gl_hash_table);
-       for (i = 0; i < tbl->size; i++) {
-               rht_for_each_entry_rcu(gl, pos, tbl, i, gl_node) {
+       rhashtable_walk_enter(&gl_hash_table, &iter);
+
+       do {
+               gl = ERR_PTR(rhashtable_walk_start(&iter));
+               if (gl)
+                       continue;
+
+               while ((gl = rhashtable_walk_next(&iter)) && !IS_ERR(gl))
                        if ((gl->gl_name.ln_sbd == sdp) &&
                            lockref_get_not_dead(&gl->gl_lockref))
                                examiner(gl);
-               }
-       }
-       rcu_read_unlock();
-       cond_resched();
+
+               rhashtable_walk_stop(&iter);
+       } while (cond_resched(), gl == ERR_PTR(-EAGAIN));
+
+       rhashtable_walk_exit(&iter);
 }
 
 /**