Commit 8581b19eb2c5 ("dm-snapshot: fix 'scheduling while atomic' on
real-time kernels") replaced hlist_bl_for_each_entry with
hlist_for_each_entry, but the two iteration macros differ after the loop
ends: hlist_bl_for_each_entry leaves "e" pointing at the last element,
while hlist_for_each_entry() sets it to NULL.
The result is that the list is no longer sorted by chunk number as it was
intended to be. This bug doesn't cause data corruption because
dm_lookup_exception walks the full list.
Restore the invariant by tracking the list tail in the "prev" variable
and appending after it with hlist_add_behind.
Signed-off-by: Mikulas Patocka <[email protected]>
Fixes: 8581b19eb2c5 ("dm-snapshot: fix 'scheduling while atomic' on real-time
kernels")
Assisted-by: Claude:claude-opus-5
---
drivers/md/dm-snap.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
Index: linux-2.6/drivers/md/dm-snap.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-snap.c
+++ linux-2.6/drivers/md/dm-snap.c
@@ -766,7 +766,7 @@ static void dm_insert_exception(struct d
struct dm_exception *new_e)
{
struct hlist_head *l;
- struct dm_exception *e = NULL;
+ struct dm_exception *e = NULL, *prev = NULL;
l = &eh->table[exception_hash(eh, new_e->old_chunk)].head;
@@ -798,21 +798,23 @@ static void dm_insert_exception(struct d
if (new_e->old_chunk < e->old_chunk)
break;
+
+ prev = e;
}
out:
- if (!e) {
+ if (e && new_e->old_chunk < e->old_chunk) {
+ /* Add before an existing exception */
+ hlist_add_before(&new_e->hash_list, &e->hash_list);
+ } else if (prev) {
+ /* Add to l's tail: prev is the last exception in this slot */
+ hlist_add_behind(&new_e->hash_list, &prev->hash_list);
+ } else {
/*
* Either the table doesn't support consecutive chunks or slot
* l is empty.
*/
hlist_add_head(&new_e->hash_list, l);
- } else if (new_e->old_chunk < e->old_chunk) {
- /* Add before an existing exception */
- hlist_add_before(&new_e->hash_list, &e->hash_list);
- } else {
- /* Add to l's tail: e is the last exception in this slot */
- hlist_add_behind(&new_e->hash_list, &e->hash_list);
}
}