Skip to content

Commit 2995b80

Browse files
rmurphy-armChristoph Hellwig
authored andcommitted
dma-debug: improve search for partial syncs
When bucket_find_contains() tries to find the original entry for a partial sync, it manages to constrain its search in a way that is both too restrictive and not restrictive enough. A driver which only uses single mappings rather than scatterlists might not set max_seg_size, but could still technically perform a partial sync at an offset of more than 64KB into a sufficiently large mapping, so we could stop searching too early before reaching a legitimate entry. Conversely, if no valid entry is present and max_range is large enough, we can pointlessly search buckets that we've already searched, or that represent an impossible wrapping around the bottom of the address space. At worst, the (legitimate) case of max_seg_size == UINT_MAX can make the loop infinite. Replace the fragile and frankly hard-to-follow "range" logic with a simple counted loop for the number of possible hash buckets below the given address. Reported-by: Yunfei Wang <[email protected]> Signed-off-by: Robin Murphy <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 81c12e9 commit 2995b80

File tree

1 file changed

+2
-4
lines changed

1 file changed

+2
-4
lines changed

kernel/dma/debug.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,10 @@ static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
350350
unsigned long *flags)
351351
{
352352

353-
unsigned int max_range = dma_get_max_seg_size(ref->dev);
354353
struct dma_debug_entry *entry, index = *ref;
355-
unsigned int range = 0;
354+
int limit = min(HASH_SIZE, (index.dev_addr >> HASH_FN_SHIFT) + 1);
356355

357-
while (range <= max_range) {
356+
for (int i = 0; i < limit; i++) {
358357
entry = __hash_bucket_find(*bucket, ref, containing_match);
359358

360359
if (entry)
@@ -364,7 +363,6 @@ static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket,
364363
* Nothing found, go back a hash bucket
365364
*/
366365
put_hash_bucket(*bucket, *flags);
367-
range += (1 << HASH_FN_SHIFT);
368366
index.dev_addr -= (1 << HASH_FN_SHIFT);
369367
*bucket = get_hash_bucket(&index, flags);
370368
}

0 commit comments

Comments
 (0)