On Tue, Jun 25, 2024 at 10:17:57PM +0100, Matthew Wilcox (Oracle) wrote: > Rosebush is a resizing hash table. See > Docuemntation/core-api/rosebush.rst for details. I thought I had more debugging enabled than I actually did, and there's some unbalanced RCU locking. I'll fold this fix in: diff --git a/lib/rosebush.c b/lib/rosebush.c index 47106a04d11d..ab2d314cecec 100644 --- a/lib/rosebush.c +++ b/lib/rosebush.c @@ -305,13 +305,14 @@ static int rbh_split_bucket(struct rbh *rbh, struct rbh_bucket *bucket, rcu_read_unlock(); /* XXX: use slab */ + err = -ENOMEM; buckets[0] = kmalloc(sizeof(*bucket), GFP_KERNEL); if (!buckets[0]) - return -ENOMEM; + goto nomem; buckets[1] = kmalloc(sizeof(*bucket), GFP_KERNEL); if (!buckets[1]) { kfree(buckets[0]); - return -ENOMEM; + goto nomem; } //printk("%s: adding buckets %p %p for hash %d\n", __func__, buckets[0], buckets[1], hash); @@ -320,6 +321,8 @@ static int rbh_split_bucket(struct rbh *rbh, struct rbh_bucket *bucket, table = (struct rbh_table *)(tagged & (tagged + 1)); mask = tagged - (unsigned long)table; hash &= mask; + + err = 0; if (rbh_dereference_protected(table->buckets[hash], rbh) != bucket) goto free; @@ -354,14 +357,17 @@ static int rbh_split_bucket(struct rbh *rbh, struct rbh_bucket *bucket, rbh_resize_unlock(rbh); kvfree_rcu_mightsleep(bucket); + rcu_read_lock(); return 0; free: rbh_resize_unlock(rbh); //printk("%s: freeing bucket %p\n", __func__, bucket); - kfree(buckets[0]); kfree(buckets[1]); +nomem: + kfree(buckets[0]); - return 0; + rcu_read_lock(); + return err; } static int __rbh_insert(struct rbh *rbh, u32 hash, void *p)